From 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 Mon Sep 17 00:00:00 2001 From: AlexanderCurl Date: Sat, 18 Apr 2026 17:46:06 +0100 Subject: Replaced file structures for themes in the correct format --- raveos-theme/hyprland/.SRCINFO | 11 - raveos-theme/hyprland/PKGBUILD | 36 - .../raveos-hyprland-theme-0.0.0-6-any.pkg.tar.zst | Bin 395239 -> 0 bytes .../pkg/raveos-hyprland-theme/.BUILDINFO | 1113 -- .../pkg/raveos-hyprland-theme/.INSTALL | 7 - .../pkg/raveos-hyprland-theme/.MTREE | Bin 1622 -> 0 bytes .../pkg/raveos-hyprland-theme/.PKGINFO | 14 - .../usr/lib/raveos-hyprland-theme/auto-apply.sh | 96 - .../system/raveos-hyprland-theme-apply.service | 12 - .../theme-data/DankMaterialShell/.changelog-1.2 | 0 .../theme-data/DankMaterialShell/.firstlaunch | 0 .../theme-data/DankMaterialShell/settings.json | 545 - .../theme-data/fastfetch/config-kitty.jsonc | 47 - .../theme-data/fastfetch/config.jsonc | 93 - .../theme-data/fastfetch/raveos-logo.png | Bin 136727 -> 0 bytes .../theme-data/fastfetch/raveos-logo.txt | 19 - .../hyprland-theme/theme-data/hypr/dms/cursor.conf | 6 - .../hyprland-theme/theme-data/hypr/dms/layout.conf | 11 - .../theme-data/hypr/dms/windowrules.conf | 0 .../hyprland-theme/theme-data/hypr/hyprland.conf | 542 - .../hyprland-theme/theme-data/hypr/monitors.conf | 5 - .../theme-data/hypr/scripts/alt-tab.sh | 273 - .../hypr/scripts/raveos-monitor-setup.sh | 100 - .../hyprland-theme/theme-data/hypr/workspaces.conf | 2 - .../hyprland-theme/theme-data/kitty/kitty.conf | 37 - .../theme-data/profile.d/raveos-fastfetch.sh | 13 - .../hyprland-theme/theme-data/sddm/astronaut.conf | 162 - .../theme-data/sddm/new-raveos-main-bg.jpeg | Bin 225018 -> 0 bytes .../hyprland-theme/theme-data/sddm/sddm.conf | 2 - raveos-theme/hyprland/metadata.json | 49 - raveos-theme/hyprland/new-raveos-main-bg.jpeg | Bin 225018 -> 0 bytes raveos-theme/hyprland/raveos-hyprland-apply.sh | 128 - .../hyprland/raveos-hyprland-theme-apply.service | 12 - .../hyprland/raveos-hyprland-theme.install | 7 - raveos-theme/hyprland/theme-data.tar.gz | Bin 775029 -> 0 bytes .../theme-data/DankMaterialShell/.changelog-1.2 | 0 .../theme-data/DankMaterialShell/.firstlaunch | 0 .../theme-data/DankMaterialShell/core/Makefile | 163 - .../theme-data/DankMaterialShell/core/README.md | 217 - .../DankMaterialShell/core/assets/dank.svg | 46 - .../DankMaterialShell/core/assets/danklogo.svg | 113 - .../DankMaterialShell/core/build_dankinstall.sh | 38 - .../DankMaterialShell/core/cmd/dankinstall/main.go | 219 - .../core/cmd/dms/assets/cli-policy.default.json | 10 - .../core/cmd/dms/commands_auth.go | 76 - .../core/cmd/dms/commands_blur.go | 40 - .../core/cmd/dms/commands_brightness.go | 311 - .../core/cmd/dms/commands_chroma.go | 300 - .../core/cmd/dms/commands_clipboard.go | 1004 -- .../core/cmd/dms/commands_colorpicker.go | 139 - .../core/cmd/dms/commands_common.go | 530 - .../core/cmd/dms/commands_config.go | 318 - .../core/cmd/dms/commands_dank16.go | 126 - .../core/cmd/dms/commands_doctor.go | 1107 -- .../core/cmd/dms/commands_download.go | 99 - .../core/cmd/dms/commands_dpms.go | 105 - .../core/cmd/dms/commands_features.go | 491 - .../core/cmd/dms/commands_greeter.go | 1850 -- .../core/cmd/dms/commands_greeter_test.go | 87 - .../core/cmd/dms/commands_keybinds.go | 265 - .../core/cmd/dms/commands_matugen.go | 202 - .../core/cmd/dms/commands_notify.go | 68 - .../core/cmd/dms/commands_open.go | 205 - .../core/cmd/dms/commands_randr.go | 58 - .../core/cmd/dms/commands_root.go | 74 - .../core/cmd/dms/commands_screenshot.go | 422 - .../core/cmd/dms/commands_setup.go | 436 - .../core/cmd/dms/commands_windowrules.go | 338 - .../DankMaterialShell/core/cmd/dms/dpms_client.go | 339 - .../core/cmd/dms/immutable_policy.go | 271 - .../DankMaterialShell/core/cmd/dms/main.go | 43 - .../DankMaterialShell/core/cmd/dms/main_distro.go | 40 - .../DankMaterialShell/core/cmd/dms/randr_client.go | 172 - .../core/cmd/dms/server_client.go | 114 - .../DankMaterialShell/core/cmd/dms/shell.go | 739 - .../DankMaterialShell/core/cmd/dms/ui.go | 53 - .../DankMaterialShell/core/cmd/dms/utils.go | 89 - .../theme-data/DankMaterialShell/core/go.mod | 87 - .../theme-data/DankMaterialShell/core/go.sum | 191 - .../theme-data/DankMaterialShell/core/install.sh | 86 - .../DankMaterialShell/core/internal/blur/probe.go | 35 - .../core/internal/clipboard/clipboard.go | 630 - .../core/internal/clipboard/store.go | 248 - .../core/internal/clipboard/watch.go | 303 - .../core/internal/colorpicker/color.go | 306 - .../core/internal/colorpicker/picker.go | 744 - .../core/internal/colorpicker/shm.go | 55 - .../core/internal/colorpicker/state.go | 1195 -- .../core/internal/colorpicker/state_test.go | 314 - .../core/internal/config/deployer.go | 718 - .../core/internal/config/deployer_test.go | 792 - .../DankMaterialShell/core/internal/config/dms.go | 57 - .../internal/config/embedded/alacritty-theme.toml | 31 - .../core/internal/config/embedded/alacritty.toml | 37 - .../internal/config/embedded/ghostty-colors.conf | 21 - .../core/internal/config/embedded/ghostty.conf | 51 - .../core/internal/config/embedded/hypr-binds.conf | 162 - .../core/internal/config/embedded/hypr-colors.conf | 25 - .../core/internal/config/embedded/hypr-layout.conf | 11 - .../core/internal/config/embedded/hyprland.conf | 121 - .../core/internal/config/embedded/kitty-tabs.conf | 24 - .../core/internal/config/embedded/kitty-theme.conf | 24 - .../core/internal/config/embedded/kitty.conf | 37 - .../core/internal/config/embedded/niri-alttab.kdl | 10 - .../core/internal/config/embedded/niri-binds.kdl | 221 - .../core/internal/config/embedded/niri-colors.kdl | 39 - .../core/internal/config/embedded/niri-greeter.kdl | 17 - .../core/internal/config/embedded/niri-layout.kdl | 22 - .../core/internal/config/embedded/niri.kdl | 279 - .../core/internal/config/embedded/testpage.pdf | Bin 7396 -> 0 bytes .../core/internal/config/hyprland.go | 15 - .../DankMaterialShell/core/internal/config/niri.go | 21 - .../core/internal/config/terminals.go | 24 - .../core/internal/config/testpage.go | 6 - .../core/internal/dank16/dank16.go | 651 - .../core/internal/dank16/dank16_test.go | 681 - .../core/internal/dank16/terminals.go | 135 - .../core/internal/deps/detector.go | 51 - .../core/internal/distros/arch.go | 807 - .../core/internal/distros/base.go | 721 - .../core/internal/distros/base_test.go | 216 - .../core/internal/distros/debian.go | 706 - .../core/internal/distros/factory.go | 19 - .../core/internal/distros/fedora.go | 550 - .../core/internal/distros/gentoo.go | 700 - .../core/internal/distros/interface.go | 158 - .../core/internal/distros/manual_packages.go | 663 - .../core/internal/distros/manual_packages_test.go | 122 - .../core/internal/distros/minimal_install.go | 44 - .../core/internal/distros/opensuse.go | 856 - .../core/internal/distros/osinfo.go | 122 - .../core/internal/distros/ubuntu.go | 702 - .../core/internal/errdefs/errdefs.go | 65 - .../core/internal/geolocation/client.go | 42 - .../core/internal/geolocation/client_geoclue.go | 243 - .../core/internal/geolocation/client_ip.go | 91 - .../core/internal/geolocation/types.go | 15 - .../greeter/assets/apparmor/usr.bin.dms-greeter | 91 - .../core/internal/greeter/installer.go | 2076 --- .../core/internal/greeter/installer_test.go | 98 - .../core/internal/headless/runner.go | 418 - .../core/internal/headless/runner_test.go | 459 - .../core/internal/keybinds/discovery.go | 107 - .../core/internal/keybinds/discovery_test.go | 287 - .../core/internal/keybinds/providers/hyprland.go | 497 - .../internal/keybinds/providers/hyprland_parser.go | 627 - .../keybinds/providers/hyprland_parser_test.go | 519 - .../internal/keybinds/providers/hyprland_test.go | 220 - .../core/internal/keybinds/providers/jsonfile.go | 119 - .../internal/keybinds/providers/jsonfile_test.go | 281 - .../core/internal/keybinds/providers/mangowc.go | 442 - .../internal/keybinds/providers/mangowc_parser.go | 613 - .../keybinds/providers/mangowc_parser_test.go | 499 - .../internal/keybinds/providers/mangowc_test.go | 320 - .../core/internal/keybinds/providers/miracle.go | 95 - .../internal/keybinds/providers/miracle_parser.go | 320 - .../core/internal/keybinds/providers/niri.go | 650 - .../internal/keybinds/providers/niri_parser.go | 400 - .../keybinds/providers/niri_parser_test.go | 630 - .../core/internal/keybinds/providers/niri_test.go | 661 - .../core/internal/keybinds/providers/sway.go | 150 - .../internal/keybinds/providers/sway_parser.go | 364 - .../keybinds/providers/sway_parser_test.go | 471 - .../core/internal/keybinds/providers/sway_test.go | 293 - .../core/internal/keybinds/registry.go | 79 - .../core/internal/keybinds/registry_test.go | 183 - .../core/internal/keybinds/types.go | 47 - .../core/internal/log/filelogger.go | 114 - .../DankMaterialShell/core/internal/log/log.go | 116 - .../core/internal/matugen/matugen.go | 978 -- .../core/internal/matugen/matugen_test.go | 443 - .../core/internal/matugen/queue.go | 143 - .../internal/mocks/brightness/mock_DBusConn.go | 130 - .../mocks/cups/mock_CUPSClientInterface.go | 1246 -- .../internal/mocks/cups_pkhelper/mock_PkHelper.go | 708 - .../core/internal/mocks/evdev/mock_EvdevDevice.go | 295 - .../core/internal/mocks/geolocation/mock_Client.go | 203 - .../Wifx/gonetworkmanager/v2/mock_AccessPoint.go | 689 - .../gonetworkmanager/v2/mock_ActiveConnection.go | 1025 -- .../Wifx/gonetworkmanager/v2/mock_Connection.go | 646 - .../Wifx/gonetworkmanager/v2/mock_Device.go | 1638 -- .../gonetworkmanager/v2/mock_DeviceWireless.go | 2241 --- .../Wifx/gonetworkmanager/v2/mock_IP4Config.go | 772 - .../gonetworkmanager/v2/mock_NetworkManager.go | 2349 --- .../Wifx/gonetworkmanager/v2/mock_Settings.go | 467 - .../github.com/godbus/dbus/v5/mock_BusObject.go | 649 - .../mocks/internal/plugins/mock_GitClient.go | 181 - .../core/internal/mocks/net/mock_Conn.go | 427 - .../core/internal/mocks/network/mock_Backend.go | 1975 --- .../core/internal/mocks/utils/mock_AppChecker.go | 242 - .../internal/mocks/version/mock_VersionFetcher.go | 144 - .../internal/mocks/wlclient/mock_WaylandDisplay.go | 229 - .../mocks/wlcontext/mock_WaylandContext.go | 226 - .../core/internal/notify/notify.go | 185 - .../DankMaterialShell/core/internal/pam/pam.go | 892 - .../core/internal/pam/pam_test.go | 671 - .../core/internal/plugins/manager.go | 588 - .../core/internal/plugins/manager_test.go | 247 - .../core/internal/plugins/registry.go | 258 - .../core/internal/plugins/registry_test.go | 326 - .../core/internal/plugins/search.go | 91 - .../core/internal/proto/dwl_ipc/dwl_ipc.go | 791 - .../proto/ext_data_control/data_control.go | 695 - .../core/internal/proto/ext_workspace/workspace.go | 1040 -- .../keyboard_shortcuts_inhibit.go | 284 - .../proto/wlr_gamma_control/gamma_control.go | 268 - .../internal/proto/wlr_layer_shell/layer_shell.go | 792 - .../wlr_output_management/output_management.go | 1515 -- .../proto/wlr_output_power/output_power.go | 283 - .../internal/proto/wlr_screencopy/screencopy.go | 532 - .../internal/proto/wp_viewporter/viewporter.go | 399 - .../internal/proto/xml/dwl-ipc-unstable-v2.xml | 252 - .../internal/proto/xml/ext-data-control-v1.xml | 276 - .../core/internal/proto/xml/ext-workspace-v1.xml | 422 - .../xml/keyboard-shortcuts-inhibit-unstable-v1.xml | 143 - .../proto/xml/wlr-gamma-control-unstable-v1.xml | 126 - .../proto/xml/wlr-layer-shell-unstable-v1.xml | 407 - .../xml/wlr-output-management-unstable-v1.xml | 611 - .../wlr-output-power-management-unstable-v1.xml | 128 - .../proto/xml/wlr-screencopy-unstable-v1.xml | 234 - .../core/internal/screenshot/compositor.go | 694 - .../core/internal/screenshot/encode.go | 172 - .../core/internal/screenshot/notify.go | 180 - .../core/internal/screenshot/region.go | 859 - .../core/internal/screenshot/region_input.go | 274 - .../core/internal/screenshot/region_render.go | 326 - .../core/internal/screenshot/screenshot.go | 1089 -- .../core/internal/screenshot/shm.go | 35 - .../core/internal/screenshot/state.go | 65 - .../core/internal/screenshot/theme.go | 125 - .../core/internal/screenshot/types.go | 81 - .../core/internal/server/apppicker/handlers.go | 51 - .../core/internal/server/apppicker/manager.go | 48 - .../core/internal/server/apppicker/models.go | 8 - .../core/internal/server/bluez/agent.go | 341 - .../core/internal/server/bluez/broker.go | 21 - .../core/internal/server/bluez/broker_test.go | 220 - .../core/internal/server/bluez/handlers.go | 237 - .../core/internal/server/bluez/handlers_test.go | 41 - .../core/internal/server/bluez/manager.go | 588 - .../internal/server/bluez/subscription_broker.go | 86 - .../core/internal/server/bluez/types.go | 78 - .../core/internal/server/bluez/types_test.go | 210 - .../core/internal/server/brightness/ddc.go | 510 - .../core/internal/server/brightness/ddc_filter.go | 135 - .../internal/server/brightness/ddc_filter_test.go | 122 - .../core/internal/server/brightness/ddc_test.go | 135 - .../core/internal/server/brightness/handlers.go | 124 - .../core/internal/server/brightness/logind.go | 66 - .../core/internal/server/brightness/logind_test.go | 95 - .../core/internal/server/brightness/manager.go | 389 - .../internal/server/brightness/manager_test.go | 11 - .../core/internal/server/brightness/sysfs.go | 267 - .../server/brightness/sysfs_logind_test.go | 278 - .../core/internal/server/brightness/sysfs_test.go | 180 - .../core/internal/server/brightness/types.go | 184 - .../core/internal/server/brightness/udev.go | 237 - .../core/internal/server/brightness/udev_test.go | 260 - .../core/internal/server/browser/handlers.go | 22 - .../core/internal/server/browser/manager.go | 49 - .../core/internal/server/browser/models.go | 5 - .../core/internal/server/clipboard/handlers.go | 325 - .../core/internal/server/clipboard/manager.go | 1911 --- .../core/internal/server/clipboard/manager_test.go | 531 - .../core/internal/server/clipboard/types.go | 196 - .../core/internal/server/cups/actions.go | 479 - .../internal/server/cups/actions_pkhelper_test.go | 235 - .../core/internal/server/cups/actions_test.go | 450 - .../core/internal/server/cups/handlers.go | 487 - .../core/internal/server/cups/handlers_test.go | 711 - .../core/internal/server/cups/manager.go | 390 - .../core/internal/server/cups/manager_test.go | 363 - .../core/internal/server/cups/pkhelper.go | 184 - .../core/internal/server/cups/pkhelper_test.go | 95 - .../core/internal/server/cups/subscription.go | 245 - .../core/internal/server/cups/subscription_dbus.go | 295 - .../core/internal/server/cups/test_connection.go | 176 - .../internal/server/cups/test_connection_test.go | 397 - .../core/internal/server/cups/testing.go | 13 - .../core/internal/server/cups/types.go | 132 - .../core/internal/server/dbus/handlers.go | 237 - .../core/internal/server/dbus/manager.go | 392 - .../core/internal/server/dbus/types.go | 52 - .../core/internal/server/dwl/handlers.go | 138 - .../core/internal/server/dwl/manager.go | 522 - .../core/internal/server/dwl/manager_test.go | 366 - .../core/internal/server/dwl/types.go | 176 - .../core/internal/server/evdev/handlers.go | 20 - .../core/internal/server/evdev/handlers_test.go | 130 - .../core/internal/server/evdev/manager.go | 413 - .../core/internal/server/evdev/manager_test.go | 344 - .../core/internal/server/evdev/models.go | 6 - .../core/internal/server/extworkspace/handlers.go | 134 - .../core/internal/server/extworkspace/manager.go | 598 - .../internal/server/extworkspace/manager_test.go | 392 - .../core/internal/server/extworkspace/types.go | 169 - .../core/internal/server/freedesktop/actions.go | 112 - .../internal/server/freedesktop/actions_test.go | 145 - .../core/internal/server/freedesktop/constants.go | 23 - .../core/internal/server/freedesktop/handlers.go | 154 - .../internal/server/freedesktop/handlers_test.go | 581 - .../core/internal/server/freedesktop/manager.go | 206 - .../internal/server/freedesktop/manager_test.go | 143 - .../internal/server/freedesktop/screensaver.go | 349 - .../server/freedesktop/screensaver_test.go | 102 - .../core/internal/server/freedesktop/types.go | 66 - .../core/internal/server/freedesktop/types_test.go | 70 - .../core/internal/server/location/handlers.go | 61 - .../core/internal/server/location/manager.go | 175 - .../core/internal/server/location/types.go | 28 - .../core/internal/server/loginctl/actions.go | 88 - .../core/internal/server/loginctl/constants.go | 10 - .../core/internal/server/loginctl/handlers.go | 156 - .../core/internal/server/loginctl/handlers_test.go | 500 - .../core/internal/server/loginctl/manager.go | 723 - .../core/internal/server/loginctl/manager_test.go | 296 - .../core/internal/server/loginctl/monitor.go | 155 - .../core/internal/server/loginctl/monitor_test.go | 298 - .../core/internal/server/loginctl/types.go | 76 - .../core/internal/server/loginctl/types_test.go | 50 - .../core/internal/server/matugen_handler.go | 79 - .../core/internal/server/models/types.go | 47 - .../core/internal/server/models/types_test.go | 52 - .../core/internal/server/network/API.md | 552 - .../core/internal/server/network/agent_iwd.go | 306 - .../server/network/agent_networkmanager.go | 897 - .../server/network/agent_networkmanager_test.go | 355 - .../core/internal/server/network/backend.go | 80 - .../server/network/backend_hybrid_iwd_networkd.go | 245 - .../internal/server/network/backend_hybrid_test.go | 135 - .../core/internal/server/network/backend_iwd.go | 238 - .../internal/server/network/backend_iwd_signals.go | 355 - .../internal/server/network/backend_iwd_test.go | 212 - .../server/network/backend_iwd_unimplemented.go | 133 - .../internal/server/network/backend_iwd_wifi.go | 662 - .../internal/server/network/backend_networkd.go | 301 - .../server/network/backend_networkd_ethernet.go | 120 - .../server/network/backend_networkd_signals.go | 68 - .../server/network/backend_networkd_test.go | 147 - .../network/backend_networkd_unimplemented.go | 99 - .../server/network/backend_networkmanager.go | 405 - .../network/backend_networkmanager_ethernet.go | 402 - .../backend_networkmanager_ethernet_test.go | 134 - .../network/backend_networkmanager_gp_saml.go | 203 - .../network/backend_networkmanager_gp_saml_test.go | 169 - .../network/backend_networkmanager_signals.go | 530 - .../network/backend_networkmanager_signals_test.go | 255 - .../server/network/backend_networkmanager_state.go | 277 - .../network/backend_networkmanager_state_test.go | 82 - .../server/network/backend_networkmanager_test.go | 154 - .../server/network/backend_networkmanager_vpn.go | 1394 -- .../network/backend_networkmanager_vpn_test.go | 138 - .../server/network/backend_networkmanager_wifi.go | 1173 -- .../network/backend_networkmanager_wifi_test.go | 202 - .../core/internal/server/network/broker.go | 22 - .../internal/server/network/connection_test.go | 109 - .../core/internal/server/network/detect.go | 89 - .../core/internal/server/network/detect_test.go | 41 - .../core/internal/server/network/handlers.go | 630 - .../core/internal/server/network/handlers_test.go | 269 - .../core/internal/server/network/helpers.go | 53 - .../core/internal/server/network/manager.go | 626 - .../core/internal/server/network/manager_test.go | 191 - .../core/internal/server/network/monitor.go | 1 - .../core/internal/server/network/priority.go | 187 - .../core/internal/server/network/priority_test.go | 50 - .../internal/server/network/subscription_broker.go | 125 - .../core/internal/server/network/testing.go | 14 - .../core/internal/server/network/types.go | 267 - .../core/internal/server/network/types_test.go | 178 - .../core/internal/server/network/wifi_qrcode.go | 59 - .../core/internal/server/network/wifi_test.go | 148 - .../core/internal/server/network/wired_test.go | 51 - .../core/internal/server/params/params.go | 113 - .../core/internal/server/params/params_test.go | 154 - .../core/internal/server/plugins/handlers.go | 27 - .../core/internal/server/plugins/handlers_test.go | 196 - .../core/internal/server/plugins/install.go | 69 - .../core/internal/server/plugins/list.go | 53 - .../core/internal/server/plugins/list_installed.go | 77 - .../core/internal/server/plugins/search.go | 74 - .../core/internal/server/plugins/types.go | 25 - .../core/internal/server/plugins/uninstall.go | 66 - .../core/internal/server/plugins/update.go | 64 - .../core/internal/server/plugins/utils.go | 17 - .../core/internal/server/router.go | 250 - .../core/internal/server/server.go | 1758 -- .../core/internal/server/server_test.go | 180 - .../core/internal/server/thememode/handlers.go | 154 - .../core/internal/server/thememode/manager.go | 462 - .../core/internal/server/thememode/types.go | 23 - .../core/internal/server/themes/handlers.go | 27 - .../core/internal/server/themes/install.go | 52 - .../core/internal/server/themes/list.go | 54 - .../core/internal/server/themes/list_installed.go | 149 - .../core/internal/server/themes/search.go | 53 - .../core/internal/server/themes/types.go | 47 - .../core/internal/server/themes/uninstall.go | 63 - .../core/internal/server/themes/update.go | 57 - .../core/internal/server/trayrecovery/manager.go | 93 - .../core/internal/server/trayrecovery/recovery.go | 262 - .../core/internal/server/wayland/gamma.go | 167 - .../core/internal/server/wayland/gamma_test.go | 120 - .../core/internal/server/wayland/geolocation.go | 50 - .../core/internal/server/wayland/handlers.go | 182 - .../core/internal/server/wayland/manager.go | 1256 -- .../core/internal/server/wayland/manager_test.go | 414 - .../core/internal/server/wayland/suncalc.go | 122 - .../core/internal/server/wayland/suncalc_test.go | 387 - .../core/internal/server/wayland/types.go | 216 - .../core/internal/server/wayland/types_test.go | 330 - .../core/internal/server/wlcontext/context.go | 200 - .../core/internal/server/wlcontext/context_test.go | 128 - .../core/internal/server/wlroutput/handlers.go | 282 - .../core/internal/server/wlroutput/manager.go | 492 - .../core/internal/server/wlroutput/manager_test.go | 414 - .../core/internal/server/wlroutput/types.go | 192 - .../core/internal/themes/manager.go | 258 - .../core/internal/themes/registry.go | 309 - .../core/internal/themes/search.go | 40 - .../DankMaterialShell/core/internal/tui/app.go | 240 - .../DankMaterialShell/core/internal/tui/banner.go | 21 - .../core/internal/tui/messages.go | 39 - .../DankMaterialShell/core/internal/tui/states.go | 22 - .../DankMaterialShell/core/internal/tui/styles.go | 124 - .../core/internal/tui/views_config.go | 382 - .../core/internal/tui/views_dependencies.go | 304 - .../core/internal/tui/views_gentoo_gcc.go | 103 - .../core/internal/tui/views_gentoo_use_flags.go | 92 - .../core/internal/tui/views_install.go | 405 - .../core/internal/tui/views_password.go | 338 - .../core/internal/tui/views_selection.go | 224 - .../core/internal/tui/views_welcome.go | 216 - .../DankMaterialShell/core/internal/utils/dbus.go | 37 - .../DankMaterialShell/core/internal/utils/exec.go | 44 - .../core/internal/utils/flatpak.go | 83 - .../core/internal/utils/flatpak_test.go | 271 - .../DankMaterialShell/core/internal/utils/group.go | 37 - .../core/internal/utils/group_test.go | 142 - .../core/internal/utils/gsettings.go | 31 - .../DankMaterialShell/core/internal/utils/math.go | 13 - .../DankMaterialShell/core/internal/utils/paths.go | 70 - .../core/internal/utils/paths_test.go | 43 - .../core/internal/utils/slices.go | 56 - .../core/internal/utils/slices_test.go | 72 - .../core/internal/version/version.go | 268 - .../core/internal/version/version_test.go | 362 - .../core/internal/wayland/client/helpers.go | 26 - .../core/internal/wayland/shm/buffer.go | 298 - .../windowrules/providers/hyprland_parser.go | 658 - .../windowrules/providers/hyprland_parser_test.go | 280 - .../internal/windowrules/providers/niri_parser.go | 875 - .../windowrules/providers/niri_parser_test.go | 335 - .../windowrules/providers/providers_test.go | 22 - .../core/internal/windowrules/types.go | 103 - .../DankMaterialShell/core/pkg/dbusutil/variant.go | 95 - .../core/pkg/dbusutil/variant_test.go | 155 - .../DankMaterialShell/core/pkg/go-wayland/AUTHORS | 3 - .../DankMaterialShell/core/pkg/go-wayland/LICENSE | 24 - .../core/pkg/go-wayland/README.md | 25 - .../DankMaterialShell/core/pkg/go-wayland/generate | 4 - .../core/pkg/go-wayland/generatep | 9 - .../core/pkg/go-wayland/wayland/client/client.go | 7542 --------- .../core/pkg/go-wayland/wayland/client/common.go | 55 - .../core/pkg/go-wayland/wayland/client/context.go | 143 - .../pkg/go-wayland/wayland/client/context_test.go | 111 - .../core/pkg/go-wayland/wayland/client/display.go | 37 - .../core/pkg/go-wayland/wayland/client/doc.go | 6 - .../core/pkg/go-wayland/wayland/client/event.go | 120 - .../core/pkg/go-wayland/wayland/client/request.go | 44 - .../core/pkg/go-wayland/wayland/client/util.go | 24 - .../wayland/stable/xdg-shell/xdg_shell.go | 13 - .../DankMaterialShell/core/pkg/ipp/CREDITS.MD | 5 - .../DankMaterialShell/core/pkg/ipp/LICENSE | 201 - .../DankMaterialShell/core/pkg/ipp/adapter-http.go | 132 - .../DankMaterialShell/core/pkg/ipp/adapter.go | 9 - .../DankMaterialShell/core/pkg/ipp/attribute.go | 528 - .../DankMaterialShell/core/pkg/ipp/constants.go | 450 - .../DankMaterialShell/core/pkg/ipp/cups-client.go | 313 - .../DankMaterialShell/core/pkg/ipp/error.go | 31 - .../DankMaterialShell/core/pkg/ipp/ipp-client.go | 329 - .../DankMaterialShell/core/pkg/ipp/request.go | 299 - .../DankMaterialShell/core/pkg/ipp/response.go | 383 - .../DankMaterialShell/core/pkg/ipp/utils.go | 28 - .../DankMaterialShell/core/pkg/syncmap/LICENSE | 28 - .../DankMaterialShell/core/pkg/syncmap/syncmap.go | 537 - .../DankMaterialShell/quickshell/AGENTS.md | 1230 -- .../DankMaterialShell/quickshell/CODENAME | 1 - .../DankMaterialShell/quickshell/Common/Anims.qml | 25 - .../quickshell/Common/AppUsageHistoryData.qml | 123 - .../quickshell/Common/Appearance.qml | 66 - .../quickshell/Common/CacheData.qml | 227 - .../quickshell/Common/CacheUtils.qml | 40 - .../quickshell/Common/DankAnim.qml | 9 - .../quickshell/Common/DankColorAnim.qml | 9 - .../quickshell/Common/DankSocket.qml | 62 - .../quickshell/Common/ElevationShadow.qml | 54 - .../DankMaterialShell/quickshell/Common/I18n.qml | 138 - .../quickshell/Common/KeyUtils.js | 178 - .../quickshell/Common/KeybindActions.js | 1329 -- .../quickshell/Common/ListViewTransitions.qml | 46 - .../quickshell/Common/ModalManager.qml | 35 - .../quickshell/Common/OSDManager.qml | 46 - .../DankMaterialShell/quickshell/Common/Paths.qml | 131 - .../quickshell/Common/PopoutManager.qml | 186 - .../DankMaterialShell/quickshell/Common/Proc.qml | 141 - .../DankMaterialShell/quickshell/Common/Ref.qml | 9 - .../quickshell/Common/SessionData.qml | 1437 -- .../quickshell/Common/SettingsData.qml | 2840 ---- .../quickshell/Common/StockThemes.js | 468 - .../DankMaterialShell/quickshell/Common/Theme.qml | 2410 --- .../quickshell/Common/TrayMenuManager.qml | 36 - .../DankMaterialShell/quickshell/Common/fzf.js | 1308 -- .../quickshell/Common/markdown2html.js | 117 - .../quickshell/Common/settings/Lists.qml | 94 - .../quickshell/Common/settings/Processes.qml | 602 - .../quickshell/Common/settings/SessionSpec.js | 109 - .../quickshell/Common/settings/SessionStore.js | 100 - .../quickshell/Common/settings/SettingsSpec.js | 553 - .../quickshell/Common/settings/SettingsStore.js | 275 - .../DankMaterialShell/quickshell/Common/suncalc.js | 308 - .../DankMaterialShell/quickshell/DMSGreeter.qml | 9 - .../DankMaterialShell/quickshell/DMSShell.qml | 1059 -- .../DankMaterialShell/quickshell/DMSShellIPC.qml | 1728 -- .../quickshell/LICENSE_CHANGE_12_11_2025.md | 23 - .../quickshell/Modals/AppPickerModal.qml | 471 - .../quickshell/Modals/BluetoothPairingModal.qml | 409 - .../quickshell/Modals/BrowserPickerModal.qml | 51 - .../Modals/Changelog/ChangelogContent.qml | 250 - .../Modals/Changelog/ChangelogFeatureCard.qml | 78 - .../quickshell/Modals/Changelog/ChangelogModal.qml | 156 - .../Modals/Changelog/ChangelogUpgradeNote.qml | 27 - .../Modals/Clipboard/ClipboardConstants.qml | 21 - .../Modals/Clipboard/ClipboardContent.qml | 260 - .../quickshell/Modals/Clipboard/ClipboardEntry.qml | 155 - .../Modals/Clipboard/ClipboardHeader.qml | 87 - .../Modals/Clipboard/ClipboardHistoryModal.qml | 174 - .../Modals/Clipboard/ClipboardHistoryPopout.qml | 197 - .../Clipboard/ClipboardKeyboardController.qml | 166 - .../Modals/Clipboard/ClipboardKeyboardHints.qml | 51 - .../Modals/Clipboard/ClipboardThumbnail.qml | 178 - .../quickshell/Modals/Common/ConfirmModal.qml | 291 - .../quickshell/Modals/Common/DankModal.qml | 496 - .../quickshell/Modals/Common/InputModal.qml | 312 - .../quickshell/Modals/DankColorPickerModal.qml | 771 - .../Modals/DankLauncherV2/ActionPanel.qml | 256 - .../Modals/DankLauncherV2/Controller.qml | 1894 --- .../Modals/DankLauncherV2/ControllerUtils.js | 128 - .../Modals/DankLauncherV2/DankLauncherV2Modal.qml | 465 - .../quickshell/Modals/DankLauncherV2/GridItem.qml | 105 - .../Modals/DankLauncherV2/ItemTransformers.js | 237 - .../Modals/DankLauncherV2/LauncherContent.qml | 1075 -- .../Modals/DankLauncherV2/LauncherContextMenu.qml | 510 - .../Modals/DankLauncherV2/NavigationHelpers.js | 254 - .../Modals/DankLauncherV2/ResultItem.qml | 196 - .../Modals/DankLauncherV2/ResultsList.qml | 498 - .../quickshell/Modals/DankLauncherV2/Scorer.js | 265 - .../quickshell/Modals/DankLauncherV2/Section.qml | 114 - .../Modals/DankLauncherV2/SectionHeader.qml | 340 - .../quickshell/Modals/DankLauncherV2/TileItem.qml | 199 - .../quickshell/Modals/DisplayConfirmationModal.qml | 212 - .../Modals/FileBrowser/FileBrowserContent.qml | 920 - .../Modals/FileBrowser/FileBrowserGridDelegate.qml | 253 - .../Modals/FileBrowser/FileBrowserListDelegate.qml | 258 - .../Modals/FileBrowser/FileBrowserModal.qml | 97 - .../Modals/FileBrowser/FileBrowserNavigation.qml | 130 - .../FileBrowser/FileBrowserOverwriteDialog.qml | 127 - .../Modals/FileBrowser/FileBrowserSaveRow.qml | 74 - .../Modals/FileBrowser/FileBrowserSidebar.qml | 70 - .../Modals/FileBrowser/FileBrowserSortMenu.qml | 183 - .../Modals/FileBrowser/FileBrowserSurfaceModal.qml | 66 - .../quickshell/Modals/FileBrowser/FileInfo.qml | 237 - .../Modals/FileBrowser/KeyboardHints.qml | 50 - .../Modals/Greeter/GreeterCompletePage.qml | 492 - .../Modals/Greeter/GreeterDoctorPage.qml | 427 - .../Modals/Greeter/GreeterDoctorResultItem.qml | 109 - .../Modals/Greeter/GreeterFeatureCard.qml | 74 - .../quickshell/Modals/Greeter/GreeterModal.qml | 333 - .../quickshell/Modals/Greeter/GreeterQuickLink.qml | 60 - .../Modals/Greeter/GreeterSettingsCard.qml | 78 - .../Modals/Greeter/GreeterStatusCard.qml | 75 - .../Modals/Greeter/GreeterWelcomePage.qml | 165 - .../quickshell/Modals/KeybindsModal.qml | 347 - .../quickshell/Modals/MuxModal.qml | 633 - .../quickshell/Modals/NetworkInfoModal.qml | 155 - .../quickshell/Modals/NetworkWiredInfoModal.qml | 155 - .../quickshell/Modals/NotificationModal.qml | 225 - .../quickshell/Modals/PolkitAuthModal.qml | 412 - .../quickshell/Modals/PowerMenuModal.qml | 809 - .../quickshell/Modals/ProcessListModal.qml | 609 - .../quickshell/Modals/Settings/ProfileSection.qml | 144 - .../quickshell/Modals/Settings/SettingsContent.qml | 522 - .../quickshell/Modals/Settings/SettingsModal.qml | 382 - .../quickshell/Modals/Settings/SettingsSidebar.qml | 1023 -- .../quickshell/Modals/WifiPasswordModal.qml | 764 - .../quickshell/Modals/WifiQRCodeModal.qml | 170 - .../quickshell/Modals/WindowRuleModal.qml | 1184 -- .../quickshell/Modals/WorkspaceRenameModal.qml | 230 - .../Modules/AppDrawer/AppDrawerPopout.qml | 166 - .../Modules/BlurredWallpaperBackground.qml | 332 - .../BuiltinDesktopPlugins/DesktopClockWidget.qml | 547 - .../OrganicBlobHourBulges.qml | 137 - .../BuiltinDesktopPlugins/SystemMonitorWidget.qml | 743 - .../ControlCenter/BuiltinPlugins/CupsWidget.qml | 321 - .../ControlCenter/BuiltinPlugins/VpnWidget.qml | 33 - .../ControlCenter/Components/ActionTile.qml | 132 - .../ControlCenter/Components/DetailHost.qml | 250 - .../Components/DragDropDetailHost.qml | 91 - .../ControlCenter/Components/DragDropGrid.qml | 1091 -- .../Components/DragDropWidgetWrapper.qml | 289 - .../ControlCenter/Components/EditControls.qml | 245 - .../ControlCenter/Components/HeaderPane.qml | 118 - .../ControlCenter/Components/PowerButton.qml | 55 - .../ControlCenter/Components/SizeControls.qml | 52 - .../ControlCenter/Components/Typography.qml | 46 - .../Modules/ControlCenter/ControlCenterPopout.qml | 272 - .../ControlCenter/Details/AudioInputDetail.qml | 363 - .../ControlCenter/Details/AudioOutputDetail.qml | 544 - .../ControlCenter/Details/BatteryDetail.qml | 267 - .../Details/BluetoothCodecSelector.qml | 332 - .../ControlCenter/Details/BluetoothDetail.qml | 743 - .../ControlCenter/Details/BrightnessDetail.qml | 498 - .../ControlCenter/Details/DiskUsageDetail.qml | 177 - .../ControlCenter/Details/NetworkDetail.qml | 893 - .../Modules/ControlCenter/Models/WidgetModel.qml | 283 - .../ControlCenter/Widgets/AudioSliderRow.qml | 103 - .../Modules/ControlCenter/Widgets/BatteryPill.qml | 46 - .../ControlCenter/Widgets/BrightnessSliderRow.qml | 194 - .../ControlCenter/Widgets/ColorPickerPill.qml | 29 - .../ControlCenter/Widgets/CompactSlider.qml | 71 - .../Modules/ControlCenter/Widgets/CompoundPill.qml | 205 - .../Modules/ControlCenter/Widgets/DetailView.qml | 23 - .../ControlCenter/Widgets/DiskUsagePill.qml | 76 - .../Modules/ControlCenter/Widgets/ErrorPill.qml | 56 - .../ControlCenter/Widgets/InputAudioSliderRow.qml | 87 - .../ControlCenter/Widgets/SmallBatteryButton.qml | 113 - .../ControlCenter/Widgets/SmallDiskUsageButton.qml | 129 - .../ControlCenter/Widgets/SmallToggleButton.qml | 90 - .../Modules/ControlCenter/Widgets/ToggleButton.qml | 134 - .../Modules/ControlCenter/utils/layout.js | 45 - .../Modules/ControlCenter/utils/state.js | 17 - .../Modules/ControlCenter/utils/widgets.js | 90 - .../quickshell/Modules/DankBar/AxisContext.qml | 57 - .../quickshell/Modules/DankBar/BarCanvas.qml | 671 - .../quickshell/Modules/DankBar/CenterSection.qml | 387 - .../quickshell/Modules/DankBar/DankBar.qml | 182 - .../quickshell/Modules/DankBar/DankBarContent.qml | 1459 -- .../quickshell/Modules/DankBar/DankBarWindow.qml | 1058 -- .../quickshell/Modules/DankBar/LeftSection.qml | 119 - .../Modules/DankBar/Popouts/BatteryPopout.qml | 633 - .../Modules/DankBar/Popouts/DWLLayoutPopout.qml | 302 - .../Modules/DankBar/Popouts/VpnPopout.qml | 87 - .../quickshell/Modules/DankBar/RightSection.qml | 121 - .../quickshell/Modules/DankBar/WidgetHost.qml | 290 - .../Modules/DankBar/Widgets/AppsDock.qml | 1011 -- .../DankBar/Widgets/AppsDockContextMenu.qml | 486 - .../DankBar/Widgets/AppsDockOverflowButton.qml | 76 - .../Modules/DankBar/Widgets/AudioVisualization.qml | 94 - .../quickshell/Modules/DankBar/Widgets/Battery.qml | 165 - .../Modules/DankBar/Widgets/CapsLockIndicator.qml | 62 - .../Modules/DankBar/Widgets/ClipboardButton.qml | 314 - .../quickshell/Modules/DankBar/Widgets/Clock.qml | 331 - .../Modules/DankBar/Widgets/ColorPicker.qml | 37 - .../DankBar/Widgets/ControlCenterButton.qml | 830 - .../Modules/DankBar/Widgets/CpuMonitor.qml | 146 - .../Modules/DankBar/Widgets/CpuTemperature.qml | 140 - .../Modules/DankBar/Widgets/DWLLayout.qml | 110 - .../Modules/DankBar/Widgets/DiskUsage.qml | 255 - .../Modules/DankBar/Widgets/FocusedApp.qml | 317 - .../Modules/DankBar/Widgets/GpuTemperature.qml | 224 - .../Modules/DankBar/Widgets/IdleInhibitor.qml | 36 - .../Modules/DankBar/Widgets/KeyboardLayoutName.qml | 268 - .../Modules/DankBar/Widgets/LauncherButton.qml | 123 - .../quickshell/Modules/DankBar/Widgets/Media.qml | 502 - .../Modules/DankBar/Widgets/NetworkMonitor.qml | 147 - .../Modules/DankBar/Widgets/NotepadButton.qml | 367 - .../DankBar/Widgets/NotificationCenterButton.qml | 40 - .../Modules/DankBar/Widgets/PowerMenuButton.qml | 25 - .../Modules/DankBar/Widgets/PrivacyIndicator.qml | 247 - .../Modules/DankBar/Widgets/RamMonitor.qml | 175 - .../Modules/DankBar/Widgets/RunningApps.qml | 902 - .../Modules/DankBar/Widgets/SystemTrayBar.qml | 1893 --- .../Modules/DankBar/Widgets/SystemUpdate.qml | 187 - .../quickshell/Modules/DankBar/Widgets/Vpn.qml | 141 - .../quickshell/Modules/DankBar/Widgets/Weather.qml | 80 - .../Modules/DankBar/Widgets/WorkspaceSwitcher.qml | 1981 --- .../quickshell/Modules/DankDash/DankDashPopout.qml | 425 - .../Modules/DankDash/MediaDropdownOverlay.qml | 513 - .../quickshell/Modules/DankDash/MediaPlayerTab.qml | 785 - .../DankDash/Overview/CalendarOverviewCard.qml | 539 - .../quickshell/Modules/DankDash/Overview/Card.qml | 24 - .../Modules/DankDash/Overview/ClockCard.qml | 113 - .../DankDash/Overview/MediaOverviewCard.qml | 211 - .../DankDash/Overview/SystemMonitorCard.qml | 178 - .../Modules/DankDash/Overview/UserInfoCard.qml | 110 - .../DankDash/Overview/WeatherOverviewCard.qml | 94 - .../quickshell/Modules/DankDash/OverviewTab.qml | 75 - .../quickshell/Modules/DankDash/WallpaperTab.qml | 590 - .../Modules/DankDash/WeatherForecastCard.qml | 206 - .../quickshell/Modules/DankDash/WeatherTab.qml | 1124 -- .../quickshell/Modules/DesktopWidgetLayer.qml | 110 - .../quickshell/Modules/Dock/Dock.qml | 671 - .../quickshell/Modules/Dock/DockAppButton.qml | 670 - .../quickshell/Modules/Dock/DockApps.qml | 646 - .../quickshell/Modules/Dock/DockContextMenu.qml | 585 - .../quickshell/Modules/Dock/DockLauncherButton.qml | 296 - .../quickshell/Modules/Dock/DockOverflowButton.qml | 75 - .../quickshell/Modules/Greetd/GreetdEnv.js | 20 - .../quickshell/Modules/Greetd/GreetdMemory.qml | 128 - .../quickshell/Modules/Greetd/GreetdSettings.qml | 199 - .../quickshell/Modules/Greetd/GreeterContent.qml | 1908 --- .../quickshell/Modules/Greetd/GreeterState.qml | 30 - .../quickshell/Modules/Greetd/GreeterSurface.qml | 34 - .../quickshell/Modules/Greetd/README.md | 277 - .../quickshell/Modules/Greetd/assets/dms-greeter | 424 - .../quickshell/Modules/Greetd/assets/dms-hypr.conf | 3 - .../quickshell/Modules/Greetd/assets/dms-niri.kdl | 23 - .../Modules/Greetd/assets/greet-hyprland.sh | 11 - .../quickshell/Modules/Greetd/assets/greet-niri.sh | 8 - .../Modules/Lock/CustomButtonKeyboard.qml | 41 - .../quickshell/Modules/Lock/FadeToDpmsWindow.qml | 102 - .../quickshell/Modules/Lock/FadeToLockWindow.qml | 102 - .../quickshell/Modules/Lock/Keyboard.qml | 344 - .../quickshell/Modules/Lock/KeyboardController.qml | 40 - .../quickshell/Modules/Lock/Lock.qml | 296 - .../quickshell/Modules/Lock/LockPowerMenu.qml | 820 - .../quickshell/Modules/Lock/LockScreenContent.qml | 1707 -- .../quickshell/Modules/Lock/LockScreenDemo.qml | 46 - .../quickshell/Modules/Lock/LockSurface.qml | 73 - .../quickshell/Modules/Lock/Pam.qml | 405 - .../quickshell/Modules/Lock/VideoScreensaver.qml | 200 - .../quickshell/Modules/Notepad/Notepad.qml | 531 - .../quickshell/Modules/Notepad/NotepadSettings.qml | 367 - .../quickshell/Modules/Notepad/NotepadTabs.qml | 285 - .../Modules/Notepad/NotepadTextEditor.qml | 924 - .../Center/HistoryNotificationCard.qml | 277 - .../Center/HistoryNotificationList.qml | 387 - .../Center/KeyboardNavigatedNotificationList.qml | 311 - .../Notifications/Center/NotificationCard.qml | 1073 -- .../Center/NotificationCenterPopout.qml | 321 - .../Center/NotificationEmptyState.qml | 34 - .../Notifications/Center/NotificationHeader.qml | 158 - .../Center/NotificationKeyboardController.qml | 556 - .../Center/NotificationKeyboardHints.qml | 50 - .../Notifications/Center/NotificationSettings.qml | 449 - .../Notifications/Popup/NotificationPopup.qml | 1164 -- .../Popup/NotificationPopupManager.qml | 239 - .../quickshell/Modules/OSD/AudioOutputOSD.qml | 67 - .../quickshell/Modules/OSD/BrightnessOSD.qml | 274 - .../quickshell/Modules/OSD/CapsLockOSD.qml | 37 - .../quickshell/Modules/OSD/IdleInhibitorOSD.qml | 29 - .../quickshell/Modules/OSD/MediaPlaybackOSD.qml | 319 - .../quickshell/Modules/OSD/MediaVolumeOSD.qml | 264 - .../quickshell/Modules/OSD/MicMuteOSD.qml | 29 - .../quickshell/Modules/OSD/PowerProfileOSD.qml | 43 - .../quickshell/Modules/OSD/VolumeOSD.qml | 254 - .../quickshell/Modules/Plugins/BasePill.qml | 195 - .../quickshell/Modules/Plugins/ColorSetting.qml | 104 - .../Modules/Plugins/DesktopPluginComponent.qml | 67 - .../Modules/Plugins/DesktopPluginWrapper.qml | 758 - .../quickshell/Modules/Plugins/ListSetting.qml | 132 - .../Modules/Plugins/ListSettingWithInput.qml | 256 - .../quickshell/Modules/Plugins/PluginComponent.qml | 333 - .../Modules/Plugins/PluginControlCenterWrapper.qml | 51 - .../quickshell/Modules/Plugins/PluginPopout.qml | 83 - .../quickshell/Modules/Plugins/PluginSettings.qml | 311 - .../quickshell/Modules/Plugins/PopoutComponent.qml | 87 - .../Modules/Plugins/SelectionSetting.qml | 91 - .../quickshell/Modules/Plugins/SliderSetting.qml | 81 - .../quickshell/Modules/Plugins/StringSetting.qml | 84 - .../quickshell/Modules/Plugins/ToggleSetting.qml | 81 - .../quickshell/Modules/ProcessList/DisksView.qml | 346 - .../Modules/ProcessList/PerformanceView.qml | 304 - .../Modules/ProcessList/ProcessContextMenu.qml | 341 - .../Modules/ProcessList/ProcessListPopout.qml | 535 - .../Modules/ProcessList/ProcessesView.qml | 769 - .../quickshell/Modules/ProcessList/SystemView.qml | 386 - .../quickshell/Modules/Settings/AboutTab.qml | 900 - .../quickshell/Modules/Settings/AudioTab.qml | 747 - .../quickshell/Modules/Settings/ClipboardTab.qml | 463 - .../quickshell/Modules/Settings/DankBarTab.qml | 1563 -- .../Modules/Settings/DesktopWidgetBrowser.qml | 477 - .../Modules/Settings/DesktopWidgetInstanceCard.qml | 460 - .../DesktopWidgetSettings/ClockSettings.qml | 163 - .../PluginDesktopWidgetSettings.qml | 137 - .../SystemMonitorSettings.qml | 444 - .../Modules/Settings/DesktopWidgetsTab.qml | 708 - .../Settings/DisplayConfig/DisplayConfigState.qml | 1837 -- .../DisplayConfig/HyprlandOutputSettings.qml | 310 - .../Settings/DisplayConfig/IncludeWarningBox.qml | 94 - .../Settings/DisplayConfig/MonitorCanvas.qml | 82 - .../Modules/Settings/DisplayConfig/MonitorRect.qml | 159 - .../Settings/DisplayConfig/NiriOutputSettings.qml | 368 - .../Settings/DisplayConfig/NoBackendMessage.qml | 60 - .../Modules/Settings/DisplayConfig/OutputCard.qml | 352 - .../Modules/Settings/DisplayConfigTab.qml | 540 - .../Modules/Settings/DisplayWidgetsTab.qml | 522 - .../quickshell/Modules/Settings/DockTab.qml | 657 - .../Modules/Settings/GammaControlTab.qml | 663 - .../quickshell/Modules/Settings/GreeterTab.qml | 784 - .../quickshell/Modules/Settings/KeybindsTab.qml | 672 - .../quickshell/Modules/Settings/LauncherTab.qml | 1306 -- .../quickshell/Modules/Settings/LocaleTab.qml | 91 - .../quickshell/Modules/Settings/LockScreenTab.qml | 458 - .../quickshell/Modules/Settings/MediaPlayerTab.qml | 119 - .../quickshell/Modules/Settings/MuxTab.qml | 112 - .../quickshell/Modules/Settings/NetworkTab.qml | 1999 --- .../Modules/Settings/NotificationsTab.qml | 900 - .../quickshell/Modules/Settings/OSDTab.qml | 165 - .../quickshell/Modules/Settings/PluginBrowser.qml | 856 - .../quickshell/Modules/Settings/PluginListItem.qml | 439 - .../quickshell/Modules/Settings/PluginsTab.qml | 450 - .../quickshell/Modules/Settings/PowerSleepTab.qml | 598 - .../quickshell/Modules/Settings/PrinterTab.qml | 1702 -- .../quickshell/Modules/Settings/RunningAppsTab.qml | 175 - .../quickshell/Modules/Settings/SoundsTab.qml | 168 - .../Modules/Settings/SystemUpdaterTab.qml | 142 - .../quickshell/Modules/Settings/ThemeBrowser.qml | 697 - .../quickshell/Modules/Settings/ThemeColorsTab.qml | 3016 ---- .../quickshell/Modules/Settings/TimeWeatherTab.qml | 1148 -- .../Modules/Settings/TypographyMotionTab.qml | 490 - .../quickshell/Modules/Settings/WallpaperTab.qml | 1368 -- .../Modules/Settings/WidgetSelectionPopup.qml | 382 - .../Modules/Settings/Widgets/DeviceAliasRow.qml | 180 - .../Settings/Widgets/SettingsButtonGroupRow.qml | 117 - .../Modules/Settings/Widgets/SettingsCard.qml | 199 - .../Settings/Widgets/SettingsColorPicker.qml | 119 - .../Settings/Widgets/SettingsDisplayPicker.qml | 103 - .../Modules/Settings/Widgets/SettingsDivider.qml | 11 - .../Settings/Widgets/SettingsDropdownRow.qml | 60 - .../Settings/Widgets/SettingsSliderCard.qml | 108 - .../Modules/Settings/Widgets/SettingsSliderRow.qml | 148 - .../Settings/Widgets/SettingsToggleCard.qml | 120 - .../Modules/Settings/Widgets/SettingsToggleRow.qml | 58 - .../Settings/Widgets/SystemMonitorVariantCard.qml | 390 - .../quickshell/Modules/Settings/WidgetsTab.qml | 1145 -- .../Modules/Settings/WidgetsTabSection.qml | 2940 ---- .../quickshell/Modules/Settings/WindowRulesTab.qml | 685 - .../quickshell/Modules/Settings/WorkspacesTab.qml | 526 - .../quickshell/Modules/SystemUpdatePopout.qml | 329 - .../DankMaterialShell/quickshell/Modules/Toast.qml | 444 - .../quickshell/Modules/WallpaperBackground.qml | 658 - .../Modules/WorkspaceOverlays/HyprlandOverview.qml | 291 - .../WorkspaceOverlays/NiriOverviewOverlay.qml | 322 - .../Modules/WorkspaceOverlays/OverviewWidget.qml | 443 - .../Modules/WorkspaceOverlays/OverviewWindow.qml | 142 - .../PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml | 32 - .../PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml | 57 - .../quickshell/PLUGINS/ColorDemoPlugin/plugin.json | 12 - .../DetailExampleWidget.qml | 138 - .../PLUGINS/ControlCenterDetailExample/plugin.json | 12 - .../ControlCenterExampleWidget.qml | 68 - .../PLUGINS/ControlCenterExample/plugin.json | 12 - .../PLUGINS/ExampleDesktopClock/DesktopClock.qml | 172 - .../ExampleDesktopClock/DesktopClockSettings.qml | 45 - .../PLUGINS/ExampleDesktopClock/plugin.json | 17 - .../PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml | 97 - .../PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml | 151 - .../PLUGINS/ExampleEmojiPlugin/README.md | 52 - .../PLUGINS/ExampleEmojiPlugin/plugin.json | 16 - .../PLUGINS/ExampleWithVariants/README.md | 116 - .../ExampleWithVariants/VariantSettings.qml | 303 - .../PLUGINS/ExampleWithVariants/VariantWidget.qml | 57 - .../PLUGINS/ExampleWithVariants/plugin.json | 16 - .../LauncherExample/LauncherExampleLauncher.qml | 140 - .../LauncherExample/LauncherExampleSettings.qml | 244 - .../quickshell/PLUGINS/LauncherExample/README.md | 244 - .../quickshell/PLUGINS/LauncherExample/plugin.json | 17 - .../LauncherImageExample/LauncherImageExample.qml | 113 - .../PLUGINS/LauncherImageExample/README.md | 43 - .../PLUGINS/LauncherImageExample/plugin.json | 14 - .../quickshell/PLUGINS/POPOUT_SERVICE.md | 294 - .../PopoutControlExample/PopoutControlSettings.qml | 98 - .../PopoutControlExample/PopoutControlWidget.qml | 93 - .../PLUGINS/PopoutControlExample/README.md | 208 - .../PLUGINS/PopoutControlExample/plugin.json | 13 - .../QuickNotesExample/QuickNotesLauncher.qml | 174 - .../QuickNotesExample/QuickNotesSettings.qml | 263 - .../PLUGINS/QuickNotesExample/plugin.json | 17 - .../DankMaterialShell/quickshell/PLUGINS/README.md | 1665 -- .../quickshell/PLUGINS/THEME_REFERENCE.md | 132 - .../PLUGINS/WallpaperWatcherDaemon/README.md | 37 - .../WallpaperWatcherDaemon.qml | 66 - .../WallpaperWatcherSettings.qml | 24 - .../PLUGINS/WallpaperWatcherDaemon/plugin.json | 16 - .../quickshell/PLUGINS/plugin-schema.json | 115 - .../DankMaterialShell/quickshell/README.md | 241 - .../quickshell/Services/AppSearchService.qml | 985 -- .../quickshell/Services/AudioService.qml | 1075 -- .../quickshell/Services/BarWidgetService.qml | 171 - .../quickshell/Services/BatteryService.qml | 271 - .../quickshell/Services/BluetoothService.qml | 523 - .../quickshell/Services/BlurService.qml | 113 - .../quickshell/Services/CalendarService.qml | 317 - .../quickshell/Services/CavaService.qml | 76 - .../quickshell/Services/ChangelogService.qml | 108 - .../quickshell/Services/ClipboardService.qml | 275 - .../quickshell/Services/CompositorService.qml | 677 - .../quickshell/Services/CupsService.qml | 860 - .../quickshell/Services/DMSNetworkService.qml | 944 -- .../quickshell/Services/DMSService.qml | 757 - .../quickshell/Services/DSearchService.qml | 184 - .../quickshell/Services/DesktopService.qml | 94 - .../quickshell/Services/DesktopWidgetRegistry.qml | 232 - .../quickshell/Services/DgopService.qml | 778 - .../quickshell/Services/DisplayService.qml | 1170 -- .../quickshell/Services/DwlService.qml | 454 - .../quickshell/Services/ExtWorkspaceService.qml | 277 - .../quickshell/Services/FirstLaunchService.qml | 111 - .../quickshell/Services/HyprlandService.qml | 338 - .../quickshell/Services/IdleService.qml | 191 - .../quickshell/Services/KeybindsService.qml | 528 - .../quickshell/Services/LegacyNetworkService.qml | 987 -- .../quickshell/Services/LocationService.qml | 55 - .../quickshell/Services/MprisController.qml | 78 - .../quickshell/Services/MultimediaService.qml | 35 - .../quickshell/Services/MuxService.qml | 230 - .../quickshell/Services/NetworkService.qml | 313 - .../quickshell/Services/NiriService.qml | 1494 -- .../quickshell/Services/NotepadStorageService.qml | 473 - .../quickshell/Services/NotificationService.qml | 1237 -- .../quickshell/Services/PluginService.qml | 876 - .../quickshell/Services/PolkitService.qml | 40 - .../quickshell/Services/PopoutService.qml | 709 - .../quickshell/Services/PortalService.qml | 316 - .../quickshell/Services/PowerProfileWatcher.qml | 36 - .../quickshell/Services/PrivacyService.qml | 155 - .../quickshell/Services/SessionService.qml | 619 - .../quickshell/Services/SettingsSearchService.qml | 240 - .../quickshell/Services/SystemUpdateService.qml | 396 - .../quickshell/Services/ToastService.qml | 174 - .../quickshell/Services/TrackArtService.qml | 49 - .../quickshell/Services/UserInfoService.qml | 35 - .../quickshell/Services/VPNService.qml | 221 - .../Services/WallpaperCyclingService.qml | 495 - .../quickshell/Services/WeatherService.qml | 914 - .../quickshell/Services/WlrOutputService.qml | 346 - .../quickshell/Services/niri-wpblur.kdl | 9 - .../quickshell/Shaders/frag/ripple.frag | 61 - .../quickshell/Shaders/frag/wp_disc.frag | 126 - .../quickshell/Shaders/frag/wp_fade.frag | 91 - .../quickshell/Shaders/frag/wp_iris_bloom.frag | 119 - .../quickshell/Shaders/frag/wp_pixelate.frag | 125 - .../quickshell/Shaders/frag/wp_portal.frag | 124 - .../quickshell/Shaders/frag/wp_stripes.frag | 205 - .../quickshell/Shaders/frag/wp_wipe.frag | 129 - .../quickshell/Shaders/qsb/ripple.frag.qsb | Bin 3522 -> 0 bytes .../quickshell/Shaders/qsb/wp_disc.frag.qsb | Bin 6244 -> 0 bytes .../quickshell/Shaders/qsb/wp_fade.frag.qsb | Bin 5123 -> 0 bytes .../quickshell/Shaders/qsb/wp_iris_bloom.frag.qsb | Bin 6549 -> 0 bytes .../quickshell/Shaders/qsb/wp_pixelate.frag.qsb | Bin 6704 -> 0 bytes .../quickshell/Shaders/qsb/wp_portal.frag.qsb | Bin 6456 -> 0 bytes .../quickshell/Shaders/qsb/wp_stripes.frag.qsb | Bin 8873 -> 0 bytes .../quickshell/Shaders/qsb/wp_wipe.frag.qsb | Bin 6262 -> 0 bytes .../DankMaterialShell/quickshell/VERSION | 1 - .../quickshell/Widgets/AppIconRenderer.qml | 130 - .../quickshell/Widgets/AppLauncherGridDelegate.qml | 126 - .../quickshell/Widgets/AppLauncherListDelegate.qml | 140 - .../quickshell/Widgets/CachingImage.qml | 102 - .../quickshell/Widgets/DankActionButton.qml | 44 - .../quickshell/Widgets/DankAlbumArt.qml | 161 - .../quickshell/Widgets/DankBackdrop.qml | 64 - .../quickshell/Widgets/DankButton.qml | 99 - .../quickshell/Widgets/DankButtonGroup.qml | 236 - .../quickshell/Widgets/DankCircularImage.qml | 171 - .../quickshell/Widgets/DankCollapsibleSection.qml | 130 - .../quickshell/Widgets/DankDropdown.qml | 456 - .../quickshell/Widgets/DankFilterChips.qml | 108 - .../quickshell/Widgets/DankFlickable.qml | 179 - .../quickshell/Widgets/DankGridView.qml | 175 - .../quickshell/Widgets/DankIcon.qml | 77 - .../quickshell/Widgets/DankIconPicker.qml | 259 - .../quickshell/Widgets/DankListView.qml | 213 - .../quickshell/Widgets/DankLocationSearch.qml | 266 - .../quickshell/Widgets/DankNFIcon.qml | 164 - .../quickshell/Widgets/DankNumberStepper.qml | 67 - .../quickshell/Widgets/DankOSD.qml | 334 - .../quickshell/Widgets/DankPopout.qml | 620 - .../quickshell/Widgets/DankRipple.qml | 104 - .../quickshell/Widgets/DankSVGIcon.qml | 81 - .../quickshell/Widgets/DankScrollbar.qml | 46 - .../quickshell/Widgets/DankSeekbar.qml | 262 - .../quickshell/Widgets/DankSlideout.qml | 209 - .../quickshell/Widgets/DankSlider.qml | 294 - .../quickshell/Widgets/DankTabBar.qml | 263 - .../quickshell/Widgets/DankTextField.qml | 271 - .../quickshell/Widgets/DankToggle.qml | 195 - .../quickshell/Widgets/DankTooltip.qml | 92 - .../quickshell/Widgets/DankTooltipV2.qml | 154 - .../quickshell/Widgets/FloatingWindowControls.qml | 118 - .../quickshell/Widgets/KeybindItem.qml | 1840 -- .../quickshell/Widgets/M3WaveProgress.qml | 274 - .../quickshell/Widgets/NumericText.qml | 22 - .../quickshell/Widgets/PluginGlobalVar.qml | 30 - .../quickshell/Widgets/ScrollConstants.js | 14 - .../quickshell/Widgets/StateLayer.qml | 74 - .../quickshell/Widgets/StyledRect.qml | 29 - .../quickshell/Widgets/StyledText.qml | 49 - .../quickshell/Widgets/StyledTextMetrics.qml | 24 - .../quickshell/Widgets/SystemLogo.qml | 84 - .../quickshell/Widgets/VpnDetailContent.qml | 235 - .../quickshell/Widgets/VpnProfileDelegate.qml | 287 - .../quickshell/Widgets/WindowBlur.qml | 65 - .../DankMaterialShell/quickshell/assets/dank.svg | 49 - .../quickshell/assets/danklogo.svg | 105 - .../quickshell/assets/danklogo2.svg | 113 - .../quickshell/assets/danklogonormal.svg | 118 - .../quickshell/assets/discord.svg | 1 - .../assets/fonts/inter/InterVariable.ttf | Bin 879708 -> 0 bytes .../quickshell/assets/fonts/inter/LICENSE.txt | 92 - .../quickshell/assets/fonts/inter/README.md | 163 - .../assets/fonts/material-design-icons/LICENSE | 202 - .../assets/fonts/material-design-icons/README.md | 141 - ...lSymbolsRounded[FILL,GRAD,opsz,wght].codepoints | 4102 ----- ...MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf | Bin 14586584 -> 0 bytes ...terialSymbolsRounded[FILL,GRAD,opsz,wght].woff2 | Bin 5094260 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-Bold.ttf | Bin 2672432 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-Light.ttf | Bin 2641408 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-Medium.ttf | Bin 2636736 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf | Bin 2642616 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-Retina.ttf | Bin 2638472 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFont-SemiBold.ttf | Bin 2657272 -> 0 bytes .../fonts/nerd-fonts/FiraCodeNerdFontMono-Bold.ttf | Bin 2677400 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontMono-Light.ttf | Bin 2646620 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontMono-Medium.ttf | Bin 2641764 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontMono-Regular.ttf | Bin 2647492 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontMono-Retina.ttf | Bin 2643500 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontMono-SemiBold.ttf | Bin 2662304 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-Bold.ttf | Bin 2686036 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-Light.ttf | Bin 2655032 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-Medium.ttf | Bin 2650356 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-Regular.ttf | Bin 2656220 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-Retina.ttf | Bin 2652092 -> 0 bytes .../nerd-fonts/FiraCodeNerdFontPropo-SemiBold.ttf | Bin 2670896 -> 0 bytes .../quickshell/assets/fonts/nerd-fonts/LICENSE | 93 - .../quickshell/assets/fonts/nerd-fonts/README.md | 47 - .../quickshell/assets/hyprland.svg | 10 - .../DankMaterialShell/quickshell/assets/labwc.png | Bin 5211 -> 0 bytes .../DankMaterialShell/quickshell/assets/mango.png | Bin 13507 -> 0 bytes .../quickshell/assets/matrix-logo-white.svg | 18 - .../quickshell/assets/miraclewm.svg | 1198 -- .../DankMaterialShell/quickshell/assets/niri.svg | 405 - .../DankMaterialShell/quickshell/assets/pam/fprint | 3 - .../DankMaterialShell/quickshell/assets/pam/login | 5 - .../DankMaterialShell/quickshell/assets/pam/u2f | 3 - .../quickshell/assets/raveos-logo.svg | 2766 --- .../DankMaterialShell/quickshell/assets/reddit.svg | 20 - .../quickshell/assets/sounds/freedesktop/CREDITS | 77 - .../sounds/freedesktop/audio-volume-change.oga | Bin 5596 -> 0 bytes .../sounds/freedesktop/audio-volume-change.wav | Bin 11342 -> 0 bytes .../assets/sounds/freedesktop/desktop-login.oga | Bin 226948 -> 0 bytes .../assets/sounds/freedesktop/desktop-login.wav | Bin 708514 -> 0 bytes .../sounds/freedesktop/message-new-instant.oga | Bin 22733 -> 0 bytes .../sounds/freedesktop/message-new-instant.wav | Bin 180966 -> 0 bytes .../assets/sounds/freedesktop/message.oga | Bin 10429 -> 0 bytes .../assets/sounds/freedesktop/message.wav | Bin 54990 -> 0 bytes .../quickshell/assets/sounds/plasma/LICENSE | 107 - .../quickshell/assets/sounds/plasma/README.md | 47 - .../quickshell/assets/sounds/plasma/power-plug.ogg | Bin 118410 -> 0 bytes .../quickshell/assets/sounds/plasma/power-plug.wav | Bin 528810 -> 0 bytes .../assets/sounds/plasma/power-unplug.ogg | Bin 118408 -> 0 bytes .../assets/sounds/plasma/power-unplug.wav | Bin 528810 -> 0 bytes .../quickshell/assets/sounds/wavconvert.sh | 21 - .../DankMaterialShell/quickshell/assets/sway.svg | 47 - .../quickshell/matugen/configs/alacritty.toml | 3 - .../quickshell/matugen/configs/base.toml | 1 - .../quickshell/matugen/configs/dgop.toml | 3 - .../quickshell/matugen/configs/emacs.toml | 3 - .../quickshell/matugen/configs/equibop.toml | 3 - .../quickshell/matugen/configs/firefox.toml | 3 - .../quickshell/matugen/configs/foot.toml | 3 - .../quickshell/matugen/configs/ghostty.toml | 3 - .../quickshell/matugen/configs/gtk3-dark.toml | 7 - .../quickshell/matugen/configs/gtk3-light.toml | 7 - .../quickshell/matugen/configs/hyprland.toml | 3 - .../quickshell/matugen/configs/kcolorscheme.toml | 11 - .../quickshell/matugen/configs/kitty.toml | 7 - .../quickshell/matugen/configs/mangowc.toml | 4 - .../quickshell/matugen/configs/neovim.toml | 7 - .../quickshell/matugen/configs/niri.toml | 3 - .../quickshell/matugen/configs/pywalfox.toml | 4 - .../quickshell/matugen/configs/qt5ct.toml | 3 - .../quickshell/matugen/configs/qt6ct.toml | 3 - .../quickshell/matugen/configs/vesktop.toml | 3 - .../quickshell/matugen/configs/wezterm.toml | 3 - .../quickshell/matugen/configs/zed.toml | 3 - .../quickshell/matugen/configs/zenbrowser.toml | 3 - .../quickshell/matugen/dms-theme.vsix | Bin 12556 -> 0 bytes .../quickshell/matugen/templates/alacritty.toml | 31 - .../quickshell/matugen/templates/dank-emacs.el | 381 - .../quickshell/matugen/templates/dank-zed.json | 1523 -- .../quickshell/matugen/templates/dank.json | 126 - .../matugen/templates/dark-kcolorscheme.colors | 146 - .../quickshell/matugen/templates/dgop.json | 49 - .../matugen/templates/firefox-userchrome.css | 138 - .../quickshell/matugen/templates/foot.ini | 25 - .../quickshell/matugen/templates/ghostty.conf | 22 - .../quickshell/matugen/templates/gtk-colors.css | 48 - .../matugen/templates/gtk-light-colors.css | 7823 --------- .../quickshell/matugen/templates/hypr-colors.conf | 25 - .../matugen/templates/kcolorscheme.colors | 146 - .../quickshell/matugen/templates/kitty-tabs.conf | 23 - .../quickshell/matugen/templates/kitty.conf | 25 - .../matugen/templates/light-kcolorscheme.colors | 146 - .../quickshell/matugen/templates/mango-colors.conf | 6 - .../quickshell/matugen/templates/neovim-colors.lua | 94 - .../matugen/templates/neovim-lualine.lua | 3 - .../quickshell/matugen/templates/niri-colors.kdl | 39 - .../matugen/templates/pywalfox-colors.json | 22 - .../quickshell/matugen/templates/qtct-colors.conf | 144 - .../quickshell/matugen/templates/veskto-wip.css | 242 - .../quickshell/matugen/templates/vesktop-base.css | 217 - .../quickshell/matugen/templates/vesktop.css | 99 - .../matugen/templates/vscode-color-theme-dark.json | 329 - .../templates/vscode-color-theme-default.json | 281 - .../templates/vscode-color-theme-light.json | 456 - .../quickshell/matugen/templates/wezterm.toml | 13 - .../matugen/templates/zen-userchrome.css | 112 - .../quickshell/matugen/vsix-build/CHANGELOG.md | 5 - .../quickshell/matugen/vsix-build/LICENSE | 21 - .../quickshell/matugen/vsix-build/README.md | 17 - .../quickshell/matugen/vsix-build/danklogo.png | Bin 7660 -> 0 bytes .../quickshell/matugen/vsix-build/package.json | 47 - .../matugen/vsix-build/themes/dankshell-dark.json | 36 - .../vsix-build/themes/dankshell-default.json | 36 - .../matugen/vsix-build/themes/dankshell-light.json | 36 - .../DankMaterialShell/quickshell/qmlformat-all.sh | 7 - .../DankMaterialShell/quickshell/scripts/gtk.sh | 66 - .../quickshell/scripts/i18nsync.py | 361 - .../quickshell/scripts/qmllint-entrypoints.sh | 129 - .../DankMaterialShell/quickshell/scripts/qt.sh | 76 - .../quickshell/scripts/spam-notifications.sh | 207 - .../quickshell/scripts/verify-notifications.sh | 84 - .../DankMaterialShell/quickshell/shell.qml | 36 - .../quickshell/systemd/tmpfiles-dms-greeter.conf | 3 - .../quickshell/translations/README.md | 64 - .../quickshell/translations/WORKFLOW.md | 185 - .../quickshell/translations/en.json | 14342 ---------------- .../translations/extract_settings_index.py | 522 - .../translations/extract_translations.py | 149 - .../quickshell/translations/poexports/de.json | 7175 -------- .../quickshell/translations/poexports/es.json | 7175 -------- .../quickshell/translations/poexports/fa.json | 7175 -------- .../quickshell/translations/poexports/fr.json | 7175 -------- .../quickshell/translations/poexports/he.json | 7175 -------- .../quickshell/translations/poexports/hu.json | 7175 -------- .../quickshell/translations/poexports/it.json | 7175 -------- .../quickshell/translations/poexports/ja.json | 7175 -------- .../quickshell/translations/poexports/nl.json | 7175 -------- .../quickshell/translations/poexports/pl.json | 7175 -------- .../quickshell/translations/poexports/pt.json | 7175 -------- .../quickshell/translations/poexports/ru.json | 7175 -------- .../quickshell/translations/poexports/sv.json | 7175 -------- .../quickshell/translations/poexports/tr.json | 7175 -------- .../quickshell/translations/poexports/zh_CN.json | 7175 -------- .../quickshell/translations/poexports/zh_TW.json | 7175 -------- .../quickshell/translations/replace_qstr.py | 48 - .../translations/settings_search_index.json | 7217 -------- .../quickshell/translations/template.json | 16732 ------------------- raveos-theme/hyprland/theme-data/background | Bin 225018 -> 0 bytes .../theme-data/fastfetch/config-kitty.jsonc | 47 - .../hyprland/theme-data/fastfetch/config.jsonc | 93 - .../hyprland/theme-data/fastfetch/raveos-logo.png | Bin 136727 -> 0 bytes .../hyprland/theme-data/fastfetch/raveos-logo.txt | 19 - .../hyprland/theme-data/hypr/dms/colors.conf | 22 - .../hyprland/theme-data/hypr/dms/cursor.conf | 6 - .../hyprland/theme-data/hypr/dms/layout.conf | 11 - .../hyprland/theme-data/hypr/dms/windowrules.conf | 0 .../hyprland/theme-data/hypr/hyprland.conf | 154 - .../hyprland/theme-data/hypr/monitors.conf | 5 - .../hyprland/theme-data/hypr/scripts/alt-tab.sh | 273 - .../hypr/scripts/raveos-monitor-setup.sh | 100 - .../hyprland/theme-data/hypr/workspaces.conf | 2 - raveos-theme/hyprland/theme-data/kitty/kitty.conf | 38 - .../theme-data/profile.d/raveos-fastfetch.sh | 13 - .../hyprland/theme-data/sddm/astronaut.conf | 162 - .../theme-data/sddm/new-raveos-main-bg.jpeg | Bin 225018 -> 0 bytes raveos-theme/hyprland/theme-data/sddm/sddm.conf | 2 - 1178 files changed, 494316 deletions(-) delete mode 100644 raveos-theme/hyprland/.SRCINFO delete mode 100644 raveos-theme/hyprland/PKGBUILD delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme-0.0.0-6-any.pkg.tar.zst delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.BUILDINFO delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.INSTALL delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.MTREE delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.PKGINFO delete mode 100755 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/raveos-hyprland-theme/auto-apply.sh delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/systemd/system/raveos-hyprland-theme-apply.service delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.changelog-1.2 delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.firstlaunch delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/settings.json delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config-kitty.jsonc delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config.jsonc delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.png delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.txt delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/cursor.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/layout.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/windowrules.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/hyprland.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/monitors.conf delete mode 100755 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/alt-tab.sh delete mode 100755 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/raveos-monitor-setup.sh delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/workspaces.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/kitty/kitty.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/profile.d/raveos-fastfetch.sh delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/astronaut.conf delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg delete mode 100644 raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/sddm.conf delete mode 100644 raveos-theme/hyprland/metadata.json delete mode 100644 raveos-theme/hyprland/new-raveos-main-bg.jpeg delete mode 100644 raveos-theme/hyprland/raveos-hyprland-apply.sh delete mode 100644 raveos-theme/hyprland/raveos-hyprland-theme-apply.service delete mode 100644 raveos-theme/hyprland/raveos-hyprland-theme.install delete mode 100644 raveos-theme/hyprland/theme-data.tar.gz delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/.changelog-1.2 delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/.firstlaunch delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/Makefile delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/dank.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/danklogo.svg delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/core/build_dankinstall.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dankinstall/main.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/assets/cli-policy.default.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_auth.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_blur.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_brightness.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_chroma.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_clipboard.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_colorpicker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_common.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_config.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dank16.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_doctor.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_download.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dpms.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_features.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_keybinds.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_matugen.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_notify.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_open.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_randr.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_root.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_screenshot.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_setup.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_windowrules.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/dpms_client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/immutable_policy.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main_distro.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/randr_client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/server_client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/shell.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/ui.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/utils.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.mod delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.sum delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/core/install.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/blur/probe.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/clipboard.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/store.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/watch.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/color.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/picker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/shm.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/dms.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty-theme.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty-colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-binds.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-layout.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hyprland.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-tabs.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-theme.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-alttab.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-binds.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-colors.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-greeter.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-layout.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/testpage.pdf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/hyprland.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/niri.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/terminals.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/testpage.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/terminals.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/deps/detector.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/arch.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/debian.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/factory.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/fedora.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/gentoo.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/interface.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/minimal_install.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/opensuse.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/osinfo.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/ubuntu.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/errdefs/errdefs.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_geoclue.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_ip.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/assets/apparmor/usr.bin.dms-greeter delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/filelogger.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/log.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/queue.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/brightness/mock_DBusConn.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups/mock_CUPSClientInterface.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups_pkhelper/mock_PkHelper.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/evdev/mock_EvdevDevice.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/geolocation/mock_Client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/internal/plugins/mock_GitClient.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/net/mock_Conn.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/network/mock_Backend.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/utils/mock_AppChecker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/version/mock_VersionFetcher.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlclient/mock_WaylandDisplay.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlcontext/mock_WaylandContext.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/notify/notify.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/search.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/dwl_ipc/dwl_ipc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_data_control/data_control.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_workspace/workspace.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit/keyboard_shortcuts_inhibit.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_gamma_control/gamma_control.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_layer_shell/layer_shell.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_management/output_management.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_power/output_power.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_screencopy/screencopy.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wp_viewporter/viewporter.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/dwl-ipc-unstable-v2.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-data-control-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-workspace-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/keyboard-shortcuts-inhibit-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-gamma-control-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-layer-shell-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-management-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-power-management-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-screencopy-unstable-v1.xml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/compositor.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/encode.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/notify.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_input.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_render.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/screenshot.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/shm.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/state.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/theme.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/models.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/agent.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/subscription_broker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_logind_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/models.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/testing.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/models.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/constants.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/actions.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/constants.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/matugen_handler.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/API.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_iwd.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_iwd_networkd.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_signals.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_unimplemented.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_wifi.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_ethernet.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_signals.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_unimplemented.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/broker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/connection_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/helpers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/monitor.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/subscription_broker.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/testing.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_qrcode.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wired_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/install.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list_installed.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/search.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/uninstall.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/update.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/utils.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/router.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/install.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list_installed.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/search.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/uninstall.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/update.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/recovery.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/geolocation.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/handlers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/manager.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/registry.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/search.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/app.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/banner.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/messages.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/states.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/styles.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_config.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_install.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_password.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_selection.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/dbus.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/exec.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/gsettings.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/math.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/client/helpers.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/shm/buffer.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/providers_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/types.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/AUTHORS delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/README.md delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generate delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generatep delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/common.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context_test.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/display.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/doc.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/event.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/request.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/util.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/stable/xdg-shell/xdg_shell.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/CREDITS.MD delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter-http.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/attribute.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/constants.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/cups-client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/error.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/ipp-client.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/request.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/response.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/utils.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/syncmap.go delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/AGENTS.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/CODENAME delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Anims.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/AppUsageHistoryData.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Appearance.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheData.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheUtils.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankAnim.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankColorAnim.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankSocket.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ElevationShadow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/I18n.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeyUtils.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeybindActions.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ListViewTransitions.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ModalManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/OSDManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Paths.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/PopoutManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Proc.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Ref.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SessionData.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SettingsData.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/StockThemes.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Theme.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/TrayMenuManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/fzf.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/markdown2html.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Lists.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Processes.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionSpec.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionStore.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsSpec.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsStore.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/suncalc.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSGreeter.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShell.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShellIPC.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/LICENSE_CHANGE_12_11_2025.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/AppPickerModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BluetoothPairingModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BrowserPickerModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogFeatureCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogUpgradeNote.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardConstants.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardEntry.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHeader.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardThumbnail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/ConfirmModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/DankModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/InputModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankColorPickerModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ActionPanel.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Controller.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ControllerUtils.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/GridItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ItemTransformers.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/NavigationHelpers.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultsList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Scorer.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Section.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/SectionHeader.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/TileItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DisplayConfirmationModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserListDelegate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserNavigation.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserOverwriteDialog.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSaveRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSidebar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSortMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSurfaceModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileInfo.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/KeyboardHints.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterCompletePage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorPage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorResultItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterFeatureCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterQuickLink.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterSettingsCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterStatusCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterWelcomePage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/KeybindsModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/MuxModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkInfoModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkWiredInfoModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NotificationModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PolkitAuthModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PowerMenuModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/ProcessListModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/ProfileSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiPasswordModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiQRCodeModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WindowRuleModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WorkspaceRenameModal.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopup.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopupManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/AudioOutputOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/BrightnessOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/CapsLockOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/IdleInhibitorOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaPlaybackOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MicMuteOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/PowerProfileOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/VolumeOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/BasePill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ColorSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSettingWithInput.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PopoutComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SelectionSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SliderSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/StringSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ToggleSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/DisksView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/PerformanceView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessListPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessesView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/SystemView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AboutTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/ripple.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_disc.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_fade.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_iris_bloom.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_pixelate.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_portal.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_stripes.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_wipe.frag delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/ripple.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_disc.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_fade.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_iris_bloom.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_pixelate.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_portal.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_stripes.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_wipe.frag.qsb delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/VERSION delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppIconRenderer.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherGridDelegate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherListDelegate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/CachingImage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankActionButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankAlbumArt.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankBackdrop.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButtonGroup.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCircularImage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCollapsibleSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankDropdown.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFilterChips.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFlickable.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankGridView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIcon.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIconPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankListView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankLocationSearch.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNFIcon.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNumberStepper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankRipple.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSVGIcon.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankScrollbar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSeekbar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlideout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlider.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTabBar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTextField.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankToggle.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltip.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltipV2.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/FloatingWindowControls.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/KeybindItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/M3WaveProgress.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/NumericText.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/PluginGlobalVar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/ScrollConstants.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StateLayer.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledRect.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledText.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledTextMetrics.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/SystemLogo.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnDetailContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnProfileDelegate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/WindowBlur.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/dank.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo2.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogonormal.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/discord.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/InterVariable.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/LICENSE.txt delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].codepoints delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].woff2 delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Bold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Light.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Medium.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Retina.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-SemiBold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Bold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Light.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Medium.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Regular.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Retina.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-SemiBold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Bold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Light.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Medium.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Regular.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Retina.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-SemiBold.ttf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/hyprland.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/labwc.png delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/mango.png delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/matrix-logo-white.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/miraclewm.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/niri.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/fprint delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/login delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/u2f delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/raveos-logo.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/reddit.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/CREDITS delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.oga delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.wav delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.oga delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.wav delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.oga delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.wav delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.oga delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.wav delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.ogg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.wav delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.ogg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.wav delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/wavconvert.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sway.svg delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/alacritty.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/base.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/dgop.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/emacs.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/equibop.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/firefox.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/foot.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/ghostty.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-dark.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-light.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/hyprland.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kcolorscheme.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kitty.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/mangowc.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/neovim.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/niri.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/pywalfox.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt5ct.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt6ct.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/vesktop.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/wezterm.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zed.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zenbrowser.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/dms-theme.vsix delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/alacritty.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-emacs.el delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-zed.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dark-kcolorscheme.colors delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dgop.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/firefox-userchrome.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/foot.ini delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/ghostty.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-colors.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-light-colors.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/hypr-colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kcolorscheme.colors delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty-tabs.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/light-kcolorscheme.colors delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/mango-colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-colors.lua delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-lualine.lua delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/niri-colors.kdl delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/pywalfox-colors.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/qtct-colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/veskto-wip.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop-base.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-dark.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-default.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-light.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/wezterm.toml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/zen-userchrome.css delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/CHANGELOG.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/LICENSE delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/danklogo.png delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/package.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-dark.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-default.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-light.json delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/qmlformat-all.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/gtk.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/i18nsync.py delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qmllint-entrypoints.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qt.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/spam-notifications.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/verify-notifications.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/shell.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/systemd/tmpfiles-dms-greeter.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/README.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/WORKFLOW.md delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/en.json delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_settings_index.py delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_translations.py delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/de.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/es.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fa.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fr.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/he.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/hu.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/it.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ja.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/nl.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pl.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pt.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ru.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/sv.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/tr.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_CN.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_TW.json delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/replace_qstr.py delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/settings_search_index.json delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/template.json delete mode 100644 raveos-theme/hyprland/theme-data/background delete mode 100644 raveos-theme/hyprland/theme-data/fastfetch/config-kitty.jsonc delete mode 100644 raveos-theme/hyprland/theme-data/fastfetch/config.jsonc delete mode 100644 raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.png delete mode 100644 raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.txt delete mode 100644 raveos-theme/hyprland/theme-data/hypr/dms/colors.conf delete mode 100644 raveos-theme/hyprland/theme-data/hypr/dms/cursor.conf delete mode 100644 raveos-theme/hyprland/theme-data/hypr/dms/layout.conf delete mode 100644 raveos-theme/hyprland/theme-data/hypr/dms/windowrules.conf delete mode 100644 raveos-theme/hyprland/theme-data/hypr/hyprland.conf delete mode 100644 raveos-theme/hyprland/theme-data/hypr/monitors.conf delete mode 100755 raveos-theme/hyprland/theme-data/hypr/scripts/alt-tab.sh delete mode 100755 raveos-theme/hyprland/theme-data/hypr/scripts/raveos-monitor-setup.sh delete mode 100644 raveos-theme/hyprland/theme-data/hypr/workspaces.conf delete mode 100644 raveos-theme/hyprland/theme-data/kitty/kitty.conf delete mode 100644 raveos-theme/hyprland/theme-data/profile.d/raveos-fastfetch.sh delete mode 100644 raveos-theme/hyprland/theme-data/sddm/astronaut.conf delete mode 100644 raveos-theme/hyprland/theme-data/sddm/new-raveos-main-bg.jpeg delete mode 100644 raveos-theme/hyprland/theme-data/sddm/sddm.conf (limited to 'raveos-theme/hyprland') diff --git a/raveos-theme/hyprland/.SRCINFO b/raveos-theme/hyprland/.SRCINFO deleted file mode 100644 index fa1efc3..0000000 --- a/raveos-theme/hyprland/.SRCINFO +++ /dev/null @@ -1,11 +0,0 @@ -pkgbase = raveos-hyprland-theme - pkgdesc = RaveOS Hyprland theme payload and installer - pkgver = 0.0.0 - pkgrel = 6 - url = https://raveos.local - install = raveos-hyprland-theme.install - arch = any - license = custom - depends = fastfetch - -pkgname = raveos-hyprland-theme diff --git a/raveos-theme/hyprland/PKGBUILD b/raveos-theme/hyprland/PKGBUILD deleted file mode 100644 index ce5422f..0000000 --- a/raveos-theme/hyprland/PKGBUILD +++ /dev/null @@ -1,36 +0,0 @@ -pkgname=raveos-hyprland-theme -pkgver=0.0.0 -pkgrel=8 -pkgdesc="RaveOS Hyprland theme payload and installer (includes DankMaterialShell)" -arch=('any') -url="https://raveos.local" -license=('custom') -depends=('fastfetch' 'quickshell' 'go' 'matugen' 'socat') -install="${pkgname}.install" -source=() -sha256sums=() - -# Build redirection -BUILDDIR="${startdir}/build" -PKGDEST="${startdir}/build" -SRCDEST="${startdir}/build" -SRCPKGDEST="${startdir}/build" -LOGDEST="${startdir}/build" - -build() { - cd "${startdir}/theme-data/DankMaterialShell/core" - go build -o dms ./cmd/dms/ -} - -package() { - install -dm755 "${pkgdir}/usr/share/raveos/hyprland-theme" - cp -r --no-preserve=ownership "${startdir}/theme-data" "${pkgdir}/usr/share/raveos/hyprland-theme/" - - # Install DMS binary - install -Dm755 "${startdir}/theme-data/DankMaterialShell/core/dms" "${pkgdir}/usr/bin/dms" - - install -Dm755 "${startdir}/raveos-hyprland-apply.sh" \ - "${pkgdir}/usr/lib/raveos-hyprland-theme/auto-apply.sh" - install -Dm644 "${startdir}/raveos-hyprland-theme-apply.service" \ - "${pkgdir}/usr/lib/systemd/system/raveos-hyprland-theme-apply.service" -} diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme-0.0.0-6-any.pkg.tar.zst b/raveos-theme/hyprland/build/raveos-hyprland-theme-0.0.0-6-any.pkg.tar.zst deleted file mode 100644 index e3663bc..0000000 Binary files a/raveos-theme/hyprland/build/raveos-hyprland-theme-0.0.0-6-any.pkg.tar.zst and /dev/null differ diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.BUILDINFO b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.BUILDINFO deleted file mode 100644 index 18e5860..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.BUILDINFO +++ /dev/null @@ -1,1113 +0,0 @@ -format = 2 -pkgname = raveos-hyprland-theme -pkgbase = raveos-hyprland-theme -pkgver = 0.0.0-6 -pkgarch = any -pkgbuild_sha256sum = b256cb1647b4a309671031bb6cd2fb76cd1231b7cdc1fee66b9e5d3efb03ade6 -packager = Unknown Packager -builddate = 1776187236 -builddir = /home/nippy/RaveOS/RaveOS-PKGBUILD/raveos-theme/hyprland/build -startdir = /home/nippy/RaveOS/RaveOS-PKGBUILD/raveos-theme/hyprland -buildtool = makepkg -buildtoolver = 7.1.0 -buildenv = !distcc -buildenv = color -buildenv = !ccache -buildenv = check -buildenv = !sign -options = strip -options = docs -options = !libtool -options = !staticlibs -options = emptydirs -options = zipman -options = purge -options = debug -options = lto -installed = 7zip-26.00-1-x86_64 -installed = aalib-1.4rc5-19-x86_64 -installed = abseil-cpp-20260107.1-1-x86_64 -installed = accountsservice-26.13.3-1-x86_64 -installed = acl-2.3.2-1-x86_64 -installed = ada-3.4.4-1-x86_64 -installed = adwaita-cursors-50.0-1-any -installed = adwaita-fonts-50.0-1-any -installed = adwaita-icon-theme-50.0-1-any -installed = adwaita-icon-theme-legacy-46.2-3-any -installed = alsa-card-profiles-1:1.6.3-1-x86_64 -installed = alsa-lib-1.2.15.3-2-x86_64 -installed = alsa-plugins-1:1.2.12-5-x86_64 -installed = alsa-topology-conf-1.2.5.1-4-any -installed = alsa-ucm-conf-1.2.15.3-1-any -installed = amd-ucode-20260309-1-any -installed = aom-3.13.3-1-x86_64 -installed = appstream-1.1.2-1-x86_64 -installed = archlinux-keyring-20260409-1-any -installed = at-spi2-core-2.60.1-1-x86_64 -installed = attr-2.5.2-1-x86_64 -installed = audit-4.1.4-2-x86_64 -installed = augeas-1.14.1-5-x86_64 -installed = autoconf-2.73-1-any -installed = automake-1.18.1-1-any -installed = avahi-1:0.9rc4-1-x86_64 -installed = baobab-49.1-1-x86_64 -installed = base-3-3-any -installed = base-devel-1-2-any -installed = bash-5.3.9-1-x86_64 -installed = bash-completion-2.17.0-3-any -installed = binutils-2.46-1-x86_64 -installed = bison-3.8.2-8-x86_64 -installed = blas-3.12.1-2-x86_64 -installed = bluez-5.86-4-x86_64 -installed = bluez-libs-5.86-4-x86_64 -installed = bluez-obex-5.86-4-x86_64 -installed = bolt-0.9.11-1-x86_64 -installed = brltty-6.9-3-x86_64 -installed = broadcom-wl-dkms-6.30.223.271-47-x86_64 -installed = brotli-1.2.0-1-x86_64 -installed = btrfs-progs-6.19.1-1-x86_64 -installed = bubblewrap-0.11.1-1-x86_64 -installed = bzip2-1.0.8-6-x86_64 -installed = c-ares-1.34.6-1-x86_64 -installed = ca-certificates-20240618-1-any -installed = ca-certificates-mozilla-3.122-1-x86_64 -installed = ca-certificates-utils-20240618-1-any -installed = cabextract-1.11-2-x86_64 -installed = cairo-1.18.4-1-x86_64 -installed = cairomm-1.16-1.18.0-2-x86_64 -installed = capstone-5.0.7-2-x86_64 -installed = cblas-3.12.1-2-x86_64 -installed = cdparanoia-10.2-9-x86_64 -installed = chaotic-keyring-20251028-1-any -installed = chaotic-mirrorlist-20260302-2-any -installed = cifs-utils-7.5-1-x86_64 -installed = clang-22.1.3-1-x86_64 -installed = cmake-4.3.1-1-x86_64 -installed = colord-1.4.8-1-x86_64 -installed = colord-gtk-common-0.3.1-1-x86_64 -installed = colord-gtk4-0.3.1-1-x86_64 -installed = compiler-rt-22.1.3-1-x86_64 -installed = composefs-1.0.8-1-x86_64 -installed = containerd-2.2.2-1-x86_64 -installed = coreutils-9.10-1-x86_64 -installed = cpio-2.15-3-x86_64 -installed = cppdap-1.58.0-3-x86_64 -installed = cracklib-2.10.3-1-x86_64 -installed = cryptsetup-2.8.6-1-x86_64 -installed = cups-pk-helper-0.2.7-2-x86_64 -installed = curl-8.19.0-1-x86_64 -installed = dav1d-1.5.3-1-x86_64 -installed = db5.3-5.3.28-7-x86_64 -installed = dbus-1.16.2-1-x86_64 -installed = dbus-broker-37-3-x86_64 -installed = dbus-broker-units-37-3-x86_64 -installed = dbus-units-37-3-x86_64 -installed = dconf-0.49.0-1-x86_64 -installed = debugedit-5.2-1-x86_64 -installed = default-cursors-3-1-any -installed = desktop-file-utils-0.28-1-x86_64 -installed = device-mapper-2.03.39-1-x86_64 -installed = dhcpcd-10.3.1-1-x86_64 -installed = diffutils-3.12-2-x86_64 -installed = discord-1:0.0.133-1-x86_64 -installed = distroav-bin-6.0.0-1-x86_64 -installed = distroav-bin-debug-6.0.0-1-x86_64 -installed = dkms-3.4.0-1-any -installed = dmidecode-3.7-1-x86_64 -installed = dnsmasq-2.92-1-x86_64 -installed = docker-1:29.4.0-1-x86_64 -installed = docker-compose-5.1.2-1-x86_64 -installed = dosfstools-4.2-5-x86_64 -installed = double-conversion-3.4.0-1-x86_64 -installed = doublecmd-qt6-1.2.4-2-x86_64 -installed = dtc-1.7.2-5-x86_64 -installed = duktape-2.7.0-7-x86_64 -installed = e2fsprogs-1.47.4-1-x86_64 -installed = edk2-aarch64-202508-1-any -installed = edk2-arm-202508-1-any -installed = edk2-ovmf-202508-1-any -installed = efibootmgr-18-3-x86_64 -installed = efivar-39-1-x86_64 -installed = egl-wayland-4:1.1.21-1-x86_64 -installed = eglexternalplatform-1.2.1-1-any -installed = ell-0.83-1-x86_64 -installed = enchant-2.8.15-2-x86_64 -installed = eog-50.1-1-x86_64 -installed = espeak-ng-1.52.0-1-x86_64 -installed = exempi-2.6.6-3-x86_64 -installed = exfatprogs-1.3.2-1-x86_64 -installed = exiv2-0.28.8-2-x86_64 -installed = expat-2.7.5-1-x86_64 -installed = extra-cmake-modules-6.25.0-1-any -installed = f2fs-tools-1.16.0-3-x86_64 -installed = fakeroot-1.37.2-1-x86_64 -installed = fastfetch-2.61.0-1-x86_64 -installed = ffmpeg-2:8.1-3-x86_64 -installed = fftw-3.3.10-8-x86_64 -installed = file-5.47-2-x86_64 -installed = filesystem-2025.10.12-1-any -installed = findutils-4.10.0-3-x86_64 -installed = firefox-149.0.2-1-x86_64 -installed = flac-1.5.0-1-x86_64 -installed = flatpak-1:1.16.6-1-x86_64 -installed = flex-2.6.4-6-x86_64 -installed = fmt-12.1.0-2-x86_64 -installed = fontconfig-2:2.17.1-1-x86_64 -installed = freeglut-3.8.0-1-x86_64 -installed = freerdp-2:3.24.2-1-x86_64 -installed = freetype2-2.14.3-1-x86_64 -installed = fribidi-1.0.16-2-x86_64 -installed = fuse-common-3.18.2-1-x86_64 -installed = fuse2-2.9.9-5-x86_64 -installed = fuse3-3.18.2-1-x86_64 -installed = gamemode-1.8.2-2-x86_64 -installed = gamescope-3.16.23-1-x86_64 -installed = gawk-5.4.0-1-x86_64 -installed = gc-8.2.12-1-x86_64 -installed = gcc-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = gcc-libs-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = gcr-3.41.2-2-x86_64 -installed = gcr-4-4.4.0.1-1-x86_64 -installed = gdbm-1.26-2-x86_64 -installed = gdk-pixbuf2-2.44.6-2-x86_64 -installed = gedit-50.0-3-x86_64 -installed = geoclue-2.8.0-2-x86_64 -installed = geocode-glib-2-3.26.4-5-x86_64 -installed = geocode-glib-common-3.26.4-5-x86_64 -installed = gettext-1.0-2-x86_64 -installed = gexiv2-0.16.0-2-x86_64 -installed = gfxstream-0.1.2-2-x86_64 -installed = giflib-6.1.2-1-x86_64 -installed = git-2.53.0-1-x86_64 -installed = gjs-2:1.88.0-1-x86_64 -installed = glew-2.3.1-1-x86_64 -installed = glfw-1:3.4-1-x86_64 -installed = glib-networking-1:2.80.1-1-x86_64 -installed = glib2-2.88.0-1-x86_64 -installed = glibc-2.43+r5+g856c426a7534-1-x86_64 -installed = glibmm-2.68-2.88.0-1-x86_64 -installed = glm-1.0.3-1-x86_64 -installed = glslang-1:1.4.341.0-2-x86_64 -installed = glu-9.0.3-3-x86_64 -installed = glusterfs-1:11.2-2-x86_64 -installed = glycin-2.1.1-1-x86_64 -installed = gmp-6.3.0-3-x86_64 -installed = gnome-autoar-0.4.5-1-x86_64 -installed = gnome-bluetooth-3.0-47.1-3-x86_64 -installed = gnome-browser-connector-42.1-8-any -installed = gnome-calculator-49.2-1-x86_64 -installed = gnome-color-manager-3.36.2-1-x86_64 -installed = gnome-console-49.2-1-x86_64 -installed = gnome-control-center-50.1-1-x86_64 -installed = gnome-desktop-1:44.5-1-x86_64 -installed = gnome-desktop-4-1:44.5-1-x86_64 -installed = gnome-desktop-common-1:44.5-1-x86_64 -installed = gnome-disk-utility-46.1-2-x86_64 -installed = gnome-keybindings-50.1-1-x86_64 -installed = gnome-keyring-1:50.0-1-x86_64 -installed = gnome-online-accounts-3.58.1-1-x86_64 -installed = gnome-session-49.2-1-x86_64 -installed = gnome-settings-daemon-49.1-1-x86_64 -installed = gnome-shell-1:49.5-1-x86_64 -installed = gnome-shell-extensions-49.0-1-any -installed = gnome-system-monitor-49.1-1-x86_64 -installed = gnome-tweaks-49.0-2-any -installed = gnu-free-fonts-20120503-9-any -installed = gnulib-l10n-20241231-1-any -installed = gnupg-2.4.9-1-x86_64 -installed = gnutls-3.8.12-2-x86_64 -installed = gobject-introspection-runtime-1.86.0-2-x86_64 -installed = goverlay-1.7.5-1-x86_64 -installed = gperftools-2.18.1-1-x86_64 -installed = gpgme-2.0.1-3-x86_64 -installed = gpgmepp-2.0.0-2-x86_64 -installed = gpm-1.20.7.r38.ge82d1a6-6-x86_64 -installed = gptfdisk-1.0.10-2-x86_64 -installed = graphene-1.10.8-2-x86_64 -installed = graphite-1:1.3.14-6-x86_64 -installed = grep-3.12-2-x86_64 -installed = grim-1.5.0-2-x86_64 -installed = groff-1.24.1-1-x86_64 -installed = gsettings-desktop-schemas-50.0-1-any -installed = gsettings-system-schemas-50.0-1-any -installed = gsm-1.0.24-1-x86_64 -installed = gsound-1.0.3-4-x86_64 -installed = gspell-1.14.3-1-x86_64 -installed = gssdp-1.6.4-1-x86_64 -installed = gst-plugins-bad-libs-1.28.2-1-x86_64 -installed = gst-plugins-base-1.28.2-1-x86_64 -installed = gst-plugins-base-libs-1.28.2-1-x86_64 -installed = gst-plugins-good-1.28.2-1-x86_64 -installed = gstreamer-1.28.2-1-x86_64 -installed = gtest-1.17.0-2-x86_64 -installed = gtk-update-icon-cache-1:4.22.2-1-x86_64 -installed = gtk-vnc-1.5.0-1-x86_64 -installed = gtk3-1:3.24.52-1-x86_64 -installed = gtk4-1:4.22.2-1-x86_64 -installed = gtkmm-4.0-4.22.0-1-x86_64 -installed = gtksourceview4-4.8.4-2-x86_64 -installed = gtksourceview5-5.20.0-1-x86_64 -installed = guestfs-tools-1.54.0-1-x86_64 -installed = gufw-26.04-2-any -installed = guile-3.0.11-1-x86_64 -installed = gupnp-1:1.6.9-1-x86_64 -installed = gupnp-dlna-0.12.0-4-x86_64 -installed = gupnp-igd-1.6.0-2-x86_64 -installed = gvfs-1.60.0-2-x86_64 -installed = gvfs-mtp-1.60.0-2-x86_64 -installed = gvfs-smb-1.60.0-2-x86_64 -installed = gweather-locations-2026.2-1-x86_64 -installed = gzip-1.14-2-x86_64 -installed = harfbuzz-14.1.0-1-x86_64 -installed = harfbuzz-icu-14.1.0-1-x86_64 -installed = hicolor-icon-theme-0.18-1-any -installed = hidapi-0.15.0-1-x86_64 -installed = highway-1.3.0-2-x86_64 -installed = hivex-1.3.24-7-x86_64 -installed = hunspell-1.7.2-3-x86_64 -installed = hwdata-0.406-1-any -installed = hyphen-2.8.8-6-x86_64 -installed = iana-etc-20260409-1-any -installed = ibus-1.5.33-3-x86_64 -installed = icu-78.3-1-x86_64 -installed = iio-sensor-proxy-3.9-1-x86_64 -installed = imlib2-1.12.6-1-x86_64 -installed = iniparser-4.2.6-2-x86_64 -installed = iproute2-6.19.0-2-x86_64 -installed = iptables-1:1.8.13-1-x86_64 -installed = iputils-20250605-1-x86_64 -installed = iso-codes-4.20.1-1-any -installed = iw-6.17-1-x86_64 -installed = iwd-3.12-1-x86_64 -installed = jack2-1.9.22-2-x86_64 -installed = jansson-2.15.0-1-x86_64 -installed = jbigkit-2.1-8-x86_64 -installed = jfsutils-1.1.15-9-x86_64 -installed = js140-140.9.1-1-x86_64 -installed = json-c-0.18-2-x86_64 -installed = json-glib-1.10.8-1-x86_64 -installed = jsoncpp-1.9.6-3-x86_64 -installed = kbd-2.9.0-1-x86_64 -installed = kcoreaddons-6.25.0-1-x86_64 -installed = keyutils-1.6.3-3-x86_64 -installed = ki18n-6.25.0-1-x86_64 -installed = kmod-34.2-1-x86_64 -installed = kpmcore-25.12.3-1-x86_64 -installed = krb5-1.21.3-2-x86_64 -installed = kwidgetsaddons-6.25.0-1-x86_64 -installed = l-smash-2.14.5-4-x86_64 -installed = lact-0.8.4-2-x86_64 -installed = lame-3.101.r6531-1-x86_64 -installed = lapack-3.12.1-2-x86_64 -installed = lcms2-2.18-1-x86_64 -installed = ldb-2:4.24.0-1-x86_64 -installed = leancrypto-1.7.2-1-x86_64 -installed = lib32-alsa-lib-1.2.15.3-1-x86_64 -installed = lib32-alsa-plugins-1.2.12-1-x86_64 -installed = lib32-brotli-1.1.0-1-x86_64 -installed = lib32-bzip2-1.0.8-4-x86_64 -installed = lib32-curl-8.19.0-1-x86_64 -installed = lib32-dbus-1.16.2-1-x86_64 -installed = lib32-e2fsprogs-1.47.4-1-x86_64 -installed = lib32-expat-2.7.5-1-x86_64 -installed = lib32-fontconfig-2:2.17.1-1-x86_64 -installed = lib32-freetype2-2.14.3-1-x86_64 -installed = lib32-gamemode-1.8.2-1-x86_64 -installed = lib32-gcc-libs-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = lib32-glew-2.3.0-2-x86_64 -installed = lib32-glib2-2.88.0-1-x86_64 -installed = lib32-glibc-2.43+r5+g856c426a7534-1-x86_64 -installed = lib32-glu-9.0.3-2-x86_64 -installed = lib32-gmp-6.3.0-2-x86_64 -installed = lib32-gnutls-3.8.12-1-x86_64 -installed = lib32-icu-78.3-1-x86_64 -installed = lib32-json-c-0.18-2-x86_64 -installed = lib32-keyutils-1.6.3-2-x86_64 -installed = lib32-krb5-1.21.3-1-x86_64 -installed = lib32-libdisplay-info-0.3.0-1-x86_64 -installed = lib32-libdrm-2.4.131-1-x86_64 -installed = lib32-libelf-0.194-1-x86_64 -installed = lib32-libffi-3.5.2-1-x86_64 -installed = lib32-libgcrypt-1.12.1-1-x86_64 -installed = lib32-libglvnd-1.7.0-1-x86_64 -installed = lib32-libgpg-error-1.59-1-x86_64 -installed = lib32-libice-1.1.1-2-x86_64 -installed = lib32-libidn2-2.3.8-1-x86_64 -installed = lib32-libldap-2.6.13-1-x86_64 -installed = lib32-libnghttp2-1.68.1-1-x86_64 -installed = lib32-libnghttp3-1.15.0-1-x86_64 -installed = lib32-libngtcp2-1.22.0-1-x86_64 -installed = lib32-libnm-1.56.0-1-x86_64 -installed = lib32-libpciaccess-0.19-1-x86_64 -installed = lib32-libpipewire-1:1.6.3-1-x86_64 -installed = lib32-libpng-1.6.57-1-x86_64 -installed = lib32-libpsl-0.21.5-1-x86_64 -installed = lib32-libsm-1.2.6-1-x86_64 -installed = lib32-libssh2-1.11.1-1-x86_64 -installed = lib32-libtasn1-4.21.0-1-x86_64 -installed = lib32-libunistring-1.3-1-x86_64 -installed = lib32-libva-2.22.0-1-x86_64 -installed = lib32-libx11-1.8.13-1-x86_64 -installed = lib32-libxau-1.0.12-1-x86_64 -installed = lib32-libxcb-1.17.0-1-x86_64 -installed = lib32-libxcrypt-4.5.2-1-x86_64 -installed = lib32-libxcrypt-compat-4.5.2-1-x86_64 -installed = lib32-libxdmcp-1.1.5-1-x86_64 -installed = lib32-libxext-1.3.7-1-x86_64 -installed = lib32-libxfixes-6.0.1-2-x86_64 -installed = lib32-libxi-1.8.2-1-x86_64 -installed = lib32-libxinerama-1.1.6-1-x86_64 -installed = lib32-libxkbcommon-1.13.1-1-x86_64 -installed = lib32-libxml2-2.15.2-1-x86_64 -installed = lib32-libxmu-1.3.1-1-x86_64 -installed = lib32-libxshmfence-1.3.3-1-x86_64 -installed = lib32-libxss-1.2.4-2-x86_64 -installed = lib32-libxt-1.3.1-1-x86_64 -installed = lib32-libxxf86vm-1.1.5-2-x86_64 -installed = lib32-llvm-libs-1:22.1.3-1-x86_64 -installed = lib32-lm_sensors-1:3.6.2-2-x86_64 -installed = lib32-mangohud-0.8.2-1-x86_64 -installed = lib32-mesa-1:26.0.4-1-x86_64 -installed = lib32-ncurses-6.6-2-x86_64 -installed = lib32-nettle-3.10.2-1-x86_64 -installed = lib32-nspr-4.38.2-1-x86_64 -installed = lib32-nss-3.122-1-x86_64 -installed = lib32-openssl-1:3.6.2-1-x86_64 -installed = lib32-p11-kit-0.26.2-1-x86_64 -installed = lib32-pcre2-10.47-1-x86_64 -installed = lib32-pipewire-1:1.6.3-1-x86_64 -installed = lib32-spirv-tools-1:1.4.341.0-1-x86_64 -installed = lib32-sqlite-3.53.0-2-x86_64 -installed = lib32-systemd-260.1-1-x86_64 -installed = lib32-util-linux-2.42-1-x86_64 -installed = lib32-vulkan-icd-loader-1.4.341.0-1-x86_64 -installed = lib32-vulkan-mesa-implicit-layers-1:26.0.4-1-x86_64 -installed = lib32-vulkan-radeon-1:26.0.4-1-x86_64 -installed = lib32-wayland-1.24.0-1-x86_64 -installed = lib32-xcb-util-keysyms-0.4.1-2-x86_64 -installed = lib32-xz-5.8.3-1-x86_64 -installed = lib32-zlib-1.3.2-1-x86_64 -installed = lib32-zstd-1.5.7-2-x86_64 -installed = libadwaita-1:1.9.0-1-x86_64 -installed = libaemu-0.1.2-5-x86_64 -installed = libaio-0.3.113-3-x86_64 -installed = libarchive-3.8.6-1-x86_64 -installed = libasan-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libass-0.17.4-2-x86_64 -installed = libassuan-3.0.0-1-x86_64 -installed = libasyncns-1:0.8+r3+g68cd5af-3-x86_64 -installed = libatasmart-0.19-8-x86_64 -installed = libatomic-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libavc1394-0.5.4-7-x86_64 -installed = libavif-1.4.1-1-x86_64 -installed = libb2-0.98.1-3-x86_64 -installed = libblockdev-3.4.0-3-x86_64 -installed = libblockdev-crypto-3.4.0-3-x86_64 -installed = libblockdev-fs-3.4.0-3-x86_64 -installed = libblockdev-loop-3.4.0-3-x86_64 -installed = libblockdev-mdraid-3.4.0-3-x86_64 -installed = libblockdev-nvme-3.4.0-3-x86_64 -installed = libblockdev-part-3.4.0-3-x86_64 -installed = libblockdev-smart-3.4.0-3-x86_64 -installed = libblockdev-swap-3.4.0-3-x86_64 -installed = libbluray-1.4.1-1-x86_64 -installed = libbpf-1.6.2-1-x86_64 -installed = libbs2b-3.1.0-10-x86_64 -installed = libbsd-0.12.2-2-x86_64 -installed = libburn-1.5.8-1-x86_64 -installed = libbytesize-2.12-3-x86_64 -installed = libcaca-0.99.beta20-7-x86_64 -installed = libcacard-2.8.1-1-x86_64 -installed = libcanberra-1:0.30+r2+gc0620e4-6-x86_64 -installed = libcap-2.78-1-x86_64 -installed = libcap-ng-0.9.3-1-x86_64 -installed = libcbor-0.14.0-1-x86_64 -installed = libcdio-2.3.0-1-x86_64 -installed = libcdio-paranoia-10.2+2.0.2-2-x86_64 -installed = libcloudproviders-0.4.0-1-x86_64 -installed = libcolord-1.4.8-1-x86_64 -installed = libconfig-1.8.2-2-x86_64 -installed = libcue-2.3.0-2-x86_64 -installed = libcups-2:2.4.16-2-x86_64 -installed = libdaemon-0.14-6-x86_64 -installed = libdatachannel-0.24.2-1-x86_64 -installed = libdatrie-0.2.14-1-x86_64 -installed = libdbusmenu-glib-18.10.20180917-1-x86_64 -installed = libdbusmenu-gtk3-18.10.20180917-1-x86_64 -installed = libdecor-0.2.5-1-x86_64 -installed = libdeflate-1.25-1-x86_64 -installed = libdisplay-info-0.3.0-1-x86_64 -installed = libdovi-3.3.2-1-x86_64 -installed = libdrm-2.4.131-1-x86_64 -installed = libdv-1.0.0-12-x86_64 -installed = libdvdnav-7.0.0-1-x86_64 -installed = libdvdread-7.0.1-1-x86_64 -installed = libebur128-1.2.6-2-x86_64 -installed = libedit-20251016_3.1-1-x86_64 -installed = libei-1.5.0-1-x86_64 -installed = libelf-0.194-2-x86_64 -installed = libepoxy-1.5.10-3-x86_64 -installed = libevdev-1.13.6-1-x86_64 -installed = libevent-2.1.12-5-x86_64 -installed = libewf-20140816-1-x86_64 -installed = libexif-0.6.25-1-x86_64 -installed = libfdk-aac-2.0.3-2-x86_64 -installed = libffi-3.5.2-1-x86_64 -installed = libfontenc-1.1.9-1-x86_64 -installed = libfreeaptx-0.2.2-1-x86_64 -installed = libfyaml-0.9.6-2-x86_64 -installed = libgcc-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libgcrypt-1.12.1-1-x86_64 -installed = libgdm-50.0-2-x86_64 -installed = libgedit-amtk-5.10.0-1-x86_64 -installed = libgedit-gfls-1:0.4.1-1-x86_64 -installed = libgedit-gtksourceview-299.7.0-1-x86_64 -installed = libgedit-tepl-6.14.0-2-x86_64 -installed = libgee-0.20.8-1-x86_64 -installed = libgexiv2-0.14.6-2-x86_64 -installed = libgfortran-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libgirepository-1.86.0-2-x86_64 -installed = libglvnd-1.7.0-3-x86_64 -installed = libgoa-3.58.1-1-x86_64 -installed = libgomp-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libgovirt-2:0.3.11-1-x86_64 -installed = libgpg-error-1.59-1-x86_64 -installed = libgsf-1.14.56-1-x86_64 -installed = libgtop-2.41.3-2-x86_64 -installed = libgudev-238-3-x86_64 -installed = libguestfs-1.56.2-5-x86_64 -installed = libgusb-0.4.9-2-x86_64 -installed = libgweather-4-4.6.0-1-x86_64 -installed = libgxps-0.3.2-5-x86_64 -installed = libhandy-1.8.3-2-x86_64 -installed = libibus-1.5.33-3-x86_64 -installed = libical-3.0.20-3-x86_64 -installed = libice-1.1.2-1-x86_64 -installed = libidn2-2.3.8-1-x86_64 -installed = libiec61883-1.2.0-9-x86_64 -installed = libimagequant-4.4.1-1-x86_64 -installed = libimobiledevice-1.4.0-2-x86_64 -installed = libimobiledevice-glue-1.3.2-1-x86_64 -installed = libinih-62-2-x86_64 -installed = libinput-1.31.1-1-x86_64 -installed = libiptcdata-1.0.5-5-x86_64 -installed = libiscsi-1.20.3-1-x86_64 -installed = libisl-0.27-1-x86_64 -installed = libisoburn-1.5.8-1-x86_64 -installed = libisofs-1.5.8.1-1-x86_64 -installed = libjpeg-turbo-3.1.4.1-1-x86_64 -installed = libjuice-1.7.0-1-x86_64 -installed = libjxl-0.11.2-2-x86_64 -installed = libksba-1.6.8-1-x86_64 -installed = liblc3-1.1.3-2-x86_64 -installed = libldac-2.0.2.3-3-x86_64 -installed = libldap-2.6.13-1-x86_64 -installed = libldm-0.2.5-3-x86_64 -installed = liblouis-3.37.0-1-x86_64 -installed = liblsan-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libmakepkg-dropins-20-1-any -installed = libmalcontent-0.14.0-4-x86_64 -installed = libmanette-0.2.13-2-x86_64 -installed = libmbim-1.34.0-1-x86_64 -installed = libmd-1.1.0-2-x86_64 -installed = libmicrodns-0.2.0-2-x86_64 -installed = libmm-glib-1.24.2-1-x86_64 -installed = libmnl-1.0.5-2-x86_64 -installed = libmodplug-0.8.9.0-7-x86_64 -installed = libmpc-1.4.0-1-x86_64 -installed = libmtp-1.1.23-1-x86_64 -installed = libmysofa-1.3.3-1-x86_64 -installed = libnautilus-extension-50.1-1-x86_64 -installed = libnbd-1.24.2-2-x86_64 -installed = libndp-1.9-1-x86_64 -installed = libnetfilter_conntrack-1.0.9-2-x86_64 -installed = libnewt-0.52.25-2-x86_64 -installed = libnfnetlink-1.0.2-2-x86_64 -installed = libnfs-6.0.2-5-x86_64 -installed = libnftnl-1.3.1-1-x86_64 -installed = libnghttp2-1.68.1-1-x86_64 -installed = libnghttp3-1.15.0-1-x86_64 -installed = libngtcp2-1.22.0-1-x86_64 -installed = libnice-0.1.23-1-x86_64 -installed = libnl-3.12.0-1-x86_64 -installed = libnm-1.56.0-1-x86_64 -installed = libnma-common-1.10.6-3-x86_64 -installed = libnma-gtk4-1.10.6-3-x86_64 -installed = libnotify-0.8.8-1-x86_64 -installed = libnsl-2.0.1-1-x86_64 -installed = libnvme-1.16.1-3-x86_64 -installed = libobjc-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libogg-1.3.6-1-x86_64 -installed = libopenmpt-0.8.6-1-x86_64 -installed = libosinfo-1.12.0-3-x86_64 -installed = libp11-kit-0.26.2-1-x86_64 -installed = libpcap-1.10.6-1-x86_64 -installed = libpciaccess-0.19-1-x86_64 -installed = libpeas-1.38.1-1-x86_64 -installed = libpgm-5.3.128-4-x86_64 -installed = libpipewire-1:1.6.3-1-x86_64 -installed = libplacebo-7.360.1-1-x86_64 -installed = libplist-2.7.0-3-x86_64 -installed = libpng-1.6.57-1-x86_64 -installed = libportal-0.9.1-3-x86_64 -installed = libportal-gtk4-0.9.1-3-x86_64 -installed = libproxy-0.5.12-1-x86_64 -installed = libpsl-0.21.5-2-x86_64 -installed = libpulse-17.0+r98+gb096704c0-1-x86_64 -installed = libpwquality-1.4.5-7-x86_64 -installed = libqmi-1.38.0-1-x86_64 -installed = libqrtr-glib-1.4.0-1-x86_64 -installed = libquadmath-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libraqm-0.10.5-1-x86_64 -installed = libraw1394-2.1.2-4-x86_64 -installed = librest-0.10.2-1-x86_64 -installed = librsvg-2:2.62.1-1-x86_64 -installed = libsamplerate-0.2.2-3-x86_64 -installed = libsasl-2.1.28-5-x86_64 -installed = libseccomp-2.6.0-1-x86_64 -installed = libsecret-0.21.7-1-x86_64 -installed = libshout-1:2.4.6-5-x86_64 -installed = libsigc++-3.0-3.8.0-1-x86_64 -installed = libslirp-4.9.1-1-x86_64 -installed = libsm-1.2.6-1-x86_64 -installed = libsndfile-1.2.2-4-x86_64 -installed = libsodium-1.0.22-1-x86_64 -installed = libsonic-0.2.0-2-x86_64 -installed = libsoup3-3.6.6-2-x86_64 -installed = libsoxr-0.1.3-4-x86_64 -installed = libspeechd-0.12.1-3-x86_64 -installed = libsrtp-1:2.8.0-1-x86_64 -installed = libssc-0.4.2-1-x86_64 -installed = libssh-0.12.0-1-x86_64 -installed = libssh2-1.11.1-1-x86_64 -installed = libstdc++-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libstemmer-3.0.1-1-x86_64 -installed = libsysprof-capture-50.0-1-x86_64 -installed = libtasn1-4.21.0-1-x86_64 -installed = libtatsu-1.0.5-1-x86_64 -installed = libteam-1.32-3-x86_64 -installed = libthai-0.1.30-1-x86_64 -installed = libtheora-1.2.0-1-x86_64 -installed = libtiff-4.7.1-2-x86_64 -installed = libtirpc-1.3.7-1-x86_64 -installed = libtool-2.6.0-4-x86_64 -installed = libtpms-0.10.2-1-x86_64 -installed = libtraceevent-1:1.9.0-1-x86_64 -installed = libtracefs-1.8.3-1-x86_64 -installed = libtsan-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libubsan-15.2.1+r604+g0b99615a8aef-1-x86_64 -installed = libunibreak-7.0-1-x86_64 -installed = libunistring-1.4.1-1-x86_64 -installed = libunwind-1.8.2-1-x86_64 -installed = liburcu-0.15.6-1-x86_64 -installed = liburing-2.14-1-x86_64 -installed = libusb-1.0.29-1-x86_64 -installed = libusbmuxd-2.1.1-2-x86_64 -installed = libuv-1.52.1-1-x86_64 -installed = libva-2.23.0-1-x86_64 -installed = libvdpau-1.5-4-x86_64 -installed = libverto-0.3.2-6-x86_64 -installed = libvirt-1:12.2.0-1-x86_64 -installed = libvirt-glib-5.0.0-3-x86_64 -installed = libvirt-python-1:12.2.0-1-x86_64 -installed = libvorbis-1.3.7-4-x86_64 -installed = libvpl-2.16.0-2-x86_64 -installed = libvpx-1.16.0-3-x86_64 -installed = libwacom-2.18.0-2-x86_64 -installed = libwbclient-2:4.24.0-1-x86_64 -installed = libwebp-1.6.0-2-x86_64 -installed = libwireplumber-0.5.14-1-x86_64 -installed = libx11-1.8.13-1-x86_64 -installed = libxau-1.0.12-1-x86_64 -installed = libxaw-1.0.16-2-x86_64 -installed = libxcb-1.17.0-1-x86_64 -installed = libxcomposite-0.4.7-1-x86_64 -installed = libxcrypt-4.5.2-1-x86_64 -installed = libxcrypt-compat-4.5.2-1-x86_64 -installed = libxcursor-1.2.3-1-x86_64 -installed = libxcvt-0.1.3-1-x86_64 -installed = libxdamage-1.1.7-1-x86_64 -installed = libxdmcp-1.1.5-2-x86_64 -installed = libxdp-1.6.3-1-x86_64 -installed = libxext-1.3.7-1-x86_64 -installed = libxfixes-6.0.2-1-x86_64 -installed = libxfont2-2.0.7-1-x86_64 -installed = libxft-2.3.9-1-x86_64 -installed = libxi-1.8.2-1-x86_64 -installed = libxinerama-1.1.6-1-x86_64 -installed = libxkbcommon-1.13.1-1-x86_64 -installed = libxkbcommon-x11-1.13.1-1-x86_64 -installed = libxkbfile-1.2.0-1-x86_64 -installed = libxml2-2.15.2-1-x86_64 -installed = libxmlb-0.3.25-1-x86_64 -installed = libxmu-1.3.1-1-x86_64 -installed = libxpm-3.5.18-1-x86_64 -installed = libxrandr-1.5.5-1-x86_64 -installed = libxrender-0.9.12-1-x86_64 -installed = libxres-1.2.3-1-x86_64 -installed = libxshmfence-1.3.3-1-x86_64 -installed = libxslt-1.1.45-2-x86_64 -installed = libxss-1.2.5-1-x86_64 -installed = libxt-1.3.1-1-x86_64 -installed = libxtst-1.2.5-1-x86_64 -installed = libxv-1.0.13-1-x86_64 -installed = libxxf86vm-1.1.7-1-x86_64 -installed = libyaml-0.2.5-3-x86_64 -installed = libyuv-r2426+464c51a03-1-x86_64 -installed = libzip-1.11.4-1-x86_64 -installed = licenses-20240728-1-any -installed = lilv-0.26.4-1-x86_64 -installed = linux-api-headers-6.19-1-x86_64 -installed = linux-cachyos-6.18.9-1-x86_64 -installed = linux-cachyos-headers-6.18.9-1-x86_64 -installed = linux-firmware-20260309-1-any -installed = linux-firmware-amdgpu-20260309-1-any -installed = linux-firmware-atheros-20260309-1-any -installed = linux-firmware-broadcom-20260309-1-any -installed = linux-firmware-cirrus-20260309-1-any -installed = linux-firmware-intel-20260309-1-any -installed = linux-firmware-mediatek-20260309-1-any -installed = linux-firmware-nvidia-20260309-1-any -installed = linux-firmware-other-20260309-1-any -installed = linux-firmware-radeon-20260309-1-any -installed = linux-firmware-realtek-20260309-1-any -installed = linux-firmware-whence-20260309-1-any -installed = lld-22.1.3-1-x86_64 -installed = llvm-22.1.3-1-x86_64 -installed = llvm-libs-22.1.3-1-x86_64 -installed = lm_sensors-1:3.6.2-1-x86_64 -installed = lmdb-0.9.35-1-x86_64 -installed = localsearch-3.11.0-1-x86_64 -installed = lrzip-0.660-1-x86_64 -installed = lsb-release-2.0.r55.a25a4fc-1-any -installed = lsof-4.99.6-1-x86_64 -installed = lsscsi-0.32-2-x86_64 -installed = lua-5.5.0-2-x86_64 -installed = lua54-5.4.8-6-x86_64 -installed = luajit-2.1.1774896198+18b087c-1-x86_64 -installed = lutris-0.5.22-1-any -installed = lv2-1.18.10-2-x86_64 -installed = lvm2-2.03.39-1-x86_64 -installed = lz4-1:1.10.0-2-x86_64 -installed = lzo-2.10-5-x86_64 -installed = lzop-1.04-4-x86_64 -installed = m4-1.4.21-2-x86_64 -installed = mailcap-2.1.54-2-any -installed = make-4.4.1-3-x86_64 -installed = mangohud-0.8.2-3-x86_64 -installed = mbedtls-3.6.5-1-x86_64 -installed = md4c-0.5.2-2-x86_64 -installed = mdadm-4.6-1-x86_64 -installed = mesa-1:26.0.4-1-x86_64 -installed = mesa-utils-9.0.0-7-x86_64 -installed = meson-1.10.2-1-any -installed = mkinitcpio-40-4-any -installed = mkinitcpio-busybox-1.36.1-1-x86_64 -installed = mkinitcpio-openswap-0.1.1-1-any -installed = mobile-broadband-provider-info-20251101-1-any -installed = mpdecimal-4.0.1-3-x86_64 -installed = mpfr-4.2.2-1-x86_64 -installed = mpg123-1.33.4-1-x86_64 -installed = mtdev-1.1.7-1-x86_64 -installed = mtools-1:4.0.49-1-x86_64 -installed = multipath-tools-0.14.3-1-x86_64 -installed = mutter-49.5-1-x86_64 -installed = nano-9.0-1-x86_64 -installed = nautilus-49.5-1-x86_64 -installed = ncurses-6.6-2-x86_64 -installed = ndctl-84-1-x86_64 -installed = ndi-sdk-6.3.1.0.20260217.gf5b826c4e-1-x86_64 -installed = nettle-3.10.2-1-x86_64 -installed = networkmanager-1.56.0-1-x86_64 -installed = nftables-1:1.1.6-3-x86_64 -installed = nilfs-utils-2.3.0-1-x86_64 -installed = ninja-1.13.2-3-x86_64 -installed = node-gyp-12.2.0-1-any -installed = nodejs-25.9.0-1-x86_64 -installed = nodejs-nopt-9.0.0-1-any -installed = noto-fonts-1:2026.04.01-1-any -installed = noto-fonts-cjk-20240730-1-any -installed = noto-fonts-emoji-1:2.051-1-any -installed = noto-fonts-extra-1:2026.04.01-1-any -installed = npm-11.12.1-1-any -installed = npth-1.8-1-x86_64 -installed = nspr-4.38.2-1-x86_64 -installed = nss-3.122-1-x86_64 -installed = ntfs-3g-2022.10.3-2-x86_64 -installed = numactl-2.0.19-1-x86_64 -installed = obs-studio-32.1.1-2-x86_64 -installed = ocl-icd-2.3.4-1-x86_64 -installed = opencore-amr-0.1.6-2-x86_64 -installed = openjpeg2-2.5.4-1-x86_64 -installed = openssh-10.3p1-1-x86_64 -installed = openssl-3.6.2-1-x86_64 -installed = opus-1.6.1-1-x86_64 -installed = orc-0.4.42-1-x86_64 -installed = osinfo-db-20251212-1-any -installed = ostree-2025.7-3-x86_64 -installed = p11-kit-0.26.2-1-x86_64 -installed = pacman-7.1.0.r9.g54d9411-1-x86_64 -installed = pacman-contrib-1.13.1-1-x86_64 -installed = pacman-mirrorlist-20260406-1-any -installed = pahole-1:1.31-2-x86_64 -installed = pam-1.7.2-2-x86_64 -installed = pambase-20250719-1-any -installed = pango-1:1.57.1-1-x86_64 -installed = pangomm-2.48-2.56.1-1-x86_64 -installed = parted-3.7-1-x86_64 -installed = patch-2.8-1-x86_64 -installed = pavucontrol-1:6.2-1-x86_64 -installed = pcaudiolib-1.3-1-x86_64 -installed = pciutils-3.15.0-1-x86_64 -installed = pcre-8.45-4-x86_64 -installed = pcre2-10.47-1-x86_64 -installed = pcsclite-2.4.1-1-x86_64 -installed = perl-5.42.2-1-x86_64 -installed = perl-error-0.17030-3-any -installed = perl-libintl-perl-1.37-1-x86_64 -installed = perl-mailtools-2.22-3-any -installed = perl-timedate-2.35-1-any -installed = phodav-3.0-4-x86_64 -installed = pinentry-1.3.2-2-x86_64 -installed = pipewire-1:1.6.3-1-x86_64 -installed = pipewire-audio-1:1.6.3-1-x86_64 -installed = pipewire-pulse-1:1.6.3-1-x86_64 -installed = pipewire-session-manager-1:1.6.3-1-x86_64 -installed = pixman-0.46.4-1-x86_64 -installed = pkgconf-2.5.1-1-x86_64 -installed = polkit-127-3-x86_64 -installed = polkit-qt6-0.201.1-1-x86_64 -installed = poppler-26.04.0-1-x86_64 -installed = poppler-glib-26.04.0-1-x86_64 -installed = popt-1.19-2-x86_64 -installed = portaudio-1:19.7.0-4-x86_64 -installed = procps-ng-4.0.6-1-x86_64 -installed = protobuf-34.1-1-x86_64 -installed = protobuf-c-1.5.2-9-x86_64 -installed = psmisc-23.7-1-x86_64 -installed = pulse-native-provider-1:1.6.3-1-x86_64 -installed = python-3.14.4-1-x86_64 -installed = python-argcomplete-3.6.3-1-any -installed = python-attrs-26.1.0-1-any -installed = python-autocommand-2.2.2-9-any -installed = python-beautifulsoup4-4.14.3-2-any -installed = python-cairo-1.29.0-2-x86_64 -installed = python-certifi-2026.02.25-1-any -installed = python-cffi-2.0.0-2-x86_64 -installed = python-charset-normalizer-3.4.7-1-x86_64 -installed = python-click-8.3.2-1-any -installed = python-contourpy-1.3.3-3-x86_64 -installed = python-cryptography-46.0.7-1-x86_64 -installed = python-cycler-0.12.1-4-any -installed = python-dateutil-2.9.0-8-any -installed = python-dbus-1.4.0-2-x86_64 -installed = python-distro-1.9.0-4-any -installed = python-evdev-1.9.3-1-x86_64 -installed = python-filelock-3.26.0-1-any -installed = python-fonttools-4.62.1-1-x86_64 -installed = python-gobject-3.56.2-1-x86_64 -installed = python-idna-3.11-2-any -installed = python-jaraco.collections-5.1.0-3-any -installed = python-jaraco.context-6.1.2-1-any -installed = python-jaraco.functools-4.1.0-3-any -installed = python-jaraco.text-4.0.0-4-any -installed = python-kiwisolver-1.5.0-1-x86_64 -installed = python-lxml-6.0.4-1-x86_64 -installed = python-matplotlib-3.10.8-5-x86_64 -installed = python-moddb-0.14.0-2-any -installed = python-more-itertools-11.0.2-1-any -installed = python-numpy-2.4.4-1-x86_64 -installed = python-packaging-26.0-1-any -installed = python-pillow-12.2.0-1-x86_64 -installed = python-pip-26.0.1-1-any -installed = python-pipx-1.11.1-1-any -installed = python-pkg_resources-81.0.0-1-any -installed = python-platformdirs-4.9.6-1-any -installed = python-pycparser-3.00-1-any -installed = python-pyparsing-3.3.2-1-any -installed = python-pyqt6-6.11.0-1-x86_64 -installed = python-pyqt6-sip-13.11.1-1-x86_64 -installed = python-requests-2.33.1-1-any -installed = python-setuptools-1:82.0.1-1-any -installed = python-six-1.17.0-3-any -installed = python-soupsieve-2.8.3-1-any -installed = python-tqdm-4.67.3-1-any -installed = python-typing_extensions-4.15.0-3-any -installed = python-urllib3-2.6.3-1-any -installed = python-userpath-1.9.2-4-any -installed = python-wheel-0.46.3-1-any -installed = python-yaml-6.0.3-2-x86_64 -installed = qemu-audio-alsa-10.2.2-3-x86_64 -installed = qemu-audio-dbus-10.2.2-3-x86_64 -installed = qemu-audio-jack-10.2.2-3-x86_64 -installed = qemu-audio-oss-10.2.2-3-x86_64 -installed = qemu-audio-pa-10.2.2-3-x86_64 -installed = qemu-audio-pipewire-10.2.2-3-x86_64 -installed = qemu-audio-sdl-10.2.2-3-x86_64 -installed = qemu-audio-spice-10.2.2-3-x86_64 -installed = qemu-base-10.2.2-3-x86_64 -installed = qemu-block-curl-10.2.2-3-x86_64 -installed = qemu-block-dmg-10.2.2-3-x86_64 -installed = qemu-block-gluster-10.2.2-3-x86_64 -installed = qemu-block-iscsi-10.2.2-3-x86_64 -installed = qemu-block-nfs-10.2.2-3-x86_64 -installed = qemu-block-ssh-10.2.2-3-x86_64 -installed = qemu-chardev-baum-10.2.2-3-x86_64 -installed = qemu-chardev-spice-10.2.2-3-x86_64 -installed = qemu-common-10.2.2-3-x86_64 -installed = qemu-desktop-10.2.2-3-x86_64 -installed = qemu-docs-10.2.2-3-x86_64 -installed = qemu-emulators-full-10.2.2-3-x86_64 -installed = qemu-full-10.2.2-3-x86_64 -installed = qemu-hw-display-qxl-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-gl-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-pci-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-pci-gl-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-pci-rutabaga-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-gpu-rutabaga-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-vga-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-vga-gl-10.2.2-3-x86_64 -installed = qemu-hw-display-virtio-vga-rutabaga-10.2.2-3-x86_64 -installed = qemu-hw-s390x-virtio-gpu-ccw-10.2.2-3-x86_64 -installed = qemu-hw-uefi-vars-10.2.2-3-x86_64 -installed = qemu-hw-usb-host-10.2.2-3-x86_64 -installed = qemu-hw-usb-redirect-10.2.2-3-x86_64 -installed = qemu-hw-usb-smartcard-10.2.2-3-x86_64 -installed = qemu-img-10.2.2-3-x86_64 -installed = qemu-pr-helper-10.2.2-3-x86_64 -installed = qemu-system-aarch64-10.2.2-3-x86_64 -installed = qemu-system-alpha-10.2.2-3-x86_64 -installed = qemu-system-alpha-firmware-10.2.2-3-x86_64 -installed = qemu-system-arm-10.2.2-3-x86_64 -installed = qemu-system-arm-firmware-10.2.2-3-x86_64 -installed = qemu-system-avr-10.2.2-3-x86_64 -installed = qemu-system-hppa-10.2.2-3-x86_64 -installed = qemu-system-hppa-firmware-10.2.2-3-x86_64 -installed = qemu-system-loongarch64-10.2.2-3-x86_64 -installed = qemu-system-m68k-10.2.2-3-x86_64 -installed = qemu-system-microblaze-10.2.2-3-x86_64 -installed = qemu-system-microblaze-firmware-10.2.2-3-x86_64 -installed = qemu-system-mips-10.2.2-3-x86_64 -installed = qemu-system-or1k-10.2.2-3-x86_64 -installed = qemu-system-ppc-10.2.2-3-x86_64 -installed = qemu-system-ppc-firmware-10.2.2-3-x86_64 -installed = qemu-system-riscv-10.2.2-3-x86_64 -installed = qemu-system-riscv-firmware-10.2.2-3-x86_64 -installed = qemu-system-rx-10.2.2-3-x86_64 -installed = qemu-system-s390x-10.2.2-3-x86_64 -installed = qemu-system-s390x-firmware-10.2.2-3-x86_64 -installed = qemu-system-sh4-10.2.2-3-x86_64 -installed = qemu-system-sparc-10.2.2-3-x86_64 -installed = qemu-system-sparc-firmware-10.2.2-3-x86_64 -installed = qemu-system-tricore-10.2.2-3-x86_64 -installed = qemu-system-x86-10.2.2-3-x86_64 -installed = qemu-system-x86-firmware-10.2.2-3-x86_64 -installed = qemu-system-xtensa-10.2.2-3-x86_64 -installed = qemu-tests-10.2.2-3-x86_64 -installed = qemu-tools-10.2.2-3-x86_64 -installed = qemu-ui-curses-10.2.2-3-x86_64 -installed = qemu-ui-dbus-10.2.2-3-x86_64 -installed = qemu-ui-egl-headless-10.2.2-3-x86_64 -installed = qemu-ui-gtk-10.2.2-3-x86_64 -installed = qemu-ui-opengl-10.2.2-3-x86_64 -installed = qemu-ui-sdl-10.2.2-3-x86_64 -installed = qemu-ui-spice-app-10.2.2-3-x86_64 -installed = qemu-ui-spice-core-10.2.2-3-x86_64 -installed = qemu-user-10.2.2-3-x86_64 -installed = qemu-vhost-user-gpu-10.2.2-3-x86_64 -installed = qemu-vmsr-helper-10.2.2-3-x86_64 -installed = qhull-2020.2-5-x86_64 -installed = qrcodegencpp-cmake-1.8.0-4-x86_64 -installed = qt5-base-5.15.18+kde+r109-2-x86_64 -installed = qt5-declarative-5.15.18+kde+r23-1-x86_64 -installed = qt5-translations-5.15.18-1-any -installed = qt5-wayland-5.15.18+kde+r55-1-x86_64 -installed = qt6-5compat-6.11.0-1-x86_64 -installed = qt6-base-6.11.0-2-x86_64 -installed = qt6-declarative-6.11.0-1-x86_64 -installed = qt6-multimedia-6.11.0-1-x86_64 -installed = qt6-multimedia-ffmpeg-6.11.0-1-x86_64 -installed = qt6-shadertools-6.11.0-1-x86_64 -installed = qt6-svg-6.11.0-2-x86_64 -installed = qt6-tools-6.11.0-3-x86_64 -installed = qt6-translations-6.11.0-1-any -installed = qt6-virtualkeyboard-6.11.0-1-x86_64 -installed = qt6-wayland-6.11.0-1-x86_64 -installed = qt6pas-6.2.10-3-x86_64 -installed = rav1e-0.8.1-2-x86_64 -installed = raveos-app-installer-2.0.0-12-any -installed = rdma-core-62.0-1-x86_64 -installed = readline-8.3.003-1-x86_64 -installed = rhash-1.4.6-1-x86_64 -installed = rnnoise-1:0.2-1-x86_64 -installed = rpcbind-1.2.8-1-x86_64 -installed = rsync-3.4.1-2-x86_64 -installed = rtkit-0.14-1-x86_64 -installed = rubberband-4.0.0-2-x86_64 -installed = runc-1.4.2-1-x86_64 -installed = rutabaga-ffi-0.1.75-1-x86_64 -installed = sbc-2.2-1-x86_64 -installed = sddm-0.21.0-6-x86_64 -installed = sddm-astronaut-theme-75.c10bd95-1-any -installed = sdl2-compat-2.32.66-1-x86_64 -installed = sdl2_image-2.8.10-1-x86_64 -installed = sdl3-3.4.4-1-x86_64 -installed = sdl3_ttf-3.2.2-3-x86_64 -installed = seabios-1.17.0-2-any -installed = seatd-0.9.3-1-x86_64 -installed = sed-4.9-3-x86_64 -installed = semver-7.7.4-1-any -installed = serd-0.32.8-1-x86_64 -installed = shaderc-2026.1-2-x86_64 -installed = shadow-4.18.0-1-x86_64 -installed = shared-mime-info-2.4-3-x86_64 -installed = simde-0.8.2-1-any -installed = simdjson-1:4.6.1-1-x86_64 -installed = slang-2.3.3-4-x86_64 -installed = sleuthkit-4.14.0-2-x86_64 -installed = slurp-1.5.0-2-x86_64 -installed = smartmontools-7.5-1-x86_64 -installed = smbclient-2:4.24.0-1-x86_64 -installed = snappy-1.2.2-3-x86_64 -installed = sndio-1.10.0-1-x86_64 -installed = sord-0.16.22-1-x86_64 -installed = sound-theme-freedesktop-0.8-6-any -installed = spandsp-0.0.6-7-x86_64 -installed = speex-1.2.1-2-x86_64 -installed = speexdsp-1.2.1-2-x86_64 -installed = spice-0.16.0-2-x86_64 -installed = spice-gtk-0.42-5-x86_64 -installed = spice-protocol-0.14.5-1-any -installed = spirv-tools-1:1.4.341.0-2-x86_64 -installed = sqlite-3.53.0-2-x86_64 -installed = squashfs-tools-4.7.5-1-x86_64 -installed = sratom-0.6.22-1-x86_64 -installed = srt-1.5.4-1-x86_64 -installed = sshpass-1.10-2-x86_64 -installed = startup-notification-0.12-9-x86_64 -installed = steam-1.0.0.85-6-x86_64 -installed = steam-devices-1.0.0.85-6-x86_64 -installed = strace-6.19-1-x86_64 -installed = sudo-1.9.17.p2-2-x86_64 -installed = supermin-5.3.5-2-x86_64 -installed = svt-av1-4.1.0-1-x86_64 -installed = swtpm-0.10.1-2-x86_64 -installed = sysfsutils-2.1.1-2-x86_64 -installed = syslinux-6.04.pre3.r3.g05ac953c-4-x86_64 -installed = systemd-260.1-1-x86_64 -installed = systemd-libs-260.1-1-x86_64 -installed = systemd-sysvcompat-260.1-1-x86_64 -installed = taglib-2.2.1-1-x86_64 -installed = talloc-2.4.4-1-x86_64 -installed = tar-1.35-2-x86_64 -installed = tdb-1.4.15-1-x86_64 -installed = tecla-50.0-1-x86_64 -installed = tevent-1:0.17.1-2-x86_64 -installed = texinfo-7.3-1-x86_64 -installed = thin-provisioning-tools-1.3.1-1-x86_64 -installed = tinysparql-3.11.0-1-x86_64 -installed = totem-pl-parser-3.26.7-1-x86_64 -installed = tpm2-tss-4.1.3-1-x86_64 -installed = traceroute-2.1.6-1-x86_64 -installed = tslib-1.24-1-x86_64 -installed = ttf-ubuntu-font-family-1:0.83-2-any -installed = twolame-0.4.0-4-x86_64 -installed = tzdata-2026a-1-x86_64 -installed = uchardet-0.0.8-4-x86_64 -installed = udisks2-2.11.1-2-x86_64 -installed = ufw-0.36.2-7-any -installed = unzip-6.0-23-x86_64 -installed = upower-1.91.2-1-x86_64 -installed = usbredir-0.15.0-1-x86_64 -installed = usbutils-019-1-x86_64 -installed = uthash-2.3.0-3-any -installed = util-linux-2.42-1-x86_64 -installed = util-linux-libs-2.42-1-x86_64 -installed = v4l-utils-1.32.0-2-x86_64 -installed = vapoursynth-73-2-x86_64 -installed = vde2-2.3.3-8-x86_64 -installed = vid.stab-1.1.1-2-x86_64 -installed = vim-9.2.0316-1-x86_64 -installed = vim-runtime-9.2.0316-1-x86_64 -installed = virglrenderer-1.2.0-1-x86_64 -installed = virt-install-5.1.0-3-any -installed = virt-manager-5.1.0-3-any -installed = virt-viewer-11.0-4-x86_64 -installed = virtiofsd-1.13.3-1-x86_64 -installed = vivaldi-7.9.3970.50-1-x86_64 -installed = vivaldi-ffmpeg-codecs-146.0.7680.189-1-x86_64 -installed = vmaf-3.1.0-1-x86_64 -installed = volume_key-0.3.12-12-x86_64 -installed = vscodium-1.112.01907-1-x86_64 -installed = vte-common-0.84.0-1-x86_64 -installed = vte3-0.84.0-1-x86_64 -installed = vte4-0.84.0-1-x86_64 -installed = vulkan-icd-loader-1.4.341.0-1-x86_64 -installed = vulkan-mesa-implicit-layers-1:26.0.4-1-x86_64 -installed = vulkan-radeon-1:26.0.4-1-x86_64 -installed = vulkan-tools-1.4.341.0-2-x86_64 -installed = wavpack-5.9.0-1-x86_64 -installed = wayland-1.24.0-1-x86_64 -installed = webkit2gtk-4.1-2.52.2-1-x86_64 -installed = webkitgtk-6.0-2.52.2-1-x86_64 -installed = webrtc-audio-processing-1-1.3-5-x86_64 -installed = wget-1.25.0-3-x86_64 -installed = which-2.23-1-x86_64 -installed = winboat-bin-0.9.0-1-x86_64 -installed = wine-11.6-1-x86_64 -installed = wine-gecko-2.47.4-2-x86_64 -installed = wine-mono-11.0.0-1-x86_64 -installed = winetricks-20260125-1-x86_64 -installed = wireless-regdb-2026.02.04-1-any -installed = wireplumber-0.5.14-1-x86_64 -installed = woff2-1.0.2-6-x86_64 -installed = wolfssl-5.9.1-1-x86_64 -installed = wpa_supplicant-2:2.11-5-x86_64 -installed = x264-3:0.165.r3222.b35605a-2-x86_64 -installed = x265-4.1-1-x86_64 -installed = xcb-proto-1.17.0-4-any -installed = xcb-util-0.4.1-2-x86_64 -installed = xcb-util-cursor-0.1.6-1-x86_64 -installed = xcb-util-errors-1.0.1-2-x86_64 -installed = xcb-util-image-0.4.1-3-x86_64 -installed = xcb-util-keysyms-0.4.1-5-x86_64 -installed = xcb-util-renderutil-0.3.10-2-x86_64 -installed = xcb-util-wm-0.4.2-2-x86_64 -installed = xdg-dbus-proxy-0.1.7-1-x86_64 -installed = xdg-desktop-portal-1.20.4-1-x86_64 -installed = xdg-desktop-portal-gnome-50.0-1-x86_64 -installed = xdg-desktop-portal-gtk-1.15.3-1-x86_64 -installed = xdg-desktop-portal-wlr-0.8.1-1-x86_64 -installed = xdg-user-dirs-0.20-1-x86_64 -installed = xdg-user-dirs-gtk-0.16-1-x86_64 -installed = xdg-utils-1.2.1-2-any -installed = xf86-input-libinput-1.5.0-1-x86_64 -installed = xfsprogs-6.19.0-1-x86_64 -installed = xkeyboard-config-2.47-1-any -installed = xorg-fonts-encodings-1.1.0-2-any -installed = xorg-server-21.1.21-1-x86_64 -installed = xorg-server-common-21.1.21-1-x86_64 -installed = xorg-setxkbmap-1.3.5-1-x86_64 -installed = xorg-xauth-1.1.5-1-x86_64 -installed = xorg-xkbcomp-1.5.0-1-x86_64 -installed = xorg-xprop-1.2.8-1-x86_64 -installed = xorg-xrandr-1.5.3-1-x86_64 -installed = xorg-xwayland-24.1.9-1-x86_64 -installed = xorgproto-2025.1-1-any -installed = xvidcore-1.3.7-3-x86_64 -installed = xxhash-0.8.3-1-x86_64 -installed = xz-5.8.3-1-x86_64 -installed = yaml-cpp-0.9.0-1-x86_64 -installed = yara-4.5.5-1-x86_64 -installed = yaru-gtk-theme-25.10.3-1-any -installed = yay-bin-12.5.7-1-x86_64 -installed = yyjson-0.12.0-1-x86_64 -installed = zenity-4.2.2-1-x86_64 -installed = zenpower5-dkms-git-5:0.5.0.r3.g66871d8-1-x86_64 -installed = zeromq-4.3.5-3-x86_64 -installed = zimg-3.0.6-1-x86_64 -installed = zix-0.8.0-1-x86_64 -installed = zlib-1:1.3.2-3-x86_64 -installed = zlib-ng-2.3.3-1-x86_64 -installed = zstd-1.5.7-3-x86_64 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.INSTALL b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.INSTALL deleted file mode 100644 index 876a411..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.INSTALL +++ /dev/null @@ -1,7 +0,0 @@ -post_install() { - : -} - -post_upgrade() { - : -} diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.MTREE b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.MTREE deleted file mode 100644 index c018deb..0000000 Binary files a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.MTREE and /dev/null differ diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.PKGINFO b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.PKGINFO deleted file mode 100644 index 25c148a..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/.PKGINFO +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by makepkg 7.1.0 -# using fakeroot version 1.37.2 -pkgname = raveos-hyprland-theme -pkgbase = raveos-hyprland-theme -xdata = pkgtype=pkg -pkgver = 0.0.0-6 -pkgdesc = RaveOS Hyprland theme payload and installer -url = https://raveos.local -builddate = 1776187236 -packager = Unknown Packager -size = 419101 -arch = any -license = custom -depend = fastfetch diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/raveos-hyprland-theme/auto-apply.sh b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/raveos-hyprland-theme/auto-apply.sh deleted file mode 100755 index ad329c3..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/raveos-hyprland-theme/auto-apply.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -payload_dir="/usr/share/raveos/hyprland-theme/theme-data" - -if [[ ! -d "$payload_dir" ]]; then - echo "Missing payload: $payload_dir" >&2 - exit 1 -fi - -if [[ ${EUID} -ne 0 ]]; then - echo "Run as root." >&2 - exit 1 -fi - -mkdir -p /etc/skel - -if [[ -f "${payload_dir}/kitty/kitty.conf" ]]; then - install -Dm644 "${payload_dir}/kitty/kitty.conf" /etc/skel/.config/kitty/kitty.conf -fi - -if [[ -f "${payload_dir}/fastfetch/config.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config.jsonc" /etc/skel/.config/fastfetch/config.jsonc -fi - -if [[ -f "${payload_dir}/fastfetch/config-kitty.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config-kitty.jsonc" /etc/skel/.config/fastfetch/config-kitty.jsonc -fi - -if [[ -f "${payload_dir}/fastfetch/raveos-logo.png" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.png" /etc/skel/.config/fastfetch/raveos-logo.png -fi - -if [[ -f "${payload_dir}/fastfetch/raveos-logo.txt" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.txt" /etc/skel/.config/fastfetch/raveos-logo.txt -fi - -if [[ -f "${payload_dir}/profile.d/raveos-fastfetch.sh" ]]; then - install -Dm755 "${payload_dir}/profile.d/raveos-fastfetch.sh" /etc/profile.d/raveos-fastfetch.sh -fi - -if [[ -d "${payload_dir}/skel" ]]; then - cp -r --no-preserve=ownership "${payload_dir}/skel/." /etc/skel/ -fi - -if [[ -f "${payload_dir}/background" ]]; then - install -Dm644 "${payload_dir}/background" /usr/share/backgrounds/raveos/raveos-main-bg.jpeg -fi - -if [[ -f "${payload_dir}/sddm/sddm.conf" ]]; then - install -Dm644 "${payload_dir}/sddm/sddm.conf" /etc/sddm.conf.d/raveos-theme.conf -fi - -for candidate in \ - "/usr/share/sddm/themes/sddm-astronaut-theme" \ - "/usr/share/sddm/themes/astronaut" \ - "/usr/share/sddm/themes/sddm-astronaut"; do - if [[ -d "$candidate" ]]; then - if [[ -f "${payload_dir}/sddm/new-raveos-main-bg.jpeg" ]]; then - install -Dm644 "${payload_dir}/sddm/new-raveos-main-bg.jpeg" \ - "${candidate}/Backgrounds/new-raveos-main-bg.jpeg" - fi - if [[ -f "${payload_dir}/sddm/astronaut.conf" ]]; then - install -Dm644 "${payload_dir}/sddm/astronaut.conf" \ - "${candidate}/Themes/astronaut.conf" - fi - break - fi -done - -while IFS=: read -r user _ uid gid _ home shell; do - [[ "$uid" -ge 1000 ]] || continue - [[ -d "$home" ]] || continue - [[ "$shell" != "/usr/bin/nologin" && "$shell" != "/bin/false" ]] || continue - if [[ -d "${payload_dir}/skel" ]]; then - cp -r --no-preserve=ownership "${payload_dir}/skel/." "$home/" - fi - if [[ -f "${payload_dir}/kitty/kitty.conf" ]]; then - install -Dm644 "${payload_dir}/kitty/kitty.conf" "${home}/.config/kitty/kitty.conf" - fi - if [[ -f "${payload_dir}/fastfetch/config.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config.jsonc" "${home}/.config/fastfetch/config.jsonc" - fi - if [[ -f "${payload_dir}/fastfetch/config-kitty.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config-kitty.jsonc" "${home}/.config/fastfetch/config-kitty.jsonc" - fi - if [[ -f "${payload_dir}/fastfetch/raveos-logo.png" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.png" "${home}/.config/fastfetch/raveos-logo.png" - fi - if [[ -f "${payload_dir}/fastfetch/raveos-logo.txt" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.txt" "${home}/.config/fastfetch/raveos-logo.txt" - fi - chown -R "${uid}:${gid}" "$home" -done < /etc/passwd - -echo "Automatic apply finished." diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/systemd/system/raveos-hyprland-theme-apply.service b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/systemd/system/raveos-hyprland-theme-apply.service deleted file mode 100644 index 7c630f2..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/lib/systemd/system/raveos-hyprland-theme-apply.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Apply RaveOS Hyprland theme payload -After=local-fs.target systemd-user-sessions.service -ConditionPathExists=!/var/lib/raveos-hyprland-theme/.applied - -[Service] -Type=oneshot -ExecStart=/usr/lib/raveos-hyprland-theme/auto-apply.sh -ExecStartPost=/usr/bin/install -Dm644 /dev/null /var/lib/raveos-hyprland-theme/.applied - -[Install] -WantedBy=multi-user.target diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.changelog-1.2 b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.changelog-1.2 deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.firstlaunch b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/.firstlaunch deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/settings.json b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/settings.json deleted file mode 100644 index 72a922f..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/DankMaterialShell/settings.json +++ /dev/null @@ -1,545 +0,0 @@ -{ - "currentThemeName": "green", - "currentThemeCategory": "generic", - "customThemeFile": "", - "registryThemeVariants": {}, - "matugenScheme": "scheme-tonal-spot", - "runUserMatugenTemplates": true, - "matugenTargetMonitor": "", - "popupTransparency": 1, - "dockTransparency": 0.2, - "widgetBackgroundColor": "sch", - "widgetColorMode": "default", - "controlCenterTileColorMode": "primary", - "buttonColorMode": "primary", - "cornerRadius": 12, - "niriLayoutGapsOverride": -1, - "niriLayoutRadiusOverride": -1, - "niriLayoutBorderSize": -1, - "hyprlandLayoutGapsOverride": -1, - "hyprlandLayoutRadiusOverride": -1, - "hyprlandLayoutBorderSize": -1, - "mangoLayoutGapsOverride": -1, - "mangoLayoutRadiusOverride": -1, - "mangoLayoutBorderSize": -1, - "use24HourClock": true, - "showSeconds": false, - "padHours12Hour": false, - "useFahrenheit": false, - "windSpeedUnit": "kmh", - "nightModeEnabled": false, - "animationSpeed": 1, - "customAnimationDuration": 500, - "syncComponentAnimationSpeeds": true, - "popoutAnimationSpeed": 1, - "popoutCustomAnimationDuration": 150, - "modalAnimationSpeed": 1, - "modalCustomAnimationDuration": 150, - "enableRippleEffects": true, - "wallpaperFillMode": "Fill", - "blurredWallpaperLayer": false, - "blurWallpaperOnOverview": false, - "showLauncherButton": true, - "showWorkspaceSwitcher": true, - "showFocusedWindow": true, - "showWeather": true, - "showMusic": true, - "showClipboard": true, - "showCpuUsage": true, - "showMemUsage": true, - "showCpuTemp": true, - "showGpuTemp": true, - "selectedGpuIndex": 0, - "enabledGpuPciIds": [], - "showSystemTray": true, - "showClock": true, - "showNotificationButton": true, - "showBattery": true, - "showControlCenterButton": true, - "showCapsLockIndicator": true, - "controlCenterShowNetworkIcon": true, - "controlCenterShowBluetoothIcon": true, - "controlCenterShowAudioIcon": true, - "controlCenterShowAudioPercent": false, - "controlCenterShowVpnIcon": true, - "controlCenterShowBrightnessIcon": false, - "controlCenterShowBrightnessPercent": false, - "controlCenterShowMicIcon": false, - "controlCenterShowMicPercent": true, - "controlCenterShowBatteryIcon": false, - "controlCenterShowPrinterIcon": false, - "controlCenterShowScreenSharingIcon": true, - "showPrivacyButton": true, - "privacyShowMicIcon": false, - "privacyShowCameraIcon": false, - "privacyShowScreenShareIcon": false, - "controlCenterWidgets": [ - { - "id": "volumeSlider", - "enabled": true, - "width": 100 - }, - { - "id": "audioOutput", - "enabled": true, - "width": 50 - }, - { - "id": "audioInput", - "enabled": true, - "width": 50 - }, - { - "id": "nightMode", - "enabled": true, - "width": 50 - }, - { - "id": "doNotDisturb", - "enabled": true, - "width": 50 - } - ], - "showWorkspaceIndex": false, - "showWorkspaceName": false, - "showWorkspacePadding": false, - "workspaceScrolling": false, - "showWorkspaceApps": false, - "workspaceDragReorder": true, - "maxWorkspaceIcons": 3, - "workspaceAppIconSizeOffset": 0, - "groupWorkspaceApps": true, - "workspaceFollowFocus": false, - "showOccupiedWorkspacesOnly": false, - "reverseScrolling": false, - "dwlShowAllTags": false, - "workspaceColorMode": "default", - "workspaceOccupiedColorMode": "none", - "workspaceUnfocusedColorMode": "default", - "workspaceUrgentColorMode": "default", - "workspaceFocusedBorderEnabled": false, - "workspaceFocusedBorderColor": "primary", - "workspaceFocusedBorderThickness": 2, - "workspaceNameIcons": {}, - "waveProgressEnabled": true, - "scrollTitleEnabled": true, - "audioVisualizerEnabled": true, - "audioScrollMode": "volume", - "audioWheelScrollAmount": 5, - "clockCompactMode": false, - "focusedWindowCompactMode": false, - "runningAppsCompactMode": true, - "barMaxVisibleApps": 0, - "barMaxVisibleRunningApps": 0, - "barShowOverflowBadge": true, - "appsDockHideIndicators": false, - "appsDockColorizeActive": false, - "appsDockActiveColorMode": "primary", - "appsDockEnlargeOnHover": false, - "appsDockEnlargePercentage": 125, - "appsDockIconSizePercentage": 100, - "keyboardLayoutNameCompactMode": false, - "runningAppsCurrentWorkspace": false, - "runningAppsGroupByApp": false, - "runningAppsCurrentMonitor": false, - "appIdSubstitutions": [], - "centeringMode": "index", - "clockDateFormat": "ddd MMM d", - "lockDateFormat": "", - "mediaSize": 1, - "appLauncherViewMode": "grid", - "spotlightModalViewMode": "list", - "browserPickerViewMode": "grid", - "browserUsageHistory": { - "librewolf": { - "count": 4, - "lastUsed": 1770920985881, - "name": "LibreWolf" - } - }, - "appPickerViewMode": "grid", - "filePickerUsageHistory": {}, - "sortAppsAlphabetically": false, - "appLauncherGridColumns": 5, - "spotlightCloseNiriOverview": true, - "spotlightSectionViewModes": {}, - "appDrawerSectionViewModes": {}, - "niriOverviewOverlayEnabled": true, - "dankLauncherV2Size": "compact", - "dankLauncherV2BorderEnabled": false, - "dankLauncherV2BorderThickness": 2, - "dankLauncherV2BorderColor": "primary", - "dankLauncherV2ShowFooter": true, - "useAutoLocation": false, - "weatherEnabled": true, - "networkPreference": "auto", - "iconTheme": "System Default", - "cursorSettings": { - "theme": "System Default", - "size": 24, - "niri": { - "hideWhenTyping": false, - "hideAfterInactiveMs": 0 - }, - "hyprland": { - "hideOnKeyPress": false, - "hideOnTouch": false, - "inactiveTimeout": 0 - }, - "dwl": { - "cursorHideTimeout": 0 - } - }, - "launcherLogoMode": "os", - "launcherLogoCustomPath": "", - "launcherLogoColorOverride": "primary", - "launcherLogoColorInvertOnMode": false, - "launcherLogoBrightness": 0.5, - "launcherLogoContrast": 1, - "launcherLogoSizeOffset": 2, - "fontFamily": "Ubuntu", - "monoFontFamily": "Ubuntu Mono", - "fontWeight": 700, - "fontScale": 1.04, - "notepadUseMonospace": true, - "notepadFontFamily": "", - "notepadFontSize": 14, - "notepadShowLineNumbers": false, - "notepadTransparencyOverride": -1, - "notepadLastCustomTransparency": 0.7, - "soundsEnabled": true, - "useSystemSoundTheme": false, - "soundNewNotification": true, - "soundVolumeChanged": true, - "soundPluggedIn": true, - "acMonitorTimeout": 0, - "acLockTimeout": 0, - "acSuspendTimeout": 0, - "acSuspendBehavior": 0, - "acProfileName": "", - "batteryMonitorTimeout": 0, - "batteryLockTimeout": 0, - "batterySuspendTimeout": 0, - "batterySuspendBehavior": 0, - "batteryProfileName": "", - "batteryChargeLimit": 100, - "lockBeforeSuspend": false, - "loginctlLockIntegration": true, - "fadeToLockEnabled": true, - "fadeToLockGracePeriod": 5, - "fadeToDpmsEnabled": true, - "fadeToDpmsGracePeriod": 5, - "launchPrefix": "", - "brightnessDevicePins": {}, - "wifiNetworkPins": {}, - "bluetoothDevicePins": {}, - "audioInputDevicePins": {}, - "audioOutputDevicePins": {}, - "gtkThemingEnabled": false, - "qtThemingEnabled": false, - "syncModeWithPortal": true, - "terminalsAlwaysDark": true, - "runDmsMatugenTemplates": true, - "matugenTemplateGtk": true, - "matugenTemplateNiri": true, - "matugenTemplateHyprland": true, - "matugenTemplateMangowc": true, - "matugenTemplateQt5ct": true, - "matugenTemplateQt6ct": true, - "matugenTemplateFirefox": true, - "matugenTemplatePywalfox": true, - "matugenTemplateZenBrowser": true, - "matugenTemplateVesktop": true, - "matugenTemplateEquibop": true, - "matugenTemplateGhostty": true, - "matugenTemplateKitty": true, - "matugenTemplateFoot": true, - "matugenTemplateAlacritty": true, - "matugenTemplateNeovim": true, - "matugenTemplateWezterm": true, - "matugenTemplateDgop": true, - "matugenTemplateKcolorscheme": true, - "matugenTemplateVscode": true, - "matugenTemplateEmacs": true, - "showDock": false, - "dockAutoHide": false, - "dockSmartAutoHide": false, - "dockGroupByApp": false, - "dockOpenOnOverview": false, - "dockPosition": 1, - "dockSpacing": 6, - "dockBottomGap": -59, - "dockMargin": 0, - "dockIconSize": 47, - "dockIndicatorStyle": "circle", - "dockBorderEnabled": false, - "dockBorderColor": "surfaceText", - "dockBorderOpacity": 1, - "dockBorderThickness": 1, - "dockIsolateDisplays": true, - "dockLauncherEnabled": true, - "dockLauncherLogoMode": "custom", - "dockLauncherLogoCustomPath": "", - "dockLauncherLogoColorOverride": "primary", - "dockLauncherLogoSizeOffset": 3, - "dockLauncherLogoBrightness": 0.5, - "dockLauncherLogoContrast": 1, - "dockMaxVisibleApps": 0, - "dockMaxVisibleRunningApps": 0, - "dockShowOverflowBadge": true, - "notificationOverlayEnabled": false, - "modalDarkenBackground": true, - "lockScreenShowPowerActions": true, - "lockScreenShowSystemIcons": true, - "lockScreenShowTime": true, - "lockScreenShowDate": true, - "lockScreenShowProfileImage": true, - "lockScreenShowPasswordField": true, - "lockScreenShowMediaPlayer": true, - "lockScreenPowerOffMonitorsOnLock": false, - "lockAtStartup": false, - "enableFprint": false, - "maxFprintTries": 15, - "lockScreenActiveMonitor": "all", - "lockScreenInactiveColor": "#000000", - "lockScreenNotificationMode": 0, - "hideBrightnessSlider": false, - "notificationTimeoutLow": 5000, - "notificationTimeoutNormal": 5000, - "notificationTimeoutCritical": 0, - "notificationCompactMode": false, - "notificationPopupPosition": 0, - "notificationHistoryEnabled": true, - "notificationHistoryMaxCount": 50, - "notificationHistoryMaxAgeDays": 7, - "notificationHistorySaveLow": true, - "notificationHistorySaveNormal": true, - "notificationHistorySaveCritical": true, - "osdAlwaysShowValue": false, - "osdPosition": 5, - "osdVolumeEnabled": true, - "osdMediaVolumeEnabled": true, - "osdMediaPlaybackEnabled": true, - "osdBrightnessEnabled": true, - "osdIdleInhibitorEnabled": true, - "osdMicMuteEnabled": true, - "osdCapsLockEnabled": true, - "osdPowerProfileEnabled": true, - "osdAudioOutputEnabled": true, - "powerActionConfirm": true, - "powerActionHoldDuration": 0.5, - "powerMenuActions": [ - "reboot", - "logout", - "poweroff", - "lock", - "suspend", - "restart" - ], - "powerMenuDefaultAction": "logout", - "powerMenuGridLayout": false, - "customPowerActionLock": "", - "customPowerActionLogout": "", - "customPowerActionSuspend": "", - "customPowerActionHibernate": "", - "customPowerActionReboot": "", - "customPowerActionPowerOff": "", - "updaterHideWidget": false, - "updaterUseCustomCommand": false, - "updaterCustomCommand": "", - "updaterTerminalAdditionalParams": "", - "displayNameMode": "system", - "screenPreferences": {}, - "showOnLastDisplay": {}, - "niriOutputSettings": {}, - "hyprlandOutputSettings": {}, - "displayProfiles": {}, - "activeDisplayProfile": {}, - "displayProfileAutoSelect": false, - "displayShowDisconnected": false, - "displaySnapToEdge": true, - "barConfigs": [ - { - "id": "default", - "name": "Main Bar", - "enabled": true, - "position": 0, - "screenPreferences": [ - { - "name": "DP-1", - "model": "LG ULTRAGEAR" - } - ], - "showOnLastDisplay": false, - "leftWidgets": [ - "launcherButton", - "workspaceSwitcher", - { - "id": "cpuUsage", - "enabled": true, - "minimumWidth": true - }, - { - "id": "cpuTemp", - "enabled": true, - "minimumWidth": true - }, - { - "id": "memUsage", - "enabled": true, - "minimumWidth": true - }, - { - "id": "gpuTemp", - "enabled": true, - "selectedGpuIndex": 0, - "pciId": "1002:73bf" - }, - { - "id": "network_speed_monitor", - "enabled": true - } - ], - "centerWidgets": [ - "music", - "clock", - "weather", - { - "id": "notificationButton", - "enabled": true - } - ], - "rightWidgets": [ - { - "id": "systemTray", - "enabled": true - }, - { - "id": "clipboard", - "enabled": true - }, - { - "id": "privacyIndicator", - "enabled": true - }, - { - "id": "controlCenterButton", - "enabled": true - } - ], - "spacing": 0, - "innerPadding": 1, - "bottomGap": 0, - "transparency": 0.66, - "widgetTransparency": 0.78, - "squareCorners": true, - "noBackground": false, - "gothCornersEnabled": false, - "gothCornerRadiusOverride": false, - "gothCornerRadiusValue": 12, - "borderEnabled": false, - "borderColor": "surfaceText", - "borderOpacity": 1, - "borderThickness": 1, - "widgetOutlineEnabled": true, - "widgetOutlineColor": "primary", - "widgetOutlineOpacity": 0.22, - "widgetOutlineThickness": 1, - "fontScale": 1.27, - "autoHide": false, - "autoHideDelay": 250, - "showOnWindowsOpen": false, - "openOnOverview": false, - "visible": true, - "popupGapsAuto": true, - "popupGapsManual": 4, - "maximizeDetection": true, - "scrollEnabled": true, - "scrollXBehavior": "column", - "scrollYBehavior": "workspace", - "shadowIntensity": 0, - "shadowOpacity": 56, - "shadowColorMode": "text", - "shadowCustomColor": "#000000" - } - ], - "desktopClockEnabled": false, - "desktopClockStyle": "analog", - "desktopClockTransparency": 0.8, - "desktopClockColorMode": "primary", - "desktopClockCustomColor": { - "r": 1, - "g": 1, - "b": 1, - "a": 1, - "hsvHue": -1, - "hsvSaturation": 0, - "hsvValue": 1, - "hslHue": -1, - "hslSaturation": 0, - "hslLightness": 1, - "valid": true - }, - "desktopClockShowDate": true, - "desktopClockShowAnalogNumbers": false, - "desktopClockShowAnalogSeconds": true, - "desktopClockX": -1, - "desktopClockY": -1, - "desktopClockWidth": 280, - "desktopClockHeight": 180, - "desktopClockDisplayPreferences": [ - "all" - ], - "systemMonitorEnabled": false, - "systemMonitorShowHeader": true, - "systemMonitorTransparency": 0.8, - "systemMonitorColorMode": "primary", - "systemMonitorCustomColor": { - "r": 1, - "g": 1, - "b": 1, - "a": 1, - "hsvHue": -1, - "hsvSaturation": 0, - "hsvValue": 1, - "hslHue": -1, - "hslSaturation": 0, - "hslLightness": 1, - "valid": true - }, - "systemMonitorShowCpu": true, - "systemMonitorShowCpuGraph": true, - "systemMonitorShowCpuTemp": true, - "systemMonitorShowGpuTemp": false, - "systemMonitorGpuPciId": "", - "systemMonitorShowMemory": true, - "systemMonitorShowMemoryGraph": true, - "systemMonitorShowNetwork": true, - "systemMonitorShowNetworkGraph": true, - "systemMonitorShowDisk": true, - "systemMonitorShowTopProcesses": false, - "systemMonitorTopProcessCount": 3, - "systemMonitorTopProcessSortBy": "cpu", - "systemMonitorGraphInterval": 60, - "systemMonitorLayoutMode": "auto", - "systemMonitorX": -1, - "systemMonitorY": -1, - "systemMonitorWidth": 320, - "systemMonitorHeight": 480, - "systemMonitorDisplayPreferences": [ - "all" - ], - "systemMonitorVariants": [], - "desktopWidgetPositions": {}, - "desktopWidgetGridSettings": {}, - "desktopWidgetInstances": [], - "desktopWidgetGroups": [], - "builtInPluginSettings": { - "dms_settings_search": { - "trigger": "?" - } - }, - "launcherPluginVisibility": {}, - "launcherPluginOrder": [], - "configVersion": 5 -} \ No newline at end of file diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config-kitty.jsonc b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config-kitty.jsonc deleted file mode 100644 index 1737df8..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config-kitty.jsonc +++ /dev/null @@ -1,47 +0,0 @@ -{ - "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "source": "~/.config/fastfetch/raveos-logo.txt", - "type": "file", - "color": { - "1": "green", - "2": "36", - "3": "white" - }, - "padding": { - "top": 1, - "left": 2, - "right": 3 - } - }, - "display": { - "separator": " → ", - "color": { - "keys": "green", - "title": "cyan" - } - }, - "modules": [ - { "type": "custom", "format": "\u001b[1;32mRaveOS" }, - "separator", - { "type": "os", "key": "OS" }, - { "type": "kernel", "key": "Kernel" }, - { "type": "uptime", "key": "Uptime" }, - { "type": "packages", "key": "Packages" }, - { "type": "shell", "key": "Shell" }, - { "type": "de", "key": "DE" }, - { "type": "wm", "key": "WM" }, - { "type": "terminal", "key": "Terminal" }, - "separator", - { "type": "cpu", "key": "CPU" }, - { "type": "gpu", "key": "GPU" }, - { "type": "memory", "key": "RAM" }, - { "type": "disk", "key": "Disk", "folders": "/" }, - "separator", - { "type": "display", "key": "Display" }, - { "type": "theme", "key": "Theme" }, - { "type": "icons", "key": "Icons" }, - "break", - "colors" - ] -} diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config.jsonc b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config.jsonc deleted file mode 100644 index f5f842d..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/config.jsonc +++ /dev/null @@ -1,93 +0,0 @@ -{ - "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "source": "~/.config/fastfetch/raveos-logo.txt", - "type": "file", - "color": { - "1": "green", - "2": "36", - "3": "white" - }, - "padding": { - "top": 1, - "left": 2, - "right": 3 - } - }, - "display": { - "separator": " → ", - "color": { - "keys": "green", - "title": "cyan" - } - }, - "modules": [ - "title", - "separator", - { - "type": "os", - "key": "OS" - }, - { - "type": "kernel", - "key": "Kernel" - }, - { - "type": "uptime", - "key": "Uptime" - }, - { - "type": "packages", - "key": "Packages" - }, - { - "type": "shell", - "key": "Shell" - }, - { - "type": "de", - "key": "DE" - }, - { - "type": "wm", - "key": "WM" - }, - { - "type": "terminal", - "key": "Terminal" - }, - "separator", - { - "type": "cpu", - "key": "CPU" - }, - { - "type": "gpu", - "key": "GPU" - }, - { - "type": "memory", - "key": "RAM" - }, - { - "type": "disk", - "key": "Disk", - "folders": "/" - }, - "separator", - { - "type": "display", - "key": "Display" - }, - { - "type": "theme", - "key": "Theme" - }, - { - "type": "icons", - "key": "Icons" - }, - "break", - "colors" - ] -} diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.png b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.png deleted file mode 100644 index 93ebb33..0000000 Binary files a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.png and /dev/null differ diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.txt b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.txt deleted file mode 100644 index 41f87e2..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/fastfetch/raveos-logo.txt +++ /dev/null @@ -1,19 +0,0 @@ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⢠⡀⠀⠀⠀⠀⠀⠀⡀⠀⣰⣾⣿⣿⣷⣄⠀⣠⠀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠙⣦⣄⡀⠠⡀⠀⣿⡆⠙⣿⣿⣿⡿⠃⢰⣧⠀⣀⠄⢀⣤⡴⠋⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⣀⠀⠑⢮⣙⠛⠂⠙⠀⡅⣹⣄⢸⣿⣿⡇⣠⡏⠁⠈⠉⠐⠟⣉⡵⠊⠀⣠⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠄⢈⣃⡀⠐⠿⣷⣦⣀⢰⣼⣈⣿⣾⣿⣿⣿⣿⢁⣥⡆⣠⣴⣾⠿⠂⢀⣀⠁⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠠⠤⠬⠿⠿⠷⠌⠻⢿⢷⡝⢿⣿⡌⣿⡿⢱⣿⡿⢫⡾⠿⠟⠡⠾⠿⠯⠥⠤⠄⠀⠀⠀⠀ -⠀⠀⠀⠙⠂⠈⠀⠀⠄⠀⠉⠀⠐⠶⢷⣦⣬⡁⠏⠷⢈⣥⣴⠿⠶⠂⠀⠉⠁⠀⠀⠀⠁⠘⠊⠂⠀⠀ -⠀⠀⠀⠀⢀⠄⢠⣴⣶⠀⠀⠀⢀⡀⠀⠉⠙⠃⣠⡄⠘⠉⠁⠀⢀⡀⠀⠀⢠⣶⣦⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⣠⠤⠌⠁⣩⣿⣇⡀⠢⣜⣛⠛⠀⠀⡴⢫⡝⣄⠀⠀⠛⢛⡡⠔⢀⣼⣯⣅⠈⠁⠤⡄⠀⠀⠀ -⠀⠀⠀⢀⡠⢴⠾⠉⢉⣿⣿⣷⣶⣭⣶⣾⡟⣱⣿⣿⡜⢻⣶⣦⣥⣶⣾⣿⣯⡉⠉⠷⡤⢄⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⢀⡴⠂⢚⠟⢉⣾⠿⠛⢙⠉⣠⠈⢹⠇⠁⣄⢈⠋⠛⠿⣷⡉⠿⡓⡐⢦⡀⠀⠁⠀⠀⠀ -⠀⠀⠀⠀⠀⠒⢉⣵⣿⣷⣧⠆⢂⠶⢿⡽⠛⠰⣦⣴⠀⠛⣯⠿⡢⡐⠲⣽⣼⣿⣮⡙⠓⠀⠀⠄⠀⠀ -⠀⠀⢀⣴⠷⠂⣾⣿⠿⠛⣡⣾⡤⠀⠘⠁⢰⣴⣿⣿⣤⠀⠈⠃⠀⢤⣶⣌⠻⢿⣿⣧⠐⠾⣦⡀⠀⠀ -⠀⠀⠀⠀⠀⠘⠉⠀⢠⣼⠏⠋⣠⢠⡄⢀⠻⠉⣿⡿⠈⠟⡄⢰⡀⡀⠻⠹⣦⡀⠀⠉⠃⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠂⠀⠁⠀⡄⡿⠀⢣⠀⠀⠐⡌⢡⠀⠈⢀⡌⠈⢧⠂⠀⠈⠀⠑⠀⠀⠀⠀⠀⠀⠀ -⢠⣤⣤⣤⣤⣄⣰⢠⣤⣴⣦⠟⣥⣦⣀⢳⣦⡆⣴⣦⣶⣴⣾⣄⠀⢈⣷⣶⣶⣦⣄⣄⣠⣴⣶⣦⣤⠀ -⢸⣿⣧⣤⣽⡿⢁⣿⣟⣹⣿⡄⠘⣿⣿⣾⡿⠀⣿⣿⣶⣶⣾⠋⠀⢾⣿⡍⠁⢹⣿⡎⠿⠷⠶⣶⣭⡀ -⠸⣿⠇⠙⢿⡦⢼⡿⠛⠛⢿⣷⠀⠹⣿⡿⠁⠀⢿⣿⣶⣶⣶⠆⠀⠘⠿⢷⣶⠿⠟⠀⠿⢿⣶⡾⠿⠃ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/cursor.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/cursor.conf deleted file mode 100644 index 1054579..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/cursor.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Auto-generated by DMS - do not edit manually - -env = HYPRCURSOR_THEME,default -env = XCURSOR_THEME,default -env = HYPRCURSOR_SIZE,24 -env = XCURSOR_SIZE,24 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/layout.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/layout.conf deleted file mode 100644 index b9a8ad9..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/layout.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Auto-generated by DMS - do not edit manually - -general { - gaps_in = 4 - gaps_out = 4 - border_size = 2 -} - -decoration { - rounding = 12 -} diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/windowrules.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/dms/windowrules.conf deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/hyprland.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/hyprland.conf deleted file mode 100644 index 45ef8f4..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/hyprland.conf +++ /dev/null @@ -1,542 +0,0 @@ - -# ####################################################################################### -# AUTOGENERATED HYPRLAND CONFIG. -# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT, -# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. -# ####################################################################################### - -# This is an example Hyprland config file. -# Refer to the wiki for more information. -# https://wiki.hyprland.org/Configuring/ - -# Please note not all available settings / options are set here. -# For a full list, see the wiki - -# You can split this configuration into multiple files -# Create your files separately and then link them to this file like this: -# source = ~/.config/hypr/myColors.conf - - -################ -### ALT TAB ### -################ -#bind = SUPER, TAB, cyclenext -#bind = SUPER, TAB, bringactivetotop -#bind = SUPER, TAB, exec, dms ipc call hypr toggleOverview -bind = SUPER, TAB, exec, hyprswitch gui --mod-key super_l --key tab --close mod-key-release --sort-recent --filter-current-monitor - -################ -### MONITORS ### -################ - -# See https://wiki.hyprland.org/Configuring/Monitors/ -# Auto-generated by raveos-monitor-setup or manually configured -source = ./monitors.conf -source = ./workspaces.conf - -# Example workspace assignments (customize for your setup): -#workspace=1, monitor:DP-1, persistent:1 -#workspace=2, monitor:DP-1, persistent:1 -#workspace=3, monitor:DP-1, persistent:1 -#workspace=4, monitor:DP-1, persistent:1 -#workspace=5, monitor:DP-1, persistent:1 -#workspace=6, monitor:DP-2, persistent:1 -#workspace=7, monitor:DP-2, persistent:1 -#workspace=8, monitor:DP-2, persistent:1 -#workspace=9, monitor:HDMI-A-1, persistent:1 -#workspace=10, monitor:HDMI-A-1, persistent:1 - - - -################### -### MY PROGRAMS ### -################### - -# See https://wiki.hyprland.org/Configuring/Keywords/ - -# Set programs that you use -$terminal = kitty -$fileManager = Thunar - - -################# -### AUTOSTART ### -################# - -# Autostart necessary processes (like notifications daemons, status bars, etc.) -# Or execute your favorite apps at launch like this: - -exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -exec-once = dbus-update-activation-environment --systemd --all -exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 -exec-once = corectrl -exec-once = input-remapper-control --command autoload --preset uk -exec-once = hyprswitch init --show-title --size-factor 6 --workspaces-per-row 5 & - -#exec-once = systemctl --user start hyprpolkitagent - - -############################# -### ENVIRONMENT VARIABLES ### -############################# - -# See https://wiki.hyprland.org/Configuring/Environment-variables/ -exec-once = gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' -exec-once = bash -c "wl-paste --watch cliphist store &" -exec-once = dms run -exec-once = sleep 1 && /usr/lib/pam_kwallet_init -exec-once = /usr/lib/mate-polkit/polkit-mate-authentication-agent-1 -exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -exec-once = dbus-update-activation-environment --systemd --all -exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP - - -# Theme - -env = XCURSOR_SIZE,24 -env = HYPRCURSOR_SIZE,24 - -env = XDG_CURRENT_DESKTOP,Hyprland -env = XDG_SESSION_TYPE,wayland -env = XDG_SESSION_DESKTOP,Hyprland -env = XDG_MENU_PREFIX,arch- - -env = GDK_BACKEND,wayland -env = QT_QPA_PLATFORM,wayland -env = QT_QPA_PLATFORMTHEME,qt6ct -env = QT_AUTO_SCREEN_SCALE_FACTOR,1 -env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 -env = QT_STYLE_OVERRIDE,kvantum -env = SSH_AUTH_SOCK,$XDG_RUNTIME_DIR/ssh-agent.socket - -##################### -### LOOK AND FEEL ### -##################### - -# Refer to https://wiki.hyprland.org/Configuring/Variables/ - -# https://wiki.hyprland.org/Configuring/Variables/#general -general { - gaps_in = 5 - gaps_out = 2 - - border_size = 0 - - # https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors - col.active_border = rgba(4f23b5cc) rgba(b57123fc) 45deg - col.inactive_border = rgba(595959aa) - - # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = true - - # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on - allow_tearing = false - - layout = dwindle -} - -# https://wiki.hyprland.org/Configuring/Variables/#decoration -decoration { - rounding = 11 - rounding_power = 3 - - - # Change transparency of focused and unfocused windows - active_opacity = 1.0 - inactive_opacity = 1.0 - - shadow { - enabled = false - range = 4 - render_power = 3 - color = rgba(1a1a1aee) - } - - # https://wiki.hyprland.org/Configuring/Variables/#blur - blur { - enabled = true - size = 3 - passes = 1 - - - vibrancy = 0.1696 - } -} - -# https://wiki.hyprland.org/Configuring/Variables/#animations -animations { - enabled = yes, please :) - - # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more - - bezier = easeOutQuint,0.23,1,0.32,1 - bezier = easeInOutCubic,0.65,0.05,0.36,1 - bezier = linear,0,0,1,1 - bezier = almostLinear,0.5,0.5,0.75,1.0 - bezier = quick,0.15,0,0.1,1 - - animation = global, 1, 10, default - animation = border, 1, 5.39, easeOutQuint - animation = windows, 1, 4.79, easeOutQuint - animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% - animation = windowsOut, 1, 1.49, linear, popin 87% - animation = fadeIn, 1, 1.73, almostLinear - animation = fadeOut, 1, 1.46, almostLinear - animation = fade, 1, 3.03, quick - animation = layers, 1, 3.81, easeOutQuint - animation = layersIn, 1, 4, easeOutQuint, fade - animation = layersOut, 1, 1.5, linear, fade - animation = fadeLayersIn, 1, 1.79, almostLinear - animation = fadeLayersOut, 1, 1.39, almostLinear - animation = workspaces, 1, 1.94, almostLinear, fade - animation = workspacesIn, 1, 1.21, almostLinear, fade - animation = workspacesOut, 1, 1.94, almostLinear, fade -} - -# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ -# "Smart gaps" / "No gaps when only" -# uncomment all if you wish to use that. -# workspace = w[tv1], gapsout:0, gapsin:0 -# workspace = f[1], gapsout:0, gapsin:0 -# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] -# windowrule = rounding 0, floating:0, onworkspace:w[tv1] -# windowrule = bordersize 0, floating:0, onworkspace:f[1] -# windowrule = rounding 0, floating:0, onworkspace:f[1] - -# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more -dwindle { - pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below - preserve_split = true # You probably want this -} - -# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more -master { - new_status = master -} - -# https://wiki.hyprland.org/Configuring/Variables/#misc -misc { - force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers - disable_hyprland_logo = true # If true disables the random hyprland logo / anime girl background. :( -} - - -############# -### INPUT ### -############# - -# https://wiki.hyprland.org/Configuring/Variables/#input -input { - kb_layout = gb - kb_variant = mac - kb_model = - kb_options = - kb_rules = - - follow_mouse = 1 - - sensitivity = 0 # -1.0 - 1.0, 0 means no modification. - numlock_by_default = true - accel_profile = flat - - touchpad { - natural_scroll = false - } -} - -cursor { - no_warps = true -} - -# Example per-device config -# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more -device { - name = epic-mouse-v1 - sensitivity = -0.5 -} - - -################### -### KEYBINDINGS ### -################### - -# See https://wiki.hyprland.org/Configuring/Keywords/ -$mainMod = SUPER # Sets "Windows" key as main modifier -$key = tab - -# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more - -# My binds - -bind = ALT ,mouse:274, fullscreen -# bind = SUPER_L, Tab, exec, hypr-alttab -bind = CTRL_ALT, D, exec, $HOME/Documents/discord.sh -bind = CTRL_ALT, G, exec, gedit -bind = CTRL_ALT, P, exec, pavucontrol -bind = CTRL_SUPER, KP_End, exec, reboot -bind = CTRL_SUPER, KP_Next, exec, poweroff -bind = CTRL, KP_Next, exec, $HOME/Documents/mute.sh -bind = $mainMod, S, togglespecialworkspace, magic -bind = $mainMod, S, movetoworkspace, +0 -bind = $mainMod, S, togglespecialworkspace, magic -bind = $mainMod, S, movetoworkspace, special:magic -bind = $mainMod, S, togglespecialworkspace, magic -bind = CTRL_ALT, T, exec, $terminal -bind = CTRL_ALT, F, exec, freetube -bind = $mainMod, Q, killactive, -bind = $mainMod, M, exit, -bind = $mainMod, E, exec, nautilus -bind = $mainMod, V, togglefloating, -bind = $mainMod, P, pseudo, # dwindle -bind = $mainMod, J, togglesplit, # dwindle - - -# Move focus with mainMod + arrow keys -bind = $mainMod, left, movefocus, l -bind = $mainMod, right, movefocus, r -bind = $mainMod, up, movefocus, u -bind = $mainMod, down, movefocus, d - -# Switch workspaces with mainMod + [0-9] -bind = $mainMod, 1, exec, Thunar -bind = $mainMod, 2, exec, librewolf -bind = $mainMod, 3, exec, vivaldi -bind = Ctrl Shift, KP_End, workspace, 1 -bind = Ctrl Shift, KP_Down, workspace, 2 -bind = Ctrl Shift, KP_Next, workspace, 3 -bind = Ctrl Shift, KP_Left, workspace, 4 -bind = Ctrl Shift, KP_Begin, workspace, 5 -bind = Ctrl Shift, KP_Right, workspace, 6 -bind = Ctrl Shift, KP_Home, workspace, 7 -bind = Ctrl Shift, KP_Up, workspace, 8 -bind = Ctrl Shift, KP_Prior, workspace, 9 -bind = Ctrl Shift, KP_Insert, workspace, 10 - -# Move active window to a workspace with mainMod + SHIFT + [0-9] -bind = $mainMod SHIFT, KP_End, movetoworkspace, 1 -bind = $mainMod SHIFT, KP_Down, movetoworkspace, 2 -bind = $mainMod SHIFT, KP_Next, movetoworkspace, 3 -bind = $mainMod SHIFT, KP_Left, movetoworkspace, 4 -bind = $mainMod SHIFT, KP_Begin, movetoworkspace, 5 -bind = $mainMod SHIFT, KP_Right, movetoworkspace, 6 -bind = $mainMod SHIFT, KP_Home, movetoworkspace, 7 -bind = $mainMod SHIFT, KP_Up, movetoworkspace, 8 -bind = $mainMod SHIFT, KP_Prior, movetoworkspace, 9 -bind = $mainMod SHIFT, KP_Insert, movetoworkspace, 10 -# Scroll through existing workspaces with mainMod + scroll -bind = $mainMod, mouse_down, workspace, e+1 -bind = $mainMod, mouse_up, workspace, e-1 - -# Shell Binds - -bind = SUPER, SUPER_L, exec, dms ipc call spotlight toggle -bind = $mainMod, V, exec, dms ipc call clipboard toggle -#bind = $mainMod, M, exec, dms ipc call processlist toggle -bind = $mainMod, comma, exec, dms ipc call settings toggle -bind = $mainMod, N, exec, dms ipc call notifications toggle -bind = $mainMod SHIFT, N, exec, dms ipc call notepad toggle -bind = $mainMod, Y, exec, dms ipc call dankdash wallpaper -#bind = $mainMod, TAB, exec, dms ipc call hypr toggleOverview -bind = SUPER, Return, exec, kitty - -# Move/resize windows with mainMod + LMB/RMB and dragging -bindm = $mainMod, mouse:272, movewindow -bindm = $mainMod, mouse:273, resizewindow - -# Laptop multimedia keys for volume and LCD brightness -bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ -bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- -bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle -bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle -bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ -bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- - -# Requires playerctl -bindl = , XF86AudioNext, exec, playerctl next -bindl = , XF86AudioPause, exec, playerctl play-pause -bindl = , XF86AudioPlay, exec, playerctl play-pause -bindl = , XF86AudioPrev, exec, playerctl previous - -############################## -### WINDOWS AND WORKSPACES ### -############################## - -# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more -# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules - -# Example windowrule -windowrule { - name = windowrule-1 - float = on - match:class = .* -} - -windowrule { - name = windowrule-2 - size = 1000 1000 - match:class = org.pulseaudio.pavucontrol -} - -windowrule { - name = windowrule-3 - size = 640 700 - match:title = GST -} - -windowrule { - name = windowrule-4 - size = 1900 1060 - workspace = 2 - match:title = ^(.*OBS.*)$ - workspace = 6 -} - -windowrule { - name = windowrule-5 - fullscreen = on - match:class = ^steam_app\d+$ -} - -windowrule { - name = windowrule-6 - workspace = 1 - match:class = ^steam_app_\d+$ -} - -windowrule { - name = windowrule-7 - size = 1000 777 - match:title = ^(.*Properties for*.)$ -} - -windowrule { - name = windowrule-8 - size = 1000 1000 - match:class = org.gnome.gedit -} - -windowrule { - name = windowrule-10 - size = 444 444 - match:title = Preferences -} - -windowrule { - name = windowrule-11 - size = 2560 1403 - move = (0) (37) - match:title = FreeTube - workspace = 5 -} - -windowrule { - name = windowrule-12 - size = 1222 777 - match:title = rave - Thunar -} - -windowrule { - name = windowrule-13 - size = 444 111 - match:title = File Operation Progress -} - -windowrule { - name = windowrule-14 - size = 520 600 - move = (0) (541) - match:class = vivaldi-kick.com__rpslair_popout_activity-feed-Default - workspace = 9 -} - -windowrule { - name = windowrule-15 - size = 520 600 - move = (0) (0) - match:class = vivaldi-streamlabs.com__dashboard_recent-events-Default - workspace = 9 -} - -windowrule { - name = windowrule-16 - size = 1408 623 - move = (510) (0) - match:class = vivaldi-www.twitch.tv__popout_ravepriest1_chat-Default - workspace = 9 -} - -windowrule { - name = windowrule-17 - size = 1920 1080 - move = (0) (0) - match:class = discord - workspace = 7 -} - -windowrule { - name = windowrule-18 - size = 515 565 - move = (769) (0) - match:class = virt-manager - workspace = 8 -} - -windowrule { - name = windowrule-19 - size = 768 480 - move = (0) (0) - match:class = audacious - workspace = 8 -} - -windowrule { - name = windowrule-20 - size = 1413 685 - move = (510) (450) - match:class = vivaldi-kick.com__popout_rpslair_chat-Default - workspace = 9 -} - -windowrule { - name = windowrule-21 - size = 1920 1080 - move = (0) (0) - match:class = vivaldi-stable - workspace = 10 -} - -windowrule { - name = windowrule-22 - size = 1920 1080 - move = (0) (0) - match:class = firejail - workspace = 7 -} - -windowrule { - name = windowrule-23 - size = 1272 789 - move = (645) (290) - match:title = JKBMS on QEMU/KVM - workspace = 8 -} - -# Ignore maximize requests from apps. You'll probably like this. -#windowrule = suppressevent maximize, class:.* - -# Fix some dragging issues with XWayland -#windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 - -layerrule = match:class ^(quickshell)$, no_anim on - -############### -### PLUGINS ### -############### - - - - -source = ./dms/cursor.conf -source = ./dms/layout.conf -source = ./dms/windowrules.conf diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/monitors.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/monitors.conf deleted file mode 100644 index 12d095a..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/monitors.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Auto-generated by raveos-monitor-setup -# Run raveos-monitor-setup to reconfigure monitors -# Format: monitor=NAME, RESxRES@HZ, POSxPOS, SCALE - -monitor=,preferred,auto,1 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/alt-tab.sh b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/alt-tab.sh deleted file mode 100755 index 0a40f9d..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/alt-tab.sh +++ /dev/null @@ -1,273 +0,0 @@ -#!/bin/bash - -STATE_DIR="/tmp/hypr-alt-tab" -STATE_FILE="$STATE_DIR/state" -TIME_FILE="$STATE_DIR/last_press" -CURRENT_INDEX_FILE="$STATE_DIR/current_index" -WINDOW_LIST_FILE="$STATE_DIR/window_list" - -# Cooldown in seconds (time within which presses count as "continuous") -COOLDOWN=0.8 - -# Create state directory if it doesn't exist -mkdir -p "$STATE_DIR" - -# Parse arguments -same_type=false -reverse=false -visible_only=false - -for arg in "$@"; do - case $arg in - --same) same_type=true ;; - --reverse) reverse=true ;; - --visible) visible_only=true ;; - esac -done - -# Function to get window class -get_window_class() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .class' -} - -# Function to get window title -get_window_title() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .title' -} - -# Function to get window workspace ID -get_window_workspace() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .workspace.id' -} - -# Function to get active workspaces (visible on monitors) -get_active_workspaces() { - hyprctl monitors -j | jq -r '.[].activeWorkspace.id' -} - -# Function to get all windows sorted by focus history (most recent first) -get_windows_by_focus() { - hyprctl clients -j | jq -r 'sort_by(-.focusHistoryID) | .[].address' -} - -# Function to get visible windows (on active workspaces) -get_visible_windows() { - # Get all active workspace IDs - mapfile -t active_workspaces < <(get_active_workspaces) - - if [[ ${#active_workspaces[@]} -eq 0 ]]; then - return - fi - - # Convert active workspaces to JSON array for jq query - local workspaces_json="[" - for ws in "${active_workspaces[@]}"; do - workspaces_json+="$ws," - done - workspaces_json="${workspaces_json%,}]" - - # Get windows in active workspaces, sorted by focus history - hyprctl clients -j | jq -r --argjson workspaces "$workspaces_json" ' - [.[] | select(.workspace.id as $ws | $workspaces | index($ws))] - | sort_by(-.focusHistoryID) - | .[].address - ' -} - -# Function to get windows filtered by type (same class or title pattern) -get_same_type_windows() { - local current_window="$1" - local current_class=$(get_window_class "$current_window") - local current_title=$(get_window_title "$current_window") - - # Get all windows with same class - hyprctl clients -j | jq -r --arg class "$current_class" \ - '.[] | select(.class == $class) | .address' -} - -# Function to get currently focused window -get_focused_window() { - hyprctl activewindow -j | jq -r '.address' -} - -# Function to check if window exists -window_exists() { - local window="$1" - [[ -n "$window" ]] && hyprctl clients -j | jq -r '.[].address' | grep -q "^${window}$" -} - -# Function to validate and refresh window list -validate_window_list() { - local windows=("$@") - local valid_windows=() - - for window in "${windows[@]}"; do - if window_exists "$window"; then - valid_windows+=("$window") - fi - done - - printf '%s\n' "${valid_windows[@]}" -} - -# Get currently focused window -current_focused=$(get_focused_window) - -# Get appropriate window list based on mode -if [[ "$visible_only" == "true" ]]; then - # Get only windows in active workspaces (visible on monitors) - echo "Switching between visible windows only" >&2 - mapfile -t windows < <(get_visible_windows) - - # If no visible windows, fall back to all windows - if [[ ${#windows[@]} -eq 0 ]]; then - echo "No visible windows found, falling back to all windows" >&2 - mapfile -t windows < <(get_windows_by_focus) - fi - - # Apply same-type filter if requested - if [[ "$same_type" == "true" ]] && [[ -n "$current_focused" ]]; then - # Get windows of the same type as current (from visible windows) - mapfile -t same_type_windows < <(get_same_type_windows "$current_focused") - - # Filter visible windows to only include same-type windows - local filtered_windows=() - for visible_window in "${windows[@]}"; do - for same_window in "${same_type_windows[@]}"; do - if [[ "$visible_window" == "$same_window" ]]; then - filtered_windows+=("$visible_window") - break - fi - done - done - - # If filtered list has windows, use it - if [[ ${#filtered_windows[@]} -gt 0 ]]; then - windows=("${filtered_windows[@]}") - else - echo "No visible windows of same type, using all visible windows" >&2 - fi - fi -elif [[ "$same_type" == "true" ]] && [[ -n "$current_focused" ]]; then - # Get windows of the same type as current (from all windows) - mapfile -t windows < <(get_same_type_windows "$current_focused") - - # If no same-type windows or only current window, fall back to all windows - if [[ ${#windows[@]} -le 1 ]]; then - echo "No other windows of same type found, switching to all windows" >&2 - mapfile -t windows < <(get_windows_by_focus) - fi -else - # Get all windows - mapfile -t windows < <(get_windows_by_focus) -fi - -# Validate windows still exist -mapfile -t windows < <(validate_window_list "${windows[@]}") - -# Exit if no windows or only one window -if [[ ${#windows[@]} -le 1 ]]; then - echo "Not enough windows to switch" >&2 - exit 0 -fi - -# Get current time -current_time=$(date +%s.%N) - -# Read last press time -last_press=0 -[[ -f "$TIME_FILE" ]] && last_press=$(<"$TIME_FILE") - -# Calculate time difference -time_diff=$(echo "$current_time - $last_press" | bc -l 2>/dev/null || echo "1") - -# Check if we're continuing the Alt+Tab session -continuing_session=false -if (( $(echo "$time_diff <= $COOLDOWN" | bc -l 2>/dev/null || echo "0") )); then - continuing_session=true -fi - -# Find current window index in the list -current_index=-1 -for i in "${!windows[@]}"; do - if [[ "${windows[$i]}" == "$current_focused" ]]; then - current_index=$i - break - fi -done - -# If current window not in filtered list, start from beginning -if [[ $current_index -eq -1 ]]; then - current_index=0 -fi - -# Calculate target index -if [[ "$continuing_session" == "true" ]] && [[ -f "$CURRENT_INDEX_FILE" ]] && [[ -f "$WINDOW_LIST_FILE" ]]; then - # Read saved state - saved_index=$(<"$CURRENT_INDEX_FILE") - mapfile -t saved_windows < "$WINDOW_LIST_FILE" - - # Check if saved windows match current windows - same_list=true - if [[ ${#windows[@]} -ne ${#saved_windows[@]} ]]; then - same_list=false - else - for i in "${!windows[@]}"; do - if [[ "${windows[$i]}" != "${saved_windows[$i]}" ]]; then - same_list=false - break - fi - done - fi - - if [[ "$same_list" == "true" ]]; then - if [[ "$reverse" == "true" ]]; then - target_index=$(( (saved_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (saved_index + 1) % ${#windows[@]} )) - fi - else - # List changed, recalculate from current - if [[ "$reverse" == "true" ]]; then - target_index=$(( (current_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (current_index + 1) % ${#windows[@]} )) - fi - fi -else - # Start new session - move from current window - if [[ "$reverse" == "true" ]]; then - target_index=$(( (current_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (current_index + 1) % ${#windows[@]} )) - fi -fi - -# Save state -echo "$current_time" > "$TIME_FILE" -echo "$target_index" > "$CURRENT_INDEX_FILE" -printf '%s\n' "${windows[@]}" > "$WINDOW_LIST_FILE" - -# Focus the target window -target_window="${windows[$target_index]}" -if window_exists "$target_window"; then - echo "Switching to window: $target_window (Class: $(get_window_class "$target_window"), Workspace: $(get_window_workspace "$target_window"))" >&2 - hyprctl dispatch focuswindow "address:$target_window" - hyprctl dispatch bringactivetotop -fi - -# Visual feedback: dim inactive windows temporarily -hyprctl keyword decoration:dim_inactive true 2>/dev/null - -# Clear any existing reset timer -[[ -f "$STATE_DIR/dim_timer" ]] && kill "$(<"$STATE_DIR/dim_timer")" 2>/dev/null || true - -# Start timer to reset dimming -( - sleep 1.2 - hyprctl keyword decoration:dim_inactive false 2>/dev/null -) & -echo $! > "$STATE_DIR/dim_timer" diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/raveos-monitor-setup.sh b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/raveos-monitor-setup.sh deleted file mode 100755 index 2790ee4..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/scripts/raveos-monitor-setup.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash -# raveos-monitor-setup - Auto-detect monitors and generate Hyprland config -# Sets each monitor to max resolution at 60Hz -# -# Usage: raveos-monitor-setup.sh [--hypr-dir PATH] -# Default hypr dir: ~/.config/hypr - -HYPR_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/hypr" - -# Parse arguments -while [[ $# -gt 0 ]]; do - case "$1" in - --hypr-dir) HYPR_DIR="$2"; shift 2 ;; - *) shift ;; - esac -done - -MONITORS_CONF="$HYPR_DIR/monitors.conf" -WORKSPACES_CONF="$HYPR_DIR/workspaces.conf" - -# Find connected monitors via DRM sysfs -declare -a MON_NAMES -declare -a MON_RESOLUTIONS -declare -a MON_WIDTHS - -for card_output in /sys/class/drm/card*-*; do - [[ ! -d "$card_output" ]] && continue - - status=$(cat "$card_output/status" 2>/dev/null) - [[ "$status" != "connected" ]] && continue - - # Get output name: card0-DP-1 → DP-1, card1-HDMI-A-1 → HDMI-A-1 - raw_name=$(basename "$card_output") - name="${raw_name#card*-}" - - # Get available modes (first line = highest resolution) - modes_file="$card_output/modes" - if [[ -f "$modes_file" ]]; then - max_mode=$(head -1 "$modes_file") - if [[ -n "$max_mode" ]]; then - # Extract width from resolution (e.g., 2560x1440 → 2560) - width="${max_mode%%x*}" - MON_NAMES+=("$name") - MON_RESOLUTIONS+=("$max_mode") - MON_WIDTHS+=("$width") - fi - fi -done - -# If no monitors found, use fallback -if [[ ${#MON_NAMES[@]} -eq 0 ]]; then - cat > "$MONITORS_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# No monitors detected - using fallback -monitor=,preferred,auto,1 -EOF - cat > "$WORKSPACES_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# No monitors detected -EOF - echo "No monitors detected, using fallback config" - exit 0 -fi - -# Generate monitors.conf -cat > "$MONITORS_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# Run raveos-monitor-setup.sh to reconfigure monitors -EOF - -pos_x=0 -for ((i=0; i<${#MON_NAMES[@]}; i++)); do - echo "monitor=${MON_NAMES[$i]}, ${MON_RESOLUTIONS[$i]}@60, ${pos_x}x0, 1" >> "$MONITORS_CONF" - pos_x=$((pos_x + MON_WIDTHS[i])) -done - -# Generate workspaces.conf - distribute 10 workspaces across monitors -cat > "$WORKSPACES_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -EOF - -num_monitors=${#MON_NAMES[@]} -ws_per_mon=$((10 / num_monitors)) -remaining=$((10 % num_monitors)) - -ws=1 -for ((i=0; i> "$WORKSPACES_CONF" - ((ws++)) - done -done - -echo "Monitor setup complete: ${#MON_NAMES[@]} monitor(s) configured" -for ((i=0; i<${#MON_NAMES[@]}; i++)); do - echo " ${MON_NAMES[$i]}: ${MON_RESOLUTIONS[$i]}@60" -done diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/workspaces.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/workspaces.conf deleted file mode 100644 index 328ed03..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/hypr/workspaces.conf +++ /dev/null @@ -1,2 +0,0 @@ -# Auto-generated by raveos-monitor-setup -# Workspace assignments are configured automatically based on connected monitors diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/kitty/kitty.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/kitty/kitty.conf deleted file mode 100644 index 7b84ae9..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/kitty/kitty.conf +++ /dev/null @@ -1,37 +0,0 @@ -font_family JetBrains Mono -font_size 11.0 - -foreground #D8DEE9 -background #2E3440 -selection_foreground #2E3440 -selection_background #88C0D0 - -color0 #3B4252 -color1 #BF616A -color2 #A3BE8C -color3 #EBCB8B -color4 #81A1C1 -color5 #B48EAD -color6 #88C0D0 -color7 #E5E9F0 -color8 #4C566A -color9 #BF616A -color10 #A3BE8C -color11 #EBCB8B -color12 #81A1C1 -color13 #B48EAD -color14 #8FBCBB -color15 #ECEFF4 - -cursor #D8DEE9 -cursor_shape beam - -background_opacity 0.92 -window_padding_width 8 -confirm_os_window_close 0 - -tab_bar_style slant -active_tab_foreground #2E3440 -active_tab_background #A3BE8C -inactive_tab_foreground #D8DEE9 -inactive_tab_background #3B4252 diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/profile.d/raveos-fastfetch.sh b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/profile.d/raveos-fastfetch.sh deleted file mode 100644 index b3fe8ce..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/profile.d/raveos-fastfetch.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -if [[ -z "${RAVEOS_GREETED:-}" && -z "${VSCODE_PID:-}" && "${TERM}" != "dumb" ]]; then - export RAVEOS_GREETED=1 - - if command -v fastfetch >/dev/null 2>&1; then - if [[ "${TERM}" == "xterm-kitty" ]]; then - fastfetch --config "${HOME}/.config/fastfetch/config-kitty.jsonc" - else - fastfetch --config "${HOME}/.config/fastfetch/config.jsonc" - fi - fi -fi diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/astronaut.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/astronaut.conf deleted file mode 100644 index 7fa907e..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/astronaut.conf +++ /dev/null @@ -1,162 +0,0 @@ -[General] -#################### General #################### - -ScreenWidth="1920" -ScreenHeight="1080" -ScreenPadding="" -# Default 0, Options: from 0 to min(screen width/2,screen height/2). - -Font="Open Sans" -FontSize="13" -# Default is screen height divided by 80 (1080/80=13.5), Options: 0-inf. - -KeyboardSize="0.4" -# Default 0.4, Options 0.1-1.0 - -RoundCorners="20" - -Locale="" -# Locale for data and time format. I suggest leaving it blank. -HourFormat="HH:mm" -# Default Locale.ShortFormat. -DateFormat="dddd d MMMM" -# Default Locale.LongFormat. - -HeaderText="" -# You can put somehting fun. - -#################### Background #################### - -BackgroundPlaceholder="" -# Must be a relative path. -# Background displayed before the actual background is loaded. -# Use only if the background is a video, otherwise leave blank. -# Connected with: Background. -Background="Backgrounds/new-raveos-main-bg.jpeg" -# Must be a relative path. -# Supports: png, jpg, jpeg, webp, gif, avi, mp4, mov, mkv, m4v, webm. -BackgroundSpeed="" -# Default 1.0. Options: 0.0-10.0 (can go higher). -# Speed of animated wallpaper. -# Connected with: Background. -PauseBackground="" -# Default false. -# If set to true, stops playback of gifs. Works only with gifs. -# Connected with: Background. -DimBackground="0.0" -# Options: 0.0-1.0. -# Connected with: DimBackgroundColor -CropBackground="true" -# Default false. -# Crop or fit background. -# Connected with: BackgroundHorizontalAlignment and BackgroundVerticalAlignment dosn't work when set to true. -BackgroundHorizontalAlignment="center" -# Default: center, Options: left, center, right. -# Horizontal position of the background picture. -# Connected with: CropBackground must be set to false. -BackgroundVerticalAlignment="center" -# Horizontal position of the background picture. -# Default: center, Options: bottom, center, top. -# Connected with: CropBackground must be set to false. - -#################### Colors #################### - -HeaderTextColor="#ffffff" -DateTextColor="#ffffff" -TimeTextColor="#ffffff" - -FormBackgroundColor="#21222C" -BackgroundColor="#21222C" -DimBackgroundColor="#21222C" - -LoginFieldBackgroundColor="#222222" -PasswordFieldBackgroundColor="#222222" -LoginFieldTextColor="#ffffff" -PasswordFieldTextColor="#ffffff" -UserIconColor="#ffffff" -PasswordIconColor="#ffffff" - -PlaceholderTextColor="#bbbbbb" -WarningColor="#343746" - -LoginButtonTextColor="#ffffff" -LoginButtonBackgroundColor="#343746" -SystemButtonsIconsColor="#F8F8F2" -SessionButtonTextColor="#F8F8F2" -VirtualKeyboardButtonTextColor="#F8F8F2" - -DropdownTextColor="#ffffff" -DropdownSelectedBackgroundColor="#343746" -DropdownBackgroundColor="#21222C" - -HighlightTextColor="#bbbbbb" -HighlightBackgroundColor="#343746" -HighlightBorderColor="#343746" - -HoverUserIconColor="#b7cef1" -HoverPasswordIconColor="#b7cef1" -HoverSystemButtonsIconsColor="#b7cef1" -HoverSessionButtonTextColor="#b7cef1" -HoverVirtualKeyboardButtonTextColor="#b7cef1" - -#################### Form #################### - -PartialBlur="true" -# Default false. -FullBlur="" -# Default false. -# If you use FullBlur I recommend setting BlurMax to 64 and Blur to 1.0. -BlurMax="" -# Default 48, Options: 2-64 (can go higher because depends on Blur). -# Connected with: Blur. -Blur="" -# Default 2.0, Options: 0.0-3.0 (without 3.0). -# Connected with: BlurMax. - -HaveFormBackground="false" -# Form background is transparent if set to false. -# Connected with: PartialBlur and BackgroundColor. -FormPosition="center" -# Default: left, Options: left, center, right. - -#################### Virtual Keyboard #################### - -VirtualKeyboardPosition="center" -# Default: left, Options: left, center, right. - -#################### Interface Behavior #################### - -HideVirtualKeyboard="false" -HideSystemButtons="false" -HideLoginButton="false" - -ForceLastUser="true" -# If set to true last successfully logged in user appeares automatically in the username field. -PasswordFocus="true" -# Automaticaly focuses password field. -HideCompletePassword="true" -# Hides the password while typing. -AllowEmptyPassword="false" -# Enable login for users without a password. -AllowUppercaseLettersInUsernames="false" -# Do not change this! Uppercase letters are generally not allowed in usernames. This option is only for systems that differ from this standard! -BypassSystemButtonsChecks="false" -# Skips checking if sddm can perform shutdown, restart, suspend or hibernate, always displays all system buttons. -RightToLeftLayout="false" -# Revert the layout either because you would like the login to be on the right hand side or SDDM won't respect your language locale for some reason. This will reverse the current position of FormPosition if it is either left or right and in addition position some smaller elements on the right hand side of the form itself (also when FormPosition is set to center). - -#################### Translation #################### - -# These don't necessarily need to translate anything. You can enter whatever you want here. -TranslatePlaceholderUsername="" -TranslatePlaceholderPassword="" -TranslateLogin="" -TranslateLoginFailedWarning="" -TranslateCapslockWarning="" -TranslateSuspend="" -TranslateHibernate="" -TranslateReboot="" -TranslateShutdown="" -TranslateSessionSelection="" -TranslateVirtualKeyboardButtonOn="" -TranslateVirtualKeyboardButtonOff="" diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg deleted file mode 100644 index 5945d58..0000000 Binary files a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg and /dev/null differ diff --git a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/sddm.conf b/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/sddm.conf deleted file mode 100644 index 29b5b95..0000000 --- a/raveos-theme/hyprland/build/raveos-hyprland-theme/pkg/raveos-hyprland-theme/usr/share/raveos/hyprland-theme/theme-data/sddm/sddm.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Theme] -Current = sddm-astronaut-theme diff --git a/raveos-theme/hyprland/metadata.json b/raveos-theme/hyprland/metadata.json deleted file mode 100644 index 22a1b21..0000000 --- a/raveos-theme/hyprland/metadata.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "Rave Hyprland", - "version": "1.1", - "description": "Hyprland tiling WM with DankMaterialShell, green theme, blur effects", - "de": "hyprland", - "wallpaper": "new-raveos-main-bg.jpeg", - "archive": "theme-data.tar.gz", - "config_paths": { - "hypr": "hypr", - "DankMaterialShell": "DankMaterialShell" - }, - "sddm": { - "config": "sddm/sddm.conf", - "theme_config": "sddm/astronaut.conf", - "background": "sddm/new-raveos-main-bg.jpeg" - }, - "user_icons": { - "Adwaitaru-olive": "user-icons/Adwaitaru-olive" - }, - "user_themes": { - "Yaru-olive-dark": "user-themes/Yaru-olive-dark" - }, - "terminal": { - "packages": ["fastfetch", "kitty"], - "fastfetch_config": "fastfetch/config.jsonc", - "fastfetch_kitty_config": "fastfetch/config-kitty.jsonc", - "fastfetch_logo_txt": "fastfetch/raveos-logo.txt", - "fastfetch_logo_png": "fastfetch/raveos-logo.png", - "kitty_config": "kitty/kitty.conf", - "profile_script": "profile.d/raveos-fastfetch.sh" - }, - "dependencies": [ - "hyprland", - "kitty", - "thunar", - "dankmaterialshell", - "hyprswitch", - "polkit-gnome", - "wl-clipboard", - "cliphist", - "kwallet-pam", - "qt6ct", - "kvantum", - "playerctl", - "brightnessctl", - "wireplumber", - "xdg-desktop-portal-hyprland" - ] -} diff --git a/raveos-theme/hyprland/new-raveos-main-bg.jpeg b/raveos-theme/hyprland/new-raveos-main-bg.jpeg deleted file mode 100644 index 5945d58..0000000 Binary files a/raveos-theme/hyprland/new-raveos-main-bg.jpeg and /dev/null differ diff --git a/raveos-theme/hyprland/raveos-hyprland-apply.sh b/raveos-theme/hyprland/raveos-hyprland-apply.sh deleted file mode 100644 index 26957a1..0000000 --- a/raveos-theme/hyprland/raveos-hyprland-apply.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -payload_dir="/usr/share/raveos/hyprland-theme/theme-data" - -if [[ ! -d "$payload_dir" ]]; then - echo "Missing payload: $payload_dir" >&2 - exit 1 -fi - -if [[ ${EUID} -ne 0 ]]; then - echo "Run as root." >&2 - exit 1 -fi - -mkdir -p /etc/skel/.config/hypr -if [[ -d "${payload_dir}/hypr" ]]; then - cp -rf "${payload_dir}/hypr/." /etc/skel/.config/hypr/ -fi -mkdir -p /etc/skel/.config/dms -mkdir -p /etc/skel/.config/matugen -mkdir -p /etc/skel/.config/kitty -mkdir -p /etc/skel/.config/fastfetch -mkdir -p /etc/skel/.config/quickshell/pockets/DMS - -if [[ -d "${payload_dir}/DankMaterialShell/quickshell" ]]; then - cp -r "${payload_dir}/DankMaterialShell/quickshell/." /etc/skel/.config/quickshell/pockets/DMS/ - cp -r "${payload_dir}/DankMaterialShell/quickshell/." /etc/skel/.config/dms/ - if [[ -d "${payload_dir}/DankMaterialShell/quickshell/matugen/configs" ]]; then - cp -r "${payload_dir}/DankMaterialShell/quickshell/matugen/configs/." /etc/skel/.config/matugen/ - fi -fi - -if [[ -f "${payload_dir}/fastfetch/config.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config.jsonc" /etc/skel/.config/fastfetch/config.jsonc -fi - -if [[ -f "${payload_dir}/fastfetch/config-kitty.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config-kitty.jsonc" /etc/skel/.config/fastfetch/config-kitty.jsonc -fi - -if [[ -f "${payload_dir}/fastfetch/raveos-logo.png" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.png" /etc/skel/.config/fastfetch/raveos-logo.png -fi - -if [[ -f "${payload_dir}/fastfetch/raveos-logo.txt" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.txt" /etc/skel/.config/fastfetch/raveos-logo.txt -fi - -if [[ -f "${payload_dir}/profile.d/raveos-fastfetch.sh" ]]; then - install -Dm755 "${payload_dir}/profile.d/raveos-fastfetch.sh" /etc/profile.d/raveos-fastfetch.sh -fi - -if [[ -d "${payload_dir}/skel" ]]; then - cp -r --no-preserve=ownership "${payload_dir}/skel/." /etc/skel/ -fi - -if [[ -f "${payload_dir}/background" ]]; then - mkdir -p /usr/share/backgrounds/raveos - install -m644 "${payload_dir}/background" /usr/share/backgrounds/raveos/raveos-main-bg.jpeg - install -Dm644 "${payload_dir}/background" /etc/skel/.config/background -fi - -if [[ -f "${payload_dir}/sddm/sddm.conf" ]]; then - install -Dm644 "${payload_dir}/sddm/sddm.conf" /etc/sddm.conf.d/raveos-theme.conf -fi - -for candidate in \ - "/usr/share/sddm/themes/sddm-astronaut-theme" \ - "/usr/share/sddm/themes/astronaut" \ - "/usr/share/sddm/themes/sddm-astronaut"; do - if [[ -d "$candidate" ]]; then - if [[ -f "${payload_dir}/sddm/new-raveos-main-bg.jpeg" ]]; then - install -Dm644 "${payload_dir}/sddm/new-raveos-main-bg.jpeg" \ - "${candidate}/Backgrounds/new-raveos-main-bg.jpeg" - fi - if [[ -f "${payload_dir}/sddm/astronaut.conf" ]]; then - install -Dm644 "${payload_dir}/sddm/astronaut.conf" \ - "${candidate}/Themes/astronaut.conf" - fi - break - fi -done - -while IFS=: read -r user _ uid gid _ home shell; do - [[ "$uid" -ge 1000 ]] || continue - [[ -d "$home" ]] || continue - [[ "$shell" != "/usr/bin/nologin" && "$shell" != "/bin/false" ]] || continue - mkdir -p "${home}/.config/hypr" "${home}/.config/quickshell/pockets/DMS" "${home}/.config/dms" "${home}/.config/matugen" "${home}/.config/kitty" "${home}/.config/fastfetch" - if [[ -d "${payload_dir}/hypr" ]]; then - cp -rf "${payload_dir}/hypr/." "${home}/.config/hypr/" - fi - if [[ -d "${payload_dir}/DankMaterialShell/quickshell" ]]; then - cp -r "${payload_dir}/DankMaterialShell/quickshell/." "${home}/.config/quickshell/pockets/DMS/" - cp -r "${payload_dir}/DankMaterialShell/quickshell/." "${home}/.config/dms/" - if [[ -d "${payload_dir}/DankMaterialShell/quickshell/matugen/configs" ]]; then - cp -r "${payload_dir}/DankMaterialShell/quickshell/matugen/configs/." "${home}/.config/matugen/" - fi - fi - - if [[ -d "${payload_dir}/skel" ]]; then - cp -r --no-preserve=ownership "${payload_dir}/skel/." "$home/" - fi - if [[ -f "${payload_dir}/background" ]]; then - install -Dm644 "${payload_dir}/background" "${home}/.config/background" - fi - if [[ -f "${payload_dir}/kitty/kitty.conf" ]]; then - install -Dm644 "${payload_dir}/kitty/kitty.conf" "${home}/.config/kitty/kitty.conf" - fi - if [[ -f "${payload_dir}/fastfetch/config.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config.jsonc" "${home}/.config/fastfetch/config.jsonc" - fi - if [[ -f "${payload_dir}/fastfetch/config-kitty.jsonc" ]]; then - install -Dm644 "${payload_dir}/fastfetch/config-kitty.jsonc" "${home}/.config/fastfetch/config-kitty.jsonc" - fi - if [[ -f "${payload_dir}/fastfetch/raveos-logo.png" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.png" "${home}/.config/fastfetch/raveos-logo.png" - fi - if [[ -f "${payload_dir}/fastfetch/raveos-logo.txt" ]]; then - install -Dm644 "${payload_dir}/fastfetch/raveos-logo.txt" "${home}/.config/fastfetch/raveos-logo.txt" - fi - if [[ -f "${payload_dir}/hypr/scripts/raveos-monitor-setup.sh" ]]; then - bash "${payload_dir}/hypr/scripts/raveos-monitor-setup.sh" --hypr-dir "${home}/.config/hypr" - fi - chown -R "${uid}:${gid}" "$home" -done < /etc/passwd - -echo "Automatic apply finished." diff --git a/raveos-theme/hyprland/raveos-hyprland-theme-apply.service b/raveos-theme/hyprland/raveos-hyprland-theme-apply.service deleted file mode 100644 index 7c630f2..0000000 --- a/raveos-theme/hyprland/raveos-hyprland-theme-apply.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Apply RaveOS Hyprland theme payload -After=local-fs.target systemd-user-sessions.service -ConditionPathExists=!/var/lib/raveos-hyprland-theme/.applied - -[Service] -Type=oneshot -ExecStart=/usr/lib/raveos-hyprland-theme/auto-apply.sh -ExecStartPost=/usr/bin/install -Dm644 /dev/null /var/lib/raveos-hyprland-theme/.applied - -[Install] -WantedBy=multi-user.target diff --git a/raveos-theme/hyprland/raveos-hyprland-theme.install b/raveos-theme/hyprland/raveos-hyprland-theme.install deleted file mode 100644 index 876a411..0000000 --- a/raveos-theme/hyprland/raveos-hyprland-theme.install +++ /dev/null @@ -1,7 +0,0 @@ -post_install() { - : -} - -post_upgrade() { - : -} diff --git a/raveos-theme/hyprland/theme-data.tar.gz b/raveos-theme/hyprland/theme-data.tar.gz deleted file mode 100644 index 4d471ff..0000000 Binary files a/raveos-theme/hyprland/theme-data.tar.gz and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/.changelog-1.2 b/raveos-theme/hyprland/theme-data/DankMaterialShell/.changelog-1.2 deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/.firstlaunch b/raveos-theme/hyprland/theme-data/DankMaterialShell/.firstlaunch deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/Makefile b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/Makefile deleted file mode 100644 index cad9b95..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/Makefile +++ /dev/null @@ -1,163 +0,0 @@ -BINARY_NAME=dms -BINARY_NAME_INSTALL=dankinstall -SOURCE_DIR=cmd/dms -SOURCE_DIR_INSTALL=cmd/dankinstall -BUILD_DIR=bin -PREFIX ?= /usr/local -INSTALL_DIR=$(PREFIX)/bin - -GO=go -GOFLAGS=-ldflags="-s -w" - -# Version and build info -BASE_VERSION=$(shell git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.0.0") -COMMIT_COUNT=$(shell git rev-list --count HEAD 2>/dev/null || echo "0") -COMMIT_HASH=$(shell git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown") -VERSION?=$(BASE_VERSION)+git$(COMMIT_COUNT).$(COMMIT_HASH) -BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S') -COMMIT?=$(COMMIT_HASH) - -BUILD_LDFLAGS=-ldflags='-s -w -X main.Version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.commit=$(COMMIT)' - -# Architecture to build for dist target (amd64, arm64, or all) -ARCH ?= all - -.PHONY: all build dankinstall dist clean install install-all install-dankinstall uninstall uninstall-all uninstall-dankinstall install-config uninstall-config test fmt vet deps print-version help - -# Default target -all: build - -# Build the main binary (dms) -build: - @echo "Building $(BINARY_NAME)..." - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=0 $(GO) build $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) ./$(SOURCE_DIR) - @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)" - -dankinstall: - @echo "Building $(BINARY_NAME_INSTALL)..." - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=0 $(GO) build $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME_INSTALL) ./$(SOURCE_DIR_INSTALL) - @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME_INSTALL)" - -# Build distro binaries for amd64 and arm64 (Linux only, no update/greeter support) -dist: -ifeq ($(ARCH),all) - @echo "Building $(BINARY_NAME) for distribution (amd64 and arm64)..." - @mkdir -p $(BUILD_DIR) - @echo "Building for linux/amd64..." - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(SOURCE_DIR) - @echo "Building for linux/arm64..." - CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(SOURCE_DIR) - @echo "Distribution builds complete:" - @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64" - @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64" -else - @echo "Building $(BINARY_NAME) for distribution ($(ARCH))..." - @mkdir -p $(BUILD_DIR) - @echo "Building for linux/$(ARCH)..." - CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-$(ARCH) ./$(SOURCE_DIR) - @echo "Distribution build complete:" - @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-$(ARCH)" -endif - -build-all: build dankinstall - -install: - @echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..." - @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME) - @echo "Installation complete" - -install-all: - @echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..." - @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME) - @echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..." - @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL) - @echo "Installation complete" - -install-dankinstall: - @echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..." - @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL) - @echo "Installation complete" - -uninstall: - @echo "Uninstalling $(BINARY_NAME) from $(INSTALL_DIR)..." - @rm -f $(INSTALL_DIR)/$(BINARY_NAME) - @echo "Uninstall complete" - -uninstall-all: - @echo "Uninstalling $(BINARY_NAME) from $(INSTALL_DIR)..." - @rm -f $(INSTALL_DIR)/$(BINARY_NAME) - @echo "Uninstalling $(BINARY_NAME_INSTALL) from $(INSTALL_DIR)..." - @rm -f $(INSTALL_DIR)/$(BINARY_NAME_INSTALL) - @echo "Uninstall complete" - -uninstall-dankinstall: - @echo "Uninstalling $(BINARY_NAME_INSTALL) from $(INSTALL_DIR)..." - @rm -f $(INSTALL_DIR)/$(BINARY_NAME_INSTALL) - @echo "Uninstall complete" - -clean: - @echo "Cleaning build artifacts..." - @rm -rf $(BUILD_DIR) - @echo "Clean complete" - -test: - @echo "Running tests..." - $(GO) test -v ./... - -fmt: - @echo "Formatting Go code..." - $(GO) fmt ./... - -vet: - @echo "Running go vet..." - $(GO) vet ./... - -deps: - @echo "Updating dependencies..." - $(GO) mod tidy - $(GO) mod download - -dev: - @echo "Building $(BINARY_NAME) for development..." - @mkdir -p $(BUILD_DIR) - $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) ./$(SOURCE_DIR) - @echo "Development build complete: $(BUILD_DIR)/$(BINARY_NAME)" - -check-go: - @echo "Checking Go version..." - @go version | grep -E "go1\.(2[2-9]|[3-9][0-9])" > /dev/null || (echo "ERROR: Go 1.22 or higher required" && exit 1) - @echo "Go version OK" - -version: check-go - @echo "Version: $(VERSION)" - @echo "Build Time: $(BUILD_TIME)" - @echo "Commit: $(COMMIT)" - -print-version: - @echo "$(VERSION)" - -help: - @echo "Available targets:" - @echo " all - Build the main binary (dms) (default)" - @echo " build - Build the main binary (dms)" - @echo " dankinstall - Build dankinstall binary" - @echo " dist - Build dms for linux amd64/arm64 (no update/greeter)" - @echo " Use ARCH=amd64 or ARCH=arm64 to build only one" - @echo " build-all - Build both binaries" - @echo " install - Install dms to $(INSTALL_DIR)" - @echo " install-all - Install both dms and dankinstall to $(INSTALL_DIR)" - @echo " install-dankinstall - Install only dankinstall to $(INSTALL_DIR)" - @echo " uninstall - Remove dms from $(INSTALL_DIR)" - @echo " uninstall-all - Remove both binaries from $(INSTALL_DIR)" - @echo " uninstall-dankinstall - Remove only dankinstall from $(INSTALL_DIR)" - @echo " clean - Clean build artifacts" - @echo " test - Run tests" - @echo " fmt - Format Go code" - @echo " vet - Run go vet" - @echo " deps - Update dependencies" - @echo " dev - Build with debug info" - @echo " check-go - Check Go version compatibility" - @echo " version - Show version information" - @echo " help - Show this help message" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/README.md deleted file mode 100644 index fed5bfa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/README.md +++ /dev/null @@ -1,217 +0,0 @@ -# DMS Backend & CLI - -Go-based backend for DankMaterialShell providing system integration, IPC, and installation tools. - -**See [root README](../README.md) for project overview and installation.** - -## Components - -**dms CLI** -Command-line interface and daemon for shell management and system control. - -**dankinstall** -Distribution-aware installer for deploying DMS and compositor configurations on Arch, Fedora, Debian, Ubuntu, openSUSE, and Gentoo. Supports both an interactive TUI and a headless (unattended) mode via CLI flags. - -## System Integration - -### Wayland Protocols (Client) - -All Wayland protocols are consumed as a client - connecting to the compositor. - -| Protocol | Purpose | -| ----------------------------------------- | ----------------------------------------------------------- | -| `wlr-gamma-control-unstable-v1` | Night mode color temperature control | -| `wlr-screencopy-unstable-v1` | Screen capture for color picker/screenshot | -| `wlr-layer-shell-unstable-v1` | Overlay surfaces for color picker UI/screenshot | -| `wlr-output-management-unstable-v1` | Display configuration | -| `wlr-output-power-management-unstable-v1` | DPMS on/off CLI | -| `wp-viewporter` | Fractional scaling support (color picker/screenshot UIs) | -| `keyboard-shortcuts-inhibit-unstable-v1` | Inhibit compositor shortcuts during color picker/screenshot | -| `ext-data-control-v1` | Clipboard history and persistence | -| `ext-workspace-v1` | Workspace integration | -| `dwl-ipc-unstable-v2` | dwl/MangoWC IPC for tags, outputs, etc. | - -### DBus Interfaces - -**Client (consuming external services):** - -| Interface | Purpose | -| -------------------------------- | --------------------------------------------- | -| `org.bluez` | Bluetooth management with pairing agent | -| `org.freedesktop.NetworkManager` | Network management | -| `net.connman.iwd` | iwd Wi-Fi backend | -| `org.freedesktop.network1` | systemd-networkd integration | -| `org.freedesktop.login1` | Session control, sleep inhibitors, brightness | -| `org.freedesktop.Accounts` | User account information | -| `org.freedesktop.portal.Desktop` | Desktop appearance settings (color scheme) | -| CUPS via IPP + D-Bus | Printer management with job notifications | - -**Server (implementing interfaces):** - -| Interface | Purpose | -| ----------------------------- | -------------------------------------- | -| `org.freedesktop.ScreenSaver` | Screensaver inhibit for video playback | - -Custom IPC via unix socket (JSON API) for shell communication. - -### Hardware Control - -| Subsystem | Method | Purpose | -| --------- | ------------------- | ---------------------------------- | -| DDC/CI | I2C direct | External monitor brightness | -| Backlight | logind or sysfs | Internal display brightness | -| evdev | `/dev/input/event*` | Keyboard state (caps lock LED) | -| udev | netlink monitor | Backlight device updates (for OSD) | - -### Plugin System - -- Plugin registry integration -- Plugin lifecycle management -- Settings persistence - -## CLI Commands - -- `dms run [-d]` - Start shell (optionally as daemon) -- `dms restart` / `dms kill` - Manage running processes -- `dms ipc ` - Send IPC commands (toggle launcher, notifications, etc.) -- `dms plugins [install|browse|search]` - Plugin management -- `dms brightness [list|set]` - Control display/monitor brightness -- `dms color pick` - Native color picker (see below) -- `dms update` - Update DMS and dependencies (disabled in distro packages) -- `dms greeter install` - Install greetd greeter (disabled in distro packages) - -### Color Picker - -Native Wayland color picker with magnifier, no external dependencies. Supports HiDPI and fractional scaling. - -```bash -dms color pick # Pick color, output hex -dms color pick --rgb # Output as RGB (255 128 64) -dms color pick --hsv # Output as HSV (24 75% 100%) -dms color pick --json # Output all formats as JSON -dms color pick -a # Auto-copy to clipboard -``` - -The on-screen preview displays the selected format. JSON output includes hex, RGB, HSL, HSV, and CMYK values. - -## Building - -Requires Go 1.25+ - -**Development build:** - -```bash -make # Build dms CLI -make dankinstall # Build installer -make test # Run tests -``` - -**Distribution build:** - -```bash -make dist # Build without update/greeter features -``` - -Produces `bin/dms-linux-amd64` and `bin/dms-linux-arm64` - -**Installation:** - -```bash -sudo make install # Install to /usr/local/bin/dms -``` - -## Development - -**Setup pre-commit hooks:** - -```bash -git config core.hooksPath .githooks -``` - -This runs gofmt, golangci-lint, tests, and builds before each commit when `core/` files are staged. - -**Regenerating Wayland Protocol Bindings:** - -```bash -go install github.com/rajveermalviya/go-wayland/cmd/go-wayland-scanner@latest -go-wayland-scanner -i internal/proto/xml/wlr-gamma-control-unstable-v1.xml \ - -pkg wlr_gamma_control -o internal/proto/wlr_gamma_control/gamma_control.go -``` - -**Module Structure:** - -- `cmd/` - Binary entrypoints (dms, dankinstall) -- `internal/distros/` - Distribution-specific installation logic -- `internal/proto/` - Wayland protocol bindings -- `pkg/` - Shared packages - -## Installation via dankinstall - -**Interactive (TUI):** - -```bash -curl -fsSL https://install.danklinux.com | sh -``` - -**Headless (unattended):** - -Headless mode requires cached sudo credentials. Run `sudo -v` first: - -```bash -sudo -v && curl -fsSL https://install.danklinux.com | sh -s -- -c niri -t ghostty -y -sudo -v && curl -fsSL https://install.danklinux.com | sh -s -- -c hyprland -t kitty --include-deps dms-greeter -y -``` - -| Flag | Short | Description | -|------|-------|-------------| -| `--compositor ` | `-c` | Compositor/WM to install (required for headless) | -| `--term ` | `-t` | Terminal emulator (required for headless) | -| `--include-deps ` | | Enable optional dependencies (e.g. `dms-greeter`) | -| `--exclude-deps ` | | Skip specific dependencies | -| `--replace-configs ` | | Replace specific configuration files (mutually exclusive with `--replace-configs-all`) | -| `--replace-configs-all` | | Replace all configuration files (mutually exclusive with `--replace-configs`) | -| `--yes` | `-y` | Required for headless mode — confirms installation without interactive prompts | - -Headless mode requires `--yes` to proceed; without it, the installer exits with an error. -Configuration files are not replaced by default unless `--replace-configs` or `--replace-configs-all` is specified. -`dms-greeter` is disabled by default; use `--include-deps dms-greeter` to enable it. - -When no flags are provided, `dankinstall` launches the interactive TUI. - -### Headless mode validation rules - -Headless mode activates when `--compositor` or `--term` is provided. - -- Both `--compositor` and `--term` are required; providing only one results in an error. -- Headless-only flags (`--include-deps`, `--exclude-deps`, `--replace-configs`, `--replace-configs-all`, `--yes`) are rejected in TUI mode. -- Positional arguments are not accepted. - -### Log file location - -`dankinstall` writes logs to `/tmp` by default. -Set the `DANKINSTALL_LOG_DIR` environment variable to override the log directory. - -## Supported Distributions - -Arch, Fedora, Debian, Ubuntu, openSUSE, Gentoo (and derivatives) - -**Arch Linux** -Uses `pacman` for system packages, builds AUR packages via `makepkg`, no AUR helper dependency. - -**Fedora** - -Uses COPR repositories (`avengemedia/danklinux`, `avengemedia/dms`). - -**Ubuntu** -Requires PPA support. Most packages built from source (slow first install). - -**Debian** -Debian 13+ (Trixie). niri only, no Hyprland support. Builds from source. - -**openSUSE** -Most packages available in standard repos. Minimal building required. - -**Gentoo** -Uses Portage with GURU overlay. Automatically configures USE flags. Variable success depending on system configuration. - -See installer output for distribution-specific details during installation. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/dank.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/dank.svg deleted file mode 100644 index 3b4b334..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/dank.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/danklogo.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/danklogo.svg deleted file mode 100644 index 1ee6d51..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/assets/danklogo.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/build_dankinstall.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/build_dankinstall.sh deleted file mode 100755 index c430e73..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/build_dankinstall.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# Colors for output -GREEN='\033[0;32m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Get latest version tag -VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") - -echo -e "${GREEN}Building dankinstall ${VERSION}${NC}" - -# Create bin directory if it doesn't exist -mkdir -p bin - -# Build for each architecture -for ARCH in amd64 arm64; do - echo -e "${BLUE}Building for ${ARCH}...${NC}" - - cd cmd/dankinstall - GOOS=linux CGO_ENABLED=0 GOARCH=${ARCH} \ - go build -trimpath -ldflags "-s -w -X main.Version=${VERSION}" \ - -o ../../bin/dankinstall-${ARCH} - cd ../.. - - # Compress - gzip -9 -k -f bin/dankinstall-${ARCH} - - # Generate checksum - (cd bin && sha256sum dankinstall-${ARCH}.gz > dankinstall-${ARCH}.gz.sha256) - - echo -e "${GREEN}✓ Built bin/dankinstall-${ARCH}.gz${NC}" -done - -echo -e "${GREEN}Done! Files ready in bin/:${NC}" -ls -lh bin/dankinstall-* diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dankinstall/main.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dankinstall/main.go deleted file mode 100644 index 042506e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dankinstall/main.go +++ /dev/null @@ -1,219 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/headless" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/tui" - tea "github.com/charmbracelet/bubbletea" - "github.com/spf13/cobra" -) - -var Version = "dev" - -// Flag variables bound via pflag -var ( - compositor string - term string - includeDeps []string - excludeDeps []string - replaceConfigs []string - replaceConfigsAll bool - yes bool -) - -var rootCmd = &cobra.Command{ - Use: "dankinstall", - Short: "Install DankMaterialShell and its dependencies", - Long: `dankinstall sets up DankMaterialShell with your chosen compositor and terminal. - -Without flags, it launches an interactive TUI. Providing either --compositor -or --term activates headless (unattended) mode, which requires both flags. - -Headless mode requires cached sudo credentials. Run 'sudo -v' beforehand, or -configure passwordless sudo for your user.`, - Args: cobra.NoArgs, - RunE: runDankinstall, - SilenceErrors: true, - SilenceUsage: true, -} - -func init() { - rootCmd.Flags().StringVarP(&compositor, "compositor", "c", "", "Compositor/WM to install: niri or hyprland (enables headless mode)") - rootCmd.Flags().StringVarP(&term, "term", "t", "", "Terminal emulator to install: ghostty, kitty, or alacritty (enables headless mode)") - rootCmd.Flags().StringSliceVar(&includeDeps, "include-deps", []string{}, "Optional deps to enable (e.g. dms-greeter)") - rootCmd.Flags().StringSliceVar(&excludeDeps, "exclude-deps", []string{}, "Deps to skip during installation") - rootCmd.Flags().StringSliceVar(&replaceConfigs, "replace-configs", []string{}, "Deploy only named configs (e.g. niri,ghostty)") - rootCmd.Flags().BoolVar(&replaceConfigsAll, "replace-configs-all", false, "Deploy and replace all configurations") - rootCmd.Flags().BoolVarP(&yes, "yes", "y", false, "Auto-confirm all prompts") -} - -func main() { - if os.Getuid() == 0 { - fmt.Fprintln(os.Stderr, "Error: dankinstall must not be run as root") - os.Exit(1) - } - - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } -} - -func runDankinstall(cmd *cobra.Command, args []string) error { - headlessMode := compositor != "" || term != "" - - if !headlessMode { - // Reject headless-only flags when running in TUI mode. - headlessOnly := []string{ - "include-deps", - "exclude-deps", - "replace-configs", - "replace-configs-all", - "yes", - } - var set []string - for _, name := range headlessOnly { - if cmd.Flags().Changed(name) { - set = append(set, "--"+name) - } - } - if len(set) > 0 { - return fmt.Errorf("flags %s are only valid in headless mode (requires both --compositor and --term)", strings.Join(set, ", ")) - } - } - - if headlessMode { - return runHeadless() - } - return runTUI() -} - -func runHeadless() error { - // Validate required flags - if compositor == "" { - return fmt.Errorf("--compositor is required for headless mode (niri or hyprland)") - } - if term == "" { - return fmt.Errorf("--term is required for headless mode (ghostty, kitty, or alacritty)") - } - - cfg := headless.Config{ - Compositor: compositor, - Terminal: term, - IncludeDeps: includeDeps, - ExcludeDeps: excludeDeps, - ReplaceConfigs: replaceConfigs, - ReplaceConfigsAll: replaceConfigsAll, - Yes: yes, - } - - runner := headless.NewRunner(cfg) - - // Set up file logging - fileLogger, err := log.NewFileLogger() - if err != nil { - fmt.Fprintf(os.Stderr, "Warning: Failed to create log file: %v\n", err) - } - - if fileLogger != nil { - fmt.Printf("Logging to: %s\n", fileLogger.GetLogPath()) - fileLogger.StartListening(runner.GetLogChan()) - defer func() { - if err := fileLogger.Close(); err != nil { - fmt.Fprintf(os.Stderr, "Warning: Failed to close log file: %v\n", err) - } - }() - } else { - // Drain the log channel to prevent blocking sends from deadlocking - // downstream components (distros, config deployer) that write to it. - // Use an explicit stop signal because this code does not own the - // runner log channel and cannot assume it will be closed. - defer drainLogChan(runner.GetLogChan())() - } - - if err := runner.Run(); err != nil { - if fileLogger != nil { - fmt.Fprintf(os.Stderr, "\nFull logs are available at: %s\n", fileLogger.GetLogPath()) - } - return err - } - - if fileLogger != nil { - fmt.Printf("\nFull logs are available at: %s\n", fileLogger.GetLogPath()) - } - return nil -} - -func runTUI() error { - fileLogger, err := log.NewFileLogger() - if err != nil { - fmt.Printf("Warning: Failed to create log file: %v\n", err) - fmt.Println("Continuing without file logging...") - } - - logFilePath := "" - if fileLogger != nil { - logFilePath = fileLogger.GetLogPath() - fmt.Printf("Logging to: %s\n", logFilePath) - defer func() { - if err := fileLogger.Close(); err != nil { - fmt.Printf("Warning: Failed to close log file: %v\n", err) - } - }() - } - - model := tui.NewModel(Version, logFilePath) - - if fileLogger != nil { - fileLogger.StartListening(model.GetLogChan()) - } else { - // Drain the log channel to prevent blocking sends from deadlocking - // downstream components (distros, config deployer) that write to it. - // Use an explicit stop signal because this code does not own the - // model log channel and cannot assume it will be closed. - defer drainLogChan(model.GetLogChan())() - } - - p := tea.NewProgram(model, tea.WithAltScreen()) - if _, err := p.Run(); err != nil { - if logFilePath != "" { - fmt.Fprintf(os.Stderr, "\nFull logs are available at: %s\n", logFilePath) - } - return fmt.Errorf("error running program: %w", err) - } - - if logFilePath != "" { - fmt.Printf("\nFull logs are available at: %s\n", logFilePath) - } - return nil -} - -// drainLogChan starts a goroutine that discards all messages from logCh, -// preventing blocking sends from deadlocking downstream components. It returns -// a cleanup function that signals the goroutine to stop and waits for it to -// exit. Callers should defer the returned function. -func drainLogChan(logCh <-chan string) func() { - drainStop := make(chan struct{}) - drainDone := make(chan struct{}) - go func() { - defer close(drainDone) - for { - select { - case <-drainStop: - return - case _, ok := <-logCh: - if !ok { - return - } - } - } - }() - return func() { - close(drainStop) - <-drainDone - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/assets/cli-policy.default.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/assets/cli-policy.default.json deleted file mode 100644 index de9b8ad..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/assets/cli-policy.default.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "policy_version": 1, - "blocked_commands": [ - "greeter install", - "greeter enable", - "greeter uninstall", - "setup" - ], - "message": "This command is disabled on immutable/image-based systems. Use your distro-native workflow for system-level changes." -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_auth.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_auth.go deleted file mode 100644 index 727700e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_auth.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - sharedpam "github.com/AvengeMedia/DankMaterialShell/core/internal/pam" - "github.com/spf13/cobra" -) - -var authCmd = &cobra.Command{ - Use: "auth", - Short: "Manage DMS authentication sync", - Long: "Manage shared PAM/authentication setup for DMS greeter and lock screen", -} - -var authSyncCmd = &cobra.Command{ - Use: "sync", - Short: "Sync DMS authentication configuration", - Long: "Apply shared PAM/authentication changes for the lock screen and greeter based on current DMS settings", - Run: func(cmd *cobra.Command, args []string) { - yes, _ := cmd.Flags().GetBool("yes") - term, _ := cmd.Flags().GetBool("terminal") - if term { - if err := syncAuthInTerminal(yes); err != nil { - log.Fatalf("Error launching auth sync in terminal: %v", err) - } - return - } - if err := syncAuth(yes); err != nil { - log.Fatalf("Error syncing authentication: %v", err) - } - }, -} - -func init() { - authSyncCmd.Flags().BoolP("yes", "y", false, "Non-interactive mode: skip prompts") - authSyncCmd.Flags().BoolP("terminal", "t", false, "Run auth sync in a new terminal (for entering sudo password)") -} - -func syncAuth(nonInteractive bool) error { - if !nonInteractive { - fmt.Println("=== DMS Authentication Sync ===") - fmt.Println() - } - - logFunc := func(msg string) { - fmt.Println(msg) - } - - if err := sharedpam.SyncAuthConfig(logFunc, "", sharedpam.SyncAuthOptions{}); err != nil { - return err - } - - if !nonInteractive { - fmt.Println("\n=== Authentication Sync Complete ===") - fmt.Println("\nAuthentication changes have been applied.") - } - - return nil -} - -func syncAuthInTerminal(nonInteractive bool) error { - syncFlags := make([]string, 0, 1) - if nonInteractive { - syncFlags = append(syncFlags, "--yes") - } - - shellSyncCmd := "dms auth sync" - if len(syncFlags) > 0 { - shellSyncCmd += " " + strings.Join(syncFlags, " ") - } - shellCmd := shellSyncCmd + `; echo; echo "Authentication sync finished. Closing in 3 seconds..."; sleep 3` - return runCommandInTerminal(shellCmd) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_blur.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_blur.go deleted file mode 100644 index d01eb93..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_blur.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/blur" - "github.com/spf13/cobra" -) - -var blurCmd = &cobra.Command{ - Use: "blur", - Short: "Background blur utilities", -} - -var blurCheckCmd = &cobra.Command{ - Use: "check", - Short: "Check if the compositor supports background blur (ext-background-effect-v1)", - Args: cobra.NoArgs, - Run: runBlurCheck, -} - -func init() { - blurCmd.AddCommand(blurCheckCmd) -} - -func runBlurCheck(cmd *cobra.Command, args []string) { - supported, err := blur.ProbeSupport() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - switch supported { - case true: - fmt.Println("supported") - default: - fmt.Println("unsupported") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_brightness.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_brightness.go deleted file mode 100644 index 0f73493..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_brightness.go +++ /dev/null @@ -1,311 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness" - "github.com/spf13/cobra" -) - -var brightnessCmd = &cobra.Command{ - Use: "brightness", - Short: "Control device brightness", - Long: "Control brightness for backlight and LED devices (use --ddc to include DDC/I2C monitors)", -} - -var brightnessListCmd = &cobra.Command{ - Use: "list", - Short: "List all brightness devices", - Long: "List all available brightness devices with their current values", - Run: runBrightnessList, -} - -var brightnessSetCmd = &cobra.Command{ - Use: "set ", - Short: "Set brightness for a device", - Long: "Set brightness percentage (0-100) for a specific device", - Args: cobra.ExactArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - includeDDC, _ := cmd.Flags().GetBool("ddc") - return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp - }, - Run: runBrightnessSet, -} - -var brightnessGetCmd = &cobra.Command{ - Use: "get ", - Short: "Get brightness for a device", - Long: "Get current brightness percentage for a specific device", - Args: cobra.ExactArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - includeDDC, _ := cmd.Flags().GetBool("ddc") - return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp - }, - Run: runBrightnessGet, -} - -func init() { - brightnessListCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") - brightnessSetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") - brightnessSetCmd.Flags().Bool("exponential", false, "Use exponential brightness scaling") - brightnessSetCmd.Flags().Float64("exponent", 1.2, "Exponent for exponential scaling (default 1.2)") - brightnessGetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") - - brightnessCmd.SetHelpTemplate(`{{.Long}} - -Usage: - {{.UseLine}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -`) - - brightnessListCmd.SetHelpTemplate(`{{.Long}} - -Usage: - {{.UseLine}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} -`) - - brightnessSetCmd.SetHelpTemplate(`{{.Long}} - -Usage: - {{.UseLine}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} -`) - - brightnessGetCmd.SetHelpTemplate(`{{.Long}} - -Usage: - {{.UseLine}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} -`) - - brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd) -} - -func getAllBrightnessDevices(includeDDC bool) []brightness.Device { - allDevices := []brightness.Device{} - - sysfs, err := brightness.NewSysfsBackend() - if err != nil { - log.Debugf("Failed to initialize sysfs backend: %v", err) - } else { - devices, err := sysfs.GetDevices() - if err != nil { - log.Debugf("Failed to get sysfs devices: %v", err) - } else { - allDevices = append(allDevices, devices...) - } - } - - if includeDDC { - ddc, err := brightness.NewDDCBackend() - if err != nil { - fmt.Printf("Warning: Failed to initialize DDC backend: %v\n", err) - } else { - time.Sleep(100 * time.Millisecond) - devices, err := ddc.GetDevices() - if err != nil { - fmt.Printf("Warning: Failed to get DDC devices: %v\n", err) - } else { - allDevices = append(allDevices, devices...) - } - ddc.Close() - } - } - - return allDevices -} - -func runBrightnessList(cmd *cobra.Command, args []string) { - includeDDC, _ := cmd.Flags().GetBool("ddc") - allDevices := getAllBrightnessDevices(includeDDC) - - if len(allDevices) == 0 { - fmt.Println("No brightness devices found") - return - } - - maxIDLen := len("Device") - maxNameLen := len("Name") - for _, dev := range allDevices { - if len(dev.ID) > maxIDLen { - maxIDLen = len(dev.ID) - } - if len(dev.Name) > maxNameLen { - maxNameLen = len(dev.Name) - } - } - - idPad := maxIDLen + 2 - namePad := maxNameLen + 2 - - fmt.Printf("%-*s %-12s %-*s %s\n", idPad, "Device", "Class", namePad, "Name", "Brightness") - - sepLen := idPad + 2 + 12 + 2 + namePad + 2 + 15 - for range sepLen { - fmt.Print("─") - } - fmt.Println() - - for _, device := range allDevices { - fmt.Printf("%-*s %-12s %-*s %3d%%\n", - idPad, - device.ID, - device.Class, - namePad, - device.Name, - device.CurrentPercent, - ) - } -} - -func runBrightnessSet(cmd *cobra.Command, args []string) { - deviceID := args[0] - var percent int - if _, err := fmt.Sscanf(args[1], "%d", &percent); err != nil { - log.Fatalf("Invalid percent value: %s", args[1]) - } - - if percent < 0 || percent > 100 { - log.Fatalf("Percent must be between 0 and 100") - } - - includeDDC, _ := cmd.Flags().GetBool("ddc") - exponential, _ := cmd.Flags().GetBool("exponential") - exponent, _ := cmd.Flags().GetFloat64("exponent") - - parts := strings.SplitN(deviceID, ":", 2) - if len(parts) == 2 && (parts[0] == "backlight" || parts[0] == "leds") { - if ok := tryLogindBrightness(parts[0], parts[1], deviceID, percent, exponential, exponent); ok { - return - } - } - - sysfs, err := brightness.NewSysfsBackend() - if err == nil { - if err := sysfs.SetBrightnessWithExponent(deviceID, percent, exponential, exponent); err == nil { - fmt.Printf("Set %s to %d%%\n", deviceID, percent) - return - } - log.Debugf("sysfs.SetBrightness failed: %v", err) - } else { - log.Debugf("NewSysfsBackend failed: %v", err) - } - - // Try DDC if requested - if includeDDC { - ddc, err := brightness.NewDDCBackend() - if err == nil { - defer ddc.Close() - time.Sleep(100 * time.Millisecond) - if err := ddc.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, nil); err == nil { - ddc.WaitPending() - fmt.Printf("Set %s to %d%%\n", deviceID, percent) - return - } - log.Debugf("ddc.SetBrightness failed: %v", err) - } else { - log.Debugf("NewDDCBackend failed: %v", err) - } - } - - log.Fatalf("Failed to set brightness for device: %s", deviceID) -} - -func tryLogindBrightness(subsystem, name, deviceID string, percent int, exponential bool, exponent float64) bool { - sysfs, err := brightness.NewSysfsBackend() - if err != nil { - log.Debugf("NewSysfsBackend failed: %v", err) - return false - } - - logind, err := brightness.NewLogindBackend() - if err != nil { - log.Debugf("NewLogindBackend failed: %v", err) - return false - } - defer logind.Close() - - dev, err := sysfs.GetDevice(deviceID) - if err != nil { - log.Debugf("sysfs.GetDeviceByID failed: %v", err) - return false - } - - value := sysfs.PercentToValueWithExponent(percent, dev, exponential, exponent) - if err := logind.SetBrightness(subsystem, name, uint32(value)); err != nil { - log.Debugf("logind.SetBrightness failed: %v", err) - return false - } - - log.Debugf("set %s to %d%% (%d) via logind", deviceID, percent, value) - fmt.Printf("Set %s to %d%%\n", deviceID, percent) - return true -} - -func getBrightnessDevices(includeDDC bool) []string { - allDevices := getAllBrightnessDevices(includeDDC) - - var deviceIDs []string - for _, device := range allDevices { - deviceIDs = append(deviceIDs, device.ID) - } - return deviceIDs -} - -func runBrightnessGet(cmd *cobra.Command, args []string) { - deviceID := args[0] - includeDDC, _ := cmd.Flags().GetBool("ddc") - allDevices := getAllBrightnessDevices(includeDDC) - - for _, device := range allDevices { - if device.ID == deviceID { - fmt.Printf("%s: %d%% (%d/%d)\n", - device.ID, - device.CurrentPercent, - device.Current, - device.Max, - ) - return - } - } - - log.Fatalf("Device not found: %s", deviceID) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_chroma.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_chroma.go deleted file mode 100644 index 4945f33..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_chroma.go +++ /dev/null @@ -1,300 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io" - "os" - "strings" - "sync" - - "github.com/alecthomas/chroma/v2" - "github.com/alecthomas/chroma/v2/formatters/html" - "github.com/alecthomas/chroma/v2/lexers" - "github.com/alecthomas/chroma/v2/styles" - "github.com/spf13/cobra" - "github.com/yuin/goldmark" - highlighting "github.com/yuin/goldmark-highlighting/v2" - "github.com/yuin/goldmark/extension" - "github.com/yuin/goldmark/parser" - ghtml "github.com/yuin/goldmark/renderer/html" -) - -var ( - chromaLanguage string - chromaStyle string - chromaInline bool - chromaMarkdown bool - chromaLineNumbers bool - - // Caching layer for performance - lexerCache = make(map[string]chroma.Lexer) - styleCache = make(map[string]*chroma.Style) - formatterCache = make(map[string]*html.Formatter) - cacheMutex sync.RWMutex - maxFileSize = int64(5 * 1024 * 1024) // 5MB default -) - -var chromaCmd = &cobra.Command{ - Use: "chroma [file]", - Short: "Syntax highlight source code", - Long: `Generate syntax-highlighted HTML from source code. - -Reads from file or stdin, outputs HTML with syntax highlighting. -Language is auto-detected from filename or can be specified with --language. - -Examples: - dms chroma main.go - dms chroma --language python script.py - echo "def foo(): pass" | dms chroma -l python - cat code.rs | dms chroma -l rust --style dracula - dms chroma --markdown README.md - dms chroma --markdown --style github-dark notes.md - dms chroma list-languages - dms chroma list-styles`, - Args: cobra.MaximumNArgs(1), - Run: runChroma, -} - -var chromaListLanguagesCmd = &cobra.Command{ - Use: "list-languages", - Short: "List all supported languages", - Run: func(cmd *cobra.Command, args []string) { - for _, name := range lexers.Names(true) { - fmt.Println(name) - } - }, -} - -var chromaListStylesCmd = &cobra.Command{ - Use: "list-styles", - Short: "List all available color styles", - Run: func(cmd *cobra.Command, args []string) { - for _, name := range styles.Names() { - fmt.Println(name) - } - }, -} - -func init() { - chromaCmd.Flags().StringVarP(&chromaLanguage, "language", "l", "", "Language for highlighting (auto-detect if not specified)") - chromaCmd.Flags().StringVarP(&chromaStyle, "style", "s", "monokai", "Color style (monokai, dracula, github, etc.)") - chromaCmd.Flags().BoolVar(&chromaInline, "inline", false, "Output inline styles instead of CSS classes") - chromaCmd.Flags().BoolVar(&chromaLineNumbers, "line-numbers", false, "Show line numbers in output") - chromaCmd.Flags().BoolVarP(&chromaMarkdown, "markdown", "m", false, "Render markdown with syntax-highlighted code blocks") - chromaCmd.Flags().Int64Var(&maxFileSize, "max-size", 5*1024*1024, "Maximum file size to process without warning (bytes)") - - chromaCmd.AddCommand(chromaListLanguagesCmd) - chromaCmd.AddCommand(chromaListStylesCmd) -} - -func getCachedLexer(key string, fallbackFunc func() chroma.Lexer) chroma.Lexer { - cacheMutex.RLock() - if lexer, ok := lexerCache[key]; ok { - cacheMutex.RUnlock() - return lexer - } - cacheMutex.RUnlock() - - lexer := fallbackFunc() - if lexer != nil { - cacheMutex.Lock() - lexerCache[key] = lexer - cacheMutex.Unlock() - } - return lexer -} - -func getCachedStyle(name string) *chroma.Style { - cacheMutex.RLock() - if style, ok := styleCache[name]; ok { - cacheMutex.RUnlock() - return style - } - cacheMutex.RUnlock() - - style := styles.Get(name) - if style == nil { - fmt.Fprintf(os.Stderr, "Warning: Style '%s' not found, using fallback\n", name) - style = styles.Fallback - } - - cacheMutex.Lock() - styleCache[name] = style - cacheMutex.Unlock() - return style -} - -func getCachedFormatter(inline bool, lineNumbers bool) *html.Formatter { - key := fmt.Sprintf("inline=%t,lineNumbers=%t", inline, lineNumbers) - - cacheMutex.RLock() - if formatter, ok := formatterCache[key]; ok { - cacheMutex.RUnlock() - return formatter - } - cacheMutex.RUnlock() - - var opts []html.Option - if inline { - opts = append(opts, html.WithClasses(false)) - } else { - opts = append(opts, html.WithClasses(true)) - } - opts = append(opts, html.TabWidth(4)) - - if lineNumbers { - opts = append(opts, html.WithLineNumbers(true)) - opts = append(opts, html.LineNumbersInTable(false)) - opts = append(opts, html.WithLinkableLineNumbers(false, "")) - } - - formatter := html.New(opts...) - - cacheMutex.Lock() - formatterCache[key] = formatter - cacheMutex.Unlock() - return formatter -} - -func runChroma(cmd *cobra.Command, args []string) { - var source string - var filename string - - // Read from file or stdin - if len(args) > 0 { - filename = args[0] - - // Check file size before reading - fileInfo, err := os.Stat(filename) - if err != nil { - fmt.Fprintf(os.Stderr, "Error reading file info: %v\n", err) - os.Exit(1) - } - - if fileInfo.Size() > maxFileSize { - fmt.Fprintf(os.Stderr, "Warning: File size (%d bytes) exceeds recommended limit (%d bytes)\n", - fileInfo.Size(), maxFileSize) - fmt.Fprintf(os.Stderr, "Processing may be slow. Consider using smaller files.\n") - } - - content, err := os.ReadFile(filename) - if err != nil { - fmt.Fprintf(os.Stderr, "Error reading file: %v\n", err) - os.Exit(1) - } - source = string(content) - } else { - stat, _ := os.Stdin.Stat() - if (stat.Mode() & os.ModeCharDevice) != 0 { - _ = cmd.Help() - os.Exit(0) - } - - content, err := io.ReadAll(os.Stdin) - if err != nil { - fmt.Fprintf(os.Stderr, "Error reading stdin: %v\n", err) - os.Exit(1) - } - source = string(content) - } - - // Handle empty input - if strings.TrimSpace(source) == "" { - return - } - - // Handle Markdown rendering - if chromaMarkdown { - md := goldmark.New( - goldmark.WithExtensions( - extension.GFM, - highlighting.NewHighlighting( - highlighting.WithStyle(chromaStyle), - highlighting.WithFormatOptions( - html.WithClasses(!chromaInline), - ), - ), - ), - goldmark.WithParserOptions( - parser.WithAutoHeadingID(), - ), - goldmark.WithRendererOptions( - ghtml.WithHardWraps(), - ghtml.WithXHTML(), - ), - ) - - var buf bytes.Buffer - if err := md.Convert([]byte(source), &buf); err != nil { - fmt.Fprintf(os.Stderr, "Markdown rendering error: %v\n", err) - os.Exit(1) - } - fmt.Print(buf.String()) - return - } - - // Detect or use specified lexer - var lexer chroma.Lexer - if chromaLanguage != "" { - lexer = getCachedLexer(chromaLanguage, func() chroma.Lexer { - l := lexers.Get(chromaLanguage) - if l == nil { - fmt.Fprintf(os.Stderr, "Unknown language: %s\n", chromaLanguage) - os.Exit(1) - } - return l - }) - } else if filename != "" { - lexer = getCachedLexer("file:"+filename, func() chroma.Lexer { - return lexers.Match(filename) - }) - } - - // Try content analysis if no lexer found (limit to first 1KB for performance) - if lexer == nil { - analyzeContent := source - if len(source) > 1024 { - analyzeContent = source[:1024] - } - lexer = lexers.Analyse(analyzeContent) - } - - // Fallback to plaintext - if lexer == nil { - lexer = lexers.Fallback - } - - lexer = chroma.Coalesce(lexer) - - // Get cached style - style := getCachedStyle(chromaStyle) - - // Get cached formatter - formatter := getCachedFormatter(chromaInline, chromaLineNumbers) - - // Tokenize - iterator, err := lexer.Tokenise(nil, source) - if err != nil { - fmt.Fprintf(os.Stderr, "Tokenization error: %v\n", err) - os.Exit(1) - } - - // Format and output - if chromaLineNumbers { - var buf bytes.Buffer - if err := formatter.Format(&buf, style, iterator); err != nil { - fmt.Fprintf(os.Stderr, "Formatting error: %v\n", err) - os.Exit(1) - } - // Add spacing between line numbers - output := buf.String() - output = strings.ReplaceAll(output, "", "\u00A0\u00A0") - fmt.Print(output) - } else { - if err := formatter.Format(os.Stdout, style, iterator); err != nil { - fmt.Fprintf(os.Stderr, "Formatting error: %v\n", err) - os.Exit(1) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_clipboard.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_clipboard.go deleted file mode 100644 index 8a9b858..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_clipboard.go +++ /dev/null @@ -1,1004 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/base64" - "encoding/binary" - "encoding/json" - "fmt" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "io" - "net/http" - "net/url" - "os" - "os/exec" - "os/signal" - "path/filepath" - "strconv" - "strings" - "syscall" - "time" - - bolt "go.etcd.io/bbolt" - _ "golang.org/x/image/bmp" - _ "golang.org/x/image/tiff" - _ "golang.org/x/image/webp" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/spf13/cobra" -) - -var clipboardCmd = &cobra.Command{ - Use: "clipboard", - Aliases: []string{"cl"}, - Short: "Manage clipboard", - Long: "Interact with the clipboard manager", -} - -var clipCopyCmd = &cobra.Command{ - Use: "copy [text]", - Short: "Copy text to clipboard", - Long: "Copy text to clipboard. If no text provided, reads from stdin. Works without server.", - Run: runClipCopy, -} - -var ( - clipCopyForeground bool - clipCopyPasteOnce bool - clipCopyType string - clipCopyDownload bool - clipJSONOutput bool -) - -var clipPasteCmd = &cobra.Command{ - Use: "paste", - Short: "Paste text from clipboard", - Long: "Paste text from clipboard to stdout. Works without server.", - Run: runClipPaste, -} - -var clipWatchCmd = &cobra.Command{ - Use: "watch [command]", - Short: "Watch clipboard for changes", - Long: `Watch clipboard for changes and optionally execute a command. -Works like wl-paste --watch. Does not require server. - -If a command is provided, it will be executed each time the clipboard changes, -with the clipboard content piped to its stdin. - -Examples: - dms cl watch # Print clipboard changes to stdout - dms cl watch cat # Same as above - dms cl watch notify-send # Send notification on clipboard change`, - Run: runClipWatch, -} - -var clipHistoryCmd = &cobra.Command{ - Use: "history", - Short: "Show clipboard history", - Long: "Show clipboard history with previews (requires server)", - Run: runClipHistory, -} - -var clipGetCmd = &cobra.Command{ - Use: "get ", - Short: "Get clipboard entry by ID", - Long: "Get full clipboard entry data by ID (requires server). Use --copy to copy it to clipboard.", - Args: cobra.ExactArgs(1), - Run: runClipGet, -} - -var clipGetCopy bool - -var clipDeleteCmd = &cobra.Command{ - Use: "delete ", - Short: "Delete clipboard entry", - Long: "Delete a clipboard history entry by ID (requires server)", - Args: cobra.ExactArgs(1), - Run: runClipDelete, -} - -var clipClearCmd = &cobra.Command{ - Use: "clear", - Short: "Clear clipboard history", - Long: "Clear all clipboard history (requires server)", - Run: runClipClear, -} - -var clipWatchStore bool -var clipWatchMimes bool - -var clipSearchCmd = &cobra.Command{ - Use: "search [query]", - Short: "Search clipboard history", - Long: "Search clipboard history with filters (requires server)", - Run: runClipSearch, -} - -var ( - clipSearchLimit int - clipSearchOffset int - clipSearchMimeType string - clipSearchImages bool - clipSearchText bool -) - -var clipConfigCmd = &cobra.Command{ - Use: "config", - Short: "Manage clipboard config", - Long: "Get or set clipboard configuration (requires server)", -} - -var clipConfigGetCmd = &cobra.Command{ - Use: "get", - Short: "Get clipboard config", - Run: runClipConfigGet, -} - -var clipConfigSetCmd = &cobra.Command{ - Use: "set", - Short: "Set clipboard config", - Long: `Set clipboard configuration options. - -Examples: - dms cl config set --max-history 200 - dms cl config set --auto-clear-days 7 - dms cl config set --clear-at-startup`, - Run: runClipConfigSet, -} - -var ( - clipConfigMaxHistory int - clipConfigAutoClearDays int - clipConfigClearAtStartup bool - clipConfigNoClearStartup bool - clipConfigDisabled bool - clipConfigEnabled bool -) - -var clipExportCmd = &cobra.Command{ - Use: "export [file]", - Short: "Export clipboard history to JSON", - Long: "Export clipboard history to JSON file. If no file specified, writes to stdout.", - Run: runClipExport, -} - -var clipImportCmd = &cobra.Command{ - Use: "import ", - Short: "Import clipboard history from JSON", - Long: "Import clipboard history from JSON file exported by 'dms cl export'.", - Args: cobra.ExactArgs(1), - Run: runClipImport, -} - -var clipMigrateCmd = &cobra.Command{ - Use: "cliphist-migrate [db-path]", - Short: "Migrate from cliphist", - Long: "Migrate clipboard history from cliphist. Uses default cliphist path if not specified.", - Run: runClipMigrate, -} - -var clipMigrateDelete bool - -func init() { - clipCopyCmd.Flags().BoolVarP(&clipCopyForeground, "foreground", "f", false, "Stay in foreground instead of forking") - clipCopyCmd.Flags().BoolVarP(&clipCopyPasteOnce, "paste-once", "o", false, "Exit after first paste") - clipCopyCmd.Flags().StringVarP(&clipCopyType, "type", "t", "text/plain;charset=utf-8", "MIME type") - clipCopyCmd.Flags().BoolVarP(&clipCopyDownload, "download", "d", false, "Download URL as image and copy as file") - - clipWatchCmd.Flags().BoolVar(&clipJSONOutput, "json", false, "Output as JSON") - clipHistoryCmd.Flags().BoolVar(&clipJSONOutput, "json", false, "Output as JSON") - clipGetCmd.Flags().BoolVar(&clipJSONOutput, "json", false, "Output as JSON") - clipGetCmd.Flags().BoolVarP(&clipGetCopy, "copy", "C", false, "Copy entry to clipboard") - - clipSearchCmd.Flags().IntVarP(&clipSearchLimit, "limit", "l", 50, "Max results") - clipSearchCmd.Flags().IntVarP(&clipSearchOffset, "offset", "o", 0, "Result offset") - clipSearchCmd.Flags().StringVarP(&clipSearchMimeType, "mime", "m", "", "Filter by MIME type") - clipSearchCmd.Flags().BoolVar(&clipSearchImages, "images", false, "Only images") - clipSearchCmd.Flags().BoolVar(&clipSearchText, "text", false, "Only text") - clipSearchCmd.Flags().BoolVar(&clipJSONOutput, "json", false, "Output as JSON") - - clipConfigSetCmd.Flags().IntVar(&clipConfigMaxHistory, "max-history", 0, "Max history entries") - clipConfigSetCmd.Flags().IntVar(&clipConfigAutoClearDays, "auto-clear-days", -1, "Auto-clear entries older than N days (0 to disable)") - clipConfigSetCmd.Flags().BoolVar(&clipConfigClearAtStartup, "clear-at-startup", false, "Clear history on startup") - clipConfigSetCmd.Flags().BoolVar(&clipConfigNoClearStartup, "no-clear-at-startup", false, "Don't clear history on startup") - clipConfigSetCmd.Flags().BoolVar(&clipConfigDisabled, "disable", false, "Disable clipboard tracking") - clipConfigSetCmd.Flags().BoolVar(&clipConfigEnabled, "enable", false, "Enable clipboard tracking") - - clipWatchCmd.Flags().BoolVarP(&clipWatchStore, "store", "s", false, "Store clipboard changes to history (no server required)") - clipWatchCmd.Flags().BoolVarP(&clipWatchMimes, "mimes", "m", false, "Show all offered MIME types") - - clipMigrateCmd.Flags().BoolVar(&clipMigrateDelete, "delete", false, "Delete cliphist db after successful migration") - - clipConfigCmd.AddCommand(clipConfigGetCmd, clipConfigSetCmd) - clipboardCmd.AddCommand(clipCopyCmd, clipPasteCmd, clipWatchCmd, clipHistoryCmd, clipGetCmd, clipDeleteCmd, clipClearCmd, clipSearchCmd, clipConfigCmd, clipExportCmd, clipImportCmd, clipMigrateCmd) -} - -func runClipCopy(cmd *cobra.Command, args []string) { - var data []byte - copyFromStdin := false - - switch { - case len(args) > 0: - data = []byte(args[0]) - case clipCopyDownload || clipCopyType == "__multi__": - var err error - data, err = io.ReadAll(os.Stdin) - if err != nil { - log.Fatalf("read stdin: %v", err) - } - default: - copyFromStdin = true - } - - if clipCopyDownload { - filePath, err := downloadToTempFile(strings.TrimSpace(string(data))) - if err != nil { - log.Fatalf("download: %v", err) - } - if err := copyFileToClipboard(filePath); err != nil { - log.Fatalf("copy file: %v", err) - } - fmt.Printf("Downloaded and copied: %s\n", filePath) - return - } - - if clipCopyType == "__multi__" { - offers, err := parseMultiOffers(data) - if err != nil { - log.Fatalf("parse multi offers: %v", err) - } - if err := clipboard.CopyMulti(offers, true, clipCopyPasteOnce); err != nil { - log.Fatalf("copy multi: %v", err) - } - return - } - - if copyFromStdin { - if err := clipboard.CopyReader(os.Stdin, clipCopyType, clipCopyForeground, clipCopyPasteOnce); err != nil { - log.Fatalf("copy: %v", err) - } - return - } - - if err := clipboard.CopyOpts(data, clipCopyType, clipCopyForeground, clipCopyPasteOnce); err != nil { - log.Fatalf("copy: %v", err) - } -} - -func parseMultiOffers(data []byte) ([]clipboard.Offer, error) { - var offers []clipboard.Offer - pos := 0 - - for pos < len(data) { - mimeEnd := bytes.IndexByte(data[pos:], 0) - if mimeEnd == -1 { - break - } - mimeType := string(data[pos : pos+mimeEnd]) - pos += mimeEnd + 1 - - lenEnd := bytes.IndexByte(data[pos:], 0) - if lenEnd == -1 { - break - } - dataLen, err := strconv.Atoi(string(data[pos : pos+lenEnd])) - if err != nil { - return nil, fmt.Errorf("parse length: %w", err) - } - pos += lenEnd + 1 - - if pos+dataLen > len(data) { - return nil, fmt.Errorf("data truncated") - } - offerData := data[pos : pos+dataLen] - pos += dataLen - - offers = append(offers, clipboard.Offer{MimeType: mimeType, Data: offerData}) - } - - return offers, nil -} - -func runClipPaste(cmd *cobra.Command, args []string) { - data, _, err := clipboard.Paste() - if err != nil { - log.Fatalf("paste: %v", err) - } - os.Stdout.Write(data) -} - -func runClipWatch(cmd *cobra.Command, args []string) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - go func() { - <-sigCh - cancel() - }() - - switch { - case len(args) > 0: - if err := clipboard.Watch(ctx, func(data []byte, mimeType string) { - runCommand(args, data) - }); err != nil && err != context.Canceled { - log.Fatalf("Watch error: %v", err) - } - case clipWatchStore: - if err := clipboard.Watch(ctx, func(data []byte, mimeType string) { - if err := clipboard.Store(data, mimeType); err != nil { - log.Errorf("store: %v", err) - } - }); err != nil && err != context.Canceled { - log.Fatalf("Watch error: %v", err) - } - case clipWatchMimes: - if err := clipboard.WatchAll(ctx, func(data []byte, mimeType string, allMimes []string) { - if clipJSONOutput { - out := map[string]any{ - "data": string(data), - "mimeType": mimeType, - "mimeTypes": allMimes, - "timestamp": time.Now().Format(time.RFC3339), - "size": len(data), - } - j, _ := json.Marshal(out) - fmt.Println(string(j)) - return - } - fmt.Printf("=== Clipboard Change ===\n") - fmt.Printf("Selected: %s\n", mimeType) - fmt.Printf("All MIME types:\n") - for _, m := range allMimes { - fmt.Printf(" - %s\n", m) - } - fmt.Printf("Size: %d bytes\n\n", len(data)) - }); err != nil && err != context.Canceled { - log.Fatalf("Watch error: %v", err) - } - case clipJSONOutput: - if err := clipboard.Watch(ctx, func(data []byte, mimeType string) { - out := map[string]any{ - "data": string(data), - "mimeType": mimeType, - "timestamp": time.Now().Format(time.RFC3339), - "size": len(data), - } - j, _ := json.Marshal(out) - fmt.Println(string(j)) - }); err != nil && err != context.Canceled { - log.Fatalf("Watch error: %v", err) - } - default: - if err := clipboard.Watch(ctx, func(data []byte, mimeType string) { - os.Stdout.Write(data) - os.Stdout.WriteString("\n") - }); err != nil && err != context.Canceled { - log.Fatalf("Watch error: %v", err) - } - } -} - -func runCommand(args []string, stdin []byte) { - cmd := exec.Command(args[0], args[1:]...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if len(stdin) == 0 { - cmd.Run() - return - } - - r, w, err := os.Pipe() - if err != nil { - cmd.Run() - return - } - - cmd.Stdin = r - go func() { - w.Write(stdin) - w.Close() - }() - cmd.Run() -} - -func runClipHistory(cmd *cobra.Command, args []string) { - req := models.Request{ - ID: 1, - Method: "clipboard.getHistory", - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to get clipboard history: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - if resp.Result == nil { - if clipJSONOutput { - fmt.Println("[]") - } else { - fmt.Println("No clipboard history") - } - return - } - - historyList, ok := (*resp.Result).([]any) - if !ok { - log.Fatal("Invalid response format") - } - - if clipJSONOutput { - out, _ := json.MarshalIndent(historyList, "", " ") - fmt.Println(string(out)) - return - } - - if len(historyList) == 0 { - fmt.Println("No clipboard history") - return - } - - fmt.Println("Clipboard History:") - fmt.Println() - - for _, item := range historyList { - entry, ok := item.(map[string]any) - if !ok { - continue - } - - id := uint64(entry["id"].(float64)) - preview := entry["preview"].(string) - timestamp := entry["timestamp"].(string) - isImage := entry["isImage"].(bool) - - typeStr := "text" - if isImage { - typeStr = "image" - } - - fmt.Printf("ID: %d | %s | %s\n", id, typeStr, timestamp) - fmt.Printf(" %s\n", preview) - fmt.Println() - } -} - -func runClipGet(cmd *cobra.Command, args []string) { - id, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - log.Fatalf("Invalid ID: %v", err) - } - - if clipGetCopy { - req := models.Request{ - ID: 1, - Method: "clipboard.copyEntry", - Params: map[string]any{"id": id}, - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to copy clipboard entry: %v", err) - } - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - fmt.Printf("Copied entry %d to clipboard\n", id) - return - } - - req := models.Request{ - ID: 1, - Method: "clipboard.getEntry", - Params: map[string]any{ - "id": id, - }, - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to get clipboard entry: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - if resp.Result == nil { - log.Fatal("Entry not found") - } - - entry, ok := (*resp.Result).(map[string]any) - if !ok { - log.Fatal("Invalid response format") - } - - switch { - case clipJSONOutput: - output, _ := json.MarshalIndent(entry, "", " ") - fmt.Println(string(output)) - default: - if data, ok := entry["data"].(string); ok { - fmt.Print(data) - } else { - output, _ := json.MarshalIndent(entry, "", " ") - fmt.Println(string(output)) - } - } -} - -func runClipDelete(cmd *cobra.Command, args []string) { - id, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - log.Fatalf("Invalid ID: %v", err) - } - - req := models.Request{ - ID: 1, - Method: "clipboard.deleteEntry", - Params: map[string]any{ - "id": id, - }, - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to delete clipboard entry: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - fmt.Printf("Deleted entry %d\n", id) -} - -func runClipClear(cmd *cobra.Command, args []string) { - req := models.Request{ - ID: 1, - Method: "clipboard.clearHistory", - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to clear clipboard history: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - fmt.Println("Clipboard history cleared") -} - -func runClipSearch(cmd *cobra.Command, args []string) { - params := map[string]any{ - "limit": clipSearchLimit, - "offset": clipSearchOffset, - } - - if len(args) > 0 { - params["query"] = args[0] - } - if clipSearchMimeType != "" { - params["mimeType"] = clipSearchMimeType - } - if clipSearchImages { - params["isImage"] = true - } else if clipSearchText { - params["isImage"] = false - } - - req := models.Request{ - ID: 1, - Method: "clipboard.search", - Params: params, - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to search clipboard: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - if resp.Result == nil { - log.Fatal("No results") - } - - result, ok := (*resp.Result).(map[string]any) - if !ok { - log.Fatal("Invalid response format") - } - - if clipJSONOutput { - out, _ := json.MarshalIndent(result, "", " ") - fmt.Println(string(out)) - return - } - - entries, _ := result["entries"].([]any) - total := int(result["total"].(float64)) - hasMore := result["hasMore"].(bool) - - if len(entries) == 0 { - fmt.Println("No results found") - return - } - - fmt.Printf("Results: %d of %d\n\n", len(entries), total) - - for _, item := range entries { - entry, ok := item.(map[string]any) - if !ok { - continue - } - - id := uint64(entry["id"].(float64)) - preview := entry["preview"].(string) - timestamp := entry["timestamp"].(string) - isImage := entry["isImage"].(bool) - - typeStr := "text" - if isImage { - typeStr = "image" - } - - fmt.Printf("ID: %d | %s | %s\n", id, typeStr, timestamp) - fmt.Printf(" %s\n\n", preview) - } - - if hasMore { - fmt.Printf("Use --offset %d to see more results\n", clipSearchOffset+clipSearchLimit) - } -} - -func runClipConfigGet(cmd *cobra.Command, args []string) { - req := models.Request{ - ID: 1, - Method: "clipboard.getConfig", - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to get config: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - if resp.Result == nil { - log.Fatal("No config returned") - } - - cfg, ok := (*resp.Result).(map[string]any) - if !ok { - log.Fatal("Invalid response format") - } - - output, _ := json.MarshalIndent(cfg, "", " ") - fmt.Println(string(output)) -} - -func runClipConfigSet(cmd *cobra.Command, args []string) { - params := map[string]any{} - - if cmd.Flags().Changed("max-history") { - params["maxHistory"] = clipConfigMaxHistory - } - if cmd.Flags().Changed("auto-clear-days") { - params["autoClearDays"] = clipConfigAutoClearDays - } - if clipConfigClearAtStartup { - params["clearAtStartup"] = true - } - if clipConfigNoClearStartup { - params["clearAtStartup"] = false - } - if clipConfigDisabled { - params["disabled"] = true - } - if clipConfigEnabled { - params["disabled"] = false - } - - if len(params) == 0 { - fmt.Println("No config options specified") - return - } - - req := models.Request{ - ID: 1, - Method: "clipboard.setConfig", - Params: params, - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to set config: %v", err) - } - - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - - fmt.Println("Config updated") -} - -func runClipExport(cmd *cobra.Command, args []string) { - req := models.Request{ - ID: 1, - Method: "clipboard.getHistory", - } - - resp, err := sendServerRequest(req) - if err != nil { - log.Fatalf("Failed to get clipboard history: %v", err) - } - if resp.Error != "" { - log.Fatalf("Error: %s", resp.Error) - } - if resp.Result == nil { - log.Fatal("No clipboard history") - } - - out, err := json.MarshalIndent(resp.Result, "", " ") - if err != nil { - log.Fatalf("Failed to marshal: %v", err) - } - - if len(args) == 0 { - fmt.Println(string(out)) - return - } - - if err := os.WriteFile(args[0], out, 0o644); err != nil { - log.Fatalf("Failed to write file: %v", err) - } - fmt.Printf("Exported to %s\n", args[0]) -} - -func runClipImport(cmd *cobra.Command, args []string) { - data, err := os.ReadFile(args[0]) - if err != nil { - log.Fatalf("Failed to read file: %v", err) - } - - var entries []map[string]any - if err := json.Unmarshal(data, &entries); err != nil { - log.Fatalf("Failed to parse JSON: %v", err) - } - - var imported int - for _, entry := range entries { - dataStr, ok := entry["data"].(string) - if !ok { - continue - } - mimeType, _ := entry["mimeType"].(string) - if mimeType == "" { - mimeType = "text/plain" - } - - var entryData []byte - if decoded, err := base64.StdEncoding.DecodeString(dataStr); err == nil { - entryData = decoded - } else { - entryData = []byte(dataStr) - } - - if err := clipboard.Store(entryData, mimeType); err != nil { - log.Errorf("Failed to store entry: %v", err) - continue - } - imported++ - } - - fmt.Printf("Imported %d entries\n", imported) -} - -func runClipMigrate(cmd *cobra.Command, args []string) { - dbPath := getCliphistPath() - if len(args) > 0 { - dbPath = args[0] - } - - if _, err := os.Stat(dbPath); err != nil { - log.Fatalf("Cliphist db not found: %s", dbPath) - } - - db, err := bolt.Open(dbPath, 0o644, &bolt.Options{ - ReadOnly: true, - Timeout: 1 * time.Second, - }) - if err != nil { - log.Fatalf("Failed to open cliphist db: %v", err) - } - defer db.Close() - - var migrated int - err = db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("b")) - if b == nil { - return fmt.Errorf("cliphist bucket not found") - } - - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if len(v) == 0 { - continue - } - - mimeType := detectMimeType(v) - if err := clipboard.Store(v, mimeType); err != nil { - log.Errorf("Failed to store entry %d: %v", btoi(k), err) - continue - } - migrated++ - } - return nil - }) - if err != nil { - log.Fatalf("Migration failed: %v", err) - } - - fmt.Printf("Migrated %d entries from cliphist\n", migrated) - - if !clipMigrateDelete { - return - } - - db.Close() - if err := os.Remove(dbPath); err != nil { - log.Errorf("Failed to delete cliphist db: %v", err) - return - } - os.Remove(filepath.Dir(dbPath)) - fmt.Println("Deleted cliphist db") -} - -func getCliphistPath() string { - cacheDir, err := os.UserCacheDir() - if err != nil { - return filepath.Join(os.Getenv("HOME"), ".cache", "cliphist", "db") - } - return filepath.Join(cacheDir, "cliphist", "db") -} - -func detectMimeType(data []byte) string { - if _, _, err := image.DecodeConfig(bytes.NewReader(data)); err == nil { - return "image/png" - } - return "text/plain" -} - -func btoi(v []byte) uint64 { - return binary.BigEndian.Uint64(v) -} - -func downloadToTempFile(rawURL string) (string, error) { - if !strings.HasPrefix(rawURL, "http://") && !strings.HasPrefix(rawURL, "https://") { - return "", fmt.Errorf("invalid URL: %s", rawURL) - } - - parsedURL, err := url.Parse(rawURL) - if err != nil { - return "", fmt.Errorf("parse URL: %w", err) - } - - ext := filepath.Ext(parsedURL.Path) - if ext == "" { - ext = ".png" - } - - client := &http.Client{Timeout: 30 * time.Second} - - var data []byte - var contentType string - var lastErr error - - for attempt := 0; attempt < 3; attempt++ { - if attempt > 0 { - time.Sleep(time.Duration(attempt) * 500 * time.Millisecond) - } - - req, err := http.NewRequest("GET", rawURL, nil) - if err != nil { - lastErr = fmt.Errorf("create request: %w", err) - continue - } - req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") - req.Header.Set("Accept", "image/*,video/*,*/*") - - resp, err := client.Do(req) - if err != nil { - lastErr = fmt.Errorf("download (attempt %d): %w", attempt+1, err) - continue - } - - if resp.StatusCode != http.StatusOK { - resp.Body.Close() - lastErr = fmt.Errorf("download failed (attempt %d): status %d", attempt+1, resp.StatusCode) - continue - } - - data, err = io.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - lastErr = fmt.Errorf("read response (attempt %d): %w", attempt+1, err) - continue - } - - contentType = resp.Header.Get("Content-Type") - if idx := strings.Index(contentType, ";"); idx != -1 { - contentType = strings.TrimSpace(contentType[:idx]) - } - - lastErr = nil - break - } - - if lastErr != nil { - return "", lastErr - } - - if len(data) == 0 { - return "", fmt.Errorf("downloaded empty file") - } - - if !strings.HasPrefix(contentType, "image/") && !strings.HasPrefix(contentType, "video/") { - if _, _, err := image.DecodeConfig(bytes.NewReader(data)); err != nil { - return "", fmt.Errorf("not a valid media file (content-type: %s)", contentType) - } - } - - cacheDir, err := os.UserCacheDir() - if err != nil { - cacheDir = "/tmp" - } - clipDir := filepath.Join(cacheDir, "dms", "clipboard") - if err := os.MkdirAll(clipDir, 0o755); err != nil { - return "", fmt.Errorf("create cache dir: %w", err) - } - - filePath := filepath.Join(clipDir, fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)) - if err := os.WriteFile(filePath, data, 0o644); err != nil { - return "", fmt.Errorf("write file: %w", err) - } - - return filePath, nil -} - -func copyFileToClipboard(filePath string) error { - req := models.Request{ - ID: 1, - Method: "clipboard.copyFile", - Params: map[string]any{"filePath": filePath}, - } - - resp, err := sendServerRequest(req) - if err != nil { - return fmt.Errorf("server request: %w", err) - } - if resp.Error != "" { - return fmt.Errorf("server error: %s", resp.Error) - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_colorpicker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_colorpicker.go deleted file mode 100644 index 7c366e8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_colorpicker.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/colorpicker" - "github.com/spf13/cobra" -) - -var ( - colorOutputFmt string - colorAutocopy bool - colorNotify bool - colorLowercase bool -) - -var colorCmd = &cobra.Command{ - Use: "color", - Short: "Color utilities", - Long: "Color utilities including picking colors from the screen", -} - -var colorPickCmd = &cobra.Command{ - Use: "pick", - Short: "Pick a color from the screen", - Long: `Pick a color from anywhere on your screen using an interactive color picker. - -Click on any pixel to capture its color, or press Escape to cancel. - -Output format flags (mutually exclusive, default: --hex): - --hex - Hexadecimal (#RRGGBB) - --rgb - RGB values (R G B) - --hsl - HSL values (H S% L%) - --hsv - HSV values (H S% V%) - --cmyk - CMYK values (C% M% Y% K%) - --json - JSON with all formats - -Optional: - --raw - Removes ANSI escape codes and background colors. Use this when piping to other commands - -Examples: - dms color pick # Pick color, output as hex - dms color pick --rgb # Output as RGB - dms color pick --json # Output all formats as JSON - dms color pick --hex -l # Output hex in lowercase - dms color pick -a # Auto-copy result to clipboard`, - Run: runColorPick, -} - -func init() { - colorPickCmd.Flags().Bool("hex", false, "Output as hexadecimal (#RRGGBB)") - colorPickCmd.Flags().Bool("rgb", false, "Output as RGB (R G B)") - colorPickCmd.Flags().Bool("hsl", false, "Output as HSL (H S% L%)") - colorPickCmd.Flags().Bool("hsv", false, "Output as HSV (H S% V%)") - colorPickCmd.Flags().Bool("cmyk", false, "Output as CMYK (C% M% Y% K%)") - colorPickCmd.Flags().Bool("json", false, "Output all formats as JSON") - colorPickCmd.Flags().Bool("raw", false, "Removes ANSI escape codes and background colors. Use this when piping to other commands") - colorPickCmd.Flags().StringVarP(&colorOutputFmt, "output-format", "o", "", "Custom output format template") - colorPickCmd.Flags().BoolVarP(&colorAutocopy, "autocopy", "a", false, "Copy result to clipboard") - colorPickCmd.Flags().BoolVarP(&colorLowercase, "lowercase", "l", false, "Output hex in lowercase") - - colorPickCmd.MarkFlagsMutuallyExclusive("hex", "rgb", "hsl", "hsv", "cmyk", "json") - - colorCmd.AddCommand(colorPickCmd) -} - -func runColorPick(cmd *cobra.Command, args []string) { - format := colorpicker.FormatHex // default - jsonOutput, _ := cmd.Flags().GetBool("json") - - if rgb, _ := cmd.Flags().GetBool("rgb"); rgb { - format = colorpicker.FormatRGB - } else if hsl, _ := cmd.Flags().GetBool("hsl"); hsl { - format = colorpicker.FormatHSL - } else if hsv, _ := cmd.Flags().GetBool("hsv"); hsv { - format = colorpicker.FormatHSV - } else if cmyk, _ := cmd.Flags().GetBool("cmyk"); cmyk { - format = colorpicker.FormatCMYK - } - - config := colorpicker.Config{ - Format: format, - CustomFormat: colorOutputFmt, - Lowercase: colorLowercase, - Autocopy: colorAutocopy, - Notify: colorNotify, - } - - picker := colorpicker.New(config) - color, err := picker.Run() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - if color == nil { - os.Exit(0) - } - - var output string - if jsonOutput { - jsonStr, err := color.ToJSON() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - output = jsonStr - } else { - output = color.Format(config.Format, config.Lowercase, config.CustomFormat) - } - - if colorAutocopy { - copyToClipboard(output) - } - - if jsonOutput { - fmt.Println(output) - return - } - - if raw, _ := cmd.Flags().GetBool("raw"); raw { - fmt.Printf("%s\n", output) - return - } - - if color.IsDark() { - fmt.Printf("\033[48;2;%d;%d;%dm\033[97m %s \033[0m\n", color.R, color.G, color.B, output) - } else { - fmt.Printf("\033[48;2;%d;%d;%dm\033[30m %s \033[0m\n", color.R, color.G, color.B, output) - } -} - -func copyToClipboard(text string) { - if err := clipboard.CopyText(text); err != nil { - fmt.Fprintln(os.Stderr, "clipboard copy failed:", err) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_common.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_common.go deleted file mode 100644 index 6557860..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_common.go +++ /dev/null @@ -1,530 +0,0 @@ -package main - -import ( - "fmt" - "os" - "regexp" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server" - "github.com/spf13/cobra" -) - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Show version information", - Run: runVersion, -} - -var runCmd = &cobra.Command{ - Use: "run", - Short: "Launch quickshell with DMS configuration", - Long: "Launch quickshell with DMS configuration (qs -c dms)", - PreRunE: findConfig, - Run: func(cmd *cobra.Command, args []string) { - daemon, _ := cmd.Flags().GetBool("daemon") - session, _ := cmd.Flags().GetBool("session") - if daemon { - runShellDaemon(session) - } else { - runShellInteractive(session) - } - }, -} - -var restartCmd = &cobra.Command{ - Use: "restart", - Short: "Restart quickshell with DMS configuration", - Long: "Kill existing DMS shell processes and restart quickshell with DMS configuration", - PreRunE: findConfig, - Run: func(cmd *cobra.Command, args []string) { - restartShell() - }, -} - -var restartDetachedCmd = &cobra.Command{ - Use: "restart-detached ", - Hidden: true, - Args: cobra.ExactArgs(1), - PreRunE: findConfig, - Run: func(cmd *cobra.Command, args []string) { - runDetachedRestart(args[0]) - }, -} - -var killCmd = &cobra.Command{ - Use: "kill", - Short: "Kill running DMS shell processes", - Long: "Kill all running quickshell processes with DMS configuration", - Run: func(cmd *cobra.Command, args []string) { - killShell() - }, -} - -var ipcCmd = &cobra.Command{ - Use: "ipc [target] [function] [args...]", - Short: "Send IPC commands to running DMS shell", - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - _ = findConfig(cmd, args) - return getShellIPCCompletions(args, toComplete), cobra.ShellCompDirectiveNoFileComp - }, - Run: func(cmd *cobra.Command, args []string) { - runShellIPCCommand(args) - }, -} - -func init() { - ipcCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { - _ = findConfig(cmd, args) - printIPCHelp() - }) -} - -var debugSrvCmd = &cobra.Command{ - Use: "debug-srv", - Short: "Start the debug server", - Long: "Start the Unix socket debug server for DMS", - Run: func(cmd *cobra.Command, args []string) { - if err := startDebugServer(); err != nil { - log.Fatalf("Error starting debug server: %v", err) - } - }, -} - -var pluginsCmd = &cobra.Command{ - Use: "plugins", - Short: "Manage DMS plugins", - Long: "Browse and manage DMS plugins from the registry", -} - -var pluginsBrowseCmd = &cobra.Command{ - Use: "browse", - Short: "Browse available plugins", - Long: "Browse available plugins from the DMS plugin registry", - Run: func(cmd *cobra.Command, args []string) { - if err := browsePlugins(); err != nil { - log.Fatalf("Error browsing plugins: %v", err) - } - }, -} - -var pluginsListCmd = &cobra.Command{ - Use: "list", - Short: "List installed plugins", - Long: "List all installed DMS plugins", - Run: func(cmd *cobra.Command, args []string) { - if err := listInstalledPlugins(); err != nil { - log.Fatalf("Error listing plugins: %v", err) - } - }, -} - -var pluginsInstallCmd = &cobra.Command{ - Use: "install ", - Short: "Install a plugin by ID", - Long: "Install a DMS plugin from the registry using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.", - Args: cobra.ExactArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getAvailablePluginIDs(), cobra.ShellCompDirectiveNoFileComp - }, - Run: func(cmd *cobra.Command, args []string) { - if err := installPluginCLI(args[0]); err != nil { - log.Fatalf("Error installing plugin: %v", err) - } - }, -} - -var pluginsUninstallCmd = &cobra.Command{ - Use: "uninstall ", - Short: "Uninstall a plugin by ID", - Long: "Uninstall a DMS plugin using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.", - Args: cobra.ExactArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getInstalledPluginIDs(), cobra.ShellCompDirectiveNoFileComp - }, - Run: func(cmd *cobra.Command, args []string) { - if err := uninstallPluginCLI(args[0]); err != nil { - log.Fatalf("Error uninstalling plugin: %v", err) - } - }, -} - -var pluginsUpdateCmd = &cobra.Command{ - Use: "update ", - Short: "Update a plugin by ID", - Long: "Update an installed DMS plugin using its ID (e.g., 'myPlugin'). Plugin names are also supported.", - Args: cobra.ExactArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getInstalledPluginIDs(), cobra.ShellCompDirectiveNoFileComp - }, - Run: func(cmd *cobra.Command, args []string) { - if err := updatePluginCLI(args[0]); err != nil { - log.Fatalf("Error updating plugin: %v", err) - } - }, -} - -func runVersion(cmd *cobra.Command, args []string) { - fmt.Printf("%s\n", formatVersion(Version)) -} - -// Git builds: dms (git) v0.6.2-XXXX -// Stable releases: dms v0.6.2 -func formatVersion(version string) string { - // Arch/Debian/Ubuntu/OpenSUSE git format: 0.6.2+git2264.c5c5ce84 - re := regexp.MustCompile(`^([\d.]+)\+git(\d+)\.`) - if matches := re.FindStringSubmatch(version); matches != nil { - return fmt.Sprintf("dms (git) v%s-%s", matches[1], matches[2]) - } - - // Fedora COPR git format: 0.0.git.2267.d430cae9 - re = regexp.MustCompile(`^[\d.]+\.git\.(\d+)\.`) - if matches := re.FindStringSubmatch(version); matches != nil { - baseVersion := getBaseVersion() - return fmt.Sprintf("dms (git) v%s-%s", baseVersion, matches[1]) - } - - // Stable release format: 0.6.2 - re = regexp.MustCompile(`^([\d.]+)$`) - if matches := re.FindStringSubmatch(version); matches != nil { - return fmt.Sprintf("dms v%s", matches[1]) - } - - return fmt.Sprintf("dms %s", version) -} - -func getBaseVersion() string { - paths := []string{ - "/usr/share/quickshell/dms/VERSION", - "/usr/local/share/quickshell/dms/VERSION", - "/etc/xdg/quickshell/dms/VERSION", - } - - for _, path := range paths { - if content, err := os.ReadFile(path); err == nil { - ver := strings.TrimSpace(string(content)) - ver = strings.TrimPrefix(ver, "v") - if re := regexp.MustCompile(`^([\d.]+)`); re.MatchString(ver) { - if matches := re.FindStringSubmatch(ver); matches != nil { - return matches[1] - } - } - } - } - - // Fallback - return "1.0.2" -} - -func startDebugServer() error { - server.CLIVersion = Version - return server.Start(true) -} - -func browsePlugins() error { - registry, err := plugins.NewRegistry() - if err != nil { - return fmt.Errorf("failed to create registry: %w", err) - } - - manager, err := plugins.NewManager() - if err != nil { - return fmt.Errorf("failed to create manager: %w", err) - } - - fmt.Println("Fetching plugin registry...") - pluginList, err := registry.List() - if err != nil { - return fmt.Errorf("failed to list plugins: %w", err) - } - - if len(pluginList) == 0 { - fmt.Println("No plugins found in registry.") - return nil - } - - fmt.Printf("\nAvailable Plugins (%d):\n\n", len(pluginList)) - for _, plugin := range pluginList { - installed, _ := manager.IsInstalled(plugin) - installedMarker := "" - if installed { - installedMarker = " [Installed]" - } - - fmt.Printf(" %s%s\n", plugin.Name, installedMarker) - fmt.Printf(" ID: %s\n", plugin.ID) - fmt.Printf(" Category: %s\n", plugin.Category) - fmt.Printf(" Author: %s\n", plugin.Author) - fmt.Printf(" Description: %s\n", plugin.Description) - fmt.Printf(" Repository: %s\n", plugin.Repo) - if len(plugin.Capabilities) > 0 { - fmt.Printf(" Capabilities: %s\n", strings.Join(plugin.Capabilities, ", ")) - } - if len(plugin.Compositors) > 0 { - fmt.Printf(" Compositors: %s\n", strings.Join(plugin.Compositors, ", ")) - } - if len(plugin.Dependencies) > 0 { - fmt.Printf(" Dependencies: %s\n", strings.Join(plugin.Dependencies, ", ")) - } - fmt.Println() - } - - return nil -} - -func listInstalledPlugins() error { - manager, err := plugins.NewManager() - if err != nil { - return fmt.Errorf("failed to create manager: %w", err) - } - - registry, err := plugins.NewRegistry() - if err != nil { - return fmt.Errorf("failed to create registry: %w", err) - } - - installedNames, err := manager.ListInstalled() - if err != nil { - return fmt.Errorf("failed to list installed plugins: %w", err) - } - - if len(installedNames) == 0 { - fmt.Println("No plugins installed.") - return nil - } - - allPlugins, err := registry.List() - if err != nil { - return fmt.Errorf("failed to list plugins: %w", err) - } - - pluginMap := make(map[string]plugins.Plugin) - for _, p := range allPlugins { - pluginMap[p.ID] = p - } - - fmt.Printf("\nInstalled Plugins (%d):\n\n", len(installedNames)) - for _, id := range installedNames { - if plugin, ok := pluginMap[id]; ok { - fmt.Printf(" %s\n", plugin.Name) - fmt.Printf(" ID: %s\n", plugin.ID) - fmt.Printf(" Category: %s\n", plugin.Category) - fmt.Printf(" Author: %s\n", plugin.Author) - fmt.Println() - } else { - fmt.Printf(" %s (not in registry)\n\n", id) - } - } - - return nil -} - -func installPluginCLI(idOrName string) error { - registry, err := plugins.NewRegistry() - if err != nil { - return fmt.Errorf("failed to create registry: %w", err) - } - - manager, err := plugins.NewManager() - if err != nil { - return fmt.Errorf("failed to create manager: %w", err) - } - - pluginList, err := registry.List() - if err != nil { - return fmt.Errorf("failed to list plugins: %w", err) - } - - // First, try to find by ID (preferred method) - var plugin *plugins.Plugin - for _, p := range pluginList { - if p.ID == idOrName { - plugin = &p - break - } - } - - // Fallback to name for backward compatibility - if plugin == nil { - for _, p := range pluginList { - if p.Name == idOrName { - plugin = &p - break - } - } - } - - if plugin == nil { - return fmt.Errorf("plugin not found: %s", idOrName) - } - - installed, err := manager.IsInstalled(*plugin) - if err != nil { - return fmt.Errorf("failed to check install status: %w", err) - } - - if installed { - return fmt.Errorf("plugin already installed: %s", plugin.Name) - } - - fmt.Printf("Installing plugin: %s (ID: %s)\n", plugin.Name, plugin.ID) - if err := manager.Install(*plugin); err != nil { - return fmt.Errorf("failed to install plugin: %w", err) - } - - fmt.Printf("Plugin installed successfully: %s\n", plugin.Name) - return nil -} - -func getAvailablePluginIDs() []string { - registry, err := plugins.NewRegistry() - if err != nil { - return nil - } - - pluginList, err := registry.List() - if err != nil { - return nil - } - - var ids []string - for _, p := range pluginList { - ids = append(ids, p.ID) - } - return ids -} - -func getInstalledPluginIDs() []string { - manager, err := plugins.NewManager() - if err != nil { - return nil - } - - installed, err := manager.ListInstalled() - if err != nil { - return nil - } - - return installed -} - -func uninstallPluginCLI(idOrName string) error { - manager, err := plugins.NewManager() - if err != nil { - return fmt.Errorf("failed to create manager: %w", err) - } - - registry, err := plugins.NewRegistry() - if err != nil { - return fmt.Errorf("failed to create registry: %w", err) - } - - pluginList, _ := registry.List() - plugin := plugins.FindByIDOrName(idOrName, pluginList) - - if plugin != nil { - installed, err := manager.IsInstalled(*plugin) - if err != nil { - return fmt.Errorf("failed to check install status: %w", err) - } - if !installed { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - fmt.Printf("Uninstalling plugin: %s (ID: %s)\n", plugin.Name, plugin.ID) - if err := manager.Uninstall(*plugin); err != nil { - return fmt.Errorf("failed to uninstall plugin: %w", err) - } - fmt.Printf("Plugin uninstalled successfully: %s\n", plugin.Name) - return nil - } - - fmt.Printf("Uninstalling plugin: %s\n", idOrName) - if err := manager.UninstallByIDOrName(idOrName); err != nil { - return err - } - fmt.Printf("Plugin uninstalled successfully: %s\n", idOrName) - return nil -} - -func updatePluginCLI(idOrName string) error { - manager, err := plugins.NewManager() - if err != nil { - return fmt.Errorf("failed to create manager: %w", err) - } - - registry, err := plugins.NewRegistry() - if err != nil { - return fmt.Errorf("failed to create registry: %w", err) - } - - pluginList, _ := registry.List() - plugin := plugins.FindByIDOrName(idOrName, pluginList) - - if plugin != nil { - installed, err := manager.IsInstalled(*plugin) - if err != nil { - return fmt.Errorf("failed to check install status: %w", err) - } - if !installed { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - fmt.Printf("Updating plugin: %s (ID: %s)\n", plugin.Name, plugin.ID) - if err := manager.Update(*plugin); err != nil { - return fmt.Errorf("failed to update plugin: %w", err) - } - fmt.Printf("Plugin updated successfully: %s\n", plugin.Name) - return nil - } - - fmt.Printf("Updating plugin: %s\n", idOrName) - if err := manager.UpdateByIDOrName(idOrName); err != nil { - return err - } - fmt.Printf("Plugin updated successfully: %s\n", idOrName) - return nil -} - -func getCommonCommands() []*cobra.Command { - return []*cobra.Command{ - versionCmd, - runCmd, - restartCmd, - restartDetachedCmd, - killCmd, - ipcCmd, - debugSrvCmd, - pluginsCmd, - dank16Cmd, - brightnessCmd, - dpmsCmd, - keybindsCmd, - greeterCmd, - setupCmd, - colorCmd, - screenshotCmd, - notifyActionCmd, - notifyCmd, - genericNotifyActionCmd, - matugenCmd, - clipboardCmd, - chromaCmd, - doctorCmd, - configCmd, - dlCmd, - randrCmd, - blurCmd, - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_config.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_config.go deleted file mode 100644 index d604256..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_config.go +++ /dev/null @@ -1,318 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/spf13/cobra" -) - -var configCmd = &cobra.Command{ - Use: "config", - Short: "Configuration utilities", -} - -var resolveIncludeCmd = &cobra.Command{ - Use: "resolve-include ", - Short: "Check if a file is included in compositor config", - Long: "Recursively check if a file is included/sourced in compositor configuration. Returns JSON with exists and included status.", - Args: cobra.ExactArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - switch len(args) { - case 0: - return []string{"hyprland", "niri", "mangowc"}, cobra.ShellCompDirectiveNoFileComp - case 1: - return []string{"cursor.kdl", "cursor.conf", "outputs.kdl", "outputs.conf", "binds.kdl", "binds.conf"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runResolveInclude, -} - -func init() { - configCmd.AddCommand(resolveIncludeCmd) -} - -type IncludeResult struct { - Exists bool `json:"exists"` - Included bool `json:"included"` -} - -func runResolveInclude(cmd *cobra.Command, args []string) { - compositor := strings.ToLower(args[0]) - filename := args[1] - - var result IncludeResult - var err error - - switch compositor { - case "hyprland": - result, err = checkHyprlandInclude(filename) - case "niri": - result, err = checkNiriInclude(filename) - case "mangowc", "dwl", "mango": - result, err = checkMangoWCInclude(filename) - default: - log.Fatalf("Unknown compositor: %s", compositor) - } - - if err != nil { - log.Fatalf("Error checking include: %v", err) - } - - output, _ := json.Marshal(result) - fmt.Fprintln(os.Stdout, string(output)) -} - -func checkHyprlandInclude(filename string) (IncludeResult, error) { - configDir, err := utils.ExpandPath("$HOME/.config/hypr") - if err != nil { - return IncludeResult{}, err - } - - targetPath := filepath.Join(configDir, "dms", filename) - result := IncludeResult{} - - if _, err := os.Stat(targetPath); err == nil { - result.Exists = true - } - - mainConfig := filepath.Join(configDir, "hyprland.conf") - if _, err := os.Stat(mainConfig); os.IsNotExist(err) { - return result, nil - } - - processed := make(map[string]bool) - result.Included = hyprlandFindInclude(mainConfig, "dms/"+filename, processed) - return result, nil -} - -func hyprlandFindInclude(filePath, target string, processed map[string]bool) bool { - absPath, err := filepath.Abs(filePath) - if err != nil { - return false - } - - if processed[absPath] { - return false - } - processed[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return false - } - - baseDir := filepath.Dir(absPath) - lines := strings.Split(string(data), "\n") - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "#") || trimmed == "" { - continue - } - - if !strings.HasPrefix(trimmed, "source") { - continue - } - - parts := strings.SplitN(trimmed, "=", 2) - if len(parts) < 2 { - continue - } - - sourcePath := strings.TrimSpace(parts[1]) - if matchesTarget(sourcePath, target) { - return true - } - - fullPath := sourcePath - if !filepath.IsAbs(sourcePath) { - fullPath = filepath.Join(baseDir, sourcePath) - } - - expanded, err := utils.ExpandPath(fullPath) - if err != nil { - continue - } - - if hyprlandFindInclude(expanded, target, processed) { - return true - } - } - - return false -} - -func checkNiriInclude(filename string) (IncludeResult, error) { - configDir, err := utils.ExpandPath("$HOME/.config/niri") - if err != nil { - return IncludeResult{}, err - } - - targetPath := filepath.Join(configDir, "dms", filename) - result := IncludeResult{} - - if _, err := os.Stat(targetPath); err == nil { - result.Exists = true - } - - mainConfig := filepath.Join(configDir, "config.kdl") - if _, err := os.Stat(mainConfig); os.IsNotExist(err) { - return result, nil - } - - processed := make(map[string]bool) - result.Included = niriFindInclude(mainConfig, "dms/"+filename, processed) - return result, nil -} - -func niriFindInclude(filePath, target string, processed map[string]bool) bool { - absPath, err := filepath.Abs(filePath) - if err != nil { - return false - } - - if processed[absPath] { - return false - } - processed[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return false - } - - baseDir := filepath.Dir(absPath) - content := string(data) - - for _, line := range strings.Split(content, "\n") { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "//") || trimmed == "" { - continue - } - - if !strings.HasPrefix(trimmed, "include") { - continue - } - - startQuote := strings.Index(trimmed, "\"") - if startQuote == -1 { - continue - } - endQuote := strings.LastIndex(trimmed, "\"") - if endQuote <= startQuote { - continue - } - - includePath := trimmed[startQuote+1 : endQuote] - if matchesTarget(includePath, target) { - return true - } - - fullPath := includePath - if !filepath.IsAbs(includePath) { - fullPath = filepath.Join(baseDir, includePath) - } - - if niriFindInclude(fullPath, target, processed) { - return true - } - } - - return false -} - -func checkMangoWCInclude(filename string) (IncludeResult, error) { - configDir, err := utils.ExpandPath("$HOME/.config/mango") - if err != nil { - return IncludeResult{}, err - } - - targetPath := filepath.Join(configDir, "dms", filename) - result := IncludeResult{} - - if _, err := os.Stat(targetPath); err == nil { - result.Exists = true - } - - mainConfig := filepath.Join(configDir, "config.conf") - if _, err := os.Stat(mainConfig); os.IsNotExist(err) { - mainConfig = filepath.Join(configDir, "mango.conf") - } - if _, err := os.Stat(mainConfig); os.IsNotExist(err) { - return result, nil - } - - processed := make(map[string]bool) - result.Included = mangowcFindInclude(mainConfig, "dms/"+filename, processed) - return result, nil -} - -func mangowcFindInclude(filePath, target string, processed map[string]bool) bool { - absPath, err := filepath.Abs(filePath) - if err != nil { - return false - } - - if processed[absPath] { - return false - } - processed[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return false - } - - baseDir := filepath.Dir(absPath) - lines := strings.Split(string(data), "\n") - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "#") || trimmed == "" { - continue - } - - if !strings.HasPrefix(trimmed, "source") { - continue - } - - parts := strings.SplitN(trimmed, "=", 2) - if len(parts) < 2 { - continue - } - - sourcePath := strings.TrimSpace(parts[1]) - if matchesTarget(sourcePath, target) { - return true - } - - fullPath := sourcePath - if !filepath.IsAbs(sourcePath) { - fullPath = filepath.Join(baseDir, sourcePath) - } - - expanded, err := utils.ExpandPath(fullPath) - if err != nil { - continue - } - - if mangowcFindInclude(expanded, target, processed) { - return true - } - } - - return false -} - -func matchesTarget(path, target string) bool { - path = strings.TrimPrefix(path, "./") - target = strings.TrimPrefix(target, "./") - return path == target || strings.HasSuffix(path, "/"+target) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dank16.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dank16.go deleted file mode 100644 index 0bbbab1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dank16.go +++ /dev/null @@ -1,126 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/dank16" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/cobra" -) - -var dank16Cmd = &cobra.Command{ - Use: "dank16 [hex_color]", - Short: "Generate Base16 color palettes", - Long: "Generate Base16 color palettes from a color with support for various output formats", - Args: cobra.MaximumNArgs(1), - Run: runDank16, -} - -func init() { - dank16Cmd.Flags().Bool("light", false, "Generate light theme variant (sets default to light)") - dank16Cmd.Flags().Bool("json", false, "Output in JSON format") - dank16Cmd.Flags().Bool("kitty", false, "Output in Kitty terminal format") - dank16Cmd.Flags().Bool("foot", false, "Output in Foot terminal format") - dank16Cmd.Flags().Bool("neovim", false, "Output in Neovim plugin format") - dank16Cmd.Flags().Bool("alacritty", false, "Output in Alacritty terminal format") - dank16Cmd.Flags().Bool("ghostty", false, "Output in Ghostty terminal format") - dank16Cmd.Flags().Bool("wezterm", false, "Output in Wezterm terminal format") - dank16Cmd.Flags().String("background", "", "Custom background color") - dank16Cmd.Flags().String("contrast", "dps", "Contrast algorithm: dps (Delta Phi Star, default) or wcag") - dank16Cmd.Flags().Bool("variants", false, "Output all variants (dark/light/default) in JSON") - dank16Cmd.Flags().String("primary-dark", "", "Primary color for dark mode (use with --variants)") - dank16Cmd.Flags().String("primary-light", "", "Primary color for light mode (use with --variants)") - _ = dank16Cmd.RegisterFlagCompletionFunc("contrast", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"dps", "wcag"}, cobra.ShellCompDirectiveNoFileComp - }) -} - -func runDank16(cmd *cobra.Command, args []string) { - isLight, _ := cmd.Flags().GetBool("light") - isJson, _ := cmd.Flags().GetBool("json") - isKitty, _ := cmd.Flags().GetBool("kitty") - isFoot, _ := cmd.Flags().GetBool("foot") - isNeovim, _ := cmd.Flags().GetBool("neovim") - isAlacritty, _ := cmd.Flags().GetBool("alacritty") - isGhostty, _ := cmd.Flags().GetBool("ghostty") - isWezterm, _ := cmd.Flags().GetBool("wezterm") - background, _ := cmd.Flags().GetString("background") - contrastAlgo, _ := cmd.Flags().GetString("contrast") - useVariants, _ := cmd.Flags().GetBool("variants") - primaryDark, _ := cmd.Flags().GetString("primary-dark") - primaryLight, _ := cmd.Flags().GetString("primary-light") - - if background != "" && !strings.HasPrefix(background, "#") { - background = "#" + background - } - if primaryDark != "" && !strings.HasPrefix(primaryDark, "#") { - primaryDark = "#" + primaryDark - } - if primaryLight != "" && !strings.HasPrefix(primaryLight, "#") { - primaryLight = "#" + primaryLight - } - - contrastAlgo = strings.ToLower(contrastAlgo) - if contrastAlgo != "dps" && contrastAlgo != "wcag" { - log.Fatalf("Invalid contrast algorithm: %s (must be 'dps' or 'wcag')", contrastAlgo) - } - - if useVariants { - if primaryDark == "" || primaryLight == "" { - if len(args) == 0 { - log.Fatalf("--variants requires either a positional color argument or both --primary-dark and --primary-light") - } - primaryColor := args[0] - if !strings.HasPrefix(primaryColor, "#") { - primaryColor = "#" + primaryColor - } - primaryDark = primaryColor - primaryLight = primaryColor - } - variantOpts := dank16.VariantOptions{ - PrimaryDark: primaryDark, - PrimaryLight: primaryLight, - Background: background, - UseDPS: contrastAlgo == "dps", - IsLightMode: isLight, - } - variantColors := dank16.GenerateVariantPalette(variantOpts) - fmt.Print(dank16.GenerateVariantJSON(variantColors)) - return - } - - if len(args) == 0 { - log.Fatalf("A color argument is required (or use --variants with --primary-dark and --primary-light)") - } - primaryColor := args[0] - if !strings.HasPrefix(primaryColor, "#") { - primaryColor = "#" + primaryColor - } - - opts := dank16.PaletteOptions{ - IsLight: isLight, - Background: background, - UseDPS: contrastAlgo == "dps", - } - - colors := dank16.GeneratePalette(primaryColor, opts) - - if isJson { - fmt.Print(dank16.GenerateJSON(colors)) - } else if isKitty { - fmt.Print(dank16.GenerateKittyTheme(colors)) - } else if isFoot { - fmt.Print(dank16.GenerateFootTheme(colors)) - } else if isAlacritty { - fmt.Print(dank16.GenerateAlacrittyTheme(colors)) - } else if isGhostty { - fmt.Print(dank16.GenerateGhosttyTheme(colors)) - } else if isWezterm { - fmt.Print(dank16.GenerateWeztermTheme(colors)) - } else if isNeovim { - fmt.Print(dank16.GenerateNeovimTheme(colors)) - } else { - fmt.Print(dank16.GenerateGhosttyTheme(colors)) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_doctor.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_doctor.go deleted file mode 100644 index b182d06..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_doctor.go +++ /dev/null @@ -1,1107 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "slices" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - "github.com/AvengeMedia/DankMaterialShell/core/internal/tui" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/AvengeMedia/DankMaterialShell/core/internal/version" - "github.com/charmbracelet/lipgloss" - "github.com/spf13/cobra" -) - -type status string - -const ( - statusOK status = "ok" - statusWarn status = "warn" - statusError status = "error" - statusInfo status = "info" -) - -func (s status) IconStyle(styles tui.Styles) (string, lipgloss.Style) { - switch s { - case statusOK: - return "●", styles.Success - case statusWarn: - return "●", styles.Warning - case statusError: - return "●", styles.Error - default: - return "○", styles.Subtle - } -} - -type DoctorStatus struct { - Errors []checkResult - Warnings []checkResult - OK []checkResult - Info []checkResult -} - -func (ds *DoctorStatus) Add(r checkResult) { - switch r.status { - case statusError: - ds.Errors = append(ds.Errors, r) - case statusWarn: - ds.Warnings = append(ds.Warnings, r) - case statusOK: - ds.OK = append(ds.OK, r) - case statusInfo: - ds.Info = append(ds.Info, r) - } -} - -func (ds *DoctorStatus) HasIssues() bool { - return len(ds.Errors) > 0 || len(ds.Warnings) > 0 -} - -func (ds *DoctorStatus) ErrorCount() int { - return len(ds.Errors) -} - -func (ds *DoctorStatus) WarningCount() int { - return len(ds.Warnings) -} - -func (ds *DoctorStatus) OKCount() int { - return len(ds.OK) -} - -var ( - quickshellVersionRegex = regexp.MustCompile(`(?i)quickshell (\d+\.\d+\.\d+)`) - hyprlandVersionRegex = regexp.MustCompile(`v?(\d+\.\d+\.\d+)`) - niriVersionRegex = regexp.MustCompile(`niri (\d+\.\d+)`) - swayVersionRegex = regexp.MustCompile(`sway version (\d+\.\d+)`) - riverVersionRegex = regexp.MustCompile(`river (\d+\.\d+)`) - wayfireVersionRegex = regexp.MustCompile(`wayfire (\d+\.\d+)`) - labwcVersionRegex = regexp.MustCompile(`labwc (\d+\.\d+\.\d+)`) - mangowcVersionRegex = regexp.MustCompile(`mango (\d+\.\d+\.\d+)`) -) - -var doctorCmd = &cobra.Command{ - Use: "doctor", - Short: "Diagnose DMS installation and dependencies", - Long: "Check system health, verify dependencies, and diagnose configuration issues for DMS", - Run: runDoctor, -} - -var ( - doctorVerbose bool - doctorJSON bool - doctorCopy bool -) - -func init() { - doctorCmd.Flags().BoolVarP(&doctorVerbose, "verbose", "v", false, "Show detailed output including paths and versions") - doctorCmd.Flags().BoolVarP(&doctorJSON, "json", "j", false, "Output results in JSON format") - doctorCmd.Flags().BoolVarP(&doctorCopy, "copy", "C", false, "Copy results to clipboard in GitHub-friendly format") -} - -type category int - -const ( - catSystem category = iota - catVersions - catInstallation - catCompositor - catQuickshellFeatures - catOptionalFeatures - catConfigFiles - catServices - catEnvironment -) - -func (c category) String() string { - switch c { - case catSystem: - return "System" - case catVersions: - return "Versions" - case catInstallation: - return "Installation" - case catCompositor: - return "Compositor" - case catQuickshellFeatures: - return "Quickshell Features" - case catOptionalFeatures: - return "Optional Features" - case catConfigFiles: - return "Config Files" - case catServices: - return "Services" - case catEnvironment: - return "Environment" - default: - return "Unknown" - } -} - -const ( - checkNameMaxLength = 21 - doctorDocsURL = "https://danklinux.com/docs/dankmaterialshell/cli-doctor" -) - -type checkResult struct { - category category - name string - status status - message string - details string - url string -} - -type checkResultJSON struct { - Category string `json:"category"` - Name string `json:"name"` - Status string `json:"status"` - Message string `json:"message"` - Details string `json:"details,omitempty"` - URL string `json:"url,omitempty"` -} - -type doctorOutputJSON struct { - Summary struct { - Errors int `json:"errors"` - Warnings int `json:"warnings"` - OK int `json:"ok"` - Info int `json:"info"` - } `json:"summary"` - Results []checkResultJSON `json:"results"` -} - -func (r checkResult) toJSON() checkResultJSON { - return checkResultJSON{ - Category: r.category.String(), - Name: r.name, - Status: string(r.status), - Message: r.message, - Details: r.details, - URL: r.url, - } -} - -func runDoctor(cmd *cobra.Command, args []string) { - if !doctorJSON && !doctorCopy { - printDoctorHeader() - } - - qsFeatures, qsMissingFeatures := checkQuickshellFeatures() - - results := slices.Concat( - checkSystemInfo(), - checkVersions(qsMissingFeatures), - checkDMSInstallation(), - checkWindowManagers(), - qsFeatures, - checkOptionalDependencies(), - checkConfigurationFiles(), - checkSystemdServices(), - checkEnvironmentVars(), - ) - - switch { - case doctorCopy: - text := formatResultsPlain(results) - if err := clipboard.CopyOpts([]byte(text), "text/plain;charset=utf-8", false, false); err != nil { - fmt.Fprintf(os.Stderr, "Failed to copy to clipboard: %v\n", err) - os.Exit(1) - } - fmt.Println("Doctor report copied to clipboard") - case doctorJSON: - printResultsJSON(results) - default: - printResults(results) - printSummary(results, qsMissingFeatures) - } -} - -func printDoctorHeader() { - theme := tui.TerminalTheme() - styles := tui.NewStyles(theme) - - fmt.Println(getThemedASCII()) - fmt.Println(styles.Title.Render("System Health Check")) - fmt.Println(styles.Subtle.Render("──────────────────────────────────────")) - fmt.Println() -} - -func checkSystemInfo() []checkResult { - var results []checkResult - - osInfo, err := distros.GetOSInfo() - if err != nil { - status, message, details := statusWarn, fmt.Sprintf("Unknown (%v)", err), "" - - if strings.Contains(err.Error(), "Unsupported distribution") { - osRelease := readOSRelease() - switch { - case osRelease["ID"] == "nixos": - status = statusOK - message = osRelease["PRETTY_NAME"] - if message == "" { - message = fmt.Sprintf("NixOS %s", osRelease["VERSION_ID"]) - } - details = "Supported for runtime (install via NixOS module or Flake)" - case osRelease["PRETTY_NAME"] != "": - message = fmt.Sprintf("%s (not supported by dms setup)", osRelease["PRETTY_NAME"]) - details = "DMS may work but automatic installation is not available" - } - } - - results = append(results, checkResult{catSystem, "Operating System", status, message, details, doctorDocsURL + "#operating-system"}) - } else { - status := statusOK - message := osInfo.PrettyName - if message == "" { - message = fmt.Sprintf("%s %s", osInfo.Distribution.ID, osInfo.VersionID) - } - if distros.IsUnsupportedDistro(osInfo.Distribution.ID, osInfo.VersionID) { - status = statusWarn - message += " (version may not be fully supported)" - } - results = append(results, checkResult{ - catSystem, "Operating System", status, message, - fmt.Sprintf("ID: %s, Version: %s, Arch: %s", osInfo.Distribution.ID, osInfo.VersionID, osInfo.Architecture), - doctorDocsURL + "#operating-system", - }) - } - - arch := runtime.GOARCH - archStatus := statusOK - if arch != "amd64" && arch != "arm64" { - archStatus = statusError - } - results = append(results, checkResult{catSystem, "Architecture", archStatus, arch, "", doctorDocsURL + "#architecture"}) - - waylandDisplay := os.Getenv("WAYLAND_DISPLAY") - xdgSessionType := os.Getenv("XDG_SESSION_TYPE") - - switch { - case waylandDisplay != "" || xdgSessionType == "wayland": - results = append(results, checkResult{ - catSystem, "Display Server", statusOK, "Wayland", - fmt.Sprintf("WAYLAND_DISPLAY=%s", waylandDisplay), - doctorDocsURL + "#display-server", - }) - case xdgSessionType == "x11": - results = append(results, checkResult{catSystem, "Display Server", statusError, "X11 (DMS requires Wayland)", "", doctorDocsURL + "#display-server"}) - default: - results = append(results, checkResult{ - catSystem, "Display Server", statusWarn, "Unknown (ensure you're running Wayland)", - fmt.Sprintf("XDG_SESSION_TYPE=%s", xdgSessionType), - doctorDocsURL + "#display-server", - }) - } - - return results -} - -func checkEnvironmentVars() []checkResult { - var results []checkResult - results = append(results, checkEnvVar("QT_QPA_PLATFORMTHEME")...) - results = append(results, checkEnvVar("QS_ICON_THEME")...) - return results -} - -func checkEnvVar(name string) []checkResult { - value := os.Getenv(name) - if value != "" { - return []checkResult{{catEnvironment, name, statusInfo, value, "", doctorDocsURL + "#environment-variables"}} - } - if doctorVerbose { - return []checkResult{{catEnvironment, name, statusInfo, "Not set", "", doctorDocsURL + "#environment-variables"}} - } - return nil -} - -func readOSRelease() map[string]string { - result := make(map[string]string) - data, err := os.ReadFile("/etc/os-release") - if err != nil { - return result - } - for line := range strings.SplitSeq(string(data), "\n") { - if parts := strings.SplitN(line, "=", 2); len(parts) == 2 { - result[parts[0]] = strings.Trim(parts[1], "\"") - } - } - return result -} - -func checkVersions(qsMissingFeatures bool) []checkResult { - dmsCliPath, _ := os.Executable() - dmsCliDetails := "" - if doctorVerbose { - dmsCliDetails = dmsCliPath - } - - results := []checkResult{ - {catVersions, "DMS CLI", statusOK, formatVersion(Version), dmsCliDetails, doctorDocsURL + "#dms-cli"}, - } - - qsVersion, qsStatus, qsPath := getQuickshellVersionInfo(qsMissingFeatures) - qsDetails := "" - if doctorVerbose && qsPath != "" { - qsDetails = qsPath - } - results = append(results, checkResult{catVersions, "Quickshell", qsStatus, qsVersion, qsDetails, doctorDocsURL + "#quickshell"}) - - dmsVersion, dmsPath := getDMSShellVersion() - if dmsVersion != "" { - results = append(results, checkResult{catVersions, "DMS Shell", statusOK, dmsVersion, dmsPath, doctorDocsURL + "#dms-shell"}) - } else { - results = append(results, checkResult{catVersions, "DMS Shell", statusError, "Not installed or not detected", "Run 'dms setup' to install", doctorDocsURL + "#dms-shell"}) - } - - return results -} - -func getDMSShellVersion() (version, path string) { - if err := findConfig(nil, nil); err == nil && configPath != "" { - versionFile := filepath.Join(configPath, "VERSION") - if data, err := os.ReadFile(versionFile); err == nil { - return strings.TrimSpace(string(data)), configPath - } - return "installed", configPath - } - - if dmsPath, err := config.LocateDMSConfig(); err == nil { - versionFile := filepath.Join(dmsPath, "VERSION") - if data, err := os.ReadFile(versionFile); err == nil { - return strings.TrimSpace(string(data)), dmsPath - } - return "installed", dmsPath - } - - return "", "" -} - -func getQuickshellVersionInfo(missingFeatures bool) (string, status, string) { - if !utils.CommandExists("qs") { - return "Not installed", statusError, "" - } - - qsPath, _ := exec.LookPath("qs") - - output, err := exec.Command("qs", "--version").Output() - if err != nil { - return "Installed (version check failed)", statusWarn, qsPath - } - - fullVersion := strings.TrimSpace(string(output)) - if matches := quickshellVersionRegex.FindStringSubmatch(fullVersion); len(matches) >= 2 { - if version.CompareVersions(matches[1], "0.2.0") < 0 { - return fmt.Sprintf("%s (needs >= 0.2.0)", fullVersion), statusError, qsPath - } - if missingFeatures { - return fullVersion, statusWarn, qsPath - } - return fullVersion, statusOK, qsPath - } - - return fullVersion, statusWarn, qsPath -} - -func checkDMSInstallation() []checkResult { - var results []checkResult - - dmsPath := "" - if err := findConfig(nil, nil); err == nil && configPath != "" { - dmsPath = configPath - } else if path, err := config.LocateDMSConfig(); err == nil { - dmsPath = path - } - - if dmsPath == "" { - return []checkResult{{catInstallation, "DMS Configuration", statusError, "Not found", "shell.qml not found in any config path", doctorDocsURL + "#dms-configuration"}} - } - - results = append(results, checkResult{catInstallation, "DMS Configuration", statusOK, "Found", dmsPath, doctorDocsURL + "#dms-configuration"}) - - shellQml := filepath.Join(dmsPath, "shell.qml") - if _, err := os.Stat(shellQml); err != nil { - results = append(results, checkResult{catInstallation, "shell.qml", statusError, "Missing", shellQml, doctorDocsURL + "#dms-configuration"}) - } else { - results = append(results, checkResult{catInstallation, "shell.qml", statusOK, "Present", shellQml, doctorDocsURL + "#dms-configuration"}) - } - - if doctorVerbose { - installType := "Unknown" - switch { - case strings.Contains(dmsPath, "/nix/store"): - installType = "Nix store" - case strings.Contains(dmsPath, ".local/share") || strings.Contains(dmsPath, "/usr/share"): - installType = "System package" - case strings.Contains(dmsPath, ".config"): - installType = "User config" - } - results = append(results, checkResult{catInstallation, "Install Type", statusInfo, installType, dmsPath, doctorDocsURL + "#dms-configuration"}) - } - - return results -} - -func checkWindowManagers() []checkResult { - compositors := []struct { - name, versionCmd, versionArg string - versionRegex *regexp.Regexp - commands []string - }{ - {"Hyprland", "Hyprland", "--version", hyprlandVersionRegex, []string{"hyprland", "Hyprland"}}, - {"niri", "niri", "--version", niriVersionRegex, []string{"niri"}}, - {"Sway", "sway", "--version", swayVersionRegex, []string{"sway"}}, - {"River", "river", "-version", riverVersionRegex, []string{"river"}}, - {"Wayfire", "wayfire", "--version", wayfireVersionRegex, []string{"wayfire"}}, - {"labwc", "labwc", "--version", labwcVersionRegex, []string{"labwc"}}, - {"mangowc", "mango", "-v", mangowcVersionRegex, []string{"mango"}}, - } - - var results []checkResult - foundAny := false - - for _, c := range compositors { - if !slices.ContainsFunc(c.commands, utils.CommandExists) { - continue - } - foundAny = true - var compositorPath string - for _, cmd := range c.commands { - if path, err := exec.LookPath(cmd); err == nil { - compositorPath = path - break - } - } - details := "" - if doctorVerbose && compositorPath != "" { - details = compositorPath - } - results = append(results, checkResult{ - catCompositor, c.name, statusOK, - getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details, - doctorDocsURL + "#compositor-checks", - }) - } - - if !foundAny { - results = append(results, checkResult{ - catCompositor, "Compositor", statusError, - "No supported Wayland compositor found", - "Install Hyprland, niri, Sway, River, or Wayfire", - doctorDocsURL + "#compositor-checks", - }) - } - - if wm := detectRunningWM(); wm != "" { - results = append(results, checkResult{catCompositor, "Active", statusInfo, wm, "", doctorDocsURL + "#compositor"}) - } - - return results -} - -func getVersionFromCommand(cmd, arg string, regex *regexp.Regexp) string { - output, err := exec.Command(cmd, arg).CombinedOutput() - if err != nil && len(output) == 0 { - return "installed" - } - - outStr := string(output) - if matches := regex.FindStringSubmatch(outStr); len(matches) > 1 { - ver := matches[1] - if strings.Contains(outStr, "git") || strings.Contains(outStr, "dirty") { - return ver + " (git)" - } - return ver - } - return strings.TrimSpace(outStr) -} - -func detectRunningWM() string { - switch { - case os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "": - return "Hyprland" - case os.Getenv("NIRI_SOCKET") != "": - return "niri" - case os.Getenv("XDG_CURRENT_DESKTOP") != "": - return os.Getenv("XDG_CURRENT_DESKTOP") - } - return "" -} - -func checkQuickshellFeatures() ([]checkResult, bool) { - if !utils.CommandExists("qs") { - return nil, false - } - - tmpDir := os.TempDir() - testScript := filepath.Join(tmpDir, "qs-feature-test.qml") - defer os.Remove(testScript) - - qmlContent := ` -import QtQuick -import Quickshell - -ShellRoot { - id: root - - property bool polkitAvailable: false - property bool idleMonitorAvailable: false - property bool idleInhibitorAvailable: false - property bool shortcutInhibitorAvailable: false - - Timer { - interval: 50 - running: true - repeat: false - onTriggered: { - try { - var polkitTest = Qt.createQmlObject( - 'import Quickshell.Services.Polkit; import QtQuick; Item {}', - root - ) - root.polkitAvailable = true - polkitTest.destroy() - } catch (e) {} - - try { - var testItem = Qt.createQmlObject( - 'import Quickshell.Wayland; import QtQuick; QtObject { ' + - 'readonly property bool hasIdleMonitor: typeof IdleMonitor !== "undefined"; ' + - 'readonly property bool hasIdleInhibitor: typeof IdleInhibitor !== "undefined"; ' + - 'readonly property bool hasShortcutInhibitor: typeof ShortcutInhibitor !== "undefined" ' + - '}', - root - ) - root.idleMonitorAvailable = testItem.hasIdleMonitor - root.idleInhibitorAvailable = testItem.hasIdleInhibitor - root.shortcutInhibitorAvailable = testItem.hasShortcutInhibitor - testItem.destroy() - } catch (e) {} - - console.warn(root.polkitAvailable ? "FEATURE:Polkit:OK" : "FEATURE:Polkit:UNAVAILABLE") - console.warn(root.idleMonitorAvailable ? "FEATURE:IdleMonitor:OK" : "FEATURE:IdleMonitor:UNAVAILABLE") - console.warn(root.idleInhibitorAvailable ? "FEATURE:IdleInhibitor:OK" : "FEATURE:IdleInhibitor:UNAVAILABLE") - console.warn(root.shortcutInhibitorAvailable ? "FEATURE:ShortcutInhibitor:OK" : "FEATURE:ShortcutInhibitor:UNAVAILABLE") - - Quickshell.execDetached(["kill", "-TERM", String(Quickshell.processId)]) - } - } -} -` - - if err := os.WriteFile(testScript, []byte(qmlContent), 0o644); err != nil { - return nil, false - } - - cmd := exec.Command("qs", "-p", testScript) - cmd.Env = append(os.Environ(), "NO_COLOR=1") - output, _ := cmd.CombinedOutput() - outputStr := string(output) - - features := []struct{ name, desc string }{ - {"Polkit", "Authentication prompts"}, - {"IdleMonitor", "Idle detection"}, - {"IdleInhibitor", "Prevent idle/sleep"}, - {"ShortcutInhibitor", "Allow shortcut management (niri)"}, - } - - var results []checkResult - missingFeatures := false - - for _, f := range features { - available := strings.Contains(outputStr, fmt.Sprintf("FEATURE:%s:OK", f.name)) - status, message := statusOK, "Available" - if !available { - status, message = statusInfo, "Not available" - missingFeatures = true - } - results = append(results, checkResult{catQuickshellFeatures, f.name, status, message, f.desc, doctorDocsURL + "#quickshell-features"}) - } - - return results, missingFeatures -} - -func checkI2CAvailability() checkResult { - ddc, err := brightness.NewDDCBackend() - if err != nil { - return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "Not available", "External monitor brightness control", doctorDocsURL + "#optional-features"} - } - defer ddc.Close() - - devices, err := ddc.GetDevices() - if err != nil || len(devices) == 0 { - return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "No monitors detected", "External monitor brightness control", doctorDocsURL + "#optional-features"} - } - - return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"} -} - -func checkImageFormatPlugins() []checkResult { - url := doctorDocsURL + "#optional-features" - - pluginDirs := findQtPluginDirs() - if len(pluginDirs) == 0 { - return []checkResult{ - {catOptionalFeatures, "qt6-imageformats", statusInfo, "Cannot detect (plugin dir not found)", "WebP, TIFF, JP2 support", url}, - {catOptionalFeatures, "kimageformats", statusInfo, "Cannot detect (plugin dir not found)", "AVIF, HEIF, JXL support", url}, - } - } - - type pluginCheck struct { - name string - desc string - plugins []struct{ file, format string } - } - - checks := []pluginCheck{ - { - name: "qt6-imageformats", - desc: "WebP, TIFF, GIF, JP2 support", - plugins: []struct{ file, format string }{ - {"libqwebp.so", "WebP"}, - {"libqtiff.so", "TIFF"}, - {"libqgif.so", "GIF"}, - {"libqjp2.so", "JP2"}, - {"libqicns.so", "ICNS"}, - }, - }, - { - name: "kimageformats", - desc: "AVIF, HEIF, JXL support", - plugins: []struct{ file, format string }{ - {"kimg_avif.so", "AVIF"}, - {"kimg_heif.so", "HEIF"}, - {"kimg_jxl.so", "JXL"}, - {"kimg_exr.so", "EXR"}, - }, - }, - } - - var results []checkResult - for _, c := range checks { - var found []string - var foundDirs []string - for _, pluginDir := range pluginDirs { - imageFormatsDir := filepath.Join(pluginDir, "imageformats") - for _, p := range c.plugins { - if _, err := os.Stat(filepath.Join(imageFormatsDir, p.file)); err == nil { - if !slices.Contains(found, p.format) { - found = append(found, p.format) - } - if !slices.Contains(foundDirs, imageFormatsDir) { - foundDirs = append(foundDirs, imageFormatsDir) - } - } - } - } - - var result checkResult - switch { - case len(found) == 0: - result = checkResult{catOptionalFeatures, c.name, statusWarn, "Not installed", c.desc, url} - default: - details := "" - if doctorVerbose { - details = fmt.Sprintf("Formats: %s (%s)", strings.Join(found, ", "), strings.Join(foundDirs, ":")) - } - result = checkResult{catOptionalFeatures, c.name, statusOK, fmt.Sprintf("Installed (%d formats)", len(found)), details, url} - } - results = append(results, result) - } - - return results -} - -func findQtPluginDirs() []string { - var dirs []string - - addDir := func(dir string) { - if dir != "" { - if _, err := os.Stat(filepath.Join(dir, "imageformats")); err == nil { - dirs = append(dirs, dir) - } - } - } - - // Check all paths in QT_PLUGIN_PATH env var (used by NixOS and custom setups) - if envPath := os.Getenv("QT_PLUGIN_PATH"); envPath != "" { - for dir := range strings.SplitSeq(envPath, ":") { - addDir(dir) - } - } - - // Try qtpaths - for _, cmd := range []string{"qtpaths6", "qtpaths"} { - if output, err := exec.Command(cmd, "-query", "QT_INSTALL_PLUGINS").Output(); err == nil { - addDir(strings.TrimSpace(string(output))) - } - } - - // Fallback: common distro paths - for _, dir := range []string{ - "/usr/lib/qt6/plugins", - "/usr/lib64/qt6/plugins", - "/usr/lib/x86_64-linux-gnu/qt6/plugins", - "/usr/lib/aarch64-linux-gnu/qt6/plugins", - } { - addDir(dir) - } - - return dirs -} - -func detectNetworkBackend(stackResult *network.DetectResult) string { - switch stackResult.Backend { - case network.BackendNetworkManager: - return "NetworkManager" - case network.BackendIwd: - return "iwd" - case network.BackendNetworkd: - if stackResult.HasIwd { - return "iwd + systemd-networkd" - } - return "systemd-networkd" - case network.BackendConnMan: - return "ConnMan" - default: - return "" - } -} - -func getOptionalDBusStatus(busName string) (status, string) { - if utils.IsDBusServiceAvailable(busName) { - return statusOK, "Available" - } else { - return statusWarn, "Not available" - } -} - -func checkOptionalDependencies() []checkResult { - var results []checkResult - - optionalFeaturesURL := doctorDocsURL + "#optional-features" - - accountsStatus, accountsMsg := getOptionalDBusStatus("org.freedesktop.Accounts") - results = append(results, checkResult{catOptionalFeatures, "accountsservice", accountsStatus, accountsMsg, "User accounts", optionalFeaturesURL}) - - ppdStatus, ppdMsg := getOptionalDBusStatus("org.freedesktop.UPower.PowerProfiles") - results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", ppdStatus, ppdMsg, "Power profile management", optionalFeaturesURL}) - - logindStatus, logindMsg := getOptionalDBusStatus("org.freedesktop.login1") - results = append(results, checkResult{catOptionalFeatures, "logind", logindStatus, logindMsg, "Session management", optionalFeaturesURL}) - - cupsPkHelperBus := "org.opensuse.CupsPkHelper.Mechanism" - var cupsPkStatus status - var cupsPkMsg string - switch { - case utils.IsDBusServiceAvailable(cupsPkHelperBus): - cupsPkStatus, cupsPkMsg = statusOK, "Running" - case utils.IsDBusServiceActivatable(cupsPkHelperBus): - cupsPkStatus, cupsPkMsg = statusOK, "Available" - default: - cupsPkStatus, cupsPkMsg = statusWarn, "Not available (install cups-pk-helper)" - } - results = append(results, checkResult{catOptionalFeatures, "cups-pk-helper", cupsPkStatus, cupsPkMsg, "Printer management", optionalFeaturesURL}) - - results = append(results, checkI2CAvailability()) - results = append(results, checkImageFormatPlugins()...) - - terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"} - terminals = slices.DeleteFunc(terminals, func(t string) bool { - return !utils.CommandExists(t) - }) - - if len(terminals) > 0 { - results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, strings.Join(terminals, ", "), "", optionalFeaturesURL}) - } else { - results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, foot or alacritty", optionalFeaturesURL}) - } - - networkResult, err := network.DetectNetworkStack() - networkStatus, networkMessage, networkDetails := statusOK, "Not available", "Network management" - - if err == nil && networkResult.Backend != network.BackendNone { - networkMessage = detectNetworkBackend(networkResult) - if doctorVerbose { - networkDetails = networkResult.ChosenReason - } - } else { - networkStatus = statusInfo - } - - results = append(results, checkResult{catOptionalFeatures, "Network", networkStatus, networkMessage, networkDetails, optionalFeaturesURL}) - - deps := []struct { - name, cmd, desc string - important bool - }{ - {"matugen", "matugen", "Dynamic theming", true}, - {"dgop", "dgop", "System monitoring", true}, - {"cava", "cava", "Audio visualizer", true}, - {"khal", "khal", "Calendar events", false}, - {"danksearch", "dsearch", "File search", false}, - {"fprintd", "fprintd-list", "Fingerprint auth", false}, - } - - for _, d := range deps { - found := utils.CommandExists(d.cmd) - - switch { - case found: - results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, "Installed", d.desc, optionalFeaturesURL}) - case d.important: - results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, optionalFeaturesURL}) - default: - results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, optionalFeaturesURL}) - } - } - - return results -} - -func checkConfigurationFiles() []checkResult { - configDir, _ := os.UserConfigDir() - cacheDir, _ := os.UserCacheDir() - dmsDir := "DankMaterialShell" - - configFiles := []struct{ name, path string }{ - {"settings.json", filepath.Join(configDir, dmsDir, "settings.json")}, - {"clsettings.json", filepath.Join(configDir, dmsDir, "clsettings.json")}, - {"plugin_settings.json", filepath.Join(configDir, dmsDir, "plugin_settings.json")}, - {"session.json", filepath.Join(utils.XDGStateHome(), dmsDir, "session.json")}, - {"dms-colors.json", filepath.Join(cacheDir, dmsDir, "dms-colors.json")}, - } - - var results []checkResult - for _, cf := range configFiles { - info, err := os.Stat(cf.path) - if err != nil { - results = append(results, checkResult{catConfigFiles, cf.name, statusInfo, "Not yet created", cf.path, doctorDocsURL + "#config-files"}) - continue - } - - status := statusOK - message := "Present" - if info.Mode().Perm()&0o200 == 0 { - status = statusWarn - message += " (read-only)" - } - results = append(results, checkResult{catConfigFiles, cf.name, status, message, cf.path, doctorDocsURL + "#config-files"}) - } - return results -} - -func checkSystemdServices() []checkResult { - if !utils.CommandExists("systemctl") { - return nil - } - - var results []checkResult - - dmsState := getServiceState("dms", true) - if !dmsState.exists { - results = append(results, checkResult{catServices, "dms.service", statusInfo, "Not installed", "Optional user service", doctorDocsURL + "#services"}) - } else { - status, message := statusOK, dmsState.enabled - if dmsState.active != "" { - message = fmt.Sprintf("%s, %s", dmsState.enabled, dmsState.active) - } - switch { - case dmsState.enabled == "disabled": - status, message = statusWarn, "Disabled" - case dmsState.active == "failed" || dmsState.active == "inactive": - status = statusError - } - results = append(results, checkResult{catServices, "dms.service", status, message, "", doctorDocsURL + "#services"}) - } - - greetdState := getServiceState("greetd", false) - switch { - case greetdState.exists: - status := statusOK - if greetdState.enabled == "disabled" { - status = statusInfo - } - results = append(results, checkResult{catServices, "greetd", status, greetdState.enabled, "", doctorDocsURL + "#services"}) - case doctorVerbose: - results = append(results, checkResult{catServices, "greetd", statusInfo, "Not installed", "Optional greeter service", doctorDocsURL + "#services"}) - } - - return results -} - -type serviceState struct { - exists bool - enabled string - active string -} - -func getServiceState(name string, userService bool) serviceState { - args := []string{"is-enabled", name} - if userService { - args = []string{"--user", "is-enabled", name} - } - - output, _ := exec.Command("systemctl", args...).Output() - enabled := strings.TrimSpace(string(output)) - - if enabled == "" || enabled == "not-found" { - return serviceState{} - } - - state := serviceState{exists: true, enabled: enabled} - - if userService { - output, _ = exec.Command("systemctl", "--user", "is-active", name).Output() - if active := strings.TrimSpace(string(output)); active != "" && active != "unknown" { - state.active = active - } - } - - return state -} - -func printResults(results []checkResult) { - theme := tui.TerminalTheme() - styles := tui.NewStyles(theme) - - currentCategory := category(-1) - for _, r := range results { - if r.category != currentCategory { - if currentCategory != -1 { - fmt.Println() - } - fmt.Printf(" %s\n", styles.Bold.Render(r.category.String())) - currentCategory = r.category - } - printResultLine(r, styles) - } -} - -func printResultsJSON(results []checkResult) { - var ds DoctorStatus - for _, r := range results { - ds.Add(r) - } - - output := doctorOutputJSON{} - output.Summary.Errors = ds.ErrorCount() - output.Summary.Warnings = ds.WarningCount() - output.Summary.OK = ds.OKCount() - output.Summary.Info = len(ds.Info) - - output.Results = make([]checkResultJSON, 0, len(results)) - for _, r := range results { - output.Results = append(output.Results, r.toJSON()) - } - - encoder := json.NewEncoder(os.Stdout) - encoder.SetIndent("", " ") - if err := encoder.Encode(output); err != nil { - fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err) - os.Exit(1) - } -} - -func printResultLine(r checkResult, styles tui.Styles) { - icon, style := r.status.IconStyle(styles) - - name := r.name - nameLen := len(name) - - if nameLen > checkNameMaxLength { - name = name[:checkNameMaxLength-1] + "…" - nameLen = checkNameMaxLength - } - dots := strings.Repeat("·", checkNameMaxLength-nameLen) - - fmt.Printf(" %s %s %s %s\n", style.Render(icon), name, styles.Subtle.Render(dots), r.message) - - if doctorVerbose && r.details != "" { - fmt.Printf(" %s\n", styles.Subtle.Render("└─ "+r.details)) - } - - if (r.status == statusError || r.status == statusWarn) && r.url != "" { - fmt.Printf(" %s\n", styles.Subtle.Render("→ "+r.url)) - } -} - -func printSummary(results []checkResult, qsMissingFeatures bool) { - theme := tui.TerminalTheme() - styles := tui.NewStyles(theme) - - var ds DoctorStatus - for _, r := range results { - ds.Add(r) - } - - fmt.Println() - fmt.Printf(" %s\n", styles.Subtle.Render("──────────────────────────────────────")) - - if !ds.HasIssues() { - fmt.Printf(" %s\n", styles.Success.Render("✓ All checks passed!")) - } else { - var parts []string - - if ds.ErrorCount() > 0 { - parts = append(parts, styles.Error.Render(fmt.Sprintf("%d error(s)", ds.ErrorCount()))) - } - if ds.WarningCount() > 0 { - parts = append(parts, styles.Warning.Render(fmt.Sprintf("%d warning(s)", ds.WarningCount()))) - } - parts = append(parts, styles.Success.Render(fmt.Sprintf("%d ok", ds.OKCount()))) - fmt.Printf(" %s\n", strings.Join(parts, ", ")) - - if qsMissingFeatures { - fmt.Println() - fmt.Printf(" %s\n", styles.Subtle.Render("→ Consider using quickshell-git for full feature support")) - } - } - fmt.Println() -} - -func formatResultsPlain(results []checkResult) string { - var sb strings.Builder - sb.WriteString("## DMS Doctor Report\n\n") - - currentCategory := category(-1) - for _, r := range results { - if r.category != currentCategory { - if currentCategory != -1 { - sb.WriteString("\n") - } - fmt.Fprintf(&sb, "**%s**\n", r.category.String()) - currentCategory = r.category - } - - fmt.Fprintf(&sb, "- [%s] %s: %s\n", r.status, r.name, r.message) - - if doctorVerbose && r.details != "" { - fmt.Fprintf(&sb, " - %s\n", r.details) - } - } - - var ds DoctorStatus - for _, r := range results { - ds.Add(r) - } - - sb.WriteString("\n---\n") - fmt.Fprintf(&sb, "**Summary:** %d error(s), %d warning(s), %d ok\n", - ds.ErrorCount(), ds.WarningCount(), ds.OKCount()) - - return sb.String() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_download.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_download.go deleted file mode 100644 index e9caeb0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_download.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "net" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/spf13/cobra" -) - -var dlOutput string -var dlUserAgent string -var dlTimeout int -var dlIPv4Only bool - -var dlCmd = &cobra.Command{ - Use: "dl ", - Short: "Download a URL to stdout or file", - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - if err := runDownload(args[0]); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - }, -} - -func init() { - dlCmd.Flags().StringVarP(&dlOutput, "output", "o", "", "Output file path (default: stdout)") - dlCmd.Flags().StringVar(&dlUserAgent, "user-agent", "", "Custom User-Agent header") - dlCmd.Flags().IntVar(&dlTimeout, "timeout", 10, "Request timeout in seconds") - dlCmd.Flags().BoolVarP(&dlIPv4Only, "ipv4", "4", false, "Force IPv4 only") -} - -func runDownload(url string) error { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(dlTimeout)*time.Second) - defer cancel() - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return fmt.Errorf("invalid request: %w", err) - } - - switch { - case dlUserAgent != "": - req.Header.Set("User-Agent", dlUserAgent) - default: - req.Header.Set("User-Agent", "DankMaterialShell/1.0 (Linux)") - } - - dialer := &net.Dialer{Timeout: 5 * time.Second} - transport := &http.Transport{DialContext: dialer.DialContext} - if dlIPv4Only { - transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, "tcp4", addr) - } - } - client := &http.Client{Transport: transport} - - resp, err := client.Do(req) - if err != nil { - return fmt.Errorf("download failed: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("HTTP %d", resp.StatusCode) - } - - if dlOutput == "" { - _, err = io.Copy(os.Stdout, resp.Body) - return err - } - - if dir := filepath.Dir(dlOutput); dir != "." { - if err := os.MkdirAll(dir, 0755); err != nil { - return fmt.Errorf("mkdir failed: %w", err) - } - } - - f, err := os.Create(dlOutput) - if err != nil { - return fmt.Errorf("create failed: %w", err) - } - defer f.Close() - - if _, err := io.Copy(f, resp.Body); err != nil { - os.Remove(dlOutput) - return fmt.Errorf("write failed: %w", err) - } - - fmt.Println(dlOutput) - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dpms.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dpms.go deleted file mode 100644 index 77eff1a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_dpms.go +++ /dev/null @@ -1,105 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/cobra" -) - -var dpmsCmd = &cobra.Command{ - Use: "dpms", - Short: "Control display power management", -} - -var dpmsOnCmd = &cobra.Command{ - Use: "on [output]", - Short: "Turn display(s) on", - Args: cobra.MaximumNArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getDPMSOutputs(), cobra.ShellCompDirectiveNoFileComp - }, - Run: runDPMSOn, -} - -var dpmsOffCmd = &cobra.Command{ - Use: "off [output]", - Short: "Turn display(s) off", - Args: cobra.MaximumNArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getDPMSOutputs(), cobra.ShellCompDirectiveNoFileComp - }, - Run: runDPMSOff, -} - -var dpmsListCmd = &cobra.Command{ - Use: "list", - Short: "List outputs", - Args: cobra.NoArgs, - Run: runDPMSList, -} - -func init() { - dpmsCmd.AddCommand(dpmsOnCmd, dpmsOffCmd, dpmsListCmd) -} - -func runDPMSOn(cmd *cobra.Command, args []string) { - outputName := "" - if len(args) > 0 { - outputName = args[0] - } - - client, err := newDPMSClient() - if err != nil { - log.Fatalf("%v", err) - } - defer client.Close() - - if err := client.SetDPMS(outputName, true); err != nil { - log.Fatalf("%v", err) - } -} - -func runDPMSOff(cmd *cobra.Command, args []string) { - outputName := "" - if len(args) > 0 { - outputName = args[0] - } - - client, err := newDPMSClient() - if err != nil { - log.Fatalf("%v", err) - } - defer client.Close() - - if err := client.SetDPMS(outputName, false); err != nil { - log.Fatalf("%v", err) - } -} - -func getDPMSOutputs() []string { - client, err := newDPMSClient() - if err != nil { - return nil - } - defer client.Close() - return client.ListOutputs() -} - -func runDPMSList(cmd *cobra.Command, args []string) { - client, err := newDPMSClient() - if err != nil { - log.Fatalf("%v", err) - } - defer client.Close() - - for _, output := range client.ListOutputs() { - fmt.Println(output) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_features.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_features.go deleted file mode 100644 index 7ec5437..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_features.go +++ /dev/null @@ -1,491 +0,0 @@ -//go:build !distro_binary - -package main - -import ( - "bufio" - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/AvengeMedia/DankMaterialShell/core/internal/version" - "github.com/spf13/cobra" -) - -var updateCmd = &cobra.Command{ - Use: "update", - Short: "Update DankMaterialShell to the latest version", - Long: "Update DankMaterialShell to the latest version using the appropriate package manager for your distribution", - PreRunE: findConfig, - Run: func(cmd *cobra.Command, args []string) { - runUpdate() - }, -} - -var updateCheckCmd = &cobra.Command{ - Use: "check", - Short: "Check if updates are available for DankMaterialShell", - Long: "Check for available updates without performing the actual update", - Run: func(cmd *cobra.Command, args []string) { - runUpdateCheck() - }, -} - -func runUpdateCheck() { - fmt.Println("Checking for DankMaterialShell updates...") - fmt.Println() - - versionInfo, err := version.GetDMSVersionInfo() - if err != nil { - log.Fatalf("Error checking for updates: %v", err) - } - - fmt.Printf("Current version: %s\n", versionInfo.Current) - fmt.Printf("Latest version: %s\n", versionInfo.Latest) - fmt.Println() - - if versionInfo.HasUpdate { - fmt.Println("✓ Update available!") - fmt.Println() - fmt.Println("Run 'dms update' to install the latest version.") - os.Exit(0) - } else { - fmt.Println("✓ You are running the latest version.") - os.Exit(0) - } -} - -func runUpdate() { - osInfo, err := distros.GetOSInfo() - if err != nil { - log.Fatalf("Error detecting OS: %v", err) - } - - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - log.Fatalf("Unsupported distribution: %s", osInfo.Distribution.ID) - } - - var updateErr error - switch config.Family { - case distros.FamilyArch: - updateErr = updateArchLinux() - case distros.FamilySUSE: - updateErr = updateOtherDistros() - default: - updateErr = updateOtherDistros() - } - - if updateErr != nil { - if errors.Is(updateErr, errdefs.ErrUpdateCancelled) { - log.Info("Update cancelled.") - return - } - if errors.Is(updateErr, errdefs.ErrNoUpdateNeeded) { - return - } - log.Fatalf("Error updating DMS: %v", updateErr) - } - - log.Info("Update complete! Restarting DMS...") - restartShell() -} - -func updateArchLinux() error { - homeDir, err := os.UserHomeDir() - if err == nil { - dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms") - if _, err := os.Stat(dmsPath); err == nil { - return updateOtherDistros() - } - } - - var packageName string - var isAUR bool - if isArchPackageInstalled("dms-shell") { - packageName = "dms-shell" - } else if isArchPackageInstalled("dms-shell-git") { - packageName = "dms-shell-git" - isAUR = true - } else if isArchPackageInstalled("dms-shell-bin") { - packageName = "dms-shell-bin" - isAUR = true - } else { - fmt.Println("Info: No dms-shell package found.") - fmt.Println("Info: Falling back to git-based update method...") - return updateOtherDistros() - } - - if !isAUR { - fmt.Printf("This will update %s using pacman.\n", packageName) - if !confirmUpdate() { - return errdefs.ErrUpdateCancelled - } - - fmt.Printf("\nRunning: sudo pacman -S %s\n", packageName) - cmd := exec.Command("sudo", "pacman", "-S", "--noconfirm", packageName) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - fmt.Printf("Error: Failed to update using pacman: %v\n", err) - return err - } - - fmt.Println("dms successfully updated") - return nil - } - - var helper string - var updateCmd *exec.Cmd - - if utils.CommandExists("yay") { - helper = "yay" - updateCmd = exec.Command("yay", "-S", packageName) - } else if utils.CommandExists("paru") { - helper = "paru" - updateCmd = exec.Command("paru", "-S", packageName) - } else { - fmt.Println("Error: Neither yay nor paru found - please install an AUR helper") - fmt.Println("Info: Falling back to git-based update method...") - return updateOtherDistros() - } - - fmt.Printf("This will update DankMaterialShell using %s.\n", helper) - if !confirmUpdate() { - return errdefs.ErrUpdateCancelled - } - - fmt.Printf("\nRunning: %s -S %s\n", helper, packageName) - updateCmd.Stdout = os.Stdout - updateCmd.Stderr = os.Stderr - err = updateCmd.Run() - if err != nil { - fmt.Printf("Error: Failed to update using %s: %v\n", helper, err) - } - - fmt.Println("dms successfully updated") - return nil -} - -func updateOtherDistros() error { - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms") - - if _, err := os.Stat(dmsPath); os.IsNotExist(err) { - return fmt.Errorf("DMS configuration directory not found at %s", dmsPath) - } - - fmt.Printf("Found DMS configuration at %s\n", dmsPath) - - versionInfo, err := version.GetDMSVersionInfo() - if err == nil && !versionInfo.HasUpdate { - fmt.Println() - fmt.Printf("Current version: %s\n", versionInfo.Current) - fmt.Printf("Latest version: %s\n", versionInfo.Latest) - fmt.Println() - fmt.Println("✓ You are already running the latest version.") - return errdefs.ErrNoUpdateNeeded - } - - fmt.Println("\nThis will update:") - fmt.Println(" 1. The dms binary from GitHub releases") - fmt.Println(" 2. DankMaterialShell configuration using git") - if !confirmUpdate() { - return errdefs.ErrUpdateCancelled - } - - fmt.Println("\n=== Updating dms binary ===") - if err := updateDMSBinary(); err != nil { - fmt.Printf("Warning: Failed to update dms binary: %v\n", err) - fmt.Println("Continuing with shell configuration update...") - } else { - fmt.Println("dms binary successfully updated") - } - - fmt.Println("\n=== Updating DMS shell configuration ===") - - if err := os.Chdir(dmsPath); err != nil { - return fmt.Errorf("failed to change to DMS directory: %w", err) - } - - statusCmd := exec.Command("git", "status", "--porcelain") - statusOutput, _ := statusCmd.Output() - hasLocalChanges := len(strings.TrimSpace(string(statusOutput))) > 0 - - currentRefCmd := exec.Command("git", "symbolic-ref", "-q", "HEAD") - currentRefOutput, _ := currentRefCmd.Output() - onBranch := len(currentRefOutput) > 0 - - var currentTag string - var currentBranch string - - if !onBranch { - tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD") - if tagOutput, err := tagCmd.Output(); err == nil { - currentTag = strings.TrimSpace(string(tagOutput)) - } - } else { - branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") - if branchOutput, err := branchCmd.Output(); err == nil { - currentBranch = strings.TrimSpace(string(branchOutput)) - } - } - - fmt.Println("Fetching latest changes...") - fetchCmd := exec.Command("git", "fetch", "origin", "--tags", "--force") - fetchCmd.Stdout = os.Stdout - fetchCmd.Stderr = os.Stderr - if err := fetchCmd.Run(); err != nil { - return fmt.Errorf("failed to fetch changes: %w", err) - } - - if currentTag != "" { - latestTagCmd := exec.Command("git", "tag", "-l", "v*", "--sort=-version:refname") - latestTagOutput, err := latestTagCmd.Output() - if err != nil { - return fmt.Errorf("failed to get latest tag: %w", err) - } - - tags := strings.Split(strings.TrimSpace(string(latestTagOutput)), "\n") - if len(tags) == 0 || tags[0] == "" { - return fmt.Errorf("no version tags found") - } - latestTag := tags[0] - - if latestTag == currentTag { - fmt.Printf("Already on latest tag: %s\n", currentTag) - return nil - } - - fmt.Printf("Current tag: %s\n", currentTag) - fmt.Printf("Latest tag: %s\n", latestTag) - - if hasLocalChanges { - fmt.Println("\nWarning: You have local changes in your DMS configuration.") - if offerReclone(dmsPath) { - return nil - } - return errdefs.ErrUpdateCancelled - } - - fmt.Printf("Updating to %s...\n", latestTag) - checkoutCmd := exec.Command("git", "checkout", latestTag) - checkoutCmd.Stdout = os.Stdout - checkoutCmd.Stderr = os.Stderr - if err := checkoutCmd.Run(); err != nil { - fmt.Printf("Error: Failed to checkout %s: %v\n", latestTag, err) - if offerReclone(dmsPath) { - return nil - } - return fmt.Errorf("update cancelled") - } - - fmt.Printf("\nUpdate complete! Updated from %s to %s\n", currentTag, latestTag) - return nil - } - - if currentBranch == "" { - currentBranch = "master" - } - - fmt.Printf("Current branch: %s\n", currentBranch) - - if hasLocalChanges { - fmt.Println("\nWarning: You have local changes in your DMS configuration.") - if offerReclone(dmsPath) { - return nil - } - return errdefs.ErrUpdateCancelled - } - - pullCmd := exec.Command("git", "pull", "origin", currentBranch) - pullCmd.Stdout = os.Stdout - pullCmd.Stderr = os.Stderr - if err := pullCmd.Run(); err != nil { - fmt.Printf("Error: Failed to pull latest changes: %v\n", err) - if offerReclone(dmsPath) { - return nil - } - return fmt.Errorf("update cancelled") - } - - fmt.Println("\nUpdate complete!") - return nil -} - -func offerReclone(dmsPath string) bool { - fmt.Println("\nWould you like to backup and re-clone the repository? (y/N): ") - reader := bufio.NewReader(os.Stdin) - response, err := reader.ReadString('\n') - if err != nil || !strings.HasPrefix(strings.ToLower(strings.TrimSpace(response)), "y") { - return false - } - - timestamp := time.Now().Unix() - backupPath := fmt.Sprintf("%s.backup-%d", dmsPath, timestamp) - - fmt.Printf("Backing up current directory to %s...\n", backupPath) - if err := os.Rename(dmsPath, backupPath); err != nil { - fmt.Printf("Error: Failed to backup directory: %v\n", err) - return false - } - - fmt.Println("Cloning fresh copy...") - cloneCmd := exec.Command("git", "clone", "https://github.com/AvengeMedia/DankMaterialShell.git", dmsPath) - cloneCmd.Stdout = os.Stdout - cloneCmd.Stderr = os.Stderr - if err := cloneCmd.Run(); err != nil { - fmt.Printf("Error: Failed to clone repository: %v\n", err) - fmt.Printf("Restoring backup...\n") - os.Rename(backupPath, dmsPath) - return false - } - - fmt.Printf("Successfully re-cloned repository (backup at %s)\n", backupPath) - return true -} - -func confirmUpdate() bool { - fmt.Print("Do you want to proceed with the update? (y/N): ") - reader := bufio.NewReader(os.Stdin) - response, err := reader.ReadString('\n') - if err != nil { - fmt.Printf("Error reading input: %v\n", err) - return false - } - response = strings.TrimSpace(strings.ToLower(response)) - return response == "y" || response == "yes" -} - -func updateDMSBinary() error { - arch := "" - switch strings.ToLower(os.Getenv("HOSTTYPE")) { - case "x86_64", "amd64": - arch = "amd64" - case "aarch64", "arm64": - arch = "arm64" - default: - cmd := exec.Command("uname", "-m") - output, err := cmd.Output() - if err != nil { - return fmt.Errorf("failed to detect architecture: %w", err) - } - archStr := strings.TrimSpace(string(output)) - switch archStr { - case "x86_64": - arch = "amd64" - case "aarch64": - arch = "arm64" - default: - return fmt.Errorf("unsupported architecture: %s", archStr) - } - } - - fmt.Println("Fetching latest release version...") - cmd := exec.Command("curl", "-s", "https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest") - output, err := cmd.Output() - if err != nil { - return fmt.Errorf("failed to fetch latest release: %w", err) - } - - version := "" - for line := range strings.SplitSeq(string(output), "\n") { - if strings.Contains(line, "\"tag_name\"") { - parts := strings.Split(line, "\"") - if len(parts) >= 4 { - version = parts[3] - break - } - } - } - - if version == "" { - return fmt.Errorf("could not determine latest version") - } - - fmt.Printf("Latest version: %s\n", version) - - tempDir, err := os.MkdirTemp("", "dms-update-*") - if err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tempDir) - - binaryURL := fmt.Sprintf("https://github.com/AvengeMedia/DankMaterialShell/releases/download/%s/dms-cli-%s.gz", version, arch) - checksumURL := fmt.Sprintf("https://github.com/AvengeMedia/DankMaterialShell/releases/download/%s/dms-cli-%s.gz.sha256", version, arch) - - binaryPath := filepath.Join(tempDir, "dms.gz") - checksumPath := filepath.Join(tempDir, "dms.gz.sha256") - - fmt.Println("Downloading dms binary...") - downloadCmd := exec.Command("curl", "-L", binaryURL, "-o", binaryPath) - if err := downloadCmd.Run(); err != nil { - return fmt.Errorf("failed to download binary: %w", err) - } - - fmt.Println("Downloading checksum...") - downloadCmd = exec.Command("curl", "-L", checksumURL, "-o", checksumPath) - if err := downloadCmd.Run(); err != nil { - return fmt.Errorf("failed to download checksum: %w", err) - } - - fmt.Println("Verifying checksum...") - checksumData, err := os.ReadFile(checksumPath) - if err != nil { - return fmt.Errorf("failed to read checksum file: %w", err) - } - expectedChecksum := strings.Fields(string(checksumData))[0] - - actualCmd := exec.Command("sha256sum", binaryPath) - actualOutput, err := actualCmd.Output() - if err != nil { - return fmt.Errorf("failed to calculate checksum: %w", err) - } - actualChecksum := strings.Fields(string(actualOutput))[0] - - if expectedChecksum != actualChecksum { - return fmt.Errorf("checksum verification failed\nExpected: %s\nGot: %s", expectedChecksum, actualChecksum) - } - - fmt.Println("Decompressing binary...") - decompressCmd := exec.Command("gunzip", binaryPath) - if err := decompressCmd.Run(); err != nil { - return fmt.Errorf("failed to decompress binary: %w", err) - } - - decompressedPath := filepath.Join(tempDir, "dms") - - if err := os.Chmod(decompressedPath, 0o755); err != nil { - return fmt.Errorf("failed to make binary executable: %w", err) - } - - currentPath, err := exec.LookPath("dms") - if err != nil { - return fmt.Errorf("could not find current dms binary: %w", err) - } - - fmt.Printf("Installing to %s...\n", currentPath) - - replaceCmd := exec.Command("sudo", "install", "-m", "0755", decompressedPath, currentPath) - replaceCmd.Stdin = os.Stdin - replaceCmd.Stdout = os.Stdout - replaceCmd.Stderr = os.Stderr - if err := replaceCmd.Run(); err != nil { - return fmt.Errorf("failed to replace binary: %w", err) - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter.go deleted file mode 100644 index 1efa545..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter.go +++ /dev/null @@ -1,1850 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "os/user" - "path/filepath" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/greeter" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - sharedpam "github.com/AvengeMedia/DankMaterialShell/core/internal/pam" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/spf13/cobra" - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -var greeterCmd = &cobra.Command{ - Use: "greeter", - Short: "Manage DMS greeter", - Long: "Manage DMS greeter (greetd)", -} - -var ( - greeterConfigSyncFn = greeter.SyncDMSConfigs - sharedAuthSyncFn = sharedpam.SyncAuthConfig -) - -var greeterInstallCmd = &cobra.Command{ - Use: "install", - Short: "Install and configure DMS greeter", - Long: "Install greetd and configure it to use DMS as the greeter interface", - PreRunE: requireMutableSystemCommand, - Run: func(cmd *cobra.Command, args []string) { - yes, _ := cmd.Flags().GetBool("yes") - term, _ := cmd.Flags().GetBool("terminal") - if term { - installCmd := "dms greeter install" - if yes { - installCmd += " --yes" - } - installCmd += "; echo; echo \"Install finished. Closing in 3 seconds...\"; sleep 3" - if err := runCommandInTerminal(installCmd); err != nil { - log.Fatalf("Error launching install in terminal: %v", err) - } - return - } - if err := installGreeter(yes); err != nil { - log.Fatalf("Error installing greeter: %v", err) - } - }, -} - -var greeterSyncCmd = &cobra.Command{ - Use: "sync", - Short: "Sync DMS theme and settings with greeter", - Long: "Synchronize your current user's DMS theme, settings, and wallpaper configuration with the login greeter screen", - Run: func(cmd *cobra.Command, args []string) { - yes, _ := cmd.Flags().GetBool("yes") - auth, _ := cmd.Flags().GetBool("auth") - local, _ := cmd.Flags().GetBool("local") - term, _ := cmd.Flags().GetBool("terminal") - if term { - if err := syncInTerminal(yes, auth, local); err != nil { - log.Fatalf("Error launching sync in terminal: %v", err) - } - return - } - if err := syncGreeter(yes, auth, local); err != nil { - log.Fatalf("Error syncing greeter: %v", err) - } - }, -} - -func init() { - greeterSyncCmd.Flags().BoolP("yes", "y", false, "Non-interactive mode: skip prompts, use defaults (for UI)") - greeterSyncCmd.Flags().BoolP("terminal", "t", false, "Run sync in a new terminal (for entering sudo password); terminal auto-closes when done") - greeterSyncCmd.Flags().BoolP("auth", "a", false, "Configure PAM for fingerprint and U2F (adds both if modules exist); overrides UI toggles") - greeterSyncCmd.Flags().BoolP("local", "l", false, "Developer mode: force greetd config to use a local DMS checkout path") -} - -var greeterEnableCmd = &cobra.Command{ - Use: "enable", - Short: "Enable DMS greeter in greetd config", - Long: "Configure greetd to use DMS as the greeter", - PreRunE: requireMutableSystemCommand, - Run: func(cmd *cobra.Command, args []string) { - yes, _ := cmd.Flags().GetBool("yes") - term, _ := cmd.Flags().GetBool("terminal") - if term { - enableCmd := "dms greeter enable" - if yes { - enableCmd += " --yes" - } - enableCmd += "; echo; echo \"Enable finished. Closing in 3 seconds...\"; sleep 3" - if err := runCommandInTerminal(enableCmd); err != nil { - log.Fatalf("Error launching enable in terminal: %v", err) - } - return - } - if err := enableGreeter(yes); err != nil { - log.Fatalf("Error enabling greeter: %v", err) - } - }, -} - -var greeterStatusCmd = &cobra.Command{ - Use: "status", - Short: "Check greeter sync status", - Long: "Check the status of greeter installation and configuration sync", - Run: func(cmd *cobra.Command, args []string) { - if err := checkGreeterStatus(); err != nil { - log.Fatalf("Error checking greeter status: %v", err) - } - }, -} - -var greeterUninstallCmd = &cobra.Command{ - Use: "uninstall", - Short: "Remove DMS greeter configuration and restore previous display manager", - Long: "Disable greetd, remove DMS managed configs, and restore the system to its pre-DMS-greeter state", - PreRunE: requireMutableSystemCommand, - Run: func(cmd *cobra.Command, args []string) { - yes, _ := cmd.Flags().GetBool("yes") - term, _ := cmd.Flags().GetBool("terminal") - if term { - uninstallCmd := "dms greeter uninstall" - if yes { - uninstallCmd += " --yes" - } - uninstallCmd += "; echo; echo \"Uninstall finished. Closing in 3 seconds...\"; sleep 3" - if err := runCommandInTerminal(uninstallCmd); err != nil { - log.Fatalf("Error launching uninstall in terminal: %v", err) - } - return - } - if err := uninstallGreeter(yes); err != nil { - log.Fatalf("Error uninstalling greeter: %v", err) - } - }, -} - -func init() { - greeterInstallCmd.Flags().BoolP("yes", "y", false, "Non-interactive: skip confirmation prompt") - greeterInstallCmd.Flags().BoolP("terminal", "t", false, "Run in a new terminal (for entering sudo password)") - greeterEnableCmd.Flags().BoolP("yes", "y", false, "Non-interactive: skip confirmation prompt") - greeterEnableCmd.Flags().BoolP("terminal", "t", false, "Run in a new terminal (for entering sudo password)") - greeterUninstallCmd.Flags().BoolP("yes", "y", false, "Non-interactive: skip confirmation prompt") - greeterUninstallCmd.Flags().BoolP("terminal", "t", false, "Run in a new terminal (for entering sudo password)") -} - -func syncGreeterConfigsAndAuth(dmsPath, compositor string, logFunc func(string), options sharedpam.SyncAuthOptions, beforeAuth func()) error { - if err := greeterConfigSyncFn(dmsPath, compositor, logFunc, ""); err != nil { - return err - } - if beforeAuth != nil { - beforeAuth() - } - return sharedAuthSyncFn(logFunc, "", options) -} - -func installGreeter(nonInteractive bool) error { - fmt.Println("=== DMS Greeter Installation ===") - - logFunc := func(msg string) { - fmt.Println(msg) - } - - if !nonInteractive { - fmt.Print("\nThis will install greetd (if needed), configure the DMS greeter, and enable it. Continue? [Y/n]: ") - var response string - fmt.Scanln(&response) - if strings.ToLower(strings.TrimSpace(response)) == "n" || strings.ToLower(strings.TrimSpace(response)) == "no" { - fmt.Println("Aborted.") - return nil - } - fmt.Println() - } - - if err := greeter.EnsureGreetdInstalled(logFunc, ""); err != nil { - return err - } - - greeter.TryInstallGreeterPackage(logFunc, "") - if isPackageOnlyGreeterDistro() && !greeter.IsGreeterPackaged() { - return fmt.Errorf("dms-greeter must be installed from distro packages on this distribution. %s", packageInstallHint()) - } - if greeter.IsGreeterPackaged() && greeter.HasLegacyLocalGreeterWrapper() { - return fmt.Errorf("legacy manual wrapper detected at /usr/local/bin/dms-greeter; remove it before using packaged dms-greeter: sudo rm -f /usr/local/bin/dms-greeter") - } - - if isGreeterEnabled() { - fmt.Print("\nGreeter is already installed and configured. Re-run to re-sync settings and permissions? [Y/n]: ") - var response string - fmt.Scanln(&response) - response = strings.TrimSpace(strings.ToLower(response)) - if response == "n" || response == "no" { - fmt.Println("Run 'dms greeter sync' to re-sync theme and settings at any time.") - return nil - } - fmt.Println() - } - - fmt.Println("\nDetecting DMS installation...") - dmsPath, err := greeter.DetectDMSPath() - if err != nil { - return err - } - fmt.Printf("✓ Found DMS at: %s\n", dmsPath) - - fmt.Println("\nDetecting installed compositors...") - compositors := greeter.DetectCompositors() - if len(compositors) == 0 { - return fmt.Errorf("no supported compositors found (niri or Hyprland required)") - } - - var selectedCompositor string - if len(compositors) == 1 { - selectedCompositor = compositors[0] - fmt.Printf("✓ Found compositor: %s\n", selectedCompositor) - } else { - var err error - selectedCompositor, err = greeter.PromptCompositorChoice(compositors) - if err != nil { - return err - } - fmt.Printf("✓ Selected compositor: %s\n", selectedCompositor) - } - - fmt.Println("\nSetting up dms-greeter group and permissions...") - if err := greeter.SetupDMSGroup(logFunc, ""); err != nil { - return err - } - - fmt.Println("\nCopying greeter files...") - if err := greeter.CopyGreeterFiles(dmsPath, selectedCompositor, logFunc, ""); err != nil { - return err - } - - if greeter.IsAppArmorEnabled() { - fmt.Println("\nConfiguring AppArmor profile...") - if err := greeter.InstallAppArmorProfile(logFunc, ""); err != nil { - logFunc(fmt.Sprintf("⚠ AppArmor profile setup failed: %v", err)) - } - } - - fmt.Println("\nConfiguring greetd...") - greeterPathForConfig := "" - if !greeter.IsGreeterPackaged() { - greeterPathForConfig = dmsPath - } - if err := greeter.ConfigureGreetd(greeterPathForConfig, selectedCompositor, logFunc, ""); err != nil { - return err - } - - fmt.Println("\nSynchronizing DMS configurations...") - if err := syncGreeterConfigsAndAuth(dmsPath, selectedCompositor, logFunc, sharedpam.SyncAuthOptions{}, func() { - fmt.Println("\nConfiguring authentication...") - }); err != nil { - return err - } - - if err := ensureGraphicalTarget(); err != nil { - return err - } - - if err := handleConflictingDisplayManagers(); err != nil { - return err - } - - if err := ensureGreetdEnabled(); err != nil { - return err - } - - fmt.Println("\n=== Installation Complete ===") - fmt.Println("\nTo start the greeter now, run:") - fmt.Println(" sudo systemctl start greetd") - fmt.Println("\nOr reboot to see the greeter at next boot.") - - return nil -} - -func uninstallGreeter(nonInteractive bool) error { - fmt.Println("=== DMS Greeter Uninstall ===") - - logFunc := func(msg string) { fmt.Println(msg) } - - if !isGreeterEnabled() { - fmt.Println("ℹ DMS greeter is not currently configured in /etc/greetd/config.toml.") - fmt.Println(" Nothing to undo for greetd configuration.") - } - - if !nonInteractive { - fmt.Print("\nThis will:\n • Stop and disable greetd\n • Remove the DMS-managed greeter auth block\n • Remove the DMS AppArmor profile\n • Restore the most recent pre-DMS greetd config (if available)\n\nContinue? [y/N]: ") - var response string - fmt.Scanln(&response) - if strings.ToLower(strings.TrimSpace(response)) != "y" { - fmt.Println("Aborted.") - return nil - } - } - - fmt.Println("\nDisabling greetd...") - disableCmd := exec.Command("sudo", "systemctl", "disable", "greetd") - disableCmd.Stdout = os.Stdout - disableCmd.Stderr = os.Stderr - if err := disableCmd.Run(); err != nil { - fmt.Printf(" ⚠ Could not disable greetd: %v\n", err) - } else { - fmt.Println(" ✓ greetd disabled") - } - - fmt.Println("\nRemoving DMS authentication configuration...") - if err := sharedpam.RemoveManagedGreeterPamBlock(logFunc, ""); err != nil { - fmt.Printf(" ⚠ PAM cleanup failed: %v\n", err) - } - - fmt.Println("\nRemoving DMS AppArmor profile...") - if err := greeter.UninstallAppArmorProfile(logFunc, ""); err != nil { - fmt.Printf(" ⚠ AppArmor cleanup failed: %v\n", err) - } - - fmt.Println("\nRestoring greetd configuration...") - if err := restorePreDMSGreetdConfig(""); err != nil { - fmt.Printf(" ⚠ Could not restore previous greetd config: %v\n", err) - fmt.Println(" You may need to manually edit /etc/greetd/config.toml.") - } - - fmt.Println("\nChecking for other display managers to re-enable...") - suggestDisplayManagerRestore(nonInteractive) - - fmt.Println("\n=== Uninstall Complete ===") - fmt.Println("\nReboot to complete the uninstallation and switch to your previous display manager.") - fmt.Println("To re-enable DMS greeter at any time, run: dms greeter enable") - - return nil -} - -func restorePreDMSGreetdConfig(sudoPassword string) error { - const configPath = "/etc/greetd/config.toml" - const backupGlob = "/etc/greetd/config.toml.backup-*" - - matches, _ := filepath.Glob(backupGlob) - - for i := 0; i < len(matches)-1; i++ { - for j := i + 1; j < len(matches); j++ { - if matches[j] > matches[i] { - matches[i], matches[j] = matches[j], matches[i] - } - } - } - - for _, candidate := range matches { - data, err := os.ReadFile(candidate) - if err != nil { - continue - } - if strings.Contains(string(data), "dms-greeter") { - continue - } - tmp, err := os.CreateTemp("", "greetd-restore-*") - if err != nil { - return fmt.Errorf("could not create temp file: %w", err) - } - tmpPath := tmp.Name() - defer os.Remove(tmpPath) - if _, err := tmp.Write(data); err != nil { - tmp.Close() - return err - } - tmp.Close() - - if err := runSudoCommand(sudoPassword, "cp", tmpPath, configPath); err != nil { - return fmt.Errorf("failed to restore %s: %w", candidate, err) - } - if err := runSudoCommand(sudoPassword, "chmod", "644", configPath); err != nil { - return err - } - fmt.Printf(" ✓ Restored greetd config from %s\n", candidate) - return nil - } - - minimal := `[terminal] -vt = 1 - -# DMS greeter has been uninstalled. -# Configure a greeter command here or re-enable a display manager. -[default_session] -user = "greeter" -command = "agreety --cmd /bin/bash" -` - tmp, err := os.CreateTemp("", "greetd-minimal-*") - if err != nil { - return fmt.Errorf("could not create temp file: %w", err) - } - tmpPath := tmp.Name() - defer os.Remove(tmpPath) - if _, err := tmp.WriteString(minimal); err != nil { - tmp.Close() - return err - } - tmp.Close() - - if err := runSudoCommand(sudoPassword, "cp", tmpPath, configPath); err != nil { - return fmt.Errorf("failed to write fallback greetd config: %w", err) - } - _ = runSudoCommand(sudoPassword, "chmod", "644", configPath) - fmt.Println(" ✓ Wrote minimal fallback greetd config (configure a greeter command manually if needed)") - return nil -} - -func runSudoCommand(_ string, command string, args ...string) error { - cmd := exec.Command("sudo", append([]string{command}, args...)...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - -// suggestDisplayManagerRestore scans for installed DMs and re-enables one -func suggestDisplayManagerRestore(nonInteractive bool) { - knownDMs := []string{"gdm", "gdm3", "lightdm", "sddm", "lxdm", "xdm", "cosmic-greeter"} - var found []string - for _, dm := range knownDMs { - if utils.CommandExists(dm) || isSystemdUnitInstalled(dm) { - found = append(found, dm) - } - } - if len(found) == 0 { - fmt.Println(" ℹ No other display managers detected.") - fmt.Println(" You can install one (e.g. gdm, lightdm, sddm) and then run:") - fmt.Println(" sudo systemctl enable --now ") - return - } - - enableDM := func(dm string) { - fmt.Printf(" Enabling %s...\n", dm) - cmd := exec.Command("sudo", "systemctl", "enable", "--force", dm) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - fmt.Printf(" ⚠ Failed to enable %s: %v\n", dm, err) - } else { - fmt.Printf(" ✓ %s enabled (will take effect on next boot).\n", dm) - } - } - - if len(found) == 1 || nonInteractive { - chosen := found[0] - if len(found) > 1 { - fmt.Printf(" ℹ Multiple display managers found (%s); enabling %s automatically.\n", - strings.Join(found, ", "), chosen) - } else { - fmt.Printf(" ℹ Found display manager: %s\n", chosen) - } - enableDM(chosen) - return - } - - fmt.Println(" ℹ Found the following display managers:") - for i, dm := range found { - fmt.Printf(" %d) %s\n", i+1, dm) - } - fmt.Print(" Choose a number to re-enable (or press Enter to skip): ") - - scanner := bufio.NewScanner(os.Stdin) - if !scanner.Scan() { - return - } - input := strings.TrimSpace(scanner.Text()) - if input == "" { - fmt.Println(" Skipped. You can re-enable a display manager later with:") - fmt.Println(" sudo systemctl enable --now ") - return - } - - n, err := strconv.Atoi(input) - if err != nil || n < 1 || n > len(found) { - fmt.Printf(" Invalid selection %q — skipping.\n", input) - return - } - - enableDM(found[n-1]) -} - -func isSystemdUnitInstalled(unit string) bool { - cmd := exec.Command("systemctl", "list-unit-files", unit+".service", "--no-legend", "--no-pager") - out, err := cmd.Output() - return err == nil && strings.Contains(string(out), unit) -} - -func runCommandInTerminal(shellCmd string) error { - terminals := []struct { - name string - args []string - }{ - {"gnome-terminal", []string{"--", "bash", "-c", shellCmd}}, - {"konsole", []string{"-e", "bash", "-c", shellCmd}}, - {"xfce4-terminal", []string{"-e", "bash -c \"" + strings.ReplaceAll(shellCmd, `"`, `\"`) + "\""}}, - {"ghostty", []string{"-e", "bash", "-c", shellCmd}}, - {"wezterm", []string{"start", "--", "bash", "-c", shellCmd}}, - {"alacritty", []string{"-e", "bash", "-c", shellCmd}}, - {"kitty", []string{"bash", "-c", shellCmd}}, - {"xterm", []string{"-e", "bash -c \"" + strings.ReplaceAll(shellCmd, `"`, `\"`) + "\""}}, - } - for _, t := range terminals { - if _, err := exec.LookPath(t.name); err != nil { - continue - } - cmd := exec.Command(t.name, t.args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return err - } - return nil - } - return fmt.Errorf("no terminal emulator found (tried: gnome-terminal, konsole, xfce4-terminal, ghostty, wezterm, alacritty, kitty, xterm)") -} - -func syncInTerminal(nonInteractive bool, forceAuth bool, local bool) error { - syncFlags := make([]string, 0, 3) - if nonInteractive { - syncFlags = append(syncFlags, "--yes") - } - if forceAuth { - syncFlags = append(syncFlags, "--auth") - } - if local { - syncFlags = append(syncFlags, "--local") - } - shellSyncCmd := "dms greeter sync" - if len(syncFlags) > 0 { - shellSyncCmd += " " + strings.Join(syncFlags, " ") - } - shellCmd := shellSyncCmd + `; echo; echo "Sync finished. Closing in 3 seconds..."; sleep 3` - return runCommandInTerminal(shellCmd) -} - -func resolveLocalWrapperShell() (string, error) { - for _, shellName := range []string{"bash", "sh"} { - shellPath, err := exec.LookPath(shellName) - if err == nil { - return shellPath, nil - } - } - return "", fmt.Errorf("could not find bash or sh in PATH for local greeter wrapper") -} - -func syncGreeter(nonInteractive bool, forceAuth bool, local bool) error { - if !nonInteractive { - fmt.Println("=== DMS Greeter Sync ===") - fmt.Println() - } - - logFunc := func(msg string) { - fmt.Println(msg) - } - - if !nonInteractive { - fmt.Println("Detecting DMS installation...") - } - var dmsPath string - var err error - if local { - dmsPath, err = resolveLocalDMSPath() - if err != nil { - return err - } - if !nonInteractive { - fmt.Printf("✓ Using local DMS path: %s\n", dmsPath) - } - } else { - dmsPath, err = greeter.DetectDMSPath() - if err != nil { - return err - } - if !nonInteractive { - fmt.Printf("✓ Found DMS at: %s\n", dmsPath) - } - } - - if !isGreeterEnabled() { - if nonInteractive { - return fmt.Errorf("greeter is not enabled; run 'dms greeter install' or 'dms greeter enable' first") - } - fmt.Println("\n⚠ DMS greeter is not enabled in greetd config.") - fmt.Print("Would you like to enable it now? (Y/n): ") - - var response string - fmt.Scanln(&response) - response = strings.ToLower(strings.TrimSpace(response)) - - if response != "n" && response != "no" { - if err := enableGreeter(false); err != nil { - return err - } - } else { - return fmt.Errorf("greeter must be enabled before syncing") - } - } - - if greeter.IsGreeterPackaged() && greeter.HasLegacyLocalGreeterWrapper() { - return fmt.Errorf("legacy manual wrapper detected at /usr/local/bin/dms-greeter; remove it before using packaged dms-greeter: sudo rm -f /usr/local/bin/dms-greeter") - } - - cacheDir := greeter.GreeterCacheDir - if _, err := os.Stat(cacheDir); os.IsNotExist(err) { - logFunc("Cache directory not found — attempting to create it...") - } - - greeterGroup := greeter.DetectGreeterGroup() - greeterGroupExists := utils.HasGroup(greeterGroup) - if greeterGroupExists { - currentUser, err := user.Current() - if err != nil { - return fmt.Errorf("failed to get current user: %w", err) - } - - groupsCmd := exec.Command("groups", currentUser.Username) - groupsOutput, err := groupsCmd.Output() - if err != nil { - return fmt.Errorf("failed to check groups: %w", err) - } - - inGreeterGroup := strings.Contains(string(groupsOutput), greeterGroup) - if !inGreeterGroup { - if nonInteractive { - logFunc(fmt.Sprintf("⚠ Not yet in %s group — will be added during sync (logout/login required to take effect).", greeterGroup)) - } else { - fmt.Printf("\n⚠ Warning: You are not in the %s group.\n", greeterGroup) - fmt.Printf("Would you like to add your user to the %s group? (Y/n): ", greeterGroup) - - var response string - fmt.Scanln(&response) - response = strings.ToLower(strings.TrimSpace(response)) - - if response != "n" && response != "no" { - fmt.Printf("\nAdding user to %s group...\n", greeterGroup) - addUserCmd := exec.Command("sudo", "usermod", "-aG", greeterGroup, currentUser.Username) - addUserCmd.Stdout = os.Stdout - addUserCmd.Stderr = os.Stderr - if err := addUserCmd.Run(); err != nil { - return fmt.Errorf("failed to add user to %s group: %w", greeterGroup, err) - } - fmt.Printf("✓ User added to %s group\n", greeterGroup) - fmt.Println("⚠ You will need to log out and back in for the group change to take effect") - } else { - return fmt.Errorf("aborted: user must be in the greeter group before syncing") - } - } - } - } - - compositor := detectConfiguredCompositor() - if compositor == "" { - compositors := greeter.DetectCompositors() - switch len(compositors) { - case 0: - return fmt.Errorf("no supported compositors found") - case 1: - compositor = compositors[0] - if !nonInteractive { - fmt.Printf("✓ Using compositor: %s\n", compositor) - } - default: - if nonInteractive { - compositor = compositors[0] - break - } - var err error - compositor, err = promptCompositorChoice(compositors) - if err != nil { - return err - } - fmt.Printf("✓ Selected compositor: %s\n", compositor) - } - } else if !nonInteractive { - fmt.Printf("✓ Detected compositor from config: %s\n", compositor) - } - - if local { - localWrapperScript := filepath.Join(dmsPath, "Modules", "Greetd", "assets", "dms-greeter") - restoreWrapperOverride := func() {} - if info, statErr := os.Stat(localWrapperScript); statErr == nil && !info.IsDir() { - wrapperShell, shellErr := resolveLocalWrapperShell() - if shellErr != nil { - return shellErr - } - previousWrapperOverride, hadWrapperOverride := os.LookupEnv("DMS_GREETER_WRAPPER_CMD") - wrapperCmdOverride := wrapperShell + " " + localWrapperScript - _ = os.Setenv("DMS_GREETER_WRAPPER_CMD", wrapperCmdOverride) - restoreWrapperOverride = func() { - if hadWrapperOverride { - _ = os.Setenv("DMS_GREETER_WRAPPER_CMD", previousWrapperOverride) - } else { - _ = os.Unsetenv("DMS_GREETER_WRAPPER_CMD") - } - } - if !nonInteractive { - fmt.Printf("✓ Using local greeter wrapper script: %s\n", localWrapperScript) - } - } else if !nonInteractive { - fmt.Printf("ℹ Local wrapper script not found at %s; using system wrapper.\n", localWrapperScript) - } - - fmt.Println("\nUpdating greetd command to use local DMS path...") - err := greeter.ConfigureGreetd(dmsPath, compositor, logFunc, "") - restoreWrapperOverride() - if err != nil { - return fmt.Errorf("failed to apply local greeter path: %w", err) - } - if !nonInteractive { - fmt.Println("ℹ Local mode applies both DMS path override (-p) and local wrapper behavior when available.") - } - } else { - greeterPathForConfig := "" - if !greeter.IsGreeterPackaged() { - greeterPathForConfig = dmsPath - } - fmt.Println("\nUpdating greetd command...") - if err := greeter.ConfigureGreetd(greeterPathForConfig, compositor, logFunc, ""); err != nil { - return fmt.Errorf("failed to update greetd command: %w", err) - } - } - - fmt.Println("\nSetting up permissions and ACLs...") - greeter.RemediateStaleACLs(logFunc, "") - greeter.RemediateStaleAppArmor(logFunc, "") - if err := greeter.SetupDMSGroup(logFunc, ""); err != nil { - return err - } - if err := greeter.EnsureGreeterCacheDir(logFunc, ""); err != nil { - return fmt.Errorf("failed to ensure greeter cache directory at %s: %w\nRun: sudo mkdir -p %s && sudo chown root:%s %s && sudo chmod 2770 %s", cacheDir, err, cacheDir, greeterGroup, cacheDir, cacheDir) - } - - fmt.Println("\nSynchronizing DMS configurations...") - if err := syncGreeterConfigsAndAuth(dmsPath, compositor, logFunc, sharedpam.SyncAuthOptions{ - ForceGreeterAuth: forceAuth, - }, func() { - fmt.Println("\nConfiguring authentication...") - }); err != nil { - return err - } - - if greeter.IsAppArmorEnabled() { - fmt.Println("\nConfiguring AppArmor profile...") - if err := greeter.InstallAppArmorProfile(logFunc, ""); err != nil { - logFunc(fmt.Sprintf("⚠ AppArmor profile setup failed: %v", err)) - } - } - - fmt.Println("\n=== Sync Complete ===") - fmt.Println("\nYour theme, settings, and wallpaper configuration have been synced with the greeter.") - fmt.Println("Shared authentication settings were also checked and reconciled where needed.") - if forceAuth { - fmt.Println("Authentication has been configured for fingerprint and U2F (where modules exist).") - } - fmt.Println("The changes will be visible on the next login screen.") - - return nil -} - -func hasDmsShellQml(dir string) bool { - info, err := os.Stat(filepath.Join(dir, "shell.qml")) - return err == nil && !info.IsDir() -} - -func resolveDMSLocalCandidate(path string) (string, bool) { - if path == "" { - return "", false - } - if hasDmsShellQml(path) { - abs, err := filepath.Abs(path) - if err != nil { - return path, true - } - return abs, true - } - - quickshellPath := filepath.Join(path, "quickshell") - if hasDmsShellQml(quickshellPath) { - abs, err := filepath.Abs(quickshellPath) - if err != nil { - return quickshellPath, true - } - return abs, true - } - - return "", false -} - -func resolveLocalDMSPath() (string, error) { - if override := strings.TrimSpace(os.Getenv("DMS_LOCAL_PATH")); override != "" { - if resolved, ok := resolveDMSLocalCandidate(override); ok { - return resolved, nil - } - return "", fmt.Errorf("DMS_LOCAL_PATH is set but does not point to a valid DMS quickshell path: %s", override) - } - - wd, err := os.Getwd() - if err != nil { - return "", fmt.Errorf("failed to get current directory: %w", err) - } - - dir := wd - for { - if resolved, ok := resolveDMSLocalCandidate(dir); ok { - return resolved, nil - } - - parent := filepath.Dir(dir) - if parent == dir { - break - } - dir = parent - } - - homeDir, err := os.UserHomeDir() - if err == nil && homeDir != "" { - for _, candidate := range []string{ - filepath.Join(homeDir, "dms"), - filepath.Join(homeDir, "DankMaterialShell"), - filepath.Join(homeDir, "dankmaterialshell"), - filepath.Join(homeDir, "projects", "dms"), - filepath.Join(homeDir, "src", "dms"), - } { - if resolved, ok := resolveDMSLocalCandidate(candidate); ok { - return resolved, nil - } - } - - if entries, readErr := os.ReadDir(homeDir); readErr == nil { - for _, entry := range entries { - if !entry.IsDir() { - continue - } - name := strings.ToLower(entry.Name()) - if !strings.Contains(name, "dms") && !strings.Contains(name, "dank") { - continue - } - if resolved, ok := resolveDMSLocalCandidate(filepath.Join(homeDir, entry.Name())); ok { - return resolved, nil - } - } - } - } - - return "", fmt.Errorf("could not locate a local DMS checkout from %s; run from repo root or set DMS_LOCAL_PATH=/absolute/path/to/repo", wd) -} - -func disableDisplayManager(dmName string) (bool, error) { - state, err := getSystemdServiceState(dmName) - if err != nil { - return false, fmt.Errorf("failed to check %s state: %w", dmName, err) - } - - if !state.Exists { - return false, nil - } - - fmt.Printf("\nChecking %s...\n", dmName) - fmt.Printf(" Current state: enabled=%s\n", state.EnabledState) - - actionTaken := false - - if state.NeedsDisable { - var disableCmd *exec.Cmd - var actionVerb string - - if state.EnabledState == "static" { - fmt.Printf(" Masking %s (static service cannot be disabled)...\n", dmName) - disableCmd = exec.Command("sudo", "systemctl", "mask", dmName) - actionVerb = "masked" - } else { - fmt.Printf(" Disabling %s...\n", dmName) - disableCmd = exec.Command("sudo", "systemctl", "disable", dmName) - actionVerb = "disabled" - } - - disableCmd.Stdout = os.Stdout - disableCmd.Stderr = os.Stderr - if err := disableCmd.Run(); err != nil { - return actionTaken, fmt.Errorf("failed to disable/mask %s: %w", dmName, err) - } - - enabledState, shouldDisable, verifyErr := checkSystemdServiceEnabled(dmName) - if verifyErr != nil { - fmt.Printf(" ⚠ Warning: Could not verify %s was %s: %v\n", dmName, actionVerb, verifyErr) - } else if shouldDisable { - return actionTaken, fmt.Errorf("%s is still in state '%s' after %s operation", dmName, enabledState, actionVerb) - } else { - fmt.Printf(" ✓ %s %s (now: %s)\n", cases.Title(language.English).String(actionVerb), dmName, enabledState) - } - - actionTaken = true - } else { - if state.EnabledState == "masked" || state.EnabledState == "masked-runtime" { - fmt.Printf(" ✓ %s is already masked\n", dmName) - } else { - fmt.Printf(" ✓ %s is already disabled\n", dmName) - } - } - - return actionTaken, nil -} - -func ensureGreetdEnabled() error { - fmt.Println("\nChecking greetd service status...") - - state, err := getSystemdServiceState("greetd") - if err != nil { - return fmt.Errorf("failed to check greetd state: %w", err) - } - - if !state.Exists { - return fmt.Errorf("greetd service not found. Please install greetd first") - } - - fmt.Printf(" Current state: %s\n", state.EnabledState) - - if state.EnabledState == "masked" || state.EnabledState == "masked-runtime" { - fmt.Println(" Unmasking greetd...") - unmaskCmd := exec.Command("sudo", "systemctl", "unmask", "greetd") - unmaskCmd.Stdout = os.Stdout - unmaskCmd.Stderr = os.Stderr - if err := unmaskCmd.Run(); err != nil { - return fmt.Errorf("failed to unmask greetd: %w", err) - } - fmt.Println(" ✓ Unmasked greetd") - } - - if state.EnabledState == "enabled" || state.EnabledState == "enabled-runtime" { - fmt.Println(" Reasserting greetd as active display manager...") - } else { - fmt.Println(" Enabling greetd service...") - } - - enableCmd := exec.Command("sudo", "systemctl", "enable", "--force", "greetd") - enableCmd.Stdout = os.Stdout - enableCmd.Stderr = os.Stderr - if err := enableCmd.Run(); err != nil { - return fmt.Errorf("failed to enable greetd: %w", err) - } - - enabledState, _, verifyErr := checkSystemdServiceEnabled("greetd") - if verifyErr != nil { - fmt.Printf(" ⚠ Warning: Could not verify greetd enabled state: %v\n", verifyErr) - } else { - switch enabledState { - case "enabled", "enabled-runtime", "static", "indirect", "alias": - fmt.Printf(" ✓ greetd enabled (state: %s)\n", enabledState) - default: - return fmt.Errorf("greetd is still in state '%s' after enable operation", enabledState) - } - } - - return nil -} - -func ensureGraphicalTarget() error { - getDefaultCmd := exec.Command("systemctl", "get-default") - currentTarget, err := getDefaultCmd.Output() - if err != nil { - fmt.Println("⚠ Warning: Could not detect current default systemd target") - return nil - } - - currentTargetStr := strings.TrimSpace(string(currentTarget)) - if currentTargetStr != "graphical.target" { - fmt.Printf("\nSetting graphical.target as default (current: %s)...\n", currentTargetStr) - setDefaultCmd := exec.Command("sudo", "systemctl", "set-default", "graphical.target") - setDefaultCmd.Stdout = os.Stdout - setDefaultCmd.Stderr = os.Stderr - if err := setDefaultCmd.Run(); err != nil { - fmt.Println("⚠ Warning: Failed to set graphical.target as default") - fmt.Println(" Greeter may not start on boot. Run manually:") - fmt.Println(" sudo systemctl set-default graphical.target") - return nil - } - fmt.Println("✓ Set graphical.target as default") - } else { - fmt.Println("✓ Default target already set to graphical.target") - } - - return nil -} - -func handleConflictingDisplayManagers() error { - fmt.Println("\n=== Checking for Conflicting Display Managers ===") - - conflictingDMs := []string{"gdm", "gdm3", "lightdm", "sddm", "lxdm", "xdm", "cosmic-greeter"} - - disabledAny := false - var errors []string - - for _, dm := range conflictingDMs { - actionTaken, err := disableDisplayManager(dm) - if err != nil { - errMsg := fmt.Sprintf("Failed to handle %s: %v", dm, err) - errors = append(errors, errMsg) - fmt.Printf(" ⚠⚠⚠ ERROR: %s\n", errMsg) - continue - } - if actionTaken { - disabledAny = true - } - } - - if len(errors) > 0 { - fmt.Println("\n╔════════════════════════════════════════════════════════════╗") - fmt.Println("║ ⚠⚠⚠ ERRORS OCCURRED ⚠⚠⚠ ║") - fmt.Println("╚════════════════════════════════════════════════════════════╝") - fmt.Println("\nSome display managers could not be disabled:") - for _, err := range errors { - fmt.Printf(" ✗ %s\n", err) - } - fmt.Println("\nThis may prevent greetd from starting properly.") - fmt.Println("You may need to manually disable them before greetd will work.") - fmt.Println("\nManual commands to try:") - for _, dm := range conflictingDMs { - fmt.Printf(" sudo systemctl disable %s\n", dm) - fmt.Printf(" sudo systemctl mask %s\n", dm) - } - fmt.Print("\nContinue with greeter enablement anyway? (Y/n): ") - - var response string - fmt.Scanln(&response) - response = strings.ToLower(strings.TrimSpace(response)) - - if response == "n" || response == "no" { - return fmt.Errorf("aborted due to display manager conflicts") - } - fmt.Println("\nContinuing despite errors...") - } - - if !disabledAny && len(errors) == 0 { - fmt.Println("\n✓ No conflicting display managers found") - } else if disabledAny && len(errors) == 0 { - fmt.Println("\n✓ Successfully handled all conflicting display managers") - } - - return nil -} - -func enableGreeter(nonInteractive bool) error { - fmt.Println("=== DMS Greeter Enable ===") - fmt.Println() - - configPath := "/etc/greetd/config.toml" - if _, err := os.Stat(configPath); os.IsNotExist(err) { - return fmt.Errorf("greetd config not found at %s\nPlease install greetd first", configPath) - } else if err != nil { - return fmt.Errorf("failed to access greetd config at %s: %w", configPath, err) - } - - if greeter.IsGreeterPackaged() && greeter.HasLegacyLocalGreeterWrapper() { - return fmt.Errorf("legacy manual wrapper detected at /usr/local/bin/dms-greeter; remove it before using packaged dms-greeter: sudo rm -f /usr/local/bin/dms-greeter") - } - - configAlreadyCorrect := isGreeterEnabled() - configuredCompositor := detectConfiguredCompositor() - - logFunc := func(msg string) { - fmt.Println(msg) - } - greeterGroup := greeter.DetectGreeterGroup() - - if configAlreadyCorrect { - fmt.Println("✓ Greeter is already configured with dms-greeter") - if configuredCompositor != "" { - fmt.Printf("✓ Configured compositor: %s\n", configuredCompositor) - } - - fmt.Println("\nSetting up dms-greeter group and permissions...") - if err := greeter.SetupDMSGroup(logFunc, ""); err != nil { - return err - } - if err := greeter.EnsureGreeterCacheDir(logFunc, ""); err != nil { - fmt.Printf("⚠ Could not ensure cache directory: %v\n Run: sudo mkdir -p %s && sudo chown root:%s %s && sudo chmod 2770 %s\n", err, greeter.GreeterCacheDir, greeterGroup, greeter.GreeterCacheDir, greeter.GreeterCacheDir) - } - - if err := ensureGraphicalTarget(); err != nil { - return err - } - - if err := handleConflictingDisplayManagers(); err != nil { - return err - } - - if err := ensureGreetdEnabled(); err != nil { - return err - } - - fmt.Println("\n=== Enable Complete ===") - fmt.Println("\nGreeter configuration verified and system state corrected.") - fmt.Println("To start the greeter now, run:") - fmt.Println(" sudo systemctl start greetd") - fmt.Println("\nOr reboot to see the greeter at boot time.") - - return nil - } - - if !nonInteractive { - fmt.Print("\nThis will configure greetd to use the DMS greeter and may disable other display managers. Continue? [Y/n]: ") - var response string - fmt.Scanln(&response) - if strings.ToLower(strings.TrimSpace(response)) == "n" || strings.ToLower(strings.TrimSpace(response)) == "no" { - fmt.Println("Aborted.") - return nil - } - fmt.Println() - } - - fmt.Println("Detecting installed compositors...") - compositors := greeter.DetectCompositors() - - if utils.CommandExists("sway") { - compositors = append(compositors, "sway") - } - - if len(compositors) == 0 { - return fmt.Errorf("no supported compositors found (niri, Hyprland, or sway required)") - } - - var selectedCompositor string - if len(compositors) == 1 { - selectedCompositor = compositors[0] - fmt.Printf("✓ Found compositor: %s\n", selectedCompositor) - } else { - var err error - selectedCompositor, err = promptCompositorChoice(compositors) - if err != nil { - return err - } - fmt.Printf("✓ Selected compositor: %s\n", selectedCompositor) - } - - greeterPathForConfig := "" - if !greeter.IsGreeterPackaged() { - dmsPath, err := greeter.DetectDMSPath() - if err != nil { - return fmt.Errorf("failed to detect DMS path for manual greeter configuration: %w", err) - } - greeterPathForConfig = dmsPath - } - if err := greeter.ConfigureGreetd(greeterPathForConfig, selectedCompositor, logFunc, ""); err != nil { - return fmt.Errorf("failed to configure greetd: %w", err) - } - - fmt.Println("\nSetting up dms-greeter group and permissions...") - if err := greeter.SetupDMSGroup(logFunc, ""); err != nil { - return err - } - if err := greeter.EnsureGreeterCacheDir(logFunc, ""); err != nil { - fmt.Printf("⚠ Could not ensure cache directory: %v\n Run: sudo mkdir -p %s && sudo chown root:%s %s && sudo chmod 2770 %s\n", err, greeter.GreeterCacheDir, greeterGroup, greeter.GreeterCacheDir, greeter.GreeterCacheDir) - } - - if greeter.IsAppArmorEnabled() { - if err := greeter.InstallAppArmorProfile(logFunc, ""); err != nil { - logFunc(fmt.Sprintf("⚠ AppArmor profile setup failed: %v", err)) - } - } - - if err := ensureGraphicalTarget(); err != nil { - return err - } - - if err := handleConflictingDisplayManagers(); err != nil { - return err - } - - if err := ensureGreetdEnabled(); err != nil { - return err - } - - fmt.Println("\n=== Enable Complete ===") - fmt.Println("\nTo start the greeter now, run:") - fmt.Println(" sudo systemctl start greetd") - fmt.Println("\nOr reboot to see the greeter at boot time.") - - return nil -} - -func isGreeterEnabled() bool { - command := readDefaultSessionCommand("/etc/greetd/config.toml") - return command != "" && strings.Contains(command, "dms-greeter") -} - -func detectConfiguredCompositor() string { - command := strings.ToLower(readDefaultSessionCommand("/etc/greetd/config.toml")) - switch { - case strings.Contains(command, "--command niri"): - return "niri" - case strings.Contains(command, "--command hyprland"): - return "hyprland" - case strings.Contains(command, "--command sway"): - return "sway" - } - return "" -} - -func stripTomlComment(line string) string { - trimmed := strings.TrimSpace(line) - if idx := strings.Index(trimmed, "#"); idx >= 0 { - return strings.TrimSpace(trimmed[:idx]) - } - return trimmed -} - -func parseTomlSection(line string) (string, bool) { - trimmed := stripTomlComment(line) - if len(trimmed) < 3 || !strings.HasPrefix(trimmed, "[") || !strings.HasSuffix(trimmed, "]") { - return "", false - } - return strings.TrimSpace(trimmed[1 : len(trimmed)-1]), true -} - -func readDefaultSessionCommand(configPath string) string { - data, err := os.ReadFile(configPath) - if err != nil { - return "" - } - - inDefaultSession := false - for line := range strings.SplitSeq(string(data), "\n") { - if section, ok := parseTomlSection(line); ok { - inDefaultSession = section == "default_session" - continue - } - - if !inDefaultSession { - continue - } - - trimmed := stripTomlComment(line) - if !strings.HasPrefix(trimmed, "command =") && !strings.HasPrefix(trimmed, "command=") { - continue - } - - parts := strings.SplitN(trimmed, "=", 2) - if len(parts) != 2 { - continue - } - - command := strings.Trim(strings.TrimSpace(parts[1]), `"`) - if command != "" { - return command - } - } - - return "" -} - -func extractGreeterCacheDirFromCommand(command string) string { - if command == "" { - return greeter.GreeterCacheDir - } - tokens := strings.Fields(command) - for i := 0; i < len(tokens); i++ { - token := strings.Trim(tokens[i], "\"") - if token == "--cache-dir" && i+1 < len(tokens) { - return strings.Trim(tokens[i+1], "\"") - } - if strings.HasPrefix(token, "--cache-dir=") { - value := strings.TrimPrefix(token, "--cache-dir=") - value = strings.Trim(value, "\"") - if value != "" { - return value - } - } - } - return greeter.GreeterCacheDir -} - -func extractGreeterWrapperFromCommand(command string) string { - if command == "" { - return "" - } - tokens := strings.Fields(command) - if len(tokens) == 0 { - return "" - } - wrapper := strings.Trim(tokens[0], "\"") - if wrapper == "" { - return "" - } - if len(tokens) > 1 { - next := strings.Trim(tokens[1], "\"") - if next != "" && (filepath.Base(wrapper) == "bash" || filepath.Base(wrapper) == "sh") && strings.Contains(filepath.Base(next), "dms-greeter") { - return fmt.Sprintf("%s (script: %s)", wrapper, next) - } - } - return wrapper -} - -func extractGreeterPathOverrideFromCommand(command string) string { - if command == "" { - return "" - } - tokens := strings.Fields(command) - for i := 0; i < len(tokens); i++ { - token := strings.Trim(tokens[i], "\"") - if (token == "-p" || token == "--path") && i+1 < len(tokens) { - return strings.Trim(tokens[i+1], "\"") - } - if strings.HasPrefix(token, "--path=") { - value := strings.TrimPrefix(token, "--path=") - value = strings.Trim(value, "\"") - if value != "" { - return value - } - } - } - return "" -} - -func parseManagedGreeterPamAuth(pamText string) (managed bool, fingerprint bool, u2f bool, legacy bool) { - return sharedpam.ParseManagedGreeterPamAuth(pamText) -} - -func packageInstallHint() string { - osInfo, err := distros.GetOSInfo() - if err != nil { - return "Install package: dms-greeter" - } - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return "Install package: dms-greeter" - } - - switch config.Family { - case distros.FamilyDebian: - return "Install with 'sudo apt install dms-greeter' (requires DankLinux OBS repo — see https://danklinux.com/docs/dankgreeter/installation#debian)" - case distros.FamilySUSE: - return "Install with 'sudo zypper install dms-greeter' (requires DankLinux OBS repo — see https://danklinux.com/docs/dankgreeter/installation#opensuse)" - case distros.FamilyUbuntu: - return "Install with 'sudo apt install dms-greeter' (requires ppa:avengemedia/danklinux: sudo add-apt-repository ppa:avengemedia/danklinux)" - case distros.FamilyFedora: - return "Install with 'sudo dnf install dms-greeter' (requires COPR: sudo dnf copr enable avengemedia/danklinux)" - case distros.FamilyArch: - return "Install from AUR with 'paru -S greetd-dms-greeter-git' or 'yay -S greetd-dms-greeter-git'" - default: - return "Run 'dms greeter install' to install greeter" - } -} - -func systemPamManagerRemediationHint() string { - osInfo, err := distros.GetOSInfo() - if err != nil { - return "Disable it in your PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return "Disable it in your PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } - - switch config.Family { - case distros.FamilyFedora: - return "Disable it in authselect to force password-only greeter login." - case distros.FamilyDebian, distros.FamilyUbuntu: - return "Disable it in pam-auth-update to force password-only greeter login." - default: - return "Disable it in your distro PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } -} - -func isPackageOnlyGreeterDistro() bool { - osInfo, err := distros.GetOSInfo() - if err != nil { - return false - } - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return false - } - return config.Family == distros.FamilyDebian || - config.Family == distros.FamilySUSE || - config.Family == distros.FamilyUbuntu || - config.Family == distros.FamilyFedora || - config.Family == distros.FamilyArch -} - -func promptCompositorChoice(compositors []string) (string, error) { - fmt.Println("\nMultiple compositors detected:") - for i, comp := range compositors { - fmt.Printf("%d) %s\n", i+1, comp) - } - - var response string - fmt.Print("Choose compositor for greeter: ") - fmt.Scanln(&response) - response = strings.TrimSpace(response) - - choice := 0 - fmt.Sscanf(response, "%d", &choice) - - if choice < 1 || choice > len(compositors) { - return "", fmt.Errorf("invalid choice") - } - - return compositors[choice-1], nil -} - -func checkGreeterStatus() error { - fmt.Println("=== DMS Greeter Status ===") - fmt.Println() - - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - currentUser, err := user.Current() - if err != nil { - return fmt.Errorf("failed to get current user: %w", err) - } - - configPath := "/etc/greetd/config.toml" - configuredCommand := "" - allGood := true - fmt.Println("Greeter Configuration:") - if _, err := os.ReadFile(configPath); err == nil { - configuredCommand = readDefaultSessionCommand(configPath) - if configuredCommand != "" && strings.Contains(configuredCommand, "dms-greeter") { - fmt.Println(" ✓ Greeter is enabled") - if wrapper := extractGreeterWrapperFromCommand(configuredCommand); wrapper != "" { - fmt.Printf(" Wrapper: %s\n", wrapper) - } - if pathOverride := extractGreeterPathOverrideFromCommand(configuredCommand); pathOverride != "" { - fmt.Printf(" DMS path override: %s\n", pathOverride) - } - - compositor := detectConfiguredCompositor() - switch compositor { - case "niri": - fmt.Println(" Compositor: niri") - case "hyprland": - fmt.Println(" Compositor: Hyprland") - case "sway": - fmt.Println(" Compositor: sway") - default: - fmt.Println(" Compositor: unknown") - } - } else { - fmt.Println(" ✗ Greeter is NOT enabled") - fmt.Println(" Run 'dms greeter enable' to enable it, or use the Activate button in Settings → Greeter, then Sync.") - allGood = false - } - } else { - fmt.Println(" ✗ Greeter config not found") - fmt.Printf(" %s\n", packageInstallHint()) - allGood = false - } - - fmt.Println("\nGroup Membership:") - groupsCmd := exec.Command("groups", currentUser.Username) - groupsOutput, err := groupsCmd.Output() - if err != nil { - return fmt.Errorf("failed to check groups: %w", err) - } - - greeterGroup := greeter.DetectGreeterGroup() - inGreeterGroup := strings.Contains(string(groupsOutput), greeterGroup) - if inGreeterGroup { - fmt.Printf(" ✓ User is in %s group\n", greeterGroup) - } else { - fmt.Printf(" ✗ User is NOT in %s group\n", greeterGroup) - fmt.Println(" Run 'dms greeter sync' to set up group membership and permissions") - } - - cacheDir := extractGreeterCacheDirFromCommand(configuredCommand) - fmt.Println("\nGreeter Cache Directory:") - fmt.Printf(" Effective cache dir: %s\n", cacheDir) - if cacheDir != greeter.GreeterCacheDir { - fmt.Printf(" ⚠ Non-default cache dir detected (default: %s)\n", greeter.GreeterCacheDir) - } - if stat, err := os.Stat(cacheDir); err == nil && stat.IsDir() { - fmt.Printf(" ✓ %s exists\n", cacheDir) - requiredSubdirs := []string{".local/state", ".local/share", ".cache"} - missingSubdirs := false - for _, sub := range requiredSubdirs { - subPath := filepath.Join(cacheDir, sub) - if _, err := os.Stat(subPath); os.IsNotExist(err) { - fmt.Printf(" ⚠ Missing required subdir: %s\n", subPath) - missingSubdirs = true - } - } - if missingSubdirs { - fmt.Println(" Run 'dms greeter sync' to initialize the cache directory structure.") - allGood = false - } - } else { - fmt.Printf(" ✗ %s not found\n", cacheDir) - fmt.Printf(" %s\n", packageInstallHint()) - return nil - } - - fmt.Println("\nConfiguration Symlinks:") - colorSyncInfo, colorSyncErr := greeter.ResolveGreeterColorSyncInfo(homeDir) - if colorSyncErr != nil { - fmt.Printf(" ✗ Failed to resolve expected greeter color source: %v\n", colorSyncErr) - allGood = false - colorSyncInfo = greeter.GreeterColorSyncInfo{ - SourcePath: filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json"), - } - } - - colorThemeDesc := "Color theme" - if colorSyncInfo.UsesDynamicWallpaperOverride { - colorThemeDesc = "Color theme (greeter wallpaper override)" - } - - symlinks := []struct { - source string - target string - desc string - }{ - { - source: filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"), - target: filepath.Join(cacheDir, "settings.json"), - desc: "Settings", - }, - { - source: filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"), - target: filepath.Join(cacheDir, "session.json"), - desc: "Session state", - }, - { - source: colorSyncInfo.SourcePath, - target: filepath.Join(cacheDir, "colors.json"), - desc: colorThemeDesc, - }, - } - - for _, link := range symlinks { - targetInfo, err := os.Lstat(link.target) - if err != nil { - fmt.Printf(" ✗ %s: symlink not found at %s\n", link.desc, link.target) - allGood = false - continue - } - - if targetInfo.Mode()&os.ModeSymlink == 0 { - fmt.Printf(" ✗ %s: %s is not a symlink\n", link.desc, link.target) - allGood = false - continue - } - - linkDest, err := os.Readlink(link.target) - if err != nil { - fmt.Printf(" ✗ %s: failed to read symlink\n", link.desc) - allGood = false - continue - } - - if linkDest != link.source { - fmt.Printf(" ✗ %s: symlink points to wrong location\n", link.desc) - fmt.Printf(" Expected: %s\n", link.source) - fmt.Printf(" Got: %s\n", linkDest) - allGood = false - continue - } - - if _, err := os.Stat(link.source); os.IsNotExist(err) { - fmt.Printf(" ⚠ %s: symlink OK, but source file doesn't exist yet\n", link.desc) - fmt.Printf(" Will be created when you run DMS\n") - continue - } - - fmt.Printf(" ✓ %s: synced correctly\n", link.desc) - } - - if colorSyncInfo.UsesDynamicWallpaperOverride { - fmt.Printf(" ℹ Dynamic theme uses greeter override colors from %s\n", colorSyncInfo.SourcePath) - } - - fmt.Println("\nGreeter Wallpaper Override:") - overridePath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg") - if stat, err := os.Stat(overridePath); err == nil && !stat.IsDir() { - fmt.Printf(" ✓ Override file present: %s\n", overridePath) - } else if os.IsNotExist(err) { - fmt.Println(" ℹ Override file not present (desktop/session wallpaper fallback in effect)") - } else if err != nil { - fmt.Printf(" ✗ Could not inspect override file: %v\n", err) - allGood = false - } else { - fmt.Printf(" ✗ Override path is not a regular file: %s\n", overridePath) - allGood = false - } - - fmt.Println("\nGreeter PAM Authentication (DMS-managed block):") - if greeter.IsNixOS() { - fmt.Println(" ℹ NixOS detected: PAM is managed by NixOS modules.") - fmt.Println(" Configure fingerprint/U2F via your greetd NixOS module (security.pam.services.greetd).") - fmt.Println() - if allGood && inGreeterGroup { - fmt.Println("✓ All checks passed! Greeter is properly configured.") - } else if !allGood { - fmt.Println("⚠ Some issues detected. Run 'dms greeter sync' to repair configuration.") - } else if !inGreeterGroup { - fmt.Printf("⚠ User is not in %s group. Run 'dms greeter sync' after adding group membership.\n", greeterGroup) - } - return nil - } - greetdPamPath := "/etc/pam.d/greetd" - pamData, err := os.ReadFile(greetdPamPath) - if err != nil { - fmt.Printf(" ✗ Failed to read %s: %v\n", greetdPamPath, err) - allGood = false - } else { - managed, managedFprint, managedU2f, legacyManaged := parseManagedGreeterPamAuth(string(pamData)) - if managed { - fmt.Println(" ✓ Managed auth block present") - if managedFprint { - fmt.Println(" - fingerprint: enabled") - } else { - fmt.Println(" - fingerprint: disabled") - } - if managedU2f { - fmt.Println(" - security key (U2F): enabled") - } else { - fmt.Println(" - security key (U2F): disabled") - } - } else { - fmt.Println(" ℹ No managed auth block present (DMS-managed fingerprint/U2F lines are disabled)") - } - if legacyManaged { - fmt.Println(" ⚠ Legacy unmanaged DMS PAM lines detected. Run 'dms auth sync' to normalize.") - allGood = false - } - enableFprintToggle, enableU2fToggle := false, false - if enableFprint, enableU2f, settingsErr := sharedpam.ReadGreeterAuthToggles(homeDir); settingsErr == nil { - enableFprintToggle = enableFprint - enableU2fToggle = enableU2f - } else { - fmt.Printf(" ℹ Could not read greeter auth toggles from settings: %v\n", settingsErr) - } - - includedFprintFile := sharedpam.DetectIncludedPamModule(string(pamData), "pam_fprintd.so") - includedU2fFile := sharedpam.DetectIncludedPamModule(string(pamData), "pam_u2f.so") - fprintAvailableForCurrentUser := sharedpam.FingerprintAuthAvailableForCurrentUser() - - if managedFprint && includedFprintFile != "" { - fmt.Printf(" ⚠ pam_fprintd found in both DMS managed block and %s.\n", includedFprintFile) - fmt.Println(" Double fingerprint auth detected — run 'dms auth sync' to resolve.") - allGood = false - } - if managedU2f && includedU2fFile != "" { - fmt.Printf(" ⚠ pam_u2f found in both DMS managed block and %s.\n", includedU2fFile) - fmt.Println(" Double security-key auth detected — run 'dms auth sync' to resolve.") - allGood = false - } - - if includedFprintFile != "" && !managedFprint { - if enableFprintToggle { - fmt.Printf(" ℹ Fingerprint auth is enabled via included %s.\n", includedFprintFile) - if fprintAvailableForCurrentUser { - fmt.Println(" DMS toggle is enabled, and effective auth is coming from the included PAM stack.") - } else { - fmt.Println(" No enrolled fingerprints detected for the current user; password auth remains the effective path.") - } - } else { - if fprintAvailableForCurrentUser { - fmt.Printf(" ℹ Fingerprint auth is active via included %s while DMS fingerprint toggle is off.\n", includedFprintFile) - fmt.Println(" Password login will work but may be delayed while the fingerprint module runs first.") - fmt.Printf(" To eliminate the delay, %s\n", systemPamManagerRemediationHint()) - } else { - fmt.Printf(" ℹ pam_fprintd is present via included %s, but no enrolled fingerprints were detected for user %s.\n", includedFprintFile, currentUser.Username) - fmt.Println(" Password auth remains the effective login path.") - } - } - } - if includedU2fFile != "" && !managedU2f { - if enableU2fToggle { - fmt.Printf(" ℹ Security-key auth is enabled via included %s.\n", includedU2fFile) - fmt.Println(" DMS toggle is enabled, but effective auth is coming from the included PAM stack.") - } else { - fmt.Printf(" ⚠ Security-key auth is active via included %s while DMS security-key toggle is off.\n", includedU2fFile) - fmt.Printf(" %s\n", systemPamManagerRemediationHint()) - } - } - } - - fmt.Println("\nSecurity (AppArmor):") - if !greeter.IsAppArmorEnabled() { - fmt.Println(" ℹ AppArmor not enabled") - } else { - fmt.Println(" ℹ AppArmor is enabled") - - const appArmorProfilePath = "/etc/apparmor.d/usr.bin.dms-greeter" - if _, err := os.Stat(appArmorProfilePath); os.IsNotExist(err) { - fmt.Println(" ⚠ DMS AppArmor profile not installed") - fmt.Println(" Run 'dms greeter sync' to install it and prevent potential TTY fallback") - allGood = false - } else { - mode := appArmorProfileMode("dms-greeter") - if mode != "" { - fmt.Printf(" ✓ DMS AppArmor profile installed (%s mode)\n", mode) - } else { - fmt.Println(" ✓ DMS AppArmor profile installed") - } - } - - denialCount, denialSamples, denialErr := recentAppArmorGreeterDenials(3) - if denialErr != nil { - fmt.Printf(" ℹ Could not inspect AppArmor denials automatically: %v\n", denialErr) - fmt.Println(" If greetd falls back to TTY, run: sudo journalctl -b -k | grep 'apparmor.*DENIED'") - } else if denialCount > 0 { - fmt.Printf(" ⚠ Found %d recent AppArmor denial(s) related to greeter runtime.\n", denialCount) - fmt.Println(" This can cause greetd fallback to TTY (for example: 'Failed to create stream fd: Permission denied').") - fmt.Println(" Review denials with: sudo journalctl -b -k | grep 'apparmor.*DENIED'") - fmt.Println(" Then refine the profile with: sudo aa-logprof") - for i, sample := range denialSamples { - fmt.Printf(" %d) %s\n", i+1, sample) - } - allGood = false - } else { - fmt.Println(" ✓ No recent AppArmor denials detected for common greeter components") - } - } - - fmt.Println() - if allGood && inGreeterGroup { - fmt.Println("✓ All checks passed! Greeter is properly configured.") - } else if !allGood { - fmt.Println("⚠ Some issues detected. Run 'dms greeter sync' to repair configuration.") - } else if !inGreeterGroup { - fmt.Printf("⚠ User is not in %s group. Run 'dms greeter sync' after adding group membership.\n", greeterGroup) - } - - return nil -} - -func recentAppArmorGreeterDenials(sampleLimit int) (int, []string, error) { - if sampleLimit <= 0 { - sampleLimit = 3 - } - if !utils.CommandExists("journalctl") { - return 0, nil, fmt.Errorf("journalctl not found") - } - - queries := [][]string{ - {"-b", "-k", "--no-pager", "-n", "2000", "-o", "cat"}, - {"-b", "--no-pager", "-n", "2000", "-o", "cat"}, - } - - seen := make(map[string]bool) - samples := make([]string, 0, sampleLimit) - total := 0 - var lastErr error - successfulQuery := false - - for _, query := range queries { - cmd := exec.Command("journalctl", query...) - output, err := cmd.CombinedOutput() - if err != nil { - lastErr = err - continue - } - successfulQuery = true - total += collectGreeterAppArmorDenials(string(output), seen, &samples, sampleLimit) - } - - if !successfulQuery && lastErr != nil { - return 0, nil, lastErr - } - - return total, samples, nil -} - -func collectGreeterAppArmorDenials(text string, seen map[string]bool, samples *[]string, sampleLimit int) int { - count := 0 - for _, rawLine := range strings.Split(text, "\n") { - line := strings.TrimSpace(rawLine) - if line == "" || !isGreeterRelatedAppArmorDenial(line) { - continue - } - if seen[line] { - continue - } - seen[line] = true - count++ - if len(*samples) < sampleLimit { - *samples = append(*samples, line) - } - } - return count -} - -func isGreeterRelatedAppArmorDenial(line string) bool { - lower := strings.ToLower(line) - if !strings.Contains(lower, "apparmor") || !strings.Contains(lower, "denied") { - return false - } - - greeterTokens := []string{ - "dms-greeter", - "/usr/bin/dms-greeter", - "greetd", - "quickshell", - "/usr/bin/qs", - "/usr/bin/quickshell", - "niri", - "hyprland", - "sway", - "mango", - "miracle", - "labwc", - "pipewire", - "wireplumber", - "stream fd", - } - - for _, token := range greeterTokens { - if strings.Contains(lower, token) { - return true - } - } - return false -} - -// appArmorProfileMode returns "complain", "enforce", or "" for a named AppArmor profile. -func appArmorProfileMode(profileName string) string { - data, err := os.ReadFile("/sys/kernel/security/apparmor/profiles") - if err != nil { - return "" - } - for _, line := range strings.Split(string(data), "\n") { - line = strings.TrimSpace(line) - if !strings.Contains(line, profileName) { - continue - } - lower := strings.ToLower(line) - if strings.Contains(lower, "(complain)") { - return "complain" - } - if strings.Contains(lower, "(enforce)") { - return "enforce" - } - if strings.Contains(lower, "(kill)") { - return "kill" - } - } - return "" -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter_test.go deleted file mode 100644 index 775149f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_greeter_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package main - -import ( - "errors" - "reflect" - "testing" - - sharedpam "github.com/AvengeMedia/DankMaterialShell/core/internal/pam" -) - -func TestSyncGreeterConfigsAndAuthDelegatesSharedAuth(t *testing.T) { - origGreeterConfigSyncFn := greeterConfigSyncFn - origSharedAuthSyncFn := sharedAuthSyncFn - t.Cleanup(func() { - greeterConfigSyncFn = origGreeterConfigSyncFn - sharedAuthSyncFn = origSharedAuthSyncFn - }) - - var calls []string - greeterConfigSyncFn = func(dmsPath, compositor string, logFunc func(string), sudoPassword string) error { - if dmsPath != "/tmp/dms" { - t.Fatalf("unexpected dmsPath %q", dmsPath) - } - if compositor != "niri" { - t.Fatalf("unexpected compositor %q", compositor) - } - if sudoPassword != "" { - t.Fatalf("expected empty sudoPassword, got %q", sudoPassword) - } - calls = append(calls, "configs") - return nil - } - - var gotOptions sharedpam.SyncAuthOptions - sharedAuthSyncFn = func(logFunc func(string), sudoPassword string, options sharedpam.SyncAuthOptions) error { - if sudoPassword != "" { - t.Fatalf("expected empty sudoPassword, got %q", sudoPassword) - } - gotOptions = options - calls = append(calls, "auth") - return nil - } - - err := syncGreeterConfigsAndAuth("/tmp/dms", "niri", func(string) {}, sharedpam.SyncAuthOptions{ - ForceGreeterAuth: true, - }, func() { - calls = append(calls, "before-auth") - }) - if err != nil { - t.Fatalf("syncGreeterConfigsAndAuth returned error: %v", err) - } - - wantCalls := []string{"configs", "before-auth", "auth"} - if !reflect.DeepEqual(calls, wantCalls) { - t.Fatalf("call order = %v, want %v", calls, wantCalls) - } - if !gotOptions.ForceGreeterAuth { - t.Fatalf("expected ForceGreeterAuth to be true, got %+v", gotOptions) - } -} - -func TestSyncGreeterConfigsAndAuthStopsOnConfigError(t *testing.T) { - origGreeterConfigSyncFn := greeterConfigSyncFn - origSharedAuthSyncFn := sharedAuthSyncFn - t.Cleanup(func() { - greeterConfigSyncFn = origGreeterConfigSyncFn - sharedAuthSyncFn = origSharedAuthSyncFn - }) - - greeterConfigSyncFn = func(string, string, func(string), string) error { - return errors.New("config sync failed") - } - - authCalled := false - sharedAuthSyncFn = func(func(string), string, sharedpam.SyncAuthOptions) error { - authCalled = true - return nil - } - - err := syncGreeterConfigsAndAuth("/tmp/dms", "niri", func(string) {}, sharedpam.SyncAuthOptions{}, nil) - if err == nil || err.Error() != "config sync failed" { - t.Fatalf("expected config sync error, got %v", err) - } - if authCalled { - t.Fatal("expected auth sync not to run after config sync failure") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_keybinds.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_keybinds.go deleted file mode 100644 index cdb15ac..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_keybinds.go +++ /dev/null @@ -1,265 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds/providers" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/cobra" -) - -var keybindsCmd = &cobra.Command{ - Use: "keybinds", - Aliases: []string{"cheatsheet", "chsht"}, - Short: "Manage keybinds and cheatsheets", - Long: "Display and manage keybinds and cheatsheets for various applications", -} - -var keybindsListCmd = &cobra.Command{ - Use: "list", - Short: "List available providers", - Long: "List all available keybind/cheatsheet providers", - Run: runKeybindsList, -} - -var keybindsShowCmd = &cobra.Command{ - Use: "show ", - Short: "Show keybinds for a provider", - Long: "Display keybinds/cheatsheet for the specified provider", - Args: cobra.ExactArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - registry := keybinds.GetDefaultRegistry() - return registry.List(), cobra.ShellCompDirectiveNoFileComp - }, - Run: runKeybindsShow, -} - -var keybindsSetCmd = &cobra.Command{ - Use: "set ", - Short: "Set a keybind override", - Long: "Create or update a keybind override for the specified provider", - Args: cobra.ExactArgs(3), - Run: runKeybindsSet, -} - -var keybindsRemoveCmd = &cobra.Command{ - Use: "remove ", - Short: "Remove a keybind override", - Long: "Remove a keybind override from the specified provider", - Args: cobra.ExactArgs(2), - Run: runKeybindsRemove, -} - -func init() { - keybindsListCmd.Flags().BoolP("json", "j", false, "Output as JSON") - keybindsShowCmd.Flags().String("path", "", "Override config path for the provider") - keybindsSetCmd.Flags().String("desc", "", "Description for hotkey overlay") - keybindsSetCmd.Flags().Bool("allow-when-locked", false, "Allow when screen is locked") - keybindsSetCmd.Flags().Int("cooldown-ms", 0, "Cooldown in milliseconds") - keybindsSetCmd.Flags().Bool("no-repeat", false, "Disable key repeat") - keybindsSetCmd.Flags().Bool("no-inhibiting", false, "Keep bind active when shortcuts are inhibited (allow-inhibiting=false)") - keybindsSetCmd.Flags().String("replace-key", "", "Original key to replace (removes old key)") - keybindsSetCmd.Flags().String("flags", "", "Hyprland bind flags (e.g., 'e' for repeat, 'l' for locked, 'r' for release)") - - keybindsCmd.AddCommand(keybindsListCmd) - keybindsCmd.AddCommand(keybindsShowCmd) - keybindsCmd.AddCommand(keybindsSetCmd) - keybindsCmd.AddCommand(keybindsRemoveCmd) - - keybinds.SetJSONProviderFactory(func(filePath string) (keybinds.Provider, error) { - return providers.NewJSONFileProvider(filePath) - }) - - initializeProviders() -} - -func initializeProviders() { - registry := keybinds.GetDefaultRegistry() - - hyprlandProvider := providers.NewHyprlandProvider("") - if err := registry.Register(hyprlandProvider); err != nil { - log.Warnf("Failed to register Hyprland provider: %v", err) - } - - mangowcProvider := providers.NewMangoWCProvider("") - if err := registry.Register(mangowcProvider); err != nil { - log.Warnf("Failed to register MangoWC provider: %v", err) - } - - configDir, _ := os.UserConfigDir() - - if configDir != "" { - scrollProvider := providers.NewSwayProvider(filepath.Join(configDir, "scroll")) - if err := registry.Register(scrollProvider); err != nil { - log.Warnf("Failed to register Scroll provider: %v", err) - } - } - - miracleProvider := providers.NewMiracleProvider("") - if err := registry.Register(miracleProvider); err != nil { - log.Warnf("Failed to register Miracle WM provider: %v", err) - } - - if configDir != "" { - swayProvider := providers.NewSwayProvider(filepath.Join(configDir, "sway")) - if err := registry.Register(swayProvider); err != nil { - log.Warnf("Failed to register Sway provider: %v", err) - } - } - - niriProvider := providers.NewNiriProvider("") - if err := registry.Register(niriProvider); err != nil { - log.Warnf("Failed to register Niri provider: %v", err) - } - - config := keybinds.DefaultDiscoveryConfig() - if err := keybinds.AutoDiscoverProviders(registry, config); err != nil { - log.Warnf("Failed to auto-discover providers: %v", err) - } -} - -func runKeybindsList(cmd *cobra.Command, _ []string) { - providerList := keybinds.GetDefaultRegistry().List() - asJSON, _ := cmd.Flags().GetBool("json") - - if asJSON { - output, _ := json.Marshal(providerList) - fmt.Fprintln(os.Stdout, string(output)) - return - } - - if len(providerList) == 0 { - fmt.Fprintln(os.Stdout, "No providers available") - return - } - - fmt.Fprintln(os.Stdout, "Available providers:") - for _, name := range providerList { - fmt.Fprintf(os.Stdout, " - %s\n", name) - } -} - -func makeProviderWithPath(name, path string) keybinds.Provider { - switch name { - case "hyprland": - return providers.NewHyprlandProvider(path) - case "mangowc": - return providers.NewMangoWCProvider(path) - case "sway": - return providers.NewSwayProvider(path) - case "scroll": - return providers.NewSwayProvider(path) - case "miracle": - return providers.NewMiracleProvider(path) - case "niri": - return providers.NewNiriProvider(path) - default: - return nil - } -} - -func printCheatSheet(provider keybinds.Provider) { - sheet, err := provider.GetCheatSheet() - if err != nil { - log.Fatalf("Error getting cheatsheet: %v", err) - } - output, err := json.MarshalIndent(sheet, "", " ") - if err != nil { - log.Fatalf("Error generating JSON: %v", err) - } - fmt.Fprintln(os.Stdout, string(output)) -} - -func runKeybindsShow(cmd *cobra.Command, args []string) { - providerName := args[0] - customPath, _ := cmd.Flags().GetString("path") - - if customPath != "" { - provider := makeProviderWithPath(providerName, customPath) - if provider == nil { - log.Fatalf("Provider %s does not support custom path", providerName) - } - printCheatSheet(provider) - return - } - - provider, err := keybinds.GetDefaultRegistry().Get(providerName) - if err != nil { - log.Fatalf("Error: %v", err) - } - printCheatSheet(provider) -} - -func getWritableProvider(name string) keybinds.WritableProvider { - provider, err := keybinds.GetDefaultRegistry().Get(name) - if err != nil { - log.Fatalf("Error: %v", err) - } - writable, ok := provider.(keybinds.WritableProvider) - if !ok { - log.Fatalf("Provider %s does not support writing keybinds", name) - } - return writable -} - -func runKeybindsSet(cmd *cobra.Command, args []string) { - providerName, key, action := args[0], args[1], args[2] - writable := getWritableProvider(providerName) - - if replaceKey, _ := cmd.Flags().GetString("replace-key"); replaceKey != "" && replaceKey != key { - _ = writable.RemoveBind(replaceKey) - } - - options := make(map[string]any) - if v, _ := cmd.Flags().GetBool("allow-when-locked"); v { - options["allow-when-locked"] = true - } - if v, _ := cmd.Flags().GetInt("cooldown-ms"); v > 0 { - options["cooldown-ms"] = v - } - if v, _ := cmd.Flags().GetBool("no-repeat"); v { - options["repeat"] = false - } - if v, _ := cmd.Flags().GetBool("no-inhibiting"); v { - options["allow-inhibiting"] = false - } - if v, _ := cmd.Flags().GetString("flags"); v != "" { - options["flags"] = v - } - - desc, _ := cmd.Flags().GetString("desc") - if err := writable.SetBind(key, action, desc, options); err != nil { - log.Fatalf("Error setting keybind: %v", err) - } - - output, _ := json.MarshalIndent(map[string]any{ - "success": true, - "key": key, - "action": action, - "path": writable.GetOverridePath(), - }, "", " ") - fmt.Fprintln(os.Stdout, string(output)) -} - -func runKeybindsRemove(_ *cobra.Command, args []string) { - providerName, key := args[0], args[1] - writable := getWritableProvider(providerName) - - if err := writable.RemoveBind(key); err != nil { - log.Fatalf("Error removing keybind: %v", err) - } - - output, _ := json.MarshalIndent(map[string]any{ - "success": true, - "key": key, - "removed": true, - }, "", " ") - fmt.Fprintln(os.Stdout, string(output)) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_matugen.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_matugen.go deleted file mode 100644 index 566f360..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_matugen.go +++ /dev/null @@ -1,202 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "os" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/matugen" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/spf13/cobra" -) - -var matugenCmd = &cobra.Command{ - Use: "matugen", - Short: "Generate Material Design themes", - Long: "Generate Material Design themes using matugen with dank16 color integration", -} - -var matugenGenerateCmd = &cobra.Command{ - Use: "generate", - Short: "Generate theme synchronously", - Run: runMatugenGenerate, -} - -var matugenQueueCmd = &cobra.Command{ - Use: "queue", - Short: "Queue theme generation (uses socket if available)", - Run: runMatugenQueue, -} - -var matugenCheckCmd = &cobra.Command{ - Use: "check", - Short: "Check which template apps are detected", - Run: runMatugenCheck, -} - -func init() { - matugenCmd.AddCommand(matugenGenerateCmd) - matugenCmd.AddCommand(matugenQueueCmd) - matugenCmd.AddCommand(matugenCheckCmd) - - for _, cmd := range []*cobra.Command{matugenGenerateCmd, matugenQueueCmd} { - cmd.Flags().String("state-dir", "", "State directory for cache files") - cmd.Flags().String("shell-dir", "", "DMS shell installation directory") - cmd.Flags().String("config-dir", "", "User config directory") - cmd.Flags().String("kind", "image", "Source type: image or hex") - cmd.Flags().String("value", "", "Wallpaper path or hex color") - cmd.Flags().String("mode", "dark", "Color mode: dark or light") - cmd.Flags().String("icon-theme", "System Default", "Icon theme name") - cmd.Flags().String("matugen-type", "scheme-tonal-spot", "Matugen scheme type") - cmd.Flags().Bool("run-user-templates", true, "Run user matugen templates") - cmd.Flags().String("stock-colors", "", "Stock theme colors JSON") - cmd.Flags().Bool("sync-mode-with-portal", false, "Sync color scheme with GNOME portal") - cmd.Flags().Bool("terminals-always-dark", false, "Force terminal themes to dark variant") - cmd.Flags().String("skip-templates", "", "Comma-separated list of templates to skip") - cmd.Flags().Float64("contrast", 0, "Contrast value from -1 to 1 (0 = standard)") - } - - matugenQueueCmd.Flags().Bool("wait", true, "Wait for completion") - matugenQueueCmd.Flags().Duration("timeout", 90*time.Second, "Timeout for waiting") -} - -func buildMatugenOptions(cmd *cobra.Command) matugen.Options { - stateDir, _ := cmd.Flags().GetString("state-dir") - shellDir, _ := cmd.Flags().GetString("shell-dir") - configDir, _ := cmd.Flags().GetString("config-dir") - kind, _ := cmd.Flags().GetString("kind") - value, _ := cmd.Flags().GetString("value") - mode, _ := cmd.Flags().GetString("mode") - iconTheme, _ := cmd.Flags().GetString("icon-theme") - matugenType, _ := cmd.Flags().GetString("matugen-type") - runUserTemplates, _ := cmd.Flags().GetBool("run-user-templates") - stockColors, _ := cmd.Flags().GetString("stock-colors") - syncModeWithPortal, _ := cmd.Flags().GetBool("sync-mode-with-portal") - terminalsAlwaysDark, _ := cmd.Flags().GetBool("terminals-always-dark") - skipTemplates, _ := cmd.Flags().GetString("skip-templates") - contrast, _ := cmd.Flags().GetFloat64("contrast") - - return matugen.Options{ - StateDir: stateDir, - ShellDir: shellDir, - ConfigDir: configDir, - Kind: kind, - Value: value, - Mode: matugen.ColorMode(mode), - IconTheme: iconTheme, - MatugenType: matugenType, - Contrast: contrast, - RunUserTemplates: runUserTemplates, - StockColors: stockColors, - SyncModeWithPortal: syncModeWithPortal, - TerminalsAlwaysDark: terminalsAlwaysDark, - SkipTemplates: skipTemplates, - } -} - -func runMatugenGenerate(cmd *cobra.Command, args []string) { - opts := buildMatugenOptions(cmd) - err := matugen.Run(opts) - switch { - case errors.Is(err, matugen.ErrNoChanges): - os.Exit(2) - case err != nil: - log.Fatalf("Theme generation failed: %v", err) - } -} - -func runMatugenQueue(cmd *cobra.Command, args []string) { - opts := buildMatugenOptions(cmd) - wait, _ := cmd.Flags().GetBool("wait") - timeout, _ := cmd.Flags().GetDuration("timeout") - - request := models.Request{ - ID: 1, - Method: "matugen.queue", - Params: map[string]any{ - "stateDir": opts.StateDir, - "shellDir": opts.ShellDir, - "configDir": opts.ConfigDir, - "kind": opts.Kind, - "value": opts.Value, - "mode": opts.Mode, - "iconTheme": opts.IconTheme, - "matugenType": opts.MatugenType, - "runUserTemplates": opts.RunUserTemplates, - "stockColors": opts.StockColors, - "syncModeWithPortal": opts.SyncModeWithPortal, - "terminalsAlwaysDark": opts.TerminalsAlwaysDark, - "skipTemplates": opts.SkipTemplates, - "contrast": opts.Contrast, - "wait": wait, - }, - } - - if !wait { - if err := sendServerRequestFireAndForget(request); err != nil { - log.Info("Server unavailable, running synchronously") - err := matugen.Run(opts) - switch { - case errors.Is(err, matugen.ErrNoChanges): - os.Exit(2) - case err != nil: - log.Fatalf("Theme generation failed: %v", err) - } - return - } - fmt.Println("Theme generation queued") - return - } - - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - resultCh := make(chan error, 1) - go func() { - resp, ok := tryServerRequest(request) - if !ok { - log.Info("Server unavailable, running synchronously") - err := matugen.Run(opts) - switch { - case errors.Is(err, matugen.ErrNoChanges): - resultCh <- matugen.ErrNoChanges - case err != nil: - resultCh <- err - default: - resultCh <- nil - } - return - } - if resp.Error != "" { - resultCh <- fmt.Errorf("server error: %s", resp.Error) - return - } - resultCh <- nil - }() - - select { - case err := <-resultCh: - switch { - case errors.Is(err, matugen.ErrNoChanges): - os.Exit(2) - case err != nil: - log.Fatalf("Theme generation failed: %v", err) - } - fmt.Println("Theme generation completed") - case <-ctx.Done(): - log.Fatalf("Timeout waiting for theme generation") - } -} - -func runMatugenCheck(cmd *cobra.Command, args []string) { - checks := matugen.CheckTemplates(nil) - data, err := json.Marshal(checks) - if err != nil { - log.Fatalf("Failed to marshal check results: %v", err) - } - fmt.Println(string(data)) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_notify.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_notify.go deleted file mode 100644 index e04b60f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_notify.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/notify" - "github.com/spf13/cobra" -) - -var ( - notifyAppName string - notifyIcon string - notifyFile string - notifyTimeout int -) - -var notifyCmd = &cobra.Command{ - Use: "notify [body]", - Short: "Send a desktop notification", - Long: `Send a desktop notification with optional actions. - -If --file is provided, the notification will have "Open" and "Open Folder" actions. - -Examples: - dms notify "Hello" "World" - dms notify "File received" "photo.jpg" --file ~/Downloads/photo.jpg --icon smartphone - dms notify "Download complete" --file ~/Downloads/file.zip --app "My App"`, - Args: cobra.MinimumNArgs(1), - Run: runNotify, -} - -var genericNotifyActionCmd = &cobra.Command{ - Use: "notify-action-generic", - Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - notify.RunActionListener(args) - }, -} - -func init() { - notifyCmd.Flags().StringVar(¬ifyAppName, "app", "DMS", "Application name") - notifyCmd.Flags().StringVar(¬ifyIcon, "icon", "", "Icon name or path") - notifyCmd.Flags().StringVar(¬ifyFile, "file", "", "File path (enables Open/Open Folder actions)") - notifyCmd.Flags().IntVar(¬ifyTimeout, "timeout", 5000, "Timeout in milliseconds") -} - -func runNotify(cmd *cobra.Command, args []string) { - summary := args[0] - body := "" - if len(args) > 1 { - body = args[1] - } - - n := notify.Notification{ - AppName: notifyAppName, - Icon: notifyIcon, - Summary: summary, - Body: body, - FilePath: notifyFile, - Timeout: int32(notifyTimeout), - } - - if err := notify.Send(n); err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_open.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_open.go deleted file mode 100644 index 8cc16cf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_open.go +++ /dev/null @@ -1,205 +0,0 @@ -package main - -import ( - "fmt" - "mime" - "net/url" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/spf13/cobra" -) - -var ( - openMimeType string - openCategories []string - openRequestType string -) - -var openCmd = &cobra.Command{ - Use: "open [target]", - Short: "Open a file, URL, or resource with an application picker", - Long: `Open a target (URL, file, or other resource) using the DMS application picker. -By default, this opens URLs with the browser picker. You can customize the behavior -with flags to handle different MIME types or application categories. - -Examples: - dms open https://example.com # Open URL with browser picker - dms open file.pdf --mime application/pdf # Open PDF with compatible apps - dms open document.odt --category Office # Open with office applications - dms open --mime image/png image.png # Open image with image viewers`, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - runOpen(args[0]) - }, -} - -func init() { - rootCmd.AddCommand(openCmd) - openCmd.Flags().StringVar(&openMimeType, "mime", "", "MIME type for filtering applications") - openCmd.Flags().StringSliceVar(&openCategories, "category", []string{}, "Application categories to filter (e.g., WebBrowser, Office, Graphics)") - openCmd.Flags().StringVar(&openRequestType, "type", "url", "Request type (url, file, or custom)") - _ = openCmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"url", "file", "custom"}, cobra.ShellCompDirectiveNoFileComp - }) -} - -// mimeTypeToCategories maps MIME types to desktop file categories -func mimeTypeToCategories(mimeType string) []string { - // Split MIME type to get the main type - parts := strings.Split(mimeType, "/") - if len(parts) < 1 { - return nil - } - - mainType := parts[0] - - switch mainType { - case "image": - return []string{"Graphics", "Viewer"} - case "video": - return []string{"Video", "AudioVideo"} - case "audio": - return []string{"Audio", "AudioVideo"} - case "text": - if strings.Contains(mimeType, "html") { - return []string{"WebBrowser"} - } - return []string{"TextEditor", "Office"} - case "application": - if strings.Contains(mimeType, "pdf") { - return []string{"Office", "Viewer"} - } - if strings.Contains(mimeType, "document") || strings.Contains(mimeType, "spreadsheet") || - strings.Contains(mimeType, "presentation") || strings.Contains(mimeType, "msword") || - strings.Contains(mimeType, "ms-excel") || strings.Contains(mimeType, "ms-powerpoint") || - strings.Contains(mimeType, "opendocument") { - return []string{"Office"} - } - if strings.Contains(mimeType, "zip") || strings.Contains(mimeType, "tar") || - strings.Contains(mimeType, "gzip") || strings.Contains(mimeType, "compress") { - return []string{"Archiving", "Utility"} - } - return []string{"Office", "Viewer"} - } - - return nil -} - -func runOpen(target string) { - // Parse file:// URIs to extract the actual file path - actualTarget := target - detectedMimeType := openMimeType - detectedCategories := openCategories - detectedRequestType := openRequestType - - log.Infof("Processing target: %s", target) - - if parsedURL, err := url.Parse(target); err == nil && parsedURL.Scheme == "file" { - // Extract file path from file:// URI and convert to absolute path - actualTarget = parsedURL.Path - if absPath, err := filepath.Abs(actualTarget); err == nil { - actualTarget = absPath - } - - if detectedRequestType == "url" || detectedRequestType == "" { - detectedRequestType = "file" - } - - log.Infof("Detected file:// URI, extracted absolute path: %s", actualTarget) - - // Auto-detect MIME type if not provided - if detectedMimeType == "" { - ext := filepath.Ext(actualTarget) - if ext != "" { - detectedMimeType = mime.TypeByExtension(ext) - log.Infof("Detected MIME type from extension %s: %s", ext, detectedMimeType) - } - } - - // Auto-detect categories based on MIME type if not provided - if len(detectedCategories) == 0 && detectedMimeType != "" { - detectedCategories = mimeTypeToCategories(detectedMimeType) - log.Infof("Detected categories from MIME type: %v", detectedCategories) - } - } else if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") { - // Handle HTTP(S) URLs - if detectedRequestType == "" { - detectedRequestType = "url" - } - log.Infof("Detected HTTP(S) URL") - } else if strings.HasPrefix(target, "dms://") { - // Handle DMS internal URLs (theme/plugin install, etc.) - if detectedRequestType == "" { - detectedRequestType = "url" - } - log.Infof("Detected DMS internal URL") - } else if _, err := os.Stat(target); err == nil { - // Handle local file paths directly (not file:// URIs) - // Convert to absolute path - if absPath, err := filepath.Abs(target); err == nil { - actualTarget = absPath - } - - if detectedRequestType == "url" || detectedRequestType == "" { - detectedRequestType = "file" - } - - log.Infof("Detected local file path, converted to absolute: %s", actualTarget) - - // Auto-detect MIME type if not provided - if detectedMimeType == "" { - ext := filepath.Ext(actualTarget) - if ext != "" { - detectedMimeType = mime.TypeByExtension(ext) - log.Infof("Detected MIME type from extension %s: %s", ext, detectedMimeType) - } - } - - // Auto-detect categories based on MIME type if not provided - if len(detectedCategories) == 0 && detectedMimeType != "" { - detectedCategories = mimeTypeToCategories(detectedMimeType) - log.Infof("Detected categories from MIME type: %v", detectedCategories) - } - } - - params := map[string]any{ - "target": actualTarget, - } - - if detectedMimeType != "" { - params["mimeType"] = detectedMimeType - } - - if len(detectedCategories) > 0 { - params["categories"] = detectedCategories - } - - if detectedRequestType != "" { - params["requestType"] = detectedRequestType - } - - method := "apppicker.open" - if detectedMimeType == "" && len(detectedCategories) == 0 && (strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") || strings.HasPrefix(target, "dms://")) { - method = "browser.open" - params["url"] = target - } - - req := models.Request{ - ID: 1, - Method: method, - Params: params, - } - - log.Infof("Sending request - Method: %s, Params: %+v", method, params) - - if err := sendServerRequestFireAndForget(req); err != nil { - fmt.Println("DMS is not running. Please start DMS first.") - os.Exit(1) - } - - log.Infof("Request sent successfully") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_randr.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_randr.go deleted file mode 100644 index fa0c990..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_randr.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/cobra" -) - -var randrCmd = &cobra.Command{ - Use: "randr", - Short: "Query output display information", - Long: "Query Wayland compositor for output names, scales, resolutions and refresh rates via zwlr-output-management", - Run: runRandr, -} - -func init() { - randrCmd.Flags().Bool("json", false, "Output in JSON format") -} - -type randrJSON struct { - Outputs []randrOutput `json:"outputs"` -} - -func runRandr(cmd *cobra.Command, args []string) { - outputs, err := queryRandr() - if err != nil { - log.Fatalf("%v", err) - } - - jsonFlag, _ := cmd.Flags().GetBool("json") - - if jsonFlag { - data, err := json.Marshal(randrJSON{Outputs: outputs}) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - fmt.Println(string(data)) - return - } - - for i, out := range outputs { - if i > 0 { - fmt.Println() - } - status := "enabled" - if !out.Enabled { - status = "disabled" - } - fmt.Printf("%s (%s)\n", out.Name, status) - fmt.Printf(" Scale: %.4g\n", out.Scale) - fmt.Printf(" Resolution: %dx%d\n", out.Width, out.Height) - if out.Refresh > 0 { - fmt.Printf(" Refresh: %.2f Hz\n", float64(out.Refresh)/1000.0) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_root.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_root.go deleted file mode 100644 index b263ae6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_root.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/cobra" -) - -var customConfigPath string -var configPath string - -var rootCmd = &cobra.Command{ - Use: "dms", - Short: "dms CLI", - Long: "dms is the DankMaterialShell management CLI and backend server.", -} - -func init() { - rootCmd.PersistentFlags().StringVarP(&customConfigPath, "config", "c", "", "Specify a custom path to the DMS config directory") -} - -func findConfig(cmd *cobra.Command, args []string) error { - if customConfigPath != "" { - log.Debug("Custom config path provided via -c flag: %s", customConfigPath) - shellPath := filepath.Join(customConfigPath, "shell.qml") - - info, statErr := os.Stat(shellPath) - - if statErr == nil && !info.IsDir() { - configPath = customConfigPath - log.Debug("Using config from: %s", configPath) - return nil - } - - if statErr != nil { - return fmt.Errorf("custom config path error: %w", statErr) - } - - return fmt.Errorf("path is a directory, not a file: %s", shellPath) - } - - configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path") - if data, readErr := os.ReadFile(configStateFile); readErr == nil { - if len(getAllDMSPIDs()) == 0 { - os.Remove(configStateFile) - } else { - statePath := strings.TrimSpace(string(data)) - shellPath := filepath.Join(statePath, "shell.qml") - - if info, statErr := os.Stat(shellPath); statErr == nil && !info.IsDir() { - log.Debug("Using config from active session state file: %s", statePath) - configPath = statePath - log.Debug("Using config from: %s", configPath) - return nil - } - os.Remove(configStateFile) - } - } - - log.Debug("No custom path or active session, searching default XDG locations...") - var err error - configPath, err = config.LocateDMSConfig() - if err != nil { - return err - } - - log.Debug("Using config from: %s", configPath) - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_screenshot.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_screenshot.go deleted file mode 100644 index 2875019..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_screenshot.go +++ /dev/null @@ -1,422 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/screenshot" - "github.com/spf13/cobra" -) - -var ( - ssOutputName string - ssCursor string - ssFormat string - ssQuality int - ssOutputDir string - ssFilename string - ssNoClipboard bool - ssNoFile bool - ssNoNotify bool - ssNoConfirm bool - ssReset bool - ssStdout bool -) - -var screenshotCmd = &cobra.Command{ - Use: "screenshot", - Short: "Capture screenshots", - Long: `Capture screenshots from Wayland displays. - -Modes: - region - Select a region interactively (default) - full - Capture the focused output - all - Capture all outputs combined - output - Capture a specific output by name - window - Capture the focused window (Hyprland/DWL) - last - Capture the last selected region - -Output format (--format): - png - PNG format (default) - jpg/jpeg - JPEG format - ppm - PPM format - -Examples: - dms screenshot # Region select, save file + clipboard - dms screenshot full # Full screen of focused output - dms screenshot all # All screens combined - dms screenshot output -o DP-1 # Specific output - dms screenshot window # Focused window (Hyprland) - dms screenshot last # Last region (pre-selected) - dms screenshot --reset # Reset last region pre-selection - dms screenshot --no-clipboard # Save file only - dms screenshot --no-file # Clipboard only - dms screenshot --no-confirm # Region capture on mouse release - dms screenshot --cursor=on # Include cursor - dms screenshot -f jpg -q 85 # JPEG with quality 85`, -} - -var ssRegionCmd = &cobra.Command{ - Use: "region", - Short: "Select a region interactively", - Run: runScreenshotRegion, -} - -var ssFullCmd = &cobra.Command{ - Use: "full", - Short: "Capture the focused output", - Run: runScreenshotFull, -} - -var ssAllCmd = &cobra.Command{ - Use: "all", - Short: "Capture all outputs combined", - Run: runScreenshotAll, -} - -var ssOutputCmd = &cobra.Command{ - Use: "output", - Short: "Capture a specific output", - Run: runScreenshotOutput, -} - -var ssLastCmd = &cobra.Command{ - Use: "last", - Short: "Capture the last selected region", - Long: `Capture the previously selected region without interactive selection. -If no previous region exists, falls back to interactive selection.`, - Run: runScreenshotLast, -} - -var ssWindowCmd = &cobra.Command{ - Use: "window", - Short: "Capture the focused window", - Long: `Capture the currently focused window. Supported on Hyprland and DWL.`, - Run: runScreenshotWindow, -} - -var ssListCmd = &cobra.Command{ - Use: "list", - Short: "List available outputs", - Run: runScreenshotList, -} - -var notifyActionCmd = &cobra.Command{ - Use: "notify-action", - Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - screenshot.RunNotifyActionListener(args) - }, -} - -func init() { - screenshotCmd.PersistentFlags().StringVarP(&ssOutputName, "output", "o", "", "Output name for 'output' mode") - screenshotCmd.PersistentFlags().StringVar(&ssCursor, "cursor", "off", "Include cursor in screenshot (on/off)") - screenshotCmd.PersistentFlags().StringVarP(&ssFormat, "format", "f", "png", "Output format (png, jpg, ppm)") - screenshotCmd.PersistentFlags().IntVarP(&ssQuality, "quality", "q", 90, "JPEG quality (1-100)") - screenshotCmd.PersistentFlags().StringVarP(&ssOutputDir, "dir", "d", "", "Output directory") - screenshotCmd.PersistentFlags().StringVar(&ssFilename, "filename", "", "Output filename (auto-generated if empty)") - screenshotCmd.PersistentFlags().BoolVar(&ssNoClipboard, "no-clipboard", false, "Don't copy to clipboard") - screenshotCmd.PersistentFlags().BoolVar(&ssNoFile, "no-file", false, "Don't save to file") - screenshotCmd.PersistentFlags().BoolVar(&ssNoNotify, "no-notify", false, "Don't show notification") - screenshotCmd.PersistentFlags().BoolVar(&ssNoConfirm, "no-confirm", false, "Region mode: capture on mouse release without Enter/Space confirmation") - screenshotCmd.PersistentFlags().BoolVar(&ssReset, "reset", false, "Reset saved last-region preselection before capturing") - screenshotCmd.PersistentFlags().BoolVar(&ssStdout, "stdout", false, "Output image to stdout (for piping to swappy, etc.)") - - screenshotCmd.AddCommand(ssRegionCmd) - screenshotCmd.AddCommand(ssFullCmd) - screenshotCmd.AddCommand(ssAllCmd) - screenshotCmd.AddCommand(ssOutputCmd) - screenshotCmd.AddCommand(ssLastCmd) - screenshotCmd.AddCommand(ssWindowCmd) - screenshotCmd.AddCommand(ssListCmd) - - screenshotCmd.Run = runScreenshotRegion -} - -func getScreenshotConfig(mode screenshot.Mode) screenshot.Config { - config := screenshot.DefaultConfig() - config.Mode = mode - config.OutputName = ssOutputName - if strings.EqualFold(ssCursor, "on") { - config.Cursor = screenshot.CursorOn - } - config.Clipboard = !ssNoClipboard - config.SaveFile = !ssNoFile - config.Notify = !ssNoNotify - config.NoConfirm = ssNoConfirm - config.Reset = ssReset - config.Stdout = ssStdout - - if ssOutputDir != "" { - config.OutputDir = ssOutputDir - } - if ssFilename != "" { - config.Filename = ssFilename - } - - switch strings.ToLower(ssFormat) { - case "jpg", "jpeg": - config.Format = screenshot.FormatJPEG - case "ppm": - config.Format = screenshot.FormatPPM - default: - config.Format = screenshot.FormatPNG - } - - if ssQuality < 1 { - ssQuality = 1 - } - if ssQuality > 100 { - ssQuality = 100 - } - config.Quality = ssQuality - - return config -} - -func runScreenshot(config screenshot.Config) { - sc := screenshot.New(config) - result, err := sc.Run() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - if result == nil { - os.Exit(0) - } - - defer result.Buffer.Close() - - if result.YInverted { - result.Buffer.FlipVertical() - } - - if config.Stdout { - if err := writeImageToStdout(result.Buffer, config.Format, config.Quality, result.Format); err != nil { - fmt.Fprintf(os.Stderr, "Error writing to stdout: %v\n", err) - os.Exit(1) - } - return - } - - var filePath string - - if config.SaveFile { - outputDir := config.OutputDir - if outputDir == "" { - outputDir = screenshot.GetOutputDir() - } - - filename := config.Filename - if filename == "" { - filename = screenshot.GenerateFilename(config.Format) - } - - filePath = filepath.Join(outputDir, filename) - if err := screenshot.WriteToFileWithFormat(result.Buffer, filePath, config.Format, config.Quality, result.Format); err != nil { - fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err) - os.Exit(1) - } - fmt.Println(filePath) - } - - if config.Clipboard { - if err := copyImageToClipboard(result.Buffer, config.Format, config.Quality, result.Format); err != nil { - fmt.Fprintf(os.Stderr, "Error copying to clipboard: %v\n", err) - os.Exit(1) - } - if !config.SaveFile { - fmt.Println("Copied to clipboard") - } - } - - if config.Notify { - thumbData, thumbW, thumbH := bufferToRGBThumbnail(result.Buffer, 256, result.Format) - screenshot.SendNotification(screenshot.NotifyResult{ - FilePath: filePath, - Clipboard: config.Clipboard, - ImageData: thumbData, - Width: thumbW, - Height: thumbH, - }) - } -} - -func copyImageToClipboard(buf *screenshot.ShmBuffer, format screenshot.Format, quality int, pixelFormat uint32) error { - var mimeType string - var data bytes.Buffer - - img := screenshot.BufferToImageWithFormat(buf, pixelFormat) - - switch format { - case screenshot.FormatJPEG: - mimeType = "image/jpeg" - if err := screenshot.EncodeJPEG(&data, img, quality); err != nil { - return err - } - default: - mimeType = "image/png" - if err := screenshot.EncodePNG(&data, img); err != nil { - return err - } - } - - return clipboard.Copy(data.Bytes(), mimeType) -} - -func writeImageToStdout(buf *screenshot.ShmBuffer, format screenshot.Format, quality int, pixelFormat uint32) error { - img := screenshot.BufferToImageWithFormat(buf, pixelFormat) - - switch format { - case screenshot.FormatJPEG: - return screenshot.EncodeJPEG(os.Stdout, img, quality) - default: - return screenshot.EncodePNG(os.Stdout, img) - } -} - -func bufferToRGBThumbnail(buf *screenshot.ShmBuffer, maxSize int, pixelFormat uint32) ([]byte, int, int) { - srcW, srcH := buf.Width, buf.Height - scale := 1.0 - if srcW > maxSize || srcH > maxSize { - if srcW > srcH { - scale = float64(maxSize) / float64(srcW) - } else { - scale = float64(maxSize) / float64(srcH) - } - } - - dstW := int(float64(srcW) * scale) - dstH := int(float64(srcH) * scale) - if dstW < 1 { - dstW = 1 - } - if dstH < 1 { - dstH = 1 - } - - data := buf.Data() - rgb := make([]byte, dstW*dstH*3) - - var swapRB bool - switch pixelFormat { - case uint32(screenshot.FormatABGR8888), uint32(screenshot.FormatXBGR8888): - swapRB = false - default: - swapRB = true - } - - for y := 0; y < dstH; y++ { - srcY := int(float64(y) / scale) - if srcY >= srcH { - srcY = srcH - 1 - } - for x := 0; x < dstW; x++ { - srcX := int(float64(x) / scale) - if srcX >= srcW { - srcX = srcW - 1 - } - si := srcY*buf.Stride + srcX*4 - di := (y*dstW + x) * 3 - if si+3 >= len(data) { - continue - } - if swapRB { - rgb[di+0] = data[si+2] - rgb[di+1] = data[si+1] - rgb[di+2] = data[si+0] - } else { - rgb[di+0] = data[si+0] - rgb[di+1] = data[si+1] - rgb[di+2] = data[si+2] - } - } - } - return rgb, dstW, dstH -} - -func runScreenshotRegion(cmd *cobra.Command, args []string) { - config := getScreenshotConfig(screenshot.ModeRegion) - runScreenshot(config) -} - -func runScreenshotFull(cmd *cobra.Command, args []string) { - config := getScreenshotConfig(screenshot.ModeFullScreen) - runScreenshot(config) -} - -func runScreenshotAll(cmd *cobra.Command, args []string) { - config := getScreenshotConfig(screenshot.ModeAllScreens) - runScreenshot(config) -} - -func runScreenshotOutput(cmd *cobra.Command, args []string) { - if ssOutputName == "" && len(args) > 0 { - ssOutputName = args[0] - } - if ssOutputName == "" { - fmt.Fprintln(os.Stderr, "Error: output name required (use -o or provide as argument)") - os.Exit(1) - } - config := getScreenshotConfig(screenshot.ModeOutput) - runScreenshot(config) -} - -func runScreenshotLast(cmd *cobra.Command, args []string) { - config := getScreenshotConfig(screenshot.ModeLastRegion) - runScreenshot(config) -} - -func runScreenshotWindow(cmd *cobra.Command, args []string) { - config := getScreenshotConfig(screenshot.ModeWindow) - runScreenshot(config) -} - -func runScreenshotList(cmd *cobra.Command, args []string) { - outputs, err := screenshot.ListOutputs() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - for _, o := range outputs { - scaleStr := fmt.Sprintf("%.2f", o.FractionalScale) - if o.FractionalScale == float64(int(o.FractionalScale)) { - scaleStr = fmt.Sprintf("%d", int(o.FractionalScale)) - } - - transformStr := transformName(o.Transform) - - fmt.Printf("%s: %dx%d+%d+%d scale=%s transform=%s\n", - o.Name, o.Width, o.Height, o.X, o.Y, scaleStr, transformStr) - } -} - -func transformName(t int32) string { - switch t { - case 0: - return "normal" - case 1: - return "90" - case 2: - return "180" - case 3: - return "270" - case 4: - return "flipped" - case 5: - return "flipped-90" - case 6: - return "flipped-180" - case 7: - return "flipped-270" - default: - return fmt.Sprintf("%d", t) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_setup.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_setup.go deleted file mode 100644 index 0f4a58d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_setup.go +++ /dev/null @@ -1,436 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/greeter" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/spf13/cobra" -) - -var setupCmd = &cobra.Command{ - Use: "setup", - Short: "Deploy DMS configurations", - Long: "Deploy compositor and terminal configurations with interactive prompts", - PersistentPreRunE: requireMutableSystemCommand, - Run: func(cmd *cobra.Command, args []string) { - if err := runSetup(); err != nil { - log.Fatalf("Error during setup: %v", err) - } - }, -} - -var setupBindsCmd = &cobra.Command{ - Use: "binds", - Short: "Deploy default keybinds config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("binds"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupLayoutCmd = &cobra.Command{ - Use: "layout", - Short: "Deploy default layout config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("layout"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupColorsCmd = &cobra.Command{ - Use: "colors", - Short: "Deploy default colors config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("colors"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupAlttabCmd = &cobra.Command{ - Use: "alttab", - Short: "Deploy default alt-tab config (niri only)", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("alttab"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupOutputsCmd = &cobra.Command{ - Use: "outputs", - Short: "Deploy default outputs config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("outputs"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupCursorCmd = &cobra.Command{ - Use: "cursor", - Short: "Deploy default cursor config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("cursor"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -var setupWindowrulesCmd = &cobra.Command{ - Use: "windowrules", - Short: "Deploy default window rules config", - Run: func(cmd *cobra.Command, args []string) { - if err := runSetupDmsConfig("windowrules"); err != nil { - log.Fatalf("Error: %v", err) - } - }, -} - -type dmsConfigSpec struct { - niriFile string - hyprFile string - niriContent func(terminal string) string - hyprContent func(terminal string) string -} - -var dmsConfigSpecs = map[string]dmsConfigSpec{ - "binds": { - niriFile: "binds.kdl", - hyprFile: "binds.conf", - niriContent: func(t string) string { - return strings.ReplaceAll(config.NiriBindsConfig, "{{TERMINAL_COMMAND}}", t) - }, - hyprContent: func(t string) string { - return strings.ReplaceAll(config.HyprBindsConfig, "{{TERMINAL_COMMAND}}", t) - }, - }, - "layout": { - niriFile: "layout.kdl", - hyprFile: "layout.conf", - niriContent: func(_ string) string { return config.NiriLayoutConfig }, - hyprContent: func(_ string) string { return config.HyprLayoutConfig }, - }, - "colors": { - niriFile: "colors.kdl", - hyprFile: "colors.conf", - niriContent: func(_ string) string { return config.NiriColorsConfig }, - hyprContent: func(_ string) string { return config.HyprColorsConfig }, - }, - "alttab": { - niriFile: "alttab.kdl", - niriContent: func(_ string) string { return config.NiriAlttabConfig }, - }, - "outputs": { - niriFile: "outputs.kdl", - hyprFile: "outputs.conf", - niriContent: func(_ string) string { return "" }, - hyprContent: func(_ string) string { return "" }, - }, - "cursor": { - niriFile: "cursor.kdl", - hyprFile: "cursor.conf", - niriContent: func(_ string) string { return "" }, - hyprContent: func(_ string) string { return "" }, - }, - "windowrules": { - niriFile: "windowrules.kdl", - hyprFile: "windowrules.conf", - niriContent: func(_ string) string { return "" }, - hyprContent: func(_ string) string { return "" }, - }, -} - -func detectTerminal() (string, error) { - terminals := []string{"ghostty", "foot", "kitty", "alacritty"} - var found []string - for _, t := range terminals { - if utils.CommandExists(t) { - found = append(found, t) - } - } - - switch len(found) { - case 0: - return "ghostty", nil - case 1: - return found[0], nil - } - - fmt.Println("Multiple terminals detected:") - for i, t := range found { - fmt.Printf("%d) %s\n", i+1, t) - } - fmt.Printf("\nChoice (1-%d): ", len(found)) - - var response string - fmt.Scanln(&response) - response = strings.TrimSpace(response) - - choice := 0 - fmt.Sscanf(response, "%d", &choice) - if choice < 1 || choice > len(found) { - return "", fmt.Errorf("invalid choice") - } - return found[choice-1], nil -} - -func detectCompositorForSetup() (string, error) { - compositors := greeter.DetectCompositors() - - switch len(compositors) { - case 0: - return "", fmt.Errorf("no supported compositors found (niri or Hyprland required)") - case 1: - return strings.ToLower(compositors[0]), nil - } - - selected, err := greeter.PromptCompositorChoice(compositors) - if err != nil { - return "", err - } - return strings.ToLower(selected), nil -} - -func runSetupDmsConfig(name string) error { - spec, ok := dmsConfigSpecs[name] - if !ok { - return fmt.Errorf("unknown config: %s", name) - } - - compositor, err := detectCompositorForSetup() - if err != nil { - return err - } - - var filename string - var contentFn func(string) string - switch compositor { - case "niri": - filename = spec.niriFile - contentFn = spec.niriContent - case "hyprland": - filename = spec.hyprFile - contentFn = spec.hyprContent - default: - return fmt.Errorf("unsupported compositor: %s", compositor) - } - - if filename == "" { - return fmt.Errorf("%s is not supported for %s", name, compositor) - } - - var dmsDir string - switch compositor { - case "niri": - dmsDir = filepath.Join(os.Getenv("HOME"), ".config", "niri", "dms") - case "hyprland": - dmsDir = filepath.Join(os.Getenv("HOME"), ".config", "hypr", "dms") - } - - if err := os.MkdirAll(dmsDir, 0o755); err != nil { - return fmt.Errorf("failed to create dms directory: %w", err) - } - - path := filepath.Join(dmsDir, filename) - if info, err := os.Stat(path); err == nil && info.Size() > 0 { - return fmt.Errorf("%s already exists and is not empty: %s", name, path) - } - - terminal := "ghostty" - if contentFn != nil && name == "binds" { - terminal, err = detectTerminal() - if err != nil { - return err - } - } - - content := contentFn(terminal) - if err := os.WriteFile(path, []byte(content), 0o644); err != nil { - return fmt.Errorf("failed to write %s: %w", filename, err) - } - - fmt.Printf("Deployed %s to %s\n", name, path) - return nil -} - -func runSetup() error { - fmt.Println("=== DMS Configuration Setup ===") - - wm, wmSelected := promptCompositor() - terminal, terminalSelected := promptTerminal() - useSystemd := promptSystemd() - - if !wmSelected && !terminalSelected { - fmt.Println("No configurations selected. Exiting.") - return nil - } - - if wmSelected || terminalSelected { - willBackup := checkExistingConfigs(wm, wmSelected, terminal, terminalSelected) - if willBackup { - fmt.Println("\n⚠ Existing configurations will be backed up with timestamps.") - } - - fmt.Print("\nProceed with deployment? (y/N): ") - var response string - fmt.Scanln(&response) - response = strings.ToLower(strings.TrimSpace(response)) - - if response != "y" && response != "yes" { - fmt.Println("Setup cancelled.") - return nil - } - } - - fmt.Println("\nDeploying configurations...") - logChan := make(chan string, 100) - deployer := config.NewConfigDeployer(logChan) - - go func() { - for msg := range logChan { - fmt.Println(" " + msg) - } - }() - - ctx := context.Background() - var results []config.DeploymentResult - var err error - - if wmSelected && terminalSelected { - results, err = deployer.DeployConfigurationsWithSystemd(ctx, wm, terminal, useSystemd) - } else if wmSelected { - results, err = deployer.DeployConfigurationsWithSystemd(ctx, wm, deps.TerminalGhostty, useSystemd) - if len(results) > 1 { - results = results[:1] - } - } else if terminalSelected { - results, err = deployer.DeployConfigurationsWithSystemd(ctx, deps.WindowManagerNiri, terminal, useSystemd) - if len(results) > 0 && results[0].ConfigType == "Niri" { - results = results[1:] - } - } - - close(logChan) - - if err != nil { - return fmt.Errorf("deployment failed: %w", err) - } - - fmt.Println("\n=== Deployment Complete ===") - for _, result := range results { - if result.Deployed { - fmt.Printf("✓ %s: %s\n", result.ConfigType, result.Path) - if result.BackupPath != "" { - fmt.Printf(" Backup: %s\n", result.BackupPath) - } - } - } - - return nil -} - -func promptCompositor() (deps.WindowManager, bool) { - fmt.Println("Select compositor:") - fmt.Println("1) Niri") - fmt.Println("2) Hyprland") - fmt.Println("3) None") - - var response string - fmt.Print("\nChoice (1-3): ") - fmt.Scanln(&response) - response = strings.TrimSpace(response) - - switch response { - case "1": - return deps.WindowManagerNiri, true - case "2": - return deps.WindowManagerHyprland, true - default: - return deps.WindowManagerNiri, false - } -} - -func promptTerminal() (deps.Terminal, bool) { - fmt.Println("\nSelect terminal:") - fmt.Println("1) Ghostty") - fmt.Println("2) Kitty") - fmt.Println("3) Alacritty") - fmt.Println("4) None") - - var response string - fmt.Print("\nChoice (1-4): ") - fmt.Scanln(&response) - response = strings.TrimSpace(response) - - switch response { - case "1": - return deps.TerminalGhostty, true - case "2": - return deps.TerminalKitty, true - case "3": - return deps.TerminalAlacritty, true - default: - return deps.TerminalGhostty, false - } -} - -func promptSystemd() bool { - fmt.Println("\nUse systemd for session management?") - fmt.Println("1) Yes (recommended for most distros)") - fmt.Println("2) No (standalone, no systemd integration)") - - var response string - fmt.Print("\nChoice (1-2): ") - fmt.Scanln(&response) - response = strings.TrimSpace(response) - - return response != "2" -} - -func checkExistingConfigs(wm deps.WindowManager, wmSelected bool, terminal deps.Terminal, terminalSelected bool) bool { - homeDir := os.Getenv("HOME") - willBackup := false - - if wmSelected { - var configPath string - switch wm { - case deps.WindowManagerNiri: - configPath = filepath.Join(homeDir, ".config", "niri", "config.kdl") - case deps.WindowManagerHyprland: - configPath = filepath.Join(homeDir, ".config", "hypr", "hyprland.conf") - } - - if _, err := os.Stat(configPath); err == nil { - willBackup = true - } - } - - if terminalSelected { - var configPath string - switch terminal { - case deps.TerminalGhostty: - configPath = filepath.Join(homeDir, ".config", "ghostty", "config") - case deps.TerminalKitty: - configPath = filepath.Join(homeDir, ".config", "kitty", "kitty.conf") - case deps.TerminalAlacritty: - configPath = filepath.Join(homeDir, ".config", "alacritty", "alacritty.toml") - } - - if _, err := os.Stat(configPath); err == nil { - willBackup = true - } - } - - return willBackup -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_windowrules.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_windowrules.go deleted file mode 100644 index 0883811..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/commands_windowrules.go +++ /dev/null @@ -1,338 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/AvengeMedia/DankMaterialShell/core/internal/windowrules" - "github.com/AvengeMedia/DankMaterialShell/core/internal/windowrules/providers" - "github.com/spf13/cobra" -) - -var windowrulesCmd = &cobra.Command{ - Use: "windowrules", - Short: "Manage window rules", -} - -var windowrulesListCmd = &cobra.Command{ - Use: "list [compositor]", - Short: "List all window rules", - Long: "List all window rules from compositor config file. Returns JSON with rules and DMS status.", - Args: cobra.MaximumNArgs(1), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - return []string{"niri"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runWindowrulesList, -} - -var windowrulesAddCmd = &cobra.Command{ - Use: "add ''", - Short: "Add a window rule to DMS file", - Long: "Add a new window rule to the DMS-managed rules file.", - Args: cobra.ExactArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - // ! disabled hyprland return []string{"hyprland", "niri"}, cobra.ShellCompDirectiveNoFileComp - return []string{"niri"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runWindowrulesAdd, -} - -var windowrulesUpdateCmd = &cobra.Command{ - Use: "update ''", - Short: "Update a window rule in DMS file", - Long: "Update an existing window rule in the DMS-managed rules file.", - Args: cobra.ExactArgs(3), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - return []string{"niri"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runWindowrulesUpdate, -} - -var windowrulesRemoveCmd = &cobra.Command{ - Use: "remove ", - Short: "Remove a window rule from DMS file", - Long: "Remove a window rule from the DMS-managed rules file.", - Args: cobra.ExactArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - return []string{"niri"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runWindowrulesRemove, -} - -var windowrulesReorderCmd = &cobra.Command{ - Use: "reorder ''", - Short: "Reorder window rules in DMS file", - Long: "Reorder window rules by providing a JSON array of rule IDs in the desired order.", - Args: cobra.ExactArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - return []string{"niri"}, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: runWindowrulesReorder, -} - -func init() { - configCmd.AddCommand(windowrulesCmd) - windowrulesCmd.AddCommand(windowrulesListCmd) - windowrulesCmd.AddCommand(windowrulesAddCmd) - windowrulesCmd.AddCommand(windowrulesUpdateCmd) - windowrulesCmd.AddCommand(windowrulesRemoveCmd) - windowrulesCmd.AddCommand(windowrulesReorderCmd) -} - -type WindowRulesListResult struct { - Rules []windowrules.WindowRule `json:"rules"` - DMSStatus *windowrules.DMSRulesStatus `json:"dmsStatus,omitempty"` -} - -type WindowRuleWriteResult struct { - Success bool `json:"success"` - ID string `json:"id,omitempty"` - Path string `json:"path,omitempty"` - Error string `json:"error,omitempty"` -} - -func getCompositor(args []string) string { - if len(args) > 0 { - return strings.ToLower(args[0]) - } - if os.Getenv("NIRI_SOCKET") != "" { - return "niri" - } - // if os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "" { - // return "hyprland" - // } - return "" -} - -func writeRuleError(errMsg string) { - result := WindowRuleWriteResult{Success: false, Error: errMsg} - output, _ := json.Marshal(result) - fmt.Fprintln(os.Stdout, string(output)) - os.Exit(1) -} - -func writeRuleSuccess(id, path string) { - result := WindowRuleWriteResult{Success: true, ID: id, Path: path} - output, _ := json.Marshal(result) - fmt.Fprintln(os.Stdout, string(output)) -} - -func runWindowrulesList(cmd *cobra.Command, args []string) { - compositor := getCompositor(args) - if compositor == "" { - log.Fatalf("Could not detect compositor. Please specify: hyprland or niri") - } - - var result WindowRulesListResult - - switch compositor { - case "niri": - configDir, err := utils.ExpandPath("$HOME/.config/niri") - if err != nil { - log.Fatalf("Failed to expand niri config path: %v", err) - } - - parseResult, err := providers.ParseNiriWindowRules(configDir) - if err != nil { - log.Fatalf("Failed to parse niri window rules: %v", err) - } - - allRules := providers.ConvertNiriRulesToWindowRules(parseResult.Rules) - - provider := providers.NewNiriWritableProvider(configDir) - dmsRulesPath := provider.GetOverridePath() - dmsRules, _ := provider.LoadDMSRules() - - dmsRuleMap := make(map[int]windowrules.WindowRule) - for i, dr := range dmsRules { - dmsRuleMap[i] = dr - } - - dmsIdx := 0 - for i, r := range allRules { - if r.Source == dmsRulesPath { - if dmr, ok := dmsRuleMap[dmsIdx]; ok { - allRules[i].ID = dmr.ID - allRules[i].Name = dmr.Name - } - dmsIdx++ - } - } - - result.Rules = allRules - result.DMSStatus = parseResult.DMSStatus - - case "hyprland": - log.Fatalf("Hyprland support is currently disabled.") // ! disabled hyprland - configDir, err := utils.ExpandPath("$HOME/.config/hypr") - if err != nil { - log.Fatalf("Failed to expand hyprland config path: %v", err) - } - - parseResult, err := providers.ParseHyprlandWindowRules(configDir) - if err != nil { - log.Fatalf("Failed to parse hyprland window rules: %v", err) - } - - allRules := providers.ConvertHyprlandRulesToWindowRules(parseResult.Rules) - - provider := providers.NewHyprlandWritableProvider(configDir) - dmsRulesPath := provider.GetOverridePath() - dmsRules, _ := provider.LoadDMSRules() - - dmsRuleMap := make(map[int]windowrules.WindowRule) - for i, dr := range dmsRules { - dmsRuleMap[i] = dr - } - - dmsIdx := 0 - for i, r := range allRules { - if r.Source == dmsRulesPath { - if dmr, ok := dmsRuleMap[dmsIdx]; ok { - allRules[i].ID = dmr.ID - allRules[i].Name = dmr.Name - } - dmsIdx++ - } - } - - result.Rules = allRules - result.DMSStatus = parseResult.DMSStatus - - default: - log.Fatalf("Unknown compositor: %s", compositor) - } - - output, _ := json.Marshal(result) - fmt.Fprintln(os.Stdout, string(output)) -} - -func runWindowrulesAdd(cmd *cobra.Command, args []string) { - compositor := strings.ToLower(args[0]) - ruleJSON := args[1] - - var rule windowrules.WindowRule - if err := json.Unmarshal([]byte(ruleJSON), &rule); err != nil { - writeRuleError(fmt.Sprintf("Invalid JSON: %v", err)) - } - - if rule.ID == "" { - rule.ID = generateRuleID() - } - rule.Enabled = true - - provider := getWindowRulesProvider(compositor) - if provider == nil { - writeRuleError(fmt.Sprintf("Unknown compositor: %s", compositor)) - } - - if err := provider.SetRule(rule); err != nil { - writeRuleError(err.Error()) - } - - writeRuleSuccess(rule.ID, provider.GetOverridePath()) -} - -func runWindowrulesUpdate(cmd *cobra.Command, args []string) { - compositor := strings.ToLower(args[0]) - ruleID := args[1] - ruleJSON := args[2] - - var rule windowrules.WindowRule - if err := json.Unmarshal([]byte(ruleJSON), &rule); err != nil { - writeRuleError(fmt.Sprintf("Invalid JSON: %v", err)) - } - - rule.ID = ruleID - - provider := getWindowRulesProvider(compositor) - if provider == nil { - writeRuleError(fmt.Sprintf("Unknown compositor: %s", compositor)) - } - - if err := provider.SetRule(rule); err != nil { - writeRuleError(err.Error()) - } - - writeRuleSuccess(rule.ID, provider.GetOverridePath()) -} - -func runWindowrulesRemove(cmd *cobra.Command, args []string) { - compositor := strings.ToLower(args[0]) - ruleID := args[1] - - provider := getWindowRulesProvider(compositor) - if provider == nil { - writeRuleError(fmt.Sprintf("Unknown compositor: %s", compositor)) - } - - if err := provider.RemoveRule(ruleID); err != nil { - writeRuleError(err.Error()) - } - - writeRuleSuccess(ruleID, provider.GetOverridePath()) -} - -func runWindowrulesReorder(cmd *cobra.Command, args []string) { - compositor := strings.ToLower(args[0]) - idsJSON := args[1] - - var ids []string - if err := json.Unmarshal([]byte(idsJSON), &ids); err != nil { - writeRuleError(fmt.Sprintf("Invalid JSON array: %v", err)) - } - - provider := getWindowRulesProvider(compositor) - if provider == nil { - writeRuleError(fmt.Sprintf("Unknown compositor: %s", compositor)) - } - - if err := provider.ReorderRules(ids); err != nil { - writeRuleError(err.Error()) - } - - writeRuleSuccess("", provider.GetOverridePath()) -} - -func getWindowRulesProvider(compositor string) windowrules.WritableProvider { - switch compositor { - case "niri": - configDir, err := utils.ExpandPath("$HOME/.config/niri") - if err != nil { - return nil - } - return providers.NewNiriWritableProvider(configDir) - case "hyprland": - configDir, err := utils.ExpandPath("$HOME/.config/hypr") - if err != nil { - return nil - } - return providers.NewHyprlandWritableProvider(configDir) - default: - return nil - } -} - -func generateRuleID() string { - return fmt.Sprintf("wr_%d", time.Now().UnixNano()) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/dpms_client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/dpms_client.go deleted file mode 100644 index 98f66d9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/dpms_client.go +++ /dev/null @@ -1,339 +0,0 @@ -package main - -import ( - "fmt" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_power" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type cmd struct { - fn func() - done chan error -} - -type dpmsClient struct { - display *wlclient.Display - ctx *wlclient.Context - powerMgr *wlr_output_power.ZwlrOutputPowerManagerV1 - outputs map[string]*outputState - mu sync.Mutex - syncRound int - done bool - err error - cmdq chan cmd - stopChan chan struct{} - wg sync.WaitGroup -} - -type outputState struct { - wlOutput *wlclient.Output - powerCtrl *wlr_output_power.ZwlrOutputPowerV1 - name string - mode uint32 - failed bool - waitCh chan struct{} - wantMode *uint32 -} - -func (c *dpmsClient) post(fn func()) { - done := make(chan error, 1) - select { - case c.cmdq <- cmd{fn: fn, done: done}: - <-done - case <-c.stopChan: - } -} - -func (c *dpmsClient) waylandActor() { - defer c.wg.Done() - for { - select { - case <-c.stopChan: - return - case cmd := <-c.cmdq: - cmd.fn() - close(cmd.done) - } - } -} - -func newDPMSClient() (*dpmsClient, error) { - display, err := wlclient.Connect("") - if err != nil { - return nil, fmt.Errorf("failed to connect to Wayland: %w", err) - } - - c := &dpmsClient{ - display: display, - ctx: display.Context(), - outputs: make(map[string]*outputState), - cmdq: make(chan cmd, 128), - stopChan: make(chan struct{}), - } - - c.wg.Add(1) - go c.waylandActor() - - registry, err := display.GetRegistry() - if err != nil { - display.Context().Close() - return nil, fmt.Errorf("failed to get registry: %w", err) - } - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case wlr_output_power.ZwlrOutputPowerManagerV1InterfaceName: - powerMgr := wlr_output_power.NewZwlrOutputPowerManagerV1(c.ctx) - version := min(e.Version, 1) - if err := registry.Bind(e.Name, e.Interface, version, powerMgr); err == nil { - c.powerMgr = powerMgr - } - - case "wl_output": - output := wlclient.NewOutput(c.ctx) - version := min(e.Version, 4) - if err := registry.Bind(e.Name, e.Interface, version, output); err == nil { - outputID := fmt.Sprintf("output-%d", output.ID()) - state := &outputState{ - wlOutput: output, - name: outputID, - } - - c.mu.Lock() - c.outputs[outputID] = state - c.mu.Unlock() - - output.SetNameHandler(func(ev wlclient.OutputNameEvent) { - c.mu.Lock() - delete(c.outputs, state.name) - state.name = ev.Name - c.outputs[ev.Name] = state - c.mu.Unlock() - }) - } - } - }) - - syncCallback, err := display.Sync() - if err != nil { - c.Close() - return nil, fmt.Errorf("failed to sync display: %w", err) - } - syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) { - c.handleSync() - }) - - for !c.done { - if err := c.ctx.Dispatch(); err != nil { - c.Close() - return nil, fmt.Errorf("dispatch error: %w", err) - } - } - - if c.err != nil { - c.Close() - return nil, c.err - } - - return c, nil -} - -func (c *dpmsClient) handleSync() { - c.syncRound++ - - switch c.syncRound { - case 1: - if c.powerMgr == nil { - c.err = fmt.Errorf("wlr-output-power-management protocol not supported by compositor") - c.done = true - return - } - - c.mu.Lock() - for _, state := range c.outputs { - powerCtrl, err := c.powerMgr.GetOutputPower(state.wlOutput) - if err != nil { - continue - } - state.powerCtrl = powerCtrl - - powerCtrl.SetModeHandler(func(e wlr_output_power.ZwlrOutputPowerV1ModeEvent) { - c.mu.Lock() - defer c.mu.Unlock() - if state.powerCtrl == nil { - return - } - state.mode = e.Mode - if state.wantMode != nil && e.Mode == *state.wantMode && state.waitCh != nil { - close(state.waitCh) - state.wantMode = nil - } - }) - - powerCtrl.SetFailedHandler(func(e wlr_output_power.ZwlrOutputPowerV1FailedEvent) { - c.mu.Lock() - defer c.mu.Unlock() - if state.powerCtrl == nil { - return - } - state.failed = true - if state.waitCh != nil { - close(state.waitCh) - state.wantMode = nil - } - }) - } - c.mu.Unlock() - - syncCallback, err := c.display.Sync() - if err != nil { - c.err = fmt.Errorf("failed to sync display: %w", err) - c.done = true - return - } - syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) { - c.handleSync() - }) - - default: - c.done = true - } -} - -func (c *dpmsClient) ListOutputs() []string { - c.mu.Lock() - defer c.mu.Unlock() - - names := make([]string, 0, len(c.outputs)) - for name := range c.outputs { - names = append(names, name) - } - return names -} - -func (c *dpmsClient) SetDPMS(outputName string, on bool) error { - var mode uint32 - if on { - mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOn) - } else { - mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOff) - } - - var setErr error - c.post(func() { - c.mu.Lock() - var waitStates []*outputState - - if outputName == "" || outputName == "all" { - if len(c.outputs) == 0 { - c.mu.Unlock() - setErr = fmt.Errorf("no outputs found") - return - } - - for _, state := range c.outputs { - if state.powerCtrl == nil { - continue - } - state.wantMode = &mode - state.waitCh = make(chan struct{}) - state.failed = false - waitStates = append(waitStates, state) - state.powerCtrl.SetMode(mode) - } - } else { - state, ok := c.outputs[outputName] - if !ok { - c.mu.Unlock() - setErr = fmt.Errorf("output not found: %s", outputName) - return - } - if state.powerCtrl == nil { - c.mu.Unlock() - setErr = fmt.Errorf("output %s has nil powerCtrl", outputName) - return - } - state.wantMode = &mode - state.waitCh = make(chan struct{}) - state.failed = false - waitStates = append(waitStates, state) - state.powerCtrl.SetMode(mode) - } - c.mu.Unlock() - - deadline := time.Now().Add(10 * time.Second) - - for _, state := range waitStates { - c.mu.Lock() - ch := state.waitCh - c.mu.Unlock() - - done := false - for !done { - if err := c.ctx.Dispatch(); err != nil { - setErr = fmt.Errorf("dispatch error: %w", err) - return - } - - select { - case <-ch: - c.mu.Lock() - if state.failed { - setErr = fmt.Errorf("compositor reported failed for %s", state.name) - c.mu.Unlock() - return - } - c.mu.Unlock() - done = true - default: - if time.Now().After(deadline) { - setErr = fmt.Errorf("timeout waiting for mode change on %s", state.name) - return - } - time.Sleep(10 * time.Millisecond) - } - } - } - - c.mu.Lock() - for _, state := range waitStates { - if state.powerCtrl != nil { - state.powerCtrl.Destroy() - state.powerCtrl = nil - } - } - c.mu.Unlock() - - c.display.Roundtrip() - }) - - return setErr -} - -func (c *dpmsClient) Close() { - close(c.stopChan) - c.wg.Wait() - - c.mu.Lock() - defer c.mu.Unlock() - - for _, state := range c.outputs { - if state.powerCtrl != nil { - state.powerCtrl.Destroy() - } - } - c.outputs = nil - - if c.powerMgr != nil { - c.powerMgr.Destroy() - c.powerMgr = nil - } - - if c.display != nil { - c.ctx.Close() - c.display = nil - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/immutable_policy.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/immutable_policy.go deleted file mode 100644 index 5529c9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/immutable_policy.go +++ /dev/null @@ -1,271 +0,0 @@ -package main - -import ( - "bufio" - _ "embed" - "encoding/json" - "fmt" - "os" - "strings" - "sync" - - "github.com/spf13/cobra" -) - -const ( - cliPolicyPackagedPath = "/usr/share/dms/cli-policy.json" - cliPolicyAdminPath = "/etc/dms/cli-policy.json" -) - -var ( - immutablePolicyOnce sync.Once - immutablePolicy immutableCommandPolicy - immutablePolicyErr error -) - -//go:embed assets/cli-policy.default.json -var defaultCLIPolicyJSON []byte - -type immutableCommandPolicy struct { - ImmutableSystem bool - ImmutableReason string - BlockedCommands []string - Message string -} - -type cliPolicyFile struct { - PolicyVersion int `json:"policy_version"` - ImmutableSystem *bool `json:"immutable_system"` - BlockedCommands *[]string `json:"blocked_commands"` - Message *string `json:"message"` -} - -func normalizeCommandSpec(raw string) string { - normalized := strings.ToLower(strings.TrimSpace(raw)) - normalized = strings.TrimPrefix(normalized, "dms ") - return strings.Join(strings.Fields(normalized), " ") -} - -func normalizeBlockedCommands(raw []string) []string { - normalized := make([]string, 0, len(raw)) - seen := make(map[string]bool) - - for _, cmd := range raw { - spec := normalizeCommandSpec(cmd) - if spec == "" || seen[spec] { - continue - } - seen[spec] = true - normalized = append(normalized, spec) - } - - return normalized -} - -func commandBlockedByPolicy(commandPath string, blocked []string) bool { - normalizedPath := normalizeCommandSpec(commandPath) - if normalizedPath == "" { - return false - } - - for _, entry := range blocked { - spec := normalizeCommandSpec(entry) - if spec == "" { - continue - } - if normalizedPath == spec || strings.HasPrefix(normalizedPath, spec+" ") { - return true - } - } - - return false -} - -func loadPolicyFile(path string) (*cliPolicyFile, error) { - data, err := os.ReadFile(path) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, fmt.Errorf("failed to read %s: %w", path, err) - } - - var policy cliPolicyFile - if err := json.Unmarshal(data, &policy); err != nil { - return nil, fmt.Errorf("failed to parse %s: %w", path, err) - } - - return &policy, nil -} - -func mergePolicyFile(base *immutableCommandPolicy, path string) error { - policyFile, err := loadPolicyFile(path) - if err != nil { - return err - } - if policyFile == nil { - return nil - } - - if policyFile.ImmutableSystem != nil { - base.ImmutableSystem = *policyFile.ImmutableSystem - } - if policyFile.BlockedCommands != nil { - base.BlockedCommands = normalizeBlockedCommands(*policyFile.BlockedCommands) - } - if policyFile.Message != nil { - msg := strings.TrimSpace(*policyFile.Message) - if msg != "" { - base.Message = msg - } - } - - return nil -} - -func readOSReleaseMap(path string) map[string]string { - values := make(map[string]string) - - file, err := os.Open(path) - if err != nil { - return values - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) != 2 { - continue - } - key := strings.ToUpper(strings.TrimSpace(parts[0])) - value := strings.Trim(strings.TrimSpace(parts[1]), "\"") - values[key] = strings.ToLower(value) - } - - return values -} - -func hasAnyToken(text string, tokens ...string) bool { - if text == "" { - return false - } - for _, token := range tokens { - if strings.Contains(text, token) { - return true - } - } - return false -} - -func detectImmutableSystem() (bool, string) { - if _, err := os.Stat("/run/ostree-booted"); err == nil { - return true, "/run/ostree-booted is present" - } - - osRelease := readOSReleaseMap("/etc/os-release") - if len(osRelease) == 0 { - return false, "" - } - - id := osRelease["ID"] - idLike := osRelease["ID_LIKE"] - variantID := osRelease["VARIANT_ID"] - name := osRelease["NAME"] - prettyName := osRelease["PRETTY_NAME"] - - immutableIDs := map[string]bool{ - "bluefin": true, - "bazzite": true, - "silverblue": true, - "kinoite": true, - "sericea": true, - "onyx": true, - "aurora": true, - "fedora-iot": true, - "fedora-coreos": true, - } - if immutableIDs[id] { - return true, "os-release ID=" + id - } - - markers := []string{"silverblue", "kinoite", "sericea", "onyx", "bazzite", "bluefin", "aurora", "ostree", "atomic"} - if hasAnyToken(variantID, markers...) { - return true, "os-release VARIANT_ID=" + variantID - } - if hasAnyToken(idLike, "ostree", "rpm-ostree") { - return true, "os-release ID_LIKE=" + idLike - } - if hasAnyToken(name, markers...) || hasAnyToken(prettyName, markers...) { - return true, "os-release identifies an atomic/ostree variant" - } - - return false, "" -} - -func getImmutablePolicy() (*immutableCommandPolicy, error) { - immutablePolicyOnce.Do(func() { - detectedImmutable, reason := detectImmutableSystem() - immutablePolicy = immutableCommandPolicy{ - ImmutableSystem: detectedImmutable, - ImmutableReason: reason, - BlockedCommands: []string{"greeter install", "greeter enable", "setup"}, - Message: "This command is disabled on immutable/image-based systems. Use your distro-native workflow for system-level changes.", - } - - var defaultPolicy cliPolicyFile - if err := json.Unmarshal(defaultCLIPolicyJSON, &defaultPolicy); err != nil { - immutablePolicyErr = fmt.Errorf("failed to parse embedded default CLI policy: %w", err) - return - } - if defaultPolicy.BlockedCommands != nil { - immutablePolicy.BlockedCommands = normalizeBlockedCommands(*defaultPolicy.BlockedCommands) - } - if defaultPolicy.Message != nil { - msg := strings.TrimSpace(*defaultPolicy.Message) - if msg != "" { - immutablePolicy.Message = msg - } - } - - if err := mergePolicyFile(&immutablePolicy, cliPolicyPackagedPath); err != nil { - immutablePolicyErr = err - return - } - if err := mergePolicyFile(&immutablePolicy, cliPolicyAdminPath); err != nil { - immutablePolicyErr = err - return - } - }) - - if immutablePolicyErr != nil { - return nil, immutablePolicyErr - } - return &immutablePolicy, nil -} - -func requireMutableSystemCommand(cmd *cobra.Command, _ []string) error { - policy, err := getImmutablePolicy() - if err != nil { - return err - } - if !policy.ImmutableSystem { - return nil - } - - commandPath := normalizeCommandSpec(cmd.CommandPath()) - if !commandBlockedByPolicy(commandPath, policy.BlockedCommands) { - return nil - } - - reason := "" - if policy.ImmutableReason != "" { - reason = "Detected immutable system: " + policy.ImmutableReason + "\n" - } - - return fmt.Errorf("%s%s\nCommand: dms %s\nPolicy files:\n %s\n %s", reason, policy.Message, commandPath, cliPolicyPackagedPath, cliPolicyAdminPath) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main.go deleted file mode 100644 index c818148..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build !distro_binary - -package main - -import ( - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -var Version = "dev" - -func init() { - runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode") - runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process") - runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)") - runCmd.Flags().MarkHidden("daemon-child") - - greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd) - authCmd.AddCommand(authSyncCmd) - setupCmd.AddCommand(setupBindsCmd, setupLayoutCmd, setupColorsCmd, setupAlttabCmd, setupOutputsCmd, setupCursorCmd, setupWindowrulesCmd) - updateCmd.AddCommand(updateCheckCmd) - pluginsCmd.AddCommand(pluginsBrowseCmd, pluginsListCmd, pluginsInstallCmd, pluginsUninstallCmd, pluginsUpdateCmd) - rootCmd.AddCommand(getCommonCommands()...) - - rootCmd.AddCommand(authCmd) - rootCmd.AddCommand(updateCmd) - - rootCmd.SetHelpTemplate(getHelpTemplate()) -} - -func main() { - clipboard.MaybeServeAndExit() - - if os.Geteuid() == 0 && !isReadOnlyCommand(os.Args) { - log.Fatal("This program should not be run as root. Exiting.") - } - - if err := rootCmd.Execute(); err != nil { - log.Fatal(err) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main_distro.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main_distro.go deleted file mode 100644 index 2b544ff..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/main_distro.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build distro_binary - -package main - -import ( - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -var Version = "dev" - -func init() { - runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode") - runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process") - runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)") - runCmd.Flags().MarkHidden("daemon-child") - - greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd) - authCmd.AddCommand(authSyncCmd) - setupCmd.AddCommand(setupBindsCmd, setupLayoutCmd, setupColorsCmd, setupAlttabCmd, setupOutputsCmd, setupCursorCmd, setupWindowrulesCmd) - pluginsCmd.AddCommand(pluginsBrowseCmd, pluginsListCmd, pluginsInstallCmd, pluginsUninstallCmd, pluginsUpdateCmd) - rootCmd.AddCommand(getCommonCommands()...) - rootCmd.AddCommand(authCmd) - - rootCmd.SetHelpTemplate(getHelpTemplate()) -} - -func main() { - clipboard.MaybeServeAndExit() - - if os.Geteuid() == 0 && !isReadOnlyCommand(os.Args) { - log.Fatal("This program should not be run as root. Exiting.") - } - - if err := rootCmd.Execute(); err != nil { - log.Fatal(err) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/randr_client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/randr_client.go deleted file mode 100644 index 1a149ca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/randr_client.go +++ /dev/null @@ -1,172 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type randrOutput struct { - Name string `json:"name"` - Scale float64 `json:"scale"` - Width int32 `json:"width"` - Height int32 `json:"height"` - Refresh int32 `json:"refresh"` - Enabled bool `json:"enabled"` -} - -type randrHead struct { - name string - enabled bool - scale float64 - currentModeID uint32 - modeIDs []uint32 -} - -type randrMode struct { - width int32 - height int32 - refresh int32 -} - -type randrClient struct { - display *wlclient.Display - ctx *wlclient.Context - manager *wlr_output_management.ZwlrOutputManagerV1 - heads map[uint32]*randrHead - modes map[uint32]*randrMode - done bool - err error -} - -func queryRandr() ([]randrOutput, error) { - display, err := wlclient.Connect("") - if err != nil { - return nil, fmt.Errorf("failed to connect to Wayland: %w", err) - } - - c := &randrClient{ - display: display, - ctx: display.Context(), - heads: make(map[uint32]*randrHead), - modes: make(map[uint32]*randrMode), - } - defer c.ctx.Close() - - registry, err := display.GetRegistry() - if err != nil { - return nil, fmt.Errorf("failed to get registry: %w", err) - } - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - if e.Interface == wlr_output_management.ZwlrOutputManagerV1InterfaceName { - mgr := wlr_output_management.NewZwlrOutputManagerV1(c.ctx) - version := min(e.Version, 4) - - mgr.SetHeadHandler(func(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) { - c.handleHead(e) - }) - - mgr.SetDoneHandler(func(e wlr_output_management.ZwlrOutputManagerV1DoneEvent) { - c.done = true - }) - - if err := registry.Bind(e.Name, e.Interface, version, mgr); err == nil { - c.manager = mgr - } - } - }) - - // First roundtrip: discover globals and bind manager - syncCallback, err := display.Sync() - if err != nil { - return nil, fmt.Errorf("failed to sync display: %w", err) - } - syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) { - if c.manager == nil { - c.err = fmt.Errorf("zwlr_output_manager_v1 protocol not supported by compositor") - c.done = true - } - // Otherwise wait for manager's DoneHandler - }) - - for !c.done { - if err := c.ctx.Dispatch(); err != nil { - return nil, fmt.Errorf("dispatch error: %w", err) - } - } - - if c.err != nil { - return nil, c.err - } - - return c.buildOutputs(), nil -} - -func (c *randrClient) handleHead(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) { - handle := e.Head - headID := handle.ID() - - head := &randrHead{ - modeIDs: make([]uint32, 0), - } - c.heads[headID] = head - - handle.SetNameHandler(func(e wlr_output_management.ZwlrOutputHeadV1NameEvent) { - head.name = e.Name - }) - - handle.SetEnabledHandler(func(e wlr_output_management.ZwlrOutputHeadV1EnabledEvent) { - head.enabled = e.Enabled != 0 - }) - - handle.SetScaleHandler(func(e wlr_output_management.ZwlrOutputHeadV1ScaleEvent) { - head.scale = e.Scale - }) - - handle.SetCurrentModeHandler(func(e wlr_output_management.ZwlrOutputHeadV1CurrentModeEvent) { - head.currentModeID = e.Mode.ID() - }) - - handle.SetModeHandler(func(e wlr_output_management.ZwlrOutputHeadV1ModeEvent) { - modeHandle := e.Mode - modeID := modeHandle.ID() - - head.modeIDs = append(head.modeIDs, modeID) - - mode := &randrMode{} - c.modes[modeID] = mode - - modeHandle.SetSizeHandler(func(e wlr_output_management.ZwlrOutputModeV1SizeEvent) { - mode.width = e.Width - mode.height = e.Height - }) - - modeHandle.SetRefreshHandler(func(e wlr_output_management.ZwlrOutputModeV1RefreshEvent) { - mode.refresh = e.Refresh - }) - }) -} - -func (c *randrClient) buildOutputs() []randrOutput { - outputs := make([]randrOutput, 0, len(c.heads)) - - for _, head := range c.heads { - out := randrOutput{ - Name: head.name, - Scale: head.scale, - Enabled: head.enabled, - } - - if mode, ok := c.modes[head.currentModeID]; ok { - out.Width = mode.width - out.Height = mode.height - out.Refresh = mode.refresh - } - - outputs = append(outputs, out) - } - - return outputs -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/server_client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/server_client.go deleted file mode 100644 index 871d21d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/server_client.go +++ /dev/null @@ -1,114 +0,0 @@ -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "net" - "os" - "path/filepath" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func sendServerRequest(req models.Request) (*models.Response[any], error) { - socketPath := getServerSocketPath() - - conn, err := net.Dial("unix", socketPath) - if err != nil { - return nil, fmt.Errorf("failed to connect to server (is it running?): %w", err) - } - defer conn.Close() - - scanner := bufio.NewScanner(conn) - scanner.Scan() // discard initial capabilities message - - reqData, err := json.Marshal(req) - if err != nil { - return nil, fmt.Errorf("failed to marshal request: %w", err) - } - - if _, err := conn.Write(reqData); err != nil { - return nil, fmt.Errorf("failed to write request: %w", err) - } - - if _, err := conn.Write([]byte("\n")); err != nil { - return nil, fmt.Errorf("failed to write newline: %w", err) - } - - if !scanner.Scan() { - return nil, fmt.Errorf("failed to read response") - } - - var resp models.Response[any] - if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil { - return nil, fmt.Errorf("failed to unmarshal response: %w", err) - } - - return &resp, nil -} - -// sendServerRequestFireAndForget sends a request without waiting for a response. -// Useful for commands that trigger UI or async operations. -func sendServerRequestFireAndForget(req models.Request) error { - socketPath := getServerSocketPath() - - conn, err := net.Dial("unix", socketPath) - if err != nil { - return fmt.Errorf("failed to connect to server (is it running?): %w", err) - } - defer conn.Close() - - scanner := bufio.NewScanner(conn) - scanner.Scan() // discard initial capabilities message - - reqData, err := json.Marshal(req) - if err != nil { - return fmt.Errorf("failed to marshal request: %w", err) - } - - if _, err := conn.Write(reqData); err != nil { - return fmt.Errorf("failed to write request: %w", err) - } - - if _, err := conn.Write([]byte("\n")); err != nil { - return fmt.Errorf("failed to write newline: %w", err) - } - - return nil -} - -// tryServerRequest attempts to send a request but returns false if server unavailable. -// Does not log errors - caller can decide what to do on failure. -func tryServerRequest(req models.Request) (*models.Response[any], bool) { - resp, err := sendServerRequest(req) - if err != nil { - return nil, false - } - return resp, true -} - -func getServerSocketPath() string { - runtimeDir := os.Getenv("XDG_RUNTIME_DIR") - if runtimeDir == "" { - runtimeDir = os.TempDir() - } - - entries, err := os.ReadDir(runtimeDir) - if err != nil { - return filepath.Join(runtimeDir, "danklinux.sock") - } - - for _, entry := range entries { - name := entry.Name() - if name == "danklinux.sock" { - return filepath.Join(runtimeDir, name) - } - if len(name) > 10 && name[:10] == "danklinux-" && filepath.Ext(name) == ".sock" { - return filepath.Join(runtimeDir, name) - } - } - - return server.GetSocketPath() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/shell.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/shell.go deleted file mode 100644 index 7ce2003..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/shell.go +++ /dev/null @@ -1,739 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "os/exec" - "os/signal" - "path/filepath" - "slices" - "strconv" - "strings" - "sync" - "syscall" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server" -) - -type ipcTargets map[string]map[string][]string - -// getProcessExitCode returns the exit code from a ProcessState. -// For normal exits, returns the exit code directly. -// For signal termination, returns 128 + signal number (Unix convention). -func getProcessExitCode(state *os.ProcessState) int { - if state == nil { - return 1 - } - if code := state.ExitCode(); code != -1 { - return code - } - // Process was killed by signal - extract signal number - if status, ok := state.Sys().(syscall.WaitStatus); ok { - if status.Signaled() { - return 128 + int(status.Signal()) - } - } - return 1 -} - -var isSessionManaged bool - -func execDetachedRestart(targetPID int) { - selfPath, err := os.Executable() - if err != nil { - return - } - - cmd := exec.Command(selfPath, "restart-detached", strconv.Itoa(targetPID)) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - cmd.Start() -} - -func runDetachedRestart(targetPIDStr string) { - targetPID, err := strconv.Atoi(targetPIDStr) - if err != nil { - return - } - - time.Sleep(200 * time.Millisecond) - - proc, err := os.FindProcess(targetPID) - if err == nil { - proc.Signal(syscall.SIGTERM) - } - - time.Sleep(500 * time.Millisecond) - - killShell() - runShellDaemon(false) -} - -func getRuntimeDir() string { - if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" { - return runtime - } - return os.TempDir() -} - -func hasSystemdRun() bool { - _, err := exec.LookPath("systemd-run") - return err == nil -} - -func getPIDFilePath() string { - return filepath.Join(getRuntimeDir(), fmt.Sprintf("danklinux-%d.pid", os.Getpid())) -} - -func writePIDFile(childPID int) error { - pidFile := getPIDFilePath() - return os.WriteFile(pidFile, []byte(strconv.Itoa(childPID)), 0o644) -} - -func removePIDFile() { - pidFile := getPIDFilePath() - os.Remove(pidFile) -} - -func getAllDMSPIDs() []int { - dir := getRuntimeDir() - entries, err := os.ReadDir(dir) - if err != nil { - return nil - } - - var pids []int - - for _, entry := range entries { - if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".pid") { - continue - } - - pidFile := filepath.Join(dir, entry.Name()) - data, err := os.ReadFile(pidFile) - if err != nil { - continue - } - - childPID, err := strconv.Atoi(strings.TrimSpace(string(data))) - if err != nil { - os.Remove(pidFile) - continue - } - - proc, err := os.FindProcess(childPID) - if err != nil { - os.Remove(pidFile) - continue - } - - if err := proc.Signal(syscall.Signal(0)); err != nil { - os.Remove(pidFile) - continue - } - - pids = append(pids, childPID) - - parentPIDStr := strings.TrimPrefix(entry.Name(), "danklinux-") - parentPIDStr = strings.TrimSuffix(parentPIDStr, ".pid") - if parentPID, err := strconv.Atoi(parentPIDStr); err == nil { - if parentProc, err := os.FindProcess(parentPID); err == nil { - if err := parentProc.Signal(syscall.Signal(0)); err == nil { - pids = append(pids, parentPID) - } - } - } - } - - return pids -} - -func runShellInteractive(session bool) { - isSessionManaged = session - go printASCII() - fmt.Fprintf(os.Stderr, "dms %s\n", Version) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - socketPath := server.GetSocketPath() - - configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path") - if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil { - log.Warnf("Failed to write config state file: %v", err) - } - defer os.Remove(configStateFile) - - errChan := make(chan error, 2) - - go func() { - defer func() { - if r := recover(); r != nil { - errChan <- fmt.Errorf("server panic: %v", r) - } - }() - server.CLIVersion = Version - if err := server.Start(false); err != nil { - errChan <- fmt.Errorf("server error: %w", err) - } - }() - - log.Infof("Spawning quickshell with -p %s", configPath) - - cmd := exec.CommandContext(ctx, "qs", "-p", configPath) - cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath) - if os.Getenv("QT_LOGGING_RULES") == "" { - if qtRules := log.GetQtLoggingRules(); qtRules != "" { - cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules) - } - } - - // ! TODO - remove when QS 0.3 is up and we can use the pragma - cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms") - - if isSessionManaged && hasSystemdRun() { - cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope") - } - - homeDir, err := os.UserHomeDir() - if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" { - if !strings.HasPrefix(configPath, homeDir) { - cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1") - } - } - - if os.Getenv("QT_QPA_PLATFORMTHEME") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME=gtk3") - } - if os.Getenv("QT_QPA_PLATFORMTHEME_QT6") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME_QT6=gtk3") - } - if os.Getenv("QT_QPA_PLATFORM") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb") - } - - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Start(); err != nil { - log.Fatalf("Error starting quickshell: %v", err) - } - - // Write PID file for the quickshell child process - if err := writePIDFile(cmd.Process.Pid); err != nil { - log.Warnf("Failed to write PID file: %v", err) - } - defer removePIDFile() - - defer func() { - if cmd.Process != nil { - cmd.Process.Signal(syscall.SIGTERM) - } - }() - - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) - - go func() { - if err := cmd.Wait(); err != nil { - errChan <- fmt.Errorf("quickshell exited: %w", err) - } else { - errChan <- fmt.Errorf("quickshell exited") - } - }() - - for { - select { - case sig := <-sigChan: - if sig == syscall.SIGUSR1 { - if isSessionManaged { - log.Infof("Received SIGUSR1, exiting for systemd restart...") - cancel() - cmd.Process.Signal(syscall.SIGTERM) - os.Remove(socketPath) - os.Exit(1) - } - log.Infof("Received SIGUSR1, spawning detached restart process...") - execDetachedRestart(os.Getpid()) - return - } - - // Check if qs already crashed before we got SIGTERM (systemd sends SIGTERM when D-Bus name is released) - select { - case <-errChan: - cancel() - os.Remove(socketPath) - os.Exit(getProcessExitCode(cmd.ProcessState)) - case <-time.After(500 * time.Millisecond): - } - - log.Infof("\nReceived signal %v, shutting down...", sig) - cancel() - cmd.Process.Signal(syscall.SIGTERM) - os.Remove(socketPath) - return - - case err := <-errChan: - log.Error(err) - cancel() - if cmd.Process != nil { - cmd.Process.Signal(syscall.SIGTERM) - } - os.Remove(socketPath) - os.Exit(getProcessExitCode(cmd.ProcessState)) - } - } -} - -func restartShell() { - pids := getAllDMSPIDs() - - if len(pids) == 0 { - log.Info("No running DMS shell instances found. Starting daemon...") - runShellDaemon(false) - return - } - - currentPid := os.Getpid() - uniquePids := make(map[int]bool) - - for _, pid := range pids { - if pid != currentPid { - uniquePids[pid] = true - } - } - - for pid := range uniquePids { - proc, err := os.FindProcess(pid) - if err != nil { - log.Errorf("Error finding process %d: %v", pid, err) - continue - } - - if err := proc.Signal(syscall.Signal(0)); err != nil { - continue - } - - if err := proc.Signal(syscall.SIGUSR1); err != nil { - log.Errorf("Error sending SIGUSR1 to process %d: %v", pid, err) - } else { - log.Infof("Sent SIGUSR1 to DMS process with PID %d", pid) - } - } -} - -func killShell() { - pids := getAllDMSPIDs() - - if len(pids) == 0 { - log.Info("No running DMS shell instances found.") - return - } - - currentPid := os.Getpid() - uniquePids := make(map[int]bool) - - for _, pid := range pids { - if pid != currentPid { - uniquePids[pid] = true - } - } - - for pid := range uniquePids { - proc, err := os.FindProcess(pid) - if err != nil { - log.Errorf("Error finding process %d: %v", pid, err) - continue - } - - if err := proc.Signal(syscall.Signal(0)); err != nil { - continue - } - - if err := proc.Kill(); err != nil { - log.Errorf("Error killing process %d: %v", pid, err) - } else { - log.Infof("Killed DMS process with PID %d", pid) - } - } - - dir := getRuntimeDir() - entries, err := os.ReadDir(dir) - if err != nil { - return - } - - for _, entry := range entries { - if strings.HasPrefix(entry.Name(), "danklinux-") && strings.HasSuffix(entry.Name(), ".pid") { - pidFile := filepath.Join(dir, entry.Name()) - os.Remove(pidFile) - } - } -} - -func runShellDaemon(session bool) { - isSessionManaged = session - isDaemonChild := slices.Contains(os.Args, "--daemon-child") - - if !isDaemonChild { - fmt.Fprintf(os.Stderr, "dms %s\n", Version) - - cmd := exec.Command(os.Args[0], "run", "-d", "--daemon-child") - cmd.Env = os.Environ() - - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - - if err := cmd.Start(); err != nil { - log.Fatalf("Error starting daemon: %v", err) - } - - log.Infof("DMS shell daemon started (PID: %d)", cmd.Process.Pid) - return - } - - fmt.Fprintf(os.Stderr, "dms %s\n", Version) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - socketPath := server.GetSocketPath() - - configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path") - if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil { - log.Warnf("Failed to write config state file: %v", err) - } - defer os.Remove(configStateFile) - - errChan := make(chan error, 2) - - go func() { - defer func() { - if r := recover(); r != nil { - errChan <- fmt.Errorf("server panic: %v", r) - } - }() - server.CLIVersion = Version - if err := server.Start(false); err != nil { - errChan <- fmt.Errorf("server error: %w", err) - } - }() - - log.Infof("Spawning quickshell with -p %s", configPath) - - cmd := exec.CommandContext(ctx, "qs", "-p", configPath) - cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath) - if os.Getenv("QT_LOGGING_RULES") == "" { - if qtRules := log.GetQtLoggingRules(); qtRules != "" { - cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules) - } - } - - // ! TODO - remove when QS 0.3 is up and we can use the pragma - cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms") - - if isSessionManaged && hasSystemdRun() { - cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope") - } - - homeDir, err := os.UserHomeDir() - if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" { - if !strings.HasPrefix(configPath, homeDir) { - cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1") - } - } - - if os.Getenv("QT_QPA_PLATFORMTHEME") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME=gtk3") - } - if os.Getenv("QT_QPA_PLATFORMTHEME_QT6") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME_QT6=gtk3") - } - if os.Getenv("QT_QPA_PLATFORM") == "" { - cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb") - } - - devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0) - if err != nil { - log.Fatalf("Error opening /dev/null: %v", err) - } - defer devNull.Close() - - cmd.Stdin = devNull - cmd.Stdout = devNull - cmd.Stderr = devNull - - if err := cmd.Start(); err != nil { - log.Fatalf("Error starting daemon: %v", err) - } - - // Write PID file for the quickshell child process - if err := writePIDFile(cmd.Process.Pid); err != nil { - log.Warnf("Failed to write PID file: %v", err) - } - defer removePIDFile() - - defer func() { - if cmd.Process != nil { - cmd.Process.Signal(syscall.SIGTERM) - } - }() - - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) - - go func() { - if err := cmd.Wait(); err != nil { - errChan <- fmt.Errorf("quickshell exited: %w", err) - } else { - errChan <- fmt.Errorf("quickshell exited") - } - }() - - for { - select { - case sig := <-sigChan: - if sig == syscall.SIGUSR1 { - if isSessionManaged { - log.Infof("Received SIGUSR1, exiting for systemd restart...") - cancel() - cmd.Process.Signal(syscall.SIGTERM) - os.Remove(socketPath) - os.Exit(1) - } - log.Infof("Received SIGUSR1, spawning detached restart process...") - execDetachedRestart(os.Getpid()) - return - } - - // Check if qs already crashed before we got SIGTERM (systemd sends SIGTERM when D-Bus name is released) - select { - case <-errChan: - cancel() - os.Remove(socketPath) - os.Exit(getProcessExitCode(cmd.ProcessState)) - case <-time.After(500 * time.Millisecond): - } - - cancel() - cmd.Process.Signal(syscall.SIGTERM) - os.Remove(socketPath) - return - - case <-errChan: - cancel() - if cmd.Process != nil { - cmd.Process.Signal(syscall.SIGTERM) - } - os.Remove(socketPath) - os.Exit(getProcessExitCode(cmd.ProcessState)) - } - } -} - -var qsHasAnyDisplay = sync.OnceValue(func() bool { - out, err := exec.Command("qs", "ipc", "--help").Output() - if err != nil { - return false - } - return strings.Contains(string(out), "--any-display") -}) - -func parseTargetsFromIPCShowOutput(output string) ipcTargets { - targets := make(ipcTargets) - var currentTarget string - for line := range strings.SplitSeq(output, "\n") { - if after, ok := strings.CutPrefix(line, "target "); ok { - currentTarget = strings.TrimSpace(after) - targets[currentTarget] = make(map[string][]string) - } - if strings.HasPrefix(line, " function") && currentTarget != "" { - argsList := []string{} - currentFunc := strings.TrimPrefix(line, " function ") - funcDef := strings.SplitN(currentFunc, "(", 2) - argList := strings.SplitN(funcDef[1], ")", 2)[0] - args := strings.Split(argList, ",") - if len(args) > 0 && strings.TrimSpace(args[0]) != "" { - argsList = append(argsList, funcDef[0]) - for _, arg := range args { - argName := strings.SplitN(strings.TrimSpace(arg), ":", 2)[0] - argsList = append(argsList, argName) - } - targets[currentTarget][funcDef[0]] = argsList - } else { - targets[currentTarget][funcDef[0]] = make([]string, 0) - } - } - } - return targets -} - -func getShellIPCCompletions(args []string, _ string) []string { - cmdArgs := []string{"ipc"} - if qsHasAnyDisplay() { - cmdArgs = append(cmdArgs, "--any-display") - } - cmdArgs = append(cmdArgs, "-p", configPath, "show") - cmd := exec.Command("qs", cmdArgs...) - var targets ipcTargets - - if output, err := cmd.Output(); err == nil { - targets = parseTargetsFromIPCShowOutput(string(output)) - } else { - log.Debugf("Error getting IPC show output for completions: %v", err) - return nil - } - - if len(args) > 0 && args[0] == "call" { - args = args[1:] - } - - if len(args) == 0 { - targetNames := make([]string, 0) - targetNames = append(targetNames, "call") - for k := range targets { - targetNames = append(targetNames, k) - } - return targetNames - } - if len(args) == 1 { - if targetFuncs, ok := targets[args[0]]; ok { - funcNames := make([]string, 0) - for k := range targetFuncs { - funcNames = append(funcNames, k) - } - return funcNames - } - return nil - } - if len(args) <= len(targets[args[0]]) { - funcArgs := targets[args[0]][args[1]] - if len(funcArgs) >= len(args) { - return []string{fmt.Sprintf("[%s]", funcArgs[len(args)-1])} - } - } - - return nil -} - -func getFirstDMSPID() (int, bool) { - dir := getRuntimeDir() - entries, err := os.ReadDir(dir) - if err != nil { - return 0, false - } - - for _, entry := range entries { - if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".pid") { - continue - } - - data, err := os.ReadFile(filepath.Join(dir, entry.Name())) - if err != nil { - continue - } - - pid, err := strconv.Atoi(strings.TrimSpace(string(data))) - if err != nil { - continue - } - - proc, err := os.FindProcess(pid) - if err != nil { - continue - } - - if proc.Signal(syscall.Signal(0)) != nil { - continue - } - - return pid, true - } - - return 0, false -} - -func runShellIPCCommand(args []string) { - if len(args) == 0 { - printIPCHelp() - return - } - - if args[0] != "call" { - args = append([]string{"call"}, args...) - } - - cmdArgs := []string{"ipc"} - - switch pid, ok := getFirstDMSPID(); { - case ok: - cmdArgs = append(cmdArgs, "--pid", strconv.Itoa(pid)) - default: - if err := findConfig(nil, nil); err != nil { - log.Fatalf("Error finding config: %v", err) - } - // ! TODO - remove check when QS 0.3 is released - if qsHasAnyDisplay() { - cmdArgs = append(cmdArgs, "--any-display") - } - cmdArgs = append(cmdArgs, "-p", configPath) - } - - cmdArgs = append(cmdArgs, args...) - cmd := exec.Command("qs", cmdArgs...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - log.Fatalf("Error running IPC command: %v", err) - } -} - -func printIPCHelp() { - fmt.Println("Usage: dms ipc [args...]") - fmt.Println() - - cmdArgs := []string{"ipc"} - if qsHasAnyDisplay() { - cmdArgs = append(cmdArgs, "--any-display") - } - cmdArgs = append(cmdArgs, "-p", configPath, "show") - cmd := exec.Command("qs", cmdArgs...) - - output, err := cmd.Output() - if err != nil { - fmt.Println("Could not retrieve available IPC targets (is DMS running?)") - return - } - - targets := parseTargetsFromIPCShowOutput(string(output)) - if len(targets) == 0 { - fmt.Println("No IPC targets available") - return - } - - fmt.Println("Targets:") - - targetNames := make([]string, 0, len(targets)) - for name := range targets { - targetNames = append(targetNames, name) - } - slices.Sort(targetNames) - - for _, targetName := range targetNames { - funcs := targets[targetName] - funcNames := make([]string, 0, len(funcs)) - for fn := range funcs { - funcNames = append(funcNames, fn) - } - slices.Sort(funcNames) - fmt.Printf(" %-16s %s\n", targetName, strings.Join(funcNames, ", ")) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/ui.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/ui.go deleted file mode 100644 index c0b50e6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/ui.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/tui" - "github.com/charmbracelet/lipgloss" -) - -func printASCII() { - fmt.Print(getThemedASCII()) -} - -func getThemedASCII() string { - theme := tui.TerminalTheme() - - logo := ` -██████╗ █████╗ ███╗ ██╗██╗ ██╗ -██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝ -██║ ██║███████║██╔██╗ ██║█████╔╝ -██║ ██║██╔══██║██║╚██╗██║██╔═██╗ -██████╔╝██║ ██║██║ ╚████║██║ ██╗ -╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝` - - style := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true) - - return style.Render(logo) + "\n" -} - -func getHelpTemplate() string { - return getThemedASCII() + ` -{{.Long}} - -Usage: - {{.UseLine}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/utils.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/utils.go deleted file mode 100644 index 9459e41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/cmd/dms/utils.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "fmt" - "os/exec" - "slices" - "strings" -) - -// isReadOnlyCommand returns true if the CLI args indicate a command that is -// safe to run as root (e.g. shell completion, help). -func isReadOnlyCommand(args []string) bool { - for _, arg := range args[1:] { - if strings.HasPrefix(arg, "-") { - continue - } - switch arg { - case "completion", "help", "__complete": - return true - } - return false - } - return false -} - -func isArchPackageInstalled(packageName string) bool { - cmd := exec.Command("pacman", "-Q", packageName) - err := cmd.Run() - return err == nil -} - -type systemdServiceState struct { - Name string - EnabledState string - NeedsDisable bool - Exists bool -} - -// checkSystemdServiceEnabled returns (state, should_disable, error) for a systemd service -func checkSystemdServiceEnabled(serviceName string) (string, bool, error) { - cmd := exec.Command("systemctl", "is-enabled", serviceName) - output, err := cmd.Output() - - stateStr := strings.TrimSpace(string(output)) - - if err != nil { - knownStates := []string{"disabled", "masked", "masked-runtime", "not-found", "enabled", "enabled-runtime", "static", "indirect", "alias"} - isKnownState := slices.Contains(knownStates, stateStr) - - if !isKnownState { - return stateStr, false, fmt.Errorf("systemctl is-enabled failed: %w (output: %s)", err, stateStr) - } - } - - shouldDisable := false - switch stateStr { - case "enabled", "enabled-runtime", "static", "indirect", "alias": - shouldDisable = true - case "disabled", "masked", "masked-runtime", "not-found": - shouldDisable = false - default: - shouldDisable = true - } - - return stateStr, shouldDisable, nil -} - -func getSystemdServiceState(serviceName string) (*systemdServiceState, error) { - state := &systemdServiceState{ - Name: serviceName, - Exists: false, - } - - enabledState, needsDisable, err := checkSystemdServiceEnabled(serviceName) - if err != nil { - return nil, fmt.Errorf("failed to check enabled state: %w", err) - } - - state.EnabledState = enabledState - state.NeedsDisable = needsDisable - - if enabledState == "not-found" { - state.Exists = false - return state, nil - } - - state.Exists = true - return state, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.mod b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.mod deleted file mode 100644 index 9f95be8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.mod +++ /dev/null @@ -1,87 +0,0 @@ -module github.com/AvengeMedia/DankMaterialShell/core - -go 1.26.0 - -toolchain go1.26.1 - -require ( - github.com/Wifx/gonetworkmanager/v2 v2.2.0 - github.com/alecthomas/chroma/v2 v2.23.1 - github.com/charmbracelet/bubbles v1.0.0 - github.com/charmbracelet/bubbletea v1.3.10 - github.com/charmbracelet/lipgloss v1.1.0 - github.com/charmbracelet/log v0.4.2 - github.com/fsnotify/fsnotify v1.9.0 - github.com/godbus/dbus/v5 v5.2.2 - github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83 - github.com/pilebones/go-udev v0.9.1 - github.com/sblinch/kdl-go v0.0.0-20260121213736-8b7053306ca6 - github.com/spf13/cobra v1.10.2 - github.com/stretchr/testify v1.11.1 - github.com/yeqown/go-qrcode/v2 v2.2.5 - github.com/yeqown/go-qrcode/writer/standard v1.3.0 - github.com/yuin/goldmark v1.7.16 - github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc - go.etcd.io/bbolt v1.4.3 - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a - golang.org/x/image v0.36.0 -) - -require ( - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProtonMail/go-crypto v1.3.0 // indirect - github.com/clipperhouse/displaywidth v0.10.0 // indirect - github.com/clipperhouse/uax29/v2 v2.7.0 // indirect - github.com/cloudflare/circl v1.6.3 // indirect - github.com/cyphar/filepath-securejoin v0.6.1 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/fogleman/gg v1.3.0 // indirect - github.com/go-git/gcfg/v2 v2.0.2 // indirect - github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 // indirect - github.com/go-logfmt/logfmt v0.6.1 // indirect - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect - github.com/kevinburke/ssh_config v1.6.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/pjbgf/sha1cd v0.5.0 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/sergi/go-diff v1.4.0 // indirect - github.com/stretchr/objx v0.5.3 // indirect - github.com/yeqown/reedsolomon v1.0.0 // indirect - golang.org/x/crypto v0.48.0 // indirect - golang.org/x/net v0.50.0 // indirect -) - -require ( - github.com/atotto/clipboard v0.1.4 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/colorprofile v0.4.2 // indirect - github.com/charmbracelet/harmonica v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.11.6 // indirect - github.com/charmbracelet/x/cellbuf v0.0.15 // indirect - github.com/charmbracelet/x/term v0.2.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/lucasb-eyer/go-colorful v1.3.0 - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect - github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/termenv v0.16.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/spf13/afero v1.15.0 - github.com/spf13/pflag v1.0.10 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/sys v0.41.0 - golang.org/x/text v0.34.0 - gopkg.in/yaml.v3 v3.0.1 -) - -// v0.0.1 tag is missing a LICENSE file; master has it. -// See: https://github.com/mattn/go-localereader/issues/2 -replace github.com/mattn/go-localereader v0.0.1 => github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.sum b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.sum deleted file mode 100644 index 4817d4f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/go.sum +++ /dev/null @@ -1,191 +0,0 @@ -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= -github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= -github.com/Wifx/gonetworkmanager/v2 v2.2.0 h1:kPstgsQtY8CmDOOFZd81ytM9Gi3f6ImzPCKF7nNhQ2U= -github.com/Wifx/gonetworkmanager/v2 v2.2.0/go.mod h1:fMDb//SHsKWxyDUAwXvCqurV3npbIyyaQWenGpZ/uXg= -github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= -github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= -github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= -github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= -github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= -github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc= -github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E= -github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= -github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= -github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY= -github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8= -github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= -github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig= -github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw= -github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= -github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= -github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= -github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= -github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= -github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= -github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= -github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= -github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= -github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= -github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= -github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= -github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= -github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo= -github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs= -github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 h1:UU7oARtwQ5g85aFiCSwIUA6PBmAshYj0sytl/5CCBgs= -github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3/go.mod h1:ZW9JC5gionMP1kv5uiaOaV23q0FFmNrVOV8VW+y/acc= -github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67 h1:3hutPZF+/FBjR/9MdsLJ7e1mlt9pwHgwxMW7CrbmWII= -github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67/go.mod h1:xKt0pNHST9tYHvbiLxSY27CQWFwgIxBJuDrOE0JvbZw= -github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f h1:TBkCJv9YwPOuXq1OG0r01bcxRrvs15Hp/DtZuPt4H6s= -github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f/go.mod h1:B88nWzfnhTlIikoJ4d84Nc9noKS5mJoA7SgDdkt0aPU= -github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE= -github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= -github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83 h1:B+A58zGFuDrvEZpPN+yS6swJA0nzqgZvDzgl/OPyefU= -github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83/go.mod h1:iHAf8OIncO2gcQ8XOjS7CMJ2aPbX2Bs0wl5pZyanEqk= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY= -github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= -github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw= -github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= -github.com/pilebones/go-udev v0.9.1 h1:uN72M1C1fgzhsVmBGEM8w9RD1JY4iVsPZpr+Z6rb3O8= -github.com/pilebones/go-udev v0.9.1/go.mod h1:Bgcl07crebF3JSeS4+nuaRvhWFdCeFoBhXXeAp93XNo= -github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= -github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sblinch/kdl-go v0.0.0-20260121213736-8b7053306ca6 h1:JsjzqC6ymELkN4XlTjZPSahSAem21GySugLbKz6uF5E= -github.com/sblinch/kdl-go v0.0.0-20260121213736-8b7053306ca6/go.mod h1:b3oNGuAKOQzhsCKmuLc/urEOPzgHj6fB8vl8bwTBh28= -github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= -github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= -github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= -github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= -github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= -github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk= -github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw= -github.com/yeqown/go-qrcode/writer/standard v1.3.0 h1:chdyhEfRtUPgQtuPeaWVGQ/TQx4rE1PqeoW3U+53t34= -github.com/yeqown/go-qrcode/writer/standard v1.3.0/go.mod h1:O4MbzsotGCvy8upYPCR91j81dr5XLT7heuljcNXW+oQ= -github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0= -github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= -github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= -github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= -github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= -go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= -go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= -golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= -golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/install.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/install.sh deleted file mode 100755 index baca588..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/install.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' # No Color - -# Check for root privileges -if [ "$(id -u)" == "0" ]; then - printf "%bError: This script must not be run as root%b\n" "$RED" "$NC" - exit 1 -fi - -# Check if running on Linux -if [ "$(uname)" != "Linux" ]; then - printf "%bError: This installer only supports Linux systems%b\n" "$RED" "$NC" - exit 1 -fi - -# Detect architecture -ARCH=$(uname -m) -case "$ARCH" in -x86_64) - ARCH="amd64" - ;; -aarch64) - ARCH="arm64" - ;; -*) - printf "%bError: Unsupported architecture: %s%b\n" "$RED" "$ARCH" "$NC" - printf "This installer only supports x86_64 (amd64) and aarch64 (arm64) architectures\n" - exit 1 - ;; -esac - -# Get the latest release version -LATEST_VERSION=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') - -if [ -z "$LATEST_VERSION" ]; then - printf "%bError: Could not fetch latest version%b\n" "$RED" "$NC" - exit 1 -fi - -printf "%bInstalling Dankinstall %s for %s...%b\n" "$GREEN" "$LATEST_VERSION" "$ARCH" "$NC" - -# Download and install -TEMP_DIR=$(mktemp -d) -cd "$TEMP_DIR" || exit 1 - -# Download the gzipped binary and its checksum -printf "%bDownloading installer...%b\n" "$GREEN" "$NC" -curl -L "https://github.com/AvengeMedia/DankMaterialShell/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz" -o "installer.gz" -curl -L "https://github.com/AvengeMedia/DankMaterialShell/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz.sha256" -o "expected.sha256" - -# Get the expected checksum -EXPECTED_CHECKSUM=$(awk '{print $1}' expected.sha256) - -# Calculate actual checksum -printf "%bVerifying checksum...%b\n" "$GREEN" "$NC" -ACTUAL_CHECKSUM=$(sha256sum installer.gz | awk '{print $1}') - -# Compare checksums -if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then - printf "%bError: Checksum verification failed%b\n" "$RED" "$NC" - printf "Expected: %s\n" "$EXPECTED_CHECKSUM" - printf "Got: %s\n" "$ACTUAL_CHECKSUM" - printf "The downloaded file may be corrupted or tampered with\n" - cd - >/dev/null - rm -rf "$TEMP_DIR" - exit 1 -fi - -# Decompress the binary -printf "%bDecompressing installer...%b\n" "$GREEN" "$NC" -gunzip installer.gz -chmod +x installer - -# Execute the installer -printf "%bRunning installer...%b\n" "$GREEN" "$NC" -./installer - -# Cleanup -cd - >/dev/null -rm -rf "$TEMP_DIR" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/blur/probe.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/blur/probe.go deleted file mode 100644 index e9c24b8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/blur/probe.go +++ /dev/null @@ -1,35 +0,0 @@ -package blur - -import ( - wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" - client "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -const extBackgroundEffectInterface = "ext_background_effect_manager_v1" - -func ProbeSupport() (bool, error) { - display, err := client.Connect("") - if err != nil { - return false, err - } - defer display.Context().Close() - - registry, err := display.GetRegistry() - if err != nil { - return false, err - } - - found := false - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - switch e.Interface { - case extBackgroundEffectInterface: - found = true - } - }) - - if err := wlhelpers.Roundtrip(display, display.Context()); err != nil { - return false, err - } - - return found, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/clipboard.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/clipboard.go deleted file mode 100644 index d27d6ff..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/clipboard.go +++ /dev/null @@ -1,630 +0,0 @@ -package clipboard - -import ( - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "syscall" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_data_control" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -const envServe = "_DMS_CLIPBOARD_SERVE" -const envMime = "_DMS_CLIPBOARD_MIME" -const envPasteOnce = "_DMS_CLIPBOARD_PASTE_ONCE" -const envCacheFile = "_DMS_CLIPBOARD_CACHE" - -// MaybeServeAndExit intercepts before cobra when re-exec'd as a clipboard -// child. Reads source data into memory, deletes any cache file, then serves. -func MaybeServeAndExit() { - if os.Getenv(envServe) == "" { - return - } - - mimeType := os.Getenv(envMime) - pasteOnce := os.Getenv(envPasteOnce) == "1" - cachePath := os.Getenv(envCacheFile) - - var data []byte - var err error - - switch { - case cachePath != "": - data, err = os.ReadFile(cachePath) - os.Remove(cachePath) - default: - data, err = io.ReadAll(os.Stdin) - } - - if err != nil { - fmt.Fprintf(os.Stderr, "clipboard: read source: %v\n", err) - os.Exit(1) - } - - if err := serveClipboard(data, mimeType, pasteOnce); err != nil { - fmt.Fprintf(os.Stderr, "clipboard: serve: %v\n", err) - os.Exit(1) - } - os.Exit(0) -} - -func Copy(data []byte, mimeType string) error { - return copyForkCached(data, mimeType, false) -} - -func CopyOpts(data []byte, mimeType string, foreground, pasteOnce bool) error { - if foreground { - return serveClipboard(data, mimeType, pasteOnce) - } - return copyForkCached(data, mimeType, pasteOnce) -} - -func CopyReader(data io.Reader, mimeType string, foreground, pasteOnce bool) error { - if foreground { - buf, err := io.ReadAll(data) - if err != nil { - return fmt.Errorf("read source: %w", err) - } - return serveClipboard(buf, mimeType, pasteOnce) - } - return copyFork(data, mimeType, pasteOnce) -} - -func newForkCmd(mimeType string, pasteOnce bool, extra ...string) *exec.Cmd { - cmd := exec.Command(os.Args[0]) - cmd.Stderr = nil - cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} - cmd.Env = append(os.Environ(), - envServe+"=1", - envMime+"="+mimeType, - ) - if pasteOnce { - cmd.Env = append(cmd.Env, envPasteOnce+"=1") - } - cmd.Env = append(cmd.Env, extra...) - return cmd -} - -func waitReady(cmd *exec.Cmd) error { - stdout, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("stdout pipe: %w", err) - } - if err := cmd.Start(); err != nil { - return fmt.Errorf("start: %w", err) - } - var buf [1]byte - if _, err := stdout.Read(buf[:]); err != nil { - return fmt.Errorf("waiting for clipboard ready: %w", err) - } - return nil -} - -func copyForkCached(data []byte, mimeType string, pasteOnce bool) error { - cacheFile, err := createClipboardCacheFile() - if err != nil { - return fmt.Errorf("create cache file: %w", err) - } - cachePath := cacheFile.Name() - - if _, err := cacheFile.Write(data); err != nil { - cacheFile.Close() - os.Remove(cachePath) - return fmt.Errorf("write cache file: %w", err) - } - if err := cacheFile.Close(); err != nil { - os.Remove(cachePath) - return fmt.Errorf("close cache file: %w", err) - } - - cmd := newForkCmd(mimeType, pasteOnce, envCacheFile+"="+cachePath) - cmd.Stdin = nil - if err := waitReady(cmd); err != nil { - os.Remove(cachePath) - return err - } - return nil -} - -func copyFork(data io.Reader, mimeType string, pasteOnce bool) error { - cmd := newForkCmd(mimeType, pasteOnce) - - switch src := data.(type) { - case *os.File: - cmd.Stdin = src - return waitReady(cmd) - - default: - stdin, err := cmd.StdinPipe() - if err != nil { - return fmt.Errorf("stdin pipe: %w", err) - } - - stdout, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("stdout pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - return fmt.Errorf("start: %w", err) - } - if _, err := io.Copy(stdin, data); err != nil { - stdin.Close() - return fmt.Errorf("write stdin: %w", err) - } - if err := stdin.Close(); err != nil { - return fmt.Errorf("close stdin: %w", err) - } - - var buf [1]byte - if _, err := stdout.Read(buf[:]); err != nil { - return fmt.Errorf("waiting for clipboard ready: %w", err) - } - return nil - } -} - -func signalReady() { - if os.Getenv(envServe) == "" { - return - } - os.Stdout.Write([]byte{1}) -} - -func createClipboardCacheFile() (*os.File, error) { - preferredDirs := []string{} - - if cacheDir, err := os.UserCacheDir(); err == nil { - preferredDirs = append(preferredDirs, filepath.Join(cacheDir, "dms", "clipboard")) - } - preferredDirs = append(preferredDirs, "/var/tmp/dms/clipboard") - - for _, dir := range preferredDirs { - if err := os.MkdirAll(dir, 0o700); err != nil { - continue - } - cachedData, err := os.CreateTemp(dir, "dms-clipboard-*") - if err == nil { - return cachedData, nil - } - } - return os.CreateTemp("", "dms-clipboard-*") -} - -func serveClipboard(data []byte, mimeType string, pasteOnce bool) error { - display, err := wlclient.Connect("") - if err != nil { - return fmt.Errorf("wayland connect: %w", err) - } - defer display.Destroy() - - ctx := display.Context() - registry, err := display.GetRegistry() - if err != nil { - return fmt.Errorf("get registry: %w", err) - } - defer registry.Destroy() - - var dataControlMgr *ext_data_control.ExtDataControlManagerV1 - var seat *wlclient.Seat - var bindErr error - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - dataControlMgr = ext_data_control.NewExtDataControlManagerV1(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - bindErr = err - } - case "wl_seat": - if seat != nil { - return - } - seat = wlclient.NewSeat(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - bindErr = err - } - } - }) - - display.Roundtrip() - display.Roundtrip() - - if bindErr != nil { - return fmt.Errorf("registry bind: %w", bindErr) - } - if dataControlMgr == nil { - return fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - defer dataControlMgr.Destroy() - if seat == nil { - return fmt.Errorf("no seat available") - } - - device, err := dataControlMgr.GetDataDevice(seat) - if err != nil { - return fmt.Errorf("get data device: %w", err) - } - defer device.Destroy() - - source, err := dataControlMgr.CreateDataSource() - if err != nil { - return fmt.Errorf("create data source: %w", err) - } - - if err := source.Offer(mimeType); err != nil { - return fmt.Errorf("offer mime type: %w", err) - } - if mimeType == "text/plain;charset=utf-8" || mimeType == "text/plain" { - if err := source.Offer("text/plain"); err != nil { - return fmt.Errorf("offer text/plain: %w", err) - } - if err := source.Offer("text/plain;charset=utf-8"); err != nil { - return fmt.Errorf("offer text/plain;charset=utf-8: %w", err) - } - if err := source.Offer("UTF8_STRING"); err != nil { - return fmt.Errorf("offer UTF8_STRING: %w", err) - } - if err := source.Offer("STRING"); err != nil { - return fmt.Errorf("offer STRING: %w", err) - } - if err := source.Offer("TEXT"); err != nil { - return fmt.Errorf("offer TEXT: %w", err) - } - } - - cancelled := make(chan struct{}) - pasted := make(chan struct{}, 1) - - source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) { - _ = syscall.SetNonblock(e.Fd, false) - file := os.NewFile(uintptr(e.Fd), "pipe") - defer file.Close() - _, _ = file.Write(data) - select { - case pasted <- struct{}{}: - default: - } - }) - - source.SetCancelledHandler(func(e ext_data_control.ExtDataControlSourceV1CancelledEvent) { - close(cancelled) - }) - - if err := device.SetSelection(source); err != nil { - return fmt.Errorf("set selection: %w", err) - } - - display.Roundtrip() - signalReady() - - for { - select { - case <-cancelled: - return nil - case <-pasted: - if pasteOnce { - return nil - } - default: - if err := ctx.Dispatch(); err != nil { - return nil - } - } - } -} - -func CopyText(text string) error { - return Copy([]byte(text), "text/plain;charset=utf-8") -} - -func Paste() ([]byte, string, error) { - display, err := wlclient.Connect("") - if err != nil { - return nil, "", fmt.Errorf("wayland connect: %w", err) - } - defer display.Destroy() - - ctx := display.Context() - registry, err := display.GetRegistry() - if err != nil { - return nil, "", fmt.Errorf("get registry: %w", err) - } - defer registry.Destroy() - - var dataControlMgr *ext_data_control.ExtDataControlManagerV1 - var seat *wlclient.Seat - var bindErr error - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - dataControlMgr = ext_data_control.NewExtDataControlManagerV1(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - bindErr = err - } - case "wl_seat": - if seat != nil { - return - } - seat = wlclient.NewSeat(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - bindErr = err - } - } - }) - - display.Roundtrip() - display.Roundtrip() - - if bindErr != nil { - return nil, "", fmt.Errorf("registry bind: %w", bindErr) - } - - if dataControlMgr == nil { - return nil, "", fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - defer dataControlMgr.Destroy() - - if seat == nil { - return nil, "", fmt.Errorf("no seat available") - } - - device, err := dataControlMgr.GetDataDevice(seat) - if err != nil { - return nil, "", fmt.Errorf("get data device: %w", err) - } - defer device.Destroy() - - offerMimeTypes := make(map[*ext_data_control.ExtDataControlOfferV1][]string) - - device.SetDataOfferHandler(func(e ext_data_control.ExtDataControlDeviceV1DataOfferEvent) { - if e.Id == nil { - return - } - offerMimeTypes[e.Id] = nil - e.Id.SetOfferHandler(func(me ext_data_control.ExtDataControlOfferV1OfferEvent) { - offerMimeTypes[e.Id] = append(offerMimeTypes[e.Id], me.MimeType) - }) - }) - - var selectionOffer *ext_data_control.ExtDataControlOfferV1 - gotSelection := false - - device.SetSelectionHandler(func(e ext_data_control.ExtDataControlDeviceV1SelectionEvent) { - selectionOffer = e.Id - gotSelection = true - }) - - display.Roundtrip() - display.Roundtrip() - - if !gotSelection || selectionOffer == nil { - return nil, "", fmt.Errorf("no clipboard data") - } - - mimeTypes := offerMimeTypes[selectionOffer] - selectedMime := selectPreferredMimeType(mimeTypes) - if selectedMime == "" { - return nil, "", fmt.Errorf("no supported mime type") - } - - r, w, err := os.Pipe() - if err != nil { - return nil, "", fmt.Errorf("create pipe: %w", err) - } - defer r.Close() - - if err := selectionOffer.Receive(selectedMime, int(w.Fd())); err != nil { - w.Close() - return nil, "", fmt.Errorf("receive: %w", err) - } - w.Close() - - display.Roundtrip() - - data, err := io.ReadAll(r) - if err != nil { - return nil, "", fmt.Errorf("read: %w", err) - } - - return data, selectedMime, nil -} - -func PasteText() (string, error) { - data, _, err := Paste() - if err != nil { - return "", err - } - return string(data), nil -} - -func selectPreferredMimeType(mimes []string) string { - preferred := []string{ - "text/plain;charset=utf-8", - "text/plain", - "UTF8_STRING", - "STRING", - "TEXT", - "image/png", - "image/jpeg", - } - - for _, pref := range preferred { - for _, mime := range mimes { - if mime == pref { - return mime - } - } - } - - if len(mimes) > 0 { - return mimes[0] - } - return "" -} - -func IsImageMimeType(mime string) bool { - return len(mime) > 6 && mime[:6] == "image/" -} - -type Offer struct { - MimeType string - Data []byte -} - -func CopyMulti(offers []Offer, foreground, pasteOnce bool) error { - if !foreground { - return copyMultiFork(offers, pasteOnce) - } - return copyMultiServe(offers, pasteOnce) -} - -func copyMultiFork(offers []Offer, pasteOnce bool) error { - args := []string{os.Args[0], "cl", "copy", "--foreground", "--type", "__multi__"} - if pasteOnce { - args = append(args, "--paste-once") - } - - cmd := exec.Command(args[0], args[1:]...) - cmd.Stdin = nil - cmd.Stdout = nil - cmd.Stderr = nil - cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} - - stdin, err := cmd.StdinPipe() - if err != nil { - return fmt.Errorf("stdin pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - return fmt.Errorf("start: %w", err) - } - - for _, offer := range offers { - fmt.Fprintf(stdin, "%s\x00%d\x00", offer.MimeType, len(offer.Data)) - if _, err := stdin.Write(offer.Data); err != nil { - stdin.Close() - return fmt.Errorf("write offer data: %w", err) - } - } - stdin.Close() - - return nil -} - -func copyMultiServe(offers []Offer, pasteOnce bool) error { - display, err := wlclient.Connect("") - if err != nil { - return fmt.Errorf("wayland connect: %w", err) - } - defer display.Destroy() - - ctx := display.Context() - registry, err := display.GetRegistry() - if err != nil { - return fmt.Errorf("get registry: %w", err) - } - defer registry.Destroy() - - var dataControlMgr *ext_data_control.ExtDataControlManagerV1 - var seat *wlclient.Seat - var bindErr error - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - dataControlMgr = ext_data_control.NewExtDataControlManagerV1(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - bindErr = err - } - case "wl_seat": - if seat != nil { - return - } - seat = wlclient.NewSeat(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - bindErr = err - } - } - }) - - display.Roundtrip() - display.Roundtrip() - - if bindErr != nil { - return fmt.Errorf("registry bind: %w", bindErr) - } - if dataControlMgr == nil { - return fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - defer dataControlMgr.Destroy() - if seat == nil { - return fmt.Errorf("no seat available") - } - - device, err := dataControlMgr.GetDataDevice(seat) - if err != nil { - return fmt.Errorf("get data device: %w", err) - } - defer device.Destroy() - - source, err := dataControlMgr.CreateDataSource() - if err != nil { - return fmt.Errorf("create data source: %w", err) - } - - offerMap := make(map[string][]byte) - for _, offer := range offers { - if err := source.Offer(offer.MimeType); err != nil { - return fmt.Errorf("offer %s: %w", offer.MimeType, err) - } - offerMap[offer.MimeType] = offer.Data - } - - cancelled := make(chan struct{}) - pasted := make(chan struct{}, 1) - - source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) { - _ = syscall.SetNonblock(e.Fd, false) - file := os.NewFile(uintptr(e.Fd), "pipe") - defer file.Close() - - if data, ok := offerMap[e.MimeType]; ok { - _, _ = file.Write(data) - } - - select { - case pasted <- struct{}{}: - default: - } - }) - - source.SetCancelledHandler(func(e ext_data_control.ExtDataControlSourceV1CancelledEvent) { - close(cancelled) - }) - - if err := device.SetSelection(source); err != nil { - return fmt.Errorf("set selection: %w", err) - } - - display.Roundtrip() - - for { - select { - case <-cancelled: - return nil - case <-pasted: - if pasteOnce { - return nil - } - default: - if err := ctx.Dispatch(); err != nil { - return nil - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/store.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/store.go deleted file mode 100644 index 17ad7a9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/store.go +++ /dev/null @@ -1,248 +0,0 @@ -package clipboard - -import ( - "bytes" - "encoding/binary" - "fmt" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "os" - "path/filepath" - "strings" - "time" - - _ "golang.org/x/image/bmp" - _ "golang.org/x/image/tiff" - "hash/fnv" - - bolt "go.etcd.io/bbolt" -) - -type StoreConfig struct { - MaxHistory int - MaxEntrySize int64 -} - -func DefaultStoreConfig() StoreConfig { - return StoreConfig{ - MaxHistory: 100, - MaxEntrySize: 5 * 1024 * 1024, - } -} - -type Entry struct { - ID uint64 - Data []byte - MimeType string - Preview string - Size int - Timestamp time.Time - IsImage bool - Hash uint64 -} - -func Store(data []byte, mimeType string) error { - return StoreWithConfig(data, mimeType, DefaultStoreConfig()) -} - -func StoreWithConfig(data []byte, mimeType string, cfg StoreConfig) error { - if len(data) == 0 { - return nil - } - if int64(len(data)) > cfg.MaxEntrySize { - return fmt.Errorf("data too large: %d > %d", len(data), cfg.MaxEntrySize) - } - - dbPath, err := GetDBPath() - if err != nil { - return fmt.Errorf("get db path: %w", err) - } - - db, err := bolt.Open(dbPath, 0o644, &bolt.Options{Timeout: 1 * time.Second}) - if err != nil { - return fmt.Errorf("open db: %w", err) - } - defer db.Close() - - entry := Entry{ - Data: data, - MimeType: mimeType, - Size: len(data), - Timestamp: time.Now(), - IsImage: IsImageMimeType(mimeType), - Hash: computeHash(data), - } - - switch { - case entry.IsImage: - entry.Preview = imagePreview(data, mimeType) - default: - entry.Preview = textPreview(data) - } - - return db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("clipboard")) - if err != nil { - return err - } - - if err := deduplicateInTx(b, entry.Hash); err != nil { - return err - } - - id, err := b.NextSequence() - if err != nil { - return err - } - entry.ID = id - - encoded, err := encodeEntry(entry) - if err != nil { - return err - } - - if err := b.Put(itob(id), encoded); err != nil { - return err - } - - return trimLengthInTx(b, cfg.MaxHistory) - }) -} - -func GetDBPath() (string, error) { - cacheDir, err := os.UserCacheDir() - if err != nil { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", err - } - cacheDir = filepath.Join(homeDir, ".cache") - } - - newDir := filepath.Join(cacheDir, "DankMaterialShell", "clipboard") - newPath := filepath.Join(newDir, "db") - - if _, err := os.Stat(newPath); err == nil { - return newPath, nil - } - - oldDir := filepath.Join(cacheDir, "dms-clipboard") - oldPath := filepath.Join(oldDir, "db") - - if _, err := os.Stat(oldPath); err == nil { - if err := os.MkdirAll(newDir, 0o700); err != nil { - return "", err - } - if err := os.Rename(oldPath, newPath); err != nil { - return "", err - } - os.Remove(oldDir) - return newPath, nil - } - - if err := os.MkdirAll(newDir, 0o700); err != nil { - return "", err - } - return newPath, nil -} - -func deduplicateInTx(b *bolt.Bucket, hash uint64) error { - c := b.Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - if extractHash(v) != hash { - continue - } - if err := b.Delete(k); err != nil { - return err - } - } - return nil -} - -func trimLengthInTx(b *bolt.Bucket, maxHistory int) error { - c := b.Cursor() - var count int - for k, _ := c.Last(); k != nil; k, _ = c.Prev() { - if count < maxHistory { - count++ - continue - } - if err := b.Delete(k); err != nil { - return err - } - } - return nil -} - -func encodeEntry(e Entry) ([]byte, error) { - buf := new(bytes.Buffer) - - binary.Write(buf, binary.BigEndian, e.ID) - binary.Write(buf, binary.BigEndian, uint32(len(e.Data))) - buf.Write(e.Data) - binary.Write(buf, binary.BigEndian, uint32(len(e.MimeType))) - buf.WriteString(e.MimeType) - binary.Write(buf, binary.BigEndian, uint32(len(e.Preview))) - buf.WriteString(e.Preview) - binary.Write(buf, binary.BigEndian, int32(e.Size)) - binary.Write(buf, binary.BigEndian, e.Timestamp.Unix()) - if e.IsImage { - buf.WriteByte(1) - } else { - buf.WriteByte(0) - } - binary.Write(buf, binary.BigEndian, e.Hash) - - return buf.Bytes(), nil -} - -func itob(v uint64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, v) - return b -} - -func computeHash(data []byte) uint64 { - h := fnv.New64a() - h.Write(data) - return h.Sum64() -} - -func extractHash(data []byte) uint64 { - if len(data) < 8 { - return 0 - } - return binary.BigEndian.Uint64(data[len(data)-8:]) -} - -func textPreview(data []byte) string { - text := string(data) - text = strings.TrimSpace(text) - text = strings.Join(strings.Fields(text), " ") - - if len(text) > 100 { - return text[:100] + "…" - } - return text -} - -func imagePreview(data []byte, format string) string { - config, imgFmt, err := image.DecodeConfig(bytes.NewReader(data)) - if err != nil { - return fmt.Sprintf("[[ image %s %s ]]", sizeStr(len(data)), format) - } - return fmt.Sprintf("[[ image %s %s %dx%d ]]", sizeStr(len(data)), imgFmt, config.Width, config.Height) -} - -func sizeStr(size int) string { - units := []string{"B", "KiB", "MiB"} - var i int - fsize := float64(size) - for fsize >= 1024 && i < len(units)-1 { - fsize /= 1024 - i++ - } - return fmt.Sprintf("%.0f %s", fsize, units[i]) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/watch.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/watch.go deleted file mode 100644 index 327c5c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/clipboard/watch.go +++ /dev/null @@ -1,303 +0,0 @@ -package clipboard - -import ( - "context" - "errors" - "fmt" - "io" - "os" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_data_control" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type ClipboardChange struct { - Data []byte - MimeType string - MimeTypes []string -} - -func Watch(ctx context.Context, callback func(data []byte, mimeType string)) error { - display, err := wlclient.Connect("") - if err != nil { - return fmt.Errorf("wayland connect: %w", err) - } - defer display.Destroy() - - wlCtx := display.Context() - registry, err := display.GetRegistry() - if err != nil { - return fmt.Errorf("get registry: %w", err) - } - defer registry.Destroy() - - var dataControlMgr *ext_data_control.ExtDataControlManagerV1 - var seat *wlclient.Seat - var bindErr error - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - dataControlMgr = ext_data_control.NewExtDataControlManagerV1(wlCtx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - bindErr = err - } - case "wl_seat": - if seat != nil { - return - } - seat = wlclient.NewSeat(wlCtx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - bindErr = err - } - } - }) - - display.Roundtrip() - display.Roundtrip() - - if bindErr != nil { - return fmt.Errorf("registry bind: %w", bindErr) - } - - if dataControlMgr == nil { - return fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - defer dataControlMgr.Destroy() - - if seat == nil { - return fmt.Errorf("no seat available") - } - - device, err := dataControlMgr.GetDataDevice(seat) - if err != nil { - return fmt.Errorf("get data device: %w", err) - } - defer device.Destroy() - - offerMimeTypes := make(map[*ext_data_control.ExtDataControlOfferV1][]string) - - device.SetDataOfferHandler(func(e ext_data_control.ExtDataControlDeviceV1DataOfferEvent) { - if e.Id == nil { - return - } - offerMimeTypes[e.Id] = nil - e.Id.SetOfferHandler(func(me ext_data_control.ExtDataControlOfferV1OfferEvent) { - offerMimeTypes[e.Id] = append(offerMimeTypes[e.Id], me.MimeType) - }) - }) - - device.SetSelectionHandler(func(e ext_data_control.ExtDataControlDeviceV1SelectionEvent) { - if e.Id == nil { - return - } - - mimes := offerMimeTypes[e.Id] - selectedMime := selectPreferredMimeType(mimes) - if selectedMime == "" { - return - } - - r, w, err := os.Pipe() - if err != nil { - return - } - - if err := e.Id.Receive(selectedMime, int(w.Fd())); err != nil { - w.Close() - r.Close() - return - } - w.Close() - - go func() { - defer r.Close() - data, err := io.ReadAll(r) - if err != nil || len(data) == 0 { - return - } - callback(data, selectedMime) - }() - }) - - display.Roundtrip() - display.Roundtrip() - - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - if err := wlCtx.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { - return fmt.Errorf("set read deadline: %w", err) - } - if err := wlCtx.Dispatch(); err != nil { - if isTimeoutError(err) { - continue - } - return fmt.Errorf("dispatch: %w", err) - } - } - } -} - -func WatchAll(ctx context.Context, callback func(data []byte, mimeType string, allMimeTypes []string)) error { - display, err := wlclient.Connect("") - if err != nil { - return fmt.Errorf("wayland connect: %w", err) - } - defer display.Destroy() - - wlCtx := display.Context() - registry, err := display.GetRegistry() - if err != nil { - return fmt.Errorf("get registry: %w", err) - } - defer registry.Destroy() - - var dataControlMgr *ext_data_control.ExtDataControlManagerV1 - var seat *wlclient.Seat - var bindErr error - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - dataControlMgr = ext_data_control.NewExtDataControlManagerV1(wlCtx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - bindErr = err - } - case "wl_seat": - if seat != nil { - return - } - seat = wlclient.NewSeat(wlCtx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - bindErr = err - } - } - }) - - display.Roundtrip() - display.Roundtrip() - - if bindErr != nil { - return fmt.Errorf("registry bind: %w", bindErr) - } - if dataControlMgr == nil { - return fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - defer dataControlMgr.Destroy() - if seat == nil { - return fmt.Errorf("no seat available") - } - - device, err := dataControlMgr.GetDataDevice(seat) - if err != nil { - return fmt.Errorf("get data device: %w", err) - } - defer device.Destroy() - - offerMimeTypes := make(map[*ext_data_control.ExtDataControlOfferV1][]string) - - device.SetDataOfferHandler(func(e ext_data_control.ExtDataControlDeviceV1DataOfferEvent) { - if e.Id == nil { - return - } - offerMimeTypes[e.Id] = nil - e.Id.SetOfferHandler(func(me ext_data_control.ExtDataControlOfferV1OfferEvent) { - offerMimeTypes[e.Id] = append(offerMimeTypes[e.Id], me.MimeType) - }) - }) - - device.SetSelectionHandler(func(e ext_data_control.ExtDataControlDeviceV1SelectionEvent) { - if e.Id == nil { - return - } - - mimes := offerMimeTypes[e.Id] - selectedMime := selectPreferredMimeType(mimes) - if selectedMime == "" { - return - } - - mimesCopy := make([]string, len(mimes)) - copy(mimesCopy, mimes) - - r, w, err := os.Pipe() - if err != nil { - return - } - - if err := e.Id.Receive(selectedMime, int(w.Fd())); err != nil { - w.Close() - r.Close() - return - } - w.Close() - - go func() { - defer r.Close() - data, err := io.ReadAll(r) - if err != nil || len(data) == 0 { - return - } - callback(data, selectedMime, mimesCopy) - }() - }) - - display.Roundtrip() - display.Roundtrip() - - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - if err := wlCtx.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { - return fmt.Errorf("set read deadline: %w", err) - } - if err := wlCtx.Dispatch(); err != nil { - if isTimeoutError(err) { - continue - } - return fmt.Errorf("dispatch: %w", err) - } - } - } -} - -func isTimeoutError(err error) bool { - if err == nil { - return false - } - if errors.Is(err, os.ErrDeadlineExceeded) { - return true - } - if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() { - return true - } - return false -} - -func WatchChan(ctx context.Context) (<-chan ClipboardChange, <-chan error) { - ch := make(chan ClipboardChange, 16) - errCh := make(chan error, 1) - - go func() { - defer close(ch) - err := Watch(ctx, func(data []byte, mimeType string) { - select { - case ch <- ClipboardChange{Data: data, MimeType: mimeType}: - default: - } - }) - if err != nil && err != context.Canceled { - errCh <- err - } - close(errCh) - }() - - time.Sleep(50 * time.Millisecond) - return ch, errCh -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/color.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/color.go deleted file mode 100644 index 461730a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/color.go +++ /dev/null @@ -1,306 +0,0 @@ -package colorpicker - -import ( - "encoding/json" - "fmt" - "math" - "strings" -) - -type Color struct { - R, G, B, A uint8 -} - -type OutputFormat int - -const ( - FormatHex OutputFormat = iota - FormatRGB - FormatHSL - FormatHSV - FormatCMYK -) - -func ParseFormat(s string) OutputFormat { - switch strings.ToLower(s) { - case "rgb": - return FormatRGB - case "hsl": - return FormatHSL - case "hsv": - return FormatHSV - case "cmyk": - return FormatCMYK - default: - return FormatHex - } -} - -func (c Color) ToHex(lowercase bool) string { - if lowercase { - return fmt.Sprintf("#%02x%02x%02x", c.R, c.G, c.B) - } - return fmt.Sprintf("#%02X%02X%02X", c.R, c.G, c.B) -} - -func (c Color) ToRGB() string { - return fmt.Sprintf("%d %d %d", c.R, c.G, c.B) -} - -func (c Color) ToHSL() string { - h, s, l := rgbToHSL(c.R, c.G, c.B) - return fmt.Sprintf("%d %d%% %d%%", h, s, l) -} - -func (c Color) ToHSV() string { - h, s, v := rgbToHSV(c.R, c.G, c.B) - return fmt.Sprintf("%d %d%% %d%%", h, s, v) -} - -func (c Color) ToCMYK() string { - cy, m, y, k := rgbToCMYK(c.R, c.G, c.B) - return fmt.Sprintf("%d%% %d%% %d%% %d%%", cy, m, y, k) -} - -func (c Color) Format(format OutputFormat, lowercase bool, customFmt string) string { - if customFmt != "" { - return c.formatCustom(format, customFmt) - } - - switch format { - case FormatRGB: - return c.ToRGB() - case FormatHSL: - return c.ToHSL() - case FormatHSV: - return c.ToHSV() - case FormatCMYK: - return c.ToCMYK() - default: - return c.ToHex(lowercase) - } -} - -func (c Color) formatCustom(format OutputFormat, customFmt string) string { - switch format { - case FormatRGB: - return replaceArgs(customFmt, c.R, c.G, c.B) - case FormatHSL: - h, s, l := rgbToHSL(c.R, c.G, c.B) - return replaceArgs(customFmt, h, s, l) - case FormatHSV: - h, s, v := rgbToHSV(c.R, c.G, c.B) - return replaceArgs(customFmt, h, s, v) - case FormatCMYK: - cy, m, y, k := rgbToCMYK(c.R, c.G, c.B) - return replaceArgs4(customFmt, cy, m, y, k) - default: - if strings.Contains(customFmt, "{0}") { - r := fmt.Sprintf("%02X", c.R) - g := fmt.Sprintf("%02X", c.G) - b := fmt.Sprintf("%02X", c.B) - return replaceArgsStr(customFmt, r, g, b) - } - return c.ToHex(false) - } -} - -func replaceArgs[T any](format string, a, b, c T) string { - result := format - result = strings.ReplaceAll(result, "{0}", fmt.Sprintf("%v", a)) - result = strings.ReplaceAll(result, "{1}", fmt.Sprintf("%v", b)) - result = strings.ReplaceAll(result, "{2}", fmt.Sprintf("%v", c)) - return result -} - -func replaceArgs4[T any](format string, a, b, c, d T) string { - result := format - result = strings.ReplaceAll(result, "{0}", fmt.Sprintf("%v", a)) - result = strings.ReplaceAll(result, "{1}", fmt.Sprintf("%v", b)) - result = strings.ReplaceAll(result, "{2}", fmt.Sprintf("%v", c)) - result = strings.ReplaceAll(result, "{3}", fmt.Sprintf("%v", d)) - return result -} - -func replaceArgsStr(format, a, b, c string) string { - result := format - result = strings.ReplaceAll(result, "{0}", a) - result = strings.ReplaceAll(result, "{1}", b) - result = strings.ReplaceAll(result, "{2}", c) - return result -} - -func rgbToHSL(r, g, b uint8) (int, int, int) { - rf := float64(r) / 255.0 - gf := float64(g) / 255.0 - bf := float64(b) / 255.0 - - maxVal := math.Max(rf, math.Max(gf, bf)) - minVal := math.Min(rf, math.Min(gf, bf)) - l := (maxVal + minVal) / 2 - - if maxVal == minVal { - return 0, 0, int(math.Round(l * 100)) - } - - d := maxVal - minVal - var s float64 - if l > 0.5 { - s = d / (2 - maxVal - minVal) - } else { - s = d / (maxVal + minVal) - } - - var h float64 - switch maxVal { - case rf: - h = (gf - bf) / d - if gf < bf { - h += 6 - } - case gf: - h = (bf-rf)/d + 2 - case bf: - h = (rf-gf)/d + 4 - } - h /= 6 - - return int(math.Round(h * 360)), int(math.Round(s * 100)), int(math.Round(l * 100)) -} - -func rgbToHSV(r, g, b uint8) (int, int, int) { - rf := float64(r) / 255.0 - gf := float64(g) / 255.0 - bf := float64(b) / 255.0 - - maxVal := math.Max(rf, math.Max(gf, bf)) - minVal := math.Min(rf, math.Min(gf, bf)) - v := maxVal - d := maxVal - minVal - - var s float64 - if maxVal != 0 { - s = d / maxVal - } - - if maxVal == minVal { - return 0, int(math.Round(s * 100)), int(math.Round(v * 100)) - } - - var h float64 - switch maxVal { - case rf: - h = (gf - bf) / d - if gf < bf { - h += 6 - } - case gf: - h = (bf-rf)/d + 2 - case bf: - h = (rf-gf)/d + 4 - } - h /= 6 - - return int(math.Round(h * 360)), int(math.Round(s * 100)), int(math.Round(v * 100)) -} - -func rgbToCMYK(r, g, b uint8) (int, int, int, int) { - if r == 0 && g == 0 && b == 0 { - return 0, 0, 0, 100 - } - - rf := float64(r) / 255.0 - gf := float64(g) / 255.0 - bf := float64(b) / 255.0 - - k := 1 - math.Max(rf, math.Max(gf, bf)) - c := (1 - rf - k) / (1 - k) - m := (1 - gf - k) / (1 - k) - y := (1 - bf - k) / (1 - k) - - return int(math.Round(c * 100)), int(math.Round(m * 100)), int(math.Round(y * 100)), int(math.Round(k * 100)) -} - -func (c Color) Luminance() float64 { - r := float64(c.R) / 255.0 - g := float64(c.G) / 255.0 - b := float64(c.B) / 255.0 - - if r <= 0.03928 { - r = r / 12.92 - } else { - r = math.Pow((r+0.055)/1.055, 2.4) - } - - if g <= 0.03928 { - g = g / 12.92 - } else { - g = math.Pow((g+0.055)/1.055, 2.4) - } - - if b <= 0.03928 { - b = b / 12.92 - } else { - b = math.Pow((b+0.055)/1.055, 2.4) - } - - return 0.2126*r + 0.7152*g + 0.0722*b -} - -func (c Color) IsDark() bool { - return c.Luminance() < 0.179 -} - -type ColorJSON struct { - Hex string `json:"hex"` - RGB struct { - R int `json:"r"` - G int `json:"g"` - B int `json:"b"` - } `json:"rgb"` - HSL struct { - H int `json:"h"` - S int `json:"s"` - L int `json:"l"` - } `json:"hsl"` - HSV struct { - H int `json:"h"` - S int `json:"s"` - V int `json:"v"` - } `json:"hsv"` - CMYK struct { - C int `json:"c"` - M int `json:"m"` - Y int `json:"y"` - K int `json:"k"` - } `json:"cmyk"` -} - -func (c Color) ToJSON() (string, error) { - h, s, l := rgbToHSL(c.R, c.G, c.B) - hv, sv, v := rgbToHSV(c.R, c.G, c.B) - cy, m, y, k := rgbToCMYK(c.R, c.G, c.B) - - data := ColorJSON{ - Hex: c.ToHex(false), - } - data.RGB.R = int(c.R) - data.RGB.G = int(c.G) - data.RGB.B = int(c.B) - data.HSL.H = h - data.HSL.S = s - data.HSL.L = l - data.HSV.H = hv - data.HSV.S = sv - data.HSV.V = v - data.CMYK.C = cy - data.CMYK.M = m - data.CMYK.Y = y - data.CMYK.K = k - - bytes, err := json.MarshalIndent(data, "", " ") - if err != nil { - return "", err - } - return string(bytes), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/picker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/picker.go deleted file mode 100644 index 688c381..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/picker.go +++ /dev/null @@ -1,744 +0,0 @@ -package colorpicker - -import ( - "fmt" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_layer_shell" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_screencopy" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wp_viewporter" - wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type Config struct { - Format OutputFormat - CustomFormat string - Lowercase bool - Autocopy bool - Notify bool -} - -type Output struct { - wlOutput *client.Output - name string - globalName uint32 - x, y int32 - width int32 - height int32 - scale int32 - fractionalScale float64 - transform int32 -} - -type LayerSurface struct { - output *Output - state *SurfaceState - wlSurface *client.Surface - layerSurf *wlr_layer_shell.ZwlrLayerSurfaceV1 - viewport *wp_viewporter.WpViewport - wlPools [2]*client.ShmPool - wlBuffers [2]*client.Buffer - slotBusy [2]bool - needsRedraw bool - scopyBuffer *client.Buffer - configured bool - hidden bool -} - -type Picker struct { - config Config - - display *client.Display - registry *client.Registry - ctx *client.Context - - compositor *client.Compositor - shm *client.Shm - seat *client.Seat - pointer *client.Pointer - keyboard *client.Keyboard - layerShell *wlr_layer_shell.ZwlrLayerShellV1 - screencopy *wlr_screencopy.ZwlrScreencopyManagerV1 - viewporter *wp_viewporter.WpViewporter - - shortcutsInhibitMgr *keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitManagerV1 - shortcutsInhibitor *keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitorV1 - - outputs map[uint32]*Output - outputsMu sync.Mutex - - surfaces []*LayerSurface - activeSurface *LayerSurface - - running bool - pickedColor *Color - err error -} - -func New(config Config) *Picker { - return &Picker{ - config: config, - outputs: make(map[uint32]*Output), - } -} - -func (p *Picker) Run() (*Color, error) { - if err := p.connect(); err != nil { - return nil, fmt.Errorf("wayland connect: %w", err) - } - defer p.cleanup() - - if err := p.setupRegistry(); err != nil { - return nil, fmt.Errorf("registry setup: %w", err) - } - - if err := p.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - if p.screencopy == nil { - return nil, fmt.Errorf("compositor does not support wlr-screencopy-unstable-v1") - } - - if p.layerShell == nil { - return nil, fmt.Errorf("compositor does not support wlr-layer-shell-unstable-v1") - } - - if p.seat == nil { - return nil, fmt.Errorf("no seat available") - } - - if err := p.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - // Extra roundtrip to ensure pointer/keyboard from seat capabilities are registered - if err := p.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip after seat: %w", err) - } - - if err := p.createSurfaces(); err != nil { - return nil, fmt.Errorf("create surfaces: %w", err) - } - - if err := p.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - p.running = true - for p.running { - if err := p.ctx.Dispatch(); err != nil { - p.err = err - break - } - - p.flushRedraws() - p.checkDone() - } - - if p.err != nil { - return nil, p.err - } - - return p.pickedColor, nil -} - -func (p *Picker) checkDone() { - for _, ls := range p.surfaces { - picked, cancelled := ls.state.IsDone() - switch { - case cancelled: - p.running = false - return - case picked: - color, ok := ls.state.PickColor() - if ok { - p.pickedColor = &color - } - p.running = false - return - } - } -} - -func (p *Picker) flushRedraws() { - for _, ls := range p.surfaces { - if !ls.needsRedraw { - continue - } - p.redrawSurface(ls) - } -} - -func (p *Picker) connect() error { - display, err := client.Connect("") - if err != nil { - return err - } - p.display = display - p.ctx = display.Context() - return nil -} - -func (p *Picker) roundtrip() error { - return wlhelpers.Roundtrip(p.display, p.ctx) -} - -func (p *Picker) setupRegistry() error { - registry, err := p.display.GetRegistry() - if err != nil { - return err - } - p.registry = registry - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - p.handleGlobal(e) - }) - - registry.SetGlobalRemoveHandler(func(e client.RegistryGlobalRemoveEvent) { - p.outputsMu.Lock() - delete(p.outputs, e.Name) - p.outputsMu.Unlock() - }) - - return nil -} - -func (p *Picker) handleGlobal(e client.RegistryGlobalEvent) { - switch e.Interface { - case client.CompositorInterfaceName: - compositor := client.NewCompositor(p.ctx) - if err := p.registry.Bind(e.Name, e.Interface, e.Version, compositor); err == nil { - p.compositor = compositor - } - - case client.ShmInterfaceName: - shm := client.NewShm(p.ctx) - if err := p.registry.Bind(e.Name, e.Interface, e.Version, shm); err == nil { - p.shm = shm - } - - case client.SeatInterfaceName: - seat := client.NewSeat(p.ctx) - if err := p.registry.Bind(e.Name, e.Interface, e.Version, seat); err == nil { - p.seat = seat - p.setupInput() - } - - case client.OutputInterfaceName: - output := client.NewOutput(p.ctx) - version := min(e.Version, 4) - if err := p.registry.Bind(e.Name, e.Interface, version, output); err == nil { - p.outputsMu.Lock() - p.outputs[e.Name] = &Output{ - wlOutput: output, - globalName: e.Name, - scale: 1, - fractionalScale: 1.0, - } - p.outputsMu.Unlock() - p.setupOutputHandlers(e.Name, output) - } - - case wlr_layer_shell.ZwlrLayerShellV1InterfaceName: - layerShell := wlr_layer_shell.NewZwlrLayerShellV1(p.ctx) - version := min(e.Version, 4) - if err := p.registry.Bind(e.Name, e.Interface, version, layerShell); err == nil { - p.layerShell = layerShell - } - - case wlr_screencopy.ZwlrScreencopyManagerV1InterfaceName: - screencopy := wlr_screencopy.NewZwlrScreencopyManagerV1(p.ctx) - version := min(e.Version, 3) - if err := p.registry.Bind(e.Name, e.Interface, version, screencopy); err == nil { - p.screencopy = screencopy - } - - case wp_viewporter.WpViewporterInterfaceName: - viewporter := wp_viewporter.NewWpViewporter(p.ctx) - if err := p.registry.Bind(e.Name, e.Interface, e.Version, viewporter); err == nil { - p.viewporter = viewporter - } - - case keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitManagerV1InterfaceName: - mgr := keyboard_shortcuts_inhibit.NewZwpKeyboardShortcutsInhibitManagerV1(p.ctx) - if err := p.registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil { - p.shortcutsInhibitMgr = mgr - } - } -} - -func (p *Picker) setupOutputHandlers(name uint32, output *client.Output) { - output.SetGeometryHandler(func(e client.OutputGeometryEvent) { - p.outputsMu.Lock() - if o, ok := p.outputs[name]; ok { - o.x = e.X - o.y = e.Y - o.transform = int32(e.Transform) - } - p.outputsMu.Unlock() - }) - - output.SetModeHandler(func(e client.OutputModeEvent) { - if e.Flags&uint32(client.OutputModeCurrent) == 0 { - return - } - p.outputsMu.Lock() - if o, ok := p.outputs[name]; ok { - o.width = e.Width - o.height = e.Height - } - p.outputsMu.Unlock() - }) - - output.SetScaleHandler(func(e client.OutputScaleEvent) { - p.outputsMu.Lock() - if o, ok := p.outputs[name]; ok { - o.scale = e.Factor - o.fractionalScale = float64(e.Factor) - } - p.outputsMu.Unlock() - }) - - output.SetNameHandler(func(e client.OutputNameEvent) { - p.outputsMu.Lock() - if o, ok := p.outputs[name]; ok { - o.name = e.Name - } - p.outputsMu.Unlock() - }) -} - -func (p *Picker) createSurfaces() error { - p.outputsMu.Lock() - outputs := make([]*Output, 0, len(p.outputs)) - for _, o := range p.outputs { - outputs = append(outputs, o) - } - p.outputsMu.Unlock() - - for _, output := range outputs { - ls, err := p.createLayerSurface(output) - if err != nil { - return fmt.Errorf("output %s: %w", output.name, err) - } - p.surfaces = append(p.surfaces, ls) - } - - return nil -} - -func (p *Picker) createLayerSurface(output *Output) (*LayerSurface, error) { - surface, err := p.compositor.CreateSurface() - if err != nil { - return nil, fmt.Errorf("create surface: %w", err) - } - - layerSurf, err := p.layerShell.GetLayerSurface( - surface, - output.wlOutput, - uint32(wlr_layer_shell.ZwlrLayerShellV1LayerOverlay), - "dms-colorpicker", - ) - if err != nil { - return nil, fmt.Errorf("get layer surface: %w", err) - } - - ls := &LayerSurface{ - output: output, - state: NewSurfaceState(p.config.Format, p.config.Lowercase), - wlSurface: surface, - layerSurf: layerSurf, - hidden: true, // Start hidden, will show overlay when pointer enters - } - - if p.viewporter != nil { - vp, err := p.viewporter.GetViewport(surface) - if err == nil { - ls.viewport = vp - } - } - - if err := layerSurf.SetAnchor( - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorTop) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorBottom) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorLeft) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorRight), - ); err != nil { - log.Warn("failed to set layer anchor", "err", err) - } - if err := layerSurf.SetExclusiveZone(-1); err != nil { - log.Warn("failed to set exclusive zone", "err", err) - } - if err := layerSurf.SetKeyboardInteractivity(uint32(wlr_layer_shell.ZwlrLayerSurfaceV1KeyboardInteractivityExclusive)); err != nil { - log.Warn("failed to set keyboard interactivity", "err", err) - } - - layerSurf.SetConfigureHandler(func(e wlr_layer_shell.ZwlrLayerSurfaceV1ConfigureEvent) { - if err := layerSurf.AckConfigure(e.Serial); err != nil { - log.Warn("failed to ack configure", "err", err) - } - if err := ls.state.OnLayerConfigure(int(e.Width), int(e.Height)); err != nil { - log.Warn("failed to handle layer configure", "err", err) - } - ls.configured = true - - scale := p.computeSurfaceScale(ls) - ls.state.SetScale(scale) - - if !ls.state.IsReady() { - p.captureForSurface(ls) - } else { - p.redrawSurface(ls) - } - - // Request shortcut inhibition once surface is configured - p.ensureShortcutsInhibitor(ls) - }) - - layerSurf.SetClosedHandler(func(e wlr_layer_shell.ZwlrLayerSurfaceV1ClosedEvent) { - p.running = false - }) - - if err := surface.Commit(); err != nil { - log.Warn("failed to commit surface", "err", err) - } - return ls, nil -} - -func (p *Picker) computeSurfaceScale(ls *LayerSurface) int32 { - out := ls.output - if out == nil || out.scale <= 0 { - return 1 - } - return out.scale -} - -func (p *Picker) ensureShortcutsInhibitor(ls *LayerSurface) { - if p.shortcutsInhibitMgr == nil || p.seat == nil || p.shortcutsInhibitor != nil { - return - } - - inhibitor, err := p.shortcutsInhibitMgr.InhibitShortcuts(ls.wlSurface, p.seat) - if err != nil { - log.Debug("failed to create shortcuts inhibitor", "err", err) - return - } - - p.shortcutsInhibitor = inhibitor - - inhibitor.SetActiveHandler(func(e keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitorV1ActiveEvent) { - log.Debug("shortcuts inhibitor active") - }) - - inhibitor.SetInactiveHandler(func(e keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitorV1InactiveEvent) { - log.Debug("shortcuts inhibitor deactivated by compositor") - }) -} - -func (p *Picker) captureForSurface(ls *LayerSurface) { - frame, err := p.screencopy.CaptureOutput(0, ls.output.wlOutput) - if err != nil { - return - } - - frame.SetBufferHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferEvent) { - if err := ls.state.OnScreencopyBuffer(PixelFormat(e.Format), int(e.Width), int(e.Height), int(e.Stride)); err != nil { - log.Error("failed to create screencopy buffer", "err", err) - } - }) - - frame.SetBufferDoneHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferDoneEvent) { - screenBuf := ls.state.ScreenBuffer() - if screenBuf == nil { - return - } - - pool, err := p.shm.CreatePool(screenBuf.Fd(), int32(screenBuf.Size())) - if err != nil { - return - } - - wlBuffer, err := pool.CreateBuffer(0, int32(screenBuf.Width), int32(screenBuf.Height), int32(screenBuf.Stride), uint32(ls.state.screenFormat)) - if err != nil { - pool.Destroy() - return - } - - if ls.scopyBuffer != nil { - ls.scopyBuffer.Destroy() - } - ls.scopyBuffer = wlBuffer - wlBuffer.SetReleaseHandler(func(e client.BufferReleaseEvent) {}) - - if err := frame.Copy(wlBuffer); err != nil { - log.Error("failed to copy frame", "err", err) - } - pool.Destroy() - }) - - frame.SetFlagsHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FlagsEvent) { - ls.state.OnScreencopyFlags(e.Flags) - }) - - frame.SetReadyHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1ReadyEvent) { - ls.state.OnScreencopyReady() - - screenBuf := ls.state.ScreenBuffer() - if screenBuf != nil && ls.output.transform != TransformNormal { - invTransform := InverseTransform(ls.output.transform) - transformed, err := screenBuf.ApplyTransform(invTransform) - if err != nil { - log.Error("apply transform failed", "err", err) - } else if transformed != screenBuf { - ls.state.ReplaceScreenBuffer(transformed) - } - } - - logicalW, _ := ls.state.LogicalSize() - screenBuf = ls.state.ScreenBuffer() - if logicalW > 0 && screenBuf != nil { - ls.output.fractionalScale = float64(screenBuf.Width) / float64(logicalW) - } - - scale := p.computeSurfaceScale(ls) - ls.state.SetScale(scale) - frame.Destroy() - p.redrawSurface(ls) - }) - - frame.SetFailedHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FailedEvent) { - frame.Destroy() - }) -} - -func (p *Picker) redrawSurface(ls *LayerSurface) { - slot := ls.state.FrontIndex() - if ls.slotBusy[slot] { - ls.needsRedraw = true - return - } - - var renderBuf *ShmBuffer - switch { - case ls.hidden: - renderBuf = ls.state.RedrawScreenOnly() - default: - renderBuf = ls.state.Redraw() - } - if renderBuf == nil { - return - } - - ls.needsRedraw = false - - if ls.wlPools[slot] == nil { - pool, err := p.shm.CreatePool(renderBuf.Fd(), int32(renderBuf.Size())) - if err != nil { - return - } - ls.wlPools[slot] = pool - - wlBuffer, err := pool.CreateBuffer(0, int32(renderBuf.Width), int32(renderBuf.Height), int32(renderBuf.Stride), uint32(ls.state.ScreenFormat())) - if err != nil { - return - } - ls.wlBuffers[slot] = wlBuffer - - s := slot - wlBuffer.SetReleaseHandler(func(e client.BufferReleaseEvent) { - ls.slotBusy[s] = false - }) - } - - ls.slotBusy[slot] = true - - logicalW, logicalH := ls.state.LogicalSize() - if logicalW == 0 || logicalH == 0 { - logicalW = int(ls.output.width) - logicalH = int(ls.output.height) - } - - if ls.viewport != nil { - _ = ls.wlSurface.SetBufferScale(1) - _ = ls.viewport.SetSource(0, 0, float64(renderBuf.Width), float64(renderBuf.Height)) - _ = ls.viewport.SetDestination(int32(logicalW), int32(logicalH)) - } else { - bufferScale := ls.output.scale - if bufferScale <= 0 { - bufferScale = 1 - } - _ = ls.wlSurface.SetBufferScale(bufferScale) - } - _ = ls.wlSurface.Attach(ls.wlBuffers[slot], 0, 0) - _ = ls.wlSurface.Damage(0, 0, int32(logicalW), int32(logicalH)) - _ = ls.wlSurface.Commit() - - ls.state.SwapBuffers() -} - -func (p *Picker) hideSurface(ls *LayerSurface) { - if ls == nil || ls.wlSurface == nil || ls.hidden { - return - } - ls.hidden = true - // Redraw without the crosshair overlay - p.redrawSurface(ls) -} - -func (p *Picker) setupInput() { - if p.seat == nil { - return - } - - p.seat.SetCapabilitiesHandler(func(e client.SeatCapabilitiesEvent) { - if e.Capabilities&uint32(client.SeatCapabilityPointer) != 0 && p.pointer == nil { - pointer, err := p.seat.GetPointer() - if err != nil { - return - } - p.pointer = pointer - p.setupPointerHandlers() - } - if e.Capabilities&uint32(client.SeatCapabilityKeyboard) != 0 && p.keyboard == nil { - keyboard, err := p.seat.GetKeyboard() - if err != nil { - return - } - p.keyboard = keyboard - p.setupKeyboardHandlers() - } - }) -} - -func (p *Picker) setupPointerHandlers() { - p.pointer.SetEnterHandler(func(e client.PointerEnterEvent) { - if err := p.pointer.SetCursor(e.Serial, nil, 0, 0); err != nil { - log.Debug("failed to hide cursor", "err", err) - } - - if e.Surface == nil { - return - } - - p.activeSurface = nil - surfaceID := e.Surface.ID() - for _, ls := range p.surfaces { - if ls.wlSurface.ID() == surfaceID { - p.activeSurface = ls - break - } - } - if p.activeSurface == nil { - return - } - - if p.activeSurface.hidden { - p.activeSurface.hidden = false - } - - p.activeSurface.state.OnPointerMotion(e.SurfaceX, e.SurfaceY) - p.activeSurface.needsRedraw = true - }) - - p.pointer.SetLeaveHandler(func(e client.PointerLeaveEvent) { - if e.Surface == nil { - return - } - surfaceID := e.Surface.ID() - for _, ls := range p.surfaces { - if ls.wlSurface.ID() == surfaceID { - p.hideSurface(ls) - break - } - } - }) - - p.pointer.SetMotionHandler(func(e client.PointerMotionEvent) { - if p.activeSurface == nil { - return - } - p.activeSurface.state.OnPointerMotion(e.SurfaceX, e.SurfaceY) - p.activeSurface.needsRedraw = true - }) - - p.pointer.SetButtonHandler(func(e client.PointerButtonEvent) { - if p.activeSurface == nil { - return - } - p.activeSurface.state.OnPointerButton(e.Button, e.State) - }) -} - -func (p *Picker) setupKeyboardHandlers() { - p.keyboard.SetKeyHandler(func(e client.KeyboardKeyEvent) { - for _, ls := range p.surfaces { - ls.state.OnKey(e.Key, e.State) - } - }) -} - -func (p *Picker) cleanup() { - for _, ls := range p.surfaces { - if ls.scopyBuffer != nil { - ls.scopyBuffer.Destroy() - } - for i := range ls.wlBuffers { - if ls.wlBuffers[i] != nil { - ls.wlBuffers[i].Destroy() - } - if ls.wlPools[i] != nil { - ls.wlPools[i].Destroy() - } - } - if ls.viewport != nil { - ls.viewport.Destroy() - } - if ls.layerSurf != nil { - ls.layerSurf.Destroy() - } - if ls.wlSurface != nil { - ls.wlSurface.Destroy() - } - if ls.state != nil { - ls.state.Destroy() - } - } - - if p.shortcutsInhibitor != nil { - if err := p.shortcutsInhibitor.Destroy(); err != nil { - log.Debug("failed to destroy shortcuts inhibitor", "err", err) - } - p.shortcutsInhibitor = nil - } - - if p.shortcutsInhibitMgr != nil { - if err := p.shortcutsInhibitMgr.Destroy(); err != nil { - log.Debug("failed to destroy shortcuts inhibit manager", "err", err) - } - p.shortcutsInhibitMgr = nil - } - - if p.viewporter != nil { - p.viewporter.Destroy() - } - - if p.screencopy != nil { - p.screencopy.Destroy() - } - - if p.pointer != nil { - p.pointer.Release() - } - - if p.keyboard != nil { - p.keyboard.Release() - } - - if p.display != nil { - p.ctx.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/shm.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/shm.go deleted file mode 100644 index 6ee9dc0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/shm.go +++ /dev/null @@ -1,55 +0,0 @@ -package colorpicker - -import "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/shm" - -type ShmBuffer = shm.Buffer - -const ( - TransformNormal = shm.TransformNormal - Transform90 = shm.Transform90 - Transform180 = shm.Transform180 - Transform270 = shm.Transform270 - TransformFlipped = shm.TransformFlipped - TransformFlipped90 = shm.TransformFlipped90 - TransformFlipped180 = shm.TransformFlipped180 - TransformFlipped270 = shm.TransformFlipped270 -) - -func CreateShmBuffer(width, height, stride int) (*ShmBuffer, error) { - return shm.CreateBuffer(width, height, stride) -} - -func InverseTransform(transform int32) int32 { - return shm.InverseTransform(transform) -} - -func GetPixelColor(buf *ShmBuffer, x, y int) Color { - return GetPixelColorWithFormat(buf, x, y, FormatARGB8888) -} - -func GetPixelColorWithFormat(buf *ShmBuffer, x, y int, format PixelFormat) Color { - if x < 0 || x >= buf.Width || y < 0 || y >= buf.Height { - return Color{} - } - - data := buf.Data() - offset := y*buf.Stride + x*4 - if offset+3 >= len(data) { - return Color{} - } - - if format == FormatABGR8888 || format == FormatXBGR8888 { - return Color{ - R: data[offset], - G: data[offset+1], - B: data[offset+2], - A: data[offset+3], - } - } - return Color{ - B: data[offset], - G: data[offset+1], - R: data[offset+2], - A: data[offset+3], - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state.go deleted file mode 100644 index f518a5b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state.go +++ /dev/null @@ -1,1195 +0,0 @@ -package colorpicker - -import ( - "fmt" - "math" - "strings" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/shm" -) - -type PixelFormat = shm.PixelFormat - -const ( - FormatARGB8888 = shm.FormatARGB8888 - FormatXRGB8888 = shm.FormatXRGB8888 - FormatABGR8888 = shm.FormatABGR8888 - FormatXBGR8888 = shm.FormatXBGR8888 - FormatRGB888 = shm.FormatRGB888 - FormatBGR888 = shm.FormatBGR888 -) - -type SurfaceState struct { - mu sync.Mutex - - screenBuf *ShmBuffer - screenFormat PixelFormat - yInverted bool - - logicalW int - logicalH int - - renderBufs [2]*ShmBuffer - front int - - scale int32 - scaleX float64 - scaleY float64 - - pointerX int - pointerY int - - displayFormat OutputFormat - lowercase bool - - readyForDisplay bool - colorPicked bool - cancelled bool -} - -func NewSurfaceState(format OutputFormat, lowercase bool) *SurfaceState { - return &SurfaceState{ - scale: 1, - displayFormat: format, - lowercase: lowercase, - } -} - -func (s *SurfaceState) SetScale(scale int32) { - s.mu.Lock() - defer s.mu.Unlock() - - if scale <= 0 { - scale = 1 - } - s.scale = scale -} - -func (s *SurfaceState) Scale() int32 { - s.mu.Lock() - defer s.mu.Unlock() - return s.scale -} - -func (s *SurfaceState) LogicalSize() (int, int) { - s.mu.Lock() - defer s.mu.Unlock() - return s.logicalW, s.logicalH -} - -func (s *SurfaceState) OnScreencopyBuffer(format PixelFormat, width, height, stride int) error { - s.mu.Lock() - defer s.mu.Unlock() - - bpp := format.BytesPerPixel() - if stride < width*bpp { - return fmt.Errorf("invalid stride %d for width %d (bpp=%d)", stride, width, bpp) - } - - if s.screenBuf != nil { - s.screenBuf.Close() - s.screenBuf = nil - } - - buf, err := CreateShmBuffer(width, height, stride) - if err != nil { - return err - } - - s.screenBuf = buf - s.screenBuf.Format = format - s.screenFormat = format - return nil -} - -func (s *SurfaceState) ScreenBuffer() *ShmBuffer { - s.mu.Lock() - defer s.mu.Unlock() - return s.screenBuf -} - -func (s *SurfaceState) ScreenFormat() PixelFormat { - s.mu.Lock() - defer s.mu.Unlock() - return s.screenFormat -} - -func (s *SurfaceState) ReplaceScreenBuffer(newBuf *ShmBuffer) { - s.mu.Lock() - defer s.mu.Unlock() - - if s.screenBuf != nil { - s.screenBuf.Close() - } - s.screenBuf = newBuf - s.screenFormat = newBuf.Format - - s.recomputeScale() - s.ensureRenderBuffers() -} - -func (s *SurfaceState) OnScreencopyFlags(flags uint32) { - s.mu.Lock() - s.yInverted = (flags & 1) != 0 - s.mu.Unlock() -} - -func (s *SurfaceState) OnScreencopyReady() { - s.mu.Lock() - defer s.mu.Unlock() - - if s.screenBuf == nil || s.logicalW == 0 || s.logicalH == 0 { - return - } - - if s.screenFormat.Is24Bit() { - converted, newFormat, err := s.screenBuf.ConvertTo32Bit(s.screenFormat) - if err == nil && converted != s.screenBuf { - s.screenBuf.Close() - s.screenBuf = converted - s.screenFormat = newFormat - } - } - - s.recomputeScale() - s.ensureRenderBuffers() - s.readyForDisplay = true -} - -func (s *SurfaceState) OnLayerConfigure(width, height int) error { - s.mu.Lock() - defer s.mu.Unlock() - - if width <= 0 || height <= 0 { - return nil - } - - if s.logicalW == width && s.logicalH == height { - return nil - } - - s.logicalW = width - s.logicalH = height - - s.recomputeScale() - s.ensureRenderBuffers() - - return nil -} - -func (s *SurfaceState) recomputeScale() { - if s.screenBuf == nil || s.logicalW == 0 || s.logicalH == 0 { - s.scaleX = 1 - s.scaleY = 1 - return - } - s.scaleX = float64(s.screenBuf.Width) / float64(s.logicalW) - s.scaleY = float64(s.screenBuf.Height) / float64(s.logicalH) -} - -func (s *SurfaceState) ensureRenderBuffers() { - if s.screenBuf == nil { - return - } - - width := s.screenBuf.Width - height := s.screenBuf.Height - stride := s.screenBuf.Stride - - for i := range s.renderBufs { - buf := s.renderBufs[i] - if buf != nil { - if buf.Width == width && buf.Height == height && buf.Stride == stride { - continue - } - buf.Close() - s.renderBufs[i] = nil - } - - newBuf, err := CreateShmBuffer(width, height, stride) - if err != nil { - continue - } - s.renderBufs[i] = newBuf - } -} - -func (s *SurfaceState) OnPointerMotion(x, y float64) { - s.mu.Lock() - s.pointerX = int(x) - s.pointerY = int(y) - s.mu.Unlock() -} - -func (s *SurfaceState) OnPointerButton(button, state uint32) { - if state != 1 { - return - } - - s.mu.Lock() - defer s.mu.Unlock() - - switch button { - case 0x110: // BTN_LEFT - if s.readyForDisplay && s.screenBuf != nil { - s.colorPicked = true - } - } -} - -func (s *SurfaceState) OnKey(key, state uint32) { - if state != 1 { - return - } - - s.mu.Lock() - defer s.mu.Unlock() - - switch key { - case 1: // KEY_ESC - s.cancelled = true - case 28: // KEY_ENTER - if s.readyForDisplay && s.screenBuf != nil { - s.colorPicked = true - } - } -} - -func (s *SurfaceState) IsDone() (picked, cancelled bool) { - s.mu.Lock() - defer s.mu.Unlock() - return s.colorPicked, s.cancelled -} - -func (s *SurfaceState) IsReady() bool { - s.mu.Lock() - defer s.mu.Unlock() - return s.readyForDisplay -} - -func (s *SurfaceState) FrontRenderBuffer() *ShmBuffer { - s.mu.Lock() - defer s.mu.Unlock() - return s.renderBufs[s.front] -} - -func (s *SurfaceState) FrontIndex() int { - s.mu.Lock() - defer s.mu.Unlock() - return s.front -} - -func (s *SurfaceState) SwapBuffers() { - s.mu.Lock() - s.front ^= 1 - s.mu.Unlock() -} - -func (s *SurfaceState) Redraw() *ShmBuffer { - s.mu.Lock() - defer s.mu.Unlock() - - if !s.readyForDisplay || s.screenBuf == nil { - return nil - } - - dst := s.renderBufs[s.front] - if dst == nil { - return nil - } - - dst.CopyFrom(s.screenBuf) - - px := int(math.Round(float64(s.pointerX) * s.scaleX)) - py := int(math.Round(float64(s.pointerY) * s.scaleY)) - - px = clamp(px, 0, dst.Width-1) - py = clamp(py, 0, dst.Height-1) - - sampleY := py - if s.yInverted { - sampleY = s.screenBuf.Height - 1 - py - } - - picked := GetPixelColorWithFormat(s.screenBuf, px, sampleY, s.screenFormat) - - drawMagnifierWithInversion( - dst.Data(), dst.Stride, dst.Width, dst.Height, - s.screenBuf.Data(), s.screenBuf.Stride, s.screenBuf.Width, s.screenBuf.Height, - px, py, picked, s.yInverted, s.screenFormat, - ) - - drawColorPreview(dst.Data(), dst.Stride, dst.Width, dst.Height, px, py, picked, s.displayFormat, s.lowercase, s.screenFormat) - - return dst -} - -// RedrawScreenOnly renders just the screenshot without any overlay (magnifier, preview). -// Used for when pointer leaves the surface. -func (s *SurfaceState) RedrawScreenOnly() *ShmBuffer { - s.mu.Lock() - defer s.mu.Unlock() - - if !s.readyForDisplay || s.screenBuf == nil { - return nil - } - - dst := s.renderBufs[s.front] - if dst == nil { - return nil - } - - dst.CopyFrom(s.screenBuf) - return dst -} - -func (s *SurfaceState) PickColor() (Color, bool) { - s.mu.Lock() - defer s.mu.Unlock() - - if s.screenBuf == nil { - return Color{}, false - } - - sx := int(math.Round(float64(s.pointerX) * s.scaleX)) - sy := int(math.Round(float64(s.pointerY) * s.scaleY)) - - sx = clamp(sx, 0, s.screenBuf.Width-1) - sy = clamp(sy, 0, s.screenBuf.Height-1) - - if s.yInverted { - sy = s.screenBuf.Height - 1 - sy - } - - return GetPixelColorWithFormat(s.screenBuf, sx, sy, s.screenFormat), true -} - -func (s *SurfaceState) Destroy() { - s.mu.Lock() - defer s.mu.Unlock() - - if s.screenBuf != nil { - s.screenBuf.Close() - s.screenBuf = nil - } - - for i := range s.renderBufs { - if s.renderBufs[i] != nil { - s.renderBufs[i].Close() - s.renderBufs[i] = nil - } - } -} - -func clamp(v, lo, hi int) int { - switch { - case v < lo: - return lo - case v > hi: - return hi - default: - return v - } -} - -func clampF(v, lo, hi float64) float64 { - switch { - case v < lo: - return lo - case v > hi: - return hi - default: - return v - } -} - -func abs(v int) int { - if v < 0 { - return -v - } - return v -} - -func blendColors(bg, fg Color, alpha float64) Color { - alpha = clampF(alpha, 0, 1) - invAlpha := 1.0 - alpha - return Color{ - R: uint8(clampF(float64(bg.R)*invAlpha+float64(fg.R)*alpha, 0, 255)), - G: uint8(clampF(float64(bg.G)*invAlpha+float64(fg.G)*alpha, 0, 255)), - B: uint8(clampF(float64(bg.B)*invAlpha+float64(fg.B)*alpha, 0, 255)), - A: 255, - } -} - -func drawMagnifierWithInversion( - dst []byte, dstStride, dstW, dstH int, - src []byte, srcStride, srcW, srcH int, - cx, cy int, - borderColor Color, - yInverted bool, - format PixelFormat, -) { - if dstW <= 0 || dstH <= 0 || srcW <= 0 || srcH <= 0 { - return - } - - const ( - outerRadius = 80 - borderThickness = 4 - aaWidth = 1.5 - zoom = 8.0 - crossThickness = 2 - crossInnerRadius = 8 - ) - - innerRadius := float64(outerRadius - borderThickness) - outerRadiusF := float64(outerRadius) - - var rOff, bOff int - switch format { - case FormatABGR8888, FormatXBGR8888: - rOff, bOff = 0, 2 - default: - rOff, bOff = 2, 0 - } - - for dy := -outerRadius - 2; dy <= outerRadius+2; dy++ { - y := cy + dy - if y < 0 || y >= dstH { - continue - } - dstRowOff := y * dstStride - - for dx := -outerRadius - 2; dx <= outerRadius+2; dx++ { - x := cx + dx - if x < 0 || x >= dstW { - continue - } - - dist := math.Sqrt(float64(dx*dx + dy*dy)) - if dist > outerRadiusF+aaWidth { - continue - } - - dstOff := dstRowOff + x*4 - if dstOff+4 > len(dst) { - continue - } - - bgColor := Color{ - R: dst[dstOff+rOff], - G: dst[dstOff+1], - B: dst[dstOff+bOff], - A: dst[dstOff+3], - } - - var finalColor Color - - switch { - case dist > outerRadiusF: - alpha := clampF(1.0-(dist-outerRadiusF)/aaWidth, 0, 1) - finalColor = blendColors(bgColor, borderColor, alpha) - - case dist > innerRadius: - switch { - case dist > outerRadiusF-aaWidth: - alpha := clampF((outerRadiusF-dist)/aaWidth, 0, 1) - finalColor = blendColors(borderColor, borderColor, alpha) - case dist < innerRadius+aaWidth: - alpha := clampF((dist-innerRadius)/aaWidth, 0, 1) - fx := float64(dx) / zoom - fy := float64(dy) / zoom - sx := cx + int(math.Round(fx)) - sy := cy + int(math.Round(fy)) - sx = clamp(sx, 0, srcW-1) - sy = clamp(sy, 0, srcH-1) - if yInverted { - sy = srcH - 1 - sy - } - srcOff := sy*srcStride + sx*4 - if srcOff+4 <= len(src) { - magColor := Color{R: src[srcOff+rOff], G: src[srcOff+1], B: src[srcOff+bOff], A: 255} - finalColor = blendColors(magColor, borderColor, alpha) - } else { - finalColor = borderColor - } - default: - finalColor = borderColor - } - - default: - fx := float64(dx) / zoom - fy := float64(dy) / zoom - sx := cx + int(math.Round(fx)) - sy := cy + int(math.Round(fy)) - sx = clamp(sx, 0, srcW-1) - sy = clamp(sy, 0, srcH-1) - if yInverted { - sy = srcH - 1 - sy - } - srcOff := sy*srcStride + sx*4 - if srcOff+4 <= len(src) { - finalColor = Color{R: src[srcOff+rOff], G: src[srcOff+1], B: src[srcOff+bOff], A: 255} - } else { - continue - } - } - - dst[dstOff+rOff] = finalColor.R - dst[dstOff+1] = finalColor.G - dst[dstOff+bOff] = finalColor.B - dst[dstOff+3] = 255 - } - } - - drawMagnifierCrosshair(dst, dstStride, dstW, dstH, cx, cy, int(innerRadius), crossThickness, crossInnerRadius, format) -} - -func drawMagnifierCrosshair( - data []byte, stride, width, height, cx, cy, radius, thickness, innerRadius int, - format PixelFormat, -) { - if width <= 0 || height <= 0 { - return - } - - cx = clamp(cx, 0, width-1) - cy = clamp(cy, 0, height-1) - - innerR2 := innerRadius * innerRadius - - for dy := -radius; dy <= radius; dy++ { - y := cy + dy - if y < 0 || y >= height { - continue - } - rowOff := y * stride - - for dx := -radius; dx <= radius; dx++ { - x := cx + dx - if x < 0 || x >= width { - continue - } - - dist2 := dx*dx + dy*dy - if dist2 > innerR2 { - continue - } - - absX := abs(dx) - absY := abs(dy) - if absX > thickness && absY > thickness { - continue - } - - off := rowOff + x*4 - if off+4 > len(data) { - continue - } - - isOutline := absX == thickness || absY == thickness - if isOutline { - data[off+0] = 0 - data[off+1] = 0 - data[off+2] = 0 - data[off+3] = 255 - } else { - data[off+0] = 255 - data[off+1] = 255 - data[off+2] = 255 - data[off+3] = 255 - } - } - } -} - -const ( - fontW = 8 - fontH = 12 -) - -var fontGlyphs = map[rune][fontH]uint8{ - '0': { - 0b00111100, - 0b01100110, - 0b01100110, - 0b01101110, - 0b01110110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - '1': { - 0b00011000, - 0b00111000, - 0b01111000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b01111110, - 0b00000000, - 0b00000000, - }, - '2': { - 0b00111100, - 0b01100110, - 0b01100110, - 0b00000110, - 0b00001100, - 0b00011000, - 0b00110000, - 0b01100000, - 0b01100110, - 0b01111110, - 0b00000000, - 0b00000000, - }, - '3': { - 0b00111100, - 0b01100110, - 0b00000110, - 0b00000110, - 0b00011100, - 0b00000110, - 0b00000110, - 0b00000110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - '4': { - 0b00001100, - 0b00011100, - 0b00111100, - 0b01101100, - 0b11001100, - 0b11001100, - 0b11111110, - 0b00001100, - 0b00001100, - 0b00011110, - 0b00000000, - 0b00000000, - }, - '5': { - 0b01111110, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01111100, - 0b00000110, - 0b00000110, - 0b00000110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - '6': { - 0b00011100, - 0b00110000, - 0b01100000, - 0b01100000, - 0b01111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - '7': { - 0b01111110, - 0b01100110, - 0b00000110, - 0b00000110, - 0b00001100, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00000000, - 0b00000000, - }, - '8': { - 0b00111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - '9': { - 0b00111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111110, - 0b00000110, - 0b00000110, - 0b00000110, - 0b00001100, - 0b00111000, - 0b00000000, - 0b00000000, - }, - 'A': { - 0b00011000, - 0b00111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01111110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00000000, - 0b00000000, - }, - 'B': { - 0b01111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01111100, - 0b00000000, - 0b00000000, - }, - 'C': { - 0b00111100, - 0b01100110, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - 'D': { - 0b01111000, - 0b01101100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01101100, - 0b01111000, - 0b00000000, - 0b00000000, - }, - 'E': { - 0b01111110, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01111100, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01111110, - 0b00000000, - 0b00000000, - }, - 'F': { - 0b01111110, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01111100, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b00000000, - 0b00000000, - }, - '#': { - 0b00000000, - 0b00100100, - 0b00100100, - 0b01111110, - 0b00100100, - 0b00100100, - 0b01111110, - 0b00100100, - 0b00100100, - 0b00000000, - 0b00000000, - 0b00000000, - }, - 'G': { - 0b00111100, - 0b01100110, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01101110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - 'H': { - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01111110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00000000, - 0b00000000, - }, - 'K': { - 0b01100110, - 0b01100110, - 0b01101100, - 0b01111000, - 0b01110000, - 0b01111000, - 0b01101100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00000000, - 0b00000000, - }, - 'L': { - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01100000, - 0b01111110, - 0b00000000, - 0b00000000, - }, - 'M': { - 0b01100011, - 0b01110111, - 0b01111111, - 0b01101011, - 0b01100011, - 0b01100011, - 0b01100011, - 0b01100011, - 0b01100011, - 0b01100011, - 0b00000000, - 0b00000000, - }, - 'R': { - 0b01111100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01111100, - 0b01111000, - 0b01101100, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00000000, - 0b00000000, - }, - 'S': { - 0b00111100, - 0b01100110, - 0b01100000, - 0b01100000, - 0b00111100, - 0b00000110, - 0b00000110, - 0b00000110, - 0b01100110, - 0b00111100, - 0b00000000, - 0b00000000, - }, - 'V': { - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00011000, - 0b00011000, - 0b00000000, - 0b00000000, - }, - 'Y': { - 0b01100110, - 0b01100110, - 0b01100110, - 0b01100110, - 0b00111100, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00000000, - 0b00000000, - }, - '(': { - 0b00001100, - 0b00011000, - 0b00110000, - 0b00110000, - 0b00110000, - 0b00110000, - 0b00110000, - 0b00110000, - 0b00011000, - 0b00001100, - 0b00000000, - 0b00000000, - }, - ')': { - 0b00110000, - 0b00011000, - 0b00001100, - 0b00001100, - 0b00001100, - 0b00001100, - 0b00001100, - 0b00001100, - 0b00011000, - 0b00110000, - 0b00000000, - 0b00000000, - }, - ',': { - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00011000, - 0b00011000, - 0b00110000, - 0b00000000, - 0b00000000, - }, - '%': { - 0b01100010, - 0b01100110, - 0b00001100, - 0b00001100, - 0b00011000, - 0b00011000, - 0b00110000, - 0b00110000, - 0b01100110, - 0b01000110, - 0b00000000, - 0b00000000, - }, - ' ': { - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - }, -} - -func drawColorPreview(data []byte, stride, width, height int, cx, cy int, c Color, format OutputFormat, lowercase bool, pixelFormat PixelFormat) { - text := formatColorForPreview(c, format, lowercase) - if len(text) == 0 { - return - } - - const ( - paddingX = 8 - paddingY = 4 - space = 2 - offset = 88 - ) - - textW := len(text)*(fontW+space) - space - textH := fontH - - boxW := textW + paddingX*2 - boxH := textH + paddingY*2 - - x := cx + offset - y := cy - boxH/2 - - if x+boxW >= width { - x = cx - boxW - offset - } - if x < 0 { - x = 0 - } - if y < 0 { - y = 0 - } - if y+boxH >= height { - y = height - boxH - } - - drawFilledRect(data, stride, width, height, x, y, boxW, boxH, c, pixelFormat) - - lum := 0.299*float64(c.R) + 0.587*float64(c.G) + 0.114*float64(c.B) - var fg Color - if lum > 128 { - fg = Color{R: 0, G: 0, B: 0, A: 255} - } else { - fg = Color{R: 255, G: 255, B: 255, A: 255} - } - drawText(data, stride, width, height, x+paddingX, y+paddingY, text, fg, pixelFormat) -} - -func formatColorForPreview(c Color, format OutputFormat, lowercase bool) string { - switch format { - case FormatRGB: - return strings.ToUpper(c.ToRGB()) - case FormatHSL: - return strings.ToUpper(c.ToHSL()) - case FormatHSV: - return strings.ToUpper(c.ToHSV()) - case FormatCMYK: - return strings.ToUpper(c.ToCMYK()) - default: - if lowercase { - return c.ToHex(true) - } - return c.ToHex(false) - } -} - -func drawFilledRect(data []byte, stride, width, height, x, y, w, h int, col Color, format PixelFormat) { - if w <= 0 || h <= 0 { - return - } - xEnd := clamp(x+w, 0, width) - yEnd := clamp(y+h, 0, height) - x = clamp(x, 0, width) - y = clamp(y, 0, height) - - var rOff, bOff int - switch format { - case FormatABGR8888, FormatXBGR8888: - rOff, bOff = 0, 2 - default: - rOff, bOff = 2, 0 - } - - for yy := y; yy < yEnd; yy++ { - rowOff := yy * stride - for xx := x; xx < xEnd; xx++ { - off := rowOff + xx*4 - if off+4 > len(data) { - continue - } - data[off+rOff] = col.R - data[off+1] = col.G - data[off+bOff] = col.B - data[off+3] = 255 - } - } -} - -func drawText(data []byte, stride, width, height, x, y int, text string, col Color, format PixelFormat) { - for i, r := range text { - drawGlyph(data, stride, width, height, x+i*(fontW+2), y, r, col, format) - } -} - -func drawGlyph(data []byte, stride, width, height, x, y int, r rune, col Color, format PixelFormat) { - g, ok := fontGlyphs[r] - if !ok { - return - } - - var rOff, bOff int - switch format { - case FormatABGR8888, FormatXBGR8888: - rOff, bOff = 0, 2 - default: - rOff, bOff = 2, 0 - } - - for row := range fontH { - yy := y + row - if yy < 0 || yy >= height { - continue - } - rowPattern := g[row] - dstRowOff := yy * stride - - for colIdx := range fontW { - if (rowPattern & (1 << (fontW - 1 - colIdx))) == 0 { - continue - } - - xx := x + colIdx - if xx < 0 || xx >= width { - continue - } - - off := dstRowOff + xx*4 - if off+4 > len(data) { - continue - } - - data[off+rOff] = col.R - data[off+1] = col.G - data[off+bOff] = col.B - data[off+3] = 255 - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state_test.go deleted file mode 100644 index a6599aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/colorpicker/state_test.go +++ /dev/null @@ -1,314 +0,0 @@ -package colorpicker - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestSurfaceState_ConcurrentPointerMotion(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := range goroutines { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := range iterations { - s.OnPointerMotion(float64(id*10+j), float64(id*10+j)) - } - }(i) - } - - wg.Wait() -} - -func TestSurfaceState_ConcurrentScaleAccess(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 100 - - for i := range goroutines / 2 { - wg.Add(1) - go func(id int) { - defer wg.Done() - for range iterations { - s.SetScale(int32(id%3 + 1)) - } - }(i) - } - - for range goroutines / 2 { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - scale := s.Scale() - assert.GreaterOrEqual(t, scale, int32(1)) - } - }() - } - - wg.Wait() -} - -func TestSurfaceState_ConcurrentLogicalSize(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 100 - - for i := range goroutines / 2 { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := range iterations { - _ = s.OnLayerConfigure(1920+id, 1080+j) - } - }(i) - } - - for range goroutines / 2 { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - w, h := s.LogicalSize() - _ = w - _ = h - } - }() - } - - wg.Wait() -} - -func TestSurfaceState_ConcurrentIsDone(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 100 - - for range goroutines / 3 { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - s.OnPointerButton(0x110, 1) - } - }() - } - - for range goroutines / 3 { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - s.OnKey(1, 1) - } - }() - } - - for range goroutines / 3 { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - picked, cancelled := s.IsDone() - _ = picked - _ = cancelled - } - }() - } - - wg.Wait() -} - -func TestSurfaceState_ConcurrentIsReady(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 100 - - for range goroutines { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - _ = s.IsReady() - } - }() - } - - wg.Wait() -} - -func TestSurfaceState_ConcurrentSwapBuffers(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 100 - - for range goroutines { - wg.Add(1) - go func() { - defer wg.Done() - for range iterations { - s.SwapBuffers() - } - }() - } - - wg.Wait() -} - -func TestSurfaceState_ZeroScale(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - s.SetScale(0) - assert.Equal(t, int32(1), s.Scale()) -} - -func TestSurfaceState_NegativeScale(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - s.SetScale(-5) - assert.Equal(t, int32(1), s.Scale()) -} - -func TestSurfaceState_ZeroDimensionConfigure(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - - err := s.OnLayerConfigure(0, 100) - assert.NoError(t, err) - - err = s.OnLayerConfigure(100, 0) - assert.NoError(t, err) - - err = s.OnLayerConfigure(-1, 100) - assert.NoError(t, err) - - w, h := s.LogicalSize() - assert.Equal(t, 0, w) - assert.Equal(t, 0, h) -} - -func TestSurfaceState_PickColorNilBuffer(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - color, ok := s.PickColor() - assert.False(t, ok) - assert.Equal(t, Color{}, color) -} - -func TestSurfaceState_RedrawNilBuffer(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - buf := s.Redraw() - assert.Nil(t, buf) -} - -func TestSurfaceState_RedrawScreenOnlyNilBuffer(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - buf := s.RedrawScreenOnly() - assert.Nil(t, buf) -} - -func TestSurfaceState_FrontRenderBufferNil(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - buf := s.FrontRenderBuffer() - assert.Nil(t, buf) -} - -func TestSurfaceState_ScreenBufferNil(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - buf := s.ScreenBuffer() - assert.Nil(t, buf) -} - -func TestSurfaceState_DestroyMultipleTimes(t *testing.T) { - s := NewSurfaceState(FormatHex, false) - s.Destroy() - s.Destroy() -} - -func TestClamp(t *testing.T) { - tests := []struct { - v, lo, hi, expected int - }{ - {5, 0, 10, 5}, - {-5, 0, 10, 0}, - {15, 0, 10, 10}, - {0, 0, 10, 0}, - {10, 0, 10, 10}, - } - - for _, tt := range tests { - result := clamp(tt.v, tt.lo, tt.hi) - assert.Equal(t, tt.expected, result) - } -} - -func TestClampF(t *testing.T) { - tests := []struct { - v, lo, hi, expected float64 - }{ - {5.0, 0.0, 10.0, 5.0}, - {-5.0, 0.0, 10.0, 0.0}, - {15.0, 0.0, 10.0, 10.0}, - {0.0, 0.0, 10.0, 0.0}, - {10.0, 0.0, 10.0, 10.0}, - } - - for _, tt := range tests { - result := clampF(tt.v, tt.lo, tt.hi) - assert.InDelta(t, tt.expected, result, 0.001) - } -} - -func TestAbs(t *testing.T) { - tests := []struct { - v, expected int - }{ - {5, 5}, - {-5, 5}, - {0, 0}, - } - - for _, tt := range tests { - result := abs(tt.v) - assert.Equal(t, tt.expected, result) - } -} - -func TestBlendColors(t *testing.T) { - bg := Color{R: 0, G: 0, B: 0, A: 255} - fg := Color{R: 255, G: 255, B: 255, A: 255} - - result := blendColors(bg, fg, 0.0) - assert.Equal(t, bg.R, result.R) - assert.Equal(t, bg.G, result.G) - assert.Equal(t, bg.B, result.B) - - result = blendColors(bg, fg, 1.0) - assert.Equal(t, fg.R, result.R) - assert.Equal(t, fg.G, result.G) - assert.Equal(t, fg.B, result.B) - - result = blendColors(bg, fg, 0.5) - assert.InDelta(t, 127, int(result.R), 1) - assert.InDelta(t, 127, int(result.G), 1) - assert.InDelta(t, 127, int(result.B), 1) - - result = blendColors(bg, fg, -1.0) - assert.Equal(t, bg.R, result.R) - - result = blendColors(bg, fg, 2.0) - assert.Equal(t, fg.R, result.R) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer.go deleted file mode 100644 index 7cc513f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer.go +++ /dev/null @@ -1,718 +0,0 @@ -package config - -import ( - "context" - "fmt" - "os" - "path/filepath" - "regexp" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -type ConfigDeployer struct { - logChan chan<- string -} - -type DeploymentResult struct { - ConfigType string - Path string - BackupPath string - Deployed bool - Error error -} - -func NewConfigDeployer(logChan chan<- string) *ConfigDeployer { - return &ConfigDeployer{ - logChan: logChan, - } -} - -func (cd *ConfigDeployer) log(message string) { - if cd.logChan != nil { - cd.logChan <- message - } -} - -// DeployConfigurations deploys all necessary configurations based on the chosen window manager -func (cd *ConfigDeployer) DeployConfigurations(ctx context.Context, wm deps.WindowManager) ([]DeploymentResult, error) { - return cd.DeployConfigurationsWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -// DeployConfigurationsWithTerminal deploys all necessary configurations based on chosen window manager and terminal -func (cd *ConfigDeployer) DeployConfigurationsWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]DeploymentResult, error) { - return cd.DeployConfigurationsSelective(ctx, wm, terminal, nil, nil) -} - -// DeployConfigurationsWithSystemd deploys configurations with systemd option -func (cd *ConfigDeployer) DeployConfigurationsWithSystemd(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, useSystemd bool) ([]DeploymentResult, error) { - return cd.deployConfigurationsInternal(ctx, wm, terminal, nil, nil, nil, useSystemd) -} - -func (cd *ConfigDeployer) DeployConfigurationsSelective(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, installedDeps []deps.Dependency, replaceConfigs map[string]bool) ([]DeploymentResult, error) { - return cd.DeployConfigurationsSelectiveWithReinstalls(ctx, wm, terminal, installedDeps, replaceConfigs, nil) -} - -func (cd *ConfigDeployer) DeployConfigurationsSelectiveWithReinstalls(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, installedDeps []deps.Dependency, replaceConfigs map[string]bool, reinstallItems map[string]bool) ([]DeploymentResult, error) { - return cd.deployConfigurationsInternal(ctx, wm, terminal, installedDeps, replaceConfigs, reinstallItems, true) -} - -func (cd *ConfigDeployer) deployConfigurationsInternal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, installedDeps []deps.Dependency, replaceConfigs map[string]bool, reinstallItems map[string]bool, useSystemd bool) ([]DeploymentResult, error) { - var results []DeploymentResult - - // Primary config file paths used to detect fresh installs. - configPrimaryPaths := map[string]string{ - "Niri": filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl"), - "Hyprland": filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf"), - "Ghostty": filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config"), - "Kitty": filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf"), - "Alacritty": filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml"), - } - - shouldReplaceConfig := func(configType string) bool { - if replaceConfigs == nil { - return true - } - replace, exists := replaceConfigs[configType] - if !exists || replace { - return true - } - // Config is explicitly set to "don't replace" — but still deploy - // if the config file doesn't exist yet (fresh install scenario). - if primaryPath, ok := configPrimaryPaths[configType]; ok { - if _, err := os.Stat(primaryPath); os.IsNotExist(err) { - return true - } - } - return false - } - - switch wm { - case deps.WindowManagerNiri: - if shouldReplaceConfig("Niri") { - result, err := cd.deployNiriConfig(terminal, useSystemd) - results = append(results, result) - if err != nil { - return results, fmt.Errorf("failed to deploy Niri config: %w", err) - } - } - case deps.WindowManagerHyprland: - if shouldReplaceConfig("Hyprland") { - result, err := cd.deployHyprlandConfig(terminal, useSystemd) - results = append(results, result) - if err != nil { - return results, fmt.Errorf("failed to deploy Hyprland config: %w", err) - } - } - } - - switch terminal { - case deps.TerminalGhostty: - if shouldReplaceConfig("Ghostty") { - ghosttyResults, err := cd.deployGhosttyConfig() - results = append(results, ghosttyResults...) - if err != nil { - return results, fmt.Errorf("failed to deploy Ghostty config: %w", err) - } - } - case deps.TerminalKitty: - if shouldReplaceConfig("Kitty") { - kittyResults, err := cd.deployKittyConfig() - results = append(results, kittyResults...) - if err != nil { - return results, fmt.Errorf("failed to deploy Kitty config: %w", err) - } - } - case deps.TerminalAlacritty: - if shouldReplaceConfig("Alacritty") { - alacrittyResults, err := cd.deployAlacrittyConfig() - results = append(results, alacrittyResults...) - if err != nil { - return results, fmt.Errorf("failed to deploy Alacritty config: %w", err) - } - } - } - - return results, nil -} - -func (cd *ConfigDeployer) deployNiriConfig(terminal deps.Terminal, useSystemd bool) (DeploymentResult, error) { - result := DeploymentResult{ - ConfigType: "Niri", - Path: filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl"), - } - - configDir := filepath.Dir(result.Path) - if err := os.MkdirAll(configDir, 0o755); err != nil { - result.Error = fmt.Errorf("failed to create config directory: %w", err) - return result, result.Error - } - - dmsDir := filepath.Join(configDir, "dms") - if err := os.MkdirAll(dmsDir, 0o755); err != nil { - result.Error = fmt.Errorf("failed to create dms directory: %w", err) - return result, result.Error - } - - var existingConfig string - if _, err := os.Stat(result.Path); err == nil { - cd.log("Found existing Niri configuration") - - existingData, err := os.ReadFile(result.Path) - if err != nil { - result.Error = fmt.Errorf("failed to read existing config: %w", err) - return result, result.Error - } - existingConfig = string(existingData) - - timestamp := time.Now().Format("2006-01-02_15-04-05") - result.BackupPath = result.Path + ".backup." + timestamp - if err := os.WriteFile(result.BackupPath, existingData, 0o644); err != nil { - result.Error = fmt.Errorf("failed to create backup: %w", err) - return result, result.Error - } - cd.log(fmt.Sprintf("Backed up existing config to %s", result.BackupPath)) - } - - var terminalCommand string - switch terminal { - case deps.TerminalGhostty: - terminalCommand = "ghostty" - case deps.TerminalKitty: - terminalCommand = "kitty" - case deps.TerminalAlacritty: - terminalCommand = "alacritty" - default: - terminalCommand = "ghostty" - } - - newConfig := strings.ReplaceAll(NiriConfig, "{{TERMINAL_COMMAND}}", terminalCommand) - - if !useSystemd { - newConfig = cd.transformNiriConfigForNonSystemd(newConfig, terminalCommand) - } - - if existingConfig != "" { - mergedConfig, err := cd.mergeNiriOutputSections(newConfig, existingConfig, dmsDir) - if err != nil { - cd.log(fmt.Sprintf("Warning: Failed to merge output sections: %v", err)) - } else { - newConfig = mergedConfig - cd.log("Successfully merged existing output sections") - } - } - - if err := os.WriteFile(result.Path, []byte(newConfig), 0o644); err != nil { - result.Error = fmt.Errorf("failed to write config: %w", err) - return result, result.Error - } - - if err := cd.deployNiriDmsConfigs(dmsDir, terminalCommand); err != nil { - result.Error = fmt.Errorf("failed to deploy dms configs: %w", err) - return result, result.Error - } - - result.Deployed = true - cd.log("Successfully deployed Niri configuration") - return result, nil -} - -func (cd *ConfigDeployer) deployNiriDmsConfigs(dmsDir, terminalCommand string) error { - configs := []struct { - name string - content string - }{ - {"colors.kdl", NiriColorsConfig}, - {"layout.kdl", NiriLayoutConfig}, - {"alttab.kdl", NiriAlttabConfig}, - {"binds.kdl", strings.ReplaceAll(NiriBindsConfig, "{{TERMINAL_COMMAND}}", terminalCommand)}, - {"outputs.kdl", ""}, - {"cursor.kdl", ""}, - {"windowrules.kdl", ""}, - } - - for _, cfg := range configs { - path := filepath.Join(dmsDir, cfg.name) - // Skip if file already exists and is not empty to preserve user modifications - if info, err := os.Stat(path); err == nil && info.Size() > 0 { - cd.log(fmt.Sprintf("Skipping %s (already exists)", cfg.name)) - continue - } - if err := os.WriteFile(path, []byte(cfg.content), 0o644); err != nil { - return fmt.Errorf("failed to write %s: %w", cfg.name, err) - } - cd.log(fmt.Sprintf("Deployed %s", cfg.name)) - } - - return nil -} - -func (cd *ConfigDeployer) deployGhosttyConfig() ([]DeploymentResult, error) { - var results []DeploymentResult - - mainResult := DeploymentResult{ - ConfigType: "Ghostty", - Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config"), - } - - configDir := filepath.Dir(mainResult.Path) - if err := os.MkdirAll(configDir, 0o755); err != nil { - mainResult.Error = fmt.Errorf("failed to create config directory: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - if _, err := os.Stat(mainResult.Path); err == nil { - cd.log("Found existing Ghostty configuration") - - existingData, err := os.ReadFile(mainResult.Path) - if err != nil { - mainResult.Error = fmt.Errorf("failed to read existing config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - timestamp := time.Now().Format("2006-01-02_15-04-05") - mainResult.BackupPath = mainResult.Path + ".backup." + timestamp - if err := os.WriteFile(mainResult.BackupPath, existingData, 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to create backup: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath)) - } - - if err := os.WriteFile(mainResult.Path, []byte(GhosttyConfig), 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to write config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - mainResult.Deployed = true - cd.log("Successfully deployed Ghostty configuration") - results = append(results, mainResult) - - colorResult := DeploymentResult{ - ConfigType: "Ghostty Colors", - Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "themes", "dankcolors"), - } - - themesDir := filepath.Dir(colorResult.Path) - if err := os.MkdirAll(themesDir, 0o755); err != nil { - mainResult.Error = fmt.Errorf("failed to create themes directory: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0o644); err != nil { - colorResult.Error = fmt.Errorf("failed to write color config: %w", err) - return results, colorResult.Error - } - - colorResult.Deployed = true - cd.log("Successfully deployed Ghostty color configuration") - results = append(results, colorResult) - - return results, nil -} - -func (cd *ConfigDeployer) deployKittyConfig() ([]DeploymentResult, error) { - var results []DeploymentResult - - mainResult := DeploymentResult{ - ConfigType: "Kitty", - Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf"), - } - - configDir := filepath.Dir(mainResult.Path) - if err := os.MkdirAll(configDir, 0o755); err != nil { - mainResult.Error = fmt.Errorf("failed to create config directory: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - if _, err := os.Stat(mainResult.Path); err == nil { - cd.log("Found existing Kitty configuration") - - existingData, err := os.ReadFile(mainResult.Path) - if err != nil { - mainResult.Error = fmt.Errorf("failed to read existing config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - timestamp := time.Now().Format("2006-01-02_15-04-05") - mainResult.BackupPath = mainResult.Path + ".backup." + timestamp - if err := os.WriteFile(mainResult.BackupPath, existingData, 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to create backup: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath)) - } - - if err := os.WriteFile(mainResult.Path, []byte(KittyConfig), 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to write config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - mainResult.Deployed = true - cd.log("Successfully deployed Kitty configuration") - results = append(results, mainResult) - - themeResult := DeploymentResult{ - ConfigType: "Kitty Theme", - Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "dank-theme.conf"), - } - - if err := os.WriteFile(themeResult.Path, []byte(KittyThemeConfig), 0o644); err != nil { - themeResult.Error = fmt.Errorf("failed to write theme config: %w", err) - return results, themeResult.Error - } - - themeResult.Deployed = true - cd.log("Successfully deployed Kitty theme configuration") - results = append(results, themeResult) - - tabsResult := DeploymentResult{ - ConfigType: "Kitty Tabs", - Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "dank-tabs.conf"), - } - - if err := os.WriteFile(tabsResult.Path, []byte(KittyTabsConfig), 0o644); err != nil { - tabsResult.Error = fmt.Errorf("failed to write tabs config: %w", err) - return results, tabsResult.Error - } - - tabsResult.Deployed = true - cd.log("Successfully deployed Kitty tabs configuration") - results = append(results, tabsResult) - - return results, nil -} - -func (cd *ConfigDeployer) deployAlacrittyConfig() ([]DeploymentResult, error) { - var results []DeploymentResult - - mainResult := DeploymentResult{ - ConfigType: "Alacritty", - Path: filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml"), - } - - configDir := filepath.Dir(mainResult.Path) - if err := os.MkdirAll(configDir, 0o755); err != nil { - mainResult.Error = fmt.Errorf("failed to create config directory: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - if _, err := os.Stat(mainResult.Path); err == nil { - cd.log("Found existing Alacritty configuration") - - existingData, err := os.ReadFile(mainResult.Path) - if err != nil { - mainResult.Error = fmt.Errorf("failed to read existing config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - timestamp := time.Now().Format("2006-01-02_15-04-05") - mainResult.BackupPath = mainResult.Path + ".backup." + timestamp - if err := os.WriteFile(mainResult.BackupPath, existingData, 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to create backup: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath)) - } - - if err := os.WriteFile(mainResult.Path, []byte(AlacrittyConfig), 0o644); err != nil { - mainResult.Error = fmt.Errorf("failed to write config: %w", err) - return []DeploymentResult{mainResult}, mainResult.Error - } - - mainResult.Deployed = true - cd.log("Successfully deployed Alacritty configuration") - results = append(results, mainResult) - - themeResult := DeploymentResult{ - ConfigType: "Alacritty Theme", - Path: filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "dank-theme.toml"), - } - - if err := os.WriteFile(themeResult.Path, []byte(AlacrittyThemeConfig), 0o644); err != nil { - themeResult.Error = fmt.Errorf("failed to write theme config: %w", err) - return results, themeResult.Error - } - - themeResult.Deployed = true - cd.log("Successfully deployed Alacritty theme configuration") - results = append(results, themeResult) - - return results, nil -} - -func (cd *ConfigDeployer) mergeNiriOutputSections(newConfig, existingConfig, dmsDir string) (string, error) { - outputRegex := regexp.MustCompile(`(?m)^(/-)?\s*output\s+"[^"]+"\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}`) - existingOutputs := outputRegex.FindAllString(existingConfig, -1) - - if len(existingOutputs) == 0 { - return newConfig, nil - } - - outputsPath := filepath.Join(dmsDir, "outputs.kdl") - if _, err := os.Stat(outputsPath); err != nil { - var outputsContent strings.Builder - for _, output := range existingOutputs { - outputsContent.WriteString(output) - outputsContent.WriteString("\n\n") - } - if err := os.WriteFile(outputsPath, []byte(outputsContent.String()), 0o644); err != nil { - cd.log(fmt.Sprintf("Warning: Failed to migrate outputs to %s: %v", outputsPath, err)) - } else { - cd.log("Migrated output sections to dms/outputs.kdl") - } - } - - exampleOutputRegex := regexp.MustCompile(`(?m)^/-output "eDP-2" \{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}`) - mergedConfig := exampleOutputRegex.ReplaceAllString(newConfig, "") - - inputEndRegex := regexp.MustCompile(`(?m)^}$`) - inputMatches := inputEndRegex.FindAllStringIndex(newConfig, -1) - - if len(inputMatches) < 1 { - return "", fmt.Errorf("could not find insertion point for output sections") - } - - insertPos := inputMatches[0][1] - - var builder strings.Builder - builder.WriteString(mergedConfig[:insertPos]) - builder.WriteString("\n// Outputs from existing configuration\n") - - for _, output := range existingOutputs { - builder.WriteString(output) - builder.WriteString("\n") - } - - builder.WriteString(mergedConfig[insertPos:]) - - return builder.String(), nil -} - -// deployHyprlandConfig handles Hyprland configuration deployment with backup and merging -func (cd *ConfigDeployer) deployHyprlandConfig(terminal deps.Terminal, useSystemd bool) (DeploymentResult, error) { - result := DeploymentResult{ - ConfigType: "Hyprland", - Path: filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf"), - } - - configDir := filepath.Dir(result.Path) - if err := os.MkdirAll(configDir, 0o755); err != nil { - result.Error = fmt.Errorf("failed to create config directory: %w", err) - return result, result.Error - } - - dmsDir := filepath.Join(configDir, "dms") - if err := os.MkdirAll(dmsDir, 0o755); err != nil { - result.Error = fmt.Errorf("failed to create dms directory: %w", err) - return result, result.Error - } - - var existingConfig string - if _, err := os.Stat(result.Path); err == nil { - cd.log("Found existing Hyprland configuration") - - existingData, err := os.ReadFile(result.Path) - if err != nil { - result.Error = fmt.Errorf("failed to read existing config: %w", err) - return result, result.Error - } - existingConfig = string(existingData) - - timestamp := time.Now().Format("2006-01-02_15-04-05") - result.BackupPath = result.Path + ".backup." + timestamp - if err := os.WriteFile(result.BackupPath, existingData, 0o644); err != nil { - result.Error = fmt.Errorf("failed to create backup: %w", err) - return result, result.Error - } - cd.log(fmt.Sprintf("Backed up existing config to %s", result.BackupPath)) - } - - var terminalCommand string - switch terminal { - case deps.TerminalGhostty: - terminalCommand = "ghostty" - case deps.TerminalKitty: - terminalCommand = "kitty" - case deps.TerminalAlacritty: - terminalCommand = "alacritty" - default: - terminalCommand = "ghostty" - } - - newConfig := strings.ReplaceAll(HyprlandConfig, "{{TERMINAL_COMMAND}}", terminalCommand) - - if !useSystemd { - newConfig = cd.transformHyprlandConfigForNonSystemd(newConfig, terminalCommand) - } - - if existingConfig != "" { - mergedConfig, err := cd.mergeHyprlandMonitorSections(newConfig, existingConfig, dmsDir) - if err != nil { - cd.log(fmt.Sprintf("Warning: Failed to merge monitor sections: %v", err)) - } else { - newConfig = mergedConfig - cd.log("Successfully merged existing monitor sections") - } - } - - if err := os.WriteFile(result.Path, []byte(newConfig), 0o644); err != nil { - result.Error = fmt.Errorf("failed to write config: %w", err) - return result, result.Error - } - - if err := cd.deployHyprlandDmsConfigs(dmsDir, terminalCommand); err != nil { - result.Error = fmt.Errorf("failed to deploy dms configs: %w", err) - return result, result.Error - } - - result.Deployed = true - cd.log("Successfully deployed Hyprland configuration") - return result, nil -} - -func (cd *ConfigDeployer) deployHyprlandDmsConfigs(dmsDir string, terminalCommand string) error { - configs := []struct { - name string - content string - }{ - {"colors.conf", HyprColorsConfig}, - {"layout.conf", HyprLayoutConfig}, - {"binds.conf", strings.ReplaceAll(HyprBindsConfig, "{{TERMINAL_COMMAND}}", terminalCommand)}, - {"outputs.conf", ""}, - {"cursor.conf", ""}, - {"windowrules.conf", ""}, - } - - for _, cfg := range configs { - path := filepath.Join(dmsDir, cfg.name) - // Skip if file already exists and is not empty to preserve user modifications - if info, err := os.Stat(path); err == nil && info.Size() > 0 { - cd.log(fmt.Sprintf("Skipping %s (already exists)", cfg.name)) - continue - } - if err := os.WriteFile(path, []byte(cfg.content), 0o644); err != nil { - return fmt.Errorf("failed to write %s: %w", cfg.name, err) - } - cd.log(fmt.Sprintf("Deployed %s", cfg.name)) - } - - return nil -} - -func (cd *ConfigDeployer) mergeHyprlandMonitorSections(newConfig, existingConfig, dmsDir string) (string, error) { - monitorRegex := regexp.MustCompile(`(?m)^#?\s*monitor\s*=.*$`) - existingMonitors := monitorRegex.FindAllString(existingConfig, -1) - - if len(existingMonitors) == 0 { - return newConfig, nil - } - - outputsPath := filepath.Join(dmsDir, "outputs.conf") - if _, err := os.Stat(outputsPath); err != nil { - var outputsContent strings.Builder - for _, monitor := range existingMonitors { - outputsContent.WriteString(monitor) - outputsContent.WriteString("\n") - } - if err := os.WriteFile(outputsPath, []byte(outputsContent.String()), 0o644); err != nil { - cd.log(fmt.Sprintf("Warning: Failed to migrate monitors to %s: %v", outputsPath, err)) - } else { - cd.log("Migrated monitor sections to dms/outputs.conf") - } - } - - exampleMonitorRegex := regexp.MustCompile(`(?m)^# monitor = eDP-2.*$`) - mergedConfig := exampleMonitorRegex.ReplaceAllString(newConfig, "") - - monitorHeaderRegex := regexp.MustCompile(`(?m)^# MONITOR CONFIG\n# ==================$`) - headerMatch := monitorHeaderRegex.FindStringIndex(mergedConfig) - - if headerMatch == nil { - return "", fmt.Errorf("could not find MONITOR CONFIG section") - } - - insertPos := headerMatch[1] + 1 - - var builder strings.Builder - builder.WriteString(mergedConfig[:insertPos]) - builder.WriteString("# Monitors from existing configuration\n") - - for _, monitor := range existingMonitors { - builder.WriteString(monitor) - builder.WriteString("\n") - } - - builder.WriteString(mergedConfig[insertPos:]) - - return builder.String(), nil -} - -func (cd *ConfigDeployer) transformHyprlandConfigForNonSystemd(config, terminalCommand string) string { - lines := strings.Split(config, "\n") - var result []string - startupSectionFound := false - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "exec-once = dbus-update-activation-environment") { - continue - } - if strings.HasPrefix(trimmed, "exec-once = systemctl --user start") { - startupSectionFound = true - result = append(result, "exec-once = dms run") - result = append(result, "env = QT_QPA_PLATFORM,wayland;xcb") - result = append(result, "env = ELECTRON_OZONE_PLATFORM_HINT,auto") - result = append(result, "env = QT_QPA_PLATFORMTHEME,gtk3") - result = append(result, "env = QT_QPA_PLATFORMTHEME_QT6,gtk3") - result = append(result, fmt.Sprintf("env = TERMINAL,%s", terminalCommand)) - continue - } - result = append(result, line) - } - - if !startupSectionFound { - for i, line := range result { - if strings.Contains(line, "STARTUP APPS") { - insertLines := []string{ - "exec-once = dms run", - "env = QT_QPA_PLATFORM,wayland;xcb", - "env = ELECTRON_OZONE_PLATFORM_HINT,auto", - "env = QT_QPA_PLATFORMTHEME,gtk3", - "env = QT_QPA_PLATFORMTHEME_QT6,gtk3", - fmt.Sprintf("env = TERMINAL,%s", terminalCommand), - } - result = append(result[:i+2], append(insertLines, result[i+2:]...)...) - break - } - } - } - - return strings.Join(result, "\n") -} - -func (cd *ConfigDeployer) transformNiriConfigForNonSystemd(config, terminalCommand string) string { - envVars := fmt.Sprintf(`environment { - XDG_CURRENT_DESKTOP "niri" - QT_QPA_PLATFORM "wayland;xcb" - ELECTRON_OZONE_PLATFORM_HINT "auto" - QT_QPA_PLATFORMTHEME "gtk3" - QT_QPA_PLATFORMTHEME_QT6 "gtk3" - TERMINAL "%s" -}`, terminalCommand) - - config = regexp.MustCompile(`environment \{[^}]*\}`).ReplaceAllString(config, envVars) - - spawnDms := `spawn-at-startup "dms" "run"` - if !strings.Contains(config, spawnDms) { - // Insert spawn-at-startup for dms after the environment block - envBlockEnd := regexp.MustCompile(`environment \{[^}]*\}`) - if loc := envBlockEnd.FindStringIndex(config); loc != nil { - config = config[:loc[1]] + "\n" + spawnDms + config[loc[1]:] - } - } - - return config -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer_test.go deleted file mode 100644 index 3726634..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/deployer_test.go +++ /dev/null @@ -1,792 +0,0 @@ -package config - -import ( - "context" - "os" - "path/filepath" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestMergeNiriOutputSections(t *testing.T) { - cd := &ConfigDeployer{} - - tests := []struct { - name string - newConfig string - existingConfig string - wantError bool - wantContains []string - }{ - { - name: "no existing outputs", - newConfig: `input { - keyboard { - xkb { - } - } -} -layout { - gaps 5 -}`, - existingConfig: `input { - keyboard { - xkb { - } - } -} -layout { - gaps 10 -}`, - wantError: false, - wantContains: []string{"gaps 5"}, // Should keep new config - }, - { - name: "merge single output", - newConfig: `input { - keyboard { - xkb { - } - } -} -/-output "eDP-2" { - mode "2560x1600@239.998993" - position x=2560 y=0 -} -layout { - gaps 5 -}`, - existingConfig: `input { - keyboard { - xkb { - } - } -} -output "eDP-1" { - mode "1920x1080@60.000000" - position x=0 y=0 - scale 1.0 -} -layout { - gaps 10 -}`, - wantError: false, - wantContains: []string{ - "gaps 5", // New config preserved - `output "eDP-1"`, // Existing output merged - "1920x1080@60.000000", // Existing output details - "Outputs from existing configuration", // Comment added - }, - }, - { - name: "merge multiple outputs", - newConfig: `input { - keyboard { - xkb { - } - } -} -/-output "eDP-2" { - mode "2560x1600@239.998993" - position x=2560 y=0 -} -layout { - gaps 5 -}`, - existingConfig: `input { - keyboard { - xkb { - } - } -} -output "eDP-1" { - mode "1920x1080@60.000000" - position x=0 y=0 - scale 1.0 -} -/-output "HDMI-1" { - mode "1920x1080@60.000000" - position x=1920 y=0 -} -layout { - gaps 10 -}`, - wantError: false, - wantContains: []string{ - "gaps 5", // New config preserved - `output "eDP-1"`, // First existing output - `/-output "HDMI-1"`, // Second existing output (commented) - "1920x1080@60.000000", // Output details - }, - }, - { - name: "merge commented outputs", - newConfig: `input { - keyboard { - xkb { - } - } -} -/-output "eDP-2" { - mode "2560x1600@239.998993" - position x=2560 y=0 -} -layout { - gaps 5 -}`, - existingConfig: `input { - keyboard { - xkb { - } - } -} -/-output "eDP-1" { - mode "1920x1080@60.000000" - position x=0 y=0 - scale 1.0 -} -layout { - gaps 10 -}`, - wantError: false, - wantContains: []string{ - "gaps 5", // New config preserved - `/-output "eDP-1"`, // Commented output preserved - "1920x1080@60.000000", // Output details - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tmpDir := t.TempDir() - result, err := cd.mergeNiriOutputSections(tt.newConfig, tt.existingConfig, tmpDir) - - if tt.wantError { - assert.Error(t, err) - return - } - - require.NoError(t, err) - - for _, want := range tt.wantContains { - assert.Contains(t, result, want, "merged config should contain: %s", want) - } - - assert.NotContains(t, result, `/-output "eDP-2"`, "example output should be removed") - }) - } -} - -func TestConfigDeploymentFlow(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - t.Run("deploy ghostty config to empty directory", func(t *testing.T) { - results, err := cd.deployGhosttyConfig() - require.NoError(t, err) - require.Len(t, results, 2) - - mainResult := results[0] - assert.Equal(t, "Ghostty", mainResult.ConfigType) - assert.True(t, mainResult.Deployed) - assert.Empty(t, mainResult.BackupPath) - assert.FileExists(t, mainResult.Path) - - content, err := os.ReadFile(mainResult.Path) - require.NoError(t, err) - assert.Contains(t, string(content), "window-decoration = false") - - colorResult := results[1] - assert.Equal(t, "Ghostty Colors", colorResult.ConfigType) - assert.True(t, colorResult.Deployed) - assert.FileExists(t, colorResult.Path) - - colorContent, err := os.ReadFile(colorResult.Path) - require.NoError(t, err) - assert.Contains(t, string(colorContent), "background = #101418") - }) - - t.Run("deploy ghostty config with existing file", func(t *testing.T) { - existingContent := "# Old config\nfont-size = 14\n" - ghosttyPath := getGhosttyPath() - err := os.MkdirAll(filepath.Dir(ghosttyPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(ghosttyPath, []byte(existingContent), 0o644) - require.NoError(t, err) - - results, err := cd.deployGhosttyConfig() - require.NoError(t, err) - require.Len(t, results, 2) - - mainResult := results[0] - assert.Equal(t, "Ghostty", mainResult.ConfigType) - assert.True(t, mainResult.Deployed) - assert.NotEmpty(t, mainResult.BackupPath) - assert.FileExists(t, mainResult.Path) - assert.FileExists(t, mainResult.BackupPath) - - backupContent, err := os.ReadFile(mainResult.BackupPath) - require.NoError(t, err) - assert.Equal(t, existingContent, string(backupContent)) - - newContent, err := os.ReadFile(mainResult.Path) - require.NoError(t, err) - assert.NotContains(t, string(newContent), "# Old config") - - colorResult := results[1] - assert.Equal(t, "Ghostty Colors", colorResult.ConfigType) - assert.True(t, colorResult.Deployed) - assert.FileExists(t, colorResult.Path) - }) -} - -func getGhosttyPath() string { - return filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config") -} - -func TestMergeHyprlandMonitorSections(t *testing.T) { - cd := &ConfigDeployer{} - - tests := []struct { - name string - newConfig string - existingConfig string - wantError bool - wantContains []string - wantNotContains []string - }{ - { - name: "no existing monitors", - newConfig: `# ================== -# MONITOR CONFIG -# ================== -# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1 - -# ================== -# ENVIRONMENT VARS -# ================== -env = XDG_CURRENT_DESKTOP,niri`, - existingConfig: `# Some other config -input { - kb_layout = us -}`, - wantError: false, - wantContains: []string{"MONITOR CONFIG", "ENVIRONMENT VARS"}, - }, - { - name: "merge single monitor", - newConfig: `# ================== -# MONITOR CONFIG -# ================== -# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1 - -# ================== -# ENVIRONMENT VARS -# ==================`, - existingConfig: `# My config -monitor = DP-1, 1920x1080@144, 0x0, 1 -input { - kb_layout = us -}`, - wantError: false, - wantContains: []string{ - "MONITOR CONFIG", - "monitor = DP-1, 1920x1080@144, 0x0, 1", - "Monitors from existing configuration", - }, - wantNotContains: []string{ - "monitor = eDP-2", // Example monitor should be removed - }, - }, - { - name: "merge multiple monitors", - newConfig: `# ================== -# MONITOR CONFIG -# ================== -# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1 - -# ================== -# ENVIRONMENT VARS -# ==================`, - existingConfig: `monitor = DP-1, 1920x1080@144, 0x0, 1 -# monitor = HDMI-A-1, 1920x1080@60, 1920x0, 1 -monitor = eDP-1, 2560x1440@165, auto, 1.25`, - wantError: false, - wantContains: []string{ - "monitor = DP-1", - "# monitor = HDMI-A-1", // Commented monitor preserved - "monitor = eDP-1", - "Monitors from existing configuration", - }, - wantNotContains: []string{ - "monitor = eDP-2", // Example monitor should be removed - }, - }, - { - name: "preserve commented monitors", - newConfig: `# ================== -# MONITOR CONFIG -# ================== -# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1 - -# ==================`, - existingConfig: `# monitor = DP-1, 1920x1080@144, 0x0, 1 -# monitor = HDMI-A-1, 1920x1080@60, 1920x0, 1`, - wantError: false, - wantContains: []string{ - "# monitor = DP-1", - "# monitor = HDMI-A-1", - "Monitors from existing configuration", - }, - }, - { - name: "no monitor config section", - newConfig: `# Some config without monitor section -input { - kb_layout = us -}`, - existingConfig: `monitor = DP-1, 1920x1080@144, 0x0, 1`, - wantError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tmpDir := t.TempDir() - result, err := cd.mergeHyprlandMonitorSections(tt.newConfig, tt.existingConfig, tmpDir) - - if tt.wantError { - assert.Error(t, err) - return - } - - require.NoError(t, err) - - for _, want := range tt.wantContains { - assert.Contains(t, result, want, "merged config should contain: %s", want) - } - - for _, notWant := range tt.wantNotContains { - assert.NotContains(t, result, notWant, "merged config should NOT contain: %s", notWant) - } - }) - } -} - -func TestHyprlandConfigDeployment(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-hyprland-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - t.Run("deploy hyprland config to empty directory", func(t *testing.T) { - result, err := cd.deployHyprlandConfig(deps.TerminalGhostty, true) - require.NoError(t, err) - - assert.Equal(t, "Hyprland", result.ConfigType) - assert.True(t, result.Deployed) - assert.Empty(t, result.BackupPath) - assert.FileExists(t, result.Path) - - content, err := os.ReadFile(result.Path) - require.NoError(t, err) - assert.Contains(t, string(content), "# MONITOR CONFIG") - assert.Contains(t, string(content), "source = ./dms/binds.conf") - assert.Contains(t, string(content), "exec-once = ") - }) - - t.Run("deploy hyprland config with existing monitors", func(t *testing.T) { - existingContent := `# My existing Hyprland config -monitor = DP-1, 1920x1080@144, 0x0, 1 -monitor = HDMI-A-1, 3840x2160@60, 1920x0, 1.5 - -general { - gaps_in = 10 -} -` - hyprPath := filepath.Join(tempDir, ".config", "hypr", "hyprland.conf") - err := os.MkdirAll(filepath.Dir(hyprPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(hyprPath, []byte(existingContent), 0o644) - require.NoError(t, err) - - result, err := cd.deployHyprlandConfig(deps.TerminalKitty, true) - require.NoError(t, err) - - assert.Equal(t, "Hyprland", result.ConfigType) - assert.True(t, result.Deployed) - assert.NotEmpty(t, result.BackupPath) - assert.FileExists(t, result.Path) - assert.FileExists(t, result.BackupPath) - - backupContent, err := os.ReadFile(result.BackupPath) - require.NoError(t, err) - assert.Equal(t, existingContent, string(backupContent)) - - newContent, err := os.ReadFile(result.Path) - require.NoError(t, err) - assert.Contains(t, string(newContent), "monitor = DP-1, 1920x1080@144") - assert.Contains(t, string(newContent), "monitor = HDMI-A-1, 3840x2160@60") - assert.Contains(t, string(newContent), "source = ./dms/binds.conf") - assert.NotContains(t, string(newContent), "monitor = eDP-2") - }) -} - -func TestNiriConfigStructure(t *testing.T) { - assert.Contains(t, NiriConfig, "input {") - assert.Contains(t, NiriConfig, "layout {") - - assert.Contains(t, NiriBindsConfig, "binds {") - assert.Contains(t, NiriBindsConfig, `spawn "{{TERMINAL_COMMAND}}"`) -} - -func TestHyprlandConfigStructure(t *testing.T) { - assert.Contains(t, HyprlandConfig, "# MONITOR CONFIG") - assert.Contains(t, HyprlandConfig, "# STARTUP APPS") - assert.Contains(t, HyprlandConfig, "# INPUT CONFIG") - assert.Contains(t, HyprlandConfig, "source = ./dms/binds.conf") -} - -func TestGhosttyConfigStructure(t *testing.T) { - assert.Contains(t, GhosttyConfig, "window-decoration = false") - assert.Contains(t, GhosttyConfig, "background-opacity = 1.0") - assert.Contains(t, GhosttyConfig, "theme = dankcolors") -} - -func TestGhosttyColorConfigStructure(t *testing.T) { - assert.Contains(t, GhosttyColorConfig, "background = #101418") - assert.Contains(t, GhosttyColorConfig, "foreground = #e0e2e8") - assert.Contains(t, GhosttyColorConfig, "cursor-color = #9dcbfb") - assert.Contains(t, GhosttyColorConfig, "palette = 0=#101418") - assert.Contains(t, GhosttyColorConfig, "palette = 15=#ffffff") -} - -func TestKittyConfigStructure(t *testing.T) { - assert.Contains(t, KittyConfig, "font_size 12.0") - assert.Contains(t, KittyConfig, "window_padding_width 12") - assert.Contains(t, KittyConfig, "background_opacity 1.0") - assert.Contains(t, KittyConfig, "include dank-tabs.conf") - assert.Contains(t, KittyConfig, "include dank-theme.conf") -} - -func TestKittyThemeConfigStructure(t *testing.T) { - assert.Contains(t, KittyThemeConfig, "foreground #e0e2e8") - assert.Contains(t, KittyThemeConfig, "background #101418") - assert.Contains(t, KittyThemeConfig, "cursor #e0e2e8") - assert.Contains(t, KittyThemeConfig, "color0 #101418") - assert.Contains(t, KittyThemeConfig, "color15 #ffffff") -} - -func TestKittyTabsConfigStructure(t *testing.T) { - assert.Contains(t, KittyTabsConfig, "tab_bar_style powerline") - assert.Contains(t, KittyTabsConfig, "tab_powerline_style slanted") - assert.Contains(t, KittyTabsConfig, "active_tab_background #124a73") - assert.Contains(t, KittyTabsConfig, "inactive_tab_background #101418") -} - -func TestAlacrittyConfigStructure(t *testing.T) { - assert.Contains(t, AlacrittyConfig, "[general]") - assert.Contains(t, AlacrittyConfig, "~/.config/alacritty/dank-theme.toml") - assert.Contains(t, AlacrittyConfig, "[window]") - assert.Contains(t, AlacrittyConfig, "decorations = \"None\"") - assert.Contains(t, AlacrittyConfig, "padding = { x = 12, y = 12 }") - assert.Contains(t, AlacrittyConfig, "[cursor]") - assert.Contains(t, AlacrittyConfig, "[keyboard]") -} - -func TestAlacrittyThemeConfigStructure(t *testing.T) { - assert.Contains(t, AlacrittyThemeConfig, "[colors.primary]") - assert.Contains(t, AlacrittyThemeConfig, "background = '#101418'") - assert.Contains(t, AlacrittyThemeConfig, "foreground = '#e0e2e8'") - assert.Contains(t, AlacrittyThemeConfig, "[colors.cursor]") - assert.Contains(t, AlacrittyThemeConfig, "cursor = '#9dcbfb'") - assert.Contains(t, AlacrittyThemeConfig, "[colors.normal]") - assert.Contains(t, AlacrittyThemeConfig, "[colors.bright]") -} - -func TestKittyConfigDeployment(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-kitty-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - t.Run("deploy kitty config to empty directory", func(t *testing.T) { - results, err := cd.deployKittyConfig() - require.NoError(t, err) - require.Len(t, results, 3) - - mainResult := results[0] - assert.Equal(t, "Kitty", mainResult.ConfigType) - assert.True(t, mainResult.Deployed) - assert.FileExists(t, mainResult.Path) - - content, err := os.ReadFile(mainResult.Path) - require.NoError(t, err) - assert.Contains(t, string(content), "include dank-theme.conf") - - themeResult := results[1] - assert.Equal(t, "Kitty Theme", themeResult.ConfigType) - assert.True(t, themeResult.Deployed) - assert.FileExists(t, themeResult.Path) - - tabsResult := results[2] - assert.Equal(t, "Kitty Tabs", tabsResult.ConfigType) - assert.True(t, tabsResult.Deployed) - assert.FileExists(t, tabsResult.Path) - }) -} - -func TestAlacrittyConfigDeployment(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-alacritty-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - t.Run("deploy alacritty config to empty directory", func(t *testing.T) { - results, err := cd.deployAlacrittyConfig() - require.NoError(t, err) - require.Len(t, results, 2) - - mainResult := results[0] - assert.Equal(t, "Alacritty", mainResult.ConfigType) - assert.True(t, mainResult.Deployed) - assert.FileExists(t, mainResult.Path) - - content, err := os.ReadFile(mainResult.Path) - require.NoError(t, err) - assert.Contains(t, string(content), "~/.config/alacritty/dank-theme.toml") - assert.Contains(t, string(content), "[window]") - - themeResult := results[1] - assert.Equal(t, "Alacritty Theme", themeResult.ConfigType) - assert.True(t, themeResult.Deployed) - assert.FileExists(t, themeResult.Path) - - themeContent, err := os.ReadFile(themeResult.Path) - require.NoError(t, err) - assert.Contains(t, string(themeContent), "[colors.primary]") - assert.Contains(t, string(themeContent), "background = '#101418'") - }) - - t.Run("deploy alacritty config with existing file", func(t *testing.T) { - existingContent := "# Old alacritty config\n[window]\nopacity = 0.9\n" - alacrittyPath := filepath.Join(tempDir, ".config", "alacritty", "alacritty.toml") - err := os.MkdirAll(filepath.Dir(alacrittyPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(alacrittyPath, []byte(existingContent), 0o644) - require.NoError(t, err) - - results, err := cd.deployAlacrittyConfig() - require.NoError(t, err) - require.Len(t, results, 2) - - mainResult := results[0] - assert.True(t, mainResult.Deployed) - assert.NotEmpty(t, mainResult.BackupPath) - assert.FileExists(t, mainResult.BackupPath) - - backupContent, err := os.ReadFile(mainResult.BackupPath) - require.NoError(t, err) - assert.Equal(t, existingContent, string(backupContent)) - - newContent, err := os.ReadFile(mainResult.Path) - require.NoError(t, err) - assert.NotContains(t, string(newContent), "# Old alacritty config") - assert.Contains(t, string(newContent), "decorations = \"None\"") - }) -} - -func TestShouldReplaceConfigDeployIfMissing(t *testing.T) { - allFalse := map[string]bool{ - "Niri": false, - "Hyprland": false, - "Ghostty": false, - "Kitty": false, - "Alacritty": false, - } - - t.Run("replaceConfigs nil deploys config", func(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-replace-nil-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - results, err := cd.DeployConfigurationsSelectiveWithReinstalls( - context.Background(), - deps.WindowManagerNiri, - deps.TerminalGhostty, - nil, // installedDeps - nil, // replaceConfigs - nil, // reinstallItems - ) - require.NoError(t, err) - - // With replaceConfigs=nil, all configs should be deployed - hasDeployed := false - for _, r := range results { - if r.Deployed { - hasDeployed = true - break - } - } - assert.True(t, hasDeployed, "expected at least one config to be deployed when replaceConfigs is nil") - }) - - t.Run("replaceConfigs all false and config missing deploys config", func(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-replace-missing-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - results, err := cd.DeployConfigurationsSelectiveWithReinstalls( - context.Background(), - deps.WindowManagerNiri, - deps.TerminalGhostty, - nil, // installedDeps - allFalse, // replaceConfigs — all false - nil, // reinstallItems - ) - require.NoError(t, err) - - // Config files don't exist on disk, so they should still be deployed - hasDeployed := false - for _, r := range results { - if r.Deployed { - hasDeployed = true - break - } - } - assert.True(t, hasDeployed, "expected configs to be deployed when files are missing, even with replaceConfigs all false") - }) - - t.Run("replaceConfigs false and config exists skips config", func(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-replace-exists-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - // Create the Ghostty primary config file so shouldReplaceConfig returns false - ghosttyPath := filepath.Join(tempDir, ".config", "ghostty", "config") - err = os.MkdirAll(filepath.Dir(ghosttyPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(ghosttyPath, []byte("# existing ghostty config\n"), 0o644) - require.NoError(t, err) - - // Also create the Niri primary config file - niriPath := filepath.Join(tempDir, ".config", "niri", "config.kdl") - err = os.MkdirAll(filepath.Dir(niriPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(niriPath, []byte("// existing niri config\n"), 0o644) - require.NoError(t, err) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - results, err := cd.DeployConfigurationsSelectiveWithReinstalls( - context.Background(), - deps.WindowManagerNiri, - deps.TerminalGhostty, - nil, // installedDeps - allFalse, // replaceConfigs — all false - nil, // reinstallItems - ) - require.NoError(t, err) - - // Both Niri and Ghostty config files exist, so with all false they should be skipped - for _, r := range results { - assert.Fail(t, "expected no configs to be deployed", "got deployed config: %s", r.ConfigType) - } - }) - - t.Run("replaceConfigs true and config exists deploys config", func(t *testing.T) { - tempDir, err := os.MkdirTemp("", "dankinstall-replace-true-test") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - originalHome := os.Getenv("HOME") - os.Setenv("HOME", tempDir) - defer os.Setenv("HOME", originalHome) - - // Create the Ghostty primary config file - ghosttyPath := filepath.Join(tempDir, ".config", "ghostty", "config") - err = os.MkdirAll(filepath.Dir(ghosttyPath), 0o755) - require.NoError(t, err) - err = os.WriteFile(ghosttyPath, []byte("# existing ghostty config\n"), 0o644) - require.NoError(t, err) - - logChan := make(chan string, 100) - cd := NewConfigDeployer(logChan) - - replaceConfigs := map[string]bool{ - "Niri": false, - "Hyprland": false, - "Ghostty": true, // explicitly true - "Kitty": false, - "Alacritty": false, - } - - results, err := cd.DeployConfigurationsSelectiveWithReinstalls( - context.Background(), - deps.WindowManagerNiri, - deps.TerminalGhostty, - nil, // installedDeps - replaceConfigs, // Ghostty=true, rest=false - nil, // reinstallItems - ) - require.NoError(t, err) - - // Ghostty should be deployed because replaceConfigs["Ghostty"]=true - foundGhostty := false - for _, r := range results { - if r.ConfigType == "Ghostty" && r.Deployed { - foundGhostty = true - } - } - assert.True(t, foundGhostty, "expected Ghostty config to be deployed when replaceConfigs is true") - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/dms.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/dms.go deleted file mode 100644 index 7842fa5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/dms.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "fmt" - "os" - "path/filepath" - "strings" -) - -func LocateDMSConfig() (string, error) { - var primaryPaths []string - - configHome, err := os.UserConfigDir() - if err == nil && configHome != "" { - primaryPaths = append(primaryPaths, filepath.Join(configHome, "quickshell", "dms")) - } - - // System data directories - dataDirs := os.Getenv("XDG_DATA_DIRS") - if dataDirs == "" { - dataDirs = "/usr/local/share:/usr/share" - } - - for dir := range strings.SplitSeq(dataDirs, ":") { - if dir != "" { - primaryPaths = append(primaryPaths, filepath.Join(dir, "quickshell", "dms")) - } - } - - // System config directories (fallback) - configDirs := os.Getenv("XDG_CONFIG_DIRS") - if configDirs == "" { - configDirs = "/etc/xdg" - } - - for dir := range strings.SplitSeq(configDirs, ":") { - if dir != "" { - primaryPaths = append(primaryPaths, filepath.Join(dir, "quickshell", "dms")) - } - } - - // Build search paths with secondary (monorepo) paths interleaved - var searchPaths []string - for _, path := range primaryPaths { - searchPaths = append(searchPaths, path) - searchPaths = append(searchPaths, filepath.Join(path, "quickshell")) - } - - for _, path := range searchPaths { - shellPath := filepath.Join(path, "shell.qml") - if info, err := os.Stat(shellPath); err == nil && !info.IsDir() { - return path, nil - } - } - - return "", fmt.Errorf("could not find DMS config (shell.qml) in any valid config path") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty-theme.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty-theme.toml deleted file mode 100644 index 4048457..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty-theme.toml +++ /dev/null @@ -1,31 +0,0 @@ -[colors.primary] -background = '#101418' -foreground = '#e0e2e8' - -[colors.selection] -text = '#e0e2e8' -background = '#124a73' - -[colors.cursor] -text = '#101418' -cursor = '#9dcbfb' - -[colors.normal] -black = '#101418' -red = '#d75a59' -green = '#8ed88c' -yellow = '#e0d99d' -blue = '#4087bc' -magenta = '#839fbc' -cyan = '#9dcbfb' -white = '#abb2bf' - -[colors.bright] -black = '#5c6370' -red = '#e57e7e' -green = '#a2e5a0' -yellow = '#efe9b3' -blue = '#a7d9ff' -magenta = '#3d8197' -cyan = '#5c7ba3' -white = '#ffffff' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty.toml deleted file mode 100644 index b666177..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/alacritty.toml +++ /dev/null @@ -1,37 +0,0 @@ -[general] -import = [ - "~/.config/alacritty/dank-theme.toml" -] - -[window] -decorations = "None" -padding = { x = 12, y = 12 } -opacity = 1.0 - -[scrolling] -history = 3023 - -[cursor] -style = { shape = "Block", blinking = "On" } -blink_interval = 500 -unfocused_hollow = true - -[mouse] -hide_when_typing = true - -[selection] -save_to_clipboard = false - -[bell] -duration = 0 - -[keyboard] -bindings = [ - { key = "C", mods = "Control|Shift", action = "Copy" }, - { key = "V", mods = "Control|Shift", action = "Paste" }, - { key = "N", mods = "Control|Shift", action = "SpawnNewInstance" }, - { key = "Equals", mods = "Control|Shift", action = "IncreaseFontSize" }, - { key = "Minus", mods = "Control", action = "DecreaseFontSize" }, - { key = "Key0", mods = "Control", action = "ResetFontSize" }, - { key = "Enter", mods = "Shift", chars = "\n" }, -] diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty-colors.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty-colors.conf deleted file mode 100644 index 56dca5f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty-colors.conf +++ /dev/null @@ -1,21 +0,0 @@ -background = #101418 -foreground = #e0e2e8 -cursor-color = #9dcbfb -selection-background = #124a73 -selection-foreground = #e0e2e8 -palette = 0=#101418 -palette = 1=#d75a59 -palette = 2=#8ed88c -palette = 3=#e0d99d -palette = 4=#4087bc -palette = 5=#839fbc -palette = 6=#9dcbfb -palette = 7=#abb2bf -palette = 8=#5c6370 -palette = 9=#e57e7e -palette = 10=#a2e5a0 -palette = 11=#efe9b3 -palette = 12=#a7d9ff -palette = 13=#3d8197 -palette = 14=#5c7ba3 -palette = 15=#ffffff diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty.conf deleted file mode 100644 index 8ca05a2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/ghostty.conf +++ /dev/null @@ -1,51 +0,0 @@ -# Font Configuration -font-size = 12 - -# Window Configuration -window-decoration = false -window-padding-x = 12 -window-padding-y = 12 -background-opacity = 1.0 -background-blur-radius = 32 - -# Cursor Configuration -cursor-style = block -cursor-style-blink = true - -# Scrollback -scrollback-limit = 3023 - -# Terminal features -mouse-hide-while-typing = true -copy-on-select = false -confirm-close-surface = false - -# Disable annoying copied to clipboard -app-notifications = no-clipboard-copy,no-config-reload - -# Key bindings for common actions -#keybind = ctrl+c=copy_to_clipboard -#keybind = ctrl+v=paste_from_clipboard -keybind = ctrl+shift+n=new_window -keybind = ctrl+t=new_tab -keybind = ctrl+plus=increase_font_size:1 -keybind = ctrl+minus=decrease_font_size:1 -keybind = ctrl+zero=reset_font_size - -# Material 3 UI elements -unfocused-split-opacity = 0.7 -unfocused-split-fill = #44464f - -# Tab configuration -gtk-titlebar = false - -# Shell integration -shell-integration = detect -shell-integration-features = cursor,sudo,title,no-cursor -keybind = shift+enter=text:\n - -# Rando stuff -gtk-single-instance = true - -# Dank color generation -theme = dankcolors diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-binds.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-binds.conf deleted file mode 100644 index dfe5630..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-binds.conf +++ /dev/null @@ -1,162 +0,0 @@ -# === Application Launchers === -bind = SUPER, T, exec, {{TERMINAL_COMMAND}} -bind = SUPER, space, exec, dms ipc call spotlight toggle -bind = SUPER, V, exec, dms ipc call clipboard toggle -bind = SUPER, M, exec, dms ipc call processlist focusOrToggle -bind = SUPER, comma, exec, dms ipc call settings focusOrToggle -bind = SUPER, N, exec, dms ipc call notifications toggle -bind = SUPER SHIFT, N, exec, dms ipc call notepad toggle -bind = SUPER, Y, exec, dms ipc call dankdash wallpaper -bind = SUPER, TAB, exec, dms ipc call hypr toggleOverview -bind = SUPER, X, exec, dms ipc call powermenu toggle - -# === Cheat sheet -bind = SUPER SHIFT, Slash, exec, dms ipc call keybinds toggle hyprland - -# === Security === -bind = SUPER ALT, L, exec, dms ipc call lock lock -bind = SUPER SHIFT, E, exit -bind = CTRL ALT, Delete, exec, dms ipc call processlist focusOrToggle - -# === Audio Controls === -bindel = , XF86AudioRaiseVolume, exec, dms ipc call audio increment 3 -bindel = , XF86AudioLowerVolume, exec, dms ipc call audio decrement 3 -bindl = , XF86AudioMute, exec, dms ipc call audio mute -bindl = , XF86AudioMicMute, exec, dms ipc call audio micmute -bindl = , XF86AudioPause, exec, dms ipc call mpris playPause -bindl = , XF86AudioPlay, exec, dms ipc call mpris playPause -bindl = , XF86AudioPrev, exec, dms ipc call mpris previous -bindl = , XF86AudioNext, exec, dms ipc call mpris next -bindel = CTRL, XF86AudioRaiseVolume, exec, dms ipc call mpris increment 3 -bindel = CTRL, XF86AudioLowerVolume, exec, dms ipc call mpris decrement 3 - -# === Brightness Controls === -bindel = , XF86MonBrightnessUp, exec, dms ipc call brightness increment 5 "" -bindel = , XF86MonBrightnessDown, exec, dms ipc call brightness decrement 5 "" - -# === Window Management === -bind = SUPER, Q, killactive -bind = SUPER, F, fullscreen, 1 -bind = SUPER SHIFT, F, fullscreen, 0 -bind = SUPER SHIFT, T, togglefloating -bind = SUPER, W, togglegroup -bind = SUPER SHIFT, W, exec, dms ipc call window-rules toggle - -# === Focus Navigation === -bind = SUPER, left, movefocus, l -bind = SUPER, down, movefocus, d -bind = SUPER, up, movefocus, u -bind = SUPER, right, movefocus, r -bind = SUPER, H, movefocus, l -bind = SUPER, J, movefocus, d -bind = SUPER, K, movefocus, u -bind = SUPER, L, movefocus, r - -# === Window Movement === -bind = SUPER SHIFT, left, movewindow, l -bind = SUPER SHIFT, down, movewindow, d -bind = SUPER SHIFT, up, movewindow, u -bind = SUPER SHIFT, right, movewindow, r -bind = SUPER SHIFT, H, movewindow, l -bind = SUPER SHIFT, J, movewindow, d -bind = SUPER SHIFT, K, movewindow, u -bind = SUPER SHIFT, L, movewindow, r - -# === Column Navigation === -bind = SUPER, Home, focuswindow, first -bind = SUPER, End, focuswindow, last - -# === Monitor Navigation === -bind = SUPER CTRL, left, focusmonitor, l -bind = SUPER CTRL, right, focusmonitor, r -bind = SUPER CTRL, H, focusmonitor, l -bind = SUPER CTRL, J, focusmonitor, d -bind = SUPER CTRL, K, focusmonitor, u -bind = SUPER CTRL, L, focusmonitor, r - -# === Move to Monitor === -bind = SUPER SHIFT CTRL, left, movewindow, mon:l -bind = SUPER SHIFT CTRL, down, movewindow, mon:d -bind = SUPER SHIFT CTRL, up, movewindow, mon:u -bind = SUPER SHIFT CTRL, right, movewindow, mon:r -bind = SUPER SHIFT CTRL, H, movewindow, mon:l -bind = SUPER SHIFT CTRL, J, movewindow, mon:d -bind = SUPER SHIFT CTRL, K, movewindow, mon:u -bind = SUPER SHIFT CTRL, L, movewindow, mon:r - -# === Workspace Navigation === -bind = SUPER, Page_Down, workspace, e+1 -bind = SUPER, Page_Up, workspace, e-1 -bind = SUPER, U, workspace, e+1 -bind = SUPER, I, workspace, e-1 -bind = SUPER CTRL, down, movetoworkspace, e+1 -bind = SUPER CTRL, up, movetoworkspace, e-1 -bind = SUPER CTRL, U, movetoworkspace, e+1 -bind = SUPER CTRL, I, movetoworkspace, e-1 - -# === Workspace Management === -bind = CTRL SHIFT, R, exec, dms ipc call workspace-rename open - -# === Move Workspaces === -bind = SUPER SHIFT, Page_Down, movetoworkspace, e+1 -bind = SUPER SHIFT, Page_Up, movetoworkspace, e-1 -bind = SUPER SHIFT, U, movetoworkspace, e+1 -bind = SUPER SHIFT, I, movetoworkspace, e-1 - -# === Mouse Wheel Navigation === -bind = SUPER, mouse_down, workspace, e+1 -bind = SUPER, mouse_up, workspace, e-1 -bind = SUPER CTRL, mouse_down, movetoworkspace, e+1 -bind = SUPER CTRL, mouse_up, movetoworkspace, e-1 - -# === Numbered Workspaces === -bind = SUPER, 1, workspace, 1 -bind = SUPER, 2, workspace, 2 -bind = SUPER, 3, workspace, 3 -bind = SUPER, 4, workspace, 4 -bind = SUPER, 5, workspace, 5 -bind = SUPER, 6, workspace, 6 -bind = SUPER, 7, workspace, 7 -bind = SUPER, 8, workspace, 8 -bind = SUPER, 9, workspace, 9 - -# === Move to Numbered Workspaces === -bind = SUPER SHIFT, 1, movetoworkspace, 1 -bind = SUPER SHIFT, 2, movetoworkspace, 2 -bind = SUPER SHIFT, 3, movetoworkspace, 3 -bind = SUPER SHIFT, 4, movetoworkspace, 4 -bind = SUPER SHIFT, 5, movetoworkspace, 5 -bind = SUPER SHIFT, 6, movetoworkspace, 6 -bind = SUPER SHIFT, 7, movetoworkspace, 7 -bind = SUPER SHIFT, 8, movetoworkspace, 8 -bind = SUPER SHIFT, 9, movetoworkspace, 9 - -# === Column Management === -bind = SUPER, bracketleft, layoutmsg, preselect l -bind = SUPER, bracketright, layoutmsg, preselect r - -# === Sizing & Layout === -bind = SUPER, R, layoutmsg, togglesplit -bind = SUPER CTRL, F, resizeactive, exact 100% 100% - -# === Move/resize windows with mainMod + LMB/RMB and dragging === -bindmd = SUPER, mouse:272, Move window, movewindow -bindmd = SUPER, mouse:273, Resize window, resizewindow - -# === Move/resize windows with mainMod + LMB/RMB and dragging === -bindd = SUPER, code:20, Expand window left, resizeactive, -100 0 -bindd = SUPER, code:21, Shrink window left, resizeactive, 100 0 - -# === Manual Sizing === -binde = SUPER, minus, resizeactive, -10% 0 -binde = SUPER, equal, resizeactive, 10% 0 -binde = SUPER SHIFT, minus, resizeactive, 0 -10% -binde = SUPER SHIFT, equal, resizeactive, 0 10% - -# === Screenshots === -bind = , Print, exec, dms screenshot -bind = CTRL, Print, exec, dms screenshot full -bind = ALT, Print, exec, dms screenshot window - -# === System Controls === -bind = SUPER SHIFT, P, dpms, toggle diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-colors.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-colors.conf deleted file mode 100644 index 38bcb0e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-colors.conf +++ /dev/null @@ -1,25 +0,0 @@ -# ! Auto-generated file. Do not edit directly. -# Remove source = ./dms/colors.conf from your config to override. - -$primary = rgb(d0bcff) -$outline = rgb(948f99) -$error = rgb(f2b8b5) - -general { - col.active_border = $primary - col.inactive_border = $outline -} - -group { - col.border_active = $primary - col.border_inactive = $outline - col.border_locked_active = $error - col.border_locked_inactive = $outline - - groupbar { - col.active = $primary - col.inactive = $outline - col.locked_active = $error - col.locked_inactive = $outline - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-layout.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-layout.conf deleted file mode 100644 index b9a8ad9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hypr-layout.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Auto-generated by DMS - do not edit manually - -general { - gaps_in = 4 - gaps_out = 4 - border_size = 2 -} - -decoration { - rounding = 12 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hyprland.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hyprland.conf deleted file mode 100644 index f4e7a03..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/hyprland.conf +++ /dev/null @@ -1,121 +0,0 @@ -# Hyprland Configuration -# https://wiki.hypr.land/Configuring/ - -# ================== -# MONITOR CONFIG -# ================== -# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1 -monitor = , preferred,auto,auto - -# ================== -# STARTUP APPS -# ================== -exec-once = dbus-update-activation-environment --systemd --all -exec-once = systemctl --user start hyprland-session.target - -# ================== -# INPUT CONFIG -# ================== -input { - kb_layout = us - numlock_by_default = true -} - -# ================== -# GENERAL LAYOUT -# ================== -general { - gaps_in = 5 - gaps_out = 5 - border_size = 2 - - layout = dwindle -} - -# ================== -# DECORATION -# ================== -decoration { - rounding = 12 - - active_opacity = 1.0 - inactive_opacity = 1.0 - - shadow { - enabled = true - range = 30 - render_power = 5 - offset = 0 5 - color = rgba(00000070) - } -} - -# ================== -# ANIMATIONS -# ================== -animations { - enabled = true - - animation = windowsIn, 1, 3, default - animation = windowsOut, 1, 3, default - animation = workspaces, 1, 5, default - animation = windowsMove, 1, 4, default - animation = fade, 1, 3, default - animation = border, 1, 3, default -} - -# ================== -# LAYOUTS -# ================== -dwindle { - preserve_split = true -} - -master { - mfact = 0.5 -} - -# ================== -# MISC -# ================== -misc { - disable_hyprland_logo = true - disable_splash_rendering = true -} - -# ================== -# WINDOW RULES -# ================== -windowrule = tile on, match:class ^(org\.wezfurlong\.wezterm)$ - -windowrule = rounding 12, match:class ^(org\.gnome\.) - -windowrule = tile on, match:class ^(gnome-control-center)$ -windowrule = tile on, match:class ^(pavucontrol)$ -windowrule = tile on, match:class ^(nm-connection-editor)$ - -windowrule = float on, match:class ^(org\.gnome\.Calculator)$ -windowrule = float on, match:class ^(gnome-calculator)$ -windowrule = float on, match:class ^(galculator)$ -windowrule = float on, match:class ^(blueman-manager)$ -windowrule = float on, match:class ^(org\.gnome\.Nautilus)$ -windowrule = float on, match:class ^(xdg-desktop-portal)$ - -windowrule = no_initial_focus on, match:class ^(steam)$, match:title ^(notificationtoasts) -windowrule = pin on, match:class ^(steam)$, match:title ^(notificationtoasts) - -windowrule = float on, match:class ^(firefox)$, match:title ^(Picture-in-Picture)$ -windowrule = float on, match:class ^(zoom)$ - -# DMS windows floating by default -# ! Hyprland doesn't size these windows correctly so disabling by default here -# windowrule = float on, match:class ^(org.quickshell)$ - -layerrule = no_anim on, match:namespace ^(quickshell)$ -layerrule = no_anim on, match:namespace ^dms:.* - -source = ./dms/colors.conf -source = ./dms/outputs.conf -source = ./dms/layout.conf -source = ./dms/cursor.conf -source = ./dms/binds.conf diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-tabs.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-tabs.conf deleted file mode 100644 index b2305c8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-tabs.conf +++ /dev/null @@ -1,24 +0,0 @@ -tab_bar_edge top -tab_bar_style powerline -tab_powerline_style slanted -tab_bar_align left -tab_bar_min_tabs 2 -tab_bar_margin_width 0.0 -tab_bar_margin_height 2.5 1.5 -tab_bar_margin_color #101418 - -tab_bar_background #101418 - -active_tab_foreground #cfe5ff -active_tab_background #124a73 -active_tab_font_style bold - -inactive_tab_foreground #c2c7cf -inactive_tab_background #101418 -inactive_tab_font_style normal - -tab_activity_symbol " ● " -tab_numbers_style 1 - -tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]" -active_tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-theme.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-theme.conf deleted file mode 100644 index 2587bcf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty-theme.conf +++ /dev/null @@ -1,24 +0,0 @@ -cursor #e0e2e8 -cursor_text_color #c2c7cf - -foreground #e0e2e8 -background #101418 -selection_foreground #243240 -selection_background #b9c8da -url_color #9dcbfb -color0 #101418 -color1 #d75a59 -color2 #8ed88c -color3 #e0d99d -color4 #4087bc -color5 #839fbc -color6 #9dcbfb -color7 #abb2bf -color8 #5c6370 -color9 #e57e7e -color10 #a2e5a0 -color11 #efe9b3 -color12 #a7d9ff -color13 #3d8197 -color14 #5c7ba3 -color15 #ffffff diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty.conf deleted file mode 100644 index 2ae96a0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/kitty.conf +++ /dev/null @@ -1,37 +0,0 @@ -# Font Configuration -font_size 12.0 - -# Window Configuration -window_padding_width 12 -background_opacity 1.0 -background_blur 32 -hide_window_decorations yes - -# Cursor Configuration -cursor_shape block -cursor_blink_interval 1 - -# Scrollback -scrollback_lines 3000 - -# Terminal features -copy_on_select yes -strip_trailing_spaces smart - -# Key bindings for common actions -map ctrl+shift+n new_window -map ctrl+t new_tab -map ctrl+plus change_font_size all +1.0 -map ctrl+minus change_font_size all -1.0 -map ctrl+0 change_font_size all 0 - -# Tab configuration -tab_bar_style powerline -tab_bar_align left - -# Shell integration -shell_integration enabled - -# Dank color generation -include dank-tabs.conf -include dank-theme.conf diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-alttab.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-alttab.kdl deleted file mode 100644 index 5f9bdcd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-alttab.kdl +++ /dev/null @@ -1,10 +0,0 @@ -// ! DO NOT EDIT ! -// ! AUTO-GENERATED BY DMS ! -// ! CHANGES WILL BE OVERWRITTEN ! -// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE ! - -recent-windows { - highlight { - corner-radius 12 - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-binds.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-binds.kdl deleted file mode 100644 index 27cb860..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-binds.kdl +++ /dev/null @@ -1,221 +0,0 @@ -binds { - // === System & Overview === - Mod+D repeat=false { toggle-overview; } - Mod+Tab repeat=false { toggle-overview; } - Mod+Shift+Slash { show-hotkey-overlay; } - - // === Application Launchers === - Mod+T hotkey-overlay-title="Open Terminal" { spawn "{{TERMINAL_COMMAND}}"; } - Mod+Space hotkey-overlay-title="Application Launcher" { - spawn "dms" "ipc" "call" "spotlight" "toggle"; - } - Mod+V hotkey-overlay-title="Clipboard Manager" { - spawn "dms" "ipc" "call" "clipboard" "toggle"; - } - Mod+M hotkey-overlay-title="Task Manager" { - spawn "dms" "ipc" "call" "processlist" "focusOrToggle"; - } - - Super+X hotkey-overlay-title="Power Menu: Toggle" { spawn "dms" "ipc" "call" "powermenu" "toggle"; } - Mod+Comma hotkey-overlay-title="Settings" { - spawn "dms" "ipc" "call" "settings" "focusOrToggle"; - } - Mod+Y hotkey-overlay-title="Browse Wallpapers" { - spawn "dms" "ipc" "call" "dankdash" "wallpaper"; - } - Mod+N hotkey-overlay-title="Notification Center" { spawn "dms" "ipc" "call" "notifications" "toggle"; } - Mod+Shift+N hotkey-overlay-title="Notepad" { spawn "dms" "ipc" "call" "notepad" "toggle"; } - - // === Security === - Mod+Alt+L hotkey-overlay-title="Lock Screen" { - spawn "dms" "ipc" "call" "lock" "lock"; - } - Mod+Shift+E { quit; } - Ctrl+Alt+Delete hotkey-overlay-title="Task Manager" { - spawn "dms" "ipc" "call" "processlist" "focusOrToggle"; - } - - // === Audio Controls === - XF86AudioRaiseVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "increment" "3"; - } - XF86AudioLowerVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "decrement" "3"; - } - XF86AudioMute allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "mute"; - } - XF86AudioMicMute allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "micmute"; - } - XF86AudioPause allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "playPause"; - } - XF86AudioPlay allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "playPause"; - } - XF86AudioPrev allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "previous"; - } - XF86AudioNext allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "next"; - } - Ctrl+XF86AudioRaiseVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "increment" "3"; - } - Ctrl+XF86AudioLowerVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "mpris" "decrement" "3"; - } - - // === Brightness Controls === - XF86MonBrightnessUp allow-when-locked=true { - spawn "dms" "ipc" "call" "brightness" "increment" "5" ""; - } - XF86MonBrightnessDown allow-when-locked=true { - spawn "dms" "ipc" "call" "brightness" "decrement" "5" ""; - } - - // === Window Management === - Mod+Q repeat=false { close-window; } - Mod+F { maximize-column; } - Mod+Shift+F { fullscreen-window; } - Mod+Shift+T { toggle-window-floating; } - Mod+Shift+V { switch-focus-between-floating-and-tiling; } - Mod+W { toggle-column-tabbed-display; } - Mod+Shift+W hotkey-overlay-title="Create window rule" { spawn "dms" "ipc" "call" "window-rules" "toggle"; } - - // === Focus Navigation === - Mod+Left { focus-column-left; } - Mod+Down { focus-window-down; } - Mod+Up { focus-window-up; } - Mod+Right { focus-column-right; } - Mod+H { focus-column-left; } - Mod+J { focus-window-down; } - Mod+K { focus-window-up; } - Mod+L { focus-column-right; } - - // === Window Movement === - Mod+Shift+Left { move-column-left; } - Mod+Shift+Down { move-window-down; } - Mod+Shift+Up { move-window-up; } - Mod+Shift+Right { move-column-right; } - Mod+Shift+H { move-column-left; } - Mod+Shift+J { move-window-down; } - Mod+Shift+K { move-window-up; } - Mod+Shift+L { move-column-right; } - - // === Column Navigation === - Mod+Home { focus-column-first; } - Mod+End { focus-column-last; } - Mod+Ctrl+Home { move-column-to-first; } - Mod+Ctrl+End { move-column-to-last; } - - // === Monitor Navigation === - Mod+Ctrl+Left { focus-monitor-left; } - //Mod+Ctrl+Down { focus-monitor-down; } - //Mod+Ctrl+Up { focus-monitor-up; } - Mod+Ctrl+Right { focus-monitor-right; } - Mod+Ctrl+H { focus-monitor-left; } - Mod+Ctrl+J { focus-monitor-down; } - Mod+Ctrl+K { focus-monitor-up; } - Mod+Ctrl+L { focus-monitor-right; } - - // === Move to Monitor === - Mod+Shift+Ctrl+Left { move-column-to-monitor-left; } - Mod+Shift+Ctrl+Down { move-column-to-monitor-down; } - Mod+Shift+Ctrl+Up { move-column-to-monitor-up; } - Mod+Shift+Ctrl+Right { move-column-to-monitor-right; } - Mod+Shift+Ctrl+H { move-column-to-monitor-left; } - Mod+Shift+Ctrl+J { move-column-to-monitor-down; } - Mod+Shift+Ctrl+K { move-column-to-monitor-up; } - Mod+Shift+Ctrl+L { move-column-to-monitor-right; } - - // === Workspace Navigation === - Mod+Page_Down { focus-workspace-down; } - Mod+Page_Up { focus-workspace-up; } - Mod+U { focus-workspace-down; } - Mod+I { focus-workspace-up; } - Mod+Ctrl+Down { move-column-to-workspace-down; } - Mod+Ctrl+Up { move-column-to-workspace-up; } - Mod+Ctrl+U { move-column-to-workspace-down; } - Mod+Ctrl+I { move-column-to-workspace-up; } - - // === Workspace Management === - Ctrl+Shift+R hotkey-overlay-title="Rename Workspace" { - spawn "dms" "ipc" "call" "workspace-rename" "open"; - } - - // === Move Workspaces === - Mod+Shift+Page_Down { move-workspace-down; } - Mod+Shift+Page_Up { move-workspace-up; } - Mod+Shift+U { move-workspace-down; } - Mod+Shift+I { move-workspace-up; } - - // === Mouse Wheel Navigation === - Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; } - Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; } - Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; } - Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; } - - Mod+WheelScrollRight { focus-column-right; } - Mod+WheelScrollLeft { focus-column-left; } - Mod+Ctrl+WheelScrollRight { move-column-right; } - Mod+Ctrl+WheelScrollLeft { move-column-left; } - - Mod+Shift+WheelScrollDown { focus-column-right; } - Mod+Shift+WheelScrollUp { focus-column-left; } - Mod+Ctrl+Shift+WheelScrollDown { move-column-right; } - Mod+Ctrl+Shift+WheelScrollUp { move-column-left; } - - // === Numbered Workspaces === - Mod+1 { focus-workspace 1; } - Mod+2 { focus-workspace 2; } - Mod+3 { focus-workspace 3; } - Mod+4 { focus-workspace 4; } - Mod+5 { focus-workspace 5; } - Mod+6 { focus-workspace 6; } - Mod+7 { focus-workspace 7; } - Mod+8 { focus-workspace 8; } - Mod+9 { focus-workspace 9; } - - // === Move to Numbered Workspaces === - Mod+Shift+1 { move-column-to-workspace 1; } - Mod+Shift+2 { move-column-to-workspace 2; } - Mod+Shift+3 { move-column-to-workspace 3; } - Mod+Shift+4 { move-column-to-workspace 4; } - Mod+Shift+5 { move-column-to-workspace 5; } - Mod+Shift+6 { move-column-to-workspace 6; } - Mod+Shift+7 { move-column-to-workspace 7; } - Mod+Shift+8 { move-column-to-workspace 8; } - Mod+Shift+9 { move-column-to-workspace 9; } - - // === Column Management === - Mod+BracketLeft { consume-or-expel-window-left; } - Mod+BracketRight { consume-or-expel-window-right; } - Mod+Period { expel-window-from-column; } - - // === Sizing & Layout === - Mod+R { switch-preset-column-width; } - Mod+Shift+R { switch-preset-window-height; } - Mod+Ctrl+R { reset-window-height; } - Mod+Ctrl+F { expand-column-to-available-width; } - Mod+C { center-column; } - Mod+Ctrl+C { center-visible-columns; } - - // === Manual Sizing === - Mod+Minus { set-column-width "-10%"; } - Mod+Equal { set-column-width "+10%"; } - Mod+Shift+Minus { set-window-height "-10%"; } - Mod+Shift+Equal { set-window-height "+10%"; } - - // === Screenshots === - XF86Launch1 { screenshot; } - Ctrl+XF86Launch1 { screenshot-screen; } - Alt+XF86Launch1 { screenshot-window; } - Print { screenshot; } - Ctrl+Print { screenshot-screen; } - Alt+Print { screenshot-window; } - // === System Controls === - Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } - Mod+Shift+P { power-off-monitors; } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-colors.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-colors.kdl deleted file mode 100644 index 145a179..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-colors.kdl +++ /dev/null @@ -1,39 +0,0 @@ -// ! Auto-generated file. Do not edit directly. -// Remove `include "dms/colors.kdl"` from your config to override. - -layout { - background-color "transparent" - - focus-ring { - active-color "#d0bcff" - inactive-color "#948f99" - urgent-color "#f2b8b5" - } - - border { - active-color "#d0bcff" - inactive-color "#948f99" - urgent-color "#f2b8b5" - } - - shadow { - color "#00000070" - } - - tab-indicator { - active-color "#d0bcff" - inactive-color "#948f99" - urgent-color "#f2b8b5" - } - - insert-hint { - color "#d0bcff80" - } -} - -recent-windows { - highlight { - active-color "#4f378b" - urgent-color "#f2b8b5" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-greeter.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-greeter.kdl deleted file mode 100644 index 5653a16..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-greeter.kdl +++ /dev/null @@ -1,17 +0,0 @@ -hotkey-overlay { - skip-at-startup -} - -environment { - DMS_RUN_GREETER "1" -} - -gestures { - hot-corners { - off - } -} - -layout { - background-color "#000000" -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-layout.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-layout.kdl deleted file mode 100644 index 1951500..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri-layout.kdl +++ /dev/null @@ -1,22 +0,0 @@ -// ! DO NOT EDIT ! -// ! AUTO-GENERATED BY DMS ! -// ! CHANGES WILL BE OVERWRITTEN ! -// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE ! - -layout { - gaps 4 - - border { - width 2 - } - - focus-ring { - width 2 - } -} -window-rule { - geometry-corner-radius 12 - clip-to-geometry true - tiled-state true - draw-border-with-background false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri.kdl deleted file mode 100644 index 0a759e4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/niri.kdl +++ /dev/null @@ -1,279 +0,0 @@ -// This config is in the KDL format: https://kdl.dev -// "/-" comments out the following node. -// Check the wiki for a full description of the configuration: -// https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction -config-notification { - disable-failed -} - -gestures { - hot-corners { - off - } -} - -// Input device configuration. -// Find the full list of options on the wiki: -// https://github.com/YaLTeR/niri/wiki/Configuration:-Input -input { - keyboard { - xkb { - // You can set rules, model, layout, variant and options. - // For more information, see xkeyboard-config(7). - - // For example: - // layout "us,ru" - // options "grp:win_space_toggle,compose:ralt,ctrl:nocaps" - - // If this section is empty, niri will fetch xkb settings - // from org.freedesktop.locale1. You can control these using - // localectl set-x11-keymap. - } - - // Enable numlock on startup, omitting this setting disables it. - numlock - } - - // Next sections include libinput settings. - // Omitting settings disables them, or leaves them at their default values. - // All commented-out settings here are examples, not defaults. - touchpad { - // off - tap - // dwt - // dwtp - // drag false - // drag-lock - natural-scroll - // accel-speed 0.2 - // accel-profile "flat" - // scroll-method "two-finger" - // disabled-on-external-mouse - } - - mouse { - // off - // natural-scroll - // accel-speed 0.2 - // accel-profile "flat" - // scroll-method "no-scroll" - } - - trackpoint { - // off - // natural-scroll - // accel-speed 0.2 - // accel-profile "flat" - // scroll-method "on-button-down" - // scroll-button 273 - // scroll-button-lock - // middle-emulation - } - - // Uncomment this to make the mouse warp to the center of newly focused windows. - // warp-mouse-to-focus - - // Focus windows and outputs automatically when moving the mouse into them. - // Setting max-scroll-amount="0%" makes it work only on windows already fully on screen. - // focus-follows-mouse max-scroll-amount="0%" -} -// You can configure outputs by their name, which you can find -// by running `niri msg outputs` while inside a niri instance. -// The built-in laptop monitor is usually called "eDP-1". -// Find more information on the wiki: -// https://github.com/YaLTeR/niri/wiki/Configuration:-Outputs -// Remember to uncomment the node by removing "/-"! -/-output "eDP-2" { - mode "2560x1600@239.998993" - position x=2560 y=0 - variable-refresh-rate -} -// Settings that influence how windows are positioned and sized. -// Find more information on the wiki: -// https://github.com/YaLTeR/niri/wiki/Configuration:-Layout -layout { - // Set gaps around windows in logical pixels. - background-color "transparent" - // When to center a column when changing focus, options are: - // - "never", default behavior, focusing an off-screen column will keep at the left - // or right edge of the screen. - // - "always", the focused column will always be centered. - // - "on-overflow", focusing a column will center it if it doesn't fit - // together with the previously focused column. - center-focused-column "never" - // You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between. - preset-column-widths { - // Proportion sets the width as a fraction of the output width, taking gaps into account. - // For example, you can perfectly fit four windows sized "proportion 0.25" on an output. - // The default preset widths are 1/3, 1/2 and 2/3 of the output. - proportion 0.33333 - proportion 0.5 - proportion 0.66667 - // Fixed sets the width in logical pixels exactly. - // fixed 1920 - } - // You can also customize the heights that "switch-preset-window-height" (Mod+Shift+R) toggles between. - // preset-window-heights { } - // You can change the default width of the new windows. - default-column-width { proportion 0.5; } - // If you leave the brackets empty, the windows themselves will decide their initial width. - // default-column-width {} - // By default focus ring and border are rendered as a solid background rectangle - // behind windows. That is, they will show up through semitransparent windows. - // This is because windows using client-side decorations can have an arbitrary shape. - // - // If you don't like that, you should uncomment `prefer-no-csd` below. - // Niri will draw focus ring and border *around* windows that agree to omit their - // client-side decorations. - // - // Alternatively, you can override it with a window rule called - // `draw-border-with-background`. - border { - off - width 4 - active-color "#707070" // Neutral gray - inactive-color "#d0d0d0" // Light gray - urgent-color "#cc4444" // Softer red - } - shadow { - softness 30 - spread 5 - offset x=0 y=5 - color "#0007" - } - struts { - } -} -layer-rule { - match namespace="^quickshell$" - place-within-backdrop true -} -overview { - workspace-shadow { - off - } -} -// Add lines like this to spawn processes at startup. -// Note that running niri as a session supports xdg-desktop-autostart, -// which may be more convenient to use. -// See the binds section below for more spawn examples. -// This line starts waybar, a commonly used bar for Wayland compositors. -environment { - XDG_CURRENT_DESKTOP "niri" -} -hotkey-overlay { - skip-at-startup -} -prefer-no-csd -screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" -animations { - workspace-switch { - spring damping-ratio=0.80 stiffness=523 epsilon=0.0001 - } - window-open { - duration-ms 150 - curve "ease-out-expo" - } - window-close { - duration-ms 150 - curve "ease-out-quad" - } - horizontal-view-movement { - spring damping-ratio=0.85 stiffness=423 epsilon=0.0001 - } - window-movement { - spring damping-ratio=0.75 stiffness=323 epsilon=0.0001 - } - window-resize { - spring damping-ratio=0.85 stiffness=423 epsilon=0.0001 - } - config-notification-open-close { - spring damping-ratio=0.65 stiffness=923 epsilon=0.001 - } - screenshot-ui-open { - duration-ms 200 - curve "ease-out-quad" - } - overview-open-close { - spring damping-ratio=0.85 stiffness=800 epsilon=0.0001 - } -} -// Window rules let you adjust behavior for individual windows. -// Find more information on the wiki: -// https://github.com/YaLTeR/niri/wiki/Configuration:-Window-Rules -// Work around WezTerm's initial configure bug -// by setting an empty default-column-width. -window-rule { - // This regular expression is intentionally made as specific as possible, - // since this is the default config, and we want no false positives. - // You can get away with just app-id="wezterm" if you want. - match app-id=r#"^org\.wezfurlong\.wezterm$"# - default-column-width {} -} -window-rule { - match app-id=r#"^org\.gnome\."# - draw-border-with-background false - geometry-corner-radius 12 - clip-to-geometry true -} -window-rule { - match app-id=r#"^gnome-control-center$"# - match app-id=r#"^pavucontrol$"# - match app-id=r#"^nm-connection-editor$"# - default-column-width { proportion 0.5; } - open-floating false -} -window-rule { - match app-id=r#"^org\.gnome\.Calculator$"# - match app-id=r#"^gnome-calculator$"# - match app-id=r#"^galculator$"# - match app-id=r#"^blueman-manager$"# - match app-id=r#"^org\.gnome\.Nautilus$"# - match app-id=r#"^xdg-desktop-portal$"# - open-floating true -} -window-rule { - match app-id=r#"^steam$"# title=r#"^notificationtoasts_\d+_desktop$"# - default-floating-position x=10 y=10 relative-to="bottom-right" - open-focused false -} -window-rule { - match app-id=r#"^org\.wezfurlong\.wezterm$"# - match app-id="Alacritty" - match app-id="zen" - match app-id="com.mitchellh.ghostty" - match app-id="kitty" - draw-border-with-background false -} -window-rule { - match app-id=r#"firefox$"# title="^Picture-in-Picture$" - match app-id="zoom" - open-floating true -} -// Open dms windows as floating by default -window-rule { - match app-id=r#"org.quickshell$"# - match app-id=r#"com.danklinux.dms$"# - open-floating true -} -debug { - honor-xdg-activation-with-invalid-serial -} - -// Override to disable super+tab -recent-windows { - binds { - Alt+Tab { next-window scope="output"; } - Alt+Shift+Tab { previous-window scope="output"; } - Alt+grave { next-window filter="app-id"; } - Alt+Shift+grave { previous-window filter="app-id"; } - } -} - -// Include dms files -include "dms/colors.kdl" -include "dms/layout.kdl" -include "dms/alttab.kdl" -include "dms/binds.kdl" -include "dms/outputs.kdl" -include "dms/cursor.kdl" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/testpage.pdf b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/testpage.pdf deleted file mode 100644 index 03e05c4..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/embedded/testpage.pdf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/hyprland.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/hyprland.go deleted file mode 100644 index f6bb964..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/hyprland.go +++ /dev/null @@ -1,15 +0,0 @@ -package config - -import _ "embed" - -//go:embed embedded/hyprland.conf -var HyprlandConfig string - -//go:embed embedded/hypr-colors.conf -var HyprColorsConfig string - -//go:embed embedded/hypr-layout.conf -var HyprLayoutConfig string - -//go:embed embedded/hypr-binds.conf -var HyprBindsConfig string diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/niri.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/niri.go deleted file mode 100644 index 01801ca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/niri.go +++ /dev/null @@ -1,21 +0,0 @@ -package config - -import _ "embed" - -//go:embed embedded/niri.kdl -var NiriConfig string - -//go:embed embedded/niri-colors.kdl -var NiriColorsConfig string - -//go:embed embedded/niri-layout.kdl -var NiriLayoutConfig string - -//go:embed embedded/niri-alttab.kdl -var NiriAlttabConfig string - -//go:embed embedded/niri-binds.kdl -var NiriBindsConfig string - -//go:embed embedded/niri-greeter.kdl -var NiriGreeterConfig string diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/terminals.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/terminals.go deleted file mode 100644 index a5bba04..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/terminals.go +++ /dev/null @@ -1,24 +0,0 @@ -package config - -import _ "embed" - -//go:embed embedded/ghostty.conf -var GhosttyConfig string - -//go:embed embedded/ghostty-colors.conf -var GhosttyColorConfig string - -//go:embed embedded/kitty.conf -var KittyConfig string - -//go:embed embedded/kitty-theme.conf -var KittyThemeConfig string - -//go:embed embedded/kitty-tabs.conf -var KittyTabsConfig string - -//go:embed embedded/alacritty.toml -var AlacrittyConfig string - -//go:embed embedded/alacritty-theme.toml -var AlacrittyThemeConfig string diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/testpage.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/testpage.go deleted file mode 100644 index 2c5bbc7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/config/testpage.go +++ /dev/null @@ -1,6 +0,0 @@ -package config - -import _ "embed" - -//go:embed embedded/testpage.pdf -var TestPage string diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16.go deleted file mode 100644 index fedd783..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16.go +++ /dev/null @@ -1,651 +0,0 @@ -package dank16 - -import ( - "fmt" - "math" - - "github.com/lucasb-eyer/go-colorful" -) - -type RGB struct { - R, G, B float64 -} - -type HSV struct { - H, S, V float64 -} - -type ColorInfo struct { - Hex string `json:"hex"` - HexStripped string `json:"hex_stripped"` - R int `json:"r"` - G int `json:"g"` - B int `json:"b"` -} - -type VariantColorValue struct { - Hex string `json:"hex"` - HexStripped string `json:"hex_stripped"` -} - -type VariantColorInfo struct { - Dark VariantColorValue `json:"dark"` - Light VariantColorValue `json:"light"` - Default VariantColorValue `json:"default"` -} - -type Palette struct { - Color0 ColorInfo `json:"color0"` - Color1 ColorInfo `json:"color1"` - Color2 ColorInfo `json:"color2"` - Color3 ColorInfo `json:"color3"` - Color4 ColorInfo `json:"color4"` - Color5 ColorInfo `json:"color5"` - Color6 ColorInfo `json:"color6"` - Color7 ColorInfo `json:"color7"` - Color8 ColorInfo `json:"color8"` - Color9 ColorInfo `json:"color9"` - Color10 ColorInfo `json:"color10"` - Color11 ColorInfo `json:"color11"` - Color12 ColorInfo `json:"color12"` - Color13 ColorInfo `json:"color13"` - Color14 ColorInfo `json:"color14"` - Color15 ColorInfo `json:"color15"` -} - -type VariantPalette struct { - Color0 VariantColorInfo `json:"color0"` - Color1 VariantColorInfo `json:"color1"` - Color2 VariantColorInfo `json:"color2"` - Color3 VariantColorInfo `json:"color3"` - Color4 VariantColorInfo `json:"color4"` - Color5 VariantColorInfo `json:"color5"` - Color6 VariantColorInfo `json:"color6"` - Color7 VariantColorInfo `json:"color7"` - Color8 VariantColorInfo `json:"color8"` - Color9 VariantColorInfo `json:"color9"` - Color10 VariantColorInfo `json:"color10"` - Color11 VariantColorInfo `json:"color11"` - Color12 VariantColorInfo `json:"color12"` - Color13 VariantColorInfo `json:"color13"` - Color14 VariantColorInfo `json:"color14"` - Color15 VariantColorInfo `json:"color15"` -} - -func NewColorInfo(hex string) ColorInfo { - rgb := HexToRGB(hex) - stripped := hex - if len(hex) > 0 && hex[0] == '#' { - stripped = hex[1:] - } - return ColorInfo{ - Hex: hex, - HexStripped: stripped, - R: int(math.Round(rgb.R * 255)), - G: int(math.Round(rgb.G * 255)), - B: int(math.Round(rgb.B * 255)), - } -} - -func HexToRGB(hex string) RGB { - if hex[0] == '#' { - hex = hex[1:] - } - var r, g, b uint8 - fmt.Sscanf(hex, "%02x%02x%02x", &r, &g, &b) - return RGB{ - R: float64(r) / 255.0, - G: float64(g) / 255.0, - B: float64(b) / 255.0, - } -} - -func RGBToHex(rgb RGB) string { - r := math.Max(0, math.Min(1, rgb.R)) - g := math.Max(0, math.Min(1, rgb.G)) - b := math.Max(0, math.Min(1, rgb.B)) - return fmt.Sprintf("#%02x%02x%02x", int(r*255), int(g*255), int(b*255)) -} - -func RGBToHSV(rgb RGB) HSV { - max := math.Max(math.Max(rgb.R, rgb.G), rgb.B) - min := math.Min(math.Min(rgb.R, rgb.G), rgb.B) - delta := max - min - - var h float64 - switch { - case delta == 0: - h = 0 - case max == rgb.R: - h = math.Mod((rgb.G-rgb.B)/delta, 6.0) / 6.0 - case max == rgb.G: - h = ((rgb.B-rgb.R)/delta + 2.0) / 6.0 - default: - h = ((rgb.R-rgb.G)/delta + 4.0) / 6.0 - } - - if h < 0 { - h += 1.0 - } - - var s float64 - if max == 0 { - s = 0 - } else { - s = delta / max - } - - return HSV{H: h, S: s, V: max} -} - -func HSVToRGB(hsv HSV) RGB { - h := hsv.H * 6.0 - c := hsv.V * hsv.S - x := c * (1.0 - math.Abs(math.Mod(h, 2.0)-1.0)) - m := hsv.V - c - - var r, g, b float64 - switch int(h) { - case 0: - r, g, b = c, x, 0 - case 1: - r, g, b = x, c, 0 - case 2: - r, g, b = 0, c, x - case 3: - r, g, b = 0, x, c - case 4: - r, g, b = x, 0, c - case 5: - r, g, b = c, 0, x - default: - r, g, b = c, 0, x - } - - return RGB{R: r + m, G: g + m, B: b + m} -} - -func sRGBToLinear(c float64) float64 { - if c <= 0.04045 { - return c / 12.92 - } - return math.Pow((c+0.055)/1.055, 2.4) -} - -func Luminance(hex string) float64 { - rgb := HexToRGB(hex) - return 0.2126*sRGBToLinear(rgb.R) + 0.7152*sRGBToLinear(rgb.G) + 0.0722*sRGBToLinear(rgb.B) -} - -func ContrastRatio(hexFg, hexBg string) float64 { - lumFg := Luminance(hexFg) - lumBg := Luminance(hexBg) - lighter := math.Max(lumFg, lumBg) - darker := math.Min(lumFg, lumBg) - return (lighter + 0.05) / (darker + 0.05) -} - -func getLstar(hex string) float64 { - rgb := HexToRGB(hex) - col := colorful.Color{R: rgb.R, G: rgb.G, B: rgb.B} - L, _, _ := col.Lab() - return L * 100.0 // go-colorful uses 0-1, we need 0-100 for DPS -} - -// Lab to hex, clamping if needed -func labToHex(L, a, b float64) string { - c := colorful.Lab(L/100.0, a, b) // back to 0-1 for go-colorful - r, g, b2 := c.Clamped().RGB255() - return fmt.Sprintf("#%02x%02x%02x", r, g, b2) -} - -func DeltaPhiStar(hexFg, hexBg string, negativePolarity bool) float64 { - Lf := getLstar(hexFg) - Lb := getLstar(hexBg) - - phi := 1.618 - inv := 0.618 - lc := math.Pow(math.Abs(math.Pow(Lb, phi)-math.Pow(Lf, phi)), inv)*1.414 - 40 - - if negativePolarity { - lc += 5 - } - - return lc -} - -func DeltaPhiStarContrast(hexFg, hexBg string, isLightMode bool) float64 { - negativePolarity := !isLightMode - return DeltaPhiStar(hexFg, hexBg, negativePolarity) -} - -func EnsureContrast(hexColor, hexBg string, minRatio float64, isLightMode bool) string { - currentRatio := ContrastRatio(hexColor, hexBg) - if currentRatio >= minRatio { - return hexColor - } - - rgb := HexToRGB(hexColor) - hsv := RGBToHSV(rgb) - - for step := 1; step < 30; step++ { - delta := float64(step) * 0.02 - - if isLightMode { - newV := math.Max(0, hsv.V-delta) - candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if ContrastRatio(candidate, hexBg) >= minRatio { - return candidate - } - - newV = math.Min(1, hsv.V+delta) - candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if ContrastRatio(candidate, hexBg) >= minRatio { - return candidate - } - } else { - newV := math.Min(1, hsv.V+delta) - candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if ContrastRatio(candidate, hexBg) >= minRatio { - return candidate - } - - newV = math.Max(0, hsv.V-delta) - candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if ContrastRatio(candidate, hexBg) >= minRatio { - return candidate - } - } - } - - return hexColor -} - -func EnsureContrastDPS(hexColor, hexBg string, minLc float64, isLightMode bool) string { - currentLc := DeltaPhiStarContrast(hexColor, hexBg, isLightMode) - if currentLc >= minLc { - return hexColor - } - - rgb := HexToRGB(hexColor) - hsv := RGBToHSV(rgb) - - for step := 1; step < 50; step++ { - delta := float64(step) * 0.015 - - if isLightMode { - newV := math.Max(0, hsv.V-delta) - candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc { - return candidate - } - - newV = math.Min(1, hsv.V+delta) - candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc { - return candidate - } - } else { - newV := math.Min(1, hsv.V+delta) - candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc { - return candidate - } - - newV = math.Max(0, hsv.V-delta) - candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV})) - if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc { - return candidate - } - } - } - - return hexColor -} - -// Nudge L* until contrast is good enough. Keeps hue intact unlike HSV fiddling. -func EnsureContrastDPSLstar(hexColor, hexBg string, minLc float64, isLightMode bool) string { - current := DeltaPhiStarContrast(hexColor, hexBg, isLightMode) - if current >= minLc { - return hexColor - } - - fg := HexToRGB(hexColor) - cf := colorful.Color{R: fg.R, G: fg.G, B: fg.B} - Lf, af, bf := cf.Lab() - - dir := 1.0 - if isLightMode { - dir = -1.0 // light mode = darker text - } - - step := 0.5 - for range 120 { - Lf = math.Max(0, math.Min(100, Lf+dir*step)) - cand := labToHex(Lf, af, bf) - if DeltaPhiStarContrast(cand, hexBg, isLightMode) >= minLc { - return cand - } - } - - return hexColor -} - -// Bidirectional contrast - tries both lighter and darker, picks closest to original -func EnsureContrastDPSBidirectional(hexColor, hexBg string, minLc float64, isLightMode bool) string { - current := DeltaPhiStarContrast(hexColor, hexBg, isLightMode) - if current >= minLc { - return hexColor - } - - fg := HexToRGB(hexColor) - cf := colorful.Color{R: fg.R, G: fg.G, B: fg.B} - origL, af, bf := cf.Lab() - - var darkerResult, lighterResult string - darkerL, lighterL := origL, origL - darkerFound, lighterFound := false, false - - step := 0.5 - for i := range 120 { - if !darkerFound { - darkerL = math.Max(0, origL-float64(i)*step) - cand := labToHex(darkerL, af, bf) - if DeltaPhiStarContrast(cand, hexBg, isLightMode) >= minLc { - darkerResult = cand - darkerFound = true - } - } - if !lighterFound { - lighterL = math.Min(100, origL+float64(i)*step) - cand := labToHex(lighterL, af, bf) - if DeltaPhiStarContrast(cand, hexBg, isLightMode) >= minLc { - lighterResult = cand - lighterFound = true - } - } - if darkerFound && lighterFound { - break - } - } - - if darkerFound && lighterFound { - if math.Abs(darkerL-origL) <= math.Abs(lighterL-origL) { - return darkerResult - } - return lighterResult - } - if darkerFound { - return darkerResult - } - if lighterFound { - return lighterResult - } - return hexColor -} - -type PaletteOptions struct { - IsLight bool - Background string - UseDPS bool -} - -func ensureContrastAuto(hexColor, hexBg string, target float64, opts PaletteOptions) string { - if opts.UseDPS { - return EnsureContrastDPSLstar(hexColor, hexBg, target, opts.IsLight) - } - return EnsureContrast(hexColor, hexBg, target, opts.IsLight) -} - -func ensureContrastBidirectional(hexColor, hexBg string, target float64, opts PaletteOptions) string { - if opts.UseDPS { - return EnsureContrastDPSBidirectional(hexColor, hexBg, target, opts.IsLight) - } - return EnsureContrast(hexColor, hexBg, target, opts.IsLight) -} - -func blendHue(base, target, factor float64) float64 { - diff := target - base - if diff > 0.5 { - diff -= 1.0 - } else if diff < -0.5 { - diff += 1.0 - } - result := base + diff*factor - if result < 0 { - result += 1.0 - } else if result >= 1.0 { - result -= 1.0 - } - return result -} - -func DeriveContainer(primary string, isLight bool) string { - rgb := HexToRGB(primary) - hsv := RGBToHSV(rgb) - - if isLight { - containerV := math.Min(hsv.V*1.77, 1.0) - containerS := hsv.S * 0.32 - return RGBToHex(HSVToRGB(HSV{H: hsv.H, S: containerS, V: containerV})) - } - containerV := hsv.V * 0.463 - containerS := math.Min(hsv.S*1.834, 1.0) - return RGBToHex(HSVToRGB(HSV{H: hsv.H, S: containerS, V: containerV})) -} - -func GeneratePalette(primaryColor string, opts PaletteOptions) Palette { - baseColor := DeriveContainer(primaryColor, opts.IsLight) - - rgb := HexToRGB(baseColor) - hsv := RGBToHSV(rgb) - - pr := HexToRGB(primaryColor) - ph := RGBToHSV(pr) - - var palette Palette - - var normalTextTarget, secondaryTarget float64 - if opts.UseDPS { - normalTextTarget = 40.0 - secondaryTarget = 35.0 - } else { - normalTextTarget = 4.5 - secondaryTarget = 3.0 - } - - var bgColor string - if opts.Background != "" { - bgColor = opts.Background - } else if opts.IsLight { - bgColor = "#f8f8f8" - } else { - bgColor = "#1a1a1a" - } - palette.Color0 = NewColorInfo(bgColor) - - baseSat := math.Max(ph.S, 0.5) - baseVal := math.Max(ph.V, 0.5) - - redH := blendHue(0.0, ph.H, 0.12) - greenH := blendHue(0.33, ph.H, 0.10) - yellowH := blendHue(0.14, ph.H, 0.04) - - accentTarget := secondaryTarget * 0.7 - - if opts.IsLight { - redS := math.Min(baseSat*1.2, 1.0) - redV := baseVal * 0.95 - palette.Color1 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: redH, S: redS, V: redV})), bgColor, normalTextTarget, opts)) - - greenS := math.Min(baseSat*1.3, 1.0) - greenV := baseVal * 0.75 - palette.Color2 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: greenH, S: greenS, V: greenV})), bgColor, normalTextTarget, opts)) - - yellowS := math.Min(baseSat*1.5, 1.0) - yellowV := math.Min(baseVal*1.2, 1.0) - palette.Color3 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: yellowH, S: yellowS, V: yellowV})), bgColor, accentTarget, opts)) - - blueS := math.Min(ph.S*1.05, 1.0) - blueV := math.Min(ph.V*1.05, 1.0) - palette.Color4 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: ph.H, S: blueS, V: blueV})), bgColor, normalTextTarget, opts)) - - // Color5 matches primary_container exactly (light container in light mode) - container5 := DeriveContainer(primaryColor, true) - palette.Color5 = NewColorInfo(container5) - - palette.Color6 = NewColorInfo(primaryColor) - - gray7S := baseSat * 0.08 - gray7V := baseVal * 0.28 - palette.Color7 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: gray7S, V: gray7V})), bgColor, normalTextTarget, opts)) - - gray8S := baseSat * 0.05 - gray8V := baseVal * 0.85 - dimTarget := secondaryTarget * 0.5 - palette.Color8 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: gray8S, V: gray8V})), bgColor, dimTarget, opts)) - - brightRedS := math.Min(baseSat*1.0, 1.0) - brightRedV := math.Min(baseVal*1.2, 1.0) - palette.Color9 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: redH, S: brightRedS, V: brightRedV})), bgColor, accentTarget, opts)) - - brightGreenS := math.Min(baseSat*1.1, 1.0) - brightGreenV := math.Min(baseVal*1.1, 1.0) - palette.Color10 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: greenH, S: brightGreenS, V: brightGreenV})), bgColor, accentTarget, opts)) - - brightYellowS := math.Min(baseSat*1.4, 1.0) - brightYellowV := math.Min(baseVal*1.3, 1.0) - palette.Color11 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: yellowH, S: brightYellowS, V: brightYellowV})), bgColor, accentTarget, opts)) - - brightBlueS := math.Min(ph.S*1.1, 1.0) - brightBlueV := math.Min(ph.V*1.15, 1.0) - palette.Color12 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: ph.H, S: brightBlueS, V: brightBlueV})), bgColor, accentTarget, opts)) - - lightContainer := DeriveContainer(primaryColor, true) - palette.Color13 = NewColorInfo(lightContainer) - - brightCyanS := ph.S * 0.5 - brightCyanV := math.Min(ph.V*1.3, 1.0) - palette.Color14 = NewColorInfo(RGBToHex(HSVToRGB(HSV{H: ph.H, S: brightCyanS, V: brightCyanV}))) - - white15S := baseSat * 0.04 - white15V := math.Min(baseVal*1.5, 1.0) - palette.Color15 = NewColorInfo(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: white15S, V: white15V}))) - } else { - redS := math.Min(baseSat*1.1, 1.0) - redV := math.Min(baseVal*1.15, 1.0) - palette.Color1 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: redH, S: redS, V: redV})), bgColor, normalTextTarget, opts)) - - greenS := math.Min(baseSat*1.0, 1.0) - greenV := math.Min(baseVal*1.0, 1.0) - palette.Color2 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: greenH, S: greenS, V: greenV})), bgColor, normalTextTarget, opts)) - - yellowS := math.Min(baseSat*1.1, 1.0) - yellowV := math.Min(baseVal*1.25, 1.0) - palette.Color3 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: yellowH, S: yellowS, V: yellowV})), bgColor, normalTextTarget, opts)) - - // Slightly more saturated variant of primary - blueS := math.Min(ph.S*1.2, 1.0) - blueV := ph.V * 0.95 - palette.Color4 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: ph.H, S: blueS, V: blueV})), bgColor, normalTextTarget, opts)) - - // Color5 matches primary_container exactly (dark container in dark mode) - darkContainer := DeriveContainer(primaryColor, false) - palette.Color5 = NewColorInfo(darkContainer) - - palette.Color6 = NewColorInfo(primaryColor) - - gray7S := baseSat * 0.12 - gray7V := math.Min(baseVal*1.05, 1.0) - palette.Color7 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: gray7S, V: gray7V})), bgColor, normalTextTarget, opts)) - - gray8S := baseSat * 0.15 - gray8V := baseVal * 0.65 - palette.Color8 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: gray8S, V: gray8V})), bgColor, secondaryTarget, opts)) - - brightRedS := math.Min(baseSat*0.75, 1.0) - brightRedV := math.Min(baseVal*1.35, 1.0) - palette.Color9 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: redH, S: brightRedS, V: brightRedV})), bgColor, accentTarget, opts)) - - brightGreenS := math.Min(baseSat*0.7, 1.0) - brightGreenV := math.Min(baseVal*1.2, 1.0) - palette.Color10 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: greenH, S: brightGreenS, V: brightGreenV})), bgColor, accentTarget, opts)) - - brightYellowS := math.Min(baseSat*0.7, 1.0) - brightYellowV := math.Min(baseVal*1.5, 1.0) - palette.Color11 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: yellowH, S: brightYellowS, V: brightYellowV})), bgColor, accentTarget, opts)) - - // Create a gradient of primary variants: Color12 -> Color13 -> Color14 -> Color15 (near white) - // Color12: Start of the lighter gradient - slightly desaturated - brightBlueS := ph.S * 0.85 - brightBlueV := math.Min(ph.V*1.1, 1.0) - palette.Color12 = NewColorInfo(ensureContrastBidirectional(RGBToHex(HSVToRGB(HSV{H: ph.H, S: brightBlueS, V: brightBlueV})), bgColor, accentTarget, opts)) - - // Medium-high saturation pastel primary - color13S := ph.S * 0.7 - color13V := math.Min(ph.V*1.3, 1.0) - palette.Color13 = NewColorInfo(RGBToHex(HSVToRGB(HSV{H: ph.H, S: color13S, V: color13V}))) - - // Lower saturation, lighter variant - color14S := ph.S * 0.45 - color14V := math.Min(ph.V*1.4, 1.0) - palette.Color14 = NewColorInfo(RGBToHex(HSVToRGB(HSV{H: ph.H, S: color14S, V: color14V}))) - - white15S := baseSat * 0.05 - white15V := math.Min(baseVal*1.45, 1.0) - palette.Color15 = NewColorInfo(ensureContrastAuto(RGBToHex(HSVToRGB(HSV{H: hsv.H, S: white15S, V: white15V})), bgColor, normalTextTarget, opts)) - } - - return palette -} - -type VariantOptions struct { - PrimaryDark string - PrimaryLight string - Background string - UseDPS bool - IsLightMode bool -} - -func mergeColorInfo(dark, light ColorInfo, isLightMode bool) VariantColorInfo { - darkVal := VariantColorValue{Hex: dark.Hex, HexStripped: dark.HexStripped} - lightVal := VariantColorValue{Hex: light.Hex, HexStripped: light.HexStripped} - - defaultVal := darkVal - if isLightMode { - defaultVal = lightVal - } - - return VariantColorInfo{ - Dark: darkVal, - Light: lightVal, - Default: defaultVal, - } -} - -func GenerateVariantPalette(opts VariantOptions) VariantPalette { - darkOpts := PaletteOptions{IsLight: false, Background: opts.Background, UseDPS: opts.UseDPS} - lightOpts := PaletteOptions{IsLight: true, Background: opts.Background, UseDPS: opts.UseDPS} - - dark := GeneratePalette(opts.PrimaryDark, darkOpts) - light := GeneratePalette(opts.PrimaryLight, lightOpts) - - return VariantPalette{ - Color0: mergeColorInfo(dark.Color0, light.Color0, opts.IsLightMode), - Color1: mergeColorInfo(dark.Color1, light.Color1, opts.IsLightMode), - Color2: mergeColorInfo(dark.Color2, light.Color2, opts.IsLightMode), - Color3: mergeColorInfo(dark.Color3, light.Color3, opts.IsLightMode), - Color4: mergeColorInfo(dark.Color4, light.Color4, opts.IsLightMode), - Color5: mergeColorInfo(dark.Color5, light.Color5, opts.IsLightMode), - Color6: mergeColorInfo(dark.Color6, light.Color6, opts.IsLightMode), - Color7: mergeColorInfo(dark.Color7, light.Color7, opts.IsLightMode), - Color8: mergeColorInfo(dark.Color8, light.Color8, opts.IsLightMode), - Color9: mergeColorInfo(dark.Color9, light.Color9, opts.IsLightMode), - Color10: mergeColorInfo(dark.Color10, light.Color10, opts.IsLightMode), - Color11: mergeColorInfo(dark.Color11, light.Color11, opts.IsLightMode), - Color12: mergeColorInfo(dark.Color12, light.Color12, opts.IsLightMode), - Color13: mergeColorInfo(dark.Color13, light.Color13, opts.IsLightMode), - Color14: mergeColorInfo(dark.Color14, light.Color14, opts.IsLightMode), - Color15: mergeColorInfo(dark.Color15, light.Color15, opts.IsLightMode), - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16_test.go deleted file mode 100644 index 9e6b5a8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/dank16_test.go +++ /dev/null @@ -1,681 +0,0 @@ -package dank16 - -import ( - "math" - "testing" -) - -func TestHexToRGB(t *testing.T) { - tests := []struct { - name string - input string - expected RGB - }{ - { - name: "black with hash", - input: "#000000", - expected: RGB{R: 0.0, G: 0.0, B: 0.0}, - }, - { - name: "white with hash", - input: "#ffffff", - expected: RGB{R: 1.0, G: 1.0, B: 1.0}, - }, - { - name: "red without hash", - input: "ff0000", - expected: RGB{R: 1.0, G: 0.0, B: 0.0}, - }, - { - name: "purple", - input: "#625690", - expected: RGB{R: 0.3843137254901961, G: 0.33725490196078434, B: 0.5647058823529412}, - }, - { - name: "mid gray", - input: "#808080", - expected: RGB{R: 0.5019607843137255, G: 0.5019607843137255, B: 0.5019607843137255}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := HexToRGB(tt.input) - if !floatEqual(result.R, tt.expected.R) || !floatEqual(result.G, tt.expected.G) || !floatEqual(result.B, tt.expected.B) { - t.Errorf("HexToRGB(%s) = %v, expected %v", tt.input, result, tt.expected) - } - }) - } -} - -func TestRGBToHex(t *testing.T) { - tests := []struct { - name string - input RGB - expected string - }{ - { - name: "black", - input: RGB{R: 0.0, G: 0.0, B: 0.0}, - expected: "#000000", - }, - { - name: "white", - input: RGB{R: 1.0, G: 1.0, B: 1.0}, - expected: "#ffffff", - }, - { - name: "red", - input: RGB{R: 1.0, G: 0.0, B: 0.0}, - expected: "#ff0000", - }, - { - name: "clamping above 1.0", - input: RGB{R: 1.5, G: 0.5, B: 0.5}, - expected: "#ff7f7f", - }, - { - name: "clamping below 0.0", - input: RGB{R: -0.5, G: 0.5, B: 0.5}, - expected: "#007f7f", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := RGBToHex(tt.input) - if result != tt.expected { - t.Errorf("RGBToHex(%v) = %s, expected %s", tt.input, result, tt.expected) - } - }) - } -} - -func TestRGBToHSV(t *testing.T) { - tests := []struct { - name string - input RGB - expected HSV - }{ - { - name: "black", - input: RGB{R: 0.0, G: 0.0, B: 0.0}, - expected: HSV{H: 0.0, S: 0.0, V: 0.0}, - }, - { - name: "white", - input: RGB{R: 1.0, G: 1.0, B: 1.0}, - expected: HSV{H: 0.0, S: 0.0, V: 1.0}, - }, - { - name: "red", - input: RGB{R: 1.0, G: 0.0, B: 0.0}, - expected: HSV{H: 0.0, S: 1.0, V: 1.0}, - }, - { - name: "green", - input: RGB{R: 0.0, G: 1.0, B: 0.0}, - expected: HSV{H: 0.3333333333333333, S: 1.0, V: 1.0}, - }, - { - name: "blue", - input: RGB{R: 0.0, G: 0.0, B: 1.0}, - expected: HSV{H: 0.6666666666666666, S: 1.0, V: 1.0}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := RGBToHSV(tt.input) - if !floatEqual(result.H, tt.expected.H) || !floatEqual(result.S, tt.expected.S) || !floatEqual(result.V, tt.expected.V) { - t.Errorf("RGBToHSV(%v) = %v, expected %v", tt.input, result, tt.expected) - } - }) - } -} - -func TestHSVToRGB(t *testing.T) { - tests := []struct { - name string - input HSV - expected RGB - }{ - { - name: "black", - input: HSV{H: 0.0, S: 0.0, V: 0.0}, - expected: RGB{R: 0.0, G: 0.0, B: 0.0}, - }, - { - name: "white", - input: HSV{H: 0.0, S: 0.0, V: 1.0}, - expected: RGB{R: 1.0, G: 1.0, B: 1.0}, - }, - { - name: "red", - input: HSV{H: 0.0, S: 1.0, V: 1.0}, - expected: RGB{R: 1.0, G: 0.0, B: 0.0}, - }, - { - name: "green", - input: HSV{H: 0.3333333333333333, S: 1.0, V: 1.0}, - expected: RGB{R: 0.0, G: 1.0, B: 0.0}, - }, - { - name: "blue", - input: HSV{H: 0.6666666666666666, S: 1.0, V: 1.0}, - expected: RGB{R: 0.0, G: 0.0, B: 1.0}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := HSVToRGB(tt.input) - if !floatEqual(result.R, tt.expected.R) || !floatEqual(result.G, tt.expected.G) || !floatEqual(result.B, tt.expected.B) { - t.Errorf("HSVToRGB(%v) = %v, expected %v", tt.input, result, tt.expected) - } - }) - } -} - -func TestLuminance(t *testing.T) { - tests := []struct { - name string - input string - expected float64 - }{ - { - name: "black", - input: "#000000", - expected: 0.0, - }, - { - name: "white", - input: "#ffffff", - expected: 1.0, - }, - { - name: "red", - input: "#ff0000", - expected: 0.2126, - }, - { - name: "green", - input: "#00ff00", - expected: 0.7152, - }, - { - name: "blue", - input: "#0000ff", - expected: 0.0722, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := Luminance(tt.input) - if !floatEqual(result, tt.expected) { - t.Errorf("Luminance(%s) = %f, expected %f", tt.input, result, tt.expected) - } - }) - } -} - -func TestContrastRatio(t *testing.T) { - tests := []struct { - name string - fg string - bg string - expected float64 - }{ - { - name: "black on white", - fg: "#000000", - bg: "#ffffff", - expected: 21.0, - }, - { - name: "white on black", - fg: "#ffffff", - bg: "#000000", - expected: 21.0, - }, - { - name: "same color", - fg: "#808080", - bg: "#808080", - expected: 1.0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := ContrastRatio(tt.fg, tt.bg) - if !floatEqual(result, tt.expected) { - t.Errorf("ContrastRatio(%s, %s) = %f, expected %f", tt.fg, tt.bg, result, tt.expected) - } - }) - } -} - -func TestEnsureContrast(t *testing.T) { - tests := []struct { - name string - color string - bg string - minRatio float64 - isLightMode bool - }{ - { - name: "already sufficient contrast dark mode", - color: "#ffffff", - bg: "#000000", - minRatio: 4.5, - isLightMode: false, - }, - { - name: "already sufficient contrast light mode", - color: "#000000", - bg: "#ffffff", - minRatio: 4.5, - isLightMode: true, - }, - { - name: "needs adjustment dark mode", - color: "#404040", - bg: "#1a1a1a", - minRatio: 4.5, - isLightMode: false, - }, - { - name: "needs adjustment light mode", - color: "#c0c0c0", - bg: "#f8f8f8", - minRatio: 4.5, - isLightMode: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := EnsureContrast(tt.color, tt.bg, tt.minRatio, tt.isLightMode) - actualRatio := ContrastRatio(result, tt.bg) - if actualRatio < tt.minRatio { - t.Errorf("EnsureContrast(%s, %s, %f, %t) = %s with ratio %f, expected ratio >= %f", - tt.color, tt.bg, tt.minRatio, tt.isLightMode, result, actualRatio, tt.minRatio) - } - }) - } -} - -func TestGeneratePalette(t *testing.T) { - tests := []struct { - name string - base string - opts PaletteOptions - }{ - { - name: "dark theme default", - base: "#625690", - opts: PaletteOptions{IsLight: false}, - }, - { - name: "light theme default", - base: "#625690", - opts: PaletteOptions{IsLight: true}, - }, - { - name: "light theme with custom background", - base: "#625690", - opts: PaletteOptions{ - IsLight: true, - Background: "#fafafa", - }, - }, - { - name: "dark theme with custom background", - base: "#625690", - opts: PaletteOptions{ - IsLight: false, - Background: "#0a0a0a", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := GeneratePalette(tt.base, tt.opts) - - colors := []ColorInfo{ - result.Color0, result.Color1, result.Color2, result.Color3, - result.Color4, result.Color5, result.Color6, result.Color7, - result.Color8, result.Color9, result.Color10, result.Color11, - result.Color12, result.Color13, result.Color14, result.Color15, - } - - for i, color := range colors { - if len(color.Hex) != 7 || color.Hex[0] != '#' { - t.Errorf("Color at index %d (%s) is not a valid hex color", i, color.Hex) - } - } - - if tt.opts.Background != "" && result.Color0.Hex != tt.opts.Background { - t.Errorf("Background color = %s, expected %s", result.Color0.Hex, tt.opts.Background) - } else if !tt.opts.IsLight && tt.opts.Background == "" && result.Color0.Hex != "#1a1a1a" { - t.Errorf("Dark mode background = %s, expected #1a1a1a", result.Color0.Hex) - } else if tt.opts.IsLight && tt.opts.Background == "" && result.Color0.Hex != "#f8f8f8" { - t.Errorf("Light mode background = %s, expected #f8f8f8", result.Color0.Hex) - } - - // Color15 is now derived from primary, so just verify it's a valid color - // and has appropriate luminance for the mode (now theme-tinted, not pure white/black) - color15Lum := Luminance(result.Color15.Hex) - if tt.opts.IsLight { - // Light mode: Color15 should still be relatively light - if color15Lum < 0.5 { - t.Errorf("Light mode Color15 = %s (lum %.2f) is too dark", result.Color15.Hex, color15Lum) - } - } else { - // Dark mode: Color15 should be light (but may have theme tint, so lower threshold) - if color15Lum < 0.5 { - t.Errorf("Dark mode Color15 = %s (lum %.2f) is too dark", result.Color15.Hex, color15Lum) - } - } - }) - } -} - -func TestRoundTripConversion(t *testing.T) { - testColors := []string{"#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff", "#625690", "#808080"} - - for _, hex := range testColors { - t.Run(hex, func(t *testing.T) { - rgb := HexToRGB(hex) - result := RGBToHex(rgb) - if result != hex { - t.Errorf("Round trip %s -> RGB -> %s failed", hex, result) - } - }) - } -} - -func TestRGBHSVRoundTrip(t *testing.T) { - testCases := []RGB{ - {R: 0.0, G: 0.0, B: 0.0}, - {R: 1.0, G: 1.0, B: 1.0}, - {R: 1.0, G: 0.0, B: 0.0}, - {R: 0.0, G: 1.0, B: 0.0}, - {R: 0.0, G: 0.0, B: 1.0}, - {R: 0.5, G: 0.5, B: 0.5}, - {R: 0.3843137254901961, G: 0.33725490196078434, B: 0.5647058823529412}, - } - - for _, rgb := range testCases { - t.Run("", func(t *testing.T) { - hsv := RGBToHSV(rgb) - result := HSVToRGB(hsv) - if !floatEqual(result.R, rgb.R) || !floatEqual(result.G, rgb.G) || !floatEqual(result.B, rgb.B) { - t.Errorf("Round trip RGB->HSV->RGB failed: %v -> %v -> %v", rgb, hsv, result) - } - }) - } -} - -func floatEqual(a, b float64) bool { - return math.Abs(a-b) < 1e-9 -} - -func TestDeltaPhiStar(t *testing.T) { - tests := []struct { - name string - fg string - bg string - negativePolarity bool - minExpected float64 - }{ - { - name: "white on black (negative polarity)", - fg: "#ffffff", - bg: "#000000", - negativePolarity: true, - minExpected: 100.0, - }, - { - name: "black on white (positive polarity)", - fg: "#000000", - bg: "#ffffff", - negativePolarity: false, - minExpected: 100.0, - }, - { - name: "low contrast same color", - fg: "#808080", - bg: "#808080", - negativePolarity: false, - minExpected: -40.0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := DeltaPhiStar(tt.fg, tt.bg, tt.negativePolarity) - if result < tt.minExpected { - t.Errorf("DeltaPhiStar(%s, %s, %v) = %f, expected >= %f", - tt.fg, tt.bg, tt.negativePolarity, result, tt.minExpected) - } - }) - } -} - -func TestDeltaPhiStarContrast(t *testing.T) { - tests := []struct { - name string - fg string - bg string - isLightMode bool - minExpected float64 - }{ - { - name: "white on black (dark mode)", - fg: "#ffffff", - bg: "#000000", - isLightMode: false, - minExpected: 100.0, - }, - { - name: "black on white (light mode)", - fg: "#000000", - bg: "#ffffff", - isLightMode: true, - minExpected: 100.0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := DeltaPhiStarContrast(tt.fg, tt.bg, tt.isLightMode) - if result < tt.minExpected { - t.Errorf("DeltaPhiStarContrast(%s, %s, %v) = %f, expected >= %f", - tt.fg, tt.bg, tt.isLightMode, result, tt.minExpected) - } - }) - } -} - -func TestEnsureContrastDPS(t *testing.T) { - tests := []struct { - name string - color string - bg string - minLc float64 - isLightMode bool - }{ - { - name: "already sufficient contrast dark mode", - color: "#ffffff", - bg: "#000000", - minLc: 60.0, - isLightMode: false, - }, - { - name: "already sufficient contrast light mode", - color: "#000000", - bg: "#ffffff", - minLc: 60.0, - isLightMode: true, - }, - { - name: "needs adjustment dark mode", - color: "#404040", - bg: "#1a1a1a", - minLc: 60.0, - isLightMode: false, - }, - { - name: "needs adjustment light mode", - color: "#c0c0c0", - bg: "#f8f8f8", - minLc: 60.0, - isLightMode: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := EnsureContrastDPS(tt.color, tt.bg, tt.minLc, tt.isLightMode) - actualLc := DeltaPhiStarContrast(result, tt.bg, tt.isLightMode) - if actualLc < tt.minLc { - t.Errorf("EnsureContrastDPS(%s, %s, %f, %t) = %s with Lc %f, expected Lc >= %f", - tt.color, tt.bg, tt.minLc, tt.isLightMode, result, actualLc, tt.minLc) - } - }) - } -} - -func TestGeneratePaletteWithDPS(t *testing.T) { - tests := []struct { - name string - base string - opts PaletteOptions - }{ - { - name: "dark theme with DPS", - base: "#625690", - opts: PaletteOptions{IsLight: false, UseDPS: true}, - }, - { - name: "light theme with DPS", - base: "#625690", - opts: PaletteOptions{IsLight: true, UseDPS: true}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := GeneratePalette(tt.base, tt.opts) - - colors := []ColorInfo{ - result.Color0, result.Color1, result.Color2, result.Color3, - result.Color4, result.Color5, result.Color6, result.Color7, - result.Color8, result.Color9, result.Color10, result.Color11, - result.Color12, result.Color13, result.Color14, result.Color15, - } - - for i, color := range colors { - if len(color.Hex) != 7 || color.Hex[0] != '#' { - t.Errorf("Color at index %d (%s) is not a valid hex color", i, color.Hex) - } - } - - bgColor := result.Color0.Hex - for i := 1; i < 8; i++ { - // Skip Color5 (container) and Color6 (exact primary) - intentionally not contrast-adjusted - if i == 5 || i == 6 { - continue - } - lc := DeltaPhiStarContrast(colors[i].Hex, bgColor, tt.opts.IsLight) - minLc := 30.0 - if lc < minLc && lc > 0 { - t.Errorf("Color %d (%s) has insufficient DPS contrast %f with background %s (expected >= %f)", - i, colors[i].Hex, lc, bgColor, minLc) - } - } - }) - } -} - -func TestDeriveContainer(t *testing.T) { - tests := []struct { - name string - primary string - isLight bool - expected string - }{ - { - name: "dark mode", - primary: "#ccbdff", - isLight: false, - expected: "#4a3e76", - }, - { - name: "light mode", - primary: "#625690", - isLight: true, - expected: "#e7deff", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := DeriveContainer(tt.primary, tt.isLight) - - resultRGB := HexToRGB(result) - expectedRGB := HexToRGB(tt.expected) - - rDiff := math.Abs(resultRGB.R - expectedRGB.R) - gDiff := math.Abs(resultRGB.G - expectedRGB.G) - bDiff := math.Abs(resultRGB.B - expectedRGB.B) - - tolerance := 0.02 - if rDiff > tolerance || gDiff > tolerance || bDiff > tolerance { - t.Errorf("DeriveContainer(%s, %v) = %s, expected %s (RGB diff: R:%.4f G:%.4f B:%.4f)", - tt.primary, tt.isLight, result, tt.expected, rDiff, gDiff, bDiff) - } - }) - } -} - -func TestContrastAlgorithmComparison(t *testing.T) { - base := "#625690" - - optsWCAG := PaletteOptions{IsLight: false, UseDPS: false} - optsDPS := PaletteOptions{IsLight: false, UseDPS: true} - - paletteWCAG := GeneratePalette(base, optsWCAG) - paletteDPS := GeneratePalette(base, optsDPS) - - wcagColors := []ColorInfo{ - paletteWCAG.Color0, paletteWCAG.Color1, paletteWCAG.Color2, paletteWCAG.Color3, - paletteWCAG.Color4, paletteWCAG.Color5, paletteWCAG.Color6, paletteWCAG.Color7, - paletteWCAG.Color8, paletteWCAG.Color9, paletteWCAG.Color10, paletteWCAG.Color11, - paletteWCAG.Color12, paletteWCAG.Color13, paletteWCAG.Color14, paletteWCAG.Color15, - } - dpsColors := []ColorInfo{ - paletteDPS.Color0, paletteDPS.Color1, paletteDPS.Color2, paletteDPS.Color3, - paletteDPS.Color4, paletteDPS.Color5, paletteDPS.Color6, paletteDPS.Color7, - paletteDPS.Color8, paletteDPS.Color9, paletteDPS.Color10, paletteDPS.Color11, - paletteDPS.Color12, paletteDPS.Color13, paletteDPS.Color14, paletteDPS.Color15, - } - - if paletteWCAG.Color0.Hex != paletteDPS.Color0.Hex { - t.Errorf("Background colors differ: WCAG=%s, DPS=%s", paletteWCAG.Color0.Hex, paletteDPS.Color0.Hex) - } - - differentCount := 0 - for i := range 16 { - if wcagColors[i].Hex != dpsColors[i].Hex { - differentCount++ - } - } - - t.Logf("WCAG and DPS palettes differ in %d/16 colors", differentCount) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/terminals.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/terminals.go deleted file mode 100644 index 9423311..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/dank16/terminals.go +++ /dev/null @@ -1,135 +0,0 @@ -package dank16 - -import ( - "encoding/json" - "fmt" - "strings" -) - -func GenerateJSON(p Palette) string { - marshalled, _ := json.Marshal(p) - return string(marshalled) -} - -func GenerateVariantJSON(p VariantPalette) string { - marshalled, _ := json.Marshal(p) - return string(marshalled) -} - -func GenerateKittyTheme(p Palette) string { - var result strings.Builder - fmt.Fprintf(&result, "color0 %s\n", p.Color0.Hex) - fmt.Fprintf(&result, "color1 %s\n", p.Color1.Hex) - fmt.Fprintf(&result, "color2 %s\n", p.Color2.Hex) - fmt.Fprintf(&result, "color3 %s\n", p.Color3.Hex) - fmt.Fprintf(&result, "color4 %s\n", p.Color4.Hex) - fmt.Fprintf(&result, "color5 %s\n", p.Color5.Hex) - fmt.Fprintf(&result, "color6 %s\n", p.Color6.Hex) - fmt.Fprintf(&result, "color7 %s\n", p.Color7.Hex) - fmt.Fprintf(&result, "color8 %s\n", p.Color8.Hex) - fmt.Fprintf(&result, "color9 %s\n", p.Color9.Hex) - fmt.Fprintf(&result, "color10 %s\n", p.Color10.Hex) - fmt.Fprintf(&result, "color11 %s\n", p.Color11.Hex) - fmt.Fprintf(&result, "color12 %s\n", p.Color12.Hex) - fmt.Fprintf(&result, "color13 %s\n", p.Color13.Hex) - fmt.Fprintf(&result, "color14 %s\n", p.Color14.Hex) - fmt.Fprintf(&result, "color15 %s\n", p.Color15.Hex) - return result.String() -} - -func GenerateFootTheme(p Palette) string { - var result strings.Builder - fmt.Fprintf(&result, "regular0=%s\n", p.Color0.HexStripped) - fmt.Fprintf(&result, "regular1=%s\n", p.Color1.HexStripped) - fmt.Fprintf(&result, "regular2=%s\n", p.Color2.HexStripped) - fmt.Fprintf(&result, "regular3=%s\n", p.Color3.HexStripped) - fmt.Fprintf(&result, "regular4=%s\n", p.Color4.HexStripped) - fmt.Fprintf(&result, "regular5=%s\n", p.Color5.HexStripped) - fmt.Fprintf(&result, "regular6=%s\n", p.Color6.HexStripped) - fmt.Fprintf(&result, "regular7=%s\n", p.Color7.HexStripped) - fmt.Fprintf(&result, "bright0=%s\n", p.Color8.HexStripped) - fmt.Fprintf(&result, "bright1=%s\n", p.Color9.HexStripped) - fmt.Fprintf(&result, "bright2=%s\n", p.Color10.HexStripped) - fmt.Fprintf(&result, "bright3=%s\n", p.Color11.HexStripped) - fmt.Fprintf(&result, "bright4=%s\n", p.Color12.HexStripped) - fmt.Fprintf(&result, "bright5=%s\n", p.Color13.HexStripped) - fmt.Fprintf(&result, "bright6=%s\n", p.Color14.HexStripped) - fmt.Fprintf(&result, "bright7=%s\n", p.Color15.HexStripped) - return result.String() -} - -func GenerateAlacrittyTheme(p Palette) string { - var result strings.Builder - result.WriteString("[colors.normal]\n") - fmt.Fprintf(&result, "black = '%s'\n", p.Color0.Hex) - fmt.Fprintf(&result, "red = '%s'\n", p.Color1.Hex) - fmt.Fprintf(&result, "green = '%s'\n", p.Color2.Hex) - fmt.Fprintf(&result, "yellow = '%s'\n", p.Color3.Hex) - fmt.Fprintf(&result, "blue = '%s'\n", p.Color4.Hex) - fmt.Fprintf(&result, "magenta = '%s'\n", p.Color5.Hex) - fmt.Fprintf(&result, "cyan = '%s'\n", p.Color6.Hex) - fmt.Fprintf(&result, "white = '%s'\n", p.Color7.Hex) - result.WriteString("\n[colors.bright]\n") - fmt.Fprintf(&result, "black = '%s'\n", p.Color8.Hex) - fmt.Fprintf(&result, "red = '%s'\n", p.Color9.Hex) - fmt.Fprintf(&result, "green = '%s'\n", p.Color10.Hex) - fmt.Fprintf(&result, "yellow = '%s'\n", p.Color11.Hex) - fmt.Fprintf(&result, "blue = '%s'\n", p.Color12.Hex) - fmt.Fprintf(&result, "magenta = '%s'\n", p.Color13.Hex) - fmt.Fprintf(&result, "cyan = '%s'\n", p.Color14.Hex) - fmt.Fprintf(&result, "white = '%s'\n", p.Color15.Hex) - return result.String() -} - -func GenerateGhosttyTheme(p Palette) string { - var result strings.Builder - fmt.Fprintf(&result, "palette = 0=%s\n", p.Color0.Hex) - fmt.Fprintf(&result, "palette = 1=%s\n", p.Color1.Hex) - fmt.Fprintf(&result, "palette = 2=%s\n", p.Color2.Hex) - fmt.Fprintf(&result, "palette = 3=%s\n", p.Color3.Hex) - fmt.Fprintf(&result, "palette = 4=%s\n", p.Color4.Hex) - fmt.Fprintf(&result, "palette = 5=%s\n", p.Color5.Hex) - fmt.Fprintf(&result, "palette = 6=%s\n", p.Color6.Hex) - fmt.Fprintf(&result, "palette = 7=%s\n", p.Color7.Hex) - fmt.Fprintf(&result, "palette = 8=%s\n", p.Color8.Hex) - fmt.Fprintf(&result, "palette = 9=%s\n", p.Color9.Hex) - fmt.Fprintf(&result, "palette = 10=%s\n", p.Color10.Hex) - fmt.Fprintf(&result, "palette = 11=%s\n", p.Color11.Hex) - fmt.Fprintf(&result, "palette = 12=%s\n", p.Color12.Hex) - fmt.Fprintf(&result, "palette = 13=%s\n", p.Color13.Hex) - fmt.Fprintf(&result, "palette = 14=%s\n", p.Color14.Hex) - fmt.Fprintf(&result, "palette = 15=%s\n", p.Color15.Hex) - return result.String() -} - -func GenerateWeztermTheme(p Palette) string { - var result strings.Builder - fmt.Fprintf(&result, "ansi = ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']\n", - p.Color0.Hex, p.Color1.Hex, p.Color2.Hex, p.Color3.Hex, - p.Color4.Hex, p.Color5.Hex, p.Color6.Hex, p.Color7.Hex) - fmt.Fprintf(&result, "brights = ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']\n", - p.Color8.Hex, p.Color9.Hex, p.Color10.Hex, p.Color11.Hex, - p.Color12.Hex, p.Color13.Hex, p.Color14.Hex, p.Color15.Hex) - return result.String() -} - -func GenerateNeovimTheme(p Palette) string { - var result strings.Builder - fmt.Fprintf(&result, "vim.g.terminal_color_0 = \"%s\"\n", p.Color0.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_1 = \"%s\"\n", p.Color1.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_2 = \"%s\"\n", p.Color2.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_3 = \"%s\"\n", p.Color3.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_4 = \"%s\"\n", p.Color4.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_5 = \"%s\"\n", p.Color5.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_6 = \"%s\"\n", p.Color6.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_7 = \"%s\"\n", p.Color7.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_8 = \"%s\"\n", p.Color8.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_9 = \"%s\"\n", p.Color9.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_10 = \"%s\"\n", p.Color10.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_11 = \"%s\"\n", p.Color11.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_12 = \"%s\"\n", p.Color12.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_13 = \"%s\"\n", p.Color13.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_14 = \"%s\"\n", p.Color14.Hex) - fmt.Fprintf(&result, "vim.g.terminal_color_15 = \"%s\"\n", p.Color15.Hex) - return result.String() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/deps/detector.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/deps/detector.go deleted file mode 100644 index e4f54a7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/deps/detector.go +++ /dev/null @@ -1,51 +0,0 @@ -package deps - -import ( - "context" -) - -type DependencyStatus int - -const ( - StatusMissing DependencyStatus = iota - StatusInstalled - StatusNeedsUpdate - StatusNeedsReinstall -) - -type PackageVariant int - -const ( - VariantStable PackageVariant = iota - VariantGit -) - -type Dependency struct { - Name string - Status DependencyStatus - Version string - Description string - Required bool - Variant PackageVariant - CanToggle bool -} - -type WindowManager int - -const ( - WindowManagerHyprland WindowManager = iota - WindowManagerNiri -) - -type Terminal int - -const ( - TerminalGhostty Terminal = iota - TerminalKitty - TerminalAlacritty -) - -type DependencyDetector interface { - DetectDependencies(ctx context.Context, wm WindowManager) ([]Dependency, error) - DetectDependenciesWithTerminal(ctx context.Context, wm WindowManager, terminal Terminal) ([]Dependency, error) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/arch.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/arch.go deleted file mode 100644 index b412f88..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/arch.go +++ /dev/null @@ -1,807 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" - "slices" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func init() { - Register("arch", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("archarm", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("archcraft", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("cachyos", "#08A283", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("catos", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("endeavouros", "#7F3FBF", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("manjaro", "#35BF5C", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("obarun", "#2494be", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("garuda", "#cba6f7", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("artix", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) - Register("XeroLinux", "#888fe2", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution { - return NewArchDistribution(config, logChan) - }) -} - -type ArchDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig -} - -func NewArchDistribution(config DistroConfig, logChan chan<- string) *ArchDistribution { - base := NewBaseDistribution(logChan) - return &ArchDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (a *ArchDistribution) GetID() string { - return a.config.ID -} - -func (a *ArchDistribution) GetColorHex() string { - return a.config.ColorHex -} - -func (a *ArchDistribution) GetFamily() DistroFamily { - return a.config.Family -} - -func (a *ArchDistribution) GetPackageManager() PackageManagerType { - return PackageManagerPacman -} - -func (a *ArchDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return a.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (a *ArchDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - // DMS at the top (shell is prominent) - dependencies = append(dependencies, a.detectDMS()) - - // Terminal with choice support - dependencies = append(dependencies, a.detectSpecificTerminal(terminal)) - - // Common detections using base methods - dependencies = append(dependencies, a.detectGit()) - dependencies = append(dependencies, a.detectWindowManager(wm)) - dependencies = append(dependencies, a.detectQuickshell()) - dependencies = append(dependencies, a.detectDMSGreeter()) - dependencies = append(dependencies, a.detectXDGPortal()) - dependencies = append(dependencies, a.detectAccountsService()) - - // Hyprland-specific tools - if wm == deps.WindowManagerHyprland { - dependencies = append(dependencies, a.detectHyprlandTools()...) - } - - // Niri-specific tools - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, a.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, a.detectMatugen()) - dependencies = append(dependencies, a.detectDgop()) - - return dependencies, nil -} - -func (a *ArchDistribution) detectXDGPortal() deps.Dependency { - return a.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", a.packageInstalled("xdg-desktop-portal-gtk")) -} - -func (a *ArchDistribution) detectAccountsService() deps.Dependency { - return a.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", a.packageInstalled("accountsservice")) -} - -func (a *ArchDistribution) detectDMSGreeter() deps.Dependency { - return a.detectOptionalPackage("dms-greeter", "DankMaterialShell greetd greeter", a.packageInstalled("greetd-dms-greeter-git")) -} - -func (a *ArchDistribution) packageInstalled(pkg string) bool { - cmd := exec.Command("pacman", "-Q", pkg) - err := cmd.Run() - return err == nil -} - -// parseSRCINFODeps reads a .SRCINFO file and returns runtime dep and makedep package -func parseSRCINFODeps(srcinfoPath string) (deps []string, makedeps []string, err error) { - data, err := os.ReadFile(srcinfoPath) - if err != nil { - return nil, nil, err - } - for _, line := range strings.Split(string(data), "\n") { - line = strings.TrimSpace(line) - var pkg string - var target *[]string - switch { - case strings.HasPrefix(line, "makedepends = "): - pkg = strings.TrimPrefix(line, "makedepends = ") - target = &makedeps - case strings.HasPrefix(line, "depends = "): - pkg = strings.TrimPrefix(line, "depends = ") - target = &deps - default: - continue - } - // Strip version constraint (>=, <=, >, <, =) and colon-descriptions - if idx := strings.IndexAny(pkg, "><:="); idx >= 0 { - pkg = pkg[:idx] - } - pkg = strings.TrimSpace(pkg) - if pkg != "" { - *target = append(*target, pkg) - } - } - return deps, makedeps, nil -} - -func (a *ArchDistribution) isInSystemRepo(pkg string) bool { - return exec.Command("pacman", "-Si", pkg).Run() == nil -} - -func (a *ArchDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return a.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (a *ArchDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - packages := map[string]PackageMapping{ - "dms (DankMaterialShell)": a.getDMSMapping(variants["dms (DankMaterialShell)"]), - "git": {Name: "git", Repository: RepoTypeSystem}, - "quickshell": a.getQuickshellMapping(variants["quickshell"]), - "dms-greeter": {Name: "greetd-dms-greeter-git", Repository: RepoTypeAUR}, - "matugen": a.getMatugenMapping(variants["matugen"]), - "dgop": {Name: "dgop", Repository: RepoTypeSystem}, - "ghostty": {Name: "ghostty", Repository: RepoTypeSystem}, - "kitty": {Name: "kitty", Repository: RepoTypeSystem}, - "alacritty": {Name: "alacritty", Repository: RepoTypeSystem}, - "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem}, - "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem}, - } - - switch wm { - case deps.WindowManagerHyprland: - packages["hyprland"] = a.getHyprlandMapping(variants["hyprland"]) - packages["hyprctl"] = a.getHyprlandMapping(variants["hyprland"]) - packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem} - case deps.WindowManagerNiri: - packages["niri"] = a.getNiriMapping(variants["niri"]) - packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeSystem} - } - - return packages -} - -func (a *ArchDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping { - if forceQuickshellGit || variant == deps.VariantGit { - return PackageMapping{Name: "quickshell-git", Repository: RepoTypeAUR} - } - // ! TODO - for now we're only forcing quickshell-git on ARCH, as other distros use DL repos which pin a newer quickshell - return PackageMapping{Name: "quickshell-git", Repository: RepoTypeAUR} -} - -func (a *ArchDistribution) getHyprlandMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "hyprland", Repository: RepoTypeSystem} -} - -func (a *ArchDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "niri-git", Repository: RepoTypeAUR} - } - return PackageMapping{Name: "niri", Repository: RepoTypeSystem} -} - -func (a *ArchDistribution) getMatugenMapping(variant deps.PackageVariant) PackageMapping { - if runtime.GOARCH == "arm64" { - return PackageMapping{Name: "matugen-git", Repository: RepoTypeAUR} - } - - if variant == deps.VariantGit { - return PackageMapping{Name: "matugen-git", Repository: RepoTypeAUR} - } - return PackageMapping{Name: "matugen", Repository: RepoTypeSystem} -} - -func (a *ArchDistribution) getDMSMapping(variant deps.PackageVariant) PackageMapping { - if forceDMSGit || variant == deps.VariantGit { - return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR} - } - - if a.packageInstalled("dms-shell-git") { - return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR} - } - - return PackageMapping{Name: "dms-shell", Repository: RepoTypeSystem} -} - -func (a *ArchDistribution) detectXwaylandSatellite() deps.Dependency { - status := deps.StatusMissing - if a.commandExists("xwayland-satellite") { - status = deps.StatusInstalled - } - - return deps.Dependency{ - Name: "xwayland-satellite", - Status: status, - Description: "Xwayland support", - Required: true, - } -} - -func (a *ArchDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Checking base-devel...", - IsComplete: false, - LogOutput: "Checking if base-devel is installed", - } - - checkCmd := exec.CommandContext(ctx, "pacman", "-Qq", "base-devel") - if err := checkCmd.Run(); err == nil { - a.log("base-devel already installed") - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.10, - Step: "base-devel already installed", - IsComplete: false, - LogOutput: "base-devel is already installed on the system", - } - return nil - } - - a.log("Installing base-devel...") - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: "Installing base-devel...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo pacman -S --needed --noconfirm base-devel", - LogOutput: "Installing base-devel development tools", - } - - cmd := ExecSudoCommand(ctx, sudoPassword, "pacman -S --needed --noconfirm base-devel") - if err := a.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.10); err != nil { - return fmt.Errorf("failed to install base-devel: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.12, - Step: "base-devel installation complete", - IsComplete: false, - LogOutput: "base-devel successfully installed", - } - - return nil -} - -func (a *ArchDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - // Phase 1: Check Prerequisites - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := a.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - systemPkgs, aurPkgs, manualPkgs, variantMap := a.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - if slices.Contains(aurPkgs, "quickshell-git") && slices.Contains(systemPkgs, "dms-shell") { - if err := a.preinstallQuickshellGit(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to preinstall quickshell-git: %w", err) - } - aurPkgs = slices.DeleteFunc(aurPkgs, func(p string) bool { return p == "quickshell-git" }) - } - - // Phase 3: System Packages - if len(systemPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")), - } - if err := a.installSystemPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install system packages: %w", err) - } - } - - // Phase 4: AUR Packages - if len(aurPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.65, - Step: fmt.Sprintf("Installing %d AUR packages...", len(aurPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing AUR packages: %s", strings.Join(aurPkgs, ", ")), - } - if err := a.installAURPackages(ctx, aurPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install AUR packages: %w", err) - } - } - - // Phase 5: Manual Builds - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := a.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - // Phase 6: Configuration - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := a.DetectTerminalFromDeps(dependencies) - if err := a.WriteEnvironmentConfig(terminal); err != nil { - a.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := a.WriteWindowManagerConfig(wm); err != nil { - a.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := a.EnableDMSService(ctx, wm); err != nil { - a.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - // Phase 7: Complete - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (a *ArchDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]string, []string, []string, map[string]deps.PackageVariant) { - systemPkgs := []string{} - aurPkgs := []string{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := a.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - manualPkgs = append(manualPkgs, dep.Name) - continue - } - - switch pkgInfo.Repository { - case RepoTypeAUR: - aurPkgs = append(aurPkgs, pkgInfo.Name) - case RepoTypeSystem: - systemPkgs = append(systemPkgs, pkgInfo.Name) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - return systemPkgs, aurPkgs, manualPkgs, variantMap -} - -func (a *ArchDistribution) preinstallQuickshellGit(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if a.packageInstalled("quickshell-git") { - return nil - } - - if a.packageInstalled("quickshell") { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.15, - Step: "Removing stable quickshell...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo pacman -Rdd --noconfirm quickshell", - LogOutput: "Removing stable quickshell so quickshell-git can be installed", - } - cmd := ExecSudoCommand(ctx, sudoPassword, "pacman -Rdd --noconfirm quickshell") - if err := a.runWithProgress(cmd, progressChan, PhaseAURPackages, 0.15, 0.18); err != nil { - return fmt.Errorf("failed to remove stable quickshell: %w", err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.18, - Step: "Building quickshell-git before system packages...", - IsComplete: false, - CommandInfo: "Installing quickshell-git ahead of dms-shell to avoid conflict", - } - return a.installSingleAURPackage(ctx, "quickshell-git", sudoPassword, progressChan, 0.18, 0.32) -} - -func (a *ArchDistribution) installSystemPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - a.log(fmt.Sprintf("Installing system packages: %s", strings.Join(packages, ", "))) - - args := []string{"pacman", "-S", "--needed", "--noconfirm"} - if slices.Contains(packages, "dms-shell") { - args = append(args, "--assume-installed", "dms-shell-compositor=1") - } - args = append(args, packages...) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.40, - Step: "Installing system packages...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return a.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60) -} - -func (a *ArchDistribution) installAURPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - a.log(fmt.Sprintf("Installing AUR packages manually: %s", strings.Join(packages, ", "))) - - hasNiri := false - for _, pkg := range packages { - if pkg == "niri-git" { - hasNiri = true - } - } - - // If niri is in the list, install makepkg-git-lfs-proto first if not already installed - if hasNiri { - if !a.packageInstalled("makepkg-git-lfs-proto") { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.65, - Step: "Installing makepkg-git-lfs-proto for niri...", - IsComplete: false, - CommandInfo: "Installing prerequisite for niri-git", - } - - if err := a.installSingleAURPackage(ctx, "makepkg-git-lfs-proto", sudoPassword, progressChan, 0.65, 0.67); err != nil { - return fmt.Errorf("failed to install makepkg-git-lfs-proto prerequisite for niri: %w", err) - } - } - } - - // Reorder packages to ensure dms-shell-git dependencies are installed first - orderedPackages := a.reorderAURPackages(packages) - - baseProgress := 0.67 - progressStep := 0.13 / float64(len(orderedPackages)) - - for i, pkg := range orderedPackages { - currentProgress := baseProgress + (float64(i) * progressStep) - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: currentProgress, - Step: fmt.Sprintf("Installing AUR package %s (%d/%d)...", pkg, i+1, len(packages)), - IsComplete: false, - CommandInfo: fmt.Sprintf("Building and installing %s", pkg), - } - - if err := a.installSingleAURPackage(ctx, pkg, sudoPassword, progressChan, currentProgress, currentProgress+progressStep); err != nil { - return fmt.Errorf("failed to install AUR package %s: %w", pkg, err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.80, - Step: "All AUR packages installed successfully", - IsComplete: false, - LogOutput: fmt.Sprintf("Successfully installed AUR packages: %s", strings.Join(packages, ", ")), - } - - return nil -} - -func (a *ArchDistribution) reorderAURPackages(packages []string) []string { - dmsDepencies := []string{"quickshell", "quickshell-git", "dgop"} - - var deps []string - var others []string - var dmsShell []string - - for _, pkg := range packages { - if pkg == "dms-shell-git" { - dmsShell = append(dmsShell, pkg) - } else { - isDep := false - if slices.Contains(dmsDepencies, pkg) { - deps = append(deps, pkg) - isDep = true - } - if !isDep { - others = append(others, pkg) - } - } - } - - result := append(deps, others...) - result = append(result, dmsShell...) - return result -} - -func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64) error { - return a.installSingleAURPackageInternal(ctx, pkg, sudoPassword, progressChan, startProgress, endProgress, make(map[string]bool)) -} - -func (a *ArchDistribution) installSingleAURPackageInternal(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64, visited map[string]bool) error { - if visited[pkg] { - a.log(fmt.Sprintf("Skipping %s (already being installed, cycle detected)", pkg)) - return nil - } - visited[pkg] = true - - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - buildDir := filepath.Join(homeDir, ".cache", "dankinstall", "aur-builds", pkg) - - // Clean up any existing cache first - if err := os.RemoveAll(buildDir); err != nil { - a.log(fmt.Sprintf("Warning: failed to clean existing cache for %s: %v", pkg, err)) - } - - if err := os.MkdirAll(buildDir, 0o755); err != nil { - return fmt.Errorf("failed to create build directory: %w", err) - } - defer func() { - if removeErr := os.RemoveAll(buildDir); removeErr != nil { - a.log(fmt.Sprintf("Warning: failed to cleanup build directory %s: %v", buildDir, removeErr)) - } - }() - - // Clone the AUR package - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.1*(endProgress-startProgress), - Step: fmt.Sprintf("Cloning %s from AUR...", pkg), - IsComplete: false, - CommandInfo: fmt.Sprintf("git clone https://aur.archlinux.org/%s.git", pkg), - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", fmt.Sprintf("https://aur.archlinux.org/%s.git", pkg), filepath.Join(buildDir, pkg)) - if err := a.runWithProgress(cloneCmd, progressChan, PhaseAURPackages, startProgress+0.1*(endProgress-startProgress), startProgress+0.2*(endProgress-startProgress)); err != nil { - return fmt.Errorf("failed to clone %s: %w", pkg, err) - } - - packageDir := filepath.Join(buildDir, pkg) - - if pkg == "niri-git" { - pkgbuildPath := filepath.Join(packageDir, "PKGBUILD") - sedCmd := exec.CommandContext(ctx, "sed", "-i", "s/makepkg-git-lfs-proto//g", pkgbuildPath) - if err := sedCmd.Run(); err != nil { - return fmt.Errorf("failed to patch PKGBUILD for niri-git: %w", err) - } - - srcinfoPath := filepath.Join(packageDir, ".SRCINFO") - sedCmd2 := exec.CommandContext(ctx, "sed", "-i", "/makedepends = makepkg-git-lfs-proto/d", srcinfoPath) - if err := sedCmd2.Run(); err != nil { - return fmt.Errorf("failed to patch .SRCINFO for niri-git: %w", err) - } - } - - if pkg == "dms-shell-git" { - srcinfoPath := filepath.Join(packageDir, ".SRCINFO") - depsToRemove := []string{ - "depends = quickshell", - "depends = dgop", - } - - for _, dep := range depsToRemove { - sedCmd := exec.CommandContext(ctx, "sed", "-i", fmt.Sprintf("/%s/d", dep), srcinfoPath) - if err := sedCmd.Run(); err != nil { - return fmt.Errorf("failed to remove dependency %s from .SRCINFO for %s: %w", dep, pkg, err) - } - } - } - - // Remove all optdepends from .SRCINFO for all packages - srcinfoPath := filepath.Join(packageDir, ".SRCINFO") - optdepsCmd := exec.CommandContext(ctx, "sed", "-i", "/^[[:space:]]*optdepends = /d", srcinfoPath) - if err := optdepsCmd.Run(); err != nil { - return fmt.Errorf("failed to remove optdepends from .SRCINFO for %s: %w", pkg, err) - } - - srcinfoPath = filepath.Join(packageDir, ".SRCINFO") - { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.3*(endProgress-startProgress), - Step: fmt.Sprintf("Resolving dependencies for %s...", pkg), - IsComplete: false, - CommandInfo: "Classifying dependencies as system or AUR", - } - - runtimeDeps, makeDeps, err := parseSRCINFODeps(srcinfoPath) - if err != nil { - return fmt.Errorf("failed to parse .SRCINFO for %s: %w", pkg, err) - } - - seen := make(map[string]bool) - var systemPkgs []string - var aurPkgs []string - - for _, dep := range append(runtimeDeps, makeDeps...) { - if seen[dep] || a.packageInstalled(dep) { - continue - } - seen[dep] = true - if a.isInSystemRepo(dep) { - systemPkgs = append(systemPkgs, dep) - } else { - aurPkgs = append(aurPkgs, dep) - } - } - - if len(systemPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.32*(endProgress-startProgress), - Step: fmt.Sprintf("Installing %d system dependencies for %s...", len(systemPkgs), pkg), - IsComplete: false, - CommandInfo: fmt.Sprintf("sudo pacman -S --needed --noconfirm %s", strings.Join(systemPkgs, " ")), - } - if err := a.installSystemPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install system dependencies for %s: %w", pkg, err) - } - } - - for _, aurDep := range aurPkgs { - a.log(fmt.Sprintf("Dependency %s is AUR-only, building from source...", aurDep)) - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.35*(endProgress-startProgress), - Step: fmt.Sprintf("Installing AUR dependency %s for %s...", aurDep, pkg), - IsComplete: false, - CommandInfo: fmt.Sprintf("Building AUR dependency: %s", aurDep), - } - if err := a.installSingleAURPackageInternal(ctx, aurDep, sudoPassword, progressChan, - startProgress+0.35*(endProgress-startProgress), - startProgress+0.39*(endProgress-startProgress), - visited, - ); err != nil { - return fmt.Errorf("failed to install AUR dependency %s for %s: %w", aurDep, pkg, err) - } - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.4*(endProgress-startProgress), - Step: fmt.Sprintf("Building %s...", pkg), - IsComplete: false, - CommandInfo: "makepkg --noconfirm", - } - - buildCmd := exec.CommandContext(ctx, "makepkg", "--noconfirm") - buildCmd.Dir = packageDir - buildCmd.Env = append(os.Environ(), "PKGEXT=.pkg.tar") - - if err := a.runWithProgress(buildCmd, progressChan, PhaseAURPackages, startProgress+0.4*(endProgress-startProgress), startProgress+0.7*(endProgress-startProgress)); err != nil { - return fmt.Errorf("failed to build %s: %w", pkg, err) - } - - // Find built package file - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.7*(endProgress-startProgress), - Step: fmt.Sprintf("Installing %s...", pkg), - IsComplete: false, - CommandInfo: "sudo pacman -U built-package", - } - - var files []string - matches, _ := filepath.Glob(filepath.Join(packageDir, "*.pkg.tar*")) - files = matches - - if len(files) == 0 { - return fmt.Errorf("no package files found after building %s", pkg) - } - - installArgs := []string{"pacman", "-U", "--noconfirm"} - installArgs = append(installArgs, files...) - - installCmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(installArgs, " ")) - - fileNames := make([]string, len(files)) - for i, f := range files { - fileNames[i] = filepath.Base(f) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress + 0.7*(endProgress-startProgress), - LogOutput: fmt.Sprintf("Installing packages: %s", strings.Join(fileNames, ", ")), - } - - if err := a.runWithProgress(installCmd, progressChan, PhaseAURPackages, startProgress+0.7*(endProgress-startProgress), endProgress); err != nil { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: startProgress, - LogOutput: fmt.Sprintf("ERROR: pacman -U failed for %s with error: %v", pkg, err), - Error: err, - } - return fmt.Errorf("failed to install built package %s: %w", pkg, err) - } - - a.log(fmt.Sprintf("Successfully installed AUR package: %s", pkg)) - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base.go deleted file mode 100644 index 63555c8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base.go +++ /dev/null @@ -1,721 +0,0 @@ -package distros - -import ( - "bufio" - "context" - _ "embed" - "fmt" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/version" -) - -const ( - forceQuickshellGit = false - forceDMSGit = false -) - -// BaseDistribution provides common functionality for all distributions -type BaseDistribution struct { - logChan chan<- string -} - -// NewBaseDistribution creates a new base distribution -func NewBaseDistribution(logChan chan<- string) *BaseDistribution { - return &BaseDistribution{ - logChan: logChan, - } -} - -// Common helper methods -func (b *BaseDistribution) commandExists(cmd string) bool { - _, err := exec.LookPath(cmd) - return err == nil -} - -func (b *BaseDistribution) CommandExists(cmd string) bool { - return b.commandExists(cmd) -} - -func (b *BaseDistribution) log(message string) { - if b.logChan != nil { - b.logChan <- message - } -} - -func (b *BaseDistribution) logError(message string, err error) { - errorMsg := fmt.Sprintf("ERROR: %s: %v", message, err) - b.log(errorMsg) -} - -// escapeSingleQuotes escapes single quotes in a string for safe use in bash single-quoted strings. -// It replaces each ' with '\” which closes the quote, adds an escaped quote, and reopens the quote. -// This prevents shell injection and syntax errors when passwords contain single quotes or apostrophes. -func escapeSingleQuotes(s string) string { - return strings.ReplaceAll(s, "'", "'\\''") -} - -// MakeSudoCommand creates a command string that safely passes password to sudo. -// This helper escapes special characters in the password to prevent shell injection -// and syntax errors when passwords contain single quotes, apostrophes, or other special chars. -func MakeSudoCommand(sudoPassword string, command string) string { - return fmt.Sprintf("echo '%s' | sudo -S %s", escapeSingleQuotes(sudoPassword), command) -} - -// ExecSudoCommand creates an exec.Cmd that runs a command with sudo using the provided password. -// The password is properly escaped to prevent shell injection and syntax errors. -func ExecSudoCommand(ctx context.Context, sudoPassword string, command string) *exec.Cmd { - cmdStr := MakeSudoCommand(sudoPassword, command) - return exec.CommandContext(ctx, "bash", "-c", cmdStr) -} - -func (b *BaseDistribution) detectCommand(name, description string) deps.Dependency { - status := deps.StatusMissing - if b.commandExists(name) { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: name, - Status: status, - Description: description, - Required: true, - } -} - -func (b *BaseDistribution) detectPackage(name, description string, installed bool) deps.Dependency { - status := deps.StatusMissing - if installed { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: name, - Status: status, - Description: description, - Required: true, - } -} - -func (b *BaseDistribution) detectOptionalPackage(name, description string, installed bool) deps.Dependency { - status := deps.StatusMissing - if installed { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: name, - Status: status, - Description: description, - Required: false, - } -} - -func (b *BaseDistribution) detectGit() deps.Dependency { - return b.detectCommand("git", "Version control system") -} - -func (b *BaseDistribution) detectMatugen() deps.Dependency { - return b.detectCommand("matugen", "Material Design color generation tool") -} - -func (b *BaseDistribution) detectDgop() deps.Dependency { - return b.detectCommand("dgop", "Desktop portal management tool") -} - -func (b *BaseDistribution) detectDMS() deps.Dependency { - dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms") - - status := deps.StatusMissing - currentVersion := "" - - if _, err := os.Stat(dmsPath); err == nil { - status = deps.StatusInstalled - - // Only get current version, don't check for updates (lazy loading) - current, err := version.GetCurrentDMSVersion() - if err == nil { - currentVersion = current - } - } - - dep := deps.Dependency{ - Name: "dms (DankMaterialShell)", - Status: status, - Description: "Desktop Management System configuration", - Required: true, - CanToggle: true, - } - - if currentVersion != "" { - dep.Version = currentVersion - } - - return dep -} - -func (b *BaseDistribution) detectSpecificTerminal(terminal deps.Terminal) deps.Dependency { - switch terminal { - case deps.TerminalGhostty: - status := deps.StatusMissing - if b.commandExists("ghostty") { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: "ghostty", - Status: status, - Description: "A fast, native terminal emulator built in Zig.", - Required: true, - } - case deps.TerminalKitty: - status := deps.StatusMissing - if b.commandExists("kitty") { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: "kitty", - Status: status, - Description: "A feature-rich, customizable terminal emulator.", - Required: true, - } - case deps.TerminalAlacritty: - status := deps.StatusMissing - if b.commandExists("alacritty") { - status = deps.StatusInstalled - } - return deps.Dependency{ - Name: "alacritty", - Status: status, - Description: "A simple terminal emulator. (No dynamic theming)", - Required: true, - } - default: - return b.detectSpecificTerminal(deps.TerminalGhostty) - } -} - -func (b *BaseDistribution) detectHyprlandTools() []deps.Dependency { - var dependencies []deps.Dependency - - tools := []struct { - name string - description string - }{ - {"hyprctl", "Hyprland control utility"}, - {"jq", "JSON processor"}, - } - - for _, tool := range tools { - status := deps.StatusMissing - if b.commandExists(tool.name) { - status = deps.StatusInstalled - } - - dependencies = append(dependencies, deps.Dependency{ - Name: tool.name, - Status: status, - Description: tool.description, - Required: true, - }) - } - - return dependencies -} - -func (b *BaseDistribution) detectQuickshell() deps.Dependency { - if !b.commandExists("qs") { - return deps.Dependency{ - Name: "quickshell", - Status: deps.StatusMissing, - Description: "QtQuick based desktop shell toolkit", - Required: true, - Variant: deps.VariantStable, - CanToggle: true, - } - } - - cmd := exec.Command("qs", "--version") - output, err := cmd.Output() - if err != nil { - return deps.Dependency{ - Name: "quickshell", - Status: deps.StatusNeedsReinstall, - Description: "QtQuick based desktop shell toolkit (version check failed)", - Required: true, - Variant: deps.VariantStable, - CanToggle: true, - } - } - - versionStr := string(output) - versionRegex := regexp.MustCompile(`quickshell (\d+\.\d+\.\d+)`) - matches := versionRegex.FindStringSubmatch(versionStr) - - if len(matches) < 2 { - return deps.Dependency{ - Name: "quickshell", - Status: deps.StatusNeedsReinstall, - Description: "QtQuick based desktop shell toolkit (unknown version)", - Required: true, - Variant: deps.VariantStable, - CanToggle: true, - } - } - - version := matches[1] - variant := deps.VariantStable - if strings.Contains(versionStr, "git") || strings.Contains(versionStr, "+") { - variant = deps.VariantGit - } - - if b.versionCompare(version, "0.2.0") >= 0 { - return deps.Dependency{ - Name: "quickshell", - Status: deps.StatusInstalled, - Version: version, - Description: "QtQuick based desktop shell toolkit", - Required: true, - Variant: variant, - CanToggle: true, - } - } - - return deps.Dependency{ - Name: "quickshell", - Status: deps.StatusNeedsUpdate, - Variant: variant, - CanToggle: true, - Version: version, - Description: "QtQuick based desktop shell toolkit (needs 0.2.0+)", - Required: true, - } -} - -func (b *BaseDistribution) detectWindowManager(wm deps.WindowManager) deps.Dependency { - switch wm { - case deps.WindowManagerHyprland: - status := deps.StatusMissing - variant := deps.VariantStable - version := "" - - if b.commandExists("hyprland") || b.commandExists("Hyprland") { - status = deps.StatusInstalled - cmd := exec.Command("hyprctl", "version") - if output, err := cmd.Output(); err == nil { - outStr := string(output) - if strings.Contains(outStr, "git") || strings.Contains(outStr, "dirty") { - variant = deps.VariantGit - } - if versionRegex := regexp.MustCompile(`v(\d+\.\d+\.\d+)`); versionRegex.MatchString(outStr) { - matches := versionRegex.FindStringSubmatch(outStr) - if len(matches) > 1 { - version = matches[1] - } - } - } - } - return deps.Dependency{ - Name: "hyprland", - Status: status, - Version: version, - Description: "Dynamic tiling Wayland compositor", - Required: true, - Variant: variant, - CanToggle: true, - } - case deps.WindowManagerNiri: - status := deps.StatusMissing - variant := deps.VariantStable - version := "" - - if b.commandExists("niri") { - status = deps.StatusInstalled - cmd := exec.Command("niri", "--version") - if output, err := cmd.Output(); err == nil { - outStr := string(output) - if strings.Contains(outStr, "git") || strings.Contains(outStr, "+") { - variant = deps.VariantGit - } - if versionRegex := regexp.MustCompile(`niri (\d+\.\d+)`); versionRegex.MatchString(outStr) { - matches := versionRegex.FindStringSubmatch(outStr) - if len(matches) > 1 { - version = matches[1] - } - } - } - } - return deps.Dependency{ - Name: "niri", - Status: status, - Version: version, - Description: "Scrollable-tiling Wayland compositor", - Required: true, - Variant: variant, - CanToggle: true, - } - default: - return deps.Dependency{ - Name: "unknown-wm", - Status: deps.StatusMissing, - Description: "Unknown window manager", - Required: true, - } - } -} - -// Version comparison helper -func (b *BaseDistribution) versionCompare(v1, v2 string) int { - parts1 := strings.Split(v1, ".") - parts2 := strings.Split(v2, ".") - - for i := 0; i < len(parts1) && i < len(parts2); i++ { - if parts1[i] < parts2[i] { - return -1 - } - if parts1[i] > parts2[i] { - return 1 - } - } - - if len(parts1) < len(parts2) { - return -1 - } - if len(parts1) > len(parts2) { - return 1 - } - - return 0 -} - -// Common installation helper -func (b *BaseDistribution) runWithProgress(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64) error { - return b.runWithProgressTimeout(cmd, progressChan, phase, startProgress, endProgress, 20*time.Minute) -} - -func (b *BaseDistribution) runWithProgressTimeout(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64, timeout time.Duration) error { - return b.runWithProgressStepTimeout(cmd, progressChan, phase, startProgress, endProgress, "Installing...", timeout) -} - -func (b *BaseDistribution) runWithProgressStep(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64, stepMessage string) error { - return b.runWithProgressStepTimeout(cmd, progressChan, phase, startProgress, endProgress, stepMessage, 20*time.Minute) -} - -func (b *BaseDistribution) runWithProgressStepTimeout(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64, stepMessage string, timeoutDuration time.Duration) error { - stdout, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("failed to create stdout pipe: %w", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - return fmt.Errorf("failed to create stderr pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - return err - } - - outputChan := make(chan string, 100) - done := make(chan error, 1) - - go func() { - scanner := bufio.NewScanner(stdout) - for scanner.Scan() { - line := scanner.Text() - b.log(line) - outputChan <- line - } - }() - - go func() { - scanner := bufio.NewScanner(stderr) - for scanner.Scan() { - line := scanner.Text() - b.log(line) - outputChan <- line - } - }() - - go func() { - done <- cmd.Wait() - close(outputChan) - }() - - ticker := time.NewTicker(200 * time.Millisecond) - defer ticker.Stop() - - progress := startProgress - progressStep := (endProgress - startProgress) / 50 - lastOutput := "" - - var timeout *time.Timer - var timeoutChan <-chan time.Time - if timeoutDuration > 0 { - timeout = time.NewTimer(timeoutDuration) - defer timeout.Stop() - timeoutChan = timeout.C - } - - for { - select { - case err := <-done: - if err != nil { - b.logError("Command execution failed", err) - b.log(fmt.Sprintf("Last output before failure: %s", lastOutput)) - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: startProgress, - Step: "Command failed", - IsComplete: false, - LogOutput: lastOutput, - Error: err, - } - return err - } - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: endProgress, - Step: "Installation step complete", - IsComplete: false, - LogOutput: lastOutput, - } - return nil - case output, ok := <-outputChan: - if ok { - lastOutput = output - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: progress, - Step: stepMessage, - IsComplete: false, - LogOutput: output, - } - if timeout != nil { - timeout.Reset(timeoutDuration) - } - } - case <-timeoutChan: - if cmd.Process != nil { - cmd.Process.Kill() - } - err := fmt.Errorf("installation timed out after %v", timeoutDuration) - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: startProgress, - Step: "Installation timed out", - IsComplete: false, - LogOutput: lastOutput, - Error: err, - } - return err - case <-ticker.C: - if progress < endProgress-0.01 { - progress += progressStep - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: progress, - Step: "Installing...", - IsComplete: false, - LogOutput: lastOutput, - } - } - } - } -} - -func (b *BaseDistribution) DetectTerminalFromDeps(dependencies []deps.Dependency) deps.Terminal { - for _, dep := range dependencies { - switch dep.Name { - case "ghostty": - return deps.TerminalGhostty - case "kitty": - return deps.TerminalKitty - case "alacritty": - return deps.TerminalAlacritty - } - } - return deps.TerminalGhostty -} - -func (b *BaseDistribution) WriteEnvironmentConfig(terminal deps.Terminal) error { - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get home directory: %w", err) - } - - envDir := filepath.Join(homeDir, ".config", "environment.d") - if err := os.MkdirAll(envDir, 0o755); err != nil { - return fmt.Errorf("failed to create environment.d directory: %w", err) - } - - var terminalCmd string - switch terminal { - case deps.TerminalGhostty: - terminalCmd = "ghostty" - case deps.TerminalKitty: - terminalCmd = "kitty" - case deps.TerminalAlacritty: - terminalCmd = "alacritty" - default: - terminalCmd = "ghostty" - } - - content := fmt.Sprintf(`ELECTRON_OZONE_PLATFORM_HINT=auto -TERMINAL=%s -`, terminalCmd) - - envFile := filepath.Join(envDir, "90-dms.conf") - if err := os.WriteFile(envFile, []byte(content), 0o644); err != nil { - return fmt.Errorf("failed to write environment config: %w", err) - } - - b.log(fmt.Sprintf("Wrote environment config to %s", envFile)) - return nil -} - -func (b *BaseDistribution) EnableDMSService(ctx context.Context, wm deps.WindowManager) error { - switch wm { - case deps.WindowManagerNiri: - if err := exec.CommandContext(ctx, "systemctl", "--user", "add-wants", "niri.service", "dms").Run(); err != nil { - b.log("Warning: failed to add dms as a want for niri.service") - } - case deps.WindowManagerHyprland: - if err := exec.CommandContext(ctx, "systemctl", "--user", "add-wants", "hyprland-session.target", "dms").Run(); err != nil { - b.log("Warning: failed to add dms as a want for hyprland-session.target") - } - } - - return nil -} - -func (b *BaseDistribution) WriteWindowManagerConfig(wm deps.WindowManager) error { - if wm == deps.WindowManagerHyprland { - if err := b.WriteHyprlandSessionTarget(); err != nil { - return fmt.Errorf("failed to write hyprland session target: %w", err) - } - } - return nil -} - -func (b *BaseDistribution) WriteHyprlandSessionTarget() error { - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get home directory: %w", err) - } - - targetDir := filepath.Join(homeDir, ".config", "systemd", "user") - if err := os.MkdirAll(targetDir, 0o755); err != nil { - return fmt.Errorf("failed to create systemd user directory: %w", err) - } - - targetPath := filepath.Join(targetDir, "hyprland-session.target") - content := `[Unit] -Description=Hyprland Session Target -Requires=graphical-session.target -After=graphical-session.target -` - - if err := os.WriteFile(targetPath, []byte(content), 0o644); err != nil { - return fmt.Errorf("failed to write hyprland-session.target: %w", err) - } - - b.log(fmt.Sprintf("Wrote hyprland-session.target to %s", targetPath)) - return nil -} - -// installDMSBinary installs the DMS binary from GitHub releases -func (b *BaseDistribution) installDMSBinary(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - b.log("Installing/updating DMS binary...") - - // Detect architecture - arch := runtime.GOARCH - switch arch { - case "amd64": - case "arm64": - default: - return fmt.Errorf("unsupported architecture for DMS: %s", arch) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.80, - Step: "Downloading DMS binary...", - IsComplete: false, - CommandInfo: fmt.Sprintf("Downloading dms-%s.gz", arch), - } - - // Get latest release version - latestVersionCmd := exec.CommandContext(ctx, "bash", "-c", - `curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'`) - versionOutput, err := latestVersionCmd.Output() - if err != nil { - return fmt.Errorf("failed to get latest DMS version: %w", err) - } - version := strings.TrimSpace(string(versionOutput)) - if version == "" { - return fmt.Errorf("could not determine latest DMS version") - } - - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - tmpDir := filepath.Join(homeDir, ".cache", "dankinstall", "manual-builds") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - // Download the gzipped binary - downloadURL := fmt.Sprintf("https://github.com/AvengeMedia/DankMaterialShell/releases/download/%s/dms-cli-%s.gz", version, arch) - gzPath := filepath.Join(tmpDir, "dms.gz") - - downloadCmd := exec.CommandContext(ctx, "curl", "-L", downloadURL, "-o", gzPath) - if err := downloadCmd.Run(); err != nil { - return fmt.Errorf("failed to download DMS binary: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.85, - Step: "Extracting DMS binary...", - IsComplete: false, - CommandInfo: "gunzip dms.gz", - } - - // Extract the binary - extractCmd := exec.CommandContext(ctx, "gunzip", gzPath) - if err := extractCmd.Run(); err != nil { - return fmt.Errorf("failed to extract DMS binary: %w", err) - } - - binaryPath := filepath.Join(tmpDir, "dms") - - // Make it executable - chmodCmd := exec.CommandContext(ctx, "chmod", "+x", binaryPath) - if err := chmodCmd.Run(); err != nil { - return fmt.Errorf("failed to make DMS binary executable: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.88, - Step: "Installing DMS to /usr/local/bin...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo cp dms /usr/local/bin/", - } - - // Install to /usr/local/bin - installCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("cp %s /usr/local/bin/dms", binaryPath)) - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install DMS binary: %w", err) - } - - b.log("DMS binary installed successfully") - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base_test.go deleted file mode 100644 index 51e86d7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/base_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package distros - -import ( - "os" - "os/exec" - "path/filepath" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func TestBaseDistribution_detectDMS_NotInstalled(t *testing.T) { - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - - tempDir := t.TempDir() - os.Setenv("HOME", tempDir) - - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - dep := base.detectDMS() - - if dep.Status != deps.StatusMissing { - t.Errorf("Expected StatusMissing, got %d", dep.Status) - } - - if dep.Name != "dms (DankMaterialShell)" { - t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name) - } - - if !dep.Required { - t.Error("Expected Required to be true") - } -} - -func TestBaseDistribution_detectDMS_Installed(t *testing.T) { - if !utils.CommandExists("git") { - t.Skip("git not available") - } - - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - exec.Command("git", "init", dmsPath).Run() - exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run() - exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", dmsPath, "checkout", "-b", "master").Run() - - testFile := filepath.Join(dmsPath, "test.txt") - os.WriteFile(testFile, []byte("test"), 0o644) - exec.Command("git", "-C", dmsPath, "add", ".").Run() - exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run() - - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - dep := base.detectDMS() - - if dep.Status == deps.StatusMissing { - t.Error("Expected DMS to be detected as installed") - } - - if dep.Name != "dms (DankMaterialShell)" { - t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name) - } - - if !dep.Required { - t.Error("Expected Required to be true") - } - - t.Logf("Status: %d, Version: %s", dep.Status, dep.Version) -} - -func TestBaseDistribution_detectDMS_NeedsUpdate(t *testing.T) { - if !utils.CommandExists("git") { - t.Skip("git not available") - } - - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - exec.Command("git", "init", dmsPath).Run() - exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run() - exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", dmsPath, "remote", "add", "origin", "https://github.com/AvengeMedia/DankMaterialShell.git").Run() - - testFile := filepath.Join(dmsPath, "test.txt") - os.WriteFile(testFile, []byte("test"), 0o644) - exec.Command("git", "-C", dmsPath, "add", ".").Run() - exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run() - exec.Command("git", "-C", dmsPath, "tag", "v0.0.1").Run() - exec.Command("git", "-C", dmsPath, "checkout", "v0.0.1").Run() - - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - dep := base.detectDMS() - - if dep.Name != "dms (DankMaterialShell)" { - t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name) - } - - if !dep.Required { - t.Error("Expected Required to be true") - } - - t.Logf("Status: %d, Version: %s", dep.Status, dep.Version) -} - -func TestBaseDistribution_detectDMS_DirectoryWithoutGit(t *testing.T) { - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - dep := base.detectDMS() - - if dep.Status == deps.StatusMissing { - t.Error("Expected DMS to be detected as present") - } - - if dep.Name != "dms (DankMaterialShell)" { - t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name) - } - - if !dep.Required { - t.Error("Expected Required to be true") - } -} - -func TestBaseDistribution_NewBaseDistribution(t *testing.T) { - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - - if base == nil { - t.Fatal("NewBaseDistribution returned nil") - } - - if base.logChan == nil { - t.Error("logChan was not set") - } -} - -func TestBaseDistribution_versionCompare(t *testing.T) { - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - - tests := []struct { - v1 string - v2 string - expected int - }{ - {"0.1.0", "0.1.0", 0}, - {"0.1.0", "0.1.1", -1}, - {"0.1.1", "0.1.0", 1}, - {"0.2.0", "0.1.9", 1}, - {"1.0.0", "0.9.9", 1}, - } - - for _, tt := range tests { - result := base.versionCompare(tt.v1, tt.v2) - if result != tt.expected { - t.Errorf("versionCompare(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected) - } - } -} - -func TestBaseDistribution_versionCompare_WithPrefix(t *testing.T) { - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - - tests := []struct { - v1 string - v2 string - expected int - }{ - {"v0.1.0", "v0.1.0", 0}, - {"v0.1.0", "v0.1.1", -1}, - {"v0.1.1", "v0.1.0", 1}, - } - - for _, tt := range tests { - result := base.versionCompare(tt.v1, tt.v2) - if result != tt.expected { - t.Errorf("versionCompare(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/debian.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/debian.go deleted file mode 100644 index a3537ff..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/debian.go +++ /dev/null @@ -1,706 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os/exec" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func init() { - Register("debian", "#A80030", FamilyDebian, func(config DistroConfig, logChan chan<- string) Distribution { - return NewDebianDistribution(config, logChan) - }) -} - -type DebianDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig -} - -func NewDebianDistribution(config DistroConfig, logChan chan<- string) *DebianDistribution { - base := NewBaseDistribution(logChan) - return &DebianDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (d *DebianDistribution) GetID() string { - return d.config.ID -} - -func (d *DebianDistribution) GetColorHex() string { - return d.config.ColorHex -} - -func (d *DebianDistribution) GetFamily() DistroFamily { - return d.config.Family -} - -func (d *DebianDistribution) GetPackageManager() PackageManagerType { - return PackageManagerAPT -} - -func (d *DebianDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return d.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (d *DebianDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - dependencies = append(dependencies, d.detectDMS()) - - dependencies = append(dependencies, d.detectSpecificTerminal(terminal)) - - dependencies = append(dependencies, d.detectGit()) - dependencies = append(dependencies, d.detectWindowManager(wm)) - dependencies = append(dependencies, d.detectQuickshell()) - dependencies = append(dependencies, d.detectDMSGreeter()) - dependencies = append(dependencies, d.detectXDGPortal()) - dependencies = append(dependencies, d.detectAccountsService()) - - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, d.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, d.detectMatugen()) - dependencies = append(dependencies, d.detectDgop()) - - return dependencies, nil -} - -func (d *DebianDistribution) detectXDGPortal() deps.Dependency { - return d.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", d.packageInstalled("xdg-desktop-portal-gtk")) -} - -func (d *DebianDistribution) detectXwaylandSatellite() deps.Dependency { - return d.detectCommand("xwayland-satellite", "Xwayland support") -} - -func (d *DebianDistribution) detectAccountsService() deps.Dependency { - return d.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", d.packageInstalled("accountsservice")) -} - -func (d *DebianDistribution) detectDMSGreeter() deps.Dependency { - return d.detectOptionalPackage("dms-greeter", "DankMaterialShell greetd greeter", d.packageInstalled("dms-greeter")) -} - -func (d *DebianDistribution) packageInstalled(pkg string) bool { - return debianPackageInstalledPrecisely(pkg) -} - -func debianPackageInstalledPrecisely(pkg string) bool { - cmd := exec.Command("dpkg-query", "-W", "-f=${db:Status-Status}", pkg) - output, err := cmd.Output() - if err != nil { - return false - } - return strings.TrimSpace(string(output)) == "installed" -} - -func debianRepoArchitecture(arch string) string { - switch arch { - case "amd64", "x86_64": - return "amd64" - case "arm64", "aarch64": - return "arm64" - default: - return arch - } -} - -func (d *DebianDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return d.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (d *DebianDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - packages := map[string]PackageMapping{ - // Standard APT packages - "git": {Name: "git", Repository: RepoTypeSystem}, - "kitty": {Name: "kitty", Repository: RepoTypeSystem}, - "alacritty": {Name: "alacritty", Repository: RepoTypeSystem}, - "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem}, - "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem}, - - // DMS packages from OBS with variant support - "dms (DankMaterialShell)": d.getDmsMapping(variants["dms (DankMaterialShell)"]), - "quickshell": d.getQuickshellMapping(variants["quickshell"]), - "dms-greeter": {Name: "dms-greeter", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - } - - if wm == deps.WindowManagerNiri { - niriVariant := variants["niri"] - packages["niri"] = d.getNiriMapping(niriVariant) - packages["xwayland-satellite"] = d.getXwaylandSatelliteMapping(niriVariant) - } - - return packages -} - -func (d *DebianDistribution) getDmsMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "dms-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:dms-git"} - } - return PackageMapping{Name: "dms", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:dms"} -} - -func (d *DebianDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping { - if forceQuickshellGit || variant == deps.VariantGit { - return PackageMapping{Name: "quickshell-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "quickshell", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} -} - -func (d *DebianDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "niri-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "niri", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} -} - -func (d *DebianDistribution) getXwaylandSatelliteMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "xwayland-satellite-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} -} - -func (d *DebianDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Updating package lists...", - IsComplete: false, - LogOutput: "Updating APT package lists", - } - - updateCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get update") - if err := d.runWithProgress(updateCmd, progressChan, PhasePrerequisites, 0.06, 0.07); err != nil { - return fmt.Errorf("failed to update package lists: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: "Installing build-essential...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install -y build-essential", - LogOutput: "Installing build tools", - } - - checkCmd := exec.CommandContext(ctx, "dpkg", "-l", "build-essential") - if err := checkCmd.Run(); err != nil { - cmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential") - if err := d.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.09); err != nil { - return fmt.Errorf("failed to install build-essential: %w", err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.10, - Step: "Installing development dependencies...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install -y curl wget git cmake ninja-build pkg-config gnupg libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev", - LogOutput: "Installing additional development tools", - } - - devToolsCmd := ExecSudoCommand(ctx, sudoPassword, - "DEBIAN_FRONTEND=noninteractive apt-get install -y curl wget git cmake ninja-build pkg-config gnupg libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev libjpeg-dev libpugixml-dev") - if err := d.runWithProgress(devToolsCmd, progressChan, PhasePrerequisites, 0.10, 0.12); err != nil { - return fmt.Errorf("failed to install development tools: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.12, - Step: "Prerequisites installation complete", - IsComplete: false, - LogOutput: "Prerequisites successfully installed", - } - - return nil -} - -func (d *DebianDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := d.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - systemPkgs, obsPkgs, manualPkgs, variantMap := d.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - // Enable OBS repositories - if len(obsPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.15, - Step: "Enabling OBS repositories...", - IsComplete: false, - LogOutput: "Setting up OBS repositories for additional packages", - } - if err := d.enableOBSRepos(ctx, obsPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to enable OBS repositories: %w", err) - } - } - - // System Packages - if len(systemPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")), - } - if err := d.installAPTPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install APT packages: %w", err) - } - } - - // OBS Packages - obsPkgNames := d.extractPackageNames(obsPkgs) - if len(obsPkgNames) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.65, - Step: fmt.Sprintf("Installing %d OBS packages...", len(obsPkgNames)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing OBS packages: %s", strings.Join(obsPkgNames, ", ")), - } - if err := d.installAPTPackages(ctx, obsPkgNames, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install OBS packages: %w", err) - } - } - - // Manual Builds - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.80, - Step: "Installing build dependencies...", - IsComplete: false, - LogOutput: "Installing build tools for manual compilation", - } - if err := d.installBuildDependencies(ctx, manualPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install build dependencies: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := d.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := d.DetectTerminalFromDeps(dependencies) - if err := d.WriteEnvironmentConfig(terminal); err != nil { - d.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := d.WriteWindowManagerConfig(wm); err != nil { - d.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := d.EnableDMSService(ctx, wm); err != nil { - d.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (d *DebianDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]string, []PackageMapping, []string, map[string]deps.PackageVariant) { - systemPkgs := []string{} - obsPkgs := []PackageMapping{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := d.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - d.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name)) - continue - } - - switch pkgInfo.Repository { - case RepoTypeSystem: - systemPkgs = append(systemPkgs, pkgInfo.Name) - case RepoTypeOBS: - obsPkgs = append(obsPkgs, pkgInfo) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - return systemPkgs, obsPkgs, manualPkgs, variantMap -} - -func (d *DebianDistribution) extractPackageNames(packages []PackageMapping) []string { - names := make([]string, len(packages)) - for i, pkg := range packages { - names[i] = pkg.Name - } - return names -} - -func (d *DebianDistribution) aptInstallArgs(packages []string, minimal bool) []string { - args := []string{"DEBIAN_FRONTEND=noninteractive", "apt-get", "install", "-y"} - if minimal { - args = append(args, "--no-install-recommends") - } - return append(args, packages...) -} - -func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - enabledRepos := make(map[string]bool) - - osInfo, err := GetOSInfo() - if err != nil { - return fmt.Errorf("failed to get OS info: %w", err) - } - - // Determine Debian version for OBS repository URL - debianVersion := "Debian_13" - if osInfo.VersionID == "testing" { - debianVersion = "Debian_Testing" - } else if osInfo.VersionCodename == "sid" || osInfo.VersionID == "sid" || strings.Contains(strings.ToLower(osInfo.PrettyName), "sid") || strings.Contains(strings.ToLower(osInfo.PrettyName), "unstable") { - debianVersion = "Debian_Unstable" - } - - for _, pkg := range obsPkgs { - if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] { - d.log(fmt.Sprintf("Enabling OBS repository: %s", pkg.RepoURL)) - - // RepoURL format: "home:AvengeMedia:danklinux" - repoPath := strings.ReplaceAll(pkg.RepoURL, ":", ":/") - repoName := strings.ReplaceAll(pkg.RepoURL, ":", "-") - baseURL := fmt.Sprintf("https://download.opensuse.org/repositories/%s/%s", repoPath, debianVersion) - - // Check if repository already exists - listFile := fmt.Sprintf("/etc/apt/sources.list.d/%s.list", repoName) - checkCmd := exec.CommandContext(ctx, "test", "-f", listFile) - if checkCmd.Run() == nil { - d.log(fmt.Sprintf("OBS repo %s already exists, skipping", pkg.RepoURL)) - enabledRepos[pkg.RepoURL] = true - continue - } - - keyringPath := fmt.Sprintf("/etc/apt/keyrings/%s.gpg", repoName) - - // Create keyrings directory if it doesn't exist - mkdirCmd := ExecSudoCommand(ctx, sudoPassword, "mkdir -p /etc/apt/keyrings") - if err := mkdirCmd.Run(); err != nil { - d.log(fmt.Sprintf("Warning: failed to create keyrings directory: %v", err)) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.18, - Step: fmt.Sprintf("Adding OBS GPG key for %s...", pkg.RepoURL), - NeedsSudo: true, - CommandInfo: fmt.Sprintf("curl & gpg to add key for %s", pkg.RepoURL), - } - - keyCmd := fmt.Sprintf("bash -c 'rm -f %s && curl -fsSL %s/Release.key | gpg --batch --dearmor -o %s'", keyringPath, baseURL, keyringPath) - cmd := ExecSudoCommand(ctx, sudoPassword, keyCmd) - if err := d.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.18, 0.20); err != nil { - return fmt.Errorf("failed to add OBS GPG key for %s: %w", pkg.RepoURL, err) - } - - // Add repository - repoLine := fmt.Sprintf("deb [signed-by=%s arch=%s] %s/ /", keyringPath, debianRepoArchitecture(osInfo.Architecture), baseURL) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.20, - Step: fmt.Sprintf("Adding OBS repository %s...", pkg.RepoURL), - NeedsSudo: true, - CommandInfo: fmt.Sprintf("echo '%s' | sudo tee %s", repoLine, listFile), - } - - addRepoCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("bash -c \"echo '%s' | tee %s\"", repoLine, listFile)) - if err := d.runWithProgress(addRepoCmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil { - return fmt.Errorf("failed to add OBS repo %s: %w", pkg.RepoURL, err) - } - - enabledRepos[pkg.RepoURL] = true - d.log(fmt.Sprintf("OBS repo %s enabled successfully", pkg.RepoURL)) - } - } - - if len(enabledRepos) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.25, - Step: "Updating package lists...", - NeedsSudo: true, - CommandInfo: "sudo apt-get update", - } - - updateCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get update") - if err := d.runWithProgress(updateCmd, progressChan, PhaseSystemPackages, 0.25, 0.27); err != nil { - return fmt.Errorf("failed to update package lists after adding OBS repos: %w", err) - } - } - - return nil -} - -func (d *DebianDistribution) installAPTPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - d.log(fmt.Sprintf("Installing APT packages: %s", strings.Join(packages, ", "))) - - groups := orderedMinimalInstallGroups(packages) - totalGroups := len(groups) - - groupIndex := 0 - installGroup := func(groupPackages []string, minimal bool) error { - if len(groupPackages) == 0 { - return nil - } - - groupIndex++ - startProgress := 0.40 - endProgress := 0.60 - if totalGroups > 1 { - if groupIndex == 1 { - endProgress = 0.50 - } else { - startProgress = 0.50 - } - } - - args := d.aptInstallArgs(groupPackages, minimal) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: startProgress, - Step: "Installing system packages...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return d.runWithProgress(cmd, progressChan, PhaseSystemPackages, startProgress, endProgress) - } - - for _, group := range groups { - if err := installGroup(group.packages, group.minimal); err != nil { - return err - } - } - return nil -} - -func (d *DebianDistribution) installBuildDependencies(ctx context.Context, manualPkgs []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - buildDeps := make(map[string]bool) - - for _, pkg := range manualPkgs { - switch pkg { - case "niri": - buildDeps["curl"] = true - buildDeps["libxkbcommon-dev"] = true - buildDeps["libwayland-dev"] = true - buildDeps["libudev-dev"] = true - buildDeps["libinput-dev"] = true - buildDeps["libdisplay-info-dev"] = true - buildDeps["libpango1.0-dev"] = true - buildDeps["libcairo-dev"] = true - buildDeps["libpipewire-0.3-dev"] = true - buildDeps["libc6-dev"] = true - buildDeps["clang"] = true - buildDeps["libseat-dev"] = true - buildDeps["libgbm-dev"] = true - buildDeps["alacritty"] = true - buildDeps["fuzzel"] = true - case "quickshell": - buildDeps["qt6-base-dev"] = true - buildDeps["qt6-base-private-dev"] = true - buildDeps["qt6-declarative-dev"] = true - buildDeps["qt6-declarative-private-dev"] = true - buildDeps["qt6-wayland-dev"] = true - buildDeps["qt6-wayland-private-dev"] = true - buildDeps["qt6-tools-dev"] = true - buildDeps["libqt6svg6-dev"] = true - buildDeps["qt6-shadertools-dev"] = true - buildDeps["spirv-tools"] = true - buildDeps["libcli11-dev"] = true - buildDeps["libjemalloc-dev"] = true - buildDeps["libwayland-dev"] = true - buildDeps["wayland-protocols"] = true - buildDeps["libdrm-dev"] = true - buildDeps["libgbm-dev"] = true - buildDeps["libegl-dev"] = true - buildDeps["libgles2-mesa-dev"] = true - buildDeps["libgl1-mesa-dev"] = true - buildDeps["libxcb1-dev"] = true - buildDeps["libpipewire-0.3-dev"] = true - buildDeps["libpam0g-dev"] = true - case "ghostty": - buildDeps["curl"] = true - case "matugen": - buildDeps["curl"] = true - } - } - - for _, pkg := range manualPkgs { - switch pkg { - case "niri", "matugen": - if err := d.installRust(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Rust: %w", err) - } - case "dgop": - if err := d.installGo(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Go: %w", err) - } - } - } - - if len(buildDeps) == 0 { - return nil - } - - depList := make([]string, 0, len(buildDeps)) - for dep := range buildDeps { - depList = append(depList, dep) - } - - args := []string{"apt-get", "install", "-y"} - args = append(args, depList...) - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return d.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.80, 0.82) -} - -func (d *DebianDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if d.commandExists("cargo") { - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.82, - Step: "Installing rustup...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install rustup", - } - - rustupInstallCmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y rustup") - if err := d.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil { - return fmt.Errorf("failed to install rustup: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.83, - Step: "Installing stable Rust toolchain...", - IsComplete: false, - CommandInfo: "rustup install stable", - } - - rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable") - if err := d.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil { - return fmt.Errorf("failed to install Rust toolchain: %w", err) - } - - if !d.commandExists("cargo") { - d.log("Warning: cargo not found in PATH after Rust installation, trying to source environment") - } - - return nil -} - -func (d *DebianDistribution) installGo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if d.commandExists("go") { - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.87, - Step: "Installing Go...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install golang-go", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y golang-go") - return d.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.87, 0.90) -} - -func (d *DebianDistribution) InstallManualPackages(ctx context.Context, packages []string, variantMap map[string]deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - d.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", "))) - - for _, pkg := range packages { - switch pkg { - default: - if err := d.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install %s: %w", pkg, err) - } - } - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/factory.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/factory.go deleted file mode 100644 index 9c3826a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/factory.go +++ /dev/null @@ -1,19 +0,0 @@ -package distros - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -// NewDependencyDetector creates a DependencyDetector for the specified distribution -func NewDependencyDetector(distribution string, logChan chan<- string) (deps.DependencyDetector, error) { - distro, err := NewDistribution(distribution, logChan) - if err != nil { - return nil, err - } - return distro, nil -} - -// NewPackageInstaller creates a Distribution for package installation -func NewPackageInstaller(distribution string, logChan chan<- string) (Distribution, error) { - return NewDistribution(distribution, logChan) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/fedora.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/fedora.go deleted file mode 100644 index 4c16d4e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/fedora.go +++ /dev/null @@ -1,550 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os/exec" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func init() { - Register("fedora", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) - Register("evernight", "#72B8DC", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) - Register("nobara", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) - Register("fedora-asahi-remix", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) - Register("bluefin", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) - Register("ultramarine", "#00078b", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution { - return NewFedoraDistribution(config, logChan) - }) -} - -type FedoraDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig -} - -func NewFedoraDistribution(config DistroConfig, logChan chan<- string) *FedoraDistribution { - base := NewBaseDistribution(logChan) - return &FedoraDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (f *FedoraDistribution) GetID() string { - return f.config.ID -} - -func (f *FedoraDistribution) GetColorHex() string { - return f.config.ColorHex -} - -func (f *FedoraDistribution) GetFamily() DistroFamily { - return f.config.Family -} - -func (f *FedoraDistribution) GetPackageManager() PackageManagerType { - return PackageManagerDNF -} - -func (f *FedoraDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return f.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (f *FedoraDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - // DMS at the top (shell is prominent) - dependencies = append(dependencies, f.detectDMS()) - - // Terminal with choice support - dependencies = append(dependencies, f.detectSpecificTerminal(terminal)) - - // Common detections using base methods - dependencies = append(dependencies, f.detectGit()) - dependencies = append(dependencies, f.detectWindowManager(wm)) - dependencies = append(dependencies, f.detectQuickshell()) - dependencies = append(dependencies, f.detectDMSGreeter()) - dependencies = append(dependencies, f.detectXDGPortal()) - dependencies = append(dependencies, f.detectAccountsService()) - - // Hyprland-specific tools - if wm == deps.WindowManagerHyprland { - dependencies = append(dependencies, f.detectHyprlandTools()...) - } - - // Niri-specific tools - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, f.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, f.detectMatugen()) - dependencies = append(dependencies, f.detectDgop()) - - return dependencies, nil -} - -func (f *FedoraDistribution) detectXDGPortal() deps.Dependency { - return f.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", f.packageInstalled("xdg-desktop-portal-gtk")) -} - -func (f *FedoraDistribution) packageInstalled(pkg string) bool { - cmd := exec.Command("rpm", "-q", pkg) - err := cmd.Run() - return err == nil -} - -func (f *FedoraDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return f.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (f *FedoraDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - packages := map[string]PackageMapping{ - // Standard DNF packages - "git": {Name: "git", Repository: RepoTypeSystem}, - "ghostty": {Name: "ghostty", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}, - "kitty": {Name: "kitty", Repository: RepoTypeSystem}, - "alacritty": {Name: "alacritty", Repository: RepoTypeSystem}, - "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem}, - "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem}, - - // COPR packages - "quickshell": f.getQuickshellMapping(variants["quickshell"]), - "dms-greeter": {Name: "dms-greeter", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}, - "matugen": {Name: "matugen", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}, - "dms (DankMaterialShell)": f.getDmsMapping(variants["dms (DankMaterialShell)"]), - "dgop": {Name: "dgop", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}, - } - - switch wm { - case deps.WindowManagerHyprland: - packages["hyprland"] = f.getHyprlandMapping(variants["hyprland"]) - packages["hyprctl"] = f.getHyprlandMapping(variants["hyprland"]) - packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem} - case deps.WindowManagerNiri: - packages["niri"] = f.getNiriMapping(variants["niri"]) - packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeSystem} - } - - return packages -} - -func (f *FedoraDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping { - if forceQuickshellGit || variant == deps.VariantGit { - return PackageMapping{Name: "quickshell-git", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"} - } - return PackageMapping{Name: "quickshell", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"} -} - -func (f *FedoraDistribution) getDmsMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "dms", Repository: RepoTypeCOPR, RepoURL: "avengemedia/dms-git"} - } - return PackageMapping{Name: "dms", Repository: RepoTypeCOPR, RepoURL: "avengemedia/dms"} -} - -func (f *FedoraDistribution) getHyprlandMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "hyprland", Repository: RepoTypeCOPR, RepoURL: "sdegler/hyprland"} -} - -func (f *FedoraDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "niri", Repository: RepoTypeCOPR, RepoURL: "yalter/niri-git"} - } - return PackageMapping{Name: "niri", Repository: RepoTypeCOPR, RepoURL: "yalter/niri"} -} - -func (f *FedoraDistribution) detectXwaylandSatellite() deps.Dependency { - status := deps.StatusMissing - if f.commandExists("xwayland-satellite") { - status = deps.StatusInstalled - } - - return deps.Dependency{ - Name: "xwayland-satellite", - Status: status, - Description: "Xwayland support", - Required: true, - } -} - -func (f *FedoraDistribution) detectAccountsService() deps.Dependency { - status := deps.StatusMissing - if f.packageInstalled("accountsservice") { - status = deps.StatusInstalled - } - - return deps.Dependency{ - Name: "accountsservice", - Status: status, - Description: "D-Bus interface for user account query and manipulation", - Required: true, - } -} - -func (f *FedoraDistribution) detectDMSGreeter() deps.Dependency { - return f.detectOptionalPackage("dms-greeter", "DankMaterialShell greetd greeter", f.packageInstalled("dms-greeter")) -} - -func (f *FedoraDistribution) getPrerequisites() []string { - return []string{ - "dnf-plugins-core", - "make", - "unzip", - "libwayland-server", - } -} - -func (f *FedoraDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - prerequisites := f.getPrerequisites() - var missingPkgs []string - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Checking prerequisites...", - IsComplete: false, - LogOutput: "Checking prerequisite packages", - } - - for _, pkg := range prerequisites { - checkCmd := exec.CommandContext(ctx, "rpm", "-q", pkg) - if err := checkCmd.Run(); err != nil { - missingPkgs = append(missingPkgs, pkg) - } - } - - _, err := exec.LookPath("go") - if err != nil { - f.log("go not found in PATH, will install golang-bin") - missingPkgs = append(missingPkgs, "golang-bin") - } else { - f.log("go already available in PATH") - } - - if len(missingPkgs) == 0 { - f.log("All prerequisites already installed") - return nil - } - - f.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", "))) - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)), - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo dnf install -y %s", strings.Join(missingPkgs, " ")), - LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")), - } - - args := []string{"dnf", "install", "-y"} - args = append(args, missingPkgs...) - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - output, err := cmd.CombinedOutput() - if err != nil { - f.logError("failed to install prerequisites", err) - f.log(fmt.Sprintf("Prerequisites command output: %s", string(output))) - return fmt.Errorf("failed to install prerequisites: %w", err) - } - f.log(fmt.Sprintf("Prerequisites install output: %s", string(output))) - - return nil -} - -func (f *FedoraDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - // Phase 1: Check Prerequisites - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := f.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - dnfPkgs, coprPkgs, manualPkgs, variantMap := f.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - // Phase 2: Enable COPR repositories - if len(coprPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.15, - Step: "Enabling COPR repositories...", - IsComplete: false, - LogOutput: "Setting up COPR repositories for additional packages", - } - if err := f.enableCOPRRepos(ctx, coprPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to enable COPR repositories: %w", err) - } - } - - // Phase 3: System Packages (DNF) - if len(dnfPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(dnfPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(dnfPkgs, ", ")), - } - if err := f.installDNFPackages(ctx, dnfPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install DNF packages: %w", err) - } - } - - // Phase 4: COPR Packages - coprPkgNames := f.extractPackageNames(coprPkgs) - if len(coprPkgNames) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, // Reusing AUR phase for COPR - Progress: 0.65, - Step: fmt.Sprintf("Installing %d COPR packages...", len(coprPkgNames)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing COPR packages: %s", strings.Join(coprPkgNames, ", ")), - } - if err := f.installCOPRPackages(ctx, coprPkgNames, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install COPR packages: %w", err) - } - } - - // Phase 5: Manual Builds - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := f.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - // Phase 6: Configuration - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := f.DetectTerminalFromDeps(dependencies) - if err := f.WriteEnvironmentConfig(terminal); err != nil { - f.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := f.WriteWindowManagerConfig(wm); err != nil { - f.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := f.EnableDMSService(ctx, wm); err != nil { - f.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - // Phase 7: Complete - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (f *FedoraDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]string, []PackageMapping, []string, map[string]deps.PackageVariant) { - dnfPkgs := []string{} - coprPkgs := []PackageMapping{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := f.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - f.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name)) - continue - } - - switch pkgInfo.Repository { - case RepoTypeSystem: - dnfPkgs = append(dnfPkgs, pkgInfo.Name) - case RepoTypeCOPR: - coprPkgs = append(coprPkgs, pkgInfo) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - return dnfPkgs, coprPkgs, manualPkgs, variantMap -} - -func (f *FedoraDistribution) extractPackageNames(packages []PackageMapping) []string { - names := make([]string, len(packages)) - for i, pkg := range packages { - names[i] = pkg.Name - } - return names -} - -func (f *FedoraDistribution) enableCOPRRepos(ctx context.Context, coprPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - enabledRepos := make(map[string]bool) - - for _, pkg := range coprPkgs { - if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] { - f.log(fmt.Sprintf("Enabling COPR repository: %s", pkg.RepoURL)) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.20, - Step: fmt.Sprintf("Enabling COPR repo %s...", pkg.RepoURL), - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo dnf copr enable -y %s", pkg.RepoURL), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("dnf copr enable -y %s 2>&1", pkg.RepoURL)) - output, err := cmd.CombinedOutput() - if err != nil { - f.logError(fmt.Sprintf("failed to enable COPR repo %s", pkg.RepoURL), err) - f.log(fmt.Sprintf("COPR enable command output: %s", string(output))) - return fmt.Errorf("failed to enable COPR repo %s: %w", pkg.RepoURL, err) - } - f.log(fmt.Sprintf("COPR repo %s enabled successfully: %s", pkg.RepoURL, string(output))) - enabledRepos[pkg.RepoURL] = true - - // Special handling for niri COPR repo - set priority=1 - if pkg.RepoURL == "yalter/niri-git" { - f.log("Setting priority=1 for niri-git COPR repo...") - repoFile := "/etc/yum.repos.d/_copr:copr.fedorainfracloud.org:yalter:niri-git.repo" - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.22, - Step: "Setting niri COPR repo priority...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("echo \"priority=1\" | sudo tee -a %s", repoFile), - } - - priorityCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("bash -c 'echo \"priority=1\" | tee -a %s'", repoFile)) - priorityOutput, err := priorityCmd.CombinedOutput() - if err != nil { - f.logError("failed to set niri COPR repo priority", err) - f.log(fmt.Sprintf("Priority command output: %s", string(priorityOutput))) - return fmt.Errorf("failed to set niri COPR repo priority: %w", err) - } - f.log(fmt.Sprintf("niri COPR repo priority set successfully: %s", string(priorityOutput))) - } - } - } - - return nil -} - -func (f *FedoraDistribution) installDNFPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - f.log(fmt.Sprintf("Installing DNF packages: %s", strings.Join(packages, ", "))) - - return f.installDNFGroups(ctx, packages, sudoPassword, progressChan, PhaseSystemPackages, "Installing system packages...", 0.40, 0.60) -} - -func (f *FedoraDistribution) installCOPRPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - f.log(fmt.Sprintf("Installing COPR packages: %s", strings.Join(packages, ", "))) - - return f.installDNFGroups(ctx, packages, sudoPassword, progressChan, PhaseAURPackages, "Installing COPR packages...", 0.70, 0.85) -} - -func (f *FedoraDistribution) dnfInstallArgs(packages []string, minimal bool) []string { - args := []string{"dnf", "install", "-y"} - if minimal { - args = append(args, "--setopt=install_weak_deps=False") - } - return append(args, packages...) -} - -func (f *FedoraDistribution) installDNFGroups(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg, phase InstallPhase, step string, startProgress float64, endProgress float64) error { - groups := orderedMinimalInstallGroups(packages) - totalGroups := len(groups) - - groupIndex := 0 - installGroup := func(groupPackages []string, minimal bool) error { - if len(groupPackages) == 0 { - return nil - } - - groupIndex++ - groupStart := startProgress - groupEnd := endProgress - if totalGroups > 1 { - midpoint := startProgress + ((endProgress - startProgress) / 2) - if groupIndex == 1 { - groupEnd = midpoint - } else { - groupStart = midpoint - } - } - - args := f.dnfInstallArgs(groupPackages, minimal) - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: groupStart, - Step: step, - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return f.runWithProgress(cmd, progressChan, phase, groupStart, groupEnd) - } - - for _, group := range groups { - if err := installGroup(group.packages, group.minimal); err != nil { - return err - } - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/gentoo.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/gentoo.go deleted file mode 100644 index e0a2a9c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/gentoo.go +++ /dev/null @@ -1,700 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os/exec" - "runtime" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -var GentooGlobalUseFlags = []string{ - "dbus", - "udev", - "alsa", - "policykit", - "jpeg", - "png", - "webp", - "gif", - "tiff", - "svg", - "brotli", - "gdbm", - "accessibility", - "gtk", - "qt6", - "egl", - "gbm", -} - -func init() { - Register("gentoo", "#54487A", FamilyGentoo, func(config DistroConfig, logChan chan<- string) Distribution { - return NewGentooDistribution(config, logChan) - }) -} - -type GentooDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig - skipGlobalUseFlags bool -} - -func NewGentooDistribution(config DistroConfig, logChan chan<- string) *GentooDistribution { - base := NewBaseDistribution(logChan) - return &GentooDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (g *GentooDistribution) getArchKeyword() string { - arch := runtime.GOARCH - switch arch { - case "amd64": - return "~amd64" - case "arm64": - return "~arm64" - default: - return "~amd64" - } -} - -func (g *GentooDistribution) GetID() string { - return g.config.ID -} - -func (g *GentooDistribution) GetColorHex() string { - return g.config.ColorHex -} - -func (g *GentooDistribution) GetFamily() DistroFamily { - return g.config.Family -} - -func (g *GentooDistribution) GetPackageManager() PackageManagerType { - return PackageManagerPortage -} - -func (g *GentooDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return g.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (g *GentooDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - dependencies = append(dependencies, g.detectDMS()) - - dependencies = append(dependencies, g.detectSpecificTerminal(terminal)) - - dependencies = append(dependencies, g.detectGit()) - dependencies = append(dependencies, g.detectWindowManager(wm)) - dependencies = append(dependencies, g.detectQuickshell()) - dependencies = append(dependencies, g.detectXDGPortal()) - dependencies = append(dependencies, g.detectAccountsService()) - - if wm == deps.WindowManagerHyprland { - dependencies = append(dependencies, g.detectHyprlandTools()...) - } - - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, g.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, g.detectMatugen()) - dependencies = append(dependencies, g.detectDgop()) - - return dependencies, nil -} - -func (g *GentooDistribution) detectXDGPortal() deps.Dependency { - return g.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", g.packageInstalled("sys-apps/xdg-desktop-portal-gtk")) -} - -func (g *GentooDistribution) detectXwaylandSatellite() deps.Dependency { - return g.detectPackage("xwayland-satellite", "Xwayland support", g.packageInstalled("gui-apps/xwayland-satellite")) -} - -func (g *GentooDistribution) detectAccountsService() deps.Dependency { - return g.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", g.packageInstalled("sys-apps/accountsservice")) -} - -func (g *GentooDistribution) packageInstalled(pkg string) bool { - cmd := exec.Command("qlist", "-I", pkg) - err := cmd.Run() - return err == nil -} - -func (g *GentooDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return g.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (g *GentooDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - archKeyword := g.getArchKeyword() - packages := map[string]PackageMapping{ - "git": {Name: "dev-vcs/git", Repository: RepoTypeSystem}, - "kitty": {Name: "x11-terms/kitty", Repository: RepoTypeSystem, UseFlags: "X wayland"}, - "alacritty": {Name: "x11-terms/alacritty", Repository: RepoTypeSystem, UseFlags: "X wayland"}, - "xdg-desktop-portal-gtk": {Name: "sys-apps/xdg-desktop-portal-gtk", Repository: RepoTypeSystem, UseFlags: "wayland X"}, - "accountsservice": {Name: "sys-apps/accountsservice", Repository: RepoTypeSystem}, - - "qtbase": {Name: "dev-qt/qtbase", Repository: RepoTypeSystem, UseFlags: "wayland opengl vulkan widgets"}, - "qtdeclarative": {Name: "dev-qt/qtdeclarative", Repository: RepoTypeSystem, UseFlags: "opengl vulkan"}, - "qtwayland": {Name: "dev-qt/qtwayland", Repository: RepoTypeSystem}, - "mesa": {Name: "media-libs/mesa", Repository: RepoTypeSystem, UseFlags: "opengl vulkan"}, - - "quickshell": g.getQuickshellMapping(variants["quickshell"]), - "matugen": {Name: "x11-misc/matugen", Repository: RepoTypeGURU, AcceptKeywords: archKeyword}, - "dms (DankMaterialShell)": g.getDmsMapping(variants["dms (DankMaterialShell)"]), - "dgop": {Name: "dgop", Repository: RepoTypeManual, BuildFunc: "installDgop"}, - } - - switch wm { - case deps.WindowManagerHyprland: - packages["hyprland"] = g.getHyprlandMapping(variants["hyprland"]) - packages["hyprctl"] = g.getHyprlandMapping(variants["hyprland"]) - packages["jq"] = PackageMapping{Name: "app-misc/jq", Repository: RepoTypeSystem} - case deps.WindowManagerNiri: - packages["niri"] = g.getNiriMapping(variants["niri"]) - packages["xwayland-satellite"] = PackageMapping{Name: "gui-apps/xwayland-satellite", Repository: RepoTypeGURU, AcceptKeywords: archKeyword} - } - - return packages -} - -func (g *GentooDistribution) getQuickshellMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "gui-apps/quickshell", Repository: RepoTypeGURU, UseFlags: "breakpad jemalloc sockets wayland layer-shell session-lock toplevel-management screencopy X pipewire tray mpris pam hyprland hyprland-global-shortcuts hyprland-focus-grab i3 i3-ipc bluetooth", AcceptKeywords: "**"} -} - -func (g *GentooDistribution) getDmsMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "dms", Repository: RepoTypeManual, BuildFunc: "installDankMaterialShell"} -} - -func (g *GentooDistribution) getHyprlandMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "gui-wm/hyprland", Repository: RepoTypeSystem, UseFlags: "X", AcceptKeywords: g.getArchKeyword()} -} - -func (g *GentooDistribution) getNiriMapping(_ deps.PackageVariant) PackageMapping { - return PackageMapping{Name: "gui-wm/niri", Repository: RepoTypeGURU, UseFlags: "dbus screencast", AcceptKeywords: g.getArchKeyword()} -} - -func (g *GentooDistribution) getPrerequisites() []string { - return []string{ - "app-eselect/eselect-repository", - "dev-vcs/git", - "dev-build/make", - "app-arch/unzip", - "dev-util/pkgconf", - "dev-qt/qtdeclarative", - } -} - -func (g *GentooDistribution) setGlobalUseFlags(ctx context.Context, sudoPassword string) error { - useFlags := strings.Join(GentooGlobalUseFlags, " ") - - checkCmd := exec.CommandContext(ctx, "grep", "-q", "^USE=", "/etc/portage/make.conf") - hasUse := checkCmd.Run() == nil - - var cmd *exec.Cmd - if hasUse { - cmd = ExecSudoCommand(ctx, sudoPassword, fmt.Sprintf("sed -i 's/^USE=\"\\(.*\\)\"/USE=\"\\1 %s\"/' /etc/portage/make.conf", useFlags)) - } else { - cmd = ExecSudoCommand(ctx, sudoPassword, fmt.Sprintf("bash -c \"echo 'USE=\\\"%s\\\"' >> /etc/portage/make.conf\"", useFlags)) - } - - output, err := cmd.CombinedOutput() - if err != nil { - g.log(fmt.Sprintf("Failed to set global USE flags: %s", string(output))) - return err - } - - g.log(fmt.Sprintf("Set global USE flags: %s", useFlags)) - return nil -} - -func (g *GentooDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - prerequisites := g.getPrerequisites() - var missingPkgs []string - - if !g.skipGlobalUseFlags { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Setting global USE flags...", - IsComplete: false, - LogOutput: "Configuring global USE flags in /etc/portage/make.conf", - } - - if err := g.setGlobalUseFlags(ctx, sudoPassword); err != nil { - g.logError("failed to set global USE flags", err) - return fmt.Errorf("failed to set global USE flags: %w", err) - } - } else { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Skipping global USE flags...", - IsComplete: false, - LogOutput: "Skipping global USE flags configuration (using existing configuration)", - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Checking prerequisites...", - IsComplete: false, - LogOutput: "Checking prerequisite packages", - } - - for _, pkg := range prerequisites { - checkCmd := exec.CommandContext(ctx, "qlist", "-I", pkg) - if err := checkCmd.Run(); err != nil { - missingPkgs = append(missingPkgs, pkg) - } - } - - _, err := exec.LookPath("go") - if err != nil { - g.log("go not found in PATH, will install dev-lang/go") - missingPkgs = append(missingPkgs, "dev-lang/go") - } else { - g.log("go already available in PATH") - } - - if len(missingPkgs) == 0 { - g.log("All prerequisites already installed") - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.07, - Step: "Syncing Portage tree...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo emerge --sync", - LogOutput: "Syncing Portage tree with emerge --sync", - } - - syncCmd := ExecSudoCommand(ctx, sudoPassword, "emerge --sync --quiet") - syncOutput, syncErr := syncCmd.CombinedOutput() - if syncErr != nil { - g.log(fmt.Sprintf("emerge --sync output: %s", string(syncOutput))) - return fmt.Errorf("failed to sync Portage tree: %w\nOutput: %s", syncErr, string(syncOutput)) - } - g.log("Portage tree synced successfully") - - g.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", "))) - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)), - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo emerge --ask=n %s", strings.Join(missingPkgs, " ")), - LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")), - } - - args := []string{"emerge", "--ask=n", "--quiet"} - args = append(args, missingPkgs...) - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - output, err := cmd.CombinedOutput() - if err != nil { - g.logError("failed to install prerequisites", err) - g.log(fmt.Sprintf("Prerequisites command output: %s", string(output))) - return fmt.Errorf("failed to install prerequisites: %w\nOutput: %s", err, string(output)) - } - g.log(fmt.Sprintf("Prerequisites install output: %s", string(output))) - - return nil -} - -func (g *GentooDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - g.skipGlobalUseFlags = skipGlobalUseFlags - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := g.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - systemPkgs, guruPkgs, manualPkgs, variantMap := g.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - g.log(fmt.Sprintf("CATEGORIZED PACKAGES: system=%d, guru=%d, manual=%d", len(systemPkgs), len(guruPkgs), len(manualPkgs))) - - if len(systemPkgs) > 0 { - systemPkgNames := g.extractPackageNames(systemPkgs) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgNames, ", ")), - } - if err := g.installPortagePackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Portage packages: %w", err) - } - } - - if len(guruPkgs) > 0 { - g.log(fmt.Sprintf("FOUND %d GURU PACKAGES - WILL SYNC GURU REPO", len(guruPkgs))) - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.60, - Step: "Syncing GURU repository...", - IsComplete: false, - LogOutput: "Syncing GURU repository to fetch latest ebuilds", - } - g.log("ABOUT TO CALL syncGURURepo") - if err := g.syncGURURepo(ctx, sudoPassword, progressChan); err != nil { - g.log(fmt.Sprintf("syncGURURepo RETURNED ERROR: %v", err)) - return fmt.Errorf("failed to sync GURU repository: %w", err) - } - g.log("syncGURURepo COMPLETED SUCCESSFULLY") - - guruPkgNames := g.extractPackageNames(guruPkgs) - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.65, - Step: fmt.Sprintf("Installing %d GURU packages...", len(guruPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing GURU packages: %s", strings.Join(guruPkgNames, ", ")), - } - if err := g.installGURUPackages(ctx, guruPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install GURU packages: %w", err) - } - } - - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := g.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := g.DetectTerminalFromDeps(dependencies) - if err := g.WriteEnvironmentConfig(terminal); err != nil { - g.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := g.WriteWindowManagerConfig(wm); err != nil { - g.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := g.EnableDMSService(ctx, wm); err != nil { - g.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (g *GentooDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]PackageMapping, []PackageMapping, []string, map[string]deps.PackageVariant) { - systemPkgs := []PackageMapping{} - guruPkgs := []PackageMapping{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := g.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - g.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name)) - continue - } - - switch pkgInfo.Repository { - case RepoTypeSystem: - systemPkgs = append(systemPkgs, pkgInfo) - case RepoTypeGURU: - guruPkgs = append(guruPkgs, pkgInfo) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - return systemPkgs, guruPkgs, manualPkgs, variantMap -} - -func (g *GentooDistribution) extractPackageNames(packages []PackageMapping) []string { - names := make([]string, len(packages)) - for i, pkg := range packages { - names[i] = pkg.Name - } - return names -} - -func (g *GentooDistribution) installPortagePackages(ctx context.Context, packages []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - packageNames := g.extractPackageNames(packages) - g.log(fmt.Sprintf("Installing Portage packages: %s", strings.Join(packageNames, ", "))) - - for _, pkg := range packages { - if pkg.AcceptKeywords != "" { - if err := g.setPackageAcceptKeywords(ctx, pkg.Name, pkg.AcceptKeywords, sudoPassword); err != nil { - return fmt.Errorf("failed to set accept keywords for %s: %w", pkg.Name, err) - } - } - if pkg.UseFlags != "" { - if err := g.setPackageUseFlags(ctx, pkg.Name, pkg.UseFlags, sudoPassword); err != nil { - return fmt.Errorf("failed to set USE flags for %s: %w", pkg.Name, err) - } - } - } - - args := []string{"emerge", "--ask=n", "--quiet"} - args = append(args, packageNames...) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.40, - Step: "Installing system packages...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return g.runWithProgressTimeout(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60, 0) -} - -func (g *GentooDistribution) setPackageUseFlags(ctx context.Context, packageName, useFlags, sudoPassword string) error { - packageUseDir := "/etc/portage/package.use" - - mkdirCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("mkdir -p %s", packageUseDir)) - if output, err := mkdirCmd.CombinedOutput(); err != nil { - g.log(fmt.Sprintf("mkdir output: %s", string(output))) - return fmt.Errorf("failed to create package.use directory: %w", err) - } - - useFlagLine := fmt.Sprintf("%s %s", packageName, useFlags) - - checkExistingCmd := exec.CommandContext(ctx, "bash", "-c", - fmt.Sprintf("grep -q '^%s ' %s/danklinux 2>/dev/null", packageName, packageUseDir)) - if checkExistingCmd.Run() == nil { - g.log(fmt.Sprintf("Updating USE flags for %s from existing entry", packageName)) - escapedPkg := strings.ReplaceAll(packageName, "/", "\\/") - replaceCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("sed -i '/^%s /d' %s/danklinux; exit_code=$?; exit $exit_code", escapedPkg, packageUseDir)) - if output, err := replaceCmd.CombinedOutput(); err != nil { - g.log(fmt.Sprintf("sed delete output: %s", string(output))) - return fmt.Errorf("failed to remove old USE flags: %w", err) - } - } - - appendCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("bash -c \"echo '%s' >> %s/danklinux\"", useFlagLine, packageUseDir)) - - output, err := appendCmd.CombinedOutput() - if err != nil { - g.log(fmt.Sprintf("append output: %s", string(output))) - return fmt.Errorf("failed to write USE flags to package.use: %w", err) - } - - g.log(fmt.Sprintf("Set USE flags for %s: %s", packageName, useFlags)) - return nil -} - -func (g *GentooDistribution) syncGURURepo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.55, - Step: "Enabling GURU repository...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo eselect repository enable guru", - LogOutput: "Enabling GURU repository with eselect", - } - - // Enable GURU repository - enableCmd := ExecSudoCommand(ctx, sudoPassword, - "eselect repository enable guru 2>&1; exit_code=$?; exit $exit_code") - output, err := enableCmd.CombinedOutput() - - g.log(fmt.Sprintf("eselect repository enable guru output:\n%s", string(output))) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.55, - LogOutput: "GURU repository enabled", - } - - if err != nil { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.55, - LogOutput: fmt.Sprintf("ERROR enabling GURU: %v", err), - Error: err, - } - return fmt.Errorf("failed to enable GURU repository: %w\nOutput: %s", err, string(output)) - } - - // Sync GURU repository - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.57, - Step: "Syncing GURU repository...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo emaint sync --repo guru", - LogOutput: "Syncing GURU repository", - } - - syncCmd := ExecSudoCommand(ctx, sudoPassword, - "emaint sync --repo guru 2>&1; exit_code=$?; exit $exit_code") - syncOutput, syncErr := syncCmd.CombinedOutput() - - g.log(fmt.Sprintf("emaint sync --repo guru output:\n%s", string(syncOutput))) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.57, - LogOutput: "GURU repository synced", - } - - if syncErr != nil { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.57, - LogOutput: fmt.Sprintf("ERROR syncing GURU: %v", syncErr), - Error: syncErr, - } - return fmt.Errorf("failed to sync GURU repository: %w\nOutput: %s", syncErr, string(syncOutput)) - } - - return nil -} - -func (g *GentooDistribution) setPackageAcceptKeywords(ctx context.Context, packageName, keywords, sudoPassword string) error { - checkCmd := exec.CommandContext(ctx, "portageq", "match", "/", packageName) - if output, err := checkCmd.CombinedOutput(); err == nil && len(output) > 0 { - g.log(fmt.Sprintf("Package %s is already available (may already be unmasked)", packageName)) - return nil - } - - acceptKeywordsDir := "/etc/portage/package.accept_keywords" - - mkdirCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("mkdir -p %s", acceptKeywordsDir)) - if output, err := mkdirCmd.CombinedOutput(); err != nil { - g.log(fmt.Sprintf("mkdir output: %s", string(output))) - return fmt.Errorf("failed to create package.accept_keywords directory: %w", err) - } - - keywordLine := fmt.Sprintf("%s %s", packageName, keywords) - - checkExistingCmd := exec.CommandContext(ctx, "bash", "-c", - fmt.Sprintf("grep -q '^%s ' %s/danklinux 2>/dev/null", packageName, acceptKeywordsDir)) - if checkExistingCmd.Run() == nil { - g.log(fmt.Sprintf("Updating accept keywords for %s from existing entry", packageName)) - escapedPkg := strings.ReplaceAll(packageName, "/", "\\/") - replaceCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("sed -i '/^%s /d' %s/danklinux; exit_code=$?; exit $exit_code", escapedPkg, acceptKeywordsDir)) - if output, err := replaceCmd.CombinedOutput(); err != nil { - g.log(fmt.Sprintf("sed delete output: %s", string(output))) - return fmt.Errorf("failed to remove old accept keywords: %w", err) - } - } - - appendCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("bash -c \"echo '%s' >> %s/danklinux\"", keywordLine, acceptKeywordsDir)) - - output, err := appendCmd.CombinedOutput() - if err != nil { - g.log(fmt.Sprintf("append output: %s", string(output))) - return fmt.Errorf("failed to write accept keywords: %w", err) - } - - g.log(fmt.Sprintf("Set accept keywords for %s: %s", packageName, keywords)) - return nil -} - -func (g *GentooDistribution) installGURUPackages(ctx context.Context, packages []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - packageNames := g.extractPackageNames(packages) - g.log(fmt.Sprintf("Installing GURU packages: %s", strings.Join(packageNames, ", "))) - - for _, pkg := range packages { - if pkg.AcceptKeywords != "" { - if err := g.setPackageAcceptKeywords(ctx, pkg.Name, pkg.AcceptKeywords, sudoPassword); err != nil { - return fmt.Errorf("failed to set accept keywords for %s: %w", pkg.Name, err) - } - } - if pkg.UseFlags != "" { - if err := g.setPackageUseFlags(ctx, pkg.Name, pkg.UseFlags, sudoPassword); err != nil { - return fmt.Errorf("failed to set USE flags for %s: %w", pkg.Name, err) - } - } - } - - guruPackages := make([]string, len(packageNames)) - for i, pkg := range packageNames { - guruPackages[i] = pkg + "::guru" - } - - args := []string{"emerge", "--ask=n", "--quiet"} - args = append(args, guruPackages...) - - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.70, - Step: "Installing GURU packages...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return g.runWithProgressTimeout(cmd, progressChan, PhaseAURPackages, 0.70, 0.85, 0) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/interface.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/interface.go deleted file mode 100644 index f719f1b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/interface.go +++ /dev/null @@ -1,158 +0,0 @@ -package distros - -import ( - "context" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -// DistroFamily represents a family of related distributions -type DistroFamily string - -const ( - FamilyArch DistroFamily = "arch" - FamilyFedora DistroFamily = "fedora" - FamilySUSE DistroFamily = "suse" - FamilyUbuntu DistroFamily = "ubuntu" - FamilyDebian DistroFamily = "debian" - FamilyNix DistroFamily = "nix" - FamilyGentoo DistroFamily = "gentoo" -) - -// PackageManagerType defines the package manager a distro uses -type PackageManagerType string - -const ( - PackageManagerPacman PackageManagerType = "pacman" - PackageManagerDNF PackageManagerType = "dnf" - PackageManagerAPT PackageManagerType = "apt" - PackageManagerZypper PackageManagerType = "zypper" - PackageManagerNix PackageManagerType = "nix" - PackageManagerPortage PackageManagerType = "portage" -) - -// RepositoryType defines the type of repository for a package -type RepositoryType string - -const ( - RepoTypeSystem RepositoryType = "system" // Standard system repo (pacman, dnf, apt) - RepoTypeAUR RepositoryType = "aur" // Arch User Repository - RepoTypeCOPR RepositoryType = "copr" // Fedora COPR - RepoTypePPA RepositoryType = "ppa" // Ubuntu PPA - RepoTypeOBS RepositoryType = "obs" // OpenBuild Service (Debian/OpenSUSE) - RepoTypeFlake RepositoryType = "flake" // Nix flake - RepoTypeGURU RepositoryType = "guru" // Gentoo GURU - RepoTypeManual RepositoryType = "manual" // Manual build from source -) - -// InstallPhase represents the current phase of installation -type InstallPhase int - -const ( - PhasePrerequisites InstallPhase = iota - PhaseAURHelper - PhaseSystemPackages - PhaseAURPackages - PhaseCursorTheme - PhaseConfiguration - PhaseGreeterSetup - PhaseComplete -) - -// InstallProgressMsg represents progress during package installation -type InstallProgressMsg struct { - Phase InstallPhase - Progress float64 - Step string - IsComplete bool - NeedsSudo bool - CommandInfo string - LogOutput string - Error error -} - -// PackageMapping defines how to install a package on a specific distro -type PackageMapping struct { - Name string // Package name to install - Repository RepositoryType // Repository type - RepoURL string // Repository URL if needed (e.g., COPR repo, PPA) - BuildFunc string // Name of manual build function if RepoTypeManual - UseFlags string // USE flags for Gentoo packages - AcceptKeywords string // Accept keywords for Gentoo packages (e.g., "~amd64") -} - -// Distribution defines a Linux distribution with all its specific configurations -type Distribution interface { - // Metadata - GetID() string - GetColorHex() string - GetFamily() DistroFamily - GetPackageManager() PackageManagerType - - // Dependency Detection - DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) - DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) - - // Package Installation - InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error - - // Package Mapping - GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping - - // Prerequisites - InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error -} - -// DistroConfig holds configuration for a distribution -type DistroConfig struct { - ID string - ColorHex string - Family DistroFamily - Constructor func(config DistroConfig, logChan chan<- string) Distribution -} - -// Registry holds all supported distributions -var Registry = make(map[string]DistroConfig) - -// Register adds a distribution to the registry -func Register(id, colorHex string, family DistroFamily, constructor func(config DistroConfig, logChan chan<- string) Distribution) { - Registry[id] = DistroConfig{ - ID: id, - ColorHex: colorHex, - Family: family, - Constructor: constructor, - } -} - -// GetSupportedDistros returns a list of all supported distribution IDs -func GetSupportedDistros() []string { - ids := make([]string, 0, len(Registry)) - for id := range Registry { - ids = append(ids, id) - } - return ids -} - -// IsDistroSupported checks if a distribution ID is supported -func IsDistroSupported(id string) bool { - _, exists := Registry[id] - return exists -} - -// NewDistribution creates a distribution instance by ID -func NewDistribution(id string, logChan chan<- string) (Distribution, error) { - config, exists := Registry[id] - if !exists { - return nil, &UnsupportedDistributionError{ID: id} - } - return config.Constructor(config, logChan), nil -} - -// UnsupportedDistributionError is returned when a distribution is not supported -type UnsupportedDistributionError struct { - ID string -} - -func (e *UnsupportedDistributionError) Error() string { - return "unsupported distribution: " + e.ID -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages.go deleted file mode 100644 index 2f38161..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages.go +++ /dev/null @@ -1,663 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -// ManualPackageInstaller provides methods for installing packages from source -type ManualPackageInstaller struct { - *BaseDistribution -} - -// parseLatestTagFromGitOutput parses git ls-remote output and returns the latest tag -func (m *ManualPackageInstaller) parseLatestTagFromGitOutput(output string) string { - lines := strings.SplitSeq(output, "\n") - for line := range lines { - if strings.Contains(line, "refs/tags/") && !strings.Contains(line, "^{}") { - parts := strings.Split(line, "refs/tags/") - if len(parts) > 1 { - latestTag := strings.TrimSpace(parts[1]) - return latestTag - } - } - } - return "" -} - -// getLatestQuickshellTag fetches the latest tag from the quickshell repository -func (m *ManualPackageInstaller) getLatestQuickshellTag(ctx context.Context) string { - tagCmd := exec.CommandContext(ctx, "git", "ls-remote", "--tags", "--sort=-v:refname", - "https://github.com/quickshell-mirror/quickshell.git") - tagOutput, err := tagCmd.Output() - if err != nil { - m.log(fmt.Sprintf("Warning: failed to fetch quickshell tags: %v", err)) - return "" - } - - return m.parseLatestTagFromGitOutput(string(tagOutput)) -} - -func (m *ManualPackageInstaller) InstallManualPackages(ctx context.Context, packages []string, variantMap map[string]deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - m.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", "))) - - for _, pkg := range packages { - variant := variantMap[pkg] - switch pkg { - case "dms (DankMaterialShell)", "dms": - if err := m.installDankMaterialShell(ctx, variant, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install DankMaterialShell: %w", err) - } - case "dgop": - if err := m.installDgop(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install dgop: %w", err) - } - case "niri": - if err := m.installNiri(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install niri: %w", err) - } - case "quickshell": - if err := m.installQuickshell(ctx, variant, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install quickshell: %w", err) - } - case "hyprland": - if err := m.installHyprland(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install hyprland: %w", err) - } - case "ghostty": - if err := m.installGhostty(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install ghostty: %w", err) - } - case "matugen": - if err := m.installMatugen(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install matugen: %w", err) - } - case "xwayland-satellite": - if err := m.installXwaylandSatellite(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install xwayland-satellite: %w", err) - } - default: - m.log(fmt.Sprintf("Warning: No manual build method for %s", pkg)) - } - } - - return nil -} - -func (m *ManualPackageInstaller) installDgop(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing dgop from source...") - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return fmt.Errorf("HOME environment variable not set") - } - - cacheDir := filepath.Join(homeDir, ".cache", "dankinstall") - if err := os.MkdirAll(cacheDir, 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - tmpDir := filepath.Join(cacheDir, "dgop-build") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Cloning dgop repository...", - IsComplete: false, - CommandInfo: "git clone https://github.com/AvengeMedia/dgop.git", - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/AvengeMedia/dgop.git", tmpDir) - if err := cloneCmd.Run(); err != nil { - m.logError("failed to clone dgop repository", err) - return fmt.Errorf("failed to clone dgop repository: %w", err) - } - - buildCmd := exec.CommandContext(ctx, "make") - buildCmd.Dir = tmpDir - buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir) - if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.7, "Building dgop..."); err != nil { - return fmt.Errorf("failed to build dgop: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.7, - Step: "Installing dgop...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo make install", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "make install") - installCmd.Dir = tmpDir - if err := installCmd.Run(); err != nil { - m.logError("failed to install dgop", err) - return fmt.Errorf("failed to install dgop: %w", err) - } - - m.log("dgop installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installNiri(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing niri from source...") - - homeDir, _ := os.UserHomeDir() - buildDir := filepath.Join(homeDir, ".cache", "dankinstall", "niri-build") - tmpDir := filepath.Join(homeDir, ".cache", "dankinstall", "tmp") - if err := os.MkdirAll(buildDir, 0o755); err != nil { - return fmt.Errorf("failed to create build directory: %w", err) - } - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer func() { - os.RemoveAll(buildDir) - os.RemoveAll(tmpDir) - }() - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.2, - Step: "Cloning niri repository...", - IsComplete: false, - CommandInfo: "git clone https://github.com/YaLTeR/niri.git", - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/YaLTeR/niri.git", buildDir) - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone niri: %w", err) - } - - checkoutCmd := exec.CommandContext(ctx, "git", "-C", buildDir, "checkout", "v25.08") - if err := checkoutCmd.Run(); err != nil { - m.log(fmt.Sprintf("Warning: failed to checkout v25.08, using main: %v", err)) - } - - if !m.commandExists("cargo-deb") { - cargoDebInstallCmd := exec.CommandContext(ctx, "cargo", "install", "cargo-deb") - cargoDebInstallCmd.Env = append(os.Environ(), "TMPDIR="+tmpDir) - if err := m.runWithProgressStep(cargoDebInstallCmd, progressChan, PhaseSystemPackages, 0.3, 0.35, "Installing cargo-deb..."); err != nil { - return fmt.Errorf("failed to install cargo-deb: %w", err) - } - } - - buildDebCmd := exec.CommandContext(ctx, "cargo", "deb") - buildDebCmd.Dir = buildDir - buildDebCmd.Env = append(os.Environ(), "TMPDIR="+tmpDir) - if err := m.runWithProgressStep(buildDebCmd, progressChan, PhaseSystemPackages, 0.35, 0.95, "Building niri deb package..."); err != nil { - return fmt.Errorf("failed to build niri deb: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.95, - Step: "Installing niri deb package...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "dpkg -i niri.deb", - } - - installDebCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("dpkg -i %s/target/debian/niri_*.deb", buildDir)) - - output, err := installDebCmd.CombinedOutput() - if err != nil { - m.log(fmt.Sprintf("dpkg install failed. Output:\n%s", string(output))) - return fmt.Errorf("failed to install niri deb package: %w\nOutput:\n%s", err, string(output)) - } - - m.log(fmt.Sprintf("dpkg install successful. Output:\n%s", string(output))) - - m.log("niri installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installQuickshell(ctx context.Context, variant deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing quickshell from source...") - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return fmt.Errorf("HOME environment variable not set") - } - - cacheDir := filepath.Join(homeDir, ".cache", "dankinstall") - if err := os.MkdirAll(cacheDir, 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - tmpDir := filepath.Join(cacheDir, "quickshell-build") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Cloning quickshell repository...", - IsComplete: false, - CommandInfo: "git clone https://github.com/quickshell-mirror/quickshell.git", - } - - var cloneCmd *exec.Cmd - if forceQuickshellGit || variant == deps.VariantGit { - cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } else { - latestTag := m.getLatestQuickshellTag(ctx) - if latestTag != "" { - m.log(fmt.Sprintf("Using latest quickshell tag: %s", latestTag)) - cloneCmd = exec.CommandContext(ctx, "git", "clone", "--branch", latestTag, "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } else { - m.log("Warning: failed to fetch latest tag, using default branch") - cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } - } - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone quickshell: %w", err) - } - - buildDir := tmpDir + "/build" - if err := os.MkdirAll(buildDir, 0o755); err != nil { - return fmt.Errorf("failed to create build directory: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.3, - Step: "Configuring quickshell build...", - IsComplete: false, - CommandInfo: "cmake -B build -S . -G Ninja", - } - - configureCmd := exec.CommandContext(ctx, "cmake", "-GNinja", "-B", "build", - "-DCMAKE_BUILD_TYPE=RelWithDebInfo", - "-DCRASH_REPORTER=off", - "-DCMAKE_CXX_STANDARD=20") - configureCmd.Dir = tmpDir - configureCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir) - - output, err := configureCmd.CombinedOutput() - if err != nil { - m.log(fmt.Sprintf("cmake configure failed. Output:\n%s", string(output))) - return fmt.Errorf("failed to configure quickshell: %w\nCMake output:\n%s", err, string(output)) - } - - m.log(fmt.Sprintf("cmake configure successful. Output:\n%s", string(output))) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.4, - Step: "Building quickshell (this may take a while)...", - IsComplete: false, - CommandInfo: "cmake --build build", - } - - buildCmd := exec.CommandContext(ctx, "cmake", "--build", "build") - buildCmd.Dir = tmpDir - buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir) - if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.8, "Building quickshell..."); err != nil { - return fmt.Errorf("failed to build quickshell: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.8, - Step: "Installing quickshell...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo cmake --install build", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "cmake --install build") - installCmd.Dir = tmpDir - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install quickshell: %w", err) - } - - m.log("quickshell installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installHyprland(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing Hyprland from source...") - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return fmt.Errorf("HOME environment variable not set") - } - - cacheDir := filepath.Join(homeDir, ".cache", "dankinstall") - if err := os.MkdirAll(cacheDir, 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - tmpDir := filepath.Join(cacheDir, "hyprland-build") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Cloning Hyprland repository...", - IsComplete: false, - CommandInfo: "git clone --recursive https://github.com/hyprwm/Hyprland.git", - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", "--recursive", "https://github.com/hyprwm/Hyprland.git", tmpDir) - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone Hyprland: %w", err) - } - - checkoutCmd := exec.CommandContext(ctx, "git", "-C", tmpDir, "checkout", "v0.50.1") - if err := checkoutCmd.Run(); err != nil { - m.log(fmt.Sprintf("Warning: failed to checkout v0.50.1, using main: %v", err)) - } - - buildCmd := exec.CommandContext(ctx, "make", "all") - buildCmd.Dir = tmpDir - buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir) - if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.2, 0.8, "Building Hyprland..."); err != nil { - return fmt.Errorf("failed to build Hyprland: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.8, - Step: "Installing Hyprland...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo make install", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "make install") - installCmd.Dir = tmpDir - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install Hyprland: %w", err) - } - - m.log("Hyprland installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installGhostty(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing Ghostty from source...") - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return fmt.Errorf("HOME environment variable not set") - } - - cacheDir := filepath.Join(homeDir, ".cache", "dankinstall") - if err := os.MkdirAll(cacheDir, 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - tmpDir := filepath.Join(cacheDir, "ghostty-build") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Cloning Ghostty repository...", - IsComplete: false, - CommandInfo: "git clone https://github.com/ghostty-org/ghostty.git", - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/ghostty-org/ghostty.git", tmpDir) - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone Ghostty: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.2, - Step: "Building Ghostty (this may take a while)...", - IsComplete: false, - CommandInfo: "zig build -Doptimize=ReleaseFast", - } - - buildCmd := exec.CommandContext(ctx, "zig", "build", "-Doptimize=ReleaseFast") - buildCmd.Dir = tmpDir - buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir) - if err := buildCmd.Run(); err != nil { - return fmt.Errorf("failed to build Ghostty: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.8, - Step: "Installing Ghostty...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo cp zig-out/bin/ghostty /usr/local/bin/", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("cp %s/zig-out/bin/ghostty /usr/local/bin/", tmpDir)) - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install Ghostty: %w", err) - } - - m.log("Ghostty installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installMatugen(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing matugen from source...") - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Installing matugen via cargo...", - IsComplete: false, - CommandInfo: "cargo install matugen", - } - - installCmd := exec.CommandContext(ctx, "cargo", "install", "matugen") - if err := m.runWithProgressStep(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.7, "Building matugen..."); err != nil { - return fmt.Errorf("failed to install matugen: %w", err) - } - - homeDir := os.Getenv("HOME") - sourcePath := filepath.Join(homeDir, ".cargo", "bin", "matugen") - targetPath := "/usr/local/bin/matugen" - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.7, - Step: "Installing matugen binary to system...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo cp %s %s", sourcePath, targetPath), - } - - copyCmd := exec.CommandContext(ctx, "sudo", "-S", "cp", sourcePath, targetPath) - copyCmd.Stdin = strings.NewReader(sudoPassword + "\n") - if err := copyCmd.Run(); err != nil { - return fmt.Errorf("failed to copy matugen to /usr/local/bin: %w", err) - } - - // Make it executable - chmodCmd := exec.CommandContext(ctx, "sudo", "-S", "chmod", "+x", targetPath) - chmodCmd.Stdin = strings.NewReader(sudoPassword + "\n") - if err := chmodCmd.Run(); err != nil { - return fmt.Errorf("failed to make matugen executable: %w", err) - } - - m.log("matugen installed successfully from source") - return nil -} - -func (m *ManualPackageInstaller) installDankMaterialShell(ctx context.Context, variant deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing DankMaterialShell (DMS)...") - - if err := m.installDMSBinary(ctx, sudoPassword, progressChan); err != nil { - m.logError("Failed to install DMS binary", err) - } - - dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms") - - if _, err := os.Stat(dmsPath); os.IsNotExist(err) { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.90, - Step: "Cloning DankMaterialShell...", - IsComplete: false, - CommandInfo: "git clone https://github.com/AvengeMedia/DankMaterialShell.git", - } - - configDir := filepath.Dir(dmsPath) - if err := os.MkdirAll(configDir, 0o755); err != nil { - return fmt.Errorf("failed to create quickshell config directory: %w", err) - } - - cloneCmd := exec.CommandContext(ctx, "git", "clone", - "https://github.com/AvengeMedia/DankMaterialShell.git", dmsPath) - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone DankMaterialShell: %w", err) - } - - if forceDMSGit || variant == deps.VariantGit { - m.log("Using git variant (master branch)") - return nil - } - - tagCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "describe", "--tags", "--abbrev=0", "origin/master") - tagOutput, err := tagCmd.Output() - if err != nil { - m.log("Using default branch (no tags found)") - return nil - } - - latestTag := strings.TrimSpace(string(tagOutput)) - checkoutCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "checkout", latestTag) - if err := checkoutCmd.Run(); err != nil { - m.logError(fmt.Sprintf("Failed to checkout tag %s", latestTag), err) - return nil - } - - m.log(fmt.Sprintf("Checked out latest tag: %s", latestTag)) - m.log("DankMaterialShell cloned successfully") - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.90, - Step: "Updating DankMaterialShell...", - IsComplete: false, - CommandInfo: "Updating ~/.config/quickshell/dms", - } - - fetchCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "fetch", "origin", "--tags", "--force") - if err := fetchCmd.Run(); err != nil { - m.logError("Failed to fetch updates", err) - return nil - } - - if forceDMSGit || variant == deps.VariantGit { - branchCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "rev-parse", "--abbrev-ref", "HEAD") - branchOutput, err := branchCmd.Output() - if err != nil { - m.logError("Failed to get current branch", err) - return nil - } - - branch := strings.TrimSpace(string(branchOutput)) - if branch == "" { - branch = "master" - } - - pullCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "pull", "origin", branch) - if err := pullCmd.Run(); err != nil { - m.logError("Failed to pull updates", err) - return nil - } - - m.log("DankMaterialShell updated successfully (git variant)") - return nil - } - - latestTagCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "describe", "--tags", "--abbrev=0", "origin/master") - tagOutput, err := latestTagCmd.Output() - if err != nil { - m.logError("Failed to get latest tag", err) - return nil - } - - latestTag := strings.TrimSpace(string(tagOutput)) - checkoutCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "checkout", latestTag) - if err := checkoutCmd.Run(); err != nil { - m.logError(fmt.Sprintf("Failed to checkout tag %s", latestTag), err) - return nil - } - - m.log(fmt.Sprintf("Updated to tag: %s", latestTag)) - return nil -} - -func (m *ManualPackageInstaller) installXwaylandSatellite(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - m.log("Installing xwayland-satellite from source...") - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Installing xwayland-satellite via cargo...", - IsComplete: false, - CommandInfo: "cargo install --git https://github.com/Supreeeme/xwayland-satellite --tag v0.7", - } - - installCmd := exec.CommandContext(ctx, "cargo", "install", "--git", "https://github.com/Supreeeme/xwayland-satellite", "--tag", "v0.7") - if err := m.runWithProgressStep(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.7, "Building xwayland-satellite..."); err != nil { - return fmt.Errorf("failed to install xwayland-satellite: %w", err) - } - - homeDir := os.Getenv("HOME") - sourcePath := filepath.Join(homeDir, ".cargo", "bin", "xwayland-satellite") - targetPath := "/usr/local/bin/xwayland-satellite" - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.7, - Step: "Installing xwayland-satellite binary to system...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo cp %s %s", sourcePath, targetPath), - } - - copyCmd := exec.CommandContext(ctx, "sudo", "-S", "cp", sourcePath, targetPath) - copyCmd.Stdin = strings.NewReader(sudoPassword + "\n") - if err := copyCmd.Run(); err != nil { - return fmt.Errorf("failed to copy xwayland-satellite to /usr/local/bin: %w", err) - } - - chmodCmd := exec.CommandContext(ctx, "sudo", "-S", "chmod", "+x", targetPath) - chmodCmd.Stdin = strings.NewReader(sudoPassword + "\n") - if err := chmodCmd.Run(); err != nil { - return fmt.Errorf("failed to make xwayland-satellite executable: %w", err) - } - - m.log("xwayland-satellite installed successfully from source") - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages_test.go deleted file mode 100644 index 4d9fc62..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/manual_packages_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package distros - -import ( - "testing" -) - -func TestManualPackageInstaller_parseLatestTagFromGitOutput(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - { - name: "normal tag output", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1 -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0 -703a3789083d2f990c4e99cd25c97c2a4cccbd81 refs/tags/v0.1.0`, - expected: "v0.2.1", - }, - { - name: "annotated tags with ^{}", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1 -b1b150fab00a93ea983aaca5df55304bc837f51c refs/tags/v0.2.1^{} -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`, - expected: "v0.2.1", - }, - { - name: "mixed tags", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.3.0 -b1b150fab00a93ea983aaca5df55304bc837f51c refs/tags/v0.3.0^{} -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0 -c1c150fab00a93ea983aaca5df55304bc837f51d refs/tags/beta-1`, - expected: "v0.3.0", - }, - { - name: "empty output", - input: "", - expected: "", - }, - { - name: "no tags", - input: "some other output\nwithout tags", - expected: "", - }, - { - name: "only annotated tags", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1^{} -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0^{}`, - expected: "", - }, - { - name: "single tag", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v1.0.0`, - expected: "v1.0.0", - }, - { - name: "tag with extra whitespace", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1 -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`, - expected: "v0.2.1", - }, - { - name: "beta and rc tags", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.3.0-beta.1 -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`, - expected: "v0.3.0-beta.1", - }, - { - name: "tags without v prefix", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/0.2.1 -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/0.2.0`, - expected: "0.2.1", - }, - { - name: "multiple lines with spaces", - input: ` -a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v1.2.3 -a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v1.2.2 -`, - expected: "v1.2.3", - }, - { - name: "tag at end of line", - input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1`, - expected: "v0.2.1", - }, - } - - logChan := make(chan string, 100) - defer close(logChan) - - base := NewBaseDistribution(logChan) - installer := &ManualPackageInstaller{BaseDistribution: base} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := installer.parseLatestTagFromGitOutput(tt.input) - - if result != tt.expected { - t.Errorf("parseLatestTagFromGitOutput() = %q, expected %q", result, tt.expected) - } - }) - } -} - -func TestManualPackageInstaller_parseLatestTagFromGitOutput_EmptyInstaller(t *testing.T) { - // Test that parsing works even with a minimal installer setup - logChan := make(chan string, 10) - defer close(logChan) - - base := NewBaseDistribution(logChan) - installer := &ManualPackageInstaller{BaseDistribution: base} - - input := `abc123 refs/tags/v1.0.0 -def456 refs/tags/v0.9.0` - - result := installer.parseLatestTagFromGitOutput(input) - - if result != "v1.0.0" { - t.Errorf("Expected v1.0.0, got %s", result) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/minimal_install.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/minimal_install.go deleted file mode 100644 index 029f1ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/minimal_install.go +++ /dev/null @@ -1,44 +0,0 @@ -package distros - -type minimalInstallGroup struct { - packages []string - minimal bool -} - -func shouldPreferMinimalInstall(pkg string) bool { - switch pkg { - case "niri", "niri-git": - return true - default: - return false - } -} - -func splitMinimalInstallPackages(packages []string) (normal []string, minimal []string) { - for _, pkg := range packages { - if shouldPreferMinimalInstall(pkg) { - minimal = append(minimal, pkg) - continue - } - normal = append(normal, pkg) - } - return normal, minimal -} - -func orderedMinimalInstallGroups(packages []string) []minimalInstallGroup { - normal, minimal := splitMinimalInstallPackages(packages) - groups := make([]minimalInstallGroup, 0, 2) - if len(minimal) > 0 { - groups = append(groups, minimalInstallGroup{ - packages: minimal, - minimal: true, - }) - } - if len(normal) > 0 { - groups = append(groups, minimalInstallGroup{ - packages: normal, - minimal: false, - }) - } - return groups -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/opensuse.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/opensuse.go deleted file mode 100644 index 62f40cd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/opensuse.go +++ /dev/null @@ -1,856 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "slices" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func init() { - Register("opensuse-tumbleweed", "#73BA25", FamilySUSE, func(config DistroConfig, logChan chan<- string) Distribution { - return NewOpenSUSEDistribution(config, logChan) - }) - Register("opensuse-leap", "#73BA25", FamilySUSE, func(config DistroConfig, logChan chan<- string) Distribution { - return NewOpenSUSEDistribution(config, logChan) - }) - Register("opensuse-slowroll", "#73BA25", FamilySUSE, func(config DistroConfig, logChan chan<- string) Distribution { - return NewOpenSUSEDistribution(config, logChan) - }) -} - -type OpenSUSEDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig -} - -const openSUSENiriWaylandServerPackage = "libwayland-server0" - -func NewOpenSUSEDistribution(config DistroConfig, logChan chan<- string) *OpenSUSEDistribution { - base := NewBaseDistribution(logChan) - return &OpenSUSEDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (o *OpenSUSEDistribution) GetID() string { - return o.config.ID -} - -func (o *OpenSUSEDistribution) GetColorHex() string { - return o.config.ColorHex -} - -func (o *OpenSUSEDistribution) GetFamily() DistroFamily { - return o.config.Family -} - -func (o *OpenSUSEDistribution) GetPackageManager() PackageManagerType { - return PackageManagerZypper -} - -func (o *OpenSUSEDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return o.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - // DMS at the top (shell is prominent) - dependencies = append(dependencies, o.detectDMS()) - - // Terminal with choice support - dependencies = append(dependencies, o.detectSpecificTerminal(terminal)) - - // Common detections using base methods - dependencies = append(dependencies, o.detectGit()) - dependencies = append(dependencies, o.detectWindowManager(wm)) - dependencies = append(dependencies, o.detectQuickshell()) - dependencies = append(dependencies, o.detectDMSGreeter()) - dependencies = append(dependencies, o.detectXDGPortal()) - dependencies = append(dependencies, o.detectAccountsService()) - - // Hyprland-specific tools - if wm == deps.WindowManagerHyprland { - dependencies = append(dependencies, o.detectHyprlandTools()...) - } - - // Niri-specific tools - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, o.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, o.detectMatugen()) - dependencies = append(dependencies, o.detectDgop()) - - return dependencies, nil -} - -func (o *OpenSUSEDistribution) detectXDGPortal() deps.Dependency { - return o.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", o.packageInstalled("xdg-desktop-portal-gtk")) -} - -func (o *OpenSUSEDistribution) packageInstalled(pkg string) bool { - cmd := exec.Command("rpm", "-q", pkg) - err := cmd.Run() - return err == nil -} - -func (o *OpenSUSEDistribution) detectDMSGreeter() deps.Dependency { - return o.detectOptionalPackage("dms-greeter", "DankMaterialShell greetd greeter", o.packageInstalled("dms-greeter")) -} - -func (o *OpenSUSEDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return o.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - packages := map[string]PackageMapping{ - // Standard zypper packages - "git": {Name: "git", Repository: RepoTypeSystem}, - "kitty": {Name: "kitty", Repository: RepoTypeSystem}, - "alacritty": {Name: "alacritty", Repository: RepoTypeSystem}, - "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem}, - "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem}, - - // DMS packages from OBS - "dms (DankMaterialShell)": o.getDmsMapping(variants["dms (DankMaterialShell)"]), - "quickshell": o.getQuickshellMapping(variants["quickshell"]), - "dms-greeter": {Name: "dms-greeter", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - "dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"}, - } - - switch wm { - case deps.WindowManagerHyprland: - packages["hyprland"] = PackageMapping{Name: "hyprland", Repository: RepoTypeSystem} - packages["hyprctl"] = PackageMapping{Name: "hyprland", Repository: RepoTypeSystem} - packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem} - case deps.WindowManagerNiri: - // Niri stable has native package support on openSUSE - niriVariant := variants["niri"] - packages["niri"] = o.getNiriMapping(niriVariant) - packages["xwayland-satellite"] = o.getXwaylandSatelliteMapping(niriVariant) - } - - return packages -} - -func (o *OpenSUSEDistribution) getDmsMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "dms-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:dms-git"} - } - return PackageMapping{Name: "dms", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:dms"} -} - -func (o *OpenSUSEDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping { - if forceQuickshellGit || variant == deps.VariantGit { - return PackageMapping{Name: "quickshell-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "quickshell", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} -} - -func (o *OpenSUSEDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "niri-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "niri", Repository: RepoTypeSystem} -} - -func (o *OpenSUSEDistribution) getXwaylandSatelliteMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "xwayland-satellite-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"} - } - return PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeSystem} -} - -func (o *OpenSUSEDistribution) detectXwaylandSatellite() deps.Dependency { - status := deps.StatusMissing - if o.commandExists("xwayland-satellite") { - status = deps.StatusInstalled - } - - return deps.Dependency{ - Name: "xwayland-satellite", - Status: status, - Description: "Xwayland support", - Required: true, - } -} - -func (o *OpenSUSEDistribution) detectAccountsService() deps.Dependency { - status := deps.StatusMissing - if o.packageInstalled("accountsservice") { - status = deps.StatusInstalled - } - - return deps.Dependency{ - Name: "accountsservice", - Status: status, - Description: "D-Bus interface for user account query and manipulation", - Required: true, - } -} - -func (o *OpenSUSEDistribution) getPrerequisites() []string { - return []string{} -} - -func (o *OpenSUSEDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - prerequisites := o.getPrerequisites() - var missingPkgs []string - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Checking prerequisites...", - IsComplete: false, - LogOutput: "Checking prerequisite packages", - } - - for _, pkg := range prerequisites { - checkCmd := exec.CommandContext(ctx, "rpm", "-q", pkg) - if err := checkCmd.Run(); err != nil { - missingPkgs = append(missingPkgs, pkg) - } - } - - _, err := exec.LookPath("go") - if err != nil { - o.log("go not found in PATH, will install go") - missingPkgs = append(missingPkgs, "go") - } else { - o.log("go already available in PATH") - } - - if len(missingPkgs) == 0 { - o.log("All prerequisites already installed") - return nil - } - - o.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", "))) - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)), - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo zypper install -y %s", strings.Join(missingPkgs, " ")), - LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")), - } - - args := []string{"zypper", "install", "-y"} - args = append(args, missingPkgs...) - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - output, err := cmd.CombinedOutput() - if err != nil { - o.logError("failed to install prerequisites", err) - o.log(fmt.Sprintf("Prerequisites command output: %s", string(output))) - return fmt.Errorf("failed to install prerequisites: %w", err) - } - o.log(fmt.Sprintf("Prerequisites install output: %s", string(output))) - - return nil -} - -func (o *OpenSUSEDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - // Phase 1: Check Prerequisites - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := o.disableInstallMediaRepos(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to disable install media repositories: %w", err) - } - - if err := o.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - systemPkgs, obsPkgs, manualPkgs, variantMap := o.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - // Enable OBS repositories - if len(obsPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.15, - Step: "Enabling OBS repositories...", - IsComplete: false, - LogOutput: "Setting up OBS repositories for additional packages", - } - if err := o.enableOBSRepos(ctx, obsPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to enable OBS repositories: %w", err) - } - } - - // Phase 3: System Packages (Zypper) - if len(systemPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")), - } - if err := o.installZypperPackages(ctx, systemPkgs, sudoPassword, progressChan, PhaseSystemPackages, "Installing system packages...", 0.40, 0.60); err != nil { - return fmt.Errorf("failed to install zypper packages: %w", err) - } - } - - // OBS Packages - obsPkgNames := o.extractPackageNames(obsPkgs) - if len(obsPkgNames) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, - Progress: 0.65, - Step: fmt.Sprintf("Installing %d OBS packages...", len(obsPkgNames)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing OBS packages: %s", strings.Join(obsPkgNames, ", ")), - } - if err := o.installZypperPackages(ctx, obsPkgNames, sudoPassword, progressChan, PhaseAURPackages, "Installing OBS packages...", 0.70, 0.85); err != nil { - return fmt.Errorf("failed to install OBS packages: %w", err) - } - } - - // Manual Builds - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := o.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - // Configuration - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := o.DetectTerminalFromDeps(dependencies) - if err := o.WriteEnvironmentConfig(terminal); err != nil { - o.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := o.WriteWindowManagerConfig(wm); err != nil { - o.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := o.EnableDMSService(ctx, wm); err != nil { - o.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - // Complete - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (o *OpenSUSEDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]string, []PackageMapping, []string, map[string]deps.PackageVariant) { - systemPkgs := []string{} - obsPkgs := []PackageMapping{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := o.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - o.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name)) - continue - } - - switch pkgInfo.Repository { - case RepoTypeSystem: - systemPkgs = append(systemPkgs, pkgInfo.Name) - case RepoTypeOBS: - obsPkgs = append(obsPkgs, pkgInfo) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - systemPkgs = o.appendMissingSystemPackages(systemPkgs, openSUSENiriRuntimePackages(wm, disabledFlags)) - - return systemPkgs, obsPkgs, manualPkgs, variantMap -} - -func openSUSENiriRuntimePackages(wm deps.WindowManager, disabledFlags map[string]bool) []string { - if wm != deps.WindowManagerNiri || disabledFlags["niri"] { - return nil - } - - return []string{openSUSENiriWaylandServerPackage} -} - -func (o *OpenSUSEDistribution) appendMissingSystemPackages(systemPkgs []string, extraPkgs []string) []string { - for _, pkg := range extraPkgs { - if slices.Contains(systemPkgs, pkg) || o.packageInstalled(pkg) { - continue - } - - o.log(fmt.Sprintf("Adding openSUSE runtime package: %s", pkg)) - systemPkgs = append(systemPkgs, pkg) - } - - return systemPkgs -} - -func (o *OpenSUSEDistribution) extractPackageNames(packages []PackageMapping) []string { - names := make([]string, len(packages)) - for i, pkg := range packages { - names[i] = pkg.Name - } - return names -} - -func (o *OpenSUSEDistribution) enableOBSRepos(ctx context.Context, obsPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - enabledRepos := make(map[string]bool) - - osInfo, err := GetOSInfo() - if err != nil { - return fmt.Errorf("failed to get OS info: %w", err) - } - - obsDistroVersion := "openSUSE_Tumbleweed" - switch osInfo.Distribution.ID { - case "opensuse-leap": - obsDistroVersion = fmt.Sprintf("openSUSE_Leap_%s", osInfo.VersionID) - case "opensuse-slowroll": - obsDistroVersion = "openSUSE_Slowroll" - } - - for _, pkg := range obsPkgs { - if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] { - o.log(fmt.Sprintf("Enabling OBS repository: %s", pkg.RepoURL)) - - // RepoURL format: "home:AvengeMedia:danklinux" - repoPath := strings.ReplaceAll(pkg.RepoURL, ":", ":/") - repoName := strings.ReplaceAll(pkg.RepoURL, ":", "-") - repoURL := fmt.Sprintf("https://download.opensuse.org/repositories/%s/%s/%s.repo", - repoPath, obsDistroVersion, pkg.RepoURL) - - checkCmd := exec.CommandContext(ctx, "zypper", "repos", repoName) - if checkCmd.Run() == nil { - o.log(fmt.Sprintf("OBS repo %s already exists, skipping", pkg.RepoURL)) - enabledRepos[pkg.RepoURL] = true - continue - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.20, - Step: fmt.Sprintf("Enabling OBS repo %s...", pkg.RepoURL), - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo zypper addrepo %s", repoURL), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("zypper addrepo -f %s", repoURL)) - if err := o.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil { - o.log(fmt.Sprintf("OBS repo %s add failed (may already exist): %v", pkg.RepoURL, err)) - } - - enabledRepos[pkg.RepoURL] = true - o.log(fmt.Sprintf("OBS repo %s enabled successfully", pkg.RepoURL)) - } - } - - // Refresh repositories with GPG auto-import - if len(enabledRepos) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.25, - Step: "Refreshing repositories...", - NeedsSudo: true, - CommandInfo: "sudo zypper --gpg-auto-import-keys refresh", - } - - refreshCmd := ExecSudoCommand(ctx, sudoPassword, "zypper --gpg-auto-import-keys refresh") - if err := o.runWithProgress(refreshCmd, progressChan, PhaseSystemPackages, 0.25, 0.27); err != nil { - return fmt.Errorf("failed to refresh repositories: %w", err) - } - } - - return nil -} - -func isOpenSUSEInstallMediaURI(uri string) bool { - normalizedURI := strings.ToLower(strings.TrimSpace(uri)) - - return strings.HasPrefix(normalizedURI, "cd:/") || - strings.HasPrefix(normalizedURI, "dvd:/") || - strings.HasPrefix(normalizedURI, "hd:/") || - strings.HasPrefix(normalizedURI, "iso:/") -} - -func parseZypperInstallMediaAliases(output string) []string { - var aliases []string - - for _, line := range strings.Split(output, "\n") { - line = strings.TrimSpace(line) - if line == "" || !strings.Contains(line, "|") { - continue - } - - parts := strings.Split(line, "|") - if len(parts) < 7 { - continue - } - - for i := range parts { - parts[i] = strings.TrimSpace(parts[i]) - } - - alias := parts[1] - enabled := strings.ToLower(parts[3]) - uri := parts[len(parts)-1] - - if alias == "" || strings.EqualFold(alias, "alias") { - continue - } - if enabled != "" && enabled != "yes" { - continue - } - if !isOpenSUSEInstallMediaURI(uri) { - continue - } - - aliases = append(aliases, alias) - } - - return aliases -} - -func (o *OpenSUSEDistribution) disableInstallMediaRepos(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - listCmd := exec.CommandContext(ctx, "zypper", "repos", "-u") - output, err := listCmd.CombinedOutput() - if err != nil { - o.log(fmt.Sprintf("Warning: failed to list zypper repositories: %s", strings.TrimSpace(string(output)))) - return fmt.Errorf("failed to list zypper repositories: %w", err) - } - - aliases := parseZypperInstallMediaAliases(string(output)) - if len(aliases) == 0 { - return nil - } - - o.log(fmt.Sprintf("Disabling install media repositories: %s", strings.Join(aliases, ", "))) - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.055, - Step: "Disabling install media repositories...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo zypper modifyrepo -d %s", strings.Join(aliases, " ")), - LogOutput: fmt.Sprintf("Disabling install media repositories: %s", strings.Join(aliases, ", ")), - } - - for _, alias := range aliases { - cmd := ExecSudoCommand(ctx, sudoPassword, fmt.Sprintf("zypper modifyrepo -d '%s'", escapeSingleQuotes(alias))) - repoOutput, err := cmd.CombinedOutput() - if err != nil { - o.log(fmt.Sprintf("Failed to disable install media repo %s: %s", alias, strings.TrimSpace(string(repoOutput)))) - return fmt.Errorf("failed to disable install media repo %s: %w", alias, err) - } - o.log(fmt.Sprintf("Disabled install media repo %s: %s", alias, strings.TrimSpace(string(repoOutput)))) - } - - return nil -} - -func (o *OpenSUSEDistribution) zypperInstallArgs(packages []string, minimal bool) []string { - args := []string{"zypper", "install", "-y"} - if minimal { - args = append(args, "--no-recommends") - } - return append(args, packages...) -} - -func (o *OpenSUSEDistribution) installZypperPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg, phase InstallPhase, step string, startProgress float64, endProgress float64) error { - if len(packages) == 0 { - return nil - } - - o.log(fmt.Sprintf("Installing zypper packages: %s", strings.Join(packages, ", "))) - - groups := orderedMinimalInstallGroups(packages) - totalGroups := len(groups) - - groupIndex := 0 - installGroup := func(groupPackages []string, minimal bool) error { - if len(groupPackages) == 0 { - return nil - } - - groupIndex++ - groupStart := startProgress - groupEnd := endProgress - if totalGroups > 1 { - midpoint := startProgress + ((endProgress - startProgress) / 2) - if groupIndex == 1 { - groupEnd = midpoint - } else { - groupStart = midpoint - } - } - - args := o.zypperInstallArgs(groupPackages, minimal) - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: groupStart, - Step: step, - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return o.runWithProgress(cmd, progressChan, phase, groupStart, groupEnd) - } - - for _, group := range groups { - if err := installGroup(group.packages, group.minimal); err != nil { - return err - } - } - return nil -} - -func (o *OpenSUSEDistribution) installQuickshell(ctx context.Context, variant deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - o.log("Installing quickshell from source (with openSUSE-specific build flags)...") - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return fmt.Errorf("HOME environment variable not set") - } - - cacheDir := filepath.Join(homeDir, ".cache", "dankinstall") - if err := os.MkdirAll(cacheDir, 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - tmpDir := filepath.Join(cacheDir, "quickshell-build") - if err := os.MkdirAll(tmpDir, 0o755); err != nil { - return fmt.Errorf("failed to create temp directory: %w", err) - } - defer os.RemoveAll(tmpDir) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.1, - Step: "Cloning quickshell repository...", - IsComplete: false, - CommandInfo: "git clone https://github.com/quickshell-mirror/quickshell.git", - } - - var cloneCmd *exec.Cmd - if forceQuickshellGit || variant == deps.VariantGit { - cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } else { - latestTag := o.getLatestQuickshellTag(ctx) - if latestTag != "" { - o.log(fmt.Sprintf("Using latest quickshell tag: %s", latestTag)) - cloneCmd = exec.CommandContext(ctx, "git", "clone", "--branch", latestTag, "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } else { - o.log("Warning: failed to fetch latest tag, using default branch") - cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir) - } - } - if err := cloneCmd.Run(); err != nil { - return fmt.Errorf("failed to clone quickshell: %w", err) - } - - buildDir := tmpDir + "/build" - if err := os.MkdirAll(buildDir, 0o755); err != nil { - return fmt.Errorf("failed to create build directory: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.3, - Step: "Configuring quickshell build (with openSUSE flags)...", - IsComplete: false, - CommandInfo: "cmake -B build -S . -G Ninja", - } - - // Get optflags from rpm - optflagsCmd := exec.CommandContext(ctx, "rpm", "--eval", "%{optflags}") - optflagsOutput, err := optflagsCmd.Output() - optflags := strings.TrimSpace(string(optflagsOutput)) - if err != nil || optflags == "" { - o.log("Warning: Could not get optflags from rpm, using default -O2 -g") - optflags = "-O2 -g" - } - - // Set openSUSE-specific CFLAGS - customCFLAGS := fmt.Sprintf("%s -I/usr/include/wayland", optflags) - - configureCmd := exec.CommandContext(ctx, "cmake", "-GNinja", "-B", "build", - "-DCMAKE_BUILD_TYPE=RelWithDebInfo", - "-DCRASH_REPORTER=off", - "-DCMAKE_CXX_STANDARD=20") - configureCmd.Dir = tmpDir - configureCmd.Env = append(os.Environ(), - "TMPDIR="+cacheDir, - "CFLAGS="+customCFLAGS, - "CXXFLAGS="+customCFLAGS) - - o.log(fmt.Sprintf("Using CFLAGS: %s", customCFLAGS)) - - output, err := configureCmd.CombinedOutput() - if err != nil { - o.log(fmt.Sprintf("cmake configure failed. Output:\n%s", string(output))) - return fmt.Errorf("failed to configure quickshell: %w\nCMake output:\n%s", err, string(output)) - } - - o.log(fmt.Sprintf("cmake configure successful. Output:\n%s", string(output))) - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.4, - Step: "Building quickshell (this may take a while)...", - IsComplete: false, - CommandInfo: "cmake --build build", - } - - buildCmd := exec.CommandContext(ctx, "cmake", "--build", "build") - buildCmd.Dir = tmpDir - buildCmd.Env = append(os.Environ(), - "TMPDIR="+cacheDir, - "CFLAGS="+customCFLAGS, - "CXXFLAGS="+customCFLAGS) - if err := o.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.8, "Building quickshell..."); err != nil { - return fmt.Errorf("failed to build quickshell: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.8, - Step: "Installing quickshell...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo cmake --install build", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "cmake --install build") - installCmd.Dir = tmpDir - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install quickshell: %w", err) - } - - o.log("quickshell installed successfully from source") - return nil -} - -func (o *OpenSUSEDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if o.commandExists("cargo") { - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.82, - Step: "Installing rustup...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo zypper install rustup", - } - - rustupInstallCmd := ExecSudoCommand(ctx, sudoPassword, "zypper install -y rustup") - if err := o.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil { - return fmt.Errorf("failed to install rustup: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.83, - Step: "Installing stable Rust toolchain...", - IsComplete: false, - CommandInfo: "rustup install stable", - } - - rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable") - if err := o.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil { - return fmt.Errorf("failed to install Rust toolchain: %w", err) - } - - if !o.commandExists("cargo") { - o.log("Warning: cargo not found in PATH after Rust installation, trying to source environment") - } - - return nil -} - -func (o *OpenSUSEDistribution) InstallManualPackages(ctx context.Context, packages []string, variantMap map[string]deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - o.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", "))) - - for _, pkg := range packages { - if pkg == "matugen" { - if err := o.installRust(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Rust: %w", err) - } - break - } - } - - for _, pkg := range packages { - variant := variantMap[pkg] - if pkg == "quickshell" { - if err := o.installQuickshell(ctx, variant, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install quickshell: %w", err) - } - } else { - if err := o.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install %s: %w", pkg, err) - } - } - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/osinfo.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/osinfo.go deleted file mode 100644 index 8fc4b25..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/osinfo.go +++ /dev/null @@ -1,122 +0,0 @@ -package distros - -import ( - "bufio" - "fmt" - "os" - "runtime" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" -) - -// DistroInfo contains basic information about a distribution -type DistroInfo struct { - ID string - HexColorCode string -} - -// OSInfo contains complete OS information -type OSInfo struct { - Distribution DistroInfo - Version string - VersionID string - VersionCodename string - PrettyName string - Architecture string -} - -// GetOSInfo detects the current OS and returns information about it -func GetOSInfo() (*OSInfo, error) { - if runtime.GOOS != "linux" { - return nil, errdefs.NewCustomError(errdefs.ErrTypeNotLinux, fmt.Sprintf("Only linux is supported, but I found %s", runtime.GOOS)) - } - - if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" { - return nil, errdefs.NewCustomError(errdefs.ErrTypeInvalidArchitecture, fmt.Sprintf("Only amd64 and arm64 are supported, but I found %s", runtime.GOARCH)) - } - - info := &OSInfo{ - Architecture: runtime.GOARCH, - } - - file, err := os.Open("/etc/os-release") - if err != nil { - return nil, err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - parts := strings.SplitN(line, "=", 2) - if len(parts) != 2 { - continue - } - - key := parts[0] - value := strings.Trim(parts[1], "\"") - - switch key { - case "ID": - config, exists := Registry[value] - if !exists { - return nil, errdefs.NewCustomError(errdefs.ErrTypeUnsupportedDistribution, fmt.Sprintf("Unsupported distribution: %s", value)) - } - - info.Distribution = DistroInfo{ - ID: value, // Use the actual ID from os-release - HexColorCode: config.ColorHex, - } - case "VERSION_ID", "BUILD_ID": - info.VersionID = value - case "VERSION": - info.Version = value - case "VERSION_CODENAME": - info.VersionCodename = value - case "PRETTY_NAME": - info.PrettyName = value - } - } - - return info, scanner.Err() -} - -// IsUnsupportedDistro checks if a distribution/version combination is supported -func IsUnsupportedDistro(distroID, versionID string) bool { - if !IsDistroSupported(distroID) { - return true - } - - if distroID == "ubuntu" { - parts := strings.Split(versionID, ".") - if len(parts) >= 2 { - major, err1 := strconv.Atoi(parts[0]) - minor, err2 := strconv.Atoi(parts[1]) - - if err1 == nil && err2 == nil { - return major < 25 || (major == 25 && minor < 4) - } - } - return true - } - - if distroID == "debian" { - // unstable/sid support - if versionID == "sid" { - return false - } - if versionID == "" { - // debian testing/sid have no version ID - return false - } - versionNum, err := strconv.Atoi(versionID) - if err == nil { - return versionNum < 12 - } - return true - } - - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/ubuntu.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/ubuntu.go deleted file mode 100644 index 37911f0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/distros/ubuntu.go +++ /dev/null @@ -1,702 +0,0 @@ -package distros - -import ( - "context" - "fmt" - "os/exec" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func init() { - Register("ubuntu", "#E95420", FamilyUbuntu, func(config DistroConfig, logChan chan<- string) Distribution { - return NewUbuntuDistribution(config, logChan) - }) -} - -type UbuntuDistribution struct { - *BaseDistribution - *ManualPackageInstaller - config DistroConfig -} - -func NewUbuntuDistribution(config DistroConfig, logChan chan<- string) *UbuntuDistribution { - base := NewBaseDistribution(logChan) - return &UbuntuDistribution{ - BaseDistribution: base, - ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base}, - config: config, - } -} - -func (u *UbuntuDistribution) GetID() string { - return u.config.ID -} - -func (u *UbuntuDistribution) GetColorHex() string { - return u.config.ColorHex -} - -func (u *UbuntuDistribution) GetFamily() DistroFamily { - return u.config.Family -} - -func (u *UbuntuDistribution) GetPackageManager() PackageManagerType { - return PackageManagerAPT -} - -func (u *UbuntuDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) { - return u.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty) -} - -func (u *UbuntuDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) { - var dependencies []deps.Dependency - - // DMS at the top (shell is prominent) - dependencies = append(dependencies, u.detectDMS()) - - // Terminal with choice support - dependencies = append(dependencies, u.detectSpecificTerminal(terminal)) - - // Common detections using base methods - dependencies = append(dependencies, u.detectGit()) - dependencies = append(dependencies, u.detectWindowManager(wm)) - dependencies = append(dependencies, u.detectQuickshell()) - dependencies = append(dependencies, u.detectDMSGreeter()) - dependencies = append(dependencies, u.detectXDGPortal()) - dependencies = append(dependencies, u.detectAccountsService()) - - // Hyprland-specific tools - if wm == deps.WindowManagerHyprland { - dependencies = append(dependencies, u.detectHyprlandTools()...) - } - - // Niri-specific tools - if wm == deps.WindowManagerNiri { - dependencies = append(dependencies, u.detectXwaylandSatellite()) - } - - dependencies = append(dependencies, u.detectMatugen()) - dependencies = append(dependencies, u.detectDgop()) - - return dependencies, nil -} - -func (u *UbuntuDistribution) detectXDGPortal() deps.Dependency { - return u.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", u.packageInstalled("xdg-desktop-portal-gtk")) -} - -func (u *UbuntuDistribution) detectXwaylandSatellite() deps.Dependency { - return u.detectCommand("xwayland-satellite", "Xwayland support") -} - -func (u *UbuntuDistribution) detectAccountsService() deps.Dependency { - return u.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", u.packageInstalled("accountsservice")) -} - -func (u *UbuntuDistribution) detectDMSGreeter() deps.Dependency { - return u.detectOptionalPackage("dms-greeter", "DankMaterialShell greetd greeter", u.packageInstalled("dms-greeter")) -} - -func (u *UbuntuDistribution) packageInstalled(pkg string) bool { - return debianPackageInstalledPrecisely(pkg) -} - -func (u *UbuntuDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { - return u.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) -} - -func (u *UbuntuDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping { - packages := map[string]PackageMapping{ - // Standard APT packages - "git": {Name: "git", Repository: RepoTypeSystem}, - "kitty": {Name: "kitty", Repository: RepoTypeSystem}, - "alacritty": {Name: "alacritty", Repository: RepoTypeSystem}, - "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem}, - "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem}, - - // DMS packages from PPAs - "dms (DankMaterialShell)": u.getDmsMapping(variants["dms (DankMaterialShell)"]), - "quickshell": u.getQuickshellMapping(variants["quickshell"]), - "dms-greeter": {Name: "dms-greeter", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"}, - "matugen": {Name: "matugen", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"}, - "dgop": {Name: "dgop", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"}, - "ghostty": {Name: "ghostty", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"}, - } - - switch wm { - case deps.WindowManagerHyprland: - // Use the cppiber PPA for Hyprland - packages["hyprland"] = PackageMapping{Name: "hyprland", Repository: RepoTypePPA, RepoURL: "ppa:cppiber/hyprland"} - packages["hyprctl"] = PackageMapping{Name: "hyprland", Repository: RepoTypePPA, RepoURL: "ppa:cppiber/hyprland"} - packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem} - case deps.WindowManagerNiri: - niriVariant := variants["niri"] - packages["niri"] = u.getNiriMapping(niriVariant) - packages["xwayland-satellite"] = u.getXwaylandSatelliteMapping(niriVariant) - } - - return packages -} - -func (u *UbuntuDistribution) getDmsMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "dms-git", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/dms-git"} - } - return PackageMapping{Name: "dms", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/dms"} -} - -func (u *UbuntuDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping { - if forceQuickshellGit || variant == deps.VariantGit { - return PackageMapping{Name: "quickshell-git", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} - } - return PackageMapping{Name: "quickshell", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} -} - -func (u *UbuntuDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "niri-git", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} - } - return PackageMapping{Name: "niri", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} -} - -func (u *UbuntuDistribution) getXwaylandSatelliteMapping(variant deps.PackageVariant) PackageMapping { - if variant == deps.VariantGit { - return PackageMapping{Name: "xwayland-satellite-git", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} - } - return PackageMapping{Name: "xwayland-satellite", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"} -} - -func (u *UbuntuDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.06, - Step: "Updating package lists...", - IsComplete: false, - LogOutput: "Updating APT package lists", - } - - updateCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get update") - if err := u.runWithProgress(updateCmd, progressChan, PhasePrerequisites, 0.06, 0.07); err != nil { - return fmt.Errorf("failed to update package lists: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.08, - Step: "Installing build-essential...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install -y build-essential", - LogOutput: "Installing build tools", - } - - checkCmd := exec.CommandContext(ctx, "dpkg", "-l", "build-essential") - if err := checkCmd.Run(); err != nil { - // Not installed, install it - cmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y build-essential") - if err := u.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.09); err != nil { - return fmt.Errorf("failed to install build-essential: %w", err) - } - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.10, - Step: "Installing development dependencies...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install -y curl wget git cmake ninja-build pkg-config libglib2.0-dev libpolkit-agent-1-dev", - LogOutput: "Installing additional development tools", - } - - devToolsCmd := ExecSudoCommand(ctx, sudoPassword, - "apt-get install -y curl wget git cmake ninja-build pkg-config libglib2.0-dev libpolkit-agent-1-dev") - if err := u.runWithProgress(devToolsCmd, progressChan, PhasePrerequisites, 0.10, 0.12); err != nil { - return fmt.Errorf("failed to install development tools: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.12, - Step: "Prerequisites installation complete", - IsComplete: false, - LogOutput: "Prerequisites successfully installed", - } - - return nil -} - -func (u *UbuntuDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, disabledFlags map[string]bool, skipGlobalUseFlags bool, progressChan chan<- InstallProgressMsg) error { - // Phase 1: Check Prerequisites - progressChan <- InstallProgressMsg{ - Phase: PhasePrerequisites, - Progress: 0.05, - Step: "Checking system prerequisites...", - IsComplete: false, - LogOutput: "Starting prerequisite check...", - } - - if err := u.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install prerequisites: %w", err) - } - - systemPkgs, ppaPkgs, manualPkgs, variantMap := u.categorizePackages(dependencies, wm, reinstallFlags, disabledFlags) - - // Phase 2: Enable PPA repositories - if len(ppaPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.15, - Step: "Enabling PPA repositories...", - IsComplete: false, - LogOutput: "Setting up PPA repositories for additional packages", - } - if err := u.enablePPARepos(ctx, ppaPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to enable PPA repositories: %w", err) - } - } - - // Phase 3: System Packages (APT) - if len(systemPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.35, - Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)), - IsComplete: false, - NeedsSudo: true, - LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")), - } - if err := u.installAPTPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install APT packages: %w", err) - } - } - - // Phase 4: PPA Packages - ppaPkgNames := u.extractPackageNames(ppaPkgs) - if len(ppaPkgNames) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseAURPackages, // Reusing AUR phase for PPA - Progress: 0.65, - Step: fmt.Sprintf("Installing %d PPA packages...", len(ppaPkgNames)), - IsComplete: false, - LogOutput: fmt.Sprintf("Installing PPA packages: %s", strings.Join(ppaPkgNames, ", ")), - } - if err := u.installPPAPackages(ctx, ppaPkgNames, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install PPA packages: %w", err) - } - } - - // Phase 5: Manual Builds - if len(manualPkgs) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.80, - Step: "Installing build dependencies...", - IsComplete: false, - LogOutput: "Installing build tools for manual compilation", - } - if err := u.installBuildDependencies(ctx, manualPkgs, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install build dependencies: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.85, - Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)), - IsComplete: false, - LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")), - } - if err := u.InstallManualPackages(ctx, manualPkgs, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install manual packages: %w", err) - } - } - - // Phase 6: Configuration - progressChan <- InstallProgressMsg{ - Phase: PhaseConfiguration, - Progress: 0.90, - Step: "Configuring system...", - IsComplete: false, - LogOutput: "Starting post-installation configuration...", - } - - terminal := u.DetectTerminalFromDeps(dependencies) - if err := u.WriteEnvironmentConfig(terminal); err != nil { - u.log(fmt.Sprintf("Warning: failed to write environment config: %v", err)) - } - - if err := u.WriteWindowManagerConfig(wm); err != nil { - u.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err)) - } - - if err := u.EnableDMSService(ctx, wm); err != nil { - u.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err)) - } - - // Phase 7: Complete - progressChan <- InstallProgressMsg{ - Phase: PhaseComplete, - Progress: 1.0, - Step: "Installation complete!", - IsComplete: true, - LogOutput: "All packages installed and configured successfully", - } - - return nil -} - -func (u *UbuntuDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool, disabledFlags map[string]bool) ([]string, []PackageMapping, []string, map[string]deps.PackageVariant) { - systemPkgs := []string{} - ppaPkgs := []PackageMapping{} - manualPkgs := []string{} - - variantMap := make(map[string]deps.PackageVariant) - for _, dep := range dependencies { - variantMap[dep.Name] = dep.Variant - } - - packageMap := u.GetPackageMappingWithVariants(wm, variantMap) - - for _, dep := range dependencies { - if disabledFlags[dep.Name] { - continue - } - - if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] { - continue - } - - pkgInfo, exists := packageMap[dep.Name] - if !exists { - u.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name)) - continue - } - - switch pkgInfo.Repository { - case RepoTypeSystem: - systemPkgs = append(systemPkgs, pkgInfo.Name) - case RepoTypePPA: - ppaPkgs = append(ppaPkgs, pkgInfo) - case RepoTypeManual: - manualPkgs = append(manualPkgs, dep.Name) - } - } - - return systemPkgs, ppaPkgs, manualPkgs, variantMap -} - -func (u *UbuntuDistribution) extractPackageNames(packages []PackageMapping) []string { - names := make([]string, len(packages)) - for i, pkg := range packages { - names[i] = pkg.Name - } - return names -} - -func (u *UbuntuDistribution) enablePPARepos(ctx context.Context, ppaPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - enabledRepos := make(map[string]bool) - - installPPACmd := ExecSudoCommand(ctx, sudoPassword, - "apt-get install -y software-properties-common") - if err := u.runWithProgress(installPPACmd, progressChan, PhaseSystemPackages, 0.15, 0.17); err != nil { - return fmt.Errorf("failed to install software-properties-common: %w", err) - } - - for _, pkg := range ppaPkgs { - if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] { - u.log(fmt.Sprintf("Enabling PPA repository: %s", pkg.RepoURL)) - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.20, - Step: fmt.Sprintf("Enabling PPA repo %s...", pkg.RepoURL), - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo add-apt-repository -y %s", pkg.RepoURL), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, - fmt.Sprintf("add-apt-repository -y %s", pkg.RepoURL)) - if err := u.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil { - u.logError(fmt.Sprintf("failed to enable PPA repo %s", pkg.RepoURL), err) - return fmt.Errorf("failed to enable PPA repo %s: %w", pkg.RepoURL, err) - } - u.log(fmt.Sprintf("PPA repo %s enabled successfully", pkg.RepoURL)) - enabledRepos[pkg.RepoURL] = true - } - } - - if len(enabledRepos) > 0 { - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.25, - Step: "Updating package lists...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get update", - } - - updateCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get update") - if err := u.runWithProgress(updateCmd, progressChan, PhaseSystemPackages, 0.25, 0.27); err != nil { - return fmt.Errorf("failed to update package lists after adding PPAs: %w", err) - } - } - - return nil -} - -func (u *UbuntuDistribution) installAPTPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - u.log(fmt.Sprintf("Installing APT packages: %s", strings.Join(packages, ", "))) - return u.installAPTGroups(ctx, packages, sudoPassword, progressChan, PhaseSystemPackages, "Installing system packages...", 0.40, 0.60) -} - -func (u *UbuntuDistribution) installPPAPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - u.log(fmt.Sprintf("Installing PPA packages: %s", strings.Join(packages, ", "))) - return u.installAPTGroups(ctx, packages, sudoPassword, progressChan, PhaseAURPackages, "Installing PPA packages...", 0.70, 0.85) -} - -func (u *UbuntuDistribution) aptInstallArgs(packages []string, minimal bool) []string { - args := []string{"DEBIAN_FRONTEND=noninteractive", "apt-get", "install", "-y"} - if minimal { - args = append(args, "--no-install-recommends") - } - return append(args, packages...) -} - -func (u *UbuntuDistribution) installAPTGroups(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg, phase InstallPhase, step string, startProgress float64, endProgress float64) error { - groups := orderedMinimalInstallGroups(packages) - totalGroups := len(groups) - - groupIndex := 0 - installGroup := func(groupPackages []string, minimal bool) error { - if len(groupPackages) == 0 { - return nil - } - - groupIndex++ - groupStart := startProgress - groupEnd := endProgress - if totalGroups > 1 { - midpoint := startProgress + ((endProgress - startProgress) / 2) - if groupIndex == 1 { - groupEnd = midpoint - } else { - groupStart = midpoint - } - } - - args := u.aptInstallArgs(groupPackages, minimal) - progressChan <- InstallProgressMsg{ - Phase: phase, - Progress: groupStart, - Step: step, - IsComplete: false, - NeedsSudo: true, - CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")), - } - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return u.runWithProgress(cmd, progressChan, phase, groupStart, groupEnd) - } - - for _, group := range groups { - if err := installGroup(group.packages, group.minimal); err != nil { - return err - } - } - return nil -} - -func (u *UbuntuDistribution) installBuildDependencies(ctx context.Context, manualPkgs []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - buildDeps := make(map[string]bool) - - for _, pkg := range manualPkgs { - switch pkg { - case "niri": - buildDeps["curl"] = true - buildDeps["libxkbcommon-dev"] = true - buildDeps["libwayland-dev"] = true - buildDeps["libudev-dev"] = true - buildDeps["libinput-dev"] = true - buildDeps["libdisplay-info-dev"] = true - buildDeps["libpango1.0-dev"] = true - buildDeps["libcairo-dev"] = true - buildDeps["libpipewire-0.3-dev"] = true - buildDeps["libc6-dev"] = true - buildDeps["clang"] = true - buildDeps["libseat-dev"] = true - buildDeps["libgbm-dev"] = true - buildDeps["alacritty"] = true - buildDeps["fuzzel"] = true - buildDeps["libxcb-cursor-dev"] = true - case "quickshell": - buildDeps["qt6-base-dev"] = true - buildDeps["qt6-base-private-dev"] = true - buildDeps["qt6-declarative-dev"] = true - buildDeps["qt6-declarative-private-dev"] = true - buildDeps["qt6-wayland-dev"] = true - buildDeps["qt6-wayland-private-dev"] = true - buildDeps["qt6-tools-dev"] = true - buildDeps["libqt6svg6-dev"] = true - buildDeps["qt6-shadertools-dev"] = true - buildDeps["spirv-tools"] = true - buildDeps["libcli11-dev"] = true - buildDeps["libjemalloc-dev"] = true - buildDeps["libwayland-dev"] = true - buildDeps["wayland-protocols"] = true - buildDeps["libdrm-dev"] = true - buildDeps["libgbm-dev"] = true - buildDeps["libegl-dev"] = true - buildDeps["libgles2-mesa-dev"] = true - buildDeps["libgl1-mesa-dev"] = true - buildDeps["libxcb1-dev"] = true - buildDeps["libpipewire-0.3-dev"] = true - buildDeps["libpam0g-dev"] = true - case "matugen": - buildDeps["curl"] = true - } - } - - for _, pkg := range manualPkgs { - switch pkg { - case "niri", "matugen": - if err := u.installRust(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Rust: %w", err) - } - case "dgop": - if err := u.installGo(ctx, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install Go: %w", err) - } - } - } - - if len(buildDeps) == 0 { - return nil - } - - depList := make([]string, 0, len(buildDeps)) - for dep := range buildDeps { - depList = append(depList, dep) - } - - args := []string{"apt-get", "install", "-y"} - args = append(args, depList...) - - cmd := ExecSudoCommand(ctx, sudoPassword, strings.Join(args, " ")) - return u.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.80, 0.82) -} - -func (u *UbuntuDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if u.commandExists("cargo") { - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.82, - Step: "Installing rustup...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install rustup", - } - - rustupInstallCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y rustup") - if err := u.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil { - return fmt.Errorf("failed to install rustup: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.83, - Step: "Installing stable Rust toolchain...", - IsComplete: false, - CommandInfo: "rustup install stable", - } - - rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable") - if err := u.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil { - return fmt.Errorf("failed to install Rust toolchain: %w", err) - } - - // Verify cargo is now available - if !u.commandExists("cargo") { - u.log("Warning: cargo not found in PATH after Rust installation, trying to source environment") - } - - return nil -} - -func (u *UbuntuDistribution) installGo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if u.commandExists("go") { - return nil - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.87, - Step: "Adding Go PPA repository...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo add-apt-repository ppa:longsleep/golang-backports", - } - - addPPACmd := ExecSudoCommand(ctx, sudoPassword, - "add-apt-repository -y ppa:longsleep/golang-backports") - if err := u.runWithProgress(addPPACmd, progressChan, PhaseSystemPackages, 0.87, 0.88); err != nil { - return fmt.Errorf("failed to add Go PPA: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.88, - Step: "Updating package lists...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get update", - } - - updateCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get update") - if err := u.runWithProgress(updateCmd, progressChan, PhaseSystemPackages, 0.88, 0.89); err != nil { - return fmt.Errorf("failed to update package lists after adding Go PPA: %w", err) - } - - progressChan <- InstallProgressMsg{ - Phase: PhaseSystemPackages, - Progress: 0.89, - Step: "Installing Go...", - IsComplete: false, - NeedsSudo: true, - CommandInfo: "sudo apt-get install golang-go", - } - - installCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y golang-go") - return u.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.89, 0.90) -} - -func (u *UbuntuDistribution) InstallManualPackages(ctx context.Context, packages []string, variantMap map[string]deps.PackageVariant, sudoPassword string, progressChan chan<- InstallProgressMsg) error { - if len(packages) == 0 { - return nil - } - - u.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", "))) - - for _, pkg := range packages { - switch pkg { - default: - if err := u.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, variantMap, sudoPassword, progressChan); err != nil { - return fmt.Errorf("failed to install %s: %w", pkg, err) - } - } - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/errdefs/errdefs.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/errdefs/errdefs.go deleted file mode 100644 index 3b5f159..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/errdefs/errdefs.go +++ /dev/null @@ -1,65 +0,0 @@ -package errdefs - -type ErrorType int - -const ( - ErrTypeNotLinux ErrorType = iota - ErrTypeInvalidArchitecture - ErrTypeUnsupportedDistribution - ErrTypeUnsupportedVersion - ErrTypeUpdateCancelled - ErrTypeNoUpdateNeeded - ErrTypeInvalidTemperature - ErrTypeInvalidGamma - ErrTypeInvalidLocation - ErrTypeInvalidManualTimes - ErrTypeNoWaylandDisplay - ErrTypeNoGammaControl - ErrTypeNotInitialized - ErrTypeSecretPromptCancelled - ErrTypeSecretPromptTimeout - ErrTypeSecretAgentFailed - ErrTypeGeneric -) - -type CustomError struct { - Type ErrorType - Message string -} - -func (e *CustomError) Error() string { - return e.Message -} - -func NewCustomError(errType ErrorType, message string) error { - return &CustomError{ - Type: errType, - Message: message, - } -} - -const ( - ErrBadCredentials = "bad-credentials" - ErrNoSuchSSID = "no-such-ssid" - ErrAssocTimeout = "assoc-timeout" - ErrDhcpTimeout = "dhcp-timeout" - ErrUserCanceled = "user-canceled" - ErrWifiDisabled = "wifi-disabled" - ErrAlreadyConnected = "already-connected" - ErrConnectionFailed = "connection-failed" -) - -var ( - ErrUpdateCancelled = NewCustomError(ErrTypeUpdateCancelled, "update cancelled by user") - ErrNoUpdateNeeded = NewCustomError(ErrTypeNoUpdateNeeded, "no update needed") - ErrInvalidTemperature = NewCustomError(ErrTypeInvalidTemperature, "temperature must be between 1000 and 10000") - ErrInvalidGamma = NewCustomError(ErrTypeInvalidGamma, "gamma must be between 0 and 10") - ErrInvalidLocation = NewCustomError(ErrTypeInvalidLocation, "invalid latitude/longitude") - ErrInvalidManualTimes = NewCustomError(ErrTypeInvalidManualTimes, "both sunrise and sunset must be set or neither") - ErrNoWaylandDisplay = NewCustomError(ErrTypeNoWaylandDisplay, "no wayland display available") - ErrNoGammaControl = NewCustomError(ErrTypeNoGammaControl, "compositor does not support gamma control") - ErrNotInitialized = NewCustomError(ErrTypeNotInitialized, "manager not initialized") - ErrSecretPromptCancelled = NewCustomError(ErrTypeSecretPromptCancelled, "secret prompt cancelled by user") - ErrSecretPromptTimeout = NewCustomError(ErrTypeSecretPromptTimeout, "secret prompt timed out") - ErrSecretAgentFailed = NewCustomError(ErrTypeSecretAgentFailed, "secret agent operation failed") -) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client.go deleted file mode 100644 index 5b44121..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client.go +++ /dev/null @@ -1,42 +0,0 @@ -package geolocation - -import "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - -func NewClient() Client { - geoclueClient, err := newGeoClueClient() - if err != nil { - log.Warnf("GeoClue2 unavailable: %v", err) - return newSeededIpClient() - } - - loc, _ := geoclueClient.GetLocation() - if loc.Latitude != 0 || loc.Longitude != 0 { - log.Info("Using GeoClue2 location") - return geoclueClient - } - - log.Info("GeoClue2 has no fix yet, seeding with IP location") - ipLoc, err := fetchIPLocation() - if err != nil { - log.Warnf("IP location seed failed: %v", err) - return geoclueClient - } - - log.Info("Seeded GeoClue2 with IP location") - geoclueClient.SeedLocation(Location{Latitude: ipLoc.Latitude, Longitude: ipLoc.Longitude}) - return geoclueClient -} - -func newSeededIpClient() *IpClient { - client := newIpClient() - ipLoc, err := fetchIPLocation() - if err != nil { - log.Warnf("IP location also failed: %v", err) - return client - } - - log.Info("Using IP location") - client.currLocation.Latitude = ipLoc.Latitude - client.currLocation.Longitude = ipLoc.Longitude - return client -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_geoclue.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_geoclue.go deleted file mode 100644 index a06aadf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_geoclue.go +++ /dev/null @@ -1,243 +0,0 @@ -package geolocation - -import ( - "fmt" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -const ( - dbusGeoClueService = "org.freedesktop.GeoClue2" - dbusGeoCluePath = "/org/freedesktop/GeoClue2" - dbusGeoClueInterface = dbusGeoClueService - - dbusGeoClueManagerPath = dbusGeoCluePath + "/Manager" - dbusGeoClueManagerInterface = dbusGeoClueInterface + ".Manager" - dbusGeoClueManagerGetClient = dbusGeoClueManagerInterface + ".GetClient" - - dbusGeoClueClientInterface = dbusGeoClueInterface + ".Client" - dbusGeoClueClientDesktopId = dbusGeoClueClientInterface + ".DesktopId" - dbusGeoClueClientTimeThreshold = dbusGeoClueClientInterface + ".TimeThreshold" - dbusGeoClueClientTimeStart = dbusGeoClueClientInterface + ".Start" - dbusGeoClueClientTimeStop = dbusGeoClueClientInterface + ".Stop" - dbusGeoClueClientLocationUpdated = dbusGeoClueClientInterface + ".LocationUpdated" - - dbusGeoClueLocationInterface = dbusGeoClueInterface + ".Location" - dbusGeoClueLocationLatitude = dbusGeoClueLocationInterface + ".Latitude" - dbusGeoClueLocationLongitude = dbusGeoClueLocationInterface + ".Longitude" -) - -type GeoClueClient struct { - currLocation *Location - locationMutex sync.RWMutex - - dbusConn *dbus.Conn - clientPath dbus.ObjectPath - signals chan *dbus.Signal - - stopChan chan struct{} - sigWG sync.WaitGroup - - subscribers syncmap.Map[string, chan Location] -} - -func newGeoClueClient() (*GeoClueClient, error) { - dbusConn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("system bus connection failed: %w", err) - } - - c := &GeoClueClient{ - dbusConn: dbusConn, - stopChan: make(chan struct{}), - signals: make(chan *dbus.Signal, 256), - - currLocation: &Location{ - Latitude: 0.0, - Longitude: 0.0, - }, - } - - if err := c.setupClient(); err != nil { - dbusConn.Close() - return nil, err - } - - if err := c.startSignalPump(); err != nil { - return nil, err - } - - return c, nil -} - -func (c *GeoClueClient) Close() { - close(c.stopChan) - - c.sigWG.Wait() - - if c.signals != nil { - c.dbusConn.RemoveSignal(c.signals) - close(c.signals) - } - - c.subscribers.Range(func(key string, ch chan Location) bool { - close(ch) - c.subscribers.Delete(key) - return true - }) - - if c.dbusConn != nil { - c.dbusConn.Close() - } -} - -func (c *GeoClueClient) Subscribe(id string) chan Location { - ch := make(chan Location, 64) - c.subscribers.Store(id, ch) - return ch -} - -func (c *GeoClueClient) Unsubscribe(id string) { - if ch, ok := c.subscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (c *GeoClueClient) setupClient() error { - managerObj := c.dbusConn.Object(dbusGeoClueService, dbusGeoClueManagerPath) - - if err := managerObj.Call(dbusGeoClueManagerGetClient, 0).Store(&c.clientPath); err != nil { - return fmt.Errorf("failed to create GeoClue2 client: %w", err) - } - - clientObj := c.dbusConn.Object(dbusGeoClueService, c.clientPath) - if err := clientObj.SetProperty(dbusGeoClueClientDesktopId, "dms"); err != nil { - return fmt.Errorf("failed to set desktop ID: %w", err) - } - - if err := clientObj.SetProperty(dbusGeoClueClientTimeThreshold, uint(10)); err != nil { - return fmt.Errorf("failed to set time threshold: %w", err) - } - - return nil -} - -func (c *GeoClueClient) startSignalPump() error { - c.dbusConn.Signal(c.signals) - - if err := c.dbusConn.AddMatchSignal( - dbus.WithMatchObjectPath(c.clientPath), - dbus.WithMatchInterface(dbusGeoClueClientInterface), - dbus.WithMatchSender(dbusGeoClueClientLocationUpdated), - ); err != nil { - return err - } - - c.sigWG.Add(1) - go func() { - defer c.sigWG.Done() - - clientObj := c.dbusConn.Object(dbusGeoClueService, c.clientPath) - clientObj.Call(dbusGeoClueClientTimeStart, 0) - defer clientObj.Call(dbusGeoClueClientTimeStop, 0) - - for { - select { - case <-c.stopChan: - return - case sig, ok := <-c.signals: - if !ok { - return - } - if sig == nil { - continue - } - - c.handleSignal(sig) - } - } - }() - - return nil -} - -func (c *GeoClueClient) handleSignal(sig *dbus.Signal) { - switch sig.Name { - case dbusGeoClueClientLocationUpdated: - if len(sig.Body) != 2 { - return - } - - newLocationPath, ok := sig.Body[1].(dbus.ObjectPath) - if !ok { - return - } - - if err := c.handleLocationUpdated(newLocationPath); err != nil { - log.Warn("GeoClue: Failed to handle location update: %v", err) - return - } - } -} - -func (c *GeoClueClient) handleLocationUpdated(path dbus.ObjectPath) error { - locationObj := c.dbusConn.Object(dbusGeoClueService, path) - - lat, err := locationObj.GetProperty(dbusGeoClueLocationLatitude) - if err != nil { - return err - } - - long, err := locationObj.GetProperty(dbusGeoClueLocationLongitude) - if err != nil { - return err - } - - c.locationMutex.Lock() - c.currLocation.Latitude = dbusutil.AsOr(lat, 0.0) - c.currLocation.Longitude = dbusutil.AsOr(long, 0.0) - c.locationMutex.Unlock() - - c.notifySubscribers() - return nil -} - -func (c *GeoClueClient) notifySubscribers() { - currentLocation, err := c.GetLocation() - if err != nil { - return - } - - c.subscribers.Range(func(key string, ch chan Location) bool { - select { - case ch <- currentLocation: - default: - log.Warn("GeoClue: subscriber channel full, dropping update") - } - return true - }) -} - -func (c *GeoClueClient) SeedLocation(loc Location) { - c.locationMutex.Lock() - defer c.locationMutex.Unlock() - c.currLocation.Latitude = loc.Latitude - c.currLocation.Longitude = loc.Longitude -} - -func (c *GeoClueClient) GetLocation() (Location, error) { - c.locationMutex.RLock() - defer c.locationMutex.RUnlock() - if c.currLocation == nil { - return Location{ - Latitude: 0.0, - Longitude: 0.0, - }, nil - } - stateCopy := *c.currLocation - return stateCopy, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_ip.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_ip.go deleted file mode 100644 index 0e68cae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/client_ip.go +++ /dev/null @@ -1,91 +0,0 @@ -package geolocation - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "time" -) - -type IpClient struct { - currLocation *Location -} - -type ipLocationResult struct { - Location - City string -} - -type ipAPIResponse struct { - Status string `json:"status"` - Lat float64 `json:"lat"` - Lon float64 `json:"lon"` - City string `json:"city"` -} - -func newIpClient() *IpClient { - return &IpClient{ - currLocation: &Location{}, - } -} - -func (c *IpClient) Subscribe(id string) chan Location { - ch := make(chan Location, 1) - if location, err := c.GetLocation(); err == nil { - ch <- location - } - return ch -} - -func (c *IpClient) Unsubscribe(id string) {} - -func (c *IpClient) Close() {} - -func (c *IpClient) GetLocation() (Location, error) { - if c.currLocation.Latitude != 0 || c.currLocation.Longitude != 0 { - return *c.currLocation, nil - } - - result, err := fetchIPLocation() - if err != nil { - return Location{}, err - } - - c.currLocation.Latitude = result.Latitude - c.currLocation.Longitude = result.Longitude - return *c.currLocation, nil -} - -func fetchIPLocation() (ipLocationResult, error) { - client := &http.Client{Timeout: 10 * time.Second} - - resp, err := client.Get("http://ip-api.com/json/") - if err != nil { - return ipLocationResult{}, fmt.Errorf("failed to fetch IP location: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return ipLocationResult{}, fmt.Errorf("ip-api.com returned status %d", resp.StatusCode) - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return ipLocationResult{}, fmt.Errorf("failed to read response: %w", err) - } - - var data ipAPIResponse - if err := json.Unmarshal(body, &data); err != nil { - return ipLocationResult{}, fmt.Errorf("failed to parse response: %w", err) - } - - if data.Status == "fail" || (data.Lat == 0 && data.Lon == 0) { - return ipLocationResult{}, fmt.Errorf("ip-api.com returned no location data") - } - - return ipLocationResult{ - Location: Location{Latitude: data.Lat, Longitude: data.Lon}, - City: data.City, - }, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/types.go deleted file mode 100644 index bf71041..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/geolocation/types.go +++ /dev/null @@ -1,15 +0,0 @@ -package geolocation - -type Location struct { - Latitude float64 - Longitude float64 -} - -type Client interface { - GetLocation() (Location, error) - - Subscribe(id string) chan Location - Unsubscribe(id string) - - Close() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/assets/apparmor/usr.bin.dms-greeter b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/assets/apparmor/usr.bin.dms-greeter deleted file mode 100644 index 7c42f9e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/assets/apparmor/usr.bin.dms-greeter +++ /dev/null @@ -1,91 +0,0 @@ -# AppArmor profile for dms-greeter -# -# Managed by DMS — regenerated on every `dms greeter install` / `dms greeter sync`. -# Manual edits will be overwritten on next sync. -# -# Mode: complain (denials are logged, nothing is blocked) -# To switch to enforce after validating with `aa-logprof`: -# sudo aa-enforce /etc/apparmor.d/usr.bin.dms-greeter -# -#include - -profile dms-greeter /usr/bin/dms-greeter flags=(complain) { - #include - #include - - # The launcher script itself - /usr/bin/dms-greeter r, - - # Cache directory — created by dms greeter sync/enable with greeter:greeter ownership - /var/cache/dms-greeter/ rw, - /var/cache/dms-greeter/** rwlk, - - # DMS config — packaged path - /usr/share/quickshell/dms-greeter/ r, - /usr/share/quickshell/dms-greeter/** r, - /usr/share/quickshell/ r, - /usr/share/quickshell/** r, - - # DMS config — system and user overrides - /etc/dms/ r, - /etc/dms/** r, - /usr/share/dms/ r, - /usr/share/dms/** r, - /home/*/.config/quickshell/ r, - /home/*/.config/quickshell/** r, - /root/.config/quickshell/ r, - /root/.config/quickshell/** r, - - # greetd / PAM — read-only for session setup - /etc/greetd/ r, - /etc/greetd/** r, - /etc/pam.d/ r, - /etc/pam.d/** r, - /usr/lib/pam.d/ r, - /usr/lib/pam.d/** r, - - # Compositor binaries — run unconfined so each compositor uses its own profile - /usr/bin/niri Ux, - /usr/bin/hyprland Ux, - /usr/bin/Hyprland Ux, - /usr/bin/sway Ux, - /usr/bin/labwc Ux, - /usr/bin/scroll Ux, - /usr/bin/miracle-wm Ux, - /usr/bin/mango Ux, - - # Quickshell — run unconfined (has its own compositor profile on some distros) - /usr/bin/qs Ux, - /usr/bin/quickshell Ux, - - # Wayland / XDG runtime (pipewire, wireplumber, wayland socket) - /run/user/[0-9]*/ rw, - /run/user/[0-9]*/** rw, - - # DRM / GPU devices (required for Wayland compositor startup) - /dev/dri/ r, - /dev/dri/* rw, - /dev/udmabuf rw, - - # Input devices - /dev/input/ r, - /dev/input/* r, - - # Systemd journal / logging - /run/systemd/journal/socket rw, - /dev/log rw, - - # Shell helper binaries invoked by the launcher script - /usr/bin/env ix, - /usr/bin/mkdir ix, - /usr/bin/cat ix, - /usr/bin/grep ix, - /usr/bin/dirname ix, - /usr/bin/basename ix, - /usr/bin/command ix, - /bin/env ix, - /bin/mkdir ix, - - # Signal management (compositor lifecycle) - signal (send, receive) set=("term", "int", "hup", "kill"), -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer.go deleted file mode 100644 index ace72ce..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer.go +++ /dev/null @@ -1,2076 +0,0 @@ -package greeter - -import ( - "bufio" - "context" - _ "embed" - "encoding/json" - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/matugen" - sharedpam "github.com/AvengeMedia/DankMaterialShell/core/internal/pam" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/sblinch/kdl-go" - "github.com/sblinch/kdl-go/document" -) - -var appArmorProfileData []byte - -const appArmorProfileDest = "/etc/apparmor.d/usr.bin.dms-greeter" - -const GreeterCacheDir = "/var/cache/dms-greeter" - -func DetectDMSPath() (string, error) { - return config.LocateDMSConfig() -} - -// IsNixOS returns true when running on NixOS, which manages PAM configs through -// its module system. The DMS PAM managed block won't be written on NixOS. -func IsNixOS() bool { - _, err := os.Stat("/etc/NIXOS") - return err == nil -} - -func DetectGreeterGroup() string { - data, err := os.ReadFile("/etc/group") - if err != nil { - fmt.Fprintln(os.Stderr, "⚠ Warning: could not read /etc/group, defaulting to greeter") - return "greeter" - } - - if group, found := utils.FindGroupData(string(data), "greeter", "greetd", "_greeter"); found { - return group - } - - fmt.Fprintln(os.Stderr, "⚠ Warning: no greeter group found in /etc/group, defaulting to greeter") - return "greeter" -} - -func hasPasswdUser(passwdData, user string) bool { - prefix := user + ":" - for line := range strings.SplitSeq(passwdData, "\n") { - if strings.HasPrefix(line, prefix) { - return true - } - } - return false -} - -func findPasswdUser(passwdData string, candidates ...string) (string, bool) { - for _, candidate := range candidates { - if hasPasswdUser(passwdData, candidate) { - return candidate, true - } - } - return "", false -} - -func stripTomlComment(line string) string { - trimmed := strings.TrimSpace(line) - if idx := strings.Index(trimmed, "#"); idx >= 0 { - return strings.TrimSpace(trimmed[:idx]) - } - return trimmed -} - -func parseTomlSection(line string) (string, bool) { - trimmed := stripTomlComment(line) - if len(trimmed) < 3 || !strings.HasPrefix(trimmed, "[") || !strings.HasSuffix(trimmed, "]") { - return "", false - } - return strings.TrimSpace(trimmed[1 : len(trimmed)-1]), true -} - -func extractDefaultSessionUser(configContent string) string { - inDefaultSession := false - for line := range strings.SplitSeq(configContent, "\n") { - if section, ok := parseTomlSection(line); ok { - inDefaultSession = section == "default_session" - continue - } - - if !inDefaultSession { - continue - } - - trimmed := stripTomlComment(line) - if !strings.HasPrefix(trimmed, "user =") && !strings.HasPrefix(trimmed, "user=") { - continue - } - - parts := strings.SplitN(trimmed, "=", 2) - if len(parts) != 2 { - continue - } - user := strings.Trim(strings.TrimSpace(parts[1]), `"`) - if user != "" { - return user - } - } - - return "" -} - -func upsertDefaultSession(configContent, greeterUser, command string) string { - lines := strings.Split(configContent, "\n") - var out []string - - inDefaultSession := false - foundDefaultSession := false - defaultSessionUserSet := false - defaultSessionCommandSet := false - - appendDefaultSessionFields := func() { - if !defaultSessionUserSet { - out = append(out, fmt.Sprintf(`user = "%s"`, greeterUser)) - } - if !defaultSessionCommandSet { - out = append(out, command) - } - } - - for _, line := range lines { - if section, ok := parseTomlSection(line); ok { - if inDefaultSession { - appendDefaultSessionFields() - } - - inDefaultSession = section == "default_session" - if inDefaultSession { - foundDefaultSession = true - defaultSessionUserSet = false - defaultSessionCommandSet = false - } - - out = append(out, line) - continue - } - - if inDefaultSession { - trimmed := stripTomlComment(line) - if strings.HasPrefix(trimmed, "user =") || strings.HasPrefix(trimmed, "user=") { - out = append(out, fmt.Sprintf(`user = "%s"`, greeterUser)) - defaultSessionUserSet = true - continue - } - - if strings.HasPrefix(trimmed, "command =") || strings.HasPrefix(trimmed, "command=") { - if !defaultSessionCommandSet { - out = append(out, command) - defaultSessionCommandSet = true - } - continue - } - } - - out = append(out, line) - } - - if inDefaultSession { - appendDefaultSessionFields() - } - - if !foundDefaultSession { - if len(out) > 0 && strings.TrimSpace(out[len(out)-1]) != "" { - out = append(out, "") - } - out = append(out, "[default_session]") - out = append(out, fmt.Sprintf(`user = "%s"`, greeterUser)) - out = append(out, command) - } - - return strings.Join(out, "\n") -} - -func DetectGreeterUser() string { - passwdData, err := os.ReadFile("/etc/passwd") - if err == nil { - passwdContent := string(passwdData) - - if configData, cfgErr := os.ReadFile("/etc/greetd/config.toml"); cfgErr == nil { - if configured := extractDefaultSessionUser(string(configData)); configured != "" && hasPasswdUser(passwdContent, configured) { - return configured - } - } - - if user, found := findPasswdUser(passwdContent, "greeter", "greetd", "_greeter"); found { - return user - } - } else { - fmt.Fprintln(os.Stderr, "⚠ Warning: could not read /etc/passwd, defaulting greeter user to 'greeter'") - } - - if configData, cfgErr := os.ReadFile("/etc/greetd/config.toml"); cfgErr == nil { - if configured := extractDefaultSessionUser(string(configData)); configured != "" { - return configured - } - } - - fmt.Fprintln(os.Stderr, "⚠ Warning: no greeter user found, defaulting to 'greeter'") - return "greeter" -} - -func resolveGreeterWrapperPath() string { - if override := strings.TrimSpace(os.Getenv("DMS_GREETER_WRAPPER_CMD")); override != "" { - return override - } - - // Packaged installs only use the official wrapper; never fall back to /usr/local/bin. - if IsGreeterPackaged() { - packagedWrapper := "/usr/bin/dms-greeter" - if info, err := os.Stat(packagedWrapper); err == nil && !info.IsDir() && (info.Mode()&0o111) != 0 { - return packagedWrapper - } - fmt.Fprintln(os.Stderr, "⚠ Warning: packaged dms-greeter detected, but /usr/bin/dms-greeter is missing or not executable") - return packagedWrapper - } - - for _, candidate := range []string{"/usr/bin/dms-greeter", "/usr/local/bin/dms-greeter"} { - if info, err := os.Stat(candidate); err == nil && !info.IsDir() && (info.Mode()&0o111) != 0 { - return candidate - } - } - - if path, err := exec.LookPath("dms-greeter"); err == nil { - resolved := path - if realPath, realErr := filepath.EvalSymlinks(path); realErr == nil { - resolved = realPath - } - if strings.HasPrefix(resolved, "/home/") || strings.HasPrefix(resolved, "/tmp/") { - fmt.Fprintf(os.Stderr, "⚠ Warning: ignoring non-system dms-greeter on PATH: %s\n", path) - } else { - return path - } - } - - return "/usr/bin/dms-greeter" -} - -func DetectCompositors() []string { - var compositors []string - - if utils.CommandExists("niri") { - compositors = append(compositors, "niri") - } - if utils.CommandExists("Hyprland") { - compositors = append(compositors, "Hyprland") - } - - return compositors -} - -func PromptCompositorChoice(compositors []string) (string, error) { - fmt.Println("\nMultiple compositors detected:") - for i, comp := range compositors { - fmt.Printf("%d) %s\n", i+1, comp) - } - - reader := bufio.NewReader(os.Stdin) - fmt.Print("Choose compositor for greeter (1-2): ") - response, err := reader.ReadString('\n') - if err != nil { - return "", fmt.Errorf("error reading input: %w", err) - } - - response = strings.TrimSpace(response) - switch response { - case "1": - return compositors[0], nil - case "2": - if len(compositors) > 1 { - return compositors[1], nil - } - return "", fmt.Errorf("invalid choice") - default: - return "", fmt.Errorf("invalid choice") - } -} - -// EnsureGreetdInstalled checks if greetd is installed - greetd is a daemon in /usr/sbin on Debian/Ubuntu -func EnsureGreetdInstalled(logFunc func(string), sudoPassword string) error { - greetdFound := utils.CommandExists("greetd") - if !greetdFound { - for _, p := range []string{"/usr/sbin/greetd", "/sbin/greetd"} { - if _, err := os.Stat(p); err == nil { - greetdFound = true - break - } - } - } - if greetdFound { - logFunc("✓ greetd is already installed") - return nil - } - - logFunc("greetd is not installed. Installing...") - - osInfo, err := distros.GetOSInfo() - if err != nil { - return fmt.Errorf("failed to detect OS: %w", err) - } - - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return fmt.Errorf("unsupported distribution for automatic greetd installation: %s", osInfo.Distribution.ID) - } - - ctx := context.Background() - var installCmd *exec.Cmd - - switch config.Family { - case distros.FamilyArch: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "pacman -S --needed --noconfirm greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "pacman", "-S", "--needed", "--noconfirm", "greetd") - } - - case distros.FamilyFedora: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "dnf install -y greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "dnf", "install", "-y", "greetd") - } - - case distros.FamilySUSE: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "zypper install -y greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "zypper", "install", "-y", "greetd") - } - - case distros.FamilyUbuntu: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "apt-get install -y greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "greetd") - } - - case distros.FamilyDebian: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "apt-get install -y greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "greetd") - } - - case distros.FamilyGentoo: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, - "emerge --ask n sys-apps/greetd") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "emerge", "--ask", "n", "sys-apps/greetd") - } - - case distros.FamilyNix: - return fmt.Errorf("on NixOS, please add greetd to your configuration.nix") - - default: - return fmt.Errorf("unsupported distribution family for automatic greetd installation: %s", config.Family) - } - - installCmd.Stdout = os.Stdout - installCmd.Stderr = os.Stderr - - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install greetd: %w", err) - } - - logFunc("✓ greetd installed successfully") - return nil -} - -// IsGreeterPackaged returns true if dms-greeter was installed from a system package. -func IsGreeterPackaged() bool { - if !utils.CommandExists("dms-greeter") { - return false - } - packagedPath := "/usr/share/quickshell/dms-greeter" - info, err := os.Stat(packagedPath) - return err == nil && info.IsDir() -} - -// HasLegacyLocalGreeterWrapper returns true when a manually installed wrapper exists. -func HasLegacyLocalGreeterWrapper() bool { - info, err := os.Stat("/usr/local/bin/dms-greeter") - return err == nil && !info.IsDir() -} - -// TryInstallGreeterPackage attempts to install dms-greeter from the distro's official repo. -func TryInstallGreeterPackage(logFunc func(string), sudoPassword string) bool { - osInfo, err := distros.GetOSInfo() - if err != nil { - return false - } - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return false - } - - if IsGreeterPackaged() { - logFunc("✓ dms-greeter package already installed") - return true - } - - ctx := context.Background() - var installCmd *exec.Cmd - var failHint string - - switch config.Family { - case distros.FamilyDebian: - obsSlug := getDebianOBSSlug(osInfo) - keyURL := fmt.Sprintf("https://download.opensuse.org/repositories/home:AvengeMedia:danklinux/%s/Release.key", obsSlug) - repoLine := fmt.Sprintf("deb [signed-by=/etc/apt/keyrings/danklinux.gpg] https://download.opensuse.org/repositories/home:/AvengeMedia:/danklinux/%s/ /", obsSlug) - failHint = fmt.Sprintf("⚠ dms-greeter install failed. Add OBS repo manually:\nsudo apt-get install -y gnupg\nsudo mkdir -p /etc/apt/keyrings\ncurl -fsSL %s | sudo gpg --dearmor -o /etc/apt/keyrings/danklinux.gpg\necho '%s' | sudo tee /etc/apt/sources.list.d/danklinux.list\nsudo apt update && sudo apt-get install -y dms-greeter", keyURL, repoLine) - logFunc(fmt.Sprintf("Adding DankLinux OBS repository (%s)...", obsSlug)) - if _, err := exec.LookPath("gpg"); err != nil { - logFunc("Installing gnupg for OBS repository key import...") - installGPGCmd := exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "gnupg") - installGPGCmd.Stdout = os.Stdout - installGPGCmd.Stderr = os.Stderr - if err := installGPGCmd.Run(); err != nil { - logFunc(fmt.Sprintf("⚠ Failed to install gnupg: %v", err)) - } - } - mkdirCmd := exec.CommandContext(ctx, "sudo", "mkdir", "-p", "/etc/apt/keyrings") - mkdirCmd.Stdout = os.Stdout - mkdirCmd.Stderr = os.Stderr - mkdirCmd.Run() - addKeyCmd := exec.CommandContext(ctx, "bash", "-c", - fmt.Sprintf(`curl -fsSL %s | sudo gpg --dearmor -o /etc/apt/keyrings/danklinux.gpg`, keyURL)) - addKeyCmd.Stdout = os.Stdout - addKeyCmd.Stderr = os.Stderr - addKeyCmd.Run() - addRepoCmd := exec.CommandContext(ctx, "bash", "-c", - fmt.Sprintf(`echo '%s' | sudo tee /etc/apt/sources.list.d/danklinux.list`, repoLine)) - addRepoCmd.Stdout = os.Stdout - addRepoCmd.Stderr = os.Stderr - addRepoCmd.Run() - exec.CommandContext(ctx, "sudo", "apt-get", "update").Run() - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "dms-greeter") - case distros.FamilySUSE: - repoURL := getOpenSUSEOBSRepoURL(osInfo) - failHint = fmt.Sprintf("⚠ dms-greeter install failed. Add OBS repo manually:\nsudo zypper addrepo %s\nsudo zypper refresh && sudo zypper install dms-greeter", repoURL) - logFunc("Adding DankLinux OBS repository...") - addRepoCmd := exec.CommandContext(ctx, "sudo", "zypper", "addrepo", repoURL) - addRepoCmd.Stdout = os.Stdout - addRepoCmd.Stderr = os.Stderr - addRepoCmd.Run() - exec.CommandContext(ctx, "sudo", "zypper", "refresh").Run() - installCmd = exec.CommandContext(ctx, "sudo", "zypper", "install", "-y", "dms-greeter") - case distros.FamilyUbuntu: - failHint = "⚠ dms-greeter install failed. Add PPA manually: sudo add-apt-repository ppa:avengemedia/danklinux && sudo apt-get update && sudo apt-get install -y dms-greeter" - logFunc("Enabling PPA ppa:avengemedia/danklinux...") - ppacmd := exec.CommandContext(ctx, "sudo", "add-apt-repository", "-y", "ppa:avengemedia/danklinux") - ppacmd.Stdout = os.Stdout - ppacmd.Stderr = os.Stderr - ppacmd.Run() - exec.CommandContext(ctx, "sudo", "apt-get", "update").Run() - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "dms-greeter") - case distros.FamilyFedora: - failHint = "⚠ dms-greeter install failed. Enable COPR manually: sudo dnf copr enable avengemedia/danklinux && sudo dnf install dms-greeter" - logFunc("Enabling COPR avengemedia/danklinux...") - coprcmd := exec.CommandContext(ctx, "sudo", "dnf", "copr", "enable", "-y", "avengemedia/danklinux") - coprcmd.Stdout = os.Stdout - coprcmd.Stderr = os.Stderr - coprcmd.Run() - installCmd = exec.CommandContext(ctx, "sudo", "dnf", "install", "-y", "dms-greeter") - case distros.FamilyArch: - aurHelper := "" - for _, helper := range []string{"paru", "yay"} { - if _, err := exec.LookPath(helper); err == nil { - aurHelper = helper - break - } - } - if aurHelper == "" { - logFunc("⚠ No AUR helper found (paru/yay). Install greetd-dms-greeter-git from AUR: https://aur.archlinux.org/packages/greetd-dms-greeter-git") - return false - } - failHint = fmt.Sprintf("⚠ dms-greeter install failed. Install from AUR: %s -S greetd-dms-greeter-git", aurHelper) - installCmd = exec.CommandContext(ctx, aurHelper, "-S", "--noconfirm", "greetd-dms-greeter-git") - default: - return false - } - - logFunc("Installing dms-greeter from official repository...") - installCmd.Stdout = os.Stdout - installCmd.Stderr = os.Stderr - - if err := installCmd.Run(); err != nil { - logFunc(failHint) - return false - } - - logFunc("✓ dms-greeter package installed") - return true -} - -// CopyGreeterFiles installs the dms-greeter wrapper and sets up cache directory -func CopyGreeterFiles(dmsPath, compositor string, logFunc func(string), sudoPassword string) error { - if IsGreeterPackaged() { - logFunc("✓ dms-greeter package already installed") - } else { - if dmsPath == "" { - return fmt.Errorf("dms path is required for manual dms-greeter wrapper installs") - } - - assetsDir := filepath.Join(dmsPath, "Modules", "Greetd", "assets") - wrapperSrc := filepath.Join(assetsDir, "dms-greeter") - - if _, err := os.Stat(wrapperSrc); os.IsNotExist(err) { - return fmt.Errorf("dms-greeter wrapper not found at %s", wrapperSrc) - } - - wrapperDst := "/usr/local/bin/dms-greeter" - action := "Installed" - if info, err := os.Stat(wrapperDst); err == nil && !info.IsDir() { - action = "Updated" - } - if err := runSudoCmd(sudoPassword, "cp", wrapperSrc, wrapperDst); err != nil { - return fmt.Errorf("failed to copy dms-greeter wrapper: %w", err) - } - logFunc(fmt.Sprintf("✓ %s dms-greeter wrapper at %s", action, wrapperDst)) - - if err := runSudoCmd(sudoPassword, "chmod", "+x", wrapperDst); err != nil { - return fmt.Errorf("failed to make wrapper executable: %w", err) - } - - osInfo, err := distros.GetOSInfo() - if err == nil { - if config, exists := distros.Registry[osInfo.Distribution.ID]; exists && (config.Family == distros.FamilyFedora || config.Family == distros.FamilySUSE) { - if err := runSudoCmd(sudoPassword, "semanage", "fcontext", "-a", "-t", "bin_t", wrapperDst); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to set SELinux fcontext: %v", err)) - } else { - logFunc("✓ Set SELinux fcontext for dms-greeter") - } - - if err := runSudoCmd(sudoPassword, "restorecon", "-v", wrapperDst); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to restore SELinux context: %v", err)) - } else { - logFunc("✓ Restored SELinux context for dms-greeter") - } - } - } - } - - if err := EnsureGreeterCacheDir(logFunc, sudoPassword); err != nil { - return err - } - - return nil -} - -// EnsureGreeterCacheDir creates /var/cache/dms-greeter with correct ownership if it does not exist. -// It is safe to call multiple times (idempotent) and will repair ownership/mode -// when the directory already exists with stale permissions. -func EnsureGreeterCacheDir(logFunc func(string), sudoPassword string) error { - cacheDir := GreeterCacheDir - created := false - if info, err := os.Stat(cacheDir); err != nil { - if !os.IsNotExist(err) { - return fmt.Errorf("failed to stat cache directory: %w", err) - } - if err := runSudoCmd(sudoPassword, "mkdir", "-p", cacheDir); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - created = true - } else if !info.IsDir() { - return fmt.Errorf("cache path exists but is not a directory: %s", cacheDir) - } - - group := DetectGreeterGroup() - daemonUser := DetectGreeterUser() - preferredOwner := fmt.Sprintf("%s:%s", daemonUser, group) - owner := preferredOwner - if err := runSudoCmd(sudoPassword, "chown", owner, cacheDir); err != nil { - // Some setups may not have a matching daemon user at this moment; fall back - // to root: while still allowing group-writable greeter runtime access. - fallbackOwner := fmt.Sprintf("root:%s", group) - if fallbackErr := runSudoCmd(sudoPassword, "chown", fallbackOwner, cacheDir); fallbackErr != nil { - return fmt.Errorf("failed to set cache directory owner (preferred %s: %v; fallback %s: %w)", preferredOwner, err, fallbackOwner, fallbackErr) - } - owner = fallbackOwner - } - - if err := runSudoCmd(sudoPassword, "chmod", "2770", cacheDir); err != nil { - return fmt.Errorf("failed to set cache directory permissions: %w", err) - } - - runtimeDirs := []string{ - filepath.Join(cacheDir, ".local"), - filepath.Join(cacheDir, ".local", "state"), - filepath.Join(cacheDir, ".local", "share"), - filepath.Join(cacheDir, ".cache"), - } - for _, dir := range runtimeDirs { - if err := runSudoCmd(sudoPassword, "mkdir", "-p", dir); err != nil { - return fmt.Errorf("failed to create cache runtime directory %s: %w", dir, err) - } - if err := runSudoCmd(sudoPassword, "chown", owner, dir); err != nil { - return fmt.Errorf("failed to set owner for cache runtime directory %s: %w", dir, err) - } - if err := runSudoCmd(sudoPassword, "chmod", "2770", dir); err != nil { - return fmt.Errorf("failed to set permissions for cache runtime directory %s: %w", dir, err) - } - } - - legacyMemoryPath := filepath.Join(cacheDir, "memory.json") - stateMemoryPath := filepath.Join(cacheDir, ".local", "state", "memory.json") - if err := ensureGreeterMemoryCompatLink(logFunc, sudoPassword, legacyMemoryPath, stateMemoryPath); err != nil { - return err - } - - if isSELinuxEnforcing() && utils.CommandExists("restorecon") { - if err := runSudoCmd(sudoPassword, "restorecon", "-Rv", cacheDir); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to restore SELinux context for %s: %v", cacheDir, err)) - } - } - - if created { - logFunc(fmt.Sprintf("✓ Created cache directory %s (owner: %s, mode: 2770)", cacheDir, owner)) - } else { - logFunc(fmt.Sprintf("✓ Ensured cache directory %s permissions (owner: %s, mode: 2770)", cacheDir, owner)) - } - return nil -} - -func isSELinuxEnforcing() bool { - data, err := os.ReadFile("/sys/fs/selinux/enforce") - if err != nil { - return false - } - return strings.TrimSpace(string(data)) == "1" -} - -func ensureGreeterMemoryCompatLink(logFunc func(string), sudoPassword, legacyPath, statePath string) error { - info, err := os.Lstat(legacyPath) - if err == nil && info.Mode().IsRegular() { - if _, stateErr := os.Stat(statePath); os.IsNotExist(stateErr) { - if copyErr := runSudoCmd(sudoPassword, "cp", "-f", legacyPath, statePath); copyErr != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to migrate legacy greeter memory file to %s: %v", statePath, copyErr)) - } - } - } - - if err := runSudoCmd(sudoPassword, "ln", "-sfn", statePath, legacyPath); err != nil { - return fmt.Errorf("failed to create greeter memory compatibility symlink %s -> %s: %w", legacyPath, statePath, err) - } - - return nil -} - -// IsAppArmorEnabled reports whether AppArmor is active on the running kernel. -func IsAppArmorEnabled() bool { - data, err := os.ReadFile("/sys/module/apparmor/parameters/enabled") - if err != nil { - return false - } - return strings.HasPrefix(strings.TrimSpace(strings.ToLower(string(data))), "y") -} - -// InstallAppArmorProfile installs the bundled AppArmor profile and reloads it. No-op on NixOS or non-AppArmor systems. -func InstallAppArmorProfile(logFunc func(string), sudoPassword string) error { - if IsNixOS() { - logFunc(" ℹ Skipping AppArmor profile on NixOS (manage via security.apparmor.policies)") - return nil - } - - if !IsAppArmorEnabled() { - return nil - } - - if err := runSudoCmd(sudoPassword, "mkdir", "-p", "/etc/apparmor.d"); err != nil { - return fmt.Errorf("failed to create /etc/apparmor.d: %w", err) - } - - tmp, err := os.CreateTemp("", "dms-apparmor-*") - if err != nil { - return fmt.Errorf("failed to create temp file for AppArmor profile: %w", err) - } - tmpPath := tmp.Name() - defer os.Remove(tmpPath) - - if _, err := tmp.Write(appArmorProfileData); err != nil { - tmp.Close() - return fmt.Errorf("failed to write AppArmor profile: %w", err) - } - tmp.Close() - - if err := runSudoCmd(sudoPassword, "cp", tmpPath, appArmorProfileDest); err != nil { - return fmt.Errorf("failed to install AppArmor profile to %s: %w", appArmorProfileDest, err) - } - if err := runSudoCmd(sudoPassword, "chmod", "644", appArmorProfileDest); err != nil { - return fmt.Errorf("failed to set AppArmor profile permissions: %w", err) - } - - if utils.CommandExists("apparmor_parser") { - if err := runSudoCmd(sudoPassword, "apparmor_parser", "-r", appArmorProfileDest); err != nil { - logFunc(fmt.Sprintf(" ⚠ AppArmor profile installed but reload failed: %v", err)) - logFunc(" Run: sudo apparmor_parser -r " + appArmorProfileDest) - } else { - logFunc(" ✓ AppArmor profile installed and loaded (complain mode)") - } - } else { - logFunc(" ✓ AppArmor profile installed at " + appArmorProfileDest) - logFunc(" apparmor_parser not found — profile will be loaded on next boot") - } - - return nil -} - -// UninstallAppArmorProfile removes the DMS AppArmor profile and reloads AppArmor. -// It is a no-op when AppArmor is not active or the profile does not exist. -func UninstallAppArmorProfile(logFunc func(string), sudoPassword string) error { - if IsNixOS() { - return nil - } - if _, err := os.Stat("/sys/module/apparmor"); os.IsNotExist(err) { - return nil - } - if _, err := os.Stat(appArmorProfileDest); os.IsNotExist(err) { - return nil - } - - if utils.CommandExists("apparmor_parser") { - _ = runSudoCmd(sudoPassword, "apparmor_parser", "--remove", appArmorProfileDest) - } - if err := runSudoCmd(sudoPassword, "rm", "-f", appArmorProfileDest); err != nil { - return fmt.Errorf("failed to remove AppArmor profile: %w", err) - } - logFunc(" ✓ Removed DMS AppArmor profile") - return nil -} - -// EnsureACLInstalled installs the acl package (setfacl/getfacl) if not already present -func EnsureACLInstalled(logFunc func(string), sudoPassword string) error { - if utils.CommandExists("setfacl") { - return nil - } - - logFunc("setfacl not found – installing acl package...") - - osInfo, err := distros.GetOSInfo() - if err != nil { - return fmt.Errorf("failed to detect OS: %w", err) - } - - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return fmt.Errorf("unsupported distribution for automatic acl installation: %s", osInfo.Distribution.ID) - } - - ctx := context.Background() - var installCmd *exec.Cmd - - switch config.Family { - case distros.FamilyArch: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "pacman -S --needed --noconfirm acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "pacman", "-S", "--needed", "--noconfirm", "acl") - } - - case distros.FamilyFedora: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "dnf install -y acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "dnf", "install", "-y", "acl") - } - - case distros.FamilySUSE: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "zypper install -y acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "zypper", "install", "-y", "acl") - } - - case distros.FamilyUbuntu: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "apt-get install -y acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "acl") - } - - case distros.FamilyDebian: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "apt-get install -y acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "acl") - } - - case distros.FamilyGentoo: - if sudoPassword != "" { - installCmd = distros.ExecSudoCommand(ctx, sudoPassword, "emerge --ask n sys-fs/acl") - } else { - installCmd = exec.CommandContext(ctx, "sudo", "emerge", "--ask", "n", "sys-fs/acl") - } - - case distros.FamilyNix: - return fmt.Errorf("on NixOS, please add pkgs.acl to your configuration.nix") - - default: - return fmt.Errorf("unsupported distribution family for automatic acl installation: %s", config.Family) - } - - installCmd.Stdout = os.Stdout - installCmd.Stderr = os.Stderr - if err := installCmd.Run(); err != nil { - return fmt.Errorf("failed to install acl: %w", err) - } - - logFunc("✓ acl package installed") - return nil -} - -// SetupParentDirectoryACLs sets ACLs on parent directories to allow traversal -func SetupParentDirectoryACLs(logFunc func(string), sudoPassword string) error { - if err := EnsureACLInstalled(logFunc, sudoPassword); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: could not install acl package: %v", err)) - logFunc(" ACL permissions will be skipped; theme sync may not work correctly.") - return nil - } - if !utils.CommandExists("setfacl") { - logFunc("⚠ Warning: setfacl still not available after install attempt; skipping ACL setup.") - return nil - } - - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - parentDirs := []struct { - path string - desc string - }{ - {homeDir, "home directory"}, - {filepath.Join(homeDir, ".config"), ".config directory"}, - {filepath.Join(homeDir, ".local"), ".local directory"}, - {filepath.Join(homeDir, ".cache"), ".cache directory"}, - {filepath.Join(homeDir, ".local", "state"), ".local/state directory"}, - {filepath.Join(homeDir, ".local", "share"), ".local/share directory"}, - } - - group := DetectGreeterGroup() - - logFunc("\nSetting up parent directory ACLs for greeter user access...") - - for _, dir := range parentDirs { - if _, err := os.Stat(dir.path); os.IsNotExist(err) { - if err := os.MkdirAll(dir.path, 0o755); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Could not create %s: %v", dir.desc, err)) - continue - } - } - - // Group ACL covers daemon users regardless of username (e.g. greetd ≠ greeter on Fedora). - if err := runSudoCmd(sudoPassword, "setfacl", "-m", fmt.Sprintf("g:%s:rX", group), dir.path); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to set ACL on %s: %v", dir.desc, err)) - logFunc(fmt.Sprintf(" You may need to run manually: setfacl -m g:%s:rX %s", group, dir.path)) - continue - } - - logFunc(fmt.Sprintf("✓ Set ACL on %s", dir.desc)) - } - - return nil -} - -// RemediateStaleACLs removes user-based ACLs left by older binary versions. Best-effort. -func RemediateStaleACLs(logFunc func(string), sudoPassword string) { - if !utils.CommandExists("setfacl") { - return - } - - homeDir, err := os.UserHomeDir() - if err != nil { - return - } - - passwdData, err := os.ReadFile("/etc/passwd") - if err != nil { - return - } - - dirs := []string{ - homeDir, - filepath.Join(homeDir, ".config"), - filepath.Join(homeDir, ".config", "DankMaterialShell"), - filepath.Join(homeDir, ".cache"), - filepath.Join(homeDir, ".cache", "DankMaterialShell"), - filepath.Join(homeDir, ".local"), - filepath.Join(homeDir, ".local", "state"), - filepath.Join(homeDir, ".local", "share"), - } - - passwdContent := string(passwdData) - staleUsers := []string{"greeter", "greetd", "_greeter"} - existingUsers := make([]string, 0, len(staleUsers)) - for _, user := range staleUsers { - if hasPasswdUser(passwdContent, user) { - existingUsers = append(existingUsers, user) - } - } - if len(existingUsers) == 0 { - return - } - - cleaned := false - for _, dir := range dirs { - if _, err := os.Stat(dir); err != nil { - continue - } - for _, user := range existingUsers { - _ = runSudoCmd(sudoPassword, "setfacl", "-x", fmt.Sprintf("u:%s", user), dir) - cleaned = true - } - } - if cleaned { - logFunc("✓ Cleaned up stale user-based ACLs from previous versions") - } -} - -// RemediateStaleAppArmor removes any AppArmor profile installed by an older binary on -// systems where AppArmor is not active. -func RemediateStaleAppArmor(logFunc func(string), sudoPassword string) { - if IsAppArmorEnabled() { - return - } - if _, err := os.Stat(appArmorProfileDest); os.IsNotExist(err) { - return - } - logFunc("ℹ Removing stale AppArmor profile (AppArmor is not active on this system)") - _ = UninstallAppArmorProfile(logFunc, sudoPassword) -} - -func SetupDMSGroup(logFunc func(string), sudoPassword string) error { - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - currentUser := os.Getenv("USER") - if currentUser == "" { - currentUser = os.Getenv("LOGNAME") - } - if currentUser == "" { - return fmt.Errorf("failed to determine current user") - } - - group := DetectGreeterGroup() - - // Create the group if it doesn't exist yet (e.g. before greetd package is installed). - if !utils.HasGroup(group) { - if err := runSudoCmd(sudoPassword, "groupadd", "-r", group); err != nil { - return fmt.Errorf("failed to create %s group: %w", group, err) - } - logFunc(fmt.Sprintf("✓ Created system group %s", group)) - } - - groupsCmd := exec.Command("groups", currentUser) - groupsOutput, err := groupsCmd.Output() - if err == nil && strings.Contains(string(groupsOutput), group) { - logFunc(fmt.Sprintf("✓ %s is already in %s group", currentUser, group)) - } else { - if err := runSudoCmd(sudoPassword, "usermod", "-aG", group, currentUser); err != nil { - return fmt.Errorf("failed to add %s to %s group: %w", currentUser, group, err) - } - logFunc(fmt.Sprintf("✓ Added %s to %s group (logout/login required for changes to take effect)", currentUser, group)) - } - - // Also add the daemon user (e.g. greetd on Fedora) so group ACLs apply to the running process. - daemonUser := DetectGreeterUser() - if daemonUser != currentUser { - daemonGroupsCmd := exec.Command("groups", daemonUser) - daemonGroupsOutput, daemonGroupsErr := daemonGroupsCmd.Output() - if daemonGroupsErr == nil { - if strings.Contains(string(daemonGroupsOutput), group) { - logFunc(fmt.Sprintf("✓ Greeter daemon user %s is already in %s group", daemonUser, group)) - } else { - if err := runSudoCmd(sudoPassword, "usermod", "-aG", group, daemonUser); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: could not add %s to %s group: %v", daemonUser, group, err)) - } else { - logFunc(fmt.Sprintf("✓ Added greeter daemon user %s to %s group", daemonUser, group)) - } - } - } - } - - configDirs := []struct { - path string - desc string - }{ - {filepath.Join(homeDir, ".config", "DankMaterialShell"), "DankMaterialShell config"}, - {filepath.Join(homeDir, ".local", "state", "DankMaterialShell"), "DankMaterialShell state"}, - {filepath.Join(homeDir, ".cache", "DankMaterialShell"), "DankMaterialShell cache"}, - {filepath.Join(homeDir, ".cache", "quickshell"), "quickshell cache"}, - {filepath.Join(homeDir, ".config", "quickshell"), "quickshell config"}, - {filepath.Join(homeDir, ".local", "share", "wayland-sessions"), "wayland sessions"}, - {filepath.Join(homeDir, ".local", "share", "xsessions"), "xsessions"}, - } - - for _, dir := range configDirs { - if _, err := os.Stat(dir.path); os.IsNotExist(err) { - if err := os.MkdirAll(dir.path, 0o755); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Could not create %s: %v", dir.path, err)) - continue - } - } - - if err := runSudoCmd(sudoPassword, "chgrp", "-R", group, dir.path); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to set group for %s: %v", dir.desc, err)) - continue - } - - if err := runSudoCmd(sudoPassword, "chmod", "-R", "g+rX", dir.path); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to set permissions for %s: %v", dir.desc, err)) - continue - } - - logFunc(fmt.Sprintf("✓ Set group permissions for %s", dir.desc)) - } - - if err := SetupParentDirectoryACLs(logFunc, sudoPassword); err != nil { - return fmt.Errorf("failed to setup parent directory ACLs: %w", err) - } - - return nil -} - -type GreeterColorSyncInfo struct { - SourcePath string - ThemeName string - UsesDynamicWallpaperOverride bool -} - -type greeterThemeSyncSettings struct { - CurrentThemeName string `json:"currentThemeName"` - GreeterWallpaperPath string `json:"greeterWallpaperPath"` - MatugenScheme string `json:"matugenScheme"` - IconTheme string `json:"iconTheme"` -} - -type greeterThemeSyncSession struct { - IsLightMode bool `json:"isLightMode"` -} - -type greeterThemeSyncState struct { - ThemeName string - GreeterWallpaperPath string - ResolvedGreeterWallpaperPath string - MatugenScheme string - IconTheme string - IsLightMode bool - UsesDynamicWallpaperOverride bool -} - -func defaultGreeterColorsSource(homeDir string) string { - return filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json") -} - -func greeterOverrideColorsStateDir(homeDir string) string { - return filepath.Join(homeDir, ".cache", "DankMaterialShell", "greeter-colors") -} - -func greeterOverrideColorsSource(homeDir string) string { - return filepath.Join(greeterOverrideColorsStateDir(homeDir), "dms-colors.json") -} - -func readOptionalJSONFile(path string, dst any) error { - data, err := os.ReadFile(path) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - if strings.TrimSpace(string(data)) == "" { - return nil - } - return json.Unmarshal(data, dst) -} - -func readGreeterThemeSyncSettings(homeDir string) (greeterThemeSyncSettings, error) { - settings := greeterThemeSyncSettings{ - CurrentThemeName: "purple", - MatugenScheme: "scheme-tonal-spot", - IconTheme: "System Default", - } - settingsPath := filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json") - if err := readOptionalJSONFile(settingsPath, &settings); err != nil { - return greeterThemeSyncSettings{}, fmt.Errorf("failed to parse settings at %s: %w", settingsPath, err) - } - return settings, nil -} - -func readGreeterThemeSyncSession(homeDir string) (greeterThemeSyncSession, error) { - session := greeterThemeSyncSession{} - sessionPath := filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json") - if err := readOptionalJSONFile(sessionPath, &session); err != nil { - return greeterThemeSyncSession{}, fmt.Errorf("failed to parse session at %s: %w", sessionPath, err) - } - return session, nil -} - -func resolveGreeterThemeSyncState(homeDir string) (greeterThemeSyncState, error) { - settings, err := readGreeterThemeSyncSettings(homeDir) - if err != nil { - return greeterThemeSyncState{}, err - } - session, err := readGreeterThemeSyncSession(homeDir) - if err != nil { - return greeterThemeSyncState{}, err - } - - resolvedWallpaperPath := "" - if settings.GreeterWallpaperPath != "" { - resolvedWallpaperPath = settings.GreeterWallpaperPath - if !filepath.IsAbs(resolvedWallpaperPath) { - resolvedWallpaperPath = filepath.Join(homeDir, resolvedWallpaperPath) - } - } - - usesDynamicWallpaperOverride := strings.EqualFold(strings.TrimSpace(settings.CurrentThemeName), "dynamic") && resolvedWallpaperPath != "" - - return greeterThemeSyncState{ - ThemeName: settings.CurrentThemeName, - GreeterWallpaperPath: settings.GreeterWallpaperPath, - ResolvedGreeterWallpaperPath: resolvedWallpaperPath, - MatugenScheme: settings.MatugenScheme, - IconTheme: settings.IconTheme, - IsLightMode: session.IsLightMode, - UsesDynamicWallpaperOverride: usesDynamicWallpaperOverride, - }, nil -} - -func (s greeterThemeSyncState) effectiveColorsSource(homeDir string) string { - if s.UsesDynamicWallpaperOverride { - return greeterOverrideColorsSource(homeDir) - } - return defaultGreeterColorsSource(homeDir) -} - -func ResolveGreeterColorSyncInfo(homeDir string) (GreeterColorSyncInfo, error) { - state, err := resolveGreeterThemeSyncState(homeDir) - if err != nil { - return GreeterColorSyncInfo{}, err - } - return GreeterColorSyncInfo{ - SourcePath: state.effectiveColorsSource(homeDir), - ThemeName: state.ThemeName, - UsesDynamicWallpaperOverride: state.UsesDynamicWallpaperOverride, - }, nil -} - -func ensureGreeterSyncSourceFile(path string) error { - sourceDir := filepath.Dir(path) - if err := os.MkdirAll(sourceDir, 0o755); err != nil { - return fmt.Errorf("failed to create source directory %s: %w", sourceDir, err) - } - - if _, err := os.Stat(path); os.IsNotExist(err) { - if err := os.WriteFile(path, []byte("{}"), 0o644); err != nil { - return fmt.Errorf("failed to create source file %s: %w", path, err) - } - } else if err != nil { - return fmt.Errorf("failed to inspect source file %s: %w", path, err) - } - - return nil -} - -func syncGreeterDynamicOverrideColors(dmsPath, homeDir string, state greeterThemeSyncState, logFunc func(string)) error { - if !state.UsesDynamicWallpaperOverride { - return nil - } - - st, err := os.Stat(state.ResolvedGreeterWallpaperPath) - if err != nil { - return fmt.Errorf("configured greeter wallpaper not found at %s: %w", state.ResolvedGreeterWallpaperPath, err) - } - if st.IsDir() { - return fmt.Errorf("configured greeter wallpaper path points to a directory: %s", state.ResolvedGreeterWallpaperPath) - } - - mode := matugen.ColorModeDark - if state.IsLightMode { - mode = matugen.ColorModeLight - } - - opts := matugen.Options{ - StateDir: greeterOverrideColorsStateDir(homeDir), - ShellDir: dmsPath, - ConfigDir: filepath.Join(homeDir, ".config"), - Kind: "image", - Value: state.ResolvedGreeterWallpaperPath, - Mode: mode, - IconTheme: state.IconTheme, - MatugenType: state.MatugenScheme, - RunUserTemplates: false, - ColorsOnly: true, - } - - err = matugen.Run(opts) - switch { - case errors.Is(err, matugen.ErrNoChanges): - logFunc("✓ Greeter dynamic override colors already up to date") - return nil - case err != nil: - return fmt.Errorf("failed to generate greeter dynamic colors from wallpaper override: %w", err) - default: - logFunc("✓ Generated greeter dynamic colors from wallpaper override") - return nil - } -} - -func syncGreeterColorSource(homeDir, cacheDir string, state greeterThemeSyncState, logFunc func(string), sudoPassword string) error { - source := state.effectiveColorsSource(homeDir) - if !state.UsesDynamicWallpaperOverride { - if err := ensureGreeterSyncSourceFile(source); err != nil { - return err - } - } else if _, err := os.Stat(source); err != nil { - return fmt.Errorf("expected generated greeter colors at %s: %w", source, err) - } - - target := filepath.Join(cacheDir, "colors.json") - _ = runSudoCmd(sudoPassword, "rm", "-f", target) - if err := runSudoCmd(sudoPassword, "ln", "-sf", source, target); err != nil { - return fmt.Errorf("failed to create symlink for wallpaper based theming (%s -> %s): %w", target, source, err) - } - - if state.UsesDynamicWallpaperOverride { - logFunc("✓ Synced wallpaper based theming (greeter wallpaper override)") - } else { - logFunc("✓ Synced wallpaper based theming") - } - - return nil -} - -func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string) error { - homeDir, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - - cacheDir := GreeterCacheDir - - symlinks := []struct { - source string - target string - desc string - }{ - { - source: filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"), - target: filepath.Join(cacheDir, "settings.json"), - desc: "core settings (theme, clock formats, etc)", - }, - { - source: filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"), - target: filepath.Join(cacheDir, "session.json"), - desc: "state (wallpaper configuration)", - }, - } - - for _, link := range symlinks { - sourceDir := filepath.Dir(link.source) - if _, err := os.Stat(sourceDir); os.IsNotExist(err) { - if err := os.MkdirAll(sourceDir, 0o755); err != nil { - return fmt.Errorf("failed to create source directory %s for %s: %w", sourceDir, link.desc, err) - } - } - - if _, err := os.Stat(link.source); os.IsNotExist(err) { - if err := os.WriteFile(link.source, []byte("{}"), 0o644); err != nil { - return fmt.Errorf("failed to create source file %s for %s: %w", link.source, link.desc, err) - } - } - - _ = runSudoCmd(sudoPassword, "rm", "-f", link.target) - - if err := runSudoCmd(sudoPassword, "ln", "-sf", link.source, link.target); err != nil { - return fmt.Errorf("failed to create symlink for %s (%s -> %s): %w", link.desc, link.target, link.source, err) - } - - logFunc(fmt.Sprintf("✓ Synced %s", link.desc)) - } - - state, err := resolveGreeterThemeSyncState(homeDir) - if err != nil { - return fmt.Errorf("failed to resolve greeter color source: %w", err) - } - - if err := syncGreeterDynamicOverrideColors(dmsPath, homeDir, state, logFunc); err != nil { - return err - } - - if err := syncGreeterColorSource(homeDir, cacheDir, state, logFunc, sudoPassword); err != nil { - return err - } - - if err := syncGreeterWallpaperOverride(cacheDir, logFunc, sudoPassword, state); err != nil { - return fmt.Errorf("greeter wallpaper override sync failed: %w", err) - } - - if strings.ToLower(compositor) != "niri" { - return nil - } - - if err := syncNiriGreeterConfig(logFunc, sudoPassword); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to sync niri greeter config: %v", err)) - } - - return nil -} - -func syncGreeterWallpaperOverride(cacheDir string, logFunc func(string), sudoPassword string, state greeterThemeSyncState) error { - destPath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg") - if state.ResolvedGreeterWallpaperPath == "" { - if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil { - return fmt.Errorf("failed to clear override file %s: %w", destPath, err) - } - logFunc("✓ Cleared greeter wallpaper override") - return nil - } - if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil { - return fmt.Errorf("failed to remove old override file %s: %w", destPath, err) - } - src := state.ResolvedGreeterWallpaperPath - st, err := os.Stat(src) - if err != nil { - return fmt.Errorf("configured greeter wallpaper not found at %s: %w", src, err) - } - if st.IsDir() { - return fmt.Errorf("configured greeter wallpaper path points to a directory: %s", src) - } - if err := runSudoCmd(sudoPassword, "cp", src, destPath); err != nil { - return fmt.Errorf("failed to copy override wallpaper to %s: %w", destPath, err) - } - greeterGroup := DetectGreeterGroup() - daemonUser := DetectGreeterUser() - if err := runSudoCmd(sudoPassword, "chown", daemonUser+":"+greeterGroup, destPath); err != nil { - if fallbackErr := runSudoCmd(sudoPassword, "chown", "root:"+greeterGroup, destPath); fallbackErr != nil { - return fmt.Errorf("failed to set override ownership on %s: %w", destPath, err) - } - } - if err := runSudoCmd(sudoPassword, "chmod", "644", destPath); err != nil { - return fmt.Errorf("failed to set override permissions on %s: %w", destPath, err) - } - logFunc("✓ Synced greeter wallpaper override") - return nil -} - -type niriGreeterSync struct { - processed map[string]bool - nodes []*document.Node - inputCount int - outputCount int - cursorCount int - debugCount int - cursorNode *document.Node - inputNode *document.Node - outputNodes map[string]*document.Node -} - -func syncNiriGreeterConfig(logFunc func(string), sudoPassword string) error { - configDir, err := os.UserConfigDir() - if err != nil { - return fmt.Errorf("failed to resolve user config directory: %w", err) - } - - configPath := filepath.Join(configDir, "niri", "config.kdl") - if _, err := os.Stat(configPath); os.IsNotExist(err) { - logFunc("ℹ Niri config not found; skipping greeter niri sync") - return nil - } else if err != nil { - return fmt.Errorf("failed to stat niri config: %w", err) - } - - extractor := &niriGreeterSync{ - processed: make(map[string]bool), - outputNodes: make(map[string]*document.Node), - } - - if err := extractor.processFile(configPath); err != nil { - return err - } - - if len(extractor.nodes) == 0 { - logFunc("ℹ No niri input/output sections found; skipping greeter niri sync") - return nil - } - - content := extractor.render() - if strings.TrimSpace(content) == "" { - logFunc("ℹ No niri input/output content to sync; skipping greeter niri sync") - return nil - } - - greeterDir := "/etc/greetd/niri" - greeterGroup := DetectGreeterGroup() - if err := runSudoCmd(sudoPassword, "mkdir", "-p", greeterDir); err != nil { - return fmt.Errorf("failed to create greetd niri directory: %w", err) - } - if err := runSudoCmd(sudoPassword, "chown", fmt.Sprintf("root:%s", greeterGroup), greeterDir); err != nil { - return fmt.Errorf("failed to set greetd niri directory ownership: %w", err) - } - if err := runSudoCmd(sudoPassword, "chmod", "755", greeterDir); err != nil { - return fmt.Errorf("failed to set greetd niri directory permissions: %w", err) - } - - dmsTemp, err := os.CreateTemp("", "dms-greeter-niri-dms-*.kdl") - if err != nil { - return fmt.Errorf("failed to create temp file: %w", err) - } - defer os.Remove(dmsTemp.Name()) - - if _, err := dmsTemp.WriteString(content); err != nil { - _ = dmsTemp.Close() - return fmt.Errorf("failed to write temp niri config: %w", err) - } - if err := dmsTemp.Close(); err != nil { - return fmt.Errorf("failed to close temp niri config: %w", err) - } - - dmsPath := filepath.Join(greeterDir, "dms.kdl") - if err := backupFileIfExists(sudoPassword, dmsPath, ".backup"); err != nil { - return fmt.Errorf("failed to backup %s: %w", dmsPath, err) - } - if err := runSudoCmd(sudoPassword, "install", "-o", "root", "-g", greeterGroup, "-m", "0644", dmsTemp.Name(), dmsPath); err != nil { - return fmt.Errorf("failed to install greetd niri dms config: %w", err) - } - - mainContent := fmt.Sprintf("%s\ninclude \"%s\"\n", config.NiriGreeterConfig, dmsPath) - mainTemp, err := os.CreateTemp("", "dms-greeter-niri-main-*.kdl") - if err != nil { - return fmt.Errorf("failed to create temp file: %w", err) - } - defer os.Remove(mainTemp.Name()) - - if _, err := mainTemp.WriteString(mainContent); err != nil { - _ = mainTemp.Close() - return fmt.Errorf("failed to write temp niri main config: %w", err) - } - if err := mainTemp.Close(); err != nil { - return fmt.Errorf("failed to close temp niri main config: %w", err) - } - - mainPath := filepath.Join(greeterDir, "config.kdl") - if err := backupFileIfExists(sudoPassword, mainPath, ".backup"); err != nil { - return fmt.Errorf("failed to backup %s: %w", mainPath, err) - } - if err := runSudoCmd(sudoPassword, "install", "-o", "root", "-g", greeterGroup, "-m", "0644", mainTemp.Name(), mainPath); err != nil { - return fmt.Errorf("failed to install greetd niri main config: %w", err) - } - - if err := ensureGreetdNiriConfig(logFunc, sudoPassword, mainPath); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to update greetd config for niri: %v", err)) - } - - logFunc(fmt.Sprintf("✓ Synced niri greeter config (%d input, %d output, %d cursor, %d debug) to %s", extractor.inputCount, extractor.outputCount, extractor.cursorCount, extractor.debugCount, dmsPath)) - return nil -} - -func ensureGreetdNiriConfig(logFunc func(string), sudoPassword string, niriConfigPath string) error { - configPath := "/etc/greetd/config.toml" - data, err := os.ReadFile(configPath) - if os.IsNotExist(err) { - logFunc("ℹ greetd config not found; skipping niri config wiring") - return nil - } - if err != nil { - return fmt.Errorf("failed to read greetd config: %w", err) - } - - lines := strings.Split(string(data), "\n") - updated := false - for i, line := range lines { - trimmed := strings.TrimSpace(line) - if !strings.HasPrefix(trimmed, "command") { - continue - } - - parts := strings.SplitN(trimmed, "=", 2) - if len(parts) != 2 { - continue - } - - command := strings.Trim(strings.TrimSpace(parts[1]), "\"") - if !strings.Contains(command, "dms-greeter") { - continue - } - if !strings.Contains(command, "--command niri") { - continue - } - command = stripConfigFlag(command) - command = stripCacheDirFlag(command) - command = strings.TrimSpace(command + " --cache-dir " + GreeterCacheDir) - - newCommand := fmt.Sprintf("%s -C %s", command, niriConfigPath) - idx := strings.Index(line, "command") - leading := "" - if idx > 0 { - leading = line[:idx] - } - lines[i] = fmt.Sprintf("%scommand = \"%s\"", leading, newCommand) - updated = true - break - } - - if !updated { - return nil - } - - tmpFile, err := os.CreateTemp("", "greetd-config-*.toml") - if err != nil { - return fmt.Errorf("failed to create temp greetd config: %w", err) - } - defer os.Remove(tmpFile.Name()) - - if _, err := tmpFile.WriteString(strings.Join(lines, "\n")); err != nil { - _ = tmpFile.Close() - return fmt.Errorf("failed to write temp greetd config: %w", err) - } - if err := tmpFile.Close(); err != nil { - return fmt.Errorf("failed to close temp greetd config: %w", err) - } - - if err := runSudoCmd(sudoPassword, "mv", tmpFile.Name(), configPath); err != nil { - return fmt.Errorf("failed to update greetd config: %w", err) - } - - logFunc(fmt.Sprintf("✓ Updated greetd config to use niri config %s", niriConfigPath)) - return nil -} - -func backupFileIfExists(sudoPassword string, path string, suffix string) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - backupPath := fmt.Sprintf("%s%s-%s", path, suffix, time.Now().Format("20060102-150405")) - if err := runSudoCmd(sudoPassword, "cp", path, backupPath); err != nil { - return err - } - return runSudoCmd(sudoPassword, "chmod", "644", backupPath) -} - -func (s *niriGreeterSync) processFile(filePath string) error { - absPath, err := filepath.Abs(filePath) - if err != nil { - return fmt.Errorf("failed to resolve path %s: %w", filePath, err) - } - - if s.processed[absPath] { - return nil - } - s.processed[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return fmt.Errorf("failed to read %s: %w", absPath, err) - } - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return fmt.Errorf("failed to parse KDL in %s: %w", absPath, err) - } - - baseDir := filepath.Dir(absPath) - for _, node := range doc.Nodes { - name := node.Name.String() - switch name { - case "include": - if err := s.handleInclude(node, baseDir); err != nil { - return err - } - case "input": - if s.inputNode == nil { - s.inputNode = node - s.inputNode.Children = dedupeCursorChildren(s.inputNode.Children) - s.nodes = append(s.nodes, node) - } else if len(node.Children) > 0 { - s.inputNode.Children = mergeInputChildren(s.inputNode.Children, node.Children) - } - s.inputCount++ - case "output": - key := outputNodeKey(node) - if existing, ok := s.outputNodes[key]; ok { - *existing = *node - } else { - s.outputNodes[key] = node - s.nodes = append(s.nodes, node) - } - s.outputCount++ - case "cursor": - if s.cursorNode == nil { - s.cursorNode = node - s.cursorNode.Children = dedupeCursorChildren(s.cursorNode.Children) - s.nodes = append(s.nodes, node) - s.cursorCount++ - } else if len(node.Children) > 0 { - s.cursorNode.Children = mergeCursorChildren(s.cursorNode.Children, node.Children) - } - case "debug": - s.nodes = append(s.nodes, node) - s.debugCount++ - } - } - - return nil -} - -func mergeCursorChildren(existing []*document.Node, incoming []*document.Node) []*document.Node { - if len(incoming) == 0 { - return existing - } - - indexByName := make(map[string]int, len(existing)) - for i, child := range existing { - indexByName[child.Name.String()] = i - } - - for _, child := range incoming { - name := child.Name.String() - if idx, ok := indexByName[name]; ok { - existing[idx] = child - continue - } - indexByName[name] = len(existing) - existing = append(existing, child) - } - - return existing -} - -func dedupeCursorChildren(children []*document.Node) []*document.Node { - if len(children) == 0 { - return children - } - - var result []*document.Node - indexByName := make(map[string]int, len(children)) - for _, child := range children { - name := child.Name.String() - if idx, ok := indexByName[name]; ok { - result[idx] = child - continue - } - indexByName[name] = len(result) - result = append(result, child) - } - - return result -} - -func mergeInputChildren(existing []*document.Node, incoming []*document.Node) []*document.Node { - if len(incoming) == 0 { - return existing - } - - indexByName := make(map[string]int, len(existing)) - for i, child := range existing { - indexByName[child.Name.String()] = i - } - - for _, child := range incoming { - name := child.Name.String() - if idx, ok := indexByName[name]; ok { - existing[idx] = child - continue - } - indexByName[name] = len(existing) - existing = append(existing, child) - } - - return existing -} - -func outputNodeKey(node *document.Node) string { - if len(node.Arguments) > 0 { - return strings.Trim(node.Arguments[0].String(), "\"") - } - return "" -} - -func (s *niriGreeterSync) handleInclude(node *document.Node, baseDir string) error { - if len(node.Arguments) == 0 { - return nil - } - - includePath := strings.Trim(node.Arguments[0].String(), "\"") - if includePath == "" { - return nil - } - - fullPath := includePath - if !filepath.IsAbs(includePath) { - fullPath = filepath.Join(baseDir, includePath) - } - - if _, err := os.Stat(fullPath); os.IsNotExist(err) { - return nil - } else if err != nil { - return fmt.Errorf("failed to stat include %s: %w", fullPath, err) - } - - return s.processFile(fullPath) -} - -func (s *niriGreeterSync) render() string { - if len(s.nodes) == 0 { - return "" - } - - var builder strings.Builder - for _, node := range s.nodes { - _, _ = node.WriteToOptions(&builder, document.NodeWriteOptions{ - LeadingTrailingSpace: true, - NameAndType: true, - Depth: 0, - Indent: []byte(" "), - IgnoreFlags: false, - }) - builder.WriteString("\n") - } - - return builder.String() -} - -func ConfigureGreetd(dmsPath, compositor string, logFunc func(string), sudoPassword string) error { - configPath := "/etc/greetd/config.toml" - - backupPath := fmt.Sprintf("%s.backup-%s", configPath, time.Now().Format("20060102-150405")) - if err := backupFileIfExists(sudoPassword, configPath, ".backup"); err != nil { - return fmt.Errorf("failed to backup greetd config: %w", err) - } - if _, err := os.Stat(configPath); err == nil { - logFunc(fmt.Sprintf("✓ Backed up existing config to %s", backupPath)) - } - - greeterUser := DetectGreeterUser() - - var configContent string - if data, err := os.ReadFile(configPath); err == nil { - configContent = string(data) - } else if os.IsNotExist(err) { - configContent = `[terminal] -vt = 1 - -[default_session] -` - } else { - return fmt.Errorf("failed to read greetd config: %w", err) - } - - wrapperCmd := resolveGreeterWrapperPath() - - compositorLower := strings.ToLower(compositor) - commandValue := fmt.Sprintf("%s --command %s --cache-dir %s", wrapperCmd, compositorLower, GreeterCacheDir) - if dmsPath != "" { - commandValue = fmt.Sprintf("%s -p %s", commandValue, dmsPath) - } - - commandLine := fmt.Sprintf(`command = "%s"`, commandValue) - newConfig := upsertDefaultSession(configContent, greeterUser, commandLine) - - tmpFile, err := os.CreateTemp("", "greetd-config-*.toml") - if err != nil { - return fmt.Errorf("failed to create temp greetd config: %w", err) - } - defer os.Remove(tmpFile.Name()) - - if _, err := tmpFile.WriteString(newConfig); err != nil { - _ = tmpFile.Close() - return fmt.Errorf("failed to write temp greetd config: %w", err) - } - if err := tmpFile.Close(); err != nil { - return fmt.Errorf("failed to close temp greetd config: %w", err) - } - - if err := runSudoCmd(sudoPassword, "mkdir", "-p", "/etc/greetd"); err != nil { - return fmt.Errorf("failed to create /etc/greetd: %w", err) - } - - if err := runSudoCmd(sudoPassword, "install", "-o", "root", "-g", "root", "-m", "0644", tmpFile.Name(), configPath); err != nil { - return fmt.Errorf("failed to install greetd config: %w", err) - } - - logFunc(fmt.Sprintf("✓ Updated greetd configuration (user: %s, command: %s)", greeterUser, commandValue)) - return nil -} - -func stripConfigFlag(command string) string { - for _, flag := range []string{" -C ", " --config "} { - idx := strings.Index(command, flag) - if idx == -1 { - continue - } - - before := command[:idx] - after := command[idx+len(flag):] - - switch { - case strings.HasPrefix(after, `"`): - if end := strings.Index(after[1:], `"`); end != -1 { - after = after[end+2:] - } else { - after = "" - } - default: - if space := strings.Index(after, " "); space != -1 { - after = after[space:] - } else { - after = "" - } - } - - command = strings.TrimSpace(before + after) - } - - return command -} - -func stripCacheDirFlag(command string) string { - fields := strings.Fields(command) - if len(fields) == 0 { - return strings.TrimSpace(command) - } - - filtered := make([]string, 0, len(fields)) - for i := 0; i < len(fields); i++ { - token := fields[i] - if token == "--cache-dir" { - if i+1 < len(fields) { - i++ - } - continue - } - if strings.HasPrefix(token, "--cache-dir=") { - continue - } - filtered = append(filtered, token) - } - - return strings.Join(filtered, " ") -} - -// getDebianOBSSlug returns the OBS repository slug for the running Debian version. -func getDebianOBSSlug(osInfo *distros.OSInfo) string { - versionID := strings.ToLower(osInfo.VersionID) - codename := strings.ToLower(osInfo.VersionCodename) - prettyName := strings.ToLower(osInfo.PrettyName) - - if strings.Contains(prettyName, "sid") || strings.Contains(prettyName, "unstable") || - codename == "sid" || versionID == "sid" { - return "Debian_Unstable" - } - if versionID == "testing" || codename == "testing" { - return "Debian_Testing" - } - if versionID != "" { - return "Debian_" + versionID // "Debian_13" - } - return "Debian_Unstable" -} - -// getOpenSUSEOBSRepoURL returns the OBS .repo file URL for the running openSUSE variant. -func getOpenSUSEOBSRepoURL(osInfo *distros.OSInfo) string { - const base = "https://download.opensuse.org/repositories/home:AvengeMedia:danklinux" - var slug string - switch osInfo.Distribution.ID { - case "opensuse-leap": - v := osInfo.VersionID - if v != "" && !strings.Contains(v, ".") { - v += ".0" // "16" → "16.0" - } - if v == "" { - v = "16.0" - } - slug = v - case "opensuse-slowroll": - slug = "openSUSE_Slowroll" - default: // opensuse-tumbleweed || unknown version - slug = "openSUSE_Tumbleweed" - } - return fmt.Sprintf("%s/%s/home:AvengeMedia:danklinux.repo", base, slug) -} - -func runSudoCmd(sudoPassword string, command string, args ...string) error { - var cmd *exec.Cmd - - if sudoPassword != "" { - fullArgs := append([]string{command}, args...) - quotedArgs := make([]string, len(fullArgs)) - for i, arg := range fullArgs { - quotedArgs[i] = "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'" - } - cmdStr := strings.Join(quotedArgs, " ") - - cmd = distros.ExecSudoCommand(context.Background(), sudoPassword, cmdStr) - } else { - cmd = exec.Command("sudo", append([]string{command}, args...)...) - } - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - -func checkSystemdEnabled(service string) (string, error) { - cmd := exec.Command("systemctl", "is-enabled", service) - output, _ := cmd.Output() - return strings.TrimSpace(string(output)), nil -} - -func DisableConflictingDisplayManagers(sudoPassword string, logFunc func(string)) error { - conflictingDMs := []string{"gdm", "gdm3", "lightdm", "sddm", "lxdm", "xdm", "cosmic-greeter"} - for _, dm := range conflictingDMs { - state, err := checkSystemdEnabled(dm) - if err != nil || state == "" || state == "not-found" { - continue - } - switch state { - case "enabled", "enabled-runtime", "static", "indirect", "alias": - logFunc(fmt.Sprintf("Disabling conflicting display manager: %s", dm)) - if err := runSudoCmd(sudoPassword, "systemctl", "disable", dm); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: Failed to disable %s: %v", dm, err)) - } else { - logFunc(fmt.Sprintf("✓ Disabled %s", dm)) - } - } - } - return nil -} - -// EnableGreetd unmasks and enables greetd, forcing it over any other DM. -func EnableGreetd(sudoPassword string, logFunc func(string)) error { - state, err := checkSystemdEnabled("greetd") - if err != nil { - return fmt.Errorf("failed to check greetd state: %w", err) - } - if state == "not-found" { - return fmt.Errorf("greetd service not found; ensure greetd is installed") - } - if state == "masked" || state == "masked-runtime" { - logFunc(" Unmasking greetd...") - if err := runSudoCmd(sudoPassword, "systemctl", "unmask", "greetd"); err != nil { - return fmt.Errorf("failed to unmask greetd: %w", err) - } - logFunc(" ✓ Unmasked greetd") - } - logFunc(" Enabling greetd service (--force)...") - if err := runSudoCmd(sudoPassword, "systemctl", "enable", "--force", "greetd"); err != nil { - return fmt.Errorf("failed to enable greetd: %w", err) - } - logFunc("✓ greetd enabled") - return nil -} - -func EnsureGraphicalTarget(sudoPassword string, logFunc func(string)) error { - cmd := exec.Command("systemctl", "get-default") - output, err := cmd.Output() - if err != nil { - logFunc(fmt.Sprintf("⚠ Warning: could not get default systemd target: %v", err)) - return nil - } - current := strings.TrimSpace(string(output)) - if current == "graphical.target" { - logFunc("✓ Default target is already graphical.target") - return nil - } - logFunc(fmt.Sprintf(" Setting default target to graphical.target (was: %s)...", current)) - if err := runSudoCmd(sudoPassword, "systemctl", "set-default", "graphical.target"); err != nil { - return fmt.Errorf("failed to set graphical target: %w", err) - } - logFunc("✓ Default target set to graphical.target") - return nil -} - -// AutoSetupGreeter performs the full non-interactive greeter setup -func AutoSetupGreeter(compositor, sudoPassword string, logFunc func(string)) error { - if IsGreeterPackaged() && HasLegacyLocalGreeterWrapper() { - return fmt.Errorf("legacy manual wrapper detected at /usr/local/bin/dms-greeter; " + - "remove it before using packaged dms-greeter: sudo rm -f /usr/local/bin/dms-greeter") - } - - logFunc("Ensuring greetd is installed...") - if err := EnsureGreetdInstalled(logFunc, sudoPassword); err != nil { - return fmt.Errorf("greetd install failed: %w", err) - } - - dmsPath := "" - if !IsGreeterPackaged() { - detected, err := DetectDMSPath() - if err != nil { - return fmt.Errorf("DMS installation not found: %w", err) - } - dmsPath = detected - logFunc(fmt.Sprintf("✓ Found DMS at: %s", dmsPath)) - } else { - logFunc("✓ Using packaged dms-greeter (/usr/share/quickshell/dms-greeter)") - } - - logFunc("Setting up dms-greeter group and permissions...") - if err := SetupDMSGroup(logFunc, sudoPassword); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: group/permissions setup error: %v", err)) - } - - logFunc("Copying greeter files...") - if err := CopyGreeterFiles(dmsPath, compositor, logFunc, sudoPassword); err != nil { - return fmt.Errorf("failed to copy greeter files: %w", err) - } - - logFunc("Configuring greetd...") - greeterPathForConfig := "" - if !IsGreeterPackaged() { - greeterPathForConfig = dmsPath - } - if err := ConfigureGreetd(greeterPathForConfig, compositor, logFunc, sudoPassword); err != nil { - return fmt.Errorf("failed to configure greetd: %w", err) - } - - logFunc("Synchronizing DMS configurations...") - if err := SyncDMSConfigs(dmsPath, compositor, logFunc, sudoPassword); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: config sync error: %v", err)) - } - - logFunc("Configuring authentication...") - if err := sharedpam.SyncAuthConfig(logFunc, sudoPassword, sharedpam.SyncAuthOptions{}); err != nil { - return fmt.Errorf("failed to sync authentication: %w", err) - } - - logFunc("Checking for conflicting display managers...") - if err := DisableConflictingDisplayManagers(sudoPassword, logFunc); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: %v", err)) - } - - logFunc("Enabling greetd service...") - if err := EnableGreetd(sudoPassword, logFunc); err != nil { - return fmt.Errorf("failed to enable greetd: %w", err) - } - - logFunc("Ensuring graphical.target as default...") - if err := EnsureGraphicalTarget(sudoPassword, logFunc); err != nil { - logFunc(fmt.Sprintf("⚠ Warning: %v", err)) - } - - logFunc("✓ DMS greeter setup complete") - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer_test.go deleted file mode 100644 index 9acee57..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/greeter/installer_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package greeter - -import ( - "os" - "path/filepath" - "testing" -) - -func writeTestFile(t *testing.T, path string, content string) { - t.Helper() - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - t.Fatalf("failed to create parent dir for %s: %v", path, err) - } - if err := os.WriteFile(path, []byte(content), 0o644); err != nil { - t.Fatalf("failed to write %s: %v", path, err) - } -} - -func TestResolveGreeterThemeSyncState(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - settingsJSON string - sessionJSON string - wantSourcePath string - wantResolvedWallpaper string - wantDynamicOverrideUsed bool - }{ - { - name: "dynamic theme with greeter wallpaper override uses generated greeter colors", - settingsJSON: `{ - "currentThemeName": "dynamic", - "greeterWallpaperPath": "Pictures/blue.jpg", - "matugenScheme": "scheme-tonal-spot", - "iconTheme": "Papirus" -}`, - sessionJSON: `{"isLightMode":true}`, - wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "greeter-colors", "dms-colors.json"), - wantResolvedWallpaper: filepath.Join("Pictures", "blue.jpg"), - wantDynamicOverrideUsed: true, - }, - { - name: "dynamic theme without override uses desktop colors", - settingsJSON: `{ - "currentThemeName": "dynamic", - "greeterWallpaperPath": "" -}`, - sessionJSON: `{"isLightMode":false}`, - wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "dms-colors.json"), - wantResolvedWallpaper: "", - wantDynamicOverrideUsed: false, - }, - { - name: "non-dynamic theme keeps desktop colors even with override wallpaper", - settingsJSON: `{ - "currentThemeName": "purple", - "greeterWallpaperPath": "/tmp/blue.jpg" -}`, - sessionJSON: `{"isLightMode":false}`, - wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "dms-colors.json"), - wantResolvedWallpaper: "/tmp/blue.jpg", - wantDynamicOverrideUsed: false, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - homeDir := t.TempDir() - writeTestFile(t, filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"), tt.settingsJSON) - writeTestFile(t, filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"), tt.sessionJSON) - - state, err := resolveGreeterThemeSyncState(homeDir) - if err != nil { - t.Fatalf("resolveGreeterThemeSyncState returned error: %v", err) - } - - if got := state.effectiveColorsSource(homeDir); got != filepath.Join(homeDir, tt.wantSourcePath) { - t.Fatalf("effectiveColorsSource = %q, want %q", got, filepath.Join(homeDir, tt.wantSourcePath)) - } - - wantResolvedWallpaper := tt.wantResolvedWallpaper - if wantResolvedWallpaper != "" && !filepath.IsAbs(wantResolvedWallpaper) { - wantResolvedWallpaper = filepath.Join(homeDir, wantResolvedWallpaper) - } - if state.ResolvedGreeterWallpaperPath != wantResolvedWallpaper { - t.Fatalf("ResolvedGreeterWallpaperPath = %q, want %q", state.ResolvedGreeterWallpaperPath, wantResolvedWallpaper) - } - - if state.UsesDynamicWallpaperOverride != tt.wantDynamicOverrideUsed { - t.Fatalf("UsesDynamicWallpaperOverride = %v, want %v", state.UsesDynamicWallpaperOverride, tt.wantDynamicOverrideUsed) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner.go deleted file mode 100644 index 7dae9fc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner.go +++ /dev/null @@ -1,418 +0,0 @@ -package headless - -import ( - "context" - "fmt" - "os" - "os/exec" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/greeter" -) - -// ErrConfirmationRequired is returned when --yes is not set and the user -// must explicitly confirm the operation. -var ErrConfirmationRequired = fmt.Errorf("confirmation required: pass --yes to proceed") - -// validConfigNames maps lowercase CLI input to the deployer key used in -// replaceConfigs. Keep in sync with the config types checked by -// shouldReplaceConfig in deployer.go. -var validConfigNames = map[string]string{ - "niri": "Niri", - "hyprland": "Hyprland", - "ghostty": "Ghostty", - "kitty": "Kitty", - "alacritty": "Alacritty", -} - -// orderedConfigNames defines the canonical order for config names in output. -// Must be kept in sync with validConfigNames. -var orderedConfigNames = []string{"niri", "hyprland", "ghostty", "kitty", "alacritty"} - -// Config holds all CLI parameters for unattended installation. -type Config struct { - Compositor string // "niri" or "hyprland" - Terminal string // "ghostty", "kitty", or "alacritty" - IncludeDeps []string - ExcludeDeps []string - ReplaceConfigs []string // specific configs to deploy (e.g. "niri", "ghostty") - ReplaceConfigsAll bool // deploy/replace all configurations - Yes bool -} - -// Runner orchestrates unattended (headless) installation. -type Runner struct { - cfg Config - logChan chan string -} - -// NewRunner creates a new headless runner. -func NewRunner(cfg Config) *Runner { - return &Runner{ - cfg: cfg, - logChan: make(chan string, 1000), - } -} - -// GetLogChan returns the log channel for file logging. -func (r *Runner) GetLogChan() <-chan string { - return r.logChan -} - -// Run executes the full unattended installation flow. -func (r *Runner) Run() error { - r.log("Starting headless installation") - - // 1. Parse compositor and terminal selections - wm, err := r.parseWindowManager() - if err != nil { - return err - } - - terminal, err := r.parseTerminal() - if err != nil { - return err - } - - // 2. Build replace-configs map - replaceConfigs, err := r.buildReplaceConfigs() - if err != nil { - return err - } - - // 3. Detect OS - r.log("Detecting operating system...") - osInfo, err := distros.GetOSInfo() - if err != nil { - return fmt.Errorf("OS detection failed: %w", err) - } - - if distros.IsUnsupportedDistro(osInfo.Distribution.ID, osInfo.VersionID) { - return fmt.Errorf("unsupported distribution: %s %s", osInfo.PrettyName, osInfo.VersionID) - } - - fmt.Fprintf(os.Stdout, "Detected: %s (%s)\n", osInfo.PrettyName, osInfo.Architecture) - - // 4. Create distribution instance - distro, err := distros.NewDistribution(osInfo.Distribution.ID, r.logChan) - if err != nil { - return fmt.Errorf("failed to initialize distribution: %w", err) - } - - // 5. Detect dependencies - r.log("Detecting dependencies...") - fmt.Fprintln(os.Stdout, "Detecting dependencies...") - dependencies, err := distro.DetectDependenciesWithTerminal(context.Background(), wm, terminal) - if err != nil { - return fmt.Errorf("dependency detection failed: %w", err) - } - - // 5. Apply include/exclude filters and build the disabled-items map. - // Headless mode does not currently collect any explicit reinstall selections, - // so keep reinstallItems nil instead of constructing an always-empty map. - disabledItems, err := r.buildDisabledItems(dependencies) - if err != nil { - return err - } - var reinstallItems map[string]bool - - // Print dependency summary - fmt.Fprintln(os.Stdout, "\nDependencies:") - for _, dep := range dependencies { - marker := " " - status := "" - if disabledItems[dep.Name] { - marker = " SKIP " - status = "(disabled)" - } else { - switch dep.Status { - case deps.StatusInstalled: - marker = " OK " - status = "(installed)" - case deps.StatusMissing: - marker = " NEW " - status = "(will install)" - case deps.StatusNeedsUpdate: - marker = " UPD " - status = "(will update)" - case deps.StatusNeedsReinstall: - marker = " RE " - status = "(will reinstall)" - } - } - fmt.Fprintf(os.Stdout, "%s%-30s %s\n", marker, dep.Name, status) - } - fmt.Fprintln(os.Stdout) - - // 6b. Require explicit confirmation unless --yes is set - if !r.cfg.Yes { - if replaceConfigs == nil { - // --replace-configs-all - fmt.Fprintln(os.Stdout, "Packages will be installed and all configurations will be replaced.") - fmt.Fprintln(os.Stdout, "Existing config files will be backed up before replacement.") - } else if r.anyConfigEnabled(replaceConfigs) { - var names []string - for _, cliName := range orderedConfigNames { - deployerKey := validConfigNames[cliName] - if replaceConfigs[deployerKey] { - names = append(names, deployerKey) - } - } - fmt.Fprintf(os.Stdout, "Packages will be installed. The following configurations will be replaced (with backups): %s\n", strings.Join(names, ", ")) - } else { - fmt.Fprintln(os.Stdout, "Packages will be installed. No configurations will be deployed.") - } - fmt.Fprintln(os.Stdout, "Re-run with --yes (-y) to proceed.") - r.log("Aborted: --yes not set") - return ErrConfirmationRequired - } - - // 7. Authenticate sudo - sudoPassword, err := r.resolveSudoPassword() - if err != nil { - return err - } - - // 8. Install packages - fmt.Fprintln(os.Stdout, "Installing packages...") - r.log("Starting package installation") - - progressChan := make(chan distros.InstallProgressMsg, 100) - - installErr := make(chan error, 1) - go func() { - defer close(progressChan) - installErr <- distro.InstallPackages( - context.Background(), - dependencies, - wm, - sudoPassword, - reinstallItems, - disabledItems, - false, // skipGlobalUseFlags - progressChan, - ) - }() - - // Consume progress messages and print them - for msg := range progressChan { - if msg.Error != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", msg.Error) - } else if msg.Step != "" { - fmt.Fprintf(os.Stdout, " [%3.0f%%] %s\n", msg.Progress*100, msg.Step) - } - if msg.LogOutput != "" { - r.log(msg.LogOutput) - fmt.Fprintf(os.Stdout, " %s\n", msg.LogOutput) - } - } - - if err := <-installErr; err != nil { - return fmt.Errorf("package installation failed: %w", err) - } - - // 9. Greeter setup (if dms-greeter was included) - if !disabledItems["dms-greeter"] && r.depExists(dependencies, "dms-greeter") { - compositorName := "niri" - if wm == deps.WindowManagerHyprland { - compositorName = "Hyprland" - } - fmt.Fprintln(os.Stdout, "Configuring DMS greeter...") - logFunc := func(line string) { - r.log(line) - fmt.Fprintf(os.Stdout, " greeter: %s\n", line) - } - if err := greeter.AutoSetupGreeter(compositorName, sudoPassword, logFunc); err != nil { - // Non-fatal, matching TUI behavior - fmt.Fprintf(os.Stderr, "Warning: greeter setup issue (non-fatal): %v\n", err) - } - } - - // 10. Deploy configurations - fmt.Fprintln(os.Stdout, "Deploying configurations...") - r.log("Starting configuration deployment") - - deployer := config.NewConfigDeployer(r.logChan) - results, err := deployer.DeployConfigurationsSelectiveWithReinstalls( - context.Background(), - wm, - terminal, - dependencies, - replaceConfigs, - reinstallItems, - ) - if err != nil { - return fmt.Errorf("configuration deployment failed: %w", err) - } - - for _, result := range results { - if result.Deployed { - msg := fmt.Sprintf(" Deployed: %s", result.ConfigType) - if result.BackupPath != "" { - msg += fmt.Sprintf(" (backup: %s)", result.BackupPath) - } - fmt.Fprintln(os.Stdout, msg) - } - if result.Error != nil { - fmt.Fprintf(os.Stderr, " Error deploying %s: %v\n", result.ConfigType, result.Error) - } - } - - fmt.Fprintln(os.Stdout, "\nInstallation complete!") - r.log("Headless installation completed successfully") - return nil -} - -// buildDisabledItems computes the set of dependencies that should be skipped -// during installation, applying the --include-deps and --exclude-deps filters. -// dms-greeter is disabled by default (opt-in), matching TUI behavior. -func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string]bool, error) { - disabledItems := make(map[string]bool) - - // dms-greeter is opt-in (disabled by default), matching TUI behavior - for i := range dependencies { - if dependencies[i].Name == "dms-greeter" { - disabledItems["dms-greeter"] = true - break - } - } - - // Process --include-deps (enable items that are disabled by default) - for _, name := range r.cfg.IncludeDeps { - name = strings.TrimSpace(name) - if name == "" { - continue - } - if !r.depExists(dependencies, name) { - return nil, fmt.Errorf("--include-deps: unknown dependency %q", name) - } - delete(disabledItems, name) - } - - // Process --exclude-deps (disable items) - for _, name := range r.cfg.ExcludeDeps { - name = strings.TrimSpace(name) - if name == "" { - continue - } - if !r.depExists(dependencies, name) { - return nil, fmt.Errorf("--exclude-deps: unknown dependency %q", name) - } - // Don't allow excluding DMS itself - if name == "dms (DankMaterialShell)" { - return nil, fmt.Errorf("--exclude-deps: cannot exclude required package %q", name) - } - disabledItems[name] = true - } - - return disabledItems, nil -} - -// buildReplaceConfigs converts the --replace-configs / --replace-configs-all -// flags into the map[string]bool consumed by the config deployer. -// -// Returns: -// - nil when --replace-configs-all is set (deployer treats nil as "replace all") -// - a map with all known configs set to false when neither flag is set (deploy only if config file is missing on disk) -// - a map with requested configs true, all others false for --replace-configs -// - an error when both flags are set or an invalid config name is given -func (r *Runner) buildReplaceConfigs() (map[string]bool, error) { - hasSpecific := len(r.cfg.ReplaceConfigs) > 0 - if hasSpecific && r.cfg.ReplaceConfigsAll { - return nil, fmt.Errorf("--replace-configs and --replace-configs-all are mutually exclusive") - } - - if r.cfg.ReplaceConfigsAll { - return nil, nil - } - - // Build a map with all known configs explicitly set to false - result := make(map[string]bool, len(validConfigNames)) - for _, cliName := range orderedConfigNames { - result[validConfigNames[cliName]] = false - } - - // Enable only the requested configs - for _, name := range r.cfg.ReplaceConfigs { - name = strings.TrimSpace(name) - if name == "" { - continue - } - deployerKey, ok := validConfigNames[strings.ToLower(name)] - if !ok { - return nil, fmt.Errorf("--replace-configs: unknown config %q; valid values: niri, hyprland, ghostty, kitty, alacritty", name) - } - result[deployerKey] = true - } - - return result, nil -} - -func (r *Runner) log(message string) { - select { - case r.logChan <- message: - default: - } -} - -func (r *Runner) parseWindowManager() (deps.WindowManager, error) { - switch strings.ToLower(r.cfg.Compositor) { - case "niri": - return deps.WindowManagerNiri, nil - case "hyprland": - return deps.WindowManagerHyprland, nil - default: - return 0, fmt.Errorf("invalid --compositor value %q: must be 'niri' or 'hyprland'", r.cfg.Compositor) - } -} - -func (r *Runner) parseTerminal() (deps.Terminal, error) { - switch strings.ToLower(r.cfg.Terminal) { - case "ghostty": - return deps.TerminalGhostty, nil - case "kitty": - return deps.TerminalKitty, nil - case "alacritty": - return deps.TerminalAlacritty, nil - default: - return 0, fmt.Errorf("invalid --term value %q: must be 'ghostty', 'kitty', or 'alacritty'", r.cfg.Terminal) - } -} - -func (r *Runner) resolveSudoPassword() (string, error) { - // Check if sudo credentials are cached (via sudo -v or NOPASSWD) - cmd := exec.Command("sudo", "-n", "true") - if err := cmd.Run(); err == nil { - r.log("sudo cache is valid, no password needed") - fmt.Fprintln(os.Stdout, "sudo: using cached credentials") - return "", nil - } - - return "", fmt.Errorf( - "sudo authentication required but no cached credentials found\n" + - "Options:\n" + - " 1. Run 'sudo -v' before dankinstall to cache credentials\n" + - " 2. Configure passwordless sudo for your user", - ) -} - -func (r *Runner) anyConfigEnabled(m map[string]bool) bool { - for _, v := range m { - if v { - return true - } - } - return false -} - -func (r *Runner) depExists(dependencies []deps.Dependency, name string) bool { - for _, dep := range dependencies { - if dep.Name == name { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner_test.go deleted file mode 100644 index 79260ae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/headless/runner_test.go +++ /dev/null @@ -1,459 +0,0 @@ -package headless - -import ( - "strings" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" -) - -func TestParseWindowManager(t *testing.T) { - tests := []struct { - name string - input string - want deps.WindowManager - wantErr bool - }{ - {"niri lowercase", "niri", deps.WindowManagerNiri, false}, - {"niri mixed case", "Niri", deps.WindowManagerNiri, false}, - {"hyprland lowercase", "hyprland", deps.WindowManagerHyprland, false}, - {"hyprland mixed case", "Hyprland", deps.WindowManagerHyprland, false}, - {"invalid", "sway", 0, true}, - {"empty", "", 0, true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := NewRunner(Config{Compositor: tt.input}) - got, err := r.parseWindowManager() - if (err != nil) != tt.wantErr { - t.Errorf("parseWindowManager() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr && got != tt.want { - t.Errorf("parseWindowManager() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestParseTerminal(t *testing.T) { - tests := []struct { - name string - input string - want deps.Terminal - wantErr bool - }{ - {"ghostty lowercase", "ghostty", deps.TerminalGhostty, false}, - {"ghostty mixed case", "Ghostty", deps.TerminalGhostty, false}, - {"kitty lowercase", "kitty", deps.TerminalKitty, false}, - {"alacritty lowercase", "alacritty", deps.TerminalAlacritty, false}, - {"alacritty uppercase", "ALACRITTY", deps.TerminalAlacritty, false}, - {"invalid", "wezterm", 0, true}, - {"empty", "", 0, true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := NewRunner(Config{Terminal: tt.input}) - got, err := r.parseTerminal() - if (err != nil) != tt.wantErr { - t.Errorf("parseTerminal() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr && got != tt.want { - t.Errorf("parseTerminal() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestDepExists(t *testing.T) { - dependencies := []deps.Dependency{ - {Name: "niri", Status: deps.StatusInstalled}, - {Name: "ghostty", Status: deps.StatusMissing}, - {Name: "dms (DankMaterialShell)", Status: deps.StatusInstalled}, - {Name: "dms-greeter", Status: deps.StatusMissing}, - } - - tests := []struct { - name string - dep string - want bool - }{ - {"existing dep", "niri", true}, - {"existing dep with special chars", "dms (DankMaterialShell)", true}, - {"existing optional dep", "dms-greeter", true}, - {"non-existing dep", "firefox", false}, - {"empty name", "", false}, - } - - r := NewRunner(Config{}) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := r.depExists(dependencies, tt.dep); got != tt.want { - t.Errorf("depExists(%q) = %v, want %v", tt.dep, got, tt.want) - } - }) - } -} - -func TestNewRunner(t *testing.T) { - cfg := Config{ - Compositor: "niri", - Terminal: "ghostty", - IncludeDeps: []string{"dms-greeter"}, - ExcludeDeps: []string{"some-pkg"}, - Yes: true, - } - r := NewRunner(cfg) - - if r == nil { - t.Fatal("NewRunner returned nil") - } - if r.cfg.Compositor != "niri" { - t.Errorf("cfg.Compositor = %q, want %q", r.cfg.Compositor, "niri") - } - if r.cfg.Terminal != "ghostty" { - t.Errorf("cfg.Terminal = %q, want %q", r.cfg.Terminal, "ghostty") - } - if !r.cfg.Yes { - t.Error("cfg.Yes = false, want true") - } - if r.logChan == nil { - t.Error("logChan is nil") - } -} - -func TestGetLogChan(t *testing.T) { - r := NewRunner(Config{}) - ch := r.GetLogChan() - if ch == nil { - t.Fatal("GetLogChan returned nil") - } - - // Verify the channel is readable by sending a message - go func() { - r.logChan <- "test message" - }() - msg := <-ch - if msg != "test message" { - t.Errorf("received %q, want %q", msg, "test message") - } -} - -func TestLog(t *testing.T) { - r := NewRunner(Config{}) - - // log should not block even if channel is full - for i := 0; i < 1100; i++ { - r.log("message") - } - // If we reach here without hanging, the non-blocking send works -} - -func TestRunRequiresYes(t *testing.T) { - // Verify that ErrConfirmationRequired is a distinct sentinel error - if ErrConfirmationRequired == nil { - t.Fatal("ErrConfirmationRequired should not be nil") - } - expected := "confirmation required: pass --yes to proceed" - if ErrConfirmationRequired.Error() != expected { - t.Errorf("ErrConfirmationRequired = %q, want %q", ErrConfirmationRequired.Error(), expected) - } -} - -func TestConfigYesStoredCorrectly(t *testing.T) { - // Yes=false (default) should be stored - rNo := NewRunner(Config{Compositor: "niri", Terminal: "ghostty", Yes: false}) - if rNo.cfg.Yes { - t.Error("cfg.Yes = true, want false") - } - - // Yes=true should be stored - rYes := NewRunner(Config{Compositor: "niri", Terminal: "ghostty", Yes: true}) - if !rYes.cfg.Yes { - t.Error("cfg.Yes = false, want true") - } -} - -func TestValidConfigNamesCompleteness(t *testing.T) { - // orderedConfigNames and validConfigNames must stay in sync. - if len(orderedConfigNames) != len(validConfigNames) { - t.Fatalf("orderedConfigNames has %d entries but validConfigNames has %d", - len(orderedConfigNames), len(validConfigNames)) - } - - // Every entry in orderedConfigNames must exist in validConfigNames. - for _, name := range orderedConfigNames { - if _, ok := validConfigNames[name]; !ok { - t.Errorf("orderedConfigNames contains %q which is missing from validConfigNames", name) - } - } - - // validConfigNames must have no extra keys not in orderedConfigNames. - ordered := make(map[string]bool, len(orderedConfigNames)) - for _, name := range orderedConfigNames { - ordered[name] = true - } - for key := range validConfigNames { - if !ordered[key] { - t.Errorf("validConfigNames contains %q which is missing from orderedConfigNames", key) - } - } -} - -func TestBuildReplaceConfigs(t *testing.T) { - allDeployerKeys := []string{"Niri", "Hyprland", "Ghostty", "Kitty", "Alacritty"} - - tests := []struct { - name string - replaceConfigs []string - replaceAll bool - wantNil bool // expect nil (replace all) - wantEnabled []string // deployer keys that should be true - wantErr bool - }{ - { - name: "neither flag set", - wantNil: false, - wantEnabled: nil, // all should be false - }, - { - name: "replace-configs-all", - replaceAll: true, - wantNil: true, - }, - { - name: "specific configs", - replaceConfigs: []string{"niri", "ghostty"}, - wantNil: false, - wantEnabled: []string{"Niri", "Ghostty"}, - }, - { - name: "both flags set", - replaceConfigs: []string{"niri"}, - replaceAll: true, - wantErr: true, - }, - { - name: "invalid config name", - replaceConfigs: []string{"foo"}, - wantErr: true, - }, - { - name: "case insensitive", - replaceConfigs: []string{"NIRI", "Ghostty"}, - wantNil: false, - wantEnabled: []string{"Niri", "Ghostty"}, - }, - { - name: "single config", - replaceConfigs: []string{"kitty"}, - wantNil: false, - wantEnabled: []string{"Kitty"}, - }, - { - name: "whitespace entry", - replaceConfigs: []string{" ", "niri"}, - wantNil: false, - wantEnabled: []string{"Niri"}, - }, - { - name: "duplicate entry", - replaceConfigs: []string{"niri", "niri"}, - wantNil: false, - wantEnabled: []string{"Niri"}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := NewRunner(Config{ - ReplaceConfigs: tt.replaceConfigs, - ReplaceConfigsAll: tt.replaceAll, - }) - got, err := r.buildReplaceConfigs() - if (err != nil) != tt.wantErr { - t.Fatalf("buildReplaceConfigs() error = %v, wantErr %v", err, tt.wantErr) - } - if tt.wantErr { - return - } - if tt.wantNil { - if got != nil { - t.Fatalf("buildReplaceConfigs() = %v, want nil", got) - } - return - } - if got == nil { - t.Fatal("buildReplaceConfigs() = nil, want non-nil map") - } - - // All known deployer keys must be present - for _, key := range allDeployerKeys { - if _, exists := got[key]; !exists { - t.Errorf("missing deployer key %q in result map", key) - } - } - - // Build enabled set for easy lookup - enabledSet := make(map[string]bool) - for _, k := range tt.wantEnabled { - enabledSet[k] = true - } - - for _, key := range allDeployerKeys { - want := enabledSet[key] - if got[key] != want { - t.Errorf("replaceConfigs[%q] = %v, want %v", key, got[key], want) - } - } - }) - } -} - -func TestConfigReplaceConfigsStoredCorrectly(t *testing.T) { - r := NewRunner(Config{ - Compositor: "niri", - Terminal: "ghostty", - ReplaceConfigs: []string{"niri", "ghostty"}, - ReplaceConfigsAll: false, - }) - if len(r.cfg.ReplaceConfigs) != 2 { - t.Errorf("len(ReplaceConfigs) = %d, want 2", len(r.cfg.ReplaceConfigs)) - } - if r.cfg.ReplaceConfigsAll { - t.Error("ReplaceConfigsAll = true, want false") - } - - r2 := NewRunner(Config{ - Compositor: "niri", - Terminal: "ghostty", - ReplaceConfigsAll: true, - }) - if !r2.cfg.ReplaceConfigsAll { - t.Error("ReplaceConfigsAll = false, want true") - } - if len(r2.cfg.ReplaceConfigs) != 0 { - t.Errorf("len(ReplaceConfigs) = %d, want 0", len(r2.cfg.ReplaceConfigs)) - } -} - -func TestBuildDisabledItems(t *testing.T) { - dependencies := []deps.Dependency{ - {Name: "niri", Status: deps.StatusInstalled}, - {Name: "ghostty", Status: deps.StatusMissing}, - {Name: "dms (DankMaterialShell)", Status: deps.StatusInstalled}, - {Name: "dms-greeter", Status: deps.StatusMissing}, - {Name: "waybar", Status: deps.StatusMissing}, - } - - tests := []struct { - name string - includeDeps []string - excludeDeps []string - deps []deps.Dependency // nil means use the shared fixture - wantErr bool - errContains string // substring expected in error message - wantDisabled []string // dep names that should be in disabledItems - wantEnabled []string // dep names that should NOT be in disabledItems (extra check) - }{ - { - name: "no flags set, dms-greeter disabled by default", - wantDisabled: []string{"dms-greeter"}, - wantEnabled: []string{"niri", "ghostty", "waybar"}, - }, - { - name: "include dms-greeter enables it", - includeDeps: []string{"dms-greeter"}, - wantEnabled: []string{"dms-greeter"}, - }, - { - name: "exclude a regular dep", - excludeDeps: []string{"waybar"}, - wantDisabled: []string{"dms-greeter", "waybar"}, - }, - { - name: "include unknown dep returns error", - includeDeps: []string{"nonexistent"}, - wantErr: true, - errContains: "--include-deps", - }, - { - name: "exclude unknown dep returns error", - excludeDeps: []string{"nonexistent"}, - wantErr: true, - errContains: "--exclude-deps", - }, - { - name: "exclude DMS itself is forbidden", - excludeDeps: []string{"dms (DankMaterialShell)"}, - wantErr: true, - errContains: "cannot exclude required package", - }, - { - name: "include and exclude same dep", - includeDeps: []string{"dms-greeter"}, - excludeDeps: []string{"dms-greeter"}, - wantDisabled: []string{"dms-greeter"}, - }, - { - name: "whitespace entries are skipped", - includeDeps: []string{" ", "dms-greeter"}, - wantEnabled: []string{"dms-greeter"}, - }, - { - name: "no dms-greeter in deps, nothing disabled by default", - deps: []deps.Dependency{ - {Name: "niri", Status: deps.StatusInstalled}, - }, - wantEnabled: []string{"niri"}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := NewRunner(Config{ - IncludeDeps: tt.includeDeps, - ExcludeDeps: tt.excludeDeps, - }) - d := tt.deps - if d == nil { - d = dependencies - } - got, err := r.buildDisabledItems(d) - if (err != nil) != tt.wantErr { - t.Fatalf("buildDisabledItems() error = %v, wantErr %v", err, tt.wantErr) - } - if tt.wantErr { - if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("error %q does not contain %q", err.Error(), tt.errContains) - } - return - } - if got == nil { - t.Fatal("buildDisabledItems() returned nil map, want non-nil") - } - - // Check expected disabled items - for _, name := range tt.wantDisabled { - if !got[name] { - t.Errorf("expected %q to be disabled, but it is not", name) - } - } - - // Check expected enabled items (should not be in the map or be false) - for _, name := range tt.wantEnabled { - if got[name] { - t.Errorf("expected %q to NOT be disabled, but it is", name) - } - } - - // If wantDisabled is empty, the map should have length 0 - if len(tt.wantDisabled) == 0 && len(got) != 0 { - t.Errorf("expected empty disabledItems map, got %v", got) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery.go deleted file mode 100644 index 4990975..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery.go +++ /dev/null @@ -1,107 +0,0 @@ -package keybinds - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type DiscoveryConfig struct { - SearchPaths []string -} - -func DefaultDiscoveryConfig() *DiscoveryConfig { - var searchPaths []string - - configDir, err := os.UserConfigDir() - if err == nil && configDir != "" { - searchPaths = append(searchPaths, filepath.Join(configDir, "DankMaterialShell", "cheatsheets")) - } - - configDirs := os.Getenv("XDG_CONFIG_DIRS") - if configDirs != "" { - for dir := range strings.SplitSeq(configDirs, ":") { - if dir != "" { - searchPaths = append(searchPaths, filepath.Join(dir, "DankMaterialShell", "cheatsheets")) - } - } - } - - return &DiscoveryConfig{ - SearchPaths: searchPaths, - } -} - -func (d *DiscoveryConfig) FindJSONFiles() ([]string, error) { - var files []string - - for _, searchPath := range d.SearchPaths { - expandedPath, err := utils.ExpandPath(searchPath) - if err != nil { - continue - } - - if _, err := os.Stat(expandedPath); os.IsNotExist(err) { - continue - } - - entries, err := os.ReadDir(expandedPath) - if err != nil { - continue - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - if !strings.HasSuffix(entry.Name(), ".json") { - continue - } - - fullPath := filepath.Join(expandedPath, entry.Name()) - files = append(files, fullPath) - } - } - - return files, nil -} - -type JSONProviderFactory func(filePath string) (Provider, error) - -var jsonProviderFactory JSONProviderFactory - -func SetJSONProviderFactory(factory JSONProviderFactory) { - jsonProviderFactory = factory -} - -func AutoDiscoverProviders(registry *Registry, config *DiscoveryConfig) error { - if config == nil { - config = DefaultDiscoveryConfig() - } - - if jsonProviderFactory == nil { - return nil - } - - files, err := config.FindJSONFiles() - if err != nil { - return fmt.Errorf("failed to discover JSON files: %w", err) - } - - for _, file := range files { - provider, err := jsonProviderFactory(file) - if err != nil { - continue - } - - if err := registry.Register(provider); err != nil { - continue - } - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery_test.go deleted file mode 100644 index a78724e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/discovery_test.go +++ /dev/null @@ -1,287 +0,0 @@ -package keybinds - -import ( - "os" - "path/filepath" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func TestDefaultDiscoveryConfig(t *testing.T) { - oldConfigHome := os.Getenv("XDG_CONFIG_HOME") - oldConfigDirs := os.Getenv("XDG_CONFIG_DIRS") - defer func() { - os.Setenv("XDG_CONFIG_HOME", oldConfigHome) - os.Setenv("XDG_CONFIG_DIRS", oldConfigDirs) - }() - - tests := []struct { - name string - configHome string - configDirs string - expectedCount int - checkFirstPath bool - firstPath string - }{ - { - name: "default with no XDG vars", - configHome: "", - configDirs: "", - expectedCount: 1, - checkFirstPath: true, - }, - { - name: "with XDG_CONFIG_HOME set", - configHome: "/custom/config", - configDirs: "", - expectedCount: 1, - checkFirstPath: true, - firstPath: "/custom/config/DankMaterialShell/cheatsheets", - }, - { - name: "with XDG_CONFIG_DIRS set", - configHome: "/home/user/.config", - configDirs: "/etc/xdg:/opt/config", - expectedCount: 3, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - os.Setenv("XDG_CONFIG_HOME", tt.configHome) - os.Setenv("XDG_CONFIG_DIRS", tt.configDirs) - - config := DefaultDiscoveryConfig() - - if config == nil { - t.Fatal("DefaultDiscoveryConfig returned nil") - } - - if len(config.SearchPaths) != tt.expectedCount { - t.Errorf("SearchPaths count = %d, want %d", len(config.SearchPaths), tt.expectedCount) - } - - if tt.checkFirstPath && len(config.SearchPaths) > 0 { - if tt.firstPath != "" && config.SearchPaths[0] != tt.firstPath { - t.Errorf("SearchPaths[0] = %q, want %q", config.SearchPaths[0], tt.firstPath) - } - } - }) - } -} - -func TestFindJSONFiles(t *testing.T) { - tmpDir := t.TempDir() - - file1 := filepath.Join(tmpDir, "tmux.json") - file2 := filepath.Join(tmpDir, "vim.json") - txtFile := filepath.Join(tmpDir, "readme.txt") - subdir := filepath.Join(tmpDir, "subdir") - - if err := os.WriteFile(file1, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create file1: %v", err) - } - if err := os.WriteFile(file2, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create file2: %v", err) - } - if err := os.WriteFile(txtFile, []byte("text"), 0o644); err != nil { - t.Fatalf("Failed to create txt file: %v", err) - } - if err := os.MkdirAll(subdir, 0o755); err != nil { - t.Fatalf("Failed to create subdir: %v", err) - } - - config := &DiscoveryConfig{ - SearchPaths: []string{tmpDir}, - } - - files, err := config.FindJSONFiles() - if err != nil { - t.Fatalf("FindJSONFiles failed: %v", err) - } - - if len(files) != 2 { - t.Errorf("expected 2 JSON files, got %d", len(files)) - } - - found := make(map[string]bool) - for _, f := range files { - found[filepath.Base(f)] = true - } - - if !found["tmux.json"] { - t.Error("tmux.json not found") - } - if !found["vim.json"] { - t.Error("vim.json not found") - } - if found["readme.txt"] { - t.Error("readme.txt should not be included") - } -} - -func TestFindJSONFilesNonexistentPath(t *testing.T) { - config := &DiscoveryConfig{ - SearchPaths: []string{"/nonexistent/path"}, - } - - files, err := config.FindJSONFiles() - if err != nil { - t.Fatalf("FindJSONFiles failed: %v", err) - } - - if len(files) != 0 { - t.Errorf("expected 0 files for nonexistent path, got %d", len(files)) - } -} - -func TestFindJSONFilesMultiplePaths(t *testing.T) { - tmpDir1 := t.TempDir() - tmpDir2 := t.TempDir() - - file1 := filepath.Join(tmpDir1, "app1.json") - file2 := filepath.Join(tmpDir2, "app2.json") - - if err := os.WriteFile(file1, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create file1: %v", err) - } - if err := os.WriteFile(file2, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create file2: %v", err) - } - - config := &DiscoveryConfig{ - SearchPaths: []string{tmpDir1, tmpDir2}, - } - - files, err := config.FindJSONFiles() - if err != nil { - t.Fatalf("FindJSONFiles failed: %v", err) - } - - if len(files) != 2 { - t.Errorf("expected 2 JSON files from multiple paths, got %d", len(files)) - } -} - -func TestAutoDiscoverProviders(t *testing.T) { - tmpDir := t.TempDir() - - jsonContent := `{ - "title": "Test App", - "provider": "testapp", - "binds": {} -}` - - file := filepath.Join(tmpDir, "testapp.json") - if err := os.WriteFile(file, []byte(jsonContent), 0o644); err != nil { - t.Fatalf("Failed to create test file: %v", err) - } - - config := &DiscoveryConfig{ - SearchPaths: []string{tmpDir}, - } - - registry := NewRegistry() - - factoryCalled := false - SetJSONProviderFactory(func(filePath string) (Provider, error) { - factoryCalled = true - return &mockProvider{name: "testapp"}, nil - }) - - err := AutoDiscoverProviders(registry, config) - if err != nil { - t.Fatalf("AutoDiscoverProviders failed: %v", err) - } - - if !factoryCalled { - t.Error("factory was not called") - } - - provider, err := registry.Get("testapp") - if err != nil { - t.Fatalf("provider not registered: %v", err) - } - - if provider.Name() != "testapp" { - t.Errorf("provider name = %q, want %q", provider.Name(), "testapp") - } -} - -func TestAutoDiscoverProvidersNilConfig(t *testing.T) { - registry := NewRegistry() - - SetJSONProviderFactory(func(filePath string) (Provider, error) { - return &mockProvider{name: "test"}, nil - }) - - err := AutoDiscoverProviders(registry, nil) - if err != nil { - t.Fatalf("AutoDiscoverProviders with nil config failed: %v", err) - } -} - -func TestAutoDiscoverProvidersNoFactory(t *testing.T) { - tmpDir := t.TempDir() - - file := filepath.Join(tmpDir, "test.json") - if err := os.WriteFile(file, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create test file: %v", err) - } - - config := &DiscoveryConfig{ - SearchPaths: []string{tmpDir}, - } - - registry := NewRegistry() - - SetJSONProviderFactory(nil) - - err := AutoDiscoverProviders(registry, config) - if err != nil { - t.Fatalf("AutoDiscoverProviders should not fail without factory: %v", err) - } - - providers := registry.List() - if len(providers) != 0 { - t.Errorf("expected 0 providers without factory, got %d", len(providers)) - } -} - -func TestExpandPathInDiscovery(t *testing.T) { - home, err := os.UserHomeDir() - if err != nil { - t.Skip("Cannot get home directory") - } - - tests := []struct { - name string - input string - expected string - }{ - { - name: "tilde expansion", - input: "~/test", - expected: filepath.Join(home, "test"), - }, - { - name: "absolute path", - input: "/tmp/test", - expected: "/tmp/test", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := utils.ExpandPath(tt.input) - if err != nil { - t.Fatalf("expandPath failed: %v", err) - } - - if result != tt.expected { - t.Errorf("utils.ExpandPath(%q) = %q, want %q", tt.input, result, tt.expected) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland.go deleted file mode 100644 index e43a9eb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland.go +++ /dev/null @@ -1,497 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type HyprlandProvider struct { - configPath string - dmsBindsIncluded bool - parsed bool -} - -func NewHyprlandProvider(configPath string) *HyprlandProvider { - if configPath == "" { - configPath = defaultHyprlandConfigDir() - } - return &HyprlandProvider{ - configPath: configPath, - } -} - -func defaultHyprlandConfigDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - return "" - } - return filepath.Join(configDir, "hypr") -} - -func (h *HyprlandProvider) Name() string { - return "hyprland" -} - -func (h *HyprlandProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - result, err := ParseHyprlandKeysWithDMS(h.configPath) - if err != nil { - return nil, fmt.Errorf("failed to parse hyprland config: %w", err) - } - - h.dmsBindsIncluded = result.DMSBindsIncluded - h.parsed = true - - categorizedBinds := make(map[string][]keybinds.Keybind) - h.convertSection(result.Section, "", categorizedBinds, result.ConflictingConfigs) - - sheet := &keybinds.CheatSheet{ - Title: "Hyprland Keybinds", - Provider: h.Name(), - Binds: categorizedBinds, - DMSBindsIncluded: result.DMSBindsIncluded, - } - - if result.DMSStatus != nil { - sheet.DMSStatus = &keybinds.DMSBindsStatus{ - Exists: result.DMSStatus.Exists, - Included: result.DMSStatus.Included, - IncludePosition: result.DMSStatus.IncludePosition, - TotalIncludes: result.DMSStatus.TotalIncludes, - BindsAfterDMS: result.DMSStatus.BindsAfterDMS, - Effective: result.DMSStatus.Effective, - OverriddenBy: result.DMSStatus.OverriddenBy, - StatusMessage: result.DMSStatus.StatusMessage, - } - } - - return sheet, nil -} - -func (h *HyprlandProvider) HasDMSBindsIncluded() bool { - if h.parsed { - return h.dmsBindsIncluded - } - - result, err := ParseHyprlandKeysWithDMS(h.configPath) - if err != nil { - return false - } - - h.dmsBindsIncluded = result.DMSBindsIncluded - h.parsed = true - return h.dmsBindsIncluded -} - -func (h *HyprlandProvider) convertSection(section *HyprlandSection, subcategory string, categorizedBinds map[string][]keybinds.Keybind, conflicts map[string]*HyprlandKeyBinding) { - currentSubcat := subcategory - if section.Name != "" { - currentSubcat = section.Name - } - - for _, kb := range section.Keybinds { - category := h.categorizeByDispatcher(kb.Dispatcher) - bind := h.convertKeybind(&kb, currentSubcat, conflicts) - categorizedBinds[category] = append(categorizedBinds[category], bind) - } - - for _, child := range section.Children { - h.convertSection(&child, currentSubcat, categorizedBinds, conflicts) - } -} - -func (h *HyprlandProvider) categorizeByDispatcher(dispatcher string) string { - switch { - case strings.Contains(dispatcher, "workspace"): - return "Workspace" - case strings.Contains(dispatcher, "monitor"): - return "Monitor" - case strings.Contains(dispatcher, "window") || - strings.Contains(dispatcher, "focus") || - strings.Contains(dispatcher, "move") || - strings.Contains(dispatcher, "swap") || - strings.Contains(dispatcher, "resize") || - dispatcher == "killactive" || - dispatcher == "fullscreen" || - dispatcher == "togglefloating" || - dispatcher == "pin" || - dispatcher == "fakefullscreen" || - dispatcher == "splitratio" || - dispatcher == "resizeactive": - return "Window" - case dispatcher == "exec": - return "Execute" - case dispatcher == "exit" || strings.Contains(dispatcher, "dpms"): - return "System" - default: - return "Other" - } -} - -func (h *HyprlandProvider) convertKeybind(kb *HyprlandKeyBinding, subcategory string, conflicts map[string]*HyprlandKeyBinding) keybinds.Keybind { - keyStr := h.formatKey(kb) - rawAction := h.formatRawAction(kb.Dispatcher, kb.Params) - desc := kb.Comment - - if desc == "" { - desc = rawAction - } - - source := "config" - if strings.Contains(kb.Source, "dms/binds.conf") { - source = "dms" - } - - bind := keybinds.Keybind{ - Key: keyStr, - Description: desc, - Action: rawAction, - Subcategory: subcategory, - Source: source, - Flags: kb.Flags, - } - - if source == "dms" && conflicts != nil { - normalizedKey := strings.ToLower(keyStr) - if conflictKb, ok := conflicts[normalizedKey]; ok { - bind.Conflict = &keybinds.Keybind{ - Key: keyStr, - Description: conflictKb.Comment, - Action: h.formatRawAction(conflictKb.Dispatcher, conflictKb.Params), - Source: "config", - } - } - } - - return bind -} - -func (h *HyprlandProvider) formatRawAction(dispatcher, params string) string { - if params != "" { - return dispatcher + " " + params - } - return dispatcher -} - -func (h *HyprlandProvider) formatKey(kb *HyprlandKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (h *HyprlandProvider) GetOverridePath() string { - expanded, err := utils.ExpandPath(h.configPath) - if err != nil { - return filepath.Join(h.configPath, "dms", "binds.conf") - } - return filepath.Join(expanded, "dms", "binds.conf") -} - -func (h *HyprlandProvider) validateAction(action string) error { - action = strings.TrimSpace(action) - switch { - case action == "": - return fmt.Errorf("action cannot be empty") - case action == "exec" || action == "exec ": - return fmt.Errorf("exec dispatcher requires arguments") - case strings.HasPrefix(action, "exec "): - rest := strings.TrimSpace(strings.TrimPrefix(action, "exec ")) - if rest == "" { - return fmt.Errorf("exec dispatcher requires arguments") - } - } - return nil -} - -func (h *HyprlandProvider) SetBind(key, action, description string, options map[string]any) error { - if err := h.validateAction(action); err != nil { - return err - } - - overridePath := h.GetOverridePath() - - if err := os.MkdirAll(filepath.Dir(overridePath), 0o755); err != nil { - return fmt.Errorf("failed to create dms directory: %w", err) - } - - existingBinds, err := h.loadOverrideBinds() - if err != nil { - existingBinds = make(map[string]*hyprlandOverrideBind) - } - - // Extract flags from options - var flags string - if options != nil { - if f, ok := options["flags"].(string); ok { - flags = f - } - } - - normalizedKey := strings.ToLower(key) - existingBinds[normalizedKey] = &hyprlandOverrideBind{ - Key: key, - Action: action, - Description: description, - Flags: flags, - Options: options, - } - - return h.writeOverrideBinds(existingBinds) -} - -func (h *HyprlandProvider) RemoveBind(key string) error { - existingBinds, err := h.loadOverrideBinds() - if err != nil { - return nil - } - - normalizedKey := strings.ToLower(key) - delete(existingBinds, normalizedKey) - return h.writeOverrideBinds(existingBinds) -} - -type hyprlandOverrideBind struct { - Key string - Action string - Description string - Flags string // Bind flags: l=locked, r=release, e=repeat, n=non-consuming, m=mouse, t=transparent, i=ignore-mods, s=separate, d=description, o=long-press - Options map[string]any -} - -func (h *HyprlandProvider) loadOverrideBinds() (map[string]*hyprlandOverrideBind, error) { - overridePath := h.GetOverridePath() - binds := make(map[string]*hyprlandOverrideBind) - - data, err := os.ReadFile(overridePath) - if os.IsNotExist(err) { - return binds, nil - } - if err != nil { - return nil, err - } - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - - if !strings.HasPrefix(line, "bind") { - continue - } - - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - continue - } - - // Extract flags from bind type - bindType := strings.TrimSpace(parts[0]) - flags := extractBindFlags(bindType) - hasDescFlag := strings.Contains(flags, "d") - - content := strings.TrimSpace(parts[1]) - commentParts := strings.SplitN(content, "#", 2) - bindContent := strings.TrimSpace(commentParts[0]) - - var comment string - if len(commentParts) > 1 { - comment = strings.TrimSpace(commentParts[1]) - } - - // For bindd, format is: mods, key, description, dispatcher, params - var minFields, descIndex, dispatcherIndex int - if hasDescFlag { - minFields = 4 - descIndex = 2 - dispatcherIndex = 3 - } else { - minFields = 3 - dispatcherIndex = 2 - } - - fields := strings.SplitN(bindContent, ",", minFields+2) - if len(fields) < minFields { - continue - } - - mods := strings.TrimSpace(fields[0]) - keyName := strings.TrimSpace(fields[1]) - - var dispatcher, params string - if hasDescFlag { - if comment == "" { - comment = strings.TrimSpace(fields[descIndex]) - } - dispatcher = strings.TrimSpace(fields[dispatcherIndex]) - if len(fields) > dispatcherIndex+1 { - paramParts := fields[dispatcherIndex+1:] - params = strings.TrimSpace(strings.Join(paramParts, ",")) - } - } else { - dispatcher = strings.TrimSpace(fields[dispatcherIndex]) - if len(fields) > dispatcherIndex+1 { - paramParts := fields[dispatcherIndex+1:] - params = strings.TrimSpace(strings.Join(paramParts, ",")) - } - } - - keyStr := h.buildKeyString(mods, keyName) - normalizedKey := strings.ToLower(keyStr) - action := dispatcher - if params != "" { - action = dispatcher + " " + params - } - - binds[normalizedKey] = &hyprlandOverrideBind{ - Key: keyStr, - Action: action, - Description: comment, - Flags: flags, - } - } - - return binds, nil -} - -func (h *HyprlandProvider) buildKeyString(mods, key string) string { - if mods == "" { - return key - } - - modList := strings.FieldsFunc(mods, func(r rune) bool { - return r == '+' || r == ' ' - }) - - parts := append(modList, key) - return strings.Join(parts, "+") -} - -func (h *HyprlandProvider) getBindSortPriority(action string) int { - switch { - case strings.HasPrefix(action, "exec") && strings.Contains(action, "dms"): - return 0 - case strings.Contains(action, "workspace"): - return 1 - case strings.Contains(action, "window") || strings.Contains(action, "focus") || - strings.Contains(action, "move") || strings.Contains(action, "swap") || - strings.Contains(action, "resize"): - return 2 - case strings.Contains(action, "monitor"): - return 3 - case strings.HasPrefix(action, "exec"): - return 4 - case action == "exit" || strings.Contains(action, "dpms"): - return 5 - default: - return 6 - } -} - -func (h *HyprlandProvider) writeOverrideBinds(binds map[string]*hyprlandOverrideBind) error { - overridePath := h.GetOverridePath() - content := h.generateBindsContent(binds) - return os.WriteFile(overridePath, []byte(content), 0o644) -} - -func (h *HyprlandProvider) generateBindsContent(binds map[string]*hyprlandOverrideBind) string { - if len(binds) == 0 { - return "" - } - - bindList := make([]*hyprlandOverrideBind, 0, len(binds)) - for _, bind := range binds { - bindList = append(bindList, bind) - } - - sort.Slice(bindList, func(i, j int) bool { - pi, pj := h.getBindSortPriority(bindList[i].Action), h.getBindSortPriority(bindList[j].Action) - if pi != pj { - return pi < pj - } - return bindList[i].Key < bindList[j].Key - }) - - var sb strings.Builder - for _, bind := range bindList { - h.writeBindLine(&sb, bind) - } - - return sb.String() -} - -func (h *HyprlandProvider) writeBindLine(sb *strings.Builder, bind *hyprlandOverrideBind) { - mods, key := h.parseKeyString(bind.Key) - dispatcher, params := h.parseAction(bind.Action) - - // Write bind type with flags (e.g., "bind", "binde", "bindel") - sb.WriteString("bind") - if bind.Flags != "" { - sb.WriteString(bind.Flags) - } - sb.WriteString(" = ") - sb.WriteString(mods) - sb.WriteString(", ") - sb.WriteString(key) - sb.WriteString(", ") - - // For bindd (description flag), include description before dispatcher - if strings.Contains(bind.Flags, "d") && bind.Description != "" { - sb.WriteString(bind.Description) - sb.WriteString(", ") - } - - sb.WriteString(dispatcher) - - if params != "" { - sb.WriteString(", ") - sb.WriteString(params) - } - - // Only add comment if not using bindd (which has inline description) - if bind.Description != "" && !strings.Contains(bind.Flags, "d") { - sb.WriteString(" # ") - sb.WriteString(bind.Description) - } - - sb.WriteString("\n") -} - -func (h *HyprlandProvider) parseKeyString(keyStr string) (mods, key string) { - parts := strings.Split(keyStr, "+") - switch len(parts) { - case 0: - return "", keyStr - case 1: - return "", parts[0] - default: - return strings.Join(parts[:len(parts)-1], " "), parts[len(parts)-1] - } -} - -func (h *HyprlandProvider) parseAction(action string) (dispatcher, params string) { - parts := strings.SplitN(action, " ", 2) - switch len(parts) { - case 0: - return action, "" - case 1: - dispatcher = parts[0] - default: - dispatcher = parts[0] - params = parts[1] - } - - // Convert internal spawn format to Hyprland's exec - if dispatcher == "spawn" { - dispatcher = "exec" - } - - return dispatcher, params -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser.go deleted file mode 100644 index 04b5ada..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser.go +++ /dev/null @@ -1,627 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -const ( - TitleRegex = "#+!" - HideComment = "[hidden]" - CommentBindPattern = "#/#" -) - -var ModSeparators = []rune{'+', ' '} - -type HyprlandKeyBinding struct { - Mods []string `json:"mods"` - Key string `json:"key"` - Dispatcher string `json:"dispatcher"` - Params string `json:"params"` - Comment string `json:"comment"` - Source string `json:"source"` - Flags string `json:"flags"` // Bind flags: l=locked, r=release, e=repeat, n=non-consuming, m=mouse, t=transparent, i=ignore-mods, s=separate, d=description, o=long-press -} - -type HyprlandSection struct { - Children []HyprlandSection `json:"children"` - Keybinds []HyprlandKeyBinding `json:"keybinds"` - Name string `json:"name"` -} - -type HyprlandParser struct { - contentLines []string - readingLine int - configDir string - currentSource string - dmsBindsExists bool - dmsBindsIncluded bool - includeCount int - dmsIncludePos int - bindsAfterDMS int - dmsBindKeys map[string]bool - configBindKeys map[string]bool - conflictingConfigs map[string]*HyprlandKeyBinding - bindMap map[string]*HyprlandKeyBinding - bindOrder []string - processedFiles map[string]bool - dmsProcessed bool -} - -func NewHyprlandParser(configDir string) *HyprlandParser { - return &HyprlandParser{ - contentLines: []string{}, - readingLine: 0, - configDir: configDir, - dmsIncludePos: -1, - dmsBindKeys: make(map[string]bool), - configBindKeys: make(map[string]bool), - conflictingConfigs: make(map[string]*HyprlandKeyBinding), - bindMap: make(map[string]*HyprlandKeyBinding), - bindOrder: []string{}, - processedFiles: make(map[string]bool), - } -} - -func (p *HyprlandParser) ReadContent(directory string) error { - expandedDir, err := utils.ExpandPath(directory) - if err != nil { - return err - } - - info, err := os.Stat(expandedDir) - if err != nil { - return err - } - if !info.IsDir() { - return os.ErrNotExist - } - - confFiles, err := filepath.Glob(filepath.Join(expandedDir, "*.conf")) - if err != nil { - return err - } - if len(confFiles) == 0 { - return os.ErrNotExist - } - - var combinedContent []string - for _, confFile := range confFiles { - if fileInfo, err := os.Stat(confFile); err == nil && fileInfo.Mode().IsRegular() { - data, err := os.ReadFile(confFile) - if err == nil { - combinedContent = append(combinedContent, string(data)) - } - } - } - - if len(combinedContent) == 0 { - return os.ErrNotExist - } - - fullContent := strings.Join(combinedContent, "\n") - p.contentLines = strings.Split(fullContent, "\n") - return nil -} - -func hyprlandAutogenerateComment(dispatcher, params string) string { - switch dispatcher { - case "resizewindow": - return "Resize window" - - case "movewindow": - if params == "" { - return "Move window" - } - dirMap := map[string]string{ - "l": "left", - "r": "right", - "u": "up", - "d": "down", - } - if dir, ok := dirMap[params]; ok { - return "move in " + dir + " direction" - } - return "move in null direction" - - case "pin": - return "pin (show on all workspaces)" - - case "splitratio": - return "Window split ratio " + params - - case "togglefloating": - return "Float/unfloat window" - - case "resizeactive": - return "Resize window by " + params - - case "killactive": - return "Close window" - - case "fullscreen": - fsMap := map[string]string{ - "0": "fullscreen", - "1": "maximization", - "2": "fullscreen on Hyprland's side", - } - if fs, ok := fsMap[params]; ok { - return "Toggle " + fs - } - return "Toggle null" - - case "fakefullscreen": - return "Toggle fake fullscreen" - - case "workspace": - switch params { - case "+1": - return "focus right" - case "-1": - return "focus left" - } - return "focus workspace " + params - case "movefocus": - dirMap := map[string]string{ - "l": "left", - "r": "right", - "u": "up", - "d": "down", - } - if dir, ok := dirMap[params]; ok { - return "move focus " + dir - } - return "move focus null" - - case "swapwindow": - dirMap := map[string]string{ - "l": "left", - "r": "right", - "u": "up", - "d": "down", - } - if dir, ok := dirMap[params]; ok { - return "swap in " + dir + " direction" - } - return "swap in null direction" - - case "movetoworkspace": - switch params { - case "+1": - return "move to right workspace (non-silent)" - case "-1": - return "move to left workspace (non-silent)" - } - return "move to workspace " + params + " (non-silent)" - case "movetoworkspacesilent": - switch params { - case "+1": - return "move to right workspace" - case "-1": - return "move to right workspace" - } - return "move to workspace " + params - - case "togglespecialworkspace": - return "toggle special" - - case "exec": - return params - - default: - return "" - } -} - -func (p *HyprlandParser) getKeybindAtLine(lineNumber int) *HyprlandKeyBinding { - line := p.contentLines[lineNumber] - return p.parseBindLine(line) -} - -func (p *HyprlandParser) getBindsRecursive(currentContent *HyprlandSection, scope int) *HyprlandSection { - titleRegex := regexp.MustCompile(TitleRegex) - - for p.readingLine < len(p.contentLines) { - line := p.contentLines[p.readingLine] - - loc := titleRegex.FindStringIndex(line) - if loc != nil && loc[0] == 0 { - headingScope := strings.Index(line, "!") - - if headingScope <= scope { - p.readingLine-- - return currentContent - } - - sectionName := strings.TrimSpace(line[headingScope+1:]) - p.readingLine++ - - childSection := &HyprlandSection{ - Children: []HyprlandSection{}, - Keybinds: []HyprlandKeyBinding{}, - Name: sectionName, - } - result := p.getBindsRecursive(childSection, headingScope) - currentContent.Children = append(currentContent.Children, *result) - - } else if strings.HasPrefix(line, CommentBindPattern) { - keybind := p.getKeybindAtLine(p.readingLine) - if keybind != nil { - currentContent.Keybinds = append(currentContent.Keybinds, *keybind) - } - - } else if line == "" || !strings.HasPrefix(strings.TrimSpace(line), "bind") { - - } else { - keybind := p.getKeybindAtLine(p.readingLine) - if keybind != nil { - currentContent.Keybinds = append(currentContent.Keybinds, *keybind) - } - } - - p.readingLine++ - } - - return currentContent -} - -func (p *HyprlandParser) ParseKeys() *HyprlandSection { - p.readingLine = 0 - rootSection := &HyprlandSection{ - Children: []HyprlandSection{}, - Keybinds: []HyprlandKeyBinding{}, - Name: "", - } - return p.getBindsRecursive(rootSection, 0) -} - -func ParseHyprlandKeys(path string) (*HyprlandSection, error) { - parser := NewHyprlandParser(path) - if err := parser.ReadContent(path); err != nil { - return nil, err - } - return parser.ParseKeys(), nil -} - -type HyprlandParseResult struct { - Section *HyprlandSection - DMSBindsIncluded bool - DMSStatus *HyprlandDMSStatus - ConflictingConfigs map[string]*HyprlandKeyBinding -} - -type HyprlandDMSStatus struct { - Exists bool - Included bool - IncludePosition int - TotalIncludes int - BindsAfterDMS int - Effective bool - OverriddenBy int - StatusMessage string -} - -func (p *HyprlandParser) buildDMSStatus() *HyprlandDMSStatus { - status := &HyprlandDMSStatus{ - Exists: p.dmsBindsExists, - Included: p.dmsBindsIncluded, - IncludePosition: p.dmsIncludePos, - TotalIncludes: p.includeCount, - BindsAfterDMS: p.bindsAfterDMS, - } - - switch { - case !p.dmsBindsExists: - status.Effective = false - status.StatusMessage = "dms/binds.conf does not exist" - case !p.dmsBindsIncluded: - status.Effective = false - status.StatusMessage = "dms/binds.conf is not sourced in config" - case p.bindsAfterDMS > 0: - status.Effective = true - status.OverriddenBy = p.bindsAfterDMS - status.StatusMessage = "Some DMS binds may be overridden by config binds" - default: - status.Effective = true - status.StatusMessage = "DMS binds are active" - } - - return status -} - -func (p *HyprlandParser) formatBindKey(kb *HyprlandKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (p *HyprlandParser) normalizeKey(key string) string { - return strings.ToLower(key) -} - -func (p *HyprlandParser) addBind(kb *HyprlandKeyBinding) bool { - key := p.formatBindKey(kb) - normalizedKey := p.normalizeKey(key) - isDMSBind := strings.Contains(kb.Source, "dms/binds.conf") - - if isDMSBind { - p.dmsBindKeys[normalizedKey] = true - } else if p.dmsBindKeys[normalizedKey] { - p.bindsAfterDMS++ - p.conflictingConfigs[normalizedKey] = kb - p.configBindKeys[normalizedKey] = true - return false - } else { - p.configBindKeys[normalizedKey] = true - } - - if _, exists := p.bindMap[normalizedKey]; !exists { - p.bindOrder = append(p.bindOrder, key) - } - p.bindMap[normalizedKey] = kb - return true -} - -func (p *HyprlandParser) ParseWithDMS() (*HyprlandSection, error) { - expandedDir, err := utils.ExpandPath(p.configDir) - if err != nil { - return nil, err - } - - dmsBindsPath := filepath.Join(expandedDir, "dms", "binds.conf") - if _, err := os.Stat(dmsBindsPath); err == nil { - p.dmsBindsExists = true - } - - mainConfig := filepath.Join(expandedDir, "hyprland.conf") - section, err := p.parseFileWithSource(mainConfig, "") - if err != nil { - return nil, err - } - - if p.dmsBindsExists && !p.dmsProcessed { - p.parseDMSBindsDirectly(dmsBindsPath, section) - } - - return section, nil -} - -func (p *HyprlandParser) parseFileWithSource(filePath, sectionName string) (*HyprlandSection, error) { - absPath, err := filepath.Abs(filePath) - if err != nil { - return nil, err - } - - if p.processedFiles[absPath] { - return &HyprlandSection{Name: sectionName}, nil - } - p.processedFiles[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return nil, err - } - - prevSource := p.currentSource - p.currentSource = absPath - - section := &HyprlandSection{Name: sectionName} - lines := strings.Split(string(data), "\n") - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - - if strings.HasPrefix(trimmed, "source") { - p.handleSource(trimmed, section, filepath.Dir(absPath)) - continue - } - - if !strings.HasPrefix(trimmed, "bind") { - continue - } - - kb := p.parseBindLine(line) - if kb == nil { - continue - } - kb.Source = p.currentSource - if p.addBind(kb) { - section.Keybinds = append(section.Keybinds, *kb) - } - } - - p.currentSource = prevSource - return section, nil -} - -func (p *HyprlandParser) handleSource(line string, section *HyprlandSection, baseDir string) { - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - return - } - - sourcePath := strings.TrimSpace(parts[1]) - isDMSSource := sourcePath == "dms/binds.conf" || strings.HasSuffix(sourcePath, "/dms/binds.conf") - - p.includeCount++ - if isDMSSource { - p.dmsBindsIncluded = true - p.dmsIncludePos = p.includeCount - p.dmsProcessed = true - } - - fullPath := sourcePath - if !filepath.IsAbs(sourcePath) { - fullPath = filepath.Join(baseDir, sourcePath) - } - - expanded, err := utils.ExpandPath(fullPath) - if err != nil { - return - } - - includedSection, err := p.parseFileWithSource(expanded, "") - if err != nil { - return - } - - section.Children = append(section.Children, *includedSection) -} - -func (p *HyprlandParser) parseDMSBindsDirectly(dmsBindsPath string, section *HyprlandSection) { - data, err := os.ReadFile(dmsBindsPath) - if err != nil { - return - } - - prevSource := p.currentSource - p.currentSource = dmsBindsPath - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if !strings.HasPrefix(trimmed, "bind") { - continue - } - - kb := p.parseBindLine(line) - if kb == nil { - continue - } - kb.Source = dmsBindsPath - if p.addBind(kb) { - section.Keybinds = append(section.Keybinds, *kb) - } - } - - p.currentSource = prevSource - p.dmsProcessed = true -} - -func (p *HyprlandParser) parseBindLine(line string) *HyprlandKeyBinding { - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - return nil - } - - // Extract bind type and flags from the left side of "=" - bindType := strings.TrimSpace(parts[0]) - flags := extractBindFlags(bindType) - hasDescFlag := strings.Contains(flags, "d") - - keys := parts[1] - keyParts := strings.SplitN(keys, "#", 2) - keys = keyParts[0] - - var comment string - if len(keyParts) > 1 { - comment = strings.TrimSpace(keyParts[1]) - } - - // For bindd, the format is: bindd = MODS, key, description, dispatcher, params - // For regular binds: bind = MODS, key, dispatcher, params - var minFields, descIndex, dispatcherIndex int - if hasDescFlag { - minFields = 4 // mods, key, description, dispatcher - descIndex = 2 - dispatcherIndex = 3 - } else { - minFields = 3 // mods, key, dispatcher - dispatcherIndex = 2 - } - - keyFields := strings.SplitN(keys, ",", minFields+2) // Allow for params - if len(keyFields) < minFields { - return nil - } - - mods := strings.TrimSpace(keyFields[0]) - key := strings.TrimSpace(keyFields[1]) - - var dispatcher, params string - if hasDescFlag { - // bindd format: description is in the bind itself - if comment == "" { - comment = strings.TrimSpace(keyFields[descIndex]) - } - dispatcher = strings.TrimSpace(keyFields[dispatcherIndex]) - if len(keyFields) > dispatcherIndex+1 { - paramParts := keyFields[dispatcherIndex+1:] - params = strings.TrimSpace(strings.Join(paramParts, ",")) - } - } else { - dispatcher = strings.TrimSpace(keyFields[dispatcherIndex]) - if len(keyFields) > dispatcherIndex+1 { - paramParts := keyFields[dispatcherIndex+1:] - params = strings.TrimSpace(strings.Join(paramParts, ",")) - } - } - - if comment != "" && strings.HasPrefix(comment, HideComment) { - return nil - } - - if comment == "" { - comment = hyprlandAutogenerateComment(dispatcher, params) - } - - var modList []string - if mods != "" { - modstring := mods + string(ModSeparators[0]) - idx := 0 - for index, char := range modstring { - isModSep := false - for _, sep := range ModSeparators { - if char == sep { - isModSep = true - break - } - } - if isModSep { - if index-idx > 1 { - modList = append(modList, modstring[idx:index]) - } - idx = index + 1 - } - } - } - - return &HyprlandKeyBinding{ - Mods: modList, - Key: key, - Dispatcher: dispatcher, - Params: params, - Comment: comment, - Flags: flags, - } -} - -// extractBindFlags extracts the flags from a bind type string -// e.g., "binde" -> "e", "bindel" -> "el", "bindd" -> "d" -func extractBindFlags(bindType string) string { - bindType = strings.TrimSpace(bindType) - if !strings.HasPrefix(bindType, "bind") { - return "" - } - return bindType[4:] // Everything after "bind" -} - -func ParseHyprlandKeysWithDMS(path string) (*HyprlandParseResult, error) { - parser := NewHyprlandParser(path) - section, err := parser.ParseWithDMS() - if err != nil { - return nil, err - } - - return &HyprlandParseResult{ - Section: section, - DMSBindsIncluded: parser.dmsBindsIncluded, - DMSStatus: parser.buildDMSStatus(), - ConflictingConfigs: parser.conflictingConfigs, - }, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser_test.go deleted file mode 100644 index c2872e5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_parser_test.go +++ /dev/null @@ -1,519 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestHyprlandAutogenerateComment(t *testing.T) { - tests := []struct { - dispatcher string - params string - expected string - }{ - {"resizewindow", "", "Resize window"}, - {"movewindow", "", "Move window"}, - {"movewindow", "l", "move in left direction"}, - {"movewindow", "r", "move in right direction"}, - {"movewindow", "u", "move in up direction"}, - {"movewindow", "d", "move in down direction"}, - {"pin", "", "pin (show on all workspaces)"}, - {"splitratio", "0.5", "Window split ratio 0.5"}, - {"togglefloating", "", "Float/unfloat window"}, - {"resizeactive", "10 20", "Resize window by 10 20"}, - {"killactive", "", "Close window"}, - {"fullscreen", "0", "Toggle fullscreen"}, - {"fullscreen", "1", "Toggle maximization"}, - {"fullscreen", "2", "Toggle fullscreen on Hyprland's side"}, - {"fakefullscreen", "", "Toggle fake fullscreen"}, - {"workspace", "+1", "focus right"}, - {"workspace", "-1", "focus left"}, - {"workspace", "5", "focus workspace 5"}, - {"movefocus", "l", "move focus left"}, - {"movefocus", "r", "move focus right"}, - {"movefocus", "u", "move focus up"}, - {"movefocus", "d", "move focus down"}, - {"swapwindow", "l", "swap in left direction"}, - {"swapwindow", "r", "swap in right direction"}, - {"swapwindow", "u", "swap in up direction"}, - {"swapwindow", "d", "swap in down direction"}, - {"movetoworkspace", "+1", "move to right workspace (non-silent)"}, - {"movetoworkspace", "-1", "move to left workspace (non-silent)"}, - {"movetoworkspace", "3", "move to workspace 3 (non-silent)"}, - {"movetoworkspacesilent", "+1", "move to right workspace"}, - {"movetoworkspacesilent", "-1", "move to right workspace"}, - {"movetoworkspacesilent", "2", "move to workspace 2"}, - {"togglespecialworkspace", "", "toggle special"}, - {"exec", "firefox", "firefox"}, - {"unknown", "", ""}, - } - - for _, tt := range tests { - t.Run(tt.dispatcher+"_"+tt.params, func(t *testing.T) { - result := hyprlandAutogenerateComment(tt.dispatcher, tt.params) - if result != tt.expected { - t.Errorf("hyprlandAutogenerateComment(%q, %q) = %q, want %q", - tt.dispatcher, tt.params, result, tt.expected) - } - }) - } -} - -func TestHyprlandGetKeybindAtLine(t *testing.T) { - tests := []struct { - name string - line string - expected *HyprlandKeyBinding - }{ - { - name: "basic_keybind", - line: "bind = SUPER, Q, killactive", - expected: &HyprlandKeyBinding{ - Mods: []string{"SUPER"}, - Key: "Q", - Dispatcher: "killactive", - Params: "", - Comment: "Close window", - }, - }, - { - name: "keybind_with_params", - line: "bind = SUPER, left, movefocus, l", - expected: &HyprlandKeyBinding{ - Mods: []string{"SUPER"}, - Key: "left", - Dispatcher: "movefocus", - Params: "l", - Comment: "move focus left", - }, - }, - { - name: "keybind_with_comment", - line: "bind = SUPER, T, exec, kitty # Open terminal", - expected: &HyprlandKeyBinding{ - Mods: []string{"SUPER"}, - Key: "T", - Dispatcher: "exec", - Params: "kitty", - Comment: "Open terminal", - }, - }, - { - name: "keybind_hidden", - line: "bind = SUPER, H, exec, secret # [hidden]", - expected: nil, - }, - { - name: "keybind_multiple_mods", - line: "bind = SUPER+SHIFT, F, fullscreen, 0", - expected: &HyprlandKeyBinding{ - Mods: []string{"SUPER", "SHIFT"}, - Key: "F", - Dispatcher: "fullscreen", - Params: "0", - Comment: "Toggle fullscreen", - }, - }, - { - name: "keybind_no_mods", - line: "bind = , Print, exec, screenshot", - expected: &HyprlandKeyBinding{ - Mods: []string{}, - Key: "Print", - Dispatcher: "exec", - Params: "screenshot", - Comment: "screenshot", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - parser := NewHyprlandParser("") - parser.contentLines = []string{tt.line} - result := parser.getKeybindAtLine(0) - - if tt.expected == nil { - if result != nil { - t.Errorf("expected nil, got %+v", result) - } - return - } - - if result == nil { - t.Errorf("expected %+v, got nil", tt.expected) - return - } - - if result.Key != tt.expected.Key { - t.Errorf("Key = %q, want %q", result.Key, tt.expected.Key) - } - if result.Dispatcher != tt.expected.Dispatcher { - t.Errorf("Dispatcher = %q, want %q", result.Dispatcher, tt.expected.Dispatcher) - } - if result.Params != tt.expected.Params { - t.Errorf("Params = %q, want %q", result.Params, tt.expected.Params) - } - if result.Comment != tt.expected.Comment { - t.Errorf("Comment = %q, want %q", result.Comment, tt.expected.Comment) - } - if len(result.Mods) != len(tt.expected.Mods) { - t.Errorf("Mods length = %d, want %d", len(result.Mods), len(tt.expected.Mods)) - } else { - for i := range result.Mods { - if result.Mods[i] != tt.expected.Mods[i] { - t.Errorf("Mods[%d] = %q, want %q", i, result.Mods[i], tt.expected.Mods[i]) - } - } - } - }) - } -} - -func TestHyprlandParseKeysWithSections(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "hyprland.conf") - - content := `##! Window Management -bind = SUPER, Q, killactive -bind = SUPER, F, fullscreen, 0 - -###! Movement -bind = SUPER, left, movefocus, l -bind = SUPER, right, movefocus, r - -##! Applications -bind = SUPER, T, exec, kitty # Terminal -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseHyprlandKeys(tmpDir) - if err != nil { - t.Fatalf("ParseHyprlandKeys failed: %v", err) - } - - if len(section.Children) != 2 { - t.Errorf("Expected 2 top-level sections, got %d", len(section.Children)) - } - - if len(section.Children) >= 1 { - windowMgmt := section.Children[0] - if windowMgmt.Name != "Window Management" { - t.Errorf("First section name = %q, want %q", windowMgmt.Name, "Window Management") - } - if len(windowMgmt.Keybinds) != 2 { - t.Errorf("Window Management keybinds = %d, want 2", len(windowMgmt.Keybinds)) - } - - if len(windowMgmt.Children) != 1 { - t.Errorf("Window Management children = %d, want 1", len(windowMgmt.Children)) - } else { - movement := windowMgmt.Children[0] - if movement.Name != "Movement" { - t.Errorf("Movement section name = %q, want %q", movement.Name, "Movement") - } - if len(movement.Keybinds) != 2 { - t.Errorf("Movement keybinds = %d, want 2", len(movement.Keybinds)) - } - } - } - - if len(section.Children) >= 2 { - apps := section.Children[1] - if apps.Name != "Applications" { - t.Errorf("Second section name = %q, want %q", apps.Name, "Applications") - } - if len(apps.Keybinds) != 1 { - t.Errorf("Applications keybinds = %d, want 1", len(apps.Keybinds)) - } - if len(apps.Keybinds) > 0 && apps.Keybinds[0].Comment != "Terminal" { - t.Errorf("Applications keybind comment = %q, want %q", apps.Keybinds[0].Comment, "Terminal") - } - } -} - -func TestHyprlandParseKeysWithCommentBinds(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "test.conf") - - content := `#/# = SUPER, A, exec, app1 -bind = SUPER, B, exec, app2 -#/# = SUPER, C, exec, app3 # Custom comment -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseHyprlandKeys(tmpDir) - if err != nil { - t.Fatalf("ParseHyprlandKeys failed: %v", err) - } - - if len(section.Keybinds) != 3 { - t.Errorf("Expected 3 keybinds, got %d", len(section.Keybinds)) - } - - if len(section.Keybinds) > 0 && section.Keybinds[0].Key != "A" { - t.Errorf("First keybind key = %q, want %q", section.Keybinds[0].Key, "A") - } - if len(section.Keybinds) > 1 && section.Keybinds[1].Key != "B" { - t.Errorf("Second keybind key = %q, want %q", section.Keybinds[1].Key, "B") - } - if len(section.Keybinds) > 2 && section.Keybinds[2].Comment != "Custom comment" { - t.Errorf("Third keybind comment = %q, want %q", section.Keybinds[2].Comment, "Custom comment") - } -} - -func TestHyprlandReadContentMultipleFiles(t *testing.T) { - tmpDir := t.TempDir() - - file1 := filepath.Join(tmpDir, "a.conf") - file2 := filepath.Join(tmpDir, "b.conf") - - content1 := "bind = SUPER, Q, killactive\n" - content2 := "bind = SUPER, T, exec, kitty\n" - - if err := os.WriteFile(file1, []byte(content1), 0o644); err != nil { - t.Fatalf("Failed to write file1: %v", err) - } - if err := os.WriteFile(file2, []byte(content2), 0o644); err != nil { - t.Fatalf("Failed to write file2: %v", err) - } - - parser := NewHyprlandParser("") - if err := parser.ReadContent(tmpDir); err != nil { - t.Fatalf("ReadContent failed: %v", err) - } - - section := parser.ParseKeys() - if len(section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds from multiple files, got %d", len(section.Keybinds)) - } -} - -func TestHyprlandReadContentErrors(t *testing.T) { - tests := []struct { - name string - path string - }{ - { - name: "nonexistent_directory", - path: "/nonexistent/path/that/does/not/exist", - }, - { - name: "empty_directory", - path: t.TempDir(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := ParseHyprlandKeys(tt.path) - if err == nil { - t.Error("Expected error, got nil") - } - }) - } -} - -func TestHyprlandReadContentWithTildeExpansion(t *testing.T) { - homeDir, err := os.UserHomeDir() - if err != nil { - t.Skip("Cannot get home directory") - } - - tmpSubdir := filepath.Join(homeDir, ".config", "test-hypr-"+t.Name()) - if err := os.MkdirAll(tmpSubdir, 0o755); err != nil { - t.Skip("Cannot create test directory in home") - } - defer os.RemoveAll(tmpSubdir) - - configFile := filepath.Join(tmpSubdir, "test.conf") - if err := os.WriteFile(configFile, []byte("bind = SUPER, Q, killactive\n"), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - relPath, err := filepath.Rel(homeDir, tmpSubdir) - if err != nil { - t.Skip("Cannot create relative path") - } - - parser := NewHyprlandParser("") - tildePathMatch := "~/" + relPath - err = parser.ReadContent(tildePathMatch) - - if err != nil { - t.Errorf("ReadContent with tilde path failed: %v", err) - } -} - -func TestHyprlandKeybindWithParamsContainingCommas(t *testing.T) { - parser := NewHyprlandParser("") - parser.contentLines = []string{"bind = SUPER, R, exec, notify-send 'Title' 'Message, with comma'"} - - result := parser.getKeybindAtLine(0) - - if result == nil { - t.Fatal("Expected keybind, got nil") - } - - expected := "notify-send 'Title' 'Message, with comma'" - if result.Params != expected { - t.Errorf("Params = %q, want %q", result.Params, expected) - } -} - -func TestHyprlandEmptyAndCommentLines(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "test.conf") - - content := ` -# This is a comment -bind = SUPER, Q, killactive - -# Another comment - -bind = SUPER, T, exec, kitty -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseHyprlandKeys(tmpDir) - if err != nil { - t.Fatalf("ParseHyprlandKeys failed: %v", err) - } - - if len(section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(section.Keybinds)) - } -} - -func TestExtractBindFlags(t *testing.T) { - tests := []struct { - bindType string - expected string - }{ - {"bind", ""}, - {"binde", "e"}, - {"bindl", "l"}, - {"bindr", "r"}, - {"bindd", "d"}, - {"bindo", "o"}, - {"bindel", "el"}, - {"bindler", "ler"}, - {"bindem", "em"}, - {" bind ", ""}, - {" binde ", "e"}, - {"notbind", ""}, - {"", ""}, - } - - for _, tt := range tests { - t.Run(tt.bindType, func(t *testing.T) { - result := extractBindFlags(tt.bindType) - if result != tt.expected { - t.Errorf("extractBindFlags(%q) = %q, want %q", tt.bindType, result, tt.expected) - } - }) - } -} - -func TestHyprlandBindFlags(t *testing.T) { - tests := []struct { - name string - line string - expectedFlags string - expectedKey string - expectedDisp string - expectedDesc string - }{ - { - name: "regular bind", - line: "bind = SUPER, Q, killactive", - expectedFlags: "", - expectedKey: "Q", - expectedDisp: "killactive", - expectedDesc: "Close window", - }, - { - name: "binde (repeat on hold)", - line: "binde = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", - expectedFlags: "e", - expectedKey: "XF86AudioRaiseVolume", - expectedDisp: "exec", - expectedDesc: "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", - }, - { - name: "bindl (locked/inhibitor bypass)", - line: "bindl = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-", - expectedFlags: "l", - expectedKey: "XF86AudioLowerVolume", - expectedDisp: "exec", - expectedDesc: "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-", - }, - { - name: "bindr (release trigger)", - line: "bindr = SUPER, SUPER_L, exec, pkill wofi || wofi", - expectedFlags: "r", - expectedKey: "SUPER_L", - expectedDisp: "exec", - expectedDesc: "pkill wofi || wofi", - }, - { - name: "bindd (description)", - line: "bindd = SUPER, Q, Open my favourite terminal, exec, kitty", - expectedFlags: "d", - expectedKey: "Q", - expectedDisp: "exec", - expectedDesc: "Open my favourite terminal", - }, - { - name: "bindo (long press)", - line: "bindo = SUPER, XF86AudioNext, exec, playerctl next", - expectedFlags: "o", - expectedKey: "XF86AudioNext", - expectedDisp: "exec", - expectedDesc: "playerctl next", - }, - { - name: "bindel (combined flags)", - line: "bindel = , XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+", - expectedFlags: "el", - expectedKey: "XF86AudioRaiseVolume", - expectedDisp: "exec", - expectedDesc: "wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - parser := NewHyprlandParser("") - parser.contentLines = []string{tt.line} - result := parser.getKeybindAtLine(0) - - if result == nil { - t.Fatal("Expected keybind, got nil") - } - - if result.Flags != tt.expectedFlags { - t.Errorf("Flags = %q, want %q", result.Flags, tt.expectedFlags) - } - if result.Key != tt.expectedKey { - t.Errorf("Key = %q, want %q", result.Key, tt.expectedKey) - } - if result.Dispatcher != tt.expectedDisp { - t.Errorf("Dispatcher = %q, want %q", result.Dispatcher, tt.expectedDisp) - } - if result.Comment != tt.expectedDesc { - t.Errorf("Comment = %q, want %q", result.Comment, tt.expectedDesc) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_test.go deleted file mode 100644 index 90dfe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/hyprland_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestNewHyprlandProvider(t *testing.T) { - t.Run("custom path", func(t *testing.T) { - p := NewHyprlandProvider("/custom/path") - if p == nil { - t.Fatal("NewHyprlandProvider returned nil") - } - if p.configPath != "/custom/path" { - t.Errorf("configPath = %q, want %q", p.configPath, "/custom/path") - } - }) - - t.Run("empty path defaults", func(t *testing.T) { - p := NewHyprlandProvider("") - if p == nil { - t.Fatal("NewHyprlandProvider returned nil") - } - configDir, err := os.UserConfigDir() - if err != nil { - t.Fatalf("UserConfigDir failed: %v", err) - } - expected := filepath.Join(configDir, "hypr") - if p.configPath != expected { - t.Errorf("configPath = %q, want %q", p.configPath, expected) - } - }) -} - -func TestHyprlandProviderName(t *testing.T) { - p := NewHyprlandProvider("") - if p.Name() != "hyprland" { - t.Errorf("Name() = %q, want %q", p.Name(), "hyprland") - } -} - -func TestHyprlandProviderGetCheatSheet(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "hyprland.conf") - - content := `##! Window Management -bind = SUPER, Q, killactive -bind = SUPER, F, fullscreen, 0 - -###! Movement -bind = SUPER, left, movefocus, l -bind = SUPER, right, movefocus, r - -##! Applications -bind = SUPER, T, exec, kitty # Terminal -bind = SUPER, 1, workspace, 1 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - p := NewHyprlandProvider(tmpDir) - sheet, err := p.GetCheatSheet() - - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if sheet.Title != "Hyprland Keybinds" { - t.Errorf("Title = %q, want %q", sheet.Title, "Hyprland Keybinds") - } - - if sheet.Provider != "hyprland" { - t.Errorf("Provider = %q, want %q", sheet.Provider, "hyprland") - } - - if len(sheet.Binds) == 0 { - t.Error("expected categorized bindings, got none") - } - - if windowBinds, ok := sheet.Binds["Window"]; !ok || len(windowBinds) == 0 { - t.Error("expected Window category with bindings") - } - - if execBinds, ok := sheet.Binds["Execute"]; !ok || len(execBinds) == 0 { - t.Error("expected Execute category with bindings") - } - - if wsBinds, ok := sheet.Binds["Workspace"]; !ok || len(wsBinds) == 0 { - t.Error("expected Workspace category with bindings") - } -} - -func TestHyprlandProviderGetCheatSheetError(t *testing.T) { - p := NewHyprlandProvider("/nonexistent/path") - _, err := p.GetCheatSheet() - - if err == nil { - t.Error("expected error for nonexistent path, got nil") - } -} - -func TestFormatKey(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "hyprland.conf") - - tests := []struct { - name string - content string - expected string - category string - }{ - { - name: "single mod", - content: "bind = SUPER, Q, killactive", - expected: "SUPER+Q", - category: "Window", - }, - { - name: "multiple mods", - content: "bind = SUPER+SHIFT, F, fullscreen, 0", - expected: "SUPER+SHIFT+F", - category: "Window", - }, - { - name: "no mods", - content: "bind = , Print, exec, screenshot", - expected: "Print", - category: "Execute", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := os.WriteFile(configFile, []byte(tt.content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - p := NewHyprlandProvider(tmpDir) - sheet, err := p.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - categoryBinds, ok := sheet.Binds[tt.category] - if !ok || len(categoryBinds) == 0 { - t.Fatalf("expected binds in category %q", tt.category) - } - - if categoryBinds[0].Key != tt.expected { - t.Errorf("Key = %q, want %q", categoryBinds[0].Key, tt.expected) - } - }) - } -} - -func TestDescriptionFallback(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "hyprland.conf") - - tests := []struct { - name string - content string - wantDesc string - }{ - { - name: "autogenerated description for known dispatcher", - content: "bind = SUPER, Q, killactive", - wantDesc: "Close window", - }, - { - name: "custom comment overrides autogeneration", - content: "bind = SUPER, T, exec, kitty # Open terminal", - wantDesc: "Open terminal", - }, - { - name: "fallback for unknown dispatcher without params", - content: "bind = SUPER, W, unknowndispatcher", - wantDesc: "unknowndispatcher", - }, - { - name: "fallback for unknown dispatcher with params", - content: "bind = SUPER, X, customdispatcher, arg1", - wantDesc: "customdispatcher arg1", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := os.WriteFile(configFile, []byte(tt.content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - p := NewHyprlandProvider(tmpDir) - sheet, err := p.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - found := false - for _, binds := range sheet.Binds { - for _, bind := range binds { - if bind.Description == tt.wantDesc { - found = true - break - } - } - if found { - break - } - } - - if !found { - t.Errorf("expected description %q not found in any bind", tt.wantDesc) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile.go deleted file mode 100644 index 08cf449..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile.go +++ /dev/null @@ -1,119 +0,0 @@ -package providers - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type JSONFileProvider struct { - filePath string - name string -} - -func NewJSONFileProvider(filePath string) (*JSONFileProvider, error) { - if filePath == "" { - return nil, fmt.Errorf("file path cannot be empty") - } - - expandedPath, err := utils.ExpandPath(filePath) - if err != nil { - return nil, fmt.Errorf("failed to expand path: %w", err) - } - - name := filepath.Base(expandedPath) - name = name[:len(name)-len(filepath.Ext(name))] - - return &JSONFileProvider{ - filePath: expandedPath, - name: name, - }, nil -} - -func (j *JSONFileProvider) Name() string { - return j.name -} - -func (j *JSONFileProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - data, err := os.ReadFile(j.filePath) - if err != nil { - return nil, fmt.Errorf("failed to read file: %w", err) - } - - var rawData map[string]any - if err := json.Unmarshal(data, &rawData); err != nil { - return nil, fmt.Errorf("failed to parse JSON: %w", err) - } - - title, _ := rawData["title"].(string) - provider, _ := rawData["provider"].(string) - if provider == "" { - provider = j.name - } - - categorizedBinds := make(map[string][]keybinds.Keybind) - - bindsRaw, ok := rawData["binds"] - if !ok { - return nil, fmt.Errorf("missing 'binds' field") - } - - switch binds := bindsRaw.(type) { - case map[string]any: - for category, categoryBindsRaw := range binds { - categoryBindsList, ok := categoryBindsRaw.([]any) - if !ok { - continue - } - - var keybindsList []keybinds.Keybind - categoryBindsJSON, _ := json.Marshal(categoryBindsList) - if err := json.Unmarshal(categoryBindsJSON, &keybindsList); err != nil { - continue - } - - categorizedBinds[category] = keybindsList - } - - case []any: - flatBindsJSON, _ := json.Marshal(binds) - var flatBinds []struct { - Key string `json:"key"` - Description string `json:"desc"` - Action string `json:"action,omitempty"` - Category string `json:"cat,omitempty"` - Subcategory string `json:"subcat,omitempty"` - } - if err := json.Unmarshal(flatBindsJSON, &flatBinds); err != nil { - return nil, fmt.Errorf("failed to parse flat binds array: %w", err) - } - - for _, bind := range flatBinds { - category := bind.Category - if category == "" { - category = "Other" - } - - kb := keybinds.Keybind{ - Key: bind.Key, - Description: bind.Description, - Action: bind.Action, - Subcategory: bind.Subcategory, - } - categorizedBinds[category] = append(categorizedBinds[category], kb) - } - - default: - return nil, fmt.Errorf("'binds' must be either an object (categorized) or array (flat)") - } - - return &keybinds.CheatSheet{ - Title: title, - Provider: provider, - Binds: categorizedBinds, - }, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile_test.go deleted file mode 100644 index ded4385..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/jsonfile_test.go +++ /dev/null @@ -1,281 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func TestNewJSONFileProvider(t *testing.T) { - tmpDir := t.TempDir() - testFile := filepath.Join(tmpDir, "test.json") - - if err := os.WriteFile(testFile, []byte("{}"), 0o644); err != nil { - t.Fatalf("Failed to create test file: %v", err) - } - - tests := []struct { - name string - filePath string - expectError bool - wantName string - }{ - { - name: "valid file", - filePath: testFile, - expectError: false, - wantName: "test", - }, - { - name: "empty path", - filePath: "", - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - p, err := NewJSONFileProvider(tt.filePath) - - if tt.expectError { - if err == nil { - t.Error("expected error, got nil") - } - return - } - - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - if p.Name() != tt.wantName { - t.Errorf("Name() = %q, want %q", p.Name(), tt.wantName) - } - }) - } -} - -func TestJSONFileProviderGetCheatSheet(t *testing.T) { - tmpDir := t.TempDir() - testFile := filepath.Join(tmpDir, "tmux.json") - - content := `{ - "title": "Tmux Binds", - "provider": "tmux", - "binds": { - "Pane": [ - { - "key": "Ctrl+Alt+J", - "desc": "Resize split downward", - "subcat": "Sizing" - }, - { - "key": "Ctrl+K", - "desc": "Move Focus Up", - "subcat": "Navigation" - } - ] - } -}` - - if err := os.WriteFile(testFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test file: %v", err) - } - - p, err := NewJSONFileProvider(testFile) - if err != nil { - t.Fatalf("NewJSONFileProvider failed: %v", err) - } - - sheet, err := p.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if sheet.Title != "Tmux Binds" { - t.Errorf("Title = %q, want %q", sheet.Title, "Tmux Binds") - } - - if sheet.Provider != "tmux" { - t.Errorf("Provider = %q, want %q", sheet.Provider, "tmux") - } - - paneBinds, ok := sheet.Binds["Pane"] - if !ok { - t.Fatal("expected Pane category") - } - - if len(paneBinds) != 2 { - t.Errorf("len(Pane binds) = %d, want 2", len(paneBinds)) - } - - if len(paneBinds) > 0 { - bind := paneBinds[0] - if bind.Key != "Ctrl+Alt+J" { - t.Errorf("Pane[0].Key = %q, want %q", bind.Key, "Ctrl+Alt+J") - } - if bind.Description != "Resize split downward" { - t.Errorf("Pane[0].Description = %q, want %q", bind.Description, "Resize split downward") - } - if bind.Subcategory != "Sizing" { - t.Errorf("Pane[0].Subcategory = %q, want %q", bind.Subcategory, "Sizing") - } - } -} - -func TestJSONFileProviderGetCheatSheetNoProvider(t *testing.T) { - tmpDir := t.TempDir() - testFile := filepath.Join(tmpDir, "custom.json") - - content := `{ - "title": "Custom Binds", - "binds": {} -}` - - if err := os.WriteFile(testFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test file: %v", err) - } - - p, err := NewJSONFileProvider(testFile) - if err != nil { - t.Fatalf("NewJSONFileProvider failed: %v", err) - } - - sheet, err := p.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if sheet.Provider != "custom" { - t.Errorf("Provider = %q, want %q (should default to filename)", sheet.Provider, "custom") - } -} - -func TestJSONFileProviderFlatArrayBackwardsCompat(t *testing.T) { - tmpDir := t.TempDir() - testFile := filepath.Join(tmpDir, "legacy.json") - - content := `{ - "title": "Legacy Format", - "provider": "legacy", - "binds": [ - { - "key": "Ctrl+S", - "desc": "Save file", - "cat": "File", - "subcat": "Operations" - }, - { - "key": "Ctrl+O", - "desc": "Open file", - "cat": "File" - }, - { - "key": "Ctrl+Q", - "desc": "Quit", - "subcat": "Exit" - } - ] -}` - - if err := os.WriteFile(testFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test file: %v", err) - } - - p, err := NewJSONFileProvider(testFile) - if err != nil { - t.Fatalf("NewJSONFileProvider failed: %v", err) - } - - sheet, err := p.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - fileBinds, ok := sheet.Binds["File"] - if !ok || len(fileBinds) != 2 { - t.Errorf("expected 2 binds in File category, got %d", len(fileBinds)) - } - - otherBinds, ok := sheet.Binds["Other"] - if !ok || len(otherBinds) != 1 { - t.Errorf("expected 1 bind in Other category (no cat specified), got %d", len(otherBinds)) - } - - if len(fileBinds) > 0 { - if fileBinds[0].Subcategory != "Operations" { - t.Errorf("expected subcategory %q, got %q", "Operations", fileBinds[0].Subcategory) - } - } -} - -func TestJSONFileProviderInvalidJSON(t *testing.T) { - tmpDir := t.TempDir() - testFile := filepath.Join(tmpDir, "invalid.json") - - if err := os.WriteFile(testFile, []byte("not valid json"), 0o644); err != nil { - t.Fatalf("Failed to write test file: %v", err) - } - - p, err := NewJSONFileProvider(testFile) - if err != nil { - t.Fatalf("NewJSONFileProvider failed: %v", err) - } - - _, err = p.GetCheatSheet() - if err == nil { - t.Error("expected error for invalid JSON, got nil") - } -} - -func TestJSONFileProviderNonexistentFile(t *testing.T) { - p, err := NewJSONFileProvider("/nonexistent/file.json") - if err != nil { - t.Fatalf("NewJSONFileProvider failed: %v", err) - } - - _, err = p.GetCheatSheet() - if err == nil { - t.Error("expected error for nonexistent file, got nil") - } -} - -func TestExpandPath(t *testing.T) { - home, err := os.UserHomeDir() - if err != nil { - t.Skip("Cannot get home directory") - } - - tests := []struct { - name string - input string - expected string - }{ - { - name: "tilde expansion", - input: "~/test", - expected: filepath.Join(home, "test"), - }, - { - name: "no expansion needed", - input: "/absolute/path", - expected: "/absolute/path", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := utils.ExpandPath(tt.input) - if err != nil { - t.Fatalf("expandPath failed: %v", err) - } - - if result != tt.expected { - t.Errorf("utils.ExpandPath(%q) = %q, want %q", tt.input, result, tt.expected) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc.go deleted file mode 100644 index 348ee7c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc.go +++ /dev/null @@ -1,442 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type MangoWCProvider struct { - configPath string - dmsBindsIncluded bool - parsed bool -} - -func NewMangoWCProvider(configPath string) *MangoWCProvider { - if configPath == "" { - configPath = defaultMangoWCConfigDir() - } - return &MangoWCProvider{ - configPath: configPath, - } -} - -func defaultMangoWCConfigDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - return "" - } - return filepath.Join(configDir, "mango") -} - -func (m *MangoWCProvider) Name() string { - return "mangowc" -} - -func (m *MangoWCProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - result, err := ParseMangoWCKeysWithDMS(m.configPath) - if err != nil { - return nil, fmt.Errorf("failed to parse mangowc config: %w", err) - } - - m.dmsBindsIncluded = result.DMSBindsIncluded - m.parsed = true - - categorizedBinds := make(map[string][]keybinds.Keybind) - for _, kb := range result.Keybinds { - category := m.categorizeByCommand(kb.Command) - bind := m.convertKeybind(&kb, result.ConflictingConfigs) - categorizedBinds[category] = append(categorizedBinds[category], bind) - } - - sheet := &keybinds.CheatSheet{ - Title: "MangoWC Keybinds", - Provider: m.Name(), - Binds: categorizedBinds, - DMSBindsIncluded: result.DMSBindsIncluded, - } - - if result.DMSStatus != nil { - sheet.DMSStatus = &keybinds.DMSBindsStatus{ - Exists: result.DMSStatus.Exists, - Included: result.DMSStatus.Included, - IncludePosition: result.DMSStatus.IncludePosition, - TotalIncludes: result.DMSStatus.TotalIncludes, - BindsAfterDMS: result.DMSStatus.BindsAfterDMS, - Effective: result.DMSStatus.Effective, - OverriddenBy: result.DMSStatus.OverriddenBy, - StatusMessage: result.DMSStatus.StatusMessage, - } - } - - return sheet, nil -} - -func (m *MangoWCProvider) HasDMSBindsIncluded() bool { - if m.parsed { - return m.dmsBindsIncluded - } - - result, err := ParseMangoWCKeysWithDMS(m.configPath) - if err != nil { - return false - } - - m.dmsBindsIncluded = result.DMSBindsIncluded - m.parsed = true - return m.dmsBindsIncluded -} - -func (m *MangoWCProvider) categorizeByCommand(command string) string { - switch { - case strings.Contains(command, "mon"): - return "Monitor" - case command == "toggleoverview": - return "Overview" - case command == "toggle_scratchpad": - return "Scratchpad" - case strings.Contains(command, "layout") || strings.Contains(command, "proportion"): - return "Layout" - case strings.Contains(command, "gaps"): - return "Gaps" - case strings.Contains(command, "view") || strings.Contains(command, "tag"): - return "Tags" - case command == "focusstack" || - command == "focusdir" || - command == "exchange_client" || - command == "killclient" || - command == "togglefloating" || - command == "togglefullscreen" || - command == "togglefakefullscreen" || - command == "togglemaximizescreen" || - command == "toggleglobal" || - command == "toggleoverlay" || - command == "minimized" || - command == "restore_minimized" || - command == "movewin" || - command == "resizewin": - return "Window" - case command == "spawn" || command == "spawn_shell": - return "Execute" - case command == "quit" || command == "reload_config": - return "System" - default: - return "Other" - } -} - -func (m *MangoWCProvider) convertKeybind(kb *MangoWCKeyBinding, conflicts map[string]*MangoWCKeyBinding) keybinds.Keybind { - keyStr := m.formatKey(kb) - rawAction := m.formatRawAction(kb.Command, kb.Params) - desc := kb.Comment - - if desc == "" { - desc = rawAction - } - - source := "config" - if strings.Contains(kb.Source, "dms/binds.conf") || strings.Contains(kb.Source, "dms"+string(filepath.Separator)+"binds.conf") { - source = "dms" - } - - bind := keybinds.Keybind{ - Key: keyStr, - Description: desc, - Action: rawAction, - Source: source, - } - - if source == "dms" && conflicts != nil { - normalizedKey := strings.ToLower(keyStr) - if conflictKb, ok := conflicts[normalizedKey]; ok { - bind.Conflict = &keybinds.Keybind{ - Key: keyStr, - Description: conflictKb.Comment, - Action: m.formatRawAction(conflictKb.Command, conflictKb.Params), - Source: "config", - } - } - } - - return bind -} - -func (m *MangoWCProvider) formatRawAction(command, params string) string { - if params != "" { - return command + " " + params - } - return command -} - -func (m *MangoWCProvider) formatKey(kb *MangoWCKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (m *MangoWCProvider) GetOverridePath() string { - expanded, err := utils.ExpandPath(m.configPath) - if err != nil { - return filepath.Join(m.configPath, "dms", "binds.conf") - } - return filepath.Join(expanded, "dms", "binds.conf") -} - -func (m *MangoWCProvider) validateAction(action string) error { - action = strings.TrimSpace(action) - switch { - case action == "": - return fmt.Errorf("action cannot be empty") - case action == "spawn" || action == "spawn ": - return fmt.Errorf("spawn command requires arguments") - case action == "spawn_shell" || action == "spawn_shell ": - return fmt.Errorf("spawn_shell command requires arguments") - case strings.HasPrefix(action, "spawn "): - rest := strings.TrimSpace(strings.TrimPrefix(action, "spawn ")) - if rest == "" { - return fmt.Errorf("spawn command requires arguments") - } - case strings.HasPrefix(action, "spawn_shell "): - rest := strings.TrimSpace(strings.TrimPrefix(action, "spawn_shell ")) - if rest == "" { - return fmt.Errorf("spawn_shell command requires arguments") - } - } - return nil -} - -func (m *MangoWCProvider) SetBind(key, action, description string, options map[string]any) error { - if err := m.validateAction(action); err != nil { - return err - } - - overridePath := m.GetOverridePath() - - if err := os.MkdirAll(filepath.Dir(overridePath), 0o755); err != nil { - return fmt.Errorf("failed to create dms directory: %w", err) - } - - existingBinds, err := m.loadOverrideBinds() - if err != nil { - existingBinds = make(map[string]*mangowcOverrideBind) - } - - normalizedKey := strings.ToLower(key) - existingBinds[normalizedKey] = &mangowcOverrideBind{ - Key: key, - Action: action, - Description: description, - Options: options, - } - - return m.writeOverrideBinds(existingBinds) -} - -func (m *MangoWCProvider) RemoveBind(key string) error { - existingBinds, err := m.loadOverrideBinds() - if err != nil { - return nil - } - - normalizedKey := strings.ToLower(key) - delete(existingBinds, normalizedKey) - return m.writeOverrideBinds(existingBinds) -} - -type mangowcOverrideBind struct { - Key string - Action string - Description string - Options map[string]any -} - -func (m *MangoWCProvider) loadOverrideBinds() (map[string]*mangowcOverrideBind, error) { - overridePath := m.GetOverridePath() - binds := make(map[string]*mangowcOverrideBind) - - data, err := os.ReadFile(overridePath) - if os.IsNotExist(err) { - return binds, nil - } - if err != nil { - return nil, err - } - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - - if !strings.HasPrefix(line, "bind") { - continue - } - - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - continue - } - - content := strings.TrimSpace(parts[1]) - commentParts := strings.SplitN(content, "#", 2) - bindContent := strings.TrimSpace(commentParts[0]) - - var comment string - if len(commentParts) > 1 { - comment = strings.TrimSpace(commentParts[1]) - } - - fields := strings.SplitN(bindContent, ",", 4) - if len(fields) < 3 { - continue - } - - mods := strings.TrimSpace(fields[0]) - keyName := strings.TrimSpace(fields[1]) - command := strings.TrimSpace(fields[2]) - - var params string - if len(fields) > 3 { - params = strings.TrimSpace(fields[3]) - } - - keyStr := m.buildKeyString(mods, keyName) - normalizedKey := strings.ToLower(keyStr) - action := command - if params != "" { - action = command + " " + params - } - - binds[normalizedKey] = &mangowcOverrideBind{ - Key: keyStr, - Action: action, - Description: comment, - } - } - - return binds, nil -} - -func (m *MangoWCProvider) buildKeyString(mods, key string) string { - if mods == "" || strings.EqualFold(mods, "none") { - return key - } - - modList := strings.FieldsFunc(mods, func(r rune) bool { - return r == '+' || r == ' ' - }) - - parts := append(modList, key) - return strings.Join(parts, "+") -} - -func (m *MangoWCProvider) getBindSortPriority(action string) int { - switch { - case strings.HasPrefix(action, "spawn") && strings.Contains(action, "dms"): - return 0 - case strings.Contains(action, "view") || strings.Contains(action, "tag"): - return 1 - case strings.Contains(action, "focus") || strings.Contains(action, "exchange") || - strings.Contains(action, "resize") || strings.Contains(action, "move"): - return 2 - case strings.Contains(action, "mon"): - return 3 - case strings.HasPrefix(action, "spawn"): - return 4 - case action == "quit" || action == "reload_config": - return 5 - default: - return 6 - } -} - -func (m *MangoWCProvider) writeOverrideBinds(binds map[string]*mangowcOverrideBind) error { - overridePath := m.GetOverridePath() - content := m.generateBindsContent(binds) - return os.WriteFile(overridePath, []byte(content), 0o644) -} - -func (m *MangoWCProvider) generateBindsContent(binds map[string]*mangowcOverrideBind) string { - if len(binds) == 0 { - return "" - } - - bindList := make([]*mangowcOverrideBind, 0, len(binds)) - for _, bind := range binds { - bindList = append(bindList, bind) - } - - sort.Slice(bindList, func(i, j int) bool { - pi, pj := m.getBindSortPriority(bindList[i].Action), m.getBindSortPriority(bindList[j].Action) - if pi != pj { - return pi < pj - } - return bindList[i].Key < bindList[j].Key - }) - - var sb strings.Builder - for _, bind := range bindList { - m.writeBindLine(&sb, bind) - } - - return sb.String() -} - -func (m *MangoWCProvider) writeBindLine(sb *strings.Builder, bind *mangowcOverrideBind) { - mods, key := m.parseKeyString(bind.Key) - command, params := m.parseAction(bind.Action) - - sb.WriteString("bind=") - if mods == "" { - sb.WriteString("none") - } else { - sb.WriteString(mods) - } - sb.WriteString(",") - sb.WriteString(key) - sb.WriteString(",") - sb.WriteString(command) - - if params != "" { - sb.WriteString(",") - sb.WriteString(params) - } - - if bind.Description != "" { - sb.WriteString(" # ") - sb.WriteString(bind.Description) - } - - sb.WriteString("\n") -} - -func (m *MangoWCProvider) parseKeyString(keyStr string) (mods, key string) { - parts := strings.Split(keyStr, "+") - switch len(parts) { - case 0: - return "", keyStr - case 1: - return "", parts[0] - default: - return strings.Join(parts[:len(parts)-1], "+"), parts[len(parts)-1] - } -} - -func (m *MangoWCProvider) parseAction(action string) (command, params string) { - parts := strings.SplitN(action, " ", 2) - switch len(parts) { - case 0: - return action, "" - case 1: - return parts[0], "" - default: - return parts[0], parts[1] - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser.go deleted file mode 100644 index 5dac4b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser.go +++ /dev/null @@ -1,613 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -const ( - MangoWCHideComment = "[hidden]" -) - -var MangoWCModSeparators = []rune{'+', ' '} - -type MangoWCKeyBinding struct { - Mods []string `json:"mods"` - Key string `json:"key"` - Command string `json:"command"` - Params string `json:"params"` - Comment string `json:"comment"` - Source string `json:"source"` -} - -type MangoWCParser struct { - contentLines []string - readingLine int - configDir string - currentSource string - dmsBindsExists bool - dmsBindsIncluded bool - includeCount int - dmsIncludePos int - bindsAfterDMS int - dmsBindKeys map[string]bool - configBindKeys map[string]bool - conflictingConfigs map[string]*MangoWCKeyBinding - bindMap map[string]*MangoWCKeyBinding - bindOrder []string - processedFiles map[string]bool - dmsProcessed bool -} - -func NewMangoWCParser(configDir string) *MangoWCParser { - return &MangoWCParser{ - contentLines: []string{}, - readingLine: 0, - configDir: configDir, - dmsIncludePos: -1, - dmsBindKeys: make(map[string]bool), - configBindKeys: make(map[string]bool), - conflictingConfigs: make(map[string]*MangoWCKeyBinding), - bindMap: make(map[string]*MangoWCKeyBinding), - bindOrder: []string{}, - processedFiles: make(map[string]bool), - } -} - -func (p *MangoWCParser) ReadContent(path string) error { - expandedPath, err := utils.ExpandPath(path) - if err != nil { - return err - } - - info, err := os.Stat(expandedPath) - if err != nil { - return err - } - - var files []string - if info.IsDir() { - confFiles, err := filepath.Glob(filepath.Join(expandedPath, "*.conf")) - if err != nil { - return err - } - if len(confFiles) == 0 { - return os.ErrNotExist - } - files = confFiles - } else { - files = []string{expandedPath} - } - - var combinedContent []string - for _, file := range files { - if fileInfo, err := os.Stat(file); err == nil && fileInfo.Mode().IsRegular() { - data, err := os.ReadFile(file) - if err == nil { - combinedContent = append(combinedContent, string(data)) - } - } - } - - if len(combinedContent) == 0 { - return os.ErrNotExist - } - - fullContent := strings.Join(combinedContent, "\n") - p.contentLines = strings.Split(fullContent, "\n") - return nil -} - -func mangowcAutogenerateComment(command, params string) string { - switch command { - case "spawn", "spawn_shell": - return params - case "killclient": - return "Close window" - case "quit": - return "Exit MangoWC" - case "reload_config": - return "Reload configuration" - case "focusstack": - if params == "next" { - return "Focus next window" - } - if params == "prev" { - return "Focus previous window" - } - return "Focus stack " + params - case "focusdir": - dirMap := map[string]string{ - "left": "left", - "right": "right", - "up": "up", - "down": "down", - } - if dir, ok := dirMap[params]; ok { - return "Focus " + dir - } - return "Focus " + params - case "exchange_client": - dirMap := map[string]string{ - "left": "left", - "right": "right", - "up": "up", - "down": "down", - } - if dir, ok := dirMap[params]; ok { - return "Swap window " + dir - } - return "Swap window " + params - case "togglefloating": - return "Float/unfloat window" - case "togglefullscreen": - return "Toggle fullscreen" - case "togglefakefullscreen": - return "Toggle fake fullscreen" - case "togglemaximizescreen": - return "Toggle maximize" - case "toggleglobal": - return "Toggle global" - case "toggleoverview": - return "Toggle overview" - case "toggleoverlay": - return "Toggle overlay" - case "minimized": - return "Minimize window" - case "restore_minimized": - return "Restore minimized" - case "toggle_scratchpad": - return "Toggle scratchpad" - case "setlayout": - return "Set layout " + params - case "switch_layout": - return "Switch layout" - case "view": - parts := strings.Split(params, ",") - if len(parts) > 0 { - return "View tag " + parts[0] - } - return "View tag" - case "tag": - parts := strings.Split(params, ",") - if len(parts) > 0 { - return "Move to tag " + parts[0] - } - return "Move to tag" - case "toggleview": - parts := strings.Split(params, ",") - if len(parts) > 0 { - return "Toggle tag " + parts[0] - } - return "Toggle tag" - case "viewtoleft", "viewtoleft_have_client": - return "View left tag" - case "viewtoright", "viewtoright_have_client": - return "View right tag" - case "tagtoleft": - return "Move to left tag" - case "tagtoright": - return "Move to right tag" - case "focusmon": - return "Focus monitor " + params - case "tagmon": - return "Move to monitor " + params - case "incgaps": - if strings.HasPrefix(params, "-") { - return "Decrease gaps" - } - return "Increase gaps" - case "togglegaps": - return "Toggle gaps" - case "movewin": - return "Move window by " + params - case "resizewin": - return "Resize window by " + params - case "set_proportion": - return "Set proportion " + params - case "switch_proportion_preset": - return "Switch proportion preset" - default: - return "" - } -} - -func (p *MangoWCParser) getKeybindAtLine(lineNumber int) *MangoWCKeyBinding { - if lineNumber >= len(p.contentLines) { - return nil - } - - line := p.contentLines[lineNumber] - - bindMatch := regexp.MustCompile(`^(bind[lsr]*)\s*=\s*(.+)$`) - matches := bindMatch.FindStringSubmatch(line) - if len(matches) < 3 { - return nil - } - - bindType := matches[1] - content := matches[2] - - parts := strings.SplitN(content, "#", 2) - keys := parts[0] - - var comment string - if len(parts) > 1 { - comment = strings.TrimSpace(parts[1]) - } - - if strings.HasPrefix(comment, MangoWCHideComment) { - return nil - } - - keyFields := strings.SplitN(keys, ",", 4) - if len(keyFields) < 3 { - return nil - } - - mods := strings.TrimSpace(keyFields[0]) - key := strings.TrimSpace(keyFields[1]) - command := strings.TrimSpace(keyFields[2]) - - var params string - if len(keyFields) > 3 { - params = strings.TrimSpace(keyFields[3]) - } - - if comment == "" { - comment = mangowcAutogenerateComment(command, params) - } - - var modList []string - if mods != "" && !strings.EqualFold(mods, "none") { - modstring := mods + string(MangoWCModSeparators[0]) - p := 0 - for index, char := range modstring { - isModSep := false - for _, sep := range MangoWCModSeparators { - if char == sep { - isModSep = true - break - } - } - if isModSep { - if index-p > 1 { - modList = append(modList, modstring[p:index]) - } - p = index + 1 - } - } - } - - _ = bindType - - return &MangoWCKeyBinding{ - Mods: modList, - Key: key, - Command: command, - Params: params, - Comment: comment, - } -} - -func (p *MangoWCParser) ParseKeys() []MangoWCKeyBinding { - var keybinds []MangoWCKeyBinding - - for lineNumber := 0; lineNumber < len(p.contentLines); lineNumber++ { - line := p.contentLines[lineNumber] - if line == "" || strings.HasPrefix(strings.TrimSpace(line), "#") { - continue - } - - if !strings.HasPrefix(strings.TrimSpace(line), "bind") { - continue - } - - keybind := p.getKeybindAtLine(lineNumber) - if keybind != nil { - keybinds = append(keybinds, *keybind) - } - } - - return keybinds -} - -func ParseMangoWCKeys(path string) ([]MangoWCKeyBinding, error) { - parser := NewMangoWCParser(path) - if err := parser.ReadContent(path); err != nil { - return nil, err - } - return parser.ParseKeys(), nil -} - -type MangoWCParseResult struct { - Keybinds []MangoWCKeyBinding - DMSBindsIncluded bool - DMSStatus *MangoWCDMSStatus - ConflictingConfigs map[string]*MangoWCKeyBinding -} - -type MangoWCDMSStatus struct { - Exists bool - Included bool - IncludePosition int - TotalIncludes int - BindsAfterDMS int - Effective bool - OverriddenBy int - StatusMessage string -} - -func (p *MangoWCParser) buildDMSStatus() *MangoWCDMSStatus { - status := &MangoWCDMSStatus{ - Exists: p.dmsBindsExists, - Included: p.dmsBindsIncluded, - IncludePosition: p.dmsIncludePos, - TotalIncludes: p.includeCount, - BindsAfterDMS: p.bindsAfterDMS, - } - - switch { - case !p.dmsBindsExists: - status.Effective = false - status.StatusMessage = "dms/binds.conf does not exist" - case !p.dmsBindsIncluded: - status.Effective = false - status.StatusMessage = "dms/binds.conf is not sourced in config" - case p.bindsAfterDMS > 0: - status.Effective = true - status.OverriddenBy = p.bindsAfterDMS - status.StatusMessage = "Some DMS binds may be overridden by config binds" - default: - status.Effective = true - status.StatusMessage = "DMS binds are active" - } - - return status -} - -func (p *MangoWCParser) formatBindKey(kb *MangoWCKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (p *MangoWCParser) normalizeKey(key string) string { - return strings.ToLower(key) -} - -func (p *MangoWCParser) addBind(kb *MangoWCKeyBinding) { - key := p.formatBindKey(kb) - normalizedKey := p.normalizeKey(key) - isDMSBind := strings.Contains(kb.Source, "dms/binds.conf") || strings.Contains(kb.Source, "dms"+string(os.PathSeparator)+"binds.conf") - - if isDMSBind { - p.dmsBindKeys[normalizedKey] = true - } else if p.dmsBindKeys[normalizedKey] { - p.bindsAfterDMS++ - p.conflictingConfigs[normalizedKey] = kb - p.configBindKeys[normalizedKey] = true - return - } else { - p.configBindKeys[normalizedKey] = true - } - - if _, exists := p.bindMap[normalizedKey]; !exists { - p.bindOrder = append(p.bindOrder, key) - } - p.bindMap[normalizedKey] = kb -} - -func (p *MangoWCParser) ParseWithDMS() ([]MangoWCKeyBinding, error) { - expandedDir, err := utils.ExpandPath(p.configDir) - if err != nil { - return nil, err - } - - dmsBindsPath := filepath.Join(expandedDir, "dms", "binds.conf") - if _, err := os.Stat(dmsBindsPath); err == nil { - p.dmsBindsExists = true - } - - mainConfig := filepath.Join(expandedDir, "config.conf") - if _, err := os.Stat(mainConfig); os.IsNotExist(err) { - mainConfig = filepath.Join(expandedDir, "mango.conf") - } - - _, err = p.parseFileWithSource(mainConfig) - if err != nil { - return nil, err - } - - if p.dmsBindsExists && !p.dmsProcessed { - p.parseDMSBindsDirectly(dmsBindsPath) - } - - var keybinds []MangoWCKeyBinding - for _, key := range p.bindOrder { - normalizedKey := p.normalizeKey(key) - if kb, exists := p.bindMap[normalizedKey]; exists { - keybinds = append(keybinds, *kb) - } - } - - return keybinds, nil -} - -func (p *MangoWCParser) parseFileWithSource(filePath string) ([]MangoWCKeyBinding, error) { - absPath, err := filepath.Abs(filePath) - if err != nil { - return nil, err - } - - if p.processedFiles[absPath] { - return nil, nil - } - p.processedFiles[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return nil, err - } - - prevSource := p.currentSource - p.currentSource = absPath - - var keybinds []MangoWCKeyBinding - lines := strings.Split(string(data), "\n") - - for lineNum, line := range lines { - trimmed := strings.TrimSpace(line) - - if strings.HasPrefix(trimmed, "source") { - p.handleSource(trimmed, filepath.Dir(absPath), &keybinds) - continue - } - - if !strings.HasPrefix(trimmed, "bind") { - continue - } - - kb := p.getKeybindAtLineContent(line, lineNum) - if kb == nil { - continue - } - kb.Source = p.currentSource - p.addBind(kb) - keybinds = append(keybinds, *kb) - } - - p.currentSource = prevSource - return keybinds, nil -} - -func (p *MangoWCParser) handleSource(line, baseDir string, keybinds *[]MangoWCKeyBinding) { - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - return - } - - sourcePath := strings.TrimSpace(parts[1]) - isDMSSource := sourcePath == "dms/binds.conf" || sourcePath == "./dms/binds.conf" || strings.HasSuffix(sourcePath, "/dms/binds.conf") - - p.includeCount++ - if isDMSSource { - p.dmsBindsIncluded = true - p.dmsIncludePos = p.includeCount - p.dmsProcessed = true - } - - expanded, err := utils.ExpandPath(sourcePath) - if err != nil { - return - } - - fullPath := expanded - if !filepath.IsAbs(expanded) { - fullPath = filepath.Join(baseDir, expanded) - } - - includedBinds, err := p.parseFileWithSource(fullPath) - if err != nil { - return - } - - *keybinds = append(*keybinds, includedBinds...) -} - -func (p *MangoWCParser) parseDMSBindsDirectly(dmsBindsPath string) []MangoWCKeyBinding { - keybinds, err := p.parseFileWithSource(dmsBindsPath) - if err != nil { - return nil - } - p.dmsProcessed = true - return keybinds -} - -func (p *MangoWCParser) getKeybindAtLineContent(line string, _ int) *MangoWCKeyBinding { - bindMatch := regexp.MustCompile(`^(bind[lsr]*)\s*=\s*(.+)$`) - matches := bindMatch.FindStringSubmatch(line) - if len(matches) < 3 { - return nil - } - - content := matches[2] - parts := strings.SplitN(content, "#", 2) - keys := parts[0] - - var comment string - if len(parts) > 1 { - comment = strings.TrimSpace(parts[1]) - } - - if strings.HasPrefix(comment, MangoWCHideComment) { - return nil - } - - keyFields := strings.SplitN(keys, ",", 4) - if len(keyFields) < 3 { - return nil - } - - mods := strings.TrimSpace(keyFields[0]) - key := strings.TrimSpace(keyFields[1]) - command := strings.TrimSpace(keyFields[2]) - - var params string - if len(keyFields) > 3 { - params = strings.TrimSpace(keyFields[3]) - } - - if comment == "" { - comment = mangowcAutogenerateComment(command, params) - } - - var modList []string - if mods != "" && !strings.EqualFold(mods, "none") { - modstring := mods + string(MangoWCModSeparators[0]) - idx := 0 - for index, char := range modstring { - isModSep := false - for _, sep := range MangoWCModSeparators { - if char == sep { - isModSep = true - break - } - } - if isModSep { - if index-idx > 1 { - modList = append(modList, modstring[idx:index]) - } - idx = index + 1 - } - } - } - - return &MangoWCKeyBinding{ - Mods: modList, - Key: key, - Command: command, - Params: params, - Comment: comment, - } -} - -func ParseMangoWCKeysWithDMS(path string) (*MangoWCParseResult, error) { - parser := NewMangoWCParser(path) - keybinds, err := parser.ParseWithDMS() - if err != nil { - return nil, err - } - - return &MangoWCParseResult{ - Keybinds: keybinds, - DMSBindsIncluded: parser.dmsBindsIncluded, - DMSStatus: parser.buildDMSStatus(), - ConflictingConfigs: parser.conflictingConfigs, - }, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser_test.go deleted file mode 100644 index 016f50e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_parser_test.go +++ /dev/null @@ -1,499 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestMangoWCAutogenerateComment(t *testing.T) { - tests := []struct { - command string - params string - expected string - }{ - {"spawn", "kitty", "kitty"}, - {"spawn_shell", "firefox", "firefox"}, - {"killclient", "", "Close window"}, - {"quit", "", "Exit MangoWC"}, - {"reload_config", "", "Reload configuration"}, - {"focusstack", "next", "Focus next window"}, - {"focusstack", "prev", "Focus previous window"}, - {"focusdir", "left", "Focus left"}, - {"focusdir", "right", "Focus right"}, - {"focusdir", "up", "Focus up"}, - {"focusdir", "down", "Focus down"}, - {"exchange_client", "left", "Swap window left"}, - {"exchange_client", "right", "Swap window right"}, - {"togglefloating", "", "Float/unfloat window"}, - {"togglefullscreen", "", "Toggle fullscreen"}, - {"togglefakefullscreen", "", "Toggle fake fullscreen"}, - {"togglemaximizescreen", "", "Toggle maximize"}, - {"toggleglobal", "", "Toggle global"}, - {"toggleoverview", "", "Toggle overview"}, - {"toggleoverlay", "", "Toggle overlay"}, - {"minimized", "", "Minimize window"}, - {"restore_minimized", "", "Restore minimized"}, - {"toggle_scratchpad", "", "Toggle scratchpad"}, - {"setlayout", "tile", "Set layout tile"}, - {"switch_layout", "", "Switch layout"}, - {"view", "1,0", "View tag 1"}, - {"tag", "2,0", "Move to tag 2"}, - {"toggleview", "3,0", "Toggle tag 3"}, - {"viewtoleft", "", "View left tag"}, - {"viewtoright", "", "View right tag"}, - {"viewtoleft_have_client", "", "View left tag"}, - {"viewtoright_have_client", "", "View right tag"}, - {"tagtoleft", "", "Move to left tag"}, - {"tagtoright", "", "Move to right tag"}, - {"focusmon", "left", "Focus monitor left"}, - {"tagmon", "right", "Move to monitor right"}, - {"incgaps", "1", "Increase gaps"}, - {"incgaps", "-1", "Decrease gaps"}, - {"togglegaps", "", "Toggle gaps"}, - {"movewin", "+0,-50", "Move window by +0,-50"}, - {"resizewin", "+0,+50", "Resize window by +0,+50"}, - {"set_proportion", "1.0", "Set proportion 1.0"}, - {"switch_proportion_preset", "", "Switch proportion preset"}, - {"unknown", "", ""}, - } - - for _, tt := range tests { - t.Run(tt.command+"_"+tt.params, func(t *testing.T) { - result := mangowcAutogenerateComment(tt.command, tt.params) - if result != tt.expected { - t.Errorf("mangowcAutogenerateComment(%q, %q) = %q, want %q", - tt.command, tt.params, result, tt.expected) - } - }) - } -} - -func TestMangoWCGetKeybindAtLine(t *testing.T) { - tests := []struct { - name string - line string - expected *MangoWCKeyBinding - }{ - { - name: "basic_keybind", - line: "bind=ALT,q,killclient,", - expected: &MangoWCKeyBinding{ - Mods: []string{"ALT"}, - Key: "q", - Command: "killclient", - Params: "", - Comment: "Close window", - }, - }, - { - name: "keybind_with_params", - line: "bind=ALT,Left,focusdir,left", - expected: &MangoWCKeyBinding{ - Mods: []string{"ALT"}, - Key: "Left", - Command: "focusdir", - Params: "left", - Comment: "Focus left", - }, - }, - { - name: "keybind_with_comment", - line: "bind=Alt,t,spawn,kitty # Open terminal", - expected: &MangoWCKeyBinding{ - Mods: []string{"Alt"}, - Key: "t", - Command: "spawn", - Params: "kitty", - Comment: "Open terminal", - }, - }, - { - name: "keybind_hidden", - line: "bind=SUPER,h,spawn,secret # [hidden]", - expected: nil, - }, - { - name: "keybind_multiple_mods", - line: "bind=SUPER+SHIFT,Up,exchange_client,up", - expected: &MangoWCKeyBinding{ - Mods: []string{"SUPER", "SHIFT"}, - Key: "Up", - Command: "exchange_client", - Params: "up", - Comment: "Swap window up", - }, - }, - { - name: "keybind_no_mods", - line: "bind=NONE,Print,spawn,screenshot", - expected: &MangoWCKeyBinding{ - Mods: []string{}, - Key: "Print", - Command: "spawn", - Params: "screenshot", - Comment: "screenshot", - }, - }, - { - name: "keybind_multiple_params", - line: "bind=Ctrl,1,view,1,0", - expected: &MangoWCKeyBinding{ - Mods: []string{"Ctrl"}, - Key: "1", - Command: "view", - Params: "1,0", - Comment: "View tag 1", - }, - }, - { - name: "bindl_flag", - line: "bindl=SUPER+ALT,l,spawn,dms ipc call lock lock", - expected: &MangoWCKeyBinding{ - Mods: []string{"SUPER", "ALT"}, - Key: "l", - Command: "spawn", - Params: "dms ipc call lock lock", - Comment: "dms ipc call lock lock", - }, - }, - { - name: "keybind_with_spaces", - line: "bind = SUPER, r, reload_config", - expected: &MangoWCKeyBinding{ - Mods: []string{"SUPER"}, - Key: "r", - Command: "reload_config", - Params: "", - Comment: "Reload configuration", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - parser := NewMangoWCParser("") - parser.contentLines = []string{tt.line} - result := parser.getKeybindAtLine(0) - - if tt.expected == nil { - if result != nil { - t.Errorf("expected nil, got %+v", result) - } - return - } - - if result == nil { - t.Errorf("expected %+v, got nil", tt.expected) - return - } - - if result.Key != tt.expected.Key { - t.Errorf("Key = %q, want %q", result.Key, tt.expected.Key) - } - if result.Command != tt.expected.Command { - t.Errorf("Command = %q, want %q", result.Command, tt.expected.Command) - } - if result.Params != tt.expected.Params { - t.Errorf("Params = %q, want %q", result.Params, tt.expected.Params) - } - if result.Comment != tt.expected.Comment { - t.Errorf("Comment = %q, want %q", result.Comment, tt.expected.Comment) - } - if len(result.Mods) != len(tt.expected.Mods) { - t.Errorf("Mods length = %d, want %d", len(result.Mods), len(tt.expected.Mods)) - } else { - for i := range result.Mods { - if result.Mods[i] != tt.expected.Mods[i] { - t.Errorf("Mods[%d] = %q, want %q", i, result.Mods[i], tt.expected.Mods[i]) - } - } - } - }) - } -} - -func TestMangoWCParseKeys(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := `# MangoWC Configuration -blur=0 -border_radius=12 - -# Key Bindings -bind=SUPER,r,reload_config -bind=Alt,t,spawn,kitty # Terminal -bind=ALT,q,killclient, -bind=ALT,Left,focusdir,left - -# Hidden binding -bind=SUPER,h,spawn,secret # [hidden] - -# Multiple modifiers -bind=SUPER+SHIFT,Up,exchange_client,up - -# Workspace bindings -bind=Ctrl,1,view,1,0 -bind=Ctrl,2,view,2,0 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - keybinds, err := ParseMangoWCKeys(configFile) - if err != nil { - t.Fatalf("ParseMangoWCKeys failed: %v", err) - } - - expectedCount := 7 - if len(keybinds) != expectedCount { - t.Errorf("Expected %d keybinds, got %d", expectedCount, len(keybinds)) - } - - if len(keybinds) > 0 && keybinds[0].Command != "reload_config" { - t.Errorf("First keybind command = %q, want %q", keybinds[0].Command, "reload_config") - } - - foundHidden := false - for _, kb := range keybinds { - if kb.Command == "spawn" && kb.Params == "secret" { - foundHidden = true - } - } - if foundHidden { - t.Error("Hidden keybind should not be included in results") - } -} - -func TestMangoWCReadContentMultipleFiles(t *testing.T) { - tmpDir := t.TempDir() - - file1 := filepath.Join(tmpDir, "a.conf") - file2 := filepath.Join(tmpDir, "b.conf") - - content1 := "bind=ALT,q,killclient,\n" - content2 := "bind=Alt,t,spawn,kitty\n" - - if err := os.WriteFile(file1, []byte(content1), 0o644); err != nil { - t.Fatalf("Failed to write file1: %v", err) - } - if err := os.WriteFile(file2, []byte(content2), 0o644); err != nil { - t.Fatalf("Failed to write file2: %v", err) - } - - parser := NewMangoWCParser("") - if err := parser.ReadContent(tmpDir); err != nil { - t.Fatalf("ReadContent failed: %v", err) - } - - keybinds := parser.ParseKeys() - if len(keybinds) != 2 { - t.Errorf("Expected 2 keybinds from multiple files, got %d", len(keybinds)) - } -} - -func TestMangoWCReadContentSingleFile(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := "bind=ALT,q,killclient,\n" - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write config: %v", err) - } - - parser := NewMangoWCParser("") - if err := parser.ReadContent(configFile); err != nil { - t.Fatalf("ReadContent failed: %v", err) - } - - keybinds := parser.ParseKeys() - if len(keybinds) != 1 { - t.Errorf("Expected 1 keybind, got %d", len(keybinds)) - } -} - -func TestMangoWCReadContentErrors(t *testing.T) { - tests := []struct { - name string - path string - }{ - { - name: "nonexistent_directory", - path: "/nonexistent/path/that/does/not/exist", - }, - { - name: "empty_directory", - path: t.TempDir(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := ParseMangoWCKeys(tt.path) - if err == nil { - t.Error("Expected error, got nil") - } - }) - } -} - -func TestMangoWCReadContentWithTildeExpansion(t *testing.T) { - homeDir, err := os.UserHomeDir() - if err != nil { - t.Skip("Cannot get home directory") - } - - tmpSubdir := filepath.Join(homeDir, ".config", "test-mango-"+t.Name()) - if err := os.MkdirAll(tmpSubdir, 0o755); err != nil { - t.Skip("Cannot create test directory in home") - } - defer os.RemoveAll(tmpSubdir) - - configFile := filepath.Join(tmpSubdir, "config.conf") - if err := os.WriteFile(configFile, []byte("bind=ALT,q,killclient,\n"), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - relPath, err := filepath.Rel(homeDir, tmpSubdir) - if err != nil { - t.Skip("Cannot create relative path") - } - - parser := NewMangoWCParser("") - tildePathMatch := "~/" + relPath - err = parser.ReadContent(tildePathMatch) - - if err != nil { - t.Errorf("ReadContent with tilde path failed: %v", err) - } -} - -func TestMangoWCEmptyAndCommentLines(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := ` -# This is a comment -bind=ALT,q,killclient, - -# Another comment - -bind=Alt,t,spawn,kitty -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - keybinds, err := ParseMangoWCKeys(configFile) - if err != nil { - t.Fatalf("ParseMangoWCKeys failed: %v", err) - } - - if len(keybinds) != 2 { - t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(keybinds)) - } -} - -func TestMangoWCInvalidBindLines(t *testing.T) { - tests := []struct { - name string - line string - }{ - { - name: "missing_parts", - line: "bind=SUPER,q", - }, - { - name: "not_bind", - line: "blur=0", - }, - { - name: "empty_line", - line: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - parser := NewMangoWCParser("") - parser.contentLines = []string{tt.line} - result := parser.getKeybindAtLine(0) - - if result != nil { - t.Errorf("expected nil for invalid line, got %+v", result) - } - }) - } -} - -func TestMangoWCRealWorldConfig(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := `# Application Launchers -bind=Alt,t,spawn,kitty -bind=Alt,space,spawn,dms ipc call spotlight toggle -bind=Alt,v,spawn,dms ipc call clipboard toggle - -# exit -bind=ALT+SHIFT,e,quit -bind=ALT,q,killclient, - -# switch window focus -bind=SUPER,Tab,focusstack,next -bind=ALT,Left,focusdir,left -bind=ALT,Right,focusdir,right - -# tag switch -bind=SUPER,Left,viewtoleft,0 -bind=CTRL,Left,viewtoleft_have_client,0 -bind=SUPER,Right,viewtoright,0 - -bind=Ctrl,1,view,1,0 -bind=Ctrl,2,view,2,0 -bind=Ctrl,3,view,3,0 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - keybinds, err := ParseMangoWCKeys(configFile) - if err != nil { - t.Fatalf("ParseMangoWCKeys failed: %v", err) - } - - if len(keybinds) < 14 { - t.Errorf("Expected at least 14 keybinds, got %d", len(keybinds)) - } - - foundSpawn := false - foundQuit := false - foundView := false - - for _, kb := range keybinds { - if kb.Command == "spawn" && kb.Params == "kitty" { - foundSpawn = true - } - if kb.Command == "quit" { - foundQuit = true - } - if kb.Command == "view" && kb.Params == "1,0" { - foundView = true - } - } - - if !foundSpawn { - t.Error("Did not find spawn kitty keybind") - } - if !foundQuit { - t.Error("Did not find quit keybind") - } - if !foundView { - t.Error("Did not find view workspace 1 keybind") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_test.go deleted file mode 100644 index d417ce1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/mangowc_test.go +++ /dev/null @@ -1,320 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestMangoWCProviderName(t *testing.T) { - provider := NewMangoWCProvider("") - if provider.Name() != "mangowc" { - t.Errorf("Name() = %q, want %q", provider.Name(), "mangowc") - } -} - -func TestMangoWCProviderDefaultPath(t *testing.T) { - provider := NewMangoWCProvider("") - configDir, err := os.UserConfigDir() - if err != nil { - // Fall back to testing for non-empty path - if provider.configPath == "" { - t.Error("configPath should not be empty") - } - return - } - expected := filepath.Join(configDir, "mango") - if provider.configPath != expected { - t.Errorf("configPath = %q, want %q", provider.configPath, expected) - } -} - -func TestMangoWCProviderCustomPath(t *testing.T) { - customPath := "/custom/path" - provider := NewMangoWCProvider(customPath) - if provider.configPath != customPath { - t.Errorf("configPath = %q, want %q", provider.configPath, customPath) - } -} - -func TestMangoWCCategorizeByCommand(t *testing.T) { - tests := []struct { - command string - expected string - }{ - {"view", "Tags"}, - {"tag", "Tags"}, - {"toggleview", "Tags"}, - {"viewtoleft", "Tags"}, - {"viewtoright", "Tags"}, - {"viewtoleft_have_client", "Tags"}, - {"tagtoleft", "Tags"}, - {"tagtoright", "Tags"}, - {"focusmon", "Monitor"}, - {"tagmon", "Monitor"}, - {"focusstack", "Window"}, - {"focusdir", "Window"}, - {"exchange_client", "Window"}, - {"killclient", "Window"}, - {"togglefloating", "Window"}, - {"togglefullscreen", "Window"}, - {"togglefakefullscreen", "Window"}, - {"togglemaximizescreen", "Window"}, - {"toggleglobal", "Window"}, - {"toggleoverlay", "Window"}, - {"minimized", "Window"}, - {"restore_minimized", "Window"}, - {"movewin", "Window"}, - {"resizewin", "Window"}, - {"toggleoverview", "Overview"}, - {"toggle_scratchpad", "Scratchpad"}, - {"setlayout", "Layout"}, - {"switch_layout", "Layout"}, - {"set_proportion", "Layout"}, - {"switch_proportion_preset", "Layout"}, - {"incgaps", "Gaps"}, - {"togglegaps", "Gaps"}, - {"spawn", "Execute"}, - {"spawn_shell", "Execute"}, - {"quit", "System"}, - {"reload_config", "System"}, - {"unknown_command", "Other"}, - } - - provider := NewMangoWCProvider("") - for _, tt := range tests { - t.Run(tt.command, func(t *testing.T) { - result := provider.categorizeByCommand(tt.command) - if result != tt.expected { - t.Errorf("categorizeByCommand(%q) = %q, want %q", tt.command, result, tt.expected) - } - }) - } -} - -func TestMangoWCFormatKey(t *testing.T) { - tests := []struct { - name string - keybind *MangoWCKeyBinding - expected string - }{ - { - name: "single_mod", - keybind: &MangoWCKeyBinding{ - Mods: []string{"ALT"}, - Key: "q", - }, - expected: "ALT+q", - }, - { - name: "multiple_mods", - keybind: &MangoWCKeyBinding{ - Mods: []string{"SUPER", "SHIFT"}, - Key: "Up", - }, - expected: "SUPER+SHIFT+Up", - }, - { - name: "no_mods", - keybind: &MangoWCKeyBinding{ - Mods: []string{}, - Key: "Print", - }, - expected: "Print", - }, - } - - provider := NewMangoWCProvider("") - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.formatKey(tt.keybind) - if result != tt.expected { - t.Errorf("formatKey() = %q, want %q", result, tt.expected) - } - }) - } -} - -func TestMangoWCConvertKeybind(t *testing.T) { - tests := []struct { - name string - keybind *MangoWCKeyBinding - wantKey string - wantDesc string - }{ - { - name: "with_comment", - keybind: &MangoWCKeyBinding{ - Mods: []string{"ALT"}, - Key: "t", - Command: "spawn", - Params: "kitty", - Comment: "Open terminal", - }, - wantKey: "ALT+t", - wantDesc: "Open terminal", - }, - { - name: "without_comment", - keybind: &MangoWCKeyBinding{ - Mods: []string{"SUPER"}, - Key: "r", - Command: "reload_config", - Params: "", - Comment: "", - }, - wantKey: "SUPER+r", - wantDesc: "reload_config", - }, - { - name: "with_params_no_comment", - keybind: &MangoWCKeyBinding{ - Mods: []string{"CTRL"}, - Key: "1", - Command: "view", - Params: "1,0", - Comment: "", - }, - wantKey: "CTRL+1", - wantDesc: "view 1,0", - }, - } - - provider := NewMangoWCProvider("") - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.convertKeybind(tt.keybind, nil) - if result.Key != tt.wantKey { - t.Errorf("convertKeybind().Key = %q, want %q", result.Key, tt.wantKey) - } - if result.Description != tt.wantDesc { - t.Errorf("convertKeybind().Description = %q, want %q", result.Description, tt.wantDesc) - } - }) - } -} - -func TestMangoWCGetCheatSheet(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := `# MangoWC Configuration -blur=0 - -# Key Bindings -bind=SUPER,r,reload_config -bind=Alt,t,spawn,kitty # Terminal -bind=ALT,q,killclient, - -# Window management -bind=ALT,Left,focusdir,left -bind=ALT,Right,focusdir,right -bind=SUPER+SHIFT,Up,exchange_client,up - -# Tags -bind=Ctrl,1,view,1,0 -bind=Ctrl,2,view,2,0 -bind=Alt,1,tag,1,0 - -# Layout -bind=SUPER,n,switch_layout - -# Gaps -bind=ALT+SHIFT,X,incgaps,1 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewMangoWCProvider(tmpDir) - sheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if sheet == nil { - t.Fatal("Expected non-nil CheatSheet") - } - - if sheet.Title != "MangoWC Keybinds" { - t.Errorf("Title = %q, want %q", sheet.Title, "MangoWC Keybinds") - } - - if sheet.Provider != "mangowc" { - t.Errorf("Provider = %q, want %q", sheet.Provider, "mangowc") - } - - categories := []string{"System", "Execute", "Window", "Tags", "Layout", "Gaps"} - for _, category := range categories { - if _, exists := sheet.Binds[category]; !exists { - t.Errorf("Expected category %q to exist", category) - } - } - - if len(sheet.Binds["System"]) < 1 { - t.Error("Expected at least 1 System keybind") - } - if len(sheet.Binds["Execute"]) < 1 { - t.Error("Expected at least 1 Execute keybind") - } - if len(sheet.Binds["Window"]) < 3 { - t.Error("Expected at least 3 Window keybinds") - } - if len(sheet.Binds["Tags"]) < 3 { - t.Error("Expected at least 3 Tags keybinds") - } -} - -func TestMangoWCGetCheatSheetError(t *testing.T) { - provider := NewMangoWCProvider("/nonexistent/path") - _, err := provider.GetCheatSheet() - if err == nil { - t.Error("Expected error for nonexistent path, got nil") - } -} - -func TestMangoWCIntegration(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.conf") - - content := `bind=Alt,t,spawn,kitty # Open terminal -bind=ALT,q,killclient, -bind=SUPER,r,reload_config # Reload config -bind=ALT,Left,focusdir,left -bind=Ctrl,1,view,1,0 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewMangoWCProvider(tmpDir) - sheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - totalBinds := 0 - for _, binds := range sheet.Binds { - totalBinds += len(binds) - } - - expectedBinds := 5 - if totalBinds != expectedBinds { - t.Errorf("Expected %d total keybinds, got %d", expectedBinds, totalBinds) - } - - foundTerminal := false - for _, binds := range sheet.Binds { - for _, bind := range binds { - if bind.Description == "Open terminal" && bind.Key == "Alt+t" { - foundTerminal = true - } - } - } - - if !foundTerminal { - t.Error("Did not find terminal keybind with correct key and description") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle.go deleted file mode 100644 index 43fc58e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle.go +++ /dev/null @@ -1,95 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type MiracleProvider struct { - configPath string -} - -func NewMiracleProvider(configPath string) *MiracleProvider { - if configPath == "" { - configDir, err := os.UserConfigDir() - if err == nil { - configPath = filepath.Join(configDir, "miracle-wm") - } - } - return &MiracleProvider{configPath: configPath} -} - -func (m *MiracleProvider) Name() string { - return "miracle" -} - -func (m *MiracleProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - config, err := ParseMiracleConfig(m.configPath) - if err != nil { - return nil, fmt.Errorf("failed to parse miracle-wm config: %w", err) - } - - bindings := MiracleConfigToBindings(config) - categorizedBinds := make(map[string][]keybinds.Keybind) - - for _, kb := range bindings { - category := m.categorizeAction(kb.Action) - bind := keybinds.Keybind{ - Key: m.formatKey(kb), - Description: kb.Comment, - Action: kb.Action, - } - categorizedBinds[category] = append(categorizedBinds[category], bind) - } - - return &keybinds.CheatSheet{ - Title: "Miracle WM Keybinds", - Provider: m.Name(), - Binds: categorizedBinds, - }, nil -} - -func (m *MiracleProvider) GetOverridePath() string { - expanded, err := utils.ExpandPath(m.configPath) - if err != nil { - return filepath.Join(m.configPath, "config.yaml") - } - return filepath.Join(expanded, "config.yaml") -} - -func (m *MiracleProvider) formatKey(kb MiracleKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (m *MiracleProvider) categorizeAction(action string) string { - switch { - case strings.HasPrefix(action, "select_workspace_") || strings.HasPrefix(action, "move_to_workspace_"): - return "Workspace" - case strings.Contains(action, "select_") || strings.Contains(action, "move_"): - return "Window" - case action == "toggle_resize" || strings.HasPrefix(action, "resize_"): - return "Window" - case action == "fullscreen" || action == "toggle_floating" || action == "quit_active_window" || action == "toggle_pinned_to_workspace": - return "Window" - case action == "toggle_tabbing" || action == "toggle_stacking" || action == "request_vertical" || action == "request_horizontal": - return "Layout" - case action == "quit_compositor": - return "System" - case action == "terminal": - return "Execute" - case strings.HasPrefix(action, "magnifier_"): - return "Accessibility" - case strings.HasPrefix(action, "dms ") || strings.Contains(action, "dms ipc"): - return "Execute" - default: - return "Execute" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle_parser.go deleted file mode 100644 index 425c64a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/miracle_parser.go +++ /dev/null @@ -1,320 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "gopkg.in/yaml.v3" -) - -type MiracleConfig struct { - Terminal string `yaml:"terminal"` - ActionKey string `yaml:"action_key"` - DefaultActionOverrides []MiracleActionOverride `yaml:"default_action_overrides"` - CustomActions []MiracleCustomAction `yaml:"custom_actions"` -} - -type MiracleActionOverride struct { - Name string `yaml:"name"` - Action string `yaml:"action"` - Modifiers []string `yaml:"modifiers"` - Key string `yaml:"key"` -} - -type MiracleCustomAction struct { - Command string `yaml:"command"` - Action string `yaml:"action"` - Modifiers []string `yaml:"modifiers"` - Key string `yaml:"key"` -} - -type MiracleKeyBinding struct { - Mods []string - Key string - Action string - Comment string -} - -var miracleDefaultBinds = []MiracleKeyBinding{ - {Mods: []string{"Super"}, Key: "Return", Action: "terminal", Comment: "Open terminal"}, - {Mods: []string{"Super"}, Key: "v", Action: "request_vertical", Comment: "Layout windows vertically"}, - {Mods: []string{"Super"}, Key: "h", Action: "request_horizontal", Comment: "Layout windows horizontally"}, - {Mods: []string{"Super"}, Key: "Up", Action: "select_up", Comment: "Select window above"}, - {Mods: []string{"Super"}, Key: "Down", Action: "select_down", Comment: "Select window below"}, - {Mods: []string{"Super"}, Key: "Left", Action: "select_left", Comment: "Select window left"}, - {Mods: []string{"Super"}, Key: "Right", Action: "select_right", Comment: "Select window right"}, - {Mods: []string{"Super", "Shift"}, Key: "Up", Action: "move_up", Comment: "Move window up"}, - {Mods: []string{"Super", "Shift"}, Key: "Down", Action: "move_down", Comment: "Move window down"}, - {Mods: []string{"Super", "Shift"}, Key: "Left", Action: "move_left", Comment: "Move window left"}, - {Mods: []string{"Super", "Shift"}, Key: "Right", Action: "move_right", Comment: "Move window right"}, - {Mods: []string{"Super"}, Key: "r", Action: "toggle_resize", Comment: "Toggle resize mode"}, - {Mods: []string{"Super"}, Key: "f", Action: "fullscreen", Comment: "Toggle fullscreen"}, - {Mods: []string{"Super", "Shift"}, Key: "q", Action: "quit_active_window", Comment: "Close window"}, - {Mods: []string{"Super", "Shift"}, Key: "e", Action: "quit_compositor", Comment: "Exit compositor"}, - {Mods: []string{"Super"}, Key: "Space", Action: "toggle_floating", Comment: "Toggle floating"}, - {Mods: []string{"Super", "Shift"}, Key: "p", Action: "toggle_pinned_to_workspace", Comment: "Toggle pinned to workspace"}, - {Mods: []string{"Super"}, Key: "w", Action: "toggle_tabbing", Comment: "Toggle tabbing layout"}, - {Mods: []string{"Super"}, Key: "s", Action: "toggle_stacking", Comment: "Toggle stacking layout"}, - {Mods: []string{"Super"}, Key: "1", Action: "select_workspace_0", Comment: "Workspace 1"}, - {Mods: []string{"Super"}, Key: "2", Action: "select_workspace_1", Comment: "Workspace 2"}, - {Mods: []string{"Super"}, Key: "3", Action: "select_workspace_2", Comment: "Workspace 3"}, - {Mods: []string{"Super"}, Key: "4", Action: "select_workspace_3", Comment: "Workspace 4"}, - {Mods: []string{"Super"}, Key: "5", Action: "select_workspace_4", Comment: "Workspace 5"}, - {Mods: []string{"Super"}, Key: "6", Action: "select_workspace_5", Comment: "Workspace 6"}, - {Mods: []string{"Super"}, Key: "7", Action: "select_workspace_6", Comment: "Workspace 7"}, - {Mods: []string{"Super"}, Key: "8", Action: "select_workspace_7", Comment: "Workspace 8"}, - {Mods: []string{"Super"}, Key: "9", Action: "select_workspace_8", Comment: "Workspace 9"}, - {Mods: []string{"Super"}, Key: "0", Action: "select_workspace_9", Comment: "Workspace 10"}, - {Mods: []string{"Super", "Shift"}, Key: "1", Action: "move_to_workspace_0", Comment: "Move to workspace 1"}, - {Mods: []string{"Super", "Shift"}, Key: "2", Action: "move_to_workspace_1", Comment: "Move to workspace 2"}, - {Mods: []string{"Super", "Shift"}, Key: "3", Action: "move_to_workspace_2", Comment: "Move to workspace 3"}, - {Mods: []string{"Super", "Shift"}, Key: "4", Action: "move_to_workspace_3", Comment: "Move to workspace 4"}, - {Mods: []string{"Super", "Shift"}, Key: "5", Action: "move_to_workspace_4", Comment: "Move to workspace 5"}, - {Mods: []string{"Super", "Shift"}, Key: "6", Action: "move_to_workspace_5", Comment: "Move to workspace 6"}, - {Mods: []string{"Super", "Shift"}, Key: "7", Action: "move_to_workspace_6", Comment: "Move to workspace 7"}, - {Mods: []string{"Super", "Shift"}, Key: "8", Action: "move_to_workspace_7", Comment: "Move to workspace 8"}, - {Mods: []string{"Super", "Shift"}, Key: "9", Action: "move_to_workspace_8", Comment: "Move to workspace 9"}, - {Mods: []string{"Super", "Shift"}, Key: "0", Action: "move_to_workspace_9", Comment: "Move to workspace 10"}, -} - -func ParseMiracleConfig(configPath string) (*MiracleConfig, error) { - expanded, err := utils.ExpandPath(configPath) - if err != nil { - return nil, err - } - - info, err := os.Stat(expanded) - if err != nil { - return nil, err - } - - var configFile string - if info.IsDir() { - configFile = filepath.Join(expanded, "config.yaml") - } else { - configFile = expanded - } - - data, err := os.ReadFile(configFile) - if err != nil { - return nil, err - } - - var config MiracleConfig - if err := yaml.Unmarshal(data, &config); err != nil { - return nil, err - } - - if config.ActionKey == "" { - config.ActionKey = "meta" - } - - return &config, nil -} - -func resolveMiracleModifier(mod, actionKey string) string { - switch mod { - case "primary": - return resolveActionKey(actionKey) - case "alt", "alt_left", "alt_right": - return "Alt" - case "shift", "shift_left", "shift_right": - return "Shift" - case "ctrl", "ctrl_left", "ctrl_right": - return "Ctrl" - case "meta", "meta_left", "meta_right": - return "Super" - default: - return mod - } -} - -func resolveActionKey(actionKey string) string { - switch actionKey { - case "meta": - return "Super" - case "alt": - return "Alt" - case "ctrl": - return "Ctrl" - default: - return "Super" - } -} - -func miracleKeyCodeToName(keyCode string) string { - name := strings.TrimPrefix(keyCode, "KEY_") - name = strings.ToLower(name) - - switch name { - case "enter": - return "Return" - case "space": - return "Space" - case "up": - return "Up" - case "down": - return "Down" - case "left": - return "Left" - case "right": - return "Right" - case "tab": - return "Tab" - case "escape", "esc": - return "Escape" - case "delete": - return "Delete" - case "backspace": - return "BackSpace" - case "home": - return "Home" - case "end": - return "End" - case "pageup": - return "Page_Up" - case "pagedown": - return "Page_Down" - case "print": - return "Print" - case "pause": - return "Pause" - case "volumeup": - return "XF86AudioRaiseVolume" - case "volumedown": - return "XF86AudioLowerVolume" - case "mute": - return "XF86AudioMute" - case "micmute": - return "XF86AudioMicMute" - case "brightnessup": - return "XF86MonBrightnessUp" - case "brightnessdown": - return "XF86MonBrightnessDown" - case "kbdillumup": - return "XF86KbdBrightnessUp" - case "kbdillumdown": - return "XF86KbdBrightnessDown" - case "comma": - return "comma" - case "minus": - return "minus" - case "equal": - return "equal" - } - - if len(name) == 1 { - return name - } - - return name -} - -func MiracleConfigToBindings(config *MiracleConfig) []MiracleKeyBinding { - overridden := make(map[string]bool) - var bindings []MiracleKeyBinding - - for _, override := range config.DefaultActionOverrides { - mods := make([]string, 0, len(override.Modifiers)) - for _, mod := range override.Modifiers { - mods = append(mods, resolveMiracleModifier(mod, config.ActionKey)) - } - - bindings = append(bindings, MiracleKeyBinding{ - Mods: mods, - Key: miracleKeyCodeToName(override.Key), - Action: override.Name, - Comment: miracleActionDescription(override.Name), - }) - overridden[override.Name] = true - } - - for _, def := range miracleDefaultBinds { - if overridden[def.Action] { - continue - } - bindings = append(bindings, def) - } - - for _, custom := range config.CustomActions { - mods := make([]string, 0, len(custom.Modifiers)) - for _, mod := range custom.Modifiers { - mods = append(mods, resolveMiracleModifier(mod, config.ActionKey)) - } - - bindings = append(bindings, MiracleKeyBinding{ - Mods: mods, - Key: miracleKeyCodeToName(custom.Key), - Action: custom.Command, - Comment: custom.Command, - }) - } - - return bindings -} - -func miracleActionDescription(action string) string { - switch action { - case "terminal": - return "Open terminal" - case "request_vertical": - return "Layout windows vertically" - case "request_horizontal": - return "Layout windows horizontally" - case "select_up": - return "Select window above" - case "select_down": - return "Select window below" - case "select_left": - return "Select window left" - case "select_right": - return "Select window right" - case "move_up": - return "Move window up" - case "move_down": - return "Move window down" - case "move_left": - return "Move window left" - case "move_right": - return "Move window right" - case "toggle_resize": - return "Toggle resize mode" - case "fullscreen": - return "Toggle fullscreen" - case "quit_active_window": - return "Close window" - case "quit_compositor": - return "Exit compositor" - case "toggle_floating": - return "Toggle floating" - case "toggle_pinned_to_workspace": - return "Toggle pinned to workspace" - case "toggle_tabbing": - return "Toggle tabbing layout" - case "toggle_stacking": - return "Toggle stacking layout" - case "magnifier_on": - return "Enable magnifier" - case "magnifier_off": - return "Disable magnifier" - case "magnifier_increase_size": - return "Increase magnifier area" - case "magnifier_decrease_size": - return "Decrease magnifier area" - case "magnifier_increase_scale": - return "Increase magnifier scale" - case "magnifier_decrease_scale": - return "Decrease magnifier scale" - } - - if num, ok := strings.CutPrefix(action, "select_workspace_"); ok { - return "Workspace " + num - } - if num, ok := strings.CutPrefix(action, "move_to_workspace_"); ok { - return "Move to workspace " + num - } - - return action -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri.go deleted file mode 100644 index aec20b5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri.go +++ /dev/null @@ -1,650 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "sort" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" - "github.com/sblinch/kdl-go" - "github.com/sblinch/kdl-go/document" -) - -type NiriProvider struct { - configDir string - dmsBindsIncluded bool - parsed bool -} - -func NewNiriProvider(configDir string) *NiriProvider { - if configDir == "" { - configDir = defaultNiriConfigDir() - } - return &NiriProvider{ - configDir: configDir, - } -} - -func defaultNiriConfigDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - return "" - } - return filepath.Join(configDir, "niri") -} - -func (n *NiriProvider) Name() string { - return "niri" -} - -func (n *NiriProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - result, err := ParseNiriKeys(n.configDir) - if err != nil { - return nil, fmt.Errorf("failed to parse niri config: %w", err) - } - - n.dmsBindsIncluded = result.DMSBindsIncluded - n.parsed = true - - categorizedBinds := make(map[string][]keybinds.Keybind) - n.convertSection(result.Section, "", categorizedBinds, result.ConflictingConfigs) - - sheet := &keybinds.CheatSheet{ - Title: "Niri Keybinds", - Provider: n.Name(), - Binds: categorizedBinds, - DMSBindsIncluded: result.DMSBindsIncluded, - } - - if result.DMSStatus != nil { - sheet.DMSStatus = &keybinds.DMSBindsStatus{ - Exists: result.DMSStatus.Exists, - Included: result.DMSStatus.Included, - IncludePosition: result.DMSStatus.IncludePosition, - TotalIncludes: result.DMSStatus.TotalIncludes, - BindsAfterDMS: result.DMSStatus.BindsAfterDMS, - Effective: result.DMSStatus.Effective, - OverriddenBy: result.DMSStatus.OverriddenBy, - StatusMessage: result.DMSStatus.StatusMessage, - } - } - - return sheet, nil -} - -func (n *NiriProvider) HasDMSBindsIncluded() bool { - if n.parsed { - return n.dmsBindsIncluded - } - - result, err := ParseNiriKeys(n.configDir) - if err != nil { - return false - } - - n.dmsBindsIncluded = result.DMSBindsIncluded - n.parsed = true - return n.dmsBindsIncluded -} - -func (n *NiriProvider) convertSection(section *NiriSection, subcategory string, categorizedBinds map[string][]keybinds.Keybind, conflicts map[string]*NiriKeyBinding) { - currentSubcat := subcategory - if section.Name != "" { - currentSubcat = section.Name - } - - for _, kb := range section.Keybinds { - category := n.categorizeByAction(kb.Action) - bind := n.convertKeybind(&kb, currentSubcat, conflicts) - categorizedBinds[category] = append(categorizedBinds[category], bind) - } - - for _, child := range section.Children { - n.convertSection(&child, currentSubcat, categorizedBinds, conflicts) - } -} - -func (n *NiriProvider) categorizeByAction(action string) string { - switch { - case action == "next-window" || action == "previous-window": - return "Alt-Tab" - case strings.Contains(action, "screenshot"): - return "Screenshot" - case action == "show-hotkey-overlay" || action == "toggle-overview": - return "Overview" - case action == "quit" || - action == "power-off-monitors" || - action == "power-on-monitors" || - action == "suspend" || - action == "do-screen-transition" || - action == "toggle-keyboard-shortcuts-inhibit" || - strings.Contains(action, "dpms"): - return "System" - case action == "spawn": - return "Execute" - case strings.Contains(action, "workspace"): - return "Workspace" - case strings.HasPrefix(action, "focus-monitor") || - strings.HasPrefix(action, "move-column-to-monitor") || - strings.HasPrefix(action, "move-window-to-monitor"): - return "Monitor" - case strings.Contains(action, "window") || - strings.Contains(action, "focus") || - strings.Contains(action, "move") || - strings.Contains(action, "swap") || - strings.Contains(action, "resize") || - strings.Contains(action, "column"): - return "Window" - default: - return "Other" - } -} - -func (n *NiriProvider) convertKeybind(kb *NiriKeyBinding, subcategory string, conflicts map[string]*NiriKeyBinding) keybinds.Keybind { - rawAction := n.formatRawAction(kb.Action, kb.Args) - keyStr := n.formatKey(kb) - - source := "config" - if strings.Contains(kb.Source, "dms/binds.kdl") { - source = "dms" - } - - bind := keybinds.Keybind{ - Key: keyStr, - Description: kb.Description, - Action: rawAction, - Subcategory: subcategory, - Source: source, - HideOnOverlay: kb.HideOnOverlay, - CooldownMs: kb.CooldownMs, - AllowWhenLocked: kb.AllowWhenLocked, - AllowInhibiting: kb.AllowInhibiting, - Repeat: kb.Repeat, - } - - if source == "dms" && conflicts != nil { - if conflictKb, ok := conflicts[keyStr]; ok { - bind.Conflict = &keybinds.Keybind{ - Key: keyStr, - Description: conflictKb.Description, - Action: n.formatRawAction(conflictKb.Action, conflictKb.Args), - Source: "config", - } - } - } - - return bind -} - -func (n *NiriProvider) formatRawAction(action string, args []string) string { - if len(args) == 0 { - return action - } - - if action == "spawn" && len(args) >= 3 && args[1] == "-c" { - switch args[0] { - case "sh", "bash": - cmd := strings.Join(args[2:], " ") - return fmt.Sprintf("spawn %s -c \"%s\"", args[0], strings.ReplaceAll(cmd, "\"", "\\\"")) - } - } - - quotedArgs := make([]string, len(args)) - for i, arg := range args { - if arg == "" { - quotedArgs[i] = `""` - } else { - quotedArgs[i] = arg - } - } - return action + " " + strings.Join(quotedArgs, " ") -} - -func (n *NiriProvider) formatKey(kb *NiriKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (n *NiriProvider) GetOverridePath() string { - return filepath.Join(n.configDir, "dms", "binds.kdl") -} - -func (n *NiriProvider) validateAction(action string) error { - action = strings.TrimSpace(action) - switch { - case action == "": - return fmt.Errorf("action cannot be empty") - case action == "spawn" || action == "spawn ": - return fmt.Errorf("spawn command requires arguments") - case strings.HasPrefix(action, "spawn "): - rest := strings.TrimSpace(strings.TrimPrefix(action, "spawn ")) - switch rest { - case "": - return fmt.Errorf("spawn command requires arguments") - case "sh -c \"\"", "sh -c ''", "bash -c \"\"", "bash -c ''": - return fmt.Errorf("shell command cannot be empty") - } - } - return nil -} - -func (n *NiriProvider) SetBind(key, action, description string, options map[string]any) error { - if err := n.validateAction(action); err != nil { - return err - } - - overridePath := n.GetOverridePath() - - if err := os.MkdirAll(filepath.Dir(overridePath), 0o755); err != nil { - return fmt.Errorf("failed to create dms directory: %w", err) - } - - existingBinds, err := n.loadOverrideBinds() - if err != nil { - existingBinds = make(map[string]*overrideBind) - } - - existingBinds[key] = &overrideBind{ - Key: key, - Action: action, - Description: description, - Options: options, - } - - return n.writeOverrideBinds(existingBinds) -} - -func (n *NiriProvider) RemoveBind(key string) error { - existingBinds, err := n.loadOverrideBinds() - if err != nil { - return nil - } - - delete(existingBinds, key) - return n.writeOverrideBinds(existingBinds) -} - -type overrideBind struct { - Key string - Action string - Description string - Options map[string]any -} - -func (n *NiriProvider) loadOverrideBinds() (map[string]*overrideBind, error) { - overridePath := n.GetOverridePath() - binds := make(map[string]*overrideBind) - - data, err := os.ReadFile(overridePath) - if os.IsNotExist(err) { - return binds, nil - } - if err != nil { - return nil, err - } - - parser := NewNiriParser(filepath.Dir(overridePath)) - parser.currentSource = overridePath - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return nil, err - } - - for _, node := range doc.Nodes { - if node.Name.String() != "binds" || node.Children == nil { - continue - } - for _, child := range node.Children { - kb := parser.parseKeybindNode(child, "") - if kb == nil { - continue - } - keyStr := parser.formatBindKey(kb) - - action := n.buildActionFromNode(child) - if action == "" { - action = n.formatRawAction(kb.Action, kb.Args) - } - - binds[keyStr] = &overrideBind{ - Key: keyStr, - Action: action, - Description: kb.Description, - Options: n.extractOptions(child), - } - } - } - - return binds, nil -} - -func (n *NiriProvider) buildActionFromNode(bindNode *document.Node) string { - if len(bindNode.Children) == 0 { - return "" - } - - actionNode := bindNode.Children[0] - actionName := actionNode.Name.String() - if actionName == "" { - return "" - } - - parts := []string{actionName} - for _, arg := range actionNode.Arguments { - val := arg.ValueString() - if val == "" { - parts = append(parts, `""`) - } else if strings.ContainsAny(val, " \t") { - parts = append(parts, `"`+strings.ReplaceAll(val, `"`, `\"`)+`"`) - } else { - parts = append(parts, val) - } - } - - if actionNode.Properties != nil { - for _, propName := range []string{"focus", "show-pointer", "write-to-disk", "skip-confirmation", "delay-ms"} { - if val, ok := actionNode.Properties.Get(propName); ok { - parts = append(parts, propName+"="+val.String()) - } - } - } - - return strings.Join(parts, " ") -} - -func (n *NiriProvider) extractOptions(node *document.Node) map[string]any { - if node.Properties == nil { - return make(map[string]any) - } - - opts := make(map[string]any) - if val, ok := node.Properties.Get("repeat"); ok { - opts["repeat"] = val.String() == "true" - } - if val, ok := node.Properties.Get("cooldown-ms"); ok { - if ms, err := strconv.Atoi(val.String()); err == nil { - opts["cooldown-ms"] = ms - } - } - if val, ok := node.Properties.Get("allow-when-locked"); ok { - opts["allow-when-locked"] = val.String() == "true" - } - if val, ok := node.Properties.Get("allow-inhibiting"); ok { - opts["allow-inhibiting"] = val.String() == "true" - } - return opts -} - -func (n *NiriProvider) isRecentWindowsAction(action string) bool { - switch action { - case "next-window", "previous-window": - return true - default: - return false - } -} - -func (n *NiriProvider) buildBindNode(bind *overrideBind) *document.Node { - node := document.NewNode() - node.SetName(bind.Key) - - if bind.Options != nil { - if v, ok := bind.Options["repeat"]; ok && v == false { - node.AddProperty("repeat", false, "") - } - if v, ok := bind.Options["cooldown-ms"]; ok { - switch val := v.(type) { - case int: - node.AddProperty("cooldown-ms", val, "") - case string: - if ms, err := strconv.Atoi(val); err == nil { - node.AddProperty("cooldown-ms", ms, "") - } - } - } - if v, ok := bind.Options["allow-when-locked"]; ok && v == true { - node.AddProperty("allow-when-locked", true, "") - } - if v, ok := bind.Options["allow-inhibiting"]; ok && v == false { - node.AddProperty("allow-inhibiting", false, "") - } - } - - if bind.Description != "" { - node.AddProperty("hotkey-overlay-title", bind.Description, "") - } - - actionNode := n.buildActionNode(bind.Action) - node.AddNode(actionNode) - - return node -} - -func (n *NiriProvider) buildActionNode(action string) *document.Node { - action = strings.TrimSpace(action) - node := document.NewNode() - - parts := n.parseActionParts(action) - if len(parts) == 0 { - node.SetName(action) - return node - } - - node.SetName(parts[0]) - for _, arg := range parts[1:] { - if strings.Contains(arg, "=") { - kv := strings.SplitN(arg, "=", 2) - switch kv[1] { - case "true": - node.AddProperty(kv[0], true, "") - case "false": - node.AddProperty(kv[0], false, "") - default: - node.AddProperty(kv[0], kv[1], "") - } - continue - } - node.AddArgument(arg, "") - } - return node -} - -func (n *NiriProvider) parseActionParts(action string) []string { - var parts []string - var current strings.Builder - var inQuote, escaped, wasQuoted bool - - for _, r := range action { - switch { - case escaped: - current.WriteRune(r) - escaped = false - case r == '\\': - escaped = true - case r == '"': - wasQuoted = true - inQuote = !inQuote - case r == ' ' && !inQuote: - if current.Len() > 0 || wasQuoted { - parts = append(parts, current.String()) - current.Reset() - wasQuoted = false - } - default: - current.WriteRune(r) - } - } - if current.Len() > 0 || wasQuoted { - parts = append(parts, current.String()) - } - return parts -} - -func (n *NiriProvider) writeOverrideBinds(binds map[string]*overrideBind) error { - overridePath := n.GetOverridePath() - content := n.generateBindsContent(binds) - - if err := n.validateBindsContent(content); err != nil { - return err - } - - return os.WriteFile(overridePath, []byte(content), 0o644) -} - -func (n *NiriProvider) getBindSortPriority(action string) int { - switch { - case strings.HasPrefix(action, "spawn") && strings.Contains(action, "dms"): - return 0 - case strings.Contains(action, "workspace"): - return 1 - case strings.Contains(action, "window") || strings.Contains(action, "column") || - strings.Contains(action, "focus") || strings.Contains(action, "move") || - strings.Contains(action, "swap") || strings.Contains(action, "resize"): - return 2 - case strings.HasPrefix(action, "focus-monitor") || strings.Contains(action, "monitor"): - return 3 - case strings.Contains(action, "screenshot"): - return 4 - case action == "quit" || action == "power-off-monitors" || strings.Contains(action, "dpms"): - return 5 - case strings.HasPrefix(action, "spawn"): - return 6 - default: - return 7 - } -} - -func (n *NiriProvider) generateBindsContent(binds map[string]*overrideBind) string { - if len(binds) == 0 { - return "binds {}\n" - } - - var regularBinds, recentWindowsBinds []*overrideBind - for _, bind := range binds { - switch { - case n.isRecentWindowsAction(bind.Action): - recentWindowsBinds = append(recentWindowsBinds, bind) - default: - regularBinds = append(regularBinds, bind) - } - } - - sort.Slice(regularBinds, func(i, j int) bool { - pi, pj := n.getBindSortPriority(regularBinds[i].Action), n.getBindSortPriority(regularBinds[j].Action) - if pi != pj { - return pi < pj - } - return regularBinds[i].Key < regularBinds[j].Key - }) - - sort.Slice(recentWindowsBinds, func(i, j int) bool { - return recentWindowsBinds[i].Key < recentWindowsBinds[j].Key - }) - - var sb strings.Builder - - sb.WriteString("binds {\n") - for _, bind := range regularBinds { - n.writeBindNode(&sb, bind, " ") - } - sb.WriteString("}\n") - - if len(recentWindowsBinds) > 0 { - sb.WriteString("\nrecent-windows {\n") - sb.WriteString(" binds {\n") - for _, bind := range recentWindowsBinds { - n.writeBindNode(&sb, bind, " ") - } - sb.WriteString(" }\n") - sb.WriteString("}\n") - } - - return sb.String() -} - -func (n *NiriProvider) writeBindNode(sb *strings.Builder, bind *overrideBind, indent string) { - node := n.buildBindNode(bind) - - sb.WriteString(indent) - sb.WriteString(node.Name.String()) - - if node.Properties.Exist() { - sb.WriteString(" ") - sb.WriteString(strings.TrimLeft(node.Properties.String(), " ")) - } - - sb.WriteString(" { ") - if len(node.Children) > 0 { - child := node.Children[0] - actionName := child.Name.String() - sb.WriteString(actionName) - forceQuote := actionName == "spawn" - for _, arg := range child.Arguments { - sb.WriteString(" ") - n.writeArg(sb, arg.ValueString(), forceQuote) - } - if child.Properties.Exist() { - sb.WriteString(" ") - sb.WriteString(strings.TrimLeft(child.Properties.String(), " ")) - } - } - sb.WriteString("; }\n") -} - -func (n *NiriProvider) writeArg(sb *strings.Builder, val string, forceQuote bool) { - if !forceQuote && n.isNumericArg(val) { - sb.WriteString(val) - return - } - sb.WriteString("\"") - sb.WriteString(strings.ReplaceAll(val, "\"", "\\\"")) - sb.WriteString("\"") -} - -func (n *NiriProvider) isNumericArg(val string) bool { - if val == "" { - return false - } - start := 0 - if val[0] == '-' || val[0] == '+' { - if len(val) == 1 { - return false - } - start = 1 - } - for i := start; i < len(val); i++ { - if val[i] < '0' || val[i] > '9' { - return false - } - } - return true -} - -func (n *NiriProvider) validateBindsContent(content string) error { - tmpFile, err := os.CreateTemp("", "dms-binds-*.kdl") - if err != nil { - return fmt.Errorf("failed to create temp file: %w", err) - } - defer os.Remove(tmpFile.Name()) - - if _, err := tmpFile.WriteString(content); err != nil { - tmpFile.Close() - return fmt.Errorf("failed to write temp file: %w", err) - } - tmpFile.Close() - - cmd := exec.Command("niri", "validate", "-c", tmpFile.Name()) - output, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("invalid config: %s", strings.TrimSpace(string(output))) - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser.go deleted file mode 100644 index 46520ff..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser.go +++ /dev/null @@ -1,400 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/sblinch/kdl-go" - "github.com/sblinch/kdl-go/document" -) - -type NiriKeyBinding struct { - Mods []string - Key string - Action string - Args []string - Description string - HideOnOverlay bool - CooldownMs int - AllowWhenLocked bool - AllowInhibiting *bool - Repeat *bool - Source string -} - -type NiriSection struct { - Name string - Keybinds []NiriKeyBinding - Children []NiriSection -} - -type NiriParser struct { - configDir string - processedFiles map[string]bool - bindMap map[string]*NiriKeyBinding - bindOrder []string - currentSource string - dmsBindsIncluded bool - dmsBindsExists bool - includeCount int - dmsIncludePos int - bindsBeforeDMS int - bindsAfterDMS int - dmsBindKeys map[string]bool - configBindKeys map[string]bool - dmsProcessed bool - dmsBindMap map[string]*NiriKeyBinding - conflictingConfigs map[string]*NiriKeyBinding -} - -func NewNiriParser(configDir string) *NiriParser { - return &NiriParser{ - configDir: configDir, - processedFiles: make(map[string]bool), - bindMap: make(map[string]*NiriKeyBinding), - bindOrder: []string{}, - currentSource: "", - dmsIncludePos: -1, - dmsBindKeys: make(map[string]bool), - configBindKeys: make(map[string]bool), - dmsBindMap: make(map[string]*NiriKeyBinding), - conflictingConfigs: make(map[string]*NiriKeyBinding), - } -} - -func (p *NiriParser) Parse() (*NiriSection, error) { - dmsBindsPath := filepath.Join(p.configDir, "dms", "binds.kdl") - if _, err := os.Stat(dmsBindsPath); err == nil { - p.dmsBindsExists = true - } - - configPath := filepath.Join(p.configDir, "config.kdl") - section, err := p.parseFile(configPath, "") - if err != nil { - return nil, err - } - - if p.dmsBindsExists && !p.dmsProcessed { - p.parseDMSBindsDirectly(dmsBindsPath, section) - } - - section.Keybinds = p.finalizeBinds() - return section, nil -} - -func (p *NiriParser) parseDMSBindsDirectly(dmsBindsPath string, section *NiriSection) { - data, err := os.ReadFile(dmsBindsPath) - if err != nil { - return - } - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return - } - - prevSource := p.currentSource - p.currentSource = dmsBindsPath - baseDir := filepath.Dir(dmsBindsPath) - p.processNodes(doc.Nodes, section, baseDir) - p.currentSource = prevSource - p.dmsProcessed = true -} - -func (p *NiriParser) finalizeBinds() []NiriKeyBinding { - binds := make([]NiriKeyBinding, 0, len(p.bindOrder)) - for _, key := range p.bindOrder { - if kb, ok := p.bindMap[key]; ok { - binds = append(binds, *kb) - } - } - return binds -} - -func (p *NiriParser) addBind(kb *NiriKeyBinding) { - key := p.formatBindKey(kb) - isDMSBind := strings.Contains(kb.Source, "dms/binds.kdl") - - if isDMSBind { - p.dmsBindKeys[key] = true - p.dmsBindMap[key] = kb - } else if p.dmsBindKeys[key] { - p.bindsAfterDMS++ - p.conflictingConfigs[key] = kb - p.configBindKeys[key] = true - return - } else { - p.configBindKeys[key] = true - } - - if _, exists := p.bindMap[key]; !exists { - p.bindOrder = append(p.bindOrder, key) - } - p.bindMap[key] = kb -} - -func (p *NiriParser) formatBindKey(kb *NiriKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} - -func (p *NiriParser) parseFile(filePath, sectionName string) (*NiriSection, error) { - absPath, err := filepath.Abs(filePath) - if err != nil { - return nil, fmt.Errorf("failed to resolve path %s: %w", filePath, err) - } - - if p.processedFiles[absPath] { - return &NiriSection{Name: sectionName}, nil - } - p.processedFiles[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return nil, fmt.Errorf("failed to read %s: %w", absPath, err) - } - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return nil, fmt.Errorf("failed to parse KDL in %s: %w", absPath, err) - } - - section := &NiriSection{ - Name: sectionName, - } - - prevSource := p.currentSource - p.currentSource = absPath - baseDir := filepath.Dir(absPath) - p.processNodes(doc.Nodes, section, baseDir) - p.currentSource = prevSource - - return section, nil -} - -func (p *NiriParser) processNodes(nodes []*document.Node, section *NiriSection, baseDir string) { - for _, node := range nodes { - name := node.Name.String() - - switch name { - case "include": - p.handleInclude(node, section, baseDir) - case "binds": - p.extractBinds(node, section, "") - case "recent-windows": - p.handleRecentWindows(node, section) - } - } -} - -func (p *NiriParser) handleInclude(node *document.Node, section *NiriSection, baseDir string) { - if len(node.Arguments) == 0 { - return - } - - includePath := strings.Trim(node.Arguments[0].String(), "\"") - isDMSInclude := includePath == "dms/binds.kdl" || strings.HasSuffix(includePath, "/dms/binds.kdl") - - p.includeCount++ - if isDMSInclude { - p.dmsBindsIncluded = true - p.dmsIncludePos = p.includeCount - p.bindsBeforeDMS = len(p.bindMap) - } - - fullPath := filepath.Join(baseDir, includePath) - if filepath.IsAbs(includePath) { - fullPath = includePath - } - - if isDMSInclude { - p.dmsProcessed = true - } - - includedSection, err := p.parseFile(fullPath, "") - if err != nil { - return - } - - section.Children = append(section.Children, includedSection.Children...) -} - -func (p *NiriParser) HasDMSBindsIncluded() bool { - return p.dmsBindsIncluded -} - -func (p *NiriParser) handleRecentWindows(node *document.Node, section *NiriSection) { - if node.Children == nil { - return - } - - for _, child := range node.Children { - if child.Name.String() != "binds" { - continue - } - p.extractBinds(child, section, "Alt-Tab") - } -} - -func (p *NiriParser) extractBinds(node *document.Node, section *NiriSection, subcategory string) { - if node.Children == nil { - return - } - - for _, child := range node.Children { - kb := p.parseKeybindNode(child, subcategory) - if kb == nil { - continue - } - p.addBind(kb) - } -} - -func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBinding { - keyCombo := node.Name.String() - if keyCombo == "" { - return nil - } - - mods, key := p.parseKeyCombo(keyCombo) - - var action string - var args []string - if len(node.Children) > 0 { - actionNode := node.Children[0] - action = actionNode.Name.String() - for _, arg := range actionNode.Arguments { - args = append(args, arg.ValueString()) - } - if actionNode.Properties != nil { - for _, propName := range []string{"focus", "show-pointer", "write-to-disk", "skip-confirmation", "delay-ms"} { - if val, ok := actionNode.Properties.Get(propName); ok { - args = append(args, propName+"="+val.String()) - } - } - } - } - - var description string - var hideOnOverlay bool - var cooldownMs int - var allowWhenLocked bool - var allowInhibiting *bool - var repeat *bool - if node.Properties != nil { - if val, ok := node.Properties.Get("hotkey-overlay-title"); ok { - switch val.ValueString() { - case "null", "": - hideOnOverlay = true - default: - description = val.ValueString() - } - } - if val, ok := node.Properties.Get("cooldown-ms"); ok { - cooldownMs, _ = strconv.Atoi(val.String()) - } - if val, ok := node.Properties.Get("allow-when-locked"); ok { - allowWhenLocked = val.String() == "true" - } - if val, ok := node.Properties.Get("allow-inhibiting"); ok { - v := val.String() == "true" - allowInhibiting = &v - } - if val, ok := node.Properties.Get("repeat"); ok { - v := val.String() == "true" - repeat = &v - } - } - - return &NiriKeyBinding{ - Mods: mods, - Key: key, - Action: action, - Args: args, - Description: description, - HideOnOverlay: hideOnOverlay, - CooldownMs: cooldownMs, - AllowWhenLocked: allowWhenLocked, - AllowInhibiting: allowInhibiting, - Repeat: repeat, - Source: p.currentSource, - } -} - -func (p *NiriParser) parseKeyCombo(combo string) ([]string, string) { - parts := strings.Split(combo, "+") - - switch len(parts) { - case 0: - return nil, combo - case 1: - return nil, parts[0] - default: - return parts[:len(parts)-1], parts[len(parts)-1] - } -} - -type NiriParseResult struct { - Section *NiriSection - DMSBindsIncluded bool - DMSStatus *DMSBindsStatusInfo - ConflictingConfigs map[string]*NiriKeyBinding -} - -type DMSBindsStatusInfo struct { - Exists bool - Included bool - IncludePosition int - TotalIncludes int - BindsAfterDMS int - Effective bool - OverriddenBy int - StatusMessage string -} - -func (p *NiriParser) buildDMSStatus() *DMSBindsStatusInfo { - status := &DMSBindsStatusInfo{ - Exists: p.dmsBindsExists, - Included: p.dmsBindsIncluded, - IncludePosition: p.dmsIncludePos, - TotalIncludes: p.includeCount, - BindsAfterDMS: p.bindsAfterDMS, - } - - switch { - case !p.dmsBindsExists: - status.Effective = false - status.StatusMessage = "dms/binds.kdl does not exist" - case !p.dmsBindsIncluded: - status.Effective = false - status.StatusMessage = "dms/binds.kdl is not included in config.kdl" - case p.bindsAfterDMS > 0: - status.Effective = true - status.OverriddenBy = p.bindsAfterDMS - status.StatusMessage = "Some DMS binds may be overridden by config binds" - default: - status.Effective = true - status.StatusMessage = "DMS binds are active" - } - - return status -} - -func ParseNiriKeys(configDir string) (*NiriParseResult, error) { - parser := NewNiriParser(configDir) - section, err := parser.Parse() - if err != nil { - return nil, err - } - return &NiriParseResult{ - Section: section, - DMSBindsIncluded: parser.HasDMSBindsIncluded(), - DMSStatus: parser.buildDMSStatus(), - ConflictingConfigs: parser.conflictingConfigs, - }, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser_test.go deleted file mode 100644 index e21fde5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_parser_test.go +++ /dev/null @@ -1,630 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestNiriParseKeyCombo(t *testing.T) { - tests := []struct { - combo string - expectedMods []string - expectedKey string - }{ - {"Mod+Q", []string{"Mod"}, "Q"}, - {"Mod+Shift+F", []string{"Mod", "Shift"}, "F"}, - {"Ctrl+Alt+Delete", []string{"Ctrl", "Alt"}, "Delete"}, - {"Print", nil, "Print"}, - {"XF86AudioMute", nil, "XF86AudioMute"}, - {"Super+Tab", []string{"Super"}, "Tab"}, - {"Mod+Shift+Ctrl+H", []string{"Mod", "Shift", "Ctrl"}, "H"}, - } - - parser := NewNiriParser("") - for _, tt := range tests { - t.Run(tt.combo, func(t *testing.T) { - mods, key := parser.parseKeyCombo(tt.combo) - - if len(mods) != len(tt.expectedMods) { - t.Errorf("Mods length = %d, want %d", len(mods), len(tt.expectedMods)) - } else { - for i := range mods { - if mods[i] != tt.expectedMods[i] { - t.Errorf("Mods[%d] = %q, want %q", i, mods[i], tt.expectedMods[i]) - } - } - } - - if key != tt.expectedKey { - t.Errorf("Key = %q, want %q", key, tt.expectedKey) - } - }) - } -} - -func TestNiriParseBasicBinds(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Q { close-window; } - Mod+F { fullscreen-window; } - Mod+T hotkey-overlay-title="Open Terminal" { spawn "kitty"; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 3 { - t.Errorf("Expected 3 keybinds, got %d", len(result.Section.Keybinds)) - } - - foundClose := false - foundFullscreen := false - foundTerminal := false - - for _, kb := range result.Section.Keybinds { - switch kb.Action { - case "close-window": - foundClose = true - if kb.Key != "Q" || len(kb.Mods) != 1 || kb.Mods[0] != "Mod" { - t.Errorf("close-window keybind mismatch: %+v", kb) - } - case "fullscreen-window": - foundFullscreen = true - case "spawn": - foundTerminal = true - if kb.Description != "Open Terminal" { - t.Errorf("spawn description = %q, want %q", kb.Description, "Open Terminal") - } - if len(kb.Args) != 1 || kb.Args[0] != "kitty" { - t.Errorf("spawn args = %v, want [kitty]", kb.Args) - } - } - } - - if !foundClose { - t.Error("close-window keybind not found") - } - if !foundFullscreen { - t.Error("fullscreen-window keybind not found") - } - if !foundTerminal { - t.Error("spawn keybind not found") - } -} - -func TestNiriParseRecentWindows(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `recent-windows { - binds { - Alt+Tab { next-window scope="output"; } - Alt+Shift+Tab { previous-window scope="output"; } - } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds from recent-windows, got %d", len(result.Section.Keybinds)) - } - - foundNext := false - foundPrev := false - - for _, kb := range result.Section.Keybinds { - switch kb.Action { - case "next-window": - foundNext = true - case "previous-window": - foundPrev = true - } - } - - if !foundNext { - t.Error("next-window keybind not found") - } - if !foundPrev { - t.Error("previous-window keybind not found") - } -} - -func TestNiriParseInclude(t *testing.T) { - tmpDir := t.TempDir() - subDir := filepath.Join(tmpDir, "dms") - if err := os.MkdirAll(subDir, 0o755); err != nil { - t.Fatalf("Failed to create subdir: %v", err) - } - - mainConfig := filepath.Join(tmpDir, "config.kdl") - includeConfig := filepath.Join(subDir, "binds.kdl") - - mainContent := `binds { - Mod+Q { close-window; } -} -include "dms/binds.kdl" -` - includeContent := `binds { - Mod+T hotkey-overlay-title="Terminal" { spawn "kitty"; } -} -` - - if err := os.WriteFile(mainConfig, []byte(mainContent), 0o644); err != nil { - t.Fatalf("Failed to write main config: %v", err) - } - if err := os.WriteFile(includeConfig, []byte(includeContent), 0o644); err != nil { - t.Fatalf("Failed to write include config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds (1 main + 1 include), got %d", len(result.Section.Keybinds)) - } -} - -func TestNiriParseIncludeOverride(t *testing.T) { - tmpDir := t.TempDir() - subDir := filepath.Join(tmpDir, "dms") - if err := os.MkdirAll(subDir, 0o755); err != nil { - t.Fatalf("Failed to create subdir: %v", err) - } - - mainConfig := filepath.Join(tmpDir, "config.kdl") - includeConfig := filepath.Join(subDir, "binds.kdl") - - mainContent := `binds { - Mod+T hotkey-overlay-title="Main Terminal" { spawn "alacritty"; } -} -include "dms/binds.kdl" -` - includeContent := `binds { - Mod+T hotkey-overlay-title="Override Terminal" { spawn "kitty"; } -} -` - - if err := os.WriteFile(mainConfig, []byte(mainContent), 0o644); err != nil { - t.Fatalf("Failed to write main config: %v", err) - } - if err := os.WriteFile(includeConfig, []byte(includeContent), 0o644); err != nil { - t.Fatalf("Failed to write include config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 1 { - t.Errorf("Expected 1 keybind (later overrides earlier), got %d", len(result.Section.Keybinds)) - } - - if len(result.Section.Keybinds) > 0 { - kb := result.Section.Keybinds[0] - if kb.Description != "Override Terminal" { - t.Errorf("Expected description 'Override Terminal' (from include), got %q", kb.Description) - } - if len(kb.Args) != 1 || kb.Args[0] != "kitty" { - t.Errorf("Expected args [kitty] (from include), got %v", kb.Args) - } - } -} - -func TestNiriParseCircularInclude(t *testing.T) { - tmpDir := t.TempDir() - - mainConfig := filepath.Join(tmpDir, "config.kdl") - otherConfig := filepath.Join(tmpDir, "other.kdl") - - mainContent := `binds { - Mod+Q { close-window; } -} -include "other.kdl" -` - otherContent := `binds { - Mod+T { spawn "kitty"; } -} -include "config.kdl" -` - - if err := os.WriteFile(mainConfig, []byte(mainContent), 0o644); err != nil { - t.Fatalf("Failed to write main config: %v", err) - } - if err := os.WriteFile(otherConfig, []byte(otherContent), 0o644); err != nil { - t.Fatalf("Failed to write other config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed (should handle circular includes): %v", err) - } - - if len(result.Section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds (circular include handled), got %d", len(result.Section.Keybinds)) - } -} - -func TestNiriParseMissingInclude(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Q { close-window; } -} -include "nonexistent/file.kdl" -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed (should skip missing include): %v", err) - } - - if len(result.Section.Keybinds) != 1 { - t.Errorf("Expected 1 keybind (missing include skipped), got %d", len(result.Section.Keybinds)) - } -} - -func TestNiriParseNoBinds(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `cursor { - xcursor-theme "Bibata" - xcursor-size 24 -} - -input { - keyboard { - numlock - } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 0 { - t.Errorf("Expected 0 keybinds, got %d", len(result.Section.Keybinds)) - } -} - -func TestNiriParseErrors(t *testing.T) { - tests := []struct { - name string - path string - }{ - { - name: "nonexistent_directory", - path: "/nonexistent/path/that/does/not/exist", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := ParseNiriKeys(tt.path) - if err == nil { - t.Error("Expected error, got nil") - } - }) - } -} - -func TestNiriBindOverrideBehavior(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+T hotkey-overlay-title="First" { spawn "first"; } - Mod+Q { close-window; } - Mod+T hotkey-overlay-title="Second" { spawn "second"; } - Mod+F { fullscreen-window; } - Mod+T hotkey-overlay-title="Third" { spawn "third"; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 3 { - t.Fatalf("Expected 3 unique keybinds, got %d", len(result.Section.Keybinds)) - } - - var modT *NiriKeyBinding - for i := range result.Section.Keybinds { - kb := &result.Section.Keybinds[i] - if len(kb.Mods) == 1 && kb.Mods[0] == "Mod" && kb.Key == "T" { - modT = kb - break - } - } - - if modT == nil { - t.Fatal("Mod+T keybind not found") - } - - if modT.Description != "Third" { - t.Errorf("Mod+T description = %q, want 'Third' (last definition wins)", modT.Description) - } - - if len(modT.Args) != 1 || modT.Args[0] != "third" { - t.Errorf("Mod+T args = %v, want [third] (last definition wins)", modT.Args) - } -} - -func TestNiriBindOverrideWithIncludes(t *testing.T) { - tmpDir := t.TempDir() - subDir := filepath.Join(tmpDir, "custom") - if err := os.MkdirAll(subDir, 0o755); err != nil { - t.Fatalf("Failed to create subdir: %v", err) - } - - mainConfig := filepath.Join(tmpDir, "config.kdl") - includeConfig := filepath.Join(subDir, "overrides.kdl") - - mainContent := `binds { - Mod+1 { focus-workspace 1; } - Mod+2 { focus-workspace 2; } - Mod+T hotkey-overlay-title="Default Terminal" { spawn "xterm"; } -} -include "custom/overrides.kdl" -binds { - Mod+3 { focus-workspace 3; } -} -` - includeContent := `binds { - Mod+T hotkey-overlay-title="Custom Terminal" { spawn "kitty"; } - Mod+2 { focus-workspace 22; } -} -` - - if err := os.WriteFile(mainConfig, []byte(mainContent), 0o644); err != nil { - t.Fatalf("Failed to write main config: %v", err) - } - if err := os.WriteFile(includeConfig, []byte(includeContent), 0o644); err != nil { - t.Fatalf("Failed to write include config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 4 { - t.Errorf("Expected 4 unique keybinds, got %d", len(result.Section.Keybinds)) - } - - bindMap := make(map[string]*NiriKeyBinding) - for i := range result.Section.Keybinds { - kb := &result.Section.Keybinds[i] - key := "" - for _, m := range kb.Mods { - key += m + "+" - } - key += kb.Key - bindMap[key] = kb - } - - if kb, ok := bindMap["Mod+T"]; ok { - if kb.Description != "Custom Terminal" { - t.Errorf("Mod+T should be overridden by include, got description %q", kb.Description) - } - } else { - t.Error("Mod+T not found") - } - - if kb, ok := bindMap["Mod+2"]; ok { - if len(kb.Args) != 1 || kb.Args[0] != "22" { - t.Errorf("Mod+2 should be overridden by include with workspace 22, got args %v", kb.Args) - } - } else { - t.Error("Mod+2 not found") - } - - if _, ok := bindMap["Mod+1"]; !ok { - t.Error("Mod+1 should exist (not overridden)") - } - - if _, ok := bindMap["Mod+3"]; !ok { - t.Error("Mod+3 should exist (added after include)") - } -} - -func TestNiriParseMultipleArgs(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Space hotkey-overlay-title="Application Launcher" { - spawn "dms" "ipc" "call" "spotlight" "toggle"; - } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 1 { - t.Fatalf("Expected 1 keybind, got %d", len(result.Section.Keybinds)) - } - - kb := result.Section.Keybinds[0] - if len(kb.Args) != 5 { - t.Errorf("Expected 5 args, got %d: %v", len(kb.Args), kb.Args) - } - - expectedArgs := []string{"dms", "ipc", "call", "spotlight", "toggle"} - for i, arg := range expectedArgs { - if i < len(kb.Args) && kb.Args[i] != arg { - t.Errorf("Args[%d] = %q, want %q", i, kb.Args[i], arg) - } - } -} - -func TestNiriParseNumericWorkspaceBinds(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+1 hotkey-overlay-title="Focus Workspace 1" { focus-workspace 1; } - Mod+2 hotkey-overlay-title="Focus Workspace 2" { focus-workspace 2; } - Mod+0 hotkey-overlay-title="Focus Workspace 10" { focus-workspace 10; } - Mod+Shift+1 hotkey-overlay-title="Move to Workspace 1" { move-column-to-workspace 1; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 4 { - t.Errorf("Expected 4 keybinds, got %d", len(result.Section.Keybinds)) - } - - for _, kb := range result.Section.Keybinds { - switch kb.Key { - case "1": - if len(kb.Mods) == 1 && kb.Mods[0] == "Mod" { - if kb.Action != "focus-workspace" || len(kb.Args) != 1 || kb.Args[0] != "1" { - t.Errorf("Mod+1 action/args mismatch: %+v", kb) - } - if kb.Description != "Focus Workspace 1" { - t.Errorf("Mod+1 description = %q, want 'Focus Workspace 1'", kb.Description) - } - } - case "0": - if kb.Action != "focus-workspace" || len(kb.Args) != 1 || kb.Args[0] != "10" { - t.Errorf("Mod+0 action/args mismatch: %+v", kb) - } - } - } -} - -func TestNiriParseQuotedStringArgs(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Super+Minus hotkey-overlay-title="Adjust Column Width -10%" { set-column-width "-10%"; } - Super+Equal hotkey-overlay-title="Adjust Column Width +10%" { set-column-width "+10%"; } - Super+Shift+Minus hotkey-overlay-title="Adjust Window Height -10%" { set-window-height "-10%"; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 3 { - t.Errorf("Expected 3 keybinds, got %d", len(result.Section.Keybinds)) - } - - for _, kb := range result.Section.Keybinds { - if kb.Action == "set-column-width" { - if len(kb.Args) != 1 { - t.Errorf("set-column-width should have 1 arg, got %d", len(kb.Args)) - continue - } - if kb.Args[0] != "-10%" && kb.Args[0] != "+10%" { - t.Errorf("set-column-width arg = %q, want -10%% or +10%%", kb.Args[0]) - } - } - } -} - -func TestNiriParseActionWithProperties(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Shift+1 hotkey-overlay-title="Move to Workspace 1" { move-column-to-workspace 1 focus=false; } - Mod+Shift+2 hotkey-overlay-title="Move to Workspace 2" { move-column-to-workspace 2 focus=false; } - Alt+Tab { next-window scope="output"; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("ParseNiriKeys failed: %v", err) - } - - if len(result.Section.Keybinds) != 3 { - t.Errorf("Expected 3 keybinds, got %d", len(result.Section.Keybinds)) - } - - for _, kb := range result.Section.Keybinds { - switch kb.Action { - case "move-column-to-workspace": - if len(kb.Args) != 2 { - t.Errorf("move-column-to-workspace should have 2 args (index + focus), got %d", len(kb.Args)) - } - hasIndex := false - hasFocus := false - for _, arg := range kb.Args { - if arg == "1" || arg == "2" { - hasIndex = true - } - if arg == "focus=false" { - hasFocus = true - } - } - if !hasIndex { - t.Errorf("move-column-to-workspace missing index arg") - } - if !hasFocus { - t.Errorf("move-column-to-workspace missing focus=false arg") - } - case "next-window": - if kb.Key != "Tab" { - t.Errorf("next-window key = %q, want 'Tab'", kb.Key) - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_test.go deleted file mode 100644 index b04c5b2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/niri_test.go +++ /dev/null @@ -1,661 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestNiriProviderName(t *testing.T) { - provider := NewNiriProvider("") - if provider.Name() != "niri" { - t.Errorf("Name() = %q, want %q", provider.Name(), "niri") - } -} - -func TestNiriProviderGetCheatSheet(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Q { close-window; } - Mod+F { fullscreen-window; } - Mod+T hotkey-overlay-title="Open Terminal" { spawn "kitty"; } - Mod+1 { focus-workspace 1; } - Mod+Shift+1 { move-column-to-workspace 1; } - Print { screenshot; } - Mod+Shift+E { quit; } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewNiriProvider(tmpDir) - cheatSheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if cheatSheet.Title != "Niri Keybinds" { - t.Errorf("Title = %q, want %q", cheatSheet.Title, "Niri Keybinds") - } - - if cheatSheet.Provider != "niri" { - t.Errorf("Provider = %q, want %q", cheatSheet.Provider, "niri") - } - - windowBinds := cheatSheet.Binds["Window"] - if len(windowBinds) < 2 { - t.Errorf("Expected at least 2 Window binds, got %d", len(windowBinds)) - } - - execBinds := cheatSheet.Binds["Execute"] - if len(execBinds) < 1 { - t.Errorf("Expected at least 1 Execute bind, got %d", len(execBinds)) - } - - workspaceBinds := cheatSheet.Binds["Workspace"] - if len(workspaceBinds) < 2 { - t.Errorf("Expected at least 2 Workspace binds, got %d", len(workspaceBinds)) - } - - screenshotBinds := cheatSheet.Binds["Screenshot"] - if len(screenshotBinds) < 1 { - t.Errorf("Expected at least 1 Screenshot bind, got %d", len(screenshotBinds)) - } - - systemBinds := cheatSheet.Binds["System"] - if len(systemBinds) < 1 { - t.Errorf("Expected at least 1 System bind, got %d", len(systemBinds)) - } -} - -func TestNiriCategorizeByAction(t *testing.T) { - provider := NewNiriProvider("") - - tests := []struct { - action string - expected string - }{ - {"focus-workspace", "Workspace"}, - {"focus-workspace-up", "Workspace"}, - {"move-column-to-workspace", "Workspace"}, - {"focus-monitor-left", "Monitor"}, - {"move-column-to-monitor-right", "Monitor"}, - {"close-window", "Window"}, - {"fullscreen-window", "Window"}, - {"maximize-column", "Window"}, - {"toggle-window-floating", "Window"}, - {"focus-column-left", "Window"}, - {"move-column-right", "Window"}, - {"spawn", "Execute"}, - {"quit", "System"}, - {"power-off-monitors", "System"}, - {"screenshot", "Screenshot"}, - {"screenshot-window", "Screenshot"}, - {"toggle-overview", "Overview"}, - {"show-hotkey-overlay", "Overview"}, - {"next-window", "Alt-Tab"}, - {"previous-window", "Alt-Tab"}, - {"unknown-action", "Other"}, - } - - for _, tt := range tests { - t.Run(tt.action, func(t *testing.T) { - result := provider.categorizeByAction(tt.action) - if result != tt.expected { - t.Errorf("categorizeByAction(%q) = %q, want %q", tt.action, result, tt.expected) - } - }) - } -} - -func TestNiriFormatRawAction(t *testing.T) { - provider := NewNiriProvider("") - - tests := []struct { - action string - args []string - expected string - }{ - {"spawn", []string{"kitty"}, "spawn kitty"}, - {"spawn", []string{"dms", "ipc", "call"}, "spawn dms ipc call"}, - {"spawn", []string{"dms", "ipc", "call", "brightness", "increment", "5", ""}, `spawn dms ipc call brightness increment 5 ""`}, - {"spawn", []string{"dms", "ipc", "call", "dash", "toggle", ""}, `spawn dms ipc call dash toggle ""`}, - {"close-window", nil, "close-window"}, - {"fullscreen-window", nil, "fullscreen-window"}, - {"focus-workspace", []string{"1"}, "focus-workspace 1"}, - {"move-column-to-workspace", []string{"5"}, "move-column-to-workspace 5"}, - {"set-column-width", []string{"+10%"}, "set-column-width +10%"}, - } - - for _, tt := range tests { - t.Run(tt.action, func(t *testing.T) { - result := provider.formatRawAction(tt.action, tt.args) - if result != tt.expected { - t.Errorf("formatRawAction(%q, %v) = %q, want %q", tt.action, tt.args, result, tt.expected) - } - }) - } -} - -func TestNiriFormatKey(t *testing.T) { - provider := NewNiriProvider("") - - tests := []struct { - mods []string - key string - expected string - }{ - {[]string{"Mod"}, "Q", "Mod+Q"}, - {[]string{"Mod", "Shift"}, "F", "Mod+Shift+F"}, - {[]string{"Ctrl", "Alt"}, "Delete", "Ctrl+Alt+Delete"}, - {nil, "Print", "Print"}, - {[]string{}, "XF86AudioMute", "XF86AudioMute"}, - } - - for _, tt := range tests { - t.Run(tt.expected, func(t *testing.T) { - kb := &NiriKeyBinding{ - Mods: tt.mods, - Key: tt.key, - } - result := provider.formatKey(kb) - if result != tt.expected { - t.Errorf("formatKey(%v) = %q, want %q", kb, result, tt.expected) - } - }) - } -} - -func TestNiriDefaultConfigDir(t *testing.T) { - originalXDG := os.Getenv("XDG_CONFIG_HOME") - defer os.Setenv("XDG_CONFIG_HOME", originalXDG) - - os.Setenv("XDG_CONFIG_HOME", "/custom/config") - dir := defaultNiriConfigDir() - if dir != "/custom/config/niri" { - t.Errorf("With XDG_CONFIG_HOME set, got %q, want %q", dir, "/custom/config/niri") - } - - os.Unsetenv("XDG_CONFIG_HOME") - dir = defaultNiriConfigDir() - home, _ := os.UserHomeDir() - expected := filepath.Join(home, ".config", "niri") - if dir != expected { - t.Errorf("Without XDG_CONFIG_HOME, got %q, want %q", dir, expected) - } -} - -func TestNiriGenerateBindsContent(t *testing.T) { - provider := NewNiriProvider("") - - tests := []struct { - name string - binds map[string]*overrideBind - expected string - }{ - { - name: "empty binds", - binds: map[string]*overrideBind{}, - expected: "binds {}\n", - }, - { - name: "simple spawn bind", - binds: map[string]*overrideBind{ - "Mod+T": { - Key: "Mod+T", - Action: "spawn kitty", - Description: "Open Terminal", - }, - }, - expected: `binds { - Mod+T hotkey-overlay-title="Open Terminal" { spawn "kitty"; } -} -`, - }, - { - name: "spawn with multiple args", - binds: map[string]*overrideBind{ - "Mod+Space": { - Key: "Mod+Space", - Action: `spawn "dms" "ipc" "call" "spotlight" "toggle"`, - Description: "Application Launcher", - }, - }, - expected: `binds { - Mod+Space hotkey-overlay-title="Application Launcher" { spawn "dms" "ipc" "call" "spotlight" "toggle"; } -} -`, - }, - { - name: "bind with allow-when-locked", - binds: map[string]*overrideBind{ - "XF86AudioMute": { - Key: "XF86AudioMute", - Action: `spawn "dms" "ipc" "call" "audio" "mute"`, - Options: map[string]any{"allow-when-locked": true}, - }, - }, - expected: `binds { - XF86AudioMute allow-when-locked=true { spawn "dms" "ipc" "call" "audio" "mute"; } -} -`, - }, - { - name: "simple action without args", - binds: map[string]*overrideBind{ - "Mod+Q": { - Key: "Mod+Q", - Action: "close-window", - Description: "Close Window", - }, - }, - expected: `binds { - Mod+Q hotkey-overlay-title="Close Window" { close-window; } -} -`, - }, - { - name: "recent-windows action", - binds: map[string]*overrideBind{ - "Alt+Tab": { - Key: "Alt+Tab", - Action: "next-window", - }, - }, - expected: `binds { -} - -recent-windows { - binds { - Alt+Tab { next-window; } - } -} -`, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.generateBindsContent(tt.binds) - if result != tt.expected { - t.Errorf("generateBindsContent() =\n%q\nwant:\n%q", result, tt.expected) - } - }) - } -} - -func TestNiriGenerateBindsContentRoundTrip(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "Mod+Space": { - Key: "Mod+Space", - Action: `spawn "dms" "ipc" "call" "spotlight" "toggle"`, - Description: "Application Launcher", - }, - "XF86AudioMute": { - Key: "XF86AudioMute", - Action: `spawn "dms" "ipc" "call" "audio" "mute"`, - Options: map[string]any{"allow-when-locked": true}, - }, - "Mod+Q": { - Key: "Mod+Q", - Action: "close-window", - Description: "Close Window", - }, - } - - content := provider.generateBindsContent(binds) - - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write temp file: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("Failed to parse generated content: %v\nContent was:\n%s", err, content) - } - - if len(result.Section.Keybinds) != 3 { - t.Errorf("Expected 3 keybinds after round-trip, got %d", len(result.Section.Keybinds)) - } -} - -func TestNiriEmptyArgsPreservation(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "XF86MonBrightnessUp": { - Key: "XF86MonBrightnessUp", - Action: `spawn dms ipc call brightness increment 5 ""`, - Description: "Brightness Up", - }, - "XF86MonBrightnessDown": { - Key: "XF86MonBrightnessDown", - Action: `spawn dms ipc call brightness decrement 5 ""`, - Description: "Brightness Down", - }, - "Super+Alt+Page_Up": { - Key: "Super+Alt+Page_Up", - Action: `spawn dms ipc call dash toggle ""`, - Description: "Dashboard Toggle", - }, - } - - content := provider.generateBindsContent(binds) - - tmpDir := t.TempDir() - dmsDir := filepath.Join(tmpDir, "dms") - if err := os.MkdirAll(dmsDir, 0o755); err != nil { - t.Fatalf("Failed to create dms directory: %v", err) - } - - bindsFile := filepath.Join(dmsDir, "binds.kdl") - if err := os.WriteFile(bindsFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write binds file: %v", err) - } - - testProvider := NewNiriProvider(tmpDir) - loadedBinds, err := testProvider.loadOverrideBinds() - if err != nil { - t.Fatalf("Failed to load binds: %v\nContent was:\n%s", err, content) - } - - for key, expected := range binds { - loaded, ok := loadedBinds[key] - if !ok { - t.Errorf("Missing bind for key %s", key) - continue - } - if loaded.Action != expected.Action { - t.Errorf("Action mismatch for %s:\n got: %q\n want: %q", key, loaded.Action, expected.Action) - } - } -} - -func TestNiriProviderWithRealWorldConfig(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - - content := `binds { - Mod+Shift+Ctrl+D { debug-toggle-damage; } - Super+D { spawn "niri" "msg" "action" "toggle-overview"; } - Super+Tab repeat=false { toggle-overview; } - Mod+Shift+Slash { show-hotkey-overlay; } - - Mod+T hotkey-overlay-title="Open Terminal" { spawn "kitty"; } - Mod+Space hotkey-overlay-title="Application Launcher" { - spawn "dms" "ipc" "call" "spotlight" "toggle"; - } - - XF86AudioRaiseVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "increment" "3"; - } - XF86AudioLowerVolume allow-when-locked=true { - spawn "dms" "ipc" "call" "audio" "decrement" "3"; - } - - Mod+Q repeat=false { close-window; } - Mod+F { maximize-column; } - Mod+Shift+F { fullscreen-window; } - - Mod+Left { focus-column-left; } - Mod+Down { focus-window-down; } - Mod+Up { focus-window-up; } - Mod+Right { focus-column-right; } - - Mod+1 { focus-workspace 1; } - Mod+2 { focus-workspace 2; } - Mod+Shift+1 { move-column-to-workspace 1; } - Mod+Shift+2 { move-column-to-workspace 2; } - - Print { screenshot; } - Ctrl+Print { screenshot-screen; } - Alt+Print { screenshot-window; } - - Mod+Shift+E { quit; } -} - -recent-windows { - binds { - Alt+Tab { next-window scope="output"; } - Alt+Shift+Tab { previous-window scope="output"; } - } -} -` - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewNiriProvider(tmpDir) - cheatSheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - totalBinds := 0 - for _, binds := range cheatSheet.Binds { - totalBinds += len(binds) - } - - if totalBinds < 20 { - t.Errorf("Expected at least 20 keybinds, got %d", totalBinds) - } - - if len(cheatSheet.Binds["Alt-Tab"]) < 2 { - t.Errorf("Expected at least 2 Alt-Tab binds, got %d", len(cheatSheet.Binds["Alt-Tab"])) - } -} - -func TestNiriGenerateBindsContentNumericArgs(t *testing.T) { - provider := NewNiriProvider("") - - tests := []struct { - name string - binds map[string]*overrideBind - expected string - }{ - { - name: "workspace with numeric arg", - binds: map[string]*overrideBind{ - "Mod+1": { - Key: "Mod+1", - Action: "focus-workspace 1", - Description: "Focus Workspace 1", - }, - }, - expected: `binds { - Mod+1 hotkey-overlay-title="Focus Workspace 1" { focus-workspace 1; } -} -`, - }, - { - name: "workspace with large numeric arg", - binds: map[string]*overrideBind{ - "Mod+0": { - Key: "Mod+0", - Action: "focus-workspace 10", - Description: "Focus Workspace 10", - }, - }, - expected: `binds { - Mod+0 hotkey-overlay-title="Focus Workspace 10" { focus-workspace 10; } -} -`, - }, - { - name: "percentage string arg (should be quoted)", - binds: map[string]*overrideBind{ - "Super+Minus": { - Key: "Super+Minus", - Action: `set-column-width "-10%"`, - Description: "Adjust Column Width -10%", - }, - }, - expected: `binds { - Super+Minus hotkey-overlay-title="Adjust Column Width -10%" { set-column-width "-10%"; } -} -`, - }, - { - name: "positive percentage string arg", - binds: map[string]*overrideBind{ - "Super+Equal": { - Key: "Super+Equal", - Action: `set-column-width "+10%"`, - Description: "Adjust Column Width +10%", - }, - }, - expected: `binds { - Super+Equal hotkey-overlay-title="Adjust Column Width +10%" { set-column-width "+10%"; } -} -`, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.generateBindsContent(tt.binds) - if result != tt.expected { - t.Errorf("generateBindsContent() =\n%q\nwant:\n%q", result, tt.expected) - } - }) - } -} - -func TestNiriGenerateActionWithUnquotedPercentArg(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "Super+Equal": { - Key: "Super+Equal", - Action: "set-window-height +10%", - Description: "Adjust Window Height +10%", - }, - } - - content := provider.generateBindsContent(binds) - expected := `binds { - Super+Equal hotkey-overlay-title="Adjust Window Height +10%" { set-window-height "+10%"; } -} -` - if content != expected { - t.Errorf("Content mismatch.\nGot:\n%s\nWant:\n%s", content, expected) - } -} - -func TestNiriGenerateSpawnWithNumericArgs(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "XF86AudioLowerVolume": { - Key: "XF86AudioLowerVolume", - Action: `spawn "dms" "ipc" "call" "audio" "decrement" "3"`, - Options: map[string]any{"allow-when-locked": true}, - }, - } - - content := provider.generateBindsContent(binds) - expected := `binds { - XF86AudioLowerVolume allow-when-locked=true { spawn "dms" "ipc" "call" "audio" "decrement" "3"; } -} -` - if content != expected { - t.Errorf("Content mismatch.\nGot:\n%s\nWant:\n%s", content, expected) - } -} - -func TestNiriGenerateSpawnNumericArgFromCLI(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "XF86AudioLowerVolume": { - Key: "XF86AudioLowerVolume", - Action: "spawn dms ipc call audio decrement 3", - Options: map[string]any{"allow-when-locked": true}, - }, - } - - content := provider.generateBindsContent(binds) - expected := `binds { - XF86AudioLowerVolume allow-when-locked=true { spawn "dms" "ipc" "call" "audio" "decrement" "3"; } -} -` - if content != expected { - t.Errorf("Content mismatch.\nGot:\n%s\nWant:\n%s", content, expected) - } -} - -func TestNiriGenerateWorkspaceBindsRoundTrip(t *testing.T) { - provider := NewNiriProvider("") - - binds := map[string]*overrideBind{ - "Mod+1": { - Key: "Mod+1", - Action: "focus-workspace 1", - Description: "Focus Workspace 1", - }, - "Mod+2": { - Key: "Mod+2", - Action: "focus-workspace 2", - Description: "Focus Workspace 2", - }, - "Mod+Shift+1": { - Key: "Mod+Shift+1", - Action: "move-column-to-workspace 1", - Description: "Move to Workspace 1", - }, - "Super+Minus": { - Key: "Super+Minus", - Action: "set-column-width -10%", - Description: "Adjust Column Width -10%", - }, - } - - content := provider.generateBindsContent(binds) - - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config.kdl") - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write temp file: %v", err) - } - - result, err := ParseNiriKeys(tmpDir) - if err != nil { - t.Fatalf("Failed to parse generated content: %v\nContent was:\n%s", err, content) - } - - if len(result.Section.Keybinds) != 4 { - t.Errorf("Expected 4 keybinds after round-trip, got %d", len(result.Section.Keybinds)) - } - - foundFocusWS1 := false - foundMoveWS1 := false - foundSetWidth := false - - for _, kb := range result.Section.Keybinds { - switch { - case kb.Action == "focus-workspace" && len(kb.Args) > 0 && kb.Args[0] == "1": - foundFocusWS1 = true - case kb.Action == "move-column-to-workspace" && len(kb.Args) > 0 && kb.Args[0] == "1": - foundMoveWS1 = true - case kb.Action == "set-column-width" && len(kb.Args) > 0 && kb.Args[0] == "-10%": - foundSetWidth = true - } - } - - if !foundFocusWS1 { - t.Error("focus-workspace 1 not found after round-trip") - } - if !foundMoveWS1 { - t.Error("move-column-to-workspace 1 not found after round-trip") - } - if !foundSetWidth { - t.Error("set-column-width -10% not found after round-trip") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway.go deleted file mode 100644 index 93ceb73..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway.go +++ /dev/null @@ -1,150 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds" -) - -type SwayProvider struct { - configPath string - isScroll bool -} - -func NewSwayProvider(configPath string) *SwayProvider { - isScroll := false - _, scrollEnvSet := os.LookupEnv("SCROLLSOCK") - - if configPath == "" { - configDir, err := os.UserConfigDir() - if err != nil { - configDir = "" - } - if scrollEnvSet { - if configDir != "" { - configPath = filepath.Join(configDir, "scroll") - } - isScroll = true - } else { - if configDir != "" { - configPath = filepath.Join(configDir, "sway") - } - } - } else { - isScroll = strings.Contains(configPath, "scroll") - } - - return &SwayProvider{ - configPath: configPath, - isScroll: isScroll, - } -} - -func (s *SwayProvider) Name() string { - if s == nil { - if os.Getenv("SCROLLSOCK") != "" { - return "scroll" - } - return "sway" - } - - if s.isScroll { - return "scroll" - } - return "sway" -} - -func (s *SwayProvider) GetCheatSheet() (*keybinds.CheatSheet, error) { - section, err := ParseSwayKeys(s.configPath) - if err != nil { - return nil, fmt.Errorf("failed to parse sway config: %w", err) - } - - categorizedBinds := make(map[string][]keybinds.Keybind) - s.convertSection(section, "", categorizedBinds) - - cheatSheetTitle := "Sway Keybinds" - if s != nil && s.isScroll { - cheatSheetTitle = "Scroll Keybinds" - } - - return &keybinds.CheatSheet{ - Title: cheatSheetTitle, - Provider: s.Name(), - Binds: categorizedBinds, - }, nil -} - -func (s *SwayProvider) convertSection(section *SwaySection, subcategory string, categorizedBinds map[string][]keybinds.Keybind) { - currentSubcat := subcategory - if section.Name != "" { - currentSubcat = section.Name - } - - for _, kb := range section.Keybinds { - category := s.categorizeByCommand(kb.Command) - bind := s.convertKeybind(&kb, currentSubcat) - categorizedBinds[category] = append(categorizedBinds[category], bind) - } - - for _, child := range section.Children { - s.convertSection(&child, currentSubcat, categorizedBinds) - } -} - -func (s *SwayProvider) categorizeByCommand(command string) string { - command = strings.ToLower(command) - - switch { - case strings.Contains(command, "scratchpad"): - return "Scratchpad" - case strings.Contains(command, "workspace") && strings.Contains(command, "output"): - return "Monitor" - case strings.Contains(command, "workspace"): - return "Workspace" - case strings.Contains(command, "output"): - return "Monitor" - case strings.Contains(command, "layout"): - return "Layout" - case command == "kill" || - command == "fullscreen" || strings.Contains(command, "fullscreen") || - command == "floating toggle" || strings.Contains(command, "floating") || - strings.Contains(command, "focus") || - strings.Contains(command, "move") || - strings.Contains(command, "resize") || - strings.Contains(command, "split"): - return "Window" - case strings.HasPrefix(command, "exec"): - return "Execute" - case command == "exit" || command == "reload": - return "System" - default: - return "Other" - } -} - -func (s *SwayProvider) convertKeybind(kb *SwayKeyBinding, subcategory string) keybinds.Keybind { - key := s.formatKey(kb) - desc := kb.Comment - - if desc == "" { - desc = kb.Command - } - - return keybinds.Keybind{ - Key: key, - Description: desc, - Action: kb.Command, - Subcategory: subcategory, - } -} - -func (s *SwayProvider) formatKey(kb *SwayKeyBinding) string { - parts := make([]string, 0, len(kb.Mods)+1) - parts = append(parts, kb.Mods...) - parts = append(parts, kb.Key) - return strings.Join(parts, "+") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser.go deleted file mode 100644 index 647c9f7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser.go +++ /dev/null @@ -1,364 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -const ( - SwayTitleRegex = "#+!" - SwayHideComment = "[hidden]" -) - -var SwayModSeparators = []rune{'+', ' '} - -type SwayKeyBinding struct { - Mods []string `json:"mods"` - Key string `json:"key"` - Command string `json:"command"` - Comment string `json:"comment"` -} - -type SwaySection struct { - Children []SwaySection `json:"children"` - Keybinds []SwayKeyBinding `json:"keybinds"` - Name string `json:"name"` -} - -type SwayParser struct { - contentLines []string - readingLine int - variables map[string]string -} - -func NewSwayParser() *SwayParser { - return &SwayParser{ - contentLines: []string{}, - readingLine: 0, - variables: make(map[string]string), - } -} - -func (p *SwayParser) ReadContent(path string) error { - expandedPath, err := utils.ExpandPath(path) - if err != nil { - return err - } - - info, err := os.Stat(expandedPath) - if err != nil { - return err - } - - var files []string - if info.IsDir() { - mainConfig := filepath.Join(expandedPath, "config") - if fileInfo, err := os.Stat(mainConfig); err == nil && fileInfo.Mode().IsRegular() { - files = []string{mainConfig} - } else { - return os.ErrNotExist - } - } else { - files = []string{expandedPath} - } - - var combinedContent []string - for _, file := range files { - data, err := os.ReadFile(file) - if err != nil { - return err - } - combinedContent = append(combinedContent, string(data)) - } - - if len(combinedContent) == 0 { - return os.ErrNotExist - } - - fullContent := strings.Join(combinedContent, "\n") - p.contentLines = strings.Split(fullContent, "\n") - p.parseVariables() - return nil -} - -func (p *SwayParser) parseVariables() { - setRegex := regexp.MustCompile(`^\s*set\s+\$(\w+)\s+(.+)$`) - for _, line := range p.contentLines { - matches := setRegex.FindStringSubmatch(line) - if len(matches) == 3 { - varName := matches[1] - varValue := strings.TrimSpace(matches[2]) - p.variables[varName] = varValue - } - } -} - -func (p *SwayParser) expandVariables(text string) string { - result := text - for varName, varValue := range p.variables { - result = strings.ReplaceAll(result, "$"+varName, varValue) - } - return result -} - -func swayAutogenerateComment(command string) string { - command = strings.TrimSpace(command) - - if strings.HasPrefix(command, "exec ") { - cmdPart := strings.TrimPrefix(command, "exec ") - cmdPart = strings.TrimPrefix(cmdPart, "--no-startup-id ") - return cmdPart - } - - switch { - case command == "kill": - return "Close window" - case command == "exit": - return "Exit Sway" - case command == "reload": - return "Reload configuration" - case strings.HasPrefix(command, "fullscreen"): - return "Toggle fullscreen" - case strings.HasPrefix(command, "floating toggle"): - return "Float/unfloat window" - case strings.HasPrefix(command, "focus mode_toggle"): - return "Toggle focus mode" - case strings.HasPrefix(command, "focus parent"): - return "Focus parent container" - case strings.HasPrefix(command, "focus left"): - return "Focus left" - case strings.HasPrefix(command, "focus right"): - return "Focus right" - case strings.HasPrefix(command, "focus up"): - return "Focus up" - case strings.HasPrefix(command, "focus down"): - return "Focus down" - case strings.HasPrefix(command, "focus output"): - return "Focus monitor" - case strings.HasPrefix(command, "move left"): - return "Move window left" - case strings.HasPrefix(command, "move right"): - return "Move window right" - case strings.HasPrefix(command, "move up"): - return "Move window up" - case strings.HasPrefix(command, "move down"): - return "Move window down" - case strings.HasPrefix(command, "move container to workspace"): - if strings.Contains(command, "prev") { - return "Move to previous workspace" - } - if strings.Contains(command, "next") { - return "Move to next workspace" - } - parts := strings.Fields(command) - if len(parts) > 4 { - return "Move to workspace " + parts[len(parts)-1] - } - return "Move to workspace" - case strings.HasPrefix(command, "move workspace to output"): - return "Move workspace to monitor" - case strings.HasPrefix(command, "workspace"): - if strings.Contains(command, "prev") { - return "Previous workspace" - } - if strings.Contains(command, "next") { - return "Next workspace" - } - parts := strings.Fields(command) - if len(parts) > 1 { - wsNum := parts[len(parts)-1] - return "Workspace " + wsNum - } - return "Switch workspace" - case strings.HasPrefix(command, "layout"): - parts := strings.Fields(command) - if len(parts) > 1 { - return "Layout " + parts[1] - } - return "Change layout" - case strings.HasPrefix(command, "split"): - if strings.Contains(command, "h") { - return "Split horizontal" - } - if strings.Contains(command, "v") { - return "Split vertical" - } - return "Split container" - case strings.HasPrefix(command, "resize"): - return "Resize window" - case strings.Contains(command, "scratchpad"): - return "Toggle scratchpad" - default: - return command - } -} - -func (p *SwayParser) getKeybindAtLine(lineNumber int) *SwayKeyBinding { - if lineNumber >= len(p.contentLines) { - return nil - } - - line := p.contentLines[lineNumber] - - bindMatch := regexp.MustCompile(`^\s*(bindsym|bindcode)\s+(.+)$`) - matches := bindMatch.FindStringSubmatch(line) - if len(matches) < 3 { - return nil - } - - content := matches[2] - - parts := strings.SplitN(content, "#", 2) - keys := strings.TrimSpace(parts[0]) - - var comment string - if len(parts) > 1 { - comment = strings.TrimSpace(parts[1]) - } - - if strings.HasPrefix(comment, SwayHideComment) { - return nil - } - - flags := "" - if strings.HasPrefix(keys, "--") { - spaceIdx := strings.Index(keys, " ") - if spaceIdx > 0 { - flags = keys[:spaceIdx] - keys = strings.TrimSpace(keys[spaceIdx+1:]) - } - } - - keyParts := strings.Fields(keys) - if len(keyParts) < 2 { - return nil - } - - keyCombo := keyParts[0] - keyCombo = p.expandVariables(keyCombo) - command := strings.Join(keyParts[1:], " ") - command = p.expandVariables(command) - - var modList []string - var key string - - modstring := keyCombo + string(SwayModSeparators[0]) - pos := 0 - for index, char := range modstring { - isModSep := false - for _, sep := range SwayModSeparators { - if char == sep { - isModSep = true - break - } - } - if isModSep { - if index-pos > 0 { - part := modstring[pos:index] - if swayIsMod(part) { - modList = append(modList, part) - } else { - key = part - } - } - pos = index + 1 - } - } - - if comment == "" { - comment = swayAutogenerateComment(command) - } - - _ = flags - - return &SwayKeyBinding{ - Mods: modList, - Key: key, - Command: command, - Comment: comment, - } -} - -func swayIsMod(s string) bool { - s = strings.ToLower(s) - if s == "mod1" || s == "mod2" || s == "mod3" || s == "mod4" || s == "mod5" || - s == "shift" || s == "control" || s == "ctrl" || s == "alt" || s == "super" || - strings.HasPrefix(s, "$") { - return true - } - - isNumeric := true - for _, c := range s { - if c < '0' || c > '9' { - isNumeric = false - break - } - } - if isNumeric && len(s) >= 2 { - return true - } - return false -} - -func (p *SwayParser) getBindsRecursive(currentContent *SwaySection, scope int) *SwaySection { - titleRegex := regexp.MustCompile(SwayTitleRegex) - - for p.readingLine < len(p.contentLines) { - line := p.contentLines[p.readingLine] - - loc := titleRegex.FindStringIndex(line) - if loc != nil && loc[0] == 0 { - headingScope := strings.Index(line, "!") - - if headingScope <= scope { - p.readingLine-- - return currentContent - } - - sectionName := strings.TrimSpace(line[headingScope+1:]) - p.readingLine++ - - childSection := &SwaySection{ - Children: []SwaySection{}, - Keybinds: []SwayKeyBinding{}, - Name: sectionName, - } - result := p.getBindsRecursive(childSection, headingScope) - currentContent.Children = append(currentContent.Children, *result) - - } else if line == "" || (!strings.Contains(line, "bindsym") && !strings.Contains(line, "bindcode")) { - - } else { - keybind := p.getKeybindAtLine(p.readingLine) - if keybind != nil { - currentContent.Keybinds = append(currentContent.Keybinds, *keybind) - } - } - - p.readingLine++ - } - - return currentContent -} - -func (p *SwayParser) ParseKeys() *SwaySection { - p.readingLine = 0 - rootSection := &SwaySection{ - Children: []SwaySection{}, - Keybinds: []SwayKeyBinding{}, - Name: "", - } - return p.getBindsRecursive(rootSection, 0) -} - -func ParseSwayKeys(path string) (*SwaySection, error) { - parser := NewSwayParser() - if err := parser.ReadContent(path); err != nil { - return nil, err - } - return parser.ParseKeys(), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser_test.go deleted file mode 100644 index 6bb5ecf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_parser_test.go +++ /dev/null @@ -1,471 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestSwayAutogenerateComment(t *testing.T) { - tests := []struct { - command string - expected string - }{ - {"exec kitty", "kitty"}, - {"exec --no-startup-id firefox", "firefox"}, - {"kill", "Close window"}, - {"exit", "Exit Sway"}, - {"reload", "Reload configuration"}, - {"fullscreen toggle", "Toggle fullscreen"}, - {"floating toggle", "Float/unfloat window"}, - {"focus mode_toggle", "Toggle focus mode"}, - {"focus parent", "Focus parent container"}, - {"focus left", "Focus left"}, - {"focus right", "Focus right"}, - {"focus up", "Focus up"}, - {"focus down", "Focus down"}, - {"focus output left", "Focus monitor"}, - {"move left", "Move window left"}, - {"move right", "Move window right"}, - {"move up", "Move window up"}, - {"move down", "Move window down"}, - {"move container to workspace number 1", "Move to workspace 1"}, - {"move container to workspace prev", "Move to previous workspace"}, - {"move container to workspace next", "Move to next workspace"}, - {"move workspace to output left", "Move workspace to monitor"}, - {"workspace number 1", "Workspace 1"}, - {"workspace prev", "Previous workspace"}, - {"workspace next", "Next workspace"}, - {"layout tabbed", "Layout tabbed"}, - {"layout stacking", "Layout stacking"}, - {"splith", "Split horizontal"}, - {"splitv", "Split vertical"}, - {"resize grow width 10 ppt", "Resize window"}, - {"move scratchpad", "Toggle scratchpad"}, - } - - for _, tt := range tests { - t.Run(tt.command, func(t *testing.T) { - result := swayAutogenerateComment(tt.command) - if result != tt.expected { - t.Errorf("swayAutogenerateComment(%q) = %q, want %q", - tt.command, result, tt.expected) - } - }) - } -} - -func TestSwayGetKeybindAtLine(t *testing.T) { - tests := []struct { - name string - line string - expected *SwayKeyBinding - }{ - { - name: "basic_keybind", - line: "bindsym Mod4+q kill", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "q", - Command: "kill", - Comment: "Close window", - }, - }, - { - name: "keybind_with_exec", - line: "bindsym Mod4+t exec kitty", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "t", - Command: "exec kitty", - Comment: "kitty", - }, - }, - { - name: "keybind_with_comment", - line: "bindsym Mod4+Space exec dms ipc call spotlight toggle # Open launcher", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "Space", - Command: "exec dms ipc call spotlight toggle", - Comment: "Open launcher", - }, - }, - { - name: "keybind_hidden", - line: "bindsym Mod4+h exec secret # [hidden]", - expected: nil, - }, - { - name: "keybind_multiple_mods", - line: "bindsym Mod4+Shift+e exit", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4", "Shift"}, - Key: "e", - Command: "exit", - Comment: "Exit Sway", - }, - }, - { - name: "keybind_no_mods", - line: "bindsym Print exec grim screenshot.png", - expected: &SwayKeyBinding{ - Mods: []string{}, - Key: "Print", - Command: "exec grim screenshot.png", - Comment: "grim screenshot.png", - }, - }, - { - name: "keybind_with_flags", - line: "bindsym --release Mod4+x exec notify-send released", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "x", - Command: "exec notify-send released", - Comment: "notify-send released", - }, - }, - { - name: "keybind_focus_direction", - line: "bindsym Mod4+Left focus left", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "Left", - Command: "focus left", - Comment: "Focus left", - }, - }, - { - name: "keybind_workspace", - line: "bindsym Mod4+1 workspace number 1", - expected: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "1", - Command: "workspace number 1", - Comment: "Workspace 1", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - parser := NewSwayParser() - parser.contentLines = []string{tt.line} - result := parser.getKeybindAtLine(0) - - if tt.expected == nil { - if result != nil { - t.Errorf("expected nil, got %+v", result) - } - return - } - - if result == nil { - t.Errorf("expected %+v, got nil", tt.expected) - return - } - - if result.Key != tt.expected.Key { - t.Errorf("Key = %q, want %q", result.Key, tt.expected.Key) - } - if result.Command != tt.expected.Command { - t.Errorf("Command = %q, want %q", result.Command, tt.expected.Command) - } - if result.Comment != tt.expected.Comment { - t.Errorf("Comment = %q, want %q", result.Comment, tt.expected.Comment) - } - if len(result.Mods) != len(tt.expected.Mods) { - t.Errorf("Mods length = %d, want %d", len(result.Mods), len(tt.expected.Mods)) - } else { - for i := range result.Mods { - if result.Mods[i] != tt.expected.Mods[i] { - t.Errorf("Mods[%d] = %q, want %q", i, result.Mods[i], tt.expected.Mods[i]) - } - } - } - }) - } -} - -func TestSwayVariableExpansion(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := `set $mod Mod4 -set $term kitty -set $menu rofi - -bindsym $mod+t exec $term -bindsym $mod+d exec $menu -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseSwayKeys(configFile) - if err != nil { - t.Fatalf("ParseSwayKeys failed: %v", err) - } - - if len(section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds, got %d", len(section.Keybinds)) - } - - if len(section.Keybinds) > 0 { - if section.Keybinds[0].Mods[0] != "Mod4" { - t.Errorf("Expected Mod4, got %q", section.Keybinds[0].Mods[0]) - } - if section.Keybinds[0].Command != "exec kitty" { - t.Errorf("Expected 'exec kitty', got %q", section.Keybinds[0].Command) - } - } - - if len(section.Keybinds) > 1 { - if section.Keybinds[1].Command != "exec rofi" { - t.Errorf("Expected 'exec rofi', got %q", section.Keybinds[1].Command) - } - } -} - -func TestSwayParseKeysWithSections(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := `set $mod Mod4 - -##! Window Management -bindsym $mod+q kill -bindsym $mod+f fullscreen toggle - -###! Focus -bindsym $mod+Left focus left -bindsym $mod+Right focus right - -##! Applications -bindsym $mod+t exec kitty # Terminal -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseSwayKeys(tmpDir) - if err != nil { - t.Fatalf("ParseSwayKeys failed: %v", err) - } - - if len(section.Children) != 2 { - t.Errorf("Expected 2 top-level sections, got %d", len(section.Children)) - } - - if len(section.Children) >= 1 { - windowMgmt := section.Children[0] - if windowMgmt.Name != "Window Management" { - t.Errorf("First section name = %q, want %q", windowMgmt.Name, "Window Management") - } - if len(windowMgmt.Keybinds) != 2 { - t.Errorf("Window Management keybinds = %d, want 2", len(windowMgmt.Keybinds)) - } - - if len(windowMgmt.Children) != 1 { - t.Errorf("Window Management children = %d, want 1", len(windowMgmt.Children)) - } else { - focus := windowMgmt.Children[0] - if focus.Name != "Focus" { - t.Errorf("Focus section name = %q, want %q", focus.Name, "Focus") - } - if len(focus.Keybinds) != 2 { - t.Errorf("Focus keybinds = %d, want 2", len(focus.Keybinds)) - } - } - } - - if len(section.Children) >= 2 { - apps := section.Children[1] - if apps.Name != "Applications" { - t.Errorf("Second section name = %q, want %q", apps.Name, "Applications") - } - if len(apps.Keybinds) != 1 { - t.Errorf("Applications keybinds = %d, want 1", len(apps.Keybinds)) - } - if len(apps.Keybinds) > 0 && apps.Keybinds[0].Comment != "Terminal" { - t.Errorf("Applications keybind comment = %q, want %q", apps.Keybinds[0].Comment, "Terminal") - } - } -} - -func TestSwayReadContentErrors(t *testing.T) { - tests := []struct { - name string - path string - }{ - { - name: "nonexistent_directory", - path: "/nonexistent/path/that/does/not/exist", - }, - { - name: "empty_directory", - path: t.TempDir(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := ParseSwayKeys(tt.path) - if err == nil { - t.Error("Expected error, got nil") - } - }) - } -} - -func TestSwayReadContentWithTildeExpansion(t *testing.T) { - homeDir, err := os.UserHomeDir() - if err != nil { - t.Skip("Cannot get home directory") - } - - tmpSubdir := filepath.Join(homeDir, ".config", "test-sway-"+t.Name()) - if err := os.MkdirAll(tmpSubdir, 0o755); err != nil { - t.Skip("Cannot create test directory in home") - } - defer os.RemoveAll(tmpSubdir) - - configFile := filepath.Join(tmpSubdir, "config") - if err := os.WriteFile(configFile, []byte("bindsym Mod4+q kill\n"), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - relPath, err := filepath.Rel(homeDir, tmpSubdir) - if err != nil { - t.Skip("Cannot create relative path") - } - - parser := NewSwayParser() - tildePathMatch := "~/" + relPath - err = parser.ReadContent(tildePathMatch) - - if err != nil { - t.Errorf("ReadContent with tilde path failed: %v", err) - } -} - -func TestSwayEmptyAndCommentLines(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := ` -# This is a comment -bindsym Mod4+q kill - -# Another comment - -bindsym Mod4+t exec kitty -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseSwayKeys(configFile) - if err != nil { - t.Fatalf("ParseSwayKeys failed: %v", err) - } - - if len(section.Keybinds) != 2 { - t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(section.Keybinds)) - } -} - -func TestSwayRealWorldConfig(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := `set $mod Mod4 -set $term kitty - -## Application Launchers -bindsym $mod+t exec $term -bindsym $mod+Space exec rofi - -## Window Management -bindsym $mod+q kill -bindsym $mod+f fullscreen toggle - -## Focus Navigation -bindsym $mod+Left focus left -bindsym $mod+Right focus right - -## Workspace Navigation -bindsym $mod+1 workspace number 1 -bindsym $mod+2 workspace number 2 -bindsym $mod+Shift+1 move container to workspace number 1 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - section, err := ParseSwayKeys(configFile) - if err != nil { - t.Fatalf("ParseSwayKeys failed: %v", err) - } - - if len(section.Keybinds) < 9 { - t.Errorf("Expected at least 9 keybinds, got %d", len(section.Keybinds)) - } - - foundExec := false - foundKill := false - foundWorkspace := false - - for _, kb := range section.Keybinds { - if kb.Command == "exec kitty" { - foundExec = true - } - if kb.Command == "kill" { - foundKill = true - } - if kb.Command == "workspace number 1" { - foundWorkspace = true - } - } - - if !foundExec { - t.Error("Did not find exec kitty keybind") - } - if !foundKill { - t.Error("Did not find kill keybind") - } - if !foundWorkspace { - t.Error("Did not find workspace 1 keybind") - } -} - -func TestSwayIsMod(t *testing.T) { - tests := []struct { - input string - expected bool - }{ - {"Mod4", true}, - {"Shift", true}, - {"Control", true}, - {"Alt", true}, - {"Super", true}, - {"$mod", true}, - {"Left", false}, - {"q", false}, - {"1", false}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - result := swayIsMod(tt.input) - if result != tt.expected { - t.Errorf("swayIsMod(%q) = %v, want %v", tt.input, result, tt.expected) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_test.go deleted file mode 100644 index fd476d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/providers/sway_test.go +++ /dev/null @@ -1,293 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestSwayProviderName(t *testing.T) { - provider := NewSwayProvider("") - if provider.Name() != "sway" { - t.Errorf("Name() = %q, want %q", provider.Name(), "sway") - } -} - -func TestSwayProviderDefaultPath(t *testing.T) { - provider := NewSwayProvider("") - configDir, err := os.UserConfigDir() - if err != nil { - t.Skip("UserConfigDir not available") - } - expected := filepath.Join(configDir, "sway") - if provider.configPath != expected { - t.Errorf("configPath = %q, want %q", provider.configPath, expected) - } -} - -func TestSwayProviderCustomPath(t *testing.T) { - customPath := "/custom/path" - provider := NewSwayProvider(customPath) - if provider.configPath != customPath { - t.Errorf("configPath = %q, want %q", provider.configPath, customPath) - } -} - -func TestSwayCategorizeByCommand(t *testing.T) { - tests := []struct { - command string - expected string - }{ - {"workspace number 1", "Workspace"}, - {"workspace prev", "Workspace"}, - {"workspace next", "Workspace"}, - {"move container to workspace number 1", "Workspace"}, - {"focus output left", "Monitor"}, - {"move workspace to output right", "Monitor"}, - {"kill", "Window"}, - {"fullscreen toggle", "Window"}, - {"floating toggle", "Window"}, - {"focus left", "Window"}, - {"focus right", "Window"}, - {"move left", "Window"}, - {"move right", "Window"}, - {"resize grow width 10px", "Window"}, - {"splith", "Window"}, - {"splitv", "Window"}, - {"layout tabbed", "Layout"}, - {"layout stacking", "Layout"}, - {"move scratchpad", "Scratchpad"}, - {"scratchpad show", "Scratchpad"}, - {"exec kitty", "Execute"}, - {"exec --no-startup-id firefox", "Execute"}, - {"exit", "System"}, - {"reload", "System"}, - {"unknown command", "Other"}, - } - - provider := NewSwayProvider("") - for _, tt := range tests { - t.Run(tt.command, func(t *testing.T) { - result := provider.categorizeByCommand(tt.command) - if result != tt.expected { - t.Errorf("categorizeByCommand(%q) = %q, want %q", tt.command, result, tt.expected) - } - }) - } -} - -func TestSwayFormatKey(t *testing.T) { - tests := []struct { - name string - keybind *SwayKeyBinding - expected string - }{ - { - name: "single_mod", - keybind: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "q", - }, - expected: "Mod4+q", - }, - { - name: "multiple_mods", - keybind: &SwayKeyBinding{ - Mods: []string{"Mod4", "Shift"}, - Key: "e", - }, - expected: "Mod4+Shift+e", - }, - { - name: "no_mods", - keybind: &SwayKeyBinding{ - Mods: []string{}, - Key: "Print", - }, - expected: "Print", - }, - } - - provider := NewSwayProvider("") - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.formatKey(tt.keybind) - if result != tt.expected { - t.Errorf("formatKey() = %q, want %q", result, tt.expected) - } - }) - } -} - -func TestSwayConvertKeybind(t *testing.T) { - tests := []struct { - name string - keybind *SwayKeyBinding - wantKey string - wantDesc string - }{ - { - name: "with_comment", - keybind: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "t", - Command: "exec kitty", - Comment: "Open terminal", - }, - wantKey: "Mod4+t", - wantDesc: "Open terminal", - }, - { - name: "without_comment", - keybind: &SwayKeyBinding{ - Mods: []string{"Mod4"}, - Key: "r", - Command: "reload", - Comment: "", - }, - wantKey: "Mod4+r", - wantDesc: "reload", - }, - } - - provider := NewSwayProvider("") - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := provider.convertKeybind(tt.keybind, "") - if result.Key != tt.wantKey { - t.Errorf("convertKeybind().Key = %q, want %q", result.Key, tt.wantKey) - } - if result.Description != tt.wantDesc { - t.Errorf("convertKeybind().Description = %q, want %q", result.Description, tt.wantDesc) - } - }) - } -} - -func TestSwayGetCheatSheet(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := `set $mod Mod4 -set $term kitty - -# System -bindsym $mod+Shift+c reload -bindsym $mod+Shift+e exit - -# Applications -bindsym $mod+t exec $term -bindsym $mod+Space exec rofi - -# Window Management -bindsym $mod+q kill -bindsym $mod+f fullscreen toggle -bindsym $mod+Left focus left -bindsym $mod+Right focus right - -# Workspace -bindsym $mod+1 workspace number 1 -bindsym $mod+2 workspace number 2 -bindsym $mod+Shift+1 move container to workspace number 1 - -# Layout -bindsym $mod+s layout stacking -bindsym $mod+w layout tabbed -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewSwayProvider(tmpDir) - sheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - if sheet == nil { - t.Fatal("Expected non-nil CheatSheet") - } - - if sheet.Title != "Sway Keybinds" { - t.Errorf("Title = %q, want %q", sheet.Title, "Sway Keybinds") - } - - if sheet.Provider != "sway" { - t.Errorf("Provider = %q, want %q", sheet.Provider, "sway") - } - - categories := []string{"System", "Execute", "Window", "Workspace", "Layout"} - for _, category := range categories { - if _, exists := sheet.Binds[category]; !exists { - t.Errorf("Expected category %q to exist", category) - } - } - - if len(sheet.Binds["System"]) < 2 { - t.Error("Expected at least 2 System keybinds") - } - if len(sheet.Binds["Execute"]) < 2 { - t.Error("Expected at least 2 Execute keybinds") - } - if len(sheet.Binds["Window"]) < 4 { - t.Error("Expected at least 4 Window keybinds") - } - if len(sheet.Binds["Workspace"]) < 3 { - t.Error("Expected at least 3 Workspace keybinds") - } -} - -func TestSwayGetCheatSheetError(t *testing.T) { - provider := NewSwayProvider("/nonexistent/path") - _, err := provider.GetCheatSheet() - if err == nil { - t.Error("Expected error for nonexistent path, got nil") - } -} - -func TestSwayIntegration(t *testing.T) { - tmpDir := t.TempDir() - configFile := filepath.Join(tmpDir, "config") - - content := `set $mod Mod4 - -bindsym $mod+t exec kitty # Terminal -bindsym $mod+q kill -bindsym $mod+f fullscreen toggle -bindsym $mod+1 workspace number 1 -` - - if err := os.WriteFile(configFile, []byte(content), 0o644); err != nil { - t.Fatalf("Failed to write test config: %v", err) - } - - provider := NewSwayProvider(tmpDir) - sheet, err := provider.GetCheatSheet() - if err != nil { - t.Fatalf("GetCheatSheet failed: %v", err) - } - - totalBinds := 0 - for _, binds := range sheet.Binds { - totalBinds += len(binds) - } - - expectedBinds := 4 - if totalBinds != expectedBinds { - t.Errorf("Expected %d total keybinds, got %d", expectedBinds, totalBinds) - } - - foundTerminal := false - for _, binds := range sheet.Binds { - for _, bind := range binds { - if bind.Description == "Terminal" && bind.Key == "Mod4+t" { - foundTerminal = true - } - } - } - - if !foundTerminal { - t.Error("Did not find terminal keybind with correct key and description") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry.go deleted file mode 100644 index d726838..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry.go +++ /dev/null @@ -1,79 +0,0 @@ -package keybinds - -import ( - "fmt" - "sync" -) - -type Registry struct { - mu sync.RWMutex - providers map[string]Provider -} - -func NewRegistry() *Registry { - return &Registry{ - providers: make(map[string]Provider), - } -} - -func (r *Registry) Register(provider Provider) error { - if provider == nil { - return fmt.Errorf("cannot register nil provider") - } - - name := provider.Name() - if name == "" { - return fmt.Errorf("provider name cannot be empty") - } - - r.mu.Lock() - defer r.mu.Unlock() - - if _, exists := r.providers[name]; exists { - return fmt.Errorf("provider %q already registered", name) - } - - r.providers[name] = provider - return nil -} - -func (r *Registry) Get(name string) (Provider, error) { - r.mu.RLock() - defer r.mu.RUnlock() - - provider, exists := r.providers[name] - if !exists { - return nil, fmt.Errorf("provider %q not found", name) - } - - return provider, nil -} - -func (r *Registry) List() []string { - r.mu.RLock() - defer r.mu.RUnlock() - - names := make([]string, 0, len(r.providers)) - for name := range r.providers { - names = append(names, name) - } - return names -} - -var defaultRegistry = NewRegistry() - -func GetDefaultRegistry() *Registry { - return defaultRegistry -} - -func Register(provider Provider) error { - return defaultRegistry.Register(provider) -} - -func Get(name string) (Provider, error) { - return defaultRegistry.Get(name) -} - -func List() []string { - return defaultRegistry.List() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry_test.go deleted file mode 100644 index c3ddfee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/registry_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package keybinds - -import ( - "testing" -) - -type mockProvider struct { - name string - err error -} - -func (m *mockProvider) Name() string { - return m.name -} - -func (m *mockProvider) GetCheatSheet() (*CheatSheet, error) { - if m.err != nil { - return nil, m.err - } - return &CheatSheet{ - Title: "Test", - Provider: m.name, - Binds: make(map[string][]Keybind), - }, nil -} - -func TestNewRegistry(t *testing.T) { - r := NewRegistry() - if r == nil { - t.Fatal("NewRegistry returned nil") - } - - if r.providers == nil { - t.Error("providers map is nil") - } -} - -func TestRegisterProvider(t *testing.T) { - tests := []struct { - name string - provider Provider - expectError bool - errorMsg string - }{ - { - name: "valid provider", - provider: &mockProvider{name: "test"}, - expectError: false, - }, - { - name: "nil provider", - provider: nil, - expectError: true, - errorMsg: "cannot register nil provider", - }, - { - name: "empty name", - provider: &mockProvider{name: ""}, - expectError: true, - errorMsg: "provider name cannot be empty", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := NewRegistry() - err := r.Register(tt.provider) - - if tt.expectError { - if err == nil { - t.Error("expected error, got nil") - } - return - } - - if err != nil { - t.Errorf("unexpected error: %v", err) - } - }) - } -} - -func TestRegisterDuplicate(t *testing.T) { - r := NewRegistry() - p := &mockProvider{name: "test"} - - if err := r.Register(p); err != nil { - t.Fatalf("first registration failed: %v", err) - } - - err := r.Register(p) - if err == nil { - t.Error("expected error when registering duplicate, got nil") - } -} - -func TestGetProvider(t *testing.T) { - r := NewRegistry() - p := &mockProvider{name: "test"} - - if err := r.Register(p); err != nil { - t.Fatalf("registration failed: %v", err) - } - - retrieved, err := r.Get("test") - if err != nil { - t.Fatalf("Get failed: %v", err) - } - - if retrieved.Name() != "test" { - t.Errorf("Got provider name %q, want %q", retrieved.Name(), "test") - } -} - -func TestGetNonexistent(t *testing.T) { - r := NewRegistry() - - _, err := r.Get("nonexistent") - if err == nil { - t.Error("expected error for nonexistent provider, got nil") - } -} - -func TestListProviders(t *testing.T) { - r := NewRegistry() - - p1 := &mockProvider{name: "test1"} - p2 := &mockProvider{name: "test2"} - p3 := &mockProvider{name: "test3"} - - r.Register(p1) - r.Register(p2) - r.Register(p3) - - list := r.List() - - if len(list) != 3 { - t.Errorf("expected 3 providers, got %d", len(list)) - } - - found := make(map[string]bool) - for _, name := range list { - found[name] = true - } - - expected := []string{"test1", "test2", "test3"} - for _, name := range expected { - if !found[name] { - t.Errorf("expected provider %q not found in list", name) - } - } -} - -func TestDefaultRegistry(t *testing.T) { - p := &mockProvider{name: "default-test"} - - err := Register(p) - if err != nil { - t.Fatalf("Register failed: %v", err) - } - - retrieved, err := Get("default-test") - if err != nil { - t.Fatalf("Get failed: %v", err) - } - - if retrieved.Name() != "default-test" { - t.Errorf("Got provider name %q, want %q", retrieved.Name(), "default-test") - } - - list := List() - found := false - for _, name := range list { - if name == "default-test" { - found = true - break - } - } - - if !found { - t.Error("provider not found in default registry list") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/types.go deleted file mode 100644 index 109b53b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/keybinds/types.go +++ /dev/null @@ -1,47 +0,0 @@ -package keybinds - -type Keybind struct { - Key string `json:"key"` - Description string `json:"desc"` - Action string `json:"action,omitempty"` - Subcategory string `json:"subcat,omitempty"` - Source string `json:"source,omitempty"` - HideOnOverlay bool `json:"hideOnOverlay,omitempty"` - CooldownMs int `json:"cooldownMs,omitempty"` - Flags string `json:"flags,omitempty"` // Hyprland bind flags: e=repeat, l=locked, r=release, o=long-press - AllowWhenLocked bool `json:"allowWhenLocked,omitempty"` - AllowInhibiting *bool `json:"allowInhibiting,omitempty"` // nil=default(true), false=explicitly disabled - Repeat *bool `json:"repeat,omitempty"` // nil=default(true), false=explicitly disabled - Conflict *Keybind `json:"conflict,omitempty"` -} - -type DMSBindsStatus struct { - Exists bool `json:"exists"` - Included bool `json:"included"` - IncludePosition int `json:"includePosition"` - TotalIncludes int `json:"totalIncludes"` - BindsAfterDMS int `json:"bindsAfterDms"` - Effective bool `json:"effective"` - OverriddenBy int `json:"overriddenBy"` - StatusMessage string `json:"statusMessage"` -} - -type CheatSheet struct { - Title string `json:"title"` - Provider string `json:"provider"` - Binds map[string][]Keybind `json:"binds"` - DMSBindsIncluded bool `json:"dmsBindsIncluded"` - DMSStatus *DMSBindsStatus `json:"dmsStatus,omitempty"` -} - -type Provider interface { - Name() string - GetCheatSheet() (*CheatSheet, error) -} - -type WritableProvider interface { - Provider - SetBind(key, action, description string, options map[string]any) error - RemoveBind(key string) error - GetOverridePath() string -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/filelogger.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/filelogger.go deleted file mode 100644 index e3ff42b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/filelogger.go +++ /dev/null @@ -1,114 +0,0 @@ -package log - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - "regexp" - "sync" - "time" -) - -type FileLogger struct { - file *os.File - writer *bufio.Writer - logPath string - mu sync.Mutex - stopChan chan struct{} - doneChan chan struct{} - passwordRe *regexp.Regexp -} - -func NewFileLogger() (*FileLogger, error) { - timestamp := time.Now().Unix() - - // Use DANKINSTALL_LOG_DIR if set, otherwise fall back to /tmp. - logDir := os.Getenv("DANKINSTALL_LOG_DIR") - if logDir == "" { - logDir = "/tmp" - } - if err := os.MkdirAll(logDir, 0o755); err != nil { - return nil, fmt.Errorf("failed to create log directory: %w", err) - } - logPath := filepath.Join(logDir, fmt.Sprintf("dankinstall-%d.log", timestamp)) - - file, err := os.Create(logPath) - if err != nil { - return nil, fmt.Errorf("failed to create log file: %w", err) - } - - passwordRe := regexp.MustCompile(`(?i)(password[:\s=]+)[^\s]+`) - - logger := &FileLogger{ - file: file, - writer: bufio.NewWriter(file), - logPath: logPath, - stopChan: make(chan struct{}), - doneChan: make(chan struct{}), - passwordRe: passwordRe, - } - - header := fmt.Sprintf("=== DankInstall Log ===\nStarted: %s\n\n", time.Now().Format(time.RFC3339)) - logger.writeToFile(header) - - return logger, nil -} - -func (l *FileLogger) GetLogPath() string { - return l.logPath -} - -func (l *FileLogger) redactPassword(message string) string { - redacted := l.passwordRe.ReplaceAllString(message, "${1}[REDACTED]") - - redacted = regexp.MustCompile(`echo\s+'[^']+'`).ReplaceAllString(redacted, "echo '[REDACTED]'") - - return redacted -} - -func (l *FileLogger) writeToFile(message string) { - l.mu.Lock() - defer l.mu.Unlock() - - redacted := l.redactPassword(message) - timestamp := time.Now().Format("15:04:05.000") - - fmt.Fprintf(l.writer, "[%s] %s\n", timestamp, redacted) - l.writer.Flush() -} - -func (l *FileLogger) StartListening(logChan <-chan string) { - go func() { - defer close(l.doneChan) - for { - select { - case msg, ok := <-logChan: - if !ok { - return - } - l.writeToFile(msg) - case <-l.stopChan: - return - } - } - }() -} - -func (l *FileLogger) Close() error { - close(l.stopChan) - <-l.doneChan - - l.mu.Lock() - defer l.mu.Unlock() - - footer := fmt.Sprintf("\n=== DankInstall Log End ===\nCompleted: %s\n", time.Now().Format(time.RFC3339)) - l.writer.WriteString(footer) //nolint:errcheck - l.writer.Flush() - - if err := l.file.Sync(); err != nil { - return err - } - - return l.file.Close() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/log.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/log.go deleted file mode 100644 index 6b3ede3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/log/log.go +++ /dev/null @@ -1,116 +0,0 @@ -package log - -import ( - "os" - "strings" - "sync" - - "github.com/charmbracelet/lipgloss" - cblog "github.com/charmbracelet/log" -) - -// Logger embeds the Charm Logger and adds Printf/Fatalf -type Logger struct{ *cblog.Logger } - -// Printf routes goose/info-style logs through Infof. -func (l *Logger) Printf(format string, v ...any) { l.Infof(format, v...) } - -// Fatalf keeps goose’s contract of exiting the program. -func (l *Logger) Fatalf(format string, v ...any) { l.Logger.Fatalf(format, v...) } - -var ( - logger *Logger - initLogger sync.Once -) - -func parseLogLevel(level string) cblog.Level { - switch strings.ToLower(level) { - case "debug": - return cblog.DebugLevel - case "info": - return cblog.InfoLevel - case "warn", "warning": - return cblog.WarnLevel - case "error": - return cblog.ErrorLevel - case "fatal": - return cblog.FatalLevel - default: - return cblog.InfoLevel - } -} - -func GetQtLoggingRules() string { - level := os.Getenv("DMS_LOG_LEVEL") - if level == "" { - level = "info" - } - - var rules []string - switch strings.ToLower(level) { - case "fatal": - rules = []string{"*.debug=false", "*.info=false", "*.warning=false", "*.critical=false"} - case "error": - rules = []string{"*.debug=false", "*.info=false", "*.warning=false"} - case "warn", "warning": - rules = []string{"*.debug=false", "*.info=false"} - case "info": - rules = []string{"*.debug=false"} - case "debug": - return "" - default: - rules = []string{"*.debug=false"} - } - - return strings.Join(rules, ";") -} - -// GetLogger returns a logger instance -func GetLogger() *Logger { - initLogger.Do(func() { - styles := cblog.DefaultStyles() - // Attempt to match the colors used by qml/quickshell logs - styles.Levels[cblog.FatalLevel] = lipgloss.NewStyle(). - SetString(" FATAL"). - Foreground(lipgloss.Color("1")) - styles.Levels[cblog.ErrorLevel] = lipgloss.NewStyle(). - SetString(" ERROR"). - Foreground(lipgloss.Color("9")) - styles.Levels[cblog.WarnLevel] = lipgloss.NewStyle(). - SetString(" WARN"). - Foreground(lipgloss.Color("3")) - styles.Levels[cblog.InfoLevel] = lipgloss.NewStyle(). - SetString(" INFO"). - Foreground(lipgloss.Color("2")) - styles.Levels[cblog.DebugLevel] = lipgloss.NewStyle(). - SetString(" DEBUG"). - Foreground(lipgloss.Color("4")) - - base := cblog.New(os.Stderr) - base.SetStyles(styles) - base.SetReportTimestamp(false) - - level := cblog.InfoLevel - if envLevel := os.Getenv("DMS_LOG_LEVEL"); envLevel != "" { - level = parseLogLevel(envLevel) - } - base.SetLevel(level) - base.SetPrefix(" go") - - logger = &Logger{base} - }) - return logger -} - -// * Convenience wrappers - -func Debug(msg any, keyvals ...any) { GetLogger().Debug(msg, keyvals...) } -func Debugf(format string, v ...any) { GetLogger().Debugf(format, v...) } -func Info(msg any, keyvals ...any) { GetLogger().Info(msg, keyvals...) } -func Infof(format string, v ...any) { GetLogger().Infof(format, v...) } -func Warn(msg any, keyvals ...any) { GetLogger().Warn(msg, keyvals...) } -func Warnf(format string, v ...any) { GetLogger().Warnf(format, v...) } -func Error(msg any, keyvals ...any) { GetLogger().Error(msg, keyvals...) } -func Errorf(format string, v ...any) { GetLogger().Errorf(format, v...) } -func Fatal(msg any, keyvals ...any) { GetLogger().Fatal(msg, keyvals...) } -func Fatalf(format string, v ...any) { GetLogger().Fatalf(format, v...) } diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen.go deleted file mode 100644 index a29d324..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen.go +++ /dev/null @@ -1,978 +0,0 @@ -package matugen - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "math" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "sync" - "syscall" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/dank16" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/lucasb-eyer/go-colorful" -) - -var ErrNoChanges = errors.New("no color changes") - -type ColorMode string - -const ( - ColorModeDark ColorMode = "dark" - ColorModeLight ColorMode = "light" -) - -type TemplateKind int - -const ( - TemplateKindNormal TemplateKind = iota - TemplateKindTerminal - TemplateKindGTK - TemplateKindVSCode - TemplateKindEmacs -) - -type TemplateDef struct { - ID string - Commands []string - Flatpaks []string - ConfigFile string - Kind TemplateKind - RunUnconditionally bool -} - -var templateRegistry = []TemplateDef{ - {ID: "gtk", Kind: TemplateKindGTK, RunUnconditionally: true}, - {ID: "niri", Commands: []string{"niri"}, ConfigFile: "niri.toml"}, - {ID: "hyprland", Commands: []string{"Hyprland"}, ConfigFile: "hyprland.toml"}, - {ID: "mangowc", Commands: []string{"mango"}, ConfigFile: "mangowc.toml"}, - {ID: "qt5ct", Commands: []string{"qt5ct"}, ConfigFile: "qt5ct.toml"}, - {ID: "qt6ct", Commands: []string{"qt6ct"}, ConfigFile: "qt6ct.toml"}, - {ID: "firefox", Commands: []string{"firefox"}, ConfigFile: "firefox.toml"}, - {ID: "pywalfox", Commands: []string{"pywalfox"}, ConfigFile: "pywalfox.toml"}, - {ID: "zenbrowser", Commands: []string{"zen", "zen-browser", "zen-beta", "zen-twilight"}, Flatpaks: []string{"app.zen_browser.zen"}, ConfigFile: "zenbrowser.toml"}, - {ID: "vesktop", Commands: []string{"vesktop"}, Flatpaks: []string{"dev.vencord.Vesktop"}, ConfigFile: "vesktop.toml"}, - {ID: "equibop", Commands: []string{"equibop"}, ConfigFile: "equibop.toml"}, - {ID: "ghostty", Commands: []string{"ghostty"}, ConfigFile: "ghostty.toml", Kind: TemplateKindTerminal}, - {ID: "kitty", Commands: []string{"kitty"}, ConfigFile: "kitty.toml", Kind: TemplateKindTerminal}, - {ID: "foot", Commands: []string{"foot"}, ConfigFile: "foot.toml", Kind: TemplateKindTerminal}, - {ID: "alacritty", Commands: []string{"alacritty"}, ConfigFile: "alacritty.toml", Kind: TemplateKindTerminal}, - {ID: "wezterm", Commands: []string{"wezterm"}, ConfigFile: "wezterm.toml", Kind: TemplateKindTerminal}, - {ID: "nvim", Commands: []string{"nvim"}, ConfigFile: "neovim.toml", Kind: TemplateKindTerminal}, - {ID: "dgop", Commands: []string{"dgop"}, ConfigFile: "dgop.toml"}, - {ID: "kcolorscheme", ConfigFile: "kcolorscheme.toml", RunUnconditionally: true}, - {ID: "vscode", Kind: TemplateKindVSCode}, - {ID: "emacs", Commands: []string{"emacs"}, ConfigFile: "emacs.toml", Kind: TemplateKindEmacs}, - {ID: "zed", Commands: []string{"zed", "zeditor", "zedit"}, ConfigFile: "zed.toml"}, -} - -func (c *ColorMode) GTKTheme() string { - switch *c { - case ColorModeDark: - return "adw-gtk3-dark" - default: - return "adw-gtk3" - } -} - -var ( - matugenVersionMu sync.Mutex - matugenVersionOK bool - matugenSupportsCOE bool - matugenIsV4 bool -) - -type Options struct { - StateDir string - ShellDir string - ConfigDir string - Kind string - Value string - Mode ColorMode - IconTheme string - MatugenType string - Contrast float64 - RunUserTemplates bool - ColorsOnly bool - StockColors string - SyncModeWithPortal bool - TerminalsAlwaysDark bool - SkipTemplates string - AppChecker utils.AppChecker -} - -type ColorsOutput struct { - Colors struct { - Dark map[string]string `json:"dark"` - Light map[string]string `json:"light"` - } `json:"colors"` -} - -func (o *Options) ColorsOutput() string { - return filepath.Join(o.StateDir, "dms-colors.json") -} - -func (o *Options) ShouldSkipTemplate(name string) bool { - if o.SkipTemplates == "" { - return false - } - for _, skip := range strings.Split(o.SkipTemplates, ",") { - if strings.TrimSpace(skip) == name { - return true - } - } - return false -} - -func Run(opts Options) error { - if opts.StateDir == "" { - return fmt.Errorf("state-dir is required") - } - if opts.ShellDir == "" { - return fmt.Errorf("shell-dir is required") - } - if opts.ConfigDir == "" { - return fmt.Errorf("config-dir is required") - } - if opts.Kind == "" { - return fmt.Errorf("kind is required") - } - if opts.Value == "" { - return fmt.Errorf("value is required") - } - if opts.Mode == "" { - opts.Mode = ColorModeDark - } - if opts.MatugenType == "" { - opts.MatugenType = "scheme-tonal-spot" - } - if opts.IconTheme == "" { - opts.IconTheme = "System Default" - } - if opts.AppChecker == nil { - opts.AppChecker = utils.DefaultAppChecker{} - } - - if err := os.MkdirAll(opts.StateDir, 0o755); err != nil { - return fmt.Errorf("failed to create state dir: %w", err) - } - - log.Infof("Building theme: %s %s (%s)", opts.Kind, opts.Value, opts.Mode) - - changed, buildErr := buildOnce(&opts) - if buildErr != nil { - return buildErr - } - - if !changed { - log.Info("No color changes detected, skipping refresh") - return ErrNoChanges - } - - if opts.SyncModeWithPortal { - syncColorScheme(opts.Mode) - } - - log.Info("Done") - return nil -} - -func buildOnce(opts *Options) (bool, error) { - cfgFile, err := os.CreateTemp("", "matugen-config-*.toml") - if err != nil { - return false, fmt.Errorf("failed to create temp config: %w", err) - } - defer os.Remove(cfgFile.Name()) - defer cfgFile.Close() - - tmpDir, err := os.MkdirTemp("", "matugen-templates-*") - if err != nil { - return false, fmt.Errorf("failed to create temp dir: %w", err) - } - defer os.RemoveAll(tmpDir) - - if err := buildMergedConfig(opts, cfgFile, tmpDir); err != nil { - return false, fmt.Errorf("failed to build config: %w", err) - } - cfgFile.Close() - - oldColors, _ := os.ReadFile(opts.ColorsOutput()) - - var primaryDark, primaryLight, surface string - var dank16JSON string - var importArgs []string - - if opts.StockColors != "" { - log.Info("Using stock/custom theme colors with matugen base") - primaryDark = extractNestedColor(opts.StockColors, "primary", "dark") - primaryLight = extractNestedColor(opts.StockColors, "primary", "light") - surface = extractNestedColor(opts.StockColors, "surface", "dark") - - if primaryDark == "" { - return false, fmt.Errorf("failed to extract primary dark from stock colors") - } - if primaryLight == "" { - primaryLight = primaryDark - } - - dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode) - importData := fmt.Sprintf(`{"colors": %s, "dank16": %s}`, opts.StockColors, dank16JSON) - importArgs = []string{"--import-json-string", importData} - - log.Info("Running matugen color hex with stock color overrides") - args := []string{"color", "hex", primaryDark, "-m", string(opts.Mode), "-t", opts.MatugenType, "-c", cfgFile.Name()} - args = appendContrastArg(args, opts.Contrast) - args = append(args, importArgs...) - if err := runMatugen(args); err != nil { - return false, err - } - } else { - log.Infof("Using dynamic theme from %s: %s", opts.Kind, opts.Value) - - matJSON, err := runMatugenDryRun(opts) - if err != nil { - return false, fmt.Errorf("matugen dry-run failed: %w", err) - } - - primaryDark = extractMatugenColor(matJSON, "primary", "dark") - primaryLight = extractMatugenColor(matJSON, "primary", "light") - surface = extractMatugenColor(matJSON, "surface", "dark") - - if primaryDark == "" { - return false, fmt.Errorf("failed to extract primary color") - } - if primaryLight == "" { - primaryLight = primaryDark - } - - dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode) - importData := fmt.Sprintf(`{"dank16": %s}`, dank16JSON) - importArgs = []string{"--import-json-string", importData} - - log.Infof("Running matugen %s with dank16 injection", opts.Kind) - var args []string - switch opts.Kind { - case "hex": - args = []string{"color", "hex", opts.Value} - default: - args = []string{opts.Kind, opts.Value} - } - args = append(args, "-m", string(opts.Mode), "-t", opts.MatugenType, "-c", cfgFile.Name()) - args = appendContrastArg(args, opts.Contrast) - args = append(args, importArgs...) - if err := runMatugen(args); err != nil { - return false, err - } - } - - newColors, _ := os.ReadFile(opts.ColorsOutput()) - if bytes.Equal(oldColors, newColors) && len(oldColors) > 0 { - return false, nil - } - - if opts.ColorsOnly { - return true, nil - } - - if isDMSGTKActive(opts.ConfigDir) { - switch opts.Mode { - case ColorModeLight: - syncAccentColor(primaryLight) - default: - syncAccentColor(primaryDark) - } - refreshGTK(opts.Mode) - refreshGTK4() - } - - if !opts.ShouldSkipTemplate("qt6ct") && appExists(opts.AppChecker, []string{"qt6ct"}, nil) { - refreshQt6ct() - } - - signalTerminals(opts) - - return true, nil -} - -func appendContrastArg(args []string, contrast float64) []string { - if contrast == 0 { - return args - } - return append(args, "--contrast", strconv.FormatFloat(contrast, 'f', -1, 64)) -} - -func buildMergedConfig(opts *Options, cfgFile *os.File, tmpDir string) error { - userConfigPath := filepath.Join(opts.ConfigDir, "matugen", "config.toml") - - wroteConfig := false - if opts.RunUserTemplates { - if data, err := os.ReadFile(userConfigPath); err == nil { - configSection := extractTOMLSection(string(data), "[config]", "[templates]") - if configSection != "" { - cfgFile.WriteString(configSection) - cfgFile.WriteString("\n") - wroteConfig = true - } - } - } - if !wroteConfig { - cfgFile.WriteString("[config]\n\n") - } - - baseConfigPath := filepath.Join(opts.ShellDir, "matugen", "configs", "base.toml") - if data, err := os.ReadFile(baseConfigPath); err == nil { - content := string(data) - lines := strings.Split(content, "\n") - for _, line := range lines { - if strings.TrimSpace(line) == "[config]" { - continue - } - cfgFile.WriteString(substituteVars(line, opts.ShellDir) + "\n") - } - cfgFile.WriteString("\n") - } - - fmt.Fprintf(cfgFile, `[templates.dank] -input_path = '%s/matugen/templates/dank.json' -output_path = '%s' - -`, opts.ShellDir, opts.ColorsOutput()) - - if opts.ColorsOnly { - return nil - } - - homeDir, _ := os.UserHomeDir() - for _, tmpl := range templateRegistry { - if opts.ShouldSkipTemplate(tmpl.ID) { - continue - } - - switch tmpl.Kind { - case TemplateKindGTK: - switch opts.Mode { - case ColorModeLight: - appendConfig(opts, cfgFile, nil, nil, "gtk3-light.toml") - default: - appendConfig(opts, cfgFile, nil, nil, "gtk3-dark.toml") - } - case TemplateKindTerminal: - appendTerminalConfig(opts, cfgFile, tmpDir, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) - case TemplateKindVSCode: - appendVSCodeConfig(cfgFile, "vscode", filepath.Join(homeDir, ".vscode/extensions"), opts.ShellDir) - appendVSCodeConfig(cfgFile, "codium", filepath.Join(homeDir, ".vscode-oss/extensions"), opts.ShellDir) - appendVSCodeConfig(cfgFile, "codeoss", filepath.Join(homeDir, ".config/Code - OSS/extensions"), opts.ShellDir) - appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions"), opts.ShellDir) - appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions"), opts.ShellDir) - appendVSCodeConfig(cfgFile, "vscode-insiders", filepath.Join(homeDir, ".vscode-insiders/extensions"), opts.ShellDir) - case TemplateKindEmacs: - if utils.EmacsConfigDir() != "" { - appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) - } - default: - appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) - } - } - - if opts.RunUserTemplates { - if data, err := os.ReadFile(userConfigPath); err == nil { - templatesSection := extractTOMLSection(string(data), "[templates]", "") - if templatesSection != "" { - cfgFile.WriteString(templatesSection) - cfgFile.WriteString("\n") - } - } - } - - userPluginConfigDir := filepath.Join(opts.ConfigDir, "matugen", "dms", "configs") - if entries, err := os.ReadDir(userPluginConfigDir); err == nil { - for _, entry := range entries { - if !strings.HasSuffix(entry.Name(), ".toml") { - continue - } - if data, err := os.ReadFile(filepath.Join(userPluginConfigDir, entry.Name())); err == nil { - cfgFile.WriteString(string(data)) - cfgFile.WriteString("\n") - } - } - } - - return nil -} - -func appendConfig( - opts *Options, - cfgFile *os.File, - checkCmd []string, - checkFlatpaks []string, - fileName string, -) { - configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName) - if _, err := os.Stat(configPath); err != nil { - return - } - if !appExists(opts.AppChecker, checkCmd, checkFlatpaks) { - return - } - data, err := os.ReadFile(configPath) - if err != nil { - return - } - cfgFile.WriteString(substituteVars(string(data), opts.ShellDir)) - cfgFile.WriteString("\n") -} - -func appendTerminalConfig(opts *Options, cfgFile *os.File, tmpDir string, checkCmd []string, checkFlatpaks []string, fileName string) { - configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName) - if _, err := os.Stat(configPath); err != nil { - return - } - if !appExists(opts.AppChecker, checkCmd, checkFlatpaks) { - return - } - data, err := os.ReadFile(configPath) - if err != nil { - return - } - - content := string(data) - - if !opts.TerminalsAlwaysDark { - cfgFile.WriteString(substituteVars(content, opts.ShellDir)) - cfgFile.WriteString("\n") - return - } - - lines := strings.Split(content, "\n") - for _, line := range lines { - if !strings.Contains(line, "input_path") || !strings.Contains(line, "SHELL_DIR/matugen/templates/") { - continue - } - - start := strings.Index(line, "'SHELL_DIR/matugen/templates/") - if start == -1 { - continue - } - end := strings.Index(line[start+1:], "'") - if end == -1 { - continue - } - templateName := line[start+len("'SHELL_DIR/matugen/templates/") : start+1+end] - origPath := filepath.Join(opts.ShellDir, "matugen", "templates", templateName) - - origData, err := os.ReadFile(origPath) - if err != nil { - continue - } - - modified := strings.ReplaceAll(string(origData), ".default.", ".dark.") - tmpPath := filepath.Join(tmpDir, templateName) - if err := os.WriteFile(tmpPath, []byte(modified), 0o644); err != nil { - continue - } - - content = strings.ReplaceAll(content, - fmt.Sprintf("'SHELL_DIR/matugen/templates/%s'", templateName), - fmt.Sprintf("'%s'", tmpPath)) - } - - cfgFile.WriteString(substituteVars(content, opts.ShellDir)) - cfgFile.WriteString("\n") -} - -func appExists(checker utils.AppChecker, checkCmd []string, checkFlatpaks []string) bool { - // Both nil is treated as "skip check" / unconditionally run - if checkCmd == nil && checkFlatpaks == nil { - return true - } - if checkCmd != nil && checker.AnyCommandExists(checkCmd...) { - return true - } - if checkFlatpaks != nil && checker.AnyFlatpakExists(checkFlatpaks...) { - return true - } - return false -} - -func appendVSCodeConfig(cfgFile *os.File, name, extBaseDir, shellDir string) { - pattern := filepath.Join(extBaseDir, "danklinux.dms-theme-*") - matches, err := filepath.Glob(pattern) - if err != nil || len(matches) == 0 { - return - } - - extDir := matches[0] - templateDir := filepath.Join(shellDir, "matugen", "templates") - fmt.Fprintf(cfgFile, `[templates.dms%sdefault] -input_path = '%s/vscode-color-theme-default.json' -output_path = '%s/themes/dankshell-default.json' - -[templates.dms%sdark] -input_path = '%s/vscode-color-theme-dark.json' -output_path = '%s/themes/dankshell-dark.json' - -[templates.dms%slight] -input_path = '%s/vscode-color-theme-light.json' -output_path = '%s/themes/dankshell-light.json' - -`, name, templateDir, extDir, - name, templateDir, extDir, - name, templateDir, extDir) - log.Infof("Added %s theme config (extension found at %s)", name, extDir) -} - -func substituteVars(content, shellDir string) string { - result := strings.ReplaceAll(content, "'SHELL_DIR/", "'"+shellDir+"/") - result = strings.ReplaceAll(result, "'CONFIG_DIR/", "'"+utils.XDGConfigHome()+"/") - result = strings.ReplaceAll(result, "'DATA_DIR/", "'"+utils.XDGDataHome()+"/") - result = strings.ReplaceAll(result, "'CACHE_DIR/", "'"+utils.XDGCacheHome()+"/") - if emacsDir := utils.EmacsConfigDir(); emacsDir != "" { - result = strings.ReplaceAll(result, "'EMACS_DIR/", "'"+emacsDir+"/") - } - return result -} - -func extractTOMLSection(content, startMarker, endMarker string) string { - startIdx := strings.Index(content, startMarker) - if startIdx == -1 { - return "" - } - - if endMarker == "" { - return content[startIdx:] - } - - endIdx := strings.Index(content[startIdx:], endMarker) - if endIdx == -1 { - return content[startIdx:] - } - return content[startIdx : startIdx+endIdx] -} - -type matugenFlags struct { - supportsCOE bool - isV4 bool -} - -func detectMatugenVersion() (matugenFlags, error) { - matugenVersionMu.Lock() - defer matugenVersionMu.Unlock() - - if matugenVersionOK { - return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil - } - - return detectMatugenVersionLocked() -} - -func redetectMatugenVersion(old matugenFlags) (matugenFlags, bool) { - matugenVersionMu.Lock() - defer matugenVersionMu.Unlock() - - matugenVersionOK = false - flags, err := detectMatugenVersionLocked() - if err != nil { - return old, false - } - changed := flags.supportsCOE != old.supportsCOE || flags.isV4 != old.isV4 - return flags, changed -} - -func detectMatugenVersionLocked() (matugenFlags, error) { - cmd := exec.Command("matugen", "--version") - output, err := cmd.Output() - if err != nil { - return matugenFlags{}, fmt.Errorf("failed to get matugen version: %w", err) - } - - versionStr := strings.TrimSpace(string(output)) - versionStr = strings.TrimPrefix(versionStr, "matugen ") - - parts := strings.Split(versionStr, ".") - if len(parts) < 2 { - return matugenFlags{}, fmt.Errorf("unexpected matugen version format: %q", versionStr) - } - - major, err := strconv.Atoi(parts[0]) - if err != nil { - return matugenFlags{}, fmt.Errorf("failed to parse matugen major version %q: %w", parts[0], err) - } - - minor, err := strconv.Atoi(parts[1]) - if err != nil { - return matugenFlags{}, fmt.Errorf("failed to parse matugen minor version %q: %w", parts[1], err) - } - - matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1) - matugenIsV4 = major >= 4 - matugenVersionOK = true - - if matugenSupportsCOE { - log.Debugf("Matugen %s detected: continue-on-error support enabled", versionStr) - } - if matugenIsV4 { - log.Debugf("Matugen %s detected: using v4 compatibility flags", versionStr) - } - return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil -} - -func buildMatugenArgs(baseArgs []string, flags matugenFlags) []string { - args := make([]string, 0, len(baseArgs)+4) - if flags.supportsCOE { - args = append(args, "--continue-on-error") - } - args = append(args, baseArgs...) - if flags.isV4 { - args = append(args, "--source-color-index", "0") - } - return args -} - -func runMatugen(baseArgs []string) error { - flags, err := detectMatugenVersion() - if err != nil { - return err - } - - args := buildMatugenArgs(baseArgs, flags) - cmd := exec.Command("matugen", args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - runErr := cmd.Run() - if runErr == nil { - return nil - } - - log.Warnf("Matugen failed (v4=%v): %v", flags.isV4, runErr) - - newFlags, changed := redetectMatugenVersion(flags) - if !changed { - return runErr - } - - log.Warnf("Matugen version changed (v4: %v -> %v), retrying", flags.isV4, newFlags.isV4) - args = buildMatugenArgs(baseArgs, newFlags) - retryCmd := exec.Command("matugen", args...) - retryCmd.Stdout = os.Stdout - retryCmd.Stderr = os.Stderr - return retryCmd.Run() -} - -func runMatugenDryRun(opts *Options) (string, error) { - flags, err := detectMatugenVersion() - if err != nil { - return "", err - } - - output, dryErr := execDryRun(opts, flags) - if dryErr == nil { - return output, nil - } - - log.Warnf("Matugen dry-run failed (v4=%v): %v", flags.isV4, dryErr) - - newFlags, changed := redetectMatugenVersion(flags) - if !changed { - return "", dryErr - } - - log.Warnf("Matugen version changed (v4: %v -> %v), retrying dry-run", flags.isV4, newFlags.isV4) - return execDryRun(opts, newFlags) -} - -func execDryRun(opts *Options, flags matugenFlags) (string, error) { - var baseArgs []string - switch opts.Kind { - case "hex": - baseArgs = []string{"color", "hex", opts.Value} - default: - baseArgs = []string{opts.Kind, opts.Value} - } - baseArgs = append(baseArgs, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run") - baseArgs = appendContrastArg(baseArgs, opts.Contrast) - if flags.isV4 { - baseArgs = append(baseArgs, "--source-color-index", "0", "--old-json-output") - } - - cmd := exec.Command("matugen", baseArgs...) - var stderr strings.Builder - cmd.Stderr = &stderr - output, err := cmd.Output() - if err != nil { - if stderr.Len() > 0 { - return "", fmt.Errorf("matugen %v failed (v4=%v): %s", baseArgs, flags.isV4, strings.TrimSpace(stderr.String())) - } - return "", fmt.Errorf("matugen %v failed (v4=%v): %w", baseArgs, flags.isV4, err) - } - return strings.ReplaceAll(string(output), "\n", ""), nil -} - -func extractMatugenColor(jsonStr, colorName, variant string) string { - var data map[string]any - if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { - return "" - } - - colors, ok := data["colors"].(map[string]any) - if !ok { - return "" - } - - colorData, ok := colors[colorName].(map[string]any) - if !ok { - return "" - } - - variantData, ok := colorData[variant].(string) - if !ok { - return "" - } - - return variantData -} - -func extractNestedColor(jsonStr, colorName, variant string) string { - var data map[string]any - if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { - return "" - } - - colorData, ok := data[colorName].(map[string]any) - if !ok { - return "" - } - - variantData, ok := colorData[variant].(map[string]any) - if !ok { - return "" - } - - color, ok := variantData["color"].(string) - if !ok { - return "" - } - - return color -} - -func generateDank16Variants(primaryDark, primaryLight, surface string, mode ColorMode) string { - variantOpts := dank16.VariantOptions{ - PrimaryDark: primaryDark, - PrimaryLight: primaryLight, - Background: surface, - UseDPS: true, - IsLightMode: mode == ColorModeLight, - } - variantColors := dank16.GenerateVariantPalette(variantOpts) - return dank16.GenerateVariantJSON(variantColors) -} - -func isDMSGTKActive(configDir string) bool { - gtkCSS := filepath.Join(configDir, "gtk-3.0", "gtk.css") - - info, err := os.Lstat(gtkCSS) - if err != nil { - return false - } - - if info.Mode()&os.ModeSymlink != 0 { - target, err := os.Readlink(gtkCSS) - return err == nil && strings.Contains(target, "dank-colors.css") - } - - data, err := os.ReadFile(gtkCSS) - return err == nil && strings.Contains(string(data), "dank-colors.css") -} - -func refreshGTK(mode ColorMode) { - if err := utils.GsettingsSet("org.gnome.desktop.interface", "gtk-theme", ""); err != nil { - log.Warnf("Failed to reset gtk-theme: %v", err) - } - if err := utils.GsettingsSet("org.gnome.desktop.interface", "gtk-theme", mode.GTKTheme()); err != nil { - log.Warnf("Failed to set gtk-theme: %v", err) - } -} - -func refreshGTK4() { - output, err := utils.GsettingsGet("org.gnome.desktop.interface", "color-scheme") - if err != nil { - return - } - current := strings.Trim(output, "'") - - var toggle string - if current == "prefer-dark" { - toggle = "default" - } else { - toggle = "prefer-dark" - } - - if err := utils.GsettingsSet("org.gnome.desktop.interface", "color-scheme", toggle); err != nil { - log.Warnf("Failed to toggle color-scheme for GTK4 refresh: %v", err) - return - } - time.Sleep(50 * time.Millisecond) - if err := utils.GsettingsSet("org.gnome.desktop.interface", "color-scheme", current); err != nil { - log.Warnf("Failed to restore color-scheme for GTK4 refresh: %v", err) - } -} - -func refreshQt6ct() { - confPath := filepath.Join(utils.XDGConfigHome(), "qt6ct", "qt6ct.conf") - now := time.Now() - if err := os.Chtimes(confPath, now, now); err != nil { - log.Warnf("Failed to touch qt6ct.conf: %v", err) - } -} - -func signalTerminals(opts *Options) { - if !opts.ShouldSkipTemplate("kitty") && appExists(opts.AppChecker, []string{"kitty"}, nil) { - signalByName("kitty", syscall.SIGUSR1) - signalByName(".kitty-wrapped", syscall.SIGUSR1) - } - if !opts.ShouldSkipTemplate("ghostty") && appExists(opts.AppChecker, []string{"ghostty"}, nil) { - signalByName("ghostty", syscall.SIGUSR2) - signalByName(".ghostty-wrappe", syscall.SIGUSR2) - } -} - -func signalByName(name string, sig syscall.Signal) { - entries, err := os.ReadDir("/proc") - if err != nil { - return - } - for _, entry := range entries { - pid, err := strconv.Atoi(entry.Name()) - if err != nil { - continue - } - comm, err := os.ReadFile(filepath.Join("/proc", entry.Name(), "comm")) - if err != nil { - continue - } - if strings.TrimSpace(string(comm)) == name { - syscall.Kill(pid, sig) - } - } -} - -func syncColorScheme(mode ColorMode) { - scheme := "prefer-dark" - if mode == ColorModeLight { - scheme = "default" - } - - if err := utils.GsettingsSet("org.gnome.desktop.interface", "color-scheme", scheme); err != nil { - log.Warnf("Failed to sync color-scheme: %v", err) - } -} - -var adwaitaAccents = []struct { - name string - colors []colorful.Color -}{ - {"blue", hexColors("#3f8ae5", "#438de6", "#a4caee")}, - {"green", hexColors("#26a269", "#39ac76", "#81d5ad")}, - {"orange", hexColors("#f17738", "#ff7800", "#ffc994")}, - {"pink", hexColors("#e4358a", "#e64392", "#f9b3d5")}, - {"purple", hexColors("#954ab5", "#9c46b9", "#d099d6")}, - {"red", hexColors("#e84053", "#e01b24", "#f2a1a5")}, - {"slate", hexColors("#557b9f", "#6a8daf", "#b4c6d6")}, - {"teal", hexColors("#129eb0", "#2190a4", "#7bdff4")}, - {"yellow", hexColors("#cbac10", "#d4b411", "#f5c211")}, -} - -func hexColors(hexes ...string) []colorful.Color { - out := make([]colorful.Color, len(hexes)) - for i, h := range hexes { - out[i], _ = colorful.Hex(h) - } - return out -} - -func closestAdwaitaAccent(primaryHex string) string { - c, err := colorful.Hex(primaryHex) - if err != nil { - return "blue" - } - - best := "blue" - bestDist := math.MaxFloat64 - for _, a := range adwaitaAccents { - for _, ref := range a.colors { - d := c.DistanceCIEDE2000(ref) - if d < bestDist { - bestDist = d - best = a.name - } - } - } - return best -} - -func syncAccentColor(primaryHex string) { - accent := closestAdwaitaAccent(primaryHex) - log.Infof("Setting GNOME accent color: %s", accent) - if err := utils.GsettingsSet("org.gnome.desktop.interface", "accent-color", accent); err != nil { - log.Warnf("Failed to set accent-color: %v", err) - } -} - -type TemplateCheck struct { - ID string `json:"id"` - Detected bool `json:"detected"` -} - -func CheckTemplates(checker utils.AppChecker) []TemplateCheck { - if checker == nil { - checker = utils.DefaultAppChecker{} - } - - homeDir, _ := os.UserHomeDir() - checks := make([]TemplateCheck, 0, len(templateRegistry)) - - for _, tmpl := range templateRegistry { - detected := false - - switch { - case tmpl.RunUnconditionally: - detected = true - case tmpl.Kind == TemplateKindVSCode: - detected = checkVSCodeExtension(homeDir) - case tmpl.Kind == TemplateKindEmacs: - detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) && utils.EmacsConfigDir() != "" - default: - detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) - } - - checks = append(checks, TemplateCheck{ID: tmpl.ID, Detected: detected}) - } - - return checks -} - -func checkVSCodeExtension(homeDir string) bool { - extDirs := []string{ - filepath.Join(homeDir, ".vscode/extensions"), - filepath.Join(homeDir, ".vscode-oss/extensions"), - filepath.Join(homeDir, ".config/Code - OSS/extensions"), - filepath.Join(homeDir, ".cursor/extensions"), - filepath.Join(homeDir, ".windsurf/extensions"), - } - - for _, extDir := range extDirs { - pattern := filepath.Join(extDir, "danklinux.dms-theme-*") - if matches, err := filepath.Glob(pattern); err == nil && len(matches) > 0 { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen_test.go deleted file mode 100644 index 48880df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/matugen_test.go +++ /dev/null @@ -1,443 +0,0 @@ -package matugen - -import ( - "os" - "path/filepath" - "strings" - "testing" - - mocks_utils "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/utils" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/stretchr/testify/assert" -) - -func TestAppendConfigBinaryExists(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "test config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyCommandExists("sh").Return(true) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, []string{"sh"}, nil, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) == 0 { - t.Errorf("expected config to be written when binary exists") - } - if string(output) != testConfig+"\n" { - t.Errorf("expected %q, got %q", testConfig+"\n", string(output)) - } -} - -func TestAppendConfigBinaryDoesNotExist(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "test config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyCommandExists("nonexistent-binary-12345").Return(false) - mockChecker.EXPECT().AnyFlatpakExists().Return(false) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{}, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) != 0 { - t.Errorf("expected no config when binary doesn't exist, got: %q", string(output)) - } -} - -func TestAppendConfigFlatpakExists(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "zen config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyFlatpakExists("app.zen_browser.zen").Return(true) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, nil, []string{"app.zen_browser.zen"}, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) == 0 { - t.Errorf("expected config to be written when flatpak exists") - } -} - -func TestAppendConfigFlatpakDoesNotExist(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "test config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyCommandExists().Return(false) - mockChecker.EXPECT().AnyFlatpakExists("com.nonexistent.flatpak").Return(false) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, []string{}, []string{"com.nonexistent.flatpak"}, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) != 0 { - t.Errorf("expected no config when flatpak doesn't exist, got: %q", string(output)) - } -} - -func TestAppendConfigBothExist(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "zen config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyCommandExists("sh").Return(true) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, []string{"sh"}, []string{"app.zen_browser.zen"}, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) == 0 { - t.Errorf("expected config to be written when both binary and flatpak exist") - } -} - -func TestAppendConfigNeitherExists(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "test config content" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - mockChecker := mocks_utils.NewMockAppChecker(t) - mockChecker.EXPECT().AnyCommandExists("nonexistent-binary-12345").Return(false) - mockChecker.EXPECT().AnyFlatpakExists("com.nonexistent.flatpak").Return(false) - - opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - - appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{"com.nonexistent.flatpak"}, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) != 0 { - t.Errorf("expected no config when neither exists, got: %q", string(output)) - } -} - -func TestAppendConfigNoChecks(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - testConfig := "always include" - configPath := filepath.Join(configsDir, "test.toml") - if err := os.WriteFile(configPath, []byte(testConfig), 0o644); err != nil { - t.Fatalf("failed to write config: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - opts := &Options{ShellDir: shellDir} - - appendConfig(opts, cfgFile, nil, nil, "test.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) == 0 { - t.Errorf("expected config to be written when no checks specified") - } -} - -func TestAppendConfigFileDoesNotExist(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - outFile := filepath.Join(tempDir, "output.toml") - cfgFile, err := os.Create(outFile) - if err != nil { - t.Fatalf("failed to create output file: %v", err) - } - defer cfgFile.Close() - - opts := &Options{ShellDir: shellDir} - - appendConfig(opts, cfgFile, nil, nil, "nonexistent.toml") - - cfgFile.Close() - output, err := os.ReadFile(outFile) - if err != nil { - t.Fatalf("failed to read output: %v", err) - } - - if len(output) != 0 { - t.Errorf("expected no config when file doesn't exist, got: %q", string(output)) - } -} - -func TestSubstituteVars(t *testing.T) { - configDir := utils.XDGConfigHome() - dataDir := utils.XDGDataHome() - cacheDir := utils.XDGCacheHome() - - tests := []struct { - name string - input string - shellDir string - expected string - }{ - { - name: "substitutes SHELL_DIR", - input: "input_path = 'SHELL_DIR/matugen/templates/foo.conf'", - shellDir: "/home/user/shell", - expected: "input_path = '/home/user/shell/matugen/templates/foo.conf'", - }, - { - name: "substitutes CONFIG_DIR", - input: "output_path = 'CONFIG_DIR/kitty/theme.conf'", - shellDir: "/home/user/shell", - expected: "output_path = '" + configDir + "/kitty/theme.conf'", - }, - { - name: "substitutes DATA_DIR", - input: "output_path = 'DATA_DIR/color-schemes/theme.colors'", - shellDir: "/home/user/shell", - expected: "output_path = '" + dataDir + "/color-schemes/theme.colors'", - }, - { - name: "substitutes CACHE_DIR", - input: "output_path = 'CACHE_DIR/wal/colors.json'", - shellDir: "/home/user/shell", - expected: "output_path = '" + cacheDir + "/wal/colors.json'", - }, - { - name: "substitutes all dir types", - input: "'SHELL_DIR/a' 'CONFIG_DIR/b' 'DATA_DIR/c' 'CACHE_DIR/d'", - shellDir: "/shell", - expected: "'/shell/a' '" + configDir + "/b' '" + dataDir + "/c' '" + cacheDir + "/d'", - }, - { - name: "no substitution when no placeholders", - input: "input_path = '/absolute/path/foo.conf'", - shellDir: "/home/user/shell", - expected: "input_path = '/absolute/path/foo.conf'", - }, - { - name: "multiple SHELL_DIR occurrences", - input: "'SHELL_DIR/a' and 'SHELL_DIR/b'", - shellDir: "/shell", - expected: "'/shell/a' and '/shell/b'", - }, - { - name: "only substitutes quoted paths", - input: "SHELL_DIR/unquoted and 'SHELL_DIR/quoted'", - shellDir: "/shell", - expected: "SHELL_DIR/unquoted and '/shell/quoted'", - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - result := substituteVars(tc.input, tc.shellDir) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestBuildMergedConfigColorsOnly(t *testing.T) { - tempDir := t.TempDir() - - shellDir := filepath.Join(tempDir, "shell") - configsDir := filepath.Join(shellDir, "matugen", "configs") - if err := os.MkdirAll(configsDir, 0o755); err != nil { - t.Fatalf("failed to create configs dir: %v", err) - } - - baseConfig := "[config]\ncustom_keywords = []\n" - if err := os.WriteFile(filepath.Join(configsDir, "base.toml"), []byte(baseConfig), 0o644); err != nil { - t.Fatalf("failed to write base config: %v", err) - } - - cfgFile, err := os.CreateTemp(tempDir, "merged-*.toml") - if err != nil { - t.Fatalf("failed to create temp config: %v", err) - } - defer os.Remove(cfgFile.Name()) - defer cfgFile.Close() - - opts := &Options{ - ShellDir: shellDir, - ConfigDir: filepath.Join(tempDir, "config"), - StateDir: filepath.Join(tempDir, "state"), - ColorsOnly: true, - } - - if err := buildMergedConfig(opts, cfgFile, filepath.Join(tempDir, "templates")); err != nil { - t.Fatalf("buildMergedConfig failed: %v", err) - } - - if err := cfgFile.Close(); err != nil { - t.Fatalf("failed to close merged config: %v", err) - } - - output, err := os.ReadFile(cfgFile.Name()) - if err != nil { - t.Fatalf("failed to read merged config: %v", err) - } - - content := string(output) - assert.Contains(t, content, "[templates.dank]") - assert.Contains(t, content, "output_path = '"+filepath.Join(opts.StateDir, "dms-colors.json")+"'") - assert.NotContains(t, content, "[templates.gtk]") - assert.False(t, strings.Contains(content, "output_path = 'CONFIG_DIR/"), "colors-only config should not emit app template outputs") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/queue.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/queue.go deleted file mode 100644 index 38cf72a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/matugen/queue.go +++ /dev/null @@ -1,143 +0,0 @@ -package matugen - -import ( - "context" - "errors" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -type Result struct { - Success bool - Error error -} - -type QueuedJob struct { - Options Options - Done chan Result - Ctx context.Context - Cancel context.CancelFunc -} - -type Queue struct { - mu sync.Mutex - current *QueuedJob - pending *QueuedJob - jobDone chan struct{} -} - -var globalQueue *Queue -var queueOnce sync.Once - -func GetQueue() *Queue { - queueOnce.Do(func() { - globalQueue = &Queue{ - jobDone: make(chan struct{}, 1), - } - }) - return globalQueue -} - -func (q *Queue) Submit(opts Options) <-chan Result { - result := make(chan Result, 1) - ctx, cancel := context.WithCancel(context.Background()) - - job := &QueuedJob{ - Options: opts, - Done: result, - Ctx: ctx, - Cancel: cancel, - } - - q.mu.Lock() - - if q.pending != nil { - log.Info("Cancelling pending theme request") - q.pending.Cancel() - q.pending.Done <- Result{Success: false, Error: context.Canceled} - close(q.pending.Done) - } - - if q.current != nil { - q.pending = job - q.mu.Unlock() - log.Info("Theme request queued (worker running)") - return result - } - - q.current = job - q.mu.Unlock() - - go q.runWorker() - return result -} - -func (q *Queue) runWorker() { - for { - q.mu.Lock() - job := q.current - if job == nil { - q.mu.Unlock() - return - } - q.mu.Unlock() - - select { - case <-job.Ctx.Done(): - q.finishJob(Result{Success: false, Error: context.Canceled}) - continue - default: - } - - log.Infof("Processing theme: %s %s (%s)", job.Options.Kind, job.Options.Value, job.Options.Mode) - err := Run(job.Options) - - var result Result - switch { - case err == nil: - result = Result{Success: true} - case errors.Is(err, ErrNoChanges): - result = Result{Success: true} - default: - result = Result{Success: false, Error: err} - } - - q.finishJob(result) - } -} - -func (q *Queue) finishJob(result Result) { - q.mu.Lock() - defer q.mu.Unlock() - - if q.current != nil { - select { - case q.current.Done <- result: - default: - } - close(q.current.Done) - } - - q.current = q.pending - q.pending = nil - - if q.current == nil { - select { - case q.jobDone <- struct{}{}: - default: - } - } -} - -func (q *Queue) IsRunning() bool { - q.mu.Lock() - defer q.mu.Unlock() - return q.current != nil -} - -func (q *Queue) HasPending() bool { - q.mu.Lock() - defer q.mu.Unlock() - return q.pending != nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/brightness/mock_DBusConn.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/brightness/mock_DBusConn.go deleted file mode 100644 index ce9472d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/brightness/mock_DBusConn.go +++ /dev/null @@ -1,130 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_brightness - -import ( - dbus "github.com/godbus/dbus/v5" - mock "github.com/stretchr/testify/mock" -) - -// MockDBusConn is an autogenerated mock type for the DBusConn type -type MockDBusConn struct { - mock.Mock -} - -type MockDBusConn_Expecter struct { - mock *mock.Mock -} - -func (_m *MockDBusConn) EXPECT() *MockDBusConn_Expecter { - return &MockDBusConn_Expecter{mock: &_m.Mock} -} - -// Close provides a mock function with no fields -func (_m *MockDBusConn) Close() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDBusConn_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockDBusConn_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockDBusConn_Expecter) Close() *MockDBusConn_Close_Call { - return &MockDBusConn_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockDBusConn_Close_Call) Run(run func()) *MockDBusConn_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDBusConn_Close_Call) Return(_a0 error) *MockDBusConn_Close_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDBusConn_Close_Call) RunAndReturn(run func() error) *MockDBusConn_Close_Call { - _c.Call.Return(run) - return _c -} - -// Object provides a mock function with given fields: dest, path -func (_m *MockDBusConn) Object(dest string, path dbus.ObjectPath) dbus.BusObject { - ret := _m.Called(dest, path) - - if len(ret) == 0 { - panic("no return value specified for Object") - } - - var r0 dbus.BusObject - if rf, ok := ret.Get(0).(func(string, dbus.ObjectPath) dbus.BusObject); ok { - r0 = rf(dest, path) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(dbus.BusObject) - } - } - - return r0 -} - -// MockDBusConn_Object_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Object' -type MockDBusConn_Object_Call struct { - *mock.Call -} - -// Object is a helper method to define mock.On call -// - dest string -// - path dbus.ObjectPath -func (_e *MockDBusConn_Expecter) Object(dest any, path any) *MockDBusConn_Object_Call { - return &MockDBusConn_Object_Call{Call: _e.mock.On("Object", dest, path)} -} - -func (_c *MockDBusConn_Object_Call) Run(run func(dest string, path dbus.ObjectPath)) *MockDBusConn_Object_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(dbus.ObjectPath)) - }) - return _c -} - -func (_c *MockDBusConn_Object_Call) Return(_a0 dbus.BusObject) *MockDBusConn_Object_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDBusConn_Object_Call) RunAndReturn(run func(string, dbus.ObjectPath) dbus.BusObject) *MockDBusConn_Object_Call { - _c.Call.Return(run) - return _c -} - -// NewMockDBusConn creates a new instance of MockDBusConn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockDBusConn(t interface { - mock.TestingT - Cleanup(func()) -}, -) *MockDBusConn { - mock := &MockDBusConn{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups/mock_CUPSClientInterface.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups/mock_CUPSClientInterface.go deleted file mode 100644 index 3c98074..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups/mock_CUPSClientInterface.go +++ /dev/null @@ -1,1246 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_cups - -import ( - io "io" - - ipp "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - mock "github.com/stretchr/testify/mock" -) - -// MockCUPSClientInterface is an autogenerated mock type for the CUPSClientInterface type -type MockCUPSClientInterface struct { - mock.Mock -} - -type MockCUPSClientInterface_Expecter struct { - mock *mock.Mock -} - -func (_m *MockCUPSClientInterface) EXPECT() *MockCUPSClientInterface_Expecter { - return &MockCUPSClientInterface_Expecter{mock: &_m.Mock} -} - -// AcceptJobs provides a mock function with given fields: printer -func (_m *MockCUPSClientInterface) AcceptJobs(printer string) error { - ret := _m.Called(printer) - - if len(ret) == 0 { - panic("no return value specified for AcceptJobs") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_AcceptJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptJobs' -type MockCUPSClientInterface_AcceptJobs_Call struct { - *mock.Call -} - -// AcceptJobs is a helper method to define mock.On call -// - printer string -func (_e *MockCUPSClientInterface_Expecter) AcceptJobs(printer interface{}) *MockCUPSClientInterface_AcceptJobs_Call { - return &MockCUPSClientInterface_AcceptJobs_Call{Call: _e.mock.On("AcceptJobs", printer)} -} - -func (_c *MockCUPSClientInterface_AcceptJobs_Call) Run(run func(printer string)) *MockCUPSClientInterface_AcceptJobs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_AcceptJobs_Call) Return(_a0 error) *MockCUPSClientInterface_AcceptJobs_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_AcceptJobs_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_AcceptJobs_Call { - _c.Call.Return(run) - return _c -} - -// AddPrinterToClass provides a mock function with given fields: class, printer -func (_m *MockCUPSClientInterface) AddPrinterToClass(class string, printer string) error { - ret := _m.Called(class, printer) - - if len(ret) == 0 { - panic("no return value specified for AddPrinterToClass") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(class, printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_AddPrinterToClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddPrinterToClass' -type MockCUPSClientInterface_AddPrinterToClass_Call struct { - *mock.Call -} - -// AddPrinterToClass is a helper method to define mock.On call -// - class string -// - printer string -func (_e *MockCUPSClientInterface_Expecter) AddPrinterToClass(class interface{}, printer interface{}) *MockCUPSClientInterface_AddPrinterToClass_Call { - return &MockCUPSClientInterface_AddPrinterToClass_Call{Call: _e.mock.On("AddPrinterToClass", class, printer)} -} - -func (_c *MockCUPSClientInterface_AddPrinterToClass_Call) Run(run func(class string, printer string)) *MockCUPSClientInterface_AddPrinterToClass_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_AddPrinterToClass_Call) Return(_a0 error) *MockCUPSClientInterface_AddPrinterToClass_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_AddPrinterToClass_Call) RunAndReturn(run func(string, string) error) *MockCUPSClientInterface_AddPrinterToClass_Call { - _c.Call.Return(run) - return _c -} - -// CancelAllJob provides a mock function with given fields: printer, purge -func (_m *MockCUPSClientInterface) CancelAllJob(printer string, purge bool) error { - ret := _m.Called(printer, purge) - - if len(ret) == 0 { - panic("no return value specified for CancelAllJob") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(printer, purge) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_CancelAllJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelAllJob' -type MockCUPSClientInterface_CancelAllJob_Call struct { - *mock.Call -} - -// CancelAllJob is a helper method to define mock.On call -// - printer string -// - purge bool -func (_e *MockCUPSClientInterface_Expecter) CancelAllJob(printer interface{}, purge interface{}) *MockCUPSClientInterface_CancelAllJob_Call { - return &MockCUPSClientInterface_CancelAllJob_Call{Call: _e.mock.On("CancelAllJob", printer, purge)} -} - -func (_c *MockCUPSClientInterface_CancelAllJob_Call) Run(run func(printer string, purge bool)) *MockCUPSClientInterface_CancelAllJob_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_CancelAllJob_Call) Return(_a0 error) *MockCUPSClientInterface_CancelAllJob_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_CancelAllJob_Call) RunAndReturn(run func(string, bool) error) *MockCUPSClientInterface_CancelAllJob_Call { - _c.Call.Return(run) - return _c -} - -// CancelJob provides a mock function with given fields: jobID, purge -func (_m *MockCUPSClientInterface) CancelJob(jobID int, purge bool) error { - ret := _m.Called(jobID, purge) - - if len(ret) == 0 { - panic("no return value specified for CancelJob") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int, bool) error); ok { - r0 = rf(jobID, purge) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_CancelJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelJob' -type MockCUPSClientInterface_CancelJob_Call struct { - *mock.Call -} - -// CancelJob is a helper method to define mock.On call -// - jobID int -// - purge bool -func (_e *MockCUPSClientInterface_Expecter) CancelJob(jobID interface{}, purge interface{}) *MockCUPSClientInterface_CancelJob_Call { - return &MockCUPSClientInterface_CancelJob_Call{Call: _e.mock.On("CancelJob", jobID, purge)} -} - -func (_c *MockCUPSClientInterface_CancelJob_Call) Run(run func(jobID int, purge bool)) *MockCUPSClientInterface_CancelJob_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(bool)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_CancelJob_Call) Return(_a0 error) *MockCUPSClientInterface_CancelJob_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_CancelJob_Call) RunAndReturn(run func(int, bool) error) *MockCUPSClientInterface_CancelJob_Call { - _c.Call.Return(run) - return _c -} - -// CreatePrinter provides a mock function with given fields: name, deviceURI, ppd, shared, errorPolicy, information, location -func (_m *MockCUPSClientInterface) CreatePrinter(name string, deviceURI string, ppd string, shared bool, errorPolicy string, information string, location string) error { - ret := _m.Called(name, deviceURI, ppd, shared, errorPolicy, information, location) - - if len(ret) == 0 { - panic("no return value specified for CreatePrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, string, bool, string, string, string) error); ok { - r0 = rf(name, deviceURI, ppd, shared, errorPolicy, information, location) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_CreatePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreatePrinter' -type MockCUPSClientInterface_CreatePrinter_Call struct { - *mock.Call -} - -// CreatePrinter is a helper method to define mock.On call -// - name string -// - deviceURI string -// - ppd string -// - shared bool -// - errorPolicy string -// - information string -// - location string -func (_e *MockCUPSClientInterface_Expecter) CreatePrinter(name interface{}, deviceURI interface{}, ppd interface{}, shared interface{}, errorPolicy interface{}, information interface{}, location interface{}) *MockCUPSClientInterface_CreatePrinter_Call { - return &MockCUPSClientInterface_CreatePrinter_Call{Call: _e.mock.On("CreatePrinter", name, deviceURI, ppd, shared, errorPolicy, information, location)} -} - -func (_c *MockCUPSClientInterface_CreatePrinter_Call) Run(run func(name string, deviceURI string, ppd string, shared bool, errorPolicy string, information string, location string)) *MockCUPSClientInterface_CreatePrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(string), args[3].(bool), args[4].(string), args[5].(string), args[6].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_CreatePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_CreatePrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_CreatePrinter_Call) RunAndReturn(run func(string, string, string, bool, string, string, string) error) *MockCUPSClientInterface_CreatePrinter_Call { - _c.Call.Return(run) - return _c -} - -// DeleteClass provides a mock function with given fields: class -func (_m *MockCUPSClientInterface) DeleteClass(class string) error { - ret := _m.Called(class) - - if len(ret) == 0 { - panic("no return value specified for DeleteClass") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(class) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_DeleteClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteClass' -type MockCUPSClientInterface_DeleteClass_Call struct { - *mock.Call -} - -// DeleteClass is a helper method to define mock.On call -// - class string -func (_e *MockCUPSClientInterface_Expecter) DeleteClass(class interface{}) *MockCUPSClientInterface_DeleteClass_Call { - return &MockCUPSClientInterface_DeleteClass_Call{Call: _e.mock.On("DeleteClass", class)} -} - -func (_c *MockCUPSClientInterface_DeleteClass_Call) Run(run func(class string)) *MockCUPSClientInterface_DeleteClass_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_DeleteClass_Call) Return(_a0 error) *MockCUPSClientInterface_DeleteClass_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_DeleteClass_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_DeleteClass_Call { - _c.Call.Return(run) - return _c -} - -// DeletePrinter provides a mock function with given fields: printer -func (_m *MockCUPSClientInterface) DeletePrinter(printer string) error { - ret := _m.Called(printer) - - if len(ret) == 0 { - panic("no return value specified for DeletePrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_DeletePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeletePrinter' -type MockCUPSClientInterface_DeletePrinter_Call struct { - *mock.Call -} - -// DeletePrinter is a helper method to define mock.On call -// - printer string -func (_e *MockCUPSClientInterface_Expecter) DeletePrinter(printer interface{}) *MockCUPSClientInterface_DeletePrinter_Call { - return &MockCUPSClientInterface_DeletePrinter_Call{Call: _e.mock.On("DeletePrinter", printer)} -} - -func (_c *MockCUPSClientInterface_DeletePrinter_Call) Run(run func(printer string)) *MockCUPSClientInterface_DeletePrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_DeletePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_DeletePrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_DeletePrinter_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_DeletePrinter_Call { - _c.Call.Return(run) - return _c -} - -// DeletePrinterFromClass provides a mock function with given fields: class, printer -func (_m *MockCUPSClientInterface) DeletePrinterFromClass(class string, printer string) error { - ret := _m.Called(class, printer) - - if len(ret) == 0 { - panic("no return value specified for DeletePrinterFromClass") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(class, printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_DeletePrinterFromClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeletePrinterFromClass' -type MockCUPSClientInterface_DeletePrinterFromClass_Call struct { - *mock.Call -} - -// DeletePrinterFromClass is a helper method to define mock.On call -// - class string -// - printer string -func (_e *MockCUPSClientInterface_Expecter) DeletePrinterFromClass(class interface{}, printer interface{}) *MockCUPSClientInterface_DeletePrinterFromClass_Call { - return &MockCUPSClientInterface_DeletePrinterFromClass_Call{Call: _e.mock.On("DeletePrinterFromClass", class, printer)} -} - -func (_c *MockCUPSClientInterface_DeletePrinterFromClass_Call) Run(run func(class string, printer string)) *MockCUPSClientInterface_DeletePrinterFromClass_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_DeletePrinterFromClass_Call) Return(_a0 error) *MockCUPSClientInterface_DeletePrinterFromClass_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_DeletePrinterFromClass_Call) RunAndReturn(run func(string, string) error) *MockCUPSClientInterface_DeletePrinterFromClass_Call { - _c.Call.Return(run) - return _c -} - -// GetClasses provides a mock function with given fields: attributes -func (_m *MockCUPSClientInterface) GetClasses(attributes []string) (map[string]ipp.Attributes, error) { - ret := _m.Called(attributes) - - if len(ret) == 0 { - panic("no return value specified for GetClasses") - } - - var r0 map[string]ipp.Attributes - var r1 error - if rf, ok := ret.Get(0).(func([]string) (map[string]ipp.Attributes, error)); ok { - return rf(attributes) - } - if rf, ok := ret.Get(0).(func([]string) map[string]ipp.Attributes); ok { - r0 = rf(attributes) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]ipp.Attributes) - } - } - - if rf, ok := ret.Get(1).(func([]string) error); ok { - r1 = rf(attributes) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_GetClasses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClasses' -type MockCUPSClientInterface_GetClasses_Call struct { - *mock.Call -} - -// GetClasses is a helper method to define mock.On call -// - attributes []string -func (_e *MockCUPSClientInterface_Expecter) GetClasses(attributes interface{}) *MockCUPSClientInterface_GetClasses_Call { - return &MockCUPSClientInterface_GetClasses_Call{Call: _e.mock.On("GetClasses", attributes)} -} - -func (_c *MockCUPSClientInterface_GetClasses_Call) Run(run func(attributes []string)) *MockCUPSClientInterface_GetClasses_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_GetClasses_Call) Return(_a0 map[string]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetClasses_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_GetClasses_Call) RunAndReturn(run func([]string) (map[string]ipp.Attributes, error)) *MockCUPSClientInterface_GetClasses_Call { - _c.Call.Return(run) - return _c -} - -// GetDevices provides a mock function with no fields -func (_m *MockCUPSClientInterface) GetDevices() (map[string]ipp.Attributes, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetDevices") - } - - var r0 map[string]ipp.Attributes - var r1 error - if rf, ok := ret.Get(0).(func() (map[string]ipp.Attributes, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() map[string]ipp.Attributes); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]ipp.Attributes) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_GetDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDevices' -type MockCUPSClientInterface_GetDevices_Call struct { - *mock.Call -} - -// GetDevices is a helper method to define mock.On call -func (_e *MockCUPSClientInterface_Expecter) GetDevices() *MockCUPSClientInterface_GetDevices_Call { - return &MockCUPSClientInterface_GetDevices_Call{Call: _e.mock.On("GetDevices")} -} - -func (_c *MockCUPSClientInterface_GetDevices_Call) Run(run func()) *MockCUPSClientInterface_GetDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockCUPSClientInterface_GetDevices_Call) Return(_a0 map[string]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_GetDevices_Call) RunAndReturn(run func() (map[string]ipp.Attributes, error)) *MockCUPSClientInterface_GetDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetJobs provides a mock function with given fields: printer, class, whichJobs, myJobs, firstJobId, limit, attributes -func (_m *MockCUPSClientInterface) GetJobs(printer string, class string, whichJobs string, myJobs bool, firstJobId int, limit int, attributes []string) (map[int]ipp.Attributes, error) { - ret := _m.Called(printer, class, whichJobs, myJobs, firstJobId, limit, attributes) - - if len(ret) == 0 { - panic("no return value specified for GetJobs") - } - - var r0 map[int]ipp.Attributes - var r1 error - if rf, ok := ret.Get(0).(func(string, string, string, bool, int, int, []string) (map[int]ipp.Attributes, error)); ok { - return rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes) - } - if rf, ok := ret.Get(0).(func(string, string, string, bool, int, int, []string) map[int]ipp.Attributes); ok { - r0 = rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[int]ipp.Attributes) - } - } - - if rf, ok := ret.Get(1).(func(string, string, string, bool, int, int, []string) error); ok { - r1 = rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_GetJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobs' -type MockCUPSClientInterface_GetJobs_Call struct { - *mock.Call -} - -// GetJobs is a helper method to define mock.On call -// - printer string -// - class string -// - whichJobs string -// - myJobs bool -// - firstJobId int -// - limit int -// - attributes []string -func (_e *MockCUPSClientInterface_Expecter) GetJobs(printer interface{}, class interface{}, whichJobs interface{}, myJobs interface{}, firstJobId interface{}, limit interface{}, attributes interface{}) *MockCUPSClientInterface_GetJobs_Call { - return &MockCUPSClientInterface_GetJobs_Call{Call: _e.mock.On("GetJobs", printer, class, whichJobs, myJobs, firstJobId, limit, attributes)} -} - -func (_c *MockCUPSClientInterface_GetJobs_Call) Run(run func(printer string, class string, whichJobs string, myJobs bool, firstJobId int, limit int, attributes []string)) *MockCUPSClientInterface_GetJobs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(string), args[3].(bool), args[4].(int), args[5].(int), args[6].([]string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_GetJobs_Call) Return(_a0 map[int]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetJobs_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_GetJobs_Call) RunAndReturn(run func(string, string, string, bool, int, int, []string) (map[int]ipp.Attributes, error)) *MockCUPSClientInterface_GetJobs_Call { - _c.Call.Return(run) - return _c -} - -// GetPPDs provides a mock function with no fields -func (_m *MockCUPSClientInterface) GetPPDs() (map[string]ipp.Attributes, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPPDs") - } - - var r0 map[string]ipp.Attributes - var r1 error - if rf, ok := ret.Get(0).(func() (map[string]ipp.Attributes, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() map[string]ipp.Attributes); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]ipp.Attributes) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_GetPPDs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPPDs' -type MockCUPSClientInterface_GetPPDs_Call struct { - *mock.Call -} - -// GetPPDs is a helper method to define mock.On call -func (_e *MockCUPSClientInterface_Expecter) GetPPDs() *MockCUPSClientInterface_GetPPDs_Call { - return &MockCUPSClientInterface_GetPPDs_Call{Call: _e.mock.On("GetPPDs")} -} - -func (_c *MockCUPSClientInterface_GetPPDs_Call) Run(run func()) *MockCUPSClientInterface_GetPPDs_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockCUPSClientInterface_GetPPDs_Call) Return(_a0 map[string]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetPPDs_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_GetPPDs_Call) RunAndReturn(run func() (map[string]ipp.Attributes, error)) *MockCUPSClientInterface_GetPPDs_Call { - _c.Call.Return(run) - return _c -} - -// GetPrinters provides a mock function with given fields: attributes -func (_m *MockCUPSClientInterface) GetPrinters(attributes []string) (map[string]ipp.Attributes, error) { - ret := _m.Called(attributes) - - if len(ret) == 0 { - panic("no return value specified for GetPrinters") - } - - var r0 map[string]ipp.Attributes - var r1 error - if rf, ok := ret.Get(0).(func([]string) (map[string]ipp.Attributes, error)); ok { - return rf(attributes) - } - if rf, ok := ret.Get(0).(func([]string) map[string]ipp.Attributes); ok { - r0 = rf(attributes) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]ipp.Attributes) - } - } - - if rf, ok := ret.Get(1).(func([]string) error); ok { - r1 = rf(attributes) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_GetPrinters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPrinters' -type MockCUPSClientInterface_GetPrinters_Call struct { - *mock.Call -} - -// GetPrinters is a helper method to define mock.On call -// - attributes []string -func (_e *MockCUPSClientInterface_Expecter) GetPrinters(attributes interface{}) *MockCUPSClientInterface_GetPrinters_Call { - return &MockCUPSClientInterface_GetPrinters_Call{Call: _e.mock.On("GetPrinters", attributes)} -} - -func (_c *MockCUPSClientInterface_GetPrinters_Call) Run(run func(attributes []string)) *MockCUPSClientInterface_GetPrinters_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_GetPrinters_Call) Return(_a0 map[string]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetPrinters_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_GetPrinters_Call) RunAndReturn(run func([]string) (map[string]ipp.Attributes, error)) *MockCUPSClientInterface_GetPrinters_Call { - _c.Call.Return(run) - return _c -} - -// HoldJobUntil provides a mock function with given fields: jobID, holdUntil -func (_m *MockCUPSClientInterface) HoldJobUntil(jobID int, holdUntil string) error { - ret := _m.Called(jobID, holdUntil) - - if len(ret) == 0 { - panic("no return value specified for HoldJobUntil") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int, string) error); ok { - r0 = rf(jobID, holdUntil) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_HoldJobUntil_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HoldJobUntil' -type MockCUPSClientInterface_HoldJobUntil_Call struct { - *mock.Call -} - -// HoldJobUntil is a helper method to define mock.On call -// - jobID int -// - holdUntil string -func (_e *MockCUPSClientInterface_Expecter) HoldJobUntil(jobID interface{}, holdUntil interface{}) *MockCUPSClientInterface_HoldJobUntil_Call { - return &MockCUPSClientInterface_HoldJobUntil_Call{Call: _e.mock.On("HoldJobUntil", jobID, holdUntil)} -} - -func (_c *MockCUPSClientInterface_HoldJobUntil_Call) Run(run func(jobID int, holdUntil string)) *MockCUPSClientInterface_HoldJobUntil_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_HoldJobUntil_Call) Return(_a0 error) *MockCUPSClientInterface_HoldJobUntil_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_HoldJobUntil_Call) RunAndReturn(run func(int, string) error) *MockCUPSClientInterface_HoldJobUntil_Call { - _c.Call.Return(run) - return _c -} - -// MoveJob provides a mock function with given fields: jobID, destPrinter -func (_m *MockCUPSClientInterface) MoveJob(jobID int, destPrinter string) error { - ret := _m.Called(jobID, destPrinter) - - if len(ret) == 0 { - panic("no return value specified for MoveJob") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int, string) error); ok { - r0 = rf(jobID, destPrinter) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_MoveJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MoveJob' -type MockCUPSClientInterface_MoveJob_Call struct { - *mock.Call -} - -// MoveJob is a helper method to define mock.On call -// - jobID int -// - destPrinter string -func (_e *MockCUPSClientInterface_Expecter) MoveJob(jobID interface{}, destPrinter interface{}) *MockCUPSClientInterface_MoveJob_Call { - return &MockCUPSClientInterface_MoveJob_Call{Call: _e.mock.On("MoveJob", jobID, destPrinter)} -} - -func (_c *MockCUPSClientInterface_MoveJob_Call) Run(run func(jobID int, destPrinter string)) *MockCUPSClientInterface_MoveJob_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_MoveJob_Call) Return(_a0 error) *MockCUPSClientInterface_MoveJob_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_MoveJob_Call) RunAndReturn(run func(int, string) error) *MockCUPSClientInterface_MoveJob_Call { - _c.Call.Return(run) - return _c -} - -// PausePrinter provides a mock function with given fields: printer -func (_m *MockCUPSClientInterface) PausePrinter(printer string) error { - ret := _m.Called(printer) - - if len(ret) == 0 { - panic("no return value specified for PausePrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_PausePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PausePrinter' -type MockCUPSClientInterface_PausePrinter_Call struct { - *mock.Call -} - -// PausePrinter is a helper method to define mock.On call -// - printer string -func (_e *MockCUPSClientInterface_Expecter) PausePrinter(printer interface{}) *MockCUPSClientInterface_PausePrinter_Call { - return &MockCUPSClientInterface_PausePrinter_Call{Call: _e.mock.On("PausePrinter", printer)} -} - -func (_c *MockCUPSClientInterface_PausePrinter_Call) Run(run func(printer string)) *MockCUPSClientInterface_PausePrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_PausePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_PausePrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_PausePrinter_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_PausePrinter_Call { - _c.Call.Return(run) - return _c -} - -// PrintTestPage provides a mock function with given fields: printer, testPageData, size -func (_m *MockCUPSClientInterface) PrintTestPage(printer string, testPageData io.Reader, size int) (int, error) { - ret := _m.Called(printer, testPageData, size) - - if len(ret) == 0 { - panic("no return value specified for PrintTestPage") - } - - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func(string, io.Reader, int) (int, error)); ok { - return rf(printer, testPageData, size) - } - if rf, ok := ret.Get(0).(func(string, io.Reader, int) int); ok { - r0 = rf(printer, testPageData, size) - } else { - r0 = ret.Get(0).(int) - } - - if rf, ok := ret.Get(1).(func(string, io.Reader, int) error); ok { - r1 = rf(printer, testPageData, size) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_PrintTestPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrintTestPage' -type MockCUPSClientInterface_PrintTestPage_Call struct { - *mock.Call -} - -// PrintTestPage is a helper method to define mock.On call -// - printer string -// - testPageData io.Reader -// - size int -func (_e *MockCUPSClientInterface_Expecter) PrintTestPage(printer interface{}, testPageData interface{}, size interface{}) *MockCUPSClientInterface_PrintTestPage_Call { - return &MockCUPSClientInterface_PrintTestPage_Call{Call: _e.mock.On("PrintTestPage", printer, testPageData, size)} -} - -func (_c *MockCUPSClientInterface_PrintTestPage_Call) Run(run func(printer string, testPageData io.Reader, size int)) *MockCUPSClientInterface_PrintTestPage_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(io.Reader), args[2].(int)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_PrintTestPage_Call) Return(_a0 int, _a1 error) *MockCUPSClientInterface_PrintTestPage_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_PrintTestPage_Call) RunAndReturn(run func(string, io.Reader, int) (int, error)) *MockCUPSClientInterface_PrintTestPage_Call { - _c.Call.Return(run) - return _c -} - -// RejectJobs provides a mock function with given fields: printer -func (_m *MockCUPSClientInterface) RejectJobs(printer string) error { - ret := _m.Called(printer) - - if len(ret) == 0 { - panic("no return value specified for RejectJobs") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_RejectJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RejectJobs' -type MockCUPSClientInterface_RejectJobs_Call struct { - *mock.Call -} - -// RejectJobs is a helper method to define mock.On call -// - printer string -func (_e *MockCUPSClientInterface_Expecter) RejectJobs(printer interface{}) *MockCUPSClientInterface_RejectJobs_Call { - return &MockCUPSClientInterface_RejectJobs_Call{Call: _e.mock.On("RejectJobs", printer)} -} - -func (_c *MockCUPSClientInterface_RejectJobs_Call) Run(run func(printer string)) *MockCUPSClientInterface_RejectJobs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_RejectJobs_Call) Return(_a0 error) *MockCUPSClientInterface_RejectJobs_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_RejectJobs_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_RejectJobs_Call { - _c.Call.Return(run) - return _c -} - -// RestartJob provides a mock function with given fields: jobID -func (_m *MockCUPSClientInterface) RestartJob(jobID int) error { - ret := _m.Called(jobID) - - if len(ret) == 0 { - panic("no return value specified for RestartJob") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int) error); ok { - r0 = rf(jobID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_RestartJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestartJob' -type MockCUPSClientInterface_RestartJob_Call struct { - *mock.Call -} - -// RestartJob is a helper method to define mock.On call -// - jobID int -func (_e *MockCUPSClientInterface_Expecter) RestartJob(jobID interface{}) *MockCUPSClientInterface_RestartJob_Call { - return &MockCUPSClientInterface_RestartJob_Call{Call: _e.mock.On("RestartJob", jobID)} -} - -func (_c *MockCUPSClientInterface_RestartJob_Call) Run(run func(jobID int)) *MockCUPSClientInterface_RestartJob_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_RestartJob_Call) Return(_a0 error) *MockCUPSClientInterface_RestartJob_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_RestartJob_Call) RunAndReturn(run func(int) error) *MockCUPSClientInterface_RestartJob_Call { - _c.Call.Return(run) - return _c -} - -// ResumePrinter provides a mock function with given fields: printer -func (_m *MockCUPSClientInterface) ResumePrinter(printer string) error { - ret := _m.Called(printer) - - if len(ret) == 0 { - panic("no return value specified for ResumePrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(printer) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_ResumePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResumePrinter' -type MockCUPSClientInterface_ResumePrinter_Call struct { - *mock.Call -} - -// ResumePrinter is a helper method to define mock.On call -// - printer string -func (_e *MockCUPSClientInterface_Expecter) ResumePrinter(printer interface{}) *MockCUPSClientInterface_ResumePrinter_Call { - return &MockCUPSClientInterface_ResumePrinter_Call{Call: _e.mock.On("ResumePrinter", printer)} -} - -func (_c *MockCUPSClientInterface_ResumePrinter_Call) Run(run func(printer string)) *MockCUPSClientInterface_ResumePrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_ResumePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_ResumePrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_ResumePrinter_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_ResumePrinter_Call { - _c.Call.Return(run) - return _c -} - -// SendRequest provides a mock function with given fields: url, req, additionalResponseData -func (_m *MockCUPSClientInterface) SendRequest(url string, req *ipp.Request, additionalResponseData io.Writer) (*ipp.Response, error) { - ret := _m.Called(url, req, additionalResponseData) - - if len(ret) == 0 { - panic("no return value specified for SendRequest") - } - - var r0 *ipp.Response - var r1 error - if rf, ok := ret.Get(0).(func(string, *ipp.Request, io.Writer) (*ipp.Response, error)); ok { - return rf(url, req, additionalResponseData) - } - if rf, ok := ret.Get(0).(func(string, *ipp.Request, io.Writer) *ipp.Response); ok { - r0 = rf(url, req, additionalResponseData) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*ipp.Response) - } - } - - if rf, ok := ret.Get(1).(func(string, *ipp.Request, io.Writer) error); ok { - r1 = rf(url, req, additionalResponseData) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockCUPSClientInterface_SendRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendRequest' -type MockCUPSClientInterface_SendRequest_Call struct { - *mock.Call -} - -// SendRequest is a helper method to define mock.On call -// - url string -// - req *ipp.Request -// - additionalResponseData io.Writer -func (_e *MockCUPSClientInterface_Expecter) SendRequest(url interface{}, req interface{}, additionalResponseData interface{}) *MockCUPSClientInterface_SendRequest_Call { - return &MockCUPSClientInterface_SendRequest_Call{Call: _e.mock.On("SendRequest", url, req, additionalResponseData)} -} - -func (_c *MockCUPSClientInterface_SendRequest_Call) Run(run func(url string, req *ipp.Request, additionalResponseData io.Writer)) *MockCUPSClientInterface_SendRequest_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(*ipp.Request), args[2].(io.Writer)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_SendRequest_Call) Return(_a0 *ipp.Response, _a1 error) *MockCUPSClientInterface_SendRequest_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockCUPSClientInterface_SendRequest_Call) RunAndReturn(run func(string, *ipp.Request, io.Writer) (*ipp.Response, error)) *MockCUPSClientInterface_SendRequest_Call { - _c.Call.Return(run) - return _c -} - -// SetPrinterInformation provides a mock function with given fields: printer, information -func (_m *MockCUPSClientInterface) SetPrinterInformation(printer string, information string) error { - ret := _m.Called(printer, information) - - if len(ret) == 0 { - panic("no return value specified for SetPrinterInformation") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(printer, information) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_SetPrinterInformation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPrinterInformation' -type MockCUPSClientInterface_SetPrinterInformation_Call struct { - *mock.Call -} - -// SetPrinterInformation is a helper method to define mock.On call -// - printer string -// - information string -func (_e *MockCUPSClientInterface_Expecter) SetPrinterInformation(printer interface{}, information interface{}) *MockCUPSClientInterface_SetPrinterInformation_Call { - return &MockCUPSClientInterface_SetPrinterInformation_Call{Call: _e.mock.On("SetPrinterInformation", printer, information)} -} - -func (_c *MockCUPSClientInterface_SetPrinterInformation_Call) Run(run func(printer string, information string)) *MockCUPSClientInterface_SetPrinterInformation_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterInformation_Call) Return(_a0 error) *MockCUPSClientInterface_SetPrinterInformation_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterInformation_Call) RunAndReturn(run func(string, string) error) *MockCUPSClientInterface_SetPrinterInformation_Call { - _c.Call.Return(run) - return _c -} - -// SetPrinterIsShared provides a mock function with given fields: printer, shared -func (_m *MockCUPSClientInterface) SetPrinterIsShared(printer string, shared bool) error { - ret := _m.Called(printer, shared) - - if len(ret) == 0 { - panic("no return value specified for SetPrinterIsShared") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(printer, shared) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_SetPrinterIsShared_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPrinterIsShared' -type MockCUPSClientInterface_SetPrinterIsShared_Call struct { - *mock.Call -} - -// SetPrinterIsShared is a helper method to define mock.On call -// - printer string -// - shared bool -func (_e *MockCUPSClientInterface_Expecter) SetPrinterIsShared(printer interface{}, shared interface{}) *MockCUPSClientInterface_SetPrinterIsShared_Call { - return &MockCUPSClientInterface_SetPrinterIsShared_Call{Call: _e.mock.On("SetPrinterIsShared", printer, shared)} -} - -func (_c *MockCUPSClientInterface_SetPrinterIsShared_Call) Run(run func(printer string, shared bool)) *MockCUPSClientInterface_SetPrinterIsShared_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterIsShared_Call) Return(_a0 error) *MockCUPSClientInterface_SetPrinterIsShared_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterIsShared_Call) RunAndReturn(run func(string, bool) error) *MockCUPSClientInterface_SetPrinterIsShared_Call { - _c.Call.Return(run) - return _c -} - -// SetPrinterLocation provides a mock function with given fields: printer, location -func (_m *MockCUPSClientInterface) SetPrinterLocation(printer string, location string) error { - ret := _m.Called(printer, location) - - if len(ret) == 0 { - panic("no return value specified for SetPrinterLocation") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(printer, location) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockCUPSClientInterface_SetPrinterLocation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPrinterLocation' -type MockCUPSClientInterface_SetPrinterLocation_Call struct { - *mock.Call -} - -// SetPrinterLocation is a helper method to define mock.On call -// - printer string -// - location string -func (_e *MockCUPSClientInterface_Expecter) SetPrinterLocation(printer interface{}, location interface{}) *MockCUPSClientInterface_SetPrinterLocation_Call { - return &MockCUPSClientInterface_SetPrinterLocation_Call{Call: _e.mock.On("SetPrinterLocation", printer, location)} -} - -func (_c *MockCUPSClientInterface_SetPrinterLocation_Call) Run(run func(printer string, location string)) *MockCUPSClientInterface_SetPrinterLocation_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterLocation_Call) Return(_a0 error) *MockCUPSClientInterface_SetPrinterLocation_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockCUPSClientInterface_SetPrinterLocation_Call) RunAndReturn(run func(string, string) error) *MockCUPSClientInterface_SetPrinterLocation_Call { - _c.Call.Return(run) - return _c -} - -// NewMockCUPSClientInterface creates a new instance of MockCUPSClientInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockCUPSClientInterface(t interface { - mock.TestingT - Cleanup(func()) -}) *MockCUPSClientInterface { - mock := &MockCUPSClientInterface{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups_pkhelper/mock_PkHelper.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups_pkhelper/mock_PkHelper.go deleted file mode 100644 index cad5bfc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/cups_pkhelper/mock_PkHelper.go +++ /dev/null @@ -1,708 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_cups_pkhelper - -import ( - cups "github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups" - mock "github.com/stretchr/testify/mock" -) - -// MockPkHelper is an autogenerated mock type for the PkHelper type -type MockPkHelper struct { - mock.Mock -} - -type MockPkHelper_Expecter struct { - mock *mock.Mock -} - -func (_m *MockPkHelper) EXPECT() *MockPkHelper_Expecter { - return &MockPkHelper_Expecter{mock: &_m.Mock} -} - -// ClassAddPrinter provides a mock function with given fields: className, printerName -func (_m *MockPkHelper) ClassAddPrinter(className string, printerName string) error { - ret := _m.Called(className, printerName) - - if len(ret) == 0 { - panic("no return value specified for ClassAddPrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(className, printerName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_ClassAddPrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClassAddPrinter' -type MockPkHelper_ClassAddPrinter_Call struct { - *mock.Call -} - -// ClassAddPrinter is a helper method to define mock.On call -// - className string -// - printerName string -func (_e *MockPkHelper_Expecter) ClassAddPrinter(className interface{}, printerName interface{}) *MockPkHelper_ClassAddPrinter_Call { - return &MockPkHelper_ClassAddPrinter_Call{Call: _e.mock.On("ClassAddPrinter", className, printerName)} -} - -func (_c *MockPkHelper_ClassAddPrinter_Call) Run(run func(className string, printerName string)) *MockPkHelper_ClassAddPrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockPkHelper_ClassAddPrinter_Call) Return(_a0 error) *MockPkHelper_ClassAddPrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_ClassAddPrinter_Call) RunAndReturn(run func(string, string) error) *MockPkHelper_ClassAddPrinter_Call { - _c.Call.Return(run) - return _c -} - -// ClassDelete provides a mock function with given fields: className -func (_m *MockPkHelper) ClassDelete(className string) error { - ret := _m.Called(className) - - if len(ret) == 0 { - panic("no return value specified for ClassDelete") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(className) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_ClassDelete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClassDelete' -type MockPkHelper_ClassDelete_Call struct { - *mock.Call -} - -// ClassDelete is a helper method to define mock.On call -// - className string -func (_e *MockPkHelper_Expecter) ClassDelete(className interface{}) *MockPkHelper_ClassDelete_Call { - return &MockPkHelper_ClassDelete_Call{Call: _e.mock.On("ClassDelete", className)} -} - -func (_c *MockPkHelper_ClassDelete_Call) Run(run func(className string)) *MockPkHelper_ClassDelete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockPkHelper_ClassDelete_Call) Return(_a0 error) *MockPkHelper_ClassDelete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_ClassDelete_Call) RunAndReturn(run func(string) error) *MockPkHelper_ClassDelete_Call { - _c.Call.Return(run) - return _c -} - -// ClassDeletePrinter provides a mock function with given fields: className, printerName -func (_m *MockPkHelper) ClassDeletePrinter(className string, printerName string) error { - ret := _m.Called(className, printerName) - - if len(ret) == 0 { - panic("no return value specified for ClassDeletePrinter") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(className, printerName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_ClassDeletePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClassDeletePrinter' -type MockPkHelper_ClassDeletePrinter_Call struct { - *mock.Call -} - -// ClassDeletePrinter is a helper method to define mock.On call -// - className string -// - printerName string -func (_e *MockPkHelper_Expecter) ClassDeletePrinter(className interface{}, printerName interface{}) *MockPkHelper_ClassDeletePrinter_Call { - return &MockPkHelper_ClassDeletePrinter_Call{Call: _e.mock.On("ClassDeletePrinter", className, printerName)} -} - -func (_c *MockPkHelper_ClassDeletePrinter_Call) Run(run func(className string, printerName string)) *MockPkHelper_ClassDeletePrinter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockPkHelper_ClassDeletePrinter_Call) Return(_a0 error) *MockPkHelper_ClassDeletePrinter_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_ClassDeletePrinter_Call) RunAndReturn(run func(string, string) error) *MockPkHelper_ClassDeletePrinter_Call { - _c.Call.Return(run) - return _c -} - -// DevicesGet provides a mock function with given fields: timeout, limit, includeSchemes, excludeSchemes -func (_m *MockPkHelper) DevicesGet(timeout int, limit int, includeSchemes []string, excludeSchemes []string) ([]cups.Device, error) { - ret := _m.Called(timeout, limit, includeSchemes, excludeSchemes) - - if len(ret) == 0 { - panic("no return value specified for DevicesGet") - } - - var r0 []cups.Device - var r1 error - if rf, ok := ret.Get(0).(func(int, int, []string, []string) ([]cups.Device, error)); ok { - return rf(timeout, limit, includeSchemes, excludeSchemes) - } - if rf, ok := ret.Get(0).(func(int, int, []string, []string) []cups.Device); ok { - r0 = rf(timeout, limit, includeSchemes, excludeSchemes) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]cups.Device) - } - } - - if rf, ok := ret.Get(1).(func(int, int, []string, []string) error); ok { - r1 = rf(timeout, limit, includeSchemes, excludeSchemes) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockPkHelper_DevicesGet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DevicesGet' -type MockPkHelper_DevicesGet_Call struct { - *mock.Call -} - -// DevicesGet is a helper method to define mock.On call -// - timeout int -// - limit int -// - includeSchemes []string -// - excludeSchemes []string -func (_e *MockPkHelper_Expecter) DevicesGet(timeout interface{}, limit interface{}, includeSchemes interface{}, excludeSchemes interface{}) *MockPkHelper_DevicesGet_Call { - return &MockPkHelper_DevicesGet_Call{Call: _e.mock.On("DevicesGet", timeout, limit, includeSchemes, excludeSchemes)} -} - -func (_c *MockPkHelper_DevicesGet_Call) Run(run func(timeout int, limit int, includeSchemes []string, excludeSchemes []string)) *MockPkHelper_DevicesGet_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(int), args[2].([]string), args[3].([]string)) - }) - return _c -} - -func (_c *MockPkHelper_DevicesGet_Call) Return(_a0 []cups.Device, _a1 error) *MockPkHelper_DevicesGet_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockPkHelper_DevicesGet_Call) RunAndReturn(run func(int, int, []string, []string) ([]cups.Device, error)) *MockPkHelper_DevicesGet_Call { - _c.Call.Return(run) - return _c -} - -// JobCancelPurge provides a mock function with given fields: jobID, purge -func (_m *MockPkHelper) JobCancelPurge(jobID int, purge bool) error { - ret := _m.Called(jobID, purge) - - if len(ret) == 0 { - panic("no return value specified for JobCancelPurge") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int, bool) error); ok { - r0 = rf(jobID, purge) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_JobCancelPurge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'JobCancelPurge' -type MockPkHelper_JobCancelPurge_Call struct { - *mock.Call -} - -// JobCancelPurge is a helper method to define mock.On call -// - jobID int -// - purge bool -func (_e *MockPkHelper_Expecter) JobCancelPurge(jobID interface{}, purge interface{}) *MockPkHelper_JobCancelPurge_Call { - return &MockPkHelper_JobCancelPurge_Call{Call: _e.mock.On("JobCancelPurge", jobID, purge)} -} - -func (_c *MockPkHelper_JobCancelPurge_Call) Run(run func(jobID int, purge bool)) *MockPkHelper_JobCancelPurge_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(bool)) - }) - return _c -} - -func (_c *MockPkHelper_JobCancelPurge_Call) Return(_a0 error) *MockPkHelper_JobCancelPurge_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_JobCancelPurge_Call) RunAndReturn(run func(int, bool) error) *MockPkHelper_JobCancelPurge_Call { - _c.Call.Return(run) - return _c -} - -// JobRestart provides a mock function with given fields: jobID -func (_m *MockPkHelper) JobRestart(jobID int) error { - ret := _m.Called(jobID) - - if len(ret) == 0 { - panic("no return value specified for JobRestart") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int) error); ok { - r0 = rf(jobID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_JobRestart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'JobRestart' -type MockPkHelper_JobRestart_Call struct { - *mock.Call -} - -// JobRestart is a helper method to define mock.On call -// - jobID int -func (_e *MockPkHelper_Expecter) JobRestart(jobID interface{}) *MockPkHelper_JobRestart_Call { - return &MockPkHelper_JobRestart_Call{Call: _e.mock.On("JobRestart", jobID)} -} - -func (_c *MockPkHelper_JobRestart_Call) Run(run func(jobID int)) *MockPkHelper_JobRestart_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int)) - }) - return _c -} - -func (_c *MockPkHelper_JobRestart_Call) Return(_a0 error) *MockPkHelper_JobRestart_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_JobRestart_Call) RunAndReturn(run func(int) error) *MockPkHelper_JobRestart_Call { - _c.Call.Return(run) - return _c -} - -// JobSetHoldUntil provides a mock function with given fields: jobID, holdUntil -func (_m *MockPkHelper) JobSetHoldUntil(jobID int, holdUntil string) error { - ret := _m.Called(jobID, holdUntil) - - if len(ret) == 0 { - panic("no return value specified for JobSetHoldUntil") - } - - var r0 error - if rf, ok := ret.Get(0).(func(int, string) error); ok { - r0 = rf(jobID, holdUntil) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_JobSetHoldUntil_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'JobSetHoldUntil' -type MockPkHelper_JobSetHoldUntil_Call struct { - *mock.Call -} - -// JobSetHoldUntil is a helper method to define mock.On call -// - jobID int -// - holdUntil string -func (_e *MockPkHelper_Expecter) JobSetHoldUntil(jobID interface{}, holdUntil interface{}) *MockPkHelper_JobSetHoldUntil_Call { - return &MockPkHelper_JobSetHoldUntil_Call{Call: _e.mock.On("JobSetHoldUntil", jobID, holdUntil)} -} - -func (_c *MockPkHelper_JobSetHoldUntil_Call) Run(run func(jobID int, holdUntil string)) *MockPkHelper_JobSetHoldUntil_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(string)) - }) - return _c -} - -func (_c *MockPkHelper_JobSetHoldUntil_Call) Return(_a0 error) *MockPkHelper_JobSetHoldUntil_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_JobSetHoldUntil_Call) RunAndReturn(run func(int, string) error) *MockPkHelper_JobSetHoldUntil_Call { - _c.Call.Return(run) - return _c -} - -// PrinterAdd provides a mock function with given fields: name, uri, ppd, info, location -func (_m *MockPkHelper) PrinterAdd(name string, uri string, ppd string, info string, location string) error { - ret := _m.Called(name, uri, ppd, info, location) - - if len(ret) == 0 { - panic("no return value specified for PrinterAdd") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, string, string, string) error); ok { - r0 = rf(name, uri, ppd, info, location) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterAdd_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterAdd' -type MockPkHelper_PrinterAdd_Call struct { - *mock.Call -} - -// PrinterAdd is a helper method to define mock.On call -// - name string -// - uri string -// - ppd string -// - info string -// - location string -func (_e *MockPkHelper_Expecter) PrinterAdd(name interface{}, uri interface{}, ppd interface{}, info interface{}, location interface{}) *MockPkHelper_PrinterAdd_Call { - return &MockPkHelper_PrinterAdd_Call{Call: _e.mock.On("PrinterAdd", name, uri, ppd, info, location)} -} - -func (_c *MockPkHelper_PrinterAdd_Call) Run(run func(name string, uri string, ppd string, info string, location string)) *MockPkHelper_PrinterAdd_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(string), args[3].(string), args[4].(string)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterAdd_Call) Return(_a0 error) *MockPkHelper_PrinterAdd_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterAdd_Call) RunAndReturn(run func(string, string, string, string, string) error) *MockPkHelper_PrinterAdd_Call { - _c.Call.Return(run) - return _c -} - -// PrinterDelete provides a mock function with given fields: name -func (_m *MockPkHelper) PrinterDelete(name string) error { - ret := _m.Called(name) - - if len(ret) == 0 { - panic("no return value specified for PrinterDelete") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(name) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterDelete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterDelete' -type MockPkHelper_PrinterDelete_Call struct { - *mock.Call -} - -// PrinterDelete is a helper method to define mock.On call -// - name string -func (_e *MockPkHelper_Expecter) PrinterDelete(name interface{}) *MockPkHelper_PrinterDelete_Call { - return &MockPkHelper_PrinterDelete_Call{Call: _e.mock.On("PrinterDelete", name)} -} - -func (_c *MockPkHelper_PrinterDelete_Call) Run(run func(name string)) *MockPkHelper_PrinterDelete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterDelete_Call) Return(_a0 error) *MockPkHelper_PrinterDelete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterDelete_Call) RunAndReturn(run func(string) error) *MockPkHelper_PrinterDelete_Call { - _c.Call.Return(run) - return _c -} - -// PrinterSetAcceptJobs provides a mock function with given fields: name, enabled, reason -func (_m *MockPkHelper) PrinterSetAcceptJobs(name string, enabled bool, reason string) error { - ret := _m.Called(name, enabled, reason) - - if len(ret) == 0 { - panic("no return value specified for PrinterSetAcceptJobs") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool, string) error); ok { - r0 = rf(name, enabled, reason) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterSetAcceptJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterSetAcceptJobs' -type MockPkHelper_PrinterSetAcceptJobs_Call struct { - *mock.Call -} - -// PrinterSetAcceptJobs is a helper method to define mock.On call -// - name string -// - enabled bool -// - reason string -func (_e *MockPkHelper_Expecter) PrinterSetAcceptJobs(name interface{}, enabled interface{}, reason interface{}) *MockPkHelper_PrinterSetAcceptJobs_Call { - return &MockPkHelper_PrinterSetAcceptJobs_Call{Call: _e.mock.On("PrinterSetAcceptJobs", name, enabled, reason)} -} - -func (_c *MockPkHelper_PrinterSetAcceptJobs_Call) Run(run func(name string, enabled bool, reason string)) *MockPkHelper_PrinterSetAcceptJobs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool), args[2].(string)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterSetAcceptJobs_Call) Return(_a0 error) *MockPkHelper_PrinterSetAcceptJobs_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterSetAcceptJobs_Call) RunAndReturn(run func(string, bool, string) error) *MockPkHelper_PrinterSetAcceptJobs_Call { - _c.Call.Return(run) - return _c -} - -// PrinterSetEnabled provides a mock function with given fields: name, enabled -func (_m *MockPkHelper) PrinterSetEnabled(name string, enabled bool) error { - ret := _m.Called(name, enabled) - - if len(ret) == 0 { - panic("no return value specified for PrinterSetEnabled") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(name, enabled) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterSetEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterSetEnabled' -type MockPkHelper_PrinterSetEnabled_Call struct { - *mock.Call -} - -// PrinterSetEnabled is a helper method to define mock.On call -// - name string -// - enabled bool -func (_e *MockPkHelper_Expecter) PrinterSetEnabled(name interface{}, enabled interface{}) *MockPkHelper_PrinterSetEnabled_Call { - return &MockPkHelper_PrinterSetEnabled_Call{Call: _e.mock.On("PrinterSetEnabled", name, enabled)} -} - -func (_c *MockPkHelper_PrinterSetEnabled_Call) Run(run func(name string, enabled bool)) *MockPkHelper_PrinterSetEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterSetEnabled_Call) Return(_a0 error) *MockPkHelper_PrinterSetEnabled_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterSetEnabled_Call) RunAndReturn(run func(string, bool) error) *MockPkHelper_PrinterSetEnabled_Call { - _c.Call.Return(run) - return _c -} - -// PrinterSetInfo provides a mock function with given fields: name, info -func (_m *MockPkHelper) PrinterSetInfo(name string, info string) error { - ret := _m.Called(name, info) - - if len(ret) == 0 { - panic("no return value specified for PrinterSetInfo") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(name, info) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterSetInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterSetInfo' -type MockPkHelper_PrinterSetInfo_Call struct { - *mock.Call -} - -// PrinterSetInfo is a helper method to define mock.On call -// - name string -// - info string -func (_e *MockPkHelper_Expecter) PrinterSetInfo(name interface{}, info interface{}) *MockPkHelper_PrinterSetInfo_Call { - return &MockPkHelper_PrinterSetInfo_Call{Call: _e.mock.On("PrinterSetInfo", name, info)} -} - -func (_c *MockPkHelper_PrinterSetInfo_Call) Run(run func(name string, info string)) *MockPkHelper_PrinterSetInfo_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterSetInfo_Call) Return(_a0 error) *MockPkHelper_PrinterSetInfo_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterSetInfo_Call) RunAndReturn(run func(string, string) error) *MockPkHelper_PrinterSetInfo_Call { - _c.Call.Return(run) - return _c -} - -// PrinterSetLocation provides a mock function with given fields: name, location -func (_m *MockPkHelper) PrinterSetLocation(name string, location string) error { - ret := _m.Called(name, location) - - if len(ret) == 0 { - panic("no return value specified for PrinterSetLocation") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(name, location) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterSetLocation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterSetLocation' -type MockPkHelper_PrinterSetLocation_Call struct { - *mock.Call -} - -// PrinterSetLocation is a helper method to define mock.On call -// - name string -// - location string -func (_e *MockPkHelper_Expecter) PrinterSetLocation(name interface{}, location interface{}) *MockPkHelper_PrinterSetLocation_Call { - return &MockPkHelper_PrinterSetLocation_Call{Call: _e.mock.On("PrinterSetLocation", name, location)} -} - -func (_c *MockPkHelper_PrinterSetLocation_Call) Run(run func(name string, location string)) *MockPkHelper_PrinterSetLocation_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterSetLocation_Call) Return(_a0 error) *MockPkHelper_PrinterSetLocation_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterSetLocation_Call) RunAndReturn(run func(string, string) error) *MockPkHelper_PrinterSetLocation_Call { - _c.Call.Return(run) - return _c -} - -// PrinterSetShared provides a mock function with given fields: name, shared -func (_m *MockPkHelper) PrinterSetShared(name string, shared bool) error { - ret := _m.Called(name, shared) - - if len(ret) == 0 { - panic("no return value specified for PrinterSetShared") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(name, shared) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockPkHelper_PrinterSetShared_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PrinterSetShared' -type MockPkHelper_PrinterSetShared_Call struct { - *mock.Call -} - -// PrinterSetShared is a helper method to define mock.On call -// - name string -// - shared bool -func (_e *MockPkHelper_Expecter) PrinterSetShared(name interface{}, shared interface{}) *MockPkHelper_PrinterSetShared_Call { - return &MockPkHelper_PrinterSetShared_Call{Call: _e.mock.On("PrinterSetShared", name, shared)} -} - -func (_c *MockPkHelper_PrinterSetShared_Call) Run(run func(name string, shared bool)) *MockPkHelper_PrinterSetShared_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockPkHelper_PrinterSetShared_Call) Return(_a0 error) *MockPkHelper_PrinterSetShared_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockPkHelper_PrinterSetShared_Call) RunAndReturn(run func(string, bool) error) *MockPkHelper_PrinterSetShared_Call { - _c.Call.Return(run) - return _c -} - -// NewMockPkHelper creates a new instance of MockPkHelper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockPkHelper(t interface { - mock.TestingT - Cleanup(func()) -}) *MockPkHelper { - mock := &MockPkHelper{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/evdev/mock_EvdevDevice.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/evdev/mock_EvdevDevice.go deleted file mode 100644 index 4d54e3e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/evdev/mock_EvdevDevice.go +++ /dev/null @@ -1,295 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_evdev - -import ( - go_evdev "github.com/holoplot/go-evdev" - mock "github.com/stretchr/testify/mock" -) - -// MockEvdevDevice is an autogenerated mock type for the EvdevDevice type -type MockEvdevDevice struct { - mock.Mock -} - -type MockEvdevDevice_Expecter struct { - mock *mock.Mock -} - -func (_m *MockEvdevDevice) EXPECT() *MockEvdevDevice_Expecter { - return &MockEvdevDevice_Expecter{mock: &_m.Mock} -} - -// Close provides a mock function with no fields -func (_m *MockEvdevDevice) Close() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockEvdevDevice_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockEvdevDevice_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockEvdevDevice_Expecter) Close() *MockEvdevDevice_Close_Call { - return &MockEvdevDevice_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockEvdevDevice_Close_Call) Run(run func()) *MockEvdevDevice_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockEvdevDevice_Close_Call) Return(_a0 error) *MockEvdevDevice_Close_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockEvdevDevice_Close_Call) RunAndReturn(run func() error) *MockEvdevDevice_Close_Call { - _c.Call.Return(run) - return _c -} - -// Name provides a mock function with no fields -func (_m *MockEvdevDevice) Name() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockEvdevDevice_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' -type MockEvdevDevice_Name_Call struct { - *mock.Call -} - -// Name is a helper method to define mock.On call -func (_e *MockEvdevDevice_Expecter) Name() *MockEvdevDevice_Name_Call { - return &MockEvdevDevice_Name_Call{Call: _e.mock.On("Name")} -} - -func (_c *MockEvdevDevice_Name_Call) Run(run func()) *MockEvdevDevice_Name_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockEvdevDevice_Name_Call) Return(_a0 string, _a1 error) *MockEvdevDevice_Name_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockEvdevDevice_Name_Call) RunAndReturn(run func() (string, error)) *MockEvdevDevice_Name_Call { - _c.Call.Return(run) - return _c -} - -// Path provides a mock function with no fields -func (_m *MockEvdevDevice) Path() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Path") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// MockEvdevDevice_Path_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Path' -type MockEvdevDevice_Path_Call struct { - *mock.Call -} - -// Path is a helper method to define mock.On call -func (_e *MockEvdevDevice_Expecter) Path() *MockEvdevDevice_Path_Call { - return &MockEvdevDevice_Path_Call{Call: _e.mock.On("Path")} -} - -func (_c *MockEvdevDevice_Path_Call) Run(run func()) *MockEvdevDevice_Path_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockEvdevDevice_Path_Call) Return(_a0 string) *MockEvdevDevice_Path_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockEvdevDevice_Path_Call) RunAndReturn(run func() string) *MockEvdevDevice_Path_Call { - _c.Call.Return(run) - return _c -} - -// ReadOne provides a mock function with no fields -func (_m *MockEvdevDevice) ReadOne() (*go_evdev.InputEvent, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ReadOne") - } - - var r0 *go_evdev.InputEvent - var r1 error - if rf, ok := ret.Get(0).(func() (*go_evdev.InputEvent, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() *go_evdev.InputEvent); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*go_evdev.InputEvent) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockEvdevDevice_ReadOne_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadOne' -type MockEvdevDevice_ReadOne_Call struct { - *mock.Call -} - -// ReadOne is a helper method to define mock.On call -func (_e *MockEvdevDevice_Expecter) ReadOne() *MockEvdevDevice_ReadOne_Call { - return &MockEvdevDevice_ReadOne_Call{Call: _e.mock.On("ReadOne")} -} - -func (_c *MockEvdevDevice_ReadOne_Call) Run(run func()) *MockEvdevDevice_ReadOne_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockEvdevDevice_ReadOne_Call) Return(_a0 *go_evdev.InputEvent, _a1 error) *MockEvdevDevice_ReadOne_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockEvdevDevice_ReadOne_Call) RunAndReturn(run func() (*go_evdev.InputEvent, error)) *MockEvdevDevice_ReadOne_Call { - _c.Call.Return(run) - return _c -} - -// State provides a mock function with given fields: t -func (_m *MockEvdevDevice) State(t go_evdev.EvType) (go_evdev.StateMap, error) { - ret := _m.Called(t) - - if len(ret) == 0 { - panic("no return value specified for State") - } - - var r0 go_evdev.StateMap - var r1 error - if rf, ok := ret.Get(0).(func(go_evdev.EvType) (go_evdev.StateMap, error)); ok { - return rf(t) - } - if rf, ok := ret.Get(0).(func(go_evdev.EvType) go_evdev.StateMap); ok { - r0 = rf(t) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(go_evdev.StateMap) - } - } - - if rf, ok := ret.Get(1).(func(go_evdev.EvType) error); ok { - r1 = rf(t) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockEvdevDevice_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State' -type MockEvdevDevice_State_Call struct { - *mock.Call -} - -// State is a helper method to define mock.On call -// - t go_evdev.EvType -func (_e *MockEvdevDevice_Expecter) State(t interface{}) *MockEvdevDevice_State_Call { - return &MockEvdevDevice_State_Call{Call: _e.mock.On("State", t)} -} - -func (_c *MockEvdevDevice_State_Call) Run(run func(t go_evdev.EvType)) *MockEvdevDevice_State_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(go_evdev.EvType)) - }) - return _c -} - -func (_c *MockEvdevDevice_State_Call) Return(_a0 go_evdev.StateMap, _a1 error) *MockEvdevDevice_State_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockEvdevDevice_State_Call) RunAndReturn(run func(go_evdev.EvType) (go_evdev.StateMap, error)) *MockEvdevDevice_State_Call { - _c.Call.Return(run) - return _c -} - -// NewMockEvdevDevice creates a new instance of MockEvdevDevice. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockEvdevDevice(t interface { - mock.TestingT - Cleanup(func()) -}) *MockEvdevDevice { - mock := &MockEvdevDevice{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/geolocation/mock_Client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/geolocation/mock_Client.go deleted file mode 100644 index bf097cb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/geolocation/mock_Client.go +++ /dev/null @@ -1,203 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_geolocation - -import ( - geolocation "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - mock "github.com/stretchr/testify/mock" -) - -// MockClient is an autogenerated mock type for the Client type -type MockClient struct { - mock.Mock -} - -type MockClient_Expecter struct { - mock *mock.Mock -} - -func (_m *MockClient) EXPECT() *MockClient_Expecter { - return &MockClient_Expecter{mock: &_m.Mock} -} - -// Close provides a mock function with no fields -func (_m *MockClient) Close() { - _m.Called() -} - -// MockClient_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockClient_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockClient_Expecter) Close() *MockClient_Close_Call { - return &MockClient_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockClient_Close_Call) Run(run func()) *MockClient_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockClient_Close_Call) Return() *MockClient_Close_Call { - _c.Call.Return() - return _c -} - -func (_c *MockClient_Close_Call) RunAndReturn(run func()) *MockClient_Close_Call { - _c.Run(run) - return _c -} - -// GetLocation provides a mock function with no fields -func (_m *MockClient) GetLocation() (geolocation.Location, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetLocation") - } - - var r0 geolocation.Location - var r1 error - if rf, ok := ret.Get(0).(func() (geolocation.Location, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() geolocation.Location); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(geolocation.Location) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockClient_GetLocation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLocation' -type MockClient_GetLocation_Call struct { - *mock.Call -} - -// GetLocation is a helper method to define mock.On call -func (_e *MockClient_Expecter) GetLocation() *MockClient_GetLocation_Call { - return &MockClient_GetLocation_Call{Call: _e.mock.On("GetLocation")} -} - -func (_c *MockClient_GetLocation_Call) Run(run func()) *MockClient_GetLocation_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockClient_GetLocation_Call) Return(_a0 geolocation.Location, _a1 error) *MockClient_GetLocation_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockClient_GetLocation_Call) RunAndReturn(run func() (geolocation.Location, error)) *MockClient_GetLocation_Call { - _c.Call.Return(run) - return _c -} - -// Subscribe provides a mock function with given fields: id -func (_m *MockClient) Subscribe(id string) chan geolocation.Location { - ret := _m.Called(id) - - if len(ret) == 0 { - panic("no return value specified for Subscribe") - } - - var r0 chan geolocation.Location - if rf, ok := ret.Get(0).(func(string) chan geolocation.Location); ok { - r0 = rf(id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(chan geolocation.Location) - } - } - - return r0 -} - -// MockClient_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' -type MockClient_Subscribe_Call struct { - *mock.Call -} - -// Subscribe is a helper method to define mock.On call -// - id string -func (_e *MockClient_Expecter) Subscribe(id interface{}) *MockClient_Subscribe_Call { - return &MockClient_Subscribe_Call{Call: _e.mock.On("Subscribe", id)} -} - -func (_c *MockClient_Subscribe_Call) Run(run func(id string)) *MockClient_Subscribe_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockClient_Subscribe_Call) Return(_a0 chan geolocation.Location) *MockClient_Subscribe_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockClient_Subscribe_Call) RunAndReturn(run func(string) chan geolocation.Location) *MockClient_Subscribe_Call { - _c.Call.Return(run) - return _c -} - -// Unsubscribe provides a mock function with given fields: id -func (_m *MockClient) Unsubscribe(id string) { - _m.Called(id) -} - -// MockClient_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe' -type MockClient_Unsubscribe_Call struct { - *mock.Call -} - -// Unsubscribe is a helper method to define mock.On call -// - id string -func (_e *MockClient_Expecter) Unsubscribe(id interface{}) *MockClient_Unsubscribe_Call { - return &MockClient_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe", id)} -} - -func (_c *MockClient_Unsubscribe_Call) Run(run func(id string)) *MockClient_Unsubscribe_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockClient_Unsubscribe_Call) Return() *MockClient_Unsubscribe_Call { - _c.Call.Return() - return _c -} - -func (_c *MockClient_Unsubscribe_Call) RunAndReturn(run func(string)) *MockClient_Unsubscribe_Call { - _c.Run(run) - return _c -} - -// NewMockClient creates a new instance of MockClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockClient(t interface { - mock.TestingT - Cleanup(func()) -}) *MockClient { - mock := &MockClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go deleted file mode 100644 index ae5124d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go +++ /dev/null @@ -1,689 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockAccessPoint is an autogenerated mock type for the AccessPoint type -type MockAccessPoint struct { - mock.Mock -} - -type MockAccessPoint_Expecter struct { - mock *mock.Mock -} - -func (_m *MockAccessPoint) EXPECT() *MockAccessPoint_Expecter { - return &MockAccessPoint_Expecter{mock: &_m.Mock} -} - -// GetPath provides a mock function with no fields -func (_m *MockAccessPoint) GetPath() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPath") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockAccessPoint_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath' -type MockAccessPoint_GetPath_Call struct { - *mock.Call -} - -// GetPath is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPath() *MockAccessPoint_GetPath_Call { - return &MockAccessPoint_GetPath_Call{Call: _e.mock.On("GetPath")} -} - -func (_c *MockAccessPoint_GetPath_Call) Run(run func()) *MockAccessPoint_GetPath_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockAccessPoint_GetPath_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockAccessPoint_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockAccessPoint_GetPath_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFlags provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyFlags() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFlags") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFlags' -type MockAccessPoint_GetPropertyFlags_Call struct { - *mock.Call -} - -// GetPropertyFlags is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyFlags() *MockAccessPoint_GetPropertyFlags_Call { - return &MockAccessPoint_GetPropertyFlags_Call{Call: _e.mock.On("GetPropertyFlags")} -} - -func (_c *MockAccessPoint_GetPropertyFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyFlags_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyFlags_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyFlags_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFrequency provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyFrequency() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFrequency") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyFrequency_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFrequency' -type MockAccessPoint_GetPropertyFrequency_Call struct { - *mock.Call -} - -// GetPropertyFrequency is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyFrequency() *MockAccessPoint_GetPropertyFrequency_Call { - return &MockAccessPoint_GetPropertyFrequency_Call{Call: _e.mock.On("GetPropertyFrequency")} -} - -func (_c *MockAccessPoint_GetPropertyFrequency_Call) Run(run func()) *MockAccessPoint_GetPropertyFrequency_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyFrequency_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyFrequency_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyFrequency_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyFrequency_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyHWAddress provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyHWAddress() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyHWAddress") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyHWAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHWAddress' -type MockAccessPoint_GetPropertyHWAddress_Call struct { - *mock.Call -} - -// GetPropertyHWAddress is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyHWAddress() *MockAccessPoint_GetPropertyHWAddress_Call { - return &MockAccessPoint_GetPropertyHWAddress_Call{Call: _e.mock.On("GetPropertyHWAddress")} -} - -func (_c *MockAccessPoint_GetPropertyHWAddress_Call) Run(run func()) *MockAccessPoint_GetPropertyHWAddress_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyHWAddress_Call) Return(_a0 string, _a1 error) *MockAccessPoint_GetPropertyHWAddress_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyHWAddress_Call) RunAndReturn(run func() (string, error)) *MockAccessPoint_GetPropertyHWAddress_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyLastSeen provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyLastSeen() (int32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyLastSeen") - } - - var r0 int32 - var r1 error - if rf, ok := ret.Get(0).(func() (int32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() int32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(int32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyLastSeen_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyLastSeen' -type MockAccessPoint_GetPropertyLastSeen_Call struct { - *mock.Call -} - -// GetPropertyLastSeen is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyLastSeen() *MockAccessPoint_GetPropertyLastSeen_Call { - return &MockAccessPoint_GetPropertyLastSeen_Call{Call: _e.mock.On("GetPropertyLastSeen")} -} - -func (_c *MockAccessPoint_GetPropertyLastSeen_Call) Run(run func()) *MockAccessPoint_GetPropertyLastSeen_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyLastSeen_Call) Return(_a0 int32, _a1 error) *MockAccessPoint_GetPropertyLastSeen_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyLastSeen_Call) RunAndReturn(run func() (int32, error)) *MockAccessPoint_GetPropertyLastSeen_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMaxBitrate provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyMaxBitrate() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMaxBitrate") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyMaxBitrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMaxBitrate' -type MockAccessPoint_GetPropertyMaxBitrate_Call struct { - *mock.Call -} - -// GetPropertyMaxBitrate is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyMaxBitrate() *MockAccessPoint_GetPropertyMaxBitrate_Call { - return &MockAccessPoint_GetPropertyMaxBitrate_Call{Call: _e.mock.On("GetPropertyMaxBitrate")} -} - -func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) Run(run func()) *MockAccessPoint_GetPropertyMaxBitrate_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyMaxBitrate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyMaxBitrate_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMode provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyMode() (gonetworkmanager.Nm80211Mode, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMode") - } - - var r0 gonetworkmanager.Nm80211Mode - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.Nm80211Mode, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.Nm80211Mode); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.Nm80211Mode) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMode' -type MockAccessPoint_GetPropertyMode_Call struct { - *mock.Call -} - -// GetPropertyMode is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyMode() *MockAccessPoint_GetPropertyMode_Call { - return &MockAccessPoint_GetPropertyMode_Call{Call: _e.mock.On("GetPropertyMode")} -} - -func (_c *MockAccessPoint_GetPropertyMode_Call) Run(run func()) *MockAccessPoint_GetPropertyMode_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyMode_Call) Return(_a0 gonetworkmanager.Nm80211Mode, _a1 error) *MockAccessPoint_GetPropertyMode_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyMode_Call) RunAndReturn(run func() (gonetworkmanager.Nm80211Mode, error)) *MockAccessPoint_GetPropertyMode_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyRSNFlags provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyRSNFlags() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyRSNFlags") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyRSNFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRSNFlags' -type MockAccessPoint_GetPropertyRSNFlags_Call struct { - *mock.Call -} - -// GetPropertyRSNFlags is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyRSNFlags() *MockAccessPoint_GetPropertyRSNFlags_Call { - return &MockAccessPoint_GetPropertyRSNFlags_Call{Call: _e.mock.On("GetPropertyRSNFlags")} -} - -func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyRSNFlags_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyRSNFlags_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyRSNFlags_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertySSID provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertySSID() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertySSID") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertySSID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySSID' -type MockAccessPoint_GetPropertySSID_Call struct { - *mock.Call -} - -// GetPropertySSID is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertySSID() *MockAccessPoint_GetPropertySSID_Call { - return &MockAccessPoint_GetPropertySSID_Call{Call: _e.mock.On("GetPropertySSID")} -} - -func (_c *MockAccessPoint_GetPropertySSID_Call) Run(run func()) *MockAccessPoint_GetPropertySSID_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertySSID_Call) Return(_a0 string, _a1 error) *MockAccessPoint_GetPropertySSID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertySSID_Call) RunAndReturn(run func() (string, error)) *MockAccessPoint_GetPropertySSID_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyStrength provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyStrength() (uint8, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyStrength") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func() (uint8, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint8); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyStrength_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStrength' -type MockAccessPoint_GetPropertyStrength_Call struct { - *mock.Call -} - -// GetPropertyStrength is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyStrength() *MockAccessPoint_GetPropertyStrength_Call { - return &MockAccessPoint_GetPropertyStrength_Call{Call: _e.mock.On("GetPropertyStrength")} -} - -func (_c *MockAccessPoint_GetPropertyStrength_Call) Run(run func()) *MockAccessPoint_GetPropertyStrength_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyStrength_Call) Return(_a0 uint8, _a1 error) *MockAccessPoint_GetPropertyStrength_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyStrength_Call) RunAndReturn(run func() (uint8, error)) *MockAccessPoint_GetPropertyStrength_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWPAFlags provides a mock function with no fields -func (_m *MockAccessPoint) GetPropertyWPAFlags() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWPAFlags") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_GetPropertyWPAFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWPAFlags' -type MockAccessPoint_GetPropertyWPAFlags_Call struct { - *mock.Call -} - -// GetPropertyWPAFlags is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) GetPropertyWPAFlags() *MockAccessPoint_GetPropertyWPAFlags_Call { - return &MockAccessPoint_GetPropertyWPAFlags_Call{Call: _e.mock.On("GetPropertyWPAFlags")} -} - -func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyWPAFlags_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyWPAFlags_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyWPAFlags_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockAccessPoint) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockAccessPoint_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockAccessPoint_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockAccessPoint_Expecter) MarshalJSON() *MockAccessPoint_MarshalJSON_Call { - return &MockAccessPoint_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockAccessPoint_MarshalJSON_Call) Run(run func()) *MockAccessPoint_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockAccessPoint_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockAccessPoint_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockAccessPoint_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockAccessPoint_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// NewMockAccessPoint creates a new instance of MockAccessPoint. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockAccessPoint(t interface { - mock.TestingT - Cleanup(func()) -}) *MockAccessPoint { - mock := &MockAccessPoint{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go deleted file mode 100644 index a4e3344..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go +++ /dev/null @@ -1,1025 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockActiveConnection is an autogenerated mock type for the ActiveConnection type -type MockActiveConnection struct { - mock.Mock -} - -type MockActiveConnection_Expecter struct { - mock *mock.Mock -} - -func (_m *MockActiveConnection) EXPECT() *MockActiveConnection_Expecter { - return &MockActiveConnection_Expecter{mock: &_m.Mock} -} - -// GetPath provides a mock function with no fields -func (_m *MockActiveConnection) GetPath() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPath") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockActiveConnection_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath' -type MockActiveConnection_GetPath_Call struct { - *mock.Call -} - -// GetPath is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPath() *MockActiveConnection_GetPath_Call { - return &MockActiveConnection_GetPath_Call{Call: _e.mock.On("GetPath")} -} - -func (_c *MockActiveConnection_GetPath_Call) Run(run func()) *MockActiveConnection_GetPath_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockActiveConnection_GetPath_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockActiveConnection_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockActiveConnection_GetPath_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyConnection provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyConnection() (gonetworkmanager.Connection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyConnection") - } - - var r0 gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.Connection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.Connection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnection' -type MockActiveConnection_GetPropertyConnection_Call struct { - *mock.Call -} - -// GetPropertyConnection is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyConnection() *MockActiveConnection_GetPropertyConnection_Call { - return &MockActiveConnection_GetPropertyConnection_Call{Call: _e.mock.On("GetPropertyConnection")} -} - -func (_c *MockActiveConnection_GetPropertyConnection_Call) Run(run func()) *MockActiveConnection_GetPropertyConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyConnection_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockActiveConnection_GetPropertyConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyConnection_Call) RunAndReturn(run func() (gonetworkmanager.Connection, error)) *MockActiveConnection_GetPropertyConnection_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP4Config provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP4Config") - } - - var r0 gonetworkmanager.DHCP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config' -type MockActiveConnection_GetPropertyDHCP4Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP4Config is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyDHCP4Config() *MockActiveConnection_GetPropertyDHCP4Config_Call { - return &MockActiveConnection_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")} -} - -func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) Run(run func()) *MockActiveConnection_GetPropertyDHCP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockActiveConnection_GetPropertyDHCP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockActiveConnection_GetPropertyDHCP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP6Config provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP6Config") - } - - var r0 gonetworkmanager.DHCP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config' -type MockActiveConnection_GetPropertyDHCP6Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP6Config is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyDHCP6Config() *MockActiveConnection_GetPropertyDHCP6Config_Call { - return &MockActiveConnection_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")} -} - -func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) Run(run func()) *MockActiveConnection_GetPropertyDHCP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockActiveConnection_GetPropertyDHCP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockActiveConnection_GetPropertyDHCP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDefault provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyDefault() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDefault") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyDefault_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDefault' -type MockActiveConnection_GetPropertyDefault_Call struct { - *mock.Call -} - -// GetPropertyDefault is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyDefault() *MockActiveConnection_GetPropertyDefault_Call { - return &MockActiveConnection_GetPropertyDefault_Call{Call: _e.mock.On("GetPropertyDefault")} -} - -func (_c *MockActiveConnection_GetPropertyDefault_Call) Run(run func()) *MockActiveConnection_GetPropertyDefault_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDefault_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyDefault_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDefault_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyDefault_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDefault6 provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyDefault6() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDefault6") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyDefault6_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDefault6' -type MockActiveConnection_GetPropertyDefault6_Call struct { - *mock.Call -} - -// GetPropertyDefault6 is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyDefault6() *MockActiveConnection_GetPropertyDefault6_Call { - return &MockActiveConnection_GetPropertyDefault6_Call{Call: _e.mock.On("GetPropertyDefault6")} -} - -func (_c *MockActiveConnection_GetPropertyDefault6_Call) Run(run func()) *MockActiveConnection_GetPropertyDefault6_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDefault6_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyDefault6_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDefault6_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyDefault6_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDevices provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyDevices() ([]gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDevices") - } - - var r0 []gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDevices' -type MockActiveConnection_GetPropertyDevices_Call struct { - *mock.Call -} - -// GetPropertyDevices is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyDevices() *MockActiveConnection_GetPropertyDevices_Call { - return &MockActiveConnection_GetPropertyDevices_Call{Call: _e.mock.On("GetPropertyDevices")} -} - -func (_c *MockActiveConnection_GetPropertyDevices_Call) Run(run func()) *MockActiveConnection_GetPropertyDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockActiveConnection_GetPropertyDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockActiveConnection_GetPropertyDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyID provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyID() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyID") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyID' -type MockActiveConnection_GetPropertyID_Call struct { - *mock.Call -} - -// GetPropertyID is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyID() *MockActiveConnection_GetPropertyID_Call { - return &MockActiveConnection_GetPropertyID_Call{Call: _e.mock.On("GetPropertyID")} -} - -func (_c *MockActiveConnection_GetPropertyID_Call) Run(run func()) *MockActiveConnection_GetPropertyID_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyID_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyID_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyID_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP4Config provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP4Config") - } - - var r0 gonetworkmanager.IP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config' -type MockActiveConnection_GetPropertyIP4Config_Call struct { - *mock.Call -} - -// GetPropertyIP4Config is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyIP4Config() *MockActiveConnection_GetPropertyIP4Config_Call { - return &MockActiveConnection_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")} -} - -func (_c *MockActiveConnection_GetPropertyIP4Config_Call) Run(run func()) *MockActiveConnection_GetPropertyIP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockActiveConnection_GetPropertyIP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockActiveConnection_GetPropertyIP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP6Config provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP6Config") - } - - var r0 gonetworkmanager.IP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config' -type MockActiveConnection_GetPropertyIP6Config_Call struct { - *mock.Call -} - -// GetPropertyIP6Config is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyIP6Config() *MockActiveConnection_GetPropertyIP6Config_Call { - return &MockActiveConnection_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")} -} - -func (_c *MockActiveConnection_GetPropertyIP6Config_Call) Run(run func()) *MockActiveConnection_GetPropertyIP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockActiveConnection_GetPropertyIP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockActiveConnection_GetPropertyIP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMaster provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyMaster() (gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMaster") - } - - var r0 gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyMaster_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMaster' -type MockActiveConnection_GetPropertyMaster_Call struct { - *mock.Call -} - -// GetPropertyMaster is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyMaster() *MockActiveConnection_GetPropertyMaster_Call { - return &MockActiveConnection_GetPropertyMaster_Call{Call: _e.mock.On("GetPropertyMaster")} -} - -func (_c *MockActiveConnection_GetPropertyMaster_Call) Run(run func()) *MockActiveConnection_GetPropertyMaster_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyMaster_Call) Return(_a0 gonetworkmanager.Device, _a1 error) *MockActiveConnection_GetPropertyMaster_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyMaster_Call) RunAndReturn(run func() (gonetworkmanager.Device, error)) *MockActiveConnection_GetPropertyMaster_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertySpecificObject provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertySpecificObject() (gonetworkmanager.AccessPoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertySpecificObject") - } - - var r0 gonetworkmanager.AccessPoint - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.AccessPoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.AccessPoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.AccessPoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertySpecificObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySpecificObject' -type MockActiveConnection_GetPropertySpecificObject_Call struct { - *mock.Call -} - -// GetPropertySpecificObject is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertySpecificObject() *MockActiveConnection_GetPropertySpecificObject_Call { - return &MockActiveConnection_GetPropertySpecificObject_Call{Call: _e.mock.On("GetPropertySpecificObject")} -} - -func (_c *MockActiveConnection_GetPropertySpecificObject_Call) Run(run func()) *MockActiveConnection_GetPropertySpecificObject_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertySpecificObject_Call) Return(_a0 gonetworkmanager.AccessPoint, _a1 error) *MockActiveConnection_GetPropertySpecificObject_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertySpecificObject_Call) RunAndReturn(run func() (gonetworkmanager.AccessPoint, error)) *MockActiveConnection_GetPropertySpecificObject_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyState provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyState() (gonetworkmanager.NmActiveConnectionState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyState") - } - - var r0 gonetworkmanager.NmActiveConnectionState - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmActiveConnectionState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmActiveConnectionState); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmActiveConnectionState) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState' -type MockActiveConnection_GetPropertyState_Call struct { - *mock.Call -} - -// GetPropertyState is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyState() *MockActiveConnection_GetPropertyState_Call { - return &MockActiveConnection_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")} -} - -func (_c *MockActiveConnection_GetPropertyState_Call) Run(run func()) *MockActiveConnection_GetPropertyState_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmActiveConnectionState, _a1 error) *MockActiveConnection_GetPropertyState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmActiveConnectionState, error)) *MockActiveConnection_GetPropertyState_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyStateFlags provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyStateFlags() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyStateFlags") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyStateFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStateFlags' -type MockActiveConnection_GetPropertyStateFlags_Call struct { - *mock.Call -} - -// GetPropertyStateFlags is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyStateFlags() *MockActiveConnection_GetPropertyStateFlags_Call { - return &MockActiveConnection_GetPropertyStateFlags_Call{Call: _e.mock.On("GetPropertyStateFlags")} -} - -func (_c *MockActiveConnection_GetPropertyStateFlags_Call) Run(run func()) *MockActiveConnection_GetPropertyStateFlags_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyStateFlags_Call) Return(_a0 uint32, _a1 error) *MockActiveConnection_GetPropertyStateFlags_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyStateFlags_Call) RunAndReturn(run func() (uint32, error)) *MockActiveConnection_GetPropertyStateFlags_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyType provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyType() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyType") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyType' -type MockActiveConnection_GetPropertyType_Call struct { - *mock.Call -} - -// GetPropertyType is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyType() *MockActiveConnection_GetPropertyType_Call { - return &MockActiveConnection_GetPropertyType_Call{Call: _e.mock.On("GetPropertyType")} -} - -func (_c *MockActiveConnection_GetPropertyType_Call) Run(run func()) *MockActiveConnection_GetPropertyType_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyType_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyType_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyType_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyType_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyUUID provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyUUID() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyUUID") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyUUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUUID' -type MockActiveConnection_GetPropertyUUID_Call struct { - *mock.Call -} - -// GetPropertyUUID is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyUUID() *MockActiveConnection_GetPropertyUUID_Call { - return &MockActiveConnection_GetPropertyUUID_Call{Call: _e.mock.On("GetPropertyUUID")} -} - -func (_c *MockActiveConnection_GetPropertyUUID_Call) Run(run func()) *MockActiveConnection_GetPropertyUUID_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyUUID_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyUUID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyUUID_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyUUID_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyVPN provides a mock function with no fields -func (_m *MockActiveConnection) GetPropertyVPN() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyVPN") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockActiveConnection_GetPropertyVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyVPN' -type MockActiveConnection_GetPropertyVPN_Call struct { - *mock.Call -} - -// GetPropertyVPN is a helper method to define mock.On call -func (_e *MockActiveConnection_Expecter) GetPropertyVPN() *MockActiveConnection_GetPropertyVPN_Call { - return &MockActiveConnection_GetPropertyVPN_Call{Call: _e.mock.On("GetPropertyVPN")} -} - -func (_c *MockActiveConnection_GetPropertyVPN_Call) Run(run func()) *MockActiveConnection_GetPropertyVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockActiveConnection_GetPropertyVPN_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyVPN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockActiveConnection_GetPropertyVPN_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyVPN_Call { - _c.Call.Return(run) - return _c -} - -// SubscribeState provides a mock function with given fields: receiver, exit -func (_m *MockActiveConnection) SubscribeState(receiver chan gonetworkmanager.StateChange, exit chan struct{}) error { - ret := _m.Called(receiver, exit) - - if len(ret) == 0 { - panic("no return value specified for SubscribeState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(chan gonetworkmanager.StateChange, chan struct{}) error); ok { - r0 = rf(receiver, exit) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockActiveConnection_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState' -type MockActiveConnection_SubscribeState_Call struct { - *mock.Call -} - -// SubscribeState is a helper method to define mock.On call -// - receiver chan gonetworkmanager.StateChange -// - exit chan struct{} -func (_e *MockActiveConnection_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockActiveConnection_SubscribeState_Call { - return &MockActiveConnection_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)} -} - -func (_c *MockActiveConnection_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.StateChange, exit chan struct{})) *MockActiveConnection_SubscribeState_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(chan gonetworkmanager.StateChange), args[1].(chan struct{})) - }) - return _c -} - -func (_c *MockActiveConnection_SubscribeState_Call) Return(err error) *MockActiveConnection_SubscribeState_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockActiveConnection_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.StateChange, chan struct{}) error) *MockActiveConnection_SubscribeState_Call { - _c.Call.Return(run) - return _c -} - -// NewMockActiveConnection creates a new instance of MockActiveConnection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockActiveConnection(t interface { - mock.TestingT - Cleanup(func()) -}) *MockActiveConnection { - mock := &MockActiveConnection{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go deleted file mode 100644 index 84f59e1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go +++ /dev/null @@ -1,646 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockConnection is an autogenerated mock type for the Connection type -type MockConnection struct { - mock.Mock -} - -type MockConnection_Expecter struct { - mock *mock.Mock -} - -func (_m *MockConnection) EXPECT() *MockConnection_Expecter { - return &MockConnection_Expecter{mock: &_m.Mock} -} - -// ClearSecrets provides a mock function with no fields -func (_m *MockConnection) ClearSecrets() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ClearSecrets") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConnection_ClearSecrets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearSecrets' -type MockConnection_ClearSecrets_Call struct { - *mock.Call -} - -// ClearSecrets is a helper method to define mock.On call -func (_e *MockConnection_Expecter) ClearSecrets() *MockConnection_ClearSecrets_Call { - return &MockConnection_ClearSecrets_Call{Call: _e.mock.On("ClearSecrets")} -} - -func (_c *MockConnection_ClearSecrets_Call) Run(run func()) *MockConnection_ClearSecrets_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_ClearSecrets_Call) Return(_a0 error) *MockConnection_ClearSecrets_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_ClearSecrets_Call) RunAndReturn(run func() error) *MockConnection_ClearSecrets_Call { - _c.Call.Return(run) - return _c -} - -// Delete provides a mock function with no fields -func (_m *MockConnection) Delete() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Delete") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConnection_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type MockConnection_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -func (_e *MockConnection_Expecter) Delete() *MockConnection_Delete_Call { - return &MockConnection_Delete_Call{Call: _e.mock.On("Delete")} -} - -func (_c *MockConnection_Delete_Call) Run(run func()) *MockConnection_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_Delete_Call) Return(_a0 error) *MockConnection_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_Delete_Call) RunAndReturn(run func() error) *MockConnection_Delete_Call { - _c.Call.Return(run) - return _c -} - -// GetPath provides a mock function with no fields -func (_m *MockConnection) GetPath() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPath") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockConnection_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath' -type MockConnection_GetPath_Call struct { - *mock.Call -} - -// GetPath is a helper method to define mock.On call -func (_e *MockConnection_Expecter) GetPath() *MockConnection_GetPath_Call { - return &MockConnection_GetPath_Call{Call: _e.mock.On("GetPath")} -} - -func (_c *MockConnection_GetPath_Call) Run(run func()) *MockConnection_GetPath_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockConnection_GetPath_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockConnection_GetPath_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFilename provides a mock function with no fields -func (_m *MockConnection) GetPropertyFilename() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFilename") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_GetPropertyFilename_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFilename' -type MockConnection_GetPropertyFilename_Call struct { - *mock.Call -} - -// GetPropertyFilename is a helper method to define mock.On call -func (_e *MockConnection_Expecter) GetPropertyFilename() *MockConnection_GetPropertyFilename_Call { - return &MockConnection_GetPropertyFilename_Call{Call: _e.mock.On("GetPropertyFilename")} -} - -func (_c *MockConnection_GetPropertyFilename_Call) Run(run func()) *MockConnection_GetPropertyFilename_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_GetPropertyFilename_Call) Return(_a0 string, _a1 error) *MockConnection_GetPropertyFilename_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_GetPropertyFilename_Call) RunAndReturn(run func() (string, error)) *MockConnection_GetPropertyFilename_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFlags provides a mock function with no fields -func (_m *MockConnection) GetPropertyFlags() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFlags") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_GetPropertyFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFlags' -type MockConnection_GetPropertyFlags_Call struct { - *mock.Call -} - -// GetPropertyFlags is a helper method to define mock.On call -func (_e *MockConnection_Expecter) GetPropertyFlags() *MockConnection_GetPropertyFlags_Call { - return &MockConnection_GetPropertyFlags_Call{Call: _e.mock.On("GetPropertyFlags")} -} - -func (_c *MockConnection_GetPropertyFlags_Call) Run(run func()) *MockConnection_GetPropertyFlags_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_GetPropertyFlags_Call) Return(_a0 uint32, _a1 error) *MockConnection_GetPropertyFlags_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_GetPropertyFlags_Call) RunAndReturn(run func() (uint32, error)) *MockConnection_GetPropertyFlags_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyUnsaved provides a mock function with no fields -func (_m *MockConnection) GetPropertyUnsaved() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyUnsaved") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_GetPropertyUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUnsaved' -type MockConnection_GetPropertyUnsaved_Call struct { - *mock.Call -} - -// GetPropertyUnsaved is a helper method to define mock.On call -func (_e *MockConnection_Expecter) GetPropertyUnsaved() *MockConnection_GetPropertyUnsaved_Call { - return &MockConnection_GetPropertyUnsaved_Call{Call: _e.mock.On("GetPropertyUnsaved")} -} - -func (_c *MockConnection_GetPropertyUnsaved_Call) Run(run func()) *MockConnection_GetPropertyUnsaved_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_GetPropertyUnsaved_Call) Return(_a0 bool, _a1 error) *MockConnection_GetPropertyUnsaved_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_GetPropertyUnsaved_Call) RunAndReturn(run func() (bool, error)) *MockConnection_GetPropertyUnsaved_Call { - _c.Call.Return(run) - return _c -} - -// GetSecrets provides a mock function with given fields: settingName -func (_m *MockConnection) GetSecrets(settingName string) (gonetworkmanager.ConnectionSettings, error) { - ret := _m.Called(settingName) - - if len(ret) == 0 { - panic("no return value specified for GetSecrets") - } - - var r0 gonetworkmanager.ConnectionSettings - var r1 error - if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.ConnectionSettings, error)); ok { - return rf(settingName) - } - if rf, ok := ret.Get(0).(func(string) gonetworkmanager.ConnectionSettings); ok { - r0 = rf(settingName) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ConnectionSettings) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(settingName) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_GetSecrets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSecrets' -type MockConnection_GetSecrets_Call struct { - *mock.Call -} - -// GetSecrets is a helper method to define mock.On call -// - settingName string -func (_e *MockConnection_Expecter) GetSecrets(settingName interface{}) *MockConnection_GetSecrets_Call { - return &MockConnection_GetSecrets_Call{Call: _e.mock.On("GetSecrets", settingName)} -} - -func (_c *MockConnection_GetSecrets_Call) Run(run func(settingName string)) *MockConnection_GetSecrets_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockConnection_GetSecrets_Call) Return(_a0 gonetworkmanager.ConnectionSettings, _a1 error) *MockConnection_GetSecrets_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_GetSecrets_Call) RunAndReturn(run func(string) (gonetworkmanager.ConnectionSettings, error)) *MockConnection_GetSecrets_Call { - _c.Call.Return(run) - return _c -} - -// GetSettings provides a mock function with no fields -func (_m *MockConnection) GetSettings() (gonetworkmanager.ConnectionSettings, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetSettings") - } - - var r0 gonetworkmanager.ConnectionSettings - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.ConnectionSettings, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.ConnectionSettings); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ConnectionSettings) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_GetSettings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSettings' -type MockConnection_GetSettings_Call struct { - *mock.Call -} - -// GetSettings is a helper method to define mock.On call -func (_e *MockConnection_Expecter) GetSettings() *MockConnection_GetSettings_Call { - return &MockConnection_GetSettings_Call{Call: _e.mock.On("GetSettings")} -} - -func (_c *MockConnection_GetSettings_Call) Run(run func()) *MockConnection_GetSettings_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_GetSettings_Call) Return(_a0 gonetworkmanager.ConnectionSettings, _a1 error) *MockConnection_GetSettings_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_GetSettings_Call) RunAndReturn(run func() (gonetworkmanager.ConnectionSettings, error)) *MockConnection_GetSettings_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockConnection) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConnection_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockConnection_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockConnection_Expecter) MarshalJSON() *MockConnection_MarshalJSON_Call { - return &MockConnection_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockConnection_MarshalJSON_Call) Run(run func()) *MockConnection_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockConnection_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockConnection_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockConnection_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// Save provides a mock function with no fields -func (_m *MockConnection) Save() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Save") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConnection_Save_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Save' -type MockConnection_Save_Call struct { - *mock.Call -} - -// Save is a helper method to define mock.On call -func (_e *MockConnection_Expecter) Save() *MockConnection_Save_Call { - return &MockConnection_Save_Call{Call: _e.mock.On("Save")} -} - -func (_c *MockConnection_Save_Call) Run(run func()) *MockConnection_Save_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConnection_Save_Call) Return(_a0 error) *MockConnection_Save_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_Save_Call) RunAndReturn(run func() error) *MockConnection_Save_Call { - _c.Call.Return(run) - return _c -} - -// Update provides a mock function with given fields: settings -func (_m *MockConnection) Update(settings gonetworkmanager.ConnectionSettings) error { - ret := _m.Called(settings) - - if len(ret) == 0 { - panic("no return value specified for Update") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) error); ok { - r0 = rf(settings) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConnection_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' -type MockConnection_Update_Call struct { - *mock.Call -} - -// Update is a helper method to define mock.On call -// - settings gonetworkmanager.ConnectionSettings -func (_e *MockConnection_Expecter) Update(settings interface{}) *MockConnection_Update_Call { - return &MockConnection_Update_Call{Call: _e.mock.On("Update", settings)} -} - -func (_c *MockConnection_Update_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockConnection_Update_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.ConnectionSettings)) - }) - return _c -} - -func (_c *MockConnection_Update_Call) Return(_a0 error) *MockConnection_Update_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_Update_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) error) *MockConnection_Update_Call { - _c.Call.Return(run) - return _c -} - -// UpdateUnsaved provides a mock function with given fields: settings -func (_m *MockConnection) UpdateUnsaved(settings gonetworkmanager.ConnectionSettings) error { - ret := _m.Called(settings) - - if len(ret) == 0 { - panic("no return value specified for UpdateUnsaved") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) error); ok { - r0 = rf(settings) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConnection_UpdateUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateUnsaved' -type MockConnection_UpdateUnsaved_Call struct { - *mock.Call -} - -// UpdateUnsaved is a helper method to define mock.On call -// - settings gonetworkmanager.ConnectionSettings -func (_e *MockConnection_Expecter) UpdateUnsaved(settings interface{}) *MockConnection_UpdateUnsaved_Call { - return &MockConnection_UpdateUnsaved_Call{Call: _e.mock.On("UpdateUnsaved", settings)} -} - -func (_c *MockConnection_UpdateUnsaved_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockConnection_UpdateUnsaved_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.ConnectionSettings)) - }) - return _c -} - -func (_c *MockConnection_UpdateUnsaved_Call) Return(_a0 error) *MockConnection_UpdateUnsaved_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConnection_UpdateUnsaved_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) error) *MockConnection_UpdateUnsaved_Call { - _c.Call.Return(run) - return _c -} - -// NewMockConnection creates a new instance of MockConnection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockConnection(t interface { - mock.TestingT - Cleanup(func()) -}) *MockConnection { - mock := &MockConnection{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go deleted file mode 100644 index b2fc0b5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go +++ /dev/null @@ -1,1638 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockDevice is an autogenerated mock type for the Device type -type MockDevice struct { - mock.Mock -} - -type MockDevice_Expecter struct { - mock *mock.Mock -} - -func (_m *MockDevice) EXPECT() *MockDevice_Expecter { - return &MockDevice_Expecter{mock: &_m.Mock} -} - -// Delete provides a mock function with no fields -func (_m *MockDevice) Delete() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Delete") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type MockDevice_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -func (_e *MockDevice_Expecter) Delete() *MockDevice_Delete_Call { - return &MockDevice_Delete_Call{Call: _e.mock.On("Delete")} -} - -func (_c *MockDevice_Delete_Call) Run(run func()) *MockDevice_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_Delete_Call) Return(_a0 error) *MockDevice_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_Delete_Call) RunAndReturn(run func() error) *MockDevice_Delete_Call { - _c.Call.Return(run) - return _c -} - -// Disconnect provides a mock function with no fields -func (_m *MockDevice) Disconnect() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Disconnect") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_Disconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Disconnect' -type MockDevice_Disconnect_Call struct { - *mock.Call -} - -// Disconnect is a helper method to define mock.On call -func (_e *MockDevice_Expecter) Disconnect() *MockDevice_Disconnect_Call { - return &MockDevice_Disconnect_Call{Call: _e.mock.On("Disconnect")} -} - -func (_c *MockDevice_Disconnect_Call) Run(run func()) *MockDevice_Disconnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_Disconnect_Call) Return(_a0 error) *MockDevice_Disconnect_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_Disconnect_Call) RunAndReturn(run func() error) *MockDevice_Disconnect_Call { - _c.Call.Return(run) - return _c -} - -// GetPath provides a mock function with no fields -func (_m *MockDevice) GetPath() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPath") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockDevice_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath' -type MockDevice_GetPath_Call struct { - *mock.Call -} - -// GetPath is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPath() *MockDevice_GetPath_Call { - return &MockDevice_GetPath_Call{Call: _e.mock.On("GetPath")} -} - -func (_c *MockDevice_GetPath_Call) Run(run func()) *MockDevice_GetPath_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockDevice_GetPath_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockDevice_GetPath_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyActiveConnection provides a mock function with no fields -func (_m *MockDevice) GetPropertyActiveConnection() (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyActiveConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyActiveConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnection' -type MockDevice_GetPropertyActiveConnection_Call struct { - *mock.Call -} - -// GetPropertyActiveConnection is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyActiveConnection() *MockDevice_GetPropertyActiveConnection_Call { - return &MockDevice_GetPropertyActiveConnection_Call{Call: _e.mock.On("GetPropertyActiveConnection")} -} - -func (_c *MockDevice_GetPropertyActiveConnection_Call) Run(run func()) *MockDevice_GetPropertyActiveConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyActiveConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockDevice_GetPropertyActiveConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyActiveConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockDevice_GetPropertyActiveConnection_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAutoConnect provides a mock function with no fields -func (_m *MockDevice) GetPropertyAutoConnect() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAutoConnect") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAutoConnect' -type MockDevice_GetPropertyAutoConnect_Call struct { - *mock.Call -} - -// GetPropertyAutoConnect is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyAutoConnect() *MockDevice_GetPropertyAutoConnect_Call { - return &MockDevice_GetPropertyAutoConnect_Call{Call: _e.mock.On("GetPropertyAutoConnect")} -} - -func (_c *MockDevice_GetPropertyAutoConnect_Call) Run(run func()) *MockDevice_GetPropertyAutoConnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyAutoConnect_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyAutoConnect_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyAutoConnect_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyAutoConnect_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAvailableConnections provides a mock function with no fields -func (_m *MockDevice) GetPropertyAvailableConnections() ([]gonetworkmanager.Connection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAvailableConnections") - } - - var r0 []gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyAvailableConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAvailableConnections' -type MockDevice_GetPropertyAvailableConnections_Call struct { - *mock.Call -} - -// GetPropertyAvailableConnections is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyAvailableConnections() *MockDevice_GetPropertyAvailableConnections_Call { - return &MockDevice_GetPropertyAvailableConnections_Call{Call: _e.mock.On("GetPropertyAvailableConnections")} -} - -func (_c *MockDevice_GetPropertyAvailableConnections_Call) Run(run func()) *MockDevice_GetPropertyAvailableConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyAvailableConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockDevice_GetPropertyAvailableConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyAvailableConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockDevice_GetPropertyAvailableConnections_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP4Config provides a mock function with no fields -func (_m *MockDevice) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP4Config") - } - - var r0 gonetworkmanager.DHCP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config' -type MockDevice_GetPropertyDHCP4Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP4Config is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyDHCP4Config() *MockDevice_GetPropertyDHCP4Config_Call { - return &MockDevice_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")} -} - -func (_c *MockDevice_GetPropertyDHCP4Config_Call) Run(run func()) *MockDevice_GetPropertyDHCP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockDevice_GetPropertyDHCP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockDevice_GetPropertyDHCP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP6Config provides a mock function with no fields -func (_m *MockDevice) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP6Config") - } - - var r0 gonetworkmanager.DHCP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config' -type MockDevice_GetPropertyDHCP6Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP6Config is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyDHCP6Config() *MockDevice_GetPropertyDHCP6Config_Call { - return &MockDevice_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")} -} - -func (_c *MockDevice_GetPropertyDHCP6Config_Call) Run(run func()) *MockDevice_GetPropertyDHCP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockDevice_GetPropertyDHCP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockDevice_GetPropertyDHCP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDeviceType provides a mock function with no fields -func (_m *MockDevice) GetPropertyDeviceType() (gonetworkmanager.NmDeviceType, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDeviceType") - } - - var r0 gonetworkmanager.NmDeviceType - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceType, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceType); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmDeviceType) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyDeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDeviceType' -type MockDevice_GetPropertyDeviceType_Call struct { - *mock.Call -} - -// GetPropertyDeviceType is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyDeviceType() *MockDevice_GetPropertyDeviceType_Call { - return &MockDevice_GetPropertyDeviceType_Call{Call: _e.mock.On("GetPropertyDeviceType")} -} - -func (_c *MockDevice_GetPropertyDeviceType_Call) Run(run func()) *MockDevice_GetPropertyDeviceType_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyDeviceType_Call) Return(_a0 gonetworkmanager.NmDeviceType, _a1 error) *MockDevice_GetPropertyDeviceType_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyDeviceType_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceType, error)) *MockDevice_GetPropertyDeviceType_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDriver provides a mock function with no fields -func (_m *MockDevice) GetPropertyDriver() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDriver") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyDriver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriver' -type MockDevice_GetPropertyDriver_Call struct { - *mock.Call -} - -// GetPropertyDriver is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyDriver() *MockDevice_GetPropertyDriver_Call { - return &MockDevice_GetPropertyDriver_Call{Call: _e.mock.On("GetPropertyDriver")} -} - -func (_c *MockDevice_GetPropertyDriver_Call) Run(run func()) *MockDevice_GetPropertyDriver_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyDriver_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyDriver_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyDriver_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyDriver_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDriverVersion provides a mock function with no fields -func (_m *MockDevice) GetPropertyDriverVersion() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDriverVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyDriverVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriverVersion' -type MockDevice_GetPropertyDriverVersion_Call struct { - *mock.Call -} - -// GetPropertyDriverVersion is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyDriverVersion() *MockDevice_GetPropertyDriverVersion_Call { - return &MockDevice_GetPropertyDriverVersion_Call{Call: _e.mock.On("GetPropertyDriverVersion")} -} - -func (_c *MockDevice_GetPropertyDriverVersion_Call) Run(run func()) *MockDevice_GetPropertyDriverVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyDriverVersion_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyDriverVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyDriverVersion_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyDriverVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFirmwareMissing provides a mock function with no fields -func (_m *MockDevice) GetPropertyFirmwareMissing() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFirmwareMissing") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyFirmwareMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareMissing' -type MockDevice_GetPropertyFirmwareMissing_Call struct { - *mock.Call -} - -// GetPropertyFirmwareMissing is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyFirmwareMissing() *MockDevice_GetPropertyFirmwareMissing_Call { - return &MockDevice_GetPropertyFirmwareMissing_Call{Call: _e.mock.On("GetPropertyFirmwareMissing")} -} - -func (_c *MockDevice_GetPropertyFirmwareMissing_Call) Run(run func()) *MockDevice_GetPropertyFirmwareMissing_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyFirmwareMissing_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyFirmwareMissing_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyFirmwareMissing_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyFirmwareMissing_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFirmwareVersion provides a mock function with no fields -func (_m *MockDevice) GetPropertyFirmwareVersion() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFirmwareVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyFirmwareVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareVersion' -type MockDevice_GetPropertyFirmwareVersion_Call struct { - *mock.Call -} - -// GetPropertyFirmwareVersion is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyFirmwareVersion() *MockDevice_GetPropertyFirmwareVersion_Call { - return &MockDevice_GetPropertyFirmwareVersion_Call{Call: _e.mock.On("GetPropertyFirmwareVersion")} -} - -func (_c *MockDevice_GetPropertyFirmwareVersion_Call) Run(run func()) *MockDevice_GetPropertyFirmwareVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyFirmwareVersion_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyFirmwareVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyFirmwareVersion_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyFirmwareVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP4Config provides a mock function with no fields -func (_m *MockDevice) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP4Config") - } - - var r0 gonetworkmanager.IP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config' -type MockDevice_GetPropertyIP4Config_Call struct { - *mock.Call -} - -// GetPropertyIP4Config is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyIP4Config() *MockDevice_GetPropertyIP4Config_Call { - return &MockDevice_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")} -} - -func (_c *MockDevice_GetPropertyIP4Config_Call) Run(run func()) *MockDevice_GetPropertyIP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockDevice_GetPropertyIP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockDevice_GetPropertyIP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP6Config provides a mock function with no fields -func (_m *MockDevice) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP6Config") - } - - var r0 gonetworkmanager.IP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config' -type MockDevice_GetPropertyIP6Config_Call struct { - *mock.Call -} - -// GetPropertyIP6Config is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyIP6Config() *MockDevice_GetPropertyIP6Config_Call { - return &MockDevice_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")} -} - -func (_c *MockDevice_GetPropertyIP6Config_Call) Run(run func()) *MockDevice_GetPropertyIP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockDevice_GetPropertyIP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockDevice_GetPropertyIP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyInterface provides a mock function with no fields -func (_m *MockDevice) GetPropertyInterface() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyInterface") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyInterface' -type MockDevice_GetPropertyInterface_Call struct { - *mock.Call -} - -// GetPropertyInterface is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyInterface() *MockDevice_GetPropertyInterface_Call { - return &MockDevice_GetPropertyInterface_Call{Call: _e.mock.On("GetPropertyInterface")} -} - -func (_c *MockDevice_GetPropertyInterface_Call) Run(run func()) *MockDevice_GetPropertyInterface_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyInterface_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyInterface_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyInterface_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyInterface_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIp4Connectivity provides a mock function with no fields -func (_m *MockDevice) GetPropertyIp4Connectivity() (gonetworkmanager.NmConnectivity, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIp4Connectivity") - } - - var r0 gonetworkmanager.NmConnectivity - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmConnectivity) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyIp4Connectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIp4Connectivity' -type MockDevice_GetPropertyIp4Connectivity_Call struct { - *mock.Call -} - -// GetPropertyIp4Connectivity is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyIp4Connectivity() *MockDevice_GetPropertyIp4Connectivity_Call { - return &MockDevice_GetPropertyIp4Connectivity_Call{Call: _e.mock.On("GetPropertyIp4Connectivity")} -} - -func (_c *MockDevice_GetPropertyIp4Connectivity_Call) Run(run func()) *MockDevice_GetPropertyIp4Connectivity_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyIp4Connectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockDevice_GetPropertyIp4Connectivity_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyIp4Connectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockDevice_GetPropertyIp4Connectivity_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIpInterface provides a mock function with no fields -func (_m *MockDevice) GetPropertyIpInterface() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIpInterface") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyIpInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIpInterface' -type MockDevice_GetPropertyIpInterface_Call struct { - *mock.Call -} - -// GetPropertyIpInterface is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyIpInterface() *MockDevice_GetPropertyIpInterface_Call { - return &MockDevice_GetPropertyIpInterface_Call{Call: _e.mock.On("GetPropertyIpInterface")} -} - -func (_c *MockDevice_GetPropertyIpInterface_Call) Run(run func()) *MockDevice_GetPropertyIpInterface_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyIpInterface_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyIpInterface_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyIpInterface_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyIpInterface_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyManaged provides a mock function with no fields -func (_m *MockDevice) GetPropertyManaged() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyManaged") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyManaged' -type MockDevice_GetPropertyManaged_Call struct { - *mock.Call -} - -// GetPropertyManaged is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyManaged() *MockDevice_GetPropertyManaged_Call { - return &MockDevice_GetPropertyManaged_Call{Call: _e.mock.On("GetPropertyManaged")} -} - -func (_c *MockDevice_GetPropertyManaged_Call) Run(run func()) *MockDevice_GetPropertyManaged_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyManaged_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyManaged_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyManaged_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyManaged_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMtu provides a mock function with no fields -func (_m *MockDevice) GetPropertyMtu() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMtu") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyMtu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMtu' -type MockDevice_GetPropertyMtu_Call struct { - *mock.Call -} - -// GetPropertyMtu is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyMtu() *MockDevice_GetPropertyMtu_Call { - return &MockDevice_GetPropertyMtu_Call{Call: _e.mock.On("GetPropertyMtu")} -} - -func (_c *MockDevice_GetPropertyMtu_Call) Run(run func()) *MockDevice_GetPropertyMtu_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyMtu_Call) Return(_a0 uint32, _a1 error) *MockDevice_GetPropertyMtu_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyMtu_Call) RunAndReturn(run func() (uint32, error)) *MockDevice_GetPropertyMtu_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyNmPluginMissing provides a mock function with no fields -func (_m *MockDevice) GetPropertyNmPluginMissing() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyNmPluginMissing") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyNmPluginMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNmPluginMissing' -type MockDevice_GetPropertyNmPluginMissing_Call struct { - *mock.Call -} - -// GetPropertyNmPluginMissing is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyNmPluginMissing() *MockDevice_GetPropertyNmPluginMissing_Call { - return &MockDevice_GetPropertyNmPluginMissing_Call{Call: _e.mock.On("GetPropertyNmPluginMissing")} -} - -func (_c *MockDevice_GetPropertyNmPluginMissing_Call) Run(run func()) *MockDevice_GetPropertyNmPluginMissing_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyNmPluginMissing_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyNmPluginMissing_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyNmPluginMissing_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyNmPluginMissing_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyPhysicalPortId provides a mock function with no fields -func (_m *MockDevice) GetPropertyPhysicalPortId() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyPhysicalPortId") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyPhysicalPortId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPhysicalPortId' -type MockDevice_GetPropertyPhysicalPortId_Call struct { - *mock.Call -} - -// GetPropertyPhysicalPortId is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyPhysicalPortId() *MockDevice_GetPropertyPhysicalPortId_Call { - return &MockDevice_GetPropertyPhysicalPortId_Call{Call: _e.mock.On("GetPropertyPhysicalPortId")} -} - -func (_c *MockDevice_GetPropertyPhysicalPortId_Call) Run(run func()) *MockDevice_GetPropertyPhysicalPortId_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyPhysicalPortId_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyPhysicalPortId_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyPhysicalPortId_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyPhysicalPortId_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyReal provides a mock function with no fields -func (_m *MockDevice) GetPropertyReal() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyReal") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyReal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyReal' -type MockDevice_GetPropertyReal_Call struct { - *mock.Call -} - -// GetPropertyReal is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyReal() *MockDevice_GetPropertyReal_Call { - return &MockDevice_GetPropertyReal_Call{Call: _e.mock.On("GetPropertyReal")} -} - -func (_c *MockDevice_GetPropertyReal_Call) Run(run func()) *MockDevice_GetPropertyReal_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyReal_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyReal_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyReal_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyReal_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyState provides a mock function with no fields -func (_m *MockDevice) GetPropertyState() (gonetworkmanager.NmDeviceState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyState") - } - - var r0 gonetworkmanager.NmDeviceState - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceState); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmDeviceState) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState' -type MockDevice_GetPropertyState_Call struct { - *mock.Call -} - -// GetPropertyState is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyState() *MockDevice_GetPropertyState_Call { - return &MockDevice_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")} -} - -func (_c *MockDevice_GetPropertyState_Call) Run(run func()) *MockDevice_GetPropertyState_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmDeviceState, _a1 error) *MockDevice_GetPropertyState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceState, error)) *MockDevice_GetPropertyState_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyUdi provides a mock function with no fields -func (_m *MockDevice) GetPropertyUdi() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyUdi") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_GetPropertyUdi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUdi' -type MockDevice_GetPropertyUdi_Call struct { - *mock.Call -} - -// GetPropertyUdi is a helper method to define mock.On call -func (_e *MockDevice_Expecter) GetPropertyUdi() *MockDevice_GetPropertyUdi_Call { - return &MockDevice_GetPropertyUdi_Call{Call: _e.mock.On("GetPropertyUdi")} -} - -func (_c *MockDevice_GetPropertyUdi_Call) Run(run func()) *MockDevice_GetPropertyUdi_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_GetPropertyUdi_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyUdi_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_GetPropertyUdi_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyUdi_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockDevice) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDevice_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockDevice_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockDevice_Expecter) MarshalJSON() *MockDevice_MarshalJSON_Call { - return &MockDevice_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockDevice_MarshalJSON_Call) Run(run func()) *MockDevice_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDevice_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockDevice_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDevice_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockDevice_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// Reapply provides a mock function with given fields: connection, versionId, flags -func (_m *MockDevice) Reapply(connection gonetworkmanager.Connection, versionId uint64, flags uint32) error { - ret := _m.Called(connection, versionId, flags) - - if len(ret) == 0 { - panic("no return value specified for Reapply") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, uint64, uint32) error); ok { - r0 = rf(connection, versionId, flags) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_Reapply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reapply' -type MockDevice_Reapply_Call struct { - *mock.Call -} - -// Reapply is a helper method to define mock.On call -// - connection gonetworkmanager.Connection -// - versionId uint64 -// - flags uint32 -func (_e *MockDevice_Expecter) Reapply(connection interface{}, versionId interface{}, flags interface{}) *MockDevice_Reapply_Call { - return &MockDevice_Reapply_Call{Call: _e.mock.On("Reapply", connection, versionId, flags)} -} - -func (_c *MockDevice_Reapply_Call) Run(run func(connection gonetworkmanager.Connection, versionId uint64, flags uint32)) *MockDevice_Reapply_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Connection), args[1].(uint64), args[2].(uint32)) - }) - return _c -} - -func (_c *MockDevice_Reapply_Call) Return(_a0 error) *MockDevice_Reapply_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_Reapply_Call) RunAndReturn(run func(gonetworkmanager.Connection, uint64, uint32) error) *MockDevice_Reapply_Call { - _c.Call.Return(run) - return _c -} - -// SetPropertyAutoConnect provides a mock function with given fields: _a0 -func (_m *MockDevice) SetPropertyAutoConnect(_a0 bool) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for SetPropertyAutoConnect") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_SetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyAutoConnect' -type MockDevice_SetPropertyAutoConnect_Call struct { - *mock.Call -} - -// SetPropertyAutoConnect is a helper method to define mock.On call -// - _a0 bool -func (_e *MockDevice_Expecter) SetPropertyAutoConnect(_a0 interface{}) *MockDevice_SetPropertyAutoConnect_Call { - return &MockDevice_SetPropertyAutoConnect_Call{Call: _e.mock.On("SetPropertyAutoConnect", _a0)} -} - -func (_c *MockDevice_SetPropertyAutoConnect_Call) Run(run func(_a0 bool)) *MockDevice_SetPropertyAutoConnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockDevice_SetPropertyAutoConnect_Call) Return(_a0 error) *MockDevice_SetPropertyAutoConnect_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_SetPropertyAutoConnect_Call) RunAndReturn(run func(bool) error) *MockDevice_SetPropertyAutoConnect_Call { - _c.Call.Return(run) - return _c -} - -// SetPropertyManaged provides a mock function with given fields: _a0 -func (_m *MockDevice) SetPropertyManaged(_a0 bool) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for SetPropertyManaged") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_SetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyManaged' -type MockDevice_SetPropertyManaged_Call struct { - *mock.Call -} - -// SetPropertyManaged is a helper method to define mock.On call -// - _a0 bool -func (_e *MockDevice_Expecter) SetPropertyManaged(_a0 interface{}) *MockDevice_SetPropertyManaged_Call { - return &MockDevice_SetPropertyManaged_Call{Call: _e.mock.On("SetPropertyManaged", _a0)} -} - -func (_c *MockDevice_SetPropertyManaged_Call) Run(run func(_a0 bool)) *MockDevice_SetPropertyManaged_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockDevice_SetPropertyManaged_Call) Return(_a0 error) *MockDevice_SetPropertyManaged_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDevice_SetPropertyManaged_Call) RunAndReturn(run func(bool) error) *MockDevice_SetPropertyManaged_Call { - _c.Call.Return(run) - return _c -} - -// SubscribeState provides a mock function with given fields: receiver, exit -func (_m *MockDevice) SubscribeState(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{}) error { - ret := _m.Called(receiver, exit) - - if len(ret) == 0 { - panic("no return value specified for SubscribeState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error); ok { - r0 = rf(receiver, exit) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDevice_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState' -type MockDevice_SubscribeState_Call struct { - *mock.Call -} - -// SubscribeState is a helper method to define mock.On call -// - receiver chan gonetworkmanager.DeviceStateChange -// - exit chan struct{} -func (_e *MockDevice_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockDevice_SubscribeState_Call { - return &MockDevice_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)} -} - -func (_c *MockDevice_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{})) *MockDevice_SubscribeState_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(chan gonetworkmanager.DeviceStateChange), args[1].(chan struct{})) - }) - return _c -} - -func (_c *MockDevice_SubscribeState_Call) Return(err error) *MockDevice_SubscribeState_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockDevice_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error) *MockDevice_SubscribeState_Call { - _c.Call.Return(run) - return _c -} - -// NewMockDevice creates a new instance of MockDevice. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockDevice(t interface { - mock.TestingT - Cleanup(func()) -}) *MockDevice { - mock := &MockDevice{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go deleted file mode 100644 index d2d3f2d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go +++ /dev/null @@ -1,2241 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockDeviceWireless is an autogenerated mock type for the DeviceWireless type -type MockDeviceWireless struct { - mock.Mock -} - -type MockDeviceWireless_Expecter struct { - mock *mock.Mock -} - -func (_m *MockDeviceWireless) EXPECT() *MockDeviceWireless_Expecter { - return &MockDeviceWireless_Expecter{mock: &_m.Mock} -} - -// Delete provides a mock function with no fields -func (_m *MockDeviceWireless) Delete() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Delete") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type MockDeviceWireless_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) Delete() *MockDeviceWireless_Delete_Call { - return &MockDeviceWireless_Delete_Call{Call: _e.mock.On("Delete")} -} - -func (_c *MockDeviceWireless_Delete_Call) Run(run func()) *MockDeviceWireless_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_Delete_Call) Return(_a0 error) *MockDeviceWireless_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_Delete_Call) RunAndReturn(run func() error) *MockDeviceWireless_Delete_Call { - _c.Call.Return(run) - return _c -} - -// Disconnect provides a mock function with no fields -func (_m *MockDeviceWireless) Disconnect() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Disconnect") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_Disconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Disconnect' -type MockDeviceWireless_Disconnect_Call struct { - *mock.Call -} - -// Disconnect is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) Disconnect() *MockDeviceWireless_Disconnect_Call { - return &MockDeviceWireless_Disconnect_Call{Call: _e.mock.On("Disconnect")} -} - -func (_c *MockDeviceWireless_Disconnect_Call) Run(run func()) *MockDeviceWireless_Disconnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_Disconnect_Call) Return(_a0 error) *MockDeviceWireless_Disconnect_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_Disconnect_Call) RunAndReturn(run func() error) *MockDeviceWireless_Disconnect_Call { - _c.Call.Return(run) - return _c -} - -// GetAccessPoints provides a mock function with no fields -func (_m *MockDeviceWireless) GetAccessPoints() ([]gonetworkmanager.AccessPoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetAccessPoints") - } - - var r0 []gonetworkmanager.AccessPoint - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.AccessPoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAccessPoints' -type MockDeviceWireless_GetAccessPoints_Call struct { - *mock.Call -} - -// GetAccessPoints is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetAccessPoints() *MockDeviceWireless_GetAccessPoints_Call { - return &MockDeviceWireless_GetAccessPoints_Call{Call: _e.mock.On("GetAccessPoints")} -} - -func (_c *MockDeviceWireless_GetAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetAccessPoints_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetAccessPoints_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetAccessPoints_Call { - _c.Call.Return(run) - return _c -} - -// GetAllAccessPoints provides a mock function with no fields -func (_m *MockDeviceWireless) GetAllAccessPoints() ([]gonetworkmanager.AccessPoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetAllAccessPoints") - } - - var r0 []gonetworkmanager.AccessPoint - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.AccessPoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetAllAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllAccessPoints' -type MockDeviceWireless_GetAllAccessPoints_Call struct { - *mock.Call -} - -// GetAllAccessPoints is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetAllAccessPoints() *MockDeviceWireless_GetAllAccessPoints_Call { - return &MockDeviceWireless_GetAllAccessPoints_Call{Call: _e.mock.On("GetAllAccessPoints")} -} - -func (_c *MockDeviceWireless_GetAllAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetAllAccessPoints_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetAllAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetAllAccessPoints_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetAllAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetAllAccessPoints_Call { - _c.Call.Return(run) - return _c -} - -// GetPath provides a mock function with no fields -func (_m *MockDeviceWireless) GetPath() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPath") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockDeviceWireless_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath' -type MockDeviceWireless_GetPath_Call struct { - *mock.Call -} - -// GetPath is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPath() *MockDeviceWireless_GetPath_Call { - return &MockDeviceWireless_GetPath_Call{Call: _e.mock.On("GetPath")} -} - -func (_c *MockDeviceWireless_GetPath_Call) Run(run func()) *MockDeviceWireless_GetPath_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockDeviceWireless_GetPath_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockDeviceWireless_GetPath_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAccessPoints provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyAccessPoints() ([]gonetworkmanager.AccessPoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAccessPoints") - } - - var r0 []gonetworkmanager.AccessPoint - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.AccessPoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAccessPoints' -type MockDeviceWireless_GetPropertyAccessPoints_Call struct { - *mock.Call -} - -// GetPropertyAccessPoints is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyAccessPoints() *MockDeviceWireless_GetPropertyAccessPoints_Call { - return &MockDeviceWireless_GetPropertyAccessPoints_Call{Call: _e.mock.On("GetPropertyAccessPoints")} -} - -func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetPropertyAccessPoints_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetPropertyAccessPoints_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetPropertyAccessPoints_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyActiveAccessPoint provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyActiveAccessPoint() (gonetworkmanager.AccessPoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyActiveAccessPoint") - } - - var r0 gonetworkmanager.AccessPoint - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.AccessPoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.AccessPoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.AccessPoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyActiveAccessPoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveAccessPoint' -type MockDeviceWireless_GetPropertyActiveAccessPoint_Call struct { - *mock.Call -} - -// GetPropertyActiveAccessPoint is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyActiveAccessPoint() *MockDeviceWireless_GetPropertyActiveAccessPoint_Call { - return &MockDeviceWireless_GetPropertyActiveAccessPoint_Call{Call: _e.mock.On("GetPropertyActiveAccessPoint")} -} - -func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) Run(run func()) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) Return(_a0 gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) RunAndReturn(run func() (gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyActiveConnection provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyActiveConnection() (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyActiveConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyActiveConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnection' -type MockDeviceWireless_GetPropertyActiveConnection_Call struct { - *mock.Call -} - -// GetPropertyActiveConnection is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyActiveConnection() *MockDeviceWireless_GetPropertyActiveConnection_Call { - return &MockDeviceWireless_GetPropertyActiveConnection_Call{Call: _e.mock.On("GetPropertyActiveConnection")} -} - -func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) Run(run func()) *MockDeviceWireless_GetPropertyActiveConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockDeviceWireless_GetPropertyActiveConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockDeviceWireless_GetPropertyActiveConnection_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAutoConnect provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyAutoConnect() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAutoConnect") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAutoConnect' -type MockDeviceWireless_GetPropertyAutoConnect_Call struct { - *mock.Call -} - -// GetPropertyAutoConnect is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyAutoConnect() *MockDeviceWireless_GetPropertyAutoConnect_Call { - return &MockDeviceWireless_GetPropertyAutoConnect_Call{Call: _e.mock.On("GetPropertyAutoConnect")} -} - -func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) Run(run func()) *MockDeviceWireless_GetPropertyAutoConnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyAutoConnect_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyAutoConnect_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAvailableConnections provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyAvailableConnections() ([]gonetworkmanager.Connection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAvailableConnections") - } - - var r0 []gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyAvailableConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAvailableConnections' -type MockDeviceWireless_GetPropertyAvailableConnections_Call struct { - *mock.Call -} - -// GetPropertyAvailableConnections is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyAvailableConnections() *MockDeviceWireless_GetPropertyAvailableConnections_Call { - return &MockDeviceWireless_GetPropertyAvailableConnections_Call{Call: _e.mock.On("GetPropertyAvailableConnections")} -} - -func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) Run(run func()) *MockDeviceWireless_GetPropertyAvailableConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockDeviceWireless_GetPropertyAvailableConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockDeviceWireless_GetPropertyAvailableConnections_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyBitrate provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyBitrate() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyBitrate") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyBitrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyBitrate' -type MockDeviceWireless_GetPropertyBitrate_Call struct { - *mock.Call -} - -// GetPropertyBitrate is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyBitrate() *MockDeviceWireless_GetPropertyBitrate_Call { - return &MockDeviceWireless_GetPropertyBitrate_Call{Call: _e.mock.On("GetPropertyBitrate")} -} - -func (_c *MockDeviceWireless_GetPropertyBitrate_Call) Run(run func()) *MockDeviceWireless_GetPropertyBitrate_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyBitrate_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyBitrate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyBitrate_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyBitrate_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP4Config provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP4Config") - } - - var r0 gonetworkmanager.DHCP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config' -type MockDeviceWireless_GetPropertyDHCP4Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP4Config is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyDHCP4Config() *MockDeviceWireless_GetPropertyDHCP4Config_Call { - return &MockDeviceWireless_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")} -} - -func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyDHCP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockDeviceWireless_GetPropertyDHCP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockDeviceWireless_GetPropertyDHCP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDHCP6Config provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDHCP6Config") - } - - var r0 gonetworkmanager.DHCP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.DHCP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config' -type MockDeviceWireless_GetPropertyDHCP6Config_Call struct { - *mock.Call -} - -// GetPropertyDHCP6Config is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyDHCP6Config() *MockDeviceWireless_GetPropertyDHCP6Config_Call { - return &MockDeviceWireless_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")} -} - -func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyDHCP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockDeviceWireless_GetPropertyDHCP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockDeviceWireless_GetPropertyDHCP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDeviceType provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyDeviceType() (gonetworkmanager.NmDeviceType, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDeviceType") - } - - var r0 gonetworkmanager.NmDeviceType - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceType, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceType); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmDeviceType) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyDeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDeviceType' -type MockDeviceWireless_GetPropertyDeviceType_Call struct { - *mock.Call -} - -// GetPropertyDeviceType is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyDeviceType() *MockDeviceWireless_GetPropertyDeviceType_Call { - return &MockDeviceWireless_GetPropertyDeviceType_Call{Call: _e.mock.On("GetPropertyDeviceType")} -} - -func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) Run(run func()) *MockDeviceWireless_GetPropertyDeviceType_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) Return(_a0 gonetworkmanager.NmDeviceType, _a1 error) *MockDeviceWireless_GetPropertyDeviceType_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceType, error)) *MockDeviceWireless_GetPropertyDeviceType_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDriver provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyDriver() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDriver") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyDriver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriver' -type MockDeviceWireless_GetPropertyDriver_Call struct { - *mock.Call -} - -// GetPropertyDriver is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyDriver() *MockDeviceWireless_GetPropertyDriver_Call { - return &MockDeviceWireless_GetPropertyDriver_Call{Call: _e.mock.On("GetPropertyDriver")} -} - -func (_c *MockDeviceWireless_GetPropertyDriver_Call) Run(run func()) *MockDeviceWireless_GetPropertyDriver_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDriver_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyDriver_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDriver_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyDriver_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDriverVersion provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyDriverVersion() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDriverVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyDriverVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriverVersion' -type MockDeviceWireless_GetPropertyDriverVersion_Call struct { - *mock.Call -} - -// GetPropertyDriverVersion is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyDriverVersion() *MockDeviceWireless_GetPropertyDriverVersion_Call { - return &MockDeviceWireless_GetPropertyDriverVersion_Call{Call: _e.mock.On("GetPropertyDriverVersion")} -} - -func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) Run(run func()) *MockDeviceWireless_GetPropertyDriverVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyDriverVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyDriverVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFirmwareMissing provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyFirmwareMissing() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFirmwareMissing") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyFirmwareMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareMissing' -type MockDeviceWireless_GetPropertyFirmwareMissing_Call struct { - *mock.Call -} - -// GetPropertyFirmwareMissing is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyFirmwareMissing() *MockDeviceWireless_GetPropertyFirmwareMissing_Call { - return &MockDeviceWireless_GetPropertyFirmwareMissing_Call{Call: _e.mock.On("GetPropertyFirmwareMissing")} -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) Run(run func()) *MockDeviceWireless_GetPropertyFirmwareMissing_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyFirmwareMissing_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyFirmwareMissing_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyFirmwareVersion provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyFirmwareVersion() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyFirmwareVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyFirmwareVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareVersion' -type MockDeviceWireless_GetPropertyFirmwareVersion_Call struct { - *mock.Call -} - -// GetPropertyFirmwareVersion is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyFirmwareVersion() *MockDeviceWireless_GetPropertyFirmwareVersion_Call { - return &MockDeviceWireless_GetPropertyFirmwareVersion_Call{Call: _e.mock.On("GetPropertyFirmwareVersion")} -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) Run(run func()) *MockDeviceWireless_GetPropertyFirmwareVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyFirmwareVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyFirmwareVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyHwAddress provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyHwAddress() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyHwAddress") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyHwAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHwAddress' -type MockDeviceWireless_GetPropertyHwAddress_Call struct { - *mock.Call -} - -// GetPropertyHwAddress is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyHwAddress() *MockDeviceWireless_GetPropertyHwAddress_Call { - return &MockDeviceWireless_GetPropertyHwAddress_Call{Call: _e.mock.On("GetPropertyHwAddress")} -} - -func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) Run(run func()) *MockDeviceWireless_GetPropertyHwAddress_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyHwAddress_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyHwAddress_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP4Config provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP4Config") - } - - var r0 gonetworkmanager.IP4Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP4Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config' -type MockDeviceWireless_GetPropertyIP4Config_Call struct { - *mock.Call -} - -// GetPropertyIP4Config is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyIP4Config() *MockDeviceWireless_GetPropertyIP4Config_Call { - return &MockDeviceWireless_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")} -} - -func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyIP4Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockDeviceWireless_GetPropertyIP4Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockDeviceWireless_GetPropertyIP4Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIP6Config provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIP6Config") - } - - var r0 gonetworkmanager.IP6Config - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.IP6Config) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config' -type MockDeviceWireless_GetPropertyIP6Config_Call struct { - *mock.Call -} - -// GetPropertyIP6Config is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyIP6Config() *MockDeviceWireless_GetPropertyIP6Config_Call { - return &MockDeviceWireless_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")} -} - -func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyIP6Config_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockDeviceWireless_GetPropertyIP6Config_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockDeviceWireless_GetPropertyIP6Config_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyInterface provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyInterface() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyInterface") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyInterface' -type MockDeviceWireless_GetPropertyInterface_Call struct { - *mock.Call -} - -// GetPropertyInterface is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyInterface() *MockDeviceWireless_GetPropertyInterface_Call { - return &MockDeviceWireless_GetPropertyInterface_Call{Call: _e.mock.On("GetPropertyInterface")} -} - -func (_c *MockDeviceWireless_GetPropertyInterface_Call) Run(run func()) *MockDeviceWireless_GetPropertyInterface_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyInterface_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyInterface_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyInterface_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyInterface_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIp4Connectivity provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyIp4Connectivity() (gonetworkmanager.NmConnectivity, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIp4Connectivity") - } - - var r0 gonetworkmanager.NmConnectivity - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmConnectivity) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyIp4Connectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIp4Connectivity' -type MockDeviceWireless_GetPropertyIp4Connectivity_Call struct { - *mock.Call -} - -// GetPropertyIp4Connectivity is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyIp4Connectivity() *MockDeviceWireless_GetPropertyIp4Connectivity_Call { - return &MockDeviceWireless_GetPropertyIp4Connectivity_Call{Call: _e.mock.On("GetPropertyIp4Connectivity")} -} - -func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) Run(run func()) *MockDeviceWireless_GetPropertyIp4Connectivity_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockDeviceWireless_GetPropertyIp4Connectivity_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockDeviceWireless_GetPropertyIp4Connectivity_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyIpInterface provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyIpInterface() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyIpInterface") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyIpInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIpInterface' -type MockDeviceWireless_GetPropertyIpInterface_Call struct { - *mock.Call -} - -// GetPropertyIpInterface is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyIpInterface() *MockDeviceWireless_GetPropertyIpInterface_Call { - return &MockDeviceWireless_GetPropertyIpInterface_Call{Call: _e.mock.On("GetPropertyIpInterface")} -} - -func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) Run(run func()) *MockDeviceWireless_GetPropertyIpInterface_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyIpInterface_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyIpInterface_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyLastScan provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyLastScan() (int64, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyLastScan") - } - - var r0 int64 - var r1 error - if rf, ok := ret.Get(0).(func() (int64, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() int64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(int64) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyLastScan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyLastScan' -type MockDeviceWireless_GetPropertyLastScan_Call struct { - *mock.Call -} - -// GetPropertyLastScan is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyLastScan() *MockDeviceWireless_GetPropertyLastScan_Call { - return &MockDeviceWireless_GetPropertyLastScan_Call{Call: _e.mock.On("GetPropertyLastScan")} -} - -func (_c *MockDeviceWireless_GetPropertyLastScan_Call) Run(run func()) *MockDeviceWireless_GetPropertyLastScan_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyLastScan_Call) Return(_a0 int64, _a1 error) *MockDeviceWireless_GetPropertyLastScan_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyLastScan_Call) RunAndReturn(run func() (int64, error)) *MockDeviceWireless_GetPropertyLastScan_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyManaged provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyManaged() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyManaged") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyManaged' -type MockDeviceWireless_GetPropertyManaged_Call struct { - *mock.Call -} - -// GetPropertyManaged is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyManaged() *MockDeviceWireless_GetPropertyManaged_Call { - return &MockDeviceWireless_GetPropertyManaged_Call{Call: _e.mock.On("GetPropertyManaged")} -} - -func (_c *MockDeviceWireless_GetPropertyManaged_Call) Run(run func()) *MockDeviceWireless_GetPropertyManaged_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyManaged_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyManaged_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyManaged_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyManaged_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMode provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyMode() (gonetworkmanager.Nm80211Mode, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMode") - } - - var r0 gonetworkmanager.Nm80211Mode - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.Nm80211Mode, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.Nm80211Mode); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.Nm80211Mode) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMode' -type MockDeviceWireless_GetPropertyMode_Call struct { - *mock.Call -} - -// GetPropertyMode is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyMode() *MockDeviceWireless_GetPropertyMode_Call { - return &MockDeviceWireless_GetPropertyMode_Call{Call: _e.mock.On("GetPropertyMode")} -} - -func (_c *MockDeviceWireless_GetPropertyMode_Call) Run(run func()) *MockDeviceWireless_GetPropertyMode_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyMode_Call) Return(_a0 gonetworkmanager.Nm80211Mode, _a1 error) *MockDeviceWireless_GetPropertyMode_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyMode_Call) RunAndReturn(run func() (gonetworkmanager.Nm80211Mode, error)) *MockDeviceWireless_GetPropertyMode_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMtu provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyMtu() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMtu") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyMtu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMtu' -type MockDeviceWireless_GetPropertyMtu_Call struct { - *mock.Call -} - -// GetPropertyMtu is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyMtu() *MockDeviceWireless_GetPropertyMtu_Call { - return &MockDeviceWireless_GetPropertyMtu_Call{Call: _e.mock.On("GetPropertyMtu")} -} - -func (_c *MockDeviceWireless_GetPropertyMtu_Call) Run(run func()) *MockDeviceWireless_GetPropertyMtu_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyMtu_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyMtu_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyMtu_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyMtu_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyNmPluginMissing provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyNmPluginMissing() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyNmPluginMissing") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyNmPluginMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNmPluginMissing' -type MockDeviceWireless_GetPropertyNmPluginMissing_Call struct { - *mock.Call -} - -// GetPropertyNmPluginMissing is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyNmPluginMissing() *MockDeviceWireless_GetPropertyNmPluginMissing_Call { - return &MockDeviceWireless_GetPropertyNmPluginMissing_Call{Call: _e.mock.On("GetPropertyNmPluginMissing")} -} - -func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) Run(run func()) *MockDeviceWireless_GetPropertyNmPluginMissing_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyNmPluginMissing_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyNmPluginMissing_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyPermHwAddress provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyPermHwAddress() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyPermHwAddress") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyPermHwAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPermHwAddress' -type MockDeviceWireless_GetPropertyPermHwAddress_Call struct { - *mock.Call -} - -// GetPropertyPermHwAddress is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyPermHwAddress() *MockDeviceWireless_GetPropertyPermHwAddress_Call { - return &MockDeviceWireless_GetPropertyPermHwAddress_Call{Call: _e.mock.On("GetPropertyPermHwAddress")} -} - -func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) Run(run func()) *MockDeviceWireless_GetPropertyPermHwAddress_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyPermHwAddress_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyPermHwAddress_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyPhysicalPortId provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyPhysicalPortId() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyPhysicalPortId") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyPhysicalPortId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPhysicalPortId' -type MockDeviceWireless_GetPropertyPhysicalPortId_Call struct { - *mock.Call -} - -// GetPropertyPhysicalPortId is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyPhysicalPortId() *MockDeviceWireless_GetPropertyPhysicalPortId_Call { - return &MockDeviceWireless_GetPropertyPhysicalPortId_Call{Call: _e.mock.On("GetPropertyPhysicalPortId")} -} - -func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) Run(run func()) *MockDeviceWireless_GetPropertyPhysicalPortId_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyPhysicalPortId_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyPhysicalPortId_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyReal provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyReal() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyReal") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyReal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyReal' -type MockDeviceWireless_GetPropertyReal_Call struct { - *mock.Call -} - -// GetPropertyReal is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyReal() *MockDeviceWireless_GetPropertyReal_Call { - return &MockDeviceWireless_GetPropertyReal_Call{Call: _e.mock.On("GetPropertyReal")} -} - -func (_c *MockDeviceWireless_GetPropertyReal_Call) Run(run func()) *MockDeviceWireless_GetPropertyReal_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyReal_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyReal_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyReal_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyReal_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyState provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyState() (gonetworkmanager.NmDeviceState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyState") - } - - var r0 gonetworkmanager.NmDeviceState - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceState); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmDeviceState) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState' -type MockDeviceWireless_GetPropertyState_Call struct { - *mock.Call -} - -// GetPropertyState is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyState() *MockDeviceWireless_GetPropertyState_Call { - return &MockDeviceWireless_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")} -} - -func (_c *MockDeviceWireless_GetPropertyState_Call) Run(run func()) *MockDeviceWireless_GetPropertyState_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmDeviceState, _a1 error) *MockDeviceWireless_GetPropertyState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceState, error)) *MockDeviceWireless_GetPropertyState_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyUdi provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyUdi() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyUdi") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyUdi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUdi' -type MockDeviceWireless_GetPropertyUdi_Call struct { - *mock.Call -} - -// GetPropertyUdi is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyUdi() *MockDeviceWireless_GetPropertyUdi_Call { - return &MockDeviceWireless_GetPropertyUdi_Call{Call: _e.mock.On("GetPropertyUdi")} -} - -func (_c *MockDeviceWireless_GetPropertyUdi_Call) Run(run func()) *MockDeviceWireless_GetPropertyUdi_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyUdi_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyUdi_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyUdi_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyUdi_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWirelessCapabilities provides a mock function with no fields -func (_m *MockDeviceWireless) GetPropertyWirelessCapabilities() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWirelessCapabilities") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_GetPropertyWirelessCapabilities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessCapabilities' -type MockDeviceWireless_GetPropertyWirelessCapabilities_Call struct { - *mock.Call -} - -// GetPropertyWirelessCapabilities is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) GetPropertyWirelessCapabilities() *MockDeviceWireless_GetPropertyWirelessCapabilities_Call { - return &MockDeviceWireless_GetPropertyWirelessCapabilities_Call{Call: _e.mock.On("GetPropertyWirelessCapabilities")} -} - -func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) Run(run func()) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockDeviceWireless) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockDeviceWireless_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockDeviceWireless_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) MarshalJSON() *MockDeviceWireless_MarshalJSON_Call { - return &MockDeviceWireless_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockDeviceWireless_MarshalJSON_Call) Run(run func()) *MockDeviceWireless_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockDeviceWireless_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockDeviceWireless_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockDeviceWireless_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// Reapply provides a mock function with given fields: connection, versionId, flags -func (_m *MockDeviceWireless) Reapply(connection gonetworkmanager.Connection, versionId uint64, flags uint32) error { - ret := _m.Called(connection, versionId, flags) - - if len(ret) == 0 { - panic("no return value specified for Reapply") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, uint64, uint32) error); ok { - r0 = rf(connection, versionId, flags) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_Reapply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reapply' -type MockDeviceWireless_Reapply_Call struct { - *mock.Call -} - -// Reapply is a helper method to define mock.On call -// - connection gonetworkmanager.Connection -// - versionId uint64 -// - flags uint32 -func (_e *MockDeviceWireless_Expecter) Reapply(connection interface{}, versionId interface{}, flags interface{}) *MockDeviceWireless_Reapply_Call { - return &MockDeviceWireless_Reapply_Call{Call: _e.mock.On("Reapply", connection, versionId, flags)} -} - -func (_c *MockDeviceWireless_Reapply_Call) Run(run func(connection gonetworkmanager.Connection, versionId uint64, flags uint32)) *MockDeviceWireless_Reapply_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Connection), args[1].(uint64), args[2].(uint32)) - }) - return _c -} - -func (_c *MockDeviceWireless_Reapply_Call) Return(_a0 error) *MockDeviceWireless_Reapply_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_Reapply_Call) RunAndReturn(run func(gonetworkmanager.Connection, uint64, uint32) error) *MockDeviceWireless_Reapply_Call { - _c.Call.Return(run) - return _c -} - -// RequestScan provides a mock function with no fields -func (_m *MockDeviceWireless) RequestScan() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for RequestScan") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_RequestScan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestScan' -type MockDeviceWireless_RequestScan_Call struct { - *mock.Call -} - -// RequestScan is a helper method to define mock.On call -func (_e *MockDeviceWireless_Expecter) RequestScan() *MockDeviceWireless_RequestScan_Call { - return &MockDeviceWireless_RequestScan_Call{Call: _e.mock.On("RequestScan")} -} - -func (_c *MockDeviceWireless_RequestScan_Call) Run(run func()) *MockDeviceWireless_RequestScan_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockDeviceWireless_RequestScan_Call) Return(_a0 error) *MockDeviceWireless_RequestScan_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_RequestScan_Call) RunAndReturn(run func() error) *MockDeviceWireless_RequestScan_Call { - _c.Call.Return(run) - return _c -} - -// SetPropertyAutoConnect provides a mock function with given fields: _a0 -func (_m *MockDeviceWireless) SetPropertyAutoConnect(_a0 bool) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for SetPropertyAutoConnect") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_SetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyAutoConnect' -type MockDeviceWireless_SetPropertyAutoConnect_Call struct { - *mock.Call -} - -// SetPropertyAutoConnect is a helper method to define mock.On call -// - _a0 bool -func (_e *MockDeviceWireless_Expecter) SetPropertyAutoConnect(_a0 interface{}) *MockDeviceWireless_SetPropertyAutoConnect_Call { - return &MockDeviceWireless_SetPropertyAutoConnect_Call{Call: _e.mock.On("SetPropertyAutoConnect", _a0)} -} - -func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) Run(run func(_a0 bool)) *MockDeviceWireless_SetPropertyAutoConnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) Return(_a0 error) *MockDeviceWireless_SetPropertyAutoConnect_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) RunAndReturn(run func(bool) error) *MockDeviceWireless_SetPropertyAutoConnect_Call { - _c.Call.Return(run) - return _c -} - -// SetPropertyManaged provides a mock function with given fields: _a0 -func (_m *MockDeviceWireless) SetPropertyManaged(_a0 bool) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for SetPropertyManaged") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_SetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyManaged' -type MockDeviceWireless_SetPropertyManaged_Call struct { - *mock.Call -} - -// SetPropertyManaged is a helper method to define mock.On call -// - _a0 bool -func (_e *MockDeviceWireless_Expecter) SetPropertyManaged(_a0 interface{}) *MockDeviceWireless_SetPropertyManaged_Call { - return &MockDeviceWireless_SetPropertyManaged_Call{Call: _e.mock.On("SetPropertyManaged", _a0)} -} - -func (_c *MockDeviceWireless_SetPropertyManaged_Call) Run(run func(_a0 bool)) *MockDeviceWireless_SetPropertyManaged_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockDeviceWireless_SetPropertyManaged_Call) Return(_a0 error) *MockDeviceWireless_SetPropertyManaged_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockDeviceWireless_SetPropertyManaged_Call) RunAndReturn(run func(bool) error) *MockDeviceWireless_SetPropertyManaged_Call { - _c.Call.Return(run) - return _c -} - -// SubscribeState provides a mock function with given fields: receiver, exit -func (_m *MockDeviceWireless) SubscribeState(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{}) error { - ret := _m.Called(receiver, exit) - - if len(ret) == 0 { - panic("no return value specified for SubscribeState") - } - - var r0 error - if rf, ok := ret.Get(0).(func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error); ok { - r0 = rf(receiver, exit) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockDeviceWireless_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState' -type MockDeviceWireless_SubscribeState_Call struct { - *mock.Call -} - -// SubscribeState is a helper method to define mock.On call -// - receiver chan gonetworkmanager.DeviceStateChange -// - exit chan struct{} -func (_e *MockDeviceWireless_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockDeviceWireless_SubscribeState_Call { - return &MockDeviceWireless_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)} -} - -func (_c *MockDeviceWireless_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{})) *MockDeviceWireless_SubscribeState_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(chan gonetworkmanager.DeviceStateChange), args[1].(chan struct{})) - }) - return _c -} - -func (_c *MockDeviceWireless_SubscribeState_Call) Return(err error) *MockDeviceWireless_SubscribeState_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockDeviceWireless_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error) *MockDeviceWireless_SubscribeState_Call { - _c.Call.Return(run) - return _c -} - -// NewMockDeviceWireless creates a new instance of MockDeviceWireless. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockDeviceWireless(t interface { - mock.TestingT - Cleanup(func()) -}) *MockDeviceWireless { - mock := &MockDeviceWireless{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go deleted file mode 100644 index 235be86..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go +++ /dev/null @@ -1,772 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - mock "github.com/stretchr/testify/mock" -) - -// MockIP4Config is an autogenerated mock type for the IP4Config type -type MockIP4Config struct { - mock.Mock -} - -type MockIP4Config_Expecter struct { - mock *mock.Mock -} - -func (_m *MockIP4Config) EXPECT() *MockIP4Config_Expecter { - return &MockIP4Config_Expecter{mock: &_m.Mock} -} - -// GetPropertyAddressData provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyAddressData() ([]gonetworkmanager.IP4AddressData, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAddressData") - } - - var r0 []gonetworkmanager.IP4AddressData - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4AddressData, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4AddressData); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.IP4AddressData) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyAddressData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAddressData' -type MockIP4Config_GetPropertyAddressData_Call struct { - *mock.Call -} - -// GetPropertyAddressData is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyAddressData() *MockIP4Config_GetPropertyAddressData_Call { - return &MockIP4Config_GetPropertyAddressData_Call{Call: _e.mock.On("GetPropertyAddressData")} -} - -func (_c *MockIP4Config_GetPropertyAddressData_Call) Run(run func()) *MockIP4Config_GetPropertyAddressData_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyAddressData_Call) Return(_a0 []gonetworkmanager.IP4AddressData, _a1 error) *MockIP4Config_GetPropertyAddressData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyAddressData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4AddressData, error)) *MockIP4Config_GetPropertyAddressData_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAddresses provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyAddresses() ([]gonetworkmanager.IP4Address, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAddresses") - } - - var r0 []gonetworkmanager.IP4Address - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4Address, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4Address); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.IP4Address) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyAddresses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAddresses' -type MockIP4Config_GetPropertyAddresses_Call struct { - *mock.Call -} - -// GetPropertyAddresses is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyAddresses() *MockIP4Config_GetPropertyAddresses_Call { - return &MockIP4Config_GetPropertyAddresses_Call{Call: _e.mock.On("GetPropertyAddresses")} -} - -func (_c *MockIP4Config_GetPropertyAddresses_Call) Run(run func()) *MockIP4Config_GetPropertyAddresses_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyAddresses_Call) Return(_a0 []gonetworkmanager.IP4Address, _a1 error) *MockIP4Config_GetPropertyAddresses_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyAddresses_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4Address, error)) *MockIP4Config_GetPropertyAddresses_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDnsOptions provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyDnsOptions() ([]string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDnsOptions") - } - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func() ([]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyDnsOptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDnsOptions' -type MockIP4Config_GetPropertyDnsOptions_Call struct { - *mock.Call -} - -// GetPropertyDnsOptions is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyDnsOptions() *MockIP4Config_GetPropertyDnsOptions_Call { - return &MockIP4Config_GetPropertyDnsOptions_Call{Call: _e.mock.On("GetPropertyDnsOptions")} -} - -func (_c *MockIP4Config_GetPropertyDnsOptions_Call) Run(run func()) *MockIP4Config_GetPropertyDnsOptions_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyDnsOptions_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyDnsOptions_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyDnsOptions_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyDnsOptions_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDnsPriority provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyDnsPriority() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDnsPriority") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyDnsPriority_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDnsPriority' -type MockIP4Config_GetPropertyDnsPriority_Call struct { - *mock.Call -} - -// GetPropertyDnsPriority is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyDnsPriority() *MockIP4Config_GetPropertyDnsPriority_Call { - return &MockIP4Config_GetPropertyDnsPriority_Call{Call: _e.mock.On("GetPropertyDnsPriority")} -} - -func (_c *MockIP4Config_GetPropertyDnsPriority_Call) Run(run func()) *MockIP4Config_GetPropertyDnsPriority_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyDnsPriority_Call) Return(_a0 uint32, _a1 error) *MockIP4Config_GetPropertyDnsPriority_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyDnsPriority_Call) RunAndReturn(run func() (uint32, error)) *MockIP4Config_GetPropertyDnsPriority_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDomains provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyDomains() ([]string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDomains") - } - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func() ([]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyDomains_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDomains' -type MockIP4Config_GetPropertyDomains_Call struct { - *mock.Call -} - -// GetPropertyDomains is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyDomains() *MockIP4Config_GetPropertyDomains_Call { - return &MockIP4Config_GetPropertyDomains_Call{Call: _e.mock.On("GetPropertyDomains")} -} - -func (_c *MockIP4Config_GetPropertyDomains_Call) Run(run func()) *MockIP4Config_GetPropertyDomains_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyDomains_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyDomains_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyDomains_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyDomains_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyGateway provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyGateway() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyGateway") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyGateway_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyGateway' -type MockIP4Config_GetPropertyGateway_Call struct { - *mock.Call -} - -// GetPropertyGateway is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyGateway() *MockIP4Config_GetPropertyGateway_Call { - return &MockIP4Config_GetPropertyGateway_Call{Call: _e.mock.On("GetPropertyGateway")} -} - -func (_c *MockIP4Config_GetPropertyGateway_Call) Run(run func()) *MockIP4Config_GetPropertyGateway_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyGateway_Call) Return(_a0 string, _a1 error) *MockIP4Config_GetPropertyGateway_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyGateway_Call) RunAndReturn(run func() (string, error)) *MockIP4Config_GetPropertyGateway_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyNameserverData provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyNameserverData() ([]gonetworkmanager.IP4NameserverData, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyNameserverData") - } - - var r0 []gonetworkmanager.IP4NameserverData - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4NameserverData, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4NameserverData); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.IP4NameserverData) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyNameserverData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNameserverData' -type MockIP4Config_GetPropertyNameserverData_Call struct { - *mock.Call -} - -// GetPropertyNameserverData is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyNameserverData() *MockIP4Config_GetPropertyNameserverData_Call { - return &MockIP4Config_GetPropertyNameserverData_Call{Call: _e.mock.On("GetPropertyNameserverData")} -} - -func (_c *MockIP4Config_GetPropertyNameserverData_Call) Run(run func()) *MockIP4Config_GetPropertyNameserverData_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyNameserverData_Call) Return(_a0 []gonetworkmanager.IP4NameserverData, _a1 error) *MockIP4Config_GetPropertyNameserverData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyNameserverData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4NameserverData, error)) *MockIP4Config_GetPropertyNameserverData_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyNameservers provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyNameservers() ([]string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyNameservers") - } - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func() ([]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyNameservers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNameservers' -type MockIP4Config_GetPropertyNameservers_Call struct { - *mock.Call -} - -// GetPropertyNameservers is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyNameservers() *MockIP4Config_GetPropertyNameservers_Call { - return &MockIP4Config_GetPropertyNameservers_Call{Call: _e.mock.On("GetPropertyNameservers")} -} - -func (_c *MockIP4Config_GetPropertyNameservers_Call) Run(run func()) *MockIP4Config_GetPropertyNameservers_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyNameservers_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyNameservers_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyNameservers_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyNameservers_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyRouteData provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyRouteData() ([]gonetworkmanager.IP4RouteData, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyRouteData") - } - - var r0 []gonetworkmanager.IP4RouteData - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4RouteData, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4RouteData); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.IP4RouteData) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyRouteData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRouteData' -type MockIP4Config_GetPropertyRouteData_Call struct { - *mock.Call -} - -// GetPropertyRouteData is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyRouteData() *MockIP4Config_GetPropertyRouteData_Call { - return &MockIP4Config_GetPropertyRouteData_Call{Call: _e.mock.On("GetPropertyRouteData")} -} - -func (_c *MockIP4Config_GetPropertyRouteData_Call) Run(run func()) *MockIP4Config_GetPropertyRouteData_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyRouteData_Call) Return(_a0 []gonetworkmanager.IP4RouteData, _a1 error) *MockIP4Config_GetPropertyRouteData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyRouteData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4RouteData, error)) *MockIP4Config_GetPropertyRouteData_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyRoutes provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyRoutes() ([]gonetworkmanager.IP4Route, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyRoutes") - } - - var r0 []gonetworkmanager.IP4Route - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4Route, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4Route); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.IP4Route) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyRoutes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRoutes' -type MockIP4Config_GetPropertyRoutes_Call struct { - *mock.Call -} - -// GetPropertyRoutes is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyRoutes() *MockIP4Config_GetPropertyRoutes_Call { - return &MockIP4Config_GetPropertyRoutes_Call{Call: _e.mock.On("GetPropertyRoutes")} -} - -func (_c *MockIP4Config_GetPropertyRoutes_Call) Run(run func()) *MockIP4Config_GetPropertyRoutes_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyRoutes_Call) Return(_a0 []gonetworkmanager.IP4Route, _a1 error) *MockIP4Config_GetPropertyRoutes_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyRoutes_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4Route, error)) *MockIP4Config_GetPropertyRoutes_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertySearches provides a mock function with no fields -func (_m *MockIP4Config) GetPropertySearches() ([]string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertySearches") - } - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func() ([]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertySearches_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySearches' -type MockIP4Config_GetPropertySearches_Call struct { - *mock.Call -} - -// GetPropertySearches is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertySearches() *MockIP4Config_GetPropertySearches_Call { - return &MockIP4Config_GetPropertySearches_Call{Call: _e.mock.On("GetPropertySearches")} -} - -func (_c *MockIP4Config_GetPropertySearches_Call) Run(run func()) *MockIP4Config_GetPropertySearches_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertySearches_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertySearches_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertySearches_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertySearches_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWinsServerData provides a mock function with no fields -func (_m *MockIP4Config) GetPropertyWinsServerData() ([]string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWinsServerData") - } - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func() ([]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_GetPropertyWinsServerData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWinsServerData' -type MockIP4Config_GetPropertyWinsServerData_Call struct { - *mock.Call -} - -// GetPropertyWinsServerData is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) GetPropertyWinsServerData() *MockIP4Config_GetPropertyWinsServerData_Call { - return &MockIP4Config_GetPropertyWinsServerData_Call{Call: _e.mock.On("GetPropertyWinsServerData")} -} - -func (_c *MockIP4Config_GetPropertyWinsServerData_Call) Run(run func()) *MockIP4Config_GetPropertyWinsServerData_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_GetPropertyWinsServerData_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyWinsServerData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_GetPropertyWinsServerData_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyWinsServerData_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockIP4Config) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockIP4Config_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockIP4Config_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockIP4Config_Expecter) MarshalJSON() *MockIP4Config_MarshalJSON_Call { - return &MockIP4Config_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockIP4Config_MarshalJSON_Call) Run(run func()) *MockIP4Config_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockIP4Config_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockIP4Config_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockIP4Config_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockIP4Config_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// NewMockIP4Config creates a new instance of MockIP4Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockIP4Config(t interface { - mock.TestingT - Cleanup(func()) -}) *MockIP4Config { - mock := &MockIP4Config{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go deleted file mode 100644 index e74ffb0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go +++ /dev/null @@ -1,2349 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - dbus "github.com/godbus/dbus/v5" - - mock "github.com/stretchr/testify/mock" -) - -// MockNetworkManager is an autogenerated mock type for the NetworkManager type -type MockNetworkManager struct { - mock.Mock -} - -type MockNetworkManager_Expecter struct { - mock *mock.Mock -} - -func (_m *MockNetworkManager) EXPECT() *MockNetworkManager_Expecter { - return &MockNetworkManager_Expecter{mock: &_m.Mock} -} - -// ActivateConnection provides a mock function with given fields: connection, device, specificObject -func (_m *MockNetworkManager) ActivateConnection(connection gonetworkmanager.Connection, device gonetworkmanager.Device, specificObject *dbus.Object) (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called(connection, device, specificObject) - - if len(ret) == 0 { - panic("no return value specified for ActivateConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) (gonetworkmanager.ActiveConnection, error)); ok { - return rf(connection, device, specificObject) - } - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) gonetworkmanager.ActiveConnection); ok { - r0 = rf(connection, device, specificObject) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) error); ok { - r1 = rf(connection, device, specificObject) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_ActivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateConnection' -type MockNetworkManager_ActivateConnection_Call struct { - *mock.Call -} - -// ActivateConnection is a helper method to define mock.On call -// - connection gonetworkmanager.Connection -// - device gonetworkmanager.Device -// - specificObject *dbus.Object -func (_e *MockNetworkManager_Expecter) ActivateConnection(connection interface{}, device interface{}, specificObject interface{}) *MockNetworkManager_ActivateConnection_Call { - return &MockNetworkManager_ActivateConnection_Call{Call: _e.mock.On("ActivateConnection", connection, device, specificObject)} -} - -func (_c *MockNetworkManager_ActivateConnection_Call) Run(run func(connection gonetworkmanager.Connection, device gonetworkmanager.Device, specificObject *dbus.Object)) *MockNetworkManager_ActivateConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Connection), args[1].(gonetworkmanager.Device), args[2].(*dbus.Object)) - }) - return _c -} - -func (_c *MockNetworkManager_ActivateConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_ActivateConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_ActivateConnection_Call) RunAndReturn(run func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_ActivateConnection_Call { - _c.Call.Return(run) - return _c -} - -// ActivateWirelessConnection provides a mock function with given fields: connection, device, accessPoint -func (_m *MockNetworkManager) ActivateWirelessConnection(connection gonetworkmanager.Connection, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called(connection, device, accessPoint) - - if len(ret) == 0 { - panic("no return value specified for ActivateWirelessConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)); ok { - return rf(connection, device, accessPoint) - } - if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) gonetworkmanager.ActiveConnection); ok { - r0 = rf(connection, device, accessPoint) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) error); ok { - r1 = rf(connection, device, accessPoint) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_ActivateWirelessConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateWirelessConnection' -type MockNetworkManager_ActivateWirelessConnection_Call struct { - *mock.Call -} - -// ActivateWirelessConnection is a helper method to define mock.On call -// - connection gonetworkmanager.Connection -// - device gonetworkmanager.Device -// - accessPoint gonetworkmanager.AccessPoint -func (_e *MockNetworkManager_Expecter) ActivateWirelessConnection(connection interface{}, device interface{}, accessPoint interface{}) *MockNetworkManager_ActivateWirelessConnection_Call { - return &MockNetworkManager_ActivateWirelessConnection_Call{Call: _e.mock.On("ActivateWirelessConnection", connection, device, accessPoint)} -} - -func (_c *MockNetworkManager_ActivateWirelessConnection_Call) Run(run func(connection gonetworkmanager.Connection, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint)) *MockNetworkManager_ActivateWirelessConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Connection), args[1].(gonetworkmanager.Device), args[2].(gonetworkmanager.AccessPoint)) - }) - return _c -} - -func (_c *MockNetworkManager_ActivateWirelessConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_ActivateWirelessConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_ActivateWirelessConnection_Call) RunAndReturn(run func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_ActivateWirelessConnection_Call { - _c.Call.Return(run) - return _c -} - -// AddAndActivateConnection provides a mock function with given fields: connection, device -func (_m *MockNetworkManager) AddAndActivateConnection(connection map[string]map[string]interface{}, device gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called(connection, device) - - if len(ret) == 0 { - panic("no return value specified for AddAndActivateConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error)); ok { - return rf(connection, device) - } - if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device) gonetworkmanager.ActiveConnection); ok { - r0 = rf(connection, device) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func(map[string]map[string]interface{}, gonetworkmanager.Device) error); ok { - r1 = rf(connection, device) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_AddAndActivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddAndActivateConnection' -type MockNetworkManager_AddAndActivateConnection_Call struct { - *mock.Call -} - -// AddAndActivateConnection is a helper method to define mock.On call -// - connection map[string]map[string]interface{} -// - device gonetworkmanager.Device -func (_e *MockNetworkManager_Expecter) AddAndActivateConnection(connection interface{}, device interface{}) *MockNetworkManager_AddAndActivateConnection_Call { - return &MockNetworkManager_AddAndActivateConnection_Call{Call: _e.mock.On("AddAndActivateConnection", connection, device)} -} - -func (_c *MockNetworkManager_AddAndActivateConnection_Call) Run(run func(connection map[string]map[string]interface{}, device gonetworkmanager.Device)) *MockNetworkManager_AddAndActivateConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(map[string]map[string]interface{}), args[1].(gonetworkmanager.Device)) - }) - return _c -} - -func (_c *MockNetworkManager_AddAndActivateConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_AddAndActivateConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_AddAndActivateConnection_Call) RunAndReturn(run func(map[string]map[string]interface{}, gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_AddAndActivateConnection_Call { - _c.Call.Return(run) - return _c -} - -// AddAndActivateWirelessConnection provides a mock function with given fields: connection, device, accessPoint -func (_m *MockNetworkManager) AddAndActivateWirelessConnection(connection map[string]map[string]interface{}, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called(connection, device, accessPoint) - - if len(ret) == 0 { - panic("no return value specified for AddAndActivateWirelessConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)); ok { - return rf(connection, device, accessPoint) - } - if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) gonetworkmanager.ActiveConnection); ok { - r0 = rf(connection, device, accessPoint) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) error); ok { - r1 = rf(connection, device, accessPoint) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_AddAndActivateWirelessConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddAndActivateWirelessConnection' -type MockNetworkManager_AddAndActivateWirelessConnection_Call struct { - *mock.Call -} - -// AddAndActivateWirelessConnection is a helper method to define mock.On call -// - connection map[string]map[string]interface{} -// - device gonetworkmanager.Device -// - accessPoint gonetworkmanager.AccessPoint -func (_e *MockNetworkManager_Expecter) AddAndActivateWirelessConnection(connection interface{}, device interface{}, accessPoint interface{}) *MockNetworkManager_AddAndActivateWirelessConnection_Call { - return &MockNetworkManager_AddAndActivateWirelessConnection_Call{Call: _e.mock.On("AddAndActivateWirelessConnection", connection, device, accessPoint)} -} - -func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) Run(run func(connection map[string]map[string]interface{}, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint)) *MockNetworkManager_AddAndActivateWirelessConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(map[string]map[string]interface{}), args[1].(gonetworkmanager.Device), args[2].(gonetworkmanager.AccessPoint)) - }) - return _c -} - -func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_AddAndActivateWirelessConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) RunAndReturn(run func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_AddAndActivateWirelessConnection_Call { - _c.Call.Return(run) - return _c -} - -// CheckConnectivity provides a mock function with no fields -func (_m *MockNetworkManager) CheckConnectivity() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for CheckConnectivity") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_CheckConnectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckConnectivity' -type MockNetworkManager_CheckConnectivity_Call struct { - *mock.Call -} - -// CheckConnectivity is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) CheckConnectivity() *MockNetworkManager_CheckConnectivity_Call { - return &MockNetworkManager_CheckConnectivity_Call{Call: _e.mock.On("CheckConnectivity")} -} - -func (_c *MockNetworkManager_CheckConnectivity_Call) Run(run func()) *MockNetworkManager_CheckConnectivity_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_CheckConnectivity_Call) Return(_a0 error) *MockNetworkManager_CheckConnectivity_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_CheckConnectivity_Call) RunAndReturn(run func() error) *MockNetworkManager_CheckConnectivity_Call { - _c.Call.Return(run) - return _c -} - -// CheckpointAdjustRollbackTimeout provides a mock function with given fields: checkpoint, addTimeout -func (_m *MockNetworkManager) CheckpointAdjustRollbackTimeout(checkpoint gonetworkmanager.Checkpoint, addTimeout uint32) error { - ret := _m.Called(checkpoint, addTimeout) - - if len(ret) == 0 { - panic("no return value specified for CheckpointAdjustRollbackTimeout") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint, uint32) error); ok { - r0 = rf(checkpoint, addTimeout) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_CheckpointAdjustRollbackTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointAdjustRollbackTimeout' -type MockNetworkManager_CheckpointAdjustRollbackTimeout_Call struct { - *mock.Call -} - -// CheckpointAdjustRollbackTimeout is a helper method to define mock.On call -// - checkpoint gonetworkmanager.Checkpoint -// - addTimeout uint32 -func (_e *MockNetworkManager_Expecter) CheckpointAdjustRollbackTimeout(checkpoint interface{}, addTimeout interface{}) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call { - return &MockNetworkManager_CheckpointAdjustRollbackTimeout_Call{Call: _e.mock.On("CheckpointAdjustRollbackTimeout", checkpoint, addTimeout)} -} - -func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint, addTimeout uint32)) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Checkpoint), args[1].(uint32)) - }) - return _c -} - -func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) Return(_a0 error) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint, uint32) error) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call { - _c.Call.Return(run) - return _c -} - -// CheckpointCreate provides a mock function with given fields: devices, rollbackTimeout, flags -func (_m *MockNetworkManager) CheckpointCreate(devices []gonetworkmanager.Device, rollbackTimeout uint32, flags uint32) (gonetworkmanager.Checkpoint, error) { - ret := _m.Called(devices, rollbackTimeout, flags) - - if len(ret) == 0 { - panic("no return value specified for CheckpointCreate") - } - - var r0 gonetworkmanager.Checkpoint - var r1 error - if rf, ok := ret.Get(0).(func([]gonetworkmanager.Device, uint32, uint32) (gonetworkmanager.Checkpoint, error)); ok { - return rf(devices, rollbackTimeout, flags) - } - if rf, ok := ret.Get(0).(func([]gonetworkmanager.Device, uint32, uint32) gonetworkmanager.Checkpoint); ok { - r0 = rf(devices, rollbackTimeout, flags) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Checkpoint) - } - } - - if rf, ok := ret.Get(1).(func([]gonetworkmanager.Device, uint32, uint32) error); ok { - r1 = rf(devices, rollbackTimeout, flags) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_CheckpointCreate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointCreate' -type MockNetworkManager_CheckpointCreate_Call struct { - *mock.Call -} - -// CheckpointCreate is a helper method to define mock.On call -// - devices []gonetworkmanager.Device -// - rollbackTimeout uint32 -// - flags uint32 -func (_e *MockNetworkManager_Expecter) CheckpointCreate(devices interface{}, rollbackTimeout interface{}, flags interface{}) *MockNetworkManager_CheckpointCreate_Call { - return &MockNetworkManager_CheckpointCreate_Call{Call: _e.mock.On("CheckpointCreate", devices, rollbackTimeout, flags)} -} - -func (_c *MockNetworkManager_CheckpointCreate_Call) Run(run func(devices []gonetworkmanager.Device, rollbackTimeout uint32, flags uint32)) *MockNetworkManager_CheckpointCreate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]gonetworkmanager.Device), args[1].(uint32), args[2].(uint32)) - }) - return _c -} - -func (_c *MockNetworkManager_CheckpointCreate_Call) Return(_a0 gonetworkmanager.Checkpoint, _a1 error) *MockNetworkManager_CheckpointCreate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_CheckpointCreate_Call) RunAndReturn(run func([]gonetworkmanager.Device, uint32, uint32) (gonetworkmanager.Checkpoint, error)) *MockNetworkManager_CheckpointCreate_Call { - _c.Call.Return(run) - return _c -} - -// CheckpointDestroy provides a mock function with given fields: checkpoint -func (_m *MockNetworkManager) CheckpointDestroy(checkpoint gonetworkmanager.Checkpoint) error { - ret := _m.Called(checkpoint) - - if len(ret) == 0 { - panic("no return value specified for CheckpointDestroy") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) error); ok { - r0 = rf(checkpoint) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_CheckpointDestroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointDestroy' -type MockNetworkManager_CheckpointDestroy_Call struct { - *mock.Call -} - -// CheckpointDestroy is a helper method to define mock.On call -// - checkpoint gonetworkmanager.Checkpoint -func (_e *MockNetworkManager_Expecter) CheckpointDestroy(checkpoint interface{}) *MockNetworkManager_CheckpointDestroy_Call { - return &MockNetworkManager_CheckpointDestroy_Call{Call: _e.mock.On("CheckpointDestroy", checkpoint)} -} - -func (_c *MockNetworkManager_CheckpointDestroy_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint)) *MockNetworkManager_CheckpointDestroy_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Checkpoint)) - }) - return _c -} - -func (_c *MockNetworkManager_CheckpointDestroy_Call) Return(_a0 error) *MockNetworkManager_CheckpointDestroy_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_CheckpointDestroy_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint) error) *MockNetworkManager_CheckpointDestroy_Call { - _c.Call.Return(run) - return _c -} - -// CheckpointRollback provides a mock function with given fields: checkpoint -func (_m *MockNetworkManager) CheckpointRollback(checkpoint gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error) { - ret := _m.Called(checkpoint) - - if len(ret) == 0 { - panic("no return value specified for CheckpointRollback") - } - - var r0 map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult - var r1 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error)); ok { - return rf(checkpoint) - } - if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult); ok { - r0 = rf(checkpoint) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult) - } - } - - if rf, ok := ret.Get(1).(func(gonetworkmanager.Checkpoint) error); ok { - r1 = rf(checkpoint) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_CheckpointRollback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointRollback' -type MockNetworkManager_CheckpointRollback_Call struct { - *mock.Call -} - -// CheckpointRollback is a helper method to define mock.On call -// - checkpoint gonetworkmanager.Checkpoint -func (_e *MockNetworkManager_Expecter) CheckpointRollback(checkpoint interface{}) *MockNetworkManager_CheckpointRollback_Call { - return &MockNetworkManager_CheckpointRollback_Call{Call: _e.mock.On("CheckpointRollback", checkpoint)} -} - -func (_c *MockNetworkManager_CheckpointRollback_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint)) *MockNetworkManager_CheckpointRollback_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.Checkpoint)) - }) - return _c -} - -func (_c *MockNetworkManager_CheckpointRollback_Call) Return(result map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, err error) *MockNetworkManager_CheckpointRollback_Call { - _c.Call.Return(result, err) - return _c -} - -func (_c *MockNetworkManager_CheckpointRollback_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error)) *MockNetworkManager_CheckpointRollback_Call { - _c.Call.Return(run) - return _c -} - -// DeactivateConnection provides a mock function with given fields: connection -func (_m *MockNetworkManager) DeactivateConnection(connection gonetworkmanager.ActiveConnection) error { - ret := _m.Called(connection) - - if len(ret) == 0 { - panic("no return value specified for DeactivateConnection") - } - - var r0 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.ActiveConnection) error); ok { - r0 = rf(connection) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_DeactivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeactivateConnection' -type MockNetworkManager_DeactivateConnection_Call struct { - *mock.Call -} - -// DeactivateConnection is a helper method to define mock.On call -// - connection gonetworkmanager.ActiveConnection -func (_e *MockNetworkManager_Expecter) DeactivateConnection(connection interface{}) *MockNetworkManager_DeactivateConnection_Call { - return &MockNetworkManager_DeactivateConnection_Call{Call: _e.mock.On("DeactivateConnection", connection)} -} - -func (_c *MockNetworkManager_DeactivateConnection_Call) Run(run func(connection gonetworkmanager.ActiveConnection)) *MockNetworkManager_DeactivateConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.ActiveConnection)) - }) - return _c -} - -func (_c *MockNetworkManager_DeactivateConnection_Call) Return(_a0 error) *MockNetworkManager_DeactivateConnection_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_DeactivateConnection_Call) RunAndReturn(run func(gonetworkmanager.ActiveConnection) error) *MockNetworkManager_DeactivateConnection_Call { - _c.Call.Return(run) - return _c -} - -// Enable provides a mock function with given fields: enableNDisable -func (_m *MockNetworkManager) Enable(enableNDisable bool) error { - ret := _m.Called(enableNDisable) - - if len(ret) == 0 { - panic("no return value specified for Enable") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(enableNDisable) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_Enable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Enable' -type MockNetworkManager_Enable_Call struct { - *mock.Call -} - -// Enable is a helper method to define mock.On call -// - enableNDisable bool -func (_e *MockNetworkManager_Expecter) Enable(enableNDisable interface{}) *MockNetworkManager_Enable_Call { - return &MockNetworkManager_Enable_Call{Call: _e.mock.On("Enable", enableNDisable)} -} - -func (_c *MockNetworkManager_Enable_Call) Run(run func(enableNDisable bool)) *MockNetworkManager_Enable_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockNetworkManager_Enable_Call) Return(_a0 error) *MockNetworkManager_Enable_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_Enable_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_Enable_Call { - _c.Call.Return(run) - return _c -} - -// GetAllDevices provides a mock function with no fields -func (_m *MockNetworkManager) GetAllDevices() ([]gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetAllDevices") - } - - var r0 []gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetAllDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllDevices' -type MockNetworkManager_GetAllDevices_Call struct { - *mock.Call -} - -// GetAllDevices is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetAllDevices() *MockNetworkManager_GetAllDevices_Call { - return &MockNetworkManager_GetAllDevices_Call{Call: _e.mock.On("GetAllDevices")} -} - -func (_c *MockNetworkManager_GetAllDevices_Call) Run(run func()) *MockNetworkManager_GetAllDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetAllDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetAllDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetAllDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetAllDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetDeviceByIpIface provides a mock function with given fields: interfaceId -func (_m *MockNetworkManager) GetDeviceByIpIface(interfaceId string) (gonetworkmanager.Device, error) { - ret := _m.Called(interfaceId) - - if len(ret) == 0 { - panic("no return value specified for GetDeviceByIpIface") - } - - var r0 gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.Device, error)); ok { - return rf(interfaceId) - } - if rf, ok := ret.Get(0).(func(string) gonetworkmanager.Device); ok { - r0 = rf(interfaceId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(interfaceId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetDeviceByIpIface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDeviceByIpIface' -type MockNetworkManager_GetDeviceByIpIface_Call struct { - *mock.Call -} - -// GetDeviceByIpIface is a helper method to define mock.On call -// - interfaceId string -func (_e *MockNetworkManager_Expecter) GetDeviceByIpIface(interfaceId interface{}) *MockNetworkManager_GetDeviceByIpIface_Call { - return &MockNetworkManager_GetDeviceByIpIface_Call{Call: _e.mock.On("GetDeviceByIpIface", interfaceId)} -} - -func (_c *MockNetworkManager_GetDeviceByIpIface_Call) Run(run func(interfaceId string)) *MockNetworkManager_GetDeviceByIpIface_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockNetworkManager_GetDeviceByIpIface_Call) Return(_a0 gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetDeviceByIpIface_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetDeviceByIpIface_Call) RunAndReturn(run func(string) (gonetworkmanager.Device, error)) *MockNetworkManager_GetDeviceByIpIface_Call { - _c.Call.Return(run) - return _c -} - -// GetDevices provides a mock function with no fields -func (_m *MockNetworkManager) GetDevices() ([]gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetDevices") - } - - var r0 []gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDevices' -type MockNetworkManager_GetDevices_Call struct { - *mock.Call -} - -// GetDevices is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetDevices() *MockNetworkManager_GetDevices_Call { - return &MockNetworkManager_GetDevices_Call{Call: _e.mock.On("GetDevices")} -} - -func (_c *MockNetworkManager_GetDevices_Call) Run(run func()) *MockNetworkManager_GetDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyActivatingConnection provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyActivatingConnection() (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyActivatingConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyActivatingConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActivatingConnection' -type MockNetworkManager_GetPropertyActivatingConnection_Call struct { - *mock.Call -} - -// GetPropertyActivatingConnection is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyActivatingConnection() *MockNetworkManager_GetPropertyActivatingConnection_Call { - return &MockNetworkManager_GetPropertyActivatingConnection_Call{Call: _e.mock.On("GetPropertyActivatingConnection")} -} - -func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) Run(run func()) *MockNetworkManager_GetPropertyActivatingConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyActivatingConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyActivatingConnection_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyActiveConnections provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyActiveConnections() ([]gonetworkmanager.ActiveConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyActiveConnections") - } - - var r0 []gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.ActiveConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.ActiveConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyActiveConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnections' -type MockNetworkManager_GetPropertyActiveConnections_Call struct { - *mock.Call -} - -// GetPropertyActiveConnections is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyActiveConnections() *MockNetworkManager_GetPropertyActiveConnections_Call { - return &MockNetworkManager_GetPropertyActiveConnections_Call{Call: _e.mock.On("GetPropertyActiveConnections")} -} - -func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) Run(run func()) *MockNetworkManager_GetPropertyActiveConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) Return(_a0 []gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyActiveConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyActiveConnections_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyAllDevices provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyAllDevices() ([]gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyAllDevices") - } - - var r0 []gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyAllDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAllDevices' -type MockNetworkManager_GetPropertyAllDevices_Call struct { - *mock.Call -} - -// GetPropertyAllDevices is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyAllDevices() *MockNetworkManager_GetPropertyAllDevices_Call { - return &MockNetworkManager_GetPropertyAllDevices_Call{Call: _e.mock.On("GetPropertyAllDevices")} -} - -func (_c *MockNetworkManager_GetPropertyAllDevices_Call) Run(run func()) *MockNetworkManager_GetPropertyAllDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyAllDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetPropertyAllDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyAllDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetPropertyAllDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyCapabilities provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyCapabilities() ([]gonetworkmanager.NmCapability, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyCapabilities") - } - - var r0 []gonetworkmanager.NmCapability - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.NmCapability, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.NmCapability); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.NmCapability) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyCapabilities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCapabilities' -type MockNetworkManager_GetPropertyCapabilities_Call struct { - *mock.Call -} - -// GetPropertyCapabilities is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyCapabilities() *MockNetworkManager_GetPropertyCapabilities_Call { - return &MockNetworkManager_GetPropertyCapabilities_Call{Call: _e.mock.On("GetPropertyCapabilities")} -} - -func (_c *MockNetworkManager_GetPropertyCapabilities_Call) Run(run func()) *MockNetworkManager_GetPropertyCapabilities_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyCapabilities_Call) Return(_a0 []gonetworkmanager.NmCapability, _a1 error) *MockNetworkManager_GetPropertyCapabilities_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyCapabilities_Call) RunAndReturn(run func() ([]gonetworkmanager.NmCapability, error)) *MockNetworkManager_GetPropertyCapabilities_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyCheckpoints provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyCheckpoints() ([]gonetworkmanager.Checkpoint, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyCheckpoints") - } - - var r0 []gonetworkmanager.Checkpoint - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Checkpoint, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Checkpoint); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Checkpoint) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyCheckpoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCheckpoints' -type MockNetworkManager_GetPropertyCheckpoints_Call struct { - *mock.Call -} - -// GetPropertyCheckpoints is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyCheckpoints() *MockNetworkManager_GetPropertyCheckpoints_Call { - return &MockNetworkManager_GetPropertyCheckpoints_Call{Call: _e.mock.On("GetPropertyCheckpoints")} -} - -func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) Run(run func()) *MockNetworkManager_GetPropertyCheckpoints_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) Return(_a0 []gonetworkmanager.Checkpoint, _a1 error) *MockNetworkManager_GetPropertyCheckpoints_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) RunAndReturn(run func() ([]gonetworkmanager.Checkpoint, error)) *MockNetworkManager_GetPropertyCheckpoints_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyConnectivity provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyConnectivity() (gonetworkmanager.NmConnectivity, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyConnectivity") - } - - var r0 gonetworkmanager.NmConnectivity - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmConnectivity) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyConnectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivity' -type MockNetworkManager_GetPropertyConnectivity_Call struct { - *mock.Call -} - -// GetPropertyConnectivity is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyConnectivity() *MockNetworkManager_GetPropertyConnectivity_Call { - return &MockNetworkManager_GetPropertyConnectivity_Call{Call: _e.mock.On("GetPropertyConnectivity")} -} - -func (_c *MockNetworkManager_GetPropertyConnectivity_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivity_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockNetworkManager_GetPropertyConnectivity_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockNetworkManager_GetPropertyConnectivity_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyConnectivityCheckAvailable provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyConnectivityCheckAvailable() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyConnectivityCheckAvailable") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivityCheckAvailable' -type MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call struct { - *mock.Call -} - -// GetPropertyConnectivityCheckAvailable is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyConnectivityCheckAvailable() *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call { - return &MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call{Call: _e.mock.On("GetPropertyConnectivityCheckAvailable")} -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyConnectivityCheckEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyConnectivityCheckEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyConnectivityCheckEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivityCheckEnabled' -type MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call struct { - *mock.Call -} - -// GetPropertyConnectivityCheckEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyConnectivityCheckEnabled() *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call { - return &MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call{Call: _e.mock.On("GetPropertyConnectivityCheckEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyDevices provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyDevices() ([]gonetworkmanager.Device, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyDevices") - } - - var r0 []gonetworkmanager.Device - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Device) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDevices' -type MockNetworkManager_GetPropertyDevices_Call struct { - *mock.Call -} - -// GetPropertyDevices is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyDevices() *MockNetworkManager_GetPropertyDevices_Call { - return &MockNetworkManager_GetPropertyDevices_Call{Call: _e.mock.On("GetPropertyDevices")} -} - -func (_c *MockNetworkManager_GetPropertyDevices_Call) Run(run func()) *MockNetworkManager_GetPropertyDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetPropertyDevices_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetPropertyDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyMetered provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyMetered() (gonetworkmanager.NmMetered, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyMetered") - } - - var r0 gonetworkmanager.NmMetered - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmMetered, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmMetered); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmMetered) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyMetered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMetered' -type MockNetworkManager_GetPropertyMetered_Call struct { - *mock.Call -} - -// GetPropertyMetered is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyMetered() *MockNetworkManager_GetPropertyMetered_Call { - return &MockNetworkManager_GetPropertyMetered_Call{Call: _e.mock.On("GetPropertyMetered")} -} - -func (_c *MockNetworkManager_GetPropertyMetered_Call) Run(run func()) *MockNetworkManager_GetPropertyMetered_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyMetered_Call) Return(_a0 gonetworkmanager.NmMetered, _a1 error) *MockNetworkManager_GetPropertyMetered_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyMetered_Call) RunAndReturn(run func() (gonetworkmanager.NmMetered, error)) *MockNetworkManager_GetPropertyMetered_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyNetworkingEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyNetworkingEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyNetworkingEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyNetworkingEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNetworkingEnabled' -type MockNetworkManager_GetPropertyNetworkingEnabled_Call struct { - *mock.Call -} - -// GetPropertyNetworkingEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyNetworkingEnabled() *MockNetworkManager_GetPropertyNetworkingEnabled_Call { - return &MockNetworkManager_GetPropertyNetworkingEnabled_Call{Call: _e.mock.On("GetPropertyNetworkingEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyNetworkingEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyNetworkingEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyNetworkingEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyPrimaryConnection provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyPrimaryConnection() (gonetworkmanager.ActiveConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyPrimaryConnection") - } - - var r0 gonetworkmanager.ActiveConnection - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.ActiveConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyPrimaryConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPrimaryConnection' -type MockNetworkManager_GetPropertyPrimaryConnection_Call struct { - *mock.Call -} - -// GetPropertyPrimaryConnection is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyPrimaryConnection() *MockNetworkManager_GetPropertyPrimaryConnection_Call { - return &MockNetworkManager_GetPropertyPrimaryConnection_Call{Call: _e.mock.On("GetPropertyPrimaryConnection")} -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) Run(run func()) *MockNetworkManager_GetPropertyPrimaryConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyPrimaryConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyPrimaryConnection_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyPrimaryConnectionType provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyPrimaryConnectionType() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyPrimaryConnectionType") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyPrimaryConnectionType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPrimaryConnectionType' -type MockNetworkManager_GetPropertyPrimaryConnectionType_Call struct { - *mock.Call -} - -// GetPropertyPrimaryConnectionType is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyPrimaryConnectionType() *MockNetworkManager_GetPropertyPrimaryConnectionType_Call { - return &MockNetworkManager_GetPropertyPrimaryConnectionType_Call{Call: _e.mock.On("GetPropertyPrimaryConnectionType")} -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) Run(run func()) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) Return(_a0 string, _a1 error) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) RunAndReturn(run func() (string, error)) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyStartup provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyStartup() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyStartup") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyStartup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStartup' -type MockNetworkManager_GetPropertyStartup_Call struct { - *mock.Call -} - -// GetPropertyStartup is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyStartup() *MockNetworkManager_GetPropertyStartup_Call { - return &MockNetworkManager_GetPropertyStartup_Call{Call: _e.mock.On("GetPropertyStartup")} -} - -func (_c *MockNetworkManager_GetPropertyStartup_Call) Run(run func()) *MockNetworkManager_GetPropertyStartup_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyStartup_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyStartup_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyStartup_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyStartup_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyState provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyState() (gonetworkmanager.NmState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyState") - } - - var r0 gonetworkmanager.NmState - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmState); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmState) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState' -type MockNetworkManager_GetPropertyState_Call struct { - *mock.Call -} - -// GetPropertyState is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyState() *MockNetworkManager_GetPropertyState_Call { - return &MockNetworkManager_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")} -} - -func (_c *MockNetworkManager_GetPropertyState_Call) Run(run func()) *MockNetworkManager_GetPropertyState_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmState, _a1 error) *MockNetworkManager_GetPropertyState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmState, error)) *MockNetworkManager_GetPropertyState_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyVersion provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyVersion() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyVersion' -type MockNetworkManager_GetPropertyVersion_Call struct { - *mock.Call -} - -// GetPropertyVersion is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyVersion() *MockNetworkManager_GetPropertyVersion_Call { - return &MockNetworkManager_GetPropertyVersion_Call{Call: _e.mock.On("GetPropertyVersion")} -} - -func (_c *MockNetworkManager_GetPropertyVersion_Call) Run(run func()) *MockNetworkManager_GetPropertyVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyVersion_Call) Return(_a0 string, _a1 error) *MockNetworkManager_GetPropertyVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyVersion_Call) RunAndReturn(run func() (string, error)) *MockNetworkManager_GetPropertyVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWimaxEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWimaxEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWimaxEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWimaxEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWimaxEnabled' -type MockNetworkManager_GetPropertyWimaxEnabled_Call struct { - *mock.Call -} - -// GetPropertyWimaxEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWimaxEnabled() *MockNetworkManager_GetPropertyWimaxEnabled_Call { - return &MockNetworkManager_GetPropertyWimaxEnabled_Call{Call: _e.mock.On("GetPropertyWimaxEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWimaxEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWimaxEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWimaxEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWimaxHardwareEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWimaxHardwareEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWimaxHardwareEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWimaxHardwareEnabled' -type MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call struct { - *mock.Call -} - -// GetPropertyWimaxHardwareEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWimaxHardwareEnabled() *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call { - return &MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWimaxHardwareEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWirelessEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWirelessEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWirelessEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWirelessEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessEnabled' -type MockNetworkManager_GetPropertyWirelessEnabled_Call struct { - *mock.Call -} - -// GetPropertyWirelessEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWirelessEnabled() *MockNetworkManager_GetPropertyWirelessEnabled_Call { - return &MockNetworkManager_GetPropertyWirelessEnabled_Call{Call: _e.mock.On("GetPropertyWirelessEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWirelessEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWirelessEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWirelessEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWirelessHardwareEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWirelessHardwareEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWirelessHardwareEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessHardwareEnabled' -type MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call struct { - *mock.Call -} - -// GetPropertyWirelessHardwareEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWirelessHardwareEnabled() *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call { - return &MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWirelessHardwareEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWwanEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWwanEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWwanEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWwanEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWwanEnabled' -type MockNetworkManager_GetPropertyWwanEnabled_Call struct { - *mock.Call -} - -// GetPropertyWwanEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWwanEnabled() *MockNetworkManager_GetPropertyWwanEnabled_Call { - return &MockNetworkManager_GetPropertyWwanEnabled_Call{Call: _e.mock.On("GetPropertyWwanEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWwanEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWwanEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWwanEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyWwanHardwareEnabled provides a mock function with no fields -func (_m *MockNetworkManager) GetPropertyWwanHardwareEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyWwanHardwareEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_GetPropertyWwanHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWwanHardwareEnabled' -type MockNetworkManager_GetPropertyWwanHardwareEnabled_Call struct { - *mock.Call -} - -// GetPropertyWwanHardwareEnabled is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) GetPropertyWwanHardwareEnabled() *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call { - return &MockNetworkManager_GetPropertyWwanHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWwanHardwareEnabled")} -} - -func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call { - _c.Call.Return(run) - return _c -} - -// MarshalJSON provides a mock function with no fields -func (_m *MockNetworkManager) MarshalJSON() ([]byte, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for MarshalJSON") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []byte); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON' -type MockNetworkManager_MarshalJSON_Call struct { - *mock.Call -} - -// MarshalJSON is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) MarshalJSON() *MockNetworkManager_MarshalJSON_Call { - return &MockNetworkManager_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")} -} - -func (_c *MockNetworkManager_MarshalJSON_Call) Run(run func()) *MockNetworkManager_MarshalJSON_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockNetworkManager_MarshalJSON_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockNetworkManager_MarshalJSON_Call { - _c.Call.Return(run) - return _c -} - -// Reload provides a mock function with given fields: flags -func (_m *MockNetworkManager) Reload(flags uint32) error { - ret := _m.Called(flags) - - if len(ret) == 0 { - panic("no return value specified for Reload") - } - - var r0 error - if rf, ok := ret.Get(0).(func(uint32) error); ok { - r0 = rf(flags) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_Reload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reload' -type MockNetworkManager_Reload_Call struct { - *mock.Call -} - -// Reload is a helper method to define mock.On call -// - flags uint32 -func (_e *MockNetworkManager_Expecter) Reload(flags interface{}) *MockNetworkManager_Reload_Call { - return &MockNetworkManager_Reload_Call{Call: _e.mock.On("Reload", flags)} -} - -func (_c *MockNetworkManager_Reload_Call) Run(run func(flags uint32)) *MockNetworkManager_Reload_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(uint32)) - }) - return _c -} - -func (_c *MockNetworkManager_Reload_Call) Return(_a0 error) *MockNetworkManager_Reload_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_Reload_Call) RunAndReturn(run func(uint32) error) *MockNetworkManager_Reload_Call { - _c.Call.Return(run) - return _c -} - -// SetPropertyWirelessEnabled provides a mock function with given fields: _a0 -func (_m *MockNetworkManager) SetPropertyWirelessEnabled(_a0 bool) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for SetPropertyWirelessEnabled") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_SetPropertyWirelessEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyWirelessEnabled' -type MockNetworkManager_SetPropertyWirelessEnabled_Call struct { - *mock.Call -} - -// SetPropertyWirelessEnabled is a helper method to define mock.On call -// - _a0 bool -func (_e *MockNetworkManager_Expecter) SetPropertyWirelessEnabled(_a0 interface{}) *MockNetworkManager_SetPropertyWirelessEnabled_Call { - return &MockNetworkManager_SetPropertyWirelessEnabled_Call{Call: _e.mock.On("SetPropertyWirelessEnabled", _a0)} -} - -func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) Run(run func(_a0 bool)) *MockNetworkManager_SetPropertyWirelessEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) Return(_a0 error) *MockNetworkManager_SetPropertyWirelessEnabled_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_SetPropertyWirelessEnabled_Call { - _c.Call.Return(run) - return _c -} - -// Sleep provides a mock function with given fields: sleepNWake -func (_m *MockNetworkManager) Sleep(sleepNWake bool) error { - ret := _m.Called(sleepNWake) - - if len(ret) == 0 { - panic("no return value specified for Sleep") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(sleepNWake) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockNetworkManager_Sleep_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sleep' -type MockNetworkManager_Sleep_Call struct { - *mock.Call -} - -// Sleep is a helper method to define mock.On call -// - sleepNWake bool -func (_e *MockNetworkManager_Expecter) Sleep(sleepNWake interface{}) *MockNetworkManager_Sleep_Call { - return &MockNetworkManager_Sleep_Call{Call: _e.mock.On("Sleep", sleepNWake)} -} - -func (_c *MockNetworkManager_Sleep_Call) Run(run func(sleepNWake bool)) *MockNetworkManager_Sleep_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockNetworkManager_Sleep_Call) Return(_a0 error) *MockNetworkManager_Sleep_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_Sleep_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_Sleep_Call { - _c.Call.Return(run) - return _c -} - -// State provides a mock function with no fields -func (_m *MockNetworkManager) State() (gonetworkmanager.NmState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for State") - } - - var r0 gonetworkmanager.NmState - var r1 error - if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() gonetworkmanager.NmState); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(gonetworkmanager.NmState) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockNetworkManager_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State' -type MockNetworkManager_State_Call struct { - *mock.Call -} - -// State is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) State() *MockNetworkManager_State_Call { - return &MockNetworkManager_State_Call{Call: _e.mock.On("State")} -} - -func (_c *MockNetworkManager_State_Call) Run(run func()) *MockNetworkManager_State_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_State_Call) Return(_a0 gonetworkmanager.NmState, _a1 error) *MockNetworkManager_State_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockNetworkManager_State_Call) RunAndReturn(run func() (gonetworkmanager.NmState, error)) *MockNetworkManager_State_Call { - _c.Call.Return(run) - return _c -} - -// Subscribe provides a mock function with no fields -func (_m *MockNetworkManager) Subscribe() <-chan *dbus.Signal { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Subscribe") - } - - var r0 <-chan *dbus.Signal - if rf, ok := ret.Get(0).(func() <-chan *dbus.Signal); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan *dbus.Signal) - } - } - - return r0 -} - -// MockNetworkManager_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' -type MockNetworkManager_Subscribe_Call struct { - *mock.Call -} - -// Subscribe is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) Subscribe() *MockNetworkManager_Subscribe_Call { - return &MockNetworkManager_Subscribe_Call{Call: _e.mock.On("Subscribe")} -} - -func (_c *MockNetworkManager_Subscribe_Call) Run(run func()) *MockNetworkManager_Subscribe_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_Subscribe_Call) Return(_a0 <-chan *dbus.Signal) *MockNetworkManager_Subscribe_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockNetworkManager_Subscribe_Call) RunAndReturn(run func() <-chan *dbus.Signal) *MockNetworkManager_Subscribe_Call { - _c.Call.Return(run) - return _c -} - -// Unsubscribe provides a mock function with no fields -func (_m *MockNetworkManager) Unsubscribe() { - _m.Called() -} - -// MockNetworkManager_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe' -type MockNetworkManager_Unsubscribe_Call struct { - *mock.Call -} - -// Unsubscribe is a helper method to define mock.On call -func (_e *MockNetworkManager_Expecter) Unsubscribe() *MockNetworkManager_Unsubscribe_Call { - return &MockNetworkManager_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe")} -} - -func (_c *MockNetworkManager_Unsubscribe_Call) Run(run func()) *MockNetworkManager_Unsubscribe_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockNetworkManager_Unsubscribe_Call) Return() *MockNetworkManager_Unsubscribe_Call { - _c.Call.Return() - return _c -} - -func (_c *MockNetworkManager_Unsubscribe_Call) RunAndReturn(run func()) *MockNetworkManager_Unsubscribe_Call { - _c.Run(run) - return _c -} - -// NewMockNetworkManager creates a new instance of MockNetworkManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockNetworkManager(t interface { - mock.TestingT - Cleanup(func()) -}) *MockNetworkManager { - mock := &MockNetworkManager{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go deleted file mode 100644 index 20f488e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go +++ /dev/null @@ -1,467 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package gonetworkmanager - -import ( - gonetworkmanager "github.com/Wifx/gonetworkmanager/v2" - mock "github.com/stretchr/testify/mock" -) - -// MockSettings is an autogenerated mock type for the Settings type -type MockSettings struct { - mock.Mock -} - -type MockSettings_Expecter struct { - mock *mock.Mock -} - -func (_m *MockSettings) EXPECT() *MockSettings_Expecter { - return &MockSettings_Expecter{mock: &_m.Mock} -} - -// AddConnection provides a mock function with given fields: settings -func (_m *MockSettings) AddConnection(settings gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error) { - ret := _m.Called(settings) - - if len(ret) == 0 { - panic("no return value specified for AddConnection") - } - - var r0 gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)); ok { - return rf(settings) - } - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) gonetworkmanager.Connection); ok { - r0 = rf(settings) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func(gonetworkmanager.ConnectionSettings) error); ok { - r1 = rf(settings) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_AddConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddConnection' -type MockSettings_AddConnection_Call struct { - *mock.Call -} - -// AddConnection is a helper method to define mock.On call -// - settings gonetworkmanager.ConnectionSettings -func (_e *MockSettings_Expecter) AddConnection(settings interface{}) *MockSettings_AddConnection_Call { - return &MockSettings_AddConnection_Call{Call: _e.mock.On("AddConnection", settings)} -} - -func (_c *MockSettings_AddConnection_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockSettings_AddConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.ConnectionSettings)) - }) - return _c -} - -func (_c *MockSettings_AddConnection_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_AddConnection_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_AddConnection_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)) *MockSettings_AddConnection_Call { - _c.Call.Return(run) - return _c -} - -// AddConnectionUnsaved provides a mock function with given fields: settings -func (_m *MockSettings) AddConnectionUnsaved(settings gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error) { - ret := _m.Called(settings) - - if len(ret) == 0 { - panic("no return value specified for AddConnectionUnsaved") - } - - var r0 gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)); ok { - return rf(settings) - } - if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) gonetworkmanager.Connection); ok { - r0 = rf(settings) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func(gonetworkmanager.ConnectionSettings) error); ok { - r1 = rf(settings) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_AddConnectionUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddConnectionUnsaved' -type MockSettings_AddConnectionUnsaved_Call struct { - *mock.Call -} - -// AddConnectionUnsaved is a helper method to define mock.On call -// - settings gonetworkmanager.ConnectionSettings -func (_e *MockSettings_Expecter) AddConnectionUnsaved(settings interface{}) *MockSettings_AddConnectionUnsaved_Call { - return &MockSettings_AddConnectionUnsaved_Call{Call: _e.mock.On("AddConnectionUnsaved", settings)} -} - -func (_c *MockSettings_AddConnectionUnsaved_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockSettings_AddConnectionUnsaved_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(gonetworkmanager.ConnectionSettings)) - }) - return _c -} - -func (_c *MockSettings_AddConnectionUnsaved_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_AddConnectionUnsaved_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_AddConnectionUnsaved_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)) *MockSettings_AddConnectionUnsaved_Call { - _c.Call.Return(run) - return _c -} - -// GetConnectionByUUID provides a mock function with given fields: uuid -func (_m *MockSettings) GetConnectionByUUID(uuid string) (gonetworkmanager.Connection, error) { - ret := _m.Called(uuid) - - if len(ret) == 0 { - panic("no return value specified for GetConnectionByUUID") - } - - var r0 gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.Connection, error)); ok { - return rf(uuid) - } - if rf, ok := ret.Get(0).(func(string) gonetworkmanager.Connection); ok { - r0 = rf(uuid) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(uuid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_GetConnectionByUUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConnectionByUUID' -type MockSettings_GetConnectionByUUID_Call struct { - *mock.Call -} - -// GetConnectionByUUID is a helper method to define mock.On call -// - uuid string -func (_e *MockSettings_Expecter) GetConnectionByUUID(uuid interface{}) *MockSettings_GetConnectionByUUID_Call { - return &MockSettings_GetConnectionByUUID_Call{Call: _e.mock.On("GetConnectionByUUID", uuid)} -} - -func (_c *MockSettings_GetConnectionByUUID_Call) Run(run func(uuid string)) *MockSettings_GetConnectionByUUID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockSettings_GetConnectionByUUID_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_GetConnectionByUUID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_GetConnectionByUUID_Call) RunAndReturn(run func(string) (gonetworkmanager.Connection, error)) *MockSettings_GetConnectionByUUID_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyCanModify provides a mock function with no fields -func (_m *MockSettings) GetPropertyCanModify() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyCanModify") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_GetPropertyCanModify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCanModify' -type MockSettings_GetPropertyCanModify_Call struct { - *mock.Call -} - -// GetPropertyCanModify is a helper method to define mock.On call -func (_e *MockSettings_Expecter) GetPropertyCanModify() *MockSettings_GetPropertyCanModify_Call { - return &MockSettings_GetPropertyCanModify_Call{Call: _e.mock.On("GetPropertyCanModify")} -} - -func (_c *MockSettings_GetPropertyCanModify_Call) Run(run func()) *MockSettings_GetPropertyCanModify_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSettings_GetPropertyCanModify_Call) Return(_a0 bool, _a1 error) *MockSettings_GetPropertyCanModify_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_GetPropertyCanModify_Call) RunAndReturn(run func() (bool, error)) *MockSettings_GetPropertyCanModify_Call { - _c.Call.Return(run) - return _c -} - -// GetPropertyHostname provides a mock function with no fields -func (_m *MockSettings) GetPropertyHostname() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPropertyHostname") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_GetPropertyHostname_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHostname' -type MockSettings_GetPropertyHostname_Call struct { - *mock.Call -} - -// GetPropertyHostname is a helper method to define mock.On call -func (_e *MockSettings_Expecter) GetPropertyHostname() *MockSettings_GetPropertyHostname_Call { - return &MockSettings_GetPropertyHostname_Call{Call: _e.mock.On("GetPropertyHostname")} -} - -func (_c *MockSettings_GetPropertyHostname_Call) Run(run func()) *MockSettings_GetPropertyHostname_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSettings_GetPropertyHostname_Call) Return(_a0 string, _a1 error) *MockSettings_GetPropertyHostname_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_GetPropertyHostname_Call) RunAndReturn(run func() (string, error)) *MockSettings_GetPropertyHostname_Call { - _c.Call.Return(run) - return _c -} - -// ListConnections provides a mock function with no fields -func (_m *MockSettings) ListConnections() ([]gonetworkmanager.Connection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ListConnections") - } - - var r0 []gonetworkmanager.Connection - var r1 error - if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]gonetworkmanager.Connection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSettings_ListConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListConnections' -type MockSettings_ListConnections_Call struct { - *mock.Call -} - -// ListConnections is a helper method to define mock.On call -func (_e *MockSettings_Expecter) ListConnections() *MockSettings_ListConnections_Call { - return &MockSettings_ListConnections_Call{Call: _e.mock.On("ListConnections")} -} - -func (_c *MockSettings_ListConnections_Call) Run(run func()) *MockSettings_ListConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSettings_ListConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockSettings_ListConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSettings_ListConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockSettings_ListConnections_Call { - _c.Call.Return(run) - return _c -} - -// ReloadConnections provides a mock function with no fields -func (_m *MockSettings) ReloadConnections() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ReloadConnections") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockSettings_ReloadConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReloadConnections' -type MockSettings_ReloadConnections_Call struct { - *mock.Call -} - -// ReloadConnections is a helper method to define mock.On call -func (_e *MockSettings_Expecter) ReloadConnections() *MockSettings_ReloadConnections_Call { - return &MockSettings_ReloadConnections_Call{Call: _e.mock.On("ReloadConnections")} -} - -func (_c *MockSettings_ReloadConnections_Call) Run(run func()) *MockSettings_ReloadConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSettings_ReloadConnections_Call) Return(_a0 error) *MockSettings_ReloadConnections_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockSettings_ReloadConnections_Call) RunAndReturn(run func() error) *MockSettings_ReloadConnections_Call { - _c.Call.Return(run) - return _c -} - -// SaveHostname provides a mock function with given fields: hostname -func (_m *MockSettings) SaveHostname(hostname string) error { - ret := _m.Called(hostname) - - if len(ret) == 0 { - panic("no return value specified for SaveHostname") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(hostname) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockSettings_SaveHostname_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveHostname' -type MockSettings_SaveHostname_Call struct { - *mock.Call -} - -// SaveHostname is a helper method to define mock.On call -// - hostname string -func (_e *MockSettings_Expecter) SaveHostname(hostname interface{}) *MockSettings_SaveHostname_Call { - return &MockSettings_SaveHostname_Call{Call: _e.mock.On("SaveHostname", hostname)} -} - -func (_c *MockSettings_SaveHostname_Call) Run(run func(hostname string)) *MockSettings_SaveHostname_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockSettings_SaveHostname_Call) Return(_a0 error) *MockSettings_SaveHostname_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockSettings_SaveHostname_Call) RunAndReturn(run func(string) error) *MockSettings_SaveHostname_Call { - _c.Call.Return(run) - return _c -} - -// NewMockSettings creates a new instance of MockSettings. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockSettings(t interface { - mock.TestingT - Cleanup(func()) -}) *MockSettings { - mock := &MockSettings{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go deleted file mode 100644 index c0d1a3f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go +++ /dev/null @@ -1,649 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package dbus - -import ( - context "context" - - dbus "github.com/godbus/dbus/v5" - mock "github.com/stretchr/testify/mock" -) - -// MockBusObject is an autogenerated mock type for the BusObject type -type MockBusObject struct { - mock.Mock -} - -type MockBusObject_Expecter struct { - mock *mock.Mock -} - -func (_m *MockBusObject) EXPECT() *MockBusObject_Expecter { - return &MockBusObject_Expecter{mock: &_m.Mock} -} - -// AddMatchSignal provides a mock function with given fields: iface, member, options -func (_m *MockBusObject) AddMatchSignal(iface string, member string, options ...dbus.MatchOption) *dbus.Call { - _va := make([]interface{}, len(options)) - for _i := range options { - _va[_i] = options[_i] - } - var _ca []interface{} - _ca = append(_ca, iface, member) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for AddMatchSignal") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(string, string, ...dbus.MatchOption) *dbus.Call); ok { - r0 = rf(iface, member, options...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_AddMatchSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMatchSignal' -type MockBusObject_AddMatchSignal_Call struct { - *mock.Call -} - -// AddMatchSignal is a helper method to define mock.On call -// - iface string -// - member string -// - options ...dbus.MatchOption -func (_e *MockBusObject_Expecter) AddMatchSignal(iface interface{}, member interface{}, options ...interface{}) *MockBusObject_AddMatchSignal_Call { - return &MockBusObject_AddMatchSignal_Call{Call: _e.mock.On("AddMatchSignal", - append([]interface{}{iface, member}, options...)...)} -} - -func (_c *MockBusObject_AddMatchSignal_Call) Run(run func(iface string, member string, options ...dbus.MatchOption)) *MockBusObject_AddMatchSignal_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]dbus.MatchOption, len(args)-2) - for i, a := range args[2:] { - if a != nil { - variadicArgs[i] = a.(dbus.MatchOption) - } - } - run(args[0].(string), args[1].(string), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_AddMatchSignal_Call) Return(_a0 *dbus.Call) *MockBusObject_AddMatchSignal_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_AddMatchSignal_Call) RunAndReturn(run func(string, string, ...dbus.MatchOption) *dbus.Call) *MockBusObject_AddMatchSignal_Call { - _c.Call.Return(run) - return _c -} - -// Call provides a mock function with given fields: method, flags, args -func (_m *MockBusObject) Call(method string, flags dbus.Flags, args ...interface{}) *dbus.Call { - var _ca []interface{} - _ca = append(_ca, method, flags) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for Call") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(string, dbus.Flags, ...interface{}) *dbus.Call); ok { - r0 = rf(method, flags, args...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_Call_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Call' -type MockBusObject_Call_Call struct { - *mock.Call -} - -// Call is a helper method to define mock.On call -// - method string -// - flags dbus.Flags -// - args ...interface{} -func (_e *MockBusObject_Expecter) Call(method interface{}, flags interface{}, args ...interface{}) *MockBusObject_Call_Call { - return &MockBusObject_Call_Call{Call: _e.mock.On("Call", - append([]interface{}{method, flags}, args...)...)} -} - -func (_c *MockBusObject_Call_Call) Run(run func(method string, flags dbus.Flags, args ...interface{})) *MockBusObject_Call_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-2) - for i, a := range args[2:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(string), args[1].(dbus.Flags), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_Call_Call) Return(_a0 *dbus.Call) *MockBusObject_Call_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_Call_Call) RunAndReturn(run func(string, dbus.Flags, ...interface{}) *dbus.Call) *MockBusObject_Call_Call { - _c.Call.Return(run) - return _c -} - -// CallWithContext provides a mock function with given fields: ctx, method, flags, args -func (_m *MockBusObject) CallWithContext(ctx context.Context, method string, flags dbus.Flags, args ...interface{}) *dbus.Call { - var _ca []interface{} - _ca = append(_ca, ctx, method, flags) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for CallWithContext") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(context.Context, string, dbus.Flags, ...interface{}) *dbus.Call); ok { - r0 = rf(ctx, method, flags, args...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_CallWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CallWithContext' -type MockBusObject_CallWithContext_Call struct { - *mock.Call -} - -// CallWithContext is a helper method to define mock.On call -// - ctx context.Context -// - method string -// - flags dbus.Flags -// - args ...interface{} -func (_e *MockBusObject_Expecter) CallWithContext(ctx interface{}, method interface{}, flags interface{}, args ...interface{}) *MockBusObject_CallWithContext_Call { - return &MockBusObject_CallWithContext_Call{Call: _e.mock.On("CallWithContext", - append([]interface{}{ctx, method, flags}, args...)...)} -} - -func (_c *MockBusObject_CallWithContext_Call) Run(run func(ctx context.Context, method string, flags dbus.Flags, args ...interface{})) *MockBusObject_CallWithContext_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-3) - for i, a := range args[3:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(context.Context), args[1].(string), args[2].(dbus.Flags), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_CallWithContext_Call) Return(_a0 *dbus.Call) *MockBusObject_CallWithContext_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_CallWithContext_Call) RunAndReturn(run func(context.Context, string, dbus.Flags, ...interface{}) *dbus.Call) *MockBusObject_CallWithContext_Call { - _c.Call.Return(run) - return _c -} - -// Destination provides a mock function with no fields -func (_m *MockBusObject) Destination() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Destination") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// MockBusObject_Destination_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destination' -type MockBusObject_Destination_Call struct { - *mock.Call -} - -// Destination is a helper method to define mock.On call -func (_e *MockBusObject_Expecter) Destination() *MockBusObject_Destination_Call { - return &MockBusObject_Destination_Call{Call: _e.mock.On("Destination")} -} - -func (_c *MockBusObject_Destination_Call) Run(run func()) *MockBusObject_Destination_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBusObject_Destination_Call) Return(_a0 string) *MockBusObject_Destination_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_Destination_Call) RunAndReturn(run func() string) *MockBusObject_Destination_Call { - _c.Call.Return(run) - return _c -} - -// GetProperty provides a mock function with given fields: p -func (_m *MockBusObject) GetProperty(p string) (dbus.Variant, error) { - ret := _m.Called(p) - - if len(ret) == 0 { - panic("no return value specified for GetProperty") - } - - var r0 dbus.Variant - var r1 error - if rf, ok := ret.Get(0).(func(string) (dbus.Variant, error)); ok { - return rf(p) - } - if rf, ok := ret.Get(0).(func(string) dbus.Variant); ok { - r0 = rf(p) - } else { - r0 = ret.Get(0).(dbus.Variant) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(p) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBusObject_GetProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProperty' -type MockBusObject_GetProperty_Call struct { - *mock.Call -} - -// GetProperty is a helper method to define mock.On call -// - p string -func (_e *MockBusObject_Expecter) GetProperty(p interface{}) *MockBusObject_GetProperty_Call { - return &MockBusObject_GetProperty_Call{Call: _e.mock.On("GetProperty", p)} -} - -func (_c *MockBusObject_GetProperty_Call) Run(run func(p string)) *MockBusObject_GetProperty_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBusObject_GetProperty_Call) Return(_a0 dbus.Variant, _a1 error) *MockBusObject_GetProperty_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBusObject_GetProperty_Call) RunAndReturn(run func(string) (dbus.Variant, error)) *MockBusObject_GetProperty_Call { - _c.Call.Return(run) - return _c -} - -// Go provides a mock function with given fields: method, flags, ch, args -func (_m *MockBusObject) Go(method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{}) *dbus.Call { - var _ca []interface{} - _ca = append(_ca, method, flags, ch) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for Go") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call); ok { - r0 = rf(method, flags, ch, args...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_Go_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Go' -type MockBusObject_Go_Call struct { - *mock.Call -} - -// Go is a helper method to define mock.On call -// - method string -// - flags dbus.Flags -// - ch chan *dbus.Call -// - args ...interface{} -func (_e *MockBusObject_Expecter) Go(method interface{}, flags interface{}, ch interface{}, args ...interface{}) *MockBusObject_Go_Call { - return &MockBusObject_Go_Call{Call: _e.mock.On("Go", - append([]interface{}{method, flags, ch}, args...)...)} -} - -func (_c *MockBusObject_Go_Call) Run(run func(method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{})) *MockBusObject_Go_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-3) - for i, a := range args[3:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(string), args[1].(dbus.Flags), args[2].(chan *dbus.Call), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_Go_Call) Return(_a0 *dbus.Call) *MockBusObject_Go_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_Go_Call) RunAndReturn(run func(string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call) *MockBusObject_Go_Call { - _c.Call.Return(run) - return _c -} - -// GoWithContext provides a mock function with given fields: ctx, method, flags, ch, args -func (_m *MockBusObject) GoWithContext(ctx context.Context, method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{}) *dbus.Call { - var _ca []interface{} - _ca = append(_ca, ctx, method, flags, ch) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for GoWithContext") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(context.Context, string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call); ok { - r0 = rf(ctx, method, flags, ch, args...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_GoWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GoWithContext' -type MockBusObject_GoWithContext_Call struct { - *mock.Call -} - -// GoWithContext is a helper method to define mock.On call -// - ctx context.Context -// - method string -// - flags dbus.Flags -// - ch chan *dbus.Call -// - args ...interface{} -func (_e *MockBusObject_Expecter) GoWithContext(ctx interface{}, method interface{}, flags interface{}, ch interface{}, args ...interface{}) *MockBusObject_GoWithContext_Call { - return &MockBusObject_GoWithContext_Call{Call: _e.mock.On("GoWithContext", - append([]interface{}{ctx, method, flags, ch}, args...)...)} -} - -func (_c *MockBusObject_GoWithContext_Call) Run(run func(ctx context.Context, method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{})) *MockBusObject_GoWithContext_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-4) - for i, a := range args[4:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(context.Context), args[1].(string), args[2].(dbus.Flags), args[3].(chan *dbus.Call), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_GoWithContext_Call) Return(_a0 *dbus.Call) *MockBusObject_GoWithContext_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_GoWithContext_Call) RunAndReturn(run func(context.Context, string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call) *MockBusObject_GoWithContext_Call { - _c.Call.Return(run) - return _c -} - -// Path provides a mock function with no fields -func (_m *MockBusObject) Path() dbus.ObjectPath { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Path") - } - - var r0 dbus.ObjectPath - if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(dbus.ObjectPath) - } - - return r0 -} - -// MockBusObject_Path_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Path' -type MockBusObject_Path_Call struct { - *mock.Call -} - -// Path is a helper method to define mock.On call -func (_e *MockBusObject_Expecter) Path() *MockBusObject_Path_Call { - return &MockBusObject_Path_Call{Call: _e.mock.On("Path")} -} - -func (_c *MockBusObject_Path_Call) Run(run func()) *MockBusObject_Path_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBusObject_Path_Call) Return(_a0 dbus.ObjectPath) *MockBusObject_Path_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_Path_Call) RunAndReturn(run func() dbus.ObjectPath) *MockBusObject_Path_Call { - _c.Call.Return(run) - return _c -} - -// RemoveMatchSignal provides a mock function with given fields: iface, member, options -func (_m *MockBusObject) RemoveMatchSignal(iface string, member string, options ...dbus.MatchOption) *dbus.Call { - _va := make([]interface{}, len(options)) - for _i := range options { - _va[_i] = options[_i] - } - var _ca []interface{} - _ca = append(_ca, iface, member) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for RemoveMatchSignal") - } - - var r0 *dbus.Call - if rf, ok := ret.Get(0).(func(string, string, ...dbus.MatchOption) *dbus.Call); ok { - r0 = rf(iface, member, options...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dbus.Call) - } - } - - return r0 -} - -// MockBusObject_RemoveMatchSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveMatchSignal' -type MockBusObject_RemoveMatchSignal_Call struct { - *mock.Call -} - -// RemoveMatchSignal is a helper method to define mock.On call -// - iface string -// - member string -// - options ...dbus.MatchOption -func (_e *MockBusObject_Expecter) RemoveMatchSignal(iface interface{}, member interface{}, options ...interface{}) *MockBusObject_RemoveMatchSignal_Call { - return &MockBusObject_RemoveMatchSignal_Call{Call: _e.mock.On("RemoveMatchSignal", - append([]interface{}{iface, member}, options...)...)} -} - -func (_c *MockBusObject_RemoveMatchSignal_Call) Run(run func(iface string, member string, options ...dbus.MatchOption)) *MockBusObject_RemoveMatchSignal_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]dbus.MatchOption, len(args)-2) - for i, a := range args[2:] { - if a != nil { - variadicArgs[i] = a.(dbus.MatchOption) - } - } - run(args[0].(string), args[1].(string), variadicArgs...) - }) - return _c -} - -func (_c *MockBusObject_RemoveMatchSignal_Call) Return(_a0 *dbus.Call) *MockBusObject_RemoveMatchSignal_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_RemoveMatchSignal_Call) RunAndReturn(run func(string, string, ...dbus.MatchOption) *dbus.Call) *MockBusObject_RemoveMatchSignal_Call { - _c.Call.Return(run) - return _c -} - -// SetProperty provides a mock function with given fields: p, v -func (_m *MockBusObject) SetProperty(p string, v interface{}) error { - ret := _m.Called(p, v) - - if len(ret) == 0 { - panic("no return value specified for SetProperty") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { - r0 = rf(p, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBusObject_SetProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetProperty' -type MockBusObject_SetProperty_Call struct { - *mock.Call -} - -// SetProperty is a helper method to define mock.On call -// - p string -// - v interface{} -func (_e *MockBusObject_Expecter) SetProperty(p interface{}, v interface{}) *MockBusObject_SetProperty_Call { - return &MockBusObject_SetProperty_Call{Call: _e.mock.On("SetProperty", p, v)} -} - -func (_c *MockBusObject_SetProperty_Call) Run(run func(p string, v interface{})) *MockBusObject_SetProperty_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(interface{})) - }) - return _c -} - -func (_c *MockBusObject_SetProperty_Call) Return(_a0 error) *MockBusObject_SetProperty_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_SetProperty_Call) RunAndReturn(run func(string, interface{}) error) *MockBusObject_SetProperty_Call { - _c.Call.Return(run) - return _c -} - -// StoreProperty provides a mock function with given fields: p, value -func (_m *MockBusObject) StoreProperty(p string, value interface{}) error { - ret := _m.Called(p, value) - - if len(ret) == 0 { - panic("no return value specified for StoreProperty") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { - r0 = rf(p, value) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBusObject_StoreProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreProperty' -type MockBusObject_StoreProperty_Call struct { - *mock.Call -} - -// StoreProperty is a helper method to define mock.On call -// - p string -// - value interface{} -func (_e *MockBusObject_Expecter) StoreProperty(p interface{}, value interface{}) *MockBusObject_StoreProperty_Call { - return &MockBusObject_StoreProperty_Call{Call: _e.mock.On("StoreProperty", p, value)} -} - -func (_c *MockBusObject_StoreProperty_Call) Run(run func(p string, value interface{})) *MockBusObject_StoreProperty_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(interface{})) - }) - return _c -} - -func (_c *MockBusObject_StoreProperty_Call) Return(_a0 error) *MockBusObject_StoreProperty_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBusObject_StoreProperty_Call) RunAndReturn(run func(string, interface{}) error) *MockBusObject_StoreProperty_Call { - _c.Call.Return(run) - return _c -} - -// NewMockBusObject creates a new instance of MockBusObject. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockBusObject(t interface { - mock.TestingT - Cleanup(func()) -}) *MockBusObject { - mock := &MockBusObject{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/internal/plugins/mock_GitClient.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/internal/plugins/mock_GitClient.go deleted file mode 100644 index 23e34f3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/internal/plugins/mock_GitClient.go +++ /dev/null @@ -1,181 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package plugins - -import mock "github.com/stretchr/testify/mock" - -// MockGitClient is an autogenerated mock type for the GitClient type -type MockGitClient struct { - mock.Mock -} - -type MockGitClient_Expecter struct { - mock *mock.Mock -} - -func (_m *MockGitClient) EXPECT() *MockGitClient_Expecter { - return &MockGitClient_Expecter{mock: &_m.Mock} -} - -// HasUpdates provides a mock function with given fields: path -func (_m *MockGitClient) HasUpdates(path string) (bool, error) { - ret := _m.Called(path) - - if len(ret) == 0 { - panic("no return value specified for HasUpdates") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { - return rf(path) - } - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(path) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(path) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockGitClient_HasUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasUpdates' -type MockGitClient_HasUpdates_Call struct { - *mock.Call -} - -// HasUpdates is a helper method to define mock.On call -// - path string -func (_e *MockGitClient_Expecter) HasUpdates(path any) *MockGitClient_HasUpdates_Call { - return &MockGitClient_HasUpdates_Call{Call: _e.mock.On("HasUpdates", path)} -} - -func (_c *MockGitClient_HasUpdates_Call) Run(run func(path string)) *MockGitClient_HasUpdates_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockGitClient_HasUpdates_Call) Return(_a0 bool, _a1 error) *MockGitClient_HasUpdates_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockGitClient_HasUpdates_Call) RunAndReturn(run func(string) (bool, error)) *MockGitClient_HasUpdates_Call { - _c.Call.Return(run) - return _c -} - -// PlainClone provides a mock function with given fields: path, url -func (_m *MockGitClient) PlainClone(path string, url string) error { - ret := _m.Called(path, url) - - if len(ret) == 0 { - panic("no return value specified for PlainClone") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(path, url) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockGitClient_PlainClone_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PlainClone' -type MockGitClient_PlainClone_Call struct { - *mock.Call -} - -// PlainClone is a helper method to define mock.On call -// - path string -// - url string -func (_e *MockGitClient_Expecter) PlainClone(path any, url any) *MockGitClient_PlainClone_Call { - return &MockGitClient_PlainClone_Call{Call: _e.mock.On("PlainClone", path, url)} -} - -func (_c *MockGitClient_PlainClone_Call) Run(run func(path string, url string)) *MockGitClient_PlainClone_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockGitClient_PlainClone_Call) Return(_a0 error) *MockGitClient_PlainClone_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockGitClient_PlainClone_Call) RunAndReturn(run func(string, string) error) *MockGitClient_PlainClone_Call { - _c.Call.Return(run) - return _c -} - -// Pull provides a mock function with given fields: path -func (_m *MockGitClient) Pull(path string) error { - ret := _m.Called(path) - - if len(ret) == 0 { - panic("no return value specified for Pull") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(path) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockGitClient_Pull_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pull' -type MockGitClient_Pull_Call struct { - *mock.Call -} - -// Pull is a helper method to define mock.On call -// - path string -func (_e *MockGitClient_Expecter) Pull(path any) *MockGitClient_Pull_Call { - return &MockGitClient_Pull_Call{Call: _e.mock.On("Pull", path)} -} - -func (_c *MockGitClient_Pull_Call) Run(run func(path string)) *MockGitClient_Pull_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockGitClient_Pull_Call) Return(_a0 error) *MockGitClient_Pull_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockGitClient_Pull_Call) RunAndReturn(run func(string) error) *MockGitClient_Pull_Call { - _c.Call.Return(run) - return _c -} - -// NewMockGitClient creates a new instance of MockGitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockGitClient(t interface { - mock.TestingT - Cleanup(func()) -}) *MockGitClient { - mock := &MockGitClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/net/mock_Conn.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/net/mock_Conn.go deleted file mode 100644 index 248a0d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/net/mock_Conn.go +++ /dev/null @@ -1,427 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package net - -import ( - net "net" - - mock "github.com/stretchr/testify/mock" - - time "time" -) - -// MockConn is an autogenerated mock type for the Conn type -type MockConn struct { - mock.Mock -} - -type MockConn_Expecter struct { - mock *mock.Mock -} - -func (_m *MockConn) EXPECT() *MockConn_Expecter { - return &MockConn_Expecter{mock: &_m.Mock} -} - -// Close provides a mock function with no fields -func (_m *MockConn) Close() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConn_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockConn_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockConn_Expecter) Close() *MockConn_Close_Call { - return &MockConn_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockConn_Close_Call) Run(run func()) *MockConn_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConn_Close_Call) Return(_a0 error) *MockConn_Close_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_Close_Call) RunAndReturn(run func() error) *MockConn_Close_Call { - _c.Call.Return(run) - return _c -} - -// LocalAddr provides a mock function with no fields -func (_m *MockConn) LocalAddr() net.Addr { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for LocalAddr") - } - - var r0 net.Addr - if rf, ok := ret.Get(0).(func() net.Addr); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(net.Addr) - } - } - - return r0 -} - -// MockConn_LocalAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LocalAddr' -type MockConn_LocalAddr_Call struct { - *mock.Call -} - -// LocalAddr is a helper method to define mock.On call -func (_e *MockConn_Expecter) LocalAddr() *MockConn_LocalAddr_Call { - return &MockConn_LocalAddr_Call{Call: _e.mock.On("LocalAddr")} -} - -func (_c *MockConn_LocalAddr_Call) Run(run func()) *MockConn_LocalAddr_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConn_LocalAddr_Call) Return(_a0 net.Addr) *MockConn_LocalAddr_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_LocalAddr_Call) RunAndReturn(run func() net.Addr) *MockConn_LocalAddr_Call { - _c.Call.Return(run) - return _c -} - -// Read provides a mock function with given fields: b -func (_m *MockConn) Read(b []byte) (int, error) { - ret := _m.Called(b) - - if len(ret) == 0 { - panic("no return value specified for Read") - } - - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok { - return rf(b) - } - if rf, ok := ret.Get(0).(func([]byte) int); ok { - r0 = rf(b) - } else { - r0 = ret.Get(0).(int) - } - - if rf, ok := ret.Get(1).(func([]byte) error); ok { - r1 = rf(b) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConn_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read' -type MockConn_Read_Call struct { - *mock.Call -} - -// Read is a helper method to define mock.On call -// - b []byte -func (_e *MockConn_Expecter) Read(b interface{}) *MockConn_Read_Call { - return &MockConn_Read_Call{Call: _e.mock.On("Read", b)} -} - -func (_c *MockConn_Read_Call) Run(run func(b []byte)) *MockConn_Read_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]byte)) - }) - return _c -} - -func (_c *MockConn_Read_Call) Return(n int, err error) *MockConn_Read_Call { - _c.Call.Return(n, err) - return _c -} - -func (_c *MockConn_Read_Call) RunAndReturn(run func([]byte) (int, error)) *MockConn_Read_Call { - _c.Call.Return(run) - return _c -} - -// RemoteAddr provides a mock function with no fields -func (_m *MockConn) RemoteAddr() net.Addr { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for RemoteAddr") - } - - var r0 net.Addr - if rf, ok := ret.Get(0).(func() net.Addr); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(net.Addr) - } - } - - return r0 -} - -// MockConn_RemoteAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteAddr' -type MockConn_RemoteAddr_Call struct { - *mock.Call -} - -// RemoteAddr is a helper method to define mock.On call -func (_e *MockConn_Expecter) RemoteAddr() *MockConn_RemoteAddr_Call { - return &MockConn_RemoteAddr_Call{Call: _e.mock.On("RemoteAddr")} -} - -func (_c *MockConn_RemoteAddr_Call) Run(run func()) *MockConn_RemoteAddr_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockConn_RemoteAddr_Call) Return(_a0 net.Addr) *MockConn_RemoteAddr_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_RemoteAddr_Call) RunAndReturn(run func() net.Addr) *MockConn_RemoteAddr_Call { - _c.Call.Return(run) - return _c -} - -// SetDeadline provides a mock function with given fields: t -func (_m *MockConn) SetDeadline(t time.Time) error { - ret := _m.Called(t) - - if len(ret) == 0 { - panic("no return value specified for SetDeadline") - } - - var r0 error - if rf, ok := ret.Get(0).(func(time.Time) error); ok { - r0 = rf(t) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConn_SetDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDeadline' -type MockConn_SetDeadline_Call struct { - *mock.Call -} - -// SetDeadline is a helper method to define mock.On call -// - t time.Time -func (_e *MockConn_Expecter) SetDeadline(t interface{}) *MockConn_SetDeadline_Call { - return &MockConn_SetDeadline_Call{Call: _e.mock.On("SetDeadline", t)} -} - -func (_c *MockConn_SetDeadline_Call) Run(run func(t time.Time)) *MockConn_SetDeadline_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(time.Time)) - }) - return _c -} - -func (_c *MockConn_SetDeadline_Call) Return(_a0 error) *MockConn_SetDeadline_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_SetDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetDeadline_Call { - _c.Call.Return(run) - return _c -} - -// SetReadDeadline provides a mock function with given fields: t -func (_m *MockConn) SetReadDeadline(t time.Time) error { - ret := _m.Called(t) - - if len(ret) == 0 { - panic("no return value specified for SetReadDeadline") - } - - var r0 error - if rf, ok := ret.Get(0).(func(time.Time) error); ok { - r0 = rf(t) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConn_SetReadDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetReadDeadline' -type MockConn_SetReadDeadline_Call struct { - *mock.Call -} - -// SetReadDeadline is a helper method to define mock.On call -// - t time.Time -func (_e *MockConn_Expecter) SetReadDeadline(t interface{}) *MockConn_SetReadDeadline_Call { - return &MockConn_SetReadDeadline_Call{Call: _e.mock.On("SetReadDeadline", t)} -} - -func (_c *MockConn_SetReadDeadline_Call) Run(run func(t time.Time)) *MockConn_SetReadDeadline_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(time.Time)) - }) - return _c -} - -func (_c *MockConn_SetReadDeadline_Call) Return(_a0 error) *MockConn_SetReadDeadline_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_SetReadDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetReadDeadline_Call { - _c.Call.Return(run) - return _c -} - -// SetWriteDeadline provides a mock function with given fields: t -func (_m *MockConn) SetWriteDeadline(t time.Time) error { - ret := _m.Called(t) - - if len(ret) == 0 { - panic("no return value specified for SetWriteDeadline") - } - - var r0 error - if rf, ok := ret.Get(0).(func(time.Time) error); ok { - r0 = rf(t) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockConn_SetWriteDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWriteDeadline' -type MockConn_SetWriteDeadline_Call struct { - *mock.Call -} - -// SetWriteDeadline is a helper method to define mock.On call -// - t time.Time -func (_e *MockConn_Expecter) SetWriteDeadline(t interface{}) *MockConn_SetWriteDeadline_Call { - return &MockConn_SetWriteDeadline_Call{Call: _e.mock.On("SetWriteDeadline", t)} -} - -func (_c *MockConn_SetWriteDeadline_Call) Run(run func(t time.Time)) *MockConn_SetWriteDeadline_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(time.Time)) - }) - return _c -} - -func (_c *MockConn_SetWriteDeadline_Call) Return(_a0 error) *MockConn_SetWriteDeadline_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockConn_SetWriteDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetWriteDeadline_Call { - _c.Call.Return(run) - return _c -} - -// Write provides a mock function with given fields: b -func (_m *MockConn) Write(b []byte) (int, error) { - ret := _m.Called(b) - - if len(ret) == 0 { - panic("no return value specified for Write") - } - - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok { - return rf(b) - } - if rf, ok := ret.Get(0).(func([]byte) int); ok { - r0 = rf(b) - } else { - r0 = ret.Get(0).(int) - } - - if rf, ok := ret.Get(1).(func([]byte) error); ok { - r1 = rf(b) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockConn_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write' -type MockConn_Write_Call struct { - *mock.Call -} - -// Write is a helper method to define mock.On call -// - b []byte -func (_e *MockConn_Expecter) Write(b interface{}) *MockConn_Write_Call { - return &MockConn_Write_Call{Call: _e.mock.On("Write", b)} -} - -func (_c *MockConn_Write_Call) Run(run func(b []byte)) *MockConn_Write_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]byte)) - }) - return _c -} - -func (_c *MockConn_Write_Call) Return(n int, err error) *MockConn_Write_Call { - _c.Call.Return(n, err) - return _c -} - -func (_c *MockConn_Write_Call) RunAndReturn(run func([]byte) (int, error)) *MockConn_Write_Call { - _c.Call.Return(run) - return _c -} - -// NewMockConn creates a new instance of MockConn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockConn(t interface { - mock.TestingT - Cleanup(func()) -}) *MockConn { - mock := &MockConn{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/network/mock_Backend.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/network/mock_Backend.go deleted file mode 100644 index d7eb2df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/network/mock_Backend.go +++ /dev/null @@ -1,1975 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_network - -import ( - network "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - mock "github.com/stretchr/testify/mock" -) - -// MockBackend is an autogenerated mock type for the Backend type -type MockBackend struct { - mock.Mock -} - -type MockBackend_Expecter struct { - mock *mock.Mock -} - -func (_m *MockBackend) EXPECT() *MockBackend_Expecter { - return &MockBackend_Expecter{mock: &_m.Mock} -} - -// ActivateWiredConnection provides a mock function with given fields: uuid -func (_m *MockBackend) ActivateWiredConnection(uuid string) error { - ret := _m.Called(uuid) - - if len(ret) == 0 { - panic("no return value specified for ActivateWiredConnection") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(uuid) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ActivateWiredConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateWiredConnection' -type MockBackend_ActivateWiredConnection_Call struct { - *mock.Call -} - -// ActivateWiredConnection is a helper method to define mock.On call -// - uuid string -func (_e *MockBackend_Expecter) ActivateWiredConnection(uuid interface{}) *MockBackend_ActivateWiredConnection_Call { - return &MockBackend_ActivateWiredConnection_Call{Call: _e.mock.On("ActivateWiredConnection", uuid)} -} - -func (_c *MockBackend_ActivateWiredConnection_Call) Run(run func(uuid string)) *MockBackend_ActivateWiredConnection_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_ActivateWiredConnection_Call) Return(_a0 error) *MockBackend_ActivateWiredConnection_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ActivateWiredConnection_Call) RunAndReturn(run func(string) error) *MockBackend_ActivateWiredConnection_Call { - _c.Call.Return(run) - return _c -} - -// CancelCredentials provides a mock function with given fields: token -func (_m *MockBackend) CancelCredentials(token string) error { - ret := _m.Called(token) - - if len(ret) == 0 { - panic("no return value specified for CancelCredentials") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(token) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_CancelCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelCredentials' -type MockBackend_CancelCredentials_Call struct { - *mock.Call -} - -// CancelCredentials is a helper method to define mock.On call -// - token string -func (_e *MockBackend_Expecter) CancelCredentials(token interface{}) *MockBackend_CancelCredentials_Call { - return &MockBackend_CancelCredentials_Call{Call: _e.mock.On("CancelCredentials", token)} -} - -func (_c *MockBackend_CancelCredentials_Call) Run(run func(token string)) *MockBackend_CancelCredentials_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_CancelCredentials_Call) Return(_a0 error) *MockBackend_CancelCredentials_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_CancelCredentials_Call) RunAndReturn(run func(string) error) *MockBackend_CancelCredentials_Call { - _c.Call.Return(run) - return _c -} - -// ClearVPNCredentials provides a mock function with given fields: uuidOrName -func (_m *MockBackend) ClearVPNCredentials(uuidOrName string) error { - ret := _m.Called(uuidOrName) - - if len(ret) == 0 { - panic("no return value specified for ClearVPNCredentials") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(uuidOrName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ClearVPNCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearVPNCredentials' -type MockBackend_ClearVPNCredentials_Call struct { - *mock.Call -} - -// ClearVPNCredentials is a helper method to define mock.On call -// - uuidOrName string -func (_e *MockBackend_Expecter) ClearVPNCredentials(uuidOrName interface{}) *MockBackend_ClearVPNCredentials_Call { - return &MockBackend_ClearVPNCredentials_Call{Call: _e.mock.On("ClearVPNCredentials", uuidOrName)} -} - -func (_c *MockBackend_ClearVPNCredentials_Call) Run(run func(uuidOrName string)) *MockBackend_ClearVPNCredentials_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_ClearVPNCredentials_Call) Return(_a0 error) *MockBackend_ClearVPNCredentials_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ClearVPNCredentials_Call) RunAndReturn(run func(string) error) *MockBackend_ClearVPNCredentials_Call { - _c.Call.Return(run) - return _c -} - -// Close provides a mock function with no fields -func (_m *MockBackend) Close() { - _m.Called() -} - -// MockBackend_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockBackend_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockBackend_Expecter) Close() *MockBackend_Close_Call { - return &MockBackend_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockBackend_Close_Call) Run(run func()) *MockBackend_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_Close_Call) Return() *MockBackend_Close_Call { - _c.Call.Return() - return _c -} - -func (_c *MockBackend_Close_Call) RunAndReturn(run func()) *MockBackend_Close_Call { - _c.Run(run) - return _c -} - -// ConnectEthernet provides a mock function with no fields -func (_m *MockBackend) ConnectEthernet() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ConnectEthernet") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ConnectEthernet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectEthernet' -type MockBackend_ConnectEthernet_Call struct { - *mock.Call -} - -// ConnectEthernet is a helper method to define mock.On call -func (_e *MockBackend_Expecter) ConnectEthernet() *MockBackend_ConnectEthernet_Call { - return &MockBackend_ConnectEthernet_Call{Call: _e.mock.On("ConnectEthernet")} -} - -func (_c *MockBackend_ConnectEthernet_Call) Run(run func()) *MockBackend_ConnectEthernet_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_ConnectEthernet_Call) Return(_a0 error) *MockBackend_ConnectEthernet_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ConnectEthernet_Call) RunAndReturn(run func() error) *MockBackend_ConnectEthernet_Call { - _c.Call.Return(run) - return _c -} - -// ConnectVPN provides a mock function with given fields: uuidOrName, singleActive -func (_m *MockBackend) ConnectVPN(uuidOrName string, singleActive bool) error { - ret := _m.Called(uuidOrName, singleActive) - - if len(ret) == 0 { - panic("no return value specified for ConnectVPN") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(uuidOrName, singleActive) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ConnectVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectVPN' -type MockBackend_ConnectVPN_Call struct { - *mock.Call -} - -// ConnectVPN is a helper method to define mock.On call -// - uuidOrName string -// - singleActive bool -func (_e *MockBackend_Expecter) ConnectVPN(uuidOrName interface{}, singleActive interface{}) *MockBackend_ConnectVPN_Call { - return &MockBackend_ConnectVPN_Call{Call: _e.mock.On("ConnectVPN", uuidOrName, singleActive)} -} - -func (_c *MockBackend_ConnectVPN_Call) Run(run func(uuidOrName string, singleActive bool)) *MockBackend_ConnectVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockBackend_ConnectVPN_Call) Return(_a0 error) *MockBackend_ConnectVPN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ConnectVPN_Call) RunAndReturn(run func(string, bool) error) *MockBackend_ConnectVPN_Call { - _c.Call.Return(run) - return _c -} - -// ConnectWiFi provides a mock function with given fields: req -func (_m *MockBackend) ConnectWiFi(req network.ConnectionRequest) error { - ret := _m.Called(req) - - if len(ret) == 0 { - panic("no return value specified for ConnectWiFi") - } - - var r0 error - if rf, ok := ret.Get(0).(func(network.ConnectionRequest) error); ok { - r0 = rf(req) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ConnectWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectWiFi' -type MockBackend_ConnectWiFi_Call struct { - *mock.Call -} - -// ConnectWiFi is a helper method to define mock.On call -// - req network.ConnectionRequest -func (_e *MockBackend_Expecter) ConnectWiFi(req interface{}) *MockBackend_ConnectWiFi_Call { - return &MockBackend_ConnectWiFi_Call{Call: _e.mock.On("ConnectWiFi", req)} -} - -func (_c *MockBackend_ConnectWiFi_Call) Run(run func(req network.ConnectionRequest)) *MockBackend_ConnectWiFi_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(network.ConnectionRequest)) - }) - return _c -} - -func (_c *MockBackend_ConnectWiFi_Call) Return(_a0 error) *MockBackend_ConnectWiFi_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ConnectWiFi_Call) RunAndReturn(run func(network.ConnectionRequest) error) *MockBackend_ConnectWiFi_Call { - _c.Call.Return(run) - return _c -} - -// DeleteVPN provides a mock function with given fields: uuidOrName -func (_m *MockBackend) DeleteVPN(uuidOrName string) error { - ret := _m.Called(uuidOrName) - - if len(ret) == 0 { - panic("no return value specified for DeleteVPN") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(uuidOrName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DeleteVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteVPN' -type MockBackend_DeleteVPN_Call struct { - *mock.Call -} - -// DeleteVPN is a helper method to define mock.On call -// - uuidOrName string -func (_e *MockBackend_Expecter) DeleteVPN(uuidOrName interface{}) *MockBackend_DeleteVPN_Call { - return &MockBackend_DeleteVPN_Call{Call: _e.mock.On("DeleteVPN", uuidOrName)} -} - -func (_c *MockBackend_DeleteVPN_Call) Run(run func(uuidOrName string)) *MockBackend_DeleteVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_DeleteVPN_Call) Return(_a0 error) *MockBackend_DeleteVPN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DeleteVPN_Call) RunAndReturn(run func(string) error) *MockBackend_DeleteVPN_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectAllVPN provides a mock function with no fields -func (_m *MockBackend) DisconnectAllVPN() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for DisconnectAllVPN") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectAllVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectAllVPN' -type MockBackend_DisconnectAllVPN_Call struct { - *mock.Call -} - -// DisconnectAllVPN is a helper method to define mock.On call -func (_e *MockBackend_Expecter) DisconnectAllVPN() *MockBackend_DisconnectAllVPN_Call { - return &MockBackend_DisconnectAllVPN_Call{Call: _e.mock.On("DisconnectAllVPN")} -} - -func (_c *MockBackend_DisconnectAllVPN_Call) Run(run func()) *MockBackend_DisconnectAllVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_DisconnectAllVPN_Call) Return(_a0 error) *MockBackend_DisconnectAllVPN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectAllVPN_Call) RunAndReturn(run func() error) *MockBackend_DisconnectAllVPN_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectEthernet provides a mock function with no fields -func (_m *MockBackend) DisconnectEthernet() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for DisconnectEthernet") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectEthernet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectEthernet' -type MockBackend_DisconnectEthernet_Call struct { - *mock.Call -} - -// DisconnectEthernet is a helper method to define mock.On call -func (_e *MockBackend_Expecter) DisconnectEthernet() *MockBackend_DisconnectEthernet_Call { - return &MockBackend_DisconnectEthernet_Call{Call: _e.mock.On("DisconnectEthernet")} -} - -func (_c *MockBackend_DisconnectEthernet_Call) Run(run func()) *MockBackend_DisconnectEthernet_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_DisconnectEthernet_Call) Return(_a0 error) *MockBackend_DisconnectEthernet_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectEthernet_Call) RunAndReturn(run func() error) *MockBackend_DisconnectEthernet_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectEthernetDevice provides a mock function with given fields: device -func (_m *MockBackend) DisconnectEthernetDevice(device string) error { - ret := _m.Called(device) - - if len(ret) == 0 { - panic("no return value specified for DisconnectEthernetDevice") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(device) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectEthernetDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectEthernetDevice' -type MockBackend_DisconnectEthernetDevice_Call struct { - *mock.Call -} - -// DisconnectEthernetDevice is a helper method to define mock.On call -// - device string -func (_e *MockBackend_Expecter) DisconnectEthernetDevice(device interface{}) *MockBackend_DisconnectEthernetDevice_Call { - return &MockBackend_DisconnectEthernetDevice_Call{Call: _e.mock.On("DisconnectEthernetDevice", device)} -} - -func (_c *MockBackend_DisconnectEthernetDevice_Call) Run(run func(device string)) *MockBackend_DisconnectEthernetDevice_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_DisconnectEthernetDevice_Call) Return(_a0 error) *MockBackend_DisconnectEthernetDevice_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectEthernetDevice_Call) RunAndReturn(run func(string) error) *MockBackend_DisconnectEthernetDevice_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectVPN provides a mock function with given fields: uuidOrName -func (_m *MockBackend) DisconnectVPN(uuidOrName string) error { - ret := _m.Called(uuidOrName) - - if len(ret) == 0 { - panic("no return value specified for DisconnectVPN") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(uuidOrName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectVPN' -type MockBackend_DisconnectVPN_Call struct { - *mock.Call -} - -// DisconnectVPN is a helper method to define mock.On call -// - uuidOrName string -func (_e *MockBackend_Expecter) DisconnectVPN(uuidOrName interface{}) *MockBackend_DisconnectVPN_Call { - return &MockBackend_DisconnectVPN_Call{Call: _e.mock.On("DisconnectVPN", uuidOrName)} -} - -func (_c *MockBackend_DisconnectVPN_Call) Run(run func(uuidOrName string)) *MockBackend_DisconnectVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_DisconnectVPN_Call) Return(_a0 error) *MockBackend_DisconnectVPN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectVPN_Call) RunAndReturn(run func(string) error) *MockBackend_DisconnectVPN_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectWiFi provides a mock function with no fields -func (_m *MockBackend) DisconnectWiFi() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for DisconnectWiFi") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectWiFi' -type MockBackend_DisconnectWiFi_Call struct { - *mock.Call -} - -// DisconnectWiFi is a helper method to define mock.On call -func (_e *MockBackend_Expecter) DisconnectWiFi() *MockBackend_DisconnectWiFi_Call { - return &MockBackend_DisconnectWiFi_Call{Call: _e.mock.On("DisconnectWiFi")} -} - -func (_c *MockBackend_DisconnectWiFi_Call) Run(run func()) *MockBackend_DisconnectWiFi_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_DisconnectWiFi_Call) Return(_a0 error) *MockBackend_DisconnectWiFi_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectWiFi_Call) RunAndReturn(run func() error) *MockBackend_DisconnectWiFi_Call { - _c.Call.Return(run) - return _c -} - -// DisconnectWiFiDevice provides a mock function with given fields: device -func (_m *MockBackend) DisconnectWiFiDevice(device string) error { - ret := _m.Called(device) - - if len(ret) == 0 { - panic("no return value specified for DisconnectWiFiDevice") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(device) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_DisconnectWiFiDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectWiFiDevice' -type MockBackend_DisconnectWiFiDevice_Call struct { - *mock.Call -} - -// DisconnectWiFiDevice is a helper method to define mock.On call -// - device string -func (_e *MockBackend_Expecter) DisconnectWiFiDevice(device interface{}) *MockBackend_DisconnectWiFiDevice_Call { - return &MockBackend_DisconnectWiFiDevice_Call{Call: _e.mock.On("DisconnectWiFiDevice", device)} -} - -func (_c *MockBackend_DisconnectWiFiDevice_Call) Run(run func(device string)) *MockBackend_DisconnectWiFiDevice_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_DisconnectWiFiDevice_Call) Return(_a0 error) *MockBackend_DisconnectWiFiDevice_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_DisconnectWiFiDevice_Call) RunAndReturn(run func(string) error) *MockBackend_DisconnectWiFiDevice_Call { - _c.Call.Return(run) - return _c -} - -// ForgetWiFiNetwork provides a mock function with given fields: ssid -func (_m *MockBackend) ForgetWiFiNetwork(ssid string) error { - ret := _m.Called(ssid) - - if len(ret) == 0 { - panic("no return value specified for ForgetWiFiNetwork") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(ssid) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ForgetWiFiNetwork_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ForgetWiFiNetwork' -type MockBackend_ForgetWiFiNetwork_Call struct { - *mock.Call -} - -// ForgetWiFiNetwork is a helper method to define mock.On call -// - ssid string -func (_e *MockBackend_Expecter) ForgetWiFiNetwork(ssid interface{}) *MockBackend_ForgetWiFiNetwork_Call { - return &MockBackend_ForgetWiFiNetwork_Call{Call: _e.mock.On("ForgetWiFiNetwork", ssid)} -} - -func (_c *MockBackend_ForgetWiFiNetwork_Call) Run(run func(ssid string)) *MockBackend_ForgetWiFiNetwork_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_ForgetWiFiNetwork_Call) Return(_a0 error) *MockBackend_ForgetWiFiNetwork_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ForgetWiFiNetwork_Call) RunAndReturn(run func(string) error) *MockBackend_ForgetWiFiNetwork_Call { - _c.Call.Return(run) - return _c -} - -// GetCurrentState provides a mock function with no fields -func (_m *MockBackend) GetCurrentState() (*network.BackendState, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetCurrentState") - } - - var r0 *network.BackendState - var r1 error - if rf, ok := ret.Get(0).(func() (*network.BackendState, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() *network.BackendState); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*network.BackendState) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetCurrentState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCurrentState' -type MockBackend_GetCurrentState_Call struct { - *mock.Call -} - -// GetCurrentState is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetCurrentState() *MockBackend_GetCurrentState_Call { - return &MockBackend_GetCurrentState_Call{Call: _e.mock.On("GetCurrentState")} -} - -func (_c *MockBackend_GetCurrentState_Call) Run(run func()) *MockBackend_GetCurrentState_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetCurrentState_Call) Return(_a0 *network.BackendState, _a1 error) *MockBackend_GetCurrentState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetCurrentState_Call) RunAndReturn(run func() (*network.BackendState, error)) *MockBackend_GetCurrentState_Call { - _c.Call.Return(run) - return _c -} - -// GetEthernetDevices provides a mock function with no fields -func (_m *MockBackend) GetEthernetDevices() []network.EthernetDevice { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetEthernetDevices") - } - - var r0 []network.EthernetDevice - if rf, ok := ret.Get(0).(func() []network.EthernetDevice); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.EthernetDevice) - } - } - - return r0 -} - -// MockBackend_GetEthernetDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEthernetDevices' -type MockBackend_GetEthernetDevices_Call struct { - *mock.Call -} - -// GetEthernetDevices is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetEthernetDevices() *MockBackend_GetEthernetDevices_Call { - return &MockBackend_GetEthernetDevices_Call{Call: _e.mock.On("GetEthernetDevices")} -} - -func (_c *MockBackend_GetEthernetDevices_Call) Run(run func()) *MockBackend_GetEthernetDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetEthernetDevices_Call) Return(_a0 []network.EthernetDevice) *MockBackend_GetEthernetDevices_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_GetEthernetDevices_Call) RunAndReturn(run func() []network.EthernetDevice) *MockBackend_GetEthernetDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetPromptBroker provides a mock function with no fields -func (_m *MockBackend) GetPromptBroker() network.PromptBroker { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetPromptBroker") - } - - var r0 network.PromptBroker - if rf, ok := ret.Get(0).(func() network.PromptBroker); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(network.PromptBroker) - } - } - - return r0 -} - -// MockBackend_GetPromptBroker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPromptBroker' -type MockBackend_GetPromptBroker_Call struct { - *mock.Call -} - -// GetPromptBroker is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetPromptBroker() *MockBackend_GetPromptBroker_Call { - return &MockBackend_GetPromptBroker_Call{Call: _e.mock.On("GetPromptBroker")} -} - -func (_c *MockBackend_GetPromptBroker_Call) Run(run func()) *MockBackend_GetPromptBroker_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetPromptBroker_Call) Return(_a0 network.PromptBroker) *MockBackend_GetPromptBroker_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_GetPromptBroker_Call) RunAndReturn(run func() network.PromptBroker) *MockBackend_GetPromptBroker_Call { - _c.Call.Return(run) - return _c -} - -// GetVPNConfig provides a mock function with given fields: uuidOrName -func (_m *MockBackend) GetVPNConfig(uuidOrName string) (*network.VPNConfig, error) { - ret := _m.Called(uuidOrName) - - if len(ret) == 0 { - panic("no return value specified for GetVPNConfig") - } - - var r0 *network.VPNConfig - var r1 error - if rf, ok := ret.Get(0).(func(string) (*network.VPNConfig, error)); ok { - return rf(uuidOrName) - } - if rf, ok := ret.Get(0).(func(string) *network.VPNConfig); ok { - r0 = rf(uuidOrName) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*network.VPNConfig) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(uuidOrName) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetVPNConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVPNConfig' -type MockBackend_GetVPNConfig_Call struct { - *mock.Call -} - -// GetVPNConfig is a helper method to define mock.On call -// - uuidOrName string -func (_e *MockBackend_Expecter) GetVPNConfig(uuidOrName interface{}) *MockBackend_GetVPNConfig_Call { - return &MockBackend_GetVPNConfig_Call{Call: _e.mock.On("GetVPNConfig", uuidOrName)} -} - -func (_c *MockBackend_GetVPNConfig_Call) Run(run func(uuidOrName string)) *MockBackend_GetVPNConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_GetVPNConfig_Call) Return(_a0 *network.VPNConfig, _a1 error) *MockBackend_GetVPNConfig_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetVPNConfig_Call) RunAndReturn(run func(string) (*network.VPNConfig, error)) *MockBackend_GetVPNConfig_Call { - _c.Call.Return(run) - return _c -} - -// GetWiFiDevices provides a mock function with no fields -func (_m *MockBackend) GetWiFiDevices() []network.WiFiDevice { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetWiFiDevices") - } - - var r0 []network.WiFiDevice - if rf, ok := ret.Get(0).(func() []network.WiFiDevice); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.WiFiDevice) - } - } - - return r0 -} - -// MockBackend_GetWiFiDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiDevices' -type MockBackend_GetWiFiDevices_Call struct { - *mock.Call -} - -// GetWiFiDevices is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetWiFiDevices() *MockBackend_GetWiFiDevices_Call { - return &MockBackend_GetWiFiDevices_Call{Call: _e.mock.On("GetWiFiDevices")} -} - -func (_c *MockBackend_GetWiFiDevices_Call) Run(run func()) *MockBackend_GetWiFiDevices_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetWiFiDevices_Call) Return(_a0 []network.WiFiDevice) *MockBackend_GetWiFiDevices_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_GetWiFiDevices_Call) RunAndReturn(run func() []network.WiFiDevice) *MockBackend_GetWiFiDevices_Call { - _c.Call.Return(run) - return _c -} - -// GetWiFiEnabled provides a mock function with no fields -func (_m *MockBackend) GetWiFiEnabled() (bool, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetWiFiEnabled") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetWiFiEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiEnabled' -type MockBackend_GetWiFiEnabled_Call struct { - *mock.Call -} - -// GetWiFiEnabled is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetWiFiEnabled() *MockBackend_GetWiFiEnabled_Call { - return &MockBackend_GetWiFiEnabled_Call{Call: _e.mock.On("GetWiFiEnabled")} -} - -func (_c *MockBackend_GetWiFiEnabled_Call) Run(run func()) *MockBackend_GetWiFiEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetWiFiEnabled_Call) Return(_a0 bool, _a1 error) *MockBackend_GetWiFiEnabled_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetWiFiEnabled_Call) RunAndReturn(run func() (bool, error)) *MockBackend_GetWiFiEnabled_Call { - _c.Call.Return(run) - return _c -} - -// GetWiFiNetworkDetails provides a mock function with given fields: ssid -func (_m *MockBackend) GetWiFiNetworkDetails(ssid string) (*network.NetworkInfoResponse, error) { - ret := _m.Called(ssid) - - if len(ret) == 0 { - panic("no return value specified for GetWiFiNetworkDetails") - } - - var r0 *network.NetworkInfoResponse - var r1 error - if rf, ok := ret.Get(0).(func(string) (*network.NetworkInfoResponse, error)); ok { - return rf(ssid) - } - if rf, ok := ret.Get(0).(func(string) *network.NetworkInfoResponse); ok { - r0 = rf(ssid) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*network.NetworkInfoResponse) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(ssid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetWiFiNetworkDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiNetworkDetails' -type MockBackend_GetWiFiNetworkDetails_Call struct { - *mock.Call -} - -// GetWiFiNetworkDetails is a helper method to define mock.On call -// - ssid string -func (_e *MockBackend_Expecter) GetWiFiNetworkDetails(ssid interface{}) *MockBackend_GetWiFiNetworkDetails_Call { - return &MockBackend_GetWiFiNetworkDetails_Call{Call: _e.mock.On("GetWiFiNetworkDetails", ssid)} -} - -func (_c *MockBackend_GetWiFiNetworkDetails_Call) Run(run func(ssid string)) *MockBackend_GetWiFiNetworkDetails_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_GetWiFiNetworkDetails_Call) Return(_a0 *network.NetworkInfoResponse, _a1 error) *MockBackend_GetWiFiNetworkDetails_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetWiFiNetworkDetails_Call) RunAndReturn(run func(string) (*network.NetworkInfoResponse, error)) *MockBackend_GetWiFiNetworkDetails_Call { - _c.Call.Return(run) - return _c -} - -// GetWiFiQRCodeContent provides a mock function with given fields: ssid -func (_m *MockBackend) GetWiFiQRCodeContent(ssid string) (string, error) { - ret := _m.Called(ssid) - - if len(ret) == 0 { - panic("no return value specified for GetWiFiQRCodeContent") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(ssid) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(ssid) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(ssid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetWiFiQRCodeContent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiQRCodeContent' -type MockBackend_GetWiFiQRCodeContent_Call struct { - *mock.Call -} - -// GetWiFiQRCodeContent is a helper method to define mock.On call -// - ssid string -func (_e *MockBackend_Expecter) GetWiFiQRCodeContent(ssid interface{}) *MockBackend_GetWiFiQRCodeContent_Call { - return &MockBackend_GetWiFiQRCodeContent_Call{Call: _e.mock.On("GetWiFiQRCodeContent", ssid)} -} - -func (_c *MockBackend_GetWiFiQRCodeContent_Call) Run(run func(ssid string)) *MockBackend_GetWiFiQRCodeContent_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_GetWiFiQRCodeContent_Call) Return(_a0 string, _a1 error) *MockBackend_GetWiFiQRCodeContent_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetWiFiQRCodeContent_Call) RunAndReturn(run func(string) (string, error)) *MockBackend_GetWiFiQRCodeContent_Call { - _c.Call.Return(run) - return _c -} - -// GetWiredConnections provides a mock function with no fields -func (_m *MockBackend) GetWiredConnections() ([]network.WiredConnection, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetWiredConnections") - } - - var r0 []network.WiredConnection - var r1 error - if rf, ok := ret.Get(0).(func() ([]network.WiredConnection, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []network.WiredConnection); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.WiredConnection) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetWiredConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiredConnections' -type MockBackend_GetWiredConnections_Call struct { - *mock.Call -} - -// GetWiredConnections is a helper method to define mock.On call -func (_e *MockBackend_Expecter) GetWiredConnections() *MockBackend_GetWiredConnections_Call { - return &MockBackend_GetWiredConnections_Call{Call: _e.mock.On("GetWiredConnections")} -} - -func (_c *MockBackend_GetWiredConnections_Call) Run(run func()) *MockBackend_GetWiredConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_GetWiredConnections_Call) Return(_a0 []network.WiredConnection, _a1 error) *MockBackend_GetWiredConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetWiredConnections_Call) RunAndReturn(run func() ([]network.WiredConnection, error)) *MockBackend_GetWiredConnections_Call { - _c.Call.Return(run) - return _c -} - -// GetWiredNetworkDetails provides a mock function with given fields: uuid -func (_m *MockBackend) GetWiredNetworkDetails(uuid string) (*network.WiredNetworkInfoResponse, error) { - ret := _m.Called(uuid) - - if len(ret) == 0 { - panic("no return value specified for GetWiredNetworkDetails") - } - - var r0 *network.WiredNetworkInfoResponse - var r1 error - if rf, ok := ret.Get(0).(func(string) (*network.WiredNetworkInfoResponse, error)); ok { - return rf(uuid) - } - if rf, ok := ret.Get(0).(func(string) *network.WiredNetworkInfoResponse); ok { - r0 = rf(uuid) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*network.WiredNetworkInfoResponse) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(uuid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_GetWiredNetworkDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiredNetworkDetails' -type MockBackend_GetWiredNetworkDetails_Call struct { - *mock.Call -} - -// GetWiredNetworkDetails is a helper method to define mock.On call -// - uuid string -func (_e *MockBackend_Expecter) GetWiredNetworkDetails(uuid interface{}) *MockBackend_GetWiredNetworkDetails_Call { - return &MockBackend_GetWiredNetworkDetails_Call{Call: _e.mock.On("GetWiredNetworkDetails", uuid)} -} - -func (_c *MockBackend_GetWiredNetworkDetails_Call) Run(run func(uuid string)) *MockBackend_GetWiredNetworkDetails_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_GetWiredNetworkDetails_Call) Return(_a0 *network.WiredNetworkInfoResponse, _a1 error) *MockBackend_GetWiredNetworkDetails_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_GetWiredNetworkDetails_Call) RunAndReturn(run func(string) (*network.WiredNetworkInfoResponse, error)) *MockBackend_GetWiredNetworkDetails_Call { - _c.Call.Return(run) - return _c -} - -// ImportVPN provides a mock function with given fields: filePath, name -func (_m *MockBackend) ImportVPN(filePath string, name string) (*network.VPNImportResult, error) { - ret := _m.Called(filePath, name) - - if len(ret) == 0 { - panic("no return value specified for ImportVPN") - } - - var r0 *network.VPNImportResult - var r1 error - if rf, ok := ret.Get(0).(func(string, string) (*network.VPNImportResult, error)); ok { - return rf(filePath, name) - } - if rf, ok := ret.Get(0).(func(string, string) *network.VPNImportResult); ok { - r0 = rf(filePath, name) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*network.VPNImportResult) - } - } - - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(filePath, name) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_ImportVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ImportVPN' -type MockBackend_ImportVPN_Call struct { - *mock.Call -} - -// ImportVPN is a helper method to define mock.On call -// - filePath string -// - name string -func (_e *MockBackend_Expecter) ImportVPN(filePath interface{}, name interface{}) *MockBackend_ImportVPN_Call { - return &MockBackend_ImportVPN_Call{Call: _e.mock.On("ImportVPN", filePath, name)} -} - -func (_c *MockBackend_ImportVPN_Call) Run(run func(filePath string, name string)) *MockBackend_ImportVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockBackend_ImportVPN_Call) Return(_a0 *network.VPNImportResult, _a1 error) *MockBackend_ImportVPN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_ImportVPN_Call) RunAndReturn(run func(string, string) (*network.VPNImportResult, error)) *MockBackend_ImportVPN_Call { - _c.Call.Return(run) - return _c -} - -// Initialize provides a mock function with no fields -func (_m *MockBackend) Initialize() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Initialize") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_Initialize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Initialize' -type MockBackend_Initialize_Call struct { - *mock.Call -} - -// Initialize is a helper method to define mock.On call -func (_e *MockBackend_Expecter) Initialize() *MockBackend_Initialize_Call { - return &MockBackend_Initialize_Call{Call: _e.mock.On("Initialize")} -} - -func (_c *MockBackend_Initialize_Call) Run(run func()) *MockBackend_Initialize_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_Initialize_Call) Return(_a0 error) *MockBackend_Initialize_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_Initialize_Call) RunAndReturn(run func() error) *MockBackend_Initialize_Call { - _c.Call.Return(run) - return _c -} - -// ListActiveVPN provides a mock function with no fields -func (_m *MockBackend) ListActiveVPN() ([]network.VPNActive, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ListActiveVPN") - } - - var r0 []network.VPNActive - var r1 error - if rf, ok := ret.Get(0).(func() ([]network.VPNActive, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []network.VPNActive); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.VPNActive) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_ListActiveVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListActiveVPN' -type MockBackend_ListActiveVPN_Call struct { - *mock.Call -} - -// ListActiveVPN is a helper method to define mock.On call -func (_e *MockBackend_Expecter) ListActiveVPN() *MockBackend_ListActiveVPN_Call { - return &MockBackend_ListActiveVPN_Call{Call: _e.mock.On("ListActiveVPN")} -} - -func (_c *MockBackend_ListActiveVPN_Call) Run(run func()) *MockBackend_ListActiveVPN_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_ListActiveVPN_Call) Return(_a0 []network.VPNActive, _a1 error) *MockBackend_ListActiveVPN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_ListActiveVPN_Call) RunAndReturn(run func() ([]network.VPNActive, error)) *MockBackend_ListActiveVPN_Call { - _c.Call.Return(run) - return _c -} - -// ListVPNPlugins provides a mock function with no fields -func (_m *MockBackend) ListVPNPlugins() ([]network.VPNPlugin, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ListVPNPlugins") - } - - var r0 []network.VPNPlugin - var r1 error - if rf, ok := ret.Get(0).(func() ([]network.VPNPlugin, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []network.VPNPlugin); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.VPNPlugin) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_ListVPNPlugins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListVPNPlugins' -type MockBackend_ListVPNPlugins_Call struct { - *mock.Call -} - -// ListVPNPlugins is a helper method to define mock.On call -func (_e *MockBackend_Expecter) ListVPNPlugins() *MockBackend_ListVPNPlugins_Call { - return &MockBackend_ListVPNPlugins_Call{Call: _e.mock.On("ListVPNPlugins")} -} - -func (_c *MockBackend_ListVPNPlugins_Call) Run(run func()) *MockBackend_ListVPNPlugins_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_ListVPNPlugins_Call) Return(_a0 []network.VPNPlugin, _a1 error) *MockBackend_ListVPNPlugins_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_ListVPNPlugins_Call) RunAndReturn(run func() ([]network.VPNPlugin, error)) *MockBackend_ListVPNPlugins_Call { - _c.Call.Return(run) - return _c -} - -// ListVPNProfiles provides a mock function with no fields -func (_m *MockBackend) ListVPNProfiles() ([]network.VPNProfile, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ListVPNProfiles") - } - - var r0 []network.VPNProfile - var r1 error - if rf, ok := ret.Get(0).(func() ([]network.VPNProfile, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []network.VPNProfile); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]network.VPNProfile) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBackend_ListVPNProfiles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListVPNProfiles' -type MockBackend_ListVPNProfiles_Call struct { - *mock.Call -} - -// ListVPNProfiles is a helper method to define mock.On call -func (_e *MockBackend_Expecter) ListVPNProfiles() *MockBackend_ListVPNProfiles_Call { - return &MockBackend_ListVPNProfiles_Call{Call: _e.mock.On("ListVPNProfiles")} -} - -func (_c *MockBackend_ListVPNProfiles_Call) Run(run func()) *MockBackend_ListVPNProfiles_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_ListVPNProfiles_Call) Return(_a0 []network.VPNProfile, _a1 error) *MockBackend_ListVPNProfiles_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBackend_ListVPNProfiles_Call) RunAndReturn(run func() ([]network.VPNProfile, error)) *MockBackend_ListVPNProfiles_Call { - _c.Call.Return(run) - return _c -} - -// ScanWiFi provides a mock function with no fields -func (_m *MockBackend) ScanWiFi() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ScanWiFi") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ScanWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ScanWiFi' -type MockBackend_ScanWiFi_Call struct { - *mock.Call -} - -// ScanWiFi is a helper method to define mock.On call -func (_e *MockBackend_Expecter) ScanWiFi() *MockBackend_ScanWiFi_Call { - return &MockBackend_ScanWiFi_Call{Call: _e.mock.On("ScanWiFi")} -} - -func (_c *MockBackend_ScanWiFi_Call) Run(run func()) *MockBackend_ScanWiFi_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_ScanWiFi_Call) Return(_a0 error) *MockBackend_ScanWiFi_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ScanWiFi_Call) RunAndReturn(run func() error) *MockBackend_ScanWiFi_Call { - _c.Call.Return(run) - return _c -} - -// ScanWiFiDevice provides a mock function with given fields: device -func (_m *MockBackend) ScanWiFiDevice(device string) error { - ret := _m.Called(device) - - if len(ret) == 0 { - panic("no return value specified for ScanWiFiDevice") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(device) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_ScanWiFiDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ScanWiFiDevice' -type MockBackend_ScanWiFiDevice_Call struct { - *mock.Call -} - -// ScanWiFiDevice is a helper method to define mock.On call -// - device string -func (_e *MockBackend_Expecter) ScanWiFiDevice(device interface{}) *MockBackend_ScanWiFiDevice_Call { - return &MockBackend_ScanWiFiDevice_Call{Call: _e.mock.On("ScanWiFiDevice", device)} -} - -func (_c *MockBackend_ScanWiFiDevice_Call) Run(run func(device string)) *MockBackend_ScanWiFiDevice_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockBackend_ScanWiFiDevice_Call) Return(_a0 error) *MockBackend_ScanWiFiDevice_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_ScanWiFiDevice_Call) RunAndReturn(run func(string) error) *MockBackend_ScanWiFiDevice_Call { - _c.Call.Return(run) - return _c -} - -// SetPromptBroker provides a mock function with given fields: broker -func (_m *MockBackend) SetPromptBroker(broker network.PromptBroker) error { - ret := _m.Called(broker) - - if len(ret) == 0 { - panic("no return value specified for SetPromptBroker") - } - - var r0 error - if rf, ok := ret.Get(0).(func(network.PromptBroker) error); ok { - r0 = rf(broker) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_SetPromptBroker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPromptBroker' -type MockBackend_SetPromptBroker_Call struct { - *mock.Call -} - -// SetPromptBroker is a helper method to define mock.On call -// - broker network.PromptBroker -func (_e *MockBackend_Expecter) SetPromptBroker(broker interface{}) *MockBackend_SetPromptBroker_Call { - return &MockBackend_SetPromptBroker_Call{Call: _e.mock.On("SetPromptBroker", broker)} -} - -func (_c *MockBackend_SetPromptBroker_Call) Run(run func(broker network.PromptBroker)) *MockBackend_SetPromptBroker_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(network.PromptBroker)) - }) - return _c -} - -func (_c *MockBackend_SetPromptBroker_Call) Return(_a0 error) *MockBackend_SetPromptBroker_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_SetPromptBroker_Call) RunAndReturn(run func(network.PromptBroker) error) *MockBackend_SetPromptBroker_Call { - _c.Call.Return(run) - return _c -} - -// SetVPNCredentials provides a mock function with given fields: uuid, username, password, save -func (_m *MockBackend) SetVPNCredentials(uuid string, username string, password string, save bool) error { - ret := _m.Called(uuid, username, password, save) - - if len(ret) == 0 { - panic("no return value specified for SetVPNCredentials") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, string, bool) error); ok { - r0 = rf(uuid, username, password, save) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_SetVPNCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVPNCredentials' -type MockBackend_SetVPNCredentials_Call struct { - *mock.Call -} - -// SetVPNCredentials is a helper method to define mock.On call -// - uuid string -// - username string -// - password string -// - save bool -func (_e *MockBackend_Expecter) SetVPNCredentials(uuid interface{}, username interface{}, password interface{}, save interface{}) *MockBackend_SetVPNCredentials_Call { - return &MockBackend_SetVPNCredentials_Call{Call: _e.mock.On("SetVPNCredentials", uuid, username, password, save)} -} - -func (_c *MockBackend_SetVPNCredentials_Call) Run(run func(uuid string, username string, password string, save bool)) *MockBackend_SetVPNCredentials_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(string), args[3].(bool)) - }) - return _c -} - -func (_c *MockBackend_SetVPNCredentials_Call) Return(_a0 error) *MockBackend_SetVPNCredentials_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_SetVPNCredentials_Call) RunAndReturn(run func(string, string, string, bool) error) *MockBackend_SetVPNCredentials_Call { - _c.Call.Return(run) - return _c -} - -// SetWiFiAutoconnect provides a mock function with given fields: ssid, autoconnect -func (_m *MockBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - ret := _m.Called(ssid, autoconnect) - - if len(ret) == 0 { - panic("no return value specified for SetWiFiAutoconnect") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, bool) error); ok { - r0 = rf(ssid, autoconnect) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_SetWiFiAutoconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWiFiAutoconnect' -type MockBackend_SetWiFiAutoconnect_Call struct { - *mock.Call -} - -// SetWiFiAutoconnect is a helper method to define mock.On call -// - ssid string -// - autoconnect bool -func (_e *MockBackend_Expecter) SetWiFiAutoconnect(ssid interface{}, autoconnect interface{}) *MockBackend_SetWiFiAutoconnect_Call { - return &MockBackend_SetWiFiAutoconnect_Call{Call: _e.mock.On("SetWiFiAutoconnect", ssid, autoconnect)} -} - -func (_c *MockBackend_SetWiFiAutoconnect_Call) Run(run func(ssid string, autoconnect bool)) *MockBackend_SetWiFiAutoconnect_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(bool)) - }) - return _c -} - -func (_c *MockBackend_SetWiFiAutoconnect_Call) Return(_a0 error) *MockBackend_SetWiFiAutoconnect_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_SetWiFiAutoconnect_Call) RunAndReturn(run func(string, bool) error) *MockBackend_SetWiFiAutoconnect_Call { - _c.Call.Return(run) - return _c -} - -// SetWiFiEnabled provides a mock function with given fields: enabled -func (_m *MockBackend) SetWiFiEnabled(enabled bool) error { - ret := _m.Called(enabled) - - if len(ret) == 0 { - panic("no return value specified for SetWiFiEnabled") - } - - var r0 error - if rf, ok := ret.Get(0).(func(bool) error); ok { - r0 = rf(enabled) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_SetWiFiEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWiFiEnabled' -type MockBackend_SetWiFiEnabled_Call struct { - *mock.Call -} - -// SetWiFiEnabled is a helper method to define mock.On call -// - enabled bool -func (_e *MockBackend_Expecter) SetWiFiEnabled(enabled interface{}) *MockBackend_SetWiFiEnabled_Call { - return &MockBackend_SetWiFiEnabled_Call{Call: _e.mock.On("SetWiFiEnabled", enabled)} -} - -func (_c *MockBackend_SetWiFiEnabled_Call) Run(run func(enabled bool)) *MockBackend_SetWiFiEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(bool)) - }) - return _c -} - -func (_c *MockBackend_SetWiFiEnabled_Call) Return(_a0 error) *MockBackend_SetWiFiEnabled_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_SetWiFiEnabled_Call) RunAndReturn(run func(bool) error) *MockBackend_SetWiFiEnabled_Call { - _c.Call.Return(run) - return _c -} - -// StartMonitoring provides a mock function with given fields: onStateChange -func (_m *MockBackend) StartMonitoring(onStateChange func()) error { - ret := _m.Called(onStateChange) - - if len(ret) == 0 { - panic("no return value specified for StartMonitoring") - } - - var r0 error - if rf, ok := ret.Get(0).(func(func()) error); ok { - r0 = rf(onStateChange) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_StartMonitoring_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartMonitoring' -type MockBackend_StartMonitoring_Call struct { - *mock.Call -} - -// StartMonitoring is a helper method to define mock.On call -// - onStateChange func() -func (_e *MockBackend_Expecter) StartMonitoring(onStateChange interface{}) *MockBackend_StartMonitoring_Call { - return &MockBackend_StartMonitoring_Call{Call: _e.mock.On("StartMonitoring", onStateChange)} -} - -func (_c *MockBackend_StartMonitoring_Call) Run(run func(onStateChange func())) *MockBackend_StartMonitoring_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(func())) - }) - return _c -} - -func (_c *MockBackend_StartMonitoring_Call) Return(_a0 error) *MockBackend_StartMonitoring_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_StartMonitoring_Call) RunAndReturn(run func(func()) error) *MockBackend_StartMonitoring_Call { - _c.Call.Return(run) - return _c -} - -// StopMonitoring provides a mock function with no fields -func (_m *MockBackend) StopMonitoring() { - _m.Called() -} - -// MockBackend_StopMonitoring_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopMonitoring' -type MockBackend_StopMonitoring_Call struct { - *mock.Call -} - -// StopMonitoring is a helper method to define mock.On call -func (_e *MockBackend_Expecter) StopMonitoring() *MockBackend_StopMonitoring_Call { - return &MockBackend_StopMonitoring_Call{Call: _e.mock.On("StopMonitoring")} -} - -func (_c *MockBackend_StopMonitoring_Call) Run(run func()) *MockBackend_StopMonitoring_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockBackend_StopMonitoring_Call) Return() *MockBackend_StopMonitoring_Call { - _c.Call.Return() - return _c -} - -func (_c *MockBackend_StopMonitoring_Call) RunAndReturn(run func()) *MockBackend_StopMonitoring_Call { - _c.Run(run) - return _c -} - -// SubmitCredentials provides a mock function with given fields: token, secrets, save -func (_m *MockBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error { - ret := _m.Called(token, secrets, save) - - if len(ret) == 0 { - panic("no return value specified for SubmitCredentials") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, map[string]string, bool) error); ok { - r0 = rf(token, secrets, save) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_SubmitCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubmitCredentials' -type MockBackend_SubmitCredentials_Call struct { - *mock.Call -} - -// SubmitCredentials is a helper method to define mock.On call -// - token string -// - secrets map[string]string -// - save bool -func (_e *MockBackend_Expecter) SubmitCredentials(token interface{}, secrets interface{}, save interface{}) *MockBackend_SubmitCredentials_Call { - return &MockBackend_SubmitCredentials_Call{Call: _e.mock.On("SubmitCredentials", token, secrets, save)} -} - -func (_c *MockBackend_SubmitCredentials_Call) Run(run func(token string, secrets map[string]string, save bool)) *MockBackend_SubmitCredentials_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(map[string]string), args[2].(bool)) - }) - return _c -} - -func (_c *MockBackend_SubmitCredentials_Call) Return(_a0 error) *MockBackend_SubmitCredentials_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_SubmitCredentials_Call) RunAndReturn(run func(string, map[string]string, bool) error) *MockBackend_SubmitCredentials_Call { - _c.Call.Return(run) - return _c -} - -// UpdateVPNConfig provides a mock function with given fields: uuid, updates -func (_m *MockBackend) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { - ret := _m.Called(uuid, updates) - - if len(ret) == 0 { - panic("no return value specified for UpdateVPNConfig") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, map[string]interface{}) error); ok { - r0 = rf(uuid, updates) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockBackend_UpdateVPNConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateVPNConfig' -type MockBackend_UpdateVPNConfig_Call struct { - *mock.Call -} - -// UpdateVPNConfig is a helper method to define mock.On call -// - uuid string -// - updates map[string]interface{} -func (_e *MockBackend_Expecter) UpdateVPNConfig(uuid interface{}, updates interface{}) *MockBackend_UpdateVPNConfig_Call { - return &MockBackend_UpdateVPNConfig_Call{Call: _e.mock.On("UpdateVPNConfig", uuid, updates)} -} - -func (_c *MockBackend_UpdateVPNConfig_Call) Run(run func(uuid string, updates map[string]interface{})) *MockBackend_UpdateVPNConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(map[string]interface{})) - }) - return _c -} - -func (_c *MockBackend_UpdateVPNConfig_Call) Return(_a0 error) *MockBackend_UpdateVPNConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockBackend_UpdateVPNConfig_Call) RunAndReturn(run func(string, map[string]interface{}) error) *MockBackend_UpdateVPNConfig_Call { - _c.Call.Return(run) - return _c -} - -// NewMockBackend creates a new instance of MockBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockBackend(t interface { - mock.TestingT - Cleanup(func()) -}) *MockBackend { - mock := &MockBackend{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/utils/mock_AppChecker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/utils/mock_AppChecker.go deleted file mode 100644 index be220c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/utils/mock_AppChecker.go +++ /dev/null @@ -1,242 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_utils - -import mock "github.com/stretchr/testify/mock" - -// MockAppChecker is an autogenerated mock type for the AppChecker type -type MockAppChecker struct { - mock.Mock -} - -type MockAppChecker_Expecter struct { - mock *mock.Mock -} - -func (_m *MockAppChecker) EXPECT() *MockAppChecker_Expecter { - return &MockAppChecker_Expecter{mock: &_m.Mock} -} - -// AnyCommandExists provides a mock function with given fields: cmds -func (_m *MockAppChecker) AnyCommandExists(cmds ...string) bool { - _va := make([]interface{}, len(cmds)) - for _i := range cmds { - _va[_i] = cmds[_i] - } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for AnyCommandExists") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(...string) bool); ok { - r0 = rf(cmds...) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// MockAppChecker_AnyCommandExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AnyCommandExists' -type MockAppChecker_AnyCommandExists_Call struct { - *mock.Call -} - -// AnyCommandExists is a helper method to define mock.On call -// - cmds ...string -func (_e *MockAppChecker_Expecter) AnyCommandExists(cmds ...interface{}) *MockAppChecker_AnyCommandExists_Call { - return &MockAppChecker_AnyCommandExists_Call{Call: _e.mock.On("AnyCommandExists", - append([]interface{}{}, cmds...)...)} -} - -func (_c *MockAppChecker_AnyCommandExists_Call) Run(run func(cmds ...string)) *MockAppChecker_AnyCommandExists_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]string, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(string) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *MockAppChecker_AnyCommandExists_Call) Return(_a0 bool) *MockAppChecker_AnyCommandExists_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockAppChecker_AnyCommandExists_Call) RunAndReturn(run func(...string) bool) *MockAppChecker_AnyCommandExists_Call { - _c.Call.Return(run) - return _c -} - -// AnyFlatpakExists provides a mock function with given fields: flatpaks -func (_m *MockAppChecker) AnyFlatpakExists(flatpaks ...string) bool { - _va := make([]interface{}, len(flatpaks)) - for _i := range flatpaks { - _va[_i] = flatpaks[_i] - } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for AnyFlatpakExists") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(...string) bool); ok { - r0 = rf(flatpaks...) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// MockAppChecker_AnyFlatpakExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AnyFlatpakExists' -type MockAppChecker_AnyFlatpakExists_Call struct { - *mock.Call -} - -// AnyFlatpakExists is a helper method to define mock.On call -// - flatpaks ...string -func (_e *MockAppChecker_Expecter) AnyFlatpakExists(flatpaks ...interface{}) *MockAppChecker_AnyFlatpakExists_Call { - return &MockAppChecker_AnyFlatpakExists_Call{Call: _e.mock.On("AnyFlatpakExists", - append([]interface{}{}, flatpaks...)...)} -} - -func (_c *MockAppChecker_AnyFlatpakExists_Call) Run(run func(flatpaks ...string)) *MockAppChecker_AnyFlatpakExists_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]string, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(string) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *MockAppChecker_AnyFlatpakExists_Call) Return(_a0 bool) *MockAppChecker_AnyFlatpakExists_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockAppChecker_AnyFlatpakExists_Call) RunAndReturn(run func(...string) bool) *MockAppChecker_AnyFlatpakExists_Call { - _c.Call.Return(run) - return _c -} - -// CommandExists provides a mock function with given fields: cmd -func (_m *MockAppChecker) CommandExists(cmd string) bool { - ret := _m.Called(cmd) - - if len(ret) == 0 { - panic("no return value specified for CommandExists") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(cmd) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// MockAppChecker_CommandExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CommandExists' -type MockAppChecker_CommandExists_Call struct { - *mock.Call -} - -// CommandExists is a helper method to define mock.On call -// - cmd string -func (_e *MockAppChecker_Expecter) CommandExists(cmd interface{}) *MockAppChecker_CommandExists_Call { - return &MockAppChecker_CommandExists_Call{Call: _e.mock.On("CommandExists", cmd)} -} - -func (_c *MockAppChecker_CommandExists_Call) Run(run func(cmd string)) *MockAppChecker_CommandExists_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockAppChecker_CommandExists_Call) Return(_a0 bool) *MockAppChecker_CommandExists_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockAppChecker_CommandExists_Call) RunAndReturn(run func(string) bool) *MockAppChecker_CommandExists_Call { - _c.Call.Return(run) - return _c -} - -// FlatpakExists provides a mock function with given fields: name -func (_m *MockAppChecker) FlatpakExists(name string) bool { - ret := _m.Called(name) - - if len(ret) == 0 { - panic("no return value specified for FlatpakExists") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(name) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// MockAppChecker_FlatpakExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FlatpakExists' -type MockAppChecker_FlatpakExists_Call struct { - *mock.Call -} - -// FlatpakExists is a helper method to define mock.On call -// - name string -func (_e *MockAppChecker_Expecter) FlatpakExists(name interface{}) *MockAppChecker_FlatpakExists_Call { - return &MockAppChecker_FlatpakExists_Call{Call: _e.mock.On("FlatpakExists", name)} -} - -func (_c *MockAppChecker_FlatpakExists_Call) Run(run func(name string)) *MockAppChecker_FlatpakExists_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockAppChecker_FlatpakExists_Call) Return(_a0 bool) *MockAppChecker_FlatpakExists_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockAppChecker_FlatpakExists_Call) RunAndReturn(run func(string) bool) *MockAppChecker_FlatpakExists_Call { - _c.Call.Return(run) - return _c -} - -// NewMockAppChecker creates a new instance of MockAppChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockAppChecker(t interface { - mock.TestingT - Cleanup(func()) -}) *MockAppChecker { - mock := &MockAppChecker{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/version/mock_VersionFetcher.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/version/mock_VersionFetcher.go deleted file mode 100644 index a6fa27c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/version/mock_VersionFetcher.go +++ /dev/null @@ -1,144 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_version - -import mock "github.com/stretchr/testify/mock" - -// MockVersionFetcher is an autogenerated mock type for the VersionFetcher type -type MockVersionFetcher struct { - mock.Mock -} - -type MockVersionFetcher_Expecter struct { - mock *mock.Mock -} - -func (_m *MockVersionFetcher) EXPECT() *MockVersionFetcher_Expecter { - return &MockVersionFetcher_Expecter{mock: &_m.Mock} -} - -// GetCurrentVersion provides a mock function with given fields: dmsPath -func (_m *MockVersionFetcher) GetCurrentVersion(dmsPath string) (string, error) { - ret := _m.Called(dmsPath) - - if len(ret) == 0 { - panic("no return value specified for GetCurrentVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(dmsPath) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(dmsPath) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(dmsPath) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockVersionFetcher_GetCurrentVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCurrentVersion' -type MockVersionFetcher_GetCurrentVersion_Call struct { - *mock.Call -} - -// GetCurrentVersion is a helper method to define mock.On call -// - dmsPath string -func (_e *MockVersionFetcher_Expecter) GetCurrentVersion(dmsPath interface{}) *MockVersionFetcher_GetCurrentVersion_Call { - return &MockVersionFetcher_GetCurrentVersion_Call{Call: _e.mock.On("GetCurrentVersion", dmsPath)} -} - -func (_c *MockVersionFetcher_GetCurrentVersion_Call) Run(run func(dmsPath string)) *MockVersionFetcher_GetCurrentVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockVersionFetcher_GetCurrentVersion_Call) Return(_a0 string, _a1 error) *MockVersionFetcher_GetCurrentVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockVersionFetcher_GetCurrentVersion_Call) RunAndReturn(run func(string) (string, error)) *MockVersionFetcher_GetCurrentVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetLatestVersion provides a mock function with given fields: dmsPath -func (_m *MockVersionFetcher) GetLatestVersion(dmsPath string) (string, error) { - ret := _m.Called(dmsPath) - - if len(ret) == 0 { - panic("no return value specified for GetLatestVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(dmsPath) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(dmsPath) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(dmsPath) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockVersionFetcher_GetLatestVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestVersion' -type MockVersionFetcher_GetLatestVersion_Call struct { - *mock.Call -} - -// GetLatestVersion is a helper method to define mock.On call -// - dmsPath string -func (_e *MockVersionFetcher_Expecter) GetLatestVersion(dmsPath interface{}) *MockVersionFetcher_GetLatestVersion_Call { - return &MockVersionFetcher_GetLatestVersion_Call{Call: _e.mock.On("GetLatestVersion", dmsPath)} -} - -func (_c *MockVersionFetcher_GetLatestVersion_Call) Run(run func(dmsPath string)) *MockVersionFetcher_GetLatestVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockVersionFetcher_GetLatestVersion_Call) Return(_a0 string, _a1 error) *MockVersionFetcher_GetLatestVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockVersionFetcher_GetLatestVersion_Call) RunAndReturn(run func(string) (string, error)) *MockVersionFetcher_GetLatestVersion_Call { - _c.Call.Return(run) - return _c -} - -// NewMockVersionFetcher creates a new instance of MockVersionFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockVersionFetcher(t interface { - mock.TestingT - Cleanup(func()) -}) *MockVersionFetcher { - mock := &MockVersionFetcher{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlclient/mock_WaylandDisplay.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlclient/mock_WaylandDisplay.go deleted file mode 100644 index 45d944b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlclient/mock_WaylandDisplay.go +++ /dev/null @@ -1,229 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_wlclient - -import ( - client "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - mock "github.com/stretchr/testify/mock" -) - -// MockWaylandDisplay is an autogenerated mock type for the WaylandDisplay type -type MockWaylandDisplay struct { - mock.Mock -} - -type MockWaylandDisplay_Expecter struct { - mock *mock.Mock -} - -func (_m *MockWaylandDisplay) EXPECT() *MockWaylandDisplay_Expecter { - return &MockWaylandDisplay_Expecter{mock: &_m.Mock} -} - -// Context provides a mock function with no fields -func (_m *MockWaylandDisplay) Context() *client.Context { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Context") - } - - var r0 *client.Context - if rf, ok := ret.Get(0).(func() *client.Context); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*client.Context) - } - } - - return r0 -} - -// MockWaylandDisplay_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context' -type MockWaylandDisplay_Context_Call struct { - *mock.Call -} - -// Context is a helper method to define mock.On call -func (_e *MockWaylandDisplay_Expecter) Context() *MockWaylandDisplay_Context_Call { - return &MockWaylandDisplay_Context_Call{Call: _e.mock.On("Context")} -} - -func (_c *MockWaylandDisplay_Context_Call) Run(run func()) *MockWaylandDisplay_Context_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandDisplay_Context_Call) Return(_a0 *client.Context) *MockWaylandDisplay_Context_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWaylandDisplay_Context_Call) RunAndReturn(run func() *client.Context) *MockWaylandDisplay_Context_Call { - _c.Call.Return(run) - return _c -} - -// Destroy provides a mock function with no fields -func (_m *MockWaylandDisplay) Destroy() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Destroy") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockWaylandDisplay_Destroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destroy' -type MockWaylandDisplay_Destroy_Call struct { - *mock.Call -} - -// Destroy is a helper method to define mock.On call -func (_e *MockWaylandDisplay_Expecter) Destroy() *MockWaylandDisplay_Destroy_Call { - return &MockWaylandDisplay_Destroy_Call{Call: _e.mock.On("Destroy")} -} - -func (_c *MockWaylandDisplay_Destroy_Call) Run(run func()) *MockWaylandDisplay_Destroy_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandDisplay_Destroy_Call) Return(_a0 error) *MockWaylandDisplay_Destroy_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWaylandDisplay_Destroy_Call) RunAndReturn(run func() error) *MockWaylandDisplay_Destroy_Call { - _c.Call.Return(run) - return _c -} - -// GetRegistry provides a mock function with no fields -func (_m *MockWaylandDisplay) GetRegistry() (*client.Registry, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetRegistry") - } - - var r0 *client.Registry - var r1 error - if rf, ok := ret.Get(0).(func() (*client.Registry, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() *client.Registry); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*client.Registry) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockWaylandDisplay_GetRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRegistry' -type MockWaylandDisplay_GetRegistry_Call struct { - *mock.Call -} - -// GetRegistry is a helper method to define mock.On call -func (_e *MockWaylandDisplay_Expecter) GetRegistry() *MockWaylandDisplay_GetRegistry_Call { - return &MockWaylandDisplay_GetRegistry_Call{Call: _e.mock.On("GetRegistry")} -} - -func (_c *MockWaylandDisplay_GetRegistry_Call) Run(run func()) *MockWaylandDisplay_GetRegistry_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandDisplay_GetRegistry_Call) Return(_a0 *client.Registry, _a1 error) *MockWaylandDisplay_GetRegistry_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockWaylandDisplay_GetRegistry_Call) RunAndReturn(run func() (*client.Registry, error)) *MockWaylandDisplay_GetRegistry_Call { - _c.Call.Return(run) - return _c -} - -// Roundtrip provides a mock function with no fields -func (_m *MockWaylandDisplay) Roundtrip() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Roundtrip") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockWaylandDisplay_Roundtrip_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Roundtrip' -type MockWaylandDisplay_Roundtrip_Call struct { - *mock.Call -} - -// Roundtrip is a helper method to define mock.On call -func (_e *MockWaylandDisplay_Expecter) Roundtrip() *MockWaylandDisplay_Roundtrip_Call { - return &MockWaylandDisplay_Roundtrip_Call{Call: _e.mock.On("Roundtrip")} -} - -func (_c *MockWaylandDisplay_Roundtrip_Call) Run(run func()) *MockWaylandDisplay_Roundtrip_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandDisplay_Roundtrip_Call) Return(_a0 error) *MockWaylandDisplay_Roundtrip_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWaylandDisplay_Roundtrip_Call) RunAndReturn(run func() error) *MockWaylandDisplay_Roundtrip_Call { - _c.Call.Return(run) - return _c -} - -// NewMockWaylandDisplay creates a new instance of MockWaylandDisplay. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockWaylandDisplay(t interface { - mock.TestingT - Cleanup(func()) -}) *MockWaylandDisplay { - mock := &MockWaylandDisplay{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlcontext/mock_WaylandContext.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlcontext/mock_WaylandContext.go deleted file mode 100644 index f5b0c35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/mocks/wlcontext/mock_WaylandContext.go +++ /dev/null @@ -1,226 +0,0 @@ -// Code generated by mockery v2.53.5. DO NOT EDIT. - -package mocks_wlcontext - -import ( - client "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - mock "github.com/stretchr/testify/mock" -) - -// MockWaylandContext is an autogenerated mock type for the WaylandContext type -type MockWaylandContext struct { - mock.Mock -} - -type MockWaylandContext_Expecter struct { - mock *mock.Mock -} - -func (_m *MockWaylandContext) EXPECT() *MockWaylandContext_Expecter { - return &MockWaylandContext_Expecter{mock: &_m.Mock} -} - -// Close provides a mock function with no fields -func (_m *MockWaylandContext) Close() { - _m.Called() -} - -// MockWaylandContext_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type MockWaylandContext_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *MockWaylandContext_Expecter) Close() *MockWaylandContext_Close_Call { - return &MockWaylandContext_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *MockWaylandContext_Close_Call) Run(run func()) *MockWaylandContext_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandContext_Close_Call) Return() *MockWaylandContext_Close_Call { - _c.Call.Return() - return _c -} - -func (_c *MockWaylandContext_Close_Call) RunAndReturn(run func()) *MockWaylandContext_Close_Call { - _c.Run(run) - return _c -} - -// Display provides a mock function with no fields -func (_m *MockWaylandContext) Display() *client.Display { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Display") - } - - var r0 *client.Display - if rf, ok := ret.Get(0).(func() *client.Display); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*client.Display) - } - } - - return r0 -} - -// MockWaylandContext_Display_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Display' -type MockWaylandContext_Display_Call struct { - *mock.Call -} - -// Display is a helper method to define mock.On call -func (_e *MockWaylandContext_Expecter) Display() *MockWaylandContext_Display_Call { - return &MockWaylandContext_Display_Call{Call: _e.mock.On("Display")} -} - -func (_c *MockWaylandContext_Display_Call) Run(run func()) *MockWaylandContext_Display_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandContext_Display_Call) Return(_a0 *client.Display) *MockWaylandContext_Display_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWaylandContext_Display_Call) RunAndReturn(run func() *client.Display) *MockWaylandContext_Display_Call { - _c.Call.Return(run) - return _c -} - -// FatalError provides a mock function with no fields -func (_m *MockWaylandContext) FatalError() <-chan error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for FatalError") - } - - var r0 <-chan error - if rf, ok := ret.Get(0).(func() <-chan error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan error) - } - } - - return r0 -} - -// MockWaylandContext_FatalError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FatalError' -type MockWaylandContext_FatalError_Call struct { - *mock.Call -} - -// FatalError is a helper method to define mock.On call -func (_e *MockWaylandContext_Expecter) FatalError() *MockWaylandContext_FatalError_Call { - return &MockWaylandContext_FatalError_Call{Call: _e.mock.On("FatalError")} -} - -func (_c *MockWaylandContext_FatalError_Call) Run(run func()) *MockWaylandContext_FatalError_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandContext_FatalError_Call) Return(_a0 <-chan error) *MockWaylandContext_FatalError_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWaylandContext_FatalError_Call) RunAndReturn(run func() <-chan error) *MockWaylandContext_FatalError_Call { - _c.Call.Return(run) - return _c -} - -// Post provides a mock function with given fields: fn -func (_m *MockWaylandContext) Post(fn func()) { - _m.Called(fn) -} - -// MockWaylandContext_Post_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Post' -type MockWaylandContext_Post_Call struct { - *mock.Call -} - -// Post is a helper method to define mock.On call -// - fn func() -func (_e *MockWaylandContext_Expecter) Post(fn interface{}) *MockWaylandContext_Post_Call { - return &MockWaylandContext_Post_Call{Call: _e.mock.On("Post", fn)} -} - -func (_c *MockWaylandContext_Post_Call) Run(run func(fn func())) *MockWaylandContext_Post_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(func())) - }) - return _c -} - -func (_c *MockWaylandContext_Post_Call) Return() *MockWaylandContext_Post_Call { - _c.Call.Return() - return _c -} - -func (_c *MockWaylandContext_Post_Call) RunAndReturn(run func(func())) *MockWaylandContext_Post_Call { - _c.Run(run) - return _c -} - -// Start provides a mock function with no fields -func (_m *MockWaylandContext) Start() { - _m.Called() -} - -// MockWaylandContext_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' -type MockWaylandContext_Start_Call struct { - *mock.Call -} - -// Start is a helper method to define mock.On call -func (_e *MockWaylandContext_Expecter) Start() *MockWaylandContext_Start_Call { - return &MockWaylandContext_Start_Call{Call: _e.mock.On("Start")} -} - -func (_c *MockWaylandContext_Start_Call) Run(run func()) *MockWaylandContext_Start_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWaylandContext_Start_Call) Return() *MockWaylandContext_Start_Call { - _c.Call.Return() - return _c -} - -func (_c *MockWaylandContext_Start_Call) RunAndReturn(run func()) *MockWaylandContext_Start_Call { - _c.Run(run) - return _c -} - -// NewMockWaylandContext creates a new instance of MockWaylandContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockWaylandContext(t interface { - mock.TestingT - Cleanup(func()) -}) *MockWaylandContext { - mock := &MockWaylandContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/notify/notify.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/notify/notify.go deleted file mode 100644 index 1e42b16..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/notify/notify.go +++ /dev/null @@ -1,185 +0,0 @@ -package notify - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "syscall" - - "github.com/godbus/dbus/v5" -) - -const ( - notifyDest = "org.freedesktop.Notifications" - notifyPath = "/org/freedesktop/Notifications" - notifyInterface = "org.freedesktop.Notifications" - - maxSummaryLen = 29 - maxBodyLen = 80 -) - -type Notification struct { - AppName string - Icon string - Summary string - Body string - FilePath string - Timeout int32 -} - -func Send(n Notification) error { - conn, err := dbus.SessionBus() - if err != nil { - return fmt.Errorf("dbus session failed: %w", err) - } - - if n.AppName == "" { - n.AppName = "DMS" - } - if n.Timeout == 0 { - n.Timeout = 5000 - } - - if len(n.Summary) > maxSummaryLen { - n.Summary = n.Summary[:maxSummaryLen-3] + "..." - } - if len(n.Body) > maxBodyLen { - n.Body = n.Body[:maxBodyLen-3] + "..." - } - - var actions []string - if n.FilePath != "" { - actions = []string{ - "open", "Open", - "folder", "Open Folder", - } - } - - hints := map[string]dbus.Variant{} - if n.FilePath != "" { - imgPath := n.FilePath - if !strings.HasPrefix(imgPath, "file://") { - imgPath = "file://" + imgPath - } - hints["image_path"] = dbus.MakeVariant(imgPath) - } - - obj := conn.Object(notifyDest, notifyPath) - call := obj.Call( - notifyInterface+".Notify", - 0, - n.AppName, - uint32(0), - n.Icon, - n.Summary, - n.Body, - actions, - hints, - n.Timeout, - ) - - if call.Err != nil { - return fmt.Errorf("notify call failed: %w", call.Err) - } - - var notificationID uint32 - if err := call.Store(¬ificationID); err != nil { - return fmt.Errorf("failed to get notification id: %w", err) - } - - if len(actions) > 0 && n.FilePath != "" { - spawnActionListener(notificationID, n.FilePath) - } - - return nil -} - -func spawnActionListener(notificationID uint32, filePath string) { - exe, err := os.Executable() - if err != nil { - return - } - - cmd := exec.Command(exe, "notify-action-generic", fmt.Sprintf("%d", notificationID), filePath) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - cmd.Start() -} - -func RunActionListener(args []string) { - if len(args) < 2 { - return - } - - notificationID, err := strconv.ParseUint(args[0], 10, 32) - if err != nil { - return - } - - filePath := args[1] - - conn, err := dbus.SessionBus() - if err != nil { - return - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(notifyPath), - dbus.WithMatchInterface(notifyInterface), - ); err != nil { - return - } - - signals := make(chan *dbus.Signal, 10) - conn.Signal(signals) - - for sig := range signals { - switch sig.Name { - case notifyInterface + ".ActionInvoked": - if len(sig.Body) < 2 { - continue - } - id, ok := sig.Body[0].(uint32) - if !ok || id != uint32(notificationID) { - continue - } - action, ok := sig.Body[1].(string) - if !ok { - continue - } - handleAction(action, filePath) - return - - case notifyInterface + ".NotificationClosed": - if len(sig.Body) < 1 { - continue - } - id, ok := sig.Body[0].(uint32) - if !ok || id != uint32(notificationID) { - continue - } - return - } - } -} - -func handleAction(action, filePath string) { - switch action { - case "open", "default": - openPath(filePath) - case "folder": - openPath(filepath.Dir(filePath)) - } -} - -func openPath(path string) { - cmd := exec.Command("xdg-open", path) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - cmd.Start() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam.go deleted file mode 100644 index 16ca3f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam.go +++ /dev/null @@ -1,892 +0,0 @@ -package pam - -import ( - "context" - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" -) - -const ( - GreeterPamManagedBlockStart = "# BEGIN DMS GREETER AUTH (managed by dms greeter sync)" - GreeterPamManagedBlockEnd = "# END DMS GREETER AUTH" - - LockscreenPamManagedBlockStart = "# BEGIN DMS LOCKSCREEN AUTH (managed by dms greeter sync)" - LockscreenPamManagedBlockEnd = "# END DMS LOCKSCREEN AUTH" - - LockscreenU2FPamManagedBlockStart = "# BEGIN DMS LOCKSCREEN U2F AUTH (managed by dms auth sync)" - LockscreenU2FPamManagedBlockEnd = "# END DMS LOCKSCREEN U2F AUTH" - - legacyGreeterPamFprintComment = "# DMS greeter fingerprint" - legacyGreeterPamU2FComment = "# DMS greeter U2F" - - GreetdPamPath = "/etc/pam.d/greetd" - DankshellPamPath = "/etc/pam.d/dankshell" - DankshellU2FPamPath = "/etc/pam.d/dankshell-u2f" -) - -var includedPamAuthFiles = []string{ - "system-auth", - "common-auth", - "password-auth", - "system-login", - "system-local-login", - "common-auth-pc", - "login", -} - -type AuthSettings struct { - EnableFprint bool `json:"enableFprint"` - EnableU2f bool `json:"enableU2f"` - GreeterEnableFprint bool `json:"greeterEnableFprint"` - GreeterEnableU2f bool `json:"greeterEnableU2f"` -} - -type SyncAuthOptions struct { - HomeDir string - ForceGreeterAuth bool -} - -type syncDeps struct { - pamDir string - greetdPath string - dankshellPath string - dankshellU2fPath string - isNixOS func() bool - readFile func(string) ([]byte, error) - stat func(string) (os.FileInfo, error) - createTemp func(string, string) (*os.File, error) - removeFile func(string) error - runSudoCmd func(string, string, ...string) error - pamModuleExists func(string) bool - fingerprintAvailableForCurrentUser func() bool -} - -type lockscreenPamIncludeDirective struct { - target string - filterType string -} - -type lockscreenPamResolver struct { - pamDir string - readFile func(string) ([]byte, error) -} - -func defaultSyncDeps() syncDeps { - return syncDeps{ - pamDir: "/etc/pam.d", - greetdPath: GreetdPamPath, - dankshellPath: DankshellPamPath, - dankshellU2fPath: DankshellU2FPamPath, - isNixOS: IsNixOS, - readFile: os.ReadFile, - stat: os.Stat, - createTemp: os.CreateTemp, - removeFile: os.Remove, - runSudoCmd: runSudoCmd, - pamModuleExists: pamModuleExists, - fingerprintAvailableForCurrentUser: FingerprintAuthAvailableForCurrentUser, - } -} - -func IsNixOS() bool { - _, err := os.Stat("/etc/NIXOS") - return err == nil -} - -func ReadAuthSettings(homeDir string) (AuthSettings, error) { - settingsPath := filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json") - data, err := os.ReadFile(settingsPath) - if err != nil { - if os.IsNotExist(err) { - return AuthSettings{}, nil - } - return AuthSettings{}, fmt.Errorf("failed to read settings at %s: %w", settingsPath, err) - } - if strings.TrimSpace(string(data)) == "" { - return AuthSettings{}, nil - } - - var settings AuthSettings - if err := json.Unmarshal(data, &settings); err != nil { - return AuthSettings{}, fmt.Errorf("failed to parse settings at %s: %w", settingsPath, err) - } - return settings, nil -} - -func ReadGreeterAuthToggles(homeDir string) (enableFprint bool, enableU2f bool, err error) { - settings, err := ReadAuthSettings(homeDir) - if err != nil { - return false, false, err - } - return settings.GreeterEnableFprint, settings.GreeterEnableU2f, nil -} - -func SyncAuthConfig(logFunc func(string), sudoPassword string, options SyncAuthOptions) error { - return syncAuthConfigWithDeps(logFunc, sudoPassword, options, defaultSyncDeps()) -} - -func RemoveManagedGreeterPamBlock(logFunc func(string), sudoPassword string) error { - return removeManagedGreeterPamBlockWithDeps(logFunc, sudoPassword, defaultSyncDeps()) -} - -func syncAuthConfigWithDeps(logFunc func(string), sudoPassword string, options SyncAuthOptions, deps syncDeps) error { - homeDir := strings.TrimSpace(options.HomeDir) - if homeDir == "" { - var err error - homeDir, err = os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) - } - } - - settings, err := ReadAuthSettings(homeDir) - if err != nil { - return err - } - - if err := syncLockscreenPamConfigWithDeps(logFunc, sudoPassword, deps); err != nil { - return err - } - if err := syncLockscreenU2FPamConfigWithDeps(logFunc, sudoPassword, settings.EnableU2f, deps); err != nil { - return err - } - - if _, err := deps.stat(deps.greetdPath); err != nil { - if os.IsNotExist(err) { - logFunc("ℹ /etc/pam.d/greetd not found. Skipping greeter PAM sync.") - return nil - } - return fmt.Errorf("failed to inspect %s: %w", deps.greetdPath, err) - } - - if err := syncGreeterPamConfigWithDeps(logFunc, sudoPassword, settings, options.ForceGreeterAuth, deps); err != nil { - return err - } - - return nil -} - -func removeManagedGreeterPamBlockWithDeps(logFunc func(string), sudoPassword string, deps syncDeps) error { - if deps.isNixOS() { - return nil - } - - data, err := deps.readFile(deps.greetdPath) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return fmt.Errorf("failed to read %s: %w", deps.greetdPath, err) - } - - originalContent := string(data) - stripped, removed := stripManagedGreeterPamBlock(originalContent) - strippedAgain, removedLegacy := stripLegacyGreeterPamLines(stripped) - if !removed && !removedLegacy { - return nil - } - - if err := writeManagedPamFile(strippedAgain, deps.greetdPath, sudoPassword, deps); err != nil { - return fmt.Errorf("failed to write %s: %w", deps.greetdPath, err) - } - - logFunc("✓ Removed DMS managed PAM block from " + deps.greetdPath) - return nil -} - -func ParseManagedGreeterPamAuth(pamText string) (managed bool, fingerprint bool, u2f bool, legacy bool) { - if pamText == "" { - return false, false, false, false - } - - lines := strings.Split(pamText, "\n") - inManaged := false - for _, line := range lines { - trimmed := strings.TrimSpace(line) - switch trimmed { - case GreeterPamManagedBlockStart: - managed = true - inManaged = true - continue - case GreeterPamManagedBlockEnd: - inManaged = false - continue - } - - if strings.HasPrefix(trimmed, legacyGreeterPamFprintComment) || strings.HasPrefix(trimmed, legacyGreeterPamU2FComment) { - legacy = true - } - if !inManaged { - continue - } - if strings.Contains(trimmed, "pam_fprintd") { - fingerprint = true - } - if strings.Contains(trimmed, "pam_u2f") { - u2f = true - } - } - - return managed, fingerprint, u2f, legacy -} - -func StripManagedGreeterPamContent(pamText string) (string, bool) { - stripped, removed := stripManagedGreeterPamBlock(pamText) - stripped, removedLegacy := stripLegacyGreeterPamLines(stripped) - return stripped, removed || removedLegacy -} - -func PamTextIncludesFile(pamText, filename string) bool { - lines := strings.Split(pamText, "\n") - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if trimmed == "" || strings.HasPrefix(trimmed, "#") { - continue - } - if strings.Contains(trimmed, filename) && - (strings.Contains(trimmed, "include") || strings.Contains(trimmed, "substack") || strings.HasPrefix(trimmed, "@include")) { - return true - } - } - return false -} - -func PamFileHasModule(pamFilePath, module string) bool { - data, err := os.ReadFile(pamFilePath) - if err != nil { - return false - } - return pamContentHasModule(string(data), module) -} - -func DetectIncludedPamModule(pamText, module string) string { - return detectIncludedPamModule(pamText, module, defaultSyncDeps()) -} - -func detectIncludedPamModule(pamText, module string, deps syncDeps) string { - for _, includedFile := range includedPamAuthFiles { - if !PamTextIncludesFile(pamText, includedFile) { - continue - } - path := filepath.Join(deps.pamDir, includedFile) - data, err := deps.readFile(path) - if err != nil { - continue - } - if pamContentHasModule(string(data), module) { - return includedFile - } - } - return "" -} - -func pamContentHasModule(content, module string) bool { - lines := strings.Split(content, "\n") - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if trimmed == "" || strings.HasPrefix(trimmed, "#") { - continue - } - if strings.Contains(trimmed, module) { - return true - } - } - return false -} - -func hasManagedLockscreenPamFile(content string) bool { - return strings.Contains(content, LockscreenPamManagedBlockStart) && - strings.Contains(content, LockscreenPamManagedBlockEnd) -} - -func hasManagedLockscreenU2FPamFile(content string) bool { - return strings.Contains(content, LockscreenU2FPamManagedBlockStart) && - strings.Contains(content, LockscreenU2FPamManagedBlockEnd) -} - -func pamDirectiveType(line string) string { - fields := strings.Fields(line) - if len(fields) == 0 { - return "" - } - - directiveType := strings.TrimPrefix(fields[0], "-") - switch directiveType { - case "auth", "account", "password", "session": - return directiveType - default: - return "" - } -} - -func isExcludedLockscreenPamLine(line string) bool { - for _, field := range strings.Fields(line) { - if strings.HasPrefix(field, "#") { - break - } - if strings.Contains(field, "pam_u2f") || strings.Contains(field, "pam_fprintd") { - return true - } - } - return false -} - -func parseLockscreenPamIncludeDirective(trimmed string, inheritedFilter string) (lockscreenPamIncludeDirective, bool) { - fields := strings.Fields(trimmed) - if len(fields) >= 2 && fields[0] == "@include" { - return lockscreenPamIncludeDirective{ - target: fields[1], - filterType: inheritedFilter, - }, true - } - - if len(fields) >= 3 && (fields[1] == "include" || fields[1] == "substack") { - lineType := pamDirectiveType(trimmed) - if lineType == "" { - return lockscreenPamIncludeDirective{}, false - } - return lockscreenPamIncludeDirective{ - target: fields[2], - filterType: lineType, - }, true - } - - if len(fields) >= 3 && fields[1] == "@include" { - lineType := pamDirectiveType(trimmed) - if lineType == "" { - return lockscreenPamIncludeDirective{}, false - } - return lockscreenPamIncludeDirective{ - target: fields[2], - filterType: lineType, - }, true - } - - return lockscreenPamIncludeDirective{}, false -} - -func resolveLockscreenPamIncludePath(pamDir, target string) (string, error) { - if strings.TrimSpace(target) == "" { - return "", fmt.Errorf("empty PAM include target") - } - - cleanPamDir := filepath.Clean(pamDir) - if filepath.IsAbs(target) { - cleanTarget := filepath.Clean(target) - if filepath.Dir(cleanTarget) != cleanPamDir { - return "", fmt.Errorf("unsupported PAM include outside %s: %s", cleanPamDir, target) - } - return cleanTarget, nil - } - - cleanTarget := filepath.Clean(target) - if cleanTarget == "." || cleanTarget == ".." || strings.HasPrefix(cleanTarget, ".."+string(os.PathSeparator)) { - return "", fmt.Errorf("invalid PAM include target: %s", target) - } - - return filepath.Join(cleanPamDir, cleanTarget), nil -} - -func (r lockscreenPamResolver) resolveService(serviceName string, filterType string, stack []string) ([]string, error) { - path, err := resolveLockscreenPamIncludePath(r.pamDir, serviceName) - if err != nil { - return nil, err - } - - for _, seen := range stack { - if seen == path { - chain := append(append([]string{}, stack...), path) - display := make([]string, 0, len(chain)) - for _, item := range chain { - display = append(display, filepath.Base(item)) - } - return nil, fmt.Errorf("cyclic PAM include detected: %s", strings.Join(display, " -> ")) - } - } - - data, err := r.readFile(path) - if err != nil { - return nil, fmt.Errorf("failed to read PAM file %s: %w", path, err) - } - - var resolved []string - for _, rawLine := range strings.Split(strings.ReplaceAll(string(data), "\r\n", "\n"), "\n") { - rawLine = strings.TrimRight(rawLine, "\r") - trimmed := strings.TrimSpace(rawLine) - if trimmed == "" || strings.HasPrefix(trimmed, "#") || trimmed == "#%PAM-1.0" { - continue - } - - if include, ok := parseLockscreenPamIncludeDirective(trimmed, filterType); ok { - lineType := pamDirectiveType(trimmed) - if filterType != "" && lineType != "" && lineType != filterType { - continue - } - - nested, err := r.resolveService(include.target, include.filterType, append(stack, path)) - if err != nil { - return nil, err - } - resolved = append(resolved, nested...) - continue - } - - lineType := pamDirectiveType(trimmed) - if lineType == "" { - return nil, fmt.Errorf("unsupported PAM directive in %s: %s", filepath.Base(path), trimmed) - } - if filterType != "" && lineType != filterType { - continue - } - if isExcludedLockscreenPamLine(trimmed) { - continue - } - - resolved = append(resolved, rawLine) - } - - return resolved, nil -} - -func buildManagedLockscreenPamContent(pamDir string, readFile func(string) ([]byte, error)) (string, error) { - resolver := lockscreenPamResolver{ - pamDir: pamDir, - readFile: readFile, - } - - resolvedLines, err := resolver.resolveService("login", "", nil) - if err != nil { - return "", err - } - if len(resolvedLines) == 0 { - return "", fmt.Errorf("no auth directives remained after filtering %s", filepath.Join(pamDir, "login")) - } - - hasAuth := false - for _, line := range resolvedLines { - if pamDirectiveType(strings.TrimSpace(line)) == "auth" { - hasAuth = true - break - } - } - if !hasAuth { - return "", fmt.Errorf("no auth directives remained after filtering %s", filepath.Join(pamDir, "login")) - } - - var b strings.Builder - b.WriteString("#%PAM-1.0\n") - b.WriteString(LockscreenPamManagedBlockStart + "\n") - for _, line := range resolvedLines { - b.WriteString(line) - b.WriteByte('\n') - } - b.WriteString(LockscreenPamManagedBlockEnd + "\n") - return b.String(), nil -} - -func buildManagedLockscreenU2FPamContent() string { - var b strings.Builder - b.WriteString("#%PAM-1.0\n") - b.WriteString(LockscreenU2FPamManagedBlockStart + "\n") - b.WriteString("auth required pam_u2f.so cue nouserok timeout=10\n") - b.WriteString(LockscreenU2FPamManagedBlockEnd + "\n") - return b.String() -} - -func syncLockscreenPamConfigWithDeps(logFunc func(string), sudoPassword string, deps syncDeps) error { - if deps.isNixOS() { - logFunc("ℹ NixOS detected. DMS continues to use /etc/pam.d/login for lock screen password auth on NixOS unless you declare security.pam.services.dankshell yourself. U2F and fingerprint are handled separately and should not be included in dankshell.") - return nil - } - - existingData, err := deps.readFile(deps.dankshellPath) - if err == nil { - if !hasManagedLockscreenPamFile(string(existingData)) { - logFunc("ℹ Custom /etc/pam.d/dankshell found (no DMS block). Skipping.") - return nil - } - } else if !os.IsNotExist(err) { - return fmt.Errorf("failed to read %s: %w", deps.dankshellPath, err) - } - - content, err := buildManagedLockscreenPamContent(deps.pamDir, deps.readFile) - if err != nil { - return fmt.Errorf("failed to build %s from %s: %w", deps.dankshellPath, filepath.Join(deps.pamDir, "login"), err) - } - - if err := writeManagedPamFile(content, deps.dankshellPath, sudoPassword, deps); err != nil { - return fmt.Errorf("failed to write %s: %w", deps.dankshellPath, err) - } - - logFunc("✓ Created or updated /etc/pam.d/dankshell for lock screen authentication") - return nil -} - -func syncLockscreenU2FPamConfigWithDeps(logFunc func(string), sudoPassword string, enabled bool, deps syncDeps) error { - if deps.isNixOS() { - logFunc("ℹ NixOS detected. DMS does not manage /etc/pam.d/dankshell-u2f on NixOS. Keep using the bundled U2F helper or configure a custom PAM service yourself.") - return nil - } - - existingData, err := deps.readFile(deps.dankshellU2fPath) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to read %s: %w", deps.dankshellU2fPath, err) - } - - if enabled { - if err == nil && !hasManagedLockscreenU2FPamFile(string(existingData)) { - logFunc("ℹ Custom /etc/pam.d/dankshell-u2f found (no DMS block). Skipping.") - return nil - } - if err := writeManagedPamFile(buildManagedLockscreenU2FPamContent(), deps.dankshellU2fPath, sudoPassword, deps); err != nil { - return fmt.Errorf("failed to write %s: %w", deps.dankshellU2fPath, err) - } - logFunc("✓ Created or updated /etc/pam.d/dankshell-u2f for lock screen security-key authentication") - return nil - } - - if os.IsNotExist(err) { - return nil - } - if err == nil && !hasManagedLockscreenU2FPamFile(string(existingData)) { - logFunc("ℹ Custom /etc/pam.d/dankshell-u2f found (no DMS block). Leaving it untouched.") - return nil - } - - if err := deps.runSudoCmd(sudoPassword, "rm", "-f", deps.dankshellU2fPath); err != nil { - return fmt.Errorf("failed to remove %s: %w", deps.dankshellU2fPath, err) - } - logFunc("✓ Removed DMS-managed /etc/pam.d/dankshell-u2f") - return nil -} - -func stripManagedGreeterPamBlock(content string) (string, bool) { - lines := strings.Split(content, "\n") - filtered := make([]string, 0, len(lines)) - inManagedBlock := false - removed := false - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if trimmed == GreeterPamManagedBlockStart { - inManagedBlock = true - removed = true - continue - } - if trimmed == GreeterPamManagedBlockEnd { - inManagedBlock = false - removed = true - continue - } - if inManagedBlock { - removed = true - continue - } - filtered = append(filtered, line) - } - - return strings.Join(filtered, "\n"), removed -} - -func stripLegacyGreeterPamLines(content string) (string, bool) { - lines := strings.Split(content, "\n") - filtered := make([]string, 0, len(lines)) - removed := false - - for i := 0; i < len(lines); i++ { - trimmed := strings.TrimSpace(lines[i]) - if strings.HasPrefix(trimmed, legacyGreeterPamFprintComment) || strings.HasPrefix(trimmed, legacyGreeterPamU2FComment) { - removed = true - if i+1 < len(lines) { - nextLine := strings.TrimSpace(lines[i+1]) - if strings.HasPrefix(nextLine, "auth") && - (strings.Contains(nextLine, "pam_fprintd") || strings.Contains(nextLine, "pam_u2f")) { - i++ - } - } - continue - } - filtered = append(filtered, lines[i]) - } - - return strings.Join(filtered, "\n"), removed -} - -func insertManagedGreeterPamBlock(content string, blockLines []string, greetdPamPath string) (string, error) { - lines := strings.Split(content, "\n") - for i, line := range lines { - trimmed := strings.TrimSpace(line) - if trimmed != "" && !strings.HasPrefix(trimmed, "#") && strings.HasPrefix(trimmed, "auth") { - block := strings.Join(blockLines, "\n") - prefix := strings.Join(lines[:i], "\n") - suffix := strings.Join(lines[i:], "\n") - switch { - case prefix == "": - return block + "\n" + suffix, nil - case suffix == "": - return prefix + "\n" + block, nil - default: - return prefix + "\n" + block + "\n" + suffix, nil - } - } - } - return "", fmt.Errorf("no auth directive found in %s", greetdPamPath) -} - -func syncGreeterPamConfigWithDeps(logFunc func(string), sudoPassword string, settings AuthSettings, forceAuth bool, deps syncDeps) error { - var wantFprint, wantU2f bool - fprintToggleEnabled := forceAuth - u2fToggleEnabled := forceAuth - if forceAuth { - wantFprint = deps.pamModuleExists("pam_fprintd.so") - wantU2f = deps.pamModuleExists("pam_u2f.so") - } else { - fprintToggleEnabled = settings.GreeterEnableFprint - u2fToggleEnabled = settings.GreeterEnableU2f - fprintModule := deps.pamModuleExists("pam_fprintd.so") - u2fModule := deps.pamModuleExists("pam_u2f.so") - wantFprint = settings.GreeterEnableFprint && fprintModule - wantU2f = settings.GreeterEnableU2f && u2fModule - if settings.GreeterEnableFprint && !fprintModule { - logFunc("⚠ Warning: greeter fingerprint toggle is enabled, but pam_fprintd.so was not found.") - } - if settings.GreeterEnableU2f && !u2fModule { - logFunc("⚠ Warning: greeter security key toggle is enabled, but pam_u2f.so was not found.") - } - } - - if deps.isNixOS() { - logFunc("ℹ NixOS detected: PAM config is managed by NixOS modules. Skipping DMS PAM block write.") - logFunc(" Configure fingerprint/U2F auth via your greetd NixOS module options (e.g. security.pam.services.greetd).") - return nil - } - - pamData, err := deps.readFile(deps.greetdPath) - if err != nil { - return fmt.Errorf("failed to read %s: %w", deps.greetdPath, err) - } - originalContent := string(pamData) - content, _ := stripManagedGreeterPamBlock(originalContent) - content, _ = stripLegacyGreeterPamLines(content) - - includedFprintFile := detectIncludedPamModule(content, "pam_fprintd.so", deps) - includedU2fFile := detectIncludedPamModule(content, "pam_u2f.so", deps) - fprintAvailableForCurrentUser := deps.fingerprintAvailableForCurrentUser() - if wantFprint && includedFprintFile != "" { - logFunc("⚠ pam_fprintd already present in included " + includedFprintFile + " (managed by authselect/pam-auth-update). Skipping DMS fprint block to avoid double-fingerprint auth.") - wantFprint = false - } - if wantU2f && includedU2fFile != "" { - logFunc("⚠ pam_u2f already present in included " + includedU2fFile + " (managed by authselect/pam-auth-update). Skipping DMS U2F block to avoid double security-key auth.") - wantU2f = false - } - if !wantFprint && includedFprintFile != "" { - if fprintToggleEnabled { - logFunc("ℹ Fingerprint auth is still enabled via included " + includedFprintFile + ".") - if fprintAvailableForCurrentUser { - logFunc(" DMS toggle is enabled, and effective auth is provided by the included PAM stack.") - } else { - logFunc(" No enrolled fingerprints detected for the current user; password auth remains the effective path.") - } - } else { - if fprintAvailableForCurrentUser { - logFunc("ℹ Fingerprint auth is active via included " + includedFprintFile + " while DMS fingerprint toggle is off.") - logFunc(" Password login will work but may be delayed while the fingerprint module runs first.") - logFunc(" To eliminate the delay, " + pamManagerHintForCurrentDistro()) - } else { - logFunc("ℹ pam_fprintd is present via included " + includedFprintFile + ", but no enrolled fingerprints were detected for the current user.") - logFunc(" Password auth remains the effective login path.") - } - } - } - if !wantU2f && includedU2fFile != "" { - if u2fToggleEnabled { - logFunc("ℹ Security-key auth is still enabled via included " + includedU2fFile + ".") - logFunc(" DMS toggle is enabled, but effective auth is provided by the included PAM stack.") - } else { - logFunc("⚠ Security-key auth is active via included " + includedU2fFile + " while DMS security-key toggle is off.") - logFunc(" " + pamManagerHintForCurrentDistro()) - } - } - - if wantFprint || wantU2f { - blockLines := []string{GreeterPamManagedBlockStart} - if wantFprint { - blockLines = append(blockLines, "auth sufficient pam_fprintd.so max-tries=1 timeout=5") - } - if wantU2f { - blockLines = append(blockLines, "auth sufficient pam_u2f.so cue nouserok timeout=10") - } - blockLines = append(blockLines, GreeterPamManagedBlockEnd) - - content, err = insertManagedGreeterPamBlock(content, blockLines, deps.greetdPath) - if err != nil { - return err - } - } - - if content == originalContent { - return nil - } - - if err := writeManagedPamFile(content, deps.greetdPath, sudoPassword, deps); err != nil { - return fmt.Errorf("failed to install updated PAM config at %s: %w", deps.greetdPath, err) - } - if wantFprint || wantU2f { - logFunc("✓ Configured greetd PAM for fingerprint/U2F") - } else { - logFunc("✓ Cleared DMS-managed greeter PAM auth block") - } - return nil -} - -func writeManagedPamFile(content string, destPath string, sudoPassword string, deps syncDeps) error { - tmpFile, err := deps.createTemp("", "dms-pam-*.conf") - if err != nil { - return err - } - tmpPath := tmpFile.Name() - defer func() { - _ = deps.removeFile(tmpPath) - }() - - if _, err := tmpFile.WriteString(content); err != nil { - tmpFile.Close() - return err - } - if err := tmpFile.Close(); err != nil { - return err - } - if err := deps.runSudoCmd(sudoPassword, "cp", tmpPath, destPath); err != nil { - return err - } - if err := deps.runSudoCmd(sudoPassword, "chmod", "644", destPath); err != nil { - return fmt.Errorf("failed to set permissions on %s: %w", destPath, err) - } - return nil -} - -func pamManagerHintForCurrentDistro() string { - osInfo, err := distros.GetOSInfo() - if err != nil { - return "Disable it in your PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } - config, exists := distros.Registry[osInfo.Distribution.ID] - if !exists { - return "Disable it in your PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } - - switch config.Family { - case distros.FamilyFedora: - return "Disable it in authselect to force password-only greeter login." - case distros.FamilyDebian, distros.FamilyUbuntu: - return "Disable it in pam-auth-update to force password-only greeter login." - default: - return "Disable it in your distro PAM manager (authselect/pam-auth-update) or in the included PAM stack to force password-only greeter login." - } -} - -func pamModuleExists(module string) bool { - for _, libDir := range []string{ - "/usr/lib64/security", - "/usr/lib/security", - "/lib64/security", - "/lib/security", - "/lib/x86_64-linux-gnu/security", - "/usr/lib/x86_64-linux-gnu/security", - "/lib/aarch64-linux-gnu/security", - "/usr/lib/aarch64-linux-gnu/security", - "/run/current-system/sw/lib64/security", - "/run/current-system/sw/lib/security", - } { - if _, err := os.Stat(filepath.Join(libDir, module)); err == nil { - return true - } - } - return false -} - -func hasEnrolledFingerprintOutput(output string) bool { - lower := strings.ToLower(output) - if strings.Contains(lower, "no fingers enrolled") || - strings.Contains(lower, "no fingerprints enrolled") || - strings.Contains(lower, "no prints enrolled") { - return false - } - if strings.Contains(lower, "has fingers enrolled") || - strings.Contains(lower, "has fingerprints enrolled") { - return true - } - for _, line := range strings.Split(lower, "\n") { - trimmed := strings.TrimSpace(line) - if strings.HasPrefix(trimmed, "finger:") { - return true - } - if strings.HasPrefix(trimmed, "- ") && strings.Contains(trimmed, "finger") { - return true - } - } - return false -} - -func FingerprintAuthAvailableForCurrentUser() bool { - username := strings.TrimSpace(os.Getenv("SUDO_USER")) - if username == "" { - username = strings.TrimSpace(os.Getenv("USER")) - } - if username == "" { - out, err := exec.Command("id", "-un").Output() - if err == nil { - username = strings.TrimSpace(string(out)) - } - } - return fingerprintAuthAvailableForUser(username) -} - -func fingerprintAuthAvailableForUser(username string) bool { - username = strings.TrimSpace(username) - if username == "" { - return false - } - if !pamModuleExists("pam_fprintd.so") { - return false - } - if _, err := exec.LookPath("fprintd-list"); err != nil { - return false - } - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - out, err := exec.CommandContext(ctx, "fprintd-list", username).CombinedOutput() - if err != nil { - return false - } - return hasEnrolledFingerprintOutput(string(out)) -} - -func runSudoCmd(sudoPassword string, command string, args ...string) error { - var cmd *exec.Cmd - - if sudoPassword != "" { - fullArgs := append([]string{command}, args...) - quotedArgs := make([]string, len(fullArgs)) - for i, arg := range fullArgs { - quotedArgs[i] = "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'" - } - cmdStr := strings.Join(quotedArgs, " ") - - cmd = distros.ExecSudoCommand(context.Background(), sudoPassword, cmdStr) - } else { - cmd = exec.Command("sudo", append([]string{command}, args...)...) - } - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam_test.go deleted file mode 100644 index 113bf10..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/pam/pam_test.go +++ /dev/null @@ -1,671 +0,0 @@ -package pam - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "testing" -) - -func writeTestFile(t *testing.T, path string, content string) { - t.Helper() - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - t.Fatalf("failed to create parent dir for %s: %v", path, err) - } - if err := os.WriteFile(path, []byte(content), 0o644); err != nil { - t.Fatalf("failed to write %s: %v", path, err) - } -} - -type pamTestEnv struct { - pamDir string - greetdPath string - dankshellPath string - dankshellU2fPath string - tmpDir string - homeDir string - availableModules map[string]bool - fingerprintAvailable bool -} - -func newPamTestEnv(t *testing.T) *pamTestEnv { - t.Helper() - - root := t.TempDir() - pamDir := filepath.Join(root, "pam.d") - tmpDir := filepath.Join(root, "tmp") - homeDir := filepath.Join(root, "home") - - for _, dir := range []string{pamDir, tmpDir, homeDir} { - if err := os.MkdirAll(dir, 0o755); err != nil { - t.Fatalf("failed to create %s: %v", dir, err) - } - } - - return &pamTestEnv{ - pamDir: pamDir, - greetdPath: filepath.Join(pamDir, "greetd"), - dankshellPath: filepath.Join(pamDir, "dankshell"), - dankshellU2fPath: filepath.Join(pamDir, "dankshell-u2f"), - tmpDir: tmpDir, - homeDir: homeDir, - availableModules: map[string]bool{}, - } -} - -func (e *pamTestEnv) writePamFile(t *testing.T, name string, content string) { - t.Helper() - writeTestFile(t, filepath.Join(e.pamDir, name), content) -} - -func (e *pamTestEnv) writeSettings(t *testing.T, content string) { - t.Helper() - writeTestFile(t, filepath.Join(e.homeDir, ".config", "DankMaterialShell", "settings.json"), content) -} - -func (e *pamTestEnv) deps(isNixOS bool) syncDeps { - return syncDeps{ - pamDir: e.pamDir, - greetdPath: e.greetdPath, - dankshellPath: e.dankshellPath, - dankshellU2fPath: e.dankshellU2fPath, - isNixOS: func() bool { return isNixOS }, - readFile: os.ReadFile, - stat: os.Stat, - createTemp: func(_ string, pattern string) (*os.File, error) { - return os.CreateTemp(e.tmpDir, pattern) - }, - removeFile: os.Remove, - runSudoCmd: func(_ string, command string, args ...string) error { - switch command { - case "cp": - if len(args) != 2 { - return fmt.Errorf("unexpected cp args: %v", args) - } - data, err := os.ReadFile(args[0]) - if err != nil { - return err - } - if err := os.MkdirAll(filepath.Dir(args[1]), 0o755); err != nil { - return err - } - return os.WriteFile(args[1], data, 0o644) - case "chmod": - if len(args) != 2 { - return fmt.Errorf("unexpected chmod args: %v", args) - } - return nil - case "rm": - if len(args) != 2 || args[0] != "-f" { - return fmt.Errorf("unexpected rm args: %v", args) - } - if err := os.Remove(args[1]); err != nil && !os.IsNotExist(err) { - return err - } - return nil - default: - return fmt.Errorf("unexpected sudo command: %s %v", command, args) - } - }, - pamModuleExists: func(module string) bool { - return e.availableModules[module] - }, - fingerprintAvailableForCurrentUser: func() bool { - return e.fingerprintAvailable - }, - } -} - -func readFileString(t *testing.T, path string) string { - t.Helper() - data, err := os.ReadFile(path) - if err != nil { - t.Fatalf("failed to read %s: %v", path, err) - } - return string(data) -} - -func TestHasManagedLockscreenPamFile(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - content string - want bool - }{ - { - name: "both markers present", - content: "#%PAM-1.0\n" + - LockscreenPamManagedBlockStart + "\n" + - "auth sufficient pam_unix.so\n" + - LockscreenPamManagedBlockEnd + "\n", - want: true, - }, - { - name: "missing end marker is not managed", - content: "#%PAM-1.0\n" + - LockscreenPamManagedBlockStart + "\n" + - "auth sufficient pam_unix.so\n", - want: false, - }, - { - name: "custom file is not managed", - content: "#%PAM-1.0\nauth sufficient pam_unix.so\n", - want: false, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - if got := hasManagedLockscreenPamFile(tt.content); got != tt.want { - t.Fatalf("hasManagedLockscreenPamFile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestBuildManagedLockscreenPamContent(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - files map[string]string - wantContains []string - wantNotContains []string - wantCounts map[string]int - wantErr string - }{ - { - name: "preserves custom modules and strips direct u2f and fprint directives", - files: map[string]string{ - "login": "#%PAM-1.0\n" + - "auth include system-auth\n" + - "account include system-auth\n" + - "session include system-auth\n", - "system-auth": "auth requisite pam_nologin.so\n" + - "auth sufficient pam_unix.so try_first_pass nullok\n" + - "auth sufficient pam_u2f.so cue\n" + - "auth sufficient pam_fprintd.so max-tries=1\n" + - "auth required pam_radius_auth.so conf=/etc/raddb/server\n" + - "account required pam_access.so\n" + - "session optional pam_lastlog.so silent\n", - }, - wantContains: []string{ - "#%PAM-1.0", - LockscreenPamManagedBlockStart, - LockscreenPamManagedBlockEnd, - "auth requisite pam_nologin.so", - "auth sufficient pam_unix.so try_first_pass nullok", - "auth required pam_radius_auth.so conf=/etc/raddb/server", - "account required pam_access.so", - "session optional pam_lastlog.so silent", - }, - wantNotContains: []string{ - "pam_u2f", - "pam_fprintd", - }, - wantCounts: map[string]int{ - "auth required pam_radius_auth.so conf=/etc/raddb/server": 1, - "account required pam_access.so": 1, - }, - }, - { - name: "resolves nested include substack and @include transitively", - files: map[string]string{ - "login": "#%PAM-1.0\n" + - "auth include system-auth\n" + - "account include system-auth\n" + - "password include system-auth\n" + - "session include system-auth\n", - "system-auth": "auth substack custom-auth\n" + - "account include custom-auth\n" + - "password include custom-auth\n" + - "session @include common-session\n", - "custom-auth": "auth required pam_custom.so one=two\n" + - "account required pam_custom_account.so\n" + - "password required pam_custom_password.so\n", - "common-session": "session optional pam_fprintd.so max-tries=1\n" + - "session optional pam_lastlog.so silent\n", - }, - wantContains: []string{ - "auth required pam_custom.so one=two", - "account required pam_custom_account.so", - "password required pam_custom_password.so", - "session optional pam_lastlog.so silent", - }, - wantNotContains: []string{ - "pam_fprintd", - }, - wantCounts: map[string]int{ - "auth required pam_custom.so one=two": 1, - "account required pam_custom_account.so": 1, - "password required pam_custom_password.so": 1, - "session optional pam_lastlog.so silent": 1, - }, - }, - { - name: "missing include fails", - files: map[string]string{ - "login": "#%PAM-1.0\nauth include missing-auth\n", - }, - wantErr: "failed to read PAM file", - }, - { - name: "cyclic include fails", - files: map[string]string{ - "login": "#%PAM-1.0\nauth include system-auth\n", - "system-auth": "auth include login\n", - }, - wantErr: "cyclic PAM include detected", - }, - { - name: "no auth directives remain after filtering fails", - files: map[string]string{ - "login": "#%PAM-1.0\nauth include system-auth\n", - "system-auth": "auth sufficient pam_u2f.so cue\n", - }, - wantErr: "no auth directives remained after filtering", - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - for name, content := range tt.files { - env.writePamFile(t, name, content) - } - - content, err := buildManagedLockscreenPamContent(env.pamDir, os.ReadFile) - if tt.wantErr != "" { - if err == nil { - t.Fatalf("expected error containing %q, got nil", tt.wantErr) - } - if !strings.Contains(err.Error(), tt.wantErr) { - t.Fatalf("error = %q, want substring %q", err.Error(), tt.wantErr) - } - return - } - if err != nil { - t.Fatalf("buildManagedLockscreenPamContent returned error: %v", err) - } - - for _, want := range tt.wantContains { - if !strings.Contains(content, want) { - t.Errorf("missing expected string %q in output:\n%s", want, content) - } - } - for _, notWant := range tt.wantNotContains { - if strings.Contains(content, notWant) { - t.Errorf("unexpected string %q found in output:\n%s", notWant, content) - } - } - for want, wantCount := range tt.wantCounts { - if gotCount := strings.Count(content, want); gotCount != wantCount { - t.Errorf("count for %q = %d, want %d\noutput:\n%s", want, gotCount, wantCount, content) - } - } - }) - } -} - -func TestSyncLockscreenPamConfigWithDeps(t *testing.T) { - t.Parallel() - - t.Run("custom dankshell file is skipped untouched", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - customContent := "#%PAM-1.0\nauth required pam_unix.so\n" - env.writePamFile(t, "dankshell", customContent) - - var logs []string - err := syncLockscreenPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", env.deps(false)) - if err != nil { - t.Fatalf("syncLockscreenPamConfigWithDeps returned error: %v", err) - } - - if got := readFileString(t, env.dankshellPath); got != customContent { - t.Fatalf("custom dankshell content changed\ngot:\n%s\nwant:\n%s", got, customContent) - } - if len(logs) == 0 || !strings.Contains(logs[0], "Custom /etc/pam.d/dankshell found") { - t.Fatalf("expected custom-file skip log, got %v", logs) - } - }) - - t.Run("managed dankshell file is rewritten from resolved login stack", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.writePamFile(t, "login", "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n") - env.writePamFile(t, "system-auth", "auth sufficient pam_unix.so try_first_pass nullok\nauth sufficient pam_u2f.so cue\naccount required pam_access.so\n") - env.writePamFile(t, "dankshell", "#%PAM-1.0\n"+LockscreenPamManagedBlockStart+"\nauth required pam_env.so\n"+LockscreenPamManagedBlockEnd+"\n") - - var logs []string - err := syncLockscreenPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", env.deps(false)) - if err != nil { - t.Fatalf("syncLockscreenPamConfigWithDeps returned error: %v", err) - } - - output := readFileString(t, env.dankshellPath) - for _, want := range []string{ - LockscreenPamManagedBlockStart, - "auth sufficient pam_unix.so try_first_pass nullok", - "account required pam_access.so", - LockscreenPamManagedBlockEnd, - } { - if !strings.Contains(output, want) { - t.Errorf("missing expected string %q in rewritten dankshell:\n%s", want, output) - } - } - if strings.Contains(output, "pam_u2f") { - t.Errorf("rewritten dankshell still contains pam_u2f:\n%s", output) - } - if len(logs) == 0 || !strings.Contains(logs[len(logs)-1], "Created or updated /etc/pam.d/dankshell") { - t.Fatalf("expected success log, got %v", logs) - } - }) - - t.Run("mutable systems fail when login stack cannot be converted safely", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - err := syncLockscreenPamConfigWithDeps(func(string) {}, "", env.deps(false)) - if err == nil { - t.Fatal("expected error when login PAM file is missing, got nil") - } - if !strings.Contains(err.Error(), "failed to build") { - t.Fatalf("error = %q, want substring %q", err.Error(), "failed to build") - } - }) - - t.Run("NixOS remains informational and does not write dankshell", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - var logs []string - - err := syncLockscreenPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", env.deps(true)) - if err != nil { - t.Fatalf("syncLockscreenPamConfigWithDeps returned error on NixOS path: %v", err) - } - if len(logs) == 0 || !strings.Contains(logs[0], "NixOS detected") || !strings.Contains(logs[0], "/etc/pam.d/login") { - t.Fatalf("expected NixOS informational log mentioning /etc/pam.d/login, got %v", logs) - } - if _, err := os.Stat(env.dankshellPath); !os.IsNotExist(err) { - t.Fatalf("expected no dankshell file to be written on NixOS path, stat err = %v", err) - } - }) -} - -func TestSyncLockscreenU2FPamConfigWithDeps(t *testing.T) { - t.Parallel() - - t.Run("enabled creates managed file", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - var logs []string - - err := syncLockscreenU2FPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", true, env.deps(false)) - if err != nil { - t.Fatalf("syncLockscreenU2FPamConfigWithDeps returned error: %v", err) - } - - got := readFileString(t, env.dankshellU2fPath) - if got != buildManagedLockscreenU2FPamContent() { - t.Fatalf("unexpected managed dankshell-u2f content:\n%s", got) - } - if len(logs) == 0 || !strings.Contains(logs[len(logs)-1], "Created or updated /etc/pam.d/dankshell-u2f") { - t.Fatalf("expected create log, got %v", logs) - } - }) - - t.Run("enabled rewrites existing managed file", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.writePamFile(t, "dankshell-u2f", "#%PAM-1.0\n"+LockscreenU2FPamManagedBlockStart+"\nauth required pam_u2f.so old\n"+LockscreenU2FPamManagedBlockEnd+"\n") - - if err := syncLockscreenU2FPamConfigWithDeps(func(string) {}, "", true, env.deps(false)); err != nil { - t.Fatalf("syncLockscreenU2FPamConfigWithDeps returned error: %v", err) - } - if got := readFileString(t, env.dankshellU2fPath); got != buildManagedLockscreenU2FPamContent() { - t.Fatalf("managed dankshell-u2f was not rewritten:\n%s", got) - } - }) - - t.Run("disabled removes DMS-managed file", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.writePamFile(t, "dankshell-u2f", buildManagedLockscreenU2FPamContent()) - - var logs []string - err := syncLockscreenU2FPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", false, env.deps(false)) - if err != nil { - t.Fatalf("syncLockscreenU2FPamConfigWithDeps returned error: %v", err) - } - if _, err := os.Stat(env.dankshellU2fPath); !os.IsNotExist(err) { - t.Fatalf("expected managed dankshell-u2f to be removed, stat err = %v", err) - } - if len(logs) == 0 || !strings.Contains(logs[len(logs)-1], "Removed DMS-managed /etc/pam.d/dankshell-u2f") { - t.Fatalf("expected removal log, got %v", logs) - } - }) - - t.Run("disabled preserves custom file", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - customContent := "#%PAM-1.0\nauth required pam_u2f.so cue\n" - env.writePamFile(t, "dankshell-u2f", customContent) - - var logs []string - err := syncLockscreenU2FPamConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", false, env.deps(false)) - if err != nil { - t.Fatalf("syncLockscreenU2FPamConfigWithDeps returned error: %v", err) - } - if got := readFileString(t, env.dankshellU2fPath); got != customContent { - t.Fatalf("custom dankshell-u2f content changed\ngot:\n%s\nwant:\n%s", got, customContent) - } - if len(logs) == 0 || !strings.Contains(logs[0], "Custom /etc/pam.d/dankshell-u2f found") { - t.Fatalf("expected custom-file log, got %v", logs) - } - }) -} - -func TestSyncGreeterPamConfigWithDeps(t *testing.T) { - t.Parallel() - - t.Run("adds managed block for enabled auth modules", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.availableModules["pam_fprintd.so"] = true - env.availableModules["pam_u2f.so"] = true - env.writePamFile(t, "greetd", "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n") - env.writePamFile(t, "system-auth", "auth sufficient pam_unix.so\naccount required pam_unix.so\n") - - settings := AuthSettings{GreeterEnableFprint: true, GreeterEnableU2f: true} - if err := syncGreeterPamConfigWithDeps(func(string) {}, "", settings, false, env.deps(false)); err != nil { - t.Fatalf("syncGreeterPamConfigWithDeps returned error: %v", err) - } - - got := readFileString(t, env.greetdPath) - for _, want := range []string{ - GreeterPamManagedBlockStart, - "auth sufficient pam_fprintd.so max-tries=1 timeout=5", - "auth sufficient pam_u2f.so cue nouserok timeout=10", - GreeterPamManagedBlockEnd, - } { - if !strings.Contains(got, want) { - t.Errorf("missing expected string %q in greetd PAM:\n%s", want, got) - } - } - if strings.Index(got, GreeterPamManagedBlockStart) > strings.Index(got, "auth include system-auth") { - t.Fatalf("managed block was not inserted before first auth line:\n%s", got) - } - }) - - t.Run("avoids duplicate fingerprint when included stack already provides it", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.availableModules["pam_fprintd.so"] = true - env.fingerprintAvailable = true - original := "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n" - env.writePamFile(t, "greetd", original) - env.writePamFile(t, "system-auth", "auth sufficient pam_fprintd.so max-tries=1\nauth sufficient pam_unix.so\n") - - settings := AuthSettings{GreeterEnableFprint: true} - if err := syncGreeterPamConfigWithDeps(func(string) {}, "", settings, false, env.deps(false)); err != nil { - t.Fatalf("syncGreeterPamConfigWithDeps returned error: %v", err) - } - - got := readFileString(t, env.greetdPath) - if got != original { - t.Fatalf("greetd PAM changed despite included pam_fprintd stack\ngot:\n%s\nwant:\n%s", got, original) - } - if strings.Contains(got, GreeterPamManagedBlockStart) { - t.Fatalf("managed block should not be inserted when included stack already has pam_fprintd:\n%s", got) - } - }) -} - -func TestRemoveManagedGreeterPamBlockWithDeps(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.writePamFile(t, "greetd", "#%PAM-1.0\n"+ - legacyGreeterPamFprintComment+"\n"+ - "auth sufficient pam_fprintd.so max-tries=1\n"+ - GreeterPamManagedBlockStart+"\n"+ - "auth sufficient pam_u2f.so cue nouserok timeout=10\n"+ - GreeterPamManagedBlockEnd+"\n"+ - "auth include system-auth\n") - - if err := removeManagedGreeterPamBlockWithDeps(func(string) {}, "", env.deps(false)); err != nil { - t.Fatalf("removeManagedGreeterPamBlockWithDeps returned error: %v", err) - } - - got := readFileString(t, env.greetdPath) - if strings.Contains(got, GreeterPamManagedBlockStart) || strings.Contains(got, legacyGreeterPamFprintComment) { - t.Fatalf("managed or legacy DMS auth lines remained in greetd PAM:\n%s", got) - } - if !strings.Contains(got, "auth include system-auth") { - t.Fatalf("expected non-DMS greetd auth lines to remain:\n%s", got) - } -} - -func TestSyncAuthConfigWithDeps(t *testing.T) { - t.Parallel() - - t.Run("creates lockscreen targets and skips greetd when greeter is not installed", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.writeSettings(t, `{"enableU2f":true}`) - env.writePamFile(t, "login", "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n") - env.writePamFile(t, "system-auth", "auth sufficient pam_unix.so try_first_pass nullok\naccount required pam_access.so\n") - - var logs []string - err := syncAuthConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", SyncAuthOptions{HomeDir: env.homeDir}, env.deps(false)) - if err != nil { - t.Fatalf("syncAuthConfigWithDeps returned error: %v", err) - } - - if _, err := os.Stat(env.dankshellPath); err != nil { - t.Fatalf("expected dankshell to be created: %v", err) - } - if got := readFileString(t, env.dankshellU2fPath); got != buildManagedLockscreenU2FPamContent() { - t.Fatalf("unexpected dankshell-u2f content:\n%s", got) - } - if len(logs) == 0 || !strings.Contains(logs[len(logs)-1], "greetd not found") { - t.Fatalf("expected greetd skip log, got %v", logs) - } - }) - - t.Run("separate greeter and lockscreen toggles are respected", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.availableModules["pam_fprintd.so"] = true - env.writeSettings(t, `{"enableU2f":false,"greeterEnableFprint":true,"greeterEnableU2f":false}`) - env.writePamFile(t, "login", "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n") - env.writePamFile(t, "system-auth", "auth sufficient pam_unix.so try_first_pass nullok\naccount required pam_access.so\n") - env.writePamFile(t, "greetd", "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n") - - err := syncAuthConfigWithDeps(func(string) {}, "", SyncAuthOptions{HomeDir: env.homeDir}, env.deps(false)) - if err != nil { - t.Fatalf("syncAuthConfigWithDeps returned error: %v", err) - } - - dankshell := readFileString(t, env.dankshellPath) - if strings.Contains(dankshell, "pam_fprintd") || strings.Contains(dankshell, "pam_u2f") { - t.Fatalf("lockscreen PAM should strip fingerprint and U2F modules:\n%s", dankshell) - } - if _, err := os.Stat(env.dankshellU2fPath); !os.IsNotExist(err) { - t.Fatalf("expected dankshell-u2f to remain absent when enableU2f is false, stat err = %v", err) - } - - greetd := readFileString(t, env.greetdPath) - if !strings.Contains(greetd, "auth sufficient pam_fprintd.so max-tries=1 timeout=5") { - t.Fatalf("expected greetd PAM to receive fingerprint auth block:\n%s", greetd) - } - if strings.Contains(greetd, "auth sufficient pam_u2f.so cue nouserok timeout=10") { - t.Fatalf("did not expect greetd PAM to receive U2F auth block:\n%s", greetd) - } - }) - - t.Run("NixOS remains informational and non-mutating", func(t *testing.T) { - t.Parallel() - - env := newPamTestEnv(t) - env.availableModules["pam_fprintd.so"] = true - env.availableModules["pam_u2f.so"] = true - env.writeSettings(t, `{"enableU2f":true,"greeterEnableFprint":true,"greeterEnableU2f":true}`) - originalGreetd := "#%PAM-1.0\nauth include system-auth\naccount include system-auth\n" - env.writePamFile(t, "greetd", originalGreetd) - - var logs []string - err := syncAuthConfigWithDeps(func(msg string) { - logs = append(logs, msg) - }, "", SyncAuthOptions{HomeDir: env.homeDir}, env.deps(true)) - if err != nil { - t.Fatalf("syncAuthConfigWithDeps returned error: %v", err) - } - - if _, err := os.Stat(env.dankshellPath); !os.IsNotExist(err) { - t.Fatalf("expected dankshell to remain absent on NixOS path, stat err = %v", err) - } - if _, err := os.Stat(env.dankshellU2fPath); !os.IsNotExist(err) { - t.Fatalf("expected dankshell-u2f to remain absent on NixOS path, stat err = %v", err) - } - if got := readFileString(t, env.greetdPath); got != originalGreetd { - t.Fatalf("expected greetd PAM to remain unchanged on NixOS path\ngot:\n%s\nwant:\n%s", got, originalGreetd) - } - if len(logs) < 2 || !strings.Contains(strings.Join(logs, "\n"), "NixOS detected") { - t.Fatalf("expected informational NixOS logs, got %v", logs) - } - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager.go deleted file mode 100644 index 1c0ddf5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager.go +++ /dev/null @@ -1,588 +0,0 @@ -package plugins - -import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/afero" -) - -type Manager struct { - fs afero.Fs - pluginsDir string - gitClient GitClient -} - -func NewManager() (*Manager, error) { - return NewManagerWithFs(afero.NewOsFs()) -} - -func NewManagerWithFs(fs afero.Fs) (*Manager, error) { - pluginsDir := getPluginsDir() - return &Manager{ - fs: fs, - pluginsDir: pluginsDir, - gitClient: &realGitClient{}, - }, nil -} - -func getPluginsDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - log.Error("failed to get user config dir", "err", err) - return "" - } - return filepath.Join(configDir, "DankMaterialShell", "plugins") -} - -func (m *Manager) IsInstalled(plugin Plugin) (bool, error) { - path, err := m.findInstalledPath(plugin.ID) - if err != nil { - return false, err - } - return path != "", nil -} - -func (m *Manager) findInstalledPath(pluginID string) (string, error) { - // Check user plugins directory - path, err := m.findInDir(m.pluginsDir, pluginID) - if err != nil { - return "", err - } - if path != "" { - return path, nil - } - - // Check system plugins directory - systemDir := "/etc/xdg/quickshell/dms-plugins" - return m.findInDir(systemDir, pluginID) -} - -func (m *Manager) findInDir(dir, pluginID string) (string, error) { - // First, check if folder with exact ID name exists - exactPath := filepath.Join(dir, pluginID) - if exists, _ := afero.DirExists(m.fs, exactPath); exists { - return exactPath, nil - } - - // Scan all folders and check plugin.json for matching ID - exists, err := afero.DirExists(m.fs, dir) - if err != nil || !exists { - return "", nil - } - - entries, err := afero.ReadDir(m.fs, dir) - if err != nil { - return "", nil - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(dir, name) - isPlugin := entry.IsDir() || entry.Mode()&os.ModeSymlink != 0 - if !isPlugin { - if info, err := m.fs.Stat(fullPath); err == nil && info.IsDir() { - isPlugin = true - } - } - - if isPlugin && m.getPluginID(fullPath) == pluginID { - return fullPath, nil - } - } - - return "", nil -} - -func (m *Manager) Install(plugin Plugin) error { - pluginPath := filepath.Join(m.pluginsDir, plugin.ID) - - exists, err := afero.DirExists(m.fs, pluginPath) - if err != nil { - return fmt.Errorf("failed to check if plugin exists: %w", err) - } - - if exists { - return fmt.Errorf("plugin already installed: %s", plugin.Name) - } - - if err := m.fs.MkdirAll(m.pluginsDir, 0o755); err != nil { - return fmt.Errorf("failed to create plugins directory: %w", err) - } - - reposDir := filepath.Join(m.pluginsDir, ".repos") - if err := m.fs.MkdirAll(reposDir, 0o755); err != nil { - return fmt.Errorf("failed to create repos directory: %w", err) - } - - if plugin.Path != "" { - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - repoExists, err := afero.DirExists(m.fs, repoPath) - if err != nil { - return fmt.Errorf("failed to check if repo exists: %w", err) - } - - if !repoExists { - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - m.fs.RemoveAll(repoPath) //nolint:errcheck - return fmt.Errorf("failed to clone repository: %w", err) - } - } else { - // Pull latest changes if repo already exists - if err := m.gitClient.Pull(repoPath); err != nil { - // If pull fails (e.g., corrupted shallow clone), delete and re-clone - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to remove corrupted repository: %w", err) - } - - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone repository: %w", err) - } - } - } - - sourcePath := filepath.Join(repoPath, plugin.Path) - sourceExists, err := afero.DirExists(m.fs, sourcePath) - if err != nil { - return fmt.Errorf("failed to check plugin path: %w", err) - } - if !sourceExists { - return fmt.Errorf("plugin path does not exist in repository: %s", plugin.Path) - } - - if err := m.createSymlink(sourcePath, pluginPath); err != nil { - return fmt.Errorf("failed to create symlink: %w", err) - } - - metaPath := pluginPath + ".meta" - metaContent := fmt.Sprintf("repo=%s\npath=%s\nrepodir=%s", plugin.Repo, plugin.Path, repoName) - if err := afero.WriteFile(m.fs, metaPath, []byte(metaContent), 0o644); err != nil { - return fmt.Errorf("failed to write metadata: %w", err) - } - } else { - if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil { - m.fs.RemoveAll(pluginPath) //nolint:errcheck - return fmt.Errorf("failed to clone plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) getRepoName(repoURL string) string { - hash := sha256.Sum256([]byte(repoURL)) - return hex.EncodeToString(hash[:])[:16] -} - -func (m *Manager) createSymlink(source, dest string) error { - if symlinkFs, ok := m.fs.(afero.Symlinker); ok { - return symlinkFs.SymlinkIfPossible(source, dest) - } - return os.Symlink(source, dest) -} - -func (m *Manager) Update(plugin Plugin) error { - pluginPath, err := m.findInstalledPath(plugin.ID) - if err != nil { - return fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot update system plugin: %s", plugin.Name) - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - // Try to pull, if it fails (e.g., shallow clone corruption), delete and re-clone - if err := m.gitClient.Pull(repoPath); err != nil { - // Repository is likely corrupted or has issues, delete and re-clone - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to remove corrupted repository: %w", err) - } - - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone repository: %w", err) - } - } - } else { - // Try to pull, if it fails, delete and re-clone - if err := m.gitClient.Pull(pluginPath); err != nil { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove corrupted plugin: %w", err) - } - - if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone plugin: %w", err) - } - } - } - - return nil -} - -func (m *Manager) Uninstall(plugin Plugin) error { - pluginPath, err := m.findInstalledPath(plugin.ID) - if err != nil { - return fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot uninstall system plugin: %s", plugin.Name) - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - shouldCleanup, err := m.shouldCleanupRepo(repoPath, plugin.Repo, plugin.ID) - if err != nil { - return fmt.Errorf("failed to check repo cleanup: %w", err) - } - - if err := m.fs.Remove(pluginPath); err != nil { - return fmt.Errorf("failed to remove symlink: %w", err) - } - - if err := m.fs.Remove(metaPath); err != nil { - return fmt.Errorf("failed to remove metadata: %w", err) - } - - if shouldCleanup { - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to cleanup repository: %w", err) - } - } - } else { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) shouldCleanupRepo(repoPath, repoURL, excludePlugin string) (bool, error) { - installed, err := m.ListInstalled() - if err != nil { - return false, err - } - - registry, err := NewRegistry() - if err != nil { - return false, err - } - - allPlugins, err := registry.List() - if err != nil { - return false, err - } - - for _, id := range installed { - if id == excludePlugin { - continue - } - - for _, p := range allPlugins { - if p.ID == id && p.Repo == repoURL && p.Path != "" { - return false, nil - } - } - } - - return true, nil -} - -func (m *Manager) ListInstalled() ([]string, error) { - installedMap := make(map[string]bool) - - exists, err := afero.DirExists(m.fs, m.pluginsDir) - if err != nil { - return nil, err - } - - if exists { - entries, err := afero.ReadDir(m.fs, m.pluginsDir) - if err != nil { - return nil, fmt.Errorf("failed to read plugins directory: %w", err) - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(m.pluginsDir, name) - isPlugin := false - - if entry.IsDir() { - isPlugin = true - } else if entry.Mode()&os.ModeSymlink != 0 { - isPlugin = true - } else { - info, err := m.fs.Stat(fullPath) - if err == nil && info.IsDir() { - isPlugin = true - } - } - - if isPlugin { - // Read plugin.json to get the actual plugin ID - pluginID := m.getPluginID(fullPath) - if pluginID != "" { - installedMap[pluginID] = true - } - } - } - } - - systemPluginsDir := "/etc/xdg/quickshell/dms-plugins" - systemExists, err := afero.DirExists(m.fs, systemPluginsDir) - if err == nil && systemExists { - entries, err := afero.ReadDir(m.fs, systemPluginsDir) - if err == nil { - for _, entry := range entries { - if entry.IsDir() { - fullPath := filepath.Join(systemPluginsDir, entry.Name()) - // Read plugin.json to get the actual plugin ID - pluginID := m.getPluginID(fullPath) - if pluginID != "" { - installedMap[pluginID] = true - } - } - } - } - } - - var installed []string - for name := range installedMap { - installed = append(installed, name) - } - - return installed, nil -} - -// getPluginID reads the plugin.json file and returns the plugin ID -func (m *Manager) getPluginID(pluginPath string) string { - manifest := m.getPluginManifest(pluginPath) - if manifest == nil { - return "" - } - return manifest.ID -} - -func (m *Manager) getPluginManifest(pluginPath string) *pluginManifest { - manifestPath := filepath.Join(pluginPath, "plugin.json") - data, err := afero.ReadFile(m.fs, manifestPath) - if err != nil { - return nil - } - - var manifest pluginManifest - if err := json.Unmarshal(data, &manifest); err != nil { - return nil - } - - return &manifest -} - -type pluginManifest struct { - ID string `json:"id"` - Name string `json:"name"` -} - -func (m *Manager) GetPluginsDir() string { - return m.pluginsDir -} - -func (m *Manager) UninstallByIDOrName(idOrName string) error { - pluginPath, err := m.findInstalledPathByIDOrName(idOrName) - if err != nil { - return err - } - if pluginPath == "" { - return fmt.Errorf("plugin not found: %s", idOrName) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot uninstall system plugin: %s", idOrName) - } - - metaPath := pluginPath + ".meta" - metaExists, _ := afero.Exists(m.fs, metaPath) - - if metaExists { - if err := m.fs.Remove(pluginPath); err != nil { - return fmt.Errorf("failed to remove symlink: %w", err) - } - if err := m.fs.Remove(metaPath); err != nil { - return fmt.Errorf("failed to remove metadata: %w", err) - } - } else { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) UpdateByIDOrName(idOrName string) error { - pluginPath, err := m.findInstalledPathByIDOrName(idOrName) - if err != nil { - return err - } - if pluginPath == "" { - return fmt.Errorf("plugin not found: %s", idOrName) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot update system plugin: %s", idOrName) - } - - metaPath := pluginPath + ".meta" - metaExists, _ := afero.Exists(m.fs, metaPath) - - if metaExists { - // Plugin is from monorepo, but we don't know the repo URL without registry - // Just try to pull from existing .git in the symlink target - return fmt.Errorf("cannot update monorepo plugin without registry info: %s", idOrName) - } - - // Standalone plugin - just pull - if err := m.gitClient.Pull(pluginPath); err != nil { - return fmt.Errorf("failed to update plugin: %w", err) - } - - return nil -} - -func (m *Manager) findInstalledPathByIDOrName(idOrName string) (string, error) { - path, err := m.findInDirByIDOrName(m.pluginsDir, idOrName) - if err != nil { - return "", err - } - if path != "" { - return path, nil - } - - systemDir := "/etc/xdg/quickshell/dms-plugins" - return m.findInDirByIDOrName(systemDir, idOrName) -} - -func (m *Manager) findInDirByIDOrName(dir, idOrName string) (string, error) { - // Check exact folder name match first - exactPath := filepath.Join(dir, idOrName) - if exists, _ := afero.DirExists(m.fs, exactPath); exists { - return exactPath, nil - } - - exists, err := afero.DirExists(m.fs, dir) - if err != nil || !exists { - return "", nil - } - - entries, err := afero.ReadDir(m.fs, dir) - if err != nil { - return "", nil - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(dir, name) - isPlugin := entry.IsDir() || entry.Mode()&os.ModeSymlink != 0 - if !isPlugin { - if info, err := m.fs.Stat(fullPath); err == nil && info.IsDir() { - isPlugin = true - } - } - - if !isPlugin { - continue - } - - manifest := m.getPluginManifest(fullPath) - if manifest == nil { - continue - } - - if manifest.ID == idOrName || manifest.Name == idOrName { - return fullPath, nil - } - } - - return "", nil -} - -func (m *Manager) HasUpdates(pluginID string, plugin Plugin) (bool, error) { - pluginPath, err := m.findInstalledPath(pluginID) - if err != nil { - return false, fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return false, fmt.Errorf("plugin not installed: %s", pluginID) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return false, nil - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return false, fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - // Plugin is from a monorepo, check the repo directory - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - return m.gitClient.HasUpdates(repoPath) - } - - // Plugin is a standalone repo - return m.gitClient.HasUpdates(pluginPath) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager_test.go deleted file mode 100644 index 485479e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/manager_test.go +++ /dev/null @@ -1,247 +0,0 @@ -package plugins - -import ( - "os" - "path/filepath" - "testing" - - "github.com/spf13/afero" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func setupTestManager(t *testing.T) (*Manager, afero.Fs, string) { - fs := afero.NewMemMapFs() - pluginsDir := "/test-plugins" - manager := &Manager{ - fs: fs, - pluginsDir: pluginsDir, - gitClient: &mockGitClient{}, - } - return manager, fs, pluginsDir -} - -func TestNewManager(t *testing.T) { - manager, err := NewManager() - assert.NoError(t, err) - assert.NotNil(t, manager) - assert.NotEmpty(t, manager.pluginsDir) -} - -func TestGetPluginsDir(t *testing.T) { - t.Run("uses XDG_CONFIG_HOME when set", func(t *testing.T) { - oldConfig := os.Getenv("XDG_CONFIG_HOME") - defer func() { - if oldConfig != "" { - os.Setenv("XDG_CONFIG_HOME", oldConfig) - } else { - os.Unsetenv("XDG_CONFIG_HOME") - } - }() - - os.Setenv("XDG_CONFIG_HOME", "/tmp/test-config") - dir := getPluginsDir() - assert.Equal(t, "/tmp/test-config/DankMaterialShell/plugins", dir) - }) - - t.Run("falls back to home directory", func(t *testing.T) { - oldConfig := os.Getenv("XDG_CONFIG_HOME") - defer func() { - if oldConfig != "" { - os.Setenv("XDG_CONFIG_HOME", oldConfig) - } else { - os.Unsetenv("XDG_CONFIG_HOME") - } - }() - - os.Unsetenv("XDG_CONFIG_HOME") - dir := getPluginsDir() - assert.Contains(t, dir, ".config/DankMaterialShell/plugins") - }) -} - -func TestIsInstalled(t *testing.T) { - t.Run("returns true when plugin is installed", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"} - pluginPath := filepath.Join(pluginsDir, plugin.ID) - err := fs.MkdirAll(pluginPath, 0o755) - require.NoError(t, err) - - installed, err := manager.IsInstalled(plugin) - assert.NoError(t, err) - assert.True(t, installed) - }) - - t.Run("returns false when plugin is not installed", func(t *testing.T) { - manager, _, _ := setupTestManager(t) - - plugin := Plugin{ID: "non-existent", Name: "NonExistent"} - installed, err := manager.IsInstalled(plugin) - assert.NoError(t, err) - assert.False(t, installed) - }) -} - -func TestInstall(t *testing.T) { - t.Run("installs plugin successfully", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - plugin := Plugin{ - ID: "test-plugin", - Name: "TestPlugin", - Repo: "https://github.com/test/plugin", - } - - cloneCalled := false - mockGit := &mockGitClient{ - cloneFunc: func(path string, url string) error { - cloneCalled = true - assert.Equal(t, filepath.Join(pluginsDir, plugin.ID), path) - assert.Equal(t, plugin.Repo, url) - return fs.MkdirAll(path, 0o755) - }, - } - manager.gitClient = mockGit - - err := manager.Install(plugin) - assert.NoError(t, err) - assert.True(t, cloneCalled) - - exists, _ := afero.DirExists(fs, filepath.Join(pluginsDir, plugin.ID)) - assert.True(t, exists) - }) - - t.Run("returns error when plugin already installed", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"} - pluginPath := filepath.Join(pluginsDir, plugin.ID) - err := fs.MkdirAll(pluginPath, 0o755) - require.NoError(t, err) - - err = manager.Install(plugin) - assert.Error(t, err) - assert.Contains(t, err.Error(), "already installed") - }) - - t.Run("installs monorepo plugin with symlink", func(t *testing.T) { - t.Skip("Skipping symlink test as MemMapFs doesn't support symlinks") - }) -} - -func TestManagerUpdate(t *testing.T) { - t.Run("updates plugin successfully", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"} - pluginPath := filepath.Join(pluginsDir, plugin.ID) - err := fs.MkdirAll(pluginPath, 0o755) - require.NoError(t, err) - - pullCalled := false - mockGit := &mockGitClient{ - pullFunc: func(path string) error { - pullCalled = true - assert.Equal(t, pluginPath, path) - return nil - }, - } - manager.gitClient = mockGit - - err = manager.Update(plugin) - assert.NoError(t, err) - assert.True(t, pullCalled) - }) - - t.Run("returns error when plugin not installed", func(t *testing.T) { - manager, _, _ := setupTestManager(t) - - plugin := Plugin{ID: "non-existent", Name: "NonExistent"} - err := manager.Update(plugin) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not installed") - }) -} - -func TestUninstall(t *testing.T) { - t.Run("uninstalls plugin successfully", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"} - pluginPath := filepath.Join(pluginsDir, plugin.ID) - err := fs.MkdirAll(pluginPath, 0o755) - require.NoError(t, err) - - err = manager.Uninstall(plugin) - assert.NoError(t, err) - - exists, _ := afero.DirExists(fs, pluginPath) - assert.False(t, exists) - }) - - t.Run("returns error when plugin not installed", func(t *testing.T) { - manager, _, _ := setupTestManager(t) - - plugin := Plugin{ID: "non-existent", Name: "NonExistent"} - err := manager.Uninstall(plugin) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not installed") - }) -} - -func TestListInstalled(t *testing.T) { - t.Run("lists installed plugins", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - err := fs.MkdirAll(filepath.Join(pluginsDir, "Plugin1"), 0o755) - require.NoError(t, err) - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin1", "plugin.json"), []byte(`{"id":"Plugin1"}`), 0o644) - require.NoError(t, err) - - err = fs.MkdirAll(filepath.Join(pluginsDir, "Plugin2"), 0o755) - require.NoError(t, err) - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin2", "plugin.json"), []byte(`{"id":"Plugin2"}`), 0o644) - require.NoError(t, err) - - installed, err := manager.ListInstalled() - assert.NoError(t, err) - assert.Len(t, installed, 2) - assert.Contains(t, installed, "Plugin1") - assert.Contains(t, installed, "Plugin2") - }) - - t.Run("returns empty list when no plugins installed", func(t *testing.T) { - manager, _, _ := setupTestManager(t) - - installed, err := manager.ListInstalled() - assert.NoError(t, err) - assert.Empty(t, installed) - }) - - t.Run("ignores files and .repos directory", func(t *testing.T) { - manager, fs, pluginsDir := setupTestManager(t) - - err := fs.MkdirAll(pluginsDir, 0o755) - require.NoError(t, err) - err = fs.MkdirAll(filepath.Join(pluginsDir, "Plugin1"), 0o755) - require.NoError(t, err) - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin1", "plugin.json"), []byte(`{"id":"Plugin1"}`), 0o644) - require.NoError(t, err) - err = fs.MkdirAll(filepath.Join(pluginsDir, ".repos"), 0o755) - require.NoError(t, err) - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "README.md"), []byte("test"), 0o644) - require.NoError(t, err) - - installed, err := manager.ListInstalled() - assert.NoError(t, err) - assert.Len(t, installed, 1) - assert.Equal(t, "Plugin1", installed[0]) - }) -} - -func TestManagerGetPluginsDir(t *testing.T) { - manager, _, pluginsDir := setupTestManager(t) - assert.Equal(t, pluginsDir, manager.GetPluginsDir()) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry.go deleted file mode 100644 index 1728e72..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry.go +++ /dev/null @@ -1,258 +0,0 @@ -package plugins - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/go-git/go-git/v6" - "github.com/spf13/afero" -) - -const registryRepo = "https://github.com/AvengeMedia/dms-plugin-registry.git" - -type Plugin struct { - ID string `json:"id"` - Name string `json:"name"` - Capabilities []string `json:"capabilities"` - Category string `json:"category"` - Repo string `json:"repo"` - Path string `json:"path,omitempty"` - Author string `json:"author"` - Description string `json:"description"` - Dependencies []string `json:"dependencies,omitempty"` - Compositors []string `json:"compositors"` - Distro []string `json:"distro"` - Screenshot string `json:"screenshot,omitempty"` - RequiresDMS string `json:"requires_dms,omitempty"` - Featured bool `json:"featured,omitempty"` -} - -type GitClient interface { - PlainClone(path string, url string) error - Pull(path string) error - HasUpdates(path string) (bool, error) -} - -type realGitClient struct{} - -func (g *realGitClient) PlainClone(path string, url string) error { - _, err := git.PlainClone(path, &git.CloneOptions{ - URL: url, - Progress: os.Stdout, - }) - return err -} - -func (g *realGitClient) Pull(path string) error { - repo, err := git.PlainOpen(path) - if err != nil { - return err - } - - worktree, err := repo.Worktree() - if err != nil { - return err - } - - err = worktree.Pull(&git.PullOptions{}) - if err != nil && err.Error() != "already up-to-date" { - return err - } - - return nil -} - -func (g *realGitClient) HasUpdates(path string) (bool, error) { - repo, err := git.PlainOpen(path) - if err != nil { - return false, err - } - - // Fetch remote changes - err = repo.Fetch(&git.FetchOptions{}) - if err != nil && err.Error() != "already up-to-date" { - // If fetch fails, we can't determine if there are updates - // Return false and the error - return false, err - } - - // Get the HEAD reference - head, err := repo.Head() - if err != nil { - return false, err - } - - // Get the remote HEAD reference (typically origin/HEAD or origin/main or origin/master) - remote, err := repo.Remote("origin") - if err != nil { - return false, err - } - - refs, err := remote.List(&git.ListOptions{}) - if err != nil { - return false, err - } - - // Find the default branch remote ref - var remoteHead string - for _, ref := range refs { - if ref.Name().IsBranch() { - // Try common branch names - if ref.Name().Short() == "main" || ref.Name().Short() == "master" { - remoteHead = ref.Hash().String() - break - } - } - } - - // If we couldn't find a remote HEAD, assume no updates - if remoteHead == "" { - return false, nil - } - - // Compare local HEAD with remote HEAD - return head.Hash().String() != remoteHead, nil -} - -type Registry struct { - fs afero.Fs - cacheDir string - plugins []Plugin - git GitClient -} - -func NewRegistry() (*Registry, error) { - return NewRegistryWithFs(afero.NewOsFs()) -} - -func NewRegistryWithFs(fs afero.Fs) (*Registry, error) { - cacheDir := getCacheDir() - return &Registry{ - fs: fs, - cacheDir: cacheDir, - git: &realGitClient{}, - }, nil -} - -func getCacheDir() string { - return filepath.Join(os.TempDir(), "dankdots-plugin-registry") -} - -func (r *Registry) Update() error { - exists, err := afero.DirExists(r.fs, r.cacheDir) - if err != nil { - return fmt.Errorf("failed to check cache directory: %w", err) - } - - if !exists { - if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil { - return fmt.Errorf("failed to clone registry: %w", err) - } - } else { - // Try to pull, if it fails (e.g., shallow clone corruption), delete and re-clone - if err := r.git.Pull(r.cacheDir); err != nil { - // Repository is likely corrupted or has issues, delete and re-clone - if err := r.fs.RemoveAll(r.cacheDir); err != nil { - return fmt.Errorf("failed to remove corrupted registry: %w", err) - } - - if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil { - return fmt.Errorf("failed to re-clone registry: %w", err) - } - } - } - - return r.loadPlugins() -} - -func (r *Registry) loadPlugins() error { - pluginsDir := filepath.Join(r.cacheDir, "plugins") - - entries, err := afero.ReadDir(r.fs, pluginsDir) - if err != nil { - return fmt.Errorf("failed to read plugins directory: %w", err) - } - - r.plugins = []Plugin{} - - for _, entry := range entries { - if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" { - continue - } - - data, err := afero.ReadFile(r.fs, filepath.Join(pluginsDir, entry.Name())) - if err != nil { - continue - } - - var plugin Plugin - if err := json.Unmarshal(data, &plugin); err != nil { - continue - } - - if plugin.ID == "" { - plugin.ID = strings.TrimSuffix(entry.Name(), ".json") - } - - r.plugins = append(r.plugins, plugin) - } - - return nil -} - -func (r *Registry) List() ([]Plugin, error) { - if len(r.plugins) == 0 { - if err := r.Update(); err != nil { - return nil, err - } - } - - return SortByFirstParty(r.plugins), nil -} - -func (r *Registry) Search(query string) ([]Plugin, error) { - allPlugins, err := r.List() - if err != nil { - return nil, err - } - - if query == "" { - return allPlugins, nil - } - - return SortByFirstParty(FuzzySearch(query, allPlugins)), nil -} - -func (r *Registry) Get(idOrName string) (*Plugin, error) { - plugins, err := r.List() - if err != nil { - return nil, err - } - - // First, try to find by ID (preferred method) - for _, p := range plugins { - if p.ID == idOrName { - return &p, nil - } - } - - // Fallback to name for backward compatibility - for _, p := range plugins { - if p.Name == idOrName { - return &p, nil - } - } - - return nil, fmt.Errorf("plugin not found: %s", idOrName) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry_test.go deleted file mode 100644 index e535e6f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/registry_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package plugins - -import ( - "encoding/json" - "path/filepath" - "testing" - - "github.com/spf13/afero" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type mockGitClient struct { - cloneFunc func(path string, url string) error - pullFunc func(path string) error - hasUpdatesFunc func(path string) (bool, error) -} - -func (m *mockGitClient) PlainClone(path string, url string) error { - if m.cloneFunc != nil { - return m.cloneFunc(path, url) - } - return nil -} - -func (m *mockGitClient) Pull(path string) error { - if m.pullFunc != nil { - return m.pullFunc(path) - } - return nil -} - -func (m *mockGitClient) HasUpdates(path string) (bool, error) { - if m.hasUpdatesFunc != nil { - return m.hasUpdatesFunc(path) - } - return false, nil -} - -func TestNewRegistry(t *testing.T) { - registry, err := NewRegistry() - assert.NoError(t, err) - assert.NotNil(t, registry) - assert.NotEmpty(t, registry.cacheDir) -} - -func TestGetCacheDir(t *testing.T) { - cacheDir := getCacheDir() - assert.Contains(t, cacheDir, "/tmp/dankdots-plugin-registry") -} - -func setupTestRegistry(t *testing.T) (*Registry, afero.Fs, string) { - fs := afero.NewMemMapFs() - tmpDir := "/test-cache" - registry := &Registry{ - fs: fs, - cacheDir: tmpDir, - plugins: []Plugin{}, - git: &mockGitClient{}, - } - return registry, fs, tmpDir -} - -func createTestPlugin(t *testing.T, fs afero.Fs, dir string, filename string, plugin Plugin) { - pluginsDir := filepath.Join(dir, "plugins") - err := fs.MkdirAll(pluginsDir, 0o755) - require.NoError(t, err) - - data, err := json.Marshal(plugin) - require.NoError(t, err) - - err = afero.WriteFile(fs, filepath.Join(pluginsDir, filename), data, 0o644) - require.NoError(t, err) -} - -func TestLoadPlugins(t *testing.T) { - t.Run("loads valid plugin files", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - plugin1 := Plugin{ - Name: "TestPlugin1", - Capabilities: []string{"dankbar-widget"}, - Category: "monitoring", - Repo: "https://github.com/test/plugin1", - Author: "Test Author", - Description: "Test plugin 1", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - - plugin2 := Plugin{ - Name: "TestPlugin2", - Capabilities: []string{"system-tray"}, - Category: "utilities", - Repo: "https://github.com/test/plugin2", - Author: "Another Author", - Description: "Test plugin 2", - Dependencies: []string{"dep1", "dep2"}, - Compositors: []string{"hyprland", "niri"}, - Distro: []string{"arch"}, - Screenshot: "https://example.com/screenshot.png", - } - - createTestPlugin(t, fs, tmpDir, "plugin1.json", plugin1) - createTestPlugin(t, fs, tmpDir, "plugin2.json", plugin2) - - err := registry.loadPlugins() - assert.NoError(t, err) - assert.Len(t, registry.plugins, 2) - - assert.Equal(t, "TestPlugin1", registry.plugins[0].Name) - assert.Equal(t, "TestPlugin2", registry.plugins[1].Name) - assert.Equal(t, []string{"dankbar-widget"}, registry.plugins[0].Capabilities) - assert.Equal(t, []string{"dep1", "dep2"}, registry.plugins[1].Dependencies) - }) - - t.Run("skips non-json files", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - pluginsDir := filepath.Join(tmpDir, "plugins") - err := fs.MkdirAll(pluginsDir, 0o755) - require.NoError(t, err) - - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "README.md"), []byte("# Test"), 0o644) - require.NoError(t, err) - - plugin := Plugin{ - Name: "ValidPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - createTestPlugin(t, fs, tmpDir, "valid.json", plugin) - - err = registry.loadPlugins() - assert.NoError(t, err) - assert.Len(t, registry.plugins, 1) - assert.Equal(t, "ValidPlugin", registry.plugins[0].Name) - }) - - t.Run("skips directories", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - pluginsDir := filepath.Join(tmpDir, "plugins") - err := fs.MkdirAll(filepath.Join(pluginsDir, "subdir"), 0o755) - require.NoError(t, err) - - plugin := Plugin{ - Name: "ValidPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - createTestPlugin(t, fs, tmpDir, "valid.json", plugin) - - err = registry.loadPlugins() - assert.NoError(t, err) - assert.Len(t, registry.plugins, 1) - }) - - t.Run("skips invalid json files", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - pluginsDir := filepath.Join(tmpDir, "plugins") - err := fs.MkdirAll(pluginsDir, 0o755) - require.NoError(t, err) - - err = afero.WriteFile(fs, filepath.Join(pluginsDir, "invalid.json"), []byte("{invalid json}"), 0o644) - require.NoError(t, err) - - plugin := Plugin{ - Name: "ValidPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - createTestPlugin(t, fs, tmpDir, "valid.json", plugin) - - err = registry.loadPlugins() - assert.NoError(t, err) - assert.Len(t, registry.plugins, 1) - assert.Equal(t, "ValidPlugin", registry.plugins[0].Name) - }) - - t.Run("returns error when plugins directory missing", func(t *testing.T) { - registry, _, _ := setupTestRegistry(t) - - err := registry.loadPlugins() - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to read plugins directory") - }) -} - -func TestList(t *testing.T) { - t.Run("returns cached plugins if available", func(t *testing.T) { - registry, _, _ := setupTestRegistry(t) - - plugin := Plugin{ - Name: "CachedPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - - registry.plugins = []Plugin{plugin} - - plugins, err := registry.List() - assert.NoError(t, err) - assert.Len(t, plugins, 1) - assert.Equal(t, "CachedPlugin", plugins[0].Name) - }) - - t.Run("updates and loads plugins when cache is empty", func(t *testing.T) { - registry, fs, _ := setupTestRegistry(t) - - plugin := Plugin{ - Name: "NewPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - - mockGit := &mockGitClient{ - cloneFunc: func(path string, url string) error { - createTestPlugin(t, fs, path, "plugin.json", plugin) - return nil - }, - } - registry.git = mockGit - - plugins, err := registry.List() - assert.NoError(t, err) - assert.Len(t, plugins, 1) - assert.Equal(t, "NewPlugin", plugins[0].Name) - }) -} - -func TestUpdate(t *testing.T) { - t.Run("clones repository when cache doesn't exist", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - plugin := Plugin{ - Name: "RepoPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - - cloneCalled := false - mockGit := &mockGitClient{ - cloneFunc: func(path string, url string) error { - cloneCalled = true - assert.Equal(t, registryRepo, url) - assert.Equal(t, tmpDir, path) - createTestPlugin(t, fs, path, "plugin.json", plugin) - return nil - }, - } - registry.git = mockGit - - err := registry.Update() - assert.NoError(t, err) - assert.True(t, cloneCalled) - assert.Len(t, registry.plugins, 1) - assert.Equal(t, "RepoPlugin", registry.plugins[0].Name) - }) - - t.Run("pulls updates when cache exists", func(t *testing.T) { - registry, fs, tmpDir := setupTestRegistry(t) - - plugin := Plugin{ - Name: "UpdatedPlugin", - Capabilities: []string{"test"}, - Category: "test", - Repo: "https://github.com/test/test", - Author: "Test", - Description: "Test", - Compositors: []string{"niri"}, - Distro: []string{"any"}, - } - - err := fs.MkdirAll(tmpDir, 0o755) - require.NoError(t, err) - - pullCalled := false - mockGit := &mockGitClient{ - pullFunc: func(path string) error { - pullCalled = true - assert.Equal(t, tmpDir, path) - createTestPlugin(t, fs, path, "plugin.json", plugin) - return nil - }, - } - registry.git = mockGit - - err = registry.Update() - assert.NoError(t, err) - assert.True(t, pullCalled) - assert.Len(t, registry.plugins, 1) - assert.Equal(t, "UpdatedPlugin", registry.plugins[0].Name) - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/search.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/search.go deleted file mode 100644 index 833158f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/plugins/search.go +++ /dev/null @@ -1,91 +0,0 @@ -package plugins - -import ( - "sort" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func FuzzySearch(query string, plugins []Plugin) []Plugin { - if query == "" { - return plugins - } - - queryLower := strings.ToLower(query) - return utils.Filter(plugins, func(p Plugin) bool { - return fuzzyMatch(queryLower, strings.ToLower(p.Name)) || - fuzzyMatch(queryLower, strings.ToLower(p.Category)) || - fuzzyMatch(queryLower, strings.ToLower(p.Description)) || - fuzzyMatch(queryLower, strings.ToLower(p.Author)) - }) -} - -func fuzzyMatch(query, text string) bool { - queryIdx := 0 - for _, char := range text { - if queryIdx < len(query) && char == rune(query[queryIdx]) { - queryIdx++ - } - } - return queryIdx == len(query) -} - -func FilterByCategory(category string, plugins []Plugin) []Plugin { - if category == "" { - return plugins - } - categoryLower := strings.ToLower(category) - return utils.Filter(plugins, func(p Plugin) bool { - return strings.ToLower(p.Category) == categoryLower - }) -} - -func FilterByCompositor(compositor string, plugins []Plugin) []Plugin { - if compositor == "" { - return plugins - } - compositorLower := strings.ToLower(compositor) - return utils.Filter(plugins, func(p Plugin) bool { - return utils.Any(p.Compositors, func(c string) bool { - return strings.ToLower(c) == compositorLower - }) - }) -} - -func FilterByCapability(capability string, plugins []Plugin) []Plugin { - if capability == "" { - return plugins - } - capabilityLower := strings.ToLower(capability) - return utils.Filter(plugins, func(p Plugin) bool { - return utils.Any(p.Capabilities, func(c string) bool { - return strings.ToLower(c) == capabilityLower - }) - }) -} - -func SortByFirstParty(plugins []Plugin) []Plugin { - sort.SliceStable(plugins, func(i, j int) bool { - if plugins[i].Featured != plugins[j].Featured { - return plugins[i].Featured - } - isFirstPartyI := strings.HasPrefix(plugins[i].Repo, "https://github.com/AvengeMedia") - isFirstPartyJ := strings.HasPrefix(plugins[j].Repo, "https://github.com/AvengeMedia") - if isFirstPartyI != isFirstPartyJ { - return isFirstPartyI - } - return false - }) - return plugins -} - -func FindByIDOrName(idOrName string, plugins []Plugin) *Plugin { - if p, found := utils.Find(plugins, func(p Plugin) bool { return p.ID == idOrName }); found { - return &p - } - if p, found := utils.Find(plugins, func(p Plugin) bool { return p.Name == idOrName }); found { - return &p - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/dwl_ipc/dwl_ipc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/dwl_ipc/dwl_ipc.go deleted file mode 100644 index fc0e50b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/dwl_ipc/dwl_ipc.go +++ /dev/null @@ -1,791 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/dwl-ipc-unstable-v2.xml -// -// dwl_ipc_unstable_v2 Protocol Copyright: - -package dwl_ipc - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -// ZdwlIpcManagerV2InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZdwlIpcManagerV2InterfaceName = "zdwl_ipc_manager_v2" - -// ZdwlIpcManagerV2 : manage dwl state -// -// This interface is exposed as a global in wl_registry. -// -// Clients can use this interface to get a dwl_ipc_output. -// After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. -// The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. -type ZdwlIpcManagerV2 struct { - client.BaseProxy - tagsHandler ZdwlIpcManagerV2TagsHandlerFunc - layoutHandler ZdwlIpcManagerV2LayoutHandlerFunc -} - -// NewZdwlIpcManagerV2 : manage dwl state -// -// This interface is exposed as a global in wl_registry. -// -// Clients can use this interface to get a dwl_ipc_output. -// After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. -// The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. -func NewZdwlIpcManagerV2(ctx *client.Context) *ZdwlIpcManagerV2 { - zdwlIpcManagerV2 := &ZdwlIpcManagerV2{} - ctx.Register(zdwlIpcManagerV2) - return zdwlIpcManagerV2 -} - -// Release : release dwl_ipc_manager -// -// Indicates that the client will not the dwl_ipc_manager object anymore. -// Objects created through this instance are not affected. -func (i *ZdwlIpcManagerV2) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// GetOutput : get a dwl_ipc_outout for a wl_output -// -// Get a dwl_ipc_outout for the specified wl_output. -func (i *ZdwlIpcManagerV2) GetOutput(output *client.Output) (*ZdwlIpcOutputV2, error) { - id := NewZdwlIpcOutputV2(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// ZdwlIpcManagerV2TagsEvent : Announces tag amount -// -// This event is sent after binding. -// A roundtrip after binding guarantees the client recieved all tags. -type ZdwlIpcManagerV2TagsEvent struct { - Amount uint32 -} -type ZdwlIpcManagerV2TagsHandlerFunc func(ZdwlIpcManagerV2TagsEvent) - -// SetTagsHandler : sets handler for ZdwlIpcManagerV2TagsEvent -func (i *ZdwlIpcManagerV2) SetTagsHandler(f ZdwlIpcManagerV2TagsHandlerFunc) { - i.tagsHandler = f -} - -// ZdwlIpcManagerV2LayoutEvent : Announces a layout -// -// This event is sent after binding. -// A roundtrip after binding guarantees the client recieved all layouts. -type ZdwlIpcManagerV2LayoutEvent struct { - Name string -} -type ZdwlIpcManagerV2LayoutHandlerFunc func(ZdwlIpcManagerV2LayoutEvent) - -// SetLayoutHandler : sets handler for ZdwlIpcManagerV2LayoutEvent -func (i *ZdwlIpcManagerV2) SetLayoutHandler(f ZdwlIpcManagerV2LayoutHandlerFunc) { - i.layoutHandler = f -} - -func (i *ZdwlIpcManagerV2) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.tagsHandler == nil { - return - } - var e ZdwlIpcManagerV2TagsEvent - l := 0 - e.Amount = client.Uint32(data[l : l+4]) - l += 4 - - i.tagsHandler(e) - case 1: - if i.layoutHandler == nil { - return - } - var e ZdwlIpcManagerV2LayoutEvent - l := 0 - nameLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Name = client.String(data[l : l+nameLen]) - l += nameLen - - i.layoutHandler(e) - } -} - -// ZdwlIpcOutputV2InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZdwlIpcOutputV2InterfaceName = "zdwl_ipc_output_v2" - -// ZdwlIpcOutputV2 : control dwl output -// -// Observe and control a dwl output. -// -// Events are double-buffered: -// Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. -// -// Request are not double-buffered: -// The compositor will update immediately upon request. -type ZdwlIpcOutputV2 struct { - client.BaseProxy - toggleVisibilityHandler ZdwlIpcOutputV2ToggleVisibilityHandlerFunc - activeHandler ZdwlIpcOutputV2ActiveHandlerFunc - tagHandler ZdwlIpcOutputV2TagHandlerFunc - layoutHandler ZdwlIpcOutputV2LayoutHandlerFunc - titleHandler ZdwlIpcOutputV2TitleHandlerFunc - appidHandler ZdwlIpcOutputV2AppidHandlerFunc - layoutSymbolHandler ZdwlIpcOutputV2LayoutSymbolHandlerFunc - frameHandler ZdwlIpcOutputV2FrameHandlerFunc - fullscreenHandler ZdwlIpcOutputV2FullscreenHandlerFunc - floatingHandler ZdwlIpcOutputV2FloatingHandlerFunc - xHandler ZdwlIpcOutputV2XHandlerFunc - yHandler ZdwlIpcOutputV2YHandlerFunc - widthHandler ZdwlIpcOutputV2WidthHandlerFunc - heightHandler ZdwlIpcOutputV2HeightHandlerFunc - lastLayerHandler ZdwlIpcOutputV2LastLayerHandlerFunc - kbLayoutHandler ZdwlIpcOutputV2KbLayoutHandlerFunc - keymodeHandler ZdwlIpcOutputV2KeymodeHandlerFunc - scalefactorHandler ZdwlIpcOutputV2ScalefactorHandlerFunc -} - -// NewZdwlIpcOutputV2 : control dwl output -// -// Observe and control a dwl output. -// -// Events are double-buffered: -// Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. -// -// Request are not double-buffered: -// The compositor will update immediately upon request. -func NewZdwlIpcOutputV2(ctx *client.Context) *ZdwlIpcOutputV2 { - zdwlIpcOutputV2 := &ZdwlIpcOutputV2{} - ctx.Register(zdwlIpcOutputV2) - return zdwlIpcOutputV2 -} - -// Release : release dwl_ipc_outout -// -// Indicates to that the client no longer needs this dwl_ipc_output. -func (i *ZdwlIpcOutputV2) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetTags : Set the active tags of this output -// -// tagmask: bitmask of the tags that should be set. -// toggleTagset: toggle the selected tagset, zero for invalid, nonzero for valid. -func (i *ZdwlIpcOutputV2) SetTags(tagmask, toggleTagset uint32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(tagmask)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(toggleTagset)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetClientTags : Set the tags of the focused client. -// -// The tags are updated as follows: -// new_tags = (current_tags AND and_tags) XOR xor_tags -func (i *ZdwlIpcOutputV2) SetClientTags(andTags, xorTags uint32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(andTags)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(xorTags)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetLayout : Set the layout of this output -// -// index: index of a layout recieved by dwl_ipc_manager.layout -func (i *ZdwlIpcOutputV2) SetLayout(index uint32) error { - const opcode = 3 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(index)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Quit : Quit mango -// This request allows clients to instruct the compositor to quit mango. -func (i *ZdwlIpcOutputV2) Quit() error { - const opcode = 4 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SendDispatch : Set the active tags of this output -// -// dispatch: dispatch name. -// arg1: arg1. -// arg2: arg2. -// arg3: arg3. -// arg4: arg4. -// arg5: arg5. -func (i *ZdwlIpcOutputV2) SendDispatch(dispatch, arg1, arg2, arg3, arg4, arg5 string) error { - const opcode = 5 - dispatchLen := client.PaddedLen(len(dispatch) + 1) - arg1Len := client.PaddedLen(len(arg1) + 1) - arg2Len := client.PaddedLen(len(arg2) + 1) - arg3Len := client.PaddedLen(len(arg3) + 1) - arg4Len := client.PaddedLen(len(arg4) + 1) - arg5Len := client.PaddedLen(len(arg5) + 1) - _reqBufLen := 8 + (4 + dispatchLen) + (4 + arg1Len) + (4 + arg2Len) + (4 + arg3Len) + (4 + arg4Len) + (4 + arg5Len) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutString(_reqBuf[l:l+(4+dispatchLen)], dispatch) - l += (4 + dispatchLen) - client.PutString(_reqBuf[l:l+(4+arg1Len)], arg1) - l += (4 + arg1Len) - client.PutString(_reqBuf[l:l+(4+arg2Len)], arg2) - l += (4 + arg2Len) - client.PutString(_reqBuf[l:l+(4+arg3Len)], arg3) - l += (4 + arg3Len) - client.PutString(_reqBuf[l:l+(4+arg4Len)], arg4) - l += (4 + arg4Len) - client.PutString(_reqBuf[l:l+(4+arg5Len)], arg5) - l += (4 + arg5Len) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -type ZdwlIpcOutputV2TagState uint32 - -// ZdwlIpcOutputV2TagState : -const ( - // ZdwlIpcOutputV2TagStateNone : no state - ZdwlIpcOutputV2TagStateNone ZdwlIpcOutputV2TagState = 0 - // ZdwlIpcOutputV2TagStateActive : tag is active - ZdwlIpcOutputV2TagStateActive ZdwlIpcOutputV2TagState = 1 - // ZdwlIpcOutputV2TagStateUrgent : tag has at least one urgent client - ZdwlIpcOutputV2TagStateUrgent ZdwlIpcOutputV2TagState = 2 -) - -func (e ZdwlIpcOutputV2TagState) Name() string { - switch e { - case ZdwlIpcOutputV2TagStateNone: - return "none" - case ZdwlIpcOutputV2TagStateActive: - return "active" - case ZdwlIpcOutputV2TagStateUrgent: - return "urgent" - default: - return "" - } -} - -func (e ZdwlIpcOutputV2TagState) Value() string { - switch e { - case ZdwlIpcOutputV2TagStateNone: - return "0" - case ZdwlIpcOutputV2TagStateActive: - return "1" - case ZdwlIpcOutputV2TagStateUrgent: - return "2" - default: - return "" - } -} - -func (e ZdwlIpcOutputV2TagState) String() string { - return e.Name() + "=" + e.Value() -} - -// ZdwlIpcOutputV2ToggleVisibilityEvent : Toggle client visibilty -// -// Indicates the client should hide or show themselves. -// If the client is visible then hide, if hidden then show. -type ZdwlIpcOutputV2ToggleVisibilityEvent struct{} -type ZdwlIpcOutputV2ToggleVisibilityHandlerFunc func(ZdwlIpcOutputV2ToggleVisibilityEvent) - -// SetToggleVisibilityHandler : sets handler for ZdwlIpcOutputV2ToggleVisibilityEvent -func (i *ZdwlIpcOutputV2) SetToggleVisibilityHandler(f ZdwlIpcOutputV2ToggleVisibilityHandlerFunc) { - i.toggleVisibilityHandler = f -} - -// ZdwlIpcOutputV2ActiveEvent : Update the selected output. -// -// Indicates if the output is active. Zero is invalid, nonzero is valid. -type ZdwlIpcOutputV2ActiveEvent struct { - Active uint32 -} -type ZdwlIpcOutputV2ActiveHandlerFunc func(ZdwlIpcOutputV2ActiveEvent) - -// SetActiveHandler : sets handler for ZdwlIpcOutputV2ActiveEvent -func (i *ZdwlIpcOutputV2) SetActiveHandler(f ZdwlIpcOutputV2ActiveHandlerFunc) { - i.activeHandler = f -} - -// ZdwlIpcOutputV2TagEvent : Update the state of a tag. -// -// Indicates that a tag has been updated. -type ZdwlIpcOutputV2TagEvent struct { - Tag uint32 - State uint32 - Clients uint32 - Focused uint32 -} -type ZdwlIpcOutputV2TagHandlerFunc func(ZdwlIpcOutputV2TagEvent) - -// SetTagHandler : sets handler for ZdwlIpcOutputV2TagEvent -func (i *ZdwlIpcOutputV2) SetTagHandler(f ZdwlIpcOutputV2TagHandlerFunc) { - i.tagHandler = f -} - -// ZdwlIpcOutputV2LayoutEvent : Update the layout. -// -// Indicates a new layout is selected. -type ZdwlIpcOutputV2LayoutEvent struct { - Layout uint32 -} -type ZdwlIpcOutputV2LayoutHandlerFunc func(ZdwlIpcOutputV2LayoutEvent) - -// SetLayoutHandler : sets handler for ZdwlIpcOutputV2LayoutEvent -func (i *ZdwlIpcOutputV2) SetLayoutHandler(f ZdwlIpcOutputV2LayoutHandlerFunc) { - i.layoutHandler = f -} - -// ZdwlIpcOutputV2TitleEvent : Update the title. -// -// Indicates the title has changed. -type ZdwlIpcOutputV2TitleEvent struct { - Title string -} -type ZdwlIpcOutputV2TitleHandlerFunc func(ZdwlIpcOutputV2TitleEvent) - -// SetTitleHandler : sets handler for ZdwlIpcOutputV2TitleEvent -func (i *ZdwlIpcOutputV2) SetTitleHandler(f ZdwlIpcOutputV2TitleHandlerFunc) { - i.titleHandler = f -} - -// ZdwlIpcOutputV2AppidEvent : Update the appid. -// -// Indicates the appid has changed. -type ZdwlIpcOutputV2AppidEvent struct { - Appid string -} -type ZdwlIpcOutputV2AppidHandlerFunc func(ZdwlIpcOutputV2AppidEvent) - -// SetAppidHandler : sets handler for ZdwlIpcOutputV2AppidEvent -func (i *ZdwlIpcOutputV2) SetAppidHandler(f ZdwlIpcOutputV2AppidHandlerFunc) { - i.appidHandler = f -} - -// ZdwlIpcOutputV2LayoutSymbolEvent : Update the current layout symbol -// -// Indicates the layout has changed. Since layout symbols are dynamic. -// As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. -// You can ignore the zdwl_ipc_output.layout event. -type ZdwlIpcOutputV2LayoutSymbolEvent struct { - Layout string -} -type ZdwlIpcOutputV2LayoutSymbolHandlerFunc func(ZdwlIpcOutputV2LayoutSymbolEvent) - -// SetLayoutSymbolHandler : sets handler for ZdwlIpcOutputV2LayoutSymbolEvent -func (i *ZdwlIpcOutputV2) SetLayoutSymbolHandler(f ZdwlIpcOutputV2LayoutSymbolHandlerFunc) { - i.layoutSymbolHandler = f -} - -// ZdwlIpcOutputV2FrameEvent : The update sequence is done. -// -// Indicates that a sequence of status updates have finished and the client should redraw. -type ZdwlIpcOutputV2FrameEvent struct{} -type ZdwlIpcOutputV2FrameHandlerFunc func(ZdwlIpcOutputV2FrameEvent) - -// SetFrameHandler : sets handler for ZdwlIpcOutputV2FrameEvent -func (i *ZdwlIpcOutputV2) SetFrameHandler(f ZdwlIpcOutputV2FrameHandlerFunc) { - i.frameHandler = f -} - -// ZdwlIpcOutputV2FullscreenEvent : Update fullscreen status -// -// Indicates if the selected client on this output is fullscreen. -type ZdwlIpcOutputV2FullscreenEvent struct { - IsFullscreen uint32 -} -type ZdwlIpcOutputV2FullscreenHandlerFunc func(ZdwlIpcOutputV2FullscreenEvent) - -// SetFullscreenHandler : sets handler for ZdwlIpcOutputV2FullscreenEvent -func (i *ZdwlIpcOutputV2) SetFullscreenHandler(f ZdwlIpcOutputV2FullscreenHandlerFunc) { - i.fullscreenHandler = f -} - -// ZdwlIpcOutputV2FloatingEvent : Update the floating status -// -// Indicates if the selected client on this output is floating. -type ZdwlIpcOutputV2FloatingEvent struct { - IsFloating uint32 -} -type ZdwlIpcOutputV2FloatingHandlerFunc func(ZdwlIpcOutputV2FloatingEvent) - -// SetFloatingHandler : sets handler for ZdwlIpcOutputV2FloatingEvent -func (i *ZdwlIpcOutputV2) SetFloatingHandler(f ZdwlIpcOutputV2FloatingHandlerFunc) { - i.floatingHandler = f -} - -// ZdwlIpcOutputV2XEvent : Update the x coordinates -// -// Indicates if x coordinates of the selected client. -type ZdwlIpcOutputV2XEvent struct { - X int32 -} -type ZdwlIpcOutputV2XHandlerFunc func(ZdwlIpcOutputV2XEvent) - -// SetXHandler : sets handler for ZdwlIpcOutputV2XEvent -func (i *ZdwlIpcOutputV2) SetXHandler(f ZdwlIpcOutputV2XHandlerFunc) { - i.xHandler = f -} - -// ZdwlIpcOutputV2YEvent : Update the y coordinates -// -// Indicates if y coordinates of the selected client. -type ZdwlIpcOutputV2YEvent struct { - Y int32 -} -type ZdwlIpcOutputV2YHandlerFunc func(ZdwlIpcOutputV2YEvent) - -// SetYHandler : sets handler for ZdwlIpcOutputV2YEvent -func (i *ZdwlIpcOutputV2) SetYHandler(f ZdwlIpcOutputV2YHandlerFunc) { - i.yHandler = f -} - -// ZdwlIpcOutputV2WidthEvent : Update the width -// -// Indicates if width of the selected client. -type ZdwlIpcOutputV2WidthEvent struct { - Width int32 -} -type ZdwlIpcOutputV2WidthHandlerFunc func(ZdwlIpcOutputV2WidthEvent) - -// SetWidthHandler : sets handler for ZdwlIpcOutputV2WidthEvent -func (i *ZdwlIpcOutputV2) SetWidthHandler(f ZdwlIpcOutputV2WidthHandlerFunc) { - i.widthHandler = f -} - -// ZdwlIpcOutputV2HeightEvent : Update the height -// -// Indicates if height of the selected client. -type ZdwlIpcOutputV2HeightEvent struct { - Height int32 -} -type ZdwlIpcOutputV2HeightHandlerFunc func(ZdwlIpcOutputV2HeightEvent) - -// SetHeightHandler : sets handler for ZdwlIpcOutputV2HeightEvent -func (i *ZdwlIpcOutputV2) SetHeightHandler(f ZdwlIpcOutputV2HeightHandlerFunc) { - i.heightHandler = f -} - -// ZdwlIpcOutputV2LastLayerEvent : last map layer. -// -// last map layer. -type ZdwlIpcOutputV2LastLayerEvent struct { - LastLayer string -} -type ZdwlIpcOutputV2LastLayerHandlerFunc func(ZdwlIpcOutputV2LastLayerEvent) - -// SetLastLayerHandler : sets handler for ZdwlIpcOutputV2LastLayerEvent -func (i *ZdwlIpcOutputV2) SetLastLayerHandler(f ZdwlIpcOutputV2LastLayerHandlerFunc) { - i.lastLayerHandler = f -} - -// ZdwlIpcOutputV2KbLayoutEvent : current keyboard layout. -// -// current keyboard layout. -type ZdwlIpcOutputV2KbLayoutEvent struct { - KbLayout string -} -type ZdwlIpcOutputV2KbLayoutHandlerFunc func(ZdwlIpcOutputV2KbLayoutEvent) - -// SetKbLayoutHandler : sets handler for ZdwlIpcOutputV2KbLayoutEvent -func (i *ZdwlIpcOutputV2) SetKbLayoutHandler(f ZdwlIpcOutputV2KbLayoutHandlerFunc) { - i.kbLayoutHandler = f -} - -// ZdwlIpcOutputV2KeymodeEvent : current keybind mode. -// -// current keybind mode. -type ZdwlIpcOutputV2KeymodeEvent struct { - Keymode string -} -type ZdwlIpcOutputV2KeymodeHandlerFunc func(ZdwlIpcOutputV2KeymodeEvent) - -// SetKeymodeHandler : sets handler for ZdwlIpcOutputV2KeymodeEvent -func (i *ZdwlIpcOutputV2) SetKeymodeHandler(f ZdwlIpcOutputV2KeymodeHandlerFunc) { - i.keymodeHandler = f -} - -// ZdwlIpcOutputV2ScalefactorEvent : scale factor of monitor. -// -// scale factor of monitor. -type ZdwlIpcOutputV2ScalefactorEvent struct { - Scalefactor uint32 -} -type ZdwlIpcOutputV2ScalefactorHandlerFunc func(ZdwlIpcOutputV2ScalefactorEvent) - -// SetScalefactorHandler : sets handler for ZdwlIpcOutputV2ScalefactorEvent -func (i *ZdwlIpcOutputV2) SetScalefactorHandler(f ZdwlIpcOutputV2ScalefactorHandlerFunc) { - i.scalefactorHandler = f -} - -func (i *ZdwlIpcOutputV2) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.toggleVisibilityHandler == nil { - return - } - var e ZdwlIpcOutputV2ToggleVisibilityEvent - - i.toggleVisibilityHandler(e) - case 1: - if i.activeHandler == nil { - return - } - var e ZdwlIpcOutputV2ActiveEvent - l := 0 - e.Active = client.Uint32(data[l : l+4]) - l += 4 - - i.activeHandler(e) - case 2: - if i.tagHandler == nil { - return - } - var e ZdwlIpcOutputV2TagEvent - l := 0 - e.Tag = client.Uint32(data[l : l+4]) - l += 4 - e.State = client.Uint32(data[l : l+4]) - l += 4 - e.Clients = client.Uint32(data[l : l+4]) - l += 4 - e.Focused = client.Uint32(data[l : l+4]) - l += 4 - - i.tagHandler(e) - case 3: - if i.layoutHandler == nil { - return - } - var e ZdwlIpcOutputV2LayoutEvent - l := 0 - e.Layout = client.Uint32(data[l : l+4]) - l += 4 - - i.layoutHandler(e) - case 4: - if i.titleHandler == nil { - return - } - var e ZdwlIpcOutputV2TitleEvent - l := 0 - titleLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Title = client.String(data[l : l+titleLen]) - l += titleLen - - i.titleHandler(e) - case 5: - if i.appidHandler == nil { - return - } - var e ZdwlIpcOutputV2AppidEvent - l := 0 - appidLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Appid = client.String(data[l : l+appidLen]) - l += appidLen - - i.appidHandler(e) - case 6: - if i.layoutSymbolHandler == nil { - return - } - var e ZdwlIpcOutputV2LayoutSymbolEvent - l := 0 - layoutLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Layout = client.String(data[l : l+layoutLen]) - l += layoutLen - - i.layoutSymbolHandler(e) - case 7: - if i.frameHandler == nil { - return - } - var e ZdwlIpcOutputV2FrameEvent - - i.frameHandler(e) - case 8: - if i.fullscreenHandler == nil { - return - } - var e ZdwlIpcOutputV2FullscreenEvent - l := 0 - e.IsFullscreen = client.Uint32(data[l : l+4]) - l += 4 - - i.fullscreenHandler(e) - case 9: - if i.floatingHandler == nil { - return - } - var e ZdwlIpcOutputV2FloatingEvent - l := 0 - e.IsFloating = client.Uint32(data[l : l+4]) - l += 4 - - i.floatingHandler(e) - case 10: - if i.xHandler == nil { - return - } - var e ZdwlIpcOutputV2XEvent - l := 0 - e.X = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.xHandler(e) - case 11: - if i.yHandler == nil { - return - } - var e ZdwlIpcOutputV2YEvent - l := 0 - e.Y = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.yHandler(e) - case 12: - if i.widthHandler == nil { - return - } - var e ZdwlIpcOutputV2WidthEvent - l := 0 - e.Width = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.widthHandler(e) - case 13: - if i.heightHandler == nil { - return - } - var e ZdwlIpcOutputV2HeightEvent - l := 0 - e.Height = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.heightHandler(e) - case 14: - if i.lastLayerHandler == nil { - return - } - var e ZdwlIpcOutputV2LastLayerEvent - l := 0 - lastLayerLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.LastLayer = client.String(data[l : l+lastLayerLen]) - l += lastLayerLen - - i.lastLayerHandler(e) - case 15: - if i.kbLayoutHandler == nil { - return - } - var e ZdwlIpcOutputV2KbLayoutEvent - l := 0 - kbLayoutLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.KbLayout = client.String(data[l : l+kbLayoutLen]) - l += kbLayoutLen - - i.kbLayoutHandler(e) - case 16: - if i.keymodeHandler == nil { - return - } - var e ZdwlIpcOutputV2KeymodeEvent - l := 0 - keymodeLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Keymode = client.String(data[l : l+keymodeLen]) - l += keymodeLen - - i.keymodeHandler(e) - case 17: - if i.scalefactorHandler == nil { - return - } - var e ZdwlIpcOutputV2ScalefactorEvent - l := 0 - e.Scalefactor = client.Uint32(data[l : l+4]) - l += 4 - - i.scalefactorHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_data_control/data_control.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_data_control/data_control.go deleted file mode 100644 index 3a4de9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_data_control/data_control.go +++ /dev/null @@ -1,695 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/ext-data-control-v1.xml -// -// ext_data_control_v1 Protocol Copyright: -// -// Copyright © 2018 Simon Ser -// Copyright © 2019 Ivan Molodetskikh -// Copyright © 2024 Neal Gompa -// -// Permission to use, copy, modify, distribute, and sell this -// software and its documentation for any purpose is hereby granted -// without fee, provided that the above copyright notice appear in -// all copies and that both that copyright notice and this permission -// notice appear in supporting documentation, and that the name of -// the copyright holders not be used in advertising or publicity -// pertaining to distribution of the software without specific, -// written prior permission. The copyright holders make no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied -// warranty. -// -// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - -package ext_data_control - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "golang.org/x/sys/unix" -) - -// ExtDataControlManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtDataControlManagerV1InterfaceName = "ext_data_control_manager_v1" - -// ExtDataControlManagerV1 : manager to control data devices -// -// This interface is a manager that allows creating per-seat data device -// controls. -type ExtDataControlManagerV1 struct { - client.BaseProxy -} - -// NewExtDataControlManagerV1 : manager to control data devices -// -// This interface is a manager that allows creating per-seat data device -// controls. -func NewExtDataControlManagerV1(ctx *client.Context) *ExtDataControlManagerV1 { - extDataControlManagerV1 := &ExtDataControlManagerV1{} - ctx.Register(extDataControlManagerV1) - return extDataControlManagerV1 -} - -// CreateDataSource : create a new data source -// -// Create a new data source. -func (i *ExtDataControlManagerV1) CreateDataSource() (*ExtDataControlSourceV1, error) { - id := NewExtDataControlSourceV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// GetDataDevice : get a data device for a seat -// -// Create a data device that can be used to manage a seat's selection. -func (i *ExtDataControlManagerV1) GetDataDevice(seat *client.Seat) (*ExtDataControlDeviceV1, error) { - id := NewExtDataControlDeviceV1(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// GetDataDeviceWithProxy : get a data device for a seat using a pre-created proxy -// -// Like GetDataDevice, but uses a pre-created ExtDataControlDeviceV1 proxy. -// This allows setting up event handlers before the request is sent. -func (i *ExtDataControlManagerV1) GetDataDeviceWithProxy(device *ExtDataControlDeviceV1, seat *client.Seat) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], device.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - return i.Context().WriteMsg(_reqBuf[:], nil) -} - -// Destroy : destroy the manager -// -// All objects created by the manager will still remain valid, until their -// appropriate destroy request has been called. -func (i *ExtDataControlManagerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ExtDataControlDeviceV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtDataControlDeviceV1InterfaceName = "ext_data_control_device_v1" - -// ExtDataControlDeviceV1 : manage a data device for a seat -// -// This interface allows a client to manage a seat's selection. -// -// When the seat is destroyed, this object becomes inert. -type ExtDataControlDeviceV1 struct { - client.BaseProxy - dataOfferHandler ExtDataControlDeviceV1DataOfferHandlerFunc - selectionHandler ExtDataControlDeviceV1SelectionHandlerFunc - finishedHandler ExtDataControlDeviceV1FinishedHandlerFunc - primarySelectionHandler ExtDataControlDeviceV1PrimarySelectionHandlerFunc -} - -// NewExtDataControlDeviceV1 : manage a data device for a seat -// -// This interface allows a client to manage a seat's selection. -// -// When the seat is destroyed, this object becomes inert. -func NewExtDataControlDeviceV1(ctx *client.Context) *ExtDataControlDeviceV1 { - extDataControlDeviceV1 := &ExtDataControlDeviceV1{} - ctx.Register(extDataControlDeviceV1) - return extDataControlDeviceV1 -} - -// SetSelection : copy data to the selection -// -// This request asks the compositor to set the selection to the data from -// the source on behalf of the client. -// -// The given source may not be used in any further set_selection or -// set_primary_selection requests. Attempting to use a previously used -// source triggers the used_source protocol error. -// -// To unset the selection, set the source to NULL. -func (i *ExtDataControlDeviceV1) SetSelection(source *ExtDataControlSourceV1) error { - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if source == nil { - client.PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - client.PutUint32(_reqBuf[l:l+4], source.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Destroy : destroy this data device -// -// Destroys the data device object. -func (i *ExtDataControlDeviceV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetPrimarySelection : copy data to the primary selection -// -// This request asks the compositor to set the primary selection to the -// data from the source on behalf of the client. -// -// The given source may not be used in any further set_selection or -// set_primary_selection requests. Attempting to use a previously used -// source triggers the used_source protocol error. -// -// To unset the primary selection, set the source to NULL. -// -// The compositor will ignore this request if it does not support primary -// selection. -func (i *ExtDataControlDeviceV1) SetPrimarySelection(source *ExtDataControlSourceV1) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if source == nil { - client.PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - client.PutUint32(_reqBuf[l:l+4], source.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ExtDataControlDeviceV1Error uint32 - -// ExtDataControlDeviceV1Error : -const ( - // ExtDataControlDeviceV1ErrorUsedSource : source given to set_selection or set_primary_selection was already used before - ExtDataControlDeviceV1ErrorUsedSource ExtDataControlDeviceV1Error = 1 -) - -func (e ExtDataControlDeviceV1Error) Name() string { - switch e { - case ExtDataControlDeviceV1ErrorUsedSource: - return "used_source" - default: - return "" - } -} - -func (e ExtDataControlDeviceV1Error) Value() string { - switch e { - case ExtDataControlDeviceV1ErrorUsedSource: - return "1" - default: - return "" - } -} - -func (e ExtDataControlDeviceV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ExtDataControlDeviceV1DataOfferEvent : introduce a new ext_data_control_offer -// -// The data_offer event introduces a new ext_data_control_offer object, -// which will subsequently be used in either the -// ext_data_control_device.selection event (for the regular clipboard -// selections) or the ext_data_control_device.primary_selection event (for -// the primary clipboard selections). Immediately following the -// ext_data_control_device.data_offer event, the new data_offer object -// will send out ext_data_control_offer.offer events to describe the MIME -// types it offers. -type ExtDataControlDeviceV1DataOfferEvent struct { - Id *ExtDataControlOfferV1 -} -type ExtDataControlDeviceV1DataOfferHandlerFunc func(ExtDataControlDeviceV1DataOfferEvent) - -// SetDataOfferHandler : sets handler for ExtDataControlDeviceV1DataOfferEvent -func (i *ExtDataControlDeviceV1) SetDataOfferHandler(f ExtDataControlDeviceV1DataOfferHandlerFunc) { - i.dataOfferHandler = f -} - -// ExtDataControlDeviceV1SelectionEvent : advertise new selection -// -// The selection event is sent out to notify the client of a new -// ext_data_control_offer for the selection for this device. The -// ext_data_control_device.data_offer and the ext_data_control_offer.offer -// events are sent out immediately before this event to introduce the data -// offer object. The selection event is sent to a client when a new -// selection is set. The ext_data_control_offer is valid until a new -// ext_data_control_offer or NULL is received. The client must destroy the -// previous selection ext_data_control_offer, if any, upon receiving this -// event. Regardless, the previous selection will be ignored once a new -// selection ext_data_control_offer is received. -// -// The first selection event is sent upon binding the -// ext_data_control_device object. -type ExtDataControlDeviceV1SelectionEvent struct { - Id *ExtDataControlOfferV1 - OfferId uint32 // Raw object ID for external registry lookups -} -type ExtDataControlDeviceV1SelectionHandlerFunc func(ExtDataControlDeviceV1SelectionEvent) - -// SetSelectionHandler : sets handler for ExtDataControlDeviceV1SelectionEvent -func (i *ExtDataControlDeviceV1) SetSelectionHandler(f ExtDataControlDeviceV1SelectionHandlerFunc) { - i.selectionHandler = f -} - -// ExtDataControlDeviceV1FinishedEvent : this data control is no longer valid -// -// This data control object is no longer valid and should be destroyed by -// the client. -type ExtDataControlDeviceV1FinishedEvent struct{} -type ExtDataControlDeviceV1FinishedHandlerFunc func(ExtDataControlDeviceV1FinishedEvent) - -// SetFinishedHandler : sets handler for ExtDataControlDeviceV1FinishedEvent -func (i *ExtDataControlDeviceV1) SetFinishedHandler(f ExtDataControlDeviceV1FinishedHandlerFunc) { - i.finishedHandler = f -} - -// ExtDataControlDeviceV1PrimarySelectionEvent : advertise new primary selection -// -// The primary_selection event is sent out to notify the client of a new -// ext_data_control_offer for the primary selection for this device. The -// ext_data_control_device.data_offer and the ext_data_control_offer.offer -// events are sent out immediately before this event to introduce the data -// offer object. The primary_selection event is sent to a client when a -// new primary selection is set. The ext_data_control_offer is valid until -// a new ext_data_control_offer or NULL is received. The client must -// destroy the previous primary selection ext_data_control_offer, if any, -// upon receiving this event. Regardless, the previous primary selection -// will be ignored once a new primary selection ext_data_control_offer is -// received. -// -// If the compositor supports primary selection, the first -// primary_selection event is sent upon binding the -// ext_data_control_device object. -type ExtDataControlDeviceV1PrimarySelectionEvent struct { - Id *ExtDataControlOfferV1 - OfferId uint32 // Raw object ID for external registry lookups -} -type ExtDataControlDeviceV1PrimarySelectionHandlerFunc func(ExtDataControlDeviceV1PrimarySelectionEvent) - -// SetPrimarySelectionHandler : sets handler for ExtDataControlDeviceV1PrimarySelectionEvent -func (i *ExtDataControlDeviceV1) SetPrimarySelectionHandler(f ExtDataControlDeviceV1PrimarySelectionHandlerFunc) { - i.primarySelectionHandler = f -} - -func (i *ExtDataControlDeviceV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - // data_offer event: server creates a new object (new_id) - if i.dataOfferHandler == nil { - return - } - var e ExtDataControlDeviceV1DataOfferEvent - l := 0 - newID := client.Uint32(data[l : l+4]) - l += 4 - - ctx := i.Context() - offer := &ExtDataControlOfferV1{} - offer.SetContext(ctx) - offer.SetID(newID) - ctx.RegisterWithID(offer, newID) - e.Id = offer - - i.dataOfferHandler(e) - case 1: - // selection event: nullable object reference - if i.selectionHandler == nil { - return - } - var e ExtDataControlDeviceV1SelectionEvent - l := 0 - objID := client.Uint32(data[l : l+4]) - l += 4 - - e.OfferId = objID - if objID != 0 { - if p := i.Context().GetProxy(objID); p != nil { - e.Id = p.(*ExtDataControlOfferV1) - } - } - - i.selectionHandler(e) - case 2: - if i.finishedHandler == nil { - return - } - var e ExtDataControlDeviceV1FinishedEvent - - i.finishedHandler(e) - case 3: - // primary_selection event: nullable object reference - if i.primarySelectionHandler == nil { - return - } - var e ExtDataControlDeviceV1PrimarySelectionEvent - l := 0 - objID := client.Uint32(data[l : l+4]) - l += 4 - - e.OfferId = objID - if objID != 0 { - if p := i.Context().GetProxy(objID); p != nil { - e.Id = p.(*ExtDataControlOfferV1) - } - } - - i.primarySelectionHandler(e) - } -} - -// ExtDataControlSourceV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtDataControlSourceV1InterfaceName = "ext_data_control_source_v1" - -// ExtDataControlSourceV1 : offer to transfer data -// -// The ext_data_control_source object is the source side of a -// ext_data_control_offer. It is created by the source client in a data -// transfer and provides a way to describe the offered data and a way to -// respond to requests to transfer the data. -type ExtDataControlSourceV1 struct { - client.BaseProxy - sendHandler ExtDataControlSourceV1SendHandlerFunc - cancelledHandler ExtDataControlSourceV1CancelledHandlerFunc -} - -// NewExtDataControlSourceV1 : offer to transfer data -// -// The ext_data_control_source object is the source side of a -// ext_data_control_offer. It is created by the source client in a data -// transfer and provides a way to describe the offered data and a way to -// respond to requests to transfer the data. -func NewExtDataControlSourceV1(ctx *client.Context) *ExtDataControlSourceV1 { - extDataControlSourceV1 := &ExtDataControlSourceV1{} - ctx.Register(extDataControlSourceV1) - return extDataControlSourceV1 -} - -// Offer : add an offered MIME type -// -// This request adds a MIME type to the set of MIME types advertised to -// targets. Can be called several times to offer multiple types. -// -// Calling this after ext_data_control_device.set_selection is a protocol -// error. -// -// mimeType: MIME type offered by the data source -func (i *ExtDataControlSourceV1) Offer(mimeType string) error { - const opcode = 0 - mimeTypeLen := client.PaddedLen(len(mimeType) + 1) - _reqBufLen := 8 + (4 + mimeTypeLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutString(_reqBuf[l:l+(4+mimeTypeLen)], mimeType) - l += (4 + mimeTypeLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -// Destroy : destroy this source -// -// Destroys the data source object. -func (i *ExtDataControlSourceV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ExtDataControlSourceV1Error uint32 - -// ExtDataControlSourceV1Error : -const ( - // ExtDataControlSourceV1ErrorInvalidOffer : offer sent after ext_data_control_device.set_selection - ExtDataControlSourceV1ErrorInvalidOffer ExtDataControlSourceV1Error = 1 -) - -func (e ExtDataControlSourceV1Error) Name() string { - switch e { - case ExtDataControlSourceV1ErrorInvalidOffer: - return "invalid_offer" - default: - return "" - } -} - -func (e ExtDataControlSourceV1Error) Value() string { - switch e { - case ExtDataControlSourceV1ErrorInvalidOffer: - return "1" - default: - return "" - } -} - -func (e ExtDataControlSourceV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ExtDataControlSourceV1SendEvent : send the data -// -// Request for data from the client. Send the data as the specified MIME -// type over the passed file descriptor, then close it. -type ExtDataControlSourceV1SendEvent struct { - MimeType string - Fd int -} -type ExtDataControlSourceV1SendHandlerFunc func(ExtDataControlSourceV1SendEvent) - -// SetSendHandler : sets handler for ExtDataControlSourceV1SendEvent -func (i *ExtDataControlSourceV1) SetSendHandler(f ExtDataControlSourceV1SendHandlerFunc) { - i.sendHandler = f -} - -// ExtDataControlSourceV1CancelledEvent : selection was cancelled -// -// This data source is no longer valid. The data source has been replaced -// by another data source. -// -// The client should clean up and destroy this data source. -type ExtDataControlSourceV1CancelledEvent struct{} -type ExtDataControlSourceV1CancelledHandlerFunc func(ExtDataControlSourceV1CancelledEvent) - -// SetCancelledHandler : sets handler for ExtDataControlSourceV1CancelledEvent -func (i *ExtDataControlSourceV1) SetCancelledHandler(f ExtDataControlSourceV1CancelledHandlerFunc) { - i.cancelledHandler = f -} - -func (i *ExtDataControlSourceV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.sendHandler == nil { - if fd != -1 { - unix.Close(fd) - } - return - } - var e ExtDataControlSourceV1SendEvent - l := 0 - mimeTypeLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.MimeType = client.String(data[l : l+mimeTypeLen]) - l += mimeTypeLen - e.Fd = fd - - i.sendHandler(e) - case 1: - if i.cancelledHandler == nil { - return - } - var e ExtDataControlSourceV1CancelledEvent - - i.cancelledHandler(e) - } -} - -// ExtDataControlOfferV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtDataControlOfferV1InterfaceName = "ext_data_control_offer_v1" - -// ExtDataControlOfferV1 : offer to transfer data -// -// A ext_data_control_offer represents a piece of data offered for transfer -// by another client (the source client). The offer describes the different -// MIME types that the data can be converted to and provides the mechanism -// for transferring the data directly from the source client. -type ExtDataControlOfferV1 struct { - client.BaseProxy - offerHandler ExtDataControlOfferV1OfferHandlerFunc -} - -// NewExtDataControlOfferV1 : offer to transfer data -// -// A ext_data_control_offer represents a piece of data offered for transfer -// by another client (the source client). The offer describes the different -// MIME types that the data can be converted to and provides the mechanism -// for transferring the data directly from the source client. -func NewExtDataControlOfferV1(ctx *client.Context) *ExtDataControlOfferV1 { - extDataControlOfferV1 := &ExtDataControlOfferV1{} - ctx.Register(extDataControlOfferV1) - return extDataControlOfferV1 -} - -// Receive : request that the data is transferred -// -// To transfer the offered data, the client issues this request and -// indicates the MIME type it wants to receive. The transfer happens -// through the passed file descriptor (typically created with the pipe -// system call). The source client writes the data in the MIME type -// representation requested and then closes the file descriptor. -// -// The receiving client reads from the read end of the pipe until EOF and -// then closes its end, at which point the transfer is complete. -// -// This request may happen multiple times for different MIME types. -// -// mimeType: MIME type desired by receiver -// fd: file descriptor for data transfer -func (i *ExtDataControlOfferV1) Receive(mimeType string, fd int) error { - const opcode = 0 - mimeTypeLen := client.PaddedLen(len(mimeType) + 1) - _reqBufLen := 8 + (4 + mimeTypeLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutString(_reqBuf[l:l+(4+mimeTypeLen)], mimeType) - l += (4 + mimeTypeLen) - oob := unix.UnixRights(int(fd)) - err := i.Context().WriteMsg(_reqBuf, oob) - return err -} - -// Destroy : destroy this offer -// -// Destroys the data offer object. -func (i *ExtDataControlOfferV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ExtDataControlOfferV1OfferEvent : advertise offered MIME type -// -// Sent immediately after creating the ext_data_control_offer object. -// One event per offered MIME type. -type ExtDataControlOfferV1OfferEvent struct { - MimeType string -} -type ExtDataControlOfferV1OfferHandlerFunc func(ExtDataControlOfferV1OfferEvent) - -// SetOfferHandler : sets handler for ExtDataControlOfferV1OfferEvent -func (i *ExtDataControlOfferV1) SetOfferHandler(f ExtDataControlOfferV1OfferHandlerFunc) { - i.offerHandler = f -} - -func (i *ExtDataControlOfferV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.offerHandler == nil { - return - } - var e ExtDataControlOfferV1OfferEvent - l := 0 - mimeTypeLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.MimeType = client.String(data[l : l+mimeTypeLen]) - l += mimeTypeLen - - i.offerHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_workspace/workspace.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_workspace/workspace.go deleted file mode 100644 index c76ab98..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/ext_workspace/workspace.go +++ /dev/null @@ -1,1040 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/cmd/go-wayland-scanner -// XML file : ext-workspace-v1.xml -// -// ext_workspace_v1 Protocol Copyright: -// -// Copyright © 2019 Christopher Billington -// Copyright © 2020 Ilia Bozhinov -// Copyright © 2022 Victoria Brekenfeld -// -// Permission to use, copy, modify, distribute, and sell this -// software and its documentation for any purpose is hereby granted -// without fee, provided that the above copyright notice appear in -// all copies and that both that copyright notice and this permission -// notice appear in supporting documentation, and that the name of -// the copyright holders not be used in advertising or publicity -// pertaining to distribution of the software without specific, -// written prior permission. The copyright holders make no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied -// warranty. -// -// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - -package ext_workspace - -import ( - "reflect" - "unsafe" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -// registerServerProxy registers a proxy with a server-assigned ID. -// This is necessary because go-wayland-scanner doesn't properly handle new_id arguments in events. -// In requests (like DWL), the client creates the ID via NewXxx(ctx) which calls ctx.Register(). -// In events (like ext-workspace), the server creates the ID and sends it, requiring manual registration. -// The Context.objects map is private with no public API for server IDs, requiring reflection. -func registerServerProxy(ctx *client.Context, proxy client.Proxy, serverID uint32) { - defer func() { - if r := recover(); r != nil { - return - } - }() - - ctxVal := reflect.ValueOf(ctx) - if ctxVal.Kind() != reflect.Ptr || ctxVal.IsNil() { - return - } - - ctxElem := ctxVal.Elem() - objectsField := ctxElem.FieldByName("objects") - if !objectsField.IsValid() { - return - } - - objectsMapPtr := unsafe.Pointer(objectsField.UnsafeAddr()) - objectsMap := (*syncmap.Map[uint32, client.Proxy])(objectsMapPtr) - objectsMap.Store(serverID, proxy) -} - -// ExtWorkspaceManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtWorkspaceManagerV1InterfaceName = "ext_workspace_manager_v1" - -// ExtWorkspaceManagerV1 : list and control workspaces -// -// Workspaces, also called virtual desktops, are groups of surfaces. A -// compositor with a concept of workspaces may only show some such groups of -// surfaces (those of 'active' workspaces) at a time. 'Activating' a -// workspace is a request for the compositor to display that workspace's -// surfaces as normal, whereas the compositor may hide or otherwise -// de-emphasise surfaces that are associated only with 'inactive' workspaces. -// Workspaces are grouped by which sets of outputs they correspond to, and -// may contain surfaces only from those outputs. In this way, it is possible -// for each output to have its own set of workspaces, or for all outputs (or -// any other arbitrary grouping) to share workspaces. Compositors may -// optionally conceptually arrange each group of workspaces in an -// N-dimensional grid. -// -// The purpose of this protocol is to enable the creation of taskbars and -// docks by providing them with a list of workspaces and their properties, -// and allowing them to activate and deactivate workspaces. -// -// After a client binds the ext_workspace_manager_v1, each workspace will be -// sent via the workspace event. -type ExtWorkspaceManagerV1 struct { - client.BaseProxy - workspaceGroupHandler ExtWorkspaceManagerV1WorkspaceGroupHandlerFunc - workspaceHandler ExtWorkspaceManagerV1WorkspaceHandlerFunc - doneHandler ExtWorkspaceManagerV1DoneHandlerFunc - finishedHandler ExtWorkspaceManagerV1FinishedHandlerFunc -} - -// NewExtWorkspaceManagerV1 : list and control workspaces -// -// Workspaces, also called virtual desktops, are groups of surfaces. A -// compositor with a concept of workspaces may only show some such groups of -// surfaces (those of 'active' workspaces) at a time. 'Activating' a -// workspace is a request for the compositor to display that workspace's -// surfaces as normal, whereas the compositor may hide or otherwise -// de-emphasise surfaces that are associated only with 'inactive' workspaces. -// Workspaces are grouped by which sets of outputs they correspond to, and -// may contain surfaces only from those outputs. In this way, it is possible -// for each output to have its own set of workspaces, or for all outputs (or -// any other arbitrary grouping) to share workspaces. Compositors may -// optionally conceptually arrange each group of workspaces in an -// N-dimensional grid. -// -// The purpose of this protocol is to enable the creation of taskbars and -// docks by providing them with a list of workspaces and their properties, -// and allowing them to activate and deactivate workspaces. -// -// After a client binds the ext_workspace_manager_v1, each workspace will be -// sent via the workspace event. -func NewExtWorkspaceManagerV1(ctx *client.Context) *ExtWorkspaceManagerV1 { - extWorkspaceManagerV1 := &ExtWorkspaceManagerV1{} - ctx.Register(extWorkspaceManagerV1) - return extWorkspaceManagerV1 -} - -// Commit : all requests about the workspaces have been sent -// -// The client must send this request after it has finished sending other -// requests. The compositor must process a series of requests preceding a -// commit request atomically. -// -// This allows changes to the workspace properties to be seen as atomic, -// even if they happen via multiple events, and even if they involve -// multiple ext_workspace_handle_v1 objects, for example, deactivating one -// workspace and activating another. -func (i *ExtWorkspaceManagerV1) Commit() error { - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Stop : stop sending events -// -// Indicates the client no longer wishes to receive events for new -// workspace groups. However the compositor may emit further workspace -// events, until the finished event is emitted. The compositor is expected -// to send the finished event eventually once the stop request has been processed. -// -// The client must not send any requests after this one, doing so will raise a wl_display -// invalid_object error. -func (i *ExtWorkspaceManagerV1) Stop() error { - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -func (i *ExtWorkspaceManagerV1) Destroy() error { - i.MarkZombie() - return nil -} - -// ExtWorkspaceManagerV1WorkspaceGroupEvent : a workspace group has been created -// -// This event is emitted whenever a new workspace group has been created. -// -// All initial details of the workspace group (outputs) will be -// sent immediately after this event via the corresponding events in -// ext_workspace_group_handle_v1 and ext_workspace_handle_v1. -type ExtWorkspaceManagerV1WorkspaceGroupEvent struct { - WorkspaceGroup *ExtWorkspaceGroupHandleV1 -} -type ExtWorkspaceManagerV1WorkspaceGroupHandlerFunc func(ExtWorkspaceManagerV1WorkspaceGroupEvent) - -// SetWorkspaceGroupHandler : sets handler for ExtWorkspaceManagerV1WorkspaceGroupEvent -func (i *ExtWorkspaceManagerV1) SetWorkspaceGroupHandler(f ExtWorkspaceManagerV1WorkspaceGroupHandlerFunc) { - i.workspaceGroupHandler = f -} - -// ExtWorkspaceManagerV1WorkspaceEvent : workspace has been created -// -// This event is emitted whenever a new workspace has been created. -// -// All initial details of the workspace (name, coordinates, state) will -// be sent immediately after this event via the corresponding events in -// ext_workspace_handle_v1. -// -// Workspaces start off unassigned to any workspace group. -type ExtWorkspaceManagerV1WorkspaceEvent struct { - Workspace *ExtWorkspaceHandleV1 -} -type ExtWorkspaceManagerV1WorkspaceHandlerFunc func(ExtWorkspaceManagerV1WorkspaceEvent) - -// SetWorkspaceHandler : sets handler for ExtWorkspaceManagerV1WorkspaceEvent -func (i *ExtWorkspaceManagerV1) SetWorkspaceHandler(f ExtWorkspaceManagerV1WorkspaceHandlerFunc) { - i.workspaceHandler = f -} - -// ExtWorkspaceManagerV1DoneEvent : all information about the workspaces and workspace groups has been sent -// -// This event is sent after all changes in all workspaces and workspace groups have been -// sent. -// -// This allows changes to one or more ext_workspace_group_handle_v1 -// properties and ext_workspace_handle_v1 properties -// to be seen as atomic, even if they happen via multiple events. -// In particular, an output moving from one workspace group to -// another sends an output_enter event and an output_leave event to the two -// ext_workspace_group_handle_v1 objects in question. The compositor sends -// the done event only after updating the output information in both -// workspace groups. -type ExtWorkspaceManagerV1DoneEvent struct{} -type ExtWorkspaceManagerV1DoneHandlerFunc func(ExtWorkspaceManagerV1DoneEvent) - -// SetDoneHandler : sets handler for ExtWorkspaceManagerV1DoneEvent -func (i *ExtWorkspaceManagerV1) SetDoneHandler(f ExtWorkspaceManagerV1DoneHandlerFunc) { - i.doneHandler = f -} - -// ExtWorkspaceManagerV1FinishedEvent : the compositor has finished with the workspace_manager -// -// This event indicates that the compositor is done sending events to the -// ext_workspace_manager_v1. The server will destroy the object -// immediately after sending this request. -type ExtWorkspaceManagerV1FinishedEvent struct{} -type ExtWorkspaceManagerV1FinishedHandlerFunc func(ExtWorkspaceManagerV1FinishedEvent) - -// SetFinishedHandler : sets handler for ExtWorkspaceManagerV1FinishedEvent -func (i *ExtWorkspaceManagerV1) SetFinishedHandler(f ExtWorkspaceManagerV1FinishedHandlerFunc) { - i.finishedHandler = f -} - -func (i *ExtWorkspaceManagerV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.workspaceGroupHandler == nil { - return - } - var e ExtWorkspaceManagerV1WorkspaceGroupEvent - l := 0 - objectID := client.Uint32(data[l : l+4]) - proxy := i.Context().GetProxy(objectID) - if proxy != nil && !proxy.IsZombie() { - e.WorkspaceGroup = proxy.(*ExtWorkspaceGroupHandleV1) - } else { - groupHandle := &ExtWorkspaceGroupHandleV1{} - groupHandle.SetContext(i.Context()) - groupHandle.SetID(objectID) - registerServerProxy(i.Context(), groupHandle, objectID) - e.WorkspaceGroup = groupHandle - } - l += 4 - - i.workspaceGroupHandler(e) - case 1: - if i.workspaceHandler == nil { - return - } - var e ExtWorkspaceManagerV1WorkspaceEvent - l := 0 - objectID := client.Uint32(data[l : l+4]) - proxy := i.Context().GetProxy(objectID) - if proxy != nil && !proxy.IsZombie() { - e.Workspace = proxy.(*ExtWorkspaceHandleV1) - } else { - wsHandle := &ExtWorkspaceHandleV1{} - wsHandle.SetContext(i.Context()) - wsHandle.SetID(objectID) - registerServerProxy(i.Context(), wsHandle, objectID) - e.Workspace = wsHandle - } - l += 4 - - i.workspaceHandler(e) - case 2: - if i.doneHandler == nil { - return - } - var e ExtWorkspaceManagerV1DoneEvent - - i.doneHandler(e) - case 3: - if i.finishedHandler == nil { - return - } - var e ExtWorkspaceManagerV1FinishedEvent - - i.finishedHandler(e) - } -} - -// ExtWorkspaceGroupHandleV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtWorkspaceGroupHandleV1InterfaceName = "ext_workspace_group_handle_v1" - -// ExtWorkspaceGroupHandleV1 : a workspace group assigned to a set of outputs -// -// A ext_workspace_group_handle_v1 object represents a workspace group -// that is assigned a set of outputs and contains a number of workspaces. -// -// The set of outputs assigned to the workspace group is conveyed to the client via -// output_enter and output_leave events, and its workspaces are conveyed with -// workspace events. -// -// For example, a compositor which has a set of workspaces for each output may -// advertise a workspace group (and its workspaces) per output, whereas a compositor -// where a workspace spans all outputs may advertise a single workspace group for all -// outputs. -type ExtWorkspaceGroupHandleV1 struct { - client.BaseProxy - capabilitiesHandler ExtWorkspaceGroupHandleV1CapabilitiesHandlerFunc - outputEnterHandler ExtWorkspaceGroupHandleV1OutputEnterHandlerFunc - outputLeaveHandler ExtWorkspaceGroupHandleV1OutputLeaveHandlerFunc - workspaceEnterHandler ExtWorkspaceGroupHandleV1WorkspaceEnterHandlerFunc - workspaceLeaveHandler ExtWorkspaceGroupHandleV1WorkspaceLeaveHandlerFunc - removedHandler ExtWorkspaceGroupHandleV1RemovedHandlerFunc -} - -// NewExtWorkspaceGroupHandleV1 : a workspace group assigned to a set of outputs -// -// A ext_workspace_group_handle_v1 object represents a workspace group -// that is assigned a set of outputs and contains a number of workspaces. -// -// The set of outputs assigned to the workspace group is conveyed to the client via -// output_enter and output_leave events, and its workspaces are conveyed with -// workspace events. -// -// For example, a compositor which has a set of workspaces for each output may -// advertise a workspace group (and its workspaces) per output, whereas a compositor -// where a workspace spans all outputs may advertise a single workspace group for all -// outputs. -func NewExtWorkspaceGroupHandleV1(ctx *client.Context) *ExtWorkspaceGroupHandleV1 { - extWorkspaceGroupHandleV1 := &ExtWorkspaceGroupHandleV1{} - ctx.Register(extWorkspaceGroupHandleV1) - return extWorkspaceGroupHandleV1 -} - -// CreateWorkspace : create a new workspace -// -// Request that the compositor create a new workspace with the given name -// and assign it to this group. -// -// There is no guarantee that the compositor will create a new workspace, -// or that the created workspace will have the provided name. -func (i *ExtWorkspaceGroupHandleV1) CreateWorkspace(workspace string) error { - const opcode = 0 - workspaceLen := client.PaddedLen(len(workspace) + 1) - _reqBufLen := 8 + (4 + workspaceLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutString(_reqBuf[l:l+(4+workspaceLen)], workspace) - l += (4 + workspaceLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -// Destroy : destroy the ext_workspace_group_handle_v1 object -// -// Destroys the ext_workspace_group_handle_v1 object. -// -// This request should be send either when the client does not want to -// use the workspace group object any more or after the removed event to finalize -// the destruction of the object. -func (i *ExtWorkspaceGroupHandleV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ExtWorkspaceGroupHandleV1GroupCapabilities uint32 - -// ExtWorkspaceGroupHandleV1GroupCapabilities : -const ( - // ExtWorkspaceGroupHandleV1GroupCapabilitiesCreateWorkspace : create_workspace request is available - ExtWorkspaceGroupHandleV1GroupCapabilitiesCreateWorkspace ExtWorkspaceGroupHandleV1GroupCapabilities = 1 -) - -func (e ExtWorkspaceGroupHandleV1GroupCapabilities) Name() string { - switch e { - case ExtWorkspaceGroupHandleV1GroupCapabilitiesCreateWorkspace: - return "create_workspace" - default: - return "" - } -} - -func (e ExtWorkspaceGroupHandleV1GroupCapabilities) Value() string { - switch e { - case ExtWorkspaceGroupHandleV1GroupCapabilitiesCreateWorkspace: - return "1" - default: - return "" - } -} - -func (e ExtWorkspaceGroupHandleV1GroupCapabilities) String() string { - return e.Name() + "=" + e.Value() -} - -// ExtWorkspaceGroupHandleV1CapabilitiesEvent : compositor capabilities -// -// This event advertises the capabilities supported by the compositor. If -// a capability isn't supported, clients should hide or disable the UI -// elements that expose this functionality. For instance, if the -// compositor doesn't advertise support for creating workspaces, a button -// triggering the create_workspace request should not be displayed. -// -// The compositor will ignore requests it doesn't support. For instance, -// a compositor which doesn't advertise support for creating workspaces will ignore -// create_workspace requests. -// -// Compositors must send this event once after creation of an -// ext_workspace_group_handle_v1. When the capabilities change, compositors -// must send this event again. -type ExtWorkspaceGroupHandleV1CapabilitiesEvent struct { - Capabilities uint32 -} -type ExtWorkspaceGroupHandleV1CapabilitiesHandlerFunc func(ExtWorkspaceGroupHandleV1CapabilitiesEvent) - -// SetCapabilitiesHandler : sets handler for ExtWorkspaceGroupHandleV1CapabilitiesEvent -func (i *ExtWorkspaceGroupHandleV1) SetCapabilitiesHandler(f ExtWorkspaceGroupHandleV1CapabilitiesHandlerFunc) { - i.capabilitiesHandler = f -} - -// ExtWorkspaceGroupHandleV1OutputEnterEvent : output assigned to workspace group -// -// This event is emitted whenever an output is assigned to the workspace -// group or a new `wl_output` object is bound by the client, which was already -// assigned to this workspace_group. -type ExtWorkspaceGroupHandleV1OutputEnterEvent struct { - Output *client.Output -} -type ExtWorkspaceGroupHandleV1OutputEnterHandlerFunc func(ExtWorkspaceGroupHandleV1OutputEnterEvent) - -// SetOutputEnterHandler : sets handler for ExtWorkspaceGroupHandleV1OutputEnterEvent -func (i *ExtWorkspaceGroupHandleV1) SetOutputEnterHandler(f ExtWorkspaceGroupHandleV1OutputEnterHandlerFunc) { - i.outputEnterHandler = f -} - -// ExtWorkspaceGroupHandleV1OutputLeaveEvent : output removed from workspace group -// -// This event is emitted whenever an output is removed from the workspace -// group. -type ExtWorkspaceGroupHandleV1OutputLeaveEvent struct { - Output *client.Output -} -type ExtWorkspaceGroupHandleV1OutputLeaveHandlerFunc func(ExtWorkspaceGroupHandleV1OutputLeaveEvent) - -// SetOutputLeaveHandler : sets handler for ExtWorkspaceGroupHandleV1OutputLeaveEvent -func (i *ExtWorkspaceGroupHandleV1) SetOutputLeaveHandler(f ExtWorkspaceGroupHandleV1OutputLeaveHandlerFunc) { - i.outputLeaveHandler = f -} - -// ExtWorkspaceGroupHandleV1WorkspaceEnterEvent : workspace added to workspace group -// -// This event is emitted whenever a workspace is assigned to this group. -// A workspace may only ever be assigned to a single group at a single point -// in time, but can be re-assigned during it's lifetime. -type ExtWorkspaceGroupHandleV1WorkspaceEnterEvent struct { - Workspace *ExtWorkspaceHandleV1 -} -type ExtWorkspaceGroupHandleV1WorkspaceEnterHandlerFunc func(ExtWorkspaceGroupHandleV1WorkspaceEnterEvent) - -// SetWorkspaceEnterHandler : sets handler for ExtWorkspaceGroupHandleV1WorkspaceEnterEvent -func (i *ExtWorkspaceGroupHandleV1) SetWorkspaceEnterHandler(f ExtWorkspaceGroupHandleV1WorkspaceEnterHandlerFunc) { - i.workspaceEnterHandler = f -} - -// ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent : workspace removed from workspace group -// -// This event is emitted whenever a workspace is removed from this group. -type ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent struct { - Workspace *ExtWorkspaceHandleV1 -} -type ExtWorkspaceGroupHandleV1WorkspaceLeaveHandlerFunc func(ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent) - -// SetWorkspaceLeaveHandler : sets handler for ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent -func (i *ExtWorkspaceGroupHandleV1) SetWorkspaceLeaveHandler(f ExtWorkspaceGroupHandleV1WorkspaceLeaveHandlerFunc) { - i.workspaceLeaveHandler = f -} - -// ExtWorkspaceGroupHandleV1RemovedEvent : this workspace group has been removed -// -// This event is send when the group associated with the ext_workspace_group_handle_v1 -// has been removed. After sending this request the compositor will immediately consider -// the object inert. Any requests will be ignored except the destroy request. -// It is guaranteed there won't be any more events referencing this -// ext_workspace_group_handle_v1. -// -// The compositor must remove all workspaces belonging to a workspace group -// via a workspace_leave event before removing the workspace group. -type ExtWorkspaceGroupHandleV1RemovedEvent struct{} -type ExtWorkspaceGroupHandleV1RemovedHandlerFunc func(ExtWorkspaceGroupHandleV1RemovedEvent) - -// SetRemovedHandler : sets handler for ExtWorkspaceGroupHandleV1RemovedEvent -func (i *ExtWorkspaceGroupHandleV1) SetRemovedHandler(f ExtWorkspaceGroupHandleV1RemovedHandlerFunc) { - i.removedHandler = f -} - -func (i *ExtWorkspaceGroupHandleV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.capabilitiesHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1CapabilitiesEvent - l := 0 - e.Capabilities = client.Uint32(data[l : l+4]) - l += 4 - - i.capabilitiesHandler(e) - case 1: - if i.outputEnterHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1OutputEnterEvent - l := 0 - e.Output = i.Context().GetProxy(client.Uint32(data[l : l+4])).(*client.Output) - l += 4 - - i.outputEnterHandler(e) - case 2: - if i.outputLeaveHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1OutputLeaveEvent - l := 0 - e.Output = i.Context().GetProxy(client.Uint32(data[l : l+4])).(*client.Output) - l += 4 - - i.outputLeaveHandler(e) - case 3: - if i.workspaceEnterHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1WorkspaceEnterEvent - l := 0 - e.Workspace = i.Context().GetProxy(client.Uint32(data[l : l+4])).(*ExtWorkspaceHandleV1) - l += 4 - - i.workspaceEnterHandler(e) - case 4: - if i.workspaceLeaveHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent - l := 0 - e.Workspace = i.Context().GetProxy(client.Uint32(data[l : l+4])).(*ExtWorkspaceHandleV1) - l += 4 - - i.workspaceLeaveHandler(e) - case 5: - if i.removedHandler == nil { - return - } - var e ExtWorkspaceGroupHandleV1RemovedEvent - - i.removedHandler(e) - } -} - -// ExtWorkspaceHandleV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ExtWorkspaceHandleV1InterfaceName = "ext_workspace_handle_v1" - -// ExtWorkspaceHandleV1 : a workspace handing a group of surfaces -// -// A ext_workspace_handle_v1 object represents a workspace that handles a -// group of surfaces. -// -// Each workspace has: -// - a name, conveyed to the client with the name event -// - potentially an id conveyed with the id event -// - a list of states, conveyed to the client with the state event -// - and optionally a set of coordinates, conveyed to the client with the -// coordinates event -// -// The client may request that the compositor activate or deactivate the workspace. -// -// Each workspace can belong to only a single workspace group. -// Depending on the compositor policy, there might be workspaces with -// the same name in different workspace groups, but these workspaces are still -// separate (e.g. one of them might be active while the other is not). -type ExtWorkspaceHandleV1 struct { - client.BaseProxy - idHandler ExtWorkspaceHandleV1IdHandlerFunc - nameHandler ExtWorkspaceHandleV1NameHandlerFunc - coordinatesHandler ExtWorkspaceHandleV1CoordinatesHandlerFunc - stateHandler ExtWorkspaceHandleV1StateHandlerFunc - capabilitiesHandler ExtWorkspaceHandleV1CapabilitiesHandlerFunc - removedHandler ExtWorkspaceHandleV1RemovedHandlerFunc -} - -// NewExtWorkspaceHandleV1 : a workspace handing a group of surfaces -// -// A ext_workspace_handle_v1 object represents a workspace that handles a -// group of surfaces. -// -// Each workspace has: -// - a name, conveyed to the client with the name event -// - potentially an id conveyed with the id event -// - a list of states, conveyed to the client with the state event -// - and optionally a set of coordinates, conveyed to the client with the -// coordinates event -// -// The client may request that the compositor activate or deactivate the workspace. -// -// Each workspace can belong to only a single workspace group. -// Depending on the compositor policy, there might be workspaces with -// the same name in different workspace groups, but these workspaces are still -// separate (e.g. one of them might be active while the other is not). -func NewExtWorkspaceHandleV1(ctx *client.Context) *ExtWorkspaceHandleV1 { - extWorkspaceHandleV1 := &ExtWorkspaceHandleV1{} - ctx.Register(extWorkspaceHandleV1) - return extWorkspaceHandleV1 -} - -// Destroy : destroy the ext_workspace_handle_v1 object -// -// Destroys the ext_workspace_handle_v1 object. -// -// This request should be made either when the client does not want to -// use the workspace object any more or after the remove event to finalize -// the destruction of the object. -func (i *ExtWorkspaceHandleV1) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Activate : activate the workspace -// -// Request that this workspace be activated. -// -// There is no guarantee the workspace will be actually activated, and -// behaviour may be compositor-dependent. For example, activating a -// workspace may or may not deactivate all other workspaces in the same -// group. -func (i *ExtWorkspaceHandleV1) Activate() error { - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Deactivate : deactivate the workspace -// -// Request that this workspace be deactivated. -// -// There is no guarantee the workspace will be actually deactivated. -func (i *ExtWorkspaceHandleV1) Deactivate() error { - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Assign : assign workspace to group -// -// Requests that this workspace is assigned to the given workspace group. -// -// There is no guarantee the workspace will be assigned. -func (i *ExtWorkspaceHandleV1) Assign(workspaceGroup *ExtWorkspaceGroupHandleV1) error { - const opcode = 3 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], workspaceGroup.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Remove : remove the workspace -// -// Request that this workspace be removed. -// -// There is no guarantee the workspace will be actually removed. -func (i *ExtWorkspaceHandleV1) Remove() error { - const opcode = 4 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ExtWorkspaceHandleV1State uint32 - -// ExtWorkspaceHandleV1State : types of states on the workspace -// -// The different states that a workspace can have. -const ( - // ExtWorkspaceHandleV1StateActive : the workspace is active - ExtWorkspaceHandleV1StateActive ExtWorkspaceHandleV1State = 1 - // ExtWorkspaceHandleV1StateUrgent : the workspace requests attention - ExtWorkspaceHandleV1StateUrgent ExtWorkspaceHandleV1State = 2 - ExtWorkspaceHandleV1StateHidden ExtWorkspaceHandleV1State = 4 -) - -func (e ExtWorkspaceHandleV1State) Name() string { - switch e { - case ExtWorkspaceHandleV1StateActive: - return "active" - case ExtWorkspaceHandleV1StateUrgent: - return "urgent" - case ExtWorkspaceHandleV1StateHidden: - return "hidden" - default: - return "" - } -} - -func (e ExtWorkspaceHandleV1State) Value() string { - switch e { - case ExtWorkspaceHandleV1StateActive: - return "1" - case ExtWorkspaceHandleV1StateUrgent: - return "2" - case ExtWorkspaceHandleV1StateHidden: - return "4" - default: - return "" - } -} - -func (e ExtWorkspaceHandleV1State) String() string { - return e.Name() + "=" + e.Value() -} - -type ExtWorkspaceHandleV1WorkspaceCapabilities uint32 - -// ExtWorkspaceHandleV1WorkspaceCapabilities : -const ( - // ExtWorkspaceHandleV1WorkspaceCapabilitiesActivate : activate request is available - ExtWorkspaceHandleV1WorkspaceCapabilitiesActivate ExtWorkspaceHandleV1WorkspaceCapabilities = 1 - // ExtWorkspaceHandleV1WorkspaceCapabilitiesDeactivate : deactivate request is available - ExtWorkspaceHandleV1WorkspaceCapabilitiesDeactivate ExtWorkspaceHandleV1WorkspaceCapabilities = 2 - // ExtWorkspaceHandleV1WorkspaceCapabilitiesRemove : remove request is available - ExtWorkspaceHandleV1WorkspaceCapabilitiesRemove ExtWorkspaceHandleV1WorkspaceCapabilities = 4 - // ExtWorkspaceHandleV1WorkspaceCapabilitiesAssign : assign request is available - ExtWorkspaceHandleV1WorkspaceCapabilitiesAssign ExtWorkspaceHandleV1WorkspaceCapabilities = 8 -) - -func (e ExtWorkspaceHandleV1WorkspaceCapabilities) Name() string { - switch e { - case ExtWorkspaceHandleV1WorkspaceCapabilitiesActivate: - return "activate" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesDeactivate: - return "deactivate" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesRemove: - return "remove" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesAssign: - return "assign" - default: - return "" - } -} - -func (e ExtWorkspaceHandleV1WorkspaceCapabilities) Value() string { - switch e { - case ExtWorkspaceHandleV1WorkspaceCapabilitiesActivate: - return "1" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesDeactivate: - return "2" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesRemove: - return "4" - case ExtWorkspaceHandleV1WorkspaceCapabilitiesAssign: - return "8" - default: - return "" - } -} - -func (e ExtWorkspaceHandleV1WorkspaceCapabilities) String() string { - return e.Name() + "=" + e.Value() -} - -// ExtWorkspaceHandleV1IdEvent : workspace id -// -// If this event is emitted, it will be send immediately after the -// ext_workspace_handle_v1 is created or when an id is assigned to -// a workspace (at most once during it's lifetime). -// -// An id will never change during the lifetime of the `ext_workspace_handle_v1` -// and is guaranteed to be unique during it's lifetime. -// -// Ids are not human-readable and shouldn't be displayed, use `name` for that purpose. -// -// Compositors are expected to only send ids for workspaces likely stable across multiple -// sessions and can be used by clients to store preferences for workspaces. Workspaces without -// ids should be considered temporary and any data associated with them should be deleted once -// the respective object is lost. -type ExtWorkspaceHandleV1IdEvent struct { - Id string -} -type ExtWorkspaceHandleV1IdHandlerFunc func(ExtWorkspaceHandleV1IdEvent) - -// SetIdHandler : sets handler for ExtWorkspaceHandleV1IdEvent -func (i *ExtWorkspaceHandleV1) SetIdHandler(f ExtWorkspaceHandleV1IdHandlerFunc) { - i.idHandler = f -} - -// ExtWorkspaceHandleV1NameEvent : workspace name changed -// -// This event is emitted immediately after the ext_workspace_handle_v1 is -// created and whenever the name of the workspace changes. -// -// A name is meant to be human-readable and can be displayed to a user. -// Unlike the id it is neither stable nor unique. -type ExtWorkspaceHandleV1NameEvent struct { - Name string -} -type ExtWorkspaceHandleV1NameHandlerFunc func(ExtWorkspaceHandleV1NameEvent) - -// SetNameHandler : sets handler for ExtWorkspaceHandleV1NameEvent -func (i *ExtWorkspaceHandleV1) SetNameHandler(f ExtWorkspaceHandleV1NameHandlerFunc) { - i.nameHandler = f -} - -// ExtWorkspaceHandleV1CoordinatesEvent : workspace coordinates changed -// -// This event is used to organize workspaces into an N-dimensional grid -// within a workspace group, and if supported, is emitted immediately after -// the ext_workspace_handle_v1 is created and whenever the coordinates of -// the workspace change. Compositors may not send this event if they do not -// conceptually arrange workspaces in this way. If compositors simply -// number workspaces, without any geometric interpretation, they may send -// 1D coordinates, which clients should not interpret as implying any -// geometry. Sending an empty array means that the compositor no longer -// orders the workspace geometrically. -// -// Coordinates have an arbitrary number of dimensions N with an uint32 -// position along each dimension. By convention if N > 1, the first -// dimension is X, the second Y, the third Z, and so on. The compositor may -// chose to utilize these events for a more novel workspace layout -// convention, however. No guarantee is made about the grid being filled or -// bounded; there may be a workspace at coordinate 1 and another at -// coordinate 1000 and none in between. Within a workspace group, however, -// workspaces must have unique coordinates of equal dimensionality. -type ExtWorkspaceHandleV1CoordinatesEvent struct { - Coordinates []byte -} -type ExtWorkspaceHandleV1CoordinatesHandlerFunc func(ExtWorkspaceHandleV1CoordinatesEvent) - -// SetCoordinatesHandler : sets handler for ExtWorkspaceHandleV1CoordinatesEvent -func (i *ExtWorkspaceHandleV1) SetCoordinatesHandler(f ExtWorkspaceHandleV1CoordinatesHandlerFunc) { - i.coordinatesHandler = f -} - -// ExtWorkspaceHandleV1StateEvent : the state of the workspace changed -// -// This event is emitted immediately after the ext_workspace_handle_v1 is -// created and each time the workspace state changes, either because of a -// compositor action or because of a request in this protocol. -// -// Missing states convey the opposite meaning, e.g. an unset active bit -// means the workspace is currently inactive. -type ExtWorkspaceHandleV1StateEvent struct { - State uint32 -} -type ExtWorkspaceHandleV1StateHandlerFunc func(ExtWorkspaceHandleV1StateEvent) - -// SetStateHandler : sets handler for ExtWorkspaceHandleV1StateEvent -func (i *ExtWorkspaceHandleV1) SetStateHandler(f ExtWorkspaceHandleV1StateHandlerFunc) { - i.stateHandler = f -} - -// ExtWorkspaceHandleV1CapabilitiesEvent : compositor capabilities -// -// This event advertises the capabilities supported by the compositor. If -// a capability isn't supported, clients should hide or disable the UI -// elements that expose this functionality. For instance, if the -// compositor doesn't advertise support for removing workspaces, a button -// triggering the remove request should not be displayed. -// -// The compositor will ignore requests it doesn't support. For instance, -// a compositor which doesn't advertise support for remove will ignore -// remove requests. -// -// Compositors must send this event once after creation of an -// ext_workspace_handle_v1 . When the capabilities change, compositors -// must send this event again. -type ExtWorkspaceHandleV1CapabilitiesEvent struct { - Capabilities uint32 -} -type ExtWorkspaceHandleV1CapabilitiesHandlerFunc func(ExtWorkspaceHandleV1CapabilitiesEvent) - -// SetCapabilitiesHandler : sets handler for ExtWorkspaceHandleV1CapabilitiesEvent -func (i *ExtWorkspaceHandleV1) SetCapabilitiesHandler(f ExtWorkspaceHandleV1CapabilitiesHandlerFunc) { - i.capabilitiesHandler = f -} - -// ExtWorkspaceHandleV1RemovedEvent : this workspace has been removed -// -// This event is send when the workspace associated with the ext_workspace_handle_v1 -// has been removed. After sending this request, the compositor will immediately consider -// the object inert. Any requests will be ignored except the destroy request. -// -// It is guaranteed there won't be any more events referencing this -// ext_workspace_handle_v1. -// -// The compositor must only remove a workspaces not currently belonging to any -// workspace_group. -type ExtWorkspaceHandleV1RemovedEvent struct{} -type ExtWorkspaceHandleV1RemovedHandlerFunc func(ExtWorkspaceHandleV1RemovedEvent) - -// SetRemovedHandler : sets handler for ExtWorkspaceHandleV1RemovedEvent -func (i *ExtWorkspaceHandleV1) SetRemovedHandler(f ExtWorkspaceHandleV1RemovedHandlerFunc) { - i.removedHandler = f -} - -func (i *ExtWorkspaceHandleV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.idHandler == nil { - return - } - var e ExtWorkspaceHandleV1IdEvent - l := 0 - idLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Id = client.String(data[l : l+idLen]) - l += idLen - - i.idHandler(e) - case 1: - if i.nameHandler == nil { - return - } - var e ExtWorkspaceHandleV1NameEvent - l := 0 - nameLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Name = client.String(data[l : l+nameLen]) - l += nameLen - - i.nameHandler(e) - case 2: - if i.coordinatesHandler == nil { - return - } - var e ExtWorkspaceHandleV1CoordinatesEvent - l := 0 - coordinatesLen := int(client.Uint32(data[l : l+4])) - l += 4 - e.Coordinates = make([]byte, coordinatesLen) - copy(e.Coordinates, data[l:l+coordinatesLen]) - l += coordinatesLen - - i.coordinatesHandler(e) - case 3: - if i.stateHandler == nil { - return - } - var e ExtWorkspaceHandleV1StateEvent - l := 0 - e.State = client.Uint32(data[l : l+4]) - l += 4 - - i.stateHandler(e) - case 4: - if i.capabilitiesHandler == nil { - return - } - var e ExtWorkspaceHandleV1CapabilitiesEvent - l := 0 - e.Capabilities = client.Uint32(data[l : l+4]) - l += 4 - - i.capabilitiesHandler(e) - case 5: - if i.removedHandler == nil { - return - } - var e ExtWorkspaceHandleV1RemovedEvent - - i.removedHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit/keyboard_shortcuts_inhibit.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit/keyboard_shortcuts_inhibit.go deleted file mode 100644 index 0a23bb2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit/keyboard_shortcuts_inhibit.go +++ /dev/null @@ -1,284 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/keyboard-shortcuts-inhibit-unstable-v1.xml -// -// keyboard_shortcuts_inhibit_unstable_v1 Protocol Copyright: -// -// Copyright © 2017 Red Hat Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice (including the next -// paragraph) shall be included in all copies or substantial portions of the -// Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -package keyboard_shortcuts_inhibit - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -// ZwpKeyboardShortcutsInhibitManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwpKeyboardShortcutsInhibitManagerV1InterfaceName = "zwp_keyboard_shortcuts_inhibit_manager_v1" - -// ZwpKeyboardShortcutsInhibitManagerV1 : context object for keyboard grab_manager -// -// A global interface used for inhibiting the compositor keyboard shortcuts. -type ZwpKeyboardShortcutsInhibitManagerV1 struct { - client.BaseProxy -} - -// NewZwpKeyboardShortcutsInhibitManagerV1 : context object for keyboard grab_manager -// -// A global interface used for inhibiting the compositor keyboard shortcuts. -func NewZwpKeyboardShortcutsInhibitManagerV1(ctx *client.Context) *ZwpKeyboardShortcutsInhibitManagerV1 { - zwpKeyboardShortcutsInhibitManagerV1 := &ZwpKeyboardShortcutsInhibitManagerV1{} - ctx.Register(zwpKeyboardShortcutsInhibitManagerV1) - return zwpKeyboardShortcutsInhibitManagerV1 -} - -// Destroy : destroy the keyboard shortcuts inhibitor object -// -// Destroy the keyboard shortcuts inhibitor manager. -func (i *ZwpKeyboardShortcutsInhibitManagerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// InhibitShortcuts : create a new keyboard shortcuts inhibitor object -// -// Create a new keyboard shortcuts inhibitor object associated with -// the given surface for the given seat. -// -// If shortcuts are already inhibited for the specified seat and surface, -// a protocol error "already_inhibited" is raised by the compositor. -// -// surface: the surface that inhibits the keyboard shortcuts behavior -// seat: the wl_seat for which keyboard shortcuts should be disabled -func (i *ZwpKeyboardShortcutsInhibitManagerV1) InhibitShortcuts(surface *client.Surface, seat *client.Seat) (*ZwpKeyboardShortcutsInhibitorV1, error) { - id := NewZwpKeyboardShortcutsInhibitorV1(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -type ZwpKeyboardShortcutsInhibitManagerV1Error uint32 - -// ZwpKeyboardShortcutsInhibitManagerV1Error : -const ( - // ZwpKeyboardShortcutsInhibitManagerV1ErrorAlreadyInhibited : the shortcuts are already inhibited for this surface - ZwpKeyboardShortcutsInhibitManagerV1ErrorAlreadyInhibited ZwpKeyboardShortcutsInhibitManagerV1Error = 0 -) - -func (e ZwpKeyboardShortcutsInhibitManagerV1Error) Name() string { - switch e { - case ZwpKeyboardShortcutsInhibitManagerV1ErrorAlreadyInhibited: - return "already_inhibited" - default: - return "" - } -} - -func (e ZwpKeyboardShortcutsInhibitManagerV1Error) Value() string { - switch e { - case ZwpKeyboardShortcutsInhibitManagerV1ErrorAlreadyInhibited: - return "0" - default: - return "" - } -} - -func (e ZwpKeyboardShortcutsInhibitManagerV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwpKeyboardShortcutsInhibitorV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwpKeyboardShortcutsInhibitorV1InterfaceName = "zwp_keyboard_shortcuts_inhibitor_v1" - -// ZwpKeyboardShortcutsInhibitorV1 : context object for keyboard shortcuts inhibitor -// -// A keyboard shortcuts inhibitor instructs the compositor to ignore -// its own keyboard shortcuts when the associated surface has keyboard -// focus. As a result, when the surface has keyboard focus on the given -// seat, it will receive all key events originating from the specified -// seat, even those which would normally be caught by the compositor for -// its own shortcuts. -// -// The Wayland compositor is however under no obligation to disable -// all of its shortcuts, and may keep some special key combo for its own -// use, including but not limited to one allowing the user to forcibly -// restore normal keyboard events routing in the case of an unwilling -// client. The compositor may also use the same key combo to reactivate -// an existing shortcut inhibitor that was previously deactivated on -// user request. -// -// When the compositor restores its own keyboard shortcuts, an -// "inactive" event is emitted to notify the client that the keyboard -// shortcuts inhibitor is not effectively active for the surface and -// seat any more, and the client should not expect to receive all -// keyboard events. -// -// When the keyboard shortcuts inhibitor is inactive, the client has -// no way to forcibly reactivate the keyboard shortcuts inhibitor. -// -// The user can chose to re-enable a previously deactivated keyboard -// shortcuts inhibitor using any mechanism the compositor may offer, -// in which case the compositor will send an "active" event to notify -// the client. -// -// If the surface is destroyed, unmapped, or loses the seat's keyboard -// focus, the keyboard shortcuts inhibitor becomes irrelevant and the -// compositor will restore its own keyboard shortcuts but no "inactive" -// event is emitted in this case. -type ZwpKeyboardShortcutsInhibitorV1 struct { - client.BaseProxy - activeHandler ZwpKeyboardShortcutsInhibitorV1ActiveHandlerFunc - inactiveHandler ZwpKeyboardShortcutsInhibitorV1InactiveHandlerFunc -} - -// NewZwpKeyboardShortcutsInhibitorV1 : context object for keyboard shortcuts inhibitor -// -// A keyboard shortcuts inhibitor instructs the compositor to ignore -// its own keyboard shortcuts when the associated surface has keyboard -// focus. As a result, when the surface has keyboard focus on the given -// seat, it will receive all key events originating from the specified -// seat, even those which would normally be caught by the compositor for -// its own shortcuts. -// -// The Wayland compositor is however under no obligation to disable -// all of its shortcuts, and may keep some special key combo for its own -// use, including but not limited to one allowing the user to forcibly -// restore normal keyboard events routing in the case of an unwilling -// client. The compositor may also use the same key combo to reactivate -// an existing shortcut inhibitor that was previously deactivated on -// user request. -// -// When the compositor restores its own keyboard shortcuts, an -// "inactive" event is emitted to notify the client that the keyboard -// shortcuts inhibitor is not effectively active for the surface and -// seat any more, and the client should not expect to receive all -// keyboard events. -// -// When the keyboard shortcuts inhibitor is inactive, the client has -// no way to forcibly reactivate the keyboard shortcuts inhibitor. -// -// The user can chose to re-enable a previously deactivated keyboard -// shortcuts inhibitor using any mechanism the compositor may offer, -// in which case the compositor will send an "active" event to notify -// the client. -// -// If the surface is destroyed, unmapped, or loses the seat's keyboard -// focus, the keyboard shortcuts inhibitor becomes irrelevant and the -// compositor will restore its own keyboard shortcuts but no "inactive" -// event is emitted in this case. -func NewZwpKeyboardShortcutsInhibitorV1(ctx *client.Context) *ZwpKeyboardShortcutsInhibitorV1 { - zwpKeyboardShortcutsInhibitorV1 := &ZwpKeyboardShortcutsInhibitorV1{} - ctx.Register(zwpKeyboardShortcutsInhibitorV1) - return zwpKeyboardShortcutsInhibitorV1 -} - -// Destroy : destroy the keyboard shortcuts inhibitor object -// -// Remove the keyboard shortcuts inhibitor from the associated wl_surface. -func (i *ZwpKeyboardShortcutsInhibitorV1) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ZwpKeyboardShortcutsInhibitorV1ActiveEvent : shortcuts are inhibited -// -// This event indicates that the shortcut inhibitor is active. -// -// The compositor sends this event every time compositor shortcuts -// are inhibited on behalf of the surface. When active, the client -// may receive input events normally reserved by the compositor -// (see zwp_keyboard_shortcuts_inhibitor_v1). -// -// This occurs typically when the initial request "inhibit_shortcuts" -// first becomes active or when the user instructs the compositor to -// re-enable and existing shortcuts inhibitor using any mechanism -// offered by the compositor. -type ZwpKeyboardShortcutsInhibitorV1ActiveEvent struct{} -type ZwpKeyboardShortcutsInhibitorV1ActiveHandlerFunc func(ZwpKeyboardShortcutsInhibitorV1ActiveEvent) - -// SetActiveHandler : sets handler for ZwpKeyboardShortcutsInhibitorV1ActiveEvent -func (i *ZwpKeyboardShortcutsInhibitorV1) SetActiveHandler(f ZwpKeyboardShortcutsInhibitorV1ActiveHandlerFunc) { - i.activeHandler = f -} - -// ZwpKeyboardShortcutsInhibitorV1InactiveEvent : shortcuts are restored -// -// This event indicates that the shortcuts inhibitor is inactive, -// normal shortcuts processing is restored by the compositor. -type ZwpKeyboardShortcutsInhibitorV1InactiveEvent struct{} -type ZwpKeyboardShortcutsInhibitorV1InactiveHandlerFunc func(ZwpKeyboardShortcutsInhibitorV1InactiveEvent) - -// SetInactiveHandler : sets handler for ZwpKeyboardShortcutsInhibitorV1InactiveEvent -func (i *ZwpKeyboardShortcutsInhibitorV1) SetInactiveHandler(f ZwpKeyboardShortcutsInhibitorV1InactiveHandlerFunc) { - i.inactiveHandler = f -} - -func (i *ZwpKeyboardShortcutsInhibitorV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.activeHandler == nil { - return - } - var e ZwpKeyboardShortcutsInhibitorV1ActiveEvent - - i.activeHandler(e) - case 1: - if i.inactiveHandler == nil { - return - } - var e ZwpKeyboardShortcutsInhibitorV1InactiveEvent - - i.inactiveHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_gamma_control/gamma_control.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_gamma_control/gamma_control.go deleted file mode 100644 index a1cb429..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_gamma_control/gamma_control.go +++ /dev/null @@ -1,268 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/cmd/go-wayland-scanner -// XML file : wayland-protocols/wlr-gamma-control-unstable-v1.xml -// -// wlr_gamma_control_unstable_v1 Protocol Copyright: -// -// Copyright © 2015 Giulio camuffo -// Copyright © 2018 Simon Ser -// -// Permission to use, copy, modify, distribute, and sell this -// software and its documentation for any purpose is hereby granted -// without fee, provided that the above copyright notice appear in -// all copies and that both that copyright notice and this permission -// notice appear in supporting documentation, and that the name of -// the copyright holders not be used in advertising or publicity -// pertaining to distribution of the software without specific, -// written prior permission. The copyright holders make no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied -// warranty. -// -// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - -package wlr_gamma_control - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "golang.org/x/sys/unix" -) - -// ZwlrGammaControlManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrGammaControlManagerV1InterfaceName = "zwlr_gamma_control_manager_v1" - -// ZwlrGammaControlManagerV1 : manager to create per-output gamma controls -// -// This interface is a manager that allows creating per-output gamma -// controls. -type ZwlrGammaControlManagerV1 struct { - client.BaseProxy -} - -// NewZwlrGammaControlManagerV1 : manager to create per-output gamma controls -// -// This interface is a manager that allows creating per-output gamma -// controls. -func NewZwlrGammaControlManagerV1(ctx *client.Context) *ZwlrGammaControlManagerV1 { - zwlrGammaControlManagerV1 := &ZwlrGammaControlManagerV1{} - ctx.Register(zwlrGammaControlManagerV1) - return zwlrGammaControlManagerV1 -} - -// GetGammaControl : get a gamma control for an output -// -// Create a gamma control that can be used to adjust gamma tables for the -// provided output. -func (i *ZwlrGammaControlManagerV1) GetGammaControl(output *client.Output) (*ZwlrGammaControlV1, error) { - id := NewZwlrGammaControlV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// Destroy : destroy the manager -// -// All objects created by the manager will still remain valid, until their -// appropriate destroy request has been called. -func (i *ZwlrGammaControlManagerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ZwlrGammaControlV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrGammaControlV1InterfaceName = "zwlr_gamma_control_v1" - -// ZwlrGammaControlV1 : adjust gamma tables for an output -// -// This interface allows a client to adjust gamma tables for a particular -// output. -// -// The client will receive the gamma size, and will then be able to set gamma -// tables. At any time the compositor can send a failed event indicating that -// this object is no longer valid. -// -// There can only be at most one gamma control object per output, which -// has exclusive access to this particular output. When the gamma control -// object is destroyed, the gamma table is restored to its original value. -type ZwlrGammaControlV1 struct { - client.BaseProxy - gammaSizeHandler ZwlrGammaControlV1GammaSizeHandlerFunc - failedHandler ZwlrGammaControlV1FailedHandlerFunc -} - -// NewZwlrGammaControlV1 : adjust gamma tables for an output -// -// This interface allows a client to adjust gamma tables for a particular -// output. -// -// The client will receive the gamma size, and will then be able to set gamma -// tables. At any time the compositor can send a failed event indicating that -// this object is no longer valid. -// -// There can only be at most one gamma control object per output, which -// has exclusive access to this particular output. When the gamma control -// object is destroyed, the gamma table is restored to its original value. -func NewZwlrGammaControlV1(ctx *client.Context) *ZwlrGammaControlV1 { - zwlrGammaControlV1 := &ZwlrGammaControlV1{} - ctx.Register(zwlrGammaControlV1) - return zwlrGammaControlV1 -} - -// SetGamma : set the gamma table -// -// Set the gamma table. The file descriptor can be memory-mapped to provide -// the raw gamma table, which contains successive gamma ramps for the red, -// green and blue channels. Each gamma ramp is an array of 16-byte unsigned -// integers which has the same length as the gamma size. -// -// The file descriptor data must have the same length as three times the -// gamma size. -// -// fd: gamma table file descriptor -func (i *ZwlrGammaControlV1) SetGamma(fd int) error { - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - oob := unix.UnixRights(int(fd)) - err := i.Context().WriteMsg(_reqBuf[:], oob) - return err -} - -// Destroy : destroy this control -// -// Destroys the gamma control object. If the object is still valid, this -// restores the original gamma tables. -func (i *ZwlrGammaControlV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrGammaControlV1Error uint32 - -// ZwlrGammaControlV1Error : -const ( - // ZwlrGammaControlV1ErrorInvalidGamma : invalid gamma tables - ZwlrGammaControlV1ErrorInvalidGamma ZwlrGammaControlV1Error = 1 -) - -func (e ZwlrGammaControlV1Error) Name() string { - switch e { - case ZwlrGammaControlV1ErrorInvalidGamma: - return "invalid_gamma" - default: - return "" - } -} - -func (e ZwlrGammaControlV1Error) Value() string { - switch e { - case ZwlrGammaControlV1ErrorInvalidGamma: - return "1" - default: - return "" - } -} - -func (e ZwlrGammaControlV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrGammaControlV1GammaSizeEvent : size of gamma ramps -// -// Advertise the size of each gamma ramp. -// -// This event is sent immediately when the gamma control object is created. -type ZwlrGammaControlV1GammaSizeEvent struct { - Size uint32 -} -type ZwlrGammaControlV1GammaSizeHandlerFunc func(ZwlrGammaControlV1GammaSizeEvent) - -// SetGammaSizeHandler : sets handler for ZwlrGammaControlV1GammaSizeEvent -func (i *ZwlrGammaControlV1) SetGammaSizeHandler(f ZwlrGammaControlV1GammaSizeHandlerFunc) { - i.gammaSizeHandler = f -} - -// ZwlrGammaControlV1FailedEvent : object no longer valid -// -// This event indicates that the gamma control is no longer valid. This -// can happen for a number of reasons, including: -// - The output doesn't support gamma tables -// - Setting the gamma tables failed -// - Another client already has exclusive gamma control for this output -// - The compositor has transferred gamma control to another client -// -// Upon receiving this event, the client should destroy this object. -type ZwlrGammaControlV1FailedEvent struct{} -type ZwlrGammaControlV1FailedHandlerFunc func(ZwlrGammaControlV1FailedEvent) - -// SetFailedHandler : sets handler for ZwlrGammaControlV1FailedEvent -func (i *ZwlrGammaControlV1) SetFailedHandler(f ZwlrGammaControlV1FailedHandlerFunc) { - i.failedHandler = f -} - -func (i *ZwlrGammaControlV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.gammaSizeHandler == nil { - return - } - var e ZwlrGammaControlV1GammaSizeEvent - l := 0 - e.Size = client.Uint32(data[l : l+4]) - l += 4 - - i.gammaSizeHandler(e) - case 1: - if i.failedHandler == nil { - return - } - var e ZwlrGammaControlV1FailedEvent - - i.failedHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_layer_shell/layer_shell.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_layer_shell/layer_shell.go deleted file mode 100644 index 6fea165..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_layer_shell/layer_shell.go +++ /dev/null @@ -1,792 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/wlr-layer-shell-unstable-v1.xml -// -// wlr_layer_shell_unstable_v1 Protocol Copyright: -// -// Copyright © 2017 Drew DeVault -// -// Permission to use, copy, modify, distribute, and sell this -// software and its documentation for any purpose is hereby granted -// without fee, provided that the above copyright notice appear in -// all copies and that both that copyright notice and this permission -// notice appear in supporting documentation, and that the name of -// the copyright holders not be used in advertising or publicity -// pertaining to distribution of the software without specific, -// written prior permission. The copyright holders make no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied -// warranty. -// -// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - -package wlr_layer_shell - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - xdg_shell "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/stable/xdg-shell" -) - -// ZwlrLayerShellV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrLayerShellV1InterfaceName = "zwlr_layer_shell_v1" - -// ZwlrLayerShellV1 : create surfaces that are layers of the desktop -// -// Clients can use this interface to assign the surface_layer role to -// wl_surfaces. Such surfaces are assigned to a "layer" of the output and -// rendered with a defined z-depth respective to each other. They may also be -// anchored to the edges and corners of a screen and specify input handling -// semantics. This interface should be suitable for the implementation of -// many desktop shell components, and a broad number of other applications -// that interact with the desktop. -type ZwlrLayerShellV1 struct { - client.BaseProxy -} - -// NewZwlrLayerShellV1 : create surfaces that are layers of the desktop -// -// Clients can use this interface to assign the surface_layer role to -// wl_surfaces. Such surfaces are assigned to a "layer" of the output and -// rendered with a defined z-depth respective to each other. They may also be -// anchored to the edges and corners of a screen and specify input handling -// semantics. This interface should be suitable for the implementation of -// many desktop shell components, and a broad number of other applications -// that interact with the desktop. -func NewZwlrLayerShellV1(ctx *client.Context) *ZwlrLayerShellV1 { - zwlrLayerShellV1 := &ZwlrLayerShellV1{} - ctx.Register(zwlrLayerShellV1) - return zwlrLayerShellV1 -} - -// GetLayerSurface : create a layer_surface from a surface -// -// Create a layer surface for an existing surface. This assigns the role of -// layer_surface, or raises a protocol error if another role is already -// assigned. -// -// Creating a layer surface from a wl_surface which has a buffer attached -// or committed is a client error, and any attempts by a client to attach -// or manipulate a buffer prior to the first layer_surface.configure call -// must also be treated as errors. -// -// After creating a layer_surface object and setting it up, the client -// must perform an initial commit without any buffer attached. -// The compositor will reply with a layer_surface.configure event. -// The client must acknowledge it and is then allowed to attach a buffer -// to map the surface. -// -// You may pass NULL for output to allow the compositor to decide which -// output to use. Generally this will be the one that the user most -// recently interacted with. -// -// Clients can specify a namespace that defines the purpose of the layer -// surface. -// -// layer: layer to add this surface to -// namespace: namespace for the layer surface -func (i *ZwlrLayerShellV1) GetLayerSurface(surface *client.Surface, output *client.Output, layer uint32, namespace string) (*ZwlrLayerSurfaceV1, error) { - id := NewZwlrLayerSurfaceV1(i.Context()) - const opcode = 0 - namespaceLen := client.PaddedLen(len(namespace) + 1) - _reqBufLen := 8 + 4 + 4 + 4 + 4 + (4 + namespaceLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - if output == nil { - client.PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - } - client.PutUint32(_reqBuf[l:l+4], uint32(layer)) - l += 4 - client.PutString(_reqBuf[l:l+(4+namespaceLen)], namespace) - l += (4 + namespaceLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return id, err -} - -// Destroy : destroy the layer_shell object -// -// This request indicates that the client will not use the layer_shell -// object any more. Objects that have been created through this instance -// are not affected. -func (i *ZwlrLayerShellV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrLayerShellV1Error uint32 - -// ZwlrLayerShellV1Error : -const ( - // ZwlrLayerShellV1ErrorRole : wl_surface has another role - ZwlrLayerShellV1ErrorRole ZwlrLayerShellV1Error = 0 - // ZwlrLayerShellV1ErrorInvalidLayer : layer value is invalid - ZwlrLayerShellV1ErrorInvalidLayer ZwlrLayerShellV1Error = 1 - // ZwlrLayerShellV1ErrorAlreadyConstructed : wl_surface has a buffer attached or committed - ZwlrLayerShellV1ErrorAlreadyConstructed ZwlrLayerShellV1Error = 2 -) - -func (e ZwlrLayerShellV1Error) Name() string { - switch e { - case ZwlrLayerShellV1ErrorRole: - return "role" - case ZwlrLayerShellV1ErrorInvalidLayer: - return "invalid_layer" - case ZwlrLayerShellV1ErrorAlreadyConstructed: - return "already_constructed" - default: - return "" - } -} - -func (e ZwlrLayerShellV1Error) Value() string { - switch e { - case ZwlrLayerShellV1ErrorRole: - return "0" - case ZwlrLayerShellV1ErrorInvalidLayer: - return "1" - case ZwlrLayerShellV1ErrorAlreadyConstructed: - return "2" - default: - return "" - } -} - -func (e ZwlrLayerShellV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -type ZwlrLayerShellV1Layer uint32 - -// ZwlrLayerShellV1Layer : available layers for surfaces -// -// These values indicate which layers a surface can be rendered in. They -// are ordered by z depth, bottom-most first. Traditional shell surfaces -// will typically be rendered between the bottom and top layers. -// Fullscreen shell surfaces are typically rendered at the top layer. -// Multiple surfaces can share a single layer, and ordering within a -// single layer is undefined. -const ( - ZwlrLayerShellV1LayerBackground ZwlrLayerShellV1Layer = 0 - ZwlrLayerShellV1LayerBottom ZwlrLayerShellV1Layer = 1 - ZwlrLayerShellV1LayerTop ZwlrLayerShellV1Layer = 2 - ZwlrLayerShellV1LayerOverlay ZwlrLayerShellV1Layer = 3 -) - -func (e ZwlrLayerShellV1Layer) Name() string { - switch e { - case ZwlrLayerShellV1LayerBackground: - return "background" - case ZwlrLayerShellV1LayerBottom: - return "bottom" - case ZwlrLayerShellV1LayerTop: - return "top" - case ZwlrLayerShellV1LayerOverlay: - return "overlay" - default: - return "" - } -} - -func (e ZwlrLayerShellV1Layer) Value() string { - switch e { - case ZwlrLayerShellV1LayerBackground: - return "0" - case ZwlrLayerShellV1LayerBottom: - return "1" - case ZwlrLayerShellV1LayerTop: - return "2" - case ZwlrLayerShellV1LayerOverlay: - return "3" - default: - return "" - } -} - -func (e ZwlrLayerShellV1Layer) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrLayerSurfaceV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrLayerSurfaceV1InterfaceName = "zwlr_layer_surface_v1" - -// ZwlrLayerSurfaceV1 : layer metadata interface -// -// An interface that may be implemented by a wl_surface, for surfaces that -// are designed to be rendered as a layer of a stacked desktop-like -// environment. -// -// Layer surface state (layer, size, anchor, exclusive zone, -// margin, interactivity) is double-buffered, and will be applied at the -// time wl_surface.commit of the corresponding wl_surface is called. -// -// Attaching a null buffer to a layer surface unmaps it. -// -// Unmapping a layer_surface means that the surface cannot be shown by the -// compositor until it is explicitly mapped again. The layer_surface -// returns to the state it had right after layer_shell.get_layer_surface. -// The client can re-map the surface by performing a commit without any -// buffer attached, waiting for a configure event and handling it as usual. -type ZwlrLayerSurfaceV1 struct { - client.BaseProxy - configureHandler ZwlrLayerSurfaceV1ConfigureHandlerFunc - closedHandler ZwlrLayerSurfaceV1ClosedHandlerFunc -} - -// NewZwlrLayerSurfaceV1 : layer metadata interface -// -// An interface that may be implemented by a wl_surface, for surfaces that -// are designed to be rendered as a layer of a stacked desktop-like -// environment. -// -// Layer surface state (layer, size, anchor, exclusive zone, -// margin, interactivity) is double-buffered, and will be applied at the -// time wl_surface.commit of the corresponding wl_surface is called. -// -// Attaching a null buffer to a layer surface unmaps it. -// -// Unmapping a layer_surface means that the surface cannot be shown by the -// compositor until it is explicitly mapped again. The layer_surface -// returns to the state it had right after layer_shell.get_layer_surface. -// The client can re-map the surface by performing a commit without any -// buffer attached, waiting for a configure event and handling it as usual. -func NewZwlrLayerSurfaceV1(ctx *client.Context) *ZwlrLayerSurfaceV1 { - zwlrLayerSurfaceV1 := &ZwlrLayerSurfaceV1{} - ctx.Register(zwlrLayerSurfaceV1) - return zwlrLayerSurfaceV1 -} - -// SetSize : sets the size of the surface -// -// Sets the size of the surface in surface-local coordinates. The -// compositor will display the surface centered with respect to its -// anchors. -// -// If you pass 0 for either value, the compositor will assign it and -// inform you of the assignment in the configure event. You must set your -// anchor to opposite edges in the dimensions you omit; not doing so is a -// protocol error. Both values are 0 by default. -// -// Size is double-buffered, see wl_surface.commit. -func (i *ZwlrLayerSurfaceV1) SetSize(width, height uint32) error { - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetAnchor : configures the anchor point of the surface -// -// Requests that the compositor anchor the surface to the specified edges -// and corners. If two orthogonal edges are specified (e.g. 'top' and -// 'left'), then the anchor point will be the intersection of the edges -// (e.g. the top left corner of the output); otherwise the anchor point -// will be centered on that edge, or in the center if none is specified. -// -// Anchor is double-buffered, see wl_surface.commit. -func (i *ZwlrLayerSurfaceV1) SetAnchor(anchor uint32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(anchor)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetExclusiveZone : configures the exclusive geometry of this surface -// -// Requests that the compositor avoids occluding an area with other -// surfaces. The compositor's use of this information is -// implementation-dependent - do not assume that this region will not -// actually be occluded. -// -// A positive value is only meaningful if the surface is anchored to one -// edge or an edge and both perpendicular edges. If the surface is not -// anchored, anchored to only two perpendicular edges (a corner), anchored -// to only two parallel edges or anchored to all edges, a positive value -// will be treated the same as zero. -// -// A positive zone is the distance from the edge in surface-local -// coordinates to consider exclusive. -// -// Surfaces that do not wish to have an exclusive zone may instead specify -// how they should interact with surfaces that do. If set to zero, the -// surface indicates that it would like to be moved to avoid occluding -// surfaces with a positive exclusive zone. If set to -1, the surface -// indicates that it would not like to be moved to accommodate for other -// surfaces, and the compositor should extend it all the way to the edges -// it is anchored to. -// -// For example, a panel might set its exclusive zone to 10, so that -// maximized shell surfaces are not shown on top of it. A notification -// might set its exclusive zone to 0, so that it is moved to avoid -// occluding the panel, but shell surfaces are shown underneath it. A -// wallpaper or lock screen might set their exclusive zone to -1, so that -// they stretch below or over the panel. -// -// The default value is 0. -// -// Exclusive zone is double-buffered, see wl_surface.commit. -func (i *ZwlrLayerSurfaceV1) SetExclusiveZone(zone int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(zone)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetMargin : sets a margin from the anchor point -// -// Requests that the surface be placed some distance away from the anchor -// point on the output, in surface-local coordinates. Setting this value -// for edges you are not anchored to has no effect. -// -// The exclusive zone includes the margin. -// -// Margin is double-buffered, see wl_surface.commit. -func (i *ZwlrLayerSurfaceV1) SetMargin(top, right, bottom, left int32) error { - const opcode = 3 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(top)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(right)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(bottom)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(left)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetKeyboardInteractivity : requests keyboard events -// -// Set how keyboard events are delivered to this surface. By default, -// layer shell surfaces do not receive keyboard events; this request can -// be used to change this. -// -// This setting is inherited by child surfaces set by the get_popup -// request. -// -// Layer surfaces receive pointer, touch, and tablet events normally. If -// you do not want to receive them, set the input region on your surface -// to an empty region. -// -// Keyboard interactivity is double-buffered, see wl_surface.commit. -func (i *ZwlrLayerSurfaceV1) SetKeyboardInteractivity(keyboardInteractivity uint32) error { - const opcode = 4 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(keyboardInteractivity)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// GetPopup : assign this layer_surface as an xdg_popup parent -// -// This assigns an xdg_popup's parent to this layer_surface. This popup -// should have been created via xdg_surface::get_popup with the parent set -// to NULL, and this request must be invoked before committing the popup's -// initial state. -// -// See the documentation of xdg_popup for more details about what an -// xdg_popup is and how it is used. -func (i *ZwlrLayerSurfaceV1) GetPopup(popup *xdg_shell.Popup) error { - const opcode = 5 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], popup.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// AckConfigure : ack a configure event -// -// When a configure event is received, if a client commits the -// surface in response to the configure event, then the client -// must make an ack_configure request sometime before the commit -// request, passing along the serial of the configure event. -// -// If the client receives multiple configure events before it -// can respond to one, it only has to ack the last configure event. -// -// A client is not required to commit immediately after sending -// an ack_configure request - it may even ack_configure several times -// before its next surface commit. -// -// A client may send multiple ack_configure requests before committing, but -// only the last request sent before a commit indicates which configure -// event the client really is responding to. -// -// serial: the serial from the configure event -func (i *ZwlrLayerSurfaceV1) AckConfigure(serial uint32) error { - const opcode = 6 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Destroy : destroy the layer_surface -// -// This request destroys the layer surface. -func (i *ZwlrLayerSurfaceV1) Destroy() error { - defer i.MarkZombie() - const opcode = 7 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetLayer : change the layer of the surface -// -// Change the layer that the surface is rendered on. -// -// Layer is double-buffered, see wl_surface.commit. -// -// layer: layer to move this surface to -func (i *ZwlrLayerSurfaceV1) SetLayer(layer uint32) error { - const opcode = 8 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(layer)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetExclusiveEdge : set the edge the exclusive zone will be applied to -// -// Requests an edge for the exclusive zone to apply. The exclusive -// edge will be automatically deduced from anchor points when possible, -// but when the surface is anchored to a corner, it will be necessary -// to set it explicitly to disambiguate, as it is not possible to deduce -// which one of the two corner edges should be used. -// -// The edge must be one the surface is anchored to, otherwise the -// invalid_exclusive_edge protocol error will be raised. -func (i *ZwlrLayerSurfaceV1) SetExclusiveEdge(edge uint32) error { - const opcode = 9 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(edge)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrLayerSurfaceV1KeyboardInteractivity uint32 - -// ZwlrLayerSurfaceV1KeyboardInteractivity : types of keyboard interaction possible for a layer shell surface -// -// Types of keyboard interaction possible for layer shell surfaces. The -// rationale for this is twofold: (1) some applications are not interested -// in keyboard events and not allowing them to be focused can improve the -// desktop experience; (2) some applications will want to take exclusive -// keyboard focus. -const ( - ZwlrLayerSurfaceV1KeyboardInteractivityNone ZwlrLayerSurfaceV1KeyboardInteractivity = 0 - ZwlrLayerSurfaceV1KeyboardInteractivityExclusive ZwlrLayerSurfaceV1KeyboardInteractivity = 1 - ZwlrLayerSurfaceV1KeyboardInteractivityOnDemand ZwlrLayerSurfaceV1KeyboardInteractivity = 2 -) - -func (e ZwlrLayerSurfaceV1KeyboardInteractivity) Name() string { - switch e { - case ZwlrLayerSurfaceV1KeyboardInteractivityNone: - return "none" - case ZwlrLayerSurfaceV1KeyboardInteractivityExclusive: - return "exclusive" - case ZwlrLayerSurfaceV1KeyboardInteractivityOnDemand: - return "on_demand" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1KeyboardInteractivity) Value() string { - switch e { - case ZwlrLayerSurfaceV1KeyboardInteractivityNone: - return "0" - case ZwlrLayerSurfaceV1KeyboardInteractivityExclusive: - return "1" - case ZwlrLayerSurfaceV1KeyboardInteractivityOnDemand: - return "2" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1KeyboardInteractivity) String() string { - return e.Name() + "=" + e.Value() -} - -type ZwlrLayerSurfaceV1Error uint32 - -// ZwlrLayerSurfaceV1Error : -const ( - // ZwlrLayerSurfaceV1ErrorInvalidSurfaceState : provided surface state is invalid - ZwlrLayerSurfaceV1ErrorInvalidSurfaceState ZwlrLayerSurfaceV1Error = 0 - // ZwlrLayerSurfaceV1ErrorInvalidSize : size is invalid - ZwlrLayerSurfaceV1ErrorInvalidSize ZwlrLayerSurfaceV1Error = 1 - // ZwlrLayerSurfaceV1ErrorInvalidAnchor : anchor bitfield is invalid - ZwlrLayerSurfaceV1ErrorInvalidAnchor ZwlrLayerSurfaceV1Error = 2 - // ZwlrLayerSurfaceV1ErrorInvalidKeyboardInteractivity : keyboard interactivity is invalid - ZwlrLayerSurfaceV1ErrorInvalidKeyboardInteractivity ZwlrLayerSurfaceV1Error = 3 - // ZwlrLayerSurfaceV1ErrorInvalidExclusiveEdge : exclusive edge is invalid given the surface anchors - ZwlrLayerSurfaceV1ErrorInvalidExclusiveEdge ZwlrLayerSurfaceV1Error = 4 -) - -func (e ZwlrLayerSurfaceV1Error) Name() string { - switch e { - case ZwlrLayerSurfaceV1ErrorInvalidSurfaceState: - return "invalid_surface_state" - case ZwlrLayerSurfaceV1ErrorInvalidSize: - return "invalid_size" - case ZwlrLayerSurfaceV1ErrorInvalidAnchor: - return "invalid_anchor" - case ZwlrLayerSurfaceV1ErrorInvalidKeyboardInteractivity: - return "invalid_keyboard_interactivity" - case ZwlrLayerSurfaceV1ErrorInvalidExclusiveEdge: - return "invalid_exclusive_edge" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1Error) Value() string { - switch e { - case ZwlrLayerSurfaceV1ErrorInvalidSurfaceState: - return "0" - case ZwlrLayerSurfaceV1ErrorInvalidSize: - return "1" - case ZwlrLayerSurfaceV1ErrorInvalidAnchor: - return "2" - case ZwlrLayerSurfaceV1ErrorInvalidKeyboardInteractivity: - return "3" - case ZwlrLayerSurfaceV1ErrorInvalidExclusiveEdge: - return "4" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -type ZwlrLayerSurfaceV1Anchor uint32 - -// ZwlrLayerSurfaceV1Anchor : -const ( - // ZwlrLayerSurfaceV1AnchorTop : the top edge of the anchor rectangle - ZwlrLayerSurfaceV1AnchorTop ZwlrLayerSurfaceV1Anchor = 1 - // ZwlrLayerSurfaceV1AnchorBottom : the bottom edge of the anchor rectangle - ZwlrLayerSurfaceV1AnchorBottom ZwlrLayerSurfaceV1Anchor = 2 - // ZwlrLayerSurfaceV1AnchorLeft : the left edge of the anchor rectangle - ZwlrLayerSurfaceV1AnchorLeft ZwlrLayerSurfaceV1Anchor = 4 - // ZwlrLayerSurfaceV1AnchorRight : the right edge of the anchor rectangle - ZwlrLayerSurfaceV1AnchorRight ZwlrLayerSurfaceV1Anchor = 8 -) - -func (e ZwlrLayerSurfaceV1Anchor) Name() string { - switch e { - case ZwlrLayerSurfaceV1AnchorTop: - return "top" - case ZwlrLayerSurfaceV1AnchorBottom: - return "bottom" - case ZwlrLayerSurfaceV1AnchorLeft: - return "left" - case ZwlrLayerSurfaceV1AnchorRight: - return "right" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1Anchor) Value() string { - switch e { - case ZwlrLayerSurfaceV1AnchorTop: - return "1" - case ZwlrLayerSurfaceV1AnchorBottom: - return "2" - case ZwlrLayerSurfaceV1AnchorLeft: - return "4" - case ZwlrLayerSurfaceV1AnchorRight: - return "8" - default: - return "" - } -} - -func (e ZwlrLayerSurfaceV1Anchor) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrLayerSurfaceV1ConfigureEvent : suggest a surface change -// -// The configure event asks the client to resize its surface. -// -// Clients should arrange their surface for the new states, and then send -// an ack_configure request with the serial sent in this configure event at -// some point before committing the new surface. -// -// The client is free to dismiss all but the last configure event it -// received. -// -// The width and height arguments specify the size of the window in -// surface-local coordinates. -// -// The size is a hint, in the sense that the client is free to ignore it if -// it doesn't resize, pick a smaller size (to satisfy aspect ratio or -// resize in steps of NxM pixels). If the client picks a smaller size and -// is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the -// surface will be centered on this axis. -// -// If the width or height arguments are zero, it means the client should -// decide its own window dimension. -type ZwlrLayerSurfaceV1ConfigureEvent struct { - Serial uint32 - Width uint32 - Height uint32 -} -type ZwlrLayerSurfaceV1ConfigureHandlerFunc func(ZwlrLayerSurfaceV1ConfigureEvent) - -// SetConfigureHandler : sets handler for ZwlrLayerSurfaceV1ConfigureEvent -func (i *ZwlrLayerSurfaceV1) SetConfigureHandler(f ZwlrLayerSurfaceV1ConfigureHandlerFunc) { - i.configureHandler = f -} - -// ZwlrLayerSurfaceV1ClosedEvent : surface should be closed -// -// The closed event is sent by the compositor when the surface will no -// longer be shown. The output may have been destroyed or the user may -// have asked for it to be removed. Further changes to the surface will be -// ignored. The client should destroy the resource after receiving this -// event, and create a new surface if they so choose. -type ZwlrLayerSurfaceV1ClosedEvent struct{} -type ZwlrLayerSurfaceV1ClosedHandlerFunc func(ZwlrLayerSurfaceV1ClosedEvent) - -// SetClosedHandler : sets handler for ZwlrLayerSurfaceV1ClosedEvent -func (i *ZwlrLayerSurfaceV1) SetClosedHandler(f ZwlrLayerSurfaceV1ClosedHandlerFunc) { - i.closedHandler = f -} - -func (i *ZwlrLayerSurfaceV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.configureHandler == nil { - return - } - var e ZwlrLayerSurfaceV1ConfigureEvent - l := 0 - e.Serial = client.Uint32(data[l : l+4]) - l += 4 - e.Width = client.Uint32(data[l : l+4]) - l += 4 - e.Height = client.Uint32(data[l : l+4]) - l += 4 - - i.configureHandler(e) - case 1: - if i.closedHandler == nil { - return - } - var e ZwlrLayerSurfaceV1ClosedEvent - - i.closedHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_management/output_management.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_management/output_management.go deleted file mode 100644 index 23f934f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_management/output_management.go +++ /dev/null @@ -1,1515 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/cmd/go-wayland-scanner -// XML file : /home/brandon/repos/dankdots/wlr-output-management-unstable-v1.xml -// -// wlr_output_management_unstable_v1 Protocol Copyright: -// -// Copyright © 2019 Purism SPC -// -// Permission to use, copy, modify, distribute, and sell this -// software and its documentation for any purpose is hereby granted -// without fee, provided that the above copyright notice appear in -// all copies and that both that copyright notice and this permission -// notice appear in supporting documentation, and that the name of -// the copyright holders not be used in advertising or publicity -// pertaining to distribution of the software without specific, -// written prior permission. The copyright holders make no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied -// warranty. -// -// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - -package wlr_output_management - -import ( - "reflect" - "unsafe" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -func registerServerProxy(ctx *client.Context, proxy client.Proxy, serverID uint32) { - defer func() { - if r := recover(); r != nil { - return - } - }() - ctxVal := reflect.ValueOf(ctx).Elem() - objectsField := ctxVal.FieldByName("objects") - if !objectsField.IsValid() { - return - } - objectsMapPtr := unsafe.Pointer(objectsField.UnsafeAddr()) - objectsMap := (*syncmap.Map[uint32, client.Proxy])(objectsMapPtr) - objectsMap.Store(serverID, proxy) -} - -// ZwlrOutputManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputManagerV1InterfaceName = "zwlr_output_manager_v1" - -// ZwlrOutputManagerV1 : output device configuration manager -// -// This interface is a manager that allows reading and writing the current -// output device configuration. -// -// Output devices that display pixels (e.g. a physical monitor or a virtual -// output in a window) are represented as heads. Heads cannot be created nor -// destroyed by the client, but they can be enabled or disabled and their -// properties can be changed. Each head may have one or more available modes. -// -// Whenever a head appears (e.g. a monitor is plugged in), it will be -// advertised via the head event. Immediately after the output manager is -// bound, all current heads are advertised. -// -// Whenever a head's properties change, the relevant wlr_output_head events -// will be sent. Not all head properties will be sent: only properties that -// have changed need to. -// -// Whenever a head disappears (e.g. a monitor is unplugged), a -// wlr_output_head.finished event will be sent. -// -// After one or more heads appear, change or disappear, the done event will -// be sent. It carries a serial which can be used in a create_configuration -// request to update heads properties. -// -// The information obtained from this protocol should only be used for output -// configuration purposes. This protocol is not designed to be a generic -// output property advertisement protocol for regular clients. Instead, -// protocols such as xdg-output should be used. -type ZwlrOutputManagerV1 struct { - client.BaseProxy - headHandler ZwlrOutputManagerV1HeadHandlerFunc - doneHandler ZwlrOutputManagerV1DoneHandlerFunc - finishedHandler ZwlrOutputManagerV1FinishedHandlerFunc -} - -// NewZwlrOutputManagerV1 : output device configuration manager -// -// This interface is a manager that allows reading and writing the current -// output device configuration. -// -// Output devices that display pixels (e.g. a physical monitor or a virtual -// output in a window) are represented as heads. Heads cannot be created nor -// destroyed by the client, but they can be enabled or disabled and their -// properties can be changed. Each head may have one or more available modes. -// -// Whenever a head appears (e.g. a monitor is plugged in), it will be -// advertised via the head event. Immediately after the output manager is -// bound, all current heads are advertised. -// -// Whenever a head's properties change, the relevant wlr_output_head events -// will be sent. Not all head properties will be sent: only properties that -// have changed need to. -// -// Whenever a head disappears (e.g. a monitor is unplugged), a -// wlr_output_head.finished event will be sent. -// -// After one or more heads appear, change or disappear, the done event will -// be sent. It carries a serial which can be used in a create_configuration -// request to update heads properties. -// -// The information obtained from this protocol should only be used for output -// configuration purposes. This protocol is not designed to be a generic -// output property advertisement protocol for regular clients. Instead, -// protocols such as xdg-output should be used. -func NewZwlrOutputManagerV1(ctx *client.Context) *ZwlrOutputManagerV1 { - zwlrOutputManagerV1 := &ZwlrOutputManagerV1{} - ctx.Register(zwlrOutputManagerV1) - return zwlrOutputManagerV1 -} - -// CreateConfiguration : create a new output configuration object -// -// Create a new output configuration object. This allows to update head -// properties. -func (i *ZwlrOutputManagerV1) CreateConfiguration(serial uint32) (*ZwlrOutputConfigurationV1, error) { - id := NewZwlrOutputConfigurationV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// Stop : stop sending events -// -// Indicates the client no longer wishes to receive events for output -// configuration changes. However the compositor may emit further events, -// until the finished event is emitted. -// -// The client must not send any more requests after this one. -func (i *ZwlrOutputManagerV1) Stop() error { - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -func (i *ZwlrOutputManagerV1) Destroy() error { - i.MarkZombie() - return nil -} - -// ZwlrOutputManagerV1HeadEvent : introduce a new head -// -// This event introduces a new head. This happens whenever a new head -// appears (e.g. a monitor is plugged in) or after the output manager is -// bound. -type ZwlrOutputManagerV1HeadEvent struct { - Head *ZwlrOutputHeadV1 -} -type ZwlrOutputManagerV1HeadHandlerFunc func(ZwlrOutputManagerV1HeadEvent) - -// SetHeadHandler : sets handler for ZwlrOutputManagerV1HeadEvent -func (i *ZwlrOutputManagerV1) SetHeadHandler(f ZwlrOutputManagerV1HeadHandlerFunc) { - i.headHandler = f -} - -// ZwlrOutputManagerV1DoneEvent : sent all information about current configuration -// -// This event is sent after all information has been sent after binding to -// the output manager object and after any subsequent changes. This applies -// to child head and mode objects as well. In other words, this event is -// sent whenever a head or mode is created or destroyed and whenever one of -// their properties has been changed. Not all state is re-sent each time -// the current configuration changes: only the actual changes are sent. -// -// This allows changes to the output configuration to be seen as atomic, -// even if they happen via multiple events. -// -// A serial is sent to be used in a future create_configuration request. -type ZwlrOutputManagerV1DoneEvent struct { - Serial uint32 -} -type ZwlrOutputManagerV1DoneHandlerFunc func(ZwlrOutputManagerV1DoneEvent) - -// SetDoneHandler : sets handler for ZwlrOutputManagerV1DoneEvent -func (i *ZwlrOutputManagerV1) SetDoneHandler(f ZwlrOutputManagerV1DoneHandlerFunc) { - i.doneHandler = f -} - -// ZwlrOutputManagerV1FinishedEvent : the compositor has finished with the manager -// -// This event indicates that the compositor is done sending manager events. -// The compositor will destroy the object immediately after sending this -// event, so it will become invalid and the client should release any -// resources associated with it. -type ZwlrOutputManagerV1FinishedEvent struct{} -type ZwlrOutputManagerV1FinishedHandlerFunc func(ZwlrOutputManagerV1FinishedEvent) - -// SetFinishedHandler : sets handler for ZwlrOutputManagerV1FinishedEvent -func (i *ZwlrOutputManagerV1) SetFinishedHandler(f ZwlrOutputManagerV1FinishedHandlerFunc) { - i.finishedHandler = f -} - -func (i *ZwlrOutputManagerV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.headHandler == nil { - return - } - var e ZwlrOutputManagerV1HeadEvent - l := 0 - objectID := client.Uint32(data[l : l+4]) - proxy := i.Context().GetProxy(objectID) - if proxy == nil || proxy.IsZombie() { - head := &ZwlrOutputHeadV1{} - head.SetContext(i.Context()) - head.SetID(objectID) - registerServerProxy(i.Context(), head, objectID) - e.Head = head - } else if head, ok := proxy.(*ZwlrOutputHeadV1); ok { - e.Head = head - } else { - // Stale proxy of wrong type (can happen after suspend/resume) - // Replace it with the correct type - head := &ZwlrOutputHeadV1{} - head.SetContext(i.Context()) - head.SetID(objectID) - registerServerProxy(i.Context(), head, objectID) - e.Head = head - } - l += 4 - - i.headHandler(e) - case 1: - if i.doneHandler == nil { - return - } - var e ZwlrOutputManagerV1DoneEvent - l := 0 - e.Serial = client.Uint32(data[l : l+4]) - l += 4 - - i.doneHandler(e) - case 2: - if i.finishedHandler == nil { - return - } - var e ZwlrOutputManagerV1FinishedEvent - - i.finishedHandler(e) - } -} - -// ZwlrOutputHeadV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputHeadV1InterfaceName = "zwlr_output_head_v1" - -// ZwlrOutputHeadV1 : output device -// -// A head is an output device. The difference between a wl_output object and -// a head is that heads are advertised even if they are turned off. A head -// object only advertises properties and cannot be used directly to change -// them. -// -// A head has some read-only properties: modes, name, description and -// physical_size. These cannot be changed by clients. -// -// Other properties can be updated via a wlr_output_configuration object. -// -// Properties sent via this interface are applied atomically via the -// wlr_output_manager.done event. No guarantees are made regarding the order -// in which properties are sent. -type ZwlrOutputHeadV1 struct { - client.BaseProxy - nameHandler ZwlrOutputHeadV1NameHandlerFunc - descriptionHandler ZwlrOutputHeadV1DescriptionHandlerFunc - physicalSizeHandler ZwlrOutputHeadV1PhysicalSizeHandlerFunc - modeHandler ZwlrOutputHeadV1ModeHandlerFunc - enabledHandler ZwlrOutputHeadV1EnabledHandlerFunc - currentModeHandler ZwlrOutputHeadV1CurrentModeHandlerFunc - positionHandler ZwlrOutputHeadV1PositionHandlerFunc - transformHandler ZwlrOutputHeadV1TransformHandlerFunc - scaleHandler ZwlrOutputHeadV1ScaleHandlerFunc - finishedHandler ZwlrOutputHeadV1FinishedHandlerFunc - makeHandler ZwlrOutputHeadV1MakeHandlerFunc - modelHandler ZwlrOutputHeadV1ModelHandlerFunc - serialNumberHandler ZwlrOutputHeadV1SerialNumberHandlerFunc - adaptiveSyncHandler ZwlrOutputHeadV1AdaptiveSyncHandlerFunc -} - -// NewZwlrOutputHeadV1 : output device -// -// A head is an output device. The difference between a wl_output object and -// a head is that heads are advertised even if they are turned off. A head -// object only advertises properties and cannot be used directly to change -// them. -// -// A head has some read-only properties: modes, name, description and -// physical_size. These cannot be changed by clients. -// -// Other properties can be updated via a wlr_output_configuration object. -// -// Properties sent via this interface are applied atomically via the -// wlr_output_manager.done event. No guarantees are made regarding the order -// in which properties are sent. -func NewZwlrOutputHeadV1(ctx *client.Context) *ZwlrOutputHeadV1 { - zwlrOutputHeadV1 := &ZwlrOutputHeadV1{} - ctx.Register(zwlrOutputHeadV1) - return zwlrOutputHeadV1 -} - -// Release : destroy the head object -// -// This request indicates that the client will no longer use this head -// object. -func (i *ZwlrOutputHeadV1) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrOutputHeadV1AdaptiveSyncState uint32 - -// ZwlrOutputHeadV1AdaptiveSyncState : -const ( - // ZwlrOutputHeadV1AdaptiveSyncStateDisabled : adaptive sync is disabled - ZwlrOutputHeadV1AdaptiveSyncStateDisabled ZwlrOutputHeadV1AdaptiveSyncState = 0 - // ZwlrOutputHeadV1AdaptiveSyncStateEnabled : adaptive sync is enabled - ZwlrOutputHeadV1AdaptiveSyncStateEnabled ZwlrOutputHeadV1AdaptiveSyncState = 1 -) - -func (e ZwlrOutputHeadV1AdaptiveSyncState) Name() string { - switch e { - case ZwlrOutputHeadV1AdaptiveSyncStateDisabled: - return "disabled" - case ZwlrOutputHeadV1AdaptiveSyncStateEnabled: - return "enabled" - default: - return "" - } -} - -func (e ZwlrOutputHeadV1AdaptiveSyncState) Value() string { - switch e { - case ZwlrOutputHeadV1AdaptiveSyncStateDisabled: - return "0" - case ZwlrOutputHeadV1AdaptiveSyncStateEnabled: - return "1" - default: - return "" - } -} - -func (e ZwlrOutputHeadV1AdaptiveSyncState) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrOutputHeadV1NameEvent : head name -// -// This event describes the head name. -// -// The naming convention is compositor defined, but limited to alphanumeric -// characters and dashes (-). Each name is unique among all wlr_output_head -// objects, but if a wlr_output_head object is destroyed the same name may -// be reused later. The names will also remain consistent across sessions -// with the same hardware and software configuration. -// -// Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do -// not assume that the name is a reflection of an underlying DRM -// connector, X11 connection, etc. -// -// If this head matches a wl_output, the wl_output.name event must report -// the same name. -// -// The name event is sent after a wlr_output_head object is created. This -// event is only sent once per object, and the name does not change over -// the lifetime of the wlr_output_head object. -type ZwlrOutputHeadV1NameEvent struct { - Name string -} -type ZwlrOutputHeadV1NameHandlerFunc func(ZwlrOutputHeadV1NameEvent) - -// SetNameHandler : sets handler for ZwlrOutputHeadV1NameEvent -func (i *ZwlrOutputHeadV1) SetNameHandler(f ZwlrOutputHeadV1NameHandlerFunc) { - i.nameHandler = f -} - -// ZwlrOutputHeadV1DescriptionEvent : head description -// -// This event describes a human-readable description of the head. -// -// The description is a UTF-8 string with no convention defined for its -// contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11 -// output via :1'. However, do not assume that the name is a reflection of -// the make, model, serial of the underlying DRM connector or the display -// name of the underlying X11 connection, etc. -// -// If this head matches a wl_output, the wl_output.description event must -// report the same name. -// -// The description event is sent after a wlr_output_head object is created. -// This event is only sent once per object, and the description does not -// change over the lifetime of the wlr_output_head object. -type ZwlrOutputHeadV1DescriptionEvent struct { - Description string -} -type ZwlrOutputHeadV1DescriptionHandlerFunc func(ZwlrOutputHeadV1DescriptionEvent) - -// SetDescriptionHandler : sets handler for ZwlrOutputHeadV1DescriptionEvent -func (i *ZwlrOutputHeadV1) SetDescriptionHandler(f ZwlrOutputHeadV1DescriptionHandlerFunc) { - i.descriptionHandler = f -} - -// ZwlrOutputHeadV1PhysicalSizeEvent : head physical size -// -// This event describes the physical size of the head. This event is only -// sent if the head has a physical size (e.g. is not a projector or a -// virtual device). -// -// The physical size event is sent after a wlr_output_head object is created. This -// event is only sent once per object, and the physical size does not change over -// the lifetime of the wlr_output_head object. -type ZwlrOutputHeadV1PhysicalSizeEvent struct { - Width int32 - Height int32 -} -type ZwlrOutputHeadV1PhysicalSizeHandlerFunc func(ZwlrOutputHeadV1PhysicalSizeEvent) - -// SetPhysicalSizeHandler : sets handler for ZwlrOutputHeadV1PhysicalSizeEvent -func (i *ZwlrOutputHeadV1) SetPhysicalSizeHandler(f ZwlrOutputHeadV1PhysicalSizeHandlerFunc) { - i.physicalSizeHandler = f -} - -// ZwlrOutputHeadV1ModeEvent : introduce a mode -// -// This event introduces a mode for this head. It is sent once per -// supported mode. -type ZwlrOutputHeadV1ModeEvent struct { - Mode *ZwlrOutputModeV1 -} -type ZwlrOutputHeadV1ModeHandlerFunc func(ZwlrOutputHeadV1ModeEvent) - -// SetModeHandler : sets handler for ZwlrOutputHeadV1ModeEvent -func (i *ZwlrOutputHeadV1) SetModeHandler(f ZwlrOutputHeadV1ModeHandlerFunc) { - i.modeHandler = f -} - -// ZwlrOutputHeadV1EnabledEvent : head is enabled or disabled -// -// This event describes whether the head is enabled. A disabled head is not -// mapped to a region of the global compositor space. -// -// When a head is disabled, some properties (current_mode, position, -// transform and scale) are irrelevant. -type ZwlrOutputHeadV1EnabledEvent struct { - Enabled int32 -} -type ZwlrOutputHeadV1EnabledHandlerFunc func(ZwlrOutputHeadV1EnabledEvent) - -// SetEnabledHandler : sets handler for ZwlrOutputHeadV1EnabledEvent -func (i *ZwlrOutputHeadV1) SetEnabledHandler(f ZwlrOutputHeadV1EnabledHandlerFunc) { - i.enabledHandler = f -} - -// ZwlrOutputHeadV1CurrentModeEvent : current mode -// -// This event describes the mode currently in use for this head. It is only -// sent if the output is enabled. -type ZwlrOutputHeadV1CurrentModeEvent struct { - Mode *ZwlrOutputModeV1 -} -type ZwlrOutputHeadV1CurrentModeHandlerFunc func(ZwlrOutputHeadV1CurrentModeEvent) - -// SetCurrentModeHandler : sets handler for ZwlrOutputHeadV1CurrentModeEvent -func (i *ZwlrOutputHeadV1) SetCurrentModeHandler(f ZwlrOutputHeadV1CurrentModeHandlerFunc) { - i.currentModeHandler = f -} - -// ZwlrOutputHeadV1PositionEvent : current position -// -// This events describes the position of the head in the global compositor -// space. It is only sent if the output is enabled. -type ZwlrOutputHeadV1PositionEvent struct { - X int32 - Y int32 -} -type ZwlrOutputHeadV1PositionHandlerFunc func(ZwlrOutputHeadV1PositionEvent) - -// SetPositionHandler : sets handler for ZwlrOutputHeadV1PositionEvent -func (i *ZwlrOutputHeadV1) SetPositionHandler(f ZwlrOutputHeadV1PositionHandlerFunc) { - i.positionHandler = f -} - -// ZwlrOutputHeadV1TransformEvent : current transformation -// -// This event describes the transformation currently applied to the head. -// It is only sent if the output is enabled. -type ZwlrOutputHeadV1TransformEvent struct { - Transform int32 -} -type ZwlrOutputHeadV1TransformHandlerFunc func(ZwlrOutputHeadV1TransformEvent) - -// SetTransformHandler : sets handler for ZwlrOutputHeadV1TransformEvent -func (i *ZwlrOutputHeadV1) SetTransformHandler(f ZwlrOutputHeadV1TransformHandlerFunc) { - i.transformHandler = f -} - -// ZwlrOutputHeadV1ScaleEvent : current scale -// -// This events describes the scale of the head in the global compositor -// space. It is only sent if the output is enabled. -type ZwlrOutputHeadV1ScaleEvent struct { - Scale float64 -} -type ZwlrOutputHeadV1ScaleHandlerFunc func(ZwlrOutputHeadV1ScaleEvent) - -// SetScaleHandler : sets handler for ZwlrOutputHeadV1ScaleEvent -func (i *ZwlrOutputHeadV1) SetScaleHandler(f ZwlrOutputHeadV1ScaleHandlerFunc) { - i.scaleHandler = f -} - -// ZwlrOutputHeadV1FinishedEvent : the head has disappeared -// -// This event indicates that the head is no longer available. The head -// object becomes inert. Clients should send a destroy request and release -// any resources associated with it. -type ZwlrOutputHeadV1FinishedEvent struct{} -type ZwlrOutputHeadV1FinishedHandlerFunc func(ZwlrOutputHeadV1FinishedEvent) - -// SetFinishedHandler : sets handler for ZwlrOutputHeadV1FinishedEvent -func (i *ZwlrOutputHeadV1) SetFinishedHandler(f ZwlrOutputHeadV1FinishedHandlerFunc) { - i.finishedHandler = f -} - -// ZwlrOutputHeadV1MakeEvent : head manufacturer -// -// This event describes the manufacturer of the head. -// -// Together with the model and serial_number events the purpose is to -// allow clients to recognize heads from previous sessions and for example -// load head-specific configurations back. -// -// It is not guaranteed this event will be ever sent. A reason for that -// can be that the compositor does not have information about the make of -// the head or the definition of a make is not sensible in the current -// setup, for example in a virtual session. Clients can still try to -// identify the head by available information from other events but should -// be aware that there is an increased risk of false positives. -// -// If sent, the make event is sent after a wlr_output_head object is -// created and only sent once per object. The make does not change over -// the lifetime of the wlr_output_head object. -// -// It is not recommended to display the make string in UI to users. For -// that the string provided by the description event should be preferred. -type ZwlrOutputHeadV1MakeEvent struct { - Make string -} -type ZwlrOutputHeadV1MakeHandlerFunc func(ZwlrOutputHeadV1MakeEvent) - -// SetMakeHandler : sets handler for ZwlrOutputHeadV1MakeEvent -func (i *ZwlrOutputHeadV1) SetMakeHandler(f ZwlrOutputHeadV1MakeHandlerFunc) { - i.makeHandler = f -} - -// ZwlrOutputHeadV1ModelEvent : head model -// -// This event describes the model of the head. -// -// Together with the make and serial_number events the purpose is to -// allow clients to recognize heads from previous sessions and for example -// load head-specific configurations back. -// -// It is not guaranteed this event will be ever sent. A reason for that -// can be that the compositor does not have information about the model of -// the head or the definition of a model is not sensible in the current -// setup, for example in a virtual session. Clients can still try to -// identify the head by available information from other events but should -// be aware that there is an increased risk of false positives. -// -// If sent, the model event is sent after a wlr_output_head object is -// created and only sent once per object. The model does not change over -// the lifetime of the wlr_output_head object. -// -// It is not recommended to display the model string in UI to users. For -// that the string provided by the description event should be preferred. -type ZwlrOutputHeadV1ModelEvent struct { - Model string -} -type ZwlrOutputHeadV1ModelHandlerFunc func(ZwlrOutputHeadV1ModelEvent) - -// SetModelHandler : sets handler for ZwlrOutputHeadV1ModelEvent -func (i *ZwlrOutputHeadV1) SetModelHandler(f ZwlrOutputHeadV1ModelHandlerFunc) { - i.modelHandler = f -} - -// ZwlrOutputHeadV1SerialNumberEvent : head serial number -// -// This event describes the serial number of the head. -// -// Together with the make and model events the purpose is to allow clients -// to recognize heads from previous sessions and for example load head- -// specific configurations back. -// -// It is not guaranteed this event will be ever sent. A reason for that -// can be that the compositor does not have information about the serial -// number of the head or the definition of a serial number is not sensible -// in the current setup. Clients can still try to identify the head by -// available information from other events but should be aware that there -// is an increased risk of false positives. -// -// If sent, the serial number event is sent after a wlr_output_head object -// is created and only sent once per object. The serial number does not -// change over the lifetime of the wlr_output_head object. -// -// It is not recommended to display the serial_number string in UI to -// users. For that the string provided by the description event should be -// preferred. -type ZwlrOutputHeadV1SerialNumberEvent struct { - SerialNumber string -} -type ZwlrOutputHeadV1SerialNumberHandlerFunc func(ZwlrOutputHeadV1SerialNumberEvent) - -// SetSerialNumberHandler : sets handler for ZwlrOutputHeadV1SerialNumberEvent -func (i *ZwlrOutputHeadV1) SetSerialNumberHandler(f ZwlrOutputHeadV1SerialNumberHandlerFunc) { - i.serialNumberHandler = f -} - -// ZwlrOutputHeadV1AdaptiveSyncEvent : current adaptive sync state -// -// This event describes whether adaptive sync is currently enabled for -// the head or not. Adaptive sync is also known as Variable Refresh -// Rate or VRR. -type ZwlrOutputHeadV1AdaptiveSyncEvent struct { - State uint32 -} -type ZwlrOutputHeadV1AdaptiveSyncHandlerFunc func(ZwlrOutputHeadV1AdaptiveSyncEvent) - -// SetAdaptiveSyncHandler : sets handler for ZwlrOutputHeadV1AdaptiveSyncEvent -func (i *ZwlrOutputHeadV1) SetAdaptiveSyncHandler(f ZwlrOutputHeadV1AdaptiveSyncHandlerFunc) { - i.adaptiveSyncHandler = f -} - -func (i *ZwlrOutputHeadV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.nameHandler == nil { - return - } - var e ZwlrOutputHeadV1NameEvent - l := 0 - nameLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Name = client.String(data[l : l+nameLen]) - l += nameLen - - i.nameHandler(e) - case 1: - if i.descriptionHandler == nil { - return - } - var e ZwlrOutputHeadV1DescriptionEvent - l := 0 - descriptionLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Description = client.String(data[l : l+descriptionLen]) - l += descriptionLen - - i.descriptionHandler(e) - case 2: - if i.physicalSizeHandler == nil { - return - } - var e ZwlrOutputHeadV1PhysicalSizeEvent - l := 0 - e.Width = int32(client.Uint32(data[l : l+4])) - l += 4 - e.Height = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.physicalSizeHandler(e) - case 3: - if i.modeHandler == nil { - return - } - var e ZwlrOutputHeadV1ModeEvent - l := 0 - objectID := client.Uint32(data[l : l+4]) - proxy := i.Context().GetProxy(objectID) - if proxy == nil || proxy.IsZombie() { - mode := &ZwlrOutputModeV1{} - mode.SetContext(i.Context()) - mode.SetID(objectID) - registerServerProxy(i.Context(), mode, objectID) - e.Mode = mode - } else if mode, ok := proxy.(*ZwlrOutputModeV1); ok { - e.Mode = mode - } else { - // Stale proxy of wrong type (can happen after suspend/resume) - // Replace it with the correct type - mode := &ZwlrOutputModeV1{} - mode.SetContext(i.Context()) - mode.SetID(objectID) - registerServerProxy(i.Context(), mode, objectID) - e.Mode = mode - } - l += 4 - - i.modeHandler(e) - case 4: - if i.enabledHandler == nil { - return - } - var e ZwlrOutputHeadV1EnabledEvent - l := 0 - e.Enabled = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.enabledHandler(e) - case 5: - if i.currentModeHandler == nil { - return - } - var e ZwlrOutputHeadV1CurrentModeEvent - l := 0 - objectID := client.Uint32(data[l : l+4]) - proxy := i.Context().GetProxy(objectID) - if proxy == nil || proxy.IsZombie() { - // Mode not yet registered or zombie, create fresh - mode := &ZwlrOutputModeV1{} - mode.SetContext(i.Context()) - mode.SetID(objectID) - registerServerProxy(i.Context(), mode, objectID) - e.Mode = mode - } else if mode, ok := proxy.(*ZwlrOutputModeV1); ok { - e.Mode = mode - } else { - // Stale proxy of wrong type (can happen after suspend/resume) - // Replace it with the correct type - mode := &ZwlrOutputModeV1{} - mode.SetContext(i.Context()) - mode.SetID(objectID) - registerServerProxy(i.Context(), mode, objectID) - e.Mode = mode - } - l += 4 - - i.currentModeHandler(e) - case 6: - if i.positionHandler == nil { - return - } - var e ZwlrOutputHeadV1PositionEvent - l := 0 - e.X = int32(client.Uint32(data[l : l+4])) - l += 4 - e.Y = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.positionHandler(e) - case 7: - if i.transformHandler == nil { - return - } - var e ZwlrOutputHeadV1TransformEvent - l := 0 - e.Transform = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.transformHandler(e) - case 8: - if i.scaleHandler == nil { - return - } - var e ZwlrOutputHeadV1ScaleEvent - l := 0 - e.Scale = client.Fixed(data[l : l+4]) - l += 4 - - i.scaleHandler(e) - case 9: - if i.finishedHandler == nil { - return - } - var e ZwlrOutputHeadV1FinishedEvent - - i.finishedHandler(e) - case 10: - if i.makeHandler == nil { - return - } - var e ZwlrOutputHeadV1MakeEvent - l := 0 - makeLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Make = client.String(data[l : l+makeLen]) - l += makeLen - - i.makeHandler(e) - case 11: - if i.modelHandler == nil { - return - } - var e ZwlrOutputHeadV1ModelEvent - l := 0 - modelLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.Model = client.String(data[l : l+modelLen]) - l += modelLen - - i.modelHandler(e) - case 12: - if i.serialNumberHandler == nil { - return - } - var e ZwlrOutputHeadV1SerialNumberEvent - l := 0 - serialNumberLen := client.PaddedLen(int(client.Uint32(data[l : l+4]))) - l += 4 - e.SerialNumber = client.String(data[l : l+serialNumberLen]) - l += serialNumberLen - - i.serialNumberHandler(e) - case 13: - if i.adaptiveSyncHandler == nil { - return - } - var e ZwlrOutputHeadV1AdaptiveSyncEvent - l := 0 - e.State = client.Uint32(data[l : l+4]) - l += 4 - - i.adaptiveSyncHandler(e) - } -} - -// ZwlrOutputModeV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputModeV1InterfaceName = "zwlr_output_mode_v1" - -// ZwlrOutputModeV1 : output mode -// -// This object describes an output mode. -// -// Some heads don't support output modes, in which case modes won't be -// advertised. -// -// Properties sent via this interface are applied atomically via the -// wlr_output_manager.done event. No guarantees are made regarding the order -// in which properties are sent. -type ZwlrOutputModeV1 struct { - client.BaseProxy - sizeHandler ZwlrOutputModeV1SizeHandlerFunc - refreshHandler ZwlrOutputModeV1RefreshHandlerFunc - preferredHandler ZwlrOutputModeV1PreferredHandlerFunc - finishedHandler ZwlrOutputModeV1FinishedHandlerFunc -} - -// NewZwlrOutputModeV1 : output mode -// -// This object describes an output mode. -// -// Some heads don't support output modes, in which case modes won't be -// advertised. -// -// Properties sent via this interface are applied atomically via the -// wlr_output_manager.done event. No guarantees are made regarding the order -// in which properties are sent. -func NewZwlrOutputModeV1(ctx *client.Context) *ZwlrOutputModeV1 { - zwlrOutputModeV1 := &ZwlrOutputModeV1{} - ctx.Register(zwlrOutputModeV1) - return zwlrOutputModeV1 -} - -// Release : destroy the mode object -// -// This request indicates that the client will no longer use this mode -// object. -func (i *ZwlrOutputModeV1) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ZwlrOutputModeV1SizeEvent : mode size -// -// This event describes the mode size. The size is given in physical -// hardware units of the output device. This is not necessarily the same as -// the output size in the global compositor space. For instance, the output -// may be scaled or transformed. -type ZwlrOutputModeV1SizeEvent struct { - Width int32 - Height int32 -} -type ZwlrOutputModeV1SizeHandlerFunc func(ZwlrOutputModeV1SizeEvent) - -// SetSizeHandler : sets handler for ZwlrOutputModeV1SizeEvent -func (i *ZwlrOutputModeV1) SetSizeHandler(f ZwlrOutputModeV1SizeHandlerFunc) { - i.sizeHandler = f -} - -// ZwlrOutputModeV1RefreshEvent : mode refresh rate -// -// This event describes the mode's fixed vertical refresh rate. It is only -// sent if the mode has a fixed refresh rate. -type ZwlrOutputModeV1RefreshEvent struct { - Refresh int32 -} -type ZwlrOutputModeV1RefreshHandlerFunc func(ZwlrOutputModeV1RefreshEvent) - -// SetRefreshHandler : sets handler for ZwlrOutputModeV1RefreshEvent -func (i *ZwlrOutputModeV1) SetRefreshHandler(f ZwlrOutputModeV1RefreshHandlerFunc) { - i.refreshHandler = f -} - -// ZwlrOutputModeV1PreferredEvent : mode is preferred -// -// This event advertises this mode as preferred. -type ZwlrOutputModeV1PreferredEvent struct{} -type ZwlrOutputModeV1PreferredHandlerFunc func(ZwlrOutputModeV1PreferredEvent) - -// SetPreferredHandler : sets handler for ZwlrOutputModeV1PreferredEvent -func (i *ZwlrOutputModeV1) SetPreferredHandler(f ZwlrOutputModeV1PreferredHandlerFunc) { - i.preferredHandler = f -} - -// ZwlrOutputModeV1FinishedEvent : the mode has disappeared -// -// This event indicates that the mode is no longer available. The mode -// object becomes inert. Clients should send a destroy request and release -// any resources associated with it. -type ZwlrOutputModeV1FinishedEvent struct{} -type ZwlrOutputModeV1FinishedHandlerFunc func(ZwlrOutputModeV1FinishedEvent) - -// SetFinishedHandler : sets handler for ZwlrOutputModeV1FinishedEvent -func (i *ZwlrOutputModeV1) SetFinishedHandler(f ZwlrOutputModeV1FinishedHandlerFunc) { - i.finishedHandler = f -} - -func (i *ZwlrOutputModeV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.sizeHandler == nil { - return - } - var e ZwlrOutputModeV1SizeEvent - l := 0 - e.Width = int32(client.Uint32(data[l : l+4])) - l += 4 - e.Height = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.sizeHandler(e) - case 1: - if i.refreshHandler == nil { - return - } - var e ZwlrOutputModeV1RefreshEvent - l := 0 - e.Refresh = int32(client.Uint32(data[l : l+4])) - l += 4 - - i.refreshHandler(e) - case 2: - if i.preferredHandler == nil { - return - } - var e ZwlrOutputModeV1PreferredEvent - - i.preferredHandler(e) - case 3: - if i.finishedHandler == nil { - return - } - var e ZwlrOutputModeV1FinishedEvent - - i.finishedHandler(e) - } -} - -// ZwlrOutputConfigurationV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputConfigurationV1InterfaceName = "zwlr_output_configuration_v1" - -// ZwlrOutputConfigurationV1 : output configuration -// -// This object is used by the client to describe a full output configuration. -// -// First, the client needs to setup the output configuration. Each head can -// be either enabled (and configured) or disabled. It is a protocol error to -// send two enable_head or disable_head requests with the same head. It is a -// protocol error to omit a head in a configuration. -// -// Then, the client can apply or test the configuration. The compositor will -// then reply with a succeeded, failed or cancelled event. Finally the client -// should destroy the configuration object. -type ZwlrOutputConfigurationV1 struct { - client.BaseProxy - succeededHandler ZwlrOutputConfigurationV1SucceededHandlerFunc - failedHandler ZwlrOutputConfigurationV1FailedHandlerFunc - cancelledHandler ZwlrOutputConfigurationV1CancelledHandlerFunc -} - -// NewZwlrOutputConfigurationV1 : output configuration -// -// This object is used by the client to describe a full output configuration. -// -// First, the client needs to setup the output configuration. Each head can -// be either enabled (and configured) or disabled. It is a protocol error to -// send two enable_head or disable_head requests with the same head. It is a -// protocol error to omit a head in a configuration. -// -// Then, the client can apply or test the configuration. The compositor will -// then reply with a succeeded, failed or cancelled event. Finally the client -// should destroy the configuration object. -func NewZwlrOutputConfigurationV1(ctx *client.Context) *ZwlrOutputConfigurationV1 { - zwlrOutputConfigurationV1 := &ZwlrOutputConfigurationV1{} - ctx.Register(zwlrOutputConfigurationV1) - return zwlrOutputConfigurationV1 -} - -// EnableHead : enable and configure a head -// -// Enable a head. This request creates a head configuration object that can -// be used to change the head's properties. -// -// head: the head to be enabled -func (i *ZwlrOutputConfigurationV1) EnableHead(head *ZwlrOutputHeadV1) (*ZwlrOutputConfigurationHeadV1, error) { - id := NewZwlrOutputConfigurationHeadV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], head.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// DisableHead : disable a head -// -// Disable a head. -// -// head: the head to be disabled -func (i *ZwlrOutputConfigurationV1) DisableHead(head *ZwlrOutputHeadV1) error { - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], head.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Apply : apply the configuration -// -// Apply the new output configuration. -// -// In case the configuration is successfully applied, there is no guarantee -// that the new output state matches completely the requested -// configuration. For instance, a compositor might round the scale if it -// doesn't support fractional scaling. -// -// After this request has been sent, the compositor must respond with an -// succeeded, failed or cancelled event. Sending a request that isn't the -// destructor is a protocol error. -func (i *ZwlrOutputConfigurationV1) Apply() error { - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Test : test the configuration -// -// Test the new output configuration. The configuration won't be applied, -// but will only be validated. -// -// Even if the compositor succeeds to test a configuration, applying it may -// fail. -// -// After this request has been sent, the compositor must respond with an -// succeeded, failed or cancelled event. Sending a request that isn't the -// destructor is a protocol error. -func (i *ZwlrOutputConfigurationV1) Test() error { - const opcode = 3 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Destroy : destroy the output configuration -// -// Using this request a client can tell the compositor that it is not going -// to use the configuration object anymore. Any changes to the outputs -// that have not been applied will be discarded. -// -// This request also destroys wlr_output_configuration_head objects created -// via this object. -func (i *ZwlrOutputConfigurationV1) Destroy() error { - defer i.MarkZombie() - const opcode = 4 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrOutputConfigurationV1Error uint32 - -// ZwlrOutputConfigurationV1Error : -const ( - // ZwlrOutputConfigurationV1ErrorAlreadyConfiguredHead : head has been configured twice - ZwlrOutputConfigurationV1ErrorAlreadyConfiguredHead ZwlrOutputConfigurationV1Error = 1 - // ZwlrOutputConfigurationV1ErrorUnconfiguredHead : head has not been configured - ZwlrOutputConfigurationV1ErrorUnconfiguredHead ZwlrOutputConfigurationV1Error = 2 - // ZwlrOutputConfigurationV1ErrorAlreadyUsed : request sent after configuration has been applied or tested - ZwlrOutputConfigurationV1ErrorAlreadyUsed ZwlrOutputConfigurationV1Error = 3 -) - -func (e ZwlrOutputConfigurationV1Error) Name() string { - switch e { - case ZwlrOutputConfigurationV1ErrorAlreadyConfiguredHead: - return "already_configured_head" - case ZwlrOutputConfigurationV1ErrorUnconfiguredHead: - return "unconfigured_head" - case ZwlrOutputConfigurationV1ErrorAlreadyUsed: - return "already_used" - default: - return "" - } -} - -func (e ZwlrOutputConfigurationV1Error) Value() string { - switch e { - case ZwlrOutputConfigurationV1ErrorAlreadyConfiguredHead: - return "1" - case ZwlrOutputConfigurationV1ErrorUnconfiguredHead: - return "2" - case ZwlrOutputConfigurationV1ErrorAlreadyUsed: - return "3" - default: - return "" - } -} - -func (e ZwlrOutputConfigurationV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrOutputConfigurationV1SucceededEvent : configuration changes succeeded -// -// Sent after the compositor has successfully applied the changes or -// tested them. -// -// Upon receiving this event, the client should destroy this object. -// -// If the current configuration has changed, events to describe the changes -// will be sent followed by a wlr_output_manager.done event. -type ZwlrOutputConfigurationV1SucceededEvent struct{} -type ZwlrOutputConfigurationV1SucceededHandlerFunc func(ZwlrOutputConfigurationV1SucceededEvent) - -// SetSucceededHandler : sets handler for ZwlrOutputConfigurationV1SucceededEvent -func (i *ZwlrOutputConfigurationV1) SetSucceededHandler(f ZwlrOutputConfigurationV1SucceededHandlerFunc) { - i.succeededHandler = f -} - -// ZwlrOutputConfigurationV1FailedEvent : configuration changes failed -// -// Sent if the compositor rejects the changes or failed to apply them. The -// compositor should revert any changes made by the apply request that -// triggered this event. -// -// Upon receiving this event, the client should destroy this object. -type ZwlrOutputConfigurationV1FailedEvent struct{} -type ZwlrOutputConfigurationV1FailedHandlerFunc func(ZwlrOutputConfigurationV1FailedEvent) - -// SetFailedHandler : sets handler for ZwlrOutputConfigurationV1FailedEvent -func (i *ZwlrOutputConfigurationV1) SetFailedHandler(f ZwlrOutputConfigurationV1FailedHandlerFunc) { - i.failedHandler = f -} - -// ZwlrOutputConfigurationV1CancelledEvent : configuration has been cancelled -// -// Sent if the compositor cancels the configuration because the state of an -// output changed and the client has outdated information (e.g. after an -// output has been hotplugged). -// -// The client can create a new configuration with a newer serial and try -// again. -// -// Upon receiving this event, the client should destroy this object. -type ZwlrOutputConfigurationV1CancelledEvent struct{} -type ZwlrOutputConfigurationV1CancelledHandlerFunc func(ZwlrOutputConfigurationV1CancelledEvent) - -// SetCancelledHandler : sets handler for ZwlrOutputConfigurationV1CancelledEvent -func (i *ZwlrOutputConfigurationV1) SetCancelledHandler(f ZwlrOutputConfigurationV1CancelledHandlerFunc) { - i.cancelledHandler = f -} - -func (i *ZwlrOutputConfigurationV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.succeededHandler == nil { - return - } - var e ZwlrOutputConfigurationV1SucceededEvent - - i.succeededHandler(e) - case 1: - if i.failedHandler == nil { - return - } - var e ZwlrOutputConfigurationV1FailedEvent - - i.failedHandler(e) - case 2: - if i.cancelledHandler == nil { - return - } - var e ZwlrOutputConfigurationV1CancelledEvent - - i.cancelledHandler(e) - } -} - -// ZwlrOutputConfigurationHeadV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputConfigurationHeadV1InterfaceName = "zwlr_output_configuration_head_v1" - -// ZwlrOutputConfigurationHeadV1 : head configuration -// -// This object is used by the client to update a single head's configuration. -// -// It is a protocol error to set the same property twice. -type ZwlrOutputConfigurationHeadV1 struct { - client.BaseProxy -} - -// NewZwlrOutputConfigurationHeadV1 : head configuration -// -// This object is used by the client to update a single head's configuration. -// -// It is a protocol error to set the same property twice. -func NewZwlrOutputConfigurationHeadV1(ctx *client.Context) *ZwlrOutputConfigurationHeadV1 { - zwlrOutputConfigurationHeadV1 := &ZwlrOutputConfigurationHeadV1{} - ctx.Register(zwlrOutputConfigurationHeadV1) - return zwlrOutputConfigurationHeadV1 -} - -// SetMode : set the mode -// -// This request sets the head's mode. -func (i *ZwlrOutputConfigurationHeadV1) SetMode(mode *ZwlrOutputModeV1) error { - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], mode.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetCustomMode : set a custom mode -// -// This request assigns a custom mode to the head. The size is given in -// physical hardware units of the output device. If set to zero, the -// refresh rate is unspecified. -// -// It is a protocol error to set both a mode and a custom mode. -// -// width: width of the mode in hardware units -// height: height of the mode in hardware units -// refresh: vertical refresh rate in mHz or zero -func (i *ZwlrOutputConfigurationHeadV1) SetCustomMode(width, height, refresh int32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(refresh)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetPosition : set the position -// -// This request sets the head's position in the global compositor space. -// -// x: x position in the global compositor space -// y: y position in the global compositor space -func (i *ZwlrOutputConfigurationHeadV1) SetPosition(x, y int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetTransform : set the transform -// -// This request sets the head's transform. -func (i *ZwlrOutputConfigurationHeadV1) SetTransform(transform int32) error { - const opcode = 3 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(transform)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetScale : set the scale -// -// This request sets the head's scale. -func (i *ZwlrOutputConfigurationHeadV1) SetScale(scale float64) error { - const opcode = 4 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutFixed(_reqBuf[l:l+4], scale) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetAdaptiveSync : enable/disable adaptive sync -// -// This request enables/disables adaptive sync. Adaptive sync is also -// known as Variable Refresh Rate or VRR. -func (i *ZwlrOutputConfigurationHeadV1) SetAdaptiveSync(state uint32) error { - const opcode = 5 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(state)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -func (i *ZwlrOutputConfigurationHeadV1) Destroy() error { - i.MarkZombie() - return nil -} - -type ZwlrOutputConfigurationHeadV1Error uint32 - -// ZwlrOutputConfigurationHeadV1Error : -const ( - // ZwlrOutputConfigurationHeadV1ErrorAlreadySet : property has already been set - ZwlrOutputConfigurationHeadV1ErrorAlreadySet ZwlrOutputConfigurationHeadV1Error = 1 - // ZwlrOutputConfigurationHeadV1ErrorInvalidMode : mode doesn't belong to head - ZwlrOutputConfigurationHeadV1ErrorInvalidMode ZwlrOutputConfigurationHeadV1Error = 2 - // ZwlrOutputConfigurationHeadV1ErrorInvalidCustomMode : mode is invalid - ZwlrOutputConfigurationHeadV1ErrorInvalidCustomMode ZwlrOutputConfigurationHeadV1Error = 3 - // ZwlrOutputConfigurationHeadV1ErrorInvalidTransform : transform value outside enum - ZwlrOutputConfigurationHeadV1ErrorInvalidTransform ZwlrOutputConfigurationHeadV1Error = 4 - // ZwlrOutputConfigurationHeadV1ErrorInvalidScale : scale negative or zero - ZwlrOutputConfigurationHeadV1ErrorInvalidScale ZwlrOutputConfigurationHeadV1Error = 5 - // ZwlrOutputConfigurationHeadV1ErrorInvalidAdaptiveSyncState : invalid enum value used in the set_adaptive_sync request - ZwlrOutputConfigurationHeadV1ErrorInvalidAdaptiveSyncState ZwlrOutputConfigurationHeadV1Error = 6 -) - -func (e ZwlrOutputConfigurationHeadV1Error) Name() string { - switch e { - case ZwlrOutputConfigurationHeadV1ErrorAlreadySet: - return "already_set" - case ZwlrOutputConfigurationHeadV1ErrorInvalidMode: - return "invalid_mode" - case ZwlrOutputConfigurationHeadV1ErrorInvalidCustomMode: - return "invalid_custom_mode" - case ZwlrOutputConfigurationHeadV1ErrorInvalidTransform: - return "invalid_transform" - case ZwlrOutputConfigurationHeadV1ErrorInvalidScale: - return "invalid_scale" - case ZwlrOutputConfigurationHeadV1ErrorInvalidAdaptiveSyncState: - return "invalid_adaptive_sync_state" - default: - return "" - } -} - -func (e ZwlrOutputConfigurationHeadV1Error) Value() string { - switch e { - case ZwlrOutputConfigurationHeadV1ErrorAlreadySet: - return "1" - case ZwlrOutputConfigurationHeadV1ErrorInvalidMode: - return "2" - case ZwlrOutputConfigurationHeadV1ErrorInvalidCustomMode: - return "3" - case ZwlrOutputConfigurationHeadV1ErrorInvalidTransform: - return "4" - case ZwlrOutputConfigurationHeadV1ErrorInvalidScale: - return "5" - case ZwlrOutputConfigurationHeadV1ErrorInvalidAdaptiveSyncState: - return "6" - default: - return "" - } -} - -func (e ZwlrOutputConfigurationHeadV1Error) String() string { - return e.Name() + "=" + e.Value() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_power/output_power.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_power/output_power.go deleted file mode 100644 index 8a10088..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_output_power/output_power.go +++ /dev/null @@ -1,283 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/wlr-output-power-management-unstable-v1.xml -// -// wlr_output_power_management_unstable_v1 Protocol Copyright: -// -// Copyright © 2019 Purism SPC -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice (including the next -// paragraph) shall be included in all copies or substantial portions of the -// Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -package wlr_output_power - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -// ZwlrOutputPowerManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputPowerManagerV1InterfaceName = "zwlr_output_power_manager_v1" - -// ZwlrOutputPowerManagerV1 : manager to create per-output power management -// -// This interface is a manager that allows creating per-output power -// management mode controls. -type ZwlrOutputPowerManagerV1 struct { - client.BaseProxy -} - -// NewZwlrOutputPowerManagerV1 : manager to create per-output power management -// -// This interface is a manager that allows creating per-output power -// management mode controls. -func NewZwlrOutputPowerManagerV1(ctx *client.Context) *ZwlrOutputPowerManagerV1 { - zwlrOutputPowerManagerV1 := &ZwlrOutputPowerManagerV1{} - ctx.Register(zwlrOutputPowerManagerV1) - return zwlrOutputPowerManagerV1 -} - -// GetOutputPower : get a power management for an output -// -// Create an output power management mode control that can be used to -// adjust the power management mode for a given output. -func (i *ZwlrOutputPowerManagerV1) GetOutputPower(output *client.Output) (*ZwlrOutputPowerV1, error) { - id := NewZwlrOutputPowerV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// Destroy : destroy the manager -// -// All objects created by the manager will still remain valid, until their -// appropriate destroy request has been called. -func (i *ZwlrOutputPowerManagerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ZwlrOutputPowerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrOutputPowerV1InterfaceName = "zwlr_output_power_v1" - -// ZwlrOutputPowerV1 : adjust power management mode for an output -// -// This object offers requests to set the power management mode of -// an output. -type ZwlrOutputPowerV1 struct { - client.BaseProxy - modeHandler ZwlrOutputPowerV1ModeHandlerFunc - failedHandler ZwlrOutputPowerV1FailedHandlerFunc -} - -// NewZwlrOutputPowerV1 : adjust power management mode for an output -// -// This object offers requests to set the power management mode of -// an output. -func NewZwlrOutputPowerV1(ctx *client.Context) *ZwlrOutputPowerV1 { - zwlrOutputPowerV1 := &ZwlrOutputPowerV1{} - ctx.Register(zwlrOutputPowerV1) - return zwlrOutputPowerV1 -} - -// SetMode : Set an outputs power save mode -// -// Set an output's power save mode to the given mode. The mode change -// is effective immediately. If the output does not support the given -// mode a failed event is sent. -// -// mode: the power save mode to set -func (i *ZwlrOutputPowerV1) SetMode(mode uint32) error { - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(mode)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Destroy : destroy this power management -// -// Destroys the output power management mode control object. -func (i *ZwlrOutputPowerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrOutputPowerV1Mode uint32 - -// ZwlrOutputPowerV1Mode : -const ( - // ZwlrOutputPowerV1ModeOff : Output is turned off. - ZwlrOutputPowerV1ModeOff ZwlrOutputPowerV1Mode = 0 - // ZwlrOutputPowerV1ModeOn : Output is turned on, no power saving - ZwlrOutputPowerV1ModeOn ZwlrOutputPowerV1Mode = 1 -) - -func (e ZwlrOutputPowerV1Mode) Name() string { - switch e { - case ZwlrOutputPowerV1ModeOff: - return "off" - case ZwlrOutputPowerV1ModeOn: - return "on" - default: - return "" - } -} - -func (e ZwlrOutputPowerV1Mode) Value() string { - switch e { - case ZwlrOutputPowerV1ModeOff: - return "0" - case ZwlrOutputPowerV1ModeOn: - return "1" - default: - return "" - } -} - -func (e ZwlrOutputPowerV1Mode) String() string { - return e.Name() + "=" + e.Value() -} - -type ZwlrOutputPowerV1Error uint32 - -// ZwlrOutputPowerV1Error : -const ( - // ZwlrOutputPowerV1ErrorInvalidMode : nonexistent power save mode - ZwlrOutputPowerV1ErrorInvalidMode ZwlrOutputPowerV1Error = 1 -) - -func (e ZwlrOutputPowerV1Error) Name() string { - switch e { - case ZwlrOutputPowerV1ErrorInvalidMode: - return "invalid_mode" - default: - return "" - } -} - -func (e ZwlrOutputPowerV1Error) Value() string { - switch e { - case ZwlrOutputPowerV1ErrorInvalidMode: - return "1" - default: - return "" - } -} - -func (e ZwlrOutputPowerV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrOutputPowerV1ModeEvent : Report a power management mode change -// -// Report the power management mode change of an output. -// -// The mode event is sent after an output changed its power -// management mode. The reason can be a client using set_mode or the -// compositor deciding to change an output's mode. -// This event is also sent immediately when the object is created -// so the client is informed about the current power management mode. -type ZwlrOutputPowerV1ModeEvent struct { - Mode uint32 -} -type ZwlrOutputPowerV1ModeHandlerFunc func(ZwlrOutputPowerV1ModeEvent) - -// SetModeHandler : sets handler for ZwlrOutputPowerV1ModeEvent -func (i *ZwlrOutputPowerV1) SetModeHandler(f ZwlrOutputPowerV1ModeHandlerFunc) { - i.modeHandler = f -} - -// ZwlrOutputPowerV1FailedEvent : object no longer valid -// -// This event indicates that the output power management mode control -// is no longer valid. This can happen for a number of reasons, -// including: -// - The output doesn't support power management -// - Another client already has exclusive power management mode control -// for this output -// - The output disappeared -// -// Upon receiving this event, the client should destroy this object. -type ZwlrOutputPowerV1FailedEvent struct{} -type ZwlrOutputPowerV1FailedHandlerFunc func(ZwlrOutputPowerV1FailedEvent) - -// SetFailedHandler : sets handler for ZwlrOutputPowerV1FailedEvent -func (i *ZwlrOutputPowerV1) SetFailedHandler(f ZwlrOutputPowerV1FailedHandlerFunc) { - i.failedHandler = f -} - -func (i *ZwlrOutputPowerV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.modeHandler == nil { - return - } - var e ZwlrOutputPowerV1ModeEvent - l := 0 - e.Mode = client.Uint32(data[l : l+4]) - l += 4 - - i.modeHandler(e) - case 1: - if i.failedHandler == nil { - return - } - var e ZwlrOutputPowerV1FailedEvent - - i.failedHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_screencopy/screencopy.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_screencopy/screencopy.go deleted file mode 100644 index edb9c5b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wlr_screencopy/screencopy.go +++ /dev/null @@ -1,532 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : internal/proto/xml/wlr-screencopy-unstable-v1.xml -// -// wlr_screencopy_unstable_v1 Protocol Copyright: -// -// Copyright © 2018 Simon Ser -// Copyright © 2019 Andri Yngvason -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice (including the next -// paragraph) shall be included in all copies or substantial portions of the -// Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -package wlr_screencopy - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -// ZwlrScreencopyManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrScreencopyManagerV1InterfaceName = "zwlr_screencopy_manager_v1" - -// ZwlrScreencopyManagerV1 : manager to inform clients and begin capturing -// -// This object is a manager which offers requests to start capturing from a -// source. -type ZwlrScreencopyManagerV1 struct { - client.BaseProxy -} - -// NewZwlrScreencopyManagerV1 : manager to inform clients and begin capturing -// -// This object is a manager which offers requests to start capturing from a -// source. -func NewZwlrScreencopyManagerV1(ctx *client.Context) *ZwlrScreencopyManagerV1 { - zwlrScreencopyManagerV1 := &ZwlrScreencopyManagerV1{} - ctx.Register(zwlrScreencopyManagerV1) - return zwlrScreencopyManagerV1 -} - -// CaptureOutput : capture an output -// -// Capture the next frame of an entire output. -// -// overlayCursor: composite cursor onto the frame -func (i *ZwlrScreencopyManagerV1) CaptureOutput(overlayCursor int32, output *client.Output) (*ZwlrScreencopyFrameV1, error) { - frame := NewZwlrScreencopyFrameV1(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], frame.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(overlayCursor)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return frame, err -} - -// CaptureOutputRegion : capture an output's region -// -// Capture the next frame of an output's region. -// -// The region is given in output logical coordinates, see -// xdg_output.logical_size. The region will be clipped to the output's -// extents. -// -// overlayCursor: composite cursor onto the frame -func (i *ZwlrScreencopyManagerV1) CaptureOutputRegion(overlayCursor int32, output *client.Output, x, y, width, height int32) (*ZwlrScreencopyFrameV1, error) { - frame := NewZwlrScreencopyFrameV1(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], frame.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(overlayCursor)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return frame, err -} - -// Destroy : destroy the manager -// -// All objects created by the manager will still remain valid, until their -// appropriate destroy request has been called. -func (i *ZwlrScreencopyManagerV1) Destroy() error { - defer i.MarkZombie() - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ZwlrScreencopyFrameV1InterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ZwlrScreencopyFrameV1InterfaceName = "zwlr_screencopy_frame_v1" - -// ZwlrScreencopyFrameV1 : a frame ready for copy -// -// This object represents a single frame. -// -// When created, a series of buffer events will be sent, each representing a -// supported buffer type. The "buffer_done" event is sent afterwards to -// indicate that all supported buffer types have been enumerated. The client -// will then be able to send a "copy" request. If the capture is successful, -// the compositor will send a "flags" event followed by a "ready" event. -// -// For objects version 2 or lower, wl_shm buffers are always supported, ie. -// the "buffer" event is guaranteed to be sent. -// -// If the capture failed, the "failed" event is sent. This can happen anytime -// before the "ready" event. -// -// Once either a "ready" or a "failed" event is received, the client should -// destroy the frame. -type ZwlrScreencopyFrameV1 struct { - client.BaseProxy - bufferHandler ZwlrScreencopyFrameV1BufferHandlerFunc - flagsHandler ZwlrScreencopyFrameV1FlagsHandlerFunc - readyHandler ZwlrScreencopyFrameV1ReadyHandlerFunc - failedHandler ZwlrScreencopyFrameV1FailedHandlerFunc - damageHandler ZwlrScreencopyFrameV1DamageHandlerFunc - linuxDmabufHandler ZwlrScreencopyFrameV1LinuxDmabufHandlerFunc - bufferDoneHandler ZwlrScreencopyFrameV1BufferDoneHandlerFunc -} - -// NewZwlrScreencopyFrameV1 : a frame ready for copy -// -// This object represents a single frame. -// -// When created, a series of buffer events will be sent, each representing a -// supported buffer type. The "buffer_done" event is sent afterwards to -// indicate that all supported buffer types have been enumerated. The client -// will then be able to send a "copy" request. If the capture is successful, -// the compositor will send a "flags" event followed by a "ready" event. -// -// For objects version 2 or lower, wl_shm buffers are always supported, ie. -// the "buffer" event is guaranteed to be sent. -// -// If the capture failed, the "failed" event is sent. This can happen anytime -// before the "ready" event. -// -// Once either a "ready" or a "failed" event is received, the client should -// destroy the frame. -func NewZwlrScreencopyFrameV1(ctx *client.Context) *ZwlrScreencopyFrameV1 { - zwlrScreencopyFrameV1 := &ZwlrScreencopyFrameV1{} - ctx.Register(zwlrScreencopyFrameV1) - return zwlrScreencopyFrameV1 -} - -// Copy : copy the frame -// -// Copy the frame to the supplied buffer. The buffer must have the -// correct size, see zwlr_screencopy_frame_v1.buffer and -// zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a -// supported format. -// -// If the frame is successfully copied, "flags" and "ready" events are -// sent. Otherwise, a "failed" event is sent. -func (i *ZwlrScreencopyFrameV1) Copy(buffer *client.Buffer) error { - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], buffer.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Destroy : delete this object, used or not -// -// Destroys the frame. This request can be sent at any time by the client. -func (i *ZwlrScreencopyFrameV1) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// CopyWithDamage : copy the frame when it's damaged -// -// Same as copy, except it waits until there is damage to copy. -func (i *ZwlrScreencopyFrameV1) CopyWithDamage(buffer *client.Buffer) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], buffer.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ZwlrScreencopyFrameV1Error uint32 - -// ZwlrScreencopyFrameV1Error : -const ( - // ZwlrScreencopyFrameV1ErrorAlreadyUsed : the object has already been used to copy a wl_buffer - ZwlrScreencopyFrameV1ErrorAlreadyUsed ZwlrScreencopyFrameV1Error = 0 - // ZwlrScreencopyFrameV1ErrorInvalidBuffer : buffer attributes are invalid - ZwlrScreencopyFrameV1ErrorInvalidBuffer ZwlrScreencopyFrameV1Error = 1 -) - -func (e ZwlrScreencopyFrameV1Error) Name() string { - switch e { - case ZwlrScreencopyFrameV1ErrorAlreadyUsed: - return "already_used" - case ZwlrScreencopyFrameV1ErrorInvalidBuffer: - return "invalid_buffer" - default: - return "" - } -} - -func (e ZwlrScreencopyFrameV1Error) Value() string { - switch e { - case ZwlrScreencopyFrameV1ErrorAlreadyUsed: - return "0" - case ZwlrScreencopyFrameV1ErrorInvalidBuffer: - return "1" - default: - return "" - } -} - -func (e ZwlrScreencopyFrameV1Error) String() string { - return e.Name() + "=" + e.Value() -} - -type ZwlrScreencopyFrameV1Flags uint32 - -// ZwlrScreencopyFrameV1Flags : -const ( - // ZwlrScreencopyFrameV1FlagsYInvert : contents are y-inverted - ZwlrScreencopyFrameV1FlagsYInvert ZwlrScreencopyFrameV1Flags = 1 -) - -func (e ZwlrScreencopyFrameV1Flags) Name() string { - switch e { - case ZwlrScreencopyFrameV1FlagsYInvert: - return "y_invert" - default: - return "" - } -} - -func (e ZwlrScreencopyFrameV1Flags) Value() string { - switch e { - case ZwlrScreencopyFrameV1FlagsYInvert: - return "1" - default: - return "" - } -} - -func (e ZwlrScreencopyFrameV1Flags) String() string { - return e.Name() + "=" + e.Value() -} - -// ZwlrScreencopyFrameV1BufferEvent : wl_shm buffer information -// -// Provides information about wl_shm buffer parameters that need to be -// used for this frame. This event is sent once after the frame is created -// if wl_shm buffers are supported. -type ZwlrScreencopyFrameV1BufferEvent struct { - Format uint32 - Width uint32 - Height uint32 - Stride uint32 -} -type ZwlrScreencopyFrameV1BufferHandlerFunc func(ZwlrScreencopyFrameV1BufferEvent) - -// SetBufferHandler : sets handler for ZwlrScreencopyFrameV1BufferEvent -func (i *ZwlrScreencopyFrameV1) SetBufferHandler(f ZwlrScreencopyFrameV1BufferHandlerFunc) { - i.bufferHandler = f -} - -// ZwlrScreencopyFrameV1FlagsEvent : frame flags -// -// Provides flags about the frame. This event is sent once before the -// "ready" event. -type ZwlrScreencopyFrameV1FlagsEvent struct { - Flags uint32 -} -type ZwlrScreencopyFrameV1FlagsHandlerFunc func(ZwlrScreencopyFrameV1FlagsEvent) - -// SetFlagsHandler : sets handler for ZwlrScreencopyFrameV1FlagsEvent -func (i *ZwlrScreencopyFrameV1) SetFlagsHandler(f ZwlrScreencopyFrameV1FlagsHandlerFunc) { - i.flagsHandler = f -} - -// ZwlrScreencopyFrameV1ReadyEvent : indicates frame is available for reading -// -// Called as soon as the frame is copied, indicating it is available -// for reading. This event includes the time at which the presentation took place. -// -// The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, -// each component being an unsigned 32-bit value. Whole seconds are in -// tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, -// and the additional fractional part in tv_nsec as nanoseconds. Hence, -// for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part -// may have an arbitrary offset at start. -// -// After receiving this event, the client should destroy the object. -type ZwlrScreencopyFrameV1ReadyEvent struct { - TvSecHi uint32 - TvSecLo uint32 - TvNsec uint32 -} -type ZwlrScreencopyFrameV1ReadyHandlerFunc func(ZwlrScreencopyFrameV1ReadyEvent) - -// SetReadyHandler : sets handler for ZwlrScreencopyFrameV1ReadyEvent -func (i *ZwlrScreencopyFrameV1) SetReadyHandler(f ZwlrScreencopyFrameV1ReadyHandlerFunc) { - i.readyHandler = f -} - -// ZwlrScreencopyFrameV1FailedEvent : frame copy failed -// -// This event indicates that the attempted frame copy has failed. -// -// After receiving this event, the client should destroy the object. -type ZwlrScreencopyFrameV1FailedEvent struct{} -type ZwlrScreencopyFrameV1FailedHandlerFunc func(ZwlrScreencopyFrameV1FailedEvent) - -// SetFailedHandler : sets handler for ZwlrScreencopyFrameV1FailedEvent -func (i *ZwlrScreencopyFrameV1) SetFailedHandler(f ZwlrScreencopyFrameV1FailedHandlerFunc) { - i.failedHandler = f -} - -// ZwlrScreencopyFrameV1DamageEvent : carries the coordinates of the damaged region -// -// This event is sent right before the ready event when copy_with_damage is -// requested. It may be generated multiple times for each copy_with_damage -// request. -// -// The arguments describe a box around an area that has changed since the -// last copy request that was derived from the current screencopy manager -// instance. -// -// The union of all regions received between the call to copy_with_damage -// and a ready event is the total damage since the prior ready event. -type ZwlrScreencopyFrameV1DamageEvent struct { - X uint32 - Y uint32 - Width uint32 - Height uint32 -} -type ZwlrScreencopyFrameV1DamageHandlerFunc func(ZwlrScreencopyFrameV1DamageEvent) - -// SetDamageHandler : sets handler for ZwlrScreencopyFrameV1DamageEvent -func (i *ZwlrScreencopyFrameV1) SetDamageHandler(f ZwlrScreencopyFrameV1DamageHandlerFunc) { - i.damageHandler = f -} - -// ZwlrScreencopyFrameV1LinuxDmabufEvent : linux-dmabuf buffer information -// -// Provides information about linux-dmabuf buffer parameters that need to -// be used for this frame. This event is sent once after the frame is -// created if linux-dmabuf buffers are supported. -type ZwlrScreencopyFrameV1LinuxDmabufEvent struct { - Format uint32 - Width uint32 - Height uint32 -} -type ZwlrScreencopyFrameV1LinuxDmabufHandlerFunc func(ZwlrScreencopyFrameV1LinuxDmabufEvent) - -// SetLinuxDmabufHandler : sets handler for ZwlrScreencopyFrameV1LinuxDmabufEvent -func (i *ZwlrScreencopyFrameV1) SetLinuxDmabufHandler(f ZwlrScreencopyFrameV1LinuxDmabufHandlerFunc) { - i.linuxDmabufHandler = f -} - -// ZwlrScreencopyFrameV1BufferDoneEvent : all buffer types reported -// -// This event is sent once after all buffer events have been sent. -// -// The client should proceed to create a buffer of one of the supported -// types, and send a "copy" request. -type ZwlrScreencopyFrameV1BufferDoneEvent struct{} -type ZwlrScreencopyFrameV1BufferDoneHandlerFunc func(ZwlrScreencopyFrameV1BufferDoneEvent) - -// SetBufferDoneHandler : sets handler for ZwlrScreencopyFrameV1BufferDoneEvent -func (i *ZwlrScreencopyFrameV1) SetBufferDoneHandler(f ZwlrScreencopyFrameV1BufferDoneHandlerFunc) { - i.bufferDoneHandler = f -} - -func (i *ZwlrScreencopyFrameV1) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.bufferHandler == nil { - return - } - var e ZwlrScreencopyFrameV1BufferEvent - l := 0 - e.Format = client.Uint32(data[l : l+4]) - l += 4 - e.Width = client.Uint32(data[l : l+4]) - l += 4 - e.Height = client.Uint32(data[l : l+4]) - l += 4 - e.Stride = client.Uint32(data[l : l+4]) - l += 4 - - i.bufferHandler(e) - case 1: - if i.flagsHandler == nil { - return - } - var e ZwlrScreencopyFrameV1FlagsEvent - l := 0 - e.Flags = client.Uint32(data[l : l+4]) - l += 4 - - i.flagsHandler(e) - case 2: - if i.readyHandler == nil { - return - } - var e ZwlrScreencopyFrameV1ReadyEvent - l := 0 - e.TvSecHi = client.Uint32(data[l : l+4]) - l += 4 - e.TvSecLo = client.Uint32(data[l : l+4]) - l += 4 - e.TvNsec = client.Uint32(data[l : l+4]) - l += 4 - - i.readyHandler(e) - case 3: - if i.failedHandler == nil { - return - } - var e ZwlrScreencopyFrameV1FailedEvent - - i.failedHandler(e) - case 4: - if i.damageHandler == nil { - return - } - var e ZwlrScreencopyFrameV1DamageEvent - l := 0 - e.X = client.Uint32(data[l : l+4]) - l += 4 - e.Y = client.Uint32(data[l : l+4]) - l += 4 - e.Width = client.Uint32(data[l : l+4]) - l += 4 - e.Height = client.Uint32(data[l : l+4]) - l += 4 - - i.damageHandler(e) - case 5: - if i.linuxDmabufHandler == nil { - return - } - var e ZwlrScreencopyFrameV1LinuxDmabufEvent - l := 0 - e.Format = client.Uint32(data[l : l+4]) - l += 4 - e.Width = client.Uint32(data[l : l+4]) - l += 4 - e.Height = client.Uint32(data[l : l+4]) - l += 4 - - i.linuxDmabufHandler(e) - case 6: - if i.bufferDoneHandler == nil { - return - } - var e ZwlrScreencopyFrameV1BufferDoneEvent - - i.bufferDoneHandler(e) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wp_viewporter/viewporter.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wp_viewporter/viewporter.go deleted file mode 100644 index 4b390bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/wp_viewporter/viewporter.go +++ /dev/null @@ -1,399 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : /tmp/viewporter.xml -// -// viewporter Protocol Copyright: -// -// Copyright © 2013-2016 Collabora, Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice (including the next -// paragraph) shall be included in all copies or substantial portions of the -// Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -package wp_viewporter - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -// WpViewporterInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const WpViewporterInterfaceName = "wp_viewporter" - -// WpViewporter : surface cropping and scaling -// -// The global interface exposing surface cropping and scaling -// capabilities is used to instantiate an interface extension for a -// wl_surface object. This extended interface will then allow -// cropping and scaling the surface contents, effectively -// disconnecting the direct relationship between the buffer and the -// surface size. -type WpViewporter struct { - client.BaseProxy -} - -// NewWpViewporter : surface cropping and scaling -// -// The global interface exposing surface cropping and scaling -// capabilities is used to instantiate an interface extension for a -// wl_surface object. This extended interface will then allow -// cropping and scaling the surface contents, effectively -// disconnecting the direct relationship between the buffer and the -// surface size. -func NewWpViewporter(ctx *client.Context) *WpViewporter { - wpViewporter := &WpViewporter{} - ctx.Register(wpViewporter) - return wpViewporter -} - -// Destroy : unbind from the cropping and scaling interface -// -// Informs the server that the client will not be using this -// protocol object anymore. This does not affect any other objects, -// wp_viewport objects included. -func (i *WpViewporter) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// GetViewport : extend surface interface for crop and scale -// -// Instantiate an interface extension for the given wl_surface to -// crop and scale its content. If the given wl_surface already has -// a wp_viewport object associated, the viewport_exists -// protocol error is raised. -// -// surface: the surface -func (i *WpViewporter) GetViewport(surface *client.Surface) (*WpViewport, error) { - id := NewWpViewport(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -type WpViewporterError uint32 - -// WpViewporterError : -const ( - // WpViewporterErrorViewportExists : the surface already has a viewport object associated - WpViewporterErrorViewportExists WpViewporterError = 0 -) - -func (e WpViewporterError) Name() string { - switch e { - case WpViewporterErrorViewportExists: - return "viewport_exists" - default: - return "" - } -} - -func (e WpViewporterError) Value() string { - switch e { - case WpViewporterErrorViewportExists: - return "0" - default: - return "" - } -} - -func (e WpViewporterError) String() string { - return e.Name() + "=" + e.Value() -} - -// WpViewportInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const WpViewportInterfaceName = "wp_viewport" - -// WpViewport : crop and scale interface to a wl_surface -// -// An additional interface to a wl_surface object, which allows the -// client to specify the cropping and scaling of the surface -// contents. -// -// This interface works with two concepts: the source rectangle (src_x, -// src_y, src_width, src_height), and the destination size (dst_width, -// dst_height). The contents of the source rectangle are scaled to the -// destination size, and content outside the source rectangle is ignored. -// This state is double-buffered, see wl_surface.commit. -// -// The two parts of crop and scale state are independent: the source -// rectangle, and the destination size. Initially both are unset, that -// is, no scaling is applied. The whole of the current wl_buffer is -// used as the source, and the surface size is as defined in -// wl_surface.attach. -// -// If the destination size is set, it causes the surface size to become -// dst_width, dst_height. The source (rectangle) is scaled to exactly -// this size. This overrides whatever the attached wl_buffer size is, -// unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface -// has no content and therefore no size. Otherwise, the size is always -// at least 1x1 in surface local coordinates. -// -// If the source rectangle is set, it defines what area of the wl_buffer is -// taken as the source. If the source rectangle is set and the destination -// size is not set, then src_width and src_height must be integers, and the -// surface size becomes the source rectangle size. This results in cropping -// without scaling. If src_width or src_height are not integers and -// destination size is not set, the bad_size protocol error is raised when -// the surface state is applied. -// -// The coordinate transformations from buffer pixel coordinates up to -// the surface-local coordinates happen in the following order: -// 1. buffer_transform (wl_surface.set_buffer_transform) -// 2. buffer_scale (wl_surface.set_buffer_scale) -// 3. crop and scale (wp_viewport.set*) -// This means, that the source rectangle coordinates of crop and scale -// are given in the coordinates after the buffer transform and scale, -// i.e. in the coordinates that would be the surface-local coordinates -// if the crop and scale was not applied. -// -// If src_x or src_y are negative, the bad_value protocol error is raised. -// Otherwise, if the source rectangle is partially or completely outside of -// the non-NULL wl_buffer, then the out_of_buffer protocol error is raised -// when the surface state is applied. A NULL wl_buffer does not raise the -// out_of_buffer error. -// -// If the wl_surface associated with the wp_viewport is destroyed, -// all wp_viewport requests except 'destroy' raise the protocol error -// no_surface. -// -// If the wp_viewport object is destroyed, the crop and scale -// state is removed from the wl_surface. The change will be applied -// on the next wl_surface.commit. -type WpViewport struct { - client.BaseProxy -} - -// NewWpViewport : crop and scale interface to a wl_surface -// -// An additional interface to a wl_surface object, which allows the -// client to specify the cropping and scaling of the surface -// contents. -// -// This interface works with two concepts: the source rectangle (src_x, -// src_y, src_width, src_height), and the destination size (dst_width, -// dst_height). The contents of the source rectangle are scaled to the -// destination size, and content outside the source rectangle is ignored. -// This state is double-buffered, see wl_surface.commit. -// -// The two parts of crop and scale state are independent: the source -// rectangle, and the destination size. Initially both are unset, that -// is, no scaling is applied. The whole of the current wl_buffer is -// used as the source, and the surface size is as defined in -// wl_surface.attach. -// -// If the destination size is set, it causes the surface size to become -// dst_width, dst_height. The source (rectangle) is scaled to exactly -// this size. This overrides whatever the attached wl_buffer size is, -// unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface -// has no content and therefore no size. Otherwise, the size is always -// at least 1x1 in surface local coordinates. -// -// If the source rectangle is set, it defines what area of the wl_buffer is -// taken as the source. If the source rectangle is set and the destination -// size is not set, then src_width and src_height must be integers, and the -// surface size becomes the source rectangle size. This results in cropping -// without scaling. If src_width or src_height are not integers and -// destination size is not set, the bad_size protocol error is raised when -// the surface state is applied. -// -// The coordinate transformations from buffer pixel coordinates up to -// the surface-local coordinates happen in the following order: -// 1. buffer_transform (wl_surface.set_buffer_transform) -// 2. buffer_scale (wl_surface.set_buffer_scale) -// 3. crop and scale (wp_viewport.set*) -// This means, that the source rectangle coordinates of crop and scale -// are given in the coordinates after the buffer transform and scale, -// i.e. in the coordinates that would be the surface-local coordinates -// if the crop and scale was not applied. -// -// If src_x or src_y are negative, the bad_value protocol error is raised. -// Otherwise, if the source rectangle is partially or completely outside of -// the non-NULL wl_buffer, then the out_of_buffer protocol error is raised -// when the surface state is applied. A NULL wl_buffer does not raise the -// out_of_buffer error. -// -// If the wl_surface associated with the wp_viewport is destroyed, -// all wp_viewport requests except 'destroy' raise the protocol error -// no_surface. -// -// If the wp_viewport object is destroyed, the crop and scale -// state is removed from the wl_surface. The change will be applied -// on the next wl_surface.commit. -func NewWpViewport(ctx *client.Context) *WpViewport { - wpViewport := &WpViewport{} - ctx.Register(wpViewport) - return wpViewport -} - -// Destroy : remove scaling and cropping from the surface -// -// The associated wl_surface's crop and scale state is removed. -// The change is applied on the next wl_surface.commit. -func (i *WpViewport) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetSource : set the source rectangle for cropping -// -// Set the source rectangle of the associated wl_surface. See -// wp_viewport for the description, and relation to the wl_buffer -// size. -// -// If all of x, y, width and height are -1.0, the source rectangle is -// unset instead. Any other set of values where width or height are zero -// or negative, or x or y are negative, raise the bad_value protocol -// error. -// -// The crop and scale state is double-buffered, see wl_surface.commit. -// -// x: source rectangle x -// y: source rectangle y -// width: source rectangle width -// height: source rectangle height -func (i *WpViewport) SetSource(x, y, width, height float64) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutFixed(_reqBuf[l:l+4], x) - l += 4 - client.PutFixed(_reqBuf[l:l+4], y) - l += 4 - client.PutFixed(_reqBuf[l:l+4], width) - l += 4 - client.PutFixed(_reqBuf[l:l+4], height) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetDestination : set the surface size for scaling -// -// Set the destination size of the associated wl_surface. See -// wp_viewport for the description, and relation to the wl_buffer -// size. -// -// If width is -1 and height is -1, the destination size is unset -// instead. Any other pair of values for width and height that -// contains zero or negative values raises the bad_value protocol -// error. -// -// The crop and scale state is double-buffered, see wl_surface.commit. -// -// width: surface width -// height: surface height -func (i *WpViewport) SetDestination(width, height int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - client.PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - client.PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type WpViewportError uint32 - -// WpViewportError : -const ( - // WpViewportErrorBadValue : negative or zero values in width or height - WpViewportErrorBadValue WpViewportError = 0 - // WpViewportErrorBadSize : destination size is not integer - WpViewportErrorBadSize WpViewportError = 1 - // WpViewportErrorOutOfBuffer : source rectangle extends outside of the content area - WpViewportErrorOutOfBuffer WpViewportError = 2 - // WpViewportErrorNoSurface : the wl_surface was destroyed - WpViewportErrorNoSurface WpViewportError = 3 -) - -func (e WpViewportError) Name() string { - switch e { - case WpViewportErrorBadValue: - return "bad_value" - case WpViewportErrorBadSize: - return "bad_size" - case WpViewportErrorOutOfBuffer: - return "out_of_buffer" - case WpViewportErrorNoSurface: - return "no_surface" - default: - return "" - } -} - -func (e WpViewportError) Value() string { - switch e { - case WpViewportErrorBadValue: - return "0" - case WpViewportErrorBadSize: - return "1" - case WpViewportErrorOutOfBuffer: - return "2" - case WpViewportErrorNoSurface: - return "3" - default: - return "" - } -} - -func (e WpViewportError) String() string { - return e.Name() + "=" + e.Value() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/dwl-ipc-unstable-v2.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/dwl-ipc-unstable-v2.xml deleted file mode 100644 index a4e0b49..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/dwl-ipc-unstable-v2.xml +++ /dev/null @@ -1,252 +0,0 @@ - - - - - This protocol allows clients to update and get updates from dwl. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible - changes may be added together with the corresponding interface - version bump. - Backward incompatible changes are done by bumping the version - number in the protocol and interface names and resetting the - interface version. Once the protocol is to be declared stable, - the 'z' prefix and the version number in the protocol and - interface names are removed and the interface version number is - reset. - - - - - This interface is exposed as a global in wl_registry. - - Clients can use this interface to get a dwl_ipc_output. - After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. - The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. - - - - - Indicates that the client will not the dwl_ipc_manager object anymore. - Objects created through this instance are not affected. - - - - - - Get a dwl_ipc_outout for the specified wl_output. - - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all tags. - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all layouts. - - - - - - - - Observe and control a dwl output. - - Events are double-buffered: - Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. - - Request are not double-buffered: - The compositor will update immediately upon request. - - - - - - - - - - - Indicates to that the client no longer needs this dwl_ipc_output. - - - - - - Indicates the client should hide or show themselves. - If the client is visible then hide, if hidden then show. - - - - - - Indicates if the output is active. Zero is invalid, nonzero is valid. - - - - - - - Indicates that a tag has been updated. - - - - - - - - - - Indicates a new layout is selected. - - - - - - - Indicates the title has changed. - - - - - - - Indicates the appid has changed. - - - - - - - Indicates the layout has changed. Since layout symbols are dynamic. - As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. - You can ignore the zdwl_ipc_output.layout event. - - - - - - - Indicates that a sequence of status updates have finished and the client should redraw. - - - - - - - - - - - - The tags are updated as follows: - new_tags = (current_tags AND and_tags) XOR xor_tags - - - - - - - - - - - - This request allows clients to instruct the compositor to quit mango. - - - - - - - - - - - - - - - - Indicates if the selected client on this output is fullscreen. - - - - - - - Indicates if the selected client on this output is floating. - - - - - - - Indicates if x coordinates of the selected client. - - - - - - - Indicates if y coordinates of the selected client. - - - - - - - Indicates if width of the selected client. - - - - - - - Indicates if height of the selected client. - - - - - - - last map layer. - - - - - - - current keyboard layout. - - - - - - - current keybind mode. - - - - - - - scale factor of monitor. - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-data-control-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-data-control-v1.xml deleted file mode 100644 index 37ee577..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-data-control-v1.xml +++ /dev/null @@ -1,276 +0,0 @@ - - - - Copyright © 2018 Simon Ser - Copyright © 2019 Ivan Molodetskikh - Copyright © 2024 Neal Gompa - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - This protocol allows a privileged client to control data devices. In - particular, the client will be able to manage the current selection and take - the role of a clipboard manager. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - - This interface is a manager that allows creating per-seat data device - controls. - - - - - Create a new data source. - - - - - - - Create a data device that can be used to manage a seat's selection. - - - - - - - - All objects created by the manager will still remain valid, until their - appropriate destroy request has been called. - - - - - - - This interface allows a client to manage a seat's selection. - - When the seat is destroyed, this object becomes inert. - - - - - This request asks the compositor to set the selection to the data from - the source on behalf of the client. - - The given source may not be used in any further set_selection or - set_primary_selection requests. Attempting to use a previously used - source triggers the used_source protocol error. - - To unset the selection, set the source to NULL. - - - - - - - Destroys the data device object. - - - - - - The data_offer event introduces a new ext_data_control_offer object, - which will subsequently be used in either the - ext_data_control_device.selection event (for the regular clipboard - selections) or the ext_data_control_device.primary_selection event (for - the primary clipboard selections). Immediately following the - ext_data_control_device.data_offer event, the new data_offer object - will send out ext_data_control_offer.offer events to describe the MIME - types it offers. - - - - - - - The selection event is sent out to notify the client of a new - ext_data_control_offer for the selection for this device. The - ext_data_control_device.data_offer and the ext_data_control_offer.offer - events are sent out immediately before this event to introduce the data - offer object. The selection event is sent to a client when a new - selection is set. The ext_data_control_offer is valid until a new - ext_data_control_offer or NULL is received. The client must destroy the - previous selection ext_data_control_offer, if any, upon receiving this - event. Regardless, the previous selection will be ignored once a new - selection ext_data_control_offer is received. - - The first selection event is sent upon binding the - ext_data_control_device object. - - - - - - - This data control object is no longer valid and should be destroyed by - the client. - - - - - - The primary_selection event is sent out to notify the client of a new - ext_data_control_offer for the primary selection for this device. The - ext_data_control_device.data_offer and the ext_data_control_offer.offer - events are sent out immediately before this event to introduce the data - offer object. The primary_selection event is sent to a client when a - new primary selection is set. The ext_data_control_offer is valid until - a new ext_data_control_offer or NULL is received. The client must - destroy the previous primary selection ext_data_control_offer, if any, - upon receiving this event. Regardless, the previous primary selection - will be ignored once a new primary selection ext_data_control_offer is - received. - - If the compositor supports primary selection, the first - primary_selection event is sent upon binding the - ext_data_control_device object. - - - - - - - This request asks the compositor to set the primary selection to the - data from the source on behalf of the client. - - The given source may not be used in any further set_selection or - set_primary_selection requests. Attempting to use a previously used - source triggers the used_source protocol error. - - To unset the primary selection, set the source to NULL. - - The compositor will ignore this request if it does not support primary - selection. - - - - - - - - - - - - The ext_data_control_source object is the source side of a - ext_data_control_offer. It is created by the source client in a data - transfer and provides a way to describe the offered data and a way to - respond to requests to transfer the data. - - - - - - - - - This request adds a MIME type to the set of MIME types advertised to - targets. Can be called several times to offer multiple types. - - Calling this after ext_data_control_device.set_selection is a protocol - error. - - - - - - - Destroys the data source object. - - - - - - Request for data from the client. Send the data as the specified MIME - type over the passed file descriptor, then close it. - - - - - - - - This data source is no longer valid. The data source has been replaced - by another data source. - - The client should clean up and destroy this data source. - - - - - - - A ext_data_control_offer represents a piece of data offered for transfer - by another client (the source client). The offer describes the different - MIME types that the data can be converted to and provides the mechanism - for transferring the data directly from the source client. - - - - - To transfer the offered data, the client issues this request and - indicates the MIME type it wants to receive. The transfer happens - through the passed file descriptor (typically created with the pipe - system call). The source client writes the data in the MIME type - representation requested and then closes the file descriptor. - - The receiving client reads from the read end of the pipe until EOF and - then closes its end, at which point the transfer is complete. - - This request may happen multiple times for different MIME types. - - - - - - - - Destroys the data offer object. - - - - - - Sent immediately after creating the ext_data_control_offer object. - One event per offered MIME type. - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-workspace-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-workspace-v1.xml deleted file mode 100644 index 134b729..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/ext-workspace-v1.xml +++ /dev/null @@ -1,422 +0,0 @@ - - - - Copyright © 2019 Christopher Billington - Copyright © 2020 Ilia Bozhinov - Copyright © 2022 Victoria Brekenfeld - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - Workspaces, also called virtual desktops, are groups of surfaces. A - compositor with a concept of workspaces may only show some such groups of - surfaces (those of 'active' workspaces) at a time. 'Activating' a - workspace is a request for the compositor to display that workspace's - surfaces as normal, whereas the compositor may hide or otherwise - de-emphasise surfaces that are associated only with 'inactive' workspaces. - Workspaces are grouped by which sets of outputs they correspond to, and - may contain surfaces only from those outputs. In this way, it is possible - for each output to have its own set of workspaces, or for all outputs (or - any other arbitrary grouping) to share workspaces. Compositors may - optionally conceptually arrange each group of workspaces in an - N-dimensional grid. - - The purpose of this protocol is to enable the creation of taskbars and - docks by providing them with a list of workspaces and their properties, - and allowing them to activate and deactivate workspaces. - - After a client binds the ext_workspace_manager_v1, each workspace will be - sent via the workspace event. - - - - - This event is emitted whenever a new workspace group has been created. - - All initial details of the workspace group (outputs) will be - sent immediately after this event via the corresponding events in - ext_workspace_group_handle_v1 and ext_workspace_handle_v1. - - - - - - - This event is emitted whenever a new workspace has been created. - - All initial details of the workspace (name, coordinates, state) will - be sent immediately after this event via the corresponding events in - ext_workspace_handle_v1. - - Workspaces start off unassigned to any workspace group. - - - - - - - The client must send this request after it has finished sending other - requests. The compositor must process a series of requests preceding a - commit request atomically. - - This allows changes to the workspace properties to be seen as atomic, - even if they happen via multiple events, and even if they involve - multiple ext_workspace_handle_v1 objects, for example, deactivating one - workspace and activating another. - - - - - - This event is sent after all changes in all workspaces and workspace groups have been - sent. - - This allows changes to one or more ext_workspace_group_handle_v1 - properties and ext_workspace_handle_v1 properties - to be seen as atomic, even if they happen via multiple events. - In particular, an output moving from one workspace group to - another sends an output_enter event and an output_leave event to the two - ext_workspace_group_handle_v1 objects in question. The compositor sends - the done event only after updating the output information in both - workspace groups. - - - - - - This event indicates that the compositor is done sending events to the - ext_workspace_manager_v1. The server will destroy the object - immediately after sending this request. - - - - - - Indicates the client no longer wishes to receive events for new - workspace groups. However the compositor may emit further workspace - events, until the finished event is emitted. The compositor is expected - to send the finished event eventually once the stop request has been processed. - - The client must not send any requests after this one, doing so will raise a wl_display - invalid_object error. - - - - - - - - A ext_workspace_group_handle_v1 object represents a workspace group - that is assigned a set of outputs and contains a number of workspaces. - - The set of outputs assigned to the workspace group is conveyed to the client via - output_enter and output_leave events, and its workspaces are conveyed with - workspace events. - - For example, a compositor which has a set of workspaces for each output may - advertise a workspace group (and its workspaces) per output, whereas a compositor - where a workspace spans all outputs may advertise a single workspace group for all - outputs. - - - - - - - - - This event advertises the capabilities supported by the compositor. If - a capability isn't supported, clients should hide or disable the UI - elements that expose this functionality. For instance, if the - compositor doesn't advertise support for creating workspaces, a button - triggering the create_workspace request should not be displayed. - - The compositor will ignore requests it doesn't support. For instance, - a compositor which doesn't advertise support for creating workspaces will ignore - create_workspace requests. - - Compositors must send this event once after creation of an - ext_workspace_group_handle_v1. When the capabilities change, compositors - must send this event again. - - - - - - - This event is emitted whenever an output is assigned to the workspace - group or a new `wl_output` object is bound by the client, which was already - assigned to this workspace_group. - - - - - - - This event is emitted whenever an output is removed from the workspace - group. - - - - - - - This event is emitted whenever a workspace is assigned to this group. - A workspace may only ever be assigned to a single group at a single point - in time, but can be re-assigned during it's lifetime. - - - - - - - This event is emitted whenever a workspace is removed from this group. - - - - - - - This event is send when the group associated with the ext_workspace_group_handle_v1 - has been removed. After sending this request the compositor will immediately consider - the object inert. Any requests will be ignored except the destroy request. - It is guaranteed there won't be any more events referencing this - ext_workspace_group_handle_v1. - - The compositor must remove all workspaces belonging to a workspace group - via a workspace_leave event before removing the workspace group. - - - - - - Request that the compositor create a new workspace with the given name - and assign it to this group. - - There is no guarantee that the compositor will create a new workspace, - or that the created workspace will have the provided name. - - - - - - - Destroys the ext_workspace_group_handle_v1 object. - - This request should be send either when the client does not want to - use the workspace group object any more or after the removed event to finalize - the destruction of the object. - - - - - - - A ext_workspace_handle_v1 object represents a workspace that handles a - group of surfaces. - - Each workspace has: - - a name, conveyed to the client with the name event - - potentially an id conveyed with the id event - - a list of states, conveyed to the client with the state event - - and optionally a set of coordinates, conveyed to the client with the - coordinates event - - The client may request that the compositor activate or deactivate the workspace. - - Each workspace can belong to only a single workspace group. - Depending on the compositor policy, there might be workspaces with - the same name in different workspace groups, but these workspaces are still - separate (e.g. one of them might be active while the other is not). - - - - - If this event is emitted, it will be send immediately after the - ext_workspace_handle_v1 is created or when an id is assigned to - a workspace (at most once during it's lifetime). - - An id will never change during the lifetime of the `ext_workspace_handle_v1` - and is guaranteed to be unique during it's lifetime. - - Ids are not human-readable and shouldn't be displayed, use `name` for that purpose. - - Compositors are expected to only send ids for workspaces likely stable across multiple - sessions and can be used by clients to store preferences for workspaces. Workspaces without - ids should be considered temporary and any data associated with them should be deleted once - the respective object is lost. - - - - - - - This event is emitted immediately after the ext_workspace_handle_v1 is - created and whenever the name of the workspace changes. - - A name is meant to be human-readable and can be displayed to a user. - Unlike the id it is neither stable nor unique. - - - - - - - This event is used to organize workspaces into an N-dimensional grid - within a workspace group, and if supported, is emitted immediately after - the ext_workspace_handle_v1 is created and whenever the coordinates of - the workspace change. Compositors may not send this event if they do not - conceptually arrange workspaces in this way. If compositors simply - number workspaces, without any geometric interpretation, they may send - 1D coordinates, which clients should not interpret as implying any - geometry. Sending an empty array means that the compositor no longer - orders the workspace geometrically. - - Coordinates have an arbitrary number of dimensions N with an uint32 - position along each dimension. By convention if N > 1, the first - dimension is X, the second Y, the third Z, and so on. The compositor may - chose to utilize these events for a more novel workspace layout - convention, however. No guarantee is made about the grid being filled or - bounded; there may be a workspace at coordinate 1 and another at - coordinate 1000 and none in between. Within a workspace group, however, - workspaces must have unique coordinates of equal dimensionality. - - - - - - - The different states that a workspace can have. - - - - - - - The workspace is not visible in its workspace group, and clients - attempting to visualize the compositor workspace state should not - display such workspaces. - - - - - - - This event is emitted immediately after the ext_workspace_handle_v1 is - created and each time the workspace state changes, either because of a - compositor action or because of a request in this protocol. - - Missing states convey the opposite meaning, e.g. an unset active bit - means the workspace is currently inactive. - - - - - - - - - - - - - - This event advertises the capabilities supported by the compositor. If - a capability isn't supported, clients should hide or disable the UI - elements that expose this functionality. For instance, if the - compositor doesn't advertise support for removing workspaces, a button - triggering the remove request should not be displayed. - - The compositor will ignore requests it doesn't support. For instance, - a compositor which doesn't advertise support for remove will ignore - remove requests. - - Compositors must send this event once after creation of an - ext_workspace_handle_v1 . When the capabilities change, compositors - must send this event again. - - - - - - - This event is send when the workspace associated with the ext_workspace_handle_v1 - has been removed. After sending this request, the compositor will immediately consider - the object inert. Any requests will be ignored except the destroy request. - - It is guaranteed there won't be any more events referencing this - ext_workspace_handle_v1. - - The compositor must only remove a workspaces not currently belonging to any - workspace_group. - - - - - - Destroys the ext_workspace_handle_v1 object. - - This request should be made either when the client does not want to - use the workspace object any more or after the remove event to finalize - the destruction of the object. - - - - - - Request that this workspace be activated. - - There is no guarantee the workspace will be actually activated, and - behaviour may be compositor-dependent. For example, activating a - workspace may or may not deactivate all other workspaces in the same - group. - - - - - - Request that this workspace be deactivated. - - There is no guarantee the workspace will be actually deactivated. - - - - - - Requests that this workspace is assigned to the given workspace group. - - There is no guarantee the workspace will be assigned. - - - - - - - Request that this workspace be removed. - - There is no guarantee the workspace will be actually removed. - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/keyboard-shortcuts-inhibit-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/keyboard-shortcuts-inhibit-unstable-v1.xml deleted file mode 100644 index 2774876..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/keyboard-shortcuts-inhibit-unstable-v1.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Copyright © 2017 Red Hat Inc. - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - - - This protocol specifies a way for a client to request the compositor - to ignore its own keyboard shortcuts for a given seat, so that all - key events from that seat get forwarded to a surface. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible - changes may be added together with the corresponding interface - version bump. - Backward incompatible changes are done by bumping the version - number in the protocol and interface names and resetting the - interface version. Once the protocol is to be declared stable, - the 'z' prefix and the version number in the protocol and - interface names are removed and the interface version number is - reset. - - - - - A global interface used for inhibiting the compositor keyboard shortcuts. - - - - - Destroy the keyboard shortcuts inhibitor manager. - - - - - - Create a new keyboard shortcuts inhibitor object associated with - the given surface for the given seat. - - If shortcuts are already inhibited for the specified seat and surface, - a protocol error "already_inhibited" is raised by the compositor. - - - - - - - - - - - - - - A keyboard shortcuts inhibitor instructs the compositor to ignore - its own keyboard shortcuts when the associated surface has keyboard - focus. As a result, when the surface has keyboard focus on the given - seat, it will receive all key events originating from the specified - seat, even those which would normally be caught by the compositor for - its own shortcuts. - - The Wayland compositor is however under no obligation to disable - all of its shortcuts, and may keep some special key combo for its own - use, including but not limited to one allowing the user to forcibly - restore normal keyboard events routing in the case of an unwilling - client. The compositor may also use the same key combo to reactivate - an existing shortcut inhibitor that was previously deactivated on - user request. - - When the compositor restores its own keyboard shortcuts, an - "inactive" event is emitted to notify the client that the keyboard - shortcuts inhibitor is not effectively active for the surface and - seat any more, and the client should not expect to receive all - keyboard events. - - When the keyboard shortcuts inhibitor is inactive, the client has - no way to forcibly reactivate the keyboard shortcuts inhibitor. - - The user can chose to re-enable a previously deactivated keyboard - shortcuts inhibitor using any mechanism the compositor may offer, - in which case the compositor will send an "active" event to notify - the client. - - If the surface is destroyed, unmapped, or loses the seat's keyboard - focus, the keyboard shortcuts inhibitor becomes irrelevant and the - compositor will restore its own keyboard shortcuts but no "inactive" - event is emitted in this case. - - - - - Remove the keyboard shortcuts inhibitor from the associated wl_surface. - - - - - - This event indicates that the shortcut inhibitor is active. - - The compositor sends this event every time compositor shortcuts - are inhibited on behalf of the surface. When active, the client - may receive input events normally reserved by the compositor - (see zwp_keyboard_shortcuts_inhibitor_v1). - - This occurs typically when the initial request "inhibit_shortcuts" - first becomes active or when the user instructs the compositor to - re-enable and existing shortcuts inhibitor using any mechanism - offered by the compositor. - - - - - - This event indicates that the shortcuts inhibitor is inactive, - normal shortcuts processing is restored by the compositor. - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-gamma-control-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-gamma-control-unstable-v1.xml deleted file mode 100644 index 16e0be8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-gamma-control-unstable-v1.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - Copyright © 2015 Giulio camuffo - Copyright © 2018 Simon Ser - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - This protocol allows a privileged client to set the gamma tables for - outputs. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - - - - This interface is a manager that allows creating per-output gamma - controls. - - - - - Create a gamma control that can be used to adjust gamma tables for the - provided output. - - - - - - - - All objects created by the manager will still remain valid, until their - appropriate destroy request has been called. - - - - - - - This interface allows a client to adjust gamma tables for a particular - output. - - The client will receive the gamma size, and will then be able to set gamma - tables. At any time the compositor can send a failed event indicating that - this object is no longer valid. - - There can only be at most one gamma control object per output, which - has exclusive access to this particular output. When the gamma control - object is destroyed, the gamma table is restored to its original value. - - - - - Advertise the size of each gamma ramp. - - This event is sent immediately when the gamma control object is created. - - - - - - - - - - - Set the gamma table. The file descriptor can be memory-mapped to provide - the raw gamma table, which contains successive gamma ramps for the red, - green and blue channels. Each gamma ramp is an array of 16-byte unsigned - integers which has the same length as the gamma size. - - The file descriptor data must have the same length as three times the - gamma size. - - - - - - - This event indicates that the gamma control is no longer valid. This - can happen for a number of reasons, including: - - The output doesn't support gamma tables - - Setting the gamma tables failed - - Another client already has exclusive gamma control for this output - - The compositor has transferred gamma control to another client - - Upon receiving this event, the client should destroy this object. - - - - - - Destroys the gamma control object. If the object is still valid, this - restores the original gamma tables. - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-layer-shell-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-layer-shell-unstable-v1.xml deleted file mode 100644 index e9f27e4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-layer-shell-unstable-v1.xml +++ /dev/null @@ -1,407 +0,0 @@ - - - - Copyright © 2017 Drew DeVault - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - Clients can use this interface to assign the surface_layer role to - wl_surfaces. Such surfaces are assigned to a "layer" of the output and - rendered with a defined z-depth respective to each other. They may also be - anchored to the edges and corners of a screen and specify input handling - semantics. This interface should be suitable for the implementation of - many desktop shell components, and a broad number of other applications - that interact with the desktop. - - - - - Create a layer surface for an existing surface. This assigns the role of - layer_surface, or raises a protocol error if another role is already - assigned. - - Creating a layer surface from a wl_surface which has a buffer attached - or committed is a client error, and any attempts by a client to attach - or manipulate a buffer prior to the first layer_surface.configure call - must also be treated as errors. - - After creating a layer_surface object and setting it up, the client - must perform an initial commit without any buffer attached. - The compositor will reply with a layer_surface.configure event. - The client must acknowledge it and is then allowed to attach a buffer - to map the surface. - - You may pass NULL for output to allow the compositor to decide which - output to use. Generally this will be the one that the user most - recently interacted with. - - Clients can specify a namespace that defines the purpose of the layer - surface. - - - - - - - - - - - - - - - - - These values indicate which layers a surface can be rendered in. They - are ordered by z depth, bottom-most first. Traditional shell surfaces - will typically be rendered between the bottom and top layers. - Fullscreen shell surfaces are typically rendered at the top layer. - Multiple surfaces can share a single layer, and ordering within a - single layer is undefined. - - - - - - - - - - - - - This request indicates that the client will not use the layer_shell - object any more. Objects that have been created through this instance - are not affected. - - - - - - - An interface that may be implemented by a wl_surface, for surfaces that - are designed to be rendered as a layer of a stacked desktop-like - environment. - - Layer surface state (layer, size, anchor, exclusive zone, - margin, interactivity) is double-buffered, and will be applied at the - time wl_surface.commit of the corresponding wl_surface is called. - - Attaching a null buffer to a layer surface unmaps it. - - Unmapping a layer_surface means that the surface cannot be shown by the - compositor until it is explicitly mapped again. The layer_surface - returns to the state it had right after layer_shell.get_layer_surface. - The client can re-map the surface by performing a commit without any - buffer attached, waiting for a configure event and handling it as usual. - - - - - Sets the size of the surface in surface-local coordinates. The - compositor will display the surface centered with respect to its - anchors. - - If you pass 0 for either value, the compositor will assign it and - inform you of the assignment in the configure event. You must set your - anchor to opposite edges in the dimensions you omit; not doing so is a - protocol error. Both values are 0 by default. - - Size is double-buffered, see wl_surface.commit. - - - - - - - - Requests that the compositor anchor the surface to the specified edges - and corners. If two orthogonal edges are specified (e.g. 'top' and - 'left'), then the anchor point will be the intersection of the edges - (e.g. the top left corner of the output); otherwise the anchor point - will be centered on that edge, or in the center if none is specified. - - Anchor is double-buffered, see wl_surface.commit. - - - - - - - Requests that the compositor avoids occluding an area with other - surfaces. The compositor's use of this information is - implementation-dependent - do not assume that this region will not - actually be occluded. - - A positive value is only meaningful if the surface is anchored to one - edge or an edge and both perpendicular edges. If the surface is not - anchored, anchored to only two perpendicular edges (a corner), anchored - to only two parallel edges or anchored to all edges, a positive value - will be treated the same as zero. - - A positive zone is the distance from the edge in surface-local - coordinates to consider exclusive. - - Surfaces that do not wish to have an exclusive zone may instead specify - how they should interact with surfaces that do. If set to zero, the - surface indicates that it would like to be moved to avoid occluding - surfaces with a positive exclusive zone. If set to -1, the surface - indicates that it would not like to be moved to accommodate for other - surfaces, and the compositor should extend it all the way to the edges - it is anchored to. - - For example, a panel might set its exclusive zone to 10, so that - maximized shell surfaces are not shown on top of it. A notification - might set its exclusive zone to 0, so that it is moved to avoid - occluding the panel, but shell surfaces are shown underneath it. A - wallpaper or lock screen might set their exclusive zone to -1, so that - they stretch below or over the panel. - - The default value is 0. - - Exclusive zone is double-buffered, see wl_surface.commit. - - - - - - - Requests that the surface be placed some distance away from the anchor - point on the output, in surface-local coordinates. Setting this value - for edges you are not anchored to has no effect. - - The exclusive zone includes the margin. - - Margin is double-buffered, see wl_surface.commit. - - - - - - - - - - Types of keyboard interaction possible for layer shell surfaces. The - rationale for this is twofold: (1) some applications are not interested - in keyboard events and not allowing them to be focused can improve the - desktop experience; (2) some applications will want to take exclusive - keyboard focus. - - - - - This value indicates that this surface is not interested in keyboard - events and the compositor should never assign it the keyboard focus. - - This is the default value, set for newly created layer shell surfaces. - - This is useful for e.g. desktop widgets that display information or - only have interaction with non-keyboard input devices. - - - - - Request exclusive keyboard focus if this surface is above the shell surface layer. - - For the top and overlay layers, the seat will always give - exclusive keyboard focus to the top-most layer which has keyboard - interactivity set to exclusive. If this layer contains multiple - surfaces with keyboard interactivity set to exclusive, the compositor - determines the one receiving keyboard events in an implementation- - defined manner. In this case, no guarantee is made when this surface - will receive keyboard focus (if ever). - - For the bottom and background layers, the compositor is allowed to use - normal focus semantics. - - This setting is mainly intended for applications that need to ensure - they receive all keyboard events, such as a lock screen or a password - prompt. - - - - - This requests the compositor to allow this surface to be focused and - unfocused by the user in an implementation-defined manner. The user - should be able to unfocus this surface even regardless of the layer - it is on. - - Typically, the compositor will want to use its normal mechanism to - manage keyboard focus between layer shell surfaces with this setting - and regular toplevels on the desktop layer (e.g. click to focus). - Nevertheless, it is possible for a compositor to require a special - interaction to focus or unfocus layer shell surfaces (e.g. requiring - a click even if focus follows the mouse normally, or providing a - keybinding to switch focus between layers). - - This setting is mainly intended for desktop shell components (e.g. - panels) that allow keyboard interaction. Using this option can allow - implementing a desktop shell that can be fully usable without the - mouse. - - - - - - - Set how keyboard events are delivered to this surface. By default, - layer shell surfaces do not receive keyboard events; this request can - be used to change this. - - This setting is inherited by child surfaces set by the get_popup - request. - - Layer surfaces receive pointer, touch, and tablet events normally. If - you do not want to receive them, set the input region on your surface - to an empty region. - - Keyboard interactivity is double-buffered, see wl_surface.commit. - - - - - - - This assigns an xdg_popup's parent to this layer_surface. This popup - should have been created via xdg_surface::get_popup with the parent set - to NULL, and this request must be invoked before committing the popup's - initial state. - - See the documentation of xdg_popup for more details about what an - xdg_popup is and how it is used. - - - - - - - When a configure event is received, if a client commits the - surface in response to the configure event, then the client - must make an ack_configure request sometime before the commit - request, passing along the serial of the configure event. - - If the client receives multiple configure events before it - can respond to one, it only has to ack the last configure event. - - A client is not required to commit immediately after sending - an ack_configure request - it may even ack_configure several times - before its next surface commit. - - A client may send multiple ack_configure requests before committing, but - only the last request sent before a commit indicates which configure - event the client really is responding to. - - - - - - - This request destroys the layer surface. - - - - - - The configure event asks the client to resize its surface. - - Clients should arrange their surface for the new states, and then send - an ack_configure request with the serial sent in this configure event at - some point before committing the new surface. - - The client is free to dismiss all but the last configure event it - received. - - The width and height arguments specify the size of the window in - surface-local coordinates. - - The size is a hint, in the sense that the client is free to ignore it if - it doesn't resize, pick a smaller size (to satisfy aspect ratio or - resize in steps of NxM pixels). If the client picks a smaller size and - is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the - surface will be centered on this axis. - - If the width or height arguments are zero, it means the client should - decide its own window dimension. - - - - - - - - - The closed event is sent by the compositor when the surface will no - longer be shown. The output may have been destroyed or the user may - have asked for it to be removed. Further changes to the surface will be - ignored. The client should destroy the resource after receiving this - event, and create a new surface if they so choose. - - - - - - - - - - - - - - - - - - - - - - - Change the layer that the surface is rendered on. - - Layer is double-buffered, see wl_surface.commit. - - - - - - - - - Requests an edge for the exclusive zone to apply. The exclusive - edge will be automatically deduced from anchor points when possible, - but when the surface is anchored to a corner, it will be necessary - to set it explicitly to disambiguate, as it is not possible to deduce - which one of the two corner edges should be used. - - The edge must be one the surface is anchored to, otherwise the - invalid_exclusive_edge protocol error will be raised. - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-management-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-management-unstable-v1.xml deleted file mode 100644 index 541284a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-management-unstable-v1.xml +++ /dev/null @@ -1,611 +0,0 @@ - - - - Copyright © 2019 Purism SPC - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - This protocol exposes interfaces to obtain and modify output device - configuration. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - - - - This interface is a manager that allows reading and writing the current - output device configuration. - - Output devices that display pixels (e.g. a physical monitor or a virtual - output in a window) are represented as heads. Heads cannot be created nor - destroyed by the client, but they can be enabled or disabled and their - properties can be changed. Each head may have one or more available modes. - - Whenever a head appears (e.g. a monitor is plugged in), it will be - advertised via the head event. Immediately after the output manager is - bound, all current heads are advertised. - - Whenever a head's properties change, the relevant wlr_output_head events - will be sent. Not all head properties will be sent: only properties that - have changed need to. - - Whenever a head disappears (e.g. a monitor is unplugged), a - wlr_output_head.finished event will be sent. - - After one or more heads appear, change or disappear, the done event will - be sent. It carries a serial which can be used in a create_configuration - request to update heads properties. - - The information obtained from this protocol should only be used for output - configuration purposes. This protocol is not designed to be a generic - output property advertisement protocol for regular clients. Instead, - protocols such as xdg-output should be used. - - - - - This event introduces a new head. This happens whenever a new head - appears (e.g. a monitor is plugged in) or after the output manager is - bound. - - - - - - - This event is sent after all information has been sent after binding to - the output manager object and after any subsequent changes. This applies - to child head and mode objects as well. In other words, this event is - sent whenever a head or mode is created or destroyed and whenever one of - their properties has been changed. Not all state is re-sent each time - the current configuration changes: only the actual changes are sent. - - This allows changes to the output configuration to be seen as atomic, - even if they happen via multiple events. - - A serial is sent to be used in a future create_configuration request. - - - - - - - Create a new output configuration object. This allows to update head - properties. - - - - - - - - Indicates the client no longer wishes to receive events for output - configuration changes. However the compositor may emit further events, - until the finished event is emitted. - - The client must not send any more requests after this one. - - - - - - This event indicates that the compositor is done sending manager events. - The compositor will destroy the object immediately after sending this - event, so it will become invalid and the client should release any - resources associated with it. - - - - - - - A head is an output device. The difference between a wl_output object and - a head is that heads are advertised even if they are turned off. A head - object only advertises properties and cannot be used directly to change - them. - - A head has some read-only properties: modes, name, description and - physical_size. These cannot be changed by clients. - - Other properties can be updated via a wlr_output_configuration object. - - Properties sent via this interface are applied atomically via the - wlr_output_manager.done event. No guarantees are made regarding the order - in which properties are sent. - - - - - This event describes the head name. - - The naming convention is compositor defined, but limited to alphanumeric - characters and dashes (-). Each name is unique among all wlr_output_head - objects, but if a wlr_output_head object is destroyed the same name may - be reused later. The names will also remain consistent across sessions - with the same hardware and software configuration. - - Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do - not assume that the name is a reflection of an underlying DRM - connector, X11 connection, etc. - - If this head matches a wl_output, the wl_output.name event must report - the same name. - - The name event is sent after a wlr_output_head object is created. This - event is only sent once per object, and the name does not change over - the lifetime of the wlr_output_head object. - - - - - - - This event describes a human-readable description of the head. - - The description is a UTF-8 string with no convention defined for its - contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11 - output via :1'. However, do not assume that the name is a reflection of - the make, model, serial of the underlying DRM connector or the display - name of the underlying X11 connection, etc. - - If this head matches a wl_output, the wl_output.description event must - report the same name. - - The description event is sent after a wlr_output_head object is created. - This event is only sent once per object, and the description does not - change over the lifetime of the wlr_output_head object. - - - - - - - This event describes the physical size of the head. This event is only - sent if the head has a physical size (e.g. is not a projector or a - virtual device). - - The physical size event is sent after a wlr_output_head object is created. This - event is only sent once per object, and the physical size does not change over - the lifetime of the wlr_output_head object. - - - - - - - - This event introduces a mode for this head. It is sent once per - supported mode. - - - - - - - This event describes whether the head is enabled. A disabled head is not - mapped to a region of the global compositor space. - - When a head is disabled, some properties (current_mode, position, - transform and scale) are irrelevant. - - - - - - - This event describes the mode currently in use for this head. It is only - sent if the output is enabled. - - - - - - - This events describes the position of the head in the global compositor - space. It is only sent if the output is enabled. - - - - - - - - This event describes the transformation currently applied to the head. - It is only sent if the output is enabled. - - - - - - - This events describes the scale of the head in the global compositor - space. It is only sent if the output is enabled. - - - - - - - This event indicates that the head is no longer available. The head - object becomes inert. Clients should send a destroy request and release - any resources associated with it. - - - - - - - - This event describes the manufacturer of the head. - - Together with the model and serial_number events the purpose is to - allow clients to recognize heads from previous sessions and for example - load head-specific configurations back. - - It is not guaranteed this event will be ever sent. A reason for that - can be that the compositor does not have information about the make of - the head or the definition of a make is not sensible in the current - setup, for example in a virtual session. Clients can still try to - identify the head by available information from other events but should - be aware that there is an increased risk of false positives. - - If sent, the make event is sent after a wlr_output_head object is - created and only sent once per object. The make does not change over - the lifetime of the wlr_output_head object. - - It is not recommended to display the make string in UI to users. For - that the string provided by the description event should be preferred. - - - - - - - This event describes the model of the head. - - Together with the make and serial_number events the purpose is to - allow clients to recognize heads from previous sessions and for example - load head-specific configurations back. - - It is not guaranteed this event will be ever sent. A reason for that - can be that the compositor does not have information about the model of - the head or the definition of a model is not sensible in the current - setup, for example in a virtual session. Clients can still try to - identify the head by available information from other events but should - be aware that there is an increased risk of false positives. - - If sent, the model event is sent after a wlr_output_head object is - created and only sent once per object. The model does not change over - the lifetime of the wlr_output_head object. - - It is not recommended to display the model string in UI to users. For - that the string provided by the description event should be preferred. - - - - - - - This event describes the serial number of the head. - - Together with the make and model events the purpose is to allow clients - to recognize heads from previous sessions and for example load head- - specific configurations back. - - It is not guaranteed this event will be ever sent. A reason for that - can be that the compositor does not have information about the serial - number of the head or the definition of a serial number is not sensible - in the current setup. Clients can still try to identify the head by - available information from other events but should be aware that there - is an increased risk of false positives. - - If sent, the serial number event is sent after a wlr_output_head object - is created and only sent once per object. The serial number does not - change over the lifetime of the wlr_output_head object. - - It is not recommended to display the serial_number string in UI to - users. For that the string provided by the description event should be - preferred. - - - - - - - - - This request indicates that the client will no longer use this head - object. - - - - - - - - - - - - - This event describes whether adaptive sync is currently enabled for - the head or not. Adaptive sync is also known as Variable Refresh - Rate or VRR. - - - - - - - - This object describes an output mode. - - Some heads don't support output modes, in which case modes won't be - advertised. - - Properties sent via this interface are applied atomically via the - wlr_output_manager.done event. No guarantees are made regarding the order - in which properties are sent. - - - - - This event describes the mode size. The size is given in physical - hardware units of the output device. This is not necessarily the same as - the output size in the global compositor space. For instance, the output - may be scaled or transformed. - - - - - - - - This event describes the mode's fixed vertical refresh rate. It is only - sent if the mode has a fixed refresh rate. - - - - - - - This event advertises this mode as preferred. - - - - - - This event indicates that the mode is no longer available. The mode - object becomes inert. Clients should send a destroy request and release - any resources associated with it. - - - - - - - - This request indicates that the client will no longer use this mode - object. - - - - - - - This object is used by the client to describe a full output configuration. - - First, the client needs to setup the output configuration. Each head can - be either enabled (and configured) or disabled. It is a protocol error to - send two enable_head or disable_head requests with the same head. It is a - protocol error to omit a head in a configuration. - - Then, the client can apply or test the configuration. The compositor will - then reply with a succeeded, failed or cancelled event. Finally the client - should destroy the configuration object. - - - - - - - - - - - Enable a head. This request creates a head configuration object that can - be used to change the head's properties. - - - - - - - - Disable a head. - - - - - - - Apply the new output configuration. - - In case the configuration is successfully applied, there is no guarantee - that the new output state matches completely the requested - configuration. For instance, a compositor might round the scale if it - doesn't support fractional scaling. - - After this request has been sent, the compositor must respond with an - succeeded, failed or cancelled event. Sending a request that isn't the - destructor is a protocol error. - - - - - - Test the new output configuration. The configuration won't be applied, - but will only be validated. - - Even if the compositor succeeds to test a configuration, applying it may - fail. - - After this request has been sent, the compositor must respond with an - succeeded, failed or cancelled event. Sending a request that isn't the - destructor is a protocol error. - - - - - - Sent after the compositor has successfully applied the changes or - tested them. - - Upon receiving this event, the client should destroy this object. - - If the current configuration has changed, events to describe the changes - will be sent followed by a wlr_output_manager.done event. - - - - - - Sent if the compositor rejects the changes or failed to apply them. The - compositor should revert any changes made by the apply request that - triggered this event. - - Upon receiving this event, the client should destroy this object. - - - - - - Sent if the compositor cancels the configuration because the state of an - output changed and the client has outdated information (e.g. after an - output has been hotplugged). - - The client can create a new configuration with a newer serial and try - again. - - Upon receiving this event, the client should destroy this object. - - - - - - Using this request a client can tell the compositor that it is not going - to use the configuration object anymore. Any changes to the outputs - that have not been applied will be discarded. - - This request also destroys wlr_output_configuration_head objects created - via this object. - - - - - - - This object is used by the client to update a single head's configuration. - - It is a protocol error to set the same property twice. - - - - - - - - - - - - - - This request sets the head's mode. - - - - - - - This request assigns a custom mode to the head. The size is given in - physical hardware units of the output device. If set to zero, the - refresh rate is unspecified. - - It is a protocol error to set both a mode and a custom mode. - - - - - - - - - This request sets the head's position in the global compositor space. - - - - - - - - This request sets the head's transform. - - - - - - - This request sets the head's scale. - - - - - - - - - This request enables/disables adaptive sync. Adaptive sync is also - known as Variable Refresh Rate or VRR. - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-power-management-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-power-management-unstable-v1.xml deleted file mode 100644 index 20dbb77..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-output-power-management-unstable-v1.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - Copyright © 2019 Purism SPC - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - - - This protocol allows clients to control power management modes - of outputs that are currently part of the compositor space. The - intent is to allow special clients like desktop shells to power - down outputs when the system is idle. - - To modify outputs not currently part of the compositor space see - wlr-output-management. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - - - - This interface is a manager that allows creating per-output power - management mode controls. - - - - - Create an output power management mode control that can be used to - adjust the power management mode for a given output. - - - - - - - - All objects created by the manager will still remain valid, until their - appropriate destroy request has been called. - - - - - - - This object offers requests to set the power management mode of - an output. - - - - - - - - - - - - - - Set an output's power save mode to the given mode. The mode change - is effective immediately. If the output does not support the given - mode a failed event is sent. - - - - - - - Report the power management mode change of an output. - - The mode event is sent after an output changed its power - management mode. The reason can be a client using set_mode or the - compositor deciding to change an output's mode. - This event is also sent immediately when the object is created - so the client is informed about the current power management mode. - - - - - - - This event indicates that the output power management mode control - is no longer valid. This can happen for a number of reasons, - including: - - The output doesn't support power management - - Another client already has exclusive power management mode control - for this output - - The output disappeared - - Upon receiving this event, the client should destroy this object. - - - - - - Destroys the output power management mode control object. - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-screencopy-unstable-v1.xml b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-screencopy-unstable-v1.xml deleted file mode 100644 index 8b20661..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/proto/xml/wlr-screencopy-unstable-v1.xml +++ /dev/null @@ -1,234 +0,0 @@ - - - - Copyright © 2018 Simon Ser - Copyright © 2019 Andri Yngvason - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - - - This protocol allows clients to ask the compositor to copy part of the - screen content to a client buffer. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - Note! This protocol is deprecated and not intended for production use. - The ext-image-copy-capture-v1 protocol should be used instead. - - - - - This object is a manager which offers requests to start capturing from a - source. - - - - - Capture the next frame of an entire output. - - - - - - - - - Capture the next frame of an output's region. - - The region is given in output logical coordinates, see - xdg_output.logical_size. The region will be clipped to the output's - extents. - - - - - - - - - - - - - All objects created by the manager will still remain valid, until their - appropriate destroy request has been called. - - - - - - - This object represents a single frame. - - When created, a series of buffer events will be sent, each representing a - supported buffer type. The "buffer_done" event is sent afterwards to - indicate that all supported buffer types have been enumerated. The client - will then be able to send a "copy" request. If the capture is successful, - the compositor will send a "flags" event followed by a "ready" event. - - For objects version 2 or lower, wl_shm buffers are always supported, ie. - the "buffer" event is guaranteed to be sent. - - If the capture failed, the "failed" event is sent. This can happen anytime - before the "ready" event. - - Once either a "ready" or a "failed" event is received, the client should - destroy the frame. - - - - - Provides information about wl_shm buffer parameters that need to be - used for this frame. This event is sent once after the frame is created - if wl_shm buffers are supported. - - - - - - - - - - Copy the frame to the supplied buffer. The buffer must have the - correct size, see zwlr_screencopy_frame_v1.buffer and - zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a - supported format. - - If the frame is successfully copied, "flags" and "ready" events are - sent. Otherwise, a "failed" event is sent. - - - - - - - - - - - - - - - - Provides flags about the frame. This event is sent once before the - "ready" event. - - - - - - - Called as soon as the frame is copied, indicating it is available - for reading. This event includes the time at which the presentation took place. - - The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, - each component being an unsigned 32-bit value. Whole seconds are in - tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, - and the additional fractional part in tv_nsec as nanoseconds. Hence, - for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part - may have an arbitrary offset at start. - - After receiving this event, the client should destroy the object. - - - - - - - - - This event indicates that the attempted frame copy has failed. - - After receiving this event, the client should destroy the object. - - - - - - Destroys the frame. This request can be sent at any time by the client. - - - - - - - Same as copy, except it waits until there is damage to copy. - - - - - - - This event is sent right before the ready event when copy_with_damage is - requested. It may be generated multiple times for each copy_with_damage - request. - - The arguments describe a box around an area that has changed since the - last copy request that was derived from the current screencopy manager - instance. - - The union of all regions received between the call to copy_with_damage - and a ready event is the total damage since the prior ready event. - - - - - - - - - - - Provides information about linux-dmabuf buffer parameters that need to - be used for this frame. This event is sent once after the frame is - created if linux-dmabuf buffers are supported. - - - - - - - - - This event is sent once after all buffer events have been sent. - - The client should proceed to create a buffer of one of the supported - types, and send a "copy" request. - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/compositor.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/compositor.go deleted file mode 100644 index 9bd5f0e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/compositor.go +++ /dev/null @@ -1,694 +0,0 @@ -package screenshot - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management" - wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type Compositor int - -const ( - CompositorUnknown Compositor = iota - CompositorHyprland - CompositorSway - CompositorNiri - CompositorDWL - CompositorScroll - CompositorMiracle -) - -var detectedCompositor Compositor = -1 - -func DetectCompositor() Compositor { - if detectedCompositor >= 0 { - return detectedCompositor - } - - hyprlandSig := os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") - niriSocket := os.Getenv("NIRI_SOCKET") - swaySocket := os.Getenv("SWAYSOCK") - scrollSocket := os.Getenv("SCROLLSOCK") - miracleSocket := os.Getenv("MIRACLESOCK") - - switch { - case niriSocket != "": - if _, err := os.Stat(niriSocket); err == nil { - detectedCompositor = CompositorNiri - return detectedCompositor - } - case scrollSocket != "": - if _, err := os.Stat(scrollSocket); err == nil { - detectedCompositor = CompositorScroll - return detectedCompositor - } - case miracleSocket != "": - if _, err := os.Stat(miracleSocket); err == nil { - detectedCompositor = CompositorMiracle - return detectedCompositor - } - case swaySocket != "": - if _, err := os.Stat(swaySocket); err == nil { - detectedCompositor = CompositorSway - return detectedCompositor - } - case hyprlandSig != "": - detectedCompositor = CompositorHyprland - return detectedCompositor - } - - if detectDWLProtocol() { - detectedCompositor = CompositorDWL - return detectedCompositor - } - - detectedCompositor = CompositorUnknown - return detectedCompositor -} - -func detectDWLProtocol() bool { - display, err := client.Connect("") - if err != nil { - return false - } - ctx := display.Context() - defer ctx.Close() - - registry, err := display.GetRegistry() - if err != nil { - return false - } - - found := false - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - if e.Interface == dwl_ipc.ZdwlIpcManagerV2InterfaceName { - found = true - } - }) - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return false - } - - return found -} - -func SetCompositorDWL() { - detectedCompositor = CompositorDWL -} - -type WindowGeometry struct { - X int32 - Y int32 - Width int32 - Height int32 - Output string - Scale float64 - OutputX int32 - OutputY int32 - OutputTransform int32 -} - -func GetActiveWindow() (*WindowGeometry, error) { - switch DetectCompositor() { - case CompositorHyprland: - return getHyprlandActiveWindow() - case CompositorDWL: - return getDWLActiveWindow() - default: - return nil, fmt.Errorf("window capture requires Hyprland or DWL") - } -} - -type hyprlandWindow struct { - At [2]int32 `json:"at"` - Size [2]int32 `json:"size"` -} - -func getHyprlandActiveWindow() (*WindowGeometry, error) { - output, err := exec.Command("hyprctl", "-j", "activewindow").Output() - if err != nil { - return nil, fmt.Errorf("hyprctl activewindow: %w", err) - } - - var win hyprlandWindow - if err := json.Unmarshal(output, &win); err != nil { - return nil, fmt.Errorf("parse activewindow: %w", err) - } - - if win.Size[0] <= 0 || win.Size[1] <= 0 { - return nil, fmt.Errorf("no active window") - } - - return &WindowGeometry{ - X: win.At[0], - Y: win.At[1], - Width: win.Size[0], - Height: win.Size[1], - }, nil -} - -type hyprlandMonitor struct { - Name string `json:"name"` - X int32 `json:"x"` - Y int32 `json:"y"` - Width int32 `json:"width"` - Height int32 `json:"height"` - Scale float64 `json:"scale"` - Focused bool `json:"focused"` -} - -func GetHyprlandMonitorScale(name string) float64 { - output, err := exec.Command("hyprctl", "-j", "monitors").Output() - if err != nil { - return 0 - } - - var monitors []hyprlandMonitor - if err := json.Unmarshal(output, &monitors); err != nil { - return 0 - } - - for _, m := range monitors { - if m.Name == name { - return m.Scale - } - } - return 0 -} - -func getHyprlandFocusedMonitor() string { - output, err := exec.Command("hyprctl", "-j", "monitors").Output() - if err != nil { - return "" - } - - var monitors []hyprlandMonitor - if err := json.Unmarshal(output, &monitors); err != nil { - return "" - } - - for _, m := range monitors { - if m.Focused { - return m.Name - } - } - return "" -} - -func GetHyprlandMonitorGeometry(name string) (x, y, w, h int32, ok bool) { - output, err := exec.Command("hyprctl", "-j", "monitors").Output() - if err != nil { - return 0, 0, 0, 0, false - } - - var monitors []hyprlandMonitor - if err := json.Unmarshal(output, &monitors); err != nil { - return 0, 0, 0, 0, false - } - - for _, m := range monitors { - if m.Name == name { - logicalW := int32(float64(m.Width) / m.Scale) - logicalH := int32(float64(m.Height) / m.Scale) - return m.X, m.Y, logicalW, logicalH, true - } - } - return 0, 0, 0, 0, false -} - -type swayWorkspace struct { - Output string `json:"output"` - Focused bool `json:"focused"` -} - -func getSwayFocusedMonitor() string { - output, err := exec.Command("swaymsg", "-t", "get_workspaces").Output() - if err != nil { - return "" - } - - var workspaces []swayWorkspace - if err := json.Unmarshal(output, &workspaces); err != nil { - return "" - } - - for _, ws := range workspaces { - if ws.Focused { - return ws.Output - } - } - return "" -} - -func getScrollFocusedMonitor() string { - output, err := exec.Command("scrollmsg", "-t", "get_workspaces").Output() - if err != nil { - return "" - } - - var workspaces []swayWorkspace - if err := json.Unmarshal(output, &workspaces); err != nil { - return "" - } - - for _, ws := range workspaces { - if ws.Focused { - return ws.Output - } - } - return "" -} - -func getMiracleFocusedMonitor() string { - output, err := exec.Command("miraclemsg", "-t", "get_workspaces").Output() - if err != nil { - return "" - } - - var workspaces []swayWorkspace - if err := json.Unmarshal(output, &workspaces); err != nil { - return "" - } - - for _, ws := range workspaces { - if ws.Focused { - return ws.Output - } - } - return "" -} - -type niriWorkspace struct { - Output string `json:"output"` - IsFocused bool `json:"is_focused"` -} - -func getNiriFocusedMonitor() string { - output, err := exec.Command("niri", "msg", "-j", "workspaces").Output() - if err != nil { - return "" - } - - var workspaces []niriWorkspace - if err := json.Unmarshal(output, &workspaces); err != nil { - return "" - } - - for _, ws := range workspaces { - if ws.IsFocused { - return ws.Output - } - } - return "" -} - -var dwlActiveOutput string - -func SetDWLActiveOutput(name string) { - dwlActiveOutput = name -} - -func getDWLFocusedMonitor() string { - if dwlActiveOutput != "" { - return dwlActiveOutput - } - return queryDWLActiveOutput() -} - -func queryDWLActiveOutput() string { - display, err := client.Connect("") - if err != nil { - return "" - } - ctx := display.Context() - defer ctx.Close() - - registry, err := display.GetRegistry() - if err != nil { - return "" - } - - var dwlManager *dwl_ipc.ZdwlIpcManagerV2 - outputs := make(map[uint32]*client.Output) - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - switch e.Interface { - case dwl_ipc.ZdwlIpcManagerV2InterfaceName: - mgr := dwl_ipc.NewZdwlIpcManagerV2(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil { - dwlManager = mgr - } - case client.OutputInterfaceName: - out := client.NewOutput(ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := registry.Bind(e.Name, e.Interface, version, out); err == nil { - outputs[e.Name] = out - } - } - }) - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return "" - } - - if dwlManager == nil || len(outputs) == 0 { - return "" - } - - outputNames := make(map[uint32]string) - for name, out := range outputs { - n := name - out.SetNameHandler(func(e client.OutputNameEvent) { - outputNames[n] = e.Name - }) - } - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return "" - } - - type outputState struct { - name string - active bool - gotFrame bool - } - states := make(map[uint32]*outputState) - - for name, out := range outputs { - dwlOut, err := dwlManager.GetOutput(out) - if err != nil { - continue - } - state := &outputState{name: outputNames[name]} - states[name] = state - - dwlOut.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) { - state.active = e.Active != 0 - }) - dwlOut.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) { - state.gotFrame = true - }) - } - - allFramesReceived := func() bool { - for _, s := range states { - if !s.gotFrame { - return false - } - } - return true - } - - for !allFramesReceived() { - if err := ctx.Dispatch(); err != nil { - return "" - } - } - - for _, state := range states { - if state.active { - return state.name - } - } - - return "" -} - -func GetFocusedMonitor() string { - switch DetectCompositor() { - case CompositorHyprland: - return getHyprlandFocusedMonitor() - case CompositorSway: - return getSwayFocusedMonitor() - case CompositorScroll: - return getScrollFocusedMonitor() - case CompositorMiracle: - return getMiracleFocusedMonitor() - case CompositorNiri: - return getNiriFocusedMonitor() - case CompositorDWL: - return getDWLFocusedMonitor() - } - return "" -} - -type outputInfo struct { - x, y int32 - scale float64 - transform int32 -} - -func getAllOutputInfos() map[string]*outputInfo { - display, err := client.Connect("") - if err != nil { - return nil - } - ctx := display.Context() - defer ctx.Close() - - registry, err := display.GetRegistry() - if err != nil { - return nil - } - - var outputManager *wlr_output_management.ZwlrOutputManagerV1 - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - if e.Interface == wlr_output_management.ZwlrOutputManagerV1InterfaceName { - mgr := wlr_output_management.NewZwlrOutputManagerV1(ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := registry.Bind(e.Name, e.Interface, version, mgr); err == nil { - outputManager = mgr - } - } - }) - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return nil - } - - if outputManager == nil { - return nil - } - - type headState struct { - name string - x, y int32 - scale float64 - transform int32 - } - heads := make(map[*wlr_output_management.ZwlrOutputHeadV1]*headState) - done := false - - outputManager.SetHeadHandler(func(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) { - state := &headState{} - heads[e.Head] = state - e.Head.SetNameHandler(func(ne wlr_output_management.ZwlrOutputHeadV1NameEvent) { - state.name = ne.Name - }) - e.Head.SetPositionHandler(func(pe wlr_output_management.ZwlrOutputHeadV1PositionEvent) { - state.x = pe.X - state.y = pe.Y - }) - e.Head.SetScaleHandler(func(se wlr_output_management.ZwlrOutputHeadV1ScaleEvent) { - state.scale = se.Scale - }) - e.Head.SetTransformHandler(func(te wlr_output_management.ZwlrOutputHeadV1TransformEvent) { - state.transform = te.Transform - }) - }) - outputManager.SetDoneHandler(func(e wlr_output_management.ZwlrOutputManagerV1DoneEvent) { - done = true - }) - - for !done { - if err := ctx.Dispatch(); err != nil { - return nil - } - } - - result := make(map[string]*outputInfo, len(heads)) - for _, state := range heads { - if state.name == "" { - continue - } - result[state.name] = &outputInfo{ - x: state.x, - y: state.y, - scale: state.scale, - transform: state.transform, - } - } - return result -} - -func getOutputInfo(outputName string) (*outputInfo, bool) { - infos := getAllOutputInfos() - if infos == nil { - return nil, false - } - info, ok := infos[outputName] - return info, ok -} - -func getDWLActiveWindow() (*WindowGeometry, error) { - display, err := client.Connect("") - if err != nil { - return nil, fmt.Errorf("connect: %w", err) - } - ctx := display.Context() - defer ctx.Close() - - registry, err := display.GetRegistry() - if err != nil { - return nil, fmt.Errorf("get registry: %w", err) - } - - var dwlManager *dwl_ipc.ZdwlIpcManagerV2 - outputs := make(map[uint32]*client.Output) - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - switch e.Interface { - case dwl_ipc.ZdwlIpcManagerV2InterfaceName: - mgr := dwl_ipc.NewZdwlIpcManagerV2(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil { - dwlManager = mgr - } - case client.OutputInterfaceName: - out := client.NewOutput(ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := registry.Bind(e.Name, e.Interface, version, out); err == nil { - outputs[e.Name] = out - } - } - }) - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - if dwlManager == nil { - return nil, fmt.Errorf("dwl_ipc_manager not available") - } - - if len(outputs) == 0 { - return nil, fmt.Errorf("no outputs found") - } - - outputNames := make(map[uint32]string) - for name, out := range outputs { - n := name - out.SetNameHandler(func(e client.OutputNameEvent) { - outputNames[n] = e.Name - }) - } - - if err := wlhelpers.Roundtrip(display, ctx); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - type dwlOutputState struct { - output *dwl_ipc.ZdwlIpcOutputV2 - name string - active bool - x, y int32 - w, h int32 - scalefactor uint32 - gotFrame bool - } - - dwlOutputs := make(map[uint32]*dwlOutputState) - for name, out := range outputs { - dwlOut, err := dwlManager.GetOutput(out) - if err != nil { - continue - } - state := &dwlOutputState{output: dwlOut, name: outputNames[name]} - dwlOutputs[name] = state - - dwlOut.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) { - state.active = e.Active != 0 - }) - dwlOut.SetXHandler(func(e dwl_ipc.ZdwlIpcOutputV2XEvent) { - state.x = e.X - }) - dwlOut.SetYHandler(func(e dwl_ipc.ZdwlIpcOutputV2YEvent) { - state.y = e.Y - }) - dwlOut.SetWidthHandler(func(e dwl_ipc.ZdwlIpcOutputV2WidthEvent) { - state.w = e.Width - }) - dwlOut.SetHeightHandler(func(e dwl_ipc.ZdwlIpcOutputV2HeightEvent) { - state.h = e.Height - }) - dwlOut.SetScalefactorHandler(func(e dwl_ipc.ZdwlIpcOutputV2ScalefactorEvent) { - state.scalefactor = e.Scalefactor - }) - dwlOut.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) { - state.gotFrame = true - }) - } - - allFramesReceived := func() bool { - for _, s := range dwlOutputs { - if !s.gotFrame { - return false - } - } - return true - } - - for !allFramesReceived() { - if err := ctx.Dispatch(); err != nil { - return nil, fmt.Errorf("dispatch: %w", err) - } - } - - for _, state := range dwlOutputs { - if !state.active { - continue - } - if state.w <= 0 || state.h <= 0 { - return nil, fmt.Errorf("no active window") - } - scale := float64(state.scalefactor) / 100.0 - if scale <= 0 { - scale = 1.0 - } - - geom := &WindowGeometry{ - X: state.x, - Y: state.y, - Width: state.w, - Height: state.h, - Output: state.name, - Scale: scale, - } - - if info, ok := getOutputInfo(state.name); ok { - geom.OutputX = info.x - geom.OutputY = info.y - geom.OutputTransform = info.transform - } - - return geom, nil - } - - return nil, fmt.Errorf("no active output found") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/encode.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/encode.go deleted file mode 100644 index 8b40dca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/encode.go +++ /dev/null @@ -1,172 +0,0 @@ -package screenshot - -import ( - "bufio" - "fmt" - "image" - "image/jpeg" - "image/png" - "io" - "os" - "path/filepath" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func BufferToImage(buf *ShmBuffer) *image.RGBA { - return BufferToImageWithFormat(buf, uint32(FormatARGB8888)) -} - -func BufferToImageWithFormat(buf *ShmBuffer, format uint32) *image.RGBA { - img := image.NewRGBA(image.Rect(0, 0, buf.Width, buf.Height)) - data := buf.Data() - - var swapRB bool - switch format { - case uint32(FormatABGR8888), uint32(FormatXBGR8888): - swapRB = false - default: - swapRB = true - } - - for y := 0; y < buf.Height; y++ { - srcOff := y * buf.Stride - dstOff := y * img.Stride - for x := 0; x < buf.Width; x++ { - si := srcOff + x*4 - di := dstOff + x*4 - if si+3 >= len(data) || di+3 >= len(img.Pix) { - continue - } - if swapRB { - img.Pix[di+0] = data[si+2] - img.Pix[di+1] = data[si+1] - img.Pix[di+2] = data[si+0] - } else { - img.Pix[di+0] = data[si+0] - img.Pix[di+1] = data[si+1] - img.Pix[di+2] = data[si+2] - } - img.Pix[di+3] = 255 - } - } - return img -} - -func EncodePNG(w io.Writer, img image.Image) error { - enc := png.Encoder{CompressionLevel: png.BestSpeed} - return enc.Encode(w, img) -} - -func EncodeJPEG(w io.Writer, img image.Image, quality int) error { - return jpeg.Encode(w, img, &jpeg.Options{Quality: quality}) -} - -func EncodePPM(w io.Writer, img *image.RGBA) error { - bw := bufio.NewWriter(w) - bounds := img.Bounds() - if _, err := fmt.Fprintf(bw, "P6\n%d %d\n255\n", bounds.Dx(), bounds.Dy()); err != nil { - return err - } - for y := bounds.Min.Y; y < bounds.Max.Y; y++ { - for x := bounds.Min.X; x < bounds.Max.X; x++ { - off := (y-bounds.Min.Y)*img.Stride + (x-bounds.Min.X)*4 - if err := bw.WriteByte(img.Pix[off+0]); err != nil { - return err - } - if err := bw.WriteByte(img.Pix[off+1]); err != nil { - return err - } - if err := bw.WriteByte(img.Pix[off+2]); err != nil { - return err - } - } - } - return bw.Flush() -} - -func GenerateFilename(format Format) string { - t := time.Now() - ext := "png" - switch format { - case FormatJPEG: - ext = "jpg" - case FormatPPM: - ext = "ppm" - } - return fmt.Sprintf("screenshot_%s.%s", t.Format("2006-01-02_15-04-05"), ext) -} - -func GetOutputDir() string { - if dir := os.Getenv("DMS_SCREENSHOT_DIR"); dir != "" { - return dir - } - - if xdgPics := getXDGPicturesDir(); xdgPics != "" { - screenshotDir := filepath.Join(xdgPics, "Screenshots") - if err := os.MkdirAll(screenshotDir, 0o755); err == nil { - return screenshotDir - } - return xdgPics - } - - if home := os.Getenv("HOME"); home != "" { - return home - } - return "." -} - -func getXDGPicturesDir() string { - userConfigDir, err := os.UserConfigDir() - if err != nil { - log.Error("failed to get user config dir", "err", err) - return "" - } - userDirsFile := filepath.Join(userConfigDir, "user-dirs.dirs") - data, err := os.ReadFile(userDirsFile) - if err != nil { - return "" - } - - for _, line := range strings.Split(string(data), "\n") { - if len(line) == 0 || line[0] == '#' { - continue - } - const prefix = "XDG_PICTURES_DIR=" - if !strings.HasPrefix(line, prefix) { - continue - } - path := strings.Trim(line[len(prefix):], "\"") - expanded, err := utils.ExpandPath(path) - if err != nil { - return "" - } - return expanded - } - return "" -} - -func WriteToFile(buf *ShmBuffer, path string, format Format, quality int) error { - return WriteToFileWithFormat(buf, path, format, quality, uint32(FormatARGB8888)) -} - -func WriteToFileWithFormat(buf *ShmBuffer, path string, format Format, quality int, pixelFormat uint32) error { - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - - img := BufferToImageWithFormat(buf, pixelFormat) - switch format { - case FormatJPEG: - return EncodeJPEG(f, img, quality) - case FormatPPM: - return EncodePPM(f, img) - default: - return EncodePNG(f, img) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/notify.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/notify.go deleted file mode 100644 index 9633b42..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/notify.go +++ /dev/null @@ -1,180 +0,0 @@ -package screenshot - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strconv" - "syscall" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - notifyDest = "org.freedesktop.Notifications" - notifyPath = "/org/freedesktop/Notifications" - notifyInterface = "org.freedesktop.Notifications" -) - -type NotifyResult struct { - FilePath string - Clipboard bool - ImageData []byte - Width int - Height int -} - -func SendNotification(result NotifyResult) { - conn, err := dbus.SessionBus() - if err != nil { - log.Debug("dbus session failed", "err", err) - return - } - - var actions []string - if result.FilePath != "" { - actions = []string{"default", "Open"} - } - - hints := map[string]dbus.Variant{} - if len(result.ImageData) > 0 && result.Width > 0 && result.Height > 0 { - rowstride := result.Width * 3 - hints["image_data"] = dbus.MakeVariant(struct { - Width int32 - Height int32 - Rowstride int32 - HasAlpha bool - BitsPerSample int32 - Channels int32 - Data []byte - }{ - Width: int32(result.Width), - Height: int32(result.Height), - Rowstride: int32(rowstride), - HasAlpha: false, - BitsPerSample: 8, - Channels: 3, - Data: result.ImageData, - }) - } else if result.FilePath != "" { - hints["image_path"] = dbus.MakeVariant(result.FilePath) - } - - summary := "Screenshot captured" - body := "" - if result.Clipboard && result.FilePath != "" { - body = fmt.Sprintf("Copied to clipboard\n%s", filepath.Base(result.FilePath)) - } else if result.Clipboard { - body = "Copied to clipboard" - } else if result.FilePath != "" { - body = filepath.Base(result.FilePath) - } - - obj := conn.Object(notifyDest, notifyPath) - call := obj.Call( - notifyInterface+".Notify", - 0, - "DMS", - uint32(0), - "", - summary, - body, - actions, - hints, - int32(5000), - ) - - if call.Err != nil { - log.Debug("notify call failed", "err", call.Err) - return - } - - var notificationID uint32 - if err := call.Store(¬ificationID); err != nil { - log.Debug("failed to get notification id", "err", err) - return - } - - if len(actions) == 0 || result.FilePath == "" { - return - } - - spawnActionListener(notificationID, result.FilePath) -} - -func spawnActionListener(notificationID uint32, filePath string) { - exe, err := os.Executable() - if err != nil { - log.Debug("failed to get executable", "err", err) - return - } - - cmd := exec.Command(exe, "notify-action", fmt.Sprintf("%d", notificationID), filePath) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - cmd.Start() -} - -func RunNotifyActionListener(args []string) { - if len(args) < 2 { - return - } - - notificationID, err := strconv.ParseUint(args[0], 10, 32) - if err != nil { - return - } - - filePath := args[1] - - conn, err := dbus.SessionBus() - if err != nil { - return - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(notifyPath), - dbus.WithMatchInterface(notifyInterface), - ); err != nil { - return - } - - signals := make(chan *dbus.Signal, 10) - conn.Signal(signals) - - for sig := range signals { - switch sig.Name { - case notifyInterface + ".ActionInvoked": - if len(sig.Body) < 2 { - continue - } - id, ok := sig.Body[0].(uint32) - if !ok || id != uint32(notificationID) { - continue - } - openFile(filePath) - return - - case notifyInterface + ".NotificationClosed": - if len(sig.Body) < 1 { - continue - } - id, ok := sig.Body[0].(uint32) - if !ok || id != uint32(notificationID) { - continue - } - return - } - } -} - -func openFile(filePath string) { - cmd := exec.Command("xdg-open", filePath) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } - cmd.Start() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region.go deleted file mode 100644 index f296434..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region.go +++ /dev/null @@ -1,859 +0,0 @@ -package screenshot - -import ( - "fmt" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/keyboard_shortcuts_inhibit" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_layer_shell" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_screencopy" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wp_viewporter" - wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type SelectionState struct { - hasSelection bool // There's a selection to display (pre-loaded or user-drawn) - dragging bool // User is actively drawing a new selection - surface *OutputSurface // Surface where selection was made - // Surface-local logical coordinates (from pointer events) - anchorX float64 - anchorY float64 - currentX float64 - currentY float64 -} - -type RenderSlot struct { - shm *ShmBuffer - pool *client.ShmPool - wlBuf *client.Buffer - busy bool -} - -type OutputSurface struct { - output *WaylandOutput - wlSurface *client.Surface - layerSurf *wlr_layer_shell.ZwlrLayerSurfaceV1 - viewport *wp_viewporter.WpViewport - screenBuf *ShmBuffer - screenBufNoCursor *ShmBuffer - screenFormat uint32 - logicalW int - logicalH int - configured bool - yInverted bool - - // Triple-buffered render slots - slots [3]*RenderSlot - slotsReady bool -} - -type PreCapture struct { - screenBuf *ShmBuffer - screenBufNoCursor *ShmBuffer - format uint32 - yInverted bool -} - -type RegionSelector struct { - screenshoter *Screenshoter - - display *client.Display - registry *client.Registry - ctx *client.Context - - compositor *client.Compositor - shm *client.Shm - seat *client.Seat - pointer *client.Pointer - keyboard *client.Keyboard - layerShell *wlr_layer_shell.ZwlrLayerShellV1 - screencopy *wlr_screencopy.ZwlrScreencopyManagerV1 - viewporter *wp_viewporter.WpViewporter - - shortcutsInhibitMgr *keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitManagerV1 - shortcutsInhibitor *keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitorV1 - - outputs map[uint32]*WaylandOutput - outputsMu sync.Mutex - preCapture map[*WaylandOutput]*PreCapture - - surfaces []*OutputSurface - activeSurface *OutputSurface - - // Cursor surface for crosshair - cursorSurface *client.Surface - cursorBuffer *ShmBuffer - cursorWlBuf *client.Buffer - cursorPool *client.ShmPool - - selection SelectionState - pointerX float64 - pointerY float64 - preSelect Region - showCapturedCursor bool - shiftHeld bool - - running bool - cancelled bool - result Region - - capturedBuffer *ShmBuffer - capturedRegion Region -} - -func NewRegionSelector(s *Screenshoter) *RegionSelector { - return &RegionSelector{ - screenshoter: s, - outputs: make(map[uint32]*WaylandOutput), - preCapture: make(map[*WaylandOutput]*PreCapture), - showCapturedCursor: s.config.Cursor == CursorOn, - } -} - -func (r *RegionSelector) Run() (*CaptureResult, bool, error) { - if r.screenshoter != nil && r.screenshoter.config.Reset { - r.preSelect = Region{} - } else { - r.preSelect = GetLastRegion() - } - - if err := r.connect(); err != nil { - return nil, false, fmt.Errorf("wayland connect: %w", err) - } - defer r.cleanup() - - if err := r.setupRegistry(); err != nil { - return nil, false, fmt.Errorf("registry setup: %w", err) - } - - if err := r.roundtrip(); err != nil { - return nil, false, fmt.Errorf("roundtrip after registry: %w", err) - } - - switch { - case r.screencopy == nil: - return nil, false, fmt.Errorf("compositor does not support wlr-screencopy-unstable-v1") - case r.layerShell == nil: - return nil, false, fmt.Errorf("compositor does not support wlr-layer-shell-unstable-v1") - case r.seat == nil: - return nil, false, fmt.Errorf("no seat available") - case r.compositor == nil: - return nil, false, fmt.Errorf("compositor not available") - case r.shm == nil: - return nil, false, fmt.Errorf("wl_shm not available") - case len(r.outputs) == 0: - return nil, false, fmt.Errorf("no outputs available") - } - - if err := r.roundtrip(); err != nil { - return nil, false, fmt.Errorf("roundtrip after protocol check: %w", err) - } - - if err := r.preCaptureAllOutputs(); err != nil { - return nil, false, fmt.Errorf("pre-capture: %w", err) - } - - if err := r.createSurfaces(); err != nil { - return nil, false, fmt.Errorf("create surfaces: %w", err) - } - - _ = r.createCursor() - - if err := r.roundtrip(); err != nil { - return nil, false, fmt.Errorf("roundtrip after surfaces: %w", err) - } - - r.running = true - for r.running { - if err := r.ctx.Dispatch(); err != nil { - return nil, false, fmt.Errorf("dispatch: %w", err) - } - } - - if r.cancelled || r.capturedBuffer == nil { - return nil, r.cancelled, nil - } - - yInverted := false - var format uint32 - if r.selection.surface != nil { - yInverted = r.selection.surface.yInverted - format = r.selection.surface.screenFormat - } - - return &CaptureResult{ - Buffer: r.capturedBuffer, - Region: r.result, - YInverted: yInverted, - Format: format, - }, false, nil -} - -func (r *RegionSelector) connect() error { - display, err := client.Connect("") - if err != nil { - return err - } - r.display = display - r.ctx = display.Context() - return nil -} - -func (r *RegionSelector) roundtrip() error { - return wlhelpers.Roundtrip(r.display, r.ctx) -} - -func (r *RegionSelector) setupRegistry() error { - registry, err := r.display.GetRegistry() - if err != nil { - return err - } - r.registry = registry - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - r.handleGlobal(e) - }) - - registry.SetGlobalRemoveHandler(func(e client.RegistryGlobalRemoveEvent) { - r.outputsMu.Lock() - delete(r.outputs, e.Name) - r.outputsMu.Unlock() - }) - - return nil -} - -func (r *RegionSelector) handleGlobal(e client.RegistryGlobalEvent) { - switch e.Interface { - case client.CompositorInterfaceName: - comp := client.NewCompositor(r.ctx) - if err := r.registry.Bind(e.Name, e.Interface, e.Version, comp); err == nil { - r.compositor = comp - } - - case client.ShmInterfaceName: - shm := client.NewShm(r.ctx) - if err := r.registry.Bind(e.Name, e.Interface, e.Version, shm); err == nil { - r.shm = shm - } - - case client.SeatInterfaceName: - seat := client.NewSeat(r.ctx) - if err := r.registry.Bind(e.Name, e.Interface, e.Version, seat); err == nil { - r.seat = seat - r.setupInput() - } - - case client.OutputInterfaceName: - output := client.NewOutput(r.ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := r.registry.Bind(e.Name, e.Interface, version, output); err == nil { - r.outputsMu.Lock() - r.outputs[e.Name] = &WaylandOutput{ - wlOutput: output, - globalName: e.Name, - scale: 1, - fractionalScale: 1.0, - } - r.outputsMu.Unlock() - r.setupOutputHandlers(e.Name, output) - } - - case wlr_layer_shell.ZwlrLayerShellV1InterfaceName: - ls := wlr_layer_shell.NewZwlrLayerShellV1(r.ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := r.registry.Bind(e.Name, e.Interface, version, ls); err == nil { - r.layerShell = ls - } - - case wlr_screencopy.ZwlrScreencopyManagerV1InterfaceName: - sc := wlr_screencopy.NewZwlrScreencopyManagerV1(r.ctx) - version := e.Version - if version > 3 { - version = 3 - } - if err := r.registry.Bind(e.Name, e.Interface, version, sc); err == nil { - r.screencopy = sc - } - - case wp_viewporter.WpViewporterInterfaceName: - vp := wp_viewporter.NewWpViewporter(r.ctx) - if err := r.registry.Bind(e.Name, e.Interface, e.Version, vp); err == nil { - r.viewporter = vp - } - - case keyboard_shortcuts_inhibit.ZwpKeyboardShortcutsInhibitManagerV1InterfaceName: - mgr := keyboard_shortcuts_inhibit.NewZwpKeyboardShortcutsInhibitManagerV1(r.ctx) - if err := r.registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil { - r.shortcutsInhibitMgr = mgr - } - } -} - -func (r *RegionSelector) setupOutputHandlers(name uint32, output *client.Output) { - output.SetGeometryHandler(func(e client.OutputGeometryEvent) { - r.outputsMu.Lock() - if o, ok := r.outputs[name]; ok { - o.x = e.X - o.y = e.Y - o.transform = int32(e.Transform) - } - r.outputsMu.Unlock() - }) - - output.SetModeHandler(func(e client.OutputModeEvent) { - if e.Flags&uint32(client.OutputModeCurrent) == 0 { - return - } - r.outputsMu.Lock() - if o, ok := r.outputs[name]; ok { - o.width = e.Width - o.height = e.Height - } - r.outputsMu.Unlock() - }) - - output.SetScaleHandler(func(e client.OutputScaleEvent) { - r.outputsMu.Lock() - if o, ok := r.outputs[name]; ok { - o.scale = e.Factor - o.fractionalScale = float64(e.Factor) - } - r.outputsMu.Unlock() - }) - - output.SetNameHandler(func(e client.OutputNameEvent) { - r.outputsMu.Lock() - if o, ok := r.outputs[name]; ok { - o.name = e.Name - } - r.outputsMu.Unlock() - }) -} - -func (r *RegionSelector) preCaptureAllOutputs() error { - r.outputsMu.Lock() - outputs := make([]*WaylandOutput, 0, len(r.outputs)) - for _, o := range r.outputs { - outputs = append(outputs, o) - } - r.outputsMu.Unlock() - - pending := len(outputs) * 2 - done := make(chan struct{}, pending) - - for _, output := range outputs { - pc := &PreCapture{} - r.preCapture[output] = pc - - r.preCaptureOutput(output, pc, true, func() { done <- struct{}{} }) - r.preCaptureOutput(output, pc, false, func() { done <- struct{}{} }) - } - - for i := 0; i < pending; i++ { - if err := r.ctx.Dispatch(); err != nil { - return err - } - select { - case <-done: - default: - i-- - } - } - return nil -} - -func (r *RegionSelector) preCaptureOutput(output *WaylandOutput, pc *PreCapture, withCursor bool, onReady func()) { - cursor := int32(0) - if withCursor { - cursor = 1 - } - - frame, err := r.screencopy.CaptureOutput(cursor, output.wlOutput) - if err != nil { - log.Error("screencopy capture failed", "err", err) - onReady() - return - } - - var capturedBuf *ShmBuffer - - var capturedFormat PixelFormat - frame.SetBufferHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferEvent) { - capturedFormat = PixelFormat(e.Format) - bpp := capturedFormat.BytesPerPixel() - if int(e.Stride) < int(e.Width)*bpp { - log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width, "bpp", bpp) - return - } - buf, err := CreateShmBuffer(int(e.Width), int(e.Height), int(e.Stride)) - if err != nil { - log.Error("create screen buffer failed", "err", err) - return - } - - capturedBuf = buf - buf.Format = capturedFormat - - pool, err := r.shm.CreatePool(buf.Fd(), int32(buf.Size())) - if err != nil { - log.Error("create shm pool failed", "err", err) - return - } - - wlBuf, err := pool.CreateBuffer(0, int32(buf.Width), int32(buf.Height), int32(buf.Stride), e.Format) - if err != nil { - log.Error("create wl_buffer failed", "err", err) - pool.Destroy() - return - } - - if err := frame.Copy(wlBuf); err != nil { - log.Error("frame copy failed", "err", err) - } - pool.Destroy() - }) - - frame.SetFlagsHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FlagsEvent) { - if withCursor { - pc.yInverted = (e.Flags & 1) != 0 - } - }) - - frame.SetReadyHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1ReadyEvent) { - frame.Destroy() - - if capturedBuf == nil { - onReady() - return - } - - if capturedFormat.Is24Bit() { - converted, newFormat, err := capturedBuf.ConvertTo32Bit(capturedFormat) - if err != nil { - log.Error("convert 24-bit to 32-bit failed", "err", err) - } else if converted != capturedBuf { - capturedBuf.Close() - capturedBuf = converted - capturedFormat = newFormat - } - } - - pc.format = uint32(capturedFormat) - - if pc.yInverted { - capturedBuf.FlipVertical() - pc.yInverted = false - } - - if output.transform != TransformNormal { - invTransform := InverseTransform(output.transform) - transformed, err := capturedBuf.ApplyTransform(invTransform) - if err != nil { - log.Error("apply transform failed", "err", err) - } else if transformed != capturedBuf { - capturedBuf.Close() - capturedBuf = transformed - } - } - - if withCursor { - pc.screenBuf = capturedBuf - } else { - pc.screenBufNoCursor = capturedBuf - } - - onReady() - }) - - frame.SetFailedHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FailedEvent) { - log.Error("screencopy failed") - frame.Destroy() - onReady() - }) -} - -func (r *RegionSelector) createSurfaces() error { - r.outputsMu.Lock() - outputs := make([]*WaylandOutput, 0, len(r.outputs)) - for _, o := range r.outputs { - outputs = append(outputs, o) - } - r.outputsMu.Unlock() - - for _, output := range outputs { - os, err := r.createOutputSurface(output) - if err != nil { - return fmt.Errorf("output %s: %w", output.name, err) - } - r.surfaces = append(r.surfaces, os) - } - - return nil -} - -func (r *RegionSelector) createCursor() error { - const size = 24 - const hotspot = size / 2 - - surface, err := r.compositor.CreateSurface() - if err != nil { - return fmt.Errorf("create cursor surface: %w", err) - } - r.cursorSurface = surface - - buf, err := CreateShmBuffer(size, size, size*4) - if err != nil { - return fmt.Errorf("create cursor buffer: %w", err) - } - r.cursorBuffer = buf - - // Draw crosshair - data := buf.Data() - for y := 0; y < size; y++ { - for x := 0; x < size; x++ { - off := (y*size + x) * 4 - // Vertical line - if x >= hotspot-1 && x <= hotspot && y >= 2 && y < size-2 { - data[off+0] = 255 // B - data[off+1] = 255 // G - data[off+2] = 255 // R - data[off+3] = 255 // A - continue - } - // Horizontal line - if y >= hotspot-1 && y <= hotspot && x >= 2 && x < size-2 { - data[off+0] = 255 - data[off+1] = 255 - data[off+2] = 255 - data[off+3] = 255 - continue - } - // Transparent - data[off+0] = 0 - data[off+1] = 0 - data[off+2] = 0 - data[off+3] = 0 - } - } - - pool, err := r.shm.CreatePool(buf.Fd(), int32(buf.Size())) - if err != nil { - return fmt.Errorf("create cursor pool: %w", err) - } - r.cursorPool = pool - - wlBuf, err := pool.CreateBuffer(0, size, size, size*4, uint32(FormatARGB8888)) - if err != nil { - return fmt.Errorf("create cursor wl_buffer: %w", err) - } - r.cursorWlBuf = wlBuf - - if err := surface.Attach(wlBuf, 0, 0); err != nil { - return fmt.Errorf("attach cursor: %w", err) - } - if err := surface.Damage(0, 0, size, size); err != nil { - return fmt.Errorf("damage cursor: %w", err) - } - if err := surface.Commit(); err != nil { - return fmt.Errorf("commit cursor: %w", err) - } - - return nil -} - -func (r *RegionSelector) createOutputSurface(output *WaylandOutput) (*OutputSurface, error) { - surface, err := r.compositor.CreateSurface() - if err != nil { - return nil, fmt.Errorf("create surface: %w", err) - } - - layerSurf, err := r.layerShell.GetLayerSurface( - surface, - output.wlOutput, - uint32(wlr_layer_shell.ZwlrLayerShellV1LayerOverlay), - "dms-screenshot", - ) - if err != nil { - return nil, fmt.Errorf("get layer surface: %w", err) - } - - os := &OutputSurface{ - output: output, - wlSurface: surface, - layerSurf: layerSurf, - } - - if r.viewporter != nil { - vp, err := r.viewporter.GetViewport(surface) - if err == nil { - os.viewport = vp - } - } - - if err := layerSurf.SetAnchor( - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorTop) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorBottom) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorLeft) | - uint32(wlr_layer_shell.ZwlrLayerSurfaceV1AnchorRight), - ); err != nil { - return nil, fmt.Errorf("set anchor: %w", err) - } - if err := layerSurf.SetExclusiveZone(-1); err != nil { - return nil, fmt.Errorf("set exclusive zone: %w", err) - } - if err := layerSurf.SetKeyboardInteractivity(uint32(wlr_layer_shell.ZwlrLayerSurfaceV1KeyboardInteractivityExclusive)); err != nil { - return nil, fmt.Errorf("set keyboard interactivity: %w", err) - } - - layerSurf.SetConfigureHandler(func(e wlr_layer_shell.ZwlrLayerSurfaceV1ConfigureEvent) { - if err := layerSurf.AckConfigure(e.Serial); err != nil { - log.Error("ack configure failed", "err", err) - return - } - os.logicalW = int(e.Width) - os.logicalH = int(e.Height) - os.configured = true - r.captureForSurface(os) - r.ensureShortcutsInhibitor(os) - }) - - layerSurf.SetClosedHandler(func(e wlr_layer_shell.ZwlrLayerSurfaceV1ClosedEvent) { - r.running = false - r.cancelled = true - }) - - if err := surface.Commit(); err != nil { - return nil, fmt.Errorf("surface commit: %w", err) - } - - return os, nil -} - -func (r *RegionSelector) ensureShortcutsInhibitor(os *OutputSurface) { - if r.shortcutsInhibitMgr == nil || r.seat == nil || r.shortcutsInhibitor != nil { - return - } - inhibitor, err := r.shortcutsInhibitMgr.InhibitShortcuts(os.wlSurface, r.seat) - if err == nil { - r.shortcutsInhibitor = inhibitor - } -} - -func (r *RegionSelector) captureForSurface(os *OutputSurface) { - pc := r.preCapture[os.output] - if pc == nil { - return - } - - os.screenBuf = pc.screenBuf - os.screenBufNoCursor = pc.screenBufNoCursor - os.screenFormat = pc.format - os.yInverted = pc.yInverted - - if os.logicalW > 0 && os.screenBuf != nil { - os.output.fractionalScale = float64(os.screenBuf.Width) / float64(os.logicalW) - } - - r.initRenderBuffer(os) - r.applyPreSelection(os) - r.redrawSurface(os) -} - -func (r *RegionSelector) initRenderBuffer(os *OutputSurface) { - if os.screenBuf == nil { - return - } - - for i := 0; i < 3; i++ { - slot := &RenderSlot{} - - buf, err := CreateShmBuffer(os.screenBuf.Width, os.screenBuf.Height, os.screenBuf.Stride) - if err != nil { - log.Error("create render slot buffer failed", "err", err) - return - } - slot.shm = buf - - pool, err := r.shm.CreatePool(buf.Fd(), int32(buf.Size())) - if err != nil { - log.Error("create render slot pool failed", "err", err) - buf.Close() - return - } - slot.pool = pool - - wlBuf, err := pool.CreateBuffer(0, int32(buf.Width), int32(buf.Height), int32(buf.Stride), os.screenFormat) - if err != nil { - log.Error("create render slot wl_buffer failed", "err", err) - pool.Destroy() - buf.Close() - return - } - slot.wlBuf = wlBuf - - slotRef := slot - wlBuf.SetReleaseHandler(func(e client.BufferReleaseEvent) { - slotRef.busy = false - }) - - os.slots[i] = slot - } - os.slotsReady = true -} - -func (os *OutputSurface) acquireFreeSlot() *RenderSlot { - for _, slot := range os.slots { - if slot != nil && !slot.busy { - return slot - } - } - return nil -} - -func (r *RegionSelector) applyPreSelection(os *OutputSurface) { - if r.preSelect.IsEmpty() || os.screenBuf == nil || r.selection.hasSelection { - return - } - - if r.preSelect.Output != "" && r.preSelect.Output != os.output.name { - return - } - - scaleX := float64(os.logicalW) / float64(os.screenBuf.Width) - scaleY := float64(os.logicalH) / float64(os.screenBuf.Height) - - x1 := float64(r.preSelect.X-os.output.x) * scaleX - y1 := float64(r.preSelect.Y-os.output.y) * scaleY - x2 := float64(r.preSelect.X-os.output.x+r.preSelect.Width) * scaleX - y2 := float64(r.preSelect.Y-os.output.y+r.preSelect.Height) * scaleY - - r.selection.hasSelection = true - r.selection.dragging = false - r.selection.surface = os - r.selection.anchorX = x1 - r.selection.anchorY = y1 - r.selection.currentX = x2 - r.selection.currentY = y2 - r.activeSurface = os -} - -func (r *RegionSelector) getSourceBuffer(os *OutputSurface) *ShmBuffer { - if !r.showCapturedCursor && os.screenBufNoCursor != nil { - return os.screenBufNoCursor - } - return os.screenBuf -} - -func (r *RegionSelector) redrawSurface(os *OutputSurface) { - srcBuf := r.getSourceBuffer(os) - if srcBuf == nil || !os.slotsReady { - return - } - - slot := os.acquireFreeSlot() - if slot == nil { - return - } - - slot.shm.CopyFrom(srcBuf) - - // Draw overlay (dimming + selection) into this slot - r.drawOverlay(os, slot.shm) - - if os.viewport != nil { - _ = os.wlSurface.SetBufferScale(1) - _ = os.viewport.SetSource(0, 0, float64(slot.shm.Width), float64(slot.shm.Height)) - _ = os.viewport.SetDestination(int32(os.logicalW), int32(os.logicalH)) - } else { - bufferScale := os.output.scale - if bufferScale <= 0 { - bufferScale = 1 - } - _ = os.wlSurface.SetBufferScale(bufferScale) - } - - _ = os.wlSurface.Attach(slot.wlBuf, 0, 0) - _ = os.wlSurface.Damage(0, 0, int32(os.logicalW), int32(os.logicalH)) - _ = os.wlSurface.Commit() - - // Mark this slot as busy until compositor releases it - slot.busy = true -} - -func (r *RegionSelector) cleanup() { - if r.cursorWlBuf != nil { - r.cursorWlBuf.Destroy() - } - if r.cursorPool != nil { - r.cursorPool.Destroy() - } - if r.cursorSurface != nil { - r.cursorSurface.Destroy() - } - if r.cursorBuffer != nil { - r.cursorBuffer.Close() - } - - for _, os := range r.surfaces { - for _, slot := range os.slots { - if slot == nil { - continue - } - if slot.wlBuf != nil { - slot.wlBuf.Destroy() - } - if slot.pool != nil { - slot.pool.Destroy() - } - if slot.shm != nil { - slot.shm.Close() - } - } - if os.viewport != nil { - os.viewport.Destroy() - } - if os.layerSurf != nil { - os.layerSurf.Destroy() - } - if os.wlSurface != nil { - os.wlSurface.Destroy() - } - if os.screenBuf != nil { - os.screenBuf.Close() - } - if os.screenBufNoCursor != nil { - os.screenBufNoCursor.Close() - } - } - - if r.shortcutsInhibitor != nil { - _ = r.shortcutsInhibitor.Destroy() - } - if r.shortcutsInhibitMgr != nil { - _ = r.shortcutsInhibitMgr.Destroy() - } - if r.viewporter != nil { - r.viewporter.Destroy() - } - if r.screencopy != nil { - r.screencopy.Destroy() - } - if r.pointer != nil { - r.pointer.Release() - } - if r.keyboard != nil { - r.keyboard.Release() - } - if r.display != nil { - r.ctx.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_input.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_input.go deleted file mode 100644 index e243443..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_input.go +++ /dev/null @@ -1,274 +0,0 @@ -package screenshot - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -func (r *RegionSelector) setupInput() { - if r.seat == nil { - return - } - - r.seat.SetCapabilitiesHandler(func(e client.SeatCapabilitiesEvent) { - if e.Capabilities&uint32(client.SeatCapabilityPointer) != 0 && r.pointer == nil { - if pointer, err := r.seat.GetPointer(); err == nil { - r.pointer = pointer - r.setupPointerHandlers() - } - } - if e.Capabilities&uint32(client.SeatCapabilityKeyboard) != 0 && r.keyboard == nil { - if keyboard, err := r.seat.GetKeyboard(); err == nil { - r.keyboard = keyboard - r.setupKeyboardHandlers() - } - } - }) -} - -func (r *RegionSelector) setupPointerHandlers() { - r.pointer.SetEnterHandler(func(e client.PointerEnterEvent) { - if r.cursorSurface != nil { - _ = r.pointer.SetCursor(e.Serial, r.cursorSurface, 12, 12) - } - - r.activeSurface = nil - for _, os := range r.surfaces { - if os.wlSurface.ID() == e.Surface.ID() { - r.activeSurface = os - break - } - } - - r.pointerX = e.SurfaceX - r.pointerY = e.SurfaceY - }) - - r.pointer.SetMotionHandler(func(e client.PointerMotionEvent) { - if r.activeSurface == nil { - return - } - - r.pointerX = e.SurfaceX - r.pointerY = e.SurfaceY - - if !r.selection.dragging { - return - } - - curX, curY := e.SurfaceX, e.SurfaceY - if r.shiftHeld { - dx := curX - r.selection.anchorX - dy := curY - r.selection.anchorY - adx, ady := dx, dy - if adx < 0 { - adx = -adx - } - if ady < 0 { - ady = -ady - } - size := adx - if ady > adx { - size = ady - } - if dx < 0 { - curX = r.selection.anchorX - size - } else { - curX = r.selection.anchorX + size - } - if dy < 0 { - curY = r.selection.anchorY - size - } else { - curY = r.selection.anchorY + size - } - } - - r.selection.currentX = curX - r.selection.currentY = curY - for _, os := range r.surfaces { - r.redrawSurface(os) - } - }) - - r.pointer.SetButtonHandler(func(e client.PointerButtonEvent) { - if r.activeSurface == nil { - return - } - - switch e.Button { - case 0x110: // BTN_LEFT - switch e.State { - case 1: // pressed - r.preSelect = Region{} - r.selection.hasSelection = true - r.selection.dragging = true - r.selection.surface = r.activeSurface - r.selection.anchorX = r.pointerX - r.selection.anchorY = r.pointerY - r.selection.currentX = r.pointerX - r.selection.currentY = r.pointerY - for _, os := range r.surfaces { - r.redrawSurface(os) - } - case 0: // released - r.selection.dragging = false - for _, os := range r.surfaces { - r.redrawSurface(os) - } - if r.screenshoter != nil && r.screenshoter.config.NoConfirm && r.selection.hasSelection { - r.finishSelection() - } - } - default: - r.cancelled = true - r.running = false - } - }) -} - -func (r *RegionSelector) setupKeyboardHandlers() { - r.keyboard.SetModifiersHandler(func(e client.KeyboardModifiersEvent) { - r.shiftHeld = e.ModsDepressed&1 != 0 - }) - - r.keyboard.SetKeyHandler(func(e client.KeyboardKeyEvent) { - if e.State != 1 { - return - } - - switch e.Key { - case 1: - r.cancelled = true - r.running = false - case 25: - r.showCapturedCursor = !r.showCapturedCursor - for _, os := range r.surfaces { - r.redrawSurface(os) - } - case 28, 57, 96: - if r.selection.hasSelection { - r.finishSelection() - } - } - }) -} - -func (r *RegionSelector) finishSelection() { - if r.selection.surface == nil { - r.running = false - return - } - - os := r.selection.surface - srcBuf := r.getSourceBuffer(os) - if srcBuf == nil { - r.running = false - return - } - - x1, y1 := r.selection.anchorX, r.selection.anchorY - x2, y2 := r.selection.currentX, r.selection.currentY - - if x1 > x2 { - x1, x2 = x2, x1 - } - if y1 > y2 { - y1, y2 = y2, y1 - } - - scaleX, scaleY := 1.0, 1.0 - if os.logicalW > 0 { - scaleX = float64(srcBuf.Width) / float64(os.logicalW) - scaleY = float64(srcBuf.Height) / float64(os.logicalH) - } - - bx1 := int(x1 * scaleX) - by1 := int(y1 * scaleY) - bx2 := int(x2 * scaleX) - by2 := int(y2 * scaleY) - - // Clamp to buffer bounds - if bx1 < 0 { - bx1 = 0 - } - if by1 < 0 { - by1 = 0 - } - if bx2 > srcBuf.Width { - bx2 = srcBuf.Width - } - if by2 > srcBuf.Height { - by2 = srcBuf.Height - } - - w, h := bx2-bx1+1, by2-by1+1 - if r.shiftHeld && w != h { - if w < h { - h = w - } else { - w = h - } - } - if w < 1 { - w = 1 - } - if h < 1 { - h = 1 - } - - // Create cropped buffer and copy pixels directly - cropped, err := CreateShmBuffer(w, h, w*4) - if err != nil { - r.running = false - return - } - - srcData := srcBuf.Data() - dstData := cropped.Data() - for y := 0; y < h; y++ { - srcY := by1 + y - if os.yInverted { - srcY = srcBuf.Height - 1 - (by1 + y) - } - if srcY < 0 || srcY >= srcBuf.Height { - continue - } - dstY := y - if os.yInverted { - dstY = h - 1 - y - } - for x := 0; x < w; x++ { - srcX := bx1 + x - if srcX < 0 || srcX >= srcBuf.Width { - continue - } - si := srcY*srcBuf.Stride + srcX*4 - di := dstY*cropped.Stride + x*4 - if si+3 < len(srcData) && di+3 < len(dstData) { - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - dstData[di+3] = srcData[si+3] - } - } - } - - r.capturedBuffer = cropped - r.capturedRegion = Region{ - X: int32(bx1), - Y: int32(by1), - Width: int32(w), - Height: int32(h), - Output: os.output.name, - } - - // Also store for "last region" feature with global coords - r.result = Region{ - X: int32(bx1) + os.output.x, - Y: int32(by1) + os.output.y, - Width: int32(w), - Height: int32(h), - Output: os.output.name, - } - - r.running = false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_render.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_render.go deleted file mode 100644 index 4071f8a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/region_render.go +++ /dev/null @@ -1,326 +0,0 @@ -package screenshot - -import "fmt" - -var fontGlyphs = map[rune][12]uint8{ - '0': {0x3C, 0x66, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00}, - '1': {0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00}, - '2': {0x3C, 0x66, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x66, 0x7E, 0x00, 0x00}, - '3': {0x3C, 0x66, 0x06, 0x06, 0x1C, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x00}, - '4': {0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xCC, 0xFE, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, - '5': {0x7E, 0x60, 0x60, 0x60, 0x7C, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x00}, - '6': {0x1C, 0x30, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00}, - '7': {0x7E, 0x66, 0x06, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, - '8': {0x3C, 0x66, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00}, - '9': {0x3C, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x0C, 0x38, 0x00, 0x00}, - 'x': {0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00}, - 'E': {0x7E, 0x60, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, 0x00}, - 'P': {0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00}, - 'S': {0x3C, 0x66, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x00}, - 'a': {0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00}, - 'c': {0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, 0x00}, - 'd': {0x00, 0x00, 0x06, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00}, - 'e': {0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x7E, 0x60, 0x60, 0x3C, 0x00, 0x00}, - 'h': {0x00, 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00}, - 'i': {0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, - 'n': {0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00}, - 'o': {0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00}, - 'p': {0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, 0x00}, - 'r': {0x00, 0x00, 0x00, 0x6E, 0x76, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00}, - 's': {0x00, 0x00, 0x00, 0x3E, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x7C, 0x00, 0x00}, - 't': {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00}, - 'u': {0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00}, - 'w': {0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, 0x00}, - 'l': {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, - ' ': {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - ':': {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, - '/': {0x00, 0x02, 0x06, 0x0C, 0x18, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00}, - '[': {0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00}, - ']': {0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00}, -} - -type OverlayStyle struct { - BackgroundR, BackgroundG, BackgroundB, BackgroundA uint8 - TextR, TextG, TextB uint8 - AccentR, AccentG, AccentB uint8 -} - -var DefaultOverlayStyle = OverlayStyle{ - BackgroundR: 30, BackgroundG: 30, BackgroundB: 30, BackgroundA: 220, - TextR: 255, TextG: 255, TextB: 255, - AccentR: 100, AccentG: 180, AccentB: 255, -} - -func (r *RegionSelector) drawOverlay(os *OutputSurface, renderBuf *ShmBuffer) { - data := renderBuf.Data() - stride := renderBuf.Stride - w, h := renderBuf.Width, renderBuf.Height - format := os.screenFormat - - // Dim the entire buffer - for y := 0; y < h; y++ { - off := y * stride - for x := 0; x < w; x++ { - i := off + x*4 - if i+3 >= len(data) { - continue - } - data[i+0] = uint8(int(data[i+0]) * 3 / 5) - data[i+1] = uint8(int(data[i+1]) * 3 / 5) - data[i+2] = uint8(int(data[i+2]) * 3 / 5) - } - } - - r.drawHUD(data, stride, w, h, format) - - if !r.selection.hasSelection || r.selection.surface != os { - return - } - - scaleX := float64(w) / float64(os.logicalW) - scaleY := float64(h) / float64(os.logicalH) - - bx1 := int(r.selection.anchorX * scaleX) - by1 := int(r.selection.anchorY * scaleY) - bx2 := int(r.selection.currentX * scaleX) - by2 := int(r.selection.currentY * scaleY) - - if bx1 > bx2 { - bx1, bx2 = bx2, bx1 - } - if by1 > by2 { - by1, by2 = by2, by1 - } - - bx1 = clamp(bx1, 0, w-1) - by1 = clamp(by1, 0, h-1) - bx2 = clamp(bx2, 0, w-1) - by2 = clamp(by2, 0, h-1) - - srcBuf := r.getSourceBuffer(os) - srcData := srcBuf.Data() - for y := by1; y <= by2; y++ { - rowOff := y * stride - for x := bx1; x <= bx2; x++ { - si := y*srcBuf.Stride + x*4 - di := rowOff + x*4 - if si+3 >= len(srcData) || di+3 >= len(data) { - continue - } - data[di+0] = srcData[si+0] - data[di+1] = srcData[si+1] - data[di+2] = srcData[si+2] - data[di+3] = srcData[si+3] - } - } - - selW, selH := bx2-bx1+1, by2-by1+1 - if r.shiftHeld && selW != selH { - if selW < selH { - selH = selW - } else { - selW = selH - } - } - r.drawBorder(data, stride, w, h, bx1, by1, selW, selH, format) - r.drawDimensions(data, stride, w, h, bx1, by1, selW, selH, format) -} - -func (r *RegionSelector) drawHUD(data []byte, stride, bufW, bufH int, format uint32) { - if r.selection.dragging { - return - } - - style := LoadOverlayStyle() - const charW, charH, padding, itemSpacing = 8, 12, 12, 24 - - cursorLabel := "hide" - if !r.showCapturedCursor { - cursorLabel = "show" - } - captureKey := "Space/Enter" - if r.screenshoter != nil && r.screenshoter.config.NoConfirm { - captureKey = "Drag+Release" - } - - items := []struct{ key, desc string }{ - {captureKey, "capture"}, - {"P", cursorLabel + " cursor"}, - {"Esc", "cancel"}, - } - - totalW := 0 - for i, item := range items { - totalW += len(item.key)*(charW+1) + 4 + len(item.desc)*(charW+1) - if i < len(items)-1 { - totalW += itemSpacing - } - } - - hudW := totalW + padding*2 - hudH := charH + padding*2 - hudX := (bufW - hudW) / 2 - hudY := bufH - hudH - 20 - - r.fillRect(data, stride, bufW, bufH, hudX, hudY, hudW, hudH, - style.BackgroundR, style.BackgroundG, style.BackgroundB, style.BackgroundA, format) - - tx, ty := hudX+padding, hudY+padding - for i, item := range items { - r.drawText(data, stride, bufW, bufH, tx, ty, item.key, - style.AccentR, style.AccentG, style.AccentB, format) - tx += len(item.key) * (charW + 1) - - r.drawText(data, stride, bufW, bufH, tx, ty, " "+item.desc, - style.TextR, style.TextG, style.TextB, format) - tx += (1 + len(item.desc)) * (charW + 1) - - if i < len(items)-1 { - tx += itemSpacing - } - } -} - -func (r *RegionSelector) drawBorder(data []byte, stride, bufW, bufH, x, y, w, h int, format uint32) { - const thickness = 2 - for i := 0; i < thickness; i++ { - r.drawHLine(data, stride, bufW, bufH, x-i, y-i, w+2*i, format) - r.drawHLine(data, stride, bufW, bufH, x-i, y+h+i-1, w+2*i, format) - r.drawVLine(data, stride, bufW, bufH, x-i, y-i, h+2*i, format) - r.drawVLine(data, stride, bufW, bufH, x+w+i-1, y-i, h+2*i, format) - } -} - -func (r *RegionSelector) drawHLine(data []byte, stride, bufW, bufH, x, y, length int, _ uint32) { - if y < 0 || y >= bufH { - return - } - rowOff := y * stride - for i := 0; i < length; i++ { - px := x + i - if px < 0 || px >= bufW { - continue - } - off := rowOff + px*4 - if off+3 >= len(data) { - continue - } - data[off], data[off+1], data[off+2], data[off+3] = 255, 255, 255, 255 - } -} - -func (r *RegionSelector) drawVLine(data []byte, stride, bufW, bufH, x, y, length int, _ uint32) { - if x < 0 || x >= bufW { - return - } - for i := 0; i < length; i++ { - py := y + i - if py < 0 || py >= bufH { - continue - } - off := py*stride + x*4 - if off+3 >= len(data) { - continue - } - data[off], data[off+1], data[off+2], data[off+3] = 255, 255, 255, 255 - } -} - -func (r *RegionSelector) drawDimensions(data []byte, stride, bufW, bufH, x, y, w, h int, format uint32) { - text := fmt.Sprintf("%dx%d", w, h) - - const charW, charH = 8, 12 - textW := len(text) * (charW + 1) - textH := charH - - tx := x + (w-textW)/2 - ty := y + h + 8 - - if ty+textH > bufH { - ty = y - textH - 8 - } - tx = clamp(tx, 0, bufW-textW) - - r.fillRect(data, stride, bufW, bufH, tx-4, ty-2, textW+8, textH+4, 0, 0, 0, 200, format) - r.drawText(data, stride, bufW, bufH, tx, ty, text, 255, 255, 255, format) -} - -func (r *RegionSelector) fillRect(data []byte, stride, bufW, bufH, x, y, w, h int, cr, cg, cb, ca uint8, format uint32) { - alpha := float64(ca) / 255.0 - invAlpha := 1.0 - alpha - - c0, c2 := cb, cr - if format == uint32(FormatABGR8888) || format == uint32(FormatXBGR8888) { - c0, c2 = cr, cb - } - - for py := y; py < y+h && py < bufH; py++ { - if py < 0 { - continue - } - for px := x; px < x+w && px < bufW; px++ { - if px < 0 { - continue - } - off := py*stride + px*4 - if off+3 >= len(data) { - continue - } - data[off+0] = uint8(float64(data[off+0])*invAlpha + float64(c0)*alpha) - data[off+1] = uint8(float64(data[off+1])*invAlpha + float64(cg)*alpha) - data[off+2] = uint8(float64(data[off+2])*invAlpha + float64(c2)*alpha) - data[off+3] = 255 - } - } -} - -func (r *RegionSelector) drawText(data []byte, stride, bufW, bufH, x, y int, text string, cr, cg, cb uint8, format uint32) { - for i, ch := range text { - r.drawChar(data, stride, bufW, bufH, x+i*9, y, ch, cr, cg, cb, format) - } -} - -func (r *RegionSelector) drawChar(data []byte, stride, bufW, bufH, x, y int, ch rune, cr, cg, cb uint8, format uint32) { - glyph, ok := fontGlyphs[ch] - if !ok { - return - } - - c0, c2 := cb, cr - if format == uint32(FormatABGR8888) || format == uint32(FormatXBGR8888) { - c0, c2 = cr, cb - } - - for row := 0; row < 12; row++ { - py := y + row - if py < 0 || py >= bufH { - continue - } - bits := glyph[row] - for col := 0; col < 8; col++ { - if (bits & (1 << (7 - col))) == 0 { - continue - } - px := x + col - if px < 0 || px >= bufW { - continue - } - off := py*stride + px*4 - if off+3 >= len(data) { - continue - } - data[off], data[off+1], data[off+2], data[off+3] = c0, cg, c2, 255 - } - } -} - -func clamp(v, lo, hi int) int { - switch { - case v < lo: - return lo - case v > hi: - return hi - default: - return v - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/screenshot.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/screenshot.go deleted file mode 100644 index 42d3404..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/screenshot.go +++ /dev/null @@ -1,1089 +0,0 @@ -package screenshot - -import ( - "fmt" - "math" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_screencopy" - wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type WaylandOutput struct { - wlOutput *client.Output - globalName uint32 - name string - x, y int32 - width int32 - height int32 - scale int32 - fractionalScale float64 - transform int32 -} - -type CaptureResult struct { - Buffer *ShmBuffer - Region Region - YInverted bool - Format uint32 -} - -type Screenshoter struct { - config Config - - display *client.Display - registry *client.Registry - ctx *client.Context - - compositor *client.Compositor - shm *client.Shm - screencopy *wlr_screencopy.ZwlrScreencopyManagerV1 - - outputs map[uint32]*WaylandOutput - outputsMu sync.Mutex -} - -func New(config Config) *Screenshoter { - return &Screenshoter{ - config: config, - outputs: make(map[uint32]*WaylandOutput), - } -} - -func (s *Screenshoter) Run() (*CaptureResult, error) { - if err := s.connect(); err != nil { - return nil, fmt.Errorf("wayland connect: %w", err) - } - defer s.cleanup() - - if err := s.setupRegistry(); err != nil { - return nil, fmt.Errorf("registry setup: %w", err) - } - - if err := s.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - if s.screencopy == nil { - return nil, fmt.Errorf("compositor does not support wlr-screencopy-unstable-v1") - } - - if err := s.roundtrip(); err != nil { - return nil, fmt.Errorf("roundtrip: %w", err) - } - - switch s.config.Mode { - case ModeLastRegion: - return s.captureLastRegion() - case ModeRegion: - return s.captureRegion() - case ModeWindow: - return s.captureWindow() - case ModeOutput: - return s.captureOutput(s.config.OutputName) - case ModeFullScreen: - return s.captureFullScreen() - case ModeAllScreens: - return s.captureAllScreens() - default: - return s.captureRegion() - } -} - -func (s *Screenshoter) captureLastRegion() (*CaptureResult, error) { - lastRegion := GetLastRegion() - if lastRegion.IsEmpty() { - return s.captureRegion() - } - - output := s.findOutputForRegion(lastRegion) - if output == nil { - return s.captureRegion() - } - - return s.captureRegionOnOutput(output, lastRegion) -} - -func (s *Screenshoter) captureRegion() (*CaptureResult, error) { - if s.config.Reset { - if err := SaveLastRegion(Region{}); err != nil { - log.Debug("failed to reset last region", "err", err) - } - } - - selector := NewRegionSelector(s) - result, cancelled, err := selector.Run() - if err != nil { - return nil, fmt.Errorf("region selection: %w", err) - } - if cancelled || result == nil { - return nil, nil - } - - if err := SaveLastRegion(result.Region); err != nil { - log.Debug("failed to save last region", "err", err) - } - - return result, nil -} - -func (s *Screenshoter) captureWindow() (*CaptureResult, error) { - geom, err := GetActiveWindow() - if err != nil { - return nil, err - } - - region := Region{ - X: geom.X, - Y: geom.Y, - Width: geom.Width, - Height: geom.Height, - } - - var output *WaylandOutput - if geom.Output != "" { - output = s.findOutputByName(geom.Output) - } - if output == nil { - output = s.findOutputForRegion(region) - } - if output == nil { - return nil, fmt.Errorf("could not find output for window") - } - - switch DetectCompositor() { - case CompositorHyprland: - return s.captureAndCrop(output, region) - case CompositorDWL: - return s.captureDWLWindow(output, region, geom) - default: - return s.captureRegionOnOutput(output, region) - } -} - -func (s *Screenshoter) captureDWLWindow(output *WaylandOutput, region Region, geom *WindowGeometry) (*CaptureResult, error) { - result, err := s.captureWholeOutput(output) - if err != nil { - return nil, err - } - - scale := geom.Scale - if scale <= 0 || scale == 1.0 { - if output.fractionalScale > 1.0 { - scale = output.fractionalScale - } - } - if scale <= 0 { - scale = 1.0 - } - - localX := int(float64(region.X-geom.OutputX) * scale) - localY := int(float64(region.Y-geom.OutputY) * scale) - w := int(float64(region.Width) * scale) - h := int(float64(region.Height) * scale) - - if localX < 0 { - w += localX - localX = 0 - } - if localY < 0 { - h += localY - localY = 0 - } - if localX+w > result.Buffer.Width { - w = result.Buffer.Width - localX - } - if localY+h > result.Buffer.Height { - h = result.Buffer.Height - localY - } - - if w <= 0 || h <= 0 { - result.Buffer.Close() - return nil, fmt.Errorf("window not visible on output") - } - - cropped, err := CreateShmBuffer(w, h, w*4) - if err != nil { - result.Buffer.Close() - return nil, fmt.Errorf("create crop buffer: %w", err) - } - - srcData := result.Buffer.Data() - dstData := cropped.Data() - - for y := 0; y < h; y++ { - srcY := localY + y - if result.YInverted { - srcY = result.Buffer.Height - 1 - (localY + y) - } - if srcY < 0 || srcY >= result.Buffer.Height { - continue - } - - dstY := y - if result.YInverted { - dstY = h - 1 - y - } - - for x := 0; x < w; x++ { - srcX := localX + x - if srcX < 0 || srcX >= result.Buffer.Width { - continue - } - - si := srcY*result.Buffer.Stride + srcX*4 - di := dstY*cropped.Stride + x*4 - - if si+3 >= len(srcData) || di+3 >= len(dstData) { - continue - } - - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - dstData[di+3] = srcData[si+3] - } - } - - result.Buffer.Close() - cropped.Format = PixelFormat(result.Format) - - return &CaptureResult{ - Buffer: cropped, - Region: region, - YInverted: false, - Format: result.Format, - }, nil -} - -func (s *Screenshoter) captureFullScreen() (*CaptureResult, error) { - output := s.findFocusedOutput() - if output == nil { - s.outputsMu.Lock() - for _, o := range s.outputs { - output = o - break - } - s.outputsMu.Unlock() - } - - if output == nil { - return nil, fmt.Errorf("no output available") - } - - return s.captureWholeOutput(output) -} - -func (s *Screenshoter) captureOutput(name string) (*CaptureResult, error) { - s.outputsMu.Lock() - var output *WaylandOutput - for _, o := range s.outputs { - if o.name == name { - output = o - break - } - } - s.outputsMu.Unlock() - - if output == nil { - return nil, fmt.Errorf("output %q not found", name) - } - - return s.captureWholeOutput(output) -} - -func (s *Screenshoter) captureAllScreens() (*CaptureResult, error) { - s.outputsMu.Lock() - outputs := make([]*WaylandOutput, 0, len(s.outputs)) - for _, o := range s.outputs { - outputs = append(outputs, o) - } - s.outputsMu.Unlock() - - if len(outputs) == 0 { - return nil, fmt.Errorf("no outputs available") - } - if len(outputs) == 1 { - return s.captureWholeOutput(outputs[0]) - } - - wlrInfos := getAllOutputInfos() - - type pendingOutput struct { - result *CaptureResult - logX float64 - logY float64 - scale float64 - } - var pending []pendingOutput - maxScale := 1.0 - - for _, output := range outputs { - result, err := s.captureWholeOutput(output) - if err != nil { - log.Warn("failed to capture output", "name", output.name, "err", err) - continue - } - - logX, logY := float64(output.x), float64(output.y) - scale := float64(output.scale) - - switch DetectCompositor() { - case CompositorHyprland: - if hx, hy, _, _, ok := GetHyprlandMonitorGeometry(output.name); ok { - logX, logY = float64(hx), float64(hy) - } - if hs := GetHyprlandMonitorScale(output.name); hs > 0 { - scale = hs - } - default: - if wlrInfos != nil { - if info, ok := wlrInfos[output.name]; ok { - logX, logY = float64(info.x), float64(info.y) - if info.scale > 0 { - scale = info.scale - } - } - } - } - - if scale <= 0 { - scale = 1.0 - } - - pending = append(pending, pendingOutput{result: result, logX: logX, logY: logY, scale: scale}) - if scale > maxScale { - maxScale = scale - } - } - - if len(pending) == 0 { - return nil, fmt.Errorf("failed to capture any outputs") - } - if len(pending) == 1 { - return pending[0].result, nil - } - - type layoutEntry struct { - result *CaptureResult - canvasX int - canvasY int - canvasW int - canvasH int - } - entries := make([]layoutEntry, len(pending)) - var minX, minY, maxX, maxY int - - for i, p := range pending { - cx := int(math.Round(p.logX * maxScale)) - cy := int(math.Round(p.logY * maxScale)) - cw := int(math.Round(float64(p.result.Buffer.Width) * maxScale / p.scale)) - ch := int(math.Round(float64(p.result.Buffer.Height) * maxScale / p.scale)) - - entries[i] = layoutEntry{result: p.result, canvasX: cx, canvasY: cy, canvasW: cw, canvasH: ch} - - right := cx + cw - bottom := cy + ch - if i == 0 { - minX, minY, maxX, maxY = cx, cy, right, bottom - continue - } - if cx < minX { - minX = cx - } - if cy < minY { - minY = cy - } - if right > maxX { - maxX = right - } - if bottom > maxY { - maxY = bottom - } - } - - totalW := maxX - minX - totalH := maxY - minY - composite, err := CreateShmBuffer(totalW, totalH, totalW*4) - if err != nil { - for _, e := range entries { - e.result.Buffer.Close() - } - return nil, fmt.Errorf("create composite buffer: %w", err) - } - composite.Clear() - - var format uint32 - for _, e := range entries { - if format == 0 { - format = e.result.Format - } - s.blitBufferScaled(composite, e.result.Buffer, - e.canvasX-minX, e.canvasY-minY, e.canvasW, e.canvasH, - e.result.YInverted) - e.result.Buffer.Close() - } - - return &CaptureResult{ - Buffer: composite, - Region: Region{X: int32(minX), Y: int32(minY), Width: int32(totalW), Height: int32(totalH)}, - Format: format, - }, nil -} - -func (s *Screenshoter) blitBufferScaled(dst, src *ShmBuffer, dstX, dstY, dstW, dstH int, yInverted bool) { - if dstW <= 0 || dstH <= 0 { - return - } - - srcData := src.Data() - dstData := dst.Data() - - for dy := 0; dy < dstH; dy++ { - canvasY := dstY + dy - if canvasY < 0 || canvasY >= dst.Height { - continue - } - - srcY := dy * src.Height / dstH - if yInverted { - srcY = src.Height - 1 - srcY - } - if srcY < 0 || srcY >= src.Height { - continue - } - - srcRowOff := srcY * src.Stride - dstRowOff := canvasY * dst.Stride - - for dx := 0; dx < dstW; dx++ { - canvasX := dstX + dx - if canvasX < 0 || canvasX >= dst.Width { - continue - } - - srcX := dx * src.Width / dstW - if srcX >= src.Width { - continue - } - - si := srcRowOff + srcX*4 - di := dstRowOff + canvasX*4 - - if si+3 >= len(srcData) || di+3 >= len(dstData) { - continue - } - - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - dstData[di+3] = srcData[si+3] - } - } -} - -func (s *Screenshoter) captureWholeOutput(output *WaylandOutput) (*CaptureResult, error) { - cursor := int32(s.config.Cursor) - - frame, err := s.screencopy.CaptureOutput(cursor, output.wlOutput) - if err != nil { - return nil, fmt.Errorf("capture output: %w", err) - } - - result, err := s.processFrame(frame, Region{ - X: output.x, - Y: output.y, - Width: output.width, - Height: output.height, - Output: output.name, - }) - if err != nil { - return nil, err - } - - if result.YInverted { - result.Buffer.FlipVertical() - result.YInverted = false - } - - if output.transform == TransformNormal { - return result, nil - } - - invTransform := InverseTransform(output.transform) - transformed, err := result.Buffer.ApplyTransform(invTransform) - if err != nil { - result.Buffer.Close() - return nil, fmt.Errorf("apply transform: %w", err) - } - - if transformed != result.Buffer { - result.Buffer.Close() - result.Buffer = transformed - } - - result.Region.Width = int32(transformed.Width) - result.Region.Height = int32(transformed.Height) - - return result, nil -} - -func (s *Screenshoter) captureAndCrop(output *WaylandOutput, region Region) (*CaptureResult, error) { - result, err := s.captureWholeOutput(output) - if err != nil { - return nil, err - } - - outX, outY := output.x, output.y - scale := float64(output.scale) - if hx, hy, _, _, ok := GetHyprlandMonitorGeometry(output.name); ok { - outX, outY = hx, hy - } - if s := GetHyprlandMonitorScale(output.name); s > 0 { - scale = s - } - if scale <= 0 { - scale = 1.0 - } - - localX := int(float64(region.X-outX) * scale) - localY := int(float64(region.Y-outY) * scale) - w := int(float64(region.Width) * scale) - h := int(float64(region.Height) * scale) - - cropped, err := CreateShmBuffer(w, h, w*4) - if err != nil { - result.Buffer.Close() - return nil, fmt.Errorf("create crop buffer: %w", err) - } - - srcData := result.Buffer.Data() - dstData := cropped.Data() - - for y := 0; y < h; y++ { - srcY := localY + y - if result.YInverted { - srcY = result.Buffer.Height - 1 - (localY + y) - } - if srcY < 0 || srcY >= result.Buffer.Height { - continue - } - - dstY := y - if result.YInverted { - dstY = h - 1 - y - } - - for x := 0; x < w; x++ { - srcX := localX + x - if srcX < 0 || srcX >= result.Buffer.Width { - continue - } - - si := srcY*result.Buffer.Stride + srcX*4 - di := dstY*cropped.Stride + x*4 - - if si+3 >= len(srcData) || di+3 >= len(dstData) { - continue - } - - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - dstData[di+3] = srcData[si+3] - } - } - - result.Buffer.Close() - cropped.Format = PixelFormat(result.Format) - - return &CaptureResult{ - Buffer: cropped, - Region: region, - YInverted: false, - Format: result.Format, - }, nil -} - -func (s *Screenshoter) captureRegionOnOutput(output *WaylandOutput, region Region) (*CaptureResult, error) { - if output.transform != TransformNormal { - return s.captureRegionOnTransformedOutput(output, region) - } - - scale := output.fractionalScale - if scale <= 0 && DetectCompositor() == CompositorHyprland { - scale = GetHyprlandMonitorScale(output.name) - } - if scale <= 0 { - scale = float64(output.scale) - } - if scale <= 0 { - scale = 1.0 - } - - localX := int32(float64(region.X-output.x) * scale) - localY := int32(float64(region.Y-output.y) * scale) - w := int32(float64(region.Width) * scale) - h := int32(float64(region.Height) * scale) - - if DetectCompositor() == CompositorDWL { - scaledOutW := int32(float64(output.width) * scale) - scaledOutH := int32(float64(output.height) * scale) - if localX >= scaledOutW { - localX = localX % scaledOutW - } - if localY >= scaledOutH { - localY = localY % scaledOutH - } - if localX+w > scaledOutW { - w = scaledOutW - localX - } - if localY+h > scaledOutH { - h = scaledOutH - localY - } - if localX < 0 { - w += localX - localX = 0 - } - if localY < 0 { - h += localY - localY = 0 - } - } - - cursor := int32(s.config.Cursor) - - frame, err := s.screencopy.CaptureOutputRegion(cursor, output.wlOutput, localX, localY, w, h) - if err != nil { - return nil, fmt.Errorf("capture region: %w", err) - } - - return s.processFrame(frame, region) -} - -func (s *Screenshoter) captureRegionOnTransformedOutput(output *WaylandOutput, region Region) (*CaptureResult, error) { - result, err := s.captureWholeOutput(output) - if err != nil { - return nil, err - } - - scale := output.fractionalScale - if scale <= 0 && DetectCompositor() == CompositorHyprland { - scale = GetHyprlandMonitorScale(output.name) - } - if scale <= 0 { - scale = float64(output.scale) - } - if scale <= 0 { - scale = 1.0 - } - - localX := int(float64(region.X-output.x) * scale) - localY := int(float64(region.Y-output.y) * scale) - w := int(float64(region.Width) * scale) - h := int(float64(region.Height) * scale) - - if localX < 0 { - w += localX - localX = 0 - } - if localY < 0 { - h += localY - localY = 0 - } - if localX+w > result.Buffer.Width { - w = result.Buffer.Width - localX - } - if localY+h > result.Buffer.Height { - h = result.Buffer.Height - localY - } - - if w <= 0 || h <= 0 { - result.Buffer.Close() - return nil, fmt.Errorf("region not visible on output") - } - - cropped, err := CreateShmBuffer(w, h, w*4) - if err != nil { - result.Buffer.Close() - return nil, fmt.Errorf("create crop buffer: %w", err) - } - - srcData := result.Buffer.Data() - dstData := cropped.Data() - - for y := 0; y < h; y++ { - srcOff := (localY+y)*result.Buffer.Stride + localX*4 - dstOff := y * cropped.Stride - if srcOff+w*4 <= len(srcData) && dstOff+w*4 <= len(dstData) { - copy(dstData[dstOff:dstOff+w*4], srcData[srcOff:srcOff+w*4]) - } - } - - result.Buffer.Close() - cropped.Format = PixelFormat(result.Format) - - return &CaptureResult{ - Buffer: cropped, - Region: region, - YInverted: false, - Format: result.Format, - }, nil -} - -func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1, region Region) (*CaptureResult, error) { - var buf *ShmBuffer - var pool *client.ShmPool - var wlBuf *client.Buffer - var format PixelFormat - var yInverted bool - ready := false - failed := false - - frame.SetBufferHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferEvent) { - format = PixelFormat(e.Format) - bpp := format.BytesPerPixel() - if int(e.Stride) < int(e.Width)*bpp { - log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width, "bpp", bpp) - return - } - var err error - buf, err = CreateShmBuffer(int(e.Width), int(e.Height), int(e.Stride)) - if err != nil { - log.Error("failed to create buffer", "err", err) - return - } - buf.Format = format - }) - - frame.SetFlagsHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FlagsEvent) { - yInverted = (e.Flags & 1) != 0 - }) - - frame.SetBufferDoneHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferDoneEvent) { - if buf == nil { - return - } - - var err error - pool, err = s.shm.CreatePool(buf.Fd(), int32(buf.Size())) - if err != nil { - log.Error("failed to create pool", "err", err) - return - } - - wlBuf, err = pool.CreateBuffer(0, int32(buf.Width), int32(buf.Height), int32(buf.Stride), uint32(format)) - if err != nil { - pool.Destroy() - pool = nil - log.Error("failed to create wl_buffer", "err", err) - return - } - - if err := frame.Copy(wlBuf); err != nil { - log.Error("failed to copy frame", "err", err) - } - }) - - frame.SetReadyHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1ReadyEvent) { - ready = true - }) - - frame.SetFailedHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1FailedEvent) { - failed = true - }) - - for !ready && !failed { - if err := s.ctx.Dispatch(); err != nil { - frame.Destroy() - return nil, fmt.Errorf("dispatch: %w", err) - } - } - - frame.Destroy() - if wlBuf != nil { - wlBuf.Destroy() - } - if pool != nil { - pool.Destroy() - } - - if failed { - if buf != nil { - buf.Close() - } - return nil, fmt.Errorf("frame capture failed") - } - - if format.Is24Bit() { - converted, newFormat, err := buf.ConvertTo32Bit(format) - if err != nil { - buf.Close() - return nil, fmt.Errorf("convert 24-bit to 32-bit: %w", err) - } - if converted != buf { - buf.Close() - buf = converted - } - format = newFormat - } - - return &CaptureResult{ - Buffer: buf, - Region: region, - YInverted: yInverted, - Format: uint32(format), - }, nil -} - -func (s *Screenshoter) findOutputByName(name string) *WaylandOutput { - s.outputsMu.Lock() - defer s.outputsMu.Unlock() - for _, o := range s.outputs { - if o.name == name { - return o - } - } - return nil -} - -func (s *Screenshoter) findOutputForRegion(region Region) *WaylandOutput { - s.outputsMu.Lock() - defer s.outputsMu.Unlock() - - cx := region.X + region.Width/2 - cy := region.Y + region.Height/2 - - for _, o := range s.outputs { - x, y, w, h := o.x, o.y, o.width, o.height - if DetectCompositor() == CompositorHyprland { - if hx, hy, hw, hh, ok := GetHyprlandMonitorGeometry(o.name); ok { - x, y, w, h = hx, hy, hw, hh - } - } - if cx >= x && cx < x+w && cy >= y && cy < y+h { - return o - } - } - - for _, o := range s.outputs { - x, y, w, h := o.x, o.y, o.width, o.height - if DetectCompositor() == CompositorHyprland { - if hx, hy, hw, hh, ok := GetHyprlandMonitorGeometry(o.name); ok { - x, y, w, h = hx, hy, hw, hh - } - } - if region.X >= x && region.X < x+w && - region.Y >= y && region.Y < y+h { - return o - } - } - - return nil -} - -func (s *Screenshoter) findFocusedOutput() *WaylandOutput { - if mon := GetFocusedMonitor(); mon != "" { - s.outputsMu.Lock() - defer s.outputsMu.Unlock() - for _, o := range s.outputs { - if o.name == mon { - return o - } - } - } - s.outputsMu.Lock() - defer s.outputsMu.Unlock() - for _, o := range s.outputs { - return o - } - return nil -} - -func (s *Screenshoter) connect() error { - display, err := client.Connect("") - if err != nil { - return err - } - s.display = display - s.ctx = display.Context() - return nil -} - -func (s *Screenshoter) roundtrip() error { - return wlhelpers.Roundtrip(s.display, s.ctx) -} - -func (s *Screenshoter) setupRegistry() error { - registry, err := s.display.GetRegistry() - if err != nil { - return err - } - s.registry = registry - - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - s.handleGlobal(e) - }) - - registry.SetGlobalRemoveHandler(func(e client.RegistryGlobalRemoveEvent) { - s.outputsMu.Lock() - delete(s.outputs, e.Name) - s.outputsMu.Unlock() - }) - - return nil -} - -func (s *Screenshoter) handleGlobal(e client.RegistryGlobalEvent) { - switch e.Interface { - case client.CompositorInterfaceName: - comp := client.NewCompositor(s.ctx) - if err := s.registry.Bind(e.Name, e.Interface, e.Version, comp); err == nil { - s.compositor = comp - } - - case client.ShmInterfaceName: - shm := client.NewShm(s.ctx) - if err := s.registry.Bind(e.Name, e.Interface, e.Version, shm); err == nil { - s.shm = shm - } - - case client.OutputInterfaceName: - output := client.NewOutput(s.ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := s.registry.Bind(e.Name, e.Interface, version, output); err == nil { - s.outputsMu.Lock() - s.outputs[e.Name] = &WaylandOutput{ - wlOutput: output, - globalName: e.Name, - scale: 1, - fractionalScale: 1.0, - } - s.outputsMu.Unlock() - s.setupOutputHandlers(e.Name, output) - } - - case wlr_screencopy.ZwlrScreencopyManagerV1InterfaceName: - sc := wlr_screencopy.NewZwlrScreencopyManagerV1(s.ctx) - version := e.Version - if version > 3 { - version = 3 - } - if err := s.registry.Bind(e.Name, e.Interface, version, sc); err == nil { - s.screencopy = sc - } - } -} - -func (s *Screenshoter) setupOutputHandlers(name uint32, output *client.Output) { - output.SetGeometryHandler(func(e client.OutputGeometryEvent) { - s.outputsMu.Lock() - if o, ok := s.outputs[name]; ok { - o.x, o.y = e.X, e.Y - o.transform = int32(e.Transform) - } - s.outputsMu.Unlock() - }) - - output.SetModeHandler(func(e client.OutputModeEvent) { - if e.Flags&uint32(client.OutputModeCurrent) == 0 { - return - } - s.outputsMu.Lock() - if o, ok := s.outputs[name]; ok { - o.width, o.height = e.Width, e.Height - } - s.outputsMu.Unlock() - }) - - output.SetScaleHandler(func(e client.OutputScaleEvent) { - s.outputsMu.Lock() - if o, ok := s.outputs[name]; ok { - o.scale = e.Factor - o.fractionalScale = float64(e.Factor) - } - s.outputsMu.Unlock() - }) - - output.SetNameHandler(func(e client.OutputNameEvent) { - s.outputsMu.Lock() - if o, ok := s.outputs[name]; ok { - o.name = e.Name - } - s.outputsMu.Unlock() - }) -} - -func (s *Screenshoter) cleanup() { - if s.screencopy != nil { - s.screencopy.Destroy() - } - if s.display != nil { - s.ctx.Close() - } -} - -func (s *Screenshoter) GetOutputs() []*WaylandOutput { - s.outputsMu.Lock() - defer s.outputsMu.Unlock() - out := make([]*WaylandOutput, 0, len(s.outputs)) - for _, o := range s.outputs { - out = append(out, o) - } - return out -} - -func ListOutputs() ([]Output, error) { - sc := New(DefaultConfig()) - if err := sc.connect(); err != nil { - return nil, err - } - defer sc.cleanup() - - if err := sc.setupRegistry(); err != nil { - return nil, err - } - if err := sc.roundtrip(); err != nil { - return nil, err - } - if err := sc.roundtrip(); err != nil { - return nil, err - } - - sc.outputsMu.Lock() - defer sc.outputsMu.Unlock() - - compositor := DetectCompositor() - result := make([]Output, 0, len(sc.outputs)) - for _, o := range sc.outputs { - out := Output{ - Name: o.name, - X: o.x, - Y: o.y, - Width: o.width, - Height: o.height, - Scale: o.scale, - FractionalScale: o.fractionalScale, - Transform: o.transform, - } - - switch compositor { - case CompositorHyprland: - if hx, hy, hw, hh, ok := GetHyprlandMonitorGeometry(o.name); ok { - out.X, out.Y = hx, hy - out.Width, out.Height = hw, hh - } - if s := GetHyprlandMonitorScale(o.name); s > 0 { - out.FractionalScale = s - } - } - - result = append(result, out) - } - return result, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/shm.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/shm.go deleted file mode 100644 index a178cf0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/shm.go +++ /dev/null @@ -1,35 +0,0 @@ -package screenshot - -import "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/shm" - -type PixelFormat = shm.PixelFormat - -const ( - FormatARGB8888 = shm.FormatARGB8888 - FormatXRGB8888 = shm.FormatXRGB8888 - FormatABGR8888 = shm.FormatABGR8888 - FormatXBGR8888 = shm.FormatXBGR8888 - FormatRGB888 = shm.FormatRGB888 - FormatBGR888 = shm.FormatBGR888 -) - -const ( - TransformNormal = shm.TransformNormal - Transform90 = shm.Transform90 - Transform180 = shm.Transform180 - Transform270 = shm.Transform270 - TransformFlipped = shm.TransformFlipped - TransformFlipped90 = shm.TransformFlipped90 - TransformFlipped180 = shm.TransformFlipped180 - TransformFlipped270 = shm.TransformFlipped270 -) - -type ShmBuffer = shm.Buffer - -func CreateShmBuffer(width, height, stride int) (*ShmBuffer, error) { - return shm.CreateBuffer(width, height, stride) -} - -func InverseTransform(transform int32) int32 { - return shm.InverseTransform(transform) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/state.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/state.go deleted file mode 100644 index 0ba6c63..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/state.go +++ /dev/null @@ -1,65 +0,0 @@ -package screenshot - -import ( - "encoding/json" - "os" - "path" - "path/filepath" -) - -type PersistentState struct { - LastRegion Region `json:"last_region"` -} - -func getStateFilePath() string { - cacheDir, err := os.UserCacheDir() - if err != nil { - cacheDir = path.Join(os.Getenv("HOME"), ".cache") - } - return filepath.Join(cacheDir, "dms", "screenshot-state.json") -} - -func LoadState() (*PersistentState, error) { - path := getStateFilePath() - data, err := os.ReadFile(path) - if err != nil { - if os.IsNotExist(err) { - return &PersistentState{}, nil - } - return nil, err - } - - var state PersistentState - if err := json.Unmarshal(data, &state); err != nil { - return &PersistentState{}, nil - } - return &state, nil -} - -func SaveState(state *PersistentState) error { - path := getStateFilePath() - dir := filepath.Dir(path) - if err := os.MkdirAll(dir, 0o755); err != nil { - return err - } - - data, err := json.MarshalIndent(state, "", " ") - if err != nil { - return err - } - return os.WriteFile(path, data, 0o644) -} - -func GetLastRegion() Region { - state, err := LoadState() - if err != nil { - return Region{} - } - return state.LastRegion -} - -func SaveLastRegion(r Region) error { - state, _ := LoadState() - state.LastRegion = r - return SaveState(state) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/theme.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/theme.go deleted file mode 100644 index a2bd5f6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/theme.go +++ /dev/null @@ -1,125 +0,0 @@ -package screenshot - -import ( - "encoding/json" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -type ThemeColors struct { - Background string `json:"surface"` - OnSurface string `json:"on_surface"` - Primary string `json:"primary"` -} - -type ColorScheme struct { - Dark ThemeColors `json:"dark"` - Light ThemeColors `json:"light"` -} - -type ColorsFile struct { - Colors ColorScheme `json:"colors"` -} - -var cachedStyle *OverlayStyle - -func LoadOverlayStyle() OverlayStyle { - if cachedStyle != nil { - return *cachedStyle - } - - style := DefaultOverlayStyle - colors := loadColorsFile() - if colors == nil { - cachedStyle = &style - return style - } - - theme := &colors.Dark - if isLightMode() { - theme = &colors.Light - } - - if bg, ok := parseHexColor(theme.Background); ok { - style.BackgroundR, style.BackgroundG, style.BackgroundB = bg[0], bg[1], bg[2] - } - if text, ok := parseHexColor(theme.OnSurface); ok { - style.TextR, style.TextG, style.TextB = text[0], text[1], text[2] - } - if accent, ok := parseHexColor(theme.Primary); ok { - style.AccentR, style.AccentG, style.AccentB = accent[0], accent[1], accent[2] - } - - cachedStyle = &style - return style -} - -func loadColorsFile() *ColorScheme { - path := getColorsFilePath() - data, err := os.ReadFile(path) - if err != nil { - return nil - } - - var file ColorsFile - if err := json.Unmarshal(data, &file); err != nil { - return nil - } - - return &file.Colors -} - -func getColorsFilePath() string { - cacheDir, err := os.UserCacheDir() - if err != nil { - log.Error("Failed to get user cache dir", "err", err) - return "" - } - return filepath.Join(cacheDir, "DankMaterialShell", "dms-colors.json") -} - -func isLightMode() bool { - scheme, err := utils.GsettingsGet("org.gnome.desktop.interface", "color-scheme") - if err != nil { - return false - } - - switch scheme { - case "'prefer-light'", "'default'": - return true - } - return false -} - -func parseHexColor(hex string) ([3]uint8, bool) { - hex = strings.TrimPrefix(hex, "#") - if len(hex) != 6 { - return [3]uint8{}, false - } - - var r, g, b uint8 - for i, ptr := range []*uint8{&r, &g, &b} { - val := 0 - for j := 0; j < 2; j++ { - c := hex[i*2+j] - val *= 16 - switch { - case c >= '0' && c <= '9': - val += int(c - '0') - case c >= 'a' && c <= 'f': - val += int(c - 'a' + 10) - case c >= 'A' && c <= 'F': - val += int(c - 'A' + 10) - default: - return [3]uint8{}, false - } - } - *ptr = uint8(val) - } - - return [3]uint8{r, g, b}, true -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/types.go deleted file mode 100644 index 00cbe1c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/screenshot/types.go +++ /dev/null @@ -1,81 +0,0 @@ -package screenshot - -type Mode int - -const ( - ModeRegion Mode = iota - ModeWindow - ModeFullScreen - ModeAllScreens - ModeOutput - ModeLastRegion -) - -type Format int - -const ( - FormatPNG Format = iota - FormatJPEG - FormatPPM -) - -type CursorMode int - -const ( - CursorOff CursorMode = iota - CursorOn -) - -type Region struct { - X int32 `json:"x"` - Y int32 `json:"y"` - Width int32 `json:"width"` - Height int32 `json:"height"` - Output string `json:"output,omitempty"` -} - -func (r Region) IsEmpty() bool { - return r.Width <= 0 || r.Height <= 0 -} - -type Output struct { - Name string - X, Y int32 - Width int32 - Height int32 - Scale int32 - FractionalScale float64 - Transform int32 -} - -type Config struct { - Mode Mode - OutputName string - Cursor CursorMode - NoConfirm bool - Reset bool - Format Format - Quality int - OutputDir string - Filename string - Clipboard bool - SaveFile bool - Notify bool - Stdout bool -} - -func DefaultConfig() Config { - return Config{ - Mode: ModeRegion, - Cursor: CursorOff, - NoConfirm: false, - Reset: false, - Format: FormatPNG, - Quality: 90, - OutputDir: "", - Filename: "", - Clipboard: true, - SaveFile: true, - Notify: true, - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/handlers.go deleted file mode 100644 index 007ab3e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/handlers.go +++ /dev/null @@ -1,51 +0,0 @@ -package apppicker - -import ( - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "apppicker.open", "browser.open": - handleOpen(conn, req, manager) - default: - models.RespondError(conn, req.ID, "unknown method") - } -} - -func handleOpen(conn net.Conn, req models.Request, manager *Manager) { - log.Infof("AppPicker: Received %s request with params: %+v", req.Method, req.Params) - - target, ok := models.Get[string](req, "target") - if !ok { - target, ok = models.Get[string](req, "url") - if !ok { - log.Warnf("AppPicker: Invalid target parameter in request") - models.RespondError(conn, req.ID, "invalid target parameter") - return - } - } - - event := OpenEvent{ - Target: target, - RequestType: models.GetOr(req, "requestType", "url"), - MimeType: models.GetOr(req, "mimeType", ""), - } - - if categories, ok := models.Get[[]any](req, "categories"); ok { - event.Categories = make([]string, 0, len(categories)) - for _, cat := range categories { - if catStr, ok := cat.(string); ok { - event.Categories = append(event.Categories, catStr) - } - } - } - - log.Infof("AppPicker: Broadcasting event: %+v", event) - manager.RequestOpen(event) - models.Respond(conn, req.ID, "ok") - log.Infof("AppPicker: Request handled successfully") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/manager.go deleted file mode 100644 index bde0846..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/manager.go +++ /dev/null @@ -1,48 +0,0 @@ -package apppicker - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type Manager struct { - subscribers syncmap.Map[string, chan OpenEvent] - closeOnce sync.Once -} - -func NewManager() *Manager { - return &Manager{} -} - -func (m *Manager) Subscribe(id string) chan OpenEvent { - ch := make(chan OpenEvent, 16) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) RequestOpen(event OpenEvent) { - m.subscribers.Range(func(key string, ch chan OpenEvent) bool { - select { - case ch <- event: - default: - } - return true - }) -} - -func (m *Manager) Close() { - m.closeOnce.Do(func() { - m.subscribers.Range(func(key string, ch chan OpenEvent) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/models.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/models.go deleted file mode 100644 index 8861461..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/apppicker/models.go +++ /dev/null @@ -1,8 +0,0 @@ -package apppicker - -type OpenEvent struct { - Target string `json:"target"` - MimeType string `json:"mimeType,omitempty"` - Categories []string `json:"categories,omitempty"` - RequestType string `json:"requestType"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/agent.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/agent.go deleted file mode 100644 index b630a19..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/agent.go +++ /dev/null @@ -1,341 +0,0 @@ -package bluez - -import ( - "context" - "errors" - "fmt" - "strconv" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - bluezService = "org.bluez" - agentManagerPath = "/org/bluez" - agentManagerIface = "org.bluez.AgentManager1" - agent1Iface = "org.bluez.Agent1" - device1Iface = "org.bluez.Device1" - agentPath = "/com/danklinux/bluez/agent" - agentCapability = "KeyboardDisplay" -) - -const introspectXML = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -` - -type BluezAgent struct { - conn *dbus.Conn - broker PromptBroker -} - -func NewBluezAgent(broker PromptBroker) (*BluezAgent, error) { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("system bus connection failed: %w", err) - } - - agent := &BluezAgent{ - conn: conn, - broker: broker, - } - - if err := conn.Export(agent, dbus.ObjectPath(agentPath), agent1Iface); err != nil { - conn.Close() - return nil, fmt.Errorf("agent export failed: %w", err) - } - - if err := conn.Export(agent, dbus.ObjectPath(agentPath), "org.freedesktop.DBus.Introspectable"); err != nil { - conn.Close() - return nil, fmt.Errorf("introspection export failed: %w", err) - } - - mgr := conn.Object(bluezService, dbus.ObjectPath(agentManagerPath)) - if err := mgr.Call(agentManagerIface+".RegisterAgent", 0, dbus.ObjectPath(agentPath), agentCapability).Err; err != nil { - conn.Close() - return nil, fmt.Errorf("agent registration failed: %w", err) - } - - if err := mgr.Call(agentManagerIface+".RequestDefaultAgent", 0, dbus.ObjectPath(agentPath)).Err; err != nil { - log.Debugf("[BluezAgent] not default agent: %v", err) - } - - log.Infof("[BluezAgent] registered at %s with capability %s", agentPath, agentCapability) - return agent, nil -} - -func (a *BluezAgent) Close() { - if a.conn == nil { - return - } - mgr := a.conn.Object(bluezService, dbus.ObjectPath(agentManagerPath)) - mgr.Call(agentManagerIface+".UnregisterAgent", 0, dbus.ObjectPath(agentPath)) - a.conn.Close() -} - -func (a *BluezAgent) Release() *dbus.Error { - log.Infof("[BluezAgent] Release called") - return nil -} - -func (a *BluezAgent) RequestPinCode(device dbus.ObjectPath) (string, *dbus.Error) { - log.Infof("[BluezAgent] RequestPinCode: device=%s", device) - - secrets, err := a.promptFor(device, "pin", []string{"pin"}, nil) - if err != nil { - log.Warnf("[BluezAgent] RequestPinCode failed: %v", err) - return "", a.errorFrom(err) - } - - pin := secrets["pin"] - log.Infof("[BluezAgent] RequestPinCode returning PIN (len=%d)", len(pin)) - return pin, nil -} - -func (a *BluezAgent) RequestPasskey(device dbus.ObjectPath) (uint32, *dbus.Error) { - log.Infof("[BluezAgent] RequestPasskey: device=%s", device) - - secrets, err := a.promptFor(device, "passkey", []string{"passkey"}, nil) - if err != nil { - log.Warnf("[BluezAgent] RequestPasskey failed: %v", err) - return 0, a.errorFrom(err) - } - - passkey, err := strconv.ParseUint(secrets["passkey"], 10, 32) - if err != nil { - log.Warnf("[BluezAgent] invalid passkey format: %v", err) - return 0, dbus.MakeFailedError(fmt.Errorf("invalid passkey: %w", err)) - } - - log.Infof("[BluezAgent] RequestPasskey returning: %d", passkey) - return uint32(passkey), nil -} - -func (a *BluezAgent) DisplayPinCode(device dbus.ObjectPath, pincode string) *dbus.Error { - log.Infof("[BluezAgent] DisplayPinCode: device=%s, pin=%s", device, pincode) - - _, err := a.promptFor(device, "display-pin", []string{}, &pincode) - if err != nil { - log.Warnf("[BluezAgent] DisplayPinCode acknowledgment failed: %v", err) - } - - return nil -} - -func (a *BluezAgent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error { - log.Infof("[BluezAgent] DisplayPasskey: device=%s, passkey=%06d, entered=%d", device, passkey, entered) - - if entered == 0 { - passkeyStr := strconv.FormatUint(uint64(passkey), 10) - _, err := a.promptFor(device, "display-passkey", []string{}, &passkeyStr) - if err != nil { - log.Warnf("[BluezAgent] DisplayPasskey acknowledgment failed: %v", err) - } - } - - return nil -} - -func (a *BluezAgent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error { - log.Infof("[BluezAgent] RequestConfirmation: device=%s, passkey=%06d", device, passkey) - - passkeyStr := strconv.FormatUint(uint64(passkey), 10) - secrets, err := a.promptFor(device, "confirm", []string{"decision"}, &passkeyStr) - if err != nil { - log.Warnf("[BluezAgent] RequestConfirmation failed: %v", err) - return a.errorFrom(err) - } - - if secrets["decision"] != "yes" && secrets["decision"] != "accept" { - log.Debugf("[BluezAgent] RequestConfirmation rejected by user") - return dbus.NewError("org.bluez.Error.Rejected", nil) - } - - log.Infof("[BluezAgent] RequestConfirmation accepted") - return nil -} - -func (a *BluezAgent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error { - log.Infof("[BluezAgent] RequestAuthorization: device=%s", device) - - secrets, err := a.promptFor(device, "authorize", []string{"decision"}, nil) - if err != nil { - log.Warnf("[BluezAgent] RequestAuthorization failed: %v", err) - return a.errorFrom(err) - } - - if secrets["decision"] != "yes" && secrets["decision"] != "accept" { - log.Debugf("[BluezAgent] RequestAuthorization rejected by user") - return dbus.NewError("org.bluez.Error.Rejected", nil) - } - - log.Infof("[BluezAgent] RequestAuthorization accepted") - return nil -} - -func (a *BluezAgent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error { - log.Infof("[BluezAgent] AuthorizeService: device=%s, uuid=%s", device, uuid) - - secrets, err := a.promptFor(device, "authorize-service:"+uuid, []string{"decision"}, nil) - if err != nil { - log.Warnf("[BluezAgent] AuthorizeService failed: %v", err) - return a.errorFrom(err) - } - - if secrets["decision"] != "yes" && secrets["decision"] != "accept" { - log.Debugf("[BluezAgent] AuthorizeService rejected by user") - return dbus.NewError("org.bluez.Error.Rejected", nil) - } - - log.Infof("[BluezAgent] AuthorizeService accepted") - return nil -} - -func (a *BluezAgent) Cancel() *dbus.Error { - log.Infof("[BluezAgent] Cancel called") - return nil -} - -func (a *BluezAgent) Introspect() (string, *dbus.Error) { - return introspectXML, nil -} - -func (a *BluezAgent) promptFor(device dbus.ObjectPath, requestType string, fields []string, displayValue *string) (map[string]string, error) { - if a.broker == nil { - return nil, fmt.Errorf("broker not initialized") - } - - deviceName, deviceAddr := a.getDeviceInfo(device) - hints := []string{} - if displayValue != nil { - hints = append(hints, *displayValue) - } - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - var passkey *uint32 - if requestType == "confirm" || requestType == "display-passkey" { - if displayValue != nil { - if pk, err := strconv.ParseUint(*displayValue, 10, 32); err == nil { - pk32 := uint32(pk) - passkey = &pk32 - } - } - } - - token, err := a.broker.Ask(ctx, PromptRequest{ - DevicePath: string(device), - DeviceName: deviceName, - DeviceAddr: deviceAddr, - RequestType: requestType, - Fields: fields, - Hints: hints, - Passkey: passkey, - }) - if err != nil { - return nil, fmt.Errorf("prompt creation failed: %w", err) - } - - log.Infof("[BluezAgent] waiting for user response (token=%s)", token) - reply, err := a.broker.Wait(ctx, token) - if err != nil { - if errors.Is(err, errdefs.ErrSecretPromptTimeout) { - return nil, err - } - if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) { - return nil, errdefs.ErrSecretPromptCancelled - } - return nil, err - } - - if !reply.Accept && len(fields) > 0 { - return nil, errdefs.ErrSecretPromptCancelled - } - - return reply.Secrets, nil -} - -func (a *BluezAgent) getDeviceInfo(device dbus.ObjectPath) (string, string) { - obj := a.conn.Object(bluezService, device) - - var name, alias, addr string - - nameVar, err := obj.GetProperty(device1Iface + ".Name") - if err == nil { - if n, ok := nameVar.Value().(string); ok { - name = n - } - } - - aliasVar, err := obj.GetProperty(device1Iface + ".Alias") - if err == nil { - if a, ok := aliasVar.Value().(string); ok { - alias = a - } - } - - addrVar, err := obj.GetProperty(device1Iface + ".Address") - if err == nil { - if a, ok := addrVar.Value().(string); ok { - addr = a - } - } - - if alias != "" { - return alias, addr - } - if name != "" { - return name, addr - } - return addr, addr -} - -func (a *BluezAgent) errorFrom(err error) *dbus.Error { - if errors.Is(err, errdefs.ErrSecretPromptTimeout) { - return dbus.NewError("org.bluez.Error.Canceled", nil) - } - if errors.Is(err, errdefs.ErrSecretPromptCancelled) { - return dbus.NewError("org.bluez.Error.Canceled", nil) - } - return dbus.MakeFailedError(err) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker.go deleted file mode 100644 index f817707..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker.go +++ /dev/null @@ -1,21 +0,0 @@ -package bluez - -import ( - "context" - "crypto/rand" - "encoding/hex" -) - -type PromptBroker interface { - Ask(ctx context.Context, req PromptRequest) (token string, err error) - Wait(ctx context.Context, token string) (PromptReply, error) - Resolve(token string, reply PromptReply) error -} - -func generateToken() (string, error) { - bytes := make([]byte, 16) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - return hex.EncodeToString(bytes), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker_test.go deleted file mode 100644 index 9eebe61..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/broker_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package bluez - -import ( - "context" - "testing" - "time" -) - -func TestSubscriptionBrokerAskWait(t *testing.T) { - promptReceived := false - broker := NewSubscriptionBroker(func(p PairingPrompt) { - promptReceived = true - if p.Token == "" { - t.Error("expected token to be non-empty") - } - if p.DeviceName != "TestDevice" { - t.Errorf("expected DeviceName=TestDevice, got %s", p.DeviceName) - } - }) - - ctx := context.Background() - req := PromptRequest{ - DevicePath: "/org/bluez/test", - DeviceName: "TestDevice", - DeviceAddr: "AA:BB:CC:DD:EE:FF", - RequestType: "pin", - Fields: []string{"pin"}, - } - - token, err := broker.Ask(ctx, req) - if err != nil { - t.Fatalf("Ask failed: %v", err) - } - - if token == "" { - t.Fatal("expected non-empty token") - } - - if !promptReceived { - t.Fatal("expected prompt broadcast to be called") - } - - go func() { - time.Sleep(50 * time.Millisecond) - broker.Resolve(token, PromptReply{ - Secrets: map[string]string{"pin": "1234"}, - Accept: true, - }) - }() - - reply, err := broker.Wait(ctx, token) - if err != nil { - t.Fatalf("Wait failed: %v", err) - } - - if reply.Secrets["pin"] != "1234" { - t.Errorf("expected pin=1234, got %s", reply.Secrets["pin"]) - } - - if !reply.Accept { - t.Error("expected Accept=true") - } -} - -func TestSubscriptionBrokerTimeout(t *testing.T) { - broker := NewSubscriptionBroker(nil) - - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) - defer cancel() - - req := PromptRequest{ - DevicePath: "/org/bluez/test", - DeviceName: "TestDevice", - RequestType: "passkey", - Fields: []string{"passkey"}, - } - - token, err := broker.Ask(ctx, req) - if err != nil { - t.Fatalf("Ask failed: %v", err) - } - - _, err = broker.Wait(ctx, token) - if err == nil { - t.Fatal("expected timeout error") - } -} - -func TestSubscriptionBrokerCancel(t *testing.T) { - broker := NewSubscriptionBroker(nil) - - ctx := context.Background() - req := PromptRequest{ - DevicePath: "/org/bluez/test", - DeviceName: "TestDevice", - RequestType: "confirm", - Fields: []string{"decision"}, - } - - token, err := broker.Ask(ctx, req) - if err != nil { - t.Fatalf("Ask failed: %v", err) - } - - go func() { - time.Sleep(50 * time.Millisecond) - broker.Resolve(token, PromptReply{ - Cancel: true, - }) - }() - - _, err = broker.Wait(ctx, token) - if err == nil { - t.Fatal("expected cancelled error") - } -} - -func TestSubscriptionBrokerUnknownToken(t *testing.T) { - broker := NewSubscriptionBroker(nil) - - ctx := context.Background() - _, err := broker.Wait(ctx, "invalid-token") - if err == nil { - t.Fatal("expected error for unknown token") - } -} - -func TestGenerateToken(t *testing.T) { - token1, err := generateToken() - if err != nil { - t.Fatalf("generateToken failed: %v", err) - } - - token2, err := generateToken() - if err != nil { - t.Fatalf("generateToken failed: %v", err) - } - - if token1 == token2 { - t.Error("expected unique tokens") - } - - if len(token1) != 32 { - t.Errorf("expected token length 32, got %d", len(token1)) - } -} - -func TestSubscriptionBrokerResolveUnknownToken(t *testing.T) { - broker := NewSubscriptionBroker(nil) - - err := broker.Resolve("unknown-token", PromptReply{ - Secrets: map[string]string{"test": "value"}, - }) - if err == nil { - t.Fatal("expected error for unknown token") - } -} - -func TestSubscriptionBrokerMultipleRequests(t *testing.T) { - broker := NewSubscriptionBroker(nil) - ctx := context.Background() - - req1 := PromptRequest{ - DevicePath: "/org/bluez/test1", - DeviceName: "Device1", - RequestType: "pin", - Fields: []string{"pin"}, - } - - req2 := PromptRequest{ - DevicePath: "/org/bluez/test2", - DeviceName: "Device2", - RequestType: "passkey", - Fields: []string{"passkey"}, - } - - token1, err := broker.Ask(ctx, req1) - if err != nil { - t.Fatalf("Ask1 failed: %v", err) - } - - token2, err := broker.Ask(ctx, req2) - if err != nil { - t.Fatalf("Ask2 failed: %v", err) - } - - if token1 == token2 { - t.Error("expected different tokens") - } - - go func() { - time.Sleep(50 * time.Millisecond) - broker.Resolve(token1, PromptReply{ - Secrets: map[string]string{"pin": "1234"}, - Accept: true, - }) - broker.Resolve(token2, PromptReply{ - Secrets: map[string]string{"passkey": "567890"}, - Accept: true, - }) - }() - - reply1, err := broker.Wait(ctx, token1) - if err != nil { - t.Fatalf("Wait1 failed: %v", err) - } - - reply2, err := broker.Wait(ctx, token2) - if err != nil { - t.Fatalf("Wait2 failed: %v", err) - } - - if reply1.Secrets["pin"] != "1234" { - t.Errorf("expected pin=1234, got %s", reply1.Secrets["pin"]) - } - - if reply2.Secrets["passkey"] != "567890" { - t.Errorf("expected passkey=567890, got %s", reply2.Secrets["passkey"]) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers.go deleted file mode 100644 index be5a1c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers.go +++ /dev/null @@ -1,237 +0,0 @@ -package bluez - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -type BluetoothEvent struct { - Type string `json:"type"` - Data BluetoothState `json:"data"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "bluetooth.getState": - handleGetState(conn, req, manager) - case "bluetooth.startDiscovery": - handleStartDiscovery(conn, req, manager) - case "bluetooth.stopDiscovery": - handleStopDiscovery(conn, req, manager) - case "bluetooth.setPowered": - handleSetPowered(conn, req, manager) - case "bluetooth.pair": - handlePairDevice(conn, req, manager) - case "bluetooth.connect": - handleConnectDevice(conn, req, manager) - case "bluetooth.disconnect": - handleDisconnectDevice(conn, req, manager) - case "bluetooth.remove": - handleRemoveDevice(conn, req, manager) - case "bluetooth.trust": - handleTrustDevice(conn, req, manager) - case "bluetooth.untrust": - handleUntrustDevice(conn, req, manager) - case "bluetooth.subscribe": - handleSubscribe(conn, req, manager) - case "bluetooth.pairing.submit": - handlePairingSubmit(conn, req, manager) - case "bluetooth.pairing.cancel": - handlePairingCancel(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleStartDiscovery(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.StartDiscovery(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "discovery started"}) -} - -func handleStopDiscovery(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.StopDiscovery(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "discovery stopped"}) -} - -func handleSetPowered(conn net.Conn, req models.Request, manager *Manager) { - powered, err := params.Bool(req.Params, "powered") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetPowered(powered); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "powered state updated"}) -} - -func handlePairDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.PairDevice(devicePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "pairing initiated"}) -} - -func handleConnectDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.ConnectDevice(devicePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "connecting"}) -} - -func handleDisconnectDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.DisconnectDevice(devicePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "disconnected"}) -} - -func handleRemoveDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.RemoveDevice(devicePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "device removed"}) -} - -func handleTrustDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.TrustDevice(devicePath, true); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "device trusted"}) -} - -func handleUntrustDevice(conn net.Conn, req models.Request, manager *Manager) { - devicePath, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.TrustDevice(devicePath, false); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "device untrusted"}) -} - -func handlePairingSubmit(conn net.Conn, req models.Request, manager *Manager) { - token, err := params.String(req.Params, "token") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - secrets := params.StringMapOpt(req.Params, "secrets") - accept := params.BoolOpt(req.Params, "accept", false) - - if err := manager.SubmitPairing(token, secrets, accept); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "pairing response submitted"}) -} - -func handlePairingCancel(conn net.Conn, req models.Request, manager *Manager) { - token, err := params.String(req.Params, "token") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.CancelPairing(token); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "pairing cancelled"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - event := BluetoothEvent{ - Type: "state_changed", - Data: initialState, - } - - if err := json.NewEncoder(conn).Encode(models.Response[BluetoothEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - return - } - - for state := range stateChan { - event := BluetoothEvent{ - Type: "state_changed", - Data: state, - } - if err := json.NewEncoder(conn).Encode(models.Response[BluetoothEvent]{ - Result: &event, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers_test.go deleted file mode 100644 index 1846eb0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/handlers_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package bluez - -import ( - "context" - "testing" - "time" -) - -func TestBrokerIntegration(t *testing.T) { - broker := NewSubscriptionBroker(nil) - ctx := context.Background() - - req := PromptRequest{ - DevicePath: "/org/bluez/test", - DeviceName: "TestDevice", - RequestType: "pin", - Fields: []string{"pin"}, - } - - token, err := broker.Ask(ctx, req) - if err != nil { - t.Fatalf("Ask failed: %v", err) - } - - go func() { - time.Sleep(50 * time.Millisecond) - broker.Resolve(token, PromptReply{ - Secrets: map[string]string{"pin": "1234"}, - Accept: true, - }) - }() - - reply, err := broker.Wait(ctx, token) - if err != nil { - t.Fatalf("Wait failed: %v", err) - } - - if reply.Secrets["pin"] != "1234" { - t.Errorf("expected pin=1234, got %s", reply.Secrets["pin"]) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/manager.go deleted file mode 100644 index 4408d25..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/manager.go +++ /dev/null @@ -1,588 +0,0 @@ -package bluez - -import ( - "fmt" - "strings" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/godbus/dbus/v5" -) - -const ( - adapter1Iface = "org.bluez.Adapter1" - objectMgrIface = "org.freedesktop.DBus.ObjectManager" - propertiesIface = "org.freedesktop.DBus.Properties" -) - -func NewManager() (*Manager, error) { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("system bus connection failed: %w", err) - } - - m := &Manager{ - state: &BluetoothState{ - Powered: false, - Discovering: false, - Devices: []Device{}, - PairedDevices: []Device{}, - ConnectedDevices: []Device{}, - }, - stateMutex: sync.RWMutex{}, - - stopChan: make(chan struct{}), - dbusConn: conn, - signals: make(chan *dbus.Signal, 256), - dirty: make(chan struct{}, 1), - eventQueue: make(chan func(), 32), - } - - broker := NewSubscriptionBroker(m.broadcastPairingPrompt) - m.promptBroker = broker - - adapter, err := m.findAdapter() - if err != nil { - conn.Close() - return nil, fmt.Errorf("no bluetooth adapter found: %w", err) - } - m.adapterPath = adapter - - if err := m.initialize(); err != nil { - conn.Close() - return nil, err - } - - if err := m.startAgent(); err != nil { - conn.Close() - return nil, fmt.Errorf("agent start failed: %w", err) - } - - if err := m.startSignalPump(); err != nil { - m.Close() - return nil, err - } - - m.notifierWg.Add(1) - go m.notifier() - - m.eventWg.Add(1) - go m.eventWorker() - - return m, nil -} - -func (m *Manager) findAdapter() (dbus.ObjectPath, error) { - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath("/")) - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - - if err := obj.Call(objectMgrIface+".GetManagedObjects", 0).Store(&objects); err != nil { - return "", err - } - - for path, interfaces := range objects { - if _, ok := interfaces[adapter1Iface]; ok { - log.Infof("[BluezManager] found adapter: %s", path) - return path, nil - } - } - - return "", fmt.Errorf("no adapter found") -} - -func (m *Manager) initialize() error { - if err := m.updateAdapterState(); err != nil { - return err - } - - if err := m.updateDevices(); err != nil { - return err - } - - return nil -} - -func (m *Manager) updateAdapterState() error { - obj := m.dbusConn.Object(bluezService, m.adapterPath) - - poweredVar, err := obj.GetProperty(adapter1Iface + ".Powered") - if err != nil { - return err - } - - discoveringVar, err := obj.GetProperty(adapter1Iface + ".Discovering") - if err != nil { - return err - } - - m.stateMutex.Lock() - m.state.Powered = dbusutil.AsOr(poweredVar, false) - m.state.Discovering = dbusutil.AsOr(discoveringVar, false) - m.stateMutex.Unlock() - - return nil -} - -func (m *Manager) updateDevices() error { - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath("/")) - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - - if err := obj.Call(objectMgrIface+".GetManagedObjects", 0).Store(&objects); err != nil { - return err - } - - devices := []Device{} - paired := []Device{} - connected := []Device{} - - for path, interfaces := range objects { - devProps, ok := interfaces[device1Iface] - if !ok { - continue - } - - if !strings.HasPrefix(string(path), string(m.adapterPath)+"/") { - continue - } - - dev := m.deviceFromProps(string(path), devProps) - devices = append(devices, dev) - - if dev.Paired { - paired = append(paired, dev) - } - if dev.Connected { - connected = append(connected, dev) - } - } - - m.stateMutex.Lock() - m.state.Devices = devices - m.state.PairedDevices = paired - m.state.ConnectedDevices = connected - m.stateMutex.Unlock() - - return nil -} - -func (m *Manager) deviceFromProps(path string, props map[string]dbus.Variant) Device { - return Device{ - Path: path, - Address: dbusutil.GetOr(props, "Address", ""), - Name: dbusutil.GetOr(props, "Name", ""), - Alias: dbusutil.GetOr(props, "Alias", ""), - Paired: dbusutil.GetOr(props, "Paired", false), - Trusted: dbusutil.GetOr(props, "Trusted", false), - Blocked: dbusutil.GetOr(props, "Blocked", false), - Connected: dbusutil.GetOr(props, "Connected", false), - Class: dbusutil.GetOr(props, "Class", uint32(0)), - Icon: dbusutil.GetOr(props, "Icon", ""), - RSSI: dbusutil.GetOr(props, "RSSI", int16(0)), - LegacyPairing: dbusutil.GetOr(props, "LegacyPairing", false), - } -} - -func (m *Manager) startAgent() error { - if m.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - agent, err := NewBluezAgent(m.promptBroker) - if err != nil { - return err - } - - m.agent = agent - return nil -} - -func (m *Manager) startSignalPump() error { - m.dbusConn.Signal(m.signals) - - if err := m.dbusConn.AddMatchSignal( - dbus.WithMatchInterface(propertiesIface), - dbus.WithMatchMember("PropertiesChanged"), - ); err != nil { - return err - } - - if err := m.dbusConn.AddMatchSignal( - dbus.WithMatchInterface(objectMgrIface), - dbus.WithMatchMember("InterfacesAdded"), - ); err != nil { - return err - } - - if err := m.dbusConn.AddMatchSignal( - dbus.WithMatchInterface(objectMgrIface), - dbus.WithMatchMember("InterfacesRemoved"), - ); err != nil { - return err - } - - m.sigWG.Add(1) - go func() { - defer m.sigWG.Done() - for { - select { - case <-m.stopChan: - return - case sig, ok := <-m.signals: - if !ok { - return - } - if sig == nil { - continue - } - m.handleSignal(sig) - } - } - }() - - return nil -} - -func (m *Manager) handleSignal(sig *dbus.Signal) { - switch sig.Name { - case propertiesIface + ".PropertiesChanged": - if len(sig.Body) < 2 { - return - } - - iface, ok := sig.Body[0].(string) - if !ok { - return - } - - changed, ok := sig.Body[1].(map[string]dbus.Variant) - if !ok { - return - } - - switch iface { - case adapter1Iface: - if strings.HasPrefix(string(sig.Path), string(m.adapterPath)) { - m.handleAdapterPropertiesChanged(changed) - } - case device1Iface: - m.handleDevicePropertiesChanged(sig.Path, changed) - } - - case objectMgrIface + ".InterfacesAdded": - m.notifySubscribers() - - case objectMgrIface + ".InterfacesRemoved": - m.notifySubscribers() - } -} - -func (m *Manager) handleAdapterPropertiesChanged(changed map[string]dbus.Variant) { - m.stateMutex.Lock() - dirty := false - - if powered, ok := dbusutil.Get[bool](changed, "Powered"); ok { - m.state.Powered = powered - dirty = true - } - if discovering, ok := dbusutil.Get[bool](changed, "Discovering"); ok { - m.state.Discovering = discovering - dirty = true - } - - m.stateMutex.Unlock() - - if dirty { - m.notifySubscribers() - } -} - -func (m *Manager) handleDevicePropertiesChanged(path dbus.ObjectPath, changed map[string]dbus.Variant) { - paired, hasPaired := dbusutil.Get[bool](changed, "Paired") - _, hasConnected := changed["Connected"] - _, hasTrusted := changed["Trusted"] - - if hasPaired { - devicePath := string(path) - if paired { - _, wasPending := m.pendingPairings.LoadAndDelete(devicePath) - if wasPending { - select { - case m.eventQueue <- func() { - time.Sleep(300 * time.Millisecond) - log.Infof("[Bluetooth] Auto-trusting newly paired device: %s", devicePath) - if err := m.TrustDevice(devicePath, true); err != nil { - log.Warnf("[Bluetooth] Auto-trust failed: %v", err) - } - log.Infof("[Bluetooth] Auto-connecting newly paired device: %s", devicePath) - if err := m.ConnectDevice(devicePath); err != nil { - log.Warnf("[Bluetooth] Auto-connect failed: %v", err) - } - }: - default: - } - } - } else { - m.pendingPairings.Delete(devicePath) - } - } - - if hasPaired || hasConnected || hasTrusted { - select { - case m.eventQueue <- func() { - time.Sleep(100 * time.Millisecond) - m.updateDevices() - m.notifySubscribers() - }: - default: - } - } -} - -func (m *Manager) eventWorker() { - defer m.eventWg.Done() - for { - select { - case <-m.stopChan: - return - case event := <-m.eventQueue: - event() - } - } -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 200 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - m.updateDevices() - - currentState := m.snapshotState() - - if m.lastNotifiedState != nil && !stateChanged(m.lastNotifiedState, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan BluetoothState) bool { - select { - case ch <- currentState: - default: - } - return true - }) - - stateCopy := currentState - m.lastNotifiedState = &stateCopy - pending = false - } - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) GetState() BluetoothState { - return m.snapshotState() -} - -func (m *Manager) snapshotState() BluetoothState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - - s := *m.state - s.Devices = append([]Device(nil), m.state.Devices...) - s.PairedDevices = append([]Device(nil), m.state.PairedDevices...) - s.ConnectedDevices = append([]Device(nil), m.state.ConnectedDevices...) - return s -} - -func (m *Manager) Subscribe(id string) chan BluetoothState { - ch := make(chan BluetoothState, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if ch, ok := m.subscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (m *Manager) SubscribePairing(id string) chan PairingPrompt { - ch := make(chan PairingPrompt, 16) - m.pairingSubscribers.Store(id, ch) - return ch -} - -func (m *Manager) UnsubscribePairing(id string) { - if ch, ok := m.pairingSubscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (m *Manager) broadcastPairingPrompt(prompt PairingPrompt) { - m.pairingSubscribers.Range(func(key string, ch chan PairingPrompt) bool { - select { - case ch <- prompt: - default: - } - return true - }) -} - -func (m *Manager) SubmitPairing(token string, secrets map[string]string, accept bool) error { - if m.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return m.promptBroker.Resolve(token, PromptReply{ - Secrets: secrets, - Accept: accept, - Cancel: false, - }) -} - -func (m *Manager) CancelPairing(token string) error { - if m.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return m.promptBroker.Resolve(token, PromptReply{ - Cancel: true, - }) -} - -func (m *Manager) StartDiscovery() error { - obj := m.dbusConn.Object(bluezService, m.adapterPath) - return obj.Call(adapter1Iface+".StartDiscovery", 0).Err -} - -func (m *Manager) StopDiscovery() error { - obj := m.dbusConn.Object(bluezService, m.adapterPath) - return obj.Call(adapter1Iface+".StopDiscovery", 0).Err -} - -func (m *Manager) SetPowered(powered bool) error { - obj := m.dbusConn.Object(bluezService, m.adapterPath) - return obj.Call(propertiesIface+".Set", 0, adapter1Iface, "Powered", dbus.MakeVariant(powered)).Err -} - -func (m *Manager) PairDevice(devicePath string) error { - m.pendingPairings.Store(devicePath, true) - - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath)) - err := obj.Call(device1Iface+".Pair", 0).Err - - if err != nil { - m.pendingPairings.Delete(devicePath) - } - - return err -} - -func (m *Manager) ConnectDevice(devicePath string) error { - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath)) - return obj.Call(device1Iface+".Connect", 0).Err -} - -func (m *Manager) DisconnectDevice(devicePath string) error { - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath)) - return obj.Call(device1Iface+".Disconnect", 0).Err -} - -func (m *Manager) RemoveDevice(devicePath string) error { - obj := m.dbusConn.Object(bluezService, m.adapterPath) - return obj.Call(adapter1Iface+".RemoveDevice", 0, dbus.ObjectPath(devicePath)).Err -} - -func (m *Manager) TrustDevice(devicePath string, trusted bool) error { - obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath)) - return obj.Call(propertiesIface+".Set", 0, device1Iface, "Trusted", dbus.MakeVariant(trusted)).Err -} - -func (m *Manager) Close() { - close(m.stopChan) - m.notifierWg.Wait() - m.eventWg.Wait() - - m.sigWG.Wait() - - if m.signals != nil { - m.dbusConn.RemoveSignal(m.signals) - close(m.signals) - } - - if m.agent != nil { - m.agent.Close() - } - - m.subscribers.Range(func(key string, ch chan BluetoothState) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.pairingSubscribers.Range(func(key string, ch chan PairingPrompt) bool { - close(ch) - m.pairingSubscribers.Delete(key) - return true - }) - - if m.dbusConn != nil { - m.dbusConn.Close() - } -} - -func stateChanged(old, new *BluetoothState) bool { - if old.Powered != new.Powered { - return true - } - if old.Discovering != new.Discovering { - return true - } - if len(old.Devices) != len(new.Devices) { - return true - } - if len(old.PairedDevices) != len(new.PairedDevices) { - return true - } - if len(old.ConnectedDevices) != len(new.ConnectedDevices) { - return true - } - for i := range old.Devices { - if old.Devices[i].Path != new.Devices[i].Path { - return true - } - if old.Devices[i].Paired != new.Devices[i].Paired { - return true - } - if old.Devices[i].Connected != new.Devices[i].Connected { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/subscription_broker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/subscription_broker.go deleted file mode 100644 index ea04a19..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/subscription_broker.go +++ /dev/null @@ -1,86 +0,0 @@ -package bluez - -import ( - "context" - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type SubscriptionBroker struct { - pending syncmap.Map[string, chan PromptReply] - requests syncmap.Map[string, PromptRequest] - broadcastPrompt func(PairingPrompt) -} - -func NewSubscriptionBroker(broadcastPrompt func(PairingPrompt)) PromptBroker { - return &SubscriptionBroker{ - broadcastPrompt: broadcastPrompt, - } -} - -func (b *SubscriptionBroker) Ask(ctx context.Context, req PromptRequest) (string, error) { - token, err := generateToken() - if err != nil { - return "", err - } - - replyChan := make(chan PromptReply, 1) - b.pending.Store(token, replyChan) - b.requests.Store(token, req) - - if b.broadcastPrompt != nil { - prompt := PairingPrompt{ - Token: token, - DevicePath: req.DevicePath, - DeviceName: req.DeviceName, - DeviceAddr: req.DeviceAddr, - RequestType: req.RequestType, - Fields: req.Fields, - Hints: req.Hints, - Passkey: req.Passkey, - } - b.broadcastPrompt(prompt) - } - - return token, nil -} - -func (b *SubscriptionBroker) Wait(ctx context.Context, token string) (PromptReply, error) { - replyChan, exists := b.pending.Load(token) - if !exists { - return PromptReply{}, fmt.Errorf("unknown token: %s", token) - } - - select { - case <-ctx.Done(): - b.cleanup(token) - return PromptReply{}, errdefs.ErrSecretPromptTimeout - case reply := <-replyChan: - b.cleanup(token) - if reply.Cancel { - return reply, errdefs.ErrSecretPromptCancelled - } - return reply, nil - } -} - -func (b *SubscriptionBroker) Resolve(token string, reply PromptReply) error { - replyChan, exists := b.pending.Load(token) - if !exists { - return fmt.Errorf("unknown or expired token: %s", token) - } - - select { - case replyChan <- reply: - return nil - default: - return fmt.Errorf("failed to deliver reply for token: %s", token) - } -} - -func (b *SubscriptionBroker) cleanup(token string) { - b.pending.Delete(token) - b.requests.Delete(token) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types.go deleted file mode 100644 index 663acca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types.go +++ /dev/null @@ -1,78 +0,0 @@ -package bluez - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type BluetoothState struct { - Powered bool `json:"powered"` - Discovering bool `json:"discovering"` - Devices []Device `json:"devices"` - PairedDevices []Device `json:"pairedDevices"` - ConnectedDevices []Device `json:"connectedDevices"` -} - -type Device struct { - Path string `json:"path"` - Address string `json:"address"` - Name string `json:"name"` - Alias string `json:"alias"` - Paired bool `json:"paired"` - Trusted bool `json:"trusted"` - Blocked bool `json:"blocked"` - Connected bool `json:"connected"` - Class uint32 `json:"class"` - Icon string `json:"icon"` - RSSI int16 `json:"rssi"` - LegacyPairing bool `json:"legacyPairing"` -} - -type PromptRequest struct { - DevicePath string `json:"devicePath"` - DeviceName string `json:"deviceName"` - DeviceAddr string `json:"deviceAddr"` - RequestType string `json:"requestType"` - Fields []string `json:"fields"` - Hints []string `json:"hints"` - Passkey *uint32 `json:"passkey,omitempty"` -} - -type PromptReply struct { - Secrets map[string]string `json:"secrets"` - Accept bool `json:"accept"` - Cancel bool `json:"cancel"` -} - -type PairingPrompt struct { - Token string `json:"token"` - DevicePath string `json:"devicePath"` - DeviceName string `json:"deviceName"` - DeviceAddr string `json:"deviceAddr"` - RequestType string `json:"requestType"` - Fields []string `json:"fields"` - Hints []string `json:"hints"` - Passkey *uint32 `json:"passkey,omitempty"` -} - -type Manager struct { - state *BluetoothState - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan BluetoothState] - stopChan chan struct{} - dbusConn *dbus.Conn - signals chan *dbus.Signal - sigWG sync.WaitGroup - agent *BluezAgent - promptBroker PromptBroker - pairingSubscribers syncmap.Map[string, chan PairingPrompt] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotifiedState *BluetoothState - adapterPath dbus.ObjectPath - pendingPairings syncmap.Map[string, bool] - eventQueue chan func() - eventWg sync.WaitGroup -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types_test.go deleted file mode 100644 index ab5b857..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/bluez/types_test.go +++ /dev/null @@ -1,210 +0,0 @@ -package bluez - -import ( - "encoding/json" - "testing" -) - -func TestBluetoothStateJSON(t *testing.T) { - state := BluetoothState{ - Powered: true, - Discovering: false, - Devices: []Device{ - { - Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - Address: "AA:BB:CC:DD:EE:FF", - Name: "TestDevice", - Alias: "My Device", - Paired: true, - Trusted: false, - Connected: true, - Class: 0x240418, - Icon: "audio-headset", - RSSI: -50, - }, - }, - PairedDevices: []Device{ - { - Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - Address: "AA:BB:CC:DD:EE:FF", - Paired: true, - }, - }, - ConnectedDevices: []Device{ - { - Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - Address: "AA:BB:CC:DD:EE:FF", - Connected: true, - }, - }, - } - - data, err := json.Marshal(state) - if err != nil { - t.Fatalf("failed to marshal state: %v", err) - } - - var decoded BluetoothState - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("failed to unmarshal state: %v", err) - } - - if decoded.Powered != state.Powered { - t.Errorf("expected Powered=%v, got %v", state.Powered, decoded.Powered) - } - - if len(decoded.Devices) != 1 { - t.Fatalf("expected 1 device, got %d", len(decoded.Devices)) - } - - if decoded.Devices[0].Address != "AA:BB:CC:DD:EE:FF" { - t.Errorf("expected address AA:BB:CC:DD:EE:FF, got %s", decoded.Devices[0].Address) - } -} - -func TestDeviceJSON(t *testing.T) { - device := Device{ - Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - Address: "AA:BB:CC:DD:EE:FF", - Name: "TestDevice", - Alias: "My Device", - Paired: true, - Trusted: true, - Blocked: false, - Connected: true, - Class: 0x240418, - Icon: "audio-headset", - RSSI: -50, - LegacyPairing: false, - } - - data, err := json.Marshal(device) - if err != nil { - t.Fatalf("failed to marshal device: %v", err) - } - - var decoded Device - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("failed to unmarshal device: %v", err) - } - - if decoded.Address != device.Address { - t.Errorf("expected Address=%s, got %s", device.Address, decoded.Address) - } - - if decoded.Name != device.Name { - t.Errorf("expected Name=%s, got %s", device.Name, decoded.Name) - } - - if decoded.Paired != device.Paired { - t.Errorf("expected Paired=%v, got %v", device.Paired, decoded.Paired) - } - - if decoded.RSSI != device.RSSI { - t.Errorf("expected RSSI=%d, got %d", device.RSSI, decoded.RSSI) - } -} - -func TestPairingPromptJSON(t *testing.T) { - passkey := uint32(123456) - prompt := PairingPrompt{ - Token: "test-token", - DevicePath: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - DeviceName: "TestDevice", - DeviceAddr: "AA:BB:CC:DD:EE:FF", - RequestType: "confirm", - Fields: []string{"decision"}, - Hints: []string{}, - Passkey: &passkey, - } - - data, err := json.Marshal(prompt) - if err != nil { - t.Fatalf("failed to marshal prompt: %v", err) - } - - var decoded PairingPrompt - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("failed to unmarshal prompt: %v", err) - } - - if decoded.Token != prompt.Token { - t.Errorf("expected Token=%s, got %s", prompt.Token, decoded.Token) - } - - if decoded.DeviceName != prompt.DeviceName { - t.Errorf("expected DeviceName=%s, got %s", prompt.DeviceName, decoded.DeviceName) - } - - if decoded.Passkey == nil { - t.Fatal("expected non-nil Passkey") - } - - if *decoded.Passkey != *prompt.Passkey { - t.Errorf("expected Passkey=%d, got %d", *prompt.Passkey, *decoded.Passkey) - } -} - -func TestPromptReplyJSON(t *testing.T) { - reply := PromptReply{ - Secrets: map[string]string{ - "pin": "1234", - "passkey": "567890", - }, - Accept: true, - Cancel: false, - } - - data, err := json.Marshal(reply) - if err != nil { - t.Fatalf("failed to marshal reply: %v", err) - } - - var decoded PromptReply - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("failed to unmarshal reply: %v", err) - } - - if decoded.Secrets["pin"] != reply.Secrets["pin"] { - t.Errorf("expected pin=%s, got %s", reply.Secrets["pin"], decoded.Secrets["pin"]) - } - - if decoded.Accept != reply.Accept { - t.Errorf("expected Accept=%v, got %v", reply.Accept, decoded.Accept) - } -} - -func TestPromptRequestJSON(t *testing.T) { - passkey := uint32(123456) - req := PromptRequest{ - DevicePath: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF", - DeviceName: "TestDevice", - DeviceAddr: "AA:BB:CC:DD:EE:FF", - RequestType: "confirm", - Fields: []string{"decision"}, - Hints: []string{"hint1", "hint2"}, - Passkey: &passkey, - } - - data, err := json.Marshal(req) - if err != nil { - t.Fatalf("failed to marshal request: %v", err) - } - - var decoded PromptRequest - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("failed to unmarshal request: %v", err) - } - - if decoded.DevicePath != req.DevicePath { - t.Errorf("expected DevicePath=%s, got %s", req.DevicePath, decoded.DevicePath) - } - - if decoded.RequestType != req.RequestType { - t.Errorf("expected RequestType=%s, got %s", req.RequestType, decoded.RequestType) - } - - if len(decoded.Fields) != len(req.Fields) { - t.Errorf("expected %d fields, got %d", len(req.Fields), len(decoded.Fields)) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc.go deleted file mode 100644 index 00cf2d9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc.go +++ /dev/null @@ -1,510 +0,0 @@ -package brightness - -import ( - "encoding/binary" - "fmt" - "math" - "os" - "strings" - "syscall" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "golang.org/x/sys/unix" -) - -const ( - I2C_SLAVE = 0x0703 - DDCCI_ADDR = 0x37 - DDCCI_VCP_GET = 0x01 - DDCCI_VCP_SET = 0x03 - VCP_BRIGHTNESS = 0x10 - DDC_SOURCE_ADDR = 0x51 -) - -func NewDDCBackend() (*DDCBackend, error) { - b := &DDCBackend{ - scanInterval: 30 * time.Second, - debounceTimers: make(map[string]*time.Timer), - debouncePending: make(map[string]ddcPendingSet), - } - - if err := b.scanI2CDevices(); err != nil { - return nil, err - } - - return b, nil -} - -func (b *DDCBackend) scanI2CDevices() error { - return b.scanI2CDevicesInternal(false) -} - -func (b *DDCBackend) ForceRescan() error { - return b.scanI2CDevicesInternal(true) -} - -func (b *DDCBackend) scanI2CDevicesInternal(force bool) error { - b.scanMutex.Lock() - defer b.scanMutex.Unlock() - - if !force && time.Since(b.lastScan) < b.scanInterval { - return nil - } - - activeBuses := make(map[int]bool) - - for i := 0; i < 32; i++ { - busPath := fmt.Sprintf("/dev/i2c-%d", i) - if _, err := os.Stat(busPath); os.IsNotExist(err) { - continue - } - - if isIgnorableI2CBus(i) { - log.Debugf("Skipping ignorable i2c-%d", i) - continue - } - - activeBuses[i] = true - id := fmt.Sprintf("ddc:i2c-%d", i) - - dev, err := b.probeDDCDevice(i) - if err != nil || dev == nil { - continue - } - - dev.id = id - b.devices.Store(id, dev) - log.Debugf("found DDC device on i2c-%d", i) - } - - b.devices.Range(func(id string, dev *ddcDevice) bool { - if !activeBuses[dev.bus] { - b.devices.Delete(id) - log.Debugf("removed DDC device %s (bus no longer exists)", id) - } - return true - }) - - b.lastScan = time.Now() - - return nil -} - -func (b *DDCBackend) probeDDCDevice(bus int) (*ddcDevice, error) { - busPath := fmt.Sprintf("/dev/i2c-%d", bus) - - fd, err := syscall.Open(busPath, syscall.O_RDWR, 0) - if err != nil { - return nil, err - } - defer syscall.Close(fd) - - if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(DDCCI_ADDR)); errno != 0 { - return nil, errno - } - - dummy := make([]byte, 32) - syscall.Read(fd, dummy) //nolint:errcheck - - writebuf := []byte{0x00} - n, err := syscall.Write(fd, writebuf) - if err == nil && n == len(writebuf) { - name := b.getDDCName(bus) - dev := &ddcDevice{ - bus: bus, - addr: DDCCI_ADDR, - name: name, - } - b.readInitialBrightness(fd, dev) - return dev, nil - } - - readbuf := make([]byte, 4) - n, err = syscall.Read(fd, readbuf) - if err != nil || n == 0 { - return nil, fmt.Errorf("x37 unresponsive") - } - - name := b.getDDCName(bus) - - dev := &ddcDevice{ - bus: bus, - addr: DDCCI_ADDR, - name: name, - } - b.readInitialBrightness(fd, dev) - return dev, nil -} - -func (b *DDCBackend) getDDCName(bus int) string { - sysfsPath := fmt.Sprintf("/sys/class/i2c-adapter/i2c-%d/name", bus) - data, err := os.ReadFile(sysfsPath) - if err != nil { - return fmt.Sprintf("I2C-%d", bus) - } - - name := strings.TrimSpace(string(data)) - if name == "" { - name = fmt.Sprintf("I2C-%d", bus) - } - - return name -} - -func (b *DDCBackend) readInitialBrightness(fd int, dev *ddcDevice) { - cap, err := b.getVCPFeature(fd, VCP_BRIGHTNESS) - if err != nil { - log.Debugf("failed to read initial brightness for %s: %v", dev.name, err) - return - } - - dev.max = cap.max - dev.lastBrightness = cap.current - log.Debugf("initialized %s with brightness %d/%d", dev.name, cap.current, cap.max) -} - -func (b *DDCBackend) GetDevices() ([]Device, error) { - if err := b.scanI2CDevices(); err != nil { - log.Debugf("DDC scan error: %v", err) - } - - devices := make([]Device, 0) - - b.devices.Range(func(id string, dev *ddcDevice) bool { - devices = append(devices, Device{ - Class: ClassDDC, - ID: id, - Name: dev.name, - Current: dev.lastBrightness, - Max: dev.max, - CurrentPercent: dev.lastBrightness, - Backend: "ddc", - }) - return true - }) - - return devices, nil -} - -func (b *DDCBackend) SetBrightness(id string, value int, exponential bool, callback func()) error { - return b.SetBrightnessWithExponent(id, value, exponential, 1.2, callback) -} - -func (b *DDCBackend) SetBrightnessWithExponent(id string, value int, exponential bool, exponent float64, callback func()) error { - _, ok := b.devices.Load(id) - - if !ok { - if err := b.scanI2CDevicesInternal(true); err != nil { - log.Debugf("rescan failed for %s: %v", id, err) - } - _, ok = b.devices.Load(id) - } - - if !ok { - return fmt.Errorf("device not found: %s", id) - } - - if value < 0 { - return fmt.Errorf("value out of range: %d", value) - } - - b.debounceMutex.Lock() - b.debouncePending[id] = ddcPendingSet{ - percent: value, - callback: callback, - } - - if timer, exists := b.debounceTimers[id]; exists { - timer.Reset(200 * time.Millisecond) - } else { - b.debounceWg.Add(1) - b.debounceTimers[id] = time.AfterFunc(200*time.Millisecond, func() { - defer b.debounceWg.Done() - b.debounceMutex.Lock() - pending, exists := b.debouncePending[id] - if exists { - delete(b.debouncePending, id) - } - b.debounceMutex.Unlock() - - if !exists { - return - } - - err := b.setBrightnessImmediateWithExponent(id, pending.percent) - if err != nil { - log.Debugf("Failed to set brightness for %s: %v", id, err) - } - - if pending.callback != nil { - pending.callback() - } - }) - } - b.debounceMutex.Unlock() - - return nil -} - -func (b *DDCBackend) setBrightnessImmediateWithExponent(id string, value int) error { - dev, ok := b.devices.Load(id) - - if !ok { - if err := b.scanI2CDevicesInternal(true); err != nil { - log.Debugf("rescan failed for %s: %v", id, err) - } - dev, ok = b.devices.Load(id) - } - - if !ok { - return fmt.Errorf("device not found: %s", id) - } - - busPath := fmt.Sprintf("/dev/i2c-%d", dev.bus) - - if _, err := os.Stat(busPath); os.IsNotExist(err) { - b.devices.Delete(id) - log.Debugf("removed stale DDC device %s (bus no longer exists)", id) - return fmt.Errorf("device disconnected: %s", id) - } - - fd, err := syscall.Open(busPath, syscall.O_RDWR, 0) - if err != nil { - b.devices.Delete(id) - log.Debugf("removed DDC device %s (open failed: %v)", id, err) - return fmt.Errorf("open i2c device: %w", err) - } - defer syscall.Close(fd) - - if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(dev.addr)); errno != 0 { - return fmt.Errorf("set i2c slave addr: %w", errno) - } - - max := dev.max - if max == 0 { - cap, err := b.getVCPFeature(fd, VCP_BRIGHTNESS) - if err != nil { - return fmt.Errorf("get current capability: %w", err) - } - max = cap.max - dev.max = max - b.devices.Store(id, dev) - } - - if err := b.setVCPFeature(fd, VCP_BRIGHTNESS, value); err != nil { - return fmt.Errorf("set vcp feature: %w", err) - } - - log.Debugf("set %s to %d/%d", id, value, max) - - dev.max = max - dev.lastBrightness = value - b.devices.Store(id, dev) - - return nil -} - -func (b *DDCBackend) getVCPFeature(fd int, vcp byte) (*ddcCapability, error) { - for flushTry := 0; flushTry < 3; flushTry++ { - dummy := make([]byte, 32) - n, _ := syscall.Read(fd, dummy) - if n == 0 { - break - } - time.Sleep(20 * time.Millisecond) - } - - data := []byte{ - DDCCI_VCP_GET, - vcp, - } - - payload := []byte{ - DDC_SOURCE_ADDR, - byte(len(data)) | 0x80, - } - payload = append(payload, data...) - payload = append(payload, ddcciChecksum(payload)) - - n, err := syscall.Write(fd, payload) - if err != nil || n != len(payload) { - return nil, fmt.Errorf("write i2c: %w", err) - } - - time.Sleep(50 * time.Millisecond) - - pollFds := []unix.PollFd{ - { - Fd: int32(fd), - Events: unix.POLLIN, - }, - } - - pollTimeout := 200 - pollResult, err := unix.Poll(pollFds, pollTimeout) - if err != nil { - return nil, fmt.Errorf("poll i2c: %w", err) - } - if pollResult == 0 { - return nil, fmt.Errorf("poll timeout after %dms", pollTimeout) - } - if pollFds[0].Revents&unix.POLLIN == 0 { - return nil, fmt.Errorf("poll returned but POLLIN not set") - } - - response := make([]byte, 12) - n, err = syscall.Read(fd, response) - if err != nil || n < 8 { - return nil, fmt.Errorf("read i2c: %w", err) - } - - if response[0] != 0x6E || response[2] != 0x02 { - return nil, fmt.Errorf("invalid ddc response") - } - - resultCode := response[3] - if resultCode != 0x00 { - return nil, fmt.Errorf("vcp feature not supported") - } - - responseVCP := response[4] - if responseVCP != vcp { - return nil, fmt.Errorf("vcp mismatch: wanted 0x%02x, got 0x%02x", vcp, responseVCP) - } - - maxHigh := response[6] - maxLow := response[7] - currentHigh := response[8] - currentLow := response[9] - - max := int(binary.BigEndian.Uint16([]byte{maxHigh, maxLow})) - current := int(binary.BigEndian.Uint16([]byte{currentHigh, currentLow})) - - return &ddcCapability{ - vcp: vcp, - max: max, - current: current, - }, nil -} - -func ddcciChecksum(payload []byte) byte { - sum := byte(0x6E) - for _, b := range payload { - sum ^= b - } - return sum -} - -func (b *DDCBackend) setVCPFeature(fd int, vcp byte, value int) error { - data := []byte{ - DDCCI_VCP_SET, - vcp, - byte(value >> 8), - byte(value & 0xFF), - } - - payload := []byte{ - DDC_SOURCE_ADDR, - byte(len(data)) | 0x80, - } - payload = append(payload, data...) - payload = append(payload, ddcciChecksum(payload)) - - if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(DDCCI_ADDR)); errno != 0 { - return fmt.Errorf("set i2c slave for write: %w", errno) - } - - n, err := syscall.Write(fd, payload) - if err != nil || n != len(payload) { - return fmt.Errorf("write i2c: wrote %d/%d: %w", n, len(payload), err) - } - - time.Sleep(50 * time.Millisecond) - - return nil -} - -func (b *DDCBackend) percentToValue(percent int, max int, exponential bool) int { - const minValue = 1 - - if percent == 0 { - return minValue - } - - usableRange := max - minValue - var value int - - if exponential { - const exponent = 2.0 - normalizedPercent := float64(percent) / 100.0 - hardwarePercent := math.Pow(normalizedPercent, 1.0/exponent) - value = minValue + int(math.Round(hardwarePercent*float64(usableRange))) - } else { - value = minValue + ((percent - 1) * usableRange / 99) - } - - if value < minValue { - value = minValue - } - if value > max { - value = max - } - - return value -} - -func (b *DDCBackend) valueToPercent(value int, max int, exponential bool) int { - const minValue = 1 - - if max == 0 { - return 0 - } - - if value <= minValue { - return 1 - } - - usableRange := max - minValue - if usableRange == 0 { - return 100 - } - - var percent int - - if exponential { - const exponent = 2.0 - linearPercent := 1 + ((value - minValue) * 99 / usableRange) - normalizedLinear := float64(linearPercent) / 100.0 - expPercent := math.Pow(normalizedLinear, exponent) - percent = int(math.Round(expPercent * 100.0)) - } else { - percent = 1 + ((value - minValue) * 99 / usableRange) - } - - if percent > 100 { - percent = 100 - } - if percent < 1 { - percent = 1 - } - - return percent -} - -func (b *DDCBackend) WaitPending() { - done := make(chan struct{}) - go func() { - b.debounceWg.Wait() - close(done) - }() - - select { - case <-done: - case <-time.After(5 * time.Second): - log.Debug("WaitPending timed out waiting for DDC writes") - } -} - -func (b *DDCBackend) Close() { -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter.go deleted file mode 100644 index 12fc535..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter.go +++ /dev/null @@ -1,135 +0,0 @@ -package brightness - -import ( - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -// isIgnorableI2CBus checks if an I2C bus should be skipped during DDC probing. -// Based on ddcutil's sysfs_is_ignorable_i2c_device() (sysfs_base.c:1441) -func isIgnorableI2CBus(busno int) bool { - name := getI2CDeviceSysfsName(busno) - driver := getI2CSysfsDriver(busno) - - if name != "" && isIgnorableI2CDeviceName(name, driver) { - log.Debugf("i2c-%d: ignoring '%s' (driver: %s)", busno, name, driver) - return true - } - - // Only probe display adapters (0x03xxxx) and docking stations (0x0axxxx) - class := getI2CDeviceSysfsClass(busno) - if class != 0 { - classHigh := class & 0xFFFF0000 - ignorable := (classHigh != 0x030000 && classHigh != 0x0A0000) - if ignorable { - log.Debugf("i2c-%d: ignoring class 0x%08x", busno, class) - } - return ignorable - } - - return false -} - -// Based on ddcutil's ignorable_i2c_device_sysfs_name() (sysfs_base.c:1408) -func isIgnorableI2CDeviceName(name, driver string) bool { - ignorablePrefixes := []string{ - "SMBus", - "Synopsys DesignWare", - "soc:i2cdsi", - "smu", - "mac-io", - "u4", - "AMDGPU SMU", // AMD Navi2+ - probing hangs GPU - } - - for _, prefix := range ignorablePrefixes { - if strings.HasPrefix(name, prefix) { - return true - } - } - - // nouveau driver: only nvkm-* buses are valid - if driver == "nouveau" && !strings.HasPrefix(name, "nvkm-") { - return true - } - - return false -} - -// Based on ddcutil's get_i2c_device_sysfs_name() (sysfs_base.c:1175) -func getI2CDeviceSysfsName(busno int) string { - path := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/name", busno) - data, err := os.ReadFile(path) - if err != nil { - return "" - } - return strings.TrimSpace(string(data)) -} - -// Based on ddcutil's get_i2c_device_sysfs_class() (sysfs_base.c:1380) -func getI2CDeviceSysfsClass(busno int) uint32 { - classPath := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/device/class", busno) - data, err := os.ReadFile(classPath) - if err != nil { - classPath = fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/device/device/device/class", busno) - data, err = os.ReadFile(classPath) - if err != nil { - return 0 - } - } - - classStr := strings.TrimSpace(string(data)) - classStr = strings.TrimPrefix(classStr, "0x") - - class, err := strconv.ParseUint(classStr, 16, 32) - if err != nil { - return 0 - } - - return uint32(class) -} - -// Based on ddcutil's get_i2c_sysfs_driver_by_busno() (sysfs_base.c:1284) -func getI2CSysfsDriver(busno int) string { - devicePath := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d", busno) - adapterPath, err := findI2CAdapter(devicePath) - if err != nil { - return "" - } - - driverLink := filepath.Join(adapterPath, "driver") - target, err := os.Readlink(driverLink) - if err != nil { - return "" - } - - return filepath.Base(target) -} - -func findI2CAdapter(devicePath string) (string, error) { - currentPath := devicePath - - for depth := 0; depth < 10; depth++ { - if _, err := os.Stat(filepath.Join(currentPath, "name")); err == nil { - return currentPath, nil - } - - deviceLink := filepath.Join(currentPath, "device") - target, err := os.Readlink(deviceLink) - if err != nil { - break - } - - if !filepath.IsAbs(target) { - target = filepath.Join(filepath.Dir(currentPath), target) - } - currentPath = filepath.Clean(target) - } - - return "", fmt.Errorf("could not find adapter for %s", devicePath) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter_test.go deleted file mode 100644 index dc3751f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_filter_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package brightness - -import ( - "testing" -) - -func TestIsIgnorableI2CDeviceName(t *testing.T) { - tests := []struct { - name string - deviceName string - driver string - want bool - }{ - { - name: "AMDGPU SMU should be ignored", - deviceName: "AMDGPU SMU", - driver: "amdgpu", - want: true, - }, - { - name: "SMBus should be ignored", - deviceName: "SMBus I801 adapter", - driver: "", - want: true, - }, - { - name: "Synopsys DesignWare should be ignored", - deviceName: "Synopsys DesignWare I2C adapter", - driver: "", - want: true, - }, - { - name: "smu prefix should be ignored (Mac G5)", - deviceName: "smu-i2c-controller", - driver: "", - want: true, - }, - { - name: "Regular NVIDIA DDC should not be ignored", - deviceName: "NVIDIA i2c adapter 1", - driver: "nvidia", - want: false, - }, - { - name: "nouveau nvkm bus should not be ignored", - deviceName: "nvkm-0000:01:00.0-bus-0000", - driver: "nouveau", - want: false, - }, - { - name: "nouveau non-nvkm bus should be ignored", - deviceName: "nouveau-other-bus", - driver: "nouveau", - want: true, - }, - { - name: "Regular AMD display adapter should not be ignored", - deviceName: "AMDGPU DM i2c hw bus 0", - driver: "amdgpu", - want: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := isIgnorableI2CDeviceName(tt.deviceName, tt.driver) - if got != tt.want { - t.Errorf("isIgnorableI2CDeviceName(%q, %q) = %v, want %v", - tt.deviceName, tt.driver, got, tt.want) - } - }) - } -} - -func TestClassFiltering(t *testing.T) { - tests := []struct { - name string - class uint32 - want bool - }{ - { - name: "Display adapter class should not be ignored", - class: 0x030000, - want: false, - }, - { - name: "Docking station class should not be ignored", - class: 0x0a0000, - want: false, - }, - { - name: "Display adapter with subclass should not be ignored", - class: 0x030001, - want: false, - }, - { - name: "SMBus class should be ignored", - class: 0x0c0500, - want: true, - }, - { - name: "Bridge class should be ignored", - class: 0x060400, - want: true, - }, - { - name: "Generic system peripheral should be ignored", - class: 0x088000, - want: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - classHigh := tt.class & 0xFFFF0000 - ignorable := (classHigh != 0x030000 && classHigh != 0x0A0000) - if ignorable != tt.want { - t.Errorf("class 0x%08x: ignorable = %v, want %v", tt.class, ignorable, tt.want) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_test.go deleted file mode 100644 index 7f85510..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/ddc_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package brightness - -import ( - "testing" -) - -func TestDDCBackend_PercentConversions(t *testing.T) { - tests := []struct { - name string - max int - percent int - wantValue int - }{ - { - name: "0% should map to minValue=1", - max: 100, - percent: 0, - wantValue: 1, - }, - { - name: "1% should be 1", - max: 100, - percent: 1, - wantValue: 1, - }, - { - name: "50% should be ~50", - max: 100, - percent: 50, - wantValue: 50, - }, - { - name: "100% should be max", - max: 100, - percent: 100, - wantValue: 100, - }, - } - - b := &DDCBackend{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := b.percentToValue(tt.percent, tt.max, false) - diff := got - tt.wantValue - if diff < 0 { - diff = -diff - } - if diff > 1 { - t.Errorf("percentToValue() = %v, want %v (±1)", got, tt.wantValue) - } - }) - } -} - -func TestDDCBackend_ValueToPercent(t *testing.T) { - tests := []struct { - name string - max int - value int - wantPercent int - tolerance int - }{ - { - name: "zero value should be 1%", - max: 100, - value: 0, - wantPercent: 1, - tolerance: 0, - }, - { - name: "min value should be 1%", - max: 100, - value: 1, - wantPercent: 1, - tolerance: 0, - }, - { - name: "mid value should be ~50%", - max: 100, - value: 50, - wantPercent: 50, - tolerance: 2, - }, - { - name: "max value should be 100%", - max: 100, - value: 100, - wantPercent: 100, - tolerance: 0, - }, - } - - b := &DDCBackend{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := b.valueToPercent(tt.value, tt.max, false) - diff := got - tt.wantPercent - if diff < 0 { - diff = -diff - } - if diff > tt.tolerance { - t.Errorf("valueToPercent() = %v, want %v (±%d)", got, tt.wantPercent, tt.tolerance) - } - }) - } -} - -func TestDDCBackend_RoundTrip(t *testing.T) { - b := &DDCBackend{} - - tests := []struct { - name string - max int - percent int - }{ - {"1%", 100, 1}, - {"25%", 100, 25}, - {"50%", 100, 50}, - {"75%", 100, 75}, - {"100%", 100, 100}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - value := b.percentToValue(tt.percent, tt.max, false) - gotPercent := b.valueToPercent(value, tt.max, false) - - if diff := tt.percent - gotPercent; diff < -1 || diff > 1 { - t.Errorf("round trip failed: wanted %d%%, got %d%% (value=%d)", tt.percent, gotPercent, value) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/handlers.go deleted file mode 100644 index c71163e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/handlers.go +++ /dev/null @@ -1,124 +0,0 @@ -package brightness - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, m *Manager) { - switch req.Method { - case "brightness.getState": - handleGetState(conn, req, m) - case "brightness.setBrightness": - handleSetBrightness(conn, req, m) - case "brightness.increment": - handleIncrement(conn, req, m) - case "brightness.decrement": - handleDecrement(conn, req, m) - case "brightness.rescan": - handleRescan(conn, req, m) - case "brightness.subscribe": - handleSubscribe(conn, req, m) - default: - models.RespondError(conn, req.ID, "unknown method: "+req.Method) - } -} - -func handleGetState(conn net.Conn, req models.Request, m *Manager) { - models.Respond(conn, req.ID, m.GetState()) -} - -func handleSetBrightness(conn net.Conn, req models.Request, m *Manager) { - device, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - percent, err := params.Int(req.Params, "percent") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - exponential := params.BoolOpt(req.Params, "exponential", false) - exponent := params.FloatOpt(req.Params, "exponent", 1.2) - - if err := m.SetBrightnessWithExponent(device, percent, exponential, exponent); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, m.GetState()) -} - -func handleIncrement(conn net.Conn, req models.Request, m *Manager) { - device, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - step := params.IntOpt(req.Params, "step", 10) - exponential := params.BoolOpt(req.Params, "exponential", false) - exponent := params.FloatOpt(req.Params, "exponent", 1.2) - - if err := m.IncrementBrightnessWithExponent(device, step, exponential, exponent); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, m.GetState()) -} - -func handleDecrement(conn net.Conn, req models.Request, m *Manager) { - device, err := params.String(req.Params, "device") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - step := params.IntOpt(req.Params, "step", 10) - exponential := params.BoolOpt(req.Params, "exponential", false) - exponent := params.FloatOpt(req.Params, "exponent", 1.2) - - if err := m.IncrementBrightnessWithExponent(device, -step, exponential, exponent); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, m.GetState()) -} - -func handleRescan(conn net.Conn, req models.Request, m *Manager) { - m.Rescan() - models.Respond(conn, req.ID, m.GetState()) -} - -func handleSubscribe(conn net.Conn, req models.Request, m *Manager) { - clientID := fmt.Sprintf("brightness-%d", req.ID) - - ch := m.Subscribe(clientID) - defer m.Unsubscribe(clientID) - - initialState := m.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range ch { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &state, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind.go deleted file mode 100644 index 8449ab5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind.go +++ /dev/null @@ -1,66 +0,0 @@ -package brightness - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -type DBusConn interface { - Object(dest string, path dbus.ObjectPath) dbus.BusObject - Close() error -} - -type LogindBackend struct { - conn DBusConn -} - -func NewLogindBackend() (*LogindBackend, error) { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("connect to system bus: %w", err) - } - - obj := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1/session/auto") - call := obj.Call("org.freedesktop.DBus.Peer.Ping", 0) - if call.Err != nil { - conn.Close() - return nil, fmt.Errorf("logind not available: %w", call.Err) - } - - conn.Close() - - return &LogindBackend{}, nil -} - -func NewLogindBackendWithConn(conn DBusConn) *LogindBackend { - return &LogindBackend{ - conn: conn, - } -} - -func (b *LogindBackend) SetBrightness(subsystem, name string, brightness uint32) error { - if b.conn == nil { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return fmt.Errorf("connect to system bus: %w", err) - } - b.conn = conn - } - - obj := b.conn.Object("org.freedesktop.login1", "/org/freedesktop/login1/session/auto") - call := obj.Call("org.freedesktop.login1.Session.SetBrightness", 0, subsystem, name, brightness) - if call.Err != nil { - return fmt.Errorf("dbus call failed: %w", call.Err) - } - - log.Debugf("logind: set %s/%s to %d", subsystem, name, brightness) - return nil -} - -func (b *LogindBackend) Close() { - if b.conn != nil { - b.conn.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind_test.go deleted file mode 100644 index 3d4c2ee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/logind_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package brightness - -import ( - "errors" - "testing" - - mocks_brightness "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/brightness" - mock_dbus "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5" - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/mock" -) - -func TestLogindBackend_SetBrightness_Success(t *testing.T) { - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - backend := NewLogindBackendWithConn(mockConn) - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", dbus.Flags(0), "backlight", "nvidia_0", uint32(75)). - Return(&dbus.Call{Err: nil}). - Once() - - err := backend.SetBrightness("backlight", "nvidia_0", 75) - if err != nil { - t.Errorf("SetBrightness() error = %v, want nil", err) - } -} - -func TestLogindBackend_SetBrightness_DBusError(t *testing.T) { - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - backend := NewLogindBackendWithConn(mockConn) - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - dbusErr := errors.New("permission denied") - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(&dbus.Call{Err: dbusErr}). - Once() - - err := backend.SetBrightness("backlight", "test_device", 50) - if err == nil { - t.Error("SetBrightness() error = nil, want error") - } -} - -func TestLogindBackend_SetBrightness_LEDDevice(t *testing.T) { - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - backend := NewLogindBackendWithConn(mockConn) - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", dbus.Flags(0), "leds", "test_led", uint32(128)). - Return(&dbus.Call{Err: nil}). - Once() - - err := backend.SetBrightness("leds", "test_led", 128) - if err != nil { - t.Errorf("SetBrightness() error = %v, want nil", err) - } -} - -func TestLogindBackend_Close(t *testing.T) { - mockConn := mocks_brightness.NewMockDBusConn(t) - backend := NewLogindBackendWithConn(mockConn) - - mockConn.EXPECT(). - Close(). - Return(nil). - Once() - - backend.Close() -} - -func TestLogindBackend_Close_NilConn(t *testing.T) { - backend := &LogindBackend{conn: nil} - backend.Close() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager.go deleted file mode 100644 index 4cf7dd4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager.go +++ /dev/null @@ -1,389 +0,0 @@ -package brightness - -import ( - "fmt" - "sort" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -func NewManager() (*Manager, error) { - return NewManagerWithOptions(false) -} - -func NewManagerWithOptions(exponential bool) (*Manager, error) { - m := &Manager{ - stopChan: make(chan struct{}), - exponential: exponential, - } - - go m.initLogind() - go m.initSysfs() - go m.initDDC() - - return m, nil -} - -func (m *Manager) initLogind() { - log.Debug("Initializing logind backend...") - logind, err := NewLogindBackend() - if err != nil { - log.Infof("Logind backend not available: %v", err) - log.Info("Will use direct sysfs access for brightness control") - return - } - - m.logindBackend = logind - m.logindReady = true - log.Info("Logind backend initialized - will use for brightness control") -} - -func (m *Manager) initSysfs() { - log.Debug("Initializing sysfs backend...") - sysfs, err := NewSysfsBackend() - if err != nil { - log.Warnf("Failed to initialize sysfs backend: %v", err) - return - } - - devices, err := sysfs.GetDevices() - if err != nil { - log.Warnf("Failed to get initial sysfs devices: %v", err) - m.sysfsBackend = sysfs - m.sysfsReady = true - m.updateState() - m.initUdev() - return - } - - log.Infof("Sysfs backend initialized with %d devices", len(devices)) - for _, d := range devices { - log.Debugf(" - %s: %s (%d%%)", d.ID, d.Name, d.CurrentPercent) - } - - m.sysfsBackend = sysfs - m.sysfsReady = true - m.updateState() - m.initUdev() -} - -func (m *Manager) initUdev() { - m.udevMonitor = NewUdevMonitor(m) -} - -func (m *Manager) initDDC() { - ddc, err := NewDDCBackend() - if err != nil { - log.Debugf("Failed to initialize DDC backend: %v", err) - return - } - - m.ddcBackend = ddc - m.ddcReady = true - log.Info("DDC backend initialized") - - m.updateState() -} - -func (m *Manager) Rescan() { - log.Debug("Rescanning brightness devices...") - - if m.ddcReady && m.ddcBackend != nil { - if err := m.ddcBackend.ForceRescan(); err != nil { - log.Debugf("DDC force rescan failed: %v", err) - } - } - - if m.sysfsReady && m.sysfsBackend != nil { - if err := m.sysfsBackend.Rescan(); err != nil { - log.Debugf("Sysfs rescan failed: %v", err) - } - } - - m.updateState() -} - -func sortDevices(devices []Device) { - sort.Slice(devices, func(i, j int) bool { - classOrder := map[DeviceClass]int{ - ClassBacklight: 0, - ClassDDC: 1, - ClassLED: 2, - } - - orderI := classOrder[devices[i].Class] - orderJ := classOrder[devices[j].Class] - - if orderI != orderJ { - return orderI < orderJ - } - - return devices[i].Name < devices[j].Name - }) -} - -func stateChanged(old, new State) bool { - if len(old.Devices) != len(new.Devices) { - return true - } - - oldMap := make(map[string]Device) - for _, d := range old.Devices { - oldMap[d.ID] = d - } - - for _, newDev := range new.Devices { - oldDev, exists := oldMap[newDev.ID] - if !exists { - return true - } - if oldDev.Current != newDev.Current || oldDev.Max != newDev.Max { - return true - } - } - - return false -} - -func (m *Manager) updateState() { - allDevices := make([]Device, 0) - - if m.sysfsReady && m.sysfsBackend != nil { - devices, err := m.sysfsBackend.GetDevices() - if err != nil { - log.Debugf("Failed to get sysfs devices: %v", err) - } - if err == nil { - allDevices = append(allDevices, devices...) - } - } - - if m.ddcReady && m.ddcBackend != nil { - devices, err := m.ddcBackend.GetDevices() - if err != nil { - log.Debugf("Failed to get DDC devices: %v", err) - } - if err == nil { - allDevices = append(allDevices, devices...) - } - } - - sortDevices(allDevices) - - m.stateMutex.Lock() - oldState := m.state - newState := State{Devices: allDevices} - - if !stateChanged(oldState, newState) { - m.stateMutex.Unlock() - return - } - - m.state = newState - m.stateMutex.Unlock() - log.Debugf("State changed, notifying subscribers") - m.NotifySubscribers() -} - -func (m *Manager) SetBrightness(deviceID string, percent int) error { - return m.SetBrightnessWithMode(deviceID, percent, m.exponential) -} - -func (m *Manager) SetBrightnessWithMode(deviceID string, percent int, exponential bool) error { - return m.SetBrightnessWithExponent(deviceID, percent, exponential, 1.2) -} - -func (m *Manager) SetBrightnessWithExponent(deviceID string, percent int, exponential bool, exponent float64) error { - if percent < 0 { - return fmt.Errorf("percent out of range: %d", percent) - } - - log.Debugf("SetBrightness: %s to %d%%", deviceID, percent) - - m.stateMutex.Lock() - currentState := m.state - var found bool - var deviceClass DeviceClass - var deviceIndex int - - log.Debugf("Current state has %d devices", len(currentState.Devices)) - - for i, dev := range currentState.Devices { - if dev.ID == deviceID { - found = true - deviceClass = dev.Class - deviceIndex = i - break - } - } - - if !found { - m.stateMutex.Unlock() - log.Debugf("Device not found in state: %s", deviceID) - return fmt.Errorf("device not found: %s", deviceID) - } - - newDevices := make([]Device, len(currentState.Devices)) - copy(newDevices, currentState.Devices) - newDevices[deviceIndex].CurrentPercent = percent - m.state = State{Devices: newDevices} - m.stateMutex.Unlock() - - var err error - if deviceClass == ClassDDC { - log.Debugf("Calling DDC backend for %s", deviceID) - err = m.ddcBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, func() { - m.updateState() - m.debouncedBroadcast(deviceID) - }) - } else if m.logindReady && m.logindBackend != nil { - log.Debugf("Calling logind backend for %s", deviceID) - err = m.setViaSysfsWithLogindWithExponent(deviceID, percent, exponential, exponent) - } else { - log.Debugf("Calling sysfs backend for %s", deviceID) - err = m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent) - } - - if err != nil { - m.updateState() - return fmt.Errorf("failed to set brightness: %w", err) - } - - if deviceClass != ClassDDC { - log.Debugf("Queueing broadcast for %s", deviceID) - m.debouncedBroadcast(deviceID) - } - return nil -} - -func (m *Manager) IncrementBrightness(deviceID string, step int) error { - return m.IncrementBrightnessWithMode(deviceID, step, m.exponential) -} - -func (m *Manager) IncrementBrightnessWithMode(deviceID string, step int, exponential bool) error { - return m.IncrementBrightnessWithExponent(deviceID, step, exponential, 1.2) -} - -func (m *Manager) IncrementBrightnessWithExponent(deviceID string, step int, exponential bool, exponent float64) error { - m.stateMutex.RLock() - currentState := m.state - m.stateMutex.RUnlock() - - var currentPercent int - var found bool - - for _, dev := range currentState.Devices { - if dev.ID == deviceID { - currentPercent = dev.CurrentPercent - found = true - break - } - } - - if !found { - return fmt.Errorf("device not found: %s", deviceID) - } - - newPercent := currentPercent + step - if newPercent > 100 { - newPercent = 100 - } - if newPercent < 0 { - newPercent = 0 - } - - return m.SetBrightnessWithExponent(deviceID, newPercent, exponential, exponent) -} - -func (m *Manager) DecrementBrightness(deviceID string, step int) error { - return m.IncrementBrightness(deviceID, -step) -} - -func (m *Manager) setViaSysfsWithLogindWithExponent(deviceID string, percent int, exponential bool, exponent float64) error { - parts := strings.SplitN(deviceID, ":", 2) - if len(parts) != 2 { - return fmt.Errorf("invalid device id: %s", deviceID) - } - - subsystem := parts[0] - name := parts[1] - - dev, err := m.sysfsBackend.GetDevice(deviceID) - if err != nil { - return err - } - - value := m.sysfsBackend.PercentToValueWithExponent(percent, dev, exponential, exponent) - - if m.logindBackend == nil { - return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent) - } - - err = m.logindBackend.SetBrightness(subsystem, name, uint32(value)) - if err != nil { - log.Debugf("logind SetBrightness failed, falling back to direct sysfs: %v", err) - return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent) - } - - log.Debugf("set %s to %d%% (%d/%d) via logind", deviceID, percent, value, dev.maxBrightness) - return nil -} - -func (m *Manager) debouncedBroadcast(deviceID string) { - m.broadcastMutex.Lock() - defer m.broadcastMutex.Unlock() - - m.broadcastPending = true - m.pendingDeviceID = deviceID - - if m.broadcastTimer == nil { - m.broadcastTimer = time.AfterFunc(150*time.Millisecond, func() { - m.broadcastMutex.Lock() - pending := m.broadcastPending - deviceID := m.pendingDeviceID - m.broadcastPending = false - m.pendingDeviceID = "" - m.broadcastMutex.Unlock() - - if !pending || deviceID == "" { - return - } - - m.broadcastDeviceUpdate(deviceID) - }) - } else { - m.broadcastTimer.Reset(150 * time.Millisecond) - } -} - -func (m *Manager) broadcastDeviceUpdate(deviceID string) { - m.stateMutex.RLock() - var targetDevice *Device - for _, dev := range m.state.Devices { - if dev.ID == deviceID { - devCopy := dev - targetDevice = &devCopy - break - } - } - m.stateMutex.RUnlock() - - if targetDevice == nil { - log.Debugf("Device not found for broadcast: %s", deviceID) - return - } - - update := DeviceUpdate{Device: *targetDevice} - - log.Debugf("Broadcasting device update: %s at %d%%", deviceID, targetDevice.CurrentPercent) - - m.updateSubscribers.Range(func(key string, ch chan DeviceUpdate) bool { - select { - case ch <- update: - default: - } - return true - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager_test.go deleted file mode 100644 index a8ae0f8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/manager_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package brightness - -import ( - "testing" -) - -// Manager tests can be added here as needed -func TestManager_Placeholder(t *testing.T) { - // Placeholder test to keep the test file valid - t.Skip("No tests implemented yet") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs.go deleted file mode 100644 index 1ff38f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs.go +++ /dev/null @@ -1,267 +0,0 @@ -package brightness - -import ( - "fmt" - "math" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -func NewSysfsBackend() (*SysfsBackend, error) { - b := &SysfsBackend{ - basePath: "/sys/class", - classes: []string{"backlight", "leds"}, - } - - if err := b.scanDevices(); err != nil { - return nil, err - } - - return b, nil -} - -func (b *SysfsBackend) scanDevices() error { - for _, class := range b.classes { - classPath := filepath.Join(b.basePath, class) - entries, err := os.ReadDir(classPath) - if err != nil { - if os.IsNotExist(err) { - continue - } - return fmt.Errorf("read %s: %w", classPath, err) - } - - for _, entry := range entries { - devicePath := filepath.Join(classPath, entry.Name()) - - stat, err := os.Stat(devicePath) - if err != nil || !stat.IsDir() { - continue - } - maxPath := filepath.Join(devicePath, "max_brightness") - - maxData, err := os.ReadFile(maxPath) - if err != nil { - log.Debugf("skip %s/%s: no max_brightness", class, entry.Name()) - continue - } - - maxBrightness, err := strconv.Atoi(strings.TrimSpace(string(maxData))) - if err != nil || maxBrightness <= 0 { - log.Debugf("skip %s/%s: invalid max_brightness", class, entry.Name()) - continue - } - - deviceClass := ClassBacklight - minValue := 1 - if class == "leds" { - deviceClass = ClassLED - minValue = 0 - } - - deviceID := fmt.Sprintf("%s:%s", class, entry.Name()) - b.deviceCache.Store(deviceID, &sysfsDevice{ - class: deviceClass, - id: deviceID, - name: entry.Name(), - maxBrightness: maxBrightness, - minValue: minValue, - }) - - log.Debugf("found %s device: %s (max=%d)", class, entry.Name(), maxBrightness) - } - } - - return nil -} - -func shouldSuppressDevice(name string) bool { - if strings.HasSuffix(name, "::lan") { - return true - } - - keyboardLEDs := []string{ - "::scrolllock", - "::capslock", - "::numlock", - "::kana", - "::compose", - } - - for _, suffix := range keyboardLEDs { - if strings.HasSuffix(name, suffix) { - return true - } - } - - return false -} - -func (b *SysfsBackend) Rescan() error { - return b.scanDevices() -} - -func (b *SysfsBackend) GetDevices() ([]Device, error) { - devices := make([]Device, 0) - - b.deviceCache.Range(func(key string, dev *sysfsDevice) bool { - if shouldSuppressDevice(dev.name) { - return true - } - - parts := strings.SplitN(dev.id, ":", 2) - if len(parts) != 2 { - return true - } - - class := parts[0] - name := parts[1] - - devicePath := filepath.Join(b.basePath, class, name) - brightnessPath := filepath.Join(devicePath, "brightness") - - brightnessData, err := os.ReadFile(brightnessPath) - if err != nil { - log.Debugf("failed to read brightness for %s: %v", dev.id, err) - return true - } - - current, err := strconv.Atoi(strings.TrimSpace(string(brightnessData))) - if err != nil { - log.Debugf("failed to parse brightness for %s: %v", dev.id, err) - return true - } - - percent := b.ValueToPercent(current, dev, false) - - devices = append(devices, Device{ - Class: dev.class, - ID: dev.id, - Name: dev.name, - Current: current, - Max: dev.maxBrightness, - CurrentPercent: percent, - Backend: "sysfs", - }) - return true - }) - - return devices, nil -} - -func (b *SysfsBackend) GetDevice(id string) (*sysfsDevice, error) { - dev, ok := b.deviceCache.Load(id) - if !ok { - return nil, fmt.Errorf("device not found: %s", id) - } - - return dev, nil -} - -func (b *SysfsBackend) SetBrightness(id string, percent int, exponential bool) error { - return b.SetBrightnessWithExponent(id, percent, exponential, 1.2) -} - -func (b *SysfsBackend) SetBrightnessWithExponent(id string, percent int, exponential bool, exponent float64) error { - dev, err := b.GetDevice(id) - if err != nil { - return err - } - - if percent < 0 { - return fmt.Errorf("percent out of range: %d", percent) - } - - value := b.PercentToValueWithExponent(percent, dev, exponential, exponent) - - parts := strings.SplitN(id, ":", 2) - if len(parts) != 2 { - return fmt.Errorf("invalid device id: %s", id) - } - - class := parts[0] - name := parts[1] - - devicePath := filepath.Join(b.basePath, class, name) - brightnessPath := filepath.Join(devicePath, "brightness") - - data := []byte(fmt.Sprintf("%d", value)) - if err := os.WriteFile(brightnessPath, data, 0o644); err != nil { - return fmt.Errorf("write brightness: %w", err) - } - - log.Debugf("set %s to %d%% (%d/%d) via direct sysfs", id, percent, value, dev.maxBrightness) - - return nil -} - -func (b *SysfsBackend) PercentToValue(percent int, dev *sysfsDevice, exponential bool) int { - return b.PercentToValueWithExponent(percent, dev, exponential, 1.2) -} - -func (b *SysfsBackend) PercentToValueWithExponent(percent int, dev *sysfsDevice, exponential bool, exponent float64) int { - if percent == 0 { - return dev.minValue - } - - usableRange := dev.maxBrightness - dev.minValue - var value int - - if exponential { - normalizedPercent := float64(percent-1) / 99.0 - hardwarePercent := math.Pow(normalizedPercent, exponent) - value = dev.minValue + int(math.Round(hardwarePercent*float64(usableRange))) - } else { - value = dev.minValue + ((percent - 1) * usableRange / 99) - } - - if value < dev.minValue { - value = dev.minValue - } - if value > dev.maxBrightness { - value = dev.maxBrightness - } - - return value -} - -func (b *SysfsBackend) ValueToPercent(value int, dev *sysfsDevice, exponential bool) int { - return b.ValueToPercentWithExponent(value, dev, exponential, 1.2) -} - -func (b *SysfsBackend) ValueToPercentWithExponent(value int, dev *sysfsDevice, exponential bool, exponent float64) int { - if value <= dev.minValue { - if dev.minValue == 0 && value == 0 { - return 0 - } - return 1 - } - - usableRange := dev.maxBrightness - dev.minValue - if usableRange == 0 { - return 100 - } - - var percent int - - if exponential { - hardwarePercent := float64(value-dev.minValue) / float64(usableRange) - normalizedPercent := math.Pow(hardwarePercent, 1.0/exponent) - percent = 1 + int(math.Round(normalizedPercent*99.0)) - } else { - percent = 1 + int(math.Round(float64(value-dev.minValue)*99.0/float64(usableRange))) - } - - if percent > 100 { - percent = 100 - } - if percent < 1 { - percent = 1 - } - - return percent -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_logind_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_logind_test.go deleted file mode 100644 index 6ba84b8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_logind_test.go +++ /dev/null @@ -1,278 +0,0 @@ -package brightness - -import ( - "os" - "path/filepath" - "testing" - - mocks_brightness "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/brightness" - mock_dbus "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5" - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/mock" -) - -func TestManager_SetBrightness_LogindSuccess(t *testing.T) { - tmpDir := t.TempDir() - - backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight") - if err := os.MkdirAll(backlightDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0o644); err != nil { - t.Fatal(err) - } - - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - mockLogind := NewLogindBackendWithConn(mockConn) - - sysfs := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"backlight"}, - } - - if err := sysfs.scanDevices(); err != nil { - t.Fatal(err) - } - - m := &Manager{ - logindBackend: mockLogind, - sysfsBackend: sysfs, - logindReady: true, - sysfsReady: true, - stopChan: make(chan struct{}), - } - - m.state = State{ - Devices: []Device{ - { - Class: ClassBacklight, - ID: "backlight:test_backlight", - Name: "test_backlight", - Current: 50, - Max: 100, - CurrentPercent: 50, - Backend: "sysfs", - }, - }, - } - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "backlight", "test_backlight", uint32(75)). - Return(&dbus.Call{Err: nil}). - Once() - - err := m.SetBrightness("backlight:test_backlight", 75) - if err != nil { - t.Errorf("SetBrightness() with logind error = %v, want nil", err) - } - - data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness")) - if string(data) == "75\n" { - t.Error("Direct sysfs write occurred when logind should have been used") - } -} - -func TestManager_SetBrightness_LogindFailsFallbackToSysfs(t *testing.T) { - tmpDir := t.TempDir() - - backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight") - if err := os.MkdirAll(backlightDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0o644); err != nil { - t.Fatal(err) - } - - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - mockLogind := NewLogindBackendWithConn(mockConn) - - sysfs := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"backlight"}, - } - - if err := sysfs.scanDevices(); err != nil { - t.Fatal(err) - } - - m := &Manager{ - logindBackend: mockLogind, - sysfsBackend: sysfs, - logindReady: true, - sysfsReady: true, - stopChan: make(chan struct{}), - } - - m.state = State{ - Devices: []Device{ - { - Class: ClassBacklight, - ID: "backlight:test_backlight", - Name: "test_backlight", - Current: 50, - Max: 100, - CurrentPercent: 50, - Backend: "sysfs", - }, - }, - } - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "backlight", "test_backlight", mock.Anything). - Return(&dbus.Call{Err: dbus.ErrMsgNoObject}). - Once() - - err := m.SetBrightness("backlight:test_backlight", 75) - if err != nil { - t.Errorf("SetBrightness() with fallback error = %v, want nil", err) - } - - data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness")) - brightness := string(data) - if brightness != "75" { - t.Errorf("Fallback sysfs write did not occur, got brightness = %q, want %q", brightness, "75") - } -} - -func TestManager_SetBrightness_NoLogind(t *testing.T) { - tmpDir := t.TempDir() - - backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight") - if err := os.MkdirAll(backlightDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0o644); err != nil { - t.Fatal(err) - } - - sysfs := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"backlight"}, - } - - if err := sysfs.scanDevices(); err != nil { - t.Fatal(err) - } - - m := &Manager{ - logindBackend: nil, - sysfsBackend: sysfs, - logindReady: false, - sysfsReady: true, - stopChan: make(chan struct{}), - } - - m.state = State{ - Devices: []Device{ - { - Class: ClassBacklight, - ID: "backlight:test_backlight", - Name: "test_backlight", - Current: 50, - Max: 100, - CurrentPercent: 50, - Backend: "sysfs", - }, - }, - } - - err := m.SetBrightness("backlight:test_backlight", 75) - if err != nil { - t.Errorf("SetBrightness() without logind error = %v, want nil", err) - } - - data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness")) - brightness := string(data) - if brightness != "75" { - t.Errorf("Direct sysfs write = %q, want %q", brightness, "75") - } -} - -func TestManager_SetBrightness_LEDWithLogind(t *testing.T) { - tmpDir := t.TempDir() - - ledsDir := filepath.Join(tmpDir, "leds", "test_led") - if err := os.MkdirAll(ledsDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(ledsDir, "max_brightness"), []byte("255\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(ledsDir, "brightness"), []byte("128\n"), 0o644); err != nil { - t.Fatal(err) - } - - mockConn := mocks_brightness.NewMockDBusConn(t) - mockObj := mock_dbus.NewMockBusObject(t) - - mockLogind := NewLogindBackendWithConn(mockConn) - - sysfs := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"leds"}, - } - - if err := sysfs.scanDevices(); err != nil { - t.Fatal(err) - } - - m := &Manager{ - logindBackend: mockLogind, - sysfsBackend: sysfs, - logindReady: true, - sysfsReady: true, - stopChan: make(chan struct{}), - } - - m.state = State{ - Devices: []Device{ - { - Class: ClassLED, - ID: "leds:test_led", - Name: "test_led", - Current: 128, - Max: 255, - CurrentPercent: 50, - Backend: "sysfs", - }, - }, - } - - mockConn.EXPECT(). - Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")). - Return(mockObj). - Once() - - mockObj.EXPECT(). - Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "leds", "test_led", uint32(0)). - Return(&dbus.Call{Err: nil}). - Once() - - err := m.SetBrightness("leds:test_led", 0) - if err != nil { - t.Errorf("SetBrightness() LED with logind error = %v, want nil", err) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_test.go deleted file mode 100644 index 8061513..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/sysfs_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package brightness - -import ( - "os" - "path/filepath" - "testing" -) - -func TestSysfsBackend_PercentConversions(t *testing.T) { - tests := []struct { - name string - device *sysfsDevice - percent int - wantValue int - tolerance int - }{ - { - name: "backlight 0% should be minValue=1", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - percent: 0, - wantValue: 1, - tolerance: 0, - }, - { - name: "backlight 1% should be minValue=1", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - percent: 1, - wantValue: 1, - tolerance: 0, - }, - { - name: "backlight 50% should be ~50", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - percent: 50, - wantValue: 50, - tolerance: 1, - }, - { - name: "backlight 100% should be max", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - percent: 100, - wantValue: 100, - tolerance: 0, - }, - { - name: "led 0% should be 0", - device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED}, - percent: 0, - wantValue: 0, - tolerance: 0, - }, - { - name: "led 1% should be ~2-3", - device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED}, - percent: 1, - wantValue: 2, - tolerance: 3, - }, - { - name: "led 50% should be ~127", - device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED}, - percent: 50, - wantValue: 127, - tolerance: 2, - }, - { - name: "led 100% should be max", - device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED}, - percent: 100, - wantValue: 255, - tolerance: 0, - }, - } - - b := &SysfsBackend{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := b.PercentToValue(tt.percent, tt.device, false) - diff := got - tt.wantValue - if diff < 0 { - diff = -diff - } - if diff > tt.tolerance { - t.Errorf("percentToValue() = %v, want %v (±%d)", got, tt.wantValue, tt.tolerance) - } - - gotPercent := b.ValueToPercent(got, tt.device, false) - if tt.percent > 1 && gotPercent == 0 { - t.Errorf("valueToPercent() returned 0 for non-zero input (percent=%d, got value=%d)", tt.percent, got) - } - }) - } -} - -func TestSysfsBackend_ValueToPercent(t *testing.T) { - tests := []struct { - name string - device *sysfsDevice - value int - wantPercent int - }{ - { - name: "backlight min value", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - value: 1, - wantPercent: 1, - }, - { - name: "backlight max value", - device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight}, - value: 100, - wantPercent: 100, - }, - { - name: "led zero", - device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED}, - value: 0, - wantPercent: 0, - }, - } - - b := &SysfsBackend{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := b.ValueToPercent(tt.value, tt.device, false) - if got != tt.wantPercent { - t.Errorf("valueToPercent() = %v, want %v", got, tt.wantPercent) - } - }) - } -} - -func TestSysfsBackend_ScanDevices(t *testing.T) { - tmpDir := t.TempDir() - - backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight") - if err := os.MkdirAll(backlightDir, 0o755); err != nil { - t.Fatal(err) - } - - if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0o644); err != nil { - t.Fatal(err) - } - - ledsDir := filepath.Join(tmpDir, "leds", "test_led") - if err := os.MkdirAll(ledsDir, 0o755); err != nil { - t.Fatal(err) - } - - if err := os.WriteFile(filepath.Join(ledsDir, "max_brightness"), []byte("255\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(ledsDir, "brightness"), []byte("128\n"), 0o644); err != nil { - t.Fatal(err) - } - - b := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"backlight", "leds"}, - } - - if err := b.scanDevices(); err != nil { - t.Fatalf("scanDevices() error = %v", err) - } - - backlightID := "backlight:test_backlight" - if _, ok := b.deviceCache.Load(backlightID); !ok { - t.Errorf("backlight device not found") - } - - ledID := "leds:test_led" - if _, ok := b.deviceCache.Load(ledID); !ok { - t.Errorf("LED device not found") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/types.go deleted file mode 100644 index 81e00cf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/types.go +++ /dev/null @@ -1,184 +0,0 @@ -package brightness - -import ( - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type DeviceClass string - -const ( - ClassBacklight DeviceClass = "backlight" - ClassLED DeviceClass = "leds" - ClassDDC DeviceClass = "ddc" -) - -type Device struct { - Class DeviceClass `json:"class"` - ID string `json:"id"` - Name string `json:"name"` - Current int `json:"current"` - Max int `json:"max"` - CurrentPercent int `json:"currentPercent"` - Backend string `json:"backend"` -} - -type State struct { - Devices []Device `json:"devices"` -} - -type DeviceUpdate struct { - Device Device `json:"device"` -} - -type Manager struct { - logindBackend *LogindBackend - sysfsBackend *SysfsBackend - ddcBackend *DDCBackend - udevMonitor *UdevMonitor - - logindReady bool - sysfsReady bool - ddcReady bool - - exponential bool - - stateMutex sync.RWMutex - state State - - subscribers syncmap.Map[string, chan State] - updateSubscribers syncmap.Map[string, chan DeviceUpdate] - - broadcastMutex sync.Mutex - broadcastTimer *time.Timer - broadcastPending bool - pendingDeviceID string - - stopChan chan struct{} -} - -type SysfsBackend struct { - basePath string - classes []string - - deviceCache syncmap.Map[string, *sysfsDevice] -} - -type sysfsDevice struct { - class DeviceClass - id string - name string - maxBrightness int - minValue int -} - -type DDCBackend struct { - devices syncmap.Map[string, *ddcDevice] - - scanMutex sync.Mutex - lastScan time.Time - scanInterval time.Duration - - debounceMutex sync.Mutex - debounceTimers map[string]*time.Timer - debouncePending map[string]ddcPendingSet - debounceWg sync.WaitGroup -} - -type ddcPendingSet struct { - percent int - callback func() -} - -type ddcDevice struct { - bus int - addr int - id string - name string - max int - lastBrightness int -} - -type ddcCapability struct { - vcp byte - max int - current int -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 16) - - m.subscribers.Store(id, ch) - - return ch -} - -func (m *Manager) Unsubscribe(id string) { - - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - - } - -} - -func (m *Manager) SubscribeUpdates(id string) chan DeviceUpdate { - ch := make(chan DeviceUpdate, 16) - m.updateSubscribers.Store(id, ch) - return ch -} - -func (m *Manager) UnsubscribeUpdates(id string) { - if val, ok := m.updateSubscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) NotifySubscribers() { - m.stateMutex.RLock() - state := m.state - m.stateMutex.RUnlock() - - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return m.state -} - -func (m *Manager) Close() { - close(m.stopChan) - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - m.updateSubscribers.Range(func(key string, ch chan DeviceUpdate) bool { - close(ch) - m.updateSubscribers.Delete(key) - return true - }) - - if m.udevMonitor != nil { - m.udevMonitor.Close() - } - - if m.logindBackend != nil { - m.logindBackend.Close() - } - - if m.ddcBackend != nil { - m.ddcBackend.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev.go deleted file mode 100644 index b7f02a8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev.go +++ /dev/null @@ -1,237 +0,0 @@ -package brightness - -import ( - "os" - "path/filepath" - "strconv" - "strings" - "sync" - "syscall" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/pilebones/go-udev/netlink" -) - -const ( - udevRecvBufSize = 8 * 1024 * 1024 - udevMaxRetries = 5 - udevBaseDelay = 2 * time.Second - udevMaxDelay = 60 * time.Second -) - -type UdevMonitor struct { - stop chan struct{} - rescanMutex sync.Mutex - rescanTimer *time.Timer - rescanPending bool -} - -func NewUdevMonitor(manager *Manager) *UdevMonitor { - m := &UdevMonitor{ - stop: make(chan struct{}), - } - - go m.run(manager) - return m -} - -func (m *UdevMonitor) run(manager *Manager) { - matcher := &netlink.RuleDefinitions{ - Rules: []netlink.RuleDefinition{ - {Env: map[string]string{"SUBSYSTEM": "backlight"}}, - {Env: map[string]string{"SUBSYSTEM": "drm"}}, - {Env: map[string]string{"SUBSYSTEM": "i2c"}}, - }, - } - if err := matcher.Compile(); err != nil { - log.Errorf("Failed to compile udev matcher: %v", err) - return - } - - failures := 0 - for { - if err := m.monitorLoop(manager, matcher); err != nil { - log.Errorf("Udev monitor error: %v", err) - } - - select { - case <-m.stop: - return - default: - } - - failures++ - if failures > udevMaxRetries { - log.Errorf("Udev monitor exceeded %d retries, giving up", udevMaxRetries) - return - } - - delay := min(udevBaseDelay*time.Duration(1<<(failures-1)), udevMaxDelay) - log.Infof("Udev monitor reconnecting in %v (attempt %d/%d)", delay, failures, udevMaxRetries) - - select { - case <-m.stop: - return - case <-time.After(delay): - } - } -} - -func (m *UdevMonitor) monitorLoop(manager *Manager, matcher *netlink.RuleDefinitions) error { - conn := &netlink.UEventConn{} - if err := conn.Connect(netlink.UdevEvent); err != nil { - return err - } - defer conn.Close() - - if err := syscall.SetsockoptInt(conn.Fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, udevRecvBufSize); err != nil { - log.Warnf("Failed to set udev socket receive buffer: %v", err) - } - - events := make(chan netlink.UEvent) - errs := make(chan error) - conn.Monitor(events, errs, matcher) - - log.Info("Udev monitor started for backlight/drm/i2c events") - - for { - select { - case <-m.stop: - return nil - case err := <-errs: - return err - case event := <-events: - m.handleEvent(manager, event) - } - } -} - -func (m *UdevMonitor) handleEvent(manager *Manager, event netlink.UEvent) { - subsystem := event.Env["SUBSYSTEM"] - devpath := event.Env["DEVPATH"] - - if subsystem == "" || devpath == "" { - return - } - - sysname := filepath.Base(devpath) - action := string(event.Action) - - switch subsystem { - case "drm", "i2c": - m.handleDisplayEvent(manager, action, subsystem, sysname) - case "backlight": - m.handleBacklightEvent(manager, action, sysname) - } -} - -func (m *UdevMonitor) handleDisplayEvent(manager *Manager, action, subsystem, sysname string) { - switch action { - case "add", "remove", "change": - log.Debugf("Udev %s event: %s:%s - queueing DDC rescan", action, subsystem, sysname) - m.debouncedRescan(manager) - } -} - -func (m *UdevMonitor) debouncedRescan(manager *Manager) { - m.rescanMutex.Lock() - defer m.rescanMutex.Unlock() - - m.rescanPending = true - - if m.rescanTimer != nil { - m.rescanTimer.Reset(2 * time.Second) - return - } - - m.rescanTimer = time.AfterFunc(2*time.Second, func() { - m.rescanMutex.Lock() - pending := m.rescanPending - m.rescanPending = false - m.rescanMutex.Unlock() - - if !pending { - return - } - - log.Debug("Executing debounced DDC rescan") - manager.Rescan() - }) -} - -func (m *UdevMonitor) handleBacklightEvent(manager *Manager, action, sysname string) { - switch action { - case "change": - m.handleChange(manager, "backlight", sysname) - case "add", "remove": - log.Debugf("Udev %s event: backlight:%s - triggering rescan", action, sysname) - manager.Rescan() - } -} - -func (m *UdevMonitor) handleChange(manager *Manager, subsystem, sysname string) { - deviceID := subsystem + ":" + sysname - - if manager.sysfsBackend == nil { - return - } - - brightnessPath := filepath.Join(manager.sysfsBackend.basePath, subsystem, sysname, "brightness") - data, err := os.ReadFile(brightnessPath) - if err != nil { - log.Debugf("Udev change event for %s but failed to read brightness: %v", deviceID, err) - return - } - - brightness, err := strconv.Atoi(strings.TrimSpace(string(data))) - if err != nil { - log.Debugf("Failed to parse brightness for %s: %v", deviceID, err) - return - } - - manager.handleUdevBrightnessChange(deviceID, brightness) -} - -func (m *UdevMonitor) Close() { - close(m.stop) -} - -func (m *Manager) handleUdevBrightnessChange(deviceID string, rawBrightness int) { - if m.sysfsBackend == nil { - return - } - - dev, err := m.sysfsBackend.GetDevice(deviceID) - if err != nil { - log.Debugf("Udev event for unknown device %s: %v", deviceID, err) - return - } - - percent := m.sysfsBackend.ValueToPercent(rawBrightness, dev, false) - - m.stateMutex.Lock() - var found bool - for i, d := range m.state.Devices { - if d.ID != deviceID { - continue - } - found = true - if d.Current == rawBrightness { - m.stateMutex.Unlock() - return - } - m.state.Devices[i].Current = rawBrightness - m.state.Devices[i].CurrentPercent = percent - break - } - m.stateMutex.Unlock() - - if !found { - log.Debugf("Udev event for device not in state: %s", deviceID) - return - } - - log.Debugf("Udev brightness change: %s -> %d (%d%%)", deviceID, rawBrightness, percent) - m.broadcastDeviceUpdate(deviceID) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev_test.go deleted file mode 100644 index a5c406b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/brightness/udev_test.go +++ /dev/null @@ -1,260 +0,0 @@ -package brightness - -import ( - "os" - "path/filepath" - "testing" - "time" - - "github.com/pilebones/go-udev/netlink" -) - -func setupTestManager(t *testing.T) (*Manager, string) { - tmpDir := t.TempDir() - - backlightDir := filepath.Join(tmpDir, "backlight", "intel_backlight") - if err := os.MkdirAll(backlightDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("1000\n"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("500\n"), 0o644); err != nil { - t.Fatal(err) - } - - sysfs := &SysfsBackend{ - basePath: tmpDir, - classes: []string{"backlight"}, - } - if err := sysfs.scanDevices(); err != nil { - t.Fatal(err) - } - - m := &Manager{ - sysfsBackend: sysfs, - sysfsReady: true, - stopChan: make(chan struct{}), - } - - m.state = State{ - Devices: []Device{ - { - Class: ClassBacklight, - ID: "backlight:intel_backlight", - Name: "intel_backlight", - Current: 500, - Max: 1000, - CurrentPercent: 50, - Backend: "sysfs", - }, - }, - } - - return m, tmpDir -} - -func TestHandleUdevBrightnessChange_UpdatesState(t *testing.T) { - m, _ := setupTestManager(t) - - m.handleUdevBrightnessChange("backlight:intel_backlight", 750) - - state := m.GetState() - if len(state.Devices) != 1 { - t.Fatalf("expected 1 device, got %d", len(state.Devices)) - } - - dev := state.Devices[0] - if dev.Current != 750 { - t.Errorf("expected Current=750, got %d", dev.Current) - } - if dev.CurrentPercent != 75 { - t.Errorf("expected CurrentPercent=75, got %d", dev.CurrentPercent) - } -} - -func TestHandleUdevBrightnessChange_NoChangeWhenSameValue(t *testing.T) { - m, _ := setupTestManager(t) - - updateCh := m.SubscribeUpdates("test") - defer m.UnsubscribeUpdates("test") - - m.handleUdevBrightnessChange("backlight:intel_backlight", 500) - - select { - case <-updateCh: - t.Error("should not broadcast when brightness unchanged") - case <-time.After(50 * time.Millisecond): - } -} - -func TestHandleUdevBrightnessChange_BroadcastsOnChange(t *testing.T) { - m, _ := setupTestManager(t) - - updateCh := m.SubscribeUpdates("test") - defer m.UnsubscribeUpdates("test") - - m.handleUdevBrightnessChange("backlight:intel_backlight", 750) - - select { - case update := <-updateCh: - if update.Device.Current != 750 { - t.Errorf("broadcast had wrong Current: got %d, want 750", update.Device.Current) - } - case <-time.After(100 * time.Millisecond): - t.Error("expected broadcast on brightness change") - } -} - -func TestHandleUdevBrightnessChange_UnknownDevice(t *testing.T) { - m, _ := setupTestManager(t) - - m.handleUdevBrightnessChange("backlight:unknown_device", 500) - - state := m.GetState() - if len(state.Devices) != 1 { - t.Errorf("state should be unchanged, got %d devices", len(state.Devices)) - } -} - -func TestHandleUdevBrightnessChange_NilSysfsBackend(t *testing.T) { - m := &Manager{ - sysfsBackend: nil, - stopChan: make(chan struct{}), - } - - m.handleUdevBrightnessChange("backlight:test", 500) -} - -func TestHandleUdevBrightnessChange_DeviceNotInState(t *testing.T) { - m, _ := setupTestManager(t) - - m.sysfsBackend.deviceCache.Store("backlight:other_device", &sysfsDevice{ - class: ClassBacklight, - id: "backlight:other_device", - name: "other_device", - maxBrightness: 100, - minValue: 1, - }) - - m.handleUdevBrightnessChange("backlight:other_device", 50) - - state := m.GetState() - for _, d := range state.Devices { - if d.ID == "backlight:other_device" { - t.Error("device should not be added to state via udev change event") - } - } -} - -func TestHandleEvent_ChangeAction(t *testing.T) { - m, tmpDir := setupTestManager(t) - um := &UdevMonitor{stop: make(chan struct{})} - - brightnessPath := filepath.Join(tmpDir, "backlight", "intel_backlight", "brightness") - if err := os.WriteFile(brightnessPath, []byte("800\n"), 0o644); err != nil { - t.Fatal(err) - } - - event := netlink.UEvent{ - Action: netlink.CHANGE, - Env: map[string]string{ - "SUBSYSTEM": "backlight", - "DEVPATH": "/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight", - }, - } - - um.handleEvent(m, event) - - state := m.GetState() - if state.Devices[0].Current != 800 { - t.Errorf("expected Current=800 after change event, got %d", state.Devices[0].Current) - } -} - -func TestHandleEvent_MissingEnvVars(t *testing.T) { - m, _ := setupTestManager(t) - um := &UdevMonitor{stop: make(chan struct{})} - - event := netlink.UEvent{ - Action: netlink.CHANGE, - Env: map[string]string{}, - } - - um.handleEvent(m, event) - - state := m.GetState() - if state.Devices[0].Current != 500 { - t.Error("state should be unchanged with missing env vars") - } -} - -func TestHandleEvent_MissingSubsystem(t *testing.T) { - m, _ := setupTestManager(t) - um := &UdevMonitor{stop: make(chan struct{})} - - event := netlink.UEvent{ - Action: netlink.CHANGE, - Env: map[string]string{ - "DEVPATH": "/devices/foo/bar", - }, - } - - um.handleEvent(m, event) - - state := m.GetState() - if state.Devices[0].Current != 500 { - t.Error("state should be unchanged with missing SUBSYSTEM") - } -} - -func TestHandleChange_BrightnessFileNotFound(t *testing.T) { - m, _ := setupTestManager(t) - um := &UdevMonitor{stop: make(chan struct{})} - - um.handleChange(m, "backlight", "nonexistent_device") - - state := m.GetState() - if state.Devices[0].Current != 500 { - t.Error("state should be unchanged when brightness file not found") - } -} - -func TestHandleChange_InvalidBrightnessValue(t *testing.T) { - m, tmpDir := setupTestManager(t) - um := &UdevMonitor{stop: make(chan struct{})} - - brightnessPath := filepath.Join(tmpDir, "backlight", "intel_backlight", "brightness") - if err := os.WriteFile(brightnessPath, []byte("not_a_number\n"), 0o644); err != nil { - t.Fatal(err) - } - - um.handleChange(m, "backlight", "intel_backlight") - - state := m.GetState() - if state.Devices[0].Current != 500 { - t.Error("state should be unchanged with invalid brightness value") - } -} - -func TestUdevMonitor_Close(t *testing.T) { - um := &UdevMonitor{stop: make(chan struct{})} - - um.Close() - - select { - case <-um.stop: - default: - t.Error("stop channel should be closed") - } -} - -func TestHandleChange_NilSysfsBackend(t *testing.T) { - m := &Manager{ - sysfsBackend: nil, - stopChan: make(chan struct{}), - } - um := &UdevMonitor{stop: make(chan struct{})} - - um.handleChange(m, "backlight", "test_device") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/handlers.go deleted file mode 100644 index 0b4159a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/handlers.go +++ /dev/null @@ -1,22 +0,0 @@ -package browser - -import ( - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "browser.open": - url, ok := models.Get[string](req, "url") - if !ok { - models.RespondError(conn, req.ID, "invalid url parameter") - return - } - manager.RequestOpen(url) - models.Respond(conn, req.ID, "ok") - default: - models.RespondError(conn, req.ID, "unknown method") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/manager.go deleted file mode 100644 index 5306759..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/manager.go +++ /dev/null @@ -1,49 +0,0 @@ -package browser - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type Manager struct { - subscribers syncmap.Map[string, chan OpenEvent] - closeOnce sync.Once -} - -func NewManager() *Manager { - return &Manager{} -} - -func (m *Manager) Subscribe(id string) chan OpenEvent { - ch := make(chan OpenEvent, 16) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) RequestOpen(url string) { - event := OpenEvent{URL: url} - m.subscribers.Range(func(key string, ch chan OpenEvent) bool { - select { - case ch <- event: - default: - } - return true - }) -} - -func (m *Manager) Close() { - m.closeOnce.Do(func() { - m.subscribers.Range(func(key string, ch chan OpenEvent) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/models.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/models.go deleted file mode 100644 index fc63519..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/browser/models.go +++ /dev/null @@ -1,5 +0,0 @@ -package browser - -type OpenEvent struct { - URL string `json:"url"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/handlers.go deleted file mode 100644 index 1ccc710..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/handlers.go +++ /dev/null @@ -1,325 +0,0 @@ -package clipboard - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, m *Manager) { - switch req.Method { - case "clipboard.getState": - handleGetState(conn, req, m) - case "clipboard.getHistory": - handleGetHistory(conn, req, m) - case "clipboard.getEntry": - handleGetEntry(conn, req, m) - case "clipboard.deleteEntry": - handleDeleteEntry(conn, req, m) - case "clipboard.clearHistory": - handleClearHistory(conn, req, m) - case "clipboard.copy": - handleCopy(conn, req, m) - case "clipboard.copyEntry": - handleCopyEntry(conn, req, m) - case "clipboard.paste": - handlePaste(conn, req, m) - case "clipboard.subscribe": - handleSubscribe(conn, req, m) - case "clipboard.search": - handleSearch(conn, req, m) - case "clipboard.getConfig": - handleGetConfig(conn, req, m) - case "clipboard.setConfig": - handleSetConfig(conn, req, m) - case "clipboard.store": - handleStore(conn, req, m) - case "clipboard.pinEntry": - handlePinEntry(conn, req, m) - case "clipboard.unpinEntry": - handleUnpinEntry(conn, req, m) - case "clipboard.getPinnedEntries": - handleGetPinnedEntries(conn, req, m) - case "clipboard.getPinnedCount": - handleGetPinnedCount(conn, req, m) - case "clipboard.copyFile": - handleCopyFile(conn, req, m) - default: - models.RespondError(conn, req.ID, "unknown method: "+req.Method) - } -} - -func handleGetState(conn net.Conn, req models.Request, m *Manager) { - models.Respond(conn, req.ID, m.GetState()) -} - -func handleGetHistory(conn net.Conn, req models.Request, m *Manager) { - history := m.GetHistory() - for i := range history { - history[i].Data = nil - } - models.Respond(conn, req.ID, history) -} - -func handleGetEntry(conn net.Conn, req models.Request, m *Manager) { - id, err := params.Int(req.Params, "id") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - entry, err := m.GetEntry(uint64(id)) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, entry) -} - -func handleDeleteEntry(conn net.Conn, req models.Request, m *Manager) { - id, err := params.Int(req.Params, "id") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.DeleteEntry(uint64(id)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "entry deleted"}) -} - -func handleClearHistory(conn net.Conn, req models.Request, m *Manager) { - m.ClearHistory() - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "history cleared"}) -} - -func handleCopy(conn net.Conn, req models.Request, m *Manager) { - text, err := params.String(req.Params, "text") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.CopyText(text); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "copied to clipboard"}) -} - -func handleCopyEntry(conn net.Conn, req models.Request, m *Manager) { - id, err := params.Int(req.Params, "id") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - entry, err := m.GetEntry(uint64(id)) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - filePath := m.EntryToFile(entry) - if filePath != "" { - if err := m.CopyFile(filePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, map[string]any{ - "success": true, - "filePath": filePath, - }) - return - } - - if err := m.SetClipboard(entry.Data, entry.MimeType); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if entry.Pinned { - if err := m.CreateHistoryEntryFromPinned(entry); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - } else { - if err := m.TouchEntry(uint64(id)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "copied to clipboard"}) -} - -func handlePaste(conn net.Conn, req models.Request, m *Manager) { - text, err := m.PasteText() - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, map[string]string{"text": text}) -} - -func handleSubscribe(conn net.Conn, req models.Request, m *Manager) { - clientID := fmt.Sprintf("clipboard-%d", req.ID) - - ch := m.Subscribe(clientID) - defer m.Unsubscribe(clientID) - - initialState := m.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range ch { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &state, - }); err != nil { - return - } - } -} - -func handleSearch(conn net.Conn, req models.Request, m *Manager) { - p := SearchParams{ - Query: params.StringOpt(req.Params, "query", ""), - MimeType: params.StringOpt(req.Params, "mimeType", ""), - Limit: params.IntOpt(req.Params, "limit", 50), - Offset: params.IntOpt(req.Params, "offset", 0), - } - - if img, ok := models.Get[bool](req, "isImage"); ok { - p.IsImage = &img - } - if b, ok := models.Get[float64](req, "before"); ok { - v := int64(b) - p.Before = &v - } - if a, ok := models.Get[float64](req, "after"); ok { - v := int64(a) - p.After = &v - } - - models.Respond(conn, req.ID, m.Search(p)) -} - -func handleGetConfig(conn net.Conn, req models.Request, m *Manager) { - models.Respond(conn, req.ID, m.GetConfig()) -} - -func handleSetConfig(conn net.Conn, req models.Request, m *Manager) { - cfg := m.GetConfig() - - if v, ok := models.Get[float64](req, "maxHistory"); ok { - cfg.MaxHistory = int(v) - } - if v, ok := models.Get[float64](req, "maxEntrySize"); ok { - cfg.MaxEntrySize = int64(v) - } - if v, ok := models.Get[float64](req, "autoClearDays"); ok { - cfg.AutoClearDays = int(v) - } - if v, ok := models.Get[bool](req, "clearAtStartup"); ok { - cfg.ClearAtStartup = v - } - if v, ok := models.Get[bool](req, "disabled"); ok { - cfg.Disabled = v - } - if v, ok := models.Get[float64](req, "maxPinned"); ok { - cfg.MaxPinned = int(v) - } - - if err := m.SetConfig(cfg); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "config updated"}) -} - -func handleStore(conn net.Conn, req models.Request, m *Manager) { - data, err := params.String(req.Params, "data") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - mimeType := params.StringOpt(req.Params, "mimeType", "text/plain;charset=utf-8") - - if err := m.StoreData([]byte(data), mimeType); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "stored"}) -} - -func handlePinEntry(conn net.Conn, req models.Request, m *Manager) { - id, err := params.Int(req.Params, "id") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.PinEntry(uint64(id)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "entry pinned"}) -} - -func handleUnpinEntry(conn net.Conn, req models.Request, m *Manager) { - id, err := params.Int(req.Params, "id") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.UnpinEntry(uint64(id)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "entry unpinned"}) -} - -func handleGetPinnedEntries(conn net.Conn, req models.Request, m *Manager) { - pinned := m.GetPinnedEntries() - models.Respond(conn, req.ID, pinned) -} - -func handleGetPinnedCount(conn net.Conn, req models.Request, m *Manager) { - count := m.GetPinnedCount() - models.Respond(conn, req.ID, map[string]int{"count": count}) -} - -func handleCopyFile(conn net.Conn, req models.Request, m *Manager) { - filePath, err := params.String(req.Params, "filePath") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.CopyFile(filePath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "copied"}) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager.go deleted file mode 100644 index f5f528b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager.go +++ /dev/null @@ -1,1911 +0,0 @@ -package clipboard - -import ( - "bytes" - "encoding/binary" - "fmt" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "io" - "os" - "os/exec" - "path/filepath" - "slices" - "strings" - "syscall" - "time" - - "hash/fnv" - - "github.com/fsnotify/fsnotify" - "github.com/godbus/dbus/v5" - _ "golang.org/x/image/bmp" - _ "golang.org/x/image/tiff" - _ "golang.org/x/image/webp" - - bolt "go.etcd.io/bbolt" - - clipboardstore "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_data_control" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -// These mime types won't be stored in history -var sensitiveMimeTypes = []string{ - "x-kde-passwordManagerHint", -} - -func NewManager(wlCtx wlcontext.WaylandContext, config Config) (*Manager, error) { - display := wlCtx.Display() - dbPath, err := clipboardstore.GetDBPath() - if err != nil { - return nil, fmt.Errorf("failed to get db path: %w", err) - } - - configPath, _ := getConfigPath() - - m := &Manager{ - config: config, - configPath: configPath, - display: display, - wlCtx: wlCtx, - stopChan: make(chan struct{}), - subscribers: make(map[string]chan State), - dirty: make(chan struct{}, 1), - offerMimeTypes: make(map[any][]string), - offerRegistry: make(map[uint32]any), - dbPath: dbPath, - } - - if !config.Disabled { - if err := m.setupRegistry(); err != nil { - return nil, err - } - } - - m.notifierWg.Add(1) - go m.notifier() - - go m.watchConfig() - - db, err := openDB(dbPath) - if err != nil { - return nil, fmt.Errorf("failed to open db: %w", err) - } - m.db = db - - if err := m.migrateHashes(); err != nil { - log.Errorf("Failed to migrate hashes: %v", err) - } - - if !config.Disabled { - if config.ClearAtStartup { - if err := m.clearHistoryInternal(); err != nil { - log.Errorf("Failed to clear history at startup: %v", err) - } - } - - if config.AutoClearDays > 0 { - if err := m.clearOldEntries(config.AutoClearDays); err != nil { - log.Errorf("Failed to clear old entries: %v", err) - } - } - } - - m.alive = true - m.updateState() - - if !config.Disabled && m.dataControlMgr != nil && m.seat != nil { - m.setupDataDeviceSync() - } - - return m, nil -} - -func openDB(path string) (*bolt.DB, error) { - db, err := bolt.Open(path, 0o644, &bolt.Options{ - Timeout: 1 * time.Second, - }) - if err != nil { - return nil, err - } - - err = db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucketIfNotExists([]byte("clipboard")) - return err - }) - if err != nil { - db.Close() - return nil, err - } - - return db, nil -} - -func (m *Manager) post(fn func()) { - m.wlCtx.Post(fn) -} - -func (m *Manager) setupRegistry() error { - ctx := m.display.Context() - - registry, err := m.display.GetRegistry() - if err != nil { - return fmt.Errorf("failed to get registry: %w", err) - } - m.registry = registry - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case "ext_data_control_manager_v1": - if e.Version < 1 { - return - } - dataControlMgr := ext_data_control.NewExtDataControlManagerV1(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, dataControlMgr); err != nil { - log.Errorf("Failed to bind ext_data_control_manager_v1: %v", err) - return - } - m.dataControlMgr = dataControlMgr - log.Info("Bound ext_data_control_manager_v1") - case "wl_seat": - seat := wlclient.NewSeat(ctx) - if err := registry.Bind(e.Name, e.Interface, e.Version, seat); err != nil { - log.Errorf("Failed to bind wl_seat: %v", err) - return - } - m.seat = seat - m.seatName = e.Name - log.Info("Bound wl_seat") - } - }) - - m.display.Roundtrip() - m.display.Roundtrip() - - if m.dataControlMgr == nil { - return fmt.Errorf("compositor does not support ext_data_control_manager_v1") - } - - if m.seat == nil { - return fmt.Errorf("no seat available") - } - - return nil -} - -func (m *Manager) setupDataDeviceSync() { - if m.dataControlMgr == nil || m.seat == nil { - return - } - - ctx := m.display.Context() - dataMgr := m.dataControlMgr.(*ext_data_control.ExtDataControlManagerV1) - - dataDevice := ext_data_control.NewExtDataControlDeviceV1(ctx) - - dataDevice.SetDataOfferHandler(func(e ext_data_control.ExtDataControlDeviceV1DataOfferEvent) { - if e.Id == nil { - return - } - - m.offerMutex.Lock() - m.offerRegistry[e.Id.ID()] = e.Id - m.offerMimeTypes[e.Id] = make([]string, 0) - m.offerMutex.Unlock() - - e.Id.SetOfferHandler(func(me ext_data_control.ExtDataControlOfferV1OfferEvent) { - m.offerMutex.Lock() - m.offerMimeTypes[e.Id] = append(m.offerMimeTypes[e.Id], me.MimeType) - m.offerMutex.Unlock() - }) - }) - - dataDevice.SetSelectionHandler(func(e ext_data_control.ExtDataControlDeviceV1SelectionEvent) { - if !m.initialized { - m.initialized = true - return - } - - var offer any - if e.Id != nil { - offer = e.Id - } else if e.OfferId != 0 { - m.offerMutex.RLock() - offer = m.offerRegistry[e.OfferId] - m.offerMutex.RUnlock() - } - - m.ownerLock.Lock() - wasOwner := m.isOwner - m.ownerLock.Unlock() - - if offer == nil { - return - } - - if wasOwner { - return - } - - prevOffer := m.currentOffer - m.currentOffer = offer - - if prevOffer != nil && prevOffer != offer { - m.offerMutex.Lock() - delete(m.offerMimeTypes, prevOffer) - m.offerMutex.Unlock() - } - - m.offerMutex.RLock() - mimes := m.offerMimeTypes[offer] - m.offerMutex.RUnlock() - - m.mimeTypes = mimes - - if len(mimes) == 0 { - return - } - - if m.hasSensitiveMimeType(mimes) { - return - } - - preferredMime := m.selectMimeType(mimes) - if preferredMime == "" { - return - } - - typedOffer := offer.(*ext_data_control.ExtDataControlOfferV1) - - r, w, err := os.Pipe() - if err != nil { - return - } - - if err := typedOffer.Receive(preferredMime, int(w.Fd())); err != nil { - r.Close() - w.Close() - return - } - w.Close() - - go m.readAndStore(r, preferredMime) - }) - - if err := dataMgr.GetDataDeviceWithProxy(dataDevice, m.seat); err != nil { - log.Errorf("Failed to send get_data_device request: %v", err) - return - } - - m.dataDevice = dataDevice - - if err := ctx.Dispatch(); err != nil { - log.Errorf("Failed to dispatch initial events: %v", err) - return - } - - log.Info("Data device setup complete") -} - -func (m *Manager) readAndStore(r *os.File, mimeType string) { - defer r.Close() - - cfg := m.getConfig() - - done := make(chan []byte, 1) - go func() { - data, _ := io.ReadAll(r) - done <- data - }() - - var data []byte - select { - case data = <-done: - case <-time.After(500 * time.Millisecond): - return - } - - if len(data) == 0 || int64(len(data)) > cfg.MaxEntrySize { - return - } - if len(bytes.TrimSpace(data)) == 0 { - return - } - - if !cfg.Disabled && m.db != nil { - m.storeClipboardEntry(data, mimeType) - } - - m.updateState() - m.notifySubscribers() -} - -func (m *Manager) storeClipboardEntry(data []byte, mimeType string) { - if mimeType == "text/uri-list" { - if imgData, imgMime, ok := m.tryReadImageFromURI(data); ok { - data = imgData - mimeType = imgMime - } - } - - entry := Entry{ - Data: data, - MimeType: mimeType, - Size: len(data), - Timestamp: time.Now(), - IsImage: m.isImageMimeType(mimeType), - } - - switch { - case entry.IsImage: - entry.Preview = m.imagePreview(data, mimeType) - case mimeType == "text/uri-list": - entry.Preview, entry.IsImage = m.uriListPreview(data) - default: - entry.Preview = m.textPreview(data) - } - - if err := m.storeEntry(entry); err != nil { - log.Errorf("Failed to store clipboard entry: %v", err) - } -} - -func (m *Manager) storeEntry(entry Entry) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - entry.Hash = computeHash(entry.Data) - - return m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - - if err := m.deduplicateInTx(b, entry.Hash); err != nil { - return err - } - - id, err := b.NextSequence() - if err != nil { - return err - } - - entry.ID = id - - encoded, err := encodeEntry(entry) - if err != nil { - return err - } - - if err := b.Put(itob(id), encoded); err != nil { - return err - } - - return m.trimLengthInTx(b) - }) -} - -func (m *Manager) deduplicateInTx(b *bolt.Bucket, hash uint64) error { - c := b.Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - if extractHash(v) != hash { - continue - } - entry, err := decodeEntry(v) - if err == nil && entry.Pinned { - continue - } - if err := b.Delete(k); err != nil { - return err - } - } - return nil -} - -func (m *Manager) trimLengthInTx(b *bolt.Bucket) error { - if m.config.MaxHistory < 0 { - return nil - } - c := b.Cursor() - var count int - for k, v := c.Last(); k != nil; k, v = c.Prev() { - entry, err := decodeEntry(v) - if err == nil && entry.Pinned { - continue - } - if count < m.config.MaxHistory { - count++ - continue - } - if err := b.Delete(k); err != nil { - return err - } - } - return nil -} - -func encodeEntry(e Entry) ([]byte, error) { - buf := new(bytes.Buffer) - - binary.Write(buf, binary.BigEndian, e.ID) - binary.Write(buf, binary.BigEndian, uint32(len(e.Data))) - buf.Write(e.Data) - binary.Write(buf, binary.BigEndian, uint32(len(e.MimeType))) - buf.WriteString(e.MimeType) - binary.Write(buf, binary.BigEndian, uint32(len(e.Preview))) - buf.WriteString(e.Preview) - binary.Write(buf, binary.BigEndian, int32(e.Size)) - binary.Write(buf, binary.BigEndian, e.Timestamp.Unix()) - if e.IsImage { - buf.WriteByte(1) - } else { - buf.WriteByte(0) - } - binary.Write(buf, binary.BigEndian, e.Hash) - if e.Pinned { - buf.WriteByte(1) - } else { - buf.WriteByte(0) - } - - return buf.Bytes(), nil -} - -func decodeEntry(data []byte) (Entry, error) { - buf := bytes.NewReader(data) - var e Entry - - binary.Read(buf, binary.BigEndian, &e.ID) - - var dataLen uint32 - binary.Read(buf, binary.BigEndian, &dataLen) - e.Data = make([]byte, dataLen) - buf.Read(e.Data) - - var mimeLen uint32 - binary.Read(buf, binary.BigEndian, &mimeLen) - mimeBytes := make([]byte, mimeLen) - buf.Read(mimeBytes) - e.MimeType = string(mimeBytes) - - var prevLen uint32 - binary.Read(buf, binary.BigEndian, &prevLen) - prevBytes := make([]byte, prevLen) - buf.Read(prevBytes) - e.Preview = string(prevBytes) - - var size int32 - binary.Read(buf, binary.BigEndian, &size) - e.Size = int(size) - - var timestamp int64 - binary.Read(buf, binary.BigEndian, ×tamp) - e.Timestamp = time.Unix(timestamp, 0) - - var isImage byte - binary.Read(buf, binary.BigEndian, &isImage) - e.IsImage = isImage == 1 - - if buf.Len() >= 8 { - binary.Read(buf, binary.BigEndian, &e.Hash) - } - - if buf.Len() >= 1 { - var pinnedByte byte - binary.Read(buf, binary.BigEndian, &pinnedByte) - e.Pinned = pinnedByte == 1 - } - - return e, nil -} - -func itob(v uint64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, v) - return b -} - -func computeHash(data []byte) uint64 { - h := fnv.New64a() - h.Write(data) - return h.Sum64() -} - -func extractHash(data []byte) uint64 { - if len(data) < 9 { - return 0 - } - return binary.BigEndian.Uint64(data[len(data)-9 : len(data)-1]) -} - -func (m *Manager) hasSensitiveMimeType(mimes []string) bool { - return slices.ContainsFunc(mimes, func(mime string) bool { - return slices.Contains(sensitiveMimeTypes, mime) - }) -} - -func (m *Manager) selectMimeType(mimes []string) string { - preferredTypes := []string{ - "text/uri-list", - "text/plain;charset=utf-8", - "text/plain", - "UTF8_STRING", - "STRING", - "TEXT", - "image/png", - "image/jpeg", - "image/gif", - "image/bmp", - "image/tiff", - } - - for _, pref := range preferredTypes { - for _, mime := range mimes { - if mime == pref { - return mime - } - } - } - - // Skip useless MIME types when falling back - for _, mime := range mimes { - switch mime { - case "application/vnd.portal.filetransfer": - continue - default: - return mime - } - } - - return "" -} - -func (m *Manager) isImageMimeType(mime string) bool { - return strings.HasPrefix(mime, "image/") -} - -func (m *Manager) textPreview(data []byte) string { - text := string(data) - text = strings.TrimSpace(text) - text = strings.Join(strings.Fields(text), " ") - - if len(text) > 100 { - return text[:100] + "…" - } - return text -} - -func (m *Manager) imagePreview(data []byte, format string) string { - config, imgFmt, err := image.DecodeConfig(bytes.NewReader(data)) - if err != nil { - return fmt.Sprintf("[[ image %s %s ]]", sizeStr(len(data)), format) - } - return fmt.Sprintf("[[ image %s %s %dx%d ]]", sizeStr(len(data)), imgFmt, config.Width, config.Height) -} - -func (m *Manager) uriListPreview(data []byte) (string, bool) { - text := strings.TrimSpace(string(data)) - uris := strings.Split(text, "\r\n") - if len(uris) == 0 { - uris = strings.Split(text, "\n") - } - - if len(uris) > 1 { - return fmt.Sprintf("[[ %d files ]]", len(uris)), false - } - - if len(uris) == 1 && strings.HasPrefix(uris[0], "file://") { - filePath := strings.TrimPrefix(uris[0], "file://") - info, err := os.Stat(filePath) - if err != nil || info.IsDir() { - return m.textPreview(data), false - } - - cfg := m.getConfig() - if info.Size() <= cfg.MaxEntrySize { - if imgData, err := os.ReadFile(filePath); err == nil { - if config, imgFmt, err := image.DecodeConfig(bytes.NewReader(imgData)); err == nil { - return fmt.Sprintf("[[ file %s %s %dx%d ]]", filepath.Base(filePath), imgFmt, config.Width, config.Height), true - } - } - } - return fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), false - } - - return m.textPreview(data), false -} - -func (m *Manager) tryReadImageFromURI(data []byte) ([]byte, string, bool) { - text := strings.TrimSpace(string(data)) - uris := strings.Split(text, "\r\n") - if len(uris) == 0 { - uris = strings.Split(text, "\n") - } - - if len(uris) != 1 || !strings.HasPrefix(uris[0], "file://") { - return nil, "", false - } - - filePath := strings.TrimPrefix(uris[0], "file://") - info, err := os.Stat(filePath) - if err != nil || info.IsDir() { - return nil, "", false - } - - cfg := m.getConfig() - if info.Size() > cfg.MaxEntrySize { - return nil, "", false - } - - imgData, err := os.ReadFile(filePath) - if err != nil { - return nil, "", false - } - - _, imgFmt, err := image.DecodeConfig(bytes.NewReader(imgData)) - if err != nil { - return nil, "", false - } - - return imgData, "image/" + imgFmt, true -} - -func sizeStr(size int) string { - units := []string{"B", "KiB", "MiB"} - var i int - fsize := float64(size) - for fsize >= 1024 && i < len(units)-1 { - fsize /= 1024 - i++ - } - return fmt.Sprintf("%.0f %s", fsize, units[i]) -} - -func (m *Manager) updateState() { - history := m.GetHistory() - - for i := range history { - history[i].Data = nil - } - - var current *Entry - if len(history) > 0 { - c := history[0] - c.Data = nil - current = &c - } - - newState := &State{ - Enabled: m.alive, - History: history, - Current: current, - } - - m.stateMutex.Lock() - m.state = newState - m.stateMutex.Unlock() -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - - for range m.dirty { - state := m.GetState() - - if m.lastState != nil && stateEqual(m.lastState, &state) { - continue - } - - m.lastState = &state - - m.subMutex.RLock() - subs := make([]chan State, 0, len(m.subscribers)) - for _, ch := range m.subscribers { - subs = append(subs, ch) - } - m.subMutex.RUnlock() - - for _, ch := range subs { - select { - case ch <- state: - default: - } - } - } -} - -func stateEqual(a, b *State) bool { - if a == nil || b == nil { - return false - } - if a.Enabled != b.Enabled { - return false - } - if len(a.History) != len(b.History) { - return false - } - return true -} - -func (m *Manager) GetHistory() []Entry { - if m.db == nil { - return nil - } - - cfg := m.getConfig() - var cutoff time.Time - if cfg.AutoClearDays > 0 { - cutoff = time.Now().AddDate(0, 0, -cfg.AutoClearDays) - } - - var history []Entry - var stale []uint64 - - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - c := b.Cursor() - - for k, v := c.Last(); k != nil; k, v = c.Prev() { - entry, err := decodeEntry(v) - if err != nil { - continue - } - if !cutoff.IsZero() && entry.Timestamp.Before(cutoff) { - stale = append(stale, entry.ID) - continue - } - history = append(history, entry) - } - return nil - }); err != nil { - log.Errorf("Failed to read clipboard history: %v", err) - } - - if len(stale) > 0 { - go m.deleteStaleEntries(stale) - } - - return history -} - -func (m *Manager) deleteStaleEntries(ids []uint64) { - if m.db == nil { - return - } - - if err := m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - for _, id := range ids { - if err := b.Delete(itob(id)); err != nil { - log.Errorf("Failed to delete stale entry %d: %v", id, err) - } - } - return nil - }); err != nil { - log.Errorf("Failed to delete stale entries: %v", err) - } -} - -func (m *Manager) GetEntry(id uint64) (*Entry, error) { - if m.db == nil { - return nil, fmt.Errorf("database not available") - } - - var entry Entry - var found bool - - err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - v := b.Get(itob(id)) - if v == nil { - return nil - } - - var err error - entry, err = decodeEntry(v) - if err != nil { - return err - } - found = true - return nil - }) - - if err != nil { - return nil, err - } - if !found { - return nil, fmt.Errorf("entry not found") - } - - return &entry, nil -} - -func (m *Manager) DeleteEntry(id uint64) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - err := m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - return b.Delete(itob(id)) - }) - - if err == nil { - m.updateState() - m.notifySubscribers() - } - - return err -} - -func (m *Manager) TouchEntry(id uint64) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - entry, err := m.GetEntry(id) - if err != nil { - return err - } - - entry.Timestamp = time.Now() - - if err := m.storeEntry(*entry); err != nil { - return err - } - - m.updateState() - m.notifySubscribers() - - return nil -} - -func (m *Manager) CreateHistoryEntryFromPinned(pinnedEntry *Entry) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - // Create a new unpinned entry with the same data - newEntry := Entry{ - Data: pinnedEntry.Data, - MimeType: pinnedEntry.MimeType, - Size: pinnedEntry.Size, - Timestamp: time.Now(), - IsImage: pinnedEntry.IsImage, - Preview: pinnedEntry.Preview, - Pinned: false, - } - - if err := m.storeEntryWithoutDedup(newEntry); err != nil { - return err - } - - m.updateState() - m.notifySubscribers() - - return nil -} - -func (m *Manager) storeEntryWithoutDedup(entry Entry) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - entry.Hash = computeHash(entry.Data) - - return m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - - id, err := b.NextSequence() - if err != nil { - return err - } - - entry.ID = id - - encoded, err := encodeEntry(entry) - if err != nil { - return err - } - - if err := b.Put(itob(id), encoded); err != nil { - return err - } - - return m.trimLengthInTx(b) - }) -} - -func (m *Manager) ClearHistory() { - if m.db == nil { - return - } - - // Delete only non-pinned entries - if err := m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - var toDelete [][]byte - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err != nil || !entry.Pinned { - toDelete = append(toDelete, k) - } - } - - for _, k := range toDelete { - if err := b.Delete(k); err != nil { - return err - } - } - return nil - }); err != nil { - log.Errorf("Failed to clear clipboard history: %v", err) - return - } - - pinnedCount := 0 - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b != nil { - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, _ := decodeEntry(v) - if entry.Pinned { - pinnedCount++ - } - } - } - return nil - }); err != nil { - log.Errorf("Failed to count pinned entries: %v", err) - } - - if pinnedCount == 0 { - if err := m.compactDB(); err != nil { - log.Errorf("Failed to compact database: %v", err) - } - } - - m.updateState() - m.notifySubscribers() -} - -func (m *Manager) compactDB() error { - m.db.Close() - - tmpPath := m.dbPath + ".compact" - defer os.Remove(tmpPath) - - srcDB, err := bolt.Open(m.dbPath, 0o644, &bolt.Options{ReadOnly: true, Timeout: time.Second}) - if err != nil { - m.db, _ = bolt.Open(m.dbPath, 0o644, &bolt.Options{Timeout: time.Second}) - return fmt.Errorf("open source: %w", err) - } - - dstDB, err := bolt.Open(tmpPath, 0o644, &bolt.Options{Timeout: time.Second}) - if err != nil { - srcDB.Close() - m.db, _ = bolt.Open(m.dbPath, 0o644, &bolt.Options{Timeout: time.Second}) - return fmt.Errorf("open destination: %w", err) - } - - if err := bolt.Compact(dstDB, srcDB, 0); err != nil { - srcDB.Close() - dstDB.Close() - m.db, _ = bolt.Open(m.dbPath, 0o644, &bolt.Options{Timeout: time.Second}) - return fmt.Errorf("compact: %w", err) - } - - srcDB.Close() - dstDB.Close() - - if err := os.Rename(tmpPath, m.dbPath); err != nil { - m.db, _ = bolt.Open(m.dbPath, 0o644, &bolt.Options{Timeout: time.Second}) - return fmt.Errorf("rename: %w", err) - } - - m.db, err = bolt.Open(m.dbPath, 0o644, &bolt.Options{Timeout: time.Second}) - if err != nil { - return fmt.Errorf("reopen: %w", err) - } - - return nil -} - -func (m *Manager) SetClipboard(data []byte, mimeType string) error { - if int64(len(data)) > m.config.MaxEntrySize { - return fmt.Errorf("data too large") - } - - dataCopy := make([]byte, len(data)) - copy(dataCopy, data) - - m.post(func() { - if m.dataControlMgr == nil || m.dataDevice == nil { - log.Error("Data control manager or device not initialized") - return - } - - dataMgr := m.dataControlMgr.(*ext_data_control.ExtDataControlManagerV1) - - source, err := dataMgr.CreateDataSource() - if err != nil { - log.Errorf("Failed to create data source: %v", err) - return - } - - if err := source.Offer(mimeType); err != nil { - log.Errorf("Failed to offer mime type: %v", err) - return - } - - source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) { - fd := e.Fd - defer syscall.Close(fd) - - file := os.NewFile(uintptr(fd), "clipboard-pipe") - defer file.Close() - - if _, err := file.Write(dataCopy); err != nil { - log.Errorf("Failed to write clipboard data: %v", err) - } - }) - - source.SetCancelledHandler(func(e ext_data_control.ExtDataControlSourceV1CancelledEvent) { - m.ownerLock.Lock() - m.isOwner = false - m.ownerLock.Unlock() - }) - - m.currentSource = source - m.sourceMutex.Lock() - m.sourceMimeTypes = []string{mimeType} - m.sourceMutex.Unlock() - - m.ownerLock.Lock() - m.isOwner = true - m.ownerLock.Unlock() - - device := m.dataDevice.(*ext_data_control.ExtDataControlDeviceV1) - if err := device.SetSelection(source); err != nil { - log.Errorf("Failed to set selection: %v", err) - } - }) - - return nil -} - -func (m *Manager) CopyText(text string) error { - if err := m.SetClipboard([]byte(text), "text/plain;charset=utf-8"); err != nil { - return err - } - - entry := Entry{ - Data: []byte(text), - MimeType: "text/plain;charset=utf-8", - Size: len(text), - Timestamp: time.Now(), - IsImage: false, - Preview: m.textPreview([]byte(text)), - } - - if err := m.storeEntry(entry); err != nil { - log.Errorf("Failed to store clipboard entry: %v", err) - } - - m.updateState() - m.notifySubscribers() - - return nil -} - -func (m *Manager) PasteText() (string, error) { - history := m.GetHistory() - if len(history) == 0 { - return "", fmt.Errorf("no clipboard data available") - } - - entry := history[0] - if entry.IsImage { - return "", fmt.Errorf("clipboard contains image, not text") - } - - fullEntry, err := m.GetEntry(entry.ID) - if err != nil { - return "", err - } - - return string(fullEntry.Data), nil -} - -func (m *Manager) Close() { - if !m.alive { - return - } - - m.alive = false - close(m.stopChan) - - close(m.dirty) - m.notifierWg.Wait() - - m.subMutex.Lock() - for _, ch := range m.subscribers { - close(ch) - } - m.subscribers = make(map[string]chan State) - m.subMutex.Unlock() - - if m.currentSource != nil { - source := m.currentSource.(*ext_data_control.ExtDataControlSourceV1) - source.Destroy() - } - - if m.dataDevice != nil { - device := m.dataDevice.(*ext_data_control.ExtDataControlDeviceV1) - device.Destroy() - } - - if m.dataControlMgr != nil { - mgr := m.dataControlMgr.(*ext_data_control.ExtDataControlManagerV1) - mgr.Destroy() - } - - if m.registry != nil { - m.registry.Destroy() - } - - if m.db != nil { - m.db.Close() - } -} - -func (m *Manager) clearHistoryInternal() error { - return m.db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("clipboard")); err != nil { - return err - } - _, err := tx.CreateBucket([]byte("clipboard")) - return err - }) -} - -func (m *Manager) clearOldEntries(days int) error { - cutoff := time.Now().AddDate(0, 0, -days) - - return m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - var toDelete [][]byte - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err != nil { - continue - } - // Skip pinned entries - if entry.Pinned { - continue - } - if entry.Timestamp.Before(cutoff) { - toDelete = append(toDelete, k) - } - } - - for _, k := range toDelete { - if err := b.Delete(k); err != nil { - return err - } - } - return nil - }) -} - -func (m *Manager) migrateHashes() error { - if m.db == nil { - return nil - } - - var needsMigration bool - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if extractHash(v) == 0 { - needsMigration = true - return nil - } - } - return nil - }); err != nil { - return err - } - - if !needsMigration { - return nil - } - - log.Info("Migrating clipboard entries to add hashes...") - - return m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - var updates []struct { - key []byte - entry Entry - } - - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err != nil { - continue - } - if entry.Hash != 0 { - continue - } - entry.Hash = computeHash(entry.Data) - keyCopy := make([]byte, len(k)) - copy(keyCopy, k) - updates = append(updates, struct { - key []byte - entry Entry - }{keyCopy, entry}) - } - - for _, u := range updates { - encoded, err := encodeEntry(u.entry) - if err != nil { - continue - } - if err := b.Put(u.key, encoded); err != nil { - return err - } - } - - log.Infof("Migrated %d clipboard entries", len(updates)) - return nil - }) -} - -func (m *Manager) Search(params SearchParams) SearchResult { - if m.db == nil { - return SearchResult{} - } - - if params.Limit <= 0 { - params.Limit = 50 - } - if params.Limit > 500 { - params.Limit = 500 - } - - query := strings.ToLower(params.Query) - mimeFilter := strings.ToLower(params.MimeType) - - var all []Entry - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - c := b.Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - entry, err := decodeEntry(v) - if err != nil { - continue - } - - if params.IsImage != nil && entry.IsImage != *params.IsImage { - continue - } - - if mimeFilter != "" && !strings.Contains(strings.ToLower(entry.MimeType), mimeFilter) { - continue - } - - if params.Before != nil && entry.Timestamp.Unix() >= *params.Before { - continue - } - - if params.After != nil && entry.Timestamp.Unix() <= *params.After { - continue - } - - if query != "" && !strings.Contains(strings.ToLower(entry.Preview), query) { - continue - } - - entry.Data = nil - all = append(all, entry) - } - return nil - }); err != nil { - log.Errorf("Search failed: %v", err) - } - - total := len(all) - - start := params.Offset - if start > total { - start = total - } - end := start + params.Limit - if end > total { - end = total - } - - return SearchResult{ - Entries: all[start:end], - Total: total, - HasMore: end < total, - } -} - -func (m *Manager) GetConfig() Config { - return m.config -} - -func (m *Manager) SetConfig(cfg Config) error { - m.configMutex.Lock() - m.config = cfg - m.configMutex.Unlock() - - m.updateState() - m.notifySubscribers() - - return SaveConfig(cfg) -} - -func (m *Manager) getConfig() Config { - m.configMutex.RLock() - defer m.configMutex.RUnlock() - return m.config -} - -func (m *Manager) watchConfig() { - if m.configPath == "" { - return - } - - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Warnf("Failed to create config watcher: %v", err) - return - } - defer watcher.Close() - - configDir := filepath.Dir(m.configPath) - if err := watcher.Add(configDir); err != nil { - log.Warnf("Failed to watch config directory: %v", err) - return - } - - for { - select { - case <-m.stopChan: - return - case event, ok := <-watcher.Events: - if !ok { - return - } - if event.Name != m.configPath { - continue - } - if event.Op&(fsnotify.Write|fsnotify.Create) == 0 { - continue - } - newCfg := LoadConfig() - m.applyConfigChange(newCfg) - case err, ok := <-watcher.Errors: - if !ok { - return - } - log.Warnf("Config watcher error: %v", err) - } - } -} - -func (m *Manager) applyConfigChange(newCfg Config) { - m.configMutex.Lock() - oldCfg := m.config - m.config = newCfg - m.configMutex.Unlock() - - switch { - case newCfg.Disabled && !oldCfg.Disabled: - log.Info("Clipboard tracking disabled") - case !newCfg.Disabled && oldCfg.Disabled: - log.Info("Clipboard tracking enabled") - } - - m.updateState() - m.notifySubscribers() -} - -func (m *Manager) StoreData(data []byte, mimeType string) error { - cfg := m.getConfig() - - if cfg.Disabled { - return fmt.Errorf("clipboard tracking disabled") - } - - if m.db == nil { - return fmt.Errorf("database not available") - } - - if len(data) == 0 { - return nil - } - - if int64(len(data)) > cfg.MaxEntrySize { - return fmt.Errorf("data too large") - } - - if len(bytes.TrimSpace(data)) == 0 { - return nil - } - - entry := Entry{ - Data: data, - MimeType: mimeType, - Size: len(data), - Timestamp: time.Now(), - IsImage: m.isImageMimeType(mimeType), - } - - switch { - case entry.IsImage: - entry.Preview = m.imagePreview(data, mimeType) - case mimeType == "text/uri-list": - entry.Preview, entry.IsImage = m.uriListPreview(data) - default: - entry.Preview = m.textPreview(data) - } - - if err := m.storeEntry(entry); err != nil { - return err - } - - m.updateState() - m.notifySubscribers() - - return nil -} - -func (m *Manager) PinEntry(id uint64) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - entryToPin, err := m.GetEntry(id) - if err != nil { - return err - } - - var hashExists bool - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err != nil || !entry.Pinned { - continue - } - if entry.Hash == entryToPin.Hash { - hashExists = true - return nil - } - } - return nil - }); err != nil { - return err - } - - if hashExists { - return nil - } - - // Check pinned count - cfg := m.getConfig() - pinnedCount := 0 - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err == nil && entry.Pinned { - pinnedCount++ - } - } - return nil - }); err != nil { - log.Errorf("Failed to count pinned entries: %v", err) - } - - if pinnedCount >= cfg.MaxPinned { - return fmt.Errorf("maximum pinned entries reached (%d)", cfg.MaxPinned) - } - - err = m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - v := b.Get(itob(id)) - if v == nil { - return fmt.Errorf("entry not found") - } - - entry, err := decodeEntry(v) - if err != nil { - return err - } - - entry.Pinned = true - encoded, err := encodeEntry(entry) - if err != nil { - return err - } - - return b.Put(itob(id), encoded) - }) - - if err == nil { - m.updateState() - m.notifySubscribers() - } - - return err -} - -func (m *Manager) UnpinEntry(id uint64) error { - if m.db == nil { - return fmt.Errorf("database not available") - } - - err := m.db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - v := b.Get(itob(id)) - if v == nil { - return fmt.Errorf("entry not found") - } - - entry, err := decodeEntry(v) - if err != nil { - return err - } - - entry.Pinned = false - encoded, err := encodeEntry(entry) - if err != nil { - return err - } - - return b.Put(itob(id), encoded) - }) - - if err == nil { - m.updateState() - m.notifySubscribers() - } - - return err -} - -func (m *Manager) GetPinnedEntries() []Entry { - if m.db == nil { - return nil - } - - var pinned []Entry - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - c := b.Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - entry, err := decodeEntry(v) - if err != nil { - continue - } - if entry.Pinned { - entry.Data = nil - pinned = append(pinned, entry) - } - } - return nil - }); err != nil { - log.Errorf("Failed to get pinned entries: %v", err) - } - - return pinned -} - -func (m *Manager) GetPinnedCount() int { - if m.db == nil { - return 0 - } - - count := 0 - if err := m.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("clipboard")) - if b == nil { - return nil - } - - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - entry, err := decodeEntry(v) - if err == nil && entry.Pinned { - count++ - } - } - return nil - }); err != nil { - log.Errorf("Failed to count pinned entries: %v", err) - } - - return count -} - -func (m *Manager) CopyFile(filePath string) error { - fileInfo, err := os.Stat(filePath) - if err != nil { - return fmt.Errorf("file not found: %w", err) - } - - cfg := m.getConfig() - if fileInfo.Size() > cfg.MaxEntrySize { - return fmt.Errorf("file too large: %d > %d", fileInfo.Size(), cfg.MaxEntrySize) - } - - fileData, err := os.ReadFile(filePath) - if err != nil { - return fmt.Errorf("read file: %w", err) - } - - exportedPath, err := m.ExportFileForFlatpak(filePath) - if err != nil { - exportedPath = filePath - } - fileURI := "file://" + exportedPath - - if imgData, imgMime, ok := m.tryReadImageFromURI([]byte("file://" + filePath)); ok { - entry := Entry{ - Data: imgData, - MimeType: imgMime, - Size: len(imgData), - Timestamp: time.Now(), - IsImage: true, - Preview: m.imagePreview(imgData, imgMime), - } - if err := m.storeEntry(entry); err != nil { - log.Errorf("Failed to store file entry: %v", err) - } - } else { - entry := Entry{ - Data: fileData, - MimeType: "text/uri-list", - Size: len(fileData), - Timestamp: time.Now(), - IsImage: false, - Preview: fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), - } - if err := m.storeEntry(entry); err != nil { - log.Errorf("Failed to store file entry: %v", err) - } - } - - m.updateState() - m.notifySubscribers() - - _, imgMime, imgErr := image.DecodeConfig(bytes.NewReader(fileData)) - - m.post(func() { - if m.dataControlMgr == nil || m.dataDevice == nil { - log.Error("Data control manager or device not initialized") - return - } - - dataMgr := m.dataControlMgr.(*ext_data_control.ExtDataControlManagerV1) - source, err := dataMgr.CreateDataSource() - if err != nil { - log.Errorf("Failed to create data source: %v", err) - return - } - - type offer struct { - mime string - data []byte - } - offers := []offer{ - {"x-special/gnome-copied-files", []byte("copy\n" + fileURI)}, - {"text/uri-list", []byte(fileURI + "\r\n")}, - {"text/plain", []byte(filePath)}, - } - - if imgErr == nil { - imgMimeType := "image/" + imgMime - offers = append(offers, offer{imgMimeType, fileData}) - } - - offerData := make(map[string][]byte) - for _, o := range offers { - if err := source.Offer(o.mime); err != nil { - log.Errorf("Failed to offer %s: %v", o.mime, err) - return - } - offerData[o.mime] = o.data - } - - source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) { - fd := e.Fd - defer syscall.Close(fd) - file := os.NewFile(uintptr(fd), "clipboard-pipe") - defer file.Close() - if data, ok := offerData[e.MimeType]; ok { - file.Write(data) - } - }) - - source.SetCancelledHandler(func(e ext_data_control.ExtDataControlSourceV1CancelledEvent) { - m.ownerLock.Lock() - m.isOwner = false - m.ownerLock.Unlock() - }) - - m.currentSource = source - - m.ownerLock.Lock() - m.isOwner = true - m.ownerLock.Unlock() - - device := m.dataDevice.(*ext_data_control.ExtDataControlDeviceV1) - if err := device.SetSelection(source); err != nil { - log.Errorf("Failed to set selection: %v", err) - } - }) - - return nil -} - -func (m *Manager) EntryToFile(entry *Entry) string { - switch { - case entry.MimeType == "text/uri-list": - data := strings.TrimSpace(string(entry.Data)) - lines := strings.Split(data, "\n") - if len(lines) == 0 { - return "" - } - uri := strings.TrimSuffix(strings.TrimSpace(lines[0]), "\r") - if path, ok := strings.CutPrefix(uri, "file://"); ok { - return path - } - case entry.IsImage: - ext := ".png" - if suffix, ok := strings.CutPrefix(entry.MimeType, "image/"); ok { - ext = "." + suffix - } - cacheDir, err := os.UserCacheDir() - if err != nil { - return "" - } - clipDir := filepath.Join(cacheDir, "dms", "clipboard") - if err := os.MkdirAll(clipDir, 0o755); err != nil { - return "" - } - filePath := filepath.Join(clipDir, fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)) - if os.WriteFile(filePath, entry.Data, 0o644) != nil { - return "" - } - return filePath - } - return "" -} - -func (m *Manager) ExportFileForFlatpak(filePath string) (string, error) { - if _, err := os.Stat(filePath); err != nil { - return "", fmt.Errorf("file not found: %w", err) - } - - if m.dbusConn == nil { - conn, err := dbus.ConnectSessionBus() - if err != nil { - return "", fmt.Errorf("connect session bus: %w", err) - } - if !conn.SupportsUnixFDs() { - conn.Close() - return "", fmt.Errorf("D-Bus connection does not support Unix FD passing") - } - m.dbusConn = conn - } - - file, err := os.Open(filePath) - if err != nil { - return "", fmt.Errorf("open file: %w", err) - } - fd := int(file.Fd()) - - portal := m.dbusConn.Object("org.freedesktop.portal.Documents", "/org/freedesktop/portal/documents") - - var docIds []string - var extra map[string]dbus.Variant - flags := uint32(0) - - err = portal.Call( - "org.freedesktop.portal.Documents.AddFull", - 0, - []dbus.UnixFD{dbus.UnixFD(fd)}, - flags, - "", - []string{}, - ).Store(&docIds, &extra) - - file.Close() - - if err != nil { - return "", fmt.Errorf("AddFull: %w", err) - } - - if len(docIds) == 0 { - return "", fmt.Errorf("no doc IDs returned") - } - - docId := docIds[0] - - for _, app := range getInstalledFlatpaks() { - _ = portal.Call( - "org.freedesktop.portal.Documents.GrantPermissions", - 0, - docId, - app, - []string{"read"}, - ).Err - } - - uid := os.Getuid() - basename := filepath.Base(filePath) - exportedPath := fmt.Sprintf("/run/user/%d/doc/%s/%s", uid, docId, basename) - - return exportedPath, nil -} - -func getInstalledFlatpaks() []string { - out, err := exec.Command("flatpak", "list", "--app", "--columns=application").Output() - if err != nil { - return nil - } - - var apps []string - for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { - if app := strings.TrimSpace(line); app != "" { - apps = append(apps, app) - } - } - return apps -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager_test.go deleted file mode 100644 index db45bca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/manager_test.go +++ /dev/null @@ -1,531 +0,0 @@ -package clipboard - -import ( - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - mocks_wlcontext "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlcontext" -) - -func TestEncodeDecodeEntry_Roundtrip(t *testing.T) { - original := Entry{ - ID: 12345, - Data: []byte("hello world"), - MimeType: "text/plain;charset=utf-8", - Preview: "hello world", - Size: 11, - Timestamp: time.Now().Truncate(time.Second), - IsImage: false, - } - - encoded, err := encodeEntry(original) - assert.NoError(t, err) - - decoded, err := decodeEntry(encoded) - assert.NoError(t, err) - - assert.Equal(t, original.ID, decoded.ID) - assert.Equal(t, original.Data, decoded.Data) - assert.Equal(t, original.MimeType, decoded.MimeType) - assert.Equal(t, original.Preview, decoded.Preview) - assert.Equal(t, original.Size, decoded.Size) - assert.Equal(t, original.Timestamp.Unix(), decoded.Timestamp.Unix()) - assert.Equal(t, original.IsImage, decoded.IsImage) -} - -func TestEncodeDecodeEntry_Image(t *testing.T) { - original := Entry{ - ID: 99999, - Data: []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}, - MimeType: "image/png", - Preview: "[[ image 8 B png 100x100 ]]", - Size: 8, - Timestamp: time.Now().Truncate(time.Second), - IsImage: true, - } - - encoded, err := encodeEntry(original) - assert.NoError(t, err) - - decoded, err := decodeEntry(encoded) - assert.NoError(t, err) - - assert.Equal(t, original.ID, decoded.ID) - assert.Equal(t, original.Data, decoded.Data) - assert.True(t, decoded.IsImage) - assert.Equal(t, original.Preview, decoded.Preview) -} - -func TestEncodeDecodeEntry_EmptyData(t *testing.T) { - original := Entry{ - ID: 1, - Data: []byte{}, - MimeType: "text/plain", - Preview: "", - Size: 0, - Timestamp: time.Now().Truncate(time.Second), - IsImage: false, - } - - encoded, err := encodeEntry(original) - assert.NoError(t, err) - - decoded, err := decodeEntry(encoded) - assert.NoError(t, err) - - assert.Equal(t, original.ID, decoded.ID) - assert.Empty(t, decoded.Data) -} - -func TestEncodeDecodeEntry_LargeData(t *testing.T) { - largeData := make([]byte, 100000) - for i := range largeData { - largeData[i] = byte(i % 256) - } - - original := Entry{ - ID: 777, - Data: largeData, - MimeType: "application/octet-stream", - Preview: "binary data...", - Size: len(largeData), - Timestamp: time.Now().Truncate(time.Second), - IsImage: false, - } - - encoded, err := encodeEntry(original) - assert.NoError(t, err) - - decoded, err := decodeEntry(encoded) - assert.NoError(t, err) - - assert.Equal(t, original.Data, decoded.Data) - assert.Equal(t, original.Size, decoded.Size) -} - -func TestStateEqual_BothNil(t *testing.T) { - assert.False(t, stateEqual(nil, nil)) -} - -func TestStateEqual_OneNil(t *testing.T) { - s := &State{Enabled: true} - assert.False(t, stateEqual(s, nil)) - assert.False(t, stateEqual(nil, s)) -} - -func TestStateEqual_EnabledDiffers(t *testing.T) { - a := &State{Enabled: true, History: []Entry{}} - b := &State{Enabled: false, History: []Entry{}} - assert.False(t, stateEqual(a, b)) -} - -func TestStateEqual_HistoryLengthDiffers(t *testing.T) { - a := &State{Enabled: true, History: []Entry{{ID: 1}}} - b := &State{Enabled: true, History: []Entry{}} - assert.False(t, stateEqual(a, b)) -} - -func TestStateEqual_BothEqual(t *testing.T) { - a := &State{Enabled: true, History: []Entry{{ID: 1}, {ID: 2}}} - b := &State{Enabled: true, History: []Entry{{ID: 3}, {ID: 4}}} - assert.True(t, stateEqual(a, b)) -} - -func TestManager_ConcurrentSubscriberAccess(t *testing.T) { - m := &Manager{ - subscribers: make(map[string]chan State), - dirty: make(chan struct{}, 1), - } - - var wg sync.WaitGroup - const goroutines = 20 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - subID := string(rune('a' + id)) - ch := m.Subscribe(subID) - assert.NotNil(t, ch) - time.Sleep(time.Millisecond) - m.Unsubscribe(subID) - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentGetState(t *testing.T) { - m := &Manager{ - state: &State{ - Enabled: true, - History: []Entry{{ID: 1}, {ID: 2}}, - }, - } - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - s := m.GetState() - _ = s.Enabled - _ = len(s.History) - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.stateMutex.Lock() - m.state = &State{ - Enabled: j%2 == 0, - History: []Entry{{ID: uint64(j)}}, - } - m.stateMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentConfigAccess(t *testing.T) { - m := &Manager{ - config: DefaultConfig(), - } - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - cfg := m.getConfig() - _ = cfg.MaxHistory - _ = cfg.MaxEntrySize - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.configMutex.Lock() - m.config.MaxHistory = 50 + j - m.config.MaxEntrySize = int64(1024 * j) - m.configMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_NotifySubscribersNonBlocking(t *testing.T) { - m := &Manager{ - dirty: make(chan struct{}, 1), - } - - for i := 0; i < 10; i++ { - m.notifySubscribers() - } - - assert.Len(t, m.dirty, 1) -} - -func TestManager_ConcurrentOfferAccess(t *testing.T) { - m := &Manager{ - offerMimeTypes: make(map[any][]string), - offerRegistry: make(map[uint32]any), - } - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - m.offerMutex.Lock() - m.offerRegistry[key] = struct{}{} - m.offerMimeTypes[key] = []string{"text/plain"} - m.offerMutex.Unlock() - - m.offerMutex.RLock() - _ = m.offerRegistry[key] - _ = m.offerMimeTypes[key] - m.offerMutex.RUnlock() - - m.offerMutex.Lock() - delete(m.offerRegistry, key) - delete(m.offerMimeTypes, key) - m.offerMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentPersistAccess(t *testing.T) { - m := &Manager{ - persistData: make(map[string][]byte), - persistMimeTypes: []string{}, - } - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 50 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.persistMutex.RLock() - _ = m.persistData - _ = m.persistMimeTypes - m.persistMutex.RUnlock() - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.persistMutex.Lock() - m.persistMimeTypes = []string{"text/plain", "text/html"} - m.persistData = map[string][]byte{ - "text/plain": []byte("test"), - } - m.persistMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentOwnerAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.ownerLock.Lock() - _ = m.isOwner - m.ownerLock.Unlock() - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.ownerLock.Lock() - m.isOwner = j%2 == 0 - m.ownerLock.Unlock() - } - }() - } - - wg.Wait() -} - -func TestItob(t *testing.T) { - tests := []struct { - input uint64 - expected []byte - }{ - {0, []byte{0, 0, 0, 0, 0, 0, 0, 0}}, - {1, []byte{0, 0, 0, 0, 0, 0, 0, 1}}, - {256, []byte{0, 0, 0, 0, 0, 0, 1, 0}}, - {0xFFFFFFFFFFFFFFFF, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, - } - - for _, tt := range tests { - result := itob(tt.input) - assert.Equal(t, tt.expected, result) - } -} - -func TestSizeStr(t *testing.T) { - tests := []struct { - input int - expected string - }{ - {0, "0 B"}, - {100, "100 B"}, - {1024, "1 KiB"}, - {2048, "2 KiB"}, - {1048576, "1 MiB"}, - {5242880, "5 MiB"}, - } - - for _, tt := range tests { - result := sizeStr(tt.input) - assert.Equal(t, tt.expected, result) - } -} - -func TestSelectMimeType(t *testing.T) { - m := &Manager{} - - tests := []struct { - mimes []string - expected string - }{ - {[]string{"text/plain;charset=utf-8", "text/html"}, "text/plain;charset=utf-8"}, - {[]string{"text/html", "text/plain"}, "text/plain"}, - {[]string{"text/html", "image/png"}, "image/png"}, - {[]string{"image/png", "image/jpeg"}, "image/png"}, - {[]string{"image/png"}, "image/png"}, - {[]string{"application/octet-stream"}, "application/octet-stream"}, - {[]string{}, ""}, - } - - for _, tt := range tests { - result := m.selectMimeType(tt.mimes) - assert.Equal(t, tt.expected, result) - } -} - -func TestIsImageMimeType(t *testing.T) { - m := &Manager{} - - assert.True(t, m.isImageMimeType("image/png")) - assert.True(t, m.isImageMimeType("image/jpeg")) - assert.True(t, m.isImageMimeType("image/gif")) - assert.False(t, m.isImageMimeType("text/plain")) - assert.False(t, m.isImageMimeType("application/json")) -} - -func TestTextPreview(t *testing.T) { - m := &Manager{} - - short := m.textPreview([]byte("hello world")) - assert.Equal(t, "hello world", short) - - withWhitespace := m.textPreview([]byte(" hello world ")) - assert.Equal(t, "hello world", withWhitespace) - - longText := make([]byte, 200) - for i := range longText { - longText[i] = 'a' - } - preview := m.textPreview(longText) - assert.True(t, len(preview) > 100) - assert.Contains(t, preview, "…") -} - -func TestDefaultConfig(t *testing.T) { - cfg := DefaultConfig() - assert.Equal(t, 100, cfg.MaxHistory) - assert.Equal(t, int64(5*1024*1024), cfg.MaxEntrySize) - assert.Equal(t, 0, cfg.AutoClearDays) - assert.False(t, cfg.ClearAtStartup) - assert.False(t, cfg.Disabled) -} - -func TestManager_PostDelegatesToWlContext(t *testing.T) { - mockCtx := mocks_wlcontext.NewMockWaylandContext(t) - - var called atomic.Bool - mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) { - called.Store(true) - fn() - }).Once() - - m := &Manager{ - wlCtx: mockCtx, - } - - executed := false - m.post(func() { - executed = true - }) - - assert.True(t, called.Load()) - assert.True(t, executed) -} - -func TestManager_PostExecutesFunctionViaContext(t *testing.T) { - mockCtx := mocks_wlcontext.NewMockWaylandContext(t) - - var capturedFn func() - mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) { - capturedFn = fn - }).Times(3) - - m := &Manager{ - wlCtx: mockCtx, - } - - counter := 0 - m.post(func() { counter++ }) - m.post(func() { counter += 10 }) - m.post(func() { counter += 100 }) - - assert.NotNil(t, capturedFn) - capturedFn() - assert.Equal(t, 100, counter) -} - -func TestManager_ConcurrentPostWithMock(t *testing.T) { - mockCtx := mocks_wlcontext.NewMockWaylandContext(t) - - var postCount atomic.Int32 - mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) { - postCount.Add(1) - }).Times(100) - - m := &Manager{ - wlCtx: mockCtx, - } - - var wg sync.WaitGroup - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < 10; j++ { - m.post(func() {}) - } - }() - } - - wg.Wait() - assert.Equal(t, int32(100), postCount.Load()) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/types.go deleted file mode 100644 index c754561..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/clipboard/types.go +++ /dev/null @@ -1,196 +0,0 @@ -package clipboard - -import ( - "encoding/json" - "os" - "path/filepath" - "sync" - "time" - - "github.com/godbus/dbus/v5" - bolt "go.etcd.io/bbolt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type Config struct { - MaxHistory int `json:"maxHistory"` - MaxEntrySize int64 `json:"maxEntrySize"` - AutoClearDays int `json:"autoClearDays"` - ClearAtStartup bool `json:"clearAtStartup"` - Disabled bool `json:"disabled"` - MaxPinned int `json:"maxPinned"` -} - -func DefaultConfig() Config { - return Config{ - MaxHistory: 100, - MaxEntrySize: 5 * 1024 * 1024, - AutoClearDays: 0, - ClearAtStartup: false, - MaxPinned: 25, - } -} - -func getConfigPath() (string, error) { - configDir, err := os.UserConfigDir() - if err != nil { - return "", err - } - return filepath.Join(configDir, "DankMaterialShell", "clsettings.json"), nil -} - -func LoadConfig() Config { - cfg := DefaultConfig() - - path, err := getConfigPath() - if err != nil { - return cfg - } - - data, err := os.ReadFile(path) - if err != nil { - return cfg - } - - if err := json.Unmarshal(data, &cfg); err != nil { - return DefaultConfig() - } - return cfg -} - -func SaveConfig(cfg Config) error { - path, err := getConfigPath() - if err != nil { - return err - } - - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - return err - } - - data, err := json.MarshalIndent(cfg, "", " ") - if err != nil { - return err - } - - return os.WriteFile(path, data, 0o644) -} - -type SearchParams struct { - Query string `json:"query"` - MimeType string `json:"mimeType"` - IsImage *bool `json:"isImage"` - Limit int `json:"limit"` - Offset int `json:"offset"` - Before *int64 `json:"before"` - After *int64 `json:"after"` -} - -type SearchResult struct { - Entries []Entry `json:"entries"` - Total int `json:"total"` - HasMore bool `json:"hasMore"` -} - -type Entry struct { - ID uint64 `json:"id"` - Data []byte `json:"data,omitempty"` - MimeType string `json:"mimeType"` - Preview string `json:"preview"` - Size int `json:"size"` - Timestamp time.Time `json:"timestamp"` - IsImage bool `json:"isImage"` - Hash uint64 `json:"hash,omitempty"` - Pinned bool `json:"pinned"` -} - -type State struct { - Enabled bool `json:"enabled"` - History []Entry `json:"history"` - Current *Entry `json:"current,omitempty"` -} - -type Manager struct { - config Config - configMutex sync.RWMutex - configPath string - - display wlclient.WaylandDisplay - wlCtx wlcontext.WaylandContext - - registry *wlclient.Registry - dataControlMgr any - seat *wlclient.Seat - dataDevice any - currentOffer any - currentSource any - seatName uint32 - mimeTypes []string - offerMimeTypes map[any][]string - offerMutex sync.RWMutex - offerRegistry map[uint32]any - - sourceMimeTypes []string - sourceMutex sync.RWMutex - - persistData map[string][]byte - persistMimeTypes []string - persistMutex sync.RWMutex - - isOwner bool - ownerLock sync.Mutex - - initialized bool - - alive bool - stopChan chan struct{} - - db *bolt.DB - dbPath string - - state *State - stateMutex sync.RWMutex - - subscribers map[string]chan State - subMutex sync.RWMutex - dirty chan struct{} - notifierWg sync.WaitGroup - lastState *State - - dbusConn *dbus.Conn -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{} - } - return *m.state -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - m.subMutex.Lock() - m.subscribers[id] = ch - m.subMutex.Unlock() - return ch -} - -func (m *Manager) Unsubscribe(id string) { - m.subMutex.Lock() - if ch, ok := m.subscribers[id]; ok { - close(ch) - delete(m.subscribers, id) - } - m.subMutex.Unlock() -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions.go deleted file mode 100644 index 2f9b98b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions.go +++ /dev/null @@ -1,479 +0,0 @@ -package cups - -import ( - "errors" - "fmt" - "net" - "net/url" - "os/exec" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" -) - -func isAuthError(err error) bool { - if err == nil { - return false - } - - var httpErr ipp.HTTPError - if errors.As(err, &httpErr) { - return httpErr.Code == 401 || httpErr.Code == 403 - } - - var ippErr ipp.IPPError - if errors.As(err, &ippErr) { - return ippErr.Status == ipp.StatusErrorForbidden || - ippErr.Status == ipp.StatusErrorNotAuthenticated || - ippErr.Status == ipp.StatusErrorNotAuthorized - } - - return false -} - -func (m *Manager) GetPrinters() ([]Printer, error) { - attributes := []string{ - ipp.AttributePrinterName, - ipp.AttributePrinterUriSupported, - ipp.AttributePrinterState, - ipp.AttributePrinterStateReasons, - ipp.AttributePrinterLocation, - ipp.AttributePrinterInfo, - ipp.AttributePrinterMakeAndModel, - ipp.AttributePrinterIsAcceptingJobs, - } - - printerAttrs, err := m.client.GetPrinters(attributes) - if err != nil { - if isNoPrintersError(err) { - return []Printer{}, nil - } - return nil, err - } - - printers := make([]Printer, 0, len(printerAttrs)) - for _, attrs := range printerAttrs { - printer := Printer{ - Name: getStringAttr(attrs, ipp.AttributePrinterName), - URI: getStringAttr(attrs, ipp.AttributePrinterUriSupported), - State: parsePrinterState(attrs), - StateReason: getStringAttr(attrs, ipp.AttributePrinterStateReasons), - Location: getStringAttr(attrs, ipp.AttributePrinterLocation), - Info: getStringAttr(attrs, ipp.AttributePrinterInfo), - MakeModel: getStringAttr(attrs, ipp.AttributePrinterMakeAndModel), - Accepting: getBoolAttr(attrs, ipp.AttributePrinterIsAcceptingJobs), - } - - if printer.Name != "" { - printers = append(printers, printer) - } - } - - return printers, nil -} - -func (m *Manager) GetJobs(printerName string, whichJobs string) ([]Job, error) { - attributes := []string{ - ipp.AttributeJobID, - ipp.AttributeJobName, - ipp.AttributeJobState, - ipp.AttributeJobPrinterURI, - ipp.AttributeJobOriginatingUserName, - ipp.AttributeJobKilobyteOctets, - "time-at-creation", - } - - jobAttrs, err := m.client.GetJobs(printerName, "", whichJobs, false, 0, 0, attributes) - if err != nil { - return nil, err - } - - jobs := make([]Job, 0, len(jobAttrs)) - for _, attrs := range jobAttrs { - job := Job{ - ID: getIntAttr(attrs, ipp.AttributeJobID), - Name: getStringAttr(attrs, ipp.AttributeJobName), - State: parseJobState(attrs), - User: getStringAttr(attrs, ipp.AttributeJobOriginatingUserName), - Size: getIntAttr(attrs, ipp.AttributeJobKilobyteOctets) * 1024, - } - - if uri := getStringAttr(attrs, ipp.AttributeJobPrinterURI); uri != "" { - parts := strings.Split(uri, "/") - if len(parts) > 0 { - job.Printer = parts[len(parts)-1] - } - } - - if ts := getIntAttr(attrs, "time-at-creation"); ts > 0 { - job.TimeCreated = time.Unix(int64(ts), 0) - } - - if job.ID != 0 { - jobs = append(jobs, job) - } - } - - return jobs, nil -} - -func (m *Manager) CancelJob(jobID int) error { - err := m.client.CancelJob(jobID, false) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.JobCancelPurge(jobID, false) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) PausePrinter(printerName string) error { - err := m.client.PausePrinter(printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetEnabled(printerName, false) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) ResumePrinter(printerName string) error { - err := m.client.ResumePrinter(printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetEnabled(printerName, true) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) PurgeJobs(printerName string) error { - err := m.client.CancelAllJob(printerName, true) - if err == nil { - m.RefreshState() - } - return err -} - -func resolveIPFromURI(uri string) string { - parsed, err := url.Parse(uri) - if err != nil { - return "" - } - host := parsed.Hostname() - if host == "" { - return "" - } - if ip := net.ParseIP(host); ip != nil { - return ip.String() - } - addrs, err := net.LookupIP(host) - if err != nil || len(addrs) == 0 { - return "" - } - for _, addr := range addrs { - if v4 := addr.To4(); v4 != nil { - return v4.String() - } - } - return addrs[0].String() -} - -func (m *Manager) GetDevices() ([]Device, error) { - if m.pkHelper != nil { - devices, err := m.pkHelper.DevicesGet(10, 0, nil, nil) - if err != nil { - return nil, err - } - for i := range devices { - if devices[i].Class == "network" { - devices[i].IP = resolveIPFromURI(devices[i].URI) - } - } - return devices, nil - } - - deviceAttrs, err := m.client.GetDevices() - if err != nil { - return nil, err - } - - devices := make([]Device, 0, len(deviceAttrs)) - for uri, attrs := range deviceAttrs { - device := Device{ - URI: uri, - Class: getStringAttr(attrs, "device-class"), - Info: getStringAttr(attrs, "device-info"), - MakeModel: getStringAttr(attrs, "device-make-and-model"), - ID: getStringAttr(attrs, "device-id"), - Location: getStringAttr(attrs, "device-location"), - } - if device.Class == "network" { - device.IP = resolveIPFromURI(uri) - } - devices = append(devices, device) - } - - return devices, nil -} - -func (m *Manager) GetPPDs() ([]PPD, error) { - ppdAttrs, err := m.client.GetPPDs() - if err != nil { - return nil, err - } - - ppds := make([]PPD, 0, len(ppdAttrs)) - for name, attrs := range ppdAttrs { - ppd := PPD{ - Name: name, - NaturalLanguage: getStringAttr(attrs, "ppd-natural-language"), - MakeModel: getStringAttr(attrs, ipp.AttributePPDMakeAndModel), - DeviceID: getStringAttr(attrs, "ppd-device-id"), - Product: getStringAttr(attrs, "ppd-product"), - PSVersion: getStringAttr(attrs, "ppd-psversion"), - Type: getStringAttr(attrs, "ppd-type"), - } - ppds = append(ppds, ppd) - } - - return ppds, nil -} - -func (m *Manager) GetClasses() ([]PrinterClass, error) { - attributes := []string{ - ipp.AttributePrinterName, - ipp.AttributePrinterUriSupported, - ipp.AttributePrinterState, - ipp.AttributeMemberURIs, - ipp.AttributeMemberNames, - ipp.AttributePrinterLocation, - ipp.AttributePrinterInfo, - } - - classAttrs, err := m.client.GetClasses(attributes) - if err != nil { - return nil, err - } - - classes := make([]PrinterClass, 0, len(classAttrs)) - for _, attrs := range classAttrs { - class := PrinterClass{ - Name: getStringAttr(attrs, ipp.AttributePrinterName), - URI: getStringAttr(attrs, ipp.AttributePrinterUriSupported), - State: parsePrinterState(attrs), - Location: getStringAttr(attrs, ipp.AttributePrinterLocation), - Info: getStringAttr(attrs, ipp.AttributePrinterInfo), - Members: getStringSliceAttr(attrs, ipp.AttributeMemberNames), - } - classes = append(classes, class) - } - - return classes, nil -} - -func createPrinterViaLpadmin(name, deviceURI, ppd, information, location string) error { - args := []string{"-p", name, "-E", "-v", deviceURI, "-m", ppd} - if information != "" { - args = append(args, "-D", information) - } - if location != "" { - args = append(args, "-L", location) - } - out, err := exec.Command("lpadmin", args...).CombinedOutput() - if err != nil { - return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err) - } - return nil -} - -func deletePrinterViaLpadmin(name string) error { - out, err := exec.Command("lpadmin", "-x", name).CombinedOutput() - if err != nil { - return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err) - } - return nil -} - -func (m *Manager) CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy, information, location string) error { - usedPkHelper := false - - err := m.client.CreatePrinter(name, deviceURI, ppd, shared, errorPolicy, information, location) - if isAuthError(err) && m.pkHelper != nil { - if err = m.pkHelper.PrinterAdd(name, deviceURI, ppd, information, location); err != nil { - // pkHelper failed (e.g., no polkit agent), try lpadmin as last resort. - // lpadmin -E enables the printer, so no further setup needed. - if lpadminErr := createPrinterViaLpadmin(name, deviceURI, ppd, information, location); lpadminErr != nil { - return err - } - m.RefreshState() - return nil - } - usedPkHelper = true - } else if err != nil { - return err - } - - if usedPkHelper { - m.pkHelper.PrinterSetEnabled(name, true) //nolint:errcheck - m.pkHelper.PrinterSetAcceptJobs(name, true, "") //nolint:errcheck - } else { - if err := m.client.ResumePrinter(name); isAuthError(err) && m.pkHelper != nil { - m.pkHelper.PrinterSetEnabled(name, true) //nolint:errcheck - } - if err := m.client.AcceptJobs(name); isAuthError(err) && m.pkHelper != nil { - m.pkHelper.PrinterSetAcceptJobs(name, true, "") //nolint:errcheck - } - } - - m.RefreshState() - return nil -} - -func (m *Manager) DeletePrinter(printerName string) error { - err := m.client.DeletePrinter(printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterDelete(printerName) - if err != nil { - // pkHelper failed, try lpadmin as last resort - if lpadminErr := deletePrinterViaLpadmin(printerName); lpadminErr == nil { - err = nil - } - } - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) AcceptJobs(printerName string) error { - err := m.client.AcceptJobs(printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetAcceptJobs(printerName, true, "") - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) RejectJobs(printerName string) error { - err := m.client.RejectJobs(printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetAcceptJobs(printerName, false, "") - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) SetPrinterShared(printerName string, shared bool) error { - err := m.client.SetPrinterIsShared(printerName, shared) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetShared(printerName, shared) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) SetPrinterLocation(printerName, location string) error { - err := m.client.SetPrinterLocation(printerName, location) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetLocation(printerName, location) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) SetPrinterInfo(printerName, info string) error { - err := m.client.SetPrinterInformation(printerName, info) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.PrinterSetInfo(printerName, info) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) MoveJob(jobID int, destPrinter string) error { - err := m.client.MoveJob(jobID, destPrinter) - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) PrintTestPage(printerName string) (int, error) { - jobID, err := m.client.PrintTestPage(printerName, strings.NewReader(config.TestPage), len(config.TestPage)) - if err == nil { - m.RefreshState() - } - return jobID, err -} - -func (m *Manager) AddPrinterToClass(className, printerName string) error { - err := m.client.AddPrinterToClass(className, printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.ClassAddPrinter(className, printerName) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) RemovePrinterFromClass(className, printerName string) error { - err := m.client.DeletePrinterFromClass(className, printerName) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.ClassDeletePrinter(className, printerName) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) DeleteClass(className string) error { - err := m.client.DeleteClass(className) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.ClassDelete(className) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) RestartJob(jobID int) error { - err := m.client.RestartJob(jobID) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.JobRestart(jobID) - } - if err == nil { - m.RefreshState() - } - return err -} - -func (m *Manager) HoldJob(jobID int, holdUntil string) error { - err := m.client.HoldJobUntil(jobID, holdUntil) - if isAuthError(err) && m.pkHelper != nil { - err = m.pkHelper.JobSetHoldUntil(jobID, holdUntil) - } - if err == nil { - m.RefreshState() - } - return err -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go deleted file mode 100644 index ad16a8a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package cups_test - -import ( - "testing" - - mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups" - mocks_pkhelper "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups_pkhelper" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func authErr() error { - return ipp.IPPError{Status: ipp.StatusErrorForbidden} -} - -func TestManager_CancelJob_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelJob(1, false).Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().JobCancelPurge(1, false).Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.CancelJob(1)) -} - -func TestManager_CancelJob_PkHelperError(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelJob(1, false).Return(authErr()) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().JobCancelPurge(1, false).Return(assert.AnError) - - m := cups.NewTestManager(mockClient, mockPk) - assert.Error(t, m.CancelJob(1)) -} - -func TestManager_PausePrinter_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().PausePrinter("printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetEnabled("printer1", false).Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.PausePrinter("printer1")) -} - -func TestManager_ResumePrinter_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().ResumePrinter("printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetEnabled("printer1", true).Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.ResumePrinter("printer1")) -} - -func TestManager_GetDevices_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().DevicesGet(10, 0, []string(nil), []string(nil)).Return([]cups.Device{ - {URI: "usb://HP/LaserJet", Class: "direct"}, - }, nil) - - m := cups.NewTestManager(mockClient, mockPk) - got, err := m.GetDevices() - assert.NoError(t, err) - assert.Len(t, got, 1) - assert.Equal(t, "usb://HP/LaserJet", got[0].URI) -} - -func TestManager_GetDevices_PkHelperError(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().DevicesGet(10, 0, []string(nil), []string(nil)).Return(nil, assert.AnError) - - m := cups.NewTestManager(mockClient, mockPk) - _, err := m.GetDevices() - assert.Error(t, err) -} - -func TestManager_CreatePrinter_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterAdd("newprinter", "usb://HP", "generic.ppd", "info", "location").Return(nil) - mockPk.EXPECT().PrinterSetEnabled("newprinter", true).Return(nil) - mockPk.EXPECT().PrinterSetAcceptJobs("newprinter", true, "").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location")) -} - -func TestManager_DeletePrinter_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinter("printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterDelete("printer1").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.DeletePrinter("printer1")) -} - -func TestManager_AcceptJobs_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AcceptJobs("printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetAcceptJobs("printer1", true, "").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.AcceptJobs("printer1")) -} - -func TestManager_RejectJobs_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RejectJobs("printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetAcceptJobs("printer1", false, "").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.RejectJobs("printer1")) -} - -func TestManager_SetPrinterShared_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetShared("printer1", true).Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.SetPrinterShared("printer1", true)) -} - -func TestManager_SetPrinterLocation_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetLocation("printer1", "Office").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.SetPrinterLocation("printer1", "Office")) -} - -func TestManager_SetPrinterInfo_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().PrinterSetInfo("printer1", "Main Printer").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.SetPrinterInfo("printer1", "Main Printer")) -} - -func TestManager_AddPrinterToClass_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().ClassAddPrinter("office", "printer1").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.AddPrinterToClass("office", "printer1")) -} - -func TestManager_RemovePrinterFromClass_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().ClassDeletePrinter("office", "printer1").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.RemovePrinterFromClass("office", "printer1")) -} - -func TestManager_DeleteClass_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeleteClass("office").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().ClassDelete("office").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.DeleteClass("office")) -} - -func TestManager_RestartJob_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RestartJob(1).Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().JobRestart(1).Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.RestartJob(1)) -} - -func TestManager_HoldJob_WithPkHelper(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(authErr()) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - mockPk := mocks_pkhelper.NewMockPkHelper(t) - mockPk.EXPECT().JobSetHoldUntil(1, "indefinite").Return(nil) - - m := cups.NewTestManager(mockClient, mockPk) - assert.NoError(t, m.HoldJob(1, "indefinite")) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go deleted file mode 100644 index 70f4f21..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go +++ /dev/null @@ -1,450 +0,0 @@ -package cups - -import ( - "errors" - "testing" - "time" - - mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestManager_GetPrinters(t *testing.T) { - tests := []struct { - name string - mockRet map[string]ipp.Attributes - mockErr error - want int - wantErr bool - }{ - { - name: "success", - mockRet: map[string]ipp.Attributes{ - "printer1": { - ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}}, - ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}}, - ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}}, - ipp.AttributePrinterStateReasons: []ipp.Attribute{{Value: "none"}}, - ipp.AttributePrinterLocation: []ipp.Attribute{{Value: "Office"}}, - ipp.AttributePrinterInfo: []ipp.Attribute{{Value: "Test Printer"}}, - ipp.AttributePrinterMakeAndModel: []ipp.Attribute{{Value: "Generic"}}, - ipp.AttributePrinterIsAcceptingJobs: []ipp.Attribute{{Value: true}}, - }, - }, - mockErr: nil, - want: 1, - wantErr: false, - }, - { - name: "error", - mockRet: nil, - mockErr: errors.New("test error"), - want: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(tt.mockRet, tt.mockErr) - - m := &Manager{ - client: mockClient, - } - - got, err := m.GetPrinters() - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, len(got)) - if len(got) > 0 { - assert.Equal(t, "printer1", got[0].Name) - assert.Equal(t, "idle", got[0].State) - assert.Equal(t, "Office", got[0].Location) - assert.True(t, got[0].Accepting) - } - } - }) - } -} - -func TestManager_GetJobs(t *testing.T) { - tests := []struct { - name string - mockRet map[int]ipp.Attributes - mockErr error - want int - wantErr bool - }{ - { - name: "success", - mockRet: map[int]ipp.Attributes{ - 1: { - ipp.AttributeJobID: []ipp.Attribute{{Value: 1}}, - ipp.AttributeJobName: []ipp.Attribute{{Value: "test-job"}}, - ipp.AttributeJobState: []ipp.Attribute{{Value: 5}}, - ipp.AttributeJobPrinterURI: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}}, - ipp.AttributeJobOriginatingUserName: []ipp.Attribute{{Value: "testuser"}}, - ipp.AttributeJobKilobyteOctets: []ipp.Attribute{{Value: 10}}, - "time-at-creation": []ipp.Attribute{{Value: 1609459200}}, - }, - }, - mockErr: nil, - want: 1, - wantErr: false, - }, - { - name: "error", - mockRet: nil, - mockErr: errors.New("test error"), - want: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything). - Return(tt.mockRet, tt.mockErr) - - m := &Manager{ - client: mockClient, - } - - got, err := m.GetJobs("printer1", "not-completed") - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, len(got)) - if len(got) > 0 { - assert.Equal(t, 1, got[0].ID) - assert.Equal(t, "test-job", got[0].Name) - assert.Equal(t, "processing", got[0].State) - assert.Equal(t, "testuser", got[0].User) - assert.Equal(t, "printer1", got[0].Printer) - assert.Equal(t, 10240, got[0].Size) - assert.Equal(t, time.Unix(1609459200, 0), got[0].TimeCreated) - } - } - }) - } -} - -func TestManager_CancelJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelJob(1, false).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.CancelJob(1)) -} - -func TestManager_PausePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().PausePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.PausePrinter("printer1")) -} - -func TestManager_ResumePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().ResumePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.ResumePrinter("printer1")) -} - -func TestManager_PurgeJobs(t *testing.T) { - tests := []struct { - name string - mockErr error - wantErr bool - }{ - { - name: "success", - mockErr: nil, - wantErr: false, - }, - { - name: "error", - mockErr: errors.New("test error"), - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelAllJob("printer1", true).Return(tt.mockErr) - if !tt.wantErr { - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - } - - m := NewTestManager(mockClient, nil) - - err := m.PurgeJobs("printer1") - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -func TestManager_GetDevices(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetDevices().Return(map[string]ipp.Attributes{ - "usb://HP/LaserJet": { - "device-class": []ipp.Attribute{{Value: "direct"}}, - "device-info": []ipp.Attribute{{Value: "HP LaserJet"}}, - "device-make-and-model": []ipp.Attribute{{Value: "HP LaserJet 1020"}}, - }, - }, nil) - - m := &Manager{client: mockClient} - got, err := m.GetDevices() - assert.NoError(t, err) - assert.Len(t, got, 1) - assert.Equal(t, "usb://HP/LaserJet", got[0].URI) - assert.Equal(t, "direct", got[0].Class) -} - -func TestManager_GetPPDs(t *testing.T) { - tests := []struct { - name string - mockRet map[string]ipp.Attributes - mockErr error - want int - wantErr bool - }{ - { - name: "success", - mockRet: map[string]ipp.Attributes{ - "drv:///sample.drv/generic.ppd": { - "ppd-make-and-model": []ipp.Attribute{{Value: "Generic PostScript"}}, - "ppd-type": []ipp.Attribute{{Value: "ppd"}}, - }, - }, - mockErr: nil, - want: 1, - wantErr: false, - }, - { - name: "error", - mockRet: nil, - mockErr: errors.New("test error"), - want: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetPPDs().Return(tt.mockRet, tt.mockErr) - - m := &Manager{client: mockClient} - - got, err := m.GetPPDs() - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.want, len(got)) - }) - } -} - -func TestManager_GetClasses(t *testing.T) { - tests := []struct { - name string - mockRet map[string]ipp.Attributes - mockErr error - want int - wantErr bool - }{ - { - name: "success", - mockRet: map[string]ipp.Attributes{ - "office": { - ipp.AttributePrinterName: []ipp.Attribute{{Value: "office"}}, - ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}}, - ipp.AttributeMemberNames: []ipp.Attribute{{Value: "printer1"}, {Value: "printer2"}}, - }, - }, - mockErr: nil, - want: 1, - wantErr: false, - }, - { - name: "error", - mockRet: nil, - mockErr: errors.New("test error"), - want: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetClasses(mock.Anything).Return(tt.mockRet, tt.mockErr) - - m := &Manager{client: mockClient} - - got, err := m.GetClasses() - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.want, len(got)) - if len(got) > 0 { - assert.Equal(t, "office", got[0].Name) - assert.Equal(t, 2, len(got[0].Members)) - } - }) - } -} - -func TestManager_CreatePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location").Return(nil) - mockClient.EXPECT().ResumePrinter("newprinter").Return(nil) - mockClient.EXPECT().AcceptJobs("newprinter").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location")) -} - -func TestManager_DeletePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.DeletePrinter("printer1")) -} - -func TestManager_AcceptJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AcceptJobs("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.AcceptJobs("printer1")) -} - -func TestManager_RejectJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RejectJobs("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.RejectJobs("printer1")) -} - -func TestManager_SetPrinterShared(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.SetPrinterShared("printer1", true)) -} - -func TestManager_SetPrinterLocation(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.SetPrinterLocation("printer1", "Office")) -} - -func TestManager_SetPrinterInfo(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.SetPrinterInfo("printer1", "Main Printer")) -} - -func TestManager_MoveJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().MoveJob(1, "printer2").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - err := m.MoveJob(1, "printer2") - assert.NoError(t, err) -} - -func TestManager_PrintTestPage(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().PrintTestPage("printer1", mock.Anything, mock.Anything).Return(42, nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - jobID, err := m.PrintTestPage("printer1") - assert.NoError(t, err) - assert.Equal(t, 42, jobID) -} - -func TestManager_AddPrinterToClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.AddPrinterToClass("office", "printer1")) -} - -func TestManager_RemovePrinterFromClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.RemovePrinterFromClass("office", "printer1")) -} - -func TestManager_DeleteClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeleteClass("office").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.DeleteClass("office")) -} - -func TestManager_RestartJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RestartJob(1).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.RestartJob(1)) -} - -func TestManager_HoldJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - assert.NoError(t, m.HoldJob(1, "indefinite")) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go deleted file mode 100644 index 57b45d5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go +++ /dev/null @@ -1,487 +0,0 @@ -package cups - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -type CUPSEvent struct { - Type string `json:"type"` - Data CUPSState `json:"data"` -} - -type TestPageResult struct { - Success bool `json:"success"` - JobID int `json:"jobId"` - Message string `json:"message"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "cups.subscribe": - handleSubscribe(conn, req, manager) - case "cups.getPrinters": - handleGetPrinters(conn, req, manager) - case "cups.getJobs": - handleGetJobs(conn, req, manager) - case "cups.pausePrinter": - handlePausePrinter(conn, req, manager) - case "cups.resumePrinter": - handleResumePrinter(conn, req, manager) - case "cups.cancelJob": - handleCancelJob(conn, req, manager) - case "cups.purgeJobs": - handlePurgeJobs(conn, req, manager) - case "cups.getDevices": - handleGetDevices(conn, req, manager) - case "cups.getPPDs": - handleGetPPDs(conn, req, manager) - case "cups.getClasses": - handleGetClasses(conn, req, manager) - case "cups.createPrinter": - handleCreatePrinter(conn, req, manager) - case "cups.deletePrinter": - handleDeletePrinter(conn, req, manager) - case "cups.acceptJobs": - handleAcceptJobs(conn, req, manager) - case "cups.rejectJobs": - handleRejectJobs(conn, req, manager) - case "cups.setPrinterShared": - handleSetPrinterShared(conn, req, manager) - case "cups.setPrinterLocation": - handleSetPrinterLocation(conn, req, manager) - case "cups.setPrinterInfo": - handleSetPrinterInfo(conn, req, manager) - case "cups.moveJob": - handleMoveJob(conn, req, manager) - case "cups.printTestPage": - handlePrintTestPage(conn, req, manager) - case "cups.addPrinterToClass": - handleAddPrinterToClass(conn, req, manager) - case "cups.removePrinterFromClass": - handleRemovePrinterFromClass(conn, req, manager) - case "cups.deleteClass": - handleDeleteClass(conn, req, manager) - case "cups.restartJob": - handleRestartJob(conn, req, manager) - case "cups.holdJob": - handleHoldJob(conn, req, manager) - case "cups.testConnection": - handleTestConnection(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetPrinters(conn net.Conn, req models.Request, manager *Manager) { - printers, err := manager.GetPrinters() - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, printers) -} - -func handleGetJobs(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.String(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - jobs, err := manager.GetJobs(printerName, "not-completed") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, jobs) -} - -func handlePausePrinter(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.String(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.PausePrinter(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "paused"}) -} - -func handleResumePrinter(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.String(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.ResumePrinter(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "resumed"}) -} - -func handleCancelJob(conn net.Conn, req models.Request, manager *Manager) { - jobID, err := params.Int(req.Params, "jobID") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.CancelJob(jobID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job canceled"}) -} - -func handlePurgeJobs(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.String(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.PurgeJobs(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "jobs canceled"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - event := CUPSEvent{ - Type: "state_changed", - Data: initialState, - } - - if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - return - } - - for state := range stateChan { - event := CUPSEvent{ - Type: "state_changed", - Data: state, - } - if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{ - Result: &event, - }); err != nil { - return - } - } -} - -func handleGetDevices(conn net.Conn, req models.Request, manager *Manager) { - devices, err := manager.GetDevices() - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, devices) -} - -func handleGetPPDs(conn net.Conn, req models.Request, manager *Manager) { - ppds, err := manager.GetPPDs() - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, ppds) -} - -func handleGetClasses(conn net.Conn, req models.Request, manager *Manager) { - classes, err := manager.GetClasses() - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, classes) -} - -func handleCreatePrinter(conn net.Conn, req models.Request, manager *Manager) { - name, err := params.StringNonEmpty(req.Params, "name") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - deviceURI, err := params.StringNonEmpty(req.Params, "deviceURI") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - ppd, err := params.StringNonEmpty(req.Params, "ppd") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - shared := params.BoolOpt(req.Params, "shared", false) - errorPolicy := params.StringOpt(req.Params, "errorPolicy", "") - information := params.StringOpt(req.Params, "information", "") - location := params.StringOpt(req.Params, "location", "") - - if err := manager.CreatePrinter(name, deviceURI, ppd, shared, errorPolicy, information, location); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer created"}) -} - -func handleDeletePrinter(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.DeletePrinter(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer deleted"}) -} - -func handleAcceptJobs(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.AcceptJobs(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "accepting jobs"}) -} - -func handleRejectJobs(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.RejectJobs(printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "rejecting jobs"}) -} - -func handleSetPrinterShared(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - shared, err := params.Bool(req.Params, "shared") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetPrinterShared(printerName, shared); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "sharing updated"}) -} - -func handleSetPrinterLocation(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - location, err := params.String(req.Params, "location") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetPrinterLocation(printerName, location); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "location updated"}) -} - -func handleSetPrinterInfo(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - info, err := params.String(req.Params, "info") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetPrinterInfo(printerName, info); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "info updated"}) -} - -func handleMoveJob(conn net.Conn, req models.Request, manager *Manager) { - jobID, err := params.Int(req.Params, "jobID") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - destPrinter, err := params.StringNonEmpty(req.Params, "destPrinter") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.MoveJob(jobID, destPrinter); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job moved"}) -} - -func handlePrintTestPage(conn net.Conn, req models.Request, manager *Manager) { - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - jobID, err := manager.PrintTestPage(printerName) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, TestPageResult{Success: true, JobID: jobID, Message: "test page queued"}) -} - -func handleAddPrinterToClass(conn net.Conn, req models.Request, manager *Manager) { - className, err := params.StringNonEmpty(req.Params, "className") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.AddPrinterToClass(className, printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer added to class"}) -} - -func handleRemovePrinterFromClass(conn net.Conn, req models.Request, manager *Manager) { - className, err := params.StringNonEmpty(req.Params, "className") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - printerName, err := params.StringNonEmpty(req.Params, "printerName") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.RemovePrinterFromClass(className, printerName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer removed from class"}) -} - -func handleDeleteClass(conn net.Conn, req models.Request, manager *Manager) { - className, err := params.StringNonEmpty(req.Params, "className") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.DeleteClass(className); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "class deleted"}) -} - -func handleRestartJob(conn net.Conn, req models.Request, manager *Manager) { - jobID, err := params.Int(req.Params, "jobID") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.RestartJob(jobID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job restarted"}) -} - -func handleHoldJob(conn net.Conn, req models.Request, manager *Manager) { - jobID, err := params.Int(req.Params, "jobID") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - holdUntil := params.StringOpt(req.Params, "holdUntil", "indefinite") - - if err := manager.HoldJob(jobID, holdUntil); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job held"}) -} - -func handleTestConnection(conn net.Conn, req models.Request, manager *Manager) { - host, err := params.StringNonEmpty(req.Params, "host") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - port := params.IntOpt(req.Params, "port", 631) - protocol := params.StringOpt(req.Params, "protocol", "ipp") - - result, err := manager.TestRemotePrinter(host, port, protocol) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go deleted file mode 100644 index b73931e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go +++ /dev/null @@ -1,711 +0,0 @@ -package cups - -import ( - "bytes" - "encoding/json" - "errors" - "net" - "testing" - "time" - - mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -type mockConn struct { - *bytes.Buffer -} - -func (m *mockConn) Close() error { return nil } -func (m *mockConn) LocalAddr() net.Addr { return nil } -func (m *mockConn) RemoteAddr() net.Addr { return nil } -func (m *mockConn) SetDeadline(t time.Time) error { return nil } -func (m *mockConn) SetReadDeadline(t time.Time) error { return nil } -func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil } - -func TestHandleGetPrinters(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{ - "printer1": { - ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}}, - ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}}, - ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}}, - }, - }, nil) - - m := &Manager{ - client: mockClient, - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.getPrinters", - } - - handleGetPrinters(conn, req, m) - - var resp models.Response[[]Printer] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.Equal(t, 1, len(*resp.Result)) -} - -func TestHandleGetPrinters_Error(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(nil, errors.New("test error")) - - m := &Manager{ - client: mockClient, - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.getPrinters", - } - - handleGetPrinters(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.Nil(t, resp.Result) - assert.NotNil(t, resp.Error) -} - -func TestHandleGetJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything). - Return(map[int]ipp.Attributes{ - 1: { - ipp.AttributeJobID: []ipp.Attribute{{Value: 1}}, - ipp.AttributeJobName: []ipp.Attribute{{Value: "job1"}}, - ipp.AttributeJobState: []ipp.Attribute{{Value: 5}}, - }, - }, nil) - - m := &Manager{ - client: mockClient, - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.getJobs", - Params: map[string]any{ - "printerName": "printer1", - }, - } - - handleGetJobs(conn, req, m) - - var resp models.Response[[]Job] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.Equal(t, 1, len(*resp.Result)) -} - -func TestHandleGetJobs_MissingParam(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - m := &Manager{ - client: mockClient, - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.getJobs", - Params: map[string]any{}, - } - - handleGetJobs(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.Nil(t, resp.Result) - assert.NotNil(t, resp.Error) -} - -func TestHandlePausePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().PausePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.pausePrinter", - Params: map[string]any{ - "printerName": "printer1", - }, - } - - handlePausePrinter(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleResumePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().ResumePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.resumePrinter", - Params: map[string]any{ - "printerName": "printer1", - }, - } - - handleResumePrinter(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleCancelJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelJob(1, false).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.cancelJob", - Params: map[string]any{ - "jobID": float64(1), - }, - } - - handleCancelJob(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandlePurgeJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CancelAllJob("printer1", true).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.purgeJobs", - Params: map[string]any{ - "printerName": "printer1", - }, - } - - handlePurgeJobs(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleRequest_UnknownMethod(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - m := &Manager{ - client: mockClient, - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.unknownMethod", - } - - HandleRequest(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.Nil(t, resp.Result) - assert.NotNil(t, resp.Error) -} - -func TestHandleGetDevices(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetDevices().Return(map[string]ipp.Attributes{ - "usb://HP/LaserJet": { - "device-class": []ipp.Attribute{{Value: "direct"}}, - "device-info": []ipp.Attribute{{Value: "HP LaserJet"}}, - }, - }, nil) - - m := &Manager{client: mockClient} - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ID: 1, Method: "cups.getDevices"} - handleGetDevices(conn, req, m) - - var resp models.Response[[]Device] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.Equal(t, 1, len(*resp.Result)) -} - -func TestHandleGetPPDs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetPPDs().Return(map[string]ipp.Attributes{ - "generic.ppd": { - "ppd-make-and-model": []ipp.Attribute{{Value: "Generic"}}, - }, - }, nil) - - m := &Manager{client: mockClient} - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ID: 1, Method: "cups.getPPDs"} - handleGetPPDs(conn, req, m) - - var resp models.Response[[]PPD] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.Equal(t, 1, len(*resp.Result)) -} - -func TestHandleGetClasses(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().GetClasses(mock.Anything).Return(map[string]ipp.Attributes{ - "office": { - ipp.AttributePrinterName: []ipp.Attribute{{Value: "office"}}, - ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}}, - }, - }, nil) - - m := &Manager{client: mockClient} - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ID: 1, Method: "cups.getClasses"} - handleGetClasses(conn, req, m) - - var resp models.Response[[]PrinterClass] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.Equal(t, 1, len(*resp.Result)) -} - -func TestHandleCreatePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", false, "", "", "").Return(nil) - mockClient.EXPECT().ResumePrinter("newprinter").Return(nil) - mockClient.EXPECT().AcceptJobs("newprinter").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.createPrinter", - Params: map[string]any{ - "name": "newprinter", - "deviceURI": "usb://HP", - "ppd": "generic.ppd", - }, - } - handleCreatePrinter(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleCreatePrinter_MissingParams(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - m := &Manager{client: mockClient} - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ID: 1, Method: "cups.createPrinter", Params: map[string]any{}} - handleCreatePrinter(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.Nil(t, resp.Result) - assert.NotNil(t, resp.Error) -} - -func TestHandleDeletePrinter(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinter("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.deletePrinter", - Params: map[string]any{"printerName": "printer1"}, - } - handleDeletePrinter(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleAcceptJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AcceptJobs("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.acceptJobs", - Params: map[string]any{"printerName": "printer1"}, - } - handleAcceptJobs(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleRejectJobs(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RejectJobs("printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.rejectJobs", - Params: map[string]any{"printerName": "printer1"}, - } - handleRejectJobs(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleSetPrinterShared(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.setPrinterShared", - Params: map[string]any{"printerName": "printer1", "shared": true}, - } - handleSetPrinterShared(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleSetPrinterLocation(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.setPrinterLocation", - Params: map[string]any{"printerName": "printer1", "location": "Office"}, - } - handleSetPrinterLocation(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleSetPrinterInfo(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.setPrinterInfo", - Params: map[string]any{"printerName": "printer1", "info": "Main Printer"}, - } - handleSetPrinterInfo(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleMoveJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().MoveJob(1, "printer2").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.moveJob", - Params: map[string]any{"jobID": float64(1), "destPrinter": "printer2"}, - } - handleMoveJob(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandlePrintTestPage(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().PrintTestPage("printer1", mock.Anything, mock.Anything).Return(42, nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.printTestPage", - Params: map[string]any{"printerName": "printer1"}, - } - handlePrintTestPage(conn, req, m) - - var resp models.Response[TestPageResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, 42, resp.Result.JobID) -} - -func TestHandleAddPrinterToClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.addPrinterToClass", - Params: map[string]any{"className": "office", "printerName": "printer1"}, - } - handleAddPrinterToClass(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleRemovePrinterFromClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.removePrinterFromClass", - Params: map[string]any{"className": "office", "printerName": "printer1"}, - } - handleRemovePrinterFromClass(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleDeleteClass(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().DeleteClass("office").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.deleteClass", - Params: map[string]any{"className": "office"}, - } - handleDeleteClass(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleRestartJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().RestartJob(1).Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.restartJob", - Params: map[string]any{"jobID": float64(1)}, - } - handleRestartJob(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleHoldJob(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.holdJob", - Params: map[string]any{"jobID": float64(1)}, - } - handleHoldJob(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} - -func TestHandleHoldJob_WithHoldUntil(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - mockClient.EXPECT().HoldJobUntil(1, "no-hold").Return(nil) - mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil) - - m := NewTestManager(mockClient, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.holdJob", - Params: map[string]any{"jobID": float64(1), "holdUntil": "no-hold"}, - } - handleHoldJob(conn, req, m) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager.go deleted file mode 100644 index e5b7e8c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager.go +++ /dev/null @@ -1,390 +0,0 @@ -package cups - -import ( - "errors" - "fmt" - "os" - "strconv" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" -) - -func NewManager() (*Manager, error) { - host := os.Getenv("DMS_IPP_HOST") - if host == "" { - host = "localhost" - } - - portStr := os.Getenv("DMS_IPP_PORT") - port := 631 - if portStr != "" { - if p, err := strconv.Atoi(portStr); err == nil { - port = p - } - } - - username := os.Getenv("DMS_IPP_USERNAME") - password := os.Getenv("DMS_IPP_PASSWORD") - - client := ipp.NewCUPSClient(host, port, username, password, false) - baseURL := fmt.Sprintf("http://%s:%d", host, port) - - var pkHelper PkHelper - if isLocalCUPS(host) { - var err error - pkHelper, err = NewPkHelper() - if err != nil { - log.Warnf("[CUPS] Failed to initialize pkhelper: %v", err) - } - } - - m := &Manager{ - state: &CUPSState{ - Printers: make(map[string]*Printer), - }, - client: client, - pkHelper: pkHelper, - baseURL: baseURL, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - if err := m.updateState(); err != nil { - return nil, err - } - - if isLocalCUPS(host) { - m.subscription = NewDBusSubscriptionManager(client, baseURL) - log.Infof("[CUPS] Using D-Bus notifications for local CUPS") - } else { - m.subscription = NewSubscriptionManager(client, baseURL) - log.Infof("[CUPS] Using IPPGET notifications for remote CUPS") - } - - m.notifierWg.Add(1) - go m.notifier() - - return m, nil -} - -func isLocalCUPS(host string) bool { - switch host { - case "localhost", "127.0.0.1", "::1", "": - return true - } - return false -} - -func (m *Manager) eventHandler() { - defer m.eventWG.Done() - - if m.subscription == nil { - return - } - - for { - select { - case <-m.stopChan: - return - case event, ok := <-m.subscription.Events(): - if !ok { - return - } - log.Debugf("[CUPS] Received event: %s (printer: %s, job: %d)", - event.EventName, event.PrinterName, event.JobID) - - if err := m.updateState(); err != nil { - log.Warnf("[CUPS] Failed to update state after event: %v", err) - } else { - m.notifySubscribers() - } - } - } -} - -func (m *Manager) updateState() error { - printers, err := m.GetPrinters() - if err != nil { - if isNoPrintersError(err) { - m.stateMutex.Lock() - m.state.Printers = make(map[string]*Printer) - m.stateMutex.Unlock() - return nil - } - return err - } - - printerMap := make(map[string]*Printer, len(printers)) - for _, printer := range printers { - jobs, err := m.GetJobs(printer.Name, "not-completed") - if err != nil { - return err - } - - printer.Jobs = jobs - printerMap[printer.Name] = &printer - } - - m.stateMutex.Lock() - m.state.Printers = printerMap - m.stateMutex.Unlock() - - return nil -} - -func isNoPrintersError(err error) bool { - if err == nil { - return false - } - - var ippErr ipp.IPPError - if errors.As(err, &ippErr) { - return ippErr.Status == 1030 - } - - return false -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.snapshotState() - - if m.lastNotifiedState != nil && !stateChanged(m.lastNotifiedState, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - select { - case ch <- currentState: - default: - } - return true - }) - - stateCopy := currentState - m.lastNotifiedState = &stateCopy - pending = false - } - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) RefreshState() { - if err := m.updateState(); err != nil { - log.Warnf("[CUPS] Failed to refresh state: %v", err) - return - } - m.notifySubscribers() -} - -func (m *Manager) GetState() CUPSState { - return m.snapshotState() -} - -func (m *Manager) snapshotState() CUPSState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - - s := CUPSState{ - Printers: make(map[string]*Printer, len(m.state.Printers)), - } - for name, printer := range m.state.Printers { - printerCopy := *printer - s.Printers[name] = &printerCopy - } - return s -} - -func (m *Manager) Subscribe(id string) chan CUPSState { - ch := make(chan CUPSState, 64) - - wasEmpty := true - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - wasEmpty = false - return false - }) - - m.subscribers.Store(id, ch) - - if wasEmpty && m.subscription != nil { - if err := m.subscription.Start(); err != nil { - log.Warnf("[CUPS] Failed to start subscription manager: %v", err) - } else { - m.eventWG.Add(1) - go m.eventHandler() - } - } - - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } - - isEmpty := true - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - isEmpty = false - return false - }) - - if isEmpty && m.subscription != nil { - m.subscription.Stop() - m.eventWG.Wait() - } -} - -func (m *Manager) Close() { - close(m.stopChan) - - if m.subscription != nil { - m.subscription.Stop() - } - - m.eventWG.Wait() - m.notifierWg.Wait() - - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) -} - -func stateChanged(old, new *CUPSState) bool { - if len(old.Printers) != len(new.Printers) { - return true - } - for name, oldPrinter := range old.Printers { - newPrinter, exists := new.Printers[name] - if !exists { - return true - } - if oldPrinter.State != newPrinter.State || - oldPrinter.StateReason != newPrinter.StateReason || - oldPrinter.Accepting != newPrinter.Accepting || - len(oldPrinter.Jobs) != len(newPrinter.Jobs) { - return true - } - } - return false -} - -func parsePrinterState(attrs ipp.Attributes) string { - if stateAttr, ok := attrs[ipp.AttributePrinterState]; ok && len(stateAttr) > 0 { - if state, ok := stateAttr[0].Value.(int); ok { - switch state { - case 3: - return "idle" - case 4: - return "processing" - case 5: - return "stopped" - default: - return fmt.Sprintf("%d", state) - } - } - } - return "unknown" -} - -func parseJobState(attrs ipp.Attributes) string { - if stateAttr, ok := attrs[ipp.AttributeJobState]; ok && len(stateAttr) > 0 { - if state, ok := stateAttr[0].Value.(int); ok { - switch state { - case 3: - return "pending" - case 4: - return "pending-held" - case 5: - return "processing" - case 6: - return "processing-stopped" - case 7: - return "canceled" - case 8: - return "aborted" - case 9: - return "completed" - default: - return fmt.Sprintf("%d", state) - } - } - } - return "unknown" -} - -func getStringAttr(attrs ipp.Attributes, key string) string { - if attr, ok := attrs[key]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(string); ok { - return val - } - return fmt.Sprintf("%v", attr[0].Value) - } - return "" -} - -func getIntAttr(attrs ipp.Attributes, key string) int { - if attr, ok := attrs[key]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(int); ok { - return val - } - } - return 0 -} - -func getBoolAttr(attrs ipp.Attributes, key string) bool { - if attr, ok := attrs[key]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(bool); ok { - return val - } - } - return false -} - -func getStringSliceAttr(attrs ipp.Attributes, key string) []string { - attr, ok := attrs[key] - if !ok { - return nil - } - - result := make([]string, 0, len(attr)) - for _, a := range attr { - if val, ok := a.Value.(string); ok { - result = append(result, val) - } - } - return result -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go deleted file mode 100644 index 7f09e67..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go +++ /dev/null @@ -1,363 +0,0 @@ -package cups - -import ( - "testing" - - mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/stretchr/testify/assert" -) - -func TestNewManager(t *testing.T) { - m := &Manager{ - state: &CUPSState{ - Printers: make(map[string]*Printer), - }, - client: nil, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - assert.NotNil(t, m) - assert.NotNil(t, m.state) -} - -func TestManager_GetState(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - m := &Manager{ - state: &CUPSState{ - Printers: map[string]*Printer{ - "test-printer": { - Name: "test-printer", - State: "idle", - }, - }, - }, - client: mockClient, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - state := m.GetState() - assert.Equal(t, 1, len(state.Printers)) - assert.Equal(t, "test-printer", state.Printers["test-printer"].Name) -} - -func TestManager_Subscribe(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - m := &Manager{ - state: &CUPSState{ - Printers: make(map[string]*Printer), - }, - client: mockClient, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - ch := m.Subscribe("test-client") - assert.NotNil(t, ch) - - count := 0 - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - count++ - return true - }) - assert.Equal(t, 1, count) - - m.Unsubscribe("test-client") - count = 0 - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - count++ - return true - }) - assert.Equal(t, 0, count) -} - -func TestManager_Close(t *testing.T) { - mockClient := mocks_cups.NewMockCUPSClientInterface(t) - - m := &Manager{ - state: &CUPSState{ - Printers: make(map[string]*Printer), - }, - client: mockClient, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - m.eventWG.Add(1) - go func() { - defer m.eventWG.Done() - <-m.stopChan - }() - - m.notifierWg.Add(1) - go func() { - defer m.notifierWg.Done() - <-m.stopChan - }() - - m.Close() - count := 0 - m.subscribers.Range(func(key string, ch chan CUPSState) bool { - count++ - return true - }) - assert.Equal(t, 0, count) -} - -func TestStateChanged(t *testing.T) { - tests := []struct { - name string - oldState *CUPSState - newState *CUPSState - want bool - }{ - { - name: "no change", - oldState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "idle"}, - }, - }, - newState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "idle"}, - }, - }, - want: false, - }, - { - name: "state changed", - oldState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "idle"}, - }, - }, - newState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "processing"}, - }, - }, - want: true, - }, - { - name: "printer added", - oldState: &CUPSState{ - Printers: map[string]*Printer{}, - }, - newState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "idle"}, - }, - }, - want: true, - }, - { - name: "printer removed", - oldState: &CUPSState{ - Printers: map[string]*Printer{ - "p1": {Name: "p1", State: "idle"}, - }, - }, - newState: &CUPSState{ - Printers: map[string]*Printer{}, - }, - want: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := stateChanged(tt.oldState, tt.newState) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestParsePrinterState(t *testing.T) { - tests := []struct { - name string - attrs ipp.Attributes - want string - }{ - { - name: "idle", - attrs: ipp.Attributes{ - ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}}, - }, - want: "idle", - }, - { - name: "processing", - attrs: ipp.Attributes{ - ipp.AttributePrinterState: []ipp.Attribute{{Value: 4}}, - }, - want: "processing", - }, - { - name: "stopped", - attrs: ipp.Attributes{ - ipp.AttributePrinterState: []ipp.Attribute{{Value: 5}}, - }, - want: "stopped", - }, - { - name: "unknown", - attrs: ipp.Attributes{}, - want: "unknown", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := parsePrinterState(tt.attrs) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestParseJobState(t *testing.T) { - tests := []struct { - name string - attrs ipp.Attributes - want string - }{ - { - name: "pending", - attrs: ipp.Attributes{ - ipp.AttributeJobState: []ipp.Attribute{{Value: 3}}, - }, - want: "pending", - }, - { - name: "processing", - attrs: ipp.Attributes{ - ipp.AttributeJobState: []ipp.Attribute{{Value: 5}}, - }, - want: "processing", - }, - { - name: "completed", - attrs: ipp.Attributes{ - ipp.AttributeJobState: []ipp.Attribute{{Value: 9}}, - }, - want: "completed", - }, - { - name: "unknown", - attrs: ipp.Attributes{}, - want: "unknown", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := parseJobState(tt.attrs) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestGetStringAttr(t *testing.T) { - tests := []struct { - name string - attrs ipp.Attributes - key string - want string - }{ - { - name: "string value", - attrs: ipp.Attributes{ - "test-key": []ipp.Attribute{{Value: "test-value"}}, - }, - key: "test-key", - want: "test-value", - }, - { - name: "missing key", - attrs: ipp.Attributes{}, - key: "missing", - want: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := getStringAttr(tt.attrs, tt.key) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestGetIntAttr(t *testing.T) { - tests := []struct { - name string - attrs ipp.Attributes - key string - want int - }{ - { - name: "int value", - attrs: ipp.Attributes{ - "test-key": []ipp.Attribute{{Value: 42}}, - }, - key: "test-key", - want: 42, - }, - { - name: "missing key", - attrs: ipp.Attributes{}, - key: "missing", - want: 0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := getIntAttr(tt.attrs, tt.key) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestGetBoolAttr(t *testing.T) { - tests := []struct { - name string - attrs ipp.Attributes - key string - want bool - }{ - { - name: "true value", - attrs: ipp.Attributes{ - "test-key": []ipp.Attribute{{Value: true}}, - }, - key: "test-key", - want: true, - }, - { - name: "false value", - attrs: ipp.Attributes{ - "test-key": []ipp.Attribute{{Value: false}}, - }, - key: "test-key", - want: false, - }, - { - name: "missing key", - attrs: ipp.Attributes{}, - key: "missing", - want: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := getBoolAttr(tt.attrs, tt.key) - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go deleted file mode 100644 index 81dd458..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go +++ /dev/null @@ -1,184 +0,0 @@ -package cups - -import ( - "fmt" - "strings" - - "github.com/godbus/dbus/v5" -) - -const ( - pkHelperDest = "org.opensuse.CupsPkHelper.Mechanism" - pkHelperPath = "/" - pkHelperInterface = "org.opensuse.CupsPkHelper.Mechanism" -) - -type PkHelper interface { - DevicesGet(timeout, limit int, includeSchemes, excludeSchemes []string) ([]Device, error) - PrinterAdd(name, uri, ppd, info, location string) error - PrinterDelete(name string) error - PrinterSetEnabled(name string, enabled bool) error - PrinterSetAcceptJobs(name string, enabled bool, reason string) error - PrinterSetInfo(name, info string) error - PrinterSetLocation(name, location string) error - PrinterSetShared(name string, shared bool) error - ClassAddPrinter(className, printerName string) error - ClassDeletePrinter(className, printerName string) error - ClassDelete(className string) error - JobCancelPurge(jobID int, purge bool) error - JobRestart(jobID int) error - JobSetHoldUntil(jobID int, holdUntil string) error -} - -type DBusPkHelper struct { - conn *dbus.Conn - obj dbus.BusObject -} - -func NewPkHelper() (*DBusPkHelper, error) { - conn, err := dbus.SystemBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to system bus: %w", err) - } - - return &DBusPkHelper{ - conn: conn, - obj: conn.Object(pkHelperDest, pkHelperPath), - }, nil -} - -func (p *DBusPkHelper) DevicesGet(timeout, limit int, includeSchemes, excludeSchemes []string) ([]Device, error) { - if includeSchemes == nil { - includeSchemes = []string{} - } - if excludeSchemes == nil { - excludeSchemes = []string{} - } - - var errStr string - var devicesMap map[string]string - - call := p.obj.Call(pkHelperInterface+".DevicesGet", 0, int32(timeout), int32(limit), includeSchemes, excludeSchemes) - if call.Err != nil { - return nil, call.Err - } - if err := call.Store(&errStr, &devicesMap); err != nil { - return nil, err - } - if errStr != "" { - return nil, fmt.Errorf("%s", errStr) - } - - return parseDevicesMap(devicesMap), nil -} - -func parseDevicesMap(devicesMap map[string]string) []Device { - devicesByIndex := make(map[string]*Device) - - for key, value := range devicesMap { - idx := strings.LastIndex(key, ":") - if idx == -1 { - continue - } - - attr := key[:idx] - index := key[idx+1:] - - dev, ok := devicesByIndex[index] - if !ok { - dev = &Device{} - devicesByIndex[index] = dev - } - - switch attr { - case "device-uri": - dev.URI = value - case "device-class": - dev.Class = value - case "device-info": - dev.Info = value - case "device-make-and-model": - dev.MakeModel = value - case "device-id": - dev.ID = value - case "device-location": - dev.Location = value - } - } - - devices := make([]Device, 0, len(devicesByIndex)) - for _, dev := range devicesByIndex { - if dev.URI != "" { - devices = append(devices, *dev) - } - } - return devices -} - -func (p *DBusPkHelper) PrinterAdd(name, uri, ppd, info, location string) error { - return p.callSimple("PrinterAdd", name, uri, ppd, info, location) -} - -func (p *DBusPkHelper) PrinterDelete(name string) error { - return p.callSimple("PrinterDelete", name) -} - -func (p *DBusPkHelper) PrinterSetEnabled(name string, enabled bool) error { - return p.callSimple("PrinterSetEnabled", name, enabled) -} - -func (p *DBusPkHelper) PrinterSetAcceptJobs(name string, enabled bool, reason string) error { - return p.callSimple("PrinterSetAcceptJobs", name, enabled, reason) -} - -func (p *DBusPkHelper) PrinterSetInfo(name, info string) error { - return p.callSimple("PrinterSetInfo", name, info) -} - -func (p *DBusPkHelper) PrinterSetLocation(name, location string) error { - return p.callSimple("PrinterSetLocation", name, location) -} - -func (p *DBusPkHelper) PrinterSetShared(name string, shared bool) error { - return p.callSimple("PrinterSetShared", name, shared) -} - -func (p *DBusPkHelper) ClassAddPrinter(className, printerName string) error { - return p.callSimple("ClassAddPrinter", className, printerName) -} - -func (p *DBusPkHelper) ClassDeletePrinter(className, printerName string) error { - return p.callSimple("ClassDeletePrinter", className, printerName) -} - -func (p *DBusPkHelper) ClassDelete(className string) error { - return p.callSimple("ClassDelete", className) -} - -func (p *DBusPkHelper) JobCancelPurge(jobID int, purge bool) error { - return p.callSimple("JobCancelPurge", int32(jobID), purge) -} - -func (p *DBusPkHelper) JobRestart(jobID int) error { - return p.callSimple("JobRestart", int32(jobID)) -} - -func (p *DBusPkHelper) JobSetHoldUntil(jobID int, holdUntil string) error { - return p.callSimple("JobSetHoldUntil", int32(jobID), holdUntil) -} - -func (p *DBusPkHelper) callSimple(method string, args ...any) error { - var errStr string - - call := p.obj.Call(pkHelperInterface+"."+method, 0, args...) - if call.Err != nil { - return call.Err - } - if err := call.Store(&errStr); err != nil { - return err - } - if errStr != "" { - return fmt.Errorf("%s", errStr) - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go deleted file mode 100644 index 596f1d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package cups - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParseDevicesMap(t *testing.T) { - tests := []struct { - name string - input map[string]string - wantLen int - wantURIs []string - }{ - { - name: "empty", - input: map[string]string{}, - wantLen: 0, - wantURIs: nil, - }, - { - name: "single_device", - input: map[string]string{ - "device-uri:0": "usb://HP/LaserJet", - "device-class:0": "direct", - "device-info:0": "HP LaserJet", - "device-make-and-model:0": "HP LaserJet 1020", - "device-id:0": "MFG:HP;MDL:LaserJet", - }, - wantLen: 1, - wantURIs: []string{"usb://HP/LaserJet"}, - }, - { - name: "multiple_devices", - input: map[string]string{ - "device-uri:0": "usb://HP/LaserJet", - "device-class:0": "direct", - "device-info:0": "HP LaserJet", - "device-uri:1": "socket://192.168.1.100", - "device-class:1": "network", - "device-info:1": "Network Printer", - }, - wantLen: 2, - wantURIs: []string{"usb://HP/LaserJet", "socket://192.168.1.100"}, - }, - { - name: "malformed_key", - input: map[string]string{ - "no-colon-here": "value", - }, - wantLen: 0, - wantURIs: nil, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := parseDevicesMap(tt.input) - assert.Len(t, got, tt.wantLen) - - if tt.wantURIs != nil { - gotURIs := make(map[string]bool) - for _, d := range got { - gotURIs[d.URI] = true - } - for _, uri := range tt.wantURIs { - assert.True(t, gotURIs[uri], "expected URI %s not found", uri) - } - } - }) - } -} - -func TestParseDevicesMap_Attributes(t *testing.T) { - input := map[string]string{ - "device-uri:0": "usb://HP/LaserJet", - "device-class:0": "direct", - "device-info:0": "HP LaserJet", - "device-make-and-model:0": "HP LaserJet 1020", - "device-id:0": "MFG:HP;MDL:LaserJet", - "device-location:0": "USB Port", - } - - got := parseDevicesMap(input) - assert.Len(t, got, 1) - - dev := got[0] - assert.Equal(t, "usb://HP/LaserJet", dev.URI) - assert.Equal(t, "direct", dev.Class) - assert.Equal(t, "HP LaserJet", dev.Info) - assert.Equal(t, "HP LaserJet 1020", dev.MakeModel) - assert.Equal(t, "MFG:HP;MDL:LaserJet", dev.ID) - assert.Equal(t, "USB Port", dev.Location) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go deleted file mode 100644 index 6b369b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go +++ /dev/null @@ -1,245 +0,0 @@ -package cups - -import ( - "fmt" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" -) - -type SubscriptionManager struct { - client CUPSClientInterface - subscriptionID int - sequenceNumber int - eventChan chan SubscriptionEvent - stopChan chan struct{} - wg sync.WaitGroup - baseURL string - running bool - mu sync.Mutex -} - -func NewSubscriptionManager(client CUPSClientInterface, baseURL string) *SubscriptionManager { - return &SubscriptionManager{ - client: client, - eventChan: make(chan SubscriptionEvent, 100), - stopChan: make(chan struct{}), - baseURL: baseURL, - } -} - -func (sm *SubscriptionManager) Start() error { - sm.mu.Lock() - if sm.running { - sm.mu.Unlock() - return fmt.Errorf("subscription manager already running") - } - sm.running = true - sm.mu.Unlock() - - subID, err := sm.createSubscription() - if err != nil { - sm.mu.Lock() - sm.running = false - sm.mu.Unlock() - return fmt.Errorf("failed to create subscription: %w", err) - } - - sm.subscriptionID = subID - log.Infof("[CUPS] Created IPP subscription with ID %d", subID) - - sm.wg.Add(1) - go sm.notificationLoop() - - return nil -} - -func (sm *SubscriptionManager) createSubscription() (int, error) { - req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 1) - req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL) - req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms" - - // Subscription attributes go in SubscriptionAttributes (subscription-attributes-tag in IPP) - req.SubscriptionAttributes = map[string]any{ - "notify-events": []string{ - "printer-state-changed", - "printer-added", - "printer-deleted", - "job-created", - "job-completed", - "job-state-changed", - }, - "notify-pull-method": "ippget", - "notify-lease-duration": 0, - } - - // Send to root IPP endpoint - resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil) - if err != nil { - return 0, fmt.Errorf("SendRequest failed: %w", err) - } - - // Check for IPP errors - if err := resp.CheckForErrors(); err != nil { - return 0, fmt.Errorf("IPP error: %w", err) - } - - // Subscription ID comes back in SubscriptionAttributes - if len(resp.SubscriptionAttributes) > 0 { - if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 { - if val, ok := idAttr[0].Value.(int); ok { - return val, nil - } - } - } - - return 0, fmt.Errorf("no subscription ID returned") -} - -func (sm *SubscriptionManager) notificationLoop() { - defer sm.wg.Done() - - backoff := 1 * time.Second - - for { - select { - case <-sm.stopChan: - return - default: - } - - gotAny, err := sm.fetchNotificationsWithWait() - if err != nil { - log.Warnf("[CUPS] Error fetching notifications: %v", err) - jitter := time.Duration(50+(time.Now().UnixNano()%200)) * time.Millisecond - sleepTime := backoff + jitter - if sleepTime > 30*time.Second { - sleepTime = 30 * time.Second - } - select { - case <-sm.stopChan: - return - case <-time.After(sleepTime): - } - if backoff < 30*time.Second { - backoff *= 2 - } - continue - } - - backoff = 1 * time.Second - - if gotAny { - continue - } - - select { - case <-sm.stopChan: - return - case <-time.After(2 * time.Second): - } - } -} - -func (sm *SubscriptionManager) fetchNotificationsWithWait() (bool, error) { - req := ipp.NewRequest(ipp.OperationGetNotifications, 1) - req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL) - req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms" - req.OperationAttributes["notify-subscription-ids"] = sm.subscriptionID - if sm.sequenceNumber > 0 { - req.OperationAttributes["notify-sequence-numbers"] = sm.sequenceNumber - } - - resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil) - if err != nil { - return false, err - } - - gotAny := false - for _, eventGroup := range resp.SubscriptionAttributes { - if seqAttr, ok := eventGroup["notify-sequence-number"]; ok && len(seqAttr) > 0 { - if seqNum, ok := seqAttr[0].Value.(int); ok { - sm.sequenceNumber = seqNum + 1 - } - } - - event := sm.parseEvent(eventGroup) - gotAny = true - select { - case sm.eventChan <- event: - case <-sm.stopChan: - return gotAny, nil - default: - log.Warn("[CUPS] Event channel full, dropping event") - } - } - - return gotAny, nil -} - -func (sm *SubscriptionManager) parseEvent(attrs ipp.Attributes) SubscriptionEvent { - event := SubscriptionEvent{ - SubscribedAt: time.Now(), - } - - if attr, ok := attrs["notify-subscribed-event"]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(string); ok { - event.EventName = val - } - } - - if attr, ok := attrs["printer-name"]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(string); ok { - event.PrinterName = val - } - } - - if attr, ok := attrs["notify-job-id"]; ok && len(attr) > 0 { - if val, ok := attr[0].Value.(int); ok { - event.JobID = val - } - } - - return event -} - -func (sm *SubscriptionManager) Events() <-chan SubscriptionEvent { - return sm.eventChan -} - -func (sm *SubscriptionManager) Stop() { - sm.mu.Lock() - if !sm.running { - sm.mu.Unlock() - return - } - sm.running = false - sm.mu.Unlock() - - close(sm.stopChan) - sm.wg.Wait() - - if sm.subscriptionID != 0 { - sm.cancelSubscription() - sm.subscriptionID = 0 - sm.sequenceNumber = 0 - } - - sm.stopChan = make(chan struct{}) -} - -func (sm *SubscriptionManager) cancelSubscription() { - req := ipp.NewRequest(ipp.OperationCancelSubscription, 1) - req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL) - req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms" - req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID - - _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil) - if err != nil { - log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err) - } else { - log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go deleted file mode 100644 index b205a6b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go +++ /dev/null @@ -1,295 +0,0 @@ -package cups - -import ( - "fmt" - "strings" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/godbus/dbus/v5" -) - -type DBusSubscriptionManager struct { - client CUPSClientInterface - subscriptionID int - eventChan chan SubscriptionEvent - stopChan chan struct{} - wg sync.WaitGroup - baseURL string - running bool - mu sync.Mutex - conn *dbus.Conn -} - -func NewDBusSubscriptionManager(client CUPSClientInterface, baseURL string) *DBusSubscriptionManager { - return &DBusSubscriptionManager{ - client: client, - eventChan: make(chan SubscriptionEvent, 100), - stopChan: make(chan struct{}), - baseURL: baseURL, - } -} - -func (sm *DBusSubscriptionManager) Start() error { - sm.mu.Lock() - if sm.running { - sm.mu.Unlock() - return fmt.Errorf("subscription manager already running") - } - sm.running = true - sm.mu.Unlock() - - conn, err := dbus.ConnectSystemBus() - if err != nil { - sm.mu.Lock() - sm.running = false - sm.mu.Unlock() - return fmt.Errorf("connect to system bus: %w", err) - } - sm.conn = conn - - subID, err := sm.createDBusSubscription() - if err != nil { - sm.conn.Close() - sm.mu.Lock() - sm.running = false - sm.mu.Unlock() - return fmt.Errorf("failed to create D-Bus subscription: %w", err) - } - - sm.subscriptionID = subID - log.Infof("[CUPS] Created D-Bus subscription with ID %d", subID) - - if err := sm.conn.AddMatchSignal( - dbus.WithMatchInterface("org.cups.cupsd.Notifier"), - ); err != nil { - sm.cancelSubscription() - sm.conn.Close() - sm.mu.Lock() - sm.running = false - sm.mu.Unlock() - return fmt.Errorf("failed to add D-Bus match: %w", err) - } - - sm.wg.Add(1) - go sm.dbusListenerLoop() - - return nil -} - -func (sm *DBusSubscriptionManager) createDBusSubscription() (int, error) { - req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 2) - req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL) - req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms" - - req.SubscriptionAttributes = map[string]any{ - "notify-events": []string{ - "printer-state-changed", - "printer-added", - "printer-deleted", - "job-created", - "job-completed", - "job-state-changed", - }, - "notify-recipient-uri": "dbus:/", - "notify-lease-duration": 86400, - } - - resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil) - if err != nil { - return 0, fmt.Errorf("SendRequest failed: %w", err) - } - - if err := resp.CheckForErrors(); err != nil { - return 0, fmt.Errorf("IPP error: %w", err) - } - - if len(resp.SubscriptionAttributes) > 0 { - if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 { - if val, ok := idAttr[0].Value.(int); ok { - return val, nil - } - } - } - - return 0, fmt.Errorf("no subscription ID returned") -} - -func (sm *DBusSubscriptionManager) dbusListenerLoop() { - defer sm.wg.Done() - - signalChan := make(chan *dbus.Signal, 10) - sm.conn.Signal(signalChan) - defer sm.conn.RemoveSignal(signalChan) - - for { - select { - case <-sm.stopChan: - return - case sig := <-signalChan: - if sig == nil { - continue - } - - event := sm.parseDBusSignal(sig) - if event.EventName == "" { - continue - } - - select { - case sm.eventChan <- event: - case <-sm.stopChan: - return - default: - log.Warn("[CUPS] Event channel full, dropping event") - } - } - } -} - -func (sm *DBusSubscriptionManager) parseDBusSignal(sig *dbus.Signal) SubscriptionEvent { - event := SubscriptionEvent{} - - switch sig.Name { - case "org.cups.cupsd.Notifier.JobStateChanged": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "job-state-changed" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" { - if idx := strings.LastIndex(printerURI, "/"); idx != -1 { - event.PrinterName = printerURI[idx+1:] - } - } - if jobID, ok := sig.Body[3].(uint32); ok { - event.JobID = int(jobID) - } - } - - case "org.cups.cupsd.Notifier.JobCreated": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "job-created" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" { - if idx := strings.LastIndex(printerURI, "/"); idx != -1 { - event.PrinterName = printerURI[idx+1:] - } - } - if jobID, ok := sig.Body[3].(uint32); ok { - event.JobID = int(jobID) - } - } - - case "org.cups.cupsd.Notifier.JobCompleted": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "job-completed" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" { - if idx := strings.LastIndex(printerURI, "/"); idx != -1 { - event.PrinterName = printerURI[idx+1:] - } - } - if jobID, ok := sig.Body[3].(uint32); ok { - event.JobID = int(jobID) - } - } - - case "org.cups.cupsd.Notifier.PrinterStateChanged": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "printer-state-changed" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" { - if idx := strings.LastIndex(printerURI, "/"); idx != -1 { - event.PrinterName = printerURI[idx+1:] - } - } - } - - case "org.cups.cupsd.Notifier.PrinterAdded": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "printer-added" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - } - - case "org.cups.cupsd.Notifier.PrinterDeleted": - if len(sig.Body) >= 6 { - if text, ok := sig.Body[0].(string); ok { - event.EventName = "printer-deleted" - parts := strings.Split(text, " ") - if len(parts) >= 2 { - event.PrinterName = parts[0] - } - } - } - } - - return event -} - -func (sm *DBusSubscriptionManager) Events() <-chan SubscriptionEvent { - return sm.eventChan -} - -func (sm *DBusSubscriptionManager) Stop() { - sm.mu.Lock() - if !sm.running { - sm.mu.Unlock() - return - } - sm.running = false - sm.mu.Unlock() - - close(sm.stopChan) - sm.wg.Wait() - - if sm.subscriptionID != 0 { - sm.cancelSubscription() - sm.subscriptionID = 0 - } - - if sm.conn != nil { - sm.conn.Close() - sm.conn = nil - } - - sm.stopChan = make(chan struct{}) -} - -func (sm *DBusSubscriptionManager) cancelSubscription() { - req := ipp.NewRequest(ipp.OperationCancelSubscription, 1) - req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL) - req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms" - req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID - - _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil) - if err != nil { - log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err) - } else { - log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go deleted file mode 100644 index d0203e9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go +++ /dev/null @@ -1,176 +0,0 @@ -package cups - -import ( - "errors" - "fmt" - "net" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" -) - -var validProtocols = map[string]bool{ - "ipp": true, - "ipps": true, - "lpd": true, - "socket": true, -} - -func validateTestConnectionParams(host string, port int, protocol string) error { - if host == "" { - return errors.New("host is required") - } - if strings.ContainsAny(host, " \t\n\r/\\") { - return errors.New("host contains invalid characters") - } - if port < 1 || port > 65535 { - return errors.New("port must be between 1 and 65535") - } - if protocol != "" && !validProtocols[protocol] { - return errors.New("protocol must be one of: ipp, ipps, lpd, socket") - } - return nil -} - -const probeTimeout = 10 * time.Second - -func probeRemotePrinter(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - addr := net.JoinHostPort(host, fmt.Sprintf("%d", port)) - - // Fast fail: TCP reachability check - conn, err := net.DialTimeout("tcp", addr, probeTimeout) - if err != nil { - return &RemotePrinterInfo{ - Reachable: false, - Error: fmt.Sprintf("cannot reach %s: %s", addr, err.Error()), - }, nil - } - conn.Close() - - // Create a temporary IPP client pointing at the remote host. - // The TCP dial above provides fast-fail for unreachable hosts. - // The IPP adapter's ResponseHeaderTimeout (90s) bounds stalling servers. - client := ipp.NewIPPClient(host, port, "", "", useTLS) - - // Try /ipp/print first (modern driverless printers), then / (legacy) - info, err := probeIPPEndpoint(client, host, port, useTLS, "/ipp/print") - if err != nil { - // If we got an auth error, the printer exists but requires credentials. - // Report it as reachable with the URI that triggered the auth challenge. - if isAuthError(err) { - proto := "ipp" - if useTLS { - proto = "ipps" - } - return &RemotePrinterInfo{ - Reachable: true, - URI: fmt.Sprintf("%s://%s:%d/ipp/print", proto, host, port), - Info: "authentication required", - }, nil - } - info, err = probeIPPEndpoint(client, host, port, useTLS, "/") - } - if err != nil { - if isAuthError(err) { - proto := "ipp" - if useTLS { - proto = "ipps" - } - return &RemotePrinterInfo{ - Reachable: true, - URI: fmt.Sprintf("%s://%s:%d/", proto, host, port), - Info: "authentication required", - }, nil - } - // TCP reachable but not an IPP printer - return &RemotePrinterInfo{ - Reachable: true, - Error: fmt.Sprintf("host is reachable but does not appear to be an IPP printer: %s", err.Error()), - }, nil - } - - return info, nil -} - -func probeIPPEndpoint(client *ipp.IPPClient, host string, port int, useTLS bool, resourcePath string) (*RemotePrinterInfo, error) { - proto := "ipp" - if useTLS { - proto = "ipps" - } - printerURI := fmt.Sprintf("%s://%s:%d%s", proto, host, port, resourcePath) - - httpProto := "http" - if useTLS { - httpProto = "https" - } - httpURL := fmt.Sprintf("%s://%s:%d%s", httpProto, host, port, resourcePath) - - req := ipp.NewRequest(ipp.OperationGetPrinterAttributes, 1) - req.OperationAttributes[ipp.AttributePrinterURI] = printerURI - req.OperationAttributes[ipp.AttributeRequestedAttributes] = []string{ - ipp.AttributePrinterName, - ipp.AttributePrinterMakeAndModel, - ipp.AttributePrinterState, - ipp.AttributePrinterInfo, - ipp.AttributePrinterUriSupported, - } - - resp, err := client.SendRequest(httpURL, req, nil) - if err != nil { - return nil, err - } - - if len(resp.PrinterAttributes) == 0 { - return nil, errors.New("no printer attributes returned") - } - - attrs := resp.PrinterAttributes[0] - - return &RemotePrinterInfo{ - Reachable: true, - MakeModel: getStringAttr(attrs, ipp.AttributePrinterMakeAndModel), - Name: getStringAttr(attrs, ipp.AttributePrinterName), - Info: getStringAttr(attrs, ipp.AttributePrinterInfo), - State: parsePrinterState(attrs), - URI: printerURI, - }, nil -} - -// TestRemotePrinter validates inputs and probes a remote printer via IPP. -// For lpd/socket protocols, only TCP reachability is tested. -func (m *Manager) TestRemotePrinter(host string, port int, protocol string) (*RemotePrinterInfo, error) { - if protocol == "" { - protocol = "ipp" - } - - if err := validateTestConnectionParams(host, port, protocol); err != nil { - return nil, err - } - - // For non-IPP protocols, only check TCP reachability - if protocol == "lpd" || protocol == "socket" { - addr := net.JoinHostPort(host, fmt.Sprintf("%d", port)) - conn, err := net.DialTimeout("tcp", addr, probeTimeout) - if err != nil { - return &RemotePrinterInfo{ - Reachable: false, - Error: fmt.Sprintf("cannot reach %s: %s", addr, err.Error()), - }, nil - } - conn.Close() - return &RemotePrinterInfo{ - Reachable: true, - URI: fmt.Sprintf("%s://%s:%d", protocol, host, port), - }, nil - } - - useTLS := protocol == "ipps" - - probeFn := m.probeRemoteFn - if probeFn == nil { - probeFn = probeRemotePrinter - } - - return probeFn(host, port, useTLS) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go deleted file mode 100644 index b835028..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go +++ /dev/null @@ -1,397 +0,0 @@ -package cups - -import ( - "bytes" - "encoding/json" - "fmt" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/stretchr/testify/assert" -) - -func TestValidateTestConnectionParams(t *testing.T) { - tests := []struct { - name string - host string - port int - protocol string - wantErr string - }{ - { - name: "valid ipp", - host: "192.168.0.5", - port: 631, - protocol: "ipp", - wantErr: "", - }, - { - name: "valid ipps", - host: "printer.local", - port: 443, - protocol: "ipps", - wantErr: "", - }, - { - name: "valid lpd", - host: "10.0.0.1", - port: 515, - protocol: "lpd", - wantErr: "", - }, - { - name: "valid socket", - host: "10.0.0.1", - port: 9100, - protocol: "socket", - wantErr: "", - }, - { - name: "empty host", - host: "", - port: 631, - protocol: "ipp", - wantErr: "host is required", - }, - { - name: "port too low", - host: "192.168.0.5", - port: 0, - protocol: "ipp", - wantErr: "port must be between 1 and 65535", - }, - { - name: "port too high", - host: "192.168.0.5", - port: 70000, - protocol: "ipp", - wantErr: "port must be between 1 and 65535", - }, - { - name: "invalid protocol", - host: "192.168.0.5", - port: 631, - protocol: "ftp", - wantErr: "protocol must be one of: ipp, ipps, lpd, socket", - }, - { - name: "empty protocol treated as ipp", - host: "192.168.0.5", - port: 631, - protocol: "", - wantErr: "", - }, - { - name: "host with slash", - host: "192.168.0.5/admin", - port: 631, - protocol: "ipp", - wantErr: "host contains invalid characters", - }, - { - name: "host with space", - host: "192.168.0.5 ", - port: 631, - protocol: "ipp", - wantErr: "host contains invalid characters", - }, - { - name: "host with newline", - host: "192.168.0.5\n", - port: 631, - protocol: "ipp", - wantErr: "host contains invalid characters", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := validateTestConnectionParams(tt.host, tt.port, tt.protocol) - if tt.wantErr == "" { - assert.NoError(t, err) - } else { - assert.EqualError(t, err, tt.wantErr) - } - }) - } -} - -func TestManager_TestRemotePrinter_Validation(t *testing.T) { - m := NewTestManager(nil, nil) - - tests := []struct { - name string - host string - port int - protocol string - wantErr string - }{ - { - name: "empty host returns error", - host: "", - port: 631, - protocol: "ipp", - wantErr: "host is required", - }, - { - name: "invalid port returns error", - host: "192.168.0.5", - port: 0, - protocol: "ipp", - wantErr: "port must be between 1 and 65535", - }, - { - name: "invalid protocol returns error", - host: "192.168.0.5", - port: 631, - protocol: "ftp", - wantErr: "protocol must be one of: ipp, ipps, lpd, socket", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := m.TestRemotePrinter(tt.host, tt.port, tt.protocol) - assert.EqualError(t, err, tt.wantErr) - }) - } -} - -func TestManager_TestRemotePrinter_IPP(t *testing.T) { - tests := []struct { - name string - protocol string - probeRet *RemotePrinterInfo - probeErr error - wantTLS bool - wantReach bool - wantModel string - }{ - { - name: "successful ipp probe", - protocol: "ipp", - probeRet: &RemotePrinterInfo{ - Reachable: true, - MakeModel: "HP OfficeJet 8010", - Name: "OfficeJet", - State: "idle", - URI: "ipp://192.168.0.5:631/ipp/print", - }, - wantTLS: false, - wantReach: true, - wantModel: "HP OfficeJet 8010", - }, - { - name: "successful ipps probe", - protocol: "ipps", - probeRet: &RemotePrinterInfo{ - Reachable: true, - MakeModel: "HP OfficeJet 8010", - URI: "ipps://192.168.0.5:631/ipp/print", - }, - wantTLS: true, - wantReach: true, - wantModel: "HP OfficeJet 8010", - }, - { - name: "unreachable host", - protocol: "ipp", - probeRet: &RemotePrinterInfo{ - Reachable: false, - Error: "cannot reach 192.168.0.5:631: connection refused", - }, - wantReach: false, - }, - { - name: "empty protocol defaults to ipp", - protocol: "", - probeRet: &RemotePrinterInfo{ - Reachable: true, - MakeModel: "Test Printer", - }, - wantTLS: false, - wantReach: true, - wantModel: "Test Printer", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var capturedTLS bool - m := NewTestManager(nil, nil) - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - capturedTLS = useTLS - return tt.probeRet, tt.probeErr - } - - result, err := m.TestRemotePrinter("192.168.0.5", 631, tt.protocol) - if tt.probeErr != nil { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.wantReach, result.Reachable) - assert.Equal(t, tt.wantModel, result.MakeModel) - assert.Equal(t, tt.wantTLS, capturedTLS) - }) - } -} - -func TestManager_TestRemotePrinter_AuthRequired(t *testing.T) { - m := NewTestManager(nil, nil) - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - // Simulate what happens when the printer returns HTTP 401 - return probeRemotePrinterWithAuthError(host, port, useTLS) - } - - result, err := m.TestRemotePrinter("192.168.0.107", 631, "ipp") - assert.NoError(t, err) - assert.True(t, result.Reachable) - assert.Equal(t, "authentication required", result.Info) - assert.Contains(t, result.URI, "ipp://192.168.0.107:631") -} - -// probeRemotePrinterWithAuthError simulates a probe where the printer -// returns HTTP 401 on both endpoints. -func probeRemotePrinterWithAuthError(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - // This simulates what probeRemotePrinter does when both endpoints - // return auth errors. We test the auth detection logic directly. - err := ipp.HTTPError{Code: 401} - if isAuthError(err) { - proto := "ipp" - if useTLS { - proto = "ipps" - } - return &RemotePrinterInfo{ - Reachable: true, - URI: fmt.Sprintf("%s://%s:%d/ipp/print", proto, host, port), - Info: "authentication required", - }, nil - } - return nil, err -} - -func TestManager_TestRemotePrinter_NonIPPProtocol(t *testing.T) { - m := NewTestManager(nil, nil) - probeCalled := false - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - probeCalled = true - return nil, nil - } - - // These will fail at TCP dial (no real server), but the important - // thing is that probeRemoteFn is NOT called for lpd/socket. - m.TestRemotePrinter("192.168.0.5", 9100, "socket") - assert.False(t, probeCalled, "probe function should not be called for socket protocol") - - m.TestRemotePrinter("192.168.0.5", 515, "lpd") - assert.False(t, probeCalled, "probe function should not be called for lpd protocol") -} - -func TestHandleTestConnection_Success(t *testing.T) { - m := NewTestManager(nil, nil) - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - return &RemotePrinterInfo{ - Reachable: true, - MakeModel: "HP OfficeJet 8010", - Name: "OfficeJet", - State: "idle", - URI: "ipp://192.168.0.5:631/ipp/print", - }, nil - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.testConnection", - Params: map[string]any{ - "host": "192.168.0.5", - }, - } - - handleTestConnection(conn, req, m) - - var resp models.Response[RemotePrinterInfo] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Reachable) - assert.Equal(t, "HP OfficeJet 8010", resp.Result.MakeModel) -} - -func TestHandleTestConnection_MissingHost(t *testing.T) { - m := NewTestManager(nil, nil) - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.testConnection", - Params: map[string]any{}, - } - - handleTestConnection(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.Nil(t, resp.Result) - assert.NotNil(t, resp.Error) -} - -func TestHandleTestConnection_CustomPortAndProtocol(t *testing.T) { - m := NewTestManager(nil, nil) - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - assert.Equal(t, 9631, port) - assert.True(t, useTLS) - return &RemotePrinterInfo{Reachable: true, URI: "ipps://192.168.0.5:9631/ipp/print"}, nil - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.testConnection", - Params: map[string]any{ - "host": "192.168.0.5", - "port": float64(9631), - "protocol": "ipps", - }, - } - - handleTestConnection(conn, req, m) - - var resp models.Response[RemotePrinterInfo] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Reachable) -} - -func TestHandleRequest_TestConnection(t *testing.T) { - m := NewTestManager(nil, nil) - m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) { - return &RemotePrinterInfo{Reachable: true}, nil - } - - buf := &bytes.Buffer{} - conn := &mockConn{Buffer: buf} - - req := models.Request{ - ID: 1, - Method: "cups.testConnection", - Params: map[string]any{"host": "192.168.0.5"}, - } - - HandleRequest(conn, req, m) - - var resp models.Response[RemotePrinterInfo] - err := json.NewDecoder(buf).Decode(&resp) - assert.NoError(t, err) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Reachable) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/testing.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/testing.go deleted file mode 100644 index 4820e34..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/testing.go +++ /dev/null @@ -1,13 +0,0 @@ -package cups - -func NewTestManager(client CUPSClientInterface, pkHelper PkHelper) *Manager { - return &Manager{ - client: client, - pkHelper: pkHelper, - state: &CUPSState{ - Printers: make(map[string]*Printer), - }, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/types.go deleted file mode 100644 index 52e9d2c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/cups/types.go +++ /dev/null @@ -1,132 +0,0 @@ -package cups - -import ( - "io" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type CUPSState struct { - Printers map[string]*Printer `json:"printers"` -} - -type Printer struct { - Name string `json:"name"` - URI string `json:"uri"` - State string `json:"state"` - StateReason string `json:"stateReason"` - Location string `json:"location"` - Info string `json:"info"` - MakeModel string `json:"makeModel"` - Accepting bool `json:"accepting"` - Jobs []Job `json:"jobs"` -} - -type Job struct { - ID int `json:"id"` - Name string `json:"name"` - State string `json:"state"` - Printer string `json:"printer"` - User string `json:"user"` - Size int `json:"size"` - TimeCreated time.Time `json:"timeCreated"` -} - -type Device struct { - URI string `json:"uri"` - Class string `json:"class"` - Info string `json:"info"` - MakeModel string `json:"makeModel"` - ID string `json:"id"` - Location string `json:"location"` - IP string `json:"ip,omitempty"` -} - -type PPD struct { - Name string `json:"name"` - NaturalLanguage string `json:"naturalLanguage"` - MakeModel string `json:"makeModel"` - DeviceID string `json:"deviceId"` - Product string `json:"product"` - PSVersion string `json:"psVersion"` - Type string `json:"type"` -} - -type RemotePrinterInfo struct { - Reachable bool `json:"reachable"` - MakeModel string `json:"makeModel"` - Name string `json:"name"` - Info string `json:"info"` - State string `json:"state"` - URI string `json:"uri"` - Error string `json:"error,omitempty"` -} - -type PrinterClass struct { - Name string `json:"name"` - URI string `json:"uri"` - State string `json:"state"` - Members []string `json:"members"` - Location string `json:"location"` - Info string `json:"info"` -} - -type Manager struct { - state *CUPSState - client CUPSClientInterface - pkHelper PkHelper - subscription SubscriptionManagerInterface - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan CUPSState] - stopChan chan struct{} - eventWG sync.WaitGroup - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotifiedState *CUPSState - baseURL string - probeRemoteFn func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) -} - -type SubscriptionManagerInterface interface { - Start() error - Stop() - Events() <-chan SubscriptionEvent -} - -type CUPSClientInterface interface { - GetPrinters(attributes []string) (map[string]ipp.Attributes, error) - GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]ipp.Attributes, error) - CancelJob(jobID int, purge bool) error - PausePrinter(printer string) error - ResumePrinter(printer string) error - CancelAllJob(printer string, purge bool) error - SendRequest(url string, req *ipp.Request, additionalResponseData io.Writer) (*ipp.Response, error) - - GetDevices() (map[string]ipp.Attributes, error) - GetPPDs() (map[string]ipp.Attributes, error) - GetClasses(attributes []string) (map[string]ipp.Attributes, error) - CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy, information, location string) error - DeletePrinter(printer string) error - AcceptJobs(printer string) error - RejectJobs(printer string) error - SetPrinterIsShared(printer string, shared bool) error - SetPrinterLocation(printer, location string) error - SetPrinterInformation(printer, information string) error - MoveJob(jobID int, destPrinter string) error - PrintTestPage(printer string, testPageData io.Reader, size int) (int, error) - AddPrinterToClass(class, printer string) error - DeletePrinterFromClass(class, printer string) error - DeleteClass(class string) error - RestartJob(jobID int) error - HoldJobUntil(jobID int, holdUntil string) error -} - -type SubscriptionEvent struct { - EventName string - PrinterName string - JobID int - SubscribedAt time.Time -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/handlers.go deleted file mode 100644 index e625d79..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/handlers.go +++ /dev/null @@ -1,237 +0,0 @@ -package dbus - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -type objectParams struct { - bus string - dest string - path string - iface string -} - -func extractObjectParams(p map[string]any, requirePath bool) (objectParams, error) { - bus, err := params.String(p, "bus") - if err != nil { - return objectParams{}, err - } - dest, err := params.String(p, "dest") - if err != nil { - return objectParams{}, err - } - - var path string - if requirePath { - path, err = params.String(p, "path") - if err != nil { - return objectParams{}, err - } - } else { - path = params.StringOpt(p, "path", "/") - } - - iface, err := params.String(p, "interface") - if err != nil { - return objectParams{}, err - } - - return objectParams{bus: bus, dest: dest, path: path, iface: iface}, nil -} - -func HandleRequest(conn net.Conn, req models.Request, m *Manager, clientID string) { - switch req.Method { - case "dbus.call": - handleCall(conn, req, m) - case "dbus.getProperty": - handleGetProperty(conn, req, m) - case "dbus.setProperty": - handleSetProperty(conn, req, m) - case "dbus.getAllProperties": - handleGetAllProperties(conn, req, m) - case "dbus.introspect": - handleIntrospect(conn, req, m) - case "dbus.listNames": - handleListNames(conn, req, m) - case "dbus.subscribe": - handleSubscribe(conn, req, m, clientID) - case "dbus.unsubscribe": - handleUnsubscribe(conn, req, m) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleCall(conn net.Conn, req models.Request, m *Manager) { - op, err := extractObjectParams(req.Params, true) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - method, err := params.String(req.Params, "method") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - var args []any - if argsRaw, ok := params.Any(req.Params, "args"); ok { - if argsSlice, ok := argsRaw.([]any); ok { - args = argsSlice - } - } - - result, err := m.Call(op.bus, op.dest, op.path, op.iface, method, args) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleGetProperty(conn net.Conn, req models.Request, m *Manager) { - op, err := extractObjectParams(req.Params, true) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - property, err := params.String(req.Params, "property") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - result, err := m.GetProperty(op.bus, op.dest, op.path, op.iface, property) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleSetProperty(conn net.Conn, req models.Request, m *Manager) { - op, err := extractObjectParams(req.Params, true) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - property, err := params.String(req.Params, "property") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - value, ok := params.Any(req.Params, "value") - if !ok { - models.RespondError(conn, req.ID, "missing 'value' parameter") - return - } - - if err := m.SetProperty(op.bus, op.dest, op.path, op.iface, property, value); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true}) -} - -func handleGetAllProperties(conn net.Conn, req models.Request, m *Manager) { - op, err := extractObjectParams(req.Params, true) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - result, err := m.GetAllProperties(op.bus, op.dest, op.path, op.iface) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleIntrospect(conn net.Conn, req models.Request, m *Manager) { - bus, err := params.String(req.Params, "bus") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - dest, err := params.String(req.Params, "dest") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - path := params.StringOpt(req.Params, "path", "/") - - result, err := m.Introspect(bus, dest, path) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleListNames(conn net.Conn, req models.Request, m *Manager) { - bus, err := params.String(req.Params, "bus") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - result, err := m.ListNames(bus) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleSubscribe(conn net.Conn, req models.Request, m *Manager, clientID string) { - bus, err := params.String(req.Params, "bus") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - sender := params.StringOpt(req.Params, "sender", "") - path := params.StringOpt(req.Params, "path", "") - iface := params.StringOpt(req.Params, "interface", "") - member := params.StringOpt(req.Params, "member", "") - - result, err := m.Subscribe(clientID, bus, sender, path, iface, member) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleUnsubscribe(conn net.Conn, req models.Request, m *Manager) { - subID, err := params.String(req.Params, "subscriptionId") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := m.Unsubscribe(subID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true}) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/manager.go deleted file mode 100644 index 86da6bd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/manager.go +++ /dev/null @@ -1,392 +0,0 @@ -package dbus - -import ( - "crypto/rand" - "encoding/hex" - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/godbus/dbus/v5" -) - -func NewManager() (*Manager, error) { - systemConn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to system bus: %w", err) - } - - sessionConn, err := dbus.ConnectSessionBus() - if err != nil { - systemConn.Close() - return nil, fmt.Errorf("failed to connect to session bus: %w", err) - } - - m := &Manager{ - systemConn: systemConn, - sessionConn: sessionConn, - } - - go m.processSystemSignals() - go m.processSessionSignals() - - return m, nil -} - -func (m *Manager) getConn(bus string) (*dbus.Conn, error) { - switch bus { - case "system": - if m.systemConn == nil { - return nil, fmt.Errorf("system bus not connected") - } - return m.systemConn, nil - case "session": - if m.sessionConn == nil { - return nil, fmt.Errorf("session bus not connected") - } - return m.sessionConn, nil - default: - return nil, fmt.Errorf("invalid bus: %s (must be 'system' or 'session')", bus) - } -} - -func (m *Manager) Call(bus, dest, path, iface, method string, args []any) (*CallResult, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - obj := conn.Object(dest, dbus.ObjectPath(path)) - fullMethod := iface + "." + method - - convertedArgs := convertArgs(args) - call := obj.Call(fullMethod, 0, convertedArgs...) - if call.Err != nil { - return nil, fmt.Errorf("dbus call failed: %w", call.Err) - } - - return &CallResult{Values: dbusutil.NormalizeSlice(call.Body)}, nil -} - -func convertArgs(args []any) []any { - result := make([]any, len(args)) - for i, arg := range args { - result[i] = convertArg(arg) - } - return result -} - -func convertArg(arg any) any { - switch v := arg.(type) { - case float64: - if v == float64(uint32(v)) && v >= 0 && v <= float64(^uint32(0)) { - return uint32(v) - } - if v == float64(int32(v)) { - return int32(v) - } - return v - case []any: - return convertArgs(v) - case map[string]any: - result := make(map[string]any) - for k, val := range v { - result[k] = convertArg(val) - } - return result - default: - return arg - } -} - -func (m *Manager) GetProperty(bus, dest, path, iface, property string) (*PropertyResult, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - obj := conn.Object(dest, dbus.ObjectPath(path)) - - var variant dbus.Variant - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, iface, property).Store(&variant) - if err != nil { - return nil, fmt.Errorf("failed to get property: %w", err) - } - - return &PropertyResult{Value: dbusutil.Normalize(variant.Value())}, nil -} - -func (m *Manager) SetProperty(bus, dest, path, iface, property string, value any) error { - conn, err := m.getConn(bus) - if err != nil { - return err - } - - obj := conn.Object(dest, dbus.ObjectPath(path)) - - call := obj.Call("org.freedesktop.DBus.Properties.Set", 0, iface, property, dbus.MakeVariant(value)) - if call.Err != nil { - return fmt.Errorf("failed to set property: %w", call.Err) - } - - return nil -} - -func (m *Manager) GetAllProperties(bus, dest, path, iface string) (map[string]any, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - obj := conn.Object(dest, dbus.ObjectPath(path)) - - var props map[string]dbus.Variant - err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, iface).Store(&props) - if err != nil { - return nil, fmt.Errorf("failed to get properties: %w", err) - } - - result := make(map[string]any) - for k, v := range props { - result[k] = dbusutil.Normalize(v.Value()) - } - - return result, nil -} - -func (m *Manager) Introspect(bus, dest, path string) (*IntrospectResult, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - obj := conn.Object(dest, dbus.ObjectPath(path)) - - var xml string - err = obj.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xml) - if err != nil { - return nil, fmt.Errorf("failed to introspect: %w", err) - } - - return &IntrospectResult{XML: xml}, nil -} - -func (m *Manager) ListNames(bus string) (*ListNamesResult, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - var names []string - err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&names) - if err != nil { - return nil, fmt.Errorf("failed to list names: %w", err) - } - - return &ListNamesResult{Names: names}, nil -} - -func (m *Manager) Subscribe(clientID, bus, sender, path, iface, member string) (*SubscribeResult, error) { - conn, err := m.getConn(bus) - if err != nil { - return nil, err - } - - subID := generateSubscriptionID() - - parts := []string{"type='signal'"} - if sender != "" { - parts = append(parts, fmt.Sprintf("sender='%s'", sender)) - } - if path != "" { - parts = append(parts, fmt.Sprintf("path='%s'", path)) - } - if iface != "" { - parts = append(parts, fmt.Sprintf("interface='%s'", iface)) - } - if member != "" { - parts = append(parts, fmt.Sprintf("member='%s'", member)) - } - matchRule := strings.Join(parts, ",") - - call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, matchRule) - if call.Err != nil { - return nil, fmt.Errorf("failed to add match rule: %w", call.Err) - } - - sub := &signalSubscription{ - Bus: bus, - Sender: sender, - Path: path, - Interface: iface, - Member: member, - ClientID: clientID, - } - m.subscriptions.Store(subID, sub) - - log.Debugf("dbus: subscribed %s to %s", subID, matchRule) - - return &SubscribeResult{SubscriptionID: subID}, nil -} - -func (m *Manager) Unsubscribe(subID string) error { - sub, ok := m.subscriptions.LoadAndDelete(subID) - if !ok { - return fmt.Errorf("subscription not found: %s", subID) - } - - conn, err := m.getConn(sub.Bus) - if err != nil { - return err - } - - parts := []string{"type='signal'"} - if sub.Sender != "" { - parts = append(parts, fmt.Sprintf("sender='%s'", sub.Sender)) - } - if sub.Path != "" { - parts = append(parts, fmt.Sprintf("path='%s'", sub.Path)) - } - if sub.Interface != "" { - parts = append(parts, fmt.Sprintf("interface='%s'", sub.Interface)) - } - if sub.Member != "" { - parts = append(parts, fmt.Sprintf("member='%s'", sub.Member)) - } - matchRule := strings.Join(parts, ",") - - call := conn.BusObject().Call("org.freedesktop.DBus.RemoveMatch", 0, matchRule) - if call.Err != nil { - log.Warnf("dbus: failed to remove match rule: %v", call.Err) - } - - log.Debugf("dbus: unsubscribed %s", subID) - - return nil -} - -func (m *Manager) UnsubscribeClient(clientID string) { - var toDelete []string - m.subscriptions.Range(func(subID string, sub *signalSubscription) bool { - if sub.ClientID == clientID { - toDelete = append(toDelete, subID) - } - return true - }) - - for _, subID := range toDelete { - _ = m.Unsubscribe(subID) - } -} - -func (m *Manager) SubscribeSignals(clientID string) chan SignalEvent { - ch := make(chan SignalEvent, 64) - existing, loaded := m.signalSubscribers.LoadOrStore(clientID, ch) - if loaded { - return existing - } - return ch -} - -func (m *Manager) UnsubscribeSignals(clientID string) { - if ch, ok := m.signalSubscribers.LoadAndDelete(clientID); ok { - close(ch) - } - m.UnsubscribeClient(clientID) -} - -func (m *Manager) processSystemSignals() { - if m.systemConn == nil { - return - } - ch := make(chan *dbus.Signal, 256) - m.systemConn.Signal(ch) - - for sig := range ch { - m.dispatchSignal("system", sig) - } -} - -func (m *Manager) processSessionSignals() { - if m.sessionConn == nil { - return - } - ch := make(chan *dbus.Signal, 256) - m.sessionConn.Signal(ch) - - for sig := range ch { - m.dispatchSignal("session", sig) - } -} - -func (m *Manager) dispatchSignal(bus string, sig *dbus.Signal) { - path := string(sig.Path) - iface := "" - member := sig.Name - - if idx := strings.LastIndex(sig.Name, "."); idx != -1 { - iface = sig.Name[:idx] - member = sig.Name[idx+1:] - } - - m.subscriptions.Range(func(subID string, sub *signalSubscription) bool { - if sub.Bus != bus { - return true - } - if sub.Path != "" && sub.Path != path && !strings.HasPrefix(path, sub.Path) { - return true - } - if sub.Interface != "" && sub.Interface != iface { - return true - } - if sub.Member != "" && sub.Member != member { - return true - } - - event := SignalEvent{ - SubscriptionID: subID, - Sender: sig.Sender, - Path: path, - Interface: iface, - Member: member, - Body: dbusutil.NormalizeSlice(sig.Body), - } - - ch, ok := m.signalSubscribers.Load(sub.ClientID) - if !ok { - return true - } - - select { - case ch <- event: - default: - log.Warnf("dbus: channel full for %s, dropping signal", subID) - } - - return true - }) -} - -func (m *Manager) Close() { - m.signalSubscribers.Range(func(clientID string, ch chan SignalEvent) bool { - close(ch) - m.signalSubscribers.Delete(clientID) - return true - }) - - if m.systemConn != nil { - m.systemConn.Close() - } - if m.sessionConn != nil { - m.sessionConn.Close() - } -} - -func generateSubscriptionID() string { - b := make([]byte, 8) - if _, err := rand.Read(b); err != nil { - log.Warnf("dbus: failed to generate random subscription ID: %v", err) - } - return hex.EncodeToString(b) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/types.go deleted file mode 100644 index 55c45bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dbus/types.go +++ /dev/null @@ -1,52 +0,0 @@ -package dbus - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type Manager struct { - systemConn *dbus.Conn - sessionConn *dbus.Conn - - subscriptions syncmap.Map[string, *signalSubscription] - signalSubscribers syncmap.Map[string, chan SignalEvent] -} - -type signalSubscription struct { - Bus string - Sender string - Path string - Interface string - Member string - ClientID string -} - -type SignalEvent struct { - SubscriptionID string `json:"subscriptionId"` - Sender string `json:"sender"` - Path string `json:"path"` - Interface string `json:"interface"` - Member string `json:"member"` - Body []any `json:"body"` -} - -type CallResult struct { - Values []any `json:"values"` -} - -type PropertyResult struct { - Value any `json:"value"` -} - -type IntrospectResult struct { - XML string `json:"xml"` -} - -type ListNamesResult struct { - Names []string `json:"names"` -} - -type SubscribeResult struct { - SubscriptionID string `json:"subscriptionId"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go deleted file mode 100644 index e83cc84..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go +++ /dev/null @@ -1,138 +0,0 @@ -package dwl - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type SuccessResult struct { - Success bool `json:"success"` - Message string `json:"message"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - if manager == nil { - models.RespondError(conn, req.ID, "dwl manager not initialized") - return - } - - switch req.Method { - case "dwl.getState": - handleGetState(conn, req, manager) - case "dwl.setTags": - handleSetTags(conn, req, manager) - case "dwl.setClientTags": - handleSetClientTags(conn, req, manager) - case "dwl.setLayout": - handleSetLayout(conn, req, manager) - case "dwl.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - state := manager.GetState() - models.Respond(conn, req.ID, state) -} - -func handleSetTags(conn net.Conn, req models.Request, manager *Manager) { - output, ok := models.Get[string](req, "output") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'output' parameter") - return - } - - tagmask, ok := models.Get[float64](req, "tagmask") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'tagmask' parameter") - return - } - - toggleTagset, ok := models.Get[float64](req, "toggleTagset") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'toggleTagset' parameter") - return - } - - if err := manager.SetTags(output, uint32(tagmask), uint32(toggleTagset)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "tags set"}) -} - -func handleSetClientTags(conn net.Conn, req models.Request, manager *Manager) { - output, ok := models.Get[string](req, "output") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'output' parameter") - return - } - - andTags, ok := models.Get[float64](req, "andTags") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'andTags' parameter") - return - } - - xorTags, ok := models.Get[float64](req, "xorTags") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'xorTags' parameter") - return - } - - if err := manager.SetClientTags(output, uint32(andTags), uint32(xorTags)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "client tags set"}) -} - -func handleSetLayout(conn net.Conn, req models.Request, manager *Manager) { - output, ok := models.Get[string](req, "output") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'output' parameter") - return - } - - index, ok := models.Get[float64](req, "index") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'index' parameter") - return - } - - if err := manager.SetLayout(output, uint32(index)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "layout set"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range stateChan { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - Result: &state, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go deleted file mode 100644 index 0d21afa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go +++ /dev/null @@ -1,522 +0,0 @@ -package dwl - -import ( - "fmt" - "time" - - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc" -) - -func NewManager(display wlclient.WaylandDisplay) (*Manager, error) { - m := &Manager{ - display: display, - ctx: display.Context(), - cmdq: make(chan cmd, 128), - outputSetupReq: make(chan uint32, 16), - stopChan: make(chan struct{}), - - dirty: make(chan struct{}, 1), - layouts: make([]string, 0), - } - - if err := m.setupRegistry(); err != nil { - return nil, err - } - - m.updateState() - - m.notifierWg.Add(1) - go m.notifier() - - m.wg.Add(1) - go m.waylandActor() - - return m, nil -} - -func (m *Manager) post(fn func()) { - select { - case m.cmdq <- cmd{fn: fn}: - default: - log.Warn("DWL actor command queue full, dropping command") - } -} - -func (m *Manager) waylandActor() { - defer m.wg.Done() - - for { - select { - case <-m.stopChan: - return - case c := <-m.cmdq: - c.fn() - case outputID := <-m.outputSetupReq: - out, exists := m.outputs.Load(outputID) - if !exists { - log.Warnf("DWL: Output %d no longer exists, skipping setup", outputID) - continue - } - - if out.ipcOutput != nil { - continue - } - - mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2) - if !ok || mgr == nil { - log.Errorf("DWL: Manager not available for output %d setup", outputID) - continue - } - - log.Infof("DWL: Setting up ipcOutput for dynamically added output %d", outputID) - if err := m.setupOutput(mgr, out.output); err != nil { - log.Errorf("DWL: Failed to setup output %d: %v", outputID, err) - } else { - m.updateState() - } - } - } -} - -func (m *Manager) setupRegistry() error { - log.Info("DWL: starting registry setup") - - registry, err := m.display.GetRegistry() - if err != nil { - return fmt.Errorf("failed to get registry: %w", err) - } - m.registry = registry - - outputs := make([]*wlclient.Output, 0) - outputRegNames := make(map[uint32]uint32) - var dwlMgr *dwl_ipc.ZdwlIpcManagerV2 - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case dwl_ipc.ZdwlIpcManagerV2InterfaceName: - log.Infof("DWL: found %s", dwl_ipc.ZdwlIpcManagerV2InterfaceName) - manager := dwl_ipc.NewZdwlIpcManagerV2(m.ctx) - version := e.Version - if version > 2 { - version = 2 - } - if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil { - dwlMgr = manager - log.Info("DWL: manager bound successfully") - - // Set handlers immediately after binding, before roundtrips - manager.SetTagsHandler(func(e dwl_ipc.ZdwlIpcManagerV2TagsEvent) { - log.Infof("DWL: Tags count: %d", e.Amount) - m.tagCount = e.Amount - m.updateState() - }) - - manager.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcManagerV2LayoutEvent) { - log.Infof("DWL: Layout: %s", e.Name) - m.layouts = append(m.layouts, e.Name) - m.updateState() - }) - } else { - log.Errorf("DWL: failed to bind manager: %v", err) - } - case "wl_output": - log.Debugf("DWL: found wl_output (name=%d)", e.Name) - output := wlclient.NewOutput(m.ctx) - - outState := &outputState{ - registryName: e.Name, - output: output, - tags: make([]TagState, 0), - } - - output.SetNameHandler(func(ev wlclient.OutputNameEvent) { - log.Debugf("DWL: Output name: %s (registry=%d)", ev.Name, e.Name) - outState.name = ev.Name - }) - - output.SetDescriptionHandler(func(ev wlclient.OutputDescriptionEvent) { - log.Debugf("DWL: Output description: %s", ev.Description) - }) - - version := e.Version - if version > 4 { - version = 4 - } - if err := registry.Bind(e.Name, e.Interface, version, output); err == nil { - outputID := output.ID() - outState.id = outputID - log.Infof("DWL: Bound wl_output id=%d registry_name=%d", outputID, e.Name) - outputs = append(outputs, output) - outputRegNames[outputID] = e.Name - - m.outputs.Store(outputID, outState) - - if m.manager != nil { - select { - case m.outputSetupReq <- outputID: - log.Debugf("DWL: Queued setup for output %d", outputID) - default: - log.Warnf("DWL: Setup queue full, output %d will not be initialized", outputID) - } - } - } else { - log.Errorf("DWL: Failed to bind wl_output: %v", err) - } - } - }) - - registry.SetGlobalRemoveHandler(func(e wlclient.RegistryGlobalRemoveEvent) { - m.post(func() { - var outToRelease *outputState - m.outputs.Range(func(id uint32, out *outputState) bool { - if out.registryName == e.Name { - log.Infof("DWL: Output %d removed", id) - outToRelease = out - m.outputs.Delete(id) - return false - } - return true - }) - - if outToRelease != nil { - if ipcOut, ok := outToRelease.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok && ipcOut != nil { - m.wlMutex.Lock() - ipcOut.Release() - m.wlMutex.Unlock() - log.Debugf("DWL: Released ipcOutput for removed output %d", outToRelease.id) - } - m.updateState() - } - }) - }) - - if err := m.display.Roundtrip(); err != nil { - return fmt.Errorf("first roundtrip failed: %w", err) - } - if err := m.display.Roundtrip(); err != nil { - return fmt.Errorf("second roundtrip failed: %w", err) - } - - if dwlMgr == nil { - log.Info("DWL: manager not found in registry") - return fmt.Errorf("dwl_ipc_manager_v2 not available") - } - - m.manager = dwlMgr - - for _, output := range outputs { - if err := m.setupOutput(dwlMgr, output); err != nil { - log.Warnf("DWL: Failed to setup output %d: %v", output.ID(), err) - } - } - - if err := m.display.Roundtrip(); err != nil { - return fmt.Errorf("final roundtrip failed: %w", err) - } - - log.Info("DWL: registry setup complete") - return nil -} - -func (m *Manager) setupOutput(manager *dwl_ipc.ZdwlIpcManagerV2, output *wlclient.Output) error { - m.wlMutex.Lock() - ipcOutput, err := manager.GetOutput(output) - m.wlMutex.Unlock() - if err != nil { - return fmt.Errorf("failed to get dwl output: %w", err) - } - - outState, exists := m.outputs.Load(output.ID()) - if !exists { - return fmt.Errorf("output state not found for id %d", output.ID()) - } - outState.ipcOutput = ipcOutput - - ipcOutput.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) { - outState.active = e.Active - }) - - ipcOutput.SetTagHandler(func(e dwl_ipc.ZdwlIpcOutputV2TagEvent) { - updated := false - for i, tag := range outState.tags { - if tag.Tag == e.Tag { - outState.tags[i] = TagState{ - Tag: e.Tag, - State: e.State, - Clients: e.Clients, - Focused: e.Focused, - } - updated = true - break - } - } - - if !updated { - outState.tags = append(outState.tags, TagState{ - Tag: e.Tag, - State: e.State, - Clients: e.Clients, - Focused: e.Focused, - }) - } - - m.updateState() - }) - - ipcOutput.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutEvent) { - outState.layout = e.Layout - }) - - ipcOutput.SetTitleHandler(func(e dwl_ipc.ZdwlIpcOutputV2TitleEvent) { - outState.title = e.Title - }) - - ipcOutput.SetAppidHandler(func(e dwl_ipc.ZdwlIpcOutputV2AppidEvent) { - outState.appID = e.Appid - }) - - ipcOutput.SetLayoutSymbolHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutSymbolEvent) { - outState.layoutSymbol = e.Layout - }) - - ipcOutput.SetKbLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2KbLayoutEvent) { - outState.kbLayout = e.KbLayout - }) - - ipcOutput.SetKeymodeHandler(func(e dwl_ipc.ZdwlIpcOutputV2KeymodeEvent) { - outState.keymode = e.Keymode - }) - - ipcOutput.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) { - m.updateState() - }) - - return nil -} - -func (m *Manager) updateState() { - outputs := make(map[string]*OutputState) - activeOutput := "" - - m.outputs.Range(func(key uint32, out *outputState) bool { - name := out.name - if name == "" { - name = fmt.Sprintf("output-%d", out.id) - } - - tagsCopy := make([]TagState, len(out.tags)) - copy(tagsCopy, out.tags) - - outputs[name] = &OutputState{ - Name: name, - Active: out.active, - Tags: tagsCopy, - Layout: out.layout, - LayoutSymbol: out.layoutSymbol, - Title: out.title, - AppID: out.appID, - KbLayout: out.kbLayout, - Keymode: out.keymode, - } - - if out.active != 0 { - activeOutput = name - } - return true - }) - - newState := State{ - Outputs: outputs, - TagCount: m.tagCount, - Layouts: m.layouts, - ActiveOutput: activeOutput, - } - - m.stateMutex.Lock() - m.state = &newState - m.stateMutex.Unlock() - - m.notifySubscribers() -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.GetState() - - if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- currentState: - default: - log.Warn("DWL: subscriber channel full, dropping update") - } - return true - }) - - stateCopy := currentState - m.lastNotified = &stateCopy - pending = false - } - } -} - -func (m *Manager) ensureOutputSetup(out *outputState) error { - if out.ipcOutput != nil { - return nil - } - - return fmt.Errorf("output not yet initialized - setup in progress, retry in a moment") -} - -func (m *Manager) SetTags(outputName string, tagmask uint32, toggleTagset uint32) error { - availableOutputs := make([]string, 0) - var targetOut *outputState - m.outputs.Range(func(key uint32, out *outputState) bool { - name := out.name - if name == "" { - name = fmt.Sprintf("output-%d", out.id) - } - availableOutputs = append(availableOutputs, name) - if name == outputName { - targetOut = out - return false - } - return true - }) - - if targetOut == nil { - return fmt.Errorf("output not found: %s (available: %v)", outputName, availableOutputs) - } - - if err := m.ensureOutputSetup(targetOut); err != nil { - return fmt.Errorf("failed to setup output %s: %w", outputName, err) - } - - ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2) - if !ok { - return fmt.Errorf("output %s has invalid ipcOutput type", outputName) - } - - m.wlMutex.Lock() - err := ipcOut.SetTags(tagmask, toggleTagset) - m.wlMutex.Unlock() - return err -} - -func (m *Manager) SetClientTags(outputName string, andTags uint32, xorTags uint32) error { - var targetOut *outputState - m.outputs.Range(func(key uint32, out *outputState) bool { - name := out.name - if name == "" { - name = fmt.Sprintf("output-%d", out.id) - } - if name == outputName { - targetOut = out - return false - } - return true - }) - - if targetOut == nil { - return fmt.Errorf("output not found: %s", outputName) - } - - if err := m.ensureOutputSetup(targetOut); err != nil { - return fmt.Errorf("failed to setup output %s: %w", outputName, err) - } - - ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2) - if !ok { - return fmt.Errorf("output %s has invalid ipcOutput type", outputName) - } - - m.wlMutex.Lock() - err := ipcOut.SetClientTags(andTags, xorTags) - m.wlMutex.Unlock() - return err -} - -func (m *Manager) SetLayout(outputName string, index uint32) error { - var targetOut *outputState - m.outputs.Range(func(key uint32, out *outputState) bool { - name := out.name - if name == "" { - name = fmt.Sprintf("output-%d", out.id) - } - if name == outputName { - targetOut = out - return false - } - return true - }) - - if targetOut == nil { - return fmt.Errorf("output not found: %s", outputName) - } - - if err := m.ensureOutputSetup(targetOut); err != nil { - return fmt.Errorf("failed to setup output %s: %w", outputName, err) - } - - ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2) - if !ok { - return fmt.Errorf("output %s has invalid ipcOutput type", outputName) - } - - m.wlMutex.Lock() - err := ipcOut.SetLayout(index) - m.wlMutex.Unlock() - return err -} - -func (m *Manager) Close() { - close(m.stopChan) - m.wg.Wait() - m.notifierWg.Wait() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.outputs.Range(func(key uint32, out *outputState) bool { - if ipcOut, ok := out.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok { - ipcOut.Release() - } - m.outputs.Delete(key) - return true - }) - - if mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2); ok { - mgr.Release() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go deleted file mode 100644 index 13af137..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go +++ /dev/null @@ -1,366 +0,0 @@ -package dwl - -import ( - "errors" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient" -) - -func TestStateChanged_BothNil(t *testing.T) { - assert.True(t, stateChanged(nil, nil)) -} - -func TestStateChanged_OneNil(t *testing.T) { - s := &State{TagCount: 9} - assert.True(t, stateChanged(s, nil)) - assert.True(t, stateChanged(nil, s)) -} - -func TestStateChanged_TagCountDiffers(t *testing.T) { - a := &State{TagCount: 9, Outputs: make(map[string]*OutputState), Layouts: []string{}} - b := &State{TagCount: 10, Outputs: make(map[string]*OutputState), Layouts: []string{}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_LayoutLengthDiffers(t *testing.T) { - a := &State{TagCount: 9, Layouts: []string{"tile"}, Outputs: make(map[string]*OutputState)} - b := &State{TagCount: 9, Layouts: []string{"tile", "monocle"}, Outputs: make(map[string]*OutputState)} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_ActiveOutputDiffers(t *testing.T) { - a := &State{TagCount: 9, ActiveOutput: "eDP-1", Outputs: make(map[string]*OutputState), Layouts: []string{}} - b := &State{TagCount: 9, ActiveOutput: "HDMI-A-1", Outputs: make(map[string]*OutputState), Layouts: []string{}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputCountDiffers(t *testing.T) { - a := &State{ - TagCount: 9, - Outputs: map[string]*OutputState{"eDP-1": {}}, - Layouts: []string{}, - } - b := &State{ - TagCount: 9, - Outputs: map[string]*OutputState{}, - Layouts: []string{}, - } - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputFieldsDiffer(t *testing.T) { - a := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Active: 1, Layout: 0, Title: "Firefox"}, - }, - } - b := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Active: 0, Layout: 0, Title: "Firefox"}, - }, - } - assert.True(t, stateChanged(a, b)) - - b.Outputs["eDP-1"].Active = 1 - b.Outputs["eDP-1"].Layout = 1 - assert.True(t, stateChanged(a, b)) - - b.Outputs["eDP-1"].Layout = 0 - b.Outputs["eDP-1"].Title = "Code" - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_TagsDiffer(t *testing.T) { - a := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}}}, - }, - } - b := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Tags: []TagState{{Tag: 1, State: 2, Clients: 2, Focused: 1}}}, - }, - } - assert.True(t, stateChanged(a, b)) - - b.Outputs["eDP-1"].Tags[0].State = 1 - b.Outputs["eDP-1"].Tags[0].Clients = 3 - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_Equal(t *testing.T) { - a := &State{ - TagCount: 9, - ActiveOutput: "eDP-1", - Layouts: []string{"tile", "monocle"}, - Outputs: map[string]*OutputState{ - "eDP-1": { - Name: "eDP-1", - Active: 1, - Layout: 0, - LayoutSymbol: "[]=", - Title: "Firefox", - AppID: "firefox", - KbLayout: "us", - Keymode: "", - Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}}, - }, - }, - } - b := &State{ - TagCount: 9, - ActiveOutput: "eDP-1", - Layouts: []string{"tile", "monocle"}, - Outputs: map[string]*OutputState{ - "eDP-1": { - Name: "eDP-1", - Active: 1, - Layout: 0, - LayoutSymbol: "[]=", - Title: "Firefox", - AppID: "firefox", - KbLayout: "us", - Keymode: "", - Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}}, - }, - }, - } - assert.False(t, stateChanged(a, b)) -} - -func TestManager_ConcurrentGetState(t *testing.T) { - m := &Manager{ - state: &State{ - TagCount: 9, - Layouts: []string{"tile"}, - Outputs: map[string]*OutputState{"eDP-1": {Name: "eDP-1"}}, - }, - } - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - s := m.GetState() - _ = s.TagCount - _ = s.Outputs - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.stateMutex.Lock() - m.state = &State{ - TagCount: uint32(j % 10), - Layouts: []string{"tile", "monocle"}, - Outputs: map[string]*OutputState{"eDP-1": {Active: uint32(j % 2)}}, - } - m.stateMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentSubscriberAccess(t *testing.T) { - m := &Manager{ - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - var wg sync.WaitGroup - const goroutines = 20 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - subID := string(rune('a' + id)) - ch := m.Subscribe(subID) - assert.NotNil(t, ch) - time.Sleep(time.Millisecond) - m.Unsubscribe(subID) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapOutputsConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &outputState{ - id: key, - name: "test-output", - active: uint32(j % 2), - tags: []TagState{{Tag: uint32(j), State: 1}}, - } - m.outputs.Store(key, state) - - if loaded, ok := m.outputs.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.outputs.Range(func(k uint32, v *outputState) bool { - _ = v.name - _ = v.active - return true - }) - } - - m.outputs.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_NotifySubscribersNonBlocking(t *testing.T) { - m := &Manager{ - dirty: make(chan struct{}, 1), - } - - for i := 0; i < 10; i++ { - m.notifySubscribers() - } - - assert.Len(t, m.dirty, 1) -} - -func TestManager_PostQueueFull(t *testing.T) { - m := &Manager{ - cmdq: make(chan cmd, 2), - stopChan: make(chan struct{}), - } - - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - - assert.Len(t, m.cmdq, 2) -} - -func TestManager_GetStateNilState(t *testing.T) { - m := &Manager{} - - s := m.GetState() - assert.NotNil(t, s.Outputs) - assert.NotNil(t, s.Layouts) - assert.Equal(t, uint32(0), s.TagCount) -} - -func TestTagState_Fields(t *testing.T) { - tag := TagState{ - Tag: 1, - State: 2, - Clients: 3, - Focused: 1, - } - - assert.Equal(t, uint32(1), tag.Tag) - assert.Equal(t, uint32(2), tag.State) - assert.Equal(t, uint32(3), tag.Clients) - assert.Equal(t, uint32(1), tag.Focused) -} - -func TestOutputState_Fields(t *testing.T) { - out := OutputState{ - Name: "eDP-1", - Active: 1, - Tags: []TagState{{Tag: 1}}, - Layout: 0, - LayoutSymbol: "[]=", - Title: "Firefox", - AppID: "firefox", - KbLayout: "us", - Keymode: "", - } - - assert.Equal(t, "eDP-1", out.Name) - assert.Equal(t, uint32(1), out.Active) - assert.Len(t, out.Tags, 1) - assert.Equal(t, "[]=", out.LayoutSymbol) -} - -func TestStateChanged_NewOutputAppears(t *testing.T) { - a := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Name: "eDP-1"}, - }, - } - b := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Name: "eDP-1"}, - "HDMI-A-1": {Name: "HDMI-A-1"}, - }, - } - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_TagsLengthDiffers(t *testing.T) { - a := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Tags: []TagState{{Tag: 1}}}, - }, - } - b := &State{ - TagCount: 9, - Layouts: []string{}, - Outputs: map[string]*OutputState{ - "eDP-1": {Tags: []TagState{{Tag: 1}, {Tag: 2}}}, - }, - } - assert.True(t, stateChanged(a, b)) -} - -func TestNewManager_GetRegistryError(t *testing.T) { - mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t) - - mockDisplay.EXPECT().Context().Return(nil) - mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry")) - - _, err := NewManager(mockDisplay) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get registry") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/types.go deleted file mode 100644 index 2b17537..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/dwl/types.go +++ /dev/null @@ -1,176 +0,0 @@ -package dwl - -import ( - "sync" - - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type TagState struct { - Tag uint32 `json:"tag"` - State uint32 `json:"state"` - Clients uint32 `json:"clients"` - Focused uint32 `json:"focused"` -} - -type OutputState struct { - Name string `json:"name"` - Active uint32 `json:"active"` - Tags []TagState `json:"tags"` - Layout uint32 `json:"layout"` - LayoutSymbol string `json:"layoutSymbol"` - Title string `json:"title"` - AppID string `json:"appId"` - KbLayout string `json:"kbLayout"` - Keymode string `json:"keymode"` -} - -type State struct { - Outputs map[string]*OutputState `json:"outputs"` - TagCount uint32 `json:"tagCount"` - Layouts []string `json:"layouts"` - ActiveOutput string `json:"activeOutput"` -} - -type cmd struct { - fn func() -} - -type Manager struct { - display wlclient.WaylandDisplay - ctx *wlclient.Context - registry *wlclient.Registry - manager any - - outputs syncmap.Map[uint32, *outputState] - - tagCount uint32 - layouts []string - - wlMutex sync.Mutex - cmdq chan cmd - outputSetupReq chan uint32 - stopChan chan struct{} - wg sync.WaitGroup - - subscribers syncmap.Map[string, chan State] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotified *State - - stateMutex sync.RWMutex - state *State -} - -type outputState struct { - id uint32 - registryName uint32 - output *wlclient.Output - ipcOutput any - name string - active uint32 - tags []TagState - layout uint32 - layoutSymbol string - title string - appID string - kbLayout string - keymode string -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{ - Outputs: make(map[string]*OutputState), - Layouts: []string{}, - TagCount: 0, - } - } - stateCopy := *m.state - return stateCopy -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - - m.subscribers.Store(id, ch) - - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func stateChanged(old, new *State) bool { - if old == nil || new == nil { - return true - } - if old.TagCount != new.TagCount { - return true - } - if len(old.Layouts) != len(new.Layouts) { - return true - } - if old.ActiveOutput != new.ActiveOutput { - return true - } - if len(old.Outputs) != len(new.Outputs) { - return true - } - - for name, newOut := range new.Outputs { - oldOut, exists := old.Outputs[name] - if !exists { - return true - } - if oldOut.Active != newOut.Active { - return true - } - if oldOut.Layout != newOut.Layout { - return true - } - if oldOut.LayoutSymbol != newOut.LayoutSymbol { - return true - } - if oldOut.Title != newOut.Title { - return true - } - if oldOut.AppID != newOut.AppID { - return true - } - if oldOut.KbLayout != newOut.KbLayout { - return true - } - if oldOut.Keymode != newOut.Keymode { - return true - } - if len(oldOut.Tags) != len(newOut.Tags) { - return true - } - for i, newTag := range newOut.Tags { - if i >= len(oldOut.Tags) { - return true - } - oldTag := oldOut.Tags[i] - if oldTag.Tag != newTag.Tag || oldTag.State != newTag.State || - oldTag.Clients != newTag.Clients || oldTag.Focused != newTag.Focused { - return true - } - } - } - - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go deleted file mode 100644 index 54a7bca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go +++ /dev/null @@ -1,20 +0,0 @@ -package evdev - -import ( - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request, m *Manager) { - switch req.Method { - case "evdev.getState": - handleGetState(conn, req, m) - default: - models.RespondError(conn, req.ID, "unknown method: "+req.Method) - } -} - -func handleGetState(conn net.Conn, req models.Request, m *Manager) { - models.Respond(conn, req.ID, m.GetState()) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go deleted file mode 100644 index f9bd21d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package evdev - -import ( - "bytes" - "encoding/json" - "errors" - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - mocks "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/evdev" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type mockNetConn struct { - net.Conn - readBuf *bytes.Buffer - writeBuf *bytes.Buffer - closed bool -} - -func newMockNetConn() *mockNetConn { - return &mockNetConn{ - readBuf: &bytes.Buffer{}, - writeBuf: &bytes.Buffer{}, - } -} - -func (m *mockNetConn) Read(b []byte) (n int, err error) { - return m.readBuf.Read(b) -} - -func (m *mockNetConn) Write(b []byte) (n int, err error) { - return m.writeBuf.Write(b) -} - -func (m *mockNetConn) Close() error { - m.closed = true - return nil -} - -func TestHandleRequest(t *testing.T) { - t.Run("getState request", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: true}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "evdev.getState", - Params: map[string]any{}, - } - - HandleRequest(conn, req, m) - - var resp models.Response[State] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Available) - assert.True(t, resp.Result.CapsLock) - }) - - t.Run("unknown method", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 456, - Method: "evdev.unknownMethod", - Params: map[string]any{}, - } - - HandleRequest(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 456, resp.ID) - assert.NotEmpty(t, resp.Error) - assert.Contains(t, resp.Error, "unknown method") - }) -} - -func TestHandleGetState(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 789, - Method: "evdev.getState", - Params: map[string]any{}, - } - - handleGetState(conn, req, m) - - var resp models.Response[State] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 789, resp.ID) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Available) - assert.False(t, resp.Result.CapsLock) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go deleted file mode 100644 index b578481..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go +++ /dev/null @@ -1,413 +0,0 @@ -package evdev - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/fsnotify/fsnotify" - evdev "github.com/holoplot/go-evdev" -) - -const ( - evKeyType = 0x01 - evLedType = 0x11 - keyCapslockKey = 58 - ledCapslockKey = 1 - keyStateOn = 1 -) - -type EvdevDevice interface { - Name() (string, error) - Path() string - Close() error - ReadOne() (*evdev.InputEvent, error) - State(t evdev.EvType) (evdev.StateMap, error) -} - -type Manager struct { - devices []EvdevDevice - devicesMutex sync.RWMutex - monitoredPaths map[string]bool - state State - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan State] - closeChan chan struct{} - closeOnce sync.Once - watcher *fsnotify.Watcher -} - -func NewManager() (*Manager, error) { - devices, err := findKeyboards() - if err != nil { - return nil, fmt.Errorf("failed to find keyboards: %w", err) - } - - initialCapsLock := readInitialCapsLockState(devices[0]) - - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Warnf("Failed to create fsnotify watcher, hotplug detection disabled: %v", err) - watcher = nil - } else if err := watcher.Add("/dev/input"); err != nil { - log.Warnf("Failed to watch /dev/input, hotplug detection disabled: %v", err) - watcher.Close() - watcher = nil - } - - monitoredPaths := make(map[string]bool) - for _, device := range devices { - monitoredPaths[device.Path()] = true - } - - m := &Manager{ - devices: devices, - monitoredPaths: monitoredPaths, - state: State{Available: true, CapsLock: initialCapsLock}, - - closeChan: make(chan struct{}), - watcher: watcher, - } - - for i, device := range devices { - go m.monitorDevice(device, i) - } - - if watcher != nil { - go m.watchForNewKeyboards() - } - - return m, nil -} - -func readInitialCapsLockState(device EvdevDevice) bool { - ledStates, err := device.State(evLedType) - if err != nil { - log.Debugf("Could not read LED state: %v", err) - return false - } - - return ledStates[ledCapslockKey] -} - -func findKeyboards() ([]EvdevDevice, error) { - pattern := "/dev/input/event*" - matches, err := filepath.Glob(pattern) - if err != nil { - return nil, fmt.Errorf("failed to glob input devices: %w", err) - } - - if len(matches) == 0 { - return nil, fmt.Errorf("no input devices found") - } - - var keyboards []EvdevDevice - for _, path := range matches { - device, err := evdev.Open(path) - if err != nil { - continue - } - - if !isKeyboard(device) { - device.Close() - continue - } - - deviceName, _ := device.Name() - log.Debugf("Found keyboard: %s at %s", deviceName, path) - keyboards = append(keyboards, device) - } - - if len(keyboards) == 0 { - return nil, fmt.Errorf("no keyboard device found") - } - - return keyboards, nil -} - -func isKeyboard(device EvdevDevice) bool { - deviceName, err := device.Name() - if err != nil { - return false - } - - name := strings.ToLower(deviceName) - - switch { - case strings.Contains(name, "keyboard"): - return true - case strings.Contains(name, "kbd"): - return true - case strings.Contains(name, "input") && strings.Contains(name, "key"): - return true - } - - keyStates, err := device.State(evKeyType) - if err != nil { - return false - } - - hasKeyA := len(keyStates) > 30 - hasKeyZ := len(keyStates) > 44 - hasEnter := len(keyStates) > 28 - - return hasKeyA && hasKeyZ && hasEnter && len(keyStates) > 100 -} - -func (m *Manager) watchForNewKeyboards() { - defer func() { - if r := recover(); r != nil { - log.Errorf("Panic in keyboard hotplug monitor: %v", r) - } - }() - - for { - select { - case <-m.closeChan: - return - case event, ok := <-m.watcher.Events: - if !ok { - return - } - - if !strings.HasPrefix(filepath.Base(event.Name), "event") { - continue - } - - if event.Op&fsnotify.Create == fsnotify.Create { - time.Sleep(100 * time.Millisecond) - - m.devicesMutex.Lock() - if m.monitoredPaths[event.Name] { - m.devicesMutex.Unlock() - continue - } - - device, err := evdev.Open(event.Name) - if err != nil { - m.devicesMutex.Unlock() - continue - } - - if !isKeyboard(device) { - device.Close() - m.devicesMutex.Unlock() - continue - } - - deviceName, _ := device.Name() - log.Debugf("Hotplugged keyboard: %s at %s", deviceName, event.Name) - - m.devices = append(m.devices, device) - m.monitoredPaths[event.Name] = true - deviceIndex := len(m.devices) - 1 - m.devicesMutex.Unlock() - - go m.monitorDevice(device, deviceIndex) - } else if event.Op&fsnotify.Remove == fsnotify.Remove { - m.devicesMutex.Lock() - if !m.monitoredPaths[event.Name] { - m.devicesMutex.Unlock() - continue - } - - delete(m.monitoredPaths, event.Name) - for i, device := range m.devices { - if device != nil && device.Path() == event.Name { - log.Debugf("Keyboard removed: %s", event.Name) - device.Close() - m.devices[i] = nil - break - } - } - m.devicesMutex.Unlock() - } - - case err, ok := <-m.watcher.Errors: - if !ok { - return - } - log.Warnf("Keyboard hotplug watcher error: %v", err) - } - } -} - -func (m *Manager) monitorDevice(device EvdevDevice, deviceIndex int) { - defer func() { - if r := recover(); r != nil { - log.Errorf("Panic in evdev monitor: %v", r) - } - }() - - for { - select { - case <-m.closeChan: - return - default: - } - - event, err := device.ReadOne() - if err != nil { - if isClosedError(err) { - return - } - log.Warnf("Failed to read evdev event: %v", err) - time.Sleep(100 * time.Millisecond) - continue - } - - if event == nil { - continue - } - - if event.Type == evKeyType && event.Code == keyCapslockKey && event.Value == keyStateOn { - time.Sleep(50 * time.Millisecond) - m.readAndUpdateCapsLockState(deviceIndex) - } else if event.Type == evLedType && event.Code == ledCapslockKey { - capsLockState := event.Value == keyStateOn - m.updateCapsLockStateDirect(capsLockState) - } - } -} - -func isClosedError(err error) bool { - if err == nil { - return false - } - - errStr := err.Error() - switch { - case strings.Contains(errStr, "closed"): - return true - case strings.Contains(errStr, "bad file descriptor"): - return true - default: - return false - } -} - -func (m *Manager) readAndUpdateCapsLockState(deviceIndex int) { - m.devicesMutex.RLock() - if deviceIndex >= len(m.devices) { - m.devicesMutex.RUnlock() - return - } - device := m.devices[deviceIndex] - m.devicesMutex.RUnlock() - - ledStates, err := device.State(evLedType) - if err != nil { - log.Warnf("Failed to read LED state: %v", err) - return - } - - if len(ledStates) == 0 { - log.Debug("No LED state available (empty map)") - - // This means the device either: - // - doesn't support LED reporting at all, or - // - the kernel returned an empty state - return - } - - capsLockState := ledStates[ledCapslockKey] - m.updateCapsLockStateDirect(capsLockState) -} - -func (m *Manager) updateCapsLockStateDirect(capsLockState bool) { - m.stateMutex.Lock() - if m.state.CapsLock == capsLockState { - m.stateMutex.Unlock() - return - } - - m.state.CapsLock = capsLockState - newState := m.state - m.stateMutex.Unlock() - - log.Debugf("Caps lock state: %v", newState.CapsLock) - m.notifySubscribers(newState) -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return m.state -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 16) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) notifySubscribers(state State) { - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (m *Manager) Close() { - m.closeOnce.Do(func() { - close(m.closeChan) - - if m.watcher != nil { - m.watcher.Close() - } - - m.devicesMutex.Lock() - for _, device := range m.devices { - if device == nil { - continue - } - if err := device.Close(); err != nil && !isClosedError(err) { - log.Warnf("Error closing evdev device: %v", err) - } - } - m.devicesMutex.Unlock() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - }) -} - -func InitializeManager() (*Manager, error) { - if os.Getuid() != 0 && !hasInputGroupAccess() { - return nil, fmt.Errorf("insufficient permissions to access input devices") - } - - return NewManager() -} - -func hasInputGroupAccess() bool { - pattern := "/dev/input/event*" - matches, err := filepath.Glob(pattern) - if err != nil || len(matches) == 0 { - return false - } - - testFile, err := os.Open(matches[0]) - if err != nil { - return false - } - testFile.Close() - return true -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go deleted file mode 100644 index 667c078..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go +++ /dev/null @@ -1,344 +0,0 @@ -package evdev - -import ( - "errors" - "testing" - - evdev "github.com/holoplot/go-evdev" - "github.com/stretchr/testify/assert" - - mocks "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/evdev" -) - -func TestManager_Creation(t *testing.T) { - t.Run("manager created successfully with caps lock off", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - assert.NotNil(t, m) - assert.True(t, m.state.Available) - assert.False(t, m.state.CapsLock) - }) - - t.Run("manager created successfully with caps lock on", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: true}, - closeChan: make(chan struct{}), - } - - assert.NotNil(t, m) - assert.True(t, m.state.Available) - assert.True(t, m.state.CapsLock) - }) -} - -func TestManager_GetState(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - state := m.GetState() - assert.True(t, state.Available) - assert.False(t, state.CapsLock) -} - -func TestManager_Subscribe(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - assert.NotNil(t, ch) - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 1, count) -} - -func TestManager_Unsubscribe(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 1, count) - - m.Unsubscribe("test-client") - count = 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 0, count) - - select { - case _, ok := <-ch: - assert.False(t, ok, "channel should be closed") - default: - t.Error("channel should be closed") - } -} - -func TestManager_UpdateCapsLock(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - - ledStateOn := evdev.StateMap{ledCapslockKey: true} - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledStateOn, nil).Once() - - go func() { - m.readAndUpdateCapsLockState(0) - }() - - newState := <-ch - assert.True(t, newState.CapsLock) - - ledStateOff := evdev.StateMap{ledCapslockKey: false} - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledStateOff, nil).Once() - - go func() { - m.readAndUpdateCapsLockState(0) - }() - - newState = <-ch - assert.False(t, newState.CapsLock) -} - -func TestManager_Close(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Close().Return(nil).Once() - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch1 := m.Subscribe("client1") - ch2 := m.Subscribe("client2") - - m.Close() - - select { - case _, ok := <-ch1: - assert.False(t, ok, "channel 1 should be closed") - default: - t.Error("channel 1 should be closed") - } - - select { - case _, ok := <-ch2: - assert.False(t, ok, "channel 2 should be closed") - default: - t.Error("channel 2 should be closed") - } - - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 0, count) - - m.Close() -} - -func TestIsKeyboard(t *testing.T) { - tests := []struct { - name string - devName string - expected bool - }{ - {"keyboard in name", "AT Translated Set 2 keyboard", true}, - {"kbd in name", "USB kbd", true}, - {"input and key", "input key device", true}, - {"random device", "Mouse", false}, - {"empty name", "", false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Name().Return(tt.devName, nil).Once() - - if !tt.expected { - mockDevice.EXPECT().State(evdev.EvType(evKeyType)).Return(evdev.StateMap{}, nil).Maybe() - } - - result := isKeyboard(mockDevice) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestIsKeyboard_ErrorHandling(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Name().Return("", errors.New("device error")).Once() - - result := isKeyboard(mockDevice) - assert.False(t, result) -} - -func TestManager_MonitorDevice(t *testing.T) { - t.Run("caps lock key press updates state", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - - capsLockEvent := &evdev.InputEvent{ - Type: evKeyType, - Code: keyCapslockKey, - Value: keyStateOn, - } - - ledState := evdev.StateMap{ledCapslockKey: true} - - mockDevice.EXPECT().ReadOne().Return(capsLockEvent, nil).Once() - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("stop")).Maybe() - mockDevice.EXPECT().Close().Return(nil).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test") - - go m.monitorDevice(mockDevice, 0) - - state := <-ch - assert.True(t, state.CapsLock) - - m.Close() - }) -} - -func TestIsClosedError(t *testing.T) { - tests := []struct { - name string - err error - expected bool - }{ - {"nil error", nil, false}, - {"closed error", errors.New("device closed"), true}, - {"bad file descriptor", errors.New("bad file descriptor"), true}, - {"other error", errors.New("some other error"), false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := isClosedError(tt.err) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestNotifySubscribers(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - mockDevice.EXPECT().Close().Return(nil).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch1 := m.Subscribe("client1") - ch2 := m.Subscribe("client2") - - newState := State{Available: true, CapsLock: true} - go m.notifySubscribers(newState) - - state1 := <-ch1 - state2 := <-ch2 - - assert.Equal(t, newState, state1) - assert.Equal(t, newState, state2) - - m.Close() -} - -func TestReadInitialCapsLockState(t *testing.T) { - t.Run("caps lock is on", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - ledState := evdev.StateMap{ - ledCapslockKey: true, - } - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - - result := readInitialCapsLockState(mockDevice) - assert.True(t, result) - }) - - t.Run("caps lock is off", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - ledState := evdev.StateMap{ - ledCapslockKey: false, - } - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - - result := readInitialCapsLockState(mockDevice) - assert.False(t, result) - }) - - t.Run("error reading LED state", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(nil, errors.New("read error")).Once() - - result := readInitialCapsLockState(mockDevice) - assert.False(t, result) - }) -} - -func TestHasInputGroupAccess(t *testing.T) { - result := hasInputGroupAccess() - t.Logf("hasInputGroupAccess: %v", result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/models.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/models.go deleted file mode 100644 index df8ec9e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/evdev/models.go +++ /dev/null @@ -1,6 +0,0 @@ -package evdev - -type State struct { - Available bool `json:"available"` - CapsLock bool `json:"capsLock"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/handlers.go deleted file mode 100644 index 3f7e17f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/handlers.go +++ /dev/null @@ -1,134 +0,0 @@ -package extworkspace - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type SuccessResult struct { - Success bool `json:"success"` - Message string `json:"message"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - if manager == nil { - models.RespondError(conn, req.ID, "extworkspace manager not initialized") - return - } - - switch req.Method { - case "extworkspace.getState": - handleGetState(conn, req, manager) - case "extworkspace.activateWorkspace": - handleActivateWorkspace(conn, req, manager) - case "extworkspace.deactivateWorkspace": - handleDeactivateWorkspace(conn, req, manager) - case "extworkspace.removeWorkspace": - handleRemoveWorkspace(conn, req, manager) - case "extworkspace.createWorkspace": - handleCreateWorkspace(conn, req, manager) - case "extworkspace.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - state := manager.GetState() - models.Respond(conn, req.ID, state) -} - -func handleActivateWorkspace(conn net.Conn, req models.Request, manager *Manager) { - groupID := models.GetOr(req, "groupID", "") - workspaceID, ok := models.Get[string](req, "workspaceID") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'workspaceID' parameter") - return - } - - if err := manager.ActivateWorkspace(groupID, workspaceID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "workspace activated"}) -} - -func handleDeactivateWorkspace(conn net.Conn, req models.Request, manager *Manager) { - groupID := models.GetOr(req, "groupID", "") - workspaceID, ok := models.Get[string](req, "workspaceID") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'workspaceID' parameter") - return - } - - if err := manager.DeactivateWorkspace(groupID, workspaceID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "workspace deactivated"}) -} - -func handleRemoveWorkspace(conn net.Conn, req models.Request, manager *Manager) { - groupID := models.GetOr(req, "groupID", "") - workspaceID, ok := models.Get[string](req, "workspaceID") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'workspaceID' parameter") - return - } - - if err := manager.RemoveWorkspace(groupID, workspaceID); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "workspace removed"}) -} - -func handleCreateWorkspace(conn net.Conn, req models.Request, manager *Manager) { - groupID, ok := models.Get[string](req, "groupID") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'groupID' parameter") - return - } - - workspaceName, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - if err := manager.CreateWorkspace(groupID, workspaceName); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "workspace create requested"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range stateChan { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - Result: &state, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager.go deleted file mode 100644 index b791b39..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager.go +++ /dev/null @@ -1,598 +0,0 @@ -package extworkspace - -import ( - "fmt" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_workspace" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -func CheckCapability() bool { - display, err := wlclient.Connect("") - if err != nil { - return false - } - defer display.Destroy() - - registry, err := display.GetRegistry() - if err != nil { - return false - } - defer registry.Destroy() - - found := false - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - if e.Interface == ext_workspace.ExtWorkspaceManagerV1InterfaceName { - found = true - } - }) - - // Roundtrip to ensure all registry events are processed - if err := display.Roundtrip(); err != nil { - return false - } - - return found -} - -func NewManager(display wlclient.WaylandDisplay) (*Manager, error) { - m := &Manager{ - display: display, - ctx: display.Context(), - cmdq: make(chan cmd, 128), - stopChan: make(chan struct{}), - - dirty: make(chan struct{}, 1), - } - - m.wg.Add(1) - go m.waylandActor() - - if err := m.setupRegistry(); err != nil { - close(m.stopChan) - m.wg.Wait() - return nil, err - } - - m.updateState() - - m.notifierWg.Add(1) - go m.notifier() - - return m, nil -} - -func (m *Manager) post(fn func()) { - select { - case m.cmdq <- cmd{fn: fn}: - default: - log.Warn("ExtWorkspace actor command queue full, dropping command") - } -} - -func (m *Manager) waylandActor() { - defer m.wg.Done() - - for { - select { - case <-m.stopChan: - return - case c := <-m.cmdq: - c.fn() - } - } -} - -func (m *Manager) setupRegistry() error { - log.Info("ExtWorkspace: starting registry setup") - - registry, err := m.display.GetRegistry() - if err != nil { - return fmt.Errorf("failed to get registry: %w", err) - } - m.registry = registry - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - if e.Interface == "wl_output" { - output := wlclient.NewOutput(m.ctx) - if err := registry.Bind(e.Name, e.Interface, 4, output); err == nil { - outputID := output.ID() - - output.SetNameHandler(func(ev wlclient.OutputNameEvent) { - m.outputNames.Store(outputID, ev.Name) - log.Debugf("ExtWorkspace: Output %d (%s) name received", outputID, ev.Name) - m.post(func() { - m.updateState() - }) - }) - } - return - } - - if e.Interface == ext_workspace.ExtWorkspaceManagerV1InterfaceName { - log.Infof("ExtWorkspace: found %s", ext_workspace.ExtWorkspaceManagerV1InterfaceName) - manager := ext_workspace.NewExtWorkspaceManagerV1(m.ctx) - version := e.Version - if version > 1 { - version = 1 - } - - manager.SetWorkspaceGroupHandler(func(e ext_workspace.ExtWorkspaceManagerV1WorkspaceGroupEvent) { - m.handleWorkspaceGroup(e) - }) - - manager.SetWorkspaceHandler(func(e ext_workspace.ExtWorkspaceManagerV1WorkspaceEvent) { - m.handleWorkspace(e) - }) - - manager.SetDoneHandler(func(e ext_workspace.ExtWorkspaceManagerV1DoneEvent) { - log.Debug("ExtWorkspace: done event received") - m.post(func() { - m.updateState() - }) - }) - - manager.SetFinishedHandler(func(e ext_workspace.ExtWorkspaceManagerV1FinishedEvent) { - log.Info("ExtWorkspace: finished event received") - }) - - if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil { - m.manager = manager - log.Info("ExtWorkspace: manager bound successfully") - } else { - log.Errorf("ExtWorkspace: failed to bind manager: %v", err) - } - } - }) - - log.Info("ExtWorkspace: registry setup complete (events will be processed async)") - return nil -} - -func (m *Manager) handleWorkspaceGroup(e ext_workspace.ExtWorkspaceManagerV1WorkspaceGroupEvent) { - handle := e.WorkspaceGroup - groupID := handle.ID() - - log.Debugf("ExtWorkspace: New workspace group (id=%d)", groupID) - - group := &workspaceGroupState{ - id: groupID, - handle: handle, - outputIDs: make(map[uint32]bool), - workspaceIDs: make([]uint32, 0), - } - - m.groups.Store(groupID, group) - - handle.SetCapabilitiesHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1CapabilitiesEvent) { - log.Debugf("ExtWorkspace: Group %d capabilities: %d", groupID, e.Capabilities) - }) - - handle.SetOutputEnterHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1OutputEnterEvent) { - outputID := e.Output.ID() - log.Debugf("ExtWorkspace: Group %d output enter (output=%d)", groupID, outputID) - - m.post(func() { - group.outputIDs[outputID] = true - m.updateState() - }) - }) - - handle.SetOutputLeaveHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1OutputLeaveEvent) { - outputID := e.Output.ID() - log.Debugf("ExtWorkspace: Group %d output leave (output=%d)", groupID, outputID) - m.post(func() { - delete(group.outputIDs, outputID) - m.updateState() - }) - }) - - handle.SetWorkspaceEnterHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1WorkspaceEnterEvent) { - workspaceID := e.Workspace.ID() - log.Debugf("ExtWorkspace: Group %d workspace enter (workspace=%d)", groupID, workspaceID) - - m.post(func() { - if ws, ok := m.workspaces.Load(workspaceID); ok { - ws.groupID = groupID - } - - group.workspaceIDs = append(group.workspaceIDs, workspaceID) - m.updateState() - }) - }) - - handle.SetWorkspaceLeaveHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1WorkspaceLeaveEvent) { - workspaceID := e.Workspace.ID() - log.Debugf("ExtWorkspace: Group %d workspace leave (workspace=%d)", groupID, workspaceID) - - m.post(func() { - if ws, ok := m.workspaces.Load(workspaceID); ok { - ws.groupID = 0 - } - - for i, id := range group.workspaceIDs { - if id == workspaceID { - group.workspaceIDs = append(group.workspaceIDs[:i], group.workspaceIDs[i+1:]...) - break - } - } - m.updateState() - }) - }) - - handle.SetRemovedHandler(func(e ext_workspace.ExtWorkspaceGroupHandleV1RemovedEvent) { - log.Debugf("ExtWorkspace: Group %d removed", groupID) - - m.post(func() { - group.removed = true - - m.groups.Delete(groupID) - - m.wlMutex.Lock() - handle.Destroy() - m.wlMutex.Unlock() - - m.updateState() - }) - }) -} - -func (m *Manager) handleWorkspace(e ext_workspace.ExtWorkspaceManagerV1WorkspaceEvent) { - handle := e.Workspace - workspaceID := handle.ID() - - log.Debugf("ExtWorkspace: New workspace (proxy_id=%d)", workspaceID) - - ws := &workspaceState{ - id: workspaceID, - handle: handle, - coordinates: make([]uint32, 0), - } - - m.workspaces.Store(workspaceID, ws) - - handle.SetIdHandler(func(e ext_workspace.ExtWorkspaceHandleV1IdEvent) { - log.Debugf("ExtWorkspace: Workspace %d id: %s", workspaceID, e.Id) - m.post(func() { - ws.workspaceID = e.Id - m.updateState() - }) - }) - - handle.SetNameHandler(func(e ext_workspace.ExtWorkspaceHandleV1NameEvent) { - log.Debugf("ExtWorkspace: Workspace %d name: %s", workspaceID, e.Name) - m.post(func() { - ws.name = e.Name - m.updateState() - }) - }) - - handle.SetCoordinatesHandler(func(e ext_workspace.ExtWorkspaceHandleV1CoordinatesEvent) { - coords := make([]uint32, 0) - for i := 0; i < len(e.Coordinates); i += 4 { - if i+4 <= len(e.Coordinates) { - val := uint32(e.Coordinates[i]) | - uint32(e.Coordinates[i+1])<<8 | - uint32(e.Coordinates[i+2])<<16 | - uint32(e.Coordinates[i+3])<<24 - coords = append(coords, val) - } - } - log.Debugf("ExtWorkspace: Workspace %d coordinates: %v", workspaceID, coords) - m.post(func() { - ws.coordinates = coords - m.updateState() - }) - }) - - handle.SetStateHandler(func(e ext_workspace.ExtWorkspaceHandleV1StateEvent) { - log.Debugf("ExtWorkspace: Workspace %d state: %d", workspaceID, e.State) - m.post(func() { - ws.state = e.State - m.updateState() - }) - }) - - handle.SetCapabilitiesHandler(func(e ext_workspace.ExtWorkspaceHandleV1CapabilitiesEvent) { - log.Debugf("ExtWorkspace: Workspace %d capabilities: %d", workspaceID, e.Capabilities) - }) - - handle.SetRemovedHandler(func(e ext_workspace.ExtWorkspaceHandleV1RemovedEvent) { - log.Debugf("ExtWorkspace: Workspace %d removed", workspaceID) - - m.post(func() { - ws.removed = true - - m.workspaces.Delete(workspaceID) - - m.wlMutex.Lock() - handle.Destroy() - m.wlMutex.Unlock() - - m.updateState() - }) - }) -} - -func (m *Manager) updateState() { - groups := make([]*WorkspaceGroup, 0) - - m.groups.Range(func(key uint32, group *workspaceGroupState) bool { - if group.removed { - return true - } - - outputs := make([]string, 0) - for outputID := range group.outputIDs { - if name, ok := m.outputNames.Load(outputID); ok && name != "" { - outputs = append(outputs, name) - } - } - - workspaces := make([]*Workspace, 0) - for _, wsID := range group.workspaceIDs { - ws, exists := m.workspaces.Load(wsID) - if !exists { - continue - } - if ws.removed { - continue - } - - workspace := &Workspace{ - ID: ws.workspaceID, - Name: ws.name, - Coordinates: ws.coordinates, - State: ws.state, - Active: ws.state&uint32(ext_workspace.ExtWorkspaceHandleV1StateActive) != 0, - Urgent: ws.state&uint32(ext_workspace.ExtWorkspaceHandleV1StateUrgent) != 0, - Hidden: ws.state&uint32(ext_workspace.ExtWorkspaceHandleV1StateHidden) != 0, - } - workspaces = append(workspaces, workspace) - } - - groupState := &WorkspaceGroup{ - ID: fmt.Sprintf("group-%d", group.id), - Outputs: outputs, - Workspaces: workspaces, - } - groups = append(groups, groupState) - return true - }) - - newState := State{ - Groups: groups, - } - - m.stateMutex.Lock() - m.state = &newState - m.stateMutex.Unlock() - - m.notifySubscribers() -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.GetState() - - if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- currentState: - default: - log.Warn("ExtWorkspace: subscriber channel full, dropping update") - } - return true - }) - - stateCopy := currentState - m.lastNotified = &stateCopy - pending = false - } - } -} - -func (m *Manager) ActivateWorkspace(groupID, workspaceID string) error { - errChan := make(chan error, 1) - - m.post(func() { - var targetGroupID uint32 - if groupID != "" { - var parsedID uint32 - if _, err := fmt.Sscanf(groupID, "group-%d", &parsedID); err == nil { - targetGroupID = parsedID - } - } - - var found bool - m.workspaces.Range(func(key uint32, ws *workspaceState) bool { - if targetGroupID != 0 && ws.groupID != targetGroupID { - return true - } - if ws.workspaceID == workspaceID || ws.name == workspaceID { - m.wlMutex.Lock() - err := ws.handle.Activate() - if err == nil { - err = m.manager.Commit() - } - m.wlMutex.Unlock() - errChan <- err - found = true - return false - } - return true - }) - - if !found { - errChan <- fmt.Errorf("workspace not found: %s in group %s", workspaceID, groupID) - } - }) - - return <-errChan -} - -func (m *Manager) DeactivateWorkspace(groupID, workspaceID string) error { - errChan := make(chan error, 1) - - m.post(func() { - var targetGroupID uint32 - if groupID != "" { - var parsedID uint32 - if _, err := fmt.Sscanf(groupID, "group-%d", &parsedID); err == nil { - targetGroupID = parsedID - } - } - - var found bool - m.workspaces.Range(func(key uint32, ws *workspaceState) bool { - if targetGroupID != 0 && ws.groupID != targetGroupID { - return true - } - if ws.workspaceID == workspaceID || ws.name == workspaceID { - m.wlMutex.Lock() - err := ws.handle.Deactivate() - if err == nil { - err = m.manager.Commit() - } - m.wlMutex.Unlock() - errChan <- err - found = true - return false - } - return true - }) - - if !found { - errChan <- fmt.Errorf("workspace not found: %s in group %s", workspaceID, groupID) - } - }) - - return <-errChan -} - -func (m *Manager) RemoveWorkspace(groupID, workspaceID string) error { - errChan := make(chan error, 1) - - m.post(func() { - var targetGroupID uint32 - if groupID != "" { - var parsedID uint32 - if _, err := fmt.Sscanf(groupID, "group-%d", &parsedID); err == nil { - targetGroupID = parsedID - } - } - - var found bool - m.workspaces.Range(func(key uint32, ws *workspaceState) bool { - if targetGroupID != 0 && ws.groupID != targetGroupID { - return true - } - if ws.workspaceID == workspaceID || ws.name == workspaceID { - m.wlMutex.Lock() - err := ws.handle.Remove() - if err == nil { - err = m.manager.Commit() - } - m.wlMutex.Unlock() - errChan <- err - found = true - return false - } - return true - }) - - if !found { - errChan <- fmt.Errorf("workspace not found: %s in group %s", workspaceID, groupID) - } - }) - - return <-errChan -} - -func (m *Manager) CreateWorkspace(groupID, workspaceName string) error { - errChan := make(chan error, 1) - - m.post(func() { - var found bool - m.groups.Range(func(key uint32, group *workspaceGroupState) bool { - if fmt.Sprintf("group-%d", group.id) == groupID { - m.wlMutex.Lock() - err := group.handle.CreateWorkspace(workspaceName) - if err == nil { - err = m.manager.Commit() - } - m.wlMutex.Unlock() - errChan <- err - found = true - return false - } - return true - }) - - if !found { - errChan <- fmt.Errorf("workspace group not found: %s", groupID) - } - }) - - return <-errChan -} - -func (m *Manager) Close() { - close(m.stopChan) - m.wg.Wait() - m.notifierWg.Wait() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.workspaces.Range(func(key uint32, ws *workspaceState) bool { - if ws.handle != nil { - ws.handle.Destroy() - } - m.workspaces.Delete(key) - return true - }) - - m.groups.Range(func(key uint32, group *workspaceGroupState) bool { - if group.handle != nil { - group.handle.Destroy() - } - m.groups.Delete(key) - return true - }) - - if m.manager != nil { - m.manager.Stop() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager_test.go deleted file mode 100644 index b20d457..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/manager_test.go +++ /dev/null @@ -1,392 +0,0 @@ -package extworkspace - -import ( - "errors" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient" -) - -func TestStateChanged_BothNil(t *testing.T) { - assert.True(t, stateChanged(nil, nil)) -} - -func TestStateChanged_OneNil(t *testing.T) { - s := &State{Groups: []*WorkspaceGroup{}} - assert.True(t, stateChanged(s, nil)) - assert.True(t, stateChanged(nil, s)) -} - -func TestStateChanged_GroupCountDiffers(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ID: "group-1"}}} - b := &State{Groups: []*WorkspaceGroup{}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_GroupIDDiffers(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{}, Workspaces: []*Workspace{}}}} - b := &State{Groups: []*WorkspaceGroup{{ID: "group-2", Outputs: []string{}, Workspaces: []*Workspace{}}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputCountDiffers(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}, Workspaces: []*Workspace{}}}} - b := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{}, Workspaces: []*Workspace{}}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputNameDiffers(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}, Workspaces: []*Workspace{}}}} - b := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"HDMI-A-1"}, Workspaces: []*Workspace{}}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_WorkspaceCountDiffers(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{{ID: "1", Name: "ws1"}}, - }}} - b := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{}, - }}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_WorkspaceFieldsDiffer(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{{ - ID: "1", Name: "ws1", State: 0, Active: false, Urgent: false, Hidden: false, - }}, - }}} - b := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{{ - ID: "2", Name: "ws1", State: 0, Active: false, Urgent: false, Hidden: false, - }}, - }}} - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].ID = "1" - b.Groups[0].Workspaces[0].Name = "ws2" - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].Name = "ws1" - b.Groups[0].Workspaces[0].State = 1 - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].State = 0 - b.Groups[0].Workspaces[0].Active = true - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].Active = false - b.Groups[0].Workspaces[0].Urgent = true - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].Urgent = false - b.Groups[0].Workspaces[0].Hidden = true - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_WorkspaceCoordinatesDiffer(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{{ - ID: "1", Name: "ws1", Coordinates: []uint32{0, 0}, - }}, - }}} - b := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{}, - Workspaces: []*Workspace{{ - ID: "1", Name: "ws1", Coordinates: []uint32{1, 0}, - }}, - }}} - assert.True(t, stateChanged(a, b)) - - b.Groups[0].Workspaces[0].Coordinates = []uint32{0} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_Equal(t *testing.T) { - a := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{"eDP-1", "HDMI-A-1"}, - Workspaces: []*Workspace{ - {ID: "1", Name: "ws1", Coordinates: []uint32{0, 0}, State: 1, Active: true}, - {ID: "2", Name: "ws2", Coordinates: []uint32{1, 0}, State: 0, Active: false}, - }, - }}} - b := &State{Groups: []*WorkspaceGroup{{ - ID: "group-1", - Outputs: []string{"eDP-1", "HDMI-A-1"}, - Workspaces: []*Workspace{ - {ID: "1", Name: "ws1", Coordinates: []uint32{0, 0}, State: 1, Active: true}, - {ID: "2", Name: "ws2", Coordinates: []uint32{1, 0}, State: 0, Active: false}, - }, - }}} - assert.False(t, stateChanged(a, b)) -} - -func TestManager_ConcurrentGetState(t *testing.T) { - m := &Manager{ - state: &State{ - Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}}}, - }, - } - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - s := m.GetState() - _ = s.Groups - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.stateMutex.Lock() - m.state = &State{ - Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}}}, - } - m.stateMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentSubscriberAccess(t *testing.T) { - m := &Manager{ - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - var wg sync.WaitGroup - const goroutines = 20 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - subID := string(rune('a' + id)) - ch := m.Subscribe(subID) - assert.NotNil(t, ch) - time.Sleep(time.Millisecond) - m.Unsubscribe(subID) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapGroupsConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &workspaceGroupState{ - id: key, - outputIDs: map[uint32]bool{1: true}, - workspaceIDs: []uint32{uint32(j)}, - } - m.groups.Store(key, state) - - if loaded, ok := m.groups.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.groups.Range(func(k uint32, v *workspaceGroupState) bool { - _ = v.id - _ = v.outputIDs - return true - }) - } - - m.groups.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapWorkspacesConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &workspaceState{ - id: key, - workspaceID: "ws-1", - name: "workspace", - state: uint32(j % 4), - coordinates: []uint32{uint32(j), 0}, - } - m.workspaces.Store(key, state) - - if loaded, ok := m.workspaces.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.workspaces.Range(func(k uint32, v *workspaceState) bool { - _ = v.name - _ = v.state - return true - }) - } - - m.workspaces.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapOutputNamesConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - m.outputNames.Store(key, "eDP-1") - - if loaded, ok := m.outputNames.Load(key); ok { - assert.NotEmpty(t, loaded) - } - - m.outputNames.Range(func(k uint32, v string) bool { - _ = v - return true - }) - } - - m.outputNames.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_NotifySubscribersNonBlocking(t *testing.T) { - m := &Manager{ - dirty: make(chan struct{}, 1), - } - - for i := 0; i < 10; i++ { - m.notifySubscribers() - } - - assert.Len(t, m.dirty, 1) -} - -func TestManager_PostQueueFull(t *testing.T) { - m := &Manager{ - cmdq: make(chan cmd, 2), - stopChan: make(chan struct{}), - } - - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - - assert.Len(t, m.cmdq, 2) -} - -func TestManager_GetStateNilState(t *testing.T) { - m := &Manager{} - - s := m.GetState() - assert.NotNil(t, s.Groups) - assert.Empty(t, s.Groups) -} - -func TestWorkspace_Fields(t *testing.T) { - ws := Workspace{ - ID: "ws-1", - Name: "workspace 1", - Coordinates: []uint32{0, 0}, - State: 1, - Active: true, - Urgent: false, - Hidden: false, - } - - assert.Equal(t, "ws-1", ws.ID) - assert.Equal(t, "workspace 1", ws.Name) - assert.True(t, ws.Active) - assert.False(t, ws.Urgent) - assert.False(t, ws.Hidden) -} - -func TestWorkspaceGroup_Fields(t *testing.T) { - group := WorkspaceGroup{ - ID: "group-1", - Outputs: []string{"eDP-1", "HDMI-A-1"}, - Workspaces: []*Workspace{ - {ID: "ws-1", Name: "workspace 1"}, - }, - } - - assert.Equal(t, "group-1", group.ID) - assert.Len(t, group.Outputs, 2) - assert.Len(t, group.Workspaces, 1) -} - -func TestNewManager_GetRegistryError(t *testing.T) { - mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t) - - mockDisplay.EXPECT().Context().Return(nil) - mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry")) - - _, err := NewManager(mockDisplay) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get registry") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/types.go deleted file mode 100644 index 903a1cb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/extworkspace/types.go +++ /dev/null @@ -1,169 +0,0 @@ -package extworkspace - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_workspace" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type Workspace struct { - ID string `json:"id"` - Name string `json:"name"` - Coordinates []uint32 `json:"coordinates"` - State uint32 `json:"state"` - Active bool `json:"active"` - Urgent bool `json:"urgent"` - Hidden bool `json:"hidden"` -} - -type WorkspaceGroup struct { - ID string `json:"id"` - Outputs []string `json:"outputs"` - Workspaces []*Workspace `json:"workspaces"` -} - -type State struct { - Groups []*WorkspaceGroup `json:"groups"` -} - -type cmd struct { - fn func() -} - -type Manager struct { - display wlclient.WaylandDisplay - ctx *wlclient.Context - registry *wlclient.Registry - manager *ext_workspace.ExtWorkspaceManagerV1 - - outputNames syncmap.Map[uint32, string] - - groups syncmap.Map[uint32, *workspaceGroupState] - - workspaces syncmap.Map[uint32, *workspaceState] - - wlMutex sync.Mutex - cmdq chan cmd - stopChan chan struct{} - wg sync.WaitGroup - - subscribers syncmap.Map[string, chan State] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotified *State - - stateMutex sync.RWMutex - state *State -} - -type workspaceGroupState struct { - id uint32 - handle *ext_workspace.ExtWorkspaceGroupHandleV1 - outputIDs map[uint32]bool - workspaceIDs []uint32 - removed bool -} - -type workspaceState struct { - id uint32 - handle *ext_workspace.ExtWorkspaceHandleV1 - workspaceID string - name string - coordinates []uint32 - state uint32 - groupID uint32 - removed bool -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{ - Groups: []*WorkspaceGroup{}, - } - } - stateCopy := *m.state - return stateCopy -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - - m.subscribers.Store(id, ch) - - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if ch, ok := m.subscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func stateChanged(old, new *State) bool { - if old == nil || new == nil { - return true - } - if len(old.Groups) != len(new.Groups) { - return true - } - - for i, newGroup := range new.Groups { - if i >= len(old.Groups) { - return true - } - oldGroup := old.Groups[i] - if oldGroup.ID != newGroup.ID { - return true - } - if len(oldGroup.Outputs) != len(newGroup.Outputs) { - return true - } - for j, newOutput := range newGroup.Outputs { - if j >= len(oldGroup.Outputs) { - return true - } - if oldGroup.Outputs[j] != newOutput { - return true - } - } - if len(oldGroup.Workspaces) != len(newGroup.Workspaces) { - return true - } - for j, newWs := range newGroup.Workspaces { - if j >= len(oldGroup.Workspaces) { - return true - } - oldWs := oldGroup.Workspaces[j] - if oldWs.ID != newWs.ID || oldWs.Name != newWs.Name || oldWs.State != newWs.State { - return true - } - if oldWs.Active != newWs.Active || oldWs.Urgent != newWs.Urgent || oldWs.Hidden != newWs.Hidden { - return true - } - if len(oldWs.Coordinates) != len(newWs.Coordinates) { - return true - } - for k, coord := range newWs.Coordinates { - if k >= len(oldWs.Coordinates) { - return true - } - if oldWs.Coordinates[k] != coord { - return true - } - } - } - } - - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions.go deleted file mode 100644 index 52515d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions.go +++ /dev/null @@ -1,112 +0,0 @@ -package freedesktop - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/godbus/dbus/v5" -) - -func (m *Manager) SetIconFile(iconPath string) error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - err := m.accountsObj.Call(dbusAccountsUserInterface+".SetIconFile", 0, iconPath).Err - if err != nil { - return fmt.Errorf("failed to set icon file: %w", err) - } - - m.updateAccountsState() - return nil -} - -func (m *Manager) SetRealName(name string) error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - err := m.accountsObj.Call(dbusAccountsUserInterface+".SetRealName", 0, name).Err - if err != nil { - return fmt.Errorf("failed to set real name: %w", err) - } - - m.updateAccountsState() - return nil -} - -func (m *Manager) SetEmail(email string) error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - err := m.accountsObj.Call(dbusAccountsUserInterface+".SetEmail", 0, email).Err - if err != nil { - return fmt.Errorf("failed to set email: %w", err) - } - - m.updateAccountsState() - return nil -} - -func (m *Manager) SetLanguage(language string) error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - err := m.accountsObj.Call(dbusAccountsUserInterface+".SetLanguage", 0, language).Err - if err != nil { - return fmt.Errorf("failed to set language: %w", err) - } - - m.updateAccountsState() - return nil -} - -func (m *Manager) SetLocation(location string) error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - err := m.accountsObj.Call(dbusAccountsUserInterface+".SetLocation", 0, location).Err - if err != nil { - return fmt.Errorf("failed to set location: %w", err) - } - - m.updateAccountsState() - return nil -} - -func (m *Manager) GetUserIconFile(username string) (string, error) { - if m.systemConn == nil { - return "", fmt.Errorf("accounts service not available") - } - - accountsManager := m.systemConn.Object(dbusAccountsDest, dbus.ObjectPath(dbusAccountsPath)) - - var userPath dbus.ObjectPath - err := accountsManager.Call(dbusAccountsInterface+".FindUserByName", 0, username).Store(&userPath) - if err != nil { - return "", fmt.Errorf("user not found: %w", err) - } - - userObj := m.systemConn.Object(dbusAccountsDest, userPath) - variant, err := userObj.GetProperty(dbusAccountsUserInterface + ".IconFile") - if err != nil { - return "", err - } - - var iconFile string - if err := variant.Store(&iconFile); err != nil { - return "", err - } - - return iconFile, nil -} - -func (m *Manager) SetIconTheme(iconTheme string) error { - if err := utils.GsettingsSet("org.gnome.desktop.interface", "icon-theme", iconTheme); err != nil { - return fmt.Errorf("failed to set icon theme: %w", err) - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions_test.go deleted file mode 100644 index e2c21e8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/actions_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package freedesktop - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestManager_SetIconFile(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.SetIconFile("/path/to/icon.png") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_SetRealName(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.SetRealName("New Name") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_SetEmail(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.SetEmail("test@example.com") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_SetLanguage(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.SetLanguage("en_US.UTF-8") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_SetLocation(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.SetLocation("Test Location") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_GetUserIconFile(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - iconFile, err := manager.GetUserIconFile("testuser") - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - assert.Empty(t, iconFile) - }) -} - -func TestManager_UpdateAccountsState(t *testing.T) { - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.updateAccountsState() - assert.Error(t, err) - assert.Contains(t, err.Error(), "accounts service not available") - }) -} - -func TestManager_UpdateSettingsState(t *testing.T) { - t.Run("settings not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Settings: SettingsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - err := manager.updateSettingsState() - assert.Error(t, err) - assert.Contains(t, err.Error(), "settings portal not available") - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/constants.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/constants.go deleted file mode 100644 index 12db87b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/constants.go +++ /dev/null @@ -1,23 +0,0 @@ -package freedesktop - -const ( - dbusAccountsDest = "org.freedesktop.Accounts" - dbusAccountsPath = "/org/freedesktop/Accounts" - dbusAccountsInterface = "org.freedesktop.Accounts" - dbusAccountsUserInterface = "org.freedesktop.Accounts.User" - - dbusPortalDest = "org.freedesktop.portal.Desktop" - dbusPortalPath = "/org/freedesktop/portal/desktop" - dbusPortalSettingsInterface = "org.freedesktop.portal.Settings" - - dbusPropsInterface = "org.freedesktop.DBus.Properties" - - dbusScreensaverName = "org.freedesktop.ScreenSaver" - dbusScreensaverPath = "/ScreenSaver" - dbusScreensaverPath2 = "/org/freedesktop/ScreenSaver" - dbusScreensaverInterface = "org.freedesktop.ScreenSaver" - - dbusGnomeScreensaverName = "org.gnome.ScreenSaver" - dbusGnomeScreensaverPath = "/org/gnome/ScreenSaver" - dbusGnomeScreensaverInterface = "org.gnome.ScreenSaver" -) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers.go deleted file mode 100644 index c3090fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers.go +++ /dev/null @@ -1,154 +0,0 @@ -package freedesktop - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "freedesktop.getState": - handleGetState(conn, req, manager) - case "freedesktop.accounts.setIconFile": - handleSetIconFile(conn, req, manager) - case "freedesktop.accounts.setRealName": - handleSetRealName(conn, req, manager) - case "freedesktop.accounts.setEmail": - handleSetEmail(conn, req, manager) - case "freedesktop.accounts.setLanguage": - handleSetLanguage(conn, req, manager) - case "freedesktop.accounts.setLocation": - handleSetLocation(conn, req, manager) - case "freedesktop.accounts.getUserIconFile": - handleGetUserIconFile(conn, req, manager) - case "freedesktop.settings.getColorScheme": - handleGetColorScheme(conn, req, manager) - case "freedesktop.settings.setIconTheme": - handleSetIconTheme(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleSetIconFile(conn net.Conn, req models.Request, manager *Manager) { - iconPath, err := params.String(req.Params, "path") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetIconFile(iconPath); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "icon file set"}) -} - -func handleSetRealName(conn net.Conn, req models.Request, manager *Manager) { - name, err := params.String(req.Params, "name") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetRealName(name); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "real name set"}) -} - -func handleSetEmail(conn net.Conn, req models.Request, manager *Manager) { - email, err := params.String(req.Params, "email") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetEmail(email); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "email set"}) -} - -func handleSetLanguage(conn net.Conn, req models.Request, manager *Manager) { - language, err := params.String(req.Params, "language") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetLanguage(language); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "language set"}) -} - -func handleSetLocation(conn net.Conn, req models.Request, manager *Manager) { - location, err := params.String(req.Params, "location") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetLocation(location); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "location set"}) -} - -func handleGetUserIconFile(conn net.Conn, req models.Request, manager *Manager) { - username, err := params.String(req.Params, "username") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - iconFile, err := manager.GetUserIconFile(username) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Value: iconFile}) -} - -func handleGetColorScheme(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.updateSettingsState(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - state := manager.GetState() - models.Respond(conn, req.ID, map[string]uint32{"colorScheme": state.Settings.ColorScheme}) -} - -func handleSetIconTheme(conn net.Conn, req models.Request, manager *Manager) { - iconTheme, err := params.String(req.Params, "iconTheme") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetIconTheme(iconTheme); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "icon theme set"}) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers_test.go deleted file mode 100644 index f2cb5a2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/handlers_test.go +++ /dev/null @@ -1,581 +0,0 @@ -package freedesktop - -import ( - "bytes" - "encoding/json" - "net" - "sync" - "testing" - - mockdbus "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -type mockNetConn struct { - net.Conn - readBuf *bytes.Buffer - writeBuf *bytes.Buffer - closed bool -} - -func newMockNetConn() *mockNetConn { - return &mockNetConn{ - readBuf: &bytes.Buffer{}, - writeBuf: &bytes.Buffer{}, - } -} - -func (m *mockNetConn) Read(b []byte) (n int, err error) { - return m.readBuf.Read(b) -} - -func (m *mockNetConn) Write(b []byte) (n int, err error) { - return m.writeBuf.Write(b) -} - -func (m *mockNetConn) Close() error { - m.closed = true - return nil -} - -func mockGetAllAccountsProperties() *dbus.Call { - props := map[string]dbus.Variant{ - "IconFile": dbus.MakeVariant("/path/to/icon.png"), - "RealName": dbus.MakeVariant("Test"), - "UserName": dbus.MakeVariant("test"), - "AccountType": dbus.MakeVariant(int32(0)), - "HomeDirectory": dbus.MakeVariant("/home/test"), - "Shell": dbus.MakeVariant("/bin/bash"), - "Email": dbus.MakeVariant(""), - "Language": dbus.MakeVariant(""), - "Location": dbus.MakeVariant(""), - "Locked": dbus.MakeVariant(false), - "PasswordMode": dbus.MakeVariant(int32(1)), - } - return &dbus.Call{Err: nil, Body: []any{props}} -} - -func TestRespondError_Freedesktop(t *testing.T) { - conn := newMockNetConn() - models.RespondError(conn, 123, "test error") - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Equal(t, "test error", resp.Error) - assert.Nil(t, resp.Result) -} - -func TestRespond_Freedesktop(t *testing.T) { - conn := newMockNetConn() - result := models.SuccessResult{Success: true, Message: "test"} - models.Respond(conn, 123, result) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "test", resp.Result.Message) -} - -func TestHandleGetState(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - RealName: "Test User", - UID: 1000, - }, - Settings: SettingsState{ - Available: true, - ColorScheme: 1, - }, - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "freedesktop.getState"} - - handleGetState(conn, req, manager) - - var resp models.Response[FreedeskState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Accounts.Available) - assert.Equal(t, "testuser", resp.Result.Accounts.UserName) - assert.True(t, resp.Result.Settings.Available) - assert.Equal(t, uint32(1), resp.Result.Settings.ColorScheme) -} - -func TestHandleSetIconFile(t *testing.T) { - t.Run("missing path parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setIconFile", - Params: map[string]any{}, - } - - handleSetIconFile(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'path' parameter") - }) - - t.Run("successful set icon file", func(t *testing.T) { - mockAccountsObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetIconFile", dbus.Flags(0), "/path/to/icon.png").Return(mockCall) - mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties()) - - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - }, - }, - stateMutex: sync.RWMutex{}, - accountsObj: mockAccountsObj, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setIconFile", - Params: map[string]any{ - "path": "/path/to/icon.png", - }, - } - - handleSetIconFile(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "icon file set", resp.Result.Message) - }) - - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setIconFile", - Params: map[string]any{ - "path": "/path/to/icon.png", - }, - } - - handleSetIconFile(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "accounts service not available") - }) -} - -func TestHandleSetRealName(t *testing.T) { - t.Run("missing name parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setRealName", - Params: map[string]any{}, - } - - handleSetRealName(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'name' parameter") - }) - - t.Run("successful set real name", func(t *testing.T) { - mockAccountsObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetRealName", dbus.Flags(0), "New Name").Return(mockCall) - mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties()) - - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - }, - }, - stateMutex: sync.RWMutex{}, - accountsObj: mockAccountsObj, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setRealName", - Params: map[string]any{ - "name": "New Name", - }, - } - - handleSetRealName(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "real name set", resp.Result.Message) - }) -} - -func TestHandleSetEmail(t *testing.T) { - t.Run("missing email parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setEmail", - Params: map[string]any{}, - } - - handleSetEmail(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'email' parameter") - }) - - t.Run("successful set email", func(t *testing.T) { - mockAccountsObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetEmail", dbus.Flags(0), "test@example.com").Return(mockCall) - mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties()) - - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - }, - }, - stateMutex: sync.RWMutex{}, - accountsObj: mockAccountsObj, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setEmail", - Params: map[string]any{ - "email": "test@example.com", - }, - } - - handleSetEmail(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "email set", resp.Result.Message) - }) -} - -func TestHandleSetLanguage(t *testing.T) { - t.Run("missing language parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setLanguage", - Params: map[string]any{}, - } - - handleSetLanguage(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'language' parameter") - }) -} - -func TestHandleSetLocation(t *testing.T) { - t.Run("missing location parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.setLocation", - Params: map[string]any{}, - } - - handleSetLocation(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'location' parameter") - }) -} - -func TestHandleGetUserIconFile(t *testing.T) { - t.Run("missing username parameter", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.getUserIconFile", - Params: map[string]any{}, - } - - handleGetUserIconFile(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'username' parameter") - }) - - t.Run("accounts not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.accounts.getUserIconFile", - Params: map[string]any{ - "username": "testuser", - }, - } - - handleGetUserIconFile(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "accounts service not available") - }) -} - -func TestHandleGetColorScheme(t *testing.T) { - t.Run("settings not available", func(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Settings: SettingsState{ - Available: false, - }, - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "freedesktop.settings.getColorScheme"} - - handleGetColorScheme(conn, req, manager) - - var resp models.Response[map[string]uint32] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "settings portal not available") - }) - - t.Run("successful get color scheme", func(t *testing.T) { - mockSettingsObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{ - Err: nil, - Body: []any{dbus.MakeVariant(uint32(1))}, - } - mockSettingsObj.EXPECT().Call("org.freedesktop.portal.Settings.ReadOne", dbus.Flags(0), "org.freedesktop.appearance", "color-scheme").Return(mockCall) - - manager := &Manager{ - state: &FreedeskState{ - Settings: SettingsState{ - Available: true, - }, - }, - stateMutex: sync.RWMutex{}, - settingsObj: mockSettingsObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "freedesktop.settings.getColorScheme"} - - handleGetColorScheme(conn, req, manager) - - var resp models.Response[map[string]uint32] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.Equal(t, uint32(1), (*resp.Result)["colorScheme"]) - }) -} - -func TestHandleRequest(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - }, - }, - stateMutex: sync.RWMutex{}, - } - - t.Run("unknown method", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.unknown", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "unknown method") - }) - - t.Run("valid method - getState", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "freedesktop.getState", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[FreedeskState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - }) - - t.Run("all method routes", func(t *testing.T) { - tests := []string{ - "freedesktop.accounts.setIconFile", - "freedesktop.accounts.setRealName", - "freedesktop.accounts.setEmail", - "freedesktop.accounts.setLanguage", - "freedesktop.accounts.setLocation", - "freedesktop.accounts.getUserIconFile", - "freedesktop.settings.getColorScheme", - } - - for _, method := range tests { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: method, - Params: map[string]any{}, - } - - HandleRequest(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - // Will have errors due to missing params or service unavailable - // but the method routing should work - } - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager.go deleted file mode 100644 index 054f859..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager.go +++ /dev/null @@ -1,206 +0,0 @@ -package freedesktop - -import ( - "context" - "fmt" - "os" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/godbus/dbus/v5" -) - -func NewManager() (*Manager, error) { - systemConn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to system bus: %w", err) - } - - sessionConn, err := dbus.ConnectSessionBus() - if err != nil { - sessionConn = nil - } - - m := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{}, - Settings: SettingsState{}, - Screensaver: ScreensaverState{}, - }, - stateMutex: sync.RWMutex{}, - systemConn: systemConn, - sessionConn: sessionConn, - currentUID: uint64(os.Getuid()), - } - - m.initializeAccounts() - m.initializeSettings() - m.initializeScreensaver() - - return m, nil -} - -func (m *Manager) initializeAccounts() error { - accountsManager := m.systemConn.Object(dbusAccountsDest, dbus.ObjectPath(dbusAccountsPath)) - - var userPath dbus.ObjectPath - err := accountsManager.Call(dbusAccountsInterface+".FindUserById", 0, int64(m.currentUID)).Store(&userPath) - if err != nil { - m.stateMutex.Lock() - m.state.Accounts.Available = false - m.stateMutex.Unlock() - return err - } - - m.accountsObj = m.systemConn.Object(dbusAccountsDest, userPath) - - m.stateMutex.Lock() - m.state.Accounts.Available = true - m.state.Accounts.UserPath = string(userPath) - m.state.Accounts.UID = m.currentUID - m.stateMutex.Unlock() - - if err := m.updateAccountsState(); err != nil { - return fmt.Errorf("failed to update accounts state: %w", err) - } - - return nil -} - -func (m *Manager) initializeSettings() error { - if m.sessionConn == nil { - m.stateMutex.Lock() - m.state.Settings.Available = false - m.stateMutex.Unlock() - return fmt.Errorf("no session bus connection") - } - - m.settingsObj = m.sessionConn.Object(dbusPortalDest, dbus.ObjectPath(dbusPortalPath)) - - var variant dbus.Variant - err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant) - if err != nil { - m.stateMutex.Lock() - m.state.Settings.Available = false - m.stateMutex.Unlock() - return err - } - - m.stateMutex.Lock() - m.state.Settings.Available = true - m.stateMutex.Unlock() - - if err := m.updateSettingsState(); err != nil { - return fmt.Errorf("failed to update settings state: %w", err) - } - - return nil -} - -func (m *Manager) updateAccountsState() error { - if !m.state.Accounts.Available || m.accountsObj == nil { - return fmt.Errorf("accounts service not available") - } - - ctx := context.Background() - props, err := m.getAccountProperties(ctx) - if err != nil { - return err - } - - m.stateMutex.Lock() - defer m.stateMutex.Unlock() - - m.state.Accounts.IconFile = dbusutil.GetOr(props, "IconFile", "") - m.state.Accounts.RealName = dbusutil.GetOr(props, "RealName", "") - m.state.Accounts.UserName = dbusutil.GetOr(props, "UserName", "") - m.state.Accounts.AccountType = dbusutil.GetOr(props, "AccountType", int32(0)) - m.state.Accounts.HomeDirectory = dbusutil.GetOr(props, "HomeDirectory", "") - m.state.Accounts.Shell = dbusutil.GetOr(props, "Shell", "") - m.state.Accounts.Email = dbusutil.GetOr(props, "Email", "") - m.state.Accounts.Language = dbusutil.GetOr(props, "Language", "") - m.state.Accounts.Location = dbusutil.GetOr(props, "Location", "") - m.state.Accounts.Locked = dbusutil.GetOr(props, "Locked", false) - m.state.Accounts.PasswordMode = dbusutil.GetOr(props, "PasswordMode", int32(0)) - - return nil -} - -func (m *Manager) updateSettingsState() error { - if !m.state.Settings.Available || m.settingsObj == nil { - return fmt.Errorf("settings portal not available") - } - - var variant dbus.Variant - err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant) - if err != nil { - return err - } - - if colorScheme, ok := dbusutil.As[uint32](variant); ok { - m.stateMutex.Lock() - m.state.Settings.ColorScheme = colorScheme - m.stateMutex.Unlock() - } - - return nil -} - -func (m *Manager) getAccountProperties(ctx context.Context) (map[string]dbus.Variant, error) { - var props map[string]dbus.Variant - err := m.accountsObj.CallWithContext(ctx, dbusPropsInterface+".GetAll", 0, dbusAccountsUserInterface).Store(&props) - if err != nil { - return nil, err - } - return props, nil -} - -func (m *Manager) GetState() FreedeskState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return *m.state -} - -func (m *Manager) Subscribe(id string) chan FreedeskState { - ch := make(chan FreedeskState, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) NotifySubscribers() { - state := m.GetState() - m.subscribers.Range(func(key string, ch chan FreedeskState) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (m *Manager) Close() { - m.subscribers.Range(func(key string, ch chan FreedeskState) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.screensaverSubscribers.Range(func(key string, ch chan ScreensaverState) bool { - close(ch) - m.screensaverSubscribers.Delete(key) - return true - }) - - if m.systemConn != nil { - m.systemConn.Close() - } - if m.sessionConn != nil { - m.sessionConn.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager_test.go deleted file mode 100644 index b3617f5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/manager_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package freedesktop - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestManager_GetState(t *testing.T) { - state := &FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - RealName: "Test User", - UID: 1000, - }, - Settings: SettingsState{ - Available: true, - ColorScheme: 1, - }, - } - - manager := &Manager{ - state: state, - stateMutex: sync.RWMutex{}, - } - - result := manager.GetState() - assert.True(t, result.Accounts.Available) - assert.Equal(t, "testuser", result.Accounts.UserName) - assert.Equal(t, "Test User", result.Accounts.RealName) - assert.Equal(t, uint64(1000), result.Accounts.UID) - assert.True(t, result.Settings.Available) - assert.Equal(t, uint32(1), result.Settings.ColorScheme) -} - -func TestManager_GetState_ThreadSafe(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - }, - Settings: SettingsState{ - Available: true, - ColorScheme: 1, - }, - }, - stateMutex: sync.RWMutex{}, - } - - done := make(chan bool) - for i := 0; i < 10; i++ { - go func() { - state := manager.GetState() - assert.True(t, state.Accounts.Available) - assert.Equal(t, "testuser", state.Accounts.UserName) - done <- true - }() - } - - for i := 0; i < 10; i++ { - <-done - } -} - -func TestManager_Close(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - systemConn: nil, - sessionConn: nil, - } - - assert.NotPanics(t, func() { - manager.Close() - }) -} - -func TestNewManager(t *testing.T) { - t.Run("attempts to create manager", func(t *testing.T) { - manager, err := NewManager() - if err != nil { - assert.Nil(t, manager) - } else { - assert.NotNil(t, manager) - assert.NotNil(t, manager.state) - assert.NotNil(t, manager.systemConn) - - manager.Close() - } - }) -} - -func TestManager_GetState_EmptyState(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{}, - stateMutex: sync.RWMutex{}, - } - - result := manager.GetState() - assert.False(t, result.Accounts.Available) - assert.Empty(t, result.Accounts.UserName) - assert.False(t, result.Settings.Available) - assert.Equal(t, uint32(0), result.Settings.ColorScheme) -} - -func TestManager_AccountsState_Modification(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - }, - }, - stateMutex: sync.RWMutex{}, - } - - state := manager.GetState() - state.Accounts.UserName = "modifieduser" - - original := manager.GetState() - assert.Equal(t, "testuser", original.Accounts.UserName) -} - -func TestManager_SettingsState_Modification(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Settings: SettingsState{ - Available: true, - ColorScheme: 0, - }, - }, - stateMutex: sync.RWMutex{}, - } - - state := manager.GetState() - state.Settings.ColorScheme = 1 - - original := manager.GetState() - assert.Equal(t, uint32(0), original.Settings.ColorScheme) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver.go deleted file mode 100644 index 095a4c0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver.go +++ /dev/null @@ -1,349 +0,0 @@ -package freedesktop - -import ( - "fmt" - "path/filepath" - "strings" - "sync/atomic" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" - "github.com/godbus/dbus/v5/introspect" -) - -type screensaverHandler struct { - manager *Manager -} - -func screensaverIntrospectIface(ifaceName string) introspect.Interface { - return introspect.Interface{ - Name: ifaceName, - Methods: []introspect.Method{ - { - Name: "Inhibit", - Args: []introspect.Arg{ - {Name: "application_name", Type: "s", Direction: "in"}, - {Name: "reason_for_inhibit", Type: "s", Direction: "in"}, - {Name: "cookie", Type: "u", Direction: "out"}, - }, - }, - { - Name: "UnInhibit", - Args: []introspect.Arg{ - {Name: "cookie", Type: "u", Direction: "in"}, - }, - }, - { - Name: "GetActive", - Args: []introspect.Arg{ - {Name: "active", Type: "b", Direction: "out"}, - }, - }, - { - Name: "SetActive", - Args: []introspect.Arg{ - {Name: "active", Type: "b", Direction: "in"}, - }, - }, - { - Name: "Lock", - }, - }, - Signals: []introspect.Signal{ - { - Name: "ActiveChanged", - Args: []introspect.Arg{ - {Name: "new_value", Type: "b"}, - }, - }, - }, - } -} - -func (m *Manager) initializeScreensaver() error { - if m.sessionConn == nil { - m.stateMutex.Lock() - m.state.Screensaver.Available = false - m.stateMutex.Unlock() - return nil - } - - handler := &screensaverHandler{manager: m} - - m.screensaverFreedesktopClaimed = m.claimScreensaverName(handler, - dbusScreensaverName, dbusScreensaverInterface, dbusScreensaverPath, dbusScreensaverPath2) - m.screensaverGnomeClaimed = m.claimScreensaverName(handler, - dbusGnomeScreensaverName, dbusGnomeScreensaverInterface, dbusGnomeScreensaverPath) - - if !m.screensaverFreedesktopClaimed && !m.screensaverGnomeClaimed { - log.Warn("No screensaver interface could be claimed") - m.stateMutex.Lock() - m.state.Screensaver.Available = false - m.stateMutex.Unlock() - return nil - } - - go m.watchPeerDisconnects() - - m.stateMutex.Lock() - m.state.Screensaver.Available = true - m.state.Screensaver.Active = false - m.state.Screensaver.Inhibited = false - m.state.Screensaver.Inhibitors = []ScreensaverInhibitor{} - m.stateMutex.Unlock() - - log.Info("Screensaver listener initialized") - return nil -} - -func (m *Manager) claimScreensaverName(handler *screensaverHandler, name, iface string, paths ...dbus.ObjectPath) bool { - reply, err := m.sessionConn.RequestName(name, dbus.NameFlagDoNotQueue) - if err != nil { - log.Warnf("Failed to request screensaver name %s: %v", name, err) - return false - } - if reply != dbus.RequestNameReplyPrimaryOwner { - log.Warnf("Screensaver name %s already owned by another process", name) - return false - } - if err := m.exportScreensaverOnPaths(handler, iface, paths...); err != nil { - log.Warnf("Failed to export screensaver on %s: %v", name, err) - return false - } - log.Infof("Claimed %s on session bus", name) - return true -} - -// exportScreensaverOnPaths exports the handler and introspection on the given -// paths under the specified interface name. -func (m *Manager) exportScreensaverOnPaths(handler *screensaverHandler, ifaceName string, paths ...dbus.ObjectPath) error { - iface := screensaverIntrospectIface(ifaceName) - for _, path := range paths { - if err := m.sessionConn.Export(handler, path, ifaceName); err != nil { - return fmt.Errorf("export handler on %s: %w", path, err) - } - node := &introspect.Node{ - Name: string(path), - Interfaces: []introspect.Interface{ - introspect.IntrospectData, - iface, - }, - } - if err := m.sessionConn.Export(introspect.NewIntrospectable(node), path, "org.freedesktop.DBus.Introspectable"); err != nil { - log.Warnf("Failed to export introspectable on %s: %v", path, err) - } - } - return nil -} - -func (h *screensaverHandler) Inhibit(sender dbus.Sender, appName, reason string) (uint32, *dbus.Error) { - if appName == "" { - return 0, dbus.NewError("org.freedesktop.DBus.Error.InvalidArgs", []any{"application name required"}) - } - - if reason == "" { - return 0, dbus.NewError("org.freedesktop.DBus.Error.InvalidArgs", []any{"reason required"}) - } - - if strings.Contains(strings.ToLower(reason), "audio") && !strings.Contains(strings.ToLower(reason), "video") { - log.Debugf("Ignoring audio-only inhibit from %s: %s", appName, reason) - return 0, nil - } - - if idx := strings.LastIndex(appName, "/"); idx != -1 && idx < len(appName)-1 { - appName = appName[idx+1:] - } - appName = filepath.Base(appName) - - cookie := atomic.AddUint32(&h.manager.screensaverCookieCounter, 1) - - inhibitor := ScreensaverInhibitor{ - Cookie: cookie, - AppName: appName, - Reason: reason, - Peer: string(sender), - StartTime: time.Now().Unix(), - } - - h.manager.stateMutex.Lock() - h.manager.state.Screensaver.Inhibitors = append(h.manager.state.Screensaver.Inhibitors, inhibitor) - h.manager.state.Screensaver.Inhibited = len(h.manager.state.Screensaver.Inhibitors) > 0 - h.manager.stateMutex.Unlock() - - log.Infof("Screensaver inhibited by %s (%s): %s -> cookie %08X", appName, sender, reason, cookie) - - h.manager.NotifyScreensaverSubscribers() - - return cookie, nil -} - -func (h *screensaverHandler) UnInhibit(sender dbus.Sender, cookie uint32) *dbus.Error { - h.manager.stateMutex.Lock() - defer h.manager.stateMutex.Unlock() - - found := false - inhibitors := h.manager.state.Screensaver.Inhibitors - for i, inh := range inhibitors { - if inh.Cookie != cookie { - continue - } - log.Infof("Screensaver uninhibited by %s (%s) cookie %08X", inh.AppName, sender, cookie) - h.manager.state.Screensaver.Inhibitors = append(inhibitors[:i], inhibitors[i+1:]...) - found = true - break - } - - if !found { - log.Debugf("UnInhibit: no match for cookie %08X", cookie) - return nil - } - - h.manager.state.Screensaver.Inhibited = len(h.manager.state.Screensaver.Inhibitors) > 0 - - go h.manager.NotifyScreensaverSubscribers() - - return nil -} - -func (m *Manager) watchPeerDisconnects() { - if m.sessionConn == nil { - return - } - - if err := m.sessionConn.AddMatchSignal( - dbus.WithMatchInterface("org.freedesktop.DBus"), - dbus.WithMatchMember("NameOwnerChanged"), - ); err != nil { - log.Warnf("Failed to watch peer disconnects: %v", err) - return - } - - signals := make(chan *dbus.Signal, 64) - m.sessionConn.Signal(signals) - - for sig := range signals { - if sig.Name != "org.freedesktop.DBus.NameOwnerChanged" { - continue - } - if len(sig.Body) < 3 { - continue - } - - name, ok1 := sig.Body[0].(string) - newOwner, ok2 := sig.Body[2].(string) - if !ok1 || !ok2 { - continue - } - if newOwner != "" { - continue - } - - m.removeInhibitorsByPeer(name) - } -} - -func (m *Manager) removeInhibitorsByPeer(peer string) { - m.stateMutex.Lock() - defer m.stateMutex.Unlock() - - var remaining []ScreensaverInhibitor - var removed []ScreensaverInhibitor - for _, inh := range m.state.Screensaver.Inhibitors { - if inh.Peer == peer { - removed = append(removed, inh) - continue - } - remaining = append(remaining, inh) - } - - if len(removed) == 0 { - return - } - - for _, inh := range removed { - log.Infof("Screensaver: peer %s died, removing inhibitor from %s (cookie %08X)", peer, inh.AppName, inh.Cookie) - } - - m.state.Screensaver.Inhibitors = remaining - m.state.Screensaver.Inhibited = len(remaining) > 0 - - go m.NotifyScreensaverSubscribers() -} - -func (m *Manager) GetScreensaverState() ScreensaverState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return m.state.Screensaver -} - -func (m *Manager) SubscribeScreensaver(id string) chan ScreensaverState { - ch := make(chan ScreensaverState, 64) - m.screensaverSubscribers.Store(id, ch) - return ch -} - -func (m *Manager) UnsubscribeScreensaver(id string) { - if val, ok := m.screensaverSubscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) NotifyScreensaverSubscribers() { - state := m.GetScreensaverState() - m.screensaverSubscribers.Range(func(key string, ch chan ScreensaverState) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (h *screensaverHandler) GetActive() (bool, *dbus.Error) { - h.manager.stateMutex.RLock() - active := h.manager.state.Screensaver.Active - h.manager.stateMutex.RUnlock() - return active, nil -} - -func (h *screensaverHandler) SetActive(active bool) *dbus.Error { - h.manager.SetScreenLockActive(active) - return nil -} - -func (h *screensaverHandler) Lock() *dbus.Error { - h.manager.SetScreenLockActive(true) - return nil -} - -func (m *Manager) SetScreenLockActive(active bool) { - m.stateMutex.Lock() - changed := m.state.Screensaver.Active != active - m.state.Screensaver.Active = active - m.stateMutex.Unlock() - - if !changed { - return - } - - log.Infof("Screen lock active changed: %v", active) - defer m.NotifyScreensaverSubscribers() - - if m.sessionConn == nil { - return - } - if m.screensaverFreedesktopClaimed { - if err := m.sessionConn.Emit(dbusScreensaverPath, dbusScreensaverInterface+".ActiveChanged", active); err != nil { - log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusScreensaverPath, err) - } - if err := m.sessionConn.Emit(dbusScreensaverPath2, dbusScreensaverInterface+".ActiveChanged", active); err != nil { - log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusScreensaverPath2, err) - } - } - if m.screensaverGnomeClaimed { - if err := m.sessionConn.Emit(dbusGnomeScreensaverPath, dbusGnomeScreensaverInterface+".ActiveChanged", active); err != nil { - log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusGnomeScreensaverPath, err) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver_test.go deleted file mode 100644 index 324c17e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/screensaver_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package freedesktop - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestSetScreenLockActive_ChangesState(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Screensaver: ScreensaverState{Available: true}, - }, - stateMutex: sync.RWMutex{}, - } - - assert.False(t, manager.GetScreensaverState().Active) - - manager.SetScreenLockActive(true) - assert.True(t, manager.GetScreensaverState().Active) - - manager.SetScreenLockActive(false) - assert.False(t, manager.GetScreensaverState().Active) -} - -func TestSetScreenLockActive_NoChangeNoDuplicate(t *testing.T) { - ch := make(chan ScreensaverState, 64) - manager := &Manager{ - state: &FreedeskState{ - Screensaver: ScreensaverState{Available: true, Active: false}, - }, - stateMutex: sync.RWMutex{}, - } - manager.screensaverSubscribers.Store("test", ch) - defer manager.screensaverSubscribers.Delete("test") - - // Setting to same value should not notify - manager.SetScreenLockActive(false) - - select { - case <-ch: - t.Fatal("should not have received notification for no-change") - case <-time.After(50 * time.Millisecond): - // Expected: no notification - } -} - -func TestSetScreenLockActive_NotifiesSubscribers(t *testing.T) { - ch := make(chan ScreensaverState, 64) - manager := &Manager{ - state: &FreedeskState{ - Screensaver: ScreensaverState{Available: true, Active: false}, - }, - stateMutex: sync.RWMutex{}, - } - manager.screensaverSubscribers.Store("test", ch) - defer manager.screensaverSubscribers.Delete("test") - - manager.SetScreenLockActive(true) - - select { - case state := <-ch: - assert.True(t, state.Active) - case <-time.After(time.Second): - t.Fatal("timeout waiting for subscriber notification") - } -} - -func TestSetScreenLockActive_NilSessionConn(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Screensaver: ScreensaverState{Available: true}, - }, - stateMutex: sync.RWMutex{}, - } - - assert.NotPanics(t, func() { - manager.SetScreenLockActive(true) - }) - assert.True(t, manager.GetScreensaverState().Active) -} - -func TestGetActive_ReturnsCurrentState(t *testing.T) { - manager := &Manager{ - state: &FreedeskState{ - Screensaver: ScreensaverState{Available: true, Active: true}, - }, - stateMutex: sync.RWMutex{}, - } - - handler := &screensaverHandler{manager: manager} - active, dbusErr := handler.GetActive() - assert.Nil(t, dbusErr) - assert.True(t, active) -} - -func TestScreensaverState_ActiveDefaultsFalse(t *testing.T) { - state := ScreensaverState{} - assert.False(t, state.Active) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types.go deleted file mode 100644 index 0a9517a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types.go +++ /dev/null @@ -1,66 +0,0 @@ -package freedesktop - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type AccountsState struct { - Available bool `json:"available"` - UserPath string `json:"userPath"` - IconFile string `json:"iconFile"` - RealName string `json:"realName"` - UserName string `json:"userName"` - AccountType int32 `json:"accountType"` - HomeDirectory string `json:"homeDirectory"` - Shell string `json:"shell"` - Email string `json:"email"` - Language string `json:"language"` - Location string `json:"location"` - Locked bool `json:"locked"` - PasswordMode int32 `json:"passwordMode"` - UID uint64 `json:"uid"` -} - -type SettingsState struct { - Available bool `json:"available"` - ColorScheme uint32 `json:"colorScheme"` -} - -type ScreensaverInhibitor struct { - Cookie uint32 `json:"cookie"` - AppName string `json:"appName"` - Reason string `json:"reason"` - Peer string `json:"peer"` - StartTime int64 `json:"startTime"` -} - -type ScreensaverState struct { - Available bool `json:"available"` - Active bool `json:"active"` - Inhibited bool `json:"inhibited"` - Inhibitors []ScreensaverInhibitor `json:"inhibitors"` -} - -type FreedeskState struct { - Accounts AccountsState `json:"accounts"` - Settings SettingsState `json:"settings"` - Screensaver ScreensaverState `json:"screensaver"` -} - -type Manager struct { - state *FreedeskState - stateMutex sync.RWMutex - systemConn *dbus.Conn - sessionConn *dbus.Conn - accountsObj dbus.BusObject - settingsObj dbus.BusObject - currentUID uint64 - subscribers syncmap.Map[string, chan FreedeskState] - screensaverSubscribers syncmap.Map[string, chan ScreensaverState] - screensaverCookieCounter uint32 - screensaverFreedesktopClaimed bool - screensaverGnomeClaimed bool -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types_test.go deleted file mode 100644 index deb0327..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/freedesktop/types_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package freedesktop - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestAccountsState_Struct(t *testing.T) { - state := AccountsState{ - Available: true, - UserPath: "/org/freedesktop/Accounts/User1000", - RealName: "Test User", - UserName: "testuser", - Locked: false, - UID: 1000, - } - - assert.True(t, state.Available) - assert.Equal(t, "/org/freedesktop/Accounts/User1000", state.UserPath) - assert.Equal(t, "Test User", state.RealName) - assert.Equal(t, "testuser", state.UserName) - assert.Equal(t, uint64(1000), state.UID) - assert.False(t, state.Locked) -} - -func TestSettingsState_Struct(t *testing.T) { - state := SettingsState{ - Available: true, - ColorScheme: 1, // Dark mode - } - - assert.True(t, state.Available) - assert.Equal(t, uint32(1), state.ColorScheme) -} - -func TestFreedeskState_Struct(t *testing.T) { - state := FreedeskState{ - Accounts: AccountsState{ - Available: true, - UserName: "testuser", - UID: 1000, - }, - Settings: SettingsState{ - Available: true, - ColorScheme: 0, // Light mode - }, - } - - assert.True(t, state.Accounts.Available) - assert.Equal(t, "testuser", state.Accounts.UserName) - assert.True(t, state.Settings.Available) - assert.Equal(t, uint32(0), state.Settings.ColorScheme) -} - -func TestAccountsState_DefaultValues(t *testing.T) { - state := AccountsState{} - - assert.False(t, state.Available) - assert.Empty(t, state.UserPath) - assert.Empty(t, state.UserName) - assert.Equal(t, uint64(0), state.UID) -} - -func TestSettingsState_DefaultValues(t *testing.T) { - state := SettingsState{} - - assert.False(t, state.Available) - assert.Equal(t, uint32(0), state.ColorScheme) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/handlers.go deleted file mode 100644 index c9d556c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/handlers.go +++ /dev/null @@ -1,61 +0,0 @@ -package location - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type LocationEvent struct { - Type string `json:"type"` - Data State `json:"data"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "location.getState": - handleGetState(conn, req, manager) - case "location.subscribe": - handleSubscribe(conn, req, manager) - - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - event := LocationEvent{ - Type: "state_changed", - Data: initialState, - } - - if err := json.NewEncoder(conn).Encode(models.Response[LocationEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - return - } - - for state := range stateChan { - event := LocationEvent{ - Type: "state_changed", - Data: state, - } - if err := json.NewEncoder(conn).Encode(models.Response[LocationEvent]{ - Result: &event, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/manager.go deleted file mode 100644 index 24bcd95..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/manager.go +++ /dev/null @@ -1,175 +0,0 @@ -package location - -import ( - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -func NewManager(client geolocation.Client) (*Manager, error) { - currLocation, err := client.GetLocation() - if err != nil { - log.Warnf("Failed to get initial location: %v", err) - } - - m := &Manager{ - client: client, - dirty: make(chan struct{}), - stopChan: make(chan struct{}), - - state: &State{ - Latitude: currLocation.Latitude, - Longitude: currLocation.Longitude, - }, - } - - if err := m.startSignalPump(); err != nil { - return nil, err - } - - m.notifierWg.Add(1) - go m.notifier() - - return m, nil -} - -func (m *Manager) Close() { - close(m.stopChan) - m.notifierWg.Wait() - - m.sigWG.Wait() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if ch, ok := m.subscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (m *Manager) startSignalPump() error { - m.sigWG.Add(1) - go func() { - defer m.sigWG.Done() - - subscription := m.client.Subscribe("locationManager") - defer m.client.Unsubscribe("locationManager") - - for { - select { - case <-m.stopChan: - return - case location, ok := <-subscription: - if !ok { - return - } - - m.handleLocationChange(location) - } - } - }() - - return nil -} - -func (m *Manager) handleLocationChange(location geolocation.Location) { - m.stateMutex.Lock() - defer m.stateMutex.Unlock() - - m.state.Latitude = location.Latitude - m.state.Longitude = location.Longitude - - m.notifySubscribers() -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{ - Latitude: 0.0, - Longitude: 0.0, - } - } - stateCopy := *m.state - return stateCopy -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 200 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.GetState() - - if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- currentState: - default: - log.Warn("Location: subscriber channel full, dropping update") - } - return true - }) - - stateCopy := currentState - m.lastNotified = &stateCopy - pending = false - } - } -} - -func stateChanged(old, new *State) bool { - if old == nil || new == nil { - return true - } - if old.Latitude != new.Latitude { - return true - } - if old.Longitude != new.Longitude { - return true - } - - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/types.go deleted file mode 100644 index 1f3d518..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/location/types.go +++ /dev/null @@ -1,28 +0,0 @@ -package location - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type State struct { - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` -} - -type Manager struct { - state *State - stateMutex sync.RWMutex - - client geolocation.Client - - stopChan chan struct{} - sigWG sync.WaitGroup - - subscribers syncmap.Map[string, chan State] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotified *State -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/actions.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/actions.go deleted file mode 100644 index 858248e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/actions.go +++ /dev/null @@ -1,88 +0,0 @@ -package loginctl - -import ( - "fmt" -) - -func (m *Manager) Lock() error { - if m.sessionObj == nil { - return fmt.Errorf("session object not available") - } - err := m.sessionObj.Call(dbusSessionInterface+".Lock", 0).Err - if err != nil { - if refreshErr := m.refreshSessionBinding(); refreshErr == nil { - err = m.sessionObj.Call(dbusSessionInterface+".Lock", 0).Err - } - if err != nil { - return fmt.Errorf("failed to lock session: %w", err) - } - } - return nil -} - -func (m *Manager) Unlock() error { - err := m.sessionObj.Call(dbusSessionInterface+".Unlock", 0).Err - if err != nil { - if refreshErr := m.refreshSessionBinding(); refreshErr == nil { - err = m.sessionObj.Call(dbusSessionInterface+".Unlock", 0).Err - } - if err != nil { - return fmt.Errorf("failed to unlock session: %w", err) - } - } - return nil -} - -func (m *Manager) Activate() error { - err := m.sessionObj.Call(dbusSessionInterface+".Activate", 0).Err - if err != nil { - if refreshErr := m.refreshSessionBinding(); refreshErr == nil { - err = m.sessionObj.Call(dbusSessionInterface+".Activate", 0).Err - } - if err != nil { - return fmt.Errorf("failed to activate session: %w", err) - } - } - return nil -} - -func (m *Manager) SetIdleHint(idle bool) error { - err := m.sessionObj.Call(dbusSessionInterface+".SetIdleHint", 0, idle).Err - if err != nil { - if refreshErr := m.refreshSessionBinding(); refreshErr == nil { - err = m.sessionObj.Call(dbusSessionInterface+".SetIdleHint", 0, idle).Err - } - if err != nil { - return fmt.Errorf("failed to set idle hint: %w", err) - } - } - return nil -} - -func (m *Manager) Terminate() error { - err := m.sessionObj.Call(dbusSessionInterface+".Terminate", 0).Err - if err != nil { - if refreshErr := m.refreshSessionBinding(); refreshErr == nil { - err = m.sessionObj.Call(dbusSessionInterface+".Terminate", 0).Err - } - if err != nil { - return fmt.Errorf("failed to terminate session: %w", err) - } - } - return nil -} - -func (m *Manager) SetLockBeforeSuspend(enabled bool) { - m.lockBeforeSuspend.Store(enabled) -} - -func (m *Manager) SetSleepInhibitorEnabled(enabled bool) { - m.sleepInhibitorEnabled.Store(enabled) - if enabled { - // Re-acquire inhibitor if enabled - m.acquireSleepInhibitor() - } else { - // Release inhibitor if disabled - m.releaseSleepInhibitor() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/constants.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/constants.go deleted file mode 100644 index 1a29588..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/constants.go +++ /dev/null @@ -1,10 +0,0 @@ -package loginctl - -const ( - dbusDest = "org.freedesktop.login1" - dbusPath = "/org/freedesktop/login1" - dbusManagerInterface = "org.freedesktop.login1.Manager" - dbusSessionInterface = "org.freedesktop.login1.Session" - dbusUserInterface = "org.freedesktop.login1.User" - dbusPropsInterface = "org.freedesktop.DBus.Properties" -) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers.go deleted file mode 100644 index 564e996..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers.go +++ /dev/null @@ -1,156 +0,0 @@ -package loginctl - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "loginctl.getState": - handleGetState(conn, req, manager) - case "loginctl.lock": - handleLock(conn, req, manager) - case "loginctl.unlock": - handleUnlock(conn, req, manager) - case "loginctl.activate": - handleActivate(conn, req, manager) - case "loginctl.setIdleHint": - handleSetIdleHint(conn, req, manager) - case "loginctl.setLockBeforeSuspend": - handleSetLockBeforeSuspend(conn, req, manager) - case "loginctl.setSleepInhibitorEnabled": - handleSetSleepInhibitorEnabled(conn, req, manager) - case "loginctl.lockerReady": - handleLockerReady(conn, req, manager) - case "loginctl.terminate": - handleTerminate(conn, req, manager) - case "loginctl.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleLock(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.Lock(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "locked"}) -} - -func handleUnlock(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.Unlock(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "unlocked"}) -} - -func handleActivate(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.Activate(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "activated"}) -} - -func handleSetIdleHint(conn net.Conn, req models.Request, manager *Manager) { - idle, err := params.Bool(req.Params, "idle") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetIdleHint(idle); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "idle hint set"}) -} - -func handleSetLockBeforeSuspend(conn net.Conn, req models.Request, manager *Manager) { - enabled, err := params.Bool(req.Params, "enabled") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetLockBeforeSuspend(enabled) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "lock before suspend set"}) -} - -func handleSetSleepInhibitorEnabled(conn net.Conn, req models.Request, manager *Manager) { - enabled, err := params.Bool(req.Params, "enabled") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetSleepInhibitorEnabled(enabled) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "sleep inhibitor setting updated"}) -} - -func handleLockerReady(conn net.Conn, req models.Request, manager *Manager) { - manager.lockTimerMu.Lock() - if manager.lockTimer != nil { - manager.lockTimer.Stop() - manager.lockTimer = nil - } - manager.lockTimerMu.Unlock() - - id := manager.sleepCycleID.Load() - manager.releaseForCycle(id) - - if manager.inSleepCycle.Load() { - manager.signalLockerReady() - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "ok"}) -} - -func handleTerminate(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.Terminate(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "terminated"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - event := SessionEvent{ - Type: EventStateChanged, - Data: initialState, - } - if err := json.NewEncoder(conn).Encode(models.Response[SessionEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - return - } - - for state := range stateChan { - event := SessionEvent{ - Type: EventStateChanged, - Data: state, - } - if err := json.NewEncoder(conn).Encode(models.Response[SessionEvent]{ - Result: &event, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers_test.go deleted file mode 100644 index d3169e4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/handlers_test.go +++ /dev/null @@ -1,500 +0,0 @@ -package loginctl - -import ( - "bytes" - "encoding/json" - "net" - "sync" - "testing" - "time" - - mockdbus "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -type mockNetConn struct { - net.Conn - readBuf *bytes.Buffer - writeBuf *bytes.Buffer - closed bool -} - -func newMockNetConn() *mockNetConn { - return &mockNetConn{ - readBuf: &bytes.Buffer{}, - writeBuf: &bytes.Buffer{}, - } -} - -func (m *mockNetConn) Read(b []byte) (n int, err error) { - return m.readBuf.Read(b) -} - -func (m *mockNetConn) Write(b []byte) (n int, err error) { - return m.writeBuf.Write(b) -} - -func (m *mockNetConn) Close() error { - m.closed = true - return nil -} - -func TestRespondError_Loginctl(t *testing.T) { - conn := newMockNetConn() - models.RespondError(conn, 123, "test error") - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Equal(t, "test error", resp.Error) - assert.Nil(t, resp.Result) -} - -func TestRespond_Loginctl(t *testing.T) { - conn := newMockNetConn() - result := models.SuccessResult{Success: true, Message: "test"} - models.Respond(conn, 123, result) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "test", resp.Result.Message) -} - -func TestHandleGetState(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - Active: true, - SessionType: "wayland", - SessionClass: "user", - UserName: "testuser", - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.getState"} - - handleGetState(conn, req, manager) - - var resp models.Response[SessionState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.Equal(t, "1", resp.Result.SessionID) - assert.False(t, resp.Result.Locked) - assert.True(t, resp.Result.Active) -} - -func TestHandleLock(t *testing.T) { - t.Run("successful lock", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.lock"} - handleLock(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "locked", resp.Result.Message) - }) - - t.Run("lock fails", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: assert.AnError} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.lock"} - handleLock(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "failed to lock session") - }) -} - -func TestHandleUnlock(t *testing.T) { - t.Run("successful unlock", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Unlock", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.unlock"} - handleUnlock(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "unlocked", resp.Result.Message) - }) - - t.Run("unlock fails", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: assert.AnError} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Unlock", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.unlock"} - handleUnlock(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "failed to unlock session") - }) -} - -func TestHandleActivate(t *testing.T) { - t.Run("successful activate", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Activate", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.activate"} - handleActivate(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "activated", resp.Result.Message) - }) - - t.Run("activate fails", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: assert.AnError} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Activate", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.activate"} - handleActivate(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "failed to activate session") - }) -} - -func TestHandleSetIdleHint(t *testing.T) { - t.Run("missing idle parameter", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.setIdleHint", - Params: map[string]any{}, - } - - handleSetIdleHint(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'idle' parameter") - }) - - t.Run("successful set idle hint true", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.SetIdleHint", dbus.Flags(0), true).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.setIdleHint", - Params: map[string]any{ - "idle": true, - }, - } - - handleSetIdleHint(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "idle hint set", resp.Result.Message) - }) - - t.Run("set idle hint fails", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: assert.AnError} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.SetIdleHint", dbus.Flags(0), false).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.setIdleHint", - Params: map[string]any{ - "idle": false, - }, - } - - handleSetIdleHint(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "failed to set idle hint") - }) -} - -func TestHandleTerminate(t *testing.T) { - t.Run("successful terminate", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Terminate", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.terminate"} - handleTerminate(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "terminated", resp.Result.Message) - }) - - t.Run("terminate fails", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: assert.AnError} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Terminate", dbus.Flags(0)).Return(mockCall) - - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - sessionObj: mockSessionObj, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.terminate"} - handleTerminate(conn, req, manager) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "failed to terminate session") - }) -} - -func TestHandleRequest(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - }, - stateMutex: sync.RWMutex{}, - } - - t.Run("unknown method", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.unknown", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "unknown method") - }) - - t.Run("valid method - getState", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.getState", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[SessionState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - }) - - t.Run("lock method", func(t *testing.T) { - mockSessionObj := mockdbus.NewMockBusObject(t) - mockCall := &dbus.Call{Err: nil} - mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", mock.Anything).Return(mockCall) - - manager.sessionObj = mockSessionObj - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "loginctl.lock", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - }) -} - -func TestHandleSubscribe(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - }, - stateMutex: sync.RWMutex{}, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "loginctl.subscribe"} - - done := make(chan bool) - go func() { - handleSubscribe(conn, req, manager) - done <- true - }() - - time.Sleep(50 * time.Millisecond) - - conn.Close() - - if conn.writeBuf.Len() > 0 { - var resp models.Response[SessionEvent] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - if err == nil { - assert.Equal(t, 123, resp.ID) - require.NotNil(t, resp.Result) - assert.Equal(t, EventStateChanged, resp.Result.Type) - assert.Equal(t, "1", resp.Result.Data.SessionID) - } - } - - select { - case <-done: - case <-time.After(100 * time.Millisecond): - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager.go deleted file mode 100644 index 0c51e64..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager.go +++ /dev/null @@ -1,723 +0,0 @@ -package loginctl - -import ( - "context" - "fmt" - "os" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/godbus/dbus/v5" -) - -func NewManager() (*Manager, error) { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to system bus: %w", err) - } - - m := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - - stopChan: make(chan struct{}), - conn: conn, - dirty: make(chan struct{}, 1), - signals: make(chan *dbus.Signal, 256), - } - m.sleepInhibitorEnabled.Store(true) - - if err := m.initialize(); err != nil { - conn.Close() - return nil, err - } - - if err := m.acquireSleepInhibitor(); err != nil { - fmt.Fprintf(os.Stderr, "sleep inhibitor unavailable: %v\n", err) - } - - m.notifierWg.Add(1) - go m.notifier() - - if err := m.startSignalPump(); err != nil { - m.Close() - return nil, err - } - - return m, nil -} - -func (m *Manager) initialize() error { - m.managerObj = m.conn.Object(dbusDest, dbus.ObjectPath(dbusPath)) - - m.initializeFallbackDelay() - - sessionID, sessionPath, err := m.discoverSession() - if err != nil { - return fmt.Errorf("failed to get session path: %w", err) - } - - m.stateMutex.Lock() - m.state.SessionID = sessionID - m.state.SessionPath = string(sessionPath) - m.sessionPath = sessionPath - m.stateMutex.Unlock() - - m.sessionObj = m.conn.Object(dbusDest, sessionPath) - - if err := m.updateSessionState(); err != nil { - return err - } - - return nil -} - -func (m *Manager) discoverSession() (string, dbus.ObjectPath, error) { - // 1. Explicit XDG_SESSION_ID - if id := os.Getenv("XDG_SESSION_ID"); id != "" { - if path, err := m.getSession(id); err == nil { - fmt.Fprintf(os.Stderr, "loginctl: using XDG_SESSION_ID=%s\n", id) - return id, path, nil - } - } - - // 2. PID-based lookup (works when caller is inside a session cgroup) - if id, path, err := m.getSessionByPID(uint32(os.Getpid())); err == nil { - fmt.Fprintf(os.Stderr, "loginctl: found session %s via PID\n", id) - return id, path, nil - } - - // 3. User's primary display session (handles UWSM and similar) - if id, path, err := m.getUserDisplaySession(); err == nil { - fmt.Fprintf(os.Stderr, "loginctl: found session %s via User.Display\n", id) - return id, path, nil - } - - // 4. Score all sessions for current UID - if id, path, err := m.findBestSession(); err == nil { - fmt.Fprintf(os.Stderr, "loginctl: found session %s via ListSessions scoring\n", id) - return id, path, nil - } - - // 5. Last resort: "self" - path, err := m.getSession("self") - if err != nil { - return "", "", fmt.Errorf("%w", err) - } - return "self", path, nil -} - -func (m *Manager) getSession(id string) (dbus.ObjectPath, error) { - var out dbus.ObjectPath - err := m.managerObj.Call(dbusManagerInterface+".GetSession", 0, id).Store(&out) - if err != nil { - return "", err - } - return out, nil -} - -func (m *Manager) getSessionByPID(pid uint32) (string, dbus.ObjectPath, error) { - var path dbus.ObjectPath - if err := m.managerObj.Call(dbusManagerInterface+".GetSessionByPID", 0, pid).Store(&path); err != nil { - return "", "", err - } - - sessionObj := m.conn.Object(dbusDest, path) - var id dbus.Variant - if err := sessionObj.Call(dbusPropsInterface+".Get", 0, dbusSessionInterface, "Id").Store(&id); err != nil { - return "", "", err - } - return id.Value().(string), path, nil -} - -func (m *Manager) getUserDisplaySession() (string, dbus.ObjectPath, error) { - uid := uint32(os.Getuid()) - - var userPath dbus.ObjectPath - if err := m.managerObj.Call(dbusManagerInterface+".GetUser", 0, uid).Store(&userPath); err != nil { - return "", "", err - } - - userObj := m.conn.Object(dbusDest, userPath) - var display dbus.Variant - if err := userObj.Call(dbusPropsInterface+".Get", 0, dbusUserInterface, "Display").Store(&display); err != nil { - return "", "", err - } - - pair, ok := display.Value().([]any) - if !ok || len(pair) < 2 { - return "", "", fmt.Errorf("unexpected Display format") - } - - sessionID, _ := pair[0].(string) - sessionPath, _ := pair[1].(dbus.ObjectPath) - if sessionID == "" || sessionPath == "" { - return "", "", fmt.Errorf("empty Display session") - } - - return sessionID, sessionPath, nil -} - -type sessionCandidate struct { - id string - path dbus.ObjectPath -} - -func (m *Manager) findBestSession() (string, dbus.ObjectPath, error) { - // ListSessions returns a(susso): [][]any where each entry is [id, uid, name, seat, path] - var raw [][]any - if err := m.managerObj.Call(dbusManagerInterface+".ListSessions", 0).Store(&raw); err != nil { - return "", "", err - } - - uid := uint32(os.Getuid()) - var candidates []sessionCandidate - for _, entry := range raw { - if len(entry) < 5 { - continue - } - entryUID, _ := entry[1].(uint32) - if entryUID != uid { - continue - } - id, _ := entry[0].(string) - path, _ := entry[4].(dbus.ObjectPath) - if id != "" && path != "" { - candidates = append(candidates, sessionCandidate{id: id, path: path}) - } - } - if len(candidates) == 0 { - return "", "", fmt.Errorf("no sessions for uid %d", uid) - } - - bestScore := -1 - var best sessionCandidate - for _, c := range candidates { - score := m.scoreSession(c.path) - if score > bestScore { - bestScore = score - best = c - } - } - if bestScore < 0 { - return "", "", fmt.Errorf("no viable session found") - } - return best.id, best.path, nil -} - -func (m *Manager) scoreSession(path dbus.ObjectPath) int { - obj := m.conn.Object(dbusDest, path) - var props map[string]dbus.Variant - if err := obj.Call(dbusPropsInterface+".GetAll", 0, dbusSessionInterface).Store(&props); err != nil { - return -1 - } - - getStr := func(key string) string { - if v, ok := props[key]; ok { - if s, ok := v.Value().(string); ok { - return s - } - } - return "" - } - getBool := func(key string) bool { - if v, ok := props[key]; ok { - if b, ok := v.Value().(bool); ok { - return b - } - } - return false - } - getUint32 := func(key string) uint32 { - if v, ok := props[key]; ok { - if u, ok := v.Value().(uint32); ok { - return u - } - } - return 0 - } - - class := getStr("Class") - if class != "user" { - return -1 - } - if getBool("Remote") { - return -1 - } - - score := 0 - - if getBool("Active") { - score += 100 - } - - switch getStr("Type") { - case "wayland", "x11": - score += 80 - case "tty": - score += 10 - } - - if v, ok := props["Seat"]; ok { - if seatArr, ok := v.Value().([]any); ok && len(seatArr) >= 1 { - if seat, ok := seatArr[0].(string); ok && seat != "" { - score += 40 - if seat == "seat0" { - score += 10 - } - } - } - } - - if getUint32("VTNr") > 0 { - score += 20 - } - - return score -} - -func (m *Manager) refreshSessionBinding() error { - if m.managerObj == nil || m.conn == nil { - return fmt.Errorf("manager not fully initialized") - } - - sessionPath, err := m.getSession(m.state.SessionID) - if err != nil { - return fmt.Errorf("failed to get session path: %w", err) - } - - m.stateMutex.RLock() - currentPath := m.sessionPath - m.stateMutex.RUnlock() - - if sessionPath == currentPath { - return nil - } - - m.stopSignalPump() - - m.stateMutex.Lock() - m.state.SessionPath = string(sessionPath) - m.sessionPath = sessionPath - m.stateMutex.Unlock() - - m.sessionObj = m.conn.Object(dbusDest, sessionPath) - - if err := m.updateSessionState(); err != nil { - return err - } - - m.signals = make(chan *dbus.Signal, 256) - return m.startSignalPump() -} - -func (m *Manager) updateSessionState() error { - ctx := context.Background() - props, err := m.getSessionProperties(ctx) - if err != nil { - return err - } - - m.stateMutex.Lock() - defer m.stateMutex.Unlock() - - m.state.Active = dbusutil.GetOr(props, "Active", m.state.Active) - m.state.IdleHint = dbusutil.GetOr(props, "IdleHint", m.state.IdleHint) - m.state.IdleSinceHint = dbusutil.GetOr(props, "IdleSinceHint", m.state.IdleSinceHint) - if lockedHint, ok := dbusutil.Get[bool](props, "LockedHint"); ok { - m.state.LockedHint = lockedHint - m.state.Locked = lockedHint - } - m.state.SessionType = dbusutil.GetOr(props, "Type", m.state.SessionType) - m.state.SessionClass = dbusutil.GetOr(props, "Class", m.state.SessionClass) - if v, ok := props["User"]; ok { - if userArr, ok := v.Value().([]any); ok && len(userArr) >= 1 { - if uid, ok := userArr[0].(uint32); ok { - m.state.User = uid - } - } - } - m.state.UserName = dbusutil.GetOr(props, "Name", m.state.UserName) - m.state.RemoteHost = dbusutil.GetOr(props, "RemoteHost", m.state.RemoteHost) - m.state.Service = dbusutil.GetOr(props, "Service", m.state.Service) - m.state.TTY = dbusutil.GetOr(props, "TTY", m.state.TTY) - m.state.Display = dbusutil.GetOr(props, "Display", m.state.Display) - m.state.Remote = dbusutil.GetOr(props, "Remote", m.state.Remote) - if v, ok := props["Seat"]; ok { - if seatArr, ok := v.Value().([]any); ok && len(seatArr) >= 1 { - if seatID, ok := seatArr[0].(string); ok { - m.state.Seat = seatID - } - } - } - m.state.VTNr = dbusutil.GetOr(props, "VTNr", m.state.VTNr) - - return nil -} - -func (m *Manager) getSessionProperties(ctx context.Context) (map[string]dbus.Variant, error) { - var props map[string]dbus.Variant - err := m.sessionObj.CallWithContext(ctx, dbusPropsInterface+".GetAll", 0, dbusSessionInterface).Store(&props) - if err != nil { - return nil, err - } - return props, nil -} - -func (m *Manager) acquireSleepInhibitor() error { - if !m.sleepInhibitorEnabled.Load() { - return nil - } - - m.inhibitMu.Lock() - defer m.inhibitMu.Unlock() - - if m.inhibitFile != nil { - return nil - } - - if m.managerObj == nil { - return fmt.Errorf("manager object not available") - } - - file, err := m.inhibit("sleep", "DankMaterialShell", "Lock before suspend", "delay") - if err != nil { - return err - } - - m.inhibitFile = file - return nil -} - -func (m *Manager) inhibit(what, who, why, mode string) (*os.File, error) { - var fd dbus.UnixFD - err := m.managerObj.Call(dbusManagerInterface+".Inhibit", 0, what, who, why, mode).Store(&fd) - if err != nil { - return nil, err - } - return os.NewFile(uintptr(fd), "inhibit"), nil -} - -func (m *Manager) releaseSleepInhibitor() { - m.inhibitMu.Lock() - f := m.inhibitFile - m.inhibitFile = nil - m.inhibitMu.Unlock() - if f != nil { - f.Close() - } -} - -func (m *Manager) releaseForCycle(id uint64) { - if !m.inSleepCycle.Load() || m.sleepCycleID.Load() != id { - return - } - m.releaseSleepInhibitor() -} - -func (m *Manager) initializeFallbackDelay() { - var maxDelayUSec uint64 - err := m.managerObj.Call( - dbusPropsInterface+".Get", - 0, - dbusManagerInterface, - "InhibitDelayMaxUSec", - ).Store(&maxDelayUSec) - - if err != nil { - m.fallbackDelay = 2 * time.Second - return - } - - maxDelay := time.Duration(maxDelayUSec) * time.Microsecond - computed := (maxDelay * 8) / 10 - - if computed < 2*time.Second { - m.fallbackDelay = 2 * time.Second - } else if computed > 4*time.Second { - m.fallbackDelay = 4 * time.Second - } else { - m.fallbackDelay = computed - } -} - -func (m *Manager) newLockerReadyCh() chan struct{} { - m.lockerReadyChMu.Lock() - defer m.lockerReadyChMu.Unlock() - m.lockerReadyCh = make(chan struct{}) - return m.lockerReadyCh -} - -func (m *Manager) signalLockerReady() { - m.lockerReadyChMu.Lock() - ch := m.lockerReadyCh - if ch != nil { - close(ch) - m.lockerReadyCh = nil - } - m.lockerReadyChMu.Unlock() -} - -func (m *Manager) snapshotState() SessionState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return *m.state -} - -func stateChangedMeaningfully(old, new *SessionState) bool { - if old.Locked != new.Locked { - return true - } - if old.LockedHint != new.LockedHint { - return true - } - if old.Active != new.Active { - return true - } - if old.IdleHint != new.IdleHint { - return true - } - if old.PreparingForSleep != new.PreparingForSleep { - return true - } - return false -} - -func (m *Manager) GetState() SessionState { - return m.snapshotState() -} - -func (m *Manager) Subscribe(id string) chan SessionState { - ch := make(chan SessionState, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.snapshotState() - - if m.lastNotifiedState != nil && !stateChangedMeaningfully(m.lastNotifiedState, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan SessionState) bool { - select { - case ch <- currentState: - default: - } - return true - }) - - stateCopy := currentState - m.lastNotifiedState = &stateCopy - pending = false - } - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) startSignalPump() error { - m.conn.Signal(m.signals) - - if err := m.conn.AddMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ); err != nil { - m.conn.RemoveSignal(m.signals) - return err - } - if err := m.conn.AddMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Lock"), - ); err != nil { - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - m.conn.RemoveSignal(m.signals) - return err - } - if err := m.conn.AddMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Unlock"), - ); err != nil { - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Lock"), - ) - m.conn.RemoveSignal(m.signals) - return err - } - if err := m.conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)), - dbus.WithMatchInterface(dbusManagerInterface), - dbus.WithMatchMember("PrepareForSleep"), - ); err != nil { - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Lock"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Unlock"), - ) - m.conn.RemoveSignal(m.signals) - return err - } - - if err := m.conn.AddMatchSignal( - dbus.WithMatchObjectPath("/org/freedesktop/DBus"), - dbus.WithMatchInterface("org.freedesktop.DBus"), - dbus.WithMatchMember("NameOwnerChanged"), - ); err != nil { - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Lock"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Unlock"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)), - dbus.WithMatchInterface(dbusManagerInterface), - dbus.WithMatchMember("PrepareForSleep"), - ) - m.conn.RemoveSignal(m.signals) - return err - } - - m.sigWG.Add(1) - go func() { - defer m.sigWG.Done() - for { - select { - case <-m.stopChan: - return - case sig, ok := <-m.signals: - if !ok { - return - } - if sig == nil { - continue - } - m.handleDBusSignal(sig) - } - } - }() - return nil -} - -func (m *Manager) stopSignalPump() { - if m.conn == nil { - return - } - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Lock"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(m.sessionPath), - dbus.WithMatchInterface(dbusSessionInterface), - dbus.WithMatchMember("Unlock"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)), - dbus.WithMatchInterface(dbusManagerInterface), - dbus.WithMatchMember("PrepareForSleep"), - ) - m.conn.RemoveMatchSignal( - dbus.WithMatchObjectPath("/org/freedesktop/DBus"), - dbus.WithMatchInterface("org.freedesktop.DBus"), - dbus.WithMatchMember("NameOwnerChanged"), - ) - - m.conn.RemoveSignal(m.signals) - close(m.signals) - - m.sigWG.Wait() -} - -func (m *Manager) Close() { - close(m.stopChan) - m.notifierWg.Wait() - - m.stopSignalPump() - - m.releaseSleepInhibitor() - - m.subscribers.Range(func(key string, ch chan SessionState) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - if m.conn != nil { - m.conn.Close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager_test.go deleted file mode 100644 index 148ee60..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/manager_test.go +++ /dev/null @@ -1,296 +0,0 @@ -package loginctl - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestManager_GetState(t *testing.T) { - state := &SessionState{ - SessionID: "1", - Locked: false, - Active: true, - IdleHint: false, - SessionType: "wayland", - SessionClass: "user", - UserName: "testuser", - } - - manager := &Manager{ - state: state, - stateMutex: sync.RWMutex{}, - } - - result := manager.GetState() - assert.Equal(t, "1", result.SessionID) - assert.False(t, result.Locked) - assert.True(t, result.Active) - assert.Equal(t, "wayland", result.SessionType) - assert.Equal(t, "testuser", result.UserName) -} - -func TestManager_Subscribe(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - } - - ch := manager.Subscribe("test-client") - assert.NotNil(t, ch) - assert.Equal(t, 64, cap(ch)) - - _, exists := manager.subscribers.Load("test-client") - assert.True(t, exists) -} - -func TestManager_Unsubscribe(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - } - - ch := manager.Subscribe("test-client") - - manager.Unsubscribe("test-client") - - _, ok := <-ch - assert.False(t, ok) - - _, exists := manager.subscribers.Load("test-client") - assert.False(t, exists) -} - -func TestManager_Unsubscribe_NonExistent(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - } - - // Unsubscribe a non-existent client should not panic - assert.NotPanics(t, func() { - manager.Unsubscribe("non-existent") - }) -} - -func TestManager_NotifySubscribers(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - }, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - manager.notifierWg.Add(1) - go manager.notifier() - - ch := make(chan SessionState, 10) - manager.subscribers.Store("test-client", ch) - - manager.notifySubscribers() - - select { - case state := <-ch: - assert.Equal(t, "1", state.SessionID) - assert.False(t, state.Locked) - case <-time.After(200 * time.Millisecond): - t.Fatal("did not receive state update") - } - - close(manager.stopChan) - manager.notifierWg.Wait() -} - -func TestManager_NotifySubscribers_Debounce(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - }, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - manager.notifierWg.Add(1) - go manager.notifier() - - ch := make(chan SessionState, 10) - manager.subscribers.Store("test-client", ch) - - manager.notifySubscribers() - manager.notifySubscribers() - manager.notifySubscribers() - - receivedCount := 0 - timeout := time.After(200 * time.Millisecond) - for { - select { - case <-ch: - receivedCount++ - case <-timeout: - assert.Equal(t, 1, receivedCount, "should receive exactly one debounced update") - close(manager.stopChan) - manager.notifierWg.Wait() - return - } - } -} - -func TestManager_Close(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - } - - ch1 := make(chan SessionState, 1) - ch2 := make(chan SessionState, 1) - manager.subscribers.Store("client1", ch1) - manager.subscribers.Store("client2", ch2) - - manager.Close() - - select { - case <-manager.stopChan: - case <-time.After(100 * time.Millisecond): - t.Fatal("stopChan not closed") - } - - _, ok1 := <-ch1 - _, ok2 := <-ch2 - assert.False(t, ok1, "ch1 should be closed") - assert.False(t, ok2, "ch2 should be closed") - - count := 0 - manager.subscribers.Range(func(key string, ch chan SessionState) bool { - count++ - return true - }) - assert.Equal(t, 0, count) -} - -func TestManager_GetState_ThreadSafe(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - Active: true, - }, - stateMutex: sync.RWMutex{}, - } - - done := make(chan bool) - for i := 0; i < 10; i++ { - go func() { - state := manager.GetState() - assert.Equal(t, "1", state.SessionID) - assert.True(t, state.Active) - done <- true - }() - } - - for i := 0; i < 10; i++ { - select { - case <-done: - case <-time.After(1 * time.Second): - t.Fatal("timeout waiting for goroutines") - } - } -} - -func TestStateChangedMeaningfully(t *testing.T) { - tests := []struct { - name string - old *SessionState - new *SessionState - expected bool - }{ - { - name: "no change", - old: &SessionState{Locked: false, Active: true, IdleHint: false}, - new: &SessionState{Locked: false, Active: true, IdleHint: false}, - expected: false, - }, - { - name: "locked changed", - old: &SessionState{Locked: false, Active: true, IdleHint: false}, - new: &SessionState{Locked: true, Active: true, IdleHint: false}, - expected: true, - }, - { - name: "active changed", - old: &SessionState{Locked: false, Active: true, IdleHint: false}, - new: &SessionState{Locked: false, Active: false, IdleHint: false}, - expected: true, - }, - { - name: "idle hint changed", - old: &SessionState{Locked: false, Active: true, IdleHint: false}, - new: &SessionState{Locked: false, Active: true, IdleHint: true}, - expected: true, - }, - { - name: "locked hint changed", - old: &SessionState{Locked: false, Active: true, LockedHint: false}, - new: &SessionState{Locked: false, Active: true, LockedHint: true}, - expected: true, - }, - { - name: "preparing for sleep changed", - old: &SessionState{Locked: false, Active: true, PreparingForSleep: false}, - new: &SessionState{Locked: false, Active: true, PreparingForSleep: true}, - expected: true, - }, - { - name: "non-meaningful change (username)", - old: &SessionState{Locked: false, Active: true, UserName: "user1"}, - new: &SessionState{Locked: false, Active: true, UserName: "user2"}, - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := stateChangedMeaningfully(tt.old, tt.new) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestManager_SnapshotState(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - SessionID: "1", - Locked: false, - Active: true, - UserName: "testuser", - }, - stateMutex: sync.RWMutex{}, - } - - snapshot := manager.snapshotState() - assert.Equal(t, "1", snapshot.SessionID) - assert.False(t, snapshot.Locked) - assert.True(t, snapshot.Active) - assert.Equal(t, "testuser", snapshot.UserName) - - snapshot.Locked = true - assert.False(t, manager.state.Locked) -} - -func TestNewManager(t *testing.T) { - t.Run("attempts to create manager", func(t *testing.T) { - manager, err := NewManager() - if err != nil { - assert.Nil(t, manager) - } else { - assert.NotNil(t, manager) - assert.NotNil(t, manager.state) - assert.NotNil(t, &manager.subscribers) - assert.NotNil(t, manager.stopChan) - - manager.Close() - } - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor.go deleted file mode 100644 index 4c0605a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor.go +++ /dev/null @@ -1,155 +0,0 @@ -package loginctl - -import ( - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil" - "github.com/godbus/dbus/v5" -) - -func (m *Manager) handleDBusSignal(sig *dbus.Signal) { - switch sig.Name { - case dbusSessionInterface + ".Lock": - m.stateMutex.Lock() - m.state.Locked = true - m.state.LockedHint = true - m.stateMutex.Unlock() - m.notifySubscribers() - - if m.sleepInhibitorEnabled.Load() && m.inSleepCycle.Load() { - id := m.sleepCycleID.Load() - m.lockTimerMu.Lock() - if m.lockTimer != nil { - m.lockTimer.Stop() - } - m.lockTimer = time.AfterFunc(m.fallbackDelay, func() { - m.releaseForCycle(id) - }) - m.lockTimerMu.Unlock() - } - - case dbusSessionInterface + ".Unlock": - m.stateMutex.Lock() - m.state.Locked = false - m.state.LockedHint = false - m.stateMutex.Unlock() - m.notifySubscribers() - - // Cancel the lock timer if it's still running - m.lockTimerMu.Lock() - if m.lockTimer != nil { - m.lockTimer.Stop() - m.lockTimer = nil - } - m.lockTimerMu.Unlock() - - // Re-acquire the sleep inhibitor (acquireSleepInhibitor checks the enabled flag) - m.acquireSleepInhibitor() - - case dbusManagerInterface + ".PrepareForSleep": - if len(sig.Body) == 0 { - return - } - preparing, _ := sig.Body[0].(bool) - - if preparing { - cycleID := m.sleepCycleID.Add(1) - m.inSleepCycle.Store(true) - - if m.lockBeforeSuspend.Load() { - m.Lock() - } - - readyCh := m.newLockerReadyCh() - go func(id uint64, ch <-chan struct{}) { - <-ch - if m.inSleepCycle.Load() && m.sleepCycleID.Load() == id { - m.releaseSleepInhibitor() - } - }(cycleID, readyCh) - } else { - m.inSleepCycle.Store(false) - m.signalLockerReady() - m.refreshSessionBinding() - m.acquireSleepInhibitor() - } - - m.stateMutex.Lock() - m.state.PreparingForSleep = preparing - m.stateMutex.Unlock() - m.notifySubscribers() - - case dbusPropsInterface + ".PropertiesChanged": - m.handlePropertiesChanged(sig) - - case "org.freedesktop.DBus.NameOwnerChanged": - if len(sig.Body) == 3 { - name, _ := sig.Body[0].(string) - oldOwner, _ := sig.Body[1].(string) - newOwner, _ := sig.Body[2].(string) - if name == dbusDest && oldOwner != "" && newOwner != "" { - m.updateSessionState() - if !m.inSleepCycle.Load() { - m.acquireSleepInhibitor() - } - m.notifySubscribers() - } - } - } -} - -func (m *Manager) handlePropertiesChanged(sig *dbus.Signal) { - if len(sig.Body) < 2 { - return - } - - iface, ok := sig.Body[0].(string) - if !ok || iface != dbusSessionInterface { - return - } - - changes, ok := sig.Body[1].(map[string]dbus.Variant) - if !ok { - return - } - - var needsUpdate bool - - for key, variant := range changes { - switch key { - case "Active": - if val, ok := dbusutil.As[bool](variant); ok { - m.stateMutex.Lock() - m.state.Active = val - m.stateMutex.Unlock() - needsUpdate = true - } - case "IdleHint": - if val, ok := dbusutil.As[bool](variant); ok { - m.stateMutex.Lock() - m.state.IdleHint = val - m.stateMutex.Unlock() - needsUpdate = true - } - case "IdleSinceHint": - if val, ok := dbusutil.As[uint64](variant); ok { - m.stateMutex.Lock() - m.state.IdleSinceHint = val - m.stateMutex.Unlock() - needsUpdate = true - } - case "LockedHint": - if val, ok := dbusutil.As[bool](variant); ok { - m.stateMutex.Lock() - m.state.LockedHint = val - m.state.Locked = val - m.stateMutex.Unlock() - needsUpdate = true - } - } - } - - if needsUpdate { - m.notifySubscribers() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor_test.go deleted file mode 100644 index ecbb57f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/monitor_test.go +++ /dev/null @@ -1,298 +0,0 @@ -package loginctl - -import ( - "sync" - "testing" - - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" -) - -func TestManager_HandleDBusSignal_Lock(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - Locked: false, - LockedHint: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.login1.Session.Lock", - } - - manager.handleDBusSignal(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.Locked) - assert.True(t, manager.state.LockedHint) -} - -func TestManager_HandleDBusSignal_Unlock(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - Locked: true, - LockedHint: true, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.login1.Session.Unlock", - } - - manager.handleDBusSignal(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.False(t, manager.state.Locked) - assert.False(t, manager.state.LockedHint) -} - -func TestManager_HandleDBusSignal_PrepareForSleep(t *testing.T) { - t.Run("preparing for sleep - true", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - PreparingForSleep: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.login1.Manager.PrepareForSleep", - Body: []any{true}, - } - - manager.handleDBusSignal(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.PreparingForSleep) - }) - - t.Run("preparing for sleep - false", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - PreparingForSleep: true, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.login1.Manager.PrepareForSleep", - Body: []any{false}, - } - - manager.handleDBusSignal(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.False(t, manager.state.PreparingForSleep) - }) - - t.Run("empty body", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - PreparingForSleep: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.login1.Manager.PrepareForSleep", - Body: []any{}, - } - - manager.handleDBusSignal(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.False(t, manager.state.PreparingForSleep) - }) -} - -func TestManager_HandlePropertiesChanged(t *testing.T) { - t.Run("active property changed", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - Active: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.login1.Session", - map[string]dbus.Variant{ - "Active": dbus.MakeVariant(true), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.Active) - }) - - t.Run("idle hint property changed", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - IdleHint: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.login1.Session", - map[string]dbus.Variant{ - "IdleHint": dbus.MakeVariant(true), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.IdleHint) - }) - - t.Run("idle since hint property changed", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - IdleSinceHint: 0, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.login1.Session", - map[string]dbus.Variant{ - "IdleSinceHint": dbus.MakeVariant(uint64(123456789)), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.Equal(t, uint64(123456789), manager.state.IdleSinceHint) - }) - - t.Run("locked hint property changed", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - LockedHint: false, - Locked: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.login1.Session", - map[string]dbus.Variant{ - "LockedHint": dbus.MakeVariant(true), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.LockedHint) - assert.True(t, manager.state.Locked) - }) - - t.Run("wrong interface", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - Active: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.SomeOtherInterface", - map[string]dbus.Variant{ - "Active": dbus.MakeVariant(true), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.False(t, manager.state.Active) - }) - - t.Run("empty body", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{}, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{}, - } - - assert.NotPanics(t, func() { - manager.handlePropertiesChanged(sig) - }) - }) - - t.Run("multiple properties changed", func(t *testing.T) { - manager := &Manager{ - state: &SessionState{ - Active: false, - IdleHint: false, - }, - stateMutex: sync.RWMutex{}, - dirty: make(chan struct{}, 1), - } - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{ - "org.freedesktop.login1.Session", - map[string]dbus.Variant{ - "Active": dbus.MakeVariant(true), - "IdleHint": dbus.MakeVariant(true), - }, - }, - } - - manager.handlePropertiesChanged(sig) - - manager.stateMutex.RLock() - defer manager.stateMutex.RUnlock() - assert.True(t, manager.state.Active) - assert.True(t, manager.state.IdleHint) - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types.go deleted file mode 100644 index 76c7414..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types.go +++ /dev/null @@ -1,76 +0,0 @@ -package loginctl - -import ( - "os" - "sync" - "sync/atomic" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type SessionState struct { - SessionID string `json:"sessionId"` - SessionPath string `json:"sessionPath"` - Locked bool `json:"locked"` - Active bool `json:"active"` - IdleHint bool `json:"idleHint"` - IdleSinceHint uint64 `json:"idleSinceHint"` - LockedHint bool `json:"lockedHint"` - SessionType string `json:"sessionType"` - SessionClass string `json:"sessionClass"` - User uint32 `json:"user"` - UserName string `json:"userName"` - RemoteHost string `json:"remoteHost"` - Service string `json:"service"` - TTY string `json:"tty"` - Display string `json:"display"` - Remote bool `json:"remote"` - Seat string `json:"seat"` - VTNr uint32 `json:"vtnr"` - PreparingForSleep bool `json:"preparingForSleep"` -} - -type EventType string - -const ( - EventStateChanged EventType = "state_changed" - EventLock EventType = "lock" - EventUnlock EventType = "unlock" - EventPrepareForSleep EventType = "prepare_for_sleep" - EventIdleHintChanged EventType = "idle_hint_changed" - EventLockedHintChanged EventType = "locked_hint_changed" -) - -type SessionEvent struct { - Type EventType `json:"type"` - Data SessionState `json:"data"` -} - -type Manager struct { - state *SessionState - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan SessionState] - stopChan chan struct{} - conn *dbus.Conn - sessionPath dbus.ObjectPath - managerObj dbus.BusObject - sessionObj dbus.BusObject - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotifiedState *SessionState - signals chan *dbus.Signal - sigWG sync.WaitGroup - inhibitMu sync.Mutex - inhibitFile *os.File - lockBeforeSuspend atomic.Bool - inSleepCycle atomic.Bool - sleepCycleID atomic.Uint64 - lockerReadyChMu sync.Mutex - lockerReadyCh chan struct{} - lockTimerMu sync.Mutex - lockTimer *time.Timer - sleepInhibitorEnabled atomic.Bool - fallbackDelay time.Duration -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types_test.go deleted file mode 100644 index 383300f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/loginctl/types_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package loginctl - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestEventType_Constants(t *testing.T) { - assert.Equal(t, EventType("state_changed"), EventStateChanged) - assert.Equal(t, EventType("lock"), EventLock) - assert.Equal(t, EventType("unlock"), EventUnlock) - assert.Equal(t, EventType("prepare_for_sleep"), EventPrepareForSleep) - assert.Equal(t, EventType("idle_hint_changed"), EventIdleHintChanged) - assert.Equal(t, EventType("locked_hint_changed"), EventLockedHintChanged) -} - -func TestSessionState_Struct(t *testing.T) { - state := SessionState{ - SessionID: "1", - Locked: false, - Active: true, - SessionType: "wayland", - User: 1000, - UserName: "testuser", - } - - assert.Equal(t, "1", state.SessionID) - assert.True(t, state.Active) - assert.False(t, state.Locked) - assert.Equal(t, "wayland", state.SessionType) - assert.Equal(t, uint32(1000), state.User) - assert.Equal(t, "testuser", state.UserName) -} - -func TestSessionEvent_Struct(t *testing.T) { - state := SessionState{ - SessionID: "1", - Locked: true, - } - - event := SessionEvent{ - Type: EventLock, - Data: state, - } - - assert.Equal(t, EventLock, event.Type) - assert.Equal(t, "1", event.Data.SessionID) - assert.True(t, event.Data.Locked) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/matugen_handler.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/matugen_handler.go deleted file mode 100644 index 73c6ad6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/matugen_handler.go +++ /dev/null @@ -1,79 +0,0 @@ -package server - -import ( - "context" - "net" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/matugen" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type MatugenQueueResult struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` -} - -func handleMatugenQueue(conn net.Conn, req models.Request) { - opts := matugen.Options{ - StateDir: models.GetOr(req, "stateDir", ""), - ShellDir: models.GetOr(req, "shellDir", ""), - ConfigDir: models.GetOr(req, "configDir", ""), - Kind: models.GetOr(req, "kind", ""), - Value: models.GetOr(req, "value", ""), - Mode: matugen.ColorMode(models.GetOr(req, "mode", "")), - IconTheme: models.GetOr(req, "iconTheme", ""), - MatugenType: models.GetOr(req, "matugenType", ""), - RunUserTemplates: models.GetOr(req, "runUserTemplates", true), - StockColors: models.GetOr(req, "stockColors", ""), - SyncModeWithPortal: models.GetOr(req, "syncModeWithPortal", false), - TerminalsAlwaysDark: models.GetOr(req, "terminalsAlwaysDark", false), - SkipTemplates: models.GetOr(req, "skipTemplates", ""), - Contrast: models.GetOr(req, "contrast", 0.0), - } - - wait := models.GetOr(req, "wait", true) - - queue := matugen.GetQueue() - resultCh := queue.Submit(opts) - - if !wait { - models.Respond(conn, req.ID, MatugenQueueResult{ - Success: true, - Message: "queued", - }) - return - } - - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - select { - case result := <-resultCh: - if result.Error != nil { - if result.Error == context.Canceled { - models.Respond(conn, req.ID, MatugenQueueResult{ - Success: false, - Message: "cancelled", - }) - return - } - models.RespondError(conn, req.ID, result.Error.Error()) - return - } - models.Respond(conn, req.ID, MatugenQueueResult{ - Success: true, - Message: "completed", - }) - case <-ctx.Done(): - models.RespondError(conn, req.ID, "timeout waiting for theme generation") - } -} - -func handleMatugenStatus(conn net.Conn, req models.Request) { - queue := matugen.GetQueue() - models.Respond(conn, req.ID, map[string]bool{ - "running": queue.IsRunning(), - "pending": queue.HasPending(), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types.go deleted file mode 100644 index 2933fb5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types.go +++ /dev/null @@ -1,47 +0,0 @@ -package models - -import ( - "encoding/json" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -type Request struct { - ID int `json:"id,omitempty"` - Method string `json:"method"` - Params map[string]any `json:"params,omitempty"` -} - -func Get[T any](r Request, key string) (T, bool) { - v, err := params.Get[T](r.Params, key) - return v, err == nil -} - -func GetOr[T any](r Request, key string, def T) T { - return params.GetOpt(r.Params, key, def) -} - -type Response[T any] struct { - ID int `json:"id,omitempty"` - Result *T `json:"result,omitempty"` - Error string `json:"error,omitempty"` -} - -func RespondError(conn net.Conn, id int, errMsg string) { - log.Errorf("DMS API Error: id=%d error=%s", id, errMsg) - resp := Response[any]{ID: id, Error: errMsg} - json.NewEncoder(conn).Encode(resp) -} - -func Respond[T any](conn net.Conn, id int, result T) { - resp := Response[T]{ID: id, Result: &result} - json.NewEncoder(conn).Encode(resp) -} - -type SuccessResult struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Value string `json:"value,omitempty"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types_test.go deleted file mode 100644 index 98f9528..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/models/types_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package models - -import "testing" - -func TestGet(t *testing.T) { - req := Request{Params: map[string]any{"name": "test", "count": 42, "enabled": true}} - - name, ok := Get[string](req, "name") - if !ok || name != "test" { - t.Errorf("Get[string] = %q, %v; want 'test', true", name, ok) - } - - count, ok := Get[int](req, "count") - if !ok || count != 42 { - t.Errorf("Get[int] = %d, %v; want 42, true", count, ok) - } - - enabled, ok := Get[bool](req, "enabled") - if !ok || !enabled { - t.Errorf("Get[bool] = %v, %v; want true, true", enabled, ok) - } - - _, ok = Get[string](req, "missing") - if ok { - t.Error("Get missing key should return false") - } - - _, ok = Get[int](req, "name") - if ok { - t.Error("Get wrong type should return false") - } -} - -func TestGetOr(t *testing.T) { - req := Request{Params: map[string]any{"name": "test", "enabled": true}} - - if v := GetOr(req, "name", "default"); v != "test" { - t.Errorf("GetOr existing = %q; want 'test'", v) - } - - if v := GetOr(req, "missing", "default"); v != "default" { - t.Errorf("GetOr missing = %q; want 'default'", v) - } - - if v := GetOr(req, "enabled", false); !v { - t.Errorf("GetOr bool = %v; want true", v) - } - - if v := GetOr(req, "name", 0); v != 0 { - t.Errorf("GetOr wrong type = %d; want 0 (default)", v) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/API.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/API.md deleted file mode 100644 index 361ebac..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/API.md +++ /dev/null @@ -1,552 +0,0 @@ -# NetworkManager API Documentation - -## Overview - -The network manager API provides methods for managing WiFi connections, monitoring network state, and handling credential prompts through NetworkManager or iwd (and systemd-networkd for ethernet only). Communication occurs over a message-based protocol (websocket, IPC, etc.) with event subscriptions for state updates. - -## API Methods - -### network.wifi.connect - -Initiate a WiFi connection. - -**Request:** -```json -{ - "method": "network.wifi.connect", - "params": { - "ssid": "NetworkName", - "password": "optional-password", - "interactive": true - } -} -``` - -**Parameters:** -- `ssid` (string, required): Network SSID -- `password` (string, optional): Pre-shared key for WPA/WPA2/WPA3 networks -- `interactive` (boolean, optional): Enable credential prompting if authentication fails or password is missing. Automatically set to `true` when connecting to secured networks without providing a password. - -**Response:** -```json -{ - "success": true, - "message": "connecting" -} -``` - -**Behavior:** -- Returns immediately; connection happens asynchronously -- State updates delivered via `network` service subscription -- Credential prompts delivered via `network.credentials` service subscription - -### network.credentials.submit - -Submit credentials in response to a prompt. - -**Request:** -```json -{ - "method": "network.credentials.submit", - "params": { - "token": "correlation-token", - "secrets": { - "psk": "password" - }, - "save": true - } -} -``` - -**Parameters:** -- `token` (string, required): Token from credential prompt -- `secrets` (object, required): Key-value map of credential fields -- `save` (boolean, optional): Whether to persist credentials (default: false) - -**Common secret fields:** -- `psk`: Pre-shared key for WPA2/WPA3 personal networks -- `identity`: Username for 802.1X enterprise networks -- `password`: Password for 802.1X enterprise networks - -### network.credentials.cancel - -Cancel a credential prompt. - -**Request:** -```json -{ - "method": "network.credentials.cancel", - "params": { - "token": "correlation-token" - } -} -``` - -## Event Subscriptions - -### Subscribing to Events - -Subscribe to receive network state updates and credential prompts: - -```json -{ - "method": "subscribe", - "params": { - "services": ["network", "network.credentials"] - } -} -``` - -Both services are required for full connection handling. Missing `network.credentials` means credential prompts won't be received. - -### network Service Events - -State updates are sent whenever network configuration changes: - -```json -{ - "service": "network", - "data": { - "networkStatus": "wifi", - "isConnecting": false, - "connectingSSID": "", - "wifiConnected": true, - "wifiSSID": "MyNetwork", - "wifiIP": "192.168.1.100", - "lastError": "" - } -} -``` - -**State fields:** -- `networkStatus`: Current connection type (`wifi`, `ethernet`, `disconnected`) -- `isConnecting`: Whether a connection attempt is in progress -- `connectingSSID`: SSID being connected to (empty when idle) -- `wifiConnected`: Whether associated with an access point -- `wifiSSID`: Currently connected network name -- `wifiIP`: Assigned IP address (empty until DHCP completes) -- `lastError`: Error message from last failed connection attempt - -### network.credentials Service Events - -Credential prompts are sent when authentication is required: - -```json -{ - "service": "network.credentials", - "data": { - "token": "unique-prompt-id", - "ssid": "NetworkName", - "setting": "802-11-wireless-security", - "fields": ["psk"], - "hints": ["wpa3", "sae"], - "reason": "Credentials required" - } -} -``` - -**Prompt fields:** -- `token`: Unique identifier for this prompt (use in submit/cancel) -- `ssid`: Network requesting credentials -- `setting`: Authentication type (`802-11-wireless-security` for personal WiFi, `802-1x` for enterprise) -- `fields`: Array of required credential field names -- `hints`: Additional context about the network type -- `reason`: Human-readable explanation (e.g., "Previous password was incorrect") - -## Connection Flow - -### Typical Timeline - -``` -T+0ms Call network.wifi.connect -T+10ms Receive {"success": true, "message": "connecting"} -T+100ms State update: isConnecting=true, connectingSSID="Network" -T+500ms Credential prompt (if needed) -T+1000ms Submit credentials -T+3000ms State update: wifiConnected=true, wifiIP="192.168.x.x" -``` - -### State Machine - -``` -IDLE - | - | network.wifi.connect - v -CONNECTING (isConnecting=true, connectingSSID set) - | - +-- Needs credentials - | | - | v - | PROMPTING (credential prompt event) - | | - | | network.credentials.submit - | v - | back to CONNECTING - | - +-- Success - | | - | v - | CONNECTED (wifiConnected=true, wifiIP set, isConnecting=false) - | - +-- Failure - | - v - ERROR (isConnecting=false, !wifiConnected, lastError set) -``` - -## Connection Success Detection - -A connection is successful when all of the following are true: - -1. `wifiConnected` is `true` -2. `wifiIP` is set and non-empty -3. `wifiSSID` matches the target network -4. `isConnecting` is `false` - -Do not rely on `wifiConnected` alone - the device may be associated with an access point but not have an IP address yet. - -**Example:** -```javascript -function isConnectionComplete(state, targetSSID) { - return state.wifiConnected && - state.wifiIP && - state.wifiIP !== "" && - state.wifiSSID === targetSSID && - !state.isConnecting; -} -``` - -## Error Handling - -### Error Detection - -Errors occur when a connection attempt stops without success: - -```javascript -function checkForFailure(state, wasConnecting, targetSSID) { - // Was connecting, now idle, but not connected - if (wasConnecting && - !state.isConnecting && - state.connectingSSID === "" && - !state.wifiConnected) { - return state.lastError || "Connection failed"; - } - return null; -} -``` - -### Common Error Scenarios - -#### Wrong Password - -**Detection methods:** - -1. Quick failure (< 3 seconds from start) -2. `lastError` contains "password", "auth", or "secrets" -3. Second credential prompt with `reason: "Previous password was incorrect"` - -**Handling:** -```javascript -if (prompt.reason === "Previous password was incorrect") { - // Show error, clear password field, re-focus input -} -``` - -#### Network Out of Range - -**Detection:** -- `lastError` contains "not-found" or "connection-attempt-failed" - -#### Connection Timeout - -**Detection:** -- `isConnecting` remains true for > 30 seconds - -**Implementation:** -```javascript -let timeout = setTimeout(() => { - if (currentState.isConnecting) { - handleTimeout(); - } -}, 30000); -``` - -#### DHCP Failure - -**Detection:** -- `wifiConnected` is true -- `wifiIP` is empty after 15+ seconds - -### Error Message Translation - -Map technical errors to user-friendly messages: - -| lastError value | Meaning | User message | -|----------------|---------|--------------| -| `secrets-required` | Password needed | "Please enter password" | -| `authentication-failed` | Wrong password | "Incorrect password" | -| `connection-removed` | Profile deleted | "Network configuration removed" | -| `connection-attempt-failed` | Generic failure | "Failed to connect" | -| `network-not-found` | Out of range | "Network not found" | -| `(timeout)` | Timeout | "Connection timed out" | - -## Credential Handling - -### Secret Agent Architecture - -The credential system uses a broker pattern: - -``` -NetworkManager -> SecretAgent -> PromptBroker -> UI -> User - ^ - | - User Response - | -NetworkManager <- SecretAgent <- PromptBroker <- UI -``` - -### Implementing a Broker - -```go -type CustomBroker struct { - ui UIInterface - pending map[string]chan network.PromptReply -} - -func (b *CustomBroker) Ask(ctx context.Context, req network.PromptRequest) (string, error) { - token := generateToken() - b.pending[token] = make(chan network.PromptReply, 1) - - // Send to UI - b.ui.ShowCredentialPrompt(token, req) - - return token, nil -} - -func (b *CustomBroker) Wait(ctx context.Context, token string) (network.PromptReply, error) { - select { - case <-ctx.Done(): - return network.PromptReply{}, errors.New("timeout") - case reply := <-b.pending[token]: - return reply, nil - } -} - -func (b *CustomBroker) Resolve(token string, reply network.PromptReply) error { - if ch, ok := b.pending[token]; ok { - ch <- reply - close(ch) - delete(b.pending, token) - } - return nil -} -``` - -### Credential Field Types - -**Personal WiFi (802-11-wireless-security):** -- Fields: `["psk"]` -- UI: Single password input - -**Enterprise WiFi (802-1x):** -- Fields: `["identity", "password"]` -- UI: Username and password inputs - -### Building Secrets Object - -```javascript -function buildSecrets(setting, fields, formData) { - let secrets = {}; - - if (setting === "802-11-wireless-security") { - secrets.psk = formData.password; - } else if (setting === "802-1x") { - secrets.identity = formData.username; - secrets.password = formData.password; - } - - return secrets; -} -``` - -## Best Practices - -### Track Target Network - -Always store which network you're connecting to: - -```javascript -let targetSSID = null; - -function connect(ssid) { - targetSSID = ssid; - // send request -} - -function onStateUpdate(state) { - if (!targetSSID) return; - - if (state.wifiSSID === targetSSID && state.wifiConnected && state.wifiIP) { - // Success for the network we care about - targetSSID = null; - } -} -``` - -### Implement Timeouts - -Never wait indefinitely for a connection: - -```javascript -const CONNECTION_TIMEOUT = 30000; // 30 seconds -const DHCP_TIMEOUT = 15000; // 15 seconds - -let timer = setTimeout(() => { - if (stillConnecting) { - handleTimeout(); - } -}, CONNECTION_TIMEOUT); -``` - -### Handle Credential Re-prompts - -Wrong passwords trigger a second prompt: - -```javascript -function onCredentialPrompt(prompt) { - if (prompt.reason.includes("incorrect")) { - // Show error, but keep dialog open - showError("Wrong password"); - clearPasswordField(); - } else { - // First time prompt - showDialog(prompt); - } -} -``` - -### Clean Up State - -Reset tracking variables on success, failure, or cancellation: - -```javascript -function cleanup() { - clearTimeout(timer); - targetSSID = null; - closeDialogs(); -} -``` - -### Subscribe to Both Services - -Missing `network.credentials` means prompts won't arrive: - -```javascript -// Correct -services: ["network", "network.credentials"] - -// Wrong - will miss credential prompts -services: ["network"] -``` - -## Testing - -### Connection Test Checklist - -- [ ] Connect to open network -- [ ] Connect to WPA2 network with password provided -- [ ] Connect to WPA2 network without password (triggers prompt) -- [ ] Enter wrong password (verify error and re-prompt) -- [ ] Cancel credential prompt -- [ ] Connection timeout after 30 seconds -- [ ] DHCP timeout detection -- [ ] Network out of range -- [ ] Reconnect to already-configured network - -### Verifying Secret Agent Setup - -Check connection profile flags: -```bash -nmcli connection show "NetworkName" | grep flags -# Should show: 802-11-wireless-security.psk-flags: 1 (agent-owned) -``` - -Check agent registration in logs: -``` -INFO: Registered with NetworkManager as secret agent -``` - -## Security - -- Never log credential values (passwords, PSKs) -- Clear password fields when dialogs close -- Implement prompt timeouts (default: 2 minutes) -- Validate user input before submission -- Use secure channels for credential transmission - -## Troubleshooting - -### Credential prompt doesn't appear - -**Check:** -- Subscribed to both `network` and `network.credentials` -- Connection has `interactive: true` -- Secret flags set to AGENT_OWNED (value: 1) -- Broker registered successfully - -### Connection succeeds without prompting - -**Cause:** NetworkManager found saved credentials - -**Solution:** Delete existing connection first, or use different credentials - -### State updates seem delayed - -**Expected behavior:** State changes occur in rapid succession during connection - -**Solution:** Debounce UI updates; only act on final state - -### Multiple rapid credential prompts - -**Cause:** Connection profile has incorrect flags or conflicting agents - -**Solution:** -- Check only one agent is running -- Verify psk-flags value -- Check NetworkManager logs for agent conflicts - -## Data Structures Reference - -### PromptRequest -```go -type PromptRequest struct { - SSID string `json:"ssid"` - SettingName string `json:"setting"` - Fields []string `json:"fields"` - Hints []string `json:"hints"` - Reason string `json:"reason"` -} -``` - -### PromptReply -```go -type PromptReply struct { - Secrets map[string]string `json:"secrets"` - Save bool `json:"save"` - Cancel bool `json:"cancel"` -} -``` - -### NetworkState -```go -type NetworkState struct { - NetworkStatus string `json:"networkStatus"` - IsConnecting bool `json:"isConnecting"` - ConnectingSSID string `json:"connectingSSID"` - WifiConnected bool `json:"wifiConnected"` - WifiSSID string `json:"wifiSSID"` - WifiIP string `json:"wifiIP"` - LastError string `json:"lastError"` -} -``` diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_iwd.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_iwd.go deleted file mode 100644 index 5d49f04..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_iwd.go +++ /dev/null @@ -1,306 +0,0 @@ -package network - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/godbus/dbus/v5" -) - -const ( - iwdAgentManagerPath = "/net/connman/iwd" - iwdAgentManagerIface = "net.connman.iwd.AgentManager" - iwdAgentInterface = "net.connman.iwd.Agent" - iwdAgentObjectPath = "/com/danklinux/iwdagent" -) - -type ConnectionStateChecker interface { - IsConnectingTo(ssid string) bool -} - -type IWDAgent struct { - conn *dbus.Conn - objPath dbus.ObjectPath - prompts PromptBroker - onUserCanceled func() - onPromptRetry func(ssid string) - lastRequestSSID string - stateChecker ConnectionStateChecker -} - -const iwdAgentIntrospectXML = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - -` - -func NewIWDAgent(conn *dbus.Conn, prompts PromptBroker) (*IWDAgent, error) { - if conn == nil { - return nil, fmt.Errorf("dbus connection is nil") - } - - agent := &IWDAgent{ - conn: conn, - objPath: dbus.ObjectPath(iwdAgentObjectPath), - prompts: prompts, - } - - if err := conn.Export(agent, agent.objPath, iwdAgentInterface); err != nil { - return nil, fmt.Errorf("failed to export IWD agent: %w", err) - } - - if err := conn.Export(agent, agent.objPath, "org.freedesktop.DBus.Introspectable"); err != nil { - return nil, fmt.Errorf("failed to export introspection: %w", err) - } - - mgr := conn.Object("net.connman.iwd", dbus.ObjectPath(iwdAgentManagerPath)) - call := mgr.Call(iwdAgentManagerIface+".RegisterAgent", 0, agent.objPath) - if call.Err != nil { - return nil, fmt.Errorf("failed to register agent with iwd: %w", call.Err) - } - - return agent, nil -} - -func (a *IWDAgent) Close() { - if a.conn != nil { - mgr := a.conn.Object("net.connman.iwd", dbus.ObjectPath(iwdAgentManagerPath)) - mgr.Call(iwdAgentManagerIface+".UnregisterAgent", 0, a.objPath) - } -} - -func (a *IWDAgent) SetStateChecker(checker ConnectionStateChecker) { - a.stateChecker = checker -} - -func (a *IWDAgent) getNetworkName(networkPath dbus.ObjectPath) string { - netObj := a.conn.Object("net.connman.iwd", networkPath) - nameVar, err := netObj.GetProperty("net.connman.iwd.Network.Name") - if err == nil { - if name, ok := nameVar.Value().(string); ok { - return name - } - } - return string(networkPath) -} - -func (a *IWDAgent) RequestPassphrase(network dbus.ObjectPath) (string, *dbus.Error) { - ssid := a.getNetworkName(network) - - if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.prompts == nil { - if a.onUserCanceled != nil { - a.onUserCanceled() - } - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.lastRequestSSID == ssid { - if a.onPromptRetry != nil { - a.onPromptRetry(ssid) - } - } - a.lastRequestSSID = ssid - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - token, err := a.prompts.Ask(ctx, PromptRequest{ - SSID: ssid, - Fields: []string{"psk"}, - }) - if err != nil { - if a.onUserCanceled != nil { - a.onUserCanceled() - } - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - reply, err := a.prompts.Wait(ctx, token) - if err != nil { - if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) { - if a.onUserCanceled != nil { - a.onUserCanceled() - } - } - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if passphrase, ok := reply.Secrets["psk"]; ok { - return passphrase, nil - } - - if a.onUserCanceled != nil { - a.onUserCanceled() - } - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) -} - -func (a *IWDAgent) RequestPrivateKeyPassphrase(network dbus.ObjectPath) (string, *dbus.Error) { - ssid := a.getNetworkName(network) - - if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.prompts == nil { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.lastRequestSSID == ssid { - if a.onPromptRetry != nil { - a.onPromptRetry(ssid) - } - } - a.lastRequestSSID = ssid - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - token, err := a.prompts.Ask(ctx, PromptRequest{ - SSID: ssid, - Fields: []string{"private-key-password"}, - }) - if err != nil { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - reply, err := a.prompts.Wait(ctx, token) - if err != nil || reply.Cancel { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if passphrase, ok := reply.Secrets["private-key-password"]; ok { - return passphrase, nil - } - - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) -} - -func (a *IWDAgent) RequestUserNameAndPassword(network dbus.ObjectPath) (string, string, *dbus.Error) { - ssid := a.getNetworkName(network) - - if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) { - return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.prompts == nil { - return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.lastRequestSSID == ssid { - if a.onPromptRetry != nil { - a.onPromptRetry(ssid) - } - } - a.lastRequestSSID = ssid - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - token, err := a.prompts.Ask(ctx, PromptRequest{ - SSID: ssid, - Fields: []string{"identity", "password"}, - }) - if err != nil { - return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - reply, err := a.prompts.Wait(ctx, token) - if err != nil || reply.Cancel { - return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - username, hasUser := reply.Secrets["identity"] - password, hasPass := reply.Secrets["password"] - - if hasUser && hasPass { - return username, password, nil - } - - return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) -} - -func (a *IWDAgent) RequestUserPassword(network dbus.ObjectPath, user string) (string, *dbus.Error) { - ssid := a.getNetworkName(network) - - if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.prompts == nil { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if a.lastRequestSSID == ssid { - if a.onPromptRetry != nil { - a.onPromptRetry(ssid) - } - } - a.lastRequestSSID = ssid - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - token, err := a.prompts.Ask(ctx, PromptRequest{ - SSID: ssid, - Fields: []string{"password"}, - }) - if err != nil { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - reply, err := a.prompts.Wait(ctx, token) - if err != nil || reply.Cancel { - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) - } - - if password, ok := reply.Secrets["password"]; ok { - return password, nil - } - - return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil) -} - -func (a *IWDAgent) Cancel(reason string) *dbus.Error { - return nil -} - -func (a *IWDAgent) Release() *dbus.Error { - return nil -} - -func (a *IWDAgent) Introspect() (string, *dbus.Error) { - return iwdAgentIntrospectXML, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager.go deleted file mode 100644 index 088b7fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager.go +++ /dev/null @@ -1,897 +0,0 @@ -package network - -import ( - "context" - "errors" - "fmt" - "strconv" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -const ( - nmAgentManagerPath = "/org/freedesktop/NetworkManager/AgentManager" - nmAgentManagerIface = "org.freedesktop.NetworkManager.AgentManager" - nmSecretAgentIface = "org.freedesktop.NetworkManager.SecretAgent" - agentObjectPath = "/org/freedesktop/NetworkManager/SecretAgent" - agentIdentifier = "com.danklinux.NMAgent" -) - -type SecretAgent struct { - conn *dbus.Conn - objPath dbus.ObjectPath - id string - prompts PromptBroker - manager *Manager - backend *NetworkManagerBackend -} - -type ( - nmVariantMap map[string]dbus.Variant - nmSettingMap map[string]nmVariantMap -) - -const introspectXML = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - -` - -func NewSecretAgent(prompts PromptBroker, manager *Manager, backend *NetworkManagerBackend) (*SecretAgent, error) { - c, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to system bus: %w", err) - } - - sa := &SecretAgent{ - conn: c, - objPath: dbus.ObjectPath(agentObjectPath), - id: agentIdentifier, - prompts: prompts, - manager: manager, - backend: backend, - } - - if err := c.Export(sa, sa.objPath, nmSecretAgentIface); err != nil { - c.Close() - return nil, fmt.Errorf("failed to export secret agent: %w", err) - } - - if err := c.Export(sa, sa.objPath, "org.freedesktop.DBus.Introspectable"); err != nil { - c.Close() - return nil, fmt.Errorf("failed to export introspection: %w", err) - } - - mgr := c.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(nmAgentManagerPath)) - call := mgr.Call(nmAgentManagerIface+".Register", 0, sa.id) - if call.Err != nil { - c.Close() - return nil, fmt.Errorf("failed to register agent with NetworkManager: %w", call.Err) - } - - log.Infof("[SecretAgent] Registered with NetworkManager (id=%s, unique name=%s, fixed path=%s)", sa.id, c.Names()[0], sa.objPath) - return sa, nil -} - -func (a *SecretAgent) Close() { - if a.conn != nil { - mgr := a.conn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(nmAgentManagerPath)) - mgr.Call(nmAgentManagerIface+".Unregister", 0, a.id) - a.conn.Close() - } -} - -func (a *SecretAgent) GetSecrets( - conn map[string]nmVariantMap, - path dbus.ObjectPath, - settingName string, - hints []string, - flags uint32, -) (nmSettingMap, *dbus.Error) { - log.Infof("[SecretAgent] GetSecrets called: path=%s, setting=%s, hints=%v, flags=%d", - path, settingName, hints, flags) - - connType, displayName, vpnSvc := readConnTypeAndName(conn) - ssid := readSSID(conn) - fields := fieldsNeeded(settingName, hints, conn) - vpnPasswordFlags := readVPNPasswordFlags(conn, settingName) - - log.Infof("[SecretAgent] connType=%s, name=%s, vpnSvc=%s, fields=%v, flags=%d, vpnPasswordFlags=%d", connType, displayName, vpnSvc, fields, flags, vpnPasswordFlags) - - if a.backend != nil { - a.backend.stateMutex.RLock() - isConnecting := a.backend.state.IsConnecting - connectingSSID := a.backend.state.ConnectingSSID - isConnectingVPN := a.backend.state.IsConnectingVPN - connectingVPNUUID := a.backend.state.ConnectingVPNUUID - a.backend.stateMutex.RUnlock() - - switch connType { - case "802-11-wireless": - // If we're connecting to a WiFi network, only respond if it's the one we're connecting to - if isConnecting && connectingSSID != ssid { - log.Infof("[SecretAgent] Ignoring WiFi request for SSID '%s' - we're connecting to '%s'", ssid, connectingSSID) - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } - case "vpn", "wireguard": - var connUuid string - if c, ok := conn["connection"]; ok { - if v, ok := c["uuid"]; ok { - if s, ok2 := v.Value().(string); ok2 { - connUuid = s - } - } - } - - // If we're connecting to a VPN, only respond if it's the one we're connecting to - // This prevents interfering with nmcli/other tools when our app isn't connecting - if isConnectingVPN && connUuid != connectingVPNUUID { - log.Infof("[SecretAgent] Ignoring VPN request for UUID '%s' - we're connecting to '%s'", connUuid, connectingVPNUUID) - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } - } - } - - if len(fields) == 0 { - if settingName == "vpn" { - if a.backend != nil { - a.backend.stateMutex.RLock() - isConnectingVPN := a.backend.state.IsConnectingVPN - a.backend.stateMutex.RUnlock() - - if !isConnectingVPN { - log.Infof("[SecretAgent] VPN with empty hints - deferring to other agents for %s", vpnSvc) - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } - - fields = inferVPNFields(conn, vpnSvc) - log.Infof("[SecretAgent] VPN with empty hints but we're connecting - inferred fields: %v", fields) - } else { - log.Infof("[SecretAgent] VPN with empty hints - deferring to other agents for %s", vpnSvc) - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } - } - - if len(fields) == 0 { - const ( - NM_SETTING_SECRET_FLAG_NONE = 0 - NM_SETTING_SECRET_FLAG_AGENT_OWNED = 1 - NM_SETTING_SECRET_FLAG_NOT_SAVED = 2 - NM_SETTING_SECRET_FLAG_NOT_REQUIRED = 4 - ) - - var passwordFlags uint32 = 0xFFFF - switch settingName { - case "802-11-wireless-security": - if wifiSecSettings, ok := conn["802-11-wireless-security"]; ok { - if flagsVariant, ok := wifiSecSettings["psk-flags"]; ok { - if pwdFlags, ok := flagsVariant.Value().(uint32); ok { - passwordFlags = pwdFlags - } - } - } - case "802-1x": - if dot1xSettings, ok := conn["802-1x"]; ok { - if flagsVariant, ok := dot1xSettings["password-flags"]; ok { - if pwdFlags, ok := flagsVariant.Value().(uint32); ok { - passwordFlags = pwdFlags - } - } - } - } - - if passwordFlags == 0xFFFF { - log.Warnf("[SecretAgent] Could not determine password-flags for empty hints - returning NoSecrets error") - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } else if passwordFlags&NM_SETTING_SECRET_FLAG_NOT_REQUIRED != 0 { - log.Infof("[SecretAgent] Secrets not required (flags=%d)", passwordFlags) - out := nmSettingMap{} - out[settingName] = nmVariantMap{} - return out, nil - } else if passwordFlags&NM_SETTING_SECRET_FLAG_AGENT_OWNED != 0 { - switch settingName { - case "802-11-wireless-security": - fields = []string{"psk"} - case "802-1x": - fields = infer8021xFields(conn) - default: - log.Warnf("[SecretAgent] Agent-owned secrets for unhandled setting %s (flags=%d)", settingName, passwordFlags) - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) - } - log.Infof("[SecretAgent] Agent-owned secrets, inferred fields: %v", fields) - } else { - log.Infof("[SecretAgent] No secrets needed, using system stored secrets (flags=%d)", passwordFlags) - out := nmSettingMap{} - out[settingName] = nmVariantMap{} - return out, nil - } - } - } - - reason := reasonFromFlags(flags) - if a.manager != nil && connType == "802-11-wireless" && a.manager.WasRecentlyFailed(ssid) { - reason = "wrong-password" - } - if settingName == "vpn" && isPKCS11Auth(conn, vpnSvc) { - reason = "pkcs11" - } - - var connId, connUuid string - if c, ok := conn["connection"]; ok { - if v, ok := c["id"]; ok { - if s, ok2 := v.Value().(string); ok2 { - connId = s - } - } - if v, ok := c["uuid"]; ok { - if s, ok2 := v.Value().(string); ok2 { - connUuid = s - } - } - } - - if settingName == "vpn" && a.backend != nil { - // Check for cached PKCS11 PIN first - isPKCS11Request := len(fields) == 1 && fields[0] == "key_pass" - if isPKCS11Request { - a.backend.cachedPKCS11Mu.Lock() - cached := a.backend.cachedPKCS11PIN - if cached != nil && cached.ConnectionUUID == connUuid { - a.backend.cachedPKCS11PIN = nil - a.backend.cachedPKCS11Mu.Unlock() - - log.Infof("[SecretAgent] Using cached PKCS11 PIN") - - out := nmSettingMap{} - vpnSec := nmVariantMap{} - vpnSec["secrets"] = dbus.MakeVariant(map[string]string{"key_pass": cached.PIN}) - out[settingName] = vpnSec - - return out, nil - } - a.backend.cachedPKCS11Mu.Unlock() - } - - // Check for cached VPN password - a.backend.cachedVPNCredsMu.Lock() - cached := a.backend.cachedVPNCreds - if cached != nil && cached.ConnectionUUID == connUuid { - a.backend.cachedVPNCreds = nil - a.backend.cachedVPNCredsMu.Unlock() - - log.Infof("[SecretAgent] Using cached password from pre-activation prompt") - - out := nmSettingMap{} - vpnSec := nmVariantMap{} - vpnSec["secrets"] = dbus.MakeVariant(map[string]string{"password": cached.Password}) - out[settingName] = vpnSec - - if cached.SavePassword { - a.backend.pendingVPNSaveMu.Lock() - a.backend.pendingVPNSave = &pendingVPNCredentials{ - ConnectionPath: string(path), - Password: cached.Password, - SavePassword: true, - } - a.backend.pendingVPNSaveMu.Unlock() - } - - return out, nil - } - a.backend.cachedVPNCredsMu.Unlock() - - a.backend.cachedGPSamlMu.Lock() - cachedGPSaml := a.backend.cachedGPSamlCookie - if cachedGPSaml != nil && cachedGPSaml.ConnectionUUID == connUuid { - a.backend.cachedGPSamlMu.Unlock() - - log.Infof("[SecretAgent] Using cached GlobalProtect SAML cookie for %s", connUuid) - - return buildGPSamlSecretsResponse(settingName, cachedGPSaml.Cookie, cachedGPSaml.Host, cachedGPSaml.Fingerprint), nil - } - a.backend.cachedGPSamlMu.Unlock() - - if len(fields) == 1 && fields[0] == "gp-saml" { - gateway := "" - protocol := "" - if vpnSettings, ok := conn["vpn"]; ok { - if dataVariant, ok := vpnSettings["data"]; ok { - if dataMap, ok := dataVariant.Value().(map[string]string); ok { - if gw, ok := dataMap["gateway"]; ok { - gateway = gw - } - if proto, ok := dataMap["protocol"]; ok && proto != "" { - protocol = proto - } - } - } - } - - if protocol != "gp" { - return nil, dbus.MakeFailedError(fmt.Errorf("gp-saml auth only supported for GlobalProtect (protocol=gp), got: %s", protocol)) - } - - log.Infof("[SecretAgent] Starting GlobalProtect SAML authentication for gateway=%s", gateway) - - samlCtx, samlCancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer samlCancel() - - authResult, err := a.backend.runGlobalProtectSAMLAuth(samlCtx, gateway, protocol) - if err != nil { - log.Warnf("[SecretAgent] GlobalProtect SAML authentication failed: %v", err) - return nil, dbus.MakeFailedError(fmt.Errorf("GlobalProtect SAML authentication failed: %w", err)) - } - - log.Infof("[SecretAgent] GlobalProtect SAML authentication successful, returning cookie to NetworkManager") - - a.backend.cachedGPSamlMu.Lock() - a.backend.cachedGPSamlCookie = &cachedGPSamlCookie{ - ConnectionUUID: connUuid, - Cookie: authResult.Cookie, - Host: authResult.Host, - User: authResult.User, - Fingerprint: authResult.Fingerprint, - } - a.backend.cachedGPSamlMu.Unlock() - - return buildGPSamlSecretsResponse(settingName, authResult.Cookie, authResult.Host, authResult.Fingerprint), nil - } - } - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - token, err := a.prompts.Ask(ctx, PromptRequest{ - Name: displayName, - SSID: ssid, - ConnType: connType, - VpnService: vpnSvc, - SettingName: settingName, - Fields: fields, - FieldsInfo: buildFieldsInfo(settingName, fields, vpnSvc), - Hints: hints, - Reason: reason, - ConnectionId: connId, - ConnectionUuid: connUuid, - ConnectionPath: string(path), - }) - if err != nil { - log.Warnf("[SecretAgent] Failed to create prompt: %v", err) - return nil, dbus.MakeFailedError(err) - } - - log.Infof("[SecretAgent] Waiting for user input (token=%s)", token) - reply, err := a.prompts.Wait(ctx, token) - if err != nil { - log.Warnf("[SecretAgent] Prompt failed or cancelled: %v", err) - - // Clear connecting state immediately on cancellation - if a.backend != nil { - a.backend.stateMutex.Lock() - wasConnecting := a.backend.state.IsConnecting - wasConnectingVPN := a.backend.state.IsConnectingVPN - cancelledSSID := a.backend.state.ConnectingSSID - cancelledVPNUUID := a.backend.state.ConnectingVPNUUID - if wasConnecting || wasConnectingVPN { - log.Infof("[SecretAgent] Clearing connecting state due to cancelled prompt") - a.backend.state.IsConnecting = false - a.backend.state.ConnectingSSID = "" - a.backend.state.IsConnectingVPN = false - a.backend.state.ConnectingVPNUUID = "" - } - a.backend.stateMutex.Unlock() - - // If this was a WiFi connection that was just cancelled, remove the connection profile - // (it was created with AddConnection but activation was cancelled) - if wasConnecting && cancelledSSID != "" && connType == "802-11-wireless" { - log.Infof("[SecretAgent] Removing connection profile for cancelled WiFi connection: %s", cancelledSSID) - if err := a.backend.ForgetWiFiNetwork(cancelledSSID); err != nil { - log.Warnf("[SecretAgent] Failed to remove cancelled connection profile: %v", err) - } - } - - // If this was a VPN connection that was cancelled, deactivate it - if wasConnectingVPN && cancelledVPNUUID != "" { - log.Infof("[SecretAgent] Deactivating cancelled VPN connection: %s", cancelledVPNUUID) - if err := a.backend.DisconnectVPN(cancelledVPNUUID); err != nil { - log.Warnf("[SecretAgent] Failed to deactivate cancelled VPN: %v", err) - } - } - - if (wasConnecting || wasConnectingVPN) && a.backend.onStateChange != nil { - a.backend.onStateChange() - } - } - - if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) { - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.UserCanceled", nil) - } - - if errors.Is(err, errdefs.ErrSecretPromptTimeout) { - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.Failed", nil) - } - return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.Failed", nil) - } - - log.Infof("[SecretAgent] User provided secrets, save=%v", reply.Save) - - out := nmSettingMap{} - sec := nmVariantMap{} - - var vpnUsername string - for k, v := range reply.Secrets { - if settingName == "vpn" && k == "username" { - vpnUsername = v - } - sec[k] = dbus.MakeVariant(v) - } - - // Check if this is PKCS11 auth (key_pass) - pin, isPKCS11 := reply.Secrets["key_pass"] - - switch settingName { - case "vpn": - // VPN secrets must be wrapped in a "secrets" key per NM spec - secretsDict := make(map[string]string) - for k, v := range reply.Secrets { - if k != "username" { - secretsDict[k] = v - } - } - vpnSec := nmVariantMap{} - vpnSec["secrets"] = dbus.MakeVariant(secretsDict) - out[settingName] = vpnSec - log.Infof("[SecretAgent] Returning VPN secrets with %d fields for %s", len(secretsDict), vpnSvc) - - // Cache PKCS11 PIN in case GetSecrets is called again during activation - if isPKCS11 && a.backend != nil { - a.backend.cachedPKCS11Mu.Lock() - a.backend.cachedPKCS11PIN = &cachedPKCS11PIN{ - ConnectionUUID: connUuid, - PIN: pin, - } - a.backend.cachedPKCS11Mu.Unlock() - log.Infof("[SecretAgent] Cached PKCS11 PIN for potential re-request") - } - case "802-1x": - secretsOnly := nmVariantMap{} - for k, v := range reply.Secrets { - switch k { - case "password", "private-key-password", "phase2-private-key-password", "pin": - secretsOnly[k] = dbus.MakeVariant(v) - } - } - out[settingName] = secretsOnly - - if identity, ok := reply.Secrets["identity"]; ok && identity != "" { - a.save8021xIdentity(path, identity) - } - log.Infof("[SecretAgent] Returning 802-1x enterprise secrets with %d fields", len(secretsOnly)) - default: - out[settingName] = sec - } - if settingName == "vpn" && a.backend != nil && !isPKCS11 && (vpnUsername != "" || reply.Save) { - pw := reply.Secrets["password"] - a.backend.pendingVPNSaveMu.Lock() - a.backend.pendingVPNSave = &pendingVPNCredentials{ - ConnectionPath: string(path), - Username: vpnUsername, - Password: pw, - SavePassword: reply.Save, - } - a.backend.pendingVPNSaveMu.Unlock() - log.Infof("[SecretAgent] Queued credentials persist for after connection succeeds") - } - - return out, nil -} - -func (a *SecretAgent) DeleteSecrets(conn map[string]nmVariantMap, path dbus.ObjectPath) *dbus.Error { - ssid := readSSID(conn) - log.Infof("[SecretAgent] DeleteSecrets called: path=%s, SSID=%s", path, ssid) - return nil -} - -func (a *SecretAgent) DeleteSecrets2(path dbus.ObjectPath, setting string) *dbus.Error { - log.Infof("[SecretAgent] DeleteSecrets2 (alternate) called: path=%s, setting=%s", path, setting) - return nil -} - -func (a *SecretAgent) CancelGetSecrets(path dbus.ObjectPath, settingName string) *dbus.Error { - log.Infof("[SecretAgent] CancelGetSecrets called: path=%s, setting=%s", path, settingName) - - if a.prompts != nil { - if err := a.prompts.Cancel(string(path), settingName); err != nil { - log.Warnf("[SecretAgent] Failed to cancel prompt: %v", err) - } - } - - return nil -} - -func (a *SecretAgent) Introspect() (string, *dbus.Error) { - return introspectXML, nil -} - -func (a *SecretAgent) save8021xIdentity(path dbus.ObjectPath, identity string) { - connObj := a.conn.Object("org.freedesktop.NetworkManager", path) - var existing map[string]map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existing); err != nil { - log.Warnf("[SecretAgent] Failed to get settings for identity save: %v", err) - return - } - - settings := make(map[string]map[string]dbus.Variant) - if connSection, ok := existing["connection"]; ok { - settings["connection"] = connSection - } - - dot1x, ok := existing["802-1x"] - if !ok { - dot1x = make(map[string]dbus.Variant) - } - dot1x["identity"] = dbus.MakeVariant(identity) - settings["802-1x"] = dot1x - - var result map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, - settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil { - log.Warnf("[SecretAgent] Failed to save 802.1x identity: %v", err) - return - } - log.Infof("[SecretAgent] Saved 802.1x identity to connection profile") -} - -func readSSID(conn map[string]nmVariantMap) string { - if w, ok := conn["802-11-wireless"]; ok { - if v, ok := w["ssid"]; ok { - if b, ok := v.Value().([]byte); ok { - return string(b) - } - if s, ok := v.Value().(string); ok { - return s - } - } - } - return "" -} - -func readConnTypeAndName(conn map[string]nmVariantMap) (string, string, string) { - var connType, name, svc string - if c, ok := conn["connection"]; ok { - if v, ok := c["type"]; ok { - if s, ok2 := v.Value().(string); ok2 { - connType = s - } - } - if v, ok := c["id"]; ok { - if s, ok2 := v.Value().(string); ok2 { - name = s - } - } - } - if vpn, ok := conn["vpn"]; ok { - if v, ok := vpn["service-type"]; ok { - if s, ok2 := v.Value().(string); ok2 { - svc = s - } - } - } - if name == "" && connType == "802-11-wireless" { - name = readSSID(conn) - } - return connType, name, svc -} - -func fieldsNeeded(setting string, hints []string, conn map[string]nmVariantMap) []string { - switch setting { - case "802-11-wireless-security": - return []string{"psk"} - case "802-1x": - if len(hints) > 0 { - return hints - } - return infer8021xFields(conn) - case "vpn": - return hints - default: - return []string{} - } -} - -func infer8021xFields(conn map[string]nmVariantMap) []string { - dot1x, ok := conn["802-1x"] - if !ok { - return []string{"identity", "password"} - } - - var fields []string - - if v, ok := dot1x["identity"]; ok { - if id, ok := v.Value().(string); ok && id != "" { - // identity already stored, don't ask again - } else { - fields = append(fields, "identity") - } - } else { - fields = append(fields, "identity") - } - - var eapMethods []string - if v, ok := dot1x["eap"]; ok { - if methods, ok := v.Value().([]string); ok { - eapMethods = methods - } - } - - switch { - case len(eapMethods) > 0 && eapMethods[0] == "tls": - fields = append(fields, "private-key-password") - default: - fields = append(fields, "password") - } - - return fields -} - -func buildFieldsInfo(setting string, fields []string, vpnService string) []FieldInfo { - result := make([]FieldInfo, 0, len(fields)) - for _, f := range fields { - info := FieldInfo{Name: f} - switch setting { - case "802-11-wireless-security": - info.Label = "Password" - info.IsSecret = true - case "802-1x": - switch f { - case "identity": - info.Label = "Username" - info.IsSecret = false - case "password": - info.Label = "Password" - info.IsSecret = true - default: - info.Label = f - info.IsSecret = true - } - case "vpn": - info.Label, info.IsSecret = vpnFieldMeta(f, vpnService) - default: - info.Label = f - info.IsSecret = true - } - result = append(result, info) - } - return result -} - -func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string { - fields := []string{"password"} - - vpnSettings, ok := conn["vpn"] - if !ok { - return fields - } - - dataVariant, ok := vpnSettings["data"] - if !ok { - return fields - } - - dataMap, ok := dataVariant.Value().(map[string]string) - if !ok { - return fields - } - - connType := dataMap["connection-type"] - - switch { - case strings.Contains(vpnService, "openconnect"): - protocol := dataMap["protocol"] - authType := dataMap["authtype"] - username := dataMap["username"] - - if authType == "cert" && strings.HasPrefix(dataMap["usercert"], "pkcs11:") { - return []string{"key_pass"} - } - - if needsExternalBrowserAuth(protocol, authType, username, dataMap) { - switch protocol { - case "gp": - log.Infof("[SecretAgent] GlobalProtect SAML auth detected") - return []string{"gp-saml"} - default: - log.Infof("[SecretAgent] External browser auth detected for protocol '%s' but only GlobalProtect (gp) SAML is currently supported, falling back to credentials", protocol) - } - } - - if username == "" { - fields = []string{"username", "password"} - } - case strings.Contains(vpnService, "openvpn"): - if connType == "password" || connType == "password-tls" { - if dataMap["username"] == "" { - fields = []string{"username", "password"} - } - } - case strings.Contains(vpnService, "vpnc"), strings.Contains(vpnService, "l2tp"), - strings.Contains(vpnService, "pptp"): - if dataMap["username"] == "" { - fields = []string{"username", "password"} - } - } - - return fields -} - -func needsExternalBrowserAuth(protocol, authType, username string, data map[string]string) bool { - if method, ok := data["saml-auth-method"]; ok { - if method == "REDIRECT" || method == "POST" { - return true - } - } - - if authType != "" && authType != "password" && authType != "cert" { - return true - } - - switch protocol { - case "gp": - if authType == "" && username == "" { - return true - } - } - - return false -} - -func vpnFieldMeta(field, vpnService string) (label string, isSecret bool) { - switch field { - case "gp-saml": - return "GlobalProtect SAML/SSO", false - case "key_pass": - return "PIN", true - case "password": - return "Password", true - case "Xauth password": - return "IPSec Password", true - case "IPSec secret": - return "IPSec Pre-Shared Key", true - case "cert-pass": - return "Certificate Password", true - case "http-proxy-password": - return "HTTP Proxy Password", true - case "username": - return "Username", false - case "Xauth username": - return "IPSec Username", false - case "proxy-password": - return "Proxy Password", true - case "private-key-password": - return "Private Key Password", true - } - titleCaser := cases.Title(language.English) - if strings.HasSuffix(field, "password") || strings.HasSuffix(field, "secret") || - strings.HasSuffix(field, "pass") || strings.HasSuffix(field, "psk") { - return titleCaser.String(strings.ReplaceAll(field, "-", " ")), true - } - return titleCaser.String(strings.ReplaceAll(field, "-", " ")), false -} - -func isPKCS11Auth(conn map[string]nmVariantMap, vpnService string) bool { - if !strings.Contains(vpnService, "openconnect") { - return false - } - vpnSettings, ok := conn["vpn"] - if !ok { - return false - } - dataVariant, ok := vpnSettings["data"] - if !ok { - return false - } - dataMap, ok := dataVariant.Value().(map[string]string) - if !ok { - return false - } - return dataMap["authtype"] == "cert" && strings.HasPrefix(dataMap["usercert"], "pkcs11:") -} - -func readVPNPasswordFlags(conn map[string]nmVariantMap, settingName string) uint32 { - if settingName != "vpn" { - return 0xFFFF - } - - vpnSettings, ok := conn["vpn"] - if !ok { - return 0xFFFF - } - - dataVariant, ok := vpnSettings["data"] - if !ok { - return 0xFFFF - } - - dataMap, ok := dataVariant.Value().(map[string]string) - if !ok { - return 0xFFFF - } - - flagsStr, ok := dataMap["password-flags"] - if !ok { - return 0xFFFF - } - - flags64, err := strconv.ParseUint(flagsStr, 10, 32) - if err != nil { - return 0xFFFF - } - - return uint32(flags64) -} - -func reasonFromFlags(flags uint32) string { - const ( - NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE = 0x0 - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1 - NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW = 0x2 - NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED = 0x4 - NM_SECRET_AGENT_GET_SECRETS_FLAG_WPS_PBC_ACTIVE = 0x8 - NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM = 0x80000000 - NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS = 0x40000000 - ) - - if flags&NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW != 0 { - return "wrong-password" - } - if flags&NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED != 0 { - return "user-requested" - } - return "required" -} - -func buildGPSamlSecretsResponse(settingName, cookie, host, fingerprint string) nmSettingMap { - out := nmSettingMap{} - vpnSec := nmVariantMap{} - - secrets := map[string]string{ - "cookie": cookie, - "gateway": host, - "gwcert": fingerprint, - } - vpnSec["secrets"] = dbus.MakeVariant(secrets) - - out[settingName] = vpnSec - return out -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager_test.go deleted file mode 100644 index 2040986..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/agent_networkmanager_test.go +++ /dev/null @@ -1,355 +0,0 @@ -package network - -import ( - "testing" - - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" -) - -func TestNeedsExternalBrowserAuth(t *testing.T) { - tests := []struct { - name string - protocol string - authType string - username string - data map[string]string - expected bool - }{ - { - name: "GP with saml-auth-method REDIRECT", - protocol: "gp", - authType: "password", - username: "user", - data: map[string]string{"saml-auth-method": "REDIRECT"}, - expected: true, - }, - { - name: "GP with saml-auth-method POST", - protocol: "gp", - authType: "password", - username: "user", - data: map[string]string{"saml-auth-method": "POST"}, - expected: true, - }, - { - name: "GP with no authtype and no username", - protocol: "gp", - authType: "", - username: "", - data: map[string]string{}, - expected: true, - }, - { - name: "GP with username and password authtype", - protocol: "gp", - authType: "password", - username: "john", - data: map[string]string{}, - expected: false, - }, - { - name: "GP with username but no authtype", - protocol: "gp", - authType: "", - username: "john", - data: map[string]string{}, - expected: false, - }, - { - name: "GP with authtype but no username - should detect SAML", - protocol: "gp", - authType: "", - username: "", - data: map[string]string{}, - expected: true, - }, - { - name: "pulse with SAML", - protocol: "pulse", - authType: "", - username: "", - data: map[string]string{"saml-auth-method": "REDIRECT"}, - expected: true, - }, - { - name: "fortinet with non-password authtype", - protocol: "fortinet", - authType: "saml", - username: "", - data: map[string]string{}, - expected: true, - }, - { - name: "anyconnect with cert", - protocol: "anyconnect", - authType: "cert", - username: "", - data: map[string]string{}, - expected: false, - }, - { - name: "anyconnect with password", - protocol: "anyconnect", - authType: "password", - username: "user", - data: map[string]string{}, - expected: false, - }, - { - name: "empty protocol", - protocol: "", - authType: "", - username: "", - data: map[string]string{}, - expected: false, - }, - { - name: "GP with cert authtype", - protocol: "gp", - authType: "cert", - username: "", - data: map[string]string{}, - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := needsExternalBrowserAuth(tt.protocol, tt.authType, tt.username, tt.data) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestBuildGPSamlSecretsResponse(t *testing.T) { - tests := []struct { - name string - settingName string - cookie string - host string - fingerprint string - }{ - { - name: "all fields populated", - settingName: "vpn", - cookie: "authcookie=abc123&portal=GATE", - host: "vpn.example.com", - fingerprint: "pin-sha256:ABCD1234", - }, - { - name: "empty fingerprint", - settingName: "vpn", - cookie: "authcookie=xyz", - host: "10.0.0.1", - fingerprint: "", - }, - { - name: "complex cookie with special chars", - settingName: "vpn", - cookie: "authcookie=077058d3bc81&portal=PANGP_GW_01-N&user=john.doe@example.com&domain=Default&preferred-ip=192.168.1.100", - host: "connect.seclore.com", - fingerprint: "pin-sha256:xp3scfzy3rOgQEXnfPiYKrUk7D66a8b8O+gEXaMPleE=", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := buildGPSamlSecretsResponse(tt.settingName, tt.cookie, tt.host, tt.fingerprint) - - assert.NotNil(t, result) - assert.Contains(t, result, tt.settingName) - - vpnSec := result[tt.settingName] - assert.NotNil(t, vpnSec) - - secretsVariant, ok := vpnSec["secrets"] - assert.True(t, ok, "secrets key should exist") - - secrets, ok := secretsVariant.Value().(map[string]string) - assert.True(t, ok, "secrets should be map[string]string") - - assert.Equal(t, tt.cookie, secrets["cookie"]) - assert.Equal(t, tt.host, secrets["gateway"]) - assert.Equal(t, tt.fingerprint, secrets["gwcert"]) - }) - } -} - -func TestVpnFieldMeta_GPSaml(t *testing.T) { - label, isSecret := vpnFieldMeta("gp-saml", "org.freedesktop.NetworkManager.openconnect") - - assert.Equal(t, "GlobalProtect SAML/SSO", label) - assert.False(t, isSecret, "gp-saml should not be marked as secret") -} - -func TestVpnFieldMeta_StandardFields(t *testing.T) { - tests := []struct { - field string - vpnService string - expectedLabel string - expectedSecret bool - }{ - { - field: "username", - vpnService: "org.freedesktop.NetworkManager.openconnect", - expectedLabel: "Username", - expectedSecret: false, - }, - { - field: "password", - vpnService: "org.freedesktop.NetworkManager.openconnect", - expectedLabel: "Password", - expectedSecret: true, - }, - { - field: "key_pass", - vpnService: "org.freedesktop.NetworkManager.openconnect", - expectedLabel: "PIN", - expectedSecret: true, - }, - } - - for _, tt := range tests { - t.Run(tt.field, func(t *testing.T) { - label, isSecret := vpnFieldMeta(tt.field, tt.vpnService) - assert.Equal(t, tt.expectedLabel, label) - assert.Equal(t, tt.expectedSecret, isSecret) - }) - } -} - -func TestInferVPNFields_GPSaml(t *testing.T) { - tests := []struct { - name string - vpnService string - dataMap map[string]string - expectedLen int - shouldHave []string - }{ - { - name: "GP with no authtype and no username - should require SAML", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - }, - expectedLen: 1, - shouldHave: []string{"gp-saml"}, - }, - { - name: "GP with saml-auth-method REDIRECT", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - "saml-auth-method": "REDIRECT", - "username": "john", - }, - expectedLen: 1, - shouldHave: []string{"gp-saml"}, - }, - { - name: "GP with saml-auth-method POST", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - "saml-auth-method": "POST", - }, - expectedLen: 1, - shouldHave: []string{"gp-saml"}, - }, - { - name: "GP with username and password authtype - should use credentials", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - "authtype": "password", - "username": "john", - }, - expectedLen: 1, - shouldHave: []string{"password"}, - }, - { - name: "GP with username but no authtype - password only", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - "username": "john", - }, - expectedLen: 1, - shouldHave: []string{"password"}, - }, - { - name: "GP with PKCS11 cert", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "gp", - "gateway": "vpn.example.com", - "authtype": "cert", - "usercert": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II", - }, - expectedLen: 1, - shouldHave: []string{"key_pass"}, - }, - { - name: "non-GP protocol (anyconnect)", - vpnService: "org.freedesktop.NetworkManager.openconnect", - dataMap: map[string]string{ - "protocol": "anyconnect", - "gateway": "vpn.example.com", - }, - expectedLen: 2, - shouldHave: []string{"username", "password"}, - }, - { - name: "OpenVPN with username", - vpnService: "org.freedesktop.NetworkManager.openvpn", - dataMap: map[string]string{ - "connection-type": "password", - "username": "john", - }, - expectedLen: 1, - shouldHave: []string{"password"}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Convert dataMap to nmVariantMap - vpnSettings := make(nmVariantMap) - vpnSettings["data"] = dbus.MakeVariant(tt.dataMap) - vpnSettings["service-type"] = dbus.MakeVariant(tt.vpnService) - - conn := make(map[string]nmVariantMap) - conn["vpn"] = vpnSettings - - fields := inferVPNFields(conn, tt.vpnService) - - assert.Len(t, fields, tt.expectedLen, "unexpected number of fields") - if len(tt.shouldHave) > 0 { - for _, expected := range tt.shouldHave { - assert.Contains(t, fields, expected, "should contain field: %s", expected) - } - } - }) - } -} - -func TestNmVariantMap(t *testing.T) { - // Test that nmVariantMap and nmSettingMap work correctly - settingMap := make(nmSettingMap) - variantMap := make(nmVariantMap) - - variantMap["test-key"] = dbus.MakeVariant("test-value") - settingMap["test-setting"] = variantMap - - assert.Contains(t, settingMap, "test-setting") - assert.Contains(t, settingMap["test-setting"], "test-key") - - value := settingMap["test-setting"]["test-key"].Value() - assert.Equal(t, "test-value", value) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend.go deleted file mode 100644 index f1bb04d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend.go +++ /dev/null @@ -1,80 +0,0 @@ -package network - -type Backend interface { - Initialize() error - Close() - - GetWiFiEnabled() (bool, error) - SetWiFiEnabled(enabled bool) error - - ScanWiFi() error - ScanWiFiDevice(device string) error - GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) - GetWiFiQRCodeContent(ssid string) (string, error) - GetWiFiDevices() []WiFiDevice - - ConnectWiFi(req ConnectionRequest) error - DisconnectWiFi() error - DisconnectWiFiDevice(device string) error - ForgetWiFiNetwork(ssid string) error - SetWiFiAutoconnect(ssid string, autoconnect bool) error - - GetEthernetDevices() []EthernetDevice - GetWiredConnections() ([]WiredConnection, error) - GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) - ConnectEthernet() error - DisconnectEthernet() error - DisconnectEthernetDevice(device string) error - ActivateWiredConnection(uuid string) error - - ListVPNProfiles() ([]VPNProfile, error) - ListActiveVPN() ([]VPNActive, error) - ConnectVPN(uuidOrName string, singleActive bool) error - DisconnectVPN(uuidOrName string) error - DisconnectAllVPN() error - ClearVPNCredentials(uuidOrName string) error - ListVPNPlugins() ([]VPNPlugin, error) - ImportVPN(filePath string, name string) (*VPNImportResult, error) - GetVPNConfig(uuidOrName string) (*VPNConfig, error) - UpdateVPNConfig(uuid string, updates map[string]any) error - SetVPNCredentials(uuid string, username string, password string, save bool) error - DeleteVPN(uuidOrName string) error - - GetCurrentState() (*BackendState, error) - - StartMonitoring(onStateChange func()) error - StopMonitoring() - - GetPromptBroker() PromptBroker - SetPromptBroker(broker PromptBroker) error - SubmitCredentials(token string, secrets map[string]string, save bool) error - CancelCredentials(token string) error -} - -type BackendState struct { - Backend string - NetworkStatus NetworkStatus - EthernetIP string - EthernetDevice string - EthernetConnected bool - EthernetConnectionUuid string - EthernetDevices []EthernetDevice - WiFiIP string - WiFiDevice string - WiFiConnected bool - WiFiEnabled bool - WiFiSSID string - WiFiBSSID string - WiFiSignal uint8 - WiFiNetworks []WiFiNetwork - WiFiDevices []WiFiDevice - WiredConnections []WiredConnection - VPNProfiles []VPNProfile - VPNActive []VPNActive - IsConnecting bool - ConnectingSSID string - ConnectingDevice string - IsConnectingVPN bool - ConnectingVPNUUID string - LastError string -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_iwd_networkd.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_iwd_networkd.go deleted file mode 100644 index ce883ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_iwd_networkd.go +++ /dev/null @@ -1,245 +0,0 @@ -package network - -import ( - "fmt" -) - -type HybridIwdNetworkdBackend struct { - wifi *IWDBackend - l3 *SystemdNetworkdBackend - onStateChange func() -} - -func NewHybridIwdNetworkdBackend(w *IWDBackend, n *SystemdNetworkdBackend) (*HybridIwdNetworkdBackend, error) { - return &HybridIwdNetworkdBackend{ - wifi: w, - l3: n, - }, nil -} - -func (b *HybridIwdNetworkdBackend) Initialize() error { - if err := b.wifi.Initialize(); err != nil { - return fmt.Errorf("iwd init: %w", err) - } - if err := b.l3.Initialize(); err != nil { - return fmt.Errorf("networkd init: %w", err) - } - return nil -} - -func (b *HybridIwdNetworkdBackend) Close() { - b.wifi.Close() - b.l3.Close() -} - -func (b *HybridIwdNetworkdBackend) StartMonitoring(onStateChange func()) error { - b.onStateChange = onStateChange - - mergedCallback := func() { - ws, _ := b.wifi.GetCurrentState() - ls, _ := b.l3.GetCurrentState() - - if ws != nil && ls != nil && ws.WiFiDevice != "" && ls.WiFiIP != "" { - b.wifi.MarkIPConfigSeen() - } - - if b.onStateChange != nil { - b.onStateChange() - } - } - - if err := b.wifi.StartMonitoring(mergedCallback); err != nil { - return fmt.Errorf("wifi monitoring: %w", err) - } - if err := b.l3.StartMonitoring(mergedCallback); err != nil { - return fmt.Errorf("l3 monitoring: %w", err) - } - - return nil -} - -func (b *HybridIwdNetworkdBackend) StopMonitoring() { - b.wifi.StopMonitoring() - b.l3.StopMonitoring() -} - -func (b *HybridIwdNetworkdBackend) GetCurrentState() (*BackendState, error) { - ws, err := b.wifi.GetCurrentState() - if err != nil { - return nil, err - } - ls, err := b.l3.GetCurrentState() - if err != nil { - return nil, err - } - - merged := *ws - merged.Backend = "iwd+networkd" - - merged.WiFiIP = ls.WiFiIP - merged.EthernetConnected = ls.EthernetConnected - merged.EthernetIP = ls.EthernetIP - merged.EthernetDevice = ls.EthernetDevice - merged.EthernetConnectionUuid = ls.EthernetConnectionUuid - merged.WiredConnections = ls.WiredConnections - merged.EthernetDevices = ls.EthernetDevices - - if ls.EthernetConnected && ls.EthernetIP != "" { - merged.NetworkStatus = StatusEthernet - } else if ws.WiFiConnected && ls.WiFiIP != "" { - merged.NetworkStatus = StatusWiFi - } else { - merged.NetworkStatus = StatusDisconnected - } - - return &merged, nil -} - -func (b *HybridIwdNetworkdBackend) GetWiFiEnabled() (bool, error) { - return b.wifi.GetWiFiEnabled() -} - -func (b *HybridIwdNetworkdBackend) SetWiFiEnabled(enabled bool) error { - return b.wifi.SetWiFiEnabled(enabled) -} - -func (b *HybridIwdNetworkdBackend) ScanWiFi() error { - return b.wifi.ScanWiFi() -} - -func (b *HybridIwdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) { - return b.wifi.GetWiFiNetworkDetails(ssid) -} - -func (b *HybridIwdNetworkdBackend) GetWiFiQRCodeContent(ssid string) (string, error) { - return b.wifi.GetWiFiQRCodeContent(ssid) -} - -func (b *HybridIwdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error { - if err := b.wifi.ConnectWiFi(req); err != nil { - return err - } - - ws, err := b.wifi.GetCurrentState() - if err == nil && ws.WiFiDevice != "" { - b.l3.EnsureDhcpUp(ws.WiFiDevice) //nolint:errcheck - } - - return nil -} - -func (b *HybridIwdNetworkdBackend) DisconnectWiFi() error { - return b.wifi.DisconnectWiFi() -} - -func (b *HybridIwdNetworkdBackend) ForgetWiFiNetwork(ssid string) error { - return b.wifi.ForgetWiFiNetwork(ssid) -} - -func (b *HybridIwdNetworkdBackend) GetWiredConnections() ([]WiredConnection, error) { - return b.l3.GetWiredConnections() -} - -func (b *HybridIwdNetworkdBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) { - return b.l3.GetWiredNetworkDetails(uuid) -} - -func (b *HybridIwdNetworkdBackend) ConnectEthernet() error { - return b.l3.ConnectEthernet() -} - -func (b *HybridIwdNetworkdBackend) DisconnectEthernet() error { - return b.l3.DisconnectEthernet() -} - -func (b *HybridIwdNetworkdBackend) DisconnectEthernetDevice(device string) error { - return b.l3.DisconnectEthernetDevice(device) -} - -func (b *HybridIwdNetworkdBackend) GetEthernetDevices() []EthernetDevice { - return b.l3.GetEthernetDevices() -} - -func (b *HybridIwdNetworkdBackend) ActivateWiredConnection(uuid string) error { - return b.l3.ActivateWiredConnection(uuid) -} - -func (b *HybridIwdNetworkdBackend) ListVPNProfiles() ([]VPNProfile, error) { - return []VPNProfile{}, nil -} - -func (b *HybridIwdNetworkdBackend) ListActiveVPN() ([]VPNActive, error) { - return []VPNActive{}, nil -} - -func (b *HybridIwdNetworkdBackend) ConnectVPN(uuidOrName string, singleActive bool) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) DisconnectVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) DisconnectAllVPN() error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) ListVPNPlugins() ([]VPNPlugin, error) { - return []VPNPlugin{}, nil -} - -func (b *HybridIwdNetworkdBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { - return nil, fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { - return nil, fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) UpdateVPNConfig(uuid string, updates map[string]any) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) DeleteVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} - -func (b *HybridIwdNetworkdBackend) GetPromptBroker() PromptBroker { - return b.wifi.GetPromptBroker() -} - -func (b *HybridIwdNetworkdBackend) SetPromptBroker(broker PromptBroker) error { - return b.wifi.SetPromptBroker(broker) -} - -func (b *HybridIwdNetworkdBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error { - return b.wifi.SubmitCredentials(token, secrets, save) -} - -func (b *HybridIwdNetworkdBackend) CancelCredentials(token string) error { - return b.wifi.CancelCredentials(token) -} - -func (b *HybridIwdNetworkdBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - return b.wifi.SetWiFiAutoconnect(ssid, autoconnect) -} - -func (b *HybridIwdNetworkdBackend) ScanWiFiDevice(device string) error { - return b.wifi.ScanWiFiDevice(device) -} - -func (b *HybridIwdNetworkdBackend) DisconnectWiFiDevice(device string) error { - return b.wifi.DisconnectWiFiDevice(device) -} - -func (b *HybridIwdNetworkdBackend) GetWiFiDevices() []WiFiDevice { - return b.wifi.GetWiFiDevices() -} - -func (b *HybridIwdNetworkdBackend) SetVPNCredentials(uuid, username, password string, save bool) error { - return fmt.Errorf("VPN not supported in hybrid mode") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_test.go deleted file mode 100644 index cd061ed..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_hybrid_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestHybridIwdNetworkdBackend_New(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - - hybrid, err := NewHybridIwdNetworkdBackend(wifi, l3) - assert.NoError(t, err) - assert.NotNil(t, hybrid) - assert.NotNil(t, hybrid.wifi) - assert.NotNil(t, hybrid.l3) -} - -func TestHybridIwdNetworkdBackend_GetCurrentState_MergesState(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - wifi.state.WiFiConnected = true - wifi.state.WiFiSSID = "TestNetwork" - wifi.state.WiFiBSSID = "00:11:22:33:44:55" - wifi.state.WiFiSignal = 75 - wifi.state.WiFiDevice = "wlan0" - - l3.state.WiFiIP = "192.168.1.100" - l3.state.EthernetConnected = false - - state, err := hybrid.GetCurrentState() - assert.NoError(t, err) - assert.NotNil(t, state) - assert.Equal(t, "iwd+networkd", state.Backend) - assert.Equal(t, "TestNetwork", state.WiFiSSID) - assert.Equal(t, "00:11:22:33:44:55", state.WiFiBSSID) - assert.Equal(t, uint8(75), state.WiFiSignal) - assert.Equal(t, "192.168.1.100", state.WiFiIP) - assert.True(t, state.WiFiConnected) - assert.False(t, state.EthernetConnected) - assert.Equal(t, StatusWiFi, state.NetworkStatus) -} - -func TestHybridIwdNetworkdBackend_GetCurrentState_EthernetPriority(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - wifi.state.WiFiConnected = true - wifi.state.WiFiSSID = "TestNetwork" - - l3.state.WiFiIP = "192.168.1.100" - l3.state.EthernetConnected = true - l3.state.EthernetIP = "192.168.1.50" - l3.state.EthernetDevice = "eth0" - - state, err := hybrid.GetCurrentState() - assert.NoError(t, err) - assert.Equal(t, StatusEthernet, state.NetworkStatus) - assert.Equal(t, "192.168.1.50", state.EthernetIP) - assert.Equal(t, "eth0", state.EthernetDevice) -} - -func TestHybridIwdNetworkdBackend_GetCurrentState_WiFiNoIP(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - wifi.state.WiFiConnected = true - wifi.state.WiFiSSID = "TestNetwork" - - l3.state.WiFiIP = "" - l3.state.EthernetConnected = false - - state, err := hybrid.GetCurrentState() - assert.NoError(t, err) - assert.Equal(t, StatusDisconnected, state.NetworkStatus) - assert.True(t, state.WiFiConnected) - assert.Empty(t, state.WiFiIP) -} - -func TestHybridIwdNetworkdBackend_WiFiDelegation(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - enabled, err := hybrid.GetWiFiEnabled() - assert.NoError(t, err) - assert.True(t, enabled) - - state, err := hybrid.GetCurrentState() - assert.NoError(t, err) - assert.NotNil(t, state) - assert.Equal(t, "iwd+networkd", state.Backend) -} - -func TestHybridIwdNetworkdBackend_WiredDelegation(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - conns, err := hybrid.GetWiredConnections() - assert.NoError(t, err) - assert.Empty(t, conns) -} - -func TestHybridIwdNetworkdBackend_VPNNotSupported(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - profiles, err := hybrid.ListVPNProfiles() - assert.NoError(t, err) - assert.Empty(t, profiles) - - active, err := hybrid.ListActiveVPN() - assert.NoError(t, err) - assert.Empty(t, active) - - err = hybrid.ConnectVPN("test", false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} - -func TestHybridIwdNetworkdBackend_PromptBrokerDelegation(t *testing.T) { - wifi, _ := NewIWDBackend() - l3, _ := NewSystemdNetworkdBackend() - hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3) - - broker := hybrid.GetPromptBroker() - assert.Nil(t, broker) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd.go deleted file mode 100644 index f73aaf4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd.go +++ /dev/null @@ -1,238 +0,0 @@ -package network - -import ( - "fmt" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - iwdBusName = "net.connman.iwd" - iwdObjectPath = "/" - iwdAdapterInterface = "net.connman.iwd.Adapter" - iwdDeviceInterface = "net.connman.iwd.Device" - iwdStationInterface = "net.connman.iwd.Station" - iwdNetworkInterface = "net.connman.iwd.Network" - iwdKnownNetworkInterface = "net.connman.iwd.KnownNetwork" - dbusObjectManager = "org.freedesktop.DBus.ObjectManager" - dbusPropertiesInterface = "org.freedesktop.DBus.Properties" -) - -type connectAttempt struct { - ssid string - netPath dbus.ObjectPath - start time.Time - deadline time.Time - sawAuthish bool - connectedAt time.Time - sawIPConfig bool - sawPromptRetry bool - finalized bool - mu sync.Mutex -} - -type IWDBackend struct { - conn *dbus.Conn - state *BackendState - stateMutex sync.RWMutex - promptBroker PromptBroker - onStateChange func() - - devicePath dbus.ObjectPath - stationPath dbus.ObjectPath - adapterPath dbus.ObjectPath - - iwdAgent *IWDAgent - - stopChan chan struct{} - sigWG sync.WaitGroup - curAttempt *connectAttempt - attemptMutex sync.RWMutex - recentScans map[string]time.Time - recentScansMu sync.Mutex -} - -func NewIWDBackend() (*IWDBackend, error) { - backend := &IWDBackend{ - state: &BackendState{ - Backend: "iwd", - WiFiEnabled: true, - }, - stopChan: make(chan struct{}), - recentScans: make(map[string]time.Time), - } - - return backend, nil -} - -func (b *IWDBackend) Initialize() error { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return fmt.Errorf("failed to connect to system bus: %w", err) - } - b.conn = conn - - if err := b.discoverDevices(); err != nil { - conn.Close() - return fmt.Errorf("failed to discover iwd devices: %w", err) - } - - if err := b.updateState(); err != nil { - conn.Close() - return fmt.Errorf("failed to get initial state: %w", err) - } - - return nil -} - -func (b *IWDBackend) Close() { - close(b.stopChan) - b.sigWG.Wait() - - if b.iwdAgent != nil { - b.iwdAgent.Close() - } - - if b.conn != nil { - b.conn.Close() - } -} - -func (b *IWDBackend) discoverDevices() error { - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return fmt.Errorf("failed to get managed objects: %w", err) - } - - for path, interfaces := range objects { - if _, hasStation := interfaces[iwdStationInterface]; hasStation { - b.stationPath = path - } - if _, hasDevice := interfaces[iwdDeviceInterface]; hasDevice { - b.devicePath = path - - if devProps, ok := interfaces[iwdDeviceInterface]; ok { - if nameVar, ok := devProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok { - b.stateMutex.Lock() - b.state.WiFiDevice = name - b.stateMutex.Unlock() - } - } - } - } - if _, hasAdapter := interfaces[iwdAdapterInterface]; hasAdapter { - b.adapterPath = path - } - } - - if b.stationPath == "" || b.devicePath == "" { - return fmt.Errorf("no WiFi device found") - } - - return nil -} - -func (b *IWDBackend) GetCurrentState() (*BackendState, error) { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - - state := *b.state - state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...) - state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...) - state.WiFiDevices = b.getWiFiDevicesLocked() - - return &state, nil -} - -func (b *IWDBackend) OnUserCanceledPrompt() { - b.stateMutex.RLock() - cancelledSSID := b.state.ConnectingSSID - b.stateMutex.RUnlock() - - b.setConnectError("user-canceled") - - if cancelledSSID != "" { - if err := b.ForgetWiFiNetwork(cancelledSSID); err != nil { - log.Warnf("failed to forget cancelled WiFi network %s: %v", cancelledSSID, err) - } - } - - if b.onStateChange != nil { - b.onStateChange() - } -} - -func (b *IWDBackend) OnPromptRetry(ssid string) { - b.attemptMutex.RLock() - att := b.curAttempt - b.attemptMutex.RUnlock() - - if att != nil && att.ssid == ssid { - att.mu.Lock() - att.sawPromptRetry = true - att.mu.Unlock() - } -} - -func (b *IWDBackend) MarkIPConfigSeen() { - b.attemptMutex.RLock() - att := b.curAttempt - b.attemptMutex.RUnlock() - if att != nil { - att.mu.Lock() - att.sawIPConfig = true - att.mu.Unlock() - } -} - -func (b *IWDBackend) GetPromptBroker() PromptBroker { - return b.promptBroker -} - -func (b *IWDBackend) SetPromptBroker(broker PromptBroker) error { - if broker == nil { - return fmt.Errorf("broker cannot be nil") - } - - b.promptBroker = broker - return nil -} - -func (b *IWDBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error { - if b.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return b.promptBroker.Resolve(token, PromptReply{ - Secrets: secrets, - Save: save, - Cancel: false, - }) -} - -func (b *IWDBackend) CancelCredentials(token string) error { - if b.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return b.promptBroker.Resolve(token, PromptReply{ - Cancel: true, - }) -} - -func (b *IWDBackend) StopMonitoring() { - select { - case <-b.stopChan: - return - default: - close(b.stopChan) - } - b.sigWG.Wait() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_signals.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_signals.go deleted file mode 100644 index bde4753..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_signals.go +++ /dev/null @@ -1,355 +0,0 @@ -package network - -import ( - "fmt" - "time" - - "github.com/godbus/dbus/v5" -) - -func (b *IWDBackend) StartMonitoring(onStateChange func()) error { - b.onStateChange = onStateChange - - if b.promptBroker != nil { - agent, err := NewIWDAgent(b.conn, b.promptBroker) - if err != nil { - return fmt.Errorf("failed to start IWD agent: %w", err) - } - agent.onUserCanceled = b.OnUserCanceledPrompt - agent.onPromptRetry = b.OnPromptRetry - b.iwdAgent = agent - } - - sigChan := make(chan *dbus.Signal, 100) - b.conn.Signal(sigChan) - - if b.devicePath != "" { - err := b.conn.AddMatchSignal( - dbus.WithMatchObjectPath(b.devicePath), - dbus.WithMatchInterface(dbusPropertiesInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - if err != nil { - return fmt.Errorf("failed to add device signal match: %w", err) - } - } - - if b.stationPath != "" { - err := b.conn.AddMatchSignal( - dbus.WithMatchObjectPath(b.stationPath), - dbus.WithMatchInterface(dbusPropertiesInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - if err != nil { - return fmt.Errorf("failed to add station signal match: %w", err) - } - } - - b.sigWG.Add(1) - go b.signalHandler(sigChan) - - return nil -} - -func (b *IWDBackend) signalHandler(sigChan chan *dbus.Signal) { - defer b.sigWG.Done() - - for { - select { - case <-b.stopChan: - b.conn.RemoveSignal(sigChan) - close(sigChan) - return - - case sig := <-sigChan: - if sig == nil { - return - } - - if sig.Name != dbusPropertiesInterface+".PropertiesChanged" { - continue - } - - if len(sig.Body) < 2 { - continue - } - - iface, ok := sig.Body[0].(string) - if !ok { - continue - } - - changed, ok := sig.Body[1].(map[string]dbus.Variant) - if !ok { - continue - } - - stateChanged := false - - switch iface { - case iwdDeviceInterface: - if sig.Path == b.devicePath { - if poweredVar, ok := changed["Powered"]; ok { - if powered, ok := poweredVar.Value().(bool); ok { - b.stateMutex.Lock() - if b.state.WiFiEnabled != powered { - b.state.WiFiEnabled = powered - stateChanged = true - } - b.stateMutex.Unlock() - } - } - } - - case iwdStationInterface: - if sig.Path == b.stationPath { - if scanningVar, ok := changed["Scanning"]; ok { - if scanning, ok := scanningVar.Value().(bool); ok && !scanning { - networks, err := b.updateWiFiNetworks() - if err == nil { - b.stateMutex.Lock() - b.state.WiFiNetworks = networks - b.stateMutex.Unlock() - stateChanged = true - } - - b.stateMutex.RLock() - wifiConnected := b.state.WiFiConnected - b.stateMutex.RUnlock() - - if wifiConnected { - stationObj := b.conn.Object(iwdBusName, b.stationPath) - connNetVar, err := stationObj.GetProperty(iwdStationInterface + ".ConnectedNetwork") - if err == nil && connNetVar.Value() != nil { - if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" { - var orderedNetworks [][]dbus.Variant - err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks) - if err == nil { - for _, netData := range orderedNetworks { - if len(netData) < 2 { - continue - } - currentNetPath, ok := netData[0].Value().(dbus.ObjectPath) - if !ok || currentNetPath != netPath { - continue - } - signalStrength, ok := netData[1].Value().(int16) - if !ok { - continue - } - signalDbm := signalStrength / 100 - signal := uint8(signalDbm + 100) - if signalDbm > 0 { - signal = 100 - } else if signalDbm < -100 { - signal = 0 - } - b.stateMutex.Lock() - if b.state.WiFiSignal != signal { - b.state.WiFiSignal = signal - stateChanged = true - } - b.stateMutex.Unlock() - break - } - } - } - } - } - } - } - - if stateVar, ok := changed["State"]; ok { - if state, ok := stateVar.Value().(string); ok { - b.attemptMutex.RLock() - att := b.curAttempt - b.attemptMutex.RUnlock() - - var connPath dbus.ObjectPath - if v, ok := changed["ConnectedNetwork"]; ok { - if v.Value() != nil { - if p, ok := v.Value().(dbus.ObjectPath); ok { - connPath = p - } - } - } - if connPath == "" { - station := b.conn.Object(iwdBusName, b.stationPath) - if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil { - cnVar.Store(&connPath) - } - } - - b.stateMutex.RLock() - prevConnected := b.state.WiFiConnected - prevSSID := b.state.WiFiSSID - b.stateMutex.RUnlock() - - targetPath := dbus.ObjectPath("") - if att != nil { - targetPath = att.netPath - } - - isTarget := att != nil && targetPath != "" && connPath == targetPath - - if att != nil { - switch state { - case "authenticating", "associating", "associated", "roaming": - att.mu.Lock() - att.sawAuthish = true - att.mu.Unlock() - } - } - - if att != nil && state == "connected" && isTarget { - att.mu.Lock() - if att.connectedAt.IsZero() { - att.connectedAt = time.Now() - } - att.mu.Unlock() - } - - if att != nil && state == "configuring" { - att.mu.Lock() - att.sawIPConfig = true - att.mu.Unlock() - } - - switch state { - case "connected": - b.stateMutex.Lock() - b.state.WiFiConnected = true - b.state.NetworkStatus = StatusWiFi - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.LastError = "" - b.stateMutex.Unlock() - - if connPath != "" && connPath != "/" { - netObj := b.conn.Object(iwdBusName, connPath) - if nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name"); err == nil { - if name, ok := nameVar.Value().(string); ok { - b.stateMutex.Lock() - b.state.WiFiSSID = name - b.stateMutex.Unlock() - } - } - } - - stateChanged = true - - if att != nil && isTarget { - go func(attLocal *connectAttempt, tgt dbus.ObjectPath) { - time.Sleep(3 * time.Second) - station := b.conn.Object(iwdBusName, b.stationPath) - var nowState string - if stVar, err := station.GetProperty(iwdStationInterface + ".State"); err == nil { - stVar.Store(&nowState) - } - var nowConn dbus.ObjectPath - if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil { - cnVar.Store(&nowConn) - } - - if nowState == "connected" && nowConn == tgt { - b.finalizeAttempt(attLocal, "") - b.attemptMutex.Lock() - if b.curAttempt == attLocal { - b.curAttempt = nil - } - b.attemptMutex.Unlock() - } - }(att, targetPath) - } - - case "disconnecting", "disconnected": - if att != nil { - wasConnectedToTarget := prevConnected && prevSSID == att.ssid - if wasConnectedToTarget || isTarget { - code := b.classifyAttempt(att) - b.finalizeAttempt(att, code) - b.attemptMutex.Lock() - if b.curAttempt == att { - b.curAttempt = nil - } - b.attemptMutex.Unlock() - } - } - - b.stateMutex.Lock() - b.state.WiFiConnected = false - if state == "disconnected" { - b.state.NetworkStatus = StatusDisconnected - } - b.stateMutex.Unlock() - stateChanged = true - } - } - } - - if connNetVar, ok := changed["ConnectedNetwork"]; ok { - if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" { - netObj := b.conn.Object(iwdBusName, netPath) - nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name") - if err == nil { - if name, ok := nameVar.Value().(string); ok { - b.stateMutex.Lock() - if b.state.WiFiSSID != name { - b.state.WiFiSSID = name - stateChanged = true - } - b.stateMutex.Unlock() - } - } - - stationObj := b.conn.Object(iwdBusName, b.stationPath) - var orderedNetworks [][]dbus.Variant - err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks) - if err == nil { - for _, netData := range orderedNetworks { - if len(netData) < 2 { - continue - } - currentNetPath, ok := netData[0].Value().(dbus.ObjectPath) - if !ok || currentNetPath != netPath { - continue - } - signalStrength, ok := netData[1].Value().(int16) - if !ok { - continue - } - signalDbm := signalStrength / 100 - signal := uint8(signalDbm + 100) - if signalDbm > 0 { - signal = 100 - } else if signalDbm < -100 { - signal = 0 - } - b.stateMutex.Lock() - if b.state.WiFiSignal != signal { - b.state.WiFiSignal = signal - stateChanged = true - } - b.stateMutex.Unlock() - break - } - } - } else { - b.stateMutex.Lock() - if b.state.WiFiSSID != "" { - b.state.WiFiSSID = "" - b.state.WiFiSignal = 0 - stateChanged = true - } - b.stateMutex.Unlock() - } - } - } - } - - if stateChanged && b.onStateChange != nil { - b.onStateChange() - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_test.go deleted file mode 100644 index 829e413..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_test.go +++ /dev/null @@ -1,212 +0,0 @@ -package network - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestIWDBackend_MarkIPConfigSeen(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/net/connman/iwd/0/1/test", - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - backend.attemptMutex.Lock() - backend.curAttempt = att - backend.attemptMutex.Unlock() - - backend.MarkIPConfigSeen() - - att.mu.Lock() - assert.True(t, att.sawIPConfig, "sawIPConfig should be true after MarkIPConfigSeen") - att.mu.Unlock() -} - -func TestIWDBackend_MarkIPConfigSeen_NoAttempt(t *testing.T) { - backend, _ := NewIWDBackend() - - backend.attemptMutex.Lock() - backend.curAttempt = nil - backend.attemptMutex.Unlock() - - backend.MarkIPConfigSeen() -} - -func TestIWDBackend_OnPromptRetry(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/net/connman/iwd/0/1/test", - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - backend.attemptMutex.Lock() - backend.curAttempt = att - backend.attemptMutex.Unlock() - - backend.OnPromptRetry("TestNetwork") - - att.mu.Lock() - assert.True(t, att.sawPromptRetry, "sawPromptRetry should be true after OnPromptRetry") - att.mu.Unlock() -} - -func TestIWDBackend_OnPromptRetry_WrongSSID(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/net/connman/iwd/0/1/test", - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - backend.attemptMutex.Lock() - backend.curAttempt = att - backend.attemptMutex.Unlock() - - backend.OnPromptRetry("DifferentNetwork") - - att.mu.Lock() - assert.False(t, att.sawPromptRetry, "sawPromptRetry should remain false for different SSID") - att.mu.Unlock() -} - -func TestIWDBackend_ClassifyAttempt_BadCredentials_PromptRetry(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now().Add(-5 * time.Second), - deadline: time.Now().Add(10 * time.Second), - sawPromptRetry: true, - } - - code := backend.classifyAttempt(att) - assert.Equal(t, "bad-credentials", code) -} - -func TestIWDBackend_ClassifyAttempt_DhcpTimeout(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now().Add(-13 * time.Second), - deadline: time.Now().Add(2 * time.Second), - sawAuthish: true, - sawIPConfig: false, - } - - code := backend.classifyAttempt(att) - assert.Equal(t, "dhcp-timeout", code) -} - -func TestIWDBackend_ClassifyAttempt_AssocTimeout(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now().Add(-5 * time.Second), - deadline: time.Now().Add(10 * time.Second), - } - - backend.recentScansMu.Lock() - backend.recentScans["TestNetwork"] = time.Now() - backend.recentScansMu.Unlock() - - code := backend.classifyAttempt(att) - assert.Equal(t, "assoc-timeout", code) -} - -func TestIWDBackend_ClassifyAttempt_NoSuchSSID(t *testing.T) { - backend, _ := NewIWDBackend() - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now().Add(-5 * time.Second), - deadline: time.Now().Add(10 * time.Second), - } - - code := backend.classifyAttempt(att) - assert.Equal(t, "no-such-ssid", code) -} - -func TestIWDBackend_MapIwdDBusError(t *testing.T) { - backend, _ := NewIWDBackend() - - testCases := []struct { - name string - expected string - }{ - {"net.connman.iwd.Error.AlreadyConnected", "already-connected"}, - {"net.connman.iwd.Error.AuthenticationFailed", "bad-credentials"}, - {"net.connman.iwd.Error.InvalidKey", "bad-credentials"}, - {"net.connman.iwd.Error.IncorrectPassphrase", "bad-credentials"}, - {"net.connman.iwd.Error.NotFound", "no-such-ssid"}, - {"net.connman.iwd.Error.NotSupported", "connection-failed"}, - {"net.connman.iwd.Agent.Error.Canceled", "user-canceled"}, - {"net.connman.iwd.Error.Unknown", "connection-failed"}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - code := backend.mapIwdDBusError(tc.name) - assert.Equal(t, tc.expected, code) - }) - } -} - -func TestConnectAttempt_Finalization(t *testing.T) { - backend, _ := NewIWDBackend() - backend.state = &BackendState{} - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - backend.finalizeAttempt(att, "bad-credentials") - - att.mu.Lock() - assert.True(t, att.finalized) - att.mu.Unlock() - - backend.stateMutex.RLock() - assert.False(t, backend.state.IsConnecting) - assert.Empty(t, backend.state.ConnectingSSID) - assert.Equal(t, "bad-credentials", backend.state.LastError) - backend.stateMutex.RUnlock() -} - -func TestConnectAttempt_DoubleFinalization(t *testing.T) { - backend, _ := NewIWDBackend() - backend.state = &BackendState{} - - att := &connectAttempt{ - ssid: "TestNetwork", - netPath: "/test", - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - backend.finalizeAttempt(att, "bad-credentials") - backend.finalizeAttempt(att, "dhcp-timeout") - - backend.stateMutex.RLock() - assert.Equal(t, "bad-credentials", backend.state.LastError) - backend.stateMutex.RUnlock() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_unimplemented.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_unimplemented.go deleted file mode 100644 index f5a8b03..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_unimplemented.go +++ /dev/null @@ -1,133 +0,0 @@ -package network - -import ( - "fmt" - "os" -) - -func (b *IWDBackend) GetWiredConnections() ([]WiredConnection, error) { - return nil, fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) { - return nil, fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) ConnectEthernet() error { - return fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) DisconnectEthernet() error { - return fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) DisconnectEthernetDevice(device string) error { - return fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) GetEthernetDevices() []EthernetDevice { - return []EthernetDevice{} -} - -func (b *IWDBackend) ActivateWiredConnection(uuid string) error { - return fmt.Errorf("wired connections not supported by iwd") -} - -func (b *IWDBackend) ListVPNProfiles() ([]VPNProfile, error) { - return nil, fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ListActiveVPN() ([]VPNActive, error) { - return nil, fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ConnectVPN(uuidOrName string, singleActive bool) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) DisconnectVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) DisconnectAllVPN() error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ClearVPNCredentials(uuidOrName string) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ListVPNPlugins() ([]VPNPlugin, error) { - return nil, fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { - return nil, fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { - return nil, fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) UpdateVPNConfig(uuid string, updates map[string]any) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) DeleteVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) SetVPNCredentials(uuid, username, password string, save bool) error { - return fmt.Errorf("VPN not supported by iwd backend") -} - -func (b *IWDBackend) ScanWiFiDevice(device string) error { - return b.ScanWiFi() -} - -func (b *IWDBackend) DisconnectWiFiDevice(device string) error { - return b.DisconnectWiFi() -} - -func (b *IWDBackend) GetWiFiDevices() []WiFiDevice { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return b.getWiFiDevicesLocked() -} - -func (b *IWDBackend) getWiFiDevicesLocked() []WiFiDevice { - if b.state.WiFiDevice == "" { - return nil - } - - stateStr := "disconnected" - if b.state.WiFiConnected { - stateStr = "connected" - } - - return []WiFiDevice{{ - Name: b.state.WiFiDevice, - State: stateStr, - Connected: b.state.WiFiConnected, - SSID: b.state.WiFiSSID, - Signal: b.state.WiFiSignal, - IP: b.state.WiFiIP, - Networks: b.state.WiFiNetworks, - }} -} - -func (b *IWDBackend) GetWiFiQRCodeContent(ssid string) (string, error) { - path := iwdConfigPath(ssid) - - data, err := os.ReadFile(path) - if err != nil { - return "", fmt.Errorf("no saved iwd config for `%s`: %w", ssid, err) - } - - passphrase, err := parseIWDPassphrase(string(data)) - if err != nil { - return "", fmt.Errorf("failed to read passphrase for `%s`: %w", ssid, err) - } - - return FormatWiFiQRString("WPA", ssid, passphrase), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_wifi.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_wifi.go deleted file mode 100644 index b3bea13..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_iwd_wifi.go +++ /dev/null @@ -1,662 +0,0 @@ -package network - -import ( - "fmt" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/godbus/dbus/v5" -) - -func (b *IWDBackend) updateState() error { - if b.devicePath == "" { - return nil - } - - obj := b.conn.Object(iwdBusName, b.devicePath) - - poweredVar, err := obj.GetProperty(iwdDeviceInterface + ".Powered") - if err == nil { - if powered, ok := poweredVar.Value().(bool); ok { - b.stateMutex.Lock() - b.state.WiFiEnabled = powered - b.stateMutex.Unlock() - } - } - - if b.stationPath == "" { - return nil - } - - stationObj := b.conn.Object(iwdBusName, b.stationPath) - - stateVar, err := stationObj.GetProperty(iwdStationInterface + ".State") - if err == nil { - if state, ok := stateVar.Value().(string); ok { - b.stateMutex.Lock() - b.state.WiFiConnected = (state == "connected") - if state == "connected" { - b.state.NetworkStatus = StatusWiFi - } else { - b.state.NetworkStatus = StatusDisconnected - } - b.stateMutex.Unlock() - } - } - - connNetVar, err := stationObj.GetProperty(iwdStationInterface + ".ConnectedNetwork") - if err == nil && connNetVar.Value() != nil { - if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" { - netObj := b.conn.Object(iwdBusName, netPath) - - nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name") - if err == nil { - if name, ok := nameVar.Value().(string); ok { - b.stateMutex.Lock() - b.state.WiFiSSID = name - b.stateMutex.Unlock() - } - } - - var orderedNetworks [][]dbus.Variant - err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks) - if err == nil { - for _, netData := range orderedNetworks { - if len(netData) < 2 { - continue - } - currentNetPath, ok := netData[0].Value().(dbus.ObjectPath) - if !ok || currentNetPath != netPath { - continue - } - signalStrength, ok := netData[1].Value().(int16) - if !ok { - continue - } - signalDbm := signalStrength / 100 - signal := uint8(signalDbm + 100) - if signalDbm > 0 { - signal = 100 - } else if signalDbm < -100 { - signal = 0 - } - b.stateMutex.Lock() - b.state.WiFiSignal = signal - b.stateMutex.Unlock() - break - } - } - } - } - - networks, err := b.updateWiFiNetworks() - if err == nil { - b.stateMutex.Lock() - b.state.WiFiNetworks = networks - b.stateMutex.Unlock() - } - - return nil -} - -func (b *IWDBackend) GetWiFiEnabled() (bool, error) { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return b.state.WiFiEnabled, nil -} - -func (b *IWDBackend) SetWiFiEnabled(enabled bool) error { - if b.devicePath == "" { - return fmt.Errorf("no WiFi device available") - } - - obj := b.conn.Object(iwdBusName, b.devicePath) - call := obj.Call(dbusPropertiesInterface+".Set", 0, iwdDeviceInterface, "Powered", dbus.MakeVariant(enabled)) - if call.Err != nil { - return fmt.Errorf("failed to set WiFi enabled: %w", call.Err) - } - - b.stateMutex.Lock() - b.state.WiFiEnabled = enabled - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *IWDBackend) ScanWiFi() error { - if b.stationPath == "" { - return fmt.Errorf("no WiFi device available") - } - - obj := b.conn.Object(iwdBusName, b.stationPath) - - scanningVar, err := obj.GetProperty(iwdStationInterface + ".Scanning") - if err != nil { - return fmt.Errorf("failed to check scanning state: %w", err) - } - - if scanning, ok := scanningVar.Value().(bool); ok && scanning { - return fmt.Errorf("scan already in progress") - } - - call := obj.Call(iwdStationInterface+".Scan", 0) - if call.Err != nil { - return fmt.Errorf("scan request failed: %w", call.Err) - } - - return nil -} - -func (b *IWDBackend) updateWiFiNetworks() ([]WiFiNetwork, error) { - if b.stationPath == "" { - return nil, fmt.Errorf("no WiFi device available") - } - - obj := b.conn.Object(iwdBusName, b.stationPath) - - var orderedNetworks [][]dbus.Variant - err := obj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks) - if err != nil { - return nil, fmt.Errorf("failed to get networks: %w", err) - } - - knownNetworks, err := b.getKnownNetworks() - if err != nil { - knownNetworks = make(map[string]bool) - } - - autoconnectMap, err := b.getAutoconnectSettings() - if err != nil { - autoconnectMap = make(map[string]bool) - } - - b.stateMutex.RLock() - currentSSID := b.state.WiFiSSID - wifiConnected := b.state.WiFiConnected - b.stateMutex.RUnlock() - - networks := make([]WiFiNetwork, 0, len(orderedNetworks)) - for _, netData := range orderedNetworks { - if len(netData) < 2 { - continue - } - - networkPath, ok := netData[0].Value().(dbus.ObjectPath) - if !ok { - continue - } - - signalStrength, ok := netData[1].Value().(int16) - if !ok { - continue - } - - netObj := b.conn.Object(iwdBusName, networkPath) - - nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name") - if err != nil { - continue - } - name, ok := nameVar.Value().(string) - if !ok { - continue - } - - typeVar, err := netObj.GetProperty(iwdNetworkInterface + ".Type") - if err != nil { - continue - } - netType, ok := typeVar.Value().(string) - if !ok { - continue - } - - signalDbm := signalStrength / 100 - signal := uint8(signalDbm + 100) - if signalDbm > 0 { - signal = 100 - } else if signalDbm < -100 { - signal = 0 - } - - secured := netType != "open" - - network := WiFiNetwork{ - SSID: name, - Signal: signal, - Secured: secured, - Connected: wifiConnected && name == currentSSID, - Saved: knownNetworks[name], - Autoconnect: autoconnectMap[name], - Enterprise: netType == "8021x", - } - - networks = append(networks, network) - } - - sortWiFiNetworks(networks) - - b.stateMutex.Lock() - b.state.WiFiNetworks = networks - b.stateMutex.Unlock() - - now := time.Now() - b.recentScansMu.Lock() - for _, net := range networks { - b.recentScans[net.SSID] = now - } - b.recentScansMu.Unlock() - - return networks, nil -} - -func (b *IWDBackend) getKnownNetworks() (map[string]bool, error) { - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return nil, err - } - - known := make(map[string]bool) - for _, interfaces := range objects { - if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok { - if nameVar, ok := knownProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok { - known[name] = true - } - } - } - } - - return known, nil -} - -func (b *IWDBackend) getAutoconnectSettings() (map[string]bool, error) { - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return nil, err - } - - autoconnectMap := make(map[string]bool) - for _, interfaces := range objects { - if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok { - if nameVar, ok := knownProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok { - autoconnect := true - if acVar, ok := knownProps["AutoConnect"]; ok { - if ac, ok := acVar.Value().(bool); ok { - autoconnect = ac - } - } - autoconnectMap[name] = autoconnect - } - } - } - } - - return autoconnectMap, nil -} - -func (b *IWDBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) { - b.stateMutex.RLock() - networks := b.state.WiFiNetworks - b.stateMutex.RUnlock() - - var found *WiFiNetwork - for i := range networks { - if networks[i].SSID == ssid { - found = &networks[i] - break - } - } - - if found == nil { - return nil, fmt.Errorf("network not found: %s", ssid) - } - - return &NetworkInfoResponse{ - SSID: ssid, - Bands: []WiFiNetwork{*found}, - }, nil -} - -func (b *IWDBackend) setConnectError(code string) { - b.stateMutex.Lock() - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.LastError = code - b.stateMutex.Unlock() -} - -func (b *IWDBackend) seenInRecentScan(ssid string) bool { - b.recentScansMu.Lock() - defer b.recentScansMu.Unlock() - lastSeen, ok := b.recentScans[ssid] - return ok && time.Since(lastSeen) < 30*time.Second -} - -func (b *IWDBackend) classifyAttempt(att *connectAttempt) string { - att.mu.Lock() - defer att.mu.Unlock() - - if att.sawPromptRetry { - return errdefs.ErrBadCredentials - } - - if !att.connectedAt.IsZero() && !att.sawIPConfig { - connDuration := time.Since(att.connectedAt) - if connDuration > 500*time.Millisecond && connDuration < 3*time.Second { - return errdefs.ErrBadCredentials - } - } - - if (att.sawAuthish || !att.connectedAt.IsZero()) && !att.sawIPConfig { - if time.Since(att.start) > 12*time.Second { - return errdefs.ErrDhcpTimeout - } - } - - if !att.sawAuthish && att.connectedAt.IsZero() { - if !b.seenInRecentScan(att.ssid) { - return errdefs.ErrNoSuchSSID - } - return errdefs.ErrAssocTimeout - } - - return errdefs.ErrAssocTimeout -} - -func (b *IWDBackend) finalizeAttempt(att *connectAttempt, code string) { - att.mu.Lock() - if att.finalized { - att.mu.Unlock() - return - } - att.finalized = true - att.mu.Unlock() - - b.stateMutex.Lock() - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.LastError = code - b.stateMutex.Unlock() - - b.updateState() - - if b.onStateChange != nil { - b.onStateChange() - } -} - -func (b *IWDBackend) startAttemptWatchdog(att *connectAttempt) { - b.sigWG.Add(1) - go func() { - defer b.sigWG.Done() - - ticker := time.NewTicker(250 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - att.mu.Lock() - finalized := att.finalized - att.mu.Unlock() - - if finalized || time.Now().After(att.deadline) { - if !finalized { - b.finalizeAttempt(att, b.classifyAttempt(att)) - } - return - } - - station := b.conn.Object(iwdBusName, b.stationPath) - stVar, err := station.GetProperty(iwdStationInterface + ".State") - if err != nil { - continue - } - state, _ := stVar.Value().(string) - - cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork") - if err != nil { - continue - } - var connPath dbus.ObjectPath - if cnVar.Value() != nil { - connPath, _ = cnVar.Value().(dbus.ObjectPath) - } - - att.mu.Lock() - if connPath == att.netPath && state == "connected" && att.connectedAt.IsZero() { - att.connectedAt = time.Now() - } - if state == "configuring" { - att.sawIPConfig = true - } - att.mu.Unlock() - - case <-b.stopChan: - return - } - } - }() -} - -func (b *IWDBackend) mapIwdDBusError(name string) string { - switch name { - case "net.connman.iwd.Error.AlreadyConnected": - return errdefs.ErrAlreadyConnected - case "net.connman.iwd.Error.AuthenticationFailed", - "net.connman.iwd.Error.InvalidKey", - "net.connman.iwd.Error.IncorrectPassphrase": - return errdefs.ErrBadCredentials - case "net.connman.iwd.Error.NotFound": - return errdefs.ErrNoSuchSSID - case "net.connman.iwd.Error.NotSupported": - return errdefs.ErrConnectionFailed - case "net.connman.iwd.Agent.Error.Canceled": - return errdefs.ErrUserCanceled - default: - return errdefs.ErrConnectionFailed - } -} - -func (b *IWDBackend) ConnectWiFi(req ConnectionRequest) error { - if b.stationPath == "" { - b.setConnectError(errdefs.ErrWifiDisabled) - if b.onStateChange != nil { - b.onStateChange() - } - return fmt.Errorf("no WiFi device available") - } - - networkPath, err := b.findNetworkPath(req.SSID) - if err != nil { - b.setConnectError(errdefs.ErrNoSuchSSID) - if b.onStateChange != nil { - b.onStateChange() - } - return fmt.Errorf("network not found: %w", err) - } - - att := &connectAttempt{ - ssid: req.SSID, - netPath: networkPath, - start: time.Now(), - deadline: time.Now().Add(15 * time.Second), - } - - b.attemptMutex.Lock() - b.curAttempt = att - b.attemptMutex.Unlock() - - b.stateMutex.Lock() - b.state.IsConnecting = true - b.state.ConnectingSSID = req.SSID - b.state.LastError = "" - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - netObj := b.conn.Object(iwdBusName, networkPath) - go func() { - call := netObj.Call(iwdNetworkInterface+".Connect", 0) - if call.Err != nil { - var code string - if dbusErr, ok := call.Err.(dbus.Error); ok { - code = b.mapIwdDBusError(dbusErr.Name) - } else if dbusErrPtr, ok := call.Err.(*dbus.Error); ok { - code = b.mapIwdDBusError(dbusErrPtr.Name) - } else { - code = errdefs.ErrConnectionFailed - } - - att.mu.Lock() - if att.sawPromptRetry { - code = errdefs.ErrBadCredentials - } - att.mu.Unlock() - - b.finalizeAttempt(att, code) - return - } - - b.startAttemptWatchdog(att) - }() - - return nil -} - -func (b *IWDBackend) findNetworkPath(ssid string) (dbus.ObjectPath, error) { - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return "", err - } - - for path, interfaces := range objects { - if netProps, ok := interfaces[iwdNetworkInterface]; ok { - if nameVar, ok := netProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok && name == ssid { - return path, nil - } - } - } - } - - return "", fmt.Errorf("network not found") -} - -func (b *IWDBackend) DisconnectWiFi() error { - if b.stationPath == "" { - return fmt.Errorf("no WiFi device available") - } - - obj := b.conn.Object(iwdBusName, b.stationPath) - call := obj.Call(iwdStationInterface+".Disconnect", 0) - if call.Err != nil { - return fmt.Errorf("failed to disconnect: %w", call.Err) - } - - b.updateState() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *IWDBackend) ForgetWiFiNetwork(ssid string) error { - b.stateMutex.RLock() - currentSSID := b.state.WiFiSSID - isConnected := b.state.WiFiConnected - b.stateMutex.RUnlock() - - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return err - } - - for path, interfaces := range objects { - if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok { - if nameVar, ok := knownProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok && name == ssid { - knownObj := b.conn.Object(iwdBusName, path) - call := knownObj.Call(iwdKnownNetworkInterface+".Forget", 0) - if call.Err != nil { - return fmt.Errorf("failed to forget network: %w", call.Err) - } - - if isConnected && currentSSID == ssid { - b.stateMutex.Lock() - b.state.WiFiConnected = false - b.state.WiFiSSID = "" - b.state.WiFiSignal = 0 - b.state.WiFiIP = "" - b.state.NetworkStatus = StatusDisconnected - b.stateMutex.Unlock() - } - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil - } - } - } - } - - return fmt.Errorf("network not found") -} - -func (b *IWDBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - obj := b.conn.Object(iwdBusName, iwdObjectPath) - - var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant - err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects) - if err != nil { - return err - } - - for path, interfaces := range objects { - if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok { - if nameVar, ok := knownProps["Name"]; ok { - if name, ok := nameVar.Value().(string); ok && name == ssid { - knownObj := b.conn.Object(iwdBusName, path) - call := knownObj.Call(dbusPropertiesInterface+".Set", 0, iwdKnownNetworkInterface, "AutoConnect", dbus.MakeVariant(autoconnect)) - if call.Err != nil { - return fmt.Errorf("failed to set autoconnect: %w", call.Err) - } - - b.updateState() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil - } - } - } - } - - return fmt.Errorf("network not found") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd.go deleted file mode 100644 index 802cbf0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd.go +++ /dev/null @@ -1,301 +0,0 @@ -package network - -import ( - "fmt" - "net" - "strings" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - networkdBusName = "org.freedesktop.network1" - networkdManagerPath = "/org/freedesktop/network1" - networkdManagerIface = "org.freedesktop.network1.Manager" - networkdLinkIface = "org.freedesktop.network1.Link" -) - -type linkInfo struct { - ifindex int32 - name string - path dbus.ObjectPath - opState string -} - -type SystemdNetworkdBackend struct { - conn *dbus.Conn - managerPath dbus.ObjectPath - links map[string]*linkInfo - linksMutex sync.RWMutex - state *BackendState - stateMutex sync.RWMutex - onStateChange func() - stopChan chan struct{} - signals chan *dbus.Signal - sigWG sync.WaitGroup -} - -func NewSystemdNetworkdBackend() (*SystemdNetworkdBackend, error) { - return &SystemdNetworkdBackend{ - managerPath: networkdManagerPath, - links: make(map[string]*linkInfo), - state: &BackendState{ - Backend: "networkd", - WiFiNetworks: []WiFiNetwork{}, - }, - stopChan: make(chan struct{}), - }, nil -} - -func (b *SystemdNetworkdBackend) Initialize() error { - c, err := dbus.ConnectSystemBus() - if err != nil { - return fmt.Errorf("connect bus: %w", err) - } - b.conn = c - - if err := b.enumerateLinks(); err != nil { - c.Close() - return fmt.Errorf("enumerate links: %w", err) - } - - if err := b.updateState(); err != nil { - c.Close() - return fmt.Errorf("update initial state: %w", err) - } - - return nil -} - -func (b *SystemdNetworkdBackend) Close() { - close(b.stopChan) - b.StopMonitoring() - - if b.conn != nil { - b.conn.Close() - } -} - -func (b *SystemdNetworkdBackend) enumerateLinks() error { - obj := b.conn.Object(networkdBusName, b.managerPath) - - var links []struct { - Ifindex int32 - Name string - Path dbus.ObjectPath - } - err := obj.Call(networkdManagerIface+".ListLinks", 0).Store(&links) - if err != nil { - return fmt.Errorf("ListLinks: %w", err) - } - - b.linksMutex.Lock() - defer b.linksMutex.Unlock() - - for _, l := range links { - b.links[l.Name] = &linkInfo{ - ifindex: l.Ifindex, - name: l.Name, - path: l.Path, - } - log.Debugf("networkd: enumerated link %s (ifindex=%d, path=%s)", l.Name, l.Ifindex, l.Path) - } - - return nil -} - -func (b *SystemdNetworkdBackend) updateState() error { - b.linksMutex.RLock() - defer b.linksMutex.RUnlock() - - var wiredIface *linkInfo - var wifiIface *linkInfo - - for name, link := range b.links { - if b.isVirtualInterface(name) { - continue - } - - linkObj := b.conn.Object(networkdBusName, link.path) - opStateVar, err := linkObj.GetProperty(networkdLinkIface + ".OperationalState") - if err == nil { - if opState, ok := opStateVar.Value().(string); ok { - link.opState = opState - } - } - - if strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") { - if wifiIface == nil || link.opState == "routable" || link.opState == "carrier" { - wifiIface = link - } - } else if !b.isVirtualInterface(name) { - if wiredIface == nil || link.opState == "routable" || link.opState == "carrier" { - wiredIface = link - } - } - } - - var wiredConns []WiredConnection - var ethernetDevices []EthernetDevice - for name, link := range b.links { - if b.isVirtualInterface(name) || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") { - continue - } - - active := link.opState == "routable" || link.opState == "carrier" - wiredConns = append(wiredConns, WiredConnection{ - Path: link.path, - ID: name, - UUID: "wired:" + name, - Type: "ethernet", - IsActive: active, - }) - - var ip string - var hwAddr string - if iface, err := net.InterfaceByName(name); err == nil { - hwAddr = iface.HardwareAddr.String() - if addrs := b.getAddresses(name); len(addrs) > 0 { - ip = addrs[0] - } - } - - stateStr := "disconnected" - switch link.opState { - case "routable": - stateStr = "routable" - case "carrier": - stateStr = "carrier" - case "degraded": - stateStr = "degraded" - case "no-carrier": - stateStr = "no-carrier" - case "off": - stateStr = "off" - } - - ethernetDevices = append(ethernetDevices, EthernetDevice{ - Name: name, - HwAddress: hwAddr, - State: stateStr, - Connected: active, - IP: ip, - }) - } - - b.stateMutex.Lock() - defer b.stateMutex.Unlock() - - b.state.NetworkStatus = StatusDisconnected - b.state.EthernetConnected = false - b.state.EthernetIP = "" - b.state.WiFiConnected = false - b.state.WiFiIP = "" - b.state.WiredConnections = wiredConns - b.state.EthernetDevices = ethernetDevices - - if wiredIface != nil { - b.state.EthernetDevice = wiredIface.name - log.Debugf("networkd: wired interface %s opState=%s", wiredIface.name, wiredIface.opState) - if wiredIface.opState == "routable" || wiredIface.opState == "carrier" { - b.state.EthernetConnected = true - b.state.NetworkStatus = StatusEthernet - - if addrs := b.getAddresses(wiredIface.name); len(addrs) > 0 { - b.state.EthernetIP = addrs[0] - log.Debugf("networkd: ethernet IP %s on %s", addrs[0], wiredIface.name) - } - } - } - - if wifiIface != nil { - b.state.WiFiDevice = wifiIface.name - log.Debugf("networkd: wifi interface %s opState=%s", wifiIface.name, wifiIface.opState) - if wifiIface.opState == "routable" || wifiIface.opState == "carrier" { - b.state.WiFiConnected = true - - if addrs := b.getAddresses(wifiIface.name); len(addrs) > 0 { - b.state.WiFiIP = addrs[0] - log.Debugf("networkd: wifi IP %s on %s", addrs[0], wifiIface.name) - if b.state.NetworkStatus == StatusDisconnected { - b.state.NetworkStatus = StatusWiFi - } - } - } - } - - return nil -} - -func (b *SystemdNetworkdBackend) isVirtualInterface(name string) bool { - virtualPrefixes := []string{ - "lo", "docker", "veth", "virbr", "br-", "vnet", "tun", "tap", - "vboxnet", "vmnet", "kube", "cni", "flannel", "cali", - } - for _, prefix := range virtualPrefixes { - if strings.HasPrefix(name, prefix) { - return true - } - } - return false -} - -func (b *SystemdNetworkdBackend) getAddresses(ifname string) []string { - iface, err := net.InterfaceByName(ifname) - if err != nil { - return nil - } - - addrs, err := iface.Addrs() - if err != nil { - return nil - } - - var result []string - for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok { - if ipv4 := ipnet.IP.To4(); ipv4 != nil { - result = append(result, ipv4.String()) - } - } - } - return result -} - -func (b *SystemdNetworkdBackend) GetCurrentState() (*BackendState, error) { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - s := *b.state - return &s, nil -} - -func (b *SystemdNetworkdBackend) GetPromptBroker() PromptBroker { - return nil -} - -func (b *SystemdNetworkdBackend) SetPromptBroker(broker PromptBroker) error { - return nil -} - -func (b *SystemdNetworkdBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error { - return fmt.Errorf("credentials not needed by networkd backend") -} - -func (b *SystemdNetworkdBackend) CancelCredentials(token string) error { - return fmt.Errorf("credentials not needed by networkd backend") -} - -func (b *SystemdNetworkdBackend) EnsureDhcpUp(ifname string) error { - b.linksMutex.RLock() - link, exists := b.links[ifname] - b.linksMutex.RUnlock() - - if !exists { - return fmt.Errorf("interface %s not found", ifname) - } - - linkObj := b.conn.Object(networkdBusName, link.path) - return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_ethernet.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_ethernet.go deleted file mode 100644 index 8f9b225..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_ethernet.go +++ /dev/null @@ -1,120 +0,0 @@ -package network - -import ( - "fmt" - "net" - "strings" -) - -func (b *SystemdNetworkdBackend) GetWiredConnections() ([]WiredConnection, error) { - b.linksMutex.RLock() - defer b.linksMutex.RUnlock() - - var conns []WiredConnection - for name, link := range b.links { - if b.isVirtualInterface(name) || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") { - continue - } - - active := link.opState == "routable" || link.opState == "carrier" - conns = append(conns, WiredConnection{ - Path: link.path, - ID: name, - UUID: "wired:" + name, - Type: "ethernet", - IsActive: active, - }) - } - - return conns, nil -} - -func (b *SystemdNetworkdBackend) GetWiredNetworkDetails(id string) (*WiredNetworkInfoResponse, error) { - ifname := strings.TrimPrefix(id, "wired:") - - b.linksMutex.RLock() - _, exists := b.links[ifname] - b.linksMutex.RUnlock() - - if !exists { - return nil, fmt.Errorf("interface %s not found", ifname) - } - - iface, err := net.InterfaceByName(ifname) - if err != nil { - return nil, fmt.Errorf("get interface: %w", err) - } - - addrs, _ := iface.Addrs() - var ipv4s, ipv6s []string - for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok { - if ipv4 := ipnet.IP.To4(); ipv4 != nil { - ipv4s = append(ipv4s, ipnet.String()) - } else if ipv6 := ipnet.IP.To16(); ipv6 != nil { - ipv6s = append(ipv6s, ipnet.String()) - } - } - } - - return &WiredNetworkInfoResponse{ - UUID: id, - IFace: ifname, - HwAddr: iface.HardwareAddr.String(), - IPv4: WiredIPConfig{ - IPs: ipv4s, - }, - IPv6: WiredIPConfig{ - IPs: ipv6s, - }, - }, nil -} - -func (b *SystemdNetworkdBackend) ConnectEthernet() error { - b.linksMutex.RLock() - var primaryWired *linkInfo - for name, l := range b.links { - if strings.HasPrefix(name, "lo") || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") { - continue - } - primaryWired = l - break - } - b.linksMutex.RUnlock() - - if primaryWired == nil { - return fmt.Errorf("no wired interface found") - } - - linkObj := b.conn.Object(networkdBusName, primaryWired.path) - return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err -} - -func (b *SystemdNetworkdBackend) DisconnectEthernet() error { - return fmt.Errorf("not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ActivateWiredConnection(id string) error { - ifname := strings.TrimPrefix(id, "wired:") - - b.linksMutex.RLock() - link, exists := b.links[ifname] - b.linksMutex.RUnlock() - - if !exists { - return fmt.Errorf("interface %s not found", ifname) - } - - linkObj := b.conn.Object(networkdBusName, link.path) - return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err -} - -func (b *SystemdNetworkdBackend) GetEthernetDevices() []EthernetDevice { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return append([]EthernetDevice(nil), b.state.EthernetDevices...) -} - -func (b *SystemdNetworkdBackend) DisconnectEthernetDevice(device string) error { - return fmt.Errorf("not supported by networkd backend") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_signals.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_signals.go deleted file mode 100644 index dc642ed..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_signals.go +++ /dev/null @@ -1,68 +0,0 @@ -package network - -import ( - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -func (b *SystemdNetworkdBackend) StartMonitoring(onStateChange func()) error { - b.onStateChange = onStateChange - - b.signals = make(chan *dbus.Signal, 64) - b.conn.Signal(b.signals) - - matchRules := []string{ - "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/freedesktop/network1'", - "type='signal',interface='org.freedesktop.network1.Manager'", - } - - for _, rule := range matchRules { - if err := b.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule).Err; err != nil { - return fmt.Errorf("add match %q: %w", rule, err) - } - } - - b.sigWG.Add(1) - go b.signalLoop() - - return nil -} - -func (b *SystemdNetworkdBackend) StopMonitoring() { - b.sigWG.Wait() -} - -func (b *SystemdNetworkdBackend) signalLoop() { - defer b.sigWG.Done() - - for { - select { - case <-b.stopChan: - return - case sig := <-b.signals: - if sig == nil { - continue - } - - if sig.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" { - if len(sig.Body) < 2 { - continue - } - iface, ok := sig.Body[0].(string) - if !ok || iface != networkdLinkIface { - continue - } - - b.enumerateLinks() - if err := b.updateState(); err != nil { - log.Warnf("networkd state update failed: %v", err) - } - if b.onStateChange != nil { - b.onStateChange() - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_test.go deleted file mode 100644 index 18c5281..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestSystemdNetworkdBackend_New(t *testing.T) { - backend, err := NewSystemdNetworkdBackend() - assert.NoError(t, err) - assert.NotNil(t, backend) - assert.Equal(t, "networkd", backend.state.Backend) - assert.NotNil(t, backend.links) - assert.NotNil(t, backend.stopChan) -} - -func TestSystemdNetworkdBackend_GetCurrentState(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - backend.state.NetworkStatus = StatusEthernet - backend.state.EthernetConnected = true - backend.state.EthernetIP = "192.168.1.100" - - state, err := backend.GetCurrentState() - assert.NoError(t, err) - assert.NotNil(t, state) - assert.Equal(t, StatusEthernet, state.NetworkStatus) - assert.True(t, state.EthernetConnected) - assert.Equal(t, "192.168.1.100", state.EthernetIP) -} - -func TestSystemdNetworkdBackend_WiFiNotSupported(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - err := backend.ScanWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - req := ConnectionRequest{SSID: "test"} - err = backend.ConnectWiFi(req) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - err = backend.DisconnectWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - err = backend.ForgetWiFiNetwork("test") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - _, err = backend.GetWiFiNetworkDetails("test") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} - -func TestSystemdNetworkdBackend_VPNNotSupported(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - profiles, err := backend.ListVPNProfiles() - assert.NoError(t, err) - assert.Empty(t, profiles) - - active, err := backend.ListActiveVPN() - assert.NoError(t, err) - assert.Empty(t, active) - - err = backend.ConnectVPN("test", false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - err = backend.DisconnectVPN("test") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - err = backend.DisconnectAllVPN() - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") - - err = backend.ClearVPNCredentials("test") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} - -func TestSystemdNetworkdBackend_PromptBroker(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - broker := backend.GetPromptBroker() - assert.Nil(t, broker) - - err := backend.SetPromptBroker(nil) - assert.NoError(t, err) - - err = backend.SubmitCredentials("token", nil, false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not needed") - - err = backend.CancelCredentials("token") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not needed") -} - -func TestSystemdNetworkdBackend_GetWiFiEnabled(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - enabled, err := backend.GetWiFiEnabled() - assert.NoError(t, err) - assert.True(t, enabled) -} - -func TestSystemdNetworkdBackend_SetWiFiEnabled(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - err := backend.SetWiFiEnabled(false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} - -func TestSystemdNetworkdBackend_DisconnectEthernet(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - err := backend.DisconnectEthernet() - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} - -func TestSystemdNetworkdBackend_GetEthernetDevices(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - backend.state.EthernetDevices = []EthernetDevice{ - {Name: "enp0s3", State: "routable", Connected: true}, - {Name: "enp0s8", State: "no-carrier", Connected: false}, - } - - devices := backend.GetEthernetDevices() - assert.Len(t, devices, 2) - assert.Equal(t, "enp0s3", devices[0].Name) - assert.True(t, devices[0].Connected) -} - -func TestSystemdNetworkdBackend_DisconnectEthernetDevice(t *testing.T) { - backend, _ := NewSystemdNetworkdBackend() - - err := backend.DisconnectEthernetDevice("enp0s3") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not supported") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_unimplemented.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_unimplemented.go deleted file mode 100644 index 695c3c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkd_unimplemented.go +++ /dev/null @@ -1,99 +0,0 @@ -package network - -import "fmt" - -func (b *SystemdNetworkdBackend) GetWiFiEnabled() (bool, error) { - return true, nil -} - -func (b *SystemdNetworkdBackend) SetWiFiEnabled(enabled bool) error { - return fmt.Errorf("WiFi control not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ScanWiFi() error { - return fmt.Errorf("WiFi scan not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) { - return nil, fmt.Errorf("WiFi details not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) GetWiFiQRCodeContent(ssid string) (string, error) { - return "", fmt.Errorf("WiFi QR Code not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error { - return fmt.Errorf("WiFi connect not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) DisconnectWiFi() error { - return fmt.Errorf("WiFi disconnect not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ForgetWiFiNetwork(ssid string) error { - return fmt.Errorf("WiFi forget not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ListVPNProfiles() ([]VPNProfile, error) { - return []VPNProfile{}, nil -} - -func (b *SystemdNetworkdBackend) ListActiveVPN() ([]VPNActive, error) { - return []VPNActive{}, nil -} - -func (b *SystemdNetworkdBackend) ConnectVPN(uuidOrName string, singleActive bool) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) DisconnectVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) DisconnectAllVPN() error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ListVPNPlugins() ([]VPNPlugin, error) { - return []VPNPlugin{}, nil -} - -func (b *SystemdNetworkdBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { - return nil, fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { - return nil, fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) UpdateVPNConfig(uuid string, updates map[string]any) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) DeleteVPN(uuidOrName string) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) SetVPNCredentials(uuid, username, password string, save bool) error { - return fmt.Errorf("VPN not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - return fmt.Errorf("WiFi autoconnect not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) ScanWiFiDevice(device string) error { - return fmt.Errorf("WiFi scan not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) DisconnectWiFiDevice(device string) error { - return fmt.Errorf("WiFi disconnect not supported by networkd backend") -} - -func (b *SystemdNetworkdBackend) GetWiFiDevices() []WiFiDevice { - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager.go deleted file mode 100644 index 2233975..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager.go +++ /dev/null @@ -1,405 +0,0 @@ -package network - -import ( - "fmt" - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/Wifx/gonetworkmanager/v2" - "github.com/godbus/dbus/v5" -) - -const ( - dbusNMPath = "/org/freedesktop/NetworkManager" - dbusNMInterface = "org.freedesktop.NetworkManager" - dbusNMDeviceInterface = "org.freedesktop.NetworkManager.Device" - dbusNMWiredInterface = "org.freedesktop.NetworkManager.Device.Wired" - dbusNMWirelessInterface = "org.freedesktop.NetworkManager.Device.Wireless" - dbusNMAccessPointInterface = "org.freedesktop.NetworkManager.AccessPoint" - dbusPropsInterface = "org.freedesktop.DBus.Properties" - - NmDeviceStateReasonWrongPassword = 8 - NmDeviceStateReasonSupplicantTimeout = 24 - NmDeviceStateReasonSupplicantFailed = 25 - NmDeviceStateReasonSecretsRequired = 7 - NmDeviceStateReasonNoSecrets = 6 - NmDeviceStateReasonNoSsid = 10 - NmDeviceStateReasonDhcpClientFailed = 14 - NmDeviceStateReasonIpConfigUnavailable = 18 - NmDeviceStateReasonSupplicantDisconnect = 23 - NmDeviceStateReasonCarrier = 40 - NmDeviceStateReasonNewActivation = 60 -) - -type wifiDeviceInfo struct { - device gonetworkmanager.Device - wireless gonetworkmanager.DeviceWireless - name string - hwAddress string -} - -type ethernetDeviceInfo struct { - device gonetworkmanager.Device - wired gonetworkmanager.DeviceWired - name string - hwAddress string -} - -type NetworkManagerBackend struct { - nmConn any - ethernetDevice any - ethernetDevices map[string]*ethernetDeviceInfo - wifiDevice any - settings any - wifiDev any - wifiDevices map[string]*wifiDeviceInfo - - dbusConn *dbus.Conn - signals chan *dbus.Signal - sigWG sync.WaitGroup - stopChan chan struct{} - - secretAgent *SecretAgent - promptBroker PromptBroker - - state *BackendState - stateMutex sync.RWMutex - - lastFailedSSID string - lastFailedTime int64 - failedMutex sync.RWMutex - - pendingVPNSave *pendingVPNCredentials - pendingVPNSaveMu sync.Mutex - cachedVPNCreds *cachedVPNCredentials - cachedVPNCredsMu sync.Mutex - cachedPKCS11PIN *cachedPKCS11PIN - cachedPKCS11Mu sync.Mutex - cachedGPSamlCookie *cachedGPSamlCookie - cachedGPSamlMu sync.Mutex - - onStateChange func() -} - -type pendingVPNCredentials struct { - ConnectionPath string - Username string - Password string - SavePassword bool -} - -type cachedVPNCredentials struct { - ConnectionUUID string - Password string - SavePassword bool -} - -type cachedPKCS11PIN struct { - ConnectionUUID string - PIN string -} - -type cachedGPSamlCookie struct { - ConnectionUUID string - Cookie string - Host string - User string - Fingerprint string -} - -func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*NetworkManagerBackend, error) { - var nm gonetworkmanager.NetworkManager - var err error - - if len(nmConn) > 0 && nmConn[0] != nil { - // Use injected connection (for testing) - nm = nmConn[0] - } else { - // Create real connection - nm, err = gonetworkmanager.NewNetworkManager() - if err != nil { - return nil, fmt.Errorf("failed to connect to NetworkManager: %w", err) - } - } - - backend := &NetworkManagerBackend{ - nmConn: nm, - stopChan: make(chan struct{}), - ethernetDevices: make(map[string]*ethernetDeviceInfo), - wifiDevices: make(map[string]*wifiDeviceInfo), - state: &BackendState{ - Backend: "networkmanager", - }, - } - - return backend, nil -} - -func (b *NetworkManagerBackend) Initialize() error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - if s, err := gonetworkmanager.NewSettings(); err == nil { - b.settings = s - } - - devices, err := nm.GetDevices() - if err != nil { - return fmt.Errorf("failed to get devices: %w", err) - } - - for _, dev := range devices { - devType, err := dev.GetPropertyDeviceType() - if err != nil { - continue - } - - switch devType { - case gonetworkmanager.NmDeviceTypeEthernet: - if managed, _ := dev.GetPropertyManaged(); !managed { - continue - } - iface, err := dev.GetPropertyInterface() - if err != nil { - continue - } - w, err := gonetworkmanager.NewDeviceWired(dev.GetPath()) - if err != nil { - continue - } - hwAddr, _ := w.GetPropertyHwAddress() - - b.ethernetDevices[iface] = ðernetDeviceInfo{ - device: dev, - wired: w, - name: iface, - hwAddress: hwAddr, - } - - if b.ethernetDevice == nil { - b.ethernetDevice = dev - } - if err := b.updateEthernetState(); err != nil { - continue - } - _, err = b.listEthernetConnections() - if err != nil { - return fmt.Errorf("failed to get wired configurations: %w", err) - } - - case gonetworkmanager.NmDeviceTypeWifi: - iface, err := dev.GetPropertyInterface() - if err != nil { - continue - } - w, err := gonetworkmanager.NewDeviceWireless(dev.GetPath()) - if err != nil { - continue - } - hwAddr, _ := w.GetPropertyHwAddress() - - b.wifiDevices[iface] = &wifiDeviceInfo{ - device: dev, - wireless: w, - name: iface, - hwAddress: hwAddr, - } - - if b.wifiDevice == nil { - b.wifiDevice = dev - b.wifiDev = w - } - } - } - - wifiEnabled, err := nm.GetPropertyWirelessEnabled() - if err == nil { - b.stateMutex.Lock() - b.state.WiFiEnabled = wifiEnabled - b.stateMutex.Unlock() - } - - if err := b.updateWiFiState(); err != nil { - log.Warnf("Failed to update WiFi state: %v", err) - } - - if wifiEnabled { - if _, err := b.updateWiFiNetworks(); err != nil { - log.Warnf("Failed to get initial networks: %v", err) - } - b.updateAllWiFiDevices() - } - - b.updateAllEthernetDevices() - - if err := b.updatePrimaryConnection(); err != nil { - return err - } - - if _, err := b.ListVPNProfiles(); err != nil { - log.Warnf("Failed to get initial VPN profiles: %v", err) - } - - if _, err := b.ListActiveVPN(); err != nil { - log.Warnf("Failed to get initial active VPNs: %v", err) - } - - return nil -} - -func (b *NetworkManagerBackend) Close() { - close(b.stopChan) - b.StopMonitoring() - - if b.secretAgent != nil { - b.secretAgent.Close() - } -} - -func (b *NetworkManagerBackend) GetCurrentState() (*BackendState, error) { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - - state := *b.state - state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...) - state.WiFiDevices = append([]WiFiDevice(nil), b.state.WiFiDevices...) - state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...) - state.EthernetDevices = append([]EthernetDevice(nil), b.state.EthernetDevices...) - state.VPNProfiles = append([]VPNProfile(nil), b.state.VPNProfiles...) - state.VPNActive = append([]VPNActive(nil), b.state.VPNActive...) - - return &state, nil -} - -func (b *NetworkManagerBackend) StartMonitoring(onStateChange func()) error { - b.onStateChange = onStateChange - - if err := b.startSecretAgent(); err != nil { - return fmt.Errorf("failed to start secret agent: %w", err) - } - - if err := b.startSignalPump(); err != nil { - return err - } - - return nil -} - -func (b *NetworkManagerBackend) StopMonitoring() { - b.stopSignalPump() -} - -func (b *NetworkManagerBackend) GetPromptBroker() PromptBroker { - return b.promptBroker -} - -func (b *NetworkManagerBackend) SetPromptBroker(broker PromptBroker) error { - if broker == nil { - return fmt.Errorf("broker cannot be nil") - } - - hadAgent := b.secretAgent != nil - - b.promptBroker = broker - - if b.secretAgent != nil { - b.secretAgent.Close() - b.secretAgent = nil - } - - if hadAgent { - return b.startSecretAgent() - } - - return nil -} - -func (b *NetworkManagerBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error { - if b.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return b.promptBroker.Resolve(token, PromptReply{ - Secrets: secrets, - Save: save, - Cancel: false, - }) -} - -func (b *NetworkManagerBackend) CancelCredentials(token string) error { - if b.promptBroker == nil { - return fmt.Errorf("prompt broker not initialized") - } - - return b.promptBroker.Resolve(token, PromptReply{ - Cancel: true, - }) -} - -func (b *NetworkManagerBackend) ensureWiFiDevice() error { - if b.wifiDev != nil { - return nil - } - - if b.wifiDevice == nil { - return fmt.Errorf("no WiFi device available") - } - - dev := b.wifiDevice.(gonetworkmanager.Device) - wifiDev, err := gonetworkmanager.NewDeviceWireless(dev.GetPath()) - if err != nil { - return fmt.Errorf("failed to get wireless device: %w", err) - } - b.wifiDev = wifiDev - return nil -} - -func (b *NetworkManagerBackend) startSecretAgent() error { - if b.promptBroker == nil { - return fmt.Errorf("prompt broker not set") - } - - agent, err := NewSecretAgent(b.promptBroker, nil, b) - if err != nil { - return err - } - - b.secretAgent = agent - return nil -} - -func (b *NetworkManagerBackend) getActiveConnections() (map[string]bool, error) { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - activeUUIDs := make(map[string]bool) - - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return activeUUIDs, fmt.Errorf("failed to get active connections: %w", err) - } - - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - - if connType != "802-3-ethernet" { - continue - } - - state, err := activeConn.GetPropertyState() - if err != nil { - continue - } - if state < 1 || state > 2 { - continue - } - - uuid, err := activeConn.GetPropertyUUID() - if err != nil { - continue - } - activeUUIDs[uuid] = true - } - return activeUUIDs, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet.go deleted file mode 100644 index 47f785b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet.go +++ /dev/null @@ -1,402 +0,0 @@ -package network - -import ( - "fmt" - "net" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/Wifx/gonetworkmanager/v2" -) - -func (b *NetworkManagerBackend) GetWiredConnections() ([]WiredConnection, error) { - return b.listEthernetConnections() -} - -func (b *NetworkManagerBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) { - if b.ethernetDevice == nil { - return nil, fmt.Errorf("no ethernet device available") - } - - dev := b.ethernetDevice.(gonetworkmanager.Device) - - iface, _ := dev.GetPropertyInterface() - driver, _ := dev.GetPropertyDriver() - - hwAddr := "Not available" - var speed uint32 = 0 - wiredDevice, err := gonetworkmanager.NewDeviceWired(dev.GetPath()) - if err == nil { - hwAddr, _ = wiredDevice.GetPropertyHwAddress() - speed, _ = wiredDevice.GetPropertySpeed() - } - var ipv4Config WiredIPConfig - var ipv6Config WiredIPConfig - - activeConn, err := dev.GetPropertyActiveConnection() - if err == nil && activeConn != nil { - ip4Config, err := activeConn.GetPropertyIP4Config() - if err == nil && ip4Config != nil { - var ips []string - addresses, err := ip4Config.GetPropertyAddressData() - if err == nil && len(addresses) > 0 { - for _, addr := range addresses { - ips = append(ips, fmt.Sprintf("%s/%s", addr.Address, strconv.Itoa(int(addr.Prefix)))) - } - } - - gateway, _ := ip4Config.GetPropertyGateway() - dnsAddrs := "" - dns, err := ip4Config.GetPropertyNameserverData() - if err == nil && len(dns) > 0 { - for _, d := range dns { - if len(dnsAddrs) > 0 { - dnsAddrs = strings.Join([]string{dnsAddrs, d.Address}, "; ") - } else { - dnsAddrs = d.Address - } - } - } - - ipv4Config = WiredIPConfig{ - IPs: ips, - Gateway: gateway, - DNS: dnsAddrs, - } - } - - ip6Config, err := activeConn.GetPropertyIP6Config() - if err == nil && ip6Config != nil { - var ips []string - addresses, err := ip6Config.GetPropertyAddressData() - if err == nil && len(addresses) > 0 { - for _, addr := range addresses { - ips = append(ips, fmt.Sprintf("%s/%s", addr.Address, strconv.Itoa(int(addr.Prefix)))) - } - } - - gateway, _ := ip6Config.GetPropertyGateway() - dnsAddrs := "" - dns, err := ip6Config.GetPropertyNameservers() - if err == nil && len(dns) > 0 { - for _, d := range dns { - if len(d) == 16 { - ip := net.IP(d) - if len(dnsAddrs) > 0 { - dnsAddrs = strings.Join([]string{dnsAddrs, ip.String()}, "; ") - } else { - dnsAddrs = ip.String() - } - } - } - } - - ipv6Config = WiredIPConfig{ - IPs: ips, - Gateway: gateway, - DNS: dnsAddrs, - } - } - } - - return &WiredNetworkInfoResponse{ - UUID: uuid, - IFace: iface, - Driver: driver, - HwAddr: hwAddr, - Speed: strconv.Itoa(int(speed)), - IPv4: ipv4Config, - IPv6: ipv6Config, - }, nil -} - -func (b *NetworkManagerBackend) ConnectEthernet() error { - if b.ethernetDevice == nil { - return fmt.Errorf("no ethernet device available") - } - - nm := b.nmConn.(gonetworkmanager.NetworkManager) - dev := b.ethernetDevice.(gonetworkmanager.Device) - - settingsMgr, err := gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - connSettings, err := conn.GetSettings() - if err != nil { - continue - } - - if connMeta, ok := connSettings["connection"]; ok { - if connType, ok := connMeta["type"].(string); ok && connType == "802-3-ethernet" { - _, err := nm.ActivateConnection(conn, dev, nil) - if err != nil { - return fmt.Errorf("failed to activate ethernet: %w", err) - } - - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil - } - } - } - - settings := make(map[string]map[string]any) - settings["connection"] = map[string]any{ - "id": "Wired connection", - "type": "802-3-ethernet", - } - - _, err = nm.AddAndActivateConnection(settings, dev) - if err != nil { - return fmt.Errorf("failed to create and activate ethernet: %w", err) - } - - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) DisconnectEthernet() error { - if b.ethernetDevice == nil { - return fmt.Errorf("no ethernet device available") - } - - dev := b.ethernetDevice.(gonetworkmanager.Device) - - err := dev.Disconnect() - if err != nil { - return fmt.Errorf("failed to disconnect: %w", err) - } - - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) ActivateWiredConnection(uuid string) error { - if b.ethernetDevice == nil { - return fmt.Errorf("no ethernet device available") - } - - nm := b.nmConn.(gonetworkmanager.NetworkManager) - dev := b.ethernetDevice.(gonetworkmanager.Device) - - settingsMgr, err := gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - var targetConnection gonetworkmanager.Connection - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - if connectionSettings, ok := settings["connection"]; ok { - if connUUID, ok := connectionSettings["uuid"].(string); ok && connUUID == uuid { - targetConnection = conn - break - } - } - } - - if targetConnection == nil { - return fmt.Errorf("connection with UUID %s not found", uuid) - } - - _, err = nm.ActivateConnection(targetConnection, dev, nil) - if err != nil { - return fmt.Errorf("error activation connection: %w", err) - } - - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) listEthernetConnections() ([]WiredConnection, error) { - if b.ethernetDevice == nil { - return nil, fmt.Errorf("no ethernet device available") - } - - s := b.settings - if s == nil { - s, err := gonetworkmanager.NewSettings() - if err != nil { - return nil, fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return nil, fmt.Errorf("failed to get connections: %w", err) - } - - wiredConfigs := make([]WiredConnection, 0) - activeUUIDs, err := b.getActiveConnections() - - if err != nil { - return nil, fmt.Errorf("failed to get active wired connections: %w", err) - } - - currentUuid := "" - for _, connection := range connections { - path := connection.GetPath() - settings, err := connection.GetSettings() - if err != nil { - log.Errorf("unable to get settings for %s: %v", path, err) - continue - } - - connectionSettings := settings["connection"] - connType, _ := connectionSettings["type"].(string) - connID, _ := connectionSettings["id"].(string) - connUUID, _ := connectionSettings["uuid"].(string) - - if connType == "802-3-ethernet" { - wiredConfigs = append(wiredConfigs, WiredConnection{ - Path: path, - ID: connID, - UUID: connUUID, - Type: connType, - IsActive: activeUUIDs[connUUID], - }) - if activeUUIDs[connUUID] { - currentUuid = connUUID - } - } - } - - b.stateMutex.Lock() - b.state.EthernetConnectionUuid = currentUuid - b.state.WiredConnections = wiredConfigs - b.stateMutex.Unlock() - - return wiredConfigs, nil -} - -func (b *NetworkManagerBackend) GetEthernetDevices() []EthernetDevice { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return append([]EthernetDevice(nil), b.state.EthernetDevices...) -} - -func (b *NetworkManagerBackend) DisconnectEthernetDevice(device string) error { - info, ok := b.ethernetDevices[device] - if !ok { - return fmt.Errorf("ethernet device %s not found", device) - } - - if err := info.device.Disconnect(); err != nil { - return fmt.Errorf("failed to disconnect %s: %w", device, err) - } - - b.updateAllEthernetDevices() - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) updateAllEthernetDevices() { - devices := make([]EthernetDevice, 0, len(b.ethernetDevices)) - - for name, info := range b.ethernetDevices { - state, _ := info.device.GetPropertyState() - connected := state == gonetworkmanager.NmDeviceStateActivated - driver, _ := info.device.GetPropertyDriver() - - var ip string - var speed uint32 = 0 - if connected { - ip = b.getDeviceIP(info.device) - } - if info.wired != nil { - speed, _ = info.wired.GetPropertySpeed() - } - - stateStr := "disconnected" - switch state { - case gonetworkmanager.NmDeviceStateActivated: - stateStr = "activated" - case gonetworkmanager.NmDeviceStatePrepare: - stateStr = "preparing" - case gonetworkmanager.NmDeviceStateConfig: - stateStr = "configuring" - case gonetworkmanager.NmDeviceStateIpConfig: - stateStr = "ip-config" - case gonetworkmanager.NmDeviceStateIpCheck: - stateStr = "ip-check" - case gonetworkmanager.NmDeviceStateSecondaries: - stateStr = "secondaries" - case gonetworkmanager.NmDeviceStateDeactivating: - stateStr = "deactivating" - case gonetworkmanager.NmDeviceStateFailed: - stateStr = "failed" - case gonetworkmanager.NmDeviceStateUnavailable: - stateStr = "unavailable" - case gonetworkmanager.NmDeviceStateUnmanaged: - stateStr = "unmanaged" - } - - devices = append(devices, EthernetDevice{ - Name: name, - HwAddress: info.hwAddress, - State: stateStr, - Connected: connected, - IP: ip, - Speed: speed, - Driver: driver, - }) - } - - b.stateMutex.Lock() - b.state.EthernetDevices = devices - b.stateMutex.Unlock() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet_test.go deleted file mode 100644 index 0901913..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_ethernet_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package network - -import ( - "testing" - - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_GetWiredConnections_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - _, err = backend.GetWiredConnections() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_GetWiredNetworkDetails_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - _, err = backend.GetWiredNetworkDetails("test-uuid") - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_ConnectEthernet_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - err = backend.ConnectEthernet() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_DisconnectEthernet_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - err = backend.DisconnectEthernet() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_ActivateWiredConnection_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - err = backend.ActivateWiredConnection("test-uuid") - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_ActivateWiredConnection_NotFound(t *testing.T) { - t.Skip("ActivateWiredConnection creates a new Settings instance internally, cannot be fully mocked") -} - -func TestNetworkManagerBackend_ListEthernetConnections_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - _, err = backend.listEthernetConnections() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestNetworkManagerBackend_GetEthernetDevices_Empty(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - devices := backend.GetEthernetDevices() - assert.Empty(t, devices) -} - -func TestNetworkManagerBackend_GetEthernetDevices_WithState(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.state.EthernetDevices = []EthernetDevice{ - {Name: "enp0s3", HwAddress: "00:11:22:33:44:55", State: "activated", Connected: true, IP: "192.168.1.100"}, - {Name: "enp0s8", HwAddress: "00:11:22:33:44:66", State: "disconnected", Connected: false}, - } - - devices := backend.GetEthernetDevices() - assert.Len(t, devices, 2) - assert.Equal(t, "enp0s3", devices[0].Name) - assert.True(t, devices[0].Connected) - assert.Equal(t, "enp0s8", devices[1].Name) - assert.False(t, devices[1].Connected) -} - -func TestNetworkManagerBackend_DisconnectEthernetDevice_NotFound(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - err = backend.DisconnectEthernetDevice("nonexistent") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not found") -} - -func TestNetworkManagerBackend_UpdateAllEthernetDevices_Empty(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.updateAllEthernetDevices() - assert.Empty(t, backend.state.EthernetDevices) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml.go deleted file mode 100644 index b1fa7fb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml.go +++ /dev/null @@ -1,203 +0,0 @@ -package network - -import ( - "bufio" - "context" - "fmt" - "os/exec" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -type gpSamlAuthResult struct { - Cookie string - Host string - User string - Fingerprint string -} - -// runGlobalProtectSAMLAuth handles GlobalProtect SAML/SSO authentication using gp-saml-gui. -// Only supports protocol=gp. Other protocols need their own implementations. -func (b *NetworkManagerBackend) runGlobalProtectSAMLAuth(ctx context.Context, gateway, protocol string) (*gpSamlAuthResult, error) { - if gateway == "" { - return nil, fmt.Errorf("GP SAML auth: gateway is empty") - } - if protocol != "gp" { - return nil, fmt.Errorf("only GlobalProtect (protocol=gp) SAML is supported, got: %s", protocol) - } - - log.Infof("[GP-SAML] Starting GlobalProtect SAML authentication with gp-saml-gui for gateway=%s", gateway) - - gpSamlPath, err := exec.LookPath("gp-saml-gui") - if err != nil { - return nil, fmt.Errorf("GlobalProtect SAML requires gp-saml-gui (install: pip install gp-saml-gui): %w", err) - } - - args := []string{ - "--gateway", - "--allow-insecure-crypto", - gateway, - } - - cmd := exec.CommandContext(ctx, gpSamlPath, args...) - - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, fmt.Errorf("GP SAML auth: failed to create stdout pipe: %w", err) - } - - stderr, err := cmd.StderrPipe() - if err != nil { - return nil, fmt.Errorf("GP SAML auth: failed to create stderr pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("GP SAML auth: failed to start gp-saml-gui: %w", err) - } - - go func() { - scanner := bufio.NewScanner(stderr) - for scanner.Scan() { - log.Debugf("[GP-SAML] gp-saml-gui: %s", scanner.Text()) - } - }() - - result := &gpSamlAuthResult{Host: gateway} - var allOutput []string - - scanner := bufio.NewScanner(stdout) - for scanner.Scan() { - line := scanner.Text() - allOutput = append(allOutput, line) - log.Infof("[GP-SAML] stdout: %s", line) - - switch { - case strings.HasPrefix(line, "COOKIE="): - result.Cookie = unshellQuote(strings.TrimPrefix(line, "COOKIE=")) - case strings.HasPrefix(line, "HOST="): - result.Host = unshellQuote(strings.TrimPrefix(line, "HOST=")) - case strings.HasPrefix(line, "USER="): - result.User = unshellQuote(strings.TrimPrefix(line, "USER=")) - case strings.HasPrefix(line, "FINGERPRINT="): - result.Fingerprint = unshellQuote(strings.TrimPrefix(line, "FINGERPRINT=")) - default: - parseGPSamlFromCommandLine(line, result) - } - } - - if err := cmd.Wait(); err != nil { - if ctx.Err() != nil { - return nil, fmt.Errorf("GP SAML auth timed out or was cancelled: %w", ctx.Err()) - } - if result.Cookie == "" { - return nil, fmt.Errorf("GP SAML auth failed: %w (output: %s)", err, strings.Join(allOutput, "\n")) - } - log.Warnf("[GP-SAML] gp-saml-gui exited with error but cookie was captured: %v", err) - } - - if result.Cookie == "" { - return nil, fmt.Errorf("GP SAML auth: no cookie in gp-saml-gui output") - } - - log.Infof("[GP-SAML] Got prelogin-cookie from gp-saml-gui, converting to openconnect cookie via --authenticate") - - // Convert prelogin-cookie to full openconnect cookie format - ocResult, err := convertGPPreloginCookie(ctx, gateway, result.Cookie, result.User) - if err != nil { - return nil, fmt.Errorf("GP SAML auth: failed to convert prelogin-cookie: %w", err) - } - - result.Cookie = ocResult.Cookie - result.Host = ocResult.Host - result.Fingerprint = ocResult.Fingerprint - - log.Infof("[GP-SAML] Authentication successful: user=%s, host=%s, cookie_len=%d, has_fingerprint=%v", - result.User, result.Host, len(result.Cookie), result.Fingerprint != "") - return result, nil -} - -func convertGPPreloginCookie(ctx context.Context, gateway, preloginCookie, user string) (*gpSamlAuthResult, error) { - ocPath, err := exec.LookPath("openconnect") - if err != nil { - return nil, fmt.Errorf("openconnect not found: %w", err) - } - - args := []string{ - "--protocol=gp", - "--usergroup=gateway:prelogin-cookie", - "--user=" + user, - "--passwd-on-stdin", - "--allow-insecure-crypto", - "--authenticate", - gateway, - } - - cmd := exec.CommandContext(ctx, ocPath, args...) - cmd.Stdin = strings.NewReader(preloginCookie) - - output, err := cmd.CombinedOutput() - if err != nil { - return nil, fmt.Errorf("openconnect --authenticate failed: %w\noutput: %s", err, string(output)) - } - - result := &gpSamlAuthResult{} - for _, line := range strings.Split(string(output), "\n") { - line = strings.TrimSpace(line) - switch { - case strings.HasPrefix(line, "COOKIE="): - result.Cookie = unshellQuote(strings.TrimPrefix(line, "COOKIE=")) - case strings.HasPrefix(line, "HOST="): - result.Host = unshellQuote(strings.TrimPrefix(line, "HOST=")) - case strings.HasPrefix(line, "FINGERPRINT="): - result.Fingerprint = unshellQuote(strings.TrimPrefix(line, "FINGERPRINT=")) - case strings.HasPrefix(line, "CONNECT_URL="): - connectURL := unshellQuote(strings.TrimPrefix(line, "CONNECT_URL=")) - if connectURL != "" && result.Host == "" { - result.Host = connectURL - } - } - } - - if result.Cookie == "" { - return nil, fmt.Errorf("no COOKIE in openconnect --authenticate output: %s", string(output)) - } - - log.Infof("[GP-SAML] openconnect --authenticate: cookie_len=%d, host=%s, fingerprint=%s", - len(result.Cookie), result.Host, result.Fingerprint) - - return result, nil -} - -func unshellQuote(s string) string { - if len(s) >= 2 { - if (s[0] == '\'' && s[len(s)-1] == '\'') || - (s[0] == '"' && s[len(s)-1] == '"') { - return s[1 : len(s)-1] - } - } - return s -} - -func parseGPSamlFromCommandLine(line string, result *gpSamlAuthResult) { - if !strings.Contains(line, "openconnect") { - return - } - - for _, part := range strings.Fields(line) { - switch { - case strings.HasPrefix(part, "--cookie="): - if result.Cookie == "" { - result.Cookie = strings.TrimPrefix(part, "--cookie=") - } - case strings.HasPrefix(part, "--servercert="): - if result.Fingerprint == "" { - result.Fingerprint = strings.TrimPrefix(part, "--servercert=") - } - case strings.HasPrefix(part, "--user="): - if result.User == "" { - result.User = strings.TrimPrefix(part, "--user=") - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml_test.go deleted file mode 100644 index 5655815..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_gp_saml_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestUnshellQuote(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - { - name: "single quoted", - input: "'hello world'", - expected: "hello world", - }, - { - name: "double quoted", - input: `"hello world"`, - expected: "hello world", - }, - { - name: "unquoted", - input: "hello", - expected: "hello", - }, - { - name: "empty single quotes", - input: "''", - expected: "", - }, - { - name: "empty double quotes", - input: `""`, - expected: "", - }, - { - name: "single quote only", - input: "'", - expected: "'", - }, - { - name: "mismatched quotes", - input: "'hello\"", - expected: "'hello\"", - }, - { - name: "with special chars", - input: "'cookie=abc123&user=john'", - expected: "cookie=abc123&user=john", - }, - { - name: "complex cookie", - input: `'authcookie=077058d3bc81&portal=PANGP_GW_01-N&user=john.doe@example.com&domain=Default&preferred-ip=192.168.1.100'`, - expected: "authcookie=077058d3bc81&portal=PANGP_GW_01-N&user=john.doe@example.com&domain=Default&preferred-ip=192.168.1.100", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := unshellQuote(tt.input) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestParseGPSamlFromCommandLine(t *testing.T) { - tests := []struct { - name string - line string - initialResult *gpSamlAuthResult - expectedCookie string - expectedUser string - expectedFP string - }{ - { - name: "full openconnect command", - line: "openconnect --protocol=gp --cookie=AUTH123 --servercert=pin-sha256:ABC --user=john", - initialResult: &gpSamlAuthResult{}, - expectedCookie: "AUTH123", - expectedUser: "john", - expectedFP: "pin-sha256:ABC", - }, - { - name: "with equals signs in cookie", - line: "openconnect --cookie=authcookie=xyz123&portal=GATE --user=jane", - initialResult: &gpSamlAuthResult{}, - expectedCookie: "authcookie=xyz123&portal=GATE", - expectedUser: "jane", - expectedFP: "", - }, - { - name: "non-openconnect line", - line: "some other output", - initialResult: &gpSamlAuthResult{}, - expectedCookie: "", - expectedUser: "", - expectedFP: "", - }, - { - name: "preserves existing values", - line: "openconnect --user=newuser", - initialResult: &gpSamlAuthResult{Cookie: "existing", Fingerprint: "existing-fp"}, - expectedCookie: "existing", - expectedUser: "newuser", - expectedFP: "existing-fp", - }, - { - name: "only updates empty fields", - line: "openconnect --cookie=NEW --user=NEW", - initialResult: &gpSamlAuthResult{Cookie: "OLD"}, - expectedCookie: "OLD", - expectedUser: "NEW", - expectedFP: "", - }, - { - name: "real gp-saml-gui output", - line: "openconnect --protocol=gp --user=john.doe@example.com --os=linux-64 --usergroup=gateway:prelogin-cookie --passwd-on-stdin", - initialResult: &gpSamlAuthResult{}, - expectedCookie: "", - expectedUser: "john.doe@example.com", - expectedFP: "", - }, - { - name: "with server cert flag", - line: "openconnect --servercert=pin-sha256:xp3scfzy3rOgQEXnfPiYKrUk7D66a8b8O+gEXaMPleE= vpn.example.com", - initialResult: &gpSamlAuthResult{}, - expectedCookie: "", - expectedUser: "", - expectedFP: "pin-sha256:xp3scfzy3rOgQEXnfPiYKrUk7D66a8b8O+gEXaMPleE=", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := tt.initialResult - parseGPSamlFromCommandLine(tt.line, result) - - assert.Equal(t, tt.expectedCookie, result.Cookie, "cookie mismatch") - assert.Equal(t, tt.expectedUser, result.User, "user mismatch") - assert.Equal(t, tt.expectedFP, result.Fingerprint, "fingerprint mismatch") - }) - } -} - -func TestParseGPSamlFromCommandLine_MultipleLines(t *testing.T) { - // Simulate gp-saml-gui output with command line suggestion - lines := []string{ - "", - "SAML REDIRECT", - "Got SAML Login URL", - "POST to ACS endpoint...", - "Got 'prelogin-cookie': 'FAKE_cookie_12345'", - "openconnect --protocol=gp --user=john.doe@example.com --usergroup=gateway:prelogin-cookie --passwd-on-stdin vpn.example.com", - "", - } - - result := &gpSamlAuthResult{} - for _, line := range lines { - parseGPSamlFromCommandLine(line, result) - } - - assert.Equal(t, "john.doe@example.com", result.User) - assert.Empty(t, result.Cookie, "cookie should not be parsed from command line") - assert.Empty(t, result.Fingerprint) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals.go deleted file mode 100644 index 5274ed0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals.go +++ /dev/null @@ -1,530 +0,0 @@ -package network - -import ( - "github.com/Wifx/gonetworkmanager/v2" - "github.com/godbus/dbus/v5" -) - -func (b *NetworkManagerBackend) startSignalPump() error { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return err - } - b.dbusConn = conn - - signals := make(chan *dbus.Signal, 256) - b.signals = signals - conn.Signal(signals) - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ); err != nil { - conn.RemoveSignal(signals) - conn.Close() - return err - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")), - dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"), - dbus.WithMatchMember("NewConnection"), - ); err != nil { - conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - conn.RemoveSignal(signals) - conn.Close() - return err - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")), - dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"), - dbus.WithMatchMember("ConnectionRemoved"), - ); err != nil { - conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - conn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")), - dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"), - dbus.WithMatchMember("NewConnection"), - ) - conn.RemoveSignal(signals) - conn.Close() - return err - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusNMInterface), - dbus.WithMatchMember("DeviceAdded"), - ); err != nil { - conn.RemoveSignal(signals) - conn.Close() - return err - } - - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusNMInterface), - dbus.WithMatchMember("DeviceRemoved"), - ); err != nil { - conn.RemoveSignal(signals) - conn.Close() - return err - } - - for _, info := range b.wifiDevices { - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ); err != nil { - conn.RemoveSignal(signals) - conn.Close() - return err - } - } - - for _, info := range b.ethernetDevices { - if err := conn.AddMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ); err != nil { - conn.RemoveSignal(signals) - conn.Close() - return err - } - } - - b.sigWG.Add(1) - go func() { - defer b.sigWG.Done() - for { - select { - case <-b.stopChan: - return - case sig, ok := <-signals: - if !ok { - return - } - if sig == nil { - continue - } - b.handleDBusSignal(sig) - } - } - }() - return nil -} - -func (b *NetworkManagerBackend) stopSignalPump() { - if b.dbusConn == nil { - return - } - - b.dbusConn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - - for _, info := range b.wifiDevices { - b.dbusConn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - } - - for _, info := range b.ethernetDevices { - b.dbusConn.RemoveMatchSignal( - dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - } - - if b.signals != nil { - b.dbusConn.RemoveSignal(b.signals) - close(b.signals) - } - - b.sigWG.Wait() - - b.dbusConn.Close() -} - -func (b *NetworkManagerBackend) handleDBusSignal(sig *dbus.Signal) { - if sig.Name == "org.freedesktop.NetworkManager.Settings.NewConnection" || - sig.Name == "org.freedesktop.NetworkManager.Settings.ConnectionRemoved" { - b.ListVPNProfiles() - if b.onStateChange != nil { - b.onStateChange() - } - return - } - - if sig.Name == "org.freedesktop.NetworkManager.DeviceAdded" { - if len(sig.Body) >= 1 { - if devicePath, ok := sig.Body[0].(dbus.ObjectPath); ok { - b.handleDeviceAdded(devicePath) - } - } - return - } - - if sig.Name == "org.freedesktop.NetworkManager.DeviceRemoved" { - if len(sig.Body) >= 1 { - if devicePath, ok := sig.Body[0].(dbus.ObjectPath); ok { - b.handleDeviceRemoved(devicePath) - } - } - return - } - - if len(sig.Body) < 2 { - return - } - - iface, ok := sig.Body[0].(string) - if !ok { - return - } - - changes, ok := sig.Body[1].(map[string]dbus.Variant) - if !ok { - return - } - - switch iface { - case dbusNMInterface: - b.handleNetworkManagerChange(changes) - - case dbusNMDeviceInterface: - b.handleDeviceChange(sig.Path, changes) - - case dbusNMWiredInterface: - b.handleWiredChange(changes) - - case dbusNMWirelessInterface: - b.handleWiFiChange(changes) - - case dbusNMAccessPointInterface: - b.handleAccessPointChange(changes) - } -} - -func (b *NetworkManagerBackend) handleNetworkManagerChange(changes map[string]dbus.Variant) { - var needsUpdate bool - - for key := range changes { - switch key { - case "PrimaryConnection", "State", "ActiveConnections": - needsUpdate = true - case "WirelessEnabled": - nm := b.nmConn.(gonetworkmanager.NetworkManager) - if enabled, err := nm.GetPropertyWirelessEnabled(); err == nil { - b.stateMutex.Lock() - b.state.WiFiEnabled = enabled - b.stateMutex.Unlock() - needsUpdate = true - } - default: - continue - } - } - - if needsUpdate { - b.updatePrimaryConnection() - if _, exists := changes["State"]; exists { - b.updateEthernetState() - b.updateWiFiState() - } - if _, exists := changes["ActiveConnections"]; exists { - b.updateVPNConnectionState() - b.ListActiveVPN() - } - if b.onStateChange != nil { - b.onStateChange() - } - } -} - -func (b *NetworkManagerBackend) handleDeviceChange(devicePath dbus.ObjectPath, changes map[string]dbus.Variant) { - var needsUpdate bool - var stateChanged bool - var managedChanged bool - - for key := range changes { - switch key { - case "State": - stateChanged = true - needsUpdate = true - case "Ip4Config": - needsUpdate = true - case "Managed": - managedChanged = true - default: - continue - } - } - - if managedChanged { - if managedVariant, ok := changes["Managed"]; ok { - if managed, ok := managedVariant.Value().(bool); ok && managed { - b.handleDeviceAdded(devicePath) - return - } - } - } - - if !needsUpdate { - return - } - - b.updateAllEthernetDevices() - b.updateEthernetState() - b.updateAllWiFiDevices() - b.updateWiFiState() - if stateChanged { - b.listEthernetConnections() - b.updatePrimaryConnection() - } - if b.onStateChange != nil { - b.onStateChange() - } -} - -func (b *NetworkManagerBackend) handleWiredChange(changes map[string]dbus.Variant) { - var needsUpdate bool - - for key := range changes { - switch key { - case "Carrier", "Speed", "HwAddress": - needsUpdate = true - default: - continue - } - } - - if !needsUpdate { - return - } - - b.updateAllEthernetDevices() - b.updateEthernetState() - b.updatePrimaryConnection() - if b.onStateChange != nil { - b.onStateChange() - } -} - -func (b *NetworkManagerBackend) handleWiFiChange(changes map[string]dbus.Variant) { - var needsStateUpdate bool - var needsNetworkUpdate bool - - for key := range changes { - switch key { - case "ActiveAccessPoint": - needsStateUpdate = true - needsNetworkUpdate = true - case "AccessPoints": - needsNetworkUpdate = true - default: - continue - } - } - - if needsStateUpdate { - b.updateWiFiState() - } - if needsNetworkUpdate { - b.updateWiFiNetworks() - } - if needsStateUpdate || needsNetworkUpdate { - if b.onStateChange != nil { - b.onStateChange() - } - } -} - -func (b *NetworkManagerBackend) handleAccessPointChange(changes map[string]dbus.Variant) { - _, hasStrength := changes["Strength"] - if !hasStrength { - return - } - - b.stateMutex.RLock() - oldSignal := b.state.WiFiSignal - b.stateMutex.RUnlock() - - b.updateWiFiState() - - b.stateMutex.RLock() - newSignal := b.state.WiFiSignal - b.stateMutex.RUnlock() - - if signalChangeSignificant(oldSignal, newSignal) { - if b.onStateChange != nil { - b.onStateChange() - } - } -} - -func (b *NetworkManagerBackend) handleDeviceAdded(devicePath dbus.ObjectPath) { - dev, err := gonetworkmanager.NewDevice(devicePath) - if err != nil { - return - } - - devType, err := dev.GetPropertyDeviceType() - if err != nil { - return - } - - if devType != gonetworkmanager.NmDeviceTypeEthernet && devType != gonetworkmanager.NmDeviceTypeWifi { - return - } - - if b.dbusConn != nil { - b.dbusConn.AddMatchSignal( - dbus.WithMatchObjectPath(devicePath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - } - - managed, _ := dev.GetPropertyManaged() - if !managed { - return - } - - iface, err := dev.GetPropertyInterface() - if err != nil { - return - } - - switch devType { - case gonetworkmanager.NmDeviceTypeEthernet: - w, err := gonetworkmanager.NewDeviceWired(devicePath) - if err != nil { - return - } - hwAddr, _ := w.GetPropertyHwAddress() - - b.ethernetDevices[iface] = ðernetDeviceInfo{ - device: dev, - wired: w, - name: iface, - hwAddress: hwAddr, - } - - if b.ethernetDevice == nil { - b.ethernetDevice = dev - } - - b.updateAllEthernetDevices() - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - case gonetworkmanager.NmDeviceTypeWifi: - w, err := gonetworkmanager.NewDeviceWireless(devicePath) - if err != nil { - return - } - hwAddr, _ := w.GetPropertyHwAddress() - - b.wifiDevices[iface] = &wifiDeviceInfo{ - device: dev, - wireless: w, - name: iface, - hwAddress: hwAddr, - } - - if b.wifiDevice == nil { - b.wifiDevice = dev - b.wifiDev = w - } - - b.updateAllWiFiDevices() - b.updateWiFiState() - } - - if b.onStateChange != nil { - b.onStateChange() - } -} - -func (b *NetworkManagerBackend) handleDeviceRemoved(devicePath dbus.ObjectPath) { - if b.dbusConn != nil { - b.dbusConn.RemoveMatchSignal( - dbus.WithMatchObjectPath(devicePath), - dbus.WithMatchInterface(dbusPropsInterface), - dbus.WithMatchMember("PropertiesChanged"), - ) - } - - for iface, info := range b.ethernetDevices { - if info.device.GetPath() == devicePath { - delete(b.ethernetDevices, iface) - - if b.ethernetDevice != nil { - dev := b.ethernetDevice.(gonetworkmanager.Device) - if dev.GetPath() == devicePath { - b.ethernetDevice = nil - for _, remaining := range b.ethernetDevices { - b.ethernetDevice = remaining.device - break - } - } - } - - b.updateAllEthernetDevices() - b.updateEthernetState() - b.listEthernetConnections() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - return - } - } - - for iface, info := range b.wifiDevices { - if info.device.GetPath() == devicePath { - delete(b.wifiDevices, iface) - - if b.wifiDevice != nil { - dev := b.wifiDevice.(gonetworkmanager.Device) - if dev.GetPath() == devicePath { - b.wifiDevice = nil - b.wifiDev = nil - for _, remaining := range b.wifiDevices { - b.wifiDevice = remaining.device - b.wifiDev = remaining.wireless - break - } - } - } - - b.updateAllWiFiDevices() - b.updateWiFiState() - - if b.onStateChange != nil { - b.onStateChange() - } - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals_test.go deleted file mode 100644 index 6b58684..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_signals_test.go +++ /dev/null @@ -1,255 +0,0 @@ -package network - -import ( - "testing" - - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/Wifx/gonetworkmanager/v2" - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_HandleDBusSignal_NewConnection(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - sig := &dbus.Signal{ - Name: "org.freedesktop.NetworkManager.Settings.NewConnection", - Body: []any{"/org/freedesktop/NetworkManager/Settings/1"}, - } - - assert.NotPanics(t, func() { - backend.handleDBusSignal(sig) - }) -} - -func TestNetworkManagerBackend_HandleDBusSignal_ConnectionRemoved(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - sig := &dbus.Signal{ - Name: "org.freedesktop.NetworkManager.Settings.ConnectionRemoved", - Body: []any{"/org/freedesktop/NetworkManager/Settings/1"}, - } - - assert.NotPanics(t, func() { - backend.handleDBusSignal(sig) - }) -} - -func TestNetworkManagerBackend_HandleDBusSignal_InvalidBody(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{"only-one-element"}, - } - - assert.NotPanics(t, func() { - backend.handleDBusSignal(sig) - }) -} - -func TestNetworkManagerBackend_HandleDBusSignal_InvalidInterface(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{123, map[string]dbus.Variant{}}, - } - - assert.NotPanics(t, func() { - backend.handleDBusSignal(sig) - }) -} - -func TestNetworkManagerBackend_HandleDBusSignal_InvalidChanges(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - sig := &dbus.Signal{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - Body: []any{dbusNMInterface, "not-a-map"}, - } - - assert.NotPanics(t, func() { - backend.handleDBusSignal(sig) - }) -} - -func TestNetworkManagerBackend_HandleNetworkManagerChange(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil).Maybe() - mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil).Maybe() - - changes := map[string]dbus.Variant{ - "PrimaryConnection": dbus.MakeVariant("/"), - "State": dbus.MakeVariant(uint32(70)), - } - - assert.NotPanics(t, func() { - backend.handleNetworkManagerChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleNetworkManagerChange_WirelessEnabled(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyWirelessEnabled().Return(true, nil) - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil).Maybe() - mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil).Maybe() - - changes := map[string]dbus.Variant{ - "WirelessEnabled": dbus.MakeVariant(true), - } - - assert.NotPanics(t, func() { - backend.handleNetworkManagerChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleNetworkManagerChange_ActiveConnections(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil).Maybe() - - changes := map[string]dbus.Variant{ - "ActiveConnections": dbus.MakeVariant([]any{}), - } - - assert.NotPanics(t, func() { - backend.handleNetworkManagerChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleDeviceChange(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil).Maybe() - mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil).Maybe() - - changes := map[string]dbus.Variant{ - "State": dbus.MakeVariant(uint32(100)), - } - - assert.NotPanics(t, func() { - backend.handleDeviceChange("/org/freedesktop/NetworkManager/Devices/1", changes) - }) -} - -func TestNetworkManagerBackend_HandleDeviceChange_Ip4Config(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - changes := map[string]dbus.Variant{ - "Ip4Config": dbus.MakeVariant("/"), - } - - assert.NotPanics(t, func() { - backend.handleDeviceChange("/org/freedesktop/NetworkManager/Devices/1", changes) - }) -} - -func TestNetworkManagerBackend_HandleWiFiChange_ActiveAccessPoint(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - changes := map[string]dbus.Variant{ - "ActiveAccessPoint": dbus.MakeVariant("/"), - } - - assert.NotPanics(t, func() { - backend.handleWiFiChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleWiFiChange_AccessPoints(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - changes := map[string]dbus.Variant{ - "AccessPoints": dbus.MakeVariant([]any{}), - } - - assert.NotPanics(t, func() { - backend.handleWiFiChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleAccessPointChange_NoStrength(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - changes := map[string]dbus.Variant{ - "SomeOtherProperty": dbus.MakeVariant("value"), - } - - assert.NotPanics(t, func() { - backend.handleAccessPointChange(changes) - }) -} - -func TestNetworkManagerBackend_HandleAccessPointChange_WithStrength(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.stateMutex.Lock() - backend.state.WiFiSignal = 50 - backend.stateMutex.Unlock() - - changes := map[string]dbus.Variant{ - "Strength": dbus.MakeVariant(uint8(80)), - } - - assert.NotPanics(t, func() { - backend.handleAccessPointChange(changes) - }) -} - -func TestNetworkManagerBackend_StopSignalPump_NoConnection(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.dbusConn = nil - assert.NotPanics(t, func() { - backend.stopSignalPump() - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state.go deleted file mode 100644 index ba77f6d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state.go +++ /dev/null @@ -1,277 +0,0 @@ -package network - -import ( - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/Wifx/gonetworkmanager/v2" -) - -func (b *NetworkManagerBackend) updatePrimaryConnection() error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return err - } - - hasActiveVPN := false - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - if connType == "vpn" || connType == "wireguard" { - state, _ := activeConn.GetPropertyState() - if state == 2 { - hasActiveVPN = true - break - } - } - } - - if hasActiveVPN { - b.stateMutex.Lock() - b.state.NetworkStatus = StatusVPN - b.stateMutex.Unlock() - return nil - } - - primaryConn, err := nm.GetPropertyPrimaryConnection() - if err != nil { - return err - } - - if primaryConn == nil || primaryConn.GetPath() == "/" { - b.stateMutex.Lock() - b.state.NetworkStatus = StatusDisconnected - b.stateMutex.Unlock() - return nil - } - - connType, err := primaryConn.GetPropertyType() - if err != nil { - return err - } - - b.stateMutex.Lock() - switch connType { - case "802-3-ethernet": - b.state.NetworkStatus = StatusEthernet - case "802-11-wireless": - b.state.NetworkStatus = StatusWiFi - case "vpn", "wireguard": - b.state.NetworkStatus = StatusVPN - default: - b.state.NetworkStatus = StatusDisconnected - } - b.stateMutex.Unlock() - - return nil -} - -func (b *NetworkManagerBackend) updateEthernetState() error { - var connectedDevice string - var connectedIP string - var anyConnected bool - - for name, info := range b.ethernetDevices { - state, err := info.device.GetPropertyState() - if err != nil { - continue - } - - if state == gonetworkmanager.NmDeviceStateActivated { - anyConnected = true - connectedDevice = name - connectedIP = b.getDeviceIP(info.device) - break - } - } - - if !anyConnected && b.ethernetDevice != nil { - dev := b.ethernetDevice.(gonetworkmanager.Device) - iface, _ := dev.GetPropertyInterface() - connectedDevice = iface - } - - b.stateMutex.Lock() - b.state.EthernetDevice = connectedDevice - b.state.EthernetConnected = anyConnected - b.state.EthernetIP = connectedIP - b.stateMutex.Unlock() - - return nil -} - -func (b *NetworkManagerBackend) getDeviceStateReason(dev gonetworkmanager.Device) uint32 { - path := dev.GetPath() - obj := b.dbusConn.Object("org.freedesktop.NetworkManager", path) - - variant, err := obj.GetProperty(dbusNMDeviceInterface + ".StateReason") - if err != nil { - return 0 - } - - if stateReasonStruct, ok := variant.Value().([]any); ok && len(stateReasonStruct) >= 2 { - if reason, ok := stateReasonStruct[1].(uint32); ok { - return reason - } - } - - return 0 -} - -func (b *NetworkManagerBackend) classifyNMStateReason(reason uint32) string { - switch reason { - case NmDeviceStateReasonWrongPassword, - NmDeviceStateReasonSupplicantTimeout, - NmDeviceStateReasonSupplicantFailed, - NmDeviceStateReasonSecretsRequired: - return errdefs.ErrBadCredentials - case NmDeviceStateReasonNoSecrets: - return errdefs.ErrUserCanceled - case NmDeviceStateReasonNoSsid: - return errdefs.ErrNoSuchSSID - case NmDeviceStateReasonDhcpClientFailed, - NmDeviceStateReasonIpConfigUnavailable: - return errdefs.ErrDhcpTimeout - case NmDeviceStateReasonSupplicantDisconnect, - NmDeviceStateReasonCarrier: - return errdefs.ErrAssocTimeout - default: - return errdefs.ErrConnectionFailed - } -} - -func (b *NetworkManagerBackend) updateWiFiState() error { - if b.wifiDevice == nil { - return nil - } - - dev := b.wifiDevice.(gonetworkmanager.Device) - - iface, err := dev.GetPropertyInterface() - if err != nil { - return err - } - - state, err := dev.GetPropertyState() - if err != nil { - return err - } - - connected := state == gonetworkmanager.NmDeviceStateActivated - failed := state == gonetworkmanager.NmDeviceStateFailed - disconnected := state == gonetworkmanager.NmDeviceStateDisconnected - - var ip, ssid, bssid string - var signal uint8 - - if connected { - if err := b.ensureWiFiDevice(); err == nil && b.wifiDev != nil { - w := b.wifiDev.(gonetworkmanager.DeviceWireless) - activeAP, err := w.GetPropertyActiveAccessPoint() - if err == nil && activeAP != nil && activeAP.GetPath() != "/" { - ssid, _ = activeAP.GetPropertySSID() - signal, _ = activeAP.GetPropertyStrength() - bssid, _ = activeAP.GetPropertyHWAddress() - } - } - - ip = b.getDeviceIP(dev) - } - - b.stateMutex.RLock() - wasConnecting := b.state.IsConnecting - connectingSSID := b.state.ConnectingSSID - b.stateMutex.RUnlock() - - var reasonCode string - if wasConnecting && connectingSSID != "" && (failed || (disconnected && !connected)) { - reason := b.getDeviceStateReason(dev) - - if reason == NmDeviceStateReasonNewActivation || reason == 0 { - return nil - } - - log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d, reason=%d", connectingSSID, state, reason) - - reasonCode = b.classifyNMStateReason(reason) - - if reasonCode == errdefs.ErrConnectionFailed { - b.failedMutex.RLock() - if b.lastFailedSSID == connectingSSID { - elapsed := time.Now().Unix() - b.lastFailedTime - if elapsed < 5 { - reasonCode = errdefs.ErrBadCredentials - } - } - b.failedMutex.RUnlock() - } - } - - var forgetSSID string - - b.stateMutex.Lock() - - wasConnecting = b.state.IsConnecting - connectingSSID = b.state.ConnectingSSID - - if wasConnecting && connectingSSID != "" { - switch { - case connected && ssid == connectingSSID: - log.Infof("[updateWiFiState] Connection successful: %s", ssid) - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.LastError = "" - case failed || (disconnected && !connected): - log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d", connectingSSID, state) - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.LastError = reasonCode - - if reasonCode == errdefs.ErrUserCanceled { - forgetSSID = connectingSSID - } - - b.failedMutex.Lock() - b.lastFailedSSID = connectingSSID - b.lastFailedTime = time.Now().Unix() - b.failedMutex.Unlock() - } - } - - b.state.WiFiDevice = iface - b.state.WiFiConnected = connected - b.state.WiFiIP = ip - b.state.WiFiSSID = ssid - b.state.WiFiBSSID = bssid - b.state.WiFiSignal = signal - - b.stateMutex.Unlock() - - if forgetSSID != "" { - log.Infof("[updateWiFiState] User cancelled authentication, removing connection profile for %s", forgetSSID) - if err := b.ForgetWiFiNetwork(forgetSSID); err != nil { - log.Warnf("[updateWiFiState] Failed to remove cancelled connection: %v", err) - } - } - - return nil -} - -func (b *NetworkManagerBackend) getDeviceIP(dev gonetworkmanager.Device) string { - ip4Config, err := dev.GetPropertyIP4Config() - if err != nil || ip4Config == nil { - return "" - } - - addresses, err := ip4Config.GetPropertyAddressData() - if err != nil || len(addresses) == 0 { - return "" - } - - return addresses[0].Address -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state_test.go deleted file mode 100644 index 86aa48f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_state_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package network - -import ( - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/Wifx/gonetworkmanager/v2" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_UpdatePrimaryConnection(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil) - - err = backend.updatePrimaryConnection() - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_UpdateEthernetState_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.ethernetDevice = nil - err = backend.updateEthernetState() - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_UpdateWiFiState_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - err = backend.updateWiFiState() - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_ClassifyNMStateReason(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - testCases := []struct { - reason uint32 - expected string - }{ - {NmDeviceStateReasonWrongPassword, errdefs.ErrBadCredentials}, - {NmDeviceStateReasonNoSecrets, errdefs.ErrUserCanceled}, - {NmDeviceStateReasonSupplicantTimeout, errdefs.ErrBadCredentials}, - {NmDeviceStateReasonDhcpClientFailed, errdefs.ErrDhcpTimeout}, - {NmDeviceStateReasonNoSsid, errdefs.ErrNoSuchSSID}, - {999, errdefs.ErrConnectionFailed}, - } - - for _, tc := range testCases { - result := backend.classifyNMStateReason(tc.reason) - assert.Equal(t, tc.expected, result) - } -} - -func TestNetworkManagerBackend_GetDeviceIP_NoConfig(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockDevice := mock_gonetworkmanager.NewMockDevice(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockDevice.EXPECT().GetPropertyIP4Config().Return(nil, nil) - - ip := backend.getDeviceIP(mockDevice) - assert.Empty(t, ip) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_test.go deleted file mode 100644 index 1391e4a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package network - -import ( - "testing" - - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_New(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - assert.NotNil(t, backend) - assert.Equal(t, "networkmanager", backend.state.Backend) - assert.NotNil(t, backend.stopChan) - assert.NotNil(t, backend.state) -} - -func TestNetworkManagerBackend_GetCurrentState(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.state.NetworkStatus = StatusWiFi - backend.state.WiFiConnected = true - backend.state.WiFiSSID = "TestNetwork" - backend.state.WiFiIP = "192.168.1.100" - backend.state.WiFiNetworks = []WiFiNetwork{ - {SSID: "TestNetwork", Signal: 80, Connected: true}, - } - backend.state.WiredConnections = []WiredConnection{ - {ID: "Wired connection 1", UUID: "test-uuid"}, - } - - state, err := backend.GetCurrentState() - assert.NoError(t, err) - assert.NotNil(t, state) - assert.Equal(t, StatusWiFi, state.NetworkStatus) - assert.True(t, state.WiFiConnected) - assert.Equal(t, "TestNetwork", state.WiFiSSID) - assert.Len(t, state.WiFiNetworks, 1) - assert.Len(t, state.WiredConnections, 1) - - assert.NotSame(t, &backend.state.WiFiNetworks, &state.WiFiNetworks) - assert.NotSame(t, &backend.state.WiredConnections, &state.WiredConnections) -} - -func TestNetworkManagerBackend_SetPromptBroker_Nil(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - err = backend.SetPromptBroker(nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "cannot be nil") -} - -func TestNetworkManagerBackend_SubmitCredentials_NoBroker(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.promptBroker = nil - err = backend.SubmitCredentials("token", map[string]string{"password": "test"}, false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not initialized") -} - -func TestNetworkManagerBackend_CancelCredentials_NoBroker(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.promptBroker = nil - err = backend.CancelCredentials("token") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not initialized") -} - -func TestNetworkManagerBackend_EnsureWiFiDevice_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - backend.wifiDev = nil - - err = backend.ensureWiFiDevice() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_EnsureWiFiDevice_AlreadySet(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDev = "dummy-device" - - err = backend.ensureWiFiDevice() - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_StartSecretAgent_NoBroker(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.promptBroker = nil - err = backend.startSecretAgent() - assert.Error(t, err) - assert.Contains(t, err.Error(), "prompt broker not set") -} - -func TestNetworkManagerBackend_Close(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - assert.NotPanics(t, func() { - backend.Close() - }) -} - -func TestNetworkManagerBackend_GetPromptBroker(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - broker := backend.GetPromptBroker() - assert.Nil(t, broker) -} - -func TestNetworkManagerBackend_StopMonitoring_NoSignals(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - assert.NotPanics(t, func() { - backend.StopMonitoring() - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn.go deleted file mode 100644 index 261fcef..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn.go +++ /dev/null @@ -1,1394 +0,0 @@ -package network - -import ( - "bufio" - "context" - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/Wifx/gonetworkmanager/v2" - "github.com/godbus/dbus/v5" -) - -func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return nil, fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return nil, fmt.Errorf("failed to get connections: %w", err) - } - - profiles := []VPNProfile{} - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - autoconnect, _ := connMeta["autoconnect"].(bool) - - profile := VPNProfile{ - Name: connID, - UUID: connUUID, - Type: connType, - Autoconnect: autoconnect, - } - - if connType == "vpn" { - if vpnSettings, ok := settings["vpn"]; ok { - if svcType, ok := vpnSettings["service-type"].(string); ok { - profile.ServiceType = svcType - } - // Get full data map - if data, ok := vpnSettings["data"].(map[string]string); ok { - profile.Data = data - if remote, ok := data["remote"]; ok { - profile.RemoteHost = remote - } - if username, ok := data["username"]; ok { - profile.Username = username - } - } - } - } - - profiles = append(profiles, profile) - } - - sort.Slice(profiles, func(i, j int) bool { - return strings.ToLower(profiles[i].Name) < strings.ToLower(profiles[j].Name) - }) - - b.stateMutex.Lock() - b.state.VPNProfiles = profiles - b.stateMutex.Unlock() - - return profiles, nil -} - -func (b *NetworkManagerBackend) ListActiveVPN() ([]VPNActive, error) { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return nil, fmt.Errorf("failed to get active connections: %w", err) - } - - active := []VPNActive{} - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - - if connType != "vpn" && connType != "wireguard" { - continue - } - - uuid, _ := activeConn.GetPropertyUUID() - id, _ := activeConn.GetPropertyID() - state, _ := activeConn.GetPropertyState() - - var stateStr string - switch state { - case 0: - stateStr = "unknown" - case 1: - stateStr = "activating" - case 2: - stateStr = "activated" - case 3: - stateStr = "deactivating" - case 4: - stateStr = "deactivated" - } - - vpnActive := VPNActive{ - Name: id, - UUID: uuid, - State: stateStr, - Type: connType, - Plugin: "", - } - - // Get VPN device - devices, _ := activeConn.GetPropertyDevices() - if len(devices) > 0 { - if iface, err := devices[0].GetPropertyInterface(); err == nil { - vpnActive.Device = iface - } - } - - // Get VPN IP from IP4Config - if ip4Config, err := activeConn.GetPropertyIP4Config(); err == nil && ip4Config != nil { - if addrData, err := ip4Config.GetPropertyAddressData(); err == nil && len(addrData) > 0 { - vpnActive.IP = addrData[0].Address - } - if gw, err := ip4Config.GetPropertyGateway(); err == nil { - vpnActive.Gateway = gw - } - } - - // Get MTU from device - if len(devices) > 0 { - if mtu, err := devices[0].GetPropertyMtu(); err == nil { - vpnActive.MTU = mtu - } - } - - if connType == "vpn" { - conn, _ := activeConn.GetPropertyConnection() - if conn != nil { - connSettings, err := conn.GetSettings() - if err == nil { - if vpnSettings, ok := connSettings["vpn"]; ok { - if svcType, ok := vpnSettings["service-type"].(string); ok { - vpnActive.Plugin = svcType - } - // Get full data map - if data, ok := vpnSettings["data"].(map[string]string); ok { - vpnActive.Data = data - if remote, ok := data["remote"]; ok { - vpnActive.RemoteHost = remote - } - if username, ok := data["username"]; ok { - vpnActive.Username = username - } - } - } - } - } - } - - active = append(active, vpnActive) - } - - b.stateMutex.Lock() - b.state.VPNActive = active - b.stateMutex.Unlock() - - return active, nil -} - -func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool) error { - if singleActive { - active, err := b.ListActiveVPN() - if err == nil && len(active) > 0 { - alreadyConnected := false - for _, vpn := range active { - if vpn.UUID == uuidOrName || vpn.Name == uuidOrName { - alreadyConnected = true - break - } - } - - if !alreadyConnected { - if err := b.DisconnectAllVPN(); err != nil { - log.Warnf("Failed to disconnect existing VPNs: %v", err) - } - time.Sleep(500 * time.Millisecond) - } else { - return nil - } - } - } - - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - var targetConn gonetworkmanager.Connection - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - - if connUUID == uuidOrName || connID == uuidOrName { - targetConn = conn - break - } - } - - if targetConn == nil { - return fmt.Errorf("VPN connection not found: %s", uuidOrName) - } - - targetSettings, err := targetConn.GetSettings() - if err != nil { - return fmt.Errorf("failed to get connection settings: %w", err) - } - - var targetUUID string - var connName string - if connMeta, ok := targetSettings["connection"]; ok { - if uuid, ok := connMeta["uuid"].(string); ok { - targetUUID = uuid - } - if id, ok := connMeta["id"].(string); ok { - connName = id - } - } - - var vpnServiceType string - var vpnData map[string]string - if vpnSettings, ok := targetSettings["vpn"]; ok { - if svc, ok := vpnSettings["service-type"].(string); ok { - vpnServiceType = svc - } - if data, ok := vpnSettings["data"].(map[string]string); ok { - vpnData = data - } - } - - authAction := detectVPNAuthAction(vpnServiceType, vpnData) - - switch authAction { - case "openvpn_username": - if b.promptBroker == nil { - return fmt.Errorf("OpenVPN password authentication requires interactive prompt") - } - if err := b.handleOpenVPNUsernameAuth(targetConn, connName, targetUUID, vpnServiceType); err != nil { - return err - } - case "gp_saml": - gateway := vpnData["gateway"] - protocol := vpnData["protocol"] - if protocol != "gp" { - return fmt.Errorf("GlobalProtect SAML authentication only supported for protocol=gp, got: %s", protocol) - } - - log.Infof("[ConnectVPN] GlobalProtect SAML/SSO authentication required for %s (gateway=%s)", connName, gateway) - - samlCtx, samlCancel := context.WithTimeout(context.Background(), 5*time.Minute) - authResult, err := b.runGlobalProtectSAMLAuth(samlCtx, gateway, protocol) - samlCancel() - if err != nil { - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "not installed"): - return fmt.Errorf("gp-saml-gui is not installed (required for GlobalProtect SAML/SSO VPN)") - case strings.Contains(errMsg, "timed out") || strings.Contains(errMsg, "cancelled"): - return fmt.Errorf("GlobalProtect SAML authentication timed out — please try again") - case strings.Contains(errMsg, "no cookie"): - return fmt.Errorf("GlobalProtect SAML login did not complete — browser was closed before authentication finished") - case strings.Contains(errMsg, "convert prelogin-cookie"): - return fmt.Errorf("GlobalProtect VPN authentication succeeded but cookie exchange failed: %w", err) - default: - return fmt.Errorf("GlobalProtect SAML authentication failed: %w", err) - } - } - - b.cachedGPSamlMu.Lock() - b.cachedGPSamlCookie = &cachedGPSamlCookie{ - ConnectionUUID: targetUUID, - Cookie: authResult.Cookie, - Host: authResult.Host, - User: authResult.User, - Fingerprint: authResult.Fingerprint, - } - b.cachedGPSamlMu.Unlock() - - if err := targetConn.ClearSecrets(); err != nil { - log.Warnf("[ConnectVPN] ClearSecrets failed (non-fatal): %v", err) - } else { - log.Infof("[ConnectVPN] Cleared stale stored secrets for %s", connName) - } - - log.Infof("[ConnectVPN] GlobalProtect SAML cookie cached for %s, proceeding with activation", connName) - } - - b.stateMutex.Lock() - b.state.IsConnectingVPN = true - b.state.ConnectingVPNUUID = targetUUID - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - nm := b.nmConn.(gonetworkmanager.NetworkManager) - _, err = nm.ActivateConnection(targetConn, nil, nil) - if err != nil { - b.stateMutex.Lock() - b.state.IsConnectingVPN = false - b.state.ConnectingVPNUUID = "" - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - return fmt.Errorf("failed to activate VPN: %w", err) - } - - return nil -} - -func detectVPNAuthAction(serviceType string, data map[string]string) string { - if data == nil { - return "" - } - - switch { - case strings.Contains(serviceType, "openconnect"): - protocol := data["protocol"] - if needsExternalBrowserAuth(protocol, data["authtype"], data["username"], data) { - switch protocol { - case "gp": - return "gp_saml" - default: - log.Infof("[VPN] External browser auth detected for protocol '%s' but only GlobalProtect (gp) is currently supported", protocol) - } - } - case strings.Contains(serviceType, "openvpn"): - connType := data["connection-type"] - username := data["username"] - if (connType == "password" || connType == "password-tls") && username == "" { - return "openvpn_username" - } - } - return "" -} - -func (b *NetworkManagerBackend) handleOpenVPNUsernameAuth(targetConn gonetworkmanager.Connection, connName, targetUUID, vpnServiceType string) error { - log.Infof("[ConnectVPN] OpenVPN requires username in vpn.data - prompting before activation") - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - token, err := b.promptBroker.Ask(ctx, PromptRequest{ - Name: connName, - ConnType: "vpn", - VpnService: vpnServiceType, - SettingName: "vpn", - Fields: []string{"username", "password"}, - FieldsInfo: []FieldInfo{{Name: "username", Label: "Username", IsSecret: false}, {Name: "password", Label: "Password", IsSecret: true}}, - Reason: "required", - ConnectionId: connName, - ConnectionUuid: targetUUID, - ConnectionPath: string(targetConn.GetPath()), - }) - if err != nil { - return fmt.Errorf("failed to request credentials: %w", err) - } - - reply, err := b.promptBroker.Wait(ctx, token) - if err != nil { - return fmt.Errorf("credentials prompt failed: %w", err) - } - - if reply.Cancel { - return fmt.Errorf("user cancelled authentication") - } - - username := reply.Secrets["username"] - password := reply.Secrets["password"] - if username == "" { - return nil - } - - connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath()) - var existingSettings map[string]map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { - return fmt.Errorf("failed to get settings for username save: %w", err) - } - - settings := make(map[string]map[string]dbus.Variant) - if connSection, ok := existingSettings["connection"]; ok { - settings["connection"] = connSection - } - vpn := existingSettings["vpn"] - var data map[string]string - if dataVariant, ok := vpn["data"]; ok { - if dm, ok := dataVariant.Value().(map[string]string); ok { - data = make(map[string]string) - for k, v := range dm { - data[k] = v - } - } else { - data = make(map[string]string) - } - } else { - data = make(map[string]string) - } - data["username"] = username - - vpn["data"] = dbus.MakeVariant(data) - settings["vpn"] = vpn - - var result map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, - settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil { - return fmt.Errorf("failed to save username: %w", err) - } - log.Infof("[ConnectVPN] Username saved to connection") - - if password != "" { - b.cachedVPNCredsMu.Lock() - b.cachedVPNCreds = &cachedVPNCredentials{ - ConnectionUUID: targetUUID, - Password: password, - SavePassword: reply.Save, - } - b.cachedVPNCredsMu.Unlock() - log.Infof("[ConnectVPN] Cached password for GetSecrets") - } - - return nil -} - -func (b *NetworkManagerBackend) DisconnectVPN(uuidOrName string) error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return fmt.Errorf("failed to get active connections: %w", err) - } - - log.Debugf("[DisconnectVPN] Looking for VPN: %s", uuidOrName) - - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - - if connType != "vpn" && connType != "wireguard" { - continue - } - - uuid, _ := activeConn.GetPropertyUUID() - id, _ := activeConn.GetPropertyID() - state, _ := activeConn.GetPropertyState() - - log.Debugf("[DisconnectVPN] Found active VPN: uuid=%s id=%s state=%d", uuid, id, state) - - if uuid == uuidOrName || id == uuidOrName { - log.Infof("[DisconnectVPN] Deactivating VPN: %s (state=%d)", id, state) - if err := nm.DeactivateConnection(activeConn); err != nil { - return fmt.Errorf("failed to deactivate VPN: %w", err) - } - b.ListActiveVPN() - if b.onStateChange != nil { - b.onStateChange() - } - return nil - } - } - - log.Warnf("[DisconnectVPN] VPN not found in active connections: %s", uuidOrName) - - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("VPN connection not active and cannot access settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("VPN connection not active: %s", uuidOrName) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - - if connUUID == uuidOrName || connID == uuidOrName { - log.Infof("[DisconnectVPN] VPN connection exists but not active: %s", connID) - return nil - } - } - - return fmt.Errorf("VPN connection not found: %s", uuidOrName) -} - -func (b *NetworkManagerBackend) DisconnectAllVPN() error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return fmt.Errorf("failed to get active connections: %w", err) - } - - var lastErr error - var disconnected bool - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - - if connType != "vpn" && connType != "wireguard" { - continue - } - - if err := nm.DeactivateConnection(activeConn); err != nil { - lastErr = err - log.Warnf("Failed to deactivate VPN connection: %v", err) - } else { - disconnected = true - } - } - - if disconnected { - b.ListActiveVPN() - if b.onStateChange != nil { - b.onStateChange() - } - } - - return lastErr -} - -func (b *NetworkManagerBackend) ClearVPNCredentials(uuidOrName string) error { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - - if connUUID == uuidOrName || connID == uuidOrName { - if connType == "vpn" { - if vpnSettings, ok := settings["vpn"]; ok { - delete(vpnSettings, "secrets") - - if dataMap, ok := vpnSettings["data"].(map[string]string); ok { - dataMap["password-flags"] = "1" - vpnSettings["data"] = dataMap - } - } - } - - if err := conn.Update(settings); err != nil { - return fmt.Errorf("failed to update connection: %w", err) - } - - if err := conn.ClearSecrets(); err != nil { - log.Warnf("ClearSecrets call failed (may not be critical): %v", err) - } - - log.Infof("Cleared credentials for VPN: %s", connID) - return nil - } - } - - return fmt.Errorf("VPN connection not found: %s", uuidOrName) -} - -func (b *NetworkManagerBackend) updateVPNConnectionState() { - b.stateMutex.RLock() - isConnectingVPN := b.state.IsConnectingVPN - connectingVPNUUID := b.state.ConnectingVPNUUID - b.stateMutex.RUnlock() - - if !isConnectingVPN || connectingVPNUUID == "" { - return - } - - nm := b.nmConn.(gonetworkmanager.NetworkManager) - activeConns, err := nm.GetPropertyActiveConnections() - if err != nil { - return - } - - foundConnection := false - for _, activeConn := range activeConns { - connType, err := activeConn.GetPropertyType() - if err != nil { - continue - } - - if connType != "vpn" && connType != "wireguard" { - continue - } - - connUUID, err := activeConn.GetPropertyUUID() - if err != nil { - continue - } - - state, _ := activeConn.GetPropertyState() - stateReason, _ := activeConn.GetPropertyStateFlags() - - if connUUID == connectingVPNUUID { - foundConnection = true - - switch state { - case 2: - log.Infof("[updateVPNConnectionState] VPN connection successful: %s", connUUID) - b.stateMutex.Lock() - b.state.IsConnectingVPN = false - b.state.ConnectingVPNUUID = "" - b.state.LastError = "" - b.stateMutex.Unlock() - - // Clear cached PKCS11 PIN and SAML cookie on success - b.cachedPKCS11Mu.Lock() - b.cachedPKCS11PIN = nil - b.cachedPKCS11Mu.Unlock() - b.cachedGPSamlMu.Lock() - b.cachedGPSamlCookie = nil - b.cachedGPSamlMu.Unlock() - - b.pendingVPNSaveMu.Lock() - pending := b.pendingVPNSave - b.pendingVPNSave = nil - b.pendingVPNSaveMu.Unlock() - - if pending != nil { - go b.saveVPNCredentials(pending) - } - return - case 4: - log.Warnf("[updateVPNConnectionState] VPN connection failed/deactivated: %s (state=%d, flags=%d)", connUUID, state, stateReason) - b.stateMutex.Lock() - b.state.IsConnectingVPN = false - b.state.ConnectingVPNUUID = "" - b.state.LastError = "VPN connection failed" - b.stateMutex.Unlock() - - // Clear cached PKCS11 PIN and SAML cookie on failure - b.cachedPKCS11Mu.Lock() - b.cachedPKCS11PIN = nil - b.cachedPKCS11Mu.Unlock() - b.cachedGPSamlMu.Lock() - b.cachedGPSamlCookie = nil - b.cachedGPSamlMu.Unlock() - return - } - } - } - - if !foundConnection { - log.Warnf("[updateVPNConnectionState] VPN connection no longer exists: %s", connectingVPNUUID) - b.stateMutex.Lock() - b.state.IsConnectingVPN = false - b.state.ConnectingVPNUUID = "" - b.state.LastError = "VPN connection failed" - b.stateMutex.Unlock() - - // Clear cached PKCS11 PIN and SAML cookie - b.cachedPKCS11Mu.Lock() - b.cachedPKCS11PIN = nil - b.cachedPKCS11Mu.Unlock() - b.cachedGPSamlMu.Lock() - b.cachedGPSamlCookie = nil - b.cachedGPSamlMu.Unlock() - } -} - -func (b *NetworkManagerBackend) saveVPNCredentials(creds *pendingVPNCredentials) { - log.Infof("[saveVPNCredentials] Saving credentials for %s (username=%v, savePassword=%v)", - creds.ConnectionPath, creds.Username != "", creds.SavePassword) - - connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(creds.ConnectionPath)) - var existingSettings map[string]map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { - log.Warnf("[saveVPNCredentials] GetSettings failed: %v", err) - return - } - - settings := make(map[string]map[string]dbus.Variant) - if connSection, ok := existingSettings["connection"]; ok { - settings["connection"] = connSection - } - - vpn, ok := existingSettings["vpn"] - if !ok { - vpn = make(map[string]dbus.Variant) - } - - // Get existing data map - var data map[string]string - if dataVariant, ok := vpn["data"]; ok { - if dm, ok := dataVariant.Value().(map[string]string); ok { - data = make(map[string]string) - for k, v := range dm { - data[k] = v - } - } else { - data = make(map[string]string) - } - } else { - data = make(map[string]string) - } - - // Always save username if provided - if creds.Username != "" { - data["username"] = creds.Username - log.Infof("[saveVPNCredentials] Saving username") - } - - // Save password if requested - if creds.SavePassword { - data["password-flags"] = "0" - secs := make(map[string]string) - secs["password"] = creds.Password - vpn["secrets"] = dbus.MakeVariant(secs) - log.Infof("[saveVPNCredentials] Saving password with password-flags=0") - } - - vpn["data"] = dbus.MakeVariant(data) - settings["vpn"] = vpn - - var result map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, - settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil { - log.Warnf("[saveVPNCredentials] Update2 failed: %v", err) - } else { - log.Infof("[saveVPNCredentials] Successfully saved credentials") - } -} - -func (b *NetworkManagerBackend) ListVPNPlugins() ([]VPNPlugin, error) { - plugins := []VPNPlugin{} - pluginDirs := []string{ - "/usr/lib/NetworkManager/VPN", - "/usr/lib64/NetworkManager/VPN", - "/etc/NetworkManager/VPN", - } - - seen := make(map[string]bool) - - for _, dir := range pluginDirs { - entries, err := os.ReadDir(dir) - if err != nil { - continue - } - - for _, entry := range entries { - if !strings.HasSuffix(entry.Name(), ".name") { - continue - } - - filePath := filepath.Join(dir, entry.Name()) - plugin, err := parseVPNPluginFile(filePath) - if err != nil { - log.Debugf("Failed to parse VPN plugin file %s: %v", filePath, err) - continue - } - - if seen[plugin.ServiceType] { - continue - } - seen[plugin.ServiceType] = true - plugins = append(plugins, *plugin) - } - } - - sort.Slice(plugins, func(i, j int) bool { - return strings.ToLower(plugins[i].Name) < strings.ToLower(plugins[j].Name) - }) - - return plugins, nil -} - -func parseVPNPluginFile(path string) (*VPNPlugin, error) { - file, err := os.Open(path) - if err != nil { - return nil, err - } - defer file.Close() - - plugin := &VPNPlugin{} - scanner := bufio.NewScanner(file) - - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "[") { - continue - } - - parts := strings.SplitN(line, "=", 2) - if len(parts) != 2 { - continue - } - - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - - switch key { - case "name": - plugin.Name = value - case "service": - plugin.ServiceType = value - case "program": - plugin.Program = value - case "supports": - plugin.Supports = strings.Split(value, ",") - for i := range plugin.Supports { - plugin.Supports[i] = strings.TrimSpace(plugin.Supports[i]) - } - } - } - - if plugin.ServiceType == "" { - return nil, fmt.Errorf("plugin file missing service type") - } - - plugin.FileExtensions = getVPNFileExtensions(plugin.ServiceType) - - return plugin, nil -} - -func getVPNFileExtensions(serviceType string) []string { - switch { - case strings.Contains(serviceType, "openvpn"): - return []string{".ovpn", ".conf"} - case strings.Contains(serviceType, "wireguard"): - return []string{".conf"} - case strings.Contains(serviceType, "vpnc"), strings.Contains(serviceType, "cisco"): - return []string{".pcf", ".conf"} - case strings.Contains(serviceType, "openconnect"): - return []string{".conf"} - case strings.Contains(serviceType, "pptp"): - return []string{".conf"} - case strings.Contains(serviceType, "l2tp"): - return []string{".conf"} - case strings.Contains(serviceType, "strongswan"), strings.Contains(serviceType, "ipsec"): - return []string{".conf", ".sswan"} - default: - return []string{".conf"} - } -} - -func (b *NetworkManagerBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { - if _, err := os.Stat(filePath); os.IsNotExist(err) { - return &VPNImportResult{ - Success: false, - Error: fmt.Sprintf("file not found: %s", filePath), - }, nil - } - - ext := strings.ToLower(filepath.Ext(filePath)) - - switch ext { - case ".ovpn", ".conf": - return b.importVPNWithNmcli(filePath, name) - default: - return b.importVPNWithNmcli(filePath, name) - } -} - -func (b *NetworkManagerBackend) importVPNWithNmcli(filePath string, name string) (*VPNImportResult, error) { - vpnTypes := []string{"openvpn", "wireguard", "vpnc", "pptp", "l2tp", "openconnect", "strongswan"} - - var allErrors []error - var outputStr string - for _, vpnType := range vpnTypes { - cmd := exec.Command("nmcli", "connection", "import", "type", vpnType, "file", filePath) - output, err := cmd.CombinedOutput() - if err == nil { - outputStr = string(output) - break - } - allErrors = append(allErrors, fmt.Errorf("%s: %s", vpnType, strings.TrimSpace(string(output)))) - } - - if len(allErrors) == len(vpnTypes) { - return &VPNImportResult{ - Success: false, - Error: errors.Join(allErrors...).Error(), - }, nil - } - var connUUID, connName string - - lines := strings.Split(outputStr, "\n") - for _, line := range lines { - if strings.Contains(line, "successfully added") { - parts := strings.Fields(line) - for i, part := range parts { - if part == "(" && i+1 < len(parts) { - connUUID = strings.TrimSuffix(parts[i+1], ")") - break - } - } - } - } - - if name != "" && connUUID != "" { - renameCmd := exec.Command("nmcli", "connection", "modify", connUUID, "connection.id", name) - if err := renameCmd.Run(); err != nil { - log.Warnf("Failed to rename imported VPN: %v", err) - } else { - connName = name - } - } - - if connUUID == "" { - s := b.settings - if s == nil { - var settingsErr error - s, settingsErr = gonetworkmanager.NewSettings() - if settingsErr == nil { - b.settings = s - } - } - - if s != nil { - settingsMgr := s.(gonetworkmanager.Settings) - connections, _ := settingsMgr.ListConnections() - baseName := strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath)) - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - connMeta, ok := settings["connection"] - if !ok { - continue - } - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - connID, _ := connMeta["id"].(string) - if strings.Contains(connID, baseName) || (name != "" && connID == name) { - connUUID, _ = connMeta["uuid"].(string) - connName = connID - break - } - } - } - } - - b.ListVPNProfiles() - - if b.onStateChange != nil { - b.onStateChange() - } - - return &VPNImportResult{ - Success: true, - UUID: connUUID, - Name: connName, - }, nil -} - -func (b *NetworkManagerBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return nil, fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return nil, fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - - if connUUID != uuidOrName && connID != uuidOrName { - continue - } - - autoconnect := true - if ac, ok := connMeta["autoconnect"].(bool); ok { - autoconnect = ac - } - - config := &VPNConfig{ - UUID: connUUID, - Name: connID, - Type: connType, - Autoconnect: autoconnect, - Data: make(map[string]string), - } - - if connType == "vpn" { - if vpnSettings, ok := settings["vpn"]; ok { - if svcType, ok := vpnSettings["service-type"].(string); ok { - config.ServiceType = svcType - } - if dataMap, ok := vpnSettings["data"].(map[string]string); ok { - for k, v := range dataMap { - if !strings.Contains(strings.ToLower(k), "password") && - !strings.Contains(strings.ToLower(k), "secret") && - !strings.Contains(strings.ToLower(k), "key") { - config.Data[k] = v - } - } - } - } - } - - return config, nil - } - - return nil, fmt.Errorf("VPN connection not found: %s", uuidOrName) -} - -func (b *NetworkManagerBackend) UpdateVPNConfig(connUUID string, updates map[string]any) error { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - existingUUID, _ := connMeta["uuid"].(string) - if existingUUID != connUUID { - continue - } - - if name, ok := updates["name"].(string); ok && name != "" { - connMeta["id"] = name - } - - if autoconnect, ok := updates["autoconnect"].(bool); ok { - connMeta["autoconnect"] = autoconnect - } - - if data, ok := updates["data"].(map[string]any); ok { - if vpnSettings, ok := settings["vpn"]; ok { - existingData, _ := vpnSettings["data"].(map[string]string) - if existingData == nil { - existingData = make(map[string]string) - } - for k, v := range data { - if strVal, ok := v.(string); ok { - existingData[k] = strVal - } - } - vpnSettings["data"] = existingData - } - } - - if ipv4, ok := settings["ipv4"]; ok { - delete(ipv4, "addresses") - delete(ipv4, "routes") - delete(ipv4, "dns") - } - if ipv6, ok := settings["ipv6"]; ok { - delete(ipv6, "addresses") - delete(ipv6, "routes") - delete(ipv6, "dns") - } - - if err := conn.Update(settings); err != nil { - return fmt.Errorf("failed to update connection: %w", err) - } - - b.ListVPNProfiles() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil - } - - return fmt.Errorf("VPN connection not found: %s", connUUID) -} - -func (b *NetworkManagerBackend) SetVPNCredentials(connUUID string, username string, password string, saveToKeyring bool) error { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - existingUUID, _ := connMeta["uuid"].(string) - if existingUUID != connUUID { - continue - } - - vpnSettings, ok := settings["vpn"] - if !ok { - vpnSettings = make(map[string]any) - settings["vpn"] = vpnSettings - } - - existingData, _ := vpnSettings["data"].(map[string]string) - if existingData == nil { - existingData = make(map[string]string) - } - - if username != "" { - existingData["username"] = username - } - - if saveToKeyring { - existingData["password-flags"] = "0" - } else { - existingData["password-flags"] = "2" - } - - vpnSettings["data"] = existingData - - if password != "" { - secrets := make(map[string]string) - secrets["password"] = password - vpnSettings["secrets"] = secrets - } - - if ipv4, ok := settings["ipv4"]; ok { - delete(ipv4, "addresses") - delete(ipv4, "routes") - delete(ipv4, "dns") - } - if ipv6, ok := settings["ipv6"]; ok { - delete(ipv6, "addresses") - delete(ipv6, "routes") - delete(ipv6, "dns") - } - - if err := conn.Update(settings); err != nil { - return fmt.Errorf("failed to update connection: %w", err) - } - - log.Infof("Updated VPN credentials for %s (save=%v)", connUUID, saveToKeyring) - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil - } - - return fmt.Errorf("VPN connection not found: %s", connUUID) -} - -func (b *NetworkManagerBackend) DeleteVPN(uuidOrName string) error { - active, _ := b.ListActiveVPN() - for _, vpn := range active { - if vpn.UUID == uuidOrName || vpn.Name == uuidOrName { - if err := b.DisconnectVPN(uuidOrName); err != nil { - log.Warnf("Failed to disconnect VPN before deletion: %v", err) - } - time.Sleep(200 * time.Millisecond) - break - } - } - - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return fmt.Errorf("failed to get connections: %w", err) - } - - for _, conn := range connections { - settings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := settings["connection"] - if !ok { - continue - } - - connType, _ := connMeta["type"].(string) - if connType != "vpn" && connType != "wireguard" { - continue - } - - connID, _ := connMeta["id"].(string) - connUUID, _ := connMeta["uuid"].(string) - - if connUUID == uuidOrName || connID == uuidOrName { - if err := conn.Delete(); err != nil { - return fmt.Errorf("failed to delete VPN: %w", err) - } - - b.ListVPNProfiles() - - if b.onStateChange != nil { - b.onStateChange() - } - - log.Infof("Deleted VPN connection: %s (%s)", connID, connUUID) - return nil - } - } - - return fmt.Errorf("VPN connection not found: %s", uuidOrName) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn_test.go deleted file mode 100644 index eebd433..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_vpn_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package network - -import ( - "testing" - - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/Wifx/gonetworkmanager/v2" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_ListVPNProfiles(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockSettings := mock_gonetworkmanager.NewMockSettings(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - backend.settings = mockSettings - - mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil) - - profiles, err := backend.ListVPNProfiles() - assert.NoError(t, err) - assert.Empty(t, profiles) -} - -func TestNetworkManagerBackend_ListActiveVPN(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - - active, err := backend.ListActiveVPN() - assert.NoError(t, err) - assert.Empty(t, active) -} - -func TestNetworkManagerBackend_ConnectVPN_NotFound(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockSettings := mock_gonetworkmanager.NewMockSettings(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - backend.settings = mockSettings - - mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil) - - err = backend.ConnectVPN("non-existent-vpn-12345", false) - assert.Error(t, err) - assert.Contains(t, err.Error(), "not found") -} - -func TestNetworkManagerBackend_ConnectVPN_SingleActive_NoActiveVPN(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockSettings := mock_gonetworkmanager.NewMockSettings(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - backend.settings = mockSettings - - mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil) - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - - err = backend.ConnectVPN("non-existent-vpn-12345", true) - assert.Error(t, err) -} - -func TestNetworkManagerBackend_DisconnectVPN_NotActive(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - - err = backend.DisconnectVPN("non-existent-vpn-12345") - assert.Error(t, err) -} - -func TestNetworkManagerBackend_DisconnectAllVPN(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) - - err = backend.DisconnectAllVPN() - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_ClearVPNCredentials_NotFound(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockSettings := mock_gonetworkmanager.NewMockSettings(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - backend.settings = mockSettings - - mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil) - - err = backend.ClearVPNCredentials("non-existent-vpn-12345") - assert.Error(t, err) - assert.Contains(t, err.Error(), "not found") -} - -func TestNetworkManagerBackend_UpdateVPNConnectionState_NotConnecting(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.stateMutex.Lock() - backend.state.IsConnectingVPN = false - backend.state.ConnectingVPNUUID = "" - backend.stateMutex.Unlock() - - assert.NotPanics(t, func() { - backend.updateVPNConnectionState() - }) -} - -func TestNetworkManagerBackend_UpdateVPNConnectionState_EmptyUUID(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.stateMutex.Lock() - backend.state.IsConnectingVPN = true - backend.state.ConnectingVPNUUID = "" - backend.stateMutex.Unlock() - - assert.NotPanics(t, func() { - backend.updateVPNConnectionState() - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi.go deleted file mode 100644 index 6f593b1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi.go +++ /dev/null @@ -1,1173 +0,0 @@ -package network - -import ( - "bytes" - "fmt" - "sort" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/Wifx/gonetworkmanager/v2" -) - -func (b *NetworkManagerBackend) GetWiFiEnabled() (bool, error) { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - return nm.GetPropertyWirelessEnabled() -} - -func (b *NetworkManagerBackend) SetWiFiEnabled(enabled bool) error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - err := nm.SetPropertyWirelessEnabled(enabled) - if err != nil { - return fmt.Errorf("failed to set WiFi enabled: %w", err) - } - - b.stateMutex.Lock() - b.state.WiFiEnabled = enabled - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) ScanWiFi() error { - if b.wifiDevice == nil { - return fmt.Errorf("no WiFi device available") - } - - b.stateMutex.RLock() - enabled := b.state.WiFiEnabled - b.stateMutex.RUnlock() - - if !enabled { - return fmt.Errorf("WiFi is disabled") - } - - if err := b.ensureWiFiDevice(); err != nil { - return err - } - - w := b.wifiDev.(gonetworkmanager.DeviceWireless) - err := w.RequestScan() - if err != nil { - return fmt.Errorf("scan request failed: %w", err) - } - - _, err = b.updateWiFiNetworks() - return err -} - -func (b *NetworkManagerBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) { - if b.wifiDevice == nil { - return nil, fmt.Errorf("no WiFi device available") - } - - if err := b.ensureWiFiDevice(); err != nil { - return nil, err - } - wifiDev := b.wifiDev - - w := wifiDev.(gonetworkmanager.DeviceWireless) - apPaths, err := w.GetAccessPoints() - if err != nil { - return nil, fmt.Errorf("failed to get access points: %w", err) - } - - s := b.settings - if s == nil { - s, err = gonetworkmanager.NewSettings() - if err != nil { - return nil, fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return nil, fmt.Errorf("failed to get connections: %w", err) - } - - savedSSIDs := make(map[string]bool) - autoconnectMap := make(map[string]bool) - for _, conn := range connections { - connSettings, err := conn.GetSettings() - if err != nil { - continue - } - - if connMeta, ok := connSettings["connection"]; ok { - if connType, ok := connMeta["type"].(string); ok && connType == "802-11-wireless" { - if wifiSettings, ok := connSettings["802-11-wireless"]; ok { - if ssidBytes, ok := wifiSettings["ssid"].([]byte); ok { - savedSSID := string(ssidBytes) - savedSSIDs[savedSSID] = true - autoconnect := true - if ac, ok := connMeta["autoconnect"].(bool); ok { - autoconnect = ac - } - autoconnectMap[savedSSID] = autoconnect - } - } - } - } - } - - b.stateMutex.RLock() - currentSSID := b.state.WiFiSSID - currentBSSID := b.state.WiFiBSSID - b.stateMutex.RUnlock() - - var bands []WiFiNetwork - - for _, ap := range apPaths { - apSSID, err := ap.GetPropertySSID() - if err != nil || apSSID != ssid { - continue - } - - strength, _ := ap.GetPropertyStrength() - flags, _ := ap.GetPropertyFlags() - wpaFlags, _ := ap.GetPropertyWPAFlags() - rsnFlags, _ := ap.GetPropertyRSNFlags() - freq, _ := ap.GetPropertyFrequency() - maxBitrate, _ := ap.GetPropertyMaxBitrate() - bssid, _ := ap.GetPropertyHWAddress() - mode, _ := ap.GetPropertyMode() - - secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) || - wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) || - rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone) - - enterprise := (rsnFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) || - (wpaFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) - - var modeStr string - switch mode { - case gonetworkmanager.Nm80211ModeAdhoc: - modeStr = "adhoc" - case gonetworkmanager.Nm80211ModeInfra: - modeStr = "infrastructure" - case gonetworkmanager.Nm80211ModeAp: - modeStr = "ap" - default: - modeStr = "unknown" - } - - channel := frequencyToChannel(freq) - - isConnected := ssid == currentSSID && bssid == currentBSSID - rate := maxBitrate / 1000 - if isConnected { - if devBitrate, err := w.GetPropertyBitrate(); err == nil && devBitrate > 0 { - rate = devBitrate / 1000 - } - } - - network := WiFiNetwork{ - SSID: ssid, - BSSID: bssid, - Signal: strength, - Secured: secured, - Enterprise: enterprise, - Connected: isConnected, - Saved: savedSSIDs[ssid], - Autoconnect: autoconnectMap[ssid], - Frequency: freq, - Mode: modeStr, - Rate: rate, - Channel: channel, - } - - bands = append(bands, network) - } - - if len(bands) == 0 { - return nil, fmt.Errorf("network not found: %s", ssid) - } - - sort.Slice(bands, func(i, j int) bool { - if bands[i].Connected && !bands[j].Connected { - return true - } - if !bands[i].Connected && bands[j].Connected { - return false - } - return bands[i].Signal > bands[j].Signal - }) - - return &NetworkInfoResponse{ - SSID: ssid, - Bands: bands, - }, nil -} - -func (b *NetworkManagerBackend) GetWiFiQRCodeContent(ssid string) (string, error) { - conn, err := b.findConnection(ssid) - if err != nil { - return "", fmt.Errorf("no saved connection for `%s`: %w", ssid, err) - } - - connSettings, err := conn.GetSettings() - if err != nil { - return "", fmt.Errorf("failed to get settings for `%s`: %w", ssid, err) - } - - secSettings, ok := connSettings["802-11-wireless-security"] - if !ok { - return "", fmt.Errorf("network `%s` has no security settings", ssid) - } - - keyMgmt, ok := secSettings["key-mgmt"].(string) - if !ok { - return "", fmt.Errorf("failed to identify security type of network `%s`", ssid) - } - - var securityType string - switch keyMgmt { - case "none": - authAlg, _ := secSettings["auth-alg"].(string) - switch authAlg { - case "open": - securityType = "nopass" - default: - securityType = "WEP" - } - case "ieee8021x": - securityType = "WEP" - default: - securityType = "WPA" - } - - if securityType != "WPA" { - return "", fmt.Errorf("QR code generation only supports WPA connections, `%s` uses %s", ssid, securityType) - } - - secrets, err := conn.GetSecrets("802-11-wireless-security") - if err != nil { - return "", fmt.Errorf("failed to retrieve connection secrets for `%s`: %w", ssid, err) - } - - secSecrets, ok := secrets["802-11-wireless-security"] - if !ok { - return "", fmt.Errorf("failed to retrieve password for `%s`", ssid) - } - - psk, ok := secSecrets["psk"].(string) - if !ok { - return "", fmt.Errorf("failed to retrieve password for `%s`", ssid) - } - - return FormatWiFiQRString(securityType, ssid, psk), nil -} - -func (b *NetworkManagerBackend) ConnectWiFi(req ConnectionRequest) error { - devInfo, err := b.getWifiDeviceForConnection(req.Device) - if err != nil { - return err - } - - b.stateMutex.RLock() - alreadyConnected := b.state.WiFiConnected && b.state.WiFiSSID == req.SSID - b.stateMutex.RUnlock() - - if alreadyConnected && !req.Interactive && req.Device == "" { - return nil - } - - b.stateMutex.Lock() - b.state.IsConnecting = true - b.state.ConnectingSSID = req.SSID - b.state.ConnectingDevice = req.Device - b.state.LastError = "" - b.stateMutex.Unlock() - - if b.onStateChange != nil { - b.onStateChange() - } - - nm := b.nmConn.(gonetworkmanager.NetworkManager) - - existingConn, err := b.findConnection(req.SSID) - if err == nil && existingConn != nil { - _, err := nm.ActivateConnection(existingConn, devInfo.device, nil) - if err != nil { - log.Warnf("[ConnectWiFi] Failed to activate existing connection: %v", err) - b.stateMutex.Lock() - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.ConnectingDevice = "" - b.state.LastError = fmt.Sprintf("failed to activate connection: %v", err) - b.stateMutex.Unlock() - if b.onStateChange != nil { - b.onStateChange() - } - return fmt.Errorf("failed to activate connection: %w", err) - } - - return nil - } - - if err := b.createAndConnectWiFiOnDevice(req, devInfo); err != nil { - log.Warnf("[ConnectWiFi] Failed to create and connect: %v", err) - b.stateMutex.Lock() - b.state.IsConnecting = false - b.state.ConnectingSSID = "" - b.state.ConnectingDevice = "" - b.state.LastError = err.Error() - b.stateMutex.Unlock() - if b.onStateChange != nil { - b.onStateChange() - } - return err - } - - return nil -} - -func (b *NetworkManagerBackend) DisconnectWiFi() error { - if b.wifiDevice == nil { - return fmt.Errorf("no WiFi device available") - } - - dev := b.wifiDevice.(gonetworkmanager.Device) - - err := dev.Disconnect() - if err != nil { - return fmt.Errorf("failed to disconnect: %w", err) - } - - b.updateWiFiState() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) ForgetWiFiNetwork(ssid string) error { - conn, err := b.findConnection(ssid) - if err != nil { - return fmt.Errorf("connection not found: %w", err) - } - - b.stateMutex.RLock() - currentSSID := b.state.WiFiSSID - isConnected := b.state.WiFiConnected - b.stateMutex.RUnlock() - - err = conn.Delete() - if err != nil { - return fmt.Errorf("failed to delete connection: %w", err) - } - - if isConnected && currentSSID == ssid { - b.stateMutex.Lock() - b.state.WiFiConnected = false - b.state.WiFiSSID = "" - b.state.WiFiBSSID = "" - b.state.WiFiSignal = 0 - b.state.WiFiIP = "" - b.state.NetworkStatus = StatusDisconnected - b.stateMutex.Unlock() - } - - b.updateWiFiNetworks() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) IsConnectingTo(ssid string) bool { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return b.state.IsConnecting && b.state.ConnectingSSID == ssid -} - -func (b *NetworkManagerBackend) updateWiFiNetworks() ([]WiFiNetwork, error) { - if b.wifiDevice == nil { - return nil, fmt.Errorf("no WiFi device available") - } - - if err := b.ensureWiFiDevice(); err != nil { - return nil, err - } - wifiDev := b.wifiDev - - w := wifiDev.(gonetworkmanager.DeviceWireless) - apPaths, err := w.GetAccessPoints() - if err != nil { - return nil, fmt.Errorf("failed to get access points: %w", err) - } - - s := b.settings - if s == nil { - s, err = gonetworkmanager.NewSettings() - if err != nil { - return nil, fmt.Errorf("failed to get settings: %w", err) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return nil, fmt.Errorf("failed to get connections: %w", err) - } - - savedSSIDs := make(map[string]bool) - autoconnectMap := make(map[string]bool) - hiddenSSIDs := make(map[string]bool) - for _, conn := range connections { - connSettings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := connSettings["connection"] - if !ok { - continue - } - - connType, ok := connMeta["type"].(string) - if !ok || connType != "802-11-wireless" { - continue - } - - wifiSettings, ok := connSettings["802-11-wireless"] - if !ok { - continue - } - - ssidBytes, ok := wifiSettings["ssid"].([]byte) - if !ok { - continue - } - - ssid := string(ssidBytes) - savedSSIDs[ssid] = true - autoconnect := true - if ac, ok := connMeta["autoconnect"].(bool); ok { - autoconnect = ac - } - autoconnectMap[ssid] = autoconnect - - if hidden, ok := wifiSettings["hidden"].(bool); ok && hidden { - hiddenSSIDs[ssid] = true - } - } - - b.stateMutex.RLock() - currentSSID := b.state.WiFiSSID - wifiConnected := b.state.WiFiConnected - wifiSignal := b.state.WiFiSignal - wifiBSSID := b.state.WiFiBSSID - b.stateMutex.RUnlock() - - seenSSIDs := make(map[string]*WiFiNetwork) - networks := []WiFiNetwork{} - - for _, ap := range apPaths { - ssid, err := ap.GetPropertySSID() - if err != nil || ssid == "" { - continue - } - - if existing, exists := seenSSIDs[ssid]; exists { - strength, _ := ap.GetPropertyStrength() - if strength > existing.Signal { - existing.Signal = strength - freq, _ := ap.GetPropertyFrequency() - existing.Frequency = freq - bssid, _ := ap.GetPropertyHWAddress() - existing.BSSID = bssid - } - continue - } - - strength, _ := ap.GetPropertyStrength() - flags, _ := ap.GetPropertyFlags() - wpaFlags, _ := ap.GetPropertyWPAFlags() - rsnFlags, _ := ap.GetPropertyRSNFlags() - freq, _ := ap.GetPropertyFrequency() - maxBitrate, _ := ap.GetPropertyMaxBitrate() - bssid, _ := ap.GetPropertyHWAddress() - mode, _ := ap.GetPropertyMode() - - secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) || - wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) || - rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone) - - enterprise := (rsnFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) || - (wpaFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) - - var modeStr string - switch mode { - case gonetworkmanager.Nm80211ModeAdhoc: - modeStr = "adhoc" - case gonetworkmanager.Nm80211ModeInfra: - modeStr = "infrastructure" - case gonetworkmanager.Nm80211ModeAp: - modeStr = "ap" - default: - modeStr = "unknown" - } - - channel := frequencyToChannel(freq) - - isConnected := ssid == currentSSID - rate := maxBitrate / 1000 - if isConnected { - if devBitrate, err := w.GetPropertyBitrate(); err == nil && devBitrate > 0 { - rate = devBitrate / 1000 - } - } - - network := WiFiNetwork{ - SSID: ssid, - BSSID: bssid, - Signal: strength, - Secured: secured, - Enterprise: enterprise, - Connected: isConnected, - Saved: savedSSIDs[ssid], - Autoconnect: autoconnectMap[ssid], - Hidden: hiddenSSIDs[ssid], - Frequency: freq, - Mode: modeStr, - Rate: rate, - Channel: channel, - } - - seenSSIDs[ssid] = &network - networks = append(networks, network) - } - - if wifiConnected && currentSSID != "" { - if _, exists := seenSSIDs[currentSSID]; !exists { - hiddenNetwork := WiFiNetwork{ - SSID: currentSSID, - BSSID: wifiBSSID, - Signal: wifiSignal, - Secured: true, - Connected: true, - Saved: savedSSIDs[currentSSID], - Autoconnect: autoconnectMap[currentSSID], - Hidden: true, - Mode: "infrastructure", - } - networks = append(networks, hiddenNetwork) - } - } - - sortWiFiNetworks(networks) - - b.stateMutex.Lock() - b.state.WiFiNetworks = networks - b.stateMutex.Unlock() - - return networks, nil -} - -func (b *NetworkManagerBackend) findConnection(ssid string) (gonetworkmanager.Connection, error) { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return nil, err - } - b.settings = s - } - - settings := s.(gonetworkmanager.Settings) - connections, err := settings.ListConnections() - if err != nil { - return nil, err - } - - ssidBytes := []byte(ssid) - for _, conn := range connections { - connSettings, err := conn.GetSettings() - if err != nil { - continue - } - - if connMeta, ok := connSettings["connection"]; ok { - if connType, ok := connMeta["type"].(string); ok && connType == "802-11-wireless" { - if wifiSettings, ok := connSettings["802-11-wireless"]; ok { - if candidateSSID, ok := wifiSettings["ssid"].([]byte); ok { - if bytes.Equal(candidateSSID, ssidBytes) { - return conn, nil - } - } - } - } - } - } - - return nil, fmt.Errorf("connection not found") -} - -func (b *NetworkManagerBackend) createAndConnectWiFi(req ConnectionRequest) error { - devInfo, err := b.getWifiDeviceForConnection(req.Device) - if err != nil { - return err - } - return b.createAndConnectWiFiOnDevice(req, devInfo) -} - -func (b *NetworkManagerBackend) createAndConnectWiFiOnDevice(req ConnectionRequest, devInfo *wifiDeviceInfo) error { - nm := b.nmConn.(gonetworkmanager.NetworkManager) - dev := devInfo.device - w := devInfo.wireless - - var targetAP gonetworkmanager.AccessPoint - var flags, wpaFlags, rsnFlags uint32 - - if !req.Hidden { - apPaths, err := w.GetAccessPoints() - if err != nil { - return fmt.Errorf("failed to get access points: %w", err) - } - - for _, ap := range apPaths { - ssid, err := ap.GetPropertySSID() - if err != nil || ssid != req.SSID { - continue - } - targetAP = ap - break - } - - if targetAP == nil { - return fmt.Errorf("access point not found: %s", req.SSID) - } - - flags, _ = targetAP.GetPropertyFlags() - wpaFlags, _ = targetAP.GetPropertyWPAFlags() - rsnFlags, _ = targetAP.GetPropertyRSNFlags() - } - - const KeyMgmt8021x = uint32(512) - const KeyMgmtPsk = uint32(256) - const KeyMgmtSae = uint32(1024) - - var isEnterprise, isPsk, isSae, secured bool - - switch { - case req.Hidden: - secured = req.Password != "" || req.Username != "" - isEnterprise = req.Username != "" - isPsk = req.Password != "" && !isEnterprise - default: - isEnterprise = (wpaFlags&KeyMgmt8021x) != 0 || (rsnFlags&KeyMgmt8021x) != 0 - isPsk = (wpaFlags&KeyMgmtPsk) != 0 || (rsnFlags&KeyMgmtPsk) != 0 - isSae = (wpaFlags&KeyMgmtSae) != 0 || (rsnFlags&KeyMgmtSae) != 0 - secured = flags != uint32(gonetworkmanager.Nm80211APFlagsNone) || - wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) || - rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone) - } - - if isEnterprise { - log.Infof("[createAndConnectWiFi] Enterprise network detected (802.1x) - SSID: %s, interactive: %v", - req.SSID, req.Interactive) - } - - settings := make(map[string]map[string]any) - - settings["connection"] = map[string]any{ - "id": req.SSID, - "type": "802-11-wireless", - "autoconnect": true, - } - - settings["ipv4"] = map[string]any{"method": "auto"} - settings["ipv6"] = map[string]any{"method": "auto"} - - if secured { - wifiSettings := map[string]any{ - "ssid": []byte(req.SSID), - "mode": "infrastructure", - "security": "802-11-wireless-security", - } - if req.Hidden { - wifiSettings["hidden"] = true - } - settings["802-11-wireless"] = wifiSettings - - switch { - case isEnterprise || req.Username != "": - settings["802-11-wireless-security"] = map[string]any{ - "key-mgmt": "wpa-eap", - } - - eapMethod := "peap" - if req.EAPMethod != "" { - eapMethod = req.EAPMethod - } - - phase2Auth := "mschapv2" - if req.Phase2Auth != "" { - phase2Auth = req.Phase2Auth - } - - useSystemCACerts := false - if req.UseSystemCACerts != nil { - useSystemCACerts = *req.UseSystemCACerts - } - - x := map[string]any{ - "eap": []string{eapMethod}, - "system-ca-certs": useSystemCACerts, - "password-flags": uint32(0), - } - - switch eapMethod { - case "peap", "ttls": - x["phase2-auth"] = phase2Auth - case "tls": - if req.ClientCertPath != "" { - x["client-cert"] = []byte("file://" + req.ClientCertPath) - } - if req.PrivateKeyPath != "" { - x["private-key"] = []byte("file://" + req.PrivateKeyPath) - } - } - - if req.Username != "" { - x["identity"] = req.Username - } - if req.Password != "" { - x["password"] = req.Password - } - if req.AnonymousIdentity != "" { - x["anonymous-identity"] = req.AnonymousIdentity - } - if req.DomainSuffixMatch != "" { - x["domain-suffix-match"] = req.DomainSuffixMatch - } - if req.CACertPath != "" { - x["ca-cert"] = []byte("file://" + req.CACertPath) - } - - settings["802-1x"] = x - - log.Infof("[createAndConnectWiFi] WPA-EAP settings: eap=%s, phase2-auth=%s, identity=%s, interactive=%v, system-ca-certs=%v, domain-suffix-match=%q", - eapMethod, phase2Auth, req.Username, req.Interactive, useSystemCACerts, req.DomainSuffixMatch) - - case isPsk: - sec := map[string]any{ - "key-mgmt": "wpa-psk", - "psk-flags": uint32(0), - } - if !req.Interactive { - sec["psk"] = req.Password - } - settings["802-11-wireless-security"] = sec - - case isSae: - sec := map[string]any{ - "key-mgmt": "sae", - "pmf": int32(3), - "psk-flags": uint32(0), - } - if !req.Interactive { - sec["psk"] = req.Password - } - settings["802-11-wireless-security"] = sec - - default: - return fmt.Errorf("secured network but not SAE/PSK/802.1X (rsn=0x%x wpa=0x%x)", rsnFlags, wpaFlags) - } - } else { - wifiSettings := map[string]any{ - "ssid": []byte(req.SSID), - "mode": "infrastructure", - } - if req.Hidden { - wifiSettings["hidden"] = true - } - settings["802-11-wireless"] = wifiSettings - } - - if req.Interactive { - s := b.settings - if s == nil { - var settingsErr error - s, settingsErr = gonetworkmanager.NewSettings() - if settingsErr != nil { - return fmt.Errorf("failed to get settings manager: %w", settingsErr) - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - conn, err := settingsMgr.AddConnection(settings) - if err != nil { - return fmt.Errorf("failed to add connection: %w", err) - } - - if isEnterprise { - log.Infof("[createAndConnectWiFi] Enterprise connection added, activating (secret agent will be called)") - } - - if req.Hidden { - _, err = nm.ActivateConnection(conn, dev, nil) - } else { - _, err = nm.ActivateWirelessConnection(conn, dev, targetAP) - } - if err != nil { - return fmt.Errorf("failed to activate connection: %w", err) - } - - log.Infof("[createAndConnectWiFi] Connection activation initiated, waiting for NetworkManager state changes...") - } else { - var err error - if req.Hidden { - _, err = nm.AddAndActivateConnection(settings, dev) - } else { - _, err = nm.AddAndActivateWirelessConnection(settings, dev, targetAP) - } - if err != nil { - return fmt.Errorf("failed to connect: %w", err) - } - log.Infof("[createAndConnectWiFi] Connection activation initiated, waiting for NetworkManager state changes...") - } - - return nil -} - -func (b *NetworkManagerBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - conn, err := b.findConnection(ssid) - if err != nil { - return fmt.Errorf("connection not found: %w", err) - } - - settings, err := conn.GetSettings() - if err != nil { - return fmt.Errorf("failed to get connection settings: %w", err) - } - - if connMeta, ok := settings["connection"]; ok { - connMeta["autoconnect"] = autoconnect - } else { - return fmt.Errorf("connection metadata not found") - } - - if ipv4, ok := settings["ipv4"]; ok { - delete(ipv4, "addresses") - delete(ipv4, "routes") - delete(ipv4, "dns") - } - - if ipv6, ok := settings["ipv6"]; ok { - delete(ipv6, "addresses") - delete(ipv6, "routes") - delete(ipv6, "dns") - } - - err = conn.Update(settings) - if err != nil { - return fmt.Errorf("failed to update connection: %w", err) - } - - b.updateWiFiNetworks() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) ScanWiFiDevice(device string) error { - devInfo, ok := b.wifiDevices[device] - if !ok { - return fmt.Errorf("WiFi device not found: %s", device) - } - - b.stateMutex.RLock() - enabled := b.state.WiFiEnabled - b.stateMutex.RUnlock() - - if !enabled { - return fmt.Errorf("WiFi is disabled") - } - - if err := devInfo.wireless.RequestScan(); err != nil { - return fmt.Errorf("scan request failed: %w", err) - } - - b.updateAllWiFiDevices() - return nil -} - -func (b *NetworkManagerBackend) DisconnectWiFiDevice(device string) error { - devInfo, ok := b.wifiDevices[device] - if !ok { - return fmt.Errorf("WiFi device not found: %s", device) - } - - if err := devInfo.device.Disconnect(); err != nil { - return fmt.Errorf("failed to disconnect: %w", err) - } - - b.updateWiFiState() - b.updateAllWiFiDevices() - b.updatePrimaryConnection() - - if b.onStateChange != nil { - b.onStateChange() - } - - return nil -} - -func (b *NetworkManagerBackend) GetWiFiDevices() []WiFiDevice { - b.stateMutex.RLock() - defer b.stateMutex.RUnlock() - return append([]WiFiDevice(nil), b.state.WiFiDevices...) -} - -func (b *NetworkManagerBackend) updateAllWiFiDevices() { - s := b.settings - if s == nil { - var err error - s, err = gonetworkmanager.NewSettings() - if err != nil { - return - } - b.settings = s - } - - settingsMgr := s.(gonetworkmanager.Settings) - connections, err := settingsMgr.ListConnections() - if err != nil { - return - } - - savedSSIDs := make(map[string]bool) - autoconnectMap := make(map[string]bool) - hiddenSSIDs := make(map[string]bool) - for _, conn := range connections { - connSettings, err := conn.GetSettings() - if err != nil { - continue - } - - connMeta, ok := connSettings["connection"] - if !ok { - continue - } - - connType, ok := connMeta["type"].(string) - if !ok || connType != "802-11-wireless" { - continue - } - - wifiSettings, ok := connSettings["802-11-wireless"] - if !ok { - continue - } - - ssidBytes, ok := wifiSettings["ssid"].([]byte) - if !ok { - continue - } - - ssid := string(ssidBytes) - savedSSIDs[ssid] = true - autoconnect := true - if ac, ok := connMeta["autoconnect"].(bool); ok { - autoconnect = ac - } - autoconnectMap[ssid] = autoconnect - - if hidden, ok := wifiSettings["hidden"].(bool); ok && hidden { - hiddenSSIDs[ssid] = true - } - } - - var devices []WiFiDevice - - for name, devInfo := range b.wifiDevices { - state, _ := devInfo.device.GetPropertyState() - connected := state == gonetworkmanager.NmDeviceStateActivated - - var ssid, bssid, ip string - var signal uint8 - - if connected { - if activeAP, err := devInfo.wireless.GetPropertyActiveAccessPoint(); err == nil && activeAP != nil && activeAP.GetPath() != "/" { - ssid, _ = activeAP.GetPropertySSID() - signal, _ = activeAP.GetPropertyStrength() - bssid, _ = activeAP.GetPropertyHWAddress() - } - ip = b.getDeviceIP(devInfo.device) - } - - stateStr := "disconnected" - switch state { - case gonetworkmanager.NmDeviceStateActivated: - stateStr = "connected" - case gonetworkmanager.NmDeviceStateConfig, gonetworkmanager.NmDeviceStateIpConfig: - stateStr = "connecting" - case gonetworkmanager.NmDeviceStatePrepare: - stateStr = "preparing" - case gonetworkmanager.NmDeviceStateDeactivating: - stateStr = "disconnecting" - } - - apPaths, err := devInfo.wireless.GetAccessPoints() - var networks []WiFiNetwork - if err == nil { - seenSSIDs := make(map[string]*WiFiNetwork) - for _, ap := range apPaths { - apSSID, err := ap.GetPropertySSID() - if err != nil || apSSID == "" { - continue - } - - if existing, exists := seenSSIDs[apSSID]; exists { - strength, _ := ap.GetPropertyStrength() - if strength > existing.Signal { - existing.Signal = strength - freq, _ := ap.GetPropertyFrequency() - existing.Frequency = freq - apBSSID, _ := ap.GetPropertyHWAddress() - existing.BSSID = apBSSID - } - continue - } - - strength, _ := ap.GetPropertyStrength() - flags, _ := ap.GetPropertyFlags() - wpaFlags, _ := ap.GetPropertyWPAFlags() - rsnFlags, _ := ap.GetPropertyRSNFlags() - freq, _ := ap.GetPropertyFrequency() - maxBitrate, _ := ap.GetPropertyMaxBitrate() - apBSSID, _ := ap.GetPropertyHWAddress() - mode, _ := ap.GetPropertyMode() - - secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) || - wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) || - rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone) - - enterprise := (rsnFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) || - (wpaFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) - - var modeStr string - switch mode { - case gonetworkmanager.Nm80211ModeAdhoc: - modeStr = "adhoc" - case gonetworkmanager.Nm80211ModeInfra: - modeStr = "infrastructure" - case gonetworkmanager.Nm80211ModeAp: - modeStr = "ap" - default: - modeStr = "unknown" - } - - channel := frequencyToChannel(freq) - - isConnected := connected && apSSID == ssid - rate := maxBitrate / 1000 - if isConnected { - if devBitrate, err := devInfo.wireless.GetPropertyBitrate(); err == nil && devBitrate > 0 { - rate = devBitrate / 1000 - } - } - - network := WiFiNetwork{ - SSID: apSSID, - BSSID: apBSSID, - Signal: strength, - Secured: secured, - Enterprise: enterprise, - Connected: isConnected, - Saved: savedSSIDs[apSSID], - Autoconnect: autoconnectMap[apSSID], - Hidden: hiddenSSIDs[apSSID], - Frequency: freq, - Mode: modeStr, - Rate: rate, - Channel: channel, - Device: name, - } - - seenSSIDs[apSSID] = &network - networks = append(networks, network) - } - - if connected && ssid != "" { - if _, exists := seenSSIDs[ssid]; !exists { - hiddenNetwork := WiFiNetwork{ - SSID: ssid, - BSSID: bssid, - Signal: signal, - Secured: true, - Connected: true, - Saved: savedSSIDs[ssid], - Autoconnect: autoconnectMap[ssid], - Hidden: true, - Mode: "infrastructure", - Device: name, - } - networks = append(networks, hiddenNetwork) - } - } - - sortWiFiNetworks(networks) - } - - devices = append(devices, WiFiDevice{ - Name: name, - HwAddress: devInfo.hwAddress, - State: stateStr, - Connected: connected, - SSID: ssid, - BSSID: bssid, - Signal: signal, - IP: ip, - Networks: networks, - }) - } - - sort.Slice(devices, func(i, j int) bool { - return devices[i].Name < devices[j].Name - }) - - b.stateMutex.Lock() - b.state.WiFiDevices = devices - b.stateMutex.Unlock() -} - -func (b *NetworkManagerBackend) getWifiDeviceForConnection(deviceName string) (*wifiDeviceInfo, error) { - if deviceName != "" { - devInfo, ok := b.wifiDevices[deviceName] - if !ok { - return nil, fmt.Errorf("WiFi device not found: %s", deviceName) - } - return devInfo, nil - } - - if b.wifiDevice == nil { - return nil, fmt.Errorf("no WiFi device available") - } - - dev := b.wifiDevice.(gonetworkmanager.Device) - iface, _ := dev.GetPropertyInterface() - if devInfo, ok := b.wifiDevices[iface]; ok { - return devInfo, nil - } - - return nil, fmt.Errorf("no WiFi device available") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi_test.go deleted file mode 100644 index 79c2c5b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/backend_networkmanager_wifi_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package network - -import ( - "testing" - - mock_gonetworkmanager "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/Wifx/gonetworkmanager/v2" - "github.com/stretchr/testify/assert" -) - -func TestNetworkManagerBackend_GetWiFiEnabled(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().GetPropertyWirelessEnabled().Return(true, nil) - - enabled, err := backend.GetWiFiEnabled() - assert.NoError(t, err) - assert.True(t, enabled) -} - -func TestNetworkManagerBackend_SetWiFiEnabled(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - mockNM.EXPECT().SetPropertyWirelessEnabled(true).Return(nil) - - err = backend.SetWiFiEnabled(true) - assert.NoError(t, err) - - backend.stateMutex.RLock() - assert.True(t, backend.state.WiFiEnabled) - backend.stateMutex.RUnlock() -} - -func TestNetworkManagerBackend_ScanWiFi_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - err = backend.ScanWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_ScanWiFi_Disabled(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockDeviceWireless := mock_gonetworkmanager.NewMockDeviceWireless(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = mockDeviceWireless - backend.wifiDev = mockDeviceWireless - - backend.stateMutex.Lock() - backend.state.WiFiEnabled = false - backend.stateMutex.Unlock() - - err = backend.ScanWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "WiFi is disabled") -} - -func TestNetworkManagerBackend_GetWiFiNetworkDetails_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - _, err = backend.GetWiFiNetworkDetails("TestNetwork") - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_ConnectWiFi_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - req := ConnectionRequest{SSID: "TestNetwork", Password: "password"} - err = backend.ConnectWiFi(req) - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_ConnectWiFi_AlreadyConnected(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - mockDeviceWireless := mock_gonetworkmanager.NewMockDeviceWireless(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = mockDeviceWireless - backend.wifiDev = mockDeviceWireless - backend.wifiDevices = map[string]*wifiDeviceInfo{ - "wlan0": { - device: nil, - wireless: mockDeviceWireless, - name: "wlan0", - hwAddress: "00:11:22:33:44:55", - }, - } - - mockDeviceWireless.EXPECT().GetPropertyInterface().Return("wlan0", nil) - - backend.stateMutex.Lock() - backend.state.WiFiConnected = true - backend.state.WiFiSSID = "TestNetwork" - backend.state.WiFiDevice = "wlan0" - backend.stateMutex.Unlock() - - req := ConnectionRequest{SSID: "TestNetwork", Password: "password"} - err = backend.ConnectWiFi(req) - assert.NoError(t, err) -} - -func TestNetworkManagerBackend_DisconnectWiFi_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - err = backend.DisconnectWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_IsConnectingTo(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.stateMutex.Lock() - backend.state.IsConnecting = true - backend.state.ConnectingSSID = "TestNetwork" - backend.stateMutex.Unlock() - - assert.True(t, backend.IsConnectingTo("TestNetwork")) - assert.False(t, backend.IsConnectingTo("OtherNetwork")) -} - -func TestNetworkManagerBackend_IsConnectingTo_NotConnecting(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.stateMutex.Lock() - backend.state.IsConnecting = false - backend.state.ConnectingSSID = "" - backend.stateMutex.Unlock() - - assert.False(t, backend.IsConnectingTo("TestNetwork")) -} - -func TestNetworkManagerBackend_UpdateWiFiNetworks_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - _, err = backend.updateWiFiNetworks() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestNetworkManagerBackend_FindConnection_NoSettings(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.settings = nil - _, err = backend.findConnection("NonExistentNetwork") - assert.Error(t, err) -} - -func TestNetworkManagerBackend_CreateAndConnectWiFi_NoDevice(t *testing.T) { - mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) - - backend, err := NewNetworkManagerBackend(mockNM) - assert.NoError(t, err) - - backend.wifiDevice = nil - backend.wifiDev = nil - req := ConnectionRequest{SSID: "TestNetwork", Password: "password"} - err = backend.createAndConnectWiFi(req) - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/broker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/broker.go deleted file mode 100644 index 5290fb5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/broker.go +++ /dev/null @@ -1,22 +0,0 @@ -package network - -import ( - "context" - "crypto/rand" - "encoding/hex" -) - -type PromptBroker interface { - Ask(ctx context.Context, req PromptRequest) (token string, err error) - Wait(ctx context.Context, token string) (PromptReply, error) - Resolve(token string, reply PromptReply) error - Cancel(path string, setting string) error -} - -func generateToken() (string, error) { - bytes := make([]byte, 16) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - return hex.EncodeToString(bytes), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/connection_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/connection_test.go deleted file mode 100644 index 7b37731..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/connection_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package network_test - -import ( - "errors" - "testing" - - mocks_network "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/network" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - "github.com/stretchr/testify/assert" -) - -func TestConnectionRequest_Validation(t *testing.T) { - t.Run("basic WiFi connection", func(t *testing.T) { - req := network.ConnectionRequest{ - SSID: "TestNetwork", - Password: "testpass123", - } - - assert.NotEmpty(t, req.SSID) - assert.NotEmpty(t, req.Password) - assert.Empty(t, req.Username) - }) - - t.Run("enterprise WiFi connection", func(t *testing.T) { - req := network.ConnectionRequest{ - SSID: "EnterpriseNetwork", - Password: "testpass123", - Username: "testuser", - } - - assert.NotEmpty(t, req.SSID) - assert.NotEmpty(t, req.Password) - assert.NotEmpty(t, req.Username) - }) - - t.Run("open WiFi connection", func(t *testing.T) { - req := network.ConnectionRequest{ - SSID: "OpenNetwork", - } - - assert.NotEmpty(t, req.SSID) - assert.Empty(t, req.Password) - assert.Empty(t, req.Username) - }) -} - -func TestManager_ConnectWiFi_NoDevice(t *testing.T) { - backend := mocks_network.NewMockBackend(t) - req := network.ConnectionRequest{ - SSID: "TestNetwork", - Password: "testpass123", - } - backend.EXPECT().ConnectWiFi(req).Return(errors.New("no WiFi device available")) - - manager := network.NewTestManager(backend, &network.NetworkState{}) - - err := manager.ConnectWiFi(req) - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestManager_DisconnectWiFi_NoDevice(t *testing.T) { - backend := mocks_network.NewMockBackend(t) - backend.EXPECT().DisconnectWiFi().Return(errors.New("no WiFi device available")) - - manager := network.NewTestManager(backend, &network.NetworkState{}) - - err := manager.DisconnectWiFi() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no WiFi device available") -} - -func TestManager_ForgetWiFiNetwork_NotFound(t *testing.T) { - backend := mocks_network.NewMockBackend(t) - backend.EXPECT().ForgetWiFiNetwork("NonExistentNetwork").Return(errors.New("connection not found")) - - manager := network.NewTestManager(backend, &network.NetworkState{}) - - err := manager.ForgetWiFiNetwork("NonExistentNetwork") - assert.Error(t, err) - assert.Contains(t, err.Error(), "connection not found") -} - -func TestManager_ConnectEthernet_NoDevice(t *testing.T) { - backend := mocks_network.NewMockBackend(t) - backend.EXPECT().ConnectEthernet().Return(errors.New("no ethernet device available")) - - manager := network.NewTestManager(backend, &network.NetworkState{}) - - err := manager.ConnectEthernet() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -func TestManager_DisconnectEthernet_NoDevice(t *testing.T) { - backend := mocks_network.NewMockBackend(t) - backend.EXPECT().DisconnectEthernet().Return(errors.New("no ethernet device available")) - - manager := network.NewTestManager(backend, &network.NetworkState{}) - - err := manager.DisconnectEthernet() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no ethernet device available") -} - -// Note: More comprehensive tests for connection operations would require -// mocking the NetworkManager D-Bus interfaces, which is beyond the scope -// of these unit tests. The tests above cover the basic error cases and -// validation logic. Integration tests would be needed for full coverage. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect.go deleted file mode 100644 index 6031e42..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect.go +++ /dev/null @@ -1,89 +0,0 @@ -package network - -import ( - "fmt" - - "github.com/godbus/dbus/v5" -) - -type BackendType int - -const ( - BackendNone BackendType = iota - BackendNetworkManager - BackendIwd - BackendConnMan - BackendNetworkd -) - -func nameHasOwner(bus *dbus.Conn, name string) (bool, error) { - obj := bus.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") - var owned bool - if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, name).Store(&owned); err != nil { - return false, err - } - return owned, nil -} - -type DetectResult struct { - Backend BackendType - HasNM bool - HasIwd bool - HasConnMan bool - HasWpaSupp bool - HasNetworkd bool - ChosenReason string -} - -func DetectNetworkStack() (*DetectResult, error) { - bus, err := dbus.ConnectSystemBus() - if err != nil { - return nil, fmt.Errorf("connect system bus: %w", err) - } - defer bus.Close() - - hasNM, _ := nameHasOwner(bus, "org.freedesktop.NetworkManager") - hasIwd, _ := nameHasOwner(bus, "net.connman.iwd") - hasConn, _ := nameHasOwner(bus, "net.connman") - hasWpa, _ := nameHasOwner(bus, "fi.w1.wpa_supplicant1") - hasNetworkd, _ := nameHasOwner(bus, "org.freedesktop.network1") - - res := &DetectResult{ - HasNM: hasNM, - HasIwd: hasIwd, - HasConnMan: hasConn, - HasWpaSupp: hasWpa, - HasNetworkd: hasNetworkd, - } - - switch { - case hasNM: - res.Backend = BackendNetworkManager - if hasIwd { - res.ChosenReason = "NetworkManager present; iwd also running (likely NM's Wi-Fi backend). Using NM API." - } else { - res.ChosenReason = "NetworkManager present. Using NM API." - } - case hasConn && hasIwd: - res.Backend = BackendConnMan - res.ChosenReason = "ConnMan + iwd detected. Use ConnMan API (iwd is its Wi-Fi daemon)." - case hasIwd && hasNetworkd: - res.Backend = BackendNetworkd - res.ChosenReason = "iwd + systemd-networkd detected. Using iwd for Wi-Fi association and networkd for IP/DHCP." - case hasIwd: - res.Backend = BackendIwd - res.ChosenReason = "iwd detected without NM/ConnMan. Using iwd API." - case hasNetworkd: - res.Backend = BackendNetworkd - res.ChosenReason = "systemd-networkd detected (no NM/ConnMan). Using networkd for L3 and wired." - default: - res.Backend = BackendNone - if hasWpa { - res.ChosenReason = "No NM/ConnMan/iwd; wpa_supplicant present. Consider a wpa_supplicant path." - } else { - res.ChosenReason = "No known network manager bus names found." - } - } - - return res, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect_test.go deleted file mode 100644 index 87e7635..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/detect_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package network - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBackendType_Constants(t *testing.T) { - assert.Equal(t, BackendType(0), BackendNone) - assert.Equal(t, BackendType(1), BackendNetworkManager) - assert.Equal(t, BackendType(2), BackendIwd) - assert.Equal(t, BackendType(3), BackendConnMan) - assert.Equal(t, BackendType(4), BackendNetworkd) -} - -func TestDetectResult_HasNetworkdField(t *testing.T) { - result := &DetectResult{ - Backend: BackendNetworkd, - HasNetworkd: true, - HasIwd: true, - } - - assert.True(t, result.HasNetworkd) - assert.True(t, result.HasIwd) - assert.Equal(t, BackendNetworkd, result.Backend) -} - -func TestDetectNetworkStack_Integration(t *testing.T) { - result, err := DetectNetworkStack() - - if err != nil && strings.Contains(err.Error(), "connect system bus") { - t.Skipf("system D-Bus unavailable: %v", err) - } - - assert.NoError(t, err) - if assert.NotNil(t, result) { - assert.NotEmpty(t, result.ChosenReason) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers.go deleted file mode 100644 index 2b3e75e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers.go +++ /dev/null @@ -1,630 +0,0 @@ -package network - -import ( - "encoding/json" - "fmt" - "net" - "os" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - switch req.Method { - case "network.getState": - handleGetState(conn, req, manager) - case "network.wifi.scan": - handleScanWiFi(conn, req, manager) - case "network.wifi.networks": - handleGetWiFiNetworks(conn, req, manager) - case "network.wifi.connect": - handleConnectWiFi(conn, req, manager) - case "network.wifi.disconnect": - handleDisconnectWiFi(conn, req, manager) - case "network.wifi.forget": - handleForgetWiFi(conn, req, manager) - case "network.wifi.toggle": - handleToggleWiFi(conn, req, manager) - case "network.wifi.enable": - handleEnableWiFi(conn, req, manager) - case "network.wifi.disable": - handleDisableWiFi(conn, req, manager) - case "network.ethernet.connect.config": - handleConnectEthernetSpecificConfig(conn, req, manager) - case "network.ethernet.connect": - handleConnectEthernet(conn, req, manager) - case "network.ethernet.disconnect": - handleDisconnectEthernet(conn, req, manager) - case "network.preference.set": - handleSetPreference(conn, req, manager) - case "network.info": - handleGetNetworkInfo(conn, req, manager) - case "network.qrcode": - handleGetNetworkQRCode(conn, req, manager) - case "network.delete-qrcode": - handleDeleteQRCode(conn, req, manager) - case "network.ethernet.info": - handleGetWiredNetworkInfo(conn, req, manager) - case "network.subscribe": - handleSubscribe(conn, req, manager) - case "network.credentials.submit": - handleCredentialsSubmit(conn, req, manager) - case "network.credentials.cancel": - handleCredentialsCancel(conn, req, manager) - case "network.vpn.profiles": - handleListVPNProfiles(conn, req, manager) - case "network.vpn.active": - handleListActiveVPN(conn, req, manager) - case "network.vpn.connect": - handleConnectVPN(conn, req, manager) - case "network.vpn.disconnect": - handleDisconnectVPN(conn, req, manager) - case "network.vpn.disconnectAll": - handleDisconnectAllVPN(conn, req, manager) - case "network.vpn.clearCredentials": - handleClearVPNCredentials(conn, req, manager) - case "network.vpn.plugins": - handleListVPNPlugins(conn, req, manager) - case "network.vpn.import": - handleImportVPN(conn, req, manager) - case "network.vpn.getConfig": - handleGetVPNConfig(conn, req, manager) - case "network.vpn.updateConfig": - handleUpdateVPNConfig(conn, req, manager) - case "network.vpn.delete": - handleDeleteVPN(conn, req, manager) - case "network.vpn.setCredentials": - handleSetVPNCredentials(conn, req, manager) - case "network.wifi.setAutoconnect": - handleSetWiFiAutoconnect(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleCredentialsSubmit(conn net.Conn, req models.Request, manager *Manager) { - token, err := params.String(req.Params, "token") - if err != nil { - log.Warnf("handleCredentialsSubmit: missing or invalid token parameter") - models.RespondError(conn, req.ID, err.Error()) - return - } - - secrets, err := params.StringMap(req.Params, "secrets") - if err != nil { - log.Warnf("handleCredentialsSubmit: missing or invalid secrets parameter") - models.RespondError(conn, req.ID, err.Error()) - return - } - - save := params.BoolOpt(req.Params, "save", true) - - if err := manager.SubmitCredentials(token, secrets, save); err != nil { - log.Warnf("handleCredentialsSubmit: failed to submit credentials: %v", err) - models.RespondError(conn, req.ID, err.Error()) - return - } - - log.Infof("handleCredentialsSubmit: credentials submitted successfully") - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "credentials submitted"}) -} - -func handleCredentialsCancel(conn net.Conn, req models.Request, manager *Manager) { - token, err := params.String(req.Params, "token") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.CancelCredentials(token); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "credentials cancelled"}) -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleScanWiFi(conn net.Conn, req models.Request, manager *Manager) { - device := params.StringOpt(req.Params, "device", "") - var err error - if device != "" { - err = manager.ScanWiFiDevice(device) - } else { - err = manager.ScanWiFi() - } - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "scanning"}) -} - -func handleGetWiFiNetworks(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetWiFiNetworks()) -} - -func handleConnectWiFi(conn net.Conn, req models.Request, manager *Manager) { - ssid, err := params.String(req.Params, "ssid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - var connReq ConnectionRequest - connReq.SSID = ssid - connReq.Password = params.StringOpt(req.Params, "password", "") - connReq.Username = params.StringOpt(req.Params, "username", "") - connReq.Device = params.StringOpt(req.Params, "device", "") - - if interactive, ok := models.Get[bool](req, "interactive"); ok { - connReq.Interactive = interactive - } else { - state := manager.GetState() - alreadyConnected := state.WiFiConnected && state.WiFiSSID == ssid - - if alreadyConnected && connReq.Device == "" { - connReq.Interactive = false - } else { - networkInfo, err := manager.GetNetworkInfo(ssid) - isSaved := err == nil && networkInfo.Saved - - if isSaved { - connReq.Interactive = false - } else if err == nil && networkInfo.Secured && connReq.Password == "" && connReq.Username == "" { - connReq.Interactive = true - } - } - } - - connReq.AnonymousIdentity = params.StringOpt(req.Params, "anonymousIdentity", "") - connReq.DomainSuffixMatch = params.StringOpt(req.Params, "domainSuffixMatch", "") - connReq.EAPMethod = params.StringOpt(req.Params, "eapMethod", "") - connReq.Phase2Auth = params.StringOpt(req.Params, "phase2Auth", "") - connReq.CACertPath = params.StringOpt(req.Params, "caCertPath", "") - connReq.ClientCertPath = params.StringOpt(req.Params, "clientCertPath", "") - connReq.PrivateKeyPath = params.StringOpt(req.Params, "privateKeyPath", "") - - if useSystemCACerts, ok := models.Get[bool](req, "useSystemCACerts"); ok { - connReq.UseSystemCACerts = &useSystemCACerts - } - - if err := manager.ConnectWiFi(connReq); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "connecting"}) -} - -func handleDisconnectWiFi(conn net.Conn, req models.Request, manager *Manager) { - device := params.StringOpt(req.Params, "device", "") - var err error - if device != "" { - err = manager.DisconnectWiFiDevice(device) - } else { - err = manager.DisconnectWiFi() - } - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "disconnected"}) -} - -func handleForgetWiFi(conn net.Conn, req models.Request, manager *Manager) { - ssid, err := params.String(req.Params, "ssid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.ForgetWiFiNetwork(ssid); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "forgotten"}) -} - -func handleToggleWiFi(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.ToggleWiFi(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - state := manager.GetState() - models.Respond(conn, req.ID, map[string]bool{"enabled": state.WiFiEnabled}) -} - -func handleEnableWiFi(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.EnableWiFi(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, map[string]bool{"enabled": true}) -} - -func handleDisableWiFi(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.DisableWiFi(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, map[string]bool{"enabled": false}) -} - -func handleConnectEthernetSpecificConfig(conn net.Conn, req models.Request, manager *Manager) { - uuid, err := params.String(req.Params, "uuid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - if err := manager.activateConnection(uuid); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "connecting"}) -} - -func handleConnectEthernet(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.ConnectEthernet(); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "connecting"}) -} - -func handleDisconnectEthernet(conn net.Conn, req models.Request, manager *Manager) { - device := params.StringOpt(req.Params, "device", "") - var err error - if device != "" { - err = manager.DisconnectEthernetDevice(device) - } else { - err = manager.DisconnectEthernet() - } - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "disconnected"}) -} - -func handleSetPreference(conn net.Conn, req models.Request, manager *Manager) { - preference, err := params.String(req.Params, "preference") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetConnectionPreference(ConnectionPreference(preference)); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, map[string]string{"preference": preference}) -} - -func handleGetNetworkInfo(conn net.Conn, req models.Request, manager *Manager) { - ssid, err := params.String(req.Params, "ssid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - network, err := manager.GetNetworkInfoDetailed(ssid) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, network) -} - -func handleGetNetworkQRCode(conn net.Conn, req models.Request, manager *Manager) { - ssid, err := params.String(req.Params, "ssid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - content, err := manager.GetNetworkQRCode(ssid) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, content) -} - -func handleDeleteQRCode(conn net.Conn, req models.Request, _ *Manager) { - path, err := params.String(req.Params, "path") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if !isValidQRCodePath(path) { - models.RespondError(conn, req.ID, "invalid QR code path") - return - } - - if err := os.Remove(path); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "QR code file deleted"}) -} - -func handleGetWiredNetworkInfo(conn net.Conn, req models.Request, manager *Manager) { - uuid, err := params.String(req.Params, "uuid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - network, err := manager.GetWiredNetworkInfoDetailed(uuid) - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, network) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - event := NetworkEvent{ - Type: EventStateChanged, - Data: initialState, - } - if err := json.NewEncoder(conn).Encode(models.Response[NetworkEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - return - } - - for state := range stateChan { - event := NetworkEvent{ - Type: EventStateChanged, - Data: state, - } - if err := json.NewEncoder(conn).Encode(models.Response[NetworkEvent]{ - Result: &event, - }); err != nil { - return - } - } -} - -func handleListVPNProfiles(conn net.Conn, req models.Request, manager *Manager) { - profiles, err := manager.ListVPNProfiles() - if err != nil { - log.Warnf("handleListVPNProfiles: failed to list profiles: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list VPN profiles: %v", err)) - return - } - - models.Respond(conn, req.ID, profiles) -} - -func handleListActiveVPN(conn net.Conn, req models.Request, manager *Manager) { - active, err := manager.ListActiveVPN() - if err != nil { - log.Warnf("handleListActiveVPN: failed to list active VPNs: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list active VPNs: %v", err)) - return - } - - models.Respond(conn, req.ID, active) -} - -func handleConnectVPN(conn net.Conn, req models.Request, manager *Manager) { - uuidOrName, ok := params.StringAlt(req.Params, "uuidOrName", "name", "uuid") - if !ok { - log.Warnf("handleConnectVPN: missing uuidOrName/name/uuid parameter") - models.RespondError(conn, req.ID, "missing 'uuidOrName', 'name', or 'uuid' parameter") - return - } - - singleActive := params.BoolOpt(req.Params, "singleActive", true) - - if err := manager.ConnectVPN(uuidOrName, singleActive); err != nil { - log.Warnf("handleConnectVPN: failed to connect: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to connect VPN: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN connection initiated"}) -} - -func handleDisconnectVPN(conn net.Conn, req models.Request, manager *Manager) { - uuidOrName, ok := params.StringAlt(req.Params, "uuidOrName", "name", "uuid") - if !ok { - log.Warnf("handleDisconnectVPN: missing uuidOrName/name/uuid parameter") - models.RespondError(conn, req.ID, "missing 'uuidOrName', 'name', or 'uuid' parameter") - return - } - - if err := manager.DisconnectVPN(uuidOrName); err != nil { - log.Warnf("handleDisconnectVPN: failed to disconnect: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to disconnect VPN: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN disconnected"}) -} - -func handleDisconnectAllVPN(conn net.Conn, req models.Request, manager *Manager) { - if err := manager.DisconnectAllVPN(); err != nil { - log.Warnf("handleDisconnectAllVPN: failed: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to disconnect all VPNs: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "All VPNs disconnected"}) -} - -func handleClearVPNCredentials(conn net.Conn, req models.Request, manager *Manager) { - uuidOrName, ok := params.StringAlt(req.Params, "uuid", "name", "uuidOrName") - if !ok { - log.Warnf("handleClearVPNCredentials: missing uuidOrName/name/uuid parameter") - models.RespondError(conn, req.ID, "missing uuidOrName/name/uuid parameter") - return - } - - if err := manager.ClearVPNCredentials(uuidOrName); err != nil { - log.Warnf("handleClearVPNCredentials: failed: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to clear VPN credentials: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN credentials cleared"}) -} - -func handleSetWiFiAutoconnect(conn net.Conn, req models.Request, manager *Manager) { - ssid, err := params.String(req.Params, "ssid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - autoconnect, err := params.Bool(req.Params, "autoconnect") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetWiFiAutoconnect(ssid, autoconnect); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to set autoconnect: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "autoconnect updated"}) -} - -func handleListVPNPlugins(conn net.Conn, req models.Request, manager *Manager) { - plugins, err := manager.ListVPNPlugins() - if err != nil { - log.Warnf("handleListVPNPlugins: failed to list plugins: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list VPN plugins: %v", err)) - return - } - - models.Respond(conn, req.ID, plugins) -} - -func handleImportVPN(conn net.Conn, req models.Request, manager *Manager) { - filePath, ok := params.StringAlt(req.Params, "file", "path") - if !ok { - models.RespondError(conn, req.ID, "missing 'file' or 'path' parameter") - return - } - - name := params.StringOpt(req.Params, "name", "") - - result, err := manager.ImportVPN(filePath, name) - if err != nil { - log.Warnf("handleImportVPN: failed to import: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to import VPN: %v", err)) - return - } - - models.Respond(conn, req.ID, result) -} - -func handleGetVPNConfig(conn net.Conn, req models.Request, manager *Manager) { - uuidOrName, ok := params.StringAlt(req.Params, "uuid", "name", "uuidOrName") - if !ok { - models.RespondError(conn, req.ID, "missing 'uuid', 'name', or 'uuidOrName' parameter") - return - } - - config, err := manager.GetVPNConfig(uuidOrName) - if err != nil { - log.Warnf("handleGetVPNConfig: failed to get config: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to get VPN config: %v", err)) - return - } - - models.Respond(conn, req.ID, config) -} - -func handleUpdateVPNConfig(conn net.Conn, req models.Request, manager *Manager) { - connUUID, err := params.String(req.Params, "uuid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - updates := make(map[string]any) - - if name, ok := models.Get[string](req, "name"); ok { - updates["name"] = name - } - if autoconnect, ok := models.Get[bool](req, "autoconnect"); ok { - updates["autoconnect"] = autoconnect - } - if data, ok := models.Get[map[string]any](req, "data"); ok { - updates["data"] = data - } - - if len(updates) == 0 { - models.RespondError(conn, req.ID, "no updates provided") - return - } - - if err := manager.UpdateVPNConfig(connUUID, updates); err != nil { - log.Warnf("handleUpdateVPNConfig: failed to update: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to update VPN config: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN config updated"}) -} - -func handleDeleteVPN(conn net.Conn, req models.Request, manager *Manager) { - uuidOrName, ok := params.StringAlt(req.Params, "uuid", "name", "uuidOrName") - if !ok { - models.RespondError(conn, req.ID, "missing 'uuid', 'name', or 'uuidOrName' parameter") - return - } - - if err := manager.DeleteVPN(uuidOrName); err != nil { - log.Warnf("handleDeleteVPN: failed to delete: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to delete VPN: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN deleted"}) -} - -func handleSetVPNCredentials(conn net.Conn, req models.Request, manager *Manager) { - connUUID, err := params.String(req.Params, "uuid") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - username := params.StringOpt(req.Params, "username", "") - password := params.StringOpt(req.Params, "password", "") - save := params.BoolOpt(req.Params, "save", true) - - if err := manager.SetVPNCredentials(connUUID, username, password, save); err != nil { - log.Warnf("handleSetVPNCredentials: failed to set credentials: %v", err) - models.RespondError(conn, req.ID, fmt.Sprintf("failed to set VPN credentials: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "VPN credentials set"}) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers_test.go deleted file mode 100644 index ea8ae33..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/handlers_test.go +++ /dev/null @@ -1,269 +0,0 @@ -package network - -import ( - "bytes" - "encoding/json" - "net" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type mockNetConn struct { - net.Conn - readBuf *bytes.Buffer - writeBuf *bytes.Buffer - closed bool -} - -func newMockNetConn() *mockNetConn { - return &mockNetConn{ - readBuf: &bytes.Buffer{}, - writeBuf: &bytes.Buffer{}, - } -} - -func (m *mockNetConn) Read(b []byte) (n int, err error) { - return m.readBuf.Read(b) -} - -func (m *mockNetConn) Write(b []byte) (n int, err error) { - return m.writeBuf.Write(b) -} - -func (m *mockNetConn) Close() error { - m.closed = true - return nil -} - -func TestRespondError_Network(t *testing.T) { - conn := newMockNetConn() - models.RespondError(conn, 123, "test error") - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Equal(t, "test error", resp.Error) - assert.Nil(t, resp.Result) -} - -func TestRespond_Network(t *testing.T) { - conn := newMockNetConn() - result := models.SuccessResult{Success: true, Message: "test"} - models.Respond(conn, 123, result) - - var resp models.Response[models.SuccessResult] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.True(t, resp.Result.Success) - assert.Equal(t, "test", resp.Result.Message) -} - -func TestHandleGetState(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - NetworkStatus: StatusWiFi, - WiFiSSID: "TestNetwork", - WiFiConnected: true, - }, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "network.getState"} - - handleGetState(conn, req, manager) - - var resp models.Response[NetworkState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.Equal(t, StatusWiFi, resp.Result.NetworkStatus) - assert.Equal(t, "TestNetwork", resp.Result.WiFiSSID) -} - -func TestHandleGetWiFiNetworks(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - WiFiNetworks: []WiFiNetwork{ - {SSID: "Network1", Signal: 90}, - {SSID: "Network2", Signal: 80}, - }, - }, - } - - conn := newMockNetConn() - req := models.Request{ID: 123, Method: "network.wifi.networks"} - - handleGetWiFiNetworks(conn, req, manager) - - var resp models.Response[[]WiFiNetwork] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.Len(t, *resp.Result, 2) - assert.Equal(t, "Network1", (*resp.Result)[0].SSID) -} - -func TestHandleConnectWiFi(t *testing.T) { - t.Run("missing ssid parameter", func(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "network.wifi.connect", - Params: map[string]any{}, - } - - handleConnectWiFi(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'ssid' parameter") - }) -} - -func TestHandleSetPreference(t *testing.T) { - t.Run("missing preference parameter", func(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "network.preference.set", - Params: map[string]any{}, - } - - handleSetPreference(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'preference' parameter") - }) -} - -func TestHandleGetNetworkInfo(t *testing.T) { - t.Run("missing ssid parameter", func(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "network.info", - Params: map[string]any{}, - } - - handleGetNetworkInfo(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "missing or invalid 'ssid' parameter") - }) -} - -func TestHandleRequest(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - NetworkStatus: StatusWiFi, - }, - } - - t.Run("unknown method", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "network.unknown", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Contains(t, resp.Error, "unknown method") - }) - - t.Run("valid method - getState", func(t *testing.T) { - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "network.getState", - } - - HandleRequest(conn, req, manager) - - var resp models.Response[NetworkState] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - }) -} - -func TestHandleSubscribe(t *testing.T) { - // This test is complex due to the streaming nature of subscriptions - // Better suited as an integration test - t.Skip("Subscription test requires connection lifecycle management - integration test needed") -} - -func TestManager_Subscribe_Unsubscribe(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - t.Run("subscribe creates channel", func(t *testing.T) { - ch := manager.Subscribe("client1") - assert.NotNil(t, ch) - count := 0 - manager.subscribers.Range(func(key string, ch chan NetworkState) bool { - count++ - return true - }) - assert.Equal(t, 1, count) - }) - - t.Run("unsubscribe removes channel", func(t *testing.T) { - manager.Unsubscribe("client1") - count := 0 - manager.subscribers.Range(func(key string, ch chan NetworkState) bool { count++; return true }) - assert.Equal(t, 0, count) - }) - - t.Run("unsubscribe non-existent client is safe", func(t *testing.T) { - assert.NotPanics(t, func() { - manager.Unsubscribe("non-existent") - }) - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/helpers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/helpers.go deleted file mode 100644 index 4669f52..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/helpers.go +++ /dev/null @@ -1,53 +0,0 @@ -package network - -import "sort" - -func frequencyToChannel(freq uint32) uint32 { - if freq >= 2412 && freq <= 2484 { - if freq == 2484 { - return 14 - } - return (freq-2412)/5 + 1 - } - - if freq >= 5170 && freq <= 5825 { - return (freq-5170)/5 + 34 - } - - if freq >= 5955 && freq <= 7115 { - return (freq-5955)/5 + 1 - } - - return 0 -} - -func sortWiFiNetworks(networks []WiFiNetwork) { - sort.Slice(networks, func(i, j int) bool { - if networks[i].Connected && !networks[j].Connected { - return true - } - if !networks[i].Connected && networks[j].Connected { - return false - } - - if networks[i].Saved && !networks[j].Saved { - return true - } - if !networks[i].Saved && networks[j].Saved { - return false - } - - if !networks[i].Secured && networks[j].Secured { - if networks[i].Signal >= 50 { - return true - } - } - if networks[i].Secured && !networks[j].Secured { - if networks[j].Signal >= 50 { - return false - } - } - - return networks[i].Signal > networks[j].Signal - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager.go deleted file mode 100644 index 5c6657e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager.go +++ /dev/null @@ -1,626 +0,0 @@ -package network - -import ( - "fmt" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/yeqown/go-qrcode/v2" - "github.com/yeqown/go-qrcode/writer/standard" -) - -func NewManager() (*Manager, error) { - detection, err := DetectNetworkStack() - if err != nil { - return nil, fmt.Errorf("failed to detect network stack: %w", err) - } - - log.Infof("Network backend detection: %s", detection.ChosenReason) - - var backend Backend - switch detection.Backend { - case BackendNetworkManager: - nm, err := NewNetworkManagerBackend() - if err != nil { - return nil, fmt.Errorf("failed to create NetworkManager backend: %w", err) - } - backend = nm - - case BackendIwd: - iwd, err := NewIWDBackend() - if err != nil { - return nil, fmt.Errorf("failed to create iwd backend: %w", err) - } - backend = iwd - - case BackendNetworkd: - if detection.HasIwd && !detection.HasNM { - wifi, err := NewIWDBackend() - if err != nil { - return nil, fmt.Errorf("failed to create iwd backend: %w", err) - } - l3, err := NewSystemdNetworkdBackend() - if err != nil { - return nil, fmt.Errorf("failed to create networkd backend: %w", err) - } - hybrid, err := NewHybridIwdNetworkdBackend(wifi, l3) - if err != nil { - return nil, fmt.Errorf("failed to create hybrid backend: %w", err) - } - backend = hybrid - } else { - nd, err := NewSystemdNetworkdBackend() - if err != nil { - return nil, fmt.Errorf("failed to create networkd backend: %w", err) - } - backend = nd - } - - default: - return nil, fmt.Errorf("no supported network backend found: %s", detection.ChosenReason) - } - - m := &Manager{ - backend: backend, - state: &NetworkState{ - NetworkStatus: StatusDisconnected, - Preference: PreferenceAuto, - WiFiNetworks: []WiFiNetwork{}, - }, - stateMutex: sync.RWMutex{}, - - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - broker := NewSubscriptionBroker(m.broadcastCredentialPrompt) - if err := backend.SetPromptBroker(broker); err != nil { - return nil, fmt.Errorf("failed to set prompt broker: %w", err) - } - - if err := backend.Initialize(); err != nil { - return nil, fmt.Errorf("failed to initialize backend: %w", err) - } - - if err := m.syncStateFromBackend(); err != nil { - return nil, fmt.Errorf("failed to sync initial state: %w", err) - } - - m.notifierWg.Add(1) - go m.notifier() - - if err := backend.StartMonitoring(m.onBackendStateChange); err != nil { - m.Close() - return nil, fmt.Errorf("failed to start monitoring: %w", err) - } - - return m, nil -} - -func (m *Manager) syncStateFromBackend() error { - backendState, err := m.backend.GetCurrentState() - if err != nil { - return err - } - - m.stateMutex.Lock() - m.state.Backend = backendState.Backend - m.state.NetworkStatus = backendState.NetworkStatus - m.state.EthernetIP = backendState.EthernetIP - m.state.EthernetDevice = backendState.EthernetDevice - m.state.EthernetConnected = backendState.EthernetConnected - m.state.EthernetConnectionUuid = backendState.EthernetConnectionUuid - m.state.EthernetDevices = backendState.EthernetDevices - m.state.WiFiIP = backendState.WiFiIP - m.state.WiFiDevice = backendState.WiFiDevice - m.state.WiFiConnected = backendState.WiFiConnected - m.state.WiFiEnabled = backendState.WiFiEnabled - m.state.WiFiSSID = backendState.WiFiSSID - m.state.WiFiBSSID = backendState.WiFiBSSID - m.state.WiFiSignal = backendState.WiFiSignal - m.state.WiFiNetworks = backendState.WiFiNetworks - m.state.WiFiDevices = backendState.WiFiDevices - m.state.WiredConnections = backendState.WiredConnections - m.state.VPNProfiles = backendState.VPNProfiles - m.state.VPNActive = backendState.VPNActive - m.state.IsConnecting = backendState.IsConnecting - m.state.ConnectingSSID = backendState.ConnectingSSID - m.state.ConnectingDevice = backendState.ConnectingDevice - m.state.LastError = backendState.LastError - m.stateMutex.Unlock() - - return nil -} - -func (m *Manager) onBackendStateChange() { - if err := m.syncStateFromBackend(); err != nil { - log.Errorf("failed to sync state from backend: %v", err) - } - m.notifySubscribers() -} - -func signalChangeSignificant(old, new uint8) bool { - if old == 0 || new == 0 { - return true - } - diff := int(new) - int(old) - if diff < 0 { - diff = -diff - } - return diff >= 5 -} - -func (m *Manager) snapshotState() NetworkState { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - s := *m.state - s.WiFiNetworks = append([]WiFiNetwork(nil), m.state.WiFiNetworks...) - s.WiFiDevices = append([]WiFiDevice(nil), m.state.WiFiDevices...) - s.WiredConnections = append([]WiredConnection(nil), m.state.WiredConnections...) - s.EthernetDevices = append([]EthernetDevice(nil), m.state.EthernetDevices...) - s.VPNProfiles = append([]VPNProfile(nil), m.state.VPNProfiles...) - s.VPNActive = append([]VPNActive(nil), m.state.VPNActive...) - return s -} - -func stateChangedMeaningfully(old, new *NetworkState) bool { - if old.NetworkStatus != new.NetworkStatus { - return true - } - if old.Preference != new.Preference { - return true - } - if old.EthernetConnected != new.EthernetConnected { - return true - } - if old.EthernetIP != new.EthernetIP { - return true - } - if old.WiFiConnected != new.WiFiConnected { - return true - } - if old.WiFiEnabled != new.WiFiEnabled { - return true - } - if old.WiFiSSID != new.WiFiSSID { - return true - } - if old.WiFiBSSID != new.WiFiBSSID { - return true - } - if old.WiFiIP != new.WiFiIP { - return true - } - if !signalChangeSignificant(old.WiFiSignal, new.WiFiSignal) { - if old.WiFiSignal != new.WiFiSignal { - return false - } - } else if old.WiFiSignal != new.WiFiSignal { - return true - } - if old.IsConnecting != new.IsConnecting { - return true - } - if old.ConnectingSSID != new.ConnectingSSID { - return true - } - if old.LastError != new.LastError { - return true - } - if len(old.WiFiNetworks) != len(new.WiFiNetworks) { - return true - } - if len(old.WiFiDevices) != len(new.WiFiDevices) { - return true - } - if len(old.WiredConnections) != len(new.WiredConnections) { - return true - } - if len(old.EthernetDevices) != len(new.EthernetDevices) { - return true - } - - for i := range old.WiFiNetworks { - oldNet := &old.WiFiNetworks[i] - newNet := &new.WiFiNetworks[i] - if oldNet.SSID != newNet.SSID { - return true - } - if oldNet.Connected != newNet.Connected { - return true - } - if oldNet.Saved != newNet.Saved { - return true - } - if oldNet.Autoconnect != newNet.Autoconnect { - return true - } - } - - for i := range old.WiredConnections { - oldNet := &old.WiredConnections[i] - newNet := &new.WiredConnections[i] - if oldNet.ID != newNet.ID { - return true - } - if oldNet.IsActive != newNet.IsActive { - return true - } - } - - for i := range old.EthernetDevices { - oldDev := &old.EthernetDevices[i] - newDev := &new.EthernetDevices[i] - if oldDev.Name != newDev.Name { - return true - } - if oldDev.Connected != newDev.Connected { - return true - } - if oldDev.State != newDev.State { - return true - } - if oldDev.IP != newDev.IP { - return true - } - } - - // Check VPN profiles count - if len(old.VPNProfiles) != len(new.VPNProfiles) { - return true - } - - // Check active VPN connections count or state - if len(old.VPNActive) != len(new.VPNActive) { - return true - } - - // Check if any active VPN changed - for i := range old.VPNActive { - oldVPN := &old.VPNActive[i] - newVPN := &new.VPNActive[i] - if oldVPN.UUID != newVPN.UUID { - return true - } - if oldVPN.State != newVPN.State { - return true - } - } - - return false -} - -func (m *Manager) GetState() NetworkState { - return m.snapshotState() -} - -func (m *Manager) Subscribe(id string) chan NetworkState { - ch := make(chan NetworkState, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) SubscribeCredentials(id string) chan CredentialPrompt { - ch := make(chan CredentialPrompt, 16) - m.credentialSubscribers.Store(id, ch) - return ch -} - -func (m *Manager) UnsubscribeCredentials(id string) { - if ch, ok := m.credentialSubscribers.LoadAndDelete(id); ok { - close(ch) - } -} - -func (m *Manager) broadcastCredentialPrompt(prompt CredentialPrompt) { - m.credentialSubscribers.Range(func(key string, ch chan CredentialPrompt) bool { - select { - case ch <- prompt: - default: - } - return true - }) -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.snapshotState() - - if m.lastNotifiedState != nil && !stateChangedMeaningfully(m.lastNotifiedState, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan NetworkState) bool { - select { - case ch <- currentState: - default: - } - return true - }) - - stateCopy := currentState - m.lastNotifiedState = &stateCopy - pending = false - } - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) SetPromptBroker(broker PromptBroker) error { - return m.backend.SetPromptBroker(broker) -} - -func (m *Manager) SubmitCredentials(token string, secrets map[string]string, save bool) error { - return m.backend.SubmitCredentials(token, secrets, save) -} - -func (m *Manager) CancelCredentials(token string) error { - return m.backend.CancelCredentials(token) -} - -func (m *Manager) GetPromptBroker() PromptBroker { - return m.backend.GetPromptBroker() -} - -func (m *Manager) Close() { - close(m.stopChan) - m.notifierWg.Wait() - - if m.backend != nil { - m.backend.Close() - } - - m.subscribers.Range(func(key string, ch chan NetworkState) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) -} - -func (m *Manager) ScanWiFi() error { - return m.backend.ScanWiFi() -} - -func (m *Manager) GetWiFiNetworks() []WiFiNetwork { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - networks := make([]WiFiNetwork, len(m.state.WiFiNetworks)) - copy(networks, m.state.WiFiNetworks) - return networks -} - -func (m *Manager) GetNetworkInfo(ssid string) (*WiFiNetwork, error) { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - - for _, network := range m.state.WiFiNetworks { - if network.SSID == ssid { - return &network, nil - } - } - - return nil, fmt.Errorf("network not found: %s", ssid) -} - -func (m *Manager) GetNetworkInfoDetailed(ssid string) (*NetworkInfoResponse, error) { - return m.backend.GetWiFiNetworkDetails(ssid) -} - -func (m *Manager) GetNetworkQRCode(ssid string) ([2]string, error) { - content, err := m.backend.GetWiFiQRCodeContent(ssid) - if err != nil { - return [2]string{}, err - } - - qrc, err := qrcode.New(content) - if err != nil { - return [2]string{}, fmt.Errorf("failed to create QR code for `%s`: %w", ssid, err) - } - - pathThemed, pathNormal := qrCodePaths(ssid) - - wThemed, err := standard.New( - pathThemed, - standard.WithBuiltinImageEncoder(standard.PNG_FORMAT), - standard.WithBgTransparent(), - standard.WithFgColorRGBHex("#ffffff"), - ) - if err != nil { - return [2]string{}, fmt.Errorf("failed to create QR code writer: %w", err) - } - if err := qrc.Save(wThemed); err != nil { - return [2]string{}, fmt.Errorf("failed to save QR code for `%s`: %w", ssid, err) - } - - wNormal, err := standard.New(pathNormal, standard.WithBuiltinImageEncoder(standard.PNG_FORMAT)) - if err != nil { - return [2]string{}, fmt.Errorf("failed to create QR code writer: %w", err) - } - if err := qrc.Save(wNormal); err != nil { - return [2]string{}, fmt.Errorf("failed to save QR code for `%s`: %w", ssid, err) - } - - return [2]string{pathThemed, pathNormal}, nil -} - -func (m *Manager) ToggleWiFi() error { - enabled, err := m.backend.GetWiFiEnabled() - if err != nil { - return fmt.Errorf("failed to get WiFi state: %w", err) - } - - err = m.backend.SetWiFiEnabled(!enabled) - if err != nil { - return fmt.Errorf("failed to toggle WiFi: %w", err) - } - - return nil -} - -func (m *Manager) EnableWiFi() error { - err := m.backend.SetWiFiEnabled(true) - if err != nil { - return fmt.Errorf("failed to enable WiFi: %w", err) - } - - return nil -} - -func (m *Manager) DisableWiFi() error { - err := m.backend.SetWiFiEnabled(false) - if err != nil { - return fmt.Errorf("failed to disable WiFi: %w", err) - } - - return nil -} - -func (m *Manager) ConnectWiFi(req ConnectionRequest) error { - return m.backend.ConnectWiFi(req) -} - -func (m *Manager) DisconnectWiFi() error { - return m.backend.DisconnectWiFi() -} - -func (m *Manager) ForgetWiFiNetwork(ssid string) error { - return m.backend.ForgetWiFiNetwork(ssid) -} - -func (m *Manager) GetWiredConfigs() []WiredConnection { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - configs := make([]WiredConnection, len(m.state.WiredConnections)) - copy(configs, m.state.WiredConnections) - return configs -} - -func (m *Manager) GetWiredNetworkInfoDetailed(uuid string) (*WiredNetworkInfoResponse, error) { - return m.backend.GetWiredNetworkDetails(uuid) -} - -func (m *Manager) ConnectEthernet() error { - return m.backend.ConnectEthernet() -} - -func (m *Manager) DisconnectEthernet() error { - return m.backend.DisconnectEthernet() -} - -func (m *Manager) DisconnectEthernetDevice(device string) error { - return m.backend.DisconnectEthernetDevice(device) -} - -func (m *Manager) GetEthernetDevices() []EthernetDevice { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - devices := make([]EthernetDevice, len(m.state.EthernetDevices)) - copy(devices, m.state.EthernetDevices) - return devices -} - -func (m *Manager) activateConnection(uuid string) error { - return m.backend.ActivateWiredConnection(uuid) -} - -func (m *Manager) ListVPNProfiles() ([]VPNProfile, error) { - return m.backend.ListVPNProfiles() -} - -func (m *Manager) ListActiveVPN() ([]VPNActive, error) { - return m.backend.ListActiveVPN() -} - -func (m *Manager) ConnectVPN(uuidOrName string, singleActive bool) error { - return m.backend.ConnectVPN(uuidOrName, singleActive) -} - -func (m *Manager) DisconnectVPN(uuidOrName string) error { - return m.backend.DisconnectVPN(uuidOrName) -} - -func (m *Manager) DisconnectAllVPN() error { - return m.backend.DisconnectAllVPN() -} - -func (m *Manager) ClearVPNCredentials(uuidOrName string) error { - return m.backend.ClearVPNCredentials(uuidOrName) -} - -func (m *Manager) ListVPNPlugins() ([]VPNPlugin, error) { - return m.backend.ListVPNPlugins() -} - -func (m *Manager) ImportVPN(filePath string, name string) (*VPNImportResult, error) { - return m.backend.ImportVPN(filePath, name) -} - -func (m *Manager) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { - return m.backend.GetVPNConfig(uuidOrName) -} - -func (m *Manager) UpdateVPNConfig(uuid string, updates map[string]any) error { - return m.backend.UpdateVPNConfig(uuid, updates) -} - -func (m *Manager) DeleteVPN(uuidOrName string) error { - return m.backend.DeleteVPN(uuidOrName) -} - -func (m *Manager) SetVPNCredentials(uuid, username, password string, save bool) error { - return m.backend.SetVPNCredentials(uuid, username, password, save) -} - -func (m *Manager) SetWiFiAutoconnect(ssid string, autoconnect bool) error { - return m.backend.SetWiFiAutoconnect(ssid, autoconnect) -} - -func (m *Manager) GetWiFiDevices() []WiFiDevice { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - devices := make([]WiFiDevice, len(m.state.WiFiDevices)) - copy(devices, m.state.WiFiDevices) - return devices -} - -func (m *Manager) ScanWiFiDevice(device string) error { - return m.backend.ScanWiFiDevice(device) -} - -func (m *Manager) DisconnectWiFiDevice(device string) error { - return m.backend.DisconnectWiFiDevice(device) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager_test.go deleted file mode 100644 index 79545c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/manager_test.go +++ /dev/null @@ -1,191 +0,0 @@ -package network - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestManager_GetState(t *testing.T) { - state := &NetworkState{ - NetworkStatus: StatusWiFi, - WiFiSSID: "TestNetwork", - WiFiConnected: true, - } - - manager := &Manager{ - state: state, - stateMutex: sync.RWMutex{}, - } - - result := manager.GetState() - assert.Equal(t, StatusWiFi, result.NetworkStatus) - assert.Equal(t, "TestNetwork", result.WiFiSSID) - assert.True(t, result.WiFiConnected) -} - -func TestManager_NotifySubscribers(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - NetworkStatus: StatusWiFi, - }, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - manager.notifierWg.Add(1) - go manager.notifier() - - ch := make(chan NetworkState, 10) - manager.subscribers.Store("test-client", ch) - - manager.notifySubscribers() - - select { - case state := <-ch: - assert.Equal(t, StatusWiFi, state.NetworkStatus) - case <-time.After(200 * time.Millisecond): - t.Fatal("did not receive state update") - } - - close(manager.stopChan) - manager.notifierWg.Wait() -} - -func TestManager_NotifySubscribers_Debounce(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - NetworkStatus: StatusWiFi, - }, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - manager.notifierWg.Add(1) - go manager.notifier() - - ch := make(chan NetworkState, 10) - manager.subscribers.Store("test-client", ch) - - manager.notifySubscribers() - manager.notifySubscribers() - manager.notifySubscribers() - - receivedCount := 0 - timeout := time.After(200 * time.Millisecond) - for { - select { - case <-ch: - receivedCount++ - case <-timeout: - assert.Equal(t, 1, receivedCount, "should receive exactly one debounced update") - close(manager.stopChan) - manager.notifierWg.Wait() - return - } - } -} - -func TestManager_Close(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - stateMutex: sync.RWMutex{}, - stopChan: make(chan struct{}), - } - - ch1 := make(chan NetworkState, 1) - ch2 := make(chan NetworkState, 1) - manager.subscribers.Store("client1", ch1) - manager.subscribers.Store("client2", ch2) - - manager.Close() - - select { - case <-manager.stopChan: - case <-time.After(100 * time.Millisecond): - t.Fatal("stopChan not closed") - } - - _, ok1 := <-ch1 - _, ok2 := <-ch2 - assert.False(t, ok1, "ch1 should be closed") - assert.False(t, ok2, "ch2 should be closed") - - count := 0 - manager.subscribers.Range(func(key string, ch chan NetworkState) bool { count++; return true }) - assert.Equal(t, 0, count) -} - -func TestManager_Subscribe(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - ch := manager.Subscribe("test-client") - assert.NotNil(t, ch) - assert.Equal(t, 64, cap(ch)) - - _, exists := manager.subscribers.Load("test-client") - assert.True(t, exists) -} - -func TestManager_Unsubscribe(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - ch := manager.Subscribe("test-client") - - manager.Unsubscribe("test-client") - - _, ok := <-ch - assert.False(t, ok) - - _, exists := manager.subscribers.Load("test-client") - assert.False(t, exists) -} - -func TestNewManager(t *testing.T) { - t.Run("attempts to create manager", func(t *testing.T) { - manager, err := NewManager() - if err != nil { - assert.Nil(t, manager) - } else { - assert.NotNil(t, manager) - assert.NotNil(t, manager.state) - assert.NotNil(t, manager.subscribers) - assert.NotNil(t, manager.stopChan) - - manager.Close() - } - }) -} - -func TestManager_GetState_ThreadSafe(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - NetworkStatus: StatusWiFi, - WiFiSSID: "TestNetwork", - }, - stateMutex: sync.RWMutex{}, - } - - done := make(chan bool) - for i := 0; i < 10; i++ { - go func() { - state := manager.GetState() - assert.Equal(t, StatusWiFi, state.NetworkStatus) - done <- true - }() - } - - for i := 0; i < 10; i++ { - select { - case <-done: - case <-time.After(1 * time.Second): - t.Fatal("timeout waiting for goroutines") - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/monitor.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/monitor.go deleted file mode 100644 index 1ae2e9d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/monitor.go +++ /dev/null @@ -1 +0,0 @@ -package network diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority.go deleted file mode 100644 index 8ee7fdf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority.go +++ /dev/null @@ -1,187 +0,0 @@ -package network - -import ( - "fmt" - "os/exec" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - priorityHigh = int32(100) - priorityLow = int32(10) - priorityDefault = int32(0) - - metricPreferred = int64(100) - metricNonPreferred = int64(300) - metricDefault = int64(100) -) - -func (m *Manager) SetConnectionPreference(pref ConnectionPreference) error { - switch pref { - case PreferenceWiFi, PreferenceEthernet, PreferenceAuto: - default: - return fmt.Errorf("invalid preference: %s", pref) - } - - m.stateMutex.Lock() - m.state.Preference = pref - m.stateMutex.Unlock() - - if _, ok := m.backend.(*NetworkManagerBackend); !ok { - m.notifySubscribers() - return nil - } - - switch pref { - case PreferenceWiFi: - return m.prioritizeWiFi() - case PreferenceEthernet: - return m.prioritizeEthernet() - case PreferenceAuto: - return m.balancePriorities() - } - - return nil -} - -func (m *Manager) prioritizeWiFi() error { - if err := m.setConnectionPriority("802-11-wireless", priorityHigh, metricPreferred); err != nil { - log.Warnf("Failed to set WiFi priority: %v", err) - } - - if err := m.setConnectionPriority("802-3-ethernet", priorityLow, metricNonPreferred); err != nil { - log.Warnf("Failed to set Ethernet priority: %v", err) - } - - m.reapplyActiveConnections() - m.notifySubscribers() - return nil -} - -func (m *Manager) prioritizeEthernet() error { - if err := m.setConnectionPriority("802-3-ethernet", priorityHigh, metricPreferred); err != nil { - log.Warnf("Failed to set Ethernet priority: %v", err) - } - - if err := m.setConnectionPriority("802-11-wireless", priorityLow, metricNonPreferred); err != nil { - log.Warnf("Failed to set WiFi priority: %v", err) - } - - m.reapplyActiveConnections() - m.notifySubscribers() - return nil -} - -func (m *Manager) balancePriorities() error { - if err := m.setConnectionPriority("802-3-ethernet", priorityDefault, metricDefault); err != nil { - log.Warnf("Failed to reset Ethernet priority: %v", err) - } - - if err := m.setConnectionPriority("802-11-wireless", priorityDefault, metricDefault); err != nil { - log.Warnf("Failed to reset WiFi priority: %v", err) - } - - m.reapplyActiveConnections() - m.notifySubscribers() - return nil -} - -func (m *Manager) reapplyActiveConnections() { - m.stateMutex.RLock() - ethDev := m.state.EthernetDevice - wifiDev := m.state.WiFiDevice - m.stateMutex.RUnlock() - - if ethDev != "" { - exec.Command("nmcli", "dev", "reapply", ethDev).Run() - } - if wifiDev != "" { - exec.Command("nmcli", "dev", "reapply", wifiDev).Run() - } -} - -func (m *Manager) setConnectionPriority(connType string, autoconnectPriority int32, routeMetric int64) error { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return fmt.Errorf("failed to connect to system bus: %w", err) - } - defer conn.Close() - - settingsObj := conn.Object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings") - - var connPaths []dbus.ObjectPath - if err := settingsObj.Call("org.freedesktop.NetworkManager.Settings.ListConnections", 0).Store(&connPaths); err != nil { - return fmt.Errorf("failed to list connections: %w", err) - } - - for _, connPath := range connPaths { - connObj := conn.Object("org.freedesktop.NetworkManager", connPath) - - var settings map[string]map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&settings); err != nil { - continue - } - - connSection, ok := settings["connection"] - if !ok { - continue - } - - typeVariant, ok := connSection["type"] - if !ok { - continue - } - - cType, ok := typeVariant.Value().(string) - if !ok || cType != connType { - continue - } - - connName := "" - if idVariant, ok := connSection["id"]; ok { - connName, _ = idVariant.Value().(string) - } - - if connName == "" { - continue - } - - if err := exec.Command("nmcli", "con", "mod", connName, - "connection.autoconnect-priority", fmt.Sprintf("%d", autoconnectPriority), - "ipv4.route-metric", fmt.Sprintf("%d", routeMetric), - "ipv6.route-metric", fmt.Sprintf("%d", routeMetric)).Run(); err != nil { - log.Warnf("Failed to set priority for %s: %v", connName, err) - continue - } - - log.Infof("Updated %v: autoconnect-priority=%d, route-metric=%d", connName, autoconnectPriority, routeMetric) - } - - return nil -} - -func (m *Manager) GetConnectionPreference() ConnectionPreference { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return m.state.Preference -} - -func (m *Manager) WasRecentlyFailed(ssid string) bool { - nm, ok := m.backend.(*NetworkManagerBackend) - if !ok { - return false - } - - nm.failedMutex.RLock() - defer nm.failedMutex.RUnlock() - - if nm.lastFailedSSID != ssid { - return false - } - - elapsed := time.Now().Unix() - nm.lastFailedTime - return elapsed < 10 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority_test.go deleted file mode 100644 index c0c65e3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/priority_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestManager_SetConnectionPreference(t *testing.T) { - t.Run("invalid preference", func(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - Preference: PreferenceAuto, - }, - } - - err := manager.SetConnectionPreference(ConnectionPreference("invalid")) - assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid preference") - }) -} - -func TestManager_GetConnectionPreference(t *testing.T) { - tests := []struct { - name string - preference ConnectionPreference - }{ - {"auto", PreferenceAuto}, - {"wifi", PreferenceWiFi}, - {"ethernet", PreferenceEthernet}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - Preference: tt.preference, - }, - } - - result := manager.GetConnectionPreference() - assert.Equal(t, tt.preference, result) - }) - } -} - -// Note: Full testing of priority operations would require mocking NetworkManager -// D-Bus interfaces. The tests above cover the basic logic and error handling. -// Integration tests would be needed for complete coverage of network connection -// priority updates and reactivation. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/subscription_broker.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/subscription_broker.go deleted file mode 100644 index 1b150a2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/subscription_broker.go +++ /dev/null @@ -1,125 +0,0 @@ -package network - -import ( - "context" - "fmt" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type SubscriptionBroker struct { - pending syncmap.Map[string, chan PromptReply] - requests syncmap.Map[string, PromptRequest] - pathSettingToToken syncmap.Map[string, string] - broadcastPrompt func(CredentialPrompt) -} - -func NewSubscriptionBroker(broadcastPrompt func(CredentialPrompt)) PromptBroker { - return &SubscriptionBroker{ - broadcastPrompt: broadcastPrompt, - } -} - -func (b *SubscriptionBroker) Ask(ctx context.Context, req PromptRequest) (string, error) { - pathSettingKey := fmt.Sprintf("%s:%s", req.ConnectionPath, req.SettingName) - - if existingToken, alreadyPending := b.pathSettingToToken.Load(pathSettingKey); alreadyPending { - log.Infof("[SubscriptionBroker] Duplicate prompt for %s, returning existing token", pathSettingKey) - return existingToken, nil - } - - token, err := generateToken() - if err != nil { - return "", err - } - - replyChan := make(chan PromptReply, 1) - b.pending.Store(token, replyChan) - b.requests.Store(token, req) - b.pathSettingToToken.Store(pathSettingKey, token) - - if b.broadcastPrompt != nil { - prompt := CredentialPrompt{ - Token: token, - Name: req.Name, - SSID: req.SSID, - ConnType: req.ConnType, - VpnService: req.VpnService, - Setting: req.SettingName, - Fields: req.Fields, - FieldsInfo: req.FieldsInfo, - Hints: req.Hints, - Reason: req.Reason, - ConnectionId: req.ConnectionId, - ConnectionUuid: req.ConnectionUuid, - } - b.broadcastPrompt(prompt) - } - - return token, nil -} - -func (b *SubscriptionBroker) Wait(ctx context.Context, token string) (PromptReply, error) { - replyChan, exists := b.pending.Load(token) - if !exists { - return PromptReply{}, fmt.Errorf("unknown token: %s", token) - } - - select { - case <-ctx.Done(): - b.cleanup(token) - return PromptReply{}, errdefs.ErrSecretPromptTimeout - case reply := <-replyChan: - b.cleanup(token) - if reply.Cancel { - return reply, errdefs.ErrSecretPromptCancelled - } - return reply, nil - } -} - -func (b *SubscriptionBroker) Resolve(token string, reply PromptReply) error { - replyChan, exists := b.pending.Load(token) - if !exists { - log.Warnf("[SubscriptionBroker] Resolve: unknown or expired token: %s", token) - return fmt.Errorf("unknown or expired token: %s", token) - } - - select { - case replyChan <- reply: - return nil - default: - log.Warnf("[SubscriptionBroker] Resolve: failed to deliver reply for token %s (channel full or closed)", token) - return fmt.Errorf("failed to deliver reply for token: %s", token) - } -} - -func (b *SubscriptionBroker) cleanup(token string) { - if req, exists := b.requests.Load(token); exists { - pathSettingKey := fmt.Sprintf("%s:%s", req.ConnectionPath, req.SettingName) - b.pathSettingToToken.Delete(pathSettingKey) - } - - b.pending.Delete(token) - b.requests.Delete(token) -} - -func (b *SubscriptionBroker) Cancel(path string, setting string) error { - pathSettingKey := fmt.Sprintf("%s:%s", path, setting) - - token, exists := b.pathSettingToToken.Load(pathSettingKey) - if !exists { - log.Infof("[SubscriptionBroker] Cancel: no pending prompt for %s", pathSettingKey) - return nil - } - - log.Infof("[SubscriptionBroker] Cancelling prompt for %s (token=%s)", pathSettingKey, token) - - reply := PromptReply{ - Cancel: true, - } - - return b.Resolve(token, reply) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/testing.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/testing.go deleted file mode 100644 index a6c4a00..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/testing.go +++ /dev/null @@ -1,14 +0,0 @@ -package network - -// NewTestManager creates a Manager for testing with a provided backend -func NewTestManager(backend Backend, state *NetworkState) *Manager { - if state == nil { - state = &NetworkState{} - } - return &Manager{ - backend: backend, - state: state, - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types.go deleted file mode 100644 index 93448cf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types.go +++ /dev/null @@ -1,267 +0,0 @@ -package network - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type NetworkStatus string - -const ( - StatusDisconnected NetworkStatus = "disconnected" - StatusEthernet NetworkStatus = "ethernet" - StatusWiFi NetworkStatus = "wifi" - StatusVPN NetworkStatus = "vpn" -) - -type ConnectionPreference string - -const ( - PreferenceAuto ConnectionPreference = "auto" - PreferenceWiFi ConnectionPreference = "wifi" - PreferenceEthernet ConnectionPreference = "ethernet" -) - -type WiFiNetwork struct { - SSID string `json:"ssid"` - BSSID string `json:"bssid"` - Signal uint8 `json:"signal"` - Secured bool `json:"secured"` - Enterprise bool `json:"enterprise"` - Connected bool `json:"connected"` - Saved bool `json:"saved"` - Autoconnect bool `json:"autoconnect"` - Hidden bool `json:"hidden"` - Frequency uint32 `json:"frequency"` - Mode string `json:"mode"` - Rate uint32 `json:"rate"` - Channel uint32 `json:"channel"` - Device string `json:"device,omitempty"` -} - -type WiFiDevice struct { - Name string `json:"name"` - HwAddress string `json:"hwAddress"` - State string `json:"state"` - Connected bool `json:"connected"` - SSID string `json:"ssid,omitempty"` - BSSID string `json:"bssid,omitempty"` - Signal uint8 `json:"signal,omitempty"` - IP string `json:"ip,omitempty"` - Networks []WiFiNetwork `json:"networks"` -} - -type EthernetDevice struct { - Name string `json:"name"` - HwAddress string `json:"hwAddress"` - State string `json:"state"` - Connected bool `json:"connected"` - IP string `json:"ip,omitempty"` - Speed uint32 `json:"speed,omitempty"` - Driver string `json:"driver,omitempty"` -} - -type VPNProfile struct { - Name string `json:"name"` - UUID string `json:"uuid"` - Type string `json:"type"` - ServiceType string `json:"serviceType"` - RemoteHost string `json:"remoteHost,omitempty"` - Username string `json:"username,omitempty"` - Autoconnect bool `json:"autoconnect"` - Data map[string]string `json:"data,omitempty"` -} - -type VPNActive struct { - Name string `json:"name"` - UUID string `json:"uuid"` - Device string `json:"device,omitempty"` - State string `json:"state,omitempty"` - Type string `json:"type"` - Plugin string `json:"serviceType"` - IP string `json:"ip,omitempty"` - Gateway string `json:"gateway,omitempty"` - RemoteHost string `json:"remoteHost,omitempty"` - Username string `json:"username,omitempty"` - MTU uint32 `json:"mtu,omitempty"` - Data map[string]string `json:"data,omitempty"` -} - -type VPNState struct { - Profiles []VPNProfile `json:"profiles"` - Active []VPNActive `json:"activeConnections"` -} - -type NetworkState struct { - Backend string `json:"backend"` - NetworkStatus NetworkStatus `json:"networkStatus"` - Preference ConnectionPreference `json:"preference"` - EthernetIP string `json:"ethernetIP"` - EthernetDevice string `json:"ethernetDevice"` - EthernetConnected bool `json:"ethernetConnected"` - EthernetConnectionUuid string `json:"ethernetConnectionUuid"` - EthernetDevices []EthernetDevice `json:"ethernetDevices"` - WiFiIP string `json:"wifiIP"` - WiFiDevice string `json:"wifiDevice"` - WiFiConnected bool `json:"wifiConnected"` - WiFiEnabled bool `json:"wifiEnabled"` - WiFiSSID string `json:"wifiSSID"` - WiFiBSSID string `json:"wifiBSSID"` - WiFiSignal uint8 `json:"wifiSignal"` - WiFiNetworks []WiFiNetwork `json:"wifiNetworks"` - WiFiDevices []WiFiDevice `json:"wifiDevices"` - WiredConnections []WiredConnection `json:"wiredConnections"` - VPNProfiles []VPNProfile `json:"vpnProfiles"` - VPNActive []VPNActive `json:"vpnActive"` - IsConnecting bool `json:"isConnecting"` - ConnectingSSID string `json:"connectingSSID"` - ConnectingDevice string `json:"connectingDevice,omitempty"` - LastError string `json:"lastError"` -} - -type ConnectionRequest struct { - SSID string `json:"ssid"` - Password string `json:"password,omitempty"` - Username string `json:"username,omitempty"` - AnonymousIdentity string `json:"anonymousIdentity,omitempty"` - DomainSuffixMatch string `json:"domainSuffixMatch,omitempty"` - Interactive bool `json:"interactive,omitempty"` - Hidden bool `json:"hidden,omitempty"` - Device string `json:"device,omitempty"` - EAPMethod string `json:"eapMethod,omitempty"` - Phase2Auth string `json:"phase2Auth,omitempty"` - CACertPath string `json:"caCertPath,omitempty"` - ClientCertPath string `json:"clientCertPath,omitempty"` - PrivateKeyPath string `json:"privateKeyPath,omitempty"` - UseSystemCACerts *bool `json:"useSystemCACerts,omitempty"` -} - -type WiredConnection struct { - Path dbus.ObjectPath `json:"path"` - ID string `json:"id"` - UUID string `json:"uuid"` - Type string `json:"type"` - IsActive bool `json:"isActive"` -} - -type PriorityUpdate struct { - Preference ConnectionPreference `json:"preference"` -} - -type Manager struct { - backend Backend - state *NetworkState - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan NetworkState] - stopChan chan struct{} - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotifiedState *NetworkState - credentialSubscribers syncmap.Map[string, chan CredentialPrompt] -} - -type EventType string - -const ( - EventStateChanged EventType = "state_changed" - EventNetworksUpdated EventType = "networks_updated" - EventConnecting EventType = "connecting" - EventConnected EventType = "connected" - EventDisconnected EventType = "disconnected" - EventError EventType = "error" -) - -type NetworkEvent struct { - Type EventType `json:"type"` - Data NetworkState `json:"data"` -} - -type PromptRequest struct { - Name string `json:"name"` - SSID string `json:"ssid"` - ConnType string `json:"connType"` - VpnService string `json:"vpnService"` - SettingName string `json:"setting"` - Fields []string `json:"fields"` - FieldsInfo []FieldInfo `json:"fieldsInfo"` - Hints []string `json:"hints"` - Reason string `json:"reason"` - ConnectionId string `json:"connectionId"` - ConnectionUuid string `json:"connectionUuid"` - ConnectionPath string `json:"connectionPath"` -} - -type PromptReply struct { - Secrets map[string]string `json:"secrets"` - Save bool `json:"save"` - Cancel bool `json:"cancel"` -} - -type FieldInfo struct { - Name string `json:"name"` - Label string `json:"label"` - IsSecret bool `json:"isSecret"` -} - -type CredentialPrompt struct { - Token string `json:"token"` - Name string `json:"name"` - SSID string `json:"ssid"` - ConnType string `json:"connType"` - VpnService string `json:"vpnService"` - Setting string `json:"setting"` - Fields []string `json:"fields"` - FieldsInfo []FieldInfo `json:"fieldsInfo"` - Hints []string `json:"hints"` - Reason string `json:"reason"` - ConnectionId string `json:"connectionId"` - ConnectionUuid string `json:"connectionUuid"` -} - -type NetworkInfoResponse struct { - SSID string `json:"ssid"` - Bands []WiFiNetwork `json:"bands"` -} - -type WiredNetworkInfoResponse struct { - UUID string `json:"uuid"` - IFace string `json:"iface"` - Driver string `json:"driver"` - HwAddr string `json:"hwAddr"` - Speed string `json:"speed"` - IPv4 WiredIPConfig `json:"IPv4s"` - IPv6 WiredIPConfig `json:"IPv6s"` -} - -type WiredIPConfig struct { - IPs []string `json:"ips"` - Gateway string `json:"gateway"` - DNS string `json:"dns"` -} - -type VPNPlugin struct { - Name string `json:"name"` - ServiceType string `json:"serviceType"` - Program string `json:"program,omitempty"` - Supports []string `json:"supports,omitempty"` - FileExtensions []string `json:"fileExtensions"` -} - -type VPNConfig struct { - UUID string `json:"uuid"` - Name string `json:"name"` - Type string `json:"type"` - ServiceType string `json:"serviceType,omitempty"` - Autoconnect bool `json:"autoconnect"` - Data map[string]string `json:"data,omitempty"` -} - -type VPNImportResult struct { - Success bool `json:"success"` - UUID string `json:"uuid,omitempty"` - Name string `json:"name,omitempty"` - ServiceType string `json:"serviceType,omitempty"` - Error string `json:"error,omitempty"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types_test.go deleted file mode 100644 index 1c3e0bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/types_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package network - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNetworkStatus_Constants(t *testing.T) { - assert.Equal(t, NetworkStatus("disconnected"), StatusDisconnected) - assert.Equal(t, NetworkStatus("ethernet"), StatusEthernet) - assert.Equal(t, NetworkStatus("wifi"), StatusWiFi) -} - -func TestConnectionPreference_Constants(t *testing.T) { - assert.Equal(t, ConnectionPreference("auto"), PreferenceAuto) - assert.Equal(t, ConnectionPreference("wifi"), PreferenceWiFi) - assert.Equal(t, ConnectionPreference("ethernet"), PreferenceEthernet) -} - -func TestEventType_Constants(t *testing.T) { - assert.Equal(t, EventType("state_changed"), EventStateChanged) - assert.Equal(t, EventType("networks_updated"), EventNetworksUpdated) - assert.Equal(t, EventType("connecting"), EventConnecting) - assert.Equal(t, EventType("connected"), EventConnected) - assert.Equal(t, EventType("disconnected"), EventDisconnected) - assert.Equal(t, EventType("error"), EventError) -} - -func TestWiFiNetwork_JSON(t *testing.T) { - network := WiFiNetwork{ - SSID: "TestNetwork", - BSSID: "00:11:22:33:44:55", - Signal: 85, - Secured: true, - Enterprise: false, - Connected: true, - Saved: true, - Frequency: 2437, - Mode: "infrastructure", - Rate: 300, - Channel: 6, - } - - data, err := json.Marshal(network) - require.NoError(t, err) - - var decoded WiFiNetwork - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, network.SSID, decoded.SSID) - assert.Equal(t, network.BSSID, decoded.BSSID) - assert.Equal(t, network.Signal, decoded.Signal) - assert.Equal(t, network.Secured, decoded.Secured) - assert.Equal(t, network.Enterprise, decoded.Enterprise) - assert.Equal(t, network.Connected, decoded.Connected) - assert.Equal(t, network.Saved, decoded.Saved) - assert.Equal(t, network.Frequency, decoded.Frequency) - assert.Equal(t, network.Mode, decoded.Mode) - assert.Equal(t, network.Rate, decoded.Rate) - assert.Equal(t, network.Channel, decoded.Channel) -} - -func TestNetworkState_JSON(t *testing.T) { - state := NetworkState{ - NetworkStatus: StatusWiFi, - Preference: PreferenceAuto, - EthernetIP: "192.168.1.100", - EthernetDevice: "eth0", - EthernetConnected: false, - WiFiIP: "192.168.1.101", - WiFiDevice: "wlan0", - WiFiConnected: true, - WiFiEnabled: true, - WiFiSSID: "TestNetwork", - WiFiBSSID: "00:11:22:33:44:55", - WiFiSignal: 85, - WiFiNetworks: []WiFiNetwork{ - {SSID: "Network1", Signal: 90}, - {SSID: "Network2", Signal: 60}, - }, - IsConnecting: false, - ConnectingSSID: "", - LastError: "", - } - - data, err := json.Marshal(state) - require.NoError(t, err) - - var decoded NetworkState - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, state.NetworkStatus, decoded.NetworkStatus) - assert.Equal(t, state.Preference, decoded.Preference) - assert.Equal(t, state.WiFiIP, decoded.WiFiIP) - assert.Equal(t, state.WiFiSSID, decoded.WiFiSSID) - assert.Equal(t, len(state.WiFiNetworks), len(decoded.WiFiNetworks)) -} - -func TestConnectionRequest_JSON(t *testing.T) { - t.Run("with password", func(t *testing.T) { - req := ConnectionRequest{ - SSID: "TestNetwork", - Password: "testpass123", - } - - data, err := json.Marshal(req) - require.NoError(t, err) - - var decoded ConnectionRequest - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, req.SSID, decoded.SSID) - assert.Equal(t, req.Password, decoded.Password) - assert.Empty(t, decoded.Username) - }) - - t.Run("with username and password (enterprise)", func(t *testing.T) { - req := ConnectionRequest{ - SSID: "EnterpriseNetwork", - Password: "testpass123", - Username: "testuser", - } - - data, err := json.Marshal(req) - require.NoError(t, err) - - var decoded ConnectionRequest - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, req.SSID, decoded.SSID) - assert.Equal(t, req.Password, decoded.Password) - assert.Equal(t, req.Username, decoded.Username) - }) -} - -func TestPriorityUpdate_JSON(t *testing.T) { - update := PriorityUpdate{ - Preference: PreferenceWiFi, - } - - data, err := json.Marshal(update) - require.NoError(t, err) - - var decoded PriorityUpdate - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, update.Preference, decoded.Preference) -} - -func TestNetworkEvent_JSON(t *testing.T) { - event := NetworkEvent{ - Type: EventStateChanged, - Data: NetworkState{ - NetworkStatus: StatusWiFi, - WiFiSSID: "TestNetwork", - WiFiConnected: true, - }, - } - - data, err := json.Marshal(event) - require.NoError(t, err) - - var decoded NetworkEvent - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, event.Type, decoded.Type) - assert.Equal(t, event.Data.NetworkStatus, decoded.Data.NetworkStatus) - assert.Equal(t, event.Data.WiFiSSID, decoded.Data.WiFiSSID) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_qrcode.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_qrcode.go deleted file mode 100644 index 680b6d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_qrcode.go +++ /dev/null @@ -1,59 +0,0 @@ -package network - -import ( - "fmt" - "path/filepath" - "regexp" - "strings" -) - -const qrCodeTmpPrefix = "/tmp/dank-wifi-qrcode-" - -func FormatWiFiQRString(securityType, ssid, password string) string { - return fmt.Sprintf("WIFI:T:%s;S:%s;P:%s;;", securityType, ssid, password) -} - -func qrCodePaths(ssid string) (themed, normal string) { - safe := sanitizeSSIDForPath(ssid) - themed = fmt.Sprintf("%s%s-themed.png", qrCodeTmpPrefix, safe) - normal = fmt.Sprintf("%s%s-normal.png", qrCodeTmpPrefix, safe) - return -} - -func isValidQRCodePath(path string) bool { - clean := filepath.Clean(path) - return strings.HasPrefix(clean, qrCodeTmpPrefix) && strings.HasSuffix(clean, ".png") -} - -var safePathChar = regexp.MustCompile(`[^a-zA-Z0-9_-]`) - -func sanitizeSSIDForPath(ssid string) string { - return safePathChar.ReplaceAllString(ssid, "_") -} - -var iwdVerbatimSSID = regexp.MustCompile(`^[a-zA-Z0-9 _-]+$`) - -func iwdConfigPath(ssid string) string { - switch { - case iwdVerbatimSSID.MatchString(ssid): - return fmt.Sprintf("/var/lib/iwd/%s.psk", ssid) - default: - return fmt.Sprintf("/var/lib/iwd/=%x.psk", []byte(ssid)) - } -} - -func parseIWDPassphrase(data string) (string, error) { - inSecurity := false - for _, line := range strings.Split(data, "\n") { - line = strings.TrimSpace(line) - switch { - case line == "[Security]": - inSecurity = true - case strings.HasPrefix(line, "["): - inSecurity = false - case inSecurity && strings.HasPrefix(line, "Passphrase="): - return strings.TrimPrefix(line, "Passphrase="), nil - } - } - return "", fmt.Errorf("no passphrase found in iwd config") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_test.go deleted file mode 100644 index 2256b60..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wifi_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFrequencyToChannel(t *testing.T) { - tests := []struct { - name string - frequency uint32 - channel uint32 - }{ - {"2.4 GHz channel 1", 2412, 1}, - {"2.4 GHz channel 6", 2437, 6}, - {"2.4 GHz channel 11", 2462, 11}, - {"2.4 GHz channel 14", 2484, 14}, - {"5 GHz channel 36", 5180, 36}, - {"5 GHz channel 40", 5200, 40}, - {"5 GHz channel 165", 5825, 165}, - {"6 GHz channel 1", 5955, 1}, - {"6 GHz channel 233", 7115, 233}, - {"Unknown frequency", 1000, 0}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := frequencyToChannel(tt.frequency) - assert.Equal(t, tt.channel, result) - }) - } -} - -func TestSortWiFiNetworks(t *testing.T) { - t.Run("connected network comes first", func(t *testing.T) { - networks := []WiFiNetwork{ - {SSID: "Network1", Signal: 90, Connected: false}, - {SSID: "Network2", Signal: 80, Connected: true}, - {SSID: "Network3", Signal: 70, Connected: false}, - } - - sortWiFiNetworks(networks) - - assert.Equal(t, "Network2", networks[0].SSID) - assert.True(t, networks[0].Connected) - }) - - t.Run("sorts by signal strength", func(t *testing.T) { - networks := []WiFiNetwork{ - {SSID: "Weak", Signal: 40, Secured: true}, - {SSID: "Strong", Signal: 90, Secured: true}, - {SSID: "Medium", Signal: 60, Secured: true}, - } - - sortWiFiNetworks(networks) - - assert.Equal(t, "Strong", networks[0].SSID) - assert.Equal(t, "Medium", networks[1].SSID) - assert.Equal(t, "Weak", networks[2].SSID) - }) - - t.Run("prioritizes open networks with good signal", func(t *testing.T) { - networks := []WiFiNetwork{ - {SSID: "SecureWeak", Signal: 40, Secured: true}, - {SSID: "OpenStrong", Signal: 60, Secured: false}, - {SSID: "SecureStrong", Signal: 90, Secured: true}, - } - - sortWiFiNetworks(networks) - - assert.Equal(t, "OpenStrong", networks[0].SSID) - - openIdx := -1 - weakSecureIdx := -1 - for i, n := range networks { - if n.SSID == "OpenStrong" { - openIdx = i - } - if n.SSID == "SecureWeak" { - weakSecureIdx = i - } - } - assert.Less(t, openIdx, weakSecureIdx, "OpenStrong should come before SecureWeak") - }) - - t.Run("prioritizes saved networks after connected", func(t *testing.T) { - networks := []WiFiNetwork{ - {SSID: "UnsavedStrong", Signal: 95, Saved: false}, - {SSID: "SavedMedium", Signal: 60, Saved: true}, - {SSID: "SavedWeak", Signal: 50, Saved: true}, - {SSID: "UnsavedMedium", Signal: 70, Saved: false}, - } - - sortWiFiNetworks(networks) - - assert.Equal(t, "SavedMedium", networks[0].SSID) - assert.Equal(t, "SavedWeak", networks[1].SSID) - assert.Equal(t, "UnsavedStrong", networks[2].SSID) - assert.Equal(t, "UnsavedMedium", networks[3].SSID) - }) -} - -func TestManager_GetWiFiNetworks(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - WiFiNetworks: []WiFiNetwork{ - {SSID: "Network1", Signal: 90}, - {SSID: "Network2", Signal: 80}, - }, - }, - } - - networks := manager.GetWiFiNetworks() - - assert.Len(t, networks, 2) - assert.Equal(t, "Network1", networks[0].SSID) - assert.Equal(t, "Network2", networks[1].SSID) - - networks[0].SSID = "Modified" - assert.Equal(t, "Network1", manager.state.WiFiNetworks[0].SSID) -} - -func TestManager_GetNetworkInfo(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - WiFiNetworks: []WiFiNetwork{ - {SSID: "Network1", Signal: 90, BSSID: "00:11:22:33:44:55"}, - {SSID: "Network2", Signal: 80, BSSID: "AA:BB:CC:DD:EE:FF"}, - }, - }, - } - - t.Run("finds existing network", func(t *testing.T) { - network, err := manager.GetNetworkInfo("Network1") - assert.NoError(t, err) - assert.NotNil(t, network) - assert.Equal(t, "Network1", network.SSID) - assert.Equal(t, uint8(90), network.Signal) - }) - - t.Run("returns error for non-existent network", func(t *testing.T) { - network, err := manager.GetNetworkInfo("NonExistent") - assert.Error(t, err) - assert.Nil(t, network) - assert.Contains(t, err.Error(), "network not found") - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wired_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wired_test.go deleted file mode 100644 index 5c346e7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/network/wired_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestManager_GetWiredConfigs(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - EthernetConnected: true, - WiredConnections: []WiredConnection{ - {ID: "Test", IsActive: true}, - }, - }, - } - - configs := manager.GetWiredConfigs() - - assert.Len(t, configs, 1) - assert.Equal(t, "Test", configs[0].ID) -} - -func TestManager_GetEthernetDevices(t *testing.T) { - manager := &Manager{ - state: &NetworkState{ - EthernetDevices: []EthernetDevice{ - {Name: "enp0s3", Connected: true, IP: "192.168.1.100"}, - {Name: "enp0s8", Connected: false}, - }, - }, - } - - devices := manager.GetEthernetDevices() - - assert.Len(t, devices, 2) - assert.Equal(t, "enp0s3", devices[0].Name) - assert.True(t, devices[0].Connected) - assert.Equal(t, "enp0s8", devices[1].Name) - assert.False(t, devices[1].Connected) -} - -func TestManager_GetEthernetDevices_Empty(t *testing.T) { - manager := &Manager{ - state: &NetworkState{}, - } - - devices := manager.GetEthernetDevices() - assert.Empty(t, devices) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params.go deleted file mode 100644 index 1f592c6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params.go +++ /dev/null @@ -1,113 +0,0 @@ -package params - -import "fmt" - -func Get[T any](params map[string]any, key string) (T, error) { - val, ok := params[key].(T) - if !ok { - var zero T - return zero, fmt.Errorf("missing or invalid '%s' parameter", key) - } - return val, nil -} - -func GetOpt[T any](params map[string]any, key string, def T) T { - if val, ok := params[key].(T); ok { - return val - } - return def -} - -func String(params map[string]any, key string) (string, error) { - return Get[string](params, key) -} - -func StringNonEmpty(params map[string]any, key string) (string, error) { - val, err := Get[string](params, key) - if err != nil || val == "" { - return "", fmt.Errorf("missing or invalid '%s' parameter", key) - } - return val, nil -} - -func StringOpt(params map[string]any, key string, def string) string { - return GetOpt(params, key, def) -} - -func Int(params map[string]any, key string) (int, error) { - val, err := Get[float64](params, key) - if err != nil { - return 0, err - } - return int(val), nil -} - -func IntOpt(params map[string]any, key string, def int) int { - if val, ok := params[key].(float64); ok { - return int(val) - } - return def -} - -func Float(params map[string]any, key string) (float64, error) { - return Get[float64](params, key) -} - -func FloatOpt(params map[string]any, key string, def float64) float64 { - return GetOpt(params, key, def) -} - -func Bool(params map[string]any, key string) (bool, error) { - return Get[bool](params, key) -} - -func BoolOpt(params map[string]any, key string, def bool) bool { - return GetOpt(params, key, def) -} - -func StringMap(params map[string]any, key string) (map[string]string, error) { - rawMap, err := Get[map[string]any](params, key) - if err != nil { - return nil, err - } - result := make(map[string]string) - for k, v := range rawMap { - if str, ok := v.(string); ok { - result[k] = str - } - } - return result, nil -} - -func StringMapOpt(params map[string]any, key string) map[string]string { - rawMap, ok := params[key].(map[string]any) - if !ok { - return nil - } - result := make(map[string]string) - for k, v := range rawMap { - if str, ok := v.(string); ok { - result[k] = str - } - } - return result -} - -func Any(params map[string]any, key string) (any, bool) { - val, ok := params[key] - return val, ok -} - -func AnyMap(params map[string]any, key string) (map[string]any, bool) { - val, ok := params[key].(map[string]any) - return val, ok -} - -func StringAlt(params map[string]any, keys ...string) (string, bool) { - for _, key := range keys { - if val, ok := params[key].(string); ok { - return val, true - } - } - return "", false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params_test.go deleted file mode 100644 index 99847ff..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/params/params_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package params - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGet(t *testing.T) { - p := map[string]any{"key": "value"} - val, err := Get[string](p, "key") - assert.NoError(t, err) - assert.Equal(t, "value", val) - - _, err = Get[string](p, "missing") - assert.Error(t, err) - - _, err = Get[int](p, "key") - assert.Error(t, err) -} - -func TestGetOpt(t *testing.T) { - p := map[string]any{"key": "value"} - assert.Equal(t, "value", GetOpt(p, "key", "default")) - assert.Equal(t, "default", GetOpt(p, "missing", "default")) -} - -func TestString(t *testing.T) { - p := map[string]any{"s": "hello", "n": 123} - val, err := String(p, "s") - assert.NoError(t, err) - assert.Equal(t, "hello", val) - - _, err = String(p, "n") - assert.Error(t, err) -} - -func TestStringNonEmpty(t *testing.T) { - p := map[string]any{"s": "hello", "empty": ""} - val, err := StringNonEmpty(p, "s") - assert.NoError(t, err) - assert.Equal(t, "hello", val) - - _, err = StringNonEmpty(p, "empty") - assert.Error(t, err) - - _, err = StringNonEmpty(p, "missing") - assert.Error(t, err) -} - -func TestStringOpt(t *testing.T) { - p := map[string]any{"s": "hello"} - assert.Equal(t, "hello", StringOpt(p, "s", "default")) - assert.Equal(t, "default", StringOpt(p, "missing", "default")) -} - -func TestInt(t *testing.T) { - p := map[string]any{"n": float64(42), "s": "str"} - val, err := Int(p, "n") - assert.NoError(t, err) - assert.Equal(t, 42, val) - - _, err = Int(p, "s") - assert.Error(t, err) -} - -func TestIntOpt(t *testing.T) { - p := map[string]any{"n": float64(42)} - assert.Equal(t, 42, IntOpt(p, "n", 0)) - assert.Equal(t, 99, IntOpt(p, "missing", 99)) -} - -func TestFloat(t *testing.T) { - p := map[string]any{"f": 3.14, "s": "str"} - val, err := Float(p, "f") - assert.NoError(t, err) - assert.Equal(t, 3.14, val) - - _, err = Float(p, "s") - assert.Error(t, err) -} - -func TestFloatOpt(t *testing.T) { - p := map[string]any{"f": 3.14} - assert.Equal(t, 3.14, FloatOpt(p, "f", 0)) - assert.Equal(t, 1.0, FloatOpt(p, "missing", 1.0)) -} - -func TestBool(t *testing.T) { - p := map[string]any{"b": true, "s": "str"} - val, err := Bool(p, "b") - assert.NoError(t, err) - assert.True(t, val) - - _, err = Bool(p, "s") - assert.Error(t, err) -} - -func TestBoolOpt(t *testing.T) { - p := map[string]any{"b": true} - assert.True(t, BoolOpt(p, "b", false)) - assert.True(t, BoolOpt(p, "missing", true)) -} - -func TestStringMap(t *testing.T) { - p := map[string]any{ - "m": map[string]any{"a": "1", "b": "2", "c": 3}, - } - val, err := StringMap(p, "m") - assert.NoError(t, err) - assert.Equal(t, map[string]string{"a": "1", "b": "2"}, val) - - _, err = StringMap(p, "missing") - assert.Error(t, err) -} - -func TestStringMapOpt(t *testing.T) { - p := map[string]any{ - "m": map[string]any{"a": "1"}, - } - assert.Equal(t, map[string]string{"a": "1"}, StringMapOpt(p, "m")) - assert.Nil(t, StringMapOpt(p, "missing")) -} - -func TestAny(t *testing.T) { - p := map[string]any{"k": 123} - val, ok := Any(p, "k") - assert.True(t, ok) - assert.Equal(t, 123, val) - - _, ok = Any(p, "missing") - assert.False(t, ok) -} - -func TestAnyMap(t *testing.T) { - inner := map[string]any{"nested": true} - p := map[string]any{"m": inner} - val, ok := AnyMap(p, "m") - assert.True(t, ok) - assert.Equal(t, inner, val) - - _, ok = AnyMap(p, "missing") - assert.False(t, ok) -} - -func TestStringAlt(t *testing.T) { - p := map[string]any{"b": "found"} - val, ok := StringAlt(p, "a", "b", "c") - assert.True(t, ok) - assert.Equal(t, "found", val) - - _, ok = StringAlt(p, "x", "y") - assert.False(t, ok) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers.go deleted file mode 100644 index 33f6564..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers.go +++ /dev/null @@ -1,27 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request) { - switch req.Method { - case "plugins.list": - HandleList(conn, req) - case "plugins.listInstalled": - HandleListInstalled(conn, req) - case "plugins.install": - HandleInstall(conn, req) - case "plugins.uninstall": - HandleUninstall(conn, req) - case "plugins.update": - HandleUpdate(conn, req) - case "plugins.search": - HandleSearch(conn, req) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers_test.go deleted file mode 100644 index 70202e3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/handlers_test.go +++ /dev/null @@ -1,196 +0,0 @@ -package plugins - -import ( - "encoding/json" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/net" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestHandleList(t *testing.T) { - conn := net.NewMockConn(t) - conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.list", - Params: map[string]any{}, - } - - HandleList(conn, req) -} - -func TestHandleListInstalled(t *testing.T) { - conn := net.NewMockConn(t) - conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.listInstalled", - Params: map[string]any{}, - } - - HandleListInstalled(conn, req) -} - -func TestHandleInstallMissingName(t *testing.T) { - conn := net.NewMockConn(t) - var written []byte - conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) { - written = b - return len(b), nil - }).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.install", - Params: map[string]any{}, - } - - HandleInstall(conn, req) - - var resp models.Response[SuccessResult] - err := json.Unmarshal(written, &resp) - assert.NoError(t, err) - assert.NotEmpty(t, resp.Error) - assert.Contains(t, resp.Error, "missing or invalid 'name' parameter") -} - -func TestHandleInstallInvalidName(t *testing.T) { - conn := net.NewMockConn(t) - var written []byte - conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) { - written = b - return len(b), nil - }).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.install", - Params: map[string]any{ - "name": 123, - }, - } - - HandleInstall(conn, req) - - var resp models.Response[SuccessResult] - err := json.Unmarshal(written, &resp) - assert.NoError(t, err) - assert.NotEmpty(t, resp.Error) -} - -func TestHandleUninstallMissingName(t *testing.T) { - conn := net.NewMockConn(t) - var written []byte - conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) { - written = b - return len(b), nil - }).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.uninstall", - Params: map[string]any{}, - } - - HandleUninstall(conn, req) - - var resp models.Response[SuccessResult] - err := json.Unmarshal(written, &resp) - assert.NoError(t, err) - assert.NotEmpty(t, resp.Error) -} - -func TestHandleUpdateMissingName(t *testing.T) { - conn := net.NewMockConn(t) - var written []byte - conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) { - written = b - return len(b), nil - }).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.update", - Params: map[string]any{}, - } - - HandleUpdate(conn, req) - - var resp models.Response[SuccessResult] - err := json.Unmarshal(written, &resp) - assert.NoError(t, err) - assert.NotEmpty(t, resp.Error) -} - -func TestHandleSearchMissingQuery(t *testing.T) { - conn := net.NewMockConn(t) - var written []byte - conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) { - written = b - return len(b), nil - }).Maybe() - - req := models.Request{ - ID: 123, - Method: "plugins.search", - Params: map[string]any{}, - } - - HandleSearch(conn, req) - - var resp models.Response[[]PluginInfo] - err := json.Unmarshal(written, &resp) - assert.NoError(t, err) - assert.NotEmpty(t, resp.Error) -} - -func TestSortPluginInfoByFirstParty(t *testing.T) { - plugins := []PluginInfo{ - {Name: "third-party", Repo: "https://github.com/other/test"}, - {Name: "first-party", Repo: "https://github.com/AvengeMedia/test"}, - } - - SortPluginInfoByFirstParty(plugins) - - assert.Equal(t, "first-party", plugins[0].Name) - assert.Equal(t, "third-party", plugins[1].Name) -} - -func TestPluginInfoJSON(t *testing.T) { - info := PluginInfo{ - Name: "test", - Description: "test description", - Installed: true, - FirstParty: true, - } - - data, err := json.Marshal(info) - assert.NoError(t, err) - - var unmarshaled PluginInfo - err = json.Unmarshal(data, &unmarshaled) - assert.NoError(t, err) - assert.Equal(t, info.Name, unmarshaled.Name) - assert.Equal(t, info.Installed, unmarshaled.Installed) -} - -func TestSuccessResult(t *testing.T) { - result := SuccessResult{ - Success: true, - Message: "test message", - } - - data, err := json.Marshal(result) - assert.NoError(t, err) - - var unmarshaled SuccessResult - err = json.Unmarshal(data, &unmarshaled) - assert.NoError(t, err) - assert.True(t, unmarshaled.Success) - assert.Equal(t, "test message", unmarshaled.Message) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/install.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/install.go deleted file mode 100644 index 2c13a0e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/install.go +++ /dev/null @@ -1,69 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleInstall(conn net.Conn, req models.Request) { - idOrName, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - pluginList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err)) - return - } - - // First, try to find by ID (preferred method) - var plugin *plugins.Plugin - for _, p := range pluginList { - if p.ID == idOrName { - plugin = &p - break - } - } - - // Fallback to name for backward compatibility - if plugin == nil { - for _, p := range pluginList { - if p.Name == idOrName { - plugin = &p - break - } - } - } - - if plugin == nil { - models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", idOrName)) - return - } - - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - if err := manager.Install(*plugin); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to install plugin: %v", err)) - return - } - - models.Respond(conn, req.ID, SuccessResult{ - Success: true, - Message: fmt.Sprintf("plugin installed: %s", plugin.Name), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list.go deleted file mode 100644 index e44d034..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list.go +++ /dev/null @@ -1,53 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleList(conn net.Conn, req models.Request) { - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - pluginList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err)) - return - } - - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - result := make([]PluginInfo, len(pluginList)) - for i, p := range pluginList { - installed, _ := manager.IsInstalled(p) - result[i] = PluginInfo{ - ID: p.ID, - Name: p.Name, - Category: p.Category, - Author: p.Author, - Description: p.Description, - Repo: p.Repo, - Path: p.Path, - Capabilities: p.Capabilities, - Compositors: p.Compositors, - Dependencies: p.Dependencies, - Installed: installed, - FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"), - Featured: p.Featured, - RequiresDMS: p.RequiresDMS, - } - } - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list_installed.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list_installed.go deleted file mode 100644 index b771b0e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/list_installed.go +++ /dev/null @@ -1,77 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleListInstalled(conn net.Conn, req models.Request) { - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - installedNames, err := manager.ListInstalled() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list installed plugins: %v", err)) - return - } - - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - allPlugins, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err)) - return - } - - pluginMap := make(map[string]plugins.Plugin) - for _, p := range allPlugins { - pluginMap[p.ID] = p - } - - result := make([]PluginInfo, 0, len(installedNames)) - for _, id := range installedNames { - if plugin, ok := pluginMap[id]; ok { - hasUpdate := false - if hasUpdates, err := manager.HasUpdates(id, plugin); err == nil { - hasUpdate = hasUpdates - } - - result = append(result, PluginInfo{ - ID: plugin.ID, - Name: plugin.Name, - Category: plugin.Category, - Author: plugin.Author, - Description: plugin.Description, - Repo: plugin.Repo, - Path: plugin.Path, - Capabilities: plugin.Capabilities, - Compositors: plugin.Compositors, - Dependencies: plugin.Dependencies, - FirstParty: strings.HasPrefix(plugin.Repo, "https://github.com/AvengeMedia"), - HasUpdate: hasUpdate, - RequiresDMS: plugin.RequiresDMS, - }) - } else { - result = append(result, PluginInfo{ - ID: id, - Name: id, - Note: "not in registry", - }) - } - } - - SortPluginInfoByFirstParty(result) - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/search.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/search.go deleted file mode 100644 index 9dbea6d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/search.go +++ /dev/null @@ -1,74 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleSearch(conn net.Conn, req models.Request) { - query, ok := models.Get[string](req, "query") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'query' parameter") - return - } - - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - pluginList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err)) - return - } - - searchResults := plugins.FuzzySearch(query, pluginList) - - if category := models.GetOr(req, "category", ""); category != "" { - searchResults = plugins.FilterByCategory(category, searchResults) - } - - if compositor := models.GetOr(req, "compositor", ""); compositor != "" { - searchResults = plugins.FilterByCompositor(compositor, searchResults) - } - - if capability := models.GetOr(req, "capability", ""); capability != "" { - searchResults = plugins.FilterByCapability(capability, searchResults) - } - - searchResults = plugins.SortByFirstParty(searchResults) - - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - result := make([]PluginInfo, len(searchResults)) - for i, p := range searchResults { - installed, _ := manager.IsInstalled(p) - result[i] = PluginInfo{ - ID: p.ID, - Name: p.Name, - Category: p.Category, - Author: p.Author, - Description: p.Description, - Repo: p.Repo, - Path: p.Path, - Capabilities: p.Capabilities, - Compositors: p.Compositors, - Dependencies: p.Dependencies, - Installed: installed, - FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"), - RequiresDMS: p.RequiresDMS, - } - } - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/types.go deleted file mode 100644 index 8290f72..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/types.go +++ /dev/null @@ -1,25 +0,0 @@ -package plugins - -type PluginInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Category string `json:"category,omitempty"` - Author string `json:"author,omitempty"` - Description string `json:"description,omitempty"` - Repo string `json:"repo,omitempty"` - Path string `json:"path,omitempty"` - Capabilities []string `json:"capabilities,omitempty"` - Compositors []string `json:"compositors,omitempty"` - Dependencies []string `json:"dependencies,omitempty"` - Installed bool `json:"installed,omitempty"` - FirstParty bool `json:"firstParty,omitempty"` - Featured bool `json:"featured,omitempty"` - Note string `json:"note,omitempty"` - HasUpdate bool `json:"hasUpdate,omitempty"` - RequiresDMS string `json:"requires_dms,omitempty"` -} - -type SuccessResult struct { - Success bool `json:"success"` - Message string `json:"message"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/uninstall.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/uninstall.go deleted file mode 100644 index 7a3d698..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/uninstall.go +++ /dev/null @@ -1,66 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleUninstall(conn net.Conn, req models.Request) { - name, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - // First try to find in registry (by name or ID) - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - pluginList, _ := registry.List() - plugin := plugins.FindByIDOrName(name, pluginList) - - // If found in registry, use that - if plugin != nil { - installed, err := manager.IsInstalled(*plugin) - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err)) - return - } - if !installed { - models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name)) - return - } - if err := manager.Uninstall(*plugin); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to uninstall plugin: %v", err)) - return - } - models.Respond(conn, req.ID, SuccessResult{ - Success: true, - Message: fmt.Sprintf("plugin uninstalled: %s", plugin.Name), - }) - return - } - - // Not in registry - try to find and uninstall from installed plugins directly - if err := manager.UninstallByIDOrName(name); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name)) - return - } - - models.Respond(conn, req.ID, SuccessResult{ - Success: true, - Message: fmt.Sprintf("plugin uninstalled: %s", name), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/update.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/update.go deleted file mode 100644 index 4ea762a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/update.go +++ /dev/null @@ -1,64 +0,0 @@ -package plugins - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleUpdate(conn net.Conn, req models.Request) { - name, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - manager, err := plugins.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - registry, err := plugins.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - pluginList, _ := registry.List() - plugin := plugins.FindByIDOrName(name, pluginList) - - if plugin != nil { - installed, err := manager.IsInstalled(*plugin) - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err)) - return - } - if !installed { - models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name)) - return - } - if err := manager.Update(*plugin); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to update plugin: %v", err)) - return - } - models.Respond(conn, req.ID, SuccessResult{ - Success: true, - Message: fmt.Sprintf("plugin updated: %s", plugin.Name), - }) - return - } - - // Not in registry - try to update from installed plugins directly - if err := manager.UpdateByIDOrName(name); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name)) - return - } - - models.Respond(conn, req.ID, SuccessResult{ - Success: true, - Message: fmt.Sprintf("plugin updated: %s", name), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/utils.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/utils.go deleted file mode 100644 index 8b89f44..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/plugins/utils.go +++ /dev/null @@ -1,17 +0,0 @@ -package plugins - -import ( - "sort" - "strings" -) - -func SortPluginInfoByFirstParty(pluginInfos []PluginInfo) { - sort.SliceStable(pluginInfos, func(i, j int) bool { - isFirstPartyI := strings.HasPrefix(pluginInfos[i].Repo, "https://github.com/AvengeMedia") - isFirstPartyJ := strings.HasPrefix(pluginInfos[j].Repo, "https://github.com/AvengeMedia") - if isFirstPartyI != isFirstPartyJ { - return isFirstPartyI - } - return false - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/router.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/router.go deleted file mode 100644 index 6b8c10b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/router.go +++ /dev/null @@ -1,250 +0,0 @@ -package server - -import ( - "fmt" - "net" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/apppicker" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/bluez" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups" - serverDbus "github.com/AvengeMedia/DankMaterialShell/core/internal/server/dbus" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/dwl" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/evdev" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/extworkspace" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/freedesktop" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/location" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - serverPlugins "github.com/AvengeMedia/DankMaterialShell/core/internal/server/plugins" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/thememode" - serverThemes "github.com/AvengeMedia/DankMaterialShell/core/internal/server/themes" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlroutput" -) - -func RouteRequest(conn net.Conn, req models.Request) { - if strings.HasPrefix(req.Method, "network.") { - if networkManager == nil { - models.RespondError(conn, req.ID, "network manager not initialized") - return - } - network.HandleRequest(conn, req, networkManager) - return - } - - if strings.HasPrefix(req.Method, "plugins.") { - serverPlugins.HandleRequest(conn, req) - return - } - - if strings.HasPrefix(req.Method, "themes.") { - serverThemes.HandleRequest(conn, req) - return - } - - if strings.HasPrefix(req.Method, "theme.auto.") { - if themeModeManager == nil { - models.RespondError(conn, req.ID, "theme mode manager not initialized") - return - } - thememode.HandleRequest(conn, req, themeModeManager) - return - } - - if strings.HasPrefix(req.Method, "loginctl.") { - if loginctlManager == nil { - models.RespondError(conn, req.ID, "loginctl manager not initialized") - return - } - loginctl.HandleRequest(conn, req, loginctlManager) - return - } - - if strings.HasPrefix(req.Method, "freedesktop.") { - if freedesktopManager == nil { - models.RespondError(conn, req.ID, "freedesktop manager not initialized") - return - } - freedesktop.HandleRequest(conn, req, freedesktopManager) - return - } - - if strings.HasPrefix(req.Method, "wayland.") { - if waylandManager == nil { - models.RespondError(conn, req.ID, "wayland manager not initialized") - return - } - wayland.HandleRequest(conn, req, waylandManager) - return - } - - if strings.HasPrefix(req.Method, "bluetooth.") { - if bluezManager == nil { - models.RespondError(conn, req.ID, "bluetooth manager not initialized") - return - } - bluez.HandleRequest(conn, req, bluezManager) - return - } - - if strings.HasPrefix(req.Method, "browser.") || strings.HasPrefix(req.Method, "apppicker.") { - if appPickerManager == nil { - models.RespondError(conn, req.ID, "apppicker manager not initialized") - return - } - apppicker.HandleRequest(conn, req, appPickerManager) - return - } - - if strings.HasPrefix(req.Method, "cups.") { - if cupsManager == nil { - models.RespondError(conn, req.ID, "CUPS manager not initialized") - return - } - cups.HandleRequest(conn, req, cupsManager) - return - } - - if strings.HasPrefix(req.Method, "dwl.") { - if dwlManager == nil { - models.RespondError(conn, req.ID, "dwl manager not initialized") - return - } - dwl.HandleRequest(conn, req, dwlManager) - return - } - - if strings.HasPrefix(req.Method, "brightness.") { - if brightnessManager == nil { - models.RespondError(conn, req.ID, "brightness manager not initialized") - return - } - brightness.HandleRequest(conn, req, brightnessManager) - return - } - - if strings.HasPrefix(req.Method, "extworkspace.") { - if extWorkspaceManager == nil { - if extWorkspaceAvailable.Load() { - extWorkspaceInitMutex.Lock() - if extWorkspaceManager == nil { - if err := InitializeExtWorkspaceManager(); err != nil { - extWorkspaceInitMutex.Unlock() - models.RespondError(conn, req.ID, "extworkspace manager not available") - return - } - } - extWorkspaceInitMutex.Unlock() - } else { - models.RespondError(conn, req.ID, "extworkspace manager not initialized") - return - } - } - extworkspace.HandleRequest(conn, req, extWorkspaceManager) - return - } - - if strings.HasPrefix(req.Method, "wlroutput.") { - if wlrOutputManager == nil { - models.RespondError(conn, req.ID, "wlroutput manager not initialized") - return - } - wlroutput.HandleRequest(conn, req, wlrOutputManager) - return - } - - if strings.HasPrefix(req.Method, "evdev.") { - if evdevManager == nil { - models.RespondError(conn, req.ID, "evdev manager not initialized") - return - } - evdev.HandleRequest(conn, req, evdevManager) - return - } - - if strings.HasPrefix(req.Method, "dbus.") { - if dbusManager == nil { - models.RespondError(conn, req.ID, "dbus manager not initialized") - return - } - serverDbus.HandleRequest(conn, req, dbusManager, dbusClientID) - return - } - - if strings.HasPrefix(req.Method, "clipboard.") { - switch req.Method { - case "clipboard.getConfig": - cfg := clipboard.LoadConfig() - models.Respond(conn, req.ID, cfg) - return - case "clipboard.setConfig": - handleClipboardSetConfig(conn, req) - return - } - if clipboardManager == nil { - models.RespondError(conn, req.ID, "clipboard manager not initialized") - return - } - clipboard.HandleRequest(conn, req, clipboardManager) - return - } - - if strings.HasPrefix(req.Method, "location.") { - if locationManager == nil { - models.RespondError(conn, req.ID, "location manager not initialized") - return - } - location.HandleRequest(conn, req, locationManager) - return - } - - switch req.Method { - case "ping": - models.Respond(conn, req.ID, "pong") - case "getServerInfo": - info := getServerInfo() - models.Respond(conn, req.ID, info) - case "subscribe": - handleSubscribe(conn, req) - case "matugen.queue": - handleMatugenQueue(conn, req) - case "matugen.status": - handleMatugenStatus(conn, req) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleClipboardSetConfig(conn net.Conn, req models.Request) { - cfg := clipboard.LoadConfig() - - if v, ok := models.Get[float64](req, "maxHistory"); ok { - cfg.MaxHistory = int(v) - } - if v, ok := models.Get[float64](req, "maxEntrySize"); ok { - cfg.MaxEntrySize = int64(v) - } - if v, ok := models.Get[float64](req, "autoClearDays"); ok { - cfg.AutoClearDays = int(v) - } - if v, ok := models.Get[bool](req, "clearAtStartup"); ok { - cfg.ClearAtStartup = v - } - if v, ok := models.Get[bool](req, "disabled"); ok { - cfg.Disabled = v - } - if v, ok := models.Get[float64](req, "maxPinned"); ok { - cfg.MaxPinned = int(v) - } - - if err := clipboard.SaveConfig(cfg); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "config updated"}) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server.go deleted file mode 100644 index 58acb62..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server.go +++ /dev/null @@ -1,1758 +0,0 @@ -package server - -import ( - "bufio" - "encoding/json" - "fmt" - "net" - "os" - "path/filepath" - "strconv" - "strings" - "sync" - "sync/atomic" - "syscall" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/apppicker" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/bluez" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/clipboard" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups" - serverDbus "github.com/AvengeMedia/DankMaterialShell/core/internal/server/dbus" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/dwl" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/evdev" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/extworkspace" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/freedesktop" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/location" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/thememode" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/trayrecovery" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlroutput" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -const APIVersion = 24 - -var CLIVersion = "dev" - -type Capabilities struct { - Capabilities []string `json:"capabilities"` -} - -type ServerInfo struct { - APIVersion int `json:"apiVersion"` - CLIVersion string `json:"cliVersion,omitempty"` - Capabilities []string `json:"capabilities"` -} - -type ServiceEvent struct { - Service string `json:"service"` - Data any `json:"data"` -} - -var networkManager *network.Manager -var loginctlManager *loginctl.Manager -var freedesktopManager *freedesktop.Manager -var waylandManager *wayland.Manager -var bluezManager *bluez.Manager -var appPickerManager *apppicker.Manager -var cupsManager *cups.Manager -var dwlManager *dwl.Manager -var extWorkspaceManager *extworkspace.Manager -var brightnessManager *brightness.Manager -var wlrOutputManager *wlroutput.Manager -var evdevManager *evdev.Manager -var clipboardManager *clipboard.Manager -var dbusManager *serverDbus.Manager -var wlContext *wlcontext.SharedContext -var themeModeManager *thememode.Manager -var trayRecoveryManager *trayrecovery.Manager -var locationManager *location.Manager -var geoClientInstance geolocation.Client - -const dbusClientID = "dms-dbus-client" - -var capabilitySubscribers syncmap.Map[string, chan ServerInfo] -var cupsSubscribers syncmap.Map[string, bool] -var cupsSubscriberCount atomic.Int32 -var extWorkspaceAvailable atomic.Bool -var extWorkspaceInitMutex sync.Mutex - -func getSocketDir() string { - if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" { - return runtime - } - - if os.Getuid() == 0 { - if _, err := os.Stat("/run"); err == nil { - return "/run/dankdots" - } - return "/var/run/dankdots" - } - - return os.TempDir() -} - -func GetSocketPath() string { - return filepath.Join(getSocketDir(), fmt.Sprintf("danklinux-%d.sock", os.Getpid())) -} - -func FindSocket() (string, error) { - dir := getSocketDir() - entries, err := os.ReadDir(dir) - if err != nil { - return "", err - } - - for _, entry := range entries { - if strings.HasPrefix(entry.Name(), "danklinux-") && strings.HasSuffix(entry.Name(), ".sock") { - return filepath.Join(dir, entry.Name()), nil - } - } - return "", fmt.Errorf("no dms socket found") -} - -func cleanupStaleSockets() { - dir := getSocketDir() - entries, err := os.ReadDir(dir) - if err != nil { - return - } - - for _, entry := range entries { - if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".sock") { - continue - } - - pidStr := strings.TrimPrefix(entry.Name(), "danklinux-") - pidStr = strings.TrimSuffix(pidStr, ".sock") - pid, err := strconv.Atoi(pidStr) - if err != nil { - continue - } - - process, err := os.FindProcess(pid) - if err != nil { - socketPath := filepath.Join(dir, entry.Name()) - os.Remove(socketPath) - log.Debugf("Removed stale socket: %s", socketPath) - continue - } - - err = process.Signal(syscall.Signal(0)) - if err != nil { - socketPath := filepath.Join(dir, entry.Name()) - os.Remove(socketPath) - log.Debugf("Removed stale socket: %s", socketPath) - } - } -} - -func InitializeNetworkManager() error { - manager, err := network.NewManager() - if err != nil { - log.Warnf("Failed to initialize network manager: %v", err) - return err - } - - networkManager = manager - - log.Info("Network manager initialized") - return nil -} - -func InitializeLoginctlManager() error { - manager, err := loginctl.NewManager() - if err != nil { - log.Warnf("Failed to initialize loginctl manager: %v", err) - return err - } - - loginctlManager = manager - - log.Info("Loginctl manager initialized") - return nil -} - -func InitializeFreedeskManager() error { - manager, err := freedesktop.NewManager() - if err != nil { - log.Warnf("Failed to initialize freedesktop manager: %v", err) - return err - } - - freedesktopManager = manager - - log.Info("Freedesktop manager initialized") - return nil -} - -func InitializeWaylandManager() error { - log.Info("Attempting to initialize Wayland gamma control...") - - if wlContext == nil { - ctx, err := wlcontext.New() - if err != nil { - log.Errorf("Failed to create shared Wayland context: %v", err) - return err - } - wlContext = ctx - } - - config := wayland.DefaultConfig() - manager, err := wayland.NewManager(wlContext.Display(), config) - if err != nil { - log.Errorf("Failed to initialize wayland manager: %v", err) - return err - } - - waylandManager = manager - - log.Info("Wayland gamma control initialized successfully") - return nil -} - -func InitializeBluezManager() error { - manager, err := bluez.NewManager() - if err != nil { - log.Warnf("Failed to initialize bluez manager: %v", err) - return err - } - - bluezManager = manager - - log.Info("Bluez manager initialized") - return nil -} - -func InitializeAppPickerManager() error { - manager := apppicker.NewManager() - appPickerManager = manager - log.Info("AppPicker manager initialized") - return nil -} - -func InitializeCupsManager() error { - manager, err := cups.NewManager() - if err != nil { - log.Warnf("Failed to initialize cups manager: %v", err) - return err - } - - cupsManager = manager - - log.Info("CUPS manager initialized") - return nil -} - -func InitializeDwlManager() error { - log.Info("Attempting to initialize DWL IPC...") - - if wlContext == nil { - ctx, err := wlcontext.New() - if err != nil { - log.Errorf("Failed to create shared Wayland context: %v", err) - return err - } - wlContext = ctx - } - - manager, err := dwl.NewManager(wlContext.Display()) - if err != nil { - log.Debug("Failed to initialize dwl manager: %v", err) - return err - } - - dwlManager = manager - - log.Info("DWL IPC initialized successfully") - return nil -} - -func InitializeBrightnessManager() error { - manager, err := brightness.NewManager() - if err != nil { - log.Warnf("Failed to initialize brightness manager: %v", err) - return err - } - - brightnessManager = manager - - log.Info("Brightness manager initialized") - return nil -} - -func InitializeExtWorkspaceManager() error { - log.Info("Attempting to initialize ExtWorkspace...") - - if wlContext == nil { - ctx, err := wlcontext.New() - if err != nil { - log.Errorf("Failed to create shared Wayland context: %v", err) - return err - } - wlContext = ctx - } - - manager, err := extworkspace.NewManager(wlContext.Display()) - if err != nil { - log.Debug("Failed to initialize extworkspace manager: %v", err) - return err - } - - extWorkspaceManager = manager - - log.Info("ExtWorkspace initialized successfully") - return nil -} - -func InitializeWlrOutputManager() error { - log.Info("Attempting to initialize WlrOutput management...") - - if wlContext == nil { - ctx, err := wlcontext.New() - if err != nil { - log.Errorf("Failed to create shared Wayland context: %v", err) - return err - } - wlContext = ctx - } - - manager, err := wlroutput.NewManager(wlContext.Display()) - if err != nil { - log.Debug("Failed to initialize wlroutput manager: %v", err) - return err - } - - wlrOutputManager = manager - - log.Info("WlrOutput management initialized successfully") - return nil -} - -func InitializeEvdevManager() error { - manager, err := evdev.InitializeManager() - if err != nil { - log.Warnf("Failed to initialize evdev manager: %v", err) - return err - } - - evdevManager = manager - - log.Info("Evdev manager initialized") - return nil -} - -func InitializeClipboardManager() error { - log.Info("Attempting to initialize clipboard manager...") - - if wlContext == nil { - ctx, err := wlcontext.New() - if err != nil { - log.Errorf("Failed to create shared Wayland context: %v", err) - return err - } - wlContext = ctx - } - - config := clipboard.LoadConfig() - manager, err := clipboard.NewManager(wlContext, config) - if err != nil { - log.Errorf("Failed to initialize clipboard manager: %v", err) - return err - } - - clipboardManager = manager - - log.Info("Clipboard manager initialized successfully") - return nil -} - -func InitializeDbusManager() error { - manager, err := serverDbus.NewManager() - if err != nil { - log.Warnf("Failed to initialize dbus manager: %v", err) - return err - } - - dbusManager = manager - - log.Info("DBus manager initialized") - return nil -} - -func InitializeThemeModeManager() error { - manager := thememode.NewManager() - themeModeManager = manager - - log.Info("Theme mode automation manager initialized") - return nil -} - -func InitializeTrayRecoveryManager() error { - manager, err := trayrecovery.NewManager() - if err != nil { - return err - } - - trayRecoveryManager = manager - - log.Info("TrayRecovery manager initialized") - return nil -} - -func InitializeLocationManager(geoClient geolocation.Client) error { - manager, err := location.NewManager(geoClient) - if err != nil { - log.Warnf("Failed to initialize location manager: %v", err) - return err - } - - locationManager = manager - - log.Info("Location manager initialized") - return nil -} - -func handleConnection(conn net.Conn) { - defer conn.Close() - - caps := getCapabilities() - capsData, _ := json.Marshal(caps) - conn.Write(capsData) - conn.Write([]byte("\n")) - scanner := bufio.NewScanner(conn) - for scanner.Scan() { - line := scanner.Bytes() - - var req models.Request - if err := json.Unmarshal(line, &req); err != nil { - log.Warnf("handleConnection: Failed to unmarshal JSON: %v, line: %s", err, string(line)) - models.RespondError(conn, 0, "invalid json") - continue - } - - go RouteRequest(conn, req) - } -} - -func getCapabilities() Capabilities { - caps := []string{"plugins"} - - if networkManager != nil { - caps = append(caps, "network") - } - - if loginctlManager != nil { - caps = append(caps, "loginctl") - } - - if freedesktopManager != nil { - caps = append(caps, "freedesktop") - } - - if waylandManager != nil { - caps = append(caps, "gamma") - } - - if bluezManager != nil { - caps = append(caps, "bluetooth") - } - - if appPickerManager != nil { - caps = append(caps, "browser") - } - - if cupsManager != nil { - caps = append(caps, "cups") - } - - if dwlManager != nil { - caps = append(caps, "dwl") - } - - if extWorkspaceAvailable.Load() { - caps = append(caps, "extworkspace") - } - - if brightnessManager != nil { - caps = append(caps, "brightness") - } - - if wlrOutputManager != nil { - caps = append(caps, "wlroutput") - } - - if evdevManager != nil { - caps = append(caps, "evdev") - } - - if clipboardManager != nil { - caps = append(caps, "clipboard") - } - - if themeModeManager != nil { - caps = append(caps, "theme.auto") - } - - if dbusManager != nil { - caps = append(caps, "dbus") - } - - return Capabilities{Capabilities: caps} -} - -func getServerInfo() ServerInfo { - caps := []string{"plugins"} - - if networkManager != nil { - caps = append(caps, "network") - } - - if loginctlManager != nil { - caps = append(caps, "loginctl") - } - - if freedesktopManager != nil { - caps = append(caps, "freedesktop") - } - - if waylandManager != nil { - caps = append(caps, "gamma") - } - - if bluezManager != nil { - caps = append(caps, "bluetooth") - } - - if appPickerManager != nil { - caps = append(caps, "browser") - } - - if cupsManager != nil { - caps = append(caps, "cups") - } - - if dwlManager != nil { - caps = append(caps, "dwl") - } - - if extWorkspaceAvailable.Load() { - caps = append(caps, "extworkspace") - } - - if brightnessManager != nil { - caps = append(caps, "brightness") - } - - if wlrOutputManager != nil { - caps = append(caps, "wlroutput") - } - - if evdevManager != nil { - caps = append(caps, "evdev") - } - - if clipboardManager != nil { - caps = append(caps, "clipboard") - } - - if themeModeManager != nil { - caps = append(caps, "theme.auto") - } - - if locationManager != nil { - caps = append(caps, "location") - } - - if dbusManager != nil { - caps = append(caps, "dbus") - } - - return ServerInfo{ - APIVersion: APIVersion, - CLIVersion: CLIVersion, - Capabilities: caps, - } -} - -func notifyCapabilityChange() { - info := getServerInfo() - capabilitySubscribers.Range(func(key string, ch chan ServerInfo) bool { - select { - case ch <- info: - default: - } - return true - }) -} - -func handleSubscribe(conn net.Conn, req models.Request) { - clientID := fmt.Sprintf("meta-client-%p", conn) - - var services []string - if servicesParam, ok := models.Get[[]any](req, "services"); ok { - for _, s := range servicesParam { - if str, ok := s.(string); ok { - services = append(services, str) - } - } - } - - if len(services) == 0 { - services = []string{"all"} - } - - subscribeAll := false - for _, s := range services { - if s == "all" { - subscribeAll = true - break - } - } - - var wg sync.WaitGroup - eventChan := make(chan ServiceEvent, 256) - stopChan := make(chan struct{}) - - capChan := make(chan ServerInfo, 64) - capabilitySubscribers.Store(clientID+"-capabilities", capChan) - - wg.Add(1) - go func() { - defer wg.Done() - defer capabilitySubscribers.Delete(clientID + "-capabilities") - - for { - select { - case info, ok := <-capChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "server", Data: info}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - - shouldSubscribe := func(service string) bool { - if subscribeAll { - return true - } - for _, s := range services { - if s == service { - return true - } - } - return false - } - - if shouldSubscribe("network") && networkManager != nil { - wg.Add(1) - netChan := networkManager.Subscribe(clientID + "-network") - go func() { - defer wg.Done() - defer networkManager.Unsubscribe(clientID + "-network") - - initialState := networkManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "network", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-netChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "network", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("network.credentials") && networkManager != nil { - wg.Add(1) - credChan := networkManager.SubscribeCredentials(clientID + "-credentials") - go func() { - defer wg.Done() - defer networkManager.UnsubscribeCredentials(clientID + "-credentials") - - for { - select { - case prompt, ok := <-credChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "network.credentials", Data: prompt}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("loginctl") && loginctlManager != nil { - wg.Add(1) - loginChan := loginctlManager.Subscribe(clientID + "-loginctl") - go func() { - defer wg.Done() - defer loginctlManager.Unsubscribe(clientID + "-loginctl") - - initialState := loginctlManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "loginctl", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-loginChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "loginctl", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("freedesktop") && freedesktopManager != nil { - wg.Add(1) - freedesktopChan := freedesktopManager.Subscribe(clientID + "-freedesktop") - go func() { - defer wg.Done() - defer freedesktopManager.Unsubscribe(clientID + "-freedesktop") - - initialState := freedesktopManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "freedesktop", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-freedesktopChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "freedesktop", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("freedesktop.screensaver") && freedesktopManager != nil { - wg.Add(1) - screensaverChan := freedesktopManager.SubscribeScreensaver(clientID + "-screensaver") - go func() { - defer wg.Done() - defer freedesktopManager.UnsubscribeScreensaver(clientID + "-screensaver") - - initialState := freedesktopManager.GetScreensaverState() - select { - case eventChan <- ServiceEvent{Service: "freedesktop.screensaver", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-screensaverChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "freedesktop.screensaver", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("gamma") && waylandManager != nil { - wg.Add(1) - waylandChan := waylandManager.Subscribe(clientID + "-gamma") - go func() { - defer wg.Done() - defer waylandManager.Unsubscribe(clientID + "-gamma") - - initialState := waylandManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "gamma", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-waylandChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "gamma", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("theme.auto") && themeModeManager != nil { - wg.Add(1) - themeAutoChan := themeModeManager.Subscribe(clientID + "-theme-auto") - go func() { - defer wg.Done() - defer themeModeManager.Unsubscribe(clientID + "-theme-auto") - - initialState := themeModeManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "theme.auto", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-themeAutoChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "theme.auto", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("bluetooth") && bluezManager != nil { - wg.Add(1) - bluezChan := bluezManager.Subscribe(clientID + "-bluetooth") - go func() { - defer wg.Done() - defer bluezManager.Unsubscribe(clientID + "-bluetooth") - - initialState := bluezManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "bluetooth", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-bluezChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "bluetooth", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("bluetooth.pairing") && bluezManager != nil { - wg.Add(1) - pairingChan := bluezManager.SubscribePairing(clientID + "-pairing") - go func() { - defer wg.Done() - defer bluezManager.UnsubscribePairing(clientID + "-pairing") - - for { - select { - case prompt, ok := <-pairingChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "bluetooth.pairing", Data: prompt}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("browser") && appPickerManager != nil { - wg.Add(1) - appPickerChan := appPickerManager.Subscribe(clientID + "-browser") - go func() { - defer wg.Done() - defer appPickerManager.Unsubscribe(clientID + "-browser") - - for { - select { - case event, ok := <-appPickerChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "browser.open_requested", Data: event}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("cups") { - cupsSubscribers.Store(clientID+"-cups", true) - count := cupsSubscriberCount.Add(1) - - if count == 1 { - if err := InitializeCupsManager(); err != nil { - log.Warnf("Failed to initialize CUPS manager for subscription: %v", err) - } else { - notifyCapabilityChange() - } - } - - if cupsManager != nil { - wg.Add(1) - cupsChan := cupsManager.Subscribe(clientID + "-cups") - go func() { - defer wg.Done() - defer func() { - cupsManager.Unsubscribe(clientID + "-cups") - cupsSubscribers.Delete(clientID + "-cups") - count := cupsSubscriberCount.Add(-1) - - if count == 0 { - log.Info("Last CUPS subscriber disconnected, shutting down CUPS manager") - if cupsManager != nil { - cupsManager.Close() - cupsManager = nil - notifyCapabilityChange() - } - } - }() - - initialState := cupsManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "cups", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-cupsChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "cups", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - } - - if shouldSubscribe("dwl") && dwlManager != nil { - wg.Add(1) - dwlChan := dwlManager.Subscribe(clientID + "-dwl") - go func() { - defer wg.Done() - defer dwlManager.Unsubscribe(clientID + "-dwl") - - initialState := dwlManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "dwl", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-dwlChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "dwl", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("extworkspace") { - if extWorkspaceManager == nil && extWorkspaceAvailable.Load() { - extWorkspaceInitMutex.Lock() - if extWorkspaceManager == nil { - if err := InitializeExtWorkspaceManager(); err != nil { - log.Warnf("Failed to initialize ExtWorkspace manager for subscription: %v", err) - } - } - extWorkspaceInitMutex.Unlock() - } - - if extWorkspaceManager != nil { - wg.Add(1) - extWorkspaceChan := extWorkspaceManager.Subscribe(clientID + "-extworkspace") - go func() { - defer wg.Done() - defer extWorkspaceManager.Unsubscribe(clientID + "-extworkspace") - - initialState := extWorkspaceManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "extworkspace", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-extWorkspaceChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "extworkspace", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - } - - if shouldSubscribe("brightness") && brightnessManager != nil { - wg.Add(2) - brightnessStateChan := brightnessManager.Subscribe(clientID + "-brightness-state") - brightnessUpdateChan := brightnessManager.SubscribeUpdates(clientID + "-brightness-updates") - - go func() { - defer wg.Done() - defer brightnessManager.Unsubscribe(clientID + "-brightness-state") - - initialState := brightnessManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "brightness", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-brightnessStateChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "brightness", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - - go func() { - defer wg.Done() - defer brightnessManager.UnsubscribeUpdates(clientID + "-brightness-updates") - - for { - select { - case update, ok := <-brightnessUpdateChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "brightness.update", Data: update}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("wlroutput") && wlrOutputManager != nil { - wg.Add(1) - wlrOutputChan := wlrOutputManager.Subscribe(clientID + "-wlroutput") - go func() { - defer wg.Done() - defer wlrOutputManager.Unsubscribe(clientID + "-wlroutput") - - initialState := wlrOutputManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "wlroutput", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-wlrOutputChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "wlroutput", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("evdev") && evdevManager != nil { - wg.Add(1) - evdevChan := evdevManager.Subscribe(clientID + "-evdev") - go func() { - defer wg.Done() - defer evdevManager.Unsubscribe(clientID + "-evdev") - - initialState := evdevManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "evdev", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-evdevChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "evdev", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("clipboard") && clipboardManager != nil { - wg.Add(1) - clipboardChan := clipboardManager.Subscribe(clientID + "-clipboard") - go func() { - defer wg.Done() - defer clipboardManager.Unsubscribe(clientID + "-clipboard") - - initialState := clipboardManager.GetState() - select { - case eventChan <- ServiceEvent{Service: "clipboard", Data: initialState}: - case <-stopChan: - return - } - - for { - select { - case state, ok := <-clipboardChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "clipboard", Data: state}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - if shouldSubscribe("dbus") && dbusManager != nil { - wg.Add(1) - dbusChan := dbusManager.SubscribeSignals(dbusClientID) - go func() { - defer wg.Done() - defer dbusManager.UnsubscribeSignals(dbusClientID) - - for { - select { - case event, ok := <-dbusChan: - if !ok { - return - } - select { - case eventChan <- ServiceEvent{Service: "dbus", Data: event}: - case <-stopChan: - return - } - case <-stopChan: - return - } - } - }() - } - - go func() { - wg.Wait() - close(eventChan) - }() - - info := getServerInfo() - if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{ - ID: req.ID, - Result: &ServiceEvent{Service: "server", Data: info}, - }); err != nil { - close(stopChan) - return - } - - for event := range eventChan { - if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{ - ID: req.ID, - Result: &event, - }); err != nil { - close(stopChan) - return - } - } -} - -func cleanupManagers() { - if networkManager != nil { - networkManager.Close() - } - if loginctlManager != nil { - loginctlManager.Close() - } - if freedesktopManager != nil { - freedesktopManager.Close() - } - if waylandManager != nil { - waylandManager.Close() - } - if bluezManager != nil { - bluezManager.Close() - } - if appPickerManager != nil { - appPickerManager.Close() - } - if cupsManager != nil { - cupsManager.Close() - } - if dwlManager != nil { - dwlManager.Close() - } - if extWorkspaceManager != nil { - extWorkspaceManager.Close() - } - if brightnessManager != nil { - brightnessManager.Close() - } - if wlrOutputManager != nil { - wlrOutputManager.Close() - } - if evdevManager != nil { - evdevManager.Close() - } - if clipboardManager != nil { - clipboardManager.Close() - } - if dbusManager != nil { - dbusManager.Close() - } - if themeModeManager != nil { - themeModeManager.Close() - } - if trayRecoveryManager != nil { - trayRecoveryManager.Close() - } - if wlContext != nil { - wlContext.Close() - } - if locationManager != nil { - locationManager.Close() - } - if geoClientInstance != nil { - geoClientInstance.Close() - } -} - -func Start(printDocs bool) error { - cleanupStaleSockets() - - socketPath := GetSocketPath() - os.Remove(socketPath) - - listener, err := net.Listen("unix", socketPath) - if err != nil { - return err - } - defer listener.Close() - defer cleanupManagers() - - log.Infof("DMS API Server listening on: %s", socketPath) - log.Infof("API Version: %d", APIVersion) - log.Info("Protocol: JSON over Unix socket") - log.Info("Request format: {\"id\": , \"method\": \"...\", \"params\": {...}}") - log.Info("Response format: {\"id\": , \"result\": {...}} or {\"id\": , \"error\": \"...\"}") - log.Info("") - if printDocs { - log.Info("Available methods:") - log.Info(" ping - Test connection") - log.Info(" getServerInfo - Get server info (API version and capabilities)") - log.Info(" subscribe - Subscribe to multiple services (params: services [default: all])") - log.Info("Plugins:") - log.Info(" plugins.list - List all plugins") - log.Info(" plugins.listInstalled - List installed plugins") - log.Info(" plugins.install - Install plugin (params: name)") - log.Info(" plugins.uninstall - Uninstall plugin (params: name)") - log.Info(" plugins.update - Update plugin (params: name)") - log.Info(" plugins.search - Search plugins (params: query, category?, compositor?, capability?)") - log.Info("Network:") - log.Info(" network.getState - Get current network state") - log.Info(" network.wifi.scan - Scan for WiFi networks (params: device?)") - log.Info(" network.wifi.networks - Get WiFi network list") - log.Info(" network.wifi.connect - Connect to WiFi (params: ssid, password?, username?, device?, eapMethod?, phase2Auth?, caCertPath?, clientCertPath?, privateKeyPath?, useSystemCACerts?)") - log.Info(" network.wifi.disconnect - Disconnect WiFi (params: device?)") - log.Info(" network.wifi.forget - Forget network (params: ssid)") - log.Info(" network.wifi.toggle - Toggle WiFi radio") - log.Info(" network.wifi.enable - Enable WiFi") - log.Info(" network.wifi.disable - Disable WiFi") - log.Info(" network.wifi.setAutoconnect - Set network autoconnect (params: ssid, autoconnect)") - log.Info(" network.ethernet.connect - Connect Ethernet") - log.Info(" network.ethernet.connect.config - Connect Ethernet to a specific configuration") - log.Info(" network.ethernet.disconnect - Disconnect Ethernet") - log.Info(" network.vpn.profiles - List VPN profiles") - log.Info(" network.vpn.active - List active VPN connections") - log.Info(" network.vpn.connect - Connect VPN (params: uuidOrName|name|uuid, singleActive?)") - log.Info(" network.vpn.disconnect - Disconnect VPN (params: uuidOrName|name|uuid)") - log.Info(" network.vpn.disconnectAll - Disconnect all VPNs") - log.Info(" network.vpn.clearCredentials - Clear saved VPN credentials (params: uuidOrName|name|uuid)") - log.Info(" network.vpn.plugins - List available VPN plugins") - log.Info(" network.vpn.import - Import VPN from file (params: file|path, name?)") - log.Info(" network.vpn.getConfig - Get VPN configuration (params: uuid|name|uuidOrName)") - log.Info(" network.vpn.updateConfig - Update VPN configuration (params: uuid, name?, autoconnect?, data?)") - log.Info(" network.vpn.delete - Delete VPN connection (params: uuid|name|uuidOrName)") - log.Info(" network.preference.set - Set preference (params: preference [auto|wifi|ethernet])") - log.Info(" network.info - Get network info (params: ssid)") - log.Info(" network.credentials.submit - Submit credentials for prompt (params: token, secrets, save?)") - log.Info(" network.credentials.cancel - Cancel credential prompt (params: token)") - log.Info(" network.subscribe - Subscribe to network state changes (streaming)") - log.Info("Loginctl:") - log.Info(" loginctl.getState - Get current session state") - log.Info(" loginctl.lock - Lock session") - log.Info(" loginctl.unlock - Unlock session") - log.Info(" loginctl.activate - Activate session") - log.Info(" loginctl.setIdleHint - Set idle hint (params: idle)") - log.Info(" loginctl.setLockBeforeSuspend - Set lock before suspend (params: enabled)") - log.Info(" loginctl.setSleepInhibitorEnabled - Enable/disable sleep inhibitor (params: enabled)") - log.Info(" loginctl.lockerReady - Signal locker UI is ready (releases sleep inhibitor)") - log.Info(" loginctl.terminate - Terminate session") - log.Info(" loginctl.subscribe - Subscribe to session state changes (streaming)") - log.Info("Freedesktop:") - log.Info(" freedesktop.getState - Get accounts & settings state") - log.Info(" freedesktop.accounts.setIconFile - Set profile icon (params: path)") - log.Info(" freedesktop.accounts.setRealName - Set real name (params: name)") - log.Info(" freedesktop.accounts.setEmail - Set email (params: email)") - log.Info(" freedesktop.accounts.setLanguage - Set language (params: language)") - log.Info(" freedesktop.accounts.setLocation - Set location (params: location)") - log.Info(" freedesktop.accounts.getUserIconFile - Get user icon (params: username)") - log.Info(" freedesktop.settings.getColorScheme - Get color scheme") - log.Info(" freedesktop.settings.setIconTheme - Set icon theme (params: iconTheme)") - log.Info("Wayland:") - log.Info(" wayland.gamma.getState - Get current gamma control state") - log.Info(" wayland.gamma.setTemperature - Set temperature range (params: low, high)") - log.Info(" wayland.gamma.setLocation - Set location (params: latitude, longitude)") - log.Info(" wayland.gamma.setManualTimes - Set manual times (params: sunrise, sunset)") - log.Info(" wayland.gamma.setGamma - Set gamma value (params: gamma)") - log.Info(" wayland.gamma.setEnabled - Enable/disable gamma control (params: enabled)") - log.Info(" wayland.gamma.subscribe - Subscribe to gamma state changes (streaming)") - log.Info("Theme automation:") - log.Info(" theme.auto.getState - Get current theme automation state") - log.Info(" theme.auto.setEnabled - Enable/disable theme automation (params: enabled)") - log.Info(" theme.auto.setMode - Set automation mode (params: mode [time|location])") - log.Info(" theme.auto.setSchedule - Set time schedule (params: startHour, startMinute, endHour, endMinute)") - log.Info(" theme.auto.setLocation - Set location (params: latitude, longitude)") - log.Info(" theme.auto.setUseIPLocation - Use IP location (params: use)") - log.Info(" theme.auto.trigger - Trigger immediate re-evaluation") - log.Info(" theme.auto.subscribe - Subscribe to theme automation state changes (streaming)") - log.Info("Bluetooth:") - log.Info(" bluetooth.getState - Get current bluetooth state") - log.Info(" bluetooth.startDiscovery - Start device discovery") - log.Info(" bluetooth.stopDiscovery - Stop device discovery") - log.Info(" bluetooth.setPowered - Set adapter power state (params: powered)") - log.Info(" bluetooth.pair - Pair with device (params: device)") - log.Info(" bluetooth.connect - Connect to device (params: device)") - log.Info(" bluetooth.disconnect - Disconnect from device (params: device)") - log.Info(" bluetooth.remove - Remove/unpair device (params: device)") - log.Info(" bluetooth.trust - Trust device (params: device)") - log.Info(" bluetooth.untrust - Untrust device (params: device)") - log.Info(" bluetooth.pairing.submit - Submit pairing response (params: token, secrets?, accept?)") - log.Info(" bluetooth.pairing.cancel - Cancel pairing prompt (params: token)") - log.Info(" bluetooth.subscribe - Subscribe to bluetooth state changes (streaming)") - log.Info("CUPS:") - log.Info(" cups.getPrinters - Get printers list") - log.Info(" cups.getJobs - Get non-completed jobs list (params: printerName)") - log.Info(" cups.pausePrinter - Pause printer (params: printerName)") - log.Info(" cups.resumePrinter - Resume printer (params: printerName)") - log.Info(" cups.cancelJob - Cancel job (params: printerName, jobID)") - log.Info(" cups.purgeJobs - Cancel all jobs (params: printerName)") - log.Info("DWL:") - log.Info(" dwl.getState - Get current dwl state (tags, windows, layouts, keyboard)") - log.Info(" dwl.setTags - Set active tags (params: output, tagmask, toggleTagset)") - log.Info(" dwl.setClientTags - Set focused client tags (params: output, andTags, xorTags)") - log.Info(" dwl.setLayout - Set layout (params: output, index)") - log.Info(" dwl.subscribe - Subscribe to dwl state changes (streaming)") - log.Info(" Output state includes:") - log.Info(" - tags : Tag states (active, clients, focused)") - log.Info(" - layoutSymbol : Current layout name") - log.Info(" - title : Focused window title") - log.Info(" - appId : Focused window app ID") - log.Info(" - kbLayout : Current keyboard layout") - log.Info(" - keymode : Current keybind mode") - log.Info("ExtWorkspace:") - log.Info(" extworkspace.getState - Get current workspace state (groups, workspaces)") - log.Info(" extworkspace.activateWorkspace - Activate workspace (params: groupID, workspaceID)") - log.Info(" extworkspace.deactivateWorkspace - Deactivate workspace (params: groupID, workspaceID)") - log.Info(" extworkspace.removeWorkspace - Remove workspace (params: groupID, workspaceID)") - log.Info(" extworkspace.createWorkspace - Create workspace (params: groupID, name)") - log.Info(" extworkspace.subscribe - Subscribe to workspace state changes (streaming)") - log.Info("Brightness:") - log.Info(" brightness.getState - Get current brightness state for all devices") - log.Info(" brightness.setBrightness - Set device brightness (params: device, percent)") - log.Info(" brightness.increment - Increment device brightness (params: device, step?)") - log.Info(" brightness.decrement - Decrement device brightness (params: device, step?)") - log.Info(" brightness.rescan - Rescan for brightness devices (e.g., after plugging in monitor)") - log.Info(" brightness.subscribe - Subscribe to brightness state changes (streaming)") - log.Info(" Subscription events:") - log.Info(" - brightness : Full device list (on rescan, DDC discovery, device changes)") - log.Info(" - brightness.update: Single device update (on brightness change for efficiency)") - log.Info("WlrOutput:") - log.Info(" wlroutput.getState - Get current output configuration state") - log.Info(" wlroutput.applyConfiguration - Apply output configuration (params: heads)") - log.Info(" wlroutput.testConfiguration - Test output configuration without applying (params: heads)") - log.Info(" wlroutput.subscribe - Subscribe to output state changes (streaming)") - log.Info(" Head configuration params:") - log.Info(" - name : Output name (required)") - log.Info(" - enabled : Enable/disable output (required)") - log.Info(" - modeId : Mode ID from available modes (optional)") - log.Info(" - customMode : Custom mode {width, height, refresh} (optional)") - log.Info(" - position : Position {x, y} (optional)") - log.Info(" - transform : Transform value (optional)") - log.Info(" - scale : Scale value (optional)") - log.Info(" - adaptiveSync : Adaptive sync state (optional)") - log.Info("Evdev:") - log.Info(" evdev.getState - Get current evdev state (caps lock)") - log.Info(" evdev.subscribe - Subscribe to evdev state changes (streaming)") - log.Info("Clipboard:") - log.Info(" clipboard.getState - Get clipboard state (enabled, history, current)") - log.Info(" clipboard.getHistory - Get clipboard history with previews") - log.Info(" clipboard.getEntry - Get full entry by ID (params: id)") - log.Info(" clipboard.deleteEntry - Delete entry by ID (params: id)") - log.Info(" clipboard.clearHistory - Clear all clipboard history") - log.Info(" clipboard.copy - Copy text to clipboard (params: text)") - log.Info(" clipboard.paste - Get current clipboard text") - log.Info(" clipboard.search - Search history (params: query?, mimeType?, isImage?, limit?, offset?, before?, after?)") - log.Info(" clipboard.getConfig - Get clipboard configuration") - log.Info(" clipboard.setConfig - Set configuration (params: maxHistory?, maxEntrySize?, autoClearDays?, clearAtStartup?)") - log.Info(" clipboard.subscribe - Subscribe to clipboard state changes (streaming)") - log.Info("Location:") - log.Info(" location.getState - Get current location state") - log.Info(" location.subscribe - Subscribe to location changes (streaming)") - log.Info("") - } - log.Info("Initializing managers...") - log.Info("") - - go func() { - ticker := time.NewTicker(30 * time.Second) - defer ticker.Stop() - - if err := InitializeNetworkManager(); err != nil { - log.Warnf("Network manager unavailable: %v", err) - } else { - notifyCapabilityChange() - return - } - - for range ticker.C { - if networkManager != nil { - return - } - if err := InitializeNetworkManager(); err == nil { - log.Info("Network manager initialized") - notifyCapabilityChange() - return - } - } - }() - - loginctlReady := make(chan struct{}) - freedesktopReady := make(chan struct{}) - - go func() { - defer close(loginctlReady) - if err := InitializeLoginctlManager(); err != nil { - log.Warnf("Loginctl manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - go func() { - defer close(freedesktopReady) - if err := InitializeFreedeskManager(); err != nil { - log.Warnf("Freedesktop manager unavailable: %v", err) - } else if freedesktopManager != nil { - freedesktopManager.NotifySubscribers() - notifyCapabilityChange() - } - }() - - // Bridge loginctl lock state to the freedesktop/gnome screensaver - // ActiveChanged signal so apps like Bitwarden can detect screen lock. - go func() { - <-loginctlReady - <-freedesktopReady - - if loginctlManager == nil || freedesktopManager == nil { - return - } - - ch := loginctlManager.Subscribe("dms-lock-bridge") - defer loginctlManager.Unsubscribe("dms-lock-bridge") - - initial := loginctlManager.GetState() - lastLocked := initial.Locked - freedesktopManager.SetScreenLockActive(lastLocked) - - for state := range ch { - if state.Locked != lastLocked { - lastLocked = state.Locked - freedesktopManager.SetScreenLockActive(lastLocked) - } - } - }() - - if err := InitializeWaylandManager(); err != nil { - log.Warnf("Wayland manager unavailable: %v", err) - } - - if err := InitializeThemeModeManager(); err != nil { - log.Warnf("Theme mode manager unavailable: %v", err) - } else { - notifyCapabilityChange() - go func() { - <-loginctlReady - if loginctlManager == nil { - return - } - themeModeManager.WatchLoginctl(loginctlManager) - }() - } - - go func() { - <-loginctlReady - if loginctlManager == nil { - return - } - if err := InitializeTrayRecoveryManager(); err != nil { - log.Warnf("TrayRecovery manager unavailable: %v", err) - } else { - trayRecoveryManager.WatchLoginctl(loginctlManager) - } - }() - - go func() { - geoClient := geolocation.NewClient() - geoClientInstance = geoClient - - if waylandManager != nil { - waylandManager.SetGeoClient(geoClient) - } - if themeModeManager != nil { - themeModeManager.SetGeoClient(geoClient) - } - - if err := InitializeLocationManager(geoClient); err != nil { - log.Warnf("Location manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - go func() { - if err := InitializeBluezManager(); err != nil { - log.Warnf("Bluez manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - if err := InitializeAppPickerManager(); err != nil { - log.Debugf("AppPicker manager unavailable: %v", err) - } - - if err := InitializeDwlManager(); err != nil { - log.Debugf("DWL manager unavailable: %v", err) - } - - if extworkspace.CheckCapability() { - extWorkspaceAvailable.Store(true) - log.Info("ExtWorkspace capability detected and will be available on subscription") - } else { - log.Debug("ExtWorkspace capability not available") - extWorkspaceAvailable.Store(false) - } - - if err := InitializeWlrOutputManager(); err != nil { - log.Debugf("WlrOutput manager unavailable: %v", err) - } - - fatalErrChan := make(chan error, 1) - if wlrOutputManager != nil { - go func() { - err := <-wlrOutputManager.FatalError() - fatalErrChan <- fmt.Errorf("WlrOutput fatal error: %w", err) - }() - } - if wlContext != nil { - go func() { - err := <-wlContext.FatalError() - fatalErrChan <- fmt.Errorf("wayland context fatal error: %w", err) - }() - } - - go func() { - if err := InitializeBrightnessManager(); err != nil { - log.Warnf("Brightness manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - go func() { - if err := InitializeEvdevManager(); err != nil { - log.Debugf("Evdev manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - go func() { - if err := InitializeClipboardManager(); err != nil { - log.Warnf("Clipboard manager unavailable: %v", err) - } - if wlContext != nil { - wlContext.Start() - log.Info("Wayland event dispatcher started") - } - }() - - go func() { - if err := InitializeDbusManager(); err != nil { - log.Warnf("DBus manager unavailable: %v", err) - } else { - notifyCapabilityChange() - } - }() - - log.Info("") - log.Infof("Ready! Capabilities: %v", getCapabilities().Capabilities) - - listenerErrChan := make(chan error, 1) - - go func() { - for { - conn, err := listener.Accept() - if err != nil { - listenerErrChan <- err - return - } - go handleConnection(conn) - } - }() - - select { - case err := <-listenerErrChan: - return err - case err := <-fatalErrChan: - return err - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server_test.go deleted file mode 100644 index 404f624..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/server_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package server - -import ( - "encoding/json" - "fmt" - "net" - "os" - "path/filepath" - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/network" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGetSocketDir(t *testing.T) { - tests := []struct { - name string - xdgRuntimeDir string - uid int - expectedSubstr string - }{ - { - name: "uses XDG_RUNTIME_DIR when set", - xdgRuntimeDir: "/run/user/1000", - expectedSubstr: "/run/user/1000", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.xdgRuntimeDir != "" { - t.Setenv("XDG_RUNTIME_DIR", tt.xdgRuntimeDir) - } - - result := getSocketDir() - assert.Contains(t, result, tt.expectedSubstr) - }) - } -} - -func TestGetSocketPath(t *testing.T) { - path := GetSocketPath() - assert.Contains(t, path, "danklinux-") - assert.Contains(t, path, ".sock") - assert.Contains(t, path, fmt.Sprintf("%d", os.Getpid())) -} - -func TestGetCapabilities(t *testing.T) { - originalNetworkManager := networkManager - defer func() { networkManager = originalNetworkManager }() - - t.Run("capabilities without network manager", func(t *testing.T) { - networkManager = nil - caps := getCapabilities() - assert.Contains(t, caps.Capabilities, "plugins") - assert.NotContains(t, caps.Capabilities, "network") - }) - - t.Run("capabilities with network manager", func(t *testing.T) { - networkManager = &network.Manager{} - caps := getCapabilities() - assert.Contains(t, caps.Capabilities, "plugins") - assert.Contains(t, caps.Capabilities, "network") - }) -} - -type mockConn struct { - net.Conn - written []byte -} - -func (m *mockConn) Write(b []byte) (n int, err error) { - m.written = append(m.written, b...) - return len(b), nil -} - -func (m *mockConn) Close() error { - return nil -} - -func TestRespondError(t *testing.T) { - conn := &mockConn{} - models.RespondError(conn, 123, "test error") - - var resp models.Response[any] - err := json.Unmarshal(conn.written, &resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Equal(t, "test error", resp.Error) - assert.Nil(t, resp.Result) -} - -func TestRespond(t *testing.T) { - conn := &mockConn{} - result := map[string]string{"foo": "bar"} - models.Respond(conn, 123, result) - - var resp models.Response[map[string]string] - err := json.Unmarshal(conn.written, &resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.Empty(t, resp.Error) - require.NotNil(t, resp.Result) - assert.Equal(t, "bar", (*resp.Result)["foo"]) -} - -func TestRequest_JSON(t *testing.T) { - jsonStr := `{"id":123,"method":"test.method","params":{"key":"value"}}` - var req models.Request - err := json.Unmarshal([]byte(jsonStr), &req) - require.NoError(t, err) - - assert.Equal(t, 123, req.ID) - assert.Equal(t, "test.method", req.Method) - assert.Equal(t, "value", req.Params["key"]) -} - -func TestResponse_JSON(t *testing.T) { - t.Run("success response", func(t *testing.T) { - result := "success" - resp := models.Response[string]{ - ID: 123, - Result: &result, - } - - data, err := json.Marshal(resp) - require.NoError(t, err) - - var decoded models.Response[string] - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, 123, decoded.ID) - assert.Equal(t, "success", *decoded.Result) - assert.Empty(t, decoded.Error) - }) - - t.Run("error response", func(t *testing.T) { - resp := models.Response[any]{ - ID: 123, - Error: "test error", - } - - data, err := json.Marshal(resp) - require.NoError(t, err) - - var decoded models.Response[any] - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - assert.Equal(t, 123, decoded.ID) - assert.Equal(t, "test error", decoded.Error) - assert.Nil(t, decoded.Result) - }) -} - -func TestCleanupStaleSockets(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("XDG_RUNTIME_DIR", tempDir) - - staleSocket := filepath.Join(tempDir, "danklinux-4194305.sock") - err := os.WriteFile(staleSocket, []byte{}, 0o600) - require.NoError(t, err) - - activeSocket := filepath.Join(tempDir, fmt.Sprintf("danklinux-%d.sock", os.Getpid())) - err = os.WriteFile(activeSocket, []byte{}, 0o600) - require.NoError(t, err) - - cleanupStaleSockets() - - _, err = os.Stat(staleSocket) - assert.True(t, os.IsNotExist(err)) - - _, err = os.Stat(activeSocket) - assert.NoError(t, err) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/handlers.go deleted file mode 100644 index 6891875..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/handlers.go +++ /dev/null @@ -1,154 +0,0 @@ -package thememode - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - if manager == nil { - models.RespondError(conn, req.ID, "theme mode manager not initialized") - return - } - - switch req.Method { - case "theme.auto.getState": - handleGetState(conn, req, manager) - case "theme.auto.setEnabled": - handleSetEnabled(conn, req, manager) - case "theme.auto.setMode": - handleSetMode(conn, req, manager) - case "theme.auto.setSchedule": - handleSetSchedule(conn, req, manager) - case "theme.auto.setLocation": - handleSetLocation(conn, req, manager) - case "theme.auto.setUseIPLocation": - handleSetUseIPLocation(conn, req, manager) - case "theme.auto.trigger": - handleTrigger(conn, req, manager) - case "theme.auto.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleSetEnabled(conn net.Conn, req models.Request, manager *Manager) { - enabled, err := params.Bool(req.Params, "enabled") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetEnabled(enabled) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "theme auto enabled set"}) -} - -func handleSetMode(conn net.Conn, req models.Request, manager *Manager) { - mode, err := params.String(req.Params, "mode") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if mode != "time" && mode != "location" { - models.RespondError(conn, req.ID, "invalid mode") - return - } - - manager.SetMode(mode) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "theme auto mode set"}) -} - -func handleSetSchedule(conn net.Conn, req models.Request, manager *Manager) { - startHour, err := params.Int(req.Params, "startHour") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - startMinute, err := params.Int(req.Params, "startMinute") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - endHour, err := params.Int(req.Params, "endHour") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - endMinute, err := params.Int(req.Params, "endMinute") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.ValidateSchedule(startHour, startMinute, endHour, endMinute); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetSchedule(startHour, startMinute, endHour, endMinute) - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleSetLocation(conn net.Conn, req models.Request, manager *Manager) { - lat, err := params.Float(req.Params, "latitude") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - lon, err := params.Float(req.Params, "longitude") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetLocation(lat, lon) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "theme auto location set"}) -} - -func handleSetUseIPLocation(conn net.Conn, req models.Request, manager *Manager) { - use, err := params.Bool(req.Params, "use") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetUseIPLocation(use) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "theme auto IP location set"}) -} - -func handleTrigger(conn net.Conn, req models.Request, manager *Manager) { - manager.TriggerUpdate() - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "theme auto update triggered"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range stateChan { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - Result: &state, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/manager.go deleted file mode 100644 index f7644ad..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/manager.go +++ /dev/null @@ -1,462 +0,0 @@ -package thememode - -import ( - "errors" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -const ( - defaultStartHour = 18 - defaultStartMinute = 0 - defaultEndHour = 6 - defaultEndMinute = 0 - defaultElevationTwilight = -6.0 - defaultElevationDaylight = 3.0 -) - -type Manager struct { - config Config - configMutex sync.RWMutex - - state *State - stateMutex sync.RWMutex - - subscribers syncmap.Map[string, chan State] - - locationMutex sync.RWMutex - cachedIPLat *float64 - cachedIPLon *float64 - - geoClient geolocation.Client - - stopChan chan struct{} - updateTrigger chan struct{} - wg sync.WaitGroup -} - -func NewManager() *Manager { - m := &Manager{ - config: Config{ - Enabled: false, - Mode: "time", - StartHour: defaultStartHour, - StartMinute: defaultStartMinute, - EndHour: defaultEndHour, - EndMinute: defaultEndMinute, - ElevationTwilight: defaultElevationTwilight, - ElevationDaylight: defaultElevationDaylight, - }, - stopChan: make(chan struct{}), - updateTrigger: make(chan struct{}, 1), - } - - m.updateState(time.Now()) - - m.wg.Add(1) - go m.schedulerLoop() - - return m -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{Config: m.getConfig()} - } - stateCopy := *m.state - return stateCopy -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) SetEnabled(enabled bool) { - m.configMutex.Lock() - if m.config.Enabled == enabled { - m.configMutex.Unlock() - return - } - m.config.Enabled = enabled - m.configMutex.Unlock() - m.TriggerUpdate() -} - -func (m *Manager) SetMode(mode string) { - m.configMutex.Lock() - if m.config.Mode == mode { - m.configMutex.Unlock() - return - } - m.config.Mode = mode - m.configMutex.Unlock() - m.TriggerUpdate() -} - -func (m *Manager) SetSchedule(startHour, startMinute, endHour, endMinute int) { - m.configMutex.Lock() - changed := m.config.StartHour != startHour || - m.config.StartMinute != startMinute || - m.config.EndHour != endHour || - m.config.EndMinute != endMinute - if !changed { - m.configMutex.Unlock() - return - } - m.config.StartHour = startHour - m.config.StartMinute = startMinute - m.config.EndHour = endHour - m.config.EndMinute = endMinute - m.configMutex.Unlock() - m.TriggerUpdate() -} - -func (m *Manager) SetLocation(lat, lon float64) { - m.configMutex.Lock() - if m.config.Latitude != nil && m.config.Longitude != nil && - *m.config.Latitude == lat && *m.config.Longitude == lon && !m.config.UseIPLocation { - m.configMutex.Unlock() - return - } - m.config.Latitude = &lat - m.config.Longitude = &lon - m.config.UseIPLocation = false - m.configMutex.Unlock() - - m.locationMutex.Lock() - m.cachedIPLat = nil - m.cachedIPLon = nil - m.locationMutex.Unlock() - - m.TriggerUpdate() -} - -func (m *Manager) SetUseIPLocation(use bool) { - m.configMutex.Lock() - if m.config.UseIPLocation == use { - m.configMutex.Unlock() - return - } - m.config.UseIPLocation = use - if use { - m.config.Latitude = nil - m.config.Longitude = nil - } - m.configMutex.Unlock() - - if use { - m.locationMutex.Lock() - m.cachedIPLat = nil - m.cachedIPLon = nil - m.locationMutex.Unlock() - } - - m.TriggerUpdate() -} - -func (m *Manager) TriggerUpdate() { - select { - case m.updateTrigger <- struct{}{}: - default: - } -} - -func (m *Manager) Close() { - select { - case <-m.stopChan: - return - default: - close(m.stopChan) - } - m.wg.Wait() - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) -} - -func (m *Manager) WatchLoginctl(lm *loginctl.Manager) { - ch := lm.Subscribe("thememode") - m.wg.Add(1) - go func() { - defer m.wg.Done() - defer lm.Unsubscribe("thememode") - for { - select { - case <-m.stopChan: - return - case state, ok := <-ch: - if !ok { - return - } - if state.PreparingForSleep { - continue - } - m.TriggerUpdate() - } - } - }() -} - -func (m *Manager) schedulerLoop() { - defer m.wg.Done() - - var timer *time.Timer - for { - config := m.getConfig() - now := time.Now() - var isLight bool - var next time.Time - if config.Enabled { - isLight, next = m.computeSchedule(now, config) - } else { - m.stateMutex.RLock() - if m.state != nil { - isLight = m.state.IsLight - } - m.stateMutex.RUnlock() - next = now.Add(24 * time.Hour) - } - - m.updateStateWithValues(config, isLight, next) - - waitDur := time.Until(next) - if !config.Enabled { - waitDur = 24 * time.Hour - } - if waitDur < time.Second { - waitDur = time.Second - } - - if timer != nil { - timer.Stop() - } - timer = time.NewTimer(waitDur) - - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.updateTrigger: - timer.Stop() - continue - case <-timer.C: - continue - } - } -} - -func (m *Manager) updateState(now time.Time) { - config := m.getConfig() - var isLight bool - var next time.Time - if config.Enabled { - isLight, next = m.computeSchedule(now, config) - } else { - m.stateMutex.RLock() - if m.state != nil { - isLight = m.state.IsLight - } - m.stateMutex.RUnlock() - next = now.Add(24 * time.Hour) - } - m.updateStateWithValues(config, isLight, next) -} - -func (m *Manager) updateStateWithValues(config Config, isLight bool, next time.Time) { - newState := State{ - Config: config, - IsLight: isLight, - NextTransition: next, - } - - m.stateMutex.Lock() - if m.state != nil && statesEqual(m.state, &newState) { - m.stateMutex.Unlock() - return - } - m.state = &newState - m.stateMutex.Unlock() - - m.notifySubscribers() -} - -func (m *Manager) notifySubscribers() { - state := m.GetState() - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (m *Manager) getConfig() Config { - m.configMutex.RLock() - defer m.configMutex.RUnlock() - return m.config -} - -func (m *Manager) SetGeoClient(client geolocation.Client) { - m.geoClient = client -} - -func (m *Manager) getLocation(config Config) (*float64, *float64) { - if config.Latitude != nil && config.Longitude != nil { - return config.Latitude, config.Longitude - } - if !config.UseIPLocation { - return nil, nil - } - if m.geoClient == nil { - return nil, nil - } - - m.locationMutex.RLock() - if m.cachedIPLat != nil && m.cachedIPLon != nil { - lat, lon := m.cachedIPLat, m.cachedIPLon - m.locationMutex.RUnlock() - return lat, lon - } - m.locationMutex.RUnlock() - - location, err := m.geoClient.GetLocation() - if err != nil { - return nil, nil - } - - m.locationMutex.Lock() - m.cachedIPLat = &location.Latitude - m.cachedIPLon = &location.Longitude - m.locationMutex.Unlock() - - return m.cachedIPLat, m.cachedIPLon -} - -func statesEqual(a, b *State) bool { - if a == nil || b == nil { - return a == b - } - if a.IsLight != b.IsLight || !a.NextTransition.Equal(b.NextTransition) { - return false - } - return a.Config == b.Config -} - -func (m *Manager) computeSchedule(now time.Time, config Config) (bool, time.Time) { - switch config.Mode { - case "location": - return m.computeLocationSchedule(now, config) - default: - return computeTimeSchedule(now, config) - } -} - -func computeTimeSchedule(now time.Time, config Config) (bool, time.Time) { - startMinutes := config.StartHour*60 + config.StartMinute - endMinutes := config.EndHour*60 + config.EndMinute - currentMinutes := now.Hour()*60 + now.Minute() - - startTime := time.Date(now.Year(), now.Month(), now.Day(), config.StartHour, config.StartMinute, 0, 0, now.Location()) - endTime := time.Date(now.Year(), now.Month(), now.Day(), config.EndHour, config.EndMinute, 0, 0, now.Location()) - - if startMinutes == endMinutes { - next := startTime - if !next.After(now) { - next = next.Add(24 * time.Hour) - } - return true, next - } - - if startMinutes < endMinutes { - if currentMinutes < startMinutes { - return true, startTime - } - if currentMinutes >= endMinutes { - return true, startTime.Add(24 * time.Hour) - } - return false, endTime - } - - if currentMinutes >= startMinutes { - return false, endTime.Add(24 * time.Hour) - } - if currentMinutes < endMinutes { - return false, endTime - } - return true, startTime -} - -func (m *Manager) computeLocationSchedule(now time.Time, config Config) (bool, time.Time) { - lat, lon := m.getLocation(config) - if lat == nil || lon == nil { - currentIsLight := false - m.stateMutex.RLock() - if m.state != nil { - currentIsLight = m.state.IsLight - } - m.stateMutex.RUnlock() - return currentIsLight, now.Add(10 * time.Minute) - } - - times, cond := wayland.CalculateSunTimesWithTwilight(*lat, *lon, now, config.ElevationTwilight, config.ElevationDaylight) - switch cond { - case wayland.SunMidnightSun: - return true, startOfNextDay(now) - case wayland.SunPolarNight: - return false, startOfNextDay(now) - } - - if now.Before(times.Sunrise) { - return false, times.Sunrise - } - if now.Before(times.Sunset) { - return true, times.Sunset - } - - nextDay := startOfNextDay(now) - nextTimes, nextCond := wayland.CalculateSunTimesWithTwilight(*lat, *lon, nextDay, config.ElevationTwilight, config.ElevationDaylight) - switch nextCond { - case wayland.SunMidnightSun: - return true, startOfNextDay(nextDay) - case wayland.SunPolarNight: - return false, startOfNextDay(nextDay) - } - - return false, nextTimes.Sunrise -} - -func startOfNextDay(t time.Time) time.Time { - next := t.Add(24 * time.Hour) - return time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) -} - -func validateHourMinute(hour, minute int) bool { - return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 -} - -func (m *Manager) ValidateSchedule(startHour, startMinute, endHour, endMinute int) error { - if !validateHourMinute(startHour, startMinute) || !validateHourMinute(endHour, endMinute) { - return errInvalidTime - } - return nil -} - -var errInvalidTime = errors.New("invalid schedule time") diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/types.go deleted file mode 100644 index 72e6468..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/thememode/types.go +++ /dev/null @@ -1,23 +0,0 @@ -package thememode - -import "time" - -type Config struct { - Enabled bool `json:"enabled"` - Mode string `json:"mode"` - StartHour int `json:"startHour"` - StartMinute int `json:"startMinute"` - EndHour int `json:"endHour"` - EndMinute int `json:"endMinute"` - Latitude *float64 `json:"latitude,omitempty"` - Longitude *float64 `json:"longitude,omitempty"` - UseIPLocation bool `json:"useIPLocation"` - ElevationTwilight float64 `json:"elevationTwilight"` - ElevationDaylight float64 `json:"elevationDaylight"` -} - -type State struct { - Config Config `json:"config"` - IsLight bool `json:"isLight"` - NextTransition time.Time `json:"nextTransition"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/handlers.go deleted file mode 100644 index b3b308a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/handlers.go +++ /dev/null @@ -1,27 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request) { - switch req.Method { - case "themes.list": - HandleList(conn, req) - case "themes.listInstalled": - HandleListInstalled(conn, req) - case "themes.install": - HandleInstall(conn, req) - case "themes.uninstall": - HandleUninstall(conn, req) - case "themes.update": - HandleUpdate(conn, req) - case "themes.search": - HandleSearch(conn, req) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/install.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/install.go deleted file mode 100644 index 26d22ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/install.go +++ /dev/null @@ -1,52 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func HandleInstall(conn net.Conn, req models.Request) { - idOrName, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - registry, err := themes.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - themeList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list themes: %v", err)) - return - } - - theme := themes.FindByIDOrName(idOrName, themeList) - if theme == nil { - models.RespondError(conn, req.ID, fmt.Sprintf("theme not found: %s", idOrName)) - return - } - - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - registryThemeDir := registry.GetThemeDir(theme.SourceDir) - if err := manager.Install(*theme, registryThemeDir); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to install theme: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{ - Success: true, - Message: fmt.Sprintf("theme installed: %s", theme.Name), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list.go deleted file mode 100644 index 9564be1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list.go +++ /dev/null @@ -1,54 +0,0 @@ -package themes - -import ( - "fmt" - "net" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func HandleList(conn net.Conn, req models.Request) { - registry, err := themes.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - themeList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list themes: %v", err)) - return - } - - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - result := make([]ThemeInfo, len(themeList)) - for i, t := range themeList { - installed, _ := manager.IsInstalled(t) - info := ThemeInfo{ - ID: t.ID, - Name: t.Name, - Version: t.Version, - Author: t.Author, - Description: t.Description, - PreviewPath: t.PreviewPath, - SourceDir: t.SourceDir, - Installed: installed, - FirstParty: isFirstParty(t.Author), - } - addVariantsInfo(&info, t.Variants) - result[i] = info - } - - models.Respond(conn, req.ID, result) -} - -func isFirstParty(author string) bool { - return strings.EqualFold(author, "Avenge Media") || strings.EqualFold(author, "AvengeMedia") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list_installed.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list_installed.go deleted file mode 100644 index 49be81b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/list_installed.go +++ /dev/null @@ -1,149 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func addVariantsInfo(info *ThemeInfo, variants *themes.ThemeVariants) { - if variants == nil { - return - } - - if variants.Type == "multi" { - if len(variants.Flavors) == 0 && len(variants.Accents) == 0 { - return - } - info.HasVariants = true - info.Variants = &VariantsInfo{ - Type: "multi", - Flavors: make([]FlavorInfo, len(variants.Flavors)), - Accents: make([]AccentInfo, len(variants.Accents)), - } - if variants.Defaults != nil { - info.Variants.Defaults = &MultiDefaults{ - Dark: variants.Defaults.Dark, - Light: variants.Defaults.Light, - } - } - for i, f := range variants.Flavors { - mode := "" - switch { - case f.Dark.Primary != "" && f.Light.Primary != "": - mode = "both" - case f.Dark.Primary != "": - mode = "dark" - case f.Light.Primary != "": - mode = "light" - default: - if f.Dark.Surface != "" { - mode = "dark" - } else if f.Light.Surface != "" { - mode = "light" - } - } - info.Variants.Flavors[i] = FlavorInfo{ID: f.ID, Name: f.Name, Mode: mode} - } - for i, a := range variants.Accents { - color := "" - if colors, ok := a.FlavorColors["mocha"]; ok && colors.Primary != "" { - color = colors.Primary - } else if colors, ok := a.FlavorColors["latte"]; ok && colors.Primary != "" { - color = colors.Primary - } else { - for _, c := range a.FlavorColors { - if c.Primary != "" { - color = c.Primary - break - } - } - } - info.Variants.Accents[i] = AccentInfo{ID: a.ID, Name: a.Name, Color: color} - } - return - } - - if len(variants.Options) == 0 { - return - } - info.HasVariants = true - info.Variants = &VariantsInfo{ - Default: variants.Default, - Options: make([]VariantInfo, len(variants.Options)), - } - for i, v := range variants.Options { - info.Variants.Options[i] = VariantInfo{ID: v.ID, Name: v.Name} - } -} - -func HandleListInstalled(conn net.Conn, req models.Request) { - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - installedIDs, err := manager.ListInstalled() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list installed themes: %v", err)) - return - } - - themeMap := make(map[string]themes.Theme) - if registry, err := themes.NewRegistry(); err == nil { - if allThemes, err := registry.List(); err == nil { - for _, t := range allThemes { - themeMap[t.ID] = t - } - } - } - - result := make([]ThemeInfo, 0, len(installedIDs)) - for _, id := range installedIDs { - if theme, ok := themeMap[id]; ok { - hasUpdate := false - if hasUpdates, err := manager.HasUpdates(id, theme); err == nil { - hasUpdate = hasUpdates - } - - info := ThemeInfo{ - ID: theme.ID, - Name: theme.Name, - Version: theme.Version, - Author: theme.Author, - Description: theme.Description, - SourceDir: id, - FirstParty: isFirstParty(theme.Author), - HasUpdate: hasUpdate, - } - addVariantsInfo(&info, theme.Variants) - result = append(result, info) - } else { - installed, err := manager.GetInstalledTheme(id) - if err != nil { - result = append(result, ThemeInfo{ - ID: id, - Name: id, - SourceDir: id, - }) - continue - } - info := ThemeInfo{ - ID: installed.ID, - Name: installed.Name, - Version: installed.Version, - Author: installed.Author, - Description: installed.Description, - SourceDir: id, - FirstParty: isFirstParty(installed.Author), - } - addVariantsInfo(&info, installed.Variants) - result = append(result, info) - } - } - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/search.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/search.go deleted file mode 100644 index 2823fe0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/search.go +++ /dev/null @@ -1,53 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func HandleSearch(conn net.Conn, req models.Request) { - query, ok := models.Get[string](req, "query") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'query' parameter") - return - } - - registry, err := themes.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - themeList, err := registry.List() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to list themes: %v", err)) - return - } - - searchResults := themes.FuzzySearch(query, themeList) - - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - result := make([]ThemeInfo, len(searchResults)) - for i, t := range searchResults { - installed, _ := manager.IsInstalled(t) - result[i] = ThemeInfo{ - ID: t.ID, - Name: t.Name, - Version: t.Version, - Author: t.Author, - Description: t.Description, - Installed: installed, - FirstParty: isFirstParty(t.Author), - } - } - - models.Respond(conn, req.ID, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/types.go deleted file mode 100644 index 0ad19b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/types.go +++ /dev/null @@ -1,47 +0,0 @@ -package themes - -type VariantInfo struct { - ID string `json:"id"` - Name string `json:"name"` -} - -type FlavorInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Mode string `json:"mode,omitempty"` -} - -type AccentInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Color string `json:"color,omitempty"` -} - -type MultiDefaults struct { - Dark map[string]string `json:"dark,omitempty"` - Light map[string]string `json:"light,omitempty"` -} - -type VariantsInfo struct { - Type string `json:"type,omitempty"` - Default string `json:"default,omitempty"` - Defaults *MultiDefaults `json:"defaults,omitempty"` - Options []VariantInfo `json:"options,omitempty"` - Flavors []FlavorInfo `json:"flavors,omitempty"` - Accents []AccentInfo `json:"accents,omitempty"` -} - -type ThemeInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Version string `json:"version"` - Author string `json:"author,omitempty"` - Description string `json:"description,omitempty"` - PreviewPath string `json:"previewPath,omitempty"` - SourceDir string `json:"sourceDir,omitempty"` - Installed bool `json:"installed,omitempty"` - FirstParty bool `json:"firstParty,omitempty"` - HasUpdate bool `json:"hasUpdate,omitempty"` - HasVariants bool `json:"hasVariants,omitempty"` - Variants *VariantsInfo `json:"variants,omitempty"` -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/uninstall.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/uninstall.go deleted file mode 100644 index 9b453e4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/uninstall.go +++ /dev/null @@ -1,63 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func HandleUninstall(conn net.Conn, req models.Request) { - idOrName, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - registry, err := themes.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - themeList, _ := registry.List() - theme := themes.FindByIDOrName(idOrName, themeList) - - if theme != nil { - installed, err := manager.IsInstalled(*theme) - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if theme is installed: %v", err)) - return - } - if !installed { - models.RespondError(conn, req.ID, fmt.Sprintf("theme not installed: %s", idOrName)) - return - } - if err := manager.Uninstall(*theme); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to uninstall theme: %v", err)) - return - } - models.Respond(conn, req.ID, models.SuccessResult{ - Success: true, - Message: fmt.Sprintf("theme uninstalled: %s", theme.Name), - }) - return - } - - if err := manager.UninstallByID(idOrName); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("theme not found: %s", idOrName)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{ - Success: true, - Message: fmt.Sprintf("theme uninstalled: %s", idOrName), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/update.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/update.go deleted file mode 100644 index fb9f81f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/themes/update.go +++ /dev/null @@ -1,57 +0,0 @@ -package themes - -import ( - "fmt" - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/themes" -) - -func HandleUpdate(conn net.Conn, req models.Request) { - idOrName, ok := models.Get[string](req, "name") - if !ok { - models.RespondError(conn, req.ID, "missing or invalid 'name' parameter") - return - } - - manager, err := themes.NewManager() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err)) - return - } - - registry, err := themes.NewRegistry() - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err)) - return - } - - themeList, _ := registry.List() - theme := themes.FindByIDOrName(idOrName, themeList) - - if theme == nil { - models.RespondError(conn, req.ID, fmt.Sprintf("theme not found in registry: %s", idOrName)) - return - } - - installed, err := manager.IsInstalled(*theme) - if err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if theme is installed: %v", err)) - return - } - if !installed { - models.RespondError(conn, req.ID, fmt.Sprintf("theme not installed: %s", idOrName)) - return - } - - if err := manager.Update(*theme); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("failed to update theme: %v", err)) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{ - Success: true, - Message: fmt.Sprintf("theme updated: %s", theme.Name), - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/manager.go deleted file mode 100644 index 3610f1b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/manager.go +++ /dev/null @@ -1,93 +0,0 @@ -package trayrecovery - -import ( - "fmt" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl" - "github.com/godbus/dbus/v5" -) - -const resumeDelay = 3 * time.Second - -type Manager struct { - conn *dbus.Conn - stopChan chan struct{} - wg sync.WaitGroup -} - -func NewManager() (*Manager, error) { - conn, err := dbus.ConnectSessionBus() - if err != nil { - return nil, fmt.Errorf("failed to connect to session bus: %w", err) - } - - m := &Manager{ - conn: conn, - stopChan: make(chan struct{}), - } - - // Run a startup scan after a delay — covers the case where the process - // was killed during suspend and restarted by systemd (Type=dbus). - // The fresh process never sees the PrepareForSleep true→false transition, - // so the loginctl watcher alone is not enough. - go m.scheduleRecovery() - - return m, nil -} - -// WatchLoginctl subscribes to loginctl session state changes and triggers -// tray recovery after resume from suspend (PrepareForSleep false transition). -// This handles the case where the process survives suspend. -func (m *Manager) WatchLoginctl(lm *loginctl.Manager) { - ch := lm.Subscribe("tray-recovery") - m.wg.Add(1) - go func() { - defer m.wg.Done() - defer lm.Unsubscribe("tray-recovery") - - wasSleeping := false - for { - select { - case <-m.stopChan: - return - case state, ok := <-ch: - if !ok { - return - } - if state.PreparingForSleep { - wasSleeping = true - continue - } - if wasSleeping { - wasSleeping = false - go m.scheduleRecovery() - } - } - } - }() -} - -func (m *Manager) scheduleRecovery() { - select { - case <-time.After(resumeDelay): - m.recoverTrayItems() - case <-m.stopChan: - } -} - -func (m *Manager) Close() { - select { - case <-m.stopChan: - return - default: - close(m.stopChan) - } - m.wg.Wait() - if m.conn != nil { - m.conn.Close() - } - log.Info("TrayRecovery manager closed") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/recovery.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/recovery.go deleted file mode 100644 index c7b98fb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/trayrecovery/recovery.go +++ /dev/null @@ -1,262 +0,0 @@ -package trayrecovery - -import ( - "context" - "strings" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/godbus/dbus/v5" -) - -const ( - sniWatcherDest = "org.kde.StatusNotifierWatcher" - sniWatcherPath = "/StatusNotifierWatcher" - sniWatcherIface = "org.kde.StatusNotifierWatcher" - sniItemIface = "org.kde.StatusNotifierItem" - dbusIface = "org.freedesktop.DBus" - propsIface = "org.freedesktop.DBus.Properties" - probeTimeout = 300 * time.Millisecond - connProbeTimeout = 150 * time.Millisecond - batchSize = 30 -) - -var excludedPrefixes = []string{ - "org.freedesktop.", - "org.gnome.", - "org.kde.StatusNotifier", - "com.canonical.AppMenu", - "org.mpris.", - "org.pipewire.", - "org.pulseaudio", - "fi.epitaph", - "quickshell", - "org.kde.quickshell", -} - -func (m *Manager) recoverTrayItems() { - registeredItems := m.getRegisteredItems() - allNames := m.getDBusNames() - if allNames == nil { - return - } - - registeredConnIDs := m.buildRegisteredConnIDs(registeredItems) - - count := len(registeredItems) - log.Infof("TrayRecoveryService: scanning DBus for unregistered SNI items (%d already registered)...", count) - - m.scanWellKnownNames(allNames, registeredItems, registeredConnIDs) - m.scanConnectionIDs(allNames, registeredItems, registeredConnIDs) -} - -func (m *Manager) getRegisteredItems() []string { - obj := m.conn.Object(sniWatcherDest, sniWatcherPath) - variant, err := obj.GetProperty(sniWatcherIface + ".RegisteredStatusNotifierItems") - if err != nil { - log.Warnf("TrayRecoveryService: failed to get registered items: %v", err) - return nil - } - - switch v := variant.Value().(type) { - case []string: - return v - case []any: - items := make([]string, 0, len(v)) - for _, elem := range v { - if s, ok := elem.(string); ok { - items = append(items, s) - } - } - return items - } - return nil -} - -func (m *Manager) getDBusNames() []string { - var names []string - err := m.conn.BusObject().Call(dbusIface+".ListNames", 0).Store(&names) - if err != nil { - log.Warnf("TrayRecoveryService: failed to list bus names: %v", err) - return nil - } - return names -} - -func (m *Manager) getNameOwner(name string) string { - var owner string - err := m.conn.BusObject().Call(dbusIface+".GetNameOwner", 0, name).Store(&owner) - if err != nil { - return "" - } - return owner -} - -// buildRegisteredConnIDs resolves every registered SNI item (well-known name -// or :1.xxx connection ID) to a canonical connection ID. This prevents -// duplicates in both directions. -func (m *Manager) buildRegisteredConnIDs(registeredItems []string) map[string]bool { - connIDs := make(map[string]bool, len(registeredItems)) - for _, item := range registeredItems { - name := extractName(item) - if strings.HasPrefix(name, ":1.") { - connIDs[name] = true - } else { - owner := m.getNameOwner(name) - if owner != "" { - connIDs[owner] = true - } - } - } - return connIDs -} - -// scanWellKnownNames probes well-known names (e.g. DinoX, nm-applet) for -// unregistered SNI items and re-registers them. -func (m *Manager) scanWellKnownNames(allNames []string, registeredItems []string, registeredConnIDs map[string]bool) { - registeredRaw := strings.Join(registeredItems, "\n") - - for _, name := range allNames { - if strings.HasPrefix(name, ":") { - continue - } - - if strings.Contains(registeredRaw, name) { - continue - } - - // Skip if this name's connection ID is already in the registered set - // (handles the case where the app registered via connection ID instead) - connForName := m.getNameOwner(name) - if connForName != "" && registeredConnIDs[connForName] { - continue - } - - if isExcludedName(name) { - continue - } - - short := shortName(name) - objectPaths := []string{ - "/StatusNotifierItem", - "/org/ayatana/NotificationItem/" + short, - } - - for _, objPath := range objectPaths { - if m.probeSNI(name, objPath, probeTimeout) { - m.registerSNI(name) - // Update set so the connection-ID section won't double-register this app - if connForName != "" { - registeredConnIDs[connForName] = true - } - break - } - } - } -} - -// scanConnectionIDs probes all :1.xxx connections in parallel for unregistered -// SNI items (e.g. Vesktop, Electron apps). Most non-SNI connections return an -// error instantly, so this is fast. -func (m *Manager) scanConnectionIDs(allNames []string, registeredItems []string, registeredConnIDs map[string]bool) { - registeredRaw := strings.Join(registeredItems, "\n") - registeredLower := strings.ToLower(registeredRaw) - - var wg sync.WaitGroup - sem := make(chan struct{}, batchSize) - - for _, name := range allNames { - if !strings.HasPrefix(name, ":1.") { - continue - } - if registeredConnIDs[name] { - continue - } - - sem <- struct{}{} - wg.Add(1) - go func(conn string) { - defer wg.Done() - defer func() { <-sem }() - - sniID := m.getSNIId(conn, connProbeTimeout) - if sniID == "" { - return - } - - // Skip if an item with the same Id is already registered (case-insensitive) - if strings.Contains(registeredLower, strings.ToLower(sniID)) { - return - } - - m.registerSNI(conn) - log.Infof("TrayRecovery: re-registered %s (Id: %s)", conn, sniID) - }(name) - } - wg.Wait() -} - -func (m *Manager) probeSNI(dest, path string, timeout time.Duration) bool { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - obj := m.conn.Object(dest, dbus.ObjectPath(path)) - var props map[string]dbus.Variant - err := obj.CallWithContext(ctx, propsIface+".GetAll", 0, sniItemIface).Store(&props) - if err != nil { - return false - } - - _, hasID := props["Id"] - return hasID -} - -func (m *Manager) getSNIId(dest string, timeout time.Duration) string { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - obj := m.conn.Object(dest, "/StatusNotifierItem") - var variant dbus.Variant - err := obj.CallWithContext(ctx, propsIface+".Get", 0, sniItemIface, "Id").Store(&variant) - if err != nil { - return "" - } - - id, _ := variant.Value().(string) - return id -} - -func (m *Manager) registerSNI(name string) { - obj := m.conn.Object(sniWatcherDest, sniWatcherPath) - call := obj.Call(sniWatcherIface+".RegisterStatusNotifierItem", 0, name) - if call.Err != nil { - log.Warnf("TrayRecovery: failed to register %s: %v", name, call.Err) - return - } - log.Infof("TrayRecovery: re-registered %s", name) -} - -func extractName(item string) string { - if idx := strings.IndexByte(item, '/'); idx != -1 { - return item[:idx] - } - return item -} - -func shortName(name string) string { - parts := strings.Split(name, ".") - if len(parts) > 0 { - return parts[len(parts)-1] - } - return name -} - -func isExcludedName(name string) bool { - for _, prefix := range excludedPrefixes { - if strings.HasPrefix(name, prefix) { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma.go deleted file mode 100644 index 1fff03f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma.go +++ /dev/null @@ -1,167 +0,0 @@ -package wayland - -import ( - "math" -) - -type GammaRamp struct { - Red []uint16 - Green []uint16 - Blue []uint16 -} - -type rgb struct { - r, g, b float64 -} - -type xyz struct { - x, y, z float64 -} - -func illuminantD(temp int) (float64, float64, bool) { - var x float64 - switch { - case temp >= 2500 && temp <= 7000: - t := float64(temp) - x = 0.244063 + 0.09911e3/t + 2.9678e6/(t*t) - 4.6070e9/(t*t*t) - case temp > 7000 && temp <= 25000: - t := float64(temp) - x = 0.237040 + 0.24748e3/t + 1.9018e6/(t*t) - 2.0064e9/(t*t*t) - default: - return 0, 0, false - } - y := -3*(x*x) + 2.870*x - 0.275 - return x, y, true -} - -func planckianLocus(temp int) (float64, float64, bool) { - var x, y float64 - switch { - case temp >= 1667 && temp <= 4000: - t := float64(temp) - x = -0.2661239e9/(t*t*t) - 0.2343589e6/(t*t) + 0.8776956e3/t + 0.179910 - if temp <= 2222 { - y = -1.1064814*(x*x*x) - 1.34811020*(x*x) + 2.18555832*x - 0.20219683 - } else { - y = -0.9549476*(x*x*x) - 1.37418593*(x*x) + 2.09137015*x - 0.16748867 - } - case temp > 4000 && temp < 25000: - t := float64(temp) - x = -3.0258469e9/(t*t*t) + 2.1070379e6/(t*t) + 0.2226347e3/t + 0.240390 - y = 3.0817580*(x*x*x) - 5.87338670*(x*x) + 3.75112997*x - 0.37001483 - default: - return 0, 0, false - } - return x, y, true -} - -func srgbGamma(value, gamma float64) float64 { - if value <= 0.0031308 { - return 12.92 * value - } - return math.Pow(1.055*value, 1.0/gamma) - 0.055 -} - -func clamp01(v float64) float64 { - switch { - case v > 1.0: - return 1.0 - case v < 0.0: - return 0.0 - default: - return v - } -} - -func xyzToSRGB(c xyz) rgb { - return rgb{ - r: srgbGamma(clamp01(3.2404542*c.x-1.5371385*c.y-0.4985314*c.z), 2.2), - g: srgbGamma(clamp01(-0.9692660*c.x+1.8760108*c.y+0.0415560*c.z), 2.2), - b: srgbGamma(clamp01(0.0556434*c.x-0.2040259*c.y+1.0572252*c.z), 2.2), - } -} - -func normalizeRGB(c *rgb) { - maxw := math.Max(c.r, math.Max(c.g, c.b)) - if maxw > 0 { - c.r /= maxw - c.g /= maxw - c.b /= maxw - } -} - -func calcWhitepoint(temp int) rgb { - if temp == 6500 { - return rgb{r: 1.0, g: 1.0, b: 1.0} - } - - var wp xyz - - switch { - case temp >= 25000: - x, y, _ := illuminantD(25000) - wp.x = x - wp.y = y - case temp >= 4000: - x, y, _ := illuminantD(temp) - wp.x = x - wp.y = y - case temp >= 2500: - x1, y1, _ := illuminantD(temp) - x2, y2, _ := planckianLocus(temp) - factor := float64(4000-temp) / 1500.0 - sineFactor := (math.Cos(math.Pi*factor) + 1.0) / 2.0 - wp.x = x1*sineFactor + x2*(1.0-sineFactor) - wp.y = y1*sineFactor + y2*(1.0-sineFactor) - default: - t := temp - if t < 1667 { - t = 1667 - } - x, y, _ := planckianLocus(t) - wp.x = x - wp.y = y - } - - wp.z = 1.0 - wp.x - wp.y - - wpRGB := xyzToSRGB(wp) - normalizeRGB(&wpRGB) - return wpRGB -} - -func GenerateGammaRamp(size uint32, temp int, gamma float64) GammaRamp { - ramp := GammaRamp{ - Red: make([]uint16, size), - Green: make([]uint16, size), - Blue: make([]uint16, size), - } - - wp := calcWhitepoint(temp) - - for i := uint32(0); i < size; i++ { - val := float64(i) / float64(size-1) - ramp.Red[i] = uint16(clamp01(math.Pow(val*wp.r, 1.0/gamma)) * 65535.0) - ramp.Green[i] = uint16(clamp01(math.Pow(val*wp.g, 1.0/gamma)) * 65535.0) - ramp.Blue[i] = uint16(clamp01(math.Pow(val*wp.b, 1.0/gamma)) * 65535.0) - } - - return ramp -} - -func GenerateIdentityRamp(size uint32) GammaRamp { - ramp := GammaRamp{ - Red: make([]uint16, size), - Green: make([]uint16, size), - Blue: make([]uint16, size), - } - - for i := uint32(0); i < size; i++ { - val := uint16((float64(i) / float64(size-1)) * 65535.0) - ramp.Red[i] = val - ramp.Green[i] = val - ramp.Blue[i] = val - } - - return ramp -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma_test.go deleted file mode 100644 index 0bf8e71..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/gamma_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package wayland - -import ( - "testing" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func TestGenerateGammaRamp(t *testing.T) { - tests := []struct { - name string - size uint32 - temp int - gamma float64 - }{ - {"small_warm", 16, 6500, 1.0}, - {"small_cool", 16, 4000, 1.0}, - {"large_warm", 256, 6500, 1.0}, - {"large_cool", 256, 4000, 1.0}, - {"custom_gamma", 64, 5500, 1.2}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ramp := GenerateGammaRamp(tt.size, tt.temp, tt.gamma) - - if len(ramp.Red) != int(tt.size) { - t.Errorf("expected %d red values, got %d", tt.size, len(ramp.Red)) - } - if len(ramp.Green) != int(tt.size) { - t.Errorf("expected %d green values, got %d", tt.size, len(ramp.Green)) - } - if len(ramp.Blue) != int(tt.size) { - t.Errorf("expected %d blue values, got %d", tt.size, len(ramp.Blue)) - } - - if ramp.Red[0] != 0 || ramp.Green[0] != 0 || ramp.Blue[0] != 0 { - t.Errorf("first values should be 0, got R:%d G:%d B:%d", - ramp.Red[0], ramp.Green[0], ramp.Blue[0]) - } - - lastIdx := tt.size - 1 - if ramp.Red[lastIdx] == 0 || ramp.Green[lastIdx] == 0 || ramp.Blue[lastIdx] == 0 { - t.Errorf("last values should be non-zero, got R:%d G:%d B:%d", - ramp.Red[lastIdx], ramp.Green[lastIdx], ramp.Blue[lastIdx]) - } - - for i := uint32(1); i < tt.size; i++ { - if ramp.Red[i] < ramp.Red[i-1] { - t.Errorf("red ramp not monotonic at index %d", i) - } - } - }) - } -} - -func TestCalcWhitepoint(t *testing.T) { - tests := []struct { - name string - temp int - }{ - {"very_warm", 6500}, - {"neutral", 5500}, - {"cool", 4000}, - {"very_cool", 3000}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - wp := calcWhitepoint(tt.temp) - - if wp.r < 0 || wp.r > 1 { - t.Errorf("red out of range: %f", wp.r) - } - if wp.g < 0 || wp.g > 1 { - t.Errorf("green out of range: %f", wp.g) - } - if wp.b < 0 || wp.b > 1 { - t.Errorf("blue out of range: %f", wp.b) - } - }) - } -} - -func TestWhitepointProgression(t *testing.T) { - temps := []int{3000, 4000, 5000, 6000, 6500} - - var prevBlue float64 - for i, temp := range temps { - wp := calcWhitepoint(temp) - if i > 0 && wp.b < prevBlue { - t.Errorf("blue should increase with temperature, %d->%d: %f->%f", - temps[i-1], temp, prevBlue, wp.b) - } - prevBlue = wp.b - } -} - -func TestClamp(t *testing.T) { - tests := []struct { - val float64 - min float64 - max float64 - expected float64 - }{ - {5, 0, 10, 5}, - {-5, 0, 10, 0}, - {15, 0, 10, 10}, - {0, 0, 10, 0}, - {10, 0, 10, 10}, - } - - for _, tt := range tests { - result := utils.Clamp(tt.val, tt.min, tt.max) - if result != tt.expected { - t.Errorf("clamp(%f, %f, %f) = %f, want %f", - tt.val, tt.min, tt.max, result, tt.expected) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/geolocation.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/geolocation.go deleted file mode 100644 index ba99b5f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/geolocation.go +++ /dev/null @@ -1,50 +0,0 @@ -package wayland - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -type ipAPIResponse struct { - Lat float64 `json:"lat"` - Lon float64 `json:"lon"` - City string `json:"city"` -} - -func FetchIPLocation() (*float64, *float64, error) { - client := &http.Client{ - Timeout: 10 * time.Second, - } - - resp, err := client.Get("http://ip-api.com/json/") - if err != nil { - return nil, nil, fmt.Errorf("failed to fetch IP location: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, nil, fmt.Errorf("ip-api.com returned status %d", resp.StatusCode) - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, nil, fmt.Errorf("failed to read response: %w", err) - } - - var data ipAPIResponse - if err := json.Unmarshal(body, &data); err != nil { - return nil, nil, fmt.Errorf("failed to parse response: %w", err) - } - - if data.Lat == 0 && data.Lon == 0 { - return nil, nil, fmt.Errorf("missing location data in response") - } - - log.Infof("Fetched IP-based location: %s (%.4f, %.4f)", data.City, data.Lat, data.Lon) - return &data.Lat, &data.Lon, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/handlers.go deleted file mode 100644 index 76b08b5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/handlers.go +++ /dev/null @@ -1,182 +0,0 @@ -package wayland - -import ( - "encoding/json" - "fmt" - "net" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - if manager == nil { - models.RespondError(conn, req.ID, "wayland manager not initialized") - return - } - - switch req.Method { - case "wayland.gamma.getState": - handleGetState(conn, req, manager) - case "wayland.gamma.setTemperature": - handleSetTemperature(conn, req, manager) - case "wayland.gamma.setLocation": - handleSetLocation(conn, req, manager) - case "wayland.gamma.setManualTimes": - handleSetManualTimes(conn, req, manager) - case "wayland.gamma.setUseIPLocation": - handleSetUseIPLocation(conn, req, manager) - case "wayland.gamma.setGamma": - handleSetGamma(conn, req, manager) - case "wayland.gamma.setEnabled": - handleSetEnabled(conn, req, manager) - case "wayland.gamma.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleSetTemperature(conn net.Conn, req models.Request, manager *Manager) { - var lowTemp, highTemp int - - if temp, ok := models.Get[float64](req, "temp"); ok { - lowTemp = int(temp) - highTemp = int(temp) - } else { - low, err := params.Float(req.Params, "low") - if err != nil { - models.RespondError(conn, req.ID, "missing temperature parameters (provide 'temp' or both 'low' and 'high')") - return - } - high, err := params.Float(req.Params, "high") - if err != nil { - models.RespondError(conn, req.ID, "missing temperature parameters (provide 'temp' or both 'low' and 'high')") - return - } - lowTemp = int(low) - highTemp = int(high) - } - - if err := manager.SetTemperature(lowTemp, highTemp); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "temperature set"}) -} - -func handleSetLocation(conn net.Conn, req models.Request, manager *Manager) { - lat, err := params.Float(req.Params, "latitude") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - lon, err := params.Float(req.Params, "longitude") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetLocation(lat, lon); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "location set"}) -} - -func handleSetManualTimes(conn net.Conn, req models.Request, manager *Manager) { - sunriseStr, sunriseOK := models.Get[string](req, "sunrise") - sunsetStr, sunsetOK := models.Get[string](req, "sunset") - - if !sunriseOK || !sunsetOK || sunriseStr == "" || sunsetStr == "" { - manager.ClearManualTimes() - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "manual times cleared"}) - return - } - - sunrise, err := time.Parse("15:04", sunriseStr) - if err != nil { - models.RespondError(conn, req.ID, "invalid sunrise format (use HH:MM)") - return - } - - sunset, err := time.Parse("15:04", sunsetStr) - if err != nil { - models.RespondError(conn, req.ID, "invalid sunset format (use HH:MM)") - return - } - - if err := manager.SetManualTimes(sunrise, sunset); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "manual times set"}) -} - -func handleSetUseIPLocation(conn net.Conn, req models.Request, manager *Manager) { - use, err := params.Bool(req.Params, "use") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetUseIPLocation(use) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "IP location preference set"}) -} - -func handleSetGamma(conn net.Conn, req models.Request, manager *Manager) { - gamma, err := params.Float(req.Params, "gamma") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - if err := manager.SetGamma(gamma); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "gamma set"}) -} - -func handleSetEnabled(conn net.Conn, req models.Request, manager *Manager) { - enabled, err := params.Bool(req.Params, "enabled") - if err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - manager.SetEnabled(enabled) - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "enabled state set"}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range stateChan { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - Result: &state, - }); err != nil { - return - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager.go deleted file mode 100644 index 3540e3d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager.go +++ /dev/null @@ -1,1256 +0,0 @@ -package wayland - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "os" - "slices" - "syscall" - "time" - - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/godbus/dbus/v5" - "golang.org/x/sys/unix" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_gamma_control" -) - -const animKelvinStep = 25 - -func NewManager(display wlclient.WaylandDisplay, config Config) (*Manager, error) { - if err := config.Validate(); err != nil { - return nil, err - } - - if config.ElevationTwilight == 0 { - config.ElevationTwilight = -6.0 - } - if config.ElevationDaylight == 0 { - config.ElevationDaylight = 3.0 - } - - m := &Manager{ - config: config, - display: display, - ctx: display.Context(), - cmdq: make(chan cmd, 128), - stopChan: make(chan struct{}), - updateTrigger: make(chan struct{}, 1), - dirty: make(chan struct{}, 1), - dbusSignal: make(chan *dbus.Signal, 16), - } - - if err := m.setupRegistry(); err != nil { - return nil, err - } - - if err := m.setupDBusMonitor(); err != nil { - log.Warnf("Failed to setup D-Bus monitoring: %v", err) - } - - m.alive = true - m.recalcSchedule(time.Now()) - m.updateStateFromSchedule() - - m.notifierWg.Add(1) - go m.notifier() - - m.wg.Add(1) - go m.schedulerLoop() - - if m.dbusConn != nil { - m.wg.Add(1) - go m.dbusMonitor() - } - - m.wg.Add(1) - go m.waylandActor() - - if config.Enabled { - m.post(func() { - log.Info("Gamma control enabled at startup") - gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1) - m.availOutputsMu.RLock() - outs := slices.Clone(m.availableOutputs) - m.availOutputsMu.RUnlock() - if err := m.setupOutputControls(outs, gammaMgr); err != nil { - log.Errorf("Failed to initialize gamma controls: %v", err) - return - } - m.controlsInitialized = true - }) - } - - return m, nil -} - -func (m *Manager) post(fn func()) { - select { - case m.cmdq <- cmd{fn: fn}: - default: - log.Warn("Actor command queue full") - } -} - -func (m *Manager) waylandActor() { - defer m.wg.Done() - for { - select { - case <-m.stopChan: - return - case c := <-m.cmdq: - c.fn() - } - } -} - -func (m *Manager) anyOutputReady() bool { - anyReady := false - m.outputs.Range(func(_ uint32, out *outputState) bool { - if out.rampSize > 0 && !out.failed { - anyReady = true - return false // stop iteration - } - return true - }) - return anyReady -} - -func (m *Manager) setupDBusMonitor() error { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return fmt.Errorf("system bus: %w", err) - } - - matchRule := "type='signal',interface='org.freedesktop.login1.Manager',member='PrepareForSleep',path='/org/freedesktop/login1'" - if err := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, matchRule).Err; err != nil { - conn.Close() - return fmt.Errorf("add match: %w", err) - } - - conn.Signal(m.dbusSignal) - m.dbusConn = conn - return nil -} - -func (m *Manager) setupRegistry() error { - registry, err := m.display.GetRegistry() - if err != nil { - return fmt.Errorf("get registry: %w", err) - } - m.registry = registry - - outputs := make([]*wlclient.Output, 0) - outputNames := make(map[uint32]string) - var gammaMgr *wlr_gamma_control.ZwlrGammaControlManagerV1 - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - switch e.Interface { - case wlr_gamma_control.ZwlrGammaControlManagerV1InterfaceName: - manager := wlr_gamma_control.NewZwlrGammaControlManagerV1(m.ctx) - version := e.Version - if version > 1 { - version = 1 - } - if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil { - gammaMgr = manager - } - case "wl_output": - output := wlclient.NewOutput(m.ctx) - version := e.Version - if version > 4 { - version = 4 - } - if err := registry.Bind(e.Name, e.Interface, version, output); err != nil { - return - } - outputID := output.ID() - output.SetNameHandler(func(ev wlclient.OutputNameEvent) { - outputNames[outputID] = ev.Name - }) - if gammaMgr != nil { - outputs = append(outputs, output) - m.addAvailableOutput(output) - } - m.outputRegNames.Store(outputID, e.Name) - - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - - if enabled && m.controlsInitialized { - m.post(func() { - if err := m.addOutputControl(output); err != nil { - log.Warnf("Failed to add output control: %v", err) - } - }) - } - } - }) - - registry.SetGlobalRemoveHandler(func(e wlclient.RegistryGlobalRemoveEvent) { - m.post(func() { - var foundID uint32 - var foundOut *outputState - m.outputs.Range(func(id uint32, out *outputState) bool { - if out.registryName == e.Name { - foundID = id - foundOut = out - return false - } - return true - }) - if foundOut == nil { - return - } - if foundOut.gammaControl != nil { - foundOut.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1).Destroy() - foundOut.gammaControl = nil - } - m.removeAvailableOutput(foundOut.output) - if foundOut.output != nil && !foundOut.output.IsZombie() { - _ = foundOut.output.Release() - } - m.outputs.Delete(foundID) - - hasOutputs := false - m.outputs.Range(func(_ uint32, _ *outputState) bool { - hasOutputs = true - return false - }) - if !hasOutputs { - m.controlsInitialized = false - } - }) - }) - - if err := m.display.Roundtrip(); err != nil { - return fmt.Errorf("roundtrip 1: %w", err) - } - if err := m.display.Roundtrip(); err != nil { - return fmt.Errorf("roundtrip 2: %w", err) - } - - if gammaMgr == nil { - return errdefs.ErrNoGammaControl - } - if len(outputs) == 0 { - return fmt.Errorf("no outputs") - } - - physicalOutputs := make([]*wlclient.Output, 0, len(outputs)) - for _, output := range outputs { - name := outputNames[output.ID()] - if len(name) >= 9 && name[:9] == "HEADLESS-" { - continue - } - physicalOutputs = append(physicalOutputs, output) - } - - m.gammaControl = gammaMgr - m.availableOutputs = physicalOutputs - return nil -} - -func (m *Manager) setupOutputControls(outputs []*wlclient.Output, manager *wlr_gamma_control.ZwlrGammaControlManagerV1) error { - for _, output := range outputs { - control, err := manager.GetGammaControl(output) - if err != nil { - continue - } - outputID := output.ID() - registryName, _ := m.outputRegNames.Load(outputID) - outState := &outputState{ - id: outputID, - registryName: registryName, - output: output, - gammaControl: control, - } - m.setupControlHandlers(outState, control) - m.outputs.Store(outputID, outState) - } - return nil -} - -func (m *Manager) setupControlHandlers(state *outputState, control *wlr_gamma_control.ZwlrGammaControlV1) { - outputID := state.id - - control.SetGammaSizeHandler(func(e wlr_gamma_control.ZwlrGammaControlV1GammaSizeEvent) { - size := e.Size - m.post(func() { - if out, ok := m.outputs.Load(outputID); ok { - out.rampSize = size - out.failed = false - out.retryCount = 0 - } - m.lastAppliedTemp = 0 - m.applyCurrentTemp("gamma_size") - }) - }) - - control.SetFailedHandler(func(_ wlr_gamma_control.ZwlrGammaControlV1FailedEvent) { - m.post(func() { - out, ok := m.outputs.Load(outputID) - if !ok { - return - } - if ctrl, ok := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1); ok && ctrl != nil && !ctrl.IsZombie() { - ctrl.Destroy() - } - out.gammaControl = nil - out.failed = true - out.rampSize = 0 - out.retryCount++ - out.lastFailTime = time.Now() - - if !m.outputStillValid(out) { - return - } - - backoff := time.Duration(300<= 10: - return nil - case !m.outputStillValid(out): - return nil - } - if _, ok := m.outputs.Load(out.id); !ok { - return nil - } - - gammaMgr, ok := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1) - if !ok { - return fmt.Errorf("no gamma manager") - } - - if existing, ok := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1); ok && existing != nil && !existing.IsZombie() { - existing.Destroy() - out.gammaControl = nil - } - - control, err := gammaMgr.GetGammaControl(out.output) - if err != nil { - if isConnectionDeadErr(err) { - m.markConnectionDead(err) - } - return err - } - - m.setupControlHandlers(out, control) - out.gammaControl = control - out.failed = false - return nil -} - -func (m *Manager) markConnectionDead(err error) { - if m.connectionDead.Swap(true) { - return - } - log.Errorf("gamma: wayland connection appears dead (%v); pausing gamma operations", err) -} - -func (m *Manager) recalcSchedule(now time.Time) { - m.configMutex.RLock() - config := m.config - m.configMutex.RUnlock() - - m.scheduleMutex.Lock() - defer m.scheduleMutex.Unlock() - - dayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) - alreadyValid := !m.schedule.times.Sunrise.IsZero() - if m.schedule.calcDay.Equal(dayStart) && alreadyValid { - return - } - - var times SunTimes - var cond SunCondition - - if config.ManualSunrise != nil && config.ManualSunset != nil { - dur := time.Hour - if config.ManualDuration != nil { - dur = *config.ManualDuration - } - sunrise := time.Date(now.Year(), now.Month(), now.Day(), - config.ManualSunrise.Hour(), config.ManualSunrise.Minute(), config.ManualSunrise.Second(), 0, now.Location()) - sunset := time.Date(now.Year(), now.Month(), now.Day(), - config.ManualSunset.Hour(), config.ManualSunset.Minute(), config.ManualSunset.Second(), 0, now.Location()) - times = SunTimes{ - Dawn: sunrise.Add(-dur), - Sunrise: sunrise, - Sunset: sunset, - Night: sunset.Add(dur), - } - cond = SunNormal - } else { - lat, lon := m.getLocation() - if lat == nil || lon == nil { - m.gammaState = StateStatic - return - } - times, cond = CalculateSunTimesWithTwilight(*lat, *lon, now, config.ElevationTwilight, config.ElevationDaylight) - } - - m.schedule.calcDay = dayStart - m.schedule.times = times - m.schedule.condition = cond - - switch cond { - case SunNormal: - m.gammaState = StateNormal - tempDiff := config.HighTemp - config.LowTemp - if tempDiff > 0 { - dawnDur := times.Sunrise.Sub(times.Dawn) - nightDur := times.Night.Sub(times.Sunset) - m.schedule.dawnStepTime = time.Duration(max(1, int(dawnDur.Seconds())*animKelvinStep/tempDiff)) * time.Second - m.schedule.nightStepTime = time.Duration(max(1, int(nightDur.Seconds())*animKelvinStep/tempDiff)) * time.Second - } - case SunMidnightSun: - m.gammaState = StateStatic - case SunPolarNight: - m.gammaState = StateStatic - } -} - -func (m *Manager) SetGeoClient(client geolocation.Client) { - m.geoClient = client -} - -func (m *Manager) getLocation() (*float64, *float64) { - m.configMutex.RLock() - config := m.config - m.configMutex.RUnlock() - - if config.Latitude != nil && config.Longitude != nil { - return config.Latitude, config.Longitude - } - if !config.UseIPLocation { - return nil, nil - } - if m.geoClient == nil { - return nil, nil - } - - m.locationMutex.RLock() - if m.cachedIPLat != nil && m.cachedIPLon != nil { - lat, lon := m.cachedIPLat, m.cachedIPLon - m.locationMutex.RUnlock() - return lat, lon - } - m.locationMutex.RUnlock() - - location, err := m.geoClient.GetLocation() - if err != nil { - return nil, nil - } - - m.locationMutex.Lock() - m.cachedIPLat = &location.Latitude - m.cachedIPLon = &location.Longitude - m.locationMutex.Unlock() - return m.cachedIPLat, m.cachedIPLon -} - -func (m *Manager) hasValidSchedule() bool { - m.scheduleMutex.RLock() - defer m.scheduleMutex.RUnlock() - return !m.schedule.times.Sunrise.IsZero() -} - -func (m *Manager) getSunPosition(now time.Time) float64 { - m.scheduleMutex.RLock() - sched := m.schedule - state := m.gammaState - m.scheduleMutex.RUnlock() - - if sched.times.Sunrise.IsZero() { - return 1.0 - } - - switch state { - case StateStatic: - if sched.condition == SunMidnightSun { - return 1.0 - } - return 0.0 - case StateNormal: - return m.getSunPositionNormal(now, sched.times) - } - return 1.0 -} - -func (m *Manager) getSunPositionNormal(now time.Time, times SunTimes) float64 { - if now.Before(times.Dawn) { - return 0.0 - } - if now.Before(times.Sunrise) { - return interpolate(now, times.Dawn, times.Sunrise) - } - if now.Before(times.Sunset) { - return 1.0 - } - if now.Before(times.Night) { - return interpolate(now, times.Night, times.Sunset) - } - return 0.0 -} - -func interpolate(now time.Time, start, stop time.Time) float64 { - if start.Equal(stop) { - return 1.0 - } - pos := float64(now.Sub(start)) / float64(stop.Sub(start)) - switch { - case pos > 1.0: - return 1.0 - case pos < 0.0: - return 0.0 - default: - return pos - } -} - -func (m *Manager) getTempFromPosition(pos float64) int { - m.configMutex.RLock() - low, high := m.config.LowTemp, m.config.HighTemp - m.configMutex.RUnlock() - return low + int(float64(high-low)*pos) -} - -func (m *Manager) getNextDeadline(now time.Time) time.Time { - m.scheduleMutex.RLock() - sched := m.schedule - state := m.gammaState - m.scheduleMutex.RUnlock() - - switch state { - case StateStatic: - return m.tomorrow(now) - case StateNormal: - return m.getDeadlineNormal(now, sched) - default: - return m.tomorrow(now) - } -} - -func (m *Manager) getDeadlineNormal(now time.Time, sched sunSchedule) time.Time { - times := sched.times - switch { - case now.Before(times.Dawn): - return times.Dawn - case now.Before(times.Sunrise): - return now.Add(sched.dawnStepTime) - case now.Before(times.Sunset): - return times.Sunset - case now.Before(times.Night): - return now.Add(sched.nightStepTime) - default: - return m.tomorrowDawn(now) - } -} - -func (m *Manager) tomorrowDawn(now time.Time) time.Time { - tomorrow := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, now.Location()) - - m.configMutex.RLock() - config := m.config - m.configMutex.RUnlock() - - if config.ManualSunrise != nil { - dur := time.Hour - if config.ManualDuration != nil { - dur = *config.ManualDuration - } - return time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), - config.ManualSunrise.Hour(), config.ManualSunrise.Minute(), config.ManualSunrise.Second(), 0, tomorrow.Location()).Add(-dur) - } - - lat, lon := m.getLocation() - if lat == nil || lon == nil { - return tomorrow - } - - times, cond := CalculateSunTimesWithTwilight(*lat, *lon, tomorrow, config.ElevationTwilight, config.ElevationDaylight) - if cond != SunNormal { - return tomorrow - } - return times.Dawn -} - -func (m *Manager) tomorrow(now time.Time) time.Time { - return time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, now.Location()) -} - -func (m *Manager) schedulerLoop() { - defer m.wg.Done() - - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - - if enabled { - m.post(func() { m.applyCurrentTemp("startup") }) - } - - var timer *time.Timer - for { - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - - now := time.Now() - m.recalcSchedule(now) - - var waitDur time.Duration - if enabled { - deadline := m.getNextDeadline(now) - waitDur = time.Until(deadline) - if waitDur < time.Second { - waitDur = time.Second - } - } else { - waitDur = 24 * time.Hour - } - - if timer != nil { - timer.Stop() - } - timer = time.NewTimer(waitDur) - - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.updateTrigger: - timer.Stop() - m.scheduleMutex.Lock() - m.schedule.calcDay = time.Time{} - m.scheduleMutex.Unlock() - m.recalcSchedule(time.Now()) - m.updateStateFromSchedule() - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - if enabled { - m.post(func() { m.applyCurrentTemp("updateTrigger") }) - } - case <-timer.C: - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - if enabled { - m.post(func() { m.applyCurrentTemp("timer") }) - } - } - } -} - -func (m *Manager) applyCurrentTemp(_ string) { - if !m.controlsInitialized || !m.anyOutputReady() { - return - } - - // Ensure schedule is up-to-date (handles display wake after overnight sleep) - m.recalcSchedule(time.Now()) - - m.configMutex.RLock() - low, high := m.config.LowTemp, m.config.HighTemp - m.configMutex.RUnlock() - - if low == high { - m.applyGamma(low) - m.updateStateFromSchedule() - return - } - - if !m.hasValidSchedule() { - m.updateStateFromSchedule() - return - } - - now := time.Now() - pos := m.getSunPosition(now) - temp := m.getTempFromPosition(pos) - - m.applyGamma(temp) - m.updateStateFromSchedule() -} - -func (m *Manager) applyGamma(temp int) { - m.configMutex.RLock() - gamma := m.config.Gamma - m.configMutex.RUnlock() - - switch { - case m.connectionDead.Load(): - return - case !m.controlsInitialized: - return - case m.lastAppliedTemp == temp && m.lastAppliedGamma == gamma: - return - } - - var outs []*outputState - m.outputs.Range(func(_ uint32, out *outputState) bool { - outs = append(outs, out) - return true - }) - if len(outs) == 0 { - return - } - - type job struct { - out *outputState - data []byte - } - var jobs []job - - for _, out := range outs { - switch { - case out.failed: - continue - case out.rampSize == 0: - continue - case out.gammaControl == nil: - continue - case !m.outputStillValid(out): - continue - } - ramp := GenerateGammaRamp(out.rampSize, temp, gamma) - buf := bytes.NewBuffer(make([]byte, 0, int(out.rampSize)*6)) - for _, v := range ramp.Red { - binary.Write(buf, binary.LittleEndian, v) - } - for _, v := range ramp.Green { - binary.Write(buf, binary.LittleEndian, v) - } - for _, v := range ramp.Blue { - binary.Write(buf, binary.LittleEndian, v) - } - jobs = append(jobs, job{out: out, data: buf.Bytes()}) - } - - for _, j := range jobs { - err := m.setGammaBytes(j.out, j.data) - if err == nil { - continue - } - log.Warnf("gamma: failed to set output %d: %v", j.out.id, err) - j.out.failed = true - j.out.rampSize = 0 - if isConnectionDeadErr(err) { - m.markConnectionDead(err) - return - } - } - - m.lastAppliedTemp = temp - m.lastAppliedGamma = gamma -} - -func (m *Manager) setGammaBytes(out *outputState, data []byte) error { - if out.gammaControl == nil { - return fmt.Errorf("no gamma control") - } - ctrl, ok := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1) - if !ok || ctrl == nil || ctrl.IsZombie() { - return fmt.Errorf("gamma control invalid") - } - - fd, err := MemfdCreate("gamma-ramp", 0) - if err != nil { - return err - } - defer syscall.Close(fd) - - if err := syscall.Ftruncate(fd, int64(len(data))); err != nil { - return err - } - - dupFd, err := syscall.Dup(fd) - if err != nil { - return err - } - f := os.NewFile(uintptr(dupFd), "gamma") - defer f.Close() - - if _, err := f.Write(data); err != nil { - return err - } - syscall.Seek(fd, 0, 0) - - return ctrl.SetGamma(fd) -} - -func (m *Manager) updateStateFromSchedule() { - now := time.Now() - - m.configMutex.RLock() - config := m.config - m.configMutex.RUnlock() - - m.scheduleMutex.RLock() - times := m.schedule.times - m.scheduleMutex.RUnlock() - - var pos float64 - var temp int - var isDay bool - var deadline time.Time - - if times.Sunrise.IsZero() { - pos = 1.0 - temp = config.HighTemp - isDay = true - deadline = m.tomorrow(now) - } else { - pos = m.getSunPosition(now) - temp = m.getTempFromPosition(pos) - deadline = m.getNextDeadline(now) - isDay = now.After(times.Sunrise) && now.Before(times.Sunset) - } - - newState := State{ - Config: config, - CurrentTemp: temp, - NextTransition: deadline, - SunriseTime: times.Sunrise, - SunsetTime: times.Sunset, - DawnTime: times.Dawn, - NightTime: times.Night, - IsDay: isDay, - SunPosition: pos, - } - - m.stateMutex.Lock() - m.state = &newState - m.stateMutex.Unlock() - - m.notifySubscribers() -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - currentState := m.GetState() - if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) { - pending = false - continue - } - m.subscribers.Range(func(_ string, ch chan State) bool { - select { - case ch <- currentState: - default: - } - return true - }) - stateCopy := currentState - m.lastNotified = &stateCopy - pending = false - } - } -} - -func (m *Manager) dbusMonitor() { - defer m.wg.Done() - for { - select { - case <-m.stopChan: - return - case sig := <-m.dbusSignal: - if sig == nil { - continue - } - m.handleDBusSignal(sig) - } - } -} - -func (m *Manager) handleDBusSignal(sig *dbus.Signal) { - switch { - case sig.Name != "org.freedesktop.login1.Manager.PrepareForSleep": - return - case len(sig.Body) == 0: - return - } - preparing, ok := sig.Body[0].(bool) - if !ok || preparing { - return - } - m.configMutex.RLock() - enabled := m.config.Enabled - m.configMutex.RUnlock() - if !enabled { - return - } - time.AfterFunc(500*time.Millisecond, func() { - m.post(m.handleResume) - }) -} - -func (m *Manager) handleResume() { - m.configMutex.RLock() - stillEnabled := m.config.Enabled - m.configMutex.RUnlock() - - switch { - case !stillEnabled: - return - case !m.controlsInitialized: - return - case m.connectionDead.Load(): - return - } - - // Compositors (Niri, Hyprland, wlroots-based) re-apply the cached gamma - // ramp to DRM on resume; gamma_control objects stay valid. We just need - // to force a resend so the schedule catches up with the current time of - // day — the original #1235 regression was caused by lastAppliedTemp - // matching and the send being skipped. - m.recalcSchedule(time.Now()) - m.lastAppliedTemp = 0 - m.applyCurrentTemp("resume") -} - -func (m *Manager) triggerUpdate() { - select { - case m.updateTrigger <- struct{}{}: - default: - } -} - -func (m *Manager) SetConfig(config Config) error { - if err := config.Validate(); err != nil { - return err - } - m.configMutex.Lock() - m.config = config - m.configMutex.Unlock() - m.triggerUpdate() - return nil -} - -func (m *Manager) SetTemperature(low, high int) error { - m.configMutex.Lock() - if m.config.LowTemp == low && m.config.HighTemp == high { - m.configMutex.Unlock() - return nil - } - m.config.LowTemp = low - m.config.HighTemp = high - err := m.config.Validate() - m.configMutex.Unlock() - if err != nil { - return err - } - m.triggerUpdate() - return nil -} - -func (m *Manager) SetLocation(lat, lon float64) error { - m.configMutex.Lock() - if m.config.Latitude != nil && m.config.Longitude != nil && - *m.config.Latitude == lat && *m.config.Longitude == lon && !m.config.UseIPLocation { - m.configMutex.Unlock() - return nil - } - m.config.Latitude = &lat - m.config.Longitude = &lon - m.config.UseIPLocation = false - err := m.config.Validate() - m.configMutex.Unlock() - if err != nil { - return err - } - m.triggerUpdate() - return nil -} - -func (m *Manager) SetUseIPLocation(use bool) { - m.configMutex.Lock() - if m.config.UseIPLocation == use { - m.configMutex.Unlock() - return - } - m.config.UseIPLocation = use - if use { - m.config.Latitude = nil - m.config.Longitude = nil - } - m.configMutex.Unlock() - - if use { - m.locationMutex.Lock() - m.cachedIPLat = nil - m.cachedIPLon = nil - m.locationMutex.Unlock() - } - m.triggerUpdate() -} - -func (m *Manager) SetManualTimes(sunrise, sunset time.Time) error { - m.configMutex.Lock() - if m.config.ManualSunrise != nil && m.config.ManualSunset != nil && - m.config.ManualSunrise.Hour() == sunrise.Hour() && m.config.ManualSunrise.Minute() == sunrise.Minute() && - m.config.ManualSunset.Hour() == sunset.Hour() && m.config.ManualSunset.Minute() == sunset.Minute() { - m.configMutex.Unlock() - return nil - } - m.config.ManualSunrise = &sunrise - m.config.ManualSunset = &sunset - err := m.config.Validate() - m.configMutex.Unlock() - if err != nil { - return err - } - m.triggerUpdate() - return nil -} - -func (m *Manager) ClearManualTimes() { - m.configMutex.Lock() - if m.config.ManualSunrise == nil && m.config.ManualSunset == nil { - m.configMutex.Unlock() - return - } - m.config.ManualSunrise = nil - m.config.ManualSunset = nil - m.configMutex.Unlock() - m.triggerUpdate() -} - -func (m *Manager) SetGamma(gamma float64) error { - m.configMutex.Lock() - if m.config.Gamma == gamma { - m.configMutex.Unlock() - return nil - } - m.config.Gamma = gamma - err := m.config.Validate() - m.configMutex.Unlock() - if err != nil { - return err - } - m.triggerUpdate() - return nil -} - -func (m *Manager) SetEnabled(enabled bool) { - m.configMutex.Lock() - wasEnabled := m.config.Enabled - if wasEnabled == enabled { - m.configMutex.Unlock() - return - } - m.config.Enabled = enabled - highTemp := m.config.HighTemp - m.configMutex.Unlock() - - switch { - case enabled && !m.controlsInitialized: - m.post(func() { - gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1) - m.availOutputsMu.RLock() - outs := slices.Clone(m.availableOutputs) - m.availOutputsMu.RUnlock() - if err := m.setupOutputControls(outs, gammaMgr); err != nil { - log.Errorf("gamma: failed to create controls: %v", err) - return - } - m.controlsInitialized = true - m.triggerUpdate() - }) - case enabled && !wasEnabled: - m.triggerUpdate() - case !enabled && m.controlsInitialized: - m.post(func() { - m.outputs.Range(func(id uint32, out *outputState) bool { - if out.gammaControl != nil { - out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1).Destroy() - } - return true - }) - m.outputs.Range(func(key uint32, _ *outputState) bool { - m.outputs.Delete(key) - return true - }) - m.controlsInitialized = false - }) - _ = highTemp - } -} - -func (m *Manager) Close() { - close(m.stopChan) - m.wg.Wait() - m.notifierWg.Wait() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.outputs.Range(func(_ uint32, out *outputState) bool { - if ctrl, ok := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1); ok { - ctrl.Destroy() - } - return true - }) - m.outputs.Range(func(key uint32, _ *outputState) bool { - m.outputs.Delete(key) - return true - }) - - if manager, ok := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1); ok { - manager.Destroy() - } - - if m.dbusConn != nil { - m.dbusConn.RemoveSignal(m.dbusSignal) - m.dbusConn.Close() - } -} - -func MemfdCreate(name string, flags int) (int, error) { - fd, err := unix.MemfdCreate(name, flags) - if err != nil { - return -1, err - } - return fd, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager_test.go deleted file mode 100644 index 8c00129..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/manager_test.go +++ /dev/null @@ -1,414 +0,0 @@ -package wayland - -import ( - "errors" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient" -) - -func TestManager_ActorSerializesOutputStateAccess(t *testing.T) { - m := &Manager{ - cmdq: make(chan cmd, 8192), - stopChan: make(chan struct{}), - } - - m.wg.Add(1) - go m.waylandActor() - - state := &outputState{ - id: 1, - registryName: 100, - rampSize: 256, - } - m.outputs.Store(state.id, state) - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.post(func() { - if out, ok := m.outputs.Load(state.id); ok { - out.rampSize = uint32(j) - out.failed = j%2 == 0 - out.retryCount = j - out.lastFailTime = time.Now() - } - }) - } - }(i) - } - - wg.Wait() - - done := make(chan struct{}) - m.post(func() { close(done) }) - <-done - - close(m.stopChan) - m.wg.Wait() -} - -func TestManager_ConcurrentSubscriberAccess(t *testing.T) { - m := &Manager{ - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - updateTrigger: make(chan struct{}, 1), - } - - var wg sync.WaitGroup - const goroutines = 20 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - subID := string(rune('a' + id)) - ch := m.Subscribe(subID) - assert.NotNil(t, ch) - time.Sleep(time.Millisecond) - m.Unsubscribe(subID) - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentGetState(t *testing.T) { - m := &Manager{ - state: &State{ - CurrentTemp: 5000, - IsDay: true, - }, - } - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - s := m.GetState() - assert.GreaterOrEqual(t, s.CurrentTemp, 0) - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.stateMutex.Lock() - m.state = &State{ - CurrentTemp: 4000 + i*100, - IsDay: j%2 == 0, - } - m.stateMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentConfigAccess(t *testing.T) { - m := &Manager{ - config: DefaultConfig(), - } - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.configMutex.RLock() - _ = m.config.LowTemp - _ = m.config.HighTemp - _ = m.config.Enabled - m.configMutex.RUnlock() - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.configMutex.Lock() - m.config.LowTemp = 3000 + j - m.config.HighTemp = 7000 - j - m.config.Enabled = j%2 == 0 - m.configMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapOutputsConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &outputState{ - id: key, - rampSize: uint32(j), - failed: j%2 == 0, - } - m.outputs.Store(key, state) - - if loaded, ok := m.outputs.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.outputs.Range(func(k uint32, v *outputState) bool { - _ = v.rampSize - _ = v.failed - return true - }) - } - - m.outputs.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_LocationCacheConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.locationMutex.RLock() - _ = m.cachedIPLat - _ = m.cachedIPLon - m.locationMutex.RUnlock() - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - lat := float64(40 + i) - lon := float64(-74 + j) - m.locationMutex.Lock() - m.cachedIPLat = &lat - m.cachedIPLon = &lon - m.locationMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ScheduleConcurrentAccess(t *testing.T) { - now := time.Now() - m := &Manager{ - schedule: sunSchedule{ - times: SunTimes{ - Dawn: now, - Sunrise: now.Add(time.Hour), - Sunset: now.Add(12 * time.Hour), - Night: now.Add(13 * time.Hour), - }, - }, - } - - var wg sync.WaitGroup - const goroutines = 20 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.scheduleMutex.RLock() - _ = m.schedule.times.Dawn - _ = m.schedule.times.Sunrise - _ = m.schedule.times.Sunset - _ = m.schedule.condition - m.scheduleMutex.RUnlock() - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.scheduleMutex.Lock() - m.schedule.times.Dawn = time.Now() - m.schedule.times.Sunrise = time.Now().Add(time.Hour) - m.schedule.condition = SunNormal - m.scheduleMutex.Unlock() - } - }() - } - - wg.Wait() -} - -func TestInterpolate_EdgeCases(t *testing.T) { - now := time.Now() - - tests := []struct { - name string - now time.Time - start time.Time - stop time.Time - expected float64 - }{ - { - name: "same start and stop", - now: now, - start: now, - stop: now, - expected: 1.0, - }, - { - name: "now before start", - now: now, - start: now.Add(time.Hour), - stop: now.Add(2 * time.Hour), - expected: 0.0, - }, - { - name: "now after stop", - now: now.Add(3 * time.Hour), - start: now, - stop: now.Add(time.Hour), - expected: 1.0, - }, - { - name: "now at midpoint", - now: now.Add(30 * time.Minute), - start: now, - stop: now.Add(time.Hour), - expected: 0.5, - }, - { - name: "now equals start", - now: now, - start: now, - stop: now.Add(time.Hour), - expected: 0.0, - }, - { - name: "now equals stop", - now: now.Add(time.Hour), - start: now, - stop: now.Add(time.Hour), - expected: 1.0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := interpolate(tt.now, tt.start, tt.stop) - assert.InDelta(t, tt.expected, result, 0.01) - }) - } -} - -func TestGenerateGammaRamp_ZeroSize(t *testing.T) { - ramp := GenerateGammaRamp(0, 5000, 1.0) - assert.Empty(t, ramp.Red) - assert.Empty(t, ramp.Green) - assert.Empty(t, ramp.Blue) -} - -func TestGenerateGammaRamp_ValidSizes(t *testing.T) { - sizes := []uint32{1, 256, 1024} - temps := []int{1000, 4000, 6500, 10000} - gammas := []float64{0.5, 1.0, 2.0} - - for _, size := range sizes { - for _, temp := range temps { - for _, gamma := range gammas { - ramp := GenerateGammaRamp(size, temp, gamma) - assert.Len(t, ramp.Red, int(size)) - assert.Len(t, ramp.Green, int(size)) - assert.Len(t, ramp.Blue, int(size)) - } - } - } -} - -func TestNotifySubscribers_NonBlocking(t *testing.T) { - m := &Manager{ - dirty: make(chan struct{}, 1), - } - - for i := 0; i < 10; i++ { - m.notifySubscribers() - } - - assert.Len(t, m.dirty, 1) -} - -func TestNewManager_GetRegistryError(t *testing.T) { - mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t) - - mockDisplay.EXPECT().Context().Return(nil) - mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry")) - - config := DefaultConfig() - _, err := NewManager(mockDisplay, config) - assert.Error(t, err) - assert.Contains(t, err.Error(), "get registry") -} - -func TestNewManager_InvalidConfig(t *testing.T) { - mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t) - - config := Config{ - LowTemp: 500, - HighTemp: 6500, - Gamma: 1.0, - } - - _, err := NewManager(mockDisplay, config) - assert.Error(t, err) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc.go deleted file mode 100644 index c978a8e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc.go +++ /dev/null @@ -1,122 +0,0 @@ -package wayland - -import ( - "math" - "time" -) - -const ( - degToRad = math.Pi / 180.0 - radToDeg = 180.0 / math.Pi -) - -type SunCondition int - -const ( - SunNormal SunCondition = iota - SunMidnightSun - SunPolarNight -) - -type SunTimes struct { - Dawn time.Time - Sunrise time.Time - Sunset time.Time - Night time.Time -} - -func daysInYear(year int) int { - if (year%4 == 0 && year%100 != 0) || year%400 == 0 { - return 366 - } - return 365 -} - -func dateOrbitAngle(t time.Time) float64 { - return 2 * math.Pi / float64(daysInYear(t.Year())) * float64(t.YearDay()-1) -} - -func equationOfTime(orbitAngle float64) float64 { - return 4 * (0.000075 + - 0.001868*math.Cos(orbitAngle) - - 0.032077*math.Sin(orbitAngle) - - 0.014615*math.Cos(2*orbitAngle) - - 0.040849*math.Sin(2*orbitAngle)) -} - -func sunDeclination(orbitAngle float64) float64 { - return 0.006918 - - 0.399912*math.Cos(orbitAngle) + - 0.070257*math.Sin(orbitAngle) - - 0.006758*math.Cos(2*orbitAngle) + - 0.000907*math.Sin(2*orbitAngle) - - 0.002697*math.Cos(3*orbitAngle) + - 0.00148*math.Sin(3*orbitAngle) -} - -func sunHourAngle(latRad, declination, targetSunRad float64) float64 { - return math.Acos(math.Cos(targetSunRad)/ - math.Cos(latRad)*math.Cos(declination) - - math.Tan(latRad)*math.Tan(declination)) -} - -func hourAngleToSeconds(hourAngle, eqtime float64) float64 { - return radToDeg * (4.0*math.Pi - 4*hourAngle - eqtime) * 60 -} - -func sunCondition(latRad, declination float64) SunCondition { - signLat := latRad >= 0 - signDecl := declination >= 0 - if signLat == signDecl { - return SunMidnightSun - } - return SunPolarNight -} - -func CalculateSunTimesWithTwilight(lat, lon float64, date time.Time, elevTwilight, elevDaylight float64) (SunTimes, SunCondition) { - latRad := lat * degToRad - elevTwilightRad := (90.833 - elevTwilight) * degToRad - elevDaylightRad := (90.833 - elevDaylight) * degToRad - - utc := date.UTC() - orbitAngle := dateOrbitAngle(utc) - decl := sunDeclination(orbitAngle) - eqtime := equationOfTime(orbitAngle) - - haTwilight := sunHourAngle(latRad, decl, elevTwilightRad) - haDaylight := sunHourAngle(latRad, decl, elevDaylightRad) - - if math.IsNaN(haTwilight) || math.IsNaN(haDaylight) { - cond := sunCondition(latRad, decl) - return SunTimes{}, cond - } - - dayStart := time.Date(utc.Year(), utc.Month(), utc.Day(), 0, 0, 0, 0, time.UTC) - lonOffset := time.Duration(-lon*4) * time.Minute - - dawnSecs := hourAngleToSeconds(math.Abs(haTwilight), eqtime) - sunriseSecs := hourAngleToSeconds(math.Abs(haDaylight), eqtime) - sunsetSecs := hourAngleToSeconds(-math.Abs(haDaylight), eqtime) - nightSecs := hourAngleToSeconds(-math.Abs(haTwilight), eqtime) - - return SunTimes{ - Dawn: dayStart.Add(time.Duration(dawnSecs)*time.Second + lonOffset).In(date.Location()), - Sunrise: dayStart.Add(time.Duration(sunriseSecs)*time.Second + lonOffset).In(date.Location()), - Sunset: dayStart.Add(time.Duration(sunsetSecs)*time.Second + lonOffset).In(date.Location()), - Night: dayStart.Add(time.Duration(nightSecs)*time.Second + lonOffset).In(date.Location()), - }, SunNormal -} - -func CalculateSunTimes(lat, lon float64, date time.Time) SunTimes { - times, cond := CalculateSunTimesWithTwilight(lat, lon, date, -6.0, 3.0) - switch cond { - case SunMidnightSun: - dayStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location()) - dayEnd := dayStart.Add(24*time.Hour - time.Second) - return SunTimes{Dawn: dayStart, Sunrise: dayStart, Sunset: dayEnd, Night: dayEnd} - case SunPolarNight: - dayStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location()) - return SunTimes{Dawn: dayStart, Sunrise: dayStart, Sunset: dayStart, Night: dayStart} - } - return times -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc_test.go deleted file mode 100644 index b2815d9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/suncalc_test.go +++ /dev/null @@ -1,387 +0,0 @@ -package wayland - -import ( - "math" - "testing" - "time" -) - -func calculateTemperature(config Config, now time.Time) int { - if !config.Enabled { - return config.HighTemp - } - - var sunrise, sunset time.Time - - if config.ManualSunrise != nil && config.ManualSunset != nil { - year, month, day := now.Date() - loc := now.Location() - - sunrise = time.Date(year, month, day, - config.ManualSunrise.Hour(), - config.ManualSunrise.Minute(), - config.ManualSunrise.Second(), 0, loc) - sunset = time.Date(year, month, day, - config.ManualSunset.Hour(), - config.ManualSunset.Minute(), - config.ManualSunset.Second(), 0, loc) - - if sunset.Before(sunrise) { - sunset = sunset.Add(24 * time.Hour) - } - } else if config.UseIPLocation { - lat, lon, err := FetchIPLocation() - if err != nil { - return config.HighTemp - } - times := CalculateSunTimes(*lat, *lon, now) - sunrise = times.Sunrise - sunset = times.Sunset - } else if config.Latitude != nil && config.Longitude != nil { - times := CalculateSunTimes(*config.Latitude, *config.Longitude, now) - sunrise = times.Sunrise - sunset = times.Sunset - } else { - return config.HighTemp - } - - if now.Before(sunrise) || now.After(sunset) { - return config.LowTemp - } - return config.HighTemp -} - -func calculateNextTransition(config Config, now time.Time) time.Time { - if !config.Enabled { - return now.Add(24 * time.Hour) - } - - var sunrise, sunset time.Time - - if config.ManualSunrise != nil && config.ManualSunset != nil { - year, month, day := now.Date() - loc := now.Location() - - sunrise = time.Date(year, month, day, - config.ManualSunrise.Hour(), - config.ManualSunrise.Minute(), - config.ManualSunrise.Second(), 0, loc) - sunset = time.Date(year, month, day, - config.ManualSunset.Hour(), - config.ManualSunset.Minute(), - config.ManualSunset.Second(), 0, loc) - - if sunset.Before(sunrise) { - sunset = sunset.Add(24 * time.Hour) - } - } else if config.UseIPLocation { - lat, lon, err := FetchIPLocation() - if err != nil { - return now.Add(24 * time.Hour) - } - times := CalculateSunTimes(*lat, *lon, now) - sunrise = times.Sunrise - sunset = times.Sunset - } else if config.Latitude != nil && config.Longitude != nil { - times := CalculateSunTimes(*config.Latitude, *config.Longitude, now) - sunrise = times.Sunrise - sunset = times.Sunset - } else { - return now.Add(24 * time.Hour) - } - - if now.Before(sunrise) { - return sunrise - } - if now.Before(sunset) { - return sunset - } - - if config.ManualSunrise != nil && config.ManualSunset != nil { - year, month, day := now.Add(24 * time.Hour).Date() - loc := now.Location() - nextSunrise := time.Date(year, month, day, - config.ManualSunrise.Hour(), - config.ManualSunrise.Minute(), - config.ManualSunrise.Second(), 0, loc) - return nextSunrise - } - - if config.UseIPLocation { - lat, lon, err := FetchIPLocation() - if err != nil { - return now.Add(24 * time.Hour) - } - nextDayTimes := CalculateSunTimes(*lat, *lon, now.Add(24*time.Hour)) - return nextDayTimes.Sunrise - } - - if config.Latitude != nil && config.Longitude != nil { - nextDayTimes := CalculateSunTimes(*config.Latitude, *config.Longitude, now.Add(24*time.Hour)) - return nextDayTimes.Sunrise - } - - return now.Add(24 * time.Hour) -} - -func TestCalculateSunTimes(t *testing.T) { - tests := []struct { - name string - lat float64 - lon float64 - date time.Time - checkFunc func(*testing.T, SunTimes) - }{ - { - name: "new_york_summer", - lat: 40.7128, - lon: -74.0060, - date: time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local), - checkFunc: func(t *testing.T, times SunTimes) { - if times.Sunrise.Hour() < 4 || times.Sunrise.Hour() > 6 { - t.Logf("sunrise: %v", times.Sunrise) - } - if times.Sunset.Hour() < 19 || times.Sunset.Hour() > 21 { - t.Logf("sunset: %v", times.Sunset) - } - if !times.Sunset.After(times.Sunrise) { - t.Error("sunset should be after sunrise") - } - }, - }, - { - name: "london_winter", - lat: 51.5074, - lon: -0.1278, - date: time.Date(2024, 12, 21, 12, 0, 0, 0, time.UTC), - checkFunc: func(t *testing.T, times SunTimes) { - if times.Sunrise.Hour() < 7 || times.Sunrise.Hour() > 9 { - t.Errorf("unexpected sunrise hour: %d", times.Sunrise.Hour()) - } - if times.Sunset.Hour() < 15 || times.Sunset.Hour() > 17 { - t.Errorf("unexpected sunset hour: %d", times.Sunset.Hour()) - } - }, - }, - { - name: "equator_equinox", - lat: 0.0, - lon: 0.0, - date: time.Date(2024, 3, 20, 12, 0, 0, 0, time.UTC), - checkFunc: func(t *testing.T, times SunTimes) { - if times.Sunrise.Hour() < 5 || times.Sunrise.Hour() > 7 { - t.Errorf("unexpected sunrise hour: %d", times.Sunrise.Hour()) - } - if times.Sunset.Hour() < 17 || times.Sunset.Hour() > 19 { - t.Errorf("unexpected sunset hour: %d", times.Sunset.Hour()) - } - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - times := CalculateSunTimes(tt.lat, tt.lon, tt.date) - tt.checkFunc(t, times) - }) - } -} - -func TestCalculateTemperature(t *testing.T) { - lat := 40.7128 - lon := -74.0060 - date := time.Date(2024, 6, 21, 0, 0, 0, 0, time.Local) - - config := Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: &lat, - Longitude: &lon, - Enabled: true, - } - - times := CalculateSunTimes(lat, lon, date) - - tests := []struct { - name string - timeFunc func() time.Time - wantTemp int - }{ - { - name: "midnight", - timeFunc: func() time.Time { return times.Sunrise.Add(-4 * time.Hour) }, - wantTemp: 4000, - }, - { - name: "sunrise", - timeFunc: func() time.Time { return times.Sunrise }, - wantTemp: 6500, - }, - { - name: "noon", - timeFunc: func() time.Time { return times.Sunrise.Add(6 * time.Hour) }, - wantTemp: 6500, - }, - { - name: "after_sunset_transition", - timeFunc: func() time.Time { return times.Sunset.Add(2 * time.Hour) }, - wantTemp: 4000, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - temp := calculateTemperature(config, tt.timeFunc()) - - if math.Abs(float64(temp-tt.wantTemp)) > 500 { - t.Errorf("temperature = %d, want approximately %d", temp, tt.wantTemp) - } - }) - } -} - -func TestCalculateTemperatureManualTimes(t *testing.T) { - sunrise := time.Date(0, 1, 1, 6, 30, 0, 0, time.Local) - sunset := time.Date(0, 1, 1, 18, 30, 0, 0, time.Local) - - config := Config{ - LowTemp: 4000, - HighTemp: 6500, - ManualSunrise: &sunrise, - ManualSunset: &sunset, - Enabled: true, - } - - tests := []struct { - name string - time time.Time - want int - }{ - {"before_sunrise", time.Date(2024, 1, 1, 3, 0, 0, 0, time.Local), 4000}, - {"at_sunrise", time.Date(2024, 1, 1, 6, 30, 0, 0, time.Local), 6500}, - {"midday", time.Date(2024, 1, 1, 12, 0, 0, 0, time.Local), 6500}, - {"at_sunset", time.Date(2024, 1, 1, 18, 30, 0, 0, time.Local), 6500}, - {"after_sunset", time.Date(2024, 1, 1, 22, 0, 0, 0, time.Local), 4000}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - temp := calculateTemperature(config, tt.time) - if math.Abs(float64(temp-tt.want)) > 500 { - t.Errorf("temperature = %d, want approximately %d", temp, tt.want) - } - }) - } -} - -func TestCalculateTemperatureDisabled(t *testing.T) { - lat := 40.7128 - lon := -74.0060 - - config := Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: &lat, - Longitude: &lon, - Enabled: false, - } - - temp := calculateTemperature(config, time.Now()) - if temp != 6500 { - t.Errorf("disabled should return high temp, got %d", temp) - } -} - -func TestCalculateNextTransition(t *testing.T) { - lat := 40.7128 - lon := -74.0060 - date := time.Date(2024, 6, 21, 0, 0, 0, 0, time.Local) - - config := Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: &lat, - Longitude: &lon, - Enabled: true, - } - - times := CalculateSunTimes(lat, lon, date) - - tests := []struct { - name string - now time.Time - checkFunc func(*testing.T, time.Time) - }{ - { - name: "before_sunrise", - now: times.Sunrise.Add(-2 * time.Hour), - checkFunc: func(t *testing.T, next time.Time) { - if !next.Equal(times.Sunrise) && !next.After(times.Sunrise.Add(-1*time.Minute)) { - t.Error("next transition should be at or near sunrise") - } - }, - }, - { - name: "after_sunrise", - now: times.Sunrise.Add(2 * time.Hour), - checkFunc: func(t *testing.T, next time.Time) { - if !next.After(times.Sunrise) { - t.Error("next transition should be after sunrise") - } - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - next := calculateNextTransition(config, tt.now) - tt.checkFunc(t, next) - }) - } -} - -func TestSunTimesWithTwilight(t *testing.T) { - lat := 40.7128 - lon := -74.0060 - date := time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local) - - times, cond := CalculateSunTimesWithTwilight(lat, lon, date, -6.0, 3.0) - - if cond != SunNormal { - t.Errorf("expected SunNormal, got %v", cond) - } - if !times.Dawn.Before(times.Sunrise) { - t.Error("dawn should be before sunrise") - } - if !times.Sunrise.Before(times.Sunset) { - t.Error("sunrise should be before sunset") - } - if !times.Sunset.Before(times.Night) { - t.Error("sunset should be before night") - } -} - -func TestSunConditions(t *testing.T) { - tests := []struct { - name string - lat float64 - date time.Time - expected SunCondition - }{ - { - name: "normal_conditions", - lat: 40.0, - date: time.Date(2024, 6, 21, 12, 0, 0, 0, time.UTC), - expected: SunNormal, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, cond := CalculateSunTimesWithTwilight(tt.lat, 0, tt.date, -6.0, 3.0) - if cond != tt.expected { - t.Errorf("expected condition %v, got %v", tt.expected, cond) - } - }) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types.go deleted file mode 100644 index 31bac15..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types.go +++ /dev/null @@ -1,216 +0,0 @@ -package wayland - -import ( - "math" - "sync" - "sync/atomic" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/geolocation" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/godbus/dbus/v5" -) - -type GammaState int - -const ( - StateNormal GammaState = iota - StateTransition - StateStatic -) - -type Config struct { - Outputs []string - LowTemp int - HighTemp int - Latitude *float64 - Longitude *float64 - UseIPLocation bool - ManualSunrise *time.Time - ManualSunset *time.Time - ManualDuration *time.Duration - Gamma float64 - Enabled bool - ElevationTwilight float64 - ElevationDaylight float64 -} - -type State struct { - Config Config `json:"config"` - CurrentTemp int `json:"currentTemp"` - NextTransition time.Time `json:"nextTransition"` - SunriseTime time.Time `json:"sunriseTime"` - SunsetTime time.Time `json:"sunsetTime"` - DawnTime time.Time `json:"dawnTime"` - NightTime time.Time `json:"nightTime"` - IsDay bool `json:"isDay"` - SunPosition float64 `json:"sunPosition"` -} - -type cmd struct { - fn func() -} - -type sunSchedule struct { - times SunTimes - condition SunCondition - dawnStepTime time.Duration - nightStepTime time.Duration - calcDay time.Time -} - -type Manager struct { - config Config - configMutex sync.RWMutex - state *State - stateMutex sync.RWMutex - - display wlclient.WaylandDisplay - ctx *wlclient.Context - registry *wlclient.Registry - gammaControl any - availableOutputs []*wlclient.Output - availOutputsMu sync.RWMutex - outputRegNames syncmap.Map[uint32, uint32] - outputs syncmap.Map[uint32, *outputState] - controlsInitialized bool - connectionDead atomic.Bool - - cmdq chan cmd - alive bool - - stopChan chan struct{} - updateTrigger chan struct{} - wg sync.WaitGroup - - schedule sunSchedule - scheduleMutex sync.RWMutex - gammaState GammaState - - cachedIPLat *float64 - cachedIPLon *float64 - locationMutex sync.RWMutex - - subscribers syncmap.Map[string, chan State] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotified *State - - dbusConn *dbus.Conn - dbusSignal chan *dbus.Signal - - geoClient geolocation.Client - - lastAppliedTemp int - lastAppliedGamma float64 -} - -type outputState struct { - id uint32 - registryName uint32 - output *wlclient.Output - gammaControl any - rampSize uint32 - failed bool - isVirtual bool - retryCount int - lastFailTime time.Time -} - -func DefaultConfig() Config { - return Config{ - Outputs: []string{}, - LowTemp: 4000, - HighTemp: 6500, - Gamma: 1.0, - Enabled: false, - ElevationTwilight: -6.0, - ElevationDaylight: 3.0, - } -} - -func (c *Config) Validate() error { - if c.LowTemp < 1000 || c.LowTemp > 10000 { - return errdefs.ErrInvalidTemperature - } - if c.HighTemp < 1000 || c.HighTemp > 10000 { - return errdefs.ErrInvalidTemperature - } - if c.LowTemp > c.HighTemp { - return errdefs.ErrInvalidTemperature - } - if c.Gamma <= 0 || c.Gamma > 10 { - return errdefs.ErrInvalidGamma - } - if c.Latitude != nil && (math.Abs(*c.Latitude) > 90) { - return errdefs.ErrInvalidLocation - } - if c.Longitude != nil && (math.Abs(*c.Longitude) > 180) { - return errdefs.ErrInvalidLocation - } - if (c.Latitude != nil) != (c.Longitude != nil) { - return errdefs.ErrInvalidLocation - } - if (c.ManualSunrise != nil) != (c.ManualSunset != nil) { - return errdefs.ErrInvalidManualTimes - } - return nil -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{} - } - return *m.state -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func stateChanged(old, new *State) bool { - if old == nil || new == nil { - return true - } - if old.CurrentTemp != new.CurrentTemp { - return true - } - if old.IsDay != new.IsDay { - return true - } - if !old.NextTransition.Equal(new.NextTransition) { - return true - } - if !old.SunriseTime.Equal(new.SunriseTime) { - return true - } - if !old.SunsetTime.Equal(new.SunsetTime) { - return true - } - if old.Config.Enabled != new.Config.Enabled { - return true - } - if old.SunPosition != new.SunPosition { - return true - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types_test.go deleted file mode 100644 index f5bbb42..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wayland/types_test.go +++ /dev/null @@ -1,330 +0,0 @@ -package wayland - -import ( - "testing" - "time" -) - -func TestConfigValidate(t *testing.T) { - tests := []struct { - name string - config Config - wantErr bool - }{ - { - name: "valid_default", - config: DefaultConfig(), - wantErr: false, - }, - { - name: "valid_with_location", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(40.7128), - Longitude: floatPtr(-74.0060), - Gamma: 1.0, - Enabled: true, - }, - wantErr: false, - }, - { - name: "valid_manual_times", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - ManualSunrise: timePtr(time.Date(0, 1, 1, 6, 30, 0, 0, time.Local)), - ManualSunset: timePtr(time.Date(0, 1, 1, 18, 30, 0, 0, time.Local)), - Gamma: 1.0, - Enabled: true, - }, - wantErr: false, - }, - { - name: "invalid_low_temp_too_low", - config: Config{ - LowTemp: 500, - HighTemp: 6500, - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_low_temp_too_high", - config: Config{ - LowTemp: 15000, - HighTemp: 20000, - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_high_temp_too_low", - config: Config{ - LowTemp: 4000, - HighTemp: 500, - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "valid_temps_equal", - config: Config{ - LowTemp: 5000, - HighTemp: 5000, - Gamma: 1.0, - }, - wantErr: false, - }, - { - name: "invalid_temps_reversed", - config: Config{ - LowTemp: 6500, - HighTemp: 4000, - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_gamma_zero", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Gamma: 0, - }, - wantErr: true, - }, - { - name: "invalid_gamma_negative", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Gamma: -1.0, - }, - wantErr: true, - }, - { - name: "invalid_gamma_too_high", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Gamma: 15.0, - }, - wantErr: true, - }, - { - name: "invalid_latitude_too_high", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(100), - Longitude: floatPtr(0), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_latitude_too_low", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(-100), - Longitude: floatPtr(0), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_longitude_too_high", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(40), - Longitude: floatPtr(200), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_longitude_too_low", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(40), - Longitude: floatPtr(-200), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_latitude_without_longitude", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Latitude: floatPtr(40), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_longitude_without_latitude", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Longitude: floatPtr(-74), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_sunrise_without_sunset", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - ManualSunrise: timePtr(time.Date(0, 1, 1, 6, 30, 0, 0, time.Local)), - Gamma: 1.0, - }, - wantErr: true, - }, - { - name: "invalid_sunset_without_sunrise", - config: Config{ - LowTemp: 4000, - HighTemp: 6500, - ManualSunset: timePtr(time.Date(0, 1, 1, 18, 30, 0, 0, time.Local)), - Gamma: 1.0, - }, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.config.Validate() - if (err != nil) != tt.wantErr { - t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestDefaultConfig(t *testing.T) { - config := DefaultConfig() - - if config.LowTemp != 4000 { - t.Errorf("default low temp = %d, want 4000", config.LowTemp) - } - if config.HighTemp != 6500 { - t.Errorf("default high temp = %d, want 6500", config.HighTemp) - } - if config.Gamma != 1.0 { - t.Errorf("default gamma = %f, want 1.0", config.Gamma) - } - if config.Enabled { - t.Error("default should be disabled") - } - if config.Latitude != nil { - t.Error("default should not have latitude") - } - if config.Longitude != nil { - t.Error("default should not have longitude") - } -} - -func TestStateChanged(t *testing.T) { - baseState := &State{ - CurrentTemp: 5000, - NextTransition: time.Now(), - SunriseTime: time.Now().Add(6 * time.Hour), - SunsetTime: time.Now().Add(18 * time.Hour), - IsDay: true, - Config: DefaultConfig(), - } - - tests := []struct { - name string - old *State - new *State - wantChanged bool - }{ - { - name: "nil_old", - old: nil, - new: baseState, - wantChanged: true, - }, - { - name: "nil_new", - old: baseState, - new: nil, - wantChanged: true, - }, - { - name: "same_state", - old: baseState, - new: baseState, - wantChanged: false, - }, - { - name: "temp_changed", - old: baseState, - new: &State{ - CurrentTemp: 6000, - NextTransition: baseState.NextTransition, - SunriseTime: baseState.SunriseTime, - SunsetTime: baseState.SunsetTime, - IsDay: baseState.IsDay, - Config: baseState.Config, - }, - wantChanged: true, - }, - { - name: "is_day_changed", - old: baseState, - new: &State{ - CurrentTemp: baseState.CurrentTemp, - NextTransition: baseState.NextTransition, - SunriseTime: baseState.SunriseTime, - SunsetTime: baseState.SunsetTime, - IsDay: false, - Config: baseState.Config, - }, - wantChanged: true, - }, - { - name: "enabled_changed", - old: baseState, - new: &State{ - CurrentTemp: baseState.CurrentTemp, - NextTransition: baseState.NextTransition, - SunriseTime: baseState.SunriseTime, - SunsetTime: baseState.SunsetTime, - IsDay: baseState.IsDay, - Config: Config{ - LowTemp: 4000, - HighTemp: 6500, - Gamma: 1.0, - Enabled: true, - }, - }, - wantChanged: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - changed := stateChanged(tt.old, tt.new) - if changed != tt.wantChanged { - t.Errorf("stateChanged() = %v, want %v", changed, tt.wantChanged) - } - }) - } -} - -func floatPtr(f float64) *float64 { - return &f -} - -func timePtr(t time.Time) *time.Time { - return &t -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go deleted file mode 100644 index 9bbb30a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go +++ /dev/null @@ -1,200 +0,0 @@ -package wlcontext - -import ( - "fmt" - "golang.org/x/sys/unix" - "os" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type WaylandContext interface { - Display() *wlclient.Display - Post(fn func()) - FatalError() <-chan error - Start() - Close() -} - -var _ WaylandContext = (*SharedContext)(nil) - -type SharedContext struct { - display *wlclient.Display - stopChan chan struct{} - fatalError chan error - cmdQueue chan func() - wakeR int - wakeW int - wg sync.WaitGroup - mu sync.Mutex - started bool -} - -func New() (*SharedContext, error) { - display, err := wlclient.Connect("") - if err != nil { - return nil, fmt.Errorf("%w: %v", errdefs.ErrNoWaylandDisplay, err) - } - - fds := make([]int, 2) - if err := unix.Pipe(fds); err != nil { - display.Context().Close() - return nil, fmt.Errorf("failed to create wake pipe: %w", err) - } - if err := unix.SetNonblock(fds[0], true); err != nil { - unix.Close(fds[0]) - unix.Close(fds[1]) - display.Context().Close() - return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err) - } - if err := unix.SetNonblock(fds[1], true); err != nil { - unix.Close(fds[0]) - unix.Close(fds[1]) - display.Context().Close() - return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err) - } - - sc := &SharedContext{ - display: display, - stopChan: make(chan struct{}), - fatalError: make(chan error, 1), - cmdQueue: make(chan func(), 256), - wakeR: fds[0], - wakeW: fds[1], - started: false, - } - - return sc, nil -} - -func (sc *SharedContext) Start() { - sc.mu.Lock() - defer sc.mu.Unlock() - - if sc.started { - return - } - - sc.started = true - sc.wg.Add(1) - go sc.eventDispatcher() -} - -func (sc *SharedContext) Display() *wlclient.Display { - return sc.display -} - -func (sc *SharedContext) Post(fn func()) { - select { - case sc.cmdQueue <- fn: - if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe write error: %v", err) - } - default: - } -} - -func (sc *SharedContext) FatalError() <-chan error { - return sc.fatalError -} - -func (sc *SharedContext) eventDispatcher() { - defer sc.wg.Done() - defer func() { - if r := recover(); r != nil { - err := fmt.Errorf("FATAL: Wayland event dispatcher panic: %v", r) - log.Error(err) - select { - case sc.fatalError <- err: - default: - } - } - }() - - ctx := sc.display.Context() - wlFd := ctx.Fd() - - pollFds := []unix.PollFd{ - {Fd: int32(wlFd), Events: unix.POLLIN}, - {Fd: int32(sc.wakeR), Events: unix.POLLIN}, - } - - consecutiveErrors := 0 - const maxConsecutiveErrors = 20 - - for { - sc.drainCmdQueue() - - select { - case <-sc.stopChan: - return - default: - } - - _, err := unix.Poll(pollFds, -1) - switch { - case err == unix.EINTR: - continue - case err != nil: - log.Errorf("Poll error: %v", err) - return - } - - if pollFds[1].Revents&unix.POLLIN != 0 { - var buf [64]byte - if _, err := unix.Read(sc.wakeR, buf[:]); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe read error: %v", err) - } - } - - if pollFds[0].Revents&unix.POLLIN == 0 { - continue - } - - if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) { - consecutiveErrors++ - log.Warnf("Wayland connection error (%d/%d): %v", consecutiveErrors, maxConsecutiveErrors, err) - - if consecutiveErrors >= maxConsecutiveErrors { - log.Errorf("Fatal: Wayland connection unrecoverable after %d attempts. Exiting dispatcher.", maxConsecutiveErrors) - return - } - - time.Sleep(100 * time.Millisecond * time.Duration(consecutiveErrors)) - continue - } - - consecutiveErrors = 0 - } -} - -func (sc *SharedContext) drainCmdQueue() { - for { - select { - case fn := <-sc.cmdQueue: - fn() - default: - return - } - } -} - -func (sc *SharedContext) Close() { - close(sc.stopChan) - if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe write error on close: %v", err) - } - sc.wg.Wait() - - unix.Close(sc.wakeR) - unix.Close(sc.wakeW) - - if sc.display == nil { - return - } - sc.display.Context().Close() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go deleted file mode 100644 index 11ecfbf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package wlcontext - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "golang.org/x/sys/unix" -) - -func newTestSharedContext(t *testing.T, queueSize int) *SharedContext { - t.Helper() - fds := make([]int, 2) - if err := unix.Pipe(fds); err != nil { - t.Fatalf("failed to create test pipe: %v", err) - } - t.Cleanup(func() { - unix.Close(fds[0]) - unix.Close(fds[1]) - }) - return &SharedContext{ - cmdQueue: make(chan func(), queueSize), - stopChan: make(chan struct{}), - wakeR: fds[0], - wakeW: fds[1], - } -} - -func TestSharedContext_ConcurrentPostNonBlocking(t *testing.T) { - sc := newTestSharedContext(t, 256) - - var wg sync.WaitGroup - const goroutines = 100 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - sc.Post(func() { - _ = id + j - }) - } - }(i) - } - - wg.Wait() -} - -func TestSharedContext_PostQueueFull(t *testing.T) { - sc := newTestSharedContext(t, 2) - - sc.Post(func() {}) - sc.Post(func() {}) - sc.Post(func() {}) - sc.Post(func() {}) - - assert.Len(t, sc.cmdQueue, 2) -} - -func TestSharedContext_StartMultipleTimes(t *testing.T) { - sc := newTestSharedContext(t, 256) - sc.started = true - - var wg sync.WaitGroup - const goroutines = 10 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() - sc.Start() - }() - } - - wg.Wait() - - assert.True(t, sc.started) -} - -func TestSharedContext_DrainCmdQueue(t *testing.T) { - sc := newTestSharedContext(t, 256) - - counter := 0 - for i := 0; i < 10; i++ { - sc.cmdQueue <- func() { - counter++ - } - } - - sc.drainCmdQueue() - - assert.Equal(t, 10, counter) - assert.Len(t, sc.cmdQueue, 0) -} - -func TestSharedContext_DrainCmdQueueEmpty(t *testing.T) { - sc := newTestSharedContext(t, 256) - - sc.drainCmdQueue() - - assert.Len(t, sc.cmdQueue, 0) -} - -func TestSharedContext_ConcurrentDrainAndPost(t *testing.T) { - sc := newTestSharedContext(t, 256) - - var wg sync.WaitGroup - - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < 100; i++ { - sc.Post(func() {}) - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < 50; i++ { - sc.drainCmdQueue() - } - }() - - wg.Wait() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/handlers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/handlers.go deleted file mode 100644 index c885e13..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/handlers.go +++ /dev/null @@ -1,282 +0,0 @@ -package wlroutput - -import ( - "encoding/json" - "fmt" - "net" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type HeadConfig struct { - Name string `json:"name"` - Enabled bool `json:"enabled"` - ModeID *uint32 `json:"modeId,omitempty"` - CustomMode *struct { - Width int32 `json:"width"` - Height int32 `json:"height"` - Refresh int32 `json:"refresh"` - } `json:"customMode,omitempty"` - Position *struct{ X, Y int32 } `json:"position,omitempty"` - Transform *int32 `json:"transform,omitempty"` - Scale *float64 `json:"scale,omitempty"` - AdaptiveSync *uint32 `json:"adaptiveSync,omitempty"` -} - -type ConfigurationRequest struct { - Heads []HeadConfig `json:"heads"` - Test bool `json:"test"` -} - -func HandleRequest(conn net.Conn, req models.Request, manager *Manager) { - if manager == nil { - models.RespondError(conn, req.ID, "wlroutput manager not initialized") - return - } - - switch req.Method { - case "wlroutput.getState": - handleGetState(conn, req, manager) - case "wlroutput.applyConfiguration": - handleApplyConfiguration(conn, req, manager, false) - case "wlroutput.testConfiguration": - handleApplyConfiguration(conn, req, manager, true) - case "wlroutput.subscribe": - handleSubscribe(conn, req, manager) - default: - models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method)) - } -} - -func handleGetState(conn net.Conn, req models.Request, manager *Manager) { - models.Respond(conn, req.ID, manager.GetState()) -} - -func handleApplyConfiguration(conn net.Conn, req models.Request, manager *Manager, test bool) { - headsParam, ok := models.Get[any](req, "heads") - if !ok { - models.RespondError(conn, req.ID, "missing 'heads' parameter") - return - } - - headsJSON, err := json.Marshal(headsParam) - if err != nil { - models.RespondError(conn, req.ID, "invalid 'heads' parameter format") - return - } - - var heads []HeadConfig - if err := json.Unmarshal(headsJSON, &heads); err != nil { - models.RespondError(conn, req.ID, fmt.Sprintf("invalid heads configuration: %v", err)) - return - } - - if err := manager.ApplyConfiguration(heads, test); err != nil { - models.RespondError(conn, req.ID, err.Error()) - return - } - - msg := "configuration applied" - if test { - msg = "configuration test succeeded" - } - models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: msg}) -} - -func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) { - clientID := fmt.Sprintf("client-%p", conn) - stateChan := manager.Subscribe(clientID) - defer manager.Unsubscribe(clientID) - - initialState := manager.GetState() - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - ID: req.ID, - Result: &initialState, - }); err != nil { - return - } - - for state := range stateChan { - if err := json.NewEncoder(conn).Encode(models.Response[State]{ - Result: &state, - }); err != nil { - return - } - } -} - -func (m *Manager) ApplyConfiguration(heads []HeadConfig, test bool) error { - if m.manager == nil { - return fmt.Errorf("output manager not initialized") - } - - resultChan := make(chan error, 1) - - m.post(func() { - m.wlMutex.Lock() - defer m.wlMutex.Unlock() - - config, err := m.manager.CreateConfiguration(m.serial) - if err != nil { - resultChan <- fmt.Errorf("failed to create configuration: %w", err) - return - } - - responded := false - - config.SetSucceededHandler(func(e wlr_output_management.ZwlrOutputConfigurationV1SucceededEvent) { - if responded { - return - } - responded = true - log.Info("WlrOutput: configuration succeeded") - config.Destroy() - resultChan <- nil - }) - - config.SetFailedHandler(func(e wlr_output_management.ZwlrOutputConfigurationV1FailedEvent) { - if responded { - return - } - responded = true - log.Warn("WlrOutput: configuration failed") - config.Destroy() - resultChan <- fmt.Errorf("compositor rejected configuration") - }) - - config.SetCancelledHandler(func(e wlr_output_management.ZwlrOutputConfigurationV1CancelledEvent) { - if responded { - return - } - responded = true - log.Warn("WlrOutput: configuration cancelled") - config.Destroy() - resultChan <- fmt.Errorf("configuration cancelled (outdated serial)") - }) - - time.AfterFunc(time.Second, func() { - m.post(func() { - if responded { - return - } - responded = true - config.Destroy() - resultChan <- fmt.Errorf("timeout waiting for configuration response") - }) - }) - - headsByName := make(map[string]*headState) - m.heads.Range(func(key uint32, head *headState) bool { - if !head.finished { - headsByName[head.name] = head - } - return true - }) - - for _, headCfg := range heads { - head, exists := headsByName[headCfg.Name] - if !exists { - config.Destroy() - resultChan <- fmt.Errorf("head not found: %s", headCfg.Name) - return - } - - if !headCfg.Enabled { - if err := config.DisableHead(head.handle); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to disable head %s: %w", headCfg.Name, err) - return - } - continue - } - - headConfig, err := config.EnableHead(head.handle) - if err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to enable head %s: %w", headCfg.Name, err) - return - } - - if headCfg.ModeID != nil { - mode, exists := m.modes.Load(*headCfg.ModeID) - - if !exists { - config.Destroy() - resultChan <- fmt.Errorf("mode not found: %d", *headCfg.ModeID) - return - } - - if err := headConfig.SetMode(mode.handle); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set mode for %s: %w", headCfg.Name, err) - return - } - } else if headCfg.CustomMode != nil { - if err := headConfig.SetCustomMode( - headCfg.CustomMode.Width, - headCfg.CustomMode.Height, - headCfg.CustomMode.Refresh, - ); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set custom mode for %s: %w", headCfg.Name, err) - return - } - } - - if headCfg.Position != nil { - if err := headConfig.SetPosition(headCfg.Position.X, headCfg.Position.Y); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set position for %s: %w", headCfg.Name, err) - return - } - } - - if headCfg.Transform != nil { - if err := headConfig.SetTransform(*headCfg.Transform); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set transform for %s: %w", headCfg.Name, err) - return - } - } - - if headCfg.Scale != nil { - if err := headConfig.SetScale(*headCfg.Scale); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set scale for %s: %w", headCfg.Name, err) - return - } - } - - if headCfg.AdaptiveSync != nil { - if err := headConfig.SetAdaptiveSync(*headCfg.AdaptiveSync); err != nil { - config.Destroy() - resultChan <- fmt.Errorf("failed to set adaptive sync for %s: %w", headCfg.Name, err) - return - } - } - } - - var applyErr error - if test { - applyErr = config.Test() - } else { - applyErr = config.Apply() - } - - if applyErr != nil { - responded = true - config.Destroy() - action := "apply" - if test { - action = "test" - } - resultChan <- fmt.Errorf("failed to %s configuration: %w", action, applyErr) - return - } - }) - - return <-resultChan -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager.go deleted file mode 100644 index cbd89a3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager.go +++ /dev/null @@ -1,492 +0,0 @@ -package wlroutput - -import ( - "fmt" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -func NewManager(display wlclient.WaylandDisplay) (*Manager, error) { - m := &Manager{ - display: display, - ctx: display.Context(), - cmdq: make(chan cmd, 512), - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - fatalError: make(chan error, 1), - } - - m.wg.Add(1) - go m.waylandActor() - - if err := m.setupRegistry(); err != nil { - close(m.stopChan) - m.wg.Wait() - return nil, err - } - - m.updateState() - - m.notifierWg.Add(1) - go m.notifier() - - return m, nil -} - -func (m *Manager) post(fn func()) { - select { - case m.cmdq <- cmd{fn: fn}: - default: - log.Warn("WlrOutput actor command queue full, dropping command") - } -} - -func (m *Manager) waylandActor() { - defer m.wg.Done() - defer func() { - if r := recover(); r != nil { - err := fmt.Errorf("waylandActor panic: %v", r) - log.Errorf("WlrOutput: %v", err) - - select { - case m.fatalError <- err: - default: - } - - select { - case <-m.stopChan: - default: - close(m.stopChan) - } - } - }() - - for { - select { - case <-m.stopChan: - return - case c := <-m.cmdq: - func() { - defer func() { - if r := recover(); r != nil { - log.Errorf("WlrOutput: command execution panic: %v", r) - } - }() - c.fn() - }() - } - } -} - -func (m *Manager) setupRegistry() error { - log.Info("WlrOutput: starting registry setup") - - registry, err := m.display.GetRegistry() - if err != nil { - return fmt.Errorf("failed to get registry: %w", err) - } - m.registry = registry - - registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { - if e.Interface == wlr_output_management.ZwlrOutputManagerV1InterfaceName { - log.Infof("WlrOutput: found %s", wlr_output_management.ZwlrOutputManagerV1InterfaceName) - manager := wlr_output_management.NewZwlrOutputManagerV1(m.ctx) - version := e.Version - if version > 4 { - version = 4 - } - - manager.SetHeadHandler(func(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) { - m.handleHead(e) - }) - - manager.SetDoneHandler(func(e wlr_output_management.ZwlrOutputManagerV1DoneEvent) { - log.Debugf("WlrOutput: done event received (serial=%d)", e.Serial) - m.serial = e.Serial - m.post(func() { - m.updateState() - }) - }) - - manager.SetFinishedHandler(func(e wlr_output_management.ZwlrOutputManagerV1FinishedEvent) { - log.Info("WlrOutput: finished event received") - }) - - if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil { - m.manager = manager - log.Info("WlrOutput: manager bound successfully") - } else { - log.Errorf("WlrOutput: failed to bind manager: %v", err) - } - } - }) - - log.Info("WlrOutput: registry setup complete (events will be processed async)") - return nil -} - -func (m *Manager) handleHead(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) { - handle := e.Head - headID := handle.ID() - - log.Debugf("WlrOutput: New head (id=%d)", headID) - - head := &headState{ - id: headID, - handle: handle, - modeIDs: make([]uint32, 0), - } - - m.heads.Store(headID, head) - - handle.SetNameHandler(func(e wlr_output_management.ZwlrOutputHeadV1NameEvent) { - log.Debugf("WlrOutput: Head %d name: %s", headID, e.Name) - head.name = e.Name - head.ready = true - m.post(func() { - m.updateState() - }) - }) - - handle.SetDescriptionHandler(func(e wlr_output_management.ZwlrOutputHeadV1DescriptionEvent) { - log.Debugf("WlrOutput: Head %d description: %s", headID, e.Description) - head.description = e.Description - m.post(func() { - m.updateState() - }) - }) - - handle.SetPhysicalSizeHandler(func(e wlr_output_management.ZwlrOutputHeadV1PhysicalSizeEvent) { - log.Debugf("WlrOutput: Head %d physical size: %dx%d", headID, e.Width, e.Height) - head.physicalWidth = e.Width - head.physicalHeight = e.Height - m.post(func() { - m.updateState() - }) - }) - - handle.SetModeHandler(func(e wlr_output_management.ZwlrOutputHeadV1ModeEvent) { - m.handleMode(headID, e) - }) - - handle.SetEnabledHandler(func(e wlr_output_management.ZwlrOutputHeadV1EnabledEvent) { - log.Debugf("WlrOutput: Head %d enabled: %d", headID, e.Enabled) - head.enabled = e.Enabled != 0 - m.post(func() { - m.updateState() - }) - }) - - handle.SetCurrentModeHandler(func(e wlr_output_management.ZwlrOutputHeadV1CurrentModeEvent) { - modeID := e.Mode.ID() - log.Debugf("WlrOutput: Head %d current mode: %d", headID, modeID) - head.currentModeID = modeID - m.post(func() { - m.updateState() - }) - }) - - handle.SetPositionHandler(func(e wlr_output_management.ZwlrOutputHeadV1PositionEvent) { - log.Debugf("WlrOutput: Head %d position: %d,%d", headID, e.X, e.Y) - head.x = e.X - head.y = e.Y - m.post(func() { - m.updateState() - }) - }) - - handle.SetTransformHandler(func(e wlr_output_management.ZwlrOutputHeadV1TransformEvent) { - log.Debugf("WlrOutput: Head %d transform: %d", headID, e.Transform) - head.transform = e.Transform - m.post(func() { - m.updateState() - }) - }) - - handle.SetScaleHandler(func(e wlr_output_management.ZwlrOutputHeadV1ScaleEvent) { - log.Debugf("WlrOutput: Head %d scale: %f", headID, e.Scale) - head.scale = e.Scale - m.post(func() { - m.updateState() - }) - }) - - handle.SetMakeHandler(func(e wlr_output_management.ZwlrOutputHeadV1MakeEvent) { - log.Debugf("WlrOutput: Head %d make: %s", headID, e.Make) - head.make = e.Make - m.post(func() { - m.updateState() - }) - }) - - handle.SetModelHandler(func(e wlr_output_management.ZwlrOutputHeadV1ModelEvent) { - log.Debugf("WlrOutput: Head %d model: %s", headID, e.Model) - head.model = e.Model - m.post(func() { - m.updateState() - }) - }) - - handle.SetSerialNumberHandler(func(e wlr_output_management.ZwlrOutputHeadV1SerialNumberEvent) { - log.Debugf("WlrOutput: Head %d serial: %s", headID, e.SerialNumber) - head.serialNumber = e.SerialNumber - m.post(func() { - m.updateState() - }) - }) - - handle.SetAdaptiveSyncHandler(func(e wlr_output_management.ZwlrOutputHeadV1AdaptiveSyncEvent) { - log.Debugf("WlrOutput: Head %d adaptive sync: %d", headID, e.State) - head.adaptiveSync = e.State - head.adaptiveSyncSupported = true - m.post(func() { - m.updateState() - }) - }) - - handle.SetFinishedHandler(func(e wlr_output_management.ZwlrOutputHeadV1FinishedEvent) { - log.Debugf("WlrOutput: Head %d finished", headID) - head.finished = true - - m.heads.Delete(headID) - - m.wlMutex.Lock() - handle.Release() - m.wlMutex.Unlock() - - m.post(func() { - m.updateState() - }) - }) -} - -func (m *Manager) handleMode(headID uint32, e wlr_output_management.ZwlrOutputHeadV1ModeEvent) { - handle := e.Mode - modeID := handle.ID() - - log.Debugf("WlrOutput: Head %d new mode (id=%d)", headID, modeID) - - mode := &modeState{ - id: modeID, - handle: handle, - } - - m.modes.Store(modeID, mode) - - if head, ok := m.heads.Load(headID); ok { - head.modeIDs = append(head.modeIDs, modeID) - m.heads.Store(headID, head) - } - - handle.SetSizeHandler(func(e wlr_output_management.ZwlrOutputModeV1SizeEvent) { - log.Debugf("WlrOutput: Mode %d size: %dx%d", modeID, e.Width, e.Height) - mode.width = e.Width - mode.height = e.Height - m.post(func() { - m.updateState() - }) - }) - - handle.SetRefreshHandler(func(e wlr_output_management.ZwlrOutputModeV1RefreshEvent) { - log.Debugf("WlrOutput: Mode %d refresh: %d", modeID, e.Refresh) - mode.refresh = e.Refresh - m.post(func() { - m.updateState() - }) - }) - - handle.SetPreferredHandler(func(e wlr_output_management.ZwlrOutputModeV1PreferredEvent) { - log.Debugf("WlrOutput: Mode %d preferred", modeID) - mode.preferred = true - m.post(func() { - m.updateState() - }) - }) - - handle.SetFinishedHandler(func(e wlr_output_management.ZwlrOutputModeV1FinishedEvent) { - log.Debugf("WlrOutput: Mode %d finished", modeID) - mode.finished = true - - m.modes.Delete(modeID) - - m.wlMutex.Lock() - handle.Release() - m.wlMutex.Unlock() - - m.post(func() { - m.updateState() - }) - }) -} - -func (m *Manager) updateState() { - outputs := make([]Output, 0) - - m.heads.Range(func(key uint32, head *headState) bool { - if head.finished { - return true - } - - if !head.ready { - return true - } - - modes := make([]OutputMode, 0) - var currentMode *OutputMode - - for _, modeID := range head.modeIDs { - mode, exists := m.modes.Load(modeID) - if !exists { - continue - } - if mode.finished { - continue - } - - outMode := OutputMode{ - Width: mode.width, - Height: mode.height, - Refresh: mode.refresh, - Preferred: mode.preferred, - ID: modeID, - } - modes = append(modes, outMode) - - if modeID == head.currentModeID { - currentMode = &outMode - } - } - - output := Output{ - Name: head.name, - Description: head.description, - Make: head.make, - Model: head.model, - SerialNumber: head.serialNumber, - PhysicalWidth: head.physicalWidth, - PhysicalHeight: head.physicalHeight, - Enabled: head.enabled, - X: head.x, - Y: head.y, - Transform: head.transform, - Scale: head.scale, - CurrentMode: currentMode, - Modes: modes, - AdaptiveSync: head.adaptiveSync, - AdaptiveSyncSupported: head.adaptiveSyncSupported, - ID: head.id, - } - outputs = append(outputs, output) - return true - }) - - newState := State{ - Outputs: outputs, - Serial: m.serial, - } - - m.stateMutex.Lock() - m.state = &newState - m.stateMutex.Unlock() - - m.notifySubscribers() -} - -func (m *Manager) notifier() { - defer m.notifierWg.Done() - defer func() { - if r := recover(); r != nil { - err := fmt.Errorf("notifier panic: %v", r) - log.Errorf("WlrOutput: %v", err) - - select { - case m.fatalError <- err: - default: - } - - select { - case <-m.stopChan: - default: - close(m.stopChan) - } - } - }() - - const minGap = 100 * time.Millisecond - timer := time.NewTimer(minGap) - timer.Stop() - var pending bool - - for { - select { - case <-m.stopChan: - timer.Stop() - return - case <-m.dirty: - if pending { - continue - } - pending = true - timer.Reset(minGap) - case <-timer.C: - if !pending { - continue - } - - currentState := m.GetState() - - if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) { - pending = false - continue - } - - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- currentState: - default: - log.Warn("WlrOutput: subscriber channel full, dropping update") - } - return true - }) - - stateCopy := currentState - m.lastNotified = &stateCopy - pending = false - } - } -} - -func (m *Manager) Close() { - close(m.stopChan) - m.wg.Wait() - m.notifierWg.Wait() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - - m.modes.Range(func(key uint32, mode *modeState) bool { - if mode.handle != nil { - mode.handle.Release() - } - m.modes.Delete(key) - return true - }) - - m.heads.Range(func(key uint32, head *headState) bool { - if head.handle != nil { - head.handle.Release() - } - m.heads.Delete(key) - return true - }) - - if m.manager != nil { - m.manager.Stop() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager_test.go deleted file mode 100644 index e90c70c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/manager_test.go +++ /dev/null @@ -1,414 +0,0 @@ -package wlroutput - -import ( - "errors" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient" -) - -func TestStateChanged_BothNil(t *testing.T) { - assert.True(t, stateChanged(nil, nil)) -} - -func TestStateChanged_OneNil(t *testing.T) { - s := &State{Serial: 1} - assert.True(t, stateChanged(s, nil)) - assert.True(t, stateChanged(nil, s)) -} - -func TestStateChanged_SerialDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{}} - b := &State{Serial: 2, Outputs: []Output{}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputCountDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1"}}} - b := &State{Serial: 1, Outputs: []Output{}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputNameDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Enabled: true}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "HDMI-A-1", Enabled: true}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputEnabledDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Enabled: true}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Enabled: false}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputPositionDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", X: 0, Y: 0}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", X: 1920, Y: 0}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputTransformDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Transform: 0}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Transform: 1}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputScaleDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Scale: 1.0}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Scale: 2.0}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_OutputAdaptiveSyncDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", AdaptiveSync: 0}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", AdaptiveSync: 1}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_CurrentModeNilVsNonNil(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", CurrentMode: nil}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", CurrentMode: &OutputMode{Width: 1920}}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_CurrentModeDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{ - Name: "eDP-1", - CurrentMode: &OutputMode{Width: 1920, Height: 1080, Refresh: 60000}, - }}} - b := &State{Serial: 1, Outputs: []Output{{ - Name: "eDP-1", - CurrentMode: &OutputMode{Width: 2560, Height: 1440, Refresh: 60000}, - }}} - assert.True(t, stateChanged(a, b)) - - b.Outputs[0].CurrentMode.Width = 1920 - b.Outputs[0].CurrentMode.Height = 1080 - b.Outputs[0].CurrentMode.Refresh = 144000 - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_ModesLengthDiffers(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Modes: []OutputMode{{Width: 1920}}}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", Modes: []OutputMode{{Width: 1920}, {Width: 1280}}}}} - assert.True(t, stateChanged(a, b)) -} - -func TestStateChanged_Equal(t *testing.T) { - mode := OutputMode{Width: 1920, Height: 1080, Refresh: 60000, Preferred: true} - a := &State{ - Serial: 5, - Outputs: []Output{{ - Name: "eDP-1", - Description: "Built-in display", - Make: "BOE", - Model: "0x0ABC", - SerialNumber: "12345", - PhysicalWidth: 309, - PhysicalHeight: 174, - Enabled: true, - X: 0, - Y: 0, - Transform: 0, - Scale: 1.0, - CurrentMode: &mode, - Modes: []OutputMode{mode}, - AdaptiveSync: 0, - }}, - } - b := &State{ - Serial: 5, - Outputs: []Output{{ - Name: "eDP-1", - Description: "Built-in display", - Make: "BOE", - Model: "0x0ABC", - SerialNumber: "12345", - PhysicalWidth: 309, - PhysicalHeight: 174, - Enabled: true, - X: 0, - Y: 0, - Transform: 0, - Scale: 1.0, - CurrentMode: &mode, - Modes: []OutputMode{mode}, - AdaptiveSync: 0, - }}, - } - assert.False(t, stateChanged(a, b)) -} - -func TestManager_ConcurrentGetState(t *testing.T) { - m := &Manager{ - state: &State{ - Serial: 1, - Outputs: []Output{{Name: "eDP-1", Enabled: true}}, - }, - } - - var wg sync.WaitGroup - const goroutines = 50 - const iterations = 100 - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { - s := m.GetState() - _ = s.Serial - _ = s.Outputs - } - }() - } - - for i := 0; i < goroutines/2; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - m.stateMutex.Lock() - m.state = &State{ - Serial: uint32(j), - Outputs: []Output{{Name: "eDP-1", Scale: float64(j % 3)}}, - } - m.stateMutex.Unlock() - } - }(i) - } - - wg.Wait() -} - -func TestManager_ConcurrentSubscriberAccess(t *testing.T) { - m := &Manager{ - stopChan: make(chan struct{}), - dirty: make(chan struct{}, 1), - } - - var wg sync.WaitGroup - const goroutines = 20 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - subID := string(rune('a' + id)) - ch := m.Subscribe(subID) - assert.NotNil(t, ch) - time.Sleep(time.Millisecond) - m.Unsubscribe(subID) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapHeadsConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &headState{ - id: key, - name: "test-head", - enabled: j%2 == 0, - scale: float64(j % 3), - modeIDs: []uint32{uint32(j)}, - } - m.heads.Store(key, state) - - if loaded, ok := m.heads.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.heads.Range(func(k uint32, v *headState) bool { - _ = v.name - _ = v.enabled - return true - }) - } - - m.heads.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_SyncmapModesConcurrentAccess(t *testing.T) { - m := &Manager{} - - var wg sync.WaitGroup - const goroutines = 30 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - key := uint32(id) - - for j := 0; j < iterations; j++ { - state := &modeState{ - id: key, - width: int32(1920 + j), - height: int32(1080 + j), - refresh: 60000, - preferred: j == 0, - } - m.modes.Store(key, state) - - if loaded, ok := m.modes.Load(key); ok { - assert.Equal(t, key, loaded.id) - } - - m.modes.Range(func(k uint32, v *modeState) bool { - _ = v.width - _ = v.height - return true - }) - } - - m.modes.Delete(key) - }(i) - } - - wg.Wait() -} - -func TestManager_NotifySubscribersNonBlocking(t *testing.T) { - m := &Manager{ - dirty: make(chan struct{}, 1), - } - - for i := 0; i < 10; i++ { - m.notifySubscribers() - } - - assert.Len(t, m.dirty, 1) -} - -func TestManager_PostQueueFull(t *testing.T) { - m := &Manager{ - cmdq: make(chan cmd, 2), - stopChan: make(chan struct{}), - } - - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - m.post(func() {}) - - assert.Len(t, m.cmdq, 2) -} - -func TestManager_GetStateNilState(t *testing.T) { - m := &Manager{} - - s := m.GetState() - assert.NotNil(t, s.Outputs) - assert.Equal(t, uint32(0), s.Serial) -} - -func TestManager_FatalErrorChannel(t *testing.T) { - m := &Manager{ - fatalError: make(chan error, 1), - } - - ch := m.FatalError() - assert.NotNil(t, ch) - - m.fatalError <- assert.AnError - err := <-ch - assert.Error(t, err) -} - -func TestOutputMode_Fields(t *testing.T) { - mode := OutputMode{ - Width: 1920, - Height: 1080, - Refresh: 60000, - Preferred: true, - ID: 42, - } - - assert.Equal(t, int32(1920), mode.Width) - assert.Equal(t, int32(1080), mode.Height) - assert.Equal(t, int32(60000), mode.Refresh) - assert.True(t, mode.Preferred) - assert.Equal(t, uint32(42), mode.ID) -} - -func TestOutput_Fields(t *testing.T) { - out := Output{ - Name: "eDP-1", - Description: "Built-in display", - Make: "BOE", - Model: "0x0ABC", - SerialNumber: "12345", - PhysicalWidth: 309, - PhysicalHeight: 174, - Enabled: true, - X: 0, - Y: 0, - Transform: 0, - Scale: 1.5, - AdaptiveSync: 1, - ID: 1, - } - - assert.Equal(t, "eDP-1", out.Name) - assert.Equal(t, "Built-in display", out.Description) - assert.True(t, out.Enabled) - assert.Equal(t, float64(1.5), out.Scale) - assert.Equal(t, uint32(1), out.AdaptiveSync) -} - -func TestHeadState_ModeIDsSlice(t *testing.T) { - head := &headState{ - id: 1, - modeIDs: make([]uint32, 0), - } - - head.modeIDs = append(head.modeIDs, 1, 2, 3) - assert.Len(t, head.modeIDs, 3) - assert.Equal(t, uint32(1), head.modeIDs[0]) -} - -func TestStateChanged_BothCurrentModeNil(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", CurrentMode: nil}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1", CurrentMode: nil}}} - assert.False(t, stateChanged(a, b)) -} - -func TestStateChanged_IndexOutOfBounds(t *testing.T) { - a := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1"}}} - b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1"}, {Name: "HDMI-A-1"}}} - assert.True(t, stateChanged(a, b)) -} - -func TestNewManager_GetRegistryError(t *testing.T) { - mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t) - - mockDisplay.EXPECT().Context().Return(nil) - mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry")) - - _, err := NewManager(mockDisplay) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get registry") -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/types.go deleted file mode 100644 index 9c79b1a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/server/wlroutput/types.go +++ /dev/null @@ -1,192 +0,0 @@ -package wlroutput - -import ( - "sync" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type OutputMode struct { - Width int32 `json:"width"` - Height int32 `json:"height"` - Refresh int32 `json:"refresh"` - Preferred bool `json:"preferred"` - ID uint32 `json:"id"` -} - -type Output struct { - Name string `json:"name"` - Description string `json:"description"` - Make string `json:"make"` - Model string `json:"model"` - SerialNumber string `json:"serialNumber"` - PhysicalWidth int32 `json:"physicalWidth"` - PhysicalHeight int32 `json:"physicalHeight"` - Enabled bool `json:"enabled"` - X int32 `json:"x"` - Y int32 `json:"y"` - Transform int32 `json:"transform"` - Scale float64 `json:"scale"` - CurrentMode *OutputMode `json:"currentMode"` - Modes []OutputMode `json:"modes"` - AdaptiveSync uint32 `json:"adaptiveSync"` - AdaptiveSyncSupported bool `json:"adaptiveSyncSupported"` - ID uint32 `json:"id"` -} - -type State struct { - Outputs []Output `json:"outputs"` - Serial uint32 `json:"serial"` -} - -type cmd struct { - fn func() -} - -type Manager struct { - display wlclient.WaylandDisplay - ctx *wlclient.Context - registry *wlclient.Registry - manager *wlr_output_management.ZwlrOutputManagerV1 - - heads syncmap.Map[uint32, *headState] - modes syncmap.Map[uint32, *modeState] - - serial uint32 - - wlMutex sync.Mutex - cmdq chan cmd - stopChan chan struct{} - wg sync.WaitGroup - - subscribers syncmap.Map[string, chan State] - dirty chan struct{} - notifierWg sync.WaitGroup - lastNotified *State - - stateMutex sync.RWMutex - state *State - - fatalError chan error -} - -type headState struct { - id uint32 - handle *wlr_output_management.ZwlrOutputHeadV1 - name string - description string - make string - model string - serialNumber string - physicalWidth int32 - physicalHeight int32 - enabled bool - x int32 - y int32 - transform int32 - scale float64 - currentModeID uint32 - modeIDs []uint32 - adaptiveSync uint32 - adaptiveSyncSupported bool - finished bool - ready bool -} - -type modeState struct { - id uint32 - handle *wlr_output_management.ZwlrOutputModeV1 - width int32 - height int32 - refresh int32 - preferred bool - finished bool -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - if m.state == nil { - return State{ - Outputs: []Output{}, - Serial: 0, - } - } - stateCopy := *m.state - return stateCopy -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 64) - - m.subscribers.Store(id, ch) - - return ch -} - -func (m *Manager) Unsubscribe(id string) { - - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - - } - -} - -func (m *Manager) notifySubscribers() { - select { - case m.dirty <- struct{}{}: - default: - } -} - -func (m *Manager) FatalError() <-chan error { - return m.fatalError -} - -func stateChanged(old, new *State) bool { - if old == nil || new == nil { - return true - } - if old.Serial != new.Serial { - return true - } - if len(old.Outputs) != len(new.Outputs) { - return true - } - for i := range new.Outputs { - if i >= len(old.Outputs) { - return true - } - oldOut := &old.Outputs[i] - newOut := &new.Outputs[i] - if oldOut.Name != newOut.Name || oldOut.Enabled != newOut.Enabled { - return true - } - if oldOut.X != newOut.X || oldOut.Y != newOut.Y { - return true - } - if oldOut.Transform != newOut.Transform || oldOut.Scale != newOut.Scale { - return true - } - if oldOut.AdaptiveSync != newOut.AdaptiveSync || oldOut.AdaptiveSyncSupported != newOut.AdaptiveSyncSupported { - return true - } - if (oldOut.CurrentMode == nil) != (newOut.CurrentMode == nil) { - return true - } - if oldOut.CurrentMode != nil && newOut.CurrentMode != nil { - if oldOut.CurrentMode.Width != newOut.CurrentMode.Width || - oldOut.CurrentMode.Height != newOut.CurrentMode.Height || - oldOut.CurrentMode.Refresh != newOut.CurrentMode.Refresh { - return true - } - } - if len(oldOut.Modes) != len(newOut.Modes) { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/manager.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/manager.go deleted file mode 100644 index 2ebe7ae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/manager.go +++ /dev/null @@ -1,258 +0,0 @@ -package themes - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/afero" -) - -type Manager struct { - fs afero.Fs - themesDir string -} - -func NewManager() (*Manager, error) { - return NewManagerWithFs(afero.NewOsFs()) -} - -func NewManagerWithFs(fs afero.Fs) (*Manager, error) { - themesDir := getThemesDir() - return &Manager{ - fs: fs, - themesDir: themesDir, - }, nil -} - -func getThemesDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - log.Error("failed to get user config dir", "err", err) - return "" - } - return filepath.Join(configDir, "DankMaterialShell", "themes") -} - -func (m *Manager) IsInstalled(theme Theme) (bool, error) { - path := m.getInstalledPath(theme.ID) - exists, err := afero.Exists(m.fs, path) - if err != nil { - return false, err - } - return exists, nil -} - -func (m *Manager) getInstalledDir(themeID string) string { - return filepath.Join(m.themesDir, themeID) -} - -func (m *Manager) getInstalledPath(themeID string) string { - return filepath.Join(m.getInstalledDir(themeID), "theme.json") -} - -func (m *Manager) Install(theme Theme, registryThemeDir string) error { - themeDir := m.getInstalledDir(theme.ID) - - exists, err := afero.DirExists(m.fs, themeDir) - if err != nil { - return fmt.Errorf("failed to check if theme exists: %w", err) - } - - if exists { - return fmt.Errorf("theme already installed: %s", theme.Name) - } - - if err := m.fs.MkdirAll(themeDir, 0o755); err != nil { - return fmt.Errorf("failed to create theme directory: %w", err) - } - - data, err := json.MarshalIndent(theme, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal theme: %w", err) - } - - themePath := filepath.Join(themeDir, "theme.json") - if err := afero.WriteFile(m.fs, themePath, data, 0o644); err != nil { - return fmt.Errorf("failed to write theme file: %w", err) - } - - m.copyPreviewFiles(registryThemeDir, themeDir, theme) - return nil -} - -func (m *Manager) copyPreviewFiles(srcDir, dstDir string, theme Theme) { - previews := []string{"preview-dark.svg", "preview-light.svg"} - - if theme.Variants != nil { - for _, v := range theme.Variants.Options { - previews = append(previews, - fmt.Sprintf("preview-%s.svg", v.ID), - fmt.Sprintf("preview-%s-dark.svg", v.ID), - fmt.Sprintf("preview-%s-light.svg", v.ID), - ) - } - } - - for _, preview := range previews { - srcPath := filepath.Join(srcDir, preview) - if exists, _ := afero.Exists(m.fs, srcPath); !exists { - continue - } - data, err := afero.ReadFile(m.fs, srcPath) - if err != nil { - continue - } - dstPath := filepath.Join(dstDir, preview) - _ = afero.WriteFile(m.fs, dstPath, data, 0o644) - } -} - -func (m *Manager) InstallFromRegistry(registry *Registry, themeID string) error { - theme, err := registry.Get(themeID) - if err != nil { - return err - } - - registryThemeDir := registry.GetThemeDir(theme.SourceDir) - return m.Install(*theme, registryThemeDir) -} - -func (m *Manager) Update(theme Theme) error { - themePath := m.getInstalledPath(theme.ID) - - exists, err := afero.Exists(m.fs, themePath) - if err != nil { - return fmt.Errorf("failed to check if theme exists: %w", err) - } - - if !exists { - return fmt.Errorf("theme not installed: %s", theme.Name) - } - - data, err := json.MarshalIndent(theme, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal theme: %w", err) - } - - if err := afero.WriteFile(m.fs, themePath, data, 0o644); err != nil { - return fmt.Errorf("failed to write theme file: %w", err) - } - - return nil -} - -func (m *Manager) Uninstall(theme Theme) error { - return m.UninstallByID(theme.ID) -} - -func (m *Manager) UninstallByID(themeID string) error { - themeDir := m.getInstalledDir(themeID) - - exists, err := afero.DirExists(m.fs, themeDir) - if err != nil { - return fmt.Errorf("failed to check if theme exists: %w", err) - } - - if !exists { - return fmt.Errorf("theme not installed: %s", themeID) - } - - if err := m.fs.RemoveAll(themeDir); err != nil { - return fmt.Errorf("failed to remove theme: %w", err) - } - - return nil -} - -func (m *Manager) ListInstalled() ([]string, error) { - exists, err := afero.DirExists(m.fs, m.themesDir) - if err != nil { - return nil, err - } - - if !exists { - return []string{}, nil - } - - entries, err := afero.ReadDir(m.fs, m.themesDir) - if err != nil { - return nil, fmt.Errorf("failed to read themes directory: %w", err) - } - - var installed []string - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - themeID := entry.Name() - themePath := filepath.Join(m.themesDir, themeID, "theme.json") - if exists, _ := afero.Exists(m.fs, themePath); exists { - installed = append(installed, themeID) - } - } - - return installed, nil -} - -func (m *Manager) GetInstalledTheme(themeID string) (*Theme, error) { - themePath := m.getInstalledPath(themeID) - - data, err := afero.ReadFile(m.fs, themePath) - if err != nil { - return nil, fmt.Errorf("failed to read theme file: %w", err) - } - - var theme Theme - if err := json.Unmarshal(data, &theme); err != nil { - return nil, fmt.Errorf("failed to parse theme file: %w", err) - } - - return &theme, nil -} - -func (m *Manager) HasUpdates(themeID string, registryTheme Theme) (bool, error) { - installed, err := m.GetInstalledTheme(themeID) - if err != nil { - return false, err - } - - return compareVersions(installed.Version, registryTheme.Version) < 0, nil -} - -func compareVersions(installed, registry string) int { - installedParts := strings.Split(installed, ".") - registryParts := strings.Split(registry, ".") - - maxLen := len(installedParts) - if len(registryParts) > maxLen { - maxLen = len(registryParts) - } - - for i := 0; i < maxLen; i++ { - var installedNum, registryNum int - if i < len(installedParts) { - fmt.Sscanf(installedParts[i], "%d", &installedNum) - } - if i < len(registryParts) { - fmt.Sscanf(registryParts[i], "%d", ®istryNum) - } - - if installedNum < registryNum { - return -1 - } - if installedNum > registryNum { - return 1 - } - } - - return 0 -} - -func (m *Manager) GetThemesDir() string { - return m.themesDir -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/registry.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/registry.go deleted file mode 100644 index 5a39913..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/registry.go +++ /dev/null @@ -1,309 +0,0 @@ -package themes - -import ( - "encoding/json" - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/go-git/go-git/v6" - "github.com/spf13/afero" -) - -const registryRepo = "https://github.com/AvengeMedia/dms-plugin-registry.git" - -type ColorScheme struct { - Primary string `json:"primary,omitempty"` - PrimaryText string `json:"primaryText,omitempty"` - PrimaryContainer string `json:"primaryContainer,omitempty"` - Secondary string `json:"secondary,omitempty"` - Surface string `json:"surface,omitempty"` - SurfaceText string `json:"surfaceText,omitempty"` - SurfaceVariant string `json:"surfaceVariant,omitempty"` - SurfaceVariantText string `json:"surfaceVariantText,omitempty"` - SurfaceTint string `json:"surfaceTint,omitempty"` - Background string `json:"background,omitempty"` - BackgroundText string `json:"backgroundText,omitempty"` - Outline string `json:"outline,omitempty"` - SurfaceContainer string `json:"surfaceContainer,omitempty"` - SurfaceContainerHigh string `json:"surfaceContainerHigh,omitempty"` - SurfaceContainerHighest string `json:"surfaceContainerHighest,omitempty"` - Error string `json:"error,omitempty"` - Warning string `json:"warning,omitempty"` - Info string `json:"info,omitempty"` -} - -type ThemeVariant struct { - ID string `json:"id"` - Name string `json:"name"` - Dark ColorScheme `json:"dark,omitempty"` - Light ColorScheme `json:"light,omitempty"` -} - -type ThemeFlavor struct { - ID string `json:"id"` - Name string `json:"name"` - Dark ColorScheme `json:"dark,omitempty"` - Light ColorScheme `json:"light,omitempty"` -} - -type ThemeAccent struct { - ID string `json:"id"` - Name string `json:"name"` - FlavorColors map[string]ColorScheme `json:"-"` -} - -func (a *ThemeAccent) UnmarshalJSON(data []byte) error { - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - a.FlavorColors = make(map[string]ColorScheme) - var mErr error - for key, value := range raw { - switch key { - case "id": - mErr = errors.Join(mErr, json.Unmarshal(value, &a.ID)) - case "name": - mErr = errors.Join(mErr, json.Unmarshal(value, &a.Name)) - default: - var colors ColorScheme - if err := json.Unmarshal(value, &colors); err == nil { - a.FlavorColors[key] = colors - } else { - mErr = errors.Join(mErr, fmt.Errorf("failed to unmarshal flavor colors for key %s: %w", key, err)) - } - } - } - return mErr -} - -func (a ThemeAccent) MarshalJSON() ([]byte, error) { - m := map[string]any{ - "id": a.ID, - "name": a.Name, - } - for k, v := range a.FlavorColors { - m[k] = v - } - return json.Marshal(m) -} - -type MultiVariantDefaults struct { - Dark map[string]string `json:"dark,omitempty"` - Light map[string]string `json:"light,omitempty"` -} - -type ThemeVariants struct { - Type string `json:"type,omitempty"` - Default string `json:"default,omitempty"` - Defaults *MultiVariantDefaults `json:"defaults,omitempty"` - Options []ThemeVariant `json:"options,omitempty"` - Flavors []ThemeFlavor `json:"flavors,omitempty"` - Accents []ThemeAccent `json:"accents,omitempty"` -} - -type Theme struct { - ID string `json:"id"` - Name string `json:"name"` - Version string `json:"version"` - Author string `json:"author"` - Description string `json:"description"` - Dark ColorScheme `json:"dark"` - Light ColorScheme `json:"light"` - Variants *ThemeVariants `json:"variants,omitempty"` - PreviewPath string `json:"-"` - SourceDir string `json:"sourceDir,omitempty"` -} - -type GitClient interface { - PlainClone(path string, url string) error - Pull(path string) error -} - -type realGitClient struct{} - -func (g *realGitClient) PlainClone(path string, url string) error { - _, err := git.PlainClone(path, &git.CloneOptions{ - URL: url, - Progress: os.Stdout, - }) - return err -} - -func (g *realGitClient) Pull(path string) error { - repo, err := git.PlainOpen(path) - if err != nil { - return err - } - - worktree, err := repo.Worktree() - if err != nil { - return err - } - - err = worktree.Pull(&git.PullOptions{}) - if err != nil && err.Error() != "already up-to-date" { - return err - } - - return nil -} - -type Registry struct { - fs afero.Fs - cacheDir string - themes []Theme - git GitClient -} - -func NewRegistry() (*Registry, error) { - return NewRegistryWithFs(afero.NewOsFs()) -} - -func NewRegistryWithFs(fs afero.Fs) (*Registry, error) { - cacheDir := getCacheDir() - return &Registry{ - fs: fs, - cacheDir: cacheDir, - git: &realGitClient{}, - }, nil -} - -func getCacheDir() string { - return filepath.Join(os.TempDir(), "dankdots-plugin-registry") -} - -func (r *Registry) Update() error { - exists, err := afero.DirExists(r.fs, r.cacheDir) - if err != nil { - return fmt.Errorf("failed to check cache directory: %w", err) - } - - if !exists { - if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil { - return fmt.Errorf("failed to clone registry: %w", err) - } - } else { - if err := r.git.Pull(r.cacheDir); err != nil { - if err := r.fs.RemoveAll(r.cacheDir); err != nil { - return fmt.Errorf("failed to remove corrupted registry: %w", err) - } - - if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0o755); err != nil { - return fmt.Errorf("failed to create cache directory: %w", err) - } - - if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil { - return fmt.Errorf("failed to re-clone registry: %w", err) - } - } - } - - return r.loadThemes() -} - -func (r *Registry) loadThemes() error { - themesDir := filepath.Join(r.cacheDir, "themes") - - entries, err := afero.ReadDir(r.fs, themesDir) - if err != nil { - return fmt.Errorf("failed to read themes directory: %w", err) - } - - r.themes = []Theme{} - - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - themeDir := filepath.Join(themesDir, entry.Name()) - themeFile := filepath.Join(themeDir, "theme.json") - - data, err := afero.ReadFile(r.fs, themeFile) - if err != nil { - continue - } - - var theme Theme - if err := json.Unmarshal(data, &theme); err != nil { - continue - } - - if theme.ID == "" { - theme.ID = entry.Name() - } - theme.SourceDir = entry.Name() - - previewPath := filepath.Join(themeDir, "preview.svg") - if exists, _ := afero.Exists(r.fs, previewPath); exists { - theme.PreviewPath = previewPath - } - - r.themes = append(r.themes, theme) - } - - return nil -} - -func (r *Registry) List() ([]Theme, error) { - if len(r.themes) == 0 { - if err := r.Update(); err != nil { - return nil, err - } - } - - return SortByFirstParty(r.themes), nil -} - -func (r *Registry) Search(query string) ([]Theme, error) { - allThemes, err := r.List() - if err != nil { - return nil, err - } - - if query == "" { - return allThemes, nil - } - - return SortByFirstParty(FuzzySearch(query, allThemes)), nil -} - -func (r *Registry) Get(idOrName string) (*Theme, error) { - themes, err := r.List() - if err != nil { - return nil, err - } - - for _, t := range themes { - if t.ID == idOrName { - return &t, nil - } - } - - for _, t := range themes { - if t.Name == idOrName { - return &t, nil - } - } - - return nil, fmt.Errorf("theme not found: %s", idOrName) -} - -func (r *Registry) GetThemeSourcePath(themeID string) string { - return filepath.Join(r.cacheDir, "themes", themeID, "theme.json") -} - -func (r *Registry) GetThemeDir(themeID string) string { - return filepath.Join(r.cacheDir, "themes", themeID) -} - -func SortByFirstParty(themes []Theme) []Theme { - return themes -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/search.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/search.go deleted file mode 100644 index 347f791..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/themes/search.go +++ /dev/null @@ -1,40 +0,0 @@ -package themes - -import ( - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func FuzzySearch(query string, themes []Theme) []Theme { - if query == "" { - return themes - } - - queryLower := strings.ToLower(query) - return utils.Filter(themes, func(t Theme) bool { - return fuzzyMatch(queryLower, strings.ToLower(t.Name)) || - fuzzyMatch(queryLower, strings.ToLower(t.Description)) || - fuzzyMatch(queryLower, strings.ToLower(t.Author)) - }) -} - -func fuzzyMatch(query, text string) bool { - queryIdx := 0 - for _, char := range text { - if queryIdx < len(query) && char == rune(query[queryIdx]) { - queryIdx++ - } - } - return queryIdx == len(query) -} - -func FindByIDOrName(idOrName string, themes []Theme) *Theme { - if t, found := utils.Find(themes, func(t Theme) bool { return t.ID == idOrName }); found { - return &t - } - if t, found := utils.Find(themes, func(t Theme) bool { return t.Name == idOrName }); found { - return &t - } - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/app.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/app.go deleted file mode 100644 index d07430a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/app.go +++ /dev/null @@ -1,240 +0,0 @@ -package tui - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" -) - -type Model struct { - version string - state ApplicationState - - osInfo *distros.OSInfo - dependencies []deps.Dependency - err error - - spinner spinner.Model - passwordInput textinput.Model - width int - height int - isLoading bool - styles Styles - - logMessages []string - logChan chan string - logFilePath string - packageProgressChan chan packageInstallProgressMsg - packageProgress packageInstallProgressMsg - installationLogs []string - showDebugLogs bool - - selectedWM int - selectedTerminal int - selectedDep int - selectedConfig int - reinstallItems map[string]bool - disabledItems map[string]bool - replaceConfigs map[string]bool - skipGentooUseFlags bool - sudoPassword string - existingConfigs []ExistingConfigInfo - fingerprintFailed bool -} - -func NewModel(version string, logFilePath string) Model { - s := spinner.New() - s.Spinner = spinner.Dot - - theme := TerminalTheme() - styles := NewStyles(theme) - s.Style = styles.SpinnerStyle - - pi := textinput.New() - pi.Placeholder = "Enter sudo password" - pi.EchoMode = textinput.EchoPassword - pi.EchoCharacter = '•' - pi.Focus() - - logChan := make(chan string, 1000) - packageProgressChan := make(chan packageInstallProgressMsg, 100) - - return Model{ - version: version, - state: StateWelcome, - spinner: s, - passwordInput: pi, - isLoading: true, - styles: styles, - - logMessages: []string{}, - logChan: logChan, - logFilePath: logFilePath, - packageProgressChan: packageProgressChan, - packageProgress: packageInstallProgressMsg{ - progress: 0.0, - step: "Initializing package installation", - isComplete: false, - }, - showDebugLogs: false, - selectedWM: 0, - selectedTerminal: 0, // Default to Ghostty - selectedDep: 0, - selectedConfig: 0, - reinstallItems: make(map[string]bool), - disabledItems: make(map[string]bool), - replaceConfigs: make(map[string]bool), - installationLogs: []string{}, - } -} - -func (m Model) GetLogChan() <-chan string { - return m.logChan -} - -func (m Model) Init() tea.Cmd { - return tea.Batch( - m.spinner.Tick, - m.listenForLogs(), - m.detectOS(), - ) -} - -func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "ctrl+c": - return m, tea.Quit - case "ctrl+d": - // Toggle debug logs view (except during password input states) - if m.state != StatePasswordPrompt && m.state != StateFingerprintAuth { - m.showDebugLogs = !m.showDebugLogs - return m, nil - } - } - } - - if tickMsg, ok := msg.(spinner.TickMsg); ok { - var cmd tea.Cmd - m.spinner, cmd = m.spinner.Update(tickMsg) - return m, tea.Batch(cmd, m.listenForLogs()) - } - - if sizeMsg, ok := msg.(tea.WindowSizeMsg); ok { - m.width = sizeMsg.Width - m.height = sizeMsg.Height - } - - if logMsg, ok := msg.(logMsg); ok { - m.logMessages = append(m.logMessages, logMsg.message) - return m, m.listenForLogs() - } - - switch m.state { - case StateWelcome: - return m.updateWelcomeState(msg) - case StateSelectWindowManager: - return m.updateSelectWindowManagerState(msg) - case StateSelectTerminal: - return m.updateSelectTerminalState(msg) - case StateDetectingDeps: - return m.updateDetectingDepsState(msg) - case StateDependencyReview: - return m.updateDependencyReviewState(msg) - case StateGentooUseFlags: - return m.updateGentooUseFlagsState(msg) - case StateGentooGCCCheck: - return m.updateGentooGCCCheckState(msg) - case StateAuthMethodChoice: - return m.updateAuthMethodChoiceState(msg) - case StateFingerprintAuth: - return m.updateFingerprintAuthState(msg) - case StatePasswordPrompt: - return m.updatePasswordPromptState(msg) - case StateInstallingPackages: - return m.updateInstallingPackagesState(msg) - case StateConfigConfirmation: - return m.updateConfigConfirmationState(msg) - case StateDeployingConfigs: - return m.updateDeployingConfigsState(msg) - case StateInstallComplete: - return m.updateInstallCompleteState(msg) - case StateError: - return m.updateErrorState(msg) - default: - return m, m.listenForLogs() - } -} - -func (m Model) View() string { - // If debug logs are shown, show that view regardless of state - if m.showDebugLogs { - return m.viewDebugLogs() - } - - switch m.state { - case StateWelcome: - return m.viewWelcome() - case StateSelectWindowManager: - return m.viewSelectWindowManager() - case StateSelectTerminal: - return m.viewSelectTerminal() - case StateDetectingDeps: - return m.viewDetectingDeps() - case StateDependencyReview: - return m.viewDependencyReview() - case StateGentooUseFlags: - return m.viewGentooUseFlags() - case StateGentooGCCCheck: - return m.viewGentooGCCCheck() - case StateAuthMethodChoice: - return m.viewAuthMethodChoice() - case StateFingerprintAuth: - return m.viewFingerprintAuth() - case StatePasswordPrompt: - return m.viewPasswordPrompt() - case StateInstallingPackages: - return m.viewInstallingPackages() - case StateConfigConfirmation: - return m.viewConfigConfirmation() - case StateDeployingConfigs: - return m.viewDeployingConfigs() - case StateInstallComplete: - return m.viewInstallComplete() - case StateError: - return m.viewError() - default: - return m.viewWelcome() - } -} - -func (m Model) listenForLogs() tea.Cmd { - return func() tea.Msg { - select { - case msg, ok := <-m.logChan: - if !ok { - return nil - } - return logMsg{message: msg} - default: - return nil - } - } -} - -func (m Model) detectOS() tea.Cmd { - return func() tea.Msg { - info, err := distros.GetOSInfo() - osInfoMsg := &distros.OSInfo{} - if info != nil { - osInfoMsg.Distribution = info.Distribution - osInfoMsg.Version = info.Version - osInfoMsg.VersionID = info.VersionID - osInfoMsg.PrettyName = info.PrettyName - osInfoMsg.Architecture = info.Architecture - } - return osInfoCompleteMsg{info: osInfoMsg, err: err} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/banner.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/banner.go deleted file mode 100644 index e3a2ca3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/banner.go +++ /dev/null @@ -1,21 +0,0 @@ -package tui - -import "github.com/charmbracelet/lipgloss" - -func (m Model) renderBanner() string { - logo := ` -██████╗ █████╗ ███╗ ██╗██╗ ██╗ -██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝ -██║ ██║███████║██╔██╗ ██║█████╔╝ -██║ ██║██╔══██║██║╚██╗██║██╔═██╗ -██████╔╝██║ ██║██║ ╚████║██║ ██╗ -╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ` - - theme := TerminalTheme() - style := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - MarginBottom(1) - - return style.Render(logo) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/messages.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/messages.go deleted file mode 100644 index 7c03098..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/messages.go +++ /dev/null @@ -1,39 +0,0 @@ -package tui - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" -) - -type logMsg struct { - message string -} - -type osInfoCompleteMsg struct { - info *distros.OSInfo - err error -} - -type depsDetectedMsg struct { - deps []deps.Dependency - err error -} - -type packageInstallProgressMsg struct { - progress float64 - step string - isComplete bool - needsSudo bool - commandInfo string - logOutput string - error error -} - -type packageProgressCompletedMsg struct{} - -type passwordValidMsg struct { - password string - valid bool -} - -type delayCompleteMsg struct{} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/states.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/states.go deleted file mode 100644 index 6e9e194..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/states.go +++ /dev/null @@ -1,22 +0,0 @@ -package tui - -type ApplicationState int - -const ( - StateWelcome ApplicationState = iota - StateSelectWindowManager - StateSelectTerminal - StateDetectingDeps - StateDependencyReview - StateGentooUseFlags - StateGentooGCCCheck - StateAuthMethodChoice - StateFingerprintAuth - StatePasswordPrompt - StateInstallingPackages - StateConfigConfirmation - StateDeployingConfigs - StateInstallComplete - StateFinalComplete - StateError -) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/styles.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/styles.go deleted file mode 100644 index 45a9dae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/styles.go +++ /dev/null @@ -1,124 +0,0 @@ -package tui - -import ( - "github.com/charmbracelet/bubbles/progress" - "github.com/charmbracelet/lipgloss" -) - -type AppTheme struct { - Primary string - Secondary string - Accent string - Text string - Subtle string - Error string - Warning string - Success string - Background string - Surface string -} - -func TerminalTheme() AppTheme { - return AppTheme{ - Primary: "6", // #625690 - purple - Secondary: "5", // #36247a - dark purple - Accent: "12", // #7060ac - light purple - Text: "7", // #2e2e2e - dark gray - Subtle: "8", // #4a4a4a - medium gray - Error: "1", // #d83636 - red - Warning: "3", // #ffff89 - yellow - Success: "2", // #53e550 - green - Background: "15", // #1a1a1a - near black - Surface: "8", // #4a4a4a - medium gray - } -} - -func NewStyles(theme AppTheme) Styles { - return Styles{ - Title: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - MarginLeft(1). - MarginBottom(1), - - Normal: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Text)), - - Bold: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Text)). - Bold(true), - - Subtle: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Subtle)), - - Error: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Error)), - - Warning: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Warning)), - - StatusBar: lipgloss.NewStyle(). - Foreground(lipgloss.Color("#33275e")). - Background(lipgloss.Color(theme.Primary)). - Padding(0, 1), - - Key: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)). - Bold(true), - - SpinnerStyle: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)), - - Success: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Success)). - Bold(true), - - HighlightButton: lipgloss.NewStyle(). - Foreground(lipgloss.Color("#33275e")). - Background(lipgloss.Color(theme.Primary)). - Padding(0, 2). - Bold(true), - - SelectedOption: lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)). - Bold(true), - - CodeBlock: lipgloss.NewStyle(). - Background(lipgloss.Color(theme.Surface)). - Foreground(lipgloss.Color(theme.Text)). - Padding(1, 2). - MarginLeft(2), - } -} - -type Styles struct { - Title lipgloss.Style - Normal lipgloss.Style - Bold lipgloss.Style - Subtle lipgloss.Style - Warning lipgloss.Style - Error lipgloss.Style - StatusBar lipgloss.Style - Key lipgloss.Style - SpinnerStyle lipgloss.Style - Success lipgloss.Style - HighlightButton lipgloss.Style - SelectedOption lipgloss.Style - CodeBlock lipgloss.Style -} - -func (s Styles) NewThemedProgress(width int) progress.Model { - theme := TerminalTheme() - prog := progress.New( - progress.WithGradient(theme.Secondary, theme.Primary), - ) - - prog.Width = width - prog.ShowPercentage = true - prog.PercentFormat = "%.0f%%" - prog.PercentageStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Text)). - Bold(true) - - return prog -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_config.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_config.go deleted file mode 100644 index 14daff3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_config.go +++ /dev/null @@ -1,382 +0,0 @@ -package tui - -import ( - "context" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/config" - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - tea "github.com/charmbracelet/bubbletea" -) - -type configDeploymentResult struct { - results []config.DeploymentResult - error error -} - -type ExistingConfigInfo struct { - ConfigType string - Path string - Exists bool -} - -type configCheckResult struct { - configs []ExistingConfigInfo - error error -} - -func (m Model) viewDeployingConfigs() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Deploying Configurations") - b.WriteString(title) - b.WriteString("\n\n") - - spinner := m.spinner.View() - status := m.styles.Normal.Render("Setting up configuration files...") - fmt.Fprintf(&b, "%s %s", spinner, status) - b.WriteString("\n\n") - - // Show progress information - info := m.styles.Subtle.Render("• Creating backups of existing configurations\n• Deploying optimized configurations\n• Detecting system paths") - b.WriteString(info) - - // Show live log output if available - if len(m.installationLogs) > 0 { - b.WriteString("\n\n") - logHeader := m.styles.Subtle.Render("Configuration Log:") - b.WriteString(logHeader) - b.WriteString("\n") - - // Show last few lines of logs - maxLines := 5 - startIdx := 0 - if len(m.installationLogs) > maxLines { - startIdx = len(m.installationLogs) - maxLines - } - - for i := startIdx; i < len(m.installationLogs); i++ { - if m.installationLogs[i] != "" { - logLine := m.styles.Subtle.Render(" " + m.installationLogs[i]) - b.WriteString(logLine) - b.WriteString("\n") - } - } - } - - return b.String() -} - -func (m Model) updateDeployingConfigsState(msg tea.Msg) (tea.Model, tea.Cmd) { - if result, ok := msg.(configDeploymentResult); ok { - if result.error != nil { - m.err = result.error - m.state = StateError - m.isLoading = false - return m, nil - } - - for _, deployResult := range result.results { - if deployResult.Deployed { - logMsg := fmt.Sprintf("✓ %s configuration deployed", deployResult.ConfigType) - if deployResult.BackupPath != "" { - logMsg += fmt.Sprintf(" (backup: %s)", deployResult.BackupPath) - } - m.installationLogs = append(m.installationLogs, logMsg) - } - } - - m.state = StateInstallComplete - m.isLoading = false - return m, nil - } - - return m, m.listenForLogs() -} - -func (m Model) deployConfigurations() tea.Cmd { - return func() tea.Msg { - // Determine the selected window manager - var wm deps.WindowManager - switch m.selectedWM { - case 0: - wm = deps.WindowManagerNiri - case 1: - wm = deps.WindowManagerHyprland - default: - wm = deps.WindowManagerNiri - } - - // Determine the selected terminal - var terminal deps.Terminal - if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" { - switch m.selectedTerminal { - case 0: - terminal = deps.TerminalKitty - case 1: - terminal = deps.TerminalAlacritty - default: - terminal = deps.TerminalKitty - } - } else { - switch m.selectedTerminal { - case 0: - terminal = deps.TerminalGhostty - case 1: - terminal = deps.TerminalKitty - default: - terminal = deps.TerminalAlacritty - } - } - - deployer := config.NewConfigDeployer(m.logChan) - - results, err := deployer.DeployConfigurationsSelectiveWithReinstalls(context.Background(), wm, terminal, m.dependencies, m.replaceConfigs, m.reinstallItems) - - return configDeploymentResult{ - results: results, - error: err, - } - } -} - -func (m Model) viewConfigConfirmation() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Configuration Deployment") - b.WriteString(title) - b.WriteString("\n\n") - - if len(m.existingConfigs) == 0 { - // No existing configs, proceed directly - info := m.styles.Normal.Render("No existing configurations found. Proceeding with deployment...") - b.WriteString(info) - return b.String() - } - - // Show existing configurations with toggle options - for i, configInfo := range m.existingConfigs { - if configInfo.Exists { - var status string - var replaceMarker string - - shouldReplace := m.replaceConfigs[configInfo.ConfigType] - if _, exists := m.replaceConfigs[configInfo.ConfigType]; !exists { - shouldReplace = true - m.replaceConfigs[configInfo.ConfigType] = true - } - - if shouldReplace { - replaceMarker = "🔄 " - status = m.styles.Warning.Render("Will replace") - } else { - replaceMarker = "✓ " - status = m.styles.Success.Render("Keep existing") - } - - var line string - if i == m.selectedConfig { - line = fmt.Sprintf("▶ %s%-15s %s", replaceMarker, configInfo.ConfigType, status) - line += fmt.Sprintf("\n %s", configInfo.Path) - line = m.styles.SelectedOption.Render(line) - } else { - line = fmt.Sprintf(" %s%-15s %s", replaceMarker, configInfo.ConfigType, status) - line += fmt.Sprintf("\n %s", configInfo.Path) - line = m.styles.Normal.Render(line) - } - - b.WriteString(line) - b.WriteString("\n\n") - } - } - - backup := m.styles.Success.Render("✓ Replaced configurations will be backed up with timestamp") - b.WriteString(backup) - b.WriteString("\n\n") - - help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle replace/keep, Enter: Continue") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateConfigConfirmationState(msg tea.Msg) (tea.Model, tea.Cmd) { - if result, ok := msg.(configCheckResult); ok { - if result.error != nil { - m.err = result.error - m.state = StateError - return m, nil - } - - m.existingConfigs = result.configs - - firstExistingSet := false - for i, config := range result.configs { - if config.Exists { - m.replaceConfigs[config.ConfigType] = true - if !firstExistingSet { - m.selectedConfig = i - firstExistingSet = true - } - } - } - - hasExisting := false - for _, config := range result.configs { - if config.Exists { - hasExisting = true - break - } - } - - if !hasExisting { - // No existing configs, proceed directly to deployment - m.state = StateDeployingConfigs - return m, m.deployConfigurations() - } - - // Show confirmation view - return m, nil - } - - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "up": - if m.selectedConfig > 0 { - for i := m.selectedConfig - 1; i >= 0; i-- { - if m.existingConfigs[i].Exists { - m.selectedConfig = i - break - } - } - } - case "down": - if m.selectedConfig < len(m.existingConfigs)-1 { - for i := m.selectedConfig + 1; i < len(m.existingConfigs); i++ { - if m.existingConfigs[i].Exists { - m.selectedConfig = i - break - } - } - } - case " ": - if len(m.existingConfigs) > 0 && m.selectedConfig < len(m.existingConfigs) { - configType := m.existingConfigs[m.selectedConfig].ConfigType - if m.existingConfigs[m.selectedConfig].Exists { - m.replaceConfigs[configType] = !m.replaceConfigs[configType] - } - } - case "enter": - m.state = StateDeployingConfigs - return m, m.deployConfigurations() - } - } - - return m, nil -} - -func (m Model) checkExistingConfigurations() tea.Cmd { - return func() tea.Msg { - var configs []ExistingConfigInfo - - if m.selectedWM == 0 { - niriPath := filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl") - niriExists := false - if _, err := os.Stat(niriPath); err == nil { - niriExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Niri", - Path: niriPath, - Exists: niriExists, - }) - } else { - hyprlandPath := filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf") - hyprlandExists := false - if _, err := os.Stat(hyprlandPath); err == nil { - hyprlandExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Hyprland", - Path: hyprlandPath, - Exists: hyprlandExists, - }) - } - - if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" { - if m.selectedTerminal == 0 { - kittyPath := filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf") - kittyExists := false - if _, err := os.Stat(kittyPath); err == nil { - kittyExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Kitty", - Path: kittyPath, - Exists: kittyExists, - }) - } else { - alacrittyPath := filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml") - alacrittyExists := false - if _, err := os.Stat(alacrittyPath); err == nil { - alacrittyExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Alacritty", - Path: alacrittyPath, - Exists: alacrittyExists, - }) - } - } else { - switch m.selectedTerminal { - case 0: - ghosttyPath := filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config") - ghosttyExists := false - if _, err := os.Stat(ghosttyPath); err == nil { - ghosttyExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Ghostty", - Path: ghosttyPath, - Exists: ghosttyExists, - }) - case 1: - kittyPath := filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf") - kittyExists := false - if _, err := os.Stat(kittyPath); err == nil { - kittyExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Kitty", - Path: kittyPath, - Exists: kittyExists, - }) - default: - alacrittyPath := filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml") - alacrittyExists := false - if _, err := os.Stat(alacrittyPath); err == nil { - alacrittyExists = true - } - configs = append(configs, ExistingConfigInfo{ - ConfigType: "Alacritty", - Path: alacrittyPath, - Exists: alacrittyExists, - }) - } - } - - return configCheckResult{ - configs: configs, - error: nil, - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go deleted file mode 100644 index 13f0335..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go +++ /dev/null @@ -1,304 +0,0 @@ -package tui - -import ( - "context" - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - "github.com/AvengeMedia/DankMaterialShell/core/internal/greeter" - tea "github.com/charmbracelet/bubbletea" -) - -func (m Model) viewDetectingDeps() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Detecting Dependencies") - b.WriteString(title) - b.WriteString("\n\n") - - spinner := m.spinner.View() - status := m.styles.Normal.Render("Scanning system for existing packages and configurations...") - fmt.Fprintf(&b, "%s %s", spinner, status) - - return b.String() -} - -func (m Model) viewDependencyReview() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Dependency Review") - b.WriteString(title) - b.WriteString("\n\n") - - if len(m.dependencies) > 0 { - for i, dep := range m.dependencies { - var status string - var reinstallMarker string - var variantMarker string - - isDMS := dep.Name == "dms (DankMaterialShell)" - - if dep.CanToggle && dep.Variant == deps.VariantGit { - variantMarker = "[git] " - } - - if m.disabledItems[dep.Name] { - reinstallMarker = "✗ " - status = m.styles.Subtle.Render("Will skip") - } else if m.reinstallItems[dep.Name] { - reinstallMarker = "🔄 " - status = m.styles.Warning.Render("Will upgrade") - } else if isDMS { - reinstallMarker = "⚡ " - switch dep.Status { - case deps.StatusInstalled: - status = m.styles.Success.Render("✓ Required (installed)") - case deps.StatusMissing: - status = m.styles.Warning.Render("○ Required (will install)") - case deps.StatusNeedsUpdate: - status = m.styles.Warning.Render("△ Required (needs update)") - case deps.StatusNeedsReinstall: - status = m.styles.Error.Render("! Required (needs reinstall)") - } - } else { - switch dep.Status { - case deps.StatusInstalled: - status = m.styles.Subtle.Render("✓ Already installed") - case deps.StatusMissing: - status = m.styles.Warning.Render("○ Will install") - case deps.StatusNeedsUpdate: - status = m.styles.Warning.Render("△ Will install") - case deps.StatusNeedsReinstall: - status = m.styles.Error.Render("! Will install") - } - } - - note := "" - if dep.Name == "dms-greeter" { - note = m.styles.Subtle.Render(" (selection replaces your current display manager)") - } - - var line string - if i == m.selectedDep { - line = fmt.Sprintf("▶ %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status) - if dep.Version != "" { - line += fmt.Sprintf(" (%s)", dep.Version) - } - line = m.styles.SelectedOption.Render(line) + note - } else { - line = fmt.Sprintf(" %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status) - if dep.Version != "" { - line += fmt.Sprintf(" (%s)", dep.Version) - } - line = m.styles.Normal.Render(line) + note - } - - b.WriteString(line) - b.WriteString("\n") - } - } - - b.WriteString("\n") - help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle, G: Toggle stable/git, Enter: Continue") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateDetectingDepsState(msg tea.Msg) (tea.Model, tea.Cmd) { - if depsMsg, ok := msg.(depsDetectedMsg); ok { - m.isLoading = false - if depsMsg.err != nil { - m.err = depsMsg.err - m.state = StateError - } else { - m.dependencies = depsMsg.deps - // dms-greeter is opt-in skipped by default - for _, dep := range depsMsg.deps { - if dep.Name == "dms-greeter" { - m.disabledItems["dms-greeter"] = true - break - } - } - m.state = StateDependencyReview - } - return m, m.listenForLogs() - } - return m, m.listenForLogs() -} - -func (m Model) updateDependencyReviewState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "up": - if m.selectedDep > 0 { - m.selectedDep-- - } - case "down": - if m.selectedDep < len(m.dependencies)-1 { - m.selectedDep++ - } - case " ": - if len(m.dependencies) > 0 { - depName := m.dependencies[m.selectedDep].Name - isDMS := depName == "dms (DankMaterialShell)" - - if !isDMS { - isInstalled := m.dependencies[m.selectedDep].Status == deps.StatusInstalled || - m.dependencies[m.selectedDep].Status == deps.StatusNeedsReinstall - - if isInstalled { - m.reinstallItems[depName] = !m.reinstallItems[depName] - m.disabledItems[depName] = false - } else { - m.disabledItems[depName] = !m.disabledItems[depName] - m.reinstallItems[depName] = false - } - } - } - case "g", "G": - if len(m.dependencies) > 0 && m.dependencies[m.selectedDep].CanToggle { - if m.dependencies[m.selectedDep].Variant == deps.VariantStable { - m.dependencies[m.selectedDep].Variant = deps.VariantGit - } else { - m.dependencies[m.selectedDep].Variant = deps.VariantStable - } - } - case "enter": - // Check if on Gentoo - show USE flags screen - if m.osInfo != nil { - if config, exists := distros.Registry[m.osInfo.Distribution.ID]; exists && config.Family == distros.FamilyGentoo { - m.state = StateGentooUseFlags - return m, nil - } - } - // Check if fingerprint is enabled - if checkFingerprintEnabled() { - m.state = StateAuthMethodChoice - m.selectedConfig = 0 // Default to fingerprint - return m, nil - } else { - m.state = StatePasswordPrompt - m.passwordInput.Focus() - return m, nil - } - case "esc": - m.state = StateSelectWindowManager - return m, nil - } - } - return m, m.listenForLogs() -} - -func (m Model) installPackages() tea.Cmd { - return func() tea.Msg { - if m.osInfo == nil { - return packageInstallProgressMsg{ - progress: 0.0, - step: "Error: OS info not available", - isComplete: true, - } - } - - installer, err := distros.NewPackageInstaller(m.osInfo.Distribution.ID, m.logChan) - if err != nil { - return packageInstallProgressMsg{ - progress: 0.0, - step: fmt.Sprintf("Error: %s", err.Error()), - isComplete: true, - } - } - - // Convert TUI selection to deps enum - var wm deps.WindowManager - if m.selectedWM == 0 { - wm = deps.WindowManagerNiri - } else { - wm = deps.WindowManagerHyprland - } - - installerProgressChan := make(chan distros.InstallProgressMsg, 100) - - go func() { - defer close(installerProgressChan) - err := installer.InstallPackages(context.Background(), m.dependencies, wm, m.sudoPassword, m.reinstallItems, m.disabledItems, m.skipGentooUseFlags, installerProgressChan) - if err != nil { - installerProgressChan <- distros.InstallProgressMsg{ - Progress: 0.0, - Step: fmt.Sprintf("Installation error: %s", err.Error()), - IsComplete: true, - Error: err, - } - } - }() - - // Convert installer messages to TUI messages - go func() { - for msg := range installerProgressChan { - // Run optional greeter setup - if msg.Phase == distros.PhaseComplete && msg.IsComplete && msg.Error == nil { - greeterSelected := false - for _, dep := range m.dependencies { - if dep.Name == "dms-greeter" && !m.disabledItems["dms-greeter"] { - greeterSelected = true - break - } - } - if greeterSelected { - compositorName := "niri" - if m.selectedWM == 1 { - compositorName = "Hyprland" - } - m.packageProgressChan <- packageInstallProgressMsg{ - progress: 0.92, - step: "Configuring DMS greeter...", - logOutput: "Starting automated greeter setup...", - } - greeterLogFunc := func(line string) { - m.packageProgressChan <- packageInstallProgressMsg{ - progress: 0.94, - step: "Configuring DMS greeter...", - logOutput: line, - } - } - if err := greeter.AutoSetupGreeter(compositorName, m.sudoPassword, greeterLogFunc); err != nil { - m.packageProgressChan <- packageInstallProgressMsg{ - progress: 0.96, - step: "Greeter setup warning", - logOutput: fmt.Sprintf("⚠ Greeter auto-setup warning (non-fatal): %v", err), - } - } - } - } - tuiMsg := packageInstallProgressMsg{ - progress: msg.Progress, - step: msg.Step, - isComplete: msg.IsComplete, - needsSudo: msg.NeedsSudo, - commandInfo: msg.CommandInfo, - logOutput: msg.LogOutput, - error: msg.Error, - } - if msg.IsComplete { - m.logChan <- fmt.Sprintf("[DEBUG] Sending completion signal: step=%s, progress=%.2f", msg.Step, msg.Progress) - } - m.packageProgressChan <- tuiMsg - } - m.logChan <- "[DEBUG] Installer channel closed" - }() - - return packageInstallProgressMsg{ - progress: 0.05, - step: "Starting installation...", - isComplete: false, - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go deleted file mode 100644 index 74195a4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go +++ /dev/null @@ -1,103 +0,0 @@ -package tui - -import ( - "context" - "fmt" - "os/exec" - "strconv" - "strings" - - tea "github.com/charmbracelet/bubbletea" -) - -type gccVersionCheckMsg struct { - version string - major int - err error -} - -func (m Model) viewGentooGCCCheck() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("GCC Version Check Failed") - b.WriteString(title) - b.WriteString("\n\n") - - error := m.styles.Error.Render("⚠ Hyprland requires GCC 15 or newer") - b.WriteString(error) - b.WriteString("\n\n") - - info := m.styles.Normal.Render("Your current GCC version is too old. Please upgrade GCC before continuing.") - b.WriteString(info) - b.WriteString("\n\n") - - instructionsTitle := m.styles.Subtle.Render("To upgrade GCC:") - b.WriteString(instructionsTitle) - b.WriteString("\n\n") - - steps := []string{ - "1. Install GCC 15 (if not already installed):", - " sudo emerge -1av =sys-devel/gcc:15", - "", - "2. Switch to GCC 15 using gcc-config:", - " sudo gcc-config $(gcc-config -l | grep gcc-15 | awk '{print $2}' | head -1)", - "", - "3. Update environment:", - " source /etc/profile", - "", - "4. Restart this installer", - } - - for _, step := range steps { - stepLine := m.styles.Subtle.Render(step) - b.WriteString(stepLine) - b.WriteString("\n") - } - - b.WriteString("\n") - help := m.styles.Subtle.Render("Press Esc to go back, Ctrl+C to exit") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateGentooGCCCheckState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "esc": - m.state = StateSelectWindowManager - return m, nil - } - } - return m, m.listenForLogs() -} - -func (m Model) checkGCCVersion() tea.Cmd { - return func() tea.Msg { - cmd := exec.CommandContext(context.Background(), "gcc", "-dumpversion") - output, err := cmd.Output() - if err != nil { - return gccVersionCheckMsg{err: err} - } - - version := strings.TrimSpace(string(output)) - parts := strings.Split(version, ".") - if len(parts) == 0 { - return gccVersionCheckMsg{err: fmt.Errorf("invalid gcc version format")} - } - - major, err := strconv.Atoi(parts[0]) - if err != nil { - return gccVersionCheckMsg{err: err} - } - - return gccVersionCheckMsg{ - version: version, - major: major, - err: nil, - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go deleted file mode 100644 index eb259ef..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go +++ /dev/null @@ -1,92 +0,0 @@ -package tui - -import ( - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - tea "github.com/charmbracelet/bubbletea" -) - -func (m Model) viewGentooUseFlags() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Gentoo Global USE Flags") - b.WriteString(title) - b.WriteString("\n\n") - - info := m.styles.Normal.Render("The following global USE flags will be enabled in /etc/portage/make.conf:") - b.WriteString(info) - b.WriteString("\n\n") - - for _, flag := range distros.GentooGlobalUseFlags { - flagLine := m.styles.Success.Render(fmt.Sprintf(" • %s", flag)) - b.WriteString(flagLine) - b.WriteString("\n") - } - - b.WriteString("\n") - note := m.styles.Subtle.Render("These flags ensure proper Qt6, Wayland, and compositor support.") - b.WriteString(note) - b.WriteString("\n\n") - - var toggleLine string - if m.skipGentooUseFlags { - toggleLine = "▶ [✗] Skip adding global USE flags (will use existing configuration)" - toggleLine = m.styles.Warning.Render(toggleLine) - } else { - toggleLine = " [ ] Skip adding global USE flags (will use existing configuration)" - toggleLine = m.styles.Subtle.Render(toggleLine) - } - b.WriteString(toggleLine) - b.WriteString("\n\n") - - help := m.styles.Subtle.Render("Space: Toggle skip, Enter: Continue, Esc: Go back") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateGentooUseFlagsState(msg tea.Msg) (tea.Model, tea.Cmd) { - if gccMsg, ok := msg.(gccVersionCheckMsg); ok { - if gccMsg.err != nil || gccMsg.major < 15 { - m.state = StateGentooGCCCheck - return m, nil - } - if checkFingerprintEnabled() { - m.state = StateAuthMethodChoice - m.selectedConfig = 0 - } else { - m.state = StatePasswordPrompt - m.passwordInput.Focus() - } - return m, nil - } - - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case " ": - m.skipGentooUseFlags = !m.skipGentooUseFlags - return m, nil - case "enter": - if m.selectedWM == 1 { - return m, m.checkGCCVersion() - } - if checkFingerprintEnabled() { - m.state = StateAuthMethodChoice - m.selectedConfig = 0 - } else { - m.state = StatePasswordPrompt - m.passwordInput.Focus() - } - return m, nil - case "esc": - m.state = StateDependencyReview - return m, nil - } - } - return m, m.listenForLogs() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_install.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_install.go deleted file mode 100644 index c110711..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_install.go +++ /dev/null @@ -1,405 +0,0 @@ -package tui - -import ( - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -// wrapText wraps text to the specified width -func wrapText(text string, width int) string { - if len(text) <= width { - return text - } - - var result strings.Builder - words := strings.Fields(text) - currentLine := "" - - for _, word := range words { - if len(currentLine) == 0 { - currentLine = word - } else if len(currentLine)+1+len(word) <= width { - currentLine += " " + word - } else { - result.WriteString(currentLine) - result.WriteString("\n") - currentLine = word - } - } - - if len(currentLine) > 0 { - result.WriteString(currentLine) - } - - return result.String() -} - -func (m Model) viewInstallingPackages() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Installing Packages") - b.WriteString(title) - b.WriteString("\n\n") - - if !m.packageProgress.isComplete { - spinner := m.spinner.View() - status := m.styles.Normal.Render(m.packageProgress.step) - fmt.Fprintf(&b, "%s %s", spinner, status) - b.WriteString("\n\n") - - // Show progress bar - progressBar := fmt.Sprintf("[%s%s] %.0f%%", - strings.Repeat("█", int(m.packageProgress.progress*30)), - strings.Repeat("░", 30-int(m.packageProgress.progress*30)), - m.packageProgress.progress*100) - b.WriteString(m.styles.Normal.Render(progressBar)) - b.WriteString("\n") - - // Show command info if available - if m.packageProgress.commandInfo != "" { - cmdInfo := m.styles.Subtle.Render("$ " + m.packageProgress.commandInfo) - b.WriteString(cmdInfo) - b.WriteString("\n") - } - - // Show live log output - if len(m.installationLogs) > 0 { - b.WriteString("\n") - logHeader := m.styles.Subtle.Render("Live Output:") - b.WriteString(logHeader) - b.WriteString("\n") - - // Show last few lines of accumulated logs - maxLines := 8 - startIdx := 0 - if len(m.installationLogs) > maxLines { - startIdx = len(m.installationLogs) - maxLines - } - - for i := startIdx; i < len(m.installationLogs); i++ { - if m.installationLogs[i] != "" { - logLine := m.styles.Subtle.Render(" " + m.installationLogs[i]) - b.WriteString(logLine) - b.WriteString("\n") - } - } - } - - // Show error if any - if m.packageProgress.error != nil { - b.WriteString("\n") - wrappedErrorMsg := wrapText("Error: "+m.packageProgress.error.Error(), 80) - errorMsg := m.styles.Error.Render(wrappedErrorMsg) - b.WriteString(errorMsg) - } - - // Show sudo prompt if needed - if m.packageProgress.needsSudo { - sudoWarning := m.styles.Warning.Render("⚠ Using provided sudo password") - b.WriteString(sudoWarning) - } - } else { - if m.packageProgress.error != nil { - wrappedFailedMsg := wrapText("✗ Installation failed: "+m.packageProgress.error.Error(), 80) - errorMsg := m.styles.Error.Render(wrappedFailedMsg) - b.WriteString(errorMsg) - } else { - success := m.styles.Success.Render("✓ Installation complete!") - b.WriteString(success) - } - } - - return b.String() -} - -func dmsPackageName(distroID string, dependencies []deps.Dependency) string { - config, ok := distros.Registry[distroID] - if !ok { - return "dms" - } - - var isGit bool - for _, dep := range dependencies { - if dep.Name == "dms (DankMaterialShell)" { - isGit = dep.Variant == deps.VariantGit - break - } - } - - switch config.Family { - case distros.FamilyArch: - if isGit { - return "dms-shell-git" - } - return "dms-shell" - case distros.FamilyFedora, distros.FamilyUbuntu, distros.FamilyDebian, distros.FamilySUSE: - if isGit { - return "dms-git" - } - return "dms" - default: - return "dms" - } -} - -func uninstallCommand(distroID string, dependencies []deps.Dependency) string { - config, ok := distros.Registry[distroID] - if !ok { - return "" - } - if config.Family == distros.FamilyGentoo { - return "rm -rf ~/.config/quickshell/dms && sudo rm /usr/local/bin/dms" - } - pkg := dmsPackageName(distroID, dependencies) - switch config.Family { - case distros.FamilyArch: - return "sudo pacman -Rs " + pkg - case distros.FamilyFedora: - return "sudo dnf remove " + pkg - case distros.FamilyUbuntu, distros.FamilyDebian: - return "sudo apt remove " + pkg - case distros.FamilySUSE: - return "sudo zypper remove " + pkg - default: - return "" - } -} - -func (m Model) viewInstallComplete() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Success.Render("Setup Complete!") - b.WriteString(title) - b.WriteString("\n\n") - - success := m.styles.Success.Render("✓ All packages installed and configurations deployed.") - b.WriteString(success) - b.WriteString("\n\n") - - accomplishments := []string{ - "• Window manager and dependencies installed", - "• Terminal and development tools configured", - "• Configuration files deployed with backups", - "• System optimized for DankMaterialShell", - } - - for _, item := range accomplishments { - b.WriteString(m.styles.Subtle.Render(item)) - b.WriteString("\n") - } - - b.WriteString("\n") - info := m.styles.Normal.Render("Your system is ready! Log out and log back in to start using\nyour new desktop environment.\nIf you do not have a greeter, login with \"niri-session\" or \"Hyprland\"") - b.WriteString(info) - b.WriteString("\n\n") - - theme := TerminalTheme() - cmdStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Accent)) - labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Subtle)) - - b.WriteString(labelStyle.Render("Troubleshooting:") + "\n") - b.WriteString(labelStyle.Render(" Disable autostart: ") + cmdStyle.Render("systemctl --user disable dms") + "\n") - b.WriteString(labelStyle.Render(" View logs: ") + cmdStyle.Render("journalctl --user -u dms") + "\n") - - if m.osInfo != nil { - if cmd := uninstallCommand(m.osInfo.Distribution.ID, m.dependencies); cmd != "" { - b.WriteString(labelStyle.Render(" Uninstall: ") + cmdStyle.Render(cmd) + "\n") - } - } - - b.WriteString("\n") - b.WriteString(m.styles.Normal.Render("Press Enter to exit.")) - - if m.logFilePath != "" { - b.WriteString("\n\n") - logInfo := m.styles.Subtle.Render(fmt.Sprintf("Full logs: %s", m.logFilePath)) - b.WriteString(logInfo) - } - - return b.String() -} - -func (m Model) viewError() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Error.Render("Installation Failed") - b.WriteString(title) - b.WriteString("\n\n") - - if m.err != nil { - wrappedError := wrapText("✗ "+m.err.Error(), 80) - error := m.styles.Error.Render(wrappedError) - b.WriteString(error) - b.WriteString("\n\n") - } - - // Show package progress error if available - if m.packageProgress.error != nil { - wrappedPackageError := wrapText("Package Installation Error: "+m.packageProgress.error.Error(), 80) - packageError := m.styles.Error.Render(wrappedPackageError) - b.WriteString(packageError) - b.WriteString("\n\n") - } - - // Show persistent installation logs - if len(m.installationLogs) > 0 { - logHeader := m.styles.Warning.Render("Installation Logs (last 15 lines):") - b.WriteString(logHeader) - b.WriteString("\n") - - maxLines := 15 - startIdx := 0 - if len(m.installationLogs) > maxLines { - startIdx = len(m.installationLogs) - maxLines - } - - for i := startIdx; i < len(m.installationLogs); i++ { - if m.installationLogs[i] != "" { - logLine := m.styles.Subtle.Render(" " + m.installationLogs[i]) - b.WriteString(logLine) - b.WriteString("\n") - } - } - b.WriteString("\n") - } - - hint := m.styles.Subtle.Render("Press Ctrl+D for full debug logs") - b.WriteString(hint) - b.WriteString("\n") - - if m.logFilePath != "" { - b.WriteString("\n") - logInfo := m.styles.Warning.Render(fmt.Sprintf("Full logs: %s", m.logFilePath)) - b.WriteString(logInfo) - b.WriteString("\n") - } - - help := m.styles.Subtle.Render("Press Enter to exit") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateInstallingPackagesState(msg tea.Msg) (tea.Model, tea.Cmd) { - if progressMsg, ok := msg.(packageInstallProgressMsg); ok { - m.packageProgress = progressMsg - - // Accumulate log output - if progressMsg.logOutput != "" { - m.installationLogs = append(m.installationLogs, progressMsg.logOutput) - // Keep only last 50 lines to preserve more context for debugging - if len(m.installationLogs) > 50 { - m.installationLogs = m.installationLogs[len(m.installationLogs)-50:] - } - } - - if progressMsg.isComplete { - if progressMsg.error != nil { - m.state = StateError - m.isLoading = false - } else { - m.installationLogs = []string{} - m.state = StateConfigConfirmation - m.isLoading = true - return m, tea.Batch(m.spinner.Tick, m.checkExistingConfigurations()) - } - } - return m, m.listenForPackageProgress() - } - return m, m.listenForLogs() -} - -func (m Model) updateInstallCompleteState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "enter": - return m, tea.Quit - } - } - return m, m.listenForLogs() -} - -func (m Model) updateErrorState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "enter": - return m, tea.Quit - } - } - return m, m.listenForLogs() -} - -func (m Model) listenForPackageProgress() tea.Cmd { - return func() tea.Msg { - msg, ok := <-m.packageProgressChan - if !ok { - return packageProgressCompletedMsg{} - } - // Always return the message, completion will be handled in updateInstallingPackagesState - return msg - } -} - -func (m Model) viewDebugLogs() string { - var b strings.Builder - - theme := TerminalTheme() - - titleStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true) - - b.WriteString(titleStyle.Render("Debug Logs")) - b.WriteString("\n\n") - - // Combine both logMessages and installationLogs - allLogs := append([]string{}, m.logMessages...) - allLogs = append(allLogs, m.installationLogs...) - - if len(allLogs) == 0 { - b.WriteString("No logs available\n") - } else { - // Calculate available height (reserve space for header and footer) - maxHeight := m.height - 6 - if maxHeight < 10 { - maxHeight = 10 - } - - // Show the most recent logs - startIdx := 0 - if len(allLogs) > maxHeight { - startIdx = len(allLogs) - maxHeight - } - - for i := startIdx; i < len(allLogs); i++ { - if allLogs[i] != "" { - fmt.Fprintf(&b, "%d: %s\n", i, allLogs[i]) - } - } - - if startIdx > 0 { - subtleStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Subtle)) - b.WriteString(subtleStyle.Render(fmt.Sprintf("... (%d older log entries hidden)\n", startIdx))) - } - } - - b.WriteString("\n") - statusStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Accent)) - b.WriteString(statusStyle.Render("Press Ctrl+D to return, Ctrl+C to quit")) - - return b.String() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_password.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_password.go deleted file mode 100644 index deec061..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_password.go +++ /dev/null @@ -1,338 +0,0 @@ -package tui - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - tea "github.com/charmbracelet/bubbletea" -) - -func (m Model) viewAuthMethodChoice() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Authentication Method") - b.WriteString(title) - b.WriteString("\n\n") - - message := "Fingerprint authentication is available.\nHow would you like to authenticate?" - b.WriteString(m.styles.Normal.Render(message)) - b.WriteString("\n\n") - - // Option 0: Fingerprint - if m.selectedConfig == 0 { - option := m.styles.SelectedOption.Render("▶ Use Fingerprint") - b.WriteString(option) - } else { - option := m.styles.Normal.Render(" Use Fingerprint") - b.WriteString(option) - } - b.WriteString("\n") - - // Option 1: Password - if m.selectedConfig == 1 { - option := m.styles.SelectedOption.Render("▶ Use Password") - b.WriteString(option) - } else { - option := m.styles.Normal.Render(" Use Password") - b.WriteString(option) - } - b.WriteString("\n\n") - - help := m.styles.Subtle.Render("↑/↓: Navigate, Enter: Select, Esc: Back") - b.WriteString(help) - - return b.String() -} - -func (m Model) viewFingerprintAuth() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Fingerprint Authentication") - b.WriteString(title) - b.WriteString("\n\n") - - if m.fingerprintFailed { - errorMsg := m.styles.Error.Render("✗ Fingerprint authentication failed") - b.WriteString(errorMsg) - b.WriteString("\n") - retryMsg := m.styles.Subtle.Render("Returning to authentication menu...") - b.WriteString(retryMsg) - } else { - message := "Please place your finger on the fingerprint reader." - b.WriteString(m.styles.Normal.Render(message)) - b.WriteString("\n\n") - - spinner := m.spinner.View() - status := m.styles.Normal.Render("Waiting for fingerprint...") - fmt.Fprintf(&b, "%s %s", spinner, status) - } - - return b.String() -} - -func (m Model) viewPasswordPrompt() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Password Authentication") - b.WriteString(title) - b.WriteString("\n\n") - - message := "Installation requires sudo privileges.\nPlease enter your password to continue:" - b.WriteString(m.styles.Normal.Render(message)) - b.WriteString("\n\n") - - // Password input - b.WriteString(m.passwordInput.View()) - b.WriteString("\n") - - // Show validation status - if m.packageProgress.step == "Validating sudo password..." { - spinner := m.spinner.View() - status := m.styles.Normal.Render(m.packageProgress.step) - b.WriteString(spinner + " " + status) - b.WriteString("\n") - } else if m.packageProgress.error != nil { - errorMsg := m.styles.Error.Render("✗ " + m.packageProgress.error.Error() + ". Please try again.") - b.WriteString(errorMsg) - b.WriteString("\n") - } else if m.packageProgress.step == "Password validation failed" { - errorMsg := m.styles.Error.Render("✗ Incorrect password. Please try again.") - b.WriteString(errorMsg) - b.WriteString("\n") - } - - b.WriteString("\n") - help := m.styles.Subtle.Render("Enter: Continue, Esc: Back, Ctrl+C: Cancel") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateAuthMethodChoiceState(msg tea.Msg) (tea.Model, tea.Cmd) { - m.fingerprintFailed = false - - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "up": - if m.selectedConfig > 0 { - m.selectedConfig-- - } - case "down": - if m.selectedConfig < 1 { - m.selectedConfig++ - } - case "enter": - if m.selectedConfig == 0 { - m.state = StateFingerprintAuth - m.isLoading = true - return m, tea.Batch(m.spinner.Tick, m.tryFingerprint()) - } else { - m.state = StatePasswordPrompt - m.passwordInput.Focus() - return m, nil - } - case "esc": - m.state = StateDependencyReview - return m, nil - } - } - return m, nil -} - -func (m Model) updateFingerprintAuthState(msg tea.Msg) (tea.Model, tea.Cmd) { - if validMsg, ok := msg.(passwordValidMsg); ok { - if validMsg.valid { - m.sudoPassword = "" - m.packageProgress = packageInstallProgressMsg{} - m.state = StateInstallingPackages - m.isLoading = true - return m, tea.Batch(m.spinner.Tick, m.installPackages()) - } else { - m.fingerprintFailed = true - return m, m.delayThenReturn() - } - } - - if _, ok := msg.(delayCompleteMsg); ok { - m.fingerprintFailed = false - m.selectedConfig = 0 - m.state = StateAuthMethodChoice - return m, nil - } - - return m, m.listenForLogs() -} - -func (m Model) updatePasswordPromptState(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmd tea.Cmd - - if validMsg, ok := msg.(passwordValidMsg); ok { - if validMsg.valid { - // Password is valid, proceed with installation - m.sudoPassword = validMsg.password - m.passwordInput.SetValue("") // Clear password input - // Clear any error state - m.packageProgress = packageInstallProgressMsg{} - m.state = StateInstallingPackages - m.isLoading = true - return m, tea.Batch(m.spinner.Tick, m.installPackages()) - } else { - // Password is invalid, show error and stay on password prompt - m.packageProgress = packageInstallProgressMsg{ - progress: 0.0, - step: "Password validation failed", - error: fmt.Errorf("incorrect password"), - logOutput: "Authentication failed", - } - m.passwordInput.SetValue("") - m.passwordInput.Focus() - return m, nil - } - } - - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "enter": - // Don't allow multiple validation attempts while one is in progress - if m.packageProgress.step == "Validating sudo password..." { - return m, nil - } - - // Validate password first - password := m.passwordInput.Value() - if password == "" { - return m, nil // Don't proceed with empty password - } - - // Clear any previous error and show validation in progress - m.packageProgress = packageInstallProgressMsg{ - progress: 0.01, - step: "Validating sudo password...", - isComplete: false, - logOutput: "Testing password with sudo -v", - } - return m, m.validatePassword(password) - case "esc": - // Go back to dependency review - m.passwordInput.SetValue("") - m.packageProgress = packageInstallProgressMsg{} // Clear any validation state - m.state = StateDependencyReview - return m, nil - } - } - - m.passwordInput, cmd = m.passwordInput.Update(msg) - return m, cmd -} - -func checkFingerprintEnabled() bool { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - - // Check if pam_fprintd.so is in PAM config - cmd := exec.CommandContext(ctx, "grep", "-q", "pam_fprintd.so", "/etc/pam.d/system-auth") - if err := cmd.Run(); err != nil { - return false - } - - // Check if fprintd-list exists and user has enrolled fingerprints - user := os.Getenv("USER") - if user == "" { - return false - } - - listCmd := exec.CommandContext(ctx, "fprintd-list", user) - output, err := listCmd.CombinedOutput() - if err != nil { - return false - } - - // If output contains "finger:" or similar, fingerprints are enrolled - return strings.Contains(string(output), "finger") -} - -func (m Model) delayThenReturn() tea.Cmd { - return func() tea.Msg { - time.Sleep(2 * time.Second) - return delayCompleteMsg{} - } -} - -func (m Model) tryFingerprint() tea.Cmd { - return func() tea.Msg { - clearCmd := exec.Command("sudo", "-k") - clearCmd.Run() - - tmpDir := os.TempDir() - askpassScript := filepath.Join(tmpDir, fmt.Sprintf("danklinux-fp-%d.sh", time.Now().UnixNano())) - - scriptContent := "#!/bin/sh\nexit 1\n" - if err := os.WriteFile(askpassScript, []byte(scriptContent), 0o700); err != nil { - return passwordValidMsg{password: "", valid: false} - } - defer os.Remove(askpassScript) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - - cmd := exec.CommandContext(ctx, "sudo", "-A", "-v") - cmd.Env = append(os.Environ(), fmt.Sprintf("SUDO_ASKPASS=%s", askpassScript)) - - err := cmd.Run() - - if err != nil { - return passwordValidMsg{password: "", valid: false} - } - - return passwordValidMsg{password: "", valid: true} - } -} - -func (m Model) validatePassword(password string) tea.Cmd { - return func() tea.Msg { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - cmd := exec.CommandContext(ctx, "sudo", "-S", "-v") - - stdin, err := cmd.StdinPipe() - if err != nil { - return passwordValidMsg{password: "", valid: false} - } - - if err := cmd.Start(); err != nil { - return passwordValidMsg{password: "", valid: false} - } - - _, err = fmt.Fprintf(stdin, "%s\n", password) - stdin.Close() - if err != nil { - return passwordValidMsg{password: "", valid: false} - } - - err = cmd.Wait() - - if err != nil { - if ctx.Err() == context.DeadlineExceeded { - return passwordValidMsg{password: "", valid: false} - } - return passwordValidMsg{password: "", valid: false} - } - - return passwordValidMsg{password: password, valid: true} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_selection.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_selection.go deleted file mode 100644 index e45105e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_selection.go +++ /dev/null @@ -1,224 +0,0 @@ -package tui - -import ( - "context" - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/deps" - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - tea "github.com/charmbracelet/bubbletea" -) - -func (m Model) viewSelectWindowManager() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Choose Window Manager") - b.WriteString(title) - b.WriteString("\n\n") - - options := []struct { - name string - description string - }{ - {"niri", "Scrollable-tiling Wayland compositor."}, - } - - if m.osInfo == nil || m.osInfo.Distribution.ID != "debian" { - options = append(options, struct { - name string - description string - }{"Hyprland", "Dynamic tiling Wayland compositor."}) - } - - for i, option := range options { - if i == m.selectedWM { - selected := m.styles.SelectedOption.Render("▶ " + option.name) - b.WriteString(selected) - b.WriteString("\n") - desc := m.styles.Subtle.Render(" " + option.description) - b.WriteString(desc) - } else { - normal := m.styles.Normal.Render(" " + option.name) - b.WriteString(normal) - b.WriteString("\n") - desc := m.styles.Subtle.Render(" " + option.description) - b.WriteString(desc) - } - b.WriteString("\n") - if i < len(options)-1 { - b.WriteString("\n") - } - } - - b.WriteString("\n") - help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back") - b.WriteString(help) - - return b.String() -} - -func (m Model) viewSelectTerminal() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - title := m.styles.Title.Render("Choose Terminal Emulator") - b.WriteString(title) - b.WriteString("\n\n") - - var options []struct { - name string - description string - } - - if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" { - options = []struct { - name string - description string - }{ - {"kitty", "A feature-rich, customizable terminal emulator."}, - {"alacritty", "A simple terminal emulator."}, - } - } else { - options = []struct { - name string - description string - }{ - {"ghostty", "A fast, native terminal emulator built in Zig."}, - {"kitty", "A feature-rich, customizable terminal emulator."}, - {"alacritty", "A simple terminal emulator."}, - } - } - - for i, option := range options { - if i == m.selectedTerminal { - selected := m.styles.SelectedOption.Render("▶ " + option.name) - b.WriteString(selected) - b.WriteString("\n") - desc := m.styles.Subtle.Render(" " + option.description) - b.WriteString(desc) - } else { - normal := m.styles.Normal.Render(" " + option.name) - b.WriteString(normal) - b.WriteString("\n") - desc := m.styles.Subtle.Render(" " + option.description) - b.WriteString(desc) - } - b.WriteString("\n") - if i < len(options)-1 { - b.WriteString("\n") - } - } - - b.WriteString("\n") - help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back") - b.WriteString(help) - - return b.String() -} - -func (m Model) updateSelectTerminalState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - maxTerminalIndex := 2 - if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" { - maxTerminalIndex = 1 - } - - switch keyMsg.String() { - case "up": - if m.selectedTerminal > 0 { - m.selectedTerminal-- - } - case "down": - if m.selectedTerminal < maxTerminalIndex { - m.selectedTerminal++ - } - case "enter": - m.state = StateDetectingDeps - m.isLoading = true - return m, tea.Batch(m.spinner.Tick, m.detectDependencies()) - case "esc": - m.state = StateSelectWindowManager - return m, m.listenForLogs() - } - } - return m, m.listenForLogs() -} - -func (m Model) updateSelectWindowManagerState(msg tea.Msg) (tea.Model, tea.Cmd) { - if keyMsg, ok := msg.(tea.KeyMsg); ok { - maxWMIndex := 1 - if m.osInfo != nil && m.osInfo.Distribution.ID == "debian" { - maxWMIndex = 0 - } - - switch keyMsg.String() { - case "up": - if m.selectedWM > 0 { - m.selectedWM-- - } - case "down": - if m.selectedWM < maxWMIndex { - m.selectedWM++ - } - case "enter": - m.state = StateSelectTerminal - return m, m.listenForLogs() - case "esc": - // Go back to welcome screen - m.state = StateWelcome - return m, m.listenForLogs() - } - } - return m, m.listenForLogs() -} - -func (m Model) detectDependencies() tea.Cmd { - return func() tea.Msg { - if m.osInfo == nil { - return depsDetectedMsg{deps: nil, err: fmt.Errorf("OS info not available")} - } - - detector, err := distros.NewDependencyDetector(m.osInfo.Distribution.ID, m.logChan) - if err != nil { - return depsDetectedMsg{deps: nil, err: err} - } - - // Convert TUI selection to deps enum - var wm deps.WindowManager - if m.selectedWM == 0 { - wm = deps.WindowManagerNiri // First option is Niri - } else { - wm = deps.WindowManagerHyprland // Second option is Hyprland - } - - var terminal deps.Terminal - if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" { - switch m.selectedTerminal { - case 0: - terminal = deps.TerminalKitty - case 1: - terminal = deps.TerminalAlacritty - default: - terminal = deps.TerminalKitty - } - } else { - switch m.selectedTerminal { - case 0: - terminal = deps.TerminalGhostty - case 1: - terminal = deps.TerminalKitty - default: - terminal = deps.TerminalAlacritty - } - } - - dependencies, err := detector.DetectDependenciesWithTerminal(context.Background(), wm, terminal) - return depsDetectedMsg{deps: dependencies, err: err} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go deleted file mode 100644 index c5ae862..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go +++ /dev/null @@ -1,216 +0,0 @@ -package tui - -import ( - "fmt" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/distros" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -func (m Model) viewWelcome() string { - var b strings.Builder - - b.WriteString(m.renderBanner()) - b.WriteString("\n") - - theme := TerminalTheme() - - decorator := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)). - Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") - - titleBox := lipgloss.NewStyle(). - Border(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color(theme.Primary)). - Padding(0, 2). - MarginBottom(1) - - titleText := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - Render("dankinstall") - - versionTag := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)). - Italic(true). - Render(" // Dank Linux Installer") - - subtitle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Subtle)). - Italic(true). - Render("Quickstart for a Dank Desktop") - - b.WriteString(decorator) - b.WriteString("\n") - b.WriteString(titleBox.Render(titleText + versionTag)) - b.WriteString("\n") - b.WriteString(subtitle) - b.WriteString("\n\n") - - if m.osInfo != nil { - if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) { - errorBox := lipgloss.NewStyle(). - Border(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#FF6B6B")). - Padding(1, 2). - MarginBottom(1) - - errorTitle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FF6B6B")). - Bold(true). - Render("⚠ UNSUPPORTED DISTRIBUTION") - - var errorMsg string - switch m.osInfo.Distribution.ID { - case "ubuntu": - errorMsg = fmt.Sprintf("Ubuntu %s is not supported.\n\nOnly Ubuntu 25.04+ is supported.\n\nPlease upgrade to Ubuntu 25.04 or later.", m.osInfo.VersionID) - case "debian": - errorMsg = fmt.Sprintf("Debian %s is not supported.\n\nOnly Debian 13+ (Trixie) is supported.\n\nPlease upgrade to Debian 13 or later.", m.osInfo.VersionID) - case "nixos": - errorMsg = "See the NixOS documentation for installation instructions: https://danklinux.com/docs/dankmaterialshell/nixos." - default: - errorMsg = fmt.Sprintf("%s is not supported.\nFeel free to request on https://github.com/AvengeMedia/DankMaterialShell", m.osInfo.PrettyName) - } - - errorMsgStyled := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Text)). - Render(errorMsg) - - b.WriteString(errorBox.Render(errorTitle + "\n\n" + errorMsgStyled)) - b.WriteString("\n\n") - } else { - // System info box - sysBox := lipgloss.NewStyle(). - Border(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color(theme.Subtle)). - Padding(0, 1). - MarginBottom(1) - - // Style the distro name with its color - distroStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(m.osInfo.Distribution.HexColorCode)). - Bold(true) - distroName := distroStyle.Render(m.osInfo.PrettyName) - - archStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)) - - sysInfo := fmt.Sprintf("System: %s / %s", distroName, archStyle.Render(m.osInfo.Architecture)) - b.WriteString(sysBox.Render(sysInfo)) - b.WriteString("\n") - - // Feature list with better styling - featTitle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - Underline(true). - Render("WHAT YOU GET") - b.WriteString(featTitle + "\n\n") - - features := []string{ - "[shell] dms (DankMaterialShell)", - "[wm] niri or Hyprland", - "[term] Ghostty, kitty, or Alacritty", - "[style] All the themes, automatically.", - "[config] DANK defaults - keybindings, rules, animations, etc.", - } - - for i, feat := range features { - prefix := feat[:9] - content := feat[10:] - - prefixStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Accent)). - Bold(true) - - contentStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Text)) - - if i == len(features)-1 { - contentStyle = contentStyle.Bold(true) - } - - fmt.Fprintf(&b, " %s %s\n", - prefixStyle.Render(prefix), - contentStyle.Render(content)) - } - - b.WriteString("\n") - - noteStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Subtle)). - Italic(true) - note := noteStyle.Render("* Existing configs can be replaced (and backed up) or preserved") - b.WriteString(note) - b.WriteString("\n") - - if m.osInfo.Distribution.ID == "gentoo" { - gentooNote := noteStyle.Render("* Will set per-package USE flags and unmask testing packages as needed") - b.WriteString(gentooNote) - b.WriteString("\n") - } - - b.WriteString("\n") - } - - } else if m.isLoading { - spinner := m.spinner.View() - loading := m.styles.Normal.Render("Detecting system...") - fmt.Fprintf(&b, "%s %s\n\n", spinner, loading) - } - - // Footer with better visual separation - footerDivider := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Subtle)). - Render("───────────────────────────────────────────────────────────") - b.WriteString(footerDivider + "\n") - - if m.osInfo != nil { - ctrlKey := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - Render("Ctrl+C") - - if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) { - b.WriteString(m.styles.Subtle.Render("Press ") + ctrlKey + m.styles.Subtle.Render(" to quit")) - } else { - enterKey := lipgloss.NewStyle(). - Foreground(lipgloss.Color(theme.Primary)). - Bold(true). - Render("Enter") - - b.WriteString(m.styles.Subtle.Render("Press ") + enterKey + m.styles.Subtle.Render(" to choose window manager, ") + ctrlKey + m.styles.Subtle.Render(" to quit")) - } - } else { - help := m.styles.Subtle.Render("Press Enter to continue, Ctrl+C to quit") - b.WriteString(help) - } - - return b.String() -} - -func (m Model) updateWelcomeState(msg tea.Msg) (tea.Model, tea.Cmd) { - if completeMsg, ok := msg.(osInfoCompleteMsg); ok { - m.isLoading = false - if completeMsg.err != nil { - m.err = completeMsg.err - m.state = StateError - } else { - m.osInfo = completeMsg.info - } - return m, m.listenForLogs() - } - - if keyMsg, ok := msg.(tea.KeyMsg); ok { - switch keyMsg.String() { - case "enter": - if m.osInfo != nil && !distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) { - m.state = StateSelectWindowManager - return m, m.listenForLogs() - } - } - } - return m, m.listenForLogs() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/dbus.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/dbus.go deleted file mode 100644 index bafd51f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/dbus.go +++ /dev/null @@ -1,37 +0,0 @@ -package utils - -import ( - "slices" - - "github.com/godbus/dbus/v5" -) - -func IsDBusServiceAvailable(busName string) bool { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return false - } - defer conn.Close() - - obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") - var owned bool - if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, busName).Store(&owned); err != nil { - return false - } - return owned -} - -func IsDBusServiceActivatable(busName string) bool { - conn, err := dbus.ConnectSystemBus() - if err != nil { - return false - } - defer conn.Close() - - obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") - var activatable []string - if err := obj.Call("org.freedesktop.DBus.ListActivatableNames", 0).Store(&activatable); err != nil { - return false - } - return slices.Contains(activatable, busName) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/exec.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/exec.go deleted file mode 100644 index aa1eb31..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/exec.go +++ /dev/null @@ -1,44 +0,0 @@ -package utils - -import ( - "os/exec" -) - -type AppChecker interface { - CommandExists(cmd string) bool - AnyCommandExists(cmds ...string) bool - FlatpakExists(name string) bool - AnyFlatpakExists(flatpaks ...string) bool -} - -type DefaultAppChecker struct{} - -func (DefaultAppChecker) CommandExists(cmd string) bool { - return CommandExists(cmd) -} - -func (DefaultAppChecker) AnyCommandExists(cmds ...string) bool { - return AnyCommandExists(cmds...) -} - -func (DefaultAppChecker) FlatpakExists(name string) bool { - return FlatpakExists(name) -} - -func (DefaultAppChecker) AnyFlatpakExists(flatpaks ...string) bool { - return AnyFlatpakExists(flatpaks...) -} - -func CommandExists(cmd string) bool { - _, err := exec.LookPath(cmd) - return err == nil -} - -func AnyCommandExists(cmds ...string) bool { - for _, cmd := range cmds { - if CommandExists(cmd) { - return true - } - } - return false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak.go deleted file mode 100644 index f1c9009..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak.go +++ /dev/null @@ -1,83 +0,0 @@ -package utils - -import ( - "bytes" - "errors" - "os/exec" - "slices" - "strings" -) - -func FlatpakInPath() bool { - _, err := exec.LookPath("flatpak") - return err == nil -} - -func FlatpakExists(name string) bool { - if !FlatpakInPath() { - return false - } - - cmd := exec.Command("flatpak", "info", name) - err := cmd.Run() - return err == nil -} - -func FlatpakSearchBySubstring(substring string) bool { - if !FlatpakInPath() { - return false - } - - cmd := exec.Command("flatpak", "list", "--app") - var stdout bytes.Buffer - cmd.Stdout = &stdout - - if err := cmd.Run(); err != nil { - return false - } - - out := stdout.String() - - for line := range strings.SplitSeq(out, "\n") { - fields := strings.Fields(line) - if len(fields) > 1 { - id := fields[1] - idParts := strings.Split(id, ".") - // We are assuming that the last part of the ID is - // the package name we're looking for. This might - // not always be true, some developers use arbitrary - // suffixes. - if len(idParts) > 0 && idParts[len(idParts)-1] == substring { - cmd := exec.Command("flatpak", "info", id) - err := cmd.Run() - return err == nil - } - } - } - return false -} - -func AnyFlatpakExists(flatpaks ...string) bool { - return slices.ContainsFunc(flatpaks, FlatpakExists) -} - -func FlatpakInstallationDir(name string) (string, error) { - if !FlatpakInPath() { - return "", errors.New("flatpak not found in PATH") - } - - cmd := exec.Command("flatpak", "info", "--show-location", name) - var stdout bytes.Buffer - cmd.Stdout = &stdout - - if err := cmd.Run(); err != nil { - return "", errors.New("flatpak not installed: " + name) - } - - location := strings.TrimSpace(stdout.String()) - if location == "" { - return "", errors.New("installation directory not found for: " + name) - } - - return location, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go deleted file mode 100644 index 97282ae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go +++ /dev/null @@ -1,271 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" - "strings" - "testing" -) - -func TestFlatpakInPathAvailable(t *testing.T) { - result := FlatpakInPath() - if !result { - t.Skip("flatpak not in PATH") - } - if !result { - t.Errorf("expected true when flatpak is in PATH") - } -} - -func TestFlatpakInPathUnavailable(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("PATH", tempDir) - - result := FlatpakInPath() - if result { - t.Errorf("expected false when flatpak not in PATH, got true") - } -} - -func TestFlatpakExistsValidPackage(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - result := FlatpakExists("com.nonexistent.package.test") - if result { - t.Logf("package exists (unexpected but not an error)") - } -} - -func TestFlatpakExistsNoFlatpak(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("PATH", tempDir) - - result := FlatpakExists("any.package.name") - if result { - t.Errorf("expected false when flatpak not in PATH, got true") - } -} - -func TestFlatpakSearchBySubstringNoFlatpak(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("PATH", tempDir) - - result := FlatpakSearchBySubstring("test") - if result { - t.Errorf("expected false when flatpak not in PATH, got true") - } -} - -func TestFlatpakSearchBySubstringNonexistent(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - result := FlatpakSearchBySubstring("ThisIsAVeryUnlikelyPackageName12345") - if result { - t.Errorf("expected false for nonexistent package substring") - } -} - -func TestFlatpakInstallationDirNoFlatpak(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("PATH", tempDir) - - _, err := FlatpakInstallationDir("any.package.name") - if err == nil { - t.Errorf("expected error when flatpak not in PATH") - } - if err != nil && !strings.Contains(err.Error(), "not found in PATH") { - t.Errorf("expected 'not found in PATH' error, got: %v", err) - } -} - -func TestFlatpakInstallationDirNonexistent(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - _, err := FlatpakInstallationDir("com.nonexistent.package.test") - if err == nil { - t.Errorf("expected error for nonexistent package") - } - if err != nil && !strings.Contains(err.Error(), "not installed") { - t.Errorf("expected 'not installed' error, got: %v", err) - } -} - -func TestFlatpakInstallationDirValid(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - // This test requires a known installed flatpak - // We can't guarantee any specific flatpak is installed, - // so we'll skip if we can't find a common one - commonFlatpaks := []string{ - "org.mozilla.firefox", - "org.gnome.Calculator", - "org.freedesktop.Platform", - } - - var testPackage string - for _, pkg := range commonFlatpaks { - if FlatpakExists(pkg) { - testPackage = pkg - break - } - } - - if testPackage == "" { - t.Skip("no common flatpak packages found for testing") - } - - result, err := FlatpakInstallationDir(testPackage) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if result == "" { - t.Errorf("expected non-empty installation directory") - } - if !strings.Contains(result, testPackage) { - t.Logf("installation directory %s doesn't contain package name (may be expected)", result) - } -} - -func TestFlatpakExistsCommandFailure(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - // Mock a failing flatpak command through PATH interception - tempDir := t.TempDir() - fakeFlatpak := filepath.Join(tempDir, "flatpak") - - script := "#!/bin/sh\nexit 1\n" - err := os.WriteFile(fakeFlatpak, []byte(script), 0o755) - if err != nil { - t.Fatalf("failed to create fake flatpak: %v", err) - } - - originalPath := os.Getenv("PATH") - t.Setenv("PATH", tempDir+":"+originalPath) - - result := FlatpakExists("test.package") - if result { - t.Errorf("expected false when flatpak command fails, got true") - } -} - -func TestFlatpakSearchBySubstringCommandFailure(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - // Mock a failing flatpak command through PATH interception - tempDir := t.TempDir() - fakeFlatpak := filepath.Join(tempDir, "flatpak") - - script := "#!/bin/sh\nexit 1\n" - err := os.WriteFile(fakeFlatpak, []byte(script), 0o755) - if err != nil { - t.Fatalf("failed to create fake flatpak: %v", err) - } - - originalPath := os.Getenv("PATH") - t.Setenv("PATH", tempDir+":"+originalPath) - - result := FlatpakSearchBySubstring("test") - if result { - t.Errorf("expected false when flatpak command fails, got true") - } -} - -func TestFlatpakInstallationDirCommandFailure(t *testing.T) { - if !FlatpakInPath() { - t.Skip("flatpak not in PATH") - } - - // Mock a failing flatpak command through PATH interception - tempDir := t.TempDir() - fakeFlatpak := filepath.Join(tempDir, "flatpak") - - script := "#!/bin/sh\nexit 1\n" - err := os.WriteFile(fakeFlatpak, []byte(script), 0o755) - if err != nil { - t.Fatalf("failed to create fake flatpak: %v", err) - } - - originalPath := os.Getenv("PATH") - t.Setenv("PATH", tempDir+":"+originalPath) - - _, err = FlatpakInstallationDir("test.package") - if err == nil { - t.Errorf("expected error when flatpak command fails") - } - if err != nil && !strings.Contains(err.Error(), "not installed") { - t.Errorf("expected 'not installed' error, got: %v", err) - } -} - -func TestAnyFlatpakExistsSomeExist(t *testing.T) { - tempDir := t.TempDir() - fakeFlatpak := filepath.Join(tempDir, "flatpak") - - // Script that succeeds only for "app.exists.test" - script := `#!/bin/sh -if [ "$1" = "info" ] && [ "$2" = "app.exists.test" ]; then - exit 0 -fi -exit 1 -` - err := os.WriteFile(fakeFlatpak, []byte(script), 0o755) - if err != nil { - t.Fatalf("failed to create fake flatpak: %v", err) - } - - originalPath := os.Getenv("PATH") - t.Setenv("PATH", tempDir+":"+originalPath) - - result := AnyFlatpakExists("com.nonexistent.flatpak", "app.exists.test", "com.another.nonexistent") - if !result { - t.Errorf("expected true when at least one flatpak exists") - } -} - -func TestAnyFlatpakExistsNoneExist(t *testing.T) { - tempDir := t.TempDir() - fakeFlatpak := filepath.Join(tempDir, "flatpak") - - script := "#!/bin/sh\nexit 1\n" - err := os.WriteFile(fakeFlatpak, []byte(script), 0o755) - if err != nil { - t.Fatalf("failed to create fake flatpak: %v", err) - } - - originalPath := os.Getenv("PATH") - t.Setenv("PATH", tempDir+":"+originalPath) - - result := AnyFlatpakExists("com.nonexistent.flatpak1", "com.nonexistent.flatpak2") - if result { - t.Errorf("expected false when no flatpaks exist") - } -} - -func TestAnyFlatpakExistsNoFlatpak(t *testing.T) { - tempDir := t.TempDir() - t.Setenv("PATH", tempDir) - - result := AnyFlatpakExists("any.package.name", "another.package") - if result { - t.Errorf("expected false when flatpak not in PATH, got true") - } -} - -func TestAnyFlatpakExistsEmpty(t *testing.T) { - result := AnyFlatpakExists() - if result { - t.Errorf("expected false when no flatpaks specified") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group.go deleted file mode 100644 index 1a0a950..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group.go +++ /dev/null @@ -1,37 +0,0 @@ -package utils - -import ( - "os" - "strings" -) - -func HasGroup(groupName string) bool { - return HasGroupIn(groupName, "/etc/group") -} - -func HasGroupIn(groupName, path string) bool { - data, err := os.ReadFile(path) - if err != nil { - return false - } - return HasGroupData(groupName, string(data)) -} - -func HasGroupData(groupName, data string) bool { - prefix := groupName + ":" - for line := range strings.SplitSeq(data, "\n") { - if strings.HasPrefix(line, prefix) { - return true - } - } - return false -} - -func FindGroupData(data string, candidates ...string) (string, bool) { - for _, candidate := range candidates { - if HasGroupData(candidate, data) { - return candidate, true - } - } - return "", false -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group_test.go deleted file mode 100644 index 4b401dc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/group_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package utils - -import "testing" - -const testGroupData = `root:x:0:brltty,root -sys:x:3:bin,testuser -mem:x:8: -ftp:x:11: -mail:x:12: -log:x:19: -smmsp:x:25: -proc:x:26: -games:x:50: -lock:x:54: -network:x:90: -floppy:x:94: -scanner:x:96: -power:x:98: -nobody:x:65534: -adm:x:999:daemon -wheel:x:998:testuser -utmp:x:997: -audio:x:996:brltty -disk:x:995: -input:x:994:brltty,testuser,greeter -kmem:x:993: -kvm:x:992:libvirt-qemu,qemu,testuser -lp:x:991:cups,testuser -optical:x:990: -render:x:989: -sgx:x:988: -storage:x:987: -tty:x:5:brltty -uucp:x:986:brltty -video:x:985:cosmic-greeter,greeter,testuser -users:x:984: -groups:x:983: -systemd-journal:x:982: -rfkill:x:981: -bin:x:1:daemon -daemon:x:2:bin -http:x:33: -dbus:x:81: -systemd-coredump:x:980: -systemd-network:x:979: -systemd-oom:x:978: -systemd-journal-remote:x:977: -systemd-resolve:x:976: -systemd-timesync:x:975: -tss:x:974: -uuidd:x:973: -alpm:x:972: -polkitd:x:102: -testuser:x:1000: -avahi:x:971: -git:x:970: -nvidia-persistenced:x:143: -i2c:x:969:testuser -seat:x:968: -rtkit:x:133: -brlapi:x:967:brltty -gdm:x:120: -brltty:x:966: -colord:x:965: -flatpak:x:964: -geoclue:x:963:testuser -gnome-remote-desktop:x:962: -saned:x:961: -usbmux:x:140: -cosmic-greeter:x:960: -greeter:x:959:testuser -openvpn:x:958: -nm-openvpn:x:957: -named:x:40: -_talkd:x:956: -keyd:x:955: -cups:x:209:testuser -docker:x:954:testuser -mysql:x:953: -radicale:x:952: -onepassword:x:1001: -nixbld:x:951:nixbld01,nixbld02,nixbld03,nixbld04,nixbld05,nixbld06,nixbld07,nixbld08,nixbld09,nixbld10 -virtlogin:x:940: -libvirt:x:939:testuser -libvirt-qemu:x:938: -qemu:x:937: -dnsmasq:x:936: -clock:x:935: -dms-greeter:x:1002:greeter,testuser -pcscd:x:934: -test:x:1003: -empower:x:933: -` - -func TestHasGroupData(t *testing.T) { - tests := []struct { - group string - want bool - }{ - {"greeter", true}, - {"root", true}, - {"docker", true}, - {"cosmic-greeter", true}, - {"dms-greeter", true}, - {"nonexistent", false}, - {"greet", false}, - } - - for _, tt := range tests { - if got := HasGroupData(tt.group, testGroupData); got != tt.want { - t.Errorf("HasGroupData(%q) = %v, want %v", tt.group, got, tt.want) - } - } -} - -func TestFindGroupData(t *testing.T) { - tests := []struct { - name string - candidates []string - wantGroup string - wantFound bool - }{ - {"first match wins", []string{"greeter", "greetd", "_greeter"}, "greeter", true}, - {"fallback to second", []string{"greetd", "greeter"}, "greeter", true}, - {"none found", []string{"_greetd", "greetd"}, "", false}, - {"single match", []string{"docker"}, "docker", true}, - } - - for _, tt := range tests { - got, found := FindGroupData(testGroupData, tt.candidates...) - if got != tt.wantGroup || found != tt.wantFound { - t.Errorf("%s: FindGroupData(%v) = (%q, %v), want (%q, %v)", - tt.name, tt.candidates, got, found, tt.wantGroup, tt.wantFound) - } - } -} - -func TestHasGroupDataEmpty(t *testing.T) { - if HasGroupData("greeter", "") { - t.Error("expected false for empty data") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/gsettings.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/gsettings.go deleted file mode 100644 index cc8d084..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/gsettings.go +++ /dev/null @@ -1,31 +0,0 @@ -package utils - -import ( - "fmt" - "os/exec" - "strings" -) - -func dconfPath(schema, key string) string { - return "/" + strings.ReplaceAll(schema, ".", "/") + "/" + key -} - -// GsettingsGet reads a gsettings value, falling back to dconf read. -func GsettingsGet(schema, key string) (string, error) { - if out, err := exec.Command("gsettings", "get", schema, key).Output(); err == nil { - return strings.TrimSpace(string(out)), nil - } - out, err := exec.Command("dconf", "read", dconfPath(schema, key)).Output() - if err != nil { - return "", fmt.Errorf("gsettings/dconf get failed for %s %s: %w", schema, key, err) - } - return strings.TrimSpace(string(out)), nil -} - -// GsettingsSet writes a gsettings value, falling back to dconf write. -func GsettingsSet(schema, key, value string) error { - if err := exec.Command("gsettings", "set", schema, key, value).Run(); err == nil { - return nil - } - return exec.Command("dconf", "write", dconfPath(schema, key), "'"+value+"'").Run() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/math.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/math.go deleted file mode 100644 index 408af9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/math.go +++ /dev/null @@ -1,13 +0,0 @@ -package utils - -import "golang.org/x/exp/constraints" - -func Clamp[T constraints.Ordered](val, min, max T) T { - if val < min { - return min - } - if val > max { - return max - } - return val -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths.go deleted file mode 100644 index 053097e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths.go +++ /dev/null @@ -1,70 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" - "strings" -) - -func XDGStateHome() string { - if dir := os.Getenv("XDG_STATE_HOME"); dir != "" { - return dir - } - home, _ := os.UserHomeDir() - return filepath.Join(home, ".local", "state") -} - -func XDGDataHome() string { - if dir := os.Getenv("XDG_DATA_HOME"); dir != "" { - return dir - } - home, _ := os.UserHomeDir() - return filepath.Join(home, ".local", "share") -} - -func XDGCacheHome() string { - if dir, err := os.UserCacheDir(); err == nil { - return dir - } - home, _ := os.UserHomeDir() - return filepath.Join(home, ".cache") -} - -func XDGConfigHome() string { - if dir, err := os.UserConfigDir(); err == nil { - return dir - } - home, _ := os.UserHomeDir() - return filepath.Join(home, ".config") -} - -func EmacsConfigDir() string { - home, _ := os.UserHomeDir() - - emacsD := filepath.Join(home, ".emacs.d") - if info, err := os.Stat(emacsD); err == nil && info.IsDir() { - return emacsD - } - - xdgEmacs := filepath.Join(XDGConfigHome(), "emacs") - if info, err := os.Stat(xdgEmacs); err == nil && info.IsDir() { - return xdgEmacs - } - - return "" -} - -func ExpandPath(path string) (string, error) { - expanded := os.ExpandEnv(path) - expanded = filepath.Clean(expanded) - - if strings.HasPrefix(expanded, "~") { - home, err := os.UserHomeDir() - if err != nil { - return "", err - } - expanded = filepath.Join(home, expanded[1:]) - } - - return expanded, nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths_test.go deleted file mode 100644 index 964f2a7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/paths_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" - "testing" -) - -func TestExpandPathTilde(t *testing.T) { - home, err := os.UserHomeDir() - if err != nil { - t.Skip("no home directory") - } - result, err := ExpandPath("~/test") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - expected := filepath.Join(home, "test") - if result != expected { - t.Errorf("expected %s, got %s", expected, result) - } -} - -func TestExpandPathEnvVar(t *testing.T) { - t.Setenv("TEST_PATH_VAR", "/custom/path") - result, err := ExpandPath("$TEST_PATH_VAR/subdir") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if result != "/custom/path/subdir" { - t.Errorf("expected /custom/path/subdir, got %s", result) - } -} - -func TestExpandPathAbsolute(t *testing.T) { - result, err := ExpandPath("/absolute/path") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if result != "/absolute/path" { - t.Errorf("expected /absolute/path, got %s", result) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices.go deleted file mode 100644 index b636ddc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices.go +++ /dev/null @@ -1,56 +0,0 @@ -package utils - -func Filter[T any](items []T, predicate func(T) bool) []T { - var result []T - for _, item := range items { - if predicate(item) { - result = append(result, item) - } - } - return result -} - -func Find[T any](items []T, predicate func(T) bool) (T, bool) { - for _, item := range items { - if predicate(item) { - return item, true - } - } - var zero T - return zero, false -} - -func Map[T, U any](items []T, transform func(T) U) []U { - result := make([]U, len(items)) - for i, item := range items { - result[i] = transform(item) - } - return result -} - -func Contains[T comparable](items []T, target T) bool { - for _, item := range items { - if item == target { - return true - } - } - return false -} - -func Any[T any](items []T, predicate func(T) bool) bool { - for _, item := range items { - if predicate(item) { - return true - } - } - return false -} - -func All[T any](items []T, predicate func(T) bool) bool { - for _, item := range items { - if !predicate(item) { - return false - } - } - return true -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices_test.go deleted file mode 100644 index 8edcee5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/utils/slices_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package utils - -import ( - "testing" -) - -func TestFilter(t *testing.T) { - nums := []int{1, 2, 3, 4, 5} - evens := Filter(nums, func(n int) bool { return n%2 == 0 }) - if len(evens) != 2 || evens[0] != 2 || evens[1] != 4 { - t.Errorf("expected [2, 4], got %v", evens) - } -} - -func TestFilterEmpty(t *testing.T) { - result := Filter([]int{1, 2, 3}, func(n int) bool { return n > 10 }) - if len(result) != 0 { - t.Errorf("expected empty slice, got %v", result) - } -} - -func TestFind(t *testing.T) { - nums := []int{1, 2, 3, 4, 5} - val, found := Find(nums, func(n int) bool { return n == 3 }) - if !found || val != 3 { - t.Errorf("expected 3, got %v (found=%v)", val, found) - } -} - -func TestFindNotFound(t *testing.T) { - nums := []int{1, 2, 3} - val, found := Find(nums, func(n int) bool { return n == 99 }) - if found || val != 0 { - t.Errorf("expected zero value not found, got %v (found=%v)", val, found) - } -} - -func TestMap(t *testing.T) { - nums := []int{1, 2, 3} - doubled := Map(nums, func(n int) int { return n * 2 }) - if len(doubled) != 3 || doubled[0] != 2 || doubled[1] != 4 || doubled[2] != 6 { - t.Errorf("expected [2, 4, 6], got %v", doubled) - } -} - -func TestMapTypeConversion(t *testing.T) { - nums := []int{1, 2, 3} - strs := Map(nums, func(n int) string { return string(rune('a' + n - 1)) }) - if strs[0] != "a" || strs[1] != "b" || strs[2] != "c" { - t.Errorf("expected [a, b, c], got %v", strs) - } -} - -func TestContains(t *testing.T) { - nums := []int{1, 2, 3} - if !Contains(nums, 2) { - t.Error("expected to contain 2") - } - if Contains(nums, 99) { - t.Error("expected not to contain 99") - } -} - -func TestAny(t *testing.T) { - nums := []int{1, 2, 3, 4, 5} - if !Any(nums, func(n int) bool { return n > 4 }) { - t.Error("expected any > 4") - } - if Any(nums, func(n int) bool { return n > 10 }) { - t.Error("expected none > 10") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version.go deleted file mode 100644 index db8636e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version.go +++ /dev/null @@ -1,268 +0,0 @@ -package version - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" -) - -type VersionInfo struct { - Current string - Latest string - IsGit bool - IsBranch bool - IsTag bool - HasUpdate bool -} - -// VersionFetcher is an interface for fetching version information -type VersionFetcher interface { - GetCurrentVersion(dmsPath string) (string, error) - GetLatestVersion(dmsPath string) (string, error) -} - -// DefaultVersionFetcher is the default implementation that uses git/curl -type DefaultVersionFetcher struct{} - -func (d *DefaultVersionFetcher) GetCurrentVersion(dmsPath string) (string, error) { - if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil { - originalDir, err := os.Getwd() - if err != nil { - return "", err - } - defer func() { - if err := os.Chdir(originalDir); err != nil { - log.Warnf("failed to change back to original directory: %v", err) - } - }() - - if err := os.Chdir(dmsPath); err != nil { - return "", fmt.Errorf("failed to change to DMS directory: %w", err) - } - - tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD") - if tagOutput, err := tagCmd.Output(); err == nil { - return strings.TrimSpace(string(tagOutput)), nil - } - - branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") - if branchOutput, err := branchCmd.Output(); err == nil { - branch := strings.TrimSpace(string(branchOutput)) - revCmd := exec.Command("git", "rev-parse", "--short", "HEAD") - if revOutput, err := revCmd.Output(); err == nil { - rev := strings.TrimSpace(string(revOutput)) - return fmt.Sprintf("%s@%s", branch, rev), nil - } - return branch, nil - } - } - - cmd := exec.Command("dms", "--version") - if output, err := cmd.Output(); err == nil { - return strings.TrimSpace(string(output)), nil - } - - return "unknown", nil -} - -func (d *DefaultVersionFetcher) GetLatestVersion(dmsPath string) (string, error) { - if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil { - originalDir, err := os.Getwd() - if err != nil { - return "", err - } - defer func() { - if err := os.Chdir(originalDir); err != nil { - log.Warnf("failed to change back to original directory: %v", err) - } - }() - - if err := os.Chdir(dmsPath); err != nil { - return "", fmt.Errorf("failed to change to DMS directory: %w", err) - } - - currentRefCmd := exec.Command("git", "symbolic-ref", "-q", "HEAD") - currentRefOutput, _ := currentRefCmd.Output() - onBranch := len(currentRefOutput) > 0 - - if !onBranch { - tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD") - if _, err := tagCmd.Output(); err == nil { - // Add timeout to git fetch to prevent hanging - fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", "--tags", "--quiet") - if err := fetchCmd.Run(); err != nil { - log.Debugf("git fetch tags failed (continuing with local tags): %v", err) - } - - latestTagCmd := exec.Command("git", "tag", "-l", "v*", "--sort=-version:refname") - latestTagOutput, err := latestTagCmd.Output() - if err != nil { - return "", fmt.Errorf("failed to get latest tag: %w", err) - } - - tags := strings.Split(strings.TrimSpace(string(latestTagOutput)), "\n") - if len(tags) == 0 || tags[0] == "" { - return "", fmt.Errorf("no version tags found") - } - return tags[0], nil - } - } else { - branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") - branchOutput, err := branchCmd.Output() - if err != nil { - return "", fmt.Errorf("failed to get current branch: %w", err) - } - currentBranch := strings.TrimSpace(string(branchOutput)) - - // Add timeout to git fetch to prevent hanging - fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", currentBranch, "--quiet") - if err := fetchCmd.Run(); err != nil { - log.Debugf("git fetch branch failed (continuing with local ref): %v", err) - } - - remoteRevCmd := exec.Command("git", "rev-parse", "--short", fmt.Sprintf("origin/%s", currentBranch)) - remoteRevOutput, err := remoteRevCmd.Output() - if err != nil { - return "", fmt.Errorf("failed to get remote revision: %w", err) - } - remoteRev := strings.TrimSpace(string(remoteRevOutput)) - return fmt.Sprintf("%s@%s", currentBranch, remoteRev), nil - } - } - - // Add timeout to prevent hanging when GitHub is down - cmd := exec.Command("curl", "-s", "--max-time", "5", "https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest") - output, err := cmd.Output() - if err != nil { - return "", fmt.Errorf("failed to fetch latest release: %w", err) - } - - var result struct { - TagName string `json:"tag_name"` - } - if err := json.Unmarshal(output, &result); err != nil { - for _, line := range strings.Split(string(output), "\n") { - if strings.Contains(line, "\"tag_name\"") { - parts := strings.Split(line, "\"") - if len(parts) >= 4 { - return parts[3], nil - } - } - } - return "", fmt.Errorf("failed to parse latest version: %w", err) - } - - return result.TagName, nil -} - -// defaultFetcher is used by the public functions -var defaultFetcher VersionFetcher = &DefaultVersionFetcher{} - -func GetCurrentDMSVersion() (string, error) { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("failed to get home directory: %w", err) - } - - dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms") - if _, err := os.Stat(dmsPath); os.IsNotExist(err) { - return "", fmt.Errorf("DMS not installed") - } - - return defaultFetcher.GetCurrentVersion(dmsPath) -} - -func GetLatestDMSVersion() (string, error) { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("failed to get home directory: %w", err) - } - - dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms") - return defaultFetcher.GetLatestVersion(dmsPath) -} - -func GetDMSVersionInfo() (*VersionInfo, error) { - return GetDMSVersionInfoWithFetcher(defaultFetcher) -} - -func GetDMSVersionInfoWithFetcher(fetcher VersionFetcher) (*VersionInfo, error) { - homeDir, err := os.UserHomeDir() - if err != nil { - return nil, fmt.Errorf("failed to get home directory: %w", err) - } - - dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms") - if _, err := os.Stat(dmsPath); os.IsNotExist(err) { - return nil, fmt.Errorf("DMS not installed") - } - - current, err := fetcher.GetCurrentVersion(dmsPath) - if err != nil { - return nil, err - } - - latest, err := fetcher.GetLatestVersion(dmsPath) - if err != nil { - return nil, fmt.Errorf("failed to get latest version: %w", err) - } - - info := &VersionInfo{ - Current: current, - Latest: latest, - IsGit: strings.Contains(current, "@"), - IsBranch: strings.Contains(current, "@"), - IsTag: !strings.Contains(current, "@") && strings.HasPrefix(current, "v"), - } - - if info.IsBranch { - parts := strings.Split(current, "@") - latestParts := strings.Split(latest, "@") - if len(parts) == 2 && len(latestParts) == 2 { - info.HasUpdate = parts[1] != latestParts[1] - } - } else if info.IsTag { - info.HasUpdate = current != latest - } else { - info.HasUpdate = false - } - - return info, nil -} - -func CompareVersions(v1, v2 string) int { - v1 = strings.TrimPrefix(v1, "v") - v2 = strings.TrimPrefix(v2, "v") - - parts1 := strings.Split(v1, ".") - parts2 := strings.Split(v2, ".") - - maxLen := len(parts1) - if len(parts2) > maxLen { - maxLen = len(parts2) - } - - for i := 0; i < maxLen; i++ { - var p1, p2 int - if i < len(parts1) { - fmt.Sscanf(parts1[i], "%d", &p1) //nolint:errcheck - } - if i < len(parts2) { - fmt.Sscanf(parts2[i], "%d", &p2) //nolint:errcheck - } - - if p1 < p2 { - return -1 - } - if p1 > p2 { - return 1 - } - } - - return 0 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version_test.go deleted file mode 100644 index 1e424c1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/version/version_test.go +++ /dev/null @@ -1,362 +0,0 @@ -package version - -import ( - "os" - "os/exec" - "path/filepath" - "testing" - - mocks_version "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/version" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) - -func TestCompareVersions(t *testing.T) { - tests := []struct { - v1 string - v2 string - expected int - }{ - {"v0.1.0", "v0.1.0", 0}, - {"v0.1.0", "v0.1.1", -1}, - {"v0.1.1", "v0.1.0", 1}, - {"v0.1.10", "v0.1.2", 1}, - {"v0.2.0", "v0.1.9", 1}, - {"0.1.0", "0.1.0", 0}, - {"1.0.0", "v1.0.0", 0}, - {"v1.2.3", "v1.2.4", -1}, - {"v2.0.0", "v1.9.9", 1}, - } - - for _, tt := range tests { - result := CompareVersions(tt.v1, tt.v2) - if result != tt.expected { - t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected) - } - } -} - -func TestGetDMSVersionInfo_Structure(t *testing.T) { - // Create a temp directory with a fake DMS installation - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - // Create a .git directory to simulate git installation - os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - // Create mock fetcher - mockFetcher := mocks_version.NewMockVersionFetcher(t) - mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("v0.1.0", nil) - mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("v0.1.1", nil) - - info, err := GetDMSVersionInfoWithFetcher(mockFetcher) - if err != nil { - t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err) - } - - if info == nil { - t.Fatal("GetDMSVersionInfoWithFetcher() returned nil") - } - - if info.Current != "v0.1.0" { - t.Errorf("Current version = %s, expected v0.1.0", info.Current) - } - - if info.Latest != "v0.1.1" { - t.Errorf("Latest version = %s, expected v0.1.1", info.Latest) - } - - if !info.HasUpdate { - t.Error("HasUpdate should be true when current != latest") - } - - if !info.IsTag { - t.Error("IsTag should be true for v0.1.0") - } - - t.Logf("Current: %s, Latest: %s, HasUpdate: %v", info.Current, info.Latest, info.HasUpdate) -} - -func TestGetDMSVersionInfo_BranchVersion(t *testing.T) { - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - mockFetcher := mocks_version.NewMockVersionFetcher(t) - mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("master@abc1234", nil) - mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("master@def5678", nil) - - info, err := GetDMSVersionInfoWithFetcher(mockFetcher) - if err != nil { - t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err) - } - - if !info.IsBranch { - t.Error("IsBranch should be true for branch@commit format") - } - - if !info.IsGit { - t.Error("IsGit should be true for branch@commit format") - } - - if !info.HasUpdate { - t.Error("HasUpdate should be true when commits differ") - } -} - -func TestGetDMSVersionInfo_NoUpdate(t *testing.T) { - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - mockFetcher := mocks_version.NewMockVersionFetcher(t) - mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("v0.1.0", nil) - mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("v0.1.0", nil) - - info, err := GetDMSVersionInfoWithFetcher(mockFetcher) - if err != nil { - t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err) - } - - if info.HasUpdate { - t.Error("HasUpdate should be false when current == latest") - } -} - -func TestGetCurrentDMSVersion_NotInstalled(t *testing.T) { - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - - tempDir := t.TempDir() - os.Setenv("HOME", tempDir) - - _, err := GetCurrentDMSVersion() - if err == nil { - t.Error("Expected error when DMS not installed, got nil") - } -} - -func TestGetCurrentDMSVersion_GitTag(t *testing.T) { - if !utils.CommandExists("git") { - t.Skip("git not available") - } - - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - exec.Command("git", "init", dmsPath).Run() - exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run() - exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run() - - testFile := filepath.Join(dmsPath, "test.txt") - os.WriteFile(testFile, []byte("test"), 0o644) - exec.Command("git", "-C", dmsPath, "add", ".").Run() - exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run() - exec.Command("git", "-C", dmsPath, "tag", "v0.1.0").Run() - - version, err := GetCurrentDMSVersion() - if err != nil { - t.Fatalf("GetCurrentDMSVersion() failed: %v", err) - } - - if version != "v0.1.0" { - t.Errorf("Expected version v0.1.0, got %s", version) - } -} - -func TestGetCurrentDMSVersion_GitBranch(t *testing.T) { - if !utils.CommandExists("git") { - t.Skip("git not available") - } - - tempDir := t.TempDir() - dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms") - os.MkdirAll(dmsPath, 0o755) - - originalHome := os.Getenv("HOME") - defer os.Setenv("HOME", originalHome) - os.Setenv("HOME", tempDir) - - exec.Command("git", "init", dmsPath).Run() - exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run() - exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", dmsPath, "checkout", "-b", "master").Run() - - testFile := filepath.Join(dmsPath, "test.txt") - os.WriteFile(testFile, []byte("test"), 0o644) - exec.Command("git", "-C", dmsPath, "add", ".").Run() - exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run() - - version, err := GetCurrentDMSVersion() - if err != nil { - t.Fatalf("GetCurrentDMSVersion() failed: %v", err) - } - - if version == "" { - t.Error("Expected non-empty version") - } - - if len(version) < 7 { - t.Errorf("Expected version with branch@commit format, got %s", version) - } -} - -func TestVersionInfo_IsGit(t *testing.T) { - tests := []struct { - current string - isGit bool - isBranch bool - isTag bool - }{ - {"v0.1.0", false, false, true}, - {"master@abc1234", true, true, false}, - {"dev@def5678", true, true, false}, - {"v0.2.0", false, false, true}, - {"unknown", false, false, false}, - } - - for _, tt := range tests { - info := &VersionInfo{ - IsGit: tt.isGit, - IsBranch: tt.isBranch, - IsTag: tt.isTag, - } - - actualIsGit := len(tt.current) > 0 && tt.current[0] != 'v' && tt.current != "unknown" - actualIsBranch := len(tt.current) > 0 && tt.current[0] != 'v' - actualIsTag := len(tt.current) > 0 && tt.current[0] == 'v' - - if tt.current == "unknown" { - actualIsGit = false - actualIsBranch = false - actualIsTag = false - } - - if info.IsGit != tt.isGit { - t.Errorf("For %s: IsGit = %v; want %v", tt.current, info.IsGit, tt.isGit) - } - if info.IsBranch != tt.isBranch { - t.Errorf("For %s: IsBranch = %v; want %v", tt.current, info.IsBranch, tt.isBranch) - } - if info.IsTag != tt.isTag { - t.Errorf("For %s: IsTag = %v; want %v", tt.current, info.IsTag, tt.isTag) - } - - _ = actualIsGit - _ = actualIsBranch - _ = actualIsTag - } -} - -func TestVersionInfo_HasUpdate_Branch(t *testing.T) { - tests := []struct { - current string - latest string - hasUpdate bool - }{ - {"master@abc1234", "master@abc1234", false}, - {"master@abc1234", "master@def5678", true}, - {"dev@abc1234", "dev@abc1234", false}, - {"dev@old1234", "dev@new5678", true}, - } - - for _, tt := range tests { - info := &VersionInfo{ - HasUpdate: tt.hasUpdate, - } - - if info.HasUpdate != tt.hasUpdate { - t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v", - tt.current, tt.latest, info.HasUpdate, tt.hasUpdate) - } - } -} - -func TestVersionInfo_HasUpdate_Tag(t *testing.T) { - tests := []struct { - current string - latest string - hasUpdate bool - }{ - {"v0.1.0", "v0.1.0", false}, - {"v0.1.0", "v0.1.1", true}, - {"v0.1.5", "v0.1.5", false}, - {"v0.1.9", "v0.2.0", true}, - } - - for _, tt := range tests { - info := &VersionInfo{ - HasUpdate: tt.hasUpdate, - } - - if info.HasUpdate != tt.hasUpdate { - t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v", - tt.current, tt.latest, info.HasUpdate, tt.hasUpdate) - } - } -} - -func TestGetLatestDMSVersion_FallbackParsing(t *testing.T) { - jsonResponse := `{ - "tag_name": "v0.1.17", - "name": "Release v0.1.17" - }` - - lines := []string{ - ` "tag_name": "v0.1.17",`, - ` "name": "Release v0.1.17"`, - } - - for _, line := range lines { - if len(line) > 0 && line[0:15] == ` "tag_name": "` { - parts := []string{"", "", "", "v0.1.17"} - version := parts[3] - if version != "v0.1.17" { - t.Errorf("Failed to parse version from line: %s", line) - } - } - } - - _ = jsonResponse -} - -func TestCompareVersions_EdgeCases(t *testing.T) { - tests := []struct { - v1 string - v2 string - expected int - }{ - {"", "", 0}, - {"v1", "v1", 0}, - {"v1.0", "v1", 0}, - {"v1.0.0", "v1.0", 0}, - {"v1.0.1", "v1.0", 1}, - {"v1", "v1.0.1", -1}, - } - - for _, tt := range tests { - result := CompareVersions(tt.v1, tt.v2) - if result != tt.expected { - t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/client/helpers.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/client/helpers.go deleted file mode 100644 index 9075cd3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/client/helpers.go +++ /dev/null @@ -1,26 +0,0 @@ -package client - -import wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -func Roundtrip(display *wlclient.Display, ctx *wlclient.Context) error { - callback, err := display.Sync() - if err != nil { - return err - } - - done := make(chan struct{}) - callback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) { - close(done) - }) - - for { - select { - case <-done: - return nil - default: - if err := ctx.Dispatch(); err != nil { - return err - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/shm/buffer.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/shm/buffer.go deleted file mode 100644 index 9cfee20..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/wayland/shm/buffer.go +++ /dev/null @@ -1,298 +0,0 @@ -package shm - -import ( - "fmt" - - "golang.org/x/sys/unix" -) - -type PixelFormat uint32 - -const ( - FormatARGB8888 PixelFormat = 0 - FormatXRGB8888 PixelFormat = 1 - FormatABGR8888 PixelFormat = 0x34324241 - FormatXBGR8888 PixelFormat = 0x34324258 - FormatRGB888 PixelFormat = 0x34324752 - FormatBGR888 PixelFormat = 0x34324742 -) - -func (f PixelFormat) BytesPerPixel() int { - switch f { - case FormatRGB888, FormatBGR888: - return 3 - default: - return 4 - } -} - -func (f PixelFormat) Is24Bit() bool { - return f == FormatRGB888 || f == FormatBGR888 -} - -type Buffer struct { - fd int - data []byte - size int - Width int - Height int - Stride int - Format PixelFormat -} - -func CreateBuffer(width, height, stride int) (*Buffer, error) { - size := stride * height - - fd, err := unix.MemfdCreate("dms-shm", 0) - if err != nil { - return nil, fmt.Errorf("memfd_create: %w", err) - } - - if err := unix.Ftruncate(fd, int64(size)); err != nil { - unix.Close(fd) - return nil, fmt.Errorf("ftruncate: %w", err) - } - - data, err := unix.Mmap(fd, 0, size, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED) - if err != nil { - unix.Close(fd) - return nil, fmt.Errorf("mmap: %w", err) - } - - return &Buffer{ - fd: fd, - data: data, - size: size, - Width: width, - Height: height, - Stride: stride, - }, nil -} - -func (b *Buffer) Fd() int { return b.fd } -func (b *Buffer) Size() int { return b.size } -func (b *Buffer) Data() []byte { return b.data } - -func (b *Buffer) Close() error { - var firstErr error - - if b.data != nil { - if err := unix.Munmap(b.data); err != nil && firstErr == nil { - firstErr = fmt.Errorf("munmap: %w", err) - } - b.data = nil - } - - if b.fd >= 0 { - if err := unix.Close(b.fd); err != nil && firstErr == nil { - firstErr = fmt.Errorf("close: %w", err) - } - b.fd = -1 - } - - return firstErr -} - -func (b *Buffer) ConvertTo32Bit(srcFormat PixelFormat) (*Buffer, PixelFormat, error) { - if !srcFormat.Is24Bit() { - return b, srcFormat, nil - } - - dstFormat := FormatXRGB8888 - dstStride := b.Width * 4 - - dst, err := CreateBuffer(b.Width, b.Height, dstStride) - if err != nil { - return nil, srcFormat, err - } - dst.Format = dstFormat - - srcData := b.data - dstData := dst.data - - // DRM format names are counterintuitive on little-endian: - // RGB888 memory layout: B, G, R (name is logical order, not memory) - // BGR888 memory layout: R, G, B - isBGRMemory := srcFormat == FormatRGB888 - - for y := 0; y < b.Height; y++ { - srcRow := y * b.Stride - dstRow := y * dstStride - for x := 0; x < b.Width; x++ { - si := srcRow + x*3 - di := dstRow + x*4 - if isBGRMemory { - // RGB888: src memory is B,G,R -> dst XRGB8888 memory B,G,R,X - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - } else { - // BGR888: src memory is R,G,B -> dst XRGB8888 memory B,G,R,X - dstData[di+0] = srcData[si+2] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+0] - } - dstData[di+3] = 0xFF - } - } - - return dst, dstFormat, nil -} - -func (b *Buffer) GetPixelRGBA(x, y int) (r, g, b2, a uint8) { - if x < 0 || x >= b.Width || y < 0 || y >= b.Height { - return - } - - off := y*b.Stride + x*4 - if off+3 >= len(b.data) { - return - } - - switch b.Format { - case FormatXBGR8888, FormatABGR8888: - return b.data[off], b.data[off+1], b.data[off+2], 0xFF - default: - return b.data[off+2], b.data[off+1], b.data[off], 0xFF - } -} - -func (b *Buffer) GetPixelBGRA(x, y int) (b2, g, r, a uint8) { - if x < 0 || x >= b.Width || y < 0 || y >= b.Height { - return - } - - off := y*b.Stride + x*4 - if off+3 >= len(b.data) { - return - } - - return b.data[off], b.data[off+1], b.data[off+2], b.data[off+3] -} - -func (b *Buffer) ConvertBGRAtoRGBA() { - for y := 0; y < b.Height; y++ { - rowOff := y * b.Stride - for x := 0; x < b.Width; x++ { - off := rowOff + x*4 - if off+3 >= len(b.data) { - continue - } - b.data[off], b.data[off+2] = b.data[off+2], b.data[off] - } - } -} - -func (b *Buffer) FlipVertical() { - tmp := make([]byte, b.Stride) - for y := 0; y < b.Height/2; y++ { - topOff := y * b.Stride - botOff := (b.Height - 1 - y) * b.Stride - copy(tmp, b.data[topOff:topOff+b.Stride]) - copy(b.data[topOff:topOff+b.Stride], b.data[botOff:botOff+b.Stride]) - copy(b.data[botOff:botOff+b.Stride], tmp) - } -} - -func (b *Buffer) Clear() { - for i := range b.data { - b.data[i] = 0 - } -} - -func (b *Buffer) CopyFrom(src *Buffer) { - copy(b.data, src.data) -} - -const ( - TransformNormal = 0 - Transform90 = 1 - Transform180 = 2 - Transform270 = 3 - TransformFlipped = 4 - TransformFlipped90 = 5 - TransformFlipped180 = 6 - TransformFlipped270 = 7 -) - -func (b *Buffer) ApplyTransform(transform int32) (*Buffer, error) { - if transform == TransformNormal { - return b, nil - } - - var newW, newH int - switch transform { - case Transform90, Transform270, TransformFlipped90, TransformFlipped270: - newW, newH = b.Height, b.Width - default: - newW, newH = b.Width, b.Height - } - - newBuf, err := CreateBuffer(newW, newH, newW*4) - if err != nil { - return nil, err - } - newBuf.Format = b.Format - - srcData := b.data - dstData := newBuf.data - - for sy := 0; sy < b.Height; sy++ { - for sx := 0; sx < b.Width; sx++ { - var dx, dy int - - switch transform { - case Transform90: // 90° CCW - dx = sy - dy = b.Width - 1 - sx - case Transform180: - dx = b.Width - 1 - sx - dy = b.Height - 1 - sy - case Transform270: // 270° CCW = 90° CW - dx = b.Height - 1 - sy - dy = sx - case TransformFlipped: - dx = b.Width - 1 - sx - dy = sy - case TransformFlipped90: - dx = sy - dy = sx - case TransformFlipped180: - dx = sx - dy = b.Height - 1 - sy - case TransformFlipped270: - dx = b.Height - 1 - sy - dy = b.Width - 1 - sx - default: - dx, dy = sx, sy - } - - si := sy*b.Stride + sx*4 - di := dy*newBuf.Stride + dx*4 - - if si+3 < len(srcData) && di+3 < len(dstData) { - dstData[di+0] = srcData[si+0] - dstData[di+1] = srcData[si+1] - dstData[di+2] = srcData[si+2] - dstData[di+3] = srcData[si+3] - } - } - } - - return newBuf, nil -} - -func InverseTransform(transform int32) int32 { - switch transform { - case Transform90: - return Transform270 - case Transform270: - return Transform90 - case TransformFlipped90: - return TransformFlipped270 - case TransformFlipped270: - return TransformFlipped90 - default: - return transform - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser.go deleted file mode 100644 index 918c4f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser.go +++ /dev/null @@ -1,658 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" - "github.com/AvengeMedia/DankMaterialShell/core/internal/windowrules" -) - -type HyprlandWindowRule struct { - MatchClass string - MatchTitle string - MatchXWayland *bool - MatchFloating *bool - MatchFullscreen *bool - MatchPinned *bool - MatchInitialised *bool - Rule string - Value string - Source string - RawLine string -} - -type HyprlandRulesParser struct { - configDir string - processedFiles map[string]bool - rules []HyprlandWindowRule - currentSource string - dmsRulesExists bool - dmsRulesIncluded bool - includeCount int - dmsIncludePos int - rulesAfterDMS int - dmsProcessed bool -} - -func NewHyprlandRulesParser(configDir string) *HyprlandRulesParser { - return &HyprlandRulesParser{ - configDir: configDir, - processedFiles: make(map[string]bool), - rules: []HyprlandWindowRule{}, - dmsIncludePos: -1, - } -} - -func (p *HyprlandRulesParser) Parse() ([]HyprlandWindowRule, error) { - expandedDir, err := utils.ExpandPath(p.configDir) - if err != nil { - return nil, err - } - - dmsRulesPath := filepath.Join(expandedDir, "dms", "windowrules.conf") - if _, err := os.Stat(dmsRulesPath); err == nil { - p.dmsRulesExists = true - } - - mainConfig := filepath.Join(expandedDir, "hyprland.conf") - if err := p.parseFile(mainConfig); err != nil { - return nil, err - } - - if p.dmsRulesExists && !p.dmsProcessed { - p.parseDMSRulesDirectly(dmsRulesPath) - } - - return p.rules, nil -} - -func (p *HyprlandRulesParser) parseDMSRulesDirectly(dmsRulesPath string) { - data, err := os.ReadFile(dmsRulesPath) - if err != nil { - return - } - - prevSource := p.currentSource - p.currentSource = dmsRulesPath - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - p.parseLine(line) - } - - p.currentSource = prevSource - p.dmsProcessed = true -} - -func (p *HyprlandRulesParser) parseFile(filePath string) error { - absPath, err := filepath.Abs(filePath) - if err != nil { - return err - } - - if p.processedFiles[absPath] { - return nil - } - p.processedFiles[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return nil - } - - prevSource := p.currentSource - p.currentSource = absPath - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - trimmed := strings.TrimSpace(line) - - if strings.HasPrefix(trimmed, "source") { - p.handleSource(trimmed, filepath.Dir(absPath)) - continue - } - - p.parseLine(line) - } - - p.currentSource = prevSource - return nil -} - -func (p *HyprlandRulesParser) handleSource(line string, baseDir string) { - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - return - } - - sourcePath := strings.TrimSpace(parts[1]) - isDMSSource := sourcePath == "dms/windowrules.conf" || strings.HasSuffix(sourcePath, "/dms/windowrules.conf") - - p.includeCount++ - if isDMSSource { - p.dmsRulesIncluded = true - p.dmsIncludePos = p.includeCount - p.dmsProcessed = true - } - - fullPath := sourcePath - if !filepath.IsAbs(sourcePath) { - fullPath = filepath.Join(baseDir, sourcePath) - } - - expanded, err := utils.ExpandPath(fullPath) - if err != nil { - return - } - - _ = p.parseFile(expanded) -} - -func (p *HyprlandRulesParser) parseLine(line string) { - trimmed := strings.TrimSpace(line) - - if strings.HasPrefix(trimmed, "windowrule") { - rule := p.parseWindowRuleLine(trimmed) - if rule != nil { - rule.Source = p.currentSource - p.rules = append(p.rules, *rule) - } - } -} - -var windowRuleV2Regex = regexp.MustCompile(`^windowrulev?2?\s*=\s*(.+)$`) - -func (p *HyprlandRulesParser) parseWindowRuleLine(line string) *HyprlandWindowRule { - matches := windowRuleV2Regex.FindStringSubmatch(line) - if len(matches) < 2 { - return nil - } - - content := strings.TrimSpace(matches[1]) - isV2 := strings.HasPrefix(line, "windowrulev2") - - rule := &HyprlandWindowRule{ - RawLine: line, - } - - if isV2 { - p.parseWindowRuleV2(content, rule) - } else { - p.parseWindowRuleV1(content, rule) - } - - return rule -} - -func (p *HyprlandRulesParser) parseWindowRuleV1(content string, rule *HyprlandWindowRule) { - parts := strings.SplitN(content, ",", 2) - if len(parts) < 2 { - return - } - - rule.Rule = strings.TrimSpace(parts[0]) - rule.MatchClass = strings.TrimSpace(parts[1]) -} - -func (p *HyprlandRulesParser) parseWindowRuleV2(content string, rule *HyprlandWindowRule) { - parts := strings.SplitN(content, ",", 2) - if len(parts) < 2 { - return - } - - ruleAndValue := strings.TrimSpace(parts[0]) - matchPart := strings.TrimSpace(parts[1]) - - if idx := strings.Index(ruleAndValue, " "); idx > 0 { - rule.Rule = ruleAndValue[:idx] - rule.Value = strings.TrimSpace(ruleAndValue[idx+1:]) - } else { - rule.Rule = ruleAndValue - } - - matchPairs := strings.Split(matchPart, ",") - for _, pair := range matchPairs { - pair = strings.TrimSpace(pair) - if colonIdx := strings.Index(pair, ":"); colonIdx > 0 { - key := strings.TrimSpace(pair[:colonIdx]) - value := strings.TrimSpace(pair[colonIdx+1:]) - - switch key { - case "class": - rule.MatchClass = value - case "title": - rule.MatchTitle = value - case "xwayland": - b := value == "1" || value == "true" - rule.MatchXWayland = &b - case "floating": - b := value == "1" || value == "true" - rule.MatchFloating = &b - case "fullscreen": - b := value == "1" || value == "true" - rule.MatchFullscreen = &b - case "pinned": - b := value == "1" || value == "true" - rule.MatchPinned = &b - case "initialised", "initialized": - b := value == "1" || value == "true" - rule.MatchInitialised = &b - } - } - } -} - -func (p *HyprlandRulesParser) HasDMSRulesIncluded() bool { - return p.dmsRulesIncluded -} - -func (p *HyprlandRulesParser) buildDMSStatus() *windowrules.DMSRulesStatus { - status := &windowrules.DMSRulesStatus{ - Exists: p.dmsRulesExists, - Included: p.dmsRulesIncluded, - IncludePosition: p.dmsIncludePos, - TotalIncludes: p.includeCount, - RulesAfterDMS: p.rulesAfterDMS, - } - - switch { - case !p.dmsRulesExists: - status.Effective = false - status.StatusMessage = "dms/windowrules.conf does not exist" - case !p.dmsRulesIncluded: - status.Effective = false - status.StatusMessage = "dms/windowrules.conf is not sourced in config" - case p.rulesAfterDMS > 0: - status.Effective = true - status.OverriddenBy = p.rulesAfterDMS - status.StatusMessage = "Some DMS rules may be overridden by config rules" - default: - status.Effective = true - status.StatusMessage = "DMS window rules are active" - } - - return status -} - -type HyprlandRulesParseResult struct { - Rules []HyprlandWindowRule - DMSRulesIncluded bool - DMSStatus *windowrules.DMSRulesStatus -} - -func ParseHyprlandWindowRules(configDir string) (*HyprlandRulesParseResult, error) { - parser := NewHyprlandRulesParser(configDir) - rules, err := parser.Parse() - if err != nil { - return nil, err - } - return &HyprlandRulesParseResult{ - Rules: rules, - DMSRulesIncluded: parser.HasDMSRulesIncluded(), - DMSStatus: parser.buildDMSStatus(), - }, nil -} - -func applyHyprlandRuleAction(actions *windowrules.Actions, rule, value string) { - t := true - switch rule { - case "float": - actions.OpenFloating = &t - case "tile": - actions.Tile = &t - case "fullscreen": - actions.OpenFullscreen = &t - case "maximize": - actions.OpenMaximized = &t - case "nofocus": - actions.NoFocus = &t - case "noborder": - actions.NoBorder = &t - case "noshadow": - actions.NoShadow = &t - case "nodim": - actions.NoDim = &t - case "noblur": - actions.NoBlur = &t - case "noanim": - actions.NoAnim = &t - case "norounding": - actions.NoRounding = &t - case "pin": - actions.Pin = &t - case "opaque": - actions.Opaque = &t - case "forcergbx": - actions.ForcergbX = &t - case "opacity": - if f, err := strconv.ParseFloat(value, 64); err == nil { - actions.Opacity = &f - } - case "size": - actions.Size = value - case "move": - actions.Move = value - case "monitor": - actions.Monitor = value - case "workspace": - actions.Workspace = value - case "idleinhibit": - actions.Idleinhibit = value - case "rounding": - if i, err := strconv.Atoi(value); err == nil { - actions.CornerRadius = &i - } - } -} - -func ConvertHyprlandRulesToWindowRules(hyprRules []HyprlandWindowRule) []windowrules.WindowRule { - result := make([]windowrules.WindowRule, 0, len(hyprRules)) - for i, hr := range hyprRules { - wr := windowrules.WindowRule{ - ID: strconv.Itoa(i), - Enabled: true, - Source: hr.Source, - MatchCriteria: windowrules.MatchCriteria{ - AppID: hr.MatchClass, - Title: hr.MatchTitle, - XWayland: hr.MatchXWayland, - IsFloating: hr.MatchFloating, - Fullscreen: hr.MatchFullscreen, - Pinned: hr.MatchPinned, - Initialised: hr.MatchInitialised, - }, - } - applyHyprlandRuleAction(&wr.Actions, hr.Rule, hr.Value) - result = append(result, wr) - } - return result -} - -type HyprlandWritableProvider struct { - configDir string -} - -func NewHyprlandWritableProvider(configDir string) *HyprlandWritableProvider { - return &HyprlandWritableProvider{configDir: configDir} -} - -func (p *HyprlandWritableProvider) Name() string { - return "hyprland" -} - -func (p *HyprlandWritableProvider) GetOverridePath() string { - expanded, _ := utils.ExpandPath(p.configDir) - return filepath.Join(expanded, "dms", "windowrules.conf") -} - -func (p *HyprlandWritableProvider) GetRuleSet() (*windowrules.RuleSet, error) { - result, err := ParseHyprlandWindowRules(p.configDir) - if err != nil { - return nil, err - } - return &windowrules.RuleSet{ - Title: "Hyprland Window Rules", - Provider: "hyprland", - Rules: ConvertHyprlandRulesToWindowRules(result.Rules), - DMSRulesIncluded: result.DMSRulesIncluded, - DMSStatus: result.DMSStatus, - }, nil -} - -func (p *HyprlandWritableProvider) SetRule(rule windowrules.WindowRule) error { - rules, err := p.LoadDMSRules() - if err != nil { - rules = []windowrules.WindowRule{} - } - - found := false - for i, r := range rules { - if r.ID == rule.ID { - rules[i] = rule - found = true - break - } - } - if !found { - rules = append(rules, rule) - } - - return p.writeDMSRules(rules) -} - -func (p *HyprlandWritableProvider) RemoveRule(id string) error { - rules, err := p.LoadDMSRules() - if err != nil { - return err - } - - newRules := make([]windowrules.WindowRule, 0, len(rules)) - for _, r := range rules { - if r.ID != id { - newRules = append(newRules, r) - } - } - - return p.writeDMSRules(newRules) -} - -func (p *HyprlandWritableProvider) ReorderRules(ids []string) error { - rules, err := p.LoadDMSRules() - if err != nil { - return err - } - - ruleMap := make(map[string]windowrules.WindowRule) - for _, r := range rules { - ruleMap[r.ID] = r - } - - newRules := make([]windowrules.WindowRule, 0, len(ids)) - for _, id := range ids { - if r, ok := ruleMap[id]; ok { - newRules = append(newRules, r) - delete(ruleMap, id) - } - } - - for _, r := range ruleMap { - newRules = append(newRules, r) - } - - return p.writeDMSRules(newRules) -} - -var dmsRuleCommentRegex = regexp.MustCompile(`^#\s*DMS-RULE:\s*id=([^,]+),\s*name=(.*)$`) - -func (p *HyprlandWritableProvider) LoadDMSRules() ([]windowrules.WindowRule, error) { - rulesPath := p.GetOverridePath() - data, err := os.ReadFile(rulesPath) - if err != nil { - if os.IsNotExist(err) { - return []windowrules.WindowRule{}, nil - } - return nil, err - } - - var rules []windowrules.WindowRule - var currentID, currentName string - lines := strings.Split(string(data), "\n") - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - - if matches := dmsRuleCommentRegex.FindStringSubmatch(trimmed); matches != nil { - currentID = matches[1] - currentName = matches[2] - continue - } - - if strings.HasPrefix(trimmed, "windowrulev2") { - parser := NewHyprlandRulesParser(p.configDir) - hrule := parser.parseWindowRuleLine(trimmed) - if hrule == nil { - continue - } - - wr := windowrules.WindowRule{ - ID: currentID, - Name: currentName, - Enabled: true, - Source: rulesPath, - MatchCriteria: windowrules.MatchCriteria{ - AppID: hrule.MatchClass, - Title: hrule.MatchTitle, - XWayland: hrule.MatchXWayland, - IsFloating: hrule.MatchFloating, - Fullscreen: hrule.MatchFullscreen, - Pinned: hrule.MatchPinned, - Initialised: hrule.MatchInitialised, - }, - } - applyHyprlandRuleAction(&wr.Actions, hrule.Rule, hrule.Value) - - if wr.ID == "" { - wr.ID = hrule.MatchClass - if wr.ID == "" { - wr.ID = hrule.MatchTitle - } - } - - rules = append(rules, wr) - currentID = "" - currentName = "" - } - } - - return rules, nil -} - -func (p *HyprlandWritableProvider) writeDMSRules(rules []windowrules.WindowRule) error { - rulesPath := p.GetOverridePath() - - if err := os.MkdirAll(filepath.Dir(rulesPath), 0755); err != nil { - return err - } - - var lines []string - lines = append(lines, "# DMS Window Rules - Managed by DankMaterialShell") - lines = append(lines, "# Do not edit manually - changes may be overwritten") - lines = append(lines, "") - - for _, rule := range rules { - lines = append(lines, p.formatRuleLines(rule)...) - } - - return os.WriteFile(rulesPath, []byte(strings.Join(lines, "\n")), 0644) -} - -func (p *HyprlandWritableProvider) formatRuleLines(rule windowrules.WindowRule) []string { - var lines []string - lines = append(lines, fmt.Sprintf("# DMS-RULE: id=%s, name=%s", rule.ID, rule.Name)) - - var matchParts []string - if rule.MatchCriteria.AppID != "" { - matchParts = append(matchParts, fmt.Sprintf("class:%s", rule.MatchCriteria.AppID)) - } - if rule.MatchCriteria.Title != "" { - matchParts = append(matchParts, fmt.Sprintf("title:%s", rule.MatchCriteria.Title)) - } - if rule.MatchCriteria.XWayland != nil { - matchParts = append(matchParts, fmt.Sprintf("xwayland:%d", boolToInt(*rule.MatchCriteria.XWayland))) - } - if rule.MatchCriteria.IsFloating != nil { - matchParts = append(matchParts, fmt.Sprintf("floating:%d", boolToInt(*rule.MatchCriteria.IsFloating))) - } - if rule.MatchCriteria.Fullscreen != nil { - matchParts = append(matchParts, fmt.Sprintf("fullscreen:%d", boolToInt(*rule.MatchCriteria.Fullscreen))) - } - if rule.MatchCriteria.Pinned != nil { - matchParts = append(matchParts, fmt.Sprintf("pinned:%d", boolToInt(*rule.MatchCriteria.Pinned))) - } - - matchStr := strings.Join(matchParts, ", ") - a := rule.Actions - - if a.OpenFloating != nil && *a.OpenFloating { - lines = append(lines, fmt.Sprintf("windowrulev2 = float, %s", matchStr)) - } - if a.Tile != nil && *a.Tile { - lines = append(lines, fmt.Sprintf("windowrulev2 = tile, %s", matchStr)) - } - if a.OpenFullscreen != nil && *a.OpenFullscreen { - lines = append(lines, fmt.Sprintf("windowrulev2 = fullscreen, %s", matchStr)) - } - if a.OpenMaximized != nil && *a.OpenMaximized { - lines = append(lines, fmt.Sprintf("windowrulev2 = maximize, %s", matchStr)) - } - if a.NoFocus != nil && *a.NoFocus { - lines = append(lines, fmt.Sprintf("windowrulev2 = nofocus, %s", matchStr)) - } - if a.NoBorder != nil && *a.NoBorder { - lines = append(lines, fmt.Sprintf("windowrulev2 = noborder, %s", matchStr)) - } - if a.NoShadow != nil && *a.NoShadow { - lines = append(lines, fmt.Sprintf("windowrulev2 = noshadow, %s", matchStr)) - } - if a.NoDim != nil && *a.NoDim { - lines = append(lines, fmt.Sprintf("windowrulev2 = nodim, %s", matchStr)) - } - if a.NoBlur != nil && *a.NoBlur { - lines = append(lines, fmt.Sprintf("windowrulev2 = noblur, %s", matchStr)) - } - if a.NoAnim != nil && *a.NoAnim { - lines = append(lines, fmt.Sprintf("windowrulev2 = noanim, %s", matchStr)) - } - if a.NoRounding != nil && *a.NoRounding { - lines = append(lines, fmt.Sprintf("windowrulev2 = norounding, %s", matchStr)) - } - if a.Pin != nil && *a.Pin { - lines = append(lines, fmt.Sprintf("windowrulev2 = pin, %s", matchStr)) - } - if a.Opaque != nil && *a.Opaque { - lines = append(lines, fmt.Sprintf("windowrulev2 = opaque, %s", matchStr)) - } - if a.ForcergbX != nil && *a.ForcergbX { - lines = append(lines, fmt.Sprintf("windowrulev2 = forcergbx, %s", matchStr)) - } - if a.Opacity != nil { - lines = append(lines, fmt.Sprintf("windowrulev2 = opacity %.2f, %s", *a.Opacity, matchStr)) - } - if a.Size != "" { - lines = append(lines, fmt.Sprintf("windowrulev2 = size %s, %s", a.Size, matchStr)) - } - if a.Move != "" { - lines = append(lines, fmt.Sprintf("windowrulev2 = move %s, %s", a.Move, matchStr)) - } - if a.Monitor != "" { - lines = append(lines, fmt.Sprintf("windowrulev2 = monitor %s, %s", a.Monitor, matchStr)) - } - if a.Workspace != "" { - lines = append(lines, fmt.Sprintf("windowrulev2 = workspace %s, %s", a.Workspace, matchStr)) - } - if a.CornerRadius != nil { - lines = append(lines, fmt.Sprintf("windowrulev2 = rounding %d, %s", *a.CornerRadius, matchStr)) - } - if a.Idleinhibit != "" { - lines = append(lines, fmt.Sprintf("windowrulev2 = idleinhibit %s, %s", a.Idleinhibit, matchStr)) - } - - if len(lines) == 1 { - lines = append(lines, fmt.Sprintf("# (no actions defined for rule %s)", rule.ID)) - } - - lines = append(lines, "") - return lines -} - -func boolToInt(b bool) int { - if b { - return 1 - } - return 0 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser_test.go deleted file mode 100644 index 5341b4b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/hyprland_parser_test.go +++ /dev/null @@ -1,280 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestParseWindowRuleV1(t *testing.T) { - parser := NewHyprlandRulesParser("") - - tests := []struct { - name string - line string - wantClass string - wantRule string - wantNil bool - }{ - { - name: "basic float rule", - line: "windowrule = float, ^(firefox)$", - wantClass: "^(firefox)$", - wantRule: "float", - }, - { - name: "tile rule", - line: "windowrule = tile, steam", - wantClass: "steam", - wantRule: "tile", - }, - { - name: "no match returns empty class", - line: "windowrule = float", - wantClass: "", - wantRule: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := parser.parseWindowRuleLine(tt.line) - if tt.wantNil { - if result != nil { - t.Errorf("expected nil, got %+v", result) - } - return - } - if result == nil { - t.Fatal("expected non-nil result") - } - if result.MatchClass != tt.wantClass { - t.Errorf("MatchClass = %q, want %q", result.MatchClass, tt.wantClass) - } - if result.Rule != tt.wantRule { - t.Errorf("Rule = %q, want %q", result.Rule, tt.wantRule) - } - }) - } -} - -func TestParseWindowRuleV2(t *testing.T) { - parser := NewHyprlandRulesParser("") - - tests := []struct { - name string - line string - wantClass string - wantTitle string - wantRule string - wantValue string - }{ - { - name: "float with class", - line: "windowrulev2 = float, class:^(firefox)$", - wantClass: "^(firefox)$", - wantRule: "float", - }, - { - name: "opacity with value", - line: "windowrulev2 = opacity 0.8, class:^(code)$", - wantClass: "^(code)$", - wantRule: "opacity", - wantValue: "0.8", - }, - { - name: "size with value and title", - line: "windowrulev2 = size 800 600, class:^(steam)$, title:Settings", - wantClass: "^(steam)$", - wantTitle: "Settings", - wantRule: "size", - wantValue: "800 600", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := parser.parseWindowRuleLine(tt.line) - if result == nil { - t.Fatal("expected non-nil result") - } - if result.MatchClass != tt.wantClass { - t.Errorf("MatchClass = %q, want %q", result.MatchClass, tt.wantClass) - } - if result.MatchTitle != tt.wantTitle { - t.Errorf("MatchTitle = %q, want %q", result.MatchTitle, tt.wantTitle) - } - if result.Rule != tt.wantRule { - t.Errorf("Rule = %q, want %q", result.Rule, tt.wantRule) - } - if result.Value != tt.wantValue { - t.Errorf("Value = %q, want %q", result.Value, tt.wantValue) - } - }) - } -} - -func TestConvertHyprlandRulesToWindowRules(t *testing.T) { - hyprRules := []HyprlandWindowRule{ - {MatchClass: "^(firefox)$", Rule: "float"}, - {MatchClass: "^(code)$", Rule: "opacity", Value: "0.9"}, - {MatchClass: "^(steam)$", Rule: "maximize"}, - } - - result := ConvertHyprlandRulesToWindowRules(hyprRules) - - if len(result) != 3 { - t.Errorf("expected 3 rules, got %d", len(result)) - } - - if result[0].MatchCriteria.AppID != "^(firefox)$" { - t.Errorf("rule 0 AppID = %q, want ^(firefox)$", result[0].MatchCriteria.AppID) - } - if result[0].Actions.OpenFloating == nil || !*result[0].Actions.OpenFloating { - t.Error("rule 0 should have OpenFloating = true") - } - - if result[1].Actions.Opacity == nil || *result[1].Actions.Opacity != 0.9 { - t.Errorf("rule 1 Opacity = %v, want 0.9", result[1].Actions.Opacity) - } - - if result[2].Actions.OpenMaximized == nil || !*result[2].Actions.OpenMaximized { - t.Error("rule 2 should have OpenMaximized = true") - } -} - -func TestHyprlandWritableProvider(t *testing.T) { - tmpDir := t.TempDir() - provider := NewHyprlandWritableProvider(tmpDir) - - if provider.Name() != "hyprland" { - t.Errorf("Name() = %q, want hyprland", provider.Name()) - } - - expectedPath := filepath.Join(tmpDir, "dms", "windowrules.conf") - if provider.GetOverridePath() != expectedPath { - t.Errorf("GetOverridePath() = %q, want %q", provider.GetOverridePath(), expectedPath) - } -} - -func TestHyprlandSetAndLoadDMSRules(t *testing.T) { - tmpDir := t.TempDir() - provider := NewHyprlandWritableProvider(tmpDir) - - rule := newTestWindowRule("test_id", "Test Rule", "^(firefox)$") - rule.Actions.OpenFloating = boolPtr(true) - - if err := provider.SetRule(rule); err != nil { - t.Fatalf("SetRule failed: %v", err) - } - - rules, err := provider.LoadDMSRules() - if err != nil { - t.Fatalf("LoadDMSRules failed: %v", err) - } - - if len(rules) != 1 { - t.Fatalf("expected 1 rule, got %d", len(rules)) - } - - if rules[0].ID != "test_id" { - t.Errorf("ID = %q, want test_id", rules[0].ID) - } - if rules[0].MatchCriteria.AppID != "^(firefox)$" { - t.Errorf("AppID = %q, want ^(firefox)$", rules[0].MatchCriteria.AppID) - } -} - -func TestHyprlandRemoveRule(t *testing.T) { - tmpDir := t.TempDir() - provider := NewHyprlandWritableProvider(tmpDir) - - rule1 := newTestWindowRule("rule1", "Rule 1", "^(app1)$") - rule1.Actions.OpenFloating = boolPtr(true) - rule2 := newTestWindowRule("rule2", "Rule 2", "^(app2)$") - rule2.Actions.OpenFloating = boolPtr(true) - - _ = provider.SetRule(rule1) - _ = provider.SetRule(rule2) - - if err := provider.RemoveRule("rule1"); err != nil { - t.Fatalf("RemoveRule failed: %v", err) - } - - rules, _ := provider.LoadDMSRules() - if len(rules) != 1 { - t.Fatalf("expected 1 rule after removal, got %d", len(rules)) - } - if rules[0].ID != "rule2" { - t.Errorf("remaining rule ID = %q, want rule2", rules[0].ID) - } -} - -func TestHyprlandReorderRules(t *testing.T) { - tmpDir := t.TempDir() - provider := NewHyprlandWritableProvider(tmpDir) - - rule1 := newTestWindowRule("rule1", "Rule 1", "^(app1)$") - rule1.Actions.OpenFloating = boolPtr(true) - rule2 := newTestWindowRule("rule2", "Rule 2", "^(app2)$") - rule2.Actions.OpenFloating = boolPtr(true) - rule3 := newTestWindowRule("rule3", "Rule 3", "^(app3)$") - rule3.Actions.OpenFloating = boolPtr(true) - - _ = provider.SetRule(rule1) - _ = provider.SetRule(rule2) - _ = provider.SetRule(rule3) - - if err := provider.ReorderRules([]string{"rule3", "rule1", "rule2"}); err != nil { - t.Fatalf("ReorderRules failed: %v", err) - } - - rules, _ := provider.LoadDMSRules() - if len(rules) != 3 { - t.Fatalf("expected 3 rules, got %d", len(rules)) - } - expectedOrder := []string{"rule3", "rule1", "rule2"} - for i, expectedID := range expectedOrder { - if rules[i].ID != expectedID { - t.Errorf("rule %d ID = %q, want %q", i, rules[i].ID, expectedID) - } - } -} - -func TestHyprlandParseConfigWithSource(t *testing.T) { - tmpDir := t.TempDir() - - mainConfig := ` -windowrulev2 = float, class:^(mainapp)$ -source = ./extra.conf -` - extraConfig := ` -windowrulev2 = tile, class:^(extraapp)$ -` - - if err := os.WriteFile(filepath.Join(tmpDir, "hyprland.conf"), []byte(mainConfig), 0644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(tmpDir, "extra.conf"), []byte(extraConfig), 0644); err != nil { - t.Fatal(err) - } - - parser := NewHyprlandRulesParser(tmpDir) - rules, err := parser.Parse() - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - - if len(rules) != 2 { - t.Errorf("expected 2 rules, got %d", len(rules)) - } -} - -func TestBoolToInt(t *testing.T) { - if boolToInt(true) != 1 { - t.Error("boolToInt(true) should be 1") - } - if boolToInt(false) != 0 { - t.Error("boolToInt(false) should be 0") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser.go deleted file mode 100644 index 5bb5ec4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser.go +++ /dev/null @@ -1,875 +0,0 @@ -package providers - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - - "github.com/sblinch/kdl-go" - "github.com/sblinch/kdl-go/document" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/windowrules" -) - -type NiriWindowRule struct { - MatchAppID string - MatchTitle string - MatchIsFloating *bool - MatchIsActive *bool - MatchIsFocused *bool - MatchIsActiveInColumn *bool - MatchIsWindowCastTarget *bool - MatchIsUrgent *bool - MatchAtStartup *bool - Opacity *float64 - OpenFloating *bool - OpenMaximized *bool - OpenMaximizedToEdges *bool - OpenFullscreen *bool - OpenFocused *bool - OpenOnOutput string - OpenOnWorkspace string - DefaultColumnWidth string - DefaultWindowHeight string - VariableRefreshRate *bool - BlockOutFrom string - DefaultColumnDisplay string - ScrollFactor *float64 - CornerRadius *int - ClipToGeometry *bool - TiledState *bool - MinWidth *int - MaxWidth *int - MinHeight *int - MaxHeight *int - BorderColor string - FocusRingColor string - FocusRingOff *bool - BorderOff *bool - DrawBorderWithBg *bool - Source string -} - -type NiriRulesParser struct { - configDir string - processedFiles map[string]bool - rules []NiriWindowRule - currentSource string - dmsRulesIncluded bool - dmsRulesExists bool - includeCount int - dmsIncludePos int - rulesAfterDMS int - dmsProcessed bool -} - -func NewNiriRulesParser(configDir string) *NiriRulesParser { - return &NiriRulesParser{ - configDir: configDir, - processedFiles: make(map[string]bool), - rules: []NiriWindowRule{}, - dmsIncludePos: -1, - } -} - -func (p *NiriRulesParser) Parse() ([]NiriWindowRule, error) { - dmsRulesPath := filepath.Join(p.configDir, "dms", "windowrules.kdl") - if _, err := os.Stat(dmsRulesPath); err == nil { - p.dmsRulesExists = true - } - - configPath := filepath.Join(p.configDir, "config.kdl") - if err := p.parseFile(configPath); err != nil { - return nil, err - } - - if p.dmsRulesExists && !p.dmsProcessed { - p.parseDMSRulesDirectly(dmsRulesPath) - } - - return p.rules, nil -} - -func (p *NiriRulesParser) parseDMSRulesDirectly(dmsRulesPath string) { - data, err := os.ReadFile(dmsRulesPath) - if err != nil { - return - } - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return - } - - prevSource := p.currentSource - p.currentSource = dmsRulesPath - p.processNodes(doc.Nodes, filepath.Dir(dmsRulesPath)) - p.currentSource = prevSource - p.dmsProcessed = true -} - -func (p *NiriRulesParser) parseFile(filePath string) error { - absPath, err := filepath.Abs(filePath) - if err != nil { - return err - } - - if p.processedFiles[absPath] { - return nil - } - p.processedFiles[absPath] = true - - data, err := os.ReadFile(absPath) - if err != nil { - return nil - } - - doc, err := kdl.Parse(strings.NewReader(string(data))) - if err != nil { - return err - } - - prevSource := p.currentSource - p.currentSource = absPath - baseDir := filepath.Dir(absPath) - p.processNodes(doc.Nodes, baseDir) - p.currentSource = prevSource - - return nil -} - -func (p *NiriRulesParser) processNodes(nodes []*document.Node, baseDir string) { - for _, node := range nodes { - name := node.Name.String() - - switch name { - case "include": - p.handleInclude(node, baseDir) - case "window-rule": - p.parseWindowRuleNode(node) - } - } -} - -func (p *NiriRulesParser) handleInclude(node *document.Node, baseDir string) { - if len(node.Arguments) == 0 { - return - } - - includePath := strings.Trim(node.Arguments[0].String(), "\"") - isDMSInclude := includePath == "dms/windowrules.kdl" || strings.HasSuffix(includePath, "/dms/windowrules.kdl") - - p.includeCount++ - if isDMSInclude { - p.dmsRulesIncluded = true - p.dmsIncludePos = p.includeCount - p.dmsProcessed = true - } - - fullPath := filepath.Join(baseDir, includePath) - if filepath.IsAbs(includePath) { - fullPath = includePath - } - - _ = p.parseFile(fullPath) -} - -func (p *NiriRulesParser) parseWindowRuleNode(node *document.Node) { - if node.Children == nil { - return - } - - rule := NiriWindowRule{ - Source: p.currentSource, - } - - for _, child := range node.Children { - childName := child.Name.String() - - switch childName { - case "match": - p.parseMatchNode(child, &rule) - case "opacity": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if f, ok := val.(float64); ok { - rule.Opacity = &f - } - } - case "open-floating": - b := p.parseBoolArg(child) - rule.OpenFloating = &b - case "open-maximized": - b := p.parseBoolArg(child) - rule.OpenMaximized = &b - case "open-maximized-to-edges": - b := p.parseBoolArg(child) - rule.OpenMaximizedToEdges = &b - case "open-fullscreen": - b := p.parseBoolArg(child) - rule.OpenFullscreen = &b - case "open-focused": - b := p.parseBoolArg(child) - rule.OpenFocused = &b - case "open-on-output": - if len(child.Arguments) > 0 { - rule.OpenOnOutput = child.Arguments[0].ValueString() - } - case "open-on-workspace": - if len(child.Arguments) > 0 { - rule.OpenOnWorkspace = child.Arguments[0].ValueString() - } - case "default-column-width": - rule.DefaultColumnWidth = p.parseSizeNode(child) - case "default-window-height": - rule.DefaultWindowHeight = p.parseSizeNode(child) - case "variable-refresh-rate": - b := p.parseBoolArg(child) - rule.VariableRefreshRate = &b - case "block-out-from": - if len(child.Arguments) > 0 { - rule.BlockOutFrom = child.Arguments[0].ValueString() - } - case "default-column-display": - if len(child.Arguments) > 0 { - rule.DefaultColumnDisplay = child.Arguments[0].ValueString() - } - case "scroll-factor": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if f, ok := val.(float64); ok { - rule.ScrollFactor = &f - } - } - case "geometry-corner-radius": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if i, ok := val.(int64); ok { - intVal := int(i) - rule.CornerRadius = &intVal - } - } - case "clip-to-geometry": - b := p.parseBoolArg(child) - rule.ClipToGeometry = &b - case "tiled-state": - b := p.parseBoolArg(child) - rule.TiledState = &b - case "min-width": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if i, ok := val.(int64); ok { - intVal := int(i) - rule.MinWidth = &intVal - } - } - case "max-width": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if i, ok := val.(int64); ok { - intVal := int(i) - rule.MaxWidth = &intVal - } - } - case "min-height": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if i, ok := val.(int64); ok { - intVal := int(i) - rule.MinHeight = &intVal - } - } - case "max-height": - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - if i, ok := val.(int64); ok { - intVal := int(i) - rule.MaxHeight = &intVal - } - } - case "border": - p.parseBorderNode(child, &rule) - case "focus-ring": - p.parseFocusRingNode(child, &rule) - case "draw-border-with-background": - b := p.parseBoolArg(child) - rule.DrawBorderWithBg = &b - } - } - - p.rules = append(p.rules, rule) -} - -func (p *NiriRulesParser) parseSizeNode(node *document.Node) string { - if node.Children == nil { - return "" - } - for _, child := range node.Children { - name := child.Name.String() - if len(child.Arguments) > 0 { - val := child.Arguments[0].ResolvedValue() - switch name { - case "fixed": - if i, ok := val.(int64); ok { - return "fixed " + strconv.FormatInt(i, 10) - } - case "proportion": - if f, ok := val.(float64); ok { - return "proportion " + strconv.FormatFloat(f, 'f', -1, 64) - } - } - } - } - return "" -} - -func (p *NiriRulesParser) parseMatchNode(node *document.Node, rule *NiriWindowRule) { - if node.Properties == nil { - return - } - - if val, ok := node.Properties.Get("app-id"); ok { - rule.MatchAppID = val.ValueString() - } - if val, ok := node.Properties.Get("title"); ok { - rule.MatchTitle = val.ValueString() - } - if val, ok := node.Properties.Get("is-floating"); ok { - b := val.ValueString() == "true" - rule.MatchIsFloating = &b - } - if val, ok := node.Properties.Get("is-active"); ok { - b := val.ValueString() == "true" - rule.MatchIsActive = &b - } - if val, ok := node.Properties.Get("is-focused"); ok { - b := val.ValueString() == "true" - rule.MatchIsFocused = &b - } - if val, ok := node.Properties.Get("is-active-in-column"); ok { - b := val.ValueString() == "true" - rule.MatchIsActiveInColumn = &b - } - if val, ok := node.Properties.Get("is-window-cast-target"); ok { - b := val.ValueString() == "true" - rule.MatchIsWindowCastTarget = &b - } - if val, ok := node.Properties.Get("is-urgent"); ok { - b := val.ValueString() == "true" - rule.MatchIsUrgent = &b - } - if val, ok := node.Properties.Get("at-startup"); ok { - b := val.ValueString() == "true" - rule.MatchAtStartup = &b - } -} - -func (p *NiriRulesParser) parseBorderNode(node *document.Node, rule *NiriWindowRule) { - if node.Children == nil { - return - } - - for _, child := range node.Children { - switch child.Name.String() { - case "off": - b := true - rule.BorderOff = &b - case "active-color": - if len(child.Arguments) > 0 { - rule.BorderColor = child.Arguments[0].ValueString() - } - } - } -} - -func (p *NiriRulesParser) parseFocusRingNode(node *document.Node, rule *NiriWindowRule) { - if node.Children == nil { - return - } - - for _, child := range node.Children { - switch child.Name.String() { - case "off": - b := true - rule.FocusRingOff = &b - case "active-color": - if len(child.Arguments) > 0 { - rule.FocusRingColor = child.Arguments[0].ValueString() - } - } - } -} - -func (p *NiriRulesParser) parseBoolArg(node *document.Node) bool { - if len(node.Arguments) == 0 { - return true - } - return node.Arguments[0].ValueString() != "false" -} - -func (p *NiriRulesParser) HasDMSRulesIncluded() bool { - return p.dmsRulesIncluded -} - -func (p *NiriRulesParser) buildDMSStatus() *windowrules.DMSRulesStatus { - status := &windowrules.DMSRulesStatus{ - Exists: p.dmsRulesExists, - Included: p.dmsRulesIncluded, - IncludePosition: p.dmsIncludePos, - TotalIncludes: p.includeCount, - RulesAfterDMS: p.rulesAfterDMS, - } - - switch { - case !p.dmsRulesExists: - status.Effective = false - status.StatusMessage = "dms/windowrules.kdl does not exist" - case !p.dmsRulesIncluded: - status.Effective = false - status.StatusMessage = "dms/windowrules.kdl is not included in config.kdl" - case p.rulesAfterDMS > 0: - status.Effective = true - status.OverriddenBy = p.rulesAfterDMS - status.StatusMessage = "Some DMS rules may be overridden by config rules" - default: - status.Effective = true - status.StatusMessage = "DMS window rules are active" - } - - return status -} - -type NiriRulesParseResult struct { - Rules []NiriWindowRule - DMSRulesIncluded bool - DMSStatus *windowrules.DMSRulesStatus -} - -func ParseNiriWindowRules(configDir string) (*NiriRulesParseResult, error) { - parser := NewNiriRulesParser(configDir) - rules, err := parser.Parse() - if err != nil { - return nil, err - } - return &NiriRulesParseResult{ - Rules: rules, - DMSRulesIncluded: parser.HasDMSRulesIncluded(), - DMSStatus: parser.buildDMSStatus(), - }, nil -} - -func ConvertNiriRulesToWindowRules(niriRules []NiriWindowRule) []windowrules.WindowRule { - result := make([]windowrules.WindowRule, 0, len(niriRules)) - for i, nr := range niriRules { - wr := windowrules.WindowRule{ - ID: fmt.Sprintf("rule_%d", i), - Enabled: true, - Source: nr.Source, - MatchCriteria: windowrules.MatchCriteria{ - AppID: nr.MatchAppID, - Title: nr.MatchTitle, - IsFloating: nr.MatchIsFloating, - IsActive: nr.MatchIsActive, - IsFocused: nr.MatchIsFocused, - IsActiveInColumn: nr.MatchIsActiveInColumn, - IsWindowCastTarget: nr.MatchIsWindowCastTarget, - IsUrgent: nr.MatchIsUrgent, - AtStartup: nr.MatchAtStartup, - }, - Actions: windowrules.Actions{ - Opacity: nr.Opacity, - OpenFloating: nr.OpenFloating, - OpenMaximized: nr.OpenMaximized, - OpenMaximizedToEdges: nr.OpenMaximizedToEdges, - OpenFullscreen: nr.OpenFullscreen, - OpenFocused: nr.OpenFocused, - OpenOnOutput: nr.OpenOnOutput, - OpenOnWorkspace: nr.OpenOnWorkspace, - DefaultColumnWidth: nr.DefaultColumnWidth, - DefaultWindowHeight: nr.DefaultWindowHeight, - VariableRefreshRate: nr.VariableRefreshRate, - BlockOutFrom: nr.BlockOutFrom, - DefaultColumnDisplay: nr.DefaultColumnDisplay, - ScrollFactor: nr.ScrollFactor, - CornerRadius: nr.CornerRadius, - ClipToGeometry: nr.ClipToGeometry, - TiledState: nr.TiledState, - MinWidth: nr.MinWidth, - MaxWidth: nr.MaxWidth, - MinHeight: nr.MinHeight, - MaxHeight: nr.MaxHeight, - BorderColor: nr.BorderColor, - FocusRingColor: nr.FocusRingColor, - FocusRingOff: nr.FocusRingOff, - BorderOff: nr.BorderOff, - DrawBorderWithBg: nr.DrawBorderWithBg, - }, - } - result = append(result, wr) - } - return result -} - -type NiriWritableProvider struct { - configDir string -} - -func NewNiriWritableProvider(configDir string) *NiriWritableProvider { - return &NiriWritableProvider{configDir: configDir} -} - -func (p *NiriWritableProvider) Name() string { - return "niri" -} - -func (p *NiriWritableProvider) GetOverridePath() string { - return filepath.Join(p.configDir, "dms", "windowrules.kdl") -} - -func (p *NiriWritableProvider) GetRuleSet() (*windowrules.RuleSet, error) { - result, err := ParseNiriWindowRules(p.configDir) - if err != nil { - return nil, err - } - return &windowrules.RuleSet{ - Title: "Niri Window Rules", - Provider: "niri", - Rules: ConvertNiriRulesToWindowRules(result.Rules), - DMSRulesIncluded: result.DMSRulesIncluded, - DMSStatus: result.DMSStatus, - }, nil -} - -func (p *NiriWritableProvider) SetRule(rule windowrules.WindowRule) error { - rules, err := p.LoadDMSRules() - if err != nil { - rules = []windowrules.WindowRule{} - } - - found := false - for i, r := range rules { - if r.ID == rule.ID { - rules[i] = rule - found = true - break - } - } - if !found { - rules = append(rules, rule) - } - - return p.writeDMSRules(rules) -} - -func (p *NiriWritableProvider) RemoveRule(id string) error { - rules, err := p.LoadDMSRules() - if err != nil { - return err - } - - newRules := make([]windowrules.WindowRule, 0, len(rules)) - for _, r := range rules { - if r.ID != id { - newRules = append(newRules, r) - } - } - - return p.writeDMSRules(newRules) -} - -func (p *NiriWritableProvider) ReorderRules(ids []string) error { - rules, err := p.LoadDMSRules() - if err != nil { - return err - } - - ruleMap := make(map[string]windowrules.WindowRule) - for _, r := range rules { - ruleMap[r.ID] = r - } - - newRules := make([]windowrules.WindowRule, 0, len(ids)) - for _, id := range ids { - if r, ok := ruleMap[id]; ok { - newRules = append(newRules, r) - delete(ruleMap, id) - } - } - - for _, r := range ruleMap { - newRules = append(newRules, r) - } - - return p.writeDMSRules(newRules) -} - -var niriMetaCommentRegex = regexp.MustCompile(`^//\s*@id=(\S*)\s*@name=(.*)$`) - -func (p *NiriWritableProvider) LoadDMSRules() ([]windowrules.WindowRule, error) { - rulesPath := p.GetOverridePath() - data, err := os.ReadFile(rulesPath) - if err != nil { - if os.IsNotExist(err) { - return []windowrules.WindowRule{}, nil - } - return nil, err - } - - content := string(data) - lines := strings.Split(content, "\n") - - type ruleMeta struct { - id string - name string - } - var metas []ruleMeta - var currentID, currentName string - - for _, line := range lines { - trimmed := strings.TrimSpace(line) - if matches := niriMetaCommentRegex.FindStringSubmatch(trimmed); matches != nil { - currentID = matches[1] - currentName = strings.TrimSpace(matches[2]) - continue - } - if strings.HasPrefix(trimmed, "window-rule") { - metas = append(metas, ruleMeta{id: currentID, name: currentName}) - currentID = "" - currentName = "" - } - } - - doc, err := kdl.Parse(strings.NewReader(content)) - if err != nil { - return nil, err - } - - parser := NewNiriRulesParser(p.configDir) - parser.currentSource = rulesPath - - for _, node := range doc.Nodes { - if node.Name.String() == "window-rule" { - parser.parseWindowRuleNode(node) - } - } - - var rules []windowrules.WindowRule - for i, nr := range parser.rules { - id := "" - name := "" - if i < len(metas) { - id = metas[i].id - name = metas[i].name - } - if id == "" { - id = fmt.Sprintf("dms_rule_%d", i) - } - - wr := windowrules.WindowRule{ - ID: id, - Name: name, - Enabled: true, - Source: rulesPath, - MatchCriteria: windowrules.MatchCriteria{ - AppID: nr.MatchAppID, - Title: nr.MatchTitle, - IsFloating: nr.MatchIsFloating, - IsActive: nr.MatchIsActive, - IsFocused: nr.MatchIsFocused, - IsActiveInColumn: nr.MatchIsActiveInColumn, - IsWindowCastTarget: nr.MatchIsWindowCastTarget, - IsUrgent: nr.MatchIsUrgent, - AtStartup: nr.MatchAtStartup, - }, - Actions: windowrules.Actions{ - Opacity: nr.Opacity, - OpenFloating: nr.OpenFloating, - OpenMaximized: nr.OpenMaximized, - OpenMaximizedToEdges: nr.OpenMaximizedToEdges, - OpenFullscreen: nr.OpenFullscreen, - OpenFocused: nr.OpenFocused, - OpenOnOutput: nr.OpenOnOutput, - OpenOnWorkspace: nr.OpenOnWorkspace, - DefaultColumnWidth: nr.DefaultColumnWidth, - DefaultWindowHeight: nr.DefaultWindowHeight, - VariableRefreshRate: nr.VariableRefreshRate, - BlockOutFrom: nr.BlockOutFrom, - DefaultColumnDisplay: nr.DefaultColumnDisplay, - ScrollFactor: nr.ScrollFactor, - CornerRadius: nr.CornerRadius, - ClipToGeometry: nr.ClipToGeometry, - TiledState: nr.TiledState, - MinWidth: nr.MinWidth, - MaxWidth: nr.MaxWidth, - MinHeight: nr.MinHeight, - MaxHeight: nr.MaxHeight, - BorderColor: nr.BorderColor, - FocusRingColor: nr.FocusRingColor, - FocusRingOff: nr.FocusRingOff, - BorderOff: nr.BorderOff, - DrawBorderWithBg: nr.DrawBorderWithBg, - }, - } - - rules = append(rules, wr) - } - - return rules, nil -} - -func (p *NiriWritableProvider) writeDMSRules(rules []windowrules.WindowRule) error { - rulesPath := p.GetOverridePath() - - if err := os.MkdirAll(filepath.Dir(rulesPath), 0755); err != nil { - return err - } - - var lines []string - lines = append(lines, "// DMS Window Rules - Managed by DankMaterialShell") - lines = append(lines, "// Do not edit manually - changes may be overwritten") - lines = append(lines, "") - - for _, rule := range rules { - lines = append(lines, p.formatRule(rule)) - lines = append(lines, "") - } - - return os.WriteFile(rulesPath, []byte(strings.Join(lines, "\n")), 0644) -} - -func (p *NiriWritableProvider) formatRule(rule windowrules.WindowRule) string { - var lines []string - lines = append(lines, fmt.Sprintf("// @id=%s @name=%s", rule.ID, rule.Name)) - lines = append(lines, "window-rule {") - - m := rule.MatchCriteria - if m.AppID != "" || m.Title != "" || m.IsFloating != nil || m.IsActive != nil || - m.IsFocused != nil || m.IsActiveInColumn != nil || m.IsWindowCastTarget != nil || - m.IsUrgent != nil || m.AtStartup != nil { - var matchProps []string - if m.AppID != "" { - matchProps = append(matchProps, fmt.Sprintf("app-id=%q", m.AppID)) - } - if m.Title != "" { - matchProps = append(matchProps, fmt.Sprintf("title=%q", m.Title)) - } - if m.IsFloating != nil { - matchProps = append(matchProps, fmt.Sprintf("is-floating=%t", *m.IsFloating)) - } - if m.IsActive != nil { - matchProps = append(matchProps, fmt.Sprintf("is-active=%t", *m.IsActive)) - } - if m.IsFocused != nil { - matchProps = append(matchProps, fmt.Sprintf("is-focused=%t", *m.IsFocused)) - } - if m.IsActiveInColumn != nil { - matchProps = append(matchProps, fmt.Sprintf("is-active-in-column=%t", *m.IsActiveInColumn)) - } - if m.IsWindowCastTarget != nil { - matchProps = append(matchProps, fmt.Sprintf("is-window-cast-target=%t", *m.IsWindowCastTarget)) - } - if m.IsUrgent != nil { - matchProps = append(matchProps, fmt.Sprintf("is-urgent=%t", *m.IsUrgent)) - } - if m.AtStartup != nil { - matchProps = append(matchProps, fmt.Sprintf("at-startup=%t", *m.AtStartup)) - } - lines = append(lines, " match "+strings.Join(matchProps, " ")) - } - - a := rule.Actions - if a.Opacity != nil { - lines = append(lines, fmt.Sprintf(" opacity %.2f", *a.Opacity)) - } - if a.OpenFloating != nil && *a.OpenFloating { - lines = append(lines, " open-floating true") - } - if a.OpenMaximized != nil && *a.OpenMaximized { - lines = append(lines, " open-maximized true") - } - if a.OpenMaximizedToEdges != nil && *a.OpenMaximizedToEdges { - lines = append(lines, " open-maximized-to-edges true") - } - if a.OpenFullscreen != nil && *a.OpenFullscreen { - lines = append(lines, " open-fullscreen true") - } - if a.OpenFocused != nil { - lines = append(lines, fmt.Sprintf(" open-focused %t", *a.OpenFocused)) - } - if a.OpenOnOutput != "" { - lines = append(lines, fmt.Sprintf(" open-on-output %q", a.OpenOnOutput)) - } - if a.OpenOnWorkspace != "" { - lines = append(lines, fmt.Sprintf(" open-on-workspace %q", a.OpenOnWorkspace)) - } - if a.DefaultColumnWidth != "" { - lines = append(lines, formatSizeProperty("default-column-width", a.DefaultColumnWidth)) - } - if a.DefaultWindowHeight != "" { - lines = append(lines, formatSizeProperty("default-window-height", a.DefaultWindowHeight)) - } - if a.VariableRefreshRate != nil && *a.VariableRefreshRate { - lines = append(lines, " variable-refresh-rate true") - } - if a.BlockOutFrom != "" { - lines = append(lines, fmt.Sprintf(" block-out-from %q", a.BlockOutFrom)) - } - if a.DefaultColumnDisplay != "" { - lines = append(lines, fmt.Sprintf(" default-column-display %q", a.DefaultColumnDisplay)) - } - if a.ScrollFactor != nil { - lines = append(lines, fmt.Sprintf(" scroll-factor %.2f", *a.ScrollFactor)) - } - if a.CornerRadius != nil { - lines = append(lines, fmt.Sprintf(" geometry-corner-radius %d", *a.CornerRadius)) - } - if a.ClipToGeometry != nil && *a.ClipToGeometry { - lines = append(lines, " clip-to-geometry true") - } - if a.TiledState != nil && *a.TiledState { - lines = append(lines, " tiled-state true") - } - if a.MinWidth != nil { - lines = append(lines, fmt.Sprintf(" min-width %d", *a.MinWidth)) - } - if a.MaxWidth != nil { - lines = append(lines, fmt.Sprintf(" max-width %d", *a.MaxWidth)) - } - if a.MinHeight != nil { - lines = append(lines, fmt.Sprintf(" min-height %d", *a.MinHeight)) - } - if a.MaxHeight != nil { - lines = append(lines, fmt.Sprintf(" max-height %d", *a.MaxHeight)) - } - if a.BorderOff != nil && *a.BorderOff { - lines = append(lines, " border { off; }") - } else if a.BorderColor != "" { - lines = append(lines, fmt.Sprintf(" border { active-color %q; }", a.BorderColor)) - } - if a.FocusRingOff != nil && *a.FocusRingOff { - lines = append(lines, " focus-ring { off; }") - } else if a.FocusRingColor != "" { - lines = append(lines, fmt.Sprintf(" focus-ring { active-color %q; }", a.FocusRingColor)) - } - if a.DrawBorderWithBg != nil { - lines = append(lines, fmt.Sprintf(" draw-border-with-background %t", *a.DrawBorderWithBg)) - } - - lines = append(lines, "}") - return strings.Join(lines, "\n") -} - -func formatSizeProperty(name, value string) string { - parts := strings.SplitN(value, " ", 2) - if len(parts) == 2 { - return fmt.Sprintf(" %s { %s %s; }", name, parts[0], parts[1]) - } - // Bare number without type prefix — default to "fixed" - if _, err := strconv.Atoi(value); err == nil { - return fmt.Sprintf(" %s { fixed %s; }", name, value) - } - return fmt.Sprintf(" %s { }", name) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser_test.go deleted file mode 100644 index f764b6a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/niri_parser_test.go +++ /dev/null @@ -1,335 +0,0 @@ -package providers - -import ( - "os" - "path/filepath" - "testing" -) - -func TestNiriParseBasicWindowRule(t *testing.T) { - tmpDir := t.TempDir() - - config := ` -window-rule { - match app-id="^firefox$" - opacity 0.9 - open-floating true -} -` - if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(config), 0644); err != nil { - t.Fatal(err) - } - - parser := NewNiriRulesParser(tmpDir) - rules, err := parser.Parse() - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - - if len(rules) != 1 { - t.Fatalf("expected 1 rule, got %d", len(rules)) - } - - rule := rules[0] - if rule.MatchAppID != "^firefox$" { - t.Errorf("MatchAppID = %q, want ^firefox$", rule.MatchAppID) - } - if rule.Opacity == nil || *rule.Opacity != 0.9 { - t.Errorf("Opacity = %v, want 0.9", rule.Opacity) - } - if rule.OpenFloating == nil || !*rule.OpenFloating { - t.Error("OpenFloating should be true") - } -} - -func TestNiriParseMultipleRules(t *testing.T) { - tmpDir := t.TempDir() - - config := ` -window-rule { - match app-id="app1" - open-maximized true -} - -window-rule { - match app-id="app2" - open-fullscreen true -} -` - if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(config), 0644); err != nil { - t.Fatal(err) - } - - parser := NewNiriRulesParser(tmpDir) - rules, err := parser.Parse() - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - - if len(rules) != 2 { - t.Fatalf("expected 2 rules, got %d", len(rules)) - } - - if rules[0].MatchAppID != "app1" { - t.Errorf("rule 0 MatchAppID = %q, want app1", rules[0].MatchAppID) - } - if rules[1].MatchAppID != "app2" { - t.Errorf("rule 1 MatchAppID = %q, want app2", rules[1].MatchAppID) - } -} - -func TestConvertNiriRulesToWindowRules(t *testing.T) { - niriRules := []NiriWindowRule{ - {MatchAppID: "^firefox$", Opacity: floatPtr(0.8)}, - {MatchAppID: "^code$", OpenFloating: boolPtr(true)}, - } - - result := ConvertNiriRulesToWindowRules(niriRules) - - if len(result) != 2 { - t.Errorf("expected 2 rules, got %d", len(result)) - } - - if result[0].MatchCriteria.AppID != "^firefox$" { - t.Errorf("rule 0 AppID = %q, want ^firefox$", result[0].MatchCriteria.AppID) - } - if result[0].Actions.Opacity == nil || *result[0].Actions.Opacity != 0.8 { - t.Errorf("rule 0 Opacity = %v, want 0.8", result[0].Actions.Opacity) - } - - if result[1].Actions.OpenFloating == nil || !*result[1].Actions.OpenFloating { - t.Error("rule 1 should have OpenFloating = true") - } -} - -func TestNiriWritableProvider(t *testing.T) { - tmpDir := t.TempDir() - provider := NewNiriWritableProvider(tmpDir) - - if provider.Name() != "niri" { - t.Errorf("Name() = %q, want niri", provider.Name()) - } - - expectedPath := filepath.Join(tmpDir, "dms", "windowrules.kdl") - if provider.GetOverridePath() != expectedPath { - t.Errorf("GetOverridePath() = %q, want %q", provider.GetOverridePath(), expectedPath) - } -} - -func TestNiriSetAndLoadDMSRules(t *testing.T) { - tmpDir := t.TempDir() - provider := NewNiriWritableProvider(tmpDir) - - rule := newTestWindowRule("test_id", "Test Rule", "^firefox$") - rule.Actions.OpenFloating = boolPtr(true) - rule.Actions.Opacity = floatPtr(0.85) - - if err := provider.SetRule(rule); err != nil { - t.Fatalf("SetRule failed: %v", err) - } - - rules, err := provider.LoadDMSRules() - if err != nil { - t.Fatalf("LoadDMSRules failed: %v", err) - } - - if len(rules) != 1 { - t.Fatalf("expected 1 rule, got %d", len(rules)) - } - - if rules[0].ID != "test_id" { - t.Errorf("ID = %q, want test_id", rules[0].ID) - } - if rules[0].MatchCriteria.AppID != "^firefox$" { - t.Errorf("AppID = %q, want ^firefox$", rules[0].MatchCriteria.AppID) - } -} - -func TestNiriRemoveRule(t *testing.T) { - tmpDir := t.TempDir() - provider := NewNiriWritableProvider(tmpDir) - - rule1 := newTestWindowRule("rule1", "Rule 1", "app1") - rule1.Actions.OpenFloating = boolPtr(true) - rule2 := newTestWindowRule("rule2", "Rule 2", "app2") - rule2.Actions.OpenFloating = boolPtr(true) - - _ = provider.SetRule(rule1) - _ = provider.SetRule(rule2) - - if err := provider.RemoveRule("rule1"); err != nil { - t.Fatalf("RemoveRule failed: %v", err) - } - - rules, _ := provider.LoadDMSRules() - if len(rules) != 1 { - t.Fatalf("expected 1 rule after removal, got %d", len(rules)) - } - if rules[0].ID != "rule2" { - t.Errorf("remaining rule ID = %q, want rule2", rules[0].ID) - } -} - -func TestNiriReorderRules(t *testing.T) { - tmpDir := t.TempDir() - provider := NewNiriWritableProvider(tmpDir) - - rule1 := newTestWindowRule("rule1", "Rule 1", "app1") - rule1.Actions.OpenFloating = boolPtr(true) - rule2 := newTestWindowRule("rule2", "Rule 2", "app2") - rule2.Actions.OpenFloating = boolPtr(true) - rule3 := newTestWindowRule("rule3", "Rule 3", "app3") - rule3.Actions.OpenFloating = boolPtr(true) - - _ = provider.SetRule(rule1) - _ = provider.SetRule(rule2) - _ = provider.SetRule(rule3) - - if err := provider.ReorderRules([]string{"rule3", "rule1", "rule2"}); err != nil { - t.Fatalf("ReorderRules failed: %v", err) - } - - rules, _ := provider.LoadDMSRules() - if len(rules) != 3 { - t.Fatalf("expected 3 rules, got %d", len(rules)) - } - expectedOrder := []string{"rule3", "rule1", "rule2"} - for i, expectedID := range expectedOrder { - if rules[i].ID != expectedID { - t.Errorf("rule %d ID = %q, want %q", i, rules[i].ID, expectedID) - } - } -} - -func TestNiriParseConfigWithInclude(t *testing.T) { - tmpDir := t.TempDir() - - mainConfig := ` -window-rule { - match app-id="mainapp" - opacity 1.0 -} - -include "extra.kdl" -` - extraConfig := ` -window-rule { - match app-id="extraapp" - open-maximized true -} -` - - if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(mainConfig), 0644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(filepath.Join(tmpDir, "extra.kdl"), []byte(extraConfig), 0644); err != nil { - t.Fatal(err) - } - - parser := NewNiriRulesParser(tmpDir) - rules, err := parser.Parse() - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - - if len(rules) != 2 { - t.Errorf("expected 2 rules, got %d", len(rules)) - } -} - -func TestNiriParseSizeNode(t *testing.T) { - tmpDir := t.TempDir() - - config := ` -window-rule { - match app-id="testapp" - default-column-width { fixed 800; } - default-window-height { proportion 0.5; } -} -` - if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(config), 0644); err != nil { - t.Fatal(err) - } - - parser := NewNiriRulesParser(tmpDir) - rules, err := parser.Parse() - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - - if len(rules) != 1 { - t.Fatalf("expected 1 rule, got %d", len(rules)) - } - - if rules[0].DefaultColumnWidth != "fixed 800" { - t.Errorf("DefaultColumnWidth = %q, want 'fixed 800'", rules[0].DefaultColumnWidth) - } - if rules[0].DefaultWindowHeight != "proportion 0.5" { - t.Errorf("DefaultWindowHeight = %q, want 'proportion 0.5'", rules[0].DefaultWindowHeight) - } -} - -func TestFormatSizeProperty(t *testing.T) { - tests := []struct { - name string - propName string - value string - want string - }{ - { - name: "fixed size", - propName: "default-column-width", - value: "fixed 800", - want: " default-column-width { fixed 800; }", - }, - { - name: "proportion", - propName: "default-window-height", - value: "proportion 0.5", - want: " default-window-height { proportion 0.5; }", - }, - { - name: "invalid format", - propName: "default-column-width", - value: "invalid", - want: " default-column-width { }", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := formatSizeProperty(tt.propName, tt.value) - if result != tt.want { - t.Errorf("formatSizeProperty(%q, %q) = %q, want %q", - tt.propName, tt.value, result, tt.want) - } - }) - } -} - -func TestNiriDMSRulesStatus(t *testing.T) { - tmpDir := t.TempDir() - - config := ` -window-rule { - match app-id="testapp" - opacity 0.9 -} -` - if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(config), 0644); err != nil { - t.Fatal(err) - } - - result, err := ParseNiriWindowRules(tmpDir) - if err != nil { - t.Fatalf("ParseNiriWindowRules failed: %v", err) - } - - if result.DMSStatus == nil { - t.Fatal("DMSStatus should not be nil") - } - - if result.DMSStatus.Exists { - t.Error("DMSStatus.Exists should be false when dms rules file doesn't exist") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/providers_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/providers_test.go deleted file mode 100644 index de84a38..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/providers/providers_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package providers - -import "github.com/AvengeMedia/DankMaterialShell/core/internal/windowrules" - -func newTestWindowRule(id, name, appID string) windowrules.WindowRule { - return windowrules.WindowRule{ - ID: id, - Name: name, - Enabled: true, - MatchCriteria: windowrules.MatchCriteria{ - AppID: appID, - }, - } -} - -func boolPtr(b bool) *bool { - return &b -} - -func floatPtr(f float64) *float64 { - return &f -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/types.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/types.go deleted file mode 100644 index 556acb7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/internal/windowrules/types.go +++ /dev/null @@ -1,103 +0,0 @@ -package windowrules - -type MatchCriteria struct { - AppID string `json:"appId,omitempty"` - Title string `json:"title,omitempty"` - IsFloating *bool `json:"isFloating,omitempty"` - IsActive *bool `json:"isActive,omitempty"` - IsFocused *bool `json:"isFocused,omitempty"` - IsActiveInColumn *bool `json:"isActiveInColumn,omitempty"` - IsWindowCastTarget *bool `json:"isWindowCastTarget,omitempty"` - IsUrgent *bool `json:"isUrgent,omitempty"` - AtStartup *bool `json:"atStartup,omitempty"` - XWayland *bool `json:"xwayland,omitempty"` - Fullscreen *bool `json:"fullscreen,omitempty"` - Pinned *bool `json:"pinned,omitempty"` - Initialised *bool `json:"initialised,omitempty"` -} - -type Actions struct { - Opacity *float64 `json:"opacity,omitempty"` - OpenFloating *bool `json:"openFloating,omitempty"` - OpenMaximized *bool `json:"openMaximized,omitempty"` - OpenMaximizedToEdges *bool `json:"openMaximizedToEdges,omitempty"` - OpenFullscreen *bool `json:"openFullscreen,omitempty"` - OpenFocused *bool `json:"openFocused,omitempty"` - OpenOnOutput string `json:"openOnOutput,omitempty"` - OpenOnWorkspace string `json:"openOnWorkspace,omitempty"` - DefaultColumnWidth string `json:"defaultColumnWidth,omitempty"` - DefaultWindowHeight string `json:"defaultWindowHeight,omitempty"` - VariableRefreshRate *bool `json:"variableRefreshRate,omitempty"` - BlockOutFrom string `json:"blockOutFrom,omitempty"` - DefaultColumnDisplay string `json:"defaultColumnDisplay,omitempty"` - ScrollFactor *float64 `json:"scrollFactor,omitempty"` - CornerRadius *int `json:"cornerRadius,omitempty"` - ClipToGeometry *bool `json:"clipToGeometry,omitempty"` - TiledState *bool `json:"tiledState,omitempty"` - MinWidth *int `json:"minWidth,omitempty"` - MaxWidth *int `json:"maxWidth,omitempty"` - MinHeight *int `json:"minHeight,omitempty"` - MaxHeight *int `json:"maxHeight,omitempty"` - BorderColor string `json:"borderColor,omitempty"` - FocusRingColor string `json:"focusRingColor,omitempty"` - FocusRingOff *bool `json:"focusRingOff,omitempty"` - BorderOff *bool `json:"borderOff,omitempty"` - DrawBorderWithBg *bool `json:"drawBorderWithBackground,omitempty"` - Size string `json:"size,omitempty"` - Move string `json:"move,omitempty"` - Monitor string `json:"monitor,omitempty"` - Workspace string `json:"workspace,omitempty"` - Tile *bool `json:"tile,omitempty"` - NoFocus *bool `json:"nofocus,omitempty"` - NoBorder *bool `json:"noborder,omitempty"` - NoShadow *bool `json:"noshadow,omitempty"` - NoDim *bool `json:"nodim,omitempty"` - NoBlur *bool `json:"noblur,omitempty"` - NoAnim *bool `json:"noanim,omitempty"` - NoRounding *bool `json:"norounding,omitempty"` - Pin *bool `json:"pin,omitempty"` - Opaque *bool `json:"opaque,omitempty"` - ForcergbX *bool `json:"forcergbx,omitempty"` - Idleinhibit string `json:"idleinhibit,omitempty"` -} - -type WindowRule struct { - ID string `json:"id"` - Name string `json:"name,omitempty"` - Enabled bool `json:"enabled"` - MatchCriteria MatchCriteria `json:"matchCriteria"` - Actions Actions `json:"actions"` - Source string `json:"source,omitempty"` -} - -type DMSRulesStatus struct { - Exists bool `json:"exists"` - Included bool `json:"included"` - IncludePosition int `json:"includePosition"` - TotalIncludes int `json:"totalIncludes"` - RulesAfterDMS int `json:"rulesAfterDms"` - Effective bool `json:"effective"` - OverriddenBy int `json:"overriddenBy"` - StatusMessage string `json:"statusMessage"` -} - -type RuleSet struct { - Title string `json:"title"` - Provider string `json:"provider"` - Rules []WindowRule `json:"rules"` - DMSRulesIncluded bool `json:"dmsRulesIncluded"` - DMSStatus *DMSRulesStatus `json:"dmsStatus,omitempty"` -} - -type Provider interface { - Name() string - GetRuleSet() (*RuleSet, error) -} - -type WritableProvider interface { - Provider - SetRule(rule WindowRule) error - RemoveRule(id string) error - ReorderRules(ids []string) error - GetOverridePath() string -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant.go deleted file mode 100644 index 4080b66..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant.go +++ /dev/null @@ -1,95 +0,0 @@ -package dbusutil - -import "github.com/godbus/dbus/v5" - -func As[T any](v dbus.Variant) (T, bool) { - val, ok := v.Value().(T) - return val, ok -} - -func AsOr[T any](v dbus.Variant, def T) T { - if val, ok := v.Value().(T); ok { - return val - } - return def -} - -func Get[T any](m map[string]dbus.Variant, key string) (T, bool) { - v, ok := m[key] - if !ok { - var zero T - return zero, false - } - return As[T](v) -} - -func GetOr[T any](m map[string]dbus.Variant, key string, def T) T { - v, ok := m[key] - if !ok { - return def - } - return AsOr(v, def) -} - -func Normalize(v any) any { - switch val := v.(type) { - case dbus.Variant: - return Normalize(val.Value()) - case dbus.ObjectPath: - return string(val) - case []dbus.ObjectPath: - result := make([]string, len(val)) - for i, p := range val { - result[i] = string(p) - } - return result - case map[string]dbus.Variant: - result := make(map[string]any) - for k, vv := range val { - result[k] = Normalize(vv.Value()) - } - return result - case map[string]any: - result := make(map[string]any) - for k, vv := range val { - result[k] = Normalize(vv) - } - return result - case map[dbus.ObjectPath]map[string]map[string]dbus.Variant: - result := make(map[string]any) - for path, ifaces := range val { - ifaceMap := make(map[string]any) - for ifaceName, props := range ifaces { - propMap := make(map[string]any) - for propName, propVal := range props { - propMap[propName] = Normalize(propVal.Value()) - } - ifaceMap[ifaceName] = propMap - } - result[string(path)] = ifaceMap - } - return result - case []any: - result := make([]any, len(val)) - for i, item := range val { - result[i] = Normalize(item) - } - return result - case []dbus.Variant: - result := make([]any, len(val)) - for i, item := range val { - result[i] = Normalize(item.Value()) - } - return result - default: - return v - } -} - -func NormalizeSlice(values []any) []any { - result := make([]any, len(values)) - for i, v := range values { - result[i] = Normalize(v) - } - return result -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant_test.go deleted file mode 100644 index a927e54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/dbusutil/variant_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package dbusutil - -import ( - "testing" - - "github.com/godbus/dbus/v5" - "github.com/stretchr/testify/assert" -) - -func TestAs(t *testing.T) { - t.Run("string", func(t *testing.T) { - v := dbus.MakeVariant("hello") - val, ok := As[string](v) - assert.True(t, ok) - assert.Equal(t, "hello", val) - }) - - t.Run("bool", func(t *testing.T) { - v := dbus.MakeVariant(true) - val, ok := As[bool](v) - assert.True(t, ok) - assert.True(t, val) - }) - - t.Run("int32", func(t *testing.T) { - v := dbus.MakeVariant(int32(42)) - val, ok := As[int32](v) - assert.True(t, ok) - assert.Equal(t, int32(42), val) - }) - - t.Run("wrong type", func(t *testing.T) { - v := dbus.MakeVariant("hello") - _, ok := As[int](v) - assert.False(t, ok) - }) -} - -func TestAsOr(t *testing.T) { - t.Run("exists", func(t *testing.T) { - v := dbus.MakeVariant("hello") - val := AsOr(v, "default") - assert.Equal(t, "hello", val) - }) - - t.Run("wrong type uses default", func(t *testing.T) { - v := dbus.MakeVariant(123) - val := AsOr(v, "default") - assert.Equal(t, "default", val) - }) -} - -func TestGet(t *testing.T) { - m := map[string]dbus.Variant{ - "name": dbus.MakeVariant("test"), - "enabled": dbus.MakeVariant(true), - "count": dbus.MakeVariant(int32(5)), - } - - t.Run("exists", func(t *testing.T) { - val, ok := Get[string](m, "name") - assert.True(t, ok) - assert.Equal(t, "test", val) - }) - - t.Run("missing key", func(t *testing.T) { - _, ok := Get[string](m, "missing") - assert.False(t, ok) - }) - - t.Run("wrong type", func(t *testing.T) { - _, ok := Get[int](m, "name") - assert.False(t, ok) - }) -} - -func TestGetOr(t *testing.T) { - m := map[string]dbus.Variant{ - "name": dbus.MakeVariant("test"), - } - - t.Run("exists", func(t *testing.T) { - val := GetOr(m, "name", "default") - assert.Equal(t, "test", val) - }) - - t.Run("missing uses default", func(t *testing.T) { - val := GetOr(m, "missing", "default") - assert.Equal(t, "default", val) - }) - - t.Run("wrong type uses default", func(t *testing.T) { - val := GetOr(m, "name", 42) - assert.Equal(t, 42, val) - }) -} - -func TestNormalize(t *testing.T) { - t.Run("variant unwrap", func(t *testing.T) { - v := dbus.MakeVariant("hello") - result := Normalize(v) - assert.Equal(t, "hello", result) - }) - - t.Run("nested variant", func(t *testing.T) { - v := dbus.MakeVariant(dbus.MakeVariant("nested")) - result := Normalize(v) - assert.Equal(t, "nested", result) - }) - - t.Run("object path", func(t *testing.T) { - v := dbus.ObjectPath("/org/test") - result := Normalize(v) - assert.Equal(t, "/org/test", result) - }) - - t.Run("object path slice", func(t *testing.T) { - v := []dbus.ObjectPath{"/org/a", "/org/b"} - result := Normalize(v) - assert.Equal(t, []string{"/org/a", "/org/b"}, result) - }) - - t.Run("variant map", func(t *testing.T) { - v := map[string]dbus.Variant{ - "key": dbus.MakeVariant("value"), - } - result := Normalize(v) - expected := map[string]any{"key": "value"} - assert.Equal(t, expected, result) - }) - - t.Run("any slice", func(t *testing.T) { - v := []any{dbus.MakeVariant("a"), dbus.ObjectPath("/b")} - result := Normalize(v) - expected := []any{"a", "/b"} - assert.Equal(t, expected, result) - }) - - t.Run("passthrough primitives", func(t *testing.T) { - assert.Equal(t, "hello", Normalize("hello")) - assert.Equal(t, 42, Normalize(42)) - assert.Equal(t, true, Normalize(true)) - }) -} - -func TestNormalizeSlice(t *testing.T) { - input := []any{ - dbus.MakeVariant("a"), - dbus.ObjectPath("/b"), - "c", - } - result := NormalizeSlice(input) - expected := []any{"a", "/b", "c"} - assert.Equal(t, expected, result) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/AUTHORS b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/AUTHORS deleted file mode 100644 index 7b24eab..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -// Keep this sorted - -rajveermalviya diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/LICENSE deleted file mode 100644 index 4da3300..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright 2021 go-wayland authors - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/README.md deleted file mode 100644 index 9e52d99..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Wayland implementation in Go - -[![Go Reference](https://pkg.go.dev/badge/github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland.svg)](https://pkg.go.dev/github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland) - -This module contains pure Go implementation of the Wayland protocol. -Currently only wayland-client functionality is supported. - -Go code is generated from protocol XML files using -[`go-wayland-scanner`](cmd/go-wayland-scanner/scanner.go). - -To load cursor, minimal port of `wayland-cursor` & `xcursor` in pure Go -is located at [`wayland/cursor`](wayland/cursor) & [`wayland/cursor/xcursor`](wayland/cursor/xcursor) -respectively. - -To demonstrate the functionality of this module -[`examples/imageviewer`](examples/imageviewer) contains a simple image -viewer. It demos displaying a top-level window, resizing of window, -cursor themes, pointer and keyboard. Because it's in pure Go, it can be -compiled without CGO. You can try it using the following commands: - -```sh -CGO_ENABLED=0 go install github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/examples/imageviewer@latest - -imageviewer file.jpg -``` diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generate b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generate deleted file mode 100755 index 02ad975..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generate +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd ./wayland -go generate -x ./... diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generatep b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generatep deleted file mode 100755 index bd660d7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/generatep +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh - -# Runs go generate for each directory, but in parallel. Any arguments are appended to the -# go generate command. -# Usage: $ ./generatep [go generate arguments] -# Print all generate commands: $ ./generatep -x - -cd ./wayland || exit 1 -find . -type f -name '*.go' -exec dirname {} \; | sort -u | parallel -j 0 go generate "$1" {}/. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/client.go deleted file mode 100644 index fd49c20..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/client.go +++ /dev/null @@ -1,7542 +0,0 @@ -// Generated by go-wayland-scanner -// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner -// XML file : https://gitlab.freedesktop.org/wayland/wayland/-/raw/1.24.0/protocol/wayland.xml?ref_type=tags -// -// wayland Protocol Copyright: -// -// Copyright © 2008-2011 Kristian Høgsberg -// Copyright © 2010-2011 Intel Corporation -// Copyright © 2012-2013 Collabora, Ltd. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation files -// (the "Software"), to deal in the Software without restriction, -// including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, -// and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice (including the -// next paragraph) shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -package client - -import "golang.org/x/sys/unix" - -// DisplayInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const DisplayInterfaceName = "wl_display" - -// Display : core global object -// -// The core global object. This is a special singleton object. It -// is used for internal Wayland protocol features. -type Display struct { - BaseProxy - errorHandler DisplayErrorHandlerFunc - deleteIdHandler DisplayDeleteIdHandlerFunc -} - -// NewDisplay : core global object -// -// The core global object. This is a special singleton object. It -// is used for internal Wayland protocol features. -func NewDisplay(ctx *Context) *Display { - wlDisplay := &Display{} - ctx.Register(wlDisplay) - return wlDisplay -} - -// Sync : asynchronous roundtrip -// -// The sync request asks the server to emit the 'done' event -// on the returned wl_callback object. Since requests are -// handled in-order and events are delivered in-order, this can -// be used as a barrier to ensure all previous requests and the -// resulting events have been handled. -// -// The object returned by this request will be destroyed by the -// compositor after the callback is fired and as such the client must not -// attempt to use it after that point. -// -// The callback_data passed in the callback is undefined and should be ignored. -func (i *Display) Sync() (*Callback, error) { - callback := NewCallback(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], callback.ID()) - err := i.Context().WriteMsg(_reqBuf[:], nil) - return callback, err -} - -// GetRegistry : get global registry object -// -// This request creates a registry object that allows the client -// to list and bind the global objects available from the -// compositor. -// -// It should be noted that the server side resources consumed in -// response to a get_registry request can only be released when the -// client disconnects, not when the client side proxy is destroyed. -// Therefore, clients should invoke get_registry as infrequently as -// possible to avoid wasting memory. -func (i *Display) GetRegistry() (*Registry, error) { - registry := NewRegistry(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], registry.ID()) - err := i.Context().WriteMsg(_reqBuf[:], nil) - return registry, err -} - -func (i *Display) Destroy() error { - i.MarkZombie() - return nil -} - -type DisplayError uint32 - -// DisplayError : global error values -// -// These errors are global and can be emitted in response to any -// server request. -const ( - // DisplayErrorInvalidObject : server couldn't find object - DisplayErrorInvalidObject DisplayError = 0 - // DisplayErrorInvalidMethod : method doesn't exist on the specified interface or malformed request - DisplayErrorInvalidMethod DisplayError = 1 - // DisplayErrorNoMemory : server is out of memory - DisplayErrorNoMemory DisplayError = 2 - // DisplayErrorImplementation : implementation error in compositor - DisplayErrorImplementation DisplayError = 3 -) - -func (e DisplayError) Name() string { - switch e { - case DisplayErrorInvalidObject: - return "invalid_object" - case DisplayErrorInvalidMethod: - return "invalid_method" - case DisplayErrorNoMemory: - return "no_memory" - case DisplayErrorImplementation: - return "implementation" - default: - return "" - } -} - -func (e DisplayError) Value() string { - switch e { - case DisplayErrorInvalidObject: - return "0" - case DisplayErrorInvalidMethod: - return "1" - case DisplayErrorNoMemory: - return "2" - case DisplayErrorImplementation: - return "3" - default: - return "" - } -} - -func (e DisplayError) String() string { - return e.Name() + "=" + e.Value() -} - -// DisplayErrorEvent : fatal error event -// -// The error event is sent out when a fatal (non-recoverable) -// error has occurred. The object_id argument is the object -// where the error occurred, most often in response to a request -// to that object. The code identifies the error and is defined -// by the object interface. As such, each interface defines its -// own set of error codes. The message is a brief description -// of the error, for (debugging) convenience. -type DisplayErrorEvent struct { - ObjectId Proxy - Code uint32 - Message string -} -type DisplayErrorHandlerFunc func(DisplayErrorEvent) - -// SetErrorHandler : sets handler for DisplayErrorEvent -func (i *Display) SetErrorHandler(f DisplayErrorHandlerFunc) { - i.errorHandler = f -} - -// DisplayDeleteIdEvent : acknowledge object ID deletion -// -// This event is used internally by the object ID management -// logic. When a client deletes an object that it had created, -// the server will send this event to acknowledge that it has -// seen the delete request. When the client receives this event, -// it will know that it can safely reuse the object ID. -type DisplayDeleteIdEvent struct { - Id uint32 -} -type DisplayDeleteIdHandlerFunc func(DisplayDeleteIdEvent) - -// SetDeleteIdHandler : sets handler for DisplayDeleteIdEvent -func (i *Display) SetDeleteIdHandler(f DisplayDeleteIdHandlerFunc) { - i.deleteIdHandler = f -} - -func (i *Display) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.errorHandler == nil { - return - } - var e DisplayErrorEvent - l := 0 - e.ObjectId = i.Context().GetProxy(Uint32(data[l : l+4])) - l += 4 - e.Code = Uint32(data[l : l+4]) - l += 4 - messageLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Message = String(data[l : l+messageLen]) - - i.errorHandler(e) - case 1: - var e DisplayDeleteIdEvent - l := 0 - e.Id = Uint32(data[l : l+4]) - l += 4 - - i.Context().DeleteID(e.Id) - - if i.deleteIdHandler != nil { - i.deleteIdHandler(e) - } - } -} - -// RegistryInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const RegistryInterfaceName = "wl_registry" - -// Registry : global registry object -// -// The singleton global registry object. The server has a number of -// global objects that are available to all clients. These objects -// typically represent an actual object in the server (for example, -// an input device) or they are singleton objects that provide -// extension functionality. -// -// When a client creates a registry object, the registry object -// will emit a global event for each global currently in the -// registry. Globals come and go as a result of device or -// monitor hotplugs, reconfiguration or other events, and the -// registry will send out global and global_remove events to -// keep the client up to date with the changes. To mark the end -// of the initial burst of events, the client can use the -// wl_display.sync request immediately after calling -// wl_display.get_registry. -// -// A client can bind to a global object by using the bind -// request. This creates a client-side handle that lets the object -// emit events to the client and lets the client invoke requests on -// the object. -type Registry struct { - BaseProxy - globalHandler RegistryGlobalHandlerFunc - globalRemoveHandler RegistryGlobalRemoveHandlerFunc -} - -// NewRegistry : global registry object -// -// The singleton global registry object. The server has a number of -// global objects that are available to all clients. These objects -// typically represent an actual object in the server (for example, -// an input device) or they are singleton objects that provide -// extension functionality. -// -// When a client creates a registry object, the registry object -// will emit a global event for each global currently in the -// registry. Globals come and go as a result of device or -// monitor hotplugs, reconfiguration or other events, and the -// registry will send out global and global_remove events to -// keep the client up to date with the changes. To mark the end -// of the initial burst of events, the client can use the -// wl_display.sync request immediately after calling -// wl_display.get_registry. -// -// A client can bind to a global object by using the bind -// request. This creates a client-side handle that lets the object -// emit events to the client and lets the client invoke requests on -// the object. -func NewRegistry(ctx *Context) *Registry { - wlRegistry := &Registry{} - ctx.Register(wlRegistry) - return wlRegistry -} - -// Bind : bind an object to the display -// -// Binds a new, client-created object to the server using the -// specified name as the identifier. -// -// name: unique numeric name of the object -func (i *Registry) Bind(name uint32, iface string, version uint32, id Proxy) error { - const opcode = 0 - ifaceLen := PaddedLen(len(iface) + 1) - _reqBufLen := 8 + 4 + (4 + ifaceLen) + 4 + 4 - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(name)) - l += 4 - PutString(_reqBuf[l:l+(4+ifaceLen)], iface) - l += (4 + ifaceLen) - PutUint32(_reqBuf[l:l+4], uint32(version)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -func (i *Registry) Destroy() error { - i.MarkZombie() - return nil -} - -// RegistryGlobalEvent : announce global object -// -// Notify the client of global objects. -// -// The event notifies the client that a global object with -// the given name is now available, and it implements the -// given version of the given interface. -type RegistryGlobalEvent struct { - Name uint32 - Interface string - Version uint32 -} -type RegistryGlobalHandlerFunc func(RegistryGlobalEvent) - -// SetGlobalHandler : sets handler for RegistryGlobalEvent -func (i *Registry) SetGlobalHandler(f RegistryGlobalHandlerFunc) { - i.globalHandler = f -} - -// RegistryGlobalRemoveEvent : announce removal of global object -// -// Notify the client of removed global objects. -// -// This event notifies the client that the global identified -// by name is no longer available. If the client bound to -// the global using the bind request, the client should now -// destroy that object. -// -// The object remains valid and requests to the object will be -// ignored until the client destroys it, to avoid races between -// the global going away and a client sending a request to it. -type RegistryGlobalRemoveEvent struct { - Name uint32 -} -type RegistryGlobalRemoveHandlerFunc func(RegistryGlobalRemoveEvent) - -// SetGlobalRemoveHandler : sets handler for RegistryGlobalRemoveEvent -func (i *Registry) SetGlobalRemoveHandler(f RegistryGlobalRemoveHandlerFunc) { - i.globalRemoveHandler = f -} - -func (i *Registry) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.globalHandler == nil { - return - } - var e RegistryGlobalEvent - l := 0 - e.Name = Uint32(data[l : l+4]) - l += 4 - interfaceLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Interface = String(data[l : l+interfaceLen]) - l += interfaceLen - e.Version = Uint32(data[l : l+4]) - l += 4 - - i.globalHandler(e) - case 1: - if i.globalRemoveHandler == nil { - return - } - var e RegistryGlobalRemoveEvent - l := 0 - e.Name = Uint32(data[l : l+4]) - l += 4 - - i.globalRemoveHandler(e) - } -} - -// CallbackInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const CallbackInterfaceName = "wl_callback" - -// Callback : callback object -// -// Clients can handle the 'done' event to get notified when -// the related request is done. -// -// Note, because wl_callback objects are created from multiple independent -// factory interfaces, the wl_callback interface is frozen at version 1. -type Callback struct { - BaseProxy - doneHandler CallbackDoneHandlerFunc -} - -// NewCallback : callback object -// -// Clients can handle the 'done' event to get notified when -// the related request is done. -// -// Note, because wl_callback objects are created from multiple independent -// factory interfaces, the wl_callback interface is frozen at version 1. -func NewCallback(ctx *Context) *Callback { - wlCallback := &Callback{} - ctx.Register(wlCallback) - return wlCallback -} - -func (i *Callback) Destroy() error { - i.MarkZombie() - return nil -} - -// CallbackDoneEvent : done event -// -// Notify the client when the related request is done. -type CallbackDoneEvent struct { - CallbackData uint32 -} -type CallbackDoneHandlerFunc func(CallbackDoneEvent) - -// SetDoneHandler : sets handler for CallbackDoneEvent -func (i *Callback) SetDoneHandler(f CallbackDoneHandlerFunc) { - i.doneHandler = f -} - -func (i *Callback) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.doneHandler == nil { - return - } - var e CallbackDoneEvent - l := 0 - e.CallbackData = Uint32(data[l : l+4]) - l += 4 - - i.doneHandler(e) - } -} - -// CompositorInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const CompositorInterfaceName = "wl_compositor" - -// Compositor : the compositor singleton -// -// A compositor. This object is a singleton global. The -// compositor is in charge of combining the contents of multiple -// surfaces into one displayable output. -type Compositor struct { - BaseProxy -} - -// NewCompositor : the compositor singleton -// -// A compositor. This object is a singleton global. The -// compositor is in charge of combining the contents of multiple -// surfaces into one displayable output. -func NewCompositor(ctx *Context) *Compositor { - wlCompositor := &Compositor{} - ctx.Register(wlCompositor) - return wlCompositor -} - -// CreateSurface : create new surface -// -// Ask the compositor to create a new surface. -func (i *Compositor) CreateSurface() (*Surface, error) { - id := NewSurface(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// CreateRegion : create new region -// -// Ask the compositor to create a new region. -func (i *Compositor) CreateRegion() (*Region, error) { - id := NewRegion(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -func (i *Compositor) Destroy() error { - i.MarkZombie() - return nil -} - -// ShmPoolInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ShmPoolInterfaceName = "wl_shm_pool" - -// ShmPool : a shared memory pool -// -// The wl_shm_pool object encapsulates a piece of memory shared -// between the compositor and client. Through the wl_shm_pool -// object, the client can allocate shared memory wl_buffer objects. -// All objects created through the same pool share the same -// underlying mapped memory. Reusing the mapped memory avoids the -// setup/teardown overhead and is useful when interactively resizing -// a surface or for many small buffers. -type ShmPool struct { - BaseProxy -} - -// NewShmPool : a shared memory pool -// -// The wl_shm_pool object encapsulates a piece of memory shared -// between the compositor and client. Through the wl_shm_pool -// object, the client can allocate shared memory wl_buffer objects. -// All objects created through the same pool share the same -// underlying mapped memory. Reusing the mapped memory avoids the -// setup/teardown overhead and is useful when interactively resizing -// a surface or for many small buffers. -func NewShmPool(ctx *Context) *ShmPool { - wlShmPool := &ShmPool{} - ctx.Register(wlShmPool) - return wlShmPool -} - -// CreateBuffer : create a buffer from the pool -// -// Create a wl_buffer object from the pool. -// -// The buffer is created offset bytes into the pool and has -// width and height as specified. The stride argument specifies -// the number of bytes from the beginning of one row to the beginning -// of the next. The format is the pixel format of the buffer and -// must be one of those advertised through the wl_shm.format event. -// -// A buffer will keep a reference to the pool it was created from -// so it is valid to destroy the pool immediately after creating -// a buffer from it. -// -// offset: buffer byte offset within the pool -// width: buffer width, in pixels -// height: buffer height, in pixels -// stride: number of bytes from the beginning of one row to the beginning of the next row -// format: buffer pixel format -func (i *ShmPool) CreateBuffer(offset, width, height, stride int32, format uint32) (*Buffer, error) { - id := NewBuffer(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(offset)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(stride)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(format)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// Destroy : destroy the pool -// -// Destroy the shared memory pool. -// -// The mmapped memory will be released when all -// buffers that have been created from this pool -// are gone. -func (i *ShmPool) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Resize : change the size of the pool mapping -// -// This request will cause the server to remap the backing memory -// for the pool from the file descriptor passed when the pool was -// created, but using the new size. This request can only be -// used to make the pool bigger. -// -// This request only changes the amount of bytes that are mmapped -// by the server and does not touch the file corresponding to the -// file descriptor passed at creation time. It is the client's -// responsibility to ensure that the file is at least as big as -// the new pool size. -// -// size: new size of the pool, in bytes -func (i *ShmPool) Resize(size int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(size)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// ShmInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ShmInterfaceName = "wl_shm" - -// Shm : shared memory support -// -// A singleton global object that provides support for shared -// memory. -// -// Clients can create wl_shm_pool objects using the create_pool -// request. -// -// On binding the wl_shm object one or more format events -// are emitted to inform clients about the valid pixel formats -// that can be used for buffers. -type Shm struct { - BaseProxy - formatHandler ShmFormatHandlerFunc -} - -// NewShm : shared memory support -// -// A singleton global object that provides support for shared -// memory. -// -// Clients can create wl_shm_pool objects using the create_pool -// request. -// -// On binding the wl_shm object one or more format events -// are emitted to inform clients about the valid pixel formats -// that can be used for buffers. -func NewShm(ctx *Context) *Shm { - wlShm := &Shm{} - ctx.Register(wlShm) - return wlShm -} - -// CreatePool : create a shm pool -// -// Create a new wl_shm_pool object. -// -// The pool can be used to create shared memory based buffer -// objects. The server will mmap size bytes of the passed file -// descriptor, to use as backing memory for the pool. -// -// fd: file descriptor for the pool -// size: pool size, in bytes -func (i *Shm) CreatePool(fd int, size int32) (*ShmPool, error) { - id := NewShmPool(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(size)) - l += 4 - oob := unix.UnixRights(int(fd)) - err := i.Context().WriteMsg(_reqBuf[:], oob) - return id, err -} - -// Release : release the shm object -// -// Using this request a client can tell the server that it is not going to -// use the shm object anymore. -// -// Objects created via this interface remain unaffected. -func (i *Shm) Release() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type ShmError uint32 - -// ShmError : wl_shm error values -// -// These errors can be emitted in response to wl_shm requests. -const ( - // ShmErrorInvalidFormat : buffer format is not known - ShmErrorInvalidFormat ShmError = 0 - // ShmErrorInvalidStride : invalid size or stride during pool or buffer creation - ShmErrorInvalidStride ShmError = 1 - // ShmErrorInvalidFd : mmapping the file descriptor failed - ShmErrorInvalidFd ShmError = 2 -) - -func (e ShmError) Name() string { - switch e { - case ShmErrorInvalidFormat: - return "invalid_format" - case ShmErrorInvalidStride: - return "invalid_stride" - case ShmErrorInvalidFd: - return "invalid_fd" - default: - return "" - } -} - -func (e ShmError) Value() string { - switch e { - case ShmErrorInvalidFormat: - return "0" - case ShmErrorInvalidStride: - return "1" - case ShmErrorInvalidFd: - return "2" - default: - return "" - } -} - -func (e ShmError) String() string { - return e.Name() + "=" + e.Value() -} - -type ShmFormat uint32 - -// ShmFormat : pixel formats -// -// This describes the memory layout of an individual pixel. -// -// All renderers should support argb8888 and xrgb8888 but any other -// formats are optional and may not be supported by the particular -// renderer in use. -// -// The drm format codes match the macros defined in drm_fourcc.h, except -// argb8888 and xrgb8888. The formats actually supported by the compositor -// will be reported by the format event. -// -// For all wl_shm formats and unless specified in another protocol -// extension, pre-multiplied alpha is used for pixel values. -const ( - // ShmFormatArgb8888 : 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian - ShmFormatArgb8888 ShmFormat = 0 - // ShmFormatXrgb8888 : 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian - ShmFormatXrgb8888 ShmFormat = 1 - // ShmFormatC8 : 8-bit color index format, [7:0] C - ShmFormatC8 ShmFormat = 0x20203843 - // ShmFormatRgb332 : 8-bit RGB format, [7:0] R:G:B 3:3:2 - ShmFormatRgb332 ShmFormat = 0x38424752 - // ShmFormatBgr233 : 8-bit BGR format, [7:0] B:G:R 2:3:3 - ShmFormatBgr233 ShmFormat = 0x38524742 - // ShmFormatXrgb4444 : 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian - ShmFormatXrgb4444 ShmFormat = 0x32315258 - // ShmFormatXbgr4444 : 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian - ShmFormatXbgr4444 ShmFormat = 0x32314258 - // ShmFormatRgbx4444 : 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian - ShmFormatRgbx4444 ShmFormat = 0x32315852 - // ShmFormatBgrx4444 : 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian - ShmFormatBgrx4444 ShmFormat = 0x32315842 - // ShmFormatArgb4444 : 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian - ShmFormatArgb4444 ShmFormat = 0x32315241 - // ShmFormatAbgr4444 : 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian - ShmFormatAbgr4444 ShmFormat = 0x32314241 - // ShmFormatRgba4444 : 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian - ShmFormatRgba4444 ShmFormat = 0x32314152 - // ShmFormatBgra4444 : 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian - ShmFormatBgra4444 ShmFormat = 0x32314142 - // ShmFormatXrgb1555 : 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian - ShmFormatXrgb1555 ShmFormat = 0x35315258 - // ShmFormatXbgr1555 : 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian - ShmFormatXbgr1555 ShmFormat = 0x35314258 - // ShmFormatRgbx5551 : 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian - ShmFormatRgbx5551 ShmFormat = 0x35315852 - // ShmFormatBgrx5551 : 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian - ShmFormatBgrx5551 ShmFormat = 0x35315842 - // ShmFormatArgb1555 : 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian - ShmFormatArgb1555 ShmFormat = 0x35315241 - // ShmFormatAbgr1555 : 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian - ShmFormatAbgr1555 ShmFormat = 0x35314241 - // ShmFormatRgba5551 : 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian - ShmFormatRgba5551 ShmFormat = 0x35314152 - // ShmFormatBgra5551 : 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian - ShmFormatBgra5551 ShmFormat = 0x35314142 - // ShmFormatRgb565 : 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian - ShmFormatRgb565 ShmFormat = 0x36314752 - // ShmFormatBgr565 : 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian - ShmFormatBgr565 ShmFormat = 0x36314742 - // ShmFormatRgb888 : 24-bit RGB format, [23:0] R:G:B little endian - ShmFormatRgb888 ShmFormat = 0x34324752 - // ShmFormatBgr888 : 24-bit BGR format, [23:0] B:G:R little endian - ShmFormatBgr888 ShmFormat = 0x34324742 - // ShmFormatXbgr8888 : 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian - ShmFormatXbgr8888 ShmFormat = 0x34324258 - // ShmFormatRgbx8888 : 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian - ShmFormatRgbx8888 ShmFormat = 0x34325852 - // ShmFormatBgrx8888 : 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian - ShmFormatBgrx8888 ShmFormat = 0x34325842 - // ShmFormatAbgr8888 : 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian - ShmFormatAbgr8888 ShmFormat = 0x34324241 - // ShmFormatRgba8888 : 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian - ShmFormatRgba8888 ShmFormat = 0x34324152 - // ShmFormatBgra8888 : 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian - ShmFormatBgra8888 ShmFormat = 0x34324142 - // ShmFormatXrgb2101010 : 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian - ShmFormatXrgb2101010 ShmFormat = 0x30335258 - // ShmFormatXbgr2101010 : 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian - ShmFormatXbgr2101010 ShmFormat = 0x30334258 - // ShmFormatRgbx1010102 : 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian - ShmFormatRgbx1010102 ShmFormat = 0x30335852 - // ShmFormatBgrx1010102 : 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian - ShmFormatBgrx1010102 ShmFormat = 0x30335842 - // ShmFormatArgb2101010 : 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian - ShmFormatArgb2101010 ShmFormat = 0x30335241 - // ShmFormatAbgr2101010 : 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian - ShmFormatAbgr2101010 ShmFormat = 0x30334241 - // ShmFormatRgba1010102 : 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian - ShmFormatRgba1010102 ShmFormat = 0x30334152 - // ShmFormatBgra1010102 : 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian - ShmFormatBgra1010102 ShmFormat = 0x30334142 - // ShmFormatYuyv : packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian - ShmFormatYuyv ShmFormat = 0x56595559 - // ShmFormatYvyu : packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian - ShmFormatYvyu ShmFormat = 0x55595659 - // ShmFormatUyvy : packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian - ShmFormatUyvy ShmFormat = 0x59565955 - // ShmFormatVyuy : packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian - ShmFormatVyuy ShmFormat = 0x59555956 - // ShmFormatAyuv : packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian - ShmFormatAyuv ShmFormat = 0x56555941 - // ShmFormatNv12 : 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane - ShmFormatNv12 ShmFormat = 0x3231564e - // ShmFormatNv21 : 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane - ShmFormatNv21 ShmFormat = 0x3132564e - // ShmFormatNv16 : 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane - ShmFormatNv16 ShmFormat = 0x3631564e - // ShmFormatNv61 : 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane - ShmFormatNv61 ShmFormat = 0x3136564e - // ShmFormatYuv410 : 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes - ShmFormatYuv410 ShmFormat = 0x39565559 - // ShmFormatYvu410 : 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes - ShmFormatYvu410 ShmFormat = 0x39555659 - // ShmFormatYuv411 : 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes - ShmFormatYuv411 ShmFormat = 0x31315559 - // ShmFormatYvu411 : 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes - ShmFormatYvu411 ShmFormat = 0x31315659 - // ShmFormatYuv420 : 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes - ShmFormatYuv420 ShmFormat = 0x32315559 - // ShmFormatYvu420 : 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes - ShmFormatYvu420 ShmFormat = 0x32315659 - // ShmFormatYuv422 : 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes - ShmFormatYuv422 ShmFormat = 0x36315559 - // ShmFormatYvu422 : 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes - ShmFormatYvu422 ShmFormat = 0x36315659 - // ShmFormatYuv444 : 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes - ShmFormatYuv444 ShmFormat = 0x34325559 - // ShmFormatYvu444 : 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes - ShmFormatYvu444 ShmFormat = 0x34325659 - // ShmFormatR8 : [7:0] R - ShmFormatR8 ShmFormat = 0x20203852 - // ShmFormatR16 : [15:0] R little endian - ShmFormatR16 ShmFormat = 0x20363152 - // ShmFormatRg88 : [15:0] R:G 8:8 little endian - ShmFormatRg88 ShmFormat = 0x38384752 - // ShmFormatGr88 : [15:0] G:R 8:8 little endian - ShmFormatGr88 ShmFormat = 0x38385247 - // ShmFormatRg1616 : [31:0] R:G 16:16 little endian - ShmFormatRg1616 ShmFormat = 0x32334752 - // ShmFormatGr1616 : [31:0] G:R 16:16 little endian - ShmFormatGr1616 ShmFormat = 0x32335247 - // ShmFormatXrgb16161616F : [63:0] x:R:G:B 16:16:16:16 little endian - ShmFormatXrgb16161616F ShmFormat = 0x48345258 - // ShmFormatXbgr16161616F : [63:0] x:B:G:R 16:16:16:16 little endian - ShmFormatXbgr16161616F ShmFormat = 0x48344258 - // ShmFormatArgb16161616F : [63:0] A:R:G:B 16:16:16:16 little endian - ShmFormatArgb16161616F ShmFormat = 0x48345241 - // ShmFormatAbgr16161616F : [63:0] A:B:G:R 16:16:16:16 little endian - ShmFormatAbgr16161616F ShmFormat = 0x48344241 - // ShmFormatXyuv8888 : [31:0] X:Y:Cb:Cr 8:8:8:8 little endian - ShmFormatXyuv8888 ShmFormat = 0x56555958 - // ShmFormatVuy888 : [23:0] Cr:Cb:Y 8:8:8 little endian - ShmFormatVuy888 ShmFormat = 0x34325556 - // ShmFormatVuy101010 : Y followed by U then V, 10:10:10. - ShmFormatVuy101010 ShmFormat = 0x30335556 - // ShmFormatY210 : [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels - ShmFormatY210 ShmFormat = 0x30313259 - // ShmFormatY212 : [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels - ShmFormatY212 ShmFormat = 0x32313259 - // ShmFormatY216 : [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels - ShmFormatY216 ShmFormat = 0x36313259 - // ShmFormatY410 : [31:0] A:Cr:Y:Cb 2:10:10:10 little endian - ShmFormatY410 ShmFormat = 0x30313459 - // ShmFormatY412 : [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - ShmFormatY412 ShmFormat = 0x32313459 - // ShmFormatY416 : [63:0] A:Cr:Y:Cb 16:16:16:16 little endian - ShmFormatY416 ShmFormat = 0x36313459 - // ShmFormatXvyu2101010 : [31:0] X:Cr:Y:Cb 2:10:10:10 little endian - ShmFormatXvyu2101010 ShmFormat = 0x30335658 - // ShmFormatXvyu1216161616 : [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - ShmFormatXvyu1216161616 ShmFormat = 0x36335658 - // ShmFormatXvyu16161616 : [63:0] X:Cr:Y:Cb 16:16:16:16 little endian - ShmFormatXvyu16161616 ShmFormat = 0x38345658 - // ShmFormatY0L0 : [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - ShmFormatY0L0 ShmFormat = 0x304c3059 - // ShmFormatX0L0 : [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - ShmFormatX0L0 ShmFormat = 0x304c3058 - // ShmFormatY0L2 : [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - ShmFormatY0L2 ShmFormat = 0x324c3059 - // ShmFormatX0L2 : [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - ShmFormatX0L2 ShmFormat = 0x324c3058 - ShmFormatYuv4208Bit ShmFormat = 0x38305559 - ShmFormatYuv42010Bit ShmFormat = 0x30315559 - ShmFormatXrgb8888A8 ShmFormat = 0x38415258 - ShmFormatXbgr8888A8 ShmFormat = 0x38414258 - ShmFormatRgbx8888A8 ShmFormat = 0x38415852 - ShmFormatBgrx8888A8 ShmFormat = 0x38415842 - ShmFormatRgb888A8 ShmFormat = 0x38413852 - ShmFormatBgr888A8 ShmFormat = 0x38413842 - ShmFormatRgb565A8 ShmFormat = 0x38413552 - ShmFormatBgr565A8 ShmFormat = 0x38413542 - // ShmFormatNv24 : non-subsampled Cr:Cb plane - ShmFormatNv24 ShmFormat = 0x3432564e - // ShmFormatNv42 : non-subsampled Cb:Cr plane - ShmFormatNv42 ShmFormat = 0x3234564e - // ShmFormatP210 : 2x1 subsampled Cr:Cb plane, 10 bit per channel - ShmFormatP210 ShmFormat = 0x30313250 - // ShmFormatP010 : 2x2 subsampled Cr:Cb plane 10 bits per channel - ShmFormatP010 ShmFormat = 0x30313050 - // ShmFormatP012 : 2x2 subsampled Cr:Cb plane 12 bits per channel - ShmFormatP012 ShmFormat = 0x32313050 - // ShmFormatP016 : 2x2 subsampled Cr:Cb plane 16 bits per channel - ShmFormatP016 ShmFormat = 0x36313050 - // ShmFormatAxbxgxrx106106106106 : [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian - ShmFormatAxbxgxrx106106106106 ShmFormat = 0x30314241 - // ShmFormatNv15 : 2x2 subsampled Cr:Cb plane - ShmFormatNv15 ShmFormat = 0x3531564e - ShmFormatQ410 ShmFormat = 0x30313451 - ShmFormatQ401 ShmFormat = 0x31303451 - // ShmFormatXrgb16161616 : [63:0] x:R:G:B 16:16:16:16 little endian - ShmFormatXrgb16161616 ShmFormat = 0x38345258 - // ShmFormatXbgr16161616 : [63:0] x:B:G:R 16:16:16:16 little endian - ShmFormatXbgr16161616 ShmFormat = 0x38344258 - // ShmFormatArgb16161616 : [63:0] A:R:G:B 16:16:16:16 little endian - ShmFormatArgb16161616 ShmFormat = 0x38345241 - // ShmFormatAbgr16161616 : [63:0] A:B:G:R 16:16:16:16 little endian - ShmFormatAbgr16161616 ShmFormat = 0x38344241 - // ShmFormatC1 : [7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte - ShmFormatC1 ShmFormat = 0x20203143 - // ShmFormatC2 : [7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte - ShmFormatC2 ShmFormat = 0x20203243 - // ShmFormatC4 : [7:0] C0:C1 4:4 two pixels/byte - ShmFormatC4 ShmFormat = 0x20203443 - // ShmFormatD1 : [7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte - ShmFormatD1 ShmFormat = 0x20203144 - // ShmFormatD2 : [7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte - ShmFormatD2 ShmFormat = 0x20203244 - // ShmFormatD4 : [7:0] D0:D1 4:4 two pixels/byte - ShmFormatD4 ShmFormat = 0x20203444 - // ShmFormatD8 : [7:0] D - ShmFormatD8 ShmFormat = 0x20203844 - // ShmFormatR1 : [7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte - ShmFormatR1 ShmFormat = 0x20203152 - // ShmFormatR2 : [7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte - ShmFormatR2 ShmFormat = 0x20203252 - // ShmFormatR4 : [7:0] R0:R1 4:4 two pixels/byte - ShmFormatR4 ShmFormat = 0x20203452 - // ShmFormatR10 : [15:0] x:R 6:10 little endian - ShmFormatR10 ShmFormat = 0x20303152 - // ShmFormatR12 : [15:0] x:R 4:12 little endian - ShmFormatR12 ShmFormat = 0x20323152 - // ShmFormatAvuy8888 : [31:0] A:Cr:Cb:Y 8:8:8:8 little endian - ShmFormatAvuy8888 ShmFormat = 0x59555641 - // ShmFormatXvuy8888 : [31:0] X:Cr:Cb:Y 8:8:8:8 little endian - ShmFormatXvuy8888 ShmFormat = 0x59555658 - // ShmFormatP030 : 2x2 subsampled Cr:Cb plane 10 bits per channel packed - ShmFormatP030 ShmFormat = 0x30333050 -) - -func (e ShmFormat) Name() string { - switch e { - case ShmFormatArgb8888: - return "argb8888" - case ShmFormatXrgb8888: - return "xrgb8888" - case ShmFormatC8: - return "c8" - case ShmFormatRgb332: - return "rgb332" - case ShmFormatBgr233: - return "bgr233" - case ShmFormatXrgb4444: - return "xrgb4444" - case ShmFormatXbgr4444: - return "xbgr4444" - case ShmFormatRgbx4444: - return "rgbx4444" - case ShmFormatBgrx4444: - return "bgrx4444" - case ShmFormatArgb4444: - return "argb4444" - case ShmFormatAbgr4444: - return "abgr4444" - case ShmFormatRgba4444: - return "rgba4444" - case ShmFormatBgra4444: - return "bgra4444" - case ShmFormatXrgb1555: - return "xrgb1555" - case ShmFormatXbgr1555: - return "xbgr1555" - case ShmFormatRgbx5551: - return "rgbx5551" - case ShmFormatBgrx5551: - return "bgrx5551" - case ShmFormatArgb1555: - return "argb1555" - case ShmFormatAbgr1555: - return "abgr1555" - case ShmFormatRgba5551: - return "rgba5551" - case ShmFormatBgra5551: - return "bgra5551" - case ShmFormatRgb565: - return "rgb565" - case ShmFormatBgr565: - return "bgr565" - case ShmFormatRgb888: - return "rgb888" - case ShmFormatBgr888: - return "bgr888" - case ShmFormatXbgr8888: - return "xbgr8888" - case ShmFormatRgbx8888: - return "rgbx8888" - case ShmFormatBgrx8888: - return "bgrx8888" - case ShmFormatAbgr8888: - return "abgr8888" - case ShmFormatRgba8888: - return "rgba8888" - case ShmFormatBgra8888: - return "bgra8888" - case ShmFormatXrgb2101010: - return "xrgb2101010" - case ShmFormatXbgr2101010: - return "xbgr2101010" - case ShmFormatRgbx1010102: - return "rgbx1010102" - case ShmFormatBgrx1010102: - return "bgrx1010102" - case ShmFormatArgb2101010: - return "argb2101010" - case ShmFormatAbgr2101010: - return "abgr2101010" - case ShmFormatRgba1010102: - return "rgba1010102" - case ShmFormatBgra1010102: - return "bgra1010102" - case ShmFormatYuyv: - return "yuyv" - case ShmFormatYvyu: - return "yvyu" - case ShmFormatUyvy: - return "uyvy" - case ShmFormatVyuy: - return "vyuy" - case ShmFormatAyuv: - return "ayuv" - case ShmFormatNv12: - return "nv12" - case ShmFormatNv21: - return "nv21" - case ShmFormatNv16: - return "nv16" - case ShmFormatNv61: - return "nv61" - case ShmFormatYuv410: - return "yuv410" - case ShmFormatYvu410: - return "yvu410" - case ShmFormatYuv411: - return "yuv411" - case ShmFormatYvu411: - return "yvu411" - case ShmFormatYuv420: - return "yuv420" - case ShmFormatYvu420: - return "yvu420" - case ShmFormatYuv422: - return "yuv422" - case ShmFormatYvu422: - return "yvu422" - case ShmFormatYuv444: - return "yuv444" - case ShmFormatYvu444: - return "yvu444" - case ShmFormatR8: - return "r8" - case ShmFormatR16: - return "r16" - case ShmFormatRg88: - return "rg88" - case ShmFormatGr88: - return "gr88" - case ShmFormatRg1616: - return "rg1616" - case ShmFormatGr1616: - return "gr1616" - case ShmFormatXrgb16161616F: - return "xrgb16161616f" - case ShmFormatXbgr16161616F: - return "xbgr16161616f" - case ShmFormatArgb16161616F: - return "argb16161616f" - case ShmFormatAbgr16161616F: - return "abgr16161616f" - case ShmFormatXyuv8888: - return "xyuv8888" - case ShmFormatVuy888: - return "vuy888" - case ShmFormatVuy101010: - return "vuy101010" - case ShmFormatY210: - return "y210" - case ShmFormatY212: - return "y212" - case ShmFormatY216: - return "y216" - case ShmFormatY410: - return "y410" - case ShmFormatY412: - return "y412" - case ShmFormatY416: - return "y416" - case ShmFormatXvyu2101010: - return "xvyu2101010" - case ShmFormatXvyu1216161616: - return "xvyu12_16161616" - case ShmFormatXvyu16161616: - return "xvyu16161616" - case ShmFormatY0L0: - return "y0l0" - case ShmFormatX0L0: - return "x0l0" - case ShmFormatY0L2: - return "y0l2" - case ShmFormatX0L2: - return "x0l2" - case ShmFormatYuv4208Bit: - return "yuv420_8bit" - case ShmFormatYuv42010Bit: - return "yuv420_10bit" - case ShmFormatXrgb8888A8: - return "xrgb8888_a8" - case ShmFormatXbgr8888A8: - return "xbgr8888_a8" - case ShmFormatRgbx8888A8: - return "rgbx8888_a8" - case ShmFormatBgrx8888A8: - return "bgrx8888_a8" - case ShmFormatRgb888A8: - return "rgb888_a8" - case ShmFormatBgr888A8: - return "bgr888_a8" - case ShmFormatRgb565A8: - return "rgb565_a8" - case ShmFormatBgr565A8: - return "bgr565_a8" - case ShmFormatNv24: - return "nv24" - case ShmFormatNv42: - return "nv42" - case ShmFormatP210: - return "p210" - case ShmFormatP010: - return "p010" - case ShmFormatP012: - return "p012" - case ShmFormatP016: - return "p016" - case ShmFormatAxbxgxrx106106106106: - return "axbxgxrx106106106106" - case ShmFormatNv15: - return "nv15" - case ShmFormatQ410: - return "q410" - case ShmFormatQ401: - return "q401" - case ShmFormatXrgb16161616: - return "xrgb16161616" - case ShmFormatXbgr16161616: - return "xbgr16161616" - case ShmFormatArgb16161616: - return "argb16161616" - case ShmFormatAbgr16161616: - return "abgr16161616" - case ShmFormatC1: - return "c1" - case ShmFormatC2: - return "c2" - case ShmFormatC4: - return "c4" - case ShmFormatD1: - return "d1" - case ShmFormatD2: - return "d2" - case ShmFormatD4: - return "d4" - case ShmFormatD8: - return "d8" - case ShmFormatR1: - return "r1" - case ShmFormatR2: - return "r2" - case ShmFormatR4: - return "r4" - case ShmFormatR10: - return "r10" - case ShmFormatR12: - return "r12" - case ShmFormatAvuy8888: - return "avuy8888" - case ShmFormatXvuy8888: - return "xvuy8888" - case ShmFormatP030: - return "p030" - default: - return "" - } -} - -func (e ShmFormat) Value() string { - switch e { - case ShmFormatArgb8888: - return "0" - case ShmFormatXrgb8888: - return "1" - case ShmFormatC8: - return "0x20203843" - case ShmFormatRgb332: - return "0x38424752" - case ShmFormatBgr233: - return "0x38524742" - case ShmFormatXrgb4444: - return "0x32315258" - case ShmFormatXbgr4444: - return "0x32314258" - case ShmFormatRgbx4444: - return "0x32315852" - case ShmFormatBgrx4444: - return "0x32315842" - case ShmFormatArgb4444: - return "0x32315241" - case ShmFormatAbgr4444: - return "0x32314241" - case ShmFormatRgba4444: - return "0x32314152" - case ShmFormatBgra4444: - return "0x32314142" - case ShmFormatXrgb1555: - return "0x35315258" - case ShmFormatXbgr1555: - return "0x35314258" - case ShmFormatRgbx5551: - return "0x35315852" - case ShmFormatBgrx5551: - return "0x35315842" - case ShmFormatArgb1555: - return "0x35315241" - case ShmFormatAbgr1555: - return "0x35314241" - case ShmFormatRgba5551: - return "0x35314152" - case ShmFormatBgra5551: - return "0x35314142" - case ShmFormatRgb565: - return "0x36314752" - case ShmFormatBgr565: - return "0x36314742" - case ShmFormatRgb888: - return "0x34324752" - case ShmFormatBgr888: - return "0x34324742" - case ShmFormatXbgr8888: - return "0x34324258" - case ShmFormatRgbx8888: - return "0x34325852" - case ShmFormatBgrx8888: - return "0x34325842" - case ShmFormatAbgr8888: - return "0x34324241" - case ShmFormatRgba8888: - return "0x34324152" - case ShmFormatBgra8888: - return "0x34324142" - case ShmFormatXrgb2101010: - return "0x30335258" - case ShmFormatXbgr2101010: - return "0x30334258" - case ShmFormatRgbx1010102: - return "0x30335852" - case ShmFormatBgrx1010102: - return "0x30335842" - case ShmFormatArgb2101010: - return "0x30335241" - case ShmFormatAbgr2101010: - return "0x30334241" - case ShmFormatRgba1010102: - return "0x30334152" - case ShmFormatBgra1010102: - return "0x30334142" - case ShmFormatYuyv: - return "0x56595559" - case ShmFormatYvyu: - return "0x55595659" - case ShmFormatUyvy: - return "0x59565955" - case ShmFormatVyuy: - return "0x59555956" - case ShmFormatAyuv: - return "0x56555941" - case ShmFormatNv12: - return "0x3231564e" - case ShmFormatNv21: - return "0x3132564e" - case ShmFormatNv16: - return "0x3631564e" - case ShmFormatNv61: - return "0x3136564e" - case ShmFormatYuv410: - return "0x39565559" - case ShmFormatYvu410: - return "0x39555659" - case ShmFormatYuv411: - return "0x31315559" - case ShmFormatYvu411: - return "0x31315659" - case ShmFormatYuv420: - return "0x32315559" - case ShmFormatYvu420: - return "0x32315659" - case ShmFormatYuv422: - return "0x36315559" - case ShmFormatYvu422: - return "0x36315659" - case ShmFormatYuv444: - return "0x34325559" - case ShmFormatYvu444: - return "0x34325659" - case ShmFormatR8: - return "0x20203852" - case ShmFormatR16: - return "0x20363152" - case ShmFormatRg88: - return "0x38384752" - case ShmFormatGr88: - return "0x38385247" - case ShmFormatRg1616: - return "0x32334752" - case ShmFormatGr1616: - return "0x32335247" - case ShmFormatXrgb16161616F: - return "0x48345258" - case ShmFormatXbgr16161616F: - return "0x48344258" - case ShmFormatArgb16161616F: - return "0x48345241" - case ShmFormatAbgr16161616F: - return "0x48344241" - case ShmFormatXyuv8888: - return "0x56555958" - case ShmFormatVuy888: - return "0x34325556" - case ShmFormatVuy101010: - return "0x30335556" - case ShmFormatY210: - return "0x30313259" - case ShmFormatY212: - return "0x32313259" - case ShmFormatY216: - return "0x36313259" - case ShmFormatY410: - return "0x30313459" - case ShmFormatY412: - return "0x32313459" - case ShmFormatY416: - return "0x36313459" - case ShmFormatXvyu2101010: - return "0x30335658" - case ShmFormatXvyu1216161616: - return "0x36335658" - case ShmFormatXvyu16161616: - return "0x38345658" - case ShmFormatY0L0: - return "0x304c3059" - case ShmFormatX0L0: - return "0x304c3058" - case ShmFormatY0L2: - return "0x324c3059" - case ShmFormatX0L2: - return "0x324c3058" - case ShmFormatYuv4208Bit: - return "0x38305559" - case ShmFormatYuv42010Bit: - return "0x30315559" - case ShmFormatXrgb8888A8: - return "0x38415258" - case ShmFormatXbgr8888A8: - return "0x38414258" - case ShmFormatRgbx8888A8: - return "0x38415852" - case ShmFormatBgrx8888A8: - return "0x38415842" - case ShmFormatRgb888A8: - return "0x38413852" - case ShmFormatBgr888A8: - return "0x38413842" - case ShmFormatRgb565A8: - return "0x38413552" - case ShmFormatBgr565A8: - return "0x38413542" - case ShmFormatNv24: - return "0x3432564e" - case ShmFormatNv42: - return "0x3234564e" - case ShmFormatP210: - return "0x30313250" - case ShmFormatP010: - return "0x30313050" - case ShmFormatP012: - return "0x32313050" - case ShmFormatP016: - return "0x36313050" - case ShmFormatAxbxgxrx106106106106: - return "0x30314241" - case ShmFormatNv15: - return "0x3531564e" - case ShmFormatQ410: - return "0x30313451" - case ShmFormatQ401: - return "0x31303451" - case ShmFormatXrgb16161616: - return "0x38345258" - case ShmFormatXbgr16161616: - return "0x38344258" - case ShmFormatArgb16161616: - return "0x38345241" - case ShmFormatAbgr16161616: - return "0x38344241" - case ShmFormatC1: - return "0x20203143" - case ShmFormatC2: - return "0x20203243" - case ShmFormatC4: - return "0x20203443" - case ShmFormatD1: - return "0x20203144" - case ShmFormatD2: - return "0x20203244" - case ShmFormatD4: - return "0x20203444" - case ShmFormatD8: - return "0x20203844" - case ShmFormatR1: - return "0x20203152" - case ShmFormatR2: - return "0x20203252" - case ShmFormatR4: - return "0x20203452" - case ShmFormatR10: - return "0x20303152" - case ShmFormatR12: - return "0x20323152" - case ShmFormatAvuy8888: - return "0x59555641" - case ShmFormatXvuy8888: - return "0x59555658" - case ShmFormatP030: - return "0x30333050" - default: - return "" - } -} - -func (e ShmFormat) String() string { - return e.Name() + "=" + e.Value() -} - -// ShmFormatEvent : pixel format description -// -// Informs the client about a valid pixel format that -// can be used for buffers. Known formats include -// argb8888 and xrgb8888. -type ShmFormatEvent struct { - Format uint32 -} -type ShmFormatHandlerFunc func(ShmFormatEvent) - -// SetFormatHandler : sets handler for ShmFormatEvent -func (i *Shm) SetFormatHandler(f ShmFormatHandlerFunc) { - i.formatHandler = f -} - -func (i *Shm) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.formatHandler == nil { - return - } - var e ShmFormatEvent - l := 0 - e.Format = Uint32(data[l : l+4]) - l += 4 - - i.formatHandler(e) - } -} - -// BufferInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const BufferInterfaceName = "wl_buffer" - -// Buffer : content for a wl_surface -// -// A buffer provides the content for a wl_surface. Buffers are -// created through factory interfaces such as wl_shm, wp_linux_buffer_params -// (from the linux-dmabuf protocol extension) or similar. It has a width and -// a height and can be attached to a wl_surface, but the mechanism by which a -// client provides and updates the contents is defined by the buffer factory -// interface. -// -// Color channels are assumed to be electrical rather than optical (in other -// words, encoded with a transfer function) unless otherwise specified. If -// the buffer uses a format that has an alpha channel, the alpha channel is -// assumed to be premultiplied into the electrical color channel values -// (after transfer function encoding) unless otherwise specified. -// -// Note, because wl_buffer objects are created from multiple independent -// factory interfaces, the wl_buffer interface is frozen at version 1. -type Buffer struct { - BaseProxy - releaseHandler BufferReleaseHandlerFunc -} - -// NewBuffer : content for a wl_surface -// -// A buffer provides the content for a wl_surface. Buffers are -// created through factory interfaces such as wl_shm, wp_linux_buffer_params -// (from the linux-dmabuf protocol extension) or similar. It has a width and -// a height and can be attached to a wl_surface, but the mechanism by which a -// client provides and updates the contents is defined by the buffer factory -// interface. -// -// Color channels are assumed to be electrical rather than optical (in other -// words, encoded with a transfer function) unless otherwise specified. If -// the buffer uses a format that has an alpha channel, the alpha channel is -// assumed to be premultiplied into the electrical color channel values -// (after transfer function encoding) unless otherwise specified. -// -// Note, because wl_buffer objects are created from multiple independent -// factory interfaces, the wl_buffer interface is frozen at version 1. -func NewBuffer(ctx *Context) *Buffer { - wlBuffer := &Buffer{} - ctx.Register(wlBuffer) - return wlBuffer -} - -// Destroy : destroy a buffer -// -// Destroy a buffer. If and how you need to release the backing -// storage is defined by the buffer factory interface. -// -// For possible side-effects to a surface, see wl_surface.attach. -func (i *Buffer) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// BufferReleaseEvent : compositor releases buffer -// -// Sent when this wl_buffer is no longer used by the compositor. -// -// For more information on when release events may or may not be sent, -// and what consequences it has, please see the description of -// wl_surface.attach. -// -// If a client receives a release event before the frame callback -// requested in the same wl_surface.commit that attaches this -// wl_buffer to a surface, then the client is immediately free to -// reuse the buffer and its backing storage, and does not need a -// second buffer for the next surface content update. Typically -// this is possible, when the compositor maintains a copy of the -// wl_surface contents, e.g. as a GL texture. This is an important -// optimization for GL(ES) compositors with wl_shm clients. -type BufferReleaseEvent struct{} -type BufferReleaseHandlerFunc func(BufferReleaseEvent) - -// SetReleaseHandler : sets handler for BufferReleaseEvent -func (i *Buffer) SetReleaseHandler(f BufferReleaseHandlerFunc) { - i.releaseHandler = f -} - -func (i *Buffer) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.releaseHandler == nil { - return - } - var e BufferReleaseEvent - - i.releaseHandler(e) - } -} - -// DataOfferInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const DataOfferInterfaceName = "wl_data_offer" - -// DataOffer : offer to transfer data -// -// A wl_data_offer represents a piece of data offered for transfer -// by another client (the source client). It is used by the -// copy-and-paste and drag-and-drop mechanisms. The offer -// describes the different mime types that the data can be -// converted to and provides the mechanism for transferring the -// data directly from the source client. -type DataOffer struct { - BaseProxy - offerHandler DataOfferOfferHandlerFunc - sourceActionsHandler DataOfferSourceActionsHandlerFunc - actionHandler DataOfferActionHandlerFunc -} - -// NewDataOffer : offer to transfer data -// -// A wl_data_offer represents a piece of data offered for transfer -// by another client (the source client). It is used by the -// copy-and-paste and drag-and-drop mechanisms. The offer -// describes the different mime types that the data can be -// converted to and provides the mechanism for transferring the -// data directly from the source client. -func NewDataOffer(ctx *Context) *DataOffer { - wlDataOffer := &DataOffer{} - ctx.Register(wlDataOffer) - return wlDataOffer -} - -// Accept : accept one of the offered mime types -// -// Indicate that the client can accept the given mime type, or -// NULL for not accepted. -// -// For objects of version 2 or older, this request is used by the -// client to give feedback whether the client can receive the given -// mime type, or NULL if none is accepted; the feedback does not -// determine whether the drag-and-drop operation succeeds or not. -// -// For objects of version 3 or newer, this request determines the -// final result of the drag-and-drop operation. If the end result -// is that no mime types were accepted, the drag-and-drop operation -// will be cancelled and the corresponding drag source will receive -// wl_data_source.cancelled. Clients may still use this event in -// conjunction with wl_data_source.action for feedback. -// -// serial: serial number of the accept request -// mimeType: mime type accepted by the client -func (i *DataOffer) Accept(serial uint32, mimeType string) error { - const opcode = 0 - mimeTypeLen := PaddedLen(len(mimeType) + 1) - _reqBufLen := 8 + 4 + (4 + mimeTypeLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - PutString(_reqBuf[l:l+(4+mimeTypeLen)], mimeType) - l += (4 + mimeTypeLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -// Receive : request that the data is transferred -// -// To transfer the offered data, the client issues this request -// and indicates the mime type it wants to receive. The transfer -// happens through the passed file descriptor (typically created -// with the pipe system call). The source client writes the data -// in the mime type representation requested and then closes the -// file descriptor. -// -// The receiving client reads from the read end of the pipe until -// EOF and then closes its end, at which point the transfer is -// complete. -// -// This request may happen multiple times for different mime types, -// both before and after wl_data_device.drop. Drag-and-drop destination -// clients may preemptively fetch data or examine it more closely to -// determine acceptance. -// -// mimeType: mime type desired by receiver -// fd: file descriptor for data transfer -func (i *DataOffer) Receive(mimeType string, fd int) error { - const opcode = 1 - mimeTypeLen := PaddedLen(len(mimeType) + 1) - _reqBufLen := 8 + (4 + mimeTypeLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutString(_reqBuf[l:l+(4+mimeTypeLen)], mimeType) - l += (4 + mimeTypeLen) - oob := unix.UnixRights(int(fd)) - err := i.Context().WriteMsg(_reqBuf, oob) - return err -} - -// Destroy : destroy data offer -// -// Destroy the data offer. -func (i *DataOffer) Destroy() error { - defer i.MarkZombie() - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Finish : the offer will no longer be used -// -// Notifies the compositor that the drag destination successfully -// finished the drag-and-drop operation. -// -// Upon receiving this request, the compositor will emit -// wl_data_source.dnd_finished on the drag source client. -// -// It is a client error to perform other requests than -// wl_data_offer.destroy after this one. It is also an error to perform -// this request after a NULL mime type has been set in -// wl_data_offer.accept or no action was received through -// wl_data_offer.action. -// -// If wl_data_offer.finish request is received for a non drag and drop -// operation, the invalid_finish protocol error is raised. -func (i *DataOffer) Finish() error { - const opcode = 3 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetActions : set the available/preferred drag-and-drop actions -// -// Sets the actions that the destination side client supports for -// this operation. This request may trigger the emission of -// wl_data_source.action and wl_data_offer.action events if the compositor -// needs to change the selected action. -// -// This request can be called multiple times throughout the -// drag-and-drop operation, typically in response to wl_data_device.enter -// or wl_data_device.motion events. -// -// This request determines the final result of the drag-and-drop -// operation. If the end result is that no action is accepted, -// the drag source will receive wl_data_source.cancelled. -// -// The dnd_actions argument must contain only values expressed in the -// wl_data_device_manager.dnd_actions enum, and the preferred_action -// argument must only contain one of those values set, otherwise it -// will result in a protocol error. -// -// While managing an "ask" action, the destination drag-and-drop client -// may perform further wl_data_offer.receive requests, and is expected -// to perform one last wl_data_offer.set_actions request with a preferred -// action other than "ask" (and optionally wl_data_offer.accept) before -// requesting wl_data_offer.finish, in order to convey the action selected -// by the user. If the preferred action is not in the -// wl_data_offer.source_actions mask, an error will be raised. -// -// If the "ask" action is dismissed (e.g. user cancellation), the client -// is expected to perform wl_data_offer.destroy right away. -// -// This request can only be made on drag-and-drop offers, a protocol error -// will be raised otherwise. -// -// dndActions: actions supported by the destination client -// preferredAction: action preferred by the destination client -func (i *DataOffer) SetActions(dndActions, preferredAction uint32) error { - const opcode = 4 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(dndActions)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(preferredAction)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type DataOfferError uint32 - -// DataOfferError : -const ( - // DataOfferErrorInvalidFinish : finish request was called untimely - DataOfferErrorInvalidFinish DataOfferError = 0 - // DataOfferErrorInvalidActionMask : action mask contains invalid values - DataOfferErrorInvalidActionMask DataOfferError = 1 - // DataOfferErrorInvalidAction : action argument has an invalid value - DataOfferErrorInvalidAction DataOfferError = 2 - // DataOfferErrorInvalidOffer : offer doesn't accept this request - DataOfferErrorInvalidOffer DataOfferError = 3 -) - -func (e DataOfferError) Name() string { - switch e { - case DataOfferErrorInvalidFinish: - return "invalid_finish" - case DataOfferErrorInvalidActionMask: - return "invalid_action_mask" - case DataOfferErrorInvalidAction: - return "invalid_action" - case DataOfferErrorInvalidOffer: - return "invalid_offer" - default: - return "" - } -} - -func (e DataOfferError) Value() string { - switch e { - case DataOfferErrorInvalidFinish: - return "0" - case DataOfferErrorInvalidActionMask: - return "1" - case DataOfferErrorInvalidAction: - return "2" - case DataOfferErrorInvalidOffer: - return "3" - default: - return "" - } -} - -func (e DataOfferError) String() string { - return e.Name() + "=" + e.Value() -} - -// DataOfferOfferEvent : advertise offered mime type -// -// Sent immediately after creating the wl_data_offer object. One -// event per offered mime type. -type DataOfferOfferEvent struct { - MimeType string -} -type DataOfferOfferHandlerFunc func(DataOfferOfferEvent) - -// SetOfferHandler : sets handler for DataOfferOfferEvent -func (i *DataOffer) SetOfferHandler(f DataOfferOfferHandlerFunc) { - i.offerHandler = f -} - -// DataOfferSourceActionsEvent : notify the source-side available actions -// -// This event indicates the actions offered by the data source. It -// will be sent immediately after creating the wl_data_offer object, -// or anytime the source side changes its offered actions through -// wl_data_source.set_actions. -type DataOfferSourceActionsEvent struct { - SourceActions uint32 -} -type DataOfferSourceActionsHandlerFunc func(DataOfferSourceActionsEvent) - -// SetSourceActionsHandler : sets handler for DataOfferSourceActionsEvent -func (i *DataOffer) SetSourceActionsHandler(f DataOfferSourceActionsHandlerFunc) { - i.sourceActionsHandler = f -} - -// DataOfferActionEvent : notify the selected action -// -// This event indicates the action selected by the compositor after -// matching the source/destination side actions. Only one action (or -// none) will be offered here. -// -// This event can be emitted multiple times during the drag-and-drop -// operation in response to destination side action changes through -// wl_data_offer.set_actions. -// -// This event will no longer be emitted after wl_data_device.drop -// happened on the drag-and-drop destination, the client must -// honor the last action received, or the last preferred one set -// through wl_data_offer.set_actions when handling an "ask" action. -// -// Compositors may also change the selected action on the fly, mainly -// in response to keyboard modifier changes during the drag-and-drop -// operation. -// -// The most recent action received is always the valid one. Prior to -// receiving wl_data_device.drop, the chosen action may change (e.g. -// due to keyboard modifiers being pressed). At the time of receiving -// wl_data_device.drop the drag-and-drop destination must honor the -// last action received. -// -// Action changes may still happen after wl_data_device.drop, -// especially on "ask" actions, where the drag-and-drop destination -// may choose another action afterwards. Action changes happening -// at this stage are always the result of inter-client negotiation, the -// compositor shall no longer be able to induce a different action. -// -// Upon "ask" actions, it is expected that the drag-and-drop destination -// may potentially choose a different action and/or mime type, -// based on wl_data_offer.source_actions and finally chosen by the -// user (e.g. popping up a menu with the available options). The -// final wl_data_offer.set_actions and wl_data_offer.accept requests -// must happen before the call to wl_data_offer.finish. -type DataOfferActionEvent struct { - DndAction uint32 -} -type DataOfferActionHandlerFunc func(DataOfferActionEvent) - -// SetActionHandler : sets handler for DataOfferActionEvent -func (i *DataOffer) SetActionHandler(f DataOfferActionHandlerFunc) { - i.actionHandler = f -} - -func (i *DataOffer) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.offerHandler == nil { - return - } - var e DataOfferOfferEvent - l := 0 - mimeTypeLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.MimeType = String(data[l : l+mimeTypeLen]) - l += mimeTypeLen - - i.offerHandler(e) - case 1: - if i.sourceActionsHandler == nil { - return - } - var e DataOfferSourceActionsEvent - l := 0 - e.SourceActions = Uint32(data[l : l+4]) - l += 4 - - i.sourceActionsHandler(e) - case 2: - if i.actionHandler == nil { - return - } - var e DataOfferActionEvent - l := 0 - e.DndAction = Uint32(data[l : l+4]) - l += 4 - - i.actionHandler(e) - } -} - -// DataSourceInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const DataSourceInterfaceName = "wl_data_source" - -// DataSource : offer to transfer data -// -// The wl_data_source object is the source side of a wl_data_offer. -// It is created by the source client in a data transfer and -// provides a way to describe the offered data and a way to respond -// to requests to transfer the data. -type DataSource struct { - BaseProxy - targetHandler DataSourceTargetHandlerFunc - sendHandler DataSourceSendHandlerFunc - cancelledHandler DataSourceCancelledHandlerFunc - dndDropPerformedHandler DataSourceDndDropPerformedHandlerFunc - dndFinishedHandler DataSourceDndFinishedHandlerFunc - actionHandler DataSourceActionHandlerFunc -} - -// NewDataSource : offer to transfer data -// -// The wl_data_source object is the source side of a wl_data_offer. -// It is created by the source client in a data transfer and -// provides a way to describe the offered data and a way to respond -// to requests to transfer the data. -func NewDataSource(ctx *Context) *DataSource { - wlDataSource := &DataSource{} - ctx.Register(wlDataSource) - return wlDataSource -} - -// Offer : add an offered mime type -// -// This request adds a mime type to the set of mime types -// advertised to targets. Can be called several times to offer -// multiple types. -// -// mimeType: mime type offered by the data source -func (i *DataSource) Offer(mimeType string) error { - const opcode = 0 - mimeTypeLen := PaddedLen(len(mimeType) + 1) - _reqBufLen := 8 + (4 + mimeTypeLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutString(_reqBuf[l:l+(4+mimeTypeLen)], mimeType) - l += (4 + mimeTypeLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -// Destroy : destroy the data source -// -// Destroy the data source. -func (i *DataSource) Destroy() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetActions : set the available drag-and-drop actions -// -// Sets the actions that the source side client supports for this -// operation. This request may trigger wl_data_source.action and -// wl_data_offer.action events if the compositor needs to change the -// selected action. -// -// The dnd_actions argument must contain only values expressed in the -// wl_data_device_manager.dnd_actions enum, otherwise it will result -// in a protocol error. -// -// This request must be made once only, and can only be made on sources -// used in drag-and-drop, so it must be performed before -// wl_data_device.start_drag. Attempting to use the source other than -// for drag-and-drop will raise a protocol error. -// -// dndActions: actions supported by the data source -func (i *DataSource) SetActions(dndActions uint32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(dndActions)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type DataSourceError uint32 - -// DataSourceError : -const ( - // DataSourceErrorInvalidActionMask : action mask contains invalid values - DataSourceErrorInvalidActionMask DataSourceError = 0 - // DataSourceErrorInvalidSource : source doesn't accept this request - DataSourceErrorInvalidSource DataSourceError = 1 -) - -func (e DataSourceError) Name() string { - switch e { - case DataSourceErrorInvalidActionMask: - return "invalid_action_mask" - case DataSourceErrorInvalidSource: - return "invalid_source" - default: - return "" - } -} - -func (e DataSourceError) Value() string { - switch e { - case DataSourceErrorInvalidActionMask: - return "0" - case DataSourceErrorInvalidSource: - return "1" - default: - return "" - } -} - -func (e DataSourceError) String() string { - return e.Name() + "=" + e.Value() -} - -// DataSourceTargetEvent : a target accepts an offered mime type -// -// Sent when a target accepts pointer_focus or motion events. If -// a target does not accept any of the offered types, type is NULL. -// -// Used for feedback during drag-and-drop. -type DataSourceTargetEvent struct { - MimeType string -} -type DataSourceTargetHandlerFunc func(DataSourceTargetEvent) - -// SetTargetHandler : sets handler for DataSourceTargetEvent -func (i *DataSource) SetTargetHandler(f DataSourceTargetHandlerFunc) { - i.targetHandler = f -} - -// DataSourceSendEvent : send the data -// -// Request for data from the client. Send the data as the -// specified mime type over the passed file descriptor, then -// close it. -type DataSourceSendEvent struct { - MimeType string - Fd int -} -type DataSourceSendHandlerFunc func(DataSourceSendEvent) - -// SetSendHandler : sets handler for DataSourceSendEvent -func (i *DataSource) SetSendHandler(f DataSourceSendHandlerFunc) { - i.sendHandler = f -} - -// DataSourceCancelledEvent : selection was cancelled -// -// This data source is no longer valid. There are several reasons why -// this could happen: -// -// - The data source has been replaced by another data source. -// - The drag-and-drop operation was performed, but the drop destination -// did not accept any of the mime types offered through -// wl_data_source.target. -// - The drag-and-drop operation was performed, but the drop destination -// did not select any of the actions present in the mask offered through -// wl_data_source.action. -// - The drag-and-drop operation was performed but didn't happen over a -// surface. -// - The compositor cancelled the drag-and-drop operation (e.g. compositor -// dependent timeouts to avoid stale drag-and-drop transfers). -// -// The client should clean up and destroy this data source. -// -// For objects of version 2 or older, wl_data_source.cancelled will -// only be emitted if the data source was replaced by another data -// source. -type DataSourceCancelledEvent struct{} -type DataSourceCancelledHandlerFunc func(DataSourceCancelledEvent) - -// SetCancelledHandler : sets handler for DataSourceCancelledEvent -func (i *DataSource) SetCancelledHandler(f DataSourceCancelledHandlerFunc) { - i.cancelledHandler = f -} - -// DataSourceDndDropPerformedEvent : the drag-and-drop operation physically finished -// -// The user performed the drop action. This event does not indicate -// acceptance, wl_data_source.cancelled may still be emitted afterwards -// if the drop destination does not accept any mime type. -// -// However, this event might however not be received if the compositor -// cancelled the drag-and-drop operation before this event could happen. -// -// Note that the data_source may still be used in the future and should -// not be destroyed here. -type DataSourceDndDropPerformedEvent struct{} -type DataSourceDndDropPerformedHandlerFunc func(DataSourceDndDropPerformedEvent) - -// SetDndDropPerformedHandler : sets handler for DataSourceDndDropPerformedEvent -func (i *DataSource) SetDndDropPerformedHandler(f DataSourceDndDropPerformedHandlerFunc) { - i.dndDropPerformedHandler = f -} - -// DataSourceDndFinishedEvent : the drag-and-drop operation concluded -// -// The drop destination finished interoperating with this data -// source, so the client is now free to destroy this data source and -// free all associated data. -// -// If the action used to perform the operation was "move", the -// source can now delete the transferred data. -type DataSourceDndFinishedEvent struct{} -type DataSourceDndFinishedHandlerFunc func(DataSourceDndFinishedEvent) - -// SetDndFinishedHandler : sets handler for DataSourceDndFinishedEvent -func (i *DataSource) SetDndFinishedHandler(f DataSourceDndFinishedHandlerFunc) { - i.dndFinishedHandler = f -} - -// DataSourceActionEvent : notify the selected action -// -// This event indicates the action selected by the compositor after -// matching the source/destination side actions. Only one action (or -// none) will be offered here. -// -// This event can be emitted multiple times during the drag-and-drop -// operation, mainly in response to destination side changes through -// wl_data_offer.set_actions, and as the data device enters/leaves -// surfaces. -// -// It is only possible to receive this event after -// wl_data_source.dnd_drop_performed if the drag-and-drop operation -// ended in an "ask" action, in which case the final wl_data_source.action -// event will happen immediately before wl_data_source.dnd_finished. -// -// Compositors may also change the selected action on the fly, mainly -// in response to keyboard modifier changes during the drag-and-drop -// operation. -// -// The most recent action received is always the valid one. The chosen -// action may change alongside negotiation (e.g. an "ask" action can turn -// into a "move" operation), so the effects of the final action must -// always be applied in wl_data_offer.dnd_finished. -// -// Clients can trigger cursor surface changes from this point, so -// they reflect the current action. -type DataSourceActionEvent struct { - DndAction uint32 -} -type DataSourceActionHandlerFunc func(DataSourceActionEvent) - -// SetActionHandler : sets handler for DataSourceActionEvent -func (i *DataSource) SetActionHandler(f DataSourceActionHandlerFunc) { - i.actionHandler = f -} - -func (i *DataSource) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.targetHandler == nil { - return - } - var e DataSourceTargetEvent - l := 0 - mimeTypeLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.MimeType = String(data[l : l+mimeTypeLen]) - l += mimeTypeLen - - i.targetHandler(e) - case 1: - if i.sendHandler == nil { - if fd != -1 { - unix.Close(fd) - } - return - } - var e DataSourceSendEvent - l := 0 - mimeTypeLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.MimeType = String(data[l : l+mimeTypeLen]) - l += mimeTypeLen - e.Fd = fd - - i.sendHandler(e) - case 2: - if i.cancelledHandler == nil { - return - } - var e DataSourceCancelledEvent - - i.cancelledHandler(e) - case 3: - if i.dndDropPerformedHandler == nil { - return - } - var e DataSourceDndDropPerformedEvent - - i.dndDropPerformedHandler(e) - case 4: - if i.dndFinishedHandler == nil { - return - } - var e DataSourceDndFinishedEvent - - i.dndFinishedHandler(e) - case 5: - if i.actionHandler == nil { - return - } - var e DataSourceActionEvent - l := 0 - e.DndAction = Uint32(data[l : l+4]) - l += 4 - - i.actionHandler(e) - } -} - -// DataDeviceInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const DataDeviceInterfaceName = "wl_data_device" - -// DataDevice : data transfer device -// -// There is one wl_data_device per seat which can be obtained -// from the global wl_data_device_manager singleton. -// -// A wl_data_device provides access to inter-client data transfer -// mechanisms such as copy-and-paste and drag-and-drop. -type DataDevice struct { - BaseProxy - dataOfferHandler DataDeviceDataOfferHandlerFunc - enterHandler DataDeviceEnterHandlerFunc - leaveHandler DataDeviceLeaveHandlerFunc - motionHandler DataDeviceMotionHandlerFunc - dropHandler DataDeviceDropHandlerFunc - selectionHandler DataDeviceSelectionHandlerFunc -} - -// NewDataDevice : data transfer device -// -// There is one wl_data_device per seat which can be obtained -// from the global wl_data_device_manager singleton. -// -// A wl_data_device provides access to inter-client data transfer -// mechanisms such as copy-and-paste and drag-and-drop. -func NewDataDevice(ctx *Context) *DataDevice { - wlDataDevice := &DataDevice{} - ctx.Register(wlDataDevice) - return wlDataDevice -} - -// StartDrag : start drag-and-drop operation -// -// This request asks the compositor to start a drag-and-drop -// operation on behalf of the client. -// -// The source argument is the data source that provides the data -// for the eventual data transfer. If source is NULL, enter, leave -// and motion events are sent only to the client that initiated the -// drag and the client is expected to handle the data passing -// internally. If source is destroyed, the drag-and-drop session will be -// cancelled. -// -// The origin surface is the surface where the drag originates and -// the client must have an active implicit grab that matches the -// serial. -// -// The icon surface is an optional (can be NULL) surface that -// provides an icon to be moved around with the cursor. Initially, -// the top-left corner of the icon surface is placed at the cursor -// hotspot, but subsequent wl_surface.offset requests can move the -// relative position. Attach requests must be confirmed with -// wl_surface.commit as usual. The icon surface is given the role of -// a drag-and-drop icon. If the icon surface already has another role, -// it raises a protocol error. -// -// The input region is ignored for wl_surfaces with the role of a -// drag-and-drop icon. -// -// The given source may not be used in any further set_selection or -// start_drag requests. Attempting to reuse a previously-used source -// may send a used_source error. -// -// source: data source for the eventual transfer -// origin: surface where the drag originates -// icon: drag-and-drop icon surface -// serial: serial number of the implicit grab on the origin -func (i *DataDevice) StartDrag(source *DataSource, origin, icon *Surface, serial uint32) error { - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if source == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], source.ID()) - l += 4 - } - PutUint32(_reqBuf[l:l+4], origin.ID()) - l += 4 - if icon == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], icon.ID()) - l += 4 - } - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetSelection : copy data to the selection -// -// This request asks the compositor to set the selection -// to the data from the source on behalf of the client. -// -// To unset the selection, set the source to NULL. -// -// The given source may not be used in any further set_selection or -// start_drag requests. Attempting to reuse a previously-used source -// may send a used_source error. -// -// source: data source for the selection -// serial: serial number of the event that triggered this request -func (i *DataDevice) SetSelection(source *DataSource, serial uint32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if source == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], source.ID()) - l += 4 - } - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Release : destroy data device -// -// This request destroys the data device. -func (i *DataDevice) Release() error { - defer i.MarkZombie() - const opcode = 2 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type DataDeviceError uint32 - -// DataDeviceError : -const ( - // DataDeviceErrorRole : given wl_surface has another role - DataDeviceErrorRole DataDeviceError = 0 - // DataDeviceErrorUsedSource : source has already been used - DataDeviceErrorUsedSource DataDeviceError = 1 -) - -func (e DataDeviceError) Name() string { - switch e { - case DataDeviceErrorRole: - return "role" - case DataDeviceErrorUsedSource: - return "used_source" - default: - return "" - } -} - -func (e DataDeviceError) Value() string { - switch e { - case DataDeviceErrorRole: - return "0" - case DataDeviceErrorUsedSource: - return "1" - default: - return "" - } -} - -func (e DataDeviceError) String() string { - return e.Name() + "=" + e.Value() -} - -// DataDeviceDataOfferEvent : introduce a new wl_data_offer -// -// The data_offer event introduces a new wl_data_offer object, -// which will subsequently be used in either the -// data_device.enter event (for drag-and-drop) or the -// data_device.selection event (for selections). Immediately -// following the data_device.data_offer event, the new data_offer -// object will send out data_offer.offer events to describe the -// mime types it offers. -type DataDeviceDataOfferEvent struct { - Id *DataOffer -} -type DataDeviceDataOfferHandlerFunc func(DataDeviceDataOfferEvent) - -// SetDataOfferHandler : sets handler for DataDeviceDataOfferEvent -func (i *DataDevice) SetDataOfferHandler(f DataDeviceDataOfferHandlerFunc) { - i.dataOfferHandler = f -} - -// DataDeviceEnterEvent : initiate drag-and-drop session -// -// This event is sent when an active drag-and-drop pointer enters -// a surface owned by the client. The position of the pointer at -// enter time is provided by the x and y arguments, in surface-local -// coordinates. -type DataDeviceEnterEvent struct { - Serial uint32 - Surface *Surface - X float64 - Y float64 - Id *DataOffer -} -type DataDeviceEnterHandlerFunc func(DataDeviceEnterEvent) - -// SetEnterHandler : sets handler for DataDeviceEnterEvent -func (i *DataDevice) SetEnterHandler(f DataDeviceEnterHandlerFunc) { - i.enterHandler = f -} - -// DataDeviceLeaveEvent : end drag-and-drop session -// -// This event is sent when the drag-and-drop pointer leaves the -// surface and the session ends. The client must destroy the -// wl_data_offer introduced at enter time at this point. -type DataDeviceLeaveEvent struct{} -type DataDeviceLeaveHandlerFunc func(DataDeviceLeaveEvent) - -// SetLeaveHandler : sets handler for DataDeviceLeaveEvent -func (i *DataDevice) SetLeaveHandler(f DataDeviceLeaveHandlerFunc) { - i.leaveHandler = f -} - -// DataDeviceMotionEvent : drag-and-drop session motion -// -// This event is sent when the drag-and-drop pointer moves within -// the currently focused surface. The new position of the pointer -// is provided by the x and y arguments, in surface-local -// coordinates. -type DataDeviceMotionEvent struct { - Time uint32 - X float64 - Y float64 -} -type DataDeviceMotionHandlerFunc func(DataDeviceMotionEvent) - -// SetMotionHandler : sets handler for DataDeviceMotionEvent -func (i *DataDevice) SetMotionHandler(f DataDeviceMotionHandlerFunc) { - i.motionHandler = f -} - -// DataDeviceDropEvent : end drag-and-drop session successfully -// -// The event is sent when a drag-and-drop operation is ended -// because the implicit grab is removed. -// -// The drag-and-drop destination is expected to honor the last action -// received through wl_data_offer.action, if the resulting action is -// "copy" or "move", the destination can still perform -// wl_data_offer.receive requests, and is expected to end all -// transfers with a wl_data_offer.finish request. -// -// If the resulting action is "ask", the action will not be considered -// final. The drag-and-drop destination is expected to perform one last -// wl_data_offer.set_actions request, or wl_data_offer.destroy in order -// to cancel the operation. -type DataDeviceDropEvent struct{} -type DataDeviceDropHandlerFunc func(DataDeviceDropEvent) - -// SetDropHandler : sets handler for DataDeviceDropEvent -func (i *DataDevice) SetDropHandler(f DataDeviceDropHandlerFunc) { - i.dropHandler = f -} - -// DataDeviceSelectionEvent : advertise new selection -// -// The selection event is sent out to notify the client of a new -// wl_data_offer for the selection for this device. The -// data_device.data_offer and the data_offer.offer events are -// sent out immediately before this event to introduce the data -// offer object. The selection event is sent to a client -// immediately before receiving keyboard focus and when a new -// selection is set while the client has keyboard focus. The -// data_offer is valid until a new data_offer or NULL is received -// or until the client loses keyboard focus. Switching surface with -// keyboard focus within the same client doesn't mean a new selection -// will be sent. The client must destroy the previous selection -// data_offer, if any, upon receiving this event. -type DataDeviceSelectionEvent struct { - Id *DataOffer -} -type DataDeviceSelectionHandlerFunc func(DataDeviceSelectionEvent) - -// SetSelectionHandler : sets handler for DataDeviceSelectionEvent -func (i *DataDevice) SetSelectionHandler(f DataDeviceSelectionHandlerFunc) { - i.selectionHandler = f -} - -func (i *DataDevice) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.dataOfferHandler == nil { - return - } - var e DataDeviceDataOfferEvent - l := 0 - e.Id = i.Context().GetProxy(Uint32(data[l : l+4])).(*DataOffer) - l += 4 - - i.dataOfferHandler(e) - case 1: - if i.enterHandler == nil { - return - } - var e DataDeviceEnterEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - e.X = Fixed(data[l : l+4]) - l += 4 - e.Y = Fixed(data[l : l+4]) - l += 4 - e.Id = i.Context().GetProxy(Uint32(data[l : l+4])).(*DataOffer) - l += 4 - - i.enterHandler(e) - case 2: - if i.leaveHandler == nil { - return - } - var e DataDeviceLeaveEvent - - i.leaveHandler(e) - case 3: - if i.motionHandler == nil { - return - } - var e DataDeviceMotionEvent - l := 0 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.X = Fixed(data[l : l+4]) - l += 4 - e.Y = Fixed(data[l : l+4]) - l += 4 - - i.motionHandler(e) - case 4: - if i.dropHandler == nil { - return - } - var e DataDeviceDropEvent - - i.dropHandler(e) - case 5: - if i.selectionHandler == nil { - return - } - var e DataDeviceSelectionEvent - l := 0 - e.Id = i.Context().GetProxy(Uint32(data[l : l+4])).(*DataOffer) - l += 4 - - i.selectionHandler(e) - } -} - -// DataDeviceManagerInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const DataDeviceManagerInterfaceName = "wl_data_device_manager" - -// DataDeviceManager : data transfer interface -// -// The wl_data_device_manager is a singleton global object that -// provides access to inter-client data transfer mechanisms such as -// copy-and-paste and drag-and-drop. These mechanisms are tied to -// a wl_seat and this interface lets a client get a wl_data_device -// corresponding to a wl_seat. -// -// Depending on the version bound, the objects created from the bound -// wl_data_device_manager object will have different requirements for -// functioning properly. See wl_data_source.set_actions, -// wl_data_offer.accept and wl_data_offer.finish for details. -type DataDeviceManager struct { - BaseProxy -} - -// NewDataDeviceManager : data transfer interface -// -// The wl_data_device_manager is a singleton global object that -// provides access to inter-client data transfer mechanisms such as -// copy-and-paste and drag-and-drop. These mechanisms are tied to -// a wl_seat and this interface lets a client get a wl_data_device -// corresponding to a wl_seat. -// -// Depending on the version bound, the objects created from the bound -// wl_data_device_manager object will have different requirements for -// functioning properly. See wl_data_source.set_actions, -// wl_data_offer.accept and wl_data_offer.finish for details. -func NewDataDeviceManager(ctx *Context) *DataDeviceManager { - wlDataDeviceManager := &DataDeviceManager{} - ctx.Register(wlDataDeviceManager) - return wlDataDeviceManager -} - -// CreateDataSource : create a new data source -// -// Create a new data source. -func (i *DataDeviceManager) CreateDataSource() (*DataSource, error) { - id := NewDataSource(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// GetDataDevice : create a new data device -// -// Create a new data device for a given seat. -// -// seat: seat associated with the data device -func (i *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) { - id := NewDataDevice(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -func (i *DataDeviceManager) Destroy() error { - i.MarkZombie() - return nil -} - -type DataDeviceManagerDndAction uint32 - -// DataDeviceManagerDndAction : drag and drop actions -// -// This is a bitmask of the available/preferred actions in a -// drag-and-drop operation. -// -// In the compositor, the selected action is a result of matching the -// actions offered by the source and destination sides. "action" events -// with a "none" action will be sent to both source and destination if -// there is no match. All further checks will effectively happen on -// (source actions ∩ destination actions). -// -// In addition, compositors may also pick different actions in -// reaction to key modifiers being pressed. One common design that -// is used in major toolkits (and the behavior recommended for -// compositors) is: -// -// - If no modifiers are pressed, the first match (in bit order) -// will be used. -// - Pressing Shift selects "move", if enabled in the mask. -// - Pressing Control selects "copy", if enabled in the mask. -// -// Behavior beyond that is considered implementation-dependent. -// Compositors may for example bind other modifiers (like Alt/Meta) -// or drags initiated with other buttons than BTN_LEFT to specific -// actions (e.g. "ask"). -const ( - // DataDeviceManagerDndActionNone : no action - DataDeviceManagerDndActionNone DataDeviceManagerDndAction = 0 - // DataDeviceManagerDndActionCopy : copy action - DataDeviceManagerDndActionCopy DataDeviceManagerDndAction = 1 - // DataDeviceManagerDndActionMove : move action - DataDeviceManagerDndActionMove DataDeviceManagerDndAction = 2 - // DataDeviceManagerDndActionAsk : ask action - DataDeviceManagerDndActionAsk DataDeviceManagerDndAction = 4 -) - -func (e DataDeviceManagerDndAction) Name() string { - switch e { - case DataDeviceManagerDndActionNone: - return "none" - case DataDeviceManagerDndActionCopy: - return "copy" - case DataDeviceManagerDndActionMove: - return "move" - case DataDeviceManagerDndActionAsk: - return "ask" - default: - return "" - } -} - -func (e DataDeviceManagerDndAction) Value() string { - switch e { - case DataDeviceManagerDndActionNone: - return "0" - case DataDeviceManagerDndActionCopy: - return "1" - case DataDeviceManagerDndActionMove: - return "2" - case DataDeviceManagerDndActionAsk: - return "4" - default: - return "" - } -} - -func (e DataDeviceManagerDndAction) String() string { - return e.Name() + "=" + e.Value() -} - -// ShellInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ShellInterfaceName = "wl_shell" - -// Shell : create desktop-style surfaces -// -// This interface is implemented by servers that provide -// desktop-style user interfaces. -// -// It allows clients to associate a wl_shell_surface with -// a basic surface. -// -// Note! This protocol is deprecated and not intended for production use. -// For desktop-style user interfaces, use xdg_shell. Compositors and clients -// should not implement this interface. -type Shell struct { - BaseProxy -} - -// NewShell : create desktop-style surfaces -// -// This interface is implemented by servers that provide -// desktop-style user interfaces. -// -// It allows clients to associate a wl_shell_surface with -// a basic surface. -// -// Note! This protocol is deprecated and not intended for production use. -// For desktop-style user interfaces, use xdg_shell. Compositors and clients -// should not implement this interface. -func NewShell(ctx *Context) *Shell { - wlShell := &Shell{} - ctx.Register(wlShell) - return wlShell -} - -// GetShellSurface : create a shell surface from a surface -// -// Create a shell surface for an existing surface. This gives -// the wl_surface the role of a shell surface. If the wl_surface -// already has another role, it raises a protocol error. -// -// Only one shell surface can be associated with a given surface. -// -// surface: surface to be given the shell surface role -func (i *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) { - id := NewShellSurface(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -func (i *Shell) Destroy() error { - i.MarkZombie() - return nil -} - -type ShellError uint32 - -// ShellError : -const ( - // ShellErrorRole : given wl_surface has another role - ShellErrorRole ShellError = 0 -) - -func (e ShellError) Name() string { - switch e { - case ShellErrorRole: - return "role" - default: - return "" - } -} - -func (e ShellError) Value() string { - switch e { - case ShellErrorRole: - return "0" - default: - return "" - } -} - -func (e ShellError) String() string { - return e.Name() + "=" + e.Value() -} - -// ShellSurfaceInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const ShellSurfaceInterfaceName = "wl_shell_surface" - -// ShellSurface : desktop-style metadata interface -// -// An interface that may be implemented by a wl_surface, for -// implementations that provide a desktop-style user interface. -// -// It provides requests to treat surfaces like toplevel, fullscreen -// or popup windows, move, resize or maximize them, associate -// metadata like title and class, etc. -// -// On the server side the object is automatically destroyed when -// the related wl_surface is destroyed. On the client side, -// wl_shell_surface_destroy() must be called before destroying -// the wl_surface object. -type ShellSurface struct { - BaseProxy - pingHandler ShellSurfacePingHandlerFunc - configureHandler ShellSurfaceConfigureHandlerFunc - popupDoneHandler ShellSurfacePopupDoneHandlerFunc -} - -// NewShellSurface : desktop-style metadata interface -// -// An interface that may be implemented by a wl_surface, for -// implementations that provide a desktop-style user interface. -// -// It provides requests to treat surfaces like toplevel, fullscreen -// or popup windows, move, resize or maximize them, associate -// metadata like title and class, etc. -// -// On the server side the object is automatically destroyed when -// the related wl_surface is destroyed. On the client side, -// wl_shell_surface_destroy() must be called before destroying -// the wl_surface object. -func NewShellSurface(ctx *Context) *ShellSurface { - wlShellSurface := &ShellSurface{} - ctx.Register(wlShellSurface) - return wlShellSurface -} - -// Pong : respond to a ping event -// -// A client must respond to a ping event with a pong request or -// the client may be deemed unresponsive. -// -// serial: serial number of the ping event -func (i *ShellSurface) Pong(serial uint32) error { - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Move : start an interactive move -// -// Start a pointer-driven move of the surface. -// -// This request must be used in response to a button press event. -// The server may ignore move requests depending on the state of -// the surface (e.g. fullscreen or maximized). -// -// seat: seat whose pointer is used -// serial: serial number of the implicit grab on the pointer -func (i *ShellSurface) Move(seat *Seat, serial uint32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Resize : start an interactive resize -// -// Start a pointer-driven resizing of the surface. -// -// This request must be used in response to a button press event. -// The server may ignore resize requests depending on the state of -// the surface (e.g. fullscreen or maximized). -// -// seat: seat whose pointer is used -// serial: serial number of the implicit grab on the pointer -// edges: which edge or corner is being dragged -func (i *ShellSurface) Resize(seat *Seat, serial, edges uint32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(edges)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetToplevel : make the surface a toplevel surface -// -// Map the surface as a toplevel surface. -// -// A toplevel surface is not fullscreen, maximized or transient. -func (i *ShellSurface) SetToplevel() error { - const opcode = 3 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetTransient : make the surface a transient surface -// -// Map the surface relative to an existing surface. -// -// The x and y arguments specify the location of the upper left -// corner of the surface relative to the upper left corner of the -// parent surface, in surface-local coordinates. -// -// The flags argument controls details of the transient behaviour. -// -// parent: parent surface -// x: surface-local x coordinate -// y: surface-local y coordinate -// flags: transient surface behavior -func (i *ShellSurface) SetTransient(parent *Surface, x, y int32, flags uint32) error { - const opcode = 4 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], parent.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(flags)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetFullscreen : make the surface a fullscreen surface -// -// Map the surface as a fullscreen surface. -// -// If an output parameter is given then the surface will be made -// fullscreen on that output. If the client does not specify the -// output then the compositor will apply its policy - usually -// choosing the output on which the surface has the biggest surface -// area. -// -// The client may specify a method to resolve a size conflict -// between the output size and the surface size - this is provided -// through the method parameter. -// -// The framerate parameter is used only when the method is set -// to "driver", to indicate the preferred framerate. A value of 0 -// indicates that the client does not care about framerate. The -// framerate is specified in mHz, that is framerate of 60000 is 60Hz. -// -// A method of "scale" or "driver" implies a scaling operation of -// the surface, either via a direct scaling operation or a change of -// the output mode. This will override any kind of output scaling, so -// that mapping a surface with a buffer size equal to the mode can -// fill the screen independent of buffer_scale. -// -// A method of "fill" means we don't scale up the buffer, however -// any output scale is applied. This means that you may run into -// an edge case where the application maps a buffer with the same -// size of the output mode but buffer_scale 1 (thus making a -// surface larger than the output). In this case it is allowed to -// downscale the results to fit the screen. -// -// The compositor must reply to this request with a configure event -// with the dimensions for the output on which the surface will -// be made fullscreen. -// -// method: method for resolving size conflict -// framerate: framerate in mHz -// output: output on which the surface is to be fullscreen -func (i *ShellSurface) SetFullscreen(method, framerate uint32, output *Output) error { - const opcode = 5 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(method)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(framerate)) - l += 4 - if output == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetPopup : make the surface a popup surface -// -// Map the surface as a popup. -// -// A popup surface is a transient surface with an added pointer -// grab. -// -// An existing implicit grab will be changed to owner-events mode, -// and the popup grab will continue after the implicit grab ends -// (i.e. releasing the mouse button does not cause the popup to -// be unmapped). -// -// The popup grab continues until the window is destroyed or a -// mouse button is pressed in any other client's window. A click -// in any of the client's surfaces is reported as normal, however, -// clicks in other clients' surfaces will be discarded and trigger -// the callback. -// -// The x and y arguments specify the location of the upper left -// corner of the surface relative to the upper left corner of the -// parent surface, in surface-local coordinates. -// -// seat: seat whose pointer is used -// serial: serial number of the implicit grab on the pointer -// parent: parent surface -// x: surface-local x coordinate -// y: surface-local y coordinate -// flags: transient surface behavior -func (i *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x, y int32, flags uint32) error { - const opcode = 6 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], seat.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - PutUint32(_reqBuf[l:l+4], parent.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(flags)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetMaximized : make the surface a maximized surface -// -// Map the surface as a maximized surface. -// -// If an output parameter is given then the surface will be -// maximized on that output. If the client does not specify the -// output then the compositor will apply its policy - usually -// choosing the output on which the surface has the biggest surface -// area. -// -// The compositor will reply with a configure event telling -// the expected new surface size. The operation is completed -// on the next buffer attach to this surface. -// -// A maximized surface typically fills the entire output it is -// bound to, except for desktop elements such as panels. This is -// the main difference between a maximized shell surface and a -// fullscreen shell surface. -// -// The details depend on the compositor implementation. -// -// output: output on which the surface is to be maximized -func (i *ShellSurface) SetMaximized(output *Output) error { - const opcode = 7 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if output == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], output.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetTitle : set surface title -// -// Set a short title for the surface. -// -// This string may be used to identify the surface in a task bar, -// window list, or other user interface elements provided by the -// compositor. -// -// The string must be encoded in UTF-8. -// -// title: surface title -func (i *ShellSurface) SetTitle(title string) error { - const opcode = 8 - titleLen := PaddedLen(len(title) + 1) - _reqBufLen := 8 + (4 + titleLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutString(_reqBuf[l:l+(4+titleLen)], title) - l += (4 + titleLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -// SetClass : set surface class -// -// Set a class for the surface. -// -// The surface class identifies the general class of applications -// to which the surface belongs. A common convention is to use the -// file name (or the full path if it is a non-standard location) of -// the application's .desktop file as the class. -// -// class: surface class -func (i *ShellSurface) SetClass(class string) error { - const opcode = 9 - classLen := PaddedLen(len(class) + 1) - _reqBufLen := 8 + (4 + classLen) - _reqBuf := make([]byte, _reqBufLen) - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutString(_reqBuf[l:l+(4+classLen)], class) - l += (4 + classLen) - err := i.Context().WriteMsg(_reqBuf, nil) - return err -} - -func (i *ShellSurface) Destroy() error { - i.MarkZombie() - return nil -} - -type ShellSurfaceResize uint32 - -// ShellSurfaceResize : edge values for resizing -// -// These values are used to indicate which edge of a surface -// is being dragged in a resize operation. The server may -// use this information to adapt its behavior, e.g. choose -// an appropriate cursor image. -const ( - // ShellSurfaceResizeNone : no edge - ShellSurfaceResizeNone ShellSurfaceResize = 0 - // ShellSurfaceResizeTop : top edge - ShellSurfaceResizeTop ShellSurfaceResize = 1 - // ShellSurfaceResizeBottom : bottom edge - ShellSurfaceResizeBottom ShellSurfaceResize = 2 - // ShellSurfaceResizeLeft : left edge - ShellSurfaceResizeLeft ShellSurfaceResize = 4 - // ShellSurfaceResizeTopLeft : top and left edges - ShellSurfaceResizeTopLeft ShellSurfaceResize = 5 - // ShellSurfaceResizeBottomLeft : bottom and left edges - ShellSurfaceResizeBottomLeft ShellSurfaceResize = 6 - // ShellSurfaceResizeRight : right edge - ShellSurfaceResizeRight ShellSurfaceResize = 8 - // ShellSurfaceResizeTopRight : top and right edges - ShellSurfaceResizeTopRight ShellSurfaceResize = 9 - // ShellSurfaceResizeBottomRight : bottom and right edges - ShellSurfaceResizeBottomRight ShellSurfaceResize = 10 -) - -func (e ShellSurfaceResize) Name() string { - switch e { - case ShellSurfaceResizeNone: - return "none" - case ShellSurfaceResizeTop: - return "top" - case ShellSurfaceResizeBottom: - return "bottom" - case ShellSurfaceResizeLeft: - return "left" - case ShellSurfaceResizeTopLeft: - return "top_left" - case ShellSurfaceResizeBottomLeft: - return "bottom_left" - case ShellSurfaceResizeRight: - return "right" - case ShellSurfaceResizeTopRight: - return "top_right" - case ShellSurfaceResizeBottomRight: - return "bottom_right" - default: - return "" - } -} - -func (e ShellSurfaceResize) Value() string { - switch e { - case ShellSurfaceResizeNone: - return "0" - case ShellSurfaceResizeTop: - return "1" - case ShellSurfaceResizeBottom: - return "2" - case ShellSurfaceResizeLeft: - return "4" - case ShellSurfaceResizeTopLeft: - return "5" - case ShellSurfaceResizeBottomLeft: - return "6" - case ShellSurfaceResizeRight: - return "8" - case ShellSurfaceResizeTopRight: - return "9" - case ShellSurfaceResizeBottomRight: - return "10" - default: - return "" - } -} - -func (e ShellSurfaceResize) String() string { - return e.Name() + "=" + e.Value() -} - -type ShellSurfaceTransient uint32 - -// ShellSurfaceTransient : details of transient behaviour -// -// These flags specify details of the expected behaviour -// of transient surfaces. Used in the set_transient request. -const ( - // ShellSurfaceTransientInactive : do not set keyboard focus - ShellSurfaceTransientInactive ShellSurfaceTransient = 0x1 -) - -func (e ShellSurfaceTransient) Name() string { - switch e { - case ShellSurfaceTransientInactive: - return "inactive" - default: - return "" - } -} - -func (e ShellSurfaceTransient) Value() string { - switch e { - case ShellSurfaceTransientInactive: - return "0x1" - default: - return "" - } -} - -func (e ShellSurfaceTransient) String() string { - return e.Name() + "=" + e.Value() -} - -type ShellSurfaceFullscreenMethod uint32 - -// ShellSurfaceFullscreenMethod : different method to set the surface fullscreen -// -// Hints to indicate to the compositor how to deal with a conflict -// between the dimensions of the surface and the dimensions of the -// output. The compositor is free to ignore this parameter. -const ( - // ShellSurfaceFullscreenMethodDefault : no preference, apply default policy - ShellSurfaceFullscreenMethodDefault ShellSurfaceFullscreenMethod = 0 - // ShellSurfaceFullscreenMethodScale : scale, preserve the surface's aspect ratio and center on output - ShellSurfaceFullscreenMethodScale ShellSurfaceFullscreenMethod = 1 - // ShellSurfaceFullscreenMethodDriver : switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch - ShellSurfaceFullscreenMethodDriver ShellSurfaceFullscreenMethod = 2 - // ShellSurfaceFullscreenMethodFill : no upscaling, center on output and add black borders to compensate size mismatch - ShellSurfaceFullscreenMethodFill ShellSurfaceFullscreenMethod = 3 -) - -func (e ShellSurfaceFullscreenMethod) Name() string { - switch e { - case ShellSurfaceFullscreenMethodDefault: - return "default" - case ShellSurfaceFullscreenMethodScale: - return "scale" - case ShellSurfaceFullscreenMethodDriver: - return "driver" - case ShellSurfaceFullscreenMethodFill: - return "fill" - default: - return "" - } -} - -func (e ShellSurfaceFullscreenMethod) Value() string { - switch e { - case ShellSurfaceFullscreenMethodDefault: - return "0" - case ShellSurfaceFullscreenMethodScale: - return "1" - case ShellSurfaceFullscreenMethodDriver: - return "2" - case ShellSurfaceFullscreenMethodFill: - return "3" - default: - return "" - } -} - -func (e ShellSurfaceFullscreenMethod) String() string { - return e.Name() + "=" + e.Value() -} - -// ShellSurfacePingEvent : ping client -// -// Ping a client to check if it is receiving events and sending -// requests. A client is expected to reply with a pong request. -type ShellSurfacePingEvent struct { - Serial uint32 -} -type ShellSurfacePingHandlerFunc func(ShellSurfacePingEvent) - -// SetPingHandler : sets handler for ShellSurfacePingEvent -func (i *ShellSurface) SetPingHandler(f ShellSurfacePingHandlerFunc) { - i.pingHandler = f -} - -// ShellSurfaceConfigureEvent : suggest resize -// -// The configure event asks the client to resize its surface. -// -// The size is a hint, in the sense that the client is free to -// ignore it if it doesn't resize, pick a smaller size (to -// satisfy aspect ratio or resize in steps of NxM pixels). -// -// The edges parameter provides a hint about how the surface -// was resized. The client may use this information to decide -// how to adjust its content to the new size (e.g. a scrolling -// area might adjust its content position to leave the viewable -// content unmoved). -// -// The client is free to dismiss all but the last configure -// event it received. -// -// The width and height arguments specify the size of the window -// in surface-local coordinates. -type ShellSurfaceConfigureEvent struct { - Edges uint32 - Width int32 - Height int32 -} -type ShellSurfaceConfigureHandlerFunc func(ShellSurfaceConfigureEvent) - -// SetConfigureHandler : sets handler for ShellSurfaceConfigureEvent -func (i *ShellSurface) SetConfigureHandler(f ShellSurfaceConfigureHandlerFunc) { - i.configureHandler = f -} - -// ShellSurfacePopupDoneEvent : popup interaction is done -// -// The popup_done event is sent out when a popup grab is broken, -// that is, when the user clicks a surface that doesn't belong -// to the client owning the popup surface. -type ShellSurfacePopupDoneEvent struct{} -type ShellSurfacePopupDoneHandlerFunc func(ShellSurfacePopupDoneEvent) - -// SetPopupDoneHandler : sets handler for ShellSurfacePopupDoneEvent -func (i *ShellSurface) SetPopupDoneHandler(f ShellSurfacePopupDoneHandlerFunc) { - i.popupDoneHandler = f -} - -func (i *ShellSurface) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.pingHandler == nil { - return - } - var e ShellSurfacePingEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - - i.pingHandler(e) - case 1: - if i.configureHandler == nil { - return - } - var e ShellSurfaceConfigureEvent - l := 0 - e.Edges = Uint32(data[l : l+4]) - l += 4 - e.Width = int32(Uint32(data[l : l+4])) - l += 4 - e.Height = int32(Uint32(data[l : l+4])) - l += 4 - - i.configureHandler(e) - case 2: - if i.popupDoneHandler == nil { - return - } - var e ShellSurfacePopupDoneEvent - - i.popupDoneHandler(e) - } -} - -// SurfaceInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const SurfaceInterfaceName = "wl_surface" - -// Surface : an onscreen surface -// -// A surface is a rectangular area that may be displayed on zero -// or more outputs, and shown any number of times at the compositor's -// discretion. They can present wl_buffers, receive user input, and -// define a local coordinate system. -// -// The size of a surface (and relative positions on it) is described -// in surface-local coordinates, which may differ from the buffer -// coordinates of the pixel content, in case a buffer_transform -// or a buffer_scale is used. -// -// A surface without a "role" is fairly useless: a compositor does -// not know where, when or how to present it. The role is the -// purpose of a wl_surface. Examples of roles are a cursor for a -// pointer (as set by wl_pointer.set_cursor), a drag icon -// (wl_data_device.start_drag), a sub-surface -// (wl_subcompositor.get_subsurface), and a window as defined by a -// shell protocol (e.g. wl_shell.get_shell_surface). -// -// A surface can have only one role at a time. Initially a -// wl_surface does not have a role. Once a wl_surface is given a -// role, it is set permanently for the whole lifetime of the -// wl_surface object. Giving the current role again is allowed, -// unless explicitly forbidden by the relevant interface -// specification. -// -// Surface roles are given by requests in other interfaces such as -// wl_pointer.set_cursor. The request should explicitly mention -// that this request gives a role to a wl_surface. Often, this -// request also creates a new protocol object that represents the -// role and adds additional functionality to wl_surface. When a -// client wants to destroy a wl_surface, they must destroy this role -// object before the wl_surface, otherwise a defunct_role_object error is -// sent. -// -// Destroying the role object does not remove the role from the -// wl_surface, but it may stop the wl_surface from "playing the role". -// For instance, if a wl_subsurface object is destroyed, the wl_surface -// it was created for will be unmapped and forget its position and -// z-order. It is allowed to create a wl_subsurface for the same -// wl_surface again, but it is not allowed to use the wl_surface as -// a cursor (cursor is a different role than sub-surface, and role -// switching is not allowed). -type Surface struct { - BaseProxy - enterHandler SurfaceEnterHandlerFunc - leaveHandler SurfaceLeaveHandlerFunc - preferredBufferScaleHandler SurfacePreferredBufferScaleHandlerFunc - preferredBufferTransformHandler SurfacePreferredBufferTransformHandlerFunc -} - -// NewSurface : an onscreen surface -// -// A surface is a rectangular area that may be displayed on zero -// or more outputs, and shown any number of times at the compositor's -// discretion. They can present wl_buffers, receive user input, and -// define a local coordinate system. -// -// The size of a surface (and relative positions on it) is described -// in surface-local coordinates, which may differ from the buffer -// coordinates of the pixel content, in case a buffer_transform -// or a buffer_scale is used. -// -// A surface without a "role" is fairly useless: a compositor does -// not know where, when or how to present it. The role is the -// purpose of a wl_surface. Examples of roles are a cursor for a -// pointer (as set by wl_pointer.set_cursor), a drag icon -// (wl_data_device.start_drag), a sub-surface -// (wl_subcompositor.get_subsurface), and a window as defined by a -// shell protocol (e.g. wl_shell.get_shell_surface). -// -// A surface can have only one role at a time. Initially a -// wl_surface does not have a role. Once a wl_surface is given a -// role, it is set permanently for the whole lifetime of the -// wl_surface object. Giving the current role again is allowed, -// unless explicitly forbidden by the relevant interface -// specification. -// -// Surface roles are given by requests in other interfaces such as -// wl_pointer.set_cursor. The request should explicitly mention -// that this request gives a role to a wl_surface. Often, this -// request also creates a new protocol object that represents the -// role and adds additional functionality to wl_surface. When a -// client wants to destroy a wl_surface, they must destroy this role -// object before the wl_surface, otherwise a defunct_role_object error is -// sent. -// -// Destroying the role object does not remove the role from the -// wl_surface, but it may stop the wl_surface from "playing the role". -// For instance, if a wl_subsurface object is destroyed, the wl_surface -// it was created for will be unmapped and forget its position and -// z-order. It is allowed to create a wl_subsurface for the same -// wl_surface again, but it is not allowed to use the wl_surface as -// a cursor (cursor is a different role than sub-surface, and role -// switching is not allowed). -func NewSurface(ctx *Context) *Surface { - wlSurface := &Surface{} - ctx.Register(wlSurface) - return wlSurface -} - -// Destroy : delete surface -// -// Deletes the surface and invalidates its object ID. -func (i *Surface) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Attach : set the surface contents -// -// Set a buffer as the content of this surface. -// -// The new size of the surface is calculated based on the buffer -// size transformed by the inverse buffer_transform and the -// inverse buffer_scale. This means that at commit time the supplied -// buffer size must be an integer multiple of the buffer_scale. If -// that's not the case, an invalid_size error is sent. -// -// The x and y arguments specify the location of the new pending -// buffer's upper left corner, relative to the current buffer's upper -// left corner, in surface-local coordinates. In other words, the -// x and y, combined with the new surface size define in which -// directions the surface's size changes. Setting anything other than 0 -// as x and y arguments is discouraged, and should instead be replaced -// with using the separate wl_surface.offset request. -// -// When the bound wl_surface version is 5 or higher, passing any -// non-zero x or y is a protocol violation, and will result in an -// 'invalid_offset' error being raised. The x and y arguments are ignored -// and do not change the pending state. To achieve equivalent semantics, -// use wl_surface.offset. -// -// Surface contents are double-buffered state, see wl_surface.commit. -// -// The initial surface contents are void; there is no content. -// wl_surface.attach assigns the given wl_buffer as the pending -// wl_buffer. wl_surface.commit makes the pending wl_buffer the new -// surface contents, and the size of the surface becomes the size -// calculated from the wl_buffer, as described above. After commit, -// there is no pending buffer until the next attach. -// -// Committing a pending wl_buffer allows the compositor to read the -// pixels in the wl_buffer. The compositor may access the pixels at -// any time after the wl_surface.commit request. When the compositor -// will not access the pixels anymore, it will send the -// wl_buffer.release event. Only after receiving wl_buffer.release, -// the client may reuse the wl_buffer. A wl_buffer that has been -// attached and then replaced by another attach instead of committed -// will not receive a release event, and is not used by the -// compositor. -// -// If a pending wl_buffer has been committed to more than one wl_surface, -// the delivery of wl_buffer.release events becomes undefined. A well -// behaved client should not rely on wl_buffer.release events in this -// case. Alternatively, a client could create multiple wl_buffer objects -// from the same backing storage or use a protocol extension providing -// per-commit release notifications. -// -// Destroying the wl_buffer after wl_buffer.release does not change -// the surface contents. Destroying the wl_buffer before wl_buffer.release -// is allowed as long as the underlying buffer storage isn't re-used (this -// can happen e.g. on client process termination). However, if the client -// destroys the wl_buffer before receiving the wl_buffer.release event and -// mutates the underlying buffer storage, the surface contents become -// undefined immediately. -// -// If wl_surface.attach is sent with a NULL wl_buffer, the -// following wl_surface.commit will remove the surface content. -// -// If a pending wl_buffer has been destroyed, the result is not specified. -// Many compositors are known to remove the surface content on the following -// wl_surface.commit, but this behaviour is not universal. Clients seeking to -// maximise compatibility should not destroy pending buffers and should -// ensure that they explicitly remove content from surfaces, even after -// destroying buffers. -// -// buffer: buffer of surface contents -// x: surface-local x coordinate -// y: surface-local y coordinate -func (i *Surface) Attach(buffer *Buffer, x, y int32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if buffer == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], buffer.ID()) - l += 4 - } - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Damage : mark part of the surface damaged -// -// This request is used to describe the regions where the pending -// buffer is different from the current surface contents, and where -// the surface therefore needs to be repainted. The compositor -// ignores the parts of the damage that fall outside of the surface. -// -// Damage is double-buffered state, see wl_surface.commit. -// -// The damage rectangle is specified in surface-local coordinates, -// where x and y specify the upper left corner of the damage rectangle. -// -// The initial value for pending damage is empty: no damage. -// wl_surface.damage adds pending damage: the new pending damage -// is the union of old pending damage and the given rectangle. -// -// wl_surface.commit assigns pending damage as the current damage, -// and clears pending damage. The server will clear the current -// damage as it repaints the surface. -// -// Note! New clients should not use this request. Instead damage can be -// posted with wl_surface.damage_buffer which uses buffer coordinates -// instead of surface coordinates. -// -// x: surface-local x coordinate -// y: surface-local y coordinate -// width: width of damage rectangle -// height: height of damage rectangle -func (i *Surface) Damage(x, y, width, height int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Frame : request a frame throttling hint -// -// Request a notification when it is a good time to start drawing a new -// frame, by creating a frame callback. This is useful for throttling -// redrawing operations, and driving animations. -// -// When a client is animating on a wl_surface, it can use the 'frame' -// request to get notified when it is a good time to draw and commit the -// next frame of animation. If the client commits an update earlier than -// that, it is likely that some updates will not make it to the display, -// and the client is wasting resources by drawing too often. -// -// The frame request will take effect on the next wl_surface.commit. -// The notification will only be posted for one frame unless -// requested again. For a wl_surface, the notifications are posted in -// the order the frame requests were committed. -// -// The server must send the notifications so that a client -// will not send excessive updates, while still allowing -// the highest possible update rate for clients that wait for the reply -// before drawing again. The server should give some time for the client -// to draw and commit after sending the frame callback events to let it -// hit the next output refresh. -// -// A server should avoid signaling the frame callbacks if the -// surface is not visible in any way, e.g. the surface is off-screen, -// or completely obscured by other opaque surfaces. -// -// The object returned by this request will be destroyed by the -// compositor after the callback is fired and as such the client must not -// attempt to use it after that point. -// -// The callback_data passed in the callback is the current time, in -// milliseconds, with an undefined base. -func (i *Surface) Frame() (*Callback, error) { - callback := NewCallback(i.Context()) - const opcode = 3 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], callback.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return callback, err -} - -// SetOpaqueRegion : set opaque region -// -// This request sets the region of the surface that contains -// opaque content. -// -// The opaque region is an optimization hint for the compositor -// that lets it optimize the redrawing of content behind opaque -// regions. Setting an opaque region is not required for correct -// behaviour, but marking transparent content as opaque will result -// in repaint artifacts. -// -// The opaque region is specified in surface-local coordinates. -// -// The compositor ignores the parts of the opaque region that fall -// outside of the surface. -// -// Opaque region is double-buffered state, see wl_surface.commit. -// -// wl_surface.set_opaque_region changes the pending opaque region. -// wl_surface.commit copies the pending region to the current region. -// Otherwise, the pending and current regions are never changed. -// -// The initial value for an opaque region is empty. Setting the pending -// opaque region has copy semantics, and the wl_region object can be -// destroyed immediately. A NULL wl_region causes the pending opaque -// region to be set to empty. -// -// region: opaque region of the surface -func (i *Surface) SetOpaqueRegion(region *Region) error { - const opcode = 4 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if region == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], region.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetInputRegion : set input region -// -// This request sets the region of the surface that can receive -// pointer and touch events. -// -// Input events happening outside of this region will try the next -// surface in the server surface stack. The compositor ignores the -// parts of the input region that fall outside of the surface. -// -// The input region is specified in surface-local coordinates. -// -// Input region is double-buffered state, see wl_surface.commit. -// -// wl_surface.set_input_region changes the pending input region. -// wl_surface.commit copies the pending region to the current region. -// Otherwise the pending and current regions are never changed, -// except cursor and icon surfaces are special cases, see -// wl_pointer.set_cursor and wl_data_device.start_drag. -// -// The initial value for an input region is infinite. That means the -// whole surface will accept input. Setting the pending input region -// has copy semantics, and the wl_region object can be destroyed -// immediately. A NULL wl_region causes the input region to be set -// to infinite. -// -// region: input region of the surface -func (i *Surface) SetInputRegion(region *Region) error { - const opcode = 5 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - if region == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], region.ID()) - l += 4 - } - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Commit : commit pending surface state -// -// Surface state (input, opaque, and damage regions, attached buffers, -// etc.) is double-buffered. Protocol requests modify the pending state, -// as opposed to the active state in use by the compositor. -// -// A commit request atomically creates a content update from the pending -// state, even if the pending state has not been touched. The content -// update is placed in a queue until it becomes active. After commit, the -// new pending state is as documented for each related request. -// -// When the content update is applied, the wl_buffer is applied before all -// other state. This means that all coordinates in double-buffered state -// are relative to the newly attached wl_buffers, except for -// wl_surface.attach itself. If there is no newly attached wl_buffer, the -// coordinates are relative to the previous content update. -// -// All requests that need a commit to become effective are documented -// to affect double-buffered state. -// -// Other interfaces may add further double-buffered surface state. -func (i *Surface) Commit() error { - const opcode = 6 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetBufferTransform : sets the buffer transformation -// -// This request sets the transformation that the client has already applied -// to the content of the buffer. The accepted values for the transform -// parameter are the values for wl_output.transform. -// -// The compositor applies the inverse of this transformation whenever it -// uses the buffer contents. -// -// Buffer transform is double-buffered state, see wl_surface.commit. -// -// A newly created surface has its buffer transformation set to normal. -// -// wl_surface.set_buffer_transform changes the pending buffer -// transformation. wl_surface.commit copies the pending buffer -// transformation to the current one. Otherwise, the pending and current -// values are never changed. -// -// The purpose of this request is to allow clients to render content -// according to the output transform, thus permitting the compositor to -// use certain optimizations even if the display is rotated. Using -// hardware overlays and scanning out a client buffer for fullscreen -// surfaces are examples of such optimizations. Those optimizations are -// highly dependent on the compositor implementation, so the use of this -// request should be considered on a case-by-case basis. -// -// Note that if the transform value includes 90 or 270 degree rotation, -// the width of the buffer will become the surface height and the height -// of the buffer will become the surface width. -// -// If transform is not one of the values from the -// wl_output.transform enum the invalid_transform protocol error -// is raised. -// -// transform: transform for interpreting buffer contents -func (i *Surface) SetBufferTransform(transform int32) error { - const opcode = 7 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(transform)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetBufferScale : sets the buffer scaling factor -// -// This request sets an optional scaling factor on how the compositor -// interprets the contents of the buffer attached to the window. -// -// Buffer scale is double-buffered state, see wl_surface.commit. -// -// A newly created surface has its buffer scale set to 1. -// -// wl_surface.set_buffer_scale changes the pending buffer scale. -// wl_surface.commit copies the pending buffer scale to the current one. -// Otherwise, the pending and current values are never changed. -// -// The purpose of this request is to allow clients to supply higher -// resolution buffer data for use on high resolution outputs. It is -// intended that you pick the same buffer scale as the scale of the -// output that the surface is displayed on. This means the compositor -// can avoid scaling when rendering the surface on that output. -// -// Note that if the scale is larger than 1, then you have to attach -// a buffer that is larger (by a factor of scale in each dimension) -// than the desired surface size. -// -// If scale is not greater than 0 the invalid_scale protocol error is -// raised. -// -// scale: scale for interpreting buffer contents -func (i *Surface) SetBufferScale(scale int32) error { - const opcode = 8 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(scale)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// DamageBuffer : mark part of the surface damaged using buffer coordinates -// -// This request is used to describe the regions where the pending -// buffer is different from the current surface contents, and where -// the surface therefore needs to be repainted. The compositor -// ignores the parts of the damage that fall outside of the surface. -// -// Damage is double-buffered state, see wl_surface.commit. -// -// The damage rectangle is specified in buffer coordinates, -// where x and y specify the upper left corner of the damage rectangle. -// -// The initial value for pending damage is empty: no damage. -// wl_surface.damage_buffer adds pending damage: the new pending -// damage is the union of old pending damage and the given rectangle. -// -// wl_surface.commit assigns pending damage as the current damage, -// and clears pending damage. The server will clear the current -// damage as it repaints the surface. -// -// This request differs from wl_surface.damage in only one way - it -// takes damage in buffer coordinates instead of surface-local -// coordinates. While this generally is more intuitive than surface -// coordinates, it is especially desirable when using wp_viewport -// or when a drawing library (like EGL) is unaware of buffer scale -// and buffer transform. -// -// Note: Because buffer transformation changes and damage requests may -// be interleaved in the protocol stream, it is impossible to determine -// the actual mapping between surface and buffer damage until -// wl_surface.commit time. Therefore, compositors wishing to take both -// kinds of damage into account will have to accumulate damage from the -// two requests separately and only transform from one to the other -// after receiving the wl_surface.commit. -// -// x: buffer-local x coordinate -// y: buffer-local y coordinate -// width: width of damage rectangle -// height: height of damage rectangle -func (i *Surface) DamageBuffer(x, y, width, height int32) error { - const opcode = 9 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Offset : set the surface contents offset -// -// The x and y arguments specify the location of the new pending -// buffer's upper left corner, relative to the current buffer's upper -// left corner, in surface-local coordinates. In other words, the -// x and y, combined with the new surface size define in which -// directions the surface's size changes. -// -// The exact semantics of wl_surface.offset are role-specific. Refer to -// the documentation of specific roles for more information. -// -// Surface location offset is double-buffered state, see -// wl_surface.commit. -// -// This request is semantically equivalent to and the replaces the x and y -// arguments in the wl_surface.attach request in wl_surface versions prior -// to 5. See wl_surface.attach for details. -// -// x: surface-local x coordinate -// y: surface-local y coordinate -func (i *Surface) Offset(x, y int32) error { - const opcode = 10 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type SurfaceError uint32 - -// SurfaceError : wl_surface error values -// -// These errors can be emitted in response to wl_surface requests. -const ( - // SurfaceErrorInvalidScale : buffer scale value is invalid - SurfaceErrorInvalidScale SurfaceError = 0 - // SurfaceErrorInvalidTransform : buffer transform value is invalid - SurfaceErrorInvalidTransform SurfaceError = 1 - // SurfaceErrorInvalidSize : buffer size is invalid - SurfaceErrorInvalidSize SurfaceError = 2 - // SurfaceErrorInvalidOffset : buffer offset is invalid - SurfaceErrorInvalidOffset SurfaceError = 3 - // SurfaceErrorDefunctRoleObject : surface was destroyed before its role object - SurfaceErrorDefunctRoleObject SurfaceError = 4 -) - -func (e SurfaceError) Name() string { - switch e { - case SurfaceErrorInvalidScale: - return "invalid_scale" - case SurfaceErrorInvalidTransform: - return "invalid_transform" - case SurfaceErrorInvalidSize: - return "invalid_size" - case SurfaceErrorInvalidOffset: - return "invalid_offset" - case SurfaceErrorDefunctRoleObject: - return "defunct_role_object" - default: - return "" - } -} - -func (e SurfaceError) Value() string { - switch e { - case SurfaceErrorInvalidScale: - return "0" - case SurfaceErrorInvalidTransform: - return "1" - case SurfaceErrorInvalidSize: - return "2" - case SurfaceErrorInvalidOffset: - return "3" - case SurfaceErrorDefunctRoleObject: - return "4" - default: - return "" - } -} - -func (e SurfaceError) String() string { - return e.Name() + "=" + e.Value() -} - -// SurfaceEnterEvent : surface enters an output -// -// This is emitted whenever a surface's creation, movement, or resizing -// results in some part of it being within the scanout region of an -// output. -// -// Note that a surface may be overlapping with zero or more outputs. -type SurfaceEnterEvent struct { - Output *Output -} -type SurfaceEnterHandlerFunc func(SurfaceEnterEvent) - -// SetEnterHandler : sets handler for SurfaceEnterEvent -func (i *Surface) SetEnterHandler(f SurfaceEnterHandlerFunc) { - i.enterHandler = f -} - -// SurfaceLeaveEvent : surface leaves an output -// -// This is emitted whenever a surface's creation, movement, or resizing -// results in it no longer having any part of it within the scanout region -// of an output. -// -// Clients should not use the number of outputs the surface is on for frame -// throttling purposes. The surface might be hidden even if no leave event -// has been sent, and the compositor might expect new surface content -// updates even if no enter event has been sent. The frame event should be -// used instead. -type SurfaceLeaveEvent struct { - Output *Output -} -type SurfaceLeaveHandlerFunc func(SurfaceLeaveEvent) - -// SetLeaveHandler : sets handler for SurfaceLeaveEvent -func (i *Surface) SetLeaveHandler(f SurfaceLeaveHandlerFunc) { - i.leaveHandler = f -} - -// SurfacePreferredBufferScaleEvent : preferred buffer scale for the surface -// -// This event indicates the preferred buffer scale for this surface. It is -// sent whenever the compositor's preference changes. -// -// Before receiving this event the preferred buffer scale for this surface -// is 1. -// -// It is intended that scaling aware clients use this event to scale their -// content and use wl_surface.set_buffer_scale to indicate the scale they -// have rendered with. This allows clients to supply a higher detail -// buffer. -// -// The compositor shall emit a scale value greater than 0. -type SurfacePreferredBufferScaleEvent struct { - Factor int32 -} -type SurfacePreferredBufferScaleHandlerFunc func(SurfacePreferredBufferScaleEvent) - -// SetPreferredBufferScaleHandler : sets handler for SurfacePreferredBufferScaleEvent -func (i *Surface) SetPreferredBufferScaleHandler(f SurfacePreferredBufferScaleHandlerFunc) { - i.preferredBufferScaleHandler = f -} - -// SurfacePreferredBufferTransformEvent : preferred buffer transform for the surface -// -// This event indicates the preferred buffer transform for this surface. -// It is sent whenever the compositor's preference changes. -// -// Before receiving this event the preferred buffer transform for this -// surface is normal. -// -// Applying this transformation to the surface buffer contents and using -// wl_surface.set_buffer_transform might allow the compositor to use the -// surface buffer more efficiently. -type SurfacePreferredBufferTransformEvent struct { - Transform uint32 -} -type SurfacePreferredBufferTransformHandlerFunc func(SurfacePreferredBufferTransformEvent) - -// SetPreferredBufferTransformHandler : sets handler for SurfacePreferredBufferTransformEvent -func (i *Surface) SetPreferredBufferTransformHandler(f SurfacePreferredBufferTransformHandlerFunc) { - i.preferredBufferTransformHandler = f -} - -func (i *Surface) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.enterHandler == nil { - return - } - var e SurfaceEnterEvent - l := 0 - e.Output = i.Context().GetProxy(Uint32(data[l : l+4])).(*Output) - l += 4 - - i.enterHandler(e) - case 1: - if i.leaveHandler == nil { - return - } - var e SurfaceLeaveEvent - l := 0 - e.Output = i.Context().GetProxy(Uint32(data[l : l+4])).(*Output) - l += 4 - - i.leaveHandler(e) - case 2: - if i.preferredBufferScaleHandler == nil { - return - } - var e SurfacePreferredBufferScaleEvent - l := 0 - e.Factor = int32(Uint32(data[l : l+4])) - l += 4 - - i.preferredBufferScaleHandler(e) - case 3: - if i.preferredBufferTransformHandler == nil { - return - } - var e SurfacePreferredBufferTransformEvent - l := 0 - e.Transform = Uint32(data[l : l+4]) - l += 4 - - i.preferredBufferTransformHandler(e) - } -} - -// SeatInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const SeatInterfaceName = "wl_seat" - -// Seat : group of input devices -// -// A seat is a group of keyboards, pointer and touch devices. This -// object is published as a global during start up, or when such a -// device is hot plugged. A seat typically has a pointer and -// maintains a keyboard focus and a pointer focus. -type Seat struct { - BaseProxy - capabilitiesHandler SeatCapabilitiesHandlerFunc - nameHandler SeatNameHandlerFunc -} - -// NewSeat : group of input devices -// -// A seat is a group of keyboards, pointer and touch devices. This -// object is published as a global during start up, or when such a -// device is hot plugged. A seat typically has a pointer and -// maintains a keyboard focus and a pointer focus. -func NewSeat(ctx *Context) *Seat { - wlSeat := &Seat{} - ctx.Register(wlSeat) - return wlSeat -} - -// GetPointer : return pointer object -// -// The ID provided will be initialized to the wl_pointer interface -// for this seat. -// -// This request only takes effect if the seat has the pointer -// capability, or has had the pointer capability in the past. -// It is a protocol violation to issue this request on a seat that has -// never had the pointer capability. The missing_capability error will -// be sent in this case. -func (i *Seat) GetPointer() (*Pointer, error) { - id := NewPointer(i.Context()) - const opcode = 0 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// GetKeyboard : return keyboard object -// -// The ID provided will be initialized to the wl_keyboard interface -// for this seat. -// -// This request only takes effect if the seat has the keyboard -// capability, or has had the keyboard capability in the past. -// It is a protocol violation to issue this request on a seat that has -// never had the keyboard capability. The missing_capability error will -// be sent in this case. -func (i *Seat) GetKeyboard() (*Keyboard, error) { - id := NewKeyboard(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// GetTouch : return touch object -// -// The ID provided will be initialized to the wl_touch interface -// for this seat. -// -// This request only takes effect if the seat has the touch -// capability, or has had the touch capability in the past. -// It is a protocol violation to issue this request on a seat that has -// never had the touch capability. The missing_capability error will -// be sent in this case. -func (i *Seat) GetTouch() (*Touch, error) { - id := NewTouch(i.Context()) - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -// Release : release the seat object -// -// Using this request a client can tell the server that it is not going to -// use the seat object anymore. -func (i *Seat) Release() error { - defer i.MarkZombie() - const opcode = 3 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type SeatCapability uint32 - -// SeatCapability : seat capability bitmask -// -// This is a bitmask of capabilities this seat has; if a member is -// set, then it is present on the seat. -const ( - // SeatCapabilityPointer : the seat has pointer devices - SeatCapabilityPointer SeatCapability = 1 - // SeatCapabilityKeyboard : the seat has one or more keyboards - SeatCapabilityKeyboard SeatCapability = 2 - // SeatCapabilityTouch : the seat has touch devices - SeatCapabilityTouch SeatCapability = 4 -) - -func (e SeatCapability) Name() string { - switch e { - case SeatCapabilityPointer: - return "pointer" - case SeatCapabilityKeyboard: - return "keyboard" - case SeatCapabilityTouch: - return "touch" - default: - return "" - } -} - -func (e SeatCapability) Value() string { - switch e { - case SeatCapabilityPointer: - return "1" - case SeatCapabilityKeyboard: - return "2" - case SeatCapabilityTouch: - return "4" - default: - return "" - } -} - -func (e SeatCapability) String() string { - return e.Name() + "=" + e.Value() -} - -type SeatError uint32 - -// SeatError : wl_seat error values -// -// These errors can be emitted in response to wl_seat requests. -const ( - // SeatErrorMissingCapability : get_pointer, get_keyboard or get_touch called on seat without the matching capability - SeatErrorMissingCapability SeatError = 0 -) - -func (e SeatError) Name() string { - switch e { - case SeatErrorMissingCapability: - return "missing_capability" - default: - return "" - } -} - -func (e SeatError) Value() string { - switch e { - case SeatErrorMissingCapability: - return "0" - default: - return "" - } -} - -func (e SeatError) String() string { - return e.Name() + "=" + e.Value() -} - -// SeatCapabilitiesEvent : seat capabilities changed -// -// This is sent on binding to the seat global or whenever a seat gains -// or loses the pointer, keyboard or touch capabilities. -// The argument is a capability enum containing the complete set of -// capabilities this seat has. -// -// When the pointer capability is added, a client may create a -// wl_pointer object using the wl_seat.get_pointer request. This object -// will receive pointer events until the capability is removed in the -// future. -// -// When the pointer capability is removed, a client should destroy the -// wl_pointer objects associated with the seat where the capability was -// removed, using the wl_pointer.release request. No further pointer -// events will be received on these objects. -// -// In some compositors, if a seat regains the pointer capability and a -// client has a previously obtained wl_pointer object of version 4 or -// less, that object may start sending pointer events again. This -// behavior is considered a misinterpretation of the intended behavior -// and must not be relied upon by the client. wl_pointer objects of -// version 5 or later must not send events if created before the most -// recent event notifying the client of an added pointer capability. -// -// The above behavior also applies to wl_keyboard and wl_touch with the -// keyboard and touch capabilities, respectively. -type SeatCapabilitiesEvent struct { - Capabilities uint32 -} -type SeatCapabilitiesHandlerFunc func(SeatCapabilitiesEvent) - -// SetCapabilitiesHandler : sets handler for SeatCapabilitiesEvent -func (i *Seat) SetCapabilitiesHandler(f SeatCapabilitiesHandlerFunc) { - i.capabilitiesHandler = f -} - -// SeatNameEvent : unique identifier for this seat -// -// In a multi-seat configuration the seat name can be used by clients to -// help identify which physical devices the seat represents. -// -// The seat name is a UTF-8 string with no convention defined for its -// contents. Each name is unique among all wl_seat globals. The name is -// only guaranteed to be unique for the current compositor instance. -// -// The same seat names are used for all clients. Thus, the name can be -// shared across processes to refer to a specific wl_seat global. -// -// The name event is sent after binding to the seat global, and should be sent -// before announcing capabilities. This event only sent once per seat object, -// and the name does not change over the lifetime of the wl_seat global. -// -// Compositors may re-use the same seat name if the wl_seat global is -// destroyed and re-created later. -type SeatNameEvent struct { - Name string -} -type SeatNameHandlerFunc func(SeatNameEvent) - -// SetNameHandler : sets handler for SeatNameEvent -func (i *Seat) SetNameHandler(f SeatNameHandlerFunc) { - i.nameHandler = f -} - -func (i *Seat) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.capabilitiesHandler == nil { - return - } - var e SeatCapabilitiesEvent - l := 0 - e.Capabilities = Uint32(data[l : l+4]) - l += 4 - - i.capabilitiesHandler(e) - case 1: - if i.nameHandler == nil { - return - } - var e SeatNameEvent - l := 0 - nameLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Name = String(data[l : l+nameLen]) - l += nameLen - - i.nameHandler(e) - } -} - -// PointerInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const PointerInterfaceName = "wl_pointer" - -// Pointer : pointer input device -// -// The wl_pointer interface represents one or more input devices, -// such as mice, which control the pointer location and pointer_focus -// of a seat. -// -// The wl_pointer interface generates motion, enter and leave -// events for the surfaces that the pointer is located over, -// and button and axis events for button presses, button releases -// and scrolling. -type Pointer struct { - BaseProxy - enterHandler PointerEnterHandlerFunc - leaveHandler PointerLeaveHandlerFunc - motionHandler PointerMotionHandlerFunc - buttonHandler PointerButtonHandlerFunc - axisHandler PointerAxisHandlerFunc - frameHandler PointerFrameHandlerFunc - axisSourceHandler PointerAxisSourceHandlerFunc - axisStopHandler PointerAxisStopHandlerFunc - axisDiscreteHandler PointerAxisDiscreteHandlerFunc - axisValue120Handler PointerAxisValue120HandlerFunc - axisRelativeDirectionHandler PointerAxisRelativeDirectionHandlerFunc -} - -// NewPointer : pointer input device -// -// The wl_pointer interface represents one or more input devices, -// such as mice, which control the pointer location and pointer_focus -// of a seat. -// -// The wl_pointer interface generates motion, enter and leave -// events for the surfaces that the pointer is located over, -// and button and axis events for button presses, button releases -// and scrolling. -func NewPointer(ctx *Context) *Pointer { - wlPointer := &Pointer{} - ctx.Register(wlPointer) - return wlPointer -} - -// SetCursor : set the pointer surface -// -// Set the pointer surface, i.e., the surface that contains the -// pointer image (cursor). This request gives the surface the role -// of a cursor. If the surface already has another role, it raises -// a protocol error. -// -// The cursor actually changes only if the pointer -// focus for this device is one of the requesting client's surfaces -// or the surface parameter is the current pointer surface. If -// there was a previous surface set with this request it is -// replaced. If surface is NULL, the pointer image is hidden. -// -// The parameters hotspot_x and hotspot_y define the position of -// the pointer surface relative to the pointer location. Its -// top-left corner is always at (x, y) - (hotspot_x, hotspot_y), -// where (x, y) are the coordinates of the pointer location, in -// surface-local coordinates. -// -// On wl_surface.offset requests to the pointer surface, hotspot_x -// and hotspot_y are decremented by the x and y parameters -// passed to the request. The offset must be applied by -// wl_surface.commit as usual. -// -// The hotspot can also be updated by passing the currently set -// pointer surface to this request with new values for hotspot_x -// and hotspot_y. -// -// The input region is ignored for wl_surfaces with the role of -// a cursor. When the use as a cursor ends, the wl_surface is -// unmapped. -// -// The serial parameter must match the latest wl_pointer.enter -// serial number sent to the client. Otherwise the request will be -// ignored. -// -// serial: serial number of the enter event -// surface: pointer surface -// hotspotX: surface-local x coordinate -// hotspotY: surface-local y coordinate -func (i *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX, hotspotY int32) error { - const opcode = 0 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(serial)) - l += 4 - if surface == nil { - PutUint32(_reqBuf[l:l+4], 0) - l += 4 - } else { - PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - } - PutUint32(_reqBuf[l:l+4], uint32(hotspotX)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(hotspotY)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Release : release the pointer object -// -// Using this request a client can tell the server that it is not going to -// use the pointer object anymore. -// -// This request destroys the pointer proxy object, so clients must not call -// wl_pointer_destroy() after using this request. -func (i *Pointer) Release() error { - defer i.MarkZombie() - const opcode = 1 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type PointerError uint32 - -// PointerError : -const ( - // PointerErrorRole : given wl_surface has another role - PointerErrorRole PointerError = 0 -) - -func (e PointerError) Name() string { - switch e { - case PointerErrorRole: - return "role" - default: - return "" - } -} - -func (e PointerError) Value() string { - switch e { - case PointerErrorRole: - return "0" - default: - return "" - } -} - -func (e PointerError) String() string { - return e.Name() + "=" + e.Value() -} - -type PointerButtonState uint32 - -// PointerButtonState : physical button state -// -// Describes the physical state of a button that produced the button -// event. -const ( - // PointerButtonStateReleased : the button is not pressed - PointerButtonStateReleased PointerButtonState = 0 - // PointerButtonStatePressed : the button is pressed - PointerButtonStatePressed PointerButtonState = 1 -) - -func (e PointerButtonState) Name() string { - switch e { - case PointerButtonStateReleased: - return "released" - case PointerButtonStatePressed: - return "pressed" - default: - return "" - } -} - -func (e PointerButtonState) Value() string { - switch e { - case PointerButtonStateReleased: - return "0" - case PointerButtonStatePressed: - return "1" - default: - return "" - } -} - -func (e PointerButtonState) String() string { - return e.Name() + "=" + e.Value() -} - -type PointerAxis uint32 - -// PointerAxis : axis types -// -// Describes the axis types of scroll events. -const ( - // PointerAxisVerticalScroll : vertical axis - PointerAxisVerticalScroll PointerAxis = 0 - // PointerAxisHorizontalScroll : horizontal axis - PointerAxisHorizontalScroll PointerAxis = 1 -) - -func (e PointerAxis) Name() string { - switch e { - case PointerAxisVerticalScroll: - return "vertical_scroll" - case PointerAxisHorizontalScroll: - return "horizontal_scroll" - default: - return "" - } -} - -func (e PointerAxis) Value() string { - switch e { - case PointerAxisVerticalScroll: - return "0" - case PointerAxisHorizontalScroll: - return "1" - default: - return "" - } -} - -func (e PointerAxis) String() string { - return e.Name() + "=" + e.Value() -} - -type PointerAxisSource uint32 - -// PointerAxisSource : axis source types -// -// Describes the source types for axis events. This indicates to the -// client how an axis event was physically generated; a client may -// adjust the user interface accordingly. For example, scroll events -// from a "finger" source may be in a smooth coordinate space with -// kinetic scrolling whereas a "wheel" source may be in discrete steps -// of a number of lines. -// -// The "continuous" axis source is a device generating events in a -// continuous coordinate space, but using something other than a -// finger. One example for this source is button-based scrolling where -// the vertical motion of a device is converted to scroll events while -// a button is held down. -// -// The "wheel tilt" axis source indicates that the actual device is a -// wheel but the scroll event is not caused by a rotation but a -// (usually sideways) tilt of the wheel. -const ( - // PointerAxisSourceWheel : a physical wheel rotation - PointerAxisSourceWheel PointerAxisSource = 0 - // PointerAxisSourceFinger : finger on a touch surface - PointerAxisSourceFinger PointerAxisSource = 1 - // PointerAxisSourceContinuous : continuous coordinate space - PointerAxisSourceContinuous PointerAxisSource = 2 - // PointerAxisSourceWheelTilt : a physical wheel tilt - PointerAxisSourceWheelTilt PointerAxisSource = 3 -) - -func (e PointerAxisSource) Name() string { - switch e { - case PointerAxisSourceWheel: - return "wheel" - case PointerAxisSourceFinger: - return "finger" - case PointerAxisSourceContinuous: - return "continuous" - case PointerAxisSourceWheelTilt: - return "wheel_tilt" - default: - return "" - } -} - -func (e PointerAxisSource) Value() string { - switch e { - case PointerAxisSourceWheel: - return "0" - case PointerAxisSourceFinger: - return "1" - case PointerAxisSourceContinuous: - return "2" - case PointerAxisSourceWheelTilt: - return "3" - default: - return "" - } -} - -func (e PointerAxisSource) String() string { - return e.Name() + "=" + e.Value() -} - -type PointerAxisRelativeDirection uint32 - -// PointerAxisRelativeDirection : axis relative direction -// -// This specifies the direction of the physical motion that caused a -// wl_pointer.axis event, relative to the wl_pointer.axis direction. -const ( - // PointerAxisRelativeDirectionIdentical : physical motion matches axis direction - PointerAxisRelativeDirectionIdentical PointerAxisRelativeDirection = 0 - // PointerAxisRelativeDirectionInverted : physical motion is the inverse of the axis direction - PointerAxisRelativeDirectionInverted PointerAxisRelativeDirection = 1 -) - -func (e PointerAxisRelativeDirection) Name() string { - switch e { - case PointerAxisRelativeDirectionIdentical: - return "identical" - case PointerAxisRelativeDirectionInverted: - return "inverted" - default: - return "" - } -} - -func (e PointerAxisRelativeDirection) Value() string { - switch e { - case PointerAxisRelativeDirectionIdentical: - return "0" - case PointerAxisRelativeDirectionInverted: - return "1" - default: - return "" - } -} - -func (e PointerAxisRelativeDirection) String() string { - return e.Name() + "=" + e.Value() -} - -// PointerEnterEvent : enter event -// -// Notification that this seat's pointer is focused on a certain -// surface. -// -// When a seat's focus enters a surface, the pointer image -// is undefined and a client should respond to this event by setting -// an appropriate pointer image with the set_cursor request. -type PointerEnterEvent struct { - Serial uint32 - Surface *Surface - SurfaceX float64 - SurfaceY float64 -} -type PointerEnterHandlerFunc func(PointerEnterEvent) - -// SetEnterHandler : sets handler for PointerEnterEvent -func (i *Pointer) SetEnterHandler(f PointerEnterHandlerFunc) { - i.enterHandler = f -} - -// PointerLeaveEvent : leave event -// -// Notification that this seat's pointer is no longer focused on -// a certain surface. -// -// The leave notification is sent before the enter notification -// for the new focus. -type PointerLeaveEvent struct { - Serial uint32 - Surface *Surface -} -type PointerLeaveHandlerFunc func(PointerLeaveEvent) - -// SetLeaveHandler : sets handler for PointerLeaveEvent -func (i *Pointer) SetLeaveHandler(f PointerLeaveHandlerFunc) { - i.leaveHandler = f -} - -// PointerMotionEvent : pointer motion event -// -// Notification of pointer location change. The arguments -// surface_x and surface_y are the location relative to the -// focused surface. -type PointerMotionEvent struct { - Time uint32 - SurfaceX float64 - SurfaceY float64 -} -type PointerMotionHandlerFunc func(PointerMotionEvent) - -// SetMotionHandler : sets handler for PointerMotionEvent -func (i *Pointer) SetMotionHandler(f PointerMotionHandlerFunc) { - i.motionHandler = f -} - -// PointerButtonEvent : pointer button event -// -// Mouse button click and release notifications. -// -// The location of the click is given by the last motion or -// enter event. -// The time argument is a timestamp with millisecond -// granularity, with an undefined base. -// -// The button is a button code as defined in the Linux kernel's -// linux/input-event-codes.h header file, e.g. BTN_LEFT. -// -// Any 16-bit button code value is reserved for future additions to the -// kernel's event code list. All other button codes above 0xFFFF are -// currently undefined but may be used in future versions of this -// protocol. -type PointerButtonEvent struct { - Serial uint32 - Time uint32 - Button uint32 - State uint32 -} -type PointerButtonHandlerFunc func(PointerButtonEvent) - -// SetButtonHandler : sets handler for PointerButtonEvent -func (i *Pointer) SetButtonHandler(f PointerButtonHandlerFunc) { - i.buttonHandler = f -} - -// PointerAxisEvent : axis event -// -// Scroll and other axis notifications. -// -// For scroll events (vertical and horizontal scroll axes), the -// value parameter is the length of a vector along the specified -// axis in a coordinate space identical to those of motion events, -// representing a relative movement along the specified axis. -// -// For devices that support movements non-parallel to axes multiple -// axis events will be emitted. -// -// When applicable, for example for touch pads, the server can -// choose to emit scroll events where the motion vector is -// equivalent to a motion event vector. -// -// When applicable, a client can transform its content relative to the -// scroll distance. -type PointerAxisEvent struct { - Time uint32 - Axis uint32 - Value float64 -} -type PointerAxisHandlerFunc func(PointerAxisEvent) - -// SetAxisHandler : sets handler for PointerAxisEvent -func (i *Pointer) SetAxisHandler(f PointerAxisHandlerFunc) { - i.axisHandler = f -} - -// PointerFrameEvent : end of a pointer event sequence -// -// Indicates the end of a set of events that logically belong together. -// A client is expected to accumulate the data in all events within the -// frame before proceeding. -// -// All wl_pointer events before a wl_pointer.frame event belong -// logically together. For example, in a diagonal scroll motion the -// compositor will send an optional wl_pointer.axis_source event, two -// wl_pointer.axis events (horizontal and vertical) and finally a -// wl_pointer.frame event. The client may use this information to -// calculate a diagonal vector for scrolling. -// -// When multiple wl_pointer.axis events occur within the same frame, -// the motion vector is the combined motion of all events. -// When a wl_pointer.axis and a wl_pointer.axis_stop event occur within -// the same frame, this indicates that axis movement in one axis has -// stopped but continues in the other axis. -// When multiple wl_pointer.axis_stop events occur within the same -// frame, this indicates that these axes stopped in the same instance. -// -// A wl_pointer.frame event is sent for every logical event group, -// even if the group only contains a single wl_pointer event. -// Specifically, a client may get a sequence: motion, frame, button, -// frame, axis, frame, axis_stop, frame. -// -// The wl_pointer.enter and wl_pointer.leave events are logical events -// generated by the compositor and not the hardware. These events are -// also grouped by a wl_pointer.frame. When a pointer moves from one -// surface to another, a compositor should group the -// wl_pointer.leave event within the same wl_pointer.frame. -// However, a client must not rely on wl_pointer.leave and -// wl_pointer.enter being in the same wl_pointer.frame. -// Compositor-specific policies may require the wl_pointer.leave and -// wl_pointer.enter event being split across multiple wl_pointer.frame -// groups. -type PointerFrameEvent struct{} -type PointerFrameHandlerFunc func(PointerFrameEvent) - -// SetFrameHandler : sets handler for PointerFrameEvent -func (i *Pointer) SetFrameHandler(f PointerFrameHandlerFunc) { - i.frameHandler = f -} - -// PointerAxisSourceEvent : axis source event -// -// Source information for scroll and other axes. -// -// This event does not occur on its own. It is sent before a -// wl_pointer.frame event and carries the source information for -// all events within that frame. -// -// The source specifies how this event was generated. If the source is -// wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be -// sent when the user lifts the finger off the device. -// -// If the source is wl_pointer.axis_source.wheel, -// wl_pointer.axis_source.wheel_tilt or -// wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may -// or may not be sent. Whether a compositor sends an axis_stop event -// for these sources is hardware-specific and implementation-dependent; -// clients must not rely on receiving an axis_stop event for these -// scroll sources and should treat scroll sequences from these scroll -// sources as unterminated by default. -// -// This event is optional. If the source is unknown for a particular -// axis event sequence, no event is sent. -// Only one wl_pointer.axis_source event is permitted per frame. -// -// The order of wl_pointer.axis_discrete and wl_pointer.axis_source is -// not guaranteed. -type PointerAxisSourceEvent struct { - AxisSource uint32 -} -type PointerAxisSourceHandlerFunc func(PointerAxisSourceEvent) - -// SetAxisSourceHandler : sets handler for PointerAxisSourceEvent -func (i *Pointer) SetAxisSourceHandler(f PointerAxisSourceHandlerFunc) { - i.axisSourceHandler = f -} - -// PointerAxisStopEvent : axis stop event -// -// Stop notification for scroll and other axes. -// -// For some wl_pointer.axis_source types, a wl_pointer.axis_stop event -// is sent to notify a client that the axis sequence has terminated. -// This enables the client to implement kinetic scrolling. -// See the wl_pointer.axis_source documentation for information on when -// this event may be generated. -// -// Any wl_pointer.axis events with the same axis_source after this -// event should be considered as the start of a new axis motion. -// -// The timestamp is to be interpreted identical to the timestamp in the -// wl_pointer.axis event. The timestamp value may be the same as a -// preceding wl_pointer.axis event. -type PointerAxisStopEvent struct { - Time uint32 - Axis uint32 -} -type PointerAxisStopHandlerFunc func(PointerAxisStopEvent) - -// SetAxisStopHandler : sets handler for PointerAxisStopEvent -func (i *Pointer) SetAxisStopHandler(f PointerAxisStopHandlerFunc) { - i.axisStopHandler = f -} - -// PointerAxisDiscreteEvent : axis click event -// -// Discrete step information for scroll and other axes. -// -// This event carries the axis value of the wl_pointer.axis event in -// discrete steps (e.g. mouse wheel clicks). -// -// This event is deprecated with wl_pointer version 8 - this event is not -// sent to clients supporting version 8 or later. -// -// This event does not occur on its own, it is coupled with a -// wl_pointer.axis event that represents this axis value on a -// continuous scale. The protocol guarantees that each axis_discrete -// event is always followed by exactly one axis event with the same -// axis number within the same wl_pointer.frame. Note that the protocol -// allows for other events to occur between the axis_discrete and -// its coupled axis event, including other axis_discrete or axis -// events. A wl_pointer.frame must not contain more than one axis_discrete -// event per axis type. -// -// This event is optional; continuous scrolling devices -// like two-finger scrolling on touchpads do not have discrete -// steps and do not generate this event. -// -// The discrete value carries the directional information. e.g. a value -// of -2 is two steps towards the negative direction of this axis. -// -// The axis number is identical to the axis number in the associated -// axis event. -// -// The order of wl_pointer.axis_discrete and wl_pointer.axis_source is -// not guaranteed. -type PointerAxisDiscreteEvent struct { - Axis uint32 - Discrete int32 -} -type PointerAxisDiscreteHandlerFunc func(PointerAxisDiscreteEvent) - -// SetAxisDiscreteHandler : sets handler for PointerAxisDiscreteEvent -func (i *Pointer) SetAxisDiscreteHandler(f PointerAxisDiscreteHandlerFunc) { - i.axisDiscreteHandler = f -} - -// PointerAxisValue120Event : axis high-resolution scroll event -// -// Discrete high-resolution scroll information. -// -// This event carries high-resolution wheel scroll information, -// with each multiple of 120 representing one logical scroll step -// (a wheel detent). For example, an axis_value120 of 30 is one quarter of -// a logical scroll step in the positive direction, a value120 of -// -240 are two logical scroll steps in the negative direction within the -// same hardware event. -// Clients that rely on discrete scrolling should accumulate the -// value120 to multiples of 120 before processing the event. -// -// The value120 must not be zero. -// -// This event replaces the wl_pointer.axis_discrete event in clients -// supporting wl_pointer version 8 or later. -// -// Where a wl_pointer.axis_source event occurs in the same -// wl_pointer.frame, the axis source applies to this event. -// -// The order of wl_pointer.axis_value120 and wl_pointer.axis_source is -// not guaranteed. -type PointerAxisValue120Event struct { - Axis uint32 - Value120 int32 -} -type PointerAxisValue120HandlerFunc func(PointerAxisValue120Event) - -// SetAxisValue120Handler : sets handler for PointerAxisValue120Event -func (i *Pointer) SetAxisValue120Handler(f PointerAxisValue120HandlerFunc) { - i.axisValue120Handler = f -} - -// PointerAxisRelativeDirectionEvent : axis relative physical direction event -// -// Relative directional information of the entity causing the axis -// motion. -// -// For a wl_pointer.axis event, the wl_pointer.axis_relative_direction -// event specifies the movement direction of the entity causing the -// wl_pointer.axis event. For example: -// - if a user's fingers on a touchpad move down and this -// causes a wl_pointer.axis vertical_scroll down event, the physical -// direction is 'identical' -// - if a user's fingers on a touchpad move down and this causes a -// wl_pointer.axis vertical_scroll up scroll up event ('natural -// scrolling'), the physical direction is 'inverted'. -// -// A client may use this information to adjust scroll motion of -// components. Specifically, enabling natural scrolling causes the -// content to change direction compared to traditional scrolling. -// Some widgets like volume control sliders should usually match the -// physical direction regardless of whether natural scrolling is -// active. This event enables clients to match the scroll direction of -// a widget to the physical direction. -// -// This event does not occur on its own, it is coupled with a -// wl_pointer.axis event that represents this axis value. -// The protocol guarantees that each axis_relative_direction event is -// always followed by exactly one axis event with the same -// axis number within the same wl_pointer.frame. Note that the protocol -// allows for other events to occur between the axis_relative_direction -// and its coupled axis event. -// -// The axis number is identical to the axis number in the associated -// axis event. -// -// The order of wl_pointer.axis_relative_direction, -// wl_pointer.axis_discrete and wl_pointer.axis_source is not -// guaranteed. -type PointerAxisRelativeDirectionEvent struct { - Axis uint32 - Direction uint32 -} -type PointerAxisRelativeDirectionHandlerFunc func(PointerAxisRelativeDirectionEvent) - -// SetAxisRelativeDirectionHandler : sets handler for PointerAxisRelativeDirectionEvent -func (i *Pointer) SetAxisRelativeDirectionHandler(f PointerAxisRelativeDirectionHandlerFunc) { - i.axisRelativeDirectionHandler = f -} - -func (i *Pointer) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.enterHandler == nil { - return - } - var e PointerEnterEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - e.SurfaceX = Fixed(data[l : l+4]) - l += 4 - e.SurfaceY = Fixed(data[l : l+4]) - l += 4 - - i.enterHandler(e) - case 1: - if i.leaveHandler == nil { - return - } - var e PointerLeaveEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - - i.leaveHandler(e) - case 2: - if i.motionHandler == nil { - return - } - var e PointerMotionEvent - l := 0 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.SurfaceX = Fixed(data[l : l+4]) - l += 4 - e.SurfaceY = Fixed(data[l : l+4]) - l += 4 - - i.motionHandler(e) - case 3: - if i.buttonHandler == nil { - return - } - var e PointerButtonEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Button = Uint32(data[l : l+4]) - l += 4 - e.State = Uint32(data[l : l+4]) - l += 4 - - i.buttonHandler(e) - case 4: - if i.axisHandler == nil { - return - } - var e PointerAxisEvent - l := 0 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Axis = Uint32(data[l : l+4]) - l += 4 - e.Value = Fixed(data[l : l+4]) - l += 4 - - i.axisHandler(e) - case 5: - if i.frameHandler == nil { - return - } - var e PointerFrameEvent - - i.frameHandler(e) - case 6: - if i.axisSourceHandler == nil { - return - } - var e PointerAxisSourceEvent - l := 0 - e.AxisSource = Uint32(data[l : l+4]) - l += 4 - - i.axisSourceHandler(e) - case 7: - if i.axisStopHandler == nil { - return - } - var e PointerAxisStopEvent - l := 0 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Axis = Uint32(data[l : l+4]) - l += 4 - - i.axisStopHandler(e) - case 8: - if i.axisDiscreteHandler == nil { - return - } - var e PointerAxisDiscreteEvent - l := 0 - e.Axis = Uint32(data[l : l+4]) - l += 4 - e.Discrete = int32(Uint32(data[l : l+4])) - l += 4 - - i.axisDiscreteHandler(e) - case 9: - if i.axisValue120Handler == nil { - return - } - var e PointerAxisValue120Event - l := 0 - e.Axis = Uint32(data[l : l+4]) - l += 4 - e.Value120 = int32(Uint32(data[l : l+4])) - l += 4 - - i.axisValue120Handler(e) - case 10: - if i.axisRelativeDirectionHandler == nil { - return - } - var e PointerAxisRelativeDirectionEvent - l := 0 - e.Axis = Uint32(data[l : l+4]) - l += 4 - e.Direction = Uint32(data[l : l+4]) - l += 4 - - i.axisRelativeDirectionHandler(e) - } -} - -// KeyboardInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const KeyboardInterfaceName = "wl_keyboard" - -// Keyboard : keyboard input device -// -// The wl_keyboard interface represents one or more keyboards -// associated with a seat. -// -// Each wl_keyboard has the following logical state: -// -// - an active surface (possibly null), -// - the keys currently logically down, -// - the active modifiers, -// - the active group. -// -// By default, the active surface is null, the keys currently logically down -// are empty, the active modifiers and the active group are 0. -type Keyboard struct { - BaseProxy - keymapHandler KeyboardKeymapHandlerFunc - enterHandler KeyboardEnterHandlerFunc - leaveHandler KeyboardLeaveHandlerFunc - keyHandler KeyboardKeyHandlerFunc - modifiersHandler KeyboardModifiersHandlerFunc - repeatInfoHandler KeyboardRepeatInfoHandlerFunc -} - -// NewKeyboard : keyboard input device -// -// The wl_keyboard interface represents one or more keyboards -// associated with a seat. -// -// Each wl_keyboard has the following logical state: -// -// - an active surface (possibly null), -// - the keys currently logically down, -// - the active modifiers, -// - the active group. -// -// By default, the active surface is null, the keys currently logically down -// are empty, the active modifiers and the active group are 0. -func NewKeyboard(ctx *Context) *Keyboard { - wlKeyboard := &Keyboard{} - ctx.Register(wlKeyboard) - return wlKeyboard -} - -// Release : release the keyboard object -func (i *Keyboard) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type KeyboardKeymapFormat uint32 - -// KeyboardKeymapFormat : keyboard mapping format -// -// This specifies the format of the keymap provided to the -// client with the wl_keyboard.keymap event. -const ( - // KeyboardKeymapFormatNoKeymap : no keymap; client must understand how to interpret the raw keycode - KeyboardKeymapFormatNoKeymap KeyboardKeymapFormat = 0 - // KeyboardKeymapFormatXkbV1 : libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode - KeyboardKeymapFormatXkbV1 KeyboardKeymapFormat = 1 -) - -func (e KeyboardKeymapFormat) Name() string { - switch e { - case KeyboardKeymapFormatNoKeymap: - return "no_keymap" - case KeyboardKeymapFormatXkbV1: - return "xkb_v1" - default: - return "" - } -} - -func (e KeyboardKeymapFormat) Value() string { - switch e { - case KeyboardKeymapFormatNoKeymap: - return "0" - case KeyboardKeymapFormatXkbV1: - return "1" - default: - return "" - } -} - -func (e KeyboardKeymapFormat) String() string { - return e.Name() + "=" + e.Value() -} - -type KeyboardKeyState uint32 - -// KeyboardKeyState : physical key state -// -// Describes the physical state of a key that produced the key event. -// -// Since version 10, the key can be in a "repeated" pseudo-state which -// means the same as "pressed", but is used to signal repetition in the -// key event. -// -// The key may only enter the repeated state after entering the pressed -// state and before entering the released state. This event may be -// generated multiple times while the key is down. -const ( - // KeyboardKeyStateReleased : key is not pressed - KeyboardKeyStateReleased KeyboardKeyState = 0 - // KeyboardKeyStatePressed : key is pressed - KeyboardKeyStatePressed KeyboardKeyState = 1 - // KeyboardKeyStateRepeated : key was repeated - KeyboardKeyStateRepeated KeyboardKeyState = 2 -) - -func (e KeyboardKeyState) Name() string { - switch e { - case KeyboardKeyStateReleased: - return "released" - case KeyboardKeyStatePressed: - return "pressed" - case KeyboardKeyStateRepeated: - return "repeated" - default: - return "" - } -} - -func (e KeyboardKeyState) Value() string { - switch e { - case KeyboardKeyStateReleased: - return "0" - case KeyboardKeyStatePressed: - return "1" - case KeyboardKeyStateRepeated: - return "2" - default: - return "" - } -} - -func (e KeyboardKeyState) String() string { - return e.Name() + "=" + e.Value() -} - -// KeyboardKeymapEvent : keyboard mapping -// -// This event provides a file descriptor to the client which can be -// memory-mapped in read-only mode to provide a keyboard mapping -// description. -// -// From version 7 onwards, the fd must be mapped with MAP_PRIVATE by -// the recipient, as MAP_SHARED may fail. -type KeyboardKeymapEvent struct { - Format uint32 - Fd int - Size uint32 -} -type KeyboardKeymapHandlerFunc func(KeyboardKeymapEvent) - -// SetKeymapHandler : sets handler for KeyboardKeymapEvent -func (i *Keyboard) SetKeymapHandler(f KeyboardKeymapHandlerFunc) { - i.keymapHandler = f -} - -// KeyboardEnterEvent : enter event -// -// Notification that this seat's keyboard focus is on a certain -// surface. -// -// The compositor must send the wl_keyboard.modifiers event after this -// event. -// -// In the wl_keyboard logical state, this event sets the active surface to -// the surface argument and the keys currently logically down to the keys -// in the keys argument. The compositor must not send this event if the -// wl_keyboard already had an active surface immediately before this event. -// -// Clients should not use the list of pressed keys to emulate key-press -// events. The order of keys in the list is unspecified. -type KeyboardEnterEvent struct { - Serial uint32 - Surface *Surface - Keys []byte -} -type KeyboardEnterHandlerFunc func(KeyboardEnterEvent) - -// SetEnterHandler : sets handler for KeyboardEnterEvent -func (i *Keyboard) SetEnterHandler(f KeyboardEnterHandlerFunc) { - i.enterHandler = f -} - -// KeyboardLeaveEvent : leave event -// -// Notification that this seat's keyboard focus is no longer on -// a certain surface. -// -// The leave notification is sent before the enter notification -// for the new focus. -// -// In the wl_keyboard logical state, this event resets all values to their -// defaults. The compositor must not send this event if the active surface -// of the wl_keyboard was not equal to the surface argument immediately -// before this event. -type KeyboardLeaveEvent struct { - Serial uint32 - Surface *Surface -} -type KeyboardLeaveHandlerFunc func(KeyboardLeaveEvent) - -// SetLeaveHandler : sets handler for KeyboardLeaveEvent -func (i *Keyboard) SetLeaveHandler(f KeyboardLeaveHandlerFunc) { - i.leaveHandler = f -} - -// KeyboardKeyEvent : key event -// -// A key was pressed or released. -// The time argument is a timestamp with millisecond -// granularity, with an undefined base. -// -// The key is a platform-specific key code that can be interpreted -// by feeding it to the keyboard mapping (see the keymap event). -// -// If this event produces a change in modifiers, then the resulting -// wl_keyboard.modifiers event must be sent after this event. -// -// In the wl_keyboard logical state, this event adds the key to the keys -// currently logically down (if the state argument is pressed) or removes -// the key from the keys currently logically down (if the state argument is -// released). The compositor must not send this event if the wl_keyboard -// did not have an active surface immediately before this event. The -// compositor must not send this event if state is pressed (resp. released) -// and the key was already logically down (resp. was not logically down) -// immediately before this event. -// -// Since version 10, compositors may send key events with the "repeated" -// key state when a wl_keyboard.repeat_info event with a rate argument of -// 0 has been received. This allows the compositor to take over the -// responsibility of key repetition. -type KeyboardKeyEvent struct { - Serial uint32 - Time uint32 - Key uint32 - State uint32 -} -type KeyboardKeyHandlerFunc func(KeyboardKeyEvent) - -// SetKeyHandler : sets handler for KeyboardKeyEvent -func (i *Keyboard) SetKeyHandler(f KeyboardKeyHandlerFunc) { - i.keyHandler = f -} - -// KeyboardModifiersEvent : modifier and group state -// -// Notifies clients that the modifier and/or group state has -// changed, and it should update its local state. -// -// The compositor may send this event without a surface of the client -// having keyboard focus, for example to tie modifier information to -// pointer focus instead. If a modifier event with pressed modifiers is sent -// without a prior enter event, the client can assume the modifier state is -// valid until it receives the next wl_keyboard.modifiers event. In order to -// reset the modifier state again, the compositor can send a -// wl_keyboard.modifiers event with no pressed modifiers. -// -// In the wl_keyboard logical state, this event updates the modifiers and -// group. -type KeyboardModifiersEvent struct { - Serial uint32 - ModsDepressed uint32 - ModsLatched uint32 - ModsLocked uint32 - Group uint32 -} -type KeyboardModifiersHandlerFunc func(KeyboardModifiersEvent) - -// SetModifiersHandler : sets handler for KeyboardModifiersEvent -func (i *Keyboard) SetModifiersHandler(f KeyboardModifiersHandlerFunc) { - i.modifiersHandler = f -} - -// KeyboardRepeatInfoEvent : repeat rate and delay -// -// Informs the client about the keyboard's repeat rate and delay. -// -// This event is sent as soon as the wl_keyboard object has been created, -// and is guaranteed to be received by the client before any key press -// event. -// -// Negative values for either rate or delay are illegal. A rate of zero -// will disable any repeating (regardless of the value of delay). -// -// This event can be sent later on as well with a new value if necessary, -// so clients should continue listening for the event past the creation -// of wl_keyboard. -type KeyboardRepeatInfoEvent struct { - Rate int32 - Delay int32 -} -type KeyboardRepeatInfoHandlerFunc func(KeyboardRepeatInfoEvent) - -// SetRepeatInfoHandler : sets handler for KeyboardRepeatInfoEvent -func (i *Keyboard) SetRepeatInfoHandler(f KeyboardRepeatInfoHandlerFunc) { - i.repeatInfoHandler = f -} - -func (i *Keyboard) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.keymapHandler == nil { - if fd != -1 { - unix.Close(fd) - } - return - } - var e KeyboardKeymapEvent - l := 0 - e.Format = Uint32(data[l : l+4]) - l += 4 - e.Fd = fd - e.Size = Uint32(data[l : l+4]) - l += 4 - - i.keymapHandler(e) - case 1: - if i.enterHandler == nil { - return - } - var e KeyboardEnterEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - keysLen := int(Uint32(data[l : l+4])) - l += 4 - e.Keys = make([]byte, keysLen) - copy(e.Keys, data[l:l+keysLen]) - l += keysLen - - i.enterHandler(e) - case 2: - if i.leaveHandler == nil { - return - } - var e KeyboardLeaveEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - - i.leaveHandler(e) - case 3: - if i.keyHandler == nil { - return - } - var e KeyboardKeyEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Key = Uint32(data[l : l+4]) - l += 4 - e.State = Uint32(data[l : l+4]) - l += 4 - - i.keyHandler(e) - case 4: - if i.modifiersHandler == nil { - return - } - var e KeyboardModifiersEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.ModsDepressed = Uint32(data[l : l+4]) - l += 4 - e.ModsLatched = Uint32(data[l : l+4]) - l += 4 - e.ModsLocked = Uint32(data[l : l+4]) - l += 4 - e.Group = Uint32(data[l : l+4]) - l += 4 - - i.modifiersHandler(e) - case 5: - if i.repeatInfoHandler == nil { - return - } - var e KeyboardRepeatInfoEvent - l := 0 - e.Rate = int32(Uint32(data[l : l+4])) - l += 4 - e.Delay = int32(Uint32(data[l : l+4])) - l += 4 - - i.repeatInfoHandler(e) - } -} - -// TouchInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const TouchInterfaceName = "wl_touch" - -// Touch : touchscreen input device -// -// The wl_touch interface represents a touchscreen -// associated with a seat. -// -// Touch interactions can consist of one or more contacts. -// For each contact, a series of events is generated, starting -// with a down event, followed by zero or more motion events, -// and ending with an up event. Events relating to the same -// contact point can be identified by the ID of the sequence. -type Touch struct { - BaseProxy - downHandler TouchDownHandlerFunc - upHandler TouchUpHandlerFunc - motionHandler TouchMotionHandlerFunc - frameHandler TouchFrameHandlerFunc - cancelHandler TouchCancelHandlerFunc - shapeHandler TouchShapeHandlerFunc - orientationHandler TouchOrientationHandlerFunc -} - -// NewTouch : touchscreen input device -// -// The wl_touch interface represents a touchscreen -// associated with a seat. -// -// Touch interactions can consist of one or more contacts. -// For each contact, a series of events is generated, starting -// with a down event, followed by zero or more motion events, -// and ending with an up event. Events relating to the same -// contact point can be identified by the ID of the sequence. -func NewTouch(ctx *Context) *Touch { - wlTouch := &Touch{} - ctx.Register(wlTouch) - return wlTouch -} - -// Release : release the touch object -func (i *Touch) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// TouchDownEvent : touch down event and beginning of a touch sequence -// -// A new touch point has appeared on the surface. This touch point is -// assigned a unique ID. Future events from this touch point reference -// this ID. The ID ceases to be valid after a touch up event and may be -// reused in the future. -type TouchDownEvent struct { - Serial uint32 - Time uint32 - Surface *Surface - Id int32 - X float64 - Y float64 -} -type TouchDownHandlerFunc func(TouchDownEvent) - -// SetDownHandler : sets handler for TouchDownEvent -func (i *Touch) SetDownHandler(f TouchDownHandlerFunc) { - i.downHandler = f -} - -// TouchUpEvent : end of a touch event sequence -// -// The touch point has disappeared. No further events will be sent for -// this touch point and the touch point's ID is released and may be -// reused in a future touch down event. -type TouchUpEvent struct { - Serial uint32 - Time uint32 - Id int32 -} -type TouchUpHandlerFunc func(TouchUpEvent) - -// SetUpHandler : sets handler for TouchUpEvent -func (i *Touch) SetUpHandler(f TouchUpHandlerFunc) { - i.upHandler = f -} - -// TouchMotionEvent : update of touch point coordinates -// -// A touch point has changed coordinates. -type TouchMotionEvent struct { - Time uint32 - Id int32 - X float64 - Y float64 -} -type TouchMotionHandlerFunc func(TouchMotionEvent) - -// SetMotionHandler : sets handler for TouchMotionEvent -func (i *Touch) SetMotionHandler(f TouchMotionHandlerFunc) { - i.motionHandler = f -} - -// TouchFrameEvent : end of touch frame event -// -// Indicates the end of a set of events that logically belong together. -// A client is expected to accumulate the data in all events within the -// frame before proceeding. -// -// A wl_touch.frame terminates at least one event but otherwise no -// guarantee is provided about the set of events within a frame. A client -// must assume that any state not updated in a frame is unchanged from the -// previously known state. -type TouchFrameEvent struct{} -type TouchFrameHandlerFunc func(TouchFrameEvent) - -// SetFrameHandler : sets handler for TouchFrameEvent -func (i *Touch) SetFrameHandler(f TouchFrameHandlerFunc) { - i.frameHandler = f -} - -// TouchCancelEvent : touch session cancelled -// -// Sent if the compositor decides the touch stream is a global -// gesture. No further events are sent to the clients from that -// particular gesture. Touch cancellation applies to all touch points -// currently active on this client's surface. The client is -// responsible for finalizing the touch points, future touch points on -// this surface may reuse the touch point ID. -// -// No frame event is required after the cancel event. -type TouchCancelEvent struct{} -type TouchCancelHandlerFunc func(TouchCancelEvent) - -// SetCancelHandler : sets handler for TouchCancelEvent -func (i *Touch) SetCancelHandler(f TouchCancelHandlerFunc) { - i.cancelHandler = f -} - -// TouchShapeEvent : update shape of touch point -// -// Sent when a touchpoint has changed its shape. -// -// This event does not occur on its own. It is sent before a -// wl_touch.frame event and carries the new shape information for -// any previously reported, or new touch points of that frame. -// -// Other events describing the touch point such as wl_touch.down, -// wl_touch.motion or wl_touch.orientation may be sent within the -// same wl_touch.frame. A client should treat these events as a single -// logical touch point update. The order of wl_touch.shape, -// wl_touch.orientation and wl_touch.motion is not guaranteed. -// A wl_touch.down event is guaranteed to occur before the first -// wl_touch.shape event for this touch ID but both events may occur within -// the same wl_touch.frame. -// -// A touchpoint shape is approximated by an ellipse through the major and -// minor axis length. The major axis length describes the longer diameter -// of the ellipse, while the minor axis length describes the shorter -// diameter. Major and minor are orthogonal and both are specified in -// surface-local coordinates. The center of the ellipse is always at the -// touchpoint location as reported by wl_touch.down or wl_touch.move. -// -// This event is only sent by the compositor if the touch device supports -// shape reports. The client has to make reasonable assumptions about the -// shape if it did not receive this event. -type TouchShapeEvent struct { - Id int32 - Major float64 - Minor float64 -} -type TouchShapeHandlerFunc func(TouchShapeEvent) - -// SetShapeHandler : sets handler for TouchShapeEvent -func (i *Touch) SetShapeHandler(f TouchShapeHandlerFunc) { - i.shapeHandler = f -} - -// TouchOrientationEvent : update orientation of touch point -// -// Sent when a touchpoint has changed its orientation. -// -// This event does not occur on its own. It is sent before a -// wl_touch.frame event and carries the new shape information for -// any previously reported, or new touch points of that frame. -// -// Other events describing the touch point such as wl_touch.down, -// wl_touch.motion or wl_touch.shape may be sent within the -// same wl_touch.frame. A client should treat these events as a single -// logical touch point update. The order of wl_touch.shape, -// wl_touch.orientation and wl_touch.motion is not guaranteed. -// A wl_touch.down event is guaranteed to occur before the first -// wl_touch.orientation event for this touch ID but both events may occur -// within the same wl_touch.frame. -// -// The orientation describes the clockwise angle of a touchpoint's major -// axis to the positive surface y-axis and is normalized to the -180 to -// +180 degree range. The granularity of orientation depends on the touch -// device, some devices only support binary rotation values between 0 and -// 90 degrees. -// -// This event is only sent by the compositor if the touch device supports -// orientation reports. -type TouchOrientationEvent struct { - Id int32 - Orientation float64 -} -type TouchOrientationHandlerFunc func(TouchOrientationEvent) - -// SetOrientationHandler : sets handler for TouchOrientationEvent -func (i *Touch) SetOrientationHandler(f TouchOrientationHandlerFunc) { - i.orientationHandler = f -} - -func (i *Touch) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.downHandler == nil { - return - } - var e TouchDownEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Surface = i.Context().GetProxy(Uint32(data[l : l+4])).(*Surface) - l += 4 - e.Id = int32(Uint32(data[l : l+4])) - l += 4 - e.X = Fixed(data[l : l+4]) - l += 4 - e.Y = Fixed(data[l : l+4]) - l += 4 - - i.downHandler(e) - case 1: - if i.upHandler == nil { - return - } - var e TouchUpEvent - l := 0 - e.Serial = Uint32(data[l : l+4]) - l += 4 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Id = int32(Uint32(data[l : l+4])) - l += 4 - - i.upHandler(e) - case 2: - if i.motionHandler == nil { - return - } - var e TouchMotionEvent - l := 0 - e.Time = Uint32(data[l : l+4]) - l += 4 - e.Id = int32(Uint32(data[l : l+4])) - l += 4 - e.X = Fixed(data[l : l+4]) - l += 4 - e.Y = Fixed(data[l : l+4]) - l += 4 - - i.motionHandler(e) - case 3: - if i.frameHandler == nil { - return - } - var e TouchFrameEvent - - i.frameHandler(e) - case 4: - if i.cancelHandler == nil { - return - } - var e TouchCancelEvent - - i.cancelHandler(e) - case 5: - if i.shapeHandler == nil { - return - } - var e TouchShapeEvent - l := 0 - e.Id = int32(Uint32(data[l : l+4])) - l += 4 - e.Major = Fixed(data[l : l+4]) - l += 4 - e.Minor = Fixed(data[l : l+4]) - l += 4 - - i.shapeHandler(e) - case 6: - if i.orientationHandler == nil { - return - } - var e TouchOrientationEvent - l := 0 - e.Id = int32(Uint32(data[l : l+4])) - l += 4 - e.Orientation = Fixed(data[l : l+4]) - l += 4 - - i.orientationHandler(e) - } -} - -// OutputInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const OutputInterfaceName = "wl_output" - -// Output : compositor output region -// -// An output describes part of the compositor geometry. The -// compositor works in the 'compositor coordinate system' and an -// output corresponds to a rectangular area in that space that is -// actually visible. This typically corresponds to a monitor that -// displays part of the compositor space. This object is published -// as global during start up, or when a monitor is hotplugged. -type Output struct { - BaseProxy - geometryHandler OutputGeometryHandlerFunc - modeHandler OutputModeHandlerFunc - doneHandler OutputDoneHandlerFunc - scaleHandler OutputScaleHandlerFunc - nameHandler OutputNameHandlerFunc - descriptionHandler OutputDescriptionHandlerFunc -} - -// NewOutput : compositor output region -// -// An output describes part of the compositor geometry. The -// compositor works in the 'compositor coordinate system' and an -// output corresponds to a rectangular area in that space that is -// actually visible. This typically corresponds to a monitor that -// displays part of the compositor space. This object is published -// as global during start up, or when a monitor is hotplugged. -func NewOutput(ctx *Context) *Output { - wlOutput := &Output{} - ctx.Register(wlOutput) - return wlOutput -} - -// Release : release the output object -// -// Using this request a client can tell the server that it is not going to -// use the output object anymore. -func (i *Output) Release() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type OutputSubpixel uint32 - -// OutputSubpixel : subpixel geometry information -// -// This enumeration describes how the physical -// pixels on an output are laid out. -const ( - // OutputSubpixelUnknown : unknown geometry - OutputSubpixelUnknown OutputSubpixel = 0 - // OutputSubpixelNone : no geometry - OutputSubpixelNone OutputSubpixel = 1 - // OutputSubpixelHorizontalRgb : horizontal RGB - OutputSubpixelHorizontalRgb OutputSubpixel = 2 - // OutputSubpixelHorizontalBgr : horizontal BGR - OutputSubpixelHorizontalBgr OutputSubpixel = 3 - // OutputSubpixelVerticalRgb : vertical RGB - OutputSubpixelVerticalRgb OutputSubpixel = 4 - // OutputSubpixelVerticalBgr : vertical BGR - OutputSubpixelVerticalBgr OutputSubpixel = 5 -) - -func (e OutputSubpixel) Name() string { - switch e { - case OutputSubpixelUnknown: - return "unknown" - case OutputSubpixelNone: - return "none" - case OutputSubpixelHorizontalRgb: - return "horizontal_rgb" - case OutputSubpixelHorizontalBgr: - return "horizontal_bgr" - case OutputSubpixelVerticalRgb: - return "vertical_rgb" - case OutputSubpixelVerticalBgr: - return "vertical_bgr" - default: - return "" - } -} - -func (e OutputSubpixel) Value() string { - switch e { - case OutputSubpixelUnknown: - return "0" - case OutputSubpixelNone: - return "1" - case OutputSubpixelHorizontalRgb: - return "2" - case OutputSubpixelHorizontalBgr: - return "3" - case OutputSubpixelVerticalRgb: - return "4" - case OutputSubpixelVerticalBgr: - return "5" - default: - return "" - } -} - -func (e OutputSubpixel) String() string { - return e.Name() + "=" + e.Value() -} - -type OutputTransform uint32 - -// OutputTransform : transformation applied to buffer contents -// -// This describes transformations that clients and compositors apply to -// buffer contents. -// -// The flipped values correspond to an initial flip around a -// vertical axis followed by rotation. -// -// The purpose is mainly to allow clients to render accordingly and -// tell the compositor, so that for fullscreen surfaces, the -// compositor will still be able to scan out directly from client -// surfaces. -const ( - // OutputTransformNormal : no transform - OutputTransformNormal OutputTransform = 0 - // OutputTransform90 : 90 degrees counter-clockwise - OutputTransform90 OutputTransform = 1 - // OutputTransform180 : 180 degrees counter-clockwise - OutputTransform180 OutputTransform = 2 - // OutputTransform270 : 270 degrees counter-clockwise - OutputTransform270 OutputTransform = 3 - // OutputTransformFlipped : 180 degree flip around a vertical axis - OutputTransformFlipped OutputTransform = 4 - // OutputTransformFlipped90 : flip and rotate 90 degrees counter-clockwise - OutputTransformFlipped90 OutputTransform = 5 - // OutputTransformFlipped180 : flip and rotate 180 degrees counter-clockwise - OutputTransformFlipped180 OutputTransform = 6 - // OutputTransformFlipped270 : flip and rotate 270 degrees counter-clockwise - OutputTransformFlipped270 OutputTransform = 7 -) - -func (e OutputTransform) Name() string { - switch e { - case OutputTransformNormal: - return "normal" - case OutputTransform90: - return "90" - case OutputTransform180: - return "180" - case OutputTransform270: - return "270" - case OutputTransformFlipped: - return "flipped" - case OutputTransformFlipped90: - return "flipped_90" - case OutputTransformFlipped180: - return "flipped_180" - case OutputTransformFlipped270: - return "flipped_270" - default: - return "" - } -} - -func (e OutputTransform) Value() string { - switch e { - case OutputTransformNormal: - return "0" - case OutputTransform90: - return "1" - case OutputTransform180: - return "2" - case OutputTransform270: - return "3" - case OutputTransformFlipped: - return "4" - case OutputTransformFlipped90: - return "5" - case OutputTransformFlipped180: - return "6" - case OutputTransformFlipped270: - return "7" - default: - return "" - } -} - -func (e OutputTransform) String() string { - return e.Name() + "=" + e.Value() -} - -type OutputMode uint32 - -// OutputMode : mode information -// -// These flags describe properties of an output mode. -// They are used in the flags bitfield of the mode event. -const ( - // OutputModeCurrent : indicates this is the current mode - OutputModeCurrent OutputMode = 0x1 - // OutputModePreferred : indicates this is the preferred mode - OutputModePreferred OutputMode = 0x2 -) - -func (e OutputMode) Name() string { - switch e { - case OutputModeCurrent: - return "current" - case OutputModePreferred: - return "preferred" - default: - return "" - } -} - -func (e OutputMode) Value() string { - switch e { - case OutputModeCurrent: - return "0x1" - case OutputModePreferred: - return "0x2" - default: - return "" - } -} - -func (e OutputMode) String() string { - return e.Name() + "=" + e.Value() -} - -// OutputGeometryEvent : properties of the output -// -// The geometry event describes geometric properties of the output. -// The event is sent when binding to the output object and whenever -// any of the properties change. -// -// The physical size can be set to zero if it doesn't make sense for this -// output (e.g. for projectors or virtual outputs). -// -// The geometry event will be followed by a done event (starting from -// version 2). -// -// Clients should use wl_surface.preferred_buffer_transform instead of the -// transform advertised by this event to find the preferred buffer -// transform to use for a surface. -// -// Note: wl_output only advertises partial information about the output -// position and identification. Some compositors, for instance those not -// implementing a desktop-style output layout or those exposing virtual -// outputs, might fake this information. Instead of using x and y, clients -// should use xdg_output.logical_position. Instead of using make and model, -// clients should use name and description. -type OutputGeometryEvent struct { - X int32 - Y int32 - PhysicalWidth int32 - PhysicalHeight int32 - Subpixel int32 - Make string - Model string - Transform int32 -} -type OutputGeometryHandlerFunc func(OutputGeometryEvent) - -// SetGeometryHandler : sets handler for OutputGeometryEvent -func (i *Output) SetGeometryHandler(f OutputGeometryHandlerFunc) { - i.geometryHandler = f -} - -// OutputModeEvent : advertise available modes for the output -// -// The mode event describes an available mode for the output. -// -// The event is sent when binding to the output object and there -// will always be one mode, the current mode. The event is sent -// again if an output changes mode, for the mode that is now -// current. In other words, the current mode is always the last -// mode that was received with the current flag set. -// -// Non-current modes are deprecated. A compositor can decide to only -// advertise the current mode and never send other modes. Clients -// should not rely on non-current modes. -// -// The size of a mode is given in physical hardware units of -// the output device. This is not necessarily the same as -// the output size in the global compositor space. For instance, -// the output may be scaled, as described in wl_output.scale, -// or transformed, as described in wl_output.transform. Clients -// willing to retrieve the output size in the global compositor -// space should use xdg_output.logical_size instead. -// -// The vertical refresh rate can be set to zero if it doesn't make -// sense for this output (e.g. for virtual outputs). -// -// The mode event will be followed by a done event (starting from -// version 2). -// -// Clients should not use the refresh rate to schedule frames. Instead, -// they should use the wl_surface.frame event or the presentation-time -// protocol. -// -// Note: this information is not always meaningful for all outputs. Some -// compositors, such as those exposing virtual outputs, might fake the -// refresh rate or the size. -type OutputModeEvent struct { - Flags uint32 - Width int32 - Height int32 - Refresh int32 -} -type OutputModeHandlerFunc func(OutputModeEvent) - -// SetModeHandler : sets handler for OutputModeEvent -func (i *Output) SetModeHandler(f OutputModeHandlerFunc) { - i.modeHandler = f -} - -// OutputDoneEvent : sent all information about output -// -// This event is sent after all other properties have been -// sent after binding to the output object and after any -// other property changes done after that. This allows -// changes to the output properties to be seen as -// atomic, even if they happen via multiple events. -type OutputDoneEvent struct{} -type OutputDoneHandlerFunc func(OutputDoneEvent) - -// SetDoneHandler : sets handler for OutputDoneEvent -func (i *Output) SetDoneHandler(f OutputDoneHandlerFunc) { - i.doneHandler = f -} - -// OutputScaleEvent : output scaling properties -// -// This event contains scaling geometry information -// that is not in the geometry event. It may be sent after -// binding the output object or if the output scale changes -// later. The compositor will emit a non-zero, positive -// value for scale. If it is not sent, the client should -// assume a scale of 1. -// -// A scale larger than 1 means that the compositor will -// automatically scale surface buffers by this amount -// when rendering. This is used for very high resolution -// displays where applications rendering at the native -// resolution would be too small to be legible. -// -// Clients should use wl_surface.preferred_buffer_scale -// instead of this event to find the preferred buffer -// scale to use for a surface. -// -// The scale event will be followed by a done event. -type OutputScaleEvent struct { - Factor int32 -} -type OutputScaleHandlerFunc func(OutputScaleEvent) - -// SetScaleHandler : sets handler for OutputScaleEvent -func (i *Output) SetScaleHandler(f OutputScaleHandlerFunc) { - i.scaleHandler = f -} - -// OutputNameEvent : name of this output -// -// Many compositors will assign user-friendly names to their outputs, show -// them to the user, allow the user to refer to an output, etc. The client -// may wish to know this name as well to offer the user similar behaviors. -// -// The name is a UTF-8 string with no convention defined for its contents. -// Each name is unique among all wl_output globals. The name is only -// guaranteed to be unique for the compositor instance. -// -// The same output name is used for all clients for a given wl_output -// global. Thus, the name can be shared across processes to refer to a -// specific wl_output global. -// -// The name is not guaranteed to be persistent across sessions, thus cannot -// be used to reliably identify an output in e.g. configuration files. -// -// Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do -// not assume that the name is a reflection of an underlying DRM connector, -// X11 connection, etc. -// -// The name event is sent after binding the output object. This event is -// only sent once per output object, and the name does not change over the -// lifetime of the wl_output global. -// -// Compositors may re-use the same output name if the wl_output global is -// destroyed and re-created later. Compositors should avoid re-using the -// same name if possible. -// -// The name event will be followed by a done event. -type OutputNameEvent struct { - Name string -} -type OutputNameHandlerFunc func(OutputNameEvent) - -// SetNameHandler : sets handler for OutputNameEvent -func (i *Output) SetNameHandler(f OutputNameHandlerFunc) { - i.nameHandler = f -} - -// OutputDescriptionEvent : human-readable description of this output -// -// Many compositors can produce human-readable descriptions of their -// outputs. The client may wish to know this description as well, e.g. for -// output selection purposes. -// -// The description is a UTF-8 string with no convention defined for its -// contents. The description is not guaranteed to be unique among all -// wl_output globals. Examples might include 'Foocorp 11" Display' or -// 'Virtual X11 output via :1'. -// -// The description event is sent after binding the output object and -// whenever the description changes. The description is optional, and may -// not be sent at all. -// -// The description event will be followed by a done event. -type OutputDescriptionEvent struct { - Description string -} -type OutputDescriptionHandlerFunc func(OutputDescriptionEvent) - -// SetDescriptionHandler : sets handler for OutputDescriptionEvent -func (i *Output) SetDescriptionHandler(f OutputDescriptionHandlerFunc) { - i.descriptionHandler = f -} - -func (i *Output) Dispatch(opcode uint32, fd int, data []byte) { - switch opcode { - case 0: - if i.geometryHandler == nil { - return - } - var e OutputGeometryEvent - l := 0 - e.X = int32(Uint32(data[l : l+4])) - l += 4 - e.Y = int32(Uint32(data[l : l+4])) - l += 4 - e.PhysicalWidth = int32(Uint32(data[l : l+4])) - l += 4 - e.PhysicalHeight = int32(Uint32(data[l : l+4])) - l += 4 - e.Subpixel = int32(Uint32(data[l : l+4])) - l += 4 - makeLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Make = String(data[l : l+makeLen]) - l += makeLen - modelLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Model = String(data[l : l+modelLen]) - l += modelLen - e.Transform = int32(Uint32(data[l : l+4])) - l += 4 - - i.geometryHandler(e) - case 1: - if i.modeHandler == nil { - return - } - var e OutputModeEvent - l := 0 - e.Flags = Uint32(data[l : l+4]) - l += 4 - e.Width = int32(Uint32(data[l : l+4])) - l += 4 - e.Height = int32(Uint32(data[l : l+4])) - l += 4 - e.Refresh = int32(Uint32(data[l : l+4])) - l += 4 - - i.modeHandler(e) - case 2: - if i.doneHandler == nil { - return - } - var e OutputDoneEvent - - i.doneHandler(e) - case 3: - if i.scaleHandler == nil { - return - } - var e OutputScaleEvent - l := 0 - e.Factor = int32(Uint32(data[l : l+4])) - l += 4 - - i.scaleHandler(e) - case 4: - if i.nameHandler == nil { - return - } - var e OutputNameEvent - l := 0 - nameLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Name = String(data[l : l+nameLen]) - l += nameLen - - i.nameHandler(e) - case 5: - if i.descriptionHandler == nil { - return - } - var e OutputDescriptionEvent - l := 0 - descriptionLen := PaddedLen(int(Uint32(data[l : l+4]))) - l += 4 - e.Description = String(data[l : l+descriptionLen]) - l += descriptionLen - - i.descriptionHandler(e) - } -} - -// RegionInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const RegionInterfaceName = "wl_region" - -// Region : region interface -// -// A region object describes an area. -// -// Region objects are used to describe the opaque and input -// regions of a surface. -type Region struct { - BaseProxy -} - -// NewRegion : region interface -// -// A region object describes an area. -// -// Region objects are used to describe the opaque and input -// regions of a surface. -func NewRegion(ctx *Context) *Region { - wlRegion := &Region{} - ctx.Register(wlRegion) - return wlRegion -} - -// Destroy : destroy region -// -// Destroy the region. This will invalidate the object ID. -func (i *Region) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Add : add rectangle to region -// -// Add the specified rectangle to the region. -// -// x: region-local x coordinate -// y: region-local y coordinate -// width: rectangle width -// height: rectangle height -func (i *Region) Add(x, y, width, height int32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// Subtract : subtract rectangle from region -// -// Subtract the specified rectangle from the region. -// -// x: region-local x coordinate -// y: region-local y coordinate -// width: rectangle width -// height: rectangle height -func (i *Region) Subtract(x, y, width, height int32) error { - const opcode = 2 - const _reqBufLen = 8 + 4 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(width)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(height)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SubcompositorInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const SubcompositorInterfaceName = "wl_subcompositor" - -// Subcompositor : sub-surface compositing -// -// The global interface exposing sub-surface compositing capabilities. -// A wl_surface, that has sub-surfaces associated, is called the -// parent surface. Sub-surfaces can be arbitrarily nested and create -// a tree of sub-surfaces. -// -// The root surface in a tree of sub-surfaces is the main -// surface. The main surface cannot be a sub-surface, because -// sub-surfaces must always have a parent. -// -// A main surface with its sub-surfaces forms a (compound) window. -// For window management purposes, this set of wl_surface objects is -// to be considered as a single window, and it should also behave as -// such. -// -// The aim of sub-surfaces is to offload some of the compositing work -// within a window from clients to the compositor. A prime example is -// a video player with decorations and video in separate wl_surface -// objects. This should allow the compositor to pass YUV video buffer -// processing to dedicated overlay hardware when possible. -type Subcompositor struct { - BaseProxy -} - -// NewSubcompositor : sub-surface compositing -// -// The global interface exposing sub-surface compositing capabilities. -// A wl_surface, that has sub-surfaces associated, is called the -// parent surface. Sub-surfaces can be arbitrarily nested and create -// a tree of sub-surfaces. -// -// The root surface in a tree of sub-surfaces is the main -// surface. The main surface cannot be a sub-surface, because -// sub-surfaces must always have a parent. -// -// A main surface with its sub-surfaces forms a (compound) window. -// For window management purposes, this set of wl_surface objects is -// to be considered as a single window, and it should also behave as -// such. -// -// The aim of sub-surfaces is to offload some of the compositing work -// within a window from clients to the compositor. A prime example is -// a video player with decorations and video in separate wl_surface -// objects. This should allow the compositor to pass YUV video buffer -// processing to dedicated overlay hardware when possible. -func NewSubcompositor(ctx *Context) *Subcompositor { - wlSubcompositor := &Subcompositor{} - ctx.Register(wlSubcompositor) - return wlSubcompositor -} - -// Destroy : unbind from the subcompositor interface -// -// Informs the server that the client will not be using this -// protocol object anymore. This does not affect any other -// objects, wl_subsurface objects included. -func (i *Subcompositor) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// GetSubsurface : give a surface the role sub-surface -// -// Create a sub-surface interface for the given surface, and -// associate it with the given parent surface. This turns a -// plain wl_surface into a sub-surface. -// -// The to-be sub-surface must not already have another role, and it -// must not have an existing wl_subsurface object. Otherwise the -// bad_surface protocol error is raised. -// -// Adding sub-surfaces to a parent is a double-buffered operation on the -// parent (see wl_surface.commit). The effect of adding a sub-surface -// becomes visible on the next time the state of the parent surface is -// applied. -// -// The parent surface must not be one of the child surface's descendants, -// and the parent must be different from the child surface, otherwise the -// bad_parent protocol error is raised. -// -// This request modifies the behaviour of wl_surface.commit request on -// the sub-surface, see the documentation on wl_subsurface interface. -// -// surface: the surface to be turned into a sub-surface -// parent: the parent surface -func (i *Subcompositor) GetSubsurface(surface, parent *Surface) (*Subsurface, error) { - id := NewSubsurface(i.Context()) - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], id.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], surface.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], parent.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return id, err -} - -type SubcompositorError uint32 - -// SubcompositorError : -const ( - // SubcompositorErrorBadSurface : the to-be sub-surface is invalid - SubcompositorErrorBadSurface SubcompositorError = 0 - // SubcompositorErrorBadParent : the to-be sub-surface parent is invalid - SubcompositorErrorBadParent SubcompositorError = 1 -) - -func (e SubcompositorError) Name() string { - switch e { - case SubcompositorErrorBadSurface: - return "bad_surface" - case SubcompositorErrorBadParent: - return "bad_parent" - default: - return "" - } -} - -func (e SubcompositorError) Value() string { - switch e { - case SubcompositorErrorBadSurface: - return "0" - case SubcompositorErrorBadParent: - return "1" - default: - return "" - } -} - -func (e SubcompositorError) String() string { - return e.Name() + "=" + e.Value() -} - -// SubsurfaceInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const SubsurfaceInterfaceName = "wl_subsurface" - -// Subsurface : sub-surface interface to a wl_surface -// -// An additional interface to a wl_surface object, which has been -// made a sub-surface. A sub-surface has one parent surface. A -// sub-surface's size and position are not limited to that of the parent. -// Particularly, a sub-surface is not automatically clipped to its -// parent's area. -// -// A sub-surface becomes mapped, when a non-NULL wl_buffer is applied -// and the parent surface is mapped. The order of which one happens -// first is irrelevant. A sub-surface is hidden if the parent becomes -// hidden, or if a NULL wl_buffer is applied. These rules apply -// recursively through the tree of surfaces. -// -// The behaviour of a wl_surface.commit request on a sub-surface -// depends on the sub-surface's mode. The possible modes are -// synchronized and desynchronized, see methods -// wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized -// mode caches the wl_surface state to be applied when the parent's -// state gets applied, and desynchronized mode applies the pending -// wl_surface state directly. A sub-surface is initially in the -// synchronized mode. -// -// Sub-surfaces also have another kind of state, which is managed by -// wl_subsurface requests, as opposed to wl_surface requests. This -// state includes the sub-surface position relative to the parent -// surface (wl_subsurface.set_position), and the stacking order of -// the parent and its sub-surfaces (wl_subsurface.place_above and -// .place_below). This state is applied when the parent surface's -// wl_surface state is applied, regardless of the sub-surface's mode. -// As the exception, set_sync and set_desync are effective immediately. -// -// The main surface can be thought to be always in desynchronized mode, -// since it does not have a parent in the sub-surfaces sense. -// -// Even if a sub-surface is in desynchronized mode, it will behave as -// in synchronized mode, if its parent surface behaves as in -// synchronized mode. This rule is applied recursively throughout the -// tree of surfaces. This means, that one can set a sub-surface into -// synchronized mode, and then assume that all its child and grand-child -// sub-surfaces are synchronized, too, without explicitly setting them. -// -// Destroying a sub-surface takes effect immediately. If you need to -// synchronize the removal of a sub-surface to the parent surface update, -// unmap the sub-surface first by attaching a NULL wl_buffer, update parent, -// and then destroy the sub-surface. -// -// If the parent wl_surface object is destroyed, the sub-surface is -// unmapped. -// -// A sub-surface never has the keyboard focus of any seat. -// -// The wl_surface.offset request is ignored: clients must use set_position -// instead to move the sub-surface. -type Subsurface struct { - BaseProxy -} - -// NewSubsurface : sub-surface interface to a wl_surface -// -// An additional interface to a wl_surface object, which has been -// made a sub-surface. A sub-surface has one parent surface. A -// sub-surface's size and position are not limited to that of the parent. -// Particularly, a sub-surface is not automatically clipped to its -// parent's area. -// -// A sub-surface becomes mapped, when a non-NULL wl_buffer is applied -// and the parent surface is mapped. The order of which one happens -// first is irrelevant. A sub-surface is hidden if the parent becomes -// hidden, or if a NULL wl_buffer is applied. These rules apply -// recursively through the tree of surfaces. -// -// The behaviour of a wl_surface.commit request on a sub-surface -// depends on the sub-surface's mode. The possible modes are -// synchronized and desynchronized, see methods -// wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized -// mode caches the wl_surface state to be applied when the parent's -// state gets applied, and desynchronized mode applies the pending -// wl_surface state directly. A sub-surface is initially in the -// synchronized mode. -// -// Sub-surfaces also have another kind of state, which is managed by -// wl_subsurface requests, as opposed to wl_surface requests. This -// state includes the sub-surface position relative to the parent -// surface (wl_subsurface.set_position), and the stacking order of -// the parent and its sub-surfaces (wl_subsurface.place_above and -// .place_below). This state is applied when the parent surface's -// wl_surface state is applied, regardless of the sub-surface's mode. -// As the exception, set_sync and set_desync are effective immediately. -// -// The main surface can be thought to be always in desynchronized mode, -// since it does not have a parent in the sub-surfaces sense. -// -// Even if a sub-surface is in desynchronized mode, it will behave as -// in synchronized mode, if its parent surface behaves as in -// synchronized mode. This rule is applied recursively throughout the -// tree of surfaces. This means, that one can set a sub-surface into -// synchronized mode, and then assume that all its child and grand-child -// sub-surfaces are synchronized, too, without explicitly setting them. -// -// Destroying a sub-surface takes effect immediately. If you need to -// synchronize the removal of a sub-surface to the parent surface update, -// unmap the sub-surface first by attaching a NULL wl_buffer, update parent, -// and then destroy the sub-surface. -// -// If the parent wl_surface object is destroyed, the sub-surface is -// unmapped. -// -// A sub-surface never has the keyboard focus of any seat. -// -// The wl_surface.offset request is ignored: clients must use set_position -// instead to move the sub-surface. -func NewSubsurface(ctx *Context) *Subsurface { - wlSubsurface := &Subsurface{} - ctx.Register(wlSubsurface) - return wlSubsurface -} - -// Destroy : remove sub-surface interface -// -// The sub-surface interface is removed from the wl_surface object -// that was turned into a sub-surface with a -// wl_subcompositor.get_subsurface request. The wl_surface's association -// to the parent is deleted. The wl_surface is unmapped immediately. -func (i *Subsurface) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetPosition : reposition the sub-surface -// -// This schedules a sub-surface position change. -// The sub-surface will be moved so that its origin (top left -// corner pixel) will be at the location x, y of the parent surface -// coordinate system. The coordinates are not restricted to the parent -// surface area. Negative values are allowed. -// -// The scheduled coordinates will take effect whenever the state of the -// parent surface is applied. -// -// If more than one set_position request is invoked by the client before -// the commit of the parent surface, the position of a new request always -// replaces the scheduled position from any previous request. -// -// The initial position is 0, 0. -// -// x: x coordinate in the parent surface -// y: y coordinate in the parent surface -func (i *Subsurface) SetPosition(x, y int32) error { - const opcode = 1 - const _reqBufLen = 8 + 4 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(x)) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(y)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// PlaceAbove : restack the sub-surface -// -// This sub-surface is taken from the stack, and put back just -// above the reference surface, changing the z-order of the sub-surfaces. -// The reference surface must be one of the sibling surfaces, or the -// parent surface. Using any other surface, including this sub-surface, -// will cause a protocol error. -// -// The z-order is double-buffered. Requests are handled in order and -// applied immediately to a pending state. The final pending state is -// copied to the active state the next time the state of the parent -// surface is applied. -// -// A new sub-surface is initially added as the top-most in the stack -// of its siblings and parent. -// -// sibling: the reference surface -func (i *Subsurface) PlaceAbove(sibling *Surface) error { - const opcode = 2 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], sibling.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// PlaceBelow : restack the sub-surface -// -// The sub-surface is placed just below the reference surface. -// See wl_subsurface.place_above. -// -// sibling: the reference surface -func (i *Subsurface) PlaceBelow(sibling *Surface) error { - const opcode = 3 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], sibling.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetSync : set sub-surface to synchronized mode -// -// Change the commit behaviour of the sub-surface to synchronized -// mode, also described as the parent dependent mode. -// -// In synchronized mode, wl_surface.commit on a sub-surface will -// accumulate the committed state in a cache, but the state will -// not be applied and hence will not change the compositor output. -// The cached state is applied to the sub-surface immediately after -// the parent surface's state is applied. This ensures atomic -// updates of the parent and all its synchronized sub-surfaces. -// Applying the cached state will invalidate the cache, so further -// parent surface commits do not (re-)apply old state. -// -// See wl_subsurface for the recursive effect of this mode. -func (i *Subsurface) SetSync() error { - const opcode = 4 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// SetDesync : set sub-surface to desynchronized mode -// -// Change the commit behaviour of the sub-surface to desynchronized -// mode, also described as independent or freely running mode. -// -// In desynchronized mode, wl_surface.commit on a sub-surface will -// apply the pending state directly, without caching, as happens -// normally with a wl_surface. Calling wl_surface.commit on the -// parent surface has no effect on the sub-surface's wl_surface -// state. This mode allows a sub-surface to be updated on its own. -// -// If cached state exists when wl_surface.commit is called in -// desynchronized mode, the pending state is added to the cached -// state, and applied as a whole. This invalidates the cache. -// -// Note: even if a sub-surface is set to desynchronized, a parent -// sub-surface may override it to behave as synchronized. For details, -// see wl_subsurface. -// -// If a surface's parent surface behaves as desynchronized, then -// the cached state is applied on set_desync. -func (i *Subsurface) SetDesync() error { - const opcode = 5 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -type SubsurfaceError uint32 - -// SubsurfaceError : -const ( - // SubsurfaceErrorBadSurface : wl_surface is not a sibling or the parent - SubsurfaceErrorBadSurface SubsurfaceError = 0 -) - -func (e SubsurfaceError) Name() string { - switch e { - case SubsurfaceErrorBadSurface: - return "bad_surface" - default: - return "" - } -} - -func (e SubsurfaceError) Value() string { - switch e { - case SubsurfaceErrorBadSurface: - return "0" - default: - return "" - } -} - -func (e SubsurfaceError) String() string { - return e.Name() + "=" + e.Value() -} - -// FixesInterfaceName is the name of the interface as it appears in the [client.Registry]. -// It can be used to match the [client.RegistryGlobalEvent.Interface] in the -// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. -const FixesInterfaceName = "wl_fixes" - -// Fixes : wayland protocol fixes -// -// This global fixes problems with other core-protocol interfaces that -// cannot be fixed in these interfaces themselves. -type Fixes struct { - BaseProxy -} - -// NewFixes : wayland protocol fixes -// -// This global fixes problems with other core-protocol interfaces that -// cannot be fixed in these interfaces themselves. -func NewFixes(ctx *Context) *Fixes { - wlFixes := &Fixes{} - ctx.Register(wlFixes) - return wlFixes -} - -// Destroy : destroys this object -func (i *Fixes) Destroy() error { - defer i.MarkZombie() - const opcode = 0 - const _reqBufLen = 8 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} - -// DestroyRegistry : destroy a wl_registry -// -// This request destroys a wl_registry object. -// -// The client should no longer use the wl_registry after making this -// request. -// -// The compositor will emit a wl_display.delete_id event with the object ID -// of the registry and will no longer emit any events on the registry. The -// client should re-use the object ID once it receives the -// wl_display.delete_id event. -// -// registry: the registry to destroy -func (i *Fixes) DestroyRegistry(registry *Registry) error { - const opcode = 1 - const _reqBufLen = 8 + 4 - var _reqBuf [_reqBufLen]byte - l := 0 - PutUint32(_reqBuf[l:4], i.ID()) - l += 4 - PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) - l += 4 - PutUint32(_reqBuf[l:l+4], registry.ID()) - l += 4 - err := i.Context().WriteMsg(_reqBuf[:], nil) - return err -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/common.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/common.go deleted file mode 100644 index b97d1b8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/common.go +++ /dev/null @@ -1,55 +0,0 @@ -package client - -import "sync/atomic" - -type Dispatcher interface { - Dispatch(opcode uint32, fd int, data []byte) -} - -type Proxy interface { - Context() *Context - SetContext(ctx *Context) - ID() uint32 - SetID(id uint32) - IsZombie() bool - MarkZombie() -} - -type WaylandDisplay interface { - Context() *Context - GetRegistry() (*Registry, error) - Roundtrip() error - Destroy() error -} - -var _ WaylandDisplay = (*Display)(nil) - -type BaseProxy struct { - ctx *Context - id uint32 - zombie atomic.Bool -} - -func (p *BaseProxy) ID() uint32 { - return p.id -} - -func (p *BaseProxy) SetID(id uint32) { - p.id = id -} - -func (p *BaseProxy) Context() *Context { - return p.ctx -} - -func (p *BaseProxy) SetContext(ctx *Context) { - p.ctx = ctx -} - -func (p *BaseProxy) IsZombie() bool { - return p.zombie.Load() -} - -func (p *BaseProxy) MarkZombie() { - p.zombie.Store(true) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context.go deleted file mode 100644 index 4eee2cb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context.go +++ /dev/null @@ -1,143 +0,0 @@ -package client - -import ( - "errors" - "fmt" - "net" - "os" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" -) - -type Context struct { - conn *net.UnixConn - objects syncmap.Map[uint32, Proxy] // map[uint32]Proxy - thread-safe concurrent map - currentID uint32 - idMu sync.Mutex // protects currentID increment -} - -func (ctx *Context) Register(p Proxy) { - ctx.idMu.Lock() - ctx.currentID++ - id := ctx.currentID - ctx.idMu.Unlock() - - p.SetID(id) - p.SetContext(ctx) - ctx.objects.Store(id, p) -} - -func (ctx *Context) RegisterWithID(p Proxy, id uint32) { - p.SetID(id) - p.SetContext(ctx) - ctx.objects.Store(id, p) -} - -func (ctx *Context) Unregister(p Proxy) { - ctx.objects.Delete(p.ID()) -} - -func (ctx *Context) DeleteID(id uint32) { - ctx.objects.Delete(id) -} - -func (ctx *Context) GetProxy(id uint32) Proxy { - if val, ok := ctx.objects.Load(id); ok { - return val - } - return nil -} - -func (ctx *Context) Close() error { - return ctx.conn.Close() -} - -func (ctx *Context) SetReadDeadline(t time.Time) error { - return ctx.conn.SetReadDeadline(t) -} - -func (ctx *Context) Fd() int { - rawConn, err := ctx.conn.SyscallConn() - if err != nil { - return -1 - } - var fd int - rawConn.Control(func(f uintptr) { - fd = int(f) - }) - return fd -} - -// Dispatch reads and processes incoming messages and calls [client.Dispatcher.Dispatch] on the -// respective wayland protocol. -// Dispatch must be called on the same goroutine as other interactions with the Context. -// If a multi goroutine approach is desired, use [Context.GetDispatch] instead. -// Dispatch blocks if there are no incoming messages. -// A Dispatch loop is usually used to handle incoming messages. -func (ctx *Context) Dispatch() error { - return ctx.GetDispatch()() -} - -var ErrDispatchSenderNotFound = errors.New("dispatch: unable to find sender") -var ErrDispatchSenderUnsupported = errors.New("dispatch: sender does not implement Dispatch method") -var ErrDispatchUnableToReadMsg = errors.New("dispatch: unable to read msg") - -// GetDispatch reads incoming messages and returns the dispatch function which calls -// [client.Dispatcher.Dispatch] on the respective wayland protocol. -// This function is now thread-safe and can be called from multiple goroutines. -// GetDispatch blocks if there are no incoming messages. -func (ctx *Context) GetDispatch() func() error { - senderID, opcode, fd, data, err := ctx.ReadMsg() // Blocks if there are no incoming messages - if err != nil { - return func() error { - return fmt.Errorf("%w: %w", ErrDispatchUnableToReadMsg, err) - } - } - - return func() error { - proxy, ok := ctx.objects.Load(senderID) - if !ok { - return nil // Proxy already deleted via delete_id, silently ignore - } - - if proxy.IsZombie() { - return nil // Zombie proxy, discard late events - } - - sender, ok := proxy.(Dispatcher) - if !ok { - return fmt.Errorf("%w (senderID=%d)", ErrDispatchSenderUnsupported, senderID) - } - - sender.Dispatch(opcode, fd, data) - return nil - } -} - -func Connect(addr string) (*Display, error) { - if addr == "" { - runtimeDir := os.Getenv("XDG_RUNTIME_DIR") - if runtimeDir == "" { - return nil, errors.New("env XDG_RUNTIME_DIR not set") - } - if addr == "" { - addr = os.Getenv("WAYLAND_DISPLAY") - } - if addr == "" { - addr = "wayland-0" - } - addr = runtimeDir + "/" + addr - } - - ctx := &Context{} - - conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: addr, Net: "unix"}) - if err != nil { - return nil, err - } - ctx.conn = conn - - return NewDisplay(ctx), nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context_test.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context_test.go deleted file mode 100644 index 380d7da..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/context_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package client_test - -import ( - "errors" - "fmt" - "log" - - "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -// Shows a dispatch loop that will block the goroutine. -// This approach has no risk of data races but the loop blocks the goroutine when no messages are -// received. This can be a valid approach if there are no more changes that need to be made after -// setting up and starting the loop. -// For a multi goroutine approach, use [client.Context.GetDispatch]. -func ExampleContext_Dispatch() { - display, err := client.Connect("") - if err != nil { - log.Fatalf("Error connecting to Wayland server: %v", err) - } - - registry, err := display.GetRegistry() - if err != nil { - log.Fatalf("Error getting Wayland registry: %v", err) - } - - var seat *client.Seat - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - switch e.Interface { - case client.SeatInterfaceName: - seat = client.NewSeat(display.Context()) - err := registry.Bind(e.Name, e.Interface, e.Version, seat) - if err != nil { - log.Fatalf("unable to bind %s interface: %v", client.SeatInterfaceName, err) - } - } - }) - display.Roundtrip() - display.Roundtrip() - - keyboard, err := seat.GetKeyboard() - if err != nil { - log.Printf("Error getting keyboard: %v", err) - } - log.Printf("Got keyboard: %v\n", keyboard) - - for { - err := display.Context().Dispatch() - if err != nil { - log.Printf("Dispatch error: %v\n", err) - } - } -} - -// Shows how the dispatch loop can be done in another goroutine. -// This prevents the goroutine from being blocked and allows making changes to wayland objects while -// the dispatch loop is blocking another goroutine. -func ExampleContext_GetDispatch() { - display, err := client.Connect("") - if err != nil { - log.Fatalf("Error connecting to Wayland server: %v", err) - } - - registry, err := display.GetRegistry() - if err != nil { - log.Fatalf("Error getting Wayland registry: %v", err) - } - - var seat *client.Seat - registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) { - switch e.Interface { - case client.SeatInterfaceName: - seat = client.NewSeat(display.Context()) - err := registry.Bind(e.Name, e.Interface, e.Version, seat) - if err != nil { - log.Fatalf("unable to bind %s interface: %v", client.SeatInterfaceName, err) - } - } - }) - display.Roundtrip() - display.Roundtrip() - dispatchQueue := make(chan func() error) - - go func() { - for { - dispatchQueue <- display.Context().GetDispatch() - } - }() - - keyboard, err := seat.GetKeyboard() - if err != nil { - log.Printf("Error getting keyboard: %v", err) - } - log.Printf("Got keyboard: %v\n", keyboard) - - err = errors.Join(keyboard.Release(), seat.Release(), display.Context().Close()) - if err != nil { - fmt.Printf("Error cleaning up: %v\n", err) - } - - for { - select { - // Add other cases here to do other things - case dispatchFunc := <-dispatchQueue: - err := dispatchFunc() - if err != nil { - log.Printf("Dispatch error: %v\n", err) - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/display.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/display.go deleted file mode 100644 index fa2af6f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/display.go +++ /dev/null @@ -1,37 +0,0 @@ -package client - -import ( - "fmt" - "log" -) - -// Roundtrip blocks until all pending request are processed by the server. -// It is the implementation of [wl_display_roundtrip]. -// -// [wl_display_roundtrip]: https://wayland.freedesktop.org/docs/html/apb.html#Client-classwl__display_1ab60f38c2f80980ac84f347e932793390 -func (i *Display) Roundtrip() error { - callback, err := i.Sync() - if err != nil { - return fmt.Errorf("unable to get sync callback: %w", err) - } - defer func() { - if err2 := callback.Destroy(); err2 != nil { - log.Printf("unable to destroy callback: %v\n", err2) - } - }() - - done := false - callback.SetDoneHandler(func(_ CallbackDoneEvent) { - done = true - }) - - // Wait for callback to return - for !done { - err := i.Context().GetDispatch()() - if err != nil { - return fmt.Errorf("roundtrip: failed to dispatch: %w", err) - } - } - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/doc.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/doc.go deleted file mode 100644 index 91137f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Package client is Go port of wayland-client library -// for writing pure Go GUI software for wayland supported -// platforms. -package client - -//go:generate go run github.com/yaslama/go-wayland/cmd/go-wayland-scanner -pkg client -prefix wl -o client.go -i https://gitlab.freedesktop.org/wayland/wayland/-/raw/1.23.0/protocol/wayland.xml?ref_type=tags diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/event.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/event.go deleted file mode 100644 index e7b5cb8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/event.go +++ /dev/null @@ -1,120 +0,0 @@ -package client - -import ( - "bytes" - "fmt" - "unsafe" - - "golang.org/x/sys/unix" - - _ "unsafe" -) - -var oobSpace = unix.CmsgSpace(4) - -func (ctx *Context) ReadMsg() (senderID uint32, opcode uint32, fd int, msg []byte, err error) { - fd = -1 - - oob := make([]byte, oobSpace) - header := make([]byte, 8) - - n, oobn, _, _, err := ctx.conn.ReadMsgUnix(header, oob) - if err != nil { - return senderID, opcode, fd, msg, err - } - if n != 8 { - return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: incorrect number of bytes read for header (n=%d)", n) - } - - if oobn > 0 { - fds, err := getFdsFromOob(oob, oobn, "header") - if err != nil { - return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err) - } - - if len(fds) > 0 { - fd = fds[0] - } - } - - senderID = Uint32(header[:4]) - opcodeAndSize := Uint32(header[4:8]) - opcode = opcodeAndSize & 0xffff - size := opcodeAndSize >> 16 - - msgSize := int(size) - 8 - if msgSize == 0 { - return senderID, opcode, fd, nil, nil - } - - msg = make([]byte, msgSize) - - if fd == -1 { - // if something was read before, then zero it out - if oobn > 0 { - oob = make([]byte, oobSpace) - } - - n, oobn, _, _, err = ctx.conn.ReadMsgUnix(msg, oob) - } else { - n, err = ctx.conn.Read(msg) - } - if err != nil { - return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err) - } - if n != msgSize { - return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: incorrect number of bytes read for msg (n=%d, msgSize=%d)", n, msgSize) - } - - if fd == -1 && oobn > 0 { - fds, err := getFdsFromOob(oob, oobn, "msg") - if err != nil { - return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err) - } - - if len(fds) > 0 { - fd = fds[0] - } - } - - return senderID, opcode, fd, msg, nil -} - -func getFdsFromOob(oob []byte, oobn int, source string) ([]int, error) { - if oobn > len(oob) { - return nil, fmt.Errorf("getFdsFromOob: incorrect number of bytes read from %s for oob (oobn=%d)", source, oobn) - } - scms, err := unix.ParseSocketControlMessage(oob) - if err != nil { - return nil, fmt.Errorf("getFdsFromOob: unable to parse control message from %s: %w", source, err) - } - - var fdsRet []int - for _, scm := range scms { - fds, err := unix.ParseUnixRights(&scm) - if err != nil { - return nil, fmt.Errorf("getFdsFromOob: unable to parse unix rights from %s: %w", source, err) - } - - fdsRet = append(fdsRet, fds...) - } - - return fdsRet, nil -} - -func Uint32(src []byte) uint32 { - _ = src[3] - return *(*uint32)(unsafe.Pointer(&src[0])) -} - -func String(src []byte) string { - idx := bytes.IndexByte(src, 0) - src = src[:idx:idx] - return *(*string)(unsafe.Pointer(&src)) -} - -func Fixed(src []byte) float64 { - _ = src[3] - fx := *(*int32)(unsafe.Pointer(&src[0])) - return fixedToFloat64(fx) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/request.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/request.go deleted file mode 100644 index 3ca2317..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/request.go +++ /dev/null @@ -1,44 +0,0 @@ -package client - -import ( - "fmt" - "unsafe" -) - -func (ctx *Context) WriteMsg(b []byte, oob []byte) error { - n, oobn, err := ctx.conn.WriteMsgUnix(b, oob, nil) - if err != nil { - return err - } - if n != len(b) || oobn != len(oob) { - return fmt.Errorf("ctx.WriteMsg: incorrect number of bytes written (n=%d oobn=%d)", n, oobn) - } - - return nil -} - -func PutUint32(dst []byte, v uint32) { - _ = dst[3] - *(*uint32)(unsafe.Pointer(&dst[0])) = v -} - -func PutFixed(dst []byte, f float64) { - fx := fixedFromfloat64(f) - _ = dst[3] - *(*int32)(unsafe.Pointer(&dst[0])) = fx -} - -// PutString places a string in Wayland's wire format on the destination buffer. -// It first places the length of the string (plus one for the null terminator) and then the string -// followed by a null byte. -// The length of dst must be equal to, or greater than, len(v) + 5. -func PutString(dst []byte, v string) { - PutUint32(dst[:4], uint32(len(v)+1)) - copy(dst[4:], v) - dst[4+len(v)] = '\x00' // To cause panic if dst is not large enough -} - -func PutArray(dst []byte, a []byte) { - PutUint32(dst[:4], uint32(len(a))) - copy(dst[4:], a) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/util.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/util.go deleted file mode 100644 index ba3d43a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/client/util.go +++ /dev/null @@ -1,24 +0,0 @@ -package client - -import "math" - -// From wayland/wayland-util.h - -func fixedToFloat64(f int32) float64 { - u_i := (1023+44)<<52 + (1 << 51) + int64(f) - u_d := math.Float64frombits(uint64(u_i)) - return u_d - (3 << 43) -} - -func fixedFromfloat64(d float64) int32 { - u_d := d + (3 << (51 - 8)) - u_i := int64(math.Float64bits(u_d)) - return int32(u_i) -} - -func PaddedLen(l int) int { - if (l & 0x3) != 0 { - return l + (4 - (l & 0x3)) - } - return l -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/stable/xdg-shell/xdg_shell.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/stable/xdg-shell/xdg_shell.go deleted file mode 100644 index 19a203b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/go-wayland/wayland/stable/xdg-shell/xdg_shell.go +++ /dev/null @@ -1,13 +0,0 @@ -package xdg_shell - -import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" - -type Popup struct { - client.BaseProxy -} - -func NewPopup(ctx *client.Context) *Popup { - p := &Popup{} - ctx.Register(p) - return p -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/CREDITS.MD b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/CREDITS.MD deleted file mode 100644 index b7d28cc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/CREDITS.MD +++ /dev/null @@ -1,5 +0,0 @@ -# Credits - -* Original socket adapter code is mostly taken from [korylprince/printer-manager-cups](https://github.com/korylprince/printer-manager-cups) -([MIT](https://github.com/korylprince/printer-manager-cups/blob/v1.0.9/LICENSE) licensed): -[conn.go](https://github.com/korylprince/printer-manager-cups/blob/v1.0.9/cups/conn.go) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter-http.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter-http.go deleted file mode 100644 index 56ababb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter-http.go +++ /dev/null @@ -1,132 +0,0 @@ -package ipp - -import ( - "bytes" - "crypto/tls" - "fmt" - "io" - "net" - "net/http" - "strconv" - "time" -) - -type HttpAdapter struct { - host string - port int - username string - password string - useTLS bool - client *http.Client -} - -func NewHttpAdapter(host string, port int, username, password string, useTLS bool) *HttpAdapter { - httpClient := http.Client{ - Timeout: 0, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - ResponseHeaderTimeout: 90 * time.Second, - IdleConnTimeout: 120 * time.Second, - }, - } - - return &HttpAdapter{ - host: host, - port: port, - username: username, - password: password, - useTLS: useTLS, - client: &httpClient, - } -} - -func (h *HttpAdapter) SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) { - payload, err := req.Encode() - if err != nil { - return nil, err - } - - size := len(payload) - var body io.Reader - if req.File != nil && req.FileSize != -1 { - size += req.FileSize - body = io.MultiReader(bytes.NewBuffer(payload), req.File) - } else { - body = bytes.NewBuffer(payload) - } - - httpReq, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - - httpReq.Header.Set("Content-Length", strconv.Itoa(size)) - httpReq.Header.Set("Content-Type", ContentTypeIPP) - - if h.username != "" && h.password != "" { - httpReq.SetBasicAuth(h.username, h.password) - } - - httpResp, err := h.client.Do(httpReq) - if err != nil { - return nil, err - } - defer httpResp.Body.Close() - - if httpResp.StatusCode != 200 { - return nil, HTTPError{ - Code: httpResp.StatusCode, - } - } - - // buffer response to avoid read issues - buf := new(bytes.Buffer) - if httpResp.ContentLength > 0 { - buf.Grow(int(httpResp.ContentLength)) - } - if _, err := io.Copy(buf, httpResp.Body); err != nil { - return nil, fmt.Errorf("unable to buffer response: %w", err) - } - - ippResp, err := NewResponseDecoder(buf).Decode(additionalResponseData) - if err != nil { - return nil, err - } - - if err = ippResp.CheckForErrors(); err != nil { - return nil, fmt.Errorf("received error IPP response: %w", err) - } - - return ippResp, nil -} - -func (h *HttpAdapter) GetHttpUri(namespace string, object any) string { - proto := "http" - if h.useTLS { - proto = "https" - } - - uri := fmt.Sprintf("%s://%s:%d", proto, h.host, h.port) - - if namespace != "" { - uri = fmt.Sprintf("%s/%s", uri, namespace) - } - - if object != nil { - uri = fmt.Sprintf("%s/%v", uri, object) - } - - return uri -} - -func (h *HttpAdapter) TestConnection() error { - conn, err := net.Dial("tcp", net.JoinHostPort(h.host, fmt.Sprintf("%d", h.port))) - if err != nil { - return err - } - conn.Close() - - return nil -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter.go deleted file mode 100644 index 8af0520..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/adapter.go +++ /dev/null @@ -1,9 +0,0 @@ -package ipp - -import "io" - -type Adapter interface { - SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) - GetHttpUri(namespace string, object any) string - TestConnection() error -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/attribute.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/attribute.go deleted file mode 100644 index 295f521..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/attribute.go +++ /dev/null @@ -1,528 +0,0 @@ -package ipp - -import ( - "encoding/binary" - "fmt" - "io" -) - -const ( - sizeInteger = int16(4) - sizeBoolean = int16(1) -) - -// AttributeEncoder encodes attribute to a io.Writer -type AttributeEncoder struct { - writer io.Writer -} - -// NewAttributeEncoder returns a new encoder that writes to w -func NewAttributeEncoder(w io.Writer) *AttributeEncoder { - return &AttributeEncoder{w} -} - -// Encode encodes a attribute and its value to a io.Writer -// the tag is determined by the AttributeTagMapping map -func (e *AttributeEncoder) Encode(attribute string, value any) error { - tag, ok := AttributeTagMapping[attribute] - if !ok { - return fmt.Errorf("cannot get tag of attribute %s", attribute) - } - - switch v := value.(type) { - case int: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeInteger(int32(v)); err != nil { - return err - } - case int16: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeInteger(int32(v)); err != nil { - return err - } - case int8: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeInteger(int32(v)); err != nil { - return err - } - case int32: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeInteger(v); err != nil { - return err - } - case int64: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeInteger(int32(v)); err != nil { - return err - } - case []int: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeInteger(int32(val)); err != nil { - return err - } - } - case []int16: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeInteger(int32(val)); err != nil { - return err - } - } - case []int8: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeInteger(int32(val)); err != nil { - return err - } - } - case []int32: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeInteger(val); err != nil { - return err - } - } - case []int64: - if tag != TagInteger && tag != TagEnum { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeInteger(int32(val)); err != nil { - return err - } - } - case bool: - if tag != TagBoolean { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeBoolean(v); err != nil { - return err - } - case []bool: - if tag != TagBoolean { - return fmt.Errorf("tag for attribute %s does not match with value type", attribute) - } - - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeBoolean(val); err != nil { - return err - } - } - case string: - if err := e.encodeTag(tag); err != nil { - return err - } - - if err := e.encodeString(attribute); err != nil { - return err - } - - if err := e.encodeString(v); err != nil { - return err - } - case []string: - for index, val := range v { - if err := e.encodeTag(tag); err != nil { - return err - } - - if index == 0 { - if err := e.encodeString(attribute); err != nil { - return err - } - } else { - if err := e.writeNullByte(); err != nil { - return err - } - } - - if err := e.encodeString(val); err != nil { - return err - } - } - default: - return fmt.Errorf("type %T is not supported", value) - } - - return nil -} - -func (e *AttributeEncoder) encodeString(s string) error { - if err := binary.Write(e.writer, binary.BigEndian, int16(len(s))); err != nil { - return err - } - - _, err := e.writer.Write([]byte(s)) - return err -} - -func (e *AttributeEncoder) encodeInteger(i int32) error { - if err := binary.Write(e.writer, binary.BigEndian, sizeInteger); err != nil { - return err - } - - return binary.Write(e.writer, binary.BigEndian, i) -} - -func (e *AttributeEncoder) encodeBoolean(b bool) error { - if err := binary.Write(e.writer, binary.BigEndian, sizeBoolean); err != nil { - return err - } - - return binary.Write(e.writer, binary.BigEndian, b) -} - -func (e *AttributeEncoder) encodeTag(t int8) error { - return binary.Write(e.writer, binary.BigEndian, t) -} - -func (e *AttributeEncoder) writeNullByte() error { - return binary.Write(e.writer, binary.BigEndian, int16(0)) -} - -// Attribute defines an ipp attribute -type Attribute struct { - Tag int8 - Name string - Value any -} - -// Resolution defines the resolution attribute -type Resolution struct { - Height int32 - Width int32 - Depth int8 -} - -// AttributeDecoder reads and decodes ipp from an input stream -type AttributeDecoder struct { - reader io.Reader -} - -// NewAttributeDecoder returns a new decoder that reads from r -func NewAttributeDecoder(r io.Reader) *AttributeDecoder { - return &AttributeDecoder{r} -} - -// Decode reads the next ipp attribute into a attribute struct. the type is identified by a tag passed as an argument -func (d *AttributeDecoder) Decode(tag int8) (*Attribute, error) { - attr := Attribute{Tag: tag} - - name, err := d.decodeString() - if err != nil { - return nil, err - } - attr.Name = name - - switch attr.Tag { - case TagEnum, TagInteger: - val, err := d.decodeInteger() - if err != nil { - return nil, err - } - attr.Value = val - case TagBoolean: - val, err := d.decodeBool() - if err != nil { - return nil, err - } - attr.Value = val - case TagDate: - val, err := d.decodeDate() - if err != nil { - return nil, err - } - attr.Value = val - case TagRange: - val, err := d.decodeRange() - if err != nil { - return nil, err - } - attr.Value = val - case TagResolution: - val, err := d.decodeResolution() - if err != nil { - return nil, err - } - attr.Value = val - default: - val, err := d.decodeString() - if err != nil { - return nil, err - } - attr.Value = val - } - - return &attr, nil -} - -func (d *AttributeDecoder) decodeBool() (b bool, err error) { - if _, err = d.readValueLength(); err != nil { - return - } - - if err = binary.Read(d.reader, binary.BigEndian, &b); err != nil { - return - } - - return -} - -func (d *AttributeDecoder) decodeInteger() (i int, err error) { - if _, err = d.readValueLength(); err != nil { - return - } - - var reti int32 - if err = binary.Read(d.reader, binary.BigEndian, &reti); err != nil { - return - } - - return int(reti), nil -} - -func (d *AttributeDecoder) decodeString() (string, error) { - length, err := d.readValueLength() - if err != nil { - return "", err - } - - if length == 0 { - return "", nil - } - - bs := make([]byte, length) - if _, err := d.reader.Read(bs); err != nil { - return "", nil - } - - return string(bs), nil -} - -func (d *AttributeDecoder) decodeDate() ([]int, error) { - length, err := d.readValueLength() - if err != nil { - return nil, err - } - - is := make([]int, length) - var ti int8 - - for i := int16(0); i < length; i++ { - if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil { - return nil, err - } - is[i] = int(ti) - } - - return is, nil -} - -func (d *AttributeDecoder) decodeRange() ([]int32, error) { - length, err := d.readValueLength() - if err != nil { - return nil, err - } - - // initialize range element count (c) and range slice (r) - c := length / 4 - r := make([]int32, c) - - for i := int16(0); i < c; i++ { - var ti int32 - if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil { - return nil, err - } - r[i] = ti - } - - return r, nil -} - -func (d *AttributeDecoder) decodeResolution() (res Resolution, err error) { - _, err = d.readValueLength() - if err != nil { - return - } - - if err = binary.Read(d.reader, binary.BigEndian, &res.Height); err != nil { - return - } - - if err = binary.Read(d.reader, binary.BigEndian, &res.Width); err != nil { - return - } - - if err = binary.Read(d.reader, binary.BigEndian, &res.Depth); err != nil { - return - } - - return -} - -func (d *AttributeDecoder) readValueLength() (length int16, err error) { - err = binary.Read(d.reader, binary.BigEndian, &length) - return -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/constants.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/constants.go deleted file mode 100644 index 83bf41b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/constants.go +++ /dev/null @@ -1,450 +0,0 @@ -package ipp - -// ipp status codes -const ( - StatusCupsInvalid int16 = -1 - StatusOk int16 = 0x0000 - StatusOkIgnoredOrSubstituted int16 = 0x0001 - StatusOkConflicting int16 = 0x0002 - StatusOkIgnoredSubscriptions int16 = 0x0003 - StatusOkIgnoredNotifications int16 = 0x0004 - StatusOkTooManyEvents int16 = 0x0005 - StatusOkButCancelSubscription int16 = 0x0006 - StatusOkEventsComplete int16 = 0x0007 - StatusRedirectionOtherSite int16 = 0x0200 - StatusCupsSeeOther int16 = 0x0280 - StatusErrorBadRequest int16 = 0x0400 - StatusErrorForbidden int16 = 0x0401 - StatusErrorNotAuthenticated int16 = 0x0402 - StatusErrorNotAuthorized int16 = 0x0403 - StatusErrorNotPossible int16 = 0x0404 - StatusErrorTimeout int16 = 0x0405 - StatusErrorNotFound int16 = 0x0406 - StatusErrorGone int16 = 0x0407 - StatusErrorRequestEntity int16 = 0x0408 - StatusErrorRequestValue int16 = 0x0409 - StatusErrorDocumentFormatNotSupported int16 = 0x040a - StatusErrorAttributesOrValues int16 = 0x040b - StatusErrorUriScheme int16 = 0x040c - StatusErrorCharset int16 = 0x040d - StatusErrorConflicting int16 = 0x040e - StatusErrorCompressionError int16 = 0x040f - StatusErrorDocumentFormatError int16 = 0x0410 - StatusErrorDocumentAccess int16 = 0x0411 - StatusErrorAttributesNotSettable int16 = 0x0412 - StatusErrorIgnoredAllSubscriptions int16 = 0x0413 - StatusErrorTooManySubscriptions int16 = 0x0414 - StatusErrorIgnoredAllNotifications int16 = 0x0415 - StatusErrorPrintSupportFileNotFound int16 = 0x0416 - StatusErrorDocumentPassword int16 = 0x0417 - StatusErrorDocumentPermission int16 = 0x0418 - StatusErrorDocumentSecurity int16 = 0x0419 - StatusErrorDocumentUnprintable int16 = 0x041a - StatusErrorAccountInfoNeeded int16 = 0x041b - StatusErrorAccountClosed int16 = 0x041c - StatusErrorAccountLimitReached int16 = 0x041d - StatusErrorAccountAuthorizationFailed int16 = 0x041e - StatusErrorNotFetchable int16 = 0x041f - StatusErrorCupsAccountInfoNeeded int16 = 0x049C - StatusErrorCupsAccountClosed int16 = 0x049d - StatusErrorCupsAccountLimitReached int16 = 0x049e - StatusErrorCupsAccountAuthorizationFailed int16 = 0x049f - StatusErrorInternal int16 = 0x0500 - StatusErrorOperationNotSupported int16 = 0x0501 - StatusErrorServiceUnavailable int16 = 0x0502 - StatusErrorVersionNotSupported int16 = 0x0503 - StatusErrorDevice int16 = 0x0504 - StatusErrorTemporary int16 = 0x0505 - StatusErrorNotAcceptingJobs int16 = 0x0506 - StatusErrorBusy int16 = 0x0507 - StatusErrorJobCanceled int16 = 0x0508 - StatusErrorMultipleJobsNotSupported int16 = 0x0509 - StatusErrorPrinterIsDeactivated int16 = 0x050a - StatusErrorTooManyJobs int16 = 0x050b - StatusErrorTooManyDocuments int16 = 0x050c - StatusErrorCupsAuthenticationCanceled int16 = 0x1000 - StatusErrorCupsPki int16 = 0x1001 - StatusErrorCupsUpgradeRequired int16 = 0x1002 -) - -// ipp operations -const ( - OperationCupsInvalid int16 = -0x0001 - OperationCupsNone int16 = 0x0000 - OperationPrintJob int16 = 0x0002 - OperationPrintUri int16 = 0x0003 - OperationValidateJob int16 = 0x0004 - OperationCreateJob int16 = 0x0005 - OperationSendDocument int16 = 0x0006 - OperationSendUri int16 = 0x0007 - OperationCancelJob int16 = 0x0008 - OperationGetJobAttributes int16 = 0x0009 - OperationGetJobs int16 = 0x000a - OperationGetPrinterAttributes int16 = 0x000b - OperationHoldJob int16 = 0x000c - OperationReleaseJob int16 = 0x000d - OperationRestartJob int16 = 0x000e - OperationPausePrinter int16 = 0x0010 - OperationResumePrinter int16 = 0x0011 - OperationPurgeJobs int16 = 0x0012 - OperationSetPrinterAttributes int16 = 0x0013 - OperationSetJobAttributes int16 = 0x0014 - OperationGetPrinterSupportedValues int16 = 0x0015 - OperationCreatePrinterSubscriptions int16 = 0x0016 - OperationCreateJobSubscriptions int16 = 0x0017 - OperationGetSubscriptionAttributes int16 = 0x0018 - OperationGetSubscriptions int16 = 0x0019 - OperationRenewSubscription int16 = 0x001a - OperationCancelSubscription int16 = 0x001b - OperationGetNotifications int16 = 0x001c - OperationSendNotifications int16 = 0x001d - OperationGetResourceAttributes int16 = 0x001e - OperationGetResourceData int16 = 0x001f - OperationGetResources int16 = 0x0020 - OperationGetPrintSupportFiles int16 = 0x0021 - OperationEnablePrinter int16 = 0x0022 - OperationDisablePrinter int16 = 0x0023 - OperationPausePrinterAfterCurrentJob int16 = 0x0024 - OperationHoldNewJobs int16 = 0x0025 - OperationReleaseHeldNewJobs int16 = 0x0026 - OperationDeactivatePrinter int16 = 0x0027 - OperationActivatePrinter int16 = 0x0028 - OperationRestartPrinter int16 = 0x0029 - OperationShutdownPrinter int16 = 0x002a - OperationStartupPrinter int16 = 0x002b - OperationReprocessJob int16 = 0x002c - OperationCancelCurrentJob int16 = 0x002d - OperationSuspendCurrentJob int16 = 0x002e - OperationResumeJob int16 = 0x002f - OperationOperationPromoteJob int16 = 0x0030 - OperationScheduleJobAfter int16 = 0x0031 - OperationCancelDocument int16 = 0x0033 - OperationGetDocumentAttributes int16 = 0x0034 - OperationGetDocuments int16 = 0x0035 - OperationDeleteDocument int16 = 0x0036 - OperationSetDocumentAttributes int16 = 0x0037 - OperationCancelJobs int16 = 0x0038 - OperationCancelMyJobs int16 = 0x0039 - OperationResubmitJob int16 = 0x003a - OperationCloseJob int16 = 0x003b - OperationIdentifyPrinter int16 = 0x003c - OperationValidateDocument int16 = 0x003d - OperationAddDocumentImages int16 = 0x003e - OperationAcknowledgeDocument int16 = 0x003f - OperationAcknowledgeIdentifyPrinter int16 = 0x0040 - OperationAcknowledgeJob int16 = 0x0041 - OperationFetchDocument int16 = 0x0042 - OperationFetchJob int16 = 0x0043 - OperationGetOutputDeviceAttributes int16 = 0x0044 - OperationUpdateActiveJobs int16 = 0x0045 - OperationDeregisterOutputDevice int16 = 0x0046 - OperationUpdateDocumentStatus int16 = 0x0047 - OperationUpdateJobStatus int16 = 0x0048 - OperationUpdateOutputDeviceAttributes int16 = 0x0049 - OperationGetNextDocumentData int16 = 0x004a - OperationAllocatePrinterResources int16 = 0x004b - OperationCreatePrinter int16 = 0x004c - OperationDeallocatePrinterResources int16 = 0x004d - OperationDeletePrinter int16 = 0x004e - OperationGetPrinters int16 = 0x004f - OperationShutdownOnePrinter int16 = 0x0050 - OperationStartupOnePrinter int16 = 0x0051 - OperationCancelResource int16 = 0x0052 - OperationCreateResource int16 = 0x0053 - OperationInstallResource int16 = 0x0054 - OperationSendResourceData int16 = 0x0055 - OperationSetResourceAttributes int16 = 0x0056 - OperationCreateResourceSubscriptions int16 = 0x0057 - OperationCreateSystemSubscriptions int16 = 0x0058 - OperationDisableAllPrinters int16 = 0x0059 - OperationEnableAllPrinters int16 = 0x005a - OperationGetSystemAttributes int16 = 0x005b - OperationGetSystemSupportedValues int16 = 0x005c - OperationPauseAllPrinters int16 = 0x005d - OperationPauseAllPrintersAfterCurrentJob int16 = 0x005e - OperationRegisterOutputDevice int16 = 0x005f - OperationRestartSystem int16 = 0x0060 - OperationResumeAllPrinters int16 = 0x0061 - OperationSetSystemAttributes int16 = 0x0062 - OperationShutdownAllPrinter int16 = 0x0063 - OperationStartupAllPrinters int16 = 0x0064 - OperationPrivate int16 = 0x4000 - OperationCupsGetDefault int16 = 0x4001 - OperationCupsGetPrinters int16 = 0x4002 - OperationCupsAddModifyPrinter int16 = 0x4003 - OperationCupsDeletePrinter int16 = 0x4004 - OperationCupsGetClasses int16 = 0x4005 - OperationCupsAddModifyClass int16 = 0x4006 - OperationCupsDeleteClass int16 = 0x4007 - OperationCupsAcceptJobs int16 = 0x4008 - OperationCupsRejectJobs int16 = 0x4009 - OperationCupsSetDefault int16 = 0x400a - OperationCupsGetDevices int16 = 0x400b - OperationCupsGetPPDs int16 = 0x400c - OperationCupsMoveJob int16 = 0x400d - OperationCupsAuthenticateJob int16 = 0x400e - OperationCupsGetPpd int16 = 0x400f - OperationCupsGetDocument int16 = 0x4027 - OperationCupsCreateLocalPrinter int16 = 0x4028 -) - -// ipp tags -const ( - TagCupsInvalid int8 = -1 - TagZero int8 = 0x00 - TagOperation int8 = 0x01 - TagJob int8 = 0x02 - TagEnd int8 = 0x03 - TagPrinter int8 = 0x04 - TagUnsupportedGroup int8 = 0x05 - TagSubscription int8 = 0x06 - TagEventNotification int8 = 0x07 - TagResource int8 = 0x08 - TagDocument int8 = 0x09 - TagSystem int8 = 0x0a - TagUnsupportedValue int8 = 0x10 - TagDefault int8 = 0x11 - TagUnknown int8 = 0x12 - TagNoValue int8 = 0x13 - TagNotSettable int8 = 0x15 - TagDeleteAttr int8 = 0x16 - TagAdminDefine int8 = 0x17 - TagInteger int8 = 0x21 - TagBoolean int8 = 0x22 - TagEnum int8 = 0x23 - TagString int8 = 0x30 - TagDate int8 = 0x31 - TagResolution int8 = 0x32 - TagRange int8 = 0x33 - TagBeginCollection int8 = 0x34 - TagTextLang int8 = 0x35 - TagNameLang int8 = 0x36 - TagEndCollection int8 = 0x37 - TagText int8 = 0x41 - TagName int8 = 0x42 - TagReservedString int8 = 0x43 - TagKeyword int8 = 0x44 - TagUri int8 = 0x45 - TagUriScheme int8 = 0x46 - TagCharset int8 = 0x47 - TagLanguage int8 = 0x48 - TagMimeType int8 = 0x49 - TagMemberName int8 = 0x4a - TagExtension int8 = 0x7f -) - -// job states -const ( - JobStatePending int8 = 0x03 - JobStateHeld int8 = 0x04 - JobStateProcessing int8 = 0x05 - JobStateStopped int8 = 0x06 - JobStateCanceled int8 = 0x07 - JobStateAborted int8 = 0x08 - JobStateCompleted int8 = 0x09 -) - -// document states -const ( - DocumentStatePending int8 = 0x03 - DocumentStateProcessing int8 = 0x05 - DocumentStateCanceled int8 = 0x07 - DocumentStateAborted int8 = 0x08 - DocumentStateCompleted int8 = 0x08 -) - -// printer states -const ( - PrinterStateIdle int8 = 0x0003 - PrinterStateProcessing int8 = 0x0004 - PrinterStateStopped int8 = 0x0005 -) - -// job state filter -const ( - JobStateFilterNotCompleted = "not-completed" - JobStateFilterCompleted = "completed" - JobStateFilterAll = "all" -) - -// error policies -const ( - ErrorPolicyRetryJob = "retry-job" - ErrorPolicyAbortJob = "abort-job" - ErrorPolicyRetryCurrentJob = "retry-current-job" - ErrorPolicyStopPrinter = "stop-printer" -) - -// ipp defaults -const ( - CharsetLanguage = "en-US" - Charset = "utf-8" - ProtocolVersionMajor = int8(2) - ProtocolVersionMinor = int8(0) - - DefaultJobPriority = 50 -) - -// useful mime types for ipp -const ( - MimeTypePostscript = "application/postscript" - MimeTypePDF = "application/pdf" - MimeTypeOctetStream = "application/octet-stream" -) - -// ipp content types -const ( - ContentTypeIPP = "application/ipp" -) - -// known ipp attributes -const ( - AttributeCopies = "copies" - AttributeDocumentFormat = "document-format" - AttributeDocumentName = "document-name" - AttributeJobID = "job-id" - AttributeJobName = "job-name" - AttributeJobPriority = "job-priority" - AttributeJobURI = "job-uri" - AttributeLastDocument = "last-document" - AttributeMyJobs = "my-jobs" - AttributePPDName = "ppd-name" - AttributePPDMakeAndModel = "ppd-make-and-model" - AttributePrinterIsShared = "printer-is-shared" - AttributePrinterIsTemporary = "printer-is-temporary" - AttributePrinterURI = "printer-uri" - AttributePurgeJobs = "purge-jobs" - AttributeRequestedAttributes = "requested-attributes" - AttributeRequestingUserName = "requesting-user-name" - AttributeWhichJobs = "which-jobs" - AttributeFirstJobID = "first-job-id" - AttributeLimit = "limit" - AttributeStatusMessage = "status-message" - AttributeCharset = "attributes-charset" - AttributeNaturalLanguage = "attributes-natural-language" - AttributeDeviceURI = "device-uri" - AttributeHoldJobUntil = "job-hold-until" - AttributePrinterErrorPolicy = "printer-error-policy" - AttributePrinterInfo = "printer-info" - AttributePrinterLocation = "printer-location" - AttributePrinterName = "printer-name" - AttributePrinterStateReasons = "printer-state-reasons" - AttributeJobPrinterURI = "job-printer-uri" - AttributeMemberURIs = "member-uris" - AttributeDocumentNumber = "document-number" - AttributeDocumentState = "document-state" - AttributeFinishings = "finishings" - AttributeJobHoldUntil = "hold-job-until" - AttributeJobSheets = "job-sheets" - AttributeJobState = "job-state" - AttributeJobStateReason = "job-state-reason" - AttributeMedia = "media" - AttributeSides = "sides" - AttributeNumberUp = "number-up" - AttributeOrientationRequested = "orientation-requested" - AttributePrintQuality = "print-quality" - AttributePrinterIsAcceptingJobs = "printer-is-accepting-jobs" - AttributePrinterResolution = "printer-resolution" - AttributePrinterState = "printer-state" - AttributeMemberNames = "member-names" - AttributePrinterType = "printer-type" - AttributePrinterMakeAndModel = "printer-make-and-model" - AttributePrinterStateMessage = "printer-state-message" - AttributePrinterUriSupported = "printer-uri-supported" - AttributeJobMediaProgress = "job-media-progress" - AttributeJobKilobyteOctets = "job-k-octets" - AttributeNumberOfDocuments = "number-of-documents" - AttributeJobOriginatingUserName = "job-originating-user-name" - AttributeOutputOrder = "outputorder" - AttributeJobStateReasons = "job-state-reasons" - AttributeJobStateMessage = "job-state-message" - AttributeJobPrinterStateReasons = "job-printer-state-reasons" - AttributeJobPrinterStateMessage = "job-printer-state-message" - AttributeJobImpressionsCompleted = "job-impressions-completed" - AttributePrintScaling = "print-scaling" -) - -// Default attributes -var ( - DefaultClassAttributes = []string{AttributePrinterName, AttributeMemberNames} - DefaultPrinterAttributes = []string{ - AttributePrinterName, AttributePrinterType, AttributePrinterLocation, AttributePrinterInfo, - AttributePrinterMakeAndModel, AttributePrinterState, AttributePrinterStateMessage, AttributePrinterStateReasons, - AttributePrinterUriSupported, AttributeDeviceURI, AttributePrinterIsShared, - } - DefaultJobAttributes = []string{ - AttributeJobID, AttributeJobName, AttributePrinterURI, AttributeJobState, AttributeJobStateReason, - AttributeJobHoldUntil, AttributeJobMediaProgress, AttributeJobKilobyteOctets, AttributeNumberOfDocuments, AttributeCopies, - AttributeJobOriginatingUserName, - } -) - -// Attribute to tag mapping -var ( - AttributeTagMapping = map[string]int8{ - AttributeCharset: TagCharset, - AttributeNaturalLanguage: TagLanguage, - AttributeCopies: TagInteger, - AttributeDeviceURI: TagUri, - AttributeDocumentFormat: TagMimeType, - AttributeDocumentName: TagName, - AttributeDocumentNumber: TagInteger, - AttributeDocumentState: TagEnum, - AttributeFinishings: TagEnum, - AttributeJobHoldUntil: TagKeyword, - AttributeHoldJobUntil: TagKeyword, - AttributeJobID: TagInteger, - AttributeJobName: TagName, - AttributeJobPrinterURI: TagUri, - AttributeJobPriority: TagInteger, - AttributeJobSheets: TagName, - AttributeJobState: TagEnum, - AttributeJobStateReason: TagKeyword, - AttributeJobURI: TagUri, - AttributeLastDocument: TagBoolean, - AttributeMedia: TagKeyword, - AttributeSides: TagKeyword, - AttributeMemberURIs: TagUri, - AttributeMyJobs: TagBoolean, - AttributeNumberUp: TagInteger, - AttributeOrientationRequested: TagEnum, - AttributePPDName: TagName, - AttributePPDMakeAndModel: TagText, - AttributeNumberOfDocuments: TagInteger, - AttributePrintQuality: TagEnum, - AttributePrinterErrorPolicy: TagName, - AttributePrinterInfo: TagText, - AttributePrinterIsAcceptingJobs: TagBoolean, - AttributePrinterIsShared: TagBoolean, - AttributePrinterIsTemporary: TagBoolean, - AttributePrinterName: TagName, - AttributePrinterLocation: TagText, - AttributePrinterResolution: TagResolution, - AttributePrinterState: TagEnum, - AttributePrinterStateReasons: TagKeyword, - AttributePrinterURI: TagUri, - AttributePurgeJobs: TagBoolean, - AttributeRequestedAttributes: TagKeyword, - AttributeRequestingUserName: TagName, - AttributeWhichJobs: TagKeyword, - AttributeFirstJobID: TagInteger, - AttributeStatusMessage: TagText, - AttributeLimit: TagInteger, - AttributeOutputOrder: TagName, - AttributeJobStateReasons: TagString, - AttributeJobStateMessage: TagString, - AttributeJobPrinterStateReasons: TagString, - AttributeJobPrinterStateMessage: TagString, - AttributeJobImpressionsCompleted: TagInteger, - AttributePrintScaling: TagKeyword, - // IPP Subscription/Notification attributes (added for dankdots) - "notify-events": TagKeyword, - "notify-pull-method": TagKeyword, - "notify-lease-duration": TagInteger, - "notify-subscription-id": TagInteger, - "notify-subscription-ids": TagInteger, - "notify-sequence-numbers": TagInteger, - "notify-wait": TagBoolean, - "notify-recipient-uri": TagUri, - } -) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/cups-client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/cups-client.go deleted file mode 100644 index 68d60ce..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/cups-client.go +++ /dev/null @@ -1,313 +0,0 @@ -package ipp - -import ( - "io" - "strings" -) - -// CUPSClient implements a ipp client with specific cups operations -type CUPSClient struct { - *IPPClient -} - -// NewCUPSClient creates a new cups ipp client (used HttpAdapter internally) -func NewCUPSClient(host string, port int, username, password string, useTLS bool) *CUPSClient { - ippClient := NewIPPClient(host, port, username, password, useTLS) - return &CUPSClient{ippClient} -} - -// NewCUPSClientWithAdapter creates a new cups ipp client with given Adapter -func NewCUPSClientWithAdapter(username string, adapter Adapter) *CUPSClient { - ippClient := NewIPPClientWithAdapter(username, adapter) - return &CUPSClient{ippClient} -} - -// GetDevices returns a map of device uris and printer attributes -func (c *CUPSClient) GetDevices() (map[string]Attributes, error) { - req := NewRequest(OperationCupsGetDevices, 1) - - resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil) - if err != nil { - return nil, err - } - - printerNameMap := make(map[string]Attributes) - - for _, printerAttributes := range resp.PrinterAttributes { - printerNameMap[printerAttributes[AttributeDeviceURI][0].Value.(string)] = printerAttributes - } - - return printerNameMap, nil -} - -// MoveJob moves a job to a other printer -func (c *CUPSClient) MoveJob(jobID int, destPrinter string) error { - req := NewRequest(OperationCupsMoveJob, 1) - req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID) - req.PrinterAttributes[AttributeJobPrinterURI] = c.getPrinterUri(destPrinter) - - _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil) - return err -} - -// MoveAllJob moves all job from a printer to a other printer -func (c *CUPSClient) MoveAllJob(srcPrinter, destPrinter string) error { - req := NewRequest(OperationCupsMoveJob, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(srcPrinter) - req.PrinterAttributes[AttributeJobPrinterURI] = c.getPrinterUri(destPrinter) - - _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil) - return err -} - -// GetPPDs returns a map of ppd names and attributes -func (c *CUPSClient) GetPPDs() (map[string]Attributes, error) { - req := NewRequest(OperationCupsGetPPDs, 1) - - resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil) - if err != nil { - return nil, err - } - - ppdNameMap := make(map[string]Attributes) - - for _, printerAttributes := range resp.PrinterAttributes { - ppdNameMap[printerAttributes[AttributePPDName][0].Value.(string)] = printerAttributes - } - - return ppdNameMap, nil -} - -// AcceptJobs lets a printer accept jobs again -func (c *CUPSClient) AcceptJobs(printer string) error { - req := NewRequest(OperationCupsAcceptJobs, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// RejectJobs does not let a printer accept jobs -func (c *CUPSClient) RejectJobs(printer string) error { - req := NewRequest(OperationCupsRejectJobs, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// AddPrinterToClass adds a printer to a class, if the class does not exists it will be created -func (c *CUPSClient) AddPrinterToClass(class, printer string) error { - attributes, err := c.GetPrinterAttributes(class, []string{AttributeMemberURIs}) - if err != nil && !IsNotExistsError(err) { - return err - } - - memberURIList := make([]string, 0) - - if !IsNotExistsError(err) { - for _, member := range attributes[AttributeMemberURIs] { - memberString := strings.Split(member.Value.(string), "/") - printerName := memberString[len(memberString)-1] - - if printerName == printer { - return nil - } - - memberURIList = append(memberURIList, member.Value.(string)) - } - } - - memberURIList = append(memberURIList, c.getPrinterUri(printer)) - - req := NewRequest(OperationCupsAddModifyClass, 1) - req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class) - req.PrinterAttributes[AttributeMemberURIs] = memberURIList - - _, err = c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// DeletePrinterFromClass removes a printer from a class, if a class has no more printer it will be deleted -func (c *CUPSClient) DeletePrinterFromClass(class, printer string) error { - attributes, err := c.GetPrinterAttributes(class, []string{AttributeMemberURIs}) - if err != nil { - return err - } - - memberURIList := make([]string, 0) - - for _, member := range attributes[AttributeMemberURIs] { - memberString := strings.Split(member.Value.(string), "/") - printerName := memberString[len(memberString)-1] - - if printerName != printer { - memberURIList = append(memberURIList, member.Value.(string)) - } - } - - if len(memberURIList) == 0 { - return c.DeleteClass(class) - } - - req := NewRequest(OperationCupsAddModifyClass, 1) - req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class) - req.PrinterAttributes[AttributeMemberURIs] = memberURIList - - _, err = c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// DeleteClass deletes a class -func (c *CUPSClient) DeleteClass(class string) error { - req := NewRequest(OperationCupsDeleteClass, 1) - req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// CreatePrinter creates a new printer -func (c *CUPSClient) CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy string, information, location string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(name) - req.OperationAttributes[AttributePPDName] = ppd - req.OperationAttributes[AttributePrinterIsShared] = shared - req.PrinterAttributes[AttributePrinterStateReasons] = "none" - req.PrinterAttributes[AttributeDeviceURI] = deviceURI - req.PrinterAttributes[AttributePrinterInfo] = information - req.PrinterAttributes[AttributePrinterLocation] = location - req.PrinterAttributes[AttributePrinterErrorPolicy] = errorPolicy - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterPPD sets the ppd for a printer -func (c *CUPSClient) SetPrinterPPD(printer, ppd string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.OperationAttributes[AttributePPDName] = ppd - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterDeviceURI sets the device uri for a printer -func (c *CUPSClient) SetPrinterDeviceURI(printer, deviceURI string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.PrinterAttributes[AttributeDeviceURI] = deviceURI - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterIsShared shares or unshares a printer in the network -func (c *CUPSClient) SetPrinterIsShared(printer string, shared bool) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.OperationAttributes[AttributePrinterIsShared] = shared - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterErrorPolicy sets the error policy for a printer -func (c *CUPSClient) SetPrinterErrorPolicy(printer string, errorPolicy string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.PrinterAttributes[AttributePrinterErrorPolicy] = errorPolicy - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterInformation sets general printer information -func (c *CUPSClient) SetPrinterInformation(printer, information string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.PrinterAttributes[AttributePrinterInfo] = information - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// SetPrinterLocation sets the printer location -func (c *CUPSClient) SetPrinterLocation(printer, location string) error { - req := NewRequest(OperationCupsAddModifyPrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.PrinterAttributes[AttributePrinterLocation] = location - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// DeletePrinter deletes a printer -func (c *CUPSClient) DeletePrinter(printer string) error { - req := NewRequest(OperationCupsDeletePrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// GetPrinters returns a map of printer names and attributes -func (c *CUPSClient) GetPrinters(attributes []string) (map[string]Attributes, error) { - req := NewRequest(OperationCupsGetPrinters, 1) - - if attributes == nil { - req.OperationAttributes[AttributeRequestedAttributes] = DefaultPrinterAttributes - } else { - req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributePrinterName) - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil) - if err != nil { - return nil, err - } - - printerNameMap := make(map[string]Attributes) - - for _, printerAttributes := range resp.PrinterAttributes { - printerNameMap[printerAttributes[AttributePrinterName][0].Value.(string)] = printerAttributes - } - - return printerNameMap, nil -} - -// GetClasses returns a map of class names and attributes -func (c *CUPSClient) GetClasses(attributes []string) (map[string]Attributes, error) { - req := NewRequest(OperationCupsGetClasses, 1) - - if attributes == nil { - req.OperationAttributes[AttributeRequestedAttributes] = DefaultClassAttributes - } else { - req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributePrinterName) - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil) - if err != nil { - return nil, err - } - - printerNameMap := make(map[string]Attributes) - - for _, printerAttributes := range resp.PrinterAttributes { - printerNameMap[printerAttributes[AttributePrinterName][0].Value.(string)] = printerAttributes - } - - return printerNameMap, nil -} - -// PrintTestPage prints a test page using the provided PDF data -func (c *CUPSClient) PrintTestPage(printer string, testPageData io.Reader, size int) (int, error) { - return c.PrintJob(Document{ - Document: testPageData, - Name: "Test Page", - Size: size, - MimeType: MimeTypePDF, - }, printer, map[string]any{ - AttributeJobName: "Test Page", - }) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/error.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/error.go deleted file mode 100644 index e4edf5e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/error.go +++ /dev/null @@ -1,31 +0,0 @@ -package ipp - -import "fmt" - -// IsNotExistsError checks a given error whether a printer or class does not exist -func IsNotExistsError(err error) bool { - if err == nil { - return false - } - - return err.Error() == "The printer or class does not exist." -} - -// IPPError used for non ok ipp status codes -type IPPError struct { - Status int16 - Message string -} - -func (e IPPError) Error() string { - return fmt.Sprintf("ipp status: %d, message: %s", e.Status, e.Message) -} - -// HTTPError used for non 200 http codes -type HTTPError struct { - Code int -} - -func (e HTTPError) Error() string { - return fmt.Sprintf("got http code %d", e.Code) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/ipp-client.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/ipp-client.go deleted file mode 100644 index a21dd54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/ipp-client.go +++ /dev/null @@ -1,329 +0,0 @@ -package ipp - -import ( - "errors" - "fmt" - "io" - "os" - "path" -) - -// Document wraps an io.Reader with more information, needed for encoding -type Document struct { - Document io.Reader - Size int - Name string - MimeType string -} - -// IPPClient implements a generic ipp client -type IPPClient struct { - username string - adapter Adapter -} - -// NewIPPClient creates a new generic ipp client (used HttpAdapter internally) -func NewIPPClient(host string, port int, username, password string, useTLS bool) *IPPClient { - adapter := NewHttpAdapter(host, port, username, password, useTLS) - - return &IPPClient{ - username: username, - adapter: adapter, - } -} - -// NewIPPClientWithAdapter creates a new generic ipp client with given Adapter -func NewIPPClientWithAdapter(username string, adapter Adapter) *IPPClient { - return &IPPClient{ - username: username, - adapter: adapter, - } -} - -func (c *IPPClient) getPrinterUri(printer string) string { - return fmt.Sprintf("ipp://localhost/printers/%s", printer) -} - -func (c *IPPClient) getJobUri(jobID int) string { - return fmt.Sprintf("ipp://localhost/jobs/%d", jobID) -} - -func (c *IPPClient) getClassUri(printer string) string { - return fmt.Sprintf("ipp://localhost/classes/%s", printer) -} - -// SendRequest sends a request to a remote uri end returns the response -func (c *IPPClient) SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) { - if _, ok := req.OperationAttributes[AttributeRequestingUserName]; !ok { - req.OperationAttributes[AttributeRequestingUserName] = c.username - } - - return c.adapter.SendRequest(url, req, additionalResponseData) -} - -// PrintDocuments prints one or more documents using a Create-Job operation followed by one or more Send-Document operation(s). custom job settings can be specified via the jobAttributes parameter -func (c *IPPClient) PrintDocuments(docs []Document, printer string, jobAttributes map[string]any) (int, error) { - printerURI := c.getPrinterUri(printer) - - req := NewRequest(OperationCreateJob, 1) - req.OperationAttributes[AttributePrinterURI] = printerURI - req.OperationAttributes[AttributeRequestingUserName] = c.username - - // set defaults for some attributes, may get overwritten - req.OperationAttributes[AttributeJobName] = docs[0].Name - req.OperationAttributes[AttributeCopies] = 1 - req.OperationAttributes[AttributeJobPriority] = DefaultJobPriority - - for key, value := range jobAttributes { - req.JobAttributes[key] = value - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil) - if err != nil { - return -1, err - } - - if len(resp.JobAttributes) == 0 { - return 0, errors.New("server doesn't returned a job id") - } - - jobID := resp.JobAttributes[0][AttributeJobID][0].Value.(int) - - documentCount := len(docs) - 1 - - for docID, doc := range docs { - req = NewRequest(OperationSendDocument, 2) - req.OperationAttributes[AttributePrinterURI] = printerURI - req.OperationAttributes[AttributeRequestingUserName] = c.username - req.OperationAttributes[AttributeJobID] = jobID - req.OperationAttributes[AttributeDocumentName] = doc.Name - req.OperationAttributes[AttributeDocumentFormat] = doc.MimeType - req.OperationAttributes[AttributeLastDocument] = docID == documentCount - req.File = doc.Document - req.FileSize = doc.Size - - _, err = c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil) - if err != nil { - return -1, err - } - } - - return jobID, nil -} - -// PrintJob prints a document using a Print-Job operation. custom job settings can be specified via the jobAttributes parameter -func (c *IPPClient) PrintJob(doc Document, printer string, jobAttributes map[string]any) (int, error) { - printerURI := c.getPrinterUri(printer) - - req := NewRequest(OperationPrintJob, 1) - req.OperationAttributes[AttributePrinterURI] = printerURI - req.OperationAttributes[AttributeRequestingUserName] = c.username - req.OperationAttributes[AttributeJobName] = doc.Name - req.OperationAttributes[AttributeDocumentFormat] = doc.MimeType - - // set defaults for some attributes, may get overwritten - req.OperationAttributes[AttributeCopies] = 1 - req.OperationAttributes[AttributeJobPriority] = DefaultJobPriority - - for key, value := range jobAttributes { - req.JobAttributes[key] = value - } - - req.File = doc.Document - req.FileSize = doc.Size - - resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil) - if err != nil { - return -1, err - } - - if len(resp.JobAttributes) == 0 { - return 0, errors.New("server doesn't returned a job id") - } - - jobID := resp.JobAttributes[0][AttributeJobID][0].Value.(int) - - return jobID, nil -} - -// PrintFile prints a local file on the file system. custom job settings can be specified via the jobAttributes parameter -func (c *IPPClient) PrintFile(filePath, printer string, jobAttributes map[string]any) (int, error) { - fileStats, err := os.Stat(filePath) - if os.IsNotExist(err) { - return -1, err - } - - fileName := path.Base(filePath) - - document, err := os.Open(filePath) - if err != nil { - return 0, err - } - defer document.Close() - - jobAttributes[AttributeJobName] = fileName - - return c.PrintDocuments([]Document{ - { - Document: document, - Name: fileName, - Size: int(fileStats.Size()), - MimeType: MimeTypeOctetStream, - }, - }, printer, jobAttributes) -} - -// GetPrinterAttributes returns the requested attributes for the specified printer, if attributes is nil the default attributes will be used -func (c *IPPClient) GetPrinterAttributes(printer string, attributes []string) (Attributes, error) { - req := NewRequest(OperationGetPrinterAttributes, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.OperationAttributes[AttributeRequestingUserName] = c.username - - if attributes == nil { - req.OperationAttributes[AttributeRequestedAttributes] = DefaultPrinterAttributes - } else { - req.OperationAttributes[AttributeRequestedAttributes] = attributes - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil) - if err != nil { - return nil, err - } - - if len(resp.PrinterAttributes) == 0 { - return nil, errors.New("server doesn't return any printer attributes") - } - - return resp.PrinterAttributes[0], nil -} - -// ResumePrinter resumes a printer -func (c *IPPClient) ResumePrinter(printer string) error { - req := NewRequest(OperationResumePrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// PausePrinter pauses a printer -func (c *IPPClient) PausePrinter(printer string) error { - req := NewRequest(OperationPausePrinter, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// GetJobAttributes returns the requested attributes for the specified job, if attributes is nil the default job will be used -func (c *IPPClient) GetJobAttributes(jobID int, attributes []string) (Attributes, error) { - req := NewRequest(OperationGetJobAttributes, 1) - req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID) - - if attributes == nil { - req.OperationAttributes[AttributeRequestedAttributes] = DefaultJobAttributes - } else { - req.OperationAttributes[AttributeRequestedAttributes] = attributes - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("jobs", jobID), req, nil) - if err != nil { - return nil, err - } - - if len(resp.JobAttributes) == 0 { - return nil, errors.New("server doesn't return any job attributes") - } - - return resp.JobAttributes[0], nil -} - -// GetJobs returns jobs from a printer or class -func (c *IPPClient) GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]Attributes, error) { - req := NewRequest(OperationGetJobs, 1) - req.OperationAttributes[AttributeWhichJobs] = whichJobs - req.OperationAttributes[AttributeMyJobs] = myJobs - - if printer != "" { - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - } else if class != "" { - req.OperationAttributes[AttributePrinterURI] = c.getClassUri(printer) - } else { - req.OperationAttributes[AttributePrinterURI] = "ipp://localhost/" - } - - if firstJobId > 0 { - req.OperationAttributes[AttributeFirstJobID] = firstJobId - } - - if limit > 0 { - req.OperationAttributes[AttributeLimit] = limit - } - - if myJobs { - req.OperationAttributes[AttributeRequestingUserName] = c.username - } - - if attributes == nil { - req.OperationAttributes[AttributeRequestedAttributes] = DefaultJobAttributes - } else { - req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributeJobID) - } - - resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil) - if err != nil { - return nil, err - } - - jobIDMap := make(map[int]Attributes) - - for _, jobAttributes := range resp.JobAttributes { - jobIDMap[jobAttributes[AttributeJobID][0].Value.(int)] = jobAttributes - } - - return jobIDMap, nil -} - -// CancelJob cancels a job. if purge is true, the job will also be removed -func (c *IPPClient) CancelJob(jobID int, purge bool) error { - req := NewRequest(OperationCancelJob, 1) - req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID) - req.OperationAttributes[AttributePurgeJobs] = purge - - _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil) - return err -} - -// CancelAllJob cancels all jobs for a specified printer. if purge is true, the jobs will also be removed -func (c *IPPClient) CancelAllJob(printer string, purge bool) error { - req := NewRequest(OperationCancelJobs, 1) - req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer) - req.OperationAttributes[AttributePurgeJobs] = purge - - _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil) - return err -} - -// RestartJob restarts a job -func (c *IPPClient) RestartJob(jobID int) error { - req := NewRequest(OperationRestartJob, 1) - req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID) - - _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil) - return err -} - -// HoldJobUntil holds a job -func (c *IPPClient) HoldJobUntil(jobID int, holdUntil string) error { - req := NewRequest(OperationRestartJob, 1) - req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID) - req.JobAttributes[AttributeHoldJobUntil] = holdUntil - - _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil) - return err -} - -// TestConnection tests if a tcp connection to the remote server is possible -func (c *IPPClient) TestConnection() error { - return c.adapter.TestConnection() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/request.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/request.go deleted file mode 100644 index 3207038..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/request.go +++ /dev/null @@ -1,299 +0,0 @@ -package ipp - -import ( - "bytes" - "encoding/binary" - "io" -) - -// Request defines a ipp request -type Request struct { - ProtocolVersionMajor int8 - ProtocolVersionMinor int8 - - Operation int16 - RequestId int32 - - OperationAttributes map[string]any - JobAttributes map[string]any - PrinterAttributes map[string]any - SubscriptionAttributes map[string]any // Added for subscription operations - - File io.Reader - FileSize int -} - -// NewRequest creates a new ipp request -func NewRequest(op int16, reqID int32) *Request { - return &Request{ - ProtocolVersionMajor: ProtocolVersionMajor, - ProtocolVersionMinor: ProtocolVersionMinor, - Operation: op, - RequestId: reqID, - OperationAttributes: make(map[string]any), - JobAttributes: make(map[string]any), - PrinterAttributes: make(map[string]any), - SubscriptionAttributes: make(map[string]any), - File: nil, - FileSize: -1, - } -} - -// Encode encodes the request to a byte slice -func (r *Request) Encode() ([]byte, error) { - buf := new(bytes.Buffer) - enc := NewAttributeEncoder(buf) - - if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMajor); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMinor); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.Operation); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.RequestId); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, TagOperation); err != nil { - return nil, err - } - - if r.OperationAttributes == nil { - r.OperationAttributes = make(map[string]any, 2) - } - - if _, found := r.OperationAttributes[AttributeCharset]; !found { - r.OperationAttributes[AttributeCharset] = Charset - } - - if _, found := r.OperationAttributes[AttributeNaturalLanguage]; !found { - r.OperationAttributes[AttributeNaturalLanguage] = CharsetLanguage - } - - if err := r.encodeOperationAttributes(enc); err != nil { - return nil, err - } - - if len(r.JobAttributes) > 0 { - if err := binary.Write(buf, binary.BigEndian, TagJob); err != nil { - return nil, err - } - for attr, value := range r.JobAttributes { - if err := enc.Encode(attr, value); err != nil { - return nil, err - } - } - } - - if len(r.PrinterAttributes) > 0 { - if err := binary.Write(buf, binary.BigEndian, TagPrinter); err != nil { - return nil, err - } - for attr, value := range r.PrinterAttributes { - if err := enc.Encode(attr, value); err != nil { - return nil, err - } - } - } - - if len(r.SubscriptionAttributes) > 0 { - if err := binary.Write(buf, binary.BigEndian, TagSubscription); err != nil { - return nil, err - } - if err := r.encodeSubscriptionAttributes(enc); err != nil { - return nil, err - } - } - - if err := binary.Write(buf, binary.BigEndian, TagEnd); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -func (r *Request) encodeOperationAttributes(enc *AttributeEncoder) error { - ordered := []string{ - AttributeCharset, - AttributeNaturalLanguage, - AttributePrinterURI, - AttributeJobID, - } - - for _, attr := range ordered { - if value, ok := r.OperationAttributes[attr]; ok { - delete(r.OperationAttributes, attr) - if err := enc.Encode(attr, value); err != nil { - return err - } - } - } - - for attr, value := range r.OperationAttributes { - if err := enc.Encode(attr, value); err != nil { - return err - } - } - - return nil -} - -func (r *Request) encodeSubscriptionAttributes(enc *AttributeEncoder) error { - // Encode subscription attributes in proper order - // notify-pull-method and notify-lease-duration must come before notify-events - ordered := []string{ - "notify-pull-method", - "notify-lease-duration", - "notify-events", - } - - for _, attr := range ordered { - if value, ok := r.SubscriptionAttributes[attr]; ok { - delete(r.SubscriptionAttributes, attr) - if err := enc.Encode(attr, value); err != nil { - return err - } - } - } - - // Encode any remaining subscription attributes - for attr, value := range r.SubscriptionAttributes { - if err := enc.Encode(attr, value); err != nil { - return err - } - } - - return nil -} - -// RequestDecoder reads and decodes a request from a stream -type RequestDecoder struct { - reader io.Reader -} - -// NewRequestDecoder returns a new decoder that reads from r -func NewRequestDecoder(r io.Reader) *RequestDecoder { - return &RequestDecoder{ - reader: r, - } -} - -// Decode decodes a ipp request into a request struct. additional data will be written to an io.Writer if data is not nil -func (d *RequestDecoder) Decode(data io.Writer) (*Request, error) { - req := new(Request) - - if err := binary.Read(d.reader, binary.BigEndian, &req.ProtocolVersionMajor); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &req.ProtocolVersionMinor); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &req.Operation); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &req.RequestId); err != nil { - return nil, err - } - - startByteSlice := make([]byte, 1) - - tag := TagCupsInvalid - previousAttributeName := "" - tagSet := false - - attribDecoder := NewAttributeDecoder(d.reader) - - // decode attribute buffer - for { - if _, err := d.reader.Read(startByteSlice); err != nil { - // when we read from a stream, we may get an EOF if we want to read the end tag - // all data should be read and we can ignore the error - if err == io.EOF { - break - } - return nil, err - } - - startByte := int8(startByteSlice[0]) - - // check if attributes are completed - if startByte == TagEnd { - break - } - - if startByte == TagOperation { - if req.OperationAttributes == nil { - req.OperationAttributes = make(map[string]any) - } - - tag = TagOperation - tagSet = true - - } - - if startByte == TagJob { - if req.JobAttributes == nil { - req.JobAttributes = make(map[string]any) - } - tag = TagJob - tagSet = true - } - - if startByte == TagPrinter { - if req.PrinterAttributes == nil { - req.PrinterAttributes = make(map[string]any) - } - tag = TagPrinter - tagSet = true - } - - if tagSet { - if _, err := d.reader.Read(startByteSlice); err != nil { - return nil, err - } - startByte = int8(startByteSlice[0]) - } - - attrib, err := attribDecoder.Decode(startByte) - if err != nil { - return nil, err - } - - if attrib.Name != "" { - appendAttributeToRequest(req, tag, attrib.Name, attrib.Value) - previousAttributeName = attrib.Name - } else { - appendAttributeToRequest(req, tag, previousAttributeName, attrib.Value) - } - - tagSet = false - } - - if data != nil { - if _, err := io.Copy(data, d.reader); err != nil { - return nil, err - } - } - - return req, nil -} - -func appendAttributeToRequest(req *Request, tag int8, name string, value any) { - switch tag { - case TagOperation: - req.OperationAttributes[name] = value - case TagPrinter: - req.PrinterAttributes[name] = value - case TagJob: - req.JobAttributes[name] = value - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/response.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/response.go deleted file mode 100644 index e7cbd75..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/response.go +++ /dev/null @@ -1,383 +0,0 @@ -package ipp - -import ( - "bytes" - "encoding/binary" - "io" -) - -// Attributes is a wrapper for a set of attributes -type Attributes map[string][]Attribute - -// Response defines a ipp response -type Response struct { - ProtocolVersionMajor int8 - ProtocolVersionMinor int8 - - StatusCode int16 - RequestId int32 - - OperationAttributes Attributes - PrinterAttributes []Attributes - JobAttributes []Attributes - SubscriptionAttributes []Attributes // Added for subscription responses -} - -// CheckForErrors checks the status code and returns a error if it is not zero. it also returns the status message if provided by the server -func (r *Response) CheckForErrors() error { - if r.StatusCode != StatusOk { - err := IPPError{ - Status: r.StatusCode, - Message: "no status message returned", - } - - if len(r.OperationAttributes["status-message"]) > 0 { - err.Message = r.OperationAttributes["status-message"][0].Value.(string) - } - - return err - } - - return nil -} - -// NewResponse creates a new ipp response -func NewResponse(statusCode int16, reqID int32) *Response { - return &Response{ - ProtocolVersionMajor: ProtocolVersionMajor, - ProtocolVersionMinor: ProtocolVersionMinor, - StatusCode: statusCode, - RequestId: reqID, - OperationAttributes: make(Attributes), - PrinterAttributes: make([]Attributes, 0), - JobAttributes: make([]Attributes, 0), - } -} - -// Encode encodes the response to a byte slice -func (r *Response) Encode() ([]byte, error) { - buf := new(bytes.Buffer) - enc := NewAttributeEncoder(buf) - - if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMajor); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMinor); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.StatusCode); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, r.RequestId); err != nil { - return nil, err - } - - if err := binary.Write(buf, binary.BigEndian, TagOperation); err != nil { - return nil, err - } - - if r.OperationAttributes == nil { - r.OperationAttributes = make(Attributes, 0) - } - - if _, found := r.OperationAttributes[AttributeCharset]; !found { - r.OperationAttributes[AttributeCharset] = []Attribute{ - { - Value: Charset, - }, - } - } - - if _, found := r.OperationAttributes[AttributeNaturalLanguage]; !found { - r.OperationAttributes[AttributeNaturalLanguage] = []Attribute{ - { - Value: CharsetLanguage, - }, - } - } - - if err := r.encodeOperationAttributes(enc); err != nil { - return nil, err - } - - if len(r.PrinterAttributes) > 0 { - for _, printerAttr := range r.PrinterAttributes { - if err := binary.Write(buf, binary.BigEndian, TagPrinter); err != nil { - return nil, err - } - - for name, attr := range printerAttr { - if len(attr) == 0 { - continue - } - - values := make([]any, len(attr)) - for i, v := range attr { - values[i] = v.Value - } - - if len(values) == 1 { - if err := enc.Encode(name, values[0]); err != nil { - return nil, err - } - } else { - if err := enc.Encode(name, values); err != nil { - return nil, err - } - } - } - } - } - - if len(r.JobAttributes) > 0 { - for _, jobAttr := range r.JobAttributes { - if err := binary.Write(buf, binary.BigEndian, TagJob); err != nil { - return nil, err - } - - for name, attr := range jobAttr { - if len(attr) == 0 { - continue - } - - values := make([]any, len(attr)) - for i, v := range attr { - values[i] = v.Value - } - - if len(values) == 1 { - if err := enc.Encode(name, values[0]); err != nil { - return nil, err - } - } else { - if err := enc.Encode(name, values); err != nil { - return nil, err - } - } - } - } - } - - if err := binary.Write(buf, binary.BigEndian, TagEnd); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -func (r *Response) encodeOperationAttributes(enc *AttributeEncoder) error { - ordered := []string{ - AttributeCharset, - AttributeNaturalLanguage, - AttributePrinterURI, - AttributeJobID, - } - - for _, name := range ordered { - if attr, ok := r.OperationAttributes[name]; ok { - delete(r.OperationAttributes, name) - if err := encodeOperationAttribute(enc, name, attr); err != nil { - return err - } - } - } - - for name, attr := range r.OperationAttributes { - if err := encodeOperationAttribute(enc, name, attr); err != nil { - return err - } - } - - return nil -} - -func encodeOperationAttribute(enc *AttributeEncoder, name string, attr []Attribute) error { - if len(attr) == 0 { - return nil - } - - values := make([]any, len(attr)) - for i, v := range attr { - values[i] = v.Value - } - - if len(values) == 1 { - return enc.Encode(name, values[0]) - } - - return enc.Encode(name, values) -} - -// ResponseDecoder reads and decodes a response from a stream -type ResponseDecoder struct { - reader io.Reader -} - -// NewResponseDecoder returns a new decoder that reads from r -func NewResponseDecoder(r io.Reader) *ResponseDecoder { - return &ResponseDecoder{ - reader: r, - } -} - -// Decode decodes a ipp response into a response struct. additional data will be written to an io.Writer if data is not nil -func (d *ResponseDecoder) Decode(data io.Writer) (*Response, error) { - /* - 1 byte: Protocol Major Version - b - 1 byte: Protocol Minor Version - b - 2 byte: Status ID - h - 4 byte: Request ID - i - 1 byte: Operation Attribute Byte (\0x01) - N times: Attributes - 1 byte: Attribute End Byte (\0x03) - */ - - resp := new(Response) - - // wrap the reader so we have more functionality - // reader := bufio.NewReader(d.reader) - - if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMajor); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMinor); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &resp.StatusCode); err != nil { - return nil, err - } - - if err := binary.Read(d.reader, binary.BigEndian, &resp.RequestId); err != nil { - return nil, err - } - - startByteSlice := make([]byte, 1) - - tag := TagCupsInvalid - previousAttributeName := "" - tempAttributes := make(Attributes) - tagSet := false - - attribDecoder := NewAttributeDecoder(d.reader) - - // decode attribute buffer - for { - if _, err := d.reader.Read(startByteSlice); err != nil { - // when we read from a stream, we may get an EOF if we want to read the end tag - // all data should be read and we can ignore the error - if err == io.EOF { - break - } - return nil, err - } - - startByte := int8(startByteSlice[0]) - - // check if attributes are completed - if startByte == TagEnd { - break - } - - if startByte == TagOperation { - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - tempAttributes = make(Attributes) - } - - tag = TagOperation - tagSet = true - } - - if startByte == TagJob { - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - tempAttributes = make(Attributes) - } - - tag = TagJob - tagSet = true - } - - if startByte == TagPrinter { - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - tempAttributes = make(Attributes) - } - - tag = TagPrinter - tagSet = true - } - - if startByte == TagSubscription { - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - tempAttributes = make(Attributes) - } - - tag = TagSubscription - tagSet = true - } - - if startByte == TagEventNotification { - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - tempAttributes = make(Attributes) - } - - tag = TagEventNotification - tagSet = true - } - - if tagSet { - if _, err := d.reader.Read(startByteSlice); err != nil { - return nil, err - } - startByte = int8(startByteSlice[0]) - } - - attrib, err := attribDecoder.Decode(startByte) - if err != nil { - return nil, err - } - - if attrib.Name != "" { - tempAttributes[attrib.Name] = append(tempAttributes[attrib.Name], *attrib) - previousAttributeName = attrib.Name - } else { - tempAttributes[previousAttributeName] = append(tempAttributes[previousAttributeName], *attrib) - } - - tagSet = false - } - - if len(tempAttributes) > 0 && tag != TagCupsInvalid { - appendAttributeToResponse(resp, tag, tempAttributes) - } - - if data != nil { - if _, err := io.Copy(data, d.reader); err != nil { - return nil, err - } - } - - return resp, nil -} - -func appendAttributeToResponse(resp *Response, tag int8, attr map[string][]Attribute) { - switch tag { - case TagOperation: - resp.OperationAttributes = attr - case TagPrinter: - resp.PrinterAttributes = append(resp.PrinterAttributes, attr) - case TagJob: - resp.JobAttributes = append(resp.JobAttributes, attr) - case TagSubscription, TagEventNotification: - // Both subscription and event notification attributes go to SubscriptionAttributes - resp.SubscriptionAttributes = append(resp.SubscriptionAttributes, attr) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/utils.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/utils.go deleted file mode 100644 index 62689a3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/ipp/utils.go +++ /dev/null @@ -1,28 +0,0 @@ -package ipp - -import ( - "fmt" - "os" - "path" -) - -// ParseControlFile reads and decodes a cups control file into a response -func ParseControlFile(jobID int, spoolDirectory string) (*Response, error) { - if spoolDirectory == "" { - spoolDirectory = "/var/spool/cups" - } - - controlFilePath := path.Join(spoolDirectory, fmt.Sprintf("c%d", jobID)) - - if _, err := os.Stat(controlFilePath); err != nil { - return nil, err - } - - controlFile, err := os.Open(controlFilePath) - if err != nil { - return nil, err - } - defer controlFile.Close() - - return NewResponseDecoder(controlFile).Decode(nil) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/LICENSE deleted file mode 100644 index edba275..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2009 The Go Authors. -Copyright 2024 Zachary Olstein. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google LLC nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/syncmap.go b/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/syncmap.go deleted file mode 100644 index 27d9458..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/core/pkg/syncmap/syncmap.go +++ /dev/null @@ -1,537 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syncmap - -import ( - "sync" - "sync/atomic" - "unsafe" -) - -// Map is like a Go map[K]V but is safe for concurrent use -// by multiple goroutines without additional locking or coordination. -// Loads, stores, and deletes run in amortized constant time. -// -// The Map type is specialized. Most code should use a plain Go map instead, -// with separate locking or coordination, for better type safety and to make it -// easier to maintain other invariants along with the map content. -// -// The Map type is optimized for two common use cases: (1) when the entry for a given -// key is only ever written once but read many times, as in caches that only grow, -// or (2) when multiple goroutines read, write, and overwrite entries for disjoint -// sets of keys. In these two cases, use of a Map may significantly reduce lock -// contention compared to a Go map paired with a separate [Mutex] or [RWMutex]. -// -// The zero Map is empty and ready for use. A Map must not be copied after first use. -// -// In the terminology of [the Go memory model], Map arranges that a write operation -// “synchronizes before” any read operation that observes the effect of the write, where -// read and write operations are defined as follows. -// [Map.Load], [Map.LoadAndDelete], [Map.LoadOrStore], and [Map.Swap] are read operations; -// [Map.Delete], [Map.LoadAndDelete], [Map.Store], and [Map.Swap] are write operations; -// [Map.LoadOrStore] is a write operation when it returns loaded set to false. -// -// [the Go memory model]: https://go.dev/ref/mem -type Map[K comparable, V any] struct { - mu sync.Mutex - - // read contains the portion of the map's contents that are safe for - // concurrent access (with or without mu held). - // - // The read field itself is always safe to load, but must only be stored with - // mu held. - // - // Entries stored in read may be updated concurrently without mu, but updating - // a previously-expunged entry requires that the entry be copied to the dirty - // map and unexpunged with mu held. - read atomic.Pointer[readOnly[K, V]] - - // dirty contains the portion of the map's contents that require mu to be - // held. To ensure that the dirty map can be promoted to the read map quickly, - // it also includes all of the non-expunged entries in the read map. - // - // Expunged entries are not stored in the dirty map. An expunged entry in the - // clean map must be unexpunged and added to the dirty map before a new value - // can be stored to it. - // - // If the dirty map is nil, the next write to the map will initialize it by - // making a shallow copy of the clean map, omitting stale entries. - dirty map[K]*entry[V] - - // misses counts the number of loads since the read map was last updated that - // needed to lock mu to determine whether the key was present. - // - // Once enough misses have occurred to cover the cost of copying the dirty - // map, the dirty map will be promoted to the read map (in the unamended - // state) and the next store to the map will make a new dirty copy. - misses int -} - -// readOnly is an immutable struct stored atomically in the Map.read field. -type readOnly[K comparable, V any] struct { - m map[K]*entry[V] - amended bool // true if the dirty map contains some key not in m. -} - -// expunged is an arbitrary pointer that marks entries which have been deleted -// from the dirty map. -// Because the same expunged pointer is used regardless of the Map's value type, -// value pointers read from the map must be compared against expunged BEFORE -// casting the pointer to *V. -var expunged = unsafe.Pointer(new(int)) - -// An entry is a slot in the map corresponding to a particular key. -type entry[V any] struct { - // p points to the value stored for the entry. - // - // If p == nil, the entry has been deleted, and either m.dirty == nil or - // m.dirty[key] is e. - // - // If p == expunged, the entry has been deleted, m.dirty != nil, and the entry - // is missing from m.dirty. - // - // Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty - // != nil, in m.dirty[key]. - // - // If p != expunged, it is always safe to cast it to (*V). - // - // An entry can be deleted by atomic replacement with nil: when m.dirty is - // next created, it will atomically replace nil with expunged and leave - // m.dirty[key] unset. - // - // An entry's associated value can be updated by atomic replacement, provided - // p != expunged. If p == expunged, an entry's associated value can be updated - // only after first setting m.dirty[key] = e so that lookups using the dirty - // map find the entry. - p unsafe.Pointer -} - -func newEntry[V any](i V) *entry[V] { - e := &entry[V]{} - atomic.StorePointer(&e.p, unsafe.Pointer(&i)) - return e -} - -func (m *Map[K, V]) loadReadOnly() readOnly[K, V] { - if p := m.read.Load(); p != nil { - return *p - } - return readOnly[K, V]{} -} - -// Load returns the value stored in the map for a key, or nil if no -// value is present. -// The ok result indicates whether value was found in the map. -func (m *Map[K, V]) Load(key K) (value V, ok bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - // Avoid reporting a spurious miss if m.dirty got promoted while we were - // blocked on m.mu. (If further loads of the same key will not miss, it's - // not worth copying the dirty map for this key.) - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - if !ok { - return value, false - } - return e.load() -} - -func (e *entry[V]) load() (value V, ok bool) { - p := atomic.LoadPointer(&e.p) - if p == nil || p == expunged { - return value, false - } - return *(*V)(p), true -} - -// Store sets the value for a key. -func (m *Map[K, V]) Store(key K, value V) { - _, _ = m.Swap(key, value) -} - -// unexpungeLocked ensures that the entry is not marked as expunged. -// -// If the entry was previously expunged, it must be added to the dirty map -// before m.mu is unlocked. -func (e *entry[V]) unexpungeLocked() (wasExpunged bool) { - return atomic.CompareAndSwapPointer(&e.p, expunged, nil) -} - -// swapLocked unconditionally swaps a value into the entry. -// -// The entry must be known not to be expunged. -func (e *entry[V]) swapLocked(i *V) *V { - return (*V)(atomic.SwapPointer(&e.p, unsafe.Pointer(i))) -} - -// LoadOrStore returns the existing value for the key if present. -// Otherwise, it stores and returns the given value. -// The loaded result is true if the value was loaded, false if stored. -func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { - // Avoid locking if it's a clean hit. - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - actual, loaded, ok := e.tryLoadOrStore(value) - if ok { - return actual, loaded - } - } - - m.mu.Lock() - read = m.loadReadOnly() - if e, ok := read.m[key]; ok { - if e.unexpungeLocked() { - m.dirty[key] = e - } - actual, loaded, _ = e.tryLoadOrStore(value) - } else if e, ok := m.dirty[key]; ok { - actual, loaded, _ = e.tryLoadOrStore(value) - m.missLocked() - } else { - if !read.amended { - // We're adding the first new key to the dirty map. - // Make sure it is allocated and mark the read-only map as incomplete. - m.dirtyLocked() - m.read.Store(&readOnly[K, V]{m: read.m, amended: true}) - } - m.dirty[key] = newEntry(value) - actual, loaded = value, false - } - m.mu.Unlock() - - return actual, loaded -} - -// tryLoadOrStore atomically loads or stores a value if the entry is not -// expunged. -// -// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and -// returns with ok==false. -func (e *entry[V]) tryLoadOrStore(i V) (actual V, loaded, ok bool) { - ptr := atomic.LoadPointer(&e.p) - if ptr == expunged { - return actual, false, false - } - p := (*V)(ptr) - if p != nil { - return *p, true, true - } - - // Copy the interface after the first load to make this method more amenable - // to escape analysis: if we hit the "load" path or the entry is expunged, we - // shouldn't bother heap-allocating. - ic := i - for { - if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) { - return i, false, true - } - ptr = atomic.LoadPointer(&e.p) - if ptr == expunged { - return actual, false, false - } - p = (*V)(ptr) - if p != nil { - return *p, true, true - } - } -} - -// LoadAndDelete deletes the value for a key, returning the previous value if any. -// The loaded result reports whether the key was present. -func (m *Map[K, V]) LoadAndDelete(key K) (value V, loaded bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - delete(m.dirty, key) - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - if ok { - return e.delete() - } - return value, false -} - -// Delete deletes the value for a key. -func (m *Map[K, V]) Delete(key K) { - m.LoadAndDelete(key) -} - -func (e *entry[V]) delete() (value V, ok bool) { - for { - p := atomic.LoadPointer(&e.p) - if p == nil || p == expunged { - return value, false - } - if atomic.CompareAndSwapPointer(&e.p, p, nil) { - return *(*V)(p), true - } - } -} - -// trySwap swaps a value if the entry has not been expunged. -// -// If the entry is expunged, trySwap returns false and leaves the entry -// unchanged. -func (e *entry[V]) trySwap(i *V) (*V, bool) { - for { - p := atomic.LoadPointer(&e.p) - if p == expunged { - return nil, false - } - if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { - return (*V)(p), true - } - } -} - -// Swap swaps the value for a key and returns the previous value if any. -// The loaded result reports whether the key was present. -func (m *Map[K, V]) Swap(key K, value V) (previous V, loaded bool) { - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - if v, ok := e.trySwap(&value); ok { - if v == nil { - return previous, false - } - return *v, true - } - } - - m.mu.Lock() - read = m.loadReadOnly() - if e, ok := read.m[key]; ok { - if e.unexpungeLocked() { - // The entry was previously expunged, which implies that there is a - // non-nil dirty map and this entry is not in it. - m.dirty[key] = e - } - if v := e.swapLocked(&value); v != nil { - loaded = true - previous = *v - } - } else if e, ok := m.dirty[key]; ok { - if v := e.swapLocked(&value); v != nil { - loaded = true - previous = *v - } - } else { - if !read.amended { - // We're adding the first new key to the dirty map. - // Make sure it is allocated and mark the read-only map as incomplete. - m.dirtyLocked() - m.read.Store(&readOnly[K, V]{m: read.m, amended: true}) - } - m.dirty[key] = newEntry(value) - } - m.mu.Unlock() - return previous, loaded -} - -// Range calls f sequentially for each key and value present in the map. -// If f returns false, range stops the iteration. -// -// Range does not necessarily correspond to any consistent snapshot of the Map's -// contents: no key will be visited more than once, but if the value for any key -// is stored or deleted concurrently (including by f), Range may reflect any -// mapping for that key from any point during the Range call. Range does not -// block other methods on the receiver; even f itself may call any method on m. -// -// Range may be O(N) with the number of elements in the map even if f returns -// false after a constant number of calls. -func (m *Map[K, V]) Range(f func(key K, value V) bool) { - // We need to be able to iterate over all of the keys that were already - // present at the start of the call to Range. - // If read.amended is false, then read.m satisfies that property without - // requiring us to hold m.mu for a long time. - read := m.loadReadOnly() - if read.amended { - // m.dirty contains keys not in read.m. Fortunately, Range is already O(N) - // (assuming the caller does not break out early), so a call to Range - // amortizes an entire copy of the map: we can promote the dirty copy - // immediately! - m.mu.Lock() - read = m.loadReadOnly() - if read.amended { - read = readOnly[K, V]{m: m.dirty} - copyRead := read - m.read.Store(©Read) - m.dirty = nil - m.misses = 0 - } - m.mu.Unlock() - } - - for k, e := range read.m { - v, ok := e.load() - if !ok { - continue - } - if !f(k, v) { - break - } - } -} - -// CompareAndSwap swaps the old and new values for key -// if the value stored in the map is equal to old. -// The old value must be of a comparable type. -func CompareAndSwap[K comparable, V comparable](m *Map[K, V], key K, old, new V) (swapped bool) { - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - return tryCompareAndSwap(e, old, new) - } else if !read.amended { - return false // No existing value for key. - } - - m.mu.Lock() - defer m.mu.Unlock() - read = m.loadReadOnly() - swapped = false - if e, ok := read.m[key]; ok { - swapped = tryCompareAndSwap(e, old, new) - } else if e, ok := m.dirty[key]; ok { - swapped = tryCompareAndSwap(e, old, new) - // We needed to lock mu in order to load the entry for key, - // and the operation didn't change the set of keys in the map - // (so it would be made more efficient by promoting the dirty - // map to read-only). - // Count it as a miss so that we will eventually switch to the - // more efficient steady state. - m.missLocked() - } - return swapped -} - -// CompareAndDelete deletes the entry for key if its value is equal to old. -// The old value must be of a comparable type. -// -// If there is no current value for key in the map, CompareAndDelete -// returns false (even if the old value is the zero value of V). -func CompareAndDelete[K comparable, V comparable](m *Map[K, V], key K, old V) (deleted bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - // Don't delete key from m.dirty: we still need to do the “compare” part - // of the operation. The entry will eventually be expunged when the - // dirty map is promoted to the read map. - // - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - for ok { - ptr := atomic.LoadPointer(&e.p) - if ptr == nil || ptr == expunged { - return false - } - p := (*V)(ptr) - if *p != old { - return false - } - if atomic.CompareAndSwapPointer(&e.p, ptr, nil) { - return true - } - } - return false -} - -// tryCompareAndSwap compare the entry with the given old value and swaps -// it with a new value if the entry is equal to the old value, and the entry -// has not been expunged. -// -// If the entry is expunged, tryCompareAndSwap returns false and leaves -// the entry unchanged. -func tryCompareAndSwap[V comparable](e *entry[V], old, new V) bool { - ptr := atomic.LoadPointer(&e.p) - if ptr == nil || ptr == expunged { - return false - } - p := (*V)(ptr) - if *p != old { - return false - } - - // Copy the interface after the first load to make this method more amenable - // to escape analysis: if the comparison fails from the start, we shouldn't - // bother heap-allocating an interface value to store. - nc := new - for { - if atomic.CompareAndSwapPointer(&e.p, ptr, unsafe.Pointer(&nc)) { - return true - } - ptr = atomic.LoadPointer(&e.p) - if ptr == nil || ptr == expunged { - return false - } - p = (*V)(ptr) - if *p != old { - return false - } - } -} - -func (m *Map[K, V]) missLocked() { - m.misses++ - if m.misses < len(m.dirty) { - return - } - m.read.Store(&readOnly[K, V]{m: m.dirty}) - m.dirty = nil - m.misses = 0 -} - -func (m *Map[K, V]) dirtyLocked() { - if m.dirty != nil { - return - } - - read := m.loadReadOnly() - m.dirty = make(map[K]*entry[V], len(read.m)) - for k, e := range read.m { - if !e.tryExpungeLocked() { - m.dirty[k] = e - } - } -} - -func (e *entry[V]) tryExpungeLocked() (isExpunged bool) { - p := atomic.LoadPointer(&e.p) - for p == nil { - if atomic.CompareAndSwapPointer(&e.p, nil, expunged) { - return true - } - p = atomic.LoadPointer(&e.p) - } - return p == expunged -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/AGENTS.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/AGENTS.md deleted file mode 100644 index 81e555a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/AGENTS.md +++ /dev/null @@ -1,1230 +0,0 @@ -# AGENTS.md - -This file provides guidance to AI coding assistants. - -## AI Guidance - -* After receiving tool results, carefully reflect on their quality and determine optimal next steps before proceeding. Use your thinking to plan and iterate based on this new information, and then take the best next action. -* For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. -* Before you finish, please verify your solution -* Do what has been asked; nothing more, nothing less. -* NEVER create files unless they're absolutely necessary for achieving your goal. -* ALWAYS prefer editing an existing file to creating a new one. -* NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User. -* When you update or modify core context files, also update markdown documentation and memory bank -* When asked to commit changes, exclude AGENTS.md and AGENTS-*.md referenced memory bank system files from any commits. - -## Memory Bank System - -This project uses a structured memory bank system with specialized context files. Always check these files for relevant information before starting work: - -### Core Context Files - -* **AGENTS-activeContext.md** - Current session state, goals, and progress (if exists) -* **AGENTS-patterns.md** - Established code patterns and conventions (if exists) -* **AGENTS-decisions.md** - Architecture decisions and rationale (if exists) -* **AGENTS-troubleshooting.md** - Common issues and proven solutions (if exists) -* **AGENTS-config-variables.md** - Configuration variables reference (if exists) -* **AGENTS-temp.md** - Temporary scratch pad (only read when referenced) - -**Important:** Always reference the active context file first to understand what's currently being worked on and maintain session continuity. - -### Memory Bank System Backups - -When asked to backup Memory Bank System files, you will copy the core context files above and @.agents settings directory to directory @/path/to/backup-directory. If files already exist in the backup directory, you will overwrite them. - -## Project Overview - -DankMaterialShell is a complete desktop environment for Wayland compositors, built as a **monorepo** with two main components: - -**1. Go Backend (core/)** - System integration, IPC server, and CLI tools (~118,000 lines) -**2. QML Frontend (quickshell/)** - UI layer consuming the backend's IPC API - -**Architecture**: The Go backend provides all system integration via IPC (Inter-Process Communication), while QML services act as thin wrappers that communicate with the backend. This separation allows for robust system integration while maintaining a reactive, modern UI. - -**Compositor Support**: Niri, Hyprland, MangoWC, Sway, labwc, Scroll (6 compositors supported) -**Distribution Support**: Arch, Fedora, Debian, Ubuntu, openSUSE, Gentoo (6 distributions supported) - -## Technology Stack - -### Backend (core/) -- **Go 1.24+** - System integration and backend services -- **Wayland Protocols** - Display management, screenshots, clipboard, workspaces -- **D-Bus** - Bluetooth, NetworkManager, systemd-logind, desktop portals -- **IPC Server** - Unix socket JSON API for QML ↔ Go communication -- **CLI Tools** - `dms` command with 20+ subcommands, `dankinstall` TUI installer - -### Frontend (quickshell/) -- **QML (Qt Modeling Language)** - UI components and visual presentation -- **Quickshell Framework** - QML-based desktop shell framework -- **Qt/QtQuick** - UI rendering and controls -- **Matugen** - Dynamic theming system for wallpaper-based colors - -## Development Commands - -### Backend (Go) - -```bash -cd core/ - -# Build -make # Build dms CLI (bin/dms) -make dankinstall # Build installer (bin/dankinstall) -make test # Run tests -make dist # Build distribution binaries (no update/greeter features) - -# Install -sudo make install # Install to /usr/local/bin/dms - -# Development -gofmt -w . # Format Go code -go mod tidy # Clean up dependencies -golangci-lint run # Run linter - -# Run dms CLI -./bin/dms run # Start shell via dms daemon -./bin/dms ipc # Send IPC command to running shell -./bin/dms --help # View all commands -``` - -### Frontend (QML) - -```bash -cd quickshell/ - -# Run the shell (requires dms backend running or use 'dms run') -quickshell -p shell.qml -qs -p . # Shorthand -qs -v -p shell.qml # Verbose debugging - -# Code formatting and linting -qmlfmt -t 4 -i 4 -b 250 -w /path/to/file.qml # Format QML (don't use qmlformat) -make -C .. lint-qml # From quickshell/, call the repo-root lint target; requires the generated .qmlls.ini VFS from `qs -p .` -./qmlformat-all.sh # Format all QML files -``` - -## Architecture Overview - -### Monorepo Structure - -The project is organized as a monorepo with clear separation between backend and frontend: - -``` -DankMaterialShell/ -├── core/ # Go backend (~118,000 lines) -│ ├── cmd/ # Binary entrypoints -│ │ ├── dms/ # Main CLI with 20+ commands -│ │ └── dankinstall/# TUI installer -│ ├── internal/ # System integration packages (23 packages) -│ │ ├── clipboard/ # Clipboard history (ext-data-control-v1) -│ │ ├── colorpicker/# Native Wayland color picker -│ │ ├── screenshot/ # Screen capture functionality -│ │ ├── brightness/ # DDC/CI & backlight control -│ │ ├── bluez/ # Bluetooth D-Bus integration -│ │ ├── config/ # Configuration management -│ │ ├── dank16/ # Terminal color scheme generator -│ │ ├── deps/ # Dependency detection -│ │ ├── distros/ # Distribution-specific installers (6 distros) -│ │ ├── greeter/ # Display manager greeter -│ │ ├── keybinds/ # Compositor keybind management -│ │ ├── matugen/ # Matugen integration -│ │ ├── notify/ # Notification daemon -│ │ ├── plugins/ # Plugin registry & management -│ │ ├── screenshot/ # Screenshot utilities -│ │ ├── server/ # IPC server with 15+ submodules -│ │ ├── themes/ # Theme registry -│ │ ├── wayland/ # Wayland protocol handlers -│ │ └── windowrules/# Window rules management -│ ├── pkg/ # Shared packages -│ │ ├── go-wayland/ # Wayland client library -│ │ ├── dbusutil/ # D-Bus utilities -│ │ ├── ipp/ # Internet Printing Protocol -│ │ └── syncmap/ # Thread-safe map -│ └── go.mod # Go module definition -├── quickshell/ # QML frontend (UI layer) - see "QML Frontend Architecture" below -│ ├── shell.qml # Main entry point -│ ├── Services/ # IPC client wrappers -│ ├── Modules/ # UI components -│ ├── Widgets/ # Reusable controls -│ ├── Modals/ # Full-screen overlays -│ └── Common/ # Shared resources -├── distro/ # Distribution packaging -│ ├── arch/ # AUR packages -│ ├── fedora/ # RPM specs -│ ├── debian/ # Debian packaging -│ ├── ubuntu/ # Ubuntu PPAs -│ ├── opensuse/ # OBS packaging -│ └── nix/ # NixOS modules -└── flake.nix # Nix flake -``` - -### Go Backend Architecture - -The backend provides all system integration through these key components: - -#### 1. IPC Server (`internal/server/`) - -JSON-based RPC over Unix socket (`/tmp/dms-ipc-.sock`) with 15+ submodules: - -- **apppicker/** - Application search and launch -- **bluez/** - Bluetooth device management -- **brightness/** - Display and monitor brightness -- **browser/** - Web browser integration -- **clipboard/** - Clipboard history and persistence -- **cups/** - Printer management -- **dbus/** - Generic D-Bus interface access -- **dwl/** - dwl/MangoWC compositor integration -- **evdev/** - Keyboard input device monitoring -- **extworkspace/** - Workspace protocol integration -- **freedesktop/** - Desktop portal integration -- **loginctl/** - systemd-logind (power, sessions, inhibitors) -- **network/** - Network management (multi-backend) -- **params/** - IPC parameter validation -- **plugins/** - Plugin lifecycle management -- **thememode/** - Dark/light mode synchronization -- **themes/** - Theme registry operations -- **wayland/** - Night mode, gamma control, output management -- **wlcontext/** - Wayland connection management -- **wlroutput/** - wlr-output-management protocol - -#### 2. CLI Commands (`cmd/dms/`) - -The `dms` CLI provides 20+ commands: - -```bash -dms run [-d] # Start shell (daemon mode) -dms restart / kill # Manage shell process -dms ipc [args] # Send IPC commands -dms brightness [list|set] # Display brightness control -dms color pick [--rgb|--hsv] # Native color picker -dms clipboard [list|clear] # Clipboard management -dms screenshot [area|output] # Take screenshots -dms notify send # Send notifications -dms dpms [on|off] # Display power management -dms keybinds [reload|list] # Keybind management -dms windowrules [add|remove] # Window rules management -dms matugen [generate|reload] # Theme generation -dms dank16 [generate] # Terminal theme generation -dms config [get|set] # Configuration management -dms features # Show available features -dms doctor # System diagnostics -dms plugins [browse|install] # Plugin management -dms update [check] # Update DMS and deps -dms greeter [install|enable] # Greeter management -``` - -#### 3. Wayland Integration (`internal/wayland/`, `internal/proto/`) - -Native Wayland protocol implementations (as client): - -- `wlr-gamma-control-unstable-v1` - Night mode color temperature -- `wlr-screencopy-unstable-v1` - Screenshots and color picker -- `wlr-layer-shell-unstable-v1` - Overlay surfaces -- `wlr-output-management-unstable-v1` - Display configuration -- `wlr-output-power-management-unstable-v1` - DPMS control -- `ext-data-control-v1` - Clipboard history -- `ext-workspace-v1` - Workspace integration -- `dwl-ipc-unstable-v2` - dwl/MangoWC IPC -- `keyboard-shortcuts-inhibit-unstable-v1` - Shortcut inhibition -- `wp-viewporter` - Fractional scaling support - -#### 4. D-Bus Integration (`internal/server/bluez/`, `internal/server/network/`, etc.) - -**Client interfaces** (consuming external services): -- `org.bluez` - Bluetooth with pairing agent -- `org.freedesktop.NetworkManager` - Network management -- `net.connman.iwd` - iwd Wi-Fi backend -- `org.freedesktop.network1` - systemd-networkd -- `org.freedesktop.login1` - Session control, inhibitors, brightness -- `org.freedesktop.Accounts` - User account info -- `org.freedesktop.portal.Desktop` - Desktop appearance settings -- CUPS via IPP - Printer management - -**Server interfaces** (implementing services): -- `org.freedesktop.ScreenSaver` - Screensaver inhibition for media playback - -#### 5. Distribution Support (`internal/distros/`) - -`dankinstall` TUI installer with full support for: - -- **Arch Linux** - pacman + AUR (yay/paru) -- **Fedora** - dnf + COPR -- **Debian** - apt + OBS repos -- **Ubuntu** - apt + PPAs -- **openSUSE** - zypper + OBS -- **Gentoo** - emerge + GURU overlay + USE flags - -Each distro has custom package mappings, dependency detection, and installation logic. - -### QML Frontend Architecture - -The frontend follows a clean modular architecture with shell.qml reduced to ~250 lines: - -``` -shell.qml # Main entry point (minimal orchestration) -├── Common/ # Shared resources (12 files) -│ ├── Theme.qml # Material Design 3 theme singleton -│ ├── SettingsData.qml # User preferences and configuration -│ ├── SessionData.qml # Session state management -│ ├── Colors.qml # Dynamic color scheme -│ └── [8 more utility files] -├── Services/ # System integration singletons (20 files) -│ ├── AudioService.qml -│ ├── NetworkService.qml -│ ├── BluetoothService.qml -│ ├── DisplayService.qml -│ ├── NotificationService.qml -│ ├── WeatherService.qml -│ ├── PluginService.qml -│ └── [14 more services] -├── Modules/ # UI components (93 files) -│ ├── TopBar/ # Panel components (13 files) -│ ├── ControlCenter/ # System controls (13 files) -│ ├── Notifications/ # Notification system (12 files) -│ ├── AppDrawer/ # Application launcher (3 files) -│ ├── Settings/ # Configuration interface (11 files) -│ ├── ProcessList/ # System monitoring (8 files) -│ ├── Dock/ # Application dock (6 files) -│ ├── Lock/ # Screen lock system (4 files) -│ └── [23 more module files] -├── Modals/ # Full-screen overlays (10 files) -│ ├── SettingsModal.qml -│ ├── ClipboardHistoryModal.qml -│ ├── ProcessListModal.qml -│ ├── PluginSettingsModal.qml -│ └── [7 more modals] -├── Widgets/ # Reusable UI controls (19 files) -│ ├── DankIcon.qml -│ ├── DankSlider.qml -│ ├── DankToggle.qml -│ ├── DankTabBar.qml -│ ├── DankGridView.qml -│ ├── DankListView.qml -│ └── [13 more widgets] -└── plugins/ # External plugins directory ($CONFIGPATH/DankMaterialShell/plugins/) - └── PluginName/ # Example Plugin structure - ├── plugin.json # Plugin manifest - ├── PluginNameWidget.qml # Widget component - └── PluginNameSettings.qml # Settings UI -``` - -### Component Organization - -1. **Shell Entry Point** (`shell.qml`) - - Minimal orchestration layer (~250 lines) - - Imports and instantiates components - - Handles global state and property bindings - - Multi-monitor support using Quickshell's `Variants` - -2. **Common/** - Shared resources - - `Theme.qml` - Material Design 3 theme singleton with consistent colors, spacing, fonts - - `Utilities.js` - Shared functions for workspace parsing, notifications, menu handling - -3. **Services/** - IPC client wrappers (20 singletons) - - **Pattern**: All services use `Singleton` type with `id: root` - - **Architecture**: Thin QML wrappers that communicate with Go backend via IPC - - **Examples**: AudioService, NetworkService, BluetoothService, DisplayService, WeatherService, NotificationService, CalendarService, BatteryService, NiriService, MprisController - - Services expose properties and functions that send IPC requests to the Go backend - - The Go backend handles all actual system integration (D-Bus, Wayland, hardware control) - - QML services receive IPC responses and update their properties for reactive UI binding - -4. **Modules/** - UI components (93 files) - - **TopBar/**: Panel components with workspace switching, system indicators, media controls - - **ControlCenter/**: System controls for WiFi, Bluetooth, audio, display settings - - **Notifications/**: Complete notification system with center, popups, and keyboard navigation - - **AppDrawer/**: Application launcher with grid/list views and category filtering - - **Settings/**: Comprehensive configuration interface with multiple tabs - - **ProcessList/**: System monitoring with process management and performance metrics - - **Dock/**: Application dock with running apps and window management - - **Lock/**: Screen lock system with authentication - -5. **Modals/** - Full-screen overlays (10 files) - - Modal system for settings, clipboard history, file browser, network info, power menu - - Unified modal management with consistent styling and keyboard navigation - -6. **Widgets/** - Reusable UI controls (19 files) - - **DankIcon**: Centralized icon component with Material Design font integration - - **DankSlider**: Enhanced slider with animations and smart detection - - **DankToggle**: Consistent toggle switch component - - **DankTabBar**: Unified tab bar implementation - - **DankGridView**: Reusable grid view with adaptive columns - - **DankListView**: Reusable list view with configurable styling - - **DankTextField**: Styled text input with validation - - **DankDropdown**: Dropdown selection component - - **DankPopout**: Base popout component for overlays - - **StateLayer**: Material Design 3 interaction states - - **StyledRect/StyledText**: Themed base components - - **CachingImage**: Optimized image loading with caching - - **DankLocationSearch**: Location picker with search - - **SystemLogo**: Animated system branding component - -7. **Plugins/** - External plugin system (`$CONFIGPATH/DankMaterialShell/plugins/`) - - **PluginService**: Discovers, loads, and manages plugin lifecycle - - **Dynamic Loading**: Plugins loaded at runtime from external directory - - **DankBar Integration**: Plugin widgets rendered alongside built-in widgets - - **Settings System**: Per-plugin settings with persistence - -### Key Architectural Patterns - -1. **Singleton Services Pattern**: - ```qml - import QtQuick - import Quickshell - import Quickshell.Io - pragma Singleton - pragma ComponentBehavior: Bound - - Singleton { - id: root - - property type value: defaultValue - - function performAction() { /* implementation */ } - } - ``` - -2. **Smart Feature Detection**: Services detect system capabilities: - ```qml - property bool featureAvailable: false - // Auto-hide UI elements when features unavailable - visible: ServiceName.featureAvailable - ``` - -3. **Property Bindings**: Reactive UI updates through property binding -4. **Material Design Theming**: Consistent use of Theme singleton throughout - -### Important Components - -- **ControlCenter**: System controls (WiFi, Bluetooth, brightness, volume, night mode) -- **AppLauncher**: Full-featured app grid/list with 93+ applications, search, categories -- **ClipboardHistoryModal**: Complete clipboard management with cliphist integration -- **TopBar**: Per-monitor panels with workspace switching, clock, system tray -- **System App Theming**: Automatic GTK and Qt application theming using matugen templates - -#### Key Widgets - -- **DankIcon**: Centralized icon component with automatic Material Design font detection -- **DankSlider**: Enhanced slider with animations and smart detection -- **DankToggle**: Consistent toggle switch component -- **DankTabBar**: Unified tab bar implementation -- **DankGridView**: Reusable grid view with adaptive columns -- **DankListView**: Reusable list view with configurable styling - -## Code Conventions - -### Internationalization (I18n) - -When adding user-facing strings, wrap them in `I18n.tr()` with context: - -```qml -import qs.Common - -Text { - text: I18n.tr("Hello World", "Hello world greeting that appears on the lock screen") -} -``` - -**Best practices:** -- Keep new terms to a minimum - reuse existing translations when possible -- Check `quickshell/translations/en.json` for existing terms -- Example: Use "Autoconnect" instead of "Auto-connect" if it's already translated -- Provide clear context for translators in the second parameter - -### QML Style Guidelines - -1. **Structure and Formatting**: - - Use 4-space indentation - - `id` should be the first property - - Properties before signal handlers before child components - - Prefer property bindings over imperative code - - **CRITICAL**: NEVER add comments unless absolutely essential for complex logic understanding. Code should be self-documenting through clear naming and structure. Comments are a code smell indicating unclear implementation. - - Use guard statements, example `if (abc) { something() return;} somethingElse();` - - Don't use crazy ternary stuff, but use it for simple if else only. `propertyVal: a ? b : c` - -2. **Naming Conventions**: - - **Services**: Use `Singleton` type with `id: root` - - **Components**: Use descriptive names (e.g., `DankSlider`, `TopBar`) - - **Properties**: camelCase for properties, PascalCase for types - -3. **Null-Safe Operations**: - - **Use** `object?.property` - -4. **Component Structure**: - ```qml - // For regular components - Item { - id: root - - property type name: value - - signal customSignal(type param) - - onSignal: { /* handler */ } - - Component { /* children */ } - } - - // For services (singletons) - Singleton { - id: root - - property bool featureAvailable: false - property type currentValue: defaultValue - - function performAction(param) { /* implementation */ } - } - ``` - -### Import Guidelines - -#### QML Import Order - -```qml -import QtQuick -import QtQuick.Controls // If needed -import Quickshell -import Quickshell.Widgets -import Quickshell.Io // For Process, FileView -import qs.Common // For Theme, utilities -import qs.Services // For service access -import qs.Widgets // For reusable widgets (DankIcon, etc.) -``` - -#### Go Import Order - -Follow standard Go conventions: - -```go -import ( - // Standard library - "context" - "fmt" - "os" - - // External dependencies - "github.com/godbus/dbus/v5" - "github.com/spf13/cobra" - - // Internal packages - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/utils" -) -``` - -**Service Dependencies:** -- QML Services should NOT import other QML services -- Modules and Widgets can import and use services via property bindings -- Use `Theme.propertyName` for consistent styling -- Use `DankIcon { name: "icon_name" }` for all icons instead of manual Text components - -### Go Backend Code Conventions - -#### 1. Package Structure - -- **cmd/** - Binary entrypoints only, minimal logic -- **internal/** - Implementation packages (not importable by external projects) -- **pkg/** - Shared packages (potentially importable) -- Each package should have a clear, single responsibility - -#### 2. Error Handling - -```go -// Always wrap errors with context -if err != nil { - return fmt.Errorf("failed to connect to D-Bus: %w", err) -} - -// Use custom error types for specific error handling -if errors.Is(err, errdefs.ErrNotFound) { - // Handle specific error -} -``` - -#### 3. IPC Handler Pattern - -All server modules should follow this pattern: - -```go -package mymodule - -import ( - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params" -) - -type Manager struct { - // State, connections, etc. -} - -func NewManager() (*Manager, error) { - // Initialize - return &Manager{}, nil -} - -func (m *Manager) HandleRequest(req models.Request) models.Response { - switch req.Method { - case "list": - return m.handleList(req) - case "action": - return m.handleAction(req) - default: - return models.ErrorResponse(req.ID, "unknown method") - } -} - -func (m *Manager) handleAction(req models.Request) models.Response { - // Extract and validate parameters - param, err := params.String(req.Params, "name") - if err != nil { - return models.ErrorResponse(req.ID, err.Error()) - } - - // Perform action - result, err := m.doSomething(param) - if err != nil { - return models.ErrorResponse(req.ID, err.Error()) - } - - return models.SuccessResponse(req.ID, result) -} -``` - -#### 4. D-Bus Integration - -```go -// Use context for cancellation -ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) -defer cancel() - -// Always check for D-Bus availability -if !dbusutil.ServiceExists(conn, "org.bluez") { - return fmt.Errorf("bluetooth service not available") -} - -// Handle signals properly with channels -signals := make(chan *dbus.Signal, 10) -conn.Signal(signals) -defer conn.RemoveSignal(signals) -``` - -#### 5. Wayland Protocol Integration - -```go -// Check protocol availability before use -if registry.GetGammaControl() == nil { - return errdefs.ErrNotSupported -} - -// Clean up Wayland resources -defer output.Destroy() -defer surface.Destroy() -``` - -#### 6. Testing - -```go -// Use table-driven tests -func TestManager_HandleRequest(t *testing.T) { - tests := []struct { - name string - request models.Request - want models.Response - wantErr bool - }{ - { - name: "valid request", - request: models.Request{ - ID: "1", - Method: "list", - }, - wantErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := NewManager() - got := m.HandleRequest(tt.request) - // Assertions - }) - } -} - -// Use mocks for external dependencies (see internal/mocks/) -``` - -#### 7. Logging - -```go -import "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - -// Use appropriate log levels -log.Debug("Processing request", "method", req.Method) -log.Info("Service started", "address", addr) -log.Warn("Feature unavailable", "reason", "missing dependency") -log.Error("Failed to connect", "error", err) -log.Fatal("Critical failure", "error", err) // Only for unrecoverable errors -``` - -### Component Development Patterns - -#### QML Frontend Patterns - -1. **Code Reuse - Search Before Writing**: - - **ALWAYS** search the codebase for existing functions before writing new ones - - Use `Grep` or `Glob` tools to find existing implementations (e.g., search for "getWifiIcon", "getDeviceIcon") - - Many utility functions already exist in Services/ and Common/ - reuse them instead of duplicating - - Examples of existing utility functions: `Theme.getBatteryIcon()`, `BluetoothService.getDeviceIcon()`, `WeatherService.getWeatherIcon()` - - If similar functionality exists, extend or refactor rather than duplicate - -2. **Smart Feature Detection**: - ```qml - // In services - detect capabilities - property bool brightnessAvailable: false - - // In modules - adapt UI accordingly - DankSlider { - visible: DisplayService.brightnessAvailable - enabled: DisplayService.brightnessAvailable - value: DisplayService.brightnessLevel - } - ``` - -3. **Reusable Components**: - - Create reusable widgets for common patterns (like DankSlider) - - Use configurable properties for different use cases - - Include proper signal handling with unique names (avoid `valueChanged`) - -4. **Service Integration**: - - Services expose properties and functions - - Modules and Widgets bind to service properties for reactive updates - - Use service functions for actions: `ServiceName.performAction(value)` - - **CRITICAL**: DO NOT create wrapper functions for everything - bind directly to underlying APIs when possible - - Example: Use `BluetoothService.adapter.discovering = true` instead of `BluetoothService.startScan()` - - Example: Use `device.connect()` directly instead of `BluetoothService.connect(device.address)` - -### Error Handling and Debugging - -1. **Console Logging**: - ```qml - // Use appropriate log levels - console.log("Info message") // General info - console.warn("Warning message") // Warnings - console.error("Error message") // Errors - - // Include context in service operations - onExited: (exitCode) => { - if (exitCode !== 0) { - console.warn("Service failed:", serviceName, "exit code:", exitCode) - } - } - ``` - -2. **Graceful Degradation**: - - Always check feature availability before showing UI - - Provide fallbacks for missing system tools - - Use `visible` and `enabled` properties appropriately - -## Multi-Monitor Support - -The shell uses Quickshell's `Variants` pattern for multi-monitor support: -- Each connected monitor gets its own top bar instance -- Workspace switchers are compositor-aware (6 compositors supported) -- Monitors are automatically detected by screen name (DP-1, DP-2, etc.) -- **Niri**: Workspaces dynamically synchronized with per-output workspaces -- **Hyprland**: Integrates with Hyprland's workspace system -- **MangoWC**: Uses dwl-ipc-unstable-v2 for tag management -- **Sway/labwc/Scroll**: Standard i3 IPC integration - -## IPC Communication Model - -### QML ↔ Go Backend Communication - -The shell uses a Unix socket-based IPC system for all system integration: - -1. **Go Backend** (`core/internal/server/`) runs an IPC server on `/tmp/dms-ipc-.sock` -2. **QML Services** send JSON-RPC requests to the backend -3. **Backend** handles system integration (D-Bus, Wayland, hardware) and responds -4. **QML Services** receive responses and update properties for UI reactivity - -**Example Flow:** -``` -User clicks WiFi network in UI - ↓ -QML NetworkService.connectNetwork(ssid, password) - ↓ -IPC Request: {"method": "network.connect", "params": {...}} - ↓ -Go Backend: internal/server/network/ handles D-Bus to NetworkManager - ↓ -IPC Response: {"result": {"success": true}} - ↓ -QML Service updates properties → UI updates reactively -``` - -**Why this architecture?** -- **Separation of concerns**: UI (QML) vs system integration (Go) -- **Type safety**: Go provides compile-time safety for system APIs -- **Performance**: Go handles expensive operations without blocking UI -- **Robustness**: Backend crashes don't crash the UI, and vice versa -- **Testing**: Backend can be tested independently of UI - -**Development implications:** -- QML Services should be **thin wrappers** - minimal logic, just IPC calls -- System integration logic belongs in Go backend packages -- When adding features, implement backend first, then QML wrapper -- Use `dms ipc ` CLI to test backend functionality independently - -## Common Development Tasks - -### Testing and Validation - -When modifying the shell: - -**QML Frontend:** -1. **Test changes**: `qs -p .` (automatic reload on file changes) -2. **Code quality**: Run `./qmlformat-all.sh` or `qmlformat -i **/*.qml`, then from repo root run `make lint-qml` after Quickshell has generated the local `.qmlls.ini` VFS with `qs -p .` -3. **Performance**: Ensure animations remain smooth (60 FPS target) -4. **Theming**: Use `Theme.propertyName` for Material Design 3 consistency - -**Go Backend:** -1. **Build**: `cd core && make` to build dms CLI -2. **Tests**: `make test` to run Go unit tests (add appropriate test coverage for new code) -3. **Linting**: `gofmt -w .`, `go mod tidy`, and `golangci-lint run` -4. **IPC testing**: Use `dms ipc ` to test backend functionality -5. **Rebuild**: After backend changes, rebuild with `make` and restart shell - -**Integration:** -1. **Full test**: `dms restart` to restart both backend and frontend -2. **Wayland compatibility**: Test on Wayland session -3. **Multi-monitor**: Verify behavior with multiple displays -4. **Compositor compatibility**: Test on Niri, Hyprland, MangoWC, Sway, labwc, Scroll when possible -5. **Distribution compatibility**: Test installation on Arch, Fedora, Debian, Ubuntu, openSUSE, Gentoo -6. **Feature detection**: Test on systems with/without required tools - -### Adding New Modules - -1. **Create component**: - ```bash - # Create new module file - touch Modules/NewModule.qml - ``` - -2. **Follow module patterns**: - - Use `Theme.propertyName` for styling - - Import `qs.Common` and `qs.Services` as needed - - Import `qs.Widgets` for reusable components - - Bind to service properties for reactive updates - - Consider per-screen vs global behavior - - Use `DankIcon` for icons instead of manual Text components - -3. **Integration in shell.qml**: - ```qml - NewModule { - id: newModule - // Configure properties - } - ``` - -### Adding New Widgets - -1. **Create component**: - ```bash - # Create new widget file - touch Widgets/NewWidget.qml - ``` - -2. **Follow widget patterns**: - - Use `Theme.propertyName` for styling - - Import `qs.Common` for theming - - Focus on reusability and composition - - Keep widgets simple and focused - - Use `DankIcon` for icons instead of manual Text components - -### Adding New Services - -**Important**: Most system integration should be done in the Go backend, with QML services as thin IPC wrappers. - -#### Step 1: Implement Go Backend - -1. **Create backend package**: - ```bash - mkdir -p core/internal/server/newsystem - ``` - -2. **Implement backend logic** (`core/internal/server/newsystem/manager.go`): - ```go - package newsystem - - import ( - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" - ) - - type Manager struct { - // State and D-Bus connections - } - - func NewManager() (*Manager, error) { - // Initialize D-Bus connections, Wayland protocols, etc. - return &Manager{}, nil - } - - func (m *Manager) HandleRequest(req models.Request) models.Response { - // Handle IPC requests - } - ``` - -3. **Add IPC handler** in `core/internal/server/router.go`: - ```go - newsystemMgr, _ := newsystem.NewManager() - router["newsystem"] = newsystemMgr.HandleRequest - ``` - -4. **Test backend**: `dms ipc newsystem.action '{"param": "value"}'` - -#### Step 2: Create QML Wrapper - -1. **Create service**: - ```qml - // Services/NewService.qml - import QtQuick - import Quickshell - import Quickshell.Io - pragma Singleton - pragma ComponentBehavior: Bound - - Singleton { - id: root - - property bool featureAvailable: false - property type currentValue: defaultValue - - function performAction(param) { - // Send IPC request to Go backend - ipcClient.send("newsystem.action", {param: param}) - } - - // Handle IPC responses to update properties - Connections { - target: IPCClient - function onResponse(method, data) { - if (method === "newsystem.status") { - currentValue = data.value - } - } - } - } - ``` - -2. **Use in modules**: - ```qml - property alias serviceValue: NewService.currentValue - - SomeControl { - visible: NewService.featureAvailable - enabled: NewService.featureAvailable - onTriggered: NewService.performAction(value) - } - ``` - -### Creating Plugins - -Plugins are external, dynamically-loaded components that extend DankMaterialShell functionality. Plugins are stored in `~/.config/DankMaterialShell/plugins/` and have their settings isolated from core DMS settings. - -**Plugin Types:** -- **Widget plugins** (`"type": "widget"` or omit type field): Display UI components in DankBar -- **Daemon plugins** (`"type": "daemon"`): Run invisibly in the background without UI - -#### Widget Plugins - -1. **Create plugin directory**: - ```bash - mkdir -p ~/.config/DankMaterialShell/plugins/YourPlugin - ``` - -2. **Create manifest** (`plugin.json`): - ```json - { - "id": "yourPlugin", - "name": "Your Plugin", - "description": "Widget description", - "version": "1.0.0", - "author": "Your Name", - "icon": "extension", - "type": "widget", - "component": "./YourWidget.qml", - "settings": "./YourSettings.qml", - "permissions": ["settings_read", "settings_write"] - } - ``` - -3. **Create widget component** (`YourWidget.qml`): - ```qml - import QtQuick - import qs.Services - - Rectangle { - id: root - - property bool compactMode: false - property string section: "center" - property real widgetHeight: 30 - property var pluginService: null - - width: content.implicitWidth + 16 - height: widgetHeight - radius: 8 - color: "#20FFFFFF" - - Component.onCompleted: { - if (pluginService) { - var data = pluginService.loadPluginData("yourPlugin", "key", defaultValue) - } - } - } - ``` - -4. **Create settings component** (`YourSettings.qml`): - ```qml - import QtQuick - import QtQuick.Controls - - FocusScope { - id: root - - property var pluginService: null - - implicitHeight: settingsColumn.implicitHeight - height: implicitHeight - - Column { - id: settingsColumn - anchors.fill: parent - anchors.margins: 16 - spacing: 12 - - Text { - text: "Your Plugin Settings" - font.pixelSize: 18 - font.weight: Font.Bold - } - - // Your settings UI here - } - - function saveSettings(key, value) { - if (pluginService) { - pluginService.savePluginData("yourPlugin", key, value) - } - } - - function loadSettings(key, defaultValue) { - if (pluginService) { - return pluginService.loadPluginData("yourPlugin", key, defaultValue) - } - return defaultValue - } - } - ``` - -5. **Enable plugin**: - - Open Settings → Plugins - - Click "Scan for Plugins" - - Toggle plugin to enable - - Add plugin ID to DankBar widget list - -#### Daemon Plugins - -Daemon plugins run invisibly in the background without any UI components. They're useful for monitoring system events, background tasks, or data synchronization. - -1. **Create plugin directory**: - ```bash - mkdir -p ~/.config/DankMaterialShell/plugins/YourDaemon - ``` - -2. **Create manifest** (`plugin.json`): - ```json - { - "id": "yourDaemon", - "name": "Your Daemon", - "description": "Background daemon description", - "version": "1.0.0", - "author": "Your Name", - "icon": "settings_applications", - "type": "daemon", - "component": "./YourDaemon.qml", - "permissions": ["settings_read", "settings_write"] - } - ``` - -3. **Create daemon component** (`YourDaemon.qml`): - ```qml - import QtQuick - import qs.Common - import qs.Services - - Item { - id: root - - property var pluginService: null - - Connections { - target: SessionData - function onWallpaperPathChanged() { - console.log("Wallpaper changed:", SessionData.wallpaperPath) - if (pluginService) { - pluginService.savePluginData("yourDaemon", "lastEvent", Date.now()) - } - } - } - - Component.onCompleted: { - console.log("Daemon started") - } - } - ``` - -4. **Enable daemon**: - - Open Settings → Plugins - - Click "Scan for Plugins" - - Toggle daemon to enable - - Daemon runs automatically in background - -**Example**: See `PLUGINS/WallpaperWatcherDaemon/` for a complete daemon plugin that monitors wallpaper changes - -**Plugin Directory Structure:** -``` -~/.config/DankMaterialShell/ -├── settings.json # Core DMS settings + plugin settings -│ └── pluginSettings: { -│ └── yourPlugin: { -│ ├── enabled: true, -│ └── customData: {...} -│ } -│ } -└── plugins/ # Plugin files directory - └── YourPlugin/ # Plugin directory (matches manifest ID) - ├── plugin.json # Plugin manifest - ├── YourWidget.qml # Widget component - └── YourSettings.qml # Settings UI (optional) -``` - -**Key Plugin APIs:** -- `pluginService.loadPluginData(pluginId, key, default)` - Load persistent data -- `pluginService.savePluginData(pluginId, key, value)` - Save persistent data -- `PluginService.enablePlugin(pluginId)` - Load plugin -- `PluginService.disablePlugin(pluginId)` - Unload plugin - -**Important Notes:** -- Plugin settings are automatically injected by the PluginService via `item.pluginService = PluginService` -- Settings are stored in the main settings.json but namespaced under `pluginSettings.{pluginId}` -- Plugin directories must match the plugin ID in the manifest -- Use the injected `pluginService` property in both widget and settings components - -### Debugging Common Issues - -#### QML Frontend Issues - -1. **Import errors**: Check import paths in qmldir files -2. **Singleton conflicts**: Ensure services use `Singleton` type with `id: root` -3. **Property binding issues**: Use property aliases for reactive updates -4. **Theme inconsistencies**: Always use `Theme.propertyName` instead of hardcoded values -5. **IPC communication failures**: Check if `dms run` backend is running - -#### Go Backend Issues - -1. **IPC not responding**: - - Check if socket exists: `ls -la /tmp/dms-ipc-$(id -u).sock` - - Test with CLI: `dms ipc test.ping` - - Check logs: `journalctl --user -u dms.service -f` - -2. **D-Bus errors**: - - Verify service availability: `busctl --user list | grep org.bluez` - - Test D-Bus call: `busctl --user introspect org.bluez /` - - Check permissions: User must be in required groups (video, input, etc.) - -3. **Wayland protocol errors**: - - Check compositor support: Different compositors support different protocols - - Use `dms features` to see available features - - Enable debug output: `WAYLAND_DEBUG=1 dms run` - -4. **Build failures**: - - Update Go: Requires Go 1.24+ - - Clean build: `cd core && make clean && make` - - Check dependencies: `go mod download` - -5. **Process failures**: - - Check system tool availability: `which ` - - Verify PATH: `echo $PATH` - - Check command syntax in logs - -### Best Practices Summary - -#### General -- **Code Reuse**: ALWAYS search existing codebase before writing new functions - avoid duplication at all costs -- **No Comments**: Code should be self-documenting - comments indicate poor naming/structure (applies to both QML and Go) -- **Modularity**: Keep components focused and independent -- **Testing**: Write tests for Go backend, test QML changes with live reload - -#### QML Frontend -- **Reusability**: Create reusable components for common patterns using Widgets/ -- **Responsiveness**: Use property bindings for reactive UI -- **Consistency**: Follow Material Design 3 principles via Theme singleton -- **Performance**: Minimize expensive operations and use appropriate data structures -- **Icon Management**: Use `DankIcon` for all icons instead of manual Text components -- **Widget System**: Leverage existing widgets (DankSlider, DankToggle, etc.) for consistency -- **NO WRAPPER HELL**: Avoid creating unnecessary wrapper functions - bind directly to underlying APIs for better reactivity and performance -- **Modern QML Patterns**: Leverage new widgets like DankTextField, DankDropdown, CachingImage -- **Structured Organization**: Follow the established Services/Modules/Widgets/Modals separation - -#### Go Backend -- **System Integration First**: Implement backend functionality before QML wrappers -- **Error Handling**: Always wrap errors with context using `fmt.Errorf` with `%w` -- **IPC Pattern**: Follow established IPC handler patterns for consistency -- **Feature Detection**: Check for system capabilities and fail gracefully -- **Robustness**: Implement feature detection and graceful degradation -- **D-Bus Best Practices**: Use contexts, check service availability, handle signals properly -- **Wayland Best Practices**: Clean up resources, check protocol availability -- **Testing**: Write table-driven tests, use mocks for external dependencies - -#### Architecture -- **Separation of Concerns**: UI (QML) vs system integration (Go) -- **Thin QML Wrappers**: Services should only handle IPC communication, not business logic -- **Backend-First Development**: Implement and test backend via CLI before adding UI -- **Function Discovery**: Use grep/search tools to find existing utility functions before implementing new ones -- **Plugin System**: For user extensions, create plugins instead of modifying core modules - -### Common Widget Patterns - -1. **Icons**: Always use `DankIcon { name: "icon_name" }` instead of `Text { font.family: Theme.iconFont }` -2. **Sliders**: Use `DankSlider` for consistent styling and behavior -3. **Toggles**: Use `DankToggle` for switches and checkboxes -4. **Tab Bars**: Use `DankTabBar` for tabbed interfaces -5. **Lists**: Use `DankListView` for scrollable lists -6. **Grids**: Use `DankGridView` for grid layouts -7. **Text Fields**: Use `DankTextField` for text input with validation -8. **Dropdowns**: Use `DankDropdown` for selection menus -9. **Popouts**: Use `DankPopout` as base for overlay components -10. **Images**: Use `CachingImage` for optimized image loading - -### Essential Utility Functions - -Before writing new utility functions, check these existing ones: - -**Theme.qml utilities:** -- `getBatteryIcon(level, isCharging, batteryAvailable)` - Battery status icons -- `getPowerProfileIcon(profile)` - Power profile indicators - -**Service utilities:** -- `BluetoothService.getDeviceIcon(device)` - Bluetooth device type icons -- `BluetoothService.getSignalIcon(device)` - Signal strength indicators -- `WeatherService.getWeatherIcon(code)` - Weather condition icons -- `AppSearchService.getCategoryIcon(category)` - Application category icons -- `DgopService.getProcessIcon(command)` - Process type icons -- `SettingsData.getWorkspaceNameIcon(workspaceName)` - Workspace icons - -**Always search for existing functions using:** -```bash -grep -r "function.*get.*Icon" Services/ Common/ -grep -r "function.*" path/to/relevant/directory/ -``` diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/CODENAME b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/CODENAME deleted file mode 100644 index d434e3f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/CODENAME +++ /dev/null @@ -1 +0,0 @@ -The Wolverine diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Anims.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Anims.qml deleted file mode 100644 index 349e991..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Anims.qml +++ /dev/null @@ -1,25 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - readonly property int durShort: 200 - readonly property int durMed: 450 - readonly property int durLong: 600 - - readonly property int slidePx: 80 - - readonly property var emphasized: [0.05, 0.00, 0.133333, 0.06, 0.166667, 0.40, 0.208333, 0.82, 0.25, 1.00, 1.00, 1.00] - - readonly property var emphasizedDecel: [0.05, 0.70, 0.10, 1.00, 1.00, 1.00] - - readonly property var emphasizedAccel: [0.30, 0.00, 0.80, 0.15, 1.00, 1.00] - - readonly property var standard: [0.20, 0.00, 0.00, 1.00, 1.00, 1.00] - readonly property var standardDecel: [0.00, 0.00, 0.00, 1.00, 1.00, 1.00] - readonly property var standardAccel: [0.30, 0.00, 1.00, 1.00, 1.00, 1.00] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/AppUsageHistoryData.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/AppUsageHistoryData.qml deleted file mode 100644 index 1077f38..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/AppUsageHistoryData.qml +++ /dev/null @@ -1,123 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io - -Singleton { - id: root - - property var appUsageRanking: {} - property bool _saving: false - - Component.onCompleted: { - loadSettings(); - } - - function loadSettings() { - parseSettings(settingsFile.text()); - } - - function parseSettings(content) { - try { - if (content && content.trim()) { - var settings = JSON.parse(content); - appUsageRanking = settings.appUsageRanking || {}; - } - } catch (e) {} - } - - function saveSettings() { - settingsFile.setText(JSON.stringify({ - "appUsageRanking": appUsageRanking - }, null, 2)); - } - - function addAppUsage(app) { - if (!app) - return; - var appId = app.id || (app.execString || app.exec || ""); - if (!appId) - return; - var currentRanking = Object.assign({}, appUsageRanking); - - if (currentRanking[appId]) { - currentRanking[appId].usageCount = (currentRanking[appId].usageCount || 1) + 1; - currentRanking[appId].lastUsed = Date.now(); - currentRanking[appId].icon = app.icon ? String(app.icon) : (currentRanking[appId].icon || "application-x-executable"); - currentRanking[appId].name = app.name || currentRanking[appId].name || ""; - } else { - currentRanking[appId] = { - "name": app.name || "", - "exec": app.execString || app.exec || "", - "icon": app.icon ? String(app.icon) : "application-x-executable", - "comment": app.comment || "", - "usageCount": 1, - "lastUsed": Date.now() - }; - } - - appUsageRanking = currentRanking; - _saving = true; - saveSettings(); - _saving = false; - } - - function getRankedApps() { - var apps = []; - for (var appId in appUsageRanking) { - var appData = appUsageRanking[appId]; - apps.push({ - "id": appId, - "name": appData.name, - "exec": appData.exec, - "icon": appData.icon, - "comment": appData.comment, - "usageCount": appData.usageCount, - "lastUsed": appData.lastUsed - }); - } - - return apps.sort(function (a, b) { - if (a.usageCount !== b.usageCount) - return b.usageCount - a.usageCount; - return a.name.localeCompare(b.name); - }); - } - - function cleanupAppUsageRanking(availableAppIds) { - var currentRanking = Object.assign({}, appUsageRanking); - var hasChanges = false; - - for (var appId in currentRanking) { - if (availableAppIds.indexOf(appId) === -1) { - delete currentRanking[appId]; - hasChanges = true; - } - } - - if (hasChanges) { - appUsageRanking = currentRanking; - _saving = true; - saveSettings(); - _saving = false; - } - } - - FileView { - id: settingsFile - - path: StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell/appusage.json" - blockLoading: true - blockWrites: true - watchChanges: true - onLoaded: { - if (root._saving) - return; - parseSettings(settingsFile.text()); - } - onLoadFailed: error => {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Appearance.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Appearance.qml deleted file mode 100644 index 3c22566..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Appearance.qml +++ /dev/null @@ -1,66 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - readonly property Rounding rounding: Rounding {} - readonly property Spacing spacing: Spacing {} - readonly property FontSize fontSize: FontSize {} - readonly property Anim anim: Anim {} - - component Rounding: QtObject { - readonly property int small: 8 - readonly property int normal: 12 - readonly property int large: 16 - readonly property int extraLarge: 24 - readonly property int full: 1000 - } - - component Spacing: QtObject { - readonly property int small: 4 - readonly property int normal: 8 - readonly property int large: 12 - readonly property int extraLarge: 16 - readonly property int huge: 24 - } - - component FontSize: QtObject { - readonly property int small: 12 - readonly property int normal: 14 - readonly property int large: 16 - readonly property int extraLarge: 20 - readonly property int huge: 24 - } - - component AnimCurves: QtObject { - readonly property list standard: [0.2, 0, 0, 1, 1, 1] - readonly property list standardAccel: [0.3, 0, 1, 1, 1, 1] - readonly property list standardDecel: [0, 0, 0, 1, 1, 1] - readonly property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 - / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] - readonly property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] - readonly property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] - readonly property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1] - readonly property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1] - readonly property list expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1] - } - - component AnimDurations: QtObject { - readonly property int quick: 150 - readonly property int normal: 300 - readonly property int slow: 500 - readonly property int extraSlow: 1000 - readonly property int expressiveFastSpatial: 350 - readonly property int expressiveDefaultSpatial: 500 - readonly property int expressiveEffects: 200 - } - - component Anim: QtObject { - readonly property AnimCurves curves: AnimCurves {} - readonly property AnimDurations durations: AnimDurations {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheData.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheData.qml deleted file mode 100644 index 6de7a8b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheData.qml +++ /dev/null @@ -1,227 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io - -Singleton { - id: root - - readonly property int cacheConfigVersion: 1 - - readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" - - readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericCacheLocation) - readonly property string _stateDir: Paths.strip(_stateUrl) - - property bool _loading: false - - property string wallpaperLastPath: "" - property string profileLastPath: "" - - property var fileBrowserSettings: ({ - "wallpaper": { - "lastPath": "", - "viewMode": "grid", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - }, - "profile": { - "lastPath": "", - "viewMode": "grid", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - }, - "notepad_save": { - "lastPath": "", - "viewMode": "list", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - }, - "notepad_load": { - "lastPath": "", - "viewMode": "list", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - }, - "generic": { - "lastPath": "", - "viewMode": "list", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - }, - "default": { - "lastPath": "", - "viewMode": "list", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - } - }) - - Component.onCompleted: { - if (!isGreeterMode) { - loadCache(); - } - } - - function loadCache() { - _loading = true; - parseCache(cacheFile.text()); - _loading = false; - } - - function parseCache(content) { - _loading = true; - try { - if (content && content.trim()) { - const cache = JSON.parse(content); - - wallpaperLastPath = cache.wallpaperLastPath !== undefined ? cache.wallpaperLastPath : ""; - profileLastPath = cache.profileLastPath !== undefined ? cache.profileLastPath : ""; - - if (cache.fileBrowserSettings !== undefined) { - fileBrowserSettings = cache.fileBrowserSettings; - } else if (cache.fileBrowserViewMode !== undefined) { - fileBrowserSettings = { - "wallpaper": { - "lastPath": cache.wallpaperLastPath || "", - "viewMode": cache.fileBrowserViewMode || "grid", - "sortBy": cache.fileBrowserSortBy || "name", - "sortAscending": cache.fileBrowserSortAscending !== undefined ? cache.fileBrowserSortAscending : true, - "iconSizeIndex": cache.fileBrowserIconSizeIndex !== undefined ? cache.fileBrowserIconSizeIndex : 1, - "showSidebar": cache.fileBrowserShowSidebar !== undefined ? cache.fileBrowserShowSidebar : true - }, - "profile": { - "lastPath": cache.profileLastPath || "", - "viewMode": cache.fileBrowserViewMode || "grid", - "sortBy": cache.fileBrowserSortBy || "name", - "sortAscending": cache.fileBrowserSortAscending !== undefined ? cache.fileBrowserSortAscending : true, - "iconSizeIndex": cache.fileBrowserIconSizeIndex !== undefined ? cache.fileBrowserIconSizeIndex : 1, - "showSidebar": cache.fileBrowserShowSidebar !== undefined ? cache.fileBrowserShowSidebar : true - }, - "file": { - "lastPath": "", - "viewMode": "list", - "sortBy": "name", - "sortAscending": true, - "iconSizeIndex": 1, - "showSidebar": true - } - }; - } - - if (cache.configVersion === undefined) { - migrateFromUndefinedToV1(cache); - cleanupUnusedKeys(); - saveCache(); - } - } - } catch (e) { - console.warn("CacheData: Failed to parse cache:", e.message); - } finally { - _loading = false; - } - } - - function saveCache() { - if (_loading) - return; - cacheFile.setText(JSON.stringify({ - "wallpaperLastPath": wallpaperLastPath, - "profileLastPath": profileLastPath, - "fileBrowserSettings": fileBrowserSettings, - "configVersion": cacheConfigVersion - }, null, 2)); - } - - function migrateFromUndefinedToV1(cache) { - console.info("CacheData: Migrating configuration from undefined to version 1"); - } - - function cleanupUnusedKeys() { - const validKeys = ["wallpaperLastPath", "profileLastPath", "fileBrowserSettings", "configVersion"]; - - try { - const content = cacheFile.text(); - if (!content || !content.trim()) - return; - const cache = JSON.parse(content); - let needsSave = false; - - for (const key in cache) { - if (!validKeys.includes(key)) { - console.log("CacheData: Removing unused key:", key); - delete cache[key]; - needsSave = true; - } - } - - if (needsSave) { - cacheFile.setText(JSON.stringify(cache, null, 2)); - } - } catch (e) { - console.warn("CacheData: Failed to cleanup unused keys:", e.message); - } - } - - function loadLauncherCache() { - try { - var content = launcherCacheFile.text(); - if (content && content.trim()) - return JSON.parse(content); - } catch (e) { - console.warn("CacheData: Failed to parse launcher cache:", e.message); - } - return null; - } - - function saveLauncherCache(sections) { - if (_loading) - return; - launcherCacheFile.setText(JSON.stringify(sections)); - } - - FileView { - id: launcherCacheFile - - path: isGreeterMode ? "" : _stateDir + "/DankMaterialShell/launcher_cache.json" - blockLoading: true - blockWrites: true - atomicWrites: true - watchChanges: false - } - - FileView { - id: cacheFile - - path: isGreeterMode ? "" : _stateDir + "/DankMaterialShell/cache.json" - blockLoading: true - blockWrites: true - atomicWrites: true - watchChanges: !isGreeterMode - onLoaded: { - if (!isGreeterMode) { - parseCache(cacheFile.text()); - } - } - onLoadFailed: error => { - if (!isGreeterMode) { - console.info("CacheData: No cache file found, starting fresh"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheUtils.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheUtils.qml deleted file mode 100644 index 1f03f0e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/CacheUtils.qml +++ /dev/null @@ -1,40 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound -import Quickshell - -Singleton { - id: root - - // Clear all image cache - function clearImageCache() { - Quickshell.execDetached(["rm", "-rf", Paths.stringify(Paths.imagecache)]); - Paths.mkdir(Paths.imagecache); - } - - // Clear cache older than specified minutes - function clearOldCache(ageInMinutes) { - Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", "*.png", "-mmin", `+${ageInMinutes}`, "-delete"]); - } - - // Clear cache for specific size - function clearCacheForSize(size) { - Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", `*@${size}x${size}.png`, "-delete"]); - } - - // Get cache size in MB - function getCacheSize(callback) { - var process = Qt.createQmlObject(` - import Quickshell.Io - Process { - command: ["du", "-sm", "${Paths.stringify(Paths.imagecache)}"] - running: true - stdout: StdioCollector { - onStreamFinished: { - var sizeMB = parseInt(text.split("\\t")[0]) || 0 - callback(sizeMB) - } - } - } - `, root); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankAnim.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankAnim.qml deleted file mode 100644 index 63d0c1c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankAnim.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick -import qs.Common - -// Reusable NumberAnimation wrapper -NumberAnimation { - duration: Theme.expressiveDurations.normal - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.standard -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankColorAnim.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankColorAnim.qml deleted file mode 100644 index 5bd5a9d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankColorAnim.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick -import qs.Common - -// Reusable ColorAnimation wrapper -ColorAnimation { - duration: Theme.expressiveDurations.normal - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.standard -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankSocket.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankSocket.qml deleted file mode 100644 index 93471ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/DankSocket.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick -import Quickshell.Io - -Item { - id: root - - property alias path: socket.path - property alias parser: socket.parser - property bool connected: false - - property int reconnectBaseMs: 400 - property int reconnectMaxMs: 15000 - - property int _reconnectAttempt: 0 - - signal connectionStateChanged() - - onConnectedChanged: { - socket.connected = connected - } - - Socket { - id: socket - - onConnectionStateChanged: { - root.connectionStateChanged() - if (connected) { - root._reconnectAttempt = 0 - return - } - if (root.connected) { - root._scheduleReconnect() - } - } - } - - Timer { - id: reconnectTimer - interval: 0 - repeat: false - onTriggered: { - socket.connected = false - Qt.callLater(() => socket.connected = true) - } - } - - function send(data) { - const json = typeof data === "string" ? data : JSON.stringify(data) - const message = json.endsWith("\n") ? json : json + "\n" - socket.write(message) - socket.flush() - } - - function _scheduleReconnect() { - const pow = Math.min(_reconnectAttempt, 10) - const base = Math.min(reconnectBaseMs * Math.pow(2, pow), reconnectMaxMs) - const jitter = Math.floor(Math.random() * Math.floor(base / 4)) - reconnectTimer.interval = base + jitter - reconnectTimer.restart() - _reconnectAttempt++ - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ElevationShadow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ElevationShadow.qml deleted file mode 100644 index dab80cd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ElevationShadow.qml +++ /dev/null @@ -1,54 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Effects -import qs.Common - -Item { - id: root - - property var level: Theme.elevationLevel2 - property string direction: Theme.elevationLightDirection - property real fallbackOffset: 4 - - property color targetColor: "white" - property real targetRadius: Theme.cornerRadius - property color borderColor: "transparent" - property real borderWidth: 0 - - property bool shadowEnabled: Theme.elevationEnabled - property real shadowBlurPx: level && level.blurPx !== undefined ? level.blurPx : 0 - property real shadowSpreadPx: level && level.spreadPx !== undefined ? level.spreadPx : 0 - property real shadowOffsetX: Theme.elevationOffsetXFor(level, direction, fallbackOffset) - property real shadowOffsetY: Theme.elevationOffsetYFor(level, direction, fallbackOffset) - property color shadowColor: Theme.elevationShadowColor(level) - property real shadowOpacity: 1 - property real blurMax: Theme.elevationBlurMax - - property alias sourceRect: sourceRect - - layer.enabled: shadowEnabled - - layer.effect: MultiEffect { - autoPaddingEnabled: true - shadowEnabled: true - blurEnabled: false - maskEnabled: false - shadowBlur: Math.max(0, Math.min(1, root.shadowBlurPx / Math.max(1, root.blurMax))) - shadowScale: 1 + (2 * root.shadowSpreadPx) / Math.max(1, Math.min(root.width, root.height)) - shadowHorizontalOffset: root.shadowOffsetX - shadowVerticalOffset: root.shadowOffsetY - blurMax: root.blurMax - shadowColor: root.shadowColor - shadowOpacity: root.shadowOpacity - } - - Rectangle { - id: sourceRect - anchors.fill: parent - radius: root.targetRadius - color: root.targetColor - border.color: root.borderColor - border.width: root.borderWidth - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/I18n.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/I18n.qml deleted file mode 100644 index aae0009..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/I18n.qml +++ /dev/null @@ -1,138 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Qt.labs.folderlistmodel -import Quickshell -import Quickshell.Io - -Singleton { - id: root - - property string _resolvedLocale: "en" - - readonly property string _rawLocale: SessionData.locale === "" ? Qt.locale().name : SessionData.locale - readonly property string _lang: _rawLocale.split(/[_-]/)[0] - readonly property var _candidates: { - const fullUnderscore = _rawLocale; - const fullHyphen = _rawLocale.replace("_", "-"); - return [fullUnderscore, fullHyphen, _lang].filter(c => c && c !== "en"); - } - - readonly property var _rtlLanguages: ["ar", "he", "iw", "fa", "ur", "ps", "sd", "dv", "yi", "ku"] - readonly property bool isRtl: _rtlLanguages.includes(_lang) - - readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports") - - readonly property alias folder: dir.folder - property var presentLocales: ({ - "en": Qt.locale("en") - }) - property var translations: ({}) - property bool translationsLoaded: false - - property url _selectedPath: "" - - FolderListModel { - id: dir - folder: root.translationsFolder - nameFilters: ["*.json"] - showDirs: false - showDotAndDotDot: false - - onStatusChanged: if (status === FolderListModel.Ready) { - root._loadPresentLocales(); - root._pickTranslation(); - } - } - - FileView { - id: translationLoader - path: root._selectedPath - - onLoaded: { - try { - root.translations = JSON.parse(text()); - root.translationsLoaded = true; - console.info(`I18n: Loaded translations for '${root._resolvedLocale}' (${Object.keys(root.translations).length} contexts)`); - } catch (e) { - console.warn(`I18n: Error parsing '${root._resolvedLocale}':`, e, "- falling back to English"); - root._fallbackToEnglish(); - } - } - - onLoadFailed: error => { - console.warn(`I18n: Failed to load '${root._resolvedLocale}' (${error}), ` + "falling back to English"); - root._fallbackToEnglish(); - } - } - - function locale() { - if (SessionData.timeLocale) - return Qt.locale(SessionData.timeLocale); - return Qt.locale(); - } - - function _loadPresentLocales() { - if (Object.keys(presentLocales).length > 1) { - return; // already loaded - } - for (let i = 0; i < dir.count; i++) { - const name = dir.get(i, "fileName"); // e.g. "zh_CN.json" - if (name && name.endsWith(".json")) { - const shortName = name.slice(0, -5); - presentLocales[shortName] = Qt.locale(shortName); - } - } - } - - function _pickTranslation() { - for (let i = 0; i < _candidates.length; i++) { - const cand = _candidates[i]; - if (presentLocales[cand] === undefined) - continue; - _resolvedLocale = cand; - useLocale(cand, cand.startsWith("en") ? "" : translationsFolder + "/" + cand + ".json"); - return; - } - - _resolvedLocale = "en"; - _fallbackToEnglish(); - } - - function useLocale(localeTag, fileUrl) { - _resolvedLocale = localeTag || "en"; - _selectedPath = fileUrl; - translationsLoaded = false; - translations = ({}); - console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`); - } - - function _fallbackToEnglish() { - _selectedPath = ""; - translationsLoaded = false; - translations = ({}); - console.warn("I18n: Falling back to built-in English strings"); - } - - function tr(term, context) { - if (!translationsLoaded || !translations) - return term; - const ctx = context || term; - if (translations[ctx] && translations[ctx][term]) - return translations[ctx][term]; - for (const c in translations) { - if (translations[c] && translations[c][term]) - return translations[c][term]; - } - return term; - } - - function trContext(context, term) { - if (!translationsLoaded || !translations) - return term; - if (translations[context] && translations[context][term]) - return translations[context][term]; - return term; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeyUtils.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeyUtils.js deleted file mode 100644 index eaf4520..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeyUtils.js +++ /dev/null @@ -1,178 +0,0 @@ -.pragma library - -const KEY_MAP = { - 16777234: "Left", - 16777236: "Right", - 16777235: "Up", - 16777237: "Down", - 44: "Comma", - 46: "Period", - 47: "Slash", - 59: "Semicolon", - 39: "Apostrophe", - 91: "BracketLeft", - 93: "BracketRight", - 92: "Backslash", - 45: "Minus", - 61: "Equal", - 96: "grave", - 32: "space", - 16777225: "Print", - 16777226: "Print", - 16777220: "Return", - 16777221: "Return", - 16777217: "Tab", - 16777219: "BackSpace", - 16777223: "Delete", - 16777222: "Insert", - 16777232: "Home", - 16777233: "End", - 16777238: "Page_Up", - 16777239: "Page_Down", - 16777216: "Escape", - 16777252: "Caps_Lock", - 16777253: "Num_Lock", - 16777254: "Scroll_Lock", - 16777224: "Pause", - 16777330: "XF86AudioRaiseVolume", - 16777328: "XF86AudioLowerVolume", - 16777329: "XF86AudioMute", - 16842808: "XF86AudioMicMute", - 16777344: "XF86AudioPlay", - 16777345: "XF86AudioStop", - 16777346: "XF86AudioPrev", - 16777347: "XF86AudioNext", - 16777348: "XF86AudioPause", - 16777349: "XF86AudioMedia", - 16777350: "XF86AudioRecord", - 16842798: "XF86MonBrightnessUp", - 16777394: "XF86MonBrightnessUp", - 16842797: "XF86MonBrightnessDown", - 16777395: "XF86MonBrightnessDown", - 16842800: "XF86KbdBrightnessUp", - 16842799: "XF86KbdBrightnessDown", - 16842796: "XF86PowerOff", - 16842803: "XF86Sleep", - 16842804: "XF86WakeUp", - 16842802: "XF86Eject", - 16842791: "XF86Calculator", - 16842806: "XF86Explorer", - 16842794: "XF86HomePage", - 16777426: "XF86Search", - 16777427: "XF86Mail", - 16777442: "XF86Launch0", - 16777443: "XF86Launch1", - 33: "1", - 64: "2", - 35: "3", - 36: "4", - 37: "5", - 94: "6", - 38: "7", - 42: "8", - 40: "9", - 41: "0", - 60: "Comma", - 62: "Period", - 63: "Slash", - 58: "Semicolon", - 34: "Apostrophe", - 123: "BracketLeft", - 125: "BracketRight", - 124: "Backslash", - 95: "Minus", - 43: "Equal", - 126: "grave", - 196: "Adiaeresis", - 214: "Odiaeresis", - 220: "Udiaeresis", - 228: "adiaeresis", - 246: "odiaeresis", - 252: "udiaeresis", - 223: "ssharp", - 201: "Eacute", - 233: "eacute", - 200: "Egrave", - 232: "egrave", - 202: "Ecircumflex", - 234: "ecircumflex", - 203: "Ediaeresis", - 235: "ediaeresis", - 192: "Agrave", - 224: "agrave", - 194: "Acircumflex", - 226: "acircumflex", - 199: "Ccedilla", - 231: "ccedilla", - 206: "Icircumflex", - 238: "icircumflex", - 207: "Idiaeresis", - 239: "idiaeresis", - 212: "Ocircumflex", - 244: "ocircumflex", - 217: "Ugrave", - 249: "ugrave", - 219: "Ucircumflex", - 251: "ucircumflex", - 209: "Ntilde", - 241: "ntilde", - 191: "questiondown", - 161: "exclamdown" -}; - -function xkbKeyFromQtKey(qk) { - if (qk >= 65 && qk <= 90) - return String.fromCharCode(qk); - if (qk >= 97 && qk <= 122) - return String.fromCharCode(qk - 32); - if (qk >= 48 && qk <= 57) - return String.fromCharCode(qk); - if (qk >= 16777264 && qk <= 16777298) - return "F" + (qk - 16777264 + 1); - return KEY_MAP[qk] || ""; -} - -function modsFromEvent(mods) { - var result = []; - if (mods & 0x10000000) - result.push("Super"); - if (mods & 0x08000000) - result.push("Alt"); - if (mods & 0x04000000) - result.push("Ctrl"); - if (mods & 0x02000000) - result.push("Shift"); - return result; -} - -function formatToken(mods, key) { - return (mods.length ? mods.join("+") + "+" : "") + key; -} - -function normalizeKeyCombo(keyCombo) { - if (!keyCombo) - return ""; - return keyCombo.toLowerCase().replace(/\bmod\b/g, "super").replace(/\bsuper\b/g, "super"); -} - -function getConflictingBinds(keyCombo, currentAction, allBinds) { - if (!keyCombo) - return []; - var conflicts = []; - var normalizedKey = normalizeKeyCombo(keyCombo); - for (var i = 0; i < allBinds.length; i++) { - var bind = allBinds[i]; - if (bind.action === currentAction) - continue; - for (var k = 0; k < bind.keys.length; k++) { - if (normalizeKeyCombo(bind.keys[k].key) === normalizedKey) { - conflicts.push({ - action: bind.action, - desc: bind.desc || bind.action - }); - break; - } - } - } - return conflicts; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeybindActions.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeybindActions.js deleted file mode 100644 index 25b1ed0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/KeybindActions.js +++ /dev/null @@ -1,1329 +0,0 @@ -.pragma library - -const ACTION_TYPES = [ - { id: "dms", label: "DMS Action", icon: "widgets" }, - { id: "compositor", label: "Compositor", icon: "desktop_windows" }, - { id: "spawn", label: "Run Command", icon: "terminal" }, - { id: "shell", label: "Shell Command", icon: "code" } -]; - -const DMS_ACTIONS = [ - { id: "spawn dms ipc call spotlight toggle", label: "App Launcher: Toggle" }, - { id: "spawn dms ipc call spotlight open", label: "App Launcher: Open" }, - { id: "spawn dms ipc call spotlight close", label: "App Launcher: Close" }, - { id: "spawn dms ipc call clipboard toggle", label: "Clipboard: Toggle" }, - { id: "spawn dms ipc call clipboard open", label: "Clipboard: Open" }, - { id: "spawn dms ipc call clipboard close", label: "Clipboard: Close" }, - { id: "spawn dms ipc call notifications toggle", label: "Notifications: Toggle" }, - { id: "spawn dms ipc call notifications open", label: "Notifications: Open" }, - { id: "spawn dms ipc call notifications close", label: "Notifications: Close" }, - { id: "spawn dms ipc call processlist toggle", label: "Task Manager: Toggle" }, - { id: "spawn dms ipc call processlist open", label: "Task Manager: Open" }, - { id: "spawn dms ipc call processlist close", label: "Task Manager: Close" }, - { id: "spawn dms ipc call processlist focusOrToggle", label: "Task Manager: Focus or Toggle" }, - { id: "spawn dms ipc call settings toggle", label: "Settings: Toggle" }, - { id: "spawn dms ipc call settings open", label: "Settings: Open" }, - { id: "spawn dms ipc call settings close", label: "Settings: Close" }, - { id: "spawn dms ipc call settings focusOrToggle", label: "Settings: Focus or Toggle" }, - { id: "spawn dms ipc call powermenu toggle", label: "Power Menu: Toggle" }, - { id: "spawn dms ipc call powermenu open", label: "Power Menu: Open" }, - { id: "spawn dms ipc call powermenu close", label: "Power Menu: Close" }, - { id: "spawn dms ipc call control-center toggle", label: "Control Center: Toggle" }, - { id: "spawn dms ipc call control-center open", label: "Control Center: Open" }, - { id: "spawn dms ipc call control-center close", label: "Control Center: Close" }, - { id: "spawn dms ipc call notepad toggle", label: "Notepad: Toggle" }, - { id: "spawn dms ipc call notepad open", label: "Notepad: Open" }, - { id: "spawn dms ipc call notepad close", label: "Notepad: Close" }, - { id: "spawn dms ipc call dash toggle \"\"", label: "Dashboard: Toggle" }, - { id: "spawn dms ipc call dash open overview", label: "Dashboard: Overview" }, - { id: "spawn dms ipc call dash open media", label: "Dashboard: Media" }, - { id: "spawn dms ipc call dash open weather", label: "Dashboard: Weather" }, - { id: "spawn dms ipc call dankdash wallpaper", label: "Wallpaper Browser" }, - { id: "spawn dms ipc call file browse wallpaper", label: "File: Browse Wallpaper" }, - { id: "spawn dms ipc call file browse profile", label: "File: Browse Profile" }, - { id: "spawn dms ipc call keybinds toggle niri", label: "Keybinds Cheatsheet: Toggle", compositor: "niri" }, - { id: "spawn dms ipc call keybinds open niri", label: "Keybinds Cheatsheet: Open", compositor: "niri" }, - { id: "spawn dms ipc call keybinds close", label: "Keybinds Cheatsheet: Close" }, - { id: "spawn dms ipc call lock lock", label: "Lock Screen" }, - { id: "spawn dms ipc call lock demo", label: "Lock Screen: Demo" }, - { id: "spawn dms ipc call inhibit toggle", label: "Idle Inhibit: Toggle" }, - { id: "spawn dms ipc call inhibit enable", label: "Idle Inhibit: Enable" }, - { id: "spawn dms ipc call inhibit disable", label: "Idle Inhibit: Disable" }, - { id: "spawn dms ipc call audio increment 5", label: "Volume Up" }, - { id: "spawn dms ipc call audio increment 1", label: "Volume Up (1%)" }, - { id: "spawn dms ipc call audio increment 5", label: "Volume Up (5%)" }, - { id: "spawn dms ipc call audio increment 10", label: "Volume Up (10%)" }, - { id: "spawn dms ipc call audio decrement 5", label: "Volume Down" }, - { id: "spawn dms ipc call audio decrement 1", label: "Volume Down (1%)" }, - { id: "spawn dms ipc call audio decrement 5", label: "Volume Down (5%)" }, - { id: "spawn dms ipc call audio decrement 10", label: "Volume Down (10%)" }, - { id: "spawn dms ipc call mpris increment 5", label: "Player Volume Up (5%)" }, - { id: "spawn dms ipc call mpris decrement 5", label: "Player Volume Down (5%)" }, - { id: "spawn dms ipc call audio mute", label: "Volume Mute Toggle" }, - { id: "spawn dms ipc call audio micmute", label: "Microphone Mute Toggle" }, - { id: "spawn dms ipc call audio cycleoutput", label: "Audio Output: Cycle" }, - { id: "spawn dms ipc call brightness increment 5 \"\"", label: "Brightness Up" }, - { id: "spawn dms ipc call brightness increment 1 \"\"", label: "Brightness Up (1%)" }, - { id: "spawn dms ipc call brightness increment 5 \"\"", label: "Brightness Up (5%)" }, - { id: "spawn dms ipc call brightness increment 10 \"\"", label: "Brightness Up (10%)" }, - { id: "spawn dms ipc call brightness decrement 5 \"\"", label: "Brightness Down" }, - { id: "spawn dms ipc call brightness decrement 1 \"\"", label: "Brightness Down (1%)" }, - { id: "spawn dms ipc call brightness decrement 5 \"\"", label: "Brightness Down (5%)" }, - { id: "spawn dms ipc call brightness decrement 10 \"\"", label: "Brightness Down (10%)" }, - { id: "spawn dms ipc call brightness toggleExponential \"\"", label: "Brightness: Toggle Exponential" }, - { id: "spawn dms ipc call theme toggle", label: "Theme: Toggle Light/Dark" }, - { id: "spawn dms ipc call theme light", label: "Theme: Light Mode" }, - { id: "spawn dms ipc call theme dark", label: "Theme: Dark Mode" }, - { id: "spawn dms ipc call night toggle", label: "Night Mode: Toggle" }, - { id: "spawn dms ipc call night enable", label: "Night Mode: Enable" }, - { id: "spawn dms ipc call night disable", label: "Night Mode: Disable" }, - { id: "spawn dms ipc call bar toggle index 0", label: "Bar: Toggle (Primary)" }, - { id: "spawn dms ipc call bar reveal index 0", label: "Bar: Reveal (Primary)" }, - { id: "spawn dms ipc call bar hide index 0", label: "Bar: Hide (Primary)" }, - { id: "spawn dms ipc call bar toggleAutoHide index 0", label: "Bar: Toggle Auto-Hide (Primary)" }, - { id: "spawn dms ipc call bar autoHide index 0", label: "Bar: Enable Auto-Hide (Primary)" }, - { id: "spawn dms ipc call bar manualHide index 0", label: "Bar: Disable Auto-Hide (Primary)" }, - { id: "spawn dms ipc call dock toggle", label: "Dock: Toggle" }, - { id: "spawn dms ipc call dock reveal", label: "Dock: Reveal" }, - { id: "spawn dms ipc call dock hide", label: "Dock: Hide" }, - { id: "spawn dms ipc call dock toggleAutoHide", label: "Dock: Toggle Auto-Hide" }, - { id: "spawn dms ipc call dock autoHide", label: "Dock: Enable Auto-Hide" }, - { id: "spawn dms ipc call dock manualHide", label: "Dock: Disable Auto-Hide" }, - { id: "spawn dms ipc call mpris playPause", label: "Media: Play/Pause" }, - { id: "spawn dms ipc call mpris play", label: "Media: Play" }, - { id: "spawn dms ipc call mpris pause", label: "Media: Pause" }, - { id: "spawn dms ipc call mpris previous", label: "Media: Previous Track" }, - { id: "spawn dms ipc call mpris next", label: "Media: Next Track" }, - { id: "spawn dms ipc call mpris stop", label: "Media: Stop" }, - { id: "spawn dms ipc call niri screenshot", label: "Screenshot: Interactive", compositor: "niri" }, - { id: "spawn dms ipc call niri screenshotScreen", label: "Screenshot: Full Screen", compositor: "niri" }, - { id: "spawn dms ipc call niri screenshotWindow", label: "Screenshot: Window", compositor: "niri" }, - { id: "spawn dms ipc call hypr toggleOverview", label: "Hyprland: Toggle Overview", compositor: "hyprland" }, - { id: "spawn dms ipc call hypr openOverview", label: "Hyprland: Open Overview", compositor: "hyprland" }, - { id: "spawn dms ipc call hypr closeOverview", label: "Hyprland: Close Overview", compositor: "hyprland" }, - { id: "spawn dms ipc call wallpaper next", label: "Wallpaper: Next" }, - { id: "spawn dms ipc call wallpaper prev", label: "Wallpaper: Previous" }, - { id: "spawn dms ipc call workspace-rename open", label: "Workspace: Rename" } -]; - -const NIRI_ACTIONS = { - "Window": [ - { id: "close-window", label: "Close Window" }, - { id: "fullscreen-window", label: "Fullscreen" }, - { id: "maximize-column", label: "Maximize Column" }, - { id: "center-column", label: "Center Column" }, - { id: "center-visible-columns", label: "Center Visible Columns" }, - { id: "toggle-window-floating", label: "Toggle Floating" }, - { id: "switch-focus-between-floating-and-tiling", label: "Switch Floating/Tiling Focus" }, - { id: "switch-preset-column-width", label: "Cycle Column Width" }, - { id: "switch-preset-window-height", label: "Cycle Window Height" }, - { id: "set-column-width", label: "Set Column Width" }, - { id: "set-window-height", label: "Set Window Height" }, - { id: "reset-window-height", label: "Reset Window Height" }, - { id: "expand-column-to-available-width", label: "Expand to Available Width" }, - { id: "consume-or-expel-window-left", label: "Consume/Expel Left" }, - { id: "consume-or-expel-window-right", label: "Consume/Expel Right" }, - { id: "toggle-column-tabbed-display", label: "Toggle Tabbed" }, - { id: "toggle-window-rule-opacity", label: "Toggle Window Opacity" } - ], - "Focus": [ - { id: "focus-column-left", label: "Focus Left" }, - { id: "focus-column-right", label: "Focus Right" }, - { id: "focus-window-down", label: "Focus Down" }, - { id: "focus-window-up", label: "Focus Up" }, - { id: "focus-column-first", label: "Focus First Column" }, - { id: "focus-column-last", label: "Focus Last Column" } - ], - "Move": [ - { id: "move-column-left", label: "Move Left" }, - { id: "move-column-right", label: "Move Right" }, - { id: "move-window-down", label: "Move Down" }, - { id: "move-window-up", label: "Move Up" }, - { id: "move-column-to-first", label: "Move to First" }, - { id: "move-column-to-last", label: "Move to Last" } - ], - "Workspace": [ - { id: "focus-workspace-down", label: "Focus Workspace Down" }, - { id: "focus-workspace-up", label: "Focus Workspace Up" }, - { id: "focus-workspace-previous", label: "Focus Previous Workspace" }, - { id: "focus-workspace", label: "Focus Workspace (by index)" }, - { id: "move-column-to-workspace-down", label: "Move to Workspace Down" }, - { id: "move-column-to-workspace-up", label: "Move to Workspace Up" }, - { id: "move-column-to-workspace", label: "Move to Workspace (by index)" }, - { id: "move-workspace-down", label: "Move Workspace Down" }, - { id: "move-workspace-up", label: "Move Workspace Up" } - ], - "Monitor": [ - { id: "focus-monitor-left", label: "Focus Monitor Left" }, - { id: "focus-monitor-right", label: "Focus Monitor Right" }, - { id: "focus-monitor-down", label: "Focus Monitor Down" }, - { id: "focus-monitor-up", label: "Focus Monitor Up" }, - { id: "move-column-to-monitor-left", label: "Move to Monitor Left" }, - { id: "move-column-to-monitor-right", label: "Move to Monitor Right" }, - { id: "move-column-to-monitor-down", label: "Move to Monitor Down" }, - { id: "move-column-to-monitor-up", label: "Move to Monitor Up" } - ], - "Screenshot": [ - { id: "screenshot", label: "Screenshot (Interactive)" }, - { id: "screenshot-screen", label: "Screenshot Screen" }, - { id: "screenshot-window", label: "Screenshot Window" } - ], - "System": [ - { id: "toggle-overview", label: "Toggle Overview" }, - { id: "show-hotkey-overlay", label: "Show Hotkey Overlay" }, - { id: "do-screen-transition", label: "Screen Transition" }, - { id: "power-off-monitors", label: "Power Off Monitors" }, - { id: "power-on-monitors", label: "Power On Monitors" }, - { id: "toggle-keyboard-shortcuts-inhibit", label: "Toggle Shortcuts Inhibit" }, - { id: "quit", label: "Quit Niri" }, - { id: "suspend", label: "Suspend" } - ], - "Alt-Tab": [ - { id: "next-window", label: "Next Window" }, - { id: "previous-window", label: "Previous Window" } - ] -}; - -const MANGOWC_ACTIONS = { - "Window": [ - { id: "killclient", label: "Close Window" }, - { id: "focuslast", label: "Focus Last Window" }, - { id: "focusstack next", label: "Focus Next in Stack" }, - { id: "focusstack prev", label: "Focus Previous in Stack" }, - { id: "focusdir left", label: "Focus Left" }, - { id: "focusdir right", label: "Focus Right" }, - { id: "focusdir up", label: "Focus Up" }, - { id: "focusdir down", label: "Focus Down" }, - { id: "exchange_client left", label: "Swap Left" }, - { id: "exchange_client right", label: "Swap Right" }, - { id: "exchange_client up", label: "Swap Up" }, - { id: "exchange_client down", label: "Swap Down" }, - { id: "exchange_stack_client next", label: "Swap Next in Stack" }, - { id: "exchange_stack_client prev", label: "Swap Previous in Stack" }, - { id: "togglefloating", label: "Toggle Floating" }, - { id: "togglefullscreen", label: "Toggle Fullscreen" }, - { id: "togglefakefullscreen", label: "Toggle Fake Fullscreen" }, - { id: "togglemaximizescreen", label: "Toggle Maximize" }, - { id: "toggleglobal", label: "Toggle Global (Sticky)" }, - { id: "toggleoverlay", label: "Toggle Overlay" }, - { id: "minimized", label: "Minimize Window" }, - { id: "restore_minimized", label: "Restore Minimized" }, - { id: "toggle_render_border", label: "Toggle Border" }, - { id: "centerwin", label: "Center Window" }, - { id: "zoom", label: "Swap with Master" } - ], - "Move/Resize": [ - { id: "smartmovewin left", label: "Smart Move Left" }, - { id: "smartmovewin right", label: "Smart Move Right" }, - { id: "smartmovewin up", label: "Smart Move Up" }, - { id: "smartmovewin down", label: "Smart Move Down" }, - { id: "smartresizewin left", label: "Smart Resize Left" }, - { id: "smartresizewin right", label: "Smart Resize Right" }, - { id: "smartresizewin up", label: "Smart Resize Up" }, - { id: "smartresizewin down", label: "Smart Resize Down" }, - { id: "movewin", label: "Move Window (x,y)" }, - { id: "resizewin", label: "Resize Window (w,h)" } - ], - "Tags": [ - { id: "view", label: "View Tag" }, - { id: "viewtoleft", label: "View Left Tag" }, - { id: "viewtoright", label: "View Right Tag" }, - { id: "viewtoleft_have_client", label: "View Left (with client)" }, - { id: "viewtoright_have_client", label: "View Right (with client)" }, - { id: "viewcrossmon", label: "View Cross-Monitor" }, - { id: "tag", label: "Move to Tag" }, - { id: "tagsilent", label: "Move to Tag (silent)" }, - { id: "tagtoleft", label: "Move to Left Tag" }, - { id: "tagtoright", label: "Move to Right Tag" }, - { id: "tagcrossmon", label: "Move Cross-Monitor" }, - { id: "toggletag", label: "Toggle Tag on Window" }, - { id: "toggleview", label: "Toggle Tag View" }, - { id: "comboview", label: "Combo View Tags" } - ], - "Layout": [ - { id: "setlayout", label: "Set Layout" }, - { id: "switch_layout", label: "Cycle Layouts" }, - { id: "set_proportion", label: "Set Proportion" }, - { id: "switch_proportion_preset", label: "Cycle Proportion Presets" }, - { id: "incnmaster +1", label: "Increase Masters" }, - { id: "incnmaster -1", label: "Decrease Masters" }, - { id: "setmfact", label: "Set Master Factor" }, - { id: "incgaps", label: "Adjust Gaps" }, - { id: "togglegaps", label: "Toggle Gaps" } - ], - "Monitor": [ - { id: "focusmon left", label: "Focus Monitor Left" }, - { id: "focusmon right", label: "Focus Monitor Right" }, - { id: "focusmon up", label: "Focus Monitor Up" }, - { id: "focusmon down", label: "Focus Monitor Down" }, - { id: "tagmon left", label: "Move to Monitor Left" }, - { id: "tagmon right", label: "Move to Monitor Right" }, - { id: "tagmon up", label: "Move to Monitor Up" }, - { id: "tagmon down", label: "Move to Monitor Down" }, - { id: "disable_monitor", label: "Disable Monitor" }, - { id: "enable_monitor", label: "Enable Monitor" }, - { id: "toggle_monitor", label: "Toggle Monitor" }, - { id: "create_virtual_output", label: "Create Virtual Output" }, - { id: "destroy_all_virtual_output", label: "Destroy Virtual Outputs" } - ], - "Scratchpad": [ - { id: "toggle_scratchpad", label: "Toggle Scratchpad" }, - { id: "toggle_name_scratchpad", label: "Toggle Named Scratchpad" } - ], - "Overview": [ - { id: "toggleoverview", label: "Toggle Overview" } - ], - "System": [ - { id: "reload_config", label: "Reload Config" }, - { id: "quit", label: "Quit MangoWC" }, - { id: "setkeymode", label: "Set Keymode" }, - { id: "switch_keyboard_layout", label: "Switch Keyboard Layout" }, - { id: "setoption", label: "Set Option" }, - { id: "toggle_trackpad_enable", label: "Toggle Trackpad" } - ] -}; - -const HYPRLAND_ACTIONS = { - "Window": [ - { id: "killactive", label: "Close Window" }, - { id: "forcekillactive", label: "Force Kill Window" }, - { id: "closewindow", label: "Close Window (by selector)" }, - { id: "killwindow", label: "Kill Window (by selector)" }, - { id: "togglefloating", label: "Toggle Floating" }, - { id: "setfloating", label: "Set Floating" }, - { id: "settiled", label: "Set Tiled" }, - { id: "fullscreen", label: "Toggle Fullscreen" }, - { id: "fullscreenstate", label: "Set Fullscreen State" }, - { id: "pin", label: "Pin Window" }, - { id: "centerwindow", label: "Center Window" }, - { id: "resizeactive", label: "Resize Active Window" }, - { id: "moveactive", label: "Move Active Window" }, - { id: "resizewindowpixel", label: "Resize Window (pixels)" }, - { id: "movewindowpixel", label: "Move Window (pixels)" }, - { id: "alterzorder", label: "Change Z-Order" }, - { id: "bringactivetotop", label: "Bring to Top" }, - { id: "setprop", label: "Set Window Property" }, - { id: "toggleswallow", label: "Toggle Swallow" } - ], - "Focus": [ - { id: "movefocus l", label: "Focus Left" }, - { id: "movefocus r", label: "Focus Right" }, - { id: "movefocus u", label: "Focus Up" }, - { id: "movefocus d", label: "Focus Down" }, - { id: "movefocus", label: "Move Focus (direction)" }, - { id: "cyclenext", label: "Cycle Next Window" }, - { id: "cyclenext prev", label: "Cycle Previous Window" }, - { id: "focuswindow", label: "Focus Window (by selector)" }, - { id: "focuscurrentorlast", label: "Focus Current or Last" }, - { id: "focusurgentorlast", label: "Focus Urgent or Last" } - ], - "Move": [ - { id: "movewindow l", label: "Move Window Left" }, - { id: "movewindow r", label: "Move Window Right" }, - { id: "movewindow u", label: "Move Window Up" }, - { id: "movewindow d", label: "Move Window Down" }, - { id: "movewindow", label: "Move Window (direction)" }, - { id: "swapwindow l", label: "Swap Left" }, - { id: "swapwindow r", label: "Swap Right" }, - { id: "swapwindow u", label: "Swap Up" }, - { id: "swapwindow d", label: "Swap Down" }, - { id: "swapwindow", label: "Swap Window (direction)" }, - { id: "swapnext", label: "Swap with Next" }, - { id: "swapnext prev", label: "Swap with Previous" }, - { id: "movecursortocorner", label: "Move Cursor to Corner" }, - { id: "movecursor", label: "Move Cursor (x,y)" } - ], - "Workspace": [ - { id: "workspace", label: "Focus Workspace" }, - { id: "workspace +1", label: "Next Workspace" }, - { id: "workspace -1", label: "Previous Workspace" }, - { id: "workspace e+1", label: "Next Open Workspace" }, - { id: "workspace e-1", label: "Previous Open Workspace" }, - { id: "workspace previous", label: "Previous Visited Workspace" }, - { id: "workspace previous_per_monitor", label: "Previous on Monitor" }, - { id: "workspace empty", label: "First Empty Workspace" }, - { id: "movetoworkspace", label: "Move to Workspace" }, - { id: "movetoworkspace +1", label: "Move to Next Workspace" }, - { id: "movetoworkspace -1", label: "Move to Previous Workspace" }, - { id: "movetoworkspacesilent", label: "Move to Workspace (silent)" }, - { id: "movetoworkspacesilent +1", label: "Move to Next (silent)" }, - { id: "movetoworkspacesilent -1", label: "Move to Previous (silent)" }, - { id: "togglespecialworkspace", label: "Toggle Special Workspace" }, - { id: "focusworkspaceoncurrentmonitor", label: "Focus Workspace on Current Monitor" }, - { id: "renameworkspace", label: "Rename Workspace" } - ], - "Monitor": [ - { id: "focusmonitor l", label: "Focus Monitor Left" }, - { id: "focusmonitor r", label: "Focus Monitor Right" }, - { id: "focusmonitor u", label: "Focus Monitor Up" }, - { id: "focusmonitor d", label: "Focus Monitor Down" }, - { id: "focusmonitor +1", label: "Focus Next Monitor" }, - { id: "focusmonitor -1", label: "Focus Previous Monitor" }, - { id: "focusmonitor", label: "Focus Monitor (by selector)" }, - { id: "movecurrentworkspacetomonitor", label: "Move Workspace to Monitor" }, - { id: "moveworkspacetomonitor", label: "Move Specific Workspace to Monitor" }, - { id: "swapactiveworkspaces", label: "Swap Active Workspaces" } - ], - "Groups": [ - { id: "togglegroup", label: "Toggle Group" }, - { id: "changegroupactive f", label: "Next in Group" }, - { id: "changegroupactive b", label: "Previous in Group" }, - { id: "changegroupactive", label: "Change Active in Group" }, - { id: "moveintogroup l", label: "Move into Group Left" }, - { id: "moveintogroup r", label: "Move into Group Right" }, - { id: "moveintogroup u", label: "Move into Group Up" }, - { id: "moveintogroup d", label: "Move into Group Down" }, - { id: "moveoutofgroup", label: "Move out of Group" }, - { id: "movewindoworgroup l", label: "Move Window/Group Left" }, - { id: "movewindoworgroup r", label: "Move Window/Group Right" }, - { id: "movewindoworgroup u", label: "Move Window/Group Up" }, - { id: "movewindoworgroup d", label: "Move Window/Group Down" }, - { id: "movegroupwindow f", label: "Swap Forward in Group" }, - { id: "movegroupwindow b", label: "Swap Backward in Group" }, - { id: "lockgroups lock", label: "Lock All Groups" }, - { id: "lockgroups unlock", label: "Unlock All Groups" }, - { id: "lockgroups toggle", label: "Toggle Groups Lock" }, - { id: "lockactivegroup lock", label: "Lock Active Group" }, - { id: "lockactivegroup unlock", label: "Unlock Active Group" }, - { id: "lockactivegroup toggle", label: "Toggle Active Group Lock" }, - { id: "denywindowfromgroup on", label: "Deny Window from Group" }, - { id: "denywindowfromgroup off", label: "Allow Window in Group" }, - { id: "denywindowfromgroup toggle", label: "Toggle Deny from Group" }, - { id: "setignoregrouplock on", label: "Ignore Group Lock" }, - { id: "setignoregrouplock off", label: "Respect Group Lock" }, - { id: "setignoregrouplock toggle", label: "Toggle Ignore Group Lock" } - ], - "Layout": [ - { id: "splitratio", label: "Adjust Split Ratio" } - ], - "System": [ - { id: "exit", label: "Exit Hyprland" }, - { id: "forcerendererreload", label: "Force Renderer Reload" }, - { id: "dpms on", label: "DPMS On" }, - { id: "dpms off", label: "DPMS Off" }, - { id: "dpms toggle", label: "DPMS Toggle" }, - { id: "forceidle", label: "Force Idle" }, - { id: "submap", label: "Enter Submap" }, - { id: "submap reset", label: "Reset Submap" }, - { id: "global", label: "Global Shortcut" }, - { id: "event", label: "Emit Custom Event" } - ], - "Pass-through": [ - { id: "pass", label: "Pass Key to Window" }, - { id: "sendshortcut", label: "Send Shortcut to Window" }, - { id: "sendkeystate", label: "Send Key State" } - ] -}; - -const COMPOSITOR_ACTIONS = { - niri: NIRI_ACTIONS, - mangowc: MANGOWC_ACTIONS, - hyprland: HYPRLAND_ACTIONS -}; - -const CATEGORY_ORDER = ["DMS", "Execute", "Workspace", "Tags", "Window", "Move/Resize", "Focus", "Move", "Layout", "Groups", "Monitor", "Scratchpad", "Screenshot", "System", "Pass-through", "Overview", "Alt-Tab", "Other"]; - -const NIRI_ACTION_ARGS = { - "quit": { - args: [{ name: "skip-confirmation", type: "bool", label: "Skip confirmation" }] - }, - "do-screen-transition": { - args: [{ name: "delay-ms", type: "number", label: "Delay (ms)", placeholder: "250" }] - }, - "set-column-width": { - args: [{ name: "value", type: "text", label: "Width", placeholder: "+10%, -10%, 50%" }] - }, - "set-window-height": { - args: [{ name: "value", type: "text", label: "Height", placeholder: "+10%, -10%, 50%" }] - }, - "focus-workspace": { - args: [{ name: "index", type: "number", label: "Workspace", placeholder: "1, 2, 3..." }] - }, - "move-column-to-workspace": { - args: [ - { name: "index", type: "number", label: "Workspace", placeholder: "1, 2, 3..." }, - { name: "focus", type: "bool", label: "Follow focus", default: false } - ] - }, - "move-column-to-workspace-down": { - args: [{ name: "focus", type: "bool", label: "Follow focus", default: false }] - }, - "move-column-to-workspace-up": { - args: [{ name: "focus", type: "bool", label: "Follow focus", default: false }] - }, - "screenshot": { - args: [{ name: "show-pointer", type: "bool", label: "Show pointer" }] - }, - "screenshot-screen": { - args: [ - { name: "show-pointer", type: "bool", label: "Show pointer" }, - { name: "write-to-disk", type: "bool", label: "Save to disk" } - ] - }, - "screenshot-window": { - args: [{ name: "write-to-disk", type: "bool", label: "Save to disk" }] - } -}; - -const MANGOWC_ACTION_ARGS = { - "view": { - args: [ - { name: "tag", type: "number", label: "Tag", placeholder: "1-9" }, - { name: "monitor", type: "number", label: "Monitor", placeholder: "0", default: "0" } - ] - }, - "tag": { - args: [ - { name: "tag", type: "number", label: "Tag", placeholder: "1-9" }, - { name: "monitor", type: "number", label: "Monitor", placeholder: "0", default: "0" } - ] - }, - "tagsilent": { - args: [ - { name: "tag", type: "number", label: "Tag", placeholder: "1-9" }, - { name: "monitor", type: "number", label: "Monitor", placeholder: "0", default: "0" } - ] - }, - "toggletag": { - args: [ - { name: "tag", type: "number", label: "Tag", placeholder: "1-9" }, - { name: "monitor", type: "number", label: "Monitor", placeholder: "0", default: "0" } - ] - }, - "toggleview": { - args: [ - { name: "tag", type: "number", label: "Tag", placeholder: "1-9" }, - { name: "monitor", type: "number", label: "Monitor", placeholder: "0", default: "0" } - ] - }, - "comboview": { - args: [{ name: "tags", type: "text", label: "Tags", placeholder: "1,2,3" }] - }, - "setlayout": { - args: [{ name: "layout", type: "text", label: "Layout", placeholder: "tile, monocle, grid, deck" }] - }, - "set_proportion": { - args: [{ name: "value", type: "text", label: "Proportion", placeholder: "0.5, +0.1, -0.1" }] - }, - "setmfact": { - args: [{ name: "value", type: "text", label: "Factor", placeholder: "+0.05, -0.05" }] - }, - "incgaps": { - args: [{ name: "value", type: "number", label: "Amount", placeholder: "+5, -5" }] - }, - "movewin": { - args: [{ name: "value", type: "text", label: "Position", placeholder: "x,y or +10,+10" }] - }, - "resizewin": { - args: [{ name: "value", type: "text", label: "Size", placeholder: "w,h or +10,+10" }] - }, - "setkeymode": { - args: [{ name: "mode", type: "text", label: "Mode", placeholder: "default, custom" }] - }, - "setoption": { - args: [{ name: "option", type: "text", label: "Option", placeholder: "option_name value" }] - }, - "toggle_name_scratchpad": { - args: [{ name: "name", type: "text", label: "Name", placeholder: "scratchpad name" }] - }, - "incnmaster": { - args: [{ name: "value", type: "number", label: "Amount", placeholder: "+1, -1" }] - } -}; - -const HYPRLAND_ACTION_ARGS = { - "workspace": { - args: [{ name: "value", type: "text", label: "Workspace", placeholder: "1, +1, -1, name:..." }] - }, - "movetoworkspace": { - args: [ - { name: "workspace", type: "text", label: "Workspace", placeholder: "1, +1, special:name" }, - { name: "window", type: "text", label: "Window (optional)", placeholder: "class:^(app)$" } - ] - }, - "movetoworkspacesilent": { - args: [ - { name: "workspace", type: "text", label: "Workspace", placeholder: "1, +1, special:name" }, - { name: "window", type: "text", label: "Window (optional)", placeholder: "class:^(app)$" } - ] - }, - "focusworkspaceoncurrentmonitor": { - args: [{ name: "value", type: "text", label: "Workspace", placeholder: "1, +1, name:..." }] - }, - "togglespecialworkspace": { - args: [{ name: "name", type: "text", label: "Name (optional)", placeholder: "scratchpad" }] - }, - "focusmonitor": { - args: [{ name: "value", type: "text", label: "Monitor", placeholder: "l, r, +1, DP-1" }] - }, - "movecurrentworkspacetomonitor": { - args: [{ name: "monitor", type: "text", label: "Monitor", placeholder: "l, r, DP-1" }] - }, - "moveworkspacetomonitor": { - args: [ - { name: "workspace", type: "text", label: "Workspace", placeholder: "1, name:..." }, - { name: "monitor", type: "text", label: "Monitor", placeholder: "DP-1" } - ] - }, - "swapactiveworkspaces": { - args: [ - { name: "monitor1", type: "text", label: "Monitor 1", placeholder: "DP-1" }, - { name: "monitor2", type: "text", label: "Monitor 2", placeholder: "DP-2" } - ] - }, - "renameworkspace": { - args: [ - { name: "id", type: "number", label: "Workspace ID", placeholder: "1" }, - { name: "name", type: "text", label: "New Name", placeholder: "work" } - ] - }, - "fullscreen": { - args: [{ name: "mode", type: "text", label: "Mode", placeholder: "0=full, 1=max, 2=fake" }] - }, - "fullscreenstate": { - args: [ - { name: "internal", type: "text", label: "Internal", placeholder: "-1, 0, 1, 2, 3" }, - { name: "client", type: "text", label: "Client", placeholder: "-1, 0, 1, 2, 3" } - ] - }, - "resizeactive": { - args: [{ name: "value", type: "text", label: "Size", placeholder: "10 -10, 20% 0" }] - }, - "moveactive": { - args: [{ name: "value", type: "text", label: "Position", placeholder: "10 -10, exact 100 100" }] - }, - "resizewindowpixel": { - args: [ - { name: "size", type: "text", label: "Size", placeholder: "100 100" }, - { name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" } - ] - }, - "movewindowpixel": { - args: [ - { name: "position", type: "text", label: "Position", placeholder: "100 100" }, - { name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" } - ] - }, - "splitratio": { - args: [{ name: "value", type: "text", label: "Ratio", placeholder: "+0.1, -0.1, exact 0.5" }] - }, - "closewindow": { - args: [{ name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }] - }, - "killwindow": { - args: [{ name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }] - }, - "focuswindow": { - args: [{ name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }] - }, - "tagwindow": { - args: [ - { name: "tag", type: "text", label: "Tag", placeholder: "+mytag, -mytag" }, - { name: "window", type: "text", label: "Window (optional)", placeholder: "class:^(app)$" } - ] - }, - "alterzorder": { - args: [ - { name: "zheight", type: "text", label: "Z-Height", placeholder: "top, bottom" }, - { name: "window", type: "text", label: "Window (optional)", placeholder: "class:^(app)$" } - ] - }, - "setprop": { - args: [ - { name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }, - { name: "property", type: "text", label: "Property", placeholder: "opaque, alpha..." }, - { name: "value", type: "text", label: "Value", placeholder: "1, toggle" } - ] - }, - "signal": { - args: [{ name: "signal", type: "number", label: "Signal", placeholder: "9" }] - }, - "signalwindow": { - args: [ - { name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }, - { name: "signal", type: "number", label: "Signal", placeholder: "9" } - ] - }, - "submap": { - args: [{ name: "name", type: "text", label: "Submap Name", placeholder: "resize, reset" }] - }, - "global": { - args: [{ name: "name", type: "text", label: "Shortcut Name", placeholder: "app:action" }] - }, - "event": { - args: [{ name: "data", type: "text", label: "Event Data", placeholder: "custom data" }] - }, - "pass": { - args: [{ name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" }] - }, - "sendshortcut": { - args: [ - { name: "mod", type: "text", label: "Modifier", placeholder: "SUPER, ALT" }, - { name: "key", type: "text", label: "Key", placeholder: "F4" }, - { name: "window", type: "text", label: "Window (optional)", placeholder: "class:^(app)$" } - ] - }, - "sendkeystate": { - args: [ - { name: "mod", type: "text", label: "Modifier", placeholder: "SUPER" }, - { name: "key", type: "text", label: "Key", placeholder: "a" }, - { name: "state", type: "text", label: "State", placeholder: "down, repeat, up" }, - { name: "window", type: "text", label: "Window", placeholder: "class:^(app)$" } - ] - }, - "forceidle": { - args: [{ name: "seconds", type: "number", label: "Seconds", placeholder: "300" }] - }, - "movecursortocorner": { - args: [{ name: "corner", type: "number", label: "Corner", placeholder: "0-3 (BL, BR, TR, TL)" }] - }, - "movecursor": { - args: [ - { name: "x", type: "number", label: "X", placeholder: "100" }, - { name: "y", type: "number", label: "Y", placeholder: "100" } - ] - }, - "changegroupactive": { - args: [{ name: "direction", type: "text", label: "Direction/Index", placeholder: "f, b, or index" }] - }, - "movefocus": { - args: [{ name: "direction", type: "text", label: "Direction", placeholder: "l, r, u, d" }] - }, - "movewindow": { - args: [{ name: "direction", type: "text", label: "Direction/Monitor", placeholder: "l, r, mon:DP-1" }] - }, - "swapwindow": { - args: [{ name: "direction", type: "text", label: "Direction", placeholder: "l, r, u, d" }] - }, - "moveintogroup": { - args: [{ name: "direction", type: "text", label: "Direction", placeholder: "l, r, u, d" }] - }, - "movewindoworgroup": { - args: [{ name: "direction", type: "text", label: "Direction", placeholder: "l, r, u, d" }] - }, - "cyclenext": { - args: [{ name: "options", type: "text", label: "Options", placeholder: "prev, tiled, floating" }] - } -}; - -const ACTION_ARGS = { - niri: NIRI_ACTION_ARGS, - mangowc: MANGOWC_ACTION_ARGS, - hyprland: HYPRLAND_ACTION_ARGS -}; - -const DMS_ACTION_ARGS = { - "audio increment": { - base: "spawn dms ipc call audio increment", - args: [{ name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }] - }, - "audio decrement": { - base: "spawn dms ipc call audio decrement", - args: [{ name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }] - }, - "player increment": { - base: "spawn dms ipc call mpris increment", - args: [{ name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }] - }, - "player decrement": { - base: "spawn dms ipc call mpris decrement", - args: [{ name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }] - }, - "brightness increment": { - base: "spawn dms ipc call brightness increment", - args: [ - { name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }, - { name: "device", type: "text", label: "Device", placeholder: "leave empty for default", default: "" } - ] - }, - "brightness decrement": { - base: "spawn dms ipc call brightness decrement", - args: [ - { name: "amount", type: "number", label: "Amount %", placeholder: "5", default: "5" }, - { name: "device", type: "text", label: "Device", placeholder: "leave empty for default", default: "" } - ] - }, - "brightness toggleExponential": { - base: "spawn dms ipc call brightness toggleExponential", - args: [ - { name: "device", type: "text", label: "Device", placeholder: "leave empty for default", default: "" } - ] - }, - "dash toggle": { - base: "spawn dms ipc call dash toggle", - args: [ - { name: "tab", type: "text", label: "Tab", placeholder: "overview, media, wallpaper, weather", default: "" } - ] - } -}; - -function getActionTypes() { - return ACTION_TYPES; -} - -function getDmsActionArgs() { - return DMS_ACTION_ARGS; -} - -function getDmsActions(isNiri, isHyprland) { - const result = []; - for (let i = 0; i < DMS_ACTIONS.length; i++) { - const action = DMS_ACTIONS[i]; - if (!action.compositor) { - result.push(action); - continue; - } - switch (action.compositor) { - case "niri": - if (isNiri) - result.push(action); - break; - case "hyprland": - if (isHyprland) - result.push(action); - break; - } - } - return result; -} - -function getCompositorCategories(compositor) { - var actions = COMPOSITOR_ACTIONS[compositor]; - if (!actions) - return []; - return Object.keys(actions); -} - -function getCompositorActions(compositor, category) { - var actions = COMPOSITOR_ACTIONS[compositor]; - if (!actions) - return []; - return actions[category] || []; -} - -function getCategoryOrder() { - return CATEGORY_ORDER; -} - -function findDmsAction(actionId) { - for (let i = 0; i < DMS_ACTIONS.length; i++) { - if (DMS_ACTIONS[i].id === actionId) - return DMS_ACTIONS[i]; - } - return null; -} - -function findCompositorAction(compositor, actionId) { - var actions = COMPOSITOR_ACTIONS[compositor]; - if (!actions) - return null; - for (const cat in actions) { - const acts = actions[cat]; - for (let i = 0; i < acts.length; i++) { - if (acts[i].id === actionId) - return acts[i]; - } - } - return null; -} - -function getActionLabel(action, compositor) { - if (!action) - return ""; - - var dmsAct = findDmsAction(action); - if (dmsAct) - return dmsAct.label; - - if (compositor) { - var compAct = findCompositorAction(compositor, action); - if (compAct) - return compAct.label; - var base = action.split(" ")[0]; - compAct = findCompositorAction(compositor, base); - if (compAct) - return compAct.label; - } - - if (action.startsWith("spawn sh -c ")) - return action.slice(12).replace(/^["']|["']$/g, ""); - if (action.startsWith("spawn ")) - return action.slice(6); - return action; -} - -function getActionType(action) { - if (!action) - return "compositor"; - if (action.startsWith("spawn dms ipc call ")) - return "dms"; - if (/^spawn \w+ -c /.test(action) || action.startsWith("spawn_shell ")) - return "shell"; - if (action.startsWith("spawn ")) - return "spawn"; - return "compositor"; -} - -function isDmsAction(action) { - if (!action) - return false; - return action.startsWith("spawn dms ipc call "); -} - -function isValidAction(action) { - if (!action) - return false; - switch (action) { - case "spawn": - case "spawn ": - case "spawn sh -c \"\"": - case "spawn sh -c ''": - case "spawn_shell": - case "spawn_shell ": - return false; - } - return true; -} - -function isKnownCompositorAction(compositor, action) { - if (!action || !compositor) - return false; - var found = findCompositorAction(compositor, action); - if (found) - return true; - var base = action.split(" ")[0]; - return findCompositorAction(compositor, base) !== null; -} - -function buildSpawnAction(command, args) { - if (!command) - return ""; - let parts = [command]; - if (args && args.length > 0) - parts = parts.concat(args.filter(function (a) { return a; })); - return "spawn " + parts.join(" "); -} - -function buildShellAction(compositor, shellCmd, shell) { - if (!shellCmd) - return ""; - if (compositor === "mangowc") - return "spawn_shell " + shellCmd; - var shellBin = shell || "sh"; - return "spawn " + shellBin + " -c \"" + shellCmd.replace(/"/g, "\\\"") + "\""; -} - -function parseSpawnCommand(action) { - if (!action || !action.startsWith("spawn ")) - return { command: "", args: [] }; - const rest = action.slice(6); - const parts = rest.split(" ").filter(function (p) { return p; }); - return { - command: parts[0] || "", - args: parts.slice(1) - }; -} - -function parseShellCommand(action) { - if (!action) - return ""; - var match = action.match(/^spawn (\w+) -c (.+)$/); - if (match) { - var content = match[2]; - if ((content.startsWith('"') && content.endsWith('"')) || (content.startsWith("'") && content.endsWith("'"))) - content = content.slice(1, -1); - return content.replace(/\\"/g, "\""); - } - if (action.startsWith("spawn_shell ")) - return action.slice(12); - return ""; -} - -function getShellFromAction(action) { - if (!action) - return "sh"; - var match = action.match(/^spawn (\w+) -c /); - return match ? match[1] : "sh"; -} - -function getActionArgConfig(compositor, action) { - if (!action) - return null; - - var baseAction = action.split(" ")[0]; - var compositorArgs = ACTION_ARGS[compositor]; - if (compositorArgs && compositorArgs[baseAction]) - return { type: "compositor", base: baseAction, config: compositorArgs[baseAction] }; - - for (var key in DMS_ACTION_ARGS) { - if (action.startsWith(DMS_ACTION_ARGS[key].base)) - return { type: "dms", base: key, config: DMS_ACTION_ARGS[key] }; - } - - return null; -} - -function parseCompositorActionArgs(compositor, action) { - if (!action) - return { base: "", args: {} }; - - var parts = action.split(" "); - var base = parts[0]; - var args = {}; - - var compositorArgs = ACTION_ARGS[compositor]; - if (!compositorArgs || !compositorArgs[base]) - return { base: action, args: {} }; - - var argConfig = compositorArgs[base]; - var argParts = parts.slice(1); - - switch (compositor) { - case "niri": - switch (base) { - case "move-column-to-workspace": - for (var i = 0; i < argParts.length; i++) { - if (argParts[i] === "focus=true" || argParts[i] === "focus=false") { - args.focus = argParts[i] === "focus=true"; - } else if (!args.index) { - args.index = argParts[i]; - } - } - break; - case "move-column-to-workspace-down": - case "move-column-to-workspace-up": - for (var k = 0; k < argParts.length; k++) { - if (argParts[k] === "focus=true" || argParts[k] === "focus=false") - args.focus = argParts[k] === "focus=true"; - } - break; - default: - for (var j = 0; j < argParts.length; j++) { - var kv = argParts[j].split("="); - if (kv.length === 2) { - switch (kv[1]) { - case "true": - args[kv[0]] = true; - break; - case "false": - args[kv[0]] = false; - break; - default: - args[kv[0]] = kv[1]; - } - } else { - args.value = args.value ? (args.value + " " + argParts[j]) : argParts[j]; - } - } - } - break; - case "mangowc": - if (argConfig.args && argConfig.args.length > 0 && argParts.length > 0) { - var paramStr = argParts.join(" "); - var paramValues = paramStr.split(","); - for (var m = 0; m < argConfig.args.length && m < paramValues.length; m++) { - args[argConfig.args[m].name] = paramValues[m]; - } - } - break; - case "hyprland": - if (argConfig.args && argConfig.args.length > 0) { - switch (base) { - case "resizewindowpixel": - case "movewindowpixel": - var commaIdx = argParts.join(" ").indexOf(","); - if (commaIdx !== -1) { - var fullStr = argParts.join(" "); - args[argConfig.args[0].name] = fullStr.substring(0, commaIdx); - args[argConfig.args[1].name] = fullStr.substring(commaIdx + 1); - } else if (argParts.length > 0) { - args[argConfig.args[0].name] = argParts.join(" "); - } - break; - case "movetoworkspace": - case "movetoworkspacesilent": - case "tagwindow": - case "alterzorder": - if (argParts.length >= 2) { - args[argConfig.args[0].name] = argParts[0]; - args[argConfig.args[1].name] = argParts.slice(1).join(" "); - } else if (argParts.length === 1) { - args[argConfig.args[0].name] = argParts[0]; - } - break; - case "moveworkspacetomonitor": - case "swapactiveworkspaces": - case "renameworkspace": - case "fullscreenstate": - case "movecursor": - if (argParts.length >= 2) { - args[argConfig.args[0].name] = argParts[0]; - args[argConfig.args[1].name] = argParts[1]; - } else if (argParts.length === 1) { - args[argConfig.args[0].name] = argParts[0]; - } - break; - case "setprop": - if (argParts.length >= 3) { - args.window = argParts[0]; - args.property = argParts[1]; - args.value = argParts.slice(2).join(" "); - } else if (argParts.length === 2) { - args.window = argParts[0]; - args.property = argParts[1]; - } - break; - case "sendshortcut": - if (argParts.length >= 3) { - args.mod = argParts[0]; - args.key = argParts[1]; - args.window = argParts.slice(2).join(" "); - } else if (argParts.length >= 2) { - args.mod = argParts[0]; - args.key = argParts[1]; - } - break; - case "sendkeystate": - if (argParts.length >= 4) { - args.mod = argParts[0]; - args.key = argParts[1]; - args.state = argParts[2]; - args.window = argParts.slice(3).join(" "); - } - break; - case "signalwindow": - if (argParts.length >= 2) { - args.window = argParts[0]; - args.signal = argParts[1]; - } - break; - default: - if (argParts.length > 0) { - if (argConfig.args.length === 1) { - args[argConfig.args[0].name] = argParts.join(" "); - } else { - args.value = argParts.join(" "); - } - } - } - } - break; - default: - if (argParts.length > 0) - args.value = argParts.join(" "); - } - - return { base: base, args: args }; -} - -function buildCompositorAction(compositor, base, args) { - if (!base) - return ""; - - var parts = [base]; - - if (!args || Object.keys(args).length === 0) - return base; - - switch (compositor) { - case "niri": - switch (base) { - case "move-column-to-workspace": - if (args.index) - parts.push(args.index); - if (args.focus === false) - parts.push("focus=false"); - break; - case "move-column-to-workspace-down": - case "move-column-to-workspace-up": - if (args.focus === false) - parts.push("focus=false"); - break; - default: - if (args.value) - parts.push(args.value); - else if (args.index) - parts.push(args.index); - for (var prop in args) { - switch (prop) { - case "value": - case "index": - continue; - } - var val = args[prop]; - if (val === true) - parts.push(prop + "=true"); - else if (val === false) - parts.push(prop + "=false"); - else if (val !== undefined && val !== null && val !== "") - parts.push(prop + "=" + val); - } - } - break; - case "mangowc": - var compositorArgs = ACTION_ARGS.mangowc; - if (compositorArgs && compositorArgs[base] && compositorArgs[base].args) { - var argConfig = compositorArgs[base].args; - var argValues = []; - for (var i = 0; i < argConfig.length; i++) { - var argDef = argConfig[i]; - var val = args[argDef.name]; - if (val === undefined || val === "") - val = argDef.default || ""; - if (val === "" && argValues.length === 0) - continue; - argValues.push(val); - } - if (argValues.length > 0) - parts.push(argValues.join(",")); - } else if (args.value) { - parts.push(args.value); - } - break; - case "hyprland": - var hyprArgs = ACTION_ARGS.hyprland; - if (hyprArgs && hyprArgs[base] && hyprArgs[base].args) { - var hyprConfig = hyprArgs[base].args; - switch (base) { - case "resizewindowpixel": - case "movewindowpixel": - if (args[hyprConfig[0].name]) - parts.push(args[hyprConfig[0].name]); - if (args[hyprConfig[1].name]) - parts[parts.length - 1] += "," + args[hyprConfig[1].name]; - break; - case "setprop": - if (args.window) - parts.push(args.window); - if (args.property) - parts.push(args.property); - if (args.value) - parts.push(args.value); - break; - case "sendshortcut": - if (args.mod) - parts.push(args.mod); - if (args.key) - parts.push(args.key); - if (args.window) - parts.push(args.window); - break; - case "sendkeystate": - if (args.mod) - parts.push(args.mod); - if (args.key) - parts.push(args.key); - if (args.state) - parts.push(args.state); - if (args.window) - parts.push(args.window); - break; - case "signalwindow": - if (args.window) - parts.push(args.window); - if (args.signal) - parts.push(args.signal); - break; - default: - for (var j = 0; j < hyprConfig.length; j++) { - var hVal = args[hyprConfig[j].name]; - if (hVal !== undefined && hVal !== "") - parts.push(hVal); - } - } - } else if (args.value) { - parts.push(args.value); - } - break; - default: - if (args.value) - parts.push(args.value); - } - - return parts.join(" "); -} - -function parseDmsActionArgs(action) { - if (!action) - return { base: "", args: {} }; - - for (var key in DMS_ACTION_ARGS) { - var config = DMS_ACTION_ARGS[key]; - if (!action.startsWith(config.base)) - continue; - - var rest = action.slice(config.base.length).trim(); - var result = { base: key, args: {} }; - - if (!rest) - return result; - - var tokens = []; - var current = ""; - var inQuotes = false; - var hadQuotes = false; - for (var i = 0; i < rest.length; i++) { - var c = rest[i]; - switch (c) { - case '"': - inQuotes = !inQuotes; - hadQuotes = true; - break; - case ' ': - if (inQuotes) { - current += c; - } else if (current || hadQuotes) { - tokens.push(current); - current = ""; - hadQuotes = false; - } - break; - default: - current += c; - break; - } - } - if (current || hadQuotes) - tokens.push(current); - - for (var j = 0; j < config.args.length && j < tokens.length; j++) { - result.args[config.args[j].name] = tokens[j]; - } - - return result; - } - - return { base: action, args: {} }; -} - -function buildDmsAction(baseKey, args) { - var config = DMS_ACTION_ARGS[baseKey]; - if (!config) - return ""; - - var parts = [config.base]; - - for (var i = 0; i < config.args.length; i++) { - var argDef = config.args[i]; - var value = args?.[argDef.name]; - if (value === undefined || value === null) - value = argDef.default ?? ""; - - if (argDef.type === "text" && value === "") { - parts.push('""'); - } else if (value !== "") { - parts.push(value); - } else { - break; - } - } - - return parts.join(" "); -} - -function getScreenshotOptions() { - return [ - { id: "write-to-disk", label: "Save to disk", type: "bool" }, - { id: "show-pointer", label: "Show pointer", type: "bool" } - ]; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ListViewTransitions.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ListViewTransitions.qml deleted file mode 100644 index 2ccefc8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ListViewTransitions.qml +++ /dev/null @@ -1,46 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -// Reusable ListView/GridView transitions -Singleton { - id: root - - readonly property Transition add: Transition { - DankAnim { - property: "opacity" - from: 0 - to: 1 - duration: Theme.expressiveDurations.expressiveEffects - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - readonly property Transition remove: Transition { - DankAnim { - property: "opacity" - to: 0 - duration: Theme.expressiveDurations.fast - easing.bezierCurve: Theme.expressiveCurves.emphasizedAccel - } - } - - readonly property Transition displaced: Transition { - DankAnim { - property: "y" - duration: Theme.expressiveDurations.normal - easing.bezierCurve: Theme.expressiveCurves.expressiveEffects - } - } - - readonly property Transition move: Transition { - DankAnim { - property: "y" - duration: Theme.expressiveDurations.normal - easing.bezierCurve: Theme.expressiveCurves.expressiveEffects - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ModalManager.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ModalManager.qml deleted file mode 100644 index 75b11f7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/ModalManager.qml +++ /dev/null @@ -1,35 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick - -Singleton { - id: modalManager - - signal closeAllModalsExcept(var excludedModal) - signal modalChanged - - property var currentModalsByScreen: ({}) - - function openModal(modal) { - const screenName = modal.effectiveScreen?.name ?? "unknown"; - currentModalsByScreen[screenName] = modal; - modalChanged(); - Qt.callLater(() => { - if (!modal.allowStacking) - closeAllModalsExcept(modal); - if (!modal.keepPopoutsOpen) - PopoutManager.closeAllPopouts(); - TrayMenuManager.closeAllMenus(); - }); - } - - function closeModal(modal) { - const screenName = modal.effectiveScreen?.name ?? "unknown"; - if (currentModalsByScreen[screenName] === modal) { - delete currentModalsByScreen[screenName]; - modalChanged(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/OSDManager.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/OSDManager.qml deleted file mode 100644 index 06bc07f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/OSDManager.qml +++ /dev/null @@ -1,46 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick - -Singleton { - id: osdManager - - property var currentOSDsByScreen: ({}) - - Connections { - target: Quickshell - function onScreensChanged() { - const activeNames = {}; - for (let i = 0; i < Quickshell.screens.length; i++) - activeNames[Quickshell.screens[i].name] = true; - for (const screenName in osdManager.currentOSDsByScreen) { - if (activeNames[screenName]) - continue; - osdManager.currentOSDsByScreen[screenName] = null; - } - } - } - - function showOSD(osd) { - if (!osd || !osd.screen) - return; - const screenName = osd.screen.name; - const currentOSD = currentOSDsByScreen[screenName]; - - if (currentOSD && currentOSD !== osd) { - if (typeof currentOSD.hide === "function") { - try { - currentOSD.hide(); - } catch (e) { - currentOSDsByScreen[screenName] = null; - } - } else { - currentOSDsByScreen[screenName] = null; - } - } - - currentOSDsByScreen[screenName] = osd; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Paths.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Paths.qml deleted file mode 100644 index 19a4b16..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Paths.qml +++ /dev/null @@ -1,131 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtCore -import qs.Services - -Singleton { - id: root - - readonly property url home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] - readonly property url pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0] - readonly property url xdgCache: StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0] - - readonly property url data: `${StandardPaths.standardLocations(StandardPaths.GenericDataLocation)[0]}/DankMaterialShell` - readonly property url state: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/DankMaterialShell` - readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/DankMaterialShell` - readonly property url config: `${StandardPaths.standardLocations(StandardPaths.GenericConfigLocation)[0]}/DankMaterialShell` - - readonly property url imagecache: `${cache}/imagecache` - - function stringify(path: url): string { - return path.toString().replace(/%20/g, " "); - } - - function expandTilde(path: string): string { - return strip(path.replace("~", stringify(root.home))); - } - - function shortenHome(path: string): string { - return path.replace(strip(root.home), "~"); - } - - function strip(path: url): string { - return stringify(path).replace("file://", ""); - } - - function toFileUrl(path: string): string { - return path.startsWith("file://") ? path : "file://" + path; - } - - function mkdir(path: url): void { - Quickshell.execDetached(["mkdir", "-p", strip(path)]); - } - - function copy(from: url, to: url): void { - Quickshell.execDetached(["cp", strip(from), strip(to)]); - } - - function isSteamApp(appId: string): bool { - return appId && /^steam_app_\d+$/.test(appId); - } - - function moddedAppId(appId: string): string { - const subs = SettingsData.appIdSubstitutions || []; - for (let i = 0; i < subs.length; i++) { - const sub = subs[i]; - if (sub.type === "exact" && appId === sub.pattern) { - return sub.replacement; - } else if (sub.type === "contains" && appId.includes(sub.pattern)) { - return sub.replacement; - } else if (sub.type === "regex") { - const match = appId.match(new RegExp(sub.pattern)); - if (match) { - return sub.replacement.replace(/\$(\d+)/g, (_, n) => match[n] || ""); - } - } - } - const steamMatch = appId.match(/^steam_app_(\d+)$/); - if (steamMatch) - return `steam_icon_${steamMatch[1]}`; - return appId; - } - - function resolveIconPath(iconName: string): string { - if (!iconName) - return ""; - const moddedId = moddedAppId(iconName); - if (moddedId !== iconName) { - if (moddedId.startsWith("~") || moddedId.startsWith("/")) - return toFileUrl(expandTilde(moddedId)); - if (moddedId.startsWith("file://")) - return moddedId; - return Quickshell.iconPath(moddedId, true); - } - return Quickshell.iconPath(iconName, true) || DesktopService.resolveIconPath(iconName); - } - - function resolveIconUrl(iconName: string): string { - if (!iconName) - return ""; - const moddedId = moddedAppId(iconName); - if (moddedId !== iconName) { - if (moddedId.startsWith("~") || moddedId.startsWith("/")) - return toFileUrl(expandTilde(moddedId)); - if (moddedId.startsWith("file://")) - return moddedId; - return "image://icon/" + moddedId; - } - return "image://icon/" + iconName; - } - - function getAppIcon(appId: string, desktopEntry: var): string { - // ! TODO - after QS 0.3, we can install our icon properly - if (appId === "org.quickshell" || appId === "com.danklinux.dms") { - return Qt.resolvedUrl("../assets/danklogo.svg"); - } - - const moddedId = moddedAppId(appId); - if (moddedId !== appId) - return resolveIconPath(appId); - - if (desktopEntry && desktopEntry.icon) { - return Quickshell.iconPath(desktopEntry.icon, true); - } - - const icon = Quickshell.iconPath(appId, true); - if (icon && icon !== "") - return icon; - - return DesktopService.resolveIconPath(appId); - } - - function getAppName(appId: string, desktopEntry: var): string { - if (appId === "org.quickshell" || appId === "com.danklinux.dms") { - return "dms"; - } - - return desktopEntry && desktopEntry.name ? desktopEntry.name : appId; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/PopoutManager.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/PopoutManager.qml deleted file mode 100644 index 47b4eda..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/PopoutManager.qml +++ /dev/null @@ -1,186 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick - -Singleton { - id: root - - property var currentPopoutsByScreen: ({}) - property var currentPopoutTriggers: ({}) - - signal popoutOpening - signal popoutChanged - - function _closePopout(popout) { - try { - switch (true) { - case popout.dashVisible !== undefined: - popout.dashVisible = false; - return; - case popout.notificationHistoryVisible !== undefined: - popout.notificationHistoryVisible = false; - return; - default: - if (typeof popout.close !== "function") - return; - popout.close(); - } - } catch (e) { - return; - } - } - - function _isStale(popout) { - try { - if (!popout || !("shouldBeVisible" in popout)) - return true; - if (!popout.screen) - return true; - return false; - } catch (e) { - return true; - } - } - - function showPopout(popout) { - if (!popout || !popout.screen) - return; - popoutOpening(); - - const screenName = popout.screen.name; - - for (const otherScreenName in currentPopoutsByScreen) { - const otherPopout = currentPopoutsByScreen[otherScreenName]; - if (!otherPopout || otherPopout === popout) - continue; - if (_isStale(otherPopout)) { - currentPopoutsByScreen[otherScreenName] = null; - continue; - } - _closePopout(otherPopout); - } - - currentPopoutsByScreen[screenName] = popout; - popoutChanged(); - ModalManager.closeAllModalsExcept(null); - } - - function hidePopout(popout) { - if (!popout || !popout.screen) - return; - const screenName = popout.screen.name; - if (currentPopoutsByScreen[screenName] === popout) { - currentPopoutsByScreen[screenName] = null; - currentPopoutTriggers[screenName] = null; - popoutChanged(); - } - } - - function closeAllPopouts() { - for (const screenName in currentPopoutsByScreen) { - const popout = currentPopoutsByScreen[screenName]; - if (!popout || _isStale(popout)) - continue; - _closePopout(popout); - } - currentPopoutsByScreen = {}; - } - - function getActivePopout(screen) { - if (!screen) - return null; - return currentPopoutsByScreen[screen.name] || null; - } - - function requestPopout(popout, tabIndex, triggerSource) { - if (!popout || !popout.screen) - return; - const screenName = popout.screen.name; - const currentPopout = currentPopoutsByScreen[screenName]; - const triggerId = triggerSource !== undefined ? triggerSource : tabIndex; - - const willOpen = !(currentPopout === popout && popout.shouldBeVisible && triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId); - if (willOpen) { - popoutOpening(); - } - - let movedFromOtherScreen = false; - for (const otherScreenName in currentPopoutsByScreen) { - if (otherScreenName === screenName) - continue; - const otherPopout = currentPopoutsByScreen[otherScreenName]; - if (!otherPopout) - continue; - - if (_isStale(otherPopout)) { - currentPopoutsByScreen[otherScreenName] = null; - currentPopoutTriggers[otherScreenName] = null; - continue; - } - - if (otherPopout === popout) { - movedFromOtherScreen = true; - currentPopoutsByScreen[otherScreenName] = null; - currentPopoutTriggers[otherScreenName] = null; - continue; - } - - _closePopout(otherPopout); - } - - if (currentPopout && currentPopout !== popout) { - if (_isStale(currentPopout)) { - currentPopoutsByScreen[screenName] = null; - currentPopoutTriggers[screenName] = null; - } else { - _closePopout(currentPopout); - } - } - - if (currentPopout === popout && popout.shouldBeVisible && !movedFromOtherScreen) { - if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) { - _closePopout(popout); - return; - } - - if (triggerId === undefined) { - _closePopout(popout); - return; - } - - if (tabIndex !== undefined && popout.currentTabIndex !== undefined) { - popout.currentTabIndex = tabIndex; - } - if (popout.updateSurfacePosition) - popout.updateSurfacePosition(); - currentPopoutTriggers[screenName] = triggerId; - return; - } - - currentPopoutTriggers[screenName] = triggerId; - currentPopoutsByScreen[screenName] = popout; - popoutChanged(); - - if (tabIndex !== undefined && popout.currentTabIndex !== undefined) { - popout.currentTabIndex = tabIndex; - } - - if (currentPopout !== popout) { - ModalManager.closeAllModalsExcept(null); - } - - if (movedFromOtherScreen) { - popout.open(); - } else { - if (popout.dashVisible !== undefined) { - popout.dashVisible = true; - } else if (popout.notificationHistoryVisible !== undefined) { - popout.notificationHistoryVisible = true; - } else { - popout.open(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Proc.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Proc.qml deleted file mode 100644 index 813f938..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Proc.qml +++ /dev/null @@ -1,141 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - readonly property int noTimeout: -1 - property int defaultDebounceMs: 50 - property int defaultTimeoutMs: 10000 - property var _procDebouncers: ({}) - - function runCommand(id, command, callback, debounceMs, timeoutMs) { - const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs; - const timeout = (typeof timeoutMs === "number") ? timeoutMs : defaultTimeoutMs; - let procId = id ? id : Math.random(); - const isRandomId = !id; - - if (!_procDebouncers[procId]) { - const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root); - t.triggered.connect(function () { - _launchProc(procId, isRandomId); - }); - _procDebouncers[procId] = { - timer: t, - command: command, - callback: callback, - waitMs: wait, - timeoutMs: timeout, - isRandomId: isRandomId - }; - } else { - _procDebouncers[procId].command = command; - _procDebouncers[procId].callback = callback; - _procDebouncers[procId].waitMs = wait; - _procDebouncers[procId].timeoutMs = timeout; - } - - const entry = _procDebouncers[procId]; - entry.timer.interval = entry.waitMs; - entry.timer.restart(); - } - - function _launchProc(id, isRandomId) { - const entry = _procDebouncers[id]; - if (!entry) - return; - const proc = Qt.createQmlObject('import Quickshell.Io; Process { running: false }', root); - const out = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc); - const err = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc); - const timeoutTimer = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root); - - proc.stdout = out; - proc.stderr = err; - proc.command = entry.command; - - let capturedOut = ""; - let capturedErr = ""; - let exitSeen = false; - let exitCodeValue = -1; - let outSeen = false; - let errSeen = false; - let timedOut = false; - - timeoutTimer.interval = entry.timeoutMs; - timeoutTimer.triggered.connect(function () { - if (!exitSeen) { - timedOut = true; - proc.running = false; - exitSeen = true; - exitCodeValue = 124; - maybeComplete(); - } - }); - - out.streamFinished.connect(function () { - try { - capturedOut = out.text || ""; - } catch (e) { - capturedOut = ""; - } - outSeen = true; - maybeComplete(); - }); - - err.streamFinished.connect(function () { - try { - capturedErr = err.text || ""; - } catch (e) { - capturedErr = ""; - } - errSeen = true; - maybeComplete(); - }); - - proc.exited.connect(function (code) { - timeoutTimer.stop(); - exitSeen = true; - exitCodeValue = code; - maybeComplete(); - }); - - function maybeComplete() { - if (!exitSeen || !outSeen || !errSeen) - return; - timeoutTimer.stop(); - if (entry && entry.callback && typeof entry.callback === "function") { - try { - const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : ""; - const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1; - entry.callback(safeOutput, safeExitCode); - } catch (e) { - console.warn("runCommand callback error for command:", entry.command, "Error:", e); - } - } - try { - proc.destroy(); - } catch (_) {} - try { - timeoutTimer.destroy(); - } catch (_) {} - - if (isRandomId || entry.isRandomId) { - Qt.callLater(function () { - if (_procDebouncers[id]) { - try { - _procDebouncers[id].timer.destroy(); - } catch (_) {} - delete _procDebouncers[id]; - } - }); - } - } - - proc.running = true; - if (entry.timeoutMs !== noTimeout) - timeoutTimer.start(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Ref.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Ref.qml deleted file mode 100644 index 406b50c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Ref.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick -import Quickshell - -QtObject { - required property Singleton service - - Component.onCompleted: service.refCount++ - Component.onDestruction: service.refCount-- -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SessionData.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SessionData.qml deleted file mode 100644 index 13b1359..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SessionData.qml +++ /dev/null @@ -1,1437 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import "settings/SessionSpec.js" as Spec -import "settings/SessionStore.js" as Store - -Singleton { - id: root - - readonly property int sessionConfigVersion: 3 - - readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" - property bool _parseError: false - property bool _hasLoaded: false - property bool _isReadOnly: false - property bool _hasUnsavedChanges: false - property var _loadedSessionSnapshot: null - readonly property var _hooks: ({ - "updateLocale": updateLocale - }) - readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation) - readonly property string _stateDir: Paths.strip(_stateUrl) - - property bool isLightMode: false - property bool doNotDisturb: false - property bool isSwitchingMode: false - property bool suppressOSD: true - - Timer { - id: osdSuppressTimer - interval: 2000 - running: true - onTriggered: root.suppressOSD = false - } - - function suppressOSDTemporarily() { - suppressOSD = true; - osdSuppressTimer.restart(); - } - - Connections { - target: SessionService - function onSessionResumed() { - root.suppressOSD = true; - osdSuppressTimer.restart(); - } - } - - property string wallpaperPath: "/usr/share/raveos/hyprland-theme/theme-data/background" - property bool perMonitorWallpaper: false - property var monitorWallpapers: ({}) - property bool perModeWallpaper: false - property string wallpaperPathLight: "" - property string wallpaperPathDark: "" - property var monitorWallpapersLight: ({}) - property var monitorWallpapersDark: ({}) - property var monitorWallpaperFillModes: ({}) - property string wallpaperTransition: "fade" - readonly property var availableWallpaperTransitions: ["none", "fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] - property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none") - - property bool wallpaperCyclingEnabled: false - property string wallpaperCyclingMode: "interval" - property int wallpaperCyclingInterval: 300 - property string wallpaperCyclingTime: "06:00" - property var monitorCyclingSettings: ({}) - - property bool nightModeEnabled: false - property int nightModeTemperature: 4500 - property int nightModeHighTemperature: 6500 - property bool nightModeAutoEnabled: false - property string nightModeAutoMode: "time" - property int nightModeStartHour: 18 - property int nightModeStartMinute: 0 - property int nightModeEndHour: 6 - property int nightModeEndMinute: 0 - property real latitude: 0.0 - property real longitude: 0.0 - property bool nightModeUseIPLocation: false - property string nightModeLocationProvider: "" - - property bool themeModeAutoEnabled: false - property string themeModeAutoMode: "time" - property int themeModeStartHour: 18 - property int themeModeStartMinute: 0 - property int themeModeEndHour: 6 - property int themeModeEndMinute: 0 - property bool themeModeShareGammaSettings: true - property string themeModeNextTransition: "" - - property var pinnedApps: [] - property var barPinnedApps: [] - property int dockLauncherPosition: 0 - property var hiddenTrayIds: [] - property var trayItemOrder: [] - property var recentColors: [] - property bool showThirdPartyPlugins: false - property string launchPrefix: "" - property string lastBrightnessDevice: "" - property var brightnessExponentialDevices: ({}) - property var brightnessUserSetValues: ({}) - property var brightnessExponentValues: ({}) - - property int selectedGpuIndex: 0 - property bool nvidiaGpuTempEnabled: false - property bool nonNvidiaGpuTempEnabled: false - property var enabledGpuPciIds: [] - - property string wifiDeviceOverride: "" - property bool weatherHourlyDetailed: true - - property string weatherLocation: "New York, NY" - property string weatherCoordinates: "40.7128,-74.0060" - - property var hiddenApps: [] - property var appOverrides: ({}) - property bool searchAppActions: true - - property string vpnLastConnected: "" - - property string lastPlayerIdentity: "" - - property var deviceMaxVolumes: ({}) - property var hiddenOutputDeviceNames: [] - property var hiddenInputDeviceNames: [] - - property string locale: "" - property string timeLocale: "" - - property string launcherLastMode: "all" - property string launcherLastQuery: "" - property var launcherQueryHistory: [] - property string appDrawerLastMode: "apps" - property string niriOverviewLastMode: "apps" - property string settingsSidebarExpandedIds: "," - property string settingsSidebarCollapsedIds: "," - - Component.onCompleted: { - if (!isGreeterMode) { - loadSettings(); - } - } - - property var _pendingMigration: null - - function loadSettings() { - _hasUnsavedChanges = false; - _pendingMigration = null; - - if (isGreeterMode) { - parseSettings(greeterSessionFile.text()); - return; - } - - try { - const txt = settingsFile.text(); - let obj = (txt && txt.trim()) ? JSON.parse(txt) : null; - - if (obj?.brightnessLogarithmicDevices && !obj?.brightnessExponentialDevices) - obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices; - - if (obj?.nightModeStartTime !== undefined) { - const parts = obj.nightModeStartTime.split(":"); - obj.nightModeStartHour = parseInt(parts[0]) || 18; - obj.nightModeStartMinute = parseInt(parts[1]) || 0; - } - if (obj?.nightModeEndTime !== undefined) { - const parts = obj.nightModeEndTime.split(":"); - obj.nightModeEndHour = parseInt(parts[0]) || 6; - obj.nightModeEndMinute = parseInt(parts[1]) || 0; - } - - const oldVersion = obj?.configVersion ?? 0; - if (obj && oldVersion === 0) - migrateFromUndefinedToV1(obj); - - if (obj && oldVersion < sessionConfigVersion) { - const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null; - const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef); - if (migrated) { - _pendingMigration = migrated; - obj = migrated; - } - } - - Store.parse(root, obj); - - _loadedSessionSnapshot = getCurrentSessionJson(); - _hasLoaded = true; - - if (!isGreeterMode && typeof Theme !== "undefined") - Theme.generateSystemThemesFromCurrentTheme(); - - if (typeof WallpaperCyclingService !== "undefined") - WallpaperCyclingService.updateCyclingState(); - - _checkSessionWritable(); - } catch (e) { - _parseError = true; - const msg = e.message; - console.error("SessionData: Failed to parse session.json - file will not be overwritten."); - Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg)); - } - } - - function _checkSessionWritable() { - sessionWritableCheckProcess.running = true; - } - - function _onWritableCheckComplete(writable) { - const wasReadOnly = _isReadOnly; - _isReadOnly = !writable; - if (_isReadOnly) { - _hasUnsavedChanges = _checkForUnsavedChanges(); - } else { - _loadedSessionSnapshot = getCurrentSessionJson(); - _hasUnsavedChanges = false; - if (wasReadOnly && _pendingMigration) - settingsFile.setText(JSON.stringify(_pendingMigration, null, 2)); - } - _pendingMigration = null; - } - - function _checkForUnsavedChanges() { - if (!_hasLoaded || !_loadedSessionSnapshot) - return false; - const current = getCurrentSessionJson(); - return current !== _loadedSessionSnapshot; - } - - function getCurrentSessionJson() { - return JSON.stringify(Store.toJson(root), null, 2); - } - - function parseSettings(content) { - _parseError = false; - try { - let obj = (content && content.trim()) ? JSON.parse(content) : null; - - if (obj?.brightnessLogarithmicDevices && !obj?.brightnessExponentialDevices) - obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices; - - if (obj?.nightModeStartTime !== undefined) { - const parts = obj.nightModeStartTime.split(":"); - obj.nightModeStartHour = parseInt(parts[0]) || 18; - obj.nightModeStartMinute = parseInt(parts[1]) || 0; - } - if (obj?.nightModeEndTime !== undefined) { - const parts = obj.nightModeEndTime.split(":"); - obj.nightModeEndHour = parseInt(parts[0]) || 6; - obj.nightModeEndMinute = parseInt(parts[1]) || 0; - } - - const oldVersion = obj?.configVersion ?? 0; - if (obj && oldVersion === 0) - migrateFromUndefinedToV1(obj); - - if (obj && oldVersion < sessionConfigVersion) { - const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null; - const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef); - if (migrated) { - _pendingMigration = migrated; - obj = migrated; - } - } - - Store.parse(root, obj); - - _loadedSessionSnapshot = getCurrentSessionJson(); - _hasLoaded = true; - - if (!isGreeterMode && typeof Theme !== "undefined") - Theme.generateSystemThemesFromCurrentTheme(); - - if (typeof WallpaperCyclingService !== "undefined") - WallpaperCyclingService.updateCyclingState(); - } catch (e) { - _parseError = true; - const msg = e.message; - console.error("SessionData: Failed to parse session.json - file will not be overwritten."); - Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg)); - } - } - - function saveSettings() { - if (isGreeterMode || _parseError || !_hasLoaded) - return; - settingsFile.setText(getCurrentSessionJson()); - if (_isReadOnly) - _checkSessionWritable(); - } - - function set(key, value) { - Spec.set(root, key, value, saveSettings, _hooks); - } - - function migrateFromUndefinedToV1(settings) { - if (typeof SettingsData !== "undefined") { - if (settings.acMonitorTimeout !== undefined) { - SettingsData.set("acMonitorTimeout", settings.acMonitorTimeout); - } - if (settings.acLockTimeout !== undefined) { - SettingsData.set("acLockTimeout", settings.acLockTimeout); - } - if (settings.acSuspendTimeout !== undefined) { - SettingsData.set("acSuspendTimeout", settings.acSuspendTimeout); - } - if (settings.acHibernateTimeout !== undefined) { - SettingsData.set("acHibernateTimeout", settings.acHibernateTimeout); - } - if (settings.batteryMonitorTimeout !== undefined) { - SettingsData.set("batteryMonitorTimeout", settings.batteryMonitorTimeout); - } - if (settings.batteryLockTimeout !== undefined) { - SettingsData.set("batteryLockTimeout", settings.batteryLockTimeout); - } - if (settings.batterySuspendTimeout !== undefined) { - SettingsData.set("batterySuspendTimeout", settings.batterySuspendTimeout); - } - if (settings.batteryHibernateTimeout !== undefined) { - SettingsData.set("batteryHibernateTimeout", settings.batteryHibernateTimeout); - } - if (settings.lockBeforeSuspend !== undefined) { - SettingsData.set("lockBeforeSuspend", settings.lockBeforeSuspend); - } - if (settings.loginctlLockIntegration !== undefined) { - SettingsData.set("loginctlLockIntegration", settings.loginctlLockIntegration); - } - if (settings.launchPrefix !== undefined) { - SettingsData.set("launchPrefix", settings.launchPrefix); - } - } - if (typeof CacheData !== "undefined") { - if (settings.wallpaperLastPath !== undefined) { - CacheData.wallpaperLastPath = settings.wallpaperLastPath; - } - if (settings.profileLastPath !== undefined) { - CacheData.profileLastPath = settings.profileLastPath; - } - CacheData.saveCache(); - } - } - - function setLightMode(lightMode) { - isSwitchingMode = true; - syncWallpaperForCurrentMode(lightMode); - isLightMode = lightMode; - saveSettings(); - Qt.callLater(() => { - isSwitchingMode = false; - }); - } - - function setDoNotDisturb(enabled) { - doNotDisturb = enabled; - saveSettings(); - } - - function setWallpaperPath(path) { - wallpaperPath = path; - saveSettings(); - } - - function setWallpaper(imagePath) { - wallpaperPath = imagePath; - if (perModeWallpaper) { - if (isLightMode) { - wallpaperPathLight = imagePath; - } else { - wallpaperPathDark = imagePath; - } - } - saveSettings(); - - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setWallpaperColor(color) { - wallpaperPath = color; - if (perModeWallpaper) { - if (isLightMode) { - wallpaperPathLight = color; - } else { - wallpaperPathDark = color; - } - } - saveSettings(); - - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function clearWallpaper() { - wallpaperPath = ""; - saveSettings(); - - if (typeof Theme !== "undefined") { - if (typeof SettingsData !== "undefined" && SettingsData.theme) { - Theme.switchTheme(SettingsData.theme); - } else { - Theme.switchTheme("purple"); - } - } - } - - function setPerMonitorWallpaper(enabled) { - perMonitorWallpaper = enabled; - if (enabled && perModeWallpaper) { - syncWallpaperForCurrentMode(); - } - saveSettings(); - - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setPerModeWallpaper(enabled) { - if (enabled && wallpaperCyclingEnabled) { - setWallpaperCyclingEnabled(false); - } - if (enabled && perMonitorWallpaper) { - var monitorCyclingAny = false; - for (var key in monitorCyclingSettings) { - if (monitorCyclingSettings[key].enabled) { - monitorCyclingAny = true; - break; - } - } - if (monitorCyclingAny) { - var newSettings = Object.assign({}, monitorCyclingSettings); - for (var screenName in newSettings) { - newSettings[screenName].enabled = false; - } - monitorCyclingSettings = newSettings; - } - } - - perModeWallpaper = enabled; - if (enabled) { - if (perMonitorWallpaper) { - monitorWallpapersLight = Object.assign({}, monitorWallpapers); - monitorWallpapersDark = Object.assign({}, monitorWallpapers); - } else { - wallpaperPathLight = wallpaperPath; - wallpaperPathDark = wallpaperPath; - } - } else { - syncWallpaperForCurrentMode(); - } - saveSettings(); - - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setMonitorWallpaper(screenName, path) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - console.warn("SessionData: Screen not found"); - return; - } - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newMonitorWallpapers = {}; - for (var key in monitorWallpapers) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newMonitorWallpapers[key] = monitorWallpapers[key]; - } - } - - if (path && path !== "") { - newMonitorWallpapers[identifier] = path; - } - - monitorWallpapers = newMonitorWallpapers; - - if (perModeWallpaper) { - if (isLightMode) { - var newLight = {}; - for (var key in monitorWallpapersLight) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newLight[key] = monitorWallpapersLight[key]; - } - } - if (path && path !== "") { - newLight[identifier] = path; - } - monitorWallpapersLight = newLight; - } else { - var newDark = {}; - for (var key in monitorWallpapersDark) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newDark[key] = monitorWallpapersDark[key]; - } - } - if (path && path !== "") { - newDark[identifier] = path; - } - monitorWallpapersDark = newDark; - } - } - - saveSettings(); - - if (typeof Theme !== "undefined" && typeof Quickshell !== "undefined" && typeof SettingsData !== "undefined") { - var screens = Quickshell.screens; - if (screens.length > 0) { - var targetMonitor = (SettingsData.matugenTargetMonitor && SettingsData.matugenTargetMonitor !== "") ? SettingsData.matugenTargetMonitor : screens[0].name; - if (screenName === targetMonitor) { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - } - } - - function setWallpaperTransition(transition) { - wallpaperTransition = transition; - saveSettings(); - } - - function setWallpaperCyclingEnabled(enabled) { - wallpaperCyclingEnabled = enabled; - saveSettings(); - } - - function setWallpaperCyclingMode(mode) { - wallpaperCyclingMode = mode; - saveSettings(); - } - - function setWallpaperCyclingInterval(interval) { - wallpaperCyclingInterval = interval; - saveSettings(); - } - - function setWallpaperCyclingTime(time) { - wallpaperCyclingTime = time; - saveSettings(); - } - - function setMonitorCyclingEnabled(screenName, enabled) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - console.warn("SessionData: Screen not found"); - return; - } - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newSettings = {}; - for (var key in monitorCyclingSettings) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newSettings[key] = monitorCyclingSettings[key]; - } - } - - newSettings[identifier] = getMonitorCyclingSettings(screenName); - newSettings[identifier].enabled = enabled; - monitorCyclingSettings = newSettings; - saveSettings(); - } - - function setMonitorCyclingMode(screenName, mode) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - console.warn("SessionData: Screen not found"); - return; - } - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newSettings = {}; - for (var key in monitorCyclingSettings) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newSettings[key] = monitorCyclingSettings[key]; - } - } - - newSettings[identifier] = getMonitorCyclingSettings(screenName); - newSettings[identifier].mode = mode; - monitorCyclingSettings = newSettings; - saveSettings(); - } - - function setMonitorCyclingInterval(screenName, interval) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - console.warn("SessionData: Screen not found"); - return; - } - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newSettings = {}; - for (var key in monitorCyclingSettings) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newSettings[key] = monitorCyclingSettings[key]; - } - } - - newSettings[identifier] = getMonitorCyclingSettings(screenName); - newSettings[identifier].interval = interval; - monitorCyclingSettings = newSettings; - saveSettings(); - } - - function setMonitorCyclingTime(screenName, time) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - console.warn("SessionData: Screen not found"); - return; - } - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newSettings = {}; - for (var key in monitorCyclingSettings) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) { - newSettings[key] = monitorCyclingSettings[key]; - } - } - - newSettings[identifier] = getMonitorCyclingSettings(screenName); - newSettings[identifier].time = time; - monitorCyclingSettings = newSettings; - saveSettings(); - } - - function setNightModeEnabled(enabled) { - nightModeEnabled = enabled; - saveSettings(); - } - - function setNightModeTemperature(temperature) { - nightModeTemperature = temperature; - saveSettings(); - } - - function setNightModeHighTemperature(temperature) { - nightModeHighTemperature = temperature; - saveSettings(); - } - - function setNightModeAutoEnabled(enabled) { - nightModeAutoEnabled = enabled; - saveSettings(); - } - - function setNightModeAutoMode(mode) { - nightModeAutoMode = mode; - saveSettings(); - } - - function setNightModeStartHour(hour) { - nightModeStartHour = hour; - saveSettings(); - } - - function setNightModeStartMinute(minute) { - nightModeStartMinute = minute; - saveSettings(); - } - - function setNightModeEndHour(hour) { - nightModeEndHour = hour; - saveSettings(); - } - - function setNightModeEndMinute(minute) { - nightModeEndMinute = minute; - saveSettings(); - } - - function setNightModeUseIPLocation(use) { - nightModeUseIPLocation = use; - saveSettings(); - } - - function setLatitude(lat) { - latitude = lat; - saveSettings(); - } - - function setLongitude(lng) { - longitude = lng; - saveSettings(); - } - - function setNightModeLocationProvider(provider) { - nightModeLocationProvider = provider; - saveSettings(); - } - - function setThemeModeAutoEnabled(enabled) { - themeModeAutoEnabled = enabled; - saveSettings(); - } - - function setThemeModeAutoMode(mode) { - themeModeAutoMode = mode; - saveSettings(); - } - - function setThemeModeStartHour(hour) { - themeModeStartHour = hour; - saveSettings(); - } - - function setThemeModeStartMinute(minute) { - themeModeStartMinute = minute; - saveSettings(); - } - - function setThemeModeEndHour(hour) { - themeModeEndHour = hour; - saveSettings(); - } - - function setThemeModeEndMinute(minute) { - themeModeEndMinute = minute; - saveSettings(); - } - - function setThemeModeShareGammaSettings(share) { - themeModeShareGammaSettings = share; - saveSettings(); - } - - function setPinnedApps(apps) { - pinnedApps = apps; - saveSettings(); - } - - function setDockLauncherPosition(position) { - dockLauncherPosition = position; - saveSettings(); - } - - function addPinnedApp(appId) { - if (!appId) - return; - var currentPinned = [...pinnedApps]; - if (currentPinned.indexOf(appId) === -1) { - currentPinned.push(appId); - setPinnedApps(currentPinned); - } - } - - function removePinnedApp(appId) { - if (!appId) - return; - var currentPinned = pinnedApps.filter(id => id !== appId); - setPinnedApps(currentPinned); - } - - function isPinnedApp(appId) { - return appId && pinnedApps.indexOf(appId) !== -1; - } - - function setBarPinnedApps(apps) { - barPinnedApps = apps; - saveSettings(); - } - - function addBarPinnedApp(appId) { - if (!appId) - return; - var currentPinned = [...barPinnedApps]; - if (currentPinned.indexOf(appId) === -1) { - currentPinned.push(appId); - setBarPinnedApps(currentPinned); - } - } - - function removeBarPinnedApp(appId) { - if (!appId) - return; - var currentPinned = barPinnedApps.filter(id => id !== appId); - setBarPinnedApps(currentPinned); - } - - function isBarPinnedApp(appId) { - return appId && barPinnedApps.indexOf(appId) !== -1; - } - - function hideTrayId(trayId) { - if (!trayId) - return; - const current = [...hiddenTrayIds]; - if (current.indexOf(trayId) === -1) { - current.push(trayId); - hiddenTrayIds = current; - saveSettings(); - } - } - - function showTrayId(trayId) { - if (!trayId) - return; - hiddenTrayIds = hiddenTrayIds.filter(id => id !== trayId); - saveSettings(); - } - - function isHiddenTrayId(trayId) { - return trayId && hiddenTrayIds.indexOf(trayId) !== -1; - } - - function setTrayItemOrder(order) { - trayItemOrder = order; - saveSettings(); - } - - function addRecentColor(color) { - const colorStr = color.toString(); - let recent = recentColors.slice(); - recent = recent.filter(c => c !== colorStr); - recent.unshift(colorStr); - if (recent.length > 5) - recent = recent.slice(0, 5); - recentColors = recent; - saveSettings(); - } - - function setShowThirdPartyPlugins(enabled) { - showThirdPartyPlugins = enabled; - saveSettings(); - } - - function setLaunchPrefix(prefix) { - launchPrefix = prefix; - saveSettings(); - } - - function setLastBrightnessDevice(device) { - lastBrightnessDevice = device; - saveSettings(); - } - - function setBrightnessExponential(deviceName, enabled) { - var newSettings = Object.assign({}, brightnessExponentialDevices); - if (enabled) { - newSettings[deviceName] = true; - } else { - delete newSettings[deviceName]; - } - brightnessExponentialDevices = newSettings; - saveSettings(); - - if (typeof DisplayService !== "undefined") { - DisplayService.updateDeviceBrightnessDisplay(deviceName); - } - } - - function getBrightnessExponential(deviceName) { - return brightnessExponentialDevices[deviceName] === true; - } - - function setBrightnessUserSetValue(deviceName, value) { - var newValues = Object.assign({}, brightnessUserSetValues); - newValues[deviceName] = value; - brightnessUserSetValues = newValues; - saveSettings(); - } - - function getBrightnessUserSetValue(deviceName) { - return brightnessUserSetValues[deviceName]; - } - - function clearBrightnessUserSetValue(deviceName) { - var newValues = Object.assign({}, brightnessUserSetValues); - delete newValues[deviceName]; - brightnessUserSetValues = newValues; - saveSettings(); - } - - function setBrightnessExponent(deviceName, exponent) { - var newValues = Object.assign({}, brightnessExponentValues); - if (exponent !== undefined && exponent !== null) { - newValues[deviceName] = exponent; - } else { - delete newValues[deviceName]; - } - brightnessExponentValues = newValues; - saveSettings(); - } - - function getBrightnessExponent(deviceName) { - const value = brightnessExponentValues[deviceName]; - return value !== undefined ? value : 1.2; - } - - function setSelectedGpuIndex(index) { - selectedGpuIndex = index; - saveSettings(); - } - - function setNvidiaGpuTempEnabled(enabled) { - nvidiaGpuTempEnabled = enabled; - saveSettings(); - } - - function setNonNvidiaGpuTempEnabled(enabled) { - nonNvidiaGpuTempEnabled = enabled; - saveSettings(); - } - - function setEnabledGpuPciIds(pciIds) { - enabledGpuPciIds = pciIds; - saveSettings(); - } - - function setWifiDeviceOverride(device) { - wifiDeviceOverride = device || ""; - saveSettings(); - } - - function setWeatherHourlyDetailed(detailed) { - weatherHourlyDetailed = detailed; - saveSettings(); - } - - function setWeatherLocation(displayName, coordinates) { - weatherLocation = displayName; - weatherCoordinates = coordinates; - saveSettings(); - } - - function hideApp(appId) { - if (!appId) - return; - const current = [...hiddenApps]; - if (current.indexOf(appId) === -1) { - current.push(appId); - hiddenApps = current; - saveSettings(); - } - } - - function showApp(appId) { - if (!appId) - return; - hiddenApps = hiddenApps.filter(id => id !== appId); - saveSettings(); - } - - function isAppHidden(appId) { - return appId && hiddenApps.indexOf(appId) !== -1; - } - - function setAppOverride(appId, overrides) { - if (!appId) - return; - const newOverrides = Object.assign({}, appOverrides); - if (!overrides || Object.keys(overrides).length === 0) { - delete newOverrides[appId]; - } else { - newOverrides[appId] = overrides; - } - appOverrides = newOverrides; - saveSettings(); - } - - function getAppOverride(appId) { - if (!appId) - return null; - return appOverrides[appId] || null; - } - - function clearAppOverride(appId) { - if (!appId) - return; - const newOverrides = Object.assign({}, appOverrides); - delete newOverrides[appId]; - appOverrides = newOverrides; - saveSettings(); - } - - function setSearchAppActions(enabled) { - searchAppActions = enabled; - saveSettings(); - } - - function setVpnLastConnected(uuid) { - vpnLastConnected = uuid || ""; - saveSettings(); - } - - function setDeviceMaxVolume(nodeName, maxPercent) { - if (!nodeName) - return; - const updated = Object.assign({}, deviceMaxVolumes); - const clamped = Math.max(100, Math.min(200, Math.round(maxPercent))); - if (clamped === 100) { - delete updated[nodeName]; - } else { - updated[nodeName] = clamped; - } - deviceMaxVolumes = updated; - saveSettings(); - } - - function setHiddenOutputDeviceNames(deviceNames) { - if (!Array.isArray(deviceNames)) - return; - hiddenOutputDeviceNames = deviceNames; - saveSettings(); - } - - function setHiddenInputDeviceNames(deviceNames) { - if (!Array.isArray(deviceNames)) - return; - hiddenInputDeviceNames = deviceNames; - saveSettings(); - } - - function getDeviceMaxVolume(nodeName) { - if (!nodeName) - return 100; - return deviceMaxVolumes[nodeName] ?? 100; - } - - function removeDeviceMaxVolume(nodeName) { - if (!nodeName) - return; - const updated = Object.assign({}, deviceMaxVolumes); - delete updated[nodeName]; - deviceMaxVolumes = updated; - saveSettings(); - } - - function updateLocale() { - if (!locale) { - I18n._pickTranslation(); - return; - } - I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json"); - } - - function setLauncherLastMode(mode) { - launcherLastMode = mode; - saveSettings(); - } - - function setLauncherLastQuery(query) { - launcherLastQuery = query; - saveSettings(); - } - - function addLauncherHistory(query) { - let q = query.trim(); - - setLauncherLastQuery(q); - - if (!q) - return; - - if (launcherQueryHistory.length > 0 && launcherQueryHistory[0] === q) { - return; - } - - let history = [...launcherQueryHistory]; - - let idx = history.indexOf(q); - if (idx !== -1) - history.splice(idx, 1); - - history.unshift(q); - if (history.length > 50) - history = history.slice(0, 50); - - launcherQueryHistory = history; - saveSettings(); - } - - function clearLauncherHistory() { - launcherLastQuery = ""; - launcherSearchHistory = []; - saveSettings(); - } - - function setAppDrawerLastMode(mode) { - appDrawerLastMode = mode; - saveSettings(); - } - - function setNiriOverviewLastMode(mode) { - niriOverviewLastMode = mode; - saveSettings(); - } - - function setSettingsSidebarState(expandedIds, collapsedIds) { - settingsSidebarExpandedIds = expandedIds; - settingsSidebarCollapsedIds = collapsedIds; - saveSettings(); - } - - function syncWallpaperForCurrentMode(mode) { - if (!perModeWallpaper) - return; - var light = (mode !== undefined) ? mode : isLightMode; - if (perMonitorWallpaper) { - monitorWallpapers = light ? Object.assign({}, monitorWallpapersLight) : Object.assign({}, monitorWallpapersDark); - return; - } - - wallpaperPath = light ? wallpaperPathLight : wallpaperPathDark; - } - - function _findMonitorValue(map, screenName) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) - return map[screenName]; - - if (map[screen.name] !== undefined) - return map[screen.name]; - if (screen.model && map[screen.model] !== undefined) - return map[screen.model]; - if (typeof SettingsData !== "undefined") { - var displayName = SettingsData.getScreenDisplayName(screen); - if (displayName && map[displayName] !== undefined) - return map[displayName]; - } - return undefined; - } - - function getMonitorWallpaper(screenName) { - if (!perMonitorWallpaper) - return wallpaperPath; - var value = _findMonitorValue(monitorWallpapers, screenName); - return value !== undefined ? value : wallpaperPath; - } - - function getMonitorWallpaperFillMode(screenName) { - var globalFillMode = (typeof SettingsData !== "undefined") ? SettingsData.wallpaperFillMode : "Fill"; - if (!perMonitorWallpaper) - return globalFillMode; - var value = _findMonitorValue(monitorWallpaperFillModes, screenName); - return value !== undefined ? value : globalFillMode; - } - - function setMonitorWallpaperFillMode(screenName, mode) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) - return; - - var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; - - var newModes = {}; - for (var key in monitorWallpaperFillModes) { - var isThisScreen = key === screen.name || (screen.model && key === screen.model); - if (!isThisScreen) - newModes[key] = monitorWallpaperFillModes[key]; - } - - newModes[identifier] = mode; - monitorWallpaperFillModes = newModes; - saveSettings(); - } - - function getMonitorCyclingSettings(screenName) { - var defaults = { - "enabled": false, - "mode": "interval", - "interval": 300, - "time": "06:00" - }; - var value = _findMonitorValue(monitorCyclingSettings, screenName); - return Object.assign({}, defaults, value !== undefined ? value : {}); - } - - FileView { - id: settingsFile - - path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell/session.json" - blockLoading: true - blockWrites: true - atomicWrites: true - watchChanges: !isGreeterMode - onLoaded: { - if (!isGreeterMode) { - _hasUnsavedChanges = false; - parseSettings(settingsFile.text()); - } - } - onSaveFailed: error => { - root._isReadOnly = true; - root._hasUnsavedChanges = root._checkForUnsavedChanges(); - } - } - - FileView { - id: greeterSessionFile - - path: { - const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"; - return greetCfgDir + "/session.json"; - } - preload: isGreeterMode - blockLoading: false - blockWrites: true - watchChanges: false - printErrors: true - onLoaded: { - if (isGreeterMode) { - parseSettings(greeterSessionFile.text()); - } - } - } - - Process { - id: sessionWritableCheckProcess - - property string sessionPath: Paths.strip(settingsFile.path) - - command: ["sh", "-c", "[ ! -f \"" + sessionPath + "\" ] || [ -w \"" + sessionPath + "\" ] && echo 'writable' || echo 'readonly'"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const result = text.trim(); - root._onWritableCheckComplete(result === "writable"); - } - } - } - - IpcHandler { - target: "wallpaper" - - function get(): string { - if (root.perMonitorWallpaper) { - return "ERROR: Per-monitor mode enabled. Use getFor(screenName) instead."; - } - return root.wallpaperPath || ""; - } - - function set(path: string): string { - if (root.perMonitorWallpaper) { - return "ERROR: Per-monitor mode enabled. Use setFor(screenName, path) instead."; - } - - if (!path) { - return "ERROR: No path provided"; - } - - var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path; - - try { - root.setWallpaper(absolutePath); - return "SUCCESS: Wallpaper set to " + absolutePath; - } catch (e) { - return "ERROR: Failed to set wallpaper: " + e.toString(); - } - } - - function clear(): string { - root.setWallpaper(""); - root.setPerMonitorWallpaper(false); - root.monitorWallpapers = {}; - root.saveSettings(); - return "SUCCESS: All wallpapers cleared"; - } - - function next(): string { - if (root.perMonitorWallpaper) { - return "ERROR: Per-monitor mode enabled. Use nextFor(screenName) instead."; - } - - if (!root.wallpaperPath) { - return "ERROR: No wallpaper set"; - } - - try { - WallpaperCyclingService.cycleNextManually(); - return "SUCCESS: Cycling to next wallpaper"; - } catch (e) { - return "ERROR: Failed to cycle wallpaper: " + e.toString(); - } - } - - function prev(): string { - if (root.perMonitorWallpaper) { - return "ERROR: Per-monitor mode enabled. Use prevFor(screenName) instead."; - } - - if (!root.wallpaperPath) { - return "ERROR: No wallpaper set"; - } - - try { - WallpaperCyclingService.cyclePrevManually(); - return "SUCCESS: Cycling to previous wallpaper"; - } catch (e) { - return "ERROR: Failed to cycle wallpaper: " + e.toString(); - } - } - - function getFor(screenName: string): string { - if (!screenName) { - return "ERROR: No screen name provided"; - } - return root.getMonitorWallpaper(screenName) || ""; - } - - function setFor(screenName: string, path: string): string { - if (!screenName) { - return "ERROR: No screen name provided"; - } - - if (!path) { - return "ERROR: No path provided"; - } - - var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path; - - try { - if (!root.perMonitorWallpaper) { - root.setPerMonitorWallpaper(true); - } - root.setMonitorWallpaper(screenName, absolutePath); - return "SUCCESS: Wallpaper set for " + screenName + " to " + absolutePath; - } catch (e) { - return "ERROR: Failed to set wallpaper for " + screenName + ": " + e.toString(); - } - } - - function nextFor(screenName: string): string { - if (!screenName) { - return "ERROR: No screen name provided"; - } - - var currentWallpaper = root.getMonitorWallpaper(screenName); - if (!currentWallpaper) { - return "ERROR: No wallpaper set for " + screenName; - } - - try { - WallpaperCyclingService.cycleNextForMonitor(screenName); - return "SUCCESS: Cycling to next wallpaper for " + screenName; - } catch (e) { - return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString(); - } - } - - function prevFor(screenName: string): string { - if (!screenName) { - return "ERROR: No screen name provided"; - } - - var currentWallpaper = root.getMonitorWallpaper(screenName); - if (!currentWallpaper) { - return "ERROR: No wallpaper set for " + screenName; - } - - try { - WallpaperCyclingService.cyclePrevForMonitor(screenName); - return "SUCCESS: Cycling to previous wallpaper for " + screenName; - } catch (e) { - return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SettingsData.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SettingsData.qml deleted file mode 100644 index 0790ea4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/SettingsData.qml +++ /dev/null @@ -1,2840 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Common.settings -import qs.Services -import "settings/SettingsSpec.js" as Spec -import "settings/SettingsStore.js" as Store - -Singleton { - id: root - - readonly property int settingsConfigVersion: 5 - - readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" - - enum Position { - Top, - Bottom, - Left, - Right, - TopCenter, - BottomCenter, - LeftCenter, - RightCenter - } - - enum AnimationSpeed { - None, - Short, - Medium, - Long, - Custom - } - - enum SuspendBehavior { - Suspend, - Hibernate, - SuspendThenHibernate - } - - enum WidgetColorMode { - Default, - Colorful - } - - readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation) - readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation) - readonly property string _configDir: Paths.strip(_configUrl) - readonly property string pluginSettingsPath: _configDir + "/DankMaterialShell/plugin_settings.json" - - property bool _loading: false - property bool _pluginSettingsLoading: false - property bool _parseError: false - property bool _pluginParseError: false - property bool _hasLoaded: false - property bool _isReadOnly: false - property bool _hasUnsavedChanges: false - property bool _selfWrite: false - property var _loadedSettingsSnapshot: null - property var pluginSettings: ({}) - property var builtInPluginSettings: ({}) - - function getBuiltInPluginSetting(pluginId, key, defaultValue) { - if (!builtInPluginSettings[pluginId]) - return defaultValue; - return builtInPluginSettings[pluginId][key] !== undefined ? builtInPluginSettings[pluginId][key] : defaultValue; - } - - function setBuiltInPluginSetting(pluginId, key, value) { - const updated = JSON.parse(JSON.stringify(builtInPluginSettings)); - if (!updated[pluginId]) - updated[pluginId] = {}; - updated[pluginId][key] = value; - builtInPluginSettings = updated; - saveSettings(); - } - - property bool clipboardEnterToPaste: false - - property var launcherPluginVisibility: ({}) - - function getPluginAllowWithoutTrigger(pluginId) { - if (!launcherPluginVisibility[pluginId]) - return true; - return launcherPluginVisibility[pluginId].allowWithoutTrigger !== false; - } - - function setPluginAllowWithoutTrigger(pluginId, allow) { - const updated = JSON.parse(JSON.stringify(launcherPluginVisibility)); - if (!updated[pluginId]) - updated[pluginId] = {}; - updated[pluginId].allowWithoutTrigger = allow; - launcherPluginVisibility = updated; - saveSettings(); - } - - property var launcherPluginOrder: [] - onLauncherPluginOrderChanged: saveSettings() - - function setLauncherPluginOrder(order) { - launcherPluginOrder = order; - } - - function getOrderedLauncherPlugins(allPlugins) { - if (!launcherPluginOrder || launcherPluginOrder.length === 0) - return allPlugins; - const orderMap = {}; - for (let i = 0; i < launcherPluginOrder.length; i++) - orderMap[launcherPluginOrder[i]] = i; - return allPlugins.slice().sort((a, b) => { - const aOrder = orderMap[a.id] ?? 9999; - const bOrder = orderMap[b.id] ?? 9999; - if (aOrder !== bOrder) - return aOrder - bOrder; - return a.name.localeCompare(b.name); - }); - } - - property alias dankBarLeftWidgetsModel: leftWidgetsModel - property alias dankBarCenterWidgetsModel: centerWidgetsModel - property alias dankBarRightWidgetsModel: rightWidgetsModel - - property string currentThemeName: "purple" - property string currentThemeCategory: "generic" - property string customThemeFile: "" - property var registryThemeVariants: ({}) - property string matugenScheme: "scheme-tonal-spot" - property real matugenContrast: 0 - property bool runUserMatugenTemplates: true - property string matugenTargetMonitor: "" - property real popupTransparency: 1.0 - property real dockTransparency: 1 - property string widgetBackgroundColor: "sch" - property string widgetColorMode: "default" - property string controlCenterTileColorMode: "primary" - property string buttonColorMode: "primary" - property real cornerRadius: 12 - property int niriLayoutGapsOverride: -1 - property int niriLayoutRadiusOverride: -1 - property int niriLayoutBorderSize: -1 - property int hyprlandLayoutGapsOverride: -1 - property int hyprlandLayoutRadiusOverride: -1 - property int hyprlandLayoutBorderSize: -1 - property int mangoLayoutGapsOverride: -1 - property int mangoLayoutRadiusOverride: -1 - property int mangoLayoutBorderSize: -1 - - property int firstDayOfWeek: -1 - property bool showWeekNumber: false - property bool use24HourClock: true - property bool showSeconds: false - property bool padHours12Hour: false - property bool useFahrenheit: false - property string windSpeedUnit: "kmh" - property bool nightModeEnabled: false - property int animationSpeed: SettingsData.AnimationSpeed.Short - property int customAnimationDuration: 500 - property bool syncComponentAnimationSpeeds: true - onSyncComponentAnimationSpeedsChanged: saveSettings() - property int popoutAnimationSpeed: SettingsData.AnimationSpeed.Short - property int popoutCustomAnimationDuration: 150 - property int modalAnimationSpeed: SettingsData.AnimationSpeed.Short - property int modalCustomAnimationDuration: 150 - property bool enableRippleEffects: true - onEnableRippleEffectsChanged: saveSettings() - property bool m3ElevationEnabled: true - onM3ElevationEnabledChanged: saveSettings() - property int m3ElevationIntensity: 12 - onM3ElevationIntensityChanged: saveSettings() - property int m3ElevationOpacity: 30 - onM3ElevationOpacityChanged: saveSettings() - property string m3ElevationColorMode: "default" - onM3ElevationColorModeChanged: saveSettings() - property string m3ElevationLightDirection: "top" - onM3ElevationLightDirectionChanged: saveSettings() - property string m3ElevationCustomColor: "#000000" - onM3ElevationCustomColorChanged: saveSettings() - property bool modalElevationEnabled: true - onModalElevationEnabledChanged: saveSettings() - property bool popoutElevationEnabled: true - onPopoutElevationEnabledChanged: saveSettings() - property bool barElevationEnabled: true - onBarElevationEnabledChanged: saveSettings() - property bool blurEnabled: false - onBlurEnabledChanged: saveSettings() - property string blurBorderColor: "outline" - onBlurBorderColorChanged: saveSettings() - property string blurBorderCustomColor: "#ffffff" - onBlurBorderCustomColorChanged: saveSettings() - property real blurBorderOpacity: 1.0 - onBlurBorderOpacityChanged: saveSettings() - property string wallpaperFillMode: "Fill" - property bool blurredWallpaperLayer: false - property bool blurWallpaperOnOverview: false - - property bool showLauncherButton: true - property bool showWorkspaceSwitcher: true - property bool showFocusedWindow: true - property bool showWeather: true - property bool showMusic: true - property bool showClipboard: true - property bool showCpuUsage: true - property bool showMemUsage: true - property bool showCpuTemp: true - property bool showGpuTemp: true - property int selectedGpuIndex: 0 - property var enabledGpuPciIds: [] - property bool showSystemTray: true - property bool showClock: true - property bool showNotificationButton: true - property bool showBattery: true - property bool showControlCenterButton: true - property bool showCapsLockIndicator: true - - property bool controlCenterShowNetworkIcon: true - property bool controlCenterShowBluetoothIcon: true - property bool controlCenterShowAudioIcon: true - property bool controlCenterShowAudioPercent: false - property bool controlCenterShowVpnIcon: true - property bool controlCenterShowBrightnessIcon: false - property bool controlCenterShowBrightnessPercent: false - property bool controlCenterShowMicIcon: false - property bool controlCenterShowMicPercent: true - property bool controlCenterShowBatteryIcon: false - property bool controlCenterShowPrinterIcon: false - property bool controlCenterShowScreenSharingIcon: true - property bool showPrivacyButton: true - property bool privacyShowMicIcon: false - property bool privacyShowCameraIcon: false - property bool privacyShowScreenShareIcon: false - - property var controlCenterWidgets: [ - { - "id": "volumeSlider", - "enabled": true, - "width": 50 - }, - { - "id": "brightnessSlider", - "enabled": true, - "width": 50 - }, - { - "id": "wifi", - "enabled": true, - "width": 50 - }, - { - "id": "bluetooth", - "enabled": true, - "width": 50 - }, - { - "id": "audioOutput", - "enabled": true, - "width": 50 - }, - { - "id": "audioInput", - "enabled": true, - "width": 50 - }, - { - "id": "nightMode", - "enabled": true, - "width": 50 - }, - { - "id": "darkMode", - "enabled": true, - "width": 50 - } - ] - - property bool showWorkspaceIndex: false - property bool showWorkspaceName: false - property bool showWorkspacePadding: false - property bool workspaceScrolling: false - property bool showWorkspaceApps: false - property bool workspaceDragReorder: true - property bool groupWorkspaceApps: true - property int maxWorkspaceIcons: 3 - property int workspaceAppIconSizeOffset: 0 - property bool workspaceFollowFocus: false - property bool showOccupiedWorkspacesOnly: false - property bool reverseScrolling: false - property bool dwlShowAllTags: false - property bool workspaceActiveAppHighlightEnabled: false - property string workspaceColorMode: "default" - property string workspaceOccupiedColorMode: "none" - property string workspaceUnfocusedColorMode: "default" - property string workspaceUrgentColorMode: "default" - property bool workspaceFocusedBorderEnabled: false - property string workspaceFocusedBorderColor: "primary" - property int workspaceFocusedBorderThickness: 2 - property var workspaceNameIcons: ({}) - property bool waveProgressEnabled: true - property bool scrollTitleEnabled: true - property bool mediaAdaptiveWidthEnabled: true - property bool audioVisualizerEnabled: true - property string audioScrollMode: "volume" - property int audioWheelScrollAmount: 5 - property bool clockCompactMode: false - property bool focusedWindowCompactMode: false - property bool runningAppsCompactMode: true - property int barMaxVisibleApps: 0 - property int barMaxVisibleRunningApps: 0 - property bool barShowOverflowBadge: true - property bool appsDockHideIndicators: false - property bool appsDockColorizeActive: false - property string appsDockActiveColorMode: "primary" - property bool appsDockEnlargeOnHover: false - property int appsDockEnlargePercentage: 125 - property int appsDockIconSizePercentage: 100 - property bool keyboardLayoutNameCompactMode: false - property bool runningAppsCurrentWorkspace: true - property bool runningAppsGroupByApp: false - property bool runningAppsCurrentMonitor: false - property var appIdSubstitutions: [] - property string centeringMode: "index" - property string clockDateFormat: "" - property string lockDateFormat: "" - property bool greeterRememberLastSession: true - property bool greeterRememberLastUser: true - property bool greeterEnableFprint: false - property bool greeterEnableU2f: false - property string greeterWallpaperPath: "" - property bool greeterUse24HourClock: true - property bool greeterShowSeconds: false - property bool greeterPadHours12Hour: false - property string greeterLockDateFormat: "" - property string greeterFontFamily: "" - property string greeterWallpaperFillMode: "" - property int mediaSize: 1 - - property string appLauncherViewMode: "list" - property string spotlightModalViewMode: "list" - property string browserPickerViewMode: "grid" - property var browserUsageHistory: ({}) - property string appPickerViewMode: "grid" - property var filePickerUsageHistory: ({}) - property bool sortAppsAlphabetically: false - property int appLauncherGridColumns: 4 - property bool spotlightCloseNiriOverview: true - property bool rememberLastQuery: false - property var spotlightSectionViewModes: ({}) - onSpotlightSectionViewModesChanged: saveSettings() - property var appDrawerSectionViewModes: ({}) - onAppDrawerSectionViewModesChanged: saveSettings() - property bool niriOverviewOverlayEnabled: true - property string dankLauncherV2Size: "compact" - property bool dankLauncherV2BorderEnabled: false - property int dankLauncherV2BorderThickness: 2 - property string dankLauncherV2BorderColor: "primary" - property bool dankLauncherV2ShowFooter: true - property bool dankLauncherV2UnloadOnClose: false - property bool dankLauncherV2IncludeFilesInAll: false - property bool dankLauncherV2IncludeFoldersInAll: false - - property string _legacyWeatherLocation: "New York, NY" - property string _legacyWeatherCoordinates: "40.7128,-74.0060" - property string _legacyVpnLastConnected: "" - readonly property string weatherLocation: SessionData.weatherLocation - readonly property string weatherCoordinates: SessionData.weatherCoordinates - property bool useAutoLocation: false - property bool weatherEnabled: true - - property string networkPreference: "auto" - - property string iconTheme: "System Default" - property var availableIconThemes: ["System Default"] - property string systemDefaultIconTheme: "" - property bool qt5ctAvailable: false - property bool qt6ctAvailable: false - property bool gtkAvailable: false - - property var cursorSettings: ({ - "theme": "System Default", - "size": 24, - "niri": { - "hideWhenTyping": false, - "hideAfterInactiveMs": 0 - }, - "hyprland": { - "hideOnKeyPress": false, - "hideOnTouch": false, - "inactiveTimeout": 0 - }, - "dwl": { - "cursorHideTimeout": 0 - } - }) - property var availableCursorThemes: ["System Default"] - property string systemDefaultCursorTheme: "" - - property string launcherLogoMode: "apps" - property string launcherLogoCustomPath: "" - property string launcherLogoColorOverride: "" - property bool launcherLogoColorInvertOnMode: false - property real launcherLogoBrightness: 0.5 - property real launcherLogoContrast: 1 - property int launcherLogoSizeOffset: 0 - - property string fontFamily: "Inter Variable" - property string monoFontFamily: "Fira Code" - property int fontWeight: Font.Normal - property real fontScale: 1.0 - property real dankBarFontScale: 1.0 - - property bool notepadUseMonospace: true - property string notepadFontFamily: "" - property real notepadFontSize: 14 - property bool notepadShowLineNumbers: false - property real notepadTransparencyOverride: -1 - property real notepadLastCustomTransparency: 0.7 - - onNotepadUseMonospaceChanged: saveSettings() - onNotepadFontFamilyChanged: saveSettings() - onNotepadFontSizeChanged: saveSettings() - onNotepadShowLineNumbersChanged: saveSettings() - // onCenteringModeChanged: saveSettings() - onNotepadTransparencyOverrideChanged: { - if (notepadTransparencyOverride > 0) { - notepadLastCustomTransparency = notepadTransparencyOverride; - } - saveSettings(); - } - onNotepadLastCustomTransparencyChanged: saveSettings() - - property bool soundsEnabled: true - property bool useSystemSoundTheme: false - property bool soundNewNotification: true - property bool soundVolumeChanged: true - property bool soundPluggedIn: true - property bool soundLogin: false - - property int acMonitorTimeout: 0 - property int acLockTimeout: 0 - property int acSuspendTimeout: 0 - property int acSuspendBehavior: SettingsData.SuspendBehavior.Suspend - property string acProfileName: "" - property int batteryMonitorTimeout: 0 - property int batteryLockTimeout: 0 - property int batterySuspendTimeout: 0 - property int batterySuspendBehavior: SettingsData.SuspendBehavior.Suspend - property string batteryProfileName: "" - property int batteryChargeLimit: 100 - property bool lockBeforeSuspend: false - property bool loginctlLockIntegration: true - property bool fadeToLockEnabled: true - property int fadeToLockGracePeriod: 5 - property bool fadeToDpmsEnabled: true - property int fadeToDpmsGracePeriod: 5 - property string launchPrefix: "" - property var brightnessDevicePins: ({}) - property var wifiNetworkPins: ({}) - property var bluetoothDevicePins: ({}) - property var audioInputDevicePins: ({}) - property var audioOutputDevicePins: ({}) - - property bool gtkThemingEnabled: false - property bool qtThemingEnabled: false - property bool syncModeWithPortal: true - property bool terminalsAlwaysDark: false - - property string muxType: "tmux" - property bool muxUseCustomCommand: false - property string muxCustomCommand: "" - property string muxSessionFilter: "" - - property bool runDmsMatugenTemplates: true - property bool matugenTemplateGtk: true - property bool matugenTemplateNiri: true - property bool matugenTemplateHyprland: true - property bool matugenTemplateMangowc: true - property bool matugenTemplateQt5ct: true - property bool matugenTemplateQt6ct: true - property bool matugenTemplateFirefox: true - property bool matugenTemplatePywalfox: true - property bool matugenTemplateZenBrowser: true - property bool matugenTemplateVesktop: true - property bool matugenTemplateEquibop: true - property bool matugenTemplateGhostty: true - property bool matugenTemplateKitty: true - property bool matugenTemplateFoot: true - property bool matugenTemplateNeovim: false - property bool matugenTemplateAlacritty: true - property bool matugenTemplateWezterm: true - property bool matugenTemplateDgop: true - property bool matugenTemplateKcolorscheme: true - property bool matugenTemplateVscode: true - property bool matugenTemplateEmacs: true - property bool matugenTemplateZed: true - - property var matugenTemplateNeovimSettings: ({ - "dark": { - "baseTheme": "github_dark", - "harmony": 0.5 - }, - "light": { - "baseTheme": "github_light", - "harmony": 0.5 - } - }) - property bool matugenTemplateNeovimSetBackground: true - - property bool showDock: false - property bool dockAutoHide: false - property bool dockSmartAutoHide: false - property bool dockGroupByApp: false - property bool dockRestoreSpecialWorkspaceOnClick: false - property bool dockOpenOnOverview: false - property int dockPosition: SettingsData.Position.Bottom - property real dockSpacing: 4 - property real dockBottomGap: 0 - property real dockMargin: 0 - property real dockIconSize: 40 - property string dockIndicatorStyle: "circle" - property bool dockBorderEnabled: false - property string dockBorderColor: "surfaceText" - property real dockBorderOpacity: 1.0 - property int dockBorderThickness: 1 - property bool dockIsolateDisplays: false - property bool dockLauncherEnabled: false - property string dockLauncherLogoMode: "apps" - property string dockLauncherLogoCustomPath: "" - property string dockLauncherLogoColorOverride: "" - property int dockLauncherLogoSizeOffset: 0 - property real dockLauncherLogoBrightness: 0.5 - property real dockLauncherLogoContrast: 1 - property int dockMaxVisibleApps: 0 - property int dockMaxVisibleRunningApps: 0 - property bool dockShowOverflowBadge: true - - property bool notificationOverlayEnabled: false - property bool notificationPopupShadowEnabled: true - property bool notificationPopupPrivacyMode: false - property int overviewRows: 2 - property int overviewColumns: 5 - property real overviewScale: 0.16 - - property bool modalDarkenBackground: true - - property bool lockScreenShowPowerActions: true - property bool lockScreenShowSystemIcons: true - property bool lockScreenShowTime: true - property bool lockScreenShowDate: true - property bool lockScreenShowProfileImage: true - property bool lockScreenShowPasswordField: true - property bool lockScreenShowMediaPlayer: true - property bool lockScreenPowerOffMonitorsOnLock: false - property bool lockAtStartup: false - - property bool enableFprint: false - property int maxFprintTries: 15 - readonly property bool fprintdAvailable: Processes.fprintdAvailable - readonly property bool lockFingerprintCanEnable: Processes.lockFingerprintCanEnable - readonly property bool lockFingerprintReady: Processes.lockFingerprintReady - readonly property string lockFingerprintReason: Processes.lockFingerprintReason - readonly property bool greeterFingerprintCanEnable: Processes.greeterFingerprintCanEnable - readonly property bool greeterFingerprintReady: Processes.greeterFingerprintReady - readonly property string greeterFingerprintReason: Processes.greeterFingerprintReason - readonly property string greeterFingerprintSource: Processes.greeterFingerprintSource - property bool enableU2f: false - property string u2fMode: "or" - readonly property bool u2fAvailable: Processes.u2fAvailable - readonly property bool lockU2fCanEnable: Processes.lockU2fCanEnable - readonly property bool lockU2fReady: Processes.lockU2fReady - readonly property string lockU2fReason: Processes.lockU2fReason - readonly property bool greeterU2fCanEnable: Processes.greeterU2fCanEnable - readonly property bool greeterU2fReady: Processes.greeterU2fReady - readonly property string greeterU2fReason: Processes.greeterU2fReason - readonly property string greeterU2fSource: Processes.greeterU2fSource - property string lockScreenActiveMonitor: "all" - property string lockScreenInactiveColor: "#000000" - property int lockScreenNotificationMode: 0 - property bool lockScreenVideoEnabled: false - property string lockScreenVideoPath: "" - property bool lockScreenVideoCycling: false - property bool hideBrightnessSlider: false - - property int notificationTimeoutLow: 5000 - property int notificationTimeoutNormal: 5000 - property int notificationTimeoutCritical: 0 - property bool notificationCompactMode: false - property int notificationPopupPosition: SettingsData.Position.Top - property int notificationAnimationSpeed: SettingsData.AnimationSpeed.Short - property int notificationCustomAnimationDuration: 400 - property bool notificationHistoryEnabled: true - property int notificationHistoryMaxCount: 50 - property int notificationHistoryMaxAgeDays: 7 - property bool notificationHistorySaveLow: true - property bool notificationHistorySaveNormal: true - property bool notificationHistorySaveCritical: true - property var notificationRules: [] - property bool notificationFocusedMonitor: false - - property bool osdAlwaysShowValue: false - property int osdPosition: SettingsData.Position.BottomCenter - property bool osdVolumeEnabled: true - property bool osdMediaVolumeEnabled: true - property bool osdMediaPlaybackEnabled: false - property bool osdBrightnessEnabled: true - property bool osdIdleInhibitorEnabled: true - property bool osdMicMuteEnabled: true - property bool osdCapsLockEnabled: true - property bool osdPowerProfileEnabled: true - property bool osdAudioOutputEnabled: true - - property bool powerActionConfirm: true - property real powerActionHoldDuration: 0.5 - property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] - property string powerMenuDefaultAction: "logout" - property bool powerMenuGridLayout: false - property string customPowerActionLock: "" - property string customPowerActionLogout: "" - property string customPowerActionSuspend: "" - property string customPowerActionHibernate: "" - property string customPowerActionReboot: "" - property string customPowerActionPowerOff: "" - - property bool updaterHideWidget: false - property bool updaterUseCustomCommand: false - property string updaterCustomCommand: "" - property string updaterTerminalAdditionalParams: "" - - property string displayNameMode: "system" - property var screenPreferences: ({}) - property var showOnLastDisplay: ({}) - property var niriOutputSettings: ({}) - property var hyprlandOutputSettings: ({}) - property var displayProfiles: ({}) - property var activeDisplayProfile: ({}) - property bool displayProfileAutoSelect: false - property bool displayShowDisconnected: false - property bool displaySnapToEdge: true - - property var barConfigs: [ - { - "id": "default", - "name": "Main Bar", - "enabled": true, - "position": 0, - "screenPreferences": ["all"], - "showOnLastDisplay": true, - "leftWidgets": ["launcherButton", "workspaceSwitcher", "focusedWindow"], - "centerWidgets": ["music", "clock", "weather"], - "rightWidgets": ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], - "spacing": 4, - "innerPadding": 4, - "bottomGap": 0, - "transparency": 1.0, - "widgetTransparency": 1.0, - "squareCorners": false, - "noBackground": false, - "maximizeWidgetIcons": false, - "maximizeWidgetText": false, - "removeWidgetPadding": false, - "widgetPadding": 8, - "gothCornersEnabled": false, - "gothCornerRadiusOverride": false, - "gothCornerRadiusValue": 12, - "borderEnabled": false, - "borderColor": "surfaceText", - "borderOpacity": 1.0, - "borderThickness": 1, - "widgetOutlineEnabled": false, - "widgetOutlineColor": "primary", - "widgetOutlineOpacity": 1.0, - "widgetOutlineThickness": 1, - "fontScale": 1.0, - "iconScale": 1.0, - "autoHide": false, - "autoHideDelay": 250, - "showOnWindowsOpen": false, - "openOnOverview": false, - "visible": true, - "popupGapsAuto": true, - "popupGapsManual": 4, - "maximizeDetection": true, - "scrollEnabled": true, - "scrollXBehavior": "column", - "scrollYBehavior": "workspace", - "shadowIntensity": 0, - "shadowOpacity": 60, - "shadowColorMode": "default", - "shadowCustomColor": "#000000", - "clickThrough": false - } - ] - - property bool desktopClockEnabled: false - property string desktopClockStyle: "analog" - property real desktopClockTransparency: 0.8 - property string desktopClockColorMode: "primary" - property color desktopClockCustomColor: "#ffffff" - property bool desktopClockShowDate: true - property bool desktopClockShowAnalogNumbers: false - property bool desktopClockShowAnalogSeconds: true - property real desktopClockX: -1 - property real desktopClockY: -1 - property real desktopClockWidth: 280 - property real desktopClockHeight: 180 - property var desktopClockDisplayPreferences: ["all"] - - property bool systemMonitorEnabled: false - property bool systemMonitorShowHeader: true - property real systemMonitorTransparency: 0.8 - property string systemMonitorColorMode: "primary" - property color systemMonitorCustomColor: "#ffffff" - property bool systemMonitorShowCpu: true - property bool systemMonitorShowCpuGraph: true - property bool systemMonitorShowCpuTemp: true - property bool systemMonitorShowGpuTemp: false - property string systemMonitorGpuPciId: "" - property bool systemMonitorShowMemory: true - property bool systemMonitorShowMemoryGraph: true - property bool systemMonitorShowNetwork: true - property bool systemMonitorShowNetworkGraph: true - property bool systemMonitorShowDisk: true - property bool systemMonitorShowTopProcesses: false - property int systemMonitorTopProcessCount: 3 - property string systemMonitorTopProcessSortBy: "cpu" - property string systemMonitorLayoutMode: "auto" - property int systemMonitorGraphInterval: 60 - property real systemMonitorX: -1 - property real systemMonitorY: -1 - property real systemMonitorWidth: 320 - property real systemMonitorHeight: 480 - property var systemMonitorDisplayPreferences: ["all"] - property var systemMonitorVariants: [] - property var desktopWidgetPositions: ({}) - property var desktopWidgetGridSettings: ({}) - property var desktopWidgetInstances: [] - property var desktopWidgetGroups: [] - - function getDesktopWidgetGridSetting(screenKey, property, defaultValue) { - const val = desktopWidgetGridSettings?.[screenKey]?.[property]; - return val !== undefined ? val : defaultValue; - } - - function setDesktopWidgetGridSetting(screenKey, property, value) { - const allSettings = JSON.parse(JSON.stringify(desktopWidgetGridSettings || {})); - if (!allSettings[screenKey]) - allSettings[screenKey] = {}; - allSettings[screenKey][property] = value; - desktopWidgetGridSettings = allSettings; - saveSettings(); - } - - function getDesktopWidgetPosition(pluginId, screenKey, property, defaultValue) { - const pos = desktopWidgetPositions?.[pluginId]?.[screenKey]?.[property]; - return pos !== undefined ? pos : defaultValue; - } - - function updateDesktopWidgetPosition(pluginId, screenKey, updates) { - const allPositions = JSON.parse(JSON.stringify(desktopWidgetPositions || {})); - if (!allPositions[pluginId]) - allPositions[pluginId] = {}; - allPositions[pluginId][screenKey] = Object.assign({}, allPositions[pluginId][screenKey] || {}, updates); - desktopWidgetPositions = allPositions; - saveSettings(); - } - - function getSystemMonitorVariants() { - return systemMonitorVariants || []; - } - - function createSystemMonitorVariant(name, config) { - const id = "sysmon_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); - const variant = { - id: id, - name: name, - config: config || getDefaultSystemMonitorConfig() - }; - const variants = JSON.parse(JSON.stringify(systemMonitorVariants || [])); - variants.push(variant); - systemMonitorVariants = variants; - saveSettings(); - return variant; - } - - function updateSystemMonitorVariant(variantId, updates) { - const variants = JSON.parse(JSON.stringify(systemMonitorVariants || [])); - const idx = variants.findIndex(v => v.id === variantId); - if (idx === -1) - return; - Object.assign(variants[idx], updates); - systemMonitorVariants = variants; - saveSettings(); - } - - function removeSystemMonitorVariant(variantId) { - const variants = (systemMonitorVariants || []).filter(v => v.id !== variantId); - systemMonitorVariants = variants; - saveSettings(); - } - - function getSystemMonitorVariant(variantId) { - return (systemMonitorVariants || []).find(v => v.id === variantId) || null; - } - - function getDefaultSystemMonitorConfig() { - return { - showHeader: true, - transparency: 0.8, - colorMode: "primary", - customColor: "#ffffff", - showCpu: true, - showCpuGraph: true, - showCpuTemp: true, - showGpuTemp: false, - gpuPciId: "", - showMemory: true, - showMemoryGraph: true, - showNetwork: true, - showNetworkGraph: true, - showDisk: true, - showTopProcesses: false, - topProcessCount: 3, - topProcessSortBy: "cpu", - layoutMode: "auto", - graphInterval: 60, - x: -1, - y: -1, - width: 320, - height: 480, - displayPreferences: ["all"] - }; - } - - function createDesktopWidgetInstance(widgetType, name, config) { - const id = "dw_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); - const instance = { - id: id, - widgetType: widgetType, - name: name || widgetType, - enabled: true, - config: config || {}, - positions: {} - }; - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - instances.push(instance); - desktopWidgetInstances = instances; - saveSettings(); - return instance; - } - - function updateDesktopWidgetInstance(instanceId, updates) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1) - return; - Object.assign(instances[idx], updates); - desktopWidgetInstances = instances; - saveSettings(); - } - - function updateDesktopWidgetInstanceConfig(instanceId, configUpdates) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1) - return; - instances[idx].config = Object.assign({}, instances[idx].config || {}, configUpdates); - desktopWidgetInstances = instances; - saveSettings(); - } - - function updateDesktopWidgetInstancePosition(instanceId, screenKey, positionUpdates) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1) - return; - if (!instances[idx].positions) - instances[idx].positions = {}; - instances[idx].positions[screenKey] = Object.assign({}, instances[idx].positions[screenKey] || {}, positionUpdates); - desktopWidgetInstances = instances; - saveSettings(); - } - - function removeDesktopWidgetInstance(instanceId) { - const instances = (desktopWidgetInstances || []).filter(inst => inst.id !== instanceId); - desktopWidgetInstances = instances; - saveSettings(); - } - - function syncDesktopWidgetPositionToAllScreens(instanceId) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1) - return; - const positions = instances[idx].positions || {}; - const screenKeys = Object.keys(positions).filter(k => k !== "_synced"); - if (screenKeys.length === 0) - return; - const sourceKey = screenKeys[0]; - const sourcePos = positions[sourceKey]; - if (!sourcePos) - return; - const screen = Array.from(Quickshell.screens.values()).find(s => getScreenDisplayName(s) === sourceKey); - if (!screen) - return; - const screenW = screen.width; - const screenH = screen.height; - const synced = {}; - if (sourcePos.x !== undefined) - synced.x = sourcePos.x / screenW; - if (sourcePos.y !== undefined) - synced.y = sourcePos.y / screenH; - if (sourcePos.width !== undefined) - synced.width = sourcePos.width; - if (sourcePos.height !== undefined) - synced.height = sourcePos.height; - instances[idx].positions["_synced"] = synced; - desktopWidgetInstances = instances; - saveSettings(); - } - - function duplicateDesktopWidgetInstance(instanceId) { - const source = getDesktopWidgetInstance(instanceId); - if (!source) - return null; - const newId = "dw_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); - const instance = { - id: newId, - widgetType: source.widgetType, - name: source.name + " (Copy)", - enabled: source.enabled, - config: JSON.parse(JSON.stringify(source.config || {})), - positions: {} - }; - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - instances.push(instance); - desktopWidgetInstances = instances; - saveSettings(); - return instance; - } - - function getDesktopWidgetInstance(instanceId) { - return (desktopWidgetInstances || []).find(inst => inst.id === instanceId) || null; - } - - function getDesktopWidgetInstancesOfType(widgetType) { - return (desktopWidgetInstances || []).filter(inst => inst.widgetType === widgetType); - } - - function getEnabledDesktopWidgetInstances() { - return (desktopWidgetInstances || []).filter(inst => inst.enabled); - } - - function moveDesktopWidgetInstance(instanceId, direction) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1) - return false; - const targetIdx = direction === "up" ? idx - 1 : idx + 1; - if (targetIdx < 0 || targetIdx >= instances.length) - return false; - const temp = instances[idx]; - instances[idx] = instances[targetIdx]; - instances[targetIdx] = temp; - desktopWidgetInstances = instances; - saveSettings(); - return true; - } - - function reorderDesktopWidgetInstance(instanceId, newIndex) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const idx = instances.findIndex(inst => inst.id === instanceId); - if (idx === -1 || newIndex < 0 || newIndex >= instances.length) - return false; - const [item] = instances.splice(idx, 1); - instances.splice(newIndex, 0, item); - desktopWidgetInstances = instances; - saveSettings(); - return true; - } - - function reorderDesktopWidgetInstanceInGroup(instanceId, groupId, newIndexInGroup) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - const groups = desktopWidgetGroups || []; - const groupMatches = inst => { - if (groupId === null) - return !inst.group || !groups.some(g => g.id === inst.group); - return inst.group === groupId; - }; - const groupInstances = instances.filter(groupMatches); - const currentGroupIdx = groupInstances.findIndex(inst => inst.id === instanceId); - if (currentGroupIdx === -1 || currentGroupIdx === newIndexInGroup) - return false; - if (newIndexInGroup < 0 || newIndexInGroup >= groupInstances.length) - return false; - const globalIdx = instances.findIndex(inst => inst.id === instanceId); - if (globalIdx === -1) - return false; - const [item] = instances.splice(globalIdx, 1); - const targetInstance = groupInstances[newIndexInGroup]; - let targetGlobalIdx = instances.findIndex(inst => inst.id === targetInstance.id); - if (newIndexInGroup > currentGroupIdx) - targetGlobalIdx++; - instances.splice(targetGlobalIdx, 0, item); - desktopWidgetInstances = instances; - saveSettings(); - return true; - } - - function createDesktopWidgetGroup(name) { - const id = "dwg_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); - const group = { - id: id, - name: name, - collapsed: false - }; - const groups = JSON.parse(JSON.stringify(desktopWidgetGroups || [])); - groups.push(group); - desktopWidgetGroups = groups; - saveSettings(); - return group; - } - - function updateDesktopWidgetGroup(groupId, updates) { - const groups = JSON.parse(JSON.stringify(desktopWidgetGroups || [])); - const idx = groups.findIndex(g => g.id === groupId); - if (idx === -1) - return; - Object.assign(groups[idx], updates); - desktopWidgetGroups = groups; - saveSettings(); - } - - function removeDesktopWidgetGroup(groupId) { - const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || [])); - for (let i = 0; i < instances.length; i++) { - if (instances[i].group === groupId) - instances[i].group = null; - } - desktopWidgetInstances = instances; - const groups = (desktopWidgetGroups || []).filter(g => g.id !== groupId); - desktopWidgetGroups = groups; - saveSettings(); - } - - function getDesktopWidgetGroup(groupId) { - return (desktopWidgetGroups || []).find(g => g.id === groupId) || null; - } - - function getDesktopWidgetInstancesByGroup(groupId) { - return (desktopWidgetInstances || []).filter(inst => inst.group === groupId); - } - - function getUngroupedDesktopWidgetInstances() { - return (desktopWidgetInstances || []).filter(inst => !inst.group); - } - - signal forceDankBarLayoutRefresh - signal forceDockLayoutRefresh - signal widgetDataChanged - signal workspaceIconsUpdated - - function refreshAuthAvailability() { - if (isGreeterMode) - return; - Processes.detectAuthCapabilities(); - } - - Component.onCompleted: { - if (!isGreeterMode) { - Processes.settingsRoot = root; - loadSettings(); - initializeListModels(); - refreshAuthAvailability(); - Processes.checkPluginSettings(); - } - } - - function applyStoredTheme() { - if (typeof Theme !== "undefined") { - Theme.currentThemeCategory = currentThemeCategory; - Theme.switchTheme(currentThemeName, false, false); - } else { - Qt.callLater(function () { - if (typeof Theme !== "undefined") { - Theme.currentThemeCategory = currentThemeCategory; - Theme.switchTheme(currentThemeName, false, false); - } - }); - } - } - - function regenSystemThemes() { - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function updateCompositorLayout() { - if (typeof CompositorService === "undefined") - return; - if (CompositorService.isNiri && typeof NiriService !== "undefined") - NiriService.generateNiriLayoutConfig(); - if (CompositorService.isHyprland && typeof HyprlandService !== "undefined") - HyprlandService.generateLayoutConfig(); - if (CompositorService.isDwl && typeof DwlService !== "undefined") - DwlService.generateLayoutConfig(); - } - - function applyStoredIconTheme() { - updateGtkIconTheme(); - updateQtIconTheme(); - updateCosmicIconTheme(); - } - - function updateCosmicIconTheme() { - let cosmicThemeName = (iconTheme === "System Default") ? systemDefaultIconTheme : iconTheme; - if (!cosmicThemeName || cosmicThemeName === "System Default") { - const detectScript = `if command -v gsettings >/dev/null 2>&1; then - gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g" - elif command -v dconf >/dev/null 2>&1; then - dconf read /org/gnome/desktop/interface/icon-theme 2>/dev/null | sed "s/'//g" - fi`; - - Proc.runCommand("detectCosmicIconTheme", ["sh", "-c", detectScript], (output, exitCode) => { - if (exitCode !== 0) - return; - const detected = (output || "").trim(); - if (!detected || detected === "System Default") - return; - const detectedEscaped = detected.replace(/'/g, "'\\''"); - const writeScript = `mkdir -p ${_configDir}/cosmic/com.system76.CosmicTk/v1 - printf '"%s"\\n' '${detectedEscaped}' > ${_configDir}/cosmic/com.system76.CosmicTk/v1/icon_theme 2>/dev/null || true`; - Quickshell.execDetached(["sh", "-lc", writeScript]); - }); - return; - } - - const cosmicThemeNameEscaped = cosmicThemeName.replace(/'/g, "'\\''"); - const script = `mkdir -p ${_configDir}/cosmic/com.system76.CosmicTk/v1 - printf '"%s"\\n' '${cosmicThemeNameEscaped}' > ${_configDir}/cosmic/com.system76.CosmicTk/v1/icon_theme 2>/dev/null || true`; - Quickshell.execDetached(["sh", "-lc", script]); - } - - function updateCosmicThemeMode(isLightMode) { - const isDark = isLightMode ? "false" : "true"; - const script = `mkdir -p ${_configDir}/cosmic/com.system76.CosmicTheme.Mode/v1 - printf '%s\\n' ${isDark} > ${_configDir}/cosmic/com.system76.CosmicTheme.Mode/v1/is_dark 2>/dev/null || true`; - Quickshell.execDetached(["sh", "-lc", script]); - } - - function updateGtkIconTheme() { - const gtkThemeName = (iconTheme === "System Default") ? systemDefaultIconTheme : iconTheme; - if (gtkThemeName === "System Default" || gtkThemeName === "") - return; - if (typeof DMSService !== "undefined" && DMSService.apiVersion >= 3 && typeof PortalService !== "undefined") { - PortalService.setSystemIconTheme(gtkThemeName); - } - - const configScript = `mkdir -p ${_configDir}/gtk-3.0 ${_configDir}/gtk-4.0 - - for config_dir in ${_configDir}/gtk-3.0 ${_configDir}/gtk-4.0; do - settings_file="$config_dir/settings.ini" - [ -f "$settings_file" ] && [ ! -w "$settings_file" ] && continue - if [ -f "$settings_file" ]; then - if grep -q "^gtk-icon-theme-name=" "$settings_file"; then - sed -i 's/^gtk-icon-theme-name=.*/gtk-icon-theme-name=${gtkThemeName}/' "$settings_file" - else - if grep -q "\\[Settings\\]" "$settings_file"; then - sed -i '/\\[Settings\\]/a gtk-icon-theme-name=${gtkThemeName}' "$settings_file" - else - echo -e '\\n[Settings]\\ngtk-icon-theme-name=${gtkThemeName}' >> "$settings_file" - fi - fi - else - echo -e '[Settings]\\ngtk-icon-theme-name=${gtkThemeName}' > "$settings_file" - fi - done - - pkill -HUP -f 'gtk' 2>/dev/null || true`; - - Quickshell.execDetached(["sh", "-lc", configScript]); - } - - function updateQtIconTheme() { - const qtThemeName = (iconTheme === "System Default") ? "" : iconTheme; - if (!qtThemeName) - return; - const home = _homeUrl.replace("file://", "").replace(/'/g, "'\\''"); - const qtThemeNameEscaped = qtThemeName.replace(/'/g, "'\\''"); - - const script = `mkdir -p ${_configDir}/qt5ct ${_configDir}/qt6ct ${_configDir}/environment.d 2>/dev/null || true - update_qt_icon_theme() { - local config_file="$1" - local theme_name="$2" - if [ -f "$config_file" ]; then - if grep -q "^\\[Appearance\\]" "$config_file"; then - if grep -q "^icon_theme=" "$config_file"; then - sed -i "s/^icon_theme=.*/icon_theme=$theme_name/" "$config_file" - else - sed -i "/^\\[Appearance\\]/a icon_theme=$theme_name" "$config_file" - fi - else - printf "\\n[Appearance]\\nicon_theme=%s\\n" "$theme_name" >> "$config_file" - fi - else - printf "[Appearance]\\nicon_theme=%s\\n" "$theme_name" > "$config_file" - fi - } - update_qt_icon_theme ${_configDir}/qt5ct/qt5ct.conf '${qtThemeNameEscaped}' - update_qt_icon_theme ${_configDir}/qt6ct/qt6ct.conf '${qtThemeNameEscaped}'`; - - Quickshell.execDetached(["sh", "-lc", script]); - } - - function scheduleAuthApply() { - if (isGreeterMode) - return; - Qt.callLater(() => { - Processes.settingsRoot = root; - Processes.scheduleAuthApply(); - }); - } - - readonly property var _hooks: ({ - "applyStoredTheme": applyStoredTheme, - "regenSystemThemes": regenSystemThemes, - "updateCompositorLayout": updateCompositorLayout, - "applyStoredIconTheme": applyStoredIconTheme, - "updateBarConfigs": updateBarConfigs, - "updateCompositorCursor": updateCompositorCursor, - "scheduleAuthApply": scheduleAuthApply - }) - - function set(key, value) { - Spec.set(root, key, value, saveSettings, _hooks); - } - - function loadSettings() { - _loading = true; - _parseError = false; - _hasUnsavedChanges = false; - _pendingMigration = null; - - try { - const txt = settingsFile.text(); - let obj = (txt && txt.trim()) ? JSON.parse(txt) : null; - - const oldVersion = obj?.configVersion ?? 0; - if (oldVersion < settingsConfigVersion) { - const migrated = Store.migrateToVersion(obj, settingsConfigVersion); - if (migrated) { - _pendingMigration = migrated; - obj = migrated; - } - } - - Store.parse(root, obj); - - if (obj?.weatherLocation !== undefined) - _legacyWeatherLocation = obj.weatherLocation; - if (obj?.weatherCoordinates !== undefined) - _legacyWeatherCoordinates = obj.weatherCoordinates; - if (obj?.vpnLastConnected !== undefined && obj.vpnLastConnected !== "") { - _legacyVpnLastConnected = obj.vpnLastConnected; - SessionData.vpnLastConnected = _legacyVpnLastConnected; - SessionData.saveSettings(); - } - - _loadedSettingsSnapshot = JSON.stringify(Store.toJson(root)); - _hasLoaded = true; - applyStoredTheme(); - updateCompositorCursor(); - Processes.detectQtTools(); - - _checkSettingsWritable(); - } catch (e) { - _parseError = true; - const msg = e.message; - console.error("SettingsData: Failed to parse settings.json - file will not be overwritten. Error:", msg); - Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg)); - applyStoredTheme(); - } finally { - _loading = false; - } - loadPluginSettings(); - } - - property var _pendingMigration: null - - function _checkSettingsWritable() { - settingsWritableCheckProcess.running = true; - } - - function _onWritableCheckComplete(writable) { - const wasReadOnly = _isReadOnly; - _isReadOnly = !writable; - if (_isReadOnly) { - _hasUnsavedChanges = _checkForUnsavedChanges(); - if (!wasReadOnly) - console.info("SettingsData: settings.json is now read-only"); - } else { - _loadedSettingsSnapshot = JSON.stringify(Store.toJson(root)); - _hasUnsavedChanges = false; - if (wasReadOnly) - console.info("SettingsData: settings.json is now writable"); - if (_pendingMigration) - settingsFile.setText(JSON.stringify(_pendingMigration, null, 2)); - } - _pendingMigration = null; - } - - function _checkForUnsavedChanges() { - if (!_hasLoaded || !_loadedSettingsSnapshot) - return false; - const current = JSON.stringify(Store.toJson(root)); - return current !== _loadedSettingsSnapshot; - } - - function getCurrentSettingsJson() { - return JSON.stringify(Store.toJson(root), null, 2); - } - - function _resetPluginSettings() { - _pluginParseError = false; - pluginSettings = {}; - } - - function _pluginSettingsErrorCode(error) { - if (typeof error === "number") - return error; - if (error && typeof error === "object") { - if (typeof error.code === "number") - return error.code; - if (typeof error.errno === "number") - return error.errno; - } - - const msg = String(error || "").trim(); - if (/^\d+$/.test(msg)) - return Number(msg); - - return -1; - } - - function _isMissingPluginSettingsError(error) { - if (_pluginSettingsErrorCode(error) === 2) - return true; - - const msg = String(error || "").toLowerCase(); - return msg.indexOf("file does not exist") !== -1 || msg.indexOf("no such file") !== -1 || msg.indexOf("enoent") !== -1; - } - - function loadPluginSettings() { - try { - parsePluginSettings(pluginSettingsFile.text()); - } catch (e) { - const msg = e.message || String(e); - if (!_isMissingPluginSettingsError(e)) - console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg); - _resetPluginSettings(); - } - } - - function parsePluginSettings(content) { - _pluginSettingsLoading = true; - _pluginParseError = false; - try { - if (content && content.trim()) { - pluginSettings = JSON.parse(content); - } else { - pluginSettings = {}; - } - } catch (e) { - _pluginParseError = true; - const msg = e.message; - console.error("SettingsData: Failed to parse plugin_settings.json - file will not be overwritten. Error:", msg); - Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse plugin_settings.json"), msg)); - pluginSettings = {}; - } finally { - _pluginSettingsLoading = false; - } - } - - function saveSettings() { - if (_loading || _parseError || !_hasLoaded) - return; - _selfWrite = true; - settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2)); - if (_isReadOnly) - _checkSettingsWritable(); - } - - function savePluginSettings() { - if (_pluginSettingsLoading || _pluginParseError) - return; - pluginSettingsFile.setText(JSON.stringify(pluginSettings, null, 2)); - } - - function detectAvailableIconThemes() { - const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS") || ""; - const localData = Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation)); - const homeDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation)); - - const dataDirs = xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat([localData]) : ["/usr/share", "/usr/local/share", localData]; - - const iconPaths = dataDirs.map(d => d + "/icons").concat([homeDir + "/.icons"]); - const pathsArg = iconPaths.join(" "); - - const script = ` - echo "SYSDEFAULT:$(gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g" || echo '')" - for dir in ${pathsArg}; do - [ -d "$dir" ] || continue - for theme in "$dir"/*/; do - [ -d "$theme" ] || continue - basename "$theme" - done - done | grep -v '^icons$' | grep -v '^default$' | grep -v '^hicolor$' | grep -v '^locolor$' | sort -u - `; - - Proc.runCommand("detectIconThemes", ["sh", "-c", script], (output, exitCode) => { - const themes = ["System Default"]; - if (output && output.trim()) { - const lines = output.trim().split('\n'); - for (let i = 0; i < lines.length; i++) { - const line = lines[i].trim(); - if (line.startsWith("SYSDEFAULT:")) { - systemDefaultIconTheme = line.substring(11).trim(); - continue; - } - if (line) - themes.push(line); - } - } - availableIconThemes = themes; - }); - } - - function detectAvailableCursorThemes() { - const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS") || ""; - const localData = Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation)); - const homeDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation)); - - const dataDirs = xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat([localData]) : ["/usr/share", "/usr/local/share", localData]; - - const cursorPaths = dataDirs.map(d => d + "/icons").concat([homeDir + "/.icons", homeDir + "/.local/share/icons"]); - const pathsArg = cursorPaths.join(" "); - - const script = ` - echo "SYSDEFAULT:$(gsettings get org.gnome.desktop.interface cursor-theme 2>/dev/null | sed "s/'//g" || echo '')" - for dir in ${pathsArg}; do - [ -d "$dir" ] || continue - for theme in "$dir"/*/; do - [ -d "$theme" ] || continue - [ -d "$theme/cursors" ] || continue - basename "$theme" - done - done | grep -v '^icons$' | grep -v '^default$' | sort -u - `; - - Proc.runCommand("detectCursorThemes", ["sh", "-c", script], (output, exitCode) => { - const themes = ["System Default"]; - if (output && output.trim()) { - const lines = output.trim().split('\n'); - for (let i = 0; i < lines.length; i++) { - const line = lines[i].trim(); - if (line.startsWith("SYSDEFAULT:")) { - systemDefaultCursorTheme = line.substring(11).trim(); - continue; - } - if (line) - themes.push(line); - } - } - availableCursorThemes = themes; - }); - } - - function getEffectiveTimeFormat() { - if (use24HourClock) - return showSeconds ? "hh:mm:ss" : "hh:mm"; - if (padHours12Hour) - return showSeconds ? "hh:mm:ss AP" : "hh:mm AP"; - return showSeconds ? "h:mm:ss AP" : "h:mm AP"; - } - - function getEffectiveClockDateFormat() { - return clockDateFormat && clockDateFormat.length > 0 ? clockDateFormat : "ddd d"; - } - - function getEffectiveLockDateFormat() { - return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat; - } - - function initializeListModels() { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, defaultBar.leftWidgets, defaultBar.centerWidgets, defaultBar.rightWidgets); - } - } - - function updateListModel(listModel, order) { - Lists.update(listModel, order); - widgetDataChanged(); - } - - function hasNamedWorkspaces() { - if (typeof NiriService === "undefined" || !CompositorService.isNiri) - return false; - - for (var i = 0; i < NiriService.allWorkspaces.length; i++) { - var ws = NiriService.allWorkspaces[i]; - if (ws.name && ws.name.trim() !== "") - return true; - } - return false; - } - - function getNamedWorkspaces() { - var namedWorkspaces = []; - if (typeof NiriService === "undefined" || !CompositorService.isNiri) - return namedWorkspaces; - - for (const ws of NiriService.allWorkspaces) { - if (ws.name && ws.name.trim() !== "") { - namedWorkspaces.push(ws.name); - } - } - return namedWorkspaces; - } - - function getPopupYPosition(barHeight) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - const gothOffset = defaultBar?.gothCornersEnabled ? Theme.cornerRadius : 0; - const spacing = defaultBar?.spacing ?? 4; - const bottomGap = defaultBar?.bottomGap ?? 0; - return barHeight + spacing + bottomGap - gothOffset + Theme.popupDistance; - } - - function getPopupTriggerPosition(pos, screen, barThickness, widgetWidth, barSpacing, barPosition, barConfig) { - const relativeX = pos.x; - const relativeY = pos.y; - const defaultBar = barConfigs[0] || getBarConfig("default"); - const spacing = barSpacing !== undefined ? barSpacing : (defaultBar?.spacing ?? 4); - const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top); - const rawBottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0); - const bottomGap = Math.max(0, rawBottomGap); - - const useAutoGaps = (barConfig && barConfig.popupGapsAuto !== undefined) ? barConfig.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true); - const manualGapValue = (barConfig && barConfig.popupGapsManual !== undefined) ? barConfig.popupGapsManual : (defaultBar?.popupGapsManual ?? 4); - const popupGap = useAutoGaps ? Math.max(4, spacing) : manualGapValue; - - switch (position) { - case SettingsData.Position.Left: - return { - "x": barThickness + spacing + popupGap, - "y": relativeY, - "width": widgetWidth - }; - case SettingsData.Position.Right: - return { - "x": (screen?.width || 0) - (barThickness + spacing + popupGap), - "y": relativeY, - "width": widgetWidth - }; - case SettingsData.Position.Bottom: - return { - "x": relativeX, - "y": (screen?.height || 0) - (barThickness + spacing + bottomGap + popupGap), - "width": widgetWidth - }; - default: - return { - "x": relativeX, - "y": barThickness + spacing + bottomGap + popupGap, - "width": widgetWidth - }; - } - } - - function getAdjacentBarInfo(screen, barPosition, barConfig) { - if (!screen || !barConfig) { - return { - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }; - } - - if (barConfig.autoHide) { - return { - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }; - } - - const enabledBars = getEnabledBarConfigs(); - const defaultBar = barConfigs[0] || getBarConfig("default"); - const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top); - let topBar = 0; - let bottomBar = 0; - let leftBar = 0; - let rightBar = 0; - - for (var i = 0; i < enabledBars.length; i++) { - const other = enabledBars[i]; - if (other.id === barConfig.id) - continue; - if (other.autoHide) - continue; - const otherScreens = other.screenPreferences || ["all"]; - const barScreens = barConfig.screenPreferences || ["all"]; - const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") || otherScreens.some(s => isScreenInPreferences(screen, [s])); - - if (!onSameScreen) - continue; - const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4); - const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4); - const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing; - - const useAutoGaps = other.popupGapsAuto !== undefined ? other.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true); - const manualGap = other.popupGapsManual !== undefined ? other.popupGapsManual : (defaultBar?.popupGapsManual ?? 4); - const popupGap = useAutoGaps ? Math.max(4, otherSpacing) : manualGap; - - switch (other.position) { - case SettingsData.Position.Top: - topBar = Math.max(topBar, otherThickness + popupGap); - break; - case SettingsData.Position.Bottom: - bottomBar = Math.max(bottomBar, otherThickness + popupGap); - break; - case SettingsData.Position.Left: - leftBar = Math.max(leftBar, otherThickness + popupGap); - break; - case SettingsData.Position.Right: - rightBar = Math.max(rightBar, otherThickness + popupGap); - break; - } - } - - return { - "topBar": topBar, - "bottomBar": bottomBar, - "leftBar": leftBar, - "rightBar": rightBar - }; - } - - function getBarBounds(screen, barThickness, barPosition, barConfig) { - if (!screen) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - - const defaultBar = barConfigs[0] || getBarConfig("default"); - const wingRadius = (defaultBar?.gothCornerRadiusOverride ?? false) ? (defaultBar?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius; - const wingSize = (defaultBar?.gothCornersEnabled ?? false) ? Math.max(0, wingRadius) : 0; - const screenWidth = screen.width; - const screenHeight = screen.height; - const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top); - const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0); - - let topOffset = 0; - let bottomOffset = 0; - let leftOffset = 0; - let rightOffset = 0; - - if (barConfig) { - const enabledBars = getEnabledBarConfigs(); - for (var i = 0; i < enabledBars.length; i++) { - const other = enabledBars[i]; - if (other.id === barConfig.id) - continue; - const otherScreens = other.screenPreferences || ["all"]; - const barScreens = barConfig.screenPreferences || ["all"]; - const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") || otherScreens.some(s => isScreenInPreferences(screen, [s])); - - if (!onSameScreen) - continue; - const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4); - const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4); - const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing + wingSize; - const otherBottomGap = other.bottomGap !== undefined ? other.bottomGap : (defaultBar?.bottomGap ?? 0); - - switch (other.position) { - case SettingsData.Position.Top: - if (position === SettingsData.Position.Top && other.id < barConfig.id) { - topOffset += otherThickness; // Simple stacking for same pos - } else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) { - topOffset = Math.max(topOffset, otherThickness); - } - break; - case SettingsData.Position.Bottom: - if (position === SettingsData.Position.Bottom && other.id < barConfig.id) { - bottomOffset += (otherThickness + otherBottomGap); - } else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) { - bottomOffset = Math.max(bottomOffset, otherThickness + otherBottomGap); - } - break; - case SettingsData.Position.Left: - if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) { - leftOffset = Math.max(leftOffset, otherThickness); - } else if (position === SettingsData.Position.Left && other.id < barConfig.id) { - leftOffset += otherThickness; - } - break; - case SettingsData.Position.Right: - if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) { - rightOffset = Math.max(rightOffset, otherThickness); - } else if (position === SettingsData.Position.Right && other.id < barConfig.id) { - rightOffset += otherThickness; - } - break; - } - } - } - - switch (position) { - case SettingsData.Position.Top: - return { - "x": leftOffset, - "y": topOffset + bottomGap, - "width": screenWidth - leftOffset - rightOffset, - "height": barThickness + wingSize, - "wingSize": wingSize - }; - case SettingsData.Position.Bottom: - return { - "x": leftOffset, - "y": screenHeight - barThickness - wingSize - bottomGap - bottomOffset, - "width": screenWidth - leftOffset - rightOffset, - "height": barThickness + wingSize, - "wingSize": wingSize - }; - case SettingsData.Position.Left: - return { - "x": 0, - "y": topOffset, - "width": barThickness + wingSize, - "height": screenHeight - topOffset - bottomOffset, - "wingSize": wingSize - }; - case SettingsData.Position.Right: - return { - "x": screenWidth - barThickness - wingSize, - "y": topOffset, - "width": barThickness + wingSize, - "height": screenHeight - topOffset - bottomOffset, - "wingSize": wingSize - }; - } - - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - - function updateBarConfigs() { - barConfigsChanged(); - saveSettings(); - } - - function getBarConfig(barId) { - return barConfigs.find(cfg => cfg.id === barId) || null; - } - - function addBarConfig(config) { - const configs = JSON.parse(JSON.stringify(barConfigs)); - configs.push(config); - barConfigs = configs; - updateBarConfigs(); - } - - function updateBarConfig(barId, updates) { - const configs = JSON.parse(JSON.stringify(barConfigs)); - const index = configs.findIndex(cfg => cfg.id === barId); - if (index === -1) - return; - const positionChanged = updates.position !== undefined && configs[index].position !== updates.position; - - Object.assign(configs[index], updates); - barConfigs = configs; - updateBarConfigs(); - - if (positionChanged) { - NotificationService.dismissAllPopups(); - } - } - - function checkBarCollisions(barId) { - const bar = getBarConfig(barId); - if (!bar || !bar.enabled) - return []; - - const conflicts = []; - const enabledBars = getEnabledBarConfigs(); - - for (var i = 0; i < enabledBars.length; i++) { - const other = enabledBars[i]; - if (other.id === barId) - continue; - const samePosition = bar.position === other.position; - if (!samePosition) - continue; - const barScreens = bar.screenPreferences || ["all"]; - const otherScreens = other.screenPreferences || ["all"]; - - const hasAll = barScreens.includes("all") || otherScreens.includes("all"); - if (hasAll) { - conflicts.push({ - "barId": other.id, - "barName": other.name, - "reason": "Same position on all screens" - }); - continue; - } - - const overlapping = barScreens.some(screen => otherScreens.includes(screen)); - if (overlapping) { - conflicts.push({ - "barId": other.id, - "barName": other.name, - "reason": "Same position on overlapping screens" - }); - } - } - - return conflicts; - } - - function deleteBarConfig(barId) { - if (barId === "default") - return; - const configs = barConfigs.filter(cfg => cfg.id !== barId); - barConfigs = configs; - updateBarConfigs(); - } - - function getEnabledBarConfigs() { - return barConfigs.filter(cfg => cfg.enabled); - } - - function getScreensSortedByPosition() { - const screens = []; - for (var i = 0; i < Quickshell.screens.length; i++) { - screens.push(Quickshell.screens[i]); - } - screens.sort((a, b) => { - if (a.x !== b.x) - return a.x - b.x; - return a.y - b.y; - }); - return screens; - } - - function getScreenModelIndex(screen) { - if (!screen || !screen.model) - return -1; - const sorted = getScreensSortedByPosition(); - let modelCount = 0; - let screenIndex = -1; - for (var i = 0; i < sorted.length; i++) { - if (sorted[i].model === screen.model) { - if (sorted[i].name === screen.name) { - screenIndex = modelCount; - } - modelCount++; - } - } - if (modelCount <= 1) - return -1; - return screenIndex; - } - - function getScreenDisplayName(screen) { - if (!screen) - return ""; - if (displayNameMode === "model" && screen.model) { - const modelIndex = getScreenModelIndex(screen); - if (modelIndex >= 0) { - return screen.model + "-" + modelIndex; - } - return screen.model; - } - return screen.name; - } - - function isScreenInPreferences(screen, prefs) { - if (!screen) - return false; - - const screenDisplayName = getScreenDisplayName(screen); - - return prefs.some(pref => { - if (typeof pref === "string") { - if (pref === "all" || pref === screen.name) - return true; - if (displayNameMode === "model") { - return pref === screenDisplayName; - } - return pref === screen.model; - } - - if (displayNameMode === "model") { - if (pref.model && screen.model) { - if (pref.modelIndex !== undefined) { - const screenModelIndex = getScreenModelIndex(screen); - return pref.model === screen.model && pref.modelIndex === screenModelIndex; - } - return pref.model === screen.model; - } - return false; - } - return pref.name === screen.name; - }); - } - - function getFilteredScreens(componentId) { - var prefs = screenPreferences && screenPreferences[componentId] || ["all"]; - if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) { - return Quickshell.screens; - } - var filtered = Quickshell.screens.filter(screen => isScreenInPreferences(screen, prefs)); - if (filtered.length === 0 && showOnLastDisplay && showOnLastDisplay[componentId] && Quickshell.screens.length === 1) { - return Quickshell.screens; - } - return filtered; - } - - function sendTestNotifications() { - NotificationService.dismissAllPopups(); - sendTestNotification(0); - testNotifTimer1.start(); - testNotifTimer2.start(); - } - - function sendTestNotification(index) { - const notifications = [["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "preferences-system"], ["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "applications-graphics"], ["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "face-smile"]]; - - if (index < 0 || index >= notifications.length) { - return; - } - - const notif = notifications[index]; - testNotificationProcess.command = ["notify-send", "-h", "int:transient:1", "-a", "DMS", "-i", notif[2], notif[0], notif[1]]; - testNotificationProcess.running = true; - } - - function setMatugenScheme(scheme) { - var normalized = scheme || "scheme-tonal-spot"; - if (matugenScheme === normalized) - return; - set("matugenScheme", normalized); - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setMatugenContrast(value) { - if (matugenContrast === value) - return; - set("matugenContrast", value); - } - - function setRunUserMatugenTemplates(enabled) { - if (runUserMatugenTemplates === enabled) - return; - set("runUserMatugenTemplates", enabled); - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setMatugenTargetMonitor(monitorName) { - if (matugenTargetMonitor === monitorName) - return; - set("matugenTargetMonitor", monitorName); - if (typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setCornerRadius(radius) { - set("cornerRadius", radius); - updateCompositorLayout(); - } - - function setWeatherLocation(displayName, coordinates) { - SessionData.setWeatherLocation(displayName, coordinates); - } - - function setIconTheme(themeName) { - iconTheme = themeName; - updateGtkIconTheme(); - updateQtIconTheme(); - updateCosmicIconTheme(); - saveSettings(); - if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic) - Theme.generateSystemThemesFromCurrentTheme(); - } - - function setCursorTheme(themeName) { - const updated = JSON.parse(JSON.stringify(cursorSettings)); - if (updated.theme === themeName) - return; - updated.theme = themeName; - cursorSettings = updated; - saveSettings(); - updateXResources(); - updateCompositorCursor(); - } - - function setCursorSize(size) { - const updated = JSON.parse(JSON.stringify(cursorSettings)); - if (updated.size === size) - return; - updated.size = size; - cursorSettings = updated; - saveSettings(); - updateXResources(); - updateCompositorCursor(); - } - - // This solution for xwayland cursor themes is from the xwls discussion: - // https://github.com/Supreeeme/xwayland-satellite/issues/104 - // no idea if this matters on other compositors but we also set XCURSOR stuff in the launcher - function updateCompositorCursor() { - if (typeof CompositorService === "undefined") - return; - if (CompositorService.isNiri && typeof NiriService !== "undefined") { - NiriService.generateNiriCursorConfig(); - return; - } - if (CompositorService.isHyprland && typeof HyprlandService !== "undefined") { - HyprlandService.generateCursorConfig(); - return; - } - if (CompositorService.isDwl && typeof DwlService !== "undefined") { - DwlService.generateCursorConfig(); - return; - } - } - - function updateXResources() { - const homeDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation)); - const xresourcesPath = homeDir + "/.Xresources"; - const themeName = cursorSettings.theme === "System Default" ? systemDefaultCursorTheme : cursorSettings.theme; - const size = cursorSettings.size || 24; - - if (!themeName) - return; - - const script = ` - xresources_file="${xresourcesPath}" - [ -f "$xresources_file" ] && [ ! -w "$xresources_file" ] && exit 0 - theme_name="${themeName}" - cursor_size="${size}" - - current_theme="" - current_size="" - if [ -f "$xresources_file" ]; then - current_theme=$(grep -E '^[[:space:]]*Xcursor\\.theme:' "$xresources_file" 2>/dev/null | sed 's/.*:[[:space:]]*//' | head -1) - current_size=$(grep -E '^[[:space:]]*Xcursor\\.size:' "$xresources_file" 2>/dev/null | sed 's/.*:[[:space:]]*//' | head -1) - fi - - [ "$current_theme" = "$theme_name" ] && [ "$current_size" = "$cursor_size" ] && exit 0 - - if [ -f "$xresources_file" ]; then - cp "$xresources_file" "\${xresources_file}.backup$(date +%s)" - fi - - temp_file="\${xresources_file}.tmp.$$" - if [ -f "$xresources_file" ]; then - grep -v '^[[:space:]]*Xcursor\\.theme:' "$xresources_file" | grep -v '^[[:space:]]*Xcursor\\.size:' > "$temp_file" 2>/dev/null || true - else - touch "$temp_file" - fi - - echo "Xcursor.theme: $theme_name" >> "$temp_file" - echo "Xcursor.size: $cursor_size" >> "$temp_file" - mv "$temp_file" "$xresources_file" - xrdb -merge "$xresources_file" 2>/dev/null || true - `; - - Quickshell.execDetached(["sh", "-c", script]); - } - - function getCursorEnvironment() { - const isSystemDefault = cursorSettings.theme === "System Default"; - const isDefaultSize = !cursorSettings.size || cursorSettings.size === 24; - if (isSystemDefault && isDefaultSize) - return {}; - - const themeName = isSystemDefault ? "" : cursorSettings.theme; - const size = String(cursorSettings.size || 24); - const env = {}; - - if (!isDefaultSize) { - env["XCURSOR_SIZE"] = size; - env["HYPRCURSOR_SIZE"] = size; - } - if (themeName) { - env["XCURSOR_THEME"] = themeName; - env["HYPRCURSOR_THEME"] = themeName; - } - return env; - } - - function setGtkThemingEnabled(enabled) { - set("gtkThemingEnabled", enabled); - if (enabled && typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setQtThemingEnabled(enabled) { - set("qtThemingEnabled", enabled); - if (enabled && typeof Theme !== "undefined") { - Theme.generateSystemThemesFromCurrentTheme(); - } - } - - function setShowDock(enabled) { - showDock = enabled; - const defaultBar = barConfigs[0] || getBarConfig("default"); - const barPos = defaultBar?.position ?? SettingsData.Position.Top; - if (enabled && dockPosition === barPos) { - if (barPos === SettingsData.Position.Top) { - setDockPosition(SettingsData.Position.Bottom); - return; - } - if (barPos === SettingsData.Position.Bottom) { - setDockPosition(SettingsData.Position.Top); - return; - } - if (barPos === SettingsData.Position.Left) { - setDockPosition(SettingsData.Position.Right); - return; - } - if (barPos === SettingsData.Position.Right) { - setDockPosition(SettingsData.Position.Left); - return; - } - } - saveSettings(); - } - - function setDockPosition(position) { - dockPosition = position; - const defaultBar = barConfigs[0] || getBarConfig("default"); - const barPos = defaultBar?.position ?? SettingsData.Position.Top; - if (position === SettingsData.Position.Bottom && barPos === SettingsData.Position.Bottom && showDock) { - setDankBarPosition(SettingsData.Position.Top); - } - if (position === SettingsData.Position.Top && barPos === SettingsData.Position.Top && showDock) { - setDankBarPosition(SettingsData.Position.Bottom); - } - if (position === SettingsData.Position.Left && barPos === SettingsData.Position.Left && showDock) { - setDankBarPosition(SettingsData.Position.Right); - } - if (position === SettingsData.Position.Right && barPos === SettingsData.Position.Right && showDock) { - setDankBarPosition(SettingsData.Position.Left); - } - saveSettings(); - Qt.callLater(() => forceDockLayoutRefresh()); - } - - function setDankBarSpacing(spacing) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "spacing": spacing - }); - } - updateCompositorLayout(); - } - - function setDankBarPosition(position) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (!defaultBar) - return; - if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) { - setDockPosition(SettingsData.Position.Top); - return; - } - if (position === SettingsData.Position.Top && dockPosition === SettingsData.Position.Top && showDock) { - setDockPosition(SettingsData.Position.Bottom); - return; - } - if (position === SettingsData.Position.Left && dockPosition === SettingsData.Position.Left && showDock) { - setDockPosition(SettingsData.Position.Right); - return; - } - if (position === SettingsData.Position.Right && dockPosition === SettingsData.Position.Right && showDock) { - setDockPosition(SettingsData.Position.Left); - return; - } - updateBarConfig(defaultBar.id, { - "position": position - }); - } - - function setDankBarLeftWidgets(order) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "leftWidgets": order - }); - updateListModel(leftWidgetsModel, order); - } - } - - function setDankBarCenterWidgets(order) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "centerWidgets": order - }); - updateListModel(centerWidgetsModel, order); - } - } - - function setDankBarRightWidgets(order) { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "rightWidgets": order - }); - updateListModel(rightWidgetsModel, order); - } - } - - function resetDankBarWidgetsToDefault() { - var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]; - var defaultCenter = ["music", "clock", "weather"]; - var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]; - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "leftWidgets": defaultLeft, - "centerWidgets": defaultCenter, - "rightWidgets": defaultRight - }); - } - updateListModel(leftWidgetsModel, defaultLeft); - updateListModel(centerWidgetsModel, defaultCenter); - updateListModel(rightWidgetsModel, defaultRight); - showLauncherButton = true; - showWorkspaceSwitcher = true; - showFocusedWindow = true; - showWeather = true; - showMusic = true; - showClipboard = true; - showCpuUsage = true; - showMemUsage = true; - showCpuTemp = true; - showGpuTemp = true; - showSystemTray = true; - showClock = true; - showNotificationButton = true; - showBattery = true; - showControlCenterButton = true; - showCapsLockIndicator = true; - } - - function setWorkspaceNameIcon(workspaceName, iconData) { - var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons)); - iconMap[workspaceName] = iconData; - workspaceNameIcons = iconMap; - saveSettings(); - workspaceIconsUpdated(); - } - - function removeWorkspaceNameIcon(workspaceName) { - var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons)); - delete iconMap[workspaceName]; - workspaceNameIcons = iconMap; - saveSettings(); - workspaceIconsUpdated(); - } - - function getWorkspaceNameIcon(workspaceName) { - return workspaceNameIcons[workspaceName] || null; - } - - function addAppIdSubstitution(pattern, replacement, type) { - var subs = JSON.parse(JSON.stringify(appIdSubstitutions)); - subs.push({ - pattern: pattern, - replacement: replacement, - type: type - }); - appIdSubstitutions = subs; - saveSettings(); - } - - function updateAppIdSubstitution(index, pattern, replacement, type) { - var subs = JSON.parse(JSON.stringify(appIdSubstitutions)); - if (index < 0 || index >= subs.length) - return; - subs[index] = { - pattern: pattern, - replacement: replacement, - type: type - }; - appIdSubstitutions = subs; - saveSettings(); - } - - function removeAppIdSubstitution(index) { - var subs = JSON.parse(JSON.stringify(appIdSubstitutions)); - if (index < 0 || index >= subs.length) - return; - subs.splice(index, 1); - appIdSubstitutions = subs; - saveSettings(); - } - - property bool _pendingExpandNotificationRules: false - property int _pendingNotificationRuleIndex: -1 - - function addNotificationRule() { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - rules.push({ - enabled: true, - field: "appName", - pattern: "", - matchType: "contains", - action: "default", - urgency: "default" - }); - notificationRules = rules; - saveSettings(); - } - - function addNotificationRuleForNotification(appName, desktopEntry) { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - var pattern = (desktopEntry && desktopEntry !== "") ? desktopEntry : (appName || ""); - var field = (desktopEntry && desktopEntry !== "") ? "desktopEntry" : "appName"; - var rule = { - enabled: true, - field: pattern ? field : "appName", - pattern: pattern || "", - matchType: pattern ? "exact" : "contains", - action: "default", - urgency: "default" - }; - rules.push(rule); - notificationRules = rules; - saveSettings(); - var index = rules.length - 1; - _pendingExpandNotificationRules = true; - _pendingNotificationRuleIndex = index; - return index; - } - - function addMuteRuleForApp(appName, desktopEntry) { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - var pattern = (desktopEntry && desktopEntry !== "") ? desktopEntry : (appName || ""); - var field = (desktopEntry && desktopEntry !== "") ? "desktopEntry" : "appName"; - if (pattern === "") - return; - rules.push({ - enabled: true, - field: field, - pattern: pattern, - matchType: "exact", - action: "mute", - urgency: "default" - }); - notificationRules = rules; - saveSettings(); - } - - function isAppMuted(appName, desktopEntry) { - const rules = notificationRules || []; - const pat = (desktopEntry && desktopEntry !== "" ? desktopEntry : appName || "").toString().toLowerCase(); - if (!pat) - return false; - for (let i = 0; i < rules.length; i++) { - const r = rules[i]; - if ((r.action || "").toString().toLowerCase() !== "mute" || r.enabled === false) - continue; - const field = (r.field || "appName").toString().toLowerCase(); - const rulePat = (r.pattern || "").toString().toLowerCase(); - if (!rulePat) - continue; - const useDesktop = field === "desktopentry"; - const matches = (useDesktop && desktopEntry) ? (desktopEntry.toString().toLowerCase() === rulePat) : (appName && appName.toString().toLowerCase() === rulePat); - if (matches) - return true; - if (rulePat === pat) - return true; - } - return false; - } - - function removeMuteRuleForApp(appName, desktopEntry) { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - const app = (appName || "").toString().toLowerCase(); - const desktop = (desktopEntry || "").toString().toLowerCase(); - if (!app && !desktop) - return; - for (let i = rules.length - 1; i >= 0; i--) { - const r = rules[i]; - if ((r.action || "").toString().toLowerCase() !== "mute") - continue; - const rulePat = (r.pattern || "").toString().toLowerCase(); - if (!rulePat) - continue; - if (rulePat === app || rulePat === desktop) { - rules.splice(i, 1); - notificationRules = rules; - saveSettings(); - return; - } - } - } - - function updateNotificationRule(index, ruleData) { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - if (index < 0 || index >= rules.length) - return; - var existing = rules[index] || {}; - rules[index] = Object.assign({}, existing, ruleData || {}); - notificationRules = rules; - saveSettings(); - } - - function updateNotificationRuleField(index, key, value) { - if (key === undefined || key === null || key === "") - return; - var patch = {}; - patch[key] = value; - updateNotificationRule(index, patch); - } - - function removeNotificationRule(index) { - var rules = JSON.parse(JSON.stringify(notificationRules || [])); - if (index < 0 || index >= rules.length) - return; - rules.splice(index, 1); - notificationRules = rules; - saveSettings(); - } - - function getDefaultNotificationRules() { - return Spec.SPEC.notificationRules.def; - } - - function resetNotificationRules() { - notificationRules = JSON.parse(JSON.stringify(Spec.SPEC.notificationRules.def)); - saveSettings(); - } - - function getDefaultAppIdSubstitutions() { - return Spec.SPEC.appIdSubstitutions.def; - } - - function resetAppIdSubstitutions() { - appIdSubstitutions = JSON.parse(JSON.stringify(Spec.SPEC.appIdSubstitutions.def)); - saveSettings(); - } - - function getRegistryThemeVariant(themeId, defaultVariant) { - var stored = registryThemeVariants[themeId]; - if (typeof stored === "string") - return stored || defaultVariant || ""; - return defaultVariant || ""; - } - - function setRegistryThemeVariant(themeId, variantId) { - var variants = JSON.parse(JSON.stringify(registryThemeVariants)); - variants[themeId] = variantId; - registryThemeVariants = variants; - saveSettings(); - if (typeof Theme !== "undefined") - Theme.reloadCustomThemeVariant(); - } - - function getRegistryThemeMultiVariant(themeId, defaults, mode) { - var stored = registryThemeVariants[themeId]; - if (!stored || typeof stored !== "object") - return defaults || {}; - if ((stored.dark && typeof stored.dark === "object") || (stored.light && typeof stored.light === "object")) { - if (!mode) - return stored.dark || stored.light || defaults || {}; - var modeData = stored[mode]; - if (modeData && typeof modeData === "object") - return modeData; - return defaults || {}; - } - return stored; - } - - function setRegistryThemeMultiVariant(themeId, flavor, accent, mode) { - var variants = JSON.parse(JSON.stringify(registryThemeVariants)); - var existing = variants[themeId]; - var perMode = {}; - if (existing && typeof existing === "object") { - if ((existing.dark && typeof existing.dark === "object") || (existing.light && typeof existing.light === "object")) { - perMode = existing; - } else if (typeof existing.flavor === "string") { - perMode.dark = { - flavor: existing.flavor, - accent: existing.accent || "" - }; - } - } - perMode[mode || "dark"] = { - flavor: flavor, - accent: accent - }; - variants[themeId] = perMode; - registryThemeVariants = variants; - saveSettings(); - if (typeof Theme !== "undefined") - Theme.reloadCustomThemeVariant(); - } - - function toggleDankBarVisible() { - const defaultBar = barConfigs[0] || getBarConfig("default"); - if (defaultBar) { - updateBarConfig(defaultBar.id, { - "visible": !defaultBar.visible - }); - } - } - - function toggleShowDock() { - setShowDock(!showDock); - } - - function getPluginSetting(pluginId, key, defaultValue) { - if (!pluginSettings[pluginId]) { - return defaultValue; - } - return pluginSettings[pluginId][key] !== undefined ? pluginSettings[pluginId][key] : defaultValue; - } - - function setPluginSetting(pluginId, key, value) { - const updated = JSON.parse(JSON.stringify(pluginSettings)); - if (!updated[pluginId]) { - updated[pluginId] = {}; - } - updated[pluginId][key] = value; - pluginSettings = updated; - savePluginSettings(); - } - - function removePluginSettings(pluginId) { - if (pluginSettings[pluginId]) { - delete pluginSettings[pluginId]; - savePluginSettings(); - } - } - - function getPluginSettingsForPlugin(pluginId) { - const settings = pluginSettings[pluginId]; - return settings ? JSON.parse(JSON.stringify(settings)) : {}; - } - - function getNiriOutputSetting(outputId, key, defaultValue) { - if (!niriOutputSettings[outputId]) - return defaultValue; - return niriOutputSettings[outputId][key] !== undefined ? niriOutputSettings[outputId][key] : defaultValue; - } - - function setNiriOutputSetting(outputId, key, value) { - const updated = JSON.parse(JSON.stringify(niriOutputSettings)); - if (!updated[outputId]) - updated[outputId] = {}; - updated[outputId][key] = value; - niriOutputSettings = updated; - saveSettings(); - } - - function getNiriOutputSettings(outputId) { - const settings = niriOutputSettings[outputId]; - return settings ? JSON.parse(JSON.stringify(settings)) : {}; - } - - function setNiriOutputSettings(outputId, settings) { - const updated = JSON.parse(JSON.stringify(niriOutputSettings)); - updated[outputId] = settings; - niriOutputSettings = updated; - saveSettings(); - } - - function removeNiriOutputSettings(outputId) { - if (!niriOutputSettings[outputId]) - return; - const updated = JSON.parse(JSON.stringify(niriOutputSettings)); - delete updated[outputId]; - niriOutputSettings = updated; - saveSettings(); - } - - function getHyprlandOutputSetting(outputId, key, defaultValue) { - if (!hyprlandOutputSettings[outputId]) - return defaultValue; - return hyprlandOutputSettings[outputId][key] !== undefined ? hyprlandOutputSettings[outputId][key] : defaultValue; - } - - function setHyprlandOutputSetting(outputId, key, value) { - const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings)); - if (!updated[outputId]) - updated[outputId] = {}; - updated[outputId][key] = value; - hyprlandOutputSettings = updated; - saveSettings(); - } - - function removeHyprlandOutputSetting(outputId, key) { - if (!hyprlandOutputSettings[outputId] || !(key in hyprlandOutputSettings[outputId])) - return; - const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings)); - delete updated[outputId][key]; - hyprlandOutputSettings = updated; - saveSettings(); - } - - function getHyprlandOutputSettings(outputId) { - const settings = hyprlandOutputSettings[outputId]; - return settings ? JSON.parse(JSON.stringify(settings)) : {}; - } - - function setHyprlandOutputSettings(outputId, settings) { - const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings)); - updated[outputId] = settings; - hyprlandOutputSettings = updated; - saveSettings(); - } - - function removeHyprlandOutputSettings(outputId) { - if (!hyprlandOutputSettings[outputId]) - return; - const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings)); - delete updated[outputId]; - hyprlandOutputSettings = updated; - saveSettings(); - } - - function getDisplayProfiles(compositor) { - return displayProfiles[compositor] || {}; - } - - function setDisplayProfile(compositor, profileId, data) { - const updated = JSON.parse(JSON.stringify(displayProfiles)); - if (!updated[compositor]) - updated[compositor] = {}; - updated[compositor][profileId] = data; - displayProfiles = updated; - saveSettings(); - } - - function removeDisplayProfile(compositor, profileId) { - if (!displayProfiles[compositor] || !displayProfiles[compositor][profileId]) - return; - const updated = JSON.parse(JSON.stringify(displayProfiles)); - delete updated[compositor][profileId]; - displayProfiles = updated; - saveSettings(); - } - - function getActiveDisplayProfile(compositor) { - return activeDisplayProfile[compositor] || ""; - } - - function setActiveDisplayProfile(compositor, profileId) { - const updated = JSON.parse(JSON.stringify(activeDisplayProfile)); - updated[compositor] = profileId; - activeDisplayProfile = updated; - saveSettings(); - } - - ListModel { - id: leftWidgetsModel - } - - ListModel { - id: centerWidgetsModel - } - - ListModel { - id: rightWidgetsModel - } - - property Process testNotificationProcess - - testNotificationProcess: Process { - command: [] - running: false - } - - property Timer testNotifTimer1 - - testNotifTimer1: Timer { - interval: 400 - repeat: false - onTriggered: sendTestNotification(1) - } - - property Timer testNotifTimer2 - - testNotifTimer2: Timer { - interval: 800 - repeat: false - onTriggered: sendTestNotification(2) - } - - property alias settingsFile: settingsFile - - Timer { - id: settingsFileReloadDebounce - interval: 50 - onTriggered: settingsFile.reload() - repeat: false - } - - FileView { - id: settingsFile - - path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json" - blockLoading: true - blockWrites: true - atomicWrites: true - watchChanges: true - onFileChanged: { - if (_selfWrite) { - _selfWrite = false; - return; - } - settingsFileReloadDebounce.restart(); - } - onLoaded: { - if (isGreeterMode) - return; - _loading = true; - _hasUnsavedChanges = false; - try { - const txt = settingsFile.text(); - if (!txt || !txt.trim()) { - _parseError = true; - return; - } - const obj = JSON.parse(txt); - _parseError = false; - Store.parse(root, obj); - - if (obj.weatherLocation !== undefined) - _legacyWeatherLocation = obj.weatherLocation; - if (obj.weatherCoordinates !== undefined) - _legacyWeatherCoordinates = obj.weatherCoordinates; - if (obj.vpnLastConnected !== undefined && obj.vpnLastConnected !== "") { - _legacyVpnLastConnected = obj.vpnLastConnected; - SessionData.vpnLastConnected = _legacyVpnLastConnected; - SessionData.saveSettings(); - } - - _loadedSettingsSnapshot = JSON.stringify(Store.toJson(root)); - _hasLoaded = true; - applyStoredTheme(); - updateCompositorCursor(); - } catch (e) { - _parseError = true; - const msg = e.message; - console.error("SettingsData: Failed to reload settings.json - file will not be overwritten. Error:", msg); - Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg)); - } finally { - _loading = false; - } - } - onLoadFailed: error => { - if (!isGreeterMode) { - applyStoredTheme(); - } - } - onSaveFailed: error => { - root._isReadOnly = true; - root._hasUnsavedChanges = root._checkForUnsavedChanges(); - } - } - - FileView { - id: pluginSettingsFile - - path: isGreeterMode ? "" : pluginSettingsPath - blockLoading: true - blockWrites: true - atomicWrites: true - printErrors: false - watchChanges: !isGreeterMode - onLoaded: { - if (!isGreeterMode) { - parsePluginSettings(pluginSettingsFile.text()); - } - } - onLoadFailed: error => { - if (!isGreeterMode) { - const msg = String(error || ""); - if (!_isMissingPluginSettingsError(error)) - console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg); - _resetPluginSettings(); - } - } - } - - property bool pluginSettingsFileExists: false - - Process { - id: settingsWritableCheckProcess - - property string settingsPath: Paths.strip(settingsFile.path) - - command: ["sh", "-c", "[ ! -f \"" + settingsPath + "\" ] || [ -w \"" + settingsPath + "\" ] && echo 'writable' || echo 'readonly'"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const result = text.trim(); - root._onWritableCheckComplete(result === "writable"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/StockThemes.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/StockThemes.js deleted file mode 100644 index 311c27f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/StockThemes.js +++ /dev/null @@ -1,468 +0,0 @@ -// Stock theme definitions for DankMaterialShell -// Separated from Theme.qml to keep that file clean - -const StockThemes = { - DARK: { - blue: { - name: "Blue", - primary: "#42a5f5", - primaryText: "#000000", - primaryContainer: "#0d47a1", - secondary: "#8ab4f8", - surface: "#101418", - surfaceText: "#e0e2e8", - surfaceVariant: "#42474e", - surfaceVariantText: "#c2c7cf", - surfaceTint: "#8ab4f8", - background: "#101418", - backgroundText: "#e0e2e8", - outline: "#8c9199", - surfaceContainer: "#1d2024", - surfaceContainerHigh: "#272a2f", - surfaceContainerHighest: "#32353a", - }, - purple: { - name: "Purple", - primary: "#D0BCFF", - primaryText: "#381E72", - primaryContainer: "#4F378B", - secondary: "#CCC2DC", - surface: "#141218", - surfaceText: "#e6e0e9", - surfaceVariant: "#49454e", - surfaceVariantText: "#cac4cf", - surfaceTint: "#D0BCFF", - background: "#141218", - backgroundText: "#e6e0e9", - outline: "#948f99", - surfaceContainer: "#211f24", - surfaceContainerHigh: "#2b292f", - surfaceContainerHighest: "#36343a", - }, - green: { - name: "Green", - primary: "#4caf50", - primaryText: "#000000", - primaryContainer: "#1b5e20", - secondary: "#81c995", - surface: "#10140f", - surfaceText: "#e0e4db", - surfaceVariant: "#424940", - surfaceVariantText: "#c2c9bd", - surfaceTint: "#81c995", - background: "#10140f", - backgroundText: "#e0e4db", - outline: "#8c9388", - surfaceContainer: "#1d211b", - surfaceContainerHigh: "#272b25", - surfaceContainerHighest: "#323630", - }, - orange: { - name: "Orange", - primary: "#ff6d00", - primaryText: "#000000", - primaryContainer: "#3e2723", - secondary: "#ffb74d", - surface: "#1a120e", - surfaceText: "#f0dfd8", - surfaceVariant: "#52443d", - surfaceVariantText: "#d7c2b9", - surfaceTint: "#ffb74d", - background: "#1a120e", - backgroundText: "#f0dfd8", - outline: "#a08d85", - surfaceContainer: "#271e1a", - surfaceContainerHigh: "#322824", - surfaceContainerHighest: "#3d332e", - }, - red: { - name: "Red", - primary: "#f44336", - primaryText: "#000000", - primaryContainer: "#4a0e0e", - secondary: "#f28b82", - surface: "#1a1110", - surfaceText: "#f1dedc", - surfaceVariant: "#534341", - surfaceVariantText: "#d8c2be", - surfaceTint: "#f28b82", - background: "#1a1110", - backgroundText: "#f1dedc", - outline: "#a08c89", - surfaceContainer: "#271d1c", - surfaceContainerHigh: "#322826", - surfaceContainerHighest: "#3d3231", - }, - cyan: { - name: "Cyan", - primary: "#00bcd4", - primaryText: "#000000", - primaryContainer: "#004d5c", - secondary: "#4dd0e1", - surface: "#0e1416", - surfaceText: "#dee3e5", - surfaceVariant: "#3f484a", - surfaceVariantText: "#bfc8ca", - surfaceTint: "#4dd0e1", - background: "#0e1416", - backgroundText: "#dee3e5", - outline: "#899295", - surfaceContainer: "#1b2122", - surfaceContainerHigh: "#252b2c", - surfaceContainerHighest: "#303637", - }, - pink: { - name: "Pink", - primary: "#e91e63", - primaryText: "#000000", - primaryContainer: "#4a0e2f", - secondary: "#f8bbd9", - surface: "#191112", - surfaceText: "#f0dee0", - surfaceVariant: "#524345", - surfaceVariantText: "#d6c2c3", - surfaceTint: "#f8bbd9", - background: "#191112", - backgroundText: "#f0dee0", - outline: "#9f8c8e", - surfaceContainer: "#261d1e", - surfaceContainerHigh: "#312829", - surfaceContainerHighest: "#3c3233", - }, - amber: { - name: "Amber", - primary: "#ffc107", - primaryText: "#000000", - primaryContainer: "#4a3c00", - secondary: "#ffd54f", - surface: "#17130b", - surfaceText: "#ebe1d4", - surfaceVariant: "#4d4639", - surfaceVariantText: "#d0c5b4", - surfaceTint: "#ffd54f", - background: "#17130b", - backgroundText: "#ebe1d4", - outline: "#998f80", - surfaceContainer: "#231f17", - surfaceContainerHigh: "#2e2921", - surfaceContainerHighest: "#39342b", - }, - coral: { - name: "Coral", - primary: "#ffb4ab", - primaryText: "#000000", - primaryContainer: "#8c1d18", - secondary: "#f9dedc", - surface: "#1a1110", - surfaceText: "#f1dedc", - surfaceVariant: "#534341", - surfaceVariantText: "#d8c2bf", - surfaceTint: "#ffb4ab", - background: "#1a1110", - backgroundText: "#f1dedc", - outline: "#a08c8a", - surfaceContainer: "#271d1c", - surfaceContainerHigh: "#322826", - surfaceContainerHighest: "#3d3231", - }, - raveos: { - name: "RaveOS", - primary: "#3d7839", - primaryText: "#ffffff", - primaryContainer: "#1e3c1c", - secondary: "#5c8a58", - surface: "#0e140d", - surfaceText: "#e0e4db", - surfaceVariant: "#40493e", - surfaceVariantText: "#c0c9bc", - surfaceTint: "#5c8a58", - background: "#0e140d", - backgroundText: "#e0e4db", - outline: "#8a9386", - surfaceContainer: "#1a2119", - surfaceContainerHigh: "#242b22", - surfaceContainerHighest: "#2f362d", - }, - monochrome: { - name: "Monochrome", - primary: "#ffffff", - primaryText: "#2b303c", - primaryContainer: "#424753", - secondary: "#c4c6d0", - surface: "#2a2a2a", - surfaceText: "#e4e2e3", - surfaceVariant: "#474648", - surfaceVariantText: "#c8c6c7", - surfaceTint: "#c2c6d6", - background: "#131315", - backgroundText: "#e4e2e3", - outline: "#929092", - surfaceContainer: "#353535", - surfaceContainerHigh: "#424242", - surfaceContainerHighest: "#505050", - error: "#ffb4ab", - warning: "#3f4759", - info: "#595e6c", - matugen_type: "scheme-monochrome", - }, - }, - LIGHT: { - blue: { - name: "Blue Light", - primary: "#1976d2", - primaryText: "#ffffff", - primaryContainer: "#e3f2fd", - secondary: "#42a5f5", - surface: "#f7f9ff", - surfaceText: "#181c20", - surfaceVariant: "#dee3eb", - surfaceVariantText: "#42474e", - surfaceTint: "#1976d2", - background: "#f7f9ff", - backgroundText: "#181c20", - outline: "#72777f", - surfaceContainer: "#eceef4", - surfaceContainerHigh: "#e6e8ee", - surfaceContainerHighest: "#e0e2e8", - }, - purple: { - name: "Purple Light", - primary: "#6750A4", - primaryText: "#ffffff", - primaryContainer: "#EADDFF", - secondary: "#625B71", - surface: "#fef7ff", - surfaceText: "#1d1b20", - surfaceVariant: "#e7e0eb", - surfaceVariantText: "#49454e", - surfaceTint: "#6750A4", - background: "#fef7ff", - backgroundText: "#1d1b20", - outline: "#7a757f", - surfaceContainer: "#f2ecf4", - surfaceContainerHigh: "#ece6ee", - surfaceContainerHighest: "#e6e0e9", - }, - green: { - name: "Green Light", - primary: "#2e7d32", - primaryText: "#ffffff", - primaryContainer: "#e8f5e8", - secondary: "#4caf50", - surface: "#f7fbf1", - surfaceText: "#191d17", - surfaceVariant: "#dee5d8", - surfaceVariantText: "#424940", - surfaceTint: "#2e7d32", - background: "#f7fbf1", - backgroundText: "#191d17", - outline: "#72796f", - surfaceContainer: "#ecefe6", - surfaceContainerHigh: "#e6e9e0", - surfaceContainerHighest: "#e0e4db", - }, - orange: { - name: "Orange Light", - primary: "#e65100", - primaryText: "#ffffff", - primaryContainer: "#ffecb3", - secondary: "#ff9800", - surface: "#fff8f6", - surfaceText: "#221a16", - surfaceVariant: "#f4ded5", - surfaceVariantText: "#52443d", - surfaceTint: "#e65100", - background: "#fff8f6", - backgroundText: "#221a16", - outline: "#85736c", - surfaceContainer: "#fceae3", - surfaceContainerHigh: "#f6e5de", - surfaceContainerHighest: "#f0dfd8", - }, - red: { - name: "Red Light", - primary: "#d32f2f", - primaryText: "#ffffff", - primaryContainer: "#ffebee", - secondary: "#f44336", - surface: "#fff8f7", - surfaceText: "#231918", - surfaceVariant: "#f5ddda", - surfaceVariantText: "#534341", - surfaceTint: "#d32f2f", - background: "#fff8f7", - backgroundText: "#231918", - outline: "#857370", - surfaceContainer: "#fceae7", - surfaceContainerHigh: "#f7e4e1", - surfaceContainerHighest: "#f1dedc", - }, - cyan: { - name: "Cyan Light", - primary: "#0097a7", - primaryText: "#ffffff", - primaryContainer: "#e0f2f1", - secondary: "#00bcd4", - surface: "#f5fafc", - surfaceText: "#171d1e", - surfaceVariant: "#dbe4e6", - surfaceVariantText: "#3f484a", - surfaceTint: "#0097a7", - background: "#f5fafc", - backgroundText: "#171d1e", - outline: "#6f797b", - surfaceContainer: "#e9eff0", - surfaceContainerHigh: "#e3e9eb", - surfaceContainerHighest: "#dee3e5", - }, - pink: { - name: "Pink Light", - primary: "#c2185b", - primaryText: "#ffffff", - primaryContainer: "#fce4ec", - secondary: "#e91e63", - surface: "#fff8f7", - surfaceText: "#22191a", - surfaceVariant: "#f3dddf", - surfaceVariantText: "#524345", - surfaceTint: "#c2185b", - background: "#fff8f7", - backgroundText: "#22191a", - outline: "#847375", - surfaceContainer: "#fbeaeb", - surfaceContainerHigh: "#f5e4e5", - surfaceContainerHighest: "#f0dee0", - }, - amber: { - name: "Amber Light", - primary: "#ff8f00", - primaryText: "#000000", - primaryContainer: "#fff8e1", - secondary: "#ffc107", - surface: "#fff8f2", - surfaceText: "#1f1b13", - surfaceVariant: "#ede1cf", - surfaceVariantText: "#4d4639", - surfaceTint: "#ff8f00", - background: "#fff8f2", - backgroundText: "#1f1b13", - outline: "#7f7667", - surfaceContainer: "#f6ecdf", - surfaceContainerHigh: "#f1e7d9", - surfaceContainerHighest: "#ebe1d4", - }, - coral: { - name: "Coral Light", - primary: "#8c1d18", - primaryText: "#ffffff", - primaryContainer: "#ffdad6", - secondary: "#ff5449", - surface: "#fff8f7", - surfaceText: "#231918", - surfaceVariant: "#f5ddda", - surfaceVariantText: "#534341", - surfaceTint: "#8c1d18", - background: "#fff8f7", - backgroundText: "#231918", - outline: "#857371", - surfaceContainer: "#fceae7", - surfaceContainerHigh: "#f6e4e2", - surfaceContainerHighest: "#f1dedc", - }, - raveos: { - name: "RaveOS Light", - primary: "#3d7839", - primaryText: "#ffffff", - primaryContainer: "#c1e9bb", - secondary: "#3d7839", - surface: "#f7fbf1", - surfaceText: "#191d17", - surfaceVariant: "#dee5d8", - surfaceVariantText: "#424940", - surfaceTint: "#3d7839", - background: "#f7fbf1", - backgroundText: "#191d17", - outline: "#72796f", - surfaceContainer: "#ecefe6", - surfaceContainerHigh: "#e6e9e0", - surfaceContainerHighest: "#e0e4db", - }, - monochrome: { - name: "Monochrome Light", - primary: "#2b303c", - primaryText: "#ffffff", - primaryContainer: "#d6d7dc", - secondary: "#4a4d56", - surface: "#f5f5f6", - surfaceText: "#2a2a2a", - surfaceVariant: "#e0e0e2", - surfaceVariantText: "#424242", - surfaceTint: "#5a5f6e", - background: "#ffffff", - backgroundText: "#1a1a1a", - outline: "#757577", - surfaceContainer: "#e8e8ea", - surfaceContainerHigh: "#dcdcde", - surfaceContainerHighest: "#d0d0d2", - error: "#ba1a1a", - warning: "#f9e79f", - info: "#5d6475", - matugen_type: "scheme-monochrome", - }, - }, -}; - -const ThemeCategories = { - GENERIC: { - name: "Generic", - variants: [ - "raveos", - "blue", - "purple", - "green", - "orange", - "red", - "cyan", - "pink", - "amber", - "coral", - "monochrome", - ], - }, -}; - -const ThemeNames = { - RAVEOS: "raveos", - BLUE: "blue", - PURPLE: "purple", - GREEN: "green", - ORANGE: "orange", - RED: "red", - CYAN: "cyan", - PINK: "pink", - AMBER: "amber", - CORAL: "coral", - MONOCHROME: "monochrome", - DYNAMIC: "dynamic", -}; - -function isStockTheme(themeName) { - return Object.keys(StockThemes.DARK).includes(themeName); -} - -function getAvailableThemes(isLight = false) { - return isLight ? StockThemes.LIGHT : StockThemes.DARK; -} - -function getThemeByName(themeName, isLight = false) { - const themes = getAvailableThemes(isLight); - return themes[themeName] || themes.blue; -} - -function getAllThemeNames() { - return Object.keys(StockThemes.DARK); -} - -function getThemeCategories() { - return ThemeCategories; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Theme.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Theme.qml deleted file mode 100644 index a50b688..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/Theme.qml +++ /dev/null @@ -1,2410 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Modules.Greetd -import "StockThemes.js" as StockThemes - -Singleton { - id: root - - readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell" - readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true" - readonly property string defaultFontFamily: "Inter Variable" - readonly property string defaultMonoFontFamily: "Fira Code" - - readonly property real popupDistance: { - if (typeof SettingsData === "undefined") - return 4; - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return 4; - const useAuto = defaultBar.popupGapsAuto ?? true; - const manualValue = defaultBar.popupGapsManual ?? 4; - const spacing = defaultBar.spacing ?? 4; - return useAuto ? Math.max(4, spacing) : manualValue; - } - - property string currentTheme: "raveos" - property string currentThemeCategory: "generic" - property bool isLightMode: typeof SessionData !== "undefined" ? SessionData.isLightMode : false - property bool colorsFileLoadFailed: false - - readonly property string dynamic: "dynamic" - readonly property string custom: "custom" - - readonly property string homeDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation)) - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) - readonly property string shellDir: Paths.strip(Qt.resolvedUrl(".").toString()).replace("/Common/", "") - readonly property string wallpaperPath: { - if (typeof SessionData === "undefined") - return ""; - - var monitors = SessionData.monitorWallpapers; - if (SessionData.perMonitorWallpaper) { - var screens = Quickshell.screens; - if (screens.length > 0) { - var s = screens[0]; - return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath; - } - } - - return SessionData.wallpaperPath; - } - readonly property string rawWallpaperPath: { - if (typeof SessionData === "undefined") - return ""; - - var monitors = SessionData.monitorWallpapers; - if (SessionData.perMonitorWallpaper) { - var screens = Quickshell.screens; - if (screens.length > 0) { - var targetMonitor = (typeof SettingsData !== "undefined" && SettingsData.matugenTargetMonitor && SettingsData.matugenTargetMonitor !== "") ? SettingsData.matugenTargetMonitor : screens[0].name; - - var targetMonitorExists = false; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === targetMonitor) { - targetMonitorExists = true; - break; - } - } - - if (!targetMonitorExists) - targetMonitor = screens[0].name; - - var s = null; - for (var j = 0; j < screens.length; j++) { - if (screens[j].name === targetMonitor) { - s = screens[j]; - break; - } - } - - if (s) - return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath; - return monitors[targetMonitor] || SessionData.wallpaperPath; - } - } - - return SessionData.wallpaperPath; - } - - property bool matugenAvailable: false - property bool gtkThemingEnabled: typeof SettingsData !== "undefined" ? SettingsData.gtkAvailable : false - property bool qtThemingEnabled: typeof SettingsData !== "undefined" ? (SettingsData.qt5ctAvailable || SettingsData.qt6ctAvailable) : false - property var workerRunning: false - property var pendingThemeRequest: null - - signal matugenCompleted(string mode, string result) - property var matugenColors: ({}) - property var _pendingGenerateParams: null - - property bool themeModeAutomationActive: false - property bool dmsServiceWasDisconnected: true - - readonly property var dank16: { - const raw = matugenColors?.dank16; - if (!raw) - return null; - - const dark = {}; - const light = {}; - const def = {}; - - for (let i = 0; i < 16; i++) { - const key = "color" + i; - const c = raw[key]; - if (!c) - continue; - dark[key] = c.dark; - light[key] = c.light; - def[key] = c.default; - } - - return { - dark, - light, - "default": def - }; - } - property var customThemeData: null - property var customThemeRawData: null - readonly property var currentThemeVariants: customThemeRawData?.variants || null - readonly property string currentThemeId: customThemeRawData?.id || "" - - Component.onCompleted: { - Quickshell.execDetached(["mkdir", "-p", stateDir]); - Proc.runCommand("matugenCheck", ["which", "matugen"], (output, code) => { - matugenAvailable = (code === 0) && !envDisableMatugen; - const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); - - if (!matugenAvailable || isGreeterMode) { - return; - } - - if (colorsFileLoadFailed && currentTheme === dynamic && rawWallpaperPath) { - console.info("Theme: Matugen now available, regenerating colors for dynamic theme"); - const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode); - const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"; - const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"; - if (rawWallpaperPath.startsWith("#")) { - setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType); - } else { - setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType); - } - return; - } - - const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode); - const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"; - - if (currentTheme === dynamic) { - if (rawWallpaperPath) { - const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"; - if (rawWallpaperPath.startsWith("#")) { - setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType); - } else { - setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType); - } - } - } else if (currentTheme !== "custom") { - const darkTheme = StockThemes.getThemeByName(currentTheme, false); - const lightTheme = StockThemes.getThemeByName(currentTheme, true); - if (darkTheme && darkTheme.primary) { - const stockColors = buildMatugenColorsFromTheme(darkTheme, lightTheme); - const themeData = isLight ? lightTheme : darkTheme; - setDesiredTheme("hex", themeData.primary, isLight, iconTheme, themeData.matugen_type, stockColors); - } - } - }, 0); - if (typeof SessionData !== "undefined") { - SessionData.isLightModeChanged.connect(root.onLightModeChanged); - } - - if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) { - switchTheme(SettingsData.currentThemeName, false, false); - const currentIsLight = (typeof SessionData !== "undefined") ? SessionData.isLightMode : false; - SettingsData.updateCosmicThemeMode(currentIsLight); - } - - if (typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled) { - startThemeModeAutomation(); - } - } - - Connections { - target: SessionData - enabled: typeof SessionData !== "undefined" - - function onThemeModeAutoEnabledChanged() { - if (SessionData.themeModeAutoEnabled) { - root.startThemeModeAutomation(); - } else { - root.stopThemeModeAutomation(); - } - } - - function onThemeModeAutoModeChanged() { - if (root.themeModeAutomationActive) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - root.syncLocationThemeSchedule(); - } - } - - function onThemeModeStartHourChanged() { - if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onThemeModeStartMinuteChanged() { - if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onThemeModeEndHourChanged() { - if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onThemeModeEndMinuteChanged() { - if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onThemeModeShareGammaSettingsChanged() { - if (root.themeModeAutomationActive) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - root.syncLocationThemeSchedule(); - } - } - - function onNightModeStartHourChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onNightModeStartMinuteChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onNightModeEndHourChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onNightModeEndMinuteChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) { - root.evaluateThemeMode(); - root.syncTimeThemeSchedule(); - } - } - - function onLatitudeChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") { - if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0 && typeof DMSService !== "undefined") { - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }); - } - root.evaluateThemeMode(); - root.syncLocationThemeSchedule(); - } - } - - function onLongitudeChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") { - if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0 && typeof DMSService !== "undefined") { - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }); - } - root.evaluateThemeMode(); - root.syncLocationThemeSchedule(); - } - } - - function onNightModeUseIPLocationChanged() { - if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") { - if (typeof DMSService !== "undefined") { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": SessionData.nightModeUseIPLocation - }, response => { - if (!response.error && !SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }); - } - }); - } - root.evaluateThemeMode(); - root.syncLocationThemeSchedule(); - } - } - } - - // React to gamma backend's isDay state changes for location-based mode - Connections { - target: DisplayService - enabled: typeof DisplayService !== "undefined" && typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "location" && !themeAutoBackendAvailable() - - function onGammaIsDayChanged() { - if (root.isLightMode !== DisplayService.gammaIsDay) { - root.setLightMode(DisplayService.gammaIsDay, true, true); - } - } - } - - Connections { - target: DMSService - enabled: typeof DMSService !== "undefined" && typeof SessionData !== "undefined" - - function onLoginctlEvent(event) { - if (!SessionData.themeModeAutoEnabled) - return; - if (event.event === "unlock" || event.event === "resume") { - if (!themeAutoBackendAvailable()) { - root.evaluateThemeMode(); - return; - } - DMSService.sendRequest("theme.auto.trigger", {}); - } - } - - function onThemeAutoStateUpdate(data) { - if (!SessionData.themeModeAutoEnabled) { - return; - } - applyThemeAutoState(data); - } - - function onConnectionStateChanged() { - if (DMSService.isConnected && SessionData.themeModeAutoMode === "time") { - root.syncTimeThemeSchedule(); - } - - if (DMSService.isConnected && SessionData.themeModeAutoMode === "location") { - root.syncLocationThemeSchedule(); - } - - if (themeAutoBackendAvailable() && SessionData.themeModeAutoEnabled) { - DMSService.sendRequest("theme.auto.getState", null, response => { - if (response && response.result) { - applyThemeAutoState(response.result); - } - }); - } - - if (!SessionData.themeModeAutoEnabled) { - return; - } - - if (DMSService.isConnected && SessionData.themeModeAutoMode === "location") { - if (SessionData.nightModeUseIPLocation) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": true - }, response => { - if (!response.error) { - console.info("Theme automation: IP location enabled after connection"); - } - }); - } else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": false - }, response => { - if (!response.error) { - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }, locationResponse => { - if (locationResponse?.error) { - console.warn("Theme automation: Failed to set location", locationResponse.error); - } - }); - } - }); - } else { - console.warn("Theme automation: No location configured"); - } - } - } - } - - function applyGreeterTheme(themeName) { - switchTheme(themeName, false, false); - if (themeName === dynamic && dynamicColorsFileView.path) { - dynamicColorsFileView.reload(); - } - } - - function getMatugenColor(path, fallback) { - const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"; - let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode]; - for (const part of path.split(".")) { - if (!cur || typeof cur !== "object" || !(part in cur)) - return fallback; - cur = cur[part]; - } - return cur || fallback; - } - - readonly property var currentThemeData: { - if (currentTheme === "custom") { - return customThemeData || StockThemes.getThemeByName("purple", isLightMode); - } else if (currentTheme === dynamic) { - return { - "primary": getMatugenColor("primary", "#42a5f5"), - "primaryText": getMatugenColor("on_primary", "#ffffff"), - "primaryContainer": getMatugenColor("primary_container", "#1976d2"), - "secondary": getMatugenColor("secondary", "#8ab4f8"), - "surface": getMatugenColor("surface", "#1a1c1e"), - "surfaceText": getMatugenColor("on_background", "#e3e8ef"), - "surfaceVariant": getMatugenColor("surface_variant", "#44464f"), - "surfaceVariantText": getMatugenColor("on_surface_variant", "#c4c7c5"), - "surfaceTint": getMatugenColor("surface_tint", "#8ab4f8"), - "background": getMatugenColor("background", "#1a1c1e"), - "backgroundText": getMatugenColor("on_background", "#e3e8ef"), - "outline": getMatugenColor("outline", "#8e918f"), - "surfaceContainer": getMatugenColor("surface_container", "#1e2023"), - "surfaceContainerHigh": getMatugenColor("surface_container_high", "#292b2f"), - "surfaceContainerHighest": getMatugenColor("surface_container_highest", "#343740"), - "error": "#F2B8B5", - "warning": "#FF9800", - "info": "#2196F3", - "success": "#4CAF50" - }; - } else { - return StockThemes.getThemeByName(currentTheme, isLightMode); - } - } - - readonly property var availableMatugenSchemes: [({ - "value": "scheme-tonal-spot", - "label": I18n.tr("Tonal Spot", "matugen color scheme option"), - "description": I18n.tr("Balanced palette with focused accents (default).") - }), ({ - "value": "scheme-vibrant", - "label": I18n.tr("Vibrant", "matugen color scheme option"), - "description": I18n.tr("Lively palette with saturated accents.") - }), ({ - "value": "scheme-content", - "label": I18n.tr("Content", "matugen color scheme option"), - "description": I18n.tr("Derives colors that closely match the underlying image.") - }), ({ - "value": "scheme-expressive", - "label": I18n.tr("Expressive", "matugen color scheme option"), - "description": I18n.tr("Vibrant palette with playful saturation.") - }), ({ - "value": "scheme-fidelity", - "label": I18n.tr("Fidelity", "matugen color scheme option"), - "description": I18n.tr("High-fidelity palette that preserves source hues.") - }), ({ - "value": "scheme-fruit-salad", - "label": I18n.tr("Fruit Salad", "matugen color scheme option"), - "description": I18n.tr("Colorful mix of bright contrasting accents.") - }), ({ - "value": "scheme-monochrome", - "label": I18n.tr("Monochrome", "matugen color scheme option"), - "description": I18n.tr("Minimal palette built around a single hue.") - }), ({ - "value": "scheme-neutral", - "label": I18n.tr("Neutral", "matugen color scheme option"), - "description": I18n.tr("Muted palette with subdued, calming tones.") - }), ({ - "value": "scheme-rainbow", - "label": I18n.tr("Rainbow", "matugen color scheme option"), - "description": I18n.tr("Diverse palette spanning the full spectrum.") - })] - - function getMatugenScheme(value) { - const schemes = availableMatugenSchemes; - for (var i = 0; i < schemes.length; i++) { - if (schemes[i].value === value) - return schemes[i]; - } - return schemes[0]; - } - - property color primary: currentThemeData.primary - property color primaryText: currentThemeData.primaryText - property color primaryContainer: currentThemeData.primaryContainer - property color secondary: currentThemeData.secondary - property color surface: currentThemeData.surface - property color surfaceText: currentThemeData.surfaceText - property color surfaceVariant: currentThemeData.surfaceVariant - property color surfaceVariantText: currentThemeData.surfaceVariantText - property color surfaceTint: currentThemeData.surfaceTint - property color background: currentThemeData.background - property color backgroundText: currentThemeData.backgroundText - property color outline: currentThemeData.outline - property color outlineVariant: currentThemeData.outlineVariant || Qt.rgba(outline.r, outline.g, outline.b, 0.6) - property color surfaceContainer: currentThemeData.surfaceContainer - property color surfaceContainerHigh: currentThemeData.surfaceContainerHigh - property color surfaceContainerHighest: currentThemeData.surfaceContainerHighest || surfaceContainerHigh - - property color onSurface: surfaceText - property color onSurfaceVariant: surfaceVariantText - property color onPrimary: primaryText - property color onSurface_12: Qt.rgba(onSurface.r, onSurface.g, onSurface.b, 0.12) - property color onSurface_38: Qt.rgba(onSurface.r, onSurface.g, onSurface.b, 0.38) - property color onSurfaceVariant_30: Qt.rgba(onSurfaceVariant.r, onSurfaceVariant.g, onSurfaceVariant.b, 0.30) - - property color error: currentThemeData.error || "#F2B8B5" - property color warning: currentThemeData.warning || "#FF9800" - property color info: currentThemeData.info || "#2196F3" - property color tempWarning: "#ff9933" - property color tempDanger: "#ff5555" - property color success: currentThemeData.success || "#4CAF50" - - property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12) - property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08) - property color primaryPressed: Qt.rgba(primary.r, primary.g, primary.b, 0.16) - property color primarySelected: Qt.rgba(primary.r, primary.g, primary.b, 0.3) - property color primaryBackground: Qt.rgba(primary.r, primary.g, primary.b, 0.04) - - property color secondaryHover: Qt.rgba(secondary.r, secondary.g, secondary.b, 0.08) - - property color surfaceHover: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.08) - property color surfacePressed: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.12) - property color surfaceSelected: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.15) - property color surfaceLight: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.1) - property color surfaceVariantAlpha: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.2) - property color surfaceTextHover: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.08) - property color surfaceTextAlpha: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.3) - property color surfaceTextLight: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.06) - property color surfaceTextMedium: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.7) - - property color outlineButton: Qt.rgba(outline.r, outline.g, outline.b, 0.5) - property color outlineLight: Qt.rgba(outline.r, outline.g, outline.b, 0.05) - property color outlineMedium: Qt.rgba(outline.r, outline.g, outline.b, 0.08) - property color outlineStrong: Qt.rgba(outline.r, outline.g, outline.b, 0.12) - - property color errorHover: Qt.rgba(error.r, error.g, error.b, 0.12) - property color errorPressed: Qt.rgba(error.r, error.g, error.b, 0.16) - - readonly property color ccTileActiveBg: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return primaryContainer; - case "secondary": - return secondary; - case "surfaceVariant": - return surfaceVariant; - default: - return primary; - } - } - - readonly property color ccTileActiveText: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return primary; - case "secondary": - return surfaceText; - case "surfaceVariant": - return surfaceText; - default: - return primaryText; - } - } - - readonly property color ccTileInactiveIcon: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return primary; - case "secondary": - return secondary; - case "surfaceVariant": - return surfaceText; - default: - return primary; - } - } - - readonly property color ccTileRing: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return Qt.rgba(primary.r, primary.g, primary.b, 0.22); - case "secondary": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.22); - case "surfaceVariant": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.22); - default: - return Qt.rgba(primaryText.r, primaryText.g, primaryText.b, 0.22); - } - } - - readonly property color buttonBg: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return primaryContainer; - case "secondary": - return secondary; - case "surfaceVariant": - return surfaceVariant; - default: - return primary; - } - } - - readonly property color buttonText: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return primary; - case "secondary": - return surfaceText; - case "surfaceVariant": - return surfaceText; - default: - return primaryText; - } - } - - readonly property color buttonHover: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return Qt.rgba(primary.r, primary.g, primary.b, 0.12); - case "secondary": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.12); - case "surfaceVariant": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.12); - default: - return primaryHover; - } - } - - readonly property color buttonPressed: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return Qt.rgba(primary.r, primary.g, primary.b, 0.16); - case "secondary": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.16); - case "surfaceVariant": - return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.16); - default: - return primaryPressed; - } - } - - property color shadowMedium: Qt.rgba(0, 0, 0, 0.08) - property color shadowStrong: Qt.rgba(0, 0, 0, 0.3) - - readonly property bool elevationEnabled: typeof SettingsData !== "undefined" && (SettingsData.m3ElevationEnabled ?? true) - readonly property real elevationBlurMax: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? Math.min(128, Math.max(32, SettingsData.m3ElevationIntensity * 2)) : 64 - - readonly property real _elevMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? SettingsData.m3ElevationIntensity / 12 : 1 - readonly property real _opMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationOpacity !== undefined ? SettingsData.m3ElevationOpacity / 60 : 1 - function normalizeElevationDirection(direction) { - switch (direction) { - case "top": - case "topLeft": - case "topRight": - case "bottom": - case "bottomLeft": - case "bottomRight": - case "left": - case "right": - case "autoBar": - return direction; - default: - return "top"; - } - } - - readonly property string elevationLightDirection: { - if (typeof SettingsData === "undefined" || !SettingsData.m3ElevationLightDirection) - return "top"; - switch (SettingsData.m3ElevationLightDirection) { - case "autoBar": - case "top": - case "topLeft": - case "topRight": - case "bottom": - return SettingsData.m3ElevationLightDirection; - default: - return "top"; - } - } - readonly property real _elevDiagRatio: 0.55 - readonly property string _globalElevationDirForTokens: { - const normalized = normalizeElevationDirection(elevationLightDirection); - return normalized === "autoBar" ? "top" : normalized; - } - readonly property real _elevDirX: { - switch (_globalElevationDirForTokens) { - case "topLeft": - case "bottomLeft": - case "left": - return 1; - case "topRight": - case "bottomRight": - case "right": - return -1; - default: - return 0; - } - } - readonly property real _elevDirY: { - switch (_globalElevationDirForTokens) { - case "bottom": - case "bottomLeft": - case "bottomRight": - return -1; - case "left": - case "right": - return 0; - default: - return 1; - } - } - readonly property real _elevDirXScale: (_globalElevationDirForTokens === "left" || _globalElevationDirForTokens === "right") ? 1 : _elevDiagRatio - - readonly property var elevationLevel1: ({ - blurPx: 4 * _elevMult, - offsetX: 1 * _elevMult * _elevDirXScale * _elevDirX, - offsetY: 1 * _elevMult * _elevDirY, - spreadPx: 0, - alpha: 0.2 * _opMult - }) - readonly property var elevationLevel2: ({ - blurPx: 8 * _elevMult, - offsetX: 4 * _elevMult * _elevDirXScale * _elevDirX, - offsetY: 4 * _elevMult * _elevDirY, - spreadPx: 0, - alpha: 0.25 * _opMult - }) - readonly property var elevationLevel3: ({ - blurPx: 12 * _elevMult, - offsetX: 6 * _elevMult * _elevDirXScale * _elevDirX, - offsetY: 6 * _elevMult * _elevDirY, - spreadPx: 0, - alpha: 0.3 * _opMult - }) - readonly property var elevationLevel4: ({ - blurPx: 16 * _elevMult, - offsetX: 8 * _elevMult * _elevDirXScale * _elevDirX, - offsetY: 8 * _elevMult * _elevDirY, - spreadPx: 0, - alpha: 0.3 * _opMult - }) - readonly property var elevationLevel5: ({ - blurPx: 20 * _elevMult, - offsetX: 10 * _elevMult * _elevDirXScale * _elevDirX, - offsetY: 10 * _elevMult * _elevDirY, - spreadPx: 0, - alpha: 0.3 * _opMult - }) - - function elevationOffsetMagnitude(level, fallback, direction) { - if (!level) { - return fallback !== undefined ? Math.abs(fallback) : 0; - } - const yMag = Math.abs(level.offsetY !== undefined ? level.offsetY : 0); - if (yMag > 0) - return yMag; - const xMag = Math.abs(level.offsetX !== undefined ? level.offsetX : 0); - if (xMag > 0) { - if (direction === "left" || direction === "right") - return xMag; - return xMag / _elevDiagRatio; - } - return fallback !== undefined ? Math.abs(fallback) : 0; - } - - function elevationOffsetXFor(level, direction, fallback) { - const dir = normalizeElevationDirection(direction || elevationLightDirection); - const mag = elevationOffsetMagnitude(level, fallback, dir); - switch (dir) { - case "topLeft": - case "bottomLeft": - return mag * _elevDiagRatio; - case "topRight": - case "bottomRight": - return -mag * _elevDiagRatio; - case "left": - return mag; - case "right": - return -mag; - default: - return 0; - } - } - - function elevationOffsetYFor(level, direction, fallback) { - const dir = normalizeElevationDirection(direction || elevationLightDirection); - const mag = elevationOffsetMagnitude(level, fallback, dir); - switch (dir) { - case "bottom": - case "bottomLeft": - case "bottomRight": - return -mag; - case "left": - case "right": - return 0; - default: - return mag; - } - } - - function elevationOffsetX(level, fallback) { - return elevationOffsetXFor(level, elevationLightDirection, fallback); - } - - function elevationOffsetY(level, fallback) { - return elevationOffsetYFor(level, elevationLightDirection, fallback); - } - - function elevationRenderPadding(level, direction, fallbackOffset, extraPadding, minPadding) { - const dir = direction !== undefined ? direction : elevationLightDirection; - const blur = (level && level.blurPx !== undefined) ? Math.max(0, level.blurPx) : 0; - const spread = (level && level.spreadPx !== undefined) ? Math.max(0, level.spreadPx) : 0; - const fallback = fallbackOffset !== undefined ? fallbackOffset : 0; - const extra = extraPadding !== undefined ? extraPadding : 8; - const minPad = minPadding !== undefined ? minPadding : 16; - const offsetX = Math.abs(elevationOffsetXFor(level, dir, fallback)); - const offsetY = Math.abs(elevationOffsetYFor(level, dir, fallback)); - return Math.max(minPad, blur + spread + Math.max(offsetX, offsetY) + extra); - } - - function elevationShadowColor(level) { - const alpha = (level && level.alpha !== undefined) ? level.alpha : 0.3; - let r = 0; - let g = 0; - let b = 0; - - if (typeof SettingsData !== "undefined") { - const mode = SettingsData.m3ElevationColorMode || "default"; - if (mode === "default") { - r = 0; - g = 0; - b = 0; - } else if (mode === "text") { - r = surfaceText.r; - g = surfaceText.g; - b = surfaceText.b; - } else if (mode === "primary") { - r = primary.r; - g = primary.g; - b = primary.b; - } else if (mode === "surfaceVariant") { - r = surfaceVariant.r; - g = surfaceVariant.g; - b = surfaceVariant.b; - } else if (mode === "custom" && SettingsData.m3ElevationCustomColor) { - const c = Qt.color(SettingsData.m3ElevationCustomColor); - r = c.r; - g = c.g; - b = c.b; - } - } - return Qt.rgba(r, g, b, alpha); - } - function elevationTintOpacity(level) { - if (!level) - return 0; - if (level === elevationLevel1) - return 0.05; - if (level === elevationLevel2) - return 0.08; - if (level === elevationLevel3) - return 0.11; - if (level === elevationLevel4) - return 0.12; - if (level === elevationLevel5) - return 0.14; - return 0.08; - } - - readonly property var animationDurations: [ - { - "shorter": 0, - "short": 0, - "medium": 0, - "long": 0, - "extraLong": 0 - }, - { - "shorter": 50, - "short": 75, - "medium": 150, - "long": 250, - "extraLong": 500 - }, - { - "shorter": 100, - "short": 150, - "medium": 300, - "long": 500, - "extraLong": 1000 - }, - { - "shorter": 150, - "short": 225, - "medium": 450, - "long": 750, - "extraLong": 1500 - }, - { - "shorter": 200, - "short": 300, - "medium": 600, - "long": 1000, - "extraLong": 2000 - } - ] - - readonly property int currentAnimationSpeed: typeof SettingsData !== "undefined" ? SettingsData.animationSpeed : SettingsData.AnimationSpeed.Short - readonly property var currentDurations: animationDurations[currentAnimationSpeed] || animationDurations[SettingsData.AnimationSpeed.Short] - - readonly property int shorterDuration: (typeof SettingsData !== "undefined" && SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) ? SettingsData.customAnimationDuration : currentDurations.shorter - readonly property int shortDuration: (typeof SettingsData !== "undefined" && SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) ? SettingsData.customAnimationDuration : currentDurations.short - readonly property int mediumDuration: (typeof SettingsData !== "undefined" && SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) ? SettingsData.customAnimationDuration : currentDurations.medium - readonly property int longDuration: (typeof SettingsData !== "undefined" && SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) ? SettingsData.customAnimationDuration : currentDurations.long - readonly property int extraLongDuration: (typeof SettingsData !== "undefined" && SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) ? SettingsData.customAnimationDuration : currentDurations.extraLong - readonly property int standardEasing: Easing.OutCubic - readonly property int emphasizedEasing: Easing.OutQuart - - readonly property var expressiveCurves: { - "emphasized": [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1], - "emphasizedAccel": [0.3, 0, 0.8, 0.15, 1, 1], - "emphasizedDecel": [0.05, 0.7, 0.1, 1, 1, 1], - "standard": [0.2, 0, 0, 1, 1, 1], - "standardAccel": [0.3, 0, 1, 1, 1, 1], - "standardDecel": [0, 0, 0, 1, 1, 1], - "expressiveFastSpatial": [0.42, 1.67, 0.21, 0.9, 1, 1], - "expressiveDefaultSpatial": [0.38, 1.21, 0.22, 1, 1, 1], - "expressiveEffects": [0.34, 0.8, 0.34, 1, 1, 1] - } - - readonly property var animationPresetDurations: { - "none": 0, - "short": 250, - "medium": 500, - "long": 750 - } - - readonly property int currentAnimationBaseDuration: { - if (typeof SettingsData === "undefined") - return 500; - - if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) { - return SettingsData.customAnimationDuration; - } - - const presetMap = [0, 250, 500, 750]; - return presetMap[SettingsData.animationSpeed] !== undefined ? presetMap[SettingsData.animationSpeed] : 500; - } - - readonly property var expressiveDurations: { - if (typeof SettingsData === "undefined") { - return { - "fast": 200, - "normal": 400, - "large": 600, - "extraLarge": 1000, - "expressiveFastSpatial": 350, - "expressiveDefaultSpatial": 500, - "expressiveEffects": 200 - }; - } - - const baseDuration = currentAnimationBaseDuration; - return { - "fast": baseDuration * 0.4, - "normal": baseDuration * 0.8, - "large": baseDuration * 1.2, - "extraLarge": baseDuration * 2.0, - "expressiveFastSpatial": baseDuration * 0.7, - "expressiveDefaultSpatial": baseDuration, - "expressiveEffects": baseDuration * 0.4 - }; - } - - readonly property int notificationAnimationBaseDuration: { - if (typeof SettingsData === "undefined") - return 200; - if (SettingsData.notificationAnimationSpeed === SettingsData.AnimationSpeed.None) - return 0; - if (SettingsData.notificationAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return SettingsData.notificationCustomAnimationDuration; - const presetMap = [0, 200, 400, 600]; - return presetMap[SettingsData.notificationAnimationSpeed] ?? 200; - } - - readonly property int notificationEnterDuration: { - const base = notificationAnimationBaseDuration; - return base === 0 ? 0 : Math.round(base * 0.875); - } - - readonly property int notificationExitDuration: { - const base = notificationAnimationBaseDuration; - return base === 0 ? 0 : Math.round(base * 0.75); - } - - readonly property int notificationExpandDuration: { - const base = notificationAnimationBaseDuration; - return base === 0 ? 0 : Math.round(base * 1.0); - } - - readonly property int notificationCollapseDuration: { - const base = notificationAnimationBaseDuration; - return base === 0 ? 0 : Math.round(base * 0.85); - } - - readonly property real notificationIconSizeNormal: 56 - readonly property real notificationIconSizeCompact: 48 - readonly property real notificationExpandedIconSizeNormal: 48 - readonly property real notificationExpandedIconSizeCompact: 40 - readonly property real notificationActionMinWidth: 48 - readonly property real notificationButtonCornerRadius: cornerRadius / 2 - readonly property real notificationHoverRevealMargin: spacingXL - readonly property real notificationContentSpacing: spacingXS - readonly property real notificationCardPadding: spacingM - readonly property real notificationCardPaddingCompact: spacingS - - readonly property real stateLayerHover: 0.08 - readonly property real stateLayerFocus: 0.12 - readonly property real stateLayerPressed: 0.12 - readonly property real stateLayerDrag: 0.16 - - readonly property int popoutAnimationDuration: { - if (typeof SettingsData === "undefined") - return 150; - if (SettingsData.syncComponentAnimationSpeeds) { - return Math.min(currentAnimationBaseDuration, 1000); - } - const presetMap = [0, 150, 300, 500]; - if (SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return SettingsData.popoutCustomAnimationDuration; - return presetMap[SettingsData.popoutAnimationSpeed] ?? 150; - } - - readonly property int modalAnimationDuration: { - if (typeof SettingsData === "undefined") - return 150; - if (SettingsData.syncComponentAnimationSpeeds) { - return Math.min(currentAnimationBaseDuration, 1000); - } - const presetMap = [0, 150, 300, 500]; - if (SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return SettingsData.modalCustomAnimationDuration; - return presetMap[SettingsData.modalAnimationSpeed] ?? 150; - } - - property real cornerRadius: { - if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") { - return GreetdSettings.cornerRadius; - } - return typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; - } - - property string fontFamily: { - if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") { - return GreetdSettings.getEffectiveFontFamily(); - } - return typeof SettingsData !== "undefined" ? SettingsData.fontFamily : "Inter Variable"; - } - - property string monoFontFamily: { - if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") { - return GreetdSettings.monoFontFamily; - } - return typeof SettingsData !== "undefined" ? SettingsData.monoFontFamily : "Fira Code"; - } - - property int fontWeight: { - if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") { - return GreetdSettings.fontWeight; - } - return typeof SettingsData !== "undefined" ? SettingsData.fontWeight : Font.Normal; - } - - property real fontScale: { - if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") { - return GreetdSettings.fontScale; - } - return typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0; - } - - property real spacingXS: 4 - property real spacingS: 8 - property real spacingM: 12 - property real spacingL: 16 - property real spacingXL: 24 - property real fontSizeSmall: Math.round(fontScale * 12) - property real fontSizeMedium: Math.round(fontScale * 14) - property real fontSizeLarge: Math.round(fontScale * 16) - property real fontSizeXLarge: Math.round(fontScale * 20) - property real barHeight: 48 - property real iconSize: 24 - property real iconSizeSmall: 16 - property real iconSizeLarge: 32 - - property real panelTransparency: 0.85 - property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0 - - function screenTransition() { - if (CompositorService.isNiri) { - NiriService.doScreenTransition(); - } - } - - function switchTheme(themeName, savePrefs = true, enableTransition = true) { - if (enableTransition) { - screenTransition(); - themeTransitionTimer.themeName = themeName; - themeTransitionTimer.savePrefs = savePrefs; - themeTransitionTimer.restart(); - return; - } - - if (themeName === dynamic) { - currentTheme = dynamic; - if (currentThemeCategory !== "registry") - currentThemeCategory = dynamic; - } else if (themeName === custom) { - currentTheme = custom; - if (currentThemeCategory !== "registry") - currentThemeCategory = custom; - if (typeof SettingsData !== "undefined" && SettingsData.customThemeFile) { - loadCustomThemeFromFile(SettingsData.customThemeFile); - } - } else if (themeName === "" && currentThemeCategory === "registry") { - // Registry category selected but no theme chosen yet - } else { - currentTheme = themeName; - if (currentThemeCategory !== "registry") { - currentThemeCategory = "generic"; - } - } - const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); - if (savePrefs && typeof SettingsData !== "undefined" && !isGreeterMode) { - SettingsData.set("currentThemeCategory", currentThemeCategory); - SettingsData.set("currentThemeName", currentTheme); - } - - if (!isGreeterMode) { - generateSystemThemesFromCurrentTheme(); - } - } - - function setLightMode(light, savePrefs = true, enableTransition = false) { - if (enableTransition) { - screenTransition(); - lightModeTransitionTimer.lightMode = light; - lightModeTransitionTimer.savePrefs = savePrefs; - lightModeTransitionTimer.restart(); - return; - } - - const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); - if (savePrefs && typeof SessionData !== "undefined" && !isGreeterMode) { - SessionData.setLightMode(light); - } - - if (!isGreeterMode) { - if (!matugenAvailable) { - PortalService.setLightMode(light); - } - if (typeof SettingsData !== "undefined") { - SettingsData.updateCosmicThemeMode(light); - } - generateSystemThemesFromCurrentTheme(); - } - } - - function toggleLightMode(savePrefs = true) { - setLightMode(!isLightMode, savePrefs, true); - } - - function forceGenerateSystemThemes() { - if (!matugenAvailable) { - return; - } - generateSystemThemesFromCurrentTheme(); - } - - function getAvailableThemes() { - return StockThemes.getAllThemeNames(); - } - - function getThemeDisplayName(themeName) { - const themeData = StockThemes.getThemeByName(themeName, isLightMode); - return themeData.name; - } - - function getThemeColors(themeName) { - if (themeName === "custom" && customThemeData) { - return customThemeData; - } - return StockThemes.getThemeByName(themeName, isLightMode); - } - - function switchThemeCategory(category, defaultTheme) { - screenTransition(); - themeCategoryTransitionTimer.category = category; - themeCategoryTransitionTimer.defaultTheme = defaultTheme; - themeCategoryTransitionTimer.restart(); - } - - function loadCustomTheme(themeData) { - customThemeRawData = themeData; - const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"; - - var baseColors = {}; - if (themeData.dark || themeData.light) { - baseColors = themeData[colorMode] || themeData.dark || themeData.light || {}; - } else { - baseColors = themeData; - } - - if (themeData.variants) { - const themeId = themeData.id || ""; - - if (themeData.variants.type === "multi" && themeData.variants.flavors && themeData.variants.accents) { - const defaults = themeData.variants.defaults || {}; - const modeDefaults = defaults[colorMode] || defaults.dark || {}; - const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode; - const stored = isGreeterMode ? (GreetdSettings.registryThemeVariants[themeId]?.[colorMode] || modeDefaults) : (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, modeDefaults, colorMode) : modeDefaults); - var flavorId = stored.flavor || modeDefaults.flavor || ""; - const accentId = stored.accent || modeDefaults.accent || ""; - var flavor = findVariant(themeData.variants.flavors, flavorId); - if (flavor) { - const hasCurrentModeColors = flavor[colorMode] && (flavor[colorMode].primary || flavor[colorMode].surface); - if (!hasCurrentModeColors) { - flavorId = modeDefaults.flavor || ""; - flavor = findVariant(themeData.variants.flavors, flavorId); - } - } - const accent = findAccent(themeData.variants.accents, accentId); - if (flavor) { - const flavorColors = flavor[colorMode] || flavor.dark || flavor.light || {}; - baseColors = mergeColors(baseColors, flavorColors); - } - if (accent && flavor) { - const accentColors = accent[flavor.id] || {}; - baseColors = mergeColors(baseColors, accentColors); - } - customThemeData = baseColors; - generateSystemThemesFromCurrentTheme(); - return; - } - - if (themeData.variants.options && themeData.variants.options.length > 0) { - const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode; - const selectedVariantId = isGreeterMode ? (typeof GreetdSettings.registryThemeVariants[themeId] === "string" ? GreetdSettings.registryThemeVariants[themeId] : themeData.variants.default) : (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default); - const variant = findVariant(themeData.variants.options, selectedVariantId); - if (variant) { - const variantColors = variant[colorMode] || variant.dark || variant.light || {}; - customThemeData = mergeColors(baseColors, variantColors); - generateSystemThemesFromCurrentTheme(); - return; - } - } - } - - customThemeData = baseColors; - generateSystemThemesFromCurrentTheme(); - } - - function findVariant(options, variantId) { - if (!variantId || !options) - return null; - for (var i = 0; i < options.length; i++) { - if (options[i].id === variantId) - return options[i]; - } - return options[0] || null; - } - - function findAccent(accents, accentId) { - if (!accentId || !accents) - return null; - for (var i = 0; i < accents.length; i++) { - if (accents[i].id === accentId) - return accents[i]; - } - return accents[0] || null; - } - - function mergeColors(base, overlay) { - var result = JSON.parse(JSON.stringify(base)); - for (var key in overlay) { - if (overlay[key]) - result[key] = overlay[key]; - } - return result; - } - - function loadCustomThemeFromFile(filePath) { - customThemeFileView.path = filePath; - } - - function reloadCustomThemeVariant() { - if (currentTheme !== "custom" || !customThemeRawData) - return; - loadCustomTheme(customThemeRawData); - } - - property alias availableThemeNames: root._availableThemeNames - readonly property var _availableThemeNames: StockThemes.getAllThemeNames() - property string currentThemeName: currentTheme - - function panelBackground() { - return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, panelTransparency); - } - - property real notepadTransparency: SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : popupTransparency - - property bool widgetBackgroundHasAlpha: { - const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch"; - return colorMode === "sth"; - } - - property var widgetBaseBackgroundColor: { - const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch"; - switch (colorMode) { - case "s": - return surface; - case "sc": - return surfaceContainer; - case "sch": - return surfaceContainerHigh; - case "sth": - default: - return surfaceTextHover; - } - } - - property color widgetBaseHoverColor: { - const blended = blend(widgetBaseBackgroundColor, primary, 0.1); - return withAlpha(blended, Math.max(0.3, blended.a)); - } - - property color widgetIconColor: { - if (typeof SettingsData === "undefined") { - return surfaceText; - } - - switch (SettingsData.widgetColorMode) { - case "colorful": - return surfaceText; - case "default": - default: - return surfaceText; - } - } - - property color widgetTextColor: { - if (typeof SettingsData === "undefined") { - return surfaceText; - } - - switch (SettingsData.widgetColorMode) { - case "colorful": - return primary; - case "default": - default: - return surfaceText; - } - } - - function isColorDark(c) { - return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b) < 0.5; - } - - function barIconSize(barThickness, offset, maximizeIcon, iconScale) { - const defaultOffset = offset !== undefined ? offset : -6; - const size = (maximizeIcon ?? false) ? iconSizeLarge : iconSize; - const s = iconScale !== undefined ? iconScale : 1.0; - - return Math.round((barThickness / 48) * (size + defaultOffset) * s); - } - - function barTextSize(barThickness, fontScale, maximizeText) { - const scale = barThickness / 48; - const dankBarScale = fontScale !== undefined ? fontScale : 1.0; - const maxScale = (maximizeText ?? false) ? 1.5 : 1.0; - if (scale <= 0.75) - return Math.round(fontSizeSmall * 0.9 * dankBarScale * maxScale); - if (scale >= 1.25) - return Math.round(fontSizeMedium * dankBarScale * maxScale); - return Math.round(fontSizeSmall * dankBarScale * maxScale); - } - - function getBatteryIcon(level, isCharging, batteryAvailable) { - if (!batteryAvailable) - return "battery_std"; - - if (isCharging) { - if (level >= 90) - return "battery_charging_full"; - if (level >= 80) - return "battery_charging_90"; - if (level >= 60) - return "battery_charging_80"; - if (level >= 50) - return "battery_charging_60"; - if (level >= 30) - return "battery_charging_50"; - if (level >= 20) - return "battery_charging_30"; - return "battery_charging_20"; - } else { - if (level >= 95) - return "battery_full"; - if (level >= 85) - return "battery_6_bar"; - if (level >= 70) - return "battery_5_bar"; - if (level >= 55) - return "battery_4_bar"; - if (level >= 40) - return "battery_3_bar"; - if (level >= 25) - return "battery_2_bar"; - if (level >= 10) - return "battery_1_bar"; - return "battery_alert"; - } - } - - function getPowerProfileIcon(profile) { - switch (profile) { - case 0: - return "battery_saver"; - case 1: - return "battery_std"; - case 2: - return "flash_on"; - default: - return "settings"; - } - } - - function getPowerProfileLabel(profile) { - switch (profile) { - case 0: - return I18n.tr("Power Saver", "power profile option"); - case 1: - return I18n.tr("Balanced", "power profile option"); - case 2: - return I18n.tr("Performance", "power profile option"); - default: - return I18n.tr("Unknown", "power profile option"); - } - } - - function getPowerProfileDescription(profile) { - switch (profile) { - case 0: - return I18n.tr("Extend battery life", "power profile description"); - case 1: - return I18n.tr("Balance power and performance", "power profile description"); - case 2: - return I18n.tr("Prioritize performance", "power profile description"); - default: - return I18n.tr("Custom power profile", "power profile description"); - } - } - - function onLightModeChanged() { - if (currentTheme === "custom" && customThemeFileView.path) { - customThemeFileView.reload(); - } - } - - function setDesiredTheme(kind, value, isLight, iconTheme, matugenType, stockColors) { - if (!matugenAvailable) { - console.warn("Theme: matugen not available or disabled - cannot set system theme"); - return; - } - - if (workerRunning) { - console.info("Theme: Worker already running, queueing request"); - pendingThemeRequest = { - kind, - value, - isLight, - iconTheme, - matugenType, - stockColors - }; - return; - } - - console.info("Theme: Setting desired theme -", kind, "mode:", isLight ? "light" : "dark", stockColors ? "(stock colors)" : "(dynamic)"); - - if (typeof NiriService !== "undefined" && CompositorService.isNiri) { - NiriService.suppressNextToast(); - } - - const desired = { - "kind": kind, - "value": value, - "mode": isLight ? "light" : "dark", - "iconTheme": iconTheme || "System Default", - "matugenType": matugenType || "scheme-tonal-spot", - "runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true - }; - - console.log("Theme: Starting matugen worker"); - workerRunning = true; - - const args = ["dms", "matugen", "queue", "--state-dir", stateDir, "--shell-dir", shellDir, "--config-dir", configDir, "--kind", desired.kind, "--value", desired.value, "--mode", desired.mode, "--icon-theme", desired.iconTheme, "--matugen-type", desired.matugenType,]; - - if (!desired.runUserTemplates) { - args.push("--run-user-templates=false"); - } - if (stockColors) { - args.push("--stock-colors", JSON.stringify(stockColors)); - } - if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal) { - args.push("--sync-mode-with-portal"); - } - if (typeof SettingsData !== "undefined" && SettingsData.terminalsAlwaysDark) { - args.push("--terminals-always-dark"); - } - if (typeof SettingsData !== "undefined" && SettingsData.matugenContrast !== 0) { - args.push("--contrast", SettingsData.matugenContrast.toString()); - } - - if (typeof SettingsData !== "undefined") { - const skipTemplates = []; - if (!SettingsData.runDmsMatugenTemplates) { - skipTemplates.push("gtk", "nvim", "niri", "qt5ct", "qt6ct", "firefox", "pywalfox", "zenbrowser", "vesktop", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode", "emacs", "zed"); - } else { - if (!SettingsData.matugenTemplateGtk) - skipTemplates.push("gtk"); - if (!SettingsData.matugenTemplateNiri) - skipTemplates.push("niri"); - if (!SettingsData.matugenTemplateHyprland) - skipTemplates.push("hyprland"); - if (!SettingsData.matugenTemplateMangowc) - skipTemplates.push("mangowc"); - if (!SettingsData.matugenTemplateQt5ct) - skipTemplates.push("qt5ct"); - if (!SettingsData.matugenTemplateQt6ct) - skipTemplates.push("qt6ct"); - if (!SettingsData.matugenTemplateFirefox) - skipTemplates.push("firefox"); - if (!SettingsData.matugenTemplatePywalfox) - skipTemplates.push("pywalfox"); - if (!SettingsData.matugenTemplateZenBrowser) - skipTemplates.push("zenbrowser"); - if (!SettingsData.matugenTemplateVesktop) - skipTemplates.push("vesktop"); - if (!SettingsData.matugenTemplateEquibop) - skipTemplates.push("equibop"); - if (!SettingsData.matugenTemplateGhostty) - skipTemplates.push("ghostty"); - if (!SettingsData.matugenTemplateKitty) - skipTemplates.push("kitty"); - if (!SettingsData.matugenTemplateFoot) - skipTemplates.push("foot"); - if (!SettingsData.matugenTemplateNeovim) - skipTemplates.push("nvim"); - if (!SettingsData.matugenTemplateAlacritty) - skipTemplates.push("alacritty"); - if (!SettingsData.matugenTemplateWezterm) - skipTemplates.push("wezterm"); - if (!SettingsData.matugenTemplateDgop) - skipTemplates.push("dgop"); - if (!SettingsData.matugenTemplateKcolorscheme) - skipTemplates.push("kcolorscheme"); - if (!SettingsData.matugenTemplateVscode) - skipTemplates.push("vscode"); - if (!SettingsData.matugenTemplateEmacs) - skipTemplates.push("emacs"); - if (!SettingsData.matugenTemplateZed) - skipTemplates.push("zed"); - } - if (skipTemplates.length > 0) { - args.push("--skip-templates", skipTemplates.join(",")); - } - } - - systemThemeGenerator.command = args; - systemThemeGenerator.running = true; - } - - function generateSystemThemesFromCurrentTheme() { - const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); - if (!matugenAvailable || isGreeterMode) - return; - - _pendingGenerateParams = true; - _themeGenerateDebounce.restart(); - } - - function _executeThemeGeneration() { - if (!_pendingGenerateParams) - return; - _pendingGenerateParams = null; - - const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode); - const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"; - - if (currentTheme === dynamic) { - if (!rawWallpaperPath) - return; - const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"; - const kind = rawWallpaperPath.startsWith("#") ? "hex" : "image"; - setDesiredTheme(kind, rawWallpaperPath, isLight, iconTheme, selectedMatugenType, null); - return; - } - - let darkTheme, lightTheme; - if (currentTheme === "custom") { - if (customThemeRawData && (customThemeRawData.dark || customThemeRawData.light)) { - darkTheme = customThemeRawData.dark || customThemeRawData.light; - lightTheme = customThemeRawData.light || customThemeRawData.dark; - - if (customThemeRawData.variants) { - const themeId = customThemeRawData.id || ""; - - if (customThemeRawData.variants.type === "multi" && customThemeRawData.variants.flavors && customThemeRawData.variants.accents) { - const defaults = customThemeRawData.variants.defaults || {}; - const darkDefaults = defaults.dark || {}; - const lightDefaults = defaults.light || defaults.dark || {}; - const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode; - const storedDark = isGreeterMode ? (GreetdSettings.registryThemeVariants[themeId]?.dark || darkDefaults) : (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults, "dark") : darkDefaults); - const storedLight = isGreeterMode ? (GreetdSettings.registryThemeVariants[themeId]?.light || lightDefaults) : (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults, "light") : lightDefaults); - const darkFlavorId = storedDark.flavor || darkDefaults.flavor || ""; - const lightFlavorId = storedLight.flavor || lightDefaults.flavor || ""; - const accentId = storedDark.accent || darkDefaults.accent || ""; - const darkFlavor = findVariant(customThemeRawData.variants.flavors, darkFlavorId); - const lightFlavor = findVariant(customThemeRawData.variants.flavors, lightFlavorId); - const accent = findAccent(customThemeRawData.variants.accents, accentId); - if (darkFlavor) { - darkTheme = mergeColors(darkTheme, darkFlavor.dark || {}); - if (accent) - darkTheme = mergeColors(darkTheme, accent[darkFlavor.id] || {}); - } - if (lightFlavor) { - lightTheme = mergeColors(lightTheme, lightFlavor.light || {}); - if (accent) - lightTheme = mergeColors(lightTheme, accent[lightFlavor.id] || {}); - } - } else if (customThemeRawData.variants.options) { - const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode; - const selectedVariantId = isGreeterMode ? (typeof GreetdSettings.registryThemeVariants[themeId] === "string" ? GreetdSettings.registryThemeVariants[themeId] : customThemeRawData.variants.default) : (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default); - const variant = findVariant(customThemeRawData.variants.options, selectedVariantId); - if (variant) { - darkTheme = mergeColors(darkTheme, variant.dark || {}); - lightTheme = mergeColors(lightTheme, variant.light || {}); - } - } - } - } else { - darkTheme = customThemeData; - lightTheme = customThemeData; - } - } else { - darkTheme = StockThemes.getThemeByName(currentTheme, false); - lightTheme = StockThemes.getThemeByName(currentTheme, true); - } - - if (!darkTheme || !darkTheme.primary) { - console.warn("Theme data not available for:", currentTheme); - return; - } - - const stockColors = buildMatugenColorsFromTheme(darkTheme, lightTheme); - const themeData = isLight ? lightTheme : darkTheme; - setDesiredTheme("hex", themeData.primary, isLight, iconTheme, themeData.matugen_type, stockColors); - } - - function buildMatugenColorsFromTheme(darkTheme, lightTheme) { - const colors = {}; - const isLight = SessionData !== "undefined" && SessionData.isLightMode; - - function addColor(matugenKey, darkVal, lightVal) { - if (!darkVal && !lightVal) - return; - colors[matugenKey] = { - "dark": { - "color": String(darkVal || lightVal) - }, - "light": { - "color": String(lightVal || darkVal) - }, - "default": { - "color": String((isLight && lightVal) ? lightVal : darkVal) - } - }; - } - - function get(theme, key, fallback) { - return theme[key] || fallback; - } - - addColor("primary", darkTheme.primary, lightTheme.primary); - addColor("on_primary", darkTheme.primaryText, lightTheme.primaryText); - addColor("primary_container", darkTheme.primaryContainer, lightTheme.primaryContainer); - addColor("on_primary_container", darkTheme.primaryContainerText || darkTheme.surfaceText, lightTheme.primaryContainerText || lightTheme.surfaceText); - addColor("secondary", darkTheme.secondary, lightTheme.secondary); - addColor("on_secondary", darkTheme.secondaryText || darkTheme.primaryText, lightTheme.secondaryText || lightTheme.primaryText); - addColor("secondary_container", darkTheme.secondaryContainer || darkTheme.surfaceContainerHigh, lightTheme.secondaryContainer || lightTheme.surfaceContainerHigh); - addColor("on_secondary_container", darkTheme.secondaryContainerText || darkTheme.surfaceText, lightTheme.secondaryContainerText || lightTheme.surfaceText); - addColor("tertiary", darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiary || lightTheme.secondary); - addColor("on_tertiary", darkTheme.tertiaryText || darkTheme.secondaryText || darkTheme.primaryText, lightTheme.tertiaryText || lightTheme.secondaryText || lightTheme.primaryText); - addColor("tertiary_container", darkTheme.tertiaryContainer || darkTheme.secondaryContainer || darkTheme.surfaceContainerHigh, lightTheme.tertiaryContainer || lightTheme.secondaryContainer || lightTheme.surfaceContainerHigh); - addColor("on_tertiary_container", darkTheme.tertiaryContainerText || darkTheme.surfaceText, lightTheme.tertiaryContainerText || lightTheme.surfaceText); - addColor("error", darkTheme.error || "#F2B8B5", lightTheme.error || "#B3261E"); - addColor("on_error", darkTheme.errorText || "#601410", lightTheme.errorText || "#FFFFFF"); - addColor("error_container", darkTheme.errorContainer || "#8C1D18", lightTheme.errorContainer || "#F9DEDC"); - addColor("on_error_container", darkTheme.errorContainerText || "#F9DEDC", lightTheme.errorContainerText || "#410E0B"); - addColor("surface", darkTheme.surface, lightTheme.surface); - addColor("on_surface", darkTheme.surfaceText, lightTheme.surfaceText); - addColor("surface_variant", darkTheme.surfaceVariant, lightTheme.surfaceVariant); - addColor("on_surface_variant", darkTheme.surfaceVariantText, lightTheme.surfaceVariantText); - addColor("surface_tint", darkTheme.surfaceTint, lightTheme.surfaceTint); - addColor("background", darkTheme.background, lightTheme.background); - addColor("on_background", darkTheme.backgroundText, lightTheme.backgroundText); - addColor("outline", darkTheme.outline, lightTheme.outline); - addColor("outline_variant", darkTheme.outlineVariant || darkTheme.surfaceVariant, lightTheme.outlineVariant || lightTheme.surfaceVariant); - addColor("surface_container", darkTheme.surfaceContainer, lightTheme.surfaceContainer); - addColor("surface_container_high", darkTheme.surfaceContainerHigh, lightTheme.surfaceContainerHigh); - addColor("surface_container_highest", darkTheme.surfaceContainerHighest || darkTheme.surfaceContainerHigh, lightTheme.surfaceContainerHighest || lightTheme.surfaceContainerHigh); - addColor("surface_container_low", darkTheme.surfaceContainerLow || darkTheme.surface, lightTheme.surfaceContainerLow || lightTheme.surface); - addColor("surface_container_lowest", darkTheme.surfaceContainerLowest || darkTheme.background, lightTheme.surfaceContainerLowest || lightTheme.background); - addColor("surface_bright", darkTheme.surfaceBright || darkTheme.surfaceContainerHighest || darkTheme.surfaceContainerHigh, lightTheme.surfaceBright || lightTheme.surface); - addColor("surface_dim", darkTheme.surfaceDim || darkTheme.background, lightTheme.surfaceDim || lightTheme.surfaceContainer); - addColor("inverse_surface", darkTheme.inverseSurface || lightTheme.surface, lightTheme.inverseSurface || darkTheme.surface); - addColor("inverse_on_surface", darkTheme.inverseOnSurface || lightTheme.surfaceText, lightTheme.inverseOnSurface || darkTheme.surfaceText); - addColor("inverse_primary", darkTheme.inversePrimary || lightTheme.primary, lightTheme.inversePrimary || darkTheme.primary); - addColor("scrim", darkTheme.scrim || "#000000", lightTheme.scrim || "#000000"); - addColor("shadow", darkTheme.shadow || "#000000", lightTheme.shadow || "#000000"); - addColor("source_color", darkTheme.primary, lightTheme.primary); - addColor("primary_fixed", darkTheme.primaryFixed || darkTheme.primaryContainer, lightTheme.primaryFixed || lightTheme.primaryContainer); - addColor("primary_fixed_dim", darkTheme.primaryFixedDim || darkTheme.primary, lightTheme.primaryFixedDim || lightTheme.primary); - addColor("on_primary_fixed", darkTheme.onPrimaryFixed || darkTheme.primaryText, lightTheme.onPrimaryFixed || lightTheme.primaryText); - addColor("on_primary_fixed_variant", darkTheme.onPrimaryFixedVariant || darkTheme.primaryText, lightTheme.onPrimaryFixedVariant || lightTheme.primaryText); - addColor("secondary_fixed", darkTheme.secondaryFixed || darkTheme.secondary, lightTheme.secondaryFixed || lightTheme.secondary); - addColor("secondary_fixed_dim", darkTheme.secondaryFixedDim || darkTheme.secondary, lightTheme.secondaryFixedDim || lightTheme.secondary); - addColor("on_secondary_fixed", darkTheme.onSecondaryFixed || darkTheme.primaryText, lightTheme.onSecondaryFixed || lightTheme.primaryText); - addColor("on_secondary_fixed_variant", darkTheme.onSecondaryFixedVariant || darkTheme.primaryText, lightTheme.onSecondaryFixedVariant || lightTheme.primaryText); - addColor("tertiary_fixed", darkTheme.tertiaryFixed || darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiaryFixed || lightTheme.tertiary || lightTheme.secondary); - addColor("tertiary_fixed_dim", darkTheme.tertiaryFixedDim || darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiaryFixedDim || lightTheme.tertiary || lightTheme.secondary); - addColor("on_tertiary_fixed", darkTheme.onTertiaryFixed || darkTheme.primaryText, lightTheme.onTertiaryFixed || lightTheme.primaryText); - addColor("on_tertiary_fixed_variant", darkTheme.onTertiaryFixedVariant || darkTheme.primaryText, lightTheme.onTertiaryFixedVariant || lightTheme.primaryText); - - return colors; - } - - function applyGtkColors() { - if (!matugenAvailable) { - if (typeof ToastService !== "undefined") { - ToastService.showError("matugen not available or disabled - cannot apply GTK colors"); - } - return; - } - - const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "true" : "false"; - Proc.runCommand("gtkApplier", [shellDir + "/scripts/gtk.sh", configDir, isLight, shellDir], (output, exitCode) => { - if (exitCode === 0) { - if (typeof ToastService !== "undefined" && typeof NiriService !== "undefined" && !NiriService.matugenSuppression) { - ToastService.showInfo("GTK colors applied successfully"); - } - } else { - if (typeof ToastService !== "undefined") { - ToastService.showError("Failed to apply GTK colors"); - } - } - }); - } - - function applyQtColors() { - if (!matugenAvailable) { - if (typeof ToastService !== "undefined") { - ToastService.showError("matugen not available or disabled - cannot apply Qt colors"); - } - return; - } - - Proc.runCommand("qtApplier", [shellDir + "/scripts/qt.sh", configDir], (output, exitCode) => { - if (exitCode === 0) { - if (typeof ToastService !== "undefined") { - ToastService.showInfo("Qt colors applied successfully"); - } - } else { - if (typeof ToastService !== "undefined") { - ToastService.showError("Failed to apply Qt colors"); - } - } - }); - } - - function withAlpha(c, a) { - return Qt.rgba(c.r, c.g, c.b, a); - } - - function blendAlpha(c, a) { - return Qt.rgba(c.r, c.g, c.b, c.a * a); - } - - function blend(c1, c2, r) { - return Qt.rgba(c1.r * (1 - r) + c2.r * r, c1.g * (1 - r) + c2.g * r, c1.b * (1 - r) + c2.b * r, c1.a * (1 - r) + c2.a * r); - } - - function getFillMode(modeName) { - switch (modeName) { - case "Stretch": - return Image.Stretch; - case "Fit": - case "PreserveAspectFit": - return Image.PreserveAspectFit; - case "Fill": - case "PreserveAspectCrop": - return Image.PreserveAspectCrop; - case "Tile": - return Image.Tile; - case "TileVertically": - return Image.TileVertically; - case "TileHorizontally": - return Image.TileHorizontally; - case "Pad": - return Image.Pad; - default: - return Image.PreserveAspectCrop; - } - } - - function snap(value, dpr) { - const s = dpr || 1; - return Math.round(value * s) / s; - } - - function px(value, dpr) { - const s = dpr || 1; - return Math.round(value * s) / s; - } - - function hairline(dpr) { - return 1 / (dpr || 1); - } - - function invertHex(hex) { - hex = hex.replace('#', ''); - - if (!/^[0-9A-Fa-f]{6}$/.test(hex)) { - return hex; - } - - const r = parseInt(hex.substr(0, 2), 16); - const g = parseInt(hex.substr(2, 2), 16); - const b = parseInt(hex.substr(4, 2), 16); - - const invR = (255 - r).toString(16).padStart(2, '0'); - const invG = (255 - g).toString(16).padStart(2, '0'); - const invB = (255 - b).toString(16).padStart(2, '0'); - - return `#${invR}${invG}${invB}`; - } - - property var baseLogoColor: { - if (typeof SettingsData === "undefined") - return ""; - const colorOverride = SettingsData.launcherLogoColorOverride; - if (!colorOverride || colorOverride === "") - return ""; - if (colorOverride === "primary") - return primary; - if (colorOverride === "surface") - return surfaceText; - return colorOverride; - } - - property var effectiveLogoColor: { - if (typeof SettingsData === "undefined") - return ""; - - const colorOverride = SettingsData.launcherLogoColorOverride; - if (!colorOverride || colorOverride === "") - return ""; - - if (colorOverride === "primary") - return primary; - if (colorOverride === "surface") - return surfaceText; - - if (!SettingsData.launcherLogoColorInvertOnMode) { - return colorOverride; - } - - if (isLightMode) { - return invertHex(colorOverride); - } - - return colorOverride; - } - - Process { - id: systemThemeGenerator - running: false - stdout: SplitParser { - onRead: data => console.info("Theme worker:", data) - } - stderr: SplitParser { - onRead: data => console.warn("Theme worker:", data) - } - - onExited: exitCode => { - workerRunning = false; - const currentMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"; - - switch (exitCode) { - case 0: - console.info("Theme: Matugen worker completed successfully"); - root.matugenCompleted(currentMode, "success"); - break; - case 2: - console.log("Theme: Matugen worker completed with code 2 (no changes needed)"); - root.matugenCompleted(currentMode, "no-changes"); - break; - default: - if (typeof ToastService !== "undefined") { - ToastService.showError("Theme worker failed (" + exitCode + ")"); - } - console.warn("Theme: Matugen worker failed with exit code:", exitCode); - root.matugenCompleted(currentMode, "error"); - } - - if (!pendingThemeRequest) - return; - - const req = pendingThemeRequest; - pendingThemeRequest = null; - console.info("Theme: Processing queued theme request"); - setDesiredTheme(req.kind, req.value, req.isLight, req.iconTheme, req.matugenType, req.stockColors); - } - } - - FileView { - id: customThemeFileView - watchChanges: currentTheme === "custom" - - function parseAndLoadTheme() { - try { - var themeData = JSON.parse(customThemeFileView.text()); - loadCustomTheme(themeData); - } catch (e) { - ToastService.showError("Invalid JSON format: " + e.message); - } - } - - onLoaded: { - parseAndLoadTheme(); - } - - onFileChanged: { - customThemeFileView.reload(); - } - - onLoadFailed: function (error) { - if (typeof ToastService !== "undefined") { - ToastService.showError("Failed to read theme file: " + error); - } - } - } - - FileView { - id: dynamicColorsFileView - path: { - const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"; - const colorsPath = SessionData.isGreeterMode ? greetCfgDir + "/colors.json" : stateDir + "/dms-colors.json"; - return colorsPath; - } - blockLoading: false - watchChanges: !SessionData.isGreeterMode - - function parseAndLoadColors() { - try { - const colorsText = dynamicColorsFileView.text(); - if (colorsText) { - root.matugenColors = JSON.parse(colorsText); - if (typeof ToastService !== "undefined") { - ToastService.clearWallpaperError(); - } - } - } catch (e) { - console.error("Theme: Failed to parse dynamic colors:", e); - if (typeof ToastService !== "undefined") { - ToastService.wallpaperErrorStatus = "error"; - ToastService.showError("Dynamic colors parse error: " + e.message); - } - } - } - - onLoaded: { - if (currentTheme === dynamic) - colorsFileLoadFailed = false; - parseAndLoadColors(); - } - - onFileChanged: { - dynamicColorsFileView.reload(); - } - - onLoadFailed: function (error) { - if (currentTheme === dynamic) { - console.warn("Theme: Dynamic colors file load failed, marking for regeneration"); - colorsFileLoadFailed = true; - const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); - if (!isGreeterMode && matugenAvailable && rawWallpaperPath) { - console.log("Theme: Matugen available, triggering immediate regeneration"); - generateSystemThemesFromCurrentTheme(); - } - } - } - - onPathChanged: { - colorsFileLoadFailed = false; - } - } - - IpcHandler { - target: "theme" - - function toggle(): string { - root.toggleLightMode(); - return root.isLightMode ? "dark" : "light"; - } - - function light(): string { - root.setLightMode(true, true, true); - return "light"; - } - - function dark(): string { - root.setLightMode(false, true, true); - return "dark"; - } - - function getMode(): string { - return root.isLightMode ? "light" : "dark"; - } - } - - Timer { - id: _themeGenerateDebounce - interval: 100 - repeat: false - onTriggered: root._executeThemeGeneration() - } - - // These timers are for screen transitions, since sometimes QML still beats the niri call - Timer { - id: themeTransitionTimer - interval: 50 - repeat: false - property string themeName: "" - property bool savePrefs: true - onTriggered: root.switchTheme(themeName, savePrefs, false) - } - - Timer { - id: lightModeTransitionTimer - interval: 100 - repeat: false - property bool lightMode: false - property bool savePrefs: true - onTriggered: root.setLightMode(lightMode, savePrefs, false) - } - - Timer { - id: themeCategoryTransitionTimer - interval: 50 - repeat: false - property string category: "" - property string defaultTheme: "" - onTriggered: { - root.currentThemeCategory = category; - root.switchTheme(defaultTheme, true, false); - } - } - - // Theme mode automation functions - function themeAutoBackendAvailable() { - return typeof DMSService !== "undefined" && DMSService.isConnected && Array.isArray(DMSService.capabilities) && DMSService.capabilities.includes("theme.auto"); - } - - function applyThemeAutoState(state) { - if (!state) { - return; - } - if (state.config && state.config.mode && state.config.mode !== SessionData.themeModeAutoMode) { - return; - } - if (typeof SessionData !== "undefined" && state.nextTransition !== undefined) { - SessionData.themeModeNextTransition = state.nextTransition || ""; - } - if (state.isLight !== undefined && root.isLightMode !== state.isLight) { - root.setLightMode(state.isLight, true, true); - } - } - - function syncTimeThemeSchedule() { - if (typeof SessionData === "undefined" || typeof DMSService === "undefined") { - return; - } - - if (!DMSService.isConnected) { - return; - } - - const timeModeActive = SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "time"; - - if (!timeModeActive) { - return; - } - - DMSService.sendRequest("theme.auto.setMode", { - "mode": "time" - }); - - const shareSettings = SessionData.themeModeShareGammaSettings; - const startHour = shareSettings ? SessionData.nightModeStartHour : SessionData.themeModeStartHour; - const startMinute = shareSettings ? SessionData.nightModeStartMinute : SessionData.themeModeStartMinute; - const endHour = shareSettings ? SessionData.nightModeEndHour : SessionData.themeModeEndHour; - const endMinute = shareSettings ? SessionData.nightModeEndMinute : SessionData.themeModeEndMinute; - - DMSService.sendRequest("theme.auto.setSchedule", { - "startHour": startHour, - "startMinute": startMinute, - "endHour": endHour, - "endMinute": endMinute - }, response => { - if (response && response.error) { - console.error("Theme automation: Failed to sync time schedule:", response.error); - } - }); - - DMSService.sendRequest("theme.auto.setEnabled", { - "enabled": true - }); - DMSService.sendRequest("theme.auto.trigger", {}); - } - - function syncLocationThemeSchedule() { - if (typeof SessionData === "undefined" || typeof DMSService === "undefined") { - return; - } - - if (!DMSService.isConnected) { - return; - } - - const locationModeActive = SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "location"; - - if (!locationModeActive) { - return; - } - - DMSService.sendRequest("theme.auto.setMode", { - "mode": "location" - }); - - if (SessionData.nightModeUseIPLocation) { - DMSService.sendRequest("theme.auto.setUseIPLocation", { - "use": true - }); - } else { - DMSService.sendRequest("theme.auto.setUseIPLocation", { - "use": false - }); - if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - DMSService.sendRequest("theme.auto.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }); - } - } - - DMSService.sendRequest("theme.auto.setEnabled", { - "enabled": true - }); - DMSService.sendRequest("theme.auto.trigger", {}); - } - - function evaluateThemeMode() { - if (typeof SessionData === "undefined" || !SessionData.themeModeAutoEnabled) { - return; - } - - if (themeAutoBackendAvailable()) { - DMSService.sendRequest("theme.auto.getState", null, response => { - if (response && response.result) { - applyThemeAutoState(response.result); - } - }); - return; - } - - const mode = SessionData.themeModeAutoMode; - - if (mode === "location") { - evaluateLocationBasedThemeMode(); - } else { - evaluateTimeBasedThemeMode(); - } - } - - function evaluateLocationBasedThemeMode() { - if (typeof DisplayService !== "undefined") { - const shouldBeLight = DisplayService.gammaIsDay; - if (root.isLightMode !== shouldBeLight) { - root.setLightMode(shouldBeLight, true, true); - } - return; - } - - if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - const shouldBeLight = calculateIsDaytime(SessionData.latitude, SessionData.longitude); - if (root.isLightMode !== shouldBeLight) { - root.setLightMode(shouldBeLight, true, true); - } - return; - } - - if (root.themeModeAutomationActive) { - if (SessionData.nightModeUseIPLocation) { - console.warn("Theme automation: Waiting for IP location from backend"); - } else { - console.warn("Theme automation: Location mode requires coordinates"); - } - } - } - - function evaluateTimeBasedThemeMode() { - const shareSettings = SessionData.themeModeShareGammaSettings; - - const startHour = shareSettings ? SessionData.nightModeStartHour : SessionData.themeModeStartHour; - const startMinute = shareSettings ? SessionData.nightModeStartMinute : SessionData.themeModeStartMinute; - const endHour = shareSettings ? SessionData.nightModeEndHour : SessionData.themeModeEndHour; - const endMinute = shareSettings ? SessionData.nightModeEndMinute : SessionData.themeModeEndMinute; - - const now = new Date(); - const currentMinutes = now.getHours() * 60 + now.getMinutes(); - const startMinutes = startHour * 60 + startMinute; - const endMinutes = endHour * 60 + endMinute; - - let shouldBeLight; - if (startMinutes < endMinutes) { - shouldBeLight = currentMinutes < startMinutes || currentMinutes >= endMinutes; - } else { - shouldBeLight = currentMinutes >= endMinutes && currentMinutes < startMinutes; - } - - if (root.isLightMode !== shouldBeLight) { - root.setLightMode(shouldBeLight, true, true); - } - } - - function calculateIsDaytime(lat, lng) { - const now = new Date(); - const start = new Date(now.getFullYear(), 0, 0); - const diff = now - start; - const dayOfYear = Math.floor(diff / 86400000); - const latRad = lat * Math.PI / 180; - - const declination = 23.45 * Math.sin((360 / 365) * (dayOfYear - 81) * Math.PI / 180); - const declinationRad = declination * Math.PI / 180; - - const cosHourAngle = -Math.tan(latRad) * Math.tan(declinationRad); - - if (cosHourAngle > 1) { - return false; // Polar night - } - if (cosHourAngle < -1) { - return true; // Midnight sun - } - - const hourAngle = Math.acos(cosHourAngle); - const hourAngleDeg = hourAngle * 180 / Math.PI; - - const sunriseHour = 12 - hourAngleDeg / 15; - const sunsetHour = 12 + hourAngleDeg / 15; - - const timeZoneOffset = now.getTimezoneOffset() / 60; - const localSunrise = sunriseHour - lng / 15 - timeZoneOffset; - const localSunset = sunsetHour - lng / 15 - timeZoneOffset; - - const currentHour = now.getHours() + now.getMinutes() / 60; - - const normalizeSunrise = ((localSunrise % 24) + 24) % 24; - const normalizeSunset = ((localSunset % 24) + 24) % 24; - - return currentHour >= normalizeSunrise && currentHour < normalizeSunset; - } - - // Helper function to send location to backend - function sendLocationToBackend() { - if (typeof SessionData === "undefined" || typeof DMSService === "undefined") { - return false; - } - - if (!DMSService.isConnected) { - return false; - } - - if (SessionData.nightModeUseIPLocation) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": true - }, response => { - if (response?.error) { - console.warn("Theme automation: Failed to enable IP location", response.error); - } - }); - return true; - } else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": false - }, response => { - if (!response.error) { - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }, locResp => { - if (locResp?.error) { - console.warn("Theme automation: Failed to set location", locResp.error); - } - }); - } - }); - return true; - } - return false; - } - - Timer { - id: locationRetryTimer - interval: 1000 - repeat: true - running: false - property int retryCount: 0 - - onTriggered: { - if (root.sendLocationToBackend()) { - stop(); - retryCount = 0; - root.evaluateThemeMode(); - } else { - retryCount++; - if (retryCount >= 10) { - stop(); - retryCount = 0; - } - } - } - } - - function startThemeModeAutomation() { - root.themeModeAutomationActive = true; - - root.syncTimeThemeSchedule(); - root.syncLocationThemeSchedule(); - - const sent = root.sendLocationToBackend(); - - if (!sent && typeof SessionData !== "undefined" && SessionData.themeModeAutoMode === "location") { - locationRetryTimer.start(); - } else { - root.evaluateThemeMode(); - } - } - - function stopThemeModeAutomation() { - root.themeModeAutomationActive = false; - if (typeof DMSService !== "undefined" && DMSService.isConnected) { - DMSService.sendRequest("theme.auto.setEnabled", { - "enabled": false - }); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/TrayMenuManager.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/TrayMenuManager.qml deleted file mode 100644 index 560d757..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/TrayMenuManager.qml +++ /dev/null @@ -1,36 +0,0 @@ -pragma Singleton - -import Quickshell -import QtQuick - -Singleton { - id: root - - property var activeTrayMenus: ({}) - - function registerMenu(screenName, menu) { - if (!screenName || !menu) return - const newMenus = Object.assign({}, activeTrayMenus) - newMenus[screenName] = menu - activeTrayMenus = newMenus - } - - function unregisterMenu(screenName) { - if (!screenName) return - const newMenus = Object.assign({}, activeTrayMenus) - delete newMenus[screenName] - activeTrayMenus = newMenus - } - - function closeAllMenus() { - for (const screenName in activeTrayMenus) { - const menu = activeTrayMenus[screenName] - if (!menu) continue - if (typeof menu.close === "function") { - menu.close() - } else if (menu.showMenu !== undefined) { - menu.showMenu = false - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/fzf.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/fzf.js deleted file mode 100644 index 94946e6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/fzf.js +++ /dev/null @@ -1,1308 +0,0 @@ -.pragma library - -/* -https://github.com/ajitid/fzf-for-js - -BSD 3-Clause License - -Copyright (c) 2021, Ajit -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -const normalized = { - 216: "O", - 223: "s", - 248: "o", - 273: "d", - 295: "h", - 305: "i", - 320: "l", - 322: "l", - 359: "t", - 383: "s", - 384: "b", - 385: "B", - 387: "b", - 390: "O", - 392: "c", - 393: "D", - 394: "D", - 396: "d", - 398: "E", - 400: "E", - 402: "f", - 403: "G", - 407: "I", - 409: "k", - 410: "l", - 412: "M", - 413: "N", - 414: "n", - 415: "O", - 421: "p", - 427: "t", - 429: "t", - 430: "T", - 434: "V", - 436: "y", - 438: "z", - 477: "e", - 485: "g", - 544: "N", - 545: "d", - 549: "z", - 564: "l", - 565: "n", - 566: "t", - 567: "j", - 570: "A", - 571: "C", - 572: "c", - 573: "L", - 574: "T", - 575: "s", - 576: "z", - 579: "B", - 580: "U", - 581: "V", - 582: "E", - 583: "e", - 584: "J", - 585: "j", - 586: "Q", - 587: "q", - 588: "R", - 589: "r", - 590: "Y", - 591: "y", - 592: "a", - 593: "a", - 595: "b", - 596: "o", - 597: "c", - 598: "d", - 599: "d", - 600: "e", - 603: "e", - 604: "e", - 605: "e", - 606: "e", - 607: "j", - 608: "g", - 609: "g", - 610: "G", - 613: "h", - 614: "h", - 616: "i", - 618: "I", - 619: "l", - 620: "l", - 621: "l", - 623: "m", - 624: "m", - 625: "m", - 626: "n", - 627: "n", - 628: "N", - 629: "o", - 633: "r", - 634: "r", - 635: "r", - 636: "r", - 637: "r", - 638: "r", - 639: "r", - 640: "R", - 641: "R", - 642: "s", - 647: "t", - 648: "t", - 649: "u", - 651: "v", - 652: "v", - 653: "w", - 654: "y", - 655: "Y", - 656: "z", - 657: "z", - 663: "c", - 665: "B", - 666: "e", - 667: "G", - 668: "H", - 669: "j", - 670: "k", - 671: "L", - 672: "q", - 686: "h", - 867: "a", - 868: "e", - 869: "i", - 870: "o", - 871: "u", - 872: "c", - 873: "d", - 874: "h", - 875: "m", - 876: "r", - 877: "t", - 878: "v", - 879: "x", - 7424: "A", - 7427: "B", - 7428: "C", - 7429: "D", - 7431: "E", - 7432: "e", - 7433: "i", - 7434: "J", - 7435: "K", - 7436: "L", - 7437: "M", - 7438: "N", - 7439: "O", - 7440: "O", - 7441: "o", - 7442: "o", - 7443: "o", - 7446: "o", - 7447: "o", - 7448: "P", - 7449: "R", - 7450: "R", - 7451: "T", - 7452: "U", - 7453: "u", - 7454: "u", - 7455: "m", - 7456: "V", - 7457: "W", - 7458: "Z", - 7522: "i", - 7523: "r", - 7524: "u", - 7525: "v", - 7834: "a", - 7835: "s", - 8305: "i", - 8341: "h", - 8342: "k", - 8343: "l", - 8344: "m", - 8345: "n", - 8346: "p", - 8347: "s", - 8348: "t", - 8580: "c" -}; -for (let i = "\u0300".codePointAt(0); i <= "\u036F".codePointAt(0); ++i) { - const diacritic = String.fromCodePoint(i); - for (const asciiChar of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") { - const withDiacritic = (asciiChar + diacritic).normalize(); - const withDiacriticCodePoint = withDiacritic.codePointAt(0); - if (withDiacriticCodePoint > 126) { - normalized[withDiacriticCodePoint] = asciiChar; - } - } -} -const ranges = { - a: [7844, 7863], - e: [7870, 7879], - o: [7888, 7907], - u: [7912, 7921] -}; -for (const lowerChar of Object.keys(ranges)) { - const upperChar = lowerChar.toUpperCase(); - for (let i = ranges[lowerChar][0]; i <= ranges[lowerChar][1]; ++i) { - normalized[i] = i % 2 === 0 ? upperChar : lowerChar; - } -} -function normalizeRune(rune) { - if (rune < 192 || rune > 8580) { - return rune; - } - const normalizedChar = normalized[rune]; - if (normalizedChar !== void 0) - return normalizedChar.codePointAt(0); - return rune; -} -function toShort(number) { - return number; -} -function toInt(number) { - return number; -} -function maxInt16(num1, num2) { - return num1 > num2 ? num1 : num2; -} -const strToRunes = (str) => str.split("").map((s) => s.codePointAt(0)); -const runesToStr = (runes) => runes.map((r) => String.fromCodePoint(r)).join(""); -const whitespaceRunes = new Set( - " \f\n\r \v\xA0\u1680\u2028\u2029\u202F\u205F\u3000\uFEFF".split("").map((v) => v.codePointAt(0)) -); -for (let codePoint = "\u2000".codePointAt(0); codePoint <= "\u200A".codePointAt(0); codePoint++) { - whitespaceRunes.add(codePoint); -} -const isWhitespace = (rune) => whitespaceRunes.has(rune); -const whitespacesAtStart = (runes) => { - let whitespaces = 0; - for (const rune of runes) { - if (isWhitespace(rune)) - whitespaces++; - else - break; - } - return whitespaces; -}; -const whitespacesAtEnd = (runes) => { - let whitespaces = 0; - for (let i = runes.length - 1; i >= 0; i--) { - if (isWhitespace(runes[i])) - whitespaces++; - else - break; - } - return whitespaces; -}; -const MAX_ASCII = "\x7F".codePointAt(0); -const CAPITAL_A_RUNE = "A".codePointAt(0); -const CAPITAL_Z_RUNE = "Z".codePointAt(0); -const SMALL_A_RUNE = "a".codePointAt(0); -const SMALL_Z_RUNE = "z".codePointAt(0); -const NUMERAL_ZERO_RUNE = "0".codePointAt(0); -const NUMERAL_NINE_RUNE = "9".codePointAt(0); -function indexAt(index, max, forward) { - if (forward) { - return index; - } - return max - index - 1; -} -const SCORE_MATCH = 16, SCORE_GAP_START = -3, SCORE_GAP_EXTENTION = -1, BONUS_BOUNDARY = SCORE_MATCH / 2, BONUS_NON_WORD = SCORE_MATCH / 2, BONUS_CAMEL_123 = BONUS_BOUNDARY + SCORE_GAP_EXTENTION, BONUS_CONSECUTIVE = -(SCORE_GAP_START + SCORE_GAP_EXTENTION), BONUS_FIRST_CHAR_MULTIPLIER = 2; -function createPosSet(withPos) { - if (withPos) { - return /* @__PURE__ */ new Set(); - } - return null; -} -function alloc16(offset, slab2, size) { - if (slab2 !== null && slab2.i16.length > offset + size) { - const subarray = slab2.i16.subarray(offset, offset + size); - return [offset + size, subarray]; - } - return [offset, new Int16Array(size)]; -} -function alloc32(offset, slab2, size) { - if (slab2 !== null && slab2.i32.length > offset + size) { - const subarray = slab2.i32.subarray(offset, offset + size); - return [offset + size, subarray]; - } - return [offset, new Int32Array(size)]; -} -function charClassOfAscii(rune) { - if (rune >= SMALL_A_RUNE && rune <= SMALL_Z_RUNE) { - return 1; - } else if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { - return 2; - } else if (rune >= NUMERAL_ZERO_RUNE && rune <= NUMERAL_NINE_RUNE) { - return 4; - } else { - return 0; - } -} -function charClassOfNonAscii(rune) { - const char = String.fromCodePoint(rune); - if (char !== char.toUpperCase()) { - return 1; - } else if (char !== char.toLowerCase()) { - return 2; - } else if (char.match(/\p{Number}/gu) !== null) { - return 4; - } else if (char.match(/\p{Letter}/gu) !== null) { - return 3; - } - return 0; -} -function charClassOf(rune) { - if (rune <= MAX_ASCII) { - return charClassOfAscii(rune); - } - return charClassOfNonAscii(rune); -} -function bonusFor(prevClass, currClass) { - if (prevClass === 0 && currClass !== 0) { - return BONUS_BOUNDARY; - } else if (prevClass === 1 && currClass === 2 || prevClass !== 4 && currClass === 4) { - return BONUS_CAMEL_123; - } else if (currClass === 0) { - return BONUS_NON_WORD; - } - return 0; -} -function bonusAt(input, idx) { - if (idx === 0) { - return BONUS_BOUNDARY; - } - return bonusFor(charClassOf(input[idx - 1]), charClassOf(input[idx])); -} -function trySkip(input, caseSensitive, char, from) { - let rest = input.slice(from); - let idx = rest.indexOf(char); - if (idx === 0) { - return from; - } - if (!caseSensitive && char >= SMALL_A_RUNE && char <= SMALL_Z_RUNE) { - if (idx > 0) { - rest = rest.slice(0, idx); - } - const uidx = rest.indexOf(char - 32); - if (uidx >= 0) { - idx = uidx; - } - } - if (idx < 0) { - return -1; - } - return from + idx; -} -function isAscii(runes) { - for (const rune of runes) { - if (rune >= 128) { - return false; - } - } - return true; -} -function asciiFuzzyIndex(input, pattern, caseSensitive) { - if (!isAscii(input)) { - return 0; - } - if (!isAscii(pattern)) { - return -1; - } - let firstIdx = 0, idx = 0; - for (let pidx = 0; pidx < pattern.length; pidx++) { - idx = trySkip(input, caseSensitive, pattern[pidx], idx); - if (idx < 0) { - return -1; - } - if (pidx === 0 && idx > 0) { - firstIdx = idx - 1; - } - idx++; - } - return firstIdx; -} -const fuzzyMatchV2 = (caseSensitive, normalize, forward, input, pattern, withPos, slab2) => { - const M = pattern.length; - if (M === 0) { - return [{ start: 0, end: 0, score: 0 }, createPosSet(withPos)]; - } - const N = input.length; - if (slab2 !== null && N * M > slab2.i16.length) { - return fuzzyMatchV1(caseSensitive, normalize, forward, input, pattern, withPos); - } - const idx = asciiFuzzyIndex(input, pattern, caseSensitive); - if (idx < 0) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - let offset16 = 0, offset32 = 0, H0 = null, C0 = null, B = null, F = null; - [offset16, H0] = alloc16(offset16, slab2, N); - [offset16, C0] = alloc16(offset16, slab2, N); - [offset16, B] = alloc16(offset16, slab2, N); - [offset32, F] = alloc32(offset32, slab2, M); - const [, T] = alloc32(offset32, slab2, N); - for (let i = 0; i < T.length; i++) { - T[i] = input[i]; - } - let maxScore = toShort(0), maxScorePos = 0; - let pidx = 0, lastIdx = 0; - const pchar0 = pattern[0]; - let pchar = pattern[0], prevH0 = toShort(0), prevCharClass = 0, inGap = false; - let Tsub = T.subarray(idx); - let H0sub = H0.subarray(idx).subarray(0, Tsub.length), C0sub = C0.subarray(idx).subarray(0, Tsub.length), Bsub = B.subarray(idx).subarray(0, Tsub.length); - for (let [off, char] of Tsub.entries()) { - let charClass = null; - if (char <= MAX_ASCII) { - charClass = charClassOfAscii(char); - if (!caseSensitive && charClass === 2) { - char += 32; - } - } else { - charClass = charClassOfNonAscii(char); - if (!caseSensitive && charClass === 2) { - char = String.fromCodePoint(char).toLowerCase().codePointAt(0); - } - if (normalize) { - char = normalizeRune(char); - } - } - Tsub[off] = char; - const bonus = bonusFor(prevCharClass, charClass); - Bsub[off] = bonus; - prevCharClass = charClass; - if (char === pchar) { - if (pidx < M) { - F[pidx] = toInt(idx + off); - pidx++; - pchar = pattern[Math.min(pidx, M - 1)]; - } - lastIdx = idx + off; - } - if (char === pchar0) { - const score = SCORE_MATCH + bonus * BONUS_FIRST_CHAR_MULTIPLIER; - H0sub[off] = score; - C0sub[off] = 1; - if (M === 1 && (forward && score > maxScore || !forward && score >= maxScore)) { - maxScore = score; - maxScorePos = idx + off; - if (forward && bonus === BONUS_BOUNDARY) { - break; - } - } - inGap = false; - } else { - if (inGap) { - H0sub[off] = maxInt16(prevH0 + SCORE_GAP_EXTENTION, 0); - } else { - H0sub[off] = maxInt16(prevH0 + SCORE_GAP_START, 0); - } - C0sub[off] = 0; - inGap = true; - } - prevH0 = H0sub[off]; - } - if (pidx !== M) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - if (M === 1) { - const result = { - start: maxScorePos, - end: maxScorePos + 1, - score: maxScore - }; - if (!withPos) { - return [result, null]; - } - const pos2 = /* @__PURE__ */ new Set(); - pos2.add(maxScorePos); - return [result, pos2]; - } - const f0 = F[0]; - const width = lastIdx - f0 + 1; - let H = null; - [offset16, H] = alloc16(offset16, slab2, width * M); - { - const toCopy = H0.subarray(f0, lastIdx + 1); - for (const [i, v] of toCopy.entries()) { - H[i] = v; - } - } - let [, C] = alloc16(offset16, slab2, width * M); - { - const toCopy = C0.subarray(f0, lastIdx + 1); - for (const [i, v] of toCopy.entries()) { - C[i] = v; - } - } - const Fsub = F.subarray(1); - const Psub = pattern.slice(1).slice(0, Fsub.length); - for (const [off, f] of Fsub.entries()) { - let inGap2 = false; - const pchar2 = Psub[off], pidx2 = off + 1, row = pidx2 * width, Tsub2 = T.subarray(f, lastIdx + 1), Bsub2 = B.subarray(f).subarray(0, Tsub2.length), Csub = C.subarray(row + f - f0).subarray(0, Tsub2.length), Cdiag = C.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hsub = H.subarray(row + f - f0).subarray(0, Tsub2.length), Hdiag = H.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hleft = H.subarray(row + f - f0 - 1).subarray(0, Tsub2.length); - Hleft[0] = 0; - for (const [off2, char] of Tsub2.entries()) { - const col = off2 + f; - let s1 = 0, s2 = 0, consecutive = 0; - if (inGap2) { - s2 = Hleft[off2] + SCORE_GAP_EXTENTION; - } else { - s2 = Hleft[off2] + SCORE_GAP_START; - } - if (pchar2 === char) { - s1 = Hdiag[off2] + SCORE_MATCH; - let b = Bsub2[off2]; - consecutive = Cdiag[off2] + 1; - if (b === BONUS_BOUNDARY) { - consecutive = 1; - } else if (consecutive > 1) { - b = maxInt16(b, maxInt16(BONUS_CONSECUTIVE, B[col - consecutive + 1])); - } - if (s1 + b < s2) { - s1 += Bsub2[off2]; - consecutive = 0; - } else { - s1 += b; - } - } - Csub[off2] = consecutive; - inGap2 = s1 < s2; - const score = maxInt16(maxInt16(s1, s2), 0); - if (pidx2 === M - 1 && (forward && score > maxScore || !forward && score >= maxScore)) { - maxScore = score; - maxScorePos = col; - } - Hsub[off2] = score; - } - } - const pos = createPosSet(withPos); - let j = f0; - if (withPos && pos !== null) { - let i = M - 1; - j = maxScorePos; - let preferMatch = true; - while (true) { - const I = i * width, j0 = j - f0, s = H[I + j0]; - let s1 = 0, s2 = 0; - if (i > 0 && j >= F[i]) { - s1 = H[I - width + j0 - 1]; - } - if (j > F[i]) { - s2 = H[I + j0 - 1]; - } - if (s > s1 && (s > s2 || s === s2 && preferMatch)) { - pos.add(j); - if (i === 0) { - break; - } - i--; - } - preferMatch = C[I + j0] > 1 || I + width + j0 + 1 < C.length && C[I + width + j0 + 1] > 0; - j--; - } - } - return [{ start: j, end: maxScorePos + 1, score: maxScore }, pos]; -}; -function calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, withPos) { - let pidx = 0, score = 0, inGap = false, consecutive = 0, firstBonus = toShort(0); - const pos = createPosSet(withPos); - let prevCharClass = 0; - if (sidx > 0) { - prevCharClass = charClassOf(text[sidx - 1]); - } - for (let idx = sidx; idx < eidx; idx++) { - let rune = text[idx]; - const charClass = charClassOf(rune); - if (!caseSensitive) { - if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { - rune += 32; - } else if (rune > MAX_ASCII) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - } - if (normalize) { - rune = normalizeRune(rune); - } - if (rune === pattern[pidx]) { - if (withPos && pos !== null) { - pos.add(idx); - } - score += SCORE_MATCH; - let bonus = bonusFor(prevCharClass, charClass); - if (consecutive === 0) { - firstBonus = bonus; - } else { - if (bonus === BONUS_BOUNDARY) { - firstBonus = bonus; - } - bonus = maxInt16(maxInt16(bonus, firstBonus), BONUS_CONSECUTIVE); - } - if (pidx === 0) { - score += bonus * BONUS_FIRST_CHAR_MULTIPLIER; - } else { - score += bonus; - } - inGap = false; - consecutive++; - pidx++; - } else { - if (inGap) { - score += SCORE_GAP_EXTENTION; - } else { - score += SCORE_GAP_START; - } - inGap = true; - consecutive = 0; - firstBonus = 0; - } - prevCharClass = charClass; - } - return [score, pos]; -} -function fuzzyMatchV1(caseSensitive, normalize, forward, text, pattern, withPos, slab2) { - if (pattern.length === 0) { - return [{ start: 0, end: 0, score: 0 }, null]; - } - if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - let pidx = 0, sidx = -1, eidx = -1; - const lenRunes = text.length; - const lenPattern = pattern.length; - for (let index = 0; index < lenRunes; index++) { - let rune = text[indexAt(index, lenRunes, forward)]; - if (!caseSensitive) { - if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { - rune += 32; - } else if (rune > MAX_ASCII) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - } - if (normalize) { - rune = normalizeRune(rune); - } - const pchar = pattern[indexAt(pidx, lenPattern, forward)]; - if (rune === pchar) { - if (sidx < 0) { - sidx = index; - } - pidx++; - if (pidx === lenPattern) { - eidx = index + 1; - break; - } - } - } - if (sidx >= 0 && eidx >= 0) { - pidx--; - for (let index = eidx - 1; index >= sidx; index--) { - const tidx = indexAt(index, lenRunes, forward); - let rune = text[tidx]; - if (!caseSensitive) { - if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { - rune += 32; - } else if (rune > MAX_ASCII) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - } - const pidx_ = indexAt(pidx, lenPattern, forward); - const pchar = pattern[pidx_]; - if (rune === pchar) { - pidx--; - if (pidx < 0) { - sidx = index; - break; - } - } - } - if (!forward) { - const sidxTemp = sidx; - sidx = lenRunes - eidx; - eidx = lenRunes - sidxTemp; - } - const [score, pos] = calculateScore( - caseSensitive, - normalize, - text, - pattern, - sidx, - eidx, - withPos - ); - return [{ start: sidx, end: eidx, score }, pos]; - } - return [{ start: -1, end: -1, score: 0 }, null]; -}; -const exactMatchNaive = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { - if (pattern.length === 0) { - return [{ start: 0, end: 0, score: 0 }, null]; - } - const lenRunes = text.length; - const lenPattern = pattern.length; - if (lenRunes < lenPattern) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - let pidx = 0; - let bestPos = -1, bonus = toShort(0), bestBonus = toShort(-1); - for (let index = 0; index < lenRunes; index++) { - const index_ = indexAt(index, lenRunes, forward); - let rune = text[index_]; - if (!caseSensitive) { - if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { - rune += 32; - } else if (rune > MAX_ASCII) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - } - if (normalize) { - rune = normalizeRune(rune); - } - const pidx_ = indexAt(pidx, lenPattern, forward); - const pchar = pattern[pidx_]; - if (pchar === rune) { - if (pidx_ === 0) { - bonus = bonusAt(text, index_); - } - pidx++; - if (pidx === lenPattern) { - if (bonus > bestBonus) { - bestPos = index; - bestBonus = bonus; - } - if (bonus === BONUS_BOUNDARY) { - break; - } - index -= pidx - 1; - pidx = 0; - bonus = 0; - } - } else { - index -= pidx; - pidx = 0; - bonus = 0; - } - } - if (bestPos >= 0) { - let sidx = 0, eidx = 0; - if (forward) { - sidx = bestPos - lenPattern + 1; - eidx = bestPos + 1; - } else { - sidx = lenRunes - (bestPos + 1); - eidx = lenRunes - (bestPos - lenPattern + 1); - } - const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); - return [{ start: sidx, end: eidx, score }, null]; - } - return [{ start: -1, end: -1, score: 0 }, null]; -}; -const prefixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { - if (pattern.length === 0) { - return [{ start: 0, end: 0, score: 0 }, null]; - } - let trimmedLen = 0; - if (!isWhitespace(pattern[0])) { - trimmedLen = whitespacesAtStart(text); - } - if (text.length - trimmedLen < pattern.length) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - for (const [index, r] of pattern.entries()) { - let rune = text[trimmedLen + index]; - if (!caseSensitive) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - if (normalize) { - rune = normalizeRune(rune); - } - if (rune !== r) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - } - const lenPattern = pattern.length; - const [score] = calculateScore( - caseSensitive, - normalize, - text, - pattern, - trimmedLen, - trimmedLen + lenPattern, - false - ); - return [{ start: trimmedLen, end: trimmedLen + lenPattern, score }, null]; -}; -const suffixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { - const lenRunes = text.length; - let trimmedLen = lenRunes; - if (pattern.length === 0 || !isWhitespace(pattern[pattern.length - 1])) { - trimmedLen -= whitespacesAtEnd(text); - } - if (pattern.length === 0) { - return [{ start: trimmedLen, end: trimmedLen, score: 0 }, null]; - } - const diff = trimmedLen - pattern.length; - if (diff < 0) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - for (const [index, r] of pattern.entries()) { - let rune = text[index + diff]; - if (!caseSensitive) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - if (normalize) { - rune = normalizeRune(rune); - } - if (rune !== r) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - } - const lenPattern = pattern.length; - const sidx = trimmedLen - lenPattern; - const eidx = trimmedLen; - const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); - return [{ start: sidx, end: eidx, score }, null]; -}; -const equalMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { - const lenPattern = pattern.length; - if (lenPattern === 0) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - let trimmedLen = 0; - if (!isWhitespace(pattern[0])) { - trimmedLen = whitespacesAtStart(text); - } - let trimmedEndLen = 0; - if (!isWhitespace(pattern[lenPattern - 1])) { - trimmedEndLen = whitespacesAtEnd(text); - } - if (text.length - trimmedLen - trimmedEndLen != lenPattern) { - return [{ start: -1, end: -1, score: 0 }, null]; - } - let match = true; - if (normalize) { - const runes = text; - for (const [idx, pchar] of pattern.entries()) { - let rune = runes[trimmedLen + idx]; - if (!caseSensitive) { - rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); - } - if (normalizeRune(pchar) !== normalizeRune(rune)) { - match = false; - break; - } - } - } else { - let runesStr = runesToStr(text).substring(trimmedLen, text.length - trimmedEndLen); - if (!caseSensitive) { - runesStr = runesStr.toLowerCase(); - } - match = runesStr === runesToStr(pattern); - } - if (match) { - return [ - { - start: trimmedLen, - end: trimmedLen + lenPattern, - score: (SCORE_MATCH + BONUS_BOUNDARY) * lenPattern + (BONUS_FIRST_CHAR_MULTIPLIER - 1) * BONUS_BOUNDARY - }, - null - ]; - } - return [{ start: -1, end: -1, score: 0 }, null]; -}; -const SLAB_16_SIZE = 100 * 1024; -const SLAB_32_SIZE = 2048; -function makeSlab(size16, size32) { - return { - i16: new Int16Array(size16), - i32: new Int32Array(size32) - }; -} -const slab = makeSlab(SLAB_16_SIZE, SLAB_32_SIZE); -var TermType = /* @__PURE__ */ ((TermType2) => { - TermType2[TermType2["Fuzzy"] = 0] = "Fuzzy"; - TermType2[TermType2["Exact"] = 1] = "Exact"; - TermType2[TermType2["Prefix"] = 2] = "Prefix"; - TermType2[TermType2["Suffix"] = 3] = "Suffix"; - TermType2[TermType2["Equal"] = 4] = "Equal"; - return TermType2; -})(TermType || {}); -const termTypeMap = { - [0]: fuzzyMatchV2, - [1]: exactMatchNaive, - [2]: prefixMatch, - [3]: suffixMatch, - [4]: equalMatch -}; -function buildPatternForExtendedMatch(fuzzy, caseMode, normalize, str) { - let cacheable = true; - str = str.trimLeft(); - { - const trimmedAtRightStr = str.trimRight(); - if (trimmedAtRightStr.endsWith("\\") && str[trimmedAtRightStr.length] === " ") { - str = trimmedAtRightStr + " "; - } else { - str = trimmedAtRightStr; - } - } - let sortable = false; - let termSets = []; - termSets = parseTerms(fuzzy, caseMode, normalize, str); - Loop: - for (const termSet of termSets) { - for (const [idx, term] of termSet.entries()) { - if (!term.inv) { - sortable = true; - } - if (!cacheable || idx > 0 || term.inv || fuzzy && term.typ !== 0 || !fuzzy && term.typ !== 1) { - cacheable = false; - if (sortable) { - break Loop; - } - } - } - } - return { - str, - termSets, - sortable, - cacheable, - fuzzy - }; -} -function parseTerms(fuzzy, caseMode, normalize, str) { - str = str.replace(/\\ /g, " "); - const tokens = str.split(/ +/); - const sets = []; - let set = []; - let switchSet = false; - let afterBar = false; - for (const token of tokens) { - let typ = 0, inv = false, text = token.replace(/\t/g, " "); - const lowerText = text.toLowerCase(); - const caseSensitive = caseMode === "case-sensitive" || caseMode === "smart-case" && text !== lowerText; - const normalizeTerm = normalize && lowerText === runesToStr(strToRunes(lowerText).map(normalizeRune)); - if (!caseSensitive) { - text = lowerText; - } - if (!fuzzy) { - typ = 1; - } - if (set.length > 0 && !afterBar && text === "|") { - switchSet = false; - afterBar = true; - continue; - } - afterBar = false; - if (text.startsWith("!")) { - inv = true; - typ = 1; - text = text.substring(1); - } - if (text !== "$" && text.endsWith("$")) { - typ = 3; - text = text.substring(0, text.length - 1); - } - if (text.startsWith("'")) { - if (fuzzy && !inv) { - typ = 1; - } else { - typ = 0; - } - text = text.substring(1); - } else if (text.startsWith("^")) { - if (typ === 3) { - typ = 4; - } else { - typ = 2; - } - text = text.substring(1); - } - if (text.length > 0) { - if (switchSet) { - sets.push(set); - set = []; - } - let textRunes = strToRunes(text); - if (normalizeTerm) { - textRunes = textRunes.map(normalizeRune); - } - set.push({ - typ, - inv, - text: textRunes, - caseSensitive, - normalize: normalizeTerm - }); - switchSet = true; - } - } - if (set.length > 0) { - sets.push(set); - } - return sets; -} -const buildPatternForBasicMatch = (query, casing, normalize) => { - let caseSensitive = false; - switch (casing) { - case "smart-case": - if (query.toLowerCase() !== query) { - caseSensitive = true; - } - break; - case "case-sensitive": - caseSensitive = true; - break; - case "case-insensitive": - query = query.toLowerCase(); - caseSensitive = false; - break; - } - let queryRunes = strToRunes(query); - if (normalize) { - queryRunes = queryRunes.map(normalizeRune); - } - return { - queryRunes, - caseSensitive - }; -}; -function iter(algoFn, tokens, caseSensitive, normalize, forward, pattern, slab2) { - for (const part of tokens) { - const [res, pos] = algoFn(caseSensitive, normalize, forward, part.text, pattern, true, slab2); - if (res.start >= 0) { - const sidx = res.start + part.prefixLength; - const eidx = res.end + part.prefixLength; - if (pos !== null) { - const newPos = /* @__PURE__ */ new Set(); - pos.forEach((v) => newPos.add(part.prefixLength + v)); - return [[sidx, eidx], res.score, newPos]; - } - return [[sidx, eidx], res.score, pos]; - } - } - return [[-1, -1], 0, null]; -} -function computeExtendedMatch(text, pattern, fuzzyAlgo, forward) { - const input = [ - { - text, - prefixLength: 0 - } - ]; - const offsets = []; - let totalScore = 0; - const allPos = /* @__PURE__ */ new Set(); - for (const termSet of pattern.termSets) { - let offset = [0, 0]; - let currentScore = 0; - let matched = false; - for (const term of termSet) { - let algoFn = termTypeMap[term.typ]; - if (term.typ === TermType.Fuzzy) { - algoFn = fuzzyAlgo; - } - const [off, score, pos] = iter( - algoFn, - input, - term.caseSensitive, - term.normalize, - forward, - term.text, - slab - ); - const sidx = off[0]; - if (sidx >= 0) { - if (term.inv) { - continue; - } - offset = off; - currentScore = score; - matched = true; - if (pos !== null) { - pos.forEach((v) => allPos.add(v)); - } else { - for (let idx = off[0]; idx < off[1]; ++idx) { - allPos.add(idx); - } - } - break; - } else if (term.inv) { - offset = [0, 0]; - currentScore = 0; - matched = true; - continue; - } - } - if (matched) { - offsets.push(offset); - totalScore += currentScore; - } - } - return { offsets, totalScore, allPos }; -} -function getResultFromScoreMap(scoreMap, limit) { - const scoresInDesc = Object.keys(scoreMap).map((v) => parseInt(v, 10)).sort((a, b) => b - a); - let result = []; - for (const score of scoresInDesc) { - result = result.concat(scoreMap[score]); - if (result.length >= limit) { - break; - } - } - return result; -} -function getBasicMatchIter(scoreMap, queryRunes, caseSensitive) { - return (idx) => { - const itemRunes = this.runesList[idx]; - if (queryRunes.length > itemRunes.length) - return; - let [match, positions] = this.algoFn( - caseSensitive, - this.opts.normalize, - this.opts.forward, - itemRunes, - queryRunes, - true, - slab - ); - if (match.start === -1) - return; - if (this.opts.fuzzy === false) { - positions = /* @__PURE__ */ new Set(); - for (let position = match.start; position < match.end; ++position) { - positions.add(position); - } - } - const scoreKey = this.opts.sort ? match.score : 0; - if (scoreMap[scoreKey] === void 0) { - scoreMap[scoreKey] = []; - } - scoreMap[scoreKey].push(Object.assign({ - item: this.items[idx], - positions: positions != null ? positions : /* @__PURE__ */ new Set() - }, match)); - }; -} -function getExtendedMatchIter(scoreMap, pattern) { - return (idx) => { - const runes = this.runesList[idx]; - const match = computeExtendedMatch(runes, pattern, this.algoFn, this.opts.forward); - if (match.offsets.length !== pattern.termSets.length) - return; - let sidx = -1, eidx = -1; - if (match.allPos.size > 0) { - sidx = Math.min(...match.allPos); - eidx = Math.max(...match.allPos) + 1; - } - const scoreKey = this.opts.sort ? match.totalScore : 0; - if (scoreMap[scoreKey] === void 0) { - scoreMap[scoreKey] = []; - } - scoreMap[scoreKey].push({ - score: match.totalScore, - item: this.items[idx], - positions: match.allPos, - start: sidx, - end: eidx - }); - }; -} -function basicMatch(query) { - const { queryRunes, caseSensitive } = buildPatternForBasicMatch( - query, - this.opts.casing, - this.opts.normalize - ); - const scoreMap = {}; - const iter2 = getBasicMatchIter.bind(this)( - scoreMap, - queryRunes, - caseSensitive - ); - for (let i = 0, len = this.runesList.length; i < len; ++i) { - iter2(i); - } - return getResultFromScoreMap(scoreMap, this.opts.limit); -} -function extendedMatch(query) { - const pattern = buildPatternForExtendedMatch( - Boolean(this.opts.fuzzy), - this.opts.casing, - this.opts.normalize, - query - ); - const scoreMap = {}; - const iter2 = getExtendedMatchIter.bind(this)(scoreMap, pattern); - for (let i = 0, len = this.runesList.length; i < len; ++i) { - iter2(i); - } - return getResultFromScoreMap(scoreMap, this.opts.limit); -} -const defaultOpts = { - limit: Infinity, - selector: (v) => v, - casing: "smart-case", - normalize: true, - fuzzy: "v2", - tiebreakers: [], - sort: true, - forward: true, - match: basicMatch -}; -class Finder { - constructor(list, ...optionsTuple) { - this.opts = Object.assign({}, defaultOpts, optionsTuple[0]); - this.items = list; - this.runesList = list.map((item) => strToRunes(this.opts.selector(item).normalize())); - this.algoFn = exactMatchNaive; - switch (this.opts.fuzzy) { - case "v2": - this.algoFn = fuzzyMatchV2; - break; - case "v1": - this.algoFn = fuzzyMatchV1; - break; - } - } - find(query) { - if (query.length === 0 || this.items.length === 0) - return this.items.slice(0, this.opts.limit).map(createResultItemWithEmptyPos); - query = query.normalize(); - let result = this.opts.match.bind(this)(query); - return postProcessResultItems(result, this.opts); - } -} -function createResultItemWithEmptyPos(item) { - return ({ - item, - start: -1, - end: -1, - score: 0, - positions: /* @__PURE__ */ new Set() - }) -}; -function postProcessResultItems(result, opts) { - if (opts.sort) { - const { selector } = opts; - result.sort((a, b) => { - if (a.score !== b.score) { - return b.score - a.score; - } - for (const tiebreaker of opts.tiebreakers) { - const diff = tiebreaker(a, b, selector); - if (diff !== 0) { - return diff; - } - } - return 0; - }); - } - if (Number.isFinite(opts.limit)) { - result.splice(opts.limit); - } - return result; -} -function byLengthAsc(a, b, selector) { - return selector(a.item).length - selector(b.item).length; -} -function byStartAsc(a, b) { - return a.start - b.start; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/markdown2html.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/markdown2html.js deleted file mode 100644 index 04a9b52..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/markdown2html.js +++ /dev/null @@ -1,117 +0,0 @@ -.pragma library -// This exists only because I haven't been able to get linkColor to work with MarkdownText -// May not be necessary if that's possible tbh. -function markdownToHtml(text) { - if (!text) return ""; - - // Store code blocks and inline code to protect them from further processing - const codeBlocks = []; - const inlineCode = []; - let blockIndex = 0; - let inlineIndex = 0; - - // First, extract and replace code blocks with placeholders - let html = text.replace(/```([\s\S]*?)```/g, (match, code) => { - // Trim leading and trailing blank lines only - const trimmedCode = code.replace(/^\n+|\n+$/g, ''); - // Escape HTML entities in code - const escapedCode = trimmedCode.replace(/&/g, '&') - .replace(//g, '>'); - codeBlocks.push(`
${escapedCode}
`); - return `\x00CODEBLOCK${blockIndex++}\x00`; - }); - - // Extract and replace inline code - html = html.replace(/`([^`]+)`/g, (match, code) => { - // Escape HTML entities in code - const escapedCode = code.replace(/&/g, '&') - .replace(//g, '>'); - inlineCode.push(`${escapedCode}`); - return `\x00INLINECODE${inlineIndex++}\x00`; - }); - - // Extract plain URLs before escaping so & in query strings is preserved - const urls = []; - let urlIndex = 0; - html = html.replace(/(^|[\s])((?:https?|file):\/\/[^\s]+)/gm, (match, prefix, url) => { - urls.push(url); - return prefix + `\x00URL${urlIndex++}\x00`; - }); - - // Escape HTML entities (but not in code blocks or URLs) - html = html.replace(/&/g, '&') - .replace(//g, '>'); - - // Headers - html = html.replace(/^### (.*?)$/gm, '

$1

'); - html = html.replace(/^## (.*?)$/gm, '

$1

'); - html = html.replace(/^# (.*?)$/gm, '

$1

'); - - // Bold and italic (order matters!) - html = html.replace(/\*\*\*(.*?)\*\*\*/g, '$1'); - html = html.replace(/\*\*(.*?)\*\*/g, '$1'); - html = html.replace(/\*(.*?)\*/g, '$1'); - html = html.replace(/___(.*?)___/g, '$1'); - html = html.replace(/__(.*?)__/g, '$1'); - html = html.replace(/_(.*?)_/g, '$1'); - - // Links - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - - // Lists - html = html.replace(/^\* (.*?)$/gm, '
  • $1
  • '); - html = html.replace(/^- (.*?)$/gm, '
  • $1
  • '); - html = html.replace(/^\d+\. (.*?)$/gm, '
  • $1
  • '); - - // Wrap consecutive list items in ul/ol tags - html = html.replace(/(
  • [\s\S]*?<\/li>\s*)+/g, function(match) { - return '
      ' + match + '
    '; - }); - - // Restore extracted URLs as anchor tags (preserves raw & in href) - html = html.replace(/\x00URL(\d+)\x00/g, (_, index) => { - const url = urls[parseInt(index)]; - const display = url.replace(/&/g, '&').replace(//g, '>'); - return `${display}`; - }); - - // Restore code blocks and inline code BEFORE line break processing - html = html.replace(/\x00CODEBLOCK(\d+)\x00/g, (match, index) => { - return codeBlocks[parseInt(index)]; - }); - - html = html.replace(/\x00INLINECODE(\d+)\x00/g, (match, index) => { - return inlineCode[parseInt(index)]; - }); - - // Line breaks (after code blocks are restored) - html = html.replace(/\n\n/g, '

    '); - html = html.replace(/\n/g, '
    '); - - // Wrap in paragraph tags if not already wrapped - if (!html.startsWith('<')) { - html = '

    ' + html + '

    '; - } - - // Clean up the final HTML - // Remove
    tags immediately before block elements - html = html.replace(/\s*
    /g, '
    ');
    -    html = html.replace(/\s*
      /g, '
        '); - html = html.replace(/\s*/g, ''); - - // Remove empty paragraphs - html = html.replace(/

        \s*<\/p>/g, ''); - html = html.replace(/

        \s*\s*<\/p>/g, ''); - - // Remove excessive line breaks - html = html.replace(/(){3,}/g, '

        '); // Max 2 consecutive line breaks - html = html.replace(/(<\/p>)\s*(

        )/g, '$1$2'); // Remove whitespace between paragraphs - - // Remove leading/trailing whitespace - html = html.trim(); - - return html; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Lists.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Lists.qml deleted file mode 100644 index 57b5f2d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Lists.qml +++ /dev/null @@ -1,94 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick - -Singleton { - id: root - - function init(leftModel, centerModel, rightModel, left, center, right) { - const dummy = { - widgetId: "dummy", - enabled: true, - size: 20, - selectedGpuIndex: 0, - pciId: "", - mountPath: "/", - minimumWidth: true, - showSwap: false, - mediaSize: 1, - showNetworkIcon: true, - showBluetoothIcon: true, - showAudioIcon: true, - showAudioPercent: true, - showVpnIcon: true, - showBrightnessIcon: false, - showBrightnessPercent: false, - showMicIcon: false, - showMicPercent: true, - showBatteryIcon: false, - showPrinterIcon: false, - showScreenSharingIcon: true - }; - leftModel.append(dummy); - centerModel.append(dummy); - rightModel.append(dummy); - - update(leftModel, left); - update(centerModel, center); - update(rightModel, right); - } - - function update(model, order) { - model.clear(); - for (var i = 0; i < order.length; i++) { - var isObj = typeof order[i] !== "string"; - var widgetId = isObj ? order[i].id : order[i]; - var item = { - widgetId: widgetId, - enabled: isObj ? order[i].enabled : true - }; - if (isObj && order[i].size !== undefined) - item.size = order[i].size; - if (isObj && order[i].selectedGpuIndex !== undefined) - item.selectedGpuIndex = order[i].selectedGpuIndex; - if (isObj && order[i].pciId !== undefined) - item.pciId = order[i].pciId; - if (isObj && order[i].mountPath !== undefined) - item.mountPath = order[i].mountPath; - if (isObj && order[i].minimumWidth !== undefined) - item.minimumWidth = order[i].minimumWidth; - if (isObj && order[i].showSwap !== undefined) - item.showSwap = order[i].showSwap; - if (isObj && order[i].mediaSize !== undefined) - item.mediaSize = order[i].mediaSize; - if (isObj && order[i].showNetworkIcon !== undefined) - item.showNetworkIcon = order[i].showNetworkIcon; - if (isObj && order[i].showBluetoothIcon !== undefined) - item.showBluetoothIcon = order[i].showBluetoothIcon; - if (isObj && order[i].showAudioIcon !== undefined) - item.showAudioIcon = order[i].showAudioIcon; - if (isObj && order[i].showAudioPercent !== undefined) - item.showAudioPercent = order[i].showAudioPercent; - if (isObj && order[i].showVpnIcon !== undefined) - item.showVpnIcon = order[i].showVpnIcon; - if (isObj && order[i].showBrightnessIcon !== undefined) - item.showBrightnessIcon = order[i].showBrightnessIcon; - if (isObj && order[i].showBrightnessPercent !== undefined) - item.showBrightnessPercent = order[i].showBrightnessPercent; - if (isObj && order[i].showMicIcon !== undefined) - item.showMicIcon = order[i].showMicIcon; - if (isObj && order[i].showMicPercent !== undefined) - item.showMicPercent = order[i].showMicPercent; - if (isObj && order[i].showBatteryIcon !== undefined) - item.showBatteryIcon = order[i].showBatteryIcon; - if (isObj && order[i].showPrinterIcon !== undefined) - item.showPrinterIcon = order[i].showPrinterIcon; - if (isObj && order[i].showScreenSharingIcon !== undefined) - item.showScreenSharingIcon = order[i].showScreenSharingIcon; - - model.append(item); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Processes.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Processes.qml deleted file mode 100644 index a11abae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/Processes.qml +++ /dev/null @@ -1,602 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services - -Singleton { - id: root - - property var settingsRoot: null - - property string greetdPamText: "" - property string systemAuthPamText: "" - property string commonAuthPamText: "" - property string passwordAuthPamText: "" - property string systemLoginPamText: "" - property string systemLocalLoginPamText: "" - property string commonAuthPcPamText: "" - property string loginPamText: "" - property string dankshellU2fPamText: "" - property string u2fKeysText: "" - - property string fingerprintProbeOutput: "" - property int fingerprintProbeExitCode: 0 - property bool fingerprintProbeFinalized: false - - property string pamProbeOutput: "" - property bool pamProbeFinalized: false - - readonly property string homeDir: Quickshell.env("HOME") || "" - readonly property string u2fKeysPath: homeDir ? homeDir + "/.config/Yubico/u2f_keys" : "" - readonly property bool homeU2fKeysDetected: u2fKeysPath !== "" && u2fKeysWatcher.loaded && u2fKeysText.trim() !== "" - readonly property bool lockU2fCustomConfigDetected: pamModuleEnabled(dankshellU2fPamText, "pam_u2f") - readonly property bool greeterPamHasFprint: greeterPamStackHasModule("pam_fprintd") - readonly property bool greeterPamHasU2f: greeterPamStackHasModule("pam_u2f") - - function envFlag(name) { - const value = (Quickshell.env(name) || "").trim().toLowerCase(); - if (value === "1" || value === "true" || value === "yes" || value === "on") - return true; - if (value === "0" || value === "false" || value === "no" || value === "off") - return false; - return null; - } - - readonly property var forcedFprintAvailable: envFlag("DMS_FORCE_FPRINT_AVAILABLE") - readonly property var forcedU2fAvailable: envFlag("DMS_FORCE_U2F_AVAILABLE") - - // --- Derived auth probe state --- - - readonly property bool pamFprintSupportDetected: pamProbeFinalized && pamProbeOutput.includes("pam_fprintd.so:true") - readonly property bool pamU2fSupportDetected: pamProbeFinalized && pamProbeOutput.includes("pam_u2f.so:true") - - readonly property string fingerprintProbeState: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable ? "ready" : "probe_failed"; - if (!fingerprintProbeFinalized) - return "probe_failed"; - return parseFingerprintProbe(fingerprintProbeExitCode, fingerprintProbeOutput, pamFprintSupportDetected); - } - - // --- Lock fingerprint capabilities --- - - readonly property bool lockFingerprintCanEnable: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable; - switch (fingerprintProbeState) { - case "ready": - case "missing_enrollment": - return true; - default: - return false; - } - } - - readonly property bool lockFingerprintReady: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable; - return fingerprintProbeState === "ready"; - } - - readonly property string lockFingerprintReason: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable ? "ready" : "probe_failed"; - return fingerprintProbeState; - } - - // --- Greeter fingerprint capabilities --- - - readonly property bool greeterFingerprintCanEnable: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable; - if (greeterPamHasFprint) - return fingerprintProbeState !== "missing_reader"; - switch (fingerprintProbeState) { - case "ready": - case "missing_enrollment": - return true; - default: - return false; - } - } - - readonly property bool greeterFingerprintReady: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable; - return fingerprintProbeState === "ready"; - } - - readonly property string greeterFingerprintReason: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable ? "ready" : "probe_failed"; - if (greeterPamHasFprint) { - switch (fingerprintProbeState) { - case "ready": - return "configured_externally"; - case "missing_enrollment": - return "missing_enrollment"; - case "missing_reader": - return "missing_reader"; - default: - return "probe_failed"; - } - } - return fingerprintProbeState; - } - - readonly property string greeterFingerprintSource: { - if (forcedFprintAvailable !== null) - return forcedFprintAvailable ? "dms" : "none"; - if (greeterPamHasFprint) - return "pam"; - switch (fingerprintProbeState) { - case "ready": - case "missing_enrollment": - return "dms"; - default: - return "none"; - } - } - - // --- Lock U2F capabilities --- - - readonly property bool lockU2fReady: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable; - return lockU2fCustomConfigDetected || homeU2fKeysDetected; - } - - readonly property bool lockU2fCanEnable: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable; - return lockU2fReady || pamU2fSupportDetected; - } - - readonly property string lockU2fReason: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable ? "ready" : "probe_failed"; - if (lockU2fReady) - return "ready"; - if (lockU2fCanEnable) - return "missing_key_registration"; - return "missing_pam_support"; - } - - // --- Greeter U2F capabilities --- - - readonly property bool greeterU2fReady: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable; - if (greeterPamHasU2f) - return true; - return homeU2fKeysDetected; - } - - readonly property bool greeterU2fCanEnable: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable; - if (greeterPamHasU2f) - return true; - return greeterU2fReady || pamU2fSupportDetected; - } - - readonly property string greeterU2fReason: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable ? "ready" : "probe_failed"; - if (greeterPamHasU2f) - return "configured_externally"; - if (greeterU2fReady) - return "ready"; - if (greeterU2fCanEnable) - return "missing_key_registration"; - return "missing_pam_support"; - } - - readonly property string greeterU2fSource: { - if (forcedU2fAvailable !== null) - return forcedU2fAvailable ? "dms" : "none"; - if (greeterPamHasU2f) - return "pam"; - if (greeterU2fCanEnable) - return "dms"; - return "none"; - } - - // --- Aggregates --- - - readonly property bool fprintdAvailable: lockFingerprintReady || greeterFingerprintReady - readonly property bool u2fAvailable: lockU2fReady || greeterU2fReady - - // --- Auth detection --- - - readonly property var _fprintProbeCommand: ["sh", "-c", "if command -v fprintd-list >/dev/null 2>&1; then fprintd-list \"${USER:-$(id -un)}\" 2>&1; else printf '__missing_command__\\n'; exit 127; fi"] - readonly property var _pamProbeCommand: ["sh", "-c", "for module in pam_fprintd.so pam_u2f.so; do found=false; for dir in /usr/lib64/security /usr/lib/security /lib/security /lib/x86_64-linux-gnu/security /usr/lib/x86_64-linux-gnu/security /usr/lib/aarch64-linux-gnu/security /run/current-system/sw/lib/security; do if [ -f \"$dir/$module\" ]; then found=true; break; fi; done; printf '%s:%s\\n' \"$module\" \"$found\"; done"] - - function detectAuthCapabilities() { - if (forcedFprintAvailable === null) { - fingerprintProbeFinalized = false; - Proc.runCommand("fprint-probe", _fprintProbeCommand, (output, exitCode) => { - fingerprintProbeOutput = output || ""; - fingerprintProbeExitCode = exitCode; - fingerprintProbeFinalized = true; - }, 0); - } - - pamProbeFinalized = false; - Proc.runCommand("pam-probe", _pamProbeCommand, (output, _exitCode) => { - pamProbeOutput = output || ""; - pamProbeFinalized = true; - }, 0); - } - - function detectFprintd() { - detectAuthCapabilities(); - } - - function detectU2f() { - detectAuthCapabilities(); - } - - // --- Auth apply pipeline --- - - property bool authApplyRunning: false - property bool authApplyQueued: false - property bool authApplyRerunRequested: false - property bool authApplyTerminalFallbackFromPrecheck: false - property string authApplyStdout: "" - property string authApplyStderr: "" - property string authApplySudoProbeStderr: "" - property string authApplyTerminalFallbackStderr: "" - - function scheduleAuthApply() { - if (!settingsRoot || settingsRoot.isGreeterMode) - return; - - authApplyQueued = true; - if (authApplyRunning) { - authApplyRerunRequested = true; - return; - } - - authApplyDebounce.restart(); - } - - function beginAuthApply() { - if (!authApplyQueued || authApplyRunning || !settingsRoot || settingsRoot.isGreeterMode) - return; - - authApplyQueued = false; - authApplyRerunRequested = false; - authApplyStdout = ""; - authApplyStderr = ""; - authApplySudoProbeStderr = ""; - authApplyTerminalFallbackStderr = ""; - authApplyTerminalFallbackFromPrecheck = false; - authApplyRunning = true; - authApplySudoProbeProcess.running = true; - } - - function launchAuthApplyTerminalFallback(fromPrecheck, details) { - authApplyTerminalFallbackFromPrecheck = fromPrecheck; - if (details && details !== "") - ToastService.showInfo(I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync"); - authApplyTerminalFallbackStderr = ""; - authApplyTerminalFallbackProcess.running = true; - } - - function finishAuthApply() { - const shouldRerun = authApplyQueued || authApplyRerunRequested; - authApplyRunning = false; - authApplyRerunRequested = false; - if (shouldRerun) - authApplyDebounce.restart(); - } - - // --- PAM parsing helpers --- - - function stripPamComment(line) { - if (!line) - return ""; - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) - return ""; - const hashIdx = trimmed.indexOf("#"); - if (hashIdx >= 0) - return trimmed.substring(0, hashIdx).trim(); - return trimmed; - } - - function pamModuleEnabled(pamText, moduleName) { - if (!pamText || !moduleName) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(moduleName)) - return true; - } - return false; - } - - function pamTextIncludesFile(pamText, filename) { - if (!pamText || !filename) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(filename) && (line.includes("include") || line.includes("substack") || line.startsWith("@include"))) - return true; - } - return false; - } - - function greeterPamStackHasModule(moduleName) { - if (pamModuleEnabled(greetdPamText, moduleName)) - return true; - const includedPamStacks = [["system-auth", systemAuthPamText], ["common-auth", commonAuthPamText], ["password-auth", passwordAuthPamText], ["system-login", systemLoginPamText], ["system-local-login", systemLocalLoginPamText], ["common-auth-pc", commonAuthPcPamText], ["login", loginPamText]]; - for (let i = 0; i < includedPamStacks.length; i++) { - const stack = includedPamStacks[i]; - if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName)) - return true; - } - return false; - } - - // --- Fingerprint probe output parsing --- - - function hasEnrolledFingerprintOutput(output) { - const lower = (output || "").toLowerCase(); - if (lower.includes("has fingers enrolled") || lower.includes("has fingerprints enrolled")) - return true; - const lines = lower.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const trimmed = lines[i].trim(); - if (trimmed.startsWith("finger:")) - return true; - if (trimmed.startsWith("- ") && trimmed.includes("finger")) - return true; - } - return false; - } - - function hasMissingFingerprintEnrollmentOutput(output) { - const lower = (output || "").toLowerCase(); - return lower.includes("no fingers enrolled") || lower.includes("no fingerprints enrolled") || lower.includes("no prints enrolled"); - } - - function hasMissingFingerprintReaderOutput(output) { - const lower = (output || "").toLowerCase(); - return lower.includes("no devices available") || lower.includes("no device available") || lower.includes("no devices found") || lower.includes("list_devices failed") || lower.includes("no device"); - } - - function parseFingerprintProbe(exitCode, output, pamFprintDetected) { - if (hasEnrolledFingerprintOutput(output)) - return "ready"; - if (hasMissingFingerprintEnrollmentOutput(output)) - return "missing_enrollment"; - if (hasMissingFingerprintReaderOutput(output)) - return "missing_reader"; - if (exitCode === 0) - return "missing_enrollment"; - if (exitCode === 127 || (output || "").includes("__missing_command__")) - return "probe_failed"; - return pamFprintDetected ? "probe_failed" : "missing_pam_support"; - } - - // --- Qt tools detection --- - - function detectQtTools() { - qtToolsDetectionProcess.running = true; - } - - function checkPluginSettings() { - pluginSettingsCheckProcess.running = true; - } - - property var qtToolsDetectionProcess: Process { - command: ["sh", "-c", "echo -n 'qt5ct:'; command -v qt5ct >/dev/null && echo 'true' || echo 'false'; echo -n 'qt6ct:'; command -v qt6ct >/dev/null && echo 'true' || echo 'false'; echo -n 'gtk:'; (command -v gsettings >/dev/null || command -v dconf >/dev/null) && echo 'true' || echo 'false'"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (!settingsRoot) - return; - if (text && text.trim()) { - const lines = text.trim().split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.startsWith("qt5ct:")) { - settingsRoot.qt5ctAvailable = line.split(":")[1] === "true"; - } else if (line.startsWith("qt6ct:")) { - settingsRoot.qt6ctAvailable = line.split(":")[1] === "true"; - } else if (line.startsWith("gtk:")) { - settingsRoot.gtkAvailable = line.split(":")[1] === "true"; - } - } - } - } - } - } - - Timer { - id: authApplyDebounce - interval: 300 - repeat: false - onTriggered: root.beginAuthApply() - } - - property var authApplyProcess: Process { - command: ["dms", "auth", "sync", "--yes"] - running: false - - stdout: StdioCollector { - onStreamFinished: root.authApplyStdout = text || "" - } - - stderr: StdioCollector { - onStreamFinished: root.authApplyStderr = text || "" - } - - onExited: exitCode => { - const out = (root.authApplyStdout || "").trim(); - const err = (root.authApplyStderr || "").trim(); - - if (exitCode === 0) { - let details = out; - if (err !== "") - details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err; - ToastService.showInfo(I18n.tr("Authentication changes applied."), details, "", "auth-sync"); - root.detectAuthCapabilities(); - root.finishAuthApply(); - return; - } - - let details = ""; - if (out !== "") - details = out; - if (err !== "") - details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err; - ToastService.showWarning(I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync"); - root.launchAuthApplyTerminalFallback(false, ""); - } - } - - property var authApplySudoProbeProcess: Process { - command: ["sudo", "-n", "true"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.authApplySudoProbeStderr = text || "" - } - - onExited: exitCode => { - const err = (root.authApplySudoProbeStderr || "").trim(); - if (exitCode === 0) { - ToastService.showInfo(I18n.tr("Applying authentication changes…"), "", "", "auth-sync"); - root.authApplyProcess.running = true; - return; - } - - root.launchAuthApplyTerminalFallback(true, err); - } - } - - property var authApplyTerminalFallbackProcess: Process { - command: ["dms", "auth", "sync", "--terminal", "--yes"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.authApplyTerminalFallbackStderr = text || "" - } - - onExited: exitCode => { - if (exitCode === 0) { - const message = root.authApplyTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication setup there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication setup there; it will close automatically when done."); - ToastService.showInfo(message, "", "", "auth-sync"); - } else { - let details = (root.authApplyTerminalFallbackStderr || "").trim(); - ToastService.showError(I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync"); - } - root.finishAuthApply(); - } - } - - FileView { - id: greetdPamWatcher - path: "/etc/pam.d/greetd" - printErrors: false - onLoaded: root.greetdPamText = text() - onLoadFailed: root.greetdPamText = "" - } - - FileView { - id: systemAuthPamWatcher - path: "/etc/pam.d/system-auth" - printErrors: false - onLoaded: root.systemAuthPamText = text() - onLoadFailed: root.systemAuthPamText = "" - } - - FileView { - id: commonAuthPamWatcher - path: "/etc/pam.d/common-auth" - printErrors: false - onLoaded: root.commonAuthPamText = text() - onLoadFailed: root.commonAuthPamText = "" - } - - FileView { - id: passwordAuthPamWatcher - path: "/etc/pam.d/password-auth" - printErrors: false - onLoaded: root.passwordAuthPamText = text() - onLoadFailed: root.passwordAuthPamText = "" - } - - FileView { - id: systemLoginPamWatcher - path: "/etc/pam.d/system-login" - printErrors: false - onLoaded: root.systemLoginPamText = text() - onLoadFailed: root.systemLoginPamText = "" - } - - FileView { - id: systemLocalLoginPamWatcher - path: "/etc/pam.d/system-local-login" - printErrors: false - onLoaded: root.systemLocalLoginPamText = text() - onLoadFailed: root.systemLocalLoginPamText = "" - } - - FileView { - id: commonAuthPcPamWatcher - path: "/etc/pam.d/common-auth-pc" - printErrors: false - onLoaded: root.commonAuthPcPamText = text() - onLoadFailed: root.commonAuthPcPamText = "" - } - - FileView { - id: loginPamWatcher - path: "/etc/pam.d/login" - printErrors: false - onLoaded: root.loginPamText = text() - onLoadFailed: root.loginPamText = "" - } - - FileView { - id: dankshellU2fPamWatcher - path: "/etc/pam.d/dankshell-u2f" - printErrors: false - onLoaded: root.dankshellU2fPamText = text() - onLoadFailed: root.dankshellU2fPamText = "" - } - - FileView { - id: u2fKeysWatcher - path: root.u2fKeysPath - printErrors: false - onLoaded: root.u2fKeysText = text() - onLoadFailed: root.u2fKeysText = "" - } - - property var pluginSettingsCheckProcess: Process { - command: ["test", "-f", settingsRoot?.pluginSettingsPath || ""] - running: false - - onExited: function (exitCode) { - if (!settingsRoot) - return; - settingsRoot.pluginSettingsFileExists = (exitCode === 0); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionSpec.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionSpec.js deleted file mode 100644 index e2bb4fe..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionSpec.js +++ /dev/null @@ -1,109 +0,0 @@ -.pragma library - -var SPEC = { - isLightMode: { def: false }, - doNotDisturb: { def: false }, - - wallpaperPath: { def: "" }, - perMonitorWallpaper: { def: false }, - monitorWallpapers: { def: {} }, - perModeWallpaper: { def: false }, - wallpaperPathLight: { def: "" }, - wallpaperPathDark: { def: "" }, - monitorWallpapersLight: { def: {} }, - monitorWallpapersDark: { def: {} }, - monitorWallpaperFillModes: { def: {} }, - wallpaperTransition: { def: "fade" }, - includedTransitions: { def: ["fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] }, - - wallpaperCyclingEnabled: { def: false }, - wallpaperCyclingMode: { def: "interval" }, - wallpaperCyclingInterval: { def: 300 }, - wallpaperCyclingTime: { def: "06:00" }, - monitorCyclingSettings: { def: {} }, - - nightModeEnabled: { def: false }, - nightModeTemperature: { def: 4500 }, - nightModeHighTemperature: { def: 6500 }, - nightModeAutoEnabled: { def: false }, - nightModeAutoMode: { def: "time" }, - nightModeStartHour: { def: 18 }, - nightModeStartMinute: { def: 0 }, - nightModeEndHour: { def: 6 }, - nightModeEndMinute: { def: 0 }, - latitude: { def: 0.0 }, - longitude: { def: 0.0 }, - nightModeUseIPLocation: { def: false }, - nightModeLocationProvider: { def: "" }, - - themeModeAutoEnabled: { def: false }, - themeModeAutoMode: { def: "time" }, - themeModeStartHour: { def: 18 }, - themeModeStartMinute: { def: 0 }, - themeModeEndHour: { def: 6 }, - themeModeEndMinute: { def: 0 }, - themeModeShareGammaSettings: { def: true }, - - weatherLocation: { def: "New York, NY" }, - weatherCoordinates: { def: "40.7128,-74.0060" }, - - pinnedApps: { def: [] }, - barPinnedApps: { def: [] }, - dockLauncherPosition: { def: 0 }, - hiddenTrayIds: { def: [] }, - trayItemOrder: { def: [] }, - recentColors: { def: [] }, - showThirdPartyPlugins: { def: false }, - launchPrefix: { def: "" }, - lastBrightnessDevice: { def: "" }, - - brightnessExponentialDevices: { def: {} }, - brightnessUserSetValues: { def: {} }, - brightnessExponentValues: { def: {} }, - - selectedGpuIndex: { def: 0 }, - nvidiaGpuTempEnabled: { def: false }, - nonNvidiaGpuTempEnabled: { def: false }, - enabledGpuPciIds: { def: [] }, - - wifiDeviceOverride: { def: "" }, - weatherHourlyDetailed: { def: true }, - - hiddenApps: { def: [] }, - appOverrides: { def: {} }, - searchAppActions: { def: true }, - - vpnLastConnected: { def: "" }, - - lastPlayerIdentity: { def: "" }, - - deviceMaxVolumes: { def: {} }, - hiddenOutputDeviceNames: { def: [] }, - hiddenInputDeviceNames: { def: [] }, - - locale: { def: "", onChange: "updateLocale" }, - timeLocale: { def: "" }, - - launcherLastMode: { def: "all" }, - launcherLastQuery: { def: "" }, - launcherQueryHistory: { def: [] }, - appDrawerLastMode: { def: "apps" }, - niriOverviewLastMode: { def: "apps" }, - - settingsSidebarExpandedIds: { def: "," }, - settingsSidebarCollapsedIds: { def: "," } -}; - -function getValidKeys() { - return Object.keys(SPEC).concat(["configVersion"]); -} - -function set(root, key, value, saveFn, hooks) { - if (!(key in SPEC)) return; - root[key] = value; - var hookName = SPEC[key].onChange; - if (hookName && hooks && hooks[hookName]) { - hooks[hookName](root); - } - saveFn(); -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionStore.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionStore.js deleted file mode 100644 index c1e2190..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SessionStore.js +++ /dev/null @@ -1,100 +0,0 @@ -.pragma library - - .import "./SessionSpec.js" as SpecModule - -function parse(root, jsonObj) { - var SPEC = SpecModule.SPEC; - - if (!jsonObj) return; - - for (var k in SPEC) { - if (!(k in jsonObj)) { - root[k] = SPEC[k].def; - } - } - - for (var k in jsonObj) { - if (!SPEC[k]) continue; - var raw = jsonObj[k]; - var spec = SPEC[k]; - var coerce = spec.coerce; - root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw; - } -} - -function toJson(root) { - var SPEC = SpecModule.SPEC; - var out = {}; - for (var k in SPEC) { - if (SPEC[k].persist === false) continue; - out[k] = root[k]; - } - out.configVersion = root.sessionConfigVersion; - return out; -} - -function migrateToVersion(obj, targetVersion, settingsData) { - if (!obj) return null; - - var session = JSON.parse(JSON.stringify(obj)); - var currentVersion = session.configVersion || 0; - - if (currentVersion >= targetVersion) { - return null; - } - - if (currentVersion < 2) { - console.info("SessionData: Migrating session from version", currentVersion, "to version 2"); - console.info("SessionData: Importing weather location and coordinates from settings"); - - if (settingsData && typeof settingsData !== "undefined") { - if (session.weatherLocation === undefined || session.weatherLocation === "New York, NY") { - var settingsWeatherLocation = settingsData._legacyWeatherLocation; - if (settingsWeatherLocation && settingsWeatherLocation !== "New York, NY") { - session.weatherLocation = settingsWeatherLocation; - console.info("SessionData: Migrated weatherLocation:", settingsWeatherLocation); - } - } - - if (session.weatherCoordinates === undefined || session.weatherCoordinates === "40.7128,-74.0060") { - var settingsWeatherCoordinates = settingsData._legacyWeatherCoordinates; - if (settingsWeatherCoordinates && settingsWeatherCoordinates !== "40.7128,-74.0060") { - session.weatherCoordinates = settingsWeatherCoordinates; - console.info("SessionData: Migrated weatherCoordinates:", settingsWeatherCoordinates); - } - } - } - - session.configVersion = 2; - } - - if (currentVersion < 3) { - console.info("SessionData: Migrating session to version 3"); - session.configVersion = 3; - } - - return session; -} - -function cleanup(fileText) { - var getValidKeys = SpecModule.getValidKeys; - if (!fileText || !fileText.trim()) return null; - - try { - var session = JSON.parse(fileText); - var validKeys = getValidKeys(); - var needsSave = false; - - for (var key in session) { - if (validKeys.indexOf(key) < 0) { - delete session[key]; - needsSave = true; - } - } - - return needsSave ? JSON.stringify(session, null, 2) : null; - } catch (e) { - console.warn("SessionData: Failed to cleanup unused keys:", e.message); - return null; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsSpec.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsSpec.js deleted file mode 100644 index 056545e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsSpec.js +++ /dev/null @@ -1,553 +0,0 @@ -.pragma library - -function percentToUnit(v) { - if (v === undefined || v === null) return undefined; - return v > 1 ? v / 100 : v; -} - -var SPEC = { - currentThemeName: { def: "raveos", onChange: "applyStoredTheme" }, - currentThemeCategory: { def: "generic" }, - customThemeFile: { def: "" }, - registryThemeVariants: { def: {} }, - matugenScheme: { def: "scheme-tonal-spot", onChange: "regenSystemThemes" }, - matugenContrast: { def: 0, onChange: "regenSystemThemes" }, - runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" }, - matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" }, - - popupTransparency: { def: 1.0, coerce: percentToUnit }, - dockTransparency: { def: 1.0, coerce: percentToUnit }, - - widgetBackgroundColor: { def: "sch" }, - widgetColorMode: { def: "default" }, - controlCenterTileColorMode: { def: "primary" }, - buttonColorMode: { def: "primary" }, - cornerRadius: { def: 16, onChange: "updateCompositorLayout" }, - niriLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" }, - niriLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" }, - niriLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" }, - hyprlandLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" }, - hyprlandLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" }, - hyprlandLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" }, - mangoLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" }, - mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" }, - mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" }, - - firstDayOfWeek: { def: -1 }, - showWeekNumber: { def: false }, - use24HourClock: { def: true }, - showSeconds: { def: false }, - padHours12Hour: { def: false }, - useFahrenheit: { def: false }, - windSpeedUnit: { def: "kmh" }, - nightModeEnabled: { def: false }, - animationSpeed: { def: 1 }, - customAnimationDuration: { def: 500 }, - syncComponentAnimationSpeeds: { def: true }, - popoutAnimationSpeed: { def: 1 }, - popoutCustomAnimationDuration: { def: 150 }, - modalAnimationSpeed: { def: 1 }, - modalCustomAnimationDuration: { def: 150 }, - enableRippleEffects: { def: true }, - m3ElevationEnabled: { def: true }, - m3ElevationIntensity: { def: 12 }, - m3ElevationOpacity: { def: 30 }, - m3ElevationColorMode: { def: "default" }, - m3ElevationLightDirection: { def: "top" }, - m3ElevationCustomColor: { def: "#000000" }, - modalElevationEnabled: { def: true }, - popoutElevationEnabled: { def: true }, - barElevationEnabled: { def: true }, - blurEnabled: { def: false }, - blurBorderColor: { def: "outline" }, - blurBorderCustomColor: { def: "#ffffff" }, - blurBorderOpacity: { def: 1.0, coerce: percentToUnit }, - wallpaperFillMode: { def: "Fill" }, - blurredWallpaperLayer: { def: false }, - blurWallpaperOnOverview: { def: false }, - - showLauncherButton: { def: true }, - showWorkspaceSwitcher: { def: true }, - showFocusedWindow: { def: true }, - showWeather: { def: true }, - showMusic: { def: true }, - showClipboard: { def: true }, - showCpuUsage: { def: true }, - showMemUsage: { def: true }, - showCpuTemp: { def: true }, - showGpuTemp: { def: true }, - selectedGpuIndex: { def: 0 }, - enabledGpuPciIds: { def: [] }, - showSystemTray: { def: true }, - showClock: { def: true }, - showNotificationButton: { def: true }, - showBattery: { def: true }, - showControlCenterButton: { def: true }, - showCapsLockIndicator: { def: true }, - - controlCenterShowNetworkIcon: { def: true }, - controlCenterShowBluetoothIcon: { def: true }, - controlCenterShowAudioIcon: { def: true }, - controlCenterShowAudioPercent: { def: false }, - controlCenterShowVpnIcon: { def: true }, - controlCenterShowBrightnessIcon: { def: false }, - controlCenterShowBrightnessPercent: { def: false }, - controlCenterShowMicIcon: { def: false }, - controlCenterShowMicPercent: { def: false }, - controlCenterShowBatteryIcon: { def: false }, - controlCenterShowPrinterIcon: { def: false }, - controlCenterShowScreenSharingIcon: { def: true }, - - showPrivacyButton: { def: true }, - privacyShowMicIcon: { def: false }, - privacyShowCameraIcon: { def: false }, - privacyShowScreenShareIcon: { def: false }, - - controlCenterWidgets: { - def: [ - { id: "volumeSlider", enabled: true, width: 50 }, - { id: "brightnessSlider", enabled: true, width: 50 }, - { id: "wifi", enabled: true, width: 50 }, - { id: "bluetooth", enabled: true, width: 50 }, - { id: "audioOutput", enabled: true, width: 50 }, - { id: "audioInput", enabled: true, width: 50 }, - { id: "nightMode", enabled: true, width: 50 }, - { id: "darkMode", enabled: true, width: 50 } - ] - }, - - showWorkspaceIndex: { def: false }, - showWorkspaceName: { def: false }, - showWorkspacePadding: { def: false }, - workspaceScrolling: { def: false }, - showWorkspaceApps: { def: false }, - workspaceDragReorder: { def: true }, - maxWorkspaceIcons: { def: 3 }, - workspaceAppIconSizeOffset: { def: 0 }, - groupWorkspaceApps: { def: true }, - workspaceFollowFocus: { def: false }, - showOccupiedWorkspacesOnly: { def: false }, - reverseScrolling: { def: false }, - dwlShowAllTags: { def: false }, - workspaceActiveAppHighlightEnabled: { def: false }, - workspaceColorMode: { def: "default" }, - workspaceOccupiedColorMode: { def: "none" }, - workspaceUnfocusedColorMode: { def: "default" }, - workspaceUrgentColorMode: { def: "default" }, - workspaceFocusedBorderEnabled: { def: false }, - workspaceFocusedBorderColor: { def: "primary" }, - workspaceFocusedBorderThickness: { def: 2 }, - workspaceNameIcons: { def: {} }, - waveProgressEnabled: { def: true }, - scrollTitleEnabled: { def: true }, - mediaAdaptiveWidthEnabled: { def: true }, - audioVisualizerEnabled: { def: true }, - audioScrollMode: { def: "volume" }, - audioWheelScrollAmount: { def: 5 }, - clockCompactMode: { def: false }, - focusedWindowCompactMode: { def: false }, - runningAppsCompactMode: { def: true }, - barMaxVisibleApps: { def: 0 }, - barMaxVisibleRunningApps: { def: 0 }, - barShowOverflowBadge: { def: true }, - appsDockHideIndicators: { def: false }, - appsDockColorizeActive: { def: false }, - appsDockActiveColorMode: { def: "primary" }, - appsDockEnlargeOnHover: { def: false }, - appsDockEnlargePercentage: { def: 125 }, - appsDockIconSizePercentage: { def: 100 }, - keyboardLayoutNameCompactMode: { def: false }, - runningAppsCurrentWorkspace: { def: true }, - runningAppsGroupByApp: { def: false }, - runningAppsCurrentMonitor: { def: false }, - appIdSubstitutions: { - def: [ - { pattern: "Spotify", replacement: "spotify", type: "exact" }, - { pattern: "beepertexts", replacement: "beeper", type: "exact" }, - { pattern: "home assistant desktop", replacement: "homeassistant-desktop", type: "exact" }, - { pattern: "com.transmissionbt.transmission", replacement: "transmission-gtk", type: "contains" }, - { pattern: "^steam_app_(\\d+)$", replacement: "steam_icon_$1", type: "regex" } - ] - }, - centeringMode: { def: "index" }, - clockDateFormat: { def: "" }, - lockDateFormat: { def: "" }, - greeterRememberLastSession: { def: true }, - greeterRememberLastUser: { def: true }, - greeterEnableFprint: { def: false, onChange: "scheduleAuthApply" }, - greeterEnableU2f: { def: false, onChange: "scheduleAuthApply" }, - greeterWallpaperPath: { def: "" }, - greeterUse24HourClock: { def: true }, - greeterShowSeconds: { def: false }, - greeterPadHours12Hour: { def: false }, - greeterLockDateFormat: { def: "" }, - greeterFontFamily: { def: "" }, - greeterWallpaperFillMode: { def: "" }, - mediaSize: { def: 1 }, - - appLauncherViewMode: { def: "list" }, - spotlightModalViewMode: { def: "list" }, - browserPickerViewMode: { def: "grid" }, - browserUsageHistory: { def: {} }, - appPickerViewMode: { def: "grid" }, - filePickerUsageHistory: { def: {} }, - sortAppsAlphabetically: { def: false }, - appLauncherGridColumns: { def: 4 }, - spotlightCloseNiriOverview: { def: true }, - rememberLastQuery: { def: false }, - spotlightSectionViewModes: { def: {} }, - appDrawerSectionViewModes: { def: {} }, - niriOverviewOverlayEnabled: { def: true }, - dankLauncherV2Size: { def: "compact" }, - dankLauncherV2BorderEnabled: { def: false }, - dankLauncherV2BorderThickness: { def: 2 }, - dankLauncherV2BorderColor: { def: "primary" }, - dankLauncherV2ShowFooter: { def: true }, - dankLauncherV2UnloadOnClose: { def: false }, - dankLauncherV2IncludeFilesInAll: { def: false }, - dankLauncherV2IncludeFoldersInAll: { def: false }, - - useAutoLocation: { def: false }, - weatherEnabled: { def: true }, - - networkPreference: { def: "auto" }, - - iconTheme: { def: "System Default", onChange: "applyStoredIconTheme" }, - availableIconThemes: { def: ["System Default"], persist: false }, - systemDefaultIconTheme: { def: "", persist: false }, - qt5ctAvailable: { def: false, persist: false }, - qt6ctAvailable: { def: false, persist: false }, - gtkAvailable: { def: false, persist: false }, - - cursorSettings: { def: { theme: "System Default", size: 24, niri: { hideWhenTyping: false, hideAfterInactiveMs: 0 }, hyprland: { hideOnKeyPress: false, hideOnTouch: false, inactiveTimeout: 0 }, dwl: { cursorHideTimeout: 0 } }, onChange: "updateCompositorCursor" }, - availableCursorThemes: { def: ["System Default"], persist: false }, - systemDefaultCursorTheme: { def: "", persist: false }, - - launcherLogoMode: { def: "os" }, - launcherLogoCustomPath: { def: "" }, - launcherLogoColorOverride: { def: "" }, - launcherLogoColorInvertOnMode: { def: false }, - launcherLogoBrightness: { def: 0.5 }, - launcherLogoContrast: { def: 1 }, - launcherLogoSizeOffset: { def: 0 }, - - fontFamily: { def: "Inter Variable" }, - monoFontFamily: { def: "Fira Code" }, - fontWeight: { def: 400 }, - fontScale: { def: 1.0 }, - - notepadUseMonospace: { def: true }, - notepadFontFamily: { def: "" }, - notepadFontSize: { def: 14 }, - notepadShowLineNumbers: { def: false }, - notepadTransparencyOverride: { def: -1 }, - notepadLastCustomTransparency: { def: 0.7 }, - - soundsEnabled: { def: true }, - useSystemSoundTheme: { def: false }, - soundLogin: { def: false }, - soundNewNotification: { def: true }, - soundVolumeChanged: { def: true }, - soundPluggedIn: { def: true }, - - acMonitorTimeout: { def: 0 }, - acLockTimeout: { def: 0 }, - acSuspendTimeout: { def: 0 }, - acSuspendBehavior: { def: 0 }, - acProfileName: { def: "" }, - batteryMonitorTimeout: { def: 0 }, - batteryLockTimeout: { def: 0 }, - batterySuspendTimeout: { def: 0 }, - batterySuspendBehavior: { def: 0 }, - batteryProfileName: { def: "" }, - batteryChargeLimit: { def: 100 }, - lockBeforeSuspend: { def: false }, - loginctlLockIntegration: { def: true }, - fadeToLockEnabled: { def: true }, - fadeToLockGracePeriod: { def: 5 }, - fadeToDpmsEnabled: { def: true }, - fadeToDpmsGracePeriod: { def: 5 }, - launchPrefix: { def: "" }, - brightnessDevicePins: { def: {} }, - wifiNetworkPins: { def: {} }, - bluetoothDevicePins: { def: {} }, - audioInputDevicePins: { def: {} }, - audioOutputDevicePins: { def: {} }, - - gtkThemingEnabled: { def: false, onChange: "regenSystemThemes" }, - qtThemingEnabled: { def: false, onChange: "regenSystemThemes" }, - syncModeWithPortal: { def: true }, - terminalsAlwaysDark: { def: false, onChange: "regenSystemThemes" }, - - muxType: { def: "tmux" }, - muxUseCustomCommand: { def: false }, - muxCustomCommand: { def: "" }, - muxSessionFilter: { def: "" }, - - runDmsMatugenTemplates: { def: true }, - matugenTemplateGtk: { def: true }, - matugenTemplateNiri: { def: true }, - matugenTemplateHyprland: { def: true }, - matugenTemplateMangowc: { def: true }, - matugenTemplateQt5ct: { def: true }, - matugenTemplateQt6ct: { def: true }, - matugenTemplateFirefox: { def: true }, - matugenTemplatePywalfox: { def: true }, - matugenTemplateZenBrowser: { def: true }, - matugenTemplateVesktop: { def: true }, - matugenTemplateEquibop: { def: true }, - matugenTemplateGhostty: { def: true }, - matugenTemplateKitty: { def: true }, - matugenTemplateFoot: { def: true }, - matugenTemplateAlacritty: { def: true }, - matugenTemplateNeovim: { def: false }, - matugenTemplateWezterm: { def: true }, - matugenTemplateDgop: { def: true }, - matugenTemplateKcolorscheme: { def: true }, - matugenTemplateVscode: { def: true }, - matugenTemplateEmacs: { def: true }, - matugenTemplateZed: { def: true }, - - matugenTemplateNeovimSettings: { - def: { - dark: { baseTheme: "github_dark", harmony: 0.5 }, - light: { baseTheme: "github_light", harmony: 0.5 } - } - }, - matugenTemplateNeovimSetBackground: { def: true }, - - showDock: { def: false }, - dockAutoHide: { def: false }, - dockSmartAutoHide: { def: false }, - dockGroupByApp: { def: false }, - dockRestoreSpecialWorkspaceOnClick: { def: false }, - dockOpenOnOverview: { def: false }, - dockPosition: { def: 1 }, - dockSpacing: { def: 4 }, - dockBottomGap: { def: 0 }, - dockMargin: { def: 0 }, - dockIconSize: { def: 40 }, - dockIndicatorStyle: { def: "circle" }, - dockBorderEnabled: { def: false }, - dockBorderColor: { def: "surfaceText" }, - dockBorderOpacity: { def: 1.0, coerce: percentToUnit }, - dockBorderThickness: { def: 1 }, - dockIsolateDisplays: { def: false }, - dockLauncherEnabled: { def: false }, - dockLauncherLogoMode: { def: "apps" }, - dockLauncherLogoCustomPath: { def: "" }, - dockLauncherLogoColorOverride: { def: "" }, - dockLauncherLogoSizeOffset: { def: 0 }, - dockLauncherLogoBrightness: { def: 0.5, coerce: percentToUnit }, - dockLauncherLogoContrast: { def: 1, coerce: percentToUnit }, - dockMaxVisibleApps: { def: 0 }, - dockMaxVisibleRunningApps: { def: 0 }, - dockShowOverflowBadge: { def: true }, - - notificationOverlayEnabled: { def: false }, - notificationPopupShadowEnabled: { def: true }, - notificationPopupPrivacyMode: { def: false }, - overviewRows: { def: 2, persist: false }, - overviewColumns: { def: 5, persist: false }, - overviewScale: { def: 0.16, persist: false }, - - modalDarkenBackground: { def: true }, - - lockScreenShowPowerActions: { def: true }, - lockScreenShowSystemIcons: { def: true }, - lockScreenShowTime: { def: true }, - lockScreenShowDate: { def: true }, - lockScreenShowProfileImage: { def: true }, - lockScreenShowPasswordField: { def: true }, - lockScreenShowMediaPlayer: { def: true }, - lockScreenPowerOffMonitorsOnLock: { def: false }, - lockAtStartup: { def: false }, - enableFprint: { def: false, onChange: "scheduleAuthApply" }, - maxFprintTries: { def: 15 }, - enableU2f: { def: false, onChange: "scheduleAuthApply" }, - u2fMode: { def: "or" }, - lockScreenActiveMonitor: { def: "all" }, - lockScreenInactiveColor: { def: "#000000" }, - lockScreenNotificationMode: { def: 0 }, - lockScreenVideoEnabled: { def: false }, - lockScreenVideoPath: { def: "" }, - lockScreenVideoCycling: { def: false }, - hideBrightnessSlider: { def: false }, - - notificationTimeoutLow: { def: 5000 }, - notificationTimeoutNormal: { def: 5000 }, - notificationTimeoutCritical: { def: 0 }, - notificationCompactMode: { def: false }, - notificationPopupPosition: { def: 0 }, - notificationAnimationSpeed: { def: 1 }, - notificationCustomAnimationDuration: { def: 400 }, - notificationHistoryEnabled: { def: true }, - notificationHistoryMaxCount: { def: 50 }, - notificationHistoryMaxAgeDays: { def: 7 }, - notificationHistorySaveLow: { def: true }, - notificationHistorySaveNormal: { def: true }, - notificationHistorySaveCritical: { def: true }, - notificationRules: { def: [] }, - notificationFocusedMonitor: { def: false }, - - osdAlwaysShowValue: { def: false }, - osdPosition: { def: 5 }, - osdVolumeEnabled: { def: true }, - osdMediaVolumeEnabled: { def: true }, - osdMediaPlaybackEnabled: { def: false }, - osdBrightnessEnabled: { def: true }, - osdIdleInhibitorEnabled: { def: true }, - osdMicMuteEnabled: { def: true }, - osdCapsLockEnabled: { def: true }, - osdPowerProfileEnabled: { def: false }, - osdAudioOutputEnabled: { def: true }, - - powerActionConfirm: { def: true }, - powerActionHoldDuration: { def: 0.5 }, - powerMenuActions: { def: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] }, - powerMenuDefaultAction: { def: "logout" }, - powerMenuGridLayout: { def: false }, - customPowerActionLock: { def: "" }, - customPowerActionLogout: { def: "" }, - customPowerActionSuspend: { def: "" }, - customPowerActionHibernate: { def: "" }, - customPowerActionReboot: { def: "" }, - customPowerActionPowerOff: { def: "" }, - - updaterHideWidget: { def: false }, - updaterUseCustomCommand: { def: false }, - updaterCustomCommand: { def: "" }, - updaterTerminalAdditionalParams: { def: "" }, - - displayNameMode: { def: "system" }, - screenPreferences: { def: {} }, - showOnLastDisplay: { def: {} }, - niriOutputSettings: { def: {} }, - hyprlandOutputSettings: { def: {} }, - displayProfiles: { def: {} }, - activeDisplayProfile: { def: {} }, - displayProfileAutoSelect: { def: false }, - displayShowDisconnected: { def: false }, - displaySnapToEdge: { def: true }, - - barConfigs: { - def: [{ - id: "default", - name: "Main Bar", - enabled: true, - position: 0, - screenPreferences: ["all"], - showOnLastDisplay: true, - leftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"], - centerWidgets: ["music", "clock", "weather"], - rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], - spacing: 4, - innerPadding: 4, - bottomGap: 0, - transparency: 1.0, - widgetTransparency: 1.0, - squareCorners: false, - noBackground: false, - maximizeWidgetIcons: false, - maximizeWidgetText: false, - removeWidgetPadding: false, - widgetPadding: 8, - gothCornersEnabled: false, - gothCornerRadiusOverride: false, - gothCornerRadiusValue: 12, - borderEnabled: false, - borderColor: "surfaceText", - borderOpacity: 1.0, - borderThickness: 1, - widgetOutlineEnabled: false, - widgetOutlineColor: "primary", - widgetOutlineOpacity: 1.0, - widgetOutlineThickness: 1, - fontScale: 1.0, - iconScale: 1.0, - autoHide: false, - autoHideDelay: 250, - showOnWindowsOpen: false, - openOnOverview: false, - visible: true, - popupGapsAuto: true, - popupGapsManual: 4, - maximizeDetection: true, - scrollEnabled: true, - scrollXBehavior: "column", - scrollYBehavior: "workspace", - shadowIntensity: 0, - shadowOpacity: 60, - shadowColorMode: "default", - shadowCustomColor: "#000000", - clickThrough: false - }], onChange: "updateBarConfigs" - }, - - desktopClockEnabled: { def: false }, - desktopClockStyle: { def: "analog" }, - desktopClockTransparency: { def: 0.8, coerce: percentToUnit }, - desktopClockColorMode: { def: "primary" }, - desktopClockCustomColor: { def: "#ffffff" }, - desktopClockShowDate: { def: true }, - desktopClockShowAnalogNumbers: { def: false }, - desktopClockShowAnalogSeconds: { def: true }, - desktopClockX: { def: -1 }, - desktopClockY: { def: -1 }, - desktopClockWidth: { def: 280 }, - desktopClockHeight: { def: 180 }, - desktopClockDisplayPreferences: { def: ["all"] }, - - systemMonitorEnabled: { def: false }, - systemMonitorShowHeader: { def: true }, - systemMonitorTransparency: { def: 0.8, coerce: percentToUnit }, - systemMonitorColorMode: { def: "primary" }, - systemMonitorCustomColor: { def: "#ffffff" }, - systemMonitorShowCpu: { def: true }, - systemMonitorShowCpuGraph: { def: true }, - systemMonitorShowCpuTemp: { def: true }, - systemMonitorShowGpuTemp: { def: false }, - systemMonitorGpuPciId: { def: "" }, - systemMonitorShowMemory: { def: true }, - systemMonitorShowMemoryGraph: { def: true }, - systemMonitorShowNetwork: { def: true }, - systemMonitorShowNetworkGraph: { def: true }, - systemMonitorShowDisk: { def: true }, - systemMonitorShowTopProcesses: { def: false }, - systemMonitorTopProcessCount: { def: 3 }, - systemMonitorTopProcessSortBy: { def: "cpu" }, - systemMonitorGraphInterval: { def: 60 }, - systemMonitorLayoutMode: { def: "auto" }, - systemMonitorX: { def: -1 }, - systemMonitorY: { def: -1 }, - systemMonitorWidth: { def: 320 }, - systemMonitorHeight: { def: 480 }, - systemMonitorDisplayPreferences: { def: ["all"] }, - systemMonitorVariants: { def: [] }, - desktopWidgetPositions: { def: {} }, - desktopWidgetGridSettings: { def: {} }, - - desktopWidgetInstances: { def: [] }, - - desktopWidgetGroups: { def: [] }, - - builtInPluginSettings: { def: {} }, - clipboardEnterToPaste: { def: false }, - - launcherPluginVisibility: { def: {} }, - launcherPluginOrder: { def: [] } -}; - -function getValidKeys() { - return Object.keys(SPEC).filter(function (k) { return SPEC[k].persist !== false; }).concat(["configVersion"]); -} - -function set(root, key, value, saveFn, hooks) { - if (!(key in SPEC)) return; - root[key] = value; - var hookName = SPEC[key].onChange; - if (hookName && hooks && hooks[hookName]) { - hooks[hookName](root); - } - saveFn(); -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsStore.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsStore.js deleted file mode 100644 index f88bb03..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/settings/SettingsStore.js +++ /dev/null @@ -1,275 +0,0 @@ -.pragma library - - .import "./SettingsSpec.js" as SpecModule - -function parse(root, jsonObj) { - var SPEC = SpecModule.SPEC; - - if (!jsonObj) return; - - for (var k in SPEC) { - if (k === "pluginSettings") continue; - // Runtime-only keys are never in the JSON; resetting them here - // would wipe values set by detection processes on every reload. - if (SPEC[k].persist === false) continue; - if (!(k in jsonObj)) { - root[k] = SPEC[k].def; - } - } - - for (var k in jsonObj) { - if (!SPEC[k]) continue; - if (k === "pluginSettings") continue; - var raw = jsonObj[k]; - var spec = SPEC[k]; - var coerce = spec.coerce; - root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw; - } -} - -function toJson(root) { - var SPEC = SpecModule.SPEC; - var out = {}; - for (var k in SPEC) { - if (SPEC[k].persist === false) continue; - if (k === "pluginSettings") continue; - out[k] = root[k]; - } - out.configVersion = root.settingsConfigVersion; - return out; -} - -function migrateToVersion(obj, targetVersion) { - if (!obj) return null; - - var settings = JSON.parse(JSON.stringify(obj)); - var currentVersion = settings.configVersion || 0; - - if (currentVersion >= targetVersion) { - return null; - } - - if (currentVersion < 2) { - console.info("Migrating settings from version", currentVersion, "to version 2"); - - if (settings.barConfigs === undefined) { - var position = 0; - if (settings.dankBarAtBottom !== undefined || settings.topBarAtBottom !== undefined) { - var atBottom = settings.dankBarAtBottom !== undefined ? settings.dankBarAtBottom : settings.topBarAtBottom; - position = atBottom ? 1 : 0; - } else if (settings.dankBarPosition !== undefined) { - position = settings.dankBarPosition; - } - - var defaultConfig = { - id: "default", - name: "Main Bar", - enabled: true, - position: position, - screenPreferences: ["all"], - showOnLastDisplay: true, - leftWidgets: settings.dankBarLeftWidgets || ["launcherButton", "workspaceSwitcher", "focusedWindow"], - centerWidgets: settings.dankBarCenterWidgets || ["music", "clock", "weather"], - rightWidgets: settings.dankBarRightWidgets || ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], - spacing: settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : 4, - innerPadding: settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : 4, - bottomGap: settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : 0, - transparency: settings.dankBarTransparency !== undefined ? settings.dankBarTransparency : 1.0, - widgetTransparency: settings.dankBarWidgetTransparency !== undefined ? settings.dankBarWidgetTransparency : 1.0, - squareCorners: settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : false, - noBackground: settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : false, - gothCornersEnabled: settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : false, - gothCornerRadiusOverride: settings.dankBarGothCornerRadiusOverride !== undefined ? settings.dankBarGothCornerRadiusOverride : false, - gothCornerRadiusValue: settings.dankBarGothCornerRadiusValue !== undefined ? settings.dankBarGothCornerRadiusValue : 12, - borderEnabled: settings.dankBarBorderEnabled !== undefined ? settings.dankBarBorderEnabled : false, - borderColor: settings.dankBarBorderColor || "surfaceText", - borderOpacity: settings.dankBarBorderOpacity !== undefined ? settings.dankBarBorderOpacity : 1.0, - borderThickness: settings.dankBarBorderThickness !== undefined ? settings.dankBarBorderThickness : 1, - fontScale: settings.dankBarFontScale !== undefined ? settings.dankBarFontScale : 1.0, - autoHide: settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : false, - autoHideDelay: settings.dankBarAutoHideDelay !== undefined ? settings.dankBarAutoHideDelay : 250, - openOnOverview: settings.dankBarOpenOnOverview !== undefined ? settings.dankBarOpenOnOverview : false, - visible: settings.dankBarVisible !== undefined ? settings.dankBarVisible : true, - popupGapsAuto: settings.popupGapsAuto !== undefined ? settings.popupGapsAuto : true, - popupGapsManual: settings.popupGapsManual !== undefined ? settings.popupGapsManual : 4 - }; - - settings.barConfigs = [defaultConfig]; - - var legacyKeys = [ - "dankBarLeftWidgets", "dankBarCenterWidgets", "dankBarRightWidgets", - "dankBarWidgetOrder", "dankBarAutoHide", "dankBarAutoHideDelay", - "dankBarOpenOnOverview", "dankBarVisible", "dankBarSpacing", - "dankBarBottomGap", "dankBarInnerPadding", "dankBarPosition", - "dankBarSquareCorners", "dankBarNoBackground", "dankBarGothCornersEnabled", - "dankBarGothCornerRadiusOverride", "dankBarGothCornerRadiusValue", - "dankBarBorderEnabled", "dankBarBorderColor", "dankBarBorderOpacity", - "dankBarBorderThickness", "popupGapsAuto", "popupGapsManual", - "dankBarAtBottom", "topBarAtBottom", "dankBarTransparency", "dankBarWidgetTransparency" - ]; - - for (var i = 0; i < legacyKeys.length; i++) { - delete settings[legacyKeys[i]]; - } - - console.info("Migrated single bar settings to barConfigs"); - } - - settings.configVersion = 2; - } - - if (currentVersion < 3) { - console.info("Migrating settings from version", currentVersion, "to version 3"); - console.info("Per-widget controlCenterButton config now supported via widgetData properties"); - settings.configVersion = 3; - } - - if (currentVersion < 4) { - console.info("Migrating settings from version", currentVersion, "to version 4"); - console.info("Migrating desktop widgets to unified desktopWidgetInstances"); - - var instances = []; - - if (settings.desktopClockEnabled) { - var clockPositions = {}; - if (settings.desktopClockX !== undefined && settings.desktopClockX >= 0) { - clockPositions["default"] = { - x: settings.desktopClockX, - y: settings.desktopClockY, - width: settings.desktopClockWidth || 280, - height: settings.desktopClockHeight || 180 - }; - } - - instances.push({ - id: "dw_clock_primary", - widgetType: "desktopClock", - name: "Desktop Clock", - enabled: true, - config: { - style: settings.desktopClockStyle || "analog", - transparency: settings.desktopClockTransparency !== undefined ? settings.desktopClockTransparency : 0.8, - colorMode: settings.desktopClockColorMode || "primary", - customColor: settings.desktopClockCustomColor || "#ffffff", - showDate: settings.desktopClockShowDate !== false, - showAnalogNumbers: settings.desktopClockShowAnalogNumbers || false, - showAnalogSeconds: settings.desktopClockShowAnalogSeconds !== false, - displayPreferences: settings.desktopClockDisplayPreferences || ["all"] - }, - positions: clockPositions - }); - } - - if (settings.systemMonitorEnabled) { - var sysmonPositions = {}; - if (settings.systemMonitorX !== undefined && settings.systemMonitorX >= 0) { - sysmonPositions["default"] = { - x: settings.systemMonitorX, - y: settings.systemMonitorY, - width: settings.systemMonitorWidth || 320, - height: settings.systemMonitorHeight || 480 - }; - } - - instances.push({ - id: "dw_sysmon_primary", - widgetType: "systemMonitor", - name: "System Monitor", - enabled: true, - config: { - showHeader: settings.systemMonitorShowHeader !== false, - transparency: settings.systemMonitorTransparency !== undefined ? settings.systemMonitorTransparency : 0.8, - colorMode: settings.systemMonitorColorMode || "primary", - customColor: settings.systemMonitorCustomColor || "#ffffff", - showCpu: settings.systemMonitorShowCpu !== false, - showCpuGraph: settings.systemMonitorShowCpuGraph !== false, - showCpuTemp: settings.systemMonitorShowCpuTemp !== false, - showGpuTemp: settings.systemMonitorShowGpuTemp || false, - gpuPciId: settings.systemMonitorGpuPciId || "", - showMemory: settings.systemMonitorShowMemory !== false, - showMemoryGraph: settings.systemMonitorShowMemoryGraph !== false, - showNetwork: settings.systemMonitorShowNetwork !== false, - showNetworkGraph: settings.systemMonitorShowNetworkGraph !== false, - showDisk: settings.systemMonitorShowDisk !== false, - showTopProcesses: settings.systemMonitorShowTopProcesses || false, - topProcessCount: settings.systemMonitorTopProcessCount || 3, - topProcessSortBy: settings.systemMonitorTopProcessSortBy || "cpu", - layoutMode: settings.systemMonitorLayoutMode || "auto", - graphInterval: settings.systemMonitorGraphInterval || 60, - displayPreferences: settings.systemMonitorDisplayPreferences || ["all"] - }, - positions: sysmonPositions - }); - } - - var variants = settings.systemMonitorVariants || []; - for (var i = 0; i < variants.length; i++) { - var v = variants[i]; - instances.push({ - id: v.id, - widgetType: "systemMonitor", - name: v.name || ("System Monitor " + (i + 2)), - enabled: true, - config: v.config || {}, - positions: v.positions || {} - }); - } - - settings.desktopWidgetInstances = instances; - settings.configVersion = 4; - } - - if (currentVersion < 5) { - console.info("Migrating settings from version", currentVersion, "to version 5"); - console.info("Moving sensitive data (weather location, coordinates) to session.json"); - - delete settings.weatherLocation; - delete settings.weatherCoordinates; - - settings.configVersion = 5; - } - - if (currentVersion < 6) { - console.info("Migrating settings from version", currentVersion, "to version 6"); - - if (settings.barElevationEnabled === undefined) { - var legacyBars = Array.isArray(settings.barConfigs) ? settings.barConfigs : []; - var hadLegacyBarShadowEnabled = false; - for (var j = 0; j < legacyBars.length; j++) { - var legacyIntensity = Number(legacyBars[j] && legacyBars[j].shadowIntensity); - if (!isNaN(legacyIntensity) && legacyIntensity > 0) { - hadLegacyBarShadowEnabled = true; - break; - } - } - settings.barElevationEnabled = hadLegacyBarShadowEnabled; - } - - settings.configVersion = 6; - } - - return settings; -} - -function cleanup(fileText) { - var getValidKeys = SpecModule.getValidKeys; - if (!fileText || !fileText.trim()) return; - - try { - var settings = JSON.parse(fileText); - var validKeys = getValidKeys(); - var needsSave = false; - - for (var key in settings) { - if (validKeys.indexOf(key) < 0) { - delete settings[key]; - needsSave = true; - } - } - - return needsSave ? JSON.stringify(settings, null, 2) : null; - } catch (e) { - console.warn("SettingsData: Failed to cleanup unused keys:", e.message); - return null; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/suncalc.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/suncalc.js deleted file mode 100644 index db55b9a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Common/suncalc.js +++ /dev/null @@ -1,308 +0,0 @@ -.pragma library -// Copyright (c) 2025, Vladimir Agafonkin -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// shortcuts for easier to read formulas - -const PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - tan = Math.tan, - asin = Math.asin, - atan = Math.atan2, - acos = Math.acos, - rad = PI / 180; - -// sun calculations are based on https://aa.quae.nl/en/reken/zonpositie.html formulas - -// date/time constants and conversions - -const dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; - -function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } -function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } -function toDays(date) { return toJulian(date) - J2000; } - - -// general calculations for position - -const e = rad * 23.4397; // obliquity of the Earth - -function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } -function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } - -function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } -function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } - -function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } - -function astroRefraction(h) { - if (h < 0) // the following formula works for positive altitudes only. - h = 0; // if h = -0.08901179 a div/0 would occur. - - // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: - return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); -} - -// general sun calculations - -function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } - -function eclipticLongitude(M) { - - const C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth - - return M + C + P + PI; -} - -function sunCoords(d) { - - const M = solarMeanAnomaly(d), - L = eclipticLongitude(M); - - return { - dec: declination(L, 0), - ra: rightAscension(L, 0) - }; -} - - -// calculates sun position for a given date and latitude/longitude - -function getPosition(date, lat, lng) { - - const lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - - c = sunCoords(d), - H = siderealTime(d, lw) - c.ra; - - return { - azimuth: azimuth(H, phi, c.dec), - altitude: altitude(H, phi, c.dec) - }; -}; - - -// sun times configuration (angle, morning name, evening name) - -const times = [ - [-0.833, 'sunrise', 'sunset'], - [-0.3, 'sunriseEnd', 'sunsetStart'], - [-6, 'dawn', 'dusk'], - [-12, 'nauticalDawn', 'nauticalDusk'], - [-18, 'nightEnd', 'night'], - [6, 'goldenHourEnd', 'goldenHour'] -]; - -// adds a custom time to the times config - -function addTime(angle, riseName, setName) { - times.push([angle, riseName, setName]); -}; - - -// calculations for sun times - -const J0 = 0.0009; - -function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } - -function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } -function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } - -function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } -function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } - -// returns set time for the given sun altitude -function getSetJ(h, lw, phi, dec, n, M, L) { - - const w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); - return solarTransitJ(a, M, L); -} - - -// calculates sun times for a given date, latitude/longitude, and, optionally, -// the observer height (in meters) relative to the horizon - -function getTimes(date, lat, lng, height) { - - height = height || 0; - - const lw = rad * -lng, - phi = rad * lat, - dh = observerAngle(height), - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), - Jnoon = solarTransitJ(ds, M, L); - - const result = { - solarNoon: fromJulian(Jnoon), - nadir: fromJulian(Jnoon - 0.5) - }; - - for (const time of times) { - const h0 = (time[0] + dh) * rad; - const Jset = getSetJ(h0, lw, phi, dec, n, M, L); - const Jrise = Jnoon - (Jset - Jnoon); - - result[time[1]] = fromJulian(Jrise); - result[time[2]] = fromJulian(Jset); - } - - return result; -}; - - -// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas - -function moonCoords(d) { // geocentric ecliptic coordinates of the moon - - const L = rad * (218.316 + 13.176396 * d), // ecliptic longitude - M = rad * (134.963 + 13.064993 * d), // mean anomaly - F = rad * (93.272 + 13.229350 * d), // mean distance - - l = L + rad * 6.289 * sin(M), // longitude - b = rad * 5.128 * sin(F), // latitude - dt = 385001 - 20905 * cos(M); // distance to the moon in km - - return { - ra: rightAscension(l, b), - dec: declination(l, b), - dist: dt - }; -} - -function getMoonPosition(date, lat, lng) { - - const lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - c = moonCoords(d), - H = siderealTime(d, lw) - c.ra, - h = altitude(H, phi, c.dec), - // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); - - return { - azimuth: azimuth(H, phi, c.dec), - altitude: h + astroRefraction(h), // altitude correction for refraction, - distance: c.dist, - parallacticAngle: pa - }; -}; - - -// calculations for illumination parameters of the moon, -// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and -// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - -function getMoonIllumination(date) { - - const d = toDays(date || new Date()), - s = sunCoords(d), - m = moonCoords(d), - - sdist = 149598000, // distance from Earth to Sun in km - - phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)), - inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)), - angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - - cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra)); - - return { - fraction: (1 + cos(inc)) / 2, - phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI, - angle - }; -}; - - -function hoursLater(date, h) { - return new Date(date.valueOf() + h * dayMs / 24); -} - -// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article - -function getMoonTimes(date, lat, lng, inUTC) { - const t = new Date(date); - if (inUTC) t.setUTCHours(0, 0, 0, 0); - else t.setHours(0, 0, 0, 0); - - const hc = 0.133 * rad; - let h0 = getMoonPosition(t, lat, lng).altitude - hc, - rise, set, ye; - - // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) - for (let i = 1; i <= 24; i += 2) { - const h1 = getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; - const h2 = getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; - const a = (h0 + h2) / 2 - h1; - const b = (h2 - h0) / 2; - const xe = -b / (2 * a); - const d = b * b - 4 * a * h1; - let roots = 0, x1 = 0, x2 = 0; - ye = (a * xe + b) * xe + h1; - - if (d >= 0) { - const dx = Math.sqrt(d) / (Math.abs(a) * 2); - x1 = xe - dx; - x2 = xe + dx; - if (Math.abs(x1) <= 1) roots++; - if (Math.abs(x2) <= 1) roots++; - if (x1 < -1) x1 = x2; - } - - if (roots === 1) { - if (h0 < 0) rise = i + x1; - else set = i + x1; - - } else if (roots === 2) { - rise = i + (ye < 0 ? x2 : x1); - set = i + (ye < 0 ? x1 : x2); - } - - if (rise && set) break; - - h0 = h2; - } - - const result = {}; - - if (rise) result.rise = hoursLater(t, rise); - if (set) result.set = hoursLater(t, set); - - if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; - - return result; -}; diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSGreeter.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSGreeter.qml deleted file mode 100644 index f3068f5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSGreeter.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick -import Quickshell -import qs.Modules.Greetd - -Scope { - id: root - - GreeterSurface {} -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShell.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShell.qml deleted file mode 100644 index df3cbb8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShell.qml +++ /dev/null @@ -1,1059 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals -import qs.Modals.Changelog -import qs.Modals.Clipboard -import qs.Modals.Greeter -import qs.Modals.Settings -import qs.Modals.DankLauncherV2 -import qs.Modules -import qs.Modules.AppDrawer -import qs.Modules.DankDash -import qs.Modules.ControlCenter -import qs.Modules.Dock -import qs.Modules.Lock -import qs.Modules.Notepad -import qs.Modules.Notifications.Center -import qs.Widgets -import qs.Modules.Notifications.Popup -import qs.Modules.OSD -import qs.Modules.ProcessList -import qs.Modules.DankBar -import qs.Modules.DankBar.Popouts -import qs.Modules.WorkspaceOverlays -import qs.Services - -Item { - id: root - - Instantiator { - id: daemonPluginInstantiator - asynchronous: true - model: Object.keys(PluginService.pluginDaemonComponents) - - delegate: Loader { - id: daemonLoader - property string pluginId: modelData - sourceComponent: PluginService.pluginDaemonComponents[pluginId] - - onLoaded: { - if (item) { - item.pluginService = PluginService; - if (item.popoutService !== undefined) { - item.popoutService = PopoutService; - } - item.pluginId = pluginId; - console.info("Daemon plugin loaded:", pluginId); - } - } - } - } - - Loader { - id: blurredWallpaperBackgroundLoader - active: SettingsData.blurredWallpaperLayer && CompositorService.isNiri - asynchronous: false - - sourceComponent: BlurredWallpaperBackground {} - } - - WallpaperBackground {} - - DesktopWidgetLayer {} - - Lock { - id: lock - } - - Variants { - model: Quickshell.screens - - delegate: Loader { - id: fadeWindowLoader - required property var modelData - active: SettingsData.fadeToLockEnabled - asynchronous: false - - sourceComponent: FadeToLockWindow { - screen: fadeWindowLoader.modelData - - onFadeCompleted: { - IdleService.lockRequested(); - } - - onFadeCancelled: { - console.log("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name); - } - } - - Connections { - target: IdleService - enabled: fadeWindowLoader.item !== null - - function onFadeToLockRequested() { - if (fadeWindowLoader.item) { - fadeWindowLoader.item.startFade(); - } - } - - function onCancelFadeToLock() { - if (fadeWindowLoader.item) { - fadeWindowLoader.item.cancelFade(); - } - } - } - } - } - - Variants { - model: Quickshell.screens - - delegate: Loader { - id: fadeDpmsWindowLoader - required property var modelData - active: SettingsData.fadeToDpmsEnabled - asynchronous: false - - sourceComponent: FadeToDpmsWindow { - screen: fadeDpmsWindowLoader.modelData - - onFadeCompleted: { - IdleService.requestMonitorOff(); - } - - onFadeCancelled: { - console.log("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name); - } - } - - Connections { - target: IdleService - enabled: fadeDpmsWindowLoader.item !== null - - function onFadeToDpmsRequested() { - if (fadeDpmsWindowLoader.item) { - fadeDpmsWindowLoader.item.startFade(); - } - } - - function onCancelFadeToDpms() { - if (fadeDpmsWindowLoader.item) { - fadeDpmsWindowLoader.item.cancelFade(); - } - } - - function onRequestMonitorOn() { - if (!fadeDpmsWindowLoader.item) - return; - fadeDpmsWindowLoader.item.cancelFade(); - } - } - } - } - - property string _barLayoutStateJson: { - const configs = SettingsData.barConfigs; - const mapped = configs.map(c => ({ - id: c.id, - position: c.position, - autoHide: c.autoHide, - visible: c.visible - })).sort((a, b) => { - const aVertical = a.position === SettingsData.Position.Left || a.position === SettingsData.Position.Right; - const bVertical = b.position === SettingsData.Position.Left || b.position === SettingsData.Position.Right; - if (aVertical !== bVertical) { - return aVertical - bVertical; - } - return String(a.id).localeCompare(String(b.id)); - }); - return JSON.stringify(mapped); - } - - on_BarLayoutStateJsonChanged: { - if (typeof dockRecreateDebounce !== "undefined") { - dockRecreateDebounce.restart(); - } - } - - Repeater { - id: dankBarRepeater - model: ScriptModel { - id: barRepeaterModel - values: JSON.parse(root._barLayoutStateJson) - } - - property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader - - delegate: Loader { - id: barLoader - required property var modelData - property var barConfig: SettingsData.barConfigs.find(cfg => cfg.id === modelData.id) || null - active: barConfig?.enabled ?? false - asynchronous: false - - sourceComponent: DankBar { - barConfig: barLoader.barConfig - hyprlandOverviewLoader: dankBarRepeater.hyprlandOverviewLoaderRef - - onColorPickerRequested: { - if (colorPickerModal.shouldBeVisible) { - colorPickerModal.close(); - } else { - colorPickerModal.show(); - } - } - } - } - } - - property bool dockEnabled: false - - Timer { - id: dockRecreateDebounce - interval: 500 - repeat: false - onTriggered: { - root.dockEnabled = false; - Qt.callLater(() => { - root.dockEnabled = true; - }); - } - } - - Timer { - id: loginSoundTimer - // Half a second delay before playing login sound, otherwise the sound may be cut off - // 50 is the minimum that seems to work, but 500 is safer - interval: 500 - repeat: false - onTriggered: { - AudioService.playLoginSoundIfApplicable(); - } - } - - Component.onCompleted: { - dockRecreateDebounce.start(); - // Force PolkitService singleton to initialize - PolkitService.polkitAvailable; - loginSoundTimer.start(); - } - - Loader { - id: dockLoader - active: root.dockEnabled - asynchronous: false - - property var currentPosition: SettingsData.dockPosition - property bool initialized: false - - sourceComponent: Dock { - contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null - } - - onLoaded: { - if (item) { - dockContextMenuLoader.active = true; - } - } - - Component.onCompleted: { - initialized = true; - } - - onCurrentPositionChanged: { - if (!initialized) - return; - const comp = sourceComponent; - sourceComponent = null; - sourceComponent = comp; - } - } - - Loader { - id: dankDashPopoutLoader - - active: false - asynchronous: false - - Component.onCompleted: { - PopoutService.dankDashPopoutLoader = dankDashPopoutLoader; - } - - onLoaded: { - if (item) { - PopoutService.dankDashPopout = item; - PopoutService._onDankDashPopoutLoaded(); - } - } - - sourceComponent: Component { - DankDashPopout { - id: dankDashPopout - onPopoutClosed: PopoutService.unloadDankDash() - } - } - } - - LazyLoader { - id: dockContextMenuLoader - - active: false - - DockContextMenu { - id: dockContextMenu - } - } - - LazyLoader { - id: notificationCenterLoader - - active: false - - Component.onCompleted: { - PopoutService.notificationCenterLoader = notificationCenterLoader; - } - - NotificationCenterPopout { - id: notificationCenter - onPopoutClosed: PopoutService.unloadNotificationCenter() - - Component.onCompleted: { - PopoutService.notificationCenterPopout = notificationCenter; - } - } - } - - Variants { - model: SettingsData.notificationFocusedMonitor ? Quickshell.screens : SettingsData.getFilteredScreens("notifications") - - delegate: NotificationPopupManager { - modelData: item - } - } - - LazyLoader { - id: controlCenterLoader - - active: false - - property var modalRef: colorPickerModal - property LazyLoader powerModalLoaderRef: powerMenuModalLoader - - Component.onCompleted: { - PopoutService.controlCenterLoader = controlCenterLoader; - } - - ControlCenterPopout { - id: controlCenterPopout - colorPickerModal: controlCenterLoader.modalRef - powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef - onPopoutClosed: PopoutService.unloadControlCenter() - - onLockRequested: { - lock.activate(); - } - - Component.onCompleted: { - PopoutService.controlCenterPopout = controlCenterPopout; - } - } - } - - LazyLoader { - id: wifiPasswordModalLoader - active: false - - Component.onCompleted: { - PopoutService.wifiPasswordModalLoader = wifiPasswordModalLoader; - } - - WifiPasswordModal { - id: wifiPasswordModalItem - - Component.onCompleted: { - PopoutService.wifiPasswordModal = wifiPasswordModalItem; - } - } - } - - LazyLoader { - id: wifiQRCodeModalLoader - active: false - - Component.onCompleted: { - PopoutService.wifiQRCodeModalLoader = wifiQRCodeModalLoader; - } - - WifiQRCodeModal { - id: wifiQRCodeModalItem - - Component.onCompleted: { - PopoutService.wifiQRCodeModal = wifiQRCodeModalItem; - } - } - } - - LazyLoader { - id: polkitAuthModalLoader - active: false - - PolkitAuthModal { - id: polkitAuthModal - - Component.onCompleted: { - PopoutService.polkitAuthModal = polkitAuthModal; - } - } - } - - Connections { - target: PolkitService.agent - enabled: PolkitService.polkitAvailable - - function onAuthenticationRequestStarted() { - polkitAuthModalLoader.active = true; - if (polkitAuthModalLoader.item) - polkitAuthModalLoader.item.show(); - } - } - - BluetoothPairingModal { - id: bluetoothPairingModal - - Component.onCompleted: { - PopoutService.bluetoothPairingModal = bluetoothPairingModal; - } - } - - property string lastCredentialsToken: "" - property var lastCredentialsTime: 0 - - Connections { - target: NetworkService - - function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo) { - const now = Date.now(); - const timeSinceLastPrompt = now - lastCredentialsTime; - - wifiPasswordModalLoader.active = true; - if (!wifiPasswordModalLoader.item) - return; - - if (wifiPasswordModalLoader.item.visible && timeSinceLastPrompt < 1000) { - NetworkService.cancelCredentials(lastCredentialsToken); - lastCredentialsToken = token; - lastCredentialsTime = now; - wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo); - return; - } - - lastCredentialsToken = token; - lastCredentialsTime = now; - wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo); - } - } - - LazyLoader { - id: networkInfoModalLoader - - active: false - - NetworkInfoModal { - id: networkInfoModal - - Component.onCompleted: { - PopoutService.networkInfoModal = networkInfoModal; - } - } - } - - LazyLoader { - id: batteryPopoutLoader - - active: false - - Component.onCompleted: { - PopoutService.batteryPopoutLoader = batteryPopoutLoader; - } - - BatteryPopout { - id: batteryPopout - onPopoutClosed: PopoutService.unloadBattery() - - Component.onCompleted: { - PopoutService.batteryPopout = batteryPopout; - } - } - } - - LazyLoader { - id: layoutPopoutLoader - - active: false - - Component.onCompleted: { - PopoutService.layoutPopoutLoader = layoutPopoutLoader; - } - - DWLLayoutPopout { - id: layoutPopout - onPopoutClosed: PopoutService.unloadLayoutPopout() - - Component.onCompleted: { - PopoutService.layoutPopout = layoutPopout; - } - } - } - - LazyLoader { - id: vpnPopoutLoader - - active: false - - Component.onCompleted: { - PopoutService.vpnPopoutLoader = vpnPopoutLoader; - } - - VpnPopout { - id: vpnPopout - onPopoutClosed: PopoutService.unloadVpn() - - Component.onCompleted: { - PopoutService.vpnPopout = vpnPopout; - } - } - } - - LazyLoader { - id: processListPopoutLoader - - active: false - - Component.onCompleted: { - PopoutService.processListPopoutLoader = processListPopoutLoader; - } - - ProcessListPopout { - id: processListPopout - onPopoutClosed: PopoutService.unloadProcessListPopout() - - Component.onCompleted: { - PopoutService.processListPopout = processListPopout; - } - } - } - - LazyLoader { - id: settingsModalLoader - - active: false - - Component.onCompleted: { - PopoutService.settingsModalLoader = settingsModalLoader; - } - - onActiveChanged: { - if (active && item) { - PopoutService.settingsModal = item; - PopoutService._onSettingsModalLoaded(); - } - } - - SettingsModal { - id: settingsModal - property bool wasShown: false - - onVisibleChanged: { - if (visible) { - wasShown = true; - } else if (wasShown) { - PopoutService.unloadSettings(); - } - } - } - } - - LazyLoader { - id: appDrawerLoader - - active: false - - Component.onCompleted: { - PopoutService.appDrawerLoader = appDrawerLoader; - } - - AppDrawerPopout { - id: appDrawerPopout - onPopoutClosed: PopoutService.unloadAppDrawer() - - Component.onCompleted: { - PopoutService.appDrawerPopout = appDrawerPopout; - } - } - } - - LazyLoader { - id: dankLauncherV2ModalLoader - - active: false - - Component.onCompleted: { - PopoutService.dankLauncherV2ModalLoader = dankLauncherV2ModalLoader; - } - - DankLauncherV2Modal { - id: dankLauncherV2Modal - - Component.onCompleted: { - PopoutService.dankLauncherV2Modal = dankLauncherV2Modal; - PopoutService._onDankLauncherV2ModalLoaded(); - } - } - } - - LazyLoader { - id: clipboardHistoryPopoutLoader - - active: false - - Component.onCompleted: { - PopoutService.clipboardHistoryPopoutLoader = clipboardHistoryPopoutLoader; - } - - ClipboardHistoryPopout { - id: clipboardHistoryPopout - onPopoutClosed: PopoutService.unloadClipboardHistoryPopout() - - Component.onCompleted: { - PopoutService.clipboardHistoryPopout = clipboardHistoryPopout; - } - } - } - - MuxModal { - id: muxModal - } - - ClipboardHistoryModal { - id: clipboardHistoryModalPopup - - Component.onCompleted: { - PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup; - } - } - - NotificationModal { - id: notificationModal - - Component.onCompleted: { - PopoutService.notificationModal = notificationModal; - } - } - - BrowserPickerModal { - id: browserPickerModal - } - - AppPickerModal { - id: filePickerModal - title: I18n.tr("Open with...") - viewMode: SettingsData.appPickerViewMode || "grid" - - onViewModeChanged: { - SettingsData.set("appPickerViewMode", viewMode); - } - - function shellEscape(str) { - return "'" + str.replace(/'/g, "'\\''") + "'"; - } - - onApplicationSelected: (app, filePath) => { - if (!app) - return; - let cmd = app.exec || ""; - const escapedPath = shellEscape(filePath); - const escapedUri = shellEscape("file://" + filePath); - - let hasField = false; - if (cmd.includes("%f")) { - cmd = cmd.replace("%f", escapedPath); - hasField = true; - } else if (cmd.includes("%F")) { - cmd = cmd.replace("%F", escapedPath); - hasField = true; - } else if (cmd.includes("%u")) { - cmd = cmd.replace("%u", escapedUri); - hasField = true; - } else if (cmd.includes("%U")) { - cmd = cmd.replace("%U", escapedUri); - hasField = true; - } - - cmd = cmd.replace(/%[ikc]/g, ""); - - if (!hasField) { - cmd += " " + escapedPath; - } - - console.log("FilePicker: Launching", cmd); - - Quickshell.execDetached({ - command: ["sh", "-c", cmd] - }); - } - } - - Connections { - target: DMSService - function onOpenUrlRequested(url) { - if (url.startsWith("dms://theme/install/")) { - var themeId = url.replace("dms://theme/install/", "").split(/[?#]/)[0]; - if (themeId) { - PopoutService.pendingThemeInstall = themeId; - PopoutService.openSettingsWithTab("theme"); - } - return; - } - if (url.startsWith("dms://plugin/install/")) { - var pluginId = url.replace("dms://plugin/install/", "").split(/[?#]/)[0]; - if (pluginId) { - PopoutService.pendingPluginInstall = pluginId; - PopoutService.openSettingsWithTab("plugins"); - } - return; - } - browserPickerModal.url = url; - browserPickerModal.open(); - } - - function onAppPickerRequested(data) { - console.log("DMSShell: App picker requested with data:", JSON.stringify(data)); - - if (!data || !data.target) { - console.warn("DMSShell: Invalid app picker request data"); - return; - } - - filePickerModal.targetData = data.target; - filePickerModal.targetDataLabel = data.requestType || "file"; - - if (data.categories && data.categories.length > 0) { - filePickerModal.categoryFilter = data.categories; - } else { - filePickerModal.categoryFilter = []; - } - - filePickerModal.usageHistoryKey = "filePickerUsageHistory"; - filePickerModal.open(); - } - } - - DankColorPickerModal { - id: colorPickerModal - - Component.onCompleted: { - PopoutService.colorPickerModal = colorPickerModal; - } - } - - LazyLoader { - id: workspaceRenameModalLoader - - active: false - - Component.onCompleted: PopoutService.workspaceRenameModalLoader = workspaceRenameModalLoader - - WorkspaceRenameModal { - id: workspaceRenameModal - } - } - - LazyLoader { - id: windowRuleModalLoader - - active: false - - Component.onCompleted: PopoutService.windowRuleModalLoader = windowRuleModalLoader - - WindowRuleModal { - id: windowRuleModal - } - } - - LazyLoader { - id: processListModalLoader - - active: false - - Component.onCompleted: PopoutService.processListModalLoader = processListModalLoader - - ProcessListModal { - id: processListModal - - Component.onCompleted: { - PopoutService.processListModal = processListModal; - } - } - } - - LazyLoader { - id: systemUpdateLoader - - active: false - - Component.onCompleted: { - PopoutService.systemUpdateLoader = systemUpdateLoader; - } - - SystemUpdatePopout { - id: systemUpdatePopout - onPopoutClosed: PopoutService.unloadSystemUpdate() - - Component.onCompleted: { - PopoutService.systemUpdatePopout = systemUpdatePopout; - } - } - } - - Variants { - id: notepadSlideoutVariants - model: SettingsData.getFilteredScreens("notepad") - - delegate: DankSlideout { - id: notepadSlideout - modelData: item - title: I18n.tr("Notepad") - slideoutWidth: 480 - expandable: true - expandedWidthValue: 960 - customTransparency: SettingsData.notepadTransparencyOverride - - content: Component { - Notepad { - slideout: notepadSlideout - onHideRequested: notepadSlideout.hide() - } - } - - function toggle() { - if (isVisible) { - hide(); - } else { - show(); - } - } - } - - onInstancesChanged: PopoutService.notepadSlideouts = instances - Component.onCompleted: PopoutService.notepadSlideouts = instances - } - - LazyLoader { - id: powerMenuModalLoader - - active: false - - PowerMenuModal { - id: powerMenuModal - - onPowerActionRequested: (action, title, message) => { - switch (action) { - case "logout": - SessionService.logout(); - break; - case "suspend": - SessionService.suspend(); - break; - case "hibernate": - SessionService.hibernate(); - break; - case "reboot": - SessionService.reboot(); - break; - case "poweroff": - SessionService.poweroff(); - break; - } - } - - onLockRequested: { - lock.activate(); - } - - Component.onCompleted: { - PopoutService.powerMenuModal = powerMenuModal; - } - } - } - - LazyLoader { - id: hyprKeybindsModalLoader - - active: false - - KeybindsModal { - id: keybindsModal - - Component.onCompleted: { - PopoutService.hyprKeybindsModal = keybindsModal; - } - } - } - - DMSShellIPC { - powerMenuModalLoader: powerMenuModalLoader - processListModalLoader: processListModalLoader - controlCenterLoader: controlCenterLoader - dankDashPopoutLoader: dankDashPopoutLoader - notepadSlideoutVariants: notepadSlideoutVariants - hyprKeybindsModalLoader: hyprKeybindsModalLoader - dankBarRepeater: dankBarRepeater - hyprlandOverviewLoader: hyprlandOverviewLoader - workspaceRenameModalLoader: workspaceRenameModalLoader - windowRuleModalLoader: windowRuleModalLoader - } - - Variants { - model: SettingsData.getFilteredScreens("toast") - - delegate: Toast { - modelData: item - visible: ToastService.toastVisible - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: VolumeOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: MediaVolumeOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: MediaPlaybackOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: MicMuteOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: BrightnessOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: IdleInhibitorOSD { - modelData: item - } - } - - Loader { - id: powerProfileWatcherLoader - active: SettingsData.osdPowerProfileEnabled - source: "Services/PowerProfileWatcher.qml" - } - - Variants { - model: SettingsData.osdPowerProfileEnabled ? SettingsData.getFilteredScreens("osd") : [] - - delegate: PowerProfileOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: CapsLockOSD { - modelData: item - } - } - - Variants { - model: SettingsData.getFilteredScreens("osd") - - delegate: AudioOutputOSD { - modelData: item - } - } - - LazyLoader { - id: hyprlandOverviewLoader - active: CompositorService.isHyprland - component: HyprlandOverview { - id: hyprlandOverview - } - } - - LazyLoader { - id: niriOverviewOverlayLoader - active: CompositorService.isNiri && SettingsData.niriOverviewOverlayEnabled - component: NiriOverviewOverlay { - id: niriOverviewOverlay - } - } - - Loader { - id: greeterLoader - active: false - sourceComponent: GreeterModal { - onGreeterCompleted: greeterLoader.active = false - Component.onCompleted: show() - } - - Connections { - target: FirstLaunchService - function onGreeterRequested() { - if (greeterLoader.active && greeterLoader.item) { - greeterLoader.item.show(); - return; - } - greeterLoader.active = true; - } - } - } - - Loader { - id: changelogLoader - active: false - sourceComponent: ChangelogModal { - onChangelogDismissed: changelogLoader.active = false - Component.onCompleted: show() - } - - Connections { - target: ChangelogService - function onChangelogRequested() { - if (changelogLoader.active && changelogLoader.item) { - changelogLoader.item.show(); - return; - } - changelogLoader.active = true; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShellIPC.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShellIPC.qml deleted file mode 100644 index 4a111c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/DMSShellIPC.qml +++ /dev/null @@ -1,1728 +0,0 @@ -import QtQuick -import Quickshell.Io -import Quickshell.Hyprland -import Quickshell.Wayland -import Quickshell.Services.SystemTray -import qs.Common -import qs.Services -import qs.Modules.Settings.DisplayConfig - -Item { - id: root - - required property var powerMenuModalLoader - required property var processListModalLoader - required property var controlCenterLoader - required property var dankDashPopoutLoader - required property var notepadSlideoutVariants - required property var hyprKeybindsModalLoader - required property var dankBarRepeater - required property var hyprlandOverviewLoader - required property var workspaceRenameModalLoader - required property var windowRuleModalLoader - - function getPreferredBar(refPropertyName) { - if (!root.dankBarRepeater || root.dankBarRepeater.count === 0) - return null; - - const focusedScreenName = BarWidgetService.getFocusedScreenName(); - - const loaders = Array.from({ - length: root.dankBarRepeater.count - }, (_, i) => root.dankBarRepeater.itemAt(i)); - - let currentBar = null; - - for (const loader of loaders) { - const instances = loader?.item?.barVariants?.instances || []; - for (const bar of instances) { - if (!bar) - continue; - - const onFocusedScreen = focusedScreenName && bar.modelData?.name === focusedScreenName; - const hasRef = !refPropertyName || !!bar[refPropertyName]; - - if (hasRef) { - currentBar = bar; - - if (onFocusedScreen) - break; - } - } - } - - return currentBar; - } - - IpcHandler { - function open() { - root.powerMenuModalLoader.active = true; - if (root.powerMenuModalLoader.item) - root.powerMenuModalLoader.item.openCentered(); - - return "POWERMENU_OPEN_SUCCESS"; - } - - function close() { - if (root.powerMenuModalLoader.item) - root.powerMenuModalLoader.item.close(); - - return "POWERMENU_CLOSE_SUCCESS"; - } - - function toggle() { - root.powerMenuModalLoader.active = true; - if (root.powerMenuModalLoader.item) { - if (root.powerMenuModalLoader.item.shouldBeVisible) { - root.powerMenuModalLoader.item.close(); - } else { - root.powerMenuModalLoader.item.openCentered(); - } - } - - return "POWERMENU_TOGGLE_SUCCESS"; - } - - target: "powermenu" - } - - IpcHandler { - function open(): string { - root.processListModalLoader.active = true; - if (root.processListModalLoader.item) - root.processListModalLoader.item.show(); - - return "PROCESSLIST_OPEN_SUCCESS"; - } - - function close(): string { - if (root.processListModalLoader.item) - root.processListModalLoader.item.hide(); - - return "PROCESSLIST_CLOSE_SUCCESS"; - } - - function toggle(): string { - root.processListModalLoader.active = true; - if (root.processListModalLoader.item) - root.processListModalLoader.item.toggle(); - - return "PROCESSLIST_TOGGLE_SUCCESS"; - } - - function focusOrToggle(): string { - root.processListModalLoader.active = true; - if (root.processListModalLoader.item) - root.processListModalLoader.item.focusOrToggle(); - - return "PROCESSLIST_FOCUS_OR_TOGGLE_SUCCESS"; - } - - target: "processlist" - } - - IpcHandler { - function open(): string { - const bar = root.getPreferredBar("controlCenterButtonRef"); - if (bar) { - bar.triggerControlCenter(); - return "CONTROL_CENTER_OPEN_SUCCESS"; - } - return "CONTROL_CENTER_OPEN_FAILED"; - } - - function hide(): string { - if (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) { - root.controlCenterLoader.item.close(); - return "CONTROL_CENTER_HIDE_SUCCESS"; - } - return "CONTROL_CENTER_HIDE_FAILED"; - } - - function toggle(): string { - if (root.controlCenterLoader.item?.shouldBeVisible) { - root.controlCenterLoader.item.close(); - return "CONTROL_CENTER_TOGGLE_SUCCESS"; - } - - const bar = root.getPreferredBar("controlCenterButtonRef"); - if (bar) { - bar.triggerControlCenter(); - return "CONTROL_CENTER_TOGGLE_SUCCESS"; - } - return "CONTROL_CENTER_TOGGLE_FAILED"; - } - - function status(): string { - return (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) ? "visible" : "hidden"; - } - - target: "control-center" - } - - IpcHandler { - function open(tab: string): string { - const bar = root.getPreferredBar("clockButtonRef"); - if (!bar) - return "DASH_OPEN_FAILED"; - - const dash = root.dankDashPopoutLoader.item; - const onSameScreen = dash && dash.shouldBeVisible && dash.triggerScreen?.name === bar.screen?.name; - - if (!onSameScreen) { - bar.triggerWallpaperBrowser(); - } - - if (!root.dankDashPopoutLoader.item) - return "DASH_OPEN_FAILED"; - - switch (tab.toLowerCase()) { - case "media": - root.dankDashPopoutLoader.item.currentTabIndex = 1; - break; - case "wallpaper": - root.dankDashPopoutLoader.item.currentTabIndex = 2; - break; - case "weather": - root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0; - break; - default: - root.dankDashPopoutLoader.item.currentTabIndex = 0; - break; - } - - root.dankDashPopoutLoader.item.dashVisible = true; - return "DASH_OPEN_SUCCESS"; - } - - function close(): string { - if (root.dankDashPopoutLoader.item) { - root.dankDashPopoutLoader.item.dashVisible = false; - return "DASH_CLOSE_SUCCESS"; - } - return "DASH_CLOSE_FAILED"; - } - - function toggle(tab: string): string { - if (root.dankDashPopoutLoader.item?.dashVisible) { - root.dankDashPopoutLoader.item.dashVisible = false; - return "DASH_TOGGLE_SUCCESS"; - } - - const bar = root.getPreferredBar("clockButtonRef"); - if (bar) { - bar.triggerWallpaperBrowser(); - if (root.dankDashPopoutLoader.item) { - switch (tab.toLowerCase()) { - case "media": - root.dankDashPopoutLoader.item.currentTabIndex = 1; - break; - case "wallpaper": - root.dankDashPopoutLoader.item.currentTabIndex = 2; - break; - case "weather": - root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0; - break; - default: - root.dankDashPopoutLoader.item.currentTabIndex = 0; - break; - } - } - return "DASH_TOGGLE_SUCCESS"; - } - return "DASH_TOGGLE_FAILED"; - } - - target: "dash" - } - - IpcHandler { - function getFocusedScreenName() { - if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { - return Hyprland.focusedWorkspace.monitor.name; - } - if (CompositorService.isNiri && NiriService.currentOutput) { - return NiriService.currentOutput; - } - if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && I3.workspaces?.values) { - const focusedWs = I3.workspaces.values.find(ws => ws.focused === true); - return focusedWs?.monitor?.name || ""; - } - if (CompositorService.isDwl && DwlService.activeOutput) { - return DwlService.activeOutput; - } - return ""; - } - - function getActiveNotepadInstance() { - if (root.notepadSlideoutVariants.instances.length === 0) { - return null; - } - - if (root.notepadSlideoutVariants.instances.length === 1) { - return root.notepadSlideoutVariants.instances[0]; - } - - var focusedScreen = getFocusedScreenName(); - if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) { - for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) { - var slideout = root.notepadSlideoutVariants.instances[i]; - if (slideout.modelData && slideout.modelData.name === focusedScreen) { - return slideout; - } - } - } - - for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) { - var slideout = root.notepadSlideoutVariants.instances[i]; - if (slideout.isVisible) { - return slideout; - } - } - - return root.notepadSlideoutVariants.instances[0]; - } - - function open(): string { - var instance = getActiveNotepadInstance(); - if (instance) { - instance.show(); - return "NOTEPAD_OPEN_SUCCESS"; - } - return "NOTEPAD_OPEN_FAILED"; - } - - function close(): string { - var instance = getActiveNotepadInstance(); - if (instance) { - instance.hide(); - return "NOTEPAD_CLOSE_SUCCESS"; - } - return "NOTEPAD_CLOSE_FAILED"; - } - - function toggle(): string { - var instance = getActiveNotepadInstance(); - if (instance) { - instance.toggle(); - return "NOTEPAD_TOGGLE_SUCCESS"; - } - return "NOTEPAD_TOGGLE_FAILED"; - } - - target: "notepad" - } - - IpcHandler { - function toggle(): string { - SessionService.toggleIdleInhibit(); - return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled"; - } - - function enable(): string { - SessionService.enableIdleInhibit(); - return "Idle inhibit enabled"; - } - - function disable(): string { - SessionService.disableIdleInhibit(); - return "Idle inhibit disabled"; - } - - function status(): string { - return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled"; - } - - function reason(newReason: string): string { - if (!newReason) { - return `Current reason: ${SessionService.inhibitReason}`; - } - - SessionService.setInhibitReason(newReason); - return `Inhibit reason set to: ${newReason}`; - } - - target: "inhibit" - } - - IpcHandler { - function list(): string { - return MprisController.availablePlayers.map(p => p.identity).join("\n"); - } - - function play(): void { - if (MprisController.activePlayer && MprisController.activePlayer.canPlay) { - MprisController.activePlayer.play(); - } - } - - function pause(): void { - if (MprisController.activePlayer && MprisController.activePlayer.canPause) { - MprisController.activePlayer.pause(); - } - } - - function playPause(): void { - if (MprisController.activePlayer && MprisController.activePlayer.canTogglePlaying) { - MprisController.activePlayer.togglePlaying(); - } - } - - function previous(): void { - MprisController.previousOrRewind(); - } - - function next(): void { - if (MprisController.activePlayer && MprisController.activePlayer.canGoNext) { - MprisController.activePlayer.next(); - } - } - - function stop(): void { - if (MprisController.activePlayer) { - MprisController.activePlayer.stop(); - } - } - - function increment(step: string): string { - if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) { - const currentVolume = Math.round(MprisController.activePlayer.volume * 100); - const stepValue = parseInt(step || "5"); - const newVolume = Math.max(0, Math.min(100, currentVolume + stepValue)); - - MprisController.activePlayer.volume = newVolume / 100; - return `Player volume increased to ${newVolume}%`; - } - } - - function decrement(step: string): string { - if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) { - const currentVolume = Math.round(MprisController.activePlayer.volume * 100); - const stepValue = parseInt(step || "5"); - const newVolume = Math.max(0, Math.min(100, currentVolume - stepValue)); - - MprisController.activePlayer.volume = newVolume / 100; - return `Player volume decreased to ${newVolume}%`; - } - } - - function setvolume(percentage: string): string { - if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) { - const clampedVolume = Math.max(0, Math.min(100, percentage)); - MprisController.activePlayer.volume = clampedVolume / 100; - return `Player volume set to ${clampedVolume}%`; - } - } - - target: "mpris" - } - - IpcHandler { - function toggle(provider: string): string { - if (!provider) - return "ERROR: No provider specified"; - - KeybindsService.loadCheatsheet(provider); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return `KEYBINDS_TOGGLE_FAILED: ${provider}`; - - if (root.hyprKeybindsModalLoader.item.shouldBeVisible) - root.hyprKeybindsModalLoader.item.close(); - else - root.hyprKeybindsModalLoader.item.open(); - return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`; - } - - function toggleWithPath(provider: string, path: string): string { - if (!provider) - return "ERROR: No provider specified"; - - KeybindsService.loadCheatsheet(provider); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return `KEYBINDS_TOGGLE_FAILED: ${provider}`; - - if (root.hyprKeybindsModalLoader.item.shouldBeVisible) - root.hyprKeybindsModalLoader.item.close(); - else - root.hyprKeybindsModalLoader.item.open(); - return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`; - } - - function open(provider: string): string { - if (!provider) - return "ERROR: No provider specified"; - - KeybindsService.loadCheatsheet(provider); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return `KEYBINDS_OPEN_FAILED: ${provider}`; - - root.hyprKeybindsModalLoader.item.open(); - return `KEYBINDS_OPEN_SUCCESS: ${provider}`; - } - - function openWithPath(provider: string, path: string): string { - if (!provider) - return "ERROR: No provider specified"; - - KeybindsService.loadCheatsheet(provider); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return `KEYBINDS_OPEN_FAILED: ${provider}`; - - root.hyprKeybindsModalLoader.item.open(); - return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})`; - } - - function close(): string { - if (!root.hyprKeybindsModalLoader.item) - return "KEYBINDS_CLOSE_FAILED"; - - root.hyprKeybindsModalLoader.item.close(); - return "KEYBINDS_CLOSE_SUCCESS"; - } - - target: "keybinds" - } - - IpcHandler { - function openBinds(): string { - if (!CompositorService.isHyprland) - return "HYPR_NOT_AVAILABLE"; - - KeybindsService.currentProvider = "hyprland"; - KeybindsService.loadBinds(); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return "HYPR_KEYBINDS_OPEN_FAILED"; - - root.hyprKeybindsModalLoader.item.open(); - return "HYPR_KEYBINDS_OPEN_SUCCESS"; - } - - function closeBinds(): string { - if (!CompositorService.isHyprland) - return "HYPR_NOT_AVAILABLE"; - - if (!root.hyprKeybindsModalLoader.item) - return "HYPR_KEYBINDS_CLOSE_FAILED"; - - root.hyprKeybindsModalLoader.item.close(); - return "HYPR_KEYBINDS_CLOSE_SUCCESS"; - } - - function toggleBinds(): string { - if (!CompositorService.isHyprland) - return "HYPR_NOT_AVAILABLE"; - - KeybindsService.currentProvider = "hyprland"; - KeybindsService.loadBinds(); - root.hyprKeybindsModalLoader.active = true; - - if (!root.hyprKeybindsModalLoader.item) - return "HYPR_KEYBINDS_TOGGLE_FAILED"; - - if (root.hyprKeybindsModalLoader.item.shouldBeVisible) { - root.hyprKeybindsModalLoader.item.close(); - } else { - root.hyprKeybindsModalLoader.item.open(); - } - return "HYPR_KEYBINDS_TOGGLE_SUCCESS"; - } - - function toggleOverview(): string { - if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { - return "HYPR_NOT_AVAILABLE"; - } - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS"; - } - - function closeOverview(): string { - if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { - return "HYPR_NOT_AVAILABLE"; - } - root.hyprlandOverviewLoader.item.overviewOpen = false; - return "OVERVIEW_CLOSE_SUCCESS"; - } - - function openOverview(): string { - if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { - return "HYPR_NOT_AVAILABLE"; - } - root.hyprlandOverviewLoader.item.overviewOpen = true; - return "OVERVIEW_OPEN_SUCCESS"; - } - - target: "hypr" - } - - IpcHandler { - function wallpaper(): string { - const bar = root.getPreferredBar("clockButtonRef"); - if (bar) { - bar.triggerWallpaperBrowser(); - return "SUCCESS: Toggled wallpaper browser"; - } - return "ERROR: Failed to toggle wallpaper browser"; - } - - target: "dankdash" - } - - function getBarConfig(selector: string, value: string): var { - const barSelectors = ["id", "name", "index"]; - if (!barSelectors.includes(selector)) - return { - error: "BAR_INVALID_SELECTOR" - }; - const index = selector === "index" ? Number(value) : SettingsData.barConfigs.findIndex(bar => bar[selector] == value); - const barConfig = SettingsData.barConfigs?.[index]; - if (!barConfig) - return { - error: "BAR_NOT_FOUND" - }; - return { - barConfig - }; - } - - IpcHandler { - function reveal(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - visible: true - }); - return "BAR_SHOW_SUCCESS"; - } - - function hide(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - visible: false - }); - return "BAR_HIDE_SUCCESS"; - } - - function toggle(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - visible: !barConfig.visible - }); - return !barConfig.visible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"; - } - - function status(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - return barConfig.visible ? "visible" : "hidden"; - } - - function autoHide(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - autoHide: true - }); - return "BAR_AUTO_HIDE_SUCCESS"; - } - - function manualHide(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - autoHide: false - }); - return "BAR_MANUAL_HIDE_SUCCESS"; - } - - function toggleAutoHide(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - SettingsData.updateBarConfig(barConfig.id, { - autoHide: !barConfig.autoHide - }); - return barConfig.autoHide ? "BAR_MANUAL_HIDE_SUCCESS" : "BAR_AUTO_HIDE_SUCCESS"; - } - - function getPosition(selector: string, value: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - const positions = ["top", "bottom", "left", "right"]; - return positions[barConfig.position] || "unknown"; - } - - function setPosition(selector: string, value: string, position: string): string { - const { - barConfig, - error - } = getBarConfig(selector, value); - if (error) - return error; - const positionMap = { - "top": SettingsData.Position.Top, - "bottom": SettingsData.Position.Bottom, - "left": SettingsData.Position.Left, - "right": SettingsData.Position.Right - }; - const posValue = positionMap[position.toLowerCase()]; - if (posValue === undefined) - return "BAR_INVALID_POSITION"; - SettingsData.updateBarConfig(barConfig.id, { - position: posValue - }); - return "BAR_POSITION_SET_SUCCESS"; - } - - target: "bar" - } - - IpcHandler { - function reveal(): string { - SettingsData.setShowDock(true); - return "DOCK_SHOW_SUCCESS"; - } - - function hide(): string { - SettingsData.setShowDock(false); - return "DOCK_HIDE_SUCCESS"; - } - - function toggle(): string { - SettingsData.toggleShowDock(); - return SettingsData.showDock ? "DOCK_SHOW_SUCCESS" : "DOCK_HIDE_SUCCESS"; - } - - function status(): string { - return SettingsData.showDock ? "visible" : "hidden"; - } - - function autoHide(): string { - SettingsData.dockAutoHide = true; - SettingsData.saveSettings(); - return "BAR_AUTO_HIDE_SUCCESS"; - } - - function manualHide(): string { - SettingsData.dockAutoHide = false; - SettingsData.saveSettings(); - return "BAR_MANUAL_HIDE_SUCCESS"; - } - - function toggleAutoHide(): string { - SettingsData.dockAutoHide = !SettingsData.dockAutoHide; - SettingsData.saveSettings(); - return SettingsData.dockAutoHide ? "BAR_AUTO_HIDE_SUCCESS" : "BAR_MANUAL_HIDE_SUCCESS"; - } - - target: "dock" - } - - IpcHandler { - function open(): string { - PopoutService.openSettings(); - return "SETTINGS_OPEN_SUCCESS"; - } - - function openWith(tab: string): string { - if (!tab) - return "SETTINGS_OPEN_FAILED: No tab specified"; - PopoutService.openSettingsWithTab(tab); - return `SETTINGS_OPEN_SUCCESS: ${tab}`; - } - - function close(): string { - PopoutService.closeSettings(); - return "SETTINGS_CLOSE_SUCCESS"; - } - - function toggle(): string { - PopoutService.toggleSettings(); - return "SETTINGS_TOGGLE_SUCCESS"; - } - - function toggleWith(tab: string): string { - if (!tab) - return "SETTINGS_TOGGLE_FAILED: No tab specified"; - PopoutService.toggleSettingsWithTab(tab); - return `SETTINGS_TOGGLE_SUCCESS: ${tab}`; - } - - function focusOrToggle(): string { - PopoutService.focusOrToggleSettings(); - return "SETTINGS_FOCUS_OR_TOGGLE_SUCCESS"; - } - - function focusOrToggleWith(tab: string): string { - if (!tab) - return "SETTINGS_FOCUS_OR_TOGGLE_FAILED: No tab specified"; - PopoutService.focusOrToggleSettingsWithTab(tab); - return `SETTINGS_FOCUS_OR_TOGGLE_SUCCESS: ${tab}`; - } - - function tabs(): string { - if (!PopoutService.settingsModal) - return "wallpaper\ntheme\ntypography\ntime_weather\nsounds\ndankbar\ndankbar_settings\ndankbar_widgets\nworkspaces\nmedia_player\nnotifications\nosd\nrunning_apps\nupdater\ndock\nlauncher\nkeybinds\ndisplays\nnetwork\nprinters\nlock_screen\npower_sleep\nplugins\nabout"; - var modal = PopoutService.settingsModal; - var ids = []; - var structure = modal.sidebar?.categoryStructure ?? []; - for (var i = 0; i < structure.length; i++) { - var cat = structure[i]; - if (cat.separator) - continue; - if (cat.id) - ids.push(cat.id); - if (cat.children) { - for (var j = 0; j < cat.children.length; j++) { - if (cat.children[j].id) - ids.push(cat.children[j].id); - } - } - } - return ids.join("\n"); - } - - function get(key: string): string { - return JSON.stringify(SettingsData?.[key]); - } - - function set(key: string, value: string): string { - if (!(key in SettingsData)) { - console.warn("Cannot set property, not found:", key); - return "SETTINGS_INVALID_KEY"; - } - - const typeName = typeof SettingsData?.[key]; - - try { - switch (typeName) { - case "boolean": - if (value === "true" || value === "false") - value = (value === "true"); - else - throw `${value} is not a Boolean`; - break; - case "number": - value = Number(value); - if (isNaN(value)) - throw `${value} is not a Number`; - break; - case "string": - value = String(value); - break; - case "object": - // NOTE: Parsing lists is messed up upstream and not sure if we want - // to make sure objects are well structured or just let people set - // whatever they want but risking messed up settings. - // Objects & Arrays are disabled for now - // https://github.com/quickshell-mirror/quickshell/pull/22 - throw "Setting Objects and Arrays not supported"; - default: - throw "Unsupported type"; - } - - console.warn("Setting:", key, value); - SettingsData[key] = value; - SettingsData.saveSettings(); - return "SETTINGS_SET_SUCCESS"; - } catch (e) { - console.warn("Failed to set property:", key, "error:", e); - return "SETTINGS_SET_FAILURE"; - } - } - - target: "settings" - } - - IpcHandler { - function browse(type: string) { - const modal = PopoutService.settingsModal; - if (modal) { - if (type === "wallpaper") { - modal.openWallpaperBrowser(false); - } else if (type === "profile") { - modal.openProfileBrowser(false); - } - } else { - PopoutService.openSettings(); - } - } - - target: "file" - } - - IpcHandler { - function toggle(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const success = BarWidgetService.triggerWidgetPopout(widgetId); - return success ? `WIDGET_TOGGLE_SUCCESS: ${widgetId}` : `WIDGET_TOGGLE_FAILED: ${widgetId}`; - } - - function openWith(widgetId: string, mode: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - if (typeof widget.openWithMode !== "function") - return `WIDGET_OPEN_WITH_NOT_SUPPORTED: ${widgetId}`; - - widget.openWithMode(mode || "all"); - return `WIDGET_OPEN_WITH_SUCCESS: ${widgetId} ${mode}`; - } - - function toggleWith(widgetId: string, mode: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - if (typeof widget.toggleWithMode !== "function") - return `WIDGET_TOGGLE_WITH_NOT_SUPPORTED: ${widgetId}`; - - widget.toggleWithMode(mode || "all"); - return `WIDGET_TOGGLE_WITH_SUCCESS: ${widgetId} ${mode}`; - } - - function openQuery(widgetId: string, query: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - if (typeof widget.openWithQuery !== "function") - return `WIDGET_OPEN_QUERY_NOT_SUPPORTED: ${widgetId}`; - - widget.openWithQuery(query || ""); - return `WIDGET_OPEN_QUERY_SUCCESS: ${widgetId}`; - } - - function toggleQuery(widgetId: string, query: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - if (typeof widget.toggleWithQuery !== "function") - return `WIDGET_TOGGLE_QUERY_NOT_SUPPORTED: ${widgetId}`; - - widget.toggleWithQuery(query || ""); - return `WIDGET_TOGGLE_QUERY_SUCCESS: ${widgetId}`; - } - - function list(): string { - const widgets = BarWidgetService.getRegisteredWidgetIds(); - if (widgets.length === 0) - return "No widgets registered"; - - const lines = []; - for (const widgetId of widgets) { - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - let state = ""; - if (widget?.effectiveVisible !== undefined) - state = widget.effectiveVisible ? " [visible]" : " [hidden]"; - lines.push(widgetId + state); - } - return lines.join("\n"); - } - - function status(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - - if (widget.popoutTarget?.shouldBeVisible) - return "visible"; - return "hidden"; - } - - function reveal(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - - if (typeof widget.setVisibilityOverride === "function") { - widget.setVisibilityOverride(true); - return `WIDGET_REVEAL_SUCCESS: ${widgetId}`; - } - return `WIDGET_REVEAL_NOT_SUPPORTED: ${widgetId}`; - } - - function hide(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - - if (typeof widget.setVisibilityOverride === "function") { - widget.setVisibilityOverride(false); - return `WIDGET_HIDE_SUCCESS: ${widgetId}`; - } - return `WIDGET_HIDE_NOT_SUPPORTED: ${widgetId}`; - } - - function reset(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - - if (typeof widget.clearVisibilityOverride === "function") { - widget.clearVisibilityOverride(); - return `WIDGET_RESET_SUCCESS: ${widgetId}`; - } - return `WIDGET_RESET_NOT_SUPPORTED: ${widgetId}`; - } - - function visibility(widgetId: string): string { - if (!widgetId) - return "ERROR: No widget ID specified"; - - if (!BarWidgetService.hasWidget(widgetId)) - return `WIDGET_NOT_FOUND: ${widgetId}`; - - const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId); - if (!widget) - return `WIDGET_NOT_AVAILABLE: ${widgetId}`; - - if (widget.effectiveVisible !== undefined) - return widget.effectiveVisible ? "visible" : "hidden"; - return "unknown"; - } - - target: "widget" - } - - IpcHandler { - function reload(pluginId: string): string { - if (!pluginId) - return "ERROR: No plugin ID specified"; - - if (!PluginService.availablePlugins[pluginId]) - return `PLUGIN_NOT_FOUND: ${pluginId}`; - - if (!PluginService.isPluginLoaded(pluginId)) { - const success = PluginService.enablePlugin(pluginId); - return success ? `PLUGIN_RELOAD_SUCCESS: ${pluginId}` : `PLUGIN_RELOAD_FAILED: ${pluginId}`; - } - - const success = PluginService.reloadPlugin(pluginId); - return success ? `PLUGIN_RELOAD_SUCCESS: ${pluginId}` : `PLUGIN_RELOAD_FAILED: ${pluginId}`; - } - - function enable(pluginId: string): string { - if (!pluginId) - return "ERROR: No plugin ID specified"; - - if (!PluginService.availablePlugins[pluginId]) - return `PLUGIN_NOT_FOUND: ${pluginId}`; - - const success = PluginService.enablePlugin(pluginId); - return success ? `PLUGIN_ENABLE_SUCCESS: ${pluginId}` : `PLUGIN_ENABLE_FAILED: ${pluginId}`; - } - - function disable(pluginId: string): string { - if (!pluginId) - return "ERROR: No plugin ID specified"; - - if (!PluginService.availablePlugins[pluginId]) - return `PLUGIN_NOT_FOUND: ${pluginId}`; - - const success = PluginService.disablePlugin(pluginId); - return success ? `PLUGIN_DISABLE_SUCCESS: ${pluginId}` : `PLUGIN_DISABLE_FAILED: ${pluginId}`; - } - - function toggle(pluginId: string): string { - if (!pluginId) - return "ERROR: No plugin ID specified"; - - if (!PluginService.availablePlugins[pluginId]) - return `PLUGIN_NOT_FOUND: ${pluginId}`; - - const success = PluginService.togglePlugin(pluginId); - return success ? `PLUGIN_TOGGLE_SUCCESS: ${pluginId}` : `PLUGIN_TOGGLE_FAILED: ${pluginId}`; - } - - function list(): string { - const plugins = PluginService.getAvailablePlugins(); - if (plugins.length === 0) - return "No plugins available"; - return plugins.map(p => `${p.id} [${p.loaded ? "loaded" : "disabled"}]`).join("\n"); - } - - function status(pluginId: string): string { - if (!pluginId) - return "ERROR: No plugin ID specified"; - - if (!PluginService.availablePlugins[pluginId]) - return `PLUGIN_NOT_FOUND: ${pluginId}`; - - return PluginService.isPluginLoaded(pluginId) ? "loaded" : "disabled"; - } - - target: "plugins" - } - - IpcHandler { - function open(): string { - if (!PopoutService.clipboardHistoryModal) { - return "CLIPBOARD_NOT_AVAILABLE"; - } - PopoutService.clipboardHistoryModal.show(); - return "CLIPBOARD_OPEN_SUCCESS"; - } - - function close(): string { - if (!PopoutService.clipboardHistoryModal) { - return "CLIPBOARD_NOT_AVAILABLE"; - } - PopoutService.clipboardHistoryModal.hide(); - return "CLIPBOARD_CLOSE_SUCCESS"; - } - - function toggle(): string { - if (!PopoutService.clipboardHistoryModal) { - return "CLIPBOARD_NOT_AVAILABLE"; - } - PopoutService.clipboardHistoryModal.toggle(); - return "CLIPBOARD_TOGGLE_SUCCESS"; - } - - target: "clipboard" - } - - // ! spotlight and launcher should be synonymous for backwards compat - IpcHandler { - function open(): string { - PopoutService.openDankLauncherV2(); - return "LAUNCHER_OPEN_SUCCESS"; - } - - function close(): string { - PopoutService.closeDankLauncherV2(); - return "LAUNCHER_CLOSE_SUCCESS"; - } - - function toggle(): string { - PopoutService.toggleDankLauncherV2(); - return "LAUNCHER_TOGGLE_SUCCESS"; - } - - function openWith(mode: string): string { - if (!mode) - return "LAUNCHER_OPEN_FAILED: No mode specified"; - PopoutService.openDankLauncherV2WithMode(mode); - return `LAUNCHER_OPEN_SUCCESS: ${mode}`; - } - - function toggleWith(mode: string): string { - if (!mode) - return "LAUNCHER_TOGGLE_FAILED: No mode specified"; - PopoutService.toggleDankLauncherV2WithMode(mode); - return `LAUNCHER_TOGGLE_SUCCESS: ${mode}`; - } - - function openQuery(query: string): string { - PopoutService.openDankLauncherV2WithQuery(query); - return "LAUNCHER_OPEN_QUERY_SUCCESS"; - } - - function toggleQuery(query: string): string { - PopoutService.toggleDankLauncherV2WithQuery(query); - return "LAUNCHER_TOGGLE_QUERY_SUCCESS"; - } - - target: "launcher" - } - - // ! spotlight and launcher should be synonymous for backwards compat - IpcHandler { - function open(): string { - PopoutService.openDankLauncherV2(); - return "SPOTLIGHT_OPEN_SUCCESS"; - } - - function close(): string { - PopoutService.closeDankLauncherV2(); - return "SPOTLIGHT_CLOSE_SUCCESS"; - } - - function toggle(): string { - PopoutService.toggleDankLauncherV2(); - return "SPOTLIGHT_TOGGLE_SUCCESS"; - } - - function openWith(mode: string): string { - if (!mode) - return "SPOTLIGHT_OPEN_FAILED: No mode specified"; - PopoutService.openDankLauncherV2WithMode(mode); - return `SPOTLIGHT_OPEN_SUCCESS: ${mode}`; - } - - function toggleWith(mode: string): string { - if (!mode) - return "SPOTLIGHT_TOGGLE_FAILED: No mode specified"; - PopoutService.toggleDankLauncherV2WithMode(mode); - return `SPOTLIGHT_TOGGLE_SUCCESS: ${mode}`; - } - - function openQuery(query: string): string { - PopoutService.openDankLauncherV2WithQuery(query); - return "SPOTLIGHT_OPEN_QUERY_SUCCESS"; - } - - function toggleQuery(query: string): string { - PopoutService.toggleDankLauncherV2WithQuery(query); - return "SPOTLIGHT_TOGGLE_QUERY_SUCCESS"; - } - - target: "spotlight" - } - - IpcHandler { - function info(message: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showInfo(message); - return "TOAST_INFO_SUCCESS"; - } - - function infoWith(message: string, details: string, command: string, category: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showInfo(message, details, command, category); - return "TOAST_INFO_SUCCESS"; - } - - function warn(message: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showWarning(message); - return "TOAST_WARN_SUCCESS"; - } - - function warnWith(message: string, details: string, command: string, category: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showWarning(message, details, command, category); - return "TOAST_WARN_SUCCESS"; - } - - function error(message: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showError(message); - return "TOAST_ERROR_SUCCESS"; - } - - function errorWith(message: string, details: string, command: string, category: string): string { - if (!message) - return "ERROR: No message specified"; - - ToastService.showError(message, details, command, category); - return "TOAST_ERROR_SUCCESS"; - } - - function hide(): string { - ToastService.hideToast(); - return "TOAST_HIDE_SUCCESS"; - } - - function dismiss(category: string): string { - if (!category) - return "ERROR: No category specified"; - - ToastService.dismissCategory(category); - return "TOAST_DISMISS_SUCCESS"; - } - - function status(): string { - if (!ToastService.toastVisible) - return "hidden"; - - const levels = ["info", "warn", "error"]; - return `visible:${levels[ToastService.currentLevel]}:${ToastService.currentMessage}`; - } - - target: "toast" - } - - IpcHandler { - function open(): string { - FirstLaunchService.showWelcome(); - return "WELCOME_OPEN_SUCCESS"; - } - - function doctor(): string { - FirstLaunchService.showDoctor(); - return "WELCOME_DOCTOR_SUCCESS"; - } - - function page(pageNum: string): string { - const num = parseInt(pageNum) || 0; - FirstLaunchService.showGreeter(num); - return `WELCOME_PAGE_SUCCESS: ${num}`; - } - - target: "welcome" - } - - IpcHandler { - function toggleOverlay(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const currentValue = instance.config?.showOnOverlay ?? false; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - showOnOverlay: !currentValue - }); - return !currentValue ? `DESKTOP_WIDGET_OVERLAY_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_OVERLAY_DISABLED: ${instanceId}`; - } - - function setOverlay(instanceId: string, enabled: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const enabledBool = enabled === "true" || enabled === "1"; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - showOnOverlay: enabledBool - }); - return enabledBool ? `DESKTOP_WIDGET_OVERLAY_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_OVERLAY_DISABLED: ${instanceId}`; - } - - function list(): string { - const instances = SettingsData.desktopWidgetInstances || []; - if (instances.length === 0) - return "No desktop widgets configured"; - return instances.map(i => `${i.id} [${i.widgetType}] ${i.name || i.widgetType} ${i.enabled ? "[enabled]" : "[disabled]"}`).join("\n"); - } - - function status(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const enabled = instance.enabled ?? true; - const overlay = instance.config?.showOnOverlay ?? false; - const overview = instance.config?.showOnOverview ?? false; - const clickThrough = instance.config?.clickThrough ?? false; - const syncPosition = instance.config?.syncPositionAcrossScreens ?? false; - return `enabled: ${enabled}, overlay: ${overlay}, overview: ${overview}, clickThrough: ${clickThrough}, syncPosition: ${syncPosition}`; - } - - function enable(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - SettingsData.updateDesktopWidgetInstance(instanceId, { - enabled: true - }); - return `DESKTOP_WIDGET_ENABLED: ${instanceId}`; - } - - function disable(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - SettingsData.updateDesktopWidgetInstance(instanceId, { - enabled: false - }); - return `DESKTOP_WIDGET_DISABLED: ${instanceId}`; - } - - function toggleEnabled(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const currentValue = instance.enabled ?? true; - SettingsData.updateDesktopWidgetInstance(instanceId, { - enabled: !currentValue - }); - return !currentValue ? `DESKTOP_WIDGET_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_DISABLED: ${instanceId}`; - } - - function toggleClickThrough(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const currentValue = instance.config?.clickThrough ?? false; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - clickThrough: !currentValue - }); - return !currentValue ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`; - } - - function setClickThrough(instanceId: string, enabled: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const enabledBool = enabled === "true" || enabled === "1"; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - clickThrough: enabledBool - }); - return enabledBool ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`; - } - - function toggleSyncPosition(instanceId: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const currentValue = instance.config?.syncPositionAcrossScreens ?? false; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - syncPositionAcrossScreens: !currentValue - }); - return !currentValue ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`; - } - - function setSyncPosition(instanceId: string, enabled: string): string { - if (!instanceId) - return "ERROR: No instance ID specified"; - - const instance = SettingsData.getDesktopWidgetInstance(instanceId); - if (!instance) - return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`; - - const enabledBool = enabled === "true" || enabled === "1"; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, { - syncPositionAcrossScreens: enabledBool - }); - return enabledBool ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`; - } - - target: "desktopWidget" - } - - IpcHandler { - function open(): string { - root.workspaceRenameModalLoader.active = true; - if (root.workspaceRenameModalLoader.item) { - const ws = NiriService.workspaces[NiriService.focusedWorkspaceId]; - root.workspaceRenameModalLoader.item.show(ws?.name || ""); - return "WORKSPACE_RENAME_MODAL_OPENED"; - } - return "WORKSPACE_RENAME_MODAL_NOT_FOUND"; - } - - function close(): string { - if (root.workspaceRenameModalLoader.item) { - root.workspaceRenameModalLoader.item.hide(); - return "WORKSPACE_RENAME_MODAL_CLOSED"; - } - return "WORKSPACE_RENAME_MODAL_NOT_FOUND"; - } - - function toggle(): string { - root.workspaceRenameModalLoader.active = true; - if (root.workspaceRenameModalLoader.item) { - if (root.workspaceRenameModalLoader.item.visible) { - root.workspaceRenameModalLoader.item.hide(); - return "WORKSPACE_RENAME_MODAL_CLOSED"; - } - const ws = NiriService.workspaces[NiriService.focusedWorkspaceId]; - root.workspaceRenameModalLoader.item.show(ws?.name || ""); - return "WORKSPACE_RENAME_MODAL_OPENED"; - } - return "WORKSPACE_RENAME_MODAL_NOT_FOUND"; - } - - target: "workspace-rename" - } - - IpcHandler { - function getFocusedWindow() { - const active = ToplevelManager.activeToplevel; - if (!active) - return null; - return { - appId: active.appId || "", - title: active.title || "" - }; - } - - function open(): string { - if (!CompositorService.isNiri) - return "WINDOW_RULES_NIRI_ONLY"; - root.windowRuleModalLoader.active = true; - if (root.windowRuleModalLoader.item) { - root.windowRuleModalLoader.item.show(getFocusedWindow()); - return "WINDOW_RULE_MODAL_OPENED"; - } - return "WINDOW_RULE_MODAL_NOT_FOUND"; - } - - function close(): string { - if (root.windowRuleModalLoader.item) { - root.windowRuleModalLoader.item.hide(); - return "WINDOW_RULE_MODAL_CLOSED"; - } - return "WINDOW_RULE_MODAL_NOT_FOUND"; - } - - function toggle(): string { - if (!CompositorService.isNiri) - return "WINDOW_RULES_NIRI_ONLY"; - root.windowRuleModalLoader.active = true; - if (root.windowRuleModalLoader.item) { - if (root.windowRuleModalLoader.item.visible) { - root.windowRuleModalLoader.item.hide(); - return "WINDOW_RULE_MODAL_CLOSED"; - } - root.windowRuleModalLoader.item.show(getFocusedWindow()); - return "WINDOW_RULE_MODAL_OPENED"; - } - return "WINDOW_RULE_MODAL_NOT_FOUND"; - } - - target: "window-rules" - } - - IpcHandler { - function listProfiles(): string { - const profiles = DisplayConfigState.validatedProfiles; - const activeId = SettingsData.getActiveDisplayProfile(CompositorService.compositor); - const matchedId = DisplayConfigState.matchedProfile; - const lines = []; - - for (const id in profiles) { - const p = profiles[id]; - const flags = []; - if (id === activeId) - flags.push("active"); - if (id === matchedId) - flags.push("matched"); - const flagStr = flags.length > 0 ? " [" + flags.join(",") + "]" : ""; - lines.push(p.name + flagStr + " -> " + JSON.stringify(p.outputSet)); - } - - if (lines.length === 0) - return "No profiles configured"; - return lines.join("\n"); - } - - function setProfile(profileName: string): string { - if (!profileName) - return "ERROR: No profile name specified"; - - if (SettingsData.displayProfileAutoSelect) - return "ERROR: Auto profile selection is enabled. Use toggleAuto first"; - - const profiles = DisplayConfigState.validatedProfiles; - let profileId = null; - - for (const id in profiles) { - if (profiles[id].name === profileName) { - profileId = id; - break; - } - } - - if (!profileId) - return `ERROR: Profile not found: ${profileName}`; - - DisplayConfigState.activateProfile(profileId); - return `PROFILE_SET_SUCCESS: ${profileName}`; - } - - // ! TODO - auto profile switching is buggy on niri and other compositors - function toggleAuto(): string { - return "ERROR: Auto profile selection is temporarily disabled due to compositor bugs"; - } - - function status(): string { - const auto = "off"; // disabled for now - const activeId = SettingsData.getActiveDisplayProfile(CompositorService.compositor); - const matchedId = DisplayConfigState.matchedProfile; - const profiles = DisplayConfigState.validatedProfiles; - const activeName = profiles[activeId]?.name || "none"; - const matchedName = profiles[matchedId]?.name || "none"; - const currentOutputs = JSON.stringify(DisplayConfigState.currentOutputSet); - - return `auto: ${auto}\nactive: ${activeName}\nmatched: ${matchedName}\noutputs: ${currentOutputs}`; - } - - function current(): string { - return JSON.stringify(DisplayConfigState.currentOutputSet); - } - - function refresh(): string { - DisplayConfigState.currentOutputSet = DisplayConfigState.buildCurrentOutputSet(); - DisplayConfigState.validateProfiles(); - return "Refreshed output state"; - } - - target: "outputs" - } - - IpcHandler { - function findTrayItem(itemId: string): var { - if (!itemId) - return null; - - return SystemTray.items.values.find(item => { - const id = item?.id || ""; - const title = item?.tooltipTitle || ""; - const fullKey = title ? `${id}::${title}` : id; - return fullKey === itemId || id === itemId; - }); - } - - function list(): string { - const items = SystemTray.items.values; - if (items.length === 0) - return "No tray items available"; - - return items.map(item => { - const id = item?.id || ""; - const title = item?.tooltipTitle || ""; - const fullKey = title ? `${id}::${title}` : id; - const hasMenu = item?.hasMenu ? " [menu]" : ""; - return fullKey + hasMenu; - }).join("\n"); - } - - function activate(itemId: string): string { - const item = findTrayItem(itemId); - if (!item) - return `ERROR: Tray item not found: ${itemId}`; - - item.activate(); - return `SUCCESS: Activated ${itemId}`; - } - - function status(itemId: string): string { - const item = findTrayItem(itemId); - if (!item) - return `ERROR: Tray item not found: ${itemId}`; - - const id = item?.id || ""; - const title = item?.tooltipTitle || ""; - const hasMenu = item?.hasMenu || false; - const onlyMenu = item?.onlyMenu || false; - - return `id: ${id}\ntitle: ${title}\nhasMenu: ${hasMenu}\nonlyMenu: ${onlyMenu}`; - } - - target: "tray" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/LICENSE_CHANGE_12_11_2025.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/LICENSE_CHANGE_12_11_2025.md deleted file mode 100644 index 67a4c29..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/LICENSE_CHANGE_12_11_2025.md +++ /dev/null @@ -1,23 +0,0 @@ -# DankMaterialShell License Change - -Relicensing from GPL-3.0 to MIT. - -Consent and documentation is available in [pull request #686](https://github.com/AvengeMedia/DankMaterialShell/pull/686) and is summarized below. - -## Contributors - -The project has 21 contributors requiring consent: -- 2 primary authors (10k+ lines each) -- 7 major contributors (1k+ lines or 10+ commits) -- 12 significant contributors (100+ lines) -- 2 derivative works (code adapted from other projects) - -Contributors with <50 lines are excluded as they don't meet copyright thresholds. Automated bots don't hold copyright. - -## Consent Status - -All 21 contributors have provided consent. Three contributions were sufficiently reverted or rewritten by maintainers, making them eligible without original author consent. - -## Reasoning - -GPL-3.0 may require plugins to also be GPL-3.0 licensed. MIT allows plugin authors to choose their own licenses. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/AppPickerModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/AppPickerModal.qml deleted file mode 100644 index 2188111..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/AppPickerModal.qml +++ /dev/null @@ -1,471 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Widgets -import qs.Services - -DankModal { - id: root - - property string title: I18n.tr("Select Application") - property string targetData: "" - property string targetDataLabel: "" - property string searchQuery: "" - property int selectedIndex: 0 - property int gridColumns: SettingsData.appLauncherGridColumns - property bool keyboardNavigationActive: false - property string viewMode: "grid" - property var categoryFilter: [] - property var usageHistoryKey: "" - property bool showTargetData: true - - signal applicationSelected(var app, string targetData) - - shouldBeVisible: false - allowStacking: true - modalWidth: 520 - modalHeight: 500 - - onBackgroundClicked: close() - - onDialogClosed: { - searchQuery = "" - selectedIndex = 0 - keyboardNavigationActive = false - } - - onOpened: { - searchQuery = "" - updateApplicationList() - selectedIndex = 0 - Qt.callLater(() => { - if (contentLoader.item && contentLoader.item.searchField) { - contentLoader.item.searchField.text = "" - contentLoader.item.searchField.forceActiveFocus() - } - }) - } - - function updateApplicationList() { - applicationsModel.clear() - const apps = AppSearchService.applications - const usageHistory = usageHistoryKey && SettingsData[usageHistoryKey] ? SettingsData[usageHistoryKey] : {} - let filteredApps = [] - - for (const app of apps) { - if (!app || !app.categories) continue - - let matchesCategory = categoryFilter.length === 0 - - if (categoryFilter.length > 0) { - try { - for (const cat of app.categories) { - if (categoryFilter.includes(cat)) { - matchesCategory = true - break - } - } - } catch (e) { - console.warn("AppPicker: Error iterating categories for", app.name, ":", e) - continue - } - } - - if (matchesCategory) { - const name = app.name || "" - const lowerName = name.toLowerCase() - const lowerQuery = searchQuery.toLowerCase() - - if (searchQuery === "" || lowerName.includes(lowerQuery)) { - filteredApps.push({ - name: name, - icon: app.icon || "application-x-executable", - exec: app.exec || app.execString || "", - startupClass: app.startupWMClass || "", - appData: app - }) - } - } - } - - filteredApps.sort((a, b) => { - const aId = a.appData.id || a.appData.execString || a.appData.exec || "" - const bId = b.appData.id || b.appData.execString || b.appData.exec || "" - const aUsage = usageHistory[aId] ? usageHistory[aId].count : 0 - const bUsage = usageHistory[bId] ? usageHistory[bId].count : 0 - if (aUsage !== bUsage) { - return bUsage - aUsage - } - return (a.name || "").localeCompare(b.name || "") - }) - - filteredApps.forEach(app => { - applicationsModel.append({ - name: app.name, - icon: app.icon, - exec: app.exec, - startupClass: app.startupClass, - appId: app.appData.id || app.appData.execString || app.appData.exec || "" - }) - }) - - console.log("AppPicker: Found " + filteredApps.length + " applications") - } - - onSearchQueryChanged: updateApplicationList() - - ListModel { - id: applicationsModel - } - - content: Component { - FocusScope { - id: appContent - - property alias searchField: searchField - - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - root.close() - event.accepted = true - } - - Keys.onPressed: event => { - if (applicationsModel.count === 0) return - - // Toggle view mode with Tab key - if (event.key === Qt.Key_Tab) { - root.viewMode = root.viewMode === "grid" ? "list" : "grid" - event.accepted = true - return - } - - if (root.viewMode === "grid") { - if (event.key === Qt.Key_Left) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.max(0, root.selectedIndex - 1) - event.accepted = true - } else if (event.key === Qt.Key_Right) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1) - event.accepted = true - } else if (event.key === Qt.Key_Up) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.max(0, root.selectedIndex - root.gridColumns) - event.accepted = true - } else if (event.key === Qt.Key_Down) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + root.gridColumns) - event.accepted = true - } - } else { - if (event.key === Qt.Key_Up) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.max(0, root.selectedIndex - 1) - event.accepted = true - } else if (event.key === Qt.Key_Down) { - root.keyboardNavigationActive = true - root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1) - event.accepted = true - } - } - - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (root.selectedIndex >= 0 && root.selectedIndex < applicationsModel.count) { - const app = applicationsModel.get(root.selectedIndex) - launchApplication(app) - } - event.accepted = true - } - } - - Column { - width: parent.width - Theme.spacingS * 2 - height: parent.height - Theme.spacingS * 2 - x: Theme.spacingS - y: Theme.spacingS - spacing: Theme.spacingS - - Item { - width: parent.width - height: 40 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.title - font.pixelSize: Theme.fontSizeLarge + 4 - font.weight: Font.Bold - color: Theme.surfaceText - } - - Row { - spacing: 4 - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 36 - circular: false - iconName: "view_list" - iconSize: 20 - iconColor: root.viewMode === "list" ? Theme.primary : Theme.surfaceText - backgroundColor: root.viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - onClicked: { - root.viewMode = "list" - } - } - - DankActionButton { - buttonSize: 36 - circular: false - iconName: "grid_view" - iconSize: 20 - iconColor: root.viewMode === "grid" ? Theme.primary : Theme.surfaceText - backgroundColor: root.viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - onClicked: { - root.viewMode = "grid" - } - } - } - } - - DankTextField { - id: searchField - - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - height: 52 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - font.pixelSize: Theme.fontSizeLarge - enabled: root.shouldBeVisible - ignoreLeftRightKeys: root.viewMode !== "list" - ignoreTabKeys: true - keyForwardTargets: [appContent] - - onTextEdited: { - root.searchQuery = text - } - - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.close() - event.accepted = true - return - } - - const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key) - const hasText = text.length > 0 - - if (isEnterKey && hasText) { - if (root.keyboardNavigationActive && applicationsModel.count > 0) { - const app = applicationsModel.get(root.selectedIndex) - launchApplication(app) - } else if (applicationsModel.count > 0) { - const app = applicationsModel.get(0) - launchApplication(app) - } - event.accepted = true - return - } - - const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right, Qt.Key_Tab, Qt.Key_Backtab] - const isNavigationKey = navigationKeys.includes(event.key) - const isEmptyEnter = isEnterKey && !hasText - - event.accepted = !(isNavigationKey || isEmptyEnter) - } - - Connections { - function onShouldBeVisibleChanged() { - if (!root.shouldBeVisible) { - searchField.focus = false - } - } - - target: root - } - } - - Rectangle { - width: parent.width - height: { - let usedHeight = 40 + Theme.spacingS - usedHeight += 52 + Theme.spacingS - if (root.showTargetData) { - usedHeight += 36 + Theme.spacingS - } - return parent.height - usedHeight - } - radius: Theme.cornerRadius - color: "transparent" - - DankListView { - id: appList - - property int itemHeight: 60 - property int itemSpacing: Theme.spacingS - - function ensureVisible(index) { - if (index < 0 || index >= count) return - - const itemY = index * (itemHeight + itemSpacing) - const itemBottom = itemY + itemHeight - if (itemY < contentY) { - contentY = itemY - } else if (itemBottom > contentY + height) { - contentY = itemBottom - height - } - } - - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - - visible: root.viewMode === "list" - model: applicationsModel - currentIndex: root.selectedIndex - clip: true - spacing: itemSpacing - - onCurrentIndexChanged: { - root.selectedIndex = currentIndex - if (root.keyboardNavigationActive) { - ensureVisible(currentIndex) - } - } - - delegate: AppLauncherListDelegate { - listView: appList - itemHeight: 60 - iconSize: 40 - showDescription: false - - isCurrentItem: index === root.selectedIndex - keyboardNavigationActive: root.keyboardNavigationActive - hoverUpdatesSelection: true - - onItemClicked: (idx, modelData) => { - launchApplication(modelData) - } - - onKeyboardNavigationReset: { - root.keyboardNavigationActive = false - } - } - } - - DankGridView { - id: appGrid - - function ensureVisible(index) { - if (index < 0 || index >= count) return - - const itemY = Math.floor(index / root.gridColumns) * cellHeight - const itemBottom = itemY + cellHeight - if (itemY < contentY) { - contentY = itemY - } else if (itemBottom > contentY + height) { - contentY = itemBottom - height - } - } - - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - - visible: root.viewMode === "grid" - model: applicationsModel - cellWidth: width / root.gridColumns - cellHeight: 120 - clip: true - currentIndex: root.selectedIndex - - onCurrentIndexChanged: { - root.selectedIndex = currentIndex - if (root.keyboardNavigationActive) { - ensureVisible(currentIndex) - } - } - - delegate: AppLauncherGridDelegate { - gridView: appGrid - cellWidth: appGrid.cellWidth - cellHeight: appGrid.cellHeight - - currentIndex: root.selectedIndex - keyboardNavigationActive: root.keyboardNavigationActive - hoverUpdatesSelection: true - - onItemClicked: (idx, modelData) => { - launchApplication(modelData) - } - - onKeyboardNavigationReset: { - root.keyboardNavigationActive = false - } - } - } - } - - Rectangle { - width: parent.width - height: 36 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, 0.5) - border.color: Theme.outlineMedium - border.width: 1 - visible: root.showTargetData && root.targetData.length > 0 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: root.targetDataLabel.length > 0 ? root.targetDataLabel + ": " + root.targetData : root.targetData - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideMiddle - wrapMode: Text.NoWrap - maximumLineCount: 1 - } - } - } - - function launchApplication(app) { - if (!app) return - - root.applicationSelected(app, root.targetData) - - if (usageHistoryKey && app.appId) { - const usageHistory = SettingsData[usageHistoryKey] || {} - const currentCount = usageHistory[app.appId] ? usageHistory[app.appId].count : 0 - usageHistory[app.appId] = { - count: currentCount + 1, - lastUsed: Date.now(), - name: app.name - } - SettingsData.set(usageHistoryKey, usageHistory) - } - - root.close() - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BluetoothPairingModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BluetoothPairingModal.qml deleted file mode 100644 index cd3c9b7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BluetoothPairingModal.qml +++ /dev/null @@ -1,409 +0,0 @@ -import QtQuick -import Quickshell.Hyprland -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:bluetooth-pairing" - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: root.useHyprlandFocusGrab && root.shouldHaveFocus - } - - property string deviceName: "" - property string deviceAddress: "" - property string requestType: "" - property string token: "" - property int passkey: 0 - property string pinInput: "" - property string passkeyInput: "" - - function show(pairingData) { - console.log("BluetoothPairingModal.show() called:", JSON.stringify(pairingData)); - token = pairingData.token || ""; - deviceName = pairingData.deviceName || ""; - deviceAddress = pairingData.deviceAddr || ""; - requestType = pairingData.requestType || ""; - passkey = pairingData.passkey || 0; - pinInput = ""; - passkeyInput = ""; - - console.log("BluetoothPairingModal: Calling open()"); - open(); - Qt.callLater(() => { - if (contentLoader.item) { - if (requestType === "pin" && contentLoader.item.pinInputField) { - contentLoader.item.pinInputField.forceActiveFocus(); - } else if (requestType === "passkey" && contentLoader.item.passkeyInputField) { - contentLoader.item.passkeyInputField.forceActiveFocus(); - } - } - }); - } - - shouldBeVisible: false - allowStacking: true - keepPopoutsOpen: true - modalWidth: 420 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 240 - - onShouldBeVisibleChanged: () => { - if (!shouldBeVisible) { - pinInput = ""; - passkeyInput = ""; - } - } - - onOpened: { - Qt.callLater(() => { - if (contentLoader.item) { - if (requestType === "pin" && contentLoader.item.pinInputField) { - contentLoader.item.pinInputField.forceActiveFocus(); - } else if (requestType === "passkey" && contentLoader.item.passkeyInputField) { - contentLoader.item.passkeyInputField.forceActiveFocus(); - } - } - }); - } - - onBackgroundClicked: () => { - if (token) { - DMSService.bluetoothCancelPairing(token); - } - close(); - token = ""; - pinInput = ""; - passkeyInput = ""; - } - - content: Component { - FocusScope { - id: pairingContent - - property alias pinInputField: pinInputField - property alias passkeyInputField: passkeyInputField - - anchors.fill: parent - focus: true - implicitHeight: mainColumn.implicitHeight - - Keys.onEscapePressed: event => { - if (token) { - DMSService.bluetoothCancelPairing(token); - } - close(); - token = ""; - pinInput = ""; - passkeyInput = ""; - event.accepted = true; - } - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingM - spacing: requestType === "pin" || requestType === "passkey" ? Theme.spacingM : Theme.spacingS - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Pair Bluetooth Device") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: { - switch (requestType) { - case "confirm": - return I18n.tr("Confirm passkey for ") + deviceName; - case "display-passkey": - return I18n.tr("Enter this passkey on ") + deviceName; - case "authorize": - return I18n.tr("Authorize pairing with ") + deviceName; - case "pin": - return I18n.tr("Enter PIN for ") + deviceName; - case "passkey": - return I18n.tr("Enter passkey for ") + deviceName; - default: - if (requestType.startsWith("authorize-service")) - return I18n.tr("Authorize service for ") + deviceName; - return deviceName; - } - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - 40 - elide: Text.ElideRight - } - } - - Rectangle { - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: pinInputField.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: pinInputField.activeFocus ? 2 : 1 - visible: requestType === "pin" - - MouseArea { - anchors.fill: parent - onClicked: () => { - pinInputField.forceActiveFocus(); - } - } - - DankTextField { - id: pinInputField - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: pinInput - placeholderText: I18n.tr("Enter PIN") - backgroundColor: "transparent" - enabled: root.shouldBeVisible - onTextEdited: () => { - pinInput = text; - } - onAccepted: () => { - submitPairing(); - } - } - } - - Rectangle { - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: passkeyInputField.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: passkeyInputField.activeFocus ? 2 : 1 - visible: requestType === "passkey" - - MouseArea { - anchors.fill: parent - onClicked: () => { - passkeyInputField.forceActiveFocus(); - } - } - - DankTextField { - id: passkeyInputField - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: passkeyInput - placeholderText: I18n.tr("Enter 6-digit passkey") - backgroundColor: "transparent" - enabled: root.shouldBeVisible - onTextEdited: () => { - passkeyInput = text; - } - onAccepted: () => { - submitPairing(); - } - } - } - - Rectangle { - width: parent.width - height: 56 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - visible: requestType === "confirm" || requestType === "display-passkey" - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: I18n.tr("Passkey:") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: String(passkey).padStart(6, "0") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: cancelText - - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - if (token) { - DMSService.bluetoothCancelPairing(token); - } - close(); - token = ""; - pinInput = ""; - passkeyInput = ""; - } - } - } - - Rectangle { - width: Math.max(80, pairText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: pairArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - enabled: { - if (requestType === "pin") - return pinInput.length > 0; - if (requestType === "passkey") - return passkeyInput.length === 6; - return true; - } - opacity: enabled ? 1 : 0.5 - - StyledText { - id: pairText - - anchors.centerIn: parent - text: { - switch (requestType) { - case "confirm": - case "display-passkey": - return I18n.tr("Confirm"); - case "authorize": - return I18n.tr("Authorize"); - default: - if (requestType.startsWith("authorize-service")) - return I18n.tr("Authorize"); - return I18n.tr("Pair"); - } - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: pairArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: () => { - submitPairing(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: () => { - if (token) { - DMSService.bluetoothCancelPairing(token); - } - close(); - token = ""; - pinInput = ""; - passkeyInput = ""; - } - } - } - } - - function submitPairing() { - const secrets = {}; - - switch (requestType) { - case "pin": - secrets["pin"] = pinInput; - break; - case "passkey": - secrets["passkey"] = passkeyInput; - break; - case "confirm": - case "display-passkey": - case "authorize": - secrets["decision"] = "yes"; - break; - default: - if (requestType.startsWith("authorize-service")) { - secrets["decision"] = "yes"; - } - break; - } - - DMSService.bluetoothSubmitPairing(token, secrets, true, response => { - if (response.error) { - ToastService.showError(I18n.tr("Pairing failed"), response.error); - } - }); - - close(); - token = ""; - pinInput = ""; - passkeyInput = ""; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BrowserPickerModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BrowserPickerModal.qml deleted file mode 100644 index e4afcb8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/BrowserPickerModal.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals - -AppPickerModal { - id: root - - property string url: "" - - title: I18n.tr("Open with...") - targetData: url - targetDataLabel: "" - categoryFilter: ["WebBrowser", "X-WebBrowser"] - viewMode: SettingsData.browserPickerViewMode || "grid" - usageHistoryKey: "browserUsageHistory" - showTargetData: true - - function shellEscape(str) { - return "'" + str.replace(/'/g, "'\\''") + "'" - } - - onApplicationSelected: (app, url) => { - if (!app) return - - let cmd = app.exec || "" - const escapedUrl = shellEscape(url) - - let hasField = false - if (cmd.includes("%u")) { cmd = cmd.replace("%u", escapedUrl); hasField = true } - else if (cmd.includes("%U")) { cmd = cmd.replace("%U", escapedUrl); hasField = true } - else if (cmd.includes("%f")) { cmd = cmd.replace("%f", escapedUrl); hasField = true } - else if (cmd.includes("%F")) { cmd = cmd.replace("%F", escapedUrl); hasField = true } - - cmd = cmd.replace(/%[ikc]/g, "") - - if (!hasField) { - cmd += " " + escapedUrl - } - - console.log("BrowserPicker: Launching", cmd) - - Quickshell.execDetached({ - command: ["sh", "-c", cmd] - }) - } - - onViewModeChanged: { - SettingsData.set("browserPickerViewMode", viewMode) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogContent.qml deleted file mode 100644 index 8fd3129..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogContent.qml +++ /dev/null @@ -1,250 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Column { - id: root - - readonly property real logoSize: Math.round(Theme.iconSize * 2.8) - readonly property real badgeHeight: Math.round(Theme.fontSizeSmall * 1.7) - - topPadding: Theme.spacingL - spacing: Theme.spacingL - - Column { - width: parent.width - spacing: Theme.spacingM - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Image { - width: root.logoSize - height: width * (569.94629 / 506.50931) - anchors.verticalCenter: parent.verticalCenter - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg" - layer.enabled: true - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingS - - StyledText { - text: "DMS " + ChangelogService.currentVersion - font.pixelSize: Theme.fontSizeXLarge + 2 - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - width: codenameText.implicitWidth + Theme.spacingM * 2 - height: root.badgeHeight - radius: root.badgeHeight / 2 - color: Theme.primaryContainer - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: codenameText - anchors.centerIn: parent - text: "Saffron Bloom" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - } - } - } - - StyledText { - text: "New launcher, enhanced plugin system, KDE Connect, & more" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.3 - } - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: "What's New" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Grid { - width: parent.width - columns: 2 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "space_dashboard" - title: "Dank Launcher V2" - description: "New capabilities & plugins" - onClicked: PopoutService.openDankLauncherV2() - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "smartphone" - title: "Phone Connect" - description: "KDE Connect & Valent" - onClicked: Qt.openUrlExternally("https://github.com/AvengeMedia/dms-plugins/tree/master/DankKDEConnect") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "monitor_heart" - title: "System Monitor" - description: "Redesigned process list" - onClicked: PopoutService.showProcessListModal() - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "window" - title: "Window Rules" - description: "niri window rule manager" - visible: CompositorService.isNiri - onClicked: PopoutService.openSettingsWithTab("window_rules") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "notifications_active" - title: "Enhanced Notifications" - description: "Configurable rules & styling" - visible: !CompositorService.isNiri - onClicked: PopoutService.openSettingsWithTab("notifications") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "dock_to_bottom" - title: "Dock Enhancements" - description: "Bar dock widget & more" - onClicked: PopoutService.openSettingsWithTab("dock") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "volume_up" - title: "Audio Aliases" - description: "Custom device names" - onClicked: PopoutService.openSettingsWithTab("audio") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "extension" - title: "Enhanced Plugin System" - description: "Enables new types of plugins" - onClicked: PopoutService.openSettingsWithTab("plugins") - } - - ChangelogFeatureCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "light_mode" - title: "Auto Light/Dark" - description: "Automatic mode switching" - onClicked: PopoutService.openSettingsWithTab("theme") - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.3 - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "warning" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "Upgrade Notes" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: parent.width - height: upgradeNotesColumn.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.warning, 0.08) - border.width: 1 - border.color: Theme.withAlpha(Theme.warning, 0.2) - - Column { - id: upgradeNotesColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - ChangelogUpgradeNote { - width: parent.width - text: "Spotlight replaced by Dank Launcher V2 — check settings for new options" - } - - ChangelogUpgradeNote { - width: parent.width - text: "Plugin API updated — third-party plugins may need updates" - } - } - } - - // StyledText { - // text: "See full release notes for migration steps" - // font.pixelSize: Theme.fontSizeSmall - // color: Theme.surfaceVariantText - // width: parent.width - // } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogFeatureCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogFeatureCard.qml deleted file mode 100644 index eab4f70..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogFeatureCard.qml +++ /dev/null @@ -1,78 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property string title: "" - property string description: "" - - signal clicked - - readonly property real iconContainerSize: Math.round(Theme.iconSize * 1.3) - - height: Math.round(Theme.fontSizeMedium * 4.2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Theme.primary - opacity: mouseArea.containsMouse ? 0.12 : 0 - } - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Rectangle { - width: root.iconContainerSize - height: root.iconContainerSize - radius: Math.round(root.iconContainerSize * 0.28) - color: Theme.primaryContainer - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: root.iconName - size: Theme.iconSize - 6 - color: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - root.iconContainerSize - Theme.spacingS - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogModal.qml deleted file mode 100644 index 524298b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogModal.qml +++ /dev/null @@ -1,156 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - readonly property int modalWidth: 680 - readonly property int modalHeight: screen ? Math.min(720, screen.height - 80) : 720 - - signal changelogDismissed - - function show() { - visible = true; - } - - objectName: "changelogModal" - title: i18n("What's New") - minimumSize: Qt.size(modalWidth, modalHeight) - maximumSize: Qt.size(modalWidth, modalHeight) - color: Theme.surfaceContainer - visible: false - - FocusScope { - id: contentFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - root.dismiss(); - event.accepted = true; - } - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Return: - case Qt.Key_Enter: - root.dismiss(); - event.accepted = true; - break; - } - } - - MouseArea { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: headerRow.height + Theme.spacingM - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Item { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - height: Math.round(Theme.fontSizeMedium * 2.85) - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported && windowControls.canMaximize - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.dismiss() - - DankTooltip { - text: i18n("Close") - } - } - } - } - - DankFlickable { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.bottom: footerRow.top - anchors.topMargin: Theme.spacingS - clip: true - contentHeight: mainColumn.height + Theme.spacingL * 2 - contentWidth: width - - ChangelogContent { - id: mainColumn - anchors.horizontalCenter: parent.horizontalCenter - width: Math.min(600, parent.width - Theme.spacingXL * 2) - } - } - - Rectangle { - id: footerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: Math.round(Theme.fontSizeMedium * 4.5) - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.top: parent.top - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.5 - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankButton { - text: i18n("Read Full Release Notes") - iconName: "open_in_new" - backgroundColor: Theme.surfaceContainerHighest - textColor: Theme.surfaceText - onClicked: Qt.openUrlExternally("https://danklinux.com/blog/v1-4-release") - } - - DankButton { - text: i18n("Got It") - iconName: "check" - backgroundColor: Theme.primary - textColor: Theme.primaryText - onClicked: root.dismiss() - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } - - function dismiss() { - ChangelogService.dismissChangelog(); - changelogDismissed(); - visible = false; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogUpgradeNote.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogUpgradeNote.qml deleted file mode 100644 index 545eb9a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Changelog/ChangelogUpgradeNote.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Row { - id: root - - property alias text: noteText.text - - spacing: Theme.spacingS - - DankIcon { - name: "arrow_right" - size: Theme.iconSizeSmall - 2 - color: Theme.surfaceVariantText - anchors.top: parent.top - anchors.topMargin: 2 - } - - StyledText { - id: noteText - width: root.width - Theme.iconSizeSmall - Theme.spacingS - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.WordWrap - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardConstants.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardConstants.qml deleted file mode 100644 index f796ffe..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardConstants.qml +++ /dev/null @@ -1,21 +0,0 @@ -pragma Singleton - -import QtQuick -import Quickshell - -Singleton { - id: root - readonly property int previewLength: 100 - readonly property int longTextThreshold: 200 - readonly property int modalWidth: 650 - readonly property int modalHeight: 550 - readonly property int popoutWidth: 550 - readonly property int popoutHeight: 500 - readonly property int itemHeight: 72 - readonly property int thumbnailSize: 100 - readonly property int retryInterval: 50 - readonly property int viewportBuffer: 100 - readonly property int extendedBuffer: 200 - readonly property int keyboardHintsHeight: 80 - readonly property int headerHeight: 32 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardContent.qml deleted file mode 100644 index e00bc22..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardContent.qml +++ /dev/null @@ -1,260 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: clipboardContent - - required property var modal - required property var clearConfirmDialog - - property alias searchField: searchField - property alias clipboardListView: clipboardListView - - anchors.fill: parent - - Column { - id: headerColumn - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - focus: false - - ClipboardHeader { - id: header - width: parent.width - totalCount: modal.totalCount - showKeyboardHints: modal.showKeyboardHints - activeTab: modal.activeTab - pinnedCount: modal.pinnedCount - onKeyboardHintsToggled: modal.showKeyboardHints = !modal.showKeyboardHints - onTabChanged: tabName => modal.activeTab = tabName - onClearAllClicked: { - const hasPinned = modal.pinnedCount > 0; - const message = hasPinned ? I18n.tr("This will delete all unpinned entries. %1 pinned entries will be kept.").arg(modal.pinnedCount) : I18n.tr("This will permanently delete all clipboard history."); - clearConfirmDialog.show(I18n.tr("Clear History?"), message, function () { - modal.clearAll(); - modal.hide(); - }, function () {}); - } - onCloseClicked: modal.hide() - } - - DankTextField { - id: searchField - width: parent.width - placeholderText: "" - leftIconName: "search" - showClearButton: true - focus: true - ignoreTabKeys: true - keyForwardTargets: [modal.modalFocusScope] - onTextChanged: { - modal.searchText = text; - modal.updateFilteredModel(); - } - Keys.onEscapePressed: function (event) { - modal.hide(); - event.accepted = true; - } - Component.onCompleted: { - Qt.callLater(function () { - forceActiveFocus(); - }); - } - - Connections { - target: modal - function onOpened() { - Qt.callLater(function () { - searchField.forceActiveFocus(); - }); - } - } - } - } - - Item { - id: listContainer - anchors.top: headerColumn.bottom - anchors.topMargin: Theme.spacingM - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.bottomMargin: (modal.showKeyboardHints ? (ClipboardConstants.keyboardHintsHeight + Theme.spacingM * 2) : 0) + Theme.spacingXS - clip: true - - DankListView { - id: clipboardListView - anchors.fill: parent - model: ScriptModel { - values: clipboardContent.modal.unpinnedEntries - objectProp: "id" - } - visible: modal.activeTab === "recents" - - currentIndex: clipboardContent.modal ? clipboardContent.modal.selectedIndex : 0 - spacing: Theme.spacingXS - interactive: true - flickDeceleration: 1500 - maximumFlickVelocity: 2000 - boundsBehavior: Flickable.DragAndOvershootBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - function ensureVisible(index) { - if (index < 0 || index >= count) { - return; - } - positionViewAtIndex(index, ListView.Contain); - } - - onCurrentIndexChanged: { - if (clipboardContent.modal?.keyboardNavigationActive && currentIndex >= 0) { - ensureVisible(currentIndex); - } - } - - StyledText { - text: clipboardContent.modal.clipboardAvailable ? I18n.tr("No recent clipboard entries found") : I18n.tr("Connecting to clipboard service…") - anchors.centerIn: parent - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: clipboardContent.modal.unpinnedEntries.length === 0 - } - - delegate: ClipboardEntry { - required property int index - required property var modelData - - width: clipboardListView.width - height: ClipboardConstants.itemHeight - entry: modelData - entryIndex: index + 1 - itemIndex: index - isSelected: clipboardContent.modal?.keyboardNavigationActive && index === clipboardContent.modal.selectedIndex - modal: clipboardContent.modal - listView: clipboardListView - onCopyRequested: clipboardContent.modal.copyEntry(modelData) - onDeleteRequested: clipboardContent.modal.deleteEntry(modelData) - onPinRequested: clipboardContent.modal.pinEntry(modelData) - onUnpinRequested: clipboardContent.modal.unpinEntry(modelData) - } - } - - DankListView { - id: savedListView - anchors.fill: parent - model: ScriptModel { - values: clipboardContent.modal.pinnedEntries - objectProp: "id" - } - visible: modal.activeTab === "saved" - - currentIndex: clipboardContent.modal ? clipboardContent.modal.selectedIndex : 0 - spacing: Theme.spacingXS - interactive: true - flickDeceleration: 1500 - maximumFlickVelocity: 2000 - boundsBehavior: Flickable.DragAndOvershootBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - function ensureVisible(index) { - if (index < 0 || index >= count) { - return; - } - positionViewAtIndex(index, ListView.Contain); - } - - onCurrentIndexChanged: { - if (clipboardContent.modal?.keyboardNavigationActive && currentIndex >= 0) { - ensureVisible(currentIndex); - } - } - - StyledText { - text: clipboardContent.modal.clipboardAvailable ? I18n.tr("No saved clipboard entries") : I18n.tr("Connecting to clipboard service…") - anchors.centerIn: parent - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: clipboardContent.modal.pinnedEntries.length === 0 - } - - delegate: ClipboardEntry { - required property int index - required property var modelData - - width: savedListView.width - height: ClipboardConstants.itemHeight - entry: modelData - entryIndex: index + 1 - itemIndex: index - isSelected: clipboardContent.modal?.keyboardNavigationActive && index === clipboardContent.modal.selectedIndex - modal: clipboardContent.modal - listView: savedListView - onCopyRequested: clipboardContent.modal.copyEntry(modelData) - onDeleteRequested: clipboardContent.modal.deletePinnedEntry(modelData) - onPinRequested: clipboardContent.modal.pinEntry(modelData) - onUnpinRequested: clipboardContent.modal.unpinEntry(modelData) - } - } - - Rectangle { - id: bottomFade - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 24 - z: 100 - visible: { - const listView = modal.activeTab === "recents" ? clipboardListView : savedListView; - if (listView.contentHeight <= listView.height) - return false; - const atBottom = listView.contentY >= listView.contentHeight - listView.height - 5; - return !atBottom; - } - gradient: Gradient { - GradientStop { - position: 0.0 - color: "transparent" - } - GradientStop { - position: 1.0 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - } - } - } - } - - Loader { - id: keyboardHintsLoader - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.bottomMargin: active ? Theme.spacingM : 0 - active: modal.showKeyboardHints - height: active ? ClipboardConstants.keyboardHintsHeight : 0 - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - sourceComponent: ClipboardKeyboardHints { - wtypeAvailable: modal.wtypeAvailable - enterToPaste: SettingsData.clipboardEnterToPaste - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardEntry.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardEntry.qml deleted file mode 100644 index 53a2ece..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardEntry.qml +++ /dev/null @@ -1,155 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - required property var entry - required property int entryIndex - required property int itemIndex - required property bool isSelected - required property var modal - required property var listView - - signal copyRequested - signal deleteRequested - signal pinRequested - signal unpinRequested - - readonly property string entryType: modal ? modal.getEntryType(entry) : "text" - readonly property string entryPreview: modal ? modal.getEntryPreview(entry) : "" - readonly property bool hasPinnedDuplicate: !entry.pinned && ClipboardService.hashedPinnedEntry(entry.hash) - - radius: Theme.cornerRadius - color: { - if (isSelected) { - return Theme.primaryPressed; - } - return mouseArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - - DankRipple { - id: rippleLayer - rippleColor: Theme.surfaceText - cornerRadius: root.radius - } - - Rectangle { - id: indexBadge - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 24 - height: 24 - radius: 12 - color: Theme.primarySelected - - StyledText { - anchors.centerIn: parent - text: entryIndex.toString() - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.primary - } - } - - Row { - id: actionButtons - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - iconName: "push_pin" - iconSize: Theme.iconSize - 6 - iconColor: (entry.pinned || hasPinnedDuplicate) ? Theme.primary : Theme.surfaceText - backgroundColor: (entry.pinned || hasPinnedDuplicate) ? Theme.primarySelected : "transparent" - onClicked: entry.pinned ? unpinRequested() : pinRequested() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 6 - iconColor: Theme.surfaceText - onClicked: deleteRequested() - } - } - - Item { - anchors.left: indexBadge.right - anchors.leftMargin: Theme.spacingM - anchors.right: actionButtons.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - // height: contentColumn.implicitHeight - height: ClipboardConstants.itemHeight - clip: true - - ClipboardThumbnail { - id: thumbnail - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - width: entryType === "image" ? ClipboardConstants.thumbnailSize : Theme.iconSize - height: entryType === "image" ? ClipboardConstants.itemHeight - 4 : Theme.iconSize // 100 - 4 = 96, 96:72 = 4:3 - entry: root.entry - entryType: root.entryType - modal: root.modal - listView: root.listView - itemIndex: root.itemIndex - } - - Column { - id: contentColumn - anchors.left: thumbnail.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: { - switch (entryType) { - case "image": - return I18n.tr("Image") + " • " + entryPreview; - case "long_text": - return I18n.tr("Long Text"); - default: - return I18n.tr("Text"); - } - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - width: parent.width - elide: Text.ElideRight - } - - StyledText { - text: entryPreview - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - maximumLineCount: entryType === "long_text" ? 3 : 1 - elide: Text.ElideRight - textFormat: Text.PlainText - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - anchors.rightMargin: 80 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - const pos = mouseArea.mapToItem(root, mouse.x, mouse.y); - rippleLayer.trigger(pos.x, pos.y); - } - onClicked: copyRequested() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHeader.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHeader.qml deleted file mode 100644 index fedba15..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHeader.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modals.Clipboard - -Item { - id: header - - property int totalCount: 0 - property bool showKeyboardHints: false - property string activeTab: "recents" - property int pinnedCount: 0 - - signal keyboardHintsToggled - signal clearAllClicked - signal closeClicked - signal tabChanged(string tabName) - - height: ClipboardConstants.headerHeight - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "content_paste" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Clipboard History") + ` (${totalCount})` - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - iconName: "push_pin" - iconSize: Theme.iconSize - 4 - iconColor: header.activeTab === "saved" ? Theme.primary : Theme.surfaceText - visible: header.pinnedCount > 0 - tooltipText: I18n.tr("Saved") - onClicked: tabChanged("saved") - } - - DankActionButton { - iconName: "history" - iconSize: Theme.iconSize - 4 - iconColor: header.activeTab === "recents" ? Theme.primary : Theme.surfaceText - tooltipText: I18n.tr("History") - onClicked: tabChanged("recents") - } - - DankActionButton { - iconName: "info" - iconSize: Theme.iconSize - 4 - iconColor: showKeyboardHints ? Theme.primary : Theme.surfaceText - tooltipText: I18n.tr("Keyboard Shortcuts") - onClicked: keyboardHintsToggled() - } - - DankActionButton { - iconName: "delete_sweep" - iconSize: Theme.iconSize - iconColor: Theme.surfaceText - tooltipText: I18n.tr("Clear All") - onClicked: clearAllClicked() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: closeClicked() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryModal.qml deleted file mode 100644 index 2f76cc7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryModal.qml +++ /dev/null @@ -1,174 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Hyprland -import qs.Common -import qs.Modals.Clipboard -import qs.Modals.Common -import qs.Services - -DankModal { - id: clipboardHistoryModal - - layerNamespace: "dms:clipboard" - - HyprlandFocusGrab { - windows: [clipboardHistoryModal.contentWindow] - active: clipboardHistoryModal.useHyprlandFocusGrab && clipboardHistoryModal.shouldHaveFocus - } - - property string activeTab: "recents" - onActiveTabChanged: { - ClipboardService.selectedIndex = 0; - ClipboardService.keyboardNavigationActive = false; - } - property bool showKeyboardHints: false - property Component clipboardContent - property int activeImageLoads: 0 - readonly property int maxConcurrentLoads: 3 - - readonly property bool clipboardAvailable: ClipboardService.clipboardAvailable - readonly property bool wtypeAvailable: ClipboardService.wtypeAvailable - readonly property int totalCount: ClipboardService.totalCount - readonly property var clipboardEntries: ClipboardService.clipboardEntries - readonly property var pinnedEntries: ClipboardService.pinnedEntries - readonly property int pinnedCount: ClipboardService.pinnedCount - readonly property var unpinnedEntries: ClipboardService.unpinnedEntries - readonly property int selectedIndex: ClipboardService.selectedIndex - readonly property bool keyboardNavigationActive: ClipboardService.keyboardNavigationActive - property string searchText: ClipboardService.searchText - onSearchTextChanged: ClipboardService.searchText = searchText - - Ref { - service: ClipboardService - } - - function updateFilteredModel() { - ClipboardService.updateFilteredModel(); - } - - function pasteSelected() { - ClipboardService.pasteSelected(instantClose); - } - - function toggle() { - if (shouldBeVisible) { - hide(); - } else { - show(); - } - } - - function show() { - open(); - activeImageLoads = 0; - shouldHaveFocus = true; - ClipboardService.reset(); - if (clipboardAvailable) - ClipboardService.refresh(); - keyboardController.reset(); - - Qt.callLater(function () { - if (contentLoader.item?.searchField) { - contentLoader.item.searchField.text = ""; - contentLoader.item.searchField.forceActiveFocus(); - } - }); - } - - function hide() { - close(); - } - - onDialogClosed: { - activeImageLoads = 0; - ClipboardService.reset(); - keyboardController.reset(); - } - - function refreshClipboard() { - ClipboardService.refresh(); - } - - function copyEntry(entry) { - ClipboardService.copyEntry(entry, hide); - } - - function deleteEntry(entry) { - ClipboardService.deleteEntry(entry); - } - - function deletePinnedEntry(entry) { - ClipboardService.deletePinnedEntry(entry, clearConfirmDialog); - } - - function pinEntry(entry) { - ClipboardService.pinEntry(entry); - } - - function unpinEntry(entry) { - ClipboardService.unpinEntry(entry); - } - - function clearAll() { - ClipboardService.clearAll(); - } - - function getEntryPreview(entry) { - return ClipboardService.getEntryPreview(entry); - } - - function getEntryType(entry) { - return ClipboardService.getEntryType(entry); - } - - visible: false - modalWidth: ClipboardConstants.modalWidth - modalHeight: ClipboardConstants.modalHeight - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - cornerRadius: Theme.cornerRadius - borderColor: Theme.outlineMedium - borderWidth: 1 - enableShadow: true - onBackgroundClicked: hide() - modalFocusScope.Keys.onPressed: function (event) { - keyboardController.handleKey(event); - } - content: clipboardContent - - ClipboardKeyboardController { - id: keyboardController - modal: clipboardHistoryModal - } - - ConfirmModal { - id: clearConfirmDialog - confirmButtonText: I18n.tr("Clear All") - confirmButtonColor: Theme.primary - onVisibleChanged: { - if (visible) { - clipboardHistoryModal.shouldHaveFocus = false; - return; - } - Qt.callLater(function () { - if (!clipboardHistoryModal.shouldBeVisible) { - return; - } - clipboardHistoryModal.shouldHaveFocus = true; - clipboardHistoryModal.modalFocusScope.forceActiveFocus(); - if (clipboardHistoryModal.contentLoader.item?.searchField) { - clipboardHistoryModal.contentLoader.item.searchField.forceActiveFocus(); - } - }); - } - } - - property var confirmDialog: clearConfirmDialog - - clipboardContent: Component { - ClipboardContent { - modal: clipboardHistoryModal - clearConfirmDialog: clipboardHistoryModal.confirmDialog - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryPopout.qml deleted file mode 100644 index c4f0296..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardHistoryPopout.qml +++ /dev/null @@ -1,197 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Modals.Clipboard -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:clipboard-popout" - - property var parentWidget: null - property var triggerScreen: null - property string activeTab: "recents" - property bool showKeyboardHints: false - property int activeImageLoads: 0 - readonly property int maxConcurrentLoads: 3 - - readonly property bool clipboardAvailable: ClipboardService.clipboardAvailable - readonly property bool wtypeAvailable: ClipboardService.wtypeAvailable - readonly property int totalCount: ClipboardService.totalCount - readonly property var clipboardEntries: ClipboardService.clipboardEntries - readonly property var pinnedEntries: ClipboardService.pinnedEntries - readonly property int pinnedCount: ClipboardService.pinnedCount - readonly property var unpinnedEntries: ClipboardService.unpinnedEntries - readonly property int selectedIndex: ClipboardService.selectedIndex - readonly property bool keyboardNavigationActive: ClipboardService.keyboardNavigationActive - property string searchText: ClipboardService.searchText - onSearchTextChanged: ClipboardService.searchText = searchText - - readonly property var modalFocusScope: contentLoader.item ?? null - - Ref { - service: ClipboardService - } - - function updateFilteredModel() { - ClipboardService.updateFilteredModel(); - } - - function pasteSelected() { - ClipboardService.pasteSelected(instantClose); - } - - function instantClose() { - close(); - } - - function show() { - open(); - activeImageLoads = 0; - ClipboardService.reset(); - if (clipboardAvailable) - ClipboardService.refresh(); - keyboardController.reset(); - - Qt.callLater(function () { - if (contentLoader.item?.searchField) { - contentLoader.item.searchField.text = ""; - contentLoader.item.searchField.forceActiveFocus(); - } - }); - } - - function hide() { - close(); - activeImageLoads = 0; - ClipboardService.reset(); - keyboardController.reset(); - } - - function refreshClipboard() { - ClipboardService.refresh(); - } - - function copyEntry(entry) { - ClipboardService.copyEntry(entry, hide); - } - - function deleteEntry(entry) { - ClipboardService.deleteEntry(entry); - } - - function deletePinnedEntry(entry) { - ClipboardService.deletePinnedEntry(entry, clearConfirmDialog); - } - - function pinEntry(entry) { - ClipboardService.pinEntry(entry); - } - - function unpinEntry(entry) { - ClipboardService.unpinEntry(entry); - } - - function clearAll() { - ClipboardService.clearAll(); - } - - function getEntryPreview(entry) { - return ClipboardService.getEntryPreview(entry); - } - - function getEntryType(entry) { - return ClipboardService.getEntryType(entry); - } - - popupWidth: ClipboardConstants.popoutWidth - popupHeight: ClipboardConstants.popoutHeight - triggerWidth: 55 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - contentHandlesKeys: true - - onBackgroundClicked: hide() - - onShouldBeVisibleChanged: { - if (!shouldBeVisible) - return; - if (clipboardAvailable) - ClipboardService.refresh(); - keyboardController.reset(); - Qt.callLater(function () { - if (contentLoader.item?.searchField) { - contentLoader.item.searchField.text = ""; - contentLoader.item.searchField.forceActiveFocus(); - } - }); - } - - onPopoutClosed: { - activeImageLoads = 0; - ClipboardService.reset(); - keyboardController.reset(); - } - - ClipboardKeyboardController { - id: keyboardController - modal: root - } - - ConfirmModal { - id: clearConfirmDialog - confirmButtonText: I18n.tr("Clear All") - confirmButtonColor: Theme.primary - } - - property var confirmDialog: clearConfirmDialog - - content: Component { - FocusScope { - id: contentFocusScope - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - focus: true - - property alias searchField: clipboardContentItem.searchField - - Keys.onPressed: function (event) { - keyboardController.handleKey(event); - } - - Component.onCompleted: { - if (root.shouldBeVisible) - forceActiveFocus(); - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => contentFocusScope.forceActiveFocus()); - } - } - function onOpened() { - Qt.callLater(() => { - if (clipboardContentItem.searchField) { - clipboardContentItem.searchField.forceActiveFocus(); - } - }); - } - } - - ClipboardContent { - id: clipboardContentItem - modal: root - clearConfirmDialog: root.confirmDialog - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardController.qml deleted file mode 100644 index f2a457e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardController.qml +++ /dev/null @@ -1,166 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services - -QtObject { - id: keyboardController - - required property var modal - - function reset() { - ClipboardService.selectedIndex = 0; - ClipboardService.keyboardNavigationActive = false; - modal.showKeyboardHints = false; - } - - function selectNext() { - const entries = modal.activeTab === "saved" ? ClipboardService.pinnedEntries : ClipboardService.unpinnedEntries; - if (!entries || entries.length === 0) { - return; - } - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = Math.min(ClipboardService.selectedIndex + 1, entries.length - 1); - } - - function selectPrevious() { - const entries = modal.activeTab === "saved" ? ClipboardService.pinnedEntries : ClipboardService.unpinnedEntries; - if (!entries || entries.length === 0) { - return; - } - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = Math.max(ClipboardService.selectedIndex - 1, 0); - } - - function copySelected() { - const entries = modal.activeTab === "saved" ? ClipboardService.pinnedEntries : ClipboardService.unpinnedEntries; - if (!entries || entries.length === 0 || ClipboardService.selectedIndex < 0 || ClipboardService.selectedIndex >= entries.length) { - return; - } - const selectedEntry = entries[ClipboardService.selectedIndex]; - modal.copyEntry(selectedEntry); - } - - function deleteSelected() { - const entries = modal.activeTab === "saved" ? ClipboardService.pinnedEntries : ClipboardService.unpinnedEntries; - if (!entries || entries.length === 0 || ClipboardService.selectedIndex < 0 || ClipboardService.selectedIndex >= entries.length) { - return; - } - const selectedEntry = entries[ClipboardService.selectedIndex]; - if (modal.activeTab === "saved") { - modal.deletePinnedEntry(selectedEntry); - } else { - modal.deleteEntry(selectedEntry); - } - } - - function handleKey(event) { - switch (event.key) { - case Qt.Key_Escape: - if (ClipboardService.keyboardNavigationActive) { - ClipboardService.keyboardNavigationActive = false; - } else { - modal.hide(); - } - event.accepted = true; - return; - case Qt.Key_Down: - case Qt.Key_Tab: - if (!ClipboardService.keyboardNavigationActive) { - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = 0; - } else { - selectNext(); - } - event.accepted = true; - return; - case Qt.Key_Up: - case Qt.Key_Backtab: - if (!ClipboardService.keyboardNavigationActive) { - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = 0; - } else if (ClipboardService.selectedIndex === 0) { - ClipboardService.keyboardNavigationActive = false; - } else { - selectPrevious(); - } - event.accepted = true; - return; - case Qt.Key_F10: - modal.showKeyboardHints = !modal.showKeyboardHints; - event.accepted = true; - return; - } - - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - if (!ClipboardService.keyboardNavigationActive) { - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = 0; - } else { - selectNext(); - } - event.accepted = true; - return; - case Qt.Key_P: - case Qt.Key_K: - if (!ClipboardService.keyboardNavigationActive) { - ClipboardService.keyboardNavigationActive = true; - ClipboardService.selectedIndex = 0; - } else if (ClipboardService.selectedIndex === 0) { - ClipboardService.keyboardNavigationActive = false; - } else { - selectPrevious(); - } - event.accepted = true; - return; - case Qt.Key_C: - if (ClipboardService.keyboardNavigationActive) { - copySelected(); - event.accepted = true; - } - return; - } - } - - if (event.modifiers & Qt.ShiftModifier) { - switch (event.key) { - case Qt.Key_Delete: - modal.clearAll(); - modal.hide(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (ClipboardService.keyboardNavigationActive) { - if (SettingsData.clipboardEnterToPaste) { - copySelected(); - } else { - modal.pasteSelected(); - } - event.accepted = true; - } - return; - } - } - - if (ClipboardService.keyboardNavigationActive) { - switch (event.key) { - case Qt.Key_Return: - case Qt.Key_Enter: - if (SettingsData.clipboardEnterToPaste) { - modal.pasteSelected(); - } else { - copySelected(); - } - event.accepted = true; - return; - case Qt.Key_Delete: - deleteSelected(); - event.accepted = true; - return; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml deleted file mode 100644 index 0285952..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: keyboardHints - - property bool wtypeAvailable: false - property bool enterToPaste: false - readonly property string hintsText: { - if (!wtypeAvailable) - return I18n.tr("Shift+Del: Clear All • Esc: Close"); - return enterToPaste ? I18n.tr("Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close"); - } - - height: ClipboardConstants.keyboardHintsHeight - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Theme.primary - border.width: 2 - opacity: visible ? 1 : 0 - z: 100 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: keyboardHints.enterToPaste - ? I18n.tr("↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", "Keyboard hints when enter-to-paste is enabled") - : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: keyboardHints.hintsText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardThumbnail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardThumbnail.qml deleted file mode 100644 index 26a9210..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Clipboard/ClipboardThumbnail.qml +++ /dev/null @@ -1,178 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: thumbnail - - required property var entry - required property string entryType - required property var modal - required property var listView - required property int itemIndex - - Image { - id: thumbnailImage - - property bool isVisible: false - property string cachedImageData: "" - property bool loadQueued: false - - anchors.fill: parent - source: cachedImageData ? `data:image/png;base64,${cachedImageData}` : "" - fillMode: Image.PreserveAspectCrop - smooth: true - cache: false - visible: false - asynchronous: true - sourceSize.width: 128 - sourceSize.height: 128 - - function tryLoadImage() { - if (thumbnailImage.loadQueued || entryType !== "image" || thumbnailImage.cachedImageData) { - return; - } - thumbnailImage.loadQueued = true; - if (modal.activeImageLoads < modal.maxConcurrentLoads) { - modal.activeImageLoads++; - thumbnailImage.loadImage(); - } else { - retryTimer.restart(); - } - } - - function loadImage() { - DMSService.sendRequest("clipboard.getEntry", { - "id": entry.id - }, function (response) { - thumbnailImage.loadQueued = false; - if (modal.activeImageLoads > 0) { - modal.activeImageLoads--; - } - if (response.error) { - console.warn("ClipboardThumbnail: Failed to load image:", entry.id); - return; - } - const data = response.result?.data; - if (data) { - thumbnailImage.cachedImageData = data; - } - }); - } - - Timer { - id: retryTimer - interval: ClipboardConstants.retryInterval - onTriggered: { - if (!thumbnailImage.loadQueued) { - return; - } - if (modal.activeImageLoads < modal.maxConcurrentLoads) { - modal.activeImageLoads++; - thumbnailImage.loadImage(); - } else { - retryTimer.restart(); - } - } - } - - Component.onCompleted: { - if (entryType !== "image" || listView.height <= 0) { - return; - } - - const itemY = itemIndex * (ClipboardConstants.itemHeight + listView.spacing); - const viewTop = listView.contentY; - const viewBottom = viewTop + listView.height; - isVisible = (itemY + ClipboardConstants.itemHeight >= viewTop && itemY <= viewBottom); - - if (isVisible) { - tryLoadImage(); - } - } - - Timer { - id: visibilityTimer - interval: 100 - onTriggered: thumbnailImage.checkVisibility() - } - - function checkVisibility() { - if (entryType !== "image" || listView.height <= 0 || isVisible) { - return; - } - const itemY = itemIndex * (ClipboardConstants.itemHeight + listView.spacing); - const viewTop = listView.contentY - ClipboardConstants.viewportBuffer; - const viewBottom = viewTop + listView.height + ClipboardConstants.extendedBuffer; - const nowVisible = (itemY + ClipboardConstants.itemHeight >= viewTop && itemY <= viewBottom); - if (nowVisible) { - isVisible = true; - tryLoadImage(); - } - } - - Connections { - target: listView - - function onContentYChanged() { - if (thumbnailImage.isVisible || entryType !== "image") { - return; - } - visibilityTimer.restart(); - } - - function onHeightChanged() { - if (thumbnailImage.isVisible || entryType !== "image") { - return; - } - visibilityTimer.restart(); - } - } - } - - MultiEffect { - anchors.fill: parent - anchors.margins: 2 - source: thumbnailImage - maskEnabled: true - maskSource: clipboardRoundedRectangularMask - visible: entryType === "image" && thumbnailImage.status === Image.Ready && thumbnailImage.source != "" - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - - Item { - id: clipboardRoundedRectangularMask - width: ClipboardConstants.thumbnailSize - height: ClipboardConstants.itemHeight - 4 - layer.enabled: true - layer.smooth: true - visible: false - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius / 2 // Thumbnail corner radius is divided by 2 so it doesnt look weird on large corner radius (eg: 32px) - color: "black" - antialiasing: true - } - } - - DankIcon { - visible: !(entryType === "image" && thumbnailImage.status === Image.Ready && thumbnailImage.source != "") - name: { - switch (entryType) { - case "image": - return "image"; - case "long_text": - return "subject"; - default: - return "content_copy"; - } - } - size: Theme.iconSize - color: Theme.primary - anchors.centerIn: parent - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/ConfirmModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/ConfirmModal.qml deleted file mode 100644 index b9c9b90..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/ConfirmModal.qml +++ /dev/null @@ -1,291 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.Common -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:confirm-modal" - keepPopoutsOpen: true - - property string confirmTitle: "" - property string confirmMessage: "" - property string confirmButtonText: "Confirm" - property string cancelButtonText: "Cancel" - property color confirmButtonColor: Theme.primary - property var onConfirm: function () {} - property var onCancel: function () {} - property int selectedButton: -1 - property bool keyboardNavigation: false - - function show(title, message, onConfirmCallback, onCancelCallback) { - confirmTitle = title || ""; - confirmMessage = message || ""; - confirmButtonText = "Confirm"; - cancelButtonText = "Cancel"; - confirmButtonColor = Theme.primary; - onConfirm = onConfirmCallback || (() => {}); - onCancel = onCancelCallback || (() => {}); - selectedButton = -1; - keyboardNavigation = false; - open(); - } - - function showWithOptions(options) { - confirmTitle = options.title || ""; - confirmMessage = options.message || ""; - confirmButtonText = options.confirmText || "Confirm"; - cancelButtonText = options.cancelText || "Cancel"; - confirmButtonColor = options.confirmColor || Theme.primary; - onConfirm = options.onConfirm || (() => {}); - onCancel = options.onCancel || (() => {}); - selectedButton = -1; - keyboardNavigation = false; - open(); - } - - function selectButton() { - close(); - if (selectedButton === 0) { - if (onCancel) { - onCancel(); - } - } else { - if (onConfirm) { - onConfirm(); - } - } - } - - shouldBeVisible: false - allowStacking: true - modalWidth: 350 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 160 - enableShadow: true - shouldHaveFocus: true - onBackgroundClicked: { - close(); - if (onCancel) { - onCancel(); - } - } - onOpened: { - Qt.callLater(function () { - modalFocusScope.forceActiveFocus(); - modalFocusScope.focus = true; - shouldHaveFocus = true; - }); - } - modalFocusScope.Keys.onPressed: function (event) { - switch (event.key) { - case Qt.Key_Escape: - close(); - if (onCancel) { - onCancel(); - } - event.accepted = true; - break; - case Qt.Key_Left: - case Qt.Key_Up: - keyboardNavigation = true; - selectedButton = 0; - event.accepted = true; - break; - case Qt.Key_Right: - case Qt.Key_Down: - keyboardNavigation = true; - selectedButton = 1; - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = (selectedButton + 1) % 2; - event.accepted = true; - } - break; - case Qt.Key_P: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = selectedButton === -1 ? 1 : (selectedButton - 1 + 2) % 2; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = 1; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = 0; - event.accepted = true; - } - break; - case Qt.Key_H: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = 0; - event.accepted = true; - } - break; - case Qt.Key_L: - if (event.modifiers & Qt.ControlModifier) { - keyboardNavigation = true; - selectedButton = 1; - event.accepted = true; - } - break; - case Qt.Key_Tab: - keyboardNavigation = true; - selectedButton = selectedButton === -1 ? 0 : (selectedButton + 1) % 2; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - if (selectedButton !== -1) { - selectButton(); - } else { - selectedButton = 1; - selectButton(); - } - event.accepted = true; - break; - } - } - - content: Component { - Item { - anchors.fill: parent - implicitHeight: mainColumn.implicitHeight - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - anchors.topMargin: Theme.spacingL - spacing: 0 - - StyledText { - text: confirmTitle - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignHCenter - } - - Item { - width: 1 - height: Theme.spacingL - } - - StyledText { - text: confirmMessage - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } - - Item { - width: 1 - height: Theme.spacingL * 1.5 - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Rectangle { - width: 120 - height: 40 - radius: Theme.cornerRadius - color: { - if (keyboardNavigation && selectedButton === 0) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - } else if (cancelButton.containsMouse) { - return Theme.surfacePressed; - } else { - return Theme.surfaceVariantAlpha; - } - } - border.color: (keyboardNavigation && selectedButton === 0) ? Theme.primary : "transparent" - border.width: (keyboardNavigation && selectedButton === 0) ? 1 : 0 - - StyledText { - text: cancelButtonText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: cancelButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - selectedButton = 0; - selectButton(); - } - } - } - - Rectangle { - width: 120 - height: 40 - radius: Theme.cornerRadius - color: { - const baseColor = confirmButtonColor; - if (keyboardNavigation && selectedButton === 1) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 1); - } else if (confirmButton.containsMouse) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 0.9); - } else { - return baseColor; - } - } - border.color: (keyboardNavigation && selectedButton === 1) ? "white" : "transparent" - border.width: (keyboardNavigation && selectedButton === 1) ? 1 : 0 - - StyledText { - text: confirmButtonText - font.pixelSize: Theme.fontSizeMedium - color: Theme.primaryText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: confirmButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - selectedButton = 1; - selectButton(); - } - } - } - } - - Item { - width: 1 - height: Theme.spacingL - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/DankModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/DankModal.qml deleted file mode 100644 index cafa133..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/DankModal.qml +++ /dev/null @@ -1,496 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string layerNamespace: "dms:modal" - property alias content: contentLoader.sourceComponent - property alias contentLoader: contentLoader - property Item directContent: null - property real modalWidth: 400 - property real modalHeight: 300 - property var targetScreen - readonly property var effectiveScreen: contentWindow.screen ?? targetScreen - readonly property real screenWidth: effectiveScreen?.width ?? 1920 - readonly property real screenHeight: effectiveScreen?.height ?? 1080 - readonly property real dpr: effectiveScreen ? CompositorService.getScreenScale(effectiveScreen) : 1 - property bool showBackground: true - property real backgroundOpacity: 0.5 - property string positioning: "center" - property point customPosition: Qt.point(0, 0) - property bool closeOnEscapeKey: true - property bool closeOnBackgroundClick: true - property string animationType: "scale" - property int animationDuration: Theme.modalAnimationDuration - property real animationScaleCollapsed: 0.96 - property real animationOffset: Theme.spacingL - property list animationEnterCurve: Theme.expressiveCurves.expressiveDefaultSpatial - property list animationExitCurve: Theme.expressiveCurves.emphasized - property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - property color borderColor: Theme.outlineMedium - property real borderWidth: 0 - property real cornerRadius: Theme.cornerRadius - property bool enableShadow: true - property alias modalFocusScope: focusScope - property bool shouldBeVisible: false - property bool shouldHaveFocus: shouldBeVisible - property bool allowFocusOverride: false - property bool allowStacking: false - property bool keepContentLoaded: false - property bool keepPopoutsOpen: false - property var customKeyboardFocus: null - property bool useOverlayLayer: false - readonly property alias contentWindow: contentWindow - readonly property alias clickCatcher: clickCatcher - readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab - readonly property bool useBackground: showBackground && SettingsData.modalDarkenBackground - readonly property bool useSingleWindow: CompositorService.isHyprland || useBackground - - signal opened - signal dialogClosed - signal backgroundClicked - - property bool animationsEnabled: true - - function open() { - closeTimer.stop(); - const focusedScreen = CompositorService.getFocusedScreen(); - const screenChanged = focusedScreen && contentWindow.screen !== focusedScreen; - if (focusedScreen) { - if (screenChanged) - contentWindow.visible = false; - contentWindow.screen = focusedScreen; - if (!useSingleWindow) { - if (screenChanged) - clickCatcher.visible = false; - clickCatcher.screen = focusedScreen; - } - } - if (screenChanged) { - Qt.callLater(() => root._finishOpen()); - } else { - _finishOpen(); - } - } - - function _finishOpen() { - ModalManager.openModal(root); - shouldBeVisible = true; - if (!useSingleWindow) - clickCatcher.visible = true; - contentWindow.visible = true; - shouldHaveFocus = false; - Qt.callLater(() => shouldHaveFocus = Qt.binding(() => shouldBeVisible)); - } - - function close() { - shouldBeVisible = false; - shouldHaveFocus = false; - ModalManager.closeModal(root); - closeTimer.restart(); - } - - function instantClose() { - animationsEnabled = false; - shouldBeVisible = false; - shouldHaveFocus = false; - ModalManager.closeModal(root); - closeTimer.stop(); - contentWindow.visible = false; - if (!useSingleWindow) - clickCatcher.visible = false; - dialogClosed(); - Qt.callLater(() => animationsEnabled = true); - } - - function toggle() { - shouldBeVisible ? close() : open(); - } - - Connections { - target: ModalManager - function onCloseAllModalsExcept(excludedModal) { - if (excludedModal !== root && !allowStacking && shouldBeVisible) - close(); - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - if (!contentWindow.screen) - return; - const currentScreenName = contentWindow.screen.name; - let screenStillExists = false; - for (let i = 0; i < Quickshell.screens.length; i++) { - if (Quickshell.screens[i].name === currentScreenName) { - screenStillExists = true; - break; - } - } - if (screenStillExists) - return; - const newScreen = CompositorService.getFocusedScreen(); - if (newScreen) { - contentWindow.screen = newScreen; - if (!useSingleWindow) - clickCatcher.screen = newScreen; - } - } - } - - Timer { - id: closeTimer - interval: animationDuration + 50 - onTriggered: { - if (shouldBeVisible) - return; - contentWindow.visible = false; - if (!useSingleWindow) - clickCatcher.visible = false; - dialogClosed(); - } - } - - readonly property var shadowLevel: Theme.elevationLevel3 - readonly property real shadowFallbackOffset: 6 - readonly property real shadowRenderPadding: (root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, Theme.elevationLightDirection, shadowFallbackOffset, 8, 16) : 0 - readonly property real shadowMotionPadding: animationType === "slide" ? 30 : Math.max(0, animationOffset) - readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr) - readonly property real alignedWidth: Theme.px(modalWidth, dpr) - readonly property real alignedHeight: Theme.px(modalHeight, dpr) - - readonly property real alignedX: Theme.snap((() => { - switch (positioning) { - case "center": - return (screenWidth - alignedWidth) / 2; - case "top-right": - return Math.max(Theme.spacingL, screenWidth - alignedWidth - Theme.spacingL); - case "custom": - return customPosition.x; - default: - return 0; - } - })(), dpr) - - readonly property real alignedY: Theme.snap((() => { - switch (positioning) { - case "center": - return (screenHeight - alignedHeight) / 2; - case "top-right": - return Theme.barHeight + Theme.spacingXS; - case "custom": - return customPosition.y; - default: - return 0; - } - })(), dpr) - - PanelWindow { - id: clickCatcher - visible: false - color: "transparent" - - WlrLayershell.namespace: root.layerNamespace + ":clickcatcher" - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - top: true - left: true - right: true - bottom: true - } - - mask: Region { - item: Rectangle { - x: root.alignedX - y: root.alignedY - width: root.alignedWidth - height: root.alignedHeight - } - intersection: Intersection.Xor - } - - MouseArea { - anchors.fill: parent - enabled: root.closeOnBackgroundClick && root.shouldBeVisible - onClicked: root.backgroundClicked() - } - } - - PanelWindow { - id: contentWindow - visible: false - color: "transparent" - - WindowBlur { - targetWindow: contentWindow - readonly property real s: Math.min(1, modalContainer.scaleValue) - blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr) - blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr) - blurWidth: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.width * s : 0 - blurHeight: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.height * s : 0 - blurRadius: root.cornerRadius - } - - WlrLayershell.namespace: root.layerNamespace - WlrLayershell.layer: { - if (root.useOverlayLayer) - return WlrLayershell.Overlay; - switch (Quickshell.env("DMS_MODAL_LAYER")) { - case "bottom": - console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "background": - console.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "overlay": - return WlrLayershell.Overlay; - default: - return WlrLayershell.Top; - } - } - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (customKeyboardFocus !== null) - return customKeyboardFocus; - if (!shouldHaveFocus) - return WlrKeyboardFocus.None; - if (root.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - anchors { - left: true - top: true - right: root.useSingleWindow - bottom: root.useSingleWindow - } - - WlrLayershell.margins { - left: root.useSingleWindow ? 0 : Math.max(0, Theme.snap(root.alignedX - shadowBuffer, dpr)) - top: root.useSingleWindow ? 0 : Math.max(0, Theme.snap(root.alignedY - shadowBuffer, dpr)) - right: 0 - bottom: 0 - } - - implicitWidth: root.useSingleWindow ? 0 : root.alignedWidth + (shadowBuffer * 2) - implicitHeight: root.useSingleWindow ? 0 : root.alignedHeight + (shadowBuffer * 2) - - onVisibleChanged: { - if (visible) { - opened(); - } else { - if (Qt.inputMethod) { - Qt.inputMethod.hide(); - Qt.inputMethod.reset(); - } - } - } - - MouseArea { - anchors.fill: parent - enabled: root.useSingleWindow && root.closeOnBackgroundClick && root.shouldBeVisible - z: -2 - onClicked: root.backgroundClicked() - } - - Rectangle { - anchors.fill: parent - z: -1 - color: "black" - opacity: root.useBackground ? (root.shouldBeVisible ? root.backgroundOpacity : 0) : 0 - visible: root.useBackground - - Behavior on opacity { - enabled: root.animationsEnabled - DankAnim { - duration: root.animationDuration - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - } - - Item { - id: modalContainer - x: root.useSingleWindow ? root.alignedX : shadowBuffer - y: root.useSingleWindow ? root.alignedY : shadowBuffer - - width: root.alignedWidth - height: root.alignedHeight - - MouseArea { - anchors.fill: parent - enabled: root.useSingleWindow && root.shouldBeVisible - hoverEnabled: false - acceptedButtons: Qt.AllButtons - onPressed: mouse.accepted = true - onClicked: mouse.accepted = true - z: -1 - } - - readonly property bool slide: root.animationType === "slide" - readonly property real offsetX: slide ? 15 : 0 - readonly property real offsetY: slide ? -30 : root.animationOffset - - property real animX: 0 - property real animY: 0 - property real scaleValue: root.animationScaleCollapsed - - onOffsetXChanged: animX = Theme.snap(root.shouldBeVisible ? 0 : offsetX, root.dpr) - onOffsetYChanged: animY = Theme.snap(root.shouldBeVisible ? 0 : offsetY, root.dpr) - - Connections { - target: root - function onShouldBeVisibleChanged() { - modalContainer.animX = Theme.snap(root.shouldBeVisible ? 0 : modalContainer.offsetX, root.dpr); - modalContainer.animY = Theme.snap(root.shouldBeVisible ? 0 : modalContainer.offsetY, root.dpr); - modalContainer.scaleValue = root.shouldBeVisible ? 1.0 : root.animationScaleCollapsed; - } - } - - Behavior on animX { - enabled: root.animationsEnabled - DankAnim { - duration: root.animationDuration - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Behavior on animY { - enabled: root.animationsEnabled - DankAnim { - duration: root.animationDuration - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Behavior on scaleValue { - enabled: root.animationsEnabled - DankAnim { - duration: root.animationDuration - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Item { - id: contentContainer - anchors.centerIn: parent - width: parent.width - height: parent.height - clip: false - - Item { - id: animatedContent - anchors.fill: parent - clip: false - opacity: root.shouldBeVisible ? 1 : 0 - scale: modalContainer.scaleValue - x: Theme.snap(modalContainer.animX, root.dpr) + (parent.width - width) * (1 - modalContainer.scaleValue) * 0.5 - y: Theme.snap(modalContainer.animY, root.dpr) + (parent.height - height) * (1 - modalContainer.scaleValue) * 0.5 - - Behavior on opacity { - enabled: root.animationsEnabled - NumberAnimation { - duration: animationDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - ElevationShadow { - id: modalShadowLayer - anchors.fill: parent - level: root.shadowLevel - fallbackOffset: root.shadowFallbackOffset - targetRadius: root.cornerRadius - targetColor: root.backgroundColor - borderColor: root.borderColor - borderWidth: root.borderWidth - shadowEnabled: root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - } - - Rectangle { - anchors.fill: parent - radius: root.cornerRadius - color: "transparent" - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - FocusScope { - anchors.fill: parent - focus: root.shouldBeVisible - clip: false - - Item { - id: directContentWrapper - anchors.fill: parent - visible: root.directContent !== null - focus: true - clip: false - - Component.onCompleted: { - if (root.directContent) { - root.directContent.parent = directContentWrapper; - root.directContent.anchors.fill = directContentWrapper; - Qt.callLater(() => root.directContent.forceActiveFocus()); - } - } - - Connections { - target: root - function onDirectContentChanged() { - if (root.directContent) { - root.directContent.parent = directContentWrapper; - root.directContent.anchors.fill = directContentWrapper; - Qt.callLater(() => root.directContent.forceActiveFocus()); - } - } - } - } - - Loader { - id: contentLoader - anchors.fill: parent - active: root.directContent === null && (root.keepContentLoaded || root.shouldBeVisible || contentWindow.visible) - asynchronous: false - focus: true - clip: false - visible: root.directContent === null - - onLoaded: { - if (item) { - Qt.callLater(() => item.forceActiveFocus()); - } - } - } - } - } - } - } - - FocusScope { - id: focusScope - objectName: "modalFocusScope" - anchors.fill: parent - visible: root.shouldBeVisible || contentWindow.visible - focus: root.shouldBeVisible - Keys.onEscapePressed: event => { - if (root.closeOnEscapeKey && shouldHaveFocus) { - root.close(); - event.accepted = true; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/InputModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/InputModal.qml deleted file mode 100644 index c65f3e0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Common/InputModal.qml +++ /dev/null @@ -1,312 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.Common -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:input-modal" - keepPopoutsOpen: true - - property string inputTitle: "" - property string inputMessage: "" - property string inputPlaceholder: "" - property string inputText: "" - property string confirmButtonText: "Confirm" - property string cancelButtonText: "Cancel" - property color confirmButtonColor: Theme.primary - property var onConfirm: function (text) {} - property var onCancel: function () {} - property int selectedButton: -1 - property bool keyboardNavigation: false - - function show(title, message, onConfirmCallback, onCancelCallback) { - inputTitle = title || ""; - inputMessage = message || ""; - inputPlaceholder = ""; - inputText = ""; - confirmButtonText = "Confirm"; - cancelButtonText = "Cancel"; - confirmButtonColor = Theme.primary; - onConfirm = onConfirmCallback || ((text) => {}); - onCancel = onCancelCallback || (() => {}); - selectedButton = -1; - keyboardNavigation = false; - open(); - } - - function showWithOptions(options) { - inputTitle = options.title || ""; - inputMessage = options.message || ""; - inputPlaceholder = options.placeholder || ""; - inputText = options.initialText || ""; - confirmButtonText = options.confirmText || "Confirm"; - cancelButtonText = options.cancelText || "Cancel"; - confirmButtonColor = options.confirmColor || Theme.primary; - onConfirm = options.onConfirm || ((text) => {}); - onCancel = options.onCancel || (() => {}); - selectedButton = -1; - keyboardNavigation = false; - open(); - } - - function confirmAndClose() { - const text = inputText; - close(); - if (onConfirm) { - onConfirm(text); - } - } - - function cancelAndClose() { - close(); - if (onCancel) { - onCancel(); - } - } - - function selectButton() { - if (selectedButton === 0) { - cancelAndClose(); - } else { - confirmAndClose(); - } - } - - shouldBeVisible: false - allowStacking: true - modalWidth: 350 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 200 - enableShadow: true - shouldHaveFocus: true - onBackgroundClicked: cancelAndClose() - onOpened: { - Qt.callLater(function () { - if (contentLoader.item && contentLoader.item.textInputRef) { - contentLoader.item.textInputRef.forceActiveFocus(); - } - }); - } - - content: Component { - FocusScope { - anchors.fill: parent - implicitHeight: mainColumn.implicitHeight - focus: true - - property alias textInputRef: textInput - - Keys.onPressed: function (event) { - const textFieldFocused = textInput.activeFocus; - - switch (event.key) { - case Qt.Key_Escape: - root.cancelAndClose(); - event.accepted = true; - break; - case Qt.Key_Tab: - if (textFieldFocused) { - root.keyboardNavigation = true; - root.selectedButton = 0; - textInput.focus = false; - } else { - root.keyboardNavigation = true; - if (root.selectedButton === -1) { - root.selectedButton = 0; - } else if (root.selectedButton === 0) { - root.selectedButton = 1; - } else { - root.selectedButton = -1; - textInput.forceActiveFocus(); - } - } - event.accepted = true; - break; - case Qt.Key_Left: - if (!textFieldFocused) { - root.keyboardNavigation = true; - root.selectedButton = 0; - event.accepted = true; - } - break; - case Qt.Key_Right: - if (!textFieldFocused) { - root.keyboardNavigation = true; - root.selectedButton = 1; - event.accepted = true; - } - break; - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.selectedButton !== -1) { - root.selectButton(); - } else { - root.confirmAndClose(); - } - event.accepted = true; - break; - } - } - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - anchors.topMargin: Theme.spacingL - spacing: 0 - - StyledText { - text: root.inputTitle - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignHCenter - } - - Item { - width: 1 - height: Theme.spacingL - } - - StyledText { - text: root.inputMessage - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - visible: root.inputMessage !== "" - } - - Item { - width: 1 - height: root.inputMessage !== "" ? Theme.spacingL : 0 - visible: root.inputMessage !== "" - } - - Rectangle { - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: Theme.surfaceVariantAlpha - border.color: textInput.activeFocus ? Theme.primary : "transparent" - border.width: textInput.activeFocus ? 1 : 0 - - TextInput { - id: textInput - - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - verticalAlignment: TextInput.AlignVCenter - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - selectionColor: Theme.primary - selectedTextColor: Theme.primaryText - clip: true - text: root.inputText - onTextChanged: root.inputText = text - - StyledText { - anchors.fill: parent - verticalAlignment: Text.AlignVCenter - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - text: root.inputPlaceholder - visible: textInput.text === "" && !textInput.activeFocus - } - } - } - - Item { - width: 1 - height: Theme.spacingL * 1.5 - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Rectangle { - width: 120 - height: 40 - radius: Theme.cornerRadius - color: { - if (root.keyboardNavigation && root.selectedButton === 0) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - } else if (cancelButton.containsMouse) { - return Theme.surfacePressed; - } else { - return Theme.surfaceVariantAlpha; - } - } - border.color: (root.keyboardNavigation && root.selectedButton === 0) ? Theme.primary : "transparent" - border.width: (root.keyboardNavigation && root.selectedButton === 0) ? 1 : 0 - - StyledText { - text: root.cancelButtonText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: cancelButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.cancelAndClose() - } - } - - Rectangle { - width: 120 - height: 40 - radius: Theme.cornerRadius - color: { - const baseColor = root.confirmButtonColor; - if (root.keyboardNavigation && root.selectedButton === 1) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 1); - } else if (confirmButton.containsMouse) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 0.9); - } else { - return baseColor; - } - } - border.color: (root.keyboardNavigation && root.selectedButton === 1) ? "white" : "transparent" - border.width: (root.keyboardNavigation && root.selectedButton === 1) ? 1 : 0 - - StyledText { - text: root.confirmButtonText - font.pixelSize: Theme.fontSizeMedium - color: Theme.primaryText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: confirmButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.confirmAndClose() - } - } - } - - Item { - width: 1 - height: Theme.spacingL - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankColorPickerModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankColorPickerModal.qml deleted file mode 100644 index 8a33878..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankColorPickerModal.qml +++ /dev/null @@ -1,771 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:color-picker" - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: root.useHyprlandFocusGrab && root.shouldHaveFocus - } - - property string pickerTitle: I18n.tr("Choose Color") - property color selectedColor: SessionData.recentColors.length > 0 ? SessionData.recentColors[0] : Theme.primary - property var onColorSelectedCallback: null - - signal colorSelected(color selectedColor) - - property color currentColor: Theme.primary - property real hue: 0 - property real saturation: 1 - property real value: 1 - property real alpha: 1 - property real gradientX: 0 - property real gradientY: 0 - - readonly property var standardColors: ["#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#d32f2f", "#c2185b", "#7b1fa2", "#512da8", "#303f9f", "#1976d2", "#0288d1", "#0097a7", "#00796b", "#388e3c", "#689f38", "#afb42b", "#fbc02d", "#ffa000", "#f57c00", "#e64a19", "#c62828", "#ad1457", "#6a1b9a", "#4527a0", "#283593", "#1565c0", "#0277bd", "#00838f", "#00695c", "#2e7d32", "#558b2f", "#9e9d24", "#f9a825", "#ff8f00", "#ef6c00", "#d84315", "#ffffff", "#9e9e9e", "#212121"] - - function show() { - currentColor = selectedColor; - updateFromColor(currentColor); - open(); - } - - function hide() { - onColorSelectedCallback = null; - close(); - } - - function hideInstant() { - instantClose(); - } - - function toggle() { - if (shouldBeVisible) { - hide(); - } else { - show(); - } - } - - function toggleInstant() { - if (shouldBeVisible) { - hideInstant(); - } else { - show(); - } - } - - onColorSelected: color => { - if (onColorSelectedCallback) { - onColorSelectedCallback(color); - } - } - - function copyColorToClipboard(colorValue) { - Quickshell.execDetached(["dms", "cl", "copy", colorValue]); - ToastService.showInfo(`Color ${colorValue} copied`); - SessionData.addRecentColor(currentColor); - } - - function updateFromColor(color) { - hue = color.hsvHue; - saturation = color.hsvSaturation; - value = color.hsvValue; - alpha = color.a; - gradientX = saturation; - gradientY = 1 - value; - } - - function updateColor() { - currentColor = Qt.hsva(hue, saturation, value, alpha); - } - - function updateColorFromGradient(x, y) { - saturation = Math.max(0, Math.min(1, x)); - value = Math.max(0, Math.min(1, 1 - y)); - updateColor(); - selectedColor = currentColor; - } - - function applyPickedColor(colorStr) { - if (colorStr.length < 7 || !colorStr.startsWith('#')) - return; - const pickedColor = Qt.color(colorStr); - root.selectedColor = pickedColor; - root.currentColor = pickedColor; - root.updateFromColor(pickedColor); - copyColorToClipboard(colorStr); - root.show(); - } - - function pickColorFromScreen() { - hideInstant(); - Proc.runCommand("dms-color-pick", ["dms", "color", "pick", "--json"], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("dms color pick exited with code:", exitCode); - root.show(); - return; - } - try { - const result = JSON.parse(output); - if (result.hex) { - applyPickedColor(result.hex); - } else { - console.warn("Failed to parse dms color pick output: missing hex"); - root.show(); - } - } catch (e) { - console.warn("Failed to parse dms color pick JSON:", e); - root.show(); - } - }, 0, Proc.noTimeout); - } - - modalWidth: 680 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 680 - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - cornerRadius: Theme.cornerRadius - borderColor: Theme.outlineMedium - borderWidth: 1 - keepContentLoaded: true - allowStacking: true - - onBackgroundClicked: hide() - - IpcHandler { - function open(): string { - root.show(); - return "COLOR_PICKER_MODAL_OPEN_SUCCESS"; - } - - function openColor(color: string): string { - root.selectedColor = Qt.color(color); - root.currentColor = Qt.color(color); - root.updateFromColor(Qt.color(color)); - return open(); - } - - function close(): string { - root.hide(); - return "COLOR_PICKER_MODAL_CLOSE_SUCCESS"; - } - - function closeInstant(): string { - root.hideInstant(); - return "COLOR_PICKER_MODAL_CLOSE_INSTANT_SUCCESS"; - } - - function toggle(): string { - root.toggle(); - return "COLOR_PICKER_MODAL_TOGGLE_SUCCESS"; - } - - function toggleInstant(): string { - root.toggleInstant(); - return "COLOR_PICKER_MODAL_TOGGLE_INSTANT_SUCCESS"; - } - - target: "color-picker" - } - - content: Component { - FocusScope { - id: colorContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property alias hexInput: hexInput - - anchors.fill: parent - implicitHeight: mainColumn.implicitHeight - focus: true - - Keys.onEscapePressed: event => { - root.hide(); - event.accepted = true; - } - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - 90 - spacing: Theme.spacingXS - - StyledText { - text: root.pickerTitle - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - } - - StyledText { - text: I18n.tr("Select a color from the palette or use custom sliders") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - anchors.left: parent.left - } - } - - DankActionButton { - iconName: "colorize" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: () => { - root.pickColorFromScreen(); - } - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: () => { - root.hide(); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - id: gradientPicker - width: parent.width - 70 - height: 280 - radius: Theme.cornerRadius - border.color: Theme.outlineStrong - border.width: 1 - clip: true - - Rectangle { - anchors.fill: parent - color: Qt.hsva(root.hue, 1, 1, 1) - - Rectangle { - anchors.fill: parent - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: "#ffffff" - } - GradientStop { - position: 1.0 - color: "transparent" - } - } - } - - Rectangle { - anchors.fill: parent - gradient: Gradient { - orientation: Gradient.Vertical - GradientStop { - position: 0.0 - color: "transparent" - } - GradientStop { - position: 1.0 - color: "#000000" - } - } - } - } - - Rectangle { - id: pickerCircle - width: 16 - height: 16 - radius: 8 - border.color: "white" - border.width: 2 - color: "transparent" - x: root.gradientX * parent.width - width / 2 - y: root.gradientY * parent.height - height / 2 - - Rectangle { - anchors.centerIn: parent - width: parent.width - 4 - height: parent.height - 4 - radius: width / 2 - border.color: "black" - border.width: 1 - color: "transparent" - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.CrossCursor - onPressed: mouse => { - const x = Math.max(0, Math.min(1, mouse.x / width)); - const y = Math.max(0, Math.min(1, mouse.y / height)); - root.gradientX = x; - root.gradientY = y; - root.updateColorFromGradient(x, y); - } - onPositionChanged: mouse => { - if (pressed) { - const x = Math.max(0, Math.min(1, mouse.x / width)); - const y = Math.max(0, Math.min(1, mouse.y / height)); - root.gradientX = x; - root.gradientY = y; - root.updateColorFromGradient(x, y); - } - } - } - } - - Rectangle { - id: hueSlider - width: 50 - height: 280 - radius: Theme.cornerRadius - border.color: Theme.outlineStrong - border.width: 1 - - gradient: Gradient { - orientation: Gradient.Vertical - GradientStop { - position: 0.00 - color: "#ff0000" - } - GradientStop { - position: 0.17 - color: "#ffff00" - } - GradientStop { - position: 0.33 - color: "#00ff00" - } - GradientStop { - position: 0.50 - color: "#00ffff" - } - GradientStop { - position: 0.67 - color: "#0000ff" - } - GradientStop { - position: 0.83 - color: "#ff00ff" - } - GradientStop { - position: 1.00 - color: "#ff0000" - } - } - - Rectangle { - id: hueIndicator - width: parent.width - height: 4 - color: "white" - border.color: "black" - border.width: 1 - y: root.hue * parent.height - height / 2 - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SizeVerCursor - onPressed: mouse => { - const h = Math.max(0, Math.min(1, mouse.y / height)); - root.hue = h; - root.updateColor(); - root.selectedColor = root.currentColor; - } - onPositionChanged: mouse => { - if (pressed) { - const h = Math.max(0, Math.min(1, mouse.y / height)); - root.hue = h; - root.updateColor(); - root.selectedColor = root.currentColor; - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Material Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - } - - GridView { - width: parent.width - height: 140 - cellWidth: 38 - cellHeight: 38 - clip: true - interactive: false - model: root.standardColors - - delegate: Rectangle { - width: 36 - height: 36 - color: modelData - radius: 4 - border.color: Theme.outlineStrong - border.width: 1 - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: () => { - const pickedColor = Qt.color(modelData); - root.selectedColor = pickedColor; - root.currentColor = pickedColor; - root.updateFromColor(pickedColor); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: 210 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Recent Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - } - - Row { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: 5 - - Rectangle { - width: 36 - height: 36 - radius: 4 - border.color: Theme.outlineStrong - border.width: 1 - - color: { - if (index < SessionData.recentColors.length) { - return SessionData.recentColors[index]; - } - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - - opacity: index < SessionData.recentColors.length ? 1.0 : 0.3 - - MouseArea { - anchors.fill: parent - cursorShape: index < SessionData.recentColors.length ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: index < SessionData.recentColors.length - onClicked: () => { - if (index < SessionData.recentColors.length) { - const pickedColor = SessionData.recentColors[index]; - root.selectedColor = pickedColor; - root.currentColor = pickedColor; - root.updateFromColor(pickedColor); - } - } - } - } - } - } - } - - Column { - width: parent.width - 330 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Opacity") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - } - - DankSlider { - width: parent.width - value: Math.round(root.alpha * 100) - minimum: 0 - maximum: 100 - showValue: false - onSliderValueChanged: newValue => { - root.alpha = newValue / 100; - root.updateColor(); - root.selectedColor = root.currentColor; - } - } - } - - Rectangle { - width: 100 - height: 50 - radius: Theme.cornerRadius - color: root.currentColor - border.color: Theme.outlineStrong - border.width: 2 - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Hex") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.left: parent.left - } - - Row { - width: parent.width - spacing: Theme.spacingXS - - DankTextField { - id: hexInput - width: parent.width - 36 - height: 36 - text: root.currentColor.toString() - font.pixelSize: Theme.fontSizeMedium - textColor: { - if (text.length === 0) - return Theme.surfaceText; - const hexPattern = /^#?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$/; - return hexPattern.test(text) ? Theme.surfaceText : Theme.error; - } - placeholderText: "#000000" - backgroundColor: Theme.surfaceHover - borderWidth: 1 - focusedBorderWidth: 2 - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - onAccepted: () => { - const hexPattern = /^#?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$/; - if (!hexPattern.test(text)) - return; - const color = Qt.color(text); - if (color) { - root.selectedColor = color; - root.currentColor = color; - root.updateFromColor(color); - } - } - } - - DankActionButton { - iconName: "content_copy" - iconSize: Theme.iconSize - 6 - iconColor: Theme.surfaceText - buttonSize: 36 - anchors.verticalCenter: parent.verticalCenter - onClicked: () => { - root.copyColorToClipboard(hexInput.text); - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("RGB") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.left: parent.left - } - - Row { - width: parent.width - spacing: Theme.spacingXS - - Rectangle { - width: parent.width - 36 - height: 36 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: Theme.outline - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: { - const r = Math.round(root.currentColor.r * 255); - const g = Math.round(root.currentColor.g * 255); - const b = Math.round(root.currentColor.b * 255); - if (root.alpha < 1) { - const a = Math.round(root.alpha * 255); - return `${r}, ${g}, ${b}, ${a}`; - } - return `${r}, ${g}, ${b}`; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - } - - DankActionButton { - iconName: "content_copy" - iconSize: Theme.iconSize - 6 - iconColor: Theme.surfaceText - buttonSize: 36 - anchors.verticalCenter: parent.verticalCenter - onClicked: () => { - const r = Math.round(root.currentColor.r * 255); - const g = Math.round(root.currentColor.g * 255); - const b = Math.round(root.currentColor.b * 255); - let rgbString; - if (root.alpha < 1) { - const a = Math.round(root.alpha * 255); - rgbString = `rgba(${r}, ${g}, ${b}, ${a})`; - } else { - rgbString = `rgb(${r}, ${g}, ${b})`; - } - Quickshell.execDetached(["dms", "cl", "copy", rgbString]); - ToastService.showInfo(`${rgbString} copied`); - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("HSV") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.left: parent.left - } - - Row { - width: parent.width - spacing: Theme.spacingXS - - Rectangle { - width: parent.width - 36 - height: 36 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: Theme.outline - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: { - const h = Math.round(root.hue * 360); - const s = Math.round(root.saturation * 100); - const v = Math.round(root.value * 100); - if (root.alpha < 1) { - const a = Math.round(root.alpha * 100); - return `${h}°, ${s}%, ${v}%, ${a}%`; - } - return `${h}°, ${s}%, ${v}%`; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - } - - DankActionButton { - iconName: "content_copy" - iconSize: Theme.iconSize - 6 - iconColor: Theme.surfaceText - buttonSize: 36 - anchors.verticalCenter: parent.verticalCenter - onClicked: () => { - const h = Math.round(root.hue * 360); - const s = Math.round(root.saturation * 100); - const v = Math.round(root.value * 100); - let hsvString; - if (root.alpha < 1) { - const a = Math.round(root.alpha * 100); - hsvString = `${h}, ${s}, ${v}, ${a}`; - } else { - hsvString = `${h}, ${s}, ${v}`; - } - Quickshell.execDetached(["dms", "cl", "copy", hsvString]); - ToastService.showInfo(`HSV ${hsvString} copied`); - } - } - } - } - } - - DankButton { - visible: root.onColorSelectedCallback !== null && root.onColorSelectedCallback !== undefined - width: 70 - buttonHeight: 36 - text: I18n.tr("Save") - backgroundColor: Theme.primary - textColor: Theme.background - anchors.right: parent.right - onClicked: { - SessionData.addRecentColor(root.currentColor); - root.colorSelected(root.currentColor); - root.hide(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ActionPanel.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ActionPanel.qml deleted file mode 100644 index 31ada32..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ActionPanel.qml +++ /dev/null @@ -1,256 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var selectedItem: null - property var controller: null - property bool expanded: false - property int selectedActionIndex: 0 - - function getPluginContextMenuActions() { - if (selectedItem?.type !== "plugin" || !selectedItem?.pluginId) - return []; - var instance = PluginService.pluginInstances[selectedItem.pluginId]; - if (!instance) - return []; - if (typeof instance.getContextMenuActions !== "function") - return []; - var actions = instance.getContextMenuActions(selectedItem.data); - if (!Array.isArray(actions)) - return []; - return actions; - } - - readonly property var actions: { - var result = []; - if (selectedItem?.primaryAction) { - result.push(selectedItem.primaryAction); - } - - switch (selectedItem?.type) { - case "plugin": - var pluginActions = getPluginContextMenuActions(); - for (var i = 0; i < pluginActions.length; i++) { - var act = pluginActions[i]; - result.push({ - name: act.text || act.name || "", - icon: act.icon || "play_arrow", - action: "plugin_action", - pluginAction: act.action - }); - } - break; - case "plugin_browse": - if (selectedItem?.actions) { - for (var i = 0; i < selectedItem.actions.length; i++) { - result.push(selectedItem.actions[i]); - } - } - break; - case "app": - if (selectedItem?.isCore) - break; - if (SessionService.nvidiaCommand) { - result.push({ - name: I18n.tr("Launch on dGPU"), - icon: "memory", - action: "launch_dgpu" - }); - } - if (selectedItem?.actions) { - for (var i = 0; i < selectedItem.actions.length; i++) { - result.push(selectedItem.actions[i]); - } - } - break; - } - return result; - } - - readonly property bool hasActions: { - switch (selectedItem?.type) { - case "app": - return !selectedItem?.isCore; - case "plugin": - return getPluginContextMenuActions().length > 0; - case "plugin_browse": - return selectedItem?.actions?.length > 0; - default: - return actions.length > 1; - } - } - - width: parent?.width ?? 200 - height: expanded && hasActions ? 52 : 0 - color: Theme.surfaceContainerHigh - radius: Theme.cornerRadius - - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Rectangle { - anchors.top: parent.top - width: parent.width - height: 1 - color: Theme.outlineMedium - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - Flickable { - id: actionsFlickable - anchors.left: parent.left - anchors.right: tabHint.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - height: parent.height - contentWidth: actionsRow.width - contentHeight: height - clip: true - boundsBehavior: Flickable.StopAtBounds - flickableDirection: Flickable.HorizontalFlick - - Row { - id: actionsRow - height: parent.height - spacing: Theme.spacingS - - Repeater { - model: root.actions - - Rectangle { - id: actionButton - - required property var modelData - required property int index - - width: actionContent.implicitWidth + Theme.spacingM * 2 - height: actionsRow.height - radius: Theme.cornerRadius - color: index === root.selectedActionIndex ? Theme.primaryHover : actionArea.containsMouse ? Theme.surfaceHover : "transparent" - - Row { - id: actionContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: actionButton.modelData?.icon ?? "play_arrow" - size: 16 - color: actionButton.index === root.selectedActionIndex ? Theme.primary : Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: actionButton.modelData?.name ?? "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: actionButton.index === root.selectedActionIndex ? Theme.primary : Theme.surfaceText - } - } - - MouseArea { - id: actionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.controller && root.selectedItem) { - root.controller.executeAction(root.selectedItem, actionButton.modelData); - } - } - onEntered: root.selectedActionIndex = actionButton.index - } - } - } - } - } - - StyledText { - id: tabHint - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: root.hasActions - text: "Tab" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.outlineButton - } - } - - function toggle() { - expanded = !expanded; - selectedActionIndex = 0; - } - - function show() { - expanded = true; - selectedActionIndex = actions.length > 1 ? 1 : 0; - } - - function hide() { - expanded = false; - selectedActionIndex = 0; - } - - function cycleAction(reverse = false) { - if (actions.length > 0) { - if (! reverse) - selectedActionIndex = (selectedActionIndex + 1) % actions.length; - else - selectedActionIndex = (selectedActionIndex - 1) % actions.length; - ensureSelectedVisible(); - } - } - - function ensureSelectedVisible() { - if (selectedActionIndex < 0 || !actionsRow.children || selectedActionIndex >= actionsRow.children.length) - return; - var buttonX = 0; - for (var i = 0; i < selectedActionIndex; i++) { - var child = actionsRow.children[i]; - if (child) - buttonX += child.width + actionsRow.spacing; - } - - var button = actionsRow.children[selectedActionIndex]; - if (!button) - return; - var buttonRight = buttonX + button.width; - var viewLeft = actionsFlickable.contentX; - var viewRight = viewLeft + actionsFlickable.width; - - if (buttonX < viewLeft) { - actionsFlickable.contentX = Math.max(0, buttonX - Theme.spacingS); - } else if (buttonRight > viewRight) { - actionsFlickable.contentX = Math.min(actionsFlickable.contentWidth - actionsFlickable.width, buttonRight - actionsFlickable.width + Theme.spacingS); - } - } - - function executeSelectedAction() { - if (!controller || !selectedItem || selectedActionIndex >= actions.length) - return; - var action = actions[selectedActionIndex]; - if (action.action === "plugin_action" && typeof action.pluginAction === "function") { - action.pluginAction(); - controller.performSearch(); - controller.itemExecuted(); - } else { - controller.executeAction(selectedItem, action); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Controller.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Controller.qml deleted file mode 100644 index 67cb606..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Controller.qml +++ /dev/null @@ -1,1894 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import "Scorer.js" as Scorer -import "ControllerUtils.js" as Utils -import "NavigationHelpers.js" as Nav -import "ItemTransformers.js" as Transform - -Item { - id: root - - property string searchQuery: "" - property string searchMode: "all" - property string previousSearchMode: "all" - property bool autoSwitchedToFiles: false - property bool isFileSearching: false - property var sections: [] - property var flatModel: [] - property int selectedFlatIndex: 0 - property var selectedItem: null - property bool isSearching: false - property string activePluginId: "" - property var collapsedSections: ({}) - property bool keyboardNavigationActive: false - property bool active: false - property var _modeSectionsCache: ({}) - property bool _queryDrivenSearch: false - property bool _diskCacheConsumed: false - property var sectionViewModes: ({}) - property var pluginViewPreferences: ({}) - property int gridColumns: SettingsData.appLauncherGridColumns - property int viewModeVersion: 0 - property string viewModeContext: "spotlight" - - signal itemExecuted - signal searchCompleted - signal modeChanged(string mode) - signal queryChanged(string query) - signal viewModeChanged(string sectionId, string mode) - signal searchQueryRequested(string query) - - onActiveChanged: { - if (!active) { - SessionData.addLauncherHistory(searchQuery); - - sections = []; - flatModel = []; - selectedItem = null; - _clearModeCache(); - } - } - - onSearchModeChanged: { - if (searchMode === "apps") { - _loadAppCategories(); - } else { - appCategory = ""; - appCategories = []; - } - } - - Connections { - target: SettingsData - function onSortAppsAlphabeticallyChanged() { - AppSearchService.invalidateLauncherCache(); - _clearModeCache(); - } - } - - Connections { - target: AppSearchService - function onCacheVersionChanged() { - if (!active) - return; - _clearModeCache(); - if (searchMode === "apps") { - _loadAppCategories(); - performSearch(); - } else if (!searchQuery && searchMode === "all") { - performSearch(); - } - } - } - - Connections { - target: PluginService - function onRequestLauncherUpdate(pluginId) { - if (!active) - return; - if (activePluginId === pluginId) { - if (activePluginCategories.length <= 1) - loadPluginCategories(pluginId); - performSearch(); - return; - } - if (searchQuery) - performSearch(); - } - } - - Process { - id: wtypeProcess - command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"] - running: false - } - - Process { - id: copyProcess - running: false - onExited: pasteTimer.start() - } - - Timer { - id: pasteTimer - interval: 200 - repeat: false - onTriggered: wtypeProcess.running = true - } - - function pasteSelected() { - if (!selectedItem) - return; - if (!SessionService.wtypeAvailable) { - ToastService.showError("wtype not available - install wtype for paste support"); - return; - } - - const pluginId = selectedItem.pluginId; - if (!pluginId) - return; - const pasteArgs = AppSearchService.getPluginPasteArgs(pluginId, selectedItem.data); - if (!pasteArgs) - return; - copyProcess.command = pasteArgs; - copyProcess.running = true; - itemExecuted(); - } - - readonly property var sectionDefinitions: [ - { - id: "favorites", - title: I18n.tr("Pinned"), - icon: "push_pin", - priority: 1, - defaultViewMode: "list" - }, - { - id: "apps", - title: I18n.tr("Applications"), - icon: "apps", - priority: 2, - defaultViewMode: "list" - }, - { - id: "browse_plugins", - title: I18n.tr("Browse"), - icon: "category", - priority: 2.5, - defaultViewMode: "grid" - }, - { - id: "files", - title: I18n.tr("Files"), - icon: "folder", - priority: 4, - defaultViewMode: "list" - }, - { - id: "fallback", - title: I18n.tr("Commands"), - icon: "terminal", - priority: 5, - defaultViewMode: "list" - } - ] - - property int historyIndex: -1 - property string typingBackup: "" - - function navigateHistory(direction) { - let history = SessionData.launcherQueryHistory; - if (history.length === 0) - return; - - if (historyIndex === -1) - typingBackup = searchQuery; - - let nextIndex = historyIndex + (direction === "up" ? 1 : -1); - if (nextIndex >= history.length) - nextIndex = history.length - 1; - if (nextIndex < -1) - nextIndex = -1; - - if (nextIndex === historyIndex) - return; - historyIndex = nextIndex; - - let targetText = (historyIndex === -1) ? typingBackup : history[historyIndex]; - - setSearchQuery(targetText); - searchQueryRequested(targetText); - } - - property string fileSearchType: "all" - property string fileSearchExt: "" - property string fileSearchFolder: "" - property string fileSearchSort: "score" - - property string pluginFilter: "" - property string activePluginName: "" - property var activePluginCategories: [] - property string activePluginCategory: "" - property string appCategory: "" - property var appCategories: [] - - function getSectionViewMode(sectionId) { - if (sectionId === "browse_plugins") - return "list"; - if (pluginViewPreferences[sectionId]?.enforced) - return pluginViewPreferences[sectionId].mode; - if (sectionViewModes[sectionId]) - return sectionViewModes[sectionId]; - - var savedModes = viewModeContext === "appDrawer" ? (SettingsData.appDrawerSectionViewModes || {}) : (SettingsData.spotlightSectionViewModes || {}); - if (savedModes[sectionId]) - return savedModes[sectionId]; - - for (var i = 0; i < sectionDefinitions.length; i++) { - if (sectionDefinitions[i].id === sectionId) - return sectionDefinitions[i].defaultViewMode || "list"; - } - - if (pluginViewPreferences[sectionId]?.mode) - return pluginViewPreferences[sectionId].mode; - - return "list"; - } - - function setSectionViewMode(sectionId, mode) { - if (sectionId === "browse_plugins") - return; - if (pluginViewPreferences[sectionId]?.enforced) - return; - sectionViewModes = Object.assign({}, sectionViewModes, { - [sectionId]: mode - }); - viewModeVersion++; - if (viewModeContext === "appDrawer") { - var savedModes = Object.assign({}, SettingsData.appDrawerSectionViewModes || {}, { - [sectionId]: mode - }); - SettingsData.appDrawerSectionViewModes = savedModes; - } else { - var savedModes = Object.assign({}, SettingsData.spotlightSectionViewModes || {}, { - [sectionId]: mode - }); - SettingsData.spotlightSectionViewModes = savedModes; - } - viewModeChanged(sectionId, mode); - } - - function canChangeSectionViewMode(sectionId) { - if (sectionId === "browse_plugins") - return false; - return !pluginViewPreferences[sectionId]?.enforced; - } - - function canCollapseSection(sectionId) { - return searchMode === "all"; - } - - function setPluginViewPreference(pluginId, mode, enforced) { - var prefs = Object.assign({}, pluginViewPreferences); - prefs[pluginId] = { - mode: mode, - enforced: enforced || false - }; - pluginViewPreferences = prefs; - } - - function applyActivePluginViewPreference(pluginId, isBuiltIn) { - var sectionId = "plugin_" + pluginId; - var pref = null; - if (isBuiltIn) { - var builtIn = AppSearchService.builtInPlugins[pluginId]; - if (builtIn && builtIn.viewMode) { - pref = { - mode: builtIn.viewMode, - enforced: builtIn.viewModeEnforced === true - }; - } - } else { - pref = PluginService.getPluginViewPreference(pluginId); - } - - if (pref && pref.mode) { - setPluginViewPreference(sectionId, pref.mode, pref.enforced); - } else { - var prefs = Object.assign({}, pluginViewPreferences); - delete prefs[sectionId]; - pluginViewPreferences = prefs; - } - } - - function clearActivePluginViewPreference() { - var prefs = {}; - for (var key in pluginViewPreferences) { - if (!key.startsWith("plugin_")) { - prefs[key] = pluginViewPreferences[key]; - } - } - pluginViewPreferences = prefs; - } - - property int _searchVersion: 0 - property bool _pluginPhasePending: false - property bool _pluginPhaseForceFirst: false - property var _phase1Items: [] - - Timer { - id: searchDebounce - interval: 60 - onTriggered: root.performSearch() - } - - Timer { - id: pluginPhaseTimer - interval: 1 - onTriggered: root._performPluginPhase() - } - - Timer { - id: fileSearchDebounce - interval: 200 - onTriggered: root.performFileSearch() - } - - function getOrTransformApp(app) { - return AppSearchService.getOrTransformApp(app, transformApp); - } - - function setSearchQuery(query) { - _searchVersion++; - _queryDrivenSearch = true; - _pluginPhasePending = false; - _phase1Items = []; - pluginPhaseTimer.stop(); - searchQuery = query; - searchDebounce.restart(); - - var filesInAll = searchMode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll); - if (searchMode !== "plugins" && (searchMode === "files" || query.startsWith("/") || filesInAll) && query.length > 0) { - fileSearchDebounce.restart(); - } - } - - function setMode(mode, isAutoSwitch) { - if (searchMode === mode) - return; - if (isAutoSwitch) { - previousSearchMode = searchMode; - autoSwitchedToFiles = true; - } else { - autoSwitchedToFiles = false; - } - searchMode = mode; - modeChanged(mode); - performSearch(); - var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0; - if (mode === "files" || filesInAll) { - fileSearchDebounce.restart(); - } - } - - function restorePreviousMode() { - if (!autoSwitchedToFiles) - return; - autoSwitchedToFiles = false; - searchMode = previousSearchMode; - modeChanged(previousSearchMode); - performSearch(); - } - - function cycleMode(reverse = false) { - var modes = ["all", "apps", "files", "plugins"]; - var currentIndex = modes.indexOf(searchMode); - if (!reverse) - var nextIndex = (currentIndex + 1) % modes.length; - else - var nextIndex = (currentIndex - 1 + modes.length) % modes.length; - setMode(modes[nextIndex]); - } - - function reset() { - searchQuery = ""; - searchMode = "all"; - previousSearchMode = "all"; - autoSwitchedToFiles = false; - isFileSearching = false; - fileSearchType = "all"; - fileSearchExt = ""; - fileSearchFolder = ""; - fileSearchSort = "score"; - sections = []; - flatModel = []; - selectedFlatIndex = 0; - selectedItem = null; - isSearching = false; - activePluginId = ""; - activePluginName = ""; - activePluginCategories = []; - activePluginCategory = ""; - appCategory = ""; - appCategories = []; - pluginFilter = ""; - collapsedSections = {}; - _clearModeCache(); - _queryDrivenSearch = false; - _pluginPhasePending = false; - _pluginPhaseForceFirst = false; - _phase1Items = []; - pluginPhaseTimer.stop(); - } - - function loadPluginCategories(pluginId) { - if (!pluginId) { - if (activePluginCategories.length > 0) { - activePluginCategories = []; - activePluginCategory = ""; - } - return; - } - - const categories = AppSearchService.getPluginLauncherCategories(pluginId); - if (categories.length === activePluginCategories.length) { - let same = true; - for (let i = 0; i < categories.length; i++) { - if (categories[i].id !== activePluginCategories[i]?.id) { - same = false; - break; - } - } - if (same) - return; - } - activePluginCategories = categories; - activePluginCategory = ""; - AppSearchService.setPluginLauncherCategory(pluginId, ""); - } - - function setActivePluginCategory(categoryId) { - if (activePluginCategory === categoryId) - return; - activePluginCategory = categoryId; - AppSearchService.setPluginLauncherCategory(activePluginId, categoryId); - performSearch(); - } - - function setAppCategory(category) { - if (appCategory === category) - return; - appCategory = category; - _queryDrivenSearch = true; - _clearModeCache(); - performSearch(); - } - - function _loadAppCategories() { - appCategories = AppSearchService.getAllCategories(); - } - - function setFileSearchType(type) { - if (fileSearchType === type) - return; - fileSearchType = type; - performFileSearch(); - } - - function setFileSearchExt(ext) { - if (fileSearchExt === ext) - return; - fileSearchExt = ext; - performFileSearch(); - } - - function setFileSearchFolder(folder) { - if (fileSearchFolder === folder) - return; - fileSearchFolder = folder; - performFileSearch(); - } - - function setFileSearchSort(sort) { - if (fileSearchSort === sort) - return; - fileSearchSort = sort; - performFileSearch(); - } - - function clearPluginFilter() { - if (pluginFilter) { - pluginFilter = ""; - performSearch(); - return true; - } - return false; - } - - function preserveSelectionAfterUpdate(forceFirst) { - if (forceFirst) - return function () { - return getFirstItemIndex(); - }; - var previousSelectedId = selectedItem?.id || ""; - return function (newFlatModel) { - if (!previousSelectedId) - return getFirstItemIndex(); - for (var i = 0; i < newFlatModel.length; i++) { - if (!newFlatModel[i].isHeader && newFlatModel[i].item?.id === previousSelectedId) - return i; - } - return getFirstItemIndex(); - }; - } - - function performSearch() { - queryChanged(searchQuery); - - var currentVersion = _searchVersion; - isSearching = true; - var shouldResetSelection = _queryDrivenSearch; - _queryDrivenSearch = false; - var restoreSelection = preserveSelectionAfterUpdate(shouldResetSelection); - - var cachedSections = AppSearchService.getCachedDefaultSections(); - if (!cachedSections && !_diskCacheConsumed && !searchQuery && searchMode === "all" && !pluginFilter) { - _diskCacheConsumed = true; - var diskSections = _loadDiskCache(); - if (diskSections) { - activePluginId = ""; - activePluginName = ""; - activePluginCategories = []; - activePluginCategory = ""; - clearActivePluginViewPreference(); - for (var i = 0; i < diskSections.length; i++) { - if (collapsedSections[diskSections[i].id] !== undefined) - diskSections[i].collapsed = collapsedSections[diskSections[i].id]; - } - _applyHighlights(diskSections, ""); - flatModel = Scorer.flattenSections(diskSections); - sections = diskSections; - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - isSearching = false; - searchCompleted(); - return; - } - } - - if (cachedSections && !searchQuery && searchMode === "all" && !pluginFilter) { - activePluginId = ""; - activePluginName = ""; - activePluginCategories = []; - activePluginCategory = ""; - clearActivePluginViewPreference(); - var modeCache = _getCachedModeData("all"); - if (modeCache) { - _applyHighlights(modeCache.sections, ""); - sections = modeCache.sections; - flatModel = modeCache.flatModel; - } else { - var newSections = cachedSections.map(function (s) { - var copy = Object.assign({}, s, { - items: s.items ? s.items.slice() : [] - }); - if (collapsedSections[s.id] !== undefined) - copy.collapsed = collapsedSections[s.id]; - return copy; - }); - _applyHighlights(newSections, ""); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - _setCachedModeData("all", sections, flatModel); - } - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - isSearching = false; - searchCompleted(); - return; - } - - var allItems = []; - - var triggerMatch = detectTrigger(searchQuery); - if (triggerMatch.pluginId) { - var pluginChanged = activePluginId !== triggerMatch.pluginId; - activePluginId = triggerMatch.pluginId; - activePluginName = getPluginName(triggerMatch.pluginId, triggerMatch.isBuiltIn); - applyActivePluginViewPreference(triggerMatch.pluginId, triggerMatch.isBuiltIn); - - if (pluginChanged && !triggerMatch.isBuiltIn) - loadPluginCategories(triggerMatch.pluginId); - - var pluginItems = getPluginItems(triggerMatch.pluginId, triggerMatch.query); - for (var k = 0; k < pluginItems.length; k++) - allItems.push(pluginItems[k]); - - if (triggerMatch.isBuiltIn) { - var builtInItems = AppSearchService.getBuiltInLauncherItems(triggerMatch.pluginId, triggerMatch.query); - for (var j = 0; j < builtInItems.length; j++) { - allItems.push(transformBuiltInLauncherItem(builtInItems[j], triggerMatch.pluginId)); - } - } - - var dynamicDefs = buildDynamicSectionDefs(allItems); - var scoredItems = Scorer.scoreItems(allItems, triggerMatch.query, getFrecencyForItem); - var sortAlpha = !triggerMatch.query && SettingsData.sortAppsAlphabetically; - var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, 500); - - for (var sid in collapsedSections) { - for (var i = 0; i < newSections.length; i++) { - if (newSections[i].id === sid) { - newSections[i].collapsed = collapsedSections[sid]; - } - } - } - - _applyHighlights(newSections, triggerMatch.query); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - - isSearching = false; - searchCompleted(); - return; - } - - activePluginId = ""; - activePluginName = ""; - activePluginCategories = []; - activePluginCategory = ""; - clearActivePluginViewPreference(); - - if (searchMode === "files") { - var fileQuery = searchQuery.startsWith("/") ? searchQuery.substring(1).trim() : searchQuery.trim(); - isFileSearching = fileQuery.length >= 2 && DSearchService.dsearchAvailable; - sections = []; - flatModel = []; - selectedFlatIndex = 0; - selectedItem = null; - isSearching = false; - searchCompleted(); - return; - } - - if (searchMode === "apps") { - var isCategoryFiltered = appCategory && appCategory !== I18n.tr("All"); - var cachedSections = AppSearchService.getCachedDefaultSections(); - if (cachedSections && !searchQuery && !isCategoryFiltered) { - var modeCache = _getCachedModeData("apps"); - if (modeCache) { - _applyHighlights(modeCache.sections, ""); - sections = modeCache.sections; - flatModel = modeCache.flatModel; - } else { - var appSectionIds = ["favorites", "apps"]; - var newSections = cachedSections.filter(function (s) { - return appSectionIds.indexOf(s.id) !== -1; - }).map(function (s) { - var copy = Object.assign({}, s, { - items: s.items ? s.items.slice() : [] - }); - if (collapsedSections[s.id] !== undefined) - copy.collapsed = collapsedSections[s.id]; - return copy; - }); - _applyHighlights(newSections, ""); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - _setCachedModeData("apps", sections, flatModel); - } - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - isSearching = false; - searchCompleted(); - return; - } - - if (isCategoryFiltered) { - var rawApps = AppSearchService.getAppsInCategory(appCategory); - for (var i = 0; i < rawApps.length; i++) { - allItems.push(getOrTransformApp(rawApps[i])); - } - // Also include core apps (DMS Settings etc.) that match this category - var allCoreApps = AppSearchService.getCoreApps(""); - for (var i = 0; i < allCoreApps.length; i++) { - var coreAppCats = AppSearchService.getCategoriesForApp(allCoreApps[i]); - if (coreAppCats.indexOf(appCategory) !== -1) - allItems.push(transformCoreApp(allCoreApps[i])); - } - } else { - var apps = searchApps(searchQuery); - for (var i = 0; i < apps.length; i++) { - allItems.push(apps[i]); - } - } - - var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); - var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; - var newSections = Scorer.groupBySection(scoredItems, sectionDefinitions, sortAlpha, searchQuery ? 50 : 500); - - for (var sid in collapsedSections) { - for (var i = 0; i < newSections.length; i++) { - if (newSections[i].id === sid) { - newSections[i].collapsed = collapsedSections[sid]; - } - } - } - - _applyHighlights(newSections, searchQuery); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - - isSearching = false; - searchCompleted(); - return; - } - - if (searchMode === "plugins") { - if (!searchQuery && !pluginFilter) { - var browseItems = getPluginBrowseItems(); - for (var k = 0; k < browseItems.length; k++) - allItems.push(browseItems[k]); - } else if (pluginFilter) { - var isBuiltInFilter = !!AppSearchService.builtInPlugins[pluginFilter]; - applyActivePluginViewPreference(pluginFilter, isBuiltInFilter); - - var filterItems = getPluginItems(pluginFilter, searchQuery); - for (var k = 0; k < filterItems.length; k++) - allItems.push(filterItems[k]); - - var builtInItems = AppSearchService.getBuiltInLauncherItems(pluginFilter, searchQuery); - for (var j = 0; j < builtInItems.length; j++) { - allItems.push(transformBuiltInLauncherItem(builtInItems[j], pluginFilter)); - } - } else { - var emptyTriggerPlugins = getEmptyTriggerPlugins(); - for (var i = 0; i < emptyTriggerPlugins.length; i++) { - var pluginId = emptyTriggerPlugins[i]; - var pItems = getPluginItems(pluginId, searchQuery); - for (var k = 0; k < pItems.length; k++) - allItems.push(pItems[k]); - } - - var builtInLauncherPlugins = getBuiltInEmptyTriggerLaunchers(); - for (var i = 0; i < builtInLauncherPlugins.length; i++) { - var pluginId = builtInLauncherPlugins[i]; - var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery); - for (var j = 0; j < blItems.length; j++) { - allItems.push(transformBuiltInLauncherItem(blItems[j], pluginId)); - } - } - } - - var dynamicDefs = buildDynamicSectionDefs(allItems); - var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); - var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; - var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, 500); - - for (var sid in collapsedSections) { - for (var i = 0; i < newSections.length; i++) { - if (newSections[i].id === sid) { - newSections[i].collapsed = collapsedSections[sid]; - } - } - } - - _applyHighlights(newSections, searchQuery); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - - isSearching = false; - searchCompleted(); - return; - } - - var apps = searchApps(searchQuery); - for (var i = 0; i < apps.length; i++) { - allItems.push(apps[i]); - } - - if (searchMode === "all") { - if (searchQuery && searchQuery.length >= 2) { - _pluginPhasePending = true; - _phase1Items = allItems.slice(); - _pluginPhaseForceFirst = shouldResetSelection; - pluginPhaseTimer.restart(); - isSearching = true; - searchCompleted(); - return; - } else if (!searchQuery) { - var emptyTriggerOrdered = getEmptyTriggerPluginsOrdered(); - for (var i = 0; i < emptyTriggerOrdered.length; i++) { - var plugin = emptyTriggerOrdered[i]; - if (plugin.isBuiltIn) { - var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery); - for (var j = 0; j < blItems.length; j++) - allItems.push(transformBuiltInLauncherItem(blItems[j], plugin.id)); - } else { - var pItems = getPluginItems(plugin.id, searchQuery); - for (var j = 0; j < pItems.length; j++) - allItems.push(pItems[j]); - } - } - - var browseItems = getPluginBrowseItems(); - for (var i = 0; i < browseItems.length; i++) - allItems.push(browseItems[i]); - } - } - - var dynamicDefs = buildDynamicSectionDefs(allItems); - - if (currentVersion !== _searchVersion) { - isSearching = false; - return; - } - - var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); - var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; - var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, searchQuery ? 50 : 500); - - if (currentVersion !== _searchVersion) { - isSearching = false; - return; - } - - for (var i = 0; i < newSections.length; i++) { - var sid = newSections[i].id; - if (collapsedSections[sid] !== undefined) { - newSections[i].collapsed = collapsedSections[sid]; - } - } - - _applyHighlights(newSections, searchQuery); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - - if (!AppSearchService.isCacheValid() && !searchQuery && searchMode === "all" && !pluginFilter) { - AppSearchService.setCachedDefaultSections(sections, flatModel); - _saveDiskCache(sections); - } - - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - - isSearching = _pluginPhasePending; - searchCompleted(); - } - - function _performPluginPhase() { - _pluginPhasePending = false; - if (!searchQuery || searchQuery.length < 2 || searchMode !== "all") - return; - - var currentVersion = _searchVersion; - var restoreSelection = preserveSelectionAfterUpdate(_pluginPhaseForceFirst); - var allItems = _phase1Items; - _phase1Items = []; - - var allPluginsOrdered = getAllVisiblePluginsOrdered(); - var maxPerPlugin = 10; - for (var i = 0; i < allPluginsOrdered.length; i++) { - if (currentVersion !== _searchVersion) - return; - var plugin = allPluginsOrdered[i]; - if (plugin.isBuiltIn) { - var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery); - var blLimit = Math.min(blItems.length, maxPerPlugin); - for (var j = 0; j < blLimit; j++) { - var item = transformBuiltInLauncherItem(blItems[j], plugin.id); - item._preScored = 900 - j; - allItems.push(item); - } - } else { - var pItems = getPluginItems(plugin.id, searchQuery, maxPerPlugin); - for (var j = 0; j < pItems.length; j++) { - pItems[j]._preScored = 900 - j; - allItems.push(pItems[j]); - } - } - } - - if (currentVersion !== _searchVersion) - return; - - var dynamicDefs = buildDynamicSectionDefs(allItems); - var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); - var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, false, 50); - - if (currentVersion !== _searchVersion) - return; - - for (var i = 0; i < newSections.length; i++) { - var sid = newSections[i].id; - if (collapsedSections[sid] !== undefined) - newSections[i].collapsed = collapsedSections[sid]; - } - - _applyHighlights(newSections, searchQuery); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - selectedFlatIndex = restoreSelection(flatModel); - updateSelectedItem(); - isSearching = false; - searchCompleted(); - } - - function performFileSearch() { - if (!DSearchService.dsearchAvailable) - return; - var fileQuery = ""; - var effectiveType = fileSearchType || "all"; - var includeFiles = SettingsData.dankLauncherV2IncludeFilesInAll; - var includeFolders = SettingsData.dankLauncherV2IncludeFoldersInAll; - - if (searchQuery.startsWith("/")) { - fileQuery = searchQuery.substring(1).trim(); - } else if (searchMode === "files") { - fileQuery = searchQuery.trim(); - } else if (searchMode === "all" && (includeFiles || includeFolders)) { - fileQuery = searchQuery.trim(); - if (includeFiles && !includeFolders) - effectiveType = "file"; - else if (!includeFiles && includeFolders) - effectiveType = "dir"; - else - effectiveType = "all"; - } else { - return; - } - - if (fileQuery.length < 2) { - isFileSearching = false; - return; - } - - isFileSearching = true; - - var splitBothTypes = searchMode === "all" && includeFiles && includeFolders && DSearchService.supportsTypeFilter; - var queryTypes = splitBothTypes ? ["file", "dir"] : [effectiveType]; - var pending = queryTypes.length; - var aggregatedItems = []; - - for (var t = 0; t < queryTypes.length; t++) { - var queryType = queryTypes[t]; - var params = { - limit: 20, - fuzzy: true, - sort: fileSearchSort || "score", - desc: true - }; - - if (DSearchService.supportsTypeFilter) { - params.type = (queryType && queryType !== "all") ? queryType : "all"; - } - if (fileSearchExt) { - params.ext = fileSearchExt; - } - if (fileSearchFolder) { - params.folder = fileSearchFolder; - } - - DSearchService.search(fileQuery, params, function (response) { - pending--; - if (!response.error) { - var hits = response.result?.hits || []; - for (var i = 0; i < hits.length; i++) { - var hit = hits[i]; - var docTypes = hit.locations?.doc_type; - var isDir = docTypes ? !!docTypes["dir"] : false; - aggregatedItems.push(transformFileResult({ - path: hit.id || "", - score: hit.score || 0, - is_dir: isDir - })); - } - } - if (pending > 0) - return; - - isFileSearching = false; - _applyFileSearchResults(aggregatedItems, effectiveType); - }); - } - } - - function _applyFileSearchResults(fileItems, effectiveType) { - var fileSections = []; - var showType = effectiveType; - var order = SettingsData.launcherPluginOrder || []; - var filesOrderIdx = order.indexOf("__files"); - var foldersOrderIdx = order.indexOf("__folders"); - var filesPriority = filesOrderIdx !== -1 ? 2.6 + filesOrderIdx * 0.01 : 4; - var foldersPriority = foldersOrderIdx !== -1 ? 2.6 + foldersOrderIdx * 0.01 : 4.1; - - if (showType === "all" && DSearchService.supportsTypeFilter) { - var onlyFiles = []; - var onlyDirs = []; - for (var j = 0; j < fileItems.length; j++) { - if (fileItems[j].data?.is_dir) - onlyDirs.push(fileItems[j]); - else - onlyFiles.push(fileItems[j]); - } - if (onlyFiles.length > 0) { - fileSections.push({ - id: "files", - title: I18n.tr("Files"), - icon: "insert_drive_file", - priority: filesPriority, - items: onlyFiles, - collapsed: collapsedSections["files"] || false, - flatStartIndex: 0 - }); - } - if (onlyDirs.length > 0) { - fileSections.push({ - id: "folders", - title: I18n.tr("Folders"), - icon: "folder", - priority: foldersPriority, - items: onlyDirs, - collapsed: collapsedSections["folders"] || false, - flatStartIndex: 0 - }); - } - } else { - var filesIcon = showType === "dir" ? "folder" : showType === "file" ? "insert_drive_file" : "folder"; - var filesTitle = showType === "dir" ? I18n.tr("Folders") : I18n.tr("Files"); - var singlePriority = showType === "dir" ? foldersPriority : filesPriority; - if (fileItems.length > 0) { - fileSections.push({ - id: "files", - title: filesTitle, - icon: filesIcon, - priority: singlePriority, - items: fileItems, - collapsed: collapsedSections["files"] || false, - flatStartIndex: 0 - }); - } - } - - var newSections; - if (searchMode === "files") { - newSections = fileSections; - } else { - var existingNonFile = sections.filter(function (s) { - return s.id !== "files" && s.id !== "folders"; - }); - newSections = existingNonFile.concat(fileSections); - } - newSections.sort(function (a, b) { - return a.priority - b.priority; - }); - _applyHighlights(newSections, searchQuery); - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - selectedFlatIndex = getFirstItemIndex(); - updateSelectedItem(); - } - - function searchApps(query) { - var apps = AppSearchService.searchApplications(query); - var items = []; - - for (var i = 0; i < apps.length; i++) { - items.push(getOrTransformApp(apps[i])); - } - - var coreApps = AppSearchService.getCoreApps(query); - for (var i = 0; i < coreApps.length; i++) { - items.push(transformCoreApp(coreApps[i])); - } - - return items; - } - - function transformApp(app) { - var appId = app.id || app.execString || app.exec || ""; - var override = SessionData.getAppOverride(appId); - return Transform.transformApp(app, override, [], I18n.tr("Launch")); - } - - function transformCoreApp(app) { - return Transform.transformCoreApp(app, I18n.tr("Open")); - } - - function transformBuiltInLauncherItem(item, pluginId) { - return Transform.transformBuiltInLauncherItem(item, pluginId, I18n.tr("Open")); - } - - function transformFileResult(file) { - return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"), I18n.tr("Open in terminal")); - } - - function detectTrigger(query) { - if (!query || query.length === 0) - return { - pluginId: null, - query: query - }; - - var pluginTriggers = PluginService.getAllPluginTriggers(); - for (var trigger in pluginTriggers) { - if (trigger && query.startsWith(trigger)) { - return { - pluginId: pluginTriggers[trigger], - query: query.substring(trigger.length).trim() - }; - } - } - - var builtInTriggers = AppSearchService.getBuiltInLauncherTriggers(); - for (var trigger in builtInTriggers) { - if (trigger && query.startsWith(trigger)) { - return { - pluginId: builtInTriggers[trigger], - query: query.substring(trigger.length).trim(), - isBuiltIn: true - }; - } - } - - return { - pluginId: null, - query: query - }; - } - - function getEmptyTriggerPlugins() { - var plugins = PluginService.getPluginsWithEmptyTrigger(); - var visible = plugins.filter(function (pluginId) { - return SettingsData.getPluginAllowWithoutTrigger(pluginId); - }); - return sortPluginIdsByOrder(visible); - } - - function getAllLauncherPluginIds() { - var launchers = PluginService.getLauncherPlugins(); - return Object.keys(launchers); - } - - function getVisibleLauncherPluginIds() { - var launchers = PluginService.getLauncherPlugins(); - var visible = Object.keys(launchers).filter(function (pluginId) { - return SettingsData.getPluginAllowWithoutTrigger(pluginId); - }); - return sortPluginIdsByOrder(visible); - } - - function getAllBuiltInLauncherIds() { - var launchers = AppSearchService.getBuiltInLauncherPlugins(); - return Object.keys(launchers); - } - - function getVisibleBuiltInLauncherIds() { - var launchers = AppSearchService.getBuiltInLauncherPlugins(); - var visible = Object.keys(launchers).filter(function (pluginId) { - return SettingsData.getPluginAllowWithoutTrigger(pluginId); - }); - return sortPluginIdsByOrder(visible); - } - - function sortPluginIdsByOrder(pluginIds) { - return Utils.sortPluginIdsByOrder(pluginIds, SettingsData.launcherPluginOrder || []); - } - - function getAllVisiblePluginsOrdered() { - var thirdPartyLaunchers = PluginService.getLauncherPlugins() || {}; - var builtInLaunchers = AppSearchService.getBuiltInLauncherPlugins() || {}; - var all = []; - for (var id in thirdPartyLaunchers) { - if (SettingsData.getPluginAllowWithoutTrigger(id)) - all.push({ - id: id, - isBuiltIn: false - }); - } - for (var id in builtInLaunchers) { - if (SettingsData.getPluginAllowWithoutTrigger(id)) - all.push({ - id: id, - isBuiltIn: true - }); - } - return Utils.sortPluginsOrdered(all, SettingsData.launcherPluginOrder || []); - } - - function getEmptyTriggerPluginsOrdered() { - var thirdParty = PluginService.getPluginsWithEmptyTrigger() || []; - var builtIn = AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger() || []; - var all = []; - for (var i = 0; i < thirdParty.length; i++) { - var id = thirdParty[i]; - if (SettingsData.getPluginAllowWithoutTrigger(id)) - all.push({ - id: id, - isBuiltIn: false - }); - } - for (var i = 0; i < builtIn.length; i++) { - var id = builtIn[i]; - if (SettingsData.getPluginAllowWithoutTrigger(id)) - all.push({ - id: id, - isBuiltIn: true - }); - } - return Utils.sortPluginsOrdered(all, SettingsData.launcherPluginOrder || []); - } - - function getPluginBrowseItems() { - var items = []; - var browseLabel = I18n.tr("Browse"); - var triggerLabel = I18n.tr("Trigger: %1"); - var noTriggerLabel = I18n.tr("No trigger"); - - var launchers = PluginService.getLauncherPlugins(); - for (var pluginId in launchers) { - var trigger = PluginService.getPluginTrigger(pluginId); - var isAllowed = SettingsData.getPluginAllowWithoutTrigger(pluginId); - items.push(Transform.createPluginBrowseItem(pluginId, launchers[pluginId], trigger, false, isAllowed, browseLabel, triggerLabel, noTriggerLabel)); - } - - var builtInLaunchers = AppSearchService.getBuiltInLauncherPlugins(); - for (var pluginId in builtInLaunchers) { - var trigger = AppSearchService.getBuiltInPluginTrigger(pluginId); - var isAllowed = SettingsData.getPluginAllowWithoutTrigger(pluginId); - items.push(Transform.createPluginBrowseItem(pluginId, builtInLaunchers[pluginId], trigger, true, isAllowed, browseLabel, triggerLabel, noTriggerLabel)); - } - - return items; - } - - function getBuiltInEmptyTriggerLaunchers() { - var plugins = AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger(); - var visible = plugins.filter(function (pluginId) { - return SettingsData.getPluginAllowWithoutTrigger(pluginId); - }); - return sortPluginIdsByOrder(visible); - } - - function getPluginItems(pluginId, query, limit) { - var items = AppSearchService.getPluginItemsForPlugin(pluginId, query); - var count = limit > 0 && limit < items.length ? limit : items.length; - var transformed = []; - - for (var i = 0; i < count; i++) { - transformed.push(transformPluginItem(items[i], pluginId)); - } - - return transformed; - } - - function getPluginName(pluginId, isBuiltIn) { - if (isBuiltIn) { - var plugin = AppSearchService.builtInPlugins[pluginId]; - return plugin ? plugin.name : pluginId; - } - var launchers = PluginService.getLauncherPlugins(); - if (launchers[pluginId]) { - return launchers[pluginId].name || pluginId; - } - return pluginId; - } - - function getPluginMetadata(pluginId) { - var builtIn = AppSearchService.builtInPlugins[pluginId]; - if (builtIn) { - return { - name: builtIn.name || pluginId, - icon: builtIn.cornerIcon || "extension" - }; - } - var launchers = PluginService.getLauncherPlugins(); - if (launchers[pluginId]) { - var rawIcon = launchers[pluginId].icon || "extension"; - return { - name: launchers[pluginId].name || pluginId, - icon: Utils.stripIconPrefix(rawIcon) - }; - } - return { - name: pluginId, - icon: "extension" - }; - } - - function buildDynamicSectionDefs(items) { - var baseDefs = sectionDefinitions.slice(); - var pluginSections = {}; - var order = SettingsData.launcherPluginOrder || []; - var orderMap = {}; - for (var k = 0; k < order.length; k++) - orderMap[order[k]] = k; - var unorderedPriority = 2.6 + order.length * 0.01; - - for (var i = 0; i < items.length; i++) { - var section = items[i].section; - if (!section || !section.startsWith("plugin_")) - continue; - if (pluginSections[section]) - continue; - var pluginId = section.substring(7); - var meta = getPluginMetadata(pluginId); - var viewPref = getPluginViewPref(pluginId); - var orderIdx = orderMap[pluginId]; - var priority; - if (orderIdx !== undefined) { - priority = 2.6 + orderIdx * 0.01; - } else { - priority = unorderedPriority; - unorderedPriority += 0.01; - } - - pluginSections[section] = { - id: section, - title: meta.name, - icon: meta.icon, - priority: priority, - defaultViewMode: viewPref.mode || "list" - }; - - if (viewPref.mode) - setPluginViewPreference(section, viewPref.mode, viewPref.enforced); - } - - for (var sectionId in pluginSections) { - baseDefs.push(pluginSections[sectionId]); - } - - baseDefs.sort(function (a, b) { - return a.priority - b.priority; - }); - return baseDefs; - } - - function getPluginViewPref(pluginId) { - var builtIn = AppSearchService.builtInPlugins[pluginId]; - if (builtIn && builtIn.viewMode) { - return { - mode: builtIn.viewMode, - enforced: builtIn.viewModeEnforced === true - }; - } - - var pref = PluginService.getPluginViewPreference(pluginId); - if (pref && pref.mode) { - return pref; - } - - return { - mode: "list", - enforced: false - }; - } - - function transformPluginItem(item, pluginId) { - return Transform.transformPluginItem(item, pluginId, I18n.tr("Select")); - } - - function getFrecencyForItem(item) { - if (item.type !== "app") - return null; - - var appId = item.id; - var usageRanking = AppUsageHistoryData.appUsageRanking || {}; - - var idVariants = [appId, appId.replace(".desktop", "")]; - var usageData = null; - - for (var i = 0; i < idVariants.length; i++) { - if (usageRanking[idVariants[i]]) { - usageData = usageRanking[idVariants[i]]; - break; - } - } - - return { - usageCount: usageData?.usageCount || 0 - }; - } - - function getFirstItemIndex() { - return Nav.getFirstItemIndex(flatModel); - } - - function _getCachedModeData(mode) { - return _modeSectionsCache[mode] || null; - } - - function _setCachedModeData(mode, sectionsData, flatModelData) { - var cache = Object.assign({}, _modeSectionsCache); - cache[mode] = { - sections: sectionsData, - flatModel: flatModelData - }; - _modeSectionsCache = cache; - } - - function _clearModeCache() { - _modeSectionsCache = {}; - } - - function _saveDiskCache(sectionsData) { - var serializable = []; - for (var i = 0; i < sectionsData.length; i++) { - var s = sectionsData[i]; - var items = []; - var srcItems = s.items || []; - for (var j = 0; j < srcItems.length; j++) { - var it = srcItems[j]; - items.push({ - id: it.id, - type: it.type, - name: it.name || "", - subtitle: it.subtitle || "", - icon: it.icon || "", - iconType: it.iconType || "image", - iconFull: it.iconFull || "", - section: it.section || "", - isCore: it.isCore || false, - isBuiltInLauncher: it.isBuiltInLauncher || false, - pluginId: it.pluginId || "" - }); - } - serializable.push({ - id: s.id, - title: s.title || "", - icon: s.icon || "", - priority: s.priority || 0, - items: items - }); - } - CacheData.saveLauncherCache(serializable); - } - - function _actionsFromDesktopEntry(appId) { - if (!appId) - return []; - var entry = DesktopEntries.heuristicLookup(appId); - if (!entry || !entry.actions || entry.actions.length === 0) - return []; - var result = []; - for (var i = 0; i < entry.actions.length; i++) { - result.push({ - name: entry.actions[i].name, - icon: "play_arrow", - actionData: entry.actions[i] - }); - } - return result; - } - - function _loadDiskCache() { - var cached = CacheData.loadLauncherCache(); - if (!cached || !Array.isArray(cached) || cached.length === 0) - return null; - - var sectionsData = []; - for (var i = 0; i < cached.length; i++) { - var s = cached[i]; - var items = []; - var srcItems = s.items || []; - for (var j = 0; j < srcItems.length; j++) { - var it = srcItems[j]; - items.push({ - id: it.id || "", - type: it.type || "app", - name: it.name || "", - subtitle: it.subtitle || "", - icon: it.icon || "", - iconType: it.iconType || "image", - iconFull: it.iconFull || "", - section: it.section || "", - isCore: it.isCore || false, - isBuiltInLauncher: it.isBuiltInLauncher || false, - pluginId: it.pluginId || "", - data: { - id: it.id - }, - actions: _actionsFromDesktopEntry(it.id), - primaryAction: it.type === "app" && !it.isCore ? { - name: I18n.tr("Launch"), - icon: "open_in_new", - action: "launch" - } : null, - _diskCached: true, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: undefined - }); - } - sectionsData.push({ - id: s.id || "", - title: s.title || "", - icon: s.icon || "", - priority: s.priority || 0, - items: items, - collapsed: false, - flatStartIndex: 0 - }); - } - return sectionsData; - } - - function updateSelectedItem() { - if (selectedFlatIndex >= 0 && selectedFlatIndex < flatModel.length) { - var entry = flatModel[selectedFlatIndex]; - selectedItem = entry.isHeader ? null : entry.item; - } else { - selectedItem = null; - } - } - - function _applyHighlights(sectionsData, query) { - if (!query || query.length === 0) { - for (var i = 0; i < sectionsData.length; i++) { - var items = sectionsData[i].items; - for (var j = 0; j < items.length; j++) { - var item = items[j]; - item._hName = item.name || ""; - item._hSub = item.subtitle || ""; - item._hRich = false; - } - } - return; - } - - var highlightColor = Theme.primary; - var nameColor = Theme.surfaceText; - var subColor = Theme.surfaceVariantText; - var lowerQuery = query.toLowerCase(); - - for (var i = 0; i < sectionsData.length; i++) { - var items = sectionsData[i].items; - for (var j = 0; j < items.length; j++) { - var item = items[j]; - item._hName = _highlightField(item.name || "", lowerQuery, query.length, nameColor, highlightColor); - item._hSub = _highlightField(item.subtitle || "", lowerQuery, query.length, subColor, highlightColor); - item._hRich = true; - } - } - } - - function _highlightField(text, lowerQuery, queryLen, baseColor, highlightColor) { - if (!text) - return ""; - var idx = text.toLowerCase().indexOf(lowerQuery); - if (idx === -1) - return text; - var before = text.substring(0, idx); - var match = text.substring(idx, idx + queryLen); - var after = text.substring(idx + queryLen); - return '' + before + '' + match + '' + after + ''; - } - - function getCurrentSectionViewMode() { - if (selectedFlatIndex < 0 || selectedFlatIndex >= flatModel.length) - return "list"; - var entry = flatModel[selectedFlatIndex]; - if (!entry || entry.isHeader) - return "list"; - return getSectionViewMode(entry.sectionId); - } - - function getGridColumns(sectionId) { - return Nav.getGridColumns(getSectionViewMode(sectionId), gridColumns); - } - - function _cancelPendingSelectionReset() { - _queryDrivenSearch = false; - _pluginPhaseForceFirst = false; - } - - function selectNext() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculateNextIndex(flatModel, selectedFlatIndex, null, null, gridColumns, getSectionViewMode); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectPrevious() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculatePrevIndex(flatModel, selectedFlatIndex, null, null, gridColumns, getSectionViewMode); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectRight() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculateRightIndex(flatModel, selectedFlatIndex, getSectionViewMode); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectLeft() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculateLeftIndex(flatModel, selectedFlatIndex, getSectionViewMode); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectNextSection() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculateNextSectionIndex(flatModel, selectedFlatIndex); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectPreviousSection() { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculatePrevSectionIndex(flatModel, selectedFlatIndex); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectPageDown(visibleItems) { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculatePageDownIndex(flatModel, selectedFlatIndex, visibleItems); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectPageUp(visibleItems) { - keyboardNavigationActive = true; - _cancelPendingSelectionReset(); - var newIndex = Nav.calculatePageUpIndex(flatModel, selectedFlatIndex, visibleItems); - if (newIndex !== selectedFlatIndex) { - selectedFlatIndex = newIndex; - updateSelectedItem(); - } - } - - function selectIndex(index) { - keyboardNavigationActive = false; - if (index >= 0 && index < flatModel.length && !flatModel[index].isHeader) { - selectedFlatIndex = index; - updateSelectedItem(); - } - } - - function toggleSection(sectionId) { - _clearModeCache(); - var newCollapsed = Object.assign({}, collapsedSections); - var currentState = newCollapsed[sectionId]; - - if (currentState === undefined) { - for (var i = 0; i < sections.length; i++) { - if (sections[i].id === sectionId) { - currentState = sections[i].collapsed || false; - break; - } - } - } - - newCollapsed[sectionId] = !currentState; - collapsedSections = newCollapsed; - - var newSections = sections.slice(); - for (var i = 0; i < newSections.length; i++) { - if (newSections[i].id === sectionId) { - newSections[i] = Object.assign({}, newSections[i], { - collapsed: newCollapsed[sectionId] - }); - } - } - flatModel = Scorer.flattenSections(newSections); - sections = newSections; - - if (selectedFlatIndex >= flatModel.length) { - selectedFlatIndex = getFirstItemIndex(); - } - updateSelectedItem(); - } - - function executeSelected() { - if (searchDebounce.running) { - searchDebounce.stop(); - performSearch(); - } - if (!selectedItem) - return; - executeItem(selectedItem); - } - - function executeItem(item) { - if (!item) - return; - - SessionData.addLauncherHistory(searchQuery); - - if (item.type === "plugin_browse") { - var browsePluginId = item.data?.pluginId; - if (!browsePluginId) - return; - var browseTrigger = item.data.isBuiltIn ? AppSearchService.getBuiltInPluginTrigger(browsePluginId) : PluginService.getPluginTrigger(browsePluginId); - - if (browseTrigger && browseTrigger.length > 0) { - searchQueryRequested(browseTrigger); - } else { - setMode("plugins"); - pluginFilter = browsePluginId; - performSearch(); - } - return; - } - - switch (item.type) { - case "app": - if (item.isCore) { - AppSearchService.executeCoreApp(item.data); - } else if (item.data?.isAction) { - launchAppAction(item.data); - } else { - launchApp(item.data); - } - break; - case "plugin": - if (item.isBuiltInLauncher) { - AppSearchService.executeBuiltInLauncherItem(item.data); - } else { - AppSearchService.executePluginItem(item.data, item.pluginId); - } - break; - case "file": - openFile(item.data?.path); - break; - default: - return; - } - - itemExecuted(); - } - - function executeAction(item, action) { - if (!item || !action) - return; - switch (action.action) { - case "launch": - executeItem(item); - break; - case "open": - openFile(item.data.path); - break; - case "open_folder": - openFolder(item.data.path); - break; - case "copy_path": - copyToClipboard(item.data.path); - break; - case "open_terminal": - openTerminal(item.data.path); - break; - case "copy": - copyToClipboard(item.name); - break; - case "execute": - executeItem(item); - break; - case "launch_dgpu": - if (item.type === "app" && item.data) { - launchAppWithNvidia(item.data); - } - break; - case "toggle_all_visibility": - if (item.type === "plugin_browse" && item.data?.pluginId) { - var pluginId = item.data.pluginId; - var currentState = SettingsData.getPluginAllowWithoutTrigger(pluginId); - SettingsData.setPluginAllowWithoutTrigger(pluginId, !currentState); - performSearch(); - } - return; - default: - if (item.type === "app" && action.actionData) { - launchAppAction({ - parentApp: item.data, - actionData: action.actionData - }); - } - } - - itemExecuted(); - } - - function _resolveDesktopEntry(app) { - if (!app) - return null; - if (app.command) - return app; - var id = app.id || app.execString || app.exec || ""; - if (!id) - return null; - return DesktopEntries.heuristicLookup(id); - } - - function launchApp(app) { - var entry = _resolveDesktopEntry(app); - if (!entry) - return; - SessionService.launchDesktopEntry(entry); - AppUsageHistoryData.addAppUsage(entry); - } - - function launchAppWithNvidia(app) { - var entry = _resolveDesktopEntry(app); - if (!entry) - return; - SessionService.launchDesktopEntry(entry, true); - AppUsageHistoryData.addAppUsage(entry); - } - - function launchAppAction(actionItem) { - if (!actionItem || !actionItem.actionData) - return; - var entry = _resolveDesktopEntry(actionItem.parentApp); - if (!entry) - return; - SessionService.launchDesktopAction(entry, actionItem.actionData); - AppUsageHistoryData.addAppUsage(entry); - } - - function openFile(path) { - if (!path) - return; - Qt.openUrlExternally("file://" + path); - } - - function openFolder(path) { - if (!path) - return; - var folder = path.substring(0, path.lastIndexOf("/")); - Qt.openUrlExternally("file://" + folder); - } - - function openTerminal(path) { - if (!path) - return; - var terminal = Quickshell.env("TERMINAL") || "xterm"; - Quickshell.execDetached({ - command: [terminal], - workingDirectory: path - }); - } - - function copyToClipboard(text) { - if (!text) - return; - Quickshell.execDetached(["dms", "cl", "copy", text]); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ControllerUtils.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ControllerUtils.js deleted file mode 100644 index a06285f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ControllerUtils.js +++ /dev/null @@ -1,128 +0,0 @@ -.pragma library - -function getFileIcon(filename) { - var ext = filename.lastIndexOf(".") > 0 ? filename.substring(filename.lastIndexOf(".") + 1).toLowerCase() : ""; - - switch (ext) { - case "pdf": - return "picture_as_pdf"; - case "doc": - case "docx": - case "odt": - return "description"; - case "xls": - case "xlsx": - case "ods": - return "table_chart"; - case "ppt": - case "pptx": - case "odp": - return "slideshow"; - case "txt": - case "md": - case "rst": - return "article"; - case "jpg": - case "jpeg": - case "png": - case "gif": - case "svg": - case "webp": - return "image"; - case "mp3": - case "wav": - case "flac": - case "ogg": - return "audio_file"; - case "mp4": - case "mkv": - case "avi": - case "webm": - return "video_file"; - case "zip": - case "tar": - case "gz": - case "7z": - case "rar": - return "folder_zip"; - case "js": - case "ts": - case "py": - case "rs": - case "go": - case "java": - case "c": - case "cpp": - case "h": - return "code"; - case "html": - case "css": - case "htm": - return "web"; - case "json": - case "xml": - case "yaml": - case "yml": - return "data_object"; - case "sh": - case "bash": - case "zsh": - return "terminal"; - default: - return "insert_drive_file"; - } -} - -function stripIconPrefix(iconName) { - if (!iconName) - return "extension"; - if (iconName.startsWith("unicode:")) - return iconName.substring(8); - if (iconName.startsWith("material:")) - return iconName.substring(9); - if (iconName.startsWith("image:")) - return iconName.substring(6); - return iconName; -} - -function detectIconType(iconName) { - if (!iconName) - return "material"; - if (iconName.startsWith("unicode:")) - return "unicode"; - if (iconName.startsWith("material:")) - return "material"; - if (iconName.startsWith("image:")) - return "image"; - if (iconName.indexOf("/") >= 0 || iconName.indexOf(".") >= 0) - return "image"; - if (/^[a-z]+-[a-z]/.test(iconName.toLowerCase())) - return "image"; - return "material"; -} - -function sortPluginIdsByOrder(pluginIds, order) { - if (!order || order.length === 0) - return pluginIds; - var orderMap = {}; - for (var i = 0; i < order.length; i++) - orderMap[order[i]] = i; - return pluginIds.slice().sort(function (a, b) { - var aOrder = orderMap[a] !== undefined ? orderMap[a] : 9999; - var bOrder = orderMap[b] !== undefined ? orderMap[b] : 9999; - return aOrder - bOrder; - }); -} - -function sortPluginsOrdered(plugins, order) { - if (!order || order.length === 0) - return plugins; - var orderMap = {}; - for (var i = 0; i < order.length; i++) - orderMap[order[i]] = i; - return plugins.sort(function (a, b) { - var aOrder = orderMap[a.id] !== undefined ? orderMap[a.id] : 9999; - var bOrder = orderMap[b.id] !== undefined ? orderMap[b.id] : 9999; - return aOrder - bOrder; - }); -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml deleted file mode 100644 index 859022c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml +++ /dev/null @@ -1,465 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - visible: false - - property bool spotlightOpen: false - property bool keyboardActive: false - property bool contentVisible: false - property var spotlightContent: launcherContentLoader.item - property bool openedFromOverview: false - property bool isClosing: false - property bool _pendingInitialize: false - property string _pendingQuery: "" - property string _pendingMode: "" - readonly property bool unloadContentOnClose: SettingsData.dankLauncherV2UnloadOnClose - - readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab - readonly property var effectiveScreen: launcherWindow.screen - readonly property real screenWidth: effectiveScreen?.width ?? 1920 - readonly property real screenHeight: effectiveScreen?.height ?? 1080 - readonly property real dpr: effectiveScreen ? CompositorService.getScreenScale(effectiveScreen) : 1 - - readonly property int baseWidth: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 500; - case "medium": - return 720; - case "large": - return 860; - default: - return 620; - } - } - readonly property int baseHeight: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 480; - case "medium": - return 720; - case "large": - return 860; - default: - return 600; - } - } - readonly property int modalWidth: Math.min(baseWidth, screenWidth - 100) - readonly property int modalHeight: Math.min(baseHeight, screenHeight - 100) - readonly property real modalX: (screenWidth - modalWidth) / 2 - readonly property real modalY: (screenHeight - modalHeight) / 2 - - readonly property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - readonly property real cornerRadius: Theme.cornerRadius - readonly property color borderColor: { - if (!SettingsData.dankLauncherV2BorderEnabled) - return Theme.outlineMedium; - switch (SettingsData.dankLauncherV2BorderColor) { - case "primary": - return Theme.primary; - case "secondary": - return Theme.secondary; - case "outline": - return Theme.outline; - case "surfaceText": - return Theme.surfaceText; - default: - return Theme.primary; - } - } - readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0 - - signal dialogClosed - - function _ensureContentLoadedAndInitialize(query, mode) { - _pendingQuery = query || ""; - _pendingMode = mode || ""; - _pendingInitialize = true; - contentVisible = true; - launcherContentLoader.active = true; - - if (spotlightContent) { - _initializeAndShow(_pendingQuery, _pendingMode); - _pendingInitialize = false; - } - } - - function _initializeAndShow(query, mode) { - if (!spotlightContent) - return; - contentVisible = true; - spotlightContent.searchField.forceActiveFocus(); - - var targetQuery = ""; - - if (query) { - targetQuery = query; - } else if (SettingsData.rememberLastQuery) { - targetQuery = SessionData.launcherLastQuery || ""; - } - - if (spotlightContent.searchField) { - spotlightContent.searchField.text = targetQuery; - } - if (spotlightContent.controller) { - var targetMode = mode || SessionData.launcherLastMode || "all"; - spotlightContent.controller.searchMode = targetMode; - spotlightContent.controller.activePluginId = ""; - spotlightContent.controller.activePluginName = ""; - spotlightContent.controller.pluginFilter = ""; - spotlightContent.controller.fileSearchType = "all"; - spotlightContent.controller.fileSearchExt = ""; - spotlightContent.controller.fileSearchFolder = ""; - spotlightContent.controller.fileSearchSort = "score"; - spotlightContent.controller.collapsedSections = {}; - spotlightContent.controller.selectedFlatIndex = 0; - spotlightContent.controller.selectedItem = null; - spotlightContent.controller.historyIndex = -1; - spotlightContent.controller.searchQuery = targetQuery; - - spotlightContent.controller.performSearch(); - } - if (spotlightContent.resetScroll) { - spotlightContent.resetScroll(); - } - if (spotlightContent.actionPanel) { - spotlightContent.actionPanel.hide(); - } - } - - function _finishShow(query, mode) { - spotlightOpen = true; - isClosing = false; - openedFromOverview = false; - - keyboardActive = true; - ModalManager.openModal(root); - if (useHyprlandFocusGrab) - focusGrab.active = true; - - _ensureContentLoadedAndInitialize(query || "", mode || ""); - } - - function show() { - closeCleanupTimer.stop(); - - var focusedScreen = CompositorService.getFocusedScreen(); - if (focusedScreen && launcherWindow.screen !== focusedScreen) { - spotlightOpen = false; - isClosing = false; - launcherWindow.screen = focusedScreen; - Qt.callLater(() => root._finishShow("", "")); - return; - } - - _finishShow("", ""); - } - - function showWithQuery(query) { - closeCleanupTimer.stop(); - - var focusedScreen = CompositorService.getFocusedScreen(); - if (focusedScreen && launcherWindow.screen !== focusedScreen) { - spotlightOpen = false; - isClosing = false; - launcherWindow.screen = focusedScreen; - Qt.callLater(() => root._finishShow(query, "")); - return; - } - - _finishShow(query, ""); - } - - function hide() { - if (!spotlightOpen) - return; - openedFromOverview = false; - isClosing = true; - contentVisible = false; - - keyboardActive = false; - spotlightOpen = false; - focusGrab.active = false; - ModalManager.closeModal(root); - - closeCleanupTimer.start(); - } - - function toggle() { - spotlightOpen ? hide() : show(); - } - - function showWithMode(mode) { - closeCleanupTimer.stop(); - - var focusedScreen = CompositorService.getFocusedScreen(); - if (focusedScreen && launcherWindow.screen !== focusedScreen) { - spotlightOpen = false; - isClosing = false; - launcherWindow.screen = focusedScreen; - Qt.callLater(() => root._finishShow("", mode)); - return; - } - - spotlightOpen = true; - isClosing = false; - openedFromOverview = false; - - keyboardActive = true; - ModalManager.openModal(root); - if (useHyprlandFocusGrab) - focusGrab.active = true; - - _ensureContentLoadedAndInitialize("", mode); - } - - function toggleWithMode(mode) { - if (spotlightOpen) { - hide(); - } else { - showWithMode(mode); - } - } - - function toggleWithQuery(query) { - if (spotlightOpen) { - hide(); - } else { - showWithQuery(query); - } - } - - Timer { - id: closeCleanupTimer - interval: Theme.modalAnimationDuration + 50 - repeat: false - onTriggered: { - isClosing = false; - if (root.unloadContentOnClose) - launcherContentLoader.active = false; - dialogClosed(); - } - } - - Connections { - target: spotlightContent?.controller ?? null - - function onModeChanged(mode) { - if (spotlightContent.controller.autoSwitchedToFiles) - return; - SessionData.setLauncherLastMode(mode); - } - } - - HyprlandFocusGrab { - id: focusGrab - windows: [launcherWindow] - active: false - - onCleared: { - if (spotlightOpen) { - hide(); - } - } - } - - Connections { - target: ModalManager - function onCloseAllModalsExcept(excludedModal) { - if (excludedModal !== root && spotlightOpen) { - hide(); - } - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - if (Quickshell.screens.length === 0) - return; - - const screenName = launcherWindow.screen?.name; - if (screenName) { - for (let i = 0; i < Quickshell.screens.length; i++) { - if (Quickshell.screens[i].name === screenName) - return; - } - } - - if (spotlightOpen) - hide(); - - const newScreen = CompositorService.getFocusedScreen() ?? Quickshell.screens[0]; - if (newScreen) - launcherWindow.screen = newScreen; - } - } - - PanelWindow { - id: launcherWindow - visible: spotlightOpen || isClosing - color: "transparent" - exclusionMode: ExclusionMode.Ignore - - WindowBlur { - targetWindow: launcherWindow - readonly property real s: Math.min(1, modalContainer.scale) - blurX: root.modalX + root.modalWidth * (1 - s) * 0.5 - blurY: root.modalY + root.modalHeight * (1 - s) * 0.5 - blurWidth: (contentVisible && modalContainer.opacity > 0) ? root.modalWidth * s : 0 - blurHeight: (contentVisible && modalContainer.opacity > 0) ? root.modalHeight * s : 0 - blurRadius: root.cornerRadius - } - - WlrLayershell.namespace: "dms:spotlight" - WlrLayershell.layer: { - switch (Quickshell.env("DMS_MODAL_LAYER")) { - case "bottom": - console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "background": - console.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "overlay": - return WlrLayershell.Overlay; - default: - return WlrLayershell.Top; - } - } - WlrLayershell.keyboardFocus: keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None - - anchors { - top: true - bottom: true - left: true - right: true - } - - mask: Region { - item: spotlightOpen ? fullScreenMask : null - } - - Item { - id: fullScreenMask - anchors.fill: parent - } - - Rectangle { - id: backgroundDarken - anchors.fill: parent - color: "black" - opacity: contentVisible && SettingsData.modalDarkenBackground ? 0.5 : 0 - visible: contentVisible || opacity > 0 - - Behavior on opacity { - DankAnim { - duration: Theme.modalAnimationDuration - easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - } - - MouseArea { - anchors.fill: parent - enabled: spotlightOpen - onClicked: mouse => { - var contentX = modalContainer.x; - var contentY = modalContainer.y; - var contentW = modalContainer.width; - var contentH = modalContainer.height; - - if (mouse.x < contentX || mouse.x > contentX + contentW || mouse.y < contentY || mouse.y > contentY + contentH) { - root.hide(); - } - } - } - - Item { - id: modalContainer - x: root.modalX - y: root.modalY - width: root.modalWidth - height: root.modalHeight - visible: contentVisible || opacity > 0 - - opacity: contentVisible ? 1 : 0 - scale: contentVisible ? 1 : 0.96 - transformOrigin: Item.Center - - Behavior on opacity { - DankAnim { - duration: Theme.modalAnimationDuration - easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - Behavior on scale { - DankAnim { - duration: Theme.modalAnimationDuration - easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - ElevationShadow { - id: launcherShadowLayer - anchors.fill: parent - level: Theme.elevationLevel3 - fallbackOffset: 6 - targetColor: root.backgroundColor - borderColor: root.borderColor - borderWidth: root.borderWidth - targetRadius: root.cornerRadius - shadowEnabled: Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - } - - MouseArea { - anchors.fill: parent - onPressed: mouse => mouse.accepted = true - } - - FocusScope { - anchors.fill: parent - focus: keyboardActive - - Loader { - id: launcherContentLoader - anchors.fill: parent - active: !root.unloadContentOnClose || root.spotlightOpen || root.isClosing || root.contentVisible || root._pendingInitialize - asynchronous: false - sourceComponent: LauncherContent { - focus: true - parentModal: root - } - - onLoaded: { - if (root._pendingInitialize) { - root._initializeAndShow(root._pendingQuery, root._pendingMode); - root._pendingInitialize = false; - } - } - } - - Keys.onEscapePressed: event => { - root.hide(); - event.accepted = true; - } - } - - Rectangle { - anchors.fill: parent - radius: root.cornerRadius - color: "transparent" - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/GridItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/GridItem.qml deleted file mode 100644 index a7f39c3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/GridItem.qml +++ /dev/null @@ -1,105 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property var item: null - property bool isSelected: false - property bool isHovered: itemArea.containsMouse - property var controller: null - property int flatIndex: -1 - - signal clicked - signal rightClicked(real mouseX, real mouseY) - - readonly property string iconValue: { - if (!item) - return ""; - switch (item.iconType) { - case "material": - case "nerd": - return "material:" + (item.icon || "apps"); - case "unicode": - return "unicode:" + (item.icon || ""); - case "composite": - return item.iconFull || ""; - case "image": - default: - return item.icon || ""; - } - } - - readonly property int computedIconSize: Math.min(48, Math.max(32, width * 0.45)) - - radius: Theme.cornerRadius - color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent" - - DankRipple { - id: rippleLayer - rippleColor: Theme.surfaceText - cornerRadius: root.radius - } - - Column { - anchors.centerIn: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - width: parent.width - Theme.spacingM - - AppIconRenderer { - width: root.computedIconSize - height: root.computedIconSize - anchors.horizontalCenter: parent.horizontalCenter - iconValue: root.iconValue - iconSize: root.computedIconSize - fallbackText: (root.item?.name?.length > 0) ? root.item.name.charAt(0).toUpperCase() : "?" - iconColor: root.isSelected ? Theme.primary : Theme.surfaceText - materialIconSizeAdjustment: root.computedIconSize * 0.3 - } - - Text { - width: parent.width - text: root.item?._hName ?? root.item?.name ?? "" - textFormat: root.item?._hRich ? Text.RichText : Text.PlainText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - font.family: Theme.fontFamily - color: root.isSelected ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - maximumLineCount: 2 - wrapMode: Text.Wrap - } - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) - rippleLayer.trigger(mouse.x, mouse.y); - } - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - var scenePos = mapToItem(null, mouse.x, mouse.y); - root.rightClicked(scenePos.x, scenePos.y); - } else { - root.clicked(); - } - } - - onPositionChanged: { - if (root.controller) { - root.controller.keyboardNavigationActive = false; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ItemTransformers.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ItemTransformers.js deleted file mode 100644 index 61c108c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ItemTransformers.js +++ /dev/null @@ -1,237 +0,0 @@ -.pragma library - - .import "ControllerUtils.js" as Utils - -function transformApp(app, override, defaultActions, primaryActionLabel) { - var appId = app.id || app.execString || app.exec || ""; - - var actions = []; - if (app.actions && app.actions.length > 0) { - for (var i = 0; i < app.actions.length; i++) { - actions.push({ - name: app.actions[i].name, - icon: "play_arrow", - actionData: app.actions[i] - }); - } - } - - return { - id: appId, - type: "app", - name: override?.name || app.name || "", - subtitle: override?.comment || app.comment || "", - icon: override?.icon || app.icon || "application-x-executable", - iconType: "image", - section: "apps", - data: app, - keywords: app.keywords || [], - actions: actions, - primaryAction: { - name: primaryActionLabel, - icon: "open_in_new", - action: "launch" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: undefined - }; -} - -function transformCoreApp(app, openLabel) { - var iconName = "apps"; - var iconType = "material"; - - if (app.icon) { - if (app.icon.startsWith("svg+corner:")) { - iconType = "composite"; - } else if (app.icon.startsWith("material:")) { - iconName = app.icon.substring(9); - } else { - iconName = app.icon; - iconType = "image"; - } - } - - return { - id: app.builtInPluginId || app.action || "", - type: "app", - name: app.name || "", - subtitle: app.comment || "", - icon: iconName, - iconType: iconType, - iconFull: app.icon, - section: "apps", - data: app, - isCore: true, - actions: [], - primaryAction: { - name: openLabel, - icon: "open_in_new", - action: "launch" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: undefined - }; -} - -function transformBuiltInLauncherItem(item, pluginId, openLabel) { - var rawIcon = item.icon || "extension"; - var icon = Utils.stripIconPrefix(rawIcon); - var iconType = item.iconType; - if (!iconType) { - if (rawIcon.startsWith("material:")) - iconType = "material"; - else if (rawIcon.startsWith("unicode:")) - iconType = "unicode"; - else - iconType = "image"; - } - - return { - id: item.action || "", - type: "plugin", - name: item.name || "", - subtitle: item.comment || "", - icon: icon, - iconType: iconType, - section: "plugin_" + pluginId, - data: item, - pluginId: pluginId, - isBuiltInLauncher: true, - keywords: item.keywords || [], - actions: [], - primaryAction: { - name: openLabel, - icon: "open_in_new", - action: "execute" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: item._preScored - }; -} - -function transformFileResult(file, openLabel, openFolderLabel, copyPathLabel, openTerminalLabel) { - var filename = file.path ? file.path.split("/").pop() : ""; - var dirname = file.path ? file.path.substring(0, file.path.lastIndexOf("/")) : ""; - var isDir = file.is_dir || false; - - var actions = []; - if (isDir) { - if (openTerminalLabel) { - actions.push({ - name: openTerminalLabel, - icon: "terminal", - action: "open_terminal" - }); - } - } else { - actions.push({ - name: openFolderLabel, - icon: "folder_open", - action: "open_folder" - }); - } - actions.push({ - name: copyPathLabel, - icon: "content_copy", - action: "copy_path" - }); - - return { - id: file.path || "", - type: "file", - name: filename, - subtitle: dirname, - icon: isDir ? "folder" : Utils.getFileIcon(filename), - iconType: "material", - section: "files", - data: file, - actions: actions, - primaryAction: { - name: openLabel, - icon: "open_in_new", - action: "open" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: undefined - }; -} - -function transformPluginItem(item, pluginId, selectLabel) { - var rawIcon = item.icon || "extension"; - var icon = Utils.stripIconPrefix(rawIcon); - var iconType = item.iconType; - if (!iconType) { - if (rawIcon.startsWith("material:")) - iconType = "material"; - else if (rawIcon.startsWith("unicode:")) - iconType = "unicode"; - else - iconType = "image"; - } - - return { - id: item.id || item.name || "", - type: "plugin", - name: item.name || "", - subtitle: item.comment || item.description || "", - icon: icon, - iconType: iconType, - section: "plugin_" + pluginId, - data: item, - pluginId: pluginId, - keywords: item.keywords || [], - actions: item.actions || [], - primaryAction: item.primaryAction || { - name: selectLabel, - icon: "check", - action: "execute" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: item._preScored - }; -} - -function createPluginBrowseItem(pluginId, plugin, trigger, isBuiltIn, isAllowed, browseLabel, triggerLabel, noTriggerLabel) { - var rawIcon = isBuiltIn ? (plugin.cornerIcon || "extension") : (plugin.icon || "extension"); - return { - id: "browse_" + pluginId, - type: "plugin_browse", - name: plugin.name || pluginId, - subtitle: trigger ? triggerLabel.replace("%1", trigger) : noTriggerLabel, - icon: isBuiltIn ? rawIcon : Utils.stripIconPrefix(rawIcon), - iconType: isBuiltIn ? "material" : Utils.detectIconType(rawIcon), - section: "browse_plugins", - data: { - pluginId: pluginId, - plugin: plugin, - isBuiltIn: isBuiltIn - }, - actions: [ - { - name: "All", - icon: isAllowed ? "visibility" : "visibility_off", - action: "toggle_all_visibility" - } - ], - primaryAction: { - name: browseLabel, - icon: "arrow_forward", - action: "browse_plugin" - }, - _hName: "", - _hSub: "", - _hRich: false, - _preScored: undefined - }; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContent.qml deleted file mode 100644 index 4372515..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContent.qml +++ /dev/null @@ -1,1075 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -FocusScope { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string viewModeContext: "spotlight" - property alias searchField: searchField - property alias controller: controller - property alias resultsList: resultsList - property alias actionPanel: actionPanel - - property bool editMode: false - property var editingApp: null - property string editAppId: "" - - function resetScroll() { - resultsList.resetScroll(); - } - - function focusSearchField() { - searchField.forceActiveFocus(); - } - - function openEditMode(app) { - if (!app) - return; - editingApp = app; - editAppId = app.id || app.execString || app.exec || ""; - var existing = SessionData.getAppOverride(editAppId); - editNameField.text = existing?.name || ""; - editIconField.text = existing?.icon || ""; - editCommentField.text = existing?.comment || ""; - editEnvVarsField.text = existing?.envVars || ""; - editExtraFlagsField.text = existing?.extraFlags || ""; - editDgpuToggle.checked = existing?.launchOnDgpu || false; - editMode = true; - Qt.callLater(() => editNameField.forceActiveFocus()); - } - - function closeEditMode() { - editMode = false; - editingApp = null; - editAppId = ""; - Qt.callLater(() => searchField.forceActiveFocus()); - } - - function saveAppOverride() { - var override = {}; - if (editNameField.text.trim()) - override.name = editNameField.text.trim(); - if (editIconField.text.trim()) - override.icon = editIconField.text.trim(); - if (editCommentField.text.trim()) - override.comment = editCommentField.text.trim(); - if (editEnvVarsField.text.trim()) - override.envVars = editEnvVarsField.text.trim(); - if (editExtraFlagsField.text.trim()) - override.extraFlags = editExtraFlagsField.text.trim(); - if (editDgpuToggle.checked) - override.launchOnDgpu = true; - SessionData.setAppOverride(editAppId, override); - closeEditMode(); - } - - function resetAppOverride() { - SessionData.clearAppOverride(editAppId); - closeEditMode(); - } - - function showContextMenu(item, x, y, fromKeyboard) { - if (!item) - return; - if (!contextMenu.hasContextMenuActions(item)) - return; - contextMenu.show(x, y, item, fromKeyboard); - } - - anchors.fill: parent - focus: true - - Controller { - id: controller - active: root.parentModal?.spotlightOpen ?? true - viewModeContext: root.viewModeContext - - onItemExecuted: { - if (root.parentModal) { - root.parentModal.hide(); - } - if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) { - NiriService.toggleOverview(); - } - } - } - - LauncherContextMenu { - id: contextMenu - parent: root - controller: root.controller - searchField: root.searchField - parentHandler: root - - onEditAppRequested: app => { - root.openEditMode(app); - } - } - - Keys.onPressed: event => { - if (editMode) { - if (event.key === Qt.Key_Escape) { - closeEditMode(); - event.accepted = true; - } - return; - } - - var hasCtrl = event.modifiers & Qt.ControlModifier; - event.accepted = true; - - switch (event.key) { - case Qt.Key_Escape: - if (actionPanel.expanded) { - actionPanel.hide(); - return; - } - if (controller.clearPluginFilter()) - return; - if (root.parentModal) - root.parentModal.hide(); - return; - case Qt.Key_Backspace: - if (searchField.text.length === 0) { - if (controller.clearPluginFilter()) - return; - if (controller.autoSwitchedToFiles) { - controller.restorePreviousMode(); - return; - } - } - event.accepted = false; - return; - case Qt.Key_Down: - if (hasCtrl) { - controller.navigateHistory("down"); - } else { - controller.selectNext(); - } - return; - case Qt.Key_Up: - if (hasCtrl) { - controller.navigateHistory("up"); - } else { - controller.selectPrevious(); - } - return; - case Qt.Key_PageDown: - controller.selectPageDown(8); - return; - case Qt.Key_PageUp: - controller.selectPageUp(8); - return; - case Qt.Key_Right: - if (hasCtrl) { - controller.cycleMode(); - return; - } - if (controller.getCurrentSectionViewMode() !== "list") { - controller.selectRight(); - return; - } - event.accepted = false; - return; - case Qt.Key_Left: - if (hasCtrl) { - const reverse = true; - controller.cycleMode(reverse); - return; - } - if (controller.getCurrentSectionViewMode() !== "list") { - controller.selectLeft(); - return; - } - event.accepted = false; - return; - case Qt.Key_H: - if (hasCtrl) { - const reverse = true; - controller.cycleMode(reverse); - return; - } - event.accepted = false; - return; - case Qt.Key_J: - if (hasCtrl) { - controller.selectNext(); - return; - } - event.accepted = false; - return; - case Qt.Key_K: - if (hasCtrl) { - controller.selectPrevious(); - return; - } - event.accepted = false; - return; - case Qt.Key_L: - if (hasCtrl) { - controller.cycleMode(); - return; - } - event.accepted = false; - return; - case Qt.Key_N: - if (hasCtrl) { - controller.selectNextSection(); - return; - } - event.accepted = false; - return; - case Qt.Key_P: - if (hasCtrl) { - controller.selectPreviousSection(); - return; - } - event.accepted = false; - return; - case Qt.Key_Tab: - if (hasCtrl && actionPanel.hasActions) { - actionPanel.expanded ? actionPanel.cycleAction() : actionPanel.show(); - return; - } - controller.selectNext(); - return; - case Qt.Key_Backtab: - if (hasCtrl && actionPanel.expanded) { - const reverse = true; - actionPanel.expanded ? actionPanel.cycleAction(reverse) : actionPanel.show(); - return; - } - controller.selectPrevious(); - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (event.modifiers & Qt.ShiftModifier) { - controller.pasteSelected(); - return; - } - if (actionPanel.expanded && actionPanel.selectedActionIndex > 0) { - actionPanel.executeSelectedAction(); - } else { - controller.executeSelected(); - } - return; - case Qt.Key_Menu: - case Qt.Key_F10: - if (contextMenu.hasContextMenuActions(controller.selectedItem)) { - var scenePos = resultsList.getSelectedItemPosition(); - var localPos = root.mapFromItem(null, scenePos.x, scenePos.y); - showContextMenu(controller.selectedItem, localPos.x, localPos.y, true); - } - return; - case Qt.Key_1: - if (hasCtrl) { - controller.setMode("all"); - return; - } - event.accepted = false; - return; - case Qt.Key_2: - if (hasCtrl) { - controller.setMode("apps"); - return; - } - event.accepted = false; - return; - case Qt.Key_3: - if (hasCtrl) { - controller.setMode("files"); - return; - } - event.accepted = false; - return; - case Qt.Key_4: - if (hasCtrl) { - controller.setMode("plugins"); - return; - } - event.accepted = false; - return; - case Qt.Key_Slash: - if (event.modifiers === Qt.NoModifier && searchField.text.length === 0) { - controller.setMode("files", true); - return; - } - event.accepted = false; - return; - default: - event.accepted = false; - } - } - - Item { - anchors.fill: parent - visible: !editMode && !(root.parentModal?.isClosing ?? false) - - Item { - id: footerBar - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.leftMargin: root.parentModal?.borderWidth ?? 1 - anchors.rightMargin: root.parentModal?.borderWidth ?? 1 - anchors.bottomMargin: root.parentModal?.borderWidth ?? 1 - readonly property bool showFooter: SettingsData.dankLauncherV2Size !== "micro" && SettingsData.dankLauncherV2ShowFooter - height: showFooter ? 36 : 0 - visible: showFooter - clip: true - - Rectangle { - anchors.fill: parent - anchors.topMargin: -Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - } - - Row { - id: modeButtonsRow - anchors.left: parent.left - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight - spacing: 2 - - Repeater { - model: [ - { - id: "all", - label: I18n.tr("All"), - icon: "search" - }, - { - id: "apps", - label: I18n.tr("Apps"), - icon: "apps" - }, - { - id: "files", - label: I18n.tr("Files"), - icon: "folder" - }, - { - id: "plugins", - label: I18n.tr("Plugins"), - icon: "extension" - } - ] - - Rectangle { - required property var modelData - required property int index - - width: buttonContent.width + Theme.spacingM * 2 - height: 28 - radius: Theme.cornerRadius - color: controller.searchMode === modelData.id || modeArea.containsMouse ? Theme.primaryContainer : "transparent" - - Row { - id: buttonContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: modelData.icon - size: 14 - color: controller.searchMode === modelData.id ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: controller.searchMode === modelData.id ? Theme.primary : Theme.surfaceText - } - } - - MouseArea { - id: modeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: controller.setMode(modelData.id) - } - } - } - } - - Row { - id: hintsRow - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight - spacing: Theme.spacingM - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: "↑↓ " + I18n.tr("nav") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: "↵ " + I18n.tr("open") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: "Ctrl-Tab " + I18n.tr("actions") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - visible: actionPanel.hasActions - } - } - } - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: footerBar.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingM - spacing: Theme.spacingXS - clip: false - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - id: pluginBadge - visible: controller.activePluginName.length > 0 - width: visible ? pluginBadgeContent.implicitWidth + Theme.spacingM : 0 - height: searchField.height - radius: 16 - color: Theme.primary - - Row { - id: pluginBadgeContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "extension" - size: 14 - color: Theme.primaryText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: controller.activePluginName - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primaryText - } - } - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - DankTextField { - id: searchField - width: parent.width - (pluginBadge.visible ? pluginBadge.width + Theme.spacingS : 0) - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: controller.activePluginId ? "extension" : controller.searchQuery.startsWith("/") ? "folder" : "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeLarge - enabled: root.parentModal ? root.parentModal.spotlightOpen : true - placeholderText: "" - ignoreUpDownKeys: true - ignoreTabKeys: true - keyForwardTargets: [root] - - onTextChanged: { - controller.setSearchQuery(text); - if (actionPanel.expanded) { - actionPanel.hide(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - if (root.parentModal) { - root.parentModal.hide(); - } - event.accepted = true; - } else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter)) { - if (actionPanel.expanded && actionPanel.selectedActionIndex > 0) { - actionPanel.executeSelectedAction(); - } else { - controller.executeSelected(); - } - event.accepted = true; - } - } - } - } - - Row { - id: categoryRow - width: parent.width - readonly property bool showPluginCategories: controller.activePluginCategories.length > 0 - height: showPluginCategories ? 36 : 0 - visible: showPluginCategories - spacing: Theme.spacingS - - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - DankDropdown { - id: categoryDropdown - visible: categoryRow.showPluginCategories - width: Math.min(200, parent.width) - compactMode: true - dropdownWidth: 200 - popupWidth: 240 - maxPopupHeight: 300 - enableFuzzySearch: controller.activePluginCategories.length > 8 - currentValue: { - const cats = controller.activePluginCategories; - const current = controller.activePluginCategory; - if (!current) - return cats.length > 0 ? cats[0].name : ""; - for (let i = 0; i < cats.length; i++) { - if (cats[i].id === current) - return cats[i].name; - } - return cats.length > 0 ? cats[0].name : ""; - } - options: { - const cats = controller.activePluginCategories; - const names = []; - for (let i = 0; i < cats.length; i++) - names.push(cats[i].name); - return names; - } - - onValueChanged: value => { - const cats = controller.activePluginCategories; - for (let i = 0; i < cats.length; i++) { - if (cats[i].name === value) { - controller.setActivePluginCategory(cats[i].id); - return; - } - } - } - } - } - - Item { - id: fileFilterRow - width: parent.width - height: showFileFilters ? fileFilterContent.height : 0 - visible: showFileFilters - - readonly property bool showFileFilters: controller.searchMode === "files" - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: fileFilterContent - width: parent.width - spacing: Theme.spacingS - - Row { - id: typeChips - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - visible: DSearchService.supportsTypeFilter - - Repeater { - model: [ - { - id: "all", - label: I18n.tr("All"), - icon: "search" - }, - { - id: "file", - label: I18n.tr("Files"), - icon: "insert_drive_file" - }, - { - id: "dir", - label: I18n.tr("Folders"), - icon: "folder" - } - ] - - Rectangle { - required property var modelData - required property int index - - width: chipContent.width + Theme.spacingM * 2 - height: sortDropdown.height - radius: Theme.cornerRadius - color: controller.fileSearchType === modelData.id || chipArea.containsMouse ? Theme.primaryContainer : "transparent" - - Row { - id: chipContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: modelData.icon - size: 14 - color: controller.fileSearchType === modelData.id ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: controller.fileSearchType === modelData.id ? Theme.primary : Theme.surfaceText - } - } - - MouseArea { - id: chipArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: controller.setFileSearchType(modelData.id) - } - } - } - } - - Rectangle { - width: 1 - height: 20 - anchors.verticalCenter: parent.verticalCenter - color: Theme.outlineMedium - visible: typeChips.visible - } - - DankDropdown { - id: sortDropdown - anchors.verticalCenter: parent.verticalCenter - width: Math.min(130, parent.width / 3) - compactMode: true - dropdownWidth: 130 - popupWidth: 150 - maxPopupHeight: 200 - currentValue: { - switch (controller.fileSearchSort) { - case "score": - return I18n.tr("Score"); - case "name": - return I18n.tr("Name"); - case "modified": - return I18n.tr("Modified"); - case "size": - return I18n.tr("Size"); - default: - return I18n.tr("Score"); - } - } - options: [I18n.tr("Score"), I18n.tr("Name"), I18n.tr("Modified"), I18n.tr("Size")] - - onValueChanged: value => { - var sortMap = {}; - sortMap[I18n.tr("Score")] = "score"; - sortMap[I18n.tr("Name")] = "name"; - sortMap[I18n.tr("Modified")] = "modified"; - sortMap[I18n.tr("Size")] = "size"; - controller.setFileSearchSort(sortMap[value] || "score"); - } - } - - DankTextField { - id: extFilterField - anchors.verticalCenter: parent.verticalCenter - width: Math.min(100, parent.width / 4) - height: sortDropdown.height - placeholderText: I18n.tr("ext") - font.pixelSize: Theme.fontSizeSmall - showClearButton: text.length > 0 - - onTextChanged: { - controller.setFileSearchExt(text.trim()); - } - } - } - } - - Item { - width: parent.width - height: parent.height - searchField.height - categoryRow.height - fileFilterRow.height - actionPanel.height - Theme.spacingXS * ((categoryRow.visible ? 1 : 0) + (fileFilterRow.visible ? 1 : 0) + 2) - ResultsList { - id: resultsList - anchors.fill: parent - controller: root.controller - - onItemRightClicked: (index, item, sceneX, sceneY) => { - if (item && contextMenu.hasContextMenuActions(item)) { - var localPos = root.mapFromItem(null, sceneX, sceneY); - root.showContextMenu(item, localPos.x, localPos.y, false); - } - } - } - } - - ActionPanel { - id: actionPanel - width: parent.width - selectedItem: controller.selectedItem - controller: controller - } - } - } - - Connections { - target: controller - function onSelectedItemChanged() { - if (actionPanel.expanded && !actionPanel.hasActions) { - actionPanel.hide(); - } - } - function onSearchQueryRequested(query) { - searchField.text = query; - searchField.cursorPosition = query.length; - } - function onModeChanged() { - extFilterField.text = ""; - } - } - - FocusScope { - id: editView - anchors.fill: parent - anchors.margins: Theme.spacingM - visible: editMode - focus: editMode - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - closeEditMode(); - event.accepted = true; - } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (event.modifiers & Qt.ControlModifier) { - saveAppOverride(); - event.accepted = true; - } - } else if (event.key === Qt.Key_S && event.modifiers & Qt.ControlModifier) { - saveAppOverride(); - event.accepted = true; - } - } - - Column { - anchors.fill: parent - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: 40 - height: 40 - radius: Theme.cornerRadius - color: backButtonArea.containsMouse ? Theme.surfaceHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "arrow_back" - size: 20 - color: Theme.surfaceText - } - - MouseArea { - id: backButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: closeEditMode() - } - } - - Image { - width: 40 - height: 40 - source: Paths.resolveIconUrl(editingApp?.icon || "application-x-executable") - sourceSize.width: 40 - sourceSize.height: 40 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: I18n.tr("Edit App") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: editingApp?.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - } - - Flickable { - width: parent.width - height: parent.height - y - buttonsRow.height - Theme.spacingM - contentHeight: editFieldsColumn.height - clip: true - boundsBehavior: Flickable.StopAtBounds - - Column { - id: editFieldsColumn - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - spacing: 4 - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - DankTextField { - id: editNameField - width: parent.width - placeholderText: editingApp?.name || "" - keyNavigationTab: editIconField - keyNavigationBacktab: editExtraFlagsField - } - } - - Column { - width: parent.width - spacing: 4 - - StyledText { - text: I18n.tr("Icon") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - DankTextField { - id: editIconField - width: parent.width - placeholderText: editingApp?.icon || "" - keyNavigationTab: editCommentField - keyNavigationBacktab: editNameField - } - } - - Column { - width: parent.width - spacing: 4 - - StyledText { - text: I18n.tr("Description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - DankTextField { - id: editCommentField - width: parent.width - placeholderText: editingApp?.comment || "" - keyNavigationTab: editEnvVarsField - keyNavigationBacktab: editIconField - } - } - - Column { - width: parent.width - spacing: 4 - - StyledText { - text: I18n.tr("Environment Variables") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: "KEY=value KEY2=value2" - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - id: editEnvVarsField - width: parent.width - placeholderText: "VAR=value" - keyNavigationTab: editExtraFlagsField - keyNavigationBacktab: editCommentField - } - } - - Column { - width: parent.width - spacing: 4 - - StyledText { - text: I18n.tr("Extra Arguments") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - DankTextField { - id: editExtraFlagsField - width: parent.width - placeholderText: "--flag --option=value" - keyNavigationTab: editNameField - keyNavigationBacktab: editEnvVarsField - } - } - - DankToggle { - id: editDgpuToggle - width: parent.width - text: I18n.tr("Launch on dGPU by default") - visible: SessionService.nvidiaCommand.length > 0 - checked: false - onToggled: checked => editDgpuToggle.checked = checked - } - } - } - - Row { - id: buttonsRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Rectangle { - id: resetButton - width: 90 - height: 40 - radius: Theme.cornerRadius - color: resetButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha - visible: SessionData.getAppOverride(editAppId) !== null - - StyledText { - text: I18n.tr("Reset") - font.pixelSize: Theme.fontSizeMedium - color: Theme.error - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: resetButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: resetAppOverride() - } - } - - Rectangle { - id: cancelButton - width: 90 - height: 40 - radius: Theme.cornerRadius - color: cancelButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha - - StyledText { - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: cancelButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: closeEditMode() - } - } - - Rectangle { - id: saveButton - width: 90 - height: 40 - radius: Theme.cornerRadius - color: saveButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.9) : Theme.primary - - StyledText { - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeMedium - color: Theme.primaryText - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - id: saveButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: saveAppOverride() - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml deleted file mode 100644 index 3c55590..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml +++ /dev/null @@ -1,510 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Popup { - id: root - - property var item: null - property var controller: null - property var searchField: null - property var parentHandler: null - - signal hideRequested - signal editAppRequested(var app) - - function hasContextMenuActions(spotlightItem) { - if (!spotlightItem) - return false; - if (spotlightItem.type === "app") - return true; - if (spotlightItem.type === "plugin" && spotlightItem.pluginId) { - var instance = PluginService.pluginInstances[spotlightItem.pluginId]; - if (!instance) - return false; - if (typeof instance.getContextMenuActions !== "function") - return false; - var actions = instance.getContextMenuActions(spotlightItem.data); - return Array.isArray(actions) && actions.length > 0; - } - return false; - } - - readonly property bool isCoreApp: item?.type === "app" && !!item?.isCore - readonly property var coreAppData: isCoreApp ? item?.data ?? null : null - readonly property var desktopEntry: !isCoreApp ? (item?.data ?? null) : null - readonly property string appId: { - if (isCoreApp) { - return item?.id || coreAppData?.builtInPluginId || ""; - } - return desktopEntry?.id || desktopEntry?.execString || ""; - } - readonly property bool isPinned: appId ? SessionData.isPinnedApp(appId) : false - readonly property bool isRegularApp: item?.type === "app" && !item.isCore && desktopEntry - readonly property bool isPluginItem: item?.type === "plugin" - - function getPluginContextMenuActions() { - if (!isPluginItem || !item?.pluginId) - return []; - - var instance = PluginService.pluginInstances[item.pluginId]; - if (!instance) - return []; - if (typeof instance.getContextMenuActions !== "function") - return []; - - var actions = instance.getContextMenuActions(item.data); - if (!Array.isArray(actions)) - return []; - - return actions; - } - - function executePluginAction(actionOrObj) { - var actionFunc = typeof actionOrObj === "function" ? actionOrObj : actionOrObj?.action; - var closeLauncher = typeof actionOrObj === "object" && actionOrObj?.closeLauncher; - - if (typeof actionFunc === "function") - actionFunc(); - - if (closeLauncher) { - controller?.itemExecuted(); - } else { - controller?.performSearch(); - } - hide(); - } - - readonly property var menuItems: { - var items = []; - - if (isPluginItem) { - var pluginActions = getPluginContextMenuActions(); - for (var i = 0; i < pluginActions.length; i++) { - var act = pluginActions[i]; - items.push({ - type: "item", - icon: act.icon || "play_arrow", - text: act.text || act.name || "", - pluginAction: act - }); - } - return items; - } - - if (item?.type === "app") { - items.push({ - type: "item", - icon: isPinned ? "keep_off" : "push_pin", - text: isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock"), - action: togglePin - }); - } - - if (isRegularApp) { - items.push({ - type: "item", - icon: "visibility_off", - text: I18n.tr("Hide App"), - action: hideCurrentApp - }); - items.push({ - type: "item", - icon: "edit", - text: I18n.tr("Edit App"), - action: editCurrentApp - }); - } - - if (item?.actions && item.actions.length > 0) { - items.push({ - type: "separator" - }); - for (var i = 0; i < item.actions.length; i++) { - var act = item.actions[i]; - items.push({ - type: "item", - icon: act.icon || "play_arrow", - text: act.name || "", - actionData: act - }); - } - } - - items.push({ - type: "separator" - }); - - if (isRegularApp && SessionService.nvidiaCommand) { - items.push({ - type: "item", - icon: "memory", - text: I18n.tr("Launch on dGPU"), - action: launchWithNvidia - }); - } - - items.push({ - type: "item", - icon: "launch", - text: I18n.tr("Launch"), - action: launchApp - }); - - return items; - } - - function show(x, y, spotlightItem, fromKeyboard) { - if (!spotlightItem?.data) - return; - item = spotlightItem; - selectedMenuIndex = fromKeyboard ? 0 : -1; - keyboardNavigation = fromKeyboard; - - if (parentHandler) - parentHandler.enabled = false; - - Qt.callLater(() => { - var parentW = parent?.width ?? 500; - var parentH = parent?.height ?? 600; - var menuW = width > 0 ? width : 200; - var menuH = height > 0 ? height : 200; - var margin = 8; - - var posX = x + 4; - var posY = y + 4; - - if (posX + menuW > parentW - margin) { - posX = Math.max(margin, parentW - menuW - margin); - } - if (posY + menuH > parentH - margin) { - posY = Math.max(margin, parentH - menuH - margin); - } - - root.x = posX; - root.y = posY; - open(); - }); - } - - function hide() { - if (parentHandler) - parentHandler.enabled = true; - close(); - } - - function togglePin() { - if (!appId) - return; - if (isPinned) - SessionData.removePinnedApp(appId); - else - SessionData.addPinnedApp(appId); - hide(); - } - - function hideCurrentApp() { - if (!appId) - return; - SessionData.hideApp(appId); - controller?.performSearch(); - hide(); - } - - function editCurrentApp() { - if (!desktopEntry) - return; - editAppRequested(desktopEntry); - hide(); - } - - function launchApp() { - if (isCoreApp) { - if (!coreAppData) - return; - AppSearchService.executeCoreApp(coreAppData); - controller?.itemExecuted(); - hide(); - return; - } - if (!desktopEntry) - return; - SessionService.launchDesktopEntry(desktopEntry); - AppUsageHistoryData.addAppUsage(desktopEntry); - controller?.itemExecuted(); - hide(); - } - - function launchWithNvidia() { - if (!desktopEntry) - return; - SessionService.launchDesktopEntry(desktopEntry, true); - AppUsageHistoryData.addAppUsage(desktopEntry); - controller?.itemExecuted(); - hide(); - } - - function executeDesktopAction(actionData) { - if (!desktopEntry || !actionData) - return; - SessionService.launchDesktopAction(desktopEntry, actionData.actionData || actionData); - AppUsageHistoryData.addAppUsage(desktopEntry); - controller?.itemExecuted(); - hide(); - } - - property int selectedMenuIndex: 0 - property bool keyboardNavigation: false - - readonly property int visibleItemCount: { - var count = 0; - for (var i = 0; i < menuItems.length; i++) { - if (menuItems[i].type === "item") - count++; - } - return count; - } - - function selectNext() { - if (visibleItemCount > 0) - selectedMenuIndex = (selectedMenuIndex + 1) % visibleItemCount; - } - - function selectPrevious() { - if (visibleItemCount > 0) - selectedMenuIndex = (selectedMenuIndex - 1 + visibleItemCount) % visibleItemCount; - } - - function activateSelected() { - var itemIndex = 0; - for (var i = 0; i < menuItems.length; i++) { - if (menuItems[i].type !== "item") - continue; - if (itemIndex === selectedMenuIndex) { - var menuItem = menuItems[i]; - if (menuItem.action) - menuItem.action(); - else if (menuItem.pluginAction) - executePluginAction(menuItem.pluginAction); - else if (menuItem.actionData) - executeDesktopAction(menuItem.actionData); - return; - } - itemIndex++; - } - } - - width: menuContainer.implicitWidth - height: menuContainer.implicitHeight - padding: 0 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - modal: true - dim: false - background: Item {} - - onOpened: { - Qt.callLater(() => keyboardHandler.forceActiveFocus()); - } - - onClosed: { - if (parentHandler) - parentHandler.enabled = true; - if (searchField?.visible) { - Qt.callLater(() => searchField.forceActiveFocus()); - } - } - - enter: Transition { - NumberAnimation { - property: "opacity" - from: 0 - to: 1 - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - exit: Transition { - NumberAnimation { - property: "opacity" - from: 1 - to: 0 - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - contentItem: Item { - id: keyboardHandler - focus: true - implicitWidth: menuContainer.implicitWidth - implicitHeight: menuContainer.implicitHeight - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - root.activateSelected(); - event.accepted = true; - return; - case Qt.Key_Escape: - case Qt.Key_Left: - root.hide(); - event.accepted = true; - return; - } - } - - Rectangle { - id: menuContainer - anchors.fill: parent - implicitWidth: Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2) - implicitHeight: menuColumn.implicitHeight + Theme.spacingS * 2 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 1 - - Repeater { - model: root.menuItems - - Item { - id: menuItemDelegate - required property var modelData - required property int index - - width: menuColumn.width - height: modelData.type === "separator" ? 5 : 32 - - readonly property int itemIndex: { - var count = 0; - for (var i = 0; i < index; i++) { - if (root.menuItems[i].type === "item") - count++; - } - return count; - } - - Rectangle { - visible: menuItemDelegate.modelData.type === "separator" - width: parent.width - Theme.spacingS * 2 - height: parent.height - anchors.horizontalCenter: parent.horizontalCenter - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - } - - Rectangle { - visible: menuItemDelegate.modelData.type === "item" - width: parent.width - height: parent.height - radius: Theme.cornerRadius - color: { - if (root.keyboardNavigation && root.selectedMenuIndex === menuItemDelegate.itemIndex) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2); - } - return itemMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"; - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Item { - width: Theme.iconSize - 2 - height: Theme.iconSize - 2 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - visible: (menuItemDelegate.modelData?.icon ?? "").length > 0 - name: menuItemDelegate.modelData?.icon ?? "" - size: Theme.iconSize - 2 - color: Theme.surfaceText - opacity: 0.7 - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: menuItemDelegate.modelData.text || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.width - (Theme.iconSize - 2) - Theme.spacingS - } - } - - DankRipple { - id: menuItemRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: itemMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - root.keyboardNavigation = false; - root.selectedMenuIndex = menuItemDelegate.itemIndex; - } - onPressed: mouse => menuItemRipple.trigger(mouse.x, mouse.y) - onClicked: { - var menuItem = menuItemDelegate.modelData; - if (menuItem.action) - menuItem.action(); - else if (menuItem.pluginAction) - root.executePluginAction(menuItem.pluginAction); - else if (menuItem.actionData) - root.executeDesktopAction(menuItem.actionData); - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/NavigationHelpers.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/NavigationHelpers.js deleted file mode 100644 index 1e78b11..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/NavigationHelpers.js +++ /dev/null @@ -1,254 +0,0 @@ -.pragma library - -function getFirstItemIndex(flatModel) { - for (var i = 0; i < flatModel.length; i++) { - if (!flatModel[i].isHeader) - return i; - } - return 0; -} - -function findNextNonHeaderIndex(flatModel, startIndex) { - for (var i = startIndex; i < flatModel.length; i++) { - if (!flatModel[i].isHeader) - return i; - } - return -1; -} - -function findPrevNonHeaderIndex(flatModel, startIndex) { - for (var i = startIndex; i >= 0; i--) { - if (!flatModel[i].isHeader) - return i; - } - return -1; -} - -function getSectionBounds(flatModel, sectionId) { - if (flatModel._sectionBounds && flatModel._sectionBounds[sectionId]) - return flatModel._sectionBounds[sectionId]; - - var start = -1, end = -1; - for (var i = 0; i < flatModel.length; i++) { - if (flatModel[i].isHeader && flatModel[i].section?.id === sectionId) { - start = i + 1; - } else if (start >= 0 && !flatModel[i].isHeader && flatModel[i].sectionId === sectionId) { - end = i; - } else if (start >= 0 && end >= 0 && flatModel[i].sectionId !== sectionId) { - break; - } - } - return { - start: start, - end: end, - count: end >= start ? end - start + 1 : 0 - }; -} - -function getGridColumns(viewMode, gridColumns) { - switch (viewMode) { - case "tile": - return 3; - case "grid": - return gridColumns; - default: - return 1; - } -} - -function calculateNextIndex(flatModel, selectedFlatIndex, sectionId, viewMode, gridColumns, getSectionViewModeFn) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var entry = flatModel[selectedFlatIndex]; - if (!entry || entry.isHeader) { - var next = findNextNonHeaderIndex(flatModel, selectedFlatIndex + 1); - return next !== -1 ? next : selectedFlatIndex; - } - - var actualViewMode = viewMode || getSectionViewModeFn(entry.sectionId); - if (actualViewMode === "list") { - var next = findNextNonHeaderIndex(flatModel, selectedFlatIndex + 1); - return next !== -1 ? next : selectedFlatIndex; - } - - var bounds = getSectionBounds(flatModel, entry.sectionId); - var cols = getGridColumns(actualViewMode, gridColumns); - var posInSection = selectedFlatIndex - bounds.start; - var newPosInSection = posInSection + cols; - - if (newPosInSection < bounds.count) { - return bounds.start + newPosInSection; - } - - var currentRow = Math.floor(posInSection / cols); - var lastRow = Math.floor((bounds.count - 1) / cols); - if (currentRow < lastRow) { - return bounds.start + bounds.count - 1; - } - - var nextSection = findNextNonHeaderIndex(flatModel, bounds.end + 1); - return nextSection !== -1 ? nextSection : selectedFlatIndex; -} - -function calculatePrevIndex(flatModel, selectedFlatIndex, sectionId, viewMode, gridColumns, getSectionViewModeFn) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var entry = flatModel[selectedFlatIndex]; - if (!entry || entry.isHeader) { - var prev = findPrevNonHeaderIndex(flatModel, selectedFlatIndex - 1); - return prev !== -1 ? prev : selectedFlatIndex; - } - - var actualViewMode = viewMode || getSectionViewModeFn(entry.sectionId); - if (actualViewMode === "list") { - var prev = findPrevNonHeaderIndex(flatModel, selectedFlatIndex - 1); - return prev !== -1 ? prev : selectedFlatIndex; - } - - var bounds = getSectionBounds(flatModel, entry.sectionId); - var cols = getGridColumns(actualViewMode, gridColumns); - var posInSection = selectedFlatIndex - bounds.start; - var newPosInSection = posInSection - cols; - - if (newPosInSection >= 0) { - return bounds.start + newPosInSection; - } - - var prevItem = findPrevNonHeaderIndex(flatModel, bounds.start - 1); - return prevItem !== -1 ? prevItem : selectedFlatIndex; -} - -function calculateRightIndex(flatModel, selectedFlatIndex, getSectionViewModeFn) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var entry = flatModel[selectedFlatIndex]; - if (!entry || entry.isHeader) { - var next = findNextNonHeaderIndex(flatModel, selectedFlatIndex + 1); - return next !== -1 ? next : selectedFlatIndex; - } - - var viewMode = getSectionViewModeFn(entry.sectionId); - if (viewMode === "list") { - var next = findNextNonHeaderIndex(flatModel, selectedFlatIndex + 1); - return next !== -1 ? next : selectedFlatIndex; - } - - var bounds = getSectionBounds(flatModel, entry.sectionId); - var posInSection = selectedFlatIndex - bounds.start; - if (posInSection + 1 < bounds.count) { - return bounds.start + posInSection + 1; - } - return selectedFlatIndex; -} - -function calculateLeftIndex(flatModel, selectedFlatIndex, getSectionViewModeFn) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var entry = flatModel[selectedFlatIndex]; - if (!entry || entry.isHeader) { - var prev = findPrevNonHeaderIndex(flatModel, selectedFlatIndex - 1); - return prev !== -1 ? prev : selectedFlatIndex; - } - - var viewMode = getSectionViewModeFn(entry.sectionId); - if (viewMode === "list") { - var prev = findPrevNonHeaderIndex(flatModel, selectedFlatIndex - 1); - return prev !== -1 ? prev : selectedFlatIndex; - } - - var bounds = getSectionBounds(flatModel, entry.sectionId); - var posInSection = selectedFlatIndex - bounds.start; - if (posInSection > 0) { - return bounds.start + posInSection - 1; - } - return selectedFlatIndex; -} - -function calculateNextSectionIndex(flatModel, selectedFlatIndex) { - var currentSection = null; - if (selectedFlatIndex >= 0 && selectedFlatIndex < flatModel.length) { - currentSection = flatModel[selectedFlatIndex].sectionId; - } - - var foundCurrent = false; - for (var i = 0; i < flatModel.length; i++) { - if (flatModel[i].isHeader) { - if (foundCurrent) { - for (var j = i + 1; j < flatModel.length; j++) { - if (!flatModel[j].isHeader) - return j; - } - } - if (flatModel[i].section.id === currentSection) { - foundCurrent = true; - } - } - } - return selectedFlatIndex; -} - -function calculatePrevSectionIndex(flatModel, selectedFlatIndex) { - var currentSection = null; - if (selectedFlatIndex >= 0 && selectedFlatIndex < flatModel.length) { - currentSection = flatModel[selectedFlatIndex].sectionId; - } - - var lastSectionStart = -1; - var prevSectionStart = -1; - - for (var i = 0; i < flatModel.length; i++) { - if (flatModel[i].isHeader) { - if (flatModel[i].section.id === currentSection) { - break; - } - prevSectionStart = lastSectionStart; - lastSectionStart = i; - } - } - - if (prevSectionStart >= 0) { - for (var j = prevSectionStart + 1; j < flatModel.length; j++) { - if (!flatModel[j].isHeader) - return j; - } - } - return selectedFlatIndex; -} - -function calculatePageDownIndex(flatModel, selectedFlatIndex, visibleItems) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var itemsToSkip = visibleItems || 8; - var newIndex = selectedFlatIndex; - - for (var i = 0; i < itemsToSkip; i++) { - var next = findNextNonHeaderIndex(flatModel, newIndex + 1); - if (next === -1) - break; - newIndex = next; - } - - return newIndex; -} - -function calculatePageUpIndex(flatModel, selectedFlatIndex, visibleItems) { - if (flatModel.length === 0) - return selectedFlatIndex; - - var itemsToSkip = visibleItems || 8; - var newIndex = selectedFlatIndex; - - for (var i = 0; i < itemsToSkip; i++) { - var prev = findPrevNonHeaderIndex(flatModel, newIndex - 1); - if (prev === -1) - break; - newIndex = prev; - } - - return newIndex; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultItem.qml deleted file mode 100644 index 0a50cd3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultItem.qml +++ /dev/null @@ -1,196 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property var item: null - property bool isSelected: false - property bool isHovered: itemArea.containsMouse || allModeToggleArea.containsMouse - property var controller: null - property int flatIndex: -1 - - signal clicked - signal rightClicked(real mouseX, real mouseY) - - readonly property string iconValue: { - if (!item) - return ""; - switch (item.iconType) { - case "material": - case "nerd": - return "material:" + (item.icon || "apps"); - case "unicode": - return "unicode:" + (item.icon || ""); - case "composite": - return item.iconFull || ""; - case "image": - default: - return item.icon || ""; - } - } - - width: parent?.width ?? 200 - height: 52 - color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent" - radius: Theme.cornerRadius - - DankRipple { - id: rippleLayer - rippleColor: Theme.surfaceText - cornerRadius: root.radius - } - - MouseArea { - id: itemArea - z: 1 - anchors.fill: parent - anchors.rightMargin: root.item?.type === "plugin_browse" ? 40 : 0 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) - rippleLayer.trigger(mouse.x, mouse.y); - } - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - var scenePos = mapToItem(null, mouse.x, mouse.y); - root.rightClicked(scenePos.x, scenePos.y); - } else { - root.clicked(); - } - } - - onPositionChanged: { - if (root.controller) - root.controller.keyboardNavigationActive = false; - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - AppIconRenderer { - width: 36 - height: 36 - anchors.verticalCenter: parent.verticalCenter - iconValue: root.iconValue - iconSize: 36 - fallbackText: (root.item?.name?.length > 0) ? root.item.name.charAt(0).toUpperCase() : "?" - materialIconSizeAdjustment: 12 - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 36 - Theme.spacingM * 3 - rightContent.width - spacing: 2 - - Text { - width: parent.width - text: root.item?._hName ?? root.item?.name ?? "" - textFormat: root.item?._hRich ? Text.RichText : Text.PlainText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - font.family: Theme.fontFamily - color: Theme.surfaceText - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - - Text { - width: parent.width - text: root.item?._hSub ?? root.item?.subtitle ?? "" - textFormat: root.item?._hRich ? Text.RichText : Text.PlainText - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.fontFamily - color: Theme.surfaceVariantText - elide: Text.ElideRight - clip: true - visible: (root.item?.subtitle ?? "").length > 0 - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: rightContent - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - id: allModeToggle - visible: root.item?.type === "plugin_browse" - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: parent.verticalCenter - color: allModeToggleArea.containsMouse ? Theme.surfaceHover : "transparent" - - property bool isAllowed: { - if (root.item?.type !== "plugin_browse") - return false; - var pluginId = root.item?.data?.pluginId; - if (!pluginId) - return false; - SettingsData.launcherPluginVisibility; - return SettingsData.getPluginAllowWithoutTrigger(pluginId); - } - - DankIcon { - anchors.centerIn: parent - name: allModeToggle.isAllowed ? "visibility" : "visibility_off" - size: 18 - color: allModeToggle.isAllowed ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: allModeToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - var pluginId = root.item?.data?.pluginId; - if (!pluginId) - return; - SettingsData.setPluginAllowWithoutTrigger(pluginId, !allModeToggle.isAllowed); - } - } - } - - Rectangle { - visible: !!root.item?.type && root.item.type !== "app" && root.item.type !== "plugin_browse" - width: typeBadge.implicitWidth + Theme.spacingS * 2 - height: 20 - radius: 10 - color: Theme.surfaceVariantAlpha - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: typeBadge - anchors.centerIn: parent - text: { - if (!root.item) - return ""; - switch (root.item.type) { - case "plugin": - return I18n.tr("Plugin"); - case "file": - return root.item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File"); - default: - return ""; - } - } - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultsList.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultsList.qml deleted file mode 100644 index 53a2d45..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/ResultsList.qml +++ /dev/null @@ -1,498 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property var controller: null - property int gridColumns: controller?.gridColumns ?? 4 - property var _visualRows: [] - property var _flatIndexToRowMap: ({}) - property var _cumulativeHeights: [] - - signal itemRightClicked(int index, var item, real mouseX, real mouseY) - - function _rebuildVisualModel() { - var sections = root.controller?.sections ?? []; - var rows = []; - var indexMap = {}; - var cumHeights = []; - var cumY = 0; - - for (var s = 0; s < sections.length; s++) { - var section = sections[s]; - var sectionId = section.id; - - cumHeights.push(cumY); - rows.push({ - _rowId: "h_" + sectionId, - type: "header", - section: section, - sectionId: sectionId, - height: 32 - }); - cumY += 32; - - if (section.collapsed) - continue; - - var versionTrigger = root.controller?.viewModeVersion ?? 0; - void (versionTrigger); - var mode = root.controller?.getSectionViewMode(sectionId) ?? "list"; - var items = section.items ?? []; - var flatStartIndex = section.flatStartIndex ?? 0; - - if (mode === "list") { - for (var i = 0; i < items.length; i++) { - var flatIdx = flatStartIndex + i; - indexMap[flatIdx] = rows.length; - cumHeights.push(cumY); - rows.push({ - _rowId: items[i].id, - type: "list_item", - item: items[i], - flatIndex: flatIdx, - sectionId: sectionId, - height: 52 - }); - cumY += 52; - } - } else { - var cols = root.controller?.getGridColumns(sectionId) ?? root.gridColumns; - var cellWidth = mode === "tile" ? Math.floor(root.width / 3) : Math.floor(root.width / root.gridColumns); - var cellHeight = mode === "tile" ? cellWidth * 0.75 : cellWidth + 24; - var numRows = Math.ceil(items.length / cols); - - for (var r = 0; r < numRows; r++) { - var rowItems = []; - for (var c = 0; c < cols; c++) { - var idx = r * cols + c; - if (idx >= items.length) - break; - var fi = flatStartIndex + idx; - indexMap[fi] = rows.length; - rowItems.push({ - item: items[idx], - flatIndex: fi - }); - } - cumHeights.push(cumY); - rows.push({ - _rowId: "gr_" + sectionId + "_" + r, - type: "grid_row", - items: rowItems, - sectionId: sectionId, - viewMode: mode, - cols: cols, - height: cellHeight - }); - cumY += cellHeight; - } - } - } - - root._flatIndexToRowMap = indexMap; - root._cumulativeHeights = cumHeights; - root._visualRows = rows; - } - - onGridColumnsChanged: Qt.callLater(_rebuildVisualModel) - onWidthChanged: Qt.callLater(_rebuildVisualModel) - - Connections { - target: root.controller - function onSectionsChanged() { - Qt.callLater(root._rebuildVisualModel); - } - function onViewModeVersionChanged() { - Qt.callLater(root._rebuildVisualModel); - } - function onSearchModeChanged() { - root._visualRows = []; - root._cumulativeHeights = []; - root._flatIndexToRowMap = {}; - } - } - - function resetScroll() { - mainListView.contentY = mainListView.originY; - } - - function ensureVisible(index) { - if (index < 0 || !controller?.flatModel || index >= controller.flatModel.length) - return; - var entry = controller.flatModel[index]; - if (!entry || entry.isHeader) - return; - var rowIndex = _flatIndexToRowMap[index]; - if (rowIndex === undefined) - return; - - mainListView.positionViewAtIndex(rowIndex, ListView.Contain); - - if (stickyHeader.visible && rowIndex < _cumulativeHeights.length) { - var rowY = _cumulativeHeights[rowIndex]; - var scrollY = mainListView.contentY - mainListView.originY; - if (rowY < scrollY + stickyHeader.height) { - mainListView.contentY = Math.max(mainListView.originY, rowY - stickyHeader.height + mainListView.originY); - } - } - } - - function getSelectedItemPosition() { - var fallback = mapToItem(null, width / 2, height / 2); - if (!controller?.flatModel || controller.selectedFlatIndex < 0) - return fallback; - - var entry = controller.flatModel[controller.selectedFlatIndex]; - if (!entry || entry.isHeader) - return fallback; - - var rowIndex = _flatIndexToRowMap[controller.selectedFlatIndex]; - if (rowIndex === undefined) - return fallback; - - var rowY = (rowIndex < _cumulativeHeights.length) ? _cumulativeHeights[rowIndex] : 0; - var row = _visualRows[rowIndex]; - if (!row) - return fallback; - - var itemX = width / 2; - var itemH = row.height; - - if (row.type === "grid_row") { - var rowItems = row.items; - for (var i = 0; i < rowItems.length; i++) { - if (rowItems[i].flatIndex === controller.selectedFlatIndex) { - var cellWidth = row.viewMode === "tile" ? Math.floor(width / 3) : Math.floor(width / row.cols); - itemX = i * cellWidth + cellWidth / 2; - break; - } - } - } - - var visualY = rowY - mainListView.contentY + mainListView.originY + itemH / 2; - var clampedY = Math.max(40, Math.min(height - 40, visualY)); - return mapToItem(null, itemX, clampedY); - } - - Connections { - target: root.controller - function onSelectedFlatIndexChanged() { - if (root.controller?.keyboardNavigationActive) { - Qt.callLater(() => root.ensureVisible(root.controller.selectedFlatIndex)); - } - } - } - - DankListView { - id: mainListView - anchors.fill: parent - clip: true - scrollBarTopMargin: (root.controller?.sections?.length > 0) ? 32 : 0 - - model: ScriptModel { - values: root._visualRows - objectProp: "_rowId" - } - - add: null - remove: null - displaced: null - move: null - - delegate: Item { - id: delegateRoot - required property var modelData - required property int index - - width: mainListView.width - height: modelData?.height ?? 52 - - SectionHeader { - anchors.fill: parent - visible: delegateRoot.modelData?.type === "header" - section: delegateRoot.modelData?.section ?? null - controller: root.controller - viewMode: { - var vt = root.controller?.viewModeVersion ?? 0; - void (vt); - return root.controller?.getSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? "list"; - } - canChangeViewMode: { - var vt = root.controller?.viewModeVersion ?? 0; - void (vt); - return root.controller?.canChangeSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? false; - } - canCollapse: root.controller?.canCollapseSection(delegateRoot.modelData?.sectionId ?? "") ?? false - } - - ResultItem { - anchors.fill: parent - visible: delegateRoot.modelData?.type === "list_item" - item: delegateRoot.modelData?.type === "list_item" ? (delegateRoot.modelData?.item ?? null) : null - isSelected: delegateRoot.modelData?.type === "list_item" && (delegateRoot.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex - controller: root.controller - flatIndex: delegateRoot.modelData?.type === "list_item" ? (delegateRoot.modelData?.flatIndex ?? -1) : -1 - - onClicked: { - if (root.controller && delegateRoot.modelData?.item) { - root.controller.executeItem(delegateRoot.modelData.item); - } - } - - onRightClicked: (mouseX, mouseY) => { - root.itemRightClicked(delegateRoot.modelData?.flatIndex ?? -1, delegateRoot.modelData?.item ?? null, mouseX, mouseY); - } - } - - Row { - id: gridRowContent - anchors.fill: parent - visible: delegateRoot.modelData?.type === "grid_row" - - Repeater { - model: delegateRoot.modelData?.type === "grid_row" ? (delegateRoot.modelData?.items ?? []) : [] - - Item { - id: gridCellDelegate - required property var modelData - required property int index - - readonly property real cellWidth: delegateRoot.modelData?.viewMode === "tile" ? Math.floor(delegateRoot.width / 3) : Math.floor(delegateRoot.width / (delegateRoot.modelData?.cols ?? root.gridColumns)) - - width: cellWidth - height: delegateRoot.height - - GridItem { - width: parent.width - 4 - height: parent.height - 4 - anchors.centerIn: parent - visible: delegateRoot.modelData?.viewMode === "grid" - item: gridCellDelegate.modelData?.item ?? null - isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex - controller: root.controller - flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1 - - onClicked: { - if (root.controller && gridCellDelegate.modelData?.item) { - root.controller.executeItem(gridCellDelegate.modelData.item); - } - } - - onRightClicked: (mouseX, mouseY) => { - root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY); - } - } - - TileItem { - width: parent.width - 4 - height: parent.height - 4 - anchors.centerIn: parent - visible: delegateRoot.modelData?.viewMode === "tile" - item: gridCellDelegate.modelData?.item ?? null - isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex - controller: root.controller - flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1 - - onClicked: { - if (root.controller && gridCellDelegate.modelData?.item) { - root.controller.executeItem(gridCellDelegate.modelData.item); - } - } - - onRightClicked: (mouseX, mouseY) => { - root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY); - } - } - } - } - } - } - } - - Rectangle { - id: bottomShadow - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 24 - z: 100 - visible: { - if (BlurService.enabled) - return false; - if (mainListView.contentHeight <= mainListView.height) - return false; - var atBottom = mainListView.contentY >= mainListView.contentHeight - mainListView.height + mainListView.originY - 5; - if (atBottom) - return false; - - var flatModel = root.controller?.flatModel; - if (!flatModel || flatModel.length === 0) - return false; - var lastItemIdx = -1; - for (var i = flatModel.length - 1; i >= 0; i--) { - if (!flatModel[i].isHeader) { - lastItemIdx = i; - break; - } - } - if (lastItemIdx >= 0 && root.controller?.selectedFlatIndex === lastItemIdx) - return false; - return true; - } - gradient: Gradient { - GradientStop { - position: 0.0 - color: "transparent" - } - GradientStop { - position: 1.0 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - } - } - } - - Rectangle { - id: stickyHeader - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 32 - z: 101 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - visible: stickyHeaderSection !== null - - readonly property int versionTrigger: root.controller?.viewModeVersion ?? 0 - - readonly property var stickyHeaderSection: { - var scrollY = mainListView.contentY - mainListView.originY; - if (scrollY <= 0) - return null; - - var rows = root._visualRows; - var heights = root._cumulativeHeights; - if (rows.length === 0 || heights.length === 0) - return null; - - var lo = 0; - var hi = rows.length - 1; - while (lo < hi) { - var mid = (lo + hi + 1) >> 1; - if (mid < heights.length && heights[mid] <= scrollY) - lo = mid; - else - hi = mid - 1; - } - - for (var i = lo; i >= 0; i--) { - if (rows[i].type === "header") - return rows[i].section; - } - return null; - } - - SectionHeader { - width: parent.width - section: stickyHeader.stickyHeaderSection - controller: root.controller - viewMode: { - void (stickyHeader.versionTrigger); - return root.controller?.getSectionViewMode(stickyHeader.stickyHeaderSection?.id) ?? "list"; - } - canChangeViewMode: { - void (stickyHeader.versionTrigger); - return root.controller?.canChangeSectionViewMode(stickyHeader.stickyHeaderSection?.id) ?? false; - } - canCollapse: { - void (stickyHeader.versionTrigger); - return root.controller?.canCollapseSection(stickyHeader.stickyHeaderSection?.id) ?? false; - } - isSticky: true - } - } - - Item { - anchors.centerIn: parent - visible: (!root.controller?.sections || root.controller.sections.length === 0) && !root.controller?.isFileSearching - width: emptyColumn.implicitWidth - height: emptyColumn.implicitHeight - - Column { - id: emptyColumn - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: getEmptyIcon() - size: 48 - color: Theme.outlineButton - - function getEmptyIcon() { - var mode = root.controller?.searchMode ?? "all"; - switch (mode) { - case "files": - var fileType = root.controller?.fileSearchType ?? "all"; - switch (fileType) { - case "dir": - return "folder_open"; - case "file": - return "insert_drive_file"; - default: - return "folder_open"; - } - case "plugins": - return "extension"; - case "apps": - return "apps"; - default: - return "search_off"; - } - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: getEmptyText() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - - function getEmptyText() { - var mode = root.controller?.searchMode ?? "all"; - var hasQuery = root.controller?.searchQuery?.length > 0; - - switch (mode) { - case "files": - if (!DSearchService.dsearchAvailable) - return I18n.tr("File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch"); - if (!hasQuery) - return I18n.tr("Type to search files"); - if (root.controller.searchQuery.length < 2) - return I18n.tr("Type at least 2 characters"); - var fileType = root.controller?.fileSearchType ?? "all"; - switch (fileType) { - case "dir": - return I18n.tr("No folders found"); - case "file": - return I18n.tr("No files found"); - default: - return I18n.tr("No results found"); - } - case "plugins": - return hasQuery ? I18n.tr("No plugin results") : I18n.tr("Browse or search plugins"); - case "apps": - return I18n.tr("No apps found"); - default: - return I18n.tr("No results found"); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Scorer.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Scorer.js deleted file mode 100644 index 7d54df7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Scorer.js +++ /dev/null @@ -1,265 +0,0 @@ -.pragma library - -const Weights = { - exactMatch: 10000, - prefixMatch: 5000, - wordBoundary: 3000, - substring: 500, - fuzzy: 100, - frecency: 2000, - typeBonus: { - app: 1000, - plugin: 900, - file: 800, - action: 600 - } -} - -function tokenize(text) { - return text.toLowerCase().trim().split(/[\s\-_]+/).filter(function (w) { return w.length > 0 }) -} - -function hasWordBoundaryMatch(text, query) { - var textWords = tokenize(text) - var queryWords = tokenize(query) - - if (queryWords.length === 0) return false - if (queryWords.length > textWords.length) return false - - for (var i = 0; i <= textWords.length - queryWords.length; i++) { - var allMatch = true - for (var j = 0; j < queryWords.length; j++) { - if (!textWords[i + j].startsWith(queryWords[j])) { - allMatch = false - break - } - } - if (allMatch) return true - } - return false -} - -function levenshteinDistance(s1, s2) { - var len1 = s1.length - var len2 = s2.length - var prev = new Array(len2 + 1) - var curr = new Array(len2 + 1) - - for (var j = 0; j <= len2; j++) - prev[j] = j - - for (var i = 1; i <= len1; i++) { - curr[0] = i - for (var j = 1; j <= len2; j++) { - var cost = s1[i - 1] === s2[j - 1] ? 0 : 1 - curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost) - } - var tmp = prev - prev = curr - curr = tmp - } - return prev[len2] -} - -function fuzzyScore(text, query) { - var maxDistance = query.length === 3 ? 1 : query.length <= 6 ? 2 : 3 - var bestScore = 0 - - if (Math.abs(text.length - query.length) <= maxDistance) { - var distance = levenshteinDistance(text, query) - if (distance <= maxDistance) { - var maxLen = Math.max(text.length, query.length) - bestScore = 1 - (distance / maxLen) - } - } - - var words = tokenize(text) - for (var i = 0; i < words.length && bestScore < 0.8; i++) { - if (Math.abs(words[i].length - query.length) > maxDistance) continue - var wordDistance = levenshteinDistance(words[i], query) - if (wordDistance <= maxDistance) { - var wordMaxLen = Math.max(words[i].length, query.length) - var score = 1 - (wordDistance / wordMaxLen) - bestScore = Math.max(bestScore, score) - } - } - - return bestScore -} - -function getTimeBucketWeight(daysSinceUsed) { - for (var i = 0; i < TimeBuckets.length; i++) { - if (daysSinceUsed <= TimeBuckets[i].maxDays) { - return TimeBuckets[i].weight - } - } - return 10 -} - -function calculateTextScore(name, query) { - if (name === query) return Weights.exactMatch - if (name.startsWith(query)) return Weights.prefixMatch - if (hasWordBoundaryMatch(name, query)) return Weights.wordBoundary - if (name.includes(query)) return Weights.substring - - if (query.length >= 3) { - var fs = fuzzyScore(name, query) - if (fs > 0) return fs * Weights.fuzzy - } - - return 0 -} - -function score(item, query, frecencyData) { - var typeBonus = Weights.typeBonus[item.type] || 0 - - if (!query || query.length === 0) { - var usageCount = frecencyData ? frecencyData.usageCount : 0 - return typeBonus + (usageCount * 100) - } - - var name = (item.name || "").toLowerCase() - var q = query.toLowerCase() - - var textScore = calculateTextScore(name, q) - - if (textScore === 0 && item.subtitle) { - var subtitleScore = calculateTextScore(item.subtitle.toLowerCase(), q) - textScore = subtitleScore * 0.5 - } - - if (textScore === 0 && item.keywords) { - for (var i = 0; i < item.keywords.length; i++) { - var keywordScore = calculateTextScore(item.keywords[i].toLowerCase(), q) - if (keywordScore > 0) { - textScore = keywordScore * 0.3 - break - } - } - } - - if (textScore === 0) return 0 - - var usageBonus = frecencyData ? Math.min(frecencyData.usageCount * 50, Weights.frecency) : 0 - - return textScore + usageBonus + typeBonus -} - -function scoreItems(items, query, getFrecencyFn) { - var scored = [] - - for (var i = 0; i < items.length; i++) { - var item = items[i] - var itemScore - - if (item._preScored !== undefined && (query || item._preScored > 900)) { - itemScore = item._preScored - } else { - var frecencyData = getFrecencyFn ? getFrecencyFn(item) : null - itemScore = score(item, query, frecencyData) - } - - if (itemScore > 0 || !query || query.length === 0) { - scored.push({ - item: item, - score: itemScore - }) - } - } - - scored.sort(function (a, b) { - return b.score - a.score - }) - - return scored -} - -function groupBySection(scoredItems, sectionOrder, sortAlphabetically, maxPerSection) { - var sections = {} - var result = [] - var limit = maxPerSection || 50 - - for (var i = 0; i < sectionOrder.length; i++) { - var sectionId = sectionOrder[i].id - sections[sectionId] = { - id: sectionId, - title: sectionOrder[i].title, - icon: sectionOrder[i].icon, - priority: sectionOrder[i].priority, - items: [], - collapsed: false, - flatStartIndex: 0 - } - } - - for (var i = 0; i < scoredItems.length; i++) { - var scoredItem = scoredItems[i] - var item = scoredItem.item - var sectionId = item.section || "apps" - - if (sections[sectionId] && sections[sectionId].items.length < limit) { - sections[sectionId].items.push(item) - } else if (sections["apps"] && sections["apps"].items.length < limit) { - sections["apps"].items.push(item) - } - } - - for (var i = 0; i < sectionOrder.length; i++) { - var section = sections[sectionOrder[i].id] - if (section && section.items.length > 0) { - if (sortAlphabetically && section.id === "apps") { - section.items.sort(function (a, b) { - return (a.name || "").localeCompare(b.name || "") - }) - } - result.push(section) - } - } - - return result -} - -function flattenSections(sections) { - var flat = [] - flat._sectionBounds = null - var bounds = {} - - for (var i = 0; i < sections.length; i++) { - var section = sections[i] - - flat.push({ - isHeader: true, - section: section, - sectionId: section.id, - sectionIndex: i - }) - - var itemStart = flat.length - section.flatStartIndex = itemStart - - if (!section.collapsed) { - for (var j = 0; j < section.items.length; j++) { - flat.push({ - isHeader: false, - item: section.items[j], - sectionId: section.id, - sectionIndex: i, - indexInSection: j - }) - } - } - - var itemEnd = flat.length - 1 - var itemCount = flat.length - itemStart - if (itemCount > 0) { - bounds[section.id] = { - start: itemStart, - end: itemEnd, - count: itemCount - } - } - } - - flat._sectionBounds = bounds - return flat -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Section.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Section.qml deleted file mode 100644 index aba4c2f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/Section.qml +++ /dev/null @@ -1,114 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Item { - id: root - - property var section: null - property var controller: null - property string viewMode: "list" - property int gridColumns: 4 - property int startIndex: 0 - - signal itemClicked(int flatIndex) - signal itemRightClicked(int flatIndex, var item, real mouseX, real mouseY) - - height: headerItem.height + (section?.collapsed ? 0 : contentLoader.height + Theme.spacingXS) - width: parent?.width ?? 200 - - SectionHeader { - id: headerItem - width: parent.width - section: root.section - controller: root.controller - viewMode: root.viewMode - canChangeViewMode: root.controller?.canChangeSectionViewMode(root.section?.id) ?? true - - onViewModeToggled: { - if (root.controller && root.section) { - var newMode = root.viewMode === "list" ? "grid" : "list"; - root.controller.setSectionViewMode(root.section.id, newMode); - } - } - } - - Loader { - id: contentLoader - anchors.top: headerItem.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Theme.spacingXS - active: !root.section?.collapsed - visible: active - - sourceComponent: root.viewMode === "grid" ? gridComponent : listComponent - - Component { - id: listComponent - - Column { - spacing: 2 - width: contentLoader.width - - Repeater { - model: ScriptModel { - values: root.section?.items ?? [] - objectProp: "id" - } - - ResultItem { - required property var modelData - required property int index - - width: parent?.width ?? 200 - item: modelData - isSelected: (root.startIndex + index) === root.controller?.selectedFlatIndex - controller: root.controller - flatIndex: root.startIndex + index - - onClicked: root.itemClicked(root.startIndex + index) - onRightClicked: (mouseX, mouseY) => { - root.itemRightClicked(root.startIndex + index, modelData, mouseX, mouseY); - } - } - } - } - } - - Component { - id: gridComponent - - Flow { - width: contentLoader.width - spacing: 4 - - Repeater { - model: ScriptModel { - values: root.section?.items ?? [] - objectProp: "id" - } - - GridItem { - required property var modelData - required property int index - - width: Math.floor(contentLoader.width / root.gridColumns) - height: width + 24 - item: modelData - isSelected: (root.startIndex + index) === root.controller?.selectedFlatIndex - controller: root.controller - flatIndex: root.startIndex + index - - onClicked: root.itemClicked(root.startIndex + index) - onRightClicked: (mouseX, mouseY) => { - root.itemRightClicked(root.startIndex + index, modelData, mouseX, mouseY); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/SectionHeader.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/SectionHeader.qml deleted file mode 100644 index ee366c7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/SectionHeader.qml +++ /dev/null @@ -1,340 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var section: null - property var controller: null - property string viewMode: "list" - property bool canChangeViewMode: true - property bool canCollapse: true - property bool isSticky: false - - signal viewModeToggled - - width: parent?.width ?? 200 - height: 32 - color: isSticky ? "transparent" : (hoverArea.containsMouse ? Theme.surfaceHover : "transparent") - radius: Theme.cornerRadius - - MouseArea { - id: hoverArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - } - - Row { - id: leftContent - anchors.left: parent.left - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - // Whether the apps category picker should replace the plain title - readonly property bool hasAppCategories: root.section?.id === "apps" && (root.controller?.appCategories?.length ?? 0) > 0 - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - // Hide section icon when the category chip already shows one - visible: !leftContent.hasAppCategories - name: root.section?.icon ?? "folder" - size: 16 - color: Theme.surfaceVariantText - } - - // Plain title — hidden when the category chip is shown - StyledText { - anchors.verticalCenter: parent.verticalCenter - visible: !leftContent.hasAppCategories - text: root.section?.title ?? "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - // Compact inline category chip — only visible on the apps section - Item { - id: categoryChip - visible: leftContent.hasAppCategories - anchors.verticalCenter: parent.verticalCenter - // Size to content with a fixed-min width so it doesn't jump around - width: chipRow.implicitWidth + Theme.spacingM * 2 - height: 24 - - readonly property string currentCategory: root.controller?.appCategory || (root.controller?.appCategories?.length > 0 ? root.controller.appCategories[0] : "") - readonly property var iconMap: { - const cats = root.controller?.appCategories ?? []; - const m = {}; - cats.forEach(c => { m[c] = AppSearchService.getCategoryIcon(c); }); - return m; - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: chipArea.containsMouse || categoryPopup.visible ? Theme.surfaceContainerHigh : "transparent" - border.color: categoryPopup.visible ? Theme.primary : Theme.outlineMedium - border.width: categoryPopup.visible ? 2 : 1 - } - - Row { - id: chipRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: categoryChip.iconMap[categoryChip.currentCategory] ?? "apps" - size: 14 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: categoryChip.currentCategory - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: categoryPopup.visible ? "expand_less" : "expand_more" - size: 14 - color: Theme.surfaceVariantText - } - } - - MouseArea { - id: chipArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (categoryPopup.visible) { - categoryPopup.close(); - } else { - const pos = categoryChip.mapToItem(Overlay.overlay, 0, 0); - categoryPopup.x = pos.x; - categoryPopup.y = pos.y + categoryChip.height + 4; - categoryPopup.open(); - } - } - } - - Popup { - id: categoryPopup - parent: Overlay.overlay - width: Math.max(categoryChip.width, 180) - padding: 0 - modal: true - dim: false - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { color: "transparent" } - - contentItem: Rectangle { - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1) - border.color: Theme.primary - border.width: 2 - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: parent.radius - targetColor: parent.color - borderColor: parent.border.color - borderWidth: parent.border.width - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - } - - ListView { - id: categoryList - anchors.fill: parent - anchors.margins: Theme.spacingS - model: root.controller?.appCategories ?? [] - spacing: 2 - clip: true - interactive: contentHeight > height - implicitHeight: contentHeight - - delegate: Rectangle { - id: catDelegate - required property string modelData - required property int index - width: categoryList.width - height: 32 - radius: Theme.cornerRadius - readonly property bool isCurrent: categoryChip.currentCategory === modelData - color: isCurrent ? Theme.primaryHover : catArea.containsMouse ? Theme.primaryHoverLight : "transparent" - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: categoryChip.iconMap[catDelegate.modelData] ?? "apps" - size: 16 - color: catDelegate.isCurrent ? Theme.primary : Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: catDelegate.modelData - font.pixelSize: Theme.fontSizeMedium - color: catDelegate.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: catDelegate.isCurrent ? Font.Medium : Font.Normal - } - } - - MouseArea { - id: catArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.controller) - root.controller.setAppCategory(catDelegate.modelData); - categoryPopup.close(); - } - } - } - } - } - - // Size to list content, cap at 10 visible items - height: Math.min((root.controller?.appCategories?.length ?? 0) * 34, 10 * 34) + Theme.spacingS * 2 + 4 - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: root.section?.items?.length ?? 0 - font.pixelSize: Theme.fontSizeSmall - color: Theme.outlineButton - } - } - - Row { - id: rightContent - anchors.right: parent.right - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Row { - id: viewModeRow - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - visible: root.canChangeViewMode && !root.section?.collapsed - - Repeater { - model: [ - { - mode: "list", - icon: "view_list" - }, - { - mode: "grid", - icon: "grid_view" - }, - { - mode: "tile", - icon: "view_module" - } - ] - - Rectangle { - required property var modelData - required property int index - - width: 20 - height: 20 - radius: 4 - color: root.viewMode === modelData.mode ? Theme.primaryHover : modeArea.containsMouse ? Theme.surfaceHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: parent.modelData.icon - size: 14 - color: root.viewMode === parent.modelData.mode ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: modeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.viewMode !== parent.modelData.mode && root.controller && root.section) { - root.controller.setSectionViewMode(root.section.id, parent.modelData.mode); - } - } - } - } - } - } - - Item { - id: collapseButton - width: root.canCollapse ? 24 : 0 - height: 24 - visible: root.canCollapse - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: root.section?.collapsed ? "expand_more" : "expand_less" - size: 16 - color: collapseArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: collapseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.controller && root.section) { - root.controller.toggleSection(root.section.id); - } - } - } - } - } - - MouseArea { - anchors.fill: parent - anchors.rightMargin: rightContent.width + Theme.spacingS - cursorShape: root.canCollapse ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: root.canCollapse - onClicked: { - if (root.canCollapse && root.controller && root.section) { - root.controller.toggleSection(root.section.id); - } - } - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 1 - color: Theme.outlineMedium - visible: root.isSticky - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/TileItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/TileItem.qml deleted file mode 100644 index 0b48802..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DankLauncherV2/TileItem.qml +++ /dev/null @@ -1,199 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var item: null - property bool isSelected: false - property bool isHovered: itemArea.containsMouse - property var controller: null - property int flatIndex: -1 - - signal clicked - signal rightClicked(real mouseX, real mouseY) - - radius: Theme.cornerRadius - color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryPressed : "transparent" - border.width: isSelected ? 2 : 0 - border.color: Theme.primary - - readonly property string toplevelId: item?.data?.toplevelId ?? "" - readonly property var waylandToplevel: { - if (!toplevelId || !item?.pluginId) - return null; - const pluginInstance = PluginService.pluginInstances[item.pluginId]; - if (!pluginInstance?.getToplevelById) - return null; - return pluginInstance.getToplevelById(toplevelId); - } - readonly property bool hasScreencopy: waylandToplevel !== null - - readonly property string iconValue: { - if (!item) - return ""; - if (hasScreencopy) - return ""; - var data = item.data; - if (data?.imageUrl) - return "image:" + data.imageUrl; - if (data?.imagePath) - return "image:" + data.imagePath; - if (data?.path && isImageFile(data.path)) - return "image:" + data.path; - switch (item.iconType) { - case "material": - case "nerd": - return "material:" + (item.icon || "image"); - case "unicode": - return "unicode:" + (item.icon || ""); - case "composite": - return item.iconFull || ""; - case "image": - default: - return item.icon || ""; - } - } - - function isImageFile(path) { - if (!path) - return false; - var ext = path.split('.').pop().toLowerCase(); - return ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "jxl", "avif", "heif", "exr"].indexOf(ext) >= 0; - } - - DankRipple { - id: rippleLayer - rippleColor: Theme.surfaceText - cornerRadius: root.radius - } - - Item { - anchors.fill: parent - anchors.margins: 4 - - Rectangle { - id: imageContainer - anchors.fill: parent - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - clip: true - - ScreencopyView { - id: screencopyView - anchors.fill: parent - captureSource: root.waylandToplevel - live: root.hasScreencopy - visible: root.hasScreencopy - - Rectangle { - anchors.fill: parent - color: root.isHovered ? Theme.withAlpha(Theme.surfaceVariant, 0.2) : "transparent" - } - } - - AppIconRenderer { - anchors.fill: parent - iconValue: root.iconValue - iconSize: Math.min(parent.width, parent.height) - fallbackText: (root.item?.name?.length > 0) ? root.item.name.charAt(0).toUpperCase() : "?" - materialIconSizeAdjustment: iconSize * 0.3 - visible: !root.hasScreencopy - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: labelText.implicitHeight + Theme.spacingS * 2 - color: Theme.withAlpha(Theme.surfaceContainer, 0.85) - visible: root.item?.name?.length > 0 - - Text { - id: labelText - anchors.fill: parent - anchors.margins: Theme.spacingXS - text: root.item?._hName ?? root.item?.name ?? "" - textFormat: root.item?._hRich ? Text.RichText : Text.PlainText - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.fontFamily - color: Theme.surfaceText - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - } - - Rectangle { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXS - width: 20 - height: 20 - radius: 10 - color: Theme.primary - visible: root.isSelected - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 14 - color: Theme.primaryText - } - } - - Rectangle { - id: attributionBadge - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: Theme.spacingXS - width: root.hasScreencopy ? 28 : 40 - height: root.hasScreencopy ? 28 : 16 - radius: root.hasScreencopy ? 14 : 4 - color: root.hasScreencopy ? Theme.surfaceContainer : "transparent" - visible: attributionImage.status === Image.Ready - opacity: 0.95 - - Image { - id: attributionImage - anchors.fill: parent - anchors.margins: root.hasScreencopy ? 4 : 0 - fillMode: Image.PreserveAspectFit - source: root.item?.data?.attribution || "" - mipmap: true - } - } - } - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) - rippleLayer.trigger(mouse.x, mouse.y); - } - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - var scenePos = mapToItem(null, mouse.x, mouse.y); - root.rightClicked(scenePos.x, scenePos.y); - return; - } - root.clicked(); - } - - onPositionChanged: { - if (root.controller) - root.controller.keyboardNavigationActive = false; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DisplayConfirmationModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DisplayConfirmationModal.qml deleted file mode 100644 index f8a97de..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/DisplayConfirmationModal.qml +++ /dev/null @@ -1,212 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.Common -import qs.Widgets - -DankModal { - id: root - - property string outputName: "" - property var changes: [] - property int countdown: 10 - - signal confirmed - signal reverted - - shouldBeVisible: false - allowStacking: true - modalWidth: 420 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 200 - - Timer { - id: countdownTimer - interval: 1000 - repeat: true - running: root.shouldBeVisible - onTriggered: { - root.countdown--; - if (root.countdown <= 0) { - root.reverted(); - root.close(); - } - } - } - - onOpened: { - countdown = 10; - countdownTimer.start(); - } - - onDialogClosed: { - countdownTimer.stop(); - } - - onBackgroundClicked: { - root.reverted(); - root.close(); - } - - content: Component { - FocusScope { - id: confirmContent - - anchors.fill: parent - focus: true - implicitHeight: mainColumn.implicitHeight - - Keys.onEscapePressed: event => { - root.reverted(); - root.close(); - event.accepted = true; - } - - Keys.onReturnPressed: event => { - root.confirmed(); - root.close(); - event.accepted = true; - } - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Confirm Display Changes") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - Rectangle { - width: parent.width - height: 70 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - - StyledText { - anchors.centerIn: parent - text: root.countdown + "s" - font.pixelSize: Theme.fontSizeXLarge * 1.5 - color: Theme.primary - font.weight: Font.Bold - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: root.changes.length > 0 - - Repeater { - model: root.changes - - StyledText { - required property var modelData - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - width: Math.max(70, revertText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: revertArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: revertText - - anchors.centerIn: parent - text: I18n.tr("Revert") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: revertArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.reverted(); - root.close(); - } - } - } - - Rectangle { - width: Math.max(80, confirmText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: confirmArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: confirmText - - anchors.centerIn: parent - text: I18n.tr("Keep Changes") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: confirmArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.confirmed(); - root.close(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: { - root.reverted(); - root.close(); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserContent.qml deleted file mode 100644 index 8b96742..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserContent.qml +++ /dev/null @@ -1,920 +0,0 @@ -import Qt.labs.folderlistmodel -import QtCore -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -FocusScope { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation) - property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) - property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation) - property string videosDir: StandardPaths.writableLocation(StandardPaths.MoviesLocation) - property string picsDir: StandardPaths.writableLocation(StandardPaths.PicturesLocation) - property string downloadDir: StandardPaths.writableLocation(StandardPaths.DownloadLocation) - property string desktopDir: StandardPaths.writableLocation(StandardPaths.DesktopLocation) - property string currentPath: "" - property var fileExtensions: ["*.*"] - property alias filterExtensions: root.fileExtensions - property string browserTitle: "Select File" - property string browserIcon: "folder_open" - property string browserType: "generic" - property bool showHiddenFiles: false - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property bool backButtonFocused: false - property bool saveMode: false - property string defaultFileName: "" - property int keyboardSelectionIndex: -1 - property bool keyboardSelectionRequested: false - property bool showKeyboardHints: false - property bool showFileInfo: false - property string selectedFilePath: "" - property string selectedFileName: "" - property bool selectedFileIsDir: false - property bool showOverwriteConfirmation: false - property string pendingFilePath: "" - property bool showSidebar: true - property string viewMode: "grid" - property string sortBy: "name" - property bool sortAscending: true - property int iconSizeIndex: 1 - property var iconSizes: [80, 120, 160, 200] - property bool pathEditMode: false - property bool pathInputHasFocus: false - property int actualGridColumns: 5 - property bool _initialized: false - property bool closeOnEscape: true - property var windowControls: null - - signal fileSelected(string path) - signal closeRequested - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - function initialize() { - loadSettings(); - currentPath = getLastPath(); - _initialized = true; - } - - function reset() { - currentPath = getLastPath(); - selectedIndex = -1; - keyboardNavigationActive = false; - backButtonFocused = false; - } - - function loadSettings() { - const type = browserType || "default"; - const settings = CacheData.fileBrowserSettings[type]; - const isImageBrowser = ["wallpaper", "profile"].includes(browserType); - - if (settings) { - viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list"); - sortBy = settings.sortBy || "name"; - sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true; - iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1; - showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true; - } else { - viewMode = isImageBrowser ? "grid" : "list"; - } - } - - function saveSettings() { - if (!_initialized) - return; - const type = browserType || "default"; - let settings = CacheData.fileBrowserSettings; - if (!settings[type]) { - settings[type] = {}; - } - settings[type].viewMode = viewMode; - settings[type].sortBy = sortBy; - settings[type].sortAscending = sortAscending; - settings[type].iconSizeIndex = iconSizeIndex; - settings[type].showSidebar = showSidebar; - settings[type].lastPath = currentPath; - CacheData.fileBrowserSettings = settings; - - if (browserType === "wallpaper") { - CacheData.wallpaperLastPath = currentPath; - } else if (browserType === "profile") { - CacheData.profileLastPath = currentPath; - } - - CacheData.saveCache(); - } - - onViewModeChanged: saveSettings() - onSortByChanged: saveSettings() - onSortAscendingChanged: saveSettings() - onIconSizeIndexChanged: saveSettings() - onShowSidebarChanged: saveSettings() - - function isImageFile(fileName) { - if (!fileName) - return false; - const ext = fileName.toLowerCase().split('.').pop(); - return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext); - } - - function getLastPath() { - const type = browserType || "default"; - const settings = CacheData.fileBrowserSettings[type]; - const lastPath = settings?.lastPath || ""; - return (lastPath && lastPath !== "") ? lastPath : homeDir; - } - - function saveLastPath(path) { - const type = browserType || "default"; - let settings = CacheData.fileBrowserSettings; - if (!settings[type]) { - settings[type] = {}; - } - settings[type].lastPath = path; - CacheData.fileBrowserSettings = settings; - CacheData.saveCache(); - - if (browserType === "wallpaper") { - CacheData.wallpaperLastPath = path; - } else if (browserType === "profile") { - CacheData.profileLastPath = path; - } - } - - function setSelectedFileData(path, name, isDir) { - selectedFilePath = path; - selectedFileName = name; - selectedFileIsDir = isDir; - } - - function navigateUp() { - const path = currentPath; - if (path === homeDir) - return; - const lastSlash = path.lastIndexOf('/'); - if (lastSlash <= 0) - return; - const newPath = path.substring(0, lastSlash); - if (newPath.length < homeDir.length) { - currentPath = homeDir; - saveLastPath(homeDir); - } else { - currentPath = newPath; - saveLastPath(newPath); - } - } - - function navigateTo(path) { - currentPath = path; - saveLastPath(path); - selectedIndex = -1; - backButtonFocused = false; - } - - function keyboardFileSelection(index) { - if (index < 0) - return; - keyboardSelectionTimer.targetIndex = index; - keyboardSelectionTimer.start(); - } - - function executeKeyboardSelection(index) { - keyboardSelectionIndex = index; - keyboardSelectionRequested = true; - } - - function handleSaveFile(filePath) { - var normalizedPath = filePath; - if (!normalizedPath.startsWith("file://")) { - normalizedPath = encodeFileUrl(filePath); - } - - var exists = false; - var fileName = filePath.split('/').pop(); - - for (var i = 0; i < folderModel.count; i++) { - if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) { - exists = true; - break; - } - } - - if (exists) { - pendingFilePath = normalizedPath; - showOverwriteConfirmation = true; - } else { - fileSelected(normalizedPath); - closeRequested(); - } - } - - onCurrentPathChanged: { - selectedFilePath = ""; - selectedFileName = ""; - selectedFileIsDir = false; - saveSettings(); - } - - onSelectedIndexChanged: { - if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) { - selectedFilePath = ""; - selectedFileName = ""; - selectedFileIsDir = false; - } - } - - property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"] - - property var quickAccessLocations: [ - { - "name": I18n.tr("Home"), - "path": homeDir, - "icon": "home" - }, - { - "name": I18n.tr("Documents"), - "path": docsDir, - "icon": "description" - }, - { - "name": I18n.tr("Downloads"), - "path": downloadDir, - "icon": "download" - }, - { - "name": I18n.tr("Pictures"), - "path": picsDir, - "icon": "image" - }, - { - "name": I18n.tr("Music"), - "path": musicDir, - "icon": "music_note" - }, - { - "name": I18n.tr("Videos"), - "path": videosDir, - "icon": "movie" - }, - { - "name": I18n.tr("Desktop"), - "path": desktopDir, - "icon": "computer" - } - ] - - FolderListModel { - id: folderModel - - showDirsFirst: true - showDotAndDotDot: false - showHidden: root.showHiddenFiles - caseSensitive: false - nameFilters: fileExtensions - showFiles: true - showDirs: true - folder: encodeFileUrl(currentPath || homeDir) - sortField: { - switch (sortBy) { - case "name": - return FolderListModel.Name; - case "size": - return FolderListModel.Size; - case "modified": - return FolderListModel.Time; - case "type": - return FolderListModel.Type; - default: - return FolderListModel.Name; - } - } - sortReversed: !sortAscending - } - - QtObject { - id: keyboardController - - property int totalItems: folderModel.count - property int gridColumns: viewMode === "list" ? 1 : Math.max(1, actualGridColumns) - - function handleKey(event) { - if (event.key === Qt.Key_Escape && root.closeOnEscape) { - closeRequested(); - event.accepted = true; - return; - } - if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints; - event.accepted = true; - return; - } - if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) { - showFileInfo = !showFileInfo; - event.accepted = true; - return; - } - if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) { - if (currentPath !== homeDir) { - navigateUp(); - event.accepted = true; - } - return; - } - if (!keyboardNavigationActive) { - const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right || (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier); - - if (isInitKey) { - keyboardNavigationActive = true; - if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } else { - backButtonFocused = false; - selectedIndex = 0; - } - event.accepted = true; - } - return; - } - switch (event.key) { - case Qt.Key_Tab: - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = 0; - } else if (selectedIndex < totalItems - 1) { - selectedIndex++; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } else { - selectedIndex = 0; - } - event.accepted = true; - break; - case Qt.Key_Backtab: - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = totalItems - 1; - } else if (selectedIndex > 0) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } else { - selectedIndex = totalItems - 1; - } - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = 0; - } else if (selectedIndex < totalItems - 1) { - selectedIndex++; - } - event.accepted = true; - } - break; - case Qt.Key_P: - if (event.modifiers & Qt.ControlModifier) { - if (selectedIndex > 0) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - if (selectedIndex < totalItems - 1) { - selectedIndex++; - } - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - if (selectedIndex > 0) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } - event.accepted = true; - } - break; - case Qt.Key_H: - if (event.modifiers & Qt.ControlModifier) { - if (!backButtonFocused && selectedIndex > 0) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } - event.accepted = true; - } - break; - case Qt.Key_L: - if (event.modifiers & Qt.ControlModifier) { - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = 0; - } else if (selectedIndex < totalItems - 1) { - selectedIndex++; - } - event.accepted = true; - } - break; - case Qt.Key_Left: - if (pathInputHasFocus) - return; - if (backButtonFocused) - return; - if (selectedIndex > 0) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } - event.accepted = true; - break; - case Qt.Key_Right: - if (pathInputHasFocus) - return; - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = 0; - } else if (selectedIndex < totalItems - 1) { - selectedIndex++; - } - event.accepted = true; - break; - case Qt.Key_Up: - if (backButtonFocused) { - backButtonFocused = false; - if (gridColumns === 1) { - selectedIndex = 0; - } else { - var col = selectedIndex % gridColumns; - selectedIndex = Math.min(col, totalItems - 1); - } - } else if (selectedIndex >= gridColumns) { - selectedIndex -= gridColumns; - } else if (selectedIndex > 0 && gridColumns === 1) { - selectedIndex--; - } else if (currentPath !== homeDir) { - backButtonFocused = true; - selectedIndex = -1; - } - event.accepted = true; - break; - case Qt.Key_Down: - if (backButtonFocused) { - backButtonFocused = false; - selectedIndex = 0; - } else if (gridColumns === 1) { - if (selectedIndex < totalItems - 1) { - selectedIndex++; - } - } else { - var newIndex = selectedIndex + gridColumns; - if (newIndex < totalItems) { - selectedIndex = newIndex; - } else { - var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns; - var col = selectedIndex % gridColumns; - var targetIndex = lastRowStart + col; - if (targetIndex < totalItems && targetIndex > selectedIndex) { - selectedIndex = targetIndex; - } - } - } - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - case Qt.Key_Space: - if (backButtonFocused) { - navigateUp(); - } else if (selectedIndex >= 0 && selectedIndex < totalItems) { - root.keyboardFileSelection(selectedIndex); - } - event.accepted = true; - break; - } - } - } - - Timer { - id: keyboardSelectionTimer - - property int targetIndex: -1 - - interval: 1 - onTriggered: { - executeKeyboardSelection(targetIndex); - } - } - - focus: true - - Keys.onPressed: event => { - keyboardController.handleKey(event); - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 48 - - MouseArea { - anchors.fill: parent - onPressed: if (windowControls) - windowControls.tryStartMove() - onDoubleClicked: if (windowControls) - windowControls.tryToggleMaximize() - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - - DankIcon { - name: browserIcon - size: Theme.iconSizeLarge - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: browserTitle - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - circular: false - iconName: showHiddenFiles ? "visibility_off" : "visibility" - iconSize: Theme.iconSize - 4 - iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText - onClicked: showHiddenFiles = !showHiddenFiles - } - - DankActionButton { - circular: false - iconName: viewMode === "grid" ? "view_list" : "grid_view" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: viewMode = viewMode === "grid" ? "list" : "grid" - } - - DankActionButton { - circular: false - iconName: iconSizeIndex === 0 ? "photo_size_select_small" : iconSizeIndex === 1 ? "photo_size_select_large" : iconSizeIndex === 2 ? "photo_size_select_actual" : "zoom_in" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - visible: viewMode === "grid" - onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length - } - - DankActionButton { - circular: false - iconName: "info" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.showKeyboardHints = !root.showKeyboardHints - } - - DankActionButton { - visible: windowControls?.supported ?? false - circular: false - iconName: windowControls?.targetWindow?.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: if (windowControls) - windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.closeRequested() - } - } - } - - StyledRect { - width: parent.width - height: 1 - color: Theme.outline - } - - Item { - width: parent.width - height: parent.height - 49 - - Row { - anchors.fill: parent - spacing: 0 - - Row { - width: showSidebar ? 201 : 0 - height: parent.height - spacing: 0 - visible: showSidebar - - FileBrowserSidebar { - height: parent.height - quickAccessLocations: root.quickAccessLocations - currentPath: root.currentPath - onLocationSelected: path => navigateTo(path) - } - - StyledRect { - width: 1 - height: parent.height - color: Theme.outline - } - } - - Column { - width: parent.width - (showSidebar ? 201 : 0) - height: parent.height - spacing: 0 - - FileBrowserNavigation { - width: parent.width - currentPath: root.currentPath - homeDir: root.homeDir - backButtonFocused: root.backButtonFocused - keyboardNavigationActive: root.keyboardNavigationActive - showSidebar: root.showSidebar - pathEditMode: root.pathEditMode - onNavigateUp: root.navigateUp() - onNavigateTo: path => root.navigateTo(path) - onPathInputFocusChanged: hasFocus => { - root.pathInputHasFocus = hasFocus; - if (hasFocus) { - root.pathEditMode = true; - } - } - } - - StyledRect { - width: parent.width - height: 1 - color: Theme.outline - } - - Item { - id: gridContainer - width: parent.width - height: parent.height - 41 - clip: true - - property real gridCellWidth: iconSizes[iconSizeIndex] + 24 - property real gridCellHeight: iconSizes[iconSizeIndex] + 56 - property real availableGridWidth: width - Theme.spacingM * 2 - property int gridColumns: Math.max(1, Math.floor(availableGridWidth / gridCellWidth)) - property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2) - - onGridColumnsChanged: { - root.actualGridColumns = gridColumns; - } - Component.onCompleted: { - root.actualGridColumns = gridColumns; - } - - DankGridView { - id: fileGrid - anchors.fill: parent - anchors.leftMargin: gridContainer.gridLeftMargin - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - visible: viewMode === "grid" - cellWidth: gridContainer.gridCellWidth - cellHeight: gridContainer.gridCellHeight - cacheBuffer: 260 - model: folderModel - currentIndex: selectedIndex - onCurrentIndexChanged: { - if (keyboardNavigationActive && currentIndex >= 0) - positionViewAtIndex(currentIndex, GridView.Contain); - } - - ScrollBar.vertical: DankScrollbar { - id: gridScrollbar - } - - ScrollBar.horizontal: DankScrollbar { - policy: ScrollBar.AlwaysOff - } - - delegate: FileBrowserGridDelegate { - iconSizes: root.iconSizes - iconSizeIndex: root.iconSizeIndex - selectedIndex: root.selectedIndex - keyboardNavigationActive: root.keyboardNavigationActive - onItemClicked: (index, path, name, isDir) => { - selectedIndex = index; - setSelectedFileData(path, name, isDir); - if (isDir) { - navigateTo(path); - } else { - fileSelected(path); - root.closeRequested(); - } - } - onItemSelected: (index, path, name, isDir) => { - setSelectedFileData(path, name, isDir); - } - - Connections { - function onKeyboardSelectionRequestedChanged() { - if (root.keyboardSelectionRequested && root.keyboardSelectionIndex === index) { - root.keyboardSelectionRequested = false; - selectedIndex = index; - setSelectedFileData(filePath, fileName, fileIsDir); - if (fileIsDir) { - navigateTo(filePath); - } else { - fileSelected(filePath); - root.closeRequested(); - } - } - } - - target: root - } - } - } - - DankListView { - id: fileList - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - visible: viewMode === "list" - spacing: 2 - model: folderModel - currentIndex: selectedIndex - onCurrentIndexChanged: { - if (keyboardNavigationActive && currentIndex >= 0) - positionViewAtIndex(currentIndex, ListView.Contain); - } - - ScrollBar.vertical: DankScrollbar { - id: listScrollbar - } - - delegate: FileBrowserListDelegate { - width: fileList.width - selectedIndex: root.selectedIndex - keyboardNavigationActive: root.keyboardNavigationActive - onItemClicked: (index, path, name, isDir) => { - selectedIndex = index; - setSelectedFileData(path, name, isDir); - if (isDir) { - navigateTo(path); - } else { - fileSelected(path); - root.closeRequested(); - } - } - onItemSelected: (index, path, name, isDir) => { - setSelectedFileData(path, name, isDir); - } - - Connections { - function onKeyboardSelectionRequestedChanged() { - if (root.keyboardSelectionRequested && root.keyboardSelectionIndex === index) { - root.keyboardSelectionRequested = false; - selectedIndex = index; - setSelectedFileData(filePath, fileName, fileIsDir); - if (fileIsDir) { - navigateTo(filePath); - } else { - fileSelected(filePath); - root.closeRequested(); - } - } - } - - target: root - } - } - } - } - } - } - - FileBrowserSaveRow { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - saveMode: root.saveMode - defaultFileName: root.defaultFileName - currentPath: root.currentPath - onSaveRequested: filePath => handleSaveFile(filePath) - } - - KeyboardHints { - id: keyboardHints - - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - showHints: root.showKeyboardHints - } - - FileInfo { - id: fileInfo - - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingL - width: 300 - showFileInfo: root.showFileInfo - selectedIndex: root.selectedIndex - sourceFolderModel: folderModel - currentPath: root.currentPath - currentFileName: root.selectedFileName - currentFileIsDir: root.selectedFileIsDir - currentFileExtension: { - if (root.selectedFileIsDir || !root.selectedFileName) - return ""; - - var lastDot = root.selectedFileName.lastIndexOf('.'); - return lastDot > 0 ? root.selectedFileName.substring(lastDot + 1).toLowerCase() : ""; - } - } - - FileBrowserSortMenu { - id: sortMenu - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: 120 - anchors.rightMargin: Theme.spacingL - sortBy: root.sortBy - sortAscending: root.sortAscending - onSortBySelected: value => { - root.sortBy = value; - } - onSortOrderSelected: ascending => { - root.sortAscending = ascending; - } - } - } - - FileBrowserOverwriteDialog { - anchors.fill: parent - showDialog: showOverwriteConfirmation - pendingFilePath: root.pendingFilePath - onConfirmed: filePath => { - showOverwriteConfirmation = false; - fileSelected(filePath); - pendingFilePath = ""; - Qt.callLater(() => root.closeRequested()); - } - onCancelled: { - showOverwriteConfirmation = false; - pendingFilePath = ""; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml deleted file mode 100644 index effa9bd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml +++ /dev/null @@ -1,253 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Widgets - -StyledRect { - id: delegateRoot - - required property bool fileIsDir - required property string filePath - required property string fileName - required property int index - - property bool weMode: false - property var iconSizes: [80, 120, 160, 200] - property int iconSizeIndex: 1 - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - - signal itemClicked(int index, string path, string name, bool isDir) - signal itemSelected(int index, string path, string name, bool isDir) - - function getFileExtension(fileName) { - const parts = fileName.split('.'); - if (parts.length > 1) { - return parts[parts.length - 1].toLowerCase(); - } - return ""; - } - - function determineFileType(fileName) { - const ext = getFileExtension(fileName); - - const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico", "jxl", "avif", "heif", "exr"]; - if (imageExts.includes(ext)) { - return "image"; - } - - const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]; - if (videoExts.includes(ext)) { - return "video"; - } - - const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]; - if (audioExts.includes(ext)) { - return "audio"; - } - - const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]; - if (codeExts.includes(ext)) { - return "code"; - } - - const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]; - if (docExts.includes(ext)) { - return "document"; - } - - const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]; - if (archiveExts.includes(ext)) { - return "archive"; - } - - if (!ext || fileName.indexOf('.') === -1) { - return "binary"; - } - - return "file"; - } - - function isImageFile(fileName) { - if (!fileName) { - return false; - } - return determineFileType(fileName) === "image"; - } - - function isVideoFile(fileName) { - if (!fileName) { - return false; - } - return determineFileType(fileName) === "video"; - } - - property bool isImage: isImageFile(delegateRoot.fileName) - property bool isVideo: isVideoFile(delegateRoot.fileName) - - property string _xdgCacheHome: Paths.strip(Paths.xdgCache) - property string _thumbnailSize: iconSizeIndex >= 2 ? "x-large" : "large" - property int _thumbnailPx: iconSizeIndex >= 2 ? 512 : 256 - property string videoThumbnailPath: { - if (!delegateRoot.fileIsDir && isVideo) { - const hash = Qt.md5("file://" + delegateRoot.filePath); - return _xdgCacheHome + "/thumbnails/" + _thumbnailSize + "/" + hash + ".png"; - } - return ""; - } - - property string _videoThumb: "" - - onVideoThumbnailPathChanged: { - _videoThumb = ""; - if (!videoThumbnailPath) - return; - const thumbPath = videoThumbnailPath; - const thumbDir = _xdgCacheHome + "/thumbnails/" + _thumbnailSize; - const size = _thumbnailPx; - const fp = delegateRoot.filePath; - Paths.mkdir(thumbDir); - Proc.runCommand(null, ["test", "-f", thumbPath], function(output, exitCode) { - if (exitCode === 0) { - _videoThumb = thumbPath; - } else { - Proc.runCommand(null, ["ffmpegthumbnailer", "-i", fp, "-o", thumbPath, "-s", String(size), "-f"], function(output, exitCode) { - if (exitCode === 0) - _videoThumb = thumbPath; - }); - } - }); - } - - function getIconForFile(fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("dockerfile")) { - return "docker"; - } - const ext = fileName.split('.').pop(); - return ext || ""; - } - - width: weMode ? 245 : iconSizes[iconSizeIndex] + 16 - height: weMode ? 205 : iconSizes[iconSizeIndex] + 48 - radius: Theme.cornerRadius - color: { - if (keyboardNavigationActive && delegateRoot.index === selectedIndex) - return Theme.surfacePressed; - - return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"; - } - border.color: keyboardNavigationActive && delegateRoot.index === selectedIndex ? Theme.primary : "transparent" - border.width: (keyboardNavigationActive && delegateRoot.index === selectedIndex) ? 2 : 0 - - Component.onCompleted: { - if (keyboardNavigationActive && delegateRoot.index === selectedIndex) - itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); - } - - onSelectedIndexChanged: { - if (keyboardNavigationActive && selectedIndex === delegateRoot.index) - itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - Item { - width: weMode ? 225 : (iconSizes[iconSizeIndex] - 8) - height: weMode ? 165 : (iconSizes[iconSizeIndex] - 8) - anchors.horizontalCenter: parent.horizontalCenter - - Image { - id: gridPreviewImage - anchors.fill: parent - anchors.margins: 2 - property var weExtensions: [".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tga", ".jxl", ".avif", ".heif", ".exr"] - property int weExtIndex: 0 - property string imagePath: { - if (weMode && delegateRoot.fileIsDir) - return delegateRoot.filePath + "/preview" + weExtensions[weExtIndex]; - if (!delegateRoot.fileIsDir && isImage) - return delegateRoot.filePath; - if (_videoThumb) - return _videoThumb; - return ""; - } - source: imagePath ? "file://" + imagePath.split('/').map(s => encodeURIComponent(s)).join('/') : "" - onStatusChanged: { - if (weMode && delegateRoot.fileIsDir && status === Image.Error) { - if (weExtIndex < weExtensions.length - 1) { - weExtIndex++; - } else { - imagePath = ""; - } - } - } - fillMode: Image.PreserveAspectCrop - sourceSize.width: weMode ? 225 : iconSizes[iconSizeIndex] - sourceSize.height: weMode ? 225 : iconSizes[iconSizeIndex] - asynchronous: true - visible: false - } - - MultiEffect { - anchors.fill: parent - anchors.margins: 2 - source: gridPreviewImage - maskEnabled: true - maskSource: gridImageMask - visible: gridPreviewImage.status === Image.Ready && ((!delegateRoot.fileIsDir && (isImage || isVideo)) || (weMode && delegateRoot.fileIsDir)) - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - - Item { - id: gridImageMask - anchors.fill: parent - anchors.margins: 2 - layer.enabled: true - layer.smooth: true - visible: false - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: "black" - antialiasing: true - } - } - - DankNFIcon { - anchors.centerIn: parent - name: delegateRoot.fileIsDir ? "folder" : getIconForFile(delegateRoot.fileName) - size: iconSizes[iconSizeIndex] * 0.45 - color: delegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText - visible: (!delegateRoot.fileIsDir && !isImage && !(isVideo && gridPreviewImage.status === Image.Ready)) || (delegateRoot.fileIsDir && !weMode) - } - } - - StyledText { - text: delegateRoot.fileName || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: delegateRoot.width - Theme.spacingM - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - maximumLineCount: 2 - wrapMode: Text.Wrap - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - itemClicked(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserListDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserListDelegate.qml deleted file mode 100644 index 2f452b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserListDelegate.qml +++ /dev/null @@ -1,258 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Widgets - -StyledRect { - id: listDelegateRoot - - required property bool fileIsDir - required property string filePath - required property string fileName - required property int index - required property var fileModified - required property int fileSize - - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - - signal itemClicked(int index, string path, string name, bool isDir) - signal itemSelected(int index, string path, string name, bool isDir) - - function getFileExtension(fileName) { - const parts = fileName.split('.'); - if (parts.length > 1) { - return parts[parts.length - 1].toLowerCase(); - } - return ""; - } - - function determineFileType(fileName) { - const ext = getFileExtension(fileName); - - const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico", "jxl", "avif", "heif", "exr"]; - if (imageExts.includes(ext)) { - return "image"; - } - - const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]; - if (videoExts.includes(ext)) { - return "video"; - } - - const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]; - if (audioExts.includes(ext)) { - return "audio"; - } - - const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]; - if (codeExts.includes(ext)) { - return "code"; - } - - const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]; - if (docExts.includes(ext)) { - return "document"; - } - - const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]; - if (archiveExts.includes(ext)) { - return "archive"; - } - - if (!ext || fileName.indexOf('.') === -1) { - return "binary"; - } - - return "file"; - } - - function isImageFile(fileName) { - if (!fileName) { - return false; - } - return determineFileType(fileName) === "image"; - } - - function isVideoFile(fileName) { - if (!fileName) { - return false; - } - return determineFileType(fileName) === "video"; - } - - property bool isImage: isImageFile(listDelegateRoot.fileName) - property bool isVideo: isVideoFile(listDelegateRoot.fileName) - - property string _xdgCacheHome: Paths.strip(Paths.xdgCache) - property string videoThumbnailPath: { - if (!listDelegateRoot.fileIsDir && isVideo) { - const hash = Qt.md5("file://" + listDelegateRoot.filePath); - return _xdgCacheHome + "/thumbnails/normal/" + hash + ".png"; - } - return ""; - } - - property string _videoThumb: "" - - onVideoThumbnailPathChanged: { - _videoThumb = ""; - if (!videoThumbnailPath) - return; - const thumbPath = videoThumbnailPath; - const fp = listDelegateRoot.filePath; - Paths.mkdir(_xdgCacheHome + "/thumbnails/normal"); - Proc.runCommand(null, ["test", "-f", thumbPath], function(output, exitCode) { - if (exitCode === 0) { - _videoThumb = thumbPath; - } else { - Proc.runCommand(null, ["ffmpegthumbnailer", "-i", fp, "-o", thumbPath, "-s", "128", "-f"], function(output, exitCode) { - if (exitCode === 0) - _videoThumb = thumbPath; - }); - } - }); - } - - function getIconForFile(fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("dockerfile")) { - return "docker"; - } - const ext = fileName.split('.').pop(); - return ext || ""; - } - - function formatFileSize(size) { - if (size < 1024) - return size + " B"; - if (size < 1024 * 1024) - return (size / 1024).toFixed(1) + " KB"; - if (size < 1024 * 1024 * 1024) - return (size / (1024 * 1024)).toFixed(1) + " MB"; - return (size / (1024 * 1024 * 1024)).toFixed(1) + " GB"; - } - - height: 44 - radius: Theme.cornerRadius - color: { - if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex) - return Theme.surfacePressed; - return listMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"; - } - border.color: keyboardNavigationActive && listDelegateRoot.index === selectedIndex ? Theme.primary : "transparent" - border.width: (keyboardNavigationActive && listDelegateRoot.index === selectedIndex) ? 2 : 0 - - Component.onCompleted: { - if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex) - itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir); - } - - onSelectedIndexChanged: { - if (keyboardNavigationActive && selectedIndex === listDelegateRoot.index) - itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir); - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - Item { - width: 28 - height: 28 - anchors.verticalCenter: parent.verticalCenter - - Image { - id: listPreviewImage - anchors.fill: parent - property string imagePath: { - if (!listDelegateRoot.fileIsDir && isImage) - return listDelegateRoot.filePath; - if (_videoThumb) - return _videoThumb; - return ""; - } - source: imagePath ? "file://" + imagePath.split('/').map(s => encodeURIComponent(s)).join('/') : "" - fillMode: Image.PreserveAspectCrop - sourceSize.width: 32 - sourceSize.height: 32 - asynchronous: true - visible: false - } - - MultiEffect { - anchors.fill: parent - source: listPreviewImage - maskEnabled: true - maskSource: listImageMask - visible: listPreviewImage.status === Image.Ready && !listDelegateRoot.fileIsDir && (isImage || isVideo) - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - - Item { - id: listImageMask - anchors.fill: parent - layer.enabled: true - layer.smooth: true - visible: false - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: "black" - antialiasing: true - } - } - - DankNFIcon { - anchors.centerIn: parent - name: listDelegateRoot.fileIsDir ? "folder" : getIconForFile(listDelegateRoot.fileName) - size: Theme.iconSize - 2 - color: listDelegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText - visible: listDelegateRoot.fileIsDir || (!isImage && !(isVideo && listPreviewImage.status === Image.Ready)) - } - } - - StyledText { - text: listDelegateRoot.fileName || "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - 280 - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - maximumLineCount: 1 - clip: true - } - - StyledText { - text: listDelegateRoot.fileIsDir ? "" : formatFileSize(listDelegateRoot.fileSize) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: 70 - horizontalAlignment: Text.AlignRight - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: Qt.formatDateTime(listDelegateRoot.fileModified, "MMM d, yyyy h:mm AP") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: 140 - horizontalAlignment: Text.AlignRight - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: listMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - itemClicked(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserModal.qml deleted file mode 100644 index c7686ca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserModal.qml +++ /dev/null @@ -1,97 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -FloatingWindow { - id: fileBrowserModal - - property bool disablePopupTransparency: true - property string browserTitle: "Select File" - property string browserIcon: "folder_open" - property string browserType: "generic" - property var fileExtensions: ["*.*"] - property alias filterExtensions: fileBrowserModal.fileExtensions - property bool showHiddenFiles: false - property bool saveMode: false - property string defaultFileName: "" - property var parentModal: null - property bool shouldHaveFocus: visible - property bool allowFocusOverride: false - property bool shouldBeVisible: visible - property bool allowStacking: true - - signal fileSelected(string path) - signal dialogClosed - - function open() { - visible = true; - } - - function close() { - visible = false; - } - - objectName: "fileBrowserModal" - title: "Files - " + browserTitle - minimumSize: Qt.size(500, 400) - implicitWidth: 800 - implicitHeight: 600 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - if (parentModal && "shouldHaveFocus" in parentModal) { - parentModal.shouldHaveFocus = false; - parentModal.allowFocusOverride = true; - } - Qt.callLater(() => { - if (content) { - content.reset(); - content.forceActiveFocus(); - } - }); - } else { - if (parentModal && "allowFocusOverride" in parentModal) { - parentModal.allowFocusOverride = false; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - } - dialogClosed(); - } - } - - Loader { - id: contentLoader - anchors.fill: parent - active: fileBrowserModal.visible - sourceComponent: FileBrowserContent { - id: content - anchors.fill: parent - focus: true - closeOnEscape: false - windowControls: fileBrowserModal.windowControlsRef - - browserTitle: fileBrowserModal.browserTitle - browserIcon: fileBrowserModal.browserIcon - browserType: fileBrowserModal.browserType - fileExtensions: fileBrowserModal.fileExtensions - showHiddenFiles: fileBrowserModal.showHiddenFiles - saveMode: fileBrowserModal.saveMode - defaultFileName: fileBrowserModal.defaultFileName - - Component.onCompleted: initialize() - - onFileSelected: path => fileBrowserModal.fileSelected(path) - onCloseRequested: fileBrowserModal.close() - } - } - - property alias content: contentLoader.item - property alias windowControlsRef: windowControls - - FloatingWindowControls { - id: windowControls - targetWindow: fileBrowserModal - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserNavigation.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserNavigation.qml deleted file mode 100644 index 61ce7b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserNavigation.qml +++ /dev/null @@ -1,130 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Row { - id: navigation - - property string currentPath: "" - property string homeDir: "" - property bool backButtonFocused: false - property bool keyboardNavigationActive: false - property bool showSidebar: true - property bool pathEditMode: false - property bool pathInputHasFocus: false - - signal navigateUp() - signal navigateTo(string path) - signal pathInputFocusChanged(bool hasFocus) - - height: 40 - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - spacing: Theme.spacingS - - StyledRect { - width: 32 - height: 32 - radius: Theme.cornerRadius - color: (backButtonMouseArea.containsMouse || (backButtonFocused && keyboardNavigationActive)) && currentPath !== homeDir ? Theme.surfaceVariant : "transparent" - opacity: currentPath !== homeDir ? 1 : 0 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "arrow_back" - size: Theme.iconSizeSmall - color: Theme.surfaceText - } - - MouseArea { - id: backButtonMouseArea - - anchors.fill: parent - hoverEnabled: currentPath !== homeDir - cursorShape: currentPath !== homeDir ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: currentPath !== homeDir - onClicked: navigation.navigateUp() - } - } - - Item { - width: Math.max(0, (parent?.width ?? 0) - 40 - Theme.spacingS - (showSidebar ? 0 : 80)) - height: 32 - anchors.verticalCenter: parent.verticalCenter - - StyledRect { - anchors.fill: parent - radius: Theme.cornerRadius - color: pathEditMode ? Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) : "transparent" - border.color: pathEditMode ? Theme.primary : "transparent" - border.width: pathEditMode ? 1 : 0 - visible: !pathEditMode - - StyledText { - id: pathDisplay - text: currentPath.replace("file://", "") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - elide: Text.ElideMiddle - verticalAlignment: Text.AlignVCenter - maximumLineCount: 1 - wrapMode: Text.NoWrap - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.IBeamCursor - onClicked: { - pathEditMode = true - pathInput.text = currentPath.replace("file://", "") - Qt.callLater(() => pathInput.forceActiveFocus()) - } - } - } - - DankTextField { - id: pathInput - anchors.fill: parent - visible: pathEditMode - topPadding: Theme.spacingXS - bottomPadding: Theme.spacingXS - onAccepted: { - const newPath = text.trim() - if (newPath !== "") { - navigation.navigateTo(newPath) - } - pathEditMode = false - } - Keys.onEscapePressed: { - pathEditMode = false - } - Keys.onDownPressed: { - pathEditMode = false - } - onActiveFocusChanged: { - navigation.pathInputFocusChanged(activeFocus) - if (!activeFocus && pathEditMode) { - pathEditMode = false - } - } - } - } - - Row { - spacing: Theme.spacingXS - visible: !showSidebar - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - circular: false - iconName: "sort" - iconSize: Theme.iconSize - 6 - iconColor: Theme.surfaceText - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserOverwriteDialog.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserOverwriteDialog.qml deleted file mode 100644 index a664be5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserOverwriteDialog.qml +++ /dev/null @@ -1,127 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: overwriteDialog - - property bool showDialog: false - property string pendingFilePath: "" - - signal confirmed(string filePath) - signal cancelled() - - visible: showDialog - focus: showDialog - - Keys.onEscapePressed: { - cancelled() - } - - Keys.onReturnPressed: { - confirmed(pendingFilePath) - } - - Rectangle { - anchors.fill: parent - color: Theme.shadowStrong - opacity: 0.8 - - MouseArea { - anchors.fill: parent - onClicked: { - cancelled() - } - } - } - - StyledRect { - anchors.centerIn: parent - width: 400 - height: 160 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Theme.outlineMedium - border.width: 1 - - Column { - anchors.centerIn: parent - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("File Already Exists") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("A file with this name already exists. Do you want to overwrite it?") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - StyledRect { - width: 80 - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceVariantHover : Theme.surfaceVariant - border.color: Theme.outline - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - cancelled() - } - } - } - - StyledRect { - width: 90 - height: 36 - radius: Theme.cornerRadius - color: overwriteArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Overwrite") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: overwriteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - confirmed(pendingFilePath) - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSaveRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSaveRow.qml deleted file mode 100644 index 6360c7f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSaveRow.qml +++ /dev/null @@ -1,74 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Row { - id: saveRow - - property bool saveMode: false - property string defaultFileName: "" - property string currentPath: "" - - signal saveRequested(string filePath) - - height: saveMode ? 40 : 0 - visible: saveMode - spacing: Theme.spacingM - - DankTextField { - id: fileNameInput - - width: parent.width - saveButton.width - Theme.spacingM - height: 40 - text: defaultFileName - placeholderText: I18n.tr("Enter filename...") - ignoreLeftRightKeys: false - focus: saveMode - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - Component.onCompleted: { - if (saveMode) - Qt.callLater(() => { - forceActiveFocus() - }) - } - onAccepted: { - if (text.trim() !== "") { - var basePath = currentPath.replace(/^file:\/\//, '') - var fullPath = basePath + "/" + text.trim() - fullPath = fullPath.replace(/\/+/g, '/') - saveRequested(fullPath) - } - } - } - - StyledRect { - id: saveButton - - width: 80 - height: 40 - color: fileNameInput.text.trim() !== "" ? Theme.primary : Theme.surfaceVariant - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Save") - color: fileNameInput.text.trim() !== "" ? Theme.primaryText : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeMedium - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: Theme.cornerRadius - enabled: fileNameInput.text.trim() !== "" - onClicked: { - if (fileNameInput.text.trim() !== "") { - var basePath = currentPath.replace(/^file:\/\//, '') - var fullPath = basePath + "/" + fileNameInput.text.trim() - fullPath = fullPath.replace(/\/+/g, '/') - saveRequested(fullPath) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSidebar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSidebar.qml deleted file mode 100644 index bc02b3e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSidebar.qml +++ /dev/null @@ -1,70 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: sidebar - - property var quickAccessLocations: [] - property string currentPath: "" - signal locationSelected(string path) - - width: 200 - color: Theme.surface - clip: true - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 4 - - StyledText { - text: I18n.tr("Quick Access") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - leftPadding: Theme.spacingS - bottomPadding: Theme.spacingXS - } - - Repeater { - model: quickAccessLocations - - StyledRect { - width: parent?.width ?? 0 - height: 38 - radius: Theme.cornerRadius - color: quickAccessMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : (currentPath === modelData?.path ? Theme.surfacePressed : "transparent") - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: modelData?.icon ?? "" - size: Theme.iconSize - 2 - color: currentPath === modelData?.path ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData?.name ?? "" - font.pixelSize: Theme.fontSizeMedium - color: currentPath === modelData?.path ? Theme.primary : Theme.surfaceText - font.weight: currentPath === modelData?.path ? Font.Medium : Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: quickAccessMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: locationSelected(modelData?.path ?? "") - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSortMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSortMenu.qml deleted file mode 100644 index e1886f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSortMenu.qml +++ /dev/null @@ -1,183 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: sortMenu - - property string sortBy: "name" - property bool sortAscending: true - - signal sortBySelected(string value) - signal sortOrderSelected(bool ascending) - - width: 200 - height: sortColumn.height + Theme.spacingM * 2 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Theme.outlineMedium - border.width: 1 - visible: false - z: 100 - - Column { - id: sortColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: "Sort By" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Repeater { - model: [{ - "name": "Name", - "value": "name" - }, { - "name": "Size", - "value": "size" - }, { - "name": "Modified", - "value": "modified" - }, { - "name": "Type", - "value": "type" - }] - - StyledRect { - width: sortColumn?.width ?? 0 - height: 32 - radius: Theme.cornerRadius - color: sortMouseArea.containsMouse ? Theme.surfaceVariant : (sortBy === modelData?.value ? Theme.surfacePressed : "transparent") - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: sortBy === modelData?.value ? "check" : "" - size: Theme.iconSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: sortBy === modelData?.value - } - - StyledText { - text: modelData?.name ?? "" - font.pixelSize: Theme.fontSizeMedium - color: sortBy === modelData?.value ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: sortMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - sortMenu.sortBySelected(modelData?.value ?? "name") - sortMenu.visible = false - } - } - } - } - - StyledRect { - width: sortColumn.width - height: 1 - color: Theme.outline - } - - StyledText { - text: "Order" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - topPadding: Theme.spacingXS - } - - StyledRect { - width: sortColumn?.width ?? 0 - height: 32 - radius: Theme.cornerRadius - color: ascMouseArea.containsMouse ? Theme.surfaceVariant : (sortAscending ? Theme.surfacePressed : "transparent") - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "arrow_upward" - size: Theme.iconSizeSmall - color: sortAscending ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "Ascending" - font.pixelSize: Theme.fontSizeMedium - color: sortAscending ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: ascMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - sortMenu.sortOrderSelected(true) - sortMenu.visible = false - } - } - } - - StyledRect { - width: sortColumn?.width ?? 0 - height: 32 - radius: Theme.cornerRadius - color: descMouseArea.containsMouse ? Theme.surfaceVariant : (!sortAscending ? Theme.surfacePressed : "transparent") - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "arrow_downward" - size: Theme.iconSizeSmall - color: !sortAscending ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "Descending" - font.pixelSize: Theme.fontSizeMedium - color: !sortAscending ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: descMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - sortMenu.sortOrderSelected(false) - sortMenu.visible = false - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSurfaceModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSurfaceModal.qml deleted file mode 100644 index 25b8d5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserSurfaceModal.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick -import Quickshell.Wayland -import qs.Common -import qs.Modals.Common - -DankModal { - id: fileBrowserSurfaceModal - - property string browserTitle: "Select File" - property string browserIcon: "folder_open" - property string browserType: "generic" - property var fileExtensions: ["*.*"] - property alias filterExtensions: fileBrowserSurfaceModal.fileExtensions - property bool showHiddenFiles: false - property bool saveMode: false - property string defaultFileName: "" - property var parentPopout: null - - signal fileSelected(string path) - - layerNamespace: "dms:filebrowser" - modalWidth: 800 - modalHeight: 600 - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - closeOnEscapeKey: true - closeOnBackgroundClick: true - allowStacking: true - keepPopoutsOpen: true - - onBackgroundClicked: close() - - onOpened: { - if (parentPopout) { - parentPopout.customKeyboardFocus = WlrKeyboardFocus.None; - } - Qt.callLater(() => { - if (contentLoader.item) { - contentLoader.item.reset(); - contentLoader.item.forceActiveFocus(); - } - }); - } - - onDialogClosed: { - if (parentPopout) { - parentPopout.customKeyboardFocus = null; - } - } - - content: FileBrowserContent { - focus: true - - browserTitle: fileBrowserSurfaceModal.browserTitle - browserIcon: fileBrowserSurfaceModal.browserIcon - browserType: fileBrowserSurfaceModal.browserType - fileExtensions: fileBrowserSurfaceModal.fileExtensions - showHiddenFiles: fileBrowserSurfaceModal.showHiddenFiles - saveMode: fileBrowserSurfaceModal.saveMode - defaultFileName: fileBrowserSurfaceModal.defaultFileName - - Component.onCompleted: initialize() - - onFileSelected: path => fileBrowserSurfaceModal.fileSelected(path) - onCloseRequested: fileBrowserSurfaceModal.close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileInfo.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileInfo.qml deleted file mode 100644 index c41f039..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileInfo.qml +++ /dev/null @@ -1,237 +0,0 @@ -import QtQuick -import QtCore -import Quickshell.Io -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool showFileInfo: false - property int selectedIndex: -1 - property var sourceFolderModel: null - property string currentPath: "" - - height: 200 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Theme.secondary - border.width: 2 - opacity: showFileInfo ? 1 : 0 - z: 100 - - onShowFileInfoChanged: { - if (showFileInfo && currentFileName && currentPath) { - const fullPath = currentPath + "/" + currentFileName - fileStatProcess.selectedFilePath = fullPath - fileStatProcess.running = true - } - } - - Process { - id: fileStatProcess - command: ["stat", "-c", "%y|%A|%s|%n", selectedFilePath] - property string selectedFilePath: "" - property var fileStats: null - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (text && text.trim()) { - const parts = text.trim().split('|') - if (parts.length >= 4) { - fileStatProcess.fileStats = { - "modifiedTime": parts[0], - "permissions": parts[1], - "size": parseInt(parts[2]) || 0, - "fullPath": parts[3] - } - } - } - } - } - - onExited: function (exitCode) {} - } - - property string currentFileName: "" - property bool currentFileIsDir: false - property string currentFileExtension: "" - - onCurrentFileNameChanged: { - if (showFileInfo && currentFileName && currentPath) { - const fullPath = currentPath + "/" + currentFileName - if (fullPath !== fileStatProcess.selectedFilePath) { - fileStatProcess.selectedFilePath = fullPath - fileStatProcess.running = true - } - } - } - - function updateFileInfo(filePath, fileName, isDirectory) { - if (filePath && filePath !== fileStatProcess.selectedFilePath) { - fileStatProcess.selectedFilePath = filePath - currentFileName = fileName || "" - currentFileIsDir = isDirectory || false - - let ext = "" - if (!isDirectory && fileName) { - const lastDot = fileName.lastIndexOf('.') - if (lastDot > 0) { - ext = fileName.substring(lastDot + 1).toLowerCase() - } - } - currentFileExtension = ext - - if (showFileInfo) { - fileStatProcess.running = true - } - } - } - - readonly property var currentFileDisplayData: { - if (selectedIndex < 0 || !sourceFolderModel) { - return { - "exists": false, - "name": "No selection", - "type": "", - "size": "", - "modified": "", - "permissions": "", - "extension": "", - "position": "N/A" - } - } - - const hasValidFile = currentFileName !== "" - return { - "exists": hasValidFile, - "name": hasValidFile ? currentFileName : "Loading...", - "type": currentFileIsDir ? "Directory" : "File", - "size": fileStatProcess.fileStats ? formatFileSize(fileStatProcess.fileStats.size) : "Calculating...", - "modified": fileStatProcess.fileStats ? formatDateTime(fileStatProcess.fileStats.modifiedTime) : "Loading...", - "permissions": fileStatProcess.fileStats ? fileStatProcess.fileStats.permissions : "Loading...", - "extension": currentFileExtension, - "position": sourceFolderModel ? ((selectedIndex + 1) + " of " + sourceFolderModel.count) : "N/A" - } - } - - Column { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "info" - size: Theme.iconSize - color: Theme.secondary - } - - StyledText { - text: I18n.tr("File Information") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: currentFileDisplayData.name - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideMiddle - wrapMode: Text.NoWrap - font.weight: Font.Medium - } - - StyledText { - text: currentFileDisplayData.type + (currentFileDisplayData.extension ? " (." + currentFileDisplayData.extension + ")" : "") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: parent.width - } - - StyledText { - text: currentFileDisplayData.size - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: parent.width - visible: currentFileDisplayData.exists && !currentFileIsDir - } - - StyledText { - text: currentFileDisplayData.modified - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: parent.width - elide: Text.ElideRight - visible: currentFileDisplayData.exists - } - - StyledText { - text: currentFileDisplayData.permissions - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - visible: currentFileDisplayData.exists - } - - StyledText { - text: currentFileDisplayData.position - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: parent.width - } - } - } - - StyledText { - text: I18n.tr("F1/I: Toggle • F10: Help") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - horizontalAlignment: Text.AlignHCenter - } - - function formatFileSize(bytes) { - if (bytes === 0 || !bytes) { - return "0 B" - } - const k = 1024 - const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] - const i = Math.floor(Math.log(bytes) / Math.log(k)) - return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i] - } - - function formatDateTime(dateTimeString) { - if (!dateTimeString) { - return "Unknown" - } - const parts = dateTimeString.split(' ') - if (parts.length >= 2) { - return parts[0] + " " + parts[1].split('.')[0] - } - return dateTimeString - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/KeyboardHints.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/KeyboardHints.qml deleted file mode 100644 index 1910810..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/KeyboardHints.qml +++ /dev/null @@ -1,50 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool showHints: false - - height: 80 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Theme.primary - border.width: 2 - opacity: showHints ? 1 : 0 - z: 100 - - Column { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingS - spacing: 2 - - StyledText { - text: I18n.tr("Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterCompletePage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterCompletePage.qml deleted file mode 100644 index 8a5ca00..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterCompletePage.qml +++ /dev/null @@ -1,492 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property var greeterRoot: parent ? parent.greeterRoot : null - - readonly property real headerIconContainerSize: Math.round(Theme.iconSize * 2) - readonly property real sectionIconSize: Theme.iconSizeSmall + 2 - readonly property real keybindRowHeight: Math.round(Theme.fontSizeMedium * 2) - readonly property real keyBadgeHeight: Math.round(Theme.fontSizeSmall * 1.83) - - readonly property var featureNames: ({ - "spotlight": "App Launcher", - "clipboard": "Clipboard", - "processlist": "Task Manager", - "settings": "Settings", - "notifications": "Notifications", - "notepad": "Notepad", - "hotkeys": "Keybinds", - "lock": "Lock Screen", - "dankdash": "Dashboard" - }) - - function getFeatureDesc(action) { - const match = action.match(/dms\s+ipc\s+call\s+(\w+)/); - if (match && featureNames[match[1]]) - return featureNames[match[1]]; - return null; - } - - readonly property var dmsKeybinds: { - if (!greeterRoot || !greeterRoot.cheatsheetLoaded || !greeterRoot.cheatsheetData || !greeterRoot.cheatsheetData.binds) - return []; - const seen = new Set(); - const binds = []; - const allBinds = greeterRoot.cheatsheetData.binds; - for (const category in allBinds) { - const categoryBinds = allBinds[category]; - for (let i = 0; i < categoryBinds.length; i++) { - const bind = categoryBinds[i]; - if (!bind.key || !bind.action) - continue; - if (!bind.action.includes("dms")) - continue; - if (!(bind.action.includes("spawn") || bind.action.includes("exec"))) - continue; - const feature = getFeatureDesc(bind.action); - if (!feature) - continue; - if (seen.has(feature)) - continue; - seen.add(feature); - binds.push({ - key: bind.key, - desc: feature - }); - } - } - return binds; - } - - readonly property bool hasKeybinds: dmsKeybinds.length > 0 - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingL * 2 - contentWidth: width - - Column { - id: mainColumn - anchors.horizontalCenter: parent.horizontalCenter - width: Math.min(640, parent.width - Theme.spacingXL * 2) - topPadding: Theme.spacingL - spacing: Theme.spacingL - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Rectangle { - width: root.headerIconContainerSize - height: root.headerIconContainerSize - radius: Math.round(root.headerIconContainerSize * 0.29) - color: Theme.withAlpha(Theme.success, 0.15) - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "check_circle" - size: Theme.iconSize + 4 - color: Theme.success - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: I18n.tr("You're All Set!", "greeter completion page title") - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("DankMaterialShell is ready to use", "greeter completion page subtitle") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: root.hasKeybinds - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "keyboard" - size: root.sectionIconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("DMS Shortcuts", "greeter keybinds section header") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - id: keybindsRect - width: parent.width - height: keybindsGrid.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - readonly property bool useTwoColumns: width > 500 - readonly property int columnCount: useTwoColumns ? 2 : 1 - readonly property real itemWidth: useTwoColumns ? (width - Theme.spacingM * 3) / 2 : width - Theme.spacingM * 2 - property real maxKeyWidth: 0 - - Grid { - id: keybindsGrid - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - columns: keybindsRect.columnCount - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingM - - Repeater { - model: root.dmsKeybinds - - Row { - width: keybindsRect.itemWidth - height: root.keybindRowHeight - spacing: Theme.spacingS - - Item { - width: keybindsRect.maxKeyWidth - height: parent.height - - Row { - id: keysRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - property real naturalWidth: { - let w = 0; - for (let i = 0; i < children.length; i++) { - if (children[i].visible) - w += children[i].width + (i > 0 ? Theme.spacingXS : 0); - } - return w; - } - - Component.onCompleted: { - Qt.callLater(() => { - if (naturalWidth > keybindsRect.maxKeyWidth) - keybindsRect.maxKeyWidth = naturalWidth; - }); - } - - Repeater { - model: (modelData.key || "").split("+") - - Rectangle { - width: singleKeyText.implicitWidth + Theme.spacingM - height: root.keyBadgeHeight - radius: Theme.spacingXS - color: Theme.surfaceContainerHighest - border.width: 1 - border.color: Theme.outline - - StyledText { - id: singleKeyText - anchors.centerIn: parent - color: Theme.secondary - text: modelData - font.pixelSize: Theme.fontSizeSmall - 1 - font.weight: Font.Medium - isMonospace: true - } - } - } - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - keybindsRect.maxKeyWidth - Theme.spacingS - text: modelData.desc || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - elide: Text.ElideRight - } - } - } - } - } - } - - Rectangle { - width: parent.width - height: noKeybindsColumn.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: !root.hasKeybinds - - Column { - id: noKeybindsColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "keyboard" - size: root.sectionIconSize - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("No DMS shortcuts configured", "greeter no keybinds message") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: parent.width - height: Math.round(Theme.fontSizeMedium * 2.85) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Theme.primary - opacity: noKeybindsLinkMouse.containsMouse ? 0.12 : 0 - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "menu_book" - size: root.sectionIconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Configure Keybinds", "greeter configure keybinds link") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "open_in_new" - size: Theme.iconSizeSmall - 2 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: noKeybindsLinkMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let url = "https://danklinux.com/docs/dankmaterialshell/keybinds-ipc"; - if (CompositorService.isNiri) - url = "https://danklinux.com/docs/dankmaterialshell/compositors#dms-keybindings"; - else if (CompositorService.isHyprland) - url = "https://danklinux.com/docs/dankmaterialshell/compositors#dms-keybindings-1"; - else if (CompositorService.isDwl) - url = "https://danklinux.com/docs/dankmaterialshell/compositors#dms-keybindings-2"; - Qt.openUrlExternally(url); - } - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.3 - visible: root.hasKeybinds - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "settings" - size: root.sectionIconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Configure", "greeter settings section header") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Grid { - width: parent.width - columns: 2 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "display_settings" - title: I18n.tr("Displays", "greeter settings link") - description: I18n.tr("Resolution, position, scale", "greeter displays description") - onClicked: PopoutService.openSettingsWithTab("display_config") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "wallpaper" - title: I18n.tr("Wallpaper", "greeter settings link") - description: I18n.tr("Background image", "greeter wallpaper description") - onClicked: PopoutService.openSettingsWithTab("wallpaper") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "format_paint" - title: I18n.tr("Theme & Colors", "greeter settings link") - description: I18n.tr("Dynamic colors, presets", "greeter theme description") - onClicked: PopoutService.openSettingsWithTab("theme") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "notifications" - title: I18n.tr("Notifications", "greeter settings link") - description: I18n.tr("Popup behavior, position", "greeter notifications description") - onClicked: PopoutService.openSettingsWithTab("notifications") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "toolbar" - title: I18n.tr("DankBar", "greeter settings link") - description: I18n.tr("Widgets, layout, style", "greeter dankbar description") - onClicked: PopoutService.openSettingsWithTab("dankbar_settings") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "keyboard" - title: I18n.tr("Keybinds", "greeter settings link") - description: I18n.tr("niri shortcuts config", "greeter keybinds niri description") - visible: KeybindsService.available - onClicked: PopoutService.openSettingsWithTab("keybinds") - } - - GreeterSettingsCard { - width: (parent.width - Theme.spacingS) / 2 - iconName: "dock_to_bottom" - title: I18n.tr("Dock", "greeter settings link") - description: I18n.tr("Position, pinned apps", "greeter dock description") - visible: !KeybindsService.available - onClicked: PopoutService.openSettingsWithTab("dock") - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.3 - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "explore" - size: root.sectionIconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Explore", "greeter explore section header") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - GreeterQuickLink { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "menu_book" - title: I18n.tr("Docs", "greeter documentation link") - isExternal: true - onClicked: Qt.openUrlExternally("https://danklinux.com/docs") - } - - GreeterQuickLink { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "extension" - title: I18n.tr("Plugins", "greeter plugins link") - isExternal: true - onClicked: Qt.openUrlExternally("https://danklinux.com/plugins") - } - - GreeterQuickLink { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "palette" - title: I18n.tr("Themes", "greeter themes link") - isExternal: true - onClicked: Qt.openUrlExternally("https://danklinux.com/plugins?tab=themes") - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorPage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorPage.qml deleted file mode 100644 index 288cd58..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorPage.qml +++ /dev/null @@ -1,427 +0,0 @@ -import QtQuick -import Quickshell.Io -import qs.Common -import qs.Widgets - -Item { - id: root - - property bool isRunning: false - property bool hasRun: false - property var doctorResults: null - property int errorCount: 0 - property int warningCount: 0 - property int okCount: 0 - property int infoCount: 0 - property string selectedFilter: "error" - - readonly property real loadingContainerSize: Math.round(Theme.iconSize * 5) - readonly property real pulseRingSize: Math.round(Theme.iconSize * 3.3) - readonly property real centerIconContainerSize: Math.round(Theme.iconSize * 2.67) - readonly property real headerIconContainerSize: Math.round(Theme.iconSize * 2) - - readonly property var filteredResults: { - if (!doctorResults?.results) - return []; - return doctorResults.results.filter(r => r.status === selectedFilter); - } - - function runDoctor() { - hasRun = false; - isRunning = true; - doctorProcess.running = true; - } - - Component.onCompleted: runDoctor() - - Item { - id: loadingView - anchors.fill: parent - visible: root.isRunning - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXL - - Item { - width: root.loadingContainerSize - height: root.loadingContainerSize - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - id: pulseRing1 - anchors.centerIn: parent - width: root.pulseRingSize - height: root.pulseRingSize - radius: root.pulseRingSize / 2 - color: "transparent" - border.width: Math.round(Theme.spacingXS * 0.75) - border.color: Theme.primary - opacity: 0 - - SequentialAnimation on opacity { - running: root.isRunning - loops: Animation.Infinite - NumberAnimation { - from: 0.8 - to: 0 - duration: 1500 - easing.type: Easing.OutQuad - } - } - - SequentialAnimation on scale { - running: root.isRunning - loops: Animation.Infinite - NumberAnimation { - from: 0.5 - to: 1.5 - duration: 1500 - easing.type: Easing.OutQuad - } - } - } - - Rectangle { - id: pulseRing2 - anchors.centerIn: parent - width: root.pulseRingSize - height: root.pulseRingSize - radius: root.pulseRingSize / 2 - color: "transparent" - border.width: Math.round(Theme.spacingXS * 0.75) - border.color: Theme.secondary - opacity: 0 - - SequentialAnimation on opacity { - running: root.isRunning - loops: Animation.Infinite - NumberAnimation { - from: 0.8 - to: 0 - duration: 1500 - easing.type: Easing.OutQuad - } - } - - SequentialAnimation on scale { - running: root.isRunning - loops: Animation.Infinite - NumberAnimation { - from: 0.3 - to: 1.3 - duration: 1500 - easing.type: Easing.OutQuad - } - } - } - - Rectangle { - anchors.centerIn: parent - width: root.centerIconContainerSize - height: root.centerIconContainerSize - radius: root.centerIconContainerSize / 2 - color: Theme.primaryContainer - - DankIcon { - anchors.centerIn: parent - name: "vital_signs" - size: Theme.iconSizeLarge - color: Theme.primary - } - - SequentialAnimation on scale { - running: root.isRunning - loops: Animation.Infinite - NumberAnimation { - from: 1 - to: 1.1 - duration: 750 - easing.type: Easing.InOutQuad - } - NumberAnimation { - from: 1.1 - to: 1 - duration: 750 - easing.type: Easing.InOutQuad - } - } - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("System Check", "greeter doctor page title") - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Bold - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Analyzing configuration...", "greeter doctor page loading text") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Item { - id: resultsView - anchors.fill: parent - visible: root.hasRun && !root.isRunning - opacity: (root.hasRun && !root.isRunning) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Column { - id: headerSection - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Theme.spacingL - anchors.leftMargin: Theme.spacingXL - anchors.rightMargin: Theme.spacingXL - spacing: Theme.spacingL - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Rectangle { - width: root.headerIconContainerSize - height: root.headerIconContainerSize - radius: Math.round(root.headerIconContainerSize * 0.29) - color: root.errorCount > 0 ? Theme.errorContainer : Theme.primaryContainer - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: root.errorCount > 0 ? "warning" : "check_circle" - size: Theme.iconSize + 4 - color: root.errorCount > 0 ? Theme.error : Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: I18n.tr("System Check", "greeter doctor page title") - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - text: { - if (root.errorCount === 0) - return I18n.tr("All checks passed", "greeter doctor page success"); - return root.errorCount === 1 - ? I18n.tr("%1 issue found", "greeter doctor page error count").arg(root.errorCount) - : I18n.tr("%1 issues found", "greeter doctor page error count").arg(root.errorCount); - } - font.pixelSize: Theme.fontSizeMedium - color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - GreeterStatusCard { - width: (parent.width - Theme.spacingS * 3) / 4 - count: root.errorCount - label: I18n.tr("Errors", "greeter doctor page status card") - iconName: "error" - iconColor: Theme.error - bgColor: Theme.errorContainer || Theme.withAlpha(Theme.error, 0.15) - selected: root.selectedFilter === "error" - onClicked: root.selectedFilter = "error" - } - - GreeterStatusCard { - width: (parent.width - Theme.spacingS * 3) / 4 - count: root.warningCount - label: I18n.tr("Warnings", "greeter doctor page status card") - iconName: "warning" - iconColor: Theme.warning - bgColor: Theme.withAlpha(Theme.warning, 0.15) - selected: root.selectedFilter === "warn" - onClicked: root.selectedFilter = "warn" - } - - GreeterStatusCard { - width: (parent.width - Theme.spacingS * 3) / 4 - count: root.infoCount - label: I18n.tr("Info", "greeter doctor page status card") - iconName: "info" - iconColor: Theme.secondary - bgColor: Theme.withAlpha(Theme.secondary, 0.15) - selected: root.selectedFilter === "info" - onClicked: root.selectedFilter = "info" - } - - GreeterStatusCard { - width: (parent.width - Theme.spacingS * 3) / 4 - count: root.okCount - label: I18n.tr("OK", "greeter doctor page status card") - iconName: "check_circle" - iconColor: Theme.success - bgColor: Theme.withAlpha(Theme.success, 0.15) - selected: root.selectedFilter === "ok" - onClicked: root.selectedFilter = "ok" - } - } - } - - Rectangle { - id: resultsContainer - anchors.top: headerSection.bottom - anchors.bottom: footerSection.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Theme.spacingL - anchors.bottomMargin: Theme.spacingM - anchors.leftMargin: Theme.spacingXL - anchors.rightMargin: Theme.spacingXL - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - clip: true - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: root.filteredResults.length === 0 - - DankIcon { - name: { - switch (root.selectedFilter) { - case "error": - return "check_circle"; - case "warn": - return "thumb_up"; - case "info": - return "info"; - default: - return "verified"; - } - } - size: Math.round(Theme.iconSize * 1.67) - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - switch (root.selectedFilter) { - case "error": - return I18n.tr("No errors", "greeter doctor page empty state"); - case "warn": - return I18n.tr("No warnings", "greeter doctor page empty state"); - case "info": - return I18n.tr("No info items", "greeter doctor page empty state"); - default: - return I18n.tr("No checks passed", "greeter doctor page empty state"); - } - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - DankFlickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - clip: true - contentHeight: resultsColumn.height - contentWidth: width - visible: root.filteredResults.length > 0 - - Column { - id: resultsColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.filteredResults - - GreeterDoctorResultItem { - width: resultsColumn.width - resultData: modelData - } - } - } - } - } - - Row { - id: footerSection - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Theme.spacingL - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Run Again", "greeter doctor page button") - iconName: "refresh" - backgroundColor: Theme.surfaceContainerHighest - textColor: Theme.surfaceText - onClicked: root.runDoctor() - } - } - } - - Process { - id: doctorProcess - command: ["dms", "doctor", "--json"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - root.isRunning = false; - root.hasRun = true; - try { - root.doctorResults = JSON.parse(text); - if (root.doctorResults?.summary) { - root.errorCount = root.doctorResults.summary.errors || 0; - root.warningCount = root.doctorResults.summary.warnings || 0; - root.okCount = root.doctorResults.summary.ok || 0; - root.infoCount = root.doctorResults.summary.info || 0; - } - if (root.errorCount > 0) - root.selectedFilter = "error"; - else if (root.warningCount > 0) - root.selectedFilter = "warn"; - else if (root.infoCount > 0) - root.selectedFilter = "info"; - else - root.selectedFilter = "ok"; - } catch (e) { - console.error("GreeterDoctorPage: Failed to parse doctor output:", e); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.isRunning = false; - root.hasRun = true; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorResultItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorResultItem.qml deleted file mode 100644 index b15969a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterDoctorResultItem.qml +++ /dev/null @@ -1,109 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property var resultData: null - - readonly property string status: resultData?.status || "ok" - readonly property string statusIcon: { - switch (status) { - case "error": - return "error"; - case "warn": - return "warning"; - case "info": - return "info"; - default: - return "check_circle"; - } - } - readonly property color statusColor: { - switch (status) { - case "error": - return Theme.error; - case "warn": - return Theme.warning; - case "info": - return Theme.secondary; - default: - return Theme.success; - } - } - - height: Math.round(Theme.fontSizeMedium * 3.4) - radius: Theme.cornerRadius - color: Theme.withAlpha(statusColor, 0.08) - - DankIcon { - id: statusIcon - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - name: root.statusIcon - size: Theme.iconSize - 4 - color: root.statusColor - } - - Column { - anchors.left: statusIcon.right - anchors.leftMargin: Theme.spacingS - anchors.right: categoryChip.visible ? categoryChip.left : (urlButton.visible ? urlButton.left : parent.right) - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: 1 - - StyledText { - width: parent.width - text: root.resultData?.name || "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - } - - StyledText { - width: parent.width - text: root.resultData?.message || "" - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - elide: Text.ElideRight - visible: text.length > 0 - } - } - - Rectangle { - id: categoryChip - anchors.right: urlButton.visible ? urlButton.left : parent.right - anchors.rightMargin: urlButton.visible ? Theme.spacingXS : Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - height: Math.round(Theme.fontSizeSmall * 1.67) - width: categoryText.implicitWidth + Theme.spacingS - radius: Theme.spacingXS - color: Theme.surfaceContainerHighest - visible: !!(root.resultData?.category) - - StyledText { - id: categoryText - anchors.centerIn: parent - text: root.resultData?.category || "" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - } - } - - DankActionButton { - id: urlButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "open_in_new" - iconSize: Theme.iconSize - 6 - buttonSize: 24 - visible: !!(root.resultData?.url) - tooltipText: root.resultData?.url || "" - onClicked: Qt.openUrlExternally(root.resultData.url) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterFeatureCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterFeatureCard.qml deleted file mode 100644 index a5bf4f4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterFeatureCard.qml +++ /dev/null @@ -1,74 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property string title: "" - property string description: "" - - signal clicked - - readonly property real iconContainerSize: Math.round(Theme.iconSize * 1.5) - - height: Math.round(Theme.fontSizeMedium * 6.4) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Theme.primary - opacity: mouseArea.containsMouse ? 0.12 : 0 - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - Rectangle { - width: root.iconContainerSize - height: root.iconContainerSize - radius: Math.round(root.iconContainerSize * 0.28) - color: Theme.primaryContainer - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - anchors.centerIn: parent - name: root.iconName - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterModal.qml deleted file mode 100644 index 973dab2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterModal.qml +++ /dev/null @@ -1,333 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property int currentPage: 0 - readonly property int totalPages: 3 - readonly property var pageComponents: [welcomePage, doctorPage, completePage] - - property var cheatsheetData: ({}) - property bool cheatsheetLoaded: false - - readonly property int modalWidth: 720 - readonly property int modalHeight: screen ? Math.min(760, screen.height - 80) : 760 - - signal greeterCompleted - - Component.onCompleted: Qt.callLater(loadCheatsheet) - - function loadCheatsheet() { - const provider = KeybindsService.cheatsheetProvider; - if (KeybindsService.cheatsheetAvailable && provider && !cheatsheetLoaded) { - cheatsheetProcess.command = ["dms", "keybinds", "show", provider]; - cheatsheetProcess.running = true; - } - } - - Connections { - target: KeybindsService - function onCheatsheetAvailableChanged() { - if (KeybindsService.cheatsheetAvailable && !root.cheatsheetLoaded) - loadCheatsheet(); - } - } - - function getKeybind(actionPattern) { - if (!cheatsheetLoaded || !cheatsheetData.binds) - return ""; - for (const category in cheatsheetData.binds) { - const binds = cheatsheetData.binds[category]; - for (let i = 0; i < binds.length; i++) { - const bind = binds[i]; - if (bind.action && bind.action.includes(actionPattern)) - return bind.key || ""; - } - } - return ""; - } - - function show() { - currentPage = FirstLaunchService.requestedStartPage || 0; - visible = true; - } - - function showAtPage(page) { - currentPage = page; - visible = true; - } - - function nextPage() { - if (currentPage < totalPages - 1) - currentPage++; - } - - function prevPage() { - if (currentPage > 0) - currentPage--; - } - - function finish() { - FirstLaunchService.markFirstLaunchComplete(); - greeterCompleted(); - visible = false; - } - - function skip() { - FirstLaunchService.markFirstLaunchComplete(); - greeterCompleted(); - visible = false; - } - - objectName: "greeterModal" - title: I18n.tr("Welcome", "greeter modal window title") - minimumSize: Qt.size(modalWidth, modalHeight) - maximumSize: Qt.size(modalWidth, modalHeight) - color: Theme.surfaceContainer - visible: false - - Process { - id: cheatsheetProcess - running: false - - stdout: StdioCollector { - onStreamFinished: { - const trimmed = text.trim(); - if (trimmed.length === 0) - return; - try { - root.cheatsheetData = JSON.parse(trimmed); - root.cheatsheetLoaded = true; - } catch (e) { - console.warn("Greeter: Failed to parse cheatsheet:", e); - } - } - } - } - - FocusScope { - id: contentFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - root.skip(); - event.accepted = true; - } - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.currentPage < root.totalPages - 1) - root.nextPage(); - else - root.finish(); - event.accepted = true; - break; - case Qt.Key_Left: - if (root.currentPage > 0) - root.prevPage(); - event.accepted = true; - break; - case Qt.Key_Right: - if (root.currentPage < root.totalPages - 1) - root.nextPage(); - event.accepted = true; - break; - } - } - - MouseArea { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: headerRow.height + Theme.spacingM - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Item { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - height: Math.round(Theme.fontSizeMedium * 2.85) - - Rectangle { - id: pageIndicatorContainer - readonly property real indicatorHeight: Math.round(Theme.fontSizeMedium * 2) - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - width: pageIndicatorRow.width + Theme.spacingM * 2 - height: indicatorHeight - radius: indicatorHeight / 2 - color: Theme.surfaceContainerHigh - - Row { - id: pageIndicatorRow - anchors.centerIn: parent - spacing: Theme.spacingS - - Repeater { - model: root.totalPages - - Rectangle { - required property int index - property bool isActive: index === root.currentPage - readonly property real dotSize: Math.round(Theme.spacingS * 1.3) - - width: isActive ? dotSize * 3 : dotSize - height: dotSize - radius: dotSize / 2 - color: isActive ? Theme.primary : Theme.surfaceTextAlpha - anchors.verticalCenter: parent.verticalCenter - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - } - } - } - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported && windowControls.canMaximize - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.skip() - - DankTooltip { - text: I18n.tr("Skip setup", "greeter skip button tooltip") - } - } - } - } - - Item { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.bottom: footerRow.top - anchors.topMargin: Theme.spacingS - - Loader { - id: pageLoader - anchors.fill: parent - sourceComponent: root.pageComponents[root.currentPage] - - property var greeterRoot: root - } - } - - Rectangle { - id: footerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: Math.round(Theme.fontSizeMedium * 4.5) - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.top: parent.top - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.5 - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - visible: root.currentPage < root.totalPages - 1 - text: I18n.tr("Skip", "greeter skip button") - backgroundColor: "transparent" - textColor: Theme.surfaceVariantText - onClicked: root.skip() - } - - DankButton { - visible: root.currentPage > 0 - text: I18n.tr("Back", "greeter back button") - iconName: "arrow_back" - backgroundColor: Theme.surfaceContainerHighest - textColor: Theme.surfaceText - onClicked: root.prevPage() - } - - DankButton { - visible: root.currentPage < root.totalPages - 1 - enabled: !(root.currentPage === 1 && pageLoader.item && pageLoader.item.isRunning) - text: root.currentPage === 0 ? I18n.tr("Get Started", "greeter first page button") : I18n.tr("Next", "greeter next button") - iconName: "arrow_forward" - backgroundColor: Theme.primary - textColor: Theme.primaryText - onClicked: root.nextPage() - } - - DankButton { - visible: root.currentPage === root.totalPages - 1 - text: I18n.tr("Finish", "greeter finish button") - iconName: "check" - backgroundColor: Theme.primary - textColor: Theme.primaryText - onClicked: root.finish() - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } - - Component { - id: welcomePage - GreeterWelcomePage {} - } - - Component { - id: doctorPage - GreeterDoctorPage {} - } - - Component { - id: completePage - GreeterCompletePage {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterQuickLink.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterQuickLink.qml deleted file mode 100644 index d064275..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterQuickLink.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property string title: "" - property bool isExternal: false - - signal clicked - - height: Math.round(Theme.fontSizeMedium * 3.1) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Theme.primary - opacity: mouseArea.containsMouse ? 0.12 : 0 - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: root.iconName - size: Theme.iconSizeSmall + 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - visible: root.isExternal - name: "open_in_new" - size: Theme.iconSizeSmall - 2 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterSettingsCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterSettingsCard.qml deleted file mode 100644 index 85e6b1c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterSettingsCard.qml +++ /dev/null @@ -1,78 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property string title: "" - property string description: "" - - signal clicked - - readonly property real iconContainerSize: Math.round(Theme.iconSize * 1.5) - - height: Math.round(Theme.fontSizeMedium * 4.5) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Theme.primary - opacity: mouseArea.containsMouse ? 0.12 : 0 - } - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - width: root.iconContainerSize - height: root.iconContainerSize - radius: Math.round(root.iconContainerSize * 0.28) - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: root.iconName - size: Theme.iconSize - 4 - color: Theme.primaryText - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - root.iconContainerSize - Theme.spacingM - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterStatusCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterStatusCard.qml deleted file mode 100644 index af0d5d6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterStatusCard.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property int count: 0 - property string label: "" - property string iconName: "" - property color iconColor: Theme.surfaceText - property color bgColor: Theme.surfaceContainerHigh - property bool selected: false - - signal clicked - - height: Math.round(Theme.fontSizeMedium * 5) - radius: Theme.cornerRadius - color: bgColor - border.width: selected ? 2 : 0 - border.color: selected ? iconColor : "transparent" - scale: mouseArea.pressed ? 0.97 : 1 - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.shortDuration - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingS - - DankIcon { - name: root.iconName - size: Theme.iconSize - 4 - color: root.iconColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.count.toString() - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Bold - color: root.iconColor - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterWelcomePage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterWelcomePage.qml deleted file mode 100644 index fcb4fc5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Greeter/GreeterWelcomePage.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - readonly property real logoSize: Math.round(Theme.iconSize * 5.3) - - Column { - id: mainColumn - anchors.centerIn: parent - width: Math.min(Math.round(Theme.fontSizeMedium * 43), parent.width - Theme.spacingXL * 2) - spacing: Theme.spacingXL - - Column { - width: parent.width - spacing: Theme.spacingM - - Image { - width: root.logoSize - height: width * (569.94629 / 506.50931) - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg" - layer.enabled: true - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Welcome to DankMaterialShell", "greeter welcome page title") - font.pixelSize: Theme.fontSizeXLarge + 4 - font.weight: Font.Bold - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("A modern desktop shell for Wayland compositors", "greeter welcome page tagline") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineMedium - opacity: 0.3 - } - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Features", "greeter welcome page section header") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Grid { - width: parent.width - columns: 3 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "auto_awesome" - title: I18n.tr("Dynamic Theming", "greeter feature card title") - description: I18n.tr("Colors from wallpaper", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("theme") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "format_paint" - title: I18n.tr("App Theming", "greeter feature card title") - description: I18n.tr("GTK, Qt, IDEs, more", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("theme") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "download" - title: I18n.tr("Theme Registry", "greeter feature card title") - description: I18n.tr("Community themes", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("theme") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "view_carousel" - title: I18n.tr("DankBar", "greeter feature card title") - description: I18n.tr("Modular widget bar", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("dankbar_settings") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "extension" - title: I18n.tr("Plugins", "greeter feature card title") - description: I18n.tr("Extensible architecture", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("plugins") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "layers" - title: I18n.tr("Multi-Monitor", "greeter feature card title") - description: I18n.tr("Per-screen config", "greeter feature card description") - onClicked: { - const hasDisplayConfig = CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl; - PopoutService.openSettingsWithTab(hasDisplayConfig ? "display_config" : "display_widgets"); - } - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "nightlight" - title: I18n.tr("Display Control", "greeter feature card title") - description: I18n.tr("Night mode & gamma", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("display_gamma") - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "tune" - title: I18n.tr("Control Center", "greeter feature card title") - description: I18n.tr("Quick system toggles", "greeter feature card description") - // This is doing an IPC since its just easier and lazier to access the bar ref - onClicked: Quickshell.execDetached(["dms", "ipc", "call", "control-center", "open"]) - } - - GreeterFeatureCard { - width: (parent.width - Theme.spacingS * 2) / 3 - iconName: "lock" - title: I18n.tr("Lock Screen", "greeter feature card title") - description: I18n.tr("Security & privacy", "greeter feature card description") - onClicked: PopoutService.openSettingsWithTab("lock_screen") - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/KeybindsModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/KeybindsModal.qml deleted file mode 100644 index e1d6765..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/KeybindsModal.qml +++ /dev/null @@ -1,347 +0,0 @@ -import QtQml -import QtQuick -import QtQuick.Layouts -import Quickshell.Hyprland -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:keybinds" - useOverlayLayer: true - property real scrollStep: 60 - property var activeFlickable: null - property real _maxW: Math.min(Screen.width * 0.92, 1200) - property real _maxH: Math.min(Screen.height * 0.92, 900) - modalWidth: _maxW - modalHeight: _maxH - onBackgroundClicked: close() - onOpened: { - Qt.callLater(() => { - modalFocusScope.forceActiveFocus(); - if (contentLoader.item?.searchField) - contentLoader.item.searchField.forceActiveFocus(); - }); - if (!Object.keys(KeybindsService.cheatsheet).length && KeybindsService.cheatsheetAvailable) - KeybindsService.loadCheatsheet(); - } - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: root.useHyprlandFocusGrab && root.shouldHaveFocus - } - - function scrollDown() { - if (!root.activeFlickable) - return; - let newY = root.activeFlickable.contentY + scrollStep; - newY = Math.min(newY, root.activeFlickable.contentHeight - root.activeFlickable.height); - root.activeFlickable.contentY = newY; - } - - function scrollUp() { - if (!root.activeFlickable) - return; - let newY = root.activeFlickable.contentY - root.scrollStep; - newY = Math.max(0, newY); - root.activeFlickable.contentY = newY; - } - - modalFocusScope.Keys.onPressed: event => { - if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) { - scrollDown(); - event.accepted = true; - } else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) { - scrollUp(); - event.accepted = true; - } else if (event.key === Qt.Key_Down) { - scrollDown(); - event.accepted = true; - } else if (event.key === Qt.Key_Up) { - scrollUp(); - event.accepted = true; - } - } - - content: Component { - Item { - anchors.fill: parent - property alias searchField: searchField - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - RowLayout { - width: parent.width - - StyledText { - Layout.alignment: Qt.AlignLeft - text: KeybindsService.cheatsheet.title || i18n("Keybinds") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.primary - } - - DankTextField { - id: searchField - Layout.alignment: Qt.AlignRight - leftIconName: "search" - keyForwardTargets: [root.modalFocusScope] - onTextEdited: searchDebounce.restart() - Keys.onEscapePressed: event => { - root.close(); - event.accepted = true; - } - } - } - - Timer { - id: searchDebounce - interval: 50 - repeat: false - onTriggered: { - mainFlickable.categories = mainFlickable.generateCategories(searchField.text); - } - } - - DankFlickable { - id: mainFlickable - width: parent.width - height: parent.height - parent.spacing - 40 - contentWidth: rowLayout.implicitWidth - contentHeight: rowLayout.implicitHeight - clip: true - - Component.onCompleted: root.activeFlickable = mainFlickable - - property var rawBinds: KeybindsService.cheatsheet.binds || {} - - function generateCategories(query) { - const lowerQuery = query ? query.toLowerCase().trim() : ""; - const lowerQueryWords = query.split(/\s+/); - const processed = {}; - - for (const cat in rawBinds) { - const binds = rawBinds[cat]; - const catLower = cat.toLowerCase(); - const subcats = {}; - let hasSubcats = false; - for (let i = 0; i < binds.length; i++) { - const bind = binds[i]; - const keyLower = bind.key.toLowerCase(); - const descLower = bind.desc.toLowerCase(); - const actionLower = bind.action.toLowerCase(); - - if (bind.hideOnOverlay) - continue; - let shouldContinue = false; - for (let j = 0; j < lowerQueryWords.length; j++) { - const word = lowerQueryWords[j]; - if (!( - word.length === 0 || - keyLower.includes(word) || - descLower.includes(word) || - catLower.includes(word) || - actionLower.includes(word) - )) { - shouldContinue = true; - break; - } - } - if (shouldContinue) - continue; - - if (bind.subcat) { - hasSubcats = true; - if (!subcats[bind.subcat]) - subcats[bind.subcat] = []; - subcats[bind.subcat].push(bind); - } else { - if (!subcats["_root"]) - subcats["_root"] = []; - subcats["_root"].push(bind); - } - } - - if (Object.keys(subcats).length === 0) - continue; - - processed[cat] = { - hasSubcats: hasSubcats, - subcats: subcats, - subcatKeys: Object.keys(subcats) - }; - } - - return processed; - } - - property var categories: generateCategories(""); - - function estimateCategoryHeight(catName) { - const catData = categories[catName]; - if (!catData) - return 0; - let bindCount = 0; - for (const key of catData.subcatKeys) { - bindCount += catData.subcats[key]?.length || 0; - if (key !== "_root") - bindCount += 1; - } - return 40 + bindCount * 28; - } - - property var categoryKeys: Object.keys(categories); - - function distributeCategories(cols) { - const columns = []; - const heights = []; - for (let i = 0; i < cols; i++) { - columns.push([]); - heights.push(0); - } - const sorted = [...categoryKeys].sort((a, b) => estimateCategoryHeight(b) - estimateCategoryHeight(a)); - for (const cat of sorted) { - let minIdx = 0; - for (let i = 1; i < cols; i++) { - if (heights[i] < heights[minIdx]) - minIdx = i; - } - columns[minIdx].push(cat); - heights[minIdx] += estimateCategoryHeight(cat); - } - return columns; - } - - Row { - id: rowLayout - width: mainFlickable.width - spacing: Theme.spacingM - - property int numColumns: Math.max(1, Math.min(3, Math.floor(width / 350))) - property var columnCategories: mainFlickable.distributeCategories(numColumns) - - Repeater { - model: rowLayout.numColumns - - Column { - id: masonryColumn - width: (rowLayout.width - rowLayout.spacing * (rowLayout.numColumns - 1)) / rowLayout.numColumns - spacing: Theme.spacingXL - - Repeater { - model: rowLayout.columnCategories[index] || [] - - Column { - id: categoryColumn - width: parent.width - spacing: Theme.spacingXS - - property string catName: modelData - property var catData: mainFlickable.categories[catName] - - StyledText { - text: categoryColumn.catName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.primary - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.primary - opacity: 0.3 - } - - Item { - width: 1 - height: Theme.spacingXS - } - - Column { - width: parent.width - spacing: Theme.spacingM - - Repeater { - model: categoryColumn.catData?.subcatKeys || [] - - Column { - width: parent.width - spacing: Theme.spacingXS - - property string subcatName: modelData - property var subcatBinds: categoryColumn.catData?.subcats?.[subcatName] || [] - - StyledText { - visible: parent.subcatName !== "_root" - text: parent.subcatName - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.DemiBold - color: Theme.primary - opacity: 0.7 - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: parent.parent.subcatBinds - - Item { - width: parent.width - height: 24 - - StyledRect { - id: keyBadge - width: Math.min(keyText.implicitWidth + 12, 160) - height: 22 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: keyText - anchors.centerIn: parent - color: Theme.secondary - text: (modelData.key || "").replace(/\+/g, " + ") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - isMonospace: true - elide: Text.ElideRight - width: Math.min(implicitWidth, 148) - } - } - - StyledText { - anchors.left: parent.left - anchors.leftMargin: 170 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - text: modelData.desc || modelData.action || "" - font.pixelSize: Theme.fontSizeSmall - opacity: 0.9 - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/MuxModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/MuxModal.qml deleted file mode 100644 index 9d19388..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/MuxModal.qml +++ /dev/null @@ -1,633 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: muxModal - - layerNamespace: "dms:mux" - - property int selectedIndex: -1 - property string searchText: "" - property var filteredSessions: [] - - function updateFilteredSessions() { - var filtered = [] - var lowerSearch = searchText.trim().toLowerCase() - for (var i = 0; i < MuxService.sessions.length; i++) { - var session = MuxService.sessions[i] - if (lowerSearch.length > 0 && !session.name.toLowerCase().includes(lowerSearch)) - continue - filtered.push(session) - } - filteredSessions = filtered - - if (selectedIndex >= filteredSessions.length) { - selectedIndex = Math.max(0, filteredSessions.length - 1) - } - } - - onSearchTextChanged: updateFilteredSessions() - - Connections { - target: MuxService - function onSessionsChanged() { - updateFilteredSessions() - } - } - - HyprlandFocusGrab { - id: grab - windows: [muxModal.contentWindow] - active: CompositorService.isHyprland && muxModal.shouldHaveFocus - } - - function toggle() { - if (shouldBeVisible) { - hide() - } else { - show() - } - } - - function show() { - open() - selectedIndex = -1 - searchText = "" - MuxService.refreshSessions() - shouldHaveFocus = true - - Qt.callLater(() => { - if (muxPanel && muxPanel.searchField) { - muxPanel.searchField.forceActiveFocus(); - } - }) - } - - function hide() { - close() - selectedIndex = -1 - searchText = "" - } - - function attachToSession(name) { - MuxService.attachToSession(name) - hide() - } - - function renameSession(name) { - inputModal.showWithOptions({ - title: I18n.tr("Rename Session"), - message: I18n.tr("Enter a new name for session \"%1\"").arg(name), - initialText: name, - onConfirm: function (newName) { - MuxService.renameSession(name, newName) - } - }) - } - - function killSession(name) { - confirmModal.showWithOptions({ - title: I18n.tr("Kill Session"), - message: I18n.tr("Are you sure you want to kill session \"%1\"?").arg(name), - confirmText: I18n.tr("Kill"), - confirmColor: Theme.primary, - onConfirm: function () { - MuxService.killSession(name) - } - }) - } - - function createNewSession() { - inputModal.showWithOptions({ - title: I18n.tr("New Session"), - message: I18n.tr("Please write a name for your new %1 session").arg(MuxService.displayName), - onConfirm: function (name) { - MuxService.createSession(name) - hide() - } - }) - } - - function selectNext() { - selectedIndex = Math.min(selectedIndex + 1, filteredSessions.length - 1) - } - - function selectPrevious() { - selectedIndex = Math.max(selectedIndex - 1, -1) - } - - function activateSelected() { - if (selectedIndex === -1) { - createNewSession() - } else if (selectedIndex >= 0 && selectedIndex < filteredSessions.length) { - attachToSession(filteredSessions[selectedIndex].name) - } - } - - visible: false - modalWidth: 600 - modalHeight: 600 - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - cornerRadius: Theme.cornerRadius - borderColor: Theme.outlineMedium - borderWidth: 1 - enableShadow: true - keepContentLoaded: true - - onBackgroundClicked: hide() - - Timer { - interval: 3000 - running: muxModal.shouldBeVisible - repeat: true - onTriggered: MuxService.refreshSessions() - } - - IpcHandler { - function open(): string { - muxModal.show() - return "MUX_OPEN_SUCCESS" - } - - function close(): string { - muxModal.hide() - return "MUX_CLOSE_SUCCESS" - } - - function toggle(): string { - muxModal.toggle() - return "MUX_TOGGLE_SUCCESS" - } - - target: "mux" - } - - // Backwards compatibility - IpcHandler { - function open(): string { - muxModal.show() - return "TMUX_OPEN_SUCCESS" - } - - function close(): string { - muxModal.hide() - return "TMUX_CLOSE_SUCCESS" - } - - function toggle(): string { - muxModal.toggle() - return "TMUX_TOGGLE_SUCCESS" - } - - target: "tmux" - } - - InputModal { - id: inputModal - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - muxModal.shouldHaveFocus = false; - muxModal.contentWindow.visible = false; - return; - } - if (muxModal.shouldBeVisible) { - muxModal.contentWindow.visible = true; - } - Qt.callLater(function () { - if (!muxModal.shouldBeVisible) { - return; - } - muxModal.shouldHaveFocus = true; - muxModal.modalFocusScope.forceActiveFocus(); - if (muxPanel.searchField) { - muxPanel.searchField.forceActiveFocus(); - } - }); - } - } - - ConfirmModal { - id: confirmModal - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - muxModal.shouldHaveFocus = false; - muxModal.contentWindow.visible = false; - return; - } - if (muxModal.shouldBeVisible) { - muxModal.contentWindow.visible = true; - } - Qt.callLater(function () { - if (!muxModal.shouldBeVisible) { - return; - } - muxModal.shouldHaveFocus = true; - muxModal.modalFocusScope.forceActiveFocus(); - if (muxPanel.searchField) { - muxPanel.searchField.forceActiveFocus(); - } - }); - } - } - - directContent: Item { - id: muxPanel - - clip: false - - property alias searchField: searchField - - Keys.onPressed: event => { - if ((event.key === Qt.Key_J && (event.modifiers & Qt.ControlModifier)) || - (event.key === Qt.Key_Down)) { - selectNext() - event.accepted = true - } else if ((event.key === Qt.Key_K && (event.modifiers & Qt.ControlModifier)) || - (event.key === Qt.Key_Up)) { - selectPrevious() - event.accepted = true - } else if (event.key === Qt.Key_N && (event.modifiers & Qt.ControlModifier)) { - createNewSession() - event.accepted = true - } else if (event.key === Qt.Key_R && (event.modifiers & Qt.ControlModifier)) { - if (MuxService.supportsRename && selectedIndex >= 0 && selectedIndex < filteredSessions.length) { - renameSession(filteredSessions[selectedIndex].name) - } - event.accepted = true - } else if (event.key === Qt.Key_D && (event.modifiers & Qt.ControlModifier)) { - if (selectedIndex >= 0 && selectedIndex < filteredSessions.length) { - killSession(filteredSessions[selectedIndex].name) - } - event.accepted = true - } else if (event.key === Qt.Key_Escape) { - hide() - event.accepted = true - } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - activateSelected() - event.accepted = true - } - } - - Column { - width: parent.width - Theme.spacingM * 2 - height: parent.height - Theme.spacingM * 2 - x: Theme.spacingM - y: Theme.spacingM - spacing: Theme.spacingS - - // Header - Item { - width: parent.width - height: 40 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("%1 Sessions").arg(MuxService.displayName) - font.pixelSize: Theme.fontSizeLarge + 4 - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: { - const total = MuxService.sessions.length; - const filtered = muxModal.filteredSessions.length; - const activePart = total === 1 - ? I18n.tr("%1 active session").arg(total) - : I18n.tr("%1 active sessions").arg(total); - const filteredPart = filtered === 1 - ? I18n.tr("%1 filtered").arg(filtered) - : I18n.tr("%1 filtered").arg(filtered); - return activePart + ", " + filteredPart; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - } - - // Search field - DankTextField { - id: searchField - - width: parent.width - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search sessions...") - keyForwardTargets: [muxPanel] - - onTextEdited: { - muxModal.searchText = text - muxModal.selectedIndex = 0 - } - } - - // New Session Button - Rectangle { - width: parent.width - height: 56 - radius: Theme.cornerRadius - color: muxModal.selectedIndex === -1 ? Theme.primaryContainer : - (newMouse.containsMouse ? Theme.surfaceContainerHigh : Theme.surfaceContainer) - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - radius: 20 - color: Theme.primaryContainer - - DankIcon { - anchors.centerIn: parent - name: "add" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - Layout.fillWidth: true - spacing: 2 - - StyledText { - text: I18n.tr("New Session") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Create a new %1 session (n)").arg(MuxService.displayName) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - MouseArea { - id: newMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: muxModal.createNewSession() - } - } - - // Sessions List - Rectangle { - width: parent.width - height: parent.height - 88 - 48 - shortcutsBar.height - Theme.spacingS * 3 - radius: Theme.cornerRadius - color: "transparent" - - ScrollView { - anchors.fill: parent - clip: true - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: ScriptModel { - values: muxModal.filteredSessions - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 64 - radius: Theme.cornerRadius - color: muxModal.selectedIndex === index ? Theme.primaryContainer : - (sessionMouse.containsMouse ? Theme.surfaceContainerHigh : "transparent") - - MouseArea { - id: sessionMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: muxModal.attachToSession(modelData.name) - } - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - // Avatar - Rectangle { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - radius: 20 - color: modelData.attached ? Theme.primaryContainer : Theme.surfaceContainerHigh - - StyledText { - anchors.centerIn: parent - text: modelData.name.charAt(0).toUpperCase() - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: modelData.attached ? Theme.primary : Theme.surfaceText - } - } - - // Info - Column { - Layout.fillWidth: true - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - } - - StyledText { - text: { - var parts = [] - if (modelData.windows !== "N/A") - parts.push(modelData.windows === 1 - ? I18n.tr("%1 window").arg(modelData.windows) - : I18n.tr("%1 windows").arg(modelData.windows)) - parts.push(modelData.attached ? I18n.tr("attached") : I18n.tr("detached")) - return parts.join(" \u2022 ") - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - // Rename button (tmux only) - Rectangle { - Layout.preferredWidth: 36 - Layout.preferredHeight: 36 - radius: 18 - visible: MuxService.supportsRename - color: renameMouse.containsMouse ? Theme.surfaceContainerHighest : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "edit" - size: Theme.iconSizeSmall - color: renameMouse.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: renameMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: muxModal.renameSession(modelData.name) - } - } - - // Delete button - Rectangle { - Layout.preferredWidth: 36 - Layout.preferredHeight: 36 - radius: 18 - color: deleteMouse.containsMouse ? Theme.errorContainer : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: Theme.iconSizeSmall - color: deleteMouse.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - muxModal.killSession(modelData.name) - } - } - } - } - } - } - - // Empty state - Item { - width: parent.width - height: muxModal.filteredSessions.length === 0 ? 200 : 0 - visible: muxModal.filteredSessions.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: muxModal.searchText.length > 0 ? "search_off" : "terminal" - size: 48 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: muxModal.searchText.length > 0 ? I18n.tr("No sessions found") : I18n.tr("No active %1 sessions").arg(MuxService.displayName) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: muxModal.searchText.length > 0 ? I18n.tr("Try a different search") : I18n.tr("Press 'n' or click 'New Session' to create one") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - - // Shortcuts bar - Row { - id: shortcutsBar - width: parent.width - spacing: Theme.spacingM - bottomPadding: Theme.spacingS - - Repeater { - model: { - var shortcuts = [ - { key: "↑↓", label: I18n.tr("Navigate") }, - { key: "↵", label: I18n.tr("Attach") }, - { key: "^N", label: I18n.tr("New") }, - { key: "^D", label: I18n.tr("Kill") }, - { key: "Esc", label: I18n.tr("Close") } - ] - if (MuxService.supportsRename) - shortcuts.splice(3, 0, { key: "^R", label: I18n.tr("Rename") }) - return shortcuts - } - - delegate: Row { - required property var modelData - spacing: 4 - - Rectangle { - width: keyText.width + Theme.spacingS - height: keyText.height + 4 - radius: 4 - color: Theme.surfaceContainerHighest - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: keyText - anchors.centerIn: parent - text: modelData.key - font.pixelSize: Theme.fontSizeSmall - 1 - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkInfoModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkInfoModal.qml deleted file mode 100644 index 79dbada..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkInfoModal.qml +++ /dev/null @@ -1,155 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:network-info" - - keepPopoutsOpen: true - - property bool networkInfoModalVisible: false - property string networkSSID: "" - property var networkData: null - - function showNetworkInfo(ssid, data) { - networkSSID = ssid; - networkData = data; - networkInfoModalVisible = true; - open(); - NetworkService.fetchNetworkInfo(ssid); - } - - function hideDialog() { - networkInfoModalVisible = false; - close(); - networkSSID = ""; - networkData = null; - } - - visible: networkInfoModalVisible - modalWidth: 600 - modalHeight: 500 - enableShadow: true - onBackgroundClicked: hideDialog() - onVisibleChanged: { - if (!visible) { - networkSSID = ""; - networkData = null; - } - } - - content: Component { - Item { - anchors.fill: parent - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - - Column { - width: parent.width - 40 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Network Information") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Details for \"%1\"").arg(networkSSID) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - elide: Text.ElideRight - } - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hideDialog() - } - } - - Rectangle { - id: detailsRect - - width: parent.width - height: parent.height - 140 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: Theme.outlineStrong - border.width: 1 - clip: true - - DankFlickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: detailsText.contentHeight - - StyledText { - id: detailsText - - width: parent.width - text: NetworkService.networkInfoDetails && NetworkService.networkInfoDetails.replace(/\\n/g, '\n') || I18n.tr("No information available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - wrapMode: Text.WordWrap - } - } - } - - Item { - width: parent.width - height: 40 - - Rectangle { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: closeText - - anchors.centerIn: parent - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: closeArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.hideDialog() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkWiredInfoModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkWiredInfoModal.qml deleted file mode 100644 index 4b42fdc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NetworkWiredInfoModal.qml +++ /dev/null @@ -1,155 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:network-info-wired" - - keepPopoutsOpen: true - - property bool networkWiredInfoModalVisible: false - property string networkID: "" - property var networkData: null - - function showNetworkInfo(id, data) { - networkID = id; - networkData = data; - networkWiredInfoModalVisible = true; - open(); - NetworkService.fetchWiredNetworkInfo(data.uuid); - } - - function hideDialog() { - networkWiredInfoModalVisible = false; - close(); - networkID = ""; - networkData = null; - } - - visible: networkWiredInfoModalVisible - modalWidth: 600 - modalHeight: 500 - enableShadow: true - onBackgroundClicked: hideDialog() - onVisibleChanged: { - if (!visible) { - networkID = ""; - networkData = null; - } - } - - content: Component { - Item { - anchors.fill: parent - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - - Column { - width: parent.width - 40 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Network Information") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Details for \"%1\"").arg(networkSSID) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - elide: Text.ElideRight - } - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hideDialog() - } - } - - Rectangle { - id: detailsRect - - width: parent.width - height: parent.height - 140 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: Theme.outlineStrong - border.width: 1 - clip: true - - DankFlickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: detailsText.contentHeight - - StyledText { - id: detailsText - - width: parent.width - text: NetworkService.networkWiredInfoDetails && NetworkService.networkWiredInfoDetails.replace(/\\n/g, '\n') || I18n.tr("No information available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - wrapMode: Text.WordWrap - } - } - } - - Item { - width: parent.width - height: 40 - - Rectangle { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: closeText - - anchors.centerIn: parent - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: closeArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.hideDialog() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NotificationModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NotificationModal.qml deleted file mode 100644 index 8653344..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/NotificationModal.qml +++ /dev/null @@ -1,225 +0,0 @@ -import QtQuick -import Quickshell.Hyprland -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Modules.Notifications.Center -import qs.Services - -DankModal { - id: notificationModal - - layerNamespace: "dms:notification-center-modal" - - HyprlandFocusGrab { - windows: [notificationModal.contentWindow] - active: notificationModal.useHyprlandFocusGrab && notificationModal.shouldHaveFocus - } - - property bool notificationModalOpen: false - property var notificationListRef: null - property var historyListRef: null - property int currentTab: 0 - - property var notificationHeaderRef: null - - function show() { - notificationModalOpen = true; - currentTab = 0; - NotificationService.onOverlayOpen(); - open(); - modalKeyboardController.reset(); - if (modalKeyboardController && notificationListRef) { - modalKeyboardController.listView = notificationListRef; - modalKeyboardController.rebuildFlatNavigation(); - - Qt.callLater(() => { - modalKeyboardController.keyboardNavigationActive = true; - modalKeyboardController.selectedFlatIndex = 0; - modalKeyboardController.updateSelectedIdFromIndex(); - if (notificationListRef) { - notificationListRef.keyboardActive = true; - notificationListRef.currentIndex = 0; - } - modalKeyboardController.selectionVersion++; - modalKeyboardController.ensureVisible(); - }); - } - } - - function hide() { - notificationModalOpen = false; - NotificationService.onOverlayClose(); - close(); - modalKeyboardController.reset(); - } - - function toggle() { - if (shouldBeVisible) { - hide(); - } else { - show(); - } - } - - function clearAll() { - NotificationService.clearAllNotifications(); - } - - function dismissAllPopups() { - NotificationService.dismissAllPopups(); - } - - modalWidth: Math.min(500, screenWidth - 48) - modalHeight: Math.min(700, screenHeight * 0.85) - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - visible: false - onBackgroundClicked: hide() - onOpened: () => { - Qt.callLater(() => modalFocusScope.forceActiveFocus()); - } - onShouldBeVisibleChanged: shouldBeVisible => { - if (!shouldBeVisible) { - notificationModalOpen = false; - modalKeyboardController.reset(); - NotificationService.onOverlayClose(); - } - } - modalFocusScope.Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - hide(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Left) { - if (notificationHeaderRef && notificationHeaderRef.currentTab > 0) { - notificationHeaderRef.currentTab = 0; - event.accepted = true; - } - return; - } - if (event.key === Qt.Key_Right) { - if (notificationHeaderRef && notificationHeaderRef.currentTab === 0 && SettingsData.notificationHistoryEnabled) { - notificationHeaderRef.currentTab = 1; - event.accepted = true; - } - return; - } - - if (currentTab === 1 && historyListRef) { - historyListRef.handleKey(event); - return; - } - modalKeyboardController.handleKey(event); - } - - NotificationKeyboardController { - id: modalKeyboardController - - listView: null - isOpen: notificationModal.notificationModalOpen - onClose: () => notificationModal.hide() - } - - IpcHandler { - function open(): string { - notificationModal.show(); - return "NOTIFICATION_MODAL_OPEN_SUCCESS"; - } - - function close(): string { - notificationModal.hide(); - return "NOTIFICATION_MODAL_CLOSE_SUCCESS"; - } - - function toggle(): string { - notificationModal.toggle(); - return "NOTIFICATION_MODAL_TOGGLE_SUCCESS"; - } - - function toggleDoNotDisturb(): string { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - - return "NOTIFICATION_MODAL_TOGGLE_DND_SUCCESS"; - } - - function getDoNotDisturb(): bool { - return SessionData.doNotDisturb; - } - - function clearAll(): string { - notificationModal.clearAll(); - return "NOTIFICATION_MODAL_CLEAR_ALL_SUCCESS"; - } - - function dismissAllPopups(): string { - notificationModal.dismissAllPopups(); - return "NOTIFICATION_MODAL_DISMISS_ALL_POPUPS_SUCCESS"; - } - - target: "notifications" - } - - content: Component { - Item { - id: notificationKeyHandler - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - anchors.fill: parent - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - NotificationHeader { - id: notificationHeader - keyboardController: modalKeyboardController - onCurrentTabChanged: notificationModal.currentTab = currentTab - Component.onCompleted: notificationModal.notificationHeaderRef = notificationHeader - } - - NotificationSettings { - id: notificationSettings - expanded: notificationHeader.showSettings - } - - KeyboardNavigatedNotificationList { - id: notificationList - width: parent.width - height: parent.height - y - visible: notificationHeader.currentTab === 0 - keyboardController: modalKeyboardController - Component.onCompleted: { - notificationModal.notificationListRef = notificationList; - if (modalKeyboardController) { - modalKeyboardController.listView = notificationList; - modalKeyboardController.rebuildFlatNavigation(); - } - } - } - - HistoryNotificationList { - id: historyList - width: parent.width - height: parent.height - y - visible: notificationHeader.currentTab === 1 - Component.onCompleted: notificationModal.historyListRef = historyList - } - } - - NotificationKeyboardHints { - id: keyboardHints - - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - showHints: notificationHeader.currentTab === 0 ? modalKeyboardController.showKeyboardHints : historyList.showKeyboardHints - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PolkitAuthModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PolkitAuthModal.qml deleted file mode 100644 index 21ddf8f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PolkitAuthModal.qml +++ /dev/null @@ -1,412 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property string passwordInput: "" - property var currentFlow: PolkitService.agent?.flow - property bool isLoading: false - property bool awaitingFprintForPassword: false - readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 - - property string polkitEtcPamText: "" - property string polkitLibPamText: "" - property string systemAuthPamText: "" - property string commonAuthPamText: "" - property string passwordAuthPamText: "" - readonly property bool polkitPamHasFprint: { - const polkitText = polkitEtcPamText !== "" ? polkitEtcPamText : polkitLibPamText; - if (!polkitText) - return false; - return pamModuleEnabled(polkitText, "pam_fprintd") || (polkitText.includes("system-auth") && pamModuleEnabled(systemAuthPamText, "pam_fprintd")) || (polkitText.includes("common-auth") && pamModuleEnabled(commonAuthPamText, "pam_fprintd")) || (polkitText.includes("password-auth") && pamModuleEnabled(passwordAuthPamText, "pam_fprintd")); - } - - function stripPamComment(line) { - if (!line) - return ""; - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) - return ""; - const hashIdx = trimmed.indexOf("#"); - if (hashIdx >= 0) - return trimmed.substring(0, hashIdx).trim(); - return trimmed; - } - - function pamModuleEnabled(pamText, moduleName) { - if (!pamText || !moduleName) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (line && line.includes(moduleName)) - return true; - } - return false; - } - - function focusPasswordField() { - passwordField.forceActiveFocus(); - } - - function show() { - passwordInput = ""; - isLoading = false; - awaitingFprintForPassword = false; - visible = true; - Qt.callLater(focusPasswordField); - } - - function hide() { - visible = false; - } - - function _commitSubmit() { - isLoading = true; - awaitingFprintForPassword = false; - currentFlow.submit(passwordInput); - passwordInput = ""; - } - - function submitAuth() { - if (!currentFlow || isLoading) - return; - if (!currentFlow.isResponseRequired) { - awaitingFprintForPassword = true; - return; - } - _commitSubmit(); - } - - function cancelAuth() { - if (isLoading) - return; - awaitingFprintForPassword = false; - if (currentFlow) { - currentFlow.cancelAuthenticationRequest(); - return; - } - hide(); - } - - objectName: "polkitAuthModal" - title: I18n.tr("Authentication") - minimumSize: Qt.size(460, 220) - maximumSize: Qt.size(460, 220) - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - Qt.callLater(focusPasswordField); - return; - } - passwordInput = ""; - isLoading = false; - awaitingFprintForPassword = false; - } - - Connections { - target: PolkitService.agent - enabled: PolkitService.polkitAvailable - - function onAuthenticationRequestStarted() { - show(); - } - - function onIsActiveChanged() { - if (!(PolkitService.agent?.isActive ?? false)) - hide(); - } - } - - Connections { - target: currentFlow - enabled: currentFlow !== null - - function onIsResponseRequiredChanged() { - if (!currentFlow.isResponseRequired) - return; - if (awaitingFprintForPassword && passwordInput !== "") { - _commitSubmit(); - return; - } - awaitingFprintForPassword = false; - isLoading = false; - passwordInput = ""; - passwordField.forceActiveFocus(); - } - - function onAuthenticationSucceeded() { - hide(); - } - - function onAuthenticationFailed() { - isLoading = false; - } - - function onAuthenticationRequestCancelled() { - hide(); - } - } - - FileView { - path: "/etc/pam.d/polkit-1" - printErrors: false - onLoaded: root.polkitEtcPamText = text() - onLoadFailed: root.polkitEtcPamText = "" - } - - FileView { - path: "/usr/lib/pam.d/polkit-1" - printErrors: false - onLoaded: root.polkitLibPamText = text() - onLoadFailed: root.polkitLibPamText = "" - } - - FileView { - path: "/etc/pam.d/system-auth" - printErrors: false - onLoaded: root.systemAuthPamText = text() - onLoadFailed: root.systemAuthPamText = "" - } - - FileView { - path: "/etc/pam.d/common-auth" - printErrors: false - onLoaded: root.commonAuthPamText = text() - onLoadFailed: root.commonAuthPamText = "" - } - - FileView { - path: "/etc/pam.d/password-auth" - printErrors: false - onLoaded: root.passwordAuthPamText = text() - onLoadFailed: root.passwordAuthPamText = "" - } - - FocusScope { - id: contentFocusScope - - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - cancelAuth(); - event.accepted = true; - } - - Item { - id: headerSection - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - height: Math.max(titleColumn.implicitHeight, windowButtonRow.implicitHeight) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Column { - id: titleColumn - anchors.left: parent.left - anchors.right: windowButtonRow.left - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Authentication Required") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: currentFlow?.message ?? "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - maximumLineCount: 2 - elide: Text.ElideRight - visible: text !== "" - } - - StyledText { - text: currentFlow?.supplementaryMessage ?? "" - font.pixelSize: Theme.fontSizeSmall - color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - maximumLineCount: 2 - elide: Text.ElideRight - opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8 - visible: text !== "" - } - } - - Row { - id: windowButtonRow - anchors.right: parent.right - anchors.top: parent.top - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported && windowControls.canMaximize - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - enabled: !isLoading - opacity: enabled ? 1 : 0.5 - onClicked: cancelAuth() - } - } - } - - Column { - id: bottomSection - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - StyledText { - text: currentFlow?.inputPrompt ?? "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - visible: text !== "" - } - - DankTextField { - id: passwordField - - width: parent.width - height: inputFieldHeight - backgroundColor: Theme.surfaceHover - normalBorderColor: Theme.outlineStrong - focusedBorderColor: Theme.primary - borderWidth: 1 - focusedBorderWidth: 2 - leftIconName: polkitPamHasFprint ? "fingerprint" : "" - leftIconSize: 20 - leftIconColor: Theme.primary - leftIconFocusedColor: Theme.primary - opacity: isLoading ? 0.5 : 1 - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: passwordInput - showPasswordToggle: !(currentFlow?.responseVisible ?? false) - echoMode: (currentFlow?.responseVisible ?? false) || passwordVisible ? TextInput.Normal : TextInput.Password - placeholderText: "" - enabled: !isLoading - onTextEdited: passwordInput = text - onAccepted: submitAuth() - } - - StyledText { - text: I18n.tr("Authentication failed, please try again") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - width: parent.width - visible: currentFlow?.failed ?? false - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - enabled: !isLoading - opacity: enabled ? 1 : 0.5 - - StyledText { - id: cancelText - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: cancelAuth() - } - } - - Rectangle { - width: Math.max(80, authText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - enabled: !isLoading - opacity: enabled ? 1 : 0.5 - - StyledText { - id: authText - anchors.centerIn: parent - text: I18n.tr("Authenticate") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: authArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: submitAuth() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PowerMenuModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PowerMenuModal.qml deleted file mode 100644 index c59037f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/PowerMenuModal.qml +++ /dev/null @@ -1,809 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - - layerNamespace: "dms:power-menu" - keepPopoutsOpen: true - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: root.useHyprlandFocusGrab && root.shouldHaveFocus - } - - property int selectedIndex: 0 - property int selectedRow: 0 - property int selectedCol: 0 - property rect parentBounds: Qt.rect(0, 0, 0, 0) - property var parentScreen: null - property var visibleActions: [] - property int gridColumns: 3 - property int gridRows: 2 - - property string holdAction: "" - property int holdActionIndex: -1 - property real holdProgress: 0 - property bool showHoldHint: false - - readonly property bool needsConfirmation: SettingsData.powerActionConfirm - readonly property int holdDurationMs: SettingsData.powerActionHoldDuration * 1000 - - signal powerActionRequested(string action, string title, string message) - signal lockRequested - - function actionNeedsConfirm(action) { - return action !== "lock" && action !== "restart"; - } - - function startHold(action, actionIndex) { - if (!needsConfirmation || !actionNeedsConfirm(action)) { - executeAction(action); - return; - } - holdAction = action; - holdActionIndex = actionIndex; - holdProgress = 0; - showHoldHint = false; - holdTimer.start(); - } - - function cancelHold() { - if (holdAction === "") - return; - const wasHolding = holdProgress > 0; - holdTimer.stop(); - if (wasHolding && holdProgress < 1) { - showHoldHint = true; - hintTimer.restart(); - } - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - } - - function completeHold() { - if (holdProgress < 1) { - cancelHold(); - return; - } - const action = holdAction; - holdTimer.stop(); - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - executeAction(action); - } - - function executeAction(action) { - if (action === "lock") { - close(); - lockRequested(); - return; - } - if (action === "restart") { - close(); - Quickshell.execDetached(["dms", "restart"]); - return; - } - close(); - root.powerActionRequested(action, "", ""); - } - - Timer { - id: holdTimer - interval: 16 - repeat: true - onTriggered: { - root.holdProgress = Math.min(1, root.holdProgress + (interval / root.holdDurationMs)); - if (root.holdProgress >= 1) { - stop(); - root.completeHold(); - } - } - } - - Timer { - id: hintTimer - interval: 2000 - onTriggered: root.showHoldHint = false - } - - function openCentered() { - parentBounds = Qt.rect(0, 0, 0, 0); - parentScreen = null; - open(); - } - - function openFromControlCenter(bounds, targetScreen) { - parentBounds = bounds; - parentScreen = targetScreen; - open(); - } - - function updateVisibleActions() { - const allActions = SettingsData.powerMenuActions || ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]; - visibleActions = allActions.filter(action => { - if (action === "hibernate" && !SessionService.hibernateSupported) - return false; - return true; - }); - - if (!SettingsData.powerMenuGridLayout) - return; - const count = visibleActions.length; - if (count === 0) { - gridColumns = 1; - gridRows = 1; - return; - } - - if (count <= 3) { - gridColumns = 1; - gridRows = count; - return; - } - - if (count === 4) { - gridColumns = 2; - gridRows = 2; - return; - } - - gridColumns = 3; - gridRows = Math.ceil(count / 3); - } - - function getDefaultActionIndex() { - const defaultAction = SettingsData.powerMenuDefaultAction || "logout"; - const index = visibleActions.indexOf(defaultAction); - return index >= 0 ? index : 0; - } - - function getActionAtIndex(index) { - if (index < 0 || index >= visibleActions.length) - return ""; - return visibleActions[index]; - } - - function getActionData(action) { - switch (action) { - case "reboot": - return { - "icon": "restart_alt", - "label": I18n.tr("Reboot"), - "key": "R" - }; - case "logout": - return { - "icon": "logout", - "label": I18n.tr("Log Out"), - "key": "X" - }; - case "poweroff": - return { - "icon": "power_settings_new", - "label": I18n.tr("Power Off"), - "key": "P" - }; - case "lock": - return { - "icon": "lock", - "label": I18n.tr("Lock"), - "key": "L" - }; - case "suspend": - return { - "icon": "bedtime", - "label": I18n.tr("Suspend"), - "key": "S" - }; - case "hibernate": - return { - "icon": "ac_unit", - "label": I18n.tr("Hibernate"), - "key": "H" - }; - case "restart": - return { - "icon": "refresh", - "label": I18n.tr("Restart DMS"), - "key": "D" - }; - default: - return { - "icon": "help", - "label": action, - "key": "?" - }; - } - } - - function selectOption(action, actionIndex) { - startHold(action, actionIndex !== undefined ? actionIndex : -1); - } - - shouldBeVisible: false - modalWidth: SettingsData.powerMenuGridLayout ? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2) : 400 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight : 300 - enableShadow: true - targetScreen: parentScreen - positioning: parentBounds.width > 0 ? "custom" : "center" - customPosition: { - if (parentBounds.width > 0) { - const effectiveBarThickness = Math.max(26 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) * 0.6 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (SettingsData.barConfigs[0]?.innerPadding ?? 4))); - const barExclusionZone = effectiveBarThickness + (SettingsData.barConfigs[0]?.spacing ?? 4) + (SettingsData.barConfigs[0]?.bottomGap ?? 0); - const screenW = parentScreen?.width ?? 1920; - const screenH = parentScreen?.height ?? 1080; - const margin = Theme.spacingL; - - let targetX = parentBounds.x + (parentBounds.width - modalWidth) / 2; - let targetY = parentBounds.y + (parentBounds.height - modalHeight) / 2; - - const minY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Top ? barExclusionZone + margin : margin; - const maxY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Bottom ? screenH - modalHeight - barExclusionZone - margin : screenH - modalHeight - margin; - - targetY = Math.max(minY, Math.min(maxY, targetY)); - - return Qt.point(targetX, targetY); - } - return Qt.point(0, 0); - } - onBackgroundClicked: () => { - cancelHold(); - close(); - } - onOpened: () => { - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - showHoldHint = false; - updateVisibleActions(); - const defaultIndex = getDefaultActionIndex(); - if (SettingsData.powerMenuGridLayout) { - selectedRow = Math.floor(defaultIndex / gridColumns); - selectedCol = defaultIndex % gridColumns; - selectedIndex = defaultIndex; - } else { - selectedIndex = defaultIndex; - } - Qt.callLater(() => modalFocusScope.forceActiveFocus()); - } - onDialogClosed: () => { - cancelHold(); - } - Component.onCompleted: updateVisibleActions() - modalFocusScope.Keys.onPressed: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (SettingsData.powerMenuGridLayout) { - handleGridNavigation(event, true); - } else { - handleListNavigation(event, true); - } - } - modalFocusScope.Keys.onReleased: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (SettingsData.powerMenuGridLayout) { - handleGridNavigation(event, false); - } else { - handleListNavigation(event, false); - } - } - - function handleListNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_L || event.key === Qt.Key_S || event.key === Qt.Key_H || event.key === Qt.Key_D || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_L: - startHold("lock", visibleActions.indexOf("lock")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - case Qt.Key_D: - startHold("restart", visibleActions.indexOf("restart")); - event.accepted = true; - break; - } - } - - function handleGridNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_L || event.key === Qt.Key_S || event.key === Qt.Key_H || event.key === Qt.Key_D || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Left: - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Right: - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_L: - startHold("lock", visibleActions.indexOf("lock")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - case Qt.Key_D: - startHold("restart", visibleActions.indexOf("restart")); - event.accepted = true; - break; - } - } - - content: Component { - Item { - anchors.fill: parent - implicitHeight: (SettingsData.powerMenuGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight) + Theme.spacingL * 2 + (root.needsConfirmation ? hintRow.height + Theme.spacingM : 0) - - Grid { - id: buttonGrid - visible: SettingsData.powerMenuGridLayout - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingL - columns: root.gridColumns - columnSpacing: Theme.spacingS - rowSpacing: Theme.spacingS - - Repeater { - model: root.visibleActions - - Rectangle { - id: gridButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: (root.modalWidth - Theme.spacingL * 2 - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns - height: 100 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (mouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: gridProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: gridButtonRect.isHolding - layer.enabled: gridButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: gridProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (gridButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (gridButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: gridButtonRect.actionData.icon - size: Theme.iconSize + 8 - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: gridButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Rectangle { - width: 20 - height: 16 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: gridButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - 1 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedRow = Math.floor(index / root.gridColumns); - root.selectedCol = index % root.gridColumns; - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Column { - id: buttonColumn - visible: !SettingsData.powerMenuGridLayout - anchors { - left: parent.left - right: parent.right - top: parent.top - leftMargin: Theme.spacingL - rightMargin: Theme.spacingL - topMargin: Theme.spacingL - } - spacing: Theme.spacingS - - Repeater { - model: root.visibleActions - - Rectangle { - id: listButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: parent.width - height: 56 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (listMouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: listProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: listButtonRect.isHolding - layer.enabled: listButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: listProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (listButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (listButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Row { - anchors { - left: parent.left - right: parent.right - leftMargin: Theme.spacingM - rightMargin: Theme.spacingM - verticalCenter: parent.verticalCenter - } - spacing: Theme.spacingM - - DankIcon { - name: listButtonRect.actionData.icon - size: Theme.iconSize + 4 - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: listButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 28 - height: 20 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors { - right: parent.right - rightMargin: Theme.spacingM - verticalCenter: parent.verticalCenter - } - - StyledText { - text: listButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - - MouseArea { - id: listMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Row { - id: hintRow - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingXS - visible: root.needsConfirmation - opacity: root.showHoldHint ? 1 : 0.5 - - Behavior on opacity { - NumberAnimation { - duration: 150 - } - } - - DankIcon { - name: root.showHoldHint ? "warning" : "touch_app" - size: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - readonly property real totalMs: SettingsData.powerActionHoldDuration * 1000 - readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress)) - text: { - if (root.showHoldHint) - return I18n.tr("Hold longer to confirm"); - if (root.holdProgress > 0) { - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(remainingMs); - return I18n.tr("Hold to confirm (%1s)").arg(Math.ceil(remainingMs / 1000)); - } - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs); - return I18n.tr("Hold to confirm (%1s)").arg(SettingsData.powerActionHoldDuration); - } - font.pixelSize: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/ProcessListModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/ProcessListModal.qml deleted file mode 100644 index 8cfc705..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/ProcessListModal.qml +++ /dev/null @@ -1,609 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Modules.ProcessList -import qs.Services -import qs.Widgets - -FloatingWindow { - id: processListModal - - property bool disablePopupTransparency: true - property int currentTab: 0 - property string searchText: "" - property string expandedPid: "" - property string processFilter: "all" - property bool shouldHaveFocus: visible - property alias shouldBeVisible: processListModal.visible - - signal closingModal - - function show() { - if (!DgopService.dgopAvailable) { - console.warn("ProcessListModal: dgop is not available"); - return; - } - visible = true; - } - - function hide() { - visible = false; - if (processContextMenu.visible) - processContextMenu.close(); - } - - function toggle() { - if (!DgopService.dgopAvailable) { - console.warn("ProcessListModal: dgop is not available"); - return; - } - visible = !visible; - } - - function focusOrToggle() { - if (!DgopService.dgopAvailable) { - console.warn("ProcessListModal: dgop is not available"); - return; - } - if (visible) { - const modalTitle = I18n.tr("System Monitor", "sysmon window title"); - for (const toplevel of ToplevelManager.toplevels.values) { - if (toplevel.title !== "System Monitor" && toplevel.title !== modalTitle) - continue; - if (toplevel.activated) { - hide(); - return; - } - toplevel.activate(); - return; - } - } - show(); - } - - function formatBytes(bytes) { - if (bytes < 1024) - return bytes.toFixed(0) + " B/s"; - if (bytes < 1024 * 1024) - return (bytes / 1024).toFixed(1) + " KB/s"; - if (bytes < 1024 * 1024 * 1024) - return (bytes / (1024 * 1024)).toFixed(1) + " MB/s"; - return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s"; - } - - function nextTab() { - currentTab = (currentTab + 1) % 4; - } - - function previousTab() { - currentTab = (currentTab - 1 + 4) % 4; - } - - objectName: "processListModal" - title: I18n.tr("System Monitor", "sysmon window title") - minimumSize: Qt.size(Math.min(Math.round(Theme.fontSizeMedium * 48), Screen.width), Math.min(Math.round(Theme.fontSizeMedium * 34), Screen.height)) - implicitWidth: Math.round(Theme.fontSizeMedium * 71) - implicitHeight: Math.round(Theme.fontSizeMedium * 51) - color: Theme.surfaceContainer - visible: false - - onCurrentTabChanged: { - if (visible && currentTab === 0 && searchField.visible) - searchField.forceActiveFocus(); - } - - onVisibleChanged: { - if (!visible) { - closingModal(); - searchText = ""; - expandedPid = ""; - processFilter = "all"; - processFilterGroup.currentIndex = 0; - if (processesTabLoader.item) - processesTabLoader.item.reset(); - DgopService.removeRef(["cpu", "memory", "network", "disk", "system"]); - } else { - DgopService.addRef(["cpu", "memory", "network", "disk", "system"]); - Qt.callLater(() => { - if (currentTab === 0 && searchField.visible) - searchField.forceActiveFocus(); - else if (contentFocusScope) - contentFocusScope.forceActiveFocus(); - }); - } - } - - ProcessContextMenu { - id: processContextMenu - parentFocusItem: contentFocusScope - onProcessKilled: { - if (processesTabLoader.item) - processesTabLoader.item.forceRefresh(3); - } - } - - FocusScope { - id: contentFocusScope - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - if (processContextMenu.visible) - return; - - switch (event.key) { - case Qt.Key_1: - currentTab = 0; - event.accepted = true; - return; - case Qt.Key_2: - currentTab = 1; - event.accepted = true; - return; - case Qt.Key_3: - currentTab = 2; - event.accepted = true; - return; - case Qt.Key_4: - currentTab = 3; - event.accepted = true; - return; - case Qt.Key_Tab: - nextTab(); - event.accepted = true; - return; - case Qt.Key_Backtab: - previousTab(); - event.accepted = true; - return; - case Qt.Key_Escape: - if (searchText.length > 0) { - searchText = ""; - event.accepted = true; - return; - } - if (currentTab === 0 && processesTabLoader.item?.keyboardNavigationActive) { - processesTabLoader.item.reset(); - event.accepted = true; - return; - } - hide(); - event.accepted = true; - return; - case Qt.Key_F: - if (event.modifiers & Qt.ControlModifier) { - searchField.forceActiveFocus(); - event.accepted = true; - return; - } - break; - } - - if (currentTab === 0 && processesTabLoader.item) - processesTabLoader.item.handleKey(event); - } - - Rectangle { - anchors.centerIn: parent - width: 400 - height: 200 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1) - border.color: Theme.error - border.width: 2 - visible: !DgopService.dgopAvailable - - Column { - anchors.centerIn: parent - spacing: Theme.spacingL - - DankIcon { - name: "error" - size: 48 - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("System Monitor Unavailable") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.", "dgop unavailable error message") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } - } - } - - ColumnLayout { - anchors.fill: parent - spacing: 0 - visible: DgopService.dgopAvailable - - Item { - Layout.fillWidth: true - Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 3.4) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "analytics" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("System Monitor") - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: processListModal.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: processListModal.hide() - } - } - } - - RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 3.7) - Layout.leftMargin: Theme.spacingL - Layout.rightMargin: Theme.spacingL - spacing: Theme.spacingM - - Row { - spacing: 2 - - Repeater { - model: [ - { - text: I18n.tr("Processes"), - icon: "list_alt" - }, - { - text: I18n.tr("Performance"), - icon: "analytics" - }, - { - text: I18n.tr("Disks"), - icon: "storage" - }, - { - text: I18n.tr("System"), - icon: "computer" - } - ] - - Rectangle { - width: tabRowContent.implicitWidth + Theme.spacingM * 2 - height: Math.round(Theme.fontSizeMedium * 3.1) - radius: Theme.cornerRadius - color: currentTab === index ? Theme.primaryPressed : (tabMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent") - border.color: currentTab === index ? Theme.primary : "transparent" - border.width: currentTab === index ? 1 : 0 - - Row { - id: tabRowContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: modelData.icon - size: Theme.iconSize - 2 - color: currentTab === index ? Theme.primary : Theme.surfaceText - opacity: currentTab === index ? 1 : 0.7 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: currentTab === index ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: tabMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: currentTab = index - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - } - } - } - - Item { - Layout.fillWidth: true - } - - DankButtonGroup { - id: processFilterGroup - model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")] - currentIndex: 0 - checkEnabled: false - buttonHeight: Math.round(Theme.fontSizeSmall * 2.6) - minButtonWidth: 0 - buttonPadding: Theme.spacingS - textSize: Theme.fontSizeSmall - visible: currentTab === 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - switch (index) { - case 0: - processListModal.processFilter = "all"; - return; - case 1: - processListModal.processFilter = "user"; - return; - case 2: - processListModal.processFilter = "system"; - return; - } - } - } - - DankTextField { - id: searchField - Layout.fillWidth: true - Layout.maximumWidth: Math.round(Theme.fontSizeMedium * 18) - Layout.minimumWidth: Theme.fontSizeMedium * 4 - Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 2.8) - placeholderText: I18n.tr("Search processes...", "process search placeholder") - leftIconName: "search" - showClearButton: true - text: searchText - visible: currentTab === 0 - onTextChanged: searchText = text - ignoreUpDownKeys: true - keyForwardTargets: [contentFocusScope] - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.margins: Theme.spacingL - Layout.topMargin: Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.outlineLight - border.width: 1 - clip: true - - Loader { - id: processesTabLoader - anchors.fill: parent - anchors.margins: Theme.spacingS - active: processListModal.visible && currentTab === 0 - visible: currentTab === 0 - sourceComponent: ProcessesView { - searchText: processListModal.searchText - expandedPid: processListModal.expandedPid - processFilter: processListModal.processFilter - contextMenu: processContextMenu - onExpandedPidChanged: processListModal.expandedPid = expandedPid - } - } - - Loader { - id: performanceTabLoader - anchors.fill: parent - anchors.margins: Theme.spacingS - active: processListModal.visible && currentTab === 1 - visible: currentTab === 1 - sourceComponent: PerformanceView {} - } - - Loader { - id: disksTabLoader - anchors.fill: parent - anchors.margins: Theme.spacingS - active: processListModal.visible && currentTab === 2 - visible: currentTab === 2 - sourceComponent: DisksView {} - } - - Loader { - id: systemTabLoader - anchors.fill: parent - anchors.margins: Theme.spacingS - active: processListModal.visible && currentTab === 3 - visible: currentTab === 3 - sourceComponent: SystemView {} - } - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: Math.round(Theme.fontSizeSmall * 2.7) - Layout.leftMargin: Theme.spacingL - Layout.rightMargin: Theme.spacingL - Layout.bottomMargin: Theme.spacingM - color: "transparent" - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - Row { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Processes:", "process count label in footer") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: DgopService.processCount.toString() - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Uptime:", "uptime label in footer") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: DgopService.shortUptime || "--" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.surfaceText - } - } - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "swap_horiz" - size: 14 - color: Theme.info - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "↓" + formatBytes(DgopService.networkRxRate) + " ↑" + formatBytes(DgopService.networkTxRate) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "storage" - size: 14 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "↓" + formatBytes(DgopService.diskReadRate) + " ↑" + formatBytes(DgopService.diskWriteRate) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "memory" - size: 14 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.cpuUsage.toFixed(1) + "%" - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: DgopService.cpuUsage > 80 ? Theme.error : Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "sd_card" - size: 14 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.formatSystemMemory(DgopService.usedMemoryKB) + " / " + DgopService.formatSystemMemory(DgopService.totalMemoryKB) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: DgopService.memoryUsage > 90 ? Theme.error : Theme.surfaceText - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: processListModal - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/ProfileSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/ProfileSection.qml deleted file mode 100644 index 29b4961..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/ProfileSection.qml +++ /dev/null @@ -1,144 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var parentModal: null - - width: parent.width - Theme.spacingS * 2 - height: 110 - radius: Theme.cornerRadius - color: "transparent" - border.width: 0 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - Item { - id: profileImageContainer - - width: 80 - height: 80 - anchors.verticalCenter: parent.verticalCenter - - DankCircularImage { - id: profileImage - - anchors.fill: parent - imageSource: { - if (PortalService.profileImage === "") { - return ""; - } - if (PortalService.profileImage.startsWith("/")) { - return "file://" + PortalService.profileImage; - } - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Rectangle { - anchors.fill: parent - radius: width / 2 - color: Qt.rgba(0, 0, 0, 0.7) - visible: profileMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "edit" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: () => { - if (root.parentModal) { - root.parentModal.allowFocusOverride = true; - root.parentModal.shouldHaveFocus = false; - root.parentModal.openProfileBrowser(); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - visible: profileImage.hasImage - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: () => { - return PortalService.setProfileImage(""); - } - } - } - } - } - - MouseArea { - id: profileMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - Column { - width: 120 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: UserInfoService.fullName || "User" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: DgopService.hostname || "DMS" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsContent.qml deleted file mode 100644 index 34cd51a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsContent.qml +++ /dev/null @@ -1,522 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Settings - -FocusScope { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int currentIndex: 0 - property var parentModal: null - - focus: true - - Rectangle { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: (parentModal && parentModal.isCompactMode) ? Theme.spacingS : (32 + Theme.spacingS) - anchors.bottomMargin: 0 - anchors.topMargin: 0 - color: "transparent" - - Loader { - id: wallpaperLoader - anchors.fill: parent - active: root.currentIndex === 0 - visible: active - focus: active - - sourceComponent: Component { - WallpaperTab { - parentModal: root.parentModal - } - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: timeWeatherLoader - anchors.fill: parent - active: root.currentIndex === 1 - visible: active - focus: active - - sourceComponent: TimeWeatherTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: keybindsLoader - anchors.fill: parent - active: root.currentIndex === 2 - visible: active - focus: active - - sourceComponent: KeybindsTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: topBarLoader - anchors.fill: parent - active: root.currentIndex === 3 - visible: active - focus: active - - sourceComponent: DankBarTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: workspacesLoader - anchors.fill: parent - active: root.currentIndex === 4 - visible: active - focus: active - - sourceComponent: WorkspacesTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: dockLoader - anchors.fill: parent - active: root.currentIndex === 5 - visible: active - focus: active - - sourceComponent: Component { - DockTab {} - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: displayConfigLoader - anchors.fill: parent - active: root.currentIndex === 24 - visible: active - focus: active - - sourceComponent: DisplayConfigTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: gammaControlLoader - anchors.fill: parent - active: root.currentIndex === 25 - visible: active - focus: active - - sourceComponent: GammaControlTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: displayWidgetsLoader - anchors.fill: parent - active: root.currentIndex === 26 - visible: active - focus: active - - sourceComponent: DisplayWidgetsTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: networkLoader - anchors.fill: parent - active: root.currentIndex === 7 - visible: active - focus: active - - sourceComponent: NetworkTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: printerLoader - anchors.fill: parent - active: root.currentIndex === 8 - visible: active - focus: active - - sourceComponent: PrinterTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: launcherLoader - anchors.fill: parent - active: root.currentIndex === 9 - visible: active - focus: active - - sourceComponent: LauncherTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: themeColorsLoader - anchors.fill: parent - active: root.currentIndex === 10 - visible: active - focus: active - - sourceComponent: ThemeColorsTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: lockScreenLoader - anchors.fill: parent - active: root.currentIndex === 11 - visible: active - focus: active - - sourceComponent: LockScreenTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: greeterLoader - anchors.fill: parent - active: root.currentIndex === 31 - visible: active - focus: active - - sourceComponent: GreeterTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: pluginsLoader - anchors.fill: parent - active: root.currentIndex === 12 - visible: active - focus: active - - sourceComponent: PluginsTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: aboutLoader - anchors.fill: parent - active: root.currentIndex === 13 - visible: active - focus: active - - sourceComponent: AboutTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: typographyMotionLoader - anchors.fill: parent - active: root.currentIndex === 14 - visible: active - focus: active - - sourceComponent: TypographyMotionTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: soundsLoader - anchors.fill: parent - active: root.currentIndex === 15 - visible: active - focus: active - - sourceComponent: SoundsTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: mediaPlayerLoader - anchors.fill: parent - active: root.currentIndex === 16 - visible: active - focus: active - - sourceComponent: MediaPlayerTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: notificationsLoader - anchors.fill: parent - active: root.currentIndex === 17 - visible: active - focus: active - - sourceComponent: NotificationsTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: osdLoader - anchors.fill: parent - active: root.currentIndex === 18 - visible: active - focus: active - - sourceComponent: OSDTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: runningAppsLoader - anchors.fill: parent - active: root.currentIndex === 19 - visible: active - focus: active - - sourceComponent: RunningAppsTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: systemUpdaterLoader - anchors.fill: parent - active: root.currentIndex === 20 - visible: active - focus: active - - sourceComponent: SystemUpdaterTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: powerSleepLoader - anchors.fill: parent - active: root.currentIndex === 21 - visible: active - focus: active - - sourceComponent: PowerSleepTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: widgetsLoader - anchors.fill: parent - active: root.currentIndex === 22 - visible: active - focus: active - - sourceComponent: WidgetsTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: clipboardLoader - anchors.fill: parent - active: root.currentIndex === 23 - visible: active - focus: active - - sourceComponent: ClipboardTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: desktopWidgetsLoader - anchors.fill: parent - active: root.currentIndex === 27 - visible: active - focus: active - - sourceComponent: DesktopWidgetsTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: windowRulesLoader - anchors.fill: parent - active: root.currentIndex === 28 - visible: active - focus: active - - sourceComponent: WindowRulesTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: audioLoader - anchors.fill: parent - active: root.currentIndex === 29 - visible: active - focus: active - - sourceComponent: AudioTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: localeLoader - anchors.fill: parent - active: root.currentIndex === 30 - visible: active - focus: active - - sourceComponent: LocaleTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - - Loader { - id: muxLoader - anchors.fill: parent - active: root.currentIndex === 32 - visible: active - focus: active - - sourceComponent: MuxTab {} - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsModal.qml deleted file mode 100644 index 9ce9153..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsModal.qml +++ /dev/null @@ -1,382 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -FloatingWindow { - id: settingsModal - - property bool disablePopupTransparency: true - property var profileBrowser: profileBrowserLoader.item - property var wallpaperBrowser: wallpaperBrowserLoader.item - - function openProfileBrowser(allowStacking) { - profileBrowserLoader.active = true; - if (!profileBrowserLoader.item) - return; - if (allowStacking !== undefined) - profileBrowserLoader.item.allowStacking = allowStacking; - profileBrowserLoader.item.open(); - } - - function openWallpaperBrowser(allowStacking) { - wallpaperBrowserLoader.active = true; - if (!wallpaperBrowserLoader.item) - return; - if (allowStacking !== undefined) - wallpaperBrowserLoader.item.allowStacking = allowStacking; - wallpaperBrowserLoader.item.open(); - } - property alias sidebar: sidebar - property int currentTabIndex: 0 - property bool shouldHaveFocus: visible - property bool allowFocusOverride: false - property alias shouldBeVisible: settingsModal.visible - property bool isCompactMode: width < 700 - property bool menuVisible: !isCompactMode - property bool enableAnimations: true - - signal closingModal - - function show() { - visible = true; - } - - function hide() { - visible = false; - } - - function toggle() { - visible = !visible; - } - - function showWithTab(tabIndex: int) { - if (tabIndex >= 0) { - currentTabIndex = tabIndex; - sidebar.autoExpandForTab(tabIndex); - } - visible = true; - } - - function showWithTabName(tabName: string) { - var idx = sidebar.resolveTabIndex(tabName); - if (idx >= 0) { - currentTabIndex = idx; - sidebar.autoExpandForTab(idx); - } - visible = true; - } - - function resolveTabIndex(tabName: string): int { - return sidebar.resolveTabIndex(tabName); - } - - function toggleMenu() { - enableAnimations = true; - menuVisible = !menuVisible; - } - - objectName: "settingsModal" - title: I18n.tr("Settings", "settings window title") - minimumSize: Qt.size(500, 400) - implicitWidth: 900 - implicitHeight: screen ? Math.min(940, screen.height - 100) : 940 - color: Theme.surfaceContainer - visible: false - - onIsCompactModeChanged: { - enableAnimations = false; - if (!isCompactMode) { - menuVisible = true; - } - Qt.callLater(() => { - enableAnimations = true; - }); - } - - onVisibleChanged: { - if (!visible) { - closingModal(); - } else { - Qt.callLater(() => { - sidebar.focusSearch(); - }); - } - } - - Loader { - active: settingsModal.visible - sourceComponent: Component { - Ref { - service: CupsService - } - } - } - - LazyLoader { - id: profileBrowserLoader - active: false - - FileBrowserModal { - id: profileBrowserItem - - allowStacking: true - parentModal: settingsModal - browserTitle: I18n.tr("Select Profile Image", "profile image file browser title") - browserIcon: "person" - browserType: "profile" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - PortalService.setProfileImage(path); - close(); - } - onDialogClosed: () => { - allowStacking = true; - } - } - } - - LazyLoader { - id: wallpaperBrowserLoader - active: false - - FileBrowserModal { - id: wallpaperBrowserItem - - allowStacking: true - parentModal: settingsModal - browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title") - browserIcon: "wallpaper" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - SessionData.setWallpaper(path); - close(); - } - onDialogClosed: () => { - allowStacking = true; - } - } - } - - FocusScope { - id: contentFocusScope - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - anchors.fill: parent - focus: true - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 48 - z: 10 - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Rectangle { - anchors.fill: parent - color: Theme.surfaceContainer - opacity: 0.5 - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankActionButton { - visible: settingsModal.isCompactMode - circular: false - iconName: "menu" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - onClicked: () => { - settingsModal.toggleMenu(); - } - } - - DankIcon { - name: "settings" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Settings") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.top: parent.top - anchors.topMargin: Theme.spacingM - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: settingsModal.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: settingsModal.hide() - } - } - } - - Rectangle { - id: readOnlyBanner - - property bool showBanner: (SettingsData._isReadOnly && SettingsData._hasUnsavedChanges) || (SessionData._isReadOnly && SessionData._hasUnsavedChanges) - - width: parent.width - height: showBanner ? bannerContent.implicitHeight + Theme.spacingM * 2 : 0 - color: Theme.surfaceContainerHigh - visible: showBanner - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: bannerContent - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: bannerText - - text: I18n.tr("Settings are read-only. Changes will not persist.", "read-only settings warning for NixOS home-manager users") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: Math.max(100, parent.width - (copySettingsButton.visible ? copySettingsButton.width + Theme.spacingM : 0) - (copySessionButton.visible ? copySessionButton.width + Theme.spacingM : 0) - Theme.spacingM * 2 - Theme.iconSize) - wrapMode: Text.WordWrap - } - - DankButton { - id: copySettingsButton - - visible: SettingsData._isReadOnly && SettingsData._hasUnsavedChanges - text: "settings.json" - iconName: "content_copy" - backgroundColor: Theme.primary - textColor: Theme.primaryText - buttonHeight: 32 - horizontalPadding: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", SettingsData.getCurrentSettingsJson()]); - ToastService.showInfo(I18n.tr("Copied to clipboard")); - } - } - - DankButton { - id: copySessionButton - - visible: SessionData._isReadOnly && SessionData._hasUnsavedChanges - text: "session.json" - iconName: "content_copy" - backgroundColor: Theme.primary - textColor: Theme.primaryText - buttonHeight: 32 - horizontalPadding: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", SessionData.getCurrentSessionJson()]); - ToastService.showInfo(I18n.tr("Copied to clipboard")); - } - } - } - } - - Item { - width: parent.width - height: parent.height - 48 - readOnlyBanner.height - clip: true - - SettingsSidebar { - id: sidebar - - anchors.left: parent.left - width: settingsModal.isCompactMode ? parent.width : sidebar.implicitWidth - visible: settingsModal.isCompactMode ? settingsModal.menuVisible : true - parentModal: settingsModal - currentIndex: settingsModal.currentTabIndex - onTabChangeRequested: tabIndex => { - settingsModal.currentTabIndex = tabIndex; - if (settingsModal.isCompactMode) { - settingsModal.enableAnimations = true; - settingsModal.menuVisible = false; - } - } - } - - Item { - anchors.left: settingsModal.isCompactMode ? (settingsModal.menuVisible ? sidebar.right : parent.left) : sidebar.right - anchors.right: parent.right - height: parent.height - clip: true - - SettingsContent { - id: content - - anchors.fill: parent - parentModal: settingsModal - currentIndex: settingsModal.currentTabIndex - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: settingsModal - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml deleted file mode 100644 index 092881c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml +++ /dev/null @@ -1,1023 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Modals.Settings -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int currentIndex: 0 - property var parentModal: null - - signal tabChangeRequested(int tabIndex) - property string _expandedIds: "," - property string _collapsedIds: "," - property string _autoExpandedIds: "," - property bool searchActive: searchField.text.length > 0 - property int searchSelectedIndex: 0 - property int keyboardHighlightIndex: -1 - - function focusSearch() { - searchField.forceActiveFocus(); - } - - function highlightNext() { - var flatItems = getFlatNavigableItems(); - if (flatItems.length === 0) - return; - var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex); - if (currentPos === -1) { - currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); - } - var nextPos = (currentPos + 1) % flatItems.length; - keyboardHighlightIndex = flatItems[nextPos].tabIndex; - autoExpandForTab(keyboardHighlightIndex); - } - - function highlightPrevious() { - var flatItems = getFlatNavigableItems(); - if (flatItems.length === 0) - return; - var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex); - if (currentPos === -1) { - currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); - } - var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length; - keyboardHighlightIndex = flatItems[prevPos].tabIndex; - autoExpandForTab(keyboardHighlightIndex); - } - - function selectHighlighted() { - if (keyboardHighlightIndex < 0) - return; - var oldIndex = currentIndex; - var newIndex = keyboardHighlightIndex; - tabChangeRequested(newIndex); - autoCollapseIfNeeded(oldIndex, newIndex); - keyboardHighlightIndex = -1; - Qt.callLater(searchField.forceActiveFocus); - } - - readonly property var categoryStructure: [ - { - "id": "personalization", - "text": I18n.tr("Personalization"), - "icon": "palette", - "children": [ - { - "id": "wallpaper", - "text": I18n.tr("Wallpaper"), - "icon": "wallpaper", - "tabIndex": 0 - }, - { - "id": "theme", - "text": I18n.tr("Theme & Colors"), - "icon": "format_paint", - "tabIndex": 10 - }, - { - "id": "typography", - "text": I18n.tr("Typography & Motion"), - "icon": "text_fields", - "tabIndex": 14 - }, - { - "id": "time_weather", - "text": I18n.tr("Time & Weather"), - "icon": "schedule", - "tabIndex": 1 - }, - { - "id": "sounds", - "text": I18n.tr("Sounds"), - "icon": "volume_up", - "tabIndex": 15, - "soundsOnly": true - } - ] - }, - { - "id": "dankbar", - "text": I18n.tr("Dank Bar"), - "icon": "toolbar", - "children": [ - { - "id": "dankbar_settings", - "text": I18n.tr("Settings"), - "icon": "tune", - "tabIndex": 3 - }, - { - "id": "dankbar_widgets", - "text": I18n.tr("Widgets"), - "icon": "widgets", - "tabIndex": 22 - } - ] - }, - { - "id": "workspaces_widgets", - "text": I18n.tr("Workspaces & Widgets"), - "icon": "dashboard", - "collapsedByDefault": true, - "children": [ - { - "id": "workspaces", - "text": I18n.tr("Workspaces"), - "icon": "view_module", - "tabIndex": 4 - }, - { - "id": "media_player", - "text": I18n.tr("Media Player"), - "icon": "music_note", - "tabIndex": 16 - }, - { - "id": "notifications", - "text": I18n.tr("Notifications"), - "icon": "notifications", - "tabIndex": 17 - }, - { - "id": "osd", - "text": I18n.tr("On-screen Displays"), - "icon": "tune", - "tabIndex": 18 - }, - { - "id": "running_apps", - "text": I18n.tr("Running Apps"), - "icon": "app_registration", - "tabIndex": 19, - "hyprlandNiriOnly": true - }, - { - "id": "updater", - "text": I18n.tr("System Updater"), - "icon": "refresh", - "tabIndex": 20 - }, - { - "id": "desktop_widgets", - "text": I18n.tr("Desktop Widgets"), - "icon": "widgets", - "tabIndex": 27 - } - ] - }, - { - "id": "dock_launcher", - "text": I18n.tr("Dock & Launcher"), - "icon": "apps", - "collapsedByDefault": true, - "children": [ - { - "id": "dock", - "text": I18n.tr("Dock"), - "icon": "dock_to_bottom", - "tabIndex": 5 - }, - { - "id": "launcher", - "text": I18n.tr("Launcher"), - "icon": "grid_view", - "tabIndex": 9 - } - ] - }, - { - "id": "keybinds", - "text": I18n.tr("Keyboard Shortcuts"), - "icon": "keyboard", - "tabIndex": 2, - "shortcutsOnly": true - }, - { - "id": "displays", - "text": I18n.tr("Displays"), - "icon": "monitor", - "collapsedByDefault": true, - "children": [ - { - "id": "display_config", - "text": I18n.tr("Configuration"), - "icon": "display_settings", - "tabIndex": 24 - }, - { - "id": "display_gamma", - "text": I18n.tr("Gamma Control"), - "icon": "brightness_6", - "tabIndex": 25 - }, - { - "id": "display_widgets", - "text": I18n.tr("Widgets", "settings_displays"), - "icon": "widgets", - "tabIndex": 26 - } - ] - }, - { - "id": "network", - "text": I18n.tr("Network"), - "icon": "wifi", - "tabIndex": 7, - "dmsOnly": true - }, - { - "id": "system", - "text": I18n.tr("System"), - "icon": "memory", - "collapsedByDefault": true, - "children": [ - { - "id": "audio", - "text": I18n.tr("Audio"), - "icon": "headphones", - "tabIndex": 29 - }, - { - "id": "locale", - "text": I18n.tr("Locale"), - "icon": "language", - "tabIndex": 30 - }, - { - "id": "clipboard", - "text": I18n.tr("Clipboard"), - "icon": "content_paste", - "tabIndex": 23, - "clipboardOnly": true - }, - { - "id": "printers", - "text": I18n.tr("Printers"), - "icon": "print", - "tabIndex": 8, - "cupsOnly": true - }, - { - "id": "multiplexers", - "text": I18n.tr("Multiplexers"), - "icon": "terminal", - "tabIndex": 32 - }, - { - "id": "window_rules", - "text": I18n.tr("Window Rules"), - "icon": "select_window", - "tabIndex": 28, - "niriOnly": true - } - ] - }, - { - "id": "power_security", - "text": I18n.tr("Power & Security"), - "icon": "security", - "collapsedByDefault": true, - "children": [ - { - "id": "lock_screen", - "text": I18n.tr("Lock Screen"), - "icon": "lock", - "tabIndex": 11 - }, - { - "id": "greeter", - "text": I18n.tr("Greeter"), - "icon": "login", - "tabIndex": 31 - }, - { - "id": "power_sleep", - "text": I18n.tr("Power & Sleep"), - "icon": "power_settings_new", - "tabIndex": 21 - } - ] - }, - { - "id": "plugins", - "text": I18n.tr("Plugins"), - "icon": "extension", - "tabIndex": 12 - }, - { - "id": "separator", - "separator": true - }, - { - "id": "about", - "text": I18n.tr("About"), - "icon": "info", - "tabIndex": 13 - } - ] - - function isItemVisible(item) { - if (item.dmsOnly && NetworkService.usingLegacy) - return false; - if (item.cupsOnly && !CupsService.cupsAvailable) - return false; - if (item.shortcutsOnly && !KeybindsService.available) - return false; - if (item.soundsOnly && !AudioService.soundsAvailable) - return false; - if (item.hyprlandNiriOnly && !CompositorService.isNiri && !CompositorService.isHyprland) - return false; - if (item.niriOnly && !CompositorService.isNiri) - return false; - if (item.clipboardOnly && (!DMSService.isConnected || DMSService.apiVersion < 23)) - return false; - return true; - } - - function hasVisibleChildren(category) { - if (!category.children) - return false; - return category.children.some(child => isItemVisible(child)); - } - - function isCategoryVisible(category) { - if (category.separator) - return true; - if (!isItemVisible(category)) - return false; - if (category.children && !hasVisibleChildren(category)) - return false; - return true; - } - - function _setExpanded(id, expanded) { - var marker = "," + id + ","; - if (expanded) { - if (_expandedIds.indexOf(marker) < 0) - _expandedIds = _expandedIds + id + ","; - _collapsedIds = _collapsedIds.replace(marker, ","); - } else { - _expandedIds = _expandedIds.replace(marker, ","); - if (_collapsedIds.indexOf(marker) < 0) - _collapsedIds = _collapsedIds + id + ","; - } - SessionData.setSettingsSidebarState(_expandedIds, _collapsedIds); - } - - function _setAutoExpanded(id, value) { - var marker = "," + id + ","; - if (value) { - if (_autoExpandedIds.indexOf(marker) < 0) - _autoExpandedIds = _autoExpandedIds + id + ","; - } else { - _autoExpandedIds = _autoExpandedIds.replace(marker, ","); - } - } - - function _isAutoExpanded(id) { - return _autoExpandedIds.indexOf("," + id + ",") >= 0; - } - - function toggleCategory(categoryId) { - _setExpanded(categoryId, !isCategoryExpanded(categoryId)); - _setAutoExpanded(categoryId, false); - } - - function isCategoryExpanded(categoryId) { - if (_collapsedIds.indexOf("," + categoryId + ",") >= 0) - return false; - if (_expandedIds.indexOf("," + categoryId + ",") >= 0) - return true; - var category = categoryStructure.find(cat => cat.id === categoryId); - if (category && category.collapsedByDefault) - return false; - return true; - } - - function isChildActive(category) { - if (!category.children) - return false; - return category.children.some(child => child.tabIndex === currentIndex); - } - - function findParentCategory(tabIndex) { - for (var i = 0; i < categoryStructure.length; i++) { - var cat = categoryStructure[i]; - if (cat.children) { - for (var j = 0; j < cat.children.length; j++) { - if (cat.children[j].tabIndex === tabIndex) { - return cat; - } - } - } - } - return null; - } - - function autoExpandForTab(tabIndex) { - var parent = findParentCategory(tabIndex); - if (!parent) - return; - - if (!isCategoryExpanded(parent.id)) { - _setExpanded(parent.id, true); - _setAutoExpanded(parent.id, true); - } - } - - function autoCollapseIfNeeded(oldTabIndex, newTabIndex) { - var oldParent = findParentCategory(oldTabIndex); - var newParent = findParentCategory(newTabIndex); - - if (oldParent && oldParent !== newParent && _isAutoExpanded(oldParent.id)) { - _setExpanded(oldParent.id, false); - _setAutoExpanded(oldParent.id, false); - } - } - - function navigateNext() { - var flatItems = getFlatNavigableItems(); - var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); - var oldIndex = currentIndex; - var newIndex; - if (currentPos === -1) { - newIndex = flatItems[0]?.tabIndex ?? 0; - } else { - var nextPos = (currentPos + 1) % flatItems.length; - newIndex = flatItems[nextPos].tabIndex; - } - tabChangeRequested(newIndex); - autoCollapseIfNeeded(oldIndex, newIndex); - autoExpandForTab(newIndex); - } - - function navigatePrevious() { - var flatItems = getFlatNavigableItems(); - var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); - var oldIndex = currentIndex; - var newIndex; - if (currentPos === -1) { - newIndex = flatItems[0]?.tabIndex ?? 0; - } else { - var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length; - newIndex = flatItems[prevPos].tabIndex; - } - tabChangeRequested(newIndex); - autoCollapseIfNeeded(oldIndex, newIndex); - autoExpandForTab(newIndex); - } - - function getFlatNavigableItems() { - var items = []; - for (var i = 0; i < categoryStructure.length; i++) { - var cat = categoryStructure[i]; - if (cat.separator || !isCategoryVisible(cat)) - continue; - - if (cat.tabIndex !== undefined && !cat.children) { - items.push(cat); - } - - if (cat.children) { - for (var j = 0; j < cat.children.length; j++) { - var child = cat.children[j]; - if (isItemVisible(child)) { - items.push(child); - } - } - } - } - return items; - } - - function resolveTabIndex(name: string): int { - if (!name) - return -1; - - var normalized = name.toLowerCase().replace(/[_\-\s]/g, ""); - - for (var i = 0; i < categoryStructure.length; i++) { - var cat = categoryStructure[i]; - if (cat.separator) - continue; - - var catId = (cat.id || "").toLowerCase().replace(/[_\-\s]/g, ""); - if (catId === normalized) { - if (cat.tabIndex !== undefined) - return cat.tabIndex; - if (cat.children && cat.children.length > 0) - return cat.children[0].tabIndex; - } - - if (cat.children) { - for (var j = 0; j < cat.children.length; j++) { - var child = cat.children[j]; - var childId = (child.id || "").toLowerCase().replace(/[_\-\s]/g, ""); - if (childId === normalized) - return child.tabIndex; - } - } - } - return -1; - } - - property real __maxTextWidth: Math.max(__m1.advanceWidth, __m2.advanceWidth, __m3.advanceWidth, __m4.advanceWidth, __m5.advanceWidth, __m6.advanceWidth) - property real __calculatedWidth: Math.max(270, __maxTextWidth + Theme.iconSize * 2 + Theme.spacingM * 4 + Theme.spacingS * 2) - - implicitWidth: __calculatedWidth - width: __calculatedWidth - height: parent.height - color: Theme.surfaceContainer - radius: Theme.cornerRadius - - Component.onCompleted: { - root._expandedIds = SessionData.settingsSidebarExpandedIds; - root._collapsedIds = SessionData.settingsSidebarCollapsedIds; - } - - StyledTextMetrics { - id: __m1 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Workspaces & Widgets") - } - StyledTextMetrics { - id: __m2 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Typography & Motion") - } - StyledTextMetrics { - id: __m3 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Keyboard Shortcuts") - } - StyledTextMetrics { - id: __m4 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Power & Security") - } - StyledTextMetrics { - id: __m5 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Dock & Launcher") - } - StyledTextMetrics { - id: __m6 - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - text: I18n.tr("Personalization") - } - - function selectSearchResult(result) { - if (!result) - return; - if (result.section) { - SettingsSearchService.navigateToSection(result.section); - } - var oldIndex = root.currentIndex; - tabChangeRequested(result.tabIndex); - autoCollapseIfNeeded(oldIndex, result.tabIndex); - autoExpandForTab(result.tabIndex); - searchField.text = ""; - SettingsSearchService.clear(); - searchSelectedIndex = 0; - keyboardHighlightIndex = -1; - Qt.callLater(searchField.forceActiveFocus); - } - - function navigateSearchResults(delta) { - if (SettingsSearchService.results.length === 0) - return; - searchSelectedIndex = Math.max(0, Math.min(searchSelectedIndex + delta, SettingsSearchService.results.length - 1)); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: sidebarColumn.height - - Column { - id: sidebarColumn - width: parent.width - leftPadding: Theme.spacingS - rightPadding: Theme.spacingS - bottomPadding: Theme.spacingL - topPadding: Theme.spacingM + 2 - spacing: 2 - - ProfileSection { - width: parent.width - parent.leftPadding - parent.rightPadding - parentModal: root.parentModal - } - - Rectangle { - width: parent.width - parent.leftPadding - parent.rightPadding - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Item { - width: parent.width - parent.leftPadding - parent.rightPadding - height: Theme.spacingXS - } - - DankTextField { - id: searchField - width: parent.width - parent.leftPadding - parent.rightPadding - placeholderText: I18n.tr("Search...") - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - 4 - showClearButton: text.length > 0 - usePopupTransparency: false - onTextChanged: { - SettingsSearchService.search(text); - root.searchSelectedIndex = 0; - } - keyForwardTargets: [keyHandler] - - Item { - id: keyHandler - function navNext() { - if (root.searchActive) { - root.navigateSearchResults(1); - } else { - root.highlightNext(); - } - } - function navPrev() { - if (root.searchActive) { - root.navigateSearchResults(-1); - } else { - root.highlightPrevious(); - } - } - function navSelect() { - if (root.searchActive && SettingsSearchService.results.length > 0) { - root.selectSearchResult(SettingsSearchService.results[root.searchSelectedIndex]); - } else if (root.keyboardHighlightIndex >= 0) { - root.selectHighlighted(); - } - } - Keys.onDownPressed: event => { - navNext(); - event.accepted = true; - } - Keys.onUpPressed: event => { - navPrev(); - event.accepted = true; - } - Keys.onTabPressed: event => { - navNext(); - event.accepted = true; - } - Keys.onBacktabPressed: event => { - navPrev(); - event.accepted = true; - } - Keys.onReturnPressed: event => { - navSelect(); - event.accepted = true; - } - Keys.onEscapePressed: event => { - if (root.searchActive) { - searchField.text = ""; - SettingsSearchService.clear(); - } else { - root.keyboardHighlightIndex = -1; - } - event.accepted = true; - } - } - } - - Column { - id: searchResultsColumn - width: parent.width - parent.leftPadding - parent.rightPadding - spacing: 2 - visible: root.searchActive - - Item { - width: parent.width - height: Theme.spacingS - } - - Repeater { - model: ScriptModel { - values: SettingsSearchService.results - } - - Rectangle { - id: resultDelegate - required property int index - required property var modelData - - width: searchResultsColumn.width - height: resultContent.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: { - if (root.searchSelectedIndex === index) - return Theme.buttonBg; - if (resultMouseArea.containsMouse) - return Theme.surfaceHover; - return "transparent"; - } - - DankRipple { - id: resultRipple - rippleColor: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText - cornerRadius: resultDelegate.radius - } - - Row { - id: resultContent - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: resultDelegate.modelData.icon || "settings" - size: Theme.iconSize - 2 - color: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: resultDelegate.modelData.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText - width: parent.width - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: resultDelegate.modelData.category - font.pixelSize: Theme.fontSizeSmall - 1 - color: root.searchSelectedIndex === resultDelegate.index ? Theme.withAlpha(Theme.buttonText, 0.7) : Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignLeft - } - } - } - - MouseArea { - id: resultMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => resultRipple.trigger(mouse.x, mouse.y) - onClicked: root.selectSearchResult(resultDelegate.modelData) - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No matches") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: searchField.text.length > 0 && SettingsSearchService.results.length === 0 - topPadding: Theme.spacingM - } - } - - Item { - width: parent.width - parent.leftPadding - parent.rightPadding - height: Theme.spacingXS - visible: !root.searchActive - } - - Repeater { - model: root.categoryStructure - - delegate: Column { - id: categoryDelegate - required property int index - required property var modelData - - width: parent.width - parent.leftPadding - parent.rightPadding - visible: !root.searchActive && root.isCategoryVisible(modelData) - spacing: 2 - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: categoryDelegate.modelData.separator === true - } - - Item { - width: parent.width - height: Theme.spacingS - visible: categoryDelegate.modelData.separator === true - } - - Rectangle { - id: categoryRow - width: parent.width - height: Math.max(Theme.iconSize, Theme.fontSizeMedium) + Theme.spacingS * 2 - radius: Theme.cornerRadius - visible: categoryDelegate.modelData.separator !== true - - readonly property bool hasTab: categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children - readonly property bool isActive: hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex - readonly property bool isHighlighted: hasTab && root.keyboardHighlightIndex === categoryDelegate.modelData.tabIndex - - color: { - if (isActive) - return Theme.buttonBg; - if (isHighlighted) - return Theme.buttonHover; - if (categoryMouseArea.containsMouse) - return Theme.surfaceHover; - return "transparent"; - } - - DankRipple { - id: categoryRipple - rippleColor: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText - cornerRadius: categoryRow.radius - } - - Row { - id: categoryRowContent - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: categoryDelegate.modelData.icon || "" - size: Theme.iconSize - 2 - color: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: categoryDelegate.modelData.text || "" - font.pixelSize: Theme.fontSizeMedium - font.weight: (categoryRow.isActive || root.isChildActive(categoryDelegate.modelData)) ? Font.Medium : Font.Normal - color: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - id: expandIcon - name: root.isCategoryExpanded(categoryDelegate.modelData.id) ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: categoryDelegate.modelData.children !== undefined && categoryDelegate.modelData.children.length > 0 - } - - MouseArea { - id: categoryMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => categoryRipple.trigger(mouse.x, mouse.y) - onClicked: { - root.keyboardHighlightIndex = -1; - if (categoryDelegate.modelData.children) { - root.toggleCategory(categoryDelegate.modelData.id); - } else if (categoryDelegate.modelData.tabIndex !== undefined) { - root.tabChangeRequested(categoryDelegate.modelData.tabIndex); - } - Qt.callLater(searchField.forceActiveFocus); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Column { - id: childrenColumn - width: parent.width - spacing: 2 - visible: categoryDelegate.modelData.children !== undefined && root.isCategoryExpanded(categoryDelegate.modelData.id) - clip: true - - Repeater { - model: categoryDelegate.modelData.children || [] - - delegate: Rectangle { - id: childDelegate - required property int index - required property var modelData - - readonly property bool isActive: root.currentIndex === modelData.tabIndex - readonly property bool isHighlighted: root.keyboardHighlightIndex === modelData.tabIndex - - width: childrenColumn.width - height: Math.max(Theme.iconSize - 4, Theme.fontSizeSmall + 1) + Theme.spacingS * 2 - radius: Theme.cornerRadius - visible: root.isItemVisible(modelData) - color: { - if (isActive) - return Theme.buttonBg; - if (isHighlighted) - return Theme.buttonHover; - if (childMouseArea.containsMouse) - return Theme.surfaceHover; - return "transparent"; - } - - DankRipple { - id: childRipple - rippleColor: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText - cornerRadius: childDelegate.radius - } - - Row { - id: childRowContent - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: childDelegate.modelData.icon || "" - size: Theme.iconSize - 4 - color: childDelegate.isActive ? Theme.buttonText : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: childDelegate.modelData.text || "" - font.pixelSize: Theme.fontSizeSmall + 1 - font.weight: childDelegate.isActive ? Font.Medium : Font.Normal - color: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: childMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => childRipple.trigger(mouse.x, mouse.y) - onClicked: { - root.keyboardHighlightIndex = -1; - root.tabChangeRequested(childDelegate.modelData.tabIndex); - Qt.callLater(searchField.forceActiveFocus); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiPasswordModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiPasswordModal.qml deleted file mode 100644 index 92689f2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiPasswordModal.qml +++ /dev/null @@ -1,764 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property string wifiPasswordSSID: "" - property string wifiPasswordInput: "" - property string wifiUsernameInput: "" - property bool requiresEnterprise: false - property bool isHiddenNetwork: false - - property string wifiAnonymousIdentityInput: "" - property string wifiDomainInput: "" - - property bool isPromptMode: false - property string promptToken: "" - property string promptReason: "" - property var promptFields: [] - property string promptSetting: "" - - property bool isVpnPrompt: false - property string connectionName: "" - property string vpnServiceType: "" - property string connectionType: "" - property var fieldsInfo: [] - property var secretValues: ({}) - - readonly property bool showUsernameField: requiresEnterprise && !isVpnPrompt && fieldsInfo.length === 0 - readonly property bool showPasswordField: fieldsInfo.length === 0 - readonly property bool showAnonField: requiresEnterprise && !isVpnPrompt - readonly property bool showDomainField: requiresEnterprise && !isVpnPrompt - readonly property bool showSavePasswordCheckbox: (isVpnPrompt || fieldsInfo.length > 0) && promptReason !== "pkcs11" - - readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 - readonly property int inputFieldWithSpacing: inputFieldHeight + Theme.spacingM - readonly property int checkboxRowHeight: Theme.fontSizeMedium + Theme.spacingS - readonly property int headerHeight: Theme.fontSizeLarge + Theme.fontSizeMedium + Theme.spacingM * 2 - readonly property int buttonRowHeight: 36 + Theme.spacingM - - property int calculatedHeight: { - let h = headerHeight + buttonRowHeight + Theme.spacingL * 2; - h += fieldsInfo.length * inputFieldWithSpacing; - if (isHiddenNetwork) - h += inputFieldWithSpacing; - if (showUsernameField) - h += inputFieldWithSpacing; - if (showPasswordField) - h += inputFieldWithSpacing; - if (showAnonField) - h += inputFieldWithSpacing; - if (showDomainField) - h += inputFieldWithSpacing; - if (showSavePasswordCheckbox) - h += checkboxRowHeight; - return h; - } - - function focusFirstField() { - if (fieldsInfo.length > 0) { - if (dynamicFieldsRepeater.count > 0) { - const firstItem = dynamicFieldsRepeater.itemAt(0); - if (firstItem) - firstItem.children[0].forceActiveFocus(); - } - return; - } - if (isHiddenNetwork) { - ssidInput.forceActiveFocus(); - return; - } - if (requiresEnterprise && !isVpnPrompt) { - usernameInput.forceActiveFocus(); - return; - } - passwordInput.forceActiveFocus(); - } - - function show(ssid) { - wifiPasswordSSID = ssid; - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - isPromptMode = false; - isHiddenNetwork = false; - promptToken = ""; - promptReason = ""; - promptFields = []; - promptSetting = ""; - isVpnPrompt = false; - connectionName = ""; - vpnServiceType = ""; - connectionType = ""; - fieldsInfo = []; - secretValues = {}; - - const network = NetworkService.wifiNetworks.find(n => n.ssid === ssid); - requiresEnterprise = network?.enterprise || false; - - visible = true; - Qt.callLater(focusFirstField); - } - - function showHidden() { - wifiPasswordSSID = ""; - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - isPromptMode = false; - isHiddenNetwork = true; - promptToken = ""; - promptReason = ""; - promptFields = []; - promptSetting = ""; - isVpnPrompt = false; - connectionName = ""; - vpnServiceType = ""; - connectionType = ""; - fieldsInfo = []; - secretValues = {}; - requiresEnterprise = false; - - visible = true; - Qt.callLater(focusFirstField); - } - - function showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fInfo) { - isPromptMode = true; - promptToken = token; - promptReason = reason; - promptFields = fields || []; - promptSetting = setting || "802-11-wireless-security"; - connectionType = connType || "802-11-wireless"; - connectionName = connName || ssid || ""; - vpnServiceType = vpnService || ""; - fieldsInfo = fInfo || []; - secretValues = {}; - - isVpnPrompt = (connectionType === "vpn" || connectionType === "wireguard"); - wifiPasswordSSID = isVpnPrompt ? connectionName : ssid; - - requiresEnterprise = setting === "802-1x"; - - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - - visible = true; - Qt.callLater(() => { - if (reason === "wrong-password" && fieldsInfo.length === 0) { - passwordInput.text = ""; - } - focusFirstField(); - }); - } - - function hide() { - visible = false; - } - - function getFieldLabel(fieldName) { - switch (fieldName) { - case "username": - case "identity": - return I18n.tr("Username"); - case "password": - return I18n.tr("Password"); - case "cert-pass": - case "certpass": - return I18n.tr("Certificate Password"); - case "private-key-password": - return I18n.tr("Private Key Password"); - case "pin": - case "key_pass": - return I18n.tr("PIN"); - case "psk": - return I18n.tr("Password"); - case "anonymous-identity": - return I18n.tr("Anonymous Identity"); - default: - return fieldName.charAt(0).toUpperCase() + fieldName.slice(1).replace(/-/g, " "); - } - } - - function submitCredentialsAndClose() { - if (fieldsInfo.length > 0) { - NetworkService.submitCredentials(promptToken, secretValues, savePasswordCheckbox.checked); - hide(); - secretValues = {}; - return; - } - - if (isPromptMode) { - const secrets = {}; - if (isVpnPrompt) { - if (passwordInput.text) - secrets["password"] = passwordInput.text; - } else if (promptSetting === "802-11-wireless-security") { - secrets["psk"] = passwordInput.text; - } else if (promptSetting === "802-1x") { - if (usernameInput.text) - secrets["identity"] = usernameInput.text; - if (passwordInput.text) - secrets["password"] = passwordInput.text; - if (wifiAnonymousIdentityInput) - secrets["anonymous-identity"] = wifiAnonymousIdentityInput; - } - NetworkService.submitCredentials(promptToken, secrets, savePasswordCheckbox.checked); - } else { - const ssid = isHiddenNetwork ? ssidInput.text : wifiPasswordSSID; - const username = requiresEnterprise ? usernameInput.text : ""; - NetworkService.connectToWifi(ssid, passwordInput.text, username, wifiAnonymousIdentityInput, wifiDomainInput, isHiddenNetwork); - } - - hide(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - passwordInput.text = ""; - if (requiresEnterprise) - usernameInput.text = ""; - if (isHiddenNetwork) - ssidInput.text = ""; - } - - function clearAndClose() { - if (isPromptMode) - NetworkService.cancelCredentials(promptToken); - hide(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - secretValues = {}; - } - - objectName: "wifiPasswordModal" - title: { - if (promptReason === "pkcs11") - return I18n.tr("Smartcard PIN"); - if (isVpnPrompt) - return I18n.tr("VPN Password"); - if (isHiddenNetwork) - return I18n.tr("Hidden Network"); - return I18n.tr("Wi-Fi Password"); - } - minimumSize: Qt.size(420, calculatedHeight) - maximumSize: Qt.size(420, calculatedHeight) - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - Qt.callLater(focusFirstField); - return; - } - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - secretValues = {}; - passwordInput.text = ""; - usernameInput.text = ""; - anonInput.text = ""; - domainMatchInput.text = ""; - ssidInput.text = ""; - for (var i = 0; i < dynamicFieldsRepeater.count; i++) { - const item = dynamicFieldsRepeater.itemAt(i); - if (item?.children[0]) - item.children[0].text = ""; - } - } - - Connections { - target: NetworkService - - function onPasswordDialogShouldReopenChanged() { - if (!NetworkService.passwordDialogShouldReopen || NetworkService.connectingSSID === "") - return; - wifiPasswordSSID = NetworkService.connectingSSID; - wifiPasswordInput = ""; - visible = true; - NetworkService.passwordDialogShouldReopen = false; - } - } - - FocusScope { - id: contentFocusScope - - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - clearAndClose(); - event.accepted = true; - } - - Column { - id: contentCol - anchors.centerIn: parent - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - Item { - width: contentCol.width - height: Math.max(headerCol.height, buttonRow.height) - - MouseArea { - anchors.left: parent.left - anchors.right: buttonRow.left - anchors.rightMargin: Theme.spacingM - height: headerCol.height - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - - Column { - id: headerCol - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: { - if (promptReason === "pkcs11") - return I18n.tr("Smartcard Authentication"); - if (isVpnPrompt) - return I18n.tr("Connect to VPN"); - if (isHiddenNetwork) - return I18n.tr("Connect to Hidden Network"); - return I18n.tr("Connect to Wi-Fi"); - } - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: { - if (promptReason === "pkcs11") - return I18n.tr("Enter PIN for ") + wifiPasswordSSID; - if (fieldsInfo.length > 0) - return I18n.tr("Enter credentials for ") + wifiPasswordSSID; - if (isVpnPrompt) - return I18n.tr("Enter password for ") + wifiPasswordSSID; - if (isHiddenNetwork) - return I18n.tr("Enter network name and password"); - const prefix = requiresEnterprise ? I18n.tr("Enter credentials for ") : I18n.tr("Enter password for "); - return prefix + wifiPasswordSSID; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - elide: Text.ElideRight - } - - StyledText { - visible: isPromptMode && promptReason === "wrong-password" - text: I18n.tr("Incorrect password") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - width: parent.width - } - } - } - } - - Row { - id: buttonRow - anchors.right: parent.right - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported && windowControls.canMaximize - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: clearAndClose() - } - } - } - - Rectangle { - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: ssidInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: ssidInput.activeFocus ? 2 : 1 - visible: isHiddenNetwork - - MouseArea { - anchors.fill: parent - onClicked: ssidInput.forceActiveFocus() - } - - DankTextField { - id: ssidInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - placeholderText: I18n.tr("Network Name (SSID)") - backgroundColor: "transparent" - enabled: root.visible - keyNavigationTab: passwordInput - onAccepted: passwordInput.forceActiveFocus() - } - } - - Repeater { - id: dynamicFieldsRepeater - model: fieldsInfo - - delegate: Rectangle { - required property var modelData - required property int index - - width: contentCol.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: fieldInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: fieldInput.activeFocus ? 2 : 1 - - DankTextField { - id: fieldInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - showPasswordToggle: modelData.isSecret - echoMode: modelData.isSecret && !passwordVisible ? TextInput.Password : TextInput.Normal - placeholderText: getFieldLabel(modelData.name) - backgroundColor: "transparent" - enabled: root.visible - - Keys.onTabPressed: event => { - if (index < fieldsInfo.length - 1) { - const nextItem = dynamicFieldsRepeater.itemAt(index + 1); - if (nextItem) - nextItem.children[0].forceActiveFocus(); - } else { - const firstItem = dynamicFieldsRepeater.itemAt(0); - if (firstItem) - firstItem.children[0].forceActiveFocus(); - } - event.accepted = true; - } - - Keys.onBacktabPressed: event => { - if (index > 0) { - const prevItem = dynamicFieldsRepeater.itemAt(index - 1); - if (prevItem) - prevItem.children[0].forceActiveFocus(); - } else { - const lastItem = dynamicFieldsRepeater.itemAt(fieldsInfo.length - 1); - if (lastItem) - lastItem.children[0].forceActiveFocus(); - } - event.accepted = true; - } - - onTextEdited: { - let updated = Object.assign({}, root.secretValues); - updated[modelData.name] = text; - root.secretValues = updated; - } - - onAccepted: { - if (index < fieldsInfo.length - 1) { - const nextItem = dynamicFieldsRepeater.itemAt(index + 1); - if (nextItem) - nextItem.children[0].forceActiveFocus(); - return; - } - submitCredentialsAndClose(); - } - } - } - } - - Rectangle { - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: usernameInput.activeFocus ? 2 : 1 - visible: showUsernameField - - MouseArea { - anchors.fill: parent - onClicked: usernameInput.forceActiveFocus() - } - - DankTextField { - id: usernameInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiUsernameInput - placeholderText: I18n.tr("Username") - backgroundColor: "transparent" - enabled: root.visible - keyNavigationTab: passwordInput - keyNavigationBacktab: domainMatchInput - onTextEdited: wifiUsernameInput = text - onAccepted: passwordInput.forceActiveFocus() - } - } - - Rectangle { - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: passwordInput.activeFocus ? 2 : 1 - visible: showPasswordField - - MouseArea { - anchors.fill: parent - onClicked: passwordInput.forceActiveFocus() - } - - DankTextField { - id: passwordInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiPasswordInput - showPasswordToggle: true - echoMode: passwordVisible ? TextInput.Normal : TextInput.Password - placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : "" - backgroundColor: "transparent" - enabled: root.visible - keyNavigationTab: (requiresEnterprise && !isVpnPrompt) ? anonInput : null - keyNavigationBacktab: (requiresEnterprise && !isVpnPrompt) ? usernameInput : null - onTextEdited: wifiPasswordInput = text - onAccepted: { - if (requiresEnterprise && !isVpnPrompt) { - anonInput.forceActiveFocus(); - return; - } - submitCredentialsAndClose(); - } - } - } - - Rectangle { - visible: showAnonField - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: anonInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: anonInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: anonInput.forceActiveFocus() - } - - DankTextField { - id: anonInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiAnonymousIdentityInput - placeholderText: I18n.tr("Anonymous Identity (optional)") - backgroundColor: "transparent" - enabled: root.visible - keyNavigationTab: domainMatchInput - keyNavigationBacktab: passwordInput - onTextEdited: wifiAnonymousIdentityInput = text - onAccepted: domainMatchInput.forceActiveFocus() - } - } - - Rectangle { - visible: showDomainField - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: domainMatchInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: domainMatchInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: domainMatchInput.forceActiveFocus() - } - - DankTextField { - id: domainMatchInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiDomainInput - placeholderText: I18n.tr("Domain (optional)") - backgroundColor: "transparent" - enabled: root.visible - keyNavigationTab: usernameInput - keyNavigationBacktab: anonInput - onTextEdited: wifiDomainInput = text - onAccepted: submitCredentialsAndClose() - } - } - - Row { - spacing: Theme.spacingS - visible: showSavePasswordCheckbox - - Rectangle { - id: savePasswordCheckbox - - property bool checked: !isVpnPrompt - - width: 20 - height: 20 - radius: 4 - color: checked ? Theme.primary : "transparent" - border.color: checked ? Theme.primary : Theme.outlineButton - border.width: 2 - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 12 - color: Theme.background - visible: parent.checked - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked - } - } - - StyledText { - text: I18n.tr("Save password") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - width: parent.width - height: 40 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: cancelText - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: clearAndClose() - } - } - - Rectangle { - width: Math.max(80, connectText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - enabled: { - if (fieldsInfo.length > 0) { - for (var i = 0; i < fieldsInfo.length; i++) { - if (!fieldsInfo[i].isSecret) - continue; - const fieldName = fieldsInfo[i].name; - if (!secretValues[fieldName] || secretValues[fieldName].length === 0) - return false; - } - return true; - } - if (isVpnPrompt) - return passwordInput.text.length > 0; - if (isHiddenNetwork) - return ssidInput.text.length > 0; - return requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0; - } - opacity: enabled ? 1 : 0.5 - - StyledText { - id: connectText - anchors.centerIn: parent - text: I18n.tr("Connect") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: connectArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: submitCredentialsAndClose() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiQRCodeModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiQRCodeModal.qml deleted file mode 100644 index 06ffab7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WifiQRCodeModal.qml +++ /dev/null @@ -1,170 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import QtQuick.Effects -import Quickshell -import Quickshell.Io -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Common -import qs.Services -import qs.Widgets - -DankModal { - id: root - visible: false - layerNamespace: "dms:wifi-qrcode" - - property bool disablePopupTransparency: true - property string wifiSSID: "" - property string themedQrCodePath: "" - property string normalQrCodePath: "" - modalWidth: 420 - modalHeight: 480 - onBackgroundClicked: hide() - onOpened: { - Qt.callLater(() => { - modalFocusScope.forceActiveFocus(); - contentLoader.item.wifiSSID = wifiSSID; - contentLoader.item.themedQrCodePath = themedQrCodePath; - contentLoader.item.saveBrowserLoader = saveBrowserLoader; - }); - } - - function show(ssid) { - wifiSSID = ssid; - fetchNetworkQRCode(ssid); - } - - function hide() { - if (themedQrCodePath !== "") { - deleteQRCodeFile(themedQrCodePath); - } - if (normalQrCodePath !== "") { - deleteQRCodeFile(normalQrCodePath); - } - close(); - } - - function fetchNetworkQRCode(ssid) { - // TODO: Add loading UI? - - DMSService.sendRequest("network.qrcode", { - ssid: ssid - }, response => { - if (response.error) { - ToastService.showError("Failed to fetch network QR code: ", JSON.stringify(response.error)); - } else if (response.result) { - themedQrCodePath = response.result[0]; - normalQrCodePath = response.result[1]; - open(); - } - }); - } - - function deleteQRCodeFile(path) { - DMSService.sendRequest("network.delete-qrcode", { - path: path - }, response => { - if (response.error) { - ToastService.showError(`Failed to remove QR code at ${path}: `, JSON.stringify(response.error)); - } - }) - } - - LazyLoader { - id: saveBrowserLoader - active: false - - FileBrowserSurfaceModal { - id: saveBrowser - - browserTitle: I18n.tr("Save QR Code") - browserIcon: "qr_code" - browserType: "default" - fileExtensions: ["*.png"] - allowStacking: true - saveMode: true - defaultFileName: `${root.wifiSSID ?? "wifi-qrcode"}.png` - onFileSelected: path => { - const cleanPath = decodeURI(path.toString().replace(/^file:\/\//, '')); - const fileName = cleanPath.split('/').pop(); - const fileUrl = "file://" + cleanPath; - - copyQrCodeProcess.exec(["cp", root.normalQrCodePath, cleanPath, "-f"]) - } - - Process { - id: copyQrCodeProcess - stdout: StdioCollector { - onStreamFinished: { - saveBrowser.close(); - } - } - } - } - } - - content: Component { - Item { - id: theItem - property alias themedQrCodePath: qrCodeImg.source - property var saveBrowserLoader: null - property string wifiSSID: "" - anchors.fill: parent - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - RowLayout { - id: modalTitle - width: parent.width - - StyledText { - text: I18n.tr("WiFi QR code for ") + theItem.wifiSSID - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Bold - Layout.alignment: Qt.AlignLeft - } - - DankActionButton { - iconName: "save" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: { - saveBrowserLoader.active = true; - if (saveBrowserLoader.item) { - saveBrowserLoader.item.open(); - } - } - Layout.alignment: Qt.AlignRight - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - Layout.alignment: Qt.AlignRight - } - } - - Image { - id: qrCodeImg - height: parent.height - parent.spacing - modalTitle.height - width: height - anchors.horizontalCenter: parent.horizontalCenter - - MultiEffect { - source: qrCodeImg - anchors.fill: source - colorization: 1.0 - colorizationColor: Theme.primary - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WindowRuleModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WindowRuleModal.qml deleted file mode 100644 index 6c9583a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WindowRuleModal.qml +++ /dev/null @@ -1,1184 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var editingRule: null - property bool isEditMode: editingRule !== null - property bool isNiri: CompositorService.isNiri - property bool isHyprland: CompositorService.isHyprland - property bool submitting: false - property var targetWindow: null - - signal ruleSubmitted - - readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 - readonly property int sectionSpacing: Theme.spacingL - - objectName: "windowRuleModal" - title: isEditMode ? I18n.tr("Edit Window Rule") : I18n.tr("Create Window Rule") - minimumSize: Qt.size(500, 600) - maximumSize: Qt.size(500, 600) - color: Theme.surfaceContainer - visible: false - - function resetForm() { - nameInput.text = ""; - appIdInput.text = ""; - titleInput.text = ""; - opacityEnabled.checked = false; - opacitySlider.value = 100; - floatingToggle.checked = false; - maximizedToggle.checked = false; - maximizedToEdgesToggle.checked = false; - fullscreenToggle.checked = false; - openFocusedToggle.checked = false; - outputInput.text = ""; - workspaceInput.text = ""; - columnWidthInput.text = ""; - windowHeightInput.text = ""; - vrrToggle.checked = false; - blockOutDropdown.currentValue = ""; - columnDisplayDropdown.currentValue = ""; - scrollFactorEnabled.checked = false; - scrollFactorSlider.value = 100; - cornerRadiusEnabled.checked = false; - cornerRadiusSlider.value = 12; - clipToGeometryToggle.checked = false; - tiledStateToggle.checked = false; - drawBorderBgToggle.checked = false; - minWidthInput.text = ""; - maxWidthInput.text = ""; - minHeightInput.text = ""; - maxHeightInput.text = ""; - tileToggle.checked = false; - noFocusToggle.checked = false; - noBorderToggle.checked = false; - noShadowToggle.checked = false; - noDimToggle.checked = false; - noBlurToggle.checked = false; - noAnimToggle.checked = false; - noRoundingToggle.checked = false; - pinToggle.checked = false; - opaqueToggle.checked = false; - sizeInput.text = ""; - moveInput.text = ""; - monitorInput.text = ""; - hyprWorkspaceInput.text = ""; - } - - function show(window) { - editingRule = null; - targetWindow = window || null; - resetForm(); - if (targetWindow) { - nameInput.text = targetWindow.appId || ""; - appIdInput.text = targetWindow.appId ? "^" + targetWindow.appId + "$" : ""; - } - visible = true; - Qt.callLater(() => nameInput.forceActiveFocus()); - } - - function showEdit(rule) { - if (!rule) { - show(); - return; - } - editingRule = rule; - resetForm(); - - nameInput.text = rule.name || ""; - const match = rule.matchCriteria || {}; - appIdInput.text = match.appId || ""; - titleInput.text = match.title || ""; - - const actions = rule.actions || {}; - const hasOpacity = actions.opacity !== undefined && actions.opacity !== null; - opacityEnabled.checked = hasOpacity; - opacitySlider.value = hasOpacity ? Math.round(actions.opacity * 100) : 100; - - floatingToggle.checked = actions.openFloating || false; - maximizedToggle.checked = actions.openMaximized || false; - maximizedToEdgesToggle.checked = actions.openMaximizedToEdges || false; - fullscreenToggle.checked = actions.openFullscreen || false; - - openFocusedToggle.checked = actions.openFocused || false; - - outputInput.text = actions.openOnOutput || ""; - workspaceInput.text = actions.openOnWorkspace || ""; - columnWidthInput.text = actions.defaultColumnWidth || ""; - windowHeightInput.text = actions.defaultWindowHeight || ""; - vrrToggle.checked = actions.variableRefreshRate || false; - - blockOutDropdown.currentValue = actions.blockOutFrom || ""; - columnDisplayDropdown.currentValue = actions.defaultColumnDisplay || ""; - - const hasScrollFactor = actions.scrollFactor !== undefined && actions.scrollFactor !== null; - scrollFactorEnabled.checked = hasScrollFactor; - scrollFactorSlider.value = hasScrollFactor ? Math.round(actions.scrollFactor * 100) : 100; - - const hasCornerRadius = actions.cornerRadius !== undefined && actions.cornerRadius !== null; - cornerRadiusEnabled.checked = hasCornerRadius; - cornerRadiusSlider.value = hasCornerRadius ? actions.cornerRadius : 12; - - clipToGeometryToggle.checked = actions.clipToGeometry || false; - tiledStateToggle.checked = actions.tiledState || false; - - drawBorderBgToggle.checked = actions.drawBorderWithBackground || false; - - minWidthInput.text = actions.minWidth !== undefined ? String(actions.minWidth) : ""; - maxWidthInput.text = actions.maxWidth !== undefined ? String(actions.maxWidth) : ""; - minHeightInput.text = actions.minHeight !== undefined ? String(actions.minHeight) : ""; - maxHeightInput.text = actions.maxHeight !== undefined ? String(actions.maxHeight) : ""; - - tileToggle.checked = actions.tile || false; - noFocusToggle.checked = actions.nofocus || false; - noBorderToggle.checked = actions.noborder || false; - noShadowToggle.checked = actions.noshadow || false; - noDimToggle.checked = actions.nodim || false; - noBlurToggle.checked = actions.noblur || false; - noAnimToggle.checked = actions.noanim || false; - noRoundingToggle.checked = actions.norounding || false; - pinToggle.checked = actions.pin || false; - opaqueToggle.checked = actions.opaque || false; - sizeInput.text = actions.size || ""; - moveInput.text = actions.move || ""; - monitorInput.text = actions.monitor || ""; - hyprWorkspaceInput.text = actions.workspace || ""; - - visible = true; - Qt.callLater(() => nameInput.forceActiveFocus()); - } - - function hide() { - visible = false; - editingRule = null; - targetWindow = null; - } - - function submitAndClose() { - const matchCriteria = {}; - if (appIdInput.text.trim()) - matchCriteria.appId = appIdInput.text.trim(); - if (titleInput.text.trim()) - matchCriteria.title = titleInput.text.trim(); - - const actions = {}; - - if (opacityEnabled.checked) - actions.opacity = opacitySlider.value / 100; - if (floatingToggle.checked) - actions.openFloating = true; - if (maximizedToggle.checked) - actions.openMaximized = true; - if (maximizedToEdgesToggle.checked && isNiri) - actions.openMaximizedToEdges = true; - if (fullscreenToggle.checked) - actions.openFullscreen = true; - if (openFocusedToggle.checked && isNiri) - actions.openFocused = true; - if (outputInput.text.trim()) - actions.openOnOutput = outputInput.text.trim(); - if (workspaceInput.text.trim()) - actions.openOnWorkspace = workspaceInput.text.trim(); - if (columnWidthInput.text.trim() && isNiri) - actions.defaultColumnWidth = columnWidthInput.text.trim(); - if (windowHeightInput.text.trim() && isNiri) - actions.defaultWindowHeight = windowHeightInput.text.trim(); - if (vrrToggle.checked && isNiri) - actions.variableRefreshRate = true; - if (blockOutDropdown.currentValue && isNiri) - actions.blockOutFrom = blockOutDropdown.currentValue; - if (columnDisplayDropdown.currentValue && isNiri) - actions.defaultColumnDisplay = columnDisplayDropdown.currentValue; - if (scrollFactorEnabled.checked && isNiri) - actions.scrollFactor = scrollFactorSlider.value / 100; - if (cornerRadiusEnabled.checked) - actions.cornerRadius = cornerRadiusSlider.value; - if (clipToGeometryToggle.checked && isNiri) - actions.clipToGeometry = true; - if (tiledStateToggle.checked && isNiri) - actions.tiledState = true; - if (drawBorderBgToggle.checked && isNiri) - actions.drawBorderWithBackground = true; - - const minW = parseInt(minWidthInput.text); - const maxW = parseInt(maxWidthInput.text); - const minH = parseInt(minHeightInput.text); - const maxH = parseInt(maxHeightInput.text); - if (!isNaN(minW)) - actions.minWidth = minW; - if (!isNaN(maxW)) - actions.maxWidth = maxW; - if (!isNaN(minH)) - actions.minHeight = minH; - if (!isNaN(maxH)) - actions.maxHeight = maxH; - - if (isHyprland) { - if (tileToggle.checked) - actions.tile = true; - if (noFocusToggle.checked) - actions.nofocus = true; - if (noBorderToggle.checked) - actions.noborder = true; - if (noShadowToggle.checked) - actions.noshadow = true; - if (noDimToggle.checked) - actions.nodim = true; - if (noBlurToggle.checked) - actions.noblur = true; - if (noAnimToggle.checked) - actions.noanim = true; - if (noRoundingToggle.checked) - actions.norounding = true; - if (pinToggle.checked) - actions.pin = true; - if (opaqueToggle.checked) - actions.opaque = true; - if (sizeInput.text.trim()) - actions.size = sizeInput.text.trim(); - if (moveInput.text.trim()) - actions.move = moveInput.text.trim(); - if (monitorInput.text.trim()) - actions.monitor = monitorInput.text.trim(); - if (hyprWorkspaceInput.text.trim()) - actions.workspace = hyprWorkspaceInput.text.trim(); - } - - const name = nameInput.text.trim() || matchCriteria.appId || I18n.tr("Rule"); - const compositor = CompositorService.compositor; - - const ruleData = { - name: name, - matchCriteria: matchCriteria, - actions: actions, - enabled: true - }; - - submitting = true; - - const shouldValidate = CompositorService.isNiri; - - if (isEditMode) { - const ruleJson = JSON.stringify(ruleData); - Proc.runCommand("update-windowrule", ["dms", "config", "windowrules", "update", compositor, editingRule.id, ruleJson], (output, exitCode) => { - root.submitting = false; - if (exitCode !== 0) - return; - if (shouldValidate) - NiriService.validate(); - root.ruleSubmitted(); - root.hide(); - }); - } else { - const ruleJson = JSON.stringify(ruleData); - Proc.runCommand("add-windowrule", ["dms", "config", "windowrules", "add", compositor, ruleJson], (output, exitCode) => { - root.submitting = false; - if (exitCode !== 0) - return; - if (shouldValidate) - NiriService.validate(); - root.ruleSubmitted(); - root.hide(); - }); - } - } - - onVisibleChanged: { - if (!visible) { - editingRule = null; - targetWindow = null; - } - } - - component SectionHeader: StyledText { - property string title - text: title - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - topPadding: Theme.spacingM - bottomPadding: Theme.spacingXS - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - component CheckboxRow: Row { - property alias checked: checkbox.checked - property alias label: labelText.text - property bool indeterminate: false - spacing: Theme.spacingS - height: 24 - - Rectangle { - id: checkbox - property bool checked: false - width: 20 - height: 20 - radius: 4 - color: parent.indeterminate ? Theme.surfaceVariant : (checked ? Theme.primary : "transparent") - border.color: parent.indeterminate ? Theme.outlineButton : (checked ? Theme.primary : Theme.outlineButton) - border.width: 2 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: parent.parent.indeterminate ? "remove" : "check" - size: 12 - color: parent.parent.indeterminate ? Theme.surfaceVariantText : Theme.background - visible: parent.checked || parent.parent.indeterminate - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (parent.parent.indeterminate) { - parent.parent.indeterminate = false; - parent.checked = true; - } else { - parent.checked = !parent.checked; - } - } - } - } - - StyledText { - id: labelText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - component InputField: Rectangle { - id: inputFieldRect - default property alias contentData: inputFieldRect.data - property bool hasFocus: false - width: parent.width - height: root.inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: hasFocus ? Theme.primary : Theme.outlineStrong - border.width: hasFocus ? 2 : 1 - } - - FocusScope { - anchors.fill: parent - focus: true - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - Keys.onEscapePressed: event => { - hide(); - event.accepted = true; - } - - Item { - id: header - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - height: Math.max(headerCol.height, closeBtn.height) - - MouseArea { - anchors.left: parent.left - anchors.right: closeBtn.left - anchors.rightMargin: Theme.spacingM - height: headerCol.height - onPressed: windowControls.tryStartMove() - - Column { - id: headerCol - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: root.isEditMode ? I18n.tr("Edit Window Rule") : I18n.tr("New Window Rule") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Configure match criteria and actions") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - DankActionButton { - id: closeBtn - anchors.right: parent.right - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: hide() - } - } - - DankFlickable { - id: flickable - anchors.top: header.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: footer.top - anchors.margins: Theme.spacingL - anchors.topMargin: Theme.spacingM - contentWidth: width - contentHeight: contentCol.implicitHeight - clip: true - - Column { - id: contentCol - width: flickable.width - Theme.spacingM - spacing: Theme.spacingXS - - InputField { - hasFocus: nameInput.activeFocus - DankTextField { - id: nameInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: I18n.tr("Rule Name") - backgroundColor: "transparent" - enabled: root.visible - } - } - - SectionHeader { - title: I18n.tr("Match Criteria") - } - - InputField { - hasFocus: appIdInput.activeFocus - DankTextField { - id: appIdInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: isNiri ? I18n.tr("App ID regex (e.g. ^firefox$)") : I18n.tr("Class regex (e.g. ^firefox$)") - backgroundColor: "transparent" - enabled: root.visible - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - InputField { - width: addTitleBtn.visible ? parent.width - addTitleBtn.width - Theme.spacingS : parent.width - hasFocus: titleInput.activeFocus - DankTextField { - id: titleInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: I18n.tr("Title regex (optional)") - backgroundColor: "transparent" - enabled: root.visible - } - } - - DankActionButton { - id: addTitleBtn - width: root.inputFieldHeight - height: root.inputFieldHeight - circular: false - iconName: "add" - iconSize: 16 - iconColor: Theme.surfaceVariantText - visible: !root.isEditMode && !!root.targetWindow?.title - tooltipText: I18n.tr("Add Title") - tooltipSide: "left" - onClicked: { - if (!root.targetWindow?.title) - return; - titleInput.text = "^" + root.targetWindow.title + "$"; - } - } - } - - SectionHeader { - title: I18n.tr("Window Opening") - } - - Flow { - width: parent.width - spacing: Theme.spacingL - - CheckboxRow { - id: floatingToggle - label: I18n.tr("Float") - } - CheckboxRow { - id: maximizedToggle - label: I18n.tr("Maximize") - } - CheckboxRow { - id: fullscreenToggle - label: I18n.tr("Fullscreen") - } - CheckboxRow { - id: maximizedToEdgesToggle - label: I18n.tr("Max to Edges") - visible: isNiri - } - CheckboxRow { - id: openFocusedToggle - label: I18n.tr("Focus") - visible: isNiri - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: true - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Output") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: outputInput.activeFocus - DankTextField { - id: outputInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "HDMI-A-1" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Workspace") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: workspaceInput.activeFocus - DankTextField { - id: workspaceInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "chat" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: isNiri - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Column Width") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: columnWidthInput.activeFocus - DankTextField { - id: columnWidthInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "800" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Window Height") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: windowHeightInput.activeFocus - DankTextField { - id: windowHeightInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "600" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - } - - SectionHeader { - title: I18n.tr("Dynamic Properties") - } - - Row { - width: parent.width - spacing: Theme.spacingM - - CheckboxRow { - id: opacityEnabled - label: I18n.tr("Opacity") - anchors.verticalCenter: parent.verticalCenter - } - - DankSlider { - id: opacitySlider - width: parent.width - 100 - minimum: 10 - maximum: 100 - value: 100 - enabled: opacityEnabled.checked - opacity: enabled ? 1 : 0.4 - } - } - - Flow { - width: parent.width - spacing: Theme.spacingL - visible: isNiri - - CheckboxRow { - id: vrrToggle - label: I18n.tr("VRR On-Demand") - } - CheckboxRow { - id: clipToGeometryToggle - label: I18n.tr("Clip to Geometry") - } - CheckboxRow { - id: tiledStateToggle - label: I18n.tr("Tiled State") - } - CheckboxRow { - id: drawBorderBgToggle - label: I18n.tr("Border with BG") - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: isNiri - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Block Out From") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - id: blockOutDropdown - width: parent.width - dropdownWidth: parent.width - compactMode: true - options: ["", "screencast", "screen-capture"] - emptyText: I18n.tr("None") - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Column Display") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - id: columnDisplayDropdown - width: parent.width - dropdownWidth: parent.width - compactMode: true - options: ["", "tabbed"] - emptyText: I18n.tr("Normal") - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: isNiri - - CheckboxRow { - id: scrollFactorEnabled - label: I18n.tr("Scroll Factor") - anchors.verticalCenter: parent.verticalCenter - } - - DankSlider { - id: scrollFactorSlider - width: parent.width - 120 - minimum: 10 - maximum: 200 - value: 100 - enabled: scrollFactorEnabled.checked - opacity: enabled ? 1 : 0.4 - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - CheckboxRow { - id: cornerRadiusEnabled - label: I18n.tr("Corner Radius") - anchors.verticalCenter: parent.verticalCenter - } - - DankSlider { - id: cornerRadiusSlider - width: parent.width - 130 - minimum: 0 - maximum: 24 - value: 12 - enabled: cornerRadiusEnabled.checked - opacity: enabled ? 1 : 0.4 - } - } - - SectionHeader { - title: I18n.tr("Size Constraints") - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM * 3) / 4 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Min W") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: minWidthInput.activeFocus - DankTextField { - id: minWidthInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "px" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM * 3) / 4 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Max W") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: maxWidthInput.activeFocus - DankTextField { - id: maxWidthInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "px" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM * 3) / 4 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Min H") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: minHeightInput.activeFocus - DankTextField { - id: minHeightInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "px" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM * 3) / 4 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Max H") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: maxHeightInput.activeFocus - DankTextField { - id: maxHeightInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "px" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - } - - SectionHeader { - title: I18n.tr("Hyprland Options") - visible: isHyprland - } - - Flow { - width: parent.width - spacing: Theme.spacingL - visible: isHyprland - - CheckboxRow { - id: tileToggle - label: I18n.tr("Tile") - } - CheckboxRow { - id: noFocusToggle - label: I18n.tr("No Focus") - } - CheckboxRow { - id: noBorderToggle - label: I18n.tr("No Border") - } - CheckboxRow { - id: noShadowToggle - label: I18n.tr("No Shadow") - } - CheckboxRow { - id: noDimToggle - label: I18n.tr("No Dim") - } - CheckboxRow { - id: noBlurToggle - label: I18n.tr("No Blur") - } - CheckboxRow { - id: noAnimToggle - label: I18n.tr("No Anim") - } - CheckboxRow { - id: noRoundingToggle - label: I18n.tr("No Rounding") - } - CheckboxRow { - id: pinToggle - label: I18n.tr("Pin") - } - CheckboxRow { - id: opaqueToggle - label: I18n.tr("Opaque") - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: isHyprland - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Size") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: sizeInput.activeFocus - DankTextField { - id: sizeInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "800 600" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Move") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: moveInput.activeFocus - DankTextField { - id: moveInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "100 100" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: isHyprland - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Monitor") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: monitorInput.activeFocus - DankTextField { - id: monitorInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "DP-1" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Workspace") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - InputField { - width: parent.width - hasFocus: hyprWorkspaceInput.activeFocus - DankTextField { - id: hyprWorkspaceInput - anchors.fill: parent - font.pixelSize: Theme.fontSizeSmall - textColor: Theme.surfaceText - placeholderText: "1" - backgroundColor: "transparent" - enabled: root.visible - } - } - } - } - - Item { - width: 1 - height: Theme.spacingM - } - } - } - - Item { - id: footer - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - height: 44 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: cancelText - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: hide() - } - } - - Rectangle { - width: Math.max(80, createText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: root.submitting ? Theme.surfaceVariant : (createArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary) - - StyledText { - id: createText - anchors.centerIn: parent - text: root.submitting ? I18n.tr("Saving...") : (root.isEditMode ? I18n.tr("Update") : I18n.tr("Create")) - font.pixelSize: Theme.fontSizeMedium - color: root.submitting ? Theme.surfaceVariantText : Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: createArea - anchors.fill: parent - hoverEnabled: true - cursorShape: root.submitting ? Qt.ArrowCursor : Qt.PointingHandCursor - enabled: !root.submitting - onClicked: submitAndClose() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WorkspaceRenameModal.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WorkspaceRenameModal.qml deleted file mode 100644 index 6519ac3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/WorkspaceRenameModal.qml +++ /dev/null @@ -1,230 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 - - objectName: "workspaceRenameModal" - title: I18n.tr("Rename Workspace") - minimumSize: Qt.size(400, 160) - maximumSize: Qt.size(400, 160) - color: Theme.surfaceContainer - visible: false - - function show(name) { - nameInput.text = name; - visible = true; - Qt.callLater(() => nameInput.forceActiveFocus()); - } - - function hide() { - visible = false; - } - - function submitAndClose() { - renameWorkspace(nameInput.text); - hide(); - } - - function renameWorkspace(name) { - if (CompositorService.isNiri) { - NiriService.renameWorkspace(name); - } else if (CompositorService.isHyprland) { - HyprlandService.renameWorkspace(name); - } else { - console.warn("WorkspaceRenameModal: rename not supported for this compositor"); - } - } - - onVisibleChanged: { - if (visible) { - Qt.callLater(() => nameInput.forceActiveFocus()); - return; - } - nameInput.text = ""; - } - - FocusScope { - id: contentFocusScope - - anchors.fill: parent - focus: true - - Keys.onEscapePressed: event => { - hide(); - event.accepted = true; - } - - Column { - id: contentCol - anchors.centerIn: parent - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - Item { - width: contentCol.width - height: Math.max(headerText.height, buttonRow.height) - - MouseArea { - anchors.left: parent.left - anchors.right: buttonRow.left - anchors.rightMargin: Theme.spacingM - height: parent.height - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - StyledText { - id: headerText - text: I18n.tr("Enter a new name for this workspace") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - anchors.verticalCenter: parent.verticalCenter - width: parent.width - buttonRow.width - Theme.spacingM - } - - Row { - id: buttonRow - anchors.right: parent.right - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported && windowControls.canMaximize - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: hide() - } - } - } - - Rectangle { - width: parent.width - height: inputFieldHeight - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: nameInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: nameInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: nameInput.forceActiveFocus() - } - - DankTextField { - id: nameInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - placeholderText: I18n.tr("Workspace name") - backgroundColor: "transparent" - enabled: root.visible - onAccepted: submitAndClose() - } - } - - Item { - width: parent.width - height: 40 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: cancelText - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: hide() - } - } - - Rectangle { - width: Math.max(80, renameText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: renameArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: renameText - anchors.centerIn: parent - text: I18n.tr("Rename") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: renameArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: submitAndClose() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } - - IpcHandler { - target: "workspace-rename" - - function open(): string { - const ws = NiriService.workspaces[NiriService.focusedWorkspaceId]; - show(ws?.name || ""); - return "WORKSPACE_RENAME_MODAL_OPENED"; - } - - function close(): string { - hide(); - return "WORKSPACE_RENAME_MODAL_CLOSED"; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml deleted file mode 100644 index ba07d37..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml +++ /dev/null @@ -1,166 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.DankLauncherV2 -import qs.Widgets - -DankPopout { - id: appDrawerPopout - - layerNamespace: "dms:app-launcher" - - readonly property real screenWidth: screen?.width ?? 1920 - readonly property real screenHeight: screen?.height ?? 1080 - - property string _pendingMode: "" - property string _pendingQuery: "" - - function show() { - open(); - } - - function openWithMode(mode) { - _pendingMode = mode || ""; - open(); - } - - function toggleWithMode(mode) { - if (shouldBeVisible) { - close(); - return; - } - openWithMode(mode); - } - - function openWithQuery(query) { - _pendingQuery = query || ""; - open(); - } - - function toggleWithQuery(query) { - if (shouldBeVisible) { - close(); - return; - } - openWithQuery(query); - } - - readonly property int _baseWidth: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 500; - case "medium": - return 720; - case "large": - return 860; - default: - return 620; - } - } - - readonly property int _baseHeight: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 480; - case "medium": - return 720; - case "large": - return 860; - default: - return 600; - } - } - - popupWidth: Math.min(_baseWidth, screenWidth - 100) - popupHeight: Math.min(_baseHeight, screenHeight - 100) - - triggerWidth: 40 - positioning: "" - contentHandlesKeys: contentLoader.item?.launcherContent?.editMode ?? false - - onBackgroundClicked: { - if (contentLoader.item?.launcherContent?.editMode) { - contentLoader.item.launcherContent.closeEditMode(); - return; - } - close(); - } - - onOpened: { - var lc = contentLoader.item?.launcherContent; - if (!lc) - return; - - const query = _pendingQuery || (SettingsData.rememberLastQuery ? SessionData.launcherLastQuery : "") || ""; - const mode = _pendingMode || SessionData.appDrawerLastMode || "apps"; - _pendingMode = ""; - _pendingQuery = ""; - - if (lc.searchField) { - lc.searchField.text = query; - lc.searchField.forceActiveFocus(); - } - if (lc.controller) { - lc.controller.searchMode = mode; - lc.controller.pluginFilter = ""; - lc.controller.searchQuery = query; - - lc.controller.performSearch(); - } - lc.resetScroll?.(); - lc.actionPanel?.hide(); - } - - Connections { - target: contentLoader.item?.launcherContent?.controller ?? null - function onModeChanged(mode) { - if (contentLoader.item.launcherContent.controller.autoSwitchedToFiles) - return; - SessionData.setAppDrawerLastMode(mode); - } - } - - content: Component { - Rectangle { - id: contentContainer - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property alias launcherContent: launcherContent - - color: "transparent" - - QtObject { - id: modalAdapter - property bool spotlightOpen: appDrawerPopout.shouldBeVisible - readonly property bool isClosing: !appDrawerPopout.shouldBeVisible - - function hide() { - appDrawerPopout.close(); - } - } - - FocusScope { - anchors.fill: parent - focus: true - - LauncherContent { - id: launcherContent - anchors.fill: parent - parentModal: modalAdapter - viewModeContext: "appDrawer" - } - - Keys.onEscapePressed: event => { - if (launcherContent.editMode) { - launcherContent.closeEditMode(); - event.accepted = true; - return; - } - appDrawerPopout.close(); - event.accepted = true; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml deleted file mode 100644 index 6a5c6e8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml +++ /dev/null @@ -1,332 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Widgets -import qs.Services - -Variants { - model: { - if (SessionData.isGreeterMode) { - return Quickshell.screens; - } - return SettingsData.getFilteredScreens("wallpaper"); - } - - PanelWindow { - id: blurWallpaperWindow - - required property var modelData - - screen: modelData - - WlrLayershell.layer: WlrLayer.Background - WlrLayershell.namespace: "dms:blurwallpaper" - WlrLayershell.exclusionMode: ExclusionMode.Ignore - - anchors.top: true - anchors.bottom: true - anchors.left: true - anchors.right: true - - color: "transparent" - - mask: Region { - item: Item {} - } - - Item { - id: root - anchors.fill: parent - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string source: SessionData.getMonitorWallpaper(modelData.name) || "" - property bool isColorSource: source.startsWith("#") - - Connections { - target: SessionData - function onIsLightModeChanged() { - if (SessionData.perModeWallpaper) { - var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""; - if (newSource !== root.source) { - root.source = newSource; - } - } - } - } - - function getFillMode(modeName) { - switch (modeName) { - case "Stretch": - return Image.Stretch; - case "Fit": - case "PreserveAspectFit": - return Image.PreserveAspectFit; - case "Fill": - case "PreserveAspectCrop": - return Image.PreserveAspectCrop; - case "Tile": - return Image.Tile; - case "TileVertically": - return Image.TileVertically; - case "TileHorizontally": - return Image.TileHorizontally; - case "Pad": - return Image.Pad; - default: - return Image.PreserveAspectCrop; - } - } - - Component.onCompleted: { - if (typeof blurWallpaperWindow.updatesEnabled !== "undefined") - blurWallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading); - isInitialized = true; - } - - property bool isInitialized: false - property real transitionProgress: 0 - readonly property bool transitioning: transitionAnimation.running - property bool effectActive: false - property bool _renderSettling: true - property bool useNextForEffect: false - - Connections { - target: currentWallpaper - function onStatusChanged() { - if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) - return; - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: blurWallpaperWindow - function onWidthChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - function onHeightChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Timer { - id: renderSettleTimer - interval: 1000 - onTriggered: root._renderSettling = false - } - - onSourceChanged: { - if (!source || source.startsWith("#")) { - setWallpaperImmediate(""); - return; - } - - const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source); - - if (!isInitialized || !currentWallpaper.source) { - setWallpaperImmediate(formattedSource); - isInitialized = true; - return; - } - if (CompositorService.isNiri && SessionData.isSwitchingMode) { - setWallpaperImmediate(formattedSource); - return; - } - changeWallpaper(formattedSource); - } - - function setWallpaperImmediate(newSource) { - transitionAnimation.stop(); - root.transitionProgress = 0.0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = newSource; - nextWallpaper.source = ""; - } - - function startTransition() { - root.useNextForEffect = true; - root.effectActive = true; - if (srcNext.scheduleUpdate) - srcNext.scheduleUpdate(); - transitionDelayTimer.start(); - } - - Timer { - id: transitionDelayTimer - interval: 16 - repeat: false - onTriggered: transitionAnimation.start() - } - - function changeWallpaper(newPath) { - if (newPath === currentWallpaper.source) - return; - if (!newPath || newPath.startsWith("#")) - return; - if (root.transitioning) { - transitionAnimation.stop(); - root.transitionProgress = 0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = nextWallpaper.source; - nextWallpaper.source = ""; - } - if (!currentWallpaper.source) { - setWallpaperImmediate(newPath); - return; - } - - root._renderSettling = true; - renderSettleTimer.restart(); - - nextWallpaper.source = newPath; - - if (nextWallpaper.status === Image.Ready) - root.startTransition(); - } - - Loader { - anchors.fill: parent - active: !root.source || root.isColorSource - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: modelData.name - } - } - - readonly property int maxTextureSize: 8192 - property int textureWidth: Math.min(modelData.width, maxTextureSize) - property int textureHeight: Math.min(modelData.height, maxTextureSize) - - Image { - id: currentWallpaper - anchors.fill: parent - visible: false - opacity: 1 - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) - } - - Image { - id: nextWallpaper - anchors.fill: parent - visible: false - opacity: 0 - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) - - onStatusChanged: { - if (status !== Image.Ready) - return; - if (!root.transitioning) { - root.startTransition(); - } - } - } - - ShaderEffectSource { - id: srcNext - sourceItem: root.effectActive ? nextWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - Rectangle { - id: dummyRect - width: 1 - height: 1 - visible: false - color: "transparent" - } - - ShaderEffectSource { - id: srcDummy - sourceItem: dummyRect - hideSource: true - live: false - mipmap: false - recursive: false - } - - Item { - id: blurredLayer - anchors.fill: parent - - MultiEffect { - anchors.fill: parent - source: currentWallpaper - visible: currentWallpaper.source !== "" - blurEnabled: true - blur: 0.8 - blurMax: 75 - opacity: 1 - root.transitionProgress - autoPaddingEnabled: false - } - - MultiEffect { - anchors.fill: parent - source: root.useNextForEffect ? srcNext : srcDummy - visible: nextWallpaper.source !== "" && root.useNextForEffect - blurEnabled: true - blur: 0.8 - blurMax: 75 - opacity: root.transitionProgress - autoPaddingEnabled: false - } - } - - NumberAnimation { - id: transitionAnimation - target: root - property: "transitionProgress" - from: 0.0 - to: 1.0 - duration: 1000 - easing.type: Easing.InOutCubic - onFinished: { - if (nextWallpaper.source && nextWallpaper.status === Image.Ready) - currentWallpaper.source = nextWallpaper.source; - root.useNextForEffect = false; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - root._renderSettling = true; - renderSettleTimer.restart(); - root.effectActive = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml deleted file mode 100644 index dc2ea24..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml +++ /dev/null @@ -1,547 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - property real widgetWidth: 280 - property real widgetHeight: 200 - - property string instanceId: "" - property var instanceData: null - readonly property var cfg: instanceData?.config ?? null - readonly property bool isInstance: instanceId !== "" && cfg !== null - - property string clockStyle: isInstance ? (cfg.style ?? "analog") : SettingsData.desktopClockStyle - property bool forceSquare: clockStyle === "analog" - - property real defaultWidth: { - switch (clockStyle) { - case "analog": - return 200; - case "stacked": - return 100; - default: - return 160; - } - } - property real defaultHeight: { - switch (clockStyle) { - case "analog": - return 200; - case "stacked": - return 160; - default: - return 70; - } - } - property real minWidth: { - switch (clockStyle) { - case "analog": - return 120; - case "stacked": - return 70; - default: - return 100; - } - } - property real minHeight: { - switch (clockStyle) { - case "analog": - return 120; - case "stacked": - return 100; - default: - return 45; - } - } - - property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled - property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.desktopClockTransparency - property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.desktopClockColorMode - property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.desktopClockCustomColor - property bool showDate: isInstance ? (cfg.showDate ?? true) : SettingsData.desktopClockShowDate - property bool showAnalogNumbers: isInstance ? (cfg.showAnalogNumbers ?? false) : SettingsData.desktopClockShowAnalogNumbers - - readonly property real scaleFactor: Math.min(width, height) / 200 - - readonly property color accentColor: { - if (colorMode === "primary") - return Theme.primary; - if (colorMode === "secondary") - return Theme.secondary; - if (colorMode === "custom") - return customColor; - return Theme.primary; - } - - readonly property color handColor: accentColor - readonly property color handColorDim: Theme.withAlpha(accentColor, 0.65) - readonly property color textColor: Theme.onSurface - readonly property color subtleTextColor: Theme.onSurfaceVariant - readonly property color backgroundColor: Theme.withAlpha(Theme.surface, root.transparency) - - readonly property bool showAnalogSeconds: isInstance ? (cfg.showAnalogSeconds ?? true) : SettingsData.desktopClockShowAnalogSeconds - readonly property bool showDigitalSeconds: isInstance ? (cfg.showDigitalSeconds ?? false) : false - readonly property bool needsSeconds: clockStyle === "analog" ? showAnalogSeconds : showDigitalSeconds - - SystemClock { - id: systemClock - precision: root.needsSeconds ? SystemClock.Seconds : SystemClock.Minutes - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: root.backgroundColor - visible: root.clockStyle !== "analog" - } - - OrganicBlobHourBulges { - anchors.fill: parent - fillColor: root.backgroundColor - visible: root.clockStyle === "analog" - lobes: 12 - rotationDeg: -90 - lobeAmount: 0.075 - hillPower: 0.92 - roundness: 0.22 - paddingFrac: 0.02 - segments: 144 - } - - Loader { - anchors.fill: parent - anchors.margins: Theme.spacingM - sourceComponent: { - if (root.clockStyle === "analog") - return analogClock; - if (root.clockStyle === "stacked") - return stackedClock; - return digitalClock; - } - } - - Component { - id: analogClock - - Item { - id: analogRoot - - property real clockSize: Math.min(width, height) - property real centerX: width / 2 - property real centerY: height / 2 - property real faceRadius: clockSize / 2 - 12 - - property int hours: systemClock.date?.getHours() % 12 ?? 0 - property int minutes: systemClock.date?.getMinutes() ?? 0 - property int seconds: systemClock.date?.getSeconds() ?? 0 - - Repeater { - model: root.showAnalogNumbers ? 12 : 0 - - StyledText { - required property int index - property real angle: (index + 1) * 30 * Math.PI / 180 - property real numRadius: analogRoot.faceRadius + 10 - - x: analogRoot.centerX + numRadius * Math.sin(angle) - width / 2 - y: analogRoot.centerY - numRadius * Math.cos(angle) - height / 2 - text: index + 1 - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: root.accentColor - } - } - - Rectangle { - id: hourHand - property real angle: (analogRoot.hours + analogRoot.minutes / 60) * 30 - property real handWidth: Math.max(8, 12 * root.scaleFactor) - property real mainLength: analogRoot.faceRadius * 0.55 - property real tailLength: handWidth * 0.5 - - x: analogRoot.centerX - width / 2 - y: analogRoot.centerY - mainLength - width: handWidth - height: mainLength + tailLength - radius: width / 2 - color: root.handColor - antialiasing: true - - transform: Rotation { - origin.x: hourHand.width / 2 - origin.y: hourHand.mainLength - angle: hourHand.angle - } - } - - Rectangle { - id: minuteHand - property real angle: (analogRoot.minutes + analogRoot.seconds / 60) * 6 - property real mainLength: analogRoot.faceRadius * 0.75 - property real tailLength: hourHand.handWidth * 0.5 - - x: analogRoot.centerX - width / 2 - y: analogRoot.centerY - mainLength - width: hourHand.handWidth - height: mainLength + tailLength - radius: width / 2 - color: root.handColorDim - antialiasing: true - - transform: Rotation { - origin.x: minuteHand.width / 2 - origin.y: minuteHand.mainLength - angle: minuteHand.angle - } - } - - Rectangle { - id: secondDot - visible: root.showAnalogSeconds - - property real angle: analogRoot.seconds * 6 * Math.PI / 180 - property real orbitRadius: analogRoot.faceRadius * 0.92 - - x: analogRoot.centerX + orbitRadius * Math.sin(angle) - width / 2 - y: analogRoot.centerY - orbitRadius * Math.cos(angle) - height / 2 - width: Math.max(10, analogRoot.clockSize * 0.07) - height: width - radius: width / 2 - color: root.accentColor - - Behavior on x { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - Behavior on y { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - id: dateText - visible: root.showDate - - property real hourAngle: (analogRoot.hours + analogRoot.minutes / 60) * 30 - property real minuteAngle: analogRoot.minutes * 6 - - property string bestPosition: { - const hRad = hourAngle * Math.PI / 180; - const mRad = minuteAngle * Math.PI / 180; - - const topWeight = Math.max(0, Math.cos(hRad)) + Math.max(0, Math.cos(mRad)); - const bottomWeight = Math.max(0, -Math.cos(hRad)) + Math.max(0, -Math.cos(mRad)); - const rightWeight = Math.max(0, Math.sin(hRad)) + Math.max(0, Math.sin(mRad)); - const leftWeight = Math.max(0, -Math.sin(hRad)) + Math.max(0, -Math.sin(mRad)); - - const minWeight = Math.min(topWeight, bottomWeight, leftWeight, rightWeight); - - if (minWeight === bottomWeight) - return "bottom"; - if (minWeight === topWeight) - return "top"; - if (minWeight === rightWeight) - return "right"; - return "left"; - } - - x: { - if (bestPosition === "left") - return analogRoot.centerX - analogRoot.faceRadius * 0.5 - width / 2; - if (bestPosition === "right") - return analogRoot.centerX + analogRoot.faceRadius * 0.5 - width / 2; - return analogRoot.centerX - width / 2; - } - y: { - if (bestPosition === "top") - return analogRoot.centerY - analogRoot.faceRadius * 0.5 - height / 2; - if (bestPosition === "bottom") - return analogRoot.centerY + analogRoot.faceRadius * 0.5 - height / 2; - return analogRoot.centerY - height / 2; - } - - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) - return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? ""; - return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""; - } - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - - Behavior on x { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - Behavior on y { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - - Component { - id: digitalClock - - Item { - id: digitalRoot - - property bool hasDate: root.showDate - property bool hasAmPm: !SettingsData.use24HourClock - property real verticalScale: hasDate && hasAmPm ? 0.55 : (hasDate || hasAmPm ? 0.65 : 0.8) - property real baseSize: Math.min(height * verticalScale, width * 0.22) - property real digitWidth: baseSize * 0.62 - property real smallSize: baseSize * 0.35 - - property string hoursStr: { - const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12); - if (SettingsData.use24HourClock || SettingsData.padHours12Hour) - return String(hours).padStart(2, '0'); - return String(hours); - } - property string minutesStr: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0') - property string secondsStr: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0') - - Column { - anchors.centerIn: parent - spacing: 0 - - StyledText { - visible: root.showDate - anchors.horizontalCenter: parent.horizontalCenter - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) - return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? ""; - return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""; - } - font.pixelSize: digitalRoot.smallSize - color: Theme.withAlpha(root.accentColor, 0.7) - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 0 - - StyledText { - visible: digitalRoot.hoursStr.length > 1 - width: digitalRoot.digitWidth - text: digitalRoot.hoursStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.hoursStr.length > 1 ? digitalRoot.hoursStr.charAt(1) : digitalRoot.hoursStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - text: ":" - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.minutesStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.minutesStr.charAt(1) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - visible: root.showDigitalSeconds - text: ":" - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - StyledText { - visible: root.showDigitalSeconds - width: digitalRoot.digitWidth - text: digitalRoot.secondsStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - horizontalAlignment: Text.AlignHCenter - } - StyledText { - visible: root.showDigitalSeconds - width: digitalRoot.digitWidth - text: digitalRoot.secondsStr.charAt(1) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - horizontalAlignment: Text.AlignHCenter - } - } - - StyledText { - visible: !SettingsData.use24HourClock - anchors.horizontalCenter: parent.horizontalCenter - text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM" - font.pixelSize: digitalRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - } - } - } - - Component { - id: stackedClock - - Item { - id: stackedRoot - - property bool hasSeconds: root.showDigitalSeconds - property bool hasDate: root.showDate - property bool hasAmPm: !SettingsData.use24HourClock - property real extraContent: (hasSeconds ? 0.12 : 0) + (hasDate ? 0.08 : 0) + (hasAmPm ? 0.08 : 0) - property real baseSize: height * (0.42 - extraContent * 0.5) - property real digitWidth: baseSize * 0.58 - property real smallSize: baseSize * 0.5 - property real rowSpacing: -baseSize * 0.17 - - Column { - anchors.centerIn: parent - spacing: 0 - - Column { - spacing: stackedRoot.rowSpacing - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - if (SettingsData.use24HourClock) - return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(0); - const hours = systemClock.date?.getHours() ?? 0; - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(0); - } - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: { - if (SettingsData.use24HourClock) - return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(1); - const hours = systemClock.date?.getHours() ?? 0; - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(1); - } - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(0) - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(1) - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - } - } - - Row { - visible: stackedRoot.hasSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(0) - font.pixelSize: stackedRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - width: stackedRoot.smallSize * 0.58 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(1) - font.pixelSize: stackedRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - width: stackedRoot.smallSize * 0.58 - horizontalAlignment: Text.AlignHCenter - } - } - - Item { - width: 1 - height: stackedRoot.baseSize * 0.1 - visible: stackedRoot.hasDate - } - - StyledText { - visible: stackedRoot.hasDate - anchors.horizontalCenter: parent.horizontalCenter - text: systemClock.date?.toLocaleDateString(I18n.locale(), "MMM dd") ?? "" - font.pixelSize: stackedRoot.smallSize * 0.7 - color: Theme.withAlpha(root.accentColor, 0.7) - } - - StyledText { - visible: stackedRoot.hasAmPm - anchors.horizontalCenter: parent.horizontalCenter - text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM" - font.pixelSize: stackedRoot.smallSize * 0.7 - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml deleted file mode 100644 index cced1a4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml +++ /dev/null @@ -1,137 +0,0 @@ -import QtQuick -import QtQuick.Shapes - -Item { - id: root - - property color fillColor: "transparent" - - property int lobes: 12 - property real lobeAmount: 0.070 - property real roundness: 0.22 - property real hillPower: 0.78 - property real paddingFrac: 0.020 - property real inset: 0 - property int segments: 120 - property real rotationDeg: -90 - - layer.enabled: true - layer.samples: 4 - - function sgn(v) { - return v < 0 ? -1 : 1; - } - function clamp(v, a, b) { - return Math.max(a, Math.min(b, v)); - } - - function squircleMap(u, v, p) { - const ax = sgn(u) * Math.pow(Math.abs(u), p); - const ay = sgn(v) * Math.pow(Math.abs(v), p); - return { - x: ax, - y: ay - }; - } - - function buildPathD(w, h) { - const x0 = inset, y0 = inset; - const x1 = w - inset, y1 = h - inset; - const iw = Math.max(2, x1 - x0); - const ih = Math.max(2, y1 - y0); - - const cx = x0 + iw * 0.5; - const cy = y0 + ih * 0.5; - - const rx = iw * 0.5; - const ry = ih * 0.5; - const rMin = Math.min(rx, ry); - - const amp = clamp(lobeAmount, 0.0, 0.14) * rMin; - const extraPad = paddingFrac * rMin + 1.5; - const pad = amp + extraPad; - - const rxBase = Math.max(2, rx - pad); - const ryBase = Math.max(2, ry - pad); - - const blend = clamp(roundness, 0.0, 0.45); - const squirclePow = 1.0 + blend * 2.8; - - const N = Math.max(48, segments); - const rot = rotationDeg * Math.PI / 180.0; - const dt = (Math.PI * 2.0) / N; - - function hillWave(a) { - const t = (Math.cos(lobes * a) + 1.0) * 0.5; - return Math.pow(t, hillPower); - } - - function P(t) { - const a = t + rot; - const u = Math.cos(a); - const v = Math.sin(a); - - const m = 1.0 + (amp / rMin) * hillWave(a); - - const ex = u * rxBase * m; - const ey = v * ryBase * m; - - const sm = squircleMap(u, v, 1.0 / squirclePow); - const sx = sm.x * rxBase * m; - const sy = sm.y * ryBase * m; - - const x = ex * (1.0 - blend) + sx * blend; - const y = ey * (1.0 - blend) + sy * blend; - return { - x: cx + x, - y: cy + y - }; - } - - function dP(t) { - const eps = dt * 0.25; - const p1 = P(t - eps); - const p2 = P(t + eps); - return { - x: (p2.x - p1.x) / (2 * eps), - y: (p2.y - p1.y) / (2 * eps) - }; - } - - const p0 = P(0.0); - let d = `M ${p0.x.toFixed(2)} ${p0.y.toFixed(2)} `; - - for (let i = 0; i < N; i++) { - const tA = i * dt; - const tB = (i + 1) * dt; - - const A = P(tA); - const B = P(tB); - const dA = dP(tA); - const dB = dP(tB); - - const c1x = A.x + (dt / 3.0) * dA.x; - const c1y = A.y + (dt / 3.0) * dA.y; - const c2x = B.x - (dt / 3.0) * dB.x; - const c2y = B.y - (dt / 3.0) * dB.y; - - d += `C ${c1x.toFixed(2)} ${c1y.toFixed(2)}, ${c2x.toFixed(2)} ${c2y.toFixed(2)}, ${B.x.toFixed(2)} ${B.y.toFixed(2)} `; - } - - d += "Z"; - return d; - } - - Shape { - anchors.fill: parent - - ShapePath { - fillColor: root.fillColor - strokeColor: "transparent" - - PathSvg { - path: root.buildPathD(root.width, root.height) - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml deleted file mode 100644 index 515e74e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml +++ /dev/null @@ -1,743 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property real widgetWidth: 320 - property real widgetHeight: 480 - property real defaultWidth: 320 - property real defaultHeight: 480 - property real minWidth: { - const tileCount = enabledTiles.length; - if (tileCount === 0) - return 80; - if (tileCount === 1) - return 100; - return 160; - } - property real minHeight: { - const tileCount = enabledTiles.length; - if (tileCount === 0) - return 60; - if (tileCount === 1) - return 80; - if (tileCount <= 2) - return 120; - return 180; - } - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? null - readonly property bool isInstance: instanceId !== "" && cfg !== null - - property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled - property bool showHeader: isInstance ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader - property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency - property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode - property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor - property bool showCpu: isInstance ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu - property bool showCpuGraph: isInstance ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph - property bool showCpuTemp: isInstance ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp - property bool showGpuTemp: isInstance ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp - property string selectedGpuPciId: isInstance ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId - property bool showMemory: isInstance ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory - property bool showMemoryGraph: isInstance ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph - property bool showNetwork: isInstance ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork - property bool showNetworkGraph: isInstance ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph - property bool showDisk: isInstance ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk - property bool showTopProcesses: isInstance ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses - property int topProcessCount: isInstance ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount - property string topProcessSortBy: isInstance ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy - property string layoutMode: isInstance ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode - property int graphInterval: isInstance ? (cfg.graphInterval ?? 60) : SettingsData.systemMonitorGraphInterval - - readonly property color accentColor: { - switch (colorMode) { - case "secondary": - return Theme.secondary; - case "custom": - return customColor; - default: - return Theme.primary; - } - } - - readonly property color bgColor: Theme.withAlpha(Theme.surface, root.transparency) - readonly property color tileBg: Theme.withAlpha(Theme.surfaceContainerHigh, root.transparency) - readonly property color textColor: Theme.surfaceText - readonly property color dimColor: Theme.surfaceVariantText - - property string currentGpuPciIdRef: "" - property var activeModuleRefs: [] - - property var cpuHistory: [] - property var memHistory: [] - property var netRxHistory: [] - property var netTxHistory: [] - property var diskReadHistory: [] - property var diskWriteHistory: [] - readonly property int historySize: 60 - - readonly property int sampleInterval: { - switch (graphInterval) { - case 60: - return 1000; - case 300: - return 5000; - case 600: - return 10000; - case 900: - return 15000; - case 1800: - return 30000; - default: - return 1000; - } - } - - readonly property var enabledTiles: { - var tiles = []; - if (showCpu) - tiles.push("cpu"); - if (showMemory) - tiles.push("mem"); - if (showNetwork) - tiles.push("net"); - if (showDisk) - tiles.push("disk"); - if (showGpuTemp && selectedGpuPciId) - tiles.push("gpu"); - return tiles; - } - - readonly property var sortedProcesses: { - if (!showTopProcesses || !DgopService.processes) - return []; - var procs = DgopService.processes.slice(); - if (topProcessSortBy === "memory") { - procs.sort((a, b) => (b.memoryKB || 0) - (a.memoryKB || 0)); - } else { - procs.sort((a, b) => (b.cpu || 0) - (a.cpu || 0)); - } - return procs.slice(0, topProcessCount); - } - - Component.onCompleted: { - var modules = ["system"]; - if (showCpu || showCpuTemp || showCpuGraph) - modules.push("cpu"); - if (showMemory || showMemoryGraph) - modules.push("memory"); - if (showNetwork || showNetworkGraph) - modules.push("network"); - if (showDisk) - modules.push("disk", "diskmounts"); - if (showTopProcesses) - modules.push("processes"); - activeModuleRefs = modules; - DgopService.addRef(modules); - updateGpuRef(); - } - - Component.onDestruction: { - DgopService.removeRef(activeModuleRefs); - if (currentGpuPciIdRef) - DgopService.removeGpuPciId(currentGpuPciIdRef); - } - - onShowGpuTempChanged: updateGpuRef() - onSelectedGpuPciIdChanged: updateGpuRef() - onShowTopProcessesChanged: { - if (showTopProcesses) { - activeModuleRefs = activeModuleRefs.concat(["processes"]); - DgopService.addRef(["processes"]); - } else { - DgopService.removeRef(["processes"]); - activeModuleRefs = activeModuleRefs.filter(m => m !== "processes"); - } - } - - function updateGpuRef() { - if (currentGpuPciIdRef && currentGpuPciIdRef !== selectedGpuPciId) { - DgopService.removeGpuPciId(currentGpuPciIdRef); - currentGpuPciIdRef = ""; - } - if (!showGpuTemp || !selectedGpuPciId) { - if (currentGpuPciIdRef) { - DgopService.removeGpuPciId(currentGpuPciIdRef); - currentGpuPciIdRef = ""; - } - return; - } - if (selectedGpuPciId && !currentGpuPciIdRef) { - DgopService.addGpuPciId(selectedGpuPciId); - currentGpuPciIdRef = selectedGpuPciId; - } - } - - function getGpuInfo() { - if (!selectedGpuPciId || !DgopService.availableGpus) - return null; - return DgopService.availableGpus.find(g => g.pciId === selectedGpuPciId); - } - - function formatBytes(bytes) { - if (bytes < 1024) - return bytes.toFixed(0) + "B"; - if (bytes < 1024 * 1024) - return (bytes / 1024).toFixed(0) + "K"; - if (bytes < 1024 * 1024 * 1024) - return (bytes / (1024 * 1024)).toFixed(1) + "M"; - return (bytes / (1024 * 1024 * 1024)).toFixed(1) + "G"; - } - - function formatMemKB(kb) { - if (kb < 1024) - return kb.toFixed(0) + "K"; - if (kb < 1024 * 1024) - return (kb / 1024).toFixed(0) + "M"; - return (kb / (1024 * 1024)).toFixed(1) + "G"; - } - - function addToHistory(arr, val) { - var newArr = arr.slice(); - newArr.push(val); - if (newArr.length > historySize) - newArr.shift(); - return newArr; - } - - function sampleData() { - if (showCpuGraph) - cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage); - if (showMemoryGraph) - memHistory = addToHistory(memHistory, DgopService.memoryUsage); - if (showNetworkGraph) { - netRxHistory = addToHistory(netRxHistory, DgopService.networkRxRate); - netTxHistory = addToHistory(netTxHistory, DgopService.networkTxRate); - } - if (showDisk) { - diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate); - diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate); - } - } - - readonly property int sampleSeconds: sampleInterval / 1000 - - SystemClock { - id: sampleClock - precision: SystemClock.Seconds - onDateChanged: { - var sec = date.getSeconds(); - if (sec % root.sampleSeconds === 0) - root.sampleData(); - } - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: root.bgColor - border.width: 0 - - ColumnLayout { - anchors.fill: parent - anchors.margins: (root.enabledTiles.length === 1 && !root.showHeader) ? 0 : Theme.spacingS - spacing: Theme.spacingS - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - visible: root.showHeader - - ColumnLayout { - spacing: 0 - - StyledText { - text: DgopService.cpuModel || DgopService.hostname || "System" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - elide: Text.ElideRight - Layout.maximumWidth: root.width - Theme.spacingM * 2 - } - - StyledText { - visible: DgopService.shortUptime && DgopService.shortUptime.length > 0 - text: DgopService.shortUptime - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - } - } - - GridLayout { - id: tileGrid - Layout.fillWidth: true - Layout.fillHeight: true - columns: { - if (root.layoutMode === "list") - return 1; - if (root.layoutMode === "grid") - return 2; - // auto - if (root.width < 280) - return 1; - if (root.width < 500) - return 2; - return 3; - } - rowSpacing: Theme.spacingXS - columnSpacing: Theme.spacingXS - - Repeater { - model: root.enabledTiles - - Rectangle { - id: tile - readonly property int span: Layout.columnSpan - Layout.fillWidth: true - Layout.fillHeight: true - Layout.columnSpan: { - if (root.layoutMode === "list") - return 1; - - var cols = tileGrid.columns; - if (cols <= 1) - return 1; - - var count = root.enabledTiles.length; - var idx = index; - - if (idx !== count - 1) - return 1; - - var remainder = count % cols; - if (remainder === 0) - return 1; - - if (!tile.hasGraph) - return 1; - - return cols - remainder + 1; - } - Layout.minimumHeight: 60 - radius: Theme.cornerRadius - 2 - color: root.tileBg - border.width: 0 - clip: true - - readonly property string tileType: modelData - readonly property bool hasGraph: { - switch (tileType) { - case "cpu": - return root.showCpuGraph; - case "mem": - return root.showMemoryGraph; - case "net": - return root.showNetworkGraph; - case "disk": - return true; - default: - return false; - } - } - - Canvas { - id: tileGraph - anchors.fill: parent - visible: tile.hasGraph - renderStrategy: Canvas.Cooperative - - property var hist: { - switch (tile.tileType) { - case "cpu": - return root.cpuHistory; - case "mem": - return root.memHistory; - case "net": - return root.netRxHistory; - case "disk": - return root.diskReadHistory; - default: - return []; - } - } - property var hist2: { - switch (tile.tileType) { - case "net": - return root.netTxHistory; - case "disk": - return root.diskWriteHistory; - default: - return null; - } - } - - onHistChanged: requestPaint() - onHist2Changed: requestPaint() - onWidthChanged: requestPaint() - onHeightChanged: requestPaint() - - onPaint: { - var ctx = getContext("2d"); - ctx.reset(); - ctx.clearRect(0, 0, width, height); - if (!hist || hist.length < 2) - return; - var maxVal = 100; - if (tile.tileType === "net" || tile.tileType === "disk") { - maxVal = 1; - for (var k = 0; k < hist.length; k++) - maxVal = Math.max(maxVal, hist[k]); - if (hist2) - for (var l = 0; l < hist2.length; l++) - maxVal = Math.max(maxVal, hist2[l]); - } - - var c = root.accentColor; - var grad = ctx.createLinearGradient(0, 0, 0, height); - grad.addColorStop(0, Qt.rgba(c.r, c.g, c.b, 0.3)); - grad.addColorStop(1, Qt.rgba(c.r, c.g, c.b, 0.05)); - - ctx.fillStyle = grad; - ctx.beginPath(); - ctx.moveTo(0, height); - for (var i = 0; i < hist.length; i++) { - var x = (width / (root.historySize - 1)) * i; - var y = height - (hist[i] / maxVal) * height * 0.85; - ctx.lineTo(x, y); - } - ctx.lineTo((width / (root.historySize - 1)) * (hist.length - 1), height); - ctx.closePath(); - ctx.fill(); - - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.6); - ctx.lineWidth = 1.5; - ctx.beginPath(); - for (var j = 0; j < hist.length; j++) { - var px = (width / (root.historySize - 1)) * j; - var py = height - (hist[j] / maxVal) * height * 0.85; - j === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py); - } - ctx.stroke(); - - if (hist2 && hist2.length >= 2) { - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.3); - ctx.lineWidth = 1; - ctx.beginPath(); - for (var m = 0; m < hist2.length; m++) { - var sx = (width / (root.historySize - 1)) * m; - var sy = height - (hist2[m] / maxVal) * height * 0.85; - m === 0 ? ctx.moveTo(sx, sy) : ctx.lineTo(sx, sy); - } - ctx.stroke(); - } - } - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: tile.tileType.toUpperCase() - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: root.accentColor - } - - Item { - Layout.fillWidth: true - } - - StyledText { - visible: tile.tileType === "cpu" && root.showCpuTemp && DgopService.cpuTemperature > 0 - text: DgopService.cpuTemperature.toFixed(0) + "°" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: DgopService.cpuTemperature > 80 ? Theme.error : (DgopService.cpuTemperature > 60 ? Theme.warning : root.dimColor) - } - - StyledText { - visible: tile.tileType === "mem" - text: DgopService.formatSystemMemory(DgopService.usedMemoryKB) - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - } - - Item { - Layout.fillHeight: true - } - - StyledText { - visible: tile.tileType === "cpu" - text: DgopService.cpuUsage.toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - } - - StyledText { - visible: tile.tileType === "mem" - text: DgopService.memoryUsage.toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - } - - RowLayout { - visible: tile.tileType === "net" - spacing: Theme.spacingM - ColumnLayout { - spacing: 0 - StyledText { - text: "↓" - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - } - StyledText { - text: root.formatBytes(DgopService.networkRxRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - ColumnLayout { - spacing: 0 - StyledText { - text: "↑" - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - StyledText { - text: root.formatBytes(DgopService.networkTxRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - } - - RowLayout { - visible: tile.tileType === "disk" - spacing: Theme.spacingM - ColumnLayout { - spacing: 0 - StyledText { - text: "R" - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - } - StyledText { - text: root.formatBytes(DgopService.diskReadRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - ColumnLayout { - spacing: 0 - StyledText { - text: "W" - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - StyledText { - text: root.formatBytes(DgopService.diskWriteRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - } - - ColumnLayout { - visible: tile.tileType === "gpu" - spacing: 0 - property var gpu: root.getGpuInfo() - Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft - - StyledText { - property real temp: parent.gpu?.temperature ?? 0 - text: temp > 0 ? temp.toFixed(0) + "°C" : "--" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft - } - StyledText { - text: parent.gpu?.displayName ?? "" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.fillWidth: true - horizontalAlignment: tile.span > 1 ? Text.AlignHCenter : Text.AlignLeft - elide: Text.ElideRight - } - } - - Rectangle { - visible: tile.tileType === "cpu" || tile.tileType === "mem" - Layout.fillWidth: true - height: 4 - radius: 2 - color: Theme.withAlpha(Theme.outline, 0.2) - - Rectangle { - property real pct: tile.tileType === "cpu" ? DgopService.cpuUsage / 100 : DgopService.memoryUsage / 100 - width: parent.width * Math.min(1, pct) - height: parent.height - radius: 2 - color: pct > 0.8 ? Theme.error : (pct > 0.6 ? Theme.warning : root.accentColor) - Behavior on width { - NumberAnimation { - duration: 150 - } - } - } - } - } - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - visible: root.showTopProcesses && root.sortedProcesses.length > 0 - - Rectangle { - Layout.fillWidth: true - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: "TOP BY " + root.topProcessSortBy.toUpperCase() - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: root.accentColor - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: root.topProcessSortBy === "cpu" ? "CPU" : "MEM" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - horizontalAlignment: Text.AlignRight - } - } - - Repeater { - model: root.sortedProcesses - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: modelData.command || "unknown" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - Layout.fillWidth: true - elide: Text.ElideRight - } - - StyledText { - text: root.topProcessSortBy === "cpu" ? (modelData.cpu || 0).toFixed(1) + "%" : root.formatMemKB(modelData.memoryKB || 0) - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - horizontalAlignment: Text.AlignRight - } - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - visible: root.showDisk && DgopService.diskMounts.length > 0 - - Rectangle { - Layout.fillWidth: true - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - Repeater { - model: DgopService.diskMounts.filter(m => m.mountpoint === "/" || m.mountpoint === "/home") - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: modelData.mountpoint - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - } - - Rectangle { - Layout.fillWidth: true - height: 4 - radius: 2 - color: Theme.withAlpha(Theme.outline, 0.2) - - Rectangle { - property real pct: (modelData.used || 0) / Math.max(1, modelData.total || 1) - width: parent.width * pct - height: parent.height - radius: 2 - color: pct > 0.9 ? Theme.error : (pct > 0.75 ? Theme.warning : root.accentColor) - } - } - - StyledText { - text: ((modelData.used || 0) / (modelData.total || 1) * 100).toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - Layout.preferredWidth: 32 - horizontalAlignment: Text.AlignRight - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml deleted file mode 100644 index a275397..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml +++ /dev/null @@ -1,321 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - Ref { - service: CupsService - } - - ccWidgetIcon: CupsService.cupsAvailable && CupsService.getPrintersNum() > 0 ? "print" : "print_disabled" - ccWidgetPrimaryText: I18n.tr("Printers") - ccWidgetSecondaryText: { - if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) { - return I18n.tr("Printers: ") + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs: ") + CupsService.getTotalJobsNum(); - } else { - if (!CupsService.cupsAvailable) { - return I18n.tr("Print Server not available"); - } else { - return I18n.tr("No printer found"); - } - } - } - ccWidgetIsActive: CupsService.cupsAvailable && CupsService.getTotalJobsNum() > 0 - - onCcWidgetToggled: {} - - ccDetailContent: Component { - Rectangle { - id: detailRoot - implicitHeight: detailColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - iconName: "settings" - buttonSize: 24 - iconSize: 14 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("printers"); - } - } - - Column { - visible: !CupsService.cupsAvailable || CupsService.getPrintersNum() == 0 - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "print_disabled" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: !CupsService.cupsAvailable ? I18n.tr("Print Server not available") : I18n.tr("No printer found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - id: detailColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - visible: CupsService.cupsAvailable && CupsService.getPrintersNum() > 0 - height: visible ? 120 : 0 - - RowLayout { - spacing: Theme.spacingS - width: parent.width - - DankDropdown { - id: printerDropdown - text: "" - Layout.fillWidth: true - Layout.maximumWidth: parent.width - 180 - description: "" - currentValue: { - CupsService.getSelectedPrinter(); - } - options: CupsService.getPrintersNames() - onValueChanged: value => { - CupsService.setSelectedPrinter(value); - } - } - - Column { - spacing: Theme.spacingS - - StyledText { - text: CupsService.getCurrentPrinterStatePrettyShort() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - spacing: Theme.spacingM - - Rectangle { - height: 24 - width: 80 - radius: 14 - color: printerStatusToggle.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: true - opacity: 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: CupsService.getCurrentPrinterState() === "stopped" ? "play_arrow" : "pause" - size: Theme.fontSizeSmall + 4 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: CupsService.getCurrentPrinterState() === "stopped" ? I18n.tr("Resume") : I18n.tr("Pause") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: printerStatusToggle - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: true - onClicked: { - const selected = CupsService.getSelectedPrinter(); - if (CupsService.getCurrentPrinterState() === "stopped") { - CupsService.resumePrinter(selected); - } else { - CupsService.pausePrinter(selected); - } - } - } - } - - Rectangle { - height: 24 - width: 80 - radius: 14 - color: clearJobsToggle.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: true - opacity: 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "delete_forever" - size: Theme.fontSizeSmall + 4 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Jobs") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: clearJobsToggle - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: true - onClicked: { - const selected = CupsService.getSelectedPrinter(); - CupsService.purgeJobs(selected); - } - } - } - } - } - } - - Rectangle { - height: 1 - width: parent.width - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - DankFlickable { - width: parent.width - height: 160 - contentHeight: listCol.height - clip: true - - Column { - id: listCol - width: parent.width - spacing: Theme.spacingXS - - Item { - width: parent.width - height: 120 - visible: CupsService.getCurrentPrinterJobs().length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "work" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("The job queue of this printer is empty") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Repeater { - model: CupsService.getCurrentPrinterJobs() - - delegate: Rectangle { - required property var modelData - - width: parent ? parent.width : 300 - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.width: 1 - border.color: Theme.outlineLight - opacity: 1.0 - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "docs" - size: Theme.iconSize + 2 - color: Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Column { - spacing: 2 - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - - StyledText { - text: "[" + modelData.id + "] " + modelData.state + " (" + (modelData.size / 1024) + "kb)" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - var date = new Date(modelData.timeCreated); - return date.toLocaleString(Qt.locale(), Locale.ShortFormat); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Item { - Layout.fillWidth: true - } - } - - DankActionButton { - id: cancelJobButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "delete" - buttonSize: 36 - onClicked: { - CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id); - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml deleted file mode 100644 index 531045e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - Ref { - service: DMSNetworkService - } - - ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off") - ccWidgetPrimaryText: I18n.tr("VPN") - ccWidgetSecondaryText: { - if (!DMSNetworkService.connected) - return I18n.tr("Disconnected"); - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) - return names[0] || I18n.tr("Connected"); - return names[0] + " +" + (names.length - 1); - } - ccWidgetIsActive: DMSNetworkService.connected - - onCcWidgetToggled: DMSNetworkService.toggleVpn() - - ccDetailContent: Component { - VpnDetailContent { - listHeight: 260 - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml deleted file mode 100644 index d85c779..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml +++ /dev/null @@ -1,132 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - property string secondaryText: "" - property bool isActive: false - property bool enabled: true - property int widgetIndex: 0 - property var widgetData: null - property bool editMode: false - - signal clicked - - width: parent ? parent.width : 200 - height: 60 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - - color: isActive ? _tileBgActive : _tileBgInactive - border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: isActive ? 1 : 1 - opacity: enabled ? 1.0 : 0.6 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? hoverTint(root.color) : "transparent" - opacity: mouseArea.containsMouse ? 0.08 : 0.0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingL + 2 - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: isActive ? Theme.ccTileActiveText : Theme.ccTileInactiveIcon - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - Theme.iconSize - parent.spacing - height: parent.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Typography { - width: parent.width - text: root.text - style: Typography.Style.Body - color: isActive ? Theme.ccTileActiveText : Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - Typography { - width: parent.width - text: root.secondaryText - style: Typography.Style.Caption - color: isActive ? Theme.ccTileActiveText : Theme.surfaceVariantText - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml deleted file mode 100644 index a3b1156..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml +++ /dev/null @@ -1,250 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Details - -Item { - id: root - - property string expandedSection: "" - property var expandedWidgetData: null - property var bluetoothCodecSelector: null - property string screenName: "" - property string screenModel: "" - - property var pluginDetailInstance: null - property var widgetModel: null - property var collapseCallback: null - property real maxAvailableHeight: 9999 - - function getDetailHeight(section) { - switch (true) { - case section === "wifi": - case section === "bluetooth": - case section === "builtin_vpn": - return Math.min(350, maxAvailableHeight); - case section.startsWith("brightnessSlider_"): - return Math.min(400, maxAvailableHeight); - case section.startsWith("plugin_"): - if (pluginDetailInstance?.ccDetailHeight) - return Math.min(pluginDetailInstance.ccDetailHeight, maxAvailableHeight); - return Math.min(250, maxAvailableHeight); - default: - return Math.min(250, maxAvailableHeight); - } - } - - Loader { - id: pluginDetailLoader - width: parent.width - height: parent.height - Theme.spacingS - y: Theme.spacingS - active: false - sourceComponent: null - } - - Loader { - id: coreDetailLoader - width: parent.width - height: parent.height - Theme.spacingS - y: Theme.spacingS - active: false - sourceComponent: null - } - - Connections { - target: coreDetailLoader.item - enabled: root.expandedSection.startsWith("brightnessSlider_") - ignoreUnknownSignals: true - - function onDeviceNameChanged(newDeviceName) { - if (root.expandedWidgetData && root.expandedWidgetData.id === "brightnessSlider") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "brightnessSlider" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.deviceName = newDeviceName; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - if (root.collapseCallback) { - root.collapseCallback(); - } - } - } - } - - Connections { - target: coreDetailLoader.item - enabled: root.expandedSection.startsWith("diskUsage_") - ignoreUnknownSignals: true - - function onMountPathChanged(newMountPath) { - if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.mountPath = newMountPath; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - if (root.collapseCallback) { - root.collapseCallback(); - } - } - } - } - - onExpandedSectionChanged: { - if (pluginDetailInstance) { - pluginDetailInstance.destroy(); - pluginDetailInstance = null; - } - pluginDetailLoader.active = false; - coreDetailLoader.active = false; - - if (!root.expandedSection) { - return; - } - - if (root.expandedSection.startsWith("builtin_")) { - const builtinId = root.expandedSection; - let builtinInstance = null; - - if (builtinId === "builtin_vpn") { - if (widgetModel?.vpnLoader) { - widgetModel.vpnLoader.active = true; - } - builtinInstance = widgetModel.vpnBuiltinInstance; - } - if (builtinId === "builtin_cups") { - if (widgetModel?.cupsLoader) { - widgetModel.cupsLoader.active = true; - } - builtinInstance = widgetModel.cupsBuiltinInstance; - } - - if (!builtinInstance || !builtinInstance.ccDetailContent) { - return; - } - - pluginDetailLoader.sourceComponent = builtinInstance.ccDetailContent; - pluginDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("plugin_")) { - const pluginId = root.expandedSection.replace("plugin_", ""); - const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; - if (!pluginComponent) { - return; - } - - pluginDetailInstance = pluginComponent.createObject(null); - if (!pluginDetailInstance || !pluginDetailInstance.ccDetailContent) { - if (pluginDetailInstance) { - pluginDetailInstance.destroy(); - pluginDetailInstance = null; - } - return; - } - - pluginDetailLoader.sourceComponent = pluginDetailInstance.ccDetailContent; - pluginDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("diskUsage_")) { - coreDetailLoader.sourceComponent = diskUsageDetailComponent; - coreDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("brightnessSlider_")) { - coreDetailLoader.sourceComponent = brightnessDetailComponent; - coreDetailLoader.active = parent.height > 0; - return; - } - - switch (root.expandedSection) { - case "network": - case "wifi": - coreDetailLoader.sourceComponent = networkDetailComponent; - break; - case "bluetooth": - coreDetailLoader.sourceComponent = bluetoothDetailComponent; - break; - case "audioOutput": - coreDetailLoader.sourceComponent = audioOutputDetailComponent; - break; - case "audioInput": - coreDetailLoader.sourceComponent = audioInputDetailComponent; - break; - case "battery": - coreDetailLoader.sourceComponent = batteryDetailComponent; - break; - default: - return; - } - - coreDetailLoader.active = parent.height > 0; - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail { - id: bluetoothDetail - onShowCodecSelector: function (device) { - if (root.bluetoothCodecSelector) { - root.bluetoothCodecSelector.show(device); - root.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) { - bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName); - }); - } - } - } - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - Component { - id: diskUsageDetailComponent - DiskUsageDetail { - currentMountPath: root.expandedWidgetData?.mountPath || "/" - instanceId: root.expandedWidgetData?.instanceId || "" - } - } - - Component { - id: brightnessDetailComponent - BrightnessDetail { - initialDeviceName: root.expandedWidgetData?.deviceName || "" - instanceId: root.expandedWidgetData?.instanceId || "" - screenName: root.screenName - screenModel: root.screenModel - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml deleted file mode 100644 index 4a7ff19..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml +++ /dev/null @@ -1,91 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.ControlCenter.Details - -Item { - id: root - - property string expandedSection: "" - property var expandedWidgetData: null - - height: active ? 250 : 0 - visible: active - - readonly property bool active: expandedSection !== "" - - Loader { - anchors.fill: parent - anchors.topMargin: Theme.spacingS - sourceComponent: { - if (!root.active) - return null; - - if (expandedSection.startsWith("diskUsage_")) { - return diskUsageDetailComponent; - } - - switch (expandedSection) { - case "wifi": - return networkDetailComponent; - case "bluetooth": - return bluetoothDetailComponent; - case "audioOutput": - return audioOutputDetailComponent; - case "audioInput": - return audioInputDetailComponent; - case "battery": - return batteryDetailComponent; - default: - return null; - } - } - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail {} - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - Component { - id: diskUsageDetailComponent - DiskUsageDetail { - currentMountPath: root.expandedWidgetData?.mountPath || "/" - instanceId: root.expandedWidgetData?.instanceId || "" - - onMountPathChanged: newMountPath => { - if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.mountPath = newMountPath; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml deleted file mode 100644 index 4cdd979..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml +++ /dev/null @@ -1,1091 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets -import qs.Modules.ControlCenter.Components -import "../utils/layout.js" as LayoutUtils - -Column { - id: root - - property bool editMode: false - property string expandedSection: "" - property int expandedWidgetIndex: -1 - property var model: null - property var expandedWidgetData: null - property var bluetoothCodecSelector: null - property bool darkModeTransitionPending: false - property string screenName: "" - property string screenModel: "" - property var parentScreen: null - - signal expandClicked(var widgetData, int globalIndex) - signal removeWidget(int index) - signal moveWidget(int fromIndex, int toIndex) - signal toggleWidgetSize(int index) - signal collapseRequested - - function requestCollapse() { - collapseRequested(); - } - - spacing: editMode ? Theme.spacingL : Theme.spacingS - - property real maxPopoutHeight: 9999 - property var currentRowWidgets: [] - property real currentRowWidth: 0 - property int expandedRowIndex: -1 - property var colorPickerModal: null - - readonly property real _maxDetailHeight: { - const rows = layoutResult.rows; - let totalRowHeight = 0; - for (let i = 0; i < rows.length; i++) { - const sliderOnly = rows[i].every(w => { - const id = w.id || ""; - return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; - }); - totalRowHeight += sliderOnly ? 36 : 60; - } - const rowSpacing = Math.max(0, rows.length - 1) * spacing; - return Math.max(100, maxPopoutHeight - totalRowHeight - rowSpacing); - } - - function calculateRowsAndWidgets() { - return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex); - } - - property var layoutResult: { - const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]; - return calculateRowsAndWidgets(); - } - - onLayoutResultChanged: { - expandedRowIndex = layoutResult.expandedRowIndex; - } - - function moveToTop(item) { - const children = root.children; - for (var i = 0; i < children.length; i++) { - if (children[i] === item) - continue; - if (children[i].z) - children[i].z = Math.min(children[i].z, 999); - } - item.z = 1000; - } - - Repeater { - model: root.layoutResult.rows - - Column { - width: root.width - spacing: 0 - property int rowIndex: index - property var rowWidgets: modelData - property bool isSliderOnlyRow: { - const widgets = rowWidgets || []; - if (widgets.length === 0) - return false; - return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider"); - } - topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 - bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 - - Flow { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: rowWidgets || [] - - DragDropWidgetWrapper { - widgetData: modelData - property int globalWidgetIndex: { - const widgets = SettingsData.controlCenterWidgets || []; - for (var i = 0; i < widgets.length; i++) { - if (widgets[i].id === modelData.id) { - if (modelData.id === "diskUsage" || modelData.id === "brightnessSlider") { - if (widgets[i].instanceId === modelData.instanceId) { - return i; - } - } else { - return i; - } - } - } - return -1; - } - property int widgetWidth: modelData.width || 50 - width: { - const baseWidth = root.width; - const spacing = Theme.spacingS; - if (widgetWidth <= 25) { - return (baseWidth - spacing * 3) / 4; - } else if (widgetWidth <= 50) { - return (baseWidth - spacing) / 2; - } else if (widgetWidth <= 75) { - return (baseWidth - spacing * 2) * 0.75; - } else { - return baseWidth; - } - } - height: isSliderOnlyRow ? 48 : 60 - - editMode: root.editMode - widgetIndex: globalWidgetIndex - gridCellWidth: width - gridCellHeight: height - gridColumns: 4 - gridLayout: root - isSlider: { - const id = modelData.id || ""; - return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; - } - - widgetComponent: { - const id = modelData.id || ""; - if (id.startsWith("builtin_")) { - return builtinPluginWidgetComponent; - } else if (id.startsWith("plugin_")) { - return pluginWidgetComponent; - } else if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") { - return compoundPillComponent; - } else if (id === "volumeSlider") { - return audioSliderComponent; - } else if (id === "brightnessSlider") { - return brightnessSliderComponent; - } else if (id === "inputVolumeSlider") { - return inputAudioSliderComponent; - } else if (id === "battery") { - return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent; - } else if (id === "diskUsage") { - return widgetWidth <= 25 ? smallDiskUsageComponent : diskUsagePillComponent; - } else if (id === "colorPicker") { - return colorPickerPillComponent; - } else { - return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent; - } - } - - onWidgetMoved: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex) - onRemoveWidget: index => root.removeWidget(index) - onToggleWidgetSize: index => root.toggleWidgetSize(index) - } - } - } - - DetailHost { - id: detailHost - width: parent.width - maxAvailableHeight: root._maxDetailHeight - height: active ? (getDetailHeight(root.expandedSection) + Theme.spacingS) : 0 - property bool active: { - if (root.expandedSection === "") - return false; - - if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) { - const expandedInstanceId = root.expandedWidgetData.instanceId; - return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId); - } - - if (root.expandedSection.startsWith("brightnessSlider_") && root.expandedWidgetData) { - const expandedInstanceId = root.expandedWidgetData.instanceId; - return rowWidgets.some(w => w.id === "brightnessSlider" && w.instanceId === expandedInstanceId); - } - - return rowIndex === root.expandedRowIndex; - } - visible: active - expandedSection: root.expandedSection - expandedWidgetData: root.expandedWidgetData - bluetoothCodecSelector: root.bluetoothCodecSelector - widgetModel: root.model - collapseCallback: root.requestCollapse - screenName: root.screenName - screenModel: root.screenModel - } - } - } - - Component { - id: errorPillComponent - ErrorPill { - property var widgetData: parent.widgetData || {} - width: parent.width - height: 60 - primaryMessage: { - if (!DMSService.dmsAvailable) { - return I18n.tr("DMS_SOCKET not available"); - } - return I18n.tr("NM not supported"); - } - secondaryMessage: I18n.tr("update dms for NM integration.") - } - } - - Component { - id: compoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - width: parent.width - height: 60 - iconName: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return "sync"; - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return "settings_ethernet"; - if (status === "vpn") - return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon; - if (status === "wifi") - return NetworkService.wifiSignalIcon; - if (NetworkService.wifiEnabled) - return "wifi_off"; - return "wifi_off"; - } - case "bluetooth": - { - if (!BluetoothService.available) - return "bluetooth_disabled"; - if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) - return "bluetooth_disabled"; - return "bluetooth"; - } - case "audioOutput": - { - if (!AudioService.sink) - return "volume_off"; - let volume = AudioService.sink.audio.volume; - let muted = AudioService.sink.audio.muted; - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - case "audioInput": - { - if (!AudioService.source) - return "mic_off"; - let muted = AudioService.source.audio.muted; - return muted ? "mic_off" : "mic"; - } - default: - return widgetDef?.icon || "help"; - } - } - primaryText: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...", "network status") : I18n.tr("Enabling WiFi...", "network status"); - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return I18n.tr("Ethernet", "network status"); - if (status === "vpn") { - if (NetworkService.ethernetConnected) - return I18n.tr("Ethernet", "network status"); - if (NetworkService.wifiConnected && NetworkService.currentWifiSSID) - return NetworkService.currentWifiSSID; - } - if (status === "wifi" && NetworkService.currentWifiSSID) - return NetworkService.currentWifiSSID; - if (NetworkService.wifiEnabled) - return I18n.tr("Not connected", "network status"); - return I18n.tr("WiFi off", "network status"); - } - case "bluetooth": - { - if (!BluetoothService.available) - return I18n.tr("Bluetooth", "bluetooth status"); - if (!BluetoothService.adapter) - return I18n.tr("No adapter", "bluetooth status"); - if (!BluetoothService.adapter.enabled) - return I18n.tr("Disabled", "bluetooth status"); - return I18n.tr("Enabled", "bluetooth status"); - } - case "audioOutput": - return AudioService.sink?.description || I18n.tr("No output device", "audio status"); - case "audioInput": - return AudioService.source?.description || I18n.tr("No input device", "audio status"); - default: - return widgetDef?.text || I18n.tr("Unknown", "widget status"); - } - } - secondaryText: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return I18n.tr("Please wait...", "network status"); - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return I18n.tr("Connected", "network status"); - if (status === "vpn") { - if (NetworkService.ethernetConnected) - return I18n.tr("Connected", "network status"); - if (NetworkService.wifiConnected) - return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); - } - if (status === "wifi") - return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); - if (NetworkService.wifiEnabled) - return I18n.tr("Select network", "network status"); - return ""; - } - case "bluetooth": - { - if (!BluetoothService.available) - return I18n.tr("No adapters", "bluetooth status"); - if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) - return I18n.tr("Off", "bluetooth status"); - const primaryDevice = (() => { - if (!BluetoothService.adapter || !BluetoothService.adapter.devices) - return null; - let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]; - for (let device of devices) { - if (device && device.connected) - return device; - } - return null; - })(); - if (primaryDevice) - return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || I18n.tr("Connected Device", "bluetooth status"); - return I18n.tr("No devices", "bluetooth status"); - } - case "audioOutput": - { - if (!AudioService.sink) - return I18n.tr("Select device", "audio status"); - if (AudioService.sink.audio.muted) - return I18n.tr("Muted", "audio status"); - const volume = AudioService.sink.audio.volume; - if (typeof volume !== "number" || isNaN(volume)) - return "0%"; - return Math.round(volume * 100) + "%"; - } - case "audioInput": - { - if (!AudioService.source) - return I18n.tr("Select device", "audio status"); - if (AudioService.source.audio.muted) - return I18n.tr("Muted", "audio status"); - const volume = AudioService.source.audio.volume; - if (typeof volume !== "number" || isNaN(volume)) - return "0%"; - return Math.round(volume * 100) + "%"; - } - default: - return widgetDef?.description || ""; - } - } - isActive: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return false; - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return true; - if (status === "vpn") - return NetworkService.ethernetConnected || NetworkService.wifiConnected; - if (status === "wifi") - return true; - return NetworkService.wifiEnabled; - } - case "bluetooth": - return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled); - case "audioOutput": - return !!(AudioService.sink && !AudioService.sink.audio.muted); - case "audioInput": - return !!(AudioService.source && !AudioService.source.audio.muted); - default: - return false; - } - } - enabled: widgetDef?.enabled ?? true - onToggled: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) { - NetworkService.toggleWifiRadio(); - } - break; - } - case "bluetooth": - { - if (BluetoothService.available && BluetoothService.adapter) { - BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled; - } - break; - } - case "audioOutput": - { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.muted = !AudioService.sink.audio.muted; - } - break; - } - case "audioInput": - { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.muted = !AudioService.source.audio.muted; - } - break; - } - } - } - onExpandClicked: { - if (root.editMode) - return; - root.expandClicked(widgetData, widgetIndex); - } - onWheelEvent: function (wheelEvent) { - if (root.editMode) - return; - const id = widgetData.id || ""; - if (id === "audioOutput") { - if (!AudioService.sink || !AudioService.sink.audio) - return; - let delta = wheelEvent.angleDelta.y; - let maxVol = AudioService.sinkMaxVolume; - let currentVolume = AudioService.sink.audio.volume * 100; - let newVolume; - if (delta > 0) - newVolume = Math.min(maxVol, currentVolume + 5); - else - newVolume = Math.max(0, currentVolume - 5); - AudioService.sink.audio.muted = false; - AudioService.sink.audio.volume = newVolume / 100; - wheelEvent.accepted = true; - } else if (id === "audioInput") { - if (!AudioService.source || !AudioService.source.audio) - return; - let delta = wheelEvent.angleDelta.y; - let currentVolume = AudioService.source.audio.volume * 100; - let newVolume; - if (delta > 0) - newVolume = Math.min(100, currentVolume + 5); - else - newVolume = Math.max(0, currentVolume - 5); - AudioService.source.audio.muted = false; - AudioService.source.audio.volume = newVolume / 100; - wheelEvent.accepted = true; - } - } - } - } - - Component { - id: audioSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - AudioSliderRow { - anchors.centerIn: parent - width: parent.width - height: 14 - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - } - } - } - - Component { - id: brightnessSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - BrightnessSliderRow { - id: brightnessSliderRow - anchors.centerIn: parent - width: parent.width - height: 14 - deviceName: widgetData.deviceName || "" - instanceId: widgetData.instanceId || "" - screenName: root.screenName - parentScreen: root.parentScreen - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onIconClicked: { - if (!root.editMode && DisplayService.devices && DisplayService.devices.length > 1) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - } - - Component { - id: inputAudioSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - InputAudioSliderRow { - anchors.centerIn: parent - width: parent.width - height: 14 - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - } - } - } - - Component { - id: batteryPillComponent - BatteryPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - onExpandClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: smallBatteryComponent - SmallBatteryButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - onClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: toggleButtonComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - iconName: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; - case "darkMode": - return "contrast"; - case "doNotDisturb": - return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; - case "idleInhibitor": - return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; - default: - return "help"; - } - } - - text: { - switch (widgetData.id || "") { - case "nightMode": - return I18n.tr("Night Mode"); - case "darkMode": - return I18n.tr("Dark Mode"); - case "doNotDisturb": - return I18n.tr("Do Not Disturb"); - case "idleInhibitor": - return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake"); - default: - return I18n.tr("Unknown", "widget status"); - } - } - - iconRotation: { - if (widgetData.id !== "darkMode") - return 0; - if (darkModeTransitionPending) { - return SessionData.isLightMode ? 180 : 0; - } - return SessionData.isLightMode ? 180 : 0; - } - - isActive: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled || false; - case "darkMode": - return !SessionData.isLightMode; - case "doNotDisturb": - return SessionData.doNotDisturb || false; - case "idleInhibitor": - return SessionService.idleInhibited || false; - default: - return false; - } - } - - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "nightMode": - { - if (DisplayService.automationAvailable) - DisplayService.toggleNightMode(); - break; - } - case "darkMode": - { - const newMode = !SessionData.isLightMode; - Theme.screenTransition(); - Theme.setLightMode(newMode); - break; - } - case "doNotDisturb": - { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - break; - } - case "idleInhibitor": - { - SessionService.toggleIdleInhibit(); - break; - } - } - } - } - } - - Component { - id: smallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - iconName: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; - case "darkMode": - return "contrast"; - case "doNotDisturb": - return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; - case "idleInhibitor": - return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; - default: - return "help"; - } - } - - iconRotation: { - if (widgetData.id !== "darkMode") - return 0; - if (darkModeTransitionPending) { - return SessionData.isLightMode ? 180 : 0; - } - return SessionData.isLightMode ? 180 : 0; - } - - isActive: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled || false; - case "darkMode": - return !SessionData.isLightMode; - case "doNotDisturb": - return SessionData.doNotDisturb || false; - case "idleInhibitor": - return SessionService.idleInhibited || false; - default: - return false; - } - } - - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "nightMode": - { - if (DisplayService.automationAvailable) - DisplayService.toggleNightMode(); - break; - } - case "darkMode": - { - const newMode = !SessionData.isLightMode; - Theme.screenTransition(); - Theme.setLightMode(newMode); - break; - } - case "doNotDisturb": - { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - break; - } - case "idleInhibitor": - { - SessionService.toggleIdleInhibit(); - break; - } - } - } - } - } - - Component { - id: diskUsagePillComponent - DiskUsagePill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - mountPath: widgetData.mountPath || "/" - instanceId: widgetData.instanceId || "" - - onExpandClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: smallDiskUsageComponent - SmallDiskUsageButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - mountPath: widgetData.mountPath || "/" - instanceId: widgetData.instanceId || "" - - onClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: colorPickerPillComponent - ColorPickerPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - colorPickerModal: root.colorPickerModal - } - } - - Component { - id: builtinPluginWidgetComponent - Loader { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property int widgetWidth: widgetData.width || 50 - width: parent.width - height: 60 - - property var builtinInstance: null - - Component.onCompleted: { - const id = widgetData.id || ""; - if (id === "builtin_vpn") { - if (root.model?.vpnLoader) { - root.model.vpnLoader.active = true; - } - builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance); - } - if (id === "builtin_cups") { - if (root.model?.cupsLoader) { - root.model.cupsLoader.active = true; - } - builtinInstance = Qt.binding(() => root.model?.cupsBuiltinInstance); - } - } - - sourceComponent: { - if (!builtinInstance) - return null; - - const hasDetail = builtinInstance.ccDetailContent !== null; - - if (widgetWidth <= 25) { - return builtinSmallToggleComponent; - } else if (hasDetail) { - return builtinCompoundPillComponent; - } else { - return builtinToggleComponent; - } - } - } - } - - Component { - id: builtinCompoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - primaryText: builtinInstance?.ccWidgetPrimaryText || "Built-in" - secondaryText: builtinInstance?.ccWidgetSecondaryText || "" - isActive: builtinInstance?.ccWidgetIsActive || false - - onToggled: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - - onExpandClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetExpanded(); - } - root.expandClicked(widgetData, widgetIndex); - } - } - } - - Component { - id: builtinToggleComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - text: builtinInstance?.ccWidgetPrimaryText || "Built-in" - isActive: builtinInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: builtinSmallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - isActive: builtinInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: pluginWidgetComponent - Loader { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property int widgetWidth: widgetData.width || 50 - width: parent.width - height: 60 - - property var pluginInstance: null - property string pluginId: widgetData.id?.replace("plugin_", "") || "" - - sourceComponent: { - if (!pluginInstance) - return null; - - const hasDetail = pluginInstance.ccDetailContent !== null; - - if (widgetWidth <= 25) { - return pluginSmallToggleComponent; - } else if (hasDetail) { - return pluginCompoundPillComponent; - } else { - return pluginToggleComponent; - } - } - - function tryCreatePluginInstance() { - const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; - if (!pluginComponent) - return false; - try { - const instance = pluginComponent.createObject(null, { - "pluginId": pluginId, - "pluginService": PluginService, - "visible": false, - "width": 0, - "height": 0 - }); - if (instance) { - pluginInstance = instance; - return true; - } - } catch (e) { - console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading"); - PluginService.reloadPlugin(pluginId); - } - return false; - } - - Component.onCompleted: { - Qt.callLater(() => tryCreatePluginInstance()); - } - - Connections { - target: PluginService - function onPluginDataChanged(changedPluginId) { - if (changedPluginId === pluginId && pluginInstance) { - pluginInstance.loadPluginData(); - } - } - function onPluginLoaded(loadedPluginId) { - if (loadedPluginId !== pluginId || pluginInstance) - return; - Qt.callLater(() => tryCreatePluginInstance()); - } - } - - Component.onDestruction: { - if (pluginInstance) { - pluginInstance.destroy(); - } - } - } - } - - Component { - id: pluginCompoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - - iconName: pluginInstance?.ccWidgetIcon || "extension" - primaryText: pluginInstance?.ccWidgetPrimaryText || "Plugin" - secondaryText: pluginInstance?.ccWidgetSecondaryText || "" - isActive: pluginInstance?.ccWidgetIsActive || false - - onToggled: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - - onExpandClicked: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetExpanded(); - } - root.expandClicked(widgetData, widgetIndex); - } - } - } - - Component { - id: pluginToggleComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - - iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" - text: pluginInstance?.ccWidgetPrimaryText || widgetDef?.text || "Plugin" - secondaryText: pluginInstance?.ccWidgetSecondaryText || "" - isActive: pluginInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: pluginSmallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - - iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" - isActive: pluginInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (pluginInstance && pluginInstance.ccDetailContent) { - root.expandClicked(widgetData, widgetIndex); - } else if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml deleted file mode 100644 index 7cb0e2c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml +++ /dev/null @@ -1,289 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool editMode: false - property var widgetData: null - property int widgetIndex: -1 - property bool isSlider: false - property Component widgetComponent: null - property real gridCellWidth: 100 - property real gridCellHeight: 60 - property int gridColumns: 4 - property var gridLayout: null - - z: dragArea.drag.active ? 10000 : 1 - - signal widgetMoved(int fromIndex, int toIndex) - signal removeWidget(int index) - signal toggleWidgetSize(int index) - - width: { - const widgetWidth = widgetData?.width || 50 - if (widgetWidth <= 25) return gridCellWidth - else if (widgetWidth <= 50) return gridCellWidth * 2 - else if (widgetWidth <= 75) return gridCellWidth * 3 - else return gridCellWidth * 4 - } - height: isSlider ? 16 : gridCellHeight - - Rectangle { - id: dragIndicator - anchors.fill: parent - color: "transparent" - border.color: Theme.primary - border.width: dragArea.drag.active ? 2 : 0 - radius: Theme.cornerRadius - opacity: dragArea.drag.active ? 0.8 : 1.0 - z: dragArea.drag.active ? 10000 : 1 - - Behavior on border.width { - NumberAnimation { duration: 150 } - } - Behavior on opacity { - NumberAnimation { duration: 150 } - } - } - - Loader { - id: widgetLoader - anchors.fill: parent - sourceComponent: widgetComponent - property var widgetData: root.widgetData - property int widgetIndex: root.widgetIndex - property int globalWidgetIndex: root.widgetIndex - property int widgetWidth: root.widgetData?.width || 50 - - - MouseArea { - id: editModeBlocker - anchors.fill: parent - enabled: root.editMode - acceptedButtons: Qt.AllButtons - onPressed: function(mouse) { mouse.accepted = true } - onWheel: function(wheel) { wheel.accepted = true } - z: 100 - } - } - - MouseArea { - id: dragArea - anchors.fill: parent - enabled: editMode - cursorShape: editMode ? Qt.OpenHandCursor : Qt.PointingHandCursor - drag.target: editMode ? root : null - drag.axis: Drag.XAndYAxis - drag.smoothed: true - - onPressed: function(mouse) { - if (editMode) { - cursorShape = Qt.ClosedHandCursor - if (root.gridLayout && root.gridLayout.moveToTop) { - root.gridLayout.moveToTop(root) - } - } - } - - onReleased: function(mouse) { - if (editMode) { - cursorShape = Qt.OpenHandCursor - root.snapToGrid() - } - } - } - - Drag.active: dragArea.drag.active - Drag.hotSpot.x: width / 2 - Drag.hotSpot.y: height / 2 - - function swapIndices(i, j) { - if (i === j) return; - const arr = SettingsData.controlCenterWidgets; - if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length) return; - - const copy = arr.slice(); - const tmp = copy[i]; - copy[i] = copy[j]; - copy[j] = tmp; - - SettingsData.set("controlCenterWidgets", copy); - } - - function snapToGrid() { - if (!editMode || !gridLayout) return - - const globalPos = root.mapToItem(gridLayout, 0, 0) - const cellWidth = gridLayout.width / gridColumns - const cellHeight = gridCellHeight + Theme.spacingS - - const centerX = globalPos.x + (root.width / 2) - const centerY = globalPos.y + (root.height / 2) - - let targetCol = Math.max(0, Math.floor(centerX / cellWidth)) - let targetRow = Math.max(0, Math.floor(centerY / cellHeight)) - - targetCol = Math.min(targetCol, gridColumns - 1) - - const newIndex = findBestInsertionIndex(targetRow, targetCol) - - if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) { - swapIndices(widgetIndex, newIndex) - } - } - - function findBestInsertionIndex(targetRow, targetCol) { - const widgets = SettingsData.controlCenterWidgets || []; - const n = widgets.length; - if (!n || widgetIndex < 0 || widgetIndex >= n) return -1; - - function spanFor(width) { - const w = width ?? 50; - if (w <= 25) return 1; - if (w <= 50) return 2; - if (w <= 75) return 3; - return 4; - } - - const cols = gridColumns || 4; - - let row = 0, col = 0; - let draggedOrigKey = null; - - const pos = []; - - for (let i = 0; i < n; i++) { - const span = Math.min(spanFor(widgets[i].width), cols); - - if (col + span > cols) { - row++; - col = 0; - } - - const startCol = col; - const centerKey = row * cols + (startCol + (span - 1) / 2); - - if (i === widgetIndex) { - draggedOrigKey = centerKey; - } else { - pos.push({ index: i, row, startCol, span, centerKey }); - } - - col += span; - if (col >= cols) { - row++; - col = 0; - } - } - - if (pos.length === 0) return -1; - - const centerColCoord = targetCol + 0.5; - const targetKey = targetRow * cols + centerColCoord; - - for (let k = 0; k < pos.length; k++) { - const p = pos[k]; - if (p.row === targetRow && centerColCoord >= p.startCol && centerColCoord < (p.startCol + p.span)) { - return p.index; - } - } - - let lo = 0, hi = pos.length - 1; - if (targetKey <= pos[0].centerKey) return pos[0].index; - if (targetKey >= pos[hi].centerKey) return pos[hi].index; - - while (lo <= hi) { - const mid = (lo + hi) >> 1; - const mk = pos[mid].centerKey; - if (targetKey < mk) hi = mid - 1; - else if (targetKey > mk) lo = mid + 1; - else return pos[mid].index; - } - const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false; - return (movingUp ? pos[lo].index : pos[hi].index); - } - - Rectangle { - width: 16 - height: 16 - radius: 8 - color: Theme.error - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: -4 - visible: editMode - z: 10 - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: Theme.primaryText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: removeWidget(widgetIndex) - } - } - - SizeControls { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: -6 - visible: editMode - z: 10 - currentSize: root.widgetData?.width || 50 - isSlider: root.isSlider - widgetIndex: root.widgetIndex - onSizeChanged: (newSize) => { - var widgets = SettingsData.controlCenterWidgets.slice() - if (widgetIndex >= 0 && widgetIndex < widgets.length) { - widgets[widgetIndex].width = newSize - SettingsData.set("controlCenterWidgets", widgets) - } - } - } - - Rectangle { - id: dragHandle - width: 16 - height: 12 - radius: 2 - color: Theme.primary - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: 4 - visible: editMode - z: 15 - opacity: dragArea.drag.active ? 1.0 : 0.7 - - DankIcon { - anchors.centerIn: parent - name: "drag_indicator" - size: 10 - color: Theme.primaryText - } - - Behavior on opacity { - NumberAnimation { duration: 150 } - } - } - - Rectangle { - anchors.fill: parent - color: editMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius - border.color: "transparent" - border.width: 0 - z: -1 - - Behavior on color { - ColorAnimation { duration: Theme.shortDuration } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml deleted file mode 100644 index 50531aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml +++ /dev/null @@ -1,245 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var availableWidgets: [] - property Item popoutContent: null - - signal addWidget(string widgetId) - signal resetToDefault - signal clearAll - - height: 48 - spacing: Theme.spacingS - - onAddWidget: addWidgetPopup.close() - - Popup { - id: addWidgetPopup - parent: popoutContent - x: parent ? Math.round((parent.width - width) / 2) : 0 - y: parent ? Math.round((parent.height - height) / 2) : 0 - width: 400 - height: 300 - modal: false - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Theme.primarySelected - border.width: 0 - radius: Theme.cornerRadius - } - - contentItem: Item { - anchors.fill: parent - anchors.margins: Theme.spacingL - - Row { - id: headerRow - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Add Widget") - style: Typography.Style.Subtitle - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankListView { - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - spacing: Theme.spacingS - clip: true - model: root.availableWidgets - - delegate: Rectangle { - width: 400 - Theme.spacingL * 2 - height: 50 - radius: Theme.cornerRadius - color: widgetMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: 400 - Theme.spacingL * 2 - Theme.iconSize - Theme.spacingM * 3 - Theme.iconSize - - Typography { - text: modelData.text - style: Typography.Style.Body - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Typography { - text: modelData.description - style: Typography.Style.Caption - color: Theme.outline - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.addWidget(modelData.id); - } - } - } - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - border.color: Theme.primary - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "add" - size: Theme.iconSize - 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Add Widget") - style: Typography.Style.Button - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: addWidgetPopup.open() - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - border.color: Theme.warning - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "settings_backup_restore" - size: Theme.iconSize - 2 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Defaults") - style: Typography.Style.Button - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.resetToDefault() - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Theme.error - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "clear_all" - size: Theme.iconSize - 2 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Reset") - style: Typography.Style.Button - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.clearAll() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml deleted file mode 100644 index d36c5b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool editMode: false - - signal powerButtonClicked - signal lockRequested - signal editModeToggled - signal settingsButtonClicked - - Component.onCompleted: DgopService.addRef("system") - Component.onDestruction: DgopService.removeRef("system") - - implicitHeight: 70 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingM - - DankCircularImage { - id: avatarContainer - - width: 60 - height: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - - if (PortalService.profileImage.startsWith("/")) - return "file://" + PortalService.profileImage; - - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Typography { - text: UserInfoService.fullName || UserInfoService.username || I18n.tr("User") - style: Typography.Style.Subtitle - color: Theme.surfaceText - } - - Typography { - text: DgopService.uptime || I18n.tr("Unknown") - style: Typography.Style.Caption - color: Theme.surfaceVariantText - } - } - } - - Row { - id: actionButtonsRow - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingXS - spacing: Theme.spacingXS - - DankActionButton { - buttonSize: 36 - iconName: "lock" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: { - root.lockRequested(); - } - } - - DankActionButton { - buttonSize: 36 - iconName: "power_settings_new" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: root.powerButtonClicked() - } - - DankActionButton { - buttonSize: 36 - iconName: "settings" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: { - root.settingsButtonClicked(); - PopoutService.focusOrToggleSettings(); - } - } - - DankActionButton { - buttonSize: 36 - iconName: editMode ? "done" : "edit" - iconSize: Theme.iconSize - 4 - iconColor: editMode ? Theme.primary : Theme.surfaceText - backgroundColor: "transparent" - onClicked: root.editModeToggled() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml deleted file mode 100644 index 8ed7444..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml +++ /dev/null @@ -1,55 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - - signal pressed - - height: 34 - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: root.iconName - size: Theme.fontSizeSmall - color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: root.text - style: Typography.Style.Button - color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - ripple.trigger(mouse.x, mouse.y); - root.pressed(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml deleted file mode 100644 index aeae4ee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml +++ /dev/null @@ -1,52 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Row { - id: root - - property int currentSize: 50 - property bool isSlider: false - property int widgetIndex: -1 - - signal sizeChanged(int newSize) - - readonly property var availableSizes: isSlider ? [50, 75, 100] : [25, 50, 75, 100] - - spacing: 2 - - Repeater { - model: root.availableSizes - - Rectangle { - width: 16 - height: 16 - radius: 3 - color: modelData === root.currentSize ? Theme.primary : Theme.surfaceContainer - border.color: modelData === root.currentSize ? Theme.primary : Theme.outline - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: modelData.toString() - font.pixelSize: 8 - font.weight: Font.Medium - color: modelData === root.currentSize ? Theme.primaryText : Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - root.currentSize = modelData - root.sizeChanged(modelData) - } - } - - Behavior on color { - ColorAnimation { duration: Theme.shortDuration } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml deleted file mode 100644 index f3e554f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledText { - id: root - - enum Style { - Title, - Subtitle, - Body, - Caption, - Button - } - - property int style: Typography.Style.Body - - font.pixelSize: { - switch (style) { - case Typography.Style.Title: return Theme.fontSizeXLarge - case Typography.Style.Subtitle: return Theme.fontSizeLarge - case Typography.Style.Body: return Theme.fontSizeMedium - case Typography.Style.Caption: return Theme.fontSizeSmall - case Typography.Style.Button: return Theme.fontSizeSmall - default: return Theme.fontSizeMedium - } - } - - font.weight: { - switch (style) { - case Typography.Style.Title: return Font.Bold - case Typography.Style.Subtitle: return Font.Medium - case Typography.Style.Body: return Font.Normal - case Typography.Style.Caption: return Font.Normal - case Typography.Style.Button: return Font.Medium - default: return Font.Normal - } - } - - color: { - switch (style) { - case Typography.Style.Caption: return Theme.surfaceVariantText - default: return Theme.surfaceText - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml deleted file mode 100644 index d8839aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml +++ /dev/null @@ -1,272 +0,0 @@ -import QtQuick -import Quickshell.Wayland -import qs.Common -import qs.Modules.ControlCenter.Details -import qs.Services -import qs.Widgets -import qs.Modules.ControlCenter.Components -import qs.Modules.ControlCenter.Models -import "./utils/state.js" as StateUtils - -DankPopout { - id: root - - layerNamespace: "dms:control-center" - fullHeightSurface: true - - property string expandedSection: "" - property var triggerScreen: null - property bool editMode: false - property int expandedWidgetIndex: -1 - property var expandedWidgetData: null - property bool powerMenuOpen: powerMenuModalLoader?.item?.shouldBeVisible ?? false - - signal lockRequested - - function collapseAll() { - expandedSection = ""; - expandedWidgetIndex = -1; - expandedWidgetData = null; - } - - onEditModeChanged: { - if (editMode) { - collapseAll(); - } - } - - onVisibleChanged: { - if (!visible) { - collapseAll(); - } - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - function openWithSection(section) { - StateUtils.openWithSection(root, section); - } - - function toggleSection(section) { - StateUtils.toggleSection(root, section); - } - - popupWidth: 550 - popupHeight: { - const screenHeight = (triggerScreen?.height ?? 1080); - const maxHeight = screenHeight - 100; - const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400; - return Math.min(maxHeight, contentHeight); - } - triggerWidth: 80 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - property bool credentialsPromptOpen: NetworkService.credentialsRequested - property bool wifiPasswordModalOpen: PopoutService.wifiPasswordModal?.visible ?? false - property bool polkitModalOpen: PopoutService.polkitAuthModal?.visible ?? false - property bool anyModalOpen: credentialsPromptOpen || wifiPasswordModalOpen || polkitModalOpen || powerMenuOpen - - backgroundInteractive: !anyModalOpen - - onCredentialsPromptOpenChanged: { - if (credentialsPromptOpen && shouldBeVisible) - close(); - } - - onPolkitModalOpenChanged: { - if (polkitModalOpen && shouldBeVisible) - close(); - } - - customKeyboardFocus: { - if (!shouldBeVisible) - return WlrKeyboardFocus.None; - if (anyModalOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - onBackgroundClicked: close() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - collapseAll(); - Qt.callLater(() => { - if (NetworkService.activeService) - NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled; - }); - } else { - Qt.callLater(() => { - if (NetworkService.activeService) { - NetworkService.activeService.autoRefreshEnabled = false; - } - if (BluetoothService.adapter && BluetoothService.adapter.discovering) - BluetoothService.adapter.discovering = false; - editMode = false; - }); - } - } - - WidgetModel { - id: widgetModel - } - - content: Component { - Rectangle { - id: controlContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: mainColumn.implicitHeight + Theme.spacingM - property alias bluetoothCodecSelector: bluetoothCodecSelector - - color: "transparent" - clip: true - - Rectangle { - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.6) - radius: parent.radius - visible: root.powerMenuOpen - z: 5000 - - Behavior on opacity { - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - } - - Column { - id: mainColumn - width: parent.width - Theme.spacingL * 2 - x: Theme.spacingL - y: Theme.spacingL - spacing: Theme.spacingS - - HeaderPane { - id: headerPane - width: parent.width - editMode: root.editMode - onEditModeToggled: root.editMode = !root.editMode - onPowerButtonClicked: { - if (powerMenuModalLoader) { - powerMenuModalLoader.active = true; - if (powerMenuModalLoader.item) { - const bounds = Qt.rect(root.alignedX, root.alignedY, root.popupWidth, root.popupHeight); - powerMenuModalLoader.item.openFromControlCenter(bounds, root.screen); - } - } - } - onLockRequested: { - root.close(); - root.lockRequested(); - } - onSettingsButtonClicked: { - root.close(); - } - } - - DragDropGrid { - id: widgetGrid - width: parent.width - editMode: root.editMode - maxPopoutHeight: { - const screenHeight = (root.triggerScreen?.height ?? 1080); - return screenHeight - 100 - Theme.spacingL - headerPane.height - Theme.spacingS; - } - expandedSection: root.expandedSection - expandedWidgetIndex: root.expandedWidgetIndex - expandedWidgetData: root.expandedWidgetData - model: widgetModel - bluetoothCodecSelector: bluetoothCodecSelector - colorPickerModal: root.colorPickerModal - screenName: root.triggerScreen?.name || "" - screenModel: root.triggerScreen?.model || "" - parentScreen: root.triggerScreen - onExpandClicked: (widgetData, globalIndex) => { - root.expandedWidgetIndex = globalIndex; - root.expandedWidgetData = widgetData; - if (widgetData.id === "diskUsage") { - root.toggleSection("diskUsage_" + (widgetData.instanceId || "default")); - } else if (widgetData.id === "brightnessSlider") { - root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default")); - } else { - root.toggleSection(widgetData.id); - } - } - onRemoveWidget: index => widgetModel.removeWidget(index) - onMoveWidget: (fromIndex, toIndex) => widgetModel.moveWidget(fromIndex, toIndex) - onToggleWidgetSize: index => widgetModel.toggleWidgetSize(index) - onCollapseRequested: root.collapseAll() - } - - EditControls { - width: parent.width - visible: editMode - popoutContent: controlContent - availableWidgets: { - if (!editMode) - return []; - const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id); - const allWidgets = widgetModel.baseWidgetDefinitions.concat(widgetModel.getPluginWidgets()); - return allWidgets.filter(w => w.allowMultiple || !existingIds.includes(w.id)); - } - onAddWidget: widgetId => widgetModel.addWidget(widgetId) - onResetToDefault: () => widgetModel.resetToDefault() - onClearAll: () => widgetModel.clearAll() - } - } - - BluetoothCodecSelector { - id: bluetoothCodecSelector - anchors.fill: parent - z: 10000 - } - } - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail { - id: bluetoothDetail - onShowCodecSelector: function (device) { - if (contentLoader.item && contentLoader.item.bluetoothCodecSelector) { - contentLoader.item.bluetoothCodecSelector.show(device); - contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) { - bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName); - }); - } - } - } - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - property var colorPickerModal: null - property var powerMenuModalLoader: null -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml deleted file mode 100644 index 8fc2d46..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml +++ /dev/null @@ -1,363 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool hasInputVolumeSliderInCC: { - const widgets = SettingsData.controlCenterWidgets || []; - return widgets.some(widget => widget.id === "inputVolumeSlider"); - } - - implicitHeight: headerRow.height + (hasInputVolumeSliderInCC ? 0 : volumeSlider.height) + audioContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Input Devices") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerText.width - settingsButton.width - } - - DankActionButton { - id: settingsButton - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("audio"); - } - } - } - - Row { - id: volumeSlider - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingXS - height: 35 - spacing: 0 - visible: !hasInputVolumeSliderInCC - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.muted = !AudioService.source.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!AudioService.source || !AudioService.source.audio) - return "mic_off"; - let muted = AudioService.source.audio.muted; - return muted ? "mic_off" : "mic"; - } - size: Theme.iconSize - color: AudioService.source && AudioService.source.audio && !AudioService.source.audio.muted && AudioService.source.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: AudioService.source && AudioService.source.audio ? Math.round(AudioService.source.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: AudioService.source && AudioService.source.audio - minimum: 0 - maximum: 100 - value: AudioService.source && AudioService.source.audio ? Math.min(100, Math.round(AudioService.source.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceVariant - - onSliderValueChanged: function (newValue) { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.volume = newValue / 100; - if (newValue > 0 && AudioService.source.audio.muted) { - AudioService.source.audio.muted = false; - } - } - } - } - } - - DankFlickable { - id: audioContent - anchors.top: hasInputVolumeSliderInCC ? headerRow.bottom : volumeSlider.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: hasInputVolumeSliderInCC ? Theme.spacingM : Theme.spacingS - contentHeight: audioColumn.height - clip: true - - property int maxPinnedInputs: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedInputs() { - const pins = SettingsData.audioInputDevicePins || {}; - return normalizePinList(pins["preferredInput"]); - } - - Column { - id: audioColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ScriptModel { - values: { - const hidden = SessionData.hiddenInputDeviceNames ?? []; - const nodes = Pipewire.nodes.values.filter(node => { - if (!node.audio || node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - const pinnedList = audioContent.getPinnedInputs(); - - let sorted = [...nodes]; - sorted.sort((a, b) => { - // Pinned device first - const aPinnedIndex = pinnedList.indexOf(a.name); - const bPinnedIndex = pinnedList.indexOf(b.name); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - // Then active device - if (a === AudioService.source && b !== AudioService.source) - return -1; - if (b === AudioService.source && a !== AudioService.source) - return 1; - return 0; - }); - return sorted; - } - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: modelData === AudioService.source ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.source ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: { - if (modelData.name.includes("bluez")) - return "headset"; - else if (modelData.name.includes("usb")) - return "headset"; - else - return "mic"; - } - size: Theme.iconSize - 4 - color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - const pinButtonWidth = pinInputRow.width + Theme.spacingS * 4 + Theme.spacingM; - return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2; - } - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.source ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData === AudioService.source ? I18n.tr("Active") : I18n.tr("Available") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: pinInputRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05); - } - - Row { - id: pinInputRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin"); - } - font.pixelSize: Theme.fontSizeSmall - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {})); - let pinnedList = audioContent.normalizePinList(pins["preferredInput"]); - const pinIndex = pinnedList.indexOf(modelData.name); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.name); - if (pinnedList.length > audioContent.maxPinnedInputs) - pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs); - } - - if (pinnedList.length > 0) - pins["preferredInput"] = pinnedList; - else - delete pins["preferredInput"]; - - SettingsData.set("audioInputDevicePins", pins); - } - } - } - - DankRipple { - id: deviceRipple - cornerRadius: parent.radius - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pinInputRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - let mapped = mapToItem(parent, mouse.x, mouse.y); - deviceRipple.trigger(mapped.x, mapped.y); - } - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSource = modelData; - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml deleted file mode 100644 index 7e86ae4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml +++ /dev/null @@ -1,544 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool hasVolumeSliderInCC: { - const widgets = SettingsData.controlCenterWidgets || []; - return widgets.some(widget => widget.id === "volumeSlider"); - } - - implicitHeight: headerRow.height + (!hasVolumeSliderInCC ? volumeSlider.height : 0) + audioContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Audio Devices") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerText.width - settingsButton.width - } - - DankActionButton { - id: settingsButton - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("audio"); - } - } - } - - Row { - id: volumeSlider - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingXS - height: 35 - spacing: 0 - visible: !hasVolumeSliderInCC - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankRipple { - id: muteRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => muteRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.muted = !AudioService.sink.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!AudioService.sink || !AudioService.sink.audio) - return "volume_off"; - let muted = AudioService.sink.audio.muted; - let volume = AudioService.sink.audio.volume; - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: AudioService.sink && AudioService.sink.audio && !AudioService.sink.audio.muted && AudioService.sink.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: AudioService.sink && AudioService.sink.audio ? Math.round(AudioService.sink.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: AudioService.sink && AudioService.sink.audio - minimum: 0 - maximum: AudioService.sinkMaxVolume - value: AudioService.sink && AudioService.sink.audio ? Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceVariant - - onSliderValueChanged: function (newValue) { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.volume = newValue / 100; - if (newValue > 0 && AudioService.sink.audio.muted) { - AudioService.sink.audio.muted = false; - } - AudioService.volumeChanged(); - } - } - } - } - - DankFlickable { - id: audioContent - anchors.top: volumeSlider.visible ? volumeSlider.bottom : headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: volumeSlider.visible ? Theme.spacingS : Theme.spacingM - contentHeight: audioColumn.height - clip: true - - property int maxPinnedOutputs: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedOutputs() { - const pins = SettingsData.audioOutputDevicePins || {}; - return normalizePinList(pins["preferredOutput"]); - } - - Column { - id: audioColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ScriptModel { - values: { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - const nodes = Pipewire.nodes.values.filter(node => { - if (!node.audio || !node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - const pinnedList = audioContent.getPinnedOutputs(); - - let sorted = [...nodes]; - sorted.sort((a, b) => { - // Pinned device first - const aPinnedIndex = pinnedList.indexOf(a.name); - const bPinnedIndex = pinnedList.indexOf(b.name); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - // Then active device - if (a === AudioService.sink && b !== AudioService.sink) - return -1; - if (b === AudioService.sink && a !== AudioService.sink) - return 1; - return 0; - }); - return sorted; - } - } - - delegate: Rectangle { - id: outputDelegate - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: modelData === AudioService.sink ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.sink ? 2 : 1 - - DankRipple { - id: deviceRipple - cornerRadius: outputDelegate.radius - } - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: AudioService.sinkIcon(modelData) - size: Theme.iconSize - 4 - color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - const pinButtonWidth = pinOutputRow.width + Theme.spacingS * 4 + Theme.spacingM; - return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2; - } - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData === AudioService.sink ? I18n.tr("Active") : I18n.tr("Available") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: pinOutputRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05); - } - - Row { - id: pinOutputRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin"); - } - font.pixelSize: Theme.fontSizeSmall - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {})); - let pinnedList = audioContent.normalizePinList(pins["preferredOutput"]); - const pinIndex = pinnedList.indexOf(modelData.name); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.name); - if (pinnedList.length > audioContent.maxPinnedOutputs) - pinnedList = pinnedList.slice(0, audioContent.maxPinnedOutputs); - } - - if (pinnedList.length > 0) - pins["preferredOutput"] = pinnedList; - else - delete pins["preferredOutput"]; - - SettingsData.set("audioOutputDevicePins", pins); - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pinOutputRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - let mapped = deviceMouseArea.mapToItem(outputDelegate, mouse.x, mouse.y); - deviceRipple.trigger(mapped.x, mapped.y); - } - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSink = modelData; - } - } - } - } - } - Row { - id: playbackHeaderRow - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - height: 28 - - StyledText { - id: playbackHeaderText - text: I18n.tr("Playback") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Repeater { - model: ScriptModel { - values: { - const nodes = Pipewire.nodes.values.filter(node => { - return node.audio && node.isSink && node.isStream; - }); - return nodes; - } - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: modelData === AudioService.sink ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.sink ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: "album" - size: Theme.iconSize - 4 - color: !modelData.audio.muted ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - return parent.parent.width - iconWidth - parent.spacing - Theme.spacingM * 2; - } - - StyledText { - text: { - const modelDataMediaName = modelData && modelData.properties ? (modelData.properties["media.name"] || "") : ""; - const mediaName = AudioService.displayName(modelData) + ": " + modelDataMediaName; - const max = 35; - return mediaName.length > max ? mediaName.substring(0, max) + "..." : mediaName; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - } - } - } - Rectangle { - anchors.right: parent.right - anchors.rightMargin: 120 - anchors.verticalCenter: parent.verticalCenter - width: appVolumeRow.width - height: 28 - radius: height / 2 - - Item { - id: appVolumeRow - property color sliderTrackColor: "transparent" - anchors.centerIn: parent - - height: 40 - width: parent.width - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: appIconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: appMuteRipple - cornerRadius: parent.radius - } - - MouseArea { - id: appIconArea - anchors.fill: parent - visible: modelData !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => appMuteRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionData.suppressOSDTemporarily(); - modelData.audio.muted = !modelData.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!modelData) - return "volume_off"; - - let volume = modelData.audio.volume; - let muted = modelData.audio.muted; - - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: modelData && !modelData.audio.muted && modelData.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: modelData ? Math.round(modelData.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: 100 - enabled: modelData !== null - minimum: 0 - maximum: 100 - value: modelData ? Math.min(100, Math.round(modelData.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: appVolumeRow.sliderTrackColor.a > 0 ? appVolumeRow.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onSliderValueChanged: function (newValue) { - if (modelData) { - SessionData.suppressOSDTemporarily(); - modelData.audio.volume = newValue / 100.0; - if (newValue > 0 && modelData.audio.muted) { - modelData.audio.muted = false; - } - AudioService.playVolumeChangeSoundIfEnabled(); - } - } - } - } - PwObjectTracker { - objects: [modelData] - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml deleted file mode 100644 index 1f0206a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml +++ /dev/null @@ -1,267 +0,0 @@ -import QtQuick -import Quickshell.Services.UPower -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - function isActiveProfile(profile) { - if (typeof PowerProfiles === "undefined") { - return false; - } - return PowerProfiles.profile === profile; - } - - function setProfile(profile) { - if (typeof PowerProfiles === "undefined") { - ToastService.showError("power-profiles-daemon not available"); - return; - } - PowerProfiles.profile = profile; - if (PowerProfiles.profile !== profile) { - ToastService.showError("Failed to set power profile"); - } - } - - Column { - id: contentColumn - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - id: headerRow - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.iconSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - Theme.spacingM - - Row { - spacing: Theme.spacingS - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : I18n.tr("Power") - font.pixelSize: Theme.fontSizeXLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Bold - } - - StyledText { - text: BatteryService.batteryAvailable ? BatteryService.batteryStatus : I18n.tr("Management") - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: { - if (!BatteryService.batteryAvailable) - return I18n.tr("Power profile management available"); - const time = BatteryService.formatTimeRemaining(); - if (time !== "Unknown") { - return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(time) : I18n.tr("Time remaining: %1").arg(time); - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - visible: text.length > 0 - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: BatteryService.batteryAvailable - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryHealth - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.batteryHealth === "N/A") { - return Theme.surfaceText; - } - const healthNum = parseInt(BatteryService.batteryHealth); - return healthNum < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryCapacity > 0 ? `${BatteryService.batteryCapacity.toFixed(1)} Wh` : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - DankButtonGroup { - property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] - property int currentProfileIndex: { - if (typeof PowerProfiles === "undefined") - return 1; - return profileModel.findIndex(profile => isActiveProfile(profile)); - } - - model: profileModel.map(profile => Theme.getPowerProfileLabel(profile)) - currentIndex: currentProfileIndex - selectionMode: "single" - anchors.horizontalCenter: parent.horizontalCenter - onSelectionChanged: (index, selected) => { - if (!selected) - return; - setProfile(profileModel[index]); - } - } - - StyledRect { - width: parent.width - height: degradationContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3) - border.width: 0 - visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None - - Column { - id: degradationContent - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Power Profile Degradation") - font.pixelSize: Theme.fontSizeLarge - color: Theme.error - font.weight: Font.Medium - } - - StyledText { - text: (typeof PowerProfiles !== "undefined") ? PerformanceDegradationReason.toString(PowerProfiles.degradationReason) : "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8) - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml deleted file mode 100644 index 0cad08c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml +++ /dev/null @@ -1,332 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var device: null - property bool modalVisible: false - property var parentItem - property var availableCodecs: [] - property string currentCodec: "" - property bool isLoading: false - - readonly property bool deviceValid: device !== null && device.connected && BluetoothService.isAudioDevice(device) - - signal codecSelected(string deviceAddress, string codecName) - - function show(bluetoothDevice) { - if (!bluetoothDevice?.connected) - return; - if (!BluetoothService.isAudioDevice(bluetoothDevice)) - return; - device = bluetoothDevice; - isLoading = true; - availableCodecs = []; - currentCodec = ""; - visible = true; - modalVisible = true; - queryCodecs(); - Qt.callLater(() => { - focusScope.forceActiveFocus(); - }); - } - - function hide() { - modalVisible = false; - Qt.callLater(() => { - visible = false; - device = null; - }); - } - - function queryCodecs() { - if (!deviceValid) { - hide(); - return; - } - - const capturedDevice = device; - const capturedAddress = device.address; - - BluetoothService.getAvailableCodecs(capturedDevice, function (codecs, current) { - if (!root.deviceValid || root.device?.address !== capturedAddress) - return; - availableCodecs = codecs; - currentCodec = current; - isLoading = false; - }); - } - - function selectCodec(profileName) { - if (!deviceValid || isLoading) - return; - - const capturedDevice = device; - const capturedAddress = device.address; - - const selectedCodec = availableCodecs.find(c => c.profile === profileName); - if (!selectedCodec) - return; - - BluetoothService.updateDeviceCodec(capturedAddress, selectedCodec.name); - codecSelected(capturedAddress, selectedCodec.name); - - isLoading = true; - BluetoothService.switchCodec(capturedDevice, profileName, function (success, message) { - if (!root.device || root.device.address !== capturedAddress) - return; - - isLoading = false; - if (success) { - ToastService.showToast(message, ToastService.levelInfo); - Qt.callLater(root.hide); - return; - } - ToastService.showToast(message, ToastService.levelError); - }); - } - - onDeviceValidChanged: { - if (modalVisible && !deviceValid) { - hide(); - } - } - - visible: false - anchors.fill: parent - z: 2000 - - MouseArea { - id: modalBlocker - anchors.fill: parent - visible: modalVisible - enabled: modalVisible - hoverEnabled: true - preventStealing: true - propagateComposedEvents: false - - onClicked: root.hide() - onWheel: wheel => { - wheel.accepted = true; - } - onPositionChanged: mouse => { - mouse.accepted = true; - } - } - - Rectangle { - id: modalBackground - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.5) - opacity: modalVisible ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - FocusScope { - id: focusScope - - anchors.fill: parent - focus: root.visible - enabled: root.visible - - Keys.onEscapePressed: { - root.hide(); - event.accepted = true; - } - } - - Rectangle { - id: modalContent - anchors.centerIn: parent - width: 320 - height: contentColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: modalVisible ? 1 : 0 - scale: modalVisible ? 1 : 0.9 - - MouseArea { - anchors.fill: parent - hoverEnabled: true - preventStealing: true - propagateComposedEvents: false - onClicked: mouse => { - mouse.accepted = true; - } - onWheel: wheel => { - wheel.accepted = true; - } - onPositionChanged: mouse => { - mouse.accepted = true; - } - } - - Column { - id: contentColumn - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: device ? BluetoothService.getDeviceIcon(device) : "headset" - size: Theme.iconSize + 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: device ? (device.name || device.deviceName) : "" - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Audio Codec Selection") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - } - - StyledText { - text: isLoading ? I18n.tr("Loading codecs...") : I18n.tr("Current: %1").arg(currentCodec) - font.pixelSize: Theme.fontSizeSmall - color: isLoading ? Theme.primary : Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !isLoading - - Repeater { - model: availableCodecs - - Rectangle { - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: { - if (modelData.name === currentCodec) - return Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency); - else if (codecMouseArea.containsMouse) - return Theme.surfaceHover; - else - return "transparent"; - } - border.color: "transparent" - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: modelData.qualityColor - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: modelData.name === currentCodec ? Theme.primary : Theme.surfaceText - font.weight: modelData.name === currentCodec ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - DankIcon { - name: "check" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: modelData.name === currentCodec - } - - DankRipple { - id: codecRipple - cornerRadius: parent.radius - } - - MouseArea { - id: codecMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: modelData.name !== currentCodec && !isLoading - onPressed: mouse => codecRipple.trigger(mouse.x, mouse.y) - onClicked: { - selectCodec(modelData.profile); - } - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml deleted file mode 100644 index 580ea9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml +++ /dev/null @@ -1,743 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Bluetooth -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: { - if (height > 0) - return height; - if (!BluetoothService.adapter?.enabled) - return headerRow.height; - return headerRow.height + bluetoothContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - property var bluetoothCodecModalRef: null - property var devicesBeingPaired: new Set() - - signal showCodecSelector(var device) - - function isDeviceBeingPaired(deviceAddress) { - return devicesBeingPaired.has(deviceAddress); - } - - function handlePairDevice(device) { - if (!device) - return; - const deviceAddr = device.address; - const pairingSet = devicesBeingPaired; - - pairingSet.add(deviceAddr); - devicesBeingPairedChanged(); - - BluetoothService.pairDevice(device, function (response) { - pairingSet.delete(deviceAddr); - devicesBeingPairedChanged(); - - if (response.error) { - ToastService.showError(I18n.tr("Pairing failed"), response.error); - return; - } - if (!BluetoothService.enhancedPairingAvailable) { - ToastService.showSuccess(I18n.tr("Device paired")); - } - }); - } - - function updateDeviceCodecDisplay(deviceAddress, codecName) { - for (let i = 0; i < pairedRepeater.count; i++) { - const item = pairedRepeater.itemAt(i); - if (!item?.modelData) - continue; - if (item.modelData.address !== deviceAddress) - continue; - item.currentCodec = codecName; - break; - } - } - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedDevices() { - const pins = SettingsData.bluetoothDevicePins || {}; - return normalizePinList(pins["preferredDevice"]); - } - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Bluetooth Settings") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - headerText.implicitWidth - scanButton.width - Theme.spacingM) - height: parent.height - } - - Rectangle { - id: scanButton - - readonly property bool adapterEnabled: BluetoothService.adapter?.enabled ?? false - readonly property bool isDiscovering: BluetoothService.adapter?.discovering ?? false - - width: 100 - height: 36 - radius: 18 - color: scanMouseArea.containsMouse && adapterEnabled ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - border.color: adapterEnabled ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - border.width: 0 - visible: adapterEnabled - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: scanButton.isDiscovering ? "stop" : "bluetooth_searching" - size: 18 - color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: scanButton.isDiscovering ? I18n.tr("Scanning") : I18n.tr("Scan") - color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: scanRipple - cornerRadius: scanButton.radius - } - - MouseArea { - id: scanMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: scanButton.adapterEnabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onPressed: mouse => scanRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!BluetoothService.adapter) - return; - BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering; - } - } - } - } - - DankFlickable { - id: bluetoothContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: BluetoothService.adapter?.enabled ?? false - contentHeight: bluetoothColumn.height - clip: true - - readonly property int maxPinnedDevices: 3 - - Column { - id: bluetoothColumn - width: parent.width - spacing: Theme.spacingS - - ScriptModel { - id: pairedDevicesModel - objectProp: "address" - values: { - if (!BluetoothService.adapter?.devices) - return []; - - const pinnedList = root.getPinnedDevices(); - const devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]; - - devices.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.address); - const bPinnedIndex = pinnedList.indexOf(b.address); - - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - - if (a.connected !== b.connected) - return a.connected ? -1 : 1; - - return (b.signalStrength || 0) - (a.signalStrength || 0); - }); - - return devices; - } - } - - Repeater { - id: pairedRepeater - model: pairedDevicesModel - - delegate: Rectangle { - id: pairedDelegate - required property var modelData - required property int index - - readonly property string currentCodec: BluetoothService.deviceCodecs[modelData.address] || "" - readonly property bool isConnecting: modelData.state === BluetoothDeviceState.Connecting - readonly property bool isConnected: modelData.connected - readonly property bool isPinned: root.getPinnedDevices().includes(modelData.address) - readonly property string deviceName: modelData.name || modelData.deviceName || I18n.tr("Unknown Device") - - width: parent.width - height: 50 - radius: Theme.cornerRadius - - Component.onCompleted: { - if (!isConnected) - return; - if (!BluetoothService.isAudioDevice(modelData)) - return; - BluetoothService.refreshDeviceCodec(modelData); - } - - color: { - if (isConnecting) - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12); - if (deviceMouseArea.containsMouse) - return Theme.primaryHoverLight; - return Theme.surfaceLight; - } - - border.color: { - if (isConnecting) - return Theme.warning; - if (isConnected) - return Theme.primary; - return Theme.outlineLight; - } - border.width: (isConnecting || isConnected) ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: BluetoothService.getDeviceIcon(pairedDelegate.modelData) - size: Theme.iconSize - 4 - anchors.verticalCenter: parent.verticalCenter - color: { - if (pairedDelegate.isConnecting) - return Theme.warning; - if (pairedDelegate.isConnected) - return Theme.primary; - return Theme.surfaceText; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: pairedDelegate.deviceName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: pairedDelegate.isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: { - if (pairedDelegate.isConnecting) - return I18n.tr("Connecting..."); - if (!pairedDelegate.isConnected) - return I18n.tr("Paired"); - if (!pairedDelegate.currentCodec) - return I18n.tr("Connected"); - return I18n.tr("Connected") + " • " + pairedDelegate.currentCodec; - } - font.pixelSize: Theme.fontSizeSmall - color: pairedDelegate.isConnecting ? Theme.warning : Theme.surfaceVariantText - } - - StyledText { - readonly property var btBattery: { - const name = pairedDelegate.deviceName; - return BatteryService.bluetoothDevices.find(dev => dev.name === name || dev.name.toLowerCase().includes(name.toLowerCase()) || name.toLowerCase().includes(dev.name.toLowerCase())); - } - text: { - if (pairedDelegate.modelData.batteryAvailable && pairedDelegate.modelData.battery > 0) - return "• " + Math.round(pairedDelegate.modelData.battery * 100) + "%"; - if (btBattery) - return "• " + btBattery.percentage + "%"; - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - - StyledText { - text: pairedDelegate.modelData.signalStrength > 0 ? "• " + pairedDelegate.modelData.signalStrength + "%" : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - } - } - } - - Rectangle { - anchors.right: pairedOptionsButton.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: pinBluetoothRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: pairedDelegate.isPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinBluetoothRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: pairedDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: pairedDelegate.isPinned ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: pairedDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {})); - let pinnedList = root.normalizePinList(pins["preferredDevice"]); - const pinIndex = pinnedList.indexOf(pairedDelegate.modelData.address); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(pairedDelegate.modelData.address); - if (pinnedList.length > bluetoothContent.maxPinnedDevices) - pinnedList = pinnedList.slice(0, bluetoothContent.maxPinnedDevices); - } - - if (pinnedList.length > 0) { - pins["preferredDevice"] = pinnedList; - } else { - delete pins["preferredDevice"]; - } - - SettingsData.set("bluetoothDevicePins", pins); - } - } - } - - DankActionButton { - id: pairedOptionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (bluetoothContextMenu.visible) { - bluetoothContextMenu.close(); - return; - } - bluetoothContextMenu.currentDevice = pairedDelegate.modelData; - bluetoothContextMenu.popup(pairedOptionsButton, -bluetoothContextMenu.width + pairedOptionsButton.width, pairedOptionsButton.height + Theme.spacingXS); - } - } - - DankRipple { - id: deviceRipple - cornerRadius: pairedDelegate.radius - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pairedOptionsButton.width + Theme.spacingM + pinBluetoothRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - const pos = mapToItem(pairedDelegate, mouse.x, mouse.y); - deviceRipple.trigger(pos.x, pos.y); - } - onClicked: { - if (pairedDelegate.isConnected) { - pairedDelegate.modelData.disconnect(); - return; - } - BluetoothService.connectDeviceWithTrust(pairedDelegate.modelData); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - visible: pairedRepeater.count > 0 && availableRepeater.count > 0 - } - - Item { - width: parent.width - height: 80 - visible: (BluetoothService.adapter?.discovering ?? false) && availableRepeater.count === 0 - - DankIcon { - anchors.centerIn: parent - name: "sync" - size: 24 - color: Qt.rgba(Theme.surfaceText.r || 0.8, Theme.surfaceText.g || 0.8, Theme.surfaceText.b || 0.8, 0.4) - - RotationAnimation on rotation { - running: parent.visible - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1500 - } - } - } - - ScriptModel { - id: availableDevicesModel - objectProp: "address" - values: { - if (!BluetoothService.adapter?.discovering) - return []; - if (!Bluetooth.devices) - return []; - - const filtered = Bluetooth.devices.values.filter(dev => dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0)); - return BluetoothService.sortDevices(filtered); - } - } - - Repeater { - id: availableRepeater - model: availableDevicesModel - - delegate: Rectangle { - id: availableDelegate - required property var modelData - required property int index - - readonly property bool canConnect: BluetoothService.canConnect(modelData) - readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData) || root.isDeviceBeingPaired(modelData.address) - readonly property bool isInteractive: canConnect && !isBusy - readonly property string deviceName: modelData.name || modelData.deviceName || I18n.tr("Unknown Device") - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: availableMouseArea.containsMouse && isInteractive ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - opacity: isInteractive ? 1 : 0.6 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: BluetoothService.getDeviceIcon(availableDelegate.modelData) - size: Theme.iconSize - 4 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: availableDelegate.deviceName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: { - if (availableDelegate.modelData.pairing || availableDelegate.isBusy) - return I18n.tr("Pairing..."); - if (availableDelegate.modelData.blocked) - return I18n.tr("Blocked"); - return BluetoothService.getSignalStrength(availableDelegate.modelData); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: availableDelegate.modelData.signalStrength > 0 ? "• " + availableDelegate.modelData.signalStrength + "%" : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 && !availableDelegate.modelData.pairing && !availableDelegate.modelData.blocked - } - } - } - } - - StyledText { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: { - if (availableDelegate.isBusy) - return I18n.tr("Pairing..."); - if (!availableDelegate.canConnect) - return I18n.tr("Cannot pair"); - return I18n.tr("Pair"); - } - font.pixelSize: Theme.fontSizeSmall - color: availableDelegate.isInteractive ? Theme.primary : Theme.surfaceVariantText - font.weight: Font.Medium - } - - DankRipple { - id: availableRipple - cornerRadius: availableDelegate.radius - } - - MouseArea { - id: availableMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: availableDelegate.isInteractive ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: availableDelegate.isInteractive - onPressed: mouse => availableRipple.trigger(mouse.x, mouse.y) - onClicked: root.handlePairDevice(availableDelegate.modelData) - } - } - } - - Item { - width: parent.width - height: 60 - visible: !BluetoothService.adapter - - StyledText { - anchors.centerIn: parent - text: I18n.tr("No Bluetooth adapter found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - } - } - } - - Menu { - id: bluetoothContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property var currentDevice: null - - readonly property bool hasDevice: currentDevice !== null - readonly property bool deviceConnected: currentDevice?.connected ?? false - readonly property bool showCodecOption: hasDevice && deviceConnected && BluetoothService.isAudioDevice(currentDevice) - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: bluetoothContextMenu.deviceConnected ? I18n.tr("Disconnect") : I18n.tr("Connect") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (bluetoothContextMenu.deviceConnected) { - bluetoothContextMenu.currentDevice.disconnect(); - return; - } - BluetoothService.connectDeviceWithTrust(bluetoothContextMenu.currentDevice); - } - } - - MenuItem { - text: I18n.tr("Audio Codec") - height: bluetoothContextMenu.showCodecOption ? 32 : 0 - visible: bluetoothContextMenu.showCodecOption - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (!bluetoothContextMenu.currentDevice.connected) - return; - if (!BluetoothService.isAudioDevice(bluetoothContextMenu.currentDevice)) - return; - showCodecSelector(bluetoothContextMenu.currentDevice); - } - } - - MenuItem { - text: bluetoothContextMenu.currentDevice?.trusted ? I18n.tr("Untrust") : I18n.tr("Trust") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - bluetoothContextMenu.currentDevice.trusted = !bluetoothContextMenu.currentDevice.trusted; - } - } - - MenuItem { - text: I18n.tr("Forget Device") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (!BluetoothService.enhancedPairingAvailable) { - bluetoothContextMenu.currentDevice.forget(); - return; - } - - const devicePath = BluetoothService.getDevicePath(bluetoothContextMenu.currentDevice); - DMSService.bluetoothRemove(devicePath, response => { - if (!response.error) - return; - ToastService.showError(I18n.tr("Failed to remove device"), response.error); - }); - } - } - } - - Connections { - target: DMSService - - function onBluetoothPairingRequest(data) { - const modal = PopoutService.bluetoothPairingModal; - if (!modal) - return; - if (modal.token === data.token) - return; - modal.show(data); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml deleted file mode 100644 index 0d42e62..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml +++ /dev/null @@ -1,498 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string initialDeviceName: "" - property string instanceId: "" - property string screenName: "" - property string screenModel: "" - - signal deviceNameChanged(string newDeviceName) - - property string currentDeviceName: "" - - function getScreenPinKey() { - if (!screenName) - return ""; - const screen = Quickshell.screens.find(s => s.name === screenName); - if (screen) { - return SettingsData.getScreenDisplayName(screen); - } - if (SettingsData.displayNameMode === "model" && screenModel && screenModel.length > 0) { - return screenModel; - } - return screenName; - } - - function resolveDeviceName() { - if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) { - return ""; - } - - const pinKey = getScreenPinKey(); - if (pinKey.length > 0) { - const pins = SettingsData.brightnessDevicePins || {}; - const pinnedDevice = pins[pinKey]; - if (pinnedDevice && pinnedDevice.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === pinnedDevice); - if (found) - return found.name; - } - } - - if (initialDeviceName && initialDeviceName.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === initialDeviceName); - if (found) - return found.name; - } - - const currentDeviceNameFromService = DisplayService.currentDevice; - if (currentDeviceNameFromService) { - const found = DisplayService.devices.find(dev => dev.name === currentDeviceNameFromService); - if (found) - return found.name; - } - - const backlight = DisplayService.devices.find(d => d.class === "backlight"); - if (backlight) - return backlight.name; - - const ddc = DisplayService.devices.find(d => d.class === "ddc"); - if (ddc) - return ddc.name; - - return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""; - } - - Component.onCompleted: { - currentDeviceName = resolveDeviceName(); - } - - property bool isPinnedToScreen: { - const pinKey = getScreenPinKey(); - if (!pinKey || pinKey.length === 0) - return false; - const pins = SettingsData.brightnessDevicePins || {}; - return pins[pinKey] === currentDeviceName; - } - - function togglePinToScreen() { - const pinKey = getScreenPinKey(); - if (!pinKey || pinKey.length === 0 || !currentDeviceName || currentDeviceName.length === 0) - return; - const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {})); - - if (isPinnedToScreen) { - delete pins[pinKey]; - } else { - pins[pinKey] = currentDeviceName; - } - - SettingsData.set("brightnessDevicePins", pins); - } - - implicitHeight: { - if (height > 0) { - return height; - } - return brightnessContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - DankFlickable { - id: brightnessContent - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - contentHeight: brightnessColumn.height - clip: true - - Column { - id: brightnessColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: 100 - visible: !DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: DisplayService.brightnessAvailable ? "brightness_6" : "error" - size: 32 - color: DisplayService.brightnessAvailable ? Theme.primary : Theme.error - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: DisplayService.brightnessAvailable ? I18n.tr("No brightness devices available") : I18n.tr("Brightness control not available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Rectangle { - width: parent.width - height: 40 - visible: screenName && screenName.length > 0 && DisplayService.devices && DisplayService.devices.length > 1 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingM - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.getScreenPinKey() || I18n.tr("Unknown Monitor") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width: pinRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: isPinnedToScreen ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: isPinnedToScreen ? "push_pin" : "push_pin" - size: 16 - color: isPinnedToScreen ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: isPinnedToScreen ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: isPinnedToScreen ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: root.togglePinToScreen() - } - } - } - } - - Repeater { - model: DisplayService.devices || [] - delegate: Rectangle { - required property var modelData - required property int index - - property real deviceBrightness: { - DisplayService.brightnessVersion; - return DisplayService.getDeviceBrightness(modelData.name); - } - - width: parent.width - height: 100 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - border.color: modelData.name === currentDeviceName ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - border.width: modelData.name === currentDeviceName ? 2 : 0 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(deviceIconColumn.height, deviceInfoColumn.height, exponentControls.height) - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Column { - id: deviceIconColumn - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - name: { - const deviceClass = modelData.class || ""; - const deviceName = modelData.name || ""; - - if (deviceClass === "backlight" || deviceClass === "ddc") { - if (deviceBrightness <= 33) - return "brightness_low"; - if (deviceBrightness <= 66) - return "brightness_medium"; - return "brightness_high"; - } else if (deviceName.includes("kbd")) { - return "keyboard"; - } else { - return "lightbulb"; - } - } - size: Theme.iconSize - color: modelData.name === currentDeviceName ? Theme.primary : Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: Math.round(deviceBrightness) + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - id: deviceInfoColumn - anchors.verticalCenter: parent.verticalCenter - width: parent.parent.width - deviceIconColumn.width - exponentControls.width - Theme.spacingM * 3 - - StyledText { - text: { - const name = modelData.name || ""; - const deviceClass = modelData.class || ""; - if (deviceClass === "backlight") { - return name.replace("_", " ").replace(/\b\w/g, c => c.toUpperCase()); - } - return name; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData.name === currentDeviceName ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const deviceClass = modelData.class || ""; - if (deviceClass === "backlight") - return I18n.tr("Backlight device"); - if (deviceClass === "ddc") - return I18n.tr("DDC/CI monitor"); - if (deviceClass === "leds") - return I18n.tr("LED device"); - return deviceClass; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - id: exponentControls - width: 140 - height: 28 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - visible: SessionData.getBrightnessExponential(modelData.name) - z: 1 - - StyledRect { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - opacity: SessionData.getBrightnessExponent(modelData.name) > 1.0 ? 1.0 : 0.4 - - DankIcon { - anchors.centerIn: parent - name: "remove" - size: 14 - color: Theme.surfaceText - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: SessionData.getBrightnessExponent(modelData.name) > 1.0 - onClicked: { - const current = SessionData.getBrightnessExponent(modelData.name); - const newValue = Math.max(1.0, Math.round((current - 0.1) * 10) / 10); - SessionData.setBrightnessExponent(modelData.name, newValue); - } - } - } - - StyledRect { - width: 50 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - border.width: 0 - - StyledText { - anchors.centerIn: parent - text: SessionData.getBrightnessExponent(modelData.name).toFixed(1) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - } - } - - StyledRect { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - opacity: SessionData.getBrightnessExponent(modelData.name) < 2.5 ? 1.0 : 0.4 - - DankIcon { - anchors.centerIn: parent - name: "add" - size: 14 - color: Theme.surfaceText - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: SessionData.getBrightnessExponent(modelData.name) < 2.5 - onClicked: { - const current = SessionData.getBrightnessExponent(modelData.name); - const newValue = Math.min(2.5, Math.round((current + 0.1) * 10) / 10); - SessionData.setBrightnessExponent(modelData.name, newValue); - } - } - } - } - } - - Rectangle { - width: parent.width - height: 24 - radius: height / 2 - color: SessionData.getBrightnessExponential(modelData.name) ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "show_chart" - size: 14 - color: SessionData.getBrightnessExponential(modelData.name) ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SessionData.getBrightnessExponential(modelData.name) ? I18n.tr("Exponential") : I18n.tr("Linear") - font.pixelSize: Theme.fontSizeSmall - color: SessionData.getBrightnessExponential(modelData.name) ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: expToggleRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => expToggleRipple.trigger(mouse.x, mouse.y) - onClicked: { - const currentState = SessionData.getBrightnessExponential(modelData.name); - SessionData.setBrightnessExponential(modelData.name, !currentState); - } - } - } - } - - DankRipple { - id: deviceRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - anchors.bottomMargin: 28 - anchors.rightMargin: SessionData.getBrightnessExponential(modelData.name) ? 145 : 0 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => deviceRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pinKey = root.getScreenPinKey(); - if (pinKey.length > 0 && modelData.name !== currentDeviceName) { - const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {})); - if (pins[pinKey]) { - delete pins[pinKey]; - SettingsData.set("brightnessDevicePins", pins); - } - } - currentDeviceName = modelData.name; - deviceNameChanged(modelData.name); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml deleted file mode 100644 index 90fbf9d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml +++ /dev/null @@ -1,177 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string currentMountPath: "/" - property string instanceId: "" - - signal mountPathChanged(string newMountPath) - - implicitHeight: diskContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - DankFlickable { - id: diskContent - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - contentHeight: diskColumn.height - clip: true - - Column { - id: diskColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: 100 - visible: !DgopService.dgopAvailable || !DgopService.diskMounts || DgopService.diskMounts.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: DgopService.dgopAvailable ? "storage" : "error" - size: 32 - color: DgopService.dgopAvailable ? Theme.primary : Theme.error - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: DgopService.dgopAvailable ? I18n.tr("No disk data available") : I18n.tr("dgop not available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Repeater { - model: DgopService.diskMounts || [] - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 80 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: modelData.mount === currentMountPath ? Theme.primary : Theme.outlineLight - border.width: modelData.mount === currentMountPath ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingM - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - name: "storage" - size: Theme.iconSize - color: { - const percentStr = modelData.percent?.replace("%", "") || "0"; - const percent = parseFloat(percentStr) || 0; - if (percent > 90) - return Theme.error; - if (percent > 75) - return Theme.warning; - return modelData.mount === currentMountPath ? Theme.primary : Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const percentStr = modelData.percent?.replace("%", "") || "0"; - const percent = parseFloat(percentStr) || 0; - return percent.toFixed(0) + "%"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.parent.width - parent.parent.anchors.leftMargin - parent.spacing - 50 - Theme.spacingM - - StyledText { - text: modelData.mount === "/" ? I18n.tr("Root Filesystem") : modelData.mount - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData.mount === currentMountPath ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.mount - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - visible: modelData.mount !== "/" - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `${modelData.used || "?"} / ${modelData.size || "?"}` - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - DankRipple { - id: mountRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => mountRipple.trigger(mouse.x, mouse.y) - onClicked: { - currentMountPath = modelData.mount; - mountPathChanged(modelData.mount); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml deleted file mode 100644 index 5f1738a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml +++ /dev/null @@ -1,893 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modals - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: { - if (height > 0) - return height; - if (NetworkService.wifiToggling) - return headerRow.height + wifiToggleContent.height + Theme.spacingM; - if (NetworkService.wifiEnabled) - return headerRow.height + wifiContent.height + Theme.spacingM; - return headerRow.height + wifiOffContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Component.onCompleted: { - NetworkService.addRef(); - } - - Component.onDestruction: { - NetworkService.removeRef(); - } - - property bool hasEthernetAvailable: (NetworkService.ethernetDevices?.length ?? 0) > 0 - property bool hasWifiAvailable: (NetworkService.wifiDevices?.length ?? 0) > 0 - property bool hasBothConnectionTypes: hasEthernetAvailable && hasWifiAvailable - property int maxPinnedNetworks: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedNetworks() { - const pins = SettingsData.wifiNetworkPins || {}; - return normalizePinList(pins["preferredWifi"]); - } - - property int currentPreferenceIndex: { - if (DMSService.apiVersion < 5) - return 1; - if (NetworkService.backend !== "networkmanager" || DMSService.apiVersion <= 10) - return 1; - if (!hasEthernetAvailable) - return 1; - if (!hasWifiAvailable) - return 0; - - const pref = NetworkService.userPreference; - switch (pref) { - case "ethernet": - return 0; - case "wifi": - return 1; - default: - return NetworkService.networkStatus === "ethernet" ? 0 : 1; - } - } - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: Math.max(headerLeft.implicitHeight, rightControls.implicitHeight) + Theme.spacingS * 2 - - StyledText { - id: headerLeft - text: I18n.tr("Network") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerLeft.width - rightControls.width - } - - Row { - id: rightControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankDropdown { - id: wifiDeviceDropdown - anchors.verticalCenter: parent.verticalCenter - visible: currentPreferenceIndex === 1 && (NetworkService.wifiDevices?.length ?? 0) > 1 - compactMode: true - dropdownWidth: 120 - popupWidth: 160 - alignPopupRight: true - - options: { - const devices = NetworkService.wifiDevices; - if (!devices || devices.length === 0) - return [I18n.tr("Auto")]; - return [I18n.tr("Auto")].concat(devices.map(d => d.name)); - } - - currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto") - - onValueChanged: value => { - const deviceName = value === I18n.tr("Auto") ? "" : value; - NetworkService.setWifiDeviceOverride(deviceName); - } - } - - DankButtonGroup { - id: preferenceControls - anchors.verticalCenter: parent.verticalCenter - visible: hasBothConnectionTypes && NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10 - buttonHeight: 28 - textSize: Theme.fontSizeSmall - - model: [I18n.tr("Ethernet"), I18n.tr("WiFi")] - currentIndex: currentPreferenceIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - NetworkService.setNetworkPreference(index === 0 ? "ethernet" : "wifi"); - } - } - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("network"); - } - } - } - } - - Item { - id: wifiToggleContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiToggling - height: visible ? wifiToggleColumn.implicitHeight + Theme.spacingM * 2 : 0 - - Column { - id: wifiToggleColumn - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "sync" - size: 32 - color: Theme.primary - - RotationAnimation on rotation { - running: NetworkService.wifiToggling - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...") : I18n.tr("Enabling WiFi...") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Item { - id: wifiOffContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && !NetworkService.wifiEnabled && !NetworkService.wifiToggling - height: visible ? wifiOffColumn.implicitHeight + Theme.spacingM * 2 : 0 - - Column { - id: wifiOffColumn - anchors.centerIn: parent - spacing: Theme.spacingL - width: parent.width - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "wifi_off" - size: 48 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr("WiFi is off") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - width: enableWifiLabel.implicitWidth + Theme.spacingL * 2 - height: enableWifiLabel.implicitHeight + Theme.spacingM * 2 - radius: height / 2 - color: enableWifiButton.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) - border.width: 0 - border.color: Theme.primary - - StyledText { - id: enableWifiLabel - anchors.centerIn: parent - text: I18n.tr("Enable WiFi") - color: Theme.primary - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - } - - MouseArea { - id: enableWifiButton - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: NetworkService.toggleWifiRadio() - } - } - } - } - - ScriptModel { - id: wiredConnectionsModel - objectProp: "uuid" - values: { - const networks = NetworkService.wiredConnections; - if (!networks) - return []; - let sorted = [...networks]; - sorted.sort((a, b) => { - if (a.isActive && !b.isActive) - return -1; - if (!a.isActive && b.isActive) - return 1; - return a.id.localeCompare(b.id); - }); - return sorted; - } - } - - DankFlickable { - id: wiredContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 0 && NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10 - contentHeight: wiredColumn.height - clip: true - - Column { - id: wiredColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: wiredConnectionsModel - - delegate: Rectangle { - id: wiredDelegate - required property var modelData - required property int index - - readonly property bool isActive: modelData.isActive - readonly property string configName: modelData.id || I18n.tr("Unknown Config") - - width: parent.width - height: wiredContentRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: wiredNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: isActive ? Theme.primary : Theme.outlineLight - border.width: isActive ? 2 : 1 - - Row { - id: wiredContentRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: Theme.iconSize - 4 - color: wiredDelegate.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: wiredDelegate.configName - font.pixelSize: Theme.fontSizeMedium - color: wiredDelegate.isActive ? Theme.primary : Theme.surfaceText - font.weight: wiredDelegate.isActive ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - } - } - } - - DankActionButton { - id: wiredOptionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (wiredNetworkContextMenu.visible) { - wiredNetworkContextMenu.close(); - return; - } - wiredNetworkContextMenu.currentID = modelData.id; - wiredNetworkContextMenu.currentUUID = modelData.uuid; - wiredNetworkContextMenu.currentConnected = wiredDelegate.isActive; - wiredNetworkContextMenu.popup(wiredOptionsButton, -wiredNetworkContextMenu.width + wiredOptionsButton.width, wiredOptionsButton.height + Theme.spacingXS); - } - } - - DankRipple { - id: wiredRipple - cornerRadius: parent.radius - } - - MouseArea { - id: wiredNetworkMouseArea - anchors.fill: parent - anchors.rightMargin: wiredOptionsButton.width + Theme.spacingS - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => wiredRipple.trigger(mouse.x, mouse.y) - onClicked: function (event) { - if (modelData.uuid !== NetworkService.ethernetConnectionUuid) - NetworkService.connectToSpecificWiredConfig(modelData.uuid); - event.accepted = true; - } - } - } - } - } - } - - Menu { - id: wiredNetworkContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property string currentID: "" - property string currentUUID: "" - property bool currentConnected: false - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: I18n.tr("Activate") - height: !wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: !wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!wiredNetworkContextMenu.currentConnected) - NetworkService.connectToSpecificWiredConfig(wiredNetworkContextMenu.currentUUID); - } - } - - MenuItem { - text: I18n.tr("Disconnect") - height: wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.toggleNetworkConnection("ethernet"); - } - } - - MenuItem { - text: I18n.tr("Network Info") - height: wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const networkData = NetworkService.getWiredNetworkInfo(wiredNetworkContextMenu.currentUUID); - networkWiredInfoModalLoader.active = true; - networkWiredInfoModalLoader.item.showNetworkInfo(wiredNetworkContextMenu.currentID, networkData); - } - } - } - - ScriptModel { - id: wifiNetworksModel - objectProp: "ssid" - values: wifiContent.menuOpen ? wifiContent.frozenNetworks : wifiContent.sortedNetworks - } - - Item { - id: wifiScanningOverlay - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling && NetworkService.wifiInterface && (NetworkService.wifiNetworks?.length ?? 0) < 1 && NetworkService.isScanning - - DankIcon { - anchors.centerIn: parent - name: "refresh" - size: 48 - color: Qt.rgba(Theme.surfaceText.r || 0.8, Theme.surfaceText.g || 0.8, Theme.surfaceText.b || 0.8, 0.3) - - RotationAnimation on rotation { - running: wifiScanningOverlay.visible - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - DankListView { - id: wifiContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling && !wifiScanningOverlay.visible - clip: true - spacing: Theme.spacingS - model: wifiNetworksModel - - property var frozenNetworks: [] - property bool menuOpen: false - property var sortedNetworks: { - const ssid = NetworkService.currentWifiSSID; - const networks = NetworkService.wifiNetworks; - const pinnedList = root.getPinnedNetworks(); - - let sorted = [...networks]; - sorted.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.ssid); - const bPinnedIndex = pinnedList.indexOf(b.ssid); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - if (a.ssid === ssid) - return -1; - if (b.ssid === ssid) - return 1; - return b.signal - a.signal; - }); - return sorted; - } - onSortedNetworksChanged: { - if (!menuOpen) - frozenNetworks = sortedNetworks; - } - onMenuOpenChanged: { - if (menuOpen) - frozenNetworks = sortedNetworks; - } - - delegate: Rectangle { - id: wifiDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID - readonly property bool isPinned: root.getPinnedNetworks().includes(modelData.ssid) - readonly property string networkName: modelData.ssid || I18n.tr("Unknown Network") - readonly property int signalStrength: modelData.signal || 0 - - width: wifiContent.width - height: wifiContentRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: networkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: wifiDelegate.isConnected ? Theme.primary : Theme.outlineLight - border.width: wifiDelegate.isConnected ? 2 : 1 - - Row { - id: wifiContentRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: { - if (wifiDelegate.signalStrength >= 50) - return "wifi"; - if (wifiDelegate.signalStrength >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: Theme.iconSize - 4 - color: wifiDelegate.isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: wifiDelegate.networkName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: wifiDelegate.isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: wifiDelegate.isConnected ? I18n.tr("Connected") + " \u2022" : (modelData.secured ? I18n.tr("Secured") + " \u2022" : I18n.tr("Open") + " \u2022") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData.saved ? I18n.tr("Saved") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: text.length > 0 - } - - StyledText { - text: (modelData.saved ? "\u2022 " : "") + wifiDelegate.signalStrength + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - DankActionButton { - id: optionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (networkContextMenu.visible) { - networkContextMenu.close(); - return; - } - wifiContent.menuOpen = true; - networkContextMenu.currentSSID = modelData.ssid; - networkContextMenu.currentSecured = modelData.secured; - networkContextMenu.currentConnected = wifiDelegate.isConnected; - networkContextMenu.currentSaved = modelData.saved; - networkContextMenu.currentSignal = modelData.signal; - networkContextMenu.currentAutoconnect = modelData.autoconnect || false; - networkContextMenu.popup(optionsButton, -networkContextMenu.width + optionsButton.width, optionsButton.height + Theme.spacingXS); - } - } - - Rectangle { - id: pinButton - anchors.right: parent.right - anchors.rightMargin: optionsButton.width + Theme.spacingM + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: pinWifiRow.width + Theme.spacingS * 2 - height: pinWifiRow.implicitHeight + Theme.spacingXS * 2 - radius: height / 2 - color: wifiDelegate.isPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinWifiRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: wifiDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: wifiDelegate.isPinned ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: wifiDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {})); - let pinnedList = root.normalizePinList(pins["preferredWifi"]); - const pinIndex = pinnedList.indexOf(modelData.ssid); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.ssid); - if (pinnedList.length > root.maxPinnedNetworks) - pinnedList = pinnedList.slice(0, root.maxPinnedNetworks); - } - - if (pinnedList.length > 0) - pins["preferredWifi"] = pinnedList; - else - delete pins["preferredWifi"]; - - SettingsData.set("wifiNetworkPins", pins); - } - } - } - - DankActionButton { - id: qrCodeButton - visible: modelData.secured && modelData.saved - anchors.right: parent.right - anchors.rightMargin: optionsButton.width + pinWifiRow.width + 3 * Theme.spacingM + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "qr_code" - buttonSize: 28 - onClicked: { - PopoutService.showWifiQRCodeModal(modelData.ssid); - } - } - - DankRipple { - id: wifiRipple - cornerRadius: parent.radius - } - - MouseArea { - id: networkMouseArea - anchors.fill: parent - anchors.rightMargin: optionsButton.width + pinWifiRow.width + (qrCodeButton.visible ? qrCodeButton.width : 0) + Theme.spacingS * 5 + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => wifiRipple.trigger(mouse.x, mouse.y) - onClicked: function (event) { - if (wifiDelegate.isConnected) { - event.accepted = true; - return; - } - if (modelData.secured && !modelData.saved && DMSService.apiVersion < 7) { - PopoutService.showWifiPasswordModal(modelData.ssid); - } else { - NetworkService.connectToWifi(modelData.ssid); - } - event.accepted = true; - } - } - } - } - - Menu { - id: networkContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property string currentSSID: "" - property bool currentSecured: false - property bool currentConnected: false - property bool currentSaved: false - property int currentSignal: 0 - property bool currentAutoconnect: false - - readonly property bool showSavedOptions: currentSaved || currentConnected - - onClosed: { - wifiContent.menuOpen = false; - } - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: networkContextMenu.currentConnected ? I18n.tr("Disconnect") : I18n.tr("Connect") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (networkContextMenu.currentConnected) { - NetworkService.disconnectWifi(); - return; - } - if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved && DMSService.apiVersion < 7) { - PopoutService.showWifiPasswordModal(networkContextMenu.currentSSID); - return; - } - NetworkService.connectToWifi(networkContextMenu.currentSSID); - } - } - - MenuItem { - text: I18n.tr("Network Info") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID); - networkInfoModalLoader.active = true; - networkInfoModalLoader.item.showNetworkInfo(networkContextMenu.currentSSID, networkData); - } - } - - MenuItem { - text: networkContextMenu.currentAutoconnect ? I18n.tr("Disable Autoconnect") : I18n.tr("Enable Autoconnect") - height: networkContextMenu.showSavedOptions && DMSService.apiVersion > 13 ? 32 : 0 - visible: networkContextMenu.showSavedOptions && DMSService.apiVersion > 13 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.setWifiAutoconnect(networkContextMenu.currentSSID, !networkContextMenu.currentAutoconnect); - } - } - - MenuItem { - text: I18n.tr("Forget Network") - height: networkContextMenu.showSavedOptions ? 32 : 0 - visible: networkContextMenu.showSavedOptions - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.forgetWifiNetwork(networkContextMenu.currentSSID); - } - } - } - - Loader { - id: networkInfoModalLoader - active: false - sourceComponent: NetworkInfoModal {} - } - - Loader { - id: networkWiredInfoModalLoader - active: false - sourceComponent: NetworkWiredInfoModal {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml deleted file mode 100644 index ac616ae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml +++ /dev/null @@ -1,283 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.BuiltinPlugins -import "../utils/widgets.js" as WidgetUtils - -QtObject { - id: root - - property var vpnBuiltinInstance: null - property var cupsBuiltinInstance: null - - property var vpnLoader: Loader { - active: false - sourceComponent: Component { - VpnWidget {} - } - - onItemChanged: { - root.vpnBuiltinInstance = item; - } - - Connections { - target: SettingsData - function onControlCenterWidgetsChanged() { - const widgets = SettingsData.controlCenterWidgets || []; - const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn"); - if (!hasVpnWidget && vpnLoader.active) { - console.log("VpnWidget: No VPN widget in control center, deactivating loader"); - vpnLoader.active = false; - } - } - } - } - - property var cupsLoader: Loader { - active: false - sourceComponent: Component { - CupsWidget {} - } - - onItemChanged: { - root.cupsBuiltinInstance = item; - } - - onActiveChanged: { - if (!active) { - root.cupsBuiltinInstance = null; - } - } - - Connections { - target: SettingsData - function onControlCenterWidgetsChanged() { - const widgets = SettingsData.controlCenterWidgets || []; - const hasCupsWidget = widgets.some(w => w.id === "builtin_cups"); - if (!hasCupsWidget && cupsLoader.active) { - console.log("CupsWidget: No CUPS widget in control center, deactivating loader"); - cupsLoader.active = false; - } - } - } - } - - readonly property var coreWidgetDefinitions: [ - { - "id": "nightMode", - "text": I18n.tr("Night Mode"), - "description": I18n.tr("Blue light filter"), - "icon": "nightlight", - "type": "toggle", - "enabled": DisplayService.automationAvailable, - "warning": !DisplayService.automationAvailable ? I18n.tr("Requires night mode support") : undefined - }, - { - "id": "darkMode", - "text": I18n.tr("Dark Mode"), - "description": I18n.tr("System theme toggle"), - "icon": "contrast", - "type": "toggle", - "enabled": true - }, - { - "id": "doNotDisturb", - "text": I18n.tr("Do Not Disturb"), - "description": I18n.tr("Block notifications"), - "icon": "do_not_disturb_on", - "type": "toggle", - "enabled": true - }, - { - "id": "idleInhibitor", - "text": I18n.tr("Keep Awake"), - "description": I18n.tr("Prevent screen timeout"), - "icon": "motion_sensor_active", - "type": "toggle", - "enabled": true - }, - { - "id": "wifi", - "text": I18n.tr("Network"), - "description": I18n.tr("Wi-Fi and Ethernet connection"), - "icon": "wifi", - "type": "connection", - "enabled": NetworkService.wifiAvailable, - "warning": !NetworkService.wifiAvailable ? I18n.tr("Wi-Fi not available") : undefined - }, - { - "id": "bluetooth", - "text": I18n.tr("Bluetooth"), - "description": I18n.tr("Device connections"), - "icon": "bluetooth", - "type": "connection", - "enabled": BluetoothService.available, - "warning": !BluetoothService.available ? I18n.tr("Bluetooth not available") : undefined - }, - { - "id": "audioOutput", - "text": I18n.tr("Audio Output"), - "description": I18n.tr("Speaker settings"), - "icon": "volume_up", - "type": "connection", - "enabled": true - }, - { - "id": "audioInput", - "text": I18n.tr("Audio Input"), - "description": I18n.tr("Microphone settings"), - "icon": "mic", - "type": "connection", - "enabled": true - }, - { - "id": "volumeSlider", - "text": I18n.tr("Volume Slider"), - "description": I18n.tr("Audio volume control"), - "icon": "volume_up", - "type": "slider", - "enabled": true - }, - { - "id": "brightnessSlider", - "text": I18n.tr("Brightness Slider"), - "description": I18n.tr("Display brightness control"), - "icon": "brightness_6", - "type": "slider", - "enabled": DisplayService.brightnessAvailable, - "warning": !DisplayService.brightnessAvailable ? I18n.tr("Brightness control not available") : undefined, - "allowMultiple": true - }, - { - "id": "inputVolumeSlider", - "text": I18n.tr("Input Volume Slider"), - "description": I18n.tr("Microphone volume control"), - "icon": "mic", - "type": "slider", - "enabled": true - }, - { - "id": "battery", - "text": I18n.tr("Battery"), - "description": I18n.tr("Battery and power management"), - "icon": "battery_std", - "type": "action", - "enabled": true - }, - { - "id": "diskUsage", - "text": I18n.tr("Disk Usage"), - "description": I18n.tr("Filesystem usage monitoring"), - "icon": "storage", - "type": "action", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined, - "allowMultiple": true - }, - { - "id": "colorPicker", - "text": I18n.tr("Color Picker"), - "description": I18n.tr("Choose colors from palette"), - "icon": "palette", - "type": "action", - "enabled": true - }, - { - "id": "builtin_vpn", - "text": I18n.tr("VPN"), - "description": I18n.tr("VPN connections"), - "icon": "vpn_key", - "type": "builtin_plugin", - "enabled": DMSNetworkService.available, - "warning": !DMSNetworkService.available ? I18n.tr("VPN not available") : undefined, - "isBuiltinPlugin": true - }, - { - "id": "builtin_cups", - "text": I18n.tr("Printers"), - "description": I18n.tr("Print Server Management"), - "icon": "Print", - "type": "builtin_plugin", - "enabled": CupsService.available, - "warning": !CupsService.available ? I18n.tr("CUPS not available") : undefined, - "isBuiltinPlugin": true - } - ] - - function getPluginWidgets() { - const plugins = []; - const loadedPlugins = PluginService.getLoadedPlugins(); - - for (var i = 0; i < loadedPlugins.length; i++) { - const plugin = loadedPlugins[i]; - - if (plugin.type === "daemon") { - continue; - } - - const pluginComponent = PluginService.pluginWidgetComponents[plugin.id]; - if (!pluginComponent) - continue; - - let tempInstance; - try { - tempInstance = pluginComponent.createObject(null); - } catch (e) { - PluginService.reloadPlugin(plugin.id); - continue; - } - if (!tempInstance) - continue; - - const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0; - tempInstance.destroy(); - - if (!hasCCWidget) { - continue; - } - - plugins.push({ - "id": "plugin_" + plugin.id, - "pluginId": plugin.id, - "text": plugin.name || I18n.tr("Plugin"), - "description": plugin.description || "", - "icon": plugin.icon || "extension", - "type": "plugin", - "enabled": true, - "isPlugin": true - }); - } - - return plugins; - } - - readonly property var baseWidgetDefinitions: coreWidgetDefinitions - - function getWidgetForId(widgetId) { - return WidgetUtils.getWidgetForId(baseWidgetDefinitions, widgetId); - } - - function addWidget(widgetId) { - WidgetUtils.addWidget(widgetId); - } - - function removeWidget(index) { - WidgetUtils.removeWidget(index); - } - - function toggleWidgetSize(index) { - WidgetUtils.toggleWidgetSize(index); - } - - function moveWidget(fromIndex, toIndex) { - WidgetUtils.moveWidget(fromIndex, toIndex); - } - - function resetToDefault() { - WidgetUtils.resetToDefault(); - } - - function clearAll() { - WidgetUtils.clearAll(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml deleted file mode 100644 index 81d346d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml +++ /dev/null @@ -1,103 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var defaultSink: AudioService.sink - property color sliderTrackColor: "transparent" - - height: 40 - spacing: 0 - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - visible: defaultSink !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (defaultSink) { - SessionData.suppressOSDTemporarily(); - defaultSink.audio.muted = !defaultSink.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!defaultSink) - return "volume_off"; - - let volume = defaultSink.audio.volume; - let muted = defaultSink.audio.muted; - - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: defaultSink && !defaultSink.audio.muted && defaultSink.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - id: volumeSlider - - readonly property real actualVolumePercent: defaultSink ? Math.round(defaultSink.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: defaultSink !== null - minimum: 0 - maximum: AudioService.sinkMaxVolume - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onSliderValueChanged: function (newValue) { - if (defaultSink) { - SessionData.suppressOSDTemporarily(); - defaultSink.audio.volume = newValue / 100.0; - if (newValue > 0 && defaultSink.audio.muted) { - defaultSink.audio.muted = false; - } - AudioService.playVolumeChangeSoundIfEnabled(); - } - } - } - - Binding { - target: volumeSlider - property: "value" - value: defaultSink ? Math.min(AudioService.sinkMaxVolume, Math.round(defaultSink.audio.volume * 100)) : 0 - when: !volumeSlider.isDragging - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml deleted file mode 100644 index c14c308..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - iconName: BatteryService.getBatteryIcon() - - isActive: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - - primaryText: { - if (!BatteryService.batteryAvailable) { - return I18n.tr("No battery"); - } - return I18n.tr("Battery"); - } - - secondaryText: { - if (!BatteryService.batteryAvailable) { - return I18n.tr("Not available"); - } - if (BatteryService.isCharging) { - return `${BatteryService.batteryLevel}% • ` + I18n.tr("Charging"); - } - if (BatteryService.isPluggedIn) { - return `${BatteryService.batteryLevel}% • ` + I18n.tr("Plugged in"); - } - return `${BatteryService.batteryLevel}%`; - } - - iconColor: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - return Theme.surfaceText; - } - - onToggled: { - expandClicked(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml deleted file mode 100644 index 037c08f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml +++ /dev/null @@ -1,194 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string deviceName: "" - property string instanceId: "" - property string screenName: "" - property var parentScreen: null - - signal iconClicked - - height: 40 - spacing: 0 - - DankTooltipV2 { - id: sharedTooltip - } - - property string targetDeviceName: { - if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) { - return ""; - } - - if (screenName && screenName.length > 0) { - const pins = SettingsData.brightnessDevicePins || {}; - const pinnedDevice = pins[screenName]; - if (pinnedDevice && pinnedDevice.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === pinnedDevice); - if (found) { - return found.name; - } - } - } - - if (deviceName && deviceName.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === deviceName); - if (found) { - return found.name; - } - } - - const currentDeviceName = DisplayService.currentDevice; - if (currentDeviceName) { - const found = DisplayService.devices.find(dev => dev.name === currentDeviceName); - if (found) { - return found.name; - } - } - - const backlight = DisplayService.devices.find(d => d.class === "backlight"); - if (backlight) { - return backlight.name; - } - - const ddc = DisplayService.devices.find(d => d.class === "ddc"); - if (ddc) { - return ddc.name; - } - - return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""; - } - - property var targetDevice: { - if (!targetDeviceName || !DisplayService.devices) { - return null; - } - - return DisplayService.devices.find(dev => dev.name === targetDeviceName) || null; - } - - property real targetBrightness: { - DisplayService.brightnessVersion; - if (!targetDeviceName) { - return 0; - } - - return DisplayService.getDeviceBrightness(targetDeviceName); - } - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DisplayService.devices && DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor - - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (DisplayService.devices && DisplayService.devices.length > 1) { - root.iconClicked(); - } - } - - onEntered: { - const tooltipText = targetDevice ? "bl device: " + targetDevice.name : "Backlight Control"; - sharedTooltip.show(tooltipText, iconArea, 0, 0, "bottom"); - } - - onExited: { - sharedTooltip.hide(); - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!DisplayService.brightnessAvailable || !targetDevice) { - return "brightness_low"; - } - - if (targetDevice.class === "backlight" || targetDevice.class === "ddc") { - const brightness = targetBrightness; - if (brightness <= 33) - return "brightness_low"; - if (brightness <= 66) - return "brightness_medium"; - return "brightness_high"; - } else if (targetDevice.name.includes("kbd")) { - return "keyboard"; - } else { - return "lightbulb"; - } - } - size: Theme.iconSize - color: DisplayService.brightnessAvailable && targetDevice && targetBrightness > 0 ? Theme.primary : Theme.surfaceText - } - } - } - - DankSlider { - id: brightnessSlider - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: DisplayService.brightnessAvailable && targetDeviceName.length > 0 - minimum: { - if (!targetDevice) - return 1; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return 1; - } - return (targetDevice.class === "backlight" || targetDevice.class === "ddc") ? 1 : 0; - } - maximum: { - if (!targetDevice) - return 100; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return 100; - } - return targetDevice.displayMax || 100; - } - showValue: true - unit: { - if (!targetDevice) - return "%"; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return "%"; - } - return targetDevice.class === "ddc" ? "" : "%"; - } - onSliderValueChanged: function (newValue) { - if (DisplayService.brightnessAvailable && targetDeviceName) { - DisplayService.setBrightness(newValue, targetDeviceName, true); - } - } - thumbOutlineColor: Theme.surfaceContainer - trackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Binding on value { - value: root.targetBrightness - when: !brightnessSlider.isDragging - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml deleted file mode 100644 index a95410b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - property var colorPickerModal: null - - isActive: true - iconName: "palette" - iconColor: Theme.primary - primaryText: I18n.tr("Color Picker") - secondaryText: I18n.tr("Choose a color") - - onToggled: { - console.log("ColorPickerPill toggled, modal:", colorPickerModal); - if (colorPickerModal) { - colorPickerModal.show(); - } - } - - onExpandClicked: { - console.log("ColorPickerPill expandClicked, modal:", colorPickerModal); - if (colorPickerModal) { - colorPickerModal.show(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml deleted file mode 100644 index eeed4c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml +++ /dev/null @@ -1,71 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property color iconColor: Theme.surfaceText - property string labelText: "" - property real value: 0.0 - property real maximumValue: 1.0 - property real minimumValue: 0.0 - property bool enabled: true - - signal sliderValueChanged(real value) - - width: parent ? parent.width : 200 - height: 60 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: enabled ? 1.0 : 0.6 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.right: sliderContainer.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: root.iconColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.labelText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - id: sliderContainer - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingM - width: 120 - height: parent.height - Theme.spacingS * 2 - - DankSlider { - anchors.centerIn: parent - width: parent.width - enabled: root.enabled - minimum: Math.round(root.minimumValue * 100) - maximum: Math.round(root.maximumValue * 100) - value: Math.round(root.value * 100) - onSliderValueChanged: root.sliderValueChanged(newValue / 100.0) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml deleted file mode 100644 index 9165ec4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml +++ /dev/null @@ -1,205 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property color iconColor: Theme.surfaceText - property string primaryText: "" - property string secondaryText: "" - property bool expanded: false - property bool isActive: false - property bool showExpandArea: true - - signal toggled - signal expandClicked - signal wheelEvent(var wheelEvent) - - width: parent ? parent.width : 220 - height: 60 - radius: Theme.cornerRadius - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - color: { - const baseColor = bodyMouse.containsMouse ? Theme.primaryPressed : _containerBg; - return baseColor; - } - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.10) - border.width: 0 - antialiasing: true - - readonly property color _labelPrimary: Theme.surfaceText - readonly property color _labelSecondary: Theme.surfaceVariantText - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: { - const transparency = Theme.popupTransparency; - const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1); - return Qt.rgba(surface.r, surface.g, surface.b, transparency); - } - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileRingInactive: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.18) - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - property int _padH: Theme.spacingS - property int _tileSize: 48 - property int _tileRadius: Theme.cornerRadius - - Rectangle { - id: rightHoverOverlay - anchors.fill: parent - radius: root.radius - z: 0 - visible: false - color: hoverTint(_containerBg) - opacity: 0.08 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankRipple { - id: bodyRipple - cornerRadius: root.radius - } - - Row { - id: row - anchors.fill: parent - anchors.leftMargin: _padH - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - id: iconTile - z: 1 - width: _tileSize - height: _tileSize - anchors.verticalCenter: parent.verticalCenter - radius: _tileRadius - color: isActive ? _tileBgActive : _tileBgInactive - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - - Rectangle { - anchors.fill: parent - radius: _tileRadius - color: hoverTint(iconTile.color) - opacity: tileMouse.pressed ? 0.3 : (tileMouse.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankIcon { - anchors.centerIn: parent - name: iconName - size: Theme.iconSize - color: isActive ? _tileIconActive : _tileIconInactive - } - - DankRipple { - id: tileRipple - cornerRadius: _tileRadius - } - - MouseArea { - id: tileMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => tileRipple.trigger(mouse.x, mouse.y) - onClicked: root.toggled() - } - } - - Item { - id: body - width: row.width - iconTile.width - row.spacing - height: row.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - width: parent.width - text: root.primaryText - color: _labelPrimary - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - StyledText { - width: parent.width - text: root.secondaryText - color: _labelSecondary - font.pixelSize: Theme.fontSizeSmall - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - - MouseArea { - id: bodyMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - rightHoverOverlay.visible = true; - rightHoverOverlay.opacity = 0.08; - } - onExited: { - rightHoverOverlay.opacity = 0.0; - rightHoverOverlay.visible = false; - } - onPressed: mouse => { - const pos = mapToItem(root, mouse.x, mouse.y); - bodyRipple.trigger(pos.x, pos.y); - rightHoverOverlay.opacity = 0.16; - } - onReleased: rightHoverOverlay.opacity = containsMouse ? 0.08 : 0.0 - onClicked: root.expandClicked() - onWheel: function (ev) { - root.wheelEvent(ev); - } - } - } - } - - focus: true - Keys.onPressed: function (ev) { - if (ev.key === Qt.Key_Space || ev.key === Qt.Key_Return) { - root.toggled(); - ev.accepted = true; - } else if (ev.key === Qt.Key_Right) { - root.expandClicked(); - ev.accepted = true; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml deleted file mode 100644 index 2d946f3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml +++ /dev/null @@ -1,23 +0,0 @@ -import QtQuick - -Rectangle { - id: root - - property string title: "" - property Component content: null - property bool isVisible: true - property int contentHeight: 300 - - width: parent ? parent.width : 400 - implicitHeight: isVisible ? contentHeight : 0 - height: implicitHeight - color: "transparent" - clip: true - - Loader { - id: contentLoader - anchors.fill: parent - sourceComponent: root.content - asynchronous: true - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml deleted file mode 100644 index 827df4e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - property string mountPath: "/" - property string instanceId: "" - - iconName: "storage" - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const targetMount = DgopService.diskMounts.find(mount => mount.mount === mountPath); - return targetMount || DgopService.diskMounts.find(mount => mount.mount === "/") || DgopService.diskMounts[0]; - } - - property real usagePercent: { - if (!selectedMount || !selectedMount.percent) { - return 0; - } - const percentStr = selectedMount.percent.replace("%", ""); - return parseFloat(percentStr) || 0; - } - - isActive: DgopService.dgopAvailable && selectedMount !== null - - primaryText: { - if (!DgopService.dgopAvailable) { - return I18n.tr("Disk Usage"); - } - if (!selectedMount) { - return I18n.tr("No disk data"); - } - return selectedMount.mount; - } - - secondaryText: { - if (!DgopService.dgopAvailable) { - return I18n.tr("dgop not available"); - } - if (!selectedMount) { - return I18n.tr("No disk data available"); - } - return `${selectedMount.used} / ${selectedMount.size} (${usagePercent.toFixed(0)}%)`; - } - - iconColor: { - if (!DgopService.dgopAvailable || !selectedMount) { - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5); - } - if (usagePercent > 90) { - return Theme.error; - } - if (usagePercent > 75) { - return Theme.warning; - } - return Theme.surfaceText; - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - onToggled: { - expandClicked(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml deleted file mode 100644 index cece467..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml +++ /dev/null @@ -1,56 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string primaryMessage: "" - property string secondaryMessage: "" - - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.1) - border.color: Theme.warning - border.width: 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - DankIcon { - name: "warning" - size: 16 - color: Theme.warning - anchors.top: parent.top - anchors.topMargin: 2 - } - - Column { - width: parent.width - 16 - parent.spacing - spacing: Theme.spacingXS - - StyledText { - width: parent.width - text: root.primaryMessage - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - font.weight: Font.Medium - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - width: parent.width - text: root.secondaryMessage - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - visible: text.length > 0 - horizontalAlignment: Text.AlignLeft - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml deleted file mode 100644 index 49ea30e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var defaultSource: AudioService.source - property color sliderTrackColor: "transparent" - - height: 40 - spacing: 0 - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - visible: defaultSource !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (defaultSource) { - SessionData.suppressOSDTemporarily(); - defaultSource.audio.muted = !defaultSource.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!defaultSource) - return "mic_off"; - - let volume = defaultSource.audio.volume; - let muted = defaultSource.audio.muted; - - if (muted || volume === 0.0) - return "mic_off"; - return "mic"; - } - size: Theme.iconSize - color: defaultSource && !defaultSource.audio.muted && defaultSource.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: defaultSource ? Math.round(defaultSource.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: defaultSource !== null - minimum: 0 - maximum: 100 - value: defaultSource ? Math.min(100, Math.round(defaultSource.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - onSliderValueChanged: function (newValue) { - if (defaultSource) { - SessionData.suppressOSDTemporarily(); - defaultSource.audio.volume = newValue / 100.0; - if (newValue > 0 && defaultSource.audio.muted) { - defaultSource.audio.muted = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml deleted file mode 100644 index 02da286..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool isActive: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - property bool enabled: BatteryService.batteryAvailable - - signal clicked - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: parent.parent.width * 0.25 - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - return isActive ? _tileIconActive : _tileIconInactive; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : "" - font.pixelSize: parent.parent.width * 0.15 - font.weight: Font.Medium - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - return isActive ? _tileIconActive : _tileIconInactive; - } - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml deleted file mode 100644 index 30c4e36..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml +++ /dev/null @@ -1,129 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string mountPath: "/" - property string instanceId: "" - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) - return null; - const targetMount = DgopService.diskMounts.find(mount => mount.mount === mountPath); - return targetMount || DgopService.diskMounts.find(mount => mount.mount === "/") || DgopService.diskMounts[0]; - } - - property real usagePercent: { - if (!selectedMount?.percent) - return 0; - return parseFloat(selectedMount.percent.replace("%", "")) || 0; - } - - property bool enabled: DgopService.dgopAvailable - - signal clicked - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: Theme.cornerRadius + 4 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - color: mouseArea.containsMouse ? Theme.primaryPressed : _tileBg - border.color: "transparent" - border.width: 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "storage" - size: Theme.iconSizeSmall - color: { - if (root.usagePercent > 90) - return Theme.error; - if (root.usagePercent > 75) - return Theme.warning; - return Theme.ccTileInactiveIcon; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: root.selectedMount?.mount || root.mountPath - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - width: Math.min(implicitWidth, root.width - Theme.iconSizeSmall - Theme.spacingM) - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `${root.usagePercent.toFixed(0)}%` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: { - if (root.usagePercent > 90) - return Theme.error; - if (root.usagePercent > 75) - return Theme.warning; - return Theme.ccTileInactiveIcon; - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml deleted file mode 100644 index 7d86947..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml +++ /dev/null @@ -1,90 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property bool isActive: false - property bool enabled: true - property real iconRotation: 0 - - signal clicked - signal iconRotationCompleted - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankIcon { - anchors.centerIn: parent - name: iconName - size: Theme.iconSize - color: isActive ? _tileIconActive : _tileIconInactive - rotation: iconRotation - onRotationCompleted: root.iconRotationCompleted() - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml deleted file mode 100644 index b8adda8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml +++ /dev/null @@ -1,134 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - property bool isActive: false - property bool enabled: true - property string secondaryText: "" - property real iconRotation: 0 - - signal clicked - signal iconRotationCompleted - - width: parent ? parent.width : 200 - height: 60 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: enabled ? 1.0 : 0.6 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0) - opacity: mouseArea.containsMouse ? 0.08 : 0.0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingL + 2 - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: isActive ? Theme.ccTileActiveText : Theme.ccTileInactiveIcon - anchors.verticalCenter: parent.verticalCenter - rotation: root.iconRotation - onRotationCompleted: root.iconRotationCompleted() - } - - Item { - width: parent.width - Theme.iconSize - parent.spacing - height: parent.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - width: parent.width - text: root.text - font.pixelSize: Theme.fontSizeMedium - color: isActive ? Theme.ccTileActiveText : Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - width: parent.width - text: root.secondaryText - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.ccTileActiveText : Theme.surfaceVariantText - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js deleted file mode 100644 index b8e5651..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js +++ /dev/null @@ -1,45 +0,0 @@ -function calculateRowsAndWidgets(controlCenterColumn, expandedSection, expandedWidgetIndex) { - var rows = [] - var currentRow = [] - var currentWidth = 0 - var expandedRow = -1 - - const widgets = SettingsData.controlCenterWidgets || [] - const baseWidth = controlCenterColumn.width - const spacing = Theme.spacingS - - for (var i = 0; i < widgets.length; i++) { - const widget = widgets[i] - const widgetWidth = widget.width || 50 - - var itemWidth - if (widgetWidth <= 25) { - itemWidth = (baseWidth - spacing * 3) / 4 - } else if (widgetWidth <= 50) { - itemWidth = (baseWidth - spacing) / 2 - } else if (widgetWidth <= 75) { - itemWidth = (baseWidth - spacing * 2) * 0.75 - } else { - itemWidth = baseWidth - } - - if (currentRow.length > 0 && (currentWidth + spacing + itemWidth > baseWidth)) { - rows.push([...currentRow]) - currentRow = [widget] - currentWidth = itemWidth - } else { - currentRow.push(widget) - currentWidth += (currentRow.length > 1 ? spacing : 0) + itemWidth - } - - if (expandedWidgetIndex === i) { - expandedRow = rows.length - } - } - - if (currentRow.length > 0) { - rows.push(currentRow) - } - - return { rows: rows, expandedRowIndex: expandedRow } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js deleted file mode 100644 index a2d59a6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js +++ /dev/null @@ -1,17 +0,0 @@ -function openWithSection(root, section) { - if (root.shouldBeVisible) { - root.close(); - } else { - root.expandedSection = section; - root.open(); - } -} - -function toggleSection(root, section) { - if (root.expandedSection === section) { - root.expandedSection = ""; - root.expandedWidgetIndex = -1; - } else { - root.expandedSection = section; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js deleted file mode 100644 index 3e11d88..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js +++ /dev/null @@ -1,90 +0,0 @@ -function getWidgetForId(baseWidgetDefinitions, widgetId) { - return baseWidgetDefinitions.find(w => w.id === widgetId) -} - -function addWidget(widgetId) { - var widgets = SettingsData.controlCenterWidgets.slice() - var widget = { - "id": widgetId, - "enabled": true, - "width": 50 - } - - if (widgetId === "diskUsage") { - widget.instanceId = generateUniqueId() - widget.mountPath = "/" - } - - if (widgetId === "brightnessSlider") { - widget.instanceId = generateUniqueId() - widget.deviceName = "" - } - - widgets.push(widget) - SettingsData.set("controlCenterWidgets", widgets) -} - -function generateUniqueId() { - return Date.now().toString(36) + Math.random().toString(36).substr(2) -} - -function removeWidget(index) { - var widgets = SettingsData.controlCenterWidgets.slice() - if (index >= 0 && index < widgets.length) { - widgets.splice(index, 1) - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function toggleWidgetSize(index) { - var widgets = SettingsData.controlCenterWidgets.slice() - if (index >= 0 && index < widgets.length) { - const currentWidth = widgets[index].width || 50 - const id = widgets[index].id || "" - - if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") { - widgets[index].width = currentWidth <= 50 ? 100 : 50 - } else { - if (currentWidth <= 25) { - widgets[index].width = 50 - } else if (currentWidth <= 50) { - widgets[index].width = 100 - } else { - widgets[index].width = 25 - } - } - - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function reorderWidgets(newOrder) { - SettingsData.set("controlCenterWidgets", newOrder) -} - -function moveWidget(fromIndex, toIndex) { - let widgets = [...(SettingsData.controlCenterWidgets || [])] - if (fromIndex >= 0 && fromIndex < widgets.length && toIndex >= 0 && toIndex < widgets.length) { - const movedWidget = widgets.splice(fromIndex, 1)[0] - widgets.splice(toIndex, 0, movedWidget) - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function resetToDefault() { - const defaultWidgets = [ - {"id": "volumeSlider", "enabled": true, "width": 50}, - {"id": "brightnessSlider", "enabled": true, "width": 50}, - {"id": "wifi", "enabled": true, "width": 50}, - {"id": "bluetooth", "enabled": true, "width": 50}, - {"id": "audioOutput", "enabled": true, "width": 50}, - {"id": "audioInput", "enabled": true, "width": 50}, - {"id": "nightMode", "enabled": true, "width": 50}, - {"id": "darkMode", "enabled": true, "width": 50} - ] - SettingsData.set("controlCenterWidgets", defaultWidgets) -} - -function clearAll() { - SettingsData.set("controlCenterWidgets", []) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml deleted file mode 100644 index 8a8fe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick - -QtObject { - id: root - - property string edge: "top" - - readonly property string orientation: isVertical ? "vertical" : "horizontal" - readonly property bool isVertical: edge === "left" || edge === "right" - readonly property bool isHorizontal: !isVertical - - function primarySize(item) { - return isVertical ? item.height : item.width - } - - function crossSize(item) { - return isVertical ? item.width : item.height - } - - function setPrimaryPos(item, value) { - if (isVertical) { - item.y = value - } else { - item.x = value - } - } - - function getPrimaryPos(item) { - return isVertical ? item.y : item.x - } - - function primaryAnchor(anchors) { - return isVertical ? anchors.verticalCenter : anchors.horizontalCenter - } - - function crossAnchor(anchors) { - return isVertical ? anchors.horizontalCenter : anchors.verticalCenter - } - - function outerVisualEdge() { - if (edge === "bottom") return "bottom" - if (edge === "left") return "right" - if (edge === "right") return "left" - if (edge === "top") return "top" - return "bottom" - } - - signal axisEdgeChanged() - signal axisOrientationChanged() - signal changed() // Single coalesced signal - - onEdgeChanged: { - axisEdgeChanged() - axisOrientationChanged() - changed() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml deleted file mode 100644 index df3f17f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml +++ /dev/null @@ -1,671 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import qs.Common -import qs.Services - -Item { - id: root - - required property var barWindow - required property var axis - required property var barConfig - - anchors.fill: parent - - anchors.left: parent.left - anchors.top: parent.top - readonly property bool gothEnabled: (barConfig?.gothCornersEnabled ?? false) && !barWindow.hasMaximizedToplevel - anchors.leftMargin: -(gothEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0) - anchors.rightMargin: -(gothEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0) - anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0) - anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0) - - readonly property int barPos: barConfig?.position ?? 0 - readonly property bool isTop: barPos === SettingsData.Position.Top - readonly property bool isBottom: barPos === SettingsData.Position.Bottom - readonly property bool isLeft: barPos === SettingsData.Position.Left - readonly property bool isRight: barPos === SettingsData.Position.Right - - property real wing: gothEnabled ? barWindow._wingR : 0 - - Behavior on wing { - enabled: root.width > 0 && root.height > 0 - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - property real rt: { - if (barConfig?.squareCorners ?? false) - return 0; - if (barWindow.hasMaximizedToplevel) - return 0; - return Theme.cornerRadius; - } - - Behavior on rt { - enabled: root.width > 0 && root.height > 0 - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - // M3 elevation shadow — Level 2 baseline (navigation bar), with per-bar override support - readonly property bool hasPerBarOverride: (barConfig?.shadowIntensity ?? 0) > 0 - readonly property var elevLevel: Theme.elevationLevel2 - readonly property bool shadowEnabled: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || hasPerBarOverride - readonly property string autoBarShadowDirection: isTop ? "top" : (isBottom ? "bottom" : (isLeft ? "left" : (isRight ? "right" : "top"))) - readonly property string globalShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection - readonly property string perBarShadowDirectionMode: barConfig?.shadowDirectionMode ?? "inherit" - readonly property string perBarManualShadowDirection: { - switch (barConfig?.shadowDirection) { - case "top": - case "topLeft": - case "topRight": - case "bottom": - return barConfig.shadowDirection; - default: - return "top"; - } - } - readonly property string effectiveShadowDirection: { - if (!hasPerBarOverride) - return globalShadowDirection; - switch (perBarShadowDirectionMode) { - case "autoBar": - return autoBarShadowDirection; - case "manual": - return perBarManualShadowDirection === "autoBar" ? autoBarShadowDirection : perBarManualShadowDirection; - default: - return globalShadowDirection; - } - } - - // Per-bar override values (when barConfig.shadowIntensity > 0) - readonly property real overrideBlurPx: (barConfig?.shadowIntensity ?? 0) * 0.2 - readonly property real overrideOpacity: (barConfig?.shadowOpacity ?? 60) / 100 - readonly property string overrideColorMode: barConfig?.shadowColorMode ?? "default" - readonly property color overrideBaseColor: { - switch (overrideColorMode) { - case "surface": - return Theme.surface; - case "primary": - return Theme.primary; - case "secondary": - return Theme.secondary; - case "custom": - return barConfig?.shadowCustomColor ?? "#000000"; - default: - return "#000000"; - } - } - - // Resolved values — per-bar override wins if set, otherwise use global M3 elevation - readonly property real shadowBlurPx: hasPerBarOverride ? overrideBlurPx : (elevLevel.blurPx ?? 8) - readonly property color shadowColor: hasPerBarOverride ? Theme.withAlpha(overrideBaseColor, overrideOpacity) : Theme.elevationShadowColor(elevLevel) - readonly property real shadowOffsetMagnitude: hasPerBarOverride ? (overrideBlurPx * 0.5) : Theme.elevationOffsetMagnitude(elevLevel, 4, effectiveShadowDirection) - readonly property real shadowOffsetX: Theme.elevationOffsetXFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) - readonly property real shadowOffsetY: Theme.elevationOffsetYFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) - - readonly property string mainPath: generatePathForPosition(width, height) - readonly property string borderFullPath: generateBorderFullPath(width, height) - readonly property string borderEdgePath: generateBorderEdgePath(width, height) - property bool mainPathCorrectShape: false - property bool borderFullPathCorrectShape: false - property bool borderEdgePathCorrectShape: false - - onMainPathChanged: { - if (width > 0 && height > 0) { - root: mainPathCorrectShape = true; - } - } - onBorderFullPathChanged: { - if (width > 0 && height > 0) { - root: borderFullPathCorrectShape = true; - } - } - onBorderEdgePathChanged: { - if (width > 0 && height > 0) { - root: borderEdgePathCorrectShape = true; - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - z: -999 - onClicked: { - const activePopout = PopoutManager.getActivePopout(barWindow.screen); - if (activePopout) { - if (activePopout.dashVisible !== undefined) { - activePopout.dashVisible = false; - } else if (activePopout.notificationHistoryVisible !== undefined) { - activePopout.notificationHistoryVisible = false; - } else { - activePopout.close(); - } - } - TrayMenuManager.closeAllMenus(); - } - } - - ElevationShadow { - id: barShadow - visible: root.shadowEnabled && root.width > 0 && root.height > 0 - - // Size to the bar's rectangular body, excluding gothic wing extensions - x: root.isRight ? root.wing : 0 - y: root.isBottom ? root.wing : 0 - width: axis.isVertical ? (parent.width - root.wing) : parent.width - height: axis.isVertical ? parent.height : (parent.height - root.wing) - - shadowEnabled: root.shadowEnabled - level: root.hasPerBarOverride ? null : root.elevLevel - direction: root.effectiveShadowDirection - fallbackOffset: 4 - targetRadius: root.rt - targetColor: barWindow._bgColor - - shadowBlurPx: root.shadowBlurPx - shadowOffsetX: root.shadowOffsetX - shadowOffsetY: root.shadowOffsetY - shadowColor: root.shadowColor - blurMax: Theme.elevationBlurMax - } - - Loader { - id: barShape - anchors.fill: parent - active: mainPathCorrectShape - sourceComponent: Shape { - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - - ShapePath { - fillColor: barWindow._bgColor - strokeColor: "transparent" - strokeWidth: 0 - - PathSvg { - path: root.mainPath - } - } - } - } - - Loader { - id: barBorder - anchors.fill: parent - active: borderFullPathCorrectShape && borderEdgePathCorrectShape - - readonly property real _scale: CompositorService.getScreenScale(barWindow.screen) - readonly property real borderThickness: Math.ceil(Math.max(1, barConfig?.borderThickness ?? 1) * _scale) / _scale - readonly property real inset: borderThickness / 2 - readonly property string borderColorKey: barConfig?.borderColor || "surfaceText" - readonly property color baseColor: (borderColorKey === "surfaceText") ? Theme.surfaceText : (borderColorKey === "primary") ? Theme.primary : Theme.secondary - readonly property color borderColor: Theme.withAlpha(baseColor, barConfig?.borderOpacity ?? 1.0) - readonly property bool showFullBorder: (barConfig?.spacing ?? 4) > 0 - sourceComponent: Shape { - id: barBorderShape - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - visible: barConfig?.borderEnabled ?? false - - ShapePath { - fillColor: "transparent" - strokeColor: barBorder.borderColor - strokeWidth: barBorder.borderThickness - joinStyle: ShapePath.RoundJoin - capStyle: ShapePath.FlatCap - - PathSvg { - path: barBorder.showFullBorder ? root.borderFullPath : root.borderEdgePath - } - } - } - } - - function generatePathForPosition(w, h) { - if (isTop) - return generateTopPath(w, h); - if (isBottom) - return generateBottomPath(w, h); - if (isLeft) - return generateLeftPath(w, h); - if (isRight) - return generateRightPath(w, h); - return generateTopPath(w, h); - } - - function generateBorderPathForPosition() { - if (isTop) - return generateTopBorderPath(); - if (isBottom) - return generateBottomBorderPath(); - if (isLeft) - return generateLeftBorderPath(); - if (isRight) - return generateRightBorderPath(); - return generateTopBorderPath(); - } - - function generateTopPath(w, h) { - h = h - wing; - const r = wing; - const cr = rt; - - let d = `M ${cr} 0`; - d += ` L ${w - cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w} ${cr}`; - if (r > 0) { - d += ` L ${w} ${h + r}`; - d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; - d += ` L ${r} ${h}`; - d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; - } else { - d += ` L ${w} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - } - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - d += " Z"; - return d; - } - - function generateBottomPath(w, h) { - const fullH = h; - h = h - wing; - const r = wing; - const cr = rt; - - let d = `M ${cr} ${fullH}`; - d += ` L ${w - cr} ${fullH}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w} ${fullH - cr}`; - if (r > 0) { - d += ` L ${w} 0`; - d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 1 0 0`; - } else { - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; - } - d += ` L 0 ${fullH - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${cr} ${fullH}`; - d += " Z"; - return d; - } - - function generateLeftPath(w, h) { - w = w - wing; - const r = wing; - const cr = rt; - - let d = `M 0 ${cr}`; - d += ` L 0 ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${cr} ${h}`; - if (r > 0) { - d += ` L ${w + r} ${h}`; - d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; - d += ` L ${w} ${r}`; - d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; - } else { - d += ` L ${w - cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w} ${h - cr}`; - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; - } - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; - d += " Z"; - return d; - } - - function generateRightPath(w, h) { - const fullW = w; - w = w - wing; - const r = wing; - const cr = rt; - - let d = `M ${fullW} ${cr}`; - d += ` L ${fullW} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - cr} ${h}`; - if (r > 0) { - d += ` L 0 ${h}`; - d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 0 0 0`; - } else { - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - } - d += ` L ${fullW - cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW} ${cr}`; - d += " Z"; - return d; - } - - function generateTopBorderPath() { - const w = barBorder.width; - const h = barBorder.height - wing; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w} ${h + r}`; - d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; - d += ` L ${r} ${h}`; - d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; - } else { - d = `M ${w} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - } - return d; - } - - function generateBottomBorderPath() { - const w = barBorder.width; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w} 0`; - d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 1 0 0`; - } else { - d = `M ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${cr}`; - } - return d; - } - - function generateLeftBorderPath() { - const w = barBorder.width - wing; - const h = barBorder.height; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w + r} ${h}`; - d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; - d += ` L ${w} ${r}`; - d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; - } else { - d = `M ${w - cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w} ${h - cr}`; - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; - } - return d; - } - - function generateRightBorderPath() { - const h = barBorder.height; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M 0 ${h}`; - d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 0 0 0`; - } else { - d = `M ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - } - return d; - } - - function generateBorderFullPath(fullW, fullH) { - const i = barBorder.inset; - const r = wing; - const cr = rt; - - if (isTop) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = `M ${i + cr} ${i}`; - d += ` L ${i + w - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w} ${i + cr}`; - if (r > 0) { - d += ` L ${i + w} ${fullH - i}`; - d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; - d += ` L ${i + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${fullH - i}`; - } else { - d += ` L ${i + w} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; - d += ` L ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - } - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - d += " Z"; - return d; - } - - if (isBottom) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = `M ${i + cr} ${fullH - i}`; - d += ` L ${i + w - cr} ${fullH - i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${fullH - i - cr}`; - if (r > 0) { - d += ` L ${i + w} ${i}`; - d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; - } else { - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - } - d += ` L ${i} ${fullH - i - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${fullH - i}`; - d += " Z"; - return d; - } - - if (isLeft) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = `M ${i} ${i + cr}`; - d += ` L ${i} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${i + h}`; - if (r > 0) { - d += ` L ${fullW - i} ${i + h}`; - d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; - d += ` L ${i + w} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${fullW - i} ${i}`; - } else { - d += ` L ${i + w - cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${i + h - cr}`; - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - } - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - d += " Z"; - return d; - } - - if (isRight) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = `M ${fullW - i} ${i + cr}`; - d += ` L ${fullW - i} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - i - cr} ${i + h}`; - if (r > 0) { - d += ` L ${i} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; - } else { - d += ` L ${wing + i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${wing + i} ${i + h - cr}`; - d += ` L ${wing + i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${wing + i + cr} ${i}`; - } - d += ` L ${fullW - i - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - i} ${i + cr}`; - d += " Z"; - return d; - } - - return ""; - } - - function generateBorderEdgePath(fullW, fullH) { - const i = barBorder.inset; - const r = wing; - const cr = rt; - - if (isTop) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w} ${i + h + r}`; - d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; - d += ` L ${i + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i + h + r}`; - } else { - d = `M ${i + w} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; - d += ` L ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - } - return d; - } - - if (isBottom) { - const w = fullW - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w} ${i}`; - d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; - } else { - d = `M ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - } - return d; - } - - if (isLeft) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; - d += ` L ${i + w} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i + w + r} ${i}`; - } else { - d = `M ${i + w - cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${i + h - cr}`; - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - } - return d; - } - - if (isRight) { - const h = fullH - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; - } else { - d = `M ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - } - return d; - } - - return ""; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml deleted file mode 100644 index df86d4d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml +++ /dev/null @@ -1,387 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property string section: "center" - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - - property var centerWidgets: [] - property int totalWidgets: 0 - property real totalSize: 0 - - function updateLayout() { - if (SettingsData.centeringMode === "geometric") { - applyGeometricLayout(); - } else { - applyIndexLayout(); - } - } - - function applyGeometricLayout() { - if ((isVertical ? height : width) <= 0 || !visible) - return; - - centerWidgets = []; - totalWidgets = 0; - totalSize = 0; - - for (var i = 0; i < centerRepeater.count; i++) { - const loader = centerRepeater.itemAt(i); - if (loader && loader.active && loader.item) { - centerWidgets.push(loader.item); - totalWidgets++; - totalSize += isVertical ? loader.item.height : loader.item.width; - } - } - - if (totalWidgets === 0) - return; - - if (totalWidgets > 1) - totalSize += widgetSpacing * (totalWidgets - 1); - - positionWidgetsGeometric(); - } - - function positionWidgetsGeometric() { - const parentLength = isVertical ? height : width; - const parentCenter = parentLength / 2; - let currentPos = parentCenter - (totalSize / 2); - - centerWidgets.forEach(widget => { - if (isVertical) { - widget.anchors.verticalCenter = undefined; - widget.y = currentPos; - } else { - widget.anchors.horizontalCenter = undefined; - widget.x = currentPos; - } - const widgetSize = isVertical ? widget.height : widget.width; - currentPos += widgetSize + widgetSpacing; - }); - } - - function applyIndexLayout() { - if ((isVertical ? height : width) <= 0 || !visible) - return; - - centerWidgets = []; - totalWidgets = 0; - totalSize = 0; - - let configuredMiddleWidget = null; - let configuredLeftWidget = null; - let configuredRightWidget = null; - - const configuredWidgets = centerRepeater.count; - const isOddConfigured = configuredWidgets % 2 === 1; - const configuredMiddlePos = Math.floor(configuredWidgets / 2); - const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1); - const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2); - - for (var i = 0; i < centerRepeater.count; i++) { - const wrapper = centerRepeater.itemAt(i); - if (!wrapper) - continue; - - if (isOddConfigured && i === configuredMiddlePos && wrapper.active && wrapper.item) - configuredMiddleWidget = wrapper.item; - if (!isOddConfigured && i === configuredLeftPos && wrapper.active && wrapper.item) - configuredLeftWidget = wrapper.item; - if (!isOddConfigured && i === configuredRightPos && wrapper.active && wrapper.item) - configuredRightWidget = wrapper.item; - - if (wrapper.active && wrapper.item) { - centerWidgets.push(wrapper.item); - totalWidgets++; - totalSize += isVertical ? wrapper.item.height : wrapper.item.width; - } - } - - if (totalWidgets === 0) - return; - - if (totalWidgets > 1) - totalSize += widgetSpacing * (totalWidgets - 1); - - positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget); - } - - function positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) { - const parentCenter = (isVertical ? height : width) / 2; - const isOddConfigured = configuredWidgets % 2 === 1; - - centerWidgets.forEach(widget => { - if (isVertical) - widget.anchors.verticalCenter = undefined; - else - widget.anchors.horizontalCenter = undefined; - }); - - if (isOddConfigured && configuredMiddleWidget) { - const middleWidget = configuredMiddleWidget; - const middleIndex = centerWidgets.indexOf(middleWidget); - const middleSize = isVertical ? middleWidget.height : middleWidget.width; - - if (isVertical) - middleWidget.y = parentCenter - (middleSize / 2); - else - middleWidget.x = parentCenter - (middleSize / 2); - - let currentPos = isVertical ? middleWidget.y : middleWidget.x; - for (var i = middleIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize; - for (var i = middleIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - return; - } - - if (totalWidgets === 1) { - const widget = centerWidgets[0]; - const size = isVertical ? widget.height : widget.width; - if (isVertical) - widget.y = parentCenter - (size / 2); - else - widget.x = parentCenter - (size / 2); - return; - } - - if (!configuredLeftWidget || !configuredRightWidget) { - if (totalWidgets % 2 === 1) { - const middleIndex = Math.floor(totalWidgets / 2); - const middleWidget = centerWidgets[middleIndex]; - - if (!middleWidget) - return; - - const middleSize = isVertical ? middleWidget.height : middleWidget.width; - - if (isVertical) - middleWidget.y = parentCenter - (middleSize / 2); - else - middleWidget.x = parentCenter - (middleSize / 2); - - let currentPos = isVertical ? middleWidget.y : middleWidget.x; - for (var i = middleIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize; - for (var i = middleIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } else { - const leftIndex = (totalWidgets / 2) - 1; - const rightIndex = totalWidgets / 2; - const fallbackLeft = centerWidgets[leftIndex]; - const fallbackRight = centerWidgets[rightIndex]; - - if (!fallbackLeft || !fallbackRight) - return; - - const halfSpacing = widgetSpacing / 2; - const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width; - - if (isVertical) { - fallbackLeft.y = parentCenter - halfSpacing - leftSize; - fallbackRight.y = parentCenter + halfSpacing; - } else { - fallbackLeft.x = parentCenter - halfSpacing - leftSize; - fallbackRight.x = parentCenter + halfSpacing; - } - - let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x; - for (var i = leftIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width); - for (var i = rightIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } - return; - } - - const leftWidget = configuredLeftWidget; - const rightWidget = configuredRightWidget; - const leftIndex = centerWidgets.indexOf(leftWidget); - const rightIndex = centerWidgets.indexOf(rightWidget); - const halfSpacing = widgetSpacing / 2; - const leftSize = isVertical ? leftWidget.height : leftWidget.width; - - if (isVertical) { - leftWidget.y = parentCenter - halfSpacing - leftSize; - rightWidget.y = parentCenter + halfSpacing; - } else { - leftWidget.x = parentCenter - halfSpacing - leftSize; - rightWidget.x = parentCenter + halfSpacing; - } - - let currentPos = isVertical ? leftWidget.y : leftWidget.x; - for (var i = leftIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width); - for (var i = rightIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } - - height: parent.height - width: parent.width - anchors.centerIn: parent - - implicitWidth: isVertical ? widgetThickness : totalSize - implicitHeight: isVertical ? totalSize : widgetThickness - - Timer { - id: layoutTimer - interval: 0 - repeat: false - onTriggered: root.updateLayout() - } - - Component.onCompleted: layoutTimer.restart() - - onWidthChanged: { - if (width > 0) - layoutTimer.restart(); - } - - onHeightChanged: { - if (height > 0) - layoutTimer.restart(); - } - - onVisibleChanged: { - if (visible && (isVertical ? height : width) > 0) - layoutTimer.restart(); - } - - Repeater { - id: centerRepeater - model: root.widgetsModel - - onCountChanged: layoutTimer.restart() - - Item { - property var itemData: modelData - readonly property real itemSpacing: root.widgetSpacing - - width: root.isVertical ? root.width : (widgetLoader.item ? widgetLoader.item.width : 0) - height: widgetLoader.item ? widgetLoader.item.height : 0 - - readonly property bool active: widgetLoader.active - readonly property var item: widgetLoader.item - - WidgetHost { - id: widgetLoader - - anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined - anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined - - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: root.isVertical - axis: root.axis - section: "center" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === centerRepeater.count - 1 - sectionSpacing: parent.itemSpacing - isLeftBarEdge: false - isRightBarEdge: false - isTopBarEdge: false - isBottomBarEdge: false - - onContentItemReady: contentItem => { - contentItem.widthChanged.connect(() => layoutTimer.restart()); - contentItem.heightChanged.connect(() => layoutTimer.restart()); - layoutTimer.restart(); - } - - onActiveChanged: layoutTimer.restart() - } - } - } - - Connections { - target: SettingsData - function onCenteringModeChanged() { - layoutTimer.restart(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml deleted file mode 100644 index 392bf9b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml +++ /dev/null @@ -1,182 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.I3 -import qs.Common -import qs.Services - -Item { - id: root - - required property var barConfig - - signal colorPickerRequested - signal barReady(var barConfig) - - property alias barVariants: barVariants - property var hyprlandOverviewLoader: null - property bool systemTrayMenuOpen: false - - property alias leftWidgetsModel: leftWidgetsModel - property alias centerWidgetsModel: centerWidgetsModel - property alias rightWidgetsModel: rightWidgetsModel - - property string _leftWidgetsJson: { - root.barConfig; - const leftWidgets = root.barConfig?.leftWidgets || []; - const mapped = leftWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - property string _centerWidgetsJson: { - root.barConfig; - const centerWidgets = root.barConfig?.centerWidgets || []; - const mapped = centerWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - property string _rightWidgetsJson: { - root.barConfig; - const rightWidgets = root.barConfig?.rightWidgets || []; - const mapped = rightWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - ScriptModel { - id: leftWidgetsModel - values: JSON.parse(root._leftWidgetsJson) - } - - ScriptModel { - id: centerWidgetsModel - values: JSON.parse(root._centerWidgetsJson) - } - - ScriptModel { - id: rightWidgetsModel - values: JSON.parse(root._rightWidgetsJson) - } - - function triggerControlCenterOnFocusedScreen() { - let focusedScreenName = ""; - if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { - focusedScreenName = Hyprland.focusedWorkspace.monitor.name; - } else if (CompositorService.isNiri && NiriService.currentOutput) { - focusedScreenName = NiriService.currentOutput; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - focusedScreenName = focusedWs?.monitor?.name || ""; - } else if (CompositorService.isDwl && DwlService.activeOutput) { - focusedScreenName = DwlService.activeOutput; - } - - if (!focusedScreenName && barVariants.instances.length > 0) { - const firstBar = barVariants.instances[0]; - firstBar.triggerControlCenter(); - return true; - } - - for (var i = 0; i < barVariants.instances.length; i++) { - const barInstance = barVariants.instances[i]; - if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { - barInstance.triggerControlCenter(); - return true; - } - } - return false; - } - - function triggerWallpaperBrowserOnFocusedScreen() { - let focusedScreenName = ""; - if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { - focusedScreenName = Hyprland.focusedWorkspace.monitor.name; - } else if (CompositorService.isNiri && NiriService.currentOutput) { - focusedScreenName = NiriService.currentOutput; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - focusedScreenName = focusedWs?.monitor?.name || ""; - } else if (CompositorService.isDwl && DwlService.activeOutput) { - focusedScreenName = DwlService.activeOutput; - } - - if (!focusedScreenName && barVariants.instances.length > 0) { - const firstBar = barVariants.instances[0]; - firstBar.triggerWallpaperBrowser(); - return true; - } - - for (var i = 0; i < barVariants.instances.length; i++) { - const barInstance = barVariants.instances[i]; - if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { - barInstance.triggerWallpaperBrowser(); - return true; - } - } - return false; - } - - Variants { - id: barVariants - model: { - const prefs = root.barConfig?.screenPreferences || ["all"]; - if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) { - return Quickshell.screens; - } - const filtered = Quickshell.screens.filter(screen => SettingsData.isScreenInPreferences(screen, prefs)); - if (filtered.length === 0 && root.barConfig?.showOnLastDisplay && Quickshell.screens.length === 1) { - return Quickshell.screens; - } - return filtered; - } - - delegate: DankBarWindow { - rootWindow: root - barConfig: root.barConfig - leftWidgetsModel: root.leftWidgetsModel - centerWidgetsModel: root.centerWidgetsModel - rightWidgetsModel: root.rightWidgetsModel - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml deleted file mode 100644 index 0c977bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml +++ /dev/null @@ -1,1459 +0,0 @@ -import QtQuick -import Quickshell.Hyprland -import Quickshell.I3 -import Quickshell.Services.SystemTray -import Quickshell.Wayland -import qs.Common -import qs.Modules.DankBar.Widgets -import qs.Services - -Item { - id: topBarContent - - required property var barWindow - required property var rootWindow - required property var barConfig - - readonly property var blurBarWindow: barWindow - - property var leftWidgetsModel - property var centerWidgetsModel - property var rightWidgetsModel - - readonly property real innerPadding: barConfig?.innerPadding ?? 4 - readonly property real outlineThickness: (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0 - - property alias hLeftSection: hLeftSection - property alias hCenterSection: hCenterSection - property alias hRightSection: hRightSection - property alias vLeftSection: vLeftSection - property alias vCenterSection: vCenterSection - property alias vRightSection: vRightSection - - anchors.fill: parent - anchors.leftMargin: Math.max(Theme.spacingXS, innerPadding * 0.8) - anchors.rightMargin: Math.max(Theme.spacingXS, innerPadding * 0.8) - anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? outlineThickness : Theme.spacingXS) : 0 - anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? outlineThickness : Theme.spacingXS) : 0 - clip: false - - property int componentMapRevision: 0 - - function updateComponentMap() { - componentMapRevision++; - } - - readonly property var sortedToplevels: { - return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, barWindow.screenName); - } - - function getRealWorkspaces() { - if (CompositorService.isNiri) { - const fallbackWorkspaces = [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const currentWorkspaces = NiriService.getCurrentOutputWorkspaces(); - return currentWorkspaces.length > 0 ? currentWorkspaces : fallbackWorkspaces; - } - const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName); - return workspaces.length > 0 ? workspaces : fallbackWorkspaces; - } else if (CompositorService.isHyprland) { - const workspaces = Hyprland.workspaces?.values || []; - - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const sorted = workspaces.slice().sort((a, b) => a.id - b.id); - const filtered = sorted.filter(ws => ws.id > -1); - return filtered.length > 0 ? filtered : [ - { - "id": 1, - "name": "1" - } - ]; - } - - const monitorWorkspaces = workspaces.filter(ws => { - return ws.lastIpcObject && ws.lastIpcObject.monitor === barWindow.screenName && ws.id > -1; - }); - - if (monitorWorkspaces.length === 0) { - return [ - { - "id": 1, - "name": "1" - } - ]; - } - - return monitorWorkspaces.sort((a, b) => a.id - b.id); - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) { - return [0]; - } - if (SettingsData.dwlShowAllTags) { - return Array.from({ - length: DwlService.tagCount - }, (_, i) => i); - } - return DwlService.getVisibleTags(barWindow.screenName); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const workspaces = I3.workspaces?.values || []; - if (workspaces.length === 0) - return [ - { - "num": 1 - } - ]; - - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - return workspaces.slice().sort((a, b) => a.num - b.num); - } - - const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === barWindow.screenName); - return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [ - { - "num": 1 - } - ]; - } - return [1]; - } - - function getCurrentWorkspace() { - if (CompositorService.isNiri) { - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - return NiriService.getCurrentWorkspaceNumber(); - } - const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active); - return activeWs ? activeWs.idx : 1; - } else if (CompositorService.isHyprland) { - const monitors = Hyprland.monitors?.values || []; - const currentMonitor = monitors.find(monitor => monitor.name === barWindow.screenName); - return currentMonitor?.activeWorkspace?.id ?? 1; - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) - return 0; - const outputState = DwlService.getOutputState(barWindow.screenName); - if (!outputState || !outputState.tags) - return 0; - const activeTags = DwlService.getActiveTags(barWindow.screenName); - return activeTags.length > 0 ? activeTags[0] : 0; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === barWindow.screenName && ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - return 1; - } - - function switchWorkspace(direction) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - if (CompositorService.isNiri) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws && ws.idx === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - const nextWorkspace = realWorkspaces[nextIndex]; - if (!nextWorkspace || nextWorkspace.idx === undefined) { - return; - } - NiriService.switchToWorkspace(nextWorkspace.idx); - } - } else if (CompositorService.isHyprland) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws.id === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`); - } - } else if (CompositorService.isDwl) { - const currentTag = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(tag => tag === currentTag); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]); - } - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - try { - I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`); - } catch (_) {} - } - } - } - - function switchApp(deltaY) { - const windows = sortedToplevels; - if (windows.length < 2) { - return; - } - let currentIndex = -1; - for (let i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - let nextIndex; - if (deltaY < 0) { - if (currentIndex === -1) { - nextIndex = 0; - } else { - nextIndex = currentIndex + 1; - } - } else { - if (currentIndex === -1) { - nextIndex = windows.length - 1; - } else { - nextIndex = currentIndex - 1; - } - } - const nextWindow = windows[nextIndex]; - if (nextWindow) { - nextWindow.activate(); - } - } - - readonly property int availableWidth: width - readonly property int launcherButtonWidth: 40 - readonly property int workspaceSwitcherWidth: 120 - readonly property int focusedAppMaxWidth: 456 - readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2) - readonly property int rightSectionWidth: 200 - readonly property int clockWidth: 120 - readonly property int mediaMaxWidth: 280 - readonly property int weatherWidth: 80 - readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0 - readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2 - readonly property int clockRightEdge: clockLeftEdge + clockWidth - readonly property int leftSectionRightEdge: estimatedLeftSectionWidth - readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth - Theme.spacingS - readonly property int rightSectionLeftEdge: availableWidth - rightSectionWidth - readonly property int leftToClockGap: Math.max(0, clockLeftEdge - leftSectionRightEdge) - readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(0, mediaLeftEdge - leftSectionRightEdge) : leftToClockGap - readonly property int mediaToClockGap: mediaMaxWidth > 0 ? Theme.spacingS : 0 - readonly property int clockToRightGap: validLayout ? Math.max(0, rightSectionLeftEdge - clockRightEdge) : 1000 - readonly property bool spacingTight: !barWindow.isVertical && validLayout && (leftToMediaGap < 150 || clockToRightGap < 100) - readonly property bool overlapping: !barWindow.isVertical && validLayout && (leftToMediaGap < 100 || clockToRightGap < 50) - - function getWidgetEnabled(enabled) { - return enabled !== false; - } - - function getWidgetSection(parentItem) { - let current = parentItem; - while (current) { - if (current.objectName === "leftSection") { - return "left"; - } - if (current.objectName === "centerSection") { - return "center"; - } - if (current.objectName === "rightSection") { - return "right"; - } - current = current.parent; - } - return "left"; - } - - readonly property var widgetVisibility: ({ - "cpuUsage": DgopService.dgopAvailable, - "memUsage": DgopService.dgopAvailable, - "cpuTemp": DgopService.dgopAvailable, - "gpuTemp": DgopService.dgopAvailable, - "network_speed_monitor": DgopService.dgopAvailable - }) - - function getWidgetVisible(widgetId) { - return widgetVisibility[widgetId] ?? true; - } - - readonly property var componentMap: { - componentMapRevision; - - let baseMap = { - "launcherButton": launcherButtonComponent, - "workspaceSwitcher": workspaceSwitcherComponent, - "focusedWindow": focusedWindowComponent, - "runningApps": runningAppsComponent, - "appsDock": appsDockComponent, - "clock": clockComponent, - "music": mediaComponent, - "weather": weatherComponent, - "systemTray": systemTrayComponent, - "privacyIndicator": privacyIndicatorComponent, - "clipboard": clipboardComponent, - "cpuUsage": cpuUsageComponent, - "memUsage": memUsageComponent, - "diskUsage": diskUsageComponent, - "cpuTemp": cpuTempComponent, - "gpuTemp": gpuTempComponent, - "notificationButton": notificationButtonComponent, - "battery": batteryComponent, - "layout": layoutComponent, - "controlCenterButton": controlCenterButtonComponent, - "capsLockIndicator": capsLockIndicatorComponent, - "idleInhibitor": idleInhibitorComponent, - "spacer": spacerComponent, - "separator": separatorComponent, - "network_speed_monitor": networkComponent, - "keyboard_layout_name": keyboardLayoutNameComponent, - "vpn": vpnComponent, - "notepadButton": notepadButtonComponent, - "colorPicker": colorPickerComponent, - "systemUpdate": systemUpdateComponent, - "powerMenuButton": powerMenuButtonComponent - }; - - let pluginMap = PluginService.getWidgetComponents(); - return Object.assign(baseMap, pluginMap); - } - - function getWidgetComponent(widgetId) { - return componentMap[widgetId] || null; - } - - readonly property var allComponents: ({ - "launcherButtonComponent": launcherButtonComponent, - "workspaceSwitcherComponent": workspaceSwitcherComponent, - "focusedWindowComponent": focusedWindowComponent, - "runningAppsComponent": runningAppsComponent, - "appsDockComponent": appsDockComponent, - "clockComponent": clockComponent, - "mediaComponent": mediaComponent, - "weatherComponent": weatherComponent, - "systemTrayComponent": systemTrayComponent, - "privacyIndicatorComponent": privacyIndicatorComponent, - "clipboardComponent": clipboardComponent, - "cpuUsageComponent": cpuUsageComponent, - "memUsageComponent": memUsageComponent, - "diskUsageComponent": diskUsageComponent, - "cpuTempComponent": cpuTempComponent, - "gpuTempComponent": gpuTempComponent, - "notificationButtonComponent": notificationButtonComponent, - "batteryComponent": batteryComponent, - "layoutComponent": layoutComponent, - "controlCenterButtonComponent": controlCenterButtonComponent, - "capsLockIndicatorComponent": capsLockIndicatorComponent, - "idleInhibitorComponent": idleInhibitorComponent, - "spacerComponent": spacerComponent, - "separatorComponent": separatorComponent, - "networkComponent": networkComponent, - "keyboardLayoutNameComponent": keyboardLayoutNameComponent, - "vpnComponent": vpnComponent, - "notepadButtonComponent": notepadButtonComponent, - "colorPickerComponent": colorPickerComponent, - "systemUpdateComponent": systemUpdateComponent, - "powerMenuButtonComponent": powerMenuButtonComponent - }) - - Item { - id: stackContainer - anchors.fill: parent - - Item { - id: horizontalStack - anchors.fill: parent - visible: !barWindow.axis.isVertical - - LeftSection { - id: hLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.leftWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hLeftSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hLeftSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - RightSection { - id: hRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.rightWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hRightSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hRightSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - CenterSection { - id: hCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.centerWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hCenterSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hCenterSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - } - - Item { - id: verticalStack - anchors.fill: parent - visible: barWindow.axis.isVertical - - LeftSection { - id: vLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - top: parent.top - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.leftWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vLeftSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vLeftSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - CenterSection { - id: vCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.centerWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vCenterSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vCenterSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - RightSection { - id: vRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - height: implicitHeight - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.rightWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vRightSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vRightSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - } - } - - Component { - id: clipboardComponent - - ClipboardButton { - id: clipboardWidget - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - popoutTarget: clipboardHistoryPopoutLoader.item ?? null - - function openClipboardPopout(initialTab) { - clipboardHistoryPopoutLoader.active = true; - if (!clipboardHistoryPopoutLoader.item) { - return; - } - const popout = clipboardHistoryPopoutLoader.item; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (popout.setBarContext) { - popout.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (popout.setTriggerPosition) { - const globalPos = clipboardWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clipboardWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - popout.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - if (initialTab) { - popout.activeTab = initialTab; - } - PopoutManager.requestPopout(popout, undefined, "clipboard"); - } - - onClipboardClicked: openClipboardPopout("recents") - - onShowSavedItemsRequested: openClipboardPopout("saved") - - onClearAllRequested: { - clipboardHistoryPopoutLoader.active = true; - const popout = clipboardHistoryPopoutLoader.item; - if (!popout?.confirmDialog) { - return; - } - const hasPinned = popout.pinnedCount > 0; - const message = hasPinned ? I18n.tr("This will delete all unpinned entries. %1 pinned entries will be kept.").arg(popout.pinnedCount) : I18n.tr("This will permanently delete all clipboard history."); - popout.confirmDialog.show(I18n.tr("Clear History?"), message, function () { - if (popout && typeof popout.clearAll === "function") { - popout.clearAll(); - } - }, function () {}); - } - } - } - - Component { - id: powerMenuButtonComponent - - PowerMenuButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - onClicked: { - if (powerMenuModalLoader) { - powerMenuModalLoader.active = true; - if (powerMenuModalLoader.item) { - powerMenuModalLoader.item.openCentered(); - } - } - } - } - } - - Component { - id: launcherButtonComponent - - LauncherButton { - id: launcherButton - isActive: false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) - popoutTarget: appDrawerLoader.item - parentScreen: barWindow.screen - hyprlandOverviewLoader: barWindow ? barWindow.hyprlandOverviewLoader : null - - function _preparePopout() { - appDrawerLoader.active = true; - if (!appDrawerLoader.item) - return false; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (appDrawerLoader.item.setBarContext) - appDrawerLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - if (appDrawerLoader.item.setTriggerPosition) { - const globalPos = launcherButton.visualContent.mapToItem(null, 0, 0); - const currentScreen = barWindow.screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - appDrawerLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - return true; - } - - function openWithMode(mode) { - if (!_preparePopout()) - return; - appDrawerLoader.item.openWithMode(mode); - } - - function toggleWithMode(mode) { - if (!_preparePopout()) - return; - appDrawerLoader.item.toggleWithMode(mode); - } - - function openWithQuery(query) { - if (!_preparePopout()) - return; - appDrawerLoader.item.openWithQuery(query); - } - - function toggleWithQuery(query) { - if (!_preparePopout()) - return; - appDrawerLoader.item.toggleWithQuery(query); - } - - onClicked: { - if (!_preparePopout()) - return; - PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer"); - } - } - } - - Component { - id: workspaceSwitcherComponent - - WorkspaceSwitcher { - axis: barWindow.axis - screenName: barWindow.screenName - widgetHeight: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - parentScreen: barWindow.screen - hyprlandOverviewLoader: barWindow ? barWindow.hyprlandOverviewLoader : null - } - } - - Component { - id: focusedWindowComponent - - FocusedApp { - axis: barWindow.axis - availableWidth: topBarContent.leftToMediaGap - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - parentScreen: barWindow.screen - } - } - - Component { - id: runningAppsComponent - - RunningApps { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - topBar: topBarContent - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: appsDockComponent - - AppsDock { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - topBar: topBarContent - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: clockComponent - - Clock { - axis: barWindow.axis - compactMode: topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - - Component.onCompleted: { - barWindow.clockButtonRef = this; - } - - Component.onDestruction: { - if (barWindow.clockButtonRef === this) { - barWindow.clockButtonRef = null; - } - } - - onClockClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 0, (effectiveBarConfig?.id ?? "default") + "-" + section + "-0"); - } - } - } - } - - Component { - id: mediaComponent - - Media { - axis: barWindow.axis - compactMode: topBarContent.spacingTight || topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 1, (effectiveBarConfig?.id ?? "default") + "-" + section + "-1"); - } - } - } - } - - Component { - id: weatherComponent - - Weather { - axis: barWindow.axis - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - // Calculate barPosition from axis.edge - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - // For center section widgets, use center section bounds for DankDash centering - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - // For vertical bars, use center Y of section; for horizontal, use left edge - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - // For horizontal bars, use left edge (DankPopout will center it) - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 3, (effectiveBarConfig?.id ?? "default") + "-" + section + "-3"); - } - } - } - } - - Component { - id: systemTrayComponent - - SystemTrayBar { - parentWindow: barWindow - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - widgetData: parent.widgetData - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - isAtBottom: barWindow.axis?.edge === "bottom" - visible: SettingsData.getFilteredScreens("systemTray").includes(barWindow.screen) && SystemTray.items.values.length > 0 - } - } - - Component { - id: privacyIndicatorComponent - - PrivacyIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: cpuUsageComponent - - CpuMonitor { - id: cpuWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onCpuClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = cpuWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, cpuWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "cpu"); - } - } - } - - Component { - id: memUsageComponent - - RamMonitor { - id: ramWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onRamClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = ramWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, ramWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "memory"); - } - } - } - - Component { - id: diskUsageComponent - - DiskUsage { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - widgetData: parent.widgetData - parentScreen: barWindow.screen - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: cpuTempComponent - - CpuTemperature { - id: cpuTempWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onCpuTempClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = cpuTempWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, cpuTempWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "cpu_temp"); - } - } - } - - Component { - id: gpuTempComponent - - GpuTemperature { - id: gpuTempWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onGpuTempClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = gpuTempWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, gpuTempWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "gpu_temp"); - } - } - } - - Component { - id: networkComponent - - NetworkMonitor {} - } - - Component { - id: notificationButtonComponent - - NotificationCenterButton { - id: notificationButton - hasUnread: barWindow.notificationCount > 0 - isActive: notificationCenterLoader.item ? notificationCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: notificationCenterLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - notificationCenterLoader.active = true; - if (!notificationCenterLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (notificationCenterLoader.item.setBarContext) { - notificationCenterLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (notificationCenterLoader.item.setTriggerPosition) { - const globalPos = notificationButton.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, notificationButton.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - notificationCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(notificationCenterLoader.item, undefined, "notifications"); - } - } - } - - Component { - id: batteryComponent - - Battery { - id: batteryWidget - batteryPopupVisible: batteryPopoutLoader.item ? batteryPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - popoutTarget: batteryPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleBatteryPopup: { - batteryPopoutLoader.active = true; - if (!batteryPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (batteryPopoutLoader.item.setBarContext) { - batteryPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (batteryPopoutLoader.item.setTriggerPosition) { - const globalPos = batteryWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, batteryWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - batteryPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(batteryPopoutLoader.item, undefined, "battery"); - } - } - } - - Component { - id: layoutComponent - - DWLLayout { - id: layoutWidget - layoutPopupVisible: layoutPopoutLoader.item ? layoutPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: layoutPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleLayoutPopup: { - layoutPopoutLoader.active = true; - if (!layoutPopoutLoader.item) - return; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - - if (layoutPopoutLoader.item.setTriggerPosition) { - const globalPos = layoutWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, layoutWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "center"; - layoutPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - - PopoutManager.requestPopout(layoutPopoutLoader.item, undefined, "layout"); - } - } - } - - Component { - id: vpnComponent - - Vpn { - id: vpnWidget - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - popoutTarget: vpnPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleVpnPopup: { - vpnPopoutLoader.active = true; - if (!vpnPopoutLoader.item) - return; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - - if (vpnPopoutLoader.item.setBarContext) { - vpnPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - - if (vpnPopoutLoader.item.setTriggerPosition) { - const globalPos = vpnWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, vpnWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - vpnPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - - PopoutManager.requestPopout(vpnPopoutLoader.item, undefined, "vpn"); - } - } - } - - Component { - id: controlCenterButtonComponent - - ControlCenterButton { - isActive: controlCenterLoader.item ? controlCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: controlCenterLoader.item ?? null - parentScreen: barWindow.screen - screenName: barWindow.screen?.name || "" - screenModel: barWindow.screen?.model || "" - widgetData: parent.widgetData - - Component.onCompleted: { - barWindow.controlCenterButtonRef = this; - } - - Component.onDestruction: { - if (barWindow.controlCenterButtonRef === this) { - barWindow.controlCenterButtonRef = null; - } - } - - onClicked: { - controlCenterLoader.active = true; - if (!controlCenterLoader.item) { - return; - } - controlCenterLoader.item.triggerScreen = barWindow.screen; - if (controlCenterLoader.item.setTriggerPosition) { - const globalPos = mapToItem(null, 0, 0); - // Use topBarContent.barConfig directly - const effectiveBarConfig = topBarContent.barConfig; - // Calculate barPosition from axis.edge like Battery widget does - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const section = topBarContent.getWidgetSection(parent) || "right"; - controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(controlCenterLoader.item, undefined, "controlCenter"); - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi(); - } - } - } - } - - Component { - id: capsLockIndicatorComponent - - CapsLockIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: idleInhibitorComponent - - IdleInhibitor { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: spacerComponent - - Item { - width: barWindow.isVertical ? barWindow.widgetThickness : (parent.spacerSize || 20) - height: barWindow.isVertical ? (parent.spacerSize || 20) : barWindow.widgetThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - anchors.fill: parent - color: "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 1 - radius: 2 - visible: false - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - cursorShape: Qt.ArrowCursor - onEntered: parent.visible = true - onExited: parent.visible = false - } - } - } - } - - Component { - id: separatorComponent - - Item { - width: barWindow.isVertical ? parent.barThickness : 1 - height: barWindow.isVertical ? 1 : parent.barThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - width: barWindow.isVertical ? parent.width * 0.6 : 1 - height: barWindow.isVertical ? 1 : parent.height * 0.6 - anchors.centerIn: parent - color: Theme.outline - opacity: 0.3 - } - } - } - - Component { - id: keyboardLayoutNameComponent - - KeyboardLayoutName {} - } - - Component { - id: notepadButtonComponent - - NotepadButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: colorPickerComponent - - ColorPicker { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - onColorPickerRequested: { - barWindow.colorPickerRequested(); - } - } - } - - Component { - id: systemUpdateComponent - - SystemUpdate { - isActive: systemUpdateLoader.item ? systemUpdateLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: systemUpdateLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - systemUpdateLoader.active = true; - if (!systemUpdateLoader.item) - return; - const popout = systemUpdateLoader.item; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (popout.setBarContext) { - popout.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (popout.setTriggerPosition) { - const globalPos = visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - popout.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(popout, undefined, "systemUpdate"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml deleted file mode 100644 index d8b0216..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml +++ /dev/null @@ -1,1058 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services - -PanelWindow { - id: barWindow - - required property var rootWindow - required property var barConfig - property var modelData: item - property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null - - property var leftWidgetsModel - property var centerWidgetsModel - property var rightWidgetsModel - - property var controlCenterButtonRef: null - property var clockButtonRef: null - - function triggerControlCenter() { - controlCenterLoader.active = true; - if (!controlCenterLoader.item) { - return; - } - - if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) { - const screenPos = controlCenterButtonRef.mapToItem(null, 0, 0); - const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(screenPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width, barConfig?.spacing ?? 4, barPosition, barConfig); - const section = controlCenterButtonRef.section || "right"; - controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig); - } else { - controlCenterLoader.item.triggerScreen = barWindow.screen; - } - - controlCenterLoader.item.toggle(); - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi(); - } - } - - function triggerWallpaperBrowser() { - dankDashPopoutLoader.active = true; - if (!dankDashPopoutLoader.item) { - return; - } - - let section = "center"; - if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) { - // Calculate barPosition from axis.edge - const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1)); - section = clockButtonRef.section || "center"; - - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? topBarContent.vCenterSection : topBarContent.vCenterSection) : topBarContent.hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - triggerPos = centerSection.mapToItem(null, 0, centerY); - triggerWidth = centerSection.height; - } else { - triggerPos = centerSection.mapToItem(null, 0, 0); - triggerWidth = centerSection.width; - } - } else { - triggerPos = clockButtonRef.visualContent.mapToItem(null, 0, 0); - triggerWidth = clockButtonRef.visualWidth; - } - } else { - triggerPos = clockButtonRef.visualContent.mapToItem(null, 0, 0); - triggerWidth = clockButtonRef.visualWidth; - } - - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, barConfig?.spacing ?? 4, barPosition, barConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - - PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-" + section + "-2"); - } - - readonly property var dBarLayer: { - switch (Quickshell.env("DMS_DANKBAR_LAYER")) { - case "bottom": - return WlrLayer.Bottom; - case "overlay": - return WlrLayer.Overlay; - case "background": - return WlrLayer.background; - default: - return WlrLayer.Top; - } - } - - property var blurRegion: null - property var _blurWidgetItems: [] - - function registerBlurWidget(item) { - if (_blurWidgetItems.indexOf(item) >= 0) - return; - _blurWidgetItems = _blurWidgetItems.concat([item]); - _blurRebuildTimer.restart(); - } - - function unregisterBlurWidget(item) { - const idx = _blurWidgetItems.indexOf(item); - if (idx < 0) - return; - const arr = _blurWidgetItems.slice(); - arr.splice(idx, 1); - _blurWidgetItems = arr; - _blurRebuildTimer.restart(); - } - - Timer { - id: _blurRebuildTimer - interval: 1 - onTriggered: barBlur.rebuild() - } - - Item { - id: barBlur - visible: false - - readonly property bool barHasTransparency: barWindow._backgroundAlpha > 0 && barWindow._backgroundAlpha < 1 - - function rebuild() { - teardown(); - if (!BlurService.enabled || !BlurService.available) - return; - - const widgets = barWindow._blurWidgetItems.filter(w => w && w.visible && w.width > 0 && w.height > 0); - const hasBar = barHasTransparency; - if (!hasBar && widgets.length === 0) - return; - - const cr = Theme.cornerRadius; - let qml = 'import QtQuick; import Quickshell; Region {'; - for (let i = 0; i < widgets.length; i++) { - qml += ` property Item w${i}; Region { item: w${i}; radius: ${cr} }`; - } - qml += '}'; - - try { - const region = Qt.createQmlObject(qml, barWindow, "BarBlurRegion"); - - if (hasBar) { - region.x = Qt.binding(() => topBarMouseArea.x + barUnitInset.x + topBarSlide.x); - region.y = Qt.binding(() => topBarMouseArea.y + barUnitInset.y + topBarSlide.y); - region.width = Qt.binding(() => barUnitInset.width); - region.height = Qt.binding(() => barUnitInset.height); - region.radius = Qt.binding(() => barBackground.rt); - } - - for (let i = 0; i < widgets.length; i++) { - region[`w${i}`] = widgets[i]; - } - - barWindow.BackgroundEffect.blurRegion = region; - barWindow.blurRegion = region; - } catch (e) { - console.warn("BarBlur: Failed to create blur region:", e); - } - } - - function teardown() { - if (!barWindow.blurRegion) - return; - try { - barWindow.BackgroundEffect.blurRegion = null; - } catch (e) {} - barWindow.blurRegion.destroy(); - barWindow.blurRegion = null; - } - - onBarHasTransparencyChanged: _blurRebuildTimer.restart() - - Connections { - target: BlurService - function onEnabledChanged() { - barBlur.rebuild(); - } - } - - Connections { - target: topBarSlide - function onXChanged() { - if (barWindow.blurRegion) - barWindow.blurRegion.changed(); - } - function onYChanged() { - if (barWindow.blurRegion) - barWindow.blurRegion.changed(); - } - } - - Component.onCompleted: rebuild() - Component.onDestruction: teardown() - } - - WlrLayershell.layer: dBarLayer - WlrLayershell.namespace: "dms:bar" - - signal colorPickerRequested - - onColorPickerRequested: rootWindow.colorPickerRequested() - - property alias axis: axis - - AxisContext { - id: axis - edge: { - switch (barConfig?.position ?? 0) { - case SettingsData.Position.Top: - return "top"; - case SettingsData.Position.Bottom: - return "bottom"; - case SettingsData.Position.Left: - return "left"; - case SettingsData.Position.Right: - return "right"; - default: - return "top"; - } - } - } - - readonly property bool isVertical: axis.isVertical - - property bool gothCornersEnabled: barConfig?.gothCornersEnabled ?? false - property real wingtipsRadius: barConfig?.gothCornerRadiusOverride ? (barConfig?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius - readonly property real _wingR: Math.max(0, wingtipsRadius) - readonly property color _surfaceContainer: Theme.surfaceContainer - readonly property string _barId: barConfig?.id ?? "default" - property real _backgroundAlpha: barConfig?.transparency ?? 1.0 - readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) - - function _updateBackgroundAlpha() { - const live = SettingsData.barConfigs.find(c => c.id === _barId); - _backgroundAlpha = (live ?? barConfig)?.transparency ?? 1.0; - } - readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen) - - // Shadow buffer: extra window space for shadow to render beyond bar bounds - readonly property bool _shadowActive: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || (barConfig?.shadowIntensity ?? 0) > 0 - readonly property real _shadowBuffer: { - if (!_shadowActive) - return 0; - const hasOverride = (barConfig?.shadowIntensity ?? 0) > 0; - if (hasOverride) { - const blur = (barConfig.shadowIntensity ?? 0) * 0.2; - const offset = blur * 0.5; - return Theme.snap(Math.max(16, blur + offset + 8), _dpr); - } - return Theme.snap(Theme.elevationRenderPadding(Theme.elevationLevel2, "top", 4, 8, 16), _dpr); - } - - property string screenName: modelData.name - - property bool hasMaximizedToplevel: false - property bool hasFullscreenToplevel: false - property bool shouldHideForWindows: false - - function _updateHasMaximizedToplevel() { - if (!(barConfig?.maximizeDetection ?? true)) { - hasMaximizedToplevel = false; - return; - } - if (!CompositorService.isHyprland && !CompositorService.isNiri) { - hasMaximizedToplevel = false; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - for (let i = 0; i < filtered.length; i++) { - if (filtered[i]?.maximized) { - hasMaximizedToplevel = true; - return; - } - } - hasMaximizedToplevel = false; - } - - function _updateHasFullscreenToplevel() { - if (!CompositorService.isHyprland) { - hasFullscreenToplevel = false; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - for (let i = 0; i < filtered.length; i++) { - if (filtered[i]?.fullscreen) { - // On niri, fullscreen windows in inactive columns should not hide the bar - if (CompositorService.isNiri && !filtered[i]?.activated) - continue; - hasFullscreenToplevel = true; - return; - } - } - hasFullscreenToplevel = false; - } - - function _updateShouldHideForWindows() { - if (!(barConfig?.showOnWindowsOpen ?? false)) { - shouldHideForWindows = false; - return; - } - if (!(barConfig?.autoHide ?? false)) { - shouldHideForWindows = false; - return; - } - if (!CompositorService.isNiri && !CompositorService.isHyprland) { - shouldHideForWindows = false; - return; - } - - if (CompositorService.isNiri) { - let currentWorkspaceId = null; - for (let i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.output === screenName && ws.is_active) { - currentWorkspaceId = ws.id; - break; - } - } - - if (currentWorkspaceId === null) { - shouldHideForWindows = false; - return; - } - - let hasTiled = false; - let hasFloatingTouchingBar = false; - const pos = barConfig?.position ?? 0; - const barThickness = barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4); - - for (let i = 0; i < NiriService.windows.length; i++) { - const win = NiriService.windows[i]; - if (win.workspace_id !== currentWorkspaceId) - continue; - - if (!win.is_floating) { - hasTiled = true; - continue; - } - - const tilePos = win.layout?.tile_pos_in_workspace_view; - const winSize = win.layout?.window_size || win.layout?.tile_size; - if (!tilePos || !winSize) - continue; - - switch (pos) { - case SettingsData.Position.Top: - if (tilePos[1] < barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Bottom: - const screenHeight = barWindow.screen?.height ?? 0; - if (tilePos[1] + winSize[1] > screenHeight - barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Left: - if (tilePos[0] < barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Right: - const screenWidth = barWindow.screen?.width ?? 0; - if (tilePos[0] + winSize[0] > screenWidth - barThickness) - hasFloatingTouchingBar = true; - break; - } - } - - shouldHideForWindows = hasTiled || hasFloatingTouchingBar; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - shouldHideForWindows = filtered.length > 0; - } - - property real effectiveSpacing: hasMaximizedToplevel ? 0 : (barConfig?.spacing ?? 4) - - Behavior on effectiveSpacing { - enabled: barWindow.visible - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - readonly property int notificationCount: NotificationService.notifications.length - readonly property real effectiveBarThickness: Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr) - readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr) - - readonly property bool hasAdjacentTopBar: { - if (barConfig?.autoHide ?? false) - return false; - if (!isVertical) - return false; - return SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Top && bc.position !== 0) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - } - - readonly property bool hasAdjacentBottomBar: { - if (barConfig?.autoHide ?? false) - return false; - if (!isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Bottom && bc.position !== 1) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - readonly property bool hasAdjacentLeftBar: { - if (barConfig?.autoHide ?? false) - return false; - if (isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Left && bc.position !== 2) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - readonly property bool hasAdjacentRightBar: { - if (barConfig?.autoHide ?? false) - return false; - if (isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Right && bc.position !== 3) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - screen: modelData - implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0 - implicitWidth: isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0 - color: "transparent" - - property var nativeInhibitor: null - - Component.onCompleted: { - if (SettingsData.forceStatusBarLayoutRefresh) { - SettingsData.forceStatusBarLayoutRefresh.connect(() => { - Qt.callLater(() => { - stackContainer.visible = false; - Qt.callLater(() => { - stackContainer.visible = true; - }); - }); - }); - } - - updateGpuTempConfig(); - _updateBackgroundAlpha(); - _updateHasMaximizedToplevel(); - _updateShouldHideForWindows(); - - inhibitorInitTimer.start(); - } - - Timer { - id: inhibitorInitTimer - interval: 300 - repeat: false - onTriggered: { - if (SessionService.nativeInhibitorAvailable) { - createNativeInhibitor(); - } - } - } - - Connections { - target: PluginService - function onPluginLoaded(pluginId) { - console.info("DankBar: Plugin loaded:", pluginId); - SettingsData.widgetDataChanged(); - } - function onPluginUnloaded(pluginId) { - console.info("DankBar: Plugin unloaded:", pluginId); - SettingsData.widgetDataChanged(); - } - } - - function updateGpuTempConfig() { - const leftWidgets = barConfig?.leftWidgets || []; - const centerWidgets = barConfig?.centerWidgets || []; - const rightWidgets = barConfig?.rightWidgets || []; - const allWidgets = [...leftWidgets, ...centerWidgets, ...rightWidgets]; - - const hasGpuTempWidget = allWidgets.some(widget => { - const widgetId = typeof widget === "string" ? widget : widget.id; - const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false); - return widgetId === "gpuTemp" && widgetEnabled; - }); - - DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled; - DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled; - DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled; - } - - function createNativeInhibitor() { - if (!SessionService.nativeInhibitorAvailable) { - return; - } - - try { - const qmlString = ` - import QtQuick - import Quickshell.Wayland - - IdleInhibitor { - enabled: false - } - `; - - nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor"); - nativeInhibitor.window = barWindow; - nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited); - nativeInhibitor.enabledChanged.connect(function () { - if (SessionService.idleInhibited !== nativeInhibitor.enabled) { - SessionService.idleInhibited = nativeInhibitor.enabled; - SessionService.inhibitorChanged(); - } - }); - } catch (e) { - nativeInhibitor = null; - } - } - - Connections { - function onBarConfigChanged() { - barWindow.updateGpuTempConfig(); - barWindow._updateBackgroundAlpha(); - barWindow._updateHasMaximizedToplevel(); - barWindow._updateShouldHideForWindows(); - } - - target: rootWindow - } - - Connections { - target: SettingsData - function onBarConfigsChanged() { - barWindow._updateBackgroundAlpha(); - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - barWindow._updateHasMaximizedToplevel(); - barWindow._updateHasFullscreenToplevel(); - barWindow._updateShouldHideForWindows(); - } - } - - Connections { - target: NiriService - function onAllWorkspacesChanged() { - barWindow._updateHasMaximizedToplevel(); - barWindow._updateHasFullscreenToplevel(); - barWindow._updateShouldHideForWindows(); - } - } - - Connections { - function onNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig(); - } - - function onNonNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig(); - } - - target: SessionData - } - - readonly property int barPos: barConfig?.position ?? 0 - - anchors.top: !isVertical ? (barPos === SettingsData.Position.Top) : true - anchors.bottom: !isVertical ? (barPos === SettingsData.Position.Bottom) : true - anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left) - anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right) - - exclusiveZone: (!(barConfig?.visible ?? true) || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (barConfig?.bottomGap ?? 0)) - - Item { - id: inputMask - - readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) - - readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) - readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow - readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) - - readonly property int maskThickness: showing ? barThickness : 1 - - x: { - if (!axis.isVertical) { - return 0; - } else { - switch (barPos) { - case SettingsData.Position.Left: - return 0; - case SettingsData.Position.Right: - return parent.width - maskThickness; - default: - return 0; - } - } - } - y: { - if (axis.isVertical) { - return 0; - } else { - switch (barPos) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return parent.height - maskThickness; - default: - return 0; - } - } - } - width: axis.isVertical ? maskThickness : parent.width - height: axis.isVertical ? parent.height : maskThickness - } - - readonly property bool clickThroughEnabled: barConfig?.clickThrough ?? false - - readonly property var _leftSection: topBarContent ? (barWindow.isVertical ? topBarContent.vLeftSection : topBarContent.hLeftSection) : null - readonly property var _centerSection: topBarContent ? (barWindow.isVertical ? topBarContent.vCenterSection : topBarContent.hCenterSection) : null - readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null - readonly property real _revealProgress: topBarSlide.x + topBarSlide.y - - function sectionRect(section, isCenter, _dep) { - if (!section) - return { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - }; - - const pos = section.mapToItem(barWindow.contentItem, 0, 0); - const implW = section.implicitWidth || 0; - const implH = section.implicitHeight || 0; - - const offsetX = isCenter && !barWindow.isVertical ? (section.width - implW) / 2 : 0; - const offsetY = !barWindow.isVertical ? (section.height - implH) / 2 : (isCenter ? (section.height - implH) / 2 : 0); - - const edgePad = 2; - return { - "x": pos.x + offsetX - edgePad, - "y": pos.y + offsetY - edgePad, - "w": implW + edgePad * 2, - "h": implH + edgePad * 2 - }; - } - - mask: Region { - item: clickThroughEnabled ? null : inputMask - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._leftSection, false, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._centerSection, true, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._rightSection, false, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property bool active: barWindow.clickThroughEnabled && !inputMask.showing - x: active ? inputMask.x : 0 - y: active ? inputMask.y : 0 - width: active ? inputMask.width : 0 - height: active ? inputMask.height : 0 - } - } - - Item { - id: topBarCore - anchors.fill: parent - layer.enabled: false - - property bool autoHide: barConfig?.autoHide ?? false - property bool revealSticky: false - - Timer { - id: revealHold - interval: barWindow.clickThroughEnabled ? Math.max((barConfig?.autoHideDelay ?? 250) * 6, 1500) : (barConfig?.autoHideDelay ?? 250) - repeat: false - onTriggered: { - if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) { - topBarCore.revealSticky = false; - } - } - } - - property bool reveal: { - const inOverviewWithShow = CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false); - if (inOverviewWithShow) - return true; - - if (barWindow.hasFullscreenToplevel) - return false; - - const showOnWindowsSetting = barConfig?.showOnWindowsOpen ?? false; - if (showOnWindowsSetting && autoHide && (CompositorService.isNiri || CompositorService.isHyprland)) { - if (barWindow.shouldHideForWindows) - return topBarMouseArea.containsMouse || hasActivePopout || revealSticky; - return true; - } - - if (CompositorService.isNiri && NiriService.inOverview) - return topBarMouseArea.containsMouse || hasActivePopout || revealSticky; - - return (barConfig?.visible ?? true) && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky); - } - - property bool hasActivePopout: false - - onHasActivePopoutChanged: evaluateReveal() - - function updateActivePopoutState() { - if (!barWindow.screen) - return; - const screenName = barWindow.screen.name; - const activePopout = PopoutManager.currentPopoutsByScreen[screenName]; - const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName]; - const trayOpen = rootWindow.systemTrayMenuOpen; - - const hasVisiblePopout = activePopout && activePopout.shouldBeVisible; - topBarCore.hasActivePopout = !!(hasVisiblePopout || activeTrayMenu || trayOpen); - } - - Connections { - target: PopoutManager - function onPopoutChanged() { - topBarCore.updateActivePopoutState(); - } - } - - Connections { - target: TrayMenuManager - function onActiveTrayMenusChanged() { - topBarCore.updateActivePopoutState(); - } - } - - Connections { - function onBarConfigChanged() { - topBarCore.autoHide = barConfig?.autoHide ?? false; - } - - target: rootWindow - } - - function evaluateReveal() { - if (!autoHide) - return; - - if (topBarMouseArea.containsMouse || hasActivePopout) { - revealSticky = true; - revealHold.stop(); - return; - } - - revealHold.restart(); - } - - Connections { - target: topBarMouseArea - function onContainsMouseChanged() { - topBarCore.evaluateReveal(); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - topBarCore.evaluateReveal(); - } - } - - MouseArea { - id: topBarMouseArea - y: !barWindow.isVertical ? (barPos === SettingsData.Position.Bottom ? parent.height - height : 0) : 0 - x: barWindow.isVertical ? (barPos === SettingsData.Position.Right ? parent.width - width : 0) : 0 - height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) : undefined - width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) : undefined - anchors { - left: !barWindow.isVertical ? parent.left : (barPos === SettingsData.Position.Left ? parent.left : undefined) - right: !barWindow.isVertical ? parent.right : (barPos === SettingsData.Position.Right ? parent.right : undefined) - top: barWindow.isVertical ? parent.top : undefined - bottom: barWindow.isVertical ? parent.bottom : undefined - } - readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) - hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout - acceptedButtons: Qt.NoButton - enabled: (barConfig?.autoHide ?? false) && !inOverview - - Item { - id: topBarContainer - anchors.fill: parent - - transform: Translate { - id: topBarSlide - x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0 - y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0 - - Behavior on x { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on y { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - - Item { - id: barUnitInset - property int spacingPx: Theme.px(barWindow.effectiveSpacing, barWindow._dpr) - anchors.fill: parent - anchors.leftMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "left" ? spacingPx : 0) - anchors.rightMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "right" ? spacingPx : 0) - anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx) - anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0) - - BarCanvas { - id: barBackground - barWindow: barWindow - axis: axis - barConfig: barWindow.barConfig - } - - MouseArea { - id: scrollArea - anchors.fill: parent - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - z: -1 - - property real touchpadAccumulatorY: 0 - property real touchpadAccumulatorX: 0 - property real mouseAccumulatorY: 0 - property real mouseAccumulatorX: 0 - property bool actionInProgress: false - - Timer { - id: cooldownTimer - interval: 100 - onTriggered: parent.actionInProgress = false - } - - function handleScrollAction(behavior, direction) { - switch (behavior) { - case "workspace": - topBarContent.switchWorkspace(direction); - return true; - case "column": - if (!CompositorService.isNiri) - return false; - if (direction > 0) - NiriService.moveColumnRight(); - else - NiriService.moveColumnLeft(); - return true; - default: - return false; - } - } - - onWheel: wheel => { - if (!(barConfig?.scrollEnabled ?? true) || actionInProgress) { - wheel.accepted = false; - return; - } - - const deltaY = wheel.angleDelta.y; - const deltaX = wheel.angleDelta.x; - const isTouchpadY = wheel.pixelDelta && wheel.pixelDelta.y !== 0; - const isTouchpadX = wheel.pixelDelta && wheel.pixelDelta.x !== 0; - const xBehavior = barConfig?.scrollXBehavior ?? "column"; - const yBehavior = barConfig?.scrollYBehavior ?? "workspace"; - const reverse = SettingsData.reverseScrolling ? -1 : 1; - - if (CompositorService.isNiri && xBehavior !== "none" && Math.abs(deltaX) > Math.abs(deltaY)) { - if (isTouchpadX) { - touchpadAccumulatorX += deltaX; - if (Math.abs(touchpadAccumulatorX) >= 500) { - const direction = touchpadAccumulatorX * reverse < 0 ? 1 : -1; - if (handleScrollAction(xBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - touchpadAccumulatorX = 0; - } - } else { - mouseAccumulatorX += deltaX; - if (Math.abs(mouseAccumulatorX) >= 120) { - const direction = mouseAccumulatorX * reverse < 0 ? 1 : -1; - if (handleScrollAction(xBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - mouseAccumulatorX = 0; - } - } - wheel.accepted = false; - return; - } - - if (yBehavior === "none") { - wheel.accepted = false; - return; - } - - if (isTouchpadY) { - touchpadAccumulatorY += deltaY; - if (Math.abs(touchpadAccumulatorY) >= 500) { - const direction = touchpadAccumulatorY * reverse < 0 ? 1 : -1; - if (handleScrollAction(yBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - touchpadAccumulatorY = 0; - } - } else { - mouseAccumulatorY += deltaY; - if (Math.abs(mouseAccumulatorY) >= 120) { - const direction = mouseAccumulatorY * reverse < 0 ? 1 : -1; - if (handleScrollAction(yBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - mouseAccumulatorY = 0; - } - } - - wheel.accepted = false; - } - } - - DankBarContent { - id: topBarContent - barWindow: barWindow - rootWindow: barWindow.rootWindow - barConfig: barWindow.barConfig - leftWidgetsModel: barWindow.leftWidgetsModel - centerWidgetsModel: barWindow.centerWidgetsModel - rightWidgetsModel: barWindow.rightWidgetsModel - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml deleted file mode 100644 index d7219db..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml +++ /dev/null @@ -1,119 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - - Loader { - id: layoutLoader - anchors.fill: parent - sourceComponent: root.isVertical ? columnComp : rowComp - } - - Component { - id: rowComp - Row { - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: rowRepeater - model: root.widgetsModel - Item { - readonly property real rowSpacing: parent.widgetSpacing - property var itemData: modelData - width: widgetLoader.item ? widgetLoader.item.width : 0 - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.verticalCenter: parent.verticalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: false - axis: root.axis - section: "left" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === rowRepeater.count - 1 - sectionSpacing: parent.rowSpacing - isLeftBarEdge: true - isRightBarEdge: false - } - } - } - } - } - - Component { - id: columnComp - Column { - width: parent.width - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: columnRepeater - model: root.widgetsModel - Item { - width: parent.width - readonly property real columnSpacing: parent.widgetSpacing - property var itemData: modelData - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.horizontalCenter: parent.horizontalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: true - axis: root.axis - section: "left" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === columnRepeater.count - 1 - sectionSpacing: parent.columnSpacing - isTopBarEdge: true - isBottomBarEdge: false - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml deleted file mode 100644 index f0cb9d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml +++ /dev/null @@ -1,633 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.UPower -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:battery" - - property var triggerScreen: null - - function isActiveProfile(profile) { - if (typeof PowerProfiles === "undefined") { - return false; - } - - return PowerProfiles.profile === profile; - } - - function setProfile(profile) { - if (typeof PowerProfiles === "undefined") { - ToastService.showError(I18n.tr("power-profiles-daemon not available")); - return; - } - PowerProfiles.profile = profile; - if (PowerProfiles.profile !== profile) { - ToastService.showError(I18n.tr("Failed to set power profile")); - } - } - - popupWidth: 400 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 0 - triggerWidth: 70 - positioning: "" - screen: triggerScreen - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: batteryContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - color: "transparent" - focus: true - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Connections { - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(function () { - batteryContent.forceActiveFocus(); - }); - } - } - - target: root - } - - Column { - id: contentColumn - - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - height: 48 - spacing: Theme.spacingM - - DankIcon { - name: { - if (!BatteryService.batteryAvailable) - return "power"; - - if (!BatteryService.isCharging && BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } else { - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - return "battery_1_bar"; - } - } - size: Theme.iconSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - Column { - id: headerInfoColumn - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - 32 - Theme.spacingM * 2 - readonly property string timeInfoText: { - if (!BatteryService.batteryAvailable) - return I18n.tr("Power profile management available"); - const time = BatteryService.formatTimeRemaining(); - if (time !== "Unknown") { - return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(time) : I18n.tr("Time remaining: %1").arg(time); - } - return ""; - } - readonly property bool showPowerRate: BatteryService.batteryAvailable && Math.abs(BatteryService.changeRate) > 0.05 - readonly property bool isOnAC: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - readonly property bool isDischarging: BatteryService.batteryAvailable && !BatteryService.isCharging && !BatteryService.isPluggedIn - - Row { - spacing: Theme.spacingS - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : I18n.tr("Power") - font.pixelSize: Theme.fontSizeXLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Bold - } - - StyledText { - text: BatteryService.batteryStatus - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: headerInfoColumn.timeInfoText.length > 0 - - StyledText { - id: powerRateText - text: `${headerInfoColumn.isOnAC ? "+" : (headerInfoColumn.isDischarging ? "-" : "")}${Math.abs(BatteryService.changeRate).toFixed(1)}W` - font.pixelSize: Theme.fontSizeSmall - color: { - if (headerInfoColumn.isOnAC) { - return Theme.primary; - } - if (headerInfoColumn.isDischarging) { - return Theme.warning; - } - return Theme.surfaceTextMedium; - } - font.weight: Font.Medium - visible: headerInfoColumn.showPowerRate - } - - StyledText { - text: headerInfoColumn.timeInfoText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideRight - width: parent.width - (powerRateText.visible ? (powerRateText.implicitWidth + parent.spacing) : 0) - } - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: closeBatteryArea.containsMouse ? Theme.errorHover : "transparent" - anchors.top: parent.top - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeBatteryArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeBatteryArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.close(); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: BatteryService.batteryAvailable - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryHealth - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.batteryHealth === "N/A") { - return Theme.surfaceText; - } - const healthNum = parseInt(BatteryService.batteryHealth); - return healthNum < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryCapacity > 0 ? `${BatteryService.batteryCapacity.toFixed(1)} Wh` : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - // Individual battery details for multiple batteries - Column { - width: parent.width - spacing: Theme.spacingS - visible: !BatteryService.usePreferred && BatteryService.batteries.length > 1 - - StyledText { - text: I18n.tr("Individual Batteries") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Repeater { - model: ScriptModel { - values: BatteryService.batteries - } - - delegate: StyledRect { - required property var modelData - required property int index - - width: parent.width - height: batteryColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.width: 0 - - Column { - id: batteryColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - // Top row: name and percentage - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - percentText.width - chargingIcon.width - Theme.spacingM * 2 - - StyledText { - text: modelData.model || I18n.tr("Battery %1").arg(index + 1) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.nativePath - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideMiddle - width: parent.width - } - } - - Item { - width: 1 - height: parent.height - } - - StyledText { - id: percentText - text: `${Math.round(100 * modelData.percentage)}%` - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Bold - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: chargingIcon - name: modelData.state === UPowerDeviceState.Charging ? "bolt" : "" - size: Theme.iconSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: modelData.state === UPowerDeviceState.Charging - } - } - - // Bottom row: Health, Capacity and Time - Flow { - width: parent.width - spacing: Theme.spacingS - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!modelData.healthSupported || modelData.healthPercentage <= 0) - return "N/A"; - return `${Math.round(modelData.healthPercentage)}%`; - } - font.pixelSize: Theme.fontSizeSmall - color: { - if (!modelData.healthSupported || modelData.healthPercentage <= 0) - return Theme.surfaceText; - return modelData.healthPercentage < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: modelData.energyCapacity > 0 ? `${modelData.energyCapacity.toFixed(1)}` : "N/A" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: modelData.state === UPowerDeviceState.Charging ? I18n.tr("To Full") : modelData.state === UPowerDeviceState.Discharging ? I18n.tr("Left") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const time = modelData.state === UPowerDeviceState.Charging ? modelData.timeToFull : modelData.state === UPowerDeviceState.Discharging && BatteryService.changeRate > 0 ? (3600 * modelData.energy) / BatteryService.changeRate : 0; - - if (!time || time <= 0 || time > 86400) - return "N/A"; - - const hours = Math.floor(time / 3600); - const minutes = Math.floor((time % 3600) / 60); - return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } - } - - Item { - width: parent.width - height: profileButtonGroup.height * profileButtonGroup.scale - - DankButtonGroup { - id: profileButtonGroup - - property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] - property int currentProfileIndex: { - if (typeof PowerProfiles === "undefined") - return 1; - return profileModel.findIndex(profile => root.isActiveProfile(profile)); - } - - scale: Math.min(1, parent.width / implicitWidth) - transformOrigin: Item.Center - anchors.horizontalCenter: parent.horizontalCenter - model: profileModel.map(profile => Theme.getPowerProfileLabel(profile)) - currentIndex: currentProfileIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - root.setProfile(profileModel[index]); - } - } - } - - StyledRect { - width: parent.width - height: degradationContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3) - border.width: 0 - visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None - - Column { - id: degradationContent - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Power Profile Degradation") - font.pixelSize: Theme.fontSizeLarge - color: Theme.error - font.weight: Font.Medium - } - - StyledText { - text: (typeof PowerProfiles !== "undefined") ? PerformanceDegradationReason.toString(PowerProfiles.degradationReason) : "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8) - wrapMode: Text.WordWrap - width: parent.width - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml deleted file mode 100644 index 9daed8d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml +++ /dev/null @@ -1,302 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:layout" - - property var triggerScreen: null - - function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) { - triggerX = x; - triggerY = y; - triggerWidth = width; - triggerSection = section; - triggerScreen = screen; - root.screen = screen; - - storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4); - storedBarSpacing = barSpacing !== undefined ? barSpacing : 4; - storedBarConfig = barConfig; - - const pos = barPosition !== undefined ? barPosition : 0; - const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0; - - setBarContext(pos, bottomGap); - - updateOutputState(); - } - - onScreenChanged: updateOutputState() - - function updateOutputState() { - if (screen && DwlService.dwlAvailable) { - outputState = DwlService.getOutputState(screen.name); - } else { - outputState = null; - } - } - - property var outputState: null - property string currentLayoutSymbol: outputState?.layoutSymbol || "" - - readonly property var layoutNames: ({ - "CT": I18n.tr("Center Tiling"), - "G": I18n.tr("Grid"), - "K": I18n.tr("Deck"), - "M": I18n.tr("Monocle"), - "RT": I18n.tr("Right Tiling"), - "S": I18n.tr("Scrolling"), - "T": I18n.tr("Tiling"), - "VG": I18n.tr("Vertical Grid"), - "VK": I18n.tr("Vertical Deck"), - "VS": I18n.tr("Vertical Scrolling"), - "VT": I18n.tr("Vertical Tiling") - }) - - readonly property var layoutIcons: ({ - "CT": "view_compact", - "G": "grid_view", - "K": "layers", - "M": "fullscreen", - "RT": "view_sidebar", - "S": "view_carousel", - "T": "view_quilt", - "VG": "grid_on", - "VK": "view_day", - "VS": "scrollable_header", - "VT": "clarify" - }) - - function getLayoutName(symbol) { - return layoutNames[symbol] || symbol; - } - - function getLayoutIcon(symbol) { - return layoutIcons[symbol] || "view_quilt"; - } - - Connections { - target: DwlService - function onStateChanged() { - updateOutputState(); - } - } - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - updateOutputState(); - } - } - - Component.onCompleted: { - updateOutputState(); - } - - popupWidth: 300 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 550 - triggerWidth: 70 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: layoutContent - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => { - layoutContent.forceActiveFocus(); - }); - } - } - } - - Column { - id: contentColumn - - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - height: 40 - spacing: Theme.spacingM - - DankIcon { - name: "view_quilt" - size: Theme.iconSizeLarge - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - 32 - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Layout") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Bold - } - - StyledText { - text: root.currentLayoutSymbol - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: closeLayoutArea.containsMouse ? Theme.errorHover : "transparent" - anchors.top: parent.top - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeLayoutArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeLayoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.close(); - } - } - } - } - - StyledText { - text: I18n.tr("Available Layouts") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: DwlService.layouts - - delegate: Rectangle { - required property string modelData - required property int index - - property bool isActive: modelData === root.currentLayoutSymbol - - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: layoutArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: root.getLayoutIcon(modelData) - size: 20 - color: parent.parent.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: root.getLayoutName(modelData) - font.pixelSize: Theme.fontSizeSmall - color: parent.parent.parent.isActive ? Theme.primary : Theme.surfaceText - font.weight: parent.parent.parent.isActive ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - MouseArea { - id: layoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - if (!root.triggerScreen) { - return; - } - if (!DwlService.dwlAvailable) { - return; - } - - DwlService.setLayout(root.triggerScreen.name, index); - root.close(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - - StyledText { - text: I18n.tr("Right-click bar widget to cycle") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml deleted file mode 100644 index 064f578..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:vpn" - - Ref { - service: DMSNetworkService - } - - property bool wasVisible: false - property var triggerScreen: null - - popupWidth: 380 - popupHeight: Math.min((screen ? screen.height : Screen.height) - 100, contentLoader.item ? contentLoader.item.implicitHeight : 320) - triggerWidth: 70 - screen: triggerScreen - shouldBeVisible: false - - onShouldBeVisibleChanged: { - if (shouldBeVisible && !wasVisible) { - DMSNetworkService.getState(); - } - wasVisible = shouldBeVisible; - } - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: content - - implicitHeight: contentColumn.height + Theme.spacingL * 2 - color: "transparent" - focus: true - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Column { - id: contentColumn - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - height: 32 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("VPN Connections") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - Layout.fillWidth: true - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.close() - } - } - - VpnDetailContent { - width: parent.width - listHeight: 200 - parentPopout: root - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml deleted file mode 100644 index 58844bc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml +++ /dev/null @@ -1,121 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - - Loader { - id: layoutLoader - width: parent.width - height: parent.height - sourceComponent: root.isVertical ? columnComp : rowComp - } - - Component { - id: rowComp - Row { - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - anchors.right: parent ? parent.right : undefined - Repeater { - id: rowRepeater - model: root.widgetsModel - Item { - readonly property real rowSpacing: parent.widgetSpacing - property var itemData: modelData - width: widgetLoader.item ? widgetLoader.item.width : 0 - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.verticalCenter: parent.verticalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: false - axis: root.axis - section: "right" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === rowRepeater.count - 1 - sectionSpacing: parent.rowSpacing - isLeftBarEdge: false - isRightBarEdge: true - } - } - } - } - } - - Component { - id: columnComp - Column { - width: parent.width - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: columnRepeater - model: root.widgetsModel - Item { - width: parent.width - readonly property real columnSpacing: parent.widgetSpacing - property var itemData: modelData - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.horizontalCenter: parent.horizontalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: true - axis: root.axis - section: "right" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === columnRepeater.count - 1 - sectionSpacing: parent.columnSpacing - isTopBarEdge: false - isBottomBarEdge: true - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml deleted file mode 100644 index 01d1c73..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml +++ /dev/null @@ -1,290 +0,0 @@ -import QtQuick -import qs.Services - -Loader { - id: root - - property string widgetId: "" - property var widgetData: null - property int spacerSize: 20 - property var components: null - property bool isInColumn: false - property var axis: null - property string section: "center" - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool isFirst: false - property bool isLast: false - property real sectionSpacing: 0 - property bool isLeftBarEdge: false - property bool isRightBarEdge: false - property bool isTopBarEdge: false - property bool isBottomBarEdge: false - property string _registeredScreenName: "" - - asynchronous: false - - readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn - - readonly property bool widgetEnabled: widgetData?.enabled !== false - - active: orientationMatches && getWidgetVisible(widgetId, DgopService.dgopAvailable) && (widgetId !== "music" || MprisController.activePlayer !== null) - sourceComponent: getWidgetComponent(widgetId, components) - - signal contentItemReady(var item) - - Binding { - target: root.item - when: root.item && !root.widgetEnabled - property: "visible" - value: false - restoreMode: Binding.RestoreBinding - } - - Binding { - target: root.item - when: root.item && "parentScreen" in root.item - property: "parentScreen" - value: root.parentScreen - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "section" in root.item - property: "section" - value: root.section - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "widgetThickness" in root.item - property: "widgetThickness" - value: root.widgetThickness - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barThickness" in root.item - property: "barThickness" - value: root.barThickness - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barSpacing" in root.item - property: "barSpacing" - value: root.barSpacing - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barConfig" in root.item - property: "barConfig" - value: root.barConfig - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "blurBarWindow" in root.item - property: "blurBarWindow" - value: root.blurBarWindow - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "axis" in root.item - property: "axis" - value: root.axis - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "widgetData" in root.item - property: "widgetData" - value: root.widgetData - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isFirst" in root.item - property: "isFirst" - value: root.isFirst - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isLast" in root.item - property: "isLast" - value: root.isLast - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "sectionSpacing" in root.item - property: "sectionSpacing" - value: root.sectionSpacing - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isLeftBarEdge" in root.item - property: "isLeftBarEdge" - value: root.isLeftBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isRightBarEdge" in root.item - property: "isRightBarEdge" - value: root.isRightBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isTopBarEdge" in root.item - property: "isTopBarEdge" - value: root.isTopBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isBottomBarEdge" in root.item - property: "isBottomBarEdge" - value: root.isBottomBarEdge - restoreMode: Binding.RestoreNone - } - - onLoaded: { - if (!item) - return; - - contentItemReady(item); - - if (axis && "isVertical" in item) { - try { - item.isVertical = axis.isVertical; - } catch (e) {} - } - - if (item.pluginService !== undefined) { - var parts = widgetId.split(":"); - var pluginId = parts[0]; - var variantId = parts.length > 1 ? parts[1] : null; - - if (item.pluginId !== undefined) - item.pluginId = pluginId; - if (item.variantId !== undefined) - item.variantId = variantId; - if (item.variantData !== undefined && variantId) - item.variantData = PluginService.getPluginVariantData(pluginId, variantId); - item.pluginService = PluginService; - } - - if (item.popoutService !== undefined) - item.popoutService = PopoutService; - - registerWidgetIfEligible(); - } - - Component.onDestruction: { - unregisterWidget(); - } - - function registerWidgetIfEligible() { - if (!item || !widgetId || !parentScreen?.name) - return; - - const hasPopout = item.popoutTarget !== undefined || typeof item.triggerPopout === "function" || typeof item.clicked === "function"; - if (!hasPopout) - return; - - _registeredScreenName = parentScreen.name; - BarWidgetService.registerWidget(widgetId, _registeredScreenName, item); - } - - function unregisterWidget() { - if (!widgetId || !_registeredScreenName) - return; - - BarWidgetService.unregisterWidget(widgetId, _registeredScreenName); - _registeredScreenName = ""; - } - - function getWidgetComponent(widgetId, components) { - const componentMap = { - "launcherButton": components.launcherButtonComponent, - "workspaceSwitcher": components.workspaceSwitcherComponent, - "focusedWindow": components.focusedWindowComponent, - "runningApps": components.runningAppsComponent, - "clock": components.clockComponent, - "music": components.mediaComponent, - "weather": components.weatherComponent, - "systemTray": components.systemTrayComponent, - "privacyIndicator": components.privacyIndicatorComponent, - "clipboard": components.clipboardComponent, - "cpuUsage": components.cpuUsageComponent, - "memUsage": components.memUsageComponent, - "diskUsage": components.diskUsageComponent, - "cpuTemp": components.cpuTempComponent, - "gpuTemp": components.gpuTempComponent, - "notificationButton": components.notificationButtonComponent, - "battery": components.batteryComponent, - "controlCenterButton": components.controlCenterButtonComponent, - "capsLockIndicator": components.capsLockIndicatorComponent, - "idleInhibitor": components.idleInhibitorComponent, - "spacer": components.spacerComponent, - "separator": components.separatorComponent, - "network_speed_monitor": components.networkComponent, - "keyboard_layout_name": components.keyboardLayoutNameComponent, - "vpn": components.vpnComponent, - "notepadButton": components.notepadButtonComponent, - "colorPicker": components.colorPickerComponent, - "systemUpdate": components.systemUpdateComponent, - "layout": components.layoutComponent, - "powerMenuButton": components.powerMenuButtonComponent, - "appsDock": components.appsDockComponent - }; - - if (componentMap[widgetId]) { - return componentMap[widgetId]; - } - - var parts = widgetId.split(":"); - var pluginId = parts[0]; - - let pluginMap = PluginService.getWidgetComponents(); - return pluginMap[pluginId] || null; - } - - function getWidgetVisible(widgetId, dgopAvailable) { - const widgetVisibility = { - "cpuUsage": dgopAvailable, - "memUsage": dgopAvailable, - "cpuTemp": dgopAvailable, - "gpuTemp": dgopAvailable, - "network_speed_monitor": dgopAvailable, - "layout": CompositorService.isDwl && DwlService.dwlAvailable - }; - - return widgetVisibility[widgetId] ?? true; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml deleted file mode 100644 index 294102d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml +++ /dev/null @@ -1,1011 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - section: "left" - - property var widgetData: null - property var hoveredItem: null - property var topBar: null - property bool isAutoHideBar: false - property Item windowRoot: (Window.window ? Window.window.contentItem : null) - - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - property int pinnedAppCount: 0 - - property int maxVisibleApps: widgetData?.barMaxVisibleApps !== undefined ? widgetData.barMaxVisibleApps : SettingsData.barMaxVisibleApps - property int maxVisibleRunningApps: widgetData?.barMaxVisibleRunningApps !== undefined ? widgetData.barMaxVisibleRunningApps : SettingsData.barMaxVisibleRunningApps - property bool showOverflowBadge: widgetData?.barShowOverflowBadge !== undefined ? widgetData.barShowOverflowBadge : SettingsData.barShowOverflowBadge - property bool overflowExpanded: false - property int overflowItemCount: 0 - - onMaxVisibleAppsChanged: updateModel() - onMaxVisibleRunningAppsChanged: updateModel() - - readonly property real effectiveBarThickness: { - if (barThickness > 0 && barSpacing > 0) { - return barThickness + barSpacing; - } - const innerPadding = barConfig?.innerPadding ?? 4; - const spacing = barConfig?.spacing ?? 4; - return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing; - } - - readonly property var barBounds: { - if (!parentScreen || !barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig); - } - - readonly property real barY: barBounds.y - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return effectiveBarThickness; - } - - return 0; - } - - // --- Dock Logic Helpers --- - function movePinnedApp(fromDockIndex, toDockIndex) { - if (fromDockIndex === toDockIndex) - return; - - const currentPinned = [...(SessionData.barPinnedApps || [])]; - if (fromDockIndex < 0 || fromDockIndex >= currentPinned.length || toDockIndex < 0 || toDockIndex >= currentPinned.length) { - return; - } - - const movedApp = currentPinned.splice(fromDockIndex, 1)[0]; - currentPinned.splice(toDockIndex, 0, movedApp); - - SessionData.setBarPinnedApps(currentPinned); - } - - property int _desktopEntriesUpdateTrigger: 0 - property int _toplevelsUpdateTrigger: 0 - property int _appIdSubstitutionsTrigger: 0 - - Connections { - target: CompositorService - function onToplevelsChanged() { - _toplevelsUpdateTrigger++; - updateModel(); - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - _appIdSubstitutionsTrigger++; - updateModel(); - } - function onRunningAppsCurrentWorkspaceChanged() { - updateModel(); - } - function onBarMaxVisibleAppsChanged() { - updateModel(); - } - function onBarMaxVisibleRunningAppsChanged() { - updateModel(); - } - } - - Connections { - target: SessionData - function onBarPinnedAppsChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - } - - property var dockItems: [] - - function isOnScreen(toplevel, screenName) { - if (!toplevel.screens) - return false; - for (let i = 0; i < toplevel.screens.length; i++) { - if (toplevel.screens[i]?.name === screenName) - return true; - } - return false; - } - - function getCoreAppData(appId) { - if (typeof AppSearchService === "undefined") - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].builtInPluginId === appId) - return coreApps[i]; - } - return null; - } - - function getCoreAppDataByTitle(windowTitle) { - if (typeof AppSearchService === "undefined" || !windowTitle) - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].name === windowTitle) - return coreApps[i]; - } - return null; - } - - function createSeparator(key) { - return { - uniqueKey: key, - type: "separator", - appId: "__SEPARATOR__", - toplevel: null, - isPinned: false, - isRunning: false, - isInOverflow: false - }; - } - - function markAsOverflow(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: true - }; - } - - function markAsVisible(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: false - }; - } - - function buildBaseItems() { - const items = []; - const pinnedApps = [...(SessionData.barPinnedApps || [])]; - _toplevelsUpdateTrigger; - const allToplevels = CompositorService.sortedToplevels; - - let sortedToplevels = allToplevels; - if (SettingsData.runningAppsCurrentWorkspace && parentScreen) { - sortedToplevels = CompositorService.filterCurrentWorkspace(allToplevels, parentScreen.name) || []; - } - - const appGroups = new Map(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - appGroups.set(appId, { - appId: appId, - isPinned: true, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - }); - - sortedToplevels.forEach((toplevel, index) => { - const rawAppId = toplevel.appId || "unknown"; - let appId = Paths.moddedAppId(rawAppId); - - let coreAppData = null; - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) { - appId = coreAppData.builtInPluginId; - } - } - - if (!appGroups.has(appId)) { - appGroups.set(appId, { - appId: appId, - isPinned: false, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - } - - appGroups.get(appId).windows.push({ - toplevel: toplevel, - index: index, - windowTitle: toplevel.title - }); - }); - - const pinnedGroups = []; - const unpinnedGroups = []; - - Array.from(appGroups.entries()).forEach(([appId, group]) => { - const firstWindow = group.windows.length > 0 ? group.windows[0] : null; - - const item = { - uniqueKey: "grouped_" + appId, - type: "grouped", - appId: appId, - toplevel: firstWindow ? firstWindow.toplevel : null, - isPinned: group.isPinned, - isRunning: group.windows.length > 0, - windowCount: group.windows.length, - allWindows: group.windows, - isCoreApp: group.isCoreApp || false, - coreAppData: group.coreAppData || null, - isInOverflow: false - }; - - if (group.isPinned) { - pinnedGroups.push(item); - } else { - unpinnedGroups.push(item); - } - }); - - pinnedGroups.forEach(item => items.push(item)); - - if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) { - items.push(createSeparator("separator_grouped")); - } - - unpinnedGroups.forEach(item => items.push(item)); - - root.pinnedAppCount = pinnedGroups.length; - return { - items, - pinnedCount: pinnedGroups.length, - runningCount: unpinnedGroups.length - }; - } - - function applyOverflow(baseResult) { - const { - items - } = baseResult; - const maxPinned = root.maxVisibleApps; - const maxRunning = root.maxVisibleRunningApps; - - const pinnedItems = items.filter(i => i.type === "grouped" && i.isPinned); - const runningItems = items.filter(i => i.type === "grouped" && i.isRunning && !i.isPinned); - - const pinnedOverflow = maxPinned > 0 && pinnedItems.length > maxPinned; - const runningOverflow = maxRunning > 0 && runningItems.length > maxRunning; - - if (!pinnedOverflow && !runningOverflow) { - root.overflowItemCount = 0; - return items.map(i => markAsVisible(i)); - } - - const visiblePinnedKeys = new Set(pinnedOverflow ? pinnedItems.slice(0, maxPinned).map(i => i.uniqueKey) : pinnedItems.map(i => i.uniqueKey)); - const visibleRunningKeys = new Set(runningOverflow ? runningItems.slice(0, maxRunning).map(i => i.uniqueKey) : runningItems.map(i => i.uniqueKey)); - - const overflowPinnedCount = pinnedOverflow ? pinnedItems.length - maxPinned : 0; - const overflowRunningCount = runningOverflow ? runningItems.length - maxRunning : 0; - const totalOverflow = overflowPinnedCount + overflowRunningCount; - root.overflowItemCount = totalOverflow; - - const finalItems = []; - let addedSeparator = false; - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - switch (item.type) { - case "separator": - break; - case "grouped": - if (item.isPinned) { - if (visiblePinnedKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } else if (item.isRunning) { - if (!addedSeparator && finalItems.length > 0) { - finalItems.push(createSeparator("separator_overflow")); - addedSeparator = true; - } - if (visibleRunningKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } - break; - default: - finalItems.push(item); - break; - } - } - - if (totalOverflow > 0) { - const toggleIndex = finalItems.findIndex(i => i.type === "separator"); - const insertPos = toggleIndex >= 0 ? toggleIndex : finalItems.length; - finalItems.splice(insertPos, 0, { - uniqueKey: "overflow_toggle", - type: "overflow-toggle", - appId: "__OVERFLOW_TOGGLE__", - toplevel: null, - isPinned: false, - isRunning: false, - isInOverflow: false, - overflowCount: totalOverflow - }); - } - - return finalItems; - } - - function updateModel() { - const baseResult = buildBaseItems(); - dockItems = applyOverflow(baseResult); - } - - Component.onCompleted: updateModel() - - visible: dockItems.length > 0 - readonly property real iconCellSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout - } - } - } - - Component { - id: rowLayout - Row { - spacing: Theme.spacingXS - - Repeater { - id: repeater - model: ScriptModel { - values: root.dockItems - objectProp: "uniqueKey" - } - - delegate: dockDelegate - } - } - } - - Component { - id: columnLayout - Column { - spacing: Theme.spacingXS - - Repeater { - model: ScriptModel { - values: root.dockItems - objectProp: "uniqueKey" - } - delegate: dockDelegate - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - Component { - id: dockDelegate - Item { - id: delegateItem - property bool isSeparator: modelData.type === "separator" - readonly property bool isOverflowToggle: modelData.type === "overflow-toggle" - readonly property bool isInOverflow: modelData.isInOverflow === true - - readonly property real visualSize: isSeparator ? 8 : ((widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120)) - readonly property real visualWidth: root.isVerticalOrientation ? root.barThickness : visualSize - readonly property real visualHeight: root.isVerticalOrientation ? visualSize : root.barThickness - - visible: !isInOverflow || root.overflowExpanded - opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1 - scale: (isInOverflow && !root.overflowExpanded) ? 0.8 : 1 - - width: (isInOverflow && !root.overflowExpanded) ? 0 : visualWidth - height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - z: (dragHandler.dragging) ? 100 : 0 - - // --- Drag and Drop Shift Animation Logic --- - property real shiftOffset: { - if (root.draggedIndex < 0 || !modelData.isPinned || isSeparator) - return 0; - if (index === root.draggedIndex) - return 0; - - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const myIdx = index; - const shiftAmount = visualSize + Theme.spacingXS; - - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVerticalOrientation ? 0 : delegateItem.shiftOffset - y: root.isVerticalOrientation ? delegateItem.shiftOffset : 0 - - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - visible: isSeparator - width: root.isVerticalOrientation ? root.barThickness * 0.6 : 2 - height: root.isVerticalOrientation ? 2 : root.barThickness * 0.6 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - radius: 1 - anchors.centerIn: parent - } - - AppsDockOverflowButton { - visible: isOverflowToggle - anchors.centerIn: parent - width: delegateItem.visualWidth - height: delegateItem.visualHeight - iconSize: 24 - overflowCount: modelData.overflowCount || 0 - overflowExpanded: root.overflowExpanded - isVertical: root.isVerticalOrientation - showBadge: root.showOverflowBadge - z: 10 - onClicked: { - console.log("Overflow button clicked! Current state:", root.overflowExpanded); - root.overflowExpanded = !root.overflowExpanded; - console.log("New state:", root.overflowExpanded); - } - } - - Item { - id: appItem - visible: !isSeparator && !isOverflowToggle - anchors.fill: parent - - property bool isFocused: { - if (modelData.type === "grouped") { - return modelData.allWindows.some(w => w.toplevel && w.toplevel.activated); - } - return modelData.toplevel ? modelData.toplevel.activated : false; - } - - property var appId: modelData.appId - property int windowCount: modelData.windowCount || (modelData.isRunning ? 1 : 0) - property string windowTitle: { - if (modelData.type === "grouped") { - const active = modelData.allWindows.find(w => w.toplevel && w.toplevel.activated); - if (active) - return active.windowTitle || "(Unnamed)"; - if (modelData.allWindows.length > 0) - return modelData.allWindows[0].windowTitle || "(Unnamed)"; - return ""; - } - return modelData.toplevel ? (modelData.toplevel.title || "(Unnamed)") : ""; - } - - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = appId ? DesktopEntries.heuristicLookup(appId) : null; - const appName = appId ? Paths.getAppName(appId, desktopEntry) : "Unknown"; - - if (modelData.type === "grouped" && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - - readonly property bool enlargeEnabled: (widgetData?.appsDockEnlargeOnHover !== undefined ? widgetData.appsDockEnlargeOnHover : SettingsData.appsDockEnlargeOnHover) - readonly property real enlargeScale: enlargeEnabled && mouseArea.containsMouse ? (widgetData?.appsDockEnlargePercentage !== undefined ? widgetData.appsDockEnlargePercentage : SettingsData.appsDockEnlargePercentage) / 100.0 : 1.0 - readonly property real baseIconSizeMultiplier: (widgetData?.appsDockIconSizePercentage !== undefined ? widgetData.appsDockIconSizePercentage : SettingsData.appsDockIconSizePercentage) / 100.0 - readonly property real effectiveIconSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) * baseIconSizeMultiplier - - readonly property color activeOverlayColor: { - switch (SettingsData.appsDockActiveColorMode) { - case "secondary": - return Theme.secondary; - case "primaryContainer": - return Theme.primaryContainer; - case "error": - return Theme.error; - case "success": - return Theme.success; - default: - return Theme.primary; - } - } - - transform: Translate { - x: (dragHandler.dragging && !root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0 - y: (dragHandler.dragging && root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0 - } - - Rectangle { - id: visualContent - width: root.isVerticalOrientation ? root.iconCellSize : delegateItem.visualSize - height: root.isVerticalOrientation ? delegateItem.visualSize : root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - const colorizeEnabled = (widgetData?.appsDockColorizeActive !== undefined ? widgetData.appsDockColorizeActive : SettingsData.appsDockColorizeActive); - - if (appItem.isFocused && colorizeEnabled) { - return mouseArea.containsMouse ? Theme.withAlpha(Qt.lighter(appItem.activeOverlayColor, 1.3), 0.4) : Theme.withAlpha(appItem.activeOverlayColor, 0.3); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - AppIconRenderer { - id: coreIcon - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - iconSize: appItem.effectiveIconSize - materialIconSizeAdjustment: 0 - iconValue: { - if (!modelData || !modelData.isCoreApp || !modelData.coreAppData) - return ""; - const appId = modelData.coreAppData.id || modelData.coreAppData.builtInPluginId; - if ((appId === "dms_settings" || appId === "dms_notepad" || appId === "dms_sysmon") && modelData.coreAppData.cornerIcon) { - return "material:" + modelData.coreAppData.cornerIcon; - } - return modelData.coreAppData.icon || ""; - } - colorOverride: Theme.widgetIconColor - fallbackText: "?" - visible: iconValue !== "" - z: 2 - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - IconImage { - id: iconImg - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - width: appItem.effectiveIconSize - height: appItem.effectiveIconSize - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!appItem.appId) - return ""; - if (modelData.isCoreApp) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(appItem.appId); - return Paths.getAppIcon(appItem.appId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready && !coreIcon.visible - layer.enabled: appItem.appId === "org.quickshell" || appItem.appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - z: 2 - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - DankIcon { - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - size: appItem.effectiveIconSize - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && !coreIcon.visible && Paths.isSteamApp(appItem.appId) - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !coreIcon.visible && !Paths.isSteamApp(appItem.appId) - text: { - root._desktopEntriesUpdateTrigger; - if (!appItem.appId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(appItem.appId); - const appName = Paths.getAppName(appItem.appId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: modelData.type === "grouped" && appItem.windowCount > 1 && (widgetData?.barShowOverflowBadge !== undefined ? widgetData.barShowOverflowBadge : SettingsData.barShowOverflowBadge) - z: 10 - - StyledText { - anchors.centerIn: parent - text: appItem.windowCount > 9 ? "9+" : appItem.windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - visible: !root.isVerticalOrientation && !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: appItem.windowTitle || appItem.appId - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - Rectangle { - visible: modelData.isRunning && !(widgetData?.appsDockHideIndicators !== undefined ? widgetData.appsDockHideIndicators : SettingsData.appsDockHideIndicators) - width: root.isVerticalOrientation ? 2 : 20 - height: root.isVerticalOrientation ? 20 : 2 - radius: 1 - color: appItem.isFocused ? Theme.primary : Theme.surfaceText - opacity: appItem.isFocused ? 1 : 0.5 - - anchors.bottom: root.isVerticalOrientation ? undefined : parent.bottom - anchors.right: root.isVerticalOrientation ? parent.right : undefined - anchors.horizontalCenter: root.isVerticalOrientation ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.isVerticalOrientation ? parent.verticalCenter : undefined - - anchors.margins: 0 - z: 5 - } - } - } - - // Handler for Drag Logic - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 500 - repeat: false - onTriggered: { - if (modelData.isPinned) { - dragHandler.longPressing = true; - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && modelData.isPinned) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.movePinnedApp(root.draggedIndex, root.dropTargetIndex); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (modelData.type === "grouped") { - if (modelData.windowCount === 0) { - if (modelData.isCoreApp && modelData.coreAppData) { - AppSearchService.executeCoreApp(modelData.coreAppData); - } else { - const moddedId = Paths.moddedAppId(modelData.appId); - const desktopEntry = DesktopEntries.heuristicLookup(moddedId); - if (desktopEntry) - SessionService.launchDesktopEntry(desktopEntry); - } - } else if (modelData.windowCount === 1) { - if (modelData.allWindows[0].toplevel) - modelData.allWindows[0].toplevel.activate(); - } else { - let currentIndex = -1; - for (var i = 0; i < modelData.allWindows.length; i++) { - if (modelData.allWindows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % modelData.allWindows.length; - modelData.allWindows[nextIndex].toplevel.activate(); - } - } - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragHandler.dragStartPos.x, 2) + Math.pow(mouse.y - dragHandler.dragStartPos.y, 2)); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = index; - root.dropTargetIndex = index; - } - } - - if (!dragHandler.dragging) - return; - - const axisOffset = root.isVerticalOrientation ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x); - dragHandler.dragAxisOffset = axisOffset; - - const itemSize = (root.isVerticalOrientation ? delegateItem.height : delegateItem.width) + Theme.spacingXS; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.pinnedAppCount - 1, index + slotOffset)); - - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onEntered: { - root.hoveredItem = delegateItem; - if (isSeparator || isOverflowToggle) - return; - - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(0, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const isLeft = root.axis?.edge === "left"; - const tooltipX = isLeft ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const screenRelativeY = globalPos.y - screenY + root.minTooltipY; - tooltipLoader.item.show(appItem.tooltipText, screenX + tooltipX, screenRelativeY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(appItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) - tooltipLoader.item.hide(); - tooltipLoader.active = false; - } - } - - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - contextMenuLoader.active = true; - - if (contextMenuLoader.item) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const isBarVertical = root.axis?.isVertical ?? false; - const barEdge = root.axis?.edge ?? "top"; - - let x = globalPos.x - screenX; - let y = globalPos.y - screenY; - - switch (barEdge) { - case "bottom": - y = (root.parentScreen ? root.parentScreen.height : Screen.height) - root.barThickness - root.barSpacing; - break; - case "top": - y = root.barThickness + root.barSpacing; - break; - case "left": - x = root.barThickness + root.barSpacing; - break; - case "right": - x = (root.parentScreen ? root.parentScreen.width : Screen.width) - root.barThickness - root.barSpacing; - break; - } - - const shouldHidePin = modelData.appId === "org.quickshell" || modelData.appId === "com.danklinux.dms"; - const moddedId = Paths.moddedAppId(modelData.appId); - const desktopEntry = moddedId ? DesktopEntries.heuristicLookup(moddedId) : null; - - contextMenuLoader.item.showAt(x, y, isBarVertical, barEdge, modelData, shouldHidePin, desktopEntry, root.parentScreen); - } - } - } - } - } - } - } - - Loader { - id: contextMenuLoader - active: false - source: "AppsDockContextMenu.qml" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml deleted file mode 100644 index 46c4f69..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml +++ /dev/null @@ -1,486 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WlrLayershell.namespace: "dms:dock-context-menu" - - property var appData: null - property var anchorItem: null - property int margin: 10 - property bool hidePin: false - property var desktopEntry: null - property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, data, hidePinOption, entry, targetScreen) { - if (targetScreen) { - root.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - appData = data; - hidePin = hidePinOption || false; - desktopEntry = entry || null; - - visible = true; - - if (targetScreen) { - TrayMenuManager.registerMenu(targetScreen.name, root); - } - } - - function close() { - visible = false; - - if (root.screen) { - TrayMenuManager.unregisterMenu(root.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (root.screen) { - TrayMenuManager.unregisterMenu(root.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - root.close(); - } - } - - Rectangle { - id: menuContainer - - x: { - if (root.isVertical) { - if (root.edge === "left") { - return Math.min(root.width - width - 10, root.anchorPos.x); - } else { - return Math.max(10, root.anchorPos.x - width); - } - } else { - const left = 10; - const right = root.width - width - 10; - const want = root.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - if (root.isVertical) { - const top = 10; - const bottom = root.height - height - 10; - const want = root.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (root.edge === "top") { - return Math.min(root.height - height - 10, root.anchorPos.y); - } else { - return Math.max(10, root.anchorPos.y - height); - } - } - } - - width: Math.min(400, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - opacity: root.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - // Window list for grouped apps - Repeater { - model: { - if (!root.appData || root.appData.type !== "grouped") - return []; - - const toplevels = []; - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === root.appData.appId) { - toplevels.push(toplevel); - } - } - return toplevels; - } - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: windowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: closeButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: (modelData && modelData.title) ? modelData.title : I18n.tr("(Unnamed)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - Rectangle { - id: closeButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - radius: 10 - color: closeMouseArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: closeMouseArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData && modelData.close) { - modelData.close(); - } - root.close(); - } - } - } - - DankRipple { - id: windowRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: windowArea - anchors.fill: parent - anchors.rightMargin: 24 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData && modelData.activate) { - modelData.activate(); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.appData) - return false; - if (root.appData.type !== "grouped") - return false; - return root.appData.windowCount > 0; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: root.desktopEntry && root.desktopEntry.actions ? root.desktopEntry.actions : [] - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: actionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Item { - anchors.verticalCenter: parent.verticalCenter - width: 16 - height: 16 - visible: modelData.icon && modelData.icon !== "" - - IconImage { - anchors.fill: parent - source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : "" - smooth: true - asynchronous: true - visible: status === Image.Ready - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: actionRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: actionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionService.launchDesktopAction(root.desktopEntry, modelData); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) { - return false; - } - return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand); - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.hidePin - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: pinRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: pinArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!root.appData) { - return; - } - if (root.appData.isPinned) { - SessionData.removeBarPinnedApp(root.appData.appId); - } else { - SessionData.addBarPinnedApp(root.appData.appId); - } - root.close(); - } - } - } - - Rectangle { - visible: { - const hasNvidia = !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand; - const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)); - const hasPinOption = !root.hidePin; - const hasContentAbove = hasPinOption || hasNvidia; - return hasContentAbove && hasWindow; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: nvidiaArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Launch on dGPU") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: nvidiaRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: nvidiaArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.desktopEntry) { - SessionService.launchDesktopEntry(root.desktopEntry, true); - } - root.close(); - } - } - } - - Rectangle { - visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)) - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: { - if (root.appData && root.appData.type === "grouped") { - return I18n.tr("Close All Windows"); - } - return I18n.tr("Close Window"); - } - font.pixelSize: Theme.fontSizeSmall - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: closeRipple - rippleColor: Theme.error - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: closeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.appData?.type === "window") { - root.appData?.toplevel?.close(); - } else if (root.appData?.type === "grouped") { - root.appData?.allWindows?.forEach(window => window.toplevel?.close()); - } - root.close(); - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - onClicked: root.close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml deleted file mode 100644 index 82c78d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property real iconSize: 24 - property int overflowCount: 0 - property bool overflowExpanded: false - property bool isVertical: false - property bool showBadge: true - - signal clicked - - Rectangle { - id: buttonBackground - anchors.centerIn: parent - width: root.iconSize - height: root.iconSize - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1) - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - id: arrowIcon - anchors.centerIn: parent - size: root.iconSize * 0.6 - name: "expand_more" - color: Theme.widgetIconColor - rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) - - Behavior on rotation { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - } - - Rectangle { - visible: overflowCount > 0 && !overflowExpanded && root.showBadge - anchors.right: buttonBackground.right - anchors.top: buttonBackground.top - anchors.rightMargin: -4 - anchors.topMargin: -4 - width: Math.max(18, badgeText.width + 8) - height: 18 - radius: 9 - color: Theme.primary - z: 10 - - StyledText { - id: badgeText - anchors.centerIn: parent - text: `+${overflowCount}` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.onPrimary - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml deleted file mode 100644 index 52ace33..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import Quickshell.Services.Mpris -import qs.Common -import qs.Services - -Item { - id: root - - readonly property MprisPlayer activePlayer: MprisController.activePlayer - readonly property bool hasActiveMedia: activePlayer !== null - readonly property bool isPlaying: hasActiveMedia && activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing - - width: 20 - height: Theme.iconSize - - Loader { - active: isPlaying - - sourceComponent: Component { - Ref { - service: CavaService - } - } - } - - readonly property real maxBarHeight: Theme.iconSize - 2 - readonly property real minBarHeight: 3 - readonly property real heightRange: maxBarHeight - minBarHeight - property var barHeights: [minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight] - - Timer { - id: fallbackTimer - - running: !CavaService.cavaAvailable && isPlaying - interval: 500 - repeat: true - onTriggered: { - CavaService.values = [Math.random() * 20 + 5, Math.random() * 25 + 8, Math.random() * 22 + 6, Math.random() * 20 + 5, Math.random() * 22 + 6, Math.random() * 25 + 8]; - } - } - - Connections { - target: CavaService - function onValuesChanged() { - if (!root.isPlaying) { - root.barHeights = [root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight]; - return; - } - - const newHeights = []; - for (let i = 0; i < 6; i++) { - if (CavaService.values.length <= i) { - newHeights.push(root.minBarHeight); - continue; - } - - const rawLevel = CavaService.values[i]; - if (rawLevel <= 0) { - newHeights.push(root.minBarHeight); - } else if (rawLevel >= 100) { - newHeights.push(root.maxBarHeight); - } else { - newHeights.push(root.minBarHeight + Math.sqrt(rawLevel * 0.01) * root.heightRange); - } - } - root.barHeights = newHeights; - } - } - - Row { - anchors.centerIn: parent - spacing: 1.5 - - Repeater { - model: 6 - - Rectangle { - width: 2 - height: root.barHeights[index] - radius: 1.5 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - Behavior on height { - enabled: root.isPlaying && !CavaService.cavaAvailable - NumberAnimation { - duration: 100 - easing.type: Easing.Linear - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml deleted file mode 100644 index 51d4b54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick -import Quickshell.Services.UPower -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: battery - - property bool batteryPopupVisible: false - property var popoutTarget: null - - property real touchpadAccumulator: 0 - - readonly property int barPosition: { - switch (axis?.edge) { - case "top": - return 0; - case "bottom": - return 1; - case "left": - return 2; - case "right": - return 3; - default: - return 0; - } - } - - signal toggleBatteryPopup - - visible: true - - content: Component { - Item { - implicitWidth: battery.isVerticalOrientation ? (battery.widgetThickness - battery.horizontalPadding * 2) : batteryContent.implicitWidth - implicitHeight: battery.isVerticalOrientation ? batteryColumn.implicitHeight : (battery.widgetThickness - battery.horizontalPadding * 2) - - Column { - id: batteryColumn - visible: battery.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.barIconSize(battery.barThickness, undefined, battery.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (!BatteryService.batteryAvailable) { - return Theme.widgetIconColor; - } - - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryLevel.toString() - font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale, battery.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - visible: BatteryService.batteryAvailable - } - } - - Row { - id: batteryContent - visible: !battery.isVerticalOrientation - anchors.centerIn: parent - spacing: (barConfig?.noBackground ?? false) ? 1 : 2 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.barIconSize(battery.barThickness, -4, battery.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (!BatteryService.batteryAvailable) { - return Theme.widgetIconColor; - } - - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: `${BatteryService.batteryLevel}%` - font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale, battery.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - } - } - } - - MouseArea { - x: -battery.leftMargin - y: -battery.topMargin - width: battery.width + battery.leftMargin + battery.rightMargin - height: battery.height + battery.topMargin + battery.bottomMargin - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - battery.triggerRipple(this, mouse.x, mouse.y); - toggleBatteryPopup(); - } - onWheel: wheel => { - var delta = wheel.angleDelta.y; - if (delta === 0) - return; - - // Check if this is a touchpad - if (delta !== 120 && delta !== -120) { - touchpadAccumulator += delta; - console.info("Acc: "+touchpadAccumulator); - if (Math.abs(touchpadAccumulator) < 500) - return; - delta = touchpadAccumulator; - touchpadAccumulator = 0; - } - console.info("Trigger! Delta: "+delta) - - // This is after the other delta checks so it only shows on valid Y scroll - if (typeof PowerProfiles === "undefined") { - ToastService.showError("power-profiles-daemon not available"); - return; - } - - // Get list of profiles, and current index - const profiles = [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []); - var index = profiles.findIndex(profile => PowerProfiles.profile === profile); - - // Step once based on mouse wheel direction - if (delta > 0) index += 1; - else index -= 1; - - // Already at end of list, can't go further - if (index < 0 || index >= profiles.length) return; - - // Set new profile - PowerProfiles.profile = profiles[index]; - if (PowerProfiles.profile !== profiles[index]) { - ToastService.showError("Failed to set power profile"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml deleted file mode 100644 index ada41dd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - opacity: DMSService.capsLockState ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: !DMSService.capsLockState && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: !DMSService.capsLockState && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "shift_lock" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.primary - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml deleted file mode 100644 index e970662..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml +++ /dev/null @@ -1,314 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property bool isAutoHideBar: false - - signal clipboardClicked - signal showSavedItemsRequested - signal clearAllRequested - - readonly property real minTooltipY: { - if (!parentScreen || !(axis?.isVertical ?? false)) { - return 0; - } - if (isAutoHideBar) { - return 0; - } - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - return 0; - } - - function clamp(value, minValue, maxValue) { - return Math.max(minValue, Math.min(maxValue, value)); - } - - function openContextMenu() { - const screen = root.parentScreen || Screen; - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const isVertical = root.axis?.isVertical ?? false; - const edge = root.axis?.edge ?? "top"; - const gap = Math.max(Theme.spacingXS, root.barSpacing ?? Theme.spacingXS); - - const globalPos = root.mapToGlobal(root.width / 2, root.height / 2); - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - let anchorX = relativeX; - let anchorY = relativeY; - - if (isVertical) { - anchorX = edge === "left" ? (root.barThickness + root.barSpacing + gap) : (screen.width - (root.barThickness + root.barSpacing + gap)); - anchorY = relativeY + root.minTooltipY; - } else { - anchorX = relativeX; - anchorY = edge === "bottom" ? (screen.height - (root.barThickness + root.barSpacing + gap)) : (root.barThickness + root.barSpacing + gap); - } - - contextMenuWindow.showAt(anchorX, anchorY, isVertical, edge, screen); - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y) - onClicked: function (mouse) { - switch (mouse.button) { - case Qt.RightButton: - openContextMenu(); - break; - case Qt.LeftButton: - clipboardClicked(); - break; - } - } - } - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "content_paste" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - } - } - - PanelWindow { - id: contextMenuWindow - - WindowBlur { - targetWindow: contextMenuWindow - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: contextMenuWindow.visible ? menuContainer.width : 0 - blurHeight: contextMenuWindow.visible ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:clipboard-context-menu" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, targetScreen) { - if (targetScreen) { - contextMenuWindow.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - visible = true; - - if (contextMenuWindow.screen) { - TrayMenuManager.registerMenu(contextMenuWindow.screen.name, contextMenuWindow); - } - } - - function closeMenu() { - visible = false; - - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.closeMenu(); - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: contextMenuWindow.closeMenu() - } - - Rectangle { - id: menuContainer - - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - y: { - if (contextMenuWindow.isVertical) { - const top = 10; - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } - if (contextMenuWindow.edge === "top") { - return Math.min(contextMenuWindow.height - height - 10, contextMenuWindow.anchorPos.y); - } - return Math.max(10, contextMenuWindow.anchorPos.y - height); - } - - width: Math.min(240, Math.max(170, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(64, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - - opacity: contextMenuWindow.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Rectangle { - id: clearAllItem - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: clearAllArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "delete_sweep" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Clear All") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: clearAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.clearAllRequested(); - } - } - } - - Rectangle { - id: savedItemsItem - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: savedItemsArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "push_pin" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Show Saved Items") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: savedItemsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.showSavedItemsRequested(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml deleted file mode 100644 index c49221e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml +++ /dev/null @@ -1,331 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: false - signal clockClicked - - onClicked: clockClicked() - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : clockRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? clockColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - readonly property bool compact: widgetData?.clockCompactMode !== undefined ? widgetData.clockCompactMode : SettingsData.clockCompactMode - - Column { - id: clockColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 0 - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - const hours = systemClock?.date?.getHours(); - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0').charAt(0); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const hours = systemClock?.date?.getHours(); - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0').charAt(1); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - visible: SettingsData.showSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Item { - width: parent.width - height: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - Rectangle { - width: parent.width * 0.6 - height: 1 - color: Theme.outlineButton - anchors.centerIn: parent - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0'); - return value.charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0'); - return value.charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0'); - return value.charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0'); - return value.charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - } - - Row { - id: clockRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingS - - property real fontSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - property real digitWidth: fontSize * 0.6 - - property string hoursStr: { - const hours = systemClock?.date?.getHours() ?? 0; - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0'); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - if (SettingsData.padHours12Hour) - return String(display).padStart(2, '0'); - return String(display); - } - property string minutesStr: String(systemClock?.date?.getMinutes() ?? 0).padStart(2, '0') - property string secondsStr: String(systemClock?.date?.getSeconds() ?? 0).padStart(2, '0') - property string ampmStr: { - if (SettingsData.use24HourClock) - return ""; - const hours = systemClock?.date?.getHours() ?? 0; - return hours >= 12 ? " PM" : " AM"; - } - - Row { - spacing: 0 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - visible: clockRow.hoursStr.length > 1 - text: clockRow.hoursStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockRow.hoursStr.length > 1 ? clockRow.hoursStr.charAt(1) : clockRow.hoursStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - - StyledText { - text: clockRow.minutesStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockRow.minutesStr.charAt(1) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: SettingsData.showSeconds - text: ":" - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - - StyledText { - visible: SettingsData.showSeconds - text: clockRow.secondsStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: SettingsData.showSeconds - text: clockRow.secondsStr.charAt(1) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: !SettingsData.use24HourClock - text: clockRow.ampmStr - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - } - - StyledText { - id: middleDot - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outlineButton - anchors.verticalCenter: parent.verticalCenter - visible: !compact - } - - StyledText { - id: dateText - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) { - return systemClock?.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat); - } - return systemClock?.date?.toLocaleDateString(I18n.locale(), "ddd d"); - } - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - visible: !compact - } - } - - SystemClock { - id: systemClock - precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml deleted file mode 100644 index d3330cd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml +++ /dev/null @@ -1,37 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - - signal colorPickerRequested - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "palette" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: root.isActive ? Theme.primary : Theme.surfaceText - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - root.colorPickerRequested(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml deleted file mode 100644 index 5413d20..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml +++ /dev/null @@ -1,830 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property var popoutTarget: null - property var widgetData: null - property string screenName: "" - property string screenModel: "" - property bool showNetworkIcon: widgetData?.showNetworkIcon !== undefined ? widgetData.showNetworkIcon : SettingsData.controlCenterShowNetworkIcon - property bool showBluetoothIcon: widgetData?.showBluetoothIcon !== undefined ? widgetData.showBluetoothIcon : SettingsData.controlCenterShowBluetoothIcon - property bool showAudioIcon: widgetData?.showAudioIcon !== undefined ? widgetData.showAudioIcon : SettingsData.controlCenterShowAudioIcon - property bool showAudioPercent: widgetData?.showAudioPercent !== undefined ? widgetData.showAudioPercent : SettingsData.controlCenterShowAudioPercent - property bool showVpnIcon: widgetData?.showVpnIcon !== undefined ? widgetData.showVpnIcon : SettingsData.controlCenterShowVpnIcon - property bool showBrightnessIcon: widgetData?.showBrightnessIcon !== undefined ? widgetData.showBrightnessIcon : SettingsData.controlCenterShowBrightnessIcon - property bool showBrightnessPercent: widgetData?.showBrightnessPercent !== undefined ? widgetData.showBrightnessPercent : SettingsData.controlCenterShowBrightnessPercent - property bool showMicIcon: widgetData?.showMicIcon !== undefined ? widgetData.showMicIcon : SettingsData.controlCenterShowMicIcon - property bool showMicPercent: widgetData?.showMicPercent !== undefined ? widgetData.showMicPercent : SettingsData.controlCenterShowMicPercent - property bool showBatteryIcon: widgetData?.showBatteryIcon !== undefined ? widgetData.showBatteryIcon : SettingsData.controlCenterShowBatteryIcon - property bool showPrinterIcon: widgetData?.showPrinterIcon !== undefined ? widgetData.showPrinterIcon : SettingsData.controlCenterShowPrinterIcon - property bool showScreenSharingIcon: widgetData?.showScreenSharingIcon !== undefined ? widgetData.showScreenSharingIcon : SettingsData.controlCenterShowScreenSharingIcon - property real touchpadThreshold: 100 - property real micAccumulator: 0 - property real volumeAccumulator: 0 - property real brightnessAccumulator: 0 - readonly property real vIconSize: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - property var _hRow: null - property var _vCol: null - property var _hAudio: null - property var _hBrightness: null - property var _hMic: null - property var _vAudio: null - property var _vBrightness: null - property var _vMic: null - property var _interactionDelegates: [] - readonly property var defaultControlCenterGroupOrder: ["network", "vpn", "bluetooth", "audio", "microphone", "brightness", "battery", "printer", "screenSharing"] - readonly property var effectiveControlCenterGroupOrder: getEffectiveControlCenterGroupOrder() - readonly property var controlCenterRenderModel: getControlCenterRenderModel() - - onIsVerticalOrientationChanged: root.clearInteractionRefs() - - onWheel: function (wheelEvent) { - const delta = wheelEvent.angleDelta.y; - if (delta === 0) - return; - - root.refreshInteractionRefs(); - - const rootX = wheelEvent.x - root.leftMargin; - const rootY = wheelEvent.y - root.topMargin; - - if (root.isVerticalOrientation && _vCol) { - const pos = root.mapToItem(_vCol, rootX, rootY); - if (_vBrightness?.visible && pos.y >= _vBrightness.y && pos.y < _vBrightness.y + _vBrightness.height) { - root.handleBrightnessWheel(delta); - } else if (_vMic?.visible && pos.y >= _vMic.y && pos.y < _vMic.y + _vMic.height) { - root.handleMicWheel(delta); - } else { - root.handleVolumeWheel(delta); - } - } else if (_hRow) { - const pos = root.mapToItem(_hRow, rootX, rootY); - if (_hBrightness?.visible && pos.x >= _hBrightness.x && pos.x < _hBrightness.x + _hBrightness.width) { - root.handleBrightnessWheel(delta); - } else if (_hMic?.visible && pos.x >= _hMic.x && pos.x < _hMic.x + _hMic.width) { - root.handleMicWheel(delta); - } else { - root.handleVolumeWheel(delta); - } - } else { - root.handleVolumeWheel(delta); - } - wheelEvent.accepted = true; - } - - onRightClicked: function (rootX, rootY) { - root.refreshInteractionRefs(); - - if (root.isVerticalOrientation && _vCol) { - const pos = root.mapToItem(_vCol, rootX, rootY); - if (_vAudio?.visible && pos.y >= _vAudio.y && pos.y < _vAudio.y + _vAudio.height) { - AudioService.toggleMute(); - return; - } - if (_vMic?.visible && pos.y >= _vMic.y && pos.y < _vMic.y + _vMic.height) { - AudioService.toggleMicMute(); - return; - } - } else if (_hRow) { - const pos = root.mapToItem(_hRow, rootX, rootY); - if (_hAudio?.visible && pos.x >= _hAudio.x && pos.x < _hAudio.x + _hAudio.width) { - AudioService.toggleMute(); - return; - } - if (_hMic?.visible && pos.x >= _hMic.x && pos.x < _hMic.x + _hMic.width) { - AudioService.toggleMicMute(); - return; - } - } - } - - Loader { - active: root.showPrinterIcon - sourceComponent: Component { - Ref { - service: CupsService - } - } - } - - function getNetworkIconName() { - if (NetworkService.wifiToggling) - return "sync"; - switch (NetworkService.networkStatus) { - case "ethernet": - return "lan"; - case "vpn": - return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon; - default: - return NetworkService.wifiSignalIcon; - } - } - - function getNetworkIconColor() { - if (NetworkService.wifiToggling) - return Theme.primary; - return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.surfaceText; - } - - function getVolumeIconName() { - if (!AudioService.sink?.audio) - return "volume_up"; - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) - return "volume_down"; - return "volume_up"; - } - - function getMicIconName() { - if (!AudioService.source?.audio) - return "mic"; - if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0) - return "mic_off"; - return "mic"; - } - - function getMicIconColor() { - if (!AudioService.source?.audio) - return Theme.surfaceText; - if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0) - return Theme.surfaceText; - return Theme.widgetIconColor; - } - - function getBrightnessIconName() { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) - return "brightness_medium"; - const level = DisplayService.getDeviceBrightness(deviceName); - if (level <= 33) - return "brightness_low"; - if (level <= 66) - return "brightness_medium"; - return "brightness_high"; - } - - function getScreenPinKey() { - if (!root.screenName) - return ""; - const screen = Quickshell.screens.find(s => s.name === root.screenName); - if (screen) { - return SettingsData.getScreenDisplayName(screen); - } - if (SettingsData.displayNameMode === "model" && root.screenModel && root.screenModel.length > 0) { - return root.screenModel; - } - return root.screenName; - } - - function getPinnedBrightnessDevice() { - const pinKey = getScreenPinKey(); - if (!pinKey) - return ""; - const pins = SettingsData.brightnessDevicePins || {}; - return pins[pinKey] || ""; - } - - function hasPinnedBrightnessDevice() { - return getPinnedBrightnessDevice().length > 0; - } - - function handleVolumeWheel(delta) { - if (!AudioService.sink?.audio) - return; - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - volumeAccumulator += delta; - if (Math.abs(volumeAccumulator) < touchpadThreshold) - return; - - delta = volumeAccumulator; - volumeAccumulator = 0; - } - - const maxVol = AudioService.sinkMaxVolume; - const currentVolume = AudioService.sink.audio.volume * 100; - const newVolume = delta > 0 ? Math.min(maxVol, currentVolume + step) : Math.max(0, currentVolume - step); - AudioService.sink.audio.muted = false; - AudioService.sink.audio.volume = newVolume / 100; - AudioService.playVolumeChangeSoundIfEnabled(); - } - - function handleMicWheel(delta) { - if (!AudioService.source?.audio) - return; - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - micAccumulator += delta; - if (Math.abs(micAccumulator) < touchpadThreshold) - return; - - delta = micAccumulator; - micAccumulator = 0; - } - - const currentVolume = AudioService.source.audio.volume * 100; - const newVolume = delta > 0 ? Math.min(100, currentVolume + step) : Math.max(0, currentVolume - step); - AudioService.source.audio.muted = false; - AudioService.source.audio.volume = newVolume / 100; - } - - function handleBrightnessWheel(delta) { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) { - return; - } - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - brightnessAccumulator += delta; - if (Math.abs(brightnessAccumulator) < touchpadThreshold) - return; - - delta = brightnessAccumulator; - brightnessAccumulator = 0; - } - - const currentBrightness = DisplayService.getDeviceBrightness(deviceName); - const newBrightness = delta > 0 ? Math.min(100, currentBrightness + step) : Math.max(1, currentBrightness - step); - DisplayService.setBrightness(newBrightness, deviceName); - } - - function getBrightness() { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) { - return; - } - return DisplayService.getDeviceBrightness(deviceName) / 100; - } - - function getBatteryIconColor() { - if (!BatteryService.batteryAvailable) - return Theme.widgetIconColor; - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.widgetIconColor; - } - - function hasPrintJobs() { - return CupsService.getTotalJobsNum() > 0; - } - - function getControlCenterIconSize() { - return Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale); - } - - function getEffectiveControlCenterGroupOrder() { - const knownIds = root.defaultControlCenterGroupOrder; - const savedOrder = root.widgetData?.controlCenterGroupOrder; - const result = []; - const seen = {}; - - if (savedOrder && typeof savedOrder.length === "number") { - for (let i = 0; i < savedOrder.length; ++i) { - const groupId = savedOrder[i]; - if (knownIds.indexOf(groupId) === -1 || seen[groupId]) - continue; - - seen[groupId] = true; - result.push(groupId); - } - } - - for (let i = 0; i < knownIds.length; ++i) { - const groupId = knownIds[i]; - if (seen[groupId]) - continue; - - seen[groupId] = true; - result.push(groupId); - } - - return result; - } - - function isGroupVisible(groupId) { - switch (groupId) { - case "screenSharing": - return root.showScreenSharingIcon && NiriService.hasCasts; - case "network": - return root.showNetworkIcon && NetworkService.networkAvailable; - case "vpn": - return root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected; - case "bluetooth": - return root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled; - case "audio": - return root.showAudioIcon; - case "microphone": - return root.showMicIcon; - case "brightness": - return root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice(); - case "battery": - return root.showBatteryIcon && BatteryService.batteryAvailable; - case "printer": - return root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs(); - default: - return false; - } - } - - function isCompositeGroup(groupId) { - return groupId === "audio" || groupId === "microphone" || groupId === "brightness"; - } - - function getControlCenterRenderModel() { - return root.effectiveControlCenterGroupOrder.map(groupId => ({ - "id": groupId, - "visible": root.isGroupVisible(groupId), - "composite": root.isCompositeGroup(groupId) - })); - } - - function clearInteractionRefs() { - root._hAudio = null; - root._hBrightness = null; - root._hMic = null; - root._vAudio = null; - root._vBrightness = null; - root._vMic = null; - } - - function registerInteractionDelegate(isVertical, item) { - if (!item) - return; - - for (let i = 0; i < root._interactionDelegates.length; ++i) { - const entry = root._interactionDelegates[i]; - if (entry && entry.item === item) { - entry.isVertical = isVertical; - return; - } - } - - root._interactionDelegates = root._interactionDelegates.concat([ - { - "isVertical": isVertical, - "item": item - } - ]); - } - - function unregisterInteractionDelegate(item) { - if (!item) - return; - - root._interactionDelegates = root._interactionDelegates.filter(entry => entry && entry.item !== item); - } - - function refreshInteractionRefs() { - root.clearInteractionRefs(); - - for (let i = 0; i < root._interactionDelegates.length; ++i) { - const entry = root._interactionDelegates[i]; - const item = entry?.item; - if (!item || !item.visible) - continue; - - const groupId = item.interactionGroupId; - if (entry.isVertical) { - if (groupId === "audio") - root._vAudio = item; - else if (groupId === "microphone") - root._vMic = item; - else if (groupId === "brightness") - root._vBrightness = item; - } else { - if (groupId === "audio") - root._hAudio = item; - else if (groupId === "microphone") - root._hMic = item; - else if (groupId === "brightness") - root._hBrightness = item; - } - } - } - - function hasNoVisibleIcons() { - return !root.controlCenterRenderModel.some(entry => entry.visible); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : controlIndicators.implicitWidth - implicitHeight: root.isVerticalOrientation ? controlColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Component.onCompleted: { - root._hRow = controlIndicators; - root._vCol = controlColumn; - root.clearInteractionRefs(); - } - - Column { - id: controlColumn - visible: root.isVerticalOrientation - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXS - - Repeater { - model: root.controlCenterRenderModel - Item { - id: verticalGroupItem - required property var modelData - required property int index - property string interactionGroupId: modelData.id - - width: parent.width - height: { - switch (modelData.id) { - case "audio": - return root.vIconSize + (audioPercentV.visible ? audioPercentV.implicitHeight + 2 : 0); - case "microphone": - return root.vIconSize + (micPercentV.visible ? micPercentV.implicitHeight + 2 : 0); - case "brightness": - return root.vIconSize + (brightnessPercentV.visible ? brightnessPercentV.implicitHeight + 2 : 0); - default: - return root.vIconSize; - } - } - visible: modelData.visible - - Component.onCompleted: { - root.registerInteractionDelegate(true, verticalGroupItem); - root.refreshInteractionRefs(); - } - Component.onDestruction: { - if (root) { - root.unregisterInteractionDelegate(verticalGroupItem); - root.refreshInteractionRefs(); - } - } - onVisibleChanged: root.refreshInteractionRefs() - onInteractionGroupIdChanged: { - root.refreshInteractionRefs(); - } - - DankIcon { - anchors.centerIn: parent - visible: !verticalGroupItem.modelData.composite - name: { - switch (verticalGroupItem.modelData.id) { - case "screenSharing": - return "screen_record"; - case "network": - return root.getNetworkIconName(); - case "vpn": - return "vpn_lock"; - case "bluetooth": - return "bluetooth"; - case "battery": - return Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable); - case "printer": - return "print"; - default: - return "settings"; - } - } - size: root.vIconSize - color: { - switch (verticalGroupItem.modelData.id) { - case "screenSharing": - return NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText; - case "network": - return root.getNetworkIconColor(); - case "vpn": - return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; - case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; - case "battery": - return root.getBatteryIconColor(); - case "printer": - return Theme.primary; - default: - return Theme.widgetIconColor; - } - } - } - - DankIcon { - id: audioIconV - visible: verticalGroupItem.modelData.id === "audio" - name: root.getVolumeIconName() - size: root.vIconSize - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: audioPercentV - visible: verticalGroupItem.modelData.id === "audio" && root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume) - text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: audioIconV.bottom - anchors.topMargin: 2 - } - - DankIcon { - id: micIconV - visible: verticalGroupItem.modelData.id === "microphone" - name: root.getMicIconName() - size: root.vIconSize - color: root.getMicIconColor() - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: micPercentV - visible: verticalGroupItem.modelData.id === "microphone" && root.showMicPercent && isFinite(AudioService.source?.audio?.volume) - text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: micIconV.bottom - anchors.topMargin: 2 - } - - DankIcon { - id: brightnessIconV - visible: verticalGroupItem.modelData.id === "brightness" - name: root.getBrightnessIconName() - size: root.vIconSize - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: brightnessPercentV - visible: verticalGroupItem.modelData.id === "brightness" && root.showBrightnessPercent && isFinite(getBrightness()) - text: Math.round(getBrightness() * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: brightnessIconV.bottom - anchors.topMargin: 2 - } - } - } - - Item { - width: parent.width - height: root.vIconSize - visible: root.hasNoVisibleIcons() - - DankIcon { - name: "settings" - size: root.vIconSize - color: root.isActive ? Theme.primary : Theme.widgetIconColor - anchors.centerIn: parent - } - } - } - - Row { - id: controlIndicators - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Repeater { - model: root.controlCenterRenderModel - - Item { - id: horizontalGroupItem - required property var modelData - required property int index - property string interactionGroupId: modelData.id - - width: { - switch (modelData.id) { - case "audio": - return audioGroup.width; - case "microphone": - return micGroup.width; - case "brightness": - return brightnessGroup.width; - default: - return root.getControlCenterIconSize(); - } - } - implicitWidth: width - height: root.widgetThickness - root.horizontalPadding * 2 - visible: modelData.visible - - Component.onCompleted: { - root.registerInteractionDelegate(false, horizontalGroupItem); - root.refreshInteractionRefs(); - } - Component.onDestruction: { - if (root) { - root.unregisterInteractionDelegate(horizontalGroupItem); - root.refreshInteractionRefs(); - } - } - onVisibleChanged: root.refreshInteractionRefs() - onInteractionGroupIdChanged: { - root.refreshInteractionRefs(); - } - - DankIcon { - id: iconOnlyItem - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - visible: !horizontalGroupItem.modelData.composite - name: { - switch (horizontalGroupItem.modelData.id) { - case "screenSharing": - return "screen_record"; - case "network": - return root.getNetworkIconName(); - case "vpn": - return "vpn_lock"; - case "bluetooth": - return "bluetooth"; - case "battery": - return Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable); - case "printer": - return "print"; - default: - return "settings"; - } - } - size: root.getControlCenterIconSize() - color: { - switch (horizontalGroupItem.modelData.id) { - case "screenSharing": - return NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText; - case "network": - return root.getNetworkIconColor(); - case "vpn": - return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; - case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; - case "battery": - return root.getBatteryIconColor(); - case "printer": - return Theme.primary; - default: - return Theme.widgetIconColor; - } - } - } - - Rectangle { - id: audioGroup - width: audioContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "audio" - - Row { - id: audioContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: audioIcon - name: root.getVolumeIconName() - size: root.getControlCenterIconSize() - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: audioPercent - visible: root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume) - text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - - Rectangle { - id: micGroup - width: micContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "microphone" - - Row { - id: micContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: micIcon - name: root.getMicIconName() - size: root.getControlCenterIconSize() - color: root.getMicIconColor() - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: micPercent - visible: root.showMicPercent && isFinite(AudioService.source?.audio?.volume) - text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - - Rectangle { - id: brightnessGroup - width: brightnessContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "brightness" - - Row { - id: brightnessContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: brightnessIcon - name: root.getBrightnessIconName() - size: root.getControlCenterIconSize() - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: brightnessPercent - visible: root.showBrightnessPercent && isFinite(getBrightness()) - text: Math.round(getBrightness() * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - } - } - - DankIcon { - name: "settings" - size: root.getControlCenterIconSize() - color: root.isActive ? Theme.primary : Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - visible: root.hasNoVisibleIcons() - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.NoButton - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml deleted file mode 100644 index 212f9b5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml +++ /dev/null @@ -1,146 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal cpuClicked - - Component.onCompleted: { - DgopService.addRef(["cpu"]); - } - Component.onDestruction: { - DgopService.removeRef(["cpu"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? cpuColumn.implicitHeight : cpuContent.implicitHeight - - Column { - id: cpuColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "memory" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuUsage > 80) { - return Theme.tempDanger; - } - - if (DgopService.cpuUsage > 60) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null || DgopService.cpuUsage === 0) { - return "--"; - } - - return DgopService.cpuUsage.toFixed(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: cpuContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: cpuIcon - name: "memory" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuUsage > 80) { - return Theme.tempDanger; - } - - if (DgopService.cpuUsage > 60) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(cpuBaseline.width, cpuCurrent.width) : cpuCurrent.width - implicitHeight: cpuText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: cpuBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "100%" - } - - StyledTextMetrics { - id: cpuCurrent - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: cpuText.text - } - - StyledText { - id: cpuText - text: { - const v = DgopService.cpuUsage; - if (v === undefined || v === null || v === 0) { - return "--%"; - } - return v.toFixed(0) + "%"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - cpuClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml deleted file mode 100644 index 4066387..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml +++ /dev/null @@ -1,140 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal cpuTempClicked - - Component.onCompleted: { - DgopService.addRef(["cpu"]); - } - Component.onDestruction: { - DgopService.removeRef(["cpu"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? cpuTempColumn.implicitHeight : cpuTempRow.implicitHeight - - Column { - id: cpuTempColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "device_thermostat" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuTemperature > 85) { - return Theme.tempDanger; - } - - if (DgopService.cpuTemperature > 69) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) { - return "--"; - } - - return Math.round(DgopService.cpuTemperature).toString(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: cpuTempRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: cpuTempIcon - name: "device_thermostat" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuTemperature > 85) { - return Theme.tempDanger; - } - - if (DgopService.cpuTemperature > 69) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(tempBaseline.width, cpuTempText.paintedWidth) : cpuTempText.paintedWidth - implicitHeight: cpuTempText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: tempBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88°" - } - - StyledText { - id: cpuTempText - text: { - if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) { - return "--°"; - } - - return Math.round(DgopService.cpuTemperature) + "°"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - cpuTempClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml deleted file mode 100644 index f810cb6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: layout - - property bool layoutPopupVisible: false - property var popoutTarget: null - - signal toggleLayoutPopup() - - visible: CompositorService.isDwl && DwlService.dwlAvailable - - property var outputState: parentScreen ? DwlService.getOutputState(parentScreen.name) : null - property string currentLayoutSymbol: outputState?.layoutSymbol || "" - property int currentLayoutIndex: outputState?.layout || 0 - - readonly property var layoutIcons: ({ - "CT": "view_compact", - "G": "grid_view", - "K": "layers", - "M": "fullscreen", - "RT": "view_sidebar", - "S": "view_carousel", - "T": "view_quilt", - "VG": "grid_on", - "VK": "view_day", - "VS": "scrollable_header", - "VT": "clarify" - }) - - function getLayoutIcon(symbol) { - return layoutIcons[symbol] || "view_quilt" - } - - Connections { - target: DwlService - function onStateChanged() { - outputState = parentScreen ? DwlService.getOutputState(parentScreen.name) : null - } - } - - content: Component { - Item { - implicitWidth: layout.isVerticalOrientation ? (layout.widgetThickness - layout.horizontalPadding * 2) : layoutContent.implicitWidth - implicitHeight: layout.isVerticalOrientation ? layoutColumn.implicitHeight : (layout.widgetThickness - layout.horizontalPadding * 2) - - Column { - id: layoutColumn - visible: layout.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: layout.getLayoutIcon(layout.currentLayoutSymbol) - size: Theme.barIconSize(layout.barThickness, undefined, layout.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: layout.currentLayoutSymbol - font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale, layout.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: layoutContent - visible: !layout.isVerticalOrientation - anchors.centerIn: parent - spacing: (barConfig?.noBackground ?? false) ? 1 : 2 - - DankIcon { - name: layout.getLayoutIcon(layout.currentLayoutSymbol) - size: Theme.barIconSize(layout.barThickness, -4, layout.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: layout.currentLayoutSymbol - font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale, layout.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - onClicked: { - toggleLayoutPopup() - } - - onRightClicked: { - if (!parentScreen || !DwlService.dwlAvailable || DwlService.layouts.length === 0) { - return - } - - const currentIndex = layout.currentLayoutIndex - const nextIndex = (currentIndex + 1) % DwlService.layouts.length - - DwlService.setLayout(parentScreen.name, nextIndex) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml deleted file mode 100644 index d6e6d1b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml +++ /dev/null @@ -1,255 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/" - property int diskUsageMode: (widgetData && widgetData.diskUsageMode !== undefined) ? widgetData.diskUsageMode : 0 - property bool isHovered: mouseArea.containsMouse - property bool isAutoHideBar: false - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const currentMountPath = root.mountPath || "/"; - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === currentMountPath) { - return DgopService.diskMounts[i]; - } - } - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === "/") { - return DgopService.diskMounts[i]; - } - } - - return DgopService.diskMounts[0] || null; - } - - property real diskUsagePercent: { - if (!selectedMount || !selectedMount.percent) { - return 0; - } - const percentStr = selectedMount.percent.replace("%", ""); - return parseFloat(percentStr) || 0; - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - const spacing = barConfig?.spacing ?? 4; - const offset = barThickness + spacing; - return offset; - } - - return 0; - } - - Connections { - function onWidgetDataChanged() { - root.mountPath = Qt.binding(() => { - return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/"; - }); - - root.selectedMount = Qt.binding(() => { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const currentMountPath = root.mountPath || "/"; - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === currentMountPath) { - return DgopService.diskMounts[i]; - } - } - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === "/") { - return DgopService.diskMounts[i]; - } - } - - return DgopService.diskMounts[0] || null; - }); - } - - target: SettingsData - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : diskContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? diskColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: diskColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "storage" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.diskUsagePercent > 90) { - return Theme.tempDanger; - } - if (root.diskUsagePercent > 75) { - return Theme.tempWarning; - } - return Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { - return "--"; - } - if (!root.selectedMount) return "--"; - switch (root.diskUsageMode) { - case 1: return root.selectedMount.size || "--"; - case 2: return root.selectedMount.avail || "--"; - case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--"); - default: return root.diskUsagePercent.toFixed(0); - } - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: diskContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: 3 - - DankIcon { - name: "storage" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.diskUsagePercent > 90) { - return Theme.tempDanger; - } - if (root.diskUsagePercent > 75) { - return Theme.tempWarning; - } - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!root.selectedMount) { - return "--"; - } - return root.selectedMount.mount; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - } - - StyledText { - text: { - if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { - return "--%"; - } - if (!root.selectedMount) return "--%"; - switch (root.diskUsageMode) { - case 1: return root.selectedMount.size || "--"; - case 2: return root.selectedMount.avail || "--"; - case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--"); - default: return root.diskUsagePercent.toFixed(0) + "%"; - } - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - - StyledTextMetrics { - id: diskBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: { - switch (root.diskUsageMode) { - case 3: return "888.8G / 888.8G"; - case 1: - case 2: return "888.8G"; - default: return "100%"; - } - } - } - - width: Math.max(diskBaseline.width, paintedWidth) - } - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - MouseArea { - id: mouseArea - z: 1 - anchors.fill: parent - hoverEnabled: root.isVerticalOrientation - onEntered: { - if (root.isVerticalOrientation && root.selectedMount) { - tooltipLoader.active = true; - if (tooltipLoader.item) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen || Screen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml deleted file mode 100644 index a4ad4d2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml +++ /dev/null @@ -1,317 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: widgetData?.focusedWindowCompactMode !== undefined ? widgetData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode - property int availableWidth: 400 - readonly property int maxNormalWidth: 456 - readonly property int maxCompactWidth: 288 - property Toplevel activeWindow: null - property var activeDesktopEntry: null - property bool isHovered: mouseArea.containsMouse - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + (barSpacing || 4); - } - - return 0; - } - - function updateActiveWindow() { - const active = ToplevelManager.activeToplevel; - - if (!active) { - // Only clear if our tracked window is no longer alive - if (activeWindow) { - const alive = ToplevelManager.toplevels?.values; - if (alive && !Array.from(alive).some(t => t === activeWindow)) - activeWindow = null; - } - return; - } - - if (!parentScreen || CompositorService.filterCurrentDisplay([active], parentScreen?.name)?.length > 0) { - activeWindow = active; - } - // else: active window is on a different screen so keep the previous value - } - - Component.onCompleted: { - updateActiveWindow(); - updateDesktopEntry(); - } - - Connections { - target: ToplevelManager - function onActiveToplevelChanged() { - root.updateActiveWindow(); - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - root.updateActiveWindow(); - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - root.updateDesktopEntry(); - } - } - - Connections { - target: root - function onActiveWindowChanged() { - root.updateDesktopEntry(); - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - root.updateDesktopEntry(); - } - } - - function updateDesktopEntry() { - if (activeWindow && activeWindow.appId) { - const moddedId = Paths.moddedAppId(activeWindow.appId); - activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId); - } else { - activeDesktopEntry = null; - } - } - readonly property bool hasWindowsOnCurrentWorkspace: { - if (CompositorService.isNiri) { - let currentWorkspaceId = null; - for (var i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.is_focused) { - currentWorkspaceId = ws.id; - break; - } - } - - if (!currentWorkspaceId) { - return false; - } - - const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId); - return workspaceWindows.length > 0 && activeWindow && (activeWindow.title || activeWindow.appId); - } - - if (CompositorService.isHyprland) { - if (!Hyprland.focusedWorkspace || !activeWindow || !(activeWindow.title || activeWindow.appId)) { - return false; - } - - try { - if (!Hyprland.toplevels) - return false; - const hyprlandToplevels = Array.from(Hyprland.toplevels.values); - const activeHyprToplevel = hyprlandToplevels.find(t => t?.wayland === activeWindow); - - if (!activeHyprToplevel || !activeHyprToplevel.workspace) { - return false; - } - - return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id; - } catch (e) { - return false; - } - } - - return activeWindow && (activeWindow.title || activeWindow.appId); - } - - width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0 - height: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? visualHeight : barThickness) : 0 - visible: hasWindowsOnCurrentWorkspace - - content: Component { - Item { - implicitWidth: { - if (!root.hasWindowsOnCurrentWorkspace) - return 0; - if (root.isVerticalOrientation) - return root.widgetThickness - root.horizontalPadding * 2; - const baseWidth = contentRow.implicitWidth; - return compactMode ? Math.min(baseWidth, maxCompactWidth - root.horizontalPadding * 2) : Math.min(baseWidth, maxNormalWidth - root.horizontalPadding * 2); - } - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - clip: false - - IconImage { - id: appIcon - anchors.centerIn: parent - width: 18 - height: 18 - visible: root.isVerticalOrientation && activeWindow && status === Image.Ready - source: { - if (!activeWindow || !activeWindow.appId) - return ""; - return Paths.getAppIcon(activeWindow.appId, activeDesktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - layer.enabled: activeWindow && (activeWindow.appId === "org.quickshell" || activeWindow.appId === "com.danklinux.dms") - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.centerIn: parent - size: 18 - name: "sports_esports" - color: Theme.widgetTextColor - visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && Paths.isSteamApp(activeWindow.appId) - } - - Text { - anchors.centerIn: parent - visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && !Paths.isSteamApp(activeWindow.appId) - text: { - if (!activeWindow || !activeWindow.appId) - return "?"; - const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !root.isVerticalOrientation - - StyledText { - id: appText - text: { - if (!activeWindow || !activeWindow.appId) - return ""; - return Paths.getAppName(activeWindow.appId, activeDesktopEntry); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, compactMode ? 80 : 180) - visible: !compactMode && text.length > 0 - } - - StyledText { - text: "•" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.outlineButton - anchors.verticalCenter: parent.verticalCenter - visible: !compactMode && appText.text && titleText.text - } - - StyledText { - id: titleText - text: { - const title = activeWindow && activeWindow.title ? activeWindow.title : ""; - const appName = appText.text; - - if (compactMode) { - if (!title || title === appName) - return title || appName; - if (title.endsWith(appName)) - return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, "") || appName; - return title; - } - - if (!title || !appName) - return title; - - if (title.endsWith(appName)) - return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, ""); - - return title; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, compactMode ? 280 : 250) - visible: text.length > 0 - } - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: root.isVerticalOrientation - acceptedButtons: Qt.NoButton - onEntered: { - if (root.isVerticalOrientation && activeWindow && activeWindow.appId && root.parentScreen) { - tooltipLoader.active = true; - if (tooltipLoader.item) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS); - - const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry); - const title = activeWindow.title || ""; - const tooltipText = appName + (title ? " • " + title : ""); - - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml deleted file mode 100644 index cf07f3e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml +++ /dev/null @@ -1,224 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0 - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal gpuTempClicked - - property real displayTemp: { - if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) { - return 0; - } - - if (selectedGpuIndex >= 0 && selectedGpuIndex < DgopService.availableGpus.length) { - return DgopService.availableGpus[selectedGpuIndex].temperature || 0; - } - - return 0; - } - - function updateWidgetPciId(pciId) { - const sections = ["left", "center", "right"]; - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return; - for (let s = 0; s < sections.length; s++) { - const sectionId = sections[s]; - let widgets = []; - if (sectionId === "left") { - widgets = (defaultBar.leftWidgets || []).slice(); - } else if (sectionId === "center") { - widgets = (defaultBar.centerWidgets || []).slice(); - } else if (sectionId === "right") { - widgets = (defaultBar.rightWidgets || []).slice(); - } - for (let i = 0; i < widgets.length; i++) { - const widget = widgets[i]; - if (typeof widget === "object" && widget.id === "gpuTemp" && (!widget.pciId || widget.pciId === "")) { - widgets[i] = { - "id": widget.id, - "enabled": widget.enabled !== undefined ? widget.enabled : true, - "selectedGpuIndex": 0, - "pciId": pciId - }; - if (sectionId === "left") { - SettingsData.setDankBarLeftWidgets(widgets); - } else if (sectionId === "center") { - SettingsData.setDankBarCenterWidgets(widgets); - } else if (sectionId === "right") { - SettingsData.setDankBarRightWidgets(widgets); - } - return; - } - } - } - } - - Component.onCompleted: { - DgopService.addRef(["gpu"]); - if (widgetData && widgetData.pciId) { - DgopService.addGpuPciId(widgetData.pciId); - } else { - autoSaveTimer.running = true; - } - } - Component.onDestruction: { - DgopService.removeRef(["gpu"]); - if (widgetData && widgetData.pciId) { - DgopService.removeGpuPciId(widgetData.pciId); - } - } - - Connections { - function onWidgetDataChanged() { - root.selectedGpuIndex = Qt.binding(() => { - return (root.widgetData && root.widgetData.selectedGpuIndex !== undefined) ? root.widgetData.selectedGpuIndex : 0; - }); - } - - target: SettingsData - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? gpuTempColumn.implicitHeight : gpuTempRow.implicitHeight - - Column { - id: gpuTempColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "auto_awesome_mosaic" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.displayTemp > 80) { - return Theme.tempDanger; - } - - if (root.displayTemp > 65) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) { - return "--"; - } - - return Math.round(root.displayTemp).toString(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: gpuTempRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: gpuTempIcon - name: "auto_awesome_mosaic" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.displayTemp > 80) { - return Theme.tempDanger; - } - - if (root.displayTemp > 65) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(gpuTempBaseline.width, gpuTempText.paintedWidth) : gpuTempText.paintedWidth - implicitHeight: gpuTempText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: gpuTempBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88°" - } - - StyledText { - id: gpuTempText - text: { - if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) { - return "--°"; - } - - return Math.round(root.displayTemp) + "°"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - gpuTempClicked(); - } - } - - Timer { - id: autoSaveTimer - - interval: 100 - running: false - onTriggered: { - if (DgopService.availableGpus && DgopService.availableGpus.length > 0) { - const firstGpu = DgopService.availableGpus[0]; - if (firstGpu && firstGpu.pciId) { - updateWidgetPciId(firstGpu.pciId); - DgopService.addGpuPciId(firstGpu.pciId); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml deleted file mode 100644 index a8e5993..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml +++ /dev/null @@ -1,36 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - SessionService.toggleIdleInhibit(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml deleted file mode 100644 index 8b49a7d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml +++ /dev/null @@ -1,268 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: widgetData?.keyboardLayoutNameCompactMode !== undefined ? widgetData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode - readonly property var langCodes: ({ - "afrikaans": "af", - "albanian": "sq", - "amharic": "am", - "arabic": "ar", - "armenian": "hy", - "azerbaijani": "az", - "basque": "eu", - "belarusian": "be", - "bengali": "bn", - "bosnian": "bs", - "bulgarian": "bg", - "burmese": "my", - "catalan": "ca", - "chinese": "zh", - "croatian": "hr", - "czech": "cs", - "danish": "da", - "dutch": "nl", - "english": "en", - "esperanto": "eo", - "estonian": "et", - "filipino": "fil", - "finnish": "fi", - "french": "fr", - "galician": "gl", - "georgian": "ka", - "german": "de", - "greek": "el", - "gujarati": "gu", - "hausa": "ha", - "hebrew": "he", - "hindi": "hi", - "hungarian": "hu", - "icelandic": "is", - "igbo": "ig", - "indonesian": "id", - "irish": "ga", - "italian": "it", - "japanese": "ja", - "javanese": "jv", - "kannada": "kn", - "kazakh": "kk", - "khmer": "km", - "korean": "ko", - "kurdish": "ku", - "kyrgyz": "ky", - "lao": "lo", - "latvian": "lv", - "lithuanian": "lt", - "luxembourgish": "lb", - "macedonian": "mk", - "malay": "ms", - "malayalam": "ml", - "maltese": "mt", - "maori": "mi", - "marathi": "mr", - "mongolian": "mn", - "nepali": "ne", - "norwegian": "no", - "pashto": "ps", - "persian": "fa", - "iranian": "fa", - "farsi": "fa", - "polish": "pl", - "portuguese": "pt", - "punjabi": "pa", - "romanian": "ro", - "russian": "ru", - "serbian": "sr", - "sindhi": "sd", - "sinhala": "si", - "slovak": "sk", - "slovenian": "sl", - "somali": "so", - "spanish": "es", - "swahili": "sw", - "swedish": "sv", - "tajik": "tg", - "tamil": "ta", - "tatar": "tt", - "telugu": "te", - "thai": "th", - "tibetan": "bo", - "turkish": "tr", - "turkmen": "tk", - "ukrainian": "uk", - "urdu": "ur", - "uyghur": "ug", - "uzbek": "uz", - "vietnamese": "vi", - "welsh": "cy", - "yiddish": "yi", - "yoruba": "yo", - "zulu": "zu" - }) - readonly property var validVariants: ["US", "UK", "GB", "AZERTY", "QWERTY", "Dvorak", "Colemak", "Mac", "Intl", "International"] - property string currentLayout: { - if (CompositorService.isNiri) { - return NiriService.getCurrentKeyboardLayoutName(); - } else if (CompositorService.isDwl) { - return DwlService.currentKeyboardLayout; - } - return ""; - } - property string hyprlandKeyboard: "" - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : contentRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? contentColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: contentColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "keyboard" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!root.currentLayout) - return ""; - const lang = root.currentLayout.split(" ")[0].toLowerCase(); - const code = root.langCodes[lang] || lang.substring(0, 2); - return code.toUpperCase(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: contentRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingS - - StyledText { - text: { - if (!root.currentLayout) - return ""; - if (root.compactMode && !CompositorService.isHyprland) { - const match = root.currentLayout.match(/^(\S+)(?:.*\(([^)]+)\))?/); - if (match) { - const lang = match[1].toLowerCase(); - const code = root.langCodes[lang] || lang.substring(0, 2); - if (match[2]) { - const variant = match[2].trim(); - const isValid = root.validVariants.some(v => variant.toUpperCase().includes(v.toUpperCase())) || variant.length <= 3; - if (isValid) - return code + "-" + variant; - } - return code.toUpperCase(); - } - return root.currentLayout.substring(0, 2).toUpperCase(); - } - return root.currentLayout; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", root.hyprlandKeyboard, "next"]); - } else if (CompositorService.isDwl) { - Quickshell.execDetached(["mmsg", "-d", "switch_keyboard_layout"]); - } - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") { - updateLayout(); - } - } - } - - Component.onCompleted: { - if (CompositorService.isHyprland) { - updateLayout(); - } - } - - function updateLayout() { - if (CompositorService.isHyprland) { - Proc.runCommand(null, ["hyprctl", "-j", "devices"], (output, exitCode) => { - if (exitCode !== 0) { - root.currentLayout = "Unknown"; - return; - } - try { - const data = JSON.parse(output); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - root.hyprlandKeyboard = mainKeyboard.name; - - if (mainKeyboard) { - const layout = mainKeyboard.layout; - const variant = mainKeyboard.variant; - const index = mainKeyboard.active_layout_index; - - if (root.compactMode && layout && index !== undefined) { - const layouts = mainKeyboard.layout.split(","); - const variants = mainKeyboard.variant.split(","); - const index = mainKeyboard.active_layout_index; - - if (layouts[index] && variants[index] !== undefined) { - if (variants[index] === "") { - root.currentLayout = layouts[index]; - } else { - root.currentLayout = layouts[index] + "-" + variants[index]; - } - } else { - root.currentLayout = layouts[index]; - } - } else if (mainKeyboard && mainKeyboard.active_keymap) { - root.currentLayout = mainKeyboard.active_keymap; - } else { - root.currentLayout = "Unknown"; - } - } else { - root.currentLayout = "Unknown"; - } - } catch (e) { - root.currentLayout = "Unknown"; - } - }); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml deleted file mode 100644 index 81e6457..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml +++ /dev/null @@ -1,123 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property var hyprlandOverviewLoader: null - - content: Component { - Item { - implicitWidth: root.widgetThickness - root.horizontalPadding * 2 - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - visible: SettingsData.launcherLogoMode === "apps" - anchors.centerIn: parent - name: "apps" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - - SystemLogo { - visible: SettingsData.launcherLogoMode === "os" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - colorOverride: Theme.effectiveLogoColor - brightnessOverride: SettingsData.launcherLogoBrightness - contrastOverride: SettingsData.launcherLogoContrast - } - - IconImage { - visible: SettingsData.launcherLogoMode === "dank" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogo.svg" - layer.enabled: Theme.effectiveLogoColor !== "" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - } - } - - IconImage { - visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc) - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - asynchronous: true - source: { - if (CompositorService.isNiri) { - return "file://" + Theme.shellDir + "/assets/niri.svg"; - } else if (CompositorService.isHyprland) { - return "file://" + Theme.shellDir + "/assets/hyprland.svg"; - } else if (CompositorService.isDwl) { - return "file://" + Theme.shellDir + "/assets/mango.png"; - } else if (CompositorService.isSway) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isScroll) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isMiracle) { - return "file://" + Theme.shellDir + "/assets/miraclewm.svg"; - } else if (CompositorService.isLabwc) { - return "file://" + Theme.shellDir + "/assets/labwc.png"; - } - return ""; - } - layer.enabled: Theme.effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - brightness: { - SettingsData.launcherLogoBrightness; - } - contrast: { - SettingsData.launcherLogoContrast; - } - } - } - - IconImage { - visible: SettingsData.launcherLogoMode === "custom" && SettingsData.launcherLogoCustomPath !== "" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - asynchronous: true - source: SettingsData.launcherLogoCustomPath ? "file://" + SettingsData.launcherLogoCustomPath.replace("file://", "") : "" - layer.enabled: Theme.effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - brightness: SettingsData.launcherLogoBrightness - contrast: SettingsData.launcherLogoContrast - } - } - } - } - - onRightClicked: { - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml deleted file mode 100644 index 6007427..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml +++ /dev/null @@ -1,502 +0,0 @@ -import QtQuick -import Quickshell.Services.Mpris -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - readonly property MprisPlayer activePlayer: MprisController.activePlayer - readonly property bool playerAvailable: activePlayer !== null - readonly property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - property bool compactMode: false - property var widgetData: null - readonly property bool adaptiveWidthEnabled: SettingsData.mediaAdaptiveWidthEnabled - readonly property int maxTextWidth: { - const size = widgetData?.mediaSize !== undefined ? widgetData.mediaSize : SettingsData.mediaSize; - switch (size) { - case 0: - return 0; - case 2: - return 180; - case 3: - return 240; - default: - return 120; - } - } - readonly property int currentContentWidth: { - if (isVerticalOrientation) { - return widgetThickness - horizontalPadding * 2; - } - return 0; - } - readonly property int currentContentHeight: { - if (!isVerticalOrientation) { - return widgetThickness - horizontalPadding * 2; - } - const audioVizHeight = 20; - const playButtonHeight = 24; - return audioVizHeight + Theme.spacingXS + playButtonHeight; - } - - property real scrollAccumulatorY: 0 - property real touchpadThreshold: 100 - - onWheel: function (wheelEvent) { - if (SettingsData.audioScrollMode === "nothing") - return; - - if (SettingsData.audioScrollMode === "volume") { - if (!usePlayerVolume) - return; - - wheelEvent.accepted = true; - - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheelY = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - const currentVolume = activePlayer.volume * 100; - - let newVolume = currentVolume; - if (isMouseWheelY) { - if (deltaY > 0) { - newVolume = Math.min(100, currentVolume + SettingsData.audioWheelScrollAmount); - } else if (deltaY < 0) { - newVolume = Math.max(0, currentVolume - SettingsData.audioWheelScrollAmount); - } - } else { - scrollAccumulatorY += deltaY; - if (Math.abs(scrollAccumulatorY) >= touchpadThreshold) { - if (scrollAccumulatorY > 0) { - newVolume = Math.min(100, currentVolume + 1); - } else { - newVolume = Math.max(0, currentVolume - 1); - } - scrollAccumulatorY = 0; - } - } - - activePlayer.volume = newVolume / 100; - } else if (SettingsData.audioScrollMode === "song") { - if (!activePlayer) - return; - - wheelEvent.accepted = true; - - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheelY = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - if (isMouseWheelY) { - if (deltaY > 0) { - MprisController.previousOrRewind(); - } else { - activePlayer.next(); - } - } else { - scrollAccumulatorY += deltaY; - if (Math.abs(scrollAccumulatorY) >= touchpadThreshold) { - if (scrollAccumulatorY > 0) { - MprisController.previousOrRewind(); - } else { - activePlayer.next(); - } - scrollAccumulatorY = 0; - } - } - } - } - - content: Component { - Item { - id: contentRoot - readonly property real measuredTextWidth: { - if (!root.playerAvailable || root.maxTextWidth <= 0 || !textContainer.visible) - return 0; - // Preserve the fixed-width text slot even if metadata is briefly empty. - if (!root.adaptiveWidthEnabled) - return root.maxTextWidth; - if (textContainer.displayText.length === 0) - return 0; - const rawWidth = mediaText.contentWidth; - if (!isFinite(rawWidth) || rawWidth <= 0) - return 0; - return Math.min(root.maxTextWidth, Math.ceil(rawWidth)); - } - readonly property int horizontalContentWidth: { - const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20; - const audioVizWidth = 20; - const baseWidth = audioVizWidth + Theme.spacingXS + controlsWidth; - return baseWidth + (measuredTextWidth > 0 ? measuredTextWidth + Theme.spacingXS : 0); - } - - implicitWidth: root.playerAvailable ? (root.isVerticalOrientation ? root.currentContentWidth : horizontalContentWidth) : 0 - implicitHeight: root.playerAvailable ? root.currentContentHeight : 0 - opacity: root.playerAvailable ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on implicitWidth { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - Behavior on implicitHeight { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Column { - id: verticalLayout - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Item { - width: 20 - height: 20 - anchors.horizontalCenter: parent.horizontalCenter - - AudioVisualization { - anchors.fill: parent - visible: CavaService.cavaAvailable && SettingsData.audioVisualizerEnabled - } - - DankIcon { - anchors.fill: parent - name: "music_note" - size: 20 - color: Theme.primary - visible: !CavaService.cavaAvailable || !SettingsData.audioVisualizerEnabled - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { - const globalPos = parent.mapToItem(null, 0, 0); - const currentScreen = root.parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width, root.barSpacing, barPosition, root.barConfig); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.horizontalCenter: parent.horizontalCenter - color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover - visible: root.playerAvailable - opacity: activePlayer ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow" - size: 14 - color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - onClicked: mouse => { - if (!activePlayer) - return; - if (mouse.button === Qt.LeftButton) { - activePlayer.togglePlaying(); - } else if (mouse.button === Qt.MiddleButton) { - MprisController.previousOrRewind(); - } else if (mouse.button === Qt.RightButton) { - activePlayer.next(); - } - } - } - } - } - - Row { - id: mediaRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Row { - id: mediaInfo - spacing: Theme.spacingXS - - Item { - width: 20 - height: 20 - anchors.verticalCenter: parent.verticalCenter - - AudioVisualization { - anchors.fill: parent - visible: CavaService.cavaAvailable && SettingsData.audioVisualizerEnabled - } - - DankIcon { - anchors.fill: parent - name: "music_note" - size: 20 - color: Theme.primary - visible: !CavaService.cavaAvailable || !SettingsData.audioVisualizerEnabled - } - } - - Rectangle { - id: textContainer - readonly property string cachedIdentity: activePlayer ? (activePlayer.identity || "") : "" - readonly property string lowerIdentity: cachedIdentity.toLowerCase() - readonly property bool isWebMedia: lowerIdentity.includes("firefox") || lowerIdentity.includes("chrome") || lowerIdentity.includes("chromium") || lowerIdentity.includes("edge") || lowerIdentity.includes("safari") - - property string displayText: { - if (!activePlayer || !activePlayer.trackTitle) { - return ""; - } - - const title = isWebMedia ? activePlayer.trackTitle : (activePlayer.trackTitle || "Unknown Track"); - const subtitle = isWebMedia ? (activePlayer.trackArtist || cachedIdentity) : (activePlayer.trackArtist || ""); - return subtitle.length > 0 ? title + " • " + subtitle : title; - } - - anchors.verticalCenter: parent.verticalCenter - width: contentRoot.measuredTextWidth - height: root.widgetThickness - visible: { - const size = widgetData?.mediaSize !== undefined ? widgetData.mediaSize : SettingsData.mediaSize; - return size > 0; - } - clip: true - color: "transparent" - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - Item { - id: textClip - anchors.fill: parent - clip: true - - StyledText { - id: mediaText - property bool needsScrolling: implicitWidth > textContainer.width && SettingsData.scrollTitleEnabled - property real scrollOffset: 0 - property real textShift: 0 - - anchors.verticalCenter: parent.verticalCenter - text: textContainer.displayText - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - wrapMode: Text.NoWrap - x: (needsScrolling ? -scrollOffset : 0) + textShift - opacity: 1 - - onTextChanged: { - scrollOffset = 0; - textShift = 0; - scrollAnimation.restart(); - textChangeAnimation.restart(); - } - - SequentialAnimation { - id: scrollAnimation - running: mediaText.needsScrolling && textContainer.visible - loops: Animation.Infinite - - PauseAnimation { - duration: 2000 - } - - NumberAnimation { - target: mediaText - property: "scrollOffset" - from: 0 - to: mediaText.implicitWidth - textContainer.width + 5 - duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60) - easing.type: Easing.Linear - } - - PauseAnimation { - duration: 2000 - } - - NumberAnimation { - target: mediaText - property: "scrollOffset" - to: 0 - duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60) - easing.type: Easing.Linear - } - } - - SequentialAnimation { - id: textChangeAnimation - - ParallelAnimation { - NumberAnimation { - target: mediaText - property: "opacity" - from: 0.7 - to: 1 - duration: Theme.shortDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - - NumberAnimation { - target: mediaText - property: "textShift" - from: 4 - to: 0 - duration: Theme.shortDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - } - } - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = root.parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width, root.barSpacing, barPosition, root.barConfig); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } - } - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: prevArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - visible: root.playerAvailable - opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 12 - color: Theme.widgetTextColor - } - - MouseArea { - id: prevArea - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.verticalCenter: parent.verticalCenter - color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover - visible: root.playerAvailable - opacity: activePlayer ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow" - size: 14 - color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer) { - activePlayer.togglePlaying(); - } - } - } - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: nextArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - visible: playerAvailable - opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 12 - color: Theme.widgetTextColor - } - - MouseArea { - id: nextArea - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer) { - activePlayer.next(); - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml deleted file mode 100644 index b7d8436..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml +++ /dev/null @@ -1,147 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Modules.Plugins -import qs.Modules.ProcessList -import qs.Services -import qs.Widgets - -BasePill { - id: root - - function formatNetworkSpeed(bytesPerSec) { - if (bytesPerSec < 1024) { - return bytesPerSec.toFixed(0) + " B/s" - } else if (bytesPerSec < 1024 * 1024) { - return (bytesPerSec / 1024).toFixed(1) + " KB/s" - } else if (bytesPerSec < 1024 * 1024 * 1024) { - return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s" - } else { - return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s" - } - } - - Component.onCompleted: { - DgopService.addRef(["network"]) - } - Component.onDestruction: { - DgopService.removeRef(["network"]) - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : contentRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? contentColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: contentColumn - anchors.centerIn: parent - spacing: 2 - visible: root.isVerticalOrientation - - DankIcon { - name: "network_check" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const rate = DgopService.networkRxRate - if (rate < 1024) return rate.toFixed(0) - if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" - return (rate / (1024 * 1024)).toFixed(0) + "M" - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.info - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const rate = DgopService.networkTxRate - if (rate < 1024) return rate.toFixed(0) - if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" - return (rate / (1024 * 1024)).toFixed(0) + "M" - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !root.isVerticalOrientation - - DankIcon { - name: "network_check" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - StyledText { - text: "↓" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.info - } - - StyledText { - text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - wrapMode: Text.NoWrap - - StyledTextMetrics { - id: rxBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88.8 MB/s" - } - - width: Math.max(rxBaseline.width, paintedWidth) - } - } - - Row { - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - StyledText { - text: "↑" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.error - } - - StyledText { - text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - wrapMode: Text.NoWrap - - StyledTextMetrics { - id: txBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88.8 MB/s" - } - - width: Math.max(txBaseline.width, paintedWidth) - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml deleted file mode 100644 index 08f5e6b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml +++ /dev/null @@ -1,367 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - readonly property string focusedScreenName: (CompositorService.isHyprland && typeof Hyprland !== "undefined" && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor ? (Hyprland.focusedWorkspace.monitor.name || "") : CompositorService.isNiri && typeof NiriService !== "undefined" && NiriService.currentOutput ? NiriService.currentOutput : "") - - function resolveNotepadInstance() { - if (typeof notepadSlideoutVariants === "undefined" || !notepadSlideoutVariants || !notepadSlideoutVariants.instances) { - return null; - } - - const targetScreen = focusedScreenName; - if (targetScreen) { - for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) { - var slideout = notepadSlideoutVariants.instances[i]; - if (slideout.modelData && slideout.modelData.name === targetScreen) { - return slideout; - } - } - } - - return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null; - } - - readonly property var notepadInstance: resolveNotepadInstance() - readonly property bool isActive: notepadInstance?.isVisible ?? false - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !(axis?.isVertical ?? false)) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - - return 0; - } - - readonly property var savedTabEntries: { - const result = []; - const tabs = NotepadStorageService.tabs || []; - for (let i = 0; i < tabs.length; i++) { - const tab = tabs[i]; - if (tab && !tab.isTemporary) { - result.push({ - index: i, - tab: tab - }); - } - } - return result.slice(0, 5); - } - - function openTabByIndex(tabIndex) { - if (tabIndex < 0) - return; - if (root.notepadInstance && typeof root.notepadInstance.show === "function") { - root.notepadInstance.show(); - } - Qt.callLater(() => { - NotepadStorageService.switchToTab(tabIndex); - }); - } - - function openNewNote() { - if (root.notepadInstance && typeof root.notepadInstance.show === "function") { - root.notepadInstance.show(); - } - Qt.callLater(() => { - NotepadStorageService.createNewTab(); - }); - } - - function openContextMenu() { - const screen = root.parentScreen || Screen; - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const isVertical = root.axis?.isVertical ?? false; - const edge = root.axis?.edge ?? "top"; - const gap = Math.max(Theme.spacingXS, root.barSpacing ?? Theme.spacingXS); - - const globalPos = root.mapToGlobal(root.width / 2, root.height / 2); - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - let anchorX = relativeX; - let anchorY = relativeY; - - if (isVertical) { - anchorX = edge === "left" ? (root.barThickness + root.barSpacing + gap) : (screen.width - (root.barThickness + root.barSpacing + gap)); - anchorY = relativeY + root.minTooltipY; - } else { - anchorX = relativeX; - anchorY = edge === "bottom" ? (screen.height - (root.barThickness + root.barSpacing + gap)) : (root.barThickness + root.barSpacing + gap); - } - - contextMenuWindow.showAt(anchorX, anchorY, isVertical, edge, screen); - } - - content: Component { - Item { - implicitWidth: notepadIcon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: notepadIcon - - anchors.centerIn: parent - name: "assignment" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: root.isActive ? Theme.primary : Theme.surfaceText - } - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: function (mouse) { - if (mouse.button === Qt.RightButton) { - openContextMenu(); - return; - } - const inst = root.notepadInstance; - if (inst) { - inst.toggle(); - } - } - } - - PanelWindow { - id: contextMenuWindow - - WlrLayershell.namespace: "dms:notepad-context-menu" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, targetScreen) { - if (targetScreen) { - contextMenuWindow.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - visible = true; - - if (contextMenuWindow.screen) { - TrayMenuManager.registerMenu(contextMenuWindow.screen.name, contextMenuWindow); - } - } - - function closeMenu() { - visible = false; - - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.closeMenu(); - } - } - - MouseArea { - anchors.fill: parent - z: 0 - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: contextMenuWindow.closeMenu() - } - - Rectangle { - id: menuContainer - z: 1 - - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - y: { - if (contextMenuWindow.isVertical) { - const top = 10; - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } - if (contextMenuWindow.edge === "top") { - return Math.min(contextMenuWindow.height - height - 10, contextMenuWindow.anchorPos.y); - } - return Math.max(10, contextMenuWindow.anchorPos.y - height); - } - - width: Math.min(260, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - opacity: contextMenuWindow.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Repeater { - model: root.savedTabEntries - - Rectangle { - required property var modelData - - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: tabArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "description" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.tab?.title || I18n.tr("Saved Note") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - elide: Text.ElideRight - maximumLineCount: 1 - } - } - - MouseArea { - id: tabArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.openTabByIndex(modelData.index); - } - } - } - } - - Rectangle { - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: newNoteArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "add" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Open a new note") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: newNoteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.openNewNote(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml deleted file mode 100644 index d7bcc1e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml +++ /dev/null @@ -1,40 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool hasUnread: false - property bool isActive: false - - content: Component { - Item { - implicitWidth: notifIcon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: notifIcon - anchors.centerIn: parent - name: SessionData.doNotDisturb ? "notifications_off" : "notifications" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: SessionData.doNotDisturb ? Theme.primary : (root.isActive ? Theme.primary : Theme.widgetIconColor) - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: notifIcon.right - anchors.top: notifIcon.top - visible: root.hasUnread - } - } - } - - onRightClicked: { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml deleted file mode 100644 index da9caee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "power_settings_new" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml deleted file mode 100644 index a09aa55..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml +++ /dev/null @@ -1,247 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - section: "right" - - property bool showMicIcon: SettingsData.privacyShowMicIcon - property bool showCameraIcon: SettingsData.privacyShowCameraIcon - property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon - - readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive - readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive) - readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 - readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 - - opacity: hasActivePrivacy ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: !hasActivePrivacy && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: !hasActivePrivacy && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - content: Component { - Item { - implicitWidth: root.hasActivePrivacy ? root.contentWidth : 0 - implicitHeight: root.hasActivePrivacy ? root.contentHeight : 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: root.isVerticalOrientation && root.hasActivePrivacy - - Item { - width: 18 - height: 18 - visible: root.showMicIcon || PrivacyService.microphoneActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: { - const sourceAudio = AudioService.source?.audio; - const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0; - if (muted) - return "mic_off"; - return "mic"; - } - size: Theme.iconSizeSmall - color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.microphoneActive - anchors.centerIn: parent - } - } - - Item { - width: 18 - height: 18 - visible: root.showCameraIcon || PrivacyService.cameraActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "camera_video" - size: Theme.iconSizeSmall - color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.cameraActive - anchors.centerIn: parent - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: -2 - anchors.topMargin: -1 - visible: PrivacyService.cameraActive - } - } - - Item { - width: 18 - height: 18 - visible: root.showScreenSharingIcon || PrivacyService.screensharingActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "screen_share" - size: Theme.iconSizeSmall - color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText - filled: PrivacyService.screensharingActive - anchors.centerIn: parent - } - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: !root.isVerticalOrientation && root.hasActivePrivacy - - Item { - width: 18 - height: 18 - visible: root.showMicIcon || PrivacyService.microphoneActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - const sourceAudio = AudioService.source?.audio; - const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0; - if (muted) - return "mic_off"; - return "mic"; - } - size: Theme.iconSizeSmall - color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.microphoneActive - anchors.centerIn: parent - } - } - - Item { - width: 18 - height: 18 - visible: root.showCameraIcon || PrivacyService.cameraActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "camera_video" - size: Theme.iconSizeSmall - color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.cameraActive - anchors.centerIn: parent - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: -2 - anchors.topMargin: -1 - visible: PrivacyService.cameraActive - } - } - - Item { - width: 18 - height: 18 - visible: root.showScreenSharingIcon || PrivacyService.screensharingActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "screen_share" - size: Theme.iconSizeSmall - color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText - filled: PrivacyService.screensharingActive - anchors.centerIn: parent - } - } - } - } - } - - Rectangle { - id: tooltip - width: tooltipText.contentWidth + Theme.spacingM * 2 - height: tooltipText.contentHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Theme.outlineMedium - border.width: 1 - visible: false - opacity: root.isMouseHovered && hasActivePrivacy ? 1 : 0 - z: 100 - x: (parent.width - width) / 2 - y: -height - Theme.spacingXS - - StyledText { - id: tooltipText - anchors.centerIn: parent - text: PrivacyService.getPrivacySummary() - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - } - - Rectangle { - width: 8 - height: 8 - color: parent.color - border.color: parent.border.color - border.width: parent.border.width - rotation: 45 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.bottom - anchors.topMargin: -4 - } - - Behavior on opacity { - enabled: hasActivePrivacy && root.visible - - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml deleted file mode 100644 index f5d6de5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml +++ /dev/null @@ -1,175 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false - property bool showInGb: (widgetData && widgetData.showInGb !== undefined) ? widgetData.showInGb : false - readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0 - - signal ramClicked - - Component.onCompleted: { - DgopService.addRef(["memory"]); - } - Component.onDestruction: { - DgopService.removeRef(["memory"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? ramColumn.implicitHeight : ramContent.implicitHeight - - Column { - id: ramColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "developer_board" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.memoryUsage > 90) { - return Theme.tempDanger; - } - - if (DgopService.memoryUsage > 75) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) { - return "--"; - } - - if (root.showInGb) { - return (DgopService.usedMemoryMB / 1024).toFixed(1); - } - - return DgopService.memoryUsage.toFixed(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - visible: root.showSwap && DgopService.totalSwapKB > 0 - text: root.swapUsage.toFixed(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: ramContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: ramIcon - name: "developer_board" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.memoryUsage > 90) { - return Theme.tempDanger; - } - - if (DgopService.memoryUsage > 75) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(ramBaseline.width, ramText.paintedWidth) : ramText.paintedWidth - implicitHeight: ramText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: ramBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: { - let baseText = root.showInGb ? "88.8 GB" : "88%"; - if (!root.showSwap) { - return baseText; - } - if (root.swapUsage < 10) { - return baseText + " · 0%"; - } - return baseText + " · 88%"; - } - } - - StyledText { - id: ramText - text: { - if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) { - return root.showInGb ? "-- GB" : "--%"; - } - - let ramText = ""; - if (root.showInGb) { - ramText = (DgopService.usedMemoryMB / 1024).toFixed(1) + " GB"; - } else { - ramText = DgopService.memoryUsage.toFixed(0) + "%"; - } - - if (root.showSwap && DgopService.totalSwapKB > 0) { - return ramText + " · " + root.swapUsage.toFixed(0) + "%"; - } - return ramText; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - wrapMode: Text.NoWrap - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("memory"); - ramClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml deleted file mode 100644 index ae58802..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml +++ /dev/null @@ -1,902 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - section: "left" - - property var widgetData: null - property var hoveredItem: null - property var topBar: null - property bool isAutoHideBar: false - property Item windowRoot: (Window.window ? Window.window.contentItem : null) - - readonly property real effectiveBarThickness: { - if (barThickness > 0 && barSpacing > 0) { - return barThickness + barSpacing; - } - const innerPadding = barConfig?.innerPadding ?? 4; - const spacing = barConfig?.spacing ?? 4; - return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing; - } - - readonly property var barBounds: { - if (!parentScreen || !barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig); - } - - readonly property real barY: barBounds.y - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return effectiveBarThickness; - } - - return 0; - } - - property int _desktopEntriesUpdateTrigger: 0 - property int _toplevelsUpdateTrigger: 0 - property int _appIdSubstitutionsTrigger: 0 - - readonly property bool _currentWorkspace: widgetData?.runningAppsCurrentWorkspace !== undefined ? widgetData.runningAppsCurrentWorkspace : SettingsData.runningAppsCurrentWorkspace - readonly property bool _currentMonitor: widgetData?.runningAppsCurrentMonitor !== undefined ? widgetData.runningAppsCurrentMonitor : SettingsData.runningAppsCurrentMonitor - readonly property bool _groupByApp: widgetData?.runningAppsGroupByApp !== undefined ? widgetData.runningAppsGroupByApp : SettingsData.runningAppsGroupByApp - - readonly property var sortedToplevels: { - _toplevelsUpdateTrigger; - let toplevels = CompositorService.sortedToplevels; - if (!toplevels || toplevels.length === 0) - return []; - - if (_currentWorkspace) - toplevels = CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name) || []; - if (_currentMonitor) - toplevels = CompositorService.filterCurrentDisplay(toplevels, parentScreen?.name) || []; - return toplevels; - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - _toplevelsUpdateTrigger++; - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - _appIdSubstitutionsTrigger++; - } - } - readonly property var groupedWindows: { - if (!_groupByApp) { - return []; - } - try { - if (!sortedToplevels || sortedToplevels.length === 0) { - return []; - } - const appGroups = new Map(); - sortedToplevels.forEach((toplevel, index) => { - if (!toplevel) - return; - const appId = toplevel?.appId || "unknown"; - if (!appGroups.has(appId)) { - appGroups.set(appId, { - "appId": appId, - "windows": [] - }); - } - appGroups.get(appId).windows.push({ - "toplevel": toplevel, - "windowId": index, - "windowTitle": toplevel?.title || "(Unnamed)" - }); - }); - return Array.from(appGroups.values()); - } catch (e) { - return []; - } - } - readonly property int windowCount: _groupByApp ? (groupedWindows?.length || 0) : (sortedToplevels?.length || 0) - readonly property real iconCellSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - readonly property string focusedAppId: { - if (!sortedToplevels || sortedToplevels.length === 0) - return ""; - for (let i = 0; i < sortedToplevels.length; i++) { - if (sortedToplevels[i].activated) - return sortedToplevels[i].appId || ""; - } - return ""; - } - - visible: windowCount > 0 - - property real scrollAccumulator: 0 - property real touchpadThreshold: 500 - - onWheel: function (wheelEvent) { - wheelEvent.accepted = true; - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - const windows = root.sortedToplevels; - if (windows.length < 2) - return; - - if (isMouseWheel) { - let currentIndex = -1; - for (var i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - - let nextIndex; - if (deltaY < 0) { - nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1); - } else { - nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0); - } - - const nextWindow = windows[nextIndex]; - if (nextWindow) - nextWindow.activate(); - } else { - scrollAccumulator += deltaY; - - if (Math.abs(scrollAccumulator) >= touchpadThreshold) { - let currentIndex = -1; - for (var i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - - let nextIndex; - if (scrollAccumulator < 0) { - nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1); - } else { - nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0); - } - - const nextWindow = windows[nextIndex]; - if (nextWindow) - nextWindow.activate(); - - scrollAccumulator = 0; - } - } - } - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout - } - } - } - - Component { - id: rowLayout - Row { - spacing: Theme.spacingXS - - Repeater { - id: windowRepeater - model: ScriptModel { - values: _groupByApp ? groupedWindows : sortedToplevels - objectProp: _groupByApp ? "appId" : "address" - } - - delegate: Item { - id: delegateItem - - property bool isGrouped: root._groupByApp - property var groupData: isGrouped ? modelData : null - property var toplevelData: isGrouped ? (modelData.windows.length > 0 ? modelData.windows[0].toplevel : null) : modelData - property bool isFocused: isGrouped ? (root.focusedAppId === appId) : (toplevelData ? toplevelData.activated : false) - property string appId: isGrouped ? modelData.appId : (modelData.appId || "") - readonly property string effectiveAppId: { - root._appIdSubstitutionsTrigger; - return Paths.moddedAppId(appId); - } - property string windowTitle: toplevelData ? (toplevelData.title || "(Unnamed)") : "(Unnamed)" - property var toplevelObject: toplevelData - property int windowCount: isGrouped ? modelData.windows.length : 1 - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = effectiveAppId ? DesktopEntries.heuristicLookup(effectiveAppId) : null; - const appName = effectiveAppId ? Paths.getAppName(effectiveAppId, desktopEntry) : "Unknown"; - - if (isGrouped && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - readonly property real visualWidth: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120) - - width: visualWidth - height: root.barThickness - - Rectangle { - id: visualContent - width: delegateItem.visualWidth - height: root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - if (isFocused) { - return mouseArea.containsMouse ? Theme.primarySelected : Theme.withAlpha(Theme.primary, 0.45); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - // App icon - IconImage { - id: iconImg - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!effectiveAppId) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - return Paths.getAppIcon(effectiveAppId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready - layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && Paths.isSteamApp(effectiveAppId) - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !Paths.isSteamApp(effectiveAppId) - text: { - root._desktopEntriesUpdateTrigger; - if (!effectiveAppId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - const appName = Paths.getAppName(effectiveAppId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: isGrouped && windowCount > 1 - z: 10 - - StyledText { - anchors.centerIn: parent - text: windowCount > 9 ? "9+" : windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - visible: !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - text: windowTitle - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - if (isGrouped && windowCount > 1) { - let currentIndex = -1; - for (var i = 0; i < groupData.windows.length; i++) { - if (groupData.windows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % groupData.windows.length; - groupData.windows[nextIndex].toplevel.activate(); - } else if (toplevelObject) { - toplevelObject.activate(); - } - } else if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - - windowContextMenuLoader.active = true; - if (windowContextMenuLoader.item) { - windowContextMenuLoader.item.currentWindow = toplevelObject; - // Pass bar context - windowContextMenuLoader.item.triggerBarConfig = root.barConfig; - windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1)); - windowContextMenuLoader.item.triggerBarThickness = root.barThickness; - windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing; - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const relativeX = globalPos.x - screenX; - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS); - windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge); - } - } - } else if (mouse.button === Qt.MiddleButton) { - if (toplevelObject) { - if (typeof toplevelObject.close === "function") { - toplevelObject.close(); - } - } - } - } - onEntered: { - root.hoveredItem = delegateItem; - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - const adjustedY = relativeY + root.minTooltipY; - const finalX = screenX + tooltipX; - tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - - tooltipLoader.active = false; - } - } - } - } - } - } - } - - Component { - id: columnLayout - Column { - spacing: Theme.spacingXS - - Repeater { - id: windowRepeater - model: ScriptModel { - values: _groupByApp ? groupedWindows : sortedToplevels - objectProp: _groupByApp ? "appId" : "address" - } - - delegate: Item { - id: delegateItem - - property bool isGrouped: root._groupByApp - property var groupData: isGrouped ? modelData : null - property var toplevelData: isGrouped ? (modelData.windows.length > 0 ? modelData.windows[0].toplevel : null) : modelData - property bool isFocused: isGrouped ? (root.focusedAppId === appId) : (toplevelData ? toplevelData.activated : false) - property string appId: isGrouped ? modelData.appId : (modelData.appId || "") - readonly property string effectiveAppId: { - root._appIdSubstitutionsTrigger; - return Paths.moddedAppId(appId); - } - property string windowTitle: toplevelData ? (toplevelData.title || "(Unnamed)") : "(Unnamed)" - property var toplevelObject: toplevelData - property int windowCount: isGrouped ? modelData.windows.length : 1 - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = effectiveAppId ? DesktopEntries.heuristicLookup(effectiveAppId) : null; - const appName = effectiveAppId ? Paths.getAppName(effectiveAppId, desktopEntry) : "Unknown"; - - if (isGrouped && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - readonly property real visualWidth: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120) - - width: root.barThickness - height: root.iconCellSize - - Rectangle { - id: visualContent - width: delegateItem.visualWidth - height: root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - if (isFocused) { - return mouseArea.containsMouse ? Theme.primarySelected : Theme.withAlpha(Theme.primary, 0.45); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - IconImage { - id: iconImg - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!effectiveAppId) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - return Paths.getAppIcon(effectiveAppId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready - layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && Paths.isSteamApp(effectiveAppId) - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !Paths.isSteamApp(effectiveAppId) - text: { - root._desktopEntriesUpdateTrigger; - if (!effectiveAppId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - const appName = Paths.getAppName(effectiveAppId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: isGrouped && windowCount > 1 - z: 10 - - StyledText { - anchors.centerIn: parent - text: windowCount > 9 ? "9+" : windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - visible: !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - text: windowTitle - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - if (isGrouped && windowCount > 1) { - let currentIndex = -1; - for (var i = 0; i < groupData.windows.length; i++) { - if (groupData.windows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % groupData.windows.length; - groupData.windows[nextIndex].toplevel.activate(); - } else if (toplevelObject) { - toplevelObject.activate(); - } - } else if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - - windowContextMenuLoader.active = true; - if (windowContextMenuLoader.item) { - windowContextMenuLoader.item.currentWindow = toplevelObject; - // Pass bar context - windowContextMenuLoader.item.triggerBarConfig = root.barConfig; - windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1)); - windowContextMenuLoader.item.triggerBarThickness = root.barThickness; - windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing; - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const relativeX = globalPos.x - screenX; - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS); - windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge); - } - } - } - } - onEntered: { - root.hoveredItem = delegateItem; - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - const adjustedY = relativeY + root.minTooltipY; - const finalX = screenX + tooltipX; - tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - - tooltipLoader.active = false; - } - } - } - } - } - } - } - - Loader { - id: tooltipLoader - - active: false - - sourceComponent: DankTooltip {} - } - - Loader { - id: windowContextMenuLoader - active: false - sourceComponent: PanelWindow { - id: contextMenuWindow - - WindowBlur { - targetWindow: contextMenuWindow - blurX: contextMenuRect.x - blurY: contextMenuRect.y - blurWidth: contextMenuWindow.isVisible ? contextMenuRect.width : 0 - blurHeight: contextMenuWindow.isVisible ? contextMenuRect.height : 0 - blurRadius: Theme.cornerRadius - } - - property var currentWindow: null - property bool isVisible: false - property point anchorPos: Qt.point(0, 0) - property bool isVertical: false - property string edge: "top" - - // New properties for bar context - property int triggerBarPosition: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) - property real triggerBarThickness: 0 - property real triggerBarSpacing: 0 - property var triggerBarConfig: null - - readonly property real effectiveBarThickness: { - if (triggerBarThickness > 0 && triggerBarSpacing > 0) { - return triggerBarThickness + triggerBarSpacing; - } - return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4); - } - - property var barBounds: { - if (!contextMenuWindow.screen || !triggerBarConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig); - } - - property real barY: barBounds.y - - function showAt(x, y, vertical, barEdge) { - screen = root.parentScreen; - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - isVisible = true; - visible = true; - - if (screen) { - TrayMenuManager.registerMenu(screen.name, contextMenuWindow); - } - } - - function close() { - isVisible = false; - visible = false; - windowContextMenuLoader.active = false; - - if (screen) { - TrayMenuManager.unregisterMenu(screen.name); - } - } - - implicitWidth: 100 - implicitHeight: 40 - visible: false - color: "transparent" - - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (screen) { - TrayMenuManager.unregisterMenu(screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.close(); - } - } - - MouseArea { - anchors.fill: parent - onClicked: contextMenuWindow.close() - } - - Rectangle { - id: contextMenuRect - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } else { - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - } else { - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - if (contextMenuWindow.isVertical) { - const top = Math.max(barY, 10); - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - return contextMenuWindow.anchorPos.y; - } - } - width: 100 - height: 32 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: closeMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - } - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.widgetTextColor - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (contextMenuWindow.currentWindow) { - contextMenuWindow.currentWindow.close(); - } - contextMenuWindow.close(); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml deleted file mode 100644 index 7fb9362..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml +++ /dev/null @@ -1,1893 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.Services.SystemTray -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - - property var parentWindow: null - property var widgetData: null - property string section: "right" - property bool isAtBottom: false - property bool isAutoHideBar: false - property bool useOverflowPopup: !widgetData?.trayUseInlineExpansion - readonly property var hiddenTrayIds: { - const envValue = Quickshell.env("DMS_HIDE_TRAYIDS") || ""; - return envValue ? envValue.split(",").map(id => id.trim().toLowerCase()) : []; - } - readonly property var allTrayItems: { - if (!hiddenTrayIds.length) { - return SystemTray.items.values; - } - return SystemTray.items.values.filter(item => { - const itemId = item?.id || ""; - return !hiddenTrayIds.includes(itemId.toLowerCase()); - }); - } - function getTrayItemKey(item) { - const id = item?.id || ""; - const tooltipTitle = item?.tooltipTitle || ""; - if (!tooltipTitle || tooltipTitle === id) { - return id; - } - return `${id}::${tooltipTitle}`; - } - - function trayIconSourceFor(trayItem) { - let icon = trayItem && trayItem.icon; - if (typeof icon === 'string' || icon instanceof String) { - if (icon === "") - return ""; - if (icon.includes("?path=")) { - const split = icon.split("?path="); - if (split.length !== 2) - return icon; - const name = split[0]; - const path = split[1]; - let fileName = name.substring(name.lastIndexOf("/") + 1); - if (fileName.startsWith("dropboxstatus")) { - fileName = `hicolor/16x16/status/${fileName}`; - } - return `file://${path}/${fileName}`; - } - if (icon.startsWith("/") && !icon.startsWith("file://")) - return `file://${icon}`; - return icon; - } - return ""; - } - - function activateInlineTrayItem(trayItem, anchorItem) { - if (!trayItem) - return; - if (!trayItem.onlyMenu) { - trayItem.activate(); - return; - } - if (!trayItem.hasMenu) - return; - root.showForTrayItem(trayItem, anchorItem, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - function openInlineTrayContextMenu(trayItem, areaItem, mouse, anchorItem) { - if (!trayItem) { - return; - } - if (!trayItem.hasMenu) { - const gp = areaItem.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - root.showForTrayItem(trayItem, anchorItem, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - function toggleIconName() { - const edge = root.axis?.edge; - if (root.useOverflowPopup) { - switch (edge) { - case "left": - return root.menuOpen ? "keyboard_arrow_left" : "keyboard_arrow_right"; - case "right": - return root.menuOpen ? "keyboard_arrow_right" : "keyboard_arrow_left"; - case "bottom": - return root.menuOpen ? "keyboard_arrow_down" : "keyboard_arrow_up"; - case "top": - return root.menuOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"; - } - } - - if (edge === "left" || edge === "right") { - return root.menuOpen == (root.section !== "right") ? "keyboard_arrow_up" : "keyboard_arrow_down"; - } - - return root.menuOpen != (root.section === "right") ? "keyboard_arrow_left" : "keyboard_arrow_right"; - } - - // ! TODO - replace with either native dbus client (like plugins use) or just a DMS cli or something - function callContextMenuFallback(trayItemId, globalX, globalY) { - const script = ['ITEMS=$(dbus-send --session --print-reply --dest=org.kde.StatusNotifierWatcher /StatusNotifierWatcher org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierWatcher string:RegisteredStatusNotifierItems 2>/dev/null)', 'while IFS= read -r line; do', ' line="${line#*\\\"}"', ' line="${line%\\\"*}"', ' [ -z "$line" ] && continue', ' BUS="${line%%/*}"', ' OBJ="/${line#*/}"', ' ID=$(dbus-send --session --print-reply --dest="$BUS" "$OBJ" org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierItem string:Id 2>/dev/null | grep -oP "(?<=\\\")(.*?)(?=\\\")" | tail -1)', ' if [ "$ID" = "$1" ]; then', ' dbus-send --session --type=method_call --dest="$BUS" "$OBJ" org.kde.StatusNotifierItem.ContextMenu int32:"$2" int32:"$3"', ' exit 0', ' fi', 'done <<< "$ITEMS"',].join("\n"); - Quickshell.execDetached(["bash", "-c", script, "_", trayItemId, String(globalX), String(globalY)]); - } - - property int _trayOrderTrigger: 0 - - Connections { - target: SessionData - function onTrayItemOrderChanged() { - root._trayOrderTrigger++; - } - } - - function sortByPreferredOrder(items, trigger) { - void trigger; - const savedOrder = SessionData.trayItemOrder || []; - const orderMap = new Map(); - savedOrder.forEach((key, idx) => orderMap.set(key, idx)); - - return [...items].sort((a, b) => { - const keyA = getTrayItemKey(a); - const keyB = getTrayItemKey(b); - const orderA = orderMap.has(keyA) ? orderMap.get(keyA) : 10000 + items.indexOf(a); - const orderB = orderMap.has(keyB) ? orderMap.get(keyB) : 10000 + items.indexOf(b); - return orderA - orderB; - }); - } - - readonly property var allSortedTrayItems: sortByPreferredOrder(allTrayItems, _trayOrderTrigger) - readonly property var allSortedTrayItemKeys: allSortedTrayItems.map(item => getTrayItemKey(item)) - readonly property var mainBarItemsRaw: allSortedTrayItems.filter(item => !SessionData.isHiddenTrayId(root.getTrayItemKey(item))) - readonly property var mainBarItems: mainBarItemsRaw.map((item, idx) => ({ - key: getTrayItemKey(item), - item: item - })) - readonly property var hiddenBarItems: allSortedTrayItems.filter(item => SessionData.isHiddenTrayId(root.getTrayItemKey(item))) - readonly property bool reverseInlineHorizontal: !useOverflowPopup && !isVerticalOrientation && section === "right" - readonly property bool reverseInlineVertical: !useOverflowPopup && isVerticalOrientation && section === "right" - readonly property var displayedMainBarItems: reverseInlineHorizontal ? [...mainBarItems].reverse() : mainBarItems - readonly property var displayedInlineExpandedItems: (reverseInlineHorizontal ? [...hiddenBarItems].reverse() : hiddenBarItems).map(item => ({ - key: getTrayItemKey(item), - item: item - })) - - function moveTrayItemInFullOrder(visibleFromIndex, visibleToIndex) { - if (visibleFromIndex === visibleToIndex || visibleFromIndex < 0 || visibleToIndex < 0) - return; - - const fromKey = mainBarItems[visibleFromIndex]?.key ?? null; - const toKey = mainBarItems[visibleToIndex]?.key ?? null; - if (!fromKey || !toKey) - return; - - const fullOrder = [...allSortedTrayItemKeys]; - const fullFromIndex = fullOrder.indexOf(fromKey); - const fullToIndex = fullOrder.indexOf(toKey); - if (fullFromIndex < 0 || fullToIndex < 0) - return; - - const movedKey = fullOrder.splice(fullFromIndex, 1)[0]; - fullOrder.splice(fullToIndex, 0, movedKey); - SessionData.setTrayItemOrder(fullOrder); - } - - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - readonly property bool hasHiddenItems: allTrayItems.length > mainBarItems.length - readonly property bool inlineExpanded: hasHiddenItems && !useOverflowPopup && menuOpen - visible: allTrayItems.length > 0 - opacity: allTrayItems.length > 0 ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: allTrayItems.length === 0 && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: allTrayItems.length === 0 && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - readonly property real trayItemSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - const estimatedTopBarHeight = barThickness + barSpacing; - return estimatedTopBarHeight; - } - - return 0; - } - - readonly property string autoBarShadowDirection: { - const edge = root.axis?.edge; - switch (edge) { - case "top": - return "top"; - case "bottom": - return "bottom"; - case "left": - return "left"; - case "right": - return "right"; - default: - return "bottom"; - } - } - readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection - - property bool menuOpen: false - property var currentTrayMenu: null - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnComp : rowComp - } - } - } - - Component { - id: rowComp - Row { - spacing: 0 - layoutDirection: root.reverseInlineHorizontal ? Qt.RightToLeft : Qt.LeftToRight - - Repeater { - model: ScriptModel { - values: root.displayedMainBarItems - objectProp: "key" - } - - delegate: Item { - id: delegateRoot - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.trayItemSize - height: root.barThickness - z: dragHandler.dragging ? 100 : 0 - - property real shiftOffset: { - if (root.draggedIndex < 0) - return 0; - if (index === root.draggedIndex) - return 0; - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const shiftAmount = root.trayItemSize; - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: delegateRoot.shiftOffset - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 400 - repeat: false - onTriggered: dragHandler.longPressing = true - } - } - - Rectangle { - id: visualContent - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: trayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - transform: Translate { - x: dragHandler.dragging ? dragHandler.dragAxisOffset : 0 - } - - IconImage { - id: iconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: delegateRoot.iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: trayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - if (mouse.button === Qt.LeftButton) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.suppressShiftAnimation = true; - root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (!delegateRoot.trayItem) - return; - if (!delegateRoot.trayItem.onlyMenu) { - delegateRoot.trayItem.activate(); - return; - } - if (!delegateRoot.trayItem.hasMenu) - return; - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.abs(mouse.x - dragHandler.dragStartPos.x); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - index) : index; - root.dropTargetIndex = root.draggedIndex; - } - } - if (!dragHandler.dragging) - return; - - const axisOffset = mouse.x - dragHandler.dragStartPos.x; - dragHandler.dragAxisOffset = axisOffset; - const itemSize = root.trayItemSize; - const slotOffset = Math.round(axisOffset / itemSize); - const visualTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset)); - const newTargetIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - visualTargetIndex) : visualTargetIndex; - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onClicked: mouse => { - if (dragHandler.dragging) - return; - if (mouse.button !== Qt.RightButton) - return; - if (!delegateRoot.trayItem?.hasMenu) { - const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - } - } - } - - Item { - width: root.trayItemSize - height: root.barThickness - visible: root.hasHiddenItems - - Rectangle { - id: caretButton - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: caretArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: root.toggleIconName() - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - - DankRipple { - id: caretRipple - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: caretArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - caretRipple.trigger(mouse.x, mouse.y); - } - onClicked: root.menuOpen = !root.menuOpen - } - } - } - - Repeater { - model: ScriptModel { - values: root.displayedInlineExpandedItems - objectProp: "key" - } - - delegate: inlineExpandedTrayItemDelegate - } - } - } - - Component { - id: inlineExpandedTrayItemDelegate - - Item { - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.isVerticalOrientation ? root.barThickness : (root.inlineExpanded ? root.trayItemSize : 0) - height: root.isVerticalOrientation ? (root.inlineExpanded ? root.trayItemSize : 0) : root.barThickness - visible: width > 0 || height > 0 - - Behavior on width { - enabled: !root.isVerticalOrientation - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: root.isVerticalOrientation - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Rectangle { - id: inlineVisualContent - width: root.trayItemSize - height: root.trayItemSize - x: root.isVerticalOrientation ? Math.round((parent.width - width) / 2) : (root.reverseInlineHorizontal ? parent.width - width : 0) - y: root.isVerticalOrientation ? (root.reverseInlineVertical ? parent.height - height : 0) : Math.round((parent.height - height) / 2) - radius: Theme.cornerRadius - color: inlineTrayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - opacity: root.inlineExpanded ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - IconImage { - id: inlineIconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !inlineIconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: inlineItemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: inlineTrayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - enabled: root.inlineExpanded - - onPressed: mouse => { - const pos = mapToItem(inlineVisualContent, mouse.x, mouse.y); - inlineItemRipple.trigger(pos.x, pos.y); - } - - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - root.activateInlineTrayItem(trayItem, inlineVisualContent); - return; - } - if (mouse.button !== Qt.RightButton) - return; - root.openInlineTrayContextMenu(trayItem, inlineTrayItemArea, mouse, inlineVisualContent); - } - } - } - } - - Component { - id: verticalMainTrayItemDelegate - - Item { - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.barThickness - height: root.trayItemSize - z: dragHandler.dragging ? 100 : 0 - - property real shiftOffset: { - if (root.draggedIndex < 0) - return 0; - if (index === root.draggedIndex) - return 0; - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const shiftAmount = root.trayItemSize; - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - y: shiftOffset - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 400 - repeat: false - onTriggered: dragHandler.longPressing = true - } - } - - Rectangle { - id: visualContent - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: trayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - transform: Translate { - y: dragHandler.dragging ? dragHandler.dragAxisOffset : 0 - } - - IconImage { - id: iconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: trayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - if (mouse.button === Qt.LeftButton) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.suppressShiftAnimation = true; - root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (!trayItem) - return; - if (!trayItem.onlyMenu) { - trayItem.activate(); - return; - } - if (!trayItem.hasMenu) - return; - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.abs(mouse.y - dragHandler.dragStartPos.y); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = index; - root.dropTargetIndex = root.draggedIndex; - } - } - if (!dragHandler.dragging) - return; - - const axisOffset = mouse.y - dragHandler.dragStartPos.y; - dragHandler.dragAxisOffset = axisOffset; - const itemSize = root.trayItemSize; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset)); - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onClicked: mouse => { - if (dragHandler.dragging) - return; - if (mouse.button !== Qt.RightButton) - return; - root.openInlineTrayContextMenu(trayItem, trayItemArea, mouse, visualContent); - } - } - } - } - - Component { - id: columnComp - Column { - spacing: 0 - - // Column lacks layoutDirection, so we use four repeaters with mutually exclusive models to control whether main items or expanded items appear above/ below the toggle button. - // When reverseInlineVertical is true the first and third repeaters are empty and the second and fourth are active, and vice-versa. - // Because items are swapped between repeaters rather than reversed within a single list, vertical drag-and-drop indices don't need remapping (unlike the horizontal RightToLeft case). - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? [] : root.displayedMainBarItems - objectProp: "key" - } - delegate: verticalMainTrayItemDelegate - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? root.displayedInlineExpandedItems : [] - objectProp: "key" - } - delegate: inlineExpandedTrayItemDelegate - } - - Item { - width: root.barThickness - height: root.trayItemSize - visible: root.hasHiddenItems - - Rectangle { - id: caretButtonVert - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: caretAreaVert.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: root.toggleIconName() - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - - DankRipple { - id: caretRippleVert - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: caretAreaVert - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - caretRippleVert.trigger(mouse.x, mouse.y); - } - onClicked: root.menuOpen = !root.menuOpen - } - } - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? [] : root.displayedInlineExpandedItems - objectProp: "key" - } - delegate: inlineExpandedTrayItemDelegate - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? root.displayedMainBarItems : [] - objectProp: "key" - } - delegate: verticalMainTrayItemDelegate - } - } - } - - PanelWindow { - id: overflowMenu - - WindowBlur { - targetWindow: overflowMenu - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: root.menuOpen ? menuContainer.width : 0 - blurHeight: root.menuOpen ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - visible: root.useOverflowPopup && root.menuOpen - screen: root.parentScreen - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!root.menuOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - WlrLayershell.namespace: "dms:tray-overflow-menu" - color: "transparent" - - HyprlandFocusGrab { - windows: [overflowMenu] - active: CompositorService.useHyprlandFocusGrab && root.useOverflowPopup && root.menuOpen - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - if (root.useOverflowPopup) - root.menuOpen = false; - } - } - - Component.onDestruction: { - if (root.parentScreen) { - TrayMenuManager.unregisterMenu(root.parentScreen.name); - } - } - - function close() { - root.menuOpen = false; - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale) ? CompositorService.getScreenScale(overflowMenu.screen) : (screen?.devicePixelRatio || 1) - property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) - - property var barBounds: { - if (!overflowMenu.screen || !root.barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(overflowMenu.screen, root.barThickness + root.barSpacing, barPosition, root.barConfig); - } - - property real barX: barBounds.x - property real barY: barBounds.y - property real barWidth: barBounds.width - property real barHeight: barBounds.height - - readonly property int barPosition: root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)) - readonly property var adjacentBarInfo: parentScreen ? SettingsData.getAdjacentBarInfo(parentScreen, barPosition, root.barConfig) : ({ - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }) - readonly property real effectiveBarSize: root.barThickness + root.barSpacing - - readonly property real maskX: { - const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0; - const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0; - return Math.max(triggeringBarX, adjacentLeftBar); - } - - readonly property real maskY: { - const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0; - const adjacentTopBar = adjacentBarInfo?.topBar ?? 0; - return Math.max(triggeringBarY, adjacentTopBar); - } - - readonly property real maskWidth: { - const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0; - const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0; - const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar); - return Math.max(100, width - maskX - rightExclusion); - } - - readonly property real maskHeight: { - const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0; - const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0; - const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar); - return Math.max(100, height - maskY - bottomExclusion); - } - - mask: Region { - item: Rectangle { - x: overflowMenu.maskX - y: overflowMenu.maskY - width: overflowMenu.maskWidth - height: overflowMenu.maskHeight - } - } - - onVisibleChanged: { - if (visible) { - if (currentTrayMenu) { - currentTrayMenu.showMenu = false; - } - if (root.parentScreen) { - TrayMenuManager.registerMenu(root.parentScreen.name, overflowMenu); - } - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - updatePosition(); - } else if (!visible && root.parentScreen) { - TrayMenuManager.unregisterMenu(root.parentScreen.name); - } - } - - MouseArea { - x: overflowMenu.maskX - y: overflowMenu.maskY - width: overflowMenu.maskWidth - height: overflowMenu.maskHeight - z: -1 - enabled: root.menuOpen - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: mouse => { - const clickX = mouse.x + overflowMenu.maskX; - const clickY = mouse.y + overflowMenu.maskY; - const outsideContent = clickX < menuContainer.x || clickX > menuContainer.x + menuContainer.width || clickY < menuContainer.y || clickY > menuContainer.y + menuContainer.height; - - if (!outsideContent) - return; - root.menuOpen = false; - } - } - - FocusScope { - id: overflowFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: { - root.menuOpen = false; - } - } - - function updatePosition() { - const globalPos = root.mapToGlobal(0, 0); - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - if (root.isVerticalOrientation) { - const edge = root.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const adjustedY = relativeY + root.height / 2 + root.minTooltipY; - anchorPos = Qt.point(targetX, adjustedY); - } else { - let targetY = root.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(relativeX + root.width / 2, targetY); - } - } - - Item { - id: menuContainer - objectName: "overflowMenuContainer" - - readonly property real rawWidth: { - const itemCount = root.hiddenBarItems.length; - const cols = Math.min(5, itemCount); - const itemSize = root.trayItemSize + 4; - const spacing = 2; - return cols * itemSize + (cols - 1) * spacing + Theme.spacingS * 2; - } - readonly property real rawHeight: { - const itemCount = root.hiddenBarItems.length; - const cols = Math.min(5, itemCount); - const rows = Math.ceil(itemCount / cols); - const itemSize = root.trayItemSize + 4; - const spacing = 2; - return rows * itemSize + (rows - 1) * spacing + Theme.spacingS * 2; - } - - readonly property real alignedWidth: Theme.px(rawWidth, overflowMenu.dpr) - readonly property real alignedHeight: Theme.px(rawHeight, overflowMenu.dpr) - - width: alignedWidth - height: alignedHeight - - x: Theme.snap((() => { - if (root.isVerticalOrientation) { - const edge = root.axis?.edge; - if (edge === "left") { - const targetX = overflowMenu.anchorPos.x; - return Math.min(overflowMenu.screen.width - alignedWidth - 10, targetX); - } else { - const targetX = overflowMenu.anchorPos.x - alignedWidth; - return Math.max(10, targetX); - } - } else { - const left = 10; - const right = overflowMenu.width - alignedWidth - 10; - const want = overflowMenu.anchorPos.x - alignedWidth / 2; - return Math.max(left, Math.min(right, want)); - } - })(), overflowMenu.dpr) - - y: Theme.snap((() => { - if (root.isVerticalOrientation) { - const top = Math.max(overflowMenu.barY, 10); - const bottom = overflowMenu.height - alignedHeight - 10; - const want = overflowMenu.anchorPos.y - alignedHeight / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (root.isAtBottom) { - const targetY = overflowMenu.anchorPos.y - alignedHeight; - return Math.max(10, targetY); - } else { - const targetY = overflowMenu.anchorPos.y; - return Math.min(overflowMenu.screen.height - alignedHeight - 10, targetY); - } - } - })(), overflowMenu.dpr) - - opacity: root.menuOpen ? 1 : 0 - scale: root.menuOpen ? 1 : 0.85 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - ElevationShadow { - id: bgShadowLayer - anchors.fill: parent - level: Theme.elevationLevel3 - direction: root.effectiveShadowDirection - fallbackOffset: 6 - targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - targetRadius: Theme.cornerRadius - sourceRect.antialiasing: true - sourceRect.smooth: true - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - layer.smooth: true - layer.textureSize: Qt.size(Math.round(width * overflowMenu.dpr * 2), Math.round(height * overflowMenu.dpr * 2)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - layer.samples: 4 - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - Grid { - id: menuGrid - anchors.centerIn: parent - columns: Math.min(5, root.hiddenBarItems.length) - spacing: 2 - rowSpacing: 2 - - Repeater { - model: root.hiddenBarItems - - delegate: Rectangle { - property var trayItem: modelData - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.trayItemSize + 4 - height: root.trayItemSize + 4 - radius: Theme.cornerRadius - color: itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - IconImage { - id: menuIconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: parent.iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !menuIconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - onClicked: mouse => { - if (!trayItem) - return; - if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) { - trayItem.activate(); - root.menuOpen = false; - return; - } - if (!trayItem.hasMenu) { - const gp = itemArea.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - } - } - } - } - } - } - - Component { - id: trayMenuComponent - - Rectangle { - id: menuRoot - - property var trayItem: null - property var anchorItem: null - property var parentScreen: null - property bool isAtBottom: false - property bool isVertical: false - property var axis: null - property bool showMenu: false - property var menuHandle: null - - ListModel { - id: entryStack - } - function topEntry() { - return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null; - } - - function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) { - trayItem = item; - anchorItem = anchor; - parentScreen = screen; - isAtBottom = atBottom; - isVertical = vertical; - axis = axisObj; - menuHandle = item?.menu; - - if (parentScreen) { - for (var i = 0; i < Quickshell.screens.length; i++) { - const s = Quickshell.screens[i]; - if (s === parentScreen) { - menuWindow.screen = s; - break; - } - } - } - - showMenu = true; - } - - function close() { - showMenu = false; - } - - Connections { - target: menuWindow - function onVisibleChanged() { - if (menuWindow.visible && parentScreen) { - TrayMenuManager.registerMenu(parentScreen.name, menuRoot); - } else if (!menuWindow.visible && parentScreen) { - TrayMenuManager.unregisterMenu(parentScreen.name); - } - } - } - - Component.onDestruction: { - if (parentScreen) { - TrayMenuManager.unregisterMenu(parentScreen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - menuRoot.close(); - } - } - - function closeWithAction() { - close(); - } - - function showSubMenu(entry) { - if (!entry || !entry.hasChildren) - return; - - entryStack.append({ - handle: entry - }); - - const h = entry.menu || entry; - if (h && typeof h.updateLayout === "function") - h.updateLayout(); - - submenuHydrator.menu = h; - submenuHydrator.open(); - Qt.callLater(() => submenuHydrator.close()); - } - - function goBack() { - if (!entryStack.count) - return; - entryStack.remove(entryStack.count - 1); - } - - width: 0 - height: 0 - color: "transparent" - - PanelWindow { - id: menuWindow - - WindowBlur { - targetWindow: menuWindow - blurX: trayMenuContainer.x - blurY: trayMenuContainer.y - blurWidth: menuRoot.showMenu ? trayMenuContainer.width : 0 - blurHeight: menuRoot.showMenu ? trayMenuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:tray-menu-window" - visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false) - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!menuRoot.showMenu) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - color: "transparent" - - HyprlandFocusGrab { - windows: [menuWindow] - active: CompositorService.useHyprlandFocusGrab && menuRoot.showMenu - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale) ? CompositorService.getScreenScale(menuWindow.screen) : (screen?.devicePixelRatio || 1) - property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) - - property var barBounds: { - if (!menuWindow.screen || !root.barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(menuWindow.screen, root.barThickness + root.barSpacing, barPosition, root.barConfig); - } - - property real barX: barBounds.x - property real barY: barBounds.y - property real barWidth: barBounds.width - property real barHeight: barBounds.height - - readonly property int barPosition: root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)) - readonly property var adjacentBarInfo: menuRoot.parentScreen ? SettingsData.getAdjacentBarInfo(menuRoot.parentScreen, barPosition, root.barConfig) : ({ - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }) - readonly property real effectiveBarSize: root.barThickness + root.barSpacing - - readonly property real maskX: { - const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0; - const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0; - return Math.max(triggeringBarX, adjacentLeftBar); - } - - readonly property real maskY: { - const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0; - const adjacentTopBar = adjacentBarInfo?.topBar ?? 0; - return Math.max(triggeringBarY, adjacentTopBar); - } - - readonly property real maskWidth: { - const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0; - const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0; - const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar); - return Math.max(100, width - maskX - rightExclusion); - } - - readonly property real maskHeight: { - const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0; - const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0; - const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar); - return Math.max(100, height - maskY - bottomExclusion); - } - - mask: Region { - item: Rectangle { - x: menuWindow.maskX - y: menuWindow.maskY - width: menuWindow.maskWidth - height: menuWindow.maskHeight - } - } - - onVisibleChanged: { - if (visible) { - updatePosition(); - if (root.useOverflowPopup) - root.menuOpen = false; - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - } - } - - MouseArea { - x: menuWindow.maskX - y: menuWindow.maskY - width: menuWindow.maskWidth - height: menuWindow.maskHeight - z: -1 - enabled: menuRoot.showMenu - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: mouse => { - const clickX = mouse.x + menuWindow.maskX; - const clickY = mouse.y + menuWindow.maskY; - const outsideContent = clickX < trayMenuContainer.x || clickX > trayMenuContainer.x + trayMenuContainer.width || clickY < trayMenuContainer.y || clickY > trayMenuContainer.y + trayMenuContainer.height; - - if (!outsideContent) - return; - menuRoot.close(); - } - } - - FocusScope { - id: menuFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: { - if (entryStack.count > 0) { - menuRoot.goBack(); - } else { - menuRoot.close(); - } - } - } - - function updatePosition() { - const targetItem = (typeof menuRoot !== "undefined" && menuRoot.anchorItem) ? menuRoot.anchorItem : root; - - const isFromOverflowMenu = targetItem.objectName === "overflowMenuContainer"; - - if (isFromOverflowMenu) { - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const targetY = targetItem.y + targetItem.height / 2; - anchorPos = Qt.point(targetX, targetY); - } else { - const targetX = targetItem.x + targetItem.width / 2; - let targetY = menuRoot.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(targetX, targetY); - } - } else { - const globalPos = targetItem.mapToGlobal(0, 0); - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const adjustedY = relativeY + targetItem.height / 2 + root.minTooltipY; - anchorPos = Qt.point(targetX, adjustedY); - } else { - let targetY = menuRoot.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(relativeX + targetItem.width / 2, targetY); - } - } - } - - Item { - id: trayMenuContainer - - readonly property real rawWidth: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2)) - readonly property real rawHeight: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2) - - readonly property real alignedWidth: Theme.px(rawWidth, menuWindow.dpr) - readonly property real alignedHeight: Theme.px(rawHeight, menuWindow.dpr) - - width: alignedWidth - height: alignedHeight - - x: Theme.snap((() => { - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - if (edge === "left") { - const targetX = menuWindow.anchorPos.x; - return Math.min(menuWindow.screen.width - alignedWidth - 10, targetX); - } else { - const targetX = menuWindow.anchorPos.x - alignedWidth; - return Math.max(10, targetX); - } - } else { - const left = 10; - const right = menuWindow.width - alignedWidth - 10; - const want = menuWindow.anchorPos.x - alignedWidth / 2; - return Math.max(left, Math.min(right, want)); - } - })(), menuWindow.dpr) - - y: Theme.snap((() => { - if (menuRoot.isVertical) { - const top = Math.max(menuWindow.barY, 10); - const bottom = menuWindow.height - alignedHeight - 10; - const want = menuWindow.anchorPos.y - alignedHeight / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (menuRoot.isAtBottom) { - const targetY = menuWindow.anchorPos.y - alignedHeight; - return Math.max(10, targetY); - } else { - const targetY = menuWindow.anchorPos.y; - return Math.min(menuWindow.screen.height - alignedHeight - 10, targetY); - } - } - })(), menuWindow.dpr) - - opacity: menuRoot.showMenu ? 1 : 0 - scale: menuRoot.showMenu ? 1 : 0.85 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - ElevationShadow { - id: menuBgShadowLayer - anchors.fill: parent - level: Theme.elevationLevel3 - direction: root.effectiveShadowDirection - fallbackOffset: 6 - targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - targetRadius: Theme.cornerRadius - sourceRect.antialiasing: true - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - layer.smooth: true - layer.textureSize: Qt.size(Math.round(width * menuWindow.dpr), Math.round(height * menuWindow.dpr)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - QsMenuAnchor { - id: submenuHydrator - anchor.window: menuWindow - } - - QsMenuOpener { - id: rootOpener - menu: menuRoot.menuHandle - } - - QsMenuOpener { - id: subOpener - menu: { - const e = menuRoot.topEntry(); - return e ? (e.menu || e) : null; - } - } - - Column { - id: menuColumn - - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Rectangle { - visible: entryStack.count === 0 - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: visibilityToggleArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: menuRoot.trayItem?.id || "Unknown" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideMiddle - width: parent.width - Theme.spacingS * 2 - 24 - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: SessionData.isHiddenTrayId(root.getTrayItemKey(menuRoot.trayItem)) ? "visibility" : "visibility_off" - size: 16 - color: Theme.widgetTextColor - } - - MouseArea { - id: visibilityToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const itemKey = root.getTrayItemKey(menuRoot.trayItem); - if (!itemKey) - return; - if (SessionData.isHiddenTrayId(itemKey)) { - SessionData.showTrayId(itemKey); - } else { - SessionData.hideTrayId(itemKey); - } - menuRoot.closeWithAction(); - } - } - } - - Rectangle { - visible: entryStack.count === 0 - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: entryStack.count > 0 - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: backArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - name: "arrow_back" - size: 16 - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Back") - font.pixelSize: Theme.fontSizeSmall - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: backArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: menuRoot.goBack() - } - } - - Rectangle { - visible: entryStack.count > 0 - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: entryStack.count ? (subOpener.children ? subOpener.children : (menuRoot.topEntry()?.children || [])) : rootOpener.children - - Rectangle { - property var menuEntry: modelData - - width: menuColumn.width - height: menuEntry?.isSeparator ? 1 : 28 - radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius - color: { - if (menuEntry?.isSeparator) - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2); - return itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0); - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false) - cursorShape: Qt.PointingHandCursor - - onClicked: { - if (!menuEntry || menuEntry.isSeparator) - return; - if (menuEntry.hasChildren) { - menuRoot.showSubMenu(menuEntry); - return; - } - - if (typeof menuEntry.activate === "function") { - menuEntry.activate(); - } else if (typeof menuEntry.triggered === "function") { - menuEntry.triggered(); - } - Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.closeWithAction() }', menuRoot); - } - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - visible: !menuEntry?.isSeparator - - Rectangle { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - visible: menuEntry?.buttonType !== undefined && menuEntry.buttonType !== 0 - radius: menuEntry?.buttonType === 2 ? 8 : 2 - border.width: 1 - border.color: Theme.outline - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: parent.width - 6 - height: parent.height - 6 - radius: parent.radius - 3 - color: Theme.primary - visible: menuEntry?.checkState === 2 - } - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 10 - color: Theme.primaryText - visible: menuEntry?.buttonType === 1 && menuEntry?.checkState === 2 - } - } - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - visible: (menuEntry?.icon ?? "") !== "" - - Image { - anchors.fill: parent - source: menuEntry?.icon || "" - sourceSize.width: 16 - sourceSize.height: 16 - fillMode: Image.PreserveAspectFit - smooth: true - } - } - - StyledText { - text: menuEntry?.text || "" - font.pixelSize: Theme.fontSizeSmall - color: (menuEntry?.enabled !== false) ? Theme.surfaceText : Theme.surfaceTextMedium - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - width: Math.max(150, parent.width - 64) - wrapMode: Text.NoWrap - } - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "chevron_right" - size: 14 - color: Theme.widgetTextColor - visible: menuEntry?.hasChildren ?? false - } - } - } - } - } - } - } - } - } - } - - function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) { - if (!screen) - return; - if (currentTrayMenu) { - currentTrayMenu.showMenu = false; - currentTrayMenu.destroy(); - currentTrayMenu = null; - } - - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - - currentTrayMenu = trayMenuComponent.createObject(null); - if (!currentTrayMenu) - return; - currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml deleted file mode 100644 index 696c76c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml +++ /dev/null @@ -1,187 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - readonly property bool hasUpdates: SystemUpdateService.updateCount > 0 - readonly property bool isChecking: SystemUpdateService.isChecking - readonly property bool shouldHide: SettingsData.updaterHideWidget && !hasUpdates && !isChecking && !SystemUpdateService.hasError - - opacity: shouldHide ? 0 : 1 - - states: [ - State { - name: "hidden_horizontal" - when: root.shouldHide && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: root.shouldHide && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Ref { - service: SystemUpdateService - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? root.widgetThickness : updaterIcon.implicitWidth - implicitHeight: root.widgetThickness - - DankIcon { - id: statusIcon - anchors.centerIn: parent - visible: root.isVerticalOrientation - name: { - if (root.isChecking) - return "refresh"; - if (SystemUpdateService.hasError) - return "error"; - if (root.hasUpdates) - return "system_update_alt"; - return "check_circle"; - } - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (SystemUpdateService.hasError) - return Theme.error; - if (root.hasUpdates) - return Theme.primary; - return root.isActive ? Theme.primary : Theme.surfaceText; - } - - RotationAnimation { - id: rotationAnimation - target: statusIcon - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: root.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - statusIcon.rotation = 0; - } - } - } - } - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: (barConfig?.removeWidgetPadding ?? false) ? 0 : 6 - anchors.topMargin: (barConfig?.removeWidgetPadding ?? false) ? 0 : 6 - visible: root.isVerticalOrientation && root.hasUpdates && !root.isChecking - } - - Row { - id: updaterIcon - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: !root.isVerticalOrientation - - DankIcon { - id: statusIconHorizontal - anchors.verticalCenter: parent.verticalCenter - name: { - if (root.isChecking) - return "refresh"; - if (SystemUpdateService.hasError) - return "error"; - if (root.hasUpdates) - return "system_update_alt"; - return "check_circle"; - } - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (SystemUpdateService.hasError) - return Theme.error; - if (root.hasUpdates) - return Theme.primary; - return root.isActive ? Theme.primary : Theme.surfaceText; - } - - RotationAnimation { - id: rotationAnimationHorizontal - target: statusIconHorizontal - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: root.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - statusIconHorizontal.rotation = 0; - } - } - } - } - - StyledText { - id: countText - anchors.verticalCenter: parent.verticalCenter - text: SystemUpdateService.updateCount.toString() - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - visible: root.hasUpdates && !root.isChecking - } - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - if (popoutTarget && popoutTarget.setTriggerPosition) { - const globalPos = root.visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig); - popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml deleted file mode 100644 index fec33d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml +++ /dev/null @@ -1,141 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - Ref { - service: DMSNetworkService - } - - property bool isHovered: clickArea.containsMouse - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - - return 0; - } - - signal toggleVpnPopup - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - - name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: DMSNetworkService.connected ? Theme.primary : Theme.widgetIconColor - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - anchors.centerIn: parent - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.InOutQuad - } - } - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - MouseArea { - id: clickArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - enabled: !DMSNetworkService.isBusy - onPressed: event => { - root.triggerRipple(this, event.x, event.y); - switch (event.button) { - case Qt.RightButton: - DMSNetworkService.toggleVpn(); - return; - case Qt.LeftButton: - root.toggleVpnPopup(); - return; - } - } - onEntered: { - if (!root.parentScreen || (popoutTarget?.shouldBeVisible)) - return; - tooltipLoader.active = true; - if (!tooltipLoader.item) - return; - let tooltipText = ""; - if (!DMSNetworkService.connected) { - tooltipText = "VPN Disconnected"; - } else { - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) { - const name = names[0] || ""; - const maxLength = 25; - const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name; - tooltipText = "VPN Connected • " + displayName; - } else { - const name = names[0]; - const maxLength = 20; - const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name; - tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1); - } - } - - if (root.isVerticalOrientation) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen || Screen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } else { - const isBottom = root.axis?.edge === "bottom"; - const globalPos = mapToGlobal(width / 2, 0); - const currentScreen = root.parentScreen || Screen; - - let tooltipY; - if (isBottom) { - const tooltipHeight = Theme.fontSizeSmall * 1.5 + Theme.spacingS * 2; - tooltipY = currentScreen.height - root.barThickness - root.barSpacing - Theme.spacingXS - tooltipHeight; - } else { - tooltipY = root.barThickness + root.barSpacing + Theme.spacingXS; - } - - tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, currentScreen, false, false); - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml deleted file mode 100644 index 5dbe53a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml +++ /dev/null @@ -1,80 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - visible: SettingsData.weatherEnabled - - Ref { - service: WeatherService - } - - content: Component { - Item { - implicitWidth: { - if (!SettingsData.weatherEnabled) return 0 - if (root.isVerticalOrientation) return root.widgetThickness - root.horizontalPadding * 2 - return Math.min(100 - root.horizontalPadding * 2, weatherRow.implicitWidth) - } - implicitHeight: root.isVerticalOrientation ? weatherColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: weatherColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.barIconSize(root.barThickness, -6, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!WeatherService.weather.available) { - return "--"; - } - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - return temp; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: weatherRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.barIconSize(root.barThickness, -6, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!WeatherService.weather.available) { - return "--°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml deleted file mode 100644 index 3721e35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml +++ /dev/null @@ -1,1981 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import Quickshell.Hyprland -import Quickshell.I3 -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool isVertical: axis?.isVertical ?? false - property var axis: null - property string screenName: "" - property real widgetHeight: 30 - property real barThickness: 48 - property var barConfig: null - property var blurBarWindow: null - property var hyprlandOverviewLoader: null - property var parentScreen: null - - readonly property real _leftMargin: { - if (isVertical) - return 0; - root.x; - if (!root.parent) - return 0; - const gap = root.mapToItem(null, 0, 0).x; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _rightMargin: { - if (isVertical) - return 0; - root.x; - root.width; - if (!root.parent || !blurBarWindow) - return 0; - const gap = blurBarWindow.width - root.mapToItem(null, root.width, 0).x; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _topMargin: { - if (!isVertical) - return 0; - root.y; - if (!root.parent) - return 0; - const gap = root.mapToItem(null, 0, 0).y; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _bottomMargin: { - if (!isVertical) - return 0; - root.y; - root.height; - if (!root.parent || !blurBarWindow) - return 0; - const gap = blurBarWindow.height - root.mapToItem(null, 0, root.height).y; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - - property int _desktopEntriesUpdateTrigger: 0 - readonly property var sortedToplevels: { - return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - } - - readonly property string effectiveScreenName: { - if (!SettingsData.workspaceFollowFocus) - return root.screenName; - - switch (CompositorService.compositor) { - case "niri": - return NiriService.currentOutput || root.screenName; - case "hyprland": - return Hyprland.focusedWorkspace?.monitor?.name || root.screenName; - case "dwl": - return DwlService.activeOutput || root.screenName; - case "sway": - case "scroll": - case "miracle": - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs?.monitor?.name || root.screenName; - default: - return root.screenName; - } - } - - readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle && ExtWorkspaceService.extWorkspaceAvailable) - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - property var currentWorkspace: { - if (useExtWorkspace) - return getExtWorkspaceActiveWorkspace(); - - switch (CompositorService.compositor) { - case "niri": - return getNiriActiveWorkspace(); - case "hyprland": - return getHyprlandActiveWorkspace(); - case "dwl": - const activeTags = getDwlActiveTags(); - return activeTags.length > 0 ? activeTags[0] : -1; - case "sway": - case "scroll": - case "miracle": - return getSwayActiveWorkspace(); - default: - return 1; - } - } - property var dwlActiveTags: { - if (CompositorService.isDwl) { - return getDwlActiveTags(); - } - return []; - } - property var workspaceList: { - if (useExtWorkspace) { - const baseList = getExtWorkspaceWorkspaces(); - return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList; - } - - let baseList; - switch (CompositorService.compositor) { - case "niri": - baseList = getNiriWorkspaces(); - break; - case "hyprland": - baseList = getHyprlandWorkspaces(); - break; - case "dwl": - baseList = getDwlTags(); - break; - case "sway": - case "scroll": - case "miracle": - baseList = getSwayWorkspaces(); - break; - default: - return [1]; - } - return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList; - } - - function getSwayWorkspaces() { - const workspaces = I3.workspaces?.values || []; - if (workspaces.length === 0) - return [ - { - "num": 1 - } - ]; - - function mapWorkspace(ws) { - return { - "num": ws.number, - "name": ws.name, - "focused": ws.focused, - "active": ws.active, - "urgent": ws.urgent, - "monitor": ws.monitor - }; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return workspaces.slice().sort((a, b) => a.num - b.num).map(mapWorkspace); - } - - const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName); - return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num).map(mapWorkspace) : [ - { - "num": 1 - } - ]; - } - - function getSwayActiveWorkspace() { - if (!root.screenName || SettingsData.workspaceFollowFocus) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === root.screenName && ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - function getHyprlandWorkspaces() { - const workspaces = Hyprland.workspaces?.values || []; - if (workspaces.length === 0) { - return [ - { - id: 1, - name: "1" - } - ]; - } - - let filtered = workspaces.filter(ws => ws.id > -1); - if (filtered.length === 0) { - return [ - { - id: 1, - name: "1" - } - ]; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - filtered = filtered.slice().sort((a, b) => a.id - b.id); - } else { - const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName); - filtered = monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.id - b.id) : [ - { - id: 1, - name: "1" - } - ]; - } - - if (!SettingsData.showOccupiedWorkspacesOnly) { - return filtered; - } - - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const activeWsId = root.currentWorkspace; - return filtered.filter(ws => { - if (ws.id === activeWsId) - return true; - return hyprlandToplevels.some(tl => tl.workspace?.id === ws.id); - }); - } - - function getHyprlandActiveWorkspace() { - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return Hyprland.focusedWorkspace?.id || 1; - } - - const monitor = Hyprland.monitors?.values?.find(m => m.name === root.screenName); - return monitor?.activeWorkspace?.id || 1; - } - - function getWorkspaceIcons(ws) { - _desktopEntriesUpdateTrigger; - if (!SettingsData.showWorkspaceApps || !ws) { - return []; - } - - let targetWorkspaceId; - if (CompositorService.isNiri) { - if (!ws || typeof ws !== "object") { - const wsNumber = typeof ws === "number" ? ws : -1; - if (wsNumber <= 0) { - return []; - } - const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNumber && w.output === root.effectiveScreenName); - if (!workspace) { - return []; - } - targetWorkspaceId = workspace.id; - } else { - if (ws.id === undefined || ws.id === -1 || ws.idx === -1) { - return []; - } - targetWorkspaceId = ws.id; - } - } else if (CompositorService.isHyprland) { - targetWorkspaceId = ws.id !== undefined ? ws.id : ws; - } else if (CompositorService.isDwl) { - if (typeof ws !== "object" || ws.tag === undefined) { - return []; - } - targetWorkspaceId = ws.tag; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - targetWorkspaceId = ws.num !== undefined ? ws.num : ws; - } else { - return []; - } - - const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels; - - const byApp = {}; - let isActiveWs = false; - if (CompositorService.isNiri) { - isActiveWs = NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false; - } else if (CompositorService.isDwl) { - const output = DwlService.getOutputState(root.effectiveScreenName); - if (output && output.tags) { - const tag = output.tags.find(t => t.tag === targetWorkspaceId); - isActiveWs = tag ? (tag.state === 1) : false; - } - } else { - isActiveWs = targetWorkspaceId === root.currentWorkspace; - } - - wins.forEach((w, i) => { - if (!w) { - return; - } - - let winWs = null; - if (CompositorService.isNiri) { - winWs = w.workspace_id; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - winWs = w.workspace?.num; - } else { - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w); - winWs = hyprToplevel?.workspace?.id; - } - - if (winWs === undefined || winWs === null || winWs !== targetWorkspaceId) { - return; - } - - const keyBase = (w.app_id || w.appId || w.class || w.windowClass || "unknown"); - const moddedId = Paths.moddedAppId(keyBase); - const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${moddedId}_${i}` : moddedId; - - if (!byApp[key]) { - const isQuickshell = keyBase === "org.quickshell" || keyBase === "com.danklinux.dms"; - const isSteamApp = Paths.isSteamApp(moddedId); - const desktopEntry = DesktopEntries.heuristicLookup(moddedId); - const icon = Paths.getAppIcon(moddedId, desktopEntry); - const appName = Paths.getAppName(moddedId, desktopEntry); - byApp[key] = { - "type": "icon", - "icon": icon, - "isQuickshell": isQuickshell, - "isSteamApp": isSteamApp, - "active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)), - "count": 1, - "windowId": w.address || w.id, - "fallbackText": appName || "" - }; - } else { - byApp[key].count++; - if ((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)) { - byApp[key].active = true; - } - } - }); - - return Object.values(byApp); - } - - function padWorkspaces(list) { - const padded = list.slice(); - let placeholder; - if (useExtWorkspace) { - placeholder = { - "id": "", - "name": "", - "active": false, - "hidden": true - }; - } else if (CompositorService.isNiri) { - placeholder = { - "id": -1, - "idx": -1, - "name": "" - }; - } else if (CompositorService.isHyprland) { - placeholder = { - "id": -1, - "name": "" - }; - } else if (CompositorService.isDwl) { - placeholder = { - "tag": -1 - }; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - placeholder = { - "num": -1 - }; - } else { - placeholder = -1; - } - while (padded.length < 3) { - padded.push(placeholder); - } - return padded; - } - - function getNiriWorkspaces() { - if (NiriService.allWorkspaces.length === 0) { - return [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - } - - const fallbackWorkspaces = [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - - let workspaces; - if (!root.screenName || SettingsData.workspaceFollowFocus) { - const currentWorkspaces = NiriService.getCurrentOutputWorkspaces(); - workspaces = currentWorkspaces.length > 0 ? currentWorkspaces : fallbackWorkspaces; - } else { - const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName); - workspaces = displayWorkspaces.length > 0 ? displayWorkspaces : fallbackWorkspaces; - } - - workspaces = workspaces.slice().sort((a, b) => a.idx - b.idx); - - if (!SettingsData.showOccupiedWorkspacesOnly) { - return workspaces; - } - - return workspaces.filter(ws => { - if (ws.is_active) - return true; - return NiriService.windows?.some(win => win.workspace_id === ws.id) ?? false; - }); - } - - function getNiriActiveWorkspace() { - if (NiriService.allWorkspaces.length === 0) { - return 1; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return NiriService.getCurrentWorkspaceNumber(); - } - - const activeWs = NiriService.allWorkspaces.find(ws => ws.output === root.screenName && ws.is_active); - return activeWs ? activeWs.idx : 1; - } - - function getDwlTags() { - if (!DwlService.dwlAvailable) - return []; - - const targetScreen = root.effectiveScreenName; - const output = DwlService.getOutputState(targetScreen); - if (!output || !output.tags || output.tags.length === 0) - return []; - - if (SettingsData.dwlShowAllTags) { - return output.tags.map(tag => ({ - "tag": tag.tag, - "state": tag.state, - "clients": tag.clients, - "focused": tag.focused - })); - } - - const visibleTagIndices = DwlService.getVisibleTags(targetScreen); - return visibleTagIndices.map(tagIndex => { - const tagData = output.tags.find(t => t.tag === tagIndex); - return { - "tag": tagIndex, - "state": tagData?.state ?? 0, - "clients": tagData?.clients ?? 0, - "focused": tagData?.focused ?? false - }; - }); - } - - function getDwlActiveTags() { - if (!DwlService.dwlAvailable) - return []; - - return DwlService.getActiveTags(root.effectiveScreenName); - } - - function getExtWorkspaceWorkspaces() { - const groups = ExtWorkspaceService.groups; - if (!ExtWorkspaceService.extWorkspaceAvailable || groups.length === 0) { - return [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - const group = groups.find(g => g.outputs && g.outputs.includes(root.screenName)); - if (!group || !group.workspaces) { - return [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - let visible = group.workspaces.filter(ws => !ws.hidden); - - const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0); - if (hasValidCoordinates) { - visible = visible.sort((a, b) => { - const coordsA = a.coordinates || [0, 0]; - const coordsB = b.coordinates || [0, 0]; - if (coordsA[0] !== coordsB[0]) - return coordsA[0] - coordsB[0]; - return coordsA[1] - coordsB[1]; - }); - } - - visible = visible.map(ws => ({ - id: ws.id, - name: ws.name, - coordinates: ws.coordinates, - state: ws.state, - active: ws.active, - urgent: ws.urgent, - hidden: ws.hidden, - groupID: group.id - })); - - return visible.length > 0 ? visible : [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - function getExtWorkspaceActiveWorkspace() { - if (!ExtWorkspaceService.extWorkspaceAvailable) { - return 1; - } - - const activeWs = ExtWorkspaceService.getActiveWorkspaceForOutput(root.screenName); - return activeWs ? (activeWs.id || activeWs.name || "1") : "1"; - } - - readonly property real dpr: parentScreen ? CompositorService.getScreenScale(parentScreen) : 1 - readonly property real padding: (root.barConfig?.removeWidgetPadding ?? false) ? 0 : Theme.snap((root.barConfig?.widgetPadding ?? 12) * (widgetHeight / 30), dpr) - readonly property real visualWidth: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2) - readonly property real visualHeight: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight - readonly property real appIconSize: Theme.barIconSize(barThickness, -6 + SettingsData.workspaceAppIconSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - - function getRealWorkspaces() { - return root.workspaceList.filter(ws => { - if (useExtWorkspace) - return ws && (ws.id !== "" || ws.name !== "") && !ws.hidden; - if (CompositorService.isNiri) - return ws && ws.idx !== -1; - if (CompositorService.isHyprland) - return ws && ws.id !== -1; - if (CompositorService.isDwl) - return ws && ws.tag !== -1; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return ws && ws.num !== -1; - return ws !== -1; - }); - } - - function switchToWorkspaceByModelData(data) { - if (!data) - return; - - if (root.useExtWorkspace && (data.id || data.name)) { - ExtWorkspaceService.activateWorkspace(data.id || data.name, data.groupID || ""); - return; - } - - switch (CompositorService.compositor) { - case "niri": - if (data.idx !== undefined) - NiriService.switchToWorkspace(data.idx); - break; - case "hyprland": - if (data.id) - Hyprland.dispatch(`workspace ${data.id}`); - break; - case "dwl": - if (data.tag !== undefined) - DwlService.switchToTag(root.screenName, data.tag); - break; - case "sway": - case "scroll": - case "miracle": - if (data.num) - try { - I3.dispatch(`workspace number ${data.num}`); - } catch (_) {} - break; - } - } - - function findClosestWorkspaceIndex(localX, localY) { - if (workspaceRepeater.count === 0) - return -1; - - let closestIdx = -1; - let closestDist = Infinity; - - for (let i = 0; i < workspaceRepeater.count; i++) { - const item = workspaceRepeater.itemAt(i); - if (!item) - continue; - const center = item.mapToItem(root, item.width / 2, item.height / 2); - const dist = isVertical ? Math.abs(localY - center.y) : Math.abs(localX - center.x); - if (dist < closestDist) { - closestDist = dist; - closestIdx = i; - } - } - return closestIdx; - } - - function switchWorkspace(direction) { - if (useExtWorkspace) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => (ws.id || ws.name) === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - const nextWorkspace = realWorkspaces[nextIndex]; - ExtWorkspaceService.activateWorkspace(nextWorkspace.id || nextWorkspace.name, nextWorkspace.groupID || ""); - } else if (CompositorService.isNiri) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws && ws.idx === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - const nextWorkspace = realWorkspaces[nextIndex]; - if (!nextWorkspace || nextWorkspace.idx === undefined) { - return; - } - NiriService.switchToWorkspace(nextWorkspace.idx); - } else if (CompositorService.isHyprland) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.id === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`); - } else if (CompositorService.isDwl) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.tag === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - DwlService.switchToTag(root.screenName, realWorkspaces[nextIndex].tag); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.num === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - try { - I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`); - } catch (_) {} - } - } - - function getWorkspaceIndexFallback(modelData, index) { - if (root.useExtWorkspace) - return index + 1; - if (CompositorService.isNiri) - return (modelData?.idx !== undefined && modelData?.idx !== -1) ? modelData.idx : ""; - if (CompositorService.isHyprland) - return modelData?.id || ""; - if (CompositorService.isDwl) - return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return modelData?.num || ""; - return modelData - 1; - } - - function getWorkspaceIndex(modelData, index) { - let isPlaceholder; - if (root.useExtWorkspace) { - isPlaceholder = modelData?.hidden === true; - } else if (CompositorService.isNiri) { - isPlaceholder = modelData?.idx === -1; - } else if (CompositorService.isHyprland) { - isPlaceholder = modelData?.id === -1; - } else if (CompositorService.isDwl) { - isPlaceholder = modelData?.tag === -1; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - isPlaceholder = modelData?.num === -1; - } else { - isPlaceholder = modelData === -1; - } - - if (isPlaceholder) - return index + 1; - - let workspaceName = ""; - if (SettingsData.showWorkspaceName) { - workspaceName = modelData?.name ?? ""; - - if (workspaceName && workspaceName !== "") { - if (root.isVertical) { - workspaceName = workspaceName.charAt(0); - } - } else { - workspaceName = ""; - } - } - - if (workspaceName) { - if (SettingsData.showWorkspaceIndex) { - const indexLabel = getWorkspaceIndexFallback(modelData, index); - return indexLabel ? `${indexLabel}: ${workspaceName}` : workspaceName; - } - return workspaceName; - } - - return getWorkspaceIndexFallback(modelData, index); - } - - readonly property bool hasNativeWorkspaceSupport: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - readonly property bool hasWorkspaces: getRealWorkspaces().length > 0 - readonly property bool shouldShow: hasNativeWorkspaceSupport || (useExtWorkspace && hasWorkspaces) - - width: shouldShow ? (isVertical ? barThickness : visualWidth) : 0 - height: shouldShow ? (isVertical ? visualHeight : barThickness) : 0 - visible: shouldShow - - Item { - id: visualBackground - width: root.visualWidth - height: root.visualHeight - anchors.centerIn: parent - - Rectangle { - id: outline - anchors.centerIn: parent - width: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.width + borderWidth * 2; - } - height: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.height + borderWidth * 2; - } - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: "transparent" - border.width: { - if (barConfig?.widgetOutlineEnabled ?? false) { - return barConfig?.widgetOutlineThickness ?? 1; - } - return 0; - } - border.color: { - if (!(barConfig?.widgetOutlineEnabled ?? false)) { - return "transparent"; - } - const colorOption = barConfig?.widgetOutlineColor || "primary"; - const opacity = barConfig?.widgetOutlineOpacity ?? 1.0; - switch (colorOption) { - case "surfaceText": - return Theme.withAlpha(Theme.surfaceText, opacity); - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - default: - return Theme.withAlpha(Theme.primary, opacity); - } - } - } - - Rectangle { - id: background - anchors.fill: parent - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: { - if ((barConfig?.noBackground ?? false)) - return "transparent"; - const baseColor = Theme.widgetBaseBackgroundColor; - const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0; - if (Theme.widgetBackgroundHasAlpha) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency); - } - return Theme.withAlpha(baseColor, transparency); - } - } - } - - MouseArea { - id: edgeMouseArea - z: -1 - x: -root._leftMargin - y: -root._topMargin - width: root.width + root._leftMargin + root._rightMargin - height: root.height + root._topMargin + root._bottomMargin - acceptedButtons: Qt.LeftButton | Qt.RightButton - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - property real touchpadAccumulator: 0 - property real mouseAccumulator: 0 - property bool scrollInProgress: false - - Timer { - id: scrollCooldown - interval: 100 - onTriggered: parent.scrollInProgress = false - } - - onClicked: mouse => { - const rootPos = edgeMouseArea.mapToItem(root, mouse.x, mouse.y); - switch (mouse.button) { - case Qt.RightButton: - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } - break; - case Qt.LeftButton: - const idx = root.findClosestWorkspaceIndex(rootPos.x, rootPos.y); - if (idx >= 0) - root.switchToWorkspaceByModelData(root.workspaceList[idx]); - break; - } - } - - onWheel: wheel => { - if (Math.abs(wheel.angleDelta.x) > Math.abs(wheel.angleDelta.y)) { - wheel.accepted = false; - return; - } - - if (scrollInProgress) - return; - - const delta = wheel.angleDelta.y; - const isTouchpad = wheel.pixelDelta && wheel.pixelDelta.y !== 0; - const reverse = SettingsData.reverseScrolling ? -1 : 1; - - if (isTouchpad) { - touchpadAccumulator += delta; - if (Math.abs(touchpadAccumulator) < 500) - return; - const direction = touchpadAccumulator * reverse < 0 ? 1 : -1; - root.switchWorkspace(direction); - scrollInProgress = true; - scrollCooldown.restart(); - touchpadAccumulator = 0; - return; - } - - mouseAccumulator += delta; - if (Math.abs(mouseAccumulator) < 120) - return; - const direction = mouseAccumulator * reverse < 0 ? 1 : -1; - root.switchWorkspace(direction); - scrollInProgress = true; - scrollCooldown.restart(); - mouseAccumulator = 0; - } - } - - property int dragSourceIndex: -1 - property int dragTargetIndex: -1 - property bool suppressShiftAnimation: false - - onWorkspaceListChanged: { - if (dragSourceIndex >= 0) { - dragSourceIndex = -1; - dragTargetIndex = -1; - suppressShiftAnimation = false; - } - } - - Flow { - id: workspaceRow - - x: isVertical ? visualBackground.x : (parent.width - implicitWidth) / 2 - y: isVertical ? (parent.height - implicitHeight) / 2 : visualBackground.y - spacing: Theme.spacingS - flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight - - Repeater { - id: workspaceRepeater - model: ScriptModel { - values: root.workspaceList - } - - Item { - id: delegateRoot - - property bool isDropTarget: root.dragTargetIndex === index - - z: dragHandler.dragging ? 1000 : 1 - - property real shiftOffset: { - if (root.dragSourceIndex < 0 || index === root.dragSourceIndex) - return 0; - const dragIdx = root.dragSourceIndex; - const dropIdx = root.dragTargetIndex; - if (dropIdx < 0) - return 0; - const shiftAmount = delegateRoot.width + Theme.spacingS; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVertical ? 0 : delegateRoot.shiftOffset - y: root.isVertical ? delegateRoot.shiftOffset : 0 - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - property bool isActive: { - if (root.useExtWorkspace) - return (modelData?.id || modelData?.name) === root.currentWorkspace; - if (CompositorService.isNiri) - return !!(modelData && modelData.idx === root.currentWorkspace); - if (CompositorService.isHyprland) - return !!(modelData && modelData.id === root.currentWorkspace); - if (CompositorService.isDwl) - return !!(modelData && root.dwlActiveTags.includes(modelData.tag)); - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return !!(modelData && modelData.num === root.currentWorkspace); - return modelData === root.currentWorkspace; - } - property bool isOccupied: { - if (CompositorService.isHyprland) - return Array.from(Hyprland.toplevels?.values || []).some(tl => tl.workspace?.id === modelData?.id); - if (CompositorService.isDwl) - return modelData.clients > 0; - if (CompositorService.isNiri) { - const workspace = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.effectiveScreenName); - return workspace ? (NiriService.windows?.some(win => win.workspace_id === workspace.id) ?? false) : false; - } - return false; - } - property bool isPlaceholder: { - if (root.useExtWorkspace) - return !!(modelData && modelData.hidden); - if (CompositorService.isNiri) - return !!(modelData && modelData.idx === -1); - if (CompositorService.isHyprland) - return !!(modelData && modelData.id === -1); - if (CompositorService.isDwl) - return !!(modelData && modelData.tag === -1); - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return !!(modelData && modelData.num === -1); - return modelData === -1; - } - property bool isHovered: mouseArea.containsMouse - - property var loadedWorkspaceData: null - property bool loadedIsUrgent: false - property bool isUrgent: { - if (root.useExtWorkspace) - return modelData?.urgent ?? false; - if (CompositorService.isHyprland) - return modelData?.urgent ?? false; - if (CompositorService.isNiri) - return loadedIsUrgent; - if (CompositorService.isDwl) - return modelData?.state === 2; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return loadedIsUrgent; - return false; - } - readonly property var loadedIconData: { - if (isPlaceholder) - return null; - const name = modelData?.name; - if (!name) - return null; - return SettingsData.getWorkspaceNameIcon(name); - } - readonly property bool loadedHasIcon: loadedIconData !== null - property var loadedIcons: [] - - readonly property int stableIconCount: { - if (!SettingsData.showWorkspaceApps || isPlaceholder) - return 0; - - let targetWorkspaceId; - if (root.useExtWorkspace) { - targetWorkspaceId = modelData?.id || modelData?.name; - } else if (CompositorService.isNiri) { - targetWorkspaceId = modelData?.id; - } else if (CompositorService.isHyprland) { - targetWorkspaceId = modelData?.id; - } else if (CompositorService.isDwl) { - targetWorkspaceId = modelData?.tag; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - targetWorkspaceId = modelData?.num; - } - if (targetWorkspaceId === undefined || targetWorkspaceId === null) - return 0; - - const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels; - const seen = {}; - let groupedCount = 0; - let totalCount = 0; - - for (let i = 0; i < wins.length; i++) { - const w = wins[i]; - if (!w) - continue; - - let winWs = null; - if (CompositorService.isNiri) { - winWs = w.workspace_id; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - winWs = w.workspace?.num; - } else if (CompositorService.isHyprland) { - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w); - winWs = hyprToplevel?.workspace?.id; - } - - if (winWs !== targetWorkspaceId) - continue; - totalCount++; - - const appKey = w.app_id || w.appId || w.class || w.windowClass || "unknown"; - if (!seen[appKey]) { - seen[appKey] = true; - groupedCount++; - } - } - - return (SettingsData.groupWorkspaceApps && !isActive) ? groupedCount : totalCount; - } - - readonly property real baseWidth: root.isVertical ? (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) : (isActive ? Math.max(root.widgetHeight * 1.05, root.appIconSize * 1.6) : Math.max(root.widgetHeight * 0.7, root.appIconSize * 1.2)) - readonly property real baseHeight: root.isVertical ? (isActive ? Math.max(root.widgetHeight * 1.05, root.appIconSize * 1.6) : Math.max(root.widgetHeight * 0.7, root.appIconSize * 1.2)) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) - readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== "" - readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && (CompositorService.isNiri || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - readonly property real contentImplicitWidth: appIconsLoader.item?.contentWidth ?? 0 - readonly property real contentImplicitHeight: appIconsLoader.item?.contentHeight ?? 0 - - readonly property real iconsExtraWidth: { - if (!root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) { - const numIcons = Math.min(stableIconCount, SettingsData.maxWorkspaceIcons); - return numIcons * root.appIconSize + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0) + (isActive ? Theme.spacingXS : 0); - } - return 0; - } - readonly property real iconsExtraHeight: { - if (root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) { - const numIcons = Math.min(stableIconCount, SettingsData.maxWorkspaceIcons); - return numIcons * root.appIconSize + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0) + (isActive ? Theme.spacingXS : 0); - } - return 0; - } - - readonly property real visualWidth: { - if (contentImplicitWidth <= 0) - return baseWidth + iconsExtraWidth; - const padding = root.isVertical ? Theme.spacingXS : Theme.spacingS; - return Math.max(baseWidth + iconsExtraWidth, contentImplicitWidth + padding); - } - readonly property real visualHeight: { - if (contentImplicitHeight <= 0) - return baseHeight + iconsExtraHeight; - const padding = root.isVertical ? Theme.spacingS : Theme.spacingXS; - return Math.max(baseHeight + iconsExtraHeight, contentImplicitHeight + padding); - } - - readonly property color unfocusedColor: { - switch (SettingsData.workspaceUnfocusedColorMode) { - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - default: - return Theme.surfaceTextAlpha; - } - } - - readonly property color activeColor: { - switch (SettingsData.workspaceColorMode) { - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - case "none": - return unfocusedColor; - default: - return Theme.primary; - } - } - - readonly property color occupiedColor: { - switch (SettingsData.workspaceOccupiedColorMode) { - case "sec": - return Theme.secondary; - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - case "schh": - return Theme.surfaceContainerHighest; - default: - return unfocusedColor; - } - } - - readonly property color urgentColor: { - switch (SettingsData.workspaceUrgentColorMode) { - case "primary": - return Theme.primary; - case "secondary": - return Theme.secondary; - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - default: - return Theme.error; - } - } - - readonly property color focusedBorderColor: { - switch (SettingsData.workspaceFocusedBorderColor) { - case "surfaceText": - return Theme.surfaceText; - case "secondary": - return Theme.secondary; - default: - return Theme.primary; - } - } - - function getContrastingIconColor(bgColor) { - const luminance = 0.299 * bgColor.r + 0.587 * bgColor.g + 0.114 * bgColor.b; - return luminance > 0.4 ? Qt.rgba(0.15, 0.15, 0.15, 1) : Qt.rgba(0.8, 0.8, 0.8, 1); - } - - readonly property color quickshellIconActiveColor: getContrastingIconColor(activeColor) - readonly property color quickshellIconInactiveColor: getContrastingIconColor(unfocusedColor) - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - - Connections { - target: root - function onWorkspaceListChanged() { - if (dragHandler.dragging) { - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - mouseArea.mousePressed = false; - } - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: !isPlaceholder - cursorShape: isPlaceholder ? Qt.ArrowCursor : (dragHandler.dragging ? Qt.ClosedHandCursor : Qt.PointingHandCursor) - enabled: !isPlaceholder - acceptedButtons: Qt.LeftButton | Qt.RightButton - - property bool mousePressed: false - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && CompositorService.isNiri && SettingsData.workspaceDragReorder && !isPlaceholder) { - mousePressed = true; - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - } - } - - onPositionChanged: mouse => { - if (!mousePressed || !CompositorService.isNiri || !SettingsData.workspaceDragReorder || isPlaceholder) - return; - - if (!dragHandler.dragging) { - const distance = root.isVertical ? Math.abs(mouse.y - dragHandler.dragStartPos.y) : Math.abs(mouse.x - dragHandler.dragStartPos.x); - if (distance > 5) { - dragHandler.dragging = true; - root.dragSourceIndex = index; - root.dragTargetIndex = index; - } - } - - if (!dragHandler.dragging) - return; - - const rawAxisOffset = root.isVertical ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x); - - const itemSize = (root.isVertical ? delegateRoot.height : delegateRoot.width) + Theme.spacingS; - const maxOffsetPositive = (root.workspaceList.length - 1 - index) * itemSize; - const maxOffsetNegative = -index * itemSize; - const axisOffset = Math.max(maxOffsetNegative, Math.min(maxOffsetPositive, rawAxisOffset)); - dragHandler.dragAxisOffset = axisOffset; - - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.workspaceList.length - 1, index + slotOffset)); - - if (newTargetIndex !== root.dragTargetIndex) { - root.dragTargetIndex = newTargetIndex; - } - } - - onReleased: mouse => { - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dragTargetIndex >= 0 && root.dragTargetIndex !== root.dragSourceIndex; - - if (didReorder) { - const sourceWs = root.workspaceList[root.dragSourceIndex]; - const targetWs = root.workspaceList[root.dragTargetIndex]; - - if (sourceWs && targetWs && sourceWs.idx !== undefined && targetWs.idx !== undefined) { - root.suppressShiftAnimation = true; - NiriService.moveWorkspaceToIndex(sourceWs.idx, targetWs.idx); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - } - - mousePressed = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.dragSourceIndex = -1; - root.dragTargetIndex = -1; - - if (wasDragging || isPlaceholder) - return; - - if (mouse.button === Qt.LeftButton) { - if (root.useExtWorkspace && (modelData?.id || modelData?.name)) { - ExtWorkspaceService.activateWorkspace(modelData.id || modelData.name, modelData.groupID || ""); - } else if (CompositorService.isNiri) { - if (modelData && modelData.idx !== undefined) { - NiriService.switchToWorkspace(modelData.idx); - } - } else if (CompositorService.isHyprland && modelData?.id) { - Hyprland.dispatch(`workspace ${modelData.id}`); - } else if (CompositorService.isDwl && modelData?.tag !== undefined) { - DwlService.switchToTag(root.screenName, modelData.tag); - } else if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && modelData?.num) { - try { - I3.dispatch(`workspace number ${modelData.num}`); - } catch (_) {} - } - } else if (mouse.button === Qt.RightButton) { - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } else if (CompositorService.isDwl && modelData?.tag !== undefined) { - DwlService.toggleTag(root.screenName, modelData.tag); - } - } - } - } - - Timer { - id: dataUpdateTimer - interval: 50 - onTriggered: { - if (isPlaceholder) { - delegateRoot.loadedWorkspaceData = null; - delegateRoot.loadedIcons = []; - delegateRoot.loadedIsUrgent = false; - return; - } - - var wsData = null; - if (root.useExtWorkspace) { - wsData = modelData; - } else if (CompositorService.isNiri) { - wsData = modelData || null; - } else if (CompositorService.isHyprland) { - wsData = modelData; - } else if (CompositorService.isDwl) { - wsData = modelData; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - wsData = modelData; - } - delegateRoot.loadedWorkspaceData = wsData; - if (CompositorService.isNiri) { - const workspaceId = wsData?.id; - delegateRoot.loadedIsUrgent = workspaceId ? NiriService.windows.some(w => w.workspace_id === workspaceId && w.is_urgent) : false; - } else { - delegateRoot.loadedIsUrgent = wsData?.urgent ?? false; - } - - if (SettingsData.showWorkspaceApps) { - if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData); - } else if (CompositorService.isNiri) { - delegateRoot.loadedIcons = root.getWorkspaceIcons(isPlaceholder ? null : modelData); - } else { - delegateRoot.loadedIcons = root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData)); - } - } else { - delegateRoot.loadedIcons = []; - } - } - } - - function updateAllData() { - dataUpdateTimer.restart(); - } - - width: root.isVertical ? root.widgetHeight : visualWidth - height: root.isVertical ? visualHeight : root.widgetHeight - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - id: focusedBorderRing - x: root.isVertical ? (root.widgetHeight - width) / 2 : (parent.width - width) / 2 - y: root.isVertical ? (parent.height - height) / 2 : (root.widgetHeight - height) / 2 - width: { - const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0; - return delegateRoot.visualWidth + borderWidth * 2; - } - height: { - const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0; - return delegateRoot.visualHeight + borderWidth * 2; - } - radius: Theme.cornerRadius - color: "transparent" - border.width: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0 - border.color: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? focusedBorderColor : "transparent" - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - Rectangle { - id: visualContent - width: delegateRoot.visualWidth - height: delegateRoot.visualHeight - x: root.isVertical ? (root.widgetHeight - width) / 2 : (parent.width - width) / 2 - y: root.isVertical ? (parent.height - height) / 2 : (root.widgetHeight - height) / 2 - radius: Theme.cornerRadius - color: isActive ? activeColor : isUrgent ? urgentColor : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.withAlpha(unfocusedColor, 0.7) : isOccupied ? occupiedColor : unfocusedColor - opacity: dragHandler.dragging ? 0.8 : 1.0 - - border.width: dragHandler.dragging ? 2 : (isUrgent ? 2 : (isDropTarget ? 2 : 0)) - border.color: dragHandler.dragging ? Theme.primary : (isUrgent ? urgentColor : (isDropTarget ? Theme.primary : "transparent")) - - transform: Translate { - x: root.isVertical ? 0 : (dragHandler.dragging ? dragHandler.dragAxisOffset : 0) - y: root.isVertical ? (dragHandler.dragging ? dragHandler.dragAxisOffset : 0) : 0 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Loader { - id: appIconsLoader - anchors.fill: parent - active: SettingsData.showWorkspaceApps || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - sourceComponent: Item { - id: contentRoot - readonly property real contentWidth: contentRow.item?.implicitWidth ?? 0 - readonly property real contentHeight: contentRow.item?.implicitHeight ?? 0 - - Loader { - id: contentRow - anchors.centerIn: parent - sourceComponent: root.isVertical ? columnLayout : rowLayout - } - - Component { - id: rowLayout - Row { - spacing: 4 - visible: loadedIcons.length > 0 || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - - Item { - visible: loadedHasIcon && loadedIconData?.type === "icon" - width: wsIcon.width - height: root.appIconSize - - DankIcon { - id: wsIcon - anchors.verticalCenter: parent.verticalCenter - name: loadedIconData?.value ?? "" - size: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - weight: (isActive && !isPlaceholder) ? 500 : 400 - } - } - - Item { - visible: loadedHasIcon && loadedIconData?.type === "text" - width: wsText.implicitWidth - height: root.appIconSize - - StyledText { - id: wsText - anchors.verticalCenter: parent.verticalCenter - text: loadedIconData?.value ?? "" - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - } - - Item { - visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName) - width: wsIndexText.implicitWidth - height: root.appIconSize - - StyledText { - id: wsIndexText - anchors.verticalCenter: parent.verticalCenter - text: loadedHasIcon ? (modelData?.name ?? "") : root.getWorkspaceIndex(modelData, index) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - } - - Repeater { - model: ScriptModel { - values: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons) - } - delegate: Item { - width: root.appIconSize - height: root.appIconSize - readonly property bool appHighlightActive: SettingsData.workspaceActiveAppHighlightEnabled && modelData.active - readonly property color appBorderColor: appHighlightActive ? focusedBorderColor : Theme.primarySelected - readonly property color appGlyphColor: appHighlightActive ? focusedBorderColor : Theme.primary - readonly property real appOpacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - - IconImage { - id: rowAppIcon - anchors.fill: parent - source: modelData.icon || "" - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: !modelData.isQuickshell && !modelData.isSteamApp && status === Image.Ready - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && !modelData.isSteamApp && rowAppIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - StyledText { - anchors.centerIn: parent - text: (modelData.fallbackText || "?").charAt(0).toUpperCase() - font.pixelSize: parent.width * 0.45 - color: appGlyphColor - font.weight: Font.Bold - } - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && modelData.isSteamApp && rowSteamIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - DankIcon { - anchors.centerIn: parent - size: parent.width * 0.7 - name: "sports_esports" - color: appGlyphColor - } - } - - IconImage { - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isQuickshell - layer.enabled: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: appHighlightActive ? focusedBorderColor : (isActive ? quickshellIconActiveColor : quickshellIconInactiveColor) - } - } - - IconImage { - id: rowSteamIcon - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && modelData.icon - } - - DankIcon { - anchors.centerIn: parent - size: root.appIconSize - name: "sports_esports" - color: appHighlightActive ? focusedBorderColor : Theme.widgetTextColor - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && !modelData.icon - } - - Rectangle { - anchors.fill: parent - visible: (rowAppIcon.visible || rowSteamIcon.visible || modelData.isQuickshell) && appHighlightActive - color: "transparent" - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: focusedBorderColor - z: 1 - } - - MouseArea { - id: rowAppMouseArea - anchors.fill: parent - enabled: isActive - cursorShape: Qt.PointingHandCursor - onClicked: { - const winId = modelData.windowId; - if (!winId) - return; - if (CompositorService.isHyprland) { - Hyprland.dispatch(`focuswindow address:${winId}`); - } else if (CompositorService.isNiri) { - NiriService.focusWindow(winId); - } - } - } - - Rectangle { - visible: modelData.count > 1 && !isActive - width: root.appIconSize * 0.67 - height: root.appIconSize * 0.67 - radius: root.appIconSize * 0.33 - color: "black" - border.color: "white" - border.width: 1 - anchors.right: parent.right - anchors.bottom: parent.bottom - z: 2 - - Text { - anchors.centerIn: parent - text: modelData.count - font.pixelSize: root.appIconSize * 0.44 - color: "white" - } - } - } - } - } - } - - Component { - id: columnLayout - Column { - spacing: 4 - visible: loadedIcons.length > 0 || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - - DankIcon { - visible: loadedHasIcon && loadedIconData?.type === "icon" - anchors.horizontalCenter: parent.horizontalCenter - name: loadedIconData?.value ?? "" - size: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - weight: (isActive && !isPlaceholder) ? 500 : 400 - } - - StyledText { - visible: loadedHasIcon && loadedIconData?.type === "text" - anchors.horizontalCenter: parent.horizontalCenter - text: loadedIconData?.value ?? "" - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - - StyledText { - visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName) - anchors.horizontalCenter: parent.horizontalCenter - text: loadedHasIcon ? (root.isVertical ? (modelData?.name ?? "").charAt(0) : (modelData?.name ?? "")) : root.getWorkspaceIndex(modelData, index) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - - Repeater { - model: ScriptModel { - values: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons) - } - delegate: Item { - width: root.appIconSize - height: root.appIconSize - readonly property bool appHighlightActive: SettingsData.workspaceActiveAppHighlightEnabled && modelData.active - readonly property color appBorderColor: appHighlightActive ? focusedBorderColor : Theme.primarySelected - readonly property color appGlyphColor: appHighlightActive ? focusedBorderColor : Theme.primary - readonly property real appOpacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - - IconImage { - id: colAppIcon - anchors.fill: parent - source: modelData.icon || "" - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: !modelData.isQuickshell && !modelData.isSteamApp && status === Image.Ready - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && !modelData.isSteamApp && colAppIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - StyledText { - anchors.centerIn: parent - text: (modelData.fallbackText || "?").charAt(0).toUpperCase() - font.pixelSize: parent.width * 0.45 - color: appGlyphColor - font.weight: Font.Bold - } - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && modelData.isSteamApp && colSteamIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - DankIcon { - anchors.centerIn: parent - size: parent.width * 0.7 - name: "sports_esports" - color: appGlyphColor - } - } - - IconImage { - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isQuickshell - layer.enabled: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: appHighlightActive ? focusedBorderColor : (isActive ? quickshellIconActiveColor : quickshellIconInactiveColor) - } - } - - IconImage { - id: colSteamIcon - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && modelData.icon - } - - DankIcon { - anchors.centerIn: parent - size: root.appIconSize - name: "sports_esports" - color: appHighlightActive ? focusedBorderColor : Theme.widgetTextColor - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && !modelData.icon - } - - Rectangle { - anchors.fill: parent - visible: (colAppIcon.visible || colSteamIcon.visible || modelData.isQuickshell) && appHighlightActive - color: "transparent" - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: focusedBorderColor - z: 1 - } - - MouseArea { - id: colAppMouseArea - anchors.fill: parent - enabled: isActive - cursorShape: Qt.PointingHandCursor - onClicked: { - const winId = modelData.windowId; - if (!winId) - return; - if (CompositorService.isHyprland) { - Hyprland.dispatch(`focuswindow address:${winId}`); - } else if (CompositorService.isNiri) { - NiriService.focusWindow(winId); - } - } - } - - Rectangle { - visible: modelData.count > 1 && !isActive - width: root.appIconSize * 0.67 - height: root.appIconSize * 0.67 - radius: root.appIconSize * 0.33 - color: "black" - border.color: "white" - border.width: 1 - anchors.right: parent.right - anchors.bottom: parent.bottom - z: 2 - - Text { - anchors.centerIn: parent - text: modelData.count - font.pixelSize: root.appIconSize * 0.44 - color: "white" - } - } - } - } - } - } - } - } - } - - Component.onCompleted: updateAllData() - - Connections { - target: CompositorService - function onSortedToplevelsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: NiriService - enabled: CompositorService.isNiri - function onAllWorkspacesChanged() { - delegateRoot.updateAllData(); - } - function onWindowUrgentChanged() { - delegateRoot.updateAllData(); - } - function onWindowsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: SettingsData - function onShowWorkspaceAppsChanged() { - delegateRoot.updateAllData(); - } - function onWorkspaceNameIconsChanged() { - delegateRoot.updateAllData(); - } - function onAppIdSubstitutionsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: DwlService - enabled: CompositorService.isDwl - function onStateChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: Hyprland.workspaces - enabled: CompositorService.isHyprland - function onValuesChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: I3.workspaces - enabled: (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - function onValuesChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: ExtWorkspaceService - enabled: root.useExtWorkspace - function onStateChanged() { - delegateRoot.updateAllData(); - } - } - } - } - } - - Component.onCompleted: { - if (useExtWorkspace && !DMSService.activeSubscriptions.includes("extworkspace")) { - DMSService.addSubscription("extworkspace"); - } - _updateBlurRegistration(); - } - - property bool _blurRegistered: false - readonly property bool _shouldBlur: BlurService.enabled && blurBarWindow && blurBarWindow.registerBlurWidget && !(barConfig?.noBackground ?? false) && root.visible && root.width > 0 - - on_ShouldBlurChanged: _updateBlurRegistration() - - function _updateBlurRegistration() { - if (_shouldBlur && !_blurRegistered) { - blurBarWindow.registerBlurWidget(visualBackground); - _blurRegistered = true; - } else if (!_shouldBlur && _blurRegistered) { - if (blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualBackground); - _blurRegistered = false; - } - } - - Component.onDestruction: { - if (_blurRegistered && blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualBackground); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml deleted file mode 100644 index 34b324c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml +++ /dev/null @@ -1,425 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:dash" - - property bool dashVisible: false - property var triggerScreen: null - property int currentTabIndex: 0 - - popupWidth: SettingsData.showWeekNumber ? 736 : 700 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500 - triggerWidth: 80 - screen: triggerScreen - shouldBeVisible: dashVisible - - property bool __focusArmed: false - property bool __contentReady: false - - property var __mediaTabRef: null - - property int __dropdownType: 0 - property point __dropdownAnchor: Qt.point(0, 0) - property bool __dropdownRightEdge: false - property var __dropdownPlayer: null - property var __dropdownPlayers: [] - - function __showVolumeDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 1; - } - - function __showAudioDevicesDropdown(pos, rightEdge) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownType = 2; - } - - function __showPlayersDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 3; - } - - function __hideDropdowns() { - __volumeCloseTimer.stop(); - __dropdownType = 0; - __mediaTabRef?.resetDropdownStates(); - } - - function __startCloseTimer() { - __volumeCloseTimer.restart(); - } - - function __stopCloseTimer() { - __volumeCloseTimer.stop(); - } - - Timer { - id: __volumeCloseTimer - interval: 400 - onTriggered: { - if (__dropdownType === 1) { - __hideDropdowns(); - } - } - } - - overlayContent: Component { - MediaDropdownOverlay { - dropdownType: root.__dropdownType - anchorPos: root.__dropdownAnchor - isRightEdge: root.__dropdownRightEdge - activePlayer: root.__dropdownPlayer - allPlayers: root.__dropdownPlayers - onCloseRequested: root.__hideDropdowns() - onPanelEntered: root.__stopCloseTimer() - onPanelExited: root.__startCloseTimer() - onVolumeChanged: volume => { - const player = root.__dropdownPlayer; - const isChrome = player?.identity?.toLowerCase().includes("chrome") || player?.identity?.toLowerCase().includes("chromium"); - const usePlayerVolume = player && player.volumeSupported && !isChrome; - if (usePlayerVolume) { - player.volume = volume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = volume; - } - } - onPlayerSelected: player => { - const currentPlayer = MprisController.activePlayer; - if (currentPlayer && currentPlayer !== player && currentPlayer.canPause) { - currentPlayer.pause(); - } - MprisController.setActivePlayer(player); - root.__hideDropdowns(); - } - onDeviceSelected: device => { - root.__hideDropdowns(); - } - } - } - - function __tryFocusOnce() { - if (!__focusArmed) - return; - const win = root.window; - if (!win || !win.visible) - return; - if (!contentLoader.item) - return; - if (win.requestActivate) - win.requestActivate(); - contentLoader.item.forceActiveFocus(Qt.TabFocusReason); - - if (contentLoader.item.activeFocus) - __focusArmed = false; - } - - onDashVisibleChanged: { - if (dashVisible) { - __focusArmed = true; - __contentReady = !!contentLoader.item; - open(); - __tryFocusOnce(); - } else { - __focusArmed = false; - __contentReady = false; - __hideDropdowns(); - close(); - } - } - - Connections { - target: contentLoader - function onLoaded() { - __contentReady = true; - if (__focusArmed) - __tryFocusOnce(); - } - } - - Connections { - target: root.window ? root.window : null - enabled: !!root.window - function onVisibleChanged() { - if (__focusArmed) - __tryFocusOnce(); - } - } - - onBackgroundClicked: { - dashVisible = false; - } - - content: Component { - Rectangle { - id: mainContainer - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: Math.max(700, pages.implicitWidth + (Theme.spacingM * 2)) - implicitHeight: contentColumn.height + Theme.spacingM * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - mainContainer.forceActiveFocus(); - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(function () { - mainContainer.forceActiveFocus(); - }); - } - } - } - - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.dashVisible = false; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Tab && !(event.modifiers & Qt.ShiftModifier)) { - let nextIndex = root.currentTabIndex + 1; - while (nextIndex < tabBar.model.length && tabBar.model[nextIndex] && tabBar.model[nextIndex].isAction) { - nextIndex++; - } - if (nextIndex >= tabBar.model.length) { - nextIndex = 0; - } - root.currentTabIndex = nextIndex; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { - let prevIndex = root.currentTabIndex - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - if (prevIndex < 0) { - prevIndex = tabBar.model.length - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - } - if (prevIndex >= 0) { - root.currentTabIndex = prevIndex; - } - event.accepted = true; - return; - } - - if (root.currentTabIndex === 2 && wallpaperLoader.item?.handleKeyEvent) { - if (wallpaperLoader.item.handleKeyEvent(event)) { - event.accepted = true; - return; - } - } - } - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankTabBar { - id: tabBar - - width: parent.width - height: 48 - currentIndex: root.currentTabIndex - spacing: Theme.spacingS - equalWidthTabs: true - enableArrowNavigation: false - focus: false - activeFocusOnTab: false - nextFocusTarget: { - const item = pages.currentItem; - if (!item) - return null; - if (item.focusTarget) - return item.focusTarget; - return item; - } - - model: { - let tabs = [ - { - "icon": "dashboard", - "text": I18n.tr("Overview") - }, - { - "icon": "music_note", - "text": I18n.tr("Media") - }, - { - "icon": "wallpaper", - "text": I18n.tr("Wallpapers") - } - ]; - - if (SettingsData.weatherEnabled) { - tabs.push({ - "icon": "wb_sunny", - "text": I18n.tr("Weather") - }); - } - - tabs.push({ - "icon": "settings", - "text": I18n.tr("Settings"), - "isAction": true - }); - return tabs; - } - - onTabClicked: function (index) { - root.currentTabIndex = index; - } - - onActionTriggered: function (index) { - let settingsIndex = SettingsData.weatherEnabled ? 4 : 3; - if (index === settingsIndex) { - dashVisible = false; - PopoutService.focusOrToggleSettings(); - } - } - } - - Item { - width: parent.width - height: Theme.spacingXS - } - - Item { - id: pages - width: parent.width - height: implicitHeight - implicitWidth: currentItem && currentItem.implicitWidth > 0 ? currentItem.implicitWidth : (700 - Theme.spacingM * 2) - implicitHeight: { - if (root.currentTabIndex === 0) - return overviewLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 1) - return mediaLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 2) - return wallpaperLoader.item?.implicitHeight ?? 410; - if (SettingsData.weatherEnabled && root.currentTabIndex === 3) - return weatherLoader.item?.implicitHeight ?? 410; - return 410; - } - - readonly property var currentItem: { - if (root.currentTabIndex === 0) - return overviewLoader.item; - if (root.currentTabIndex === 1) - return mediaLoader.item; - if (root.currentTabIndex === 2) - return wallpaperLoader.item; - if (root.currentTabIndex === 3) - return weatherLoader.item; - return null; - } - - Loader { - id: overviewLoader - anchors.fill: parent - active: root.currentTabIndex === 0 - visible: active - sourceComponent: Component { - OverviewTab { - onCloseDash: root.dashVisible = false - onSwitchToWeatherTab: { - if (SettingsData.weatherEnabled) { - root.currentTabIndex = 3; - } - } - onSwitchToMediaTab: { - root.currentTabIndex = 1; - } - } - } - } - - Loader { - id: mediaLoader - anchors.fill: parent - active: root.currentTabIndex === 1 - visible: active - sourceComponent: Component { - MediaPlayerTab { - targetScreen: root.screen - popoutX: root.alignedX - popoutY: root.alignedY - popoutWidth: root.alignedWidth - popoutHeight: root.alignedHeight - contentOffsetY: Theme.spacingM + 48 + Theme.spacingS + Theme.spacingXS - section: root.triggerSection - barPosition: root.effectiveBarPosition - Component.onCompleted: root.__mediaTabRef = this - onShowVolumeDropdown: (pos, screen, rightEdge, player, players) => { - root.__showVolumeDropdown(pos, rightEdge, player, players); - } - onShowAudioDevicesDropdown: (pos, screen, rightEdge) => { - root.__showAudioDevicesDropdown(pos, rightEdge); - } - onShowPlayersDropdown: (pos, screen, rightEdge, player, players) => { - root.__showPlayersDropdown(pos, rightEdge, player, players); - } - onHideDropdowns: root.__hideDropdowns() - onVolumeButtonExited: root.__startCloseTimer() - } - } - } - - Loader { - id: wallpaperLoader - anchors.fill: parent - active: root.currentTabIndex === 2 - visible: active - sourceComponent: Component { - WallpaperTab { - active: true - tabBarItem: tabBar - keyForwardTarget: mainContainer - targetScreen: root.screen - parentPopout: root - } - } - } - - Loader { - id: weatherLoader - anchors.fill: parent - active: SettingsData.weatherEnabled && root.currentTabIndex === 3 - visible: active - sourceComponent: Component { - WeatherTab {} - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml deleted file mode 100644 index 35dfe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml +++ /dev/null @@ -1,513 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int dropdownType: 0 - property var activePlayer: null - property var allPlayers: [] - property point anchorPos: Qt.point(0, 0) - property bool isRightEdge: false - - property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - property var availableDevices: { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - return Pipewire.nodes.values.filter(node => { - if (!node.audio || !node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - } - - signal closeRequested - signal deviceSelected(var device) - signal playerSelected(var player) - signal volumeChanged(real volume) - signal panelEntered - signal panelExited - - property int __volumeHoverCount: 0 - - function volumeAreaEntered() { - __volumeHoverCount++; - panelEntered(); - } - - function volumeAreaExited() { - __volumeHoverCount--; - Qt.callLater(() => { - if (__volumeHoverCount <= 0) - panelExited(); - }); - } - - Rectangle { - id: volumePanel - visible: dropdownType === 1 && volumeAvailable - width: 60 - height: 180 - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - - opacity: dropdownType === 1 ? 1 : 0 - scale: dropdownType === 1 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: volumeShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: volumePanel.radius - targetColor: volumePanel.color - borderColor: volumePanel.border.color - borderWidth: volumePanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - hoverEnabled: true - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - Item { - id: volumeSlider - width: parent.width * 0.5 - height: parent.height - Theme.spacingXL * 2 - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - } - - Rectangle { - width: parent.width - height: volumeAvailable ? (Math.min(1.0, currentVolume) * parent.height) : 0 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - bottomLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - } - - Rectangle { - width: parent.width + 8 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = volumeAvailable ? Math.min(1.0, currentVolume) : 0; - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0) - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - enabled: volumeAvailable - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - preventStealing: true - - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - onPressed: mouse => updateVolume(mouse) - onPositionChanged: mouse => { - if (pressed) - updateVolume(mouse); - } - onClicked: mouse => updateVolume(mouse) - - function updateVolume(mouse) { - if (!volumeAvailable) - return; - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(1, ratio)); - root.volumeChanged(volume); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Theme.spacingL - text: volumeAvailable ? Math.round(currentVolume * 100) + "%" : "0%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - } - - Rectangle { - id: audioDevicesPanel - visible: dropdownType === 2 - width: 280 - height: Math.max(200, Math.min(280, availableDevices.length * 50 + 100)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 2 ? 1 : 0 - scale: dropdownType === 2 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: audioDevicesShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: audioDevicesPanel.radius - targetColor: audioDevicesPanel.color - borderColor: audioDevicesPanel.border.color - borderWidth: audioDevicesPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Audio Output Devices (") + availableDevices.length + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: deviceColumn.height - clip: true - - Column { - id: deviceColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: availableDevices - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === AudioService.sink ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: getAudioDeviceIcon(modelData) - size: 20 - color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - - function getAudioDeviceIcon(device) { - if (!device?.name) - return "speaker"; - const name = device.name.toLowerCase(); - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - return "speaker"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: modelData === AudioService.sink ? "Active" : "Available" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSink = modelData; - root.deviceSelected(modelData); - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playersPanel - visible: dropdownType === 3 - width: 240 - height: Math.max(180, Math.min(240, (allPlayers?.length || 0) * 50 + 80)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 3 ? 1 : 0 - scale: dropdownType === 3 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: playersShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: playersPanel.radius - targetColor: playersPanel.color - borderColor: playersPanel.border.color - borderWidth: playersPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Media Players (") + (allPlayers?.length || 0) + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: playerColumn.height - clip: true - - Column { - id: playerColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: allPlayers || [] - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: playerMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === activePlayer ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === activePlayer ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: "music_note" - size: 20 - color: modelData === activePlayer ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: { - if (!modelData) - return "Unknown Player"; - const identity = modelData.identity || "Unknown Player"; - const trackTitle = modelData.trackTitle || ""; - return trackTitle.length > 0 ? identity + " - " + trackTitle : identity; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === activePlayer ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - if (!modelData) - return ""; - const artist = modelData.trackArtist || ""; - const isActive = modelData === activePlayer; - if (artist.length > 0) - return artist + (isActive ? " (Active)" : ""); - return isActive ? "Active" : "Available"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - } - } - - MouseArea { - id: playerMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData?.identity) { - root.playerSelected(modelData); - } - } - } - } - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - enabled: dropdownType !== 0 - onClicked: closeRequested() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml deleted file mode 100644 index c6d7bfc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml +++ /dev/null @@ -1,785 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell.Services.Mpris -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property MprisPlayer activePlayer: MprisController.activePlayer - property var allPlayers: MprisController.availablePlayers - property var targetScreen: null - property real popoutX: 0 - property real popoutY: 0 - property real popoutWidth: 0 - property real popoutHeight: 0 - property real contentOffsetY: 0 - property string section: "" - property int barPosition: SettingsData.Position.Top - - signal showVolumeDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal showAudioDevicesDropdown(point pos, var screen, bool rightEdge) - signal showPlayersDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal hideDropdowns - signal volumeButtonExited - - property bool volumeExpanded: false - property bool devicesExpanded: false - property bool playersExpanded: false - - function resetDropdownStates() { - volumeExpanded = false; - devicesExpanded = false; - playersExpanded = false; - } - - DankTooltipV2 { - id: sharedTooltip - } - - readonly property bool isRightEdge: { - if (barPosition === SettingsData.Position.Right) - return true; - if (barPosition === SettingsData.Position.Left) - return false; - return section === "right"; - } - readonly property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - readonly property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - readonly property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - - property bool isSwitching: false - - // Derived "no players" state: always correct, no timers. - readonly property int _playerCount: allPlayers ? allPlayers.length : 0 - readonly property bool _noneAvailable: _playerCount === 0 - readonly property bool _trulyIdle: activePlayer && activePlayer.playbackState === MprisPlaybackState.Stopped && !activePlayer.trackTitle && !activePlayer.trackArtist - readonly property bool showNoPlayerNow: (!_switchHold) && (_noneAvailable || _trulyIdle) - - property bool _switchHold: false - Timer { - id: _switchHoldTimer - interval: 650 - repeat: false - onTriggered: _switchHold = false - } - - onActivePlayerChanged: { - if (!activePlayer) { - isSwitching = false; - _switchHold = false; - return; - } - isSwitching = true; - _switchHold = true; - _switchHoldTimer.restart(); - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - - function maybeFinishSwitch() { - if (activePlayer && activePlayer.trackTitle !== "") { - isSwitching = false; - _switchHold = false; - } - } - - readonly property real ratio: { - if (!activePlayer || !activePlayer.length || activePlayer.length <= 0) { - return 0; - } - const pos = (activePlayer.position || 0) % Math.max(1, activePlayer.length); - const calculatedRatio = pos / activePlayer.length; - return Math.max(0, Math.min(1, calculatedRatio)); - } - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: playerContent.height + playerContent.anchors.topMargin * 2 - - Connections { - target: activePlayer - function onTrackTitleChanged() { - _switchHoldTimer.restart(); - maybeFinishSwitch(); - } - function onTrackArtUrlChanged() { - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - } - - Connections { - target: MprisController - function onAvailablePlayersChanged() { - const count = (MprisController.availablePlayers?.length || 0); - if (count === 0) { - isSwitching = false; - _switchHold = false; - } else { - _switchHold = true; - _switchHoldTimer.restart(); - } - } - } - - function getAudioDeviceIcon(device) { - if (!device || !device.name) - return "speaker"; - - const name = device.name.toLowerCase(); - - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - if (name.includes("analog") || name.includes("built-in")) - return "speaker"; - - return "speaker"; - } - - function getVolumeIcon() { - if (!volumeAvailable) - return "volume_off"; - - const volume = currentVolume; - - if (usePlayerVolume) { - if (volume === 0.0) - return "music_off"; - return "music_note"; - } - - if (volume === 0.0) - return "volume_off"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - - function adjustVolume(step) { - if (!volumeAvailable) - return; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const current = Math.round(currentVolume * 100); - const newVolume = Math.min(maxVol, Math.max(0, current + step)); - - SessionData.suppressOSDTemporarily(); - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - } - - property bool isSeeking: false - - Timer { - interval: 1000 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionChanged() - } - - Item { - id: bgContainer - anchors.fill: parent - visible: TrackArtService._bgArtSource !== "" - - Image { - id: bgImage - anchors.centerIn: parent - width: Math.max(parent.width, parent.height) * 1.1 - height: width - source: TrackArtService._bgArtSource - fillMode: Image.PreserveAspectCrop - asynchronous: true - cache: true - visible: false - onStatusChanged: { - if (status === Image.Ready) - maybeFinishSwitch(); - } - } - - Item { - id: blurredBg - anchors.fill: parent - visible: false - - MultiEffect { - anchors.centerIn: parent - width: bgImage.width - height: bgImage.height - source: bgImage - blurEnabled: true - blurMax: 64 - blur: 0.8 - saturation: -0.2 - brightness: -0.25 - } - } - - Rectangle { - id: bgMask - anchors.fill: parent - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - MultiEffect { - anchors.fill: parent - source: blurredBg - maskEnabled: true - maskSource: bgMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - opacity: 0.7 - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surface - opacity: 0.3 - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - visible: showNoPlayerNow - - DankIcon { - name: "music_note" - size: Theme.iconSize * 3 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Active Players") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Item { - anchors.fill: parent - clip: false - visible: !_noneAvailable && (!showNoPlayerNow) - ColumnLayout { - id: playerContent - width: 484 - height: 370 - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.topMargin: 20 - anchors.horizontalCenter: parent.horizontalCenter - - Item { - width: parent.width - height: 200 - clip: false - - DankAlbumArt { - width: Math.min(parent.width * 0.8, parent.height * 0.9) - height: width - anchors.centerIn: parent - activePlayer: root.activePlayer - } - } - - // Song Info and Controls Section - Item { - width: parent.width - Layout.fillHeight: true - - Column { - id: songInfo - width: parent.width - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Track") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 2 - } - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - } - - StyledText { - text: activePlayer?.trackAlbum || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - visible: text.length > 0 - } - } - - Item { - id: seekbarContainer - width: parent.width - anchors.top: songInfo.bottom - anchors.bottom: playbackControls.top - anchors.horizontalCenter: parent.horizontalCenter - - Column { - width: parent.width - spacing: 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: parent.height * 0.2 - - DankSeekbar { - width: parent.width * 0.8 - height: 20 - anchors.horizontalCenter: parent.horizontalCenter - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width * 0.8 - height: 16 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer) - return "0:00"; - const rawPos = Math.max(0, activePlayer.position || 0); - const pos = activePlayer.length ? rawPos % Math.max(1, activePlayer.length) : rawPos; - const minutes = Math.floor(pos / 60); - const seconds = Math.floor(pos % 60); - const timeStr = minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - return timeStr; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer || !activePlayer.length) - return "0:00"; - const dur = Math.max(0, activePlayer.length || 0); - const minutes = Math.floor(dur / 60); - const seconds = Math.floor(dur % 60); - return minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Item { - id: playbackControls - width: parent.width - height: 50 - anchors.bottom: parent.bottom - - Row { - anchors.centerIn: parent - spacing: Theme.spacingM - height: parent.height - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.shuffleSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: shuffleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "shuffle" - size: 20 - color: activePlayer && activePlayer.shuffle ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: shuffleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.shuffleSupported) { - activePlayer.shuffle = !activePlayer.shuffle; - } - } - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: prevBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: prevBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 50 - height: 50 - radius: 25 - anchors.centerIn: parent - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 28 - color: Theme.background - weight: 500 - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.togglePlaying() - } - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: parent.radius - targetColor: parent.color - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowEnabled: Theme.elevationEnabled - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: nextBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: nextBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.next() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.loopSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: repeatArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: { - if (!activePlayer) - return "repeat"; - switch (activePlayer.loopState) { - case MprisLoopState.Track: - return "repeat_one"; - case MprisLoopState.Playlist: - return "repeat"; - default: - return "repeat"; - } - } - size: 20 - color: activePlayer && activePlayer.loopState !== MprisLoopState.None ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: repeatArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.loopSupported) { - switch (activePlayer.loopState) { - case MprisLoopState.None: - activePlayer.loopState = MprisLoopState.Playlist; - break; - case MprisLoopState.Playlist: - activePlayer.loopState = MprisLoopState.Track; - break; - case MprisLoopState.Track: - activePlayer.loopState = MprisLoopState.None; - break; - } - } - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playerSelectorButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 185 - color: playerSelectorArea.containsMouse || playersExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - visible: (allPlayers?.length || 0) >= 1 - - DankIcon { - anchors.centerIn: parent - name: "assistant_device" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: playerSelectorArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (playersExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - playersExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = playerSelectorButton.y + playerSelectorButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showPlayersDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onEntered: sharedTooltip.show(I18n.tr("Media Players"), playerSelectorButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } - - Rectangle { - id: volumeButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 130 - color: volumeButtonArea.containsMouse && volumeAvailable || volumeExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, volumeAvailable ? 0.3 : 0.15) - border.width: 1 - z: 101 - enabled: volumeAvailable - - property real previousVolume: 0.0 - - DankIcon { - anchors.centerIn: parent - name: getVolumeIcon() - size: 18 - color: volumeAvailable && currentVolume > 0 ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, volumeAvailable ? 1.0 : 0.5) - } - - MouseArea { - id: volumeButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - if (volumeExpanded) - return; - hideDropdowns(); - volumeExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = volumeButton.y + volumeButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showVolumeDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onExited: { - if (volumeExpanded) - volumeButtonExited(); - } - onClicked: { - SessionData.suppressOSDTemporarily(); - if (currentVolume > 0) { - volumeButton.previousVolume = currentVolume; - if (usePlayerVolume) { - activePlayer.volume = 0; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = 0; - } - } else { - const restoreVolume = volumeButton.previousVolume > 0 ? volumeButton.previousVolume : 0.5; - if (usePlayerVolume) { - activePlayer.volume = restoreVolume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = restoreVolume; - } - } - } - onWheel: wheelEvent => { - SessionData.suppressOSDTemporarily(); - const delta = wheelEvent.angleDelta.y; - const current = (currentVolume * 100) || 0; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const newVolume = delta > 0 ? Math.min(maxVol, current + 5) : Math.max(0, current - 5); - - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - wheelEvent.accepted = true; - } - } - } - - Rectangle { - id: audioDevicesButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 240 - color: audioDevicesArea.containsMouse || devicesExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - - DankIcon { - anchors.centerIn: parent - name: devicesExpanded ? "expand_less" : "speaker" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: audioDevicesArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (devicesExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - devicesExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = audioDevicesButton.y + audioDevicesButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showAudioDevicesDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight); - } - onEntered: sharedTooltip.show(I18n.tr("Output Device"), audioDevicesButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml deleted file mode 100644 index 1972f06..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml +++ /dev/null @@ -1,539 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - - property bool showEventDetails: false - property date selectedDate: systemClock.date - property var selectedDateEvents: [] - property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0 - - signal closeDash - - function weekStartQt() { - if (SettingsData.firstDayOfWeek >= 7 || SettingsData.firstDayOfWeek < 0) { - return Qt.locale().firstDayOfWeek; - } - return SettingsData.firstDayOfWeek; - } - - function weekStartJs() { - return weekStartQt() % 7; - } - - function startOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const diff = (jsDow - weekStartJs() + 7) % 7; - d.setDate(d.getDate() - diff); - return d; - } - - function endOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const add = (weekStartJs() + 6 - jsDow + 7) % 7; - d.setDate(d.getDate() + add); - return d; - } - - function getWeekNumber(dateObj) { - // Set time to noon to avoid potential Daylight Saving Time related bugs - const weekStartDay = startOfWeek(dateObj); - weekStartDay.setHours(12, 0, 0, 0); - - let week1Start; - - if (weekStartJs() === 1) { - // ISO 8601 Standard, week start on Monday - // A week belongs to the year its Thursday falls in - // So we have to get the yearTarget from weekStartDay instead of dateObj - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday - - // Week 1 is the week containing Jan 4th - const jan4 = new Date(yearTarget.getFullYear(), 0, 4); - week1Start = startOfWeek(jan4); - } else { - // Traditional / US Standard, week start on Sunday - // A week belongs to the year its Sunday falls in - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday - - // Week 1 is the week containing Jan 1st - const jan1 = new Date(yearTarget.getFullYear(), 0, 1); - week1Start = startOfWeek(jan1); - } - - week1Start.setHours(12, 0, 0, 0); - - const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day - return Math.floor(diffDays / 7) + 1; - } - - function updateSelectedDateEvents() { - if (CalendarService && CalendarService.khalAvailable) { - const events = CalendarService.getEventsForDate(selectedDate); - selectedDateEvents = events; - } else { - selectedDateEvents = []; - } - } - - function loadEventsForMonth() { - if (!CalendarService || !CalendarService.khalAvailable) { - return; - } - - const firstOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth(), 1); - const lastOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth() + 1, 0); - - const startDate = startOfWeek(firstOfMonth); - startDate.setDate(startDate.getDate() - 7); - - const endDate = endOfWeek(lastOfMonth); - endDate.setDate(endDate.getDate() + 7); - - CalendarService.loadEvents(startDate, endDate); - } - - onSelectedDateChanged: updateSelectedDateEvents() - Component.onCompleted: { - loadEventsForMonth(); - updateSelectedDateEvents(); - } - - Connections { - function onEventsByDateChanged() { - updateSelectedDateEvents(); - } - - function onKhalAvailableChanged() { - if (CalendarService && CalendarService.khalAvailable) { - loadEventsForMonth(); - } - updateSelectedDateEvents(); - } - - target: CalendarService - enabled: CalendarService !== null - } - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 1 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: 40 - visible: showEventDetails - - Rectangle { - width: 32 - height: 32 - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - radius: Theme.cornerRadius - color: backButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "arrow_back" - size: 14 - color: Theme.primary - } - - MouseArea { - id: backButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.showEventDetails = false - } - } - - StyledText { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 32 + Theme.spacingS * 2 - anchors.rightMargin: Theme.spacingS - height: 40 - anchors.verticalCenter: parent.verticalCenter - text: { - const dateStr = Qt.formatDate(selectedDate, "MMM d"); - if (selectedDateEvents && selectedDateEvents.length > 0) { - const eventCount = selectedDateEvents.length === 1 ? I18n.tr("1 event") : selectedDateEvents.length + " " + I18n.tr("events"); - return dateStr + " • " + eventCount; - } - return dateStr; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - } - - Row { - width: parent.width - height: 28 - visible: !showEventDetails - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_left" - size: 14 - color: Theme.primary - } - - MouseArea { - id: prevMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() - 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - - StyledText { - width: parent.width - 56 - height: 28 - text: calendarGrid.displayDate.toLocaleDateString(I18n.locale(), "MMMM yyyy") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_right" - size: 14 - color: Theme.primary - } - - MouseArea { - id: nextMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() + 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - } - - Row { - width: parent.width - height: parent.height - 28 - Theme.spacingS - visible: !showEventDetails - spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0 - - Column { - id: weekNumberColumn - visible: SettingsData.showWeekNumber - width: SettingsData.showWeekNumber ? 28 : 0 - height: parent.height - spacing: Theme.spacingS - - Item { - width: parent.width - height: 18 - } - - Grid { - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 1 - rows: 6 - - Repeater { - model: 6 - Rectangle { - width: parent.width - height: parent.height / 6 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: { - const rowDate = new Date(calendarGrid.firstDay); - rowDate.setDate(rowDate.getDate() + index * 7); - return root.getWeekNumber(rowDate); - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - } - - Column { - width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width - height: parent.height - spacing: Theme.spacingS - - Row { - width: parent.width - height: 18 - - Repeater { - model: { - const days = []; - const qtFirst = weekStartQt(); - for (let i = 0; i < 7; ++i) { - const qtDay = ((qtFirst - 1 + i) % 7) + 1; - days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat)); - } - return days; - } - - Rectangle { - width: parent.width / 7 - height: 18 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - - Grid { - id: calendarGrid - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 7 - rows: 6 - - property date displayDate: systemClock.date - property date selectedDate: systemClock.date - - readonly property date firstDay: { - const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1); - return startOfWeek(firstOfMonth); - } - - Repeater { - model: 42 - - Rectangle { - readonly property date dayDate: { - const date = new Date(parent.firstDay); - date.setDate(date.getDate() + index); - return date; - } - readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth() - readonly property bool isToday: dayDate.toDateString() === new Date().toDateString() - readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString() - - width: parent.width / 7 - height: parent.height / 6 - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: Math.min(parent.width - 4, parent.height - 4, 32) - height: width - color: isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: dayDate.getDate() - font.pixelSize: Theme.fontSizeSmall - color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - font.weight: isToday ? Font.Medium : Font.Normal - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 4 - width: 12 - height: 2 - radius: Theme.cornerRadius - visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate) - color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary - opacity: isToday ? 0.9 : 0.7 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - MouseArea { - id: dayArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) { - root.selectedDate = dayDate; - root.showEventDetails = true; - } - } - } - } - } - } - } - } - - DankListView { - width: parent.width - Theme.spacingS * 2 - height: parent.height - (showEventDetails ? 40 : 28 + 18) - Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - model: selectedDateEvents - visible: showEventDetails - clip: true - spacing: Theme.spacingXS - - delegate: Rectangle { - width: parent ? parent.width : 0 - height: eventContent.implicitHeight + Theme.spacingS - radius: Theme.cornerRadius - color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06); - } - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15); - } - return "transparent"; - } - border.width: 1 - - Rectangle { - width: 3 - height: parent.height - 6 - anchors.left: parent.left - anchors.leftMargin: 3 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: Theme.primary - opacity: 0.8 - } - - Column { - id: eventContent - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS + 6 - anchors.rightMargin: Theme.spacingXS - spacing: 2 - - StyledText { - width: parent.width - text: modelData.title - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - } - - StyledText { - width: parent.width - text: { - if (!modelData || modelData.allDay) { - return I18n.tr("All day"); - } else if (modelData.start && modelData.end) { - const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - const startTime = Qt.formatTime(modelData.start, timeFormat); - if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime()) { - return startTime + " – " + Qt.formatTime(modelData.end, timeFormat); - } - return startTime; - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.weight: Font.Normal - visible: text !== "" - } - } - - MouseArea { - id: eventMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: modelData.url !== "" - onClicked: { - if (modelData.url && modelData.url !== "") { - if (Qt.openUrlExternally(modelData.url) === false) { - console.warn("Failed to open URL: " + modelData.url); - } else { - root.closeDash(); - } - } - } - } - } - } - } - - SystemClock { - id: systemClock - precision: SystemClock.Hours - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml deleted file mode 100644 index 8996c81..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: card - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int pad: Theme.spacingM - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - default property alias content: contentItem.data - - Item { - id: contentItem - anchors.fill: parent - anchors.margins: card.pad - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml deleted file mode 100644 index 5f597c3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Widgets - -Card { - id: root - - Column { - anchors.centerIn: parent - spacing: 0 - - Column { - spacing: -8 - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(0) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(1) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - } - - Row { - visible: SettingsData.showSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0') - font.pixelSize: 24 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.7) - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - } - - Item { - width: 1 - height: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: systemClock?.date?.toLocaleDateString(I18n.locale(), "MMM dd") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - SystemClock { - id: systemClock - precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml deleted file mode 100644 index 35f4f47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml +++ /dev/null @@ -1,211 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - clip: false - - signal clicked() - - property MprisPlayer activePlayer: MprisController.activePlayer - property real currentPosition: activePlayer?.positionSupported ? activePlayer.position : 0 - property real displayPosition: currentPosition - - readonly property real ratio: { - if (!activePlayer || activePlayer.length <= 0) return 0 - const pos = displayPosition % Math.max(1, activePlayer.length) - const calculatedRatio = pos / activePlayer.length - return Math.max(0, Math.min(1, calculatedRatio)) - } - - onActivePlayerChanged: { - if (activePlayer?.positionSupported) { - currentPosition = Qt.binding(() => activePlayer?.position || 0) - } else { - currentPosition = 0 - } - } - - Timer { - interval: 300 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionSupported && activePlayer.positionChanged() - } - - property bool isSeeking: false - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !activePlayer - - DankIcon { - name: "music_note" - size: Theme.iconSize - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Media") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - anchors.centerIn: parent - width: parent.width - Theme.spacingXS * 2 - spacing: Theme.spacingL - visible: activePlayer - - Item { - width: 140 - height: 110 - anchors.horizontalCenter: parent.horizontalCenter - clip: false - - DankAlbumArt { - width: 110 - height: 80 - anchors.centerIn: parent - activePlayer: root.activePlayer - albumSize: 76 - animationScale: 1.05 - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - topPadding: Theme.spacingL - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: activePlayer?.trackArtist || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - } - - DankSeekbar { - width: parent.width + 4 - height: 20 - x: -2 - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width - height: 32 - - Row { - spacing: Theme.spacingS - anchors.centerIn: parent - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: prevArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: prevArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - id: playPauseButton - width: 32 - height: 32 - radius: 16 - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 16 - color: Theme.background - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.togglePlaying() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: nextArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: nextArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.next() - } - } - } - } - } - - MouseArea { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: 123 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - visible: activePlayer - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml deleted file mode 100644 index cb7089b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml +++ /dev/null @@ -1,178 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - Component.onCompleted: { - DgopService.addRef(["cpu", "memory", "system"]) - } - Component.onDestruction: { - DgopService.removeRef(["cpu", "memory", "system"]) - } - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - // CPU Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.cpuUsage || 6) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "memory" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - } - } - } - - // Temperature Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min(Math.max((DgopService.cpuTemperature || 40) / 100, 0), 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "device_thermostat" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - } - } - } - - // RAM Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.memoryUsage || 42) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "developer_board" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml deleted file mode 100644 index 0d90b44..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - Component.onCompleted: DgopService.addRef("system") - Component.onDestruction: DgopService.removeRef("system") - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankCircularImage { - id: avatarContainer - - width: 77 - height: 77 - anchors.verticalCenter: parent.verticalCenter - imageSource: { - if (PortalService.profileImage === "") - return ""; - - if (PortalService.profileImage.startsWith("/")) - return "file://" + PortalService.profileImage; - - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Column { - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: UserInfoService.username || I18n.tr("brandon") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - SystemLogo { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - colorOverride: Theme.primary - } - - StyledText { - text: { - if (CompositorService.isNiri) - return I18n.tr("on Niri"); - if (CompositorService.isHyprland) - return I18n.tr("on Hyprland"); - // technically they might not be on mangowc, but its what we support in the docs - if (CompositorService.isDwl) - return I18n.tr("on MangoWC"); - if (CompositorService.isSway) - return I18n.tr("on Sway"); - if (CompositorService.isScroll) - return I18n.tr("on Scroll"); - if (CompositorService.isMiracle) - return I18n.tr("on Miracle WM"); - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS - horizontalAlignment: Text.AlignLeft - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - DankIcon { - name: "schedule" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.shortUptime || I18n.tr("up") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml deleted file mode 100644 index 0bba92e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - signal clicked - - Component.onCompleted: WeatherService.addRef() - Component.onDestruction: WeatherService.removeRef() - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !WeatherService.weather.available - - DankIcon { - name: "cloud_off" - size: 24 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: WeatherService.weather.loading ? I18n.tr("Loading...") : I18n.tr("No Weather") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - - Button { - text: I18n.tr("Refresh") - flat: true - visible: !WeatherService.weather.loading - anchors.horizontalCenter: parent.horizontalCenter - onClicked: WeatherService.forceRefresh() - } - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - visible: WeatherService.weather.available - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: 48 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - anchors.left: parent.left - text: { - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - if (temp === undefined || temp === null) - return "--°" + (SettingsData.useFahrenheit ? "F" : "C"); - return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - font.pixelSize: Theme.fontSizeXLarge + 4 - color: Theme.surfaceText - font.weight: Font.Light - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - elide: Text.ElideRight - width: parent.parent.parent.width - 48 - Theme.spacingL * 2 - horizontalAlignment: Text.AlignLeft - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml deleted file mode 100644 index de7ea35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.DankDash.Overview - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - signal switchToWeatherTab - signal switchToMediaTab - signal closeDash - - Item { - anchors.fill: parent - // Clock - top left (narrower and shorter) - ClockCard { - x: 0 - y: 0 - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 180 - } - - // Weather - top middle-left (narrower) - WeatherOverviewCard { - x: SettingsData.weatherEnabled ? parent.width * 0.2 - Theme.spacingM : 0 - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.3 : 0 - height: 100 - visible: SettingsData.weatherEnabled - - onClicked: root.switchToWeatherTab() - } - - // UserInfo - top middle-right (extend when weather disabled) - UserInfoCard { - x: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.2 - Theme.spacingM - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.8 - height: 100 - } - - // SystemMonitor - middle left (narrow and shorter) - SystemMonitorCard { - x: 0 - y: 180 + Theme.spacingM - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 220 - } - - // Calendar - bottom middle (wider and taller) - CalendarOverviewCard { - x: parent.width * 0.2 - Theme.spacingM - y: 100 + Theme.spacingM - width: parent.width * 0.6 - height: 300 - - onCloseDash: root.closeDash() - } - - // Media - bottom right (narrow and taller) - MediaOverviewCard { - x: parent.width * 0.8 - y: 100 + Theme.spacingM - width: parent.width * 0.2 - height: 300 - - onClicked: root.switchToMediaTab() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml deleted file mode 100644 index 1f35b00..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml +++ /dev/null @@ -1,590 +0,0 @@ -import Qt.labs.folderlistmodel -import QtCore -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Modals.FileBrowser -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - property string wallpaperDir: "" - property int currentPage: 0 - property int itemsPerPage: 16 - property int totalPages: Math.max(1, Math.ceil(wallpaperFolderModel.count / itemsPerPage)) - property bool active: false - property Item focusTarget: wallpaperGrid - property Item tabBarItem: null - property int gridIndex: 0 - property Item keyForwardTarget: null - property var parentPopout: null - property int lastPage: 0 - property bool enableAnimation: false - property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation) - property string selectedFileName: "" - property var targetScreen: null - property string targetScreenName: targetScreen ? targetScreen.name : "" - - signal requestTabChange(int newIndex) - - function getCurrentWallpaper() { - if (SessionData.perMonitorWallpaper && targetScreenName) { - return SessionData.getMonitorWallpaper(targetScreenName); - } - return SessionData.wallpaperPath; - } - - function setCurrentWallpaper(path) { - if (SessionData.perMonitorWallpaper && targetScreenName) { - SessionData.setMonitorWallpaper(targetScreenName, path); - } else { - SessionData.setWallpaper(path); - } - } - - onCurrentPageChanged: { - if (currentPage !== lastPage) { - enableAnimation = false; - lastPage = currentPage; - } - updateSelectedFileName(); - } - - onGridIndexChanged: { - updateSelectedFileName(); - } - - onVisibleChanged: { - if (visible && active) { - setInitialSelection(); - } - } - - Component.onCompleted: { - loadWallpaperDirectory(); - } - - onActiveChanged: { - if (active && visible) { - setInitialSelection(); - } - } - - function handleKeyEvent(event) { - const columns = 4; - const currentCol = gridIndex % columns; - const visibleCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (gridIndex >= 0 && gridIndex < visibleCount) { - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - setCurrentWallpaper(filePath.toString().replace(/^file:\/\//, '')); - } - } - } - return true; - } - - if (event.key === Qt.Key_Right || event.key === Qt.Key_L) { - if (I18n.isRtl) { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } else { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } - return true; - } - - if (event.key === Qt.Key_Left || event.key === Qt.Key_H) { - if (I18n.isRtl) { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } else { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } - return true; - } - - if (event.key === Qt.Key_Down || event.key === Qt.Key_J) { - if (gridIndex + columns < visibleCount) { - gridIndex += columns; - } else if (currentPage < totalPages - 1) { - gridIndex = currentCol; - currentPage++; - } - return true; - } - - if (event.key === Qt.Key_Up || event.key === Qt.Key_K) { - if (gridIndex >= columns) { - gridIndex -= columns; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - const prevPageRows = Math.ceil(prevPageCount / columns); - gridIndex = (prevPageRows - 1) * columns + currentCol; - gridIndex = Math.min(gridIndex, prevPageCount - 1); - } - return true; - } - - if (event.key === Qt.Key_PageUp && currentPage > 0) { - gridIndex = 0; - currentPage--; - return true; - } - - if (event.key === Qt.Key_PageDown && currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - return true; - } - - if (event.key === Qt.Key_Home && event.modifiers & Qt.ControlModifier) { - gridIndex = 0; - currentPage = 0; - return true; - } - - if (event.key === Qt.Key_End && event.modifiers & Qt.ControlModifier) { - currentPage = totalPages - 1; - const lastPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = Math.max(0, lastPageCount - 1); - return true; - } - - return false; - } - - function setInitialSelection() { - const currentWallpaper = getCurrentWallpaper(); - if (!currentWallpaper || wallpaperFolderModel.count === 0) { - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - - for (var i = 0; i < wallpaperFolderModel.count; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath && filePath.toString().replace(/^file:\/\//, '') === currentWallpaper) { - const targetPage = Math.floor(i / itemsPerPage); - const targetIndex = i % itemsPerPage; - currentPage = targetPage; - gridIndex = targetIndex; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - } - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - } - - function loadWallpaperDirectory() { - const currentWallpaper = getCurrentWallpaper(); - - if (!currentWallpaper || currentWallpaper.startsWith("#")) { - if (CacheData.wallpaperLastPath && CacheData.wallpaperLastPath !== "") { - wallpaperDir = CacheData.wallpaperLastPath; - } else { - wallpaperDir = ""; - } - return; - } - - wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')); - } - - function updateSelectedFileName() { - if (wallpaperFolderModel.count === 0) { - selectedFileName = ""; - return; - } - - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - const pathStr = filePath.toString().replace(/^file:\/\//, ''); - selectedFileName = pathStr.substring(pathStr.lastIndexOf('/') + 1); - return; - } - } - selectedFileName = ""; - } - - Connections { - target: SessionData - function onWallpaperPathChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onMonitorWallpapersChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onPerMonitorWallpaperChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - } - - onTargetScreenNameChanged: { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - - Connections { - target: wallpaperFolderModel - function onCountChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - function onStatusChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready && wallpaperFolderModel.count > 0) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - } - - FolderListModel { - id: wallpaperFolderModel - - showDirsFirst: false - showDotAndDotDot: false - showHidden: false - caseSensitive: false - nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - showFiles: true - showDirs: false - sortField: FolderListModel.Name - folder: wallpaperDir ? "file://" + wallpaperDir.split('/').map(s => encodeURIComponent(s)).join('/') : "" - } - - FileBrowserSurfaceModal { - id: wallpaperBrowser - - browserTitle: I18n.tr("Select Wallpaper Directory", "wallpaper directory file browser title") - browserIcon: "folder_open" - browserType: "wallpaper" - showHiddenFiles: false - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - parentPopout: root.parentPopout - - onFileSelected: path => { - const cleanPath = path.replace(/^file:\/\//, ''); - setCurrentWallpaper(cleanPath); - - const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/')); - if (dirPath) { - wallpaperDir = dirPath; - CacheData.wallpaperLastPath = dirPath; - CacheData.saveCache(); - } - close(); - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: parent.height - 50 - - GridView { - id: wallpaperGrid - anchors.centerIn: parent - width: parent.width - Theme.spacingS - height: parent.height - Theme.spacingS - cellWidth: width / 4 - cellHeight: height / 4 - clip: true - enabled: root.active - interactive: root.active - boundsBehavior: Flickable.StopAtBounds - keyNavigationEnabled: false - activeFocusOnTab: false - highlightFollowsCurrentItem: true - highlightMoveDuration: enableAnimation ? Theme.shortDuration : 0 - focus: false - - highlight: Item { - z: 1000 - Rectangle { - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: "transparent" - border.width: 3 - border.color: Theme.primary - radius: Theme.cornerRadius - } - } - - model: { - const startIndex = currentPage * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, wallpaperFolderModel.count); - const items = []; - for (var i = startIndex; i < endIndex; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath) { - items.push(filePath.toString().replace(/^file:\/\//, '')); - } - } - return items; - } - - onModelChanged: { - const clampedIndex = model.length > 0 ? Math.min(Math.max(0, gridIndex), model.length - 1) : 0; - if (gridIndex !== clampedIndex) { - gridIndex = clampedIndex; - } - } - - onCountChanged: { - if (count > 0) { - const clampedIndex = Math.min(gridIndex, count - 1); - currentIndex = clampedIndex; - positionViewAtIndex(clampedIndex, GridView.Contain); - } - Qt.callLater(() => { - enableAnimation = true; - }); - } - - Connections { - target: root - function onGridIndexChanged() { - if (wallpaperGrid.count > 0) { - wallpaperGrid.currentIndex = gridIndex; - if (!enableAnimation) { - wallpaperGrid.positionViewAtIndex(gridIndex, GridView.Contain); - } - } - } - } - - delegate: Item { - width: wallpaperGrid.cellWidth - height: wallpaperGrid.cellHeight - - property string wallpaperPath: modelData || "" - property bool isSelected: getCurrentWallpaper() === modelData - - Rectangle { - id: wallpaperCard - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - radius: Theme.cornerRadius - clip: true - - Rectangle { - anchors.fill: parent - color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) : "transparent" - radius: parent.radius - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - id: maskRect - width: thumbnailImage.width - height: thumbnailImage.height - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - CachingImage { - id: thumbnailImage - anchors.fill: parent - imagePath: modelData || "" - maxCacheSize: 256 - - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - maskSource: maskRect - } - } - - StateLayer { - anchors.fill: parent - cornerRadius: parent.radius - stateColor: Theme.primary - } - - MouseArea { - id: wallpaperMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onClicked: { - gridIndex = index; - if (modelData) { - setCurrentWallpaper(modelData); - } - } - } - } - } - } - - StyledText { - anchors.centerIn: parent - visible: wallpaperFolderModel.count === 0 - text: I18n.tr("No wallpapers found\n\nClick the folder icon below to browse") - font.pixelSize: 14 - color: Theme.outline - horizontalAlignment: Text.AlignHCenter - } - } - - Column { - width: parent.width - height: 50 - - Row { - width: parent.width - height: 32 - spacing: Theme.spacingS - - Item { - width: (parent.width - controlsRow.width - browseButton.width - Theme.spacingS) / 2 - height: parent.height - } - - Row { - id: controlsRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_previous" - iconSize: 20 - buttonSize: 32 - enabled: currentPage > 0 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage > 0) { - currentPage--; - } - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: wallpaperFolderModel.count > 0 - ? (wallpaperFolderModel.count === 1 - ? I18n.tr("%1 wallpaper • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages) - : I18n.tr("%1 wallpapers • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages)) - : I18n.tr("No wallpapers") - font.pixelSize: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_next" - iconSize: 20 - buttonSize: 32 - enabled: currentPage < totalPages - 1 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage < totalPages - 1) { - currentPage++; - } - } - } - } - - DankActionButton { - id: browseButton - anchors.verticalCenter: parent.verticalCenter - iconName: "folder_open" - iconSize: 20 - buttonSize: 32 - opacity: 0.7 - onClicked: wallpaperBrowser.open() - } - } - - StyledText { - width: parent.width - height: 18 - text: selectedFileName - font.pixelSize: 12 - color: Theme.surfaceText - opacity: 0.5 - visible: selectedFileName !== "" - elide: Text.ElideMiddle - horizontalAlignment: Text.AlignHCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml deleted file mode 100644 index 5c57b65..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml +++ /dev/null @@ -1,206 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - radius: Theme.cornerRadius - - property var date: null - property var daily: true - property var forecastData: null - property var dense: false - - readonly property bool isCurrent: { - if (daily) { - date ? WeatherService.calendarDayDifference(new Date(), date) === 0 : false; - } else { - date ? WeatherService.calendarHourDifference(new Date(), date) === 0 : false; - } - } - - readonly property string dateText: { - if (daily) - return root.forecastData?.day ?? "--"; - if (!root.forecastData?.rawTime) - return root.forecastData?.time ?? "--"; - try { - const date = new Date(root.forecastData.rawTime); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return root.forecastData?.time ?? "--"; - } - } - - readonly property var minTemp: WeatherService.formatTemp(root.forecastData?.tempMin) - readonly property var maxTemp: WeatherService.formatTemp(root.forecastData?.tempMax) - readonly property string minMaxTempText: (minTemp ?? "--") + "/" + (maxTemp ?? "--") - - readonly property var temp: WeatherService.formatTemp(root.forecastData?.temp) - readonly property string tempText: temp ?? "--" - - readonly property var feelsLikeTemp: WeatherService.formatTemp(root.forecastData?.feelsLike) - readonly property string feelsLikeText: feelsLikeTemp ?? "--" - - readonly property var humidity: WeatherService.formatPercent(root.forecastData?.humidity) - readonly property string humidityText: humidity ?? "--" - - readonly property var wind: { - SettingsData.windSpeedUnit; - SettingsData.useFahrenheit; - return WeatherService.formatSpeed(root.forecastData?.wind); - } - readonly property string windText: wind ?? "--" - - readonly property var pressure: { - SettingsData.useFahrenheit; - return WeatherService.formatPressure(root.forecastData?.pressure); - } - readonly property string pressureText: pressure ?? "--" - - readonly property var precipitation: root.forecastData?.precipitationProbability - readonly property string precipitationText: precipitation + "%" ?? "--" - - readonly property var visibility: WeatherService.formatVisibility(root.forecastData?.visibility) - readonly property string visibilityText: visibility ?? "--" - - readonly property var values: daily ? [] : [ - { - "name"// 'name': "Temperature", - : - // 'text': root.tempText, - // 'icon': "thermometer" - // }, { - // 'name': "Feels Like", - // 'text': root.feelsLikeText, - // 'icon': "thermostat" - // }, { - I18n.tr("Humidity"), - "text": root.humidityText, - "icon": "humidity_low" - }, - { - "name": I18n.tr("Wind Speed"), - "text": root.windText, - "icon": "air" - }, - { - "name": I18n.tr("Pressure"), - "text": root.pressureText, - "icon": "speed" - }, - { - "name": I18n.tr("Precipitation Chance"), - "text": root.precipitationText, - "icon": "rainy" - }, - { - "name": I18n.tr("Visibility"), - "text": root.visibilityText, - "icon": "wb_sunny" - } - ] - - color: isCurrent ? Theme.withAlpha(Theme.primary, 0.1) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: isCurrent ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: isCurrent ? 1 : 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: root.forecastData != null ? root.dateText : I18n.tr("Forecast Not Available") - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : (root.forecastData ? Theme.surfaceText : Theme.outline) - font.weight: root.isCurrent ? Font.Medium : Font.Normal - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - visible: root.forecastData != null - - Column { - spacing: Theme.spacingXS - - DankIcon { - name: root.forecastData ? WeatherService.getWeatherIcon(root.forecastData.wCode || 0, root.forecastData.isDay ?? true) : "cloud" - size: Theme.iconSize - color: root.isCurrent ? Theme.primary : Theme.withAlpha(Theme.primary, 0.8) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.daily ? root.minMaxTempText : root.tempText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.feelsLikeText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - visible: !root.daily - } - } - - Column { - id: detailsColumn - spacing: 2 - visible: !root.dense - width: implicitWidth - - states: [ - State { - name: "dense" - when: root.dense - PropertyChanges { - target: detailsColumn - opacity: 0 - width: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "opacity,width" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Repeater { - model: root.values.length - Row { - spacing: 2 - - DankIcon { - name: root.values[index].icon - size: 8 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.values[index].text - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml deleted file mode 100644 index 21ea656..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml +++ /dev/null @@ -1,1124 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - property bool syncing: false - property bool showHourly: false - property bool available: WeatherService.weather.available - - function syncFrom(type) { - if (!dailyLoader.item || !hourlyLoader.item) - return; - const hourlyList = hourlyLoader.item; - const dailyList = dailyLoader.item; - syncing = true; - - try { - if (type === "hour") { - const date = new Date(); - date.setHours(hourlyList.currentIndex); - dateStepper.currentDate = date; - - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - } else if (type === "day") { - const date = new Date(dateStepper.currentDate); - date.setMonth((new Date()).getMonth()); - date.setDate((new Date()).getDate() + dailyList.currentIndex); - dateStepper.currentDate = date; - - const hourIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date).getHours())); - hourlyList.currentIndex = hourIndex; - } else if (type === "date") { - const date = dateStepper.currentDate; - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - hourlyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date()).getHours())); - } - } catch (e) { - console.warn("Weather Date Sync Error:", e); - } - - syncing = false; - } - - readonly property string sunriseTimeText: { - if (!WeatherService.weather.rawSunrise) - return WeatherService.weather.sunrise || ""; - try { - const date = new Date(WeatherService.weather.rawSunrise); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunrise || ""; - } - } - - readonly property string sunsetTimeText: { - if (!WeatherService.weather.rawSunset) - return WeatherService.weather.sunset || ""; - try { - const date = new Date(WeatherService.weather.rawSunset); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunset || ""; - } - } - - readonly property var heroMetrics: { - SettingsData.useFahrenheit; - SettingsData.windSpeedUnit; - return [ - { - "icon": "humidity_low", - "label": I18n.tr("Humidity"), - "value": WeatherService.formatPercent(WeatherService.weather.humidity) ?? "--" - }, - { - "icon": "air", - "label": I18n.tr("Wind"), - "value": WeatherService.formatSpeed(WeatherService.weather.wind) ?? "--" - }, - { - "icon": "speed", - "label": I18n.tr("Pressure"), - "value": WeatherService.formatPressure(WeatherService.weather.pressure) ?? "--" - }, - { - "icon": "rainy", - "label": I18n.tr("Precipitation"), - "value": (WeatherService.weather.precipitationProbability ?? 0) + "%" - }, - { - "icon": "wb_twilight", - "label": I18n.tr("Sunrise"), - "value": root.sunriseTimeText || "--" - }, - { - "icon": "bedtime", - "label": I18n.tr("Sunset"), - "value": root.sunsetTimeText || "--" - } - ]; - } - - Column { - id: unavailableColumn - anchors.centerIn: parent - spacing: Theme.spacingL - visible: !root.available - - DankIcon { - name: "cloud_off" - size: Theme.iconSize * 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - width: refreshButtonTwo.width + refreshText.width - height: refreshButtonTwo.height - spacing: Theme.spacingS - - StyledText { - id: refreshText - text: I18n.tr("No Weather Data Available") - font.pixelSize: Theme.fontSizeLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: refreshButtonTwo - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.top: parent.top - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseAreaTwo - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelayTwo - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltipTwo.show(I18n.tr("Refresh Weather"), refreshButtonTwo, 0, 0, "left"); - } - } - - onEntered: { - hoverDelayTwo.restart(); - } - - onExited: { - hoverDelayTwo.stop(); - refreshButtonTooltipTwo.hide(); - } - - onClicked: { - refreshButtonTwo.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimerTwo.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltipTwo - } - - Timer { - id: refreshTimerTwo - interval: 2000 - onTriggered: refreshButtonTwo.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButtonTwo.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - } - - Column { - id: mainColumn - anchors.fill: parent - visible: root.available - spacing: Theme.spacingS - - Rectangle { - id: heroCard - width: parent.width - height: heroContent.height + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.withAlpha(Theme.outline, 0.08) - border.width: 1 - - Column { - id: heroContent - x: Theme.spacingL - y: Theme.spacingL - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - Item { - width: parent.width - height: Math.max(heroLeft.height, heroMetricsGrid.height) - - Row { - id: heroLeft - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - DankIcon { - id: weatherIcon - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize * 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - } - } - - Column { - id: tempColumn - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Item { - anchors.left: parent.left - width: tempText.width + unitText.width + Theme.spacingXS - height: tempText.height - - StyledText { - id: tempText - LayoutMirroring.enabled: false - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeXLarge + 8 - color: Theme.surfaceText - font.weight: Font.Light - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: unitText - LayoutMirroring.enabled: false - text: SettingsData.useFahrenheit ? "F" : "C" - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: tempText.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (WeatherService.weather.available) - SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit); - } - enabled: WeatherService.weather.available - } - } - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: parent.left - } - - StyledText { - property var feelsLike: SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp) - text: I18n.tr("Feels Like %1°", "weather feels like temperature").arg(feelsLike) - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: WeatherService.weather.city || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - visible: text.length > 0 - anchors.left: parent.left - } - } - } - - Grid { - id: heroMetricsGrid - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - columns: 3 - columnSpacing: Theme.spacingXL - rowSpacing: Theme.spacingS - - Repeater { - model: root.heroMetrics - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: modelData.icon - size: Theme.iconSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.left: parent.left - } - } - } - } - } - } - } - } - - Item { - id: skyDateRow - width: parent.width - height: dateStepper.height - - Item { - id: dateStepper - height: dateStepperInner.height + Theme.spacingM * 2 - width: dateStepperInner.width - - property var currentDate: new Date() - - readonly property var changeDate: (magnitudeIndex, sign) => { - switch (magnitudeIndex) { - case 0: - break; - case 1: - var newDate = new Date(dateStepper.currentDate); - newDate.setMonth(dateStepper.currentDate.getMonth() + sign * 1); - dateStepper.currentDate = newDate; - break; - case 2: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 24 * 3600 * 1000); - break; - case 3: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 3600 * 1000); - break; - case 4: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 5 * 60 * 1000); - break; - } - } - readonly property var splitDate: Qt.formatDateTime(dateStepper.currentDate, SettingsData.use24HourClock ? "yyyy.MM.dd.HH.mm" : "yyyy.MM.dd.hh.mm.AP").split('.') - - Item { - id: dateStepperInner - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - readonly property var space: Theme.spacingXS - width: yearStepper.width + monthStepper.width + dayStepper.width + hourStepper.width + minuteStepper.width + (suffix.visible ? suffix.width : 0) + 10.5 * space + 2 * dateStepperInnerPadding.width - height: Math.max(yearStepper.height, monthStepper.height, dayStepper.height, hourStepper.height, minuteStepper.height) - - Item { - id: dateStepperInnerPadding - width: dateResetButton.width - } - - DankNumberStepper { - id: yearStepper - anchors.left: dateStepperInnerPadding.right - anchors.leftMargin: parent.space - width: implicitWidth - text: dateStepper.splitDate[0] - } - - DankNumberStepper { - id: monthStepper - width: implicitWidth - anchors.left: yearStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[1] - onIncrement: () => dateStepper.changeDate(1, +1) - onDecrement: () => dateStepper.changeDate(1, -1) - } - - DankNumberStepper { - id: dayStepper - width: implicitWidth - anchors.left: monthStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[2] - onIncrement: () => dateStepper.changeDate(2, +1) - onDecrement: () => dateStepper.changeDate(2, -1) - } - - DankNumberStepper { - id: hourStepper - width: implicitWidth - anchors.left: dayStepper.right - anchors.leftMargin: 1.5 * parent.space - text: dateStepper.splitDate[3] - onIncrement: () => dateStepper.changeDate(3, +1) - onDecrement: () => dateStepper.changeDate(3, -1) - } - - DankNumberStepper { - id: minuteStepper - width: implicitWidth - anchors.left: hourStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[4] - onIncrement: () => dateStepper.changeDate(4, +1) - onDecrement: () => dateStepper.changeDate(4, -1) - } - - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: yearStepper.right - anchors.right: monthStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: monthStepper.right - anchors.right: dayStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: hourStepper.right - anchors.right: minuteStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: ":" - } - } - StyledText { - id: suffix - visible: !SettingsData.use24HourClock - anchors.verticalCenter: minuteStepper.verticalCenter - anchors.left: minuteStepper.right - anchors.leftMargin: 2 * parent.space - isMonospace: true - text: dateStepper.splitDate[5] ?? "" - font.pixelSize: Theme.fontSizeSmall - } - DankActionButton { - id: dateResetButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - enabled: Math.abs(dateStepper.currentDate - new Date()) > 1000 - iconColor: enabled ? Theme.blendAlpha(Theme.surfaceText, 0.5) : "transparent" - iconSize: 12 - buttonSize: 20 - iconName: "replay" - onClicked: { - dateStepper.currentDate = new Date(); - } - } - } - - onCurrentDateChanged: if (!syncing) - root.syncFrom("date") - } - - Rectangle { - id: skyBox - anchors.left: dateStepper.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - height: parent.height - - LayoutMirroring.enabled: false - LayoutMirroring.childrenInherit: true - - property var backgroundOpacity: 0.3 - property var sunTime: WeatherService.getCurrentSunTime(dateStepper.currentDate) - property var periodIndex: sunTime?.periodIndex - property var periodPercent: sunTime?.periodPercent - property var blackColor: Theme.blend(Theme.surface, Qt.rgba(0, 0, 0, 255), 0.2) - property var redColor: Theme.secondary - property var blueColor: Theme.primary - function blackBlue(r) { - return Theme.blend(blackColor, blueColor, r); - } - property var topColor: { - const colorMap = [blackColor, Theme.withAlpha(blackBlue(0.0), 0.8), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(1.0), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.0), 0.8), blackColor, blackColor]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - property var sunColor: { - const colorMap = [Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(blueColor, 0.0), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.0)]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - - color: "transparent" - - Rectangle { - anchors.fill: parent - opacity: skyBox.backgroundOpacity - - gradient: Gradient { - GradientStop { - position: 0.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - GradientStop { - position: 0.05 - color: skyBox.topColor - } - GradientStop { - position: 0.3 - color: skyBox.topColor - } - GradientStop { - position: 0.5 - color: skyBox.topColor - } - GradientStop { - position: 0.501 - color: skyBox.blackColor - } - GradientStop { - position: 0.9 - color: skyBox.blackColor - } - GradientStop { - position: 1.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - } - } - - property var currentDate: dateStepper.currentDate - property var hMargin: 0 - property var vMargin: Theme.spacingM - property var effectiveHeight: skyBox.height - 2 * vMargin - property var effectiveWidth: skyBox.width - 2 * hMargin - - StyledText { - text: parent.sunTime?.period ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.7) - x: 0 - y: 0 - } - - Shape { - id: skyShape - anchors.left: parent.left - anchors.top: parent.top - anchors.right: parent.right - height: parent.height / 2 - opacity: skyBox.backgroundOpacity - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: skyBox.hMargin + sun.x + sun.width / 2 - centerY: skyBox.vMargin + sun.y + 30 - centerRadius: { - const a = Math.abs((skyBox.sunTime?.dayPercent ?? 0) - 0.5); - const out = 200 * (0.5 - a * a); - return out; - } - focalX: skyBox.hMargin + sun.x + sun.width / 2 - focalY: skyBox.vMargin + sun.y - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.3 - color: Theme.blendAlpha(skyBox.sunColor, 0.5) - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: sun.x - centerY: sun.y - centerRadius: 500 - focalX: centerX - focalY: centerY + 0.99 * (centerRadius - focalRadius) - focalRadius: 10 - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.45 - color: skyBox.sunColor - } - GradientStop { - position: 0.55 - color: "transparent" - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - } - - Canvas { - id: ecliptic - anchors.fill: parent - property var points: WeatherService.getEcliptic(dateStepper.currentDate) - - function getX(index) { - return points[index].h * skyBox.effectiveWidth + skyBox.hMargin; - } - function getY(index) { - return points[index].v * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 + skyBox.vMargin; - } - - onPointsChanged: requestPaint() - - onPaint: { - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - if (!points || points.length === 0) - return; - ctx.beginPath(); - ctx.moveTo(getX(0), getY(0)); - for (var i = 1; i < points.length; i++) { - ctx.lineTo(getX(i), getY(i)); - } - ctx.strokeStyle = Theme.withAlpha(Theme.outline, 0.2); - ctx.stroke(); - } - } - - property real latitude: WeatherService.getLocation()?.latitude ?? 0 - property real sunDeclination: WeatherService.getSunDeclination(dateStepper.currentDate) - - readonly property bool solarNoonIsSouth: latitude > sunDeclination - - StyledText { - id: middle - text: skyBox.solarNoonIsSouth ? "S" : "N" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 2 - middle.width / 2 - y: skyBox.height / 2 - middle.height / 2 - } - - StyledText { - id: left - text: skyBox.solarNoonIsSouth ? "E" : "W" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 4 - left.width / 2 - y: skyBox.height / 2 - left.height / 2 - } - - StyledText { - id: right - text: skyBox.solarNoonIsSouth ? "W" : "E" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: 3 * skyBox.width / 4 - right.width / 2 - y: skyBox.height / 2 - right.height / 2 - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: right.right - anchors.right: skyBox.right - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: middle.right - anchors.right: right.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: left.right - anchors.right: middle.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: skyBox.left - anchors.right: left.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - DankNFIcon { - id: moonPhase - name: WeatherService.getMoonPhase(skyBox.currentDate) || "" - size: Theme.fontSizeXLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - rotation: (WeatherService.getMoonAngle(skyBox.currentDate) || 0) / Math.PI * 180 - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, false) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - - DankIcon { - id: sun - name: "light_mode" - size: Theme.fontSizeXLarge - color: Theme.primary - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, true) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - } - } - - Item { - id: chipsRow - width: parent.width - height: forecastChips.height - - DankFilterChips { - id: forecastChips - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - model: [I18n.tr("Daily"), I18n.tr("Hourly")] - currentIndex: root.showHourly ? 1 : 0 - showCheck: false - showCounts: false - onSelectionChanged: index => { - root.showHourly = index === 1; - } - } - - DankActionButton { - id: denseButton - anchors.right: refreshButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - visible: root.showHourly && hourlyLoader.item !== null - iconName: SessionData.weatherHourlyDetailed ? "tile_large" : "tile_medium" - onClicked: SessionData.setWeatherHourlyDetailed(!SessionData.weatherHourlyDetailed) - } - - DankIcon { - id: refreshButton - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelay - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltip.show(I18n.tr("Refresh Weather"), refreshButton, 0, 0, "left"); - } - } - - onEntered: { - hoverDelay.restart(); - } - - onExited: { - hoverDelay.stop(); - refreshButtonTooltip.hide(); - } - - onClicked: { - refreshButton.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimer.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltip - } - - Timer { - id: refreshTimer - interval: 2000 - onTriggered: refreshButton.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButton.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - - Item { - width: parent.width - height: root.height - heroCard.height - skyDateRow.height - chipsRow.height - mainColumn.spacing * 3 - - Loader { - id: dailyLoader - anchors.fill: parent - sourceComponent: dailyComponent - active: root.visible && root.available - visible: !root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - - Loader { - id: hourlyLoader - anchors.fill: parent - sourceComponent: hourlyComponent - active: root.visible && root.available - visible: root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - } - } - - Component { - id: hourlyComponent - ListView { - id: hourlyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((hourlyList.width + hourlyList.spacing) / hourlyList.visibleCount) - hourlyList.spacing - property int initialIndex: (new Date()).getHours() - property bool dense: !SessionData.weatherHourlyDetailed - property int visibleCount: dense ? 10 : 5 - - model: WeatherService.weather.hourlyForecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: hourlyList.cardWidth - height: hourlyList.cardHeight - dense: hourlyList.dense - daily: false - - date: { - const d = new Date(); - d.setHours(index); - return d; - } - forecastData: WeatherService.weather.hourlyForecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("hour") - - states: [ - State { - name: "denseState" - when: hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 10 - } - }, - State { - name: "normalState" - when: !hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 5 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "visibleCount" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = hourlyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < hourlyList.model && newIndex >= 0) { - hourlyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } - - Component { - id: dailyComponent - ListView { - id: dailyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((dailyList.width + dailyList.spacing) / dailyList.visibleCount) - dailyList.spacing - property int initialIndex: 0 - property bool dense: false - property int visibleCount: 7 - - model: WeatherService.weather.forecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: dailyList.cardWidth - height: dailyList.cardHeight - dense: true - daily: true - - date: { - const date = new Date(); - date.setDate(date.getDate() + index); - return date; - } - forecastData: WeatherService.weather.forecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("day") - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = dailyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < dailyList.model && newIndex >= 0) { - dailyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml deleted file mode 100644 index 384025f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Modules.Plugins -import qs.Modules.BuiltinDesktopPlugins - -Variants { - id: root - model: Quickshell.screens - - Component.onCompleted: Qt.callLater(autoEnablePluginsForInstances) - - function autoEnablePluginsForInstances() { - const instances = SettingsData.desktopWidgetInstances || []; - const pluginTypes = new Set(); - - for (const inst of instances) { - if (!inst.enabled) - continue; - if (inst.widgetType === "desktopClock" || inst.widgetType === "systemMonitor") - continue; - pluginTypes.add(inst.widgetType); - } - - for (const pluginId of pluginTypes) { - if (PluginService.isPluginLoaded(pluginId)) - continue; - if (!PluginService.availablePlugins[pluginId]) - continue; - PluginService.enablePlugin(pluginId); - } - } - - Connections { - target: PluginService - function onPluginListUpdated() { - Qt.callLater(root.autoEnablePluginsForInstances); - } - } - - QtObject { - id: screenDelegate - - required property var modelData - - readonly property var screen: modelData - readonly property string screenKey: SettingsData.getScreenDisplayName(screen) - - function shouldShowOnScreen(prefs) { - if (!Array.isArray(prefs) || prefs.length === 0 || prefs.includes("all")) - return true; - return prefs.some(p => { - if (typeof p === "string") - return p === screenKey || p === modelData.name; - return p?.name === modelData.name || p === screenKey; - }); - } - - property Component clockComponent: Component { - DesktopClockWidget {} - } - - property Component systemMonitorComponent: Component { - SystemMonitorWidget {} - } - - property Instantiator widgetInstantiator: Instantiator { - model: ScriptModel { - objectProp: "id" - values: SettingsData.desktopWidgetInstances - } - - DesktopPluginWrapper { - required property var modelData - required property int index - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = SettingsData.desktopWidgetInstances || []; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - readonly property bool shouldBeVisible: { - if (!liveInstanceData.enabled) - return false; - const prefs = liveInstanceData.config?.displayPreferences ?? ["all"]; - return screenDelegate.shouldShowOnScreen(prefs); - } - - pluginId: liveInstanceData.widgetType - instanceId: instanceIdRef - instanceData: liveInstanceData - builtinComponent: { - switch (liveInstanceData.widgetType) { - case "desktopClock": - return screenDelegate.clockComponent; - case "systemMonitor": - return screenDelegate.systemMonitorComponent; - default: - return null; - } - } - pluginService: (liveInstanceData.widgetType !== "desktopClock" && liveInstanceData.widgetType !== "systemMonitor") ? PluginService : null - screen: screenDelegate.screen - widgetEnabled: shouldBeVisible - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml deleted file mode 100644 index 136f23a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml +++ /dev/null @@ -1,671 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import QtQuick.Shapes -import Quickshell -import Quickshell.Hyprland -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Variants { - id: dockVariants - model: SettingsData.getFilteredScreens("dock") - - property var contextMenu - - delegate: PanelWindow { - id: dock - - WindowBlur { - targetWindow: dock - blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x - blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y - blurWidth: dock.hasApps && dock.reveal ? dockBackground.width : 0 - blurHeight: dock.hasApps && dock.reveal ? dockBackground.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:dock" - - readonly property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - - anchors { - top: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true - bottom: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true - left: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left) - right: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right) - } - - property var modelData: item - property bool autoHide: SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide - property real backgroundTransparency: SettingsData.dockTransparency - property bool groupByApp: SettingsData.dockGroupByApp - readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0 - - readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0 - - readonly property real widgetHeight: SettingsData.dockIconSize - readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2 - function getBarHeight(barConfig) { - if (!barConfig) - return 0; - const innerPadding = barConfig.innerPadding ?? 4; - const widgetThickness = Math.max(20, 26 + innerPadding * 0.6); - const barThickness = Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding)); - const spacing = barConfig.spacing ?? 4; - const bottomGap = barConfig.bottomGap ?? 0; - return barThickness + spacing + bottomGap; - } - - readonly property real barSpacing: { - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return 0; - - const barPos = defaultBar.position ?? SettingsData.Position.Top; - const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom); - const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right); - const samePosition = (SettingsData.dockPosition === barPos); - const dockIsHorizontal = !isVertical; - const dockIsVertical = isVertical; - - if (!(defaultBar.visible ?? true)) - return 0; - const spacing = defaultBar.spacing ?? 4; - const bottomGap = defaultBar.bottomGap ?? 0; - if (dockIsHorizontal && barIsHorizontal && samePosition) { - return spacing + effectiveBarHeight + bottomGap; - } - if (dockIsVertical && barIsVertical && samePosition) { - return spacing + effectiveBarHeight + bottomGap; - } - return 0; - } - - readonly property real adjacentTopBarHeight: { - if (!isVertical || autoHide) - return 0; - const screenName = dock.modelData?.name ?? ""; - const topBar = SettingsData.barConfigs.find(bc => { - if (!bc.enabled || bc.autoHide || !(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Top && bc.position !== 0) - return false; - const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName); - return onThisScreen; - }); - return getBarHeight(topBar); - } - - readonly property real adjacentLeftBarWidth: { - if (isVertical || autoHide) - return 0; - const screenName = dock.modelData?.name ?? ""; - const leftBar = SettingsData.barConfigs.find(bc => { - if (!bc.enabled || bc.autoHide || !(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Left && bc.position !== 2) - return false; - const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName); - return onThisScreen; - }); - return getBarHeight(leftBar); - } - - readonly property real dockMargin: SettingsData.dockSpacing - readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin - readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1 - function px(v) { - return Math.round(v * _dpr) / _dpr; - } - - property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData) - property bool revealSticky: false - - readonly property bool shouldHideForWindows: { - if (!SettingsData.dockSmartAutoHide) - return false; - if (!CompositorService.isNiri && !CompositorService.isHyprland) - return false; - - const screenName = dock.modelData?.name ?? ""; - const dockThickness = effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin; - const screenWidth = dock.screen?.width ?? 0; - const screenHeight = dock.screen?.height ?? 0; - - if (CompositorService.isNiri) { - NiriService.windows; - - let currentWorkspaceId = null; - for (let i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.output === screenName && ws.is_active) { - currentWorkspaceId = ws.id; - break; - } - } - - if (currentWorkspaceId === null) - return false; - - for (let i = 0; i < NiriService.windows.length; i++) { - const win = NiriService.windows[i]; - if (win.workspace_id !== currentWorkspaceId) - continue; - - // Get window position and size from layout data - const tilePos = win.layout?.tile_pos_in_workspace_view; - const winSize = win.layout?.window_size || win.layout?.tile_size; - - if (tilePos && winSize) { - const winX = tilePos[0]; - const winY = tilePos[1]; - const winW = winSize[0]; - const winH = winSize[1]; - - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - if (winY < dockThickness) - return true; - break; - case SettingsData.Position.Bottom: - if (winY + winH > screenHeight - dockThickness) - return true; - break; - case SettingsData.Position.Left: - if (winX < dockThickness) - return true; - break; - case SettingsData.Position.Right: - if (winX + winW > screenWidth - dockThickness) - return true; - break; - } - } else if (!win.is_floating) { - return true; - } - } - - return false; - } - - // Hyprland implementation - Hyprland.focusedWorkspace; - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - - if (filtered.length === 0) - return false; - - for (let i = 0; i < filtered.length; i++) { - const toplevel = filtered[i]; - - let hyprToplevel = null; - if (Hyprland.toplevels) { - const hyprToplevels = Array.from(Hyprland.toplevels.values); - for (let j = 0; j < hyprToplevels.length; j++) { - if (hyprToplevels[j].wayland === toplevel) { - hyprToplevel = hyprToplevels[j]; - break; - } - } - } - - if (!hyprToplevel?.lastIpcObject) - continue; - - const ipc = hyprToplevel.lastIpcObject; - const at = ipc.at; - const size = ipc.size; - if (!at || !size) - continue; - - const monX = hyprToplevel.monitor?.x ?? 0; - const monY = hyprToplevel.monitor?.y ?? 0; - - const winX = at[0] - monX; - const winY = at[1] - monY; - const winW = size[0]; - const winH = size[1]; - - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - if (winY < dockThickness) - return true; - break; - case SettingsData.Position.Bottom: - if (winY + winH > screenHeight - dockThickness) - return true; - break; - case SettingsData.Position.Left: - if (winX < dockThickness) - return true; - break; - case SettingsData.Position.Right: - if (winX + winW > screenWidth - dockThickness) - return true; - break; - } - } - - return false; - } - - Timer { - id: revealHold - interval: 250 - repeat: false - onTriggered: dock.revealSticky = false - } - - property bool reveal: { - if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) { - return true; - } - - // Smart auto-hide: show dock when no windows overlap, hide when they do - if (SettingsData.dockSmartAutoHide) { - if (shouldHideForWindows) - return dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky; - return true; // No overlapping windows - show dock - } - - // Regular auto-hide: always hide unless hovering - return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky; - } - - onContextMenuOpenChanged: { - if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) { - revealSticky = true; - revealHold.restart(); - } - } - - Connections { - target: SettingsData - function onDockTransparencyChanged() { - dock.backgroundTransparency = SettingsData.dockTransparency; - } - } - - screen: modelData - visible: { - if (CompositorService.isNiri && NiriService.inOverview) { - return SettingsData.dockOpenOnOverview; - } - return SettingsData.showDock; - } - color: "transparent" - - exclusiveZone: { - if (!SettingsData.showDock || autoHide) - return -1; - if (barSpacing > 0) - return -1; - return px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin); - } - - property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35) - - implicitWidth: isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0 - implicitHeight: !isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0 - - Item { - id: maskItem - parent: dock.contentItem - visible: false - readonly property bool expanded: dock.reveal - x: { - const baseX = dockCore.x + dockMouseArea.x; - if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right) - return baseX - (expanded ? animationHeadroom + borderThickness : 0); - return baseX - (expanded ? borderThickness : 0); - } - y: { - const baseY = dockCore.y + dockMouseArea.y; - if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom) - return baseY - (expanded ? animationHeadroom + borderThickness : 0); - return baseY - (expanded ? borderThickness : 0); - } - width: dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0) - height: dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0) - } - - mask: Region { - item: maskItem - } - - property var hoveredButton: { - if (!dockApps.children[0]) { - return null; - } - const layoutItem = dockApps.children[0]; - const flowLayout = layoutItem.children[0]; - let repeater = null; - for (var i = 0; i < flowLayout.children.length; i++) { - const child = flowLayout.children[i]; - if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") { - repeater = child; - break; - } - } - if (!repeater || !repeater.itemAt) { - return null; - } - for (var i = 0; i < repeater.count; i++) { - const item = repeater.itemAt(i); - if (item && item.dockButton && item.dockButton.showTooltip) { - return item.dockButton; - } - } - return null; - } - - DankTooltip { - id: dockTooltip - targetScreen: dock.screen - } - - Timer { - id: tooltipRevealDelay - interval: 250 - repeat: false - onTriggered: dock.showTooltipForHoveredButton() - } - - function showTooltipForHoveredButton() { - dockTooltip.hide(); - if (!dock.hoveredButton || !dock.reveal || slideXAnimation.running || slideYAnimation.running) - return; - - const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0); - const tooltipText = dock.hoveredButton.tooltipText || ""; - if (!tooltipText) - return; - - const screenX = dock.screen ? (dock.screen.x || 0) : 0; - const screenY = dock.screen ? (dock.screen.y || 0) : 0; - const screenHeight = dock.screen ? dock.screen.height : 0; - - const gap = Theme.spacingS; - const bgMargin = barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness; - const btnW = dock.hoveredButton.width; - const btnH = dock.hoveredButton.height; - - if (!dock.isVertical) { - const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - const globalX = buttonGlobalPos.x + btnW / 2 + adjacentLeftBarWidth; - const tooltipHeight = 32; - const totalFromEdge = bgMargin + dockBackground.height + dock.borderThickness + gap; - const screenRelativeY = isBottom ? (screenHeight - totalFromEdge - tooltipHeight) : totalFromEdge; - dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false); - return; - } - - const isLeft = SettingsData.dockPosition === SettingsData.Position.Left; - const screenWidth = dock.screen ? dock.screen.width : 0; - const totalFromEdge = bgMargin + dockBackground.width + dock.borderThickness + gap; - const tooltipX = isLeft ? (screenX + totalFromEdge) : (screenX + screenWidth - totalFromEdge); - const screenRelativeY = buttonGlobalPos.y - screenY + btnH / 2 + adjacentTopBarHeight; - dockTooltip.show(tooltipText, tooltipX, screenRelativeY, dock.screen, isLeft, !isLeft); - } - - Connections { - target: dock - function onRevealChanged() { - if (!dock.reveal) { - tooltipRevealDelay.stop(); - dockTooltip.hide(); - } else { - tooltipRevealDelay.restart(); - } - } - - function onHoveredButtonChanged() { - dock.showTooltipForHoveredButton(); - } - } - - Item { - id: dockCore - anchors.fill: parent - x: isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? animationHeadroom : 0 - y: !isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? animationHeadroom : 0 - - Connections { - target: dockMouseArea - function onContainsMouseChanged() { - if (dockMouseArea.containsMouse) { - dock.revealSticky = true; - revealHold.stop(); - } else { - if (dock.autoHide && !dock.contextMenuOpen) { - revealHold.restart(); - } - } - } - } - - MouseArea { - id: dockMouseArea - property real currentScreen: modelData ? modelData : dock.screen - property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920 - property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080 - property real maxDockWidth: screenWidth * 0.98 - property real maxDockHeight: screenHeight * 0.98 - - height: { - if (dock.isVertical) { - // Keep the taller hit area regardless of the reveal state to prevent shrinking loop - return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight); - } - return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1; - } - width: { - if (dock.isVertical) { - return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1; - } - // Keep the wider hit area regardless of the reveal state to prevent shrinking loop - return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth); - } - anchors { - top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined - bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined - horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined - left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined - right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined - verticalCenter: dock.isVertical ? parent.verticalCenter : undefined - } - hoverEnabled: true - acceptedButtons: Qt.NoButton - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Item { - id: dockContainer - anchors.fill: parent - clip: false - - transform: Translate { - id: dockSlide - x: { - if (!dock.isVertical) - return 0; - if (dock.reveal) - return 0; - const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10; - if (SettingsData.dockPosition === SettingsData.Position.Right) { - return hideDistance; - } else { - return -hideDistance; - } - } - y: { - if (dock.isVertical) - return 0; - if (dock.reveal) - return 0; - const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10; - if (SettingsData.dockPosition === SettingsData.Position.Bottom) { - return hideDistance; - } else { - return -hideDistance; - } - } - - Behavior on x { - NumberAnimation { - id: slideXAnimation - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on y { - NumberAnimation { - id: slideYAnimation - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dockBackground - objectName: "dockBackground" - anchors { - top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined) : undefined - bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined - horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined - left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined) : undefined - right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined - verticalCenter: dock.isVertical ? parent.verticalCenter : undefined - } - anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - - implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2) - implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2) - width: implicitWidth - height: implicitHeight - - layer.enabled: true - clip: false - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, backgroundTransparency) - radius: Theme.cornerRadius - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - } - - Shape { - id: dockBorderShape - x: dockBackground.x - borderThickness - y: dockBackground.y - borderThickness - width: dockBackground.width + borderThickness * 2 - height: dockBackground.height + borderThickness * 2 - visible: SettingsData.dockBorderEnabled && dock.hasApps - preferredRendererType: Shape.CurveRenderer - - readonly property real borderThickness: Math.max(1, dock.borderThickness) - readonly property real i: borderThickness / 2 - readonly property real cr: Theme.cornerRadius - readonly property real w: dockBackground.width - readonly property real h: dockBackground.height - - readonly property color borderColor: { - const opacity = SettingsData.dockBorderOpacity; - switch (SettingsData.dockBorderColor) { - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - default: - return Theme.withAlpha(Theme.surfaceText, opacity); - } - } - - ShapePath { - fillColor: "transparent" - strokeColor: dockBorderShape.borderColor - strokeWidth: dockBorderShape.borderThickness - joinStyle: ShapePath.RoundJoin - capStyle: ShapePath.FlatCap - - PathSvg { - path: { - const bt = dockBorderShape.borderThickness; - const i = dockBorderShape.i; - const cr = dockBorderShape.cr + bt - i; - const w = dockBorderShape.w; - const h = dockBorderShape.h; - - let d = `M ${i + cr} ${i}`; - d += ` L ${i + w + 2 * (bt - i) - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i)} ${i + cr}`; - d += ` L ${i + w + 2 * (bt - i)} ${i + h + 2 * (bt - i) - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i) - cr} ${i + h + 2 * (bt - i)}`; - d += ` L ${i + cr} ${i + h + 2 * (bt - i)}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h + 2 * (bt - i) - cr}`; - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - d += " Z"; - return d; - } - } - } - } - - DockApps { - id: dockApps - - anchors.top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? dockBackground.top : undefined) : undefined - anchors.bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? dockBackground.bottom : undefined) : undefined - anchors.horizontalCenter: !dock.isVertical ? dockBackground.horizontalCenter : undefined - anchors.left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? dockBackground.left : undefined) : undefined - anchors.right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? dockBackground.right : undefined) : undefined - anchors.verticalCenter: dock.isVertical ? dockBackground.verticalCenter : undefined - anchors.topMargin: !dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.bottomMargin: !dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.leftMargin: dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0 - - contextMenu: dockVariants.contextMenu - groupByApp: dock.groupByApp - isVertical: dock.isVertical - dockScreen: dock.screen - iconSize: dock.widgetHeight - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml deleted file mode 100644 index 1d9fb75..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml +++ /dev/null @@ -1,670 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Hyprland -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - clip: false - property var appData - property var contextMenu: null - property var dockApps: null - property int index: -1 - property var parentDockScreen: null - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property int targetIndex: -1 - property int originalIndex: -1 - property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - property bool showWindowTitle: false - property string windowTitle: "" - property bool isHovered: mouseArea.containsMouse && !dragging - property bool showTooltip: mouseArea.containsMouse && !dragging - property var cachedDesktopEntry: null - property real actualIconSize: 40 - property bool shouldShowIndicator: { - if (!appData) - return false; - if (appData.type === "window") - return true; - if (appData.type === "grouped") - return appData.windowCount > 0; - return appData.isRunning; - } - readonly property string coreIconColorOverride: SettingsData.dockLauncherLogoColorOverride - readonly property bool coreIconHasCustomColor: coreIconColorOverride !== "" && coreIconColorOverride !== "primary" && coreIconColorOverride !== "surface" - readonly property color effectiveCoreIconColor: { - if (coreIconColorOverride === "primary") - return Theme.primary; - if (coreIconColorOverride === "surface") - return Theme.surfaceText; - if (coreIconColorOverride !== "") - return coreIconColorOverride; - return Theme.surfaceText; - } - readonly property real effectiveCoreIconBrightness: coreIconHasCustomColor ? SettingsData.dockLauncherLogoBrightness : 0.0 - readonly property real effectiveCoreIconContrast: coreIconHasCustomColor ? SettingsData.dockLauncherLogoContrast : 0.0 - - function updateDesktopEntry() { - if (!appData || appData.appId === "__SEPARATOR__") { - cachedDesktopEntry = null; - return; - } - if (appData.isCoreApp) { - cachedDesktopEntry = null; - return; - } - const moddedId = Paths.moddedAppId(appData.appId); - cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId); - } - - Component.onCompleted: updateDesktopEntry() - - onAppDataChanged: updateDesktopEntry() - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - updateDesktopEntry(); - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - updateDesktopEntry(); - } - } - property bool isWindowFocused: { - if (!appData) { - return false; - } - - if (appData.type === "window") { - const toplevel = getToplevelObject(); - if (!toplevel) { - return false; - } - return toplevel.activated; - } else if (appData.type === "grouped") { - // For grouped apps, check if any window is focused - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === appData.appId && toplevel.activated) { - return true; - } - } - } - - return false; - } - property string tooltipText: { - if (!appData || !appData.appId) { - return ""; - } - - let appName; - if (appData.isCoreApp && appData.coreAppData) { - appName = appData.coreAppData.name || appData.appId; - } else { - appName = Paths.getAppName(appData.appId, cachedDesktopEntry); - } - - if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) { - const title = appData.type === "window" ? windowTitle : appData.windowTitle; - return appName + (title ? " • " + title : ""); - } - - return appName; - } - - function getToplevelObject() { - return appData?.toplevel || null; - } - - function getGroupedToplevels() { - return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []; - } - - function getHyprToplevelForWayland(waylandToplevel) { - if (!waylandToplevel || !CompositorService.isHyprland || !Hyprland.toplevels) - return null; - const hyprToplevels = Array.from(Hyprland.toplevels.values); - for (let i = 0; i < hyprToplevels.length; i++) { - if (hyprToplevels[i].wayland === waylandToplevel) - return hyprToplevels[i]; - } - return null; - } - - function getSpecialWorkspaceName(waylandToplevel) { - const hyprToplevel = getHyprToplevelForWayland(waylandToplevel); - if (!hyprToplevel) - return ""; - const wsName = String(hyprToplevel.lastIpcObject?.workspace?.name || hyprToplevel.workspace?.name || ""); - if (!wsName.startsWith("special:")) - return ""; - return wsName.slice("special:".length); - } - - function restoreSpecialWorkspaceWindow(waylandToplevel) { - if (!SettingsData.dockRestoreSpecialWorkspaceOnClick || !CompositorService.isHyprland || !waylandToplevel) - return false; - - const specialName = getSpecialWorkspaceName(waylandToplevel); - if (!specialName) - return false; - - Hyprland.dispatch("togglespecialworkspace " + specialName); - Qt.callLater(() => waylandToplevel.activate()); - return true; - } - onIsHoveredChanged: { - if (mouseArea.pressed || dragging) - return; - if (isHovered) { - exitAnimation.stop(); - if (!bounceAnimation.running) { - bounceAnimation.restart(); - } - } else { - bounceAnimation.stop(); - exitAnimation.restart(); - } - } - - readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - readonly property real animationDistance: actualIconSize - readonly property real animationDirection: { - if (SettingsData.dockPosition === SettingsData.Position.Bottom) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Top) - return 1; - if (SettingsData.dockPosition === SettingsData.Position.Right) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Left) - return 1; - return -1; - } - - SequentialAnimation { - id: bounceAnimation - - running: false - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.25 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - } - - NumberAnimation { - id: exitAnimation - - running: false - target: root - property: "hoverAnimOffset" - to: 0 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - Timer { - id: longPressTimer - - interval: 500 - repeat: false - onTriggered: { - if (appData && appData.isPinned) { - longPressing = true; - } - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - enabled: true - preventStealing: dragging || longPressing - cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && appData && appData.isPinned) { - dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - onReleased: mouse => { - longPressTimer.stop(); - - const wasDragging = dragging; - const didReorder = wasDragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps; - - if (didReorder) - dockApps.movePinnedApp(originalIndex, targetIndex); - - longPressing = false; - dragging = false; - dragAxisOffset = 0; - targetIndex = -1; - originalIndex = -1; - - if (dockApps) { - dockApps.draggedIndex = -1; - dockApps.dropTargetIndex = -1; - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - handleLeftClick(); - } - - function handleLeftClick() { - if (!appData) - return; - - switch (appData.type) { - case "pinned": - if (!appData.appId) - return; - if (appData.isCoreApp && appData.coreAppData) { - AppSearchService.executeCoreApp(appData.coreAppData); - return; - } - const pinnedEntry = cachedDesktopEntry; - if (pinnedEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": pinnedEntry.name || appData.appId, - "icon": pinnedEntry.icon ? String(pinnedEntry.icon) : "", - "exec": pinnedEntry.exec || "", - "comment": pinnedEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(pinnedEntry); - break; - case "window": - const windowToplevel = getToplevelObject(); - if (windowToplevel) { - if (restoreSpecialWorkspaceWindow(windowToplevel)) - return; - windowToplevel.activate(); - } - break; - case "grouped": - if (appData.windowCount === 0) { - if (!appData.appId) - return; - if (appData.isCoreApp && appData.coreAppData) { - AppSearchService.executeCoreApp(appData.coreAppData); - return; - } - const groupedEntry = cachedDesktopEntry; - if (groupedEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": groupedEntry.name || appData.appId, - "icon": groupedEntry.icon ? String(groupedEntry.icon) : "", - "exec": groupedEntry.exec || "", - "comment": groupedEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(groupedEntry); - } else if (appData.windowCount === 1) { - const groupedToplevel = getToplevelObject(); - if (groupedToplevel) { - if (restoreSpecialWorkspaceWindow(groupedToplevel)) - return; - groupedToplevel.activate(); - } - } else if (contextMenu) { - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - break; - } - } - onPositionChanged: mouse => { - if (longPressing && !dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2)); - if (distance > 5) { - dragging = true; - targetIndex = index; - originalIndex = index; - if (dockApps) { - dockApps.draggedIndex = index; - dockApps.dropTargetIndex = index; - } - } - } - - if (!dragging || !dockApps) - return; - - const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x); - dragAxisOffset = axisOffset; - - const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08)); - const itemSize = actualIconSize * 1.2 + spacing; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount - 1, originalIndex + slotOffset)); - - if (newTargetIndex !== targetIndex) { - targetIndex = newTargetIndex; - dockApps.dropTargetIndex = newTargetIndex; - } - } - onClicked: mouse => { - if (!appData) - return; - - if (mouse.button === Qt.MiddleButton) { - switch (appData.type) { - case "window": - appData.toplevel?.close(); - break; - case "grouped": - if (contextMenu) { - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - break; - default: - if (!appData.appId) - return; - const desktopEntry = cachedDesktopEntry; - if (desktopEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": desktopEntry.name || appData.appId, - "icon": desktopEntry.icon ? String(desktopEntry.icon) : "", - "exec": desktopEntry.exec || "", - "comment": desktopEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(desktopEntry); - break; - } - } else if (mouse.button === Qt.RightButton) { - if (!contextMenu) - return; - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - } - } - - property real hoverAnimOffset: 0 - - Item { - id: visualContent - anchors.fill: parent - - transform: Translate { - id: iconTransform - x: { - if (dragging && !isVertical) - return dragAxisOffset; - if (!dragging && isVertical) - return hoverAnimOffset; - return 0; - } - y: { - if (dragging && isVertical) - return dragAxisOffset; - if (!dragging && !isVertical) - return hoverAnimOffset; - return 0; - } - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) - border.width: 2 - border.color: Theme.primary - visible: dragging - z: -1 - } - - AppIconRenderer { - id: coreIcon - - anchors.centerIn: parent - iconSize: actualIconSize - iconValue: appData && appData.isCoreApp && appData.coreAppData ? (appData.coreAppData.icon || "") : "" - colorOverride: effectiveCoreIconColor - brightnessOverride: effectiveCoreIconBrightness - contrastOverride: effectiveCoreIconContrast - fallbackText: "?" - visible: iconValue !== "" - } - - IconImage { - id: iconImg - - anchors.centerIn: parent - implicitSize: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms") ? actualIconSize * 0.85 : actualIconSize - source: { - if (!appData || appData.appId === "__SEPARATOR__") { - return ""; - } - if (appData.isCoreApp && appData.coreAppData) { - return ""; - } - return Paths.getAppIcon(appData.appId, cachedDesktopEntry); - } - mipmap: true - smooth: true - asynchronous: true - visible: status === Image.Ready && !coreIcon.visible - layer.enabled: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms") - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - Rectangle { - width: actualIconSize - height: actualIconSize - anchors.centerIn: parent - visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId) - color: Theme.surfaceLight - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.primarySelected - - Text { - anchors.centerIn: parent - text: { - if (!appData || !appData.appId) { - return "?"; - } - - let appName; - if (appData.isCoreApp && appData.coreAppData) { - appName = appData.coreAppData.name || appData.appId; - } else { - appName = Paths.getAppName(appData.appId, cachedDesktopEntry); - } - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: Math.max(8, parent.width * 0.35) - color: Theme.primary - font.weight: Font.Bold - } - } - - DankIcon { - anchors.centerIn: parent - size: actualIconSize - name: "sports_esports" - color: Theme.surfaceText - visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && Paths.isSteamApp(appData.appId) - } - - Loader { - anchors.horizontalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.horizontalCenter - anchors.verticalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? parent.verticalCenter : undefined - anchors.bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined - anchors.top: SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined - anchors.left: SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined - anchors.right: SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined - anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Top ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.leftMargin: SettingsData.dockPosition === SettingsData.Position.Left ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.rightMargin: SettingsData.dockPosition === SettingsData.Position.Right ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - - sourceComponent: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? columnIndicator : rowIndicator - - visible: root.shouldShowIndicator - } - } - - Component { - id: rowIndicator - - Row { - spacing: 2 - - Repeater { - model: { - if (!appData) - return 0; - if (appData.type === "grouped") { - return Math.min(appData.windowCount, 4); - } else if (appData.type === "window" || appData.isRunning) { - return 1; - } - return 0; - } - - Rectangle { - width: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2); - } - height: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return Math.max(2, actualIconSize * 0.05); - } - radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius - color: { - if (!appData) { - return "transparent"; - } - - if (appData.type !== "grouped" || appData.windowCount === 1) { - if (isWindowFocused) { - return Theme.primary; - } - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - - if (appData.type === "grouped" && appData.windowCount > 1) { - const groupToplevels = getGroupedToplevels(); - if (index < groupToplevels.length && groupToplevels[index].activated) { - return Theme.primary; - } - } - - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - } - } - } - } - - Component { - id: columnIndicator - - Column { - spacing: 2 - - Repeater { - model: { - if (!appData) - return 0; - if (appData.type === "grouped") { - return Math.min(appData.windowCount, 4); - } else if (appData.type === "window" || appData.isRunning) { - return 1; - } - return 0; - } - - Rectangle { - width: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return Math.max(2, actualIconSize * 0.05); - } - height: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2); - } - radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius - color: { - if (!appData) { - return "transparent"; - } - - if (appData.type !== "grouped" || appData.windowCount === 1) { - if (isWindowFocused) { - return Theme.primary; - } - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - - if (appData.type === "grouped" && appData.windowCount > 1) { - const groupToplevels = getGroupedToplevels(); - if (index < groupToplevels.length && groupToplevels[index].activated) { - return Theme.primary; - } - } - - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml deleted file mode 100644 index dbdc517..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml +++ /dev/null @@ -1,646 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Services - -Item { - id: root - - property var contextMenu: null - property bool requestDockShow: false - property int pinnedAppCount: 0 - property bool groupByApp: false - property bool isVertical: false - property var dockScreen: null - property real iconSize: 40 - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - property int maxVisibleApps: SettingsData.dockMaxVisibleApps - property int maxVisibleRunningApps: SettingsData.dockMaxVisibleRunningApps - property bool overflowExpanded: false - property int overflowItemCount: 0 - - readonly property real baseImplicitWidth: isVertical ? baseAppHeight : baseAppWidth - readonly property real baseImplicitHeight: isVertical ? baseAppWidth : baseAppHeight - readonly property real baseAppWidth: { - let count = 0; - const items = repeater.dockItems; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (item.isInOverflow) - continue; - if (item.type === "separator") { - count += 8 / (iconSize * 1.2); - } else { - count += 1; - } - } - return count * (iconSize * 1.2) + Math.max(0, count - 1) * layoutFlow.spacing; - } - readonly property real baseAppHeight: iconSize - - clip: false - implicitWidth: isVertical ? appLayout.height : appLayout.width - implicitHeight: isVertical ? appLayout.width : appLayout.height - - function dockIndexToPinnedIndex(dockIndex) { - if (!SettingsData.dockLauncherEnabled) - return dockIndex; - - const launcherPos = SessionData.dockLauncherPosition; - return dockIndex < launcherPos ? dockIndex : dockIndex - 1; - } - - function movePinnedApp(fromDockIndex, toDockIndex) { - const fromPinnedIndex = dockIndexToPinnedIndex(fromDockIndex); - const toPinnedIndex = dockIndexToPinnedIndex(toDockIndex); - - if (fromPinnedIndex === toPinnedIndex) - return; - - const currentPinned = [...(SessionData.pinnedApps || [])]; - if (fromPinnedIndex < 0 || fromPinnedIndex >= currentPinned.length || toPinnedIndex < 0 || toPinnedIndex >= currentPinned.length) - return; - - const movedApp = currentPinned.splice(fromPinnedIndex, 1)[0]; - currentPinned.splice(toPinnedIndex, 0, movedApp); - SessionData.setPinnedApps(currentPinned); - } - - Item { - id: appLayout - width: layoutFlow.width - height: layoutFlow.height - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - anchors.horizontalCenter: root.isVertical ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.isVertical ? parent.verticalCenter : undefined - anchors.left: root.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined - anchors.right: root.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined - anchors.top: root.isVertical ? undefined : parent.top - - Flow { - id: layoutFlow - flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight - spacing: Math.min(8, Math.max(4, root.iconSize * 0.08)) - - Repeater { - id: repeater - - property var dockItems: [] - - model: ScriptModel { - values: repeater.dockItems - objectProp: "uniqueKey" - } - - Component.onCompleted: updateModel() - - function isOnScreen(toplevel, screenName) { - if (!toplevel.screens) - return false; - for (let i = 0; i < toplevel.screens.length; i++) { - if (toplevel.screens[i]?.name === screenName) - return true; - } - return false; - } - - function getCoreAppData(appId) { - if (typeof AppSearchService === "undefined") - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].builtInPluginId === appId) - return coreApps[i]; - } - return null; - } - - function getCoreAppDataByTitle(windowTitle) { - if (typeof AppSearchService === "undefined" || !windowTitle) - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].name === windowTitle) - return coreApps[i]; - } - return null; - } - - function buildBaseItems() { - const items = []; - const pinnedApps = [...(SessionData.pinnedApps || [])]; - const allToplevels = CompositorService.sortedToplevels; - const sortedToplevels = (SettingsData.dockIsolateDisplays && root.dockScreen) ? allToplevels.filter(t => isOnScreen(t, root.dockScreen.name)) : allToplevels; - - if (root.groupByApp) { - return buildGroupedItems(pinnedApps, sortedToplevels); - } - return buildUngroupedItems(pinnedApps, sortedToplevels); - } - - function buildGroupedItems(pinnedApps, sortedToplevels) { - const items = []; - const appGroups = new Map(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - appGroups.set(appId, { - appId: appId, - isPinned: true, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - }); - - sortedToplevels.forEach((toplevel, index) => { - const rawAppId = toplevel.appId || "unknown"; - let appId = Paths.moddedAppId(rawAppId); - let coreAppData = null; - - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) - appId = coreAppData.builtInPluginId; - } - - if (!appGroups.has(appId)) { - appGroups.set(appId, { - appId: appId, - isPinned: false, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - } - appGroups.get(appId).windows.push({ - toplevel: toplevel, - index: index - }); - }); - - const pinnedGroups = []; - const unpinnedGroups = []; - - appGroups.forEach((group, appId) => { - const firstWindow = group.windows.length > 0 ? group.windows[0] : null; - const item = { - uniqueKey: "grouped_" + appId, - type: "grouped", - appId: appId, - toplevel: firstWindow ? firstWindow.toplevel : null, - isPinned: group.isPinned, - isRunning: group.windows.length > 0, - windowCount: group.windows.length, - allWindows: group.windows, - isCoreApp: group.isCoreApp || false, - coreAppData: group.coreAppData || null, - isInOverflow: false - }; - (group.isPinned ? pinnedGroups : unpinnedGroups).push(item); - }); - - pinnedGroups.forEach(item => items.push(item)); - insertLauncher(items); - - if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) { - items.push(createSeparator("separator_grouped")); - } - unpinnedGroups.forEach(item => items.push(item)); - - root.pinnedAppCount = pinnedGroups.length + (SettingsData.dockLauncherEnabled ? 1 : 0); - return { - items, - pinnedCount: pinnedGroups.length, - runningCount: unpinnedGroups.length - }; - } - - function buildUngroupedItems(pinnedApps, sortedToplevels) { - const items = []; - const runningAppIds = new Set(); - const windowItems = []; - - sortedToplevels.forEach((toplevel, index) => { - let uniqueKey = "window_" + index; - if (CompositorService.isHyprland && Hyprland.toplevels) { - const hyprlandToplevels = Array.from(Hyprland.toplevels.values); - for (let i = 0; i < hyprlandToplevels.length; i++) { - if (hyprlandToplevels[i].wayland === toplevel) { - uniqueKey = "window_" + hyprlandToplevels[i].address; - break; - } - } - } - - const rawAppId = toplevel.appId || "unknown"; - const moddedAppId = Paths.moddedAppId(rawAppId); - let coreAppData = null; - let isCoreApp = false; - - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) - isCoreApp = true; - } - - const finalAppId = isCoreApp ? coreAppData.builtInPluginId : moddedAppId; - windowItems.push({ - uniqueKey: uniqueKey, - type: "window", - appId: finalAppId, - toplevel: toplevel, - isPinned: false, - isRunning: true, - isCoreApp: isCoreApp, - coreAppData: coreAppData, - isInOverflow: false - }); - runningAppIds.add(finalAppId); - }); - - const remainingWindowItems = windowItems.slice(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - const matchIndex = remainingWindowItems.findIndex(item => item.appId === appId); - - if (matchIndex !== -1) { - const windowItem = remainingWindowItems.splice(matchIndex, 1)[0]; - windowItem.isPinned = true; - windowItem.uniqueKey = "pinned_" + appId; - if (!windowItem.isCoreApp && coreAppData) { - windowItem.isCoreApp = true; - windowItem.coreAppData = coreAppData; - } - items.push(windowItem); - } else { - items.push({ - uniqueKey: "pinned_" + appId, - type: "pinned", - appId: appId, - toplevel: null, - isPinned: true, - isRunning: runningAppIds.has(appId), - isCoreApp: coreAppData !== null, - coreAppData: coreAppData, - isInOverflow: false - }); - } - }); - - root.pinnedAppCount = pinnedApps.length + (SettingsData.dockLauncherEnabled ? 1 : 0); - insertLauncher(items); - - if (pinnedApps.length > 0 && remainingWindowItems.length > 0) { - items.push(createSeparator("separator_ungrouped")); - } - remainingWindowItems.forEach(item => items.push(item)); - - return { - items, - pinnedCount: pinnedApps.length, - runningCount: remainingWindowItems.length - }; - } - - function insertLauncher(targetArray) { - if (!SettingsData.dockLauncherEnabled) - return; - const launcherItem = { - uniqueKey: "launcher_button", - type: "launcher", - appId: "__LAUNCHER__", - toplevel: null, - isPinned: true, - isRunning: false - }; - const pos = Math.max(0, Math.min(SessionData.dockLauncherPosition, targetArray.length)); - targetArray.splice(pos, 0, launcherItem); - } - - function createSeparator(key) { - return { - uniqueKey: key, - type: "separator", - appId: "__SEPARATOR__", - toplevel: null, - isPinned: false, - isRunning: false - }; - } - - function markAsOverflow(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: true - }; - } - - function markAsVisible(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: false - }; - } - - function applyOverflow(baseResult) { - const { - items - } = baseResult; - const maxPinned = root.maxVisibleApps; - const maxRunning = root.maxVisibleRunningApps; - - const pinnedItems = items.filter(i => (i.type === "pinned" || i.type === "grouped" || i.type === "window") && i.isPinned && i.appId !== "__LAUNCHER__"); - const runningItems = items.filter(i => (i.type === "window" || i.type === "grouped") && i.isRunning && !i.isPinned); - - const pinnedOverflow = maxPinned > 0 && pinnedItems.length > maxPinned; - const runningOverflow = maxRunning > 0 && runningItems.length > maxRunning; - - if (!pinnedOverflow && !runningOverflow) { - root.overflowItemCount = 0; - return items.map(i => markAsVisible(i)); - } - - const visiblePinnedKeys = new Set(pinnedOverflow ? pinnedItems.slice(0, maxPinned).map(i => i.uniqueKey) : pinnedItems.map(i => i.uniqueKey)); - const visibleRunningKeys = new Set(runningOverflow ? runningItems.slice(0, maxRunning).map(i => i.uniqueKey) : runningItems.map(i => i.uniqueKey)); - - const overflowPinnedCount = pinnedOverflow ? pinnedItems.length - maxPinned : 0; - const overflowRunningCount = runningOverflow ? runningItems.length - maxRunning : 0; - const totalOverflow = overflowPinnedCount + overflowRunningCount; - root.overflowItemCount = totalOverflow; - - const finalItems = []; - let addedSeparator = false; - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - switch (item.type) { - case "launcher": - finalItems.push(item); - break; - case "separator": - break; - case "pinned": - case "grouped": - case "window": - if (item.isPinned && item.appId !== "__LAUNCHER__") { - if (visiblePinnedKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } else if (item.isRunning && !item.isPinned) { - if (!addedSeparator && finalItems.length > 0) { - finalItems.push(createSeparator("separator_overflow")); - addedSeparator = true; - } - if (visibleRunningKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } - break; - } - } - - if (totalOverflow > 0) { - const toggleIndex = finalItems.findIndex(i => i.type === "separator"); - const insertPos = toggleIndex >= 0 ? toggleIndex : finalItems.length; - finalItems.splice(insertPos, 0, { - uniqueKey: "overflow_toggle", - type: "overflow-toggle", - appId: "__OVERFLOW_TOGGLE__", - toplevel: null, - isPinned: false, - isRunning: false, - overflowCount: totalOverflow - }); - } - - return finalItems; - } - - function updateModel() { - const baseResult = buildBaseItems(); - dockItems = applyOverflow(baseResult); - } - - delegate: Item { - id: delegateItem - - property var dockButton: itemData.type === "launcher" ? launcherButton : button - property var itemData: modelData - readonly property bool isOverflowToggle: itemData.type === "overflow-toggle" - readonly property bool isInOverflow: itemData.isInOverflow === true - - clip: false - z: (itemData.type === "launcher" ? launcherButton.dragging : button.dragging) ? 100 : 0 - visible: !isInOverflow || root.overflowExpanded - opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1 - scale: (isInOverflow && !root.overflowExpanded) ? 0.8 : 1 - - width: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)) - height: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)) - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - property real shiftOffset: { - if (root.draggedIndex < 0 || !itemData.isPinned || itemData.type === "separator") - return 0; - if (model.index === root.draggedIndex) - return 0; - - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const myIdx = model.index; - const shiftAmount = root.iconSize * 1.2 + layoutFlow.spacing; - - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVertical ? 0 : delegateItem.shiftOffset - y: root.isVertical ? delegateItem.shiftOffset : 0 - - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - visible: itemData.type === "separator" - width: root.isVertical ? root.iconSize * 0.5 : 2 - height: root.isVertical ? 2 : root.iconSize * 0.5 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - radius: 1 - anchors.centerIn: parent - } - - DockOverflowButton { - id: overflowButton - visible: isOverflowToggle - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - overflowCount: itemData.overflowCount || 0 - overflowExpanded: root.overflowExpanded - isVertical: root.isVertical - onClicked: root.overflowExpanded = !root.overflowExpanded - } - - DockLauncherButton { - id: launcherButton - visible: itemData.type === "launcher" - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - dockApps: root - index: model.index - } - - DockAppButton { - id: button - visible: !isOverflowToggle && itemData.type !== "separator" && itemData.type !== "launcher" - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - appData: itemData - contextMenu: root.contextMenu - dockApps: root - index: model.index - parentDockScreen: root.dockScreen - showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped" - windowTitle: { - const title = itemData?.toplevel?.title || "(Unnamed)"; - return title.length > 50 ? title.substring(0, 47) + "..." : title; - } - } - } - } - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - repeater.updateModel(); - } - } - - Connections { - target: SessionData - function onPinnedAppsChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - function onDockLauncherPositionChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - } - - Connections { - target: SettingsData - function onDockIsolateDisplaysChanged() { - repeater.updateModel(); - } - function onDockLauncherEnabledChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - function onDockMaxVisibleAppsChanged() { - repeater.updateModel(); - } - function onDockMaxVisibleRunningAppsChanged() { - repeater.updateModel(); - } - } - - onGroupByAppChanged: repeater.updateModel() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml deleted file mode 100644 index 183f331..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml +++ /dev/null @@ -1,585 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WindowBlur { - targetWindow: root - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: root.visible ? menuContainer.width : 0 - blurHeight: root.visible ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:dock-context-menu" - - property var appData: null - property var anchorItem: null - property real dockVisibleHeight: 40 - property int margin: 10 - property bool hidePin: false - property var desktopEntry: null - property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms" - property var dockApps: null - - function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen, parentDockApps) { - if (dockScreen) { - root.screen = dockScreen; - } - - anchorItem = button; - appData = data; - dockVisibleHeight = dockHeight || 40; - hidePin = hidePinOption || false; - desktopEntry = entry || null; - dockApps = parentDockApps || null; - - visible = true; - } - function close() { - visible = false; - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - property point anchorPos: Qt.point(screen.width / 2, screen.height - 100) - - onAnchorItemChanged: updatePosition() - onVisibleChanged: { - if (visible) { - updatePosition(); - } - } - - function updatePosition() { - if (!anchorItem) { - anchorPos = Qt.point(screen.width / 2, screen.height - 100); - return; - } - - const dockWindow = anchorItem.Window.window; - if (!dockWindow) { - anchorPos = Qt.point(screen.width / 2, screen.height - 100); - return; - } - - const buttonPosInDock = anchorItem.mapToItem(dockWindow.contentItem, 0, 0); - let actualDockHeight = root.dockVisibleHeight; - - function findDockBackground(item) { - if (item.objectName === "dockBackground") { - return item; - } - for (var i = 0; i < item.children.length; i++) { - const found = findDockBackground(item.children[i]); - if (found) { - return found; - } - } - return null; - } - - const dockBackground = findDockBackground(dockWindow.contentItem); - let actualDockWidth = dockWindow.width; - if (dockBackground) { - actualDockHeight = dockBackground.height; - actualDockWidth = dockBackground.width; - } - - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - const dockMargin = SettingsData.dockMargin + 16; - let buttonScreenX, buttonScreenY; - - if (isVertical) { - const dockContentHeight = dockWindow.height; - const screenHeight = root.screen.height; - const dockTopMargin = Math.round((screenHeight - dockContentHeight) / 2); - buttonScreenY = dockTopMargin + buttonPosInDock.y + anchorItem.height / 2; - - if (SettingsData.dockPosition === SettingsData.Position.Right) { - buttonScreenX = root.screen.width - actualDockWidth - dockMargin - 20; - } else { - buttonScreenX = actualDockWidth + dockMargin + 20; - } - } else { - const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - - if (isDockAtBottom) { - buttonScreenY = root.screen.height - actualDockHeight - dockMargin - 20; - } else { - buttonScreenY = actualDockHeight + dockMargin + 20; - } - - const dockContentWidth = dockWindow.width; - const screenWidth = root.screen.width; - const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2); - buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2; - } - - anchorPos = Qt.point(buttonScreenX, buttonScreenY); - } - - Rectangle { - id: menuContainer - - x: { - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - if (isVertical) { - const isDockAtRight = SettingsData.dockPosition === SettingsData.Position.Right; - if (isDockAtRight) { - return Math.max(10, root.anchorPos.x - width + 30); - } else { - return Math.min(root.width - width - 10, root.anchorPos.x - 30); - } - } else { - const left = 10; - const right = root.width - width - 10; - const want = root.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - if (isVertical) { - const top = 10; - const bottom = root.height - height - 10; - const want = root.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - if (isDockAtBottom) { - return Math.max(10, root.anchorPos.y - height + 30); - } else { - return Math.min(root.height - height - 10, root.anchorPos.y - 30); - } - } - } - - width: Math.min(400, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: menuColumn.implicitHeight + Theme.spacingS * 2 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - - opacity: root.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - // Window list for grouped apps - Repeater { - model: { - if (!root.appData || root.appData.type !== "grouped") - return []; - - const toplevels = []; - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === root.appData.appId) { - toplevels.push(toplevel); - } - } - return toplevels; - } - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: windowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: closeButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: (modelData && modelData.title) ? modelData.title : I18n.tr("(Unnamed)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - Rectangle { - id: closeButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - radius: 10 - color: closeMouseArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: closeMouseArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData && modelData.close) { - modelData.close(); - } - root.close(); - } - } - } - - DankRipple { - id: windowRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: windowArea - anchors.fill: parent - anchors.rightMargin: 24 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData && modelData.activate) { - modelData.activate(); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.appData) - return false; - if (root.appData.type !== "grouped") - return false; - return root.appData.windowCount > 0; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: root.desktopEntry && root.desktopEntry.actions ? root.desktopEntry.actions : [] - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: actionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Item { - anchors.verticalCenter: parent.verticalCenter - width: 16 - height: 16 - visible: modelData.icon && modelData.icon !== "" - - IconImage { - anchors.fill: parent - source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : "" - smooth: true - asynchronous: true - visible: status === Image.Ready - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: actionRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: actionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionService.launchDesktopAction(root.desktopEntry, modelData); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) { - return false; - } - return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand); - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.hidePin - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: root.appData && root.appData.isPinned ? "keep_off" : "push_pin" - size: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: pinRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: pinArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!root.appData) - return; - - if (root.appData.isPinned) { - SessionData.removePinnedApp(root.appData.appId); - } else { - SessionData.addPinnedApp(root.appData.appId); - } - root.close(); - } - } - } - - Rectangle { - visible: { - const hasNvidia = !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand; - const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)); - const hasPinOption = !root.hidePin; - const hasContentAbove = hasPinOption || hasNvidia; - return hasContentAbove && hasWindow; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: nvidiaArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "memory" - size: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Launch on dGPU") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: nvidiaRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: nvidiaArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.desktopEntry) { - SessionService.launchDesktopEntry(root.desktopEntry, true); - } - root.close(); - } - } - } - - Rectangle { - visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)) - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "close" - size: 14 - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.type === "grouped" ? I18n.tr("Close All Windows") : I18n.tr("Close Window") - font.pixelSize: Theme.fontSizeSmall - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: closeRipple - rippleColor: Theme.error - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: closeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.appData?.type === "window") { - root.appData?.toplevel?.close(); - } else if (root.appData?.type === "grouped") { - root.appData?.allWindows?.forEach(window => window.toplevel?.close()); - } - root.close(); - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - onClicked: root.close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml deleted file mode 100644 index 84b52ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml +++ /dev/null @@ -1,296 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - clip: false - property var dockApps: null - property int index: -1 - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property int targetIndex: -1 - property int originalIndex: -1 - property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - property bool isHovered: mouseArea.containsMouse && !dragging - property bool showTooltip: mouseArea.containsMouse && !dragging - property real actualIconSize: 40 - - readonly property string tooltipText: I18n.tr("Applications") - - readonly property color effectiveLogoColor: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override === "primary") - return Theme.primary; - if (override === "surface") - return Theme.surfaceText; - if (override !== "") - return override; - return Theme.surfaceText; - } - - onIsHoveredChanged: { - if (mouseArea.pressed || dragging) - return; - if (isHovered) { - exitAnimation.stop(); - if (!bounceAnimation.running) { - bounceAnimation.restart(); - } - } else { - bounceAnimation.stop(); - exitAnimation.restart(); - } - } - - readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - readonly property real animationDistance: actualIconSize - readonly property real animationDirection: { - if (SettingsData.dockPosition === SettingsData.Position.Bottom) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Top) - return 1; - if (SettingsData.dockPosition === SettingsData.Position.Right) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Left) - return 1; - return -1; - } - - SequentialAnimation { - id: bounceAnimation - - running: false - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.25 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - } - - NumberAnimation { - id: exitAnimation - - running: false - target: root - property: "hoverAnimOffset" - to: 0 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - Timer { - id: longPressTimer - - interval: 500 - repeat: false - onTriggered: { - longPressing = true; - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - enabled: true - preventStealing: dragging || longPressing - cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) { - dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - onReleased: mouse => { - longPressTimer.stop(); - - const wasDragging = dragging; - const didReorder = wasDragging && targetIndex >= 0 && dockApps; - - if (didReorder) { - SessionData.setDockLauncherPosition(targetIndex); - } - - longPressing = false; - dragging = false; - dragAxisOffset = 0; - targetIndex = -1; - originalIndex = -1; - - if (dockApps) { - dockApps.draggedIndex = -1; - dockApps.dropTargetIndex = -1; - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - PopoutService.toggleDankLauncherV2(); - } - onPositionChanged: mouse => { - if (longPressing && !dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2)); - if (distance > 5) { - dragging = true; - targetIndex = index; - originalIndex = index; - if (dockApps) { - dockApps.draggedIndex = index; - dockApps.dropTargetIndex = index; - } - } - } - - if (!dragging || !dockApps) - return; - - const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x); - dragAxisOffset = axisOffset; - - const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08)); - const itemSize = actualIconSize * 1.2 + spacing; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount, originalIndex + slotOffset)); - - if (newTargetIndex !== targetIndex) { - targetIndex = newTargetIndex; - dockApps.dropTargetIndex = newTargetIndex; - } - } - } - - property real hoverAnimOffset: 0 - - Item { - id: visualContent - anchors.fill: parent - - transform: Translate { - x: dragging && !isVertical ? dragAxisOffset : (!dragging && isVertical ? hoverAnimOffset : 0) - y: dragging && isVertical ? dragAxisOffset : (!dragging && !isVertical ? hoverAnimOffset : 0) - } - - Item { - anchors.centerIn: parent - width: actualIconSize - height: actualIconSize - - DankIcon { - visible: SettingsData.dockLauncherLogoMode === "apps" - anchors.centerIn: parent - name: "apps" - size: actualIconSize - 4 - color: Theme.widgetIconColor - } - - SystemLogo { - visible: SettingsData.dockLauncherLogoMode === "os" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - colorOverride: effectiveLogoColor - brightnessOverride: SettingsData.dockLauncherLogoBrightness - contrastOverride: SettingsData.dockLauncherLogoContrast - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "dank" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogo.svg" - layer.enabled: effectiveLogoColor !== "" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - } - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc) - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - asynchronous: true - source: { - if (CompositorService.isNiri) { - return "file://" + Theme.shellDir + "/assets/niri.svg"; - } else if (CompositorService.isHyprland) { - return "file://" + Theme.shellDir + "/assets/hyprland.svg"; - } else if (CompositorService.isDwl) { - return "file://" + Theme.shellDir + "/assets/mango.png"; - } else if (CompositorService.isSway) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isScroll) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isMiracle) { - return "file://" + Theme.shellDir + "/assets/miraclewm.svg"; - } else if (CompositorService.isLabwc) { - return "file://" + Theme.shellDir + "/assets/labwc.png"; - } - return ""; - } - layer.enabled: effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - brightness: { - SettingsData.dockLauncherLogoBrightness; - } - contrast: { - SettingsData.dockLauncherLogoContrast; - } - } - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "custom" && SettingsData.dockLauncherLogoCustomPath !== "" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - asynchronous: true - source: SettingsData.dockLauncherLogoCustomPath ? "file://" + SettingsData.dockLauncherLogoCustomPath.replace("file://", "") : "" - layer.enabled: effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - brightness: SettingsData.dockLauncherLogoBrightness - contrast: SettingsData.dockLauncherLogoContrast - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml deleted file mode 100644 index 0d6b439..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property real actualIconSize: 40 - property int overflowCount: 0 - property bool overflowExpanded: false - property bool isVertical: false - - signal clicked - - Rectangle { - id: buttonBackground - anchors.centerIn: parent - width: actualIconSize - height: actualIconSize - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1) - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - id: arrowIcon - anchors.centerIn: parent - size: actualIconSize * 0.6 - name: "expand_more" - color: Theme.surfaceText - rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) - - Behavior on rotation { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - } - - Rectangle { - visible: overflowCount > 0 && !overflowExpanded && SettingsData.dockShowOverflowBadge - anchors.right: buttonBackground.right - anchors.top: buttonBackground.top - anchors.rightMargin: -4 - anchors.topMargin: -4 - width: Math.max(18, badgeText.width + 8) - height: 18 - radius: 9 - color: Theme.primary - z: 10 - - StyledText { - id: badgeText - anchors.centerIn: parent - text: `+${overflowCount}` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.onPrimary - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js deleted file mode 100644 index fcce181..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js +++ /dev/null @@ -1,20 +0,0 @@ -.pragma library - -function readBoolOverride(envReader, names, fallbackValue) { - for (let i = 0; i < names.length; i++) { - const name = names[i]; - const raw = envReader(name); - if (raw === undefined || raw === null || raw === "") - continue; - - const normalized = String(raw).trim().toLowerCase(); - if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") - return true; - if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") - return false; - - console.warn("Invalid boolean override for", name + ":", raw, "- trying next override/fallback"); - } - - return fallbackValue; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml deleted file mode 100644 index da949d3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml +++ /dev/null @@ -1,128 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import "GreetdEnv.js" as GreetdEnv - -Singleton { - id: root - - readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter" - readonly property string sessionConfigPath: greetCfgDir + "/session.json" - readonly property string memoryFile: greetCfgDir + "/.local/state/memory.json" - readonly property bool rememberLastSession: GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_SESSION", "DMS_SAVE_SESSION"], true) - readonly property bool rememberLastUser: GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_USER", "DMS_SAVE_USERNAME"], true) - - property string lastSessionId: "" - property string lastSuccessfulUser: "" - property bool memoryReady: false - property bool isLightMode: false - property bool nightModeEnabled: false - - Component.onCompleted: { - loadMemory(); - loadSessionConfig(); - } - - function loadMemory() { - parseMemory(memoryFileView.text()); - } - - function loadSessionConfig() { - parseSessionConfig(sessionConfigFileView.text()); - } - - function parseSessionConfig(content) { - try { - if (content && content.trim()) { - const config = JSON.parse(content); - isLightMode = config.isLightMode !== undefined ? config.isLightMode : false; - nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false; - } - } catch (e) { - console.warn("Failed to parse greeter session config:", e); - } - } - - function parseMemory(content) { - try { - if (!content || !content.trim()) - return; - const memory = JSON.parse(content); - lastSessionId = rememberLastSession ? (memory.lastSessionId || "") : ""; - lastSuccessfulUser = rememberLastUser ? (memory.lastSuccessfulUser || "") : ""; - if (!rememberLastSession || !rememberLastUser) - saveMemory(); - } catch (e) { - console.warn("Failed to parse greetd memory:", e); - } - } - - function saveMemory() { - let memory = {}; - if (rememberLastSession && lastSessionId) - memory.lastSessionId = lastSessionId; - if (rememberLastUser && lastSuccessfulUser) - memory.lastSuccessfulUser = lastSuccessfulUser; - memoryFileView.setText(JSON.stringify(memory, null, 2)); - } - - function setLastSessionId(id) { - if (!rememberLastSession) { - if (lastSessionId !== "") { - lastSessionId = ""; - saveMemory(); - } - return; - } - lastSessionId = id || ""; - saveMemory(); - } - - function setLastSuccessfulUser(username) { - if (!rememberLastUser) { - if (lastSuccessfulUser !== "") { - lastSuccessfulUser = ""; - saveMemory(); - } - return; - } - lastSuccessfulUser = username || ""; - saveMemory(); - } - - FileView { - id: memoryFileView - path: root.memoryFile - blockLoading: false - blockWrites: false - atomicWrites: true - watchChanges: false - printErrors: false - onLoaded: { - parseMemory(memoryFileView.text()); - root.memoryReady = true; - } - onLoadFailed: { - root.memoryReady = true; - } - } - - FileView { - id: sessionConfigFileView - path: root.sessionConfigPath - blockLoading: false - blockWrites: true - atomicWrites: false - watchChanges: false - printErrors: true - onLoaded: { - parseSessionConfig(sessionConfigFileView.text()); - } - onLoadFailed: error => { - console.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml deleted file mode 100644 index e1f670c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml +++ /dev/null @@ -1,199 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import "GreetdEnv.js" as GreetdEnv - -Singleton { - id: root - - readonly property string configPath: { - const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"; - return greetCfgDir + "/settings.json"; - } - - readonly property string _greeterCacheDir: { - const i = root.configPath.lastIndexOf("/"); - return i >= 0 ? root.configPath.substring(0, i) : ""; - } - readonly property string greeterWallpaperOverridePath: root._greeterCacheDir ? (root._greeterCacheDir + "/greeter_wallpaper_override.jpg") : "" - - property string currentThemeName: "purple" - property bool settingsLoaded: false - property string customThemeFile: "" - property var registryThemeVariants: ({}) - property string matugenScheme: "scheme-tonal-spot" - property bool use24HourClock: true - property bool showSeconds: false - property bool padHours12Hour: false - property bool greeterUse24HourClock: true - property bool greeterShowSeconds: false - property bool greeterPadHours12Hour: false - property string greeterLockDateFormat: "" - property string greeterFontFamily: "" - property string greeterWallpaperFillMode: "" - property bool useFahrenheit: false - property bool nightModeEnabled: false - property string weatherLocation: "New York, NY" - property string weatherCoordinates: "40.7128,-74.0060" - property bool useAutoLocation: false - property bool weatherEnabled: true - property string iconTheme: "System Default" - property bool useOSLogo: false - property string osLogoColorOverride: "" - property real osLogoBrightness: 0.5 - property real osLogoContrast: 1 - property string fontFamily: "Inter Variable" - property string monoFontFamily: "Fira Code" - property int fontWeight: Font.Normal - property real fontScale: 1.0 - property real cornerRadius: 12 - property string widgetBackgroundColor: "sch" - property string lockDateFormat: "" - property bool lockScreenShowPowerActions: true - property bool lockScreenShowProfileImage: true - property bool rememberLastSession: true - property bool rememberLastUser: true - property bool greeterEnableFprint: false - property bool greeterEnableU2f: false - property string greeterWallpaperPath: "" - property bool powerActionConfirm: true - property real powerActionHoldDuration: 0.5 - property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] - property string powerMenuDefaultAction: "logout" - property bool powerMenuGridLayout: false - property var screenPreferences: ({}) - property int animationSpeed: 2 - property string wallpaperFillMode: "Fill" - - function parseSettings(content) { - try { - let settings = {}; - if (content && content.trim()) { - settings = JSON.parse(content); - } - - const envRememberLastSession = GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_SESSION", "DMS_SAVE_SESSION"], undefined); - const envRememberLastUser = GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_USER", "DMS_SAVE_USERNAME"], undefined); - - currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "purple"; - customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""; - registryThemeVariants = settings.registryThemeVariants !== undefined ? - settings.registryThemeVariants : ({}); - matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"; - use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true; - showSeconds = settings.showSeconds !== undefined ? settings.showSeconds : false; - padHours12Hour = settings.padHours12Hour !== undefined ? settings.padHours12Hour : false; - greeterUse24HourClock = settings.greeterUse24HourClock !== undefined ? settings.greeterUse24HourClock : use24HourClock; - greeterShowSeconds = settings.greeterShowSeconds !== undefined ? settings.greeterShowSeconds : showSeconds; - greeterPadHours12Hour = settings.greeterPadHours12Hour !== undefined ? settings.greeterPadHours12Hour : padHours12Hour; - greeterLockDateFormat = settings.greeterLockDateFormat !== undefined ? settings.greeterLockDateFormat : ""; - greeterFontFamily = settings.greeterFontFamily !== undefined ? settings.greeterFontFamily : ""; - greeterWallpaperFillMode = settings.greeterWallpaperFillMode !== undefined ? settings.greeterWallpaperFillMode : ""; - useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false; - nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false; - weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"; - weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"; - useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false; - weatherEnabled = settings.weatherEnabled !== undefined ? settings.weatherEnabled : true; - iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"; - useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false; - osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""; - osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5; - osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1; - fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : Theme.defaultFontFamily; - monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : Theme.defaultMonoFontFamily; - fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal; - fontScale = settings.fontScale !== undefined ? settings.fontScale : 1.0; - cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12; - widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"; - lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""; - lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true; - lockScreenShowProfileImage = settings.lockScreenShowProfileImage !== undefined ? settings.lockScreenShowProfileImage : true; - if (envRememberLastSession !== undefined) { - rememberLastSession = envRememberLastSession; - } else { - rememberLastSession = settings.greeterRememberLastSession !== undefined ? settings.greeterRememberLastSession : settings.rememberLastSession !== undefined ? settings.rememberLastSession : true; - } - if (envRememberLastUser !== undefined) { - rememberLastUser = envRememberLastUser; - } else { - rememberLastUser = settings.greeterRememberLastUser !== undefined ? settings.greeterRememberLastUser : settings.rememberLastUser !== undefined ? settings.rememberLastUser : true; - } - greeterEnableFprint = settings.greeterEnableFprint !== undefined ? settings.greeterEnableFprint : false; - greeterEnableU2f = settings.greeterEnableU2f !== undefined ? settings.greeterEnableU2f : false; - greeterWallpaperPath = settings.greeterWallpaperPath !== undefined ? settings.greeterWallpaperPath : ""; - powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true; - powerActionHoldDuration = settings.powerActionHoldDuration !== undefined ? settings.powerActionHoldDuration : 0.5; - powerMenuActions = settings.powerMenuActions !== undefined ? settings.powerMenuActions : ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]; - powerMenuDefaultAction = settings.powerMenuDefaultAction !== undefined ? settings.powerMenuDefaultAction : "logout"; - powerMenuGridLayout = settings.powerMenuGridLayout !== undefined ? settings.powerMenuGridLayout : false; - screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({}); - animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2; - wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill"; - - if (typeof Theme !== "undefined") { - if (currentThemeName === "custom" && customThemeFile) { - Theme.loadCustomThemeFromFile(customThemeFile); - } - Theme.applyGreeterTheme(currentThemeName); - } - } catch (e) { - console.warn("Failed to parse greetd settings:", e); - } finally { - settingsLoaded = true; - } - } - - function getEffectiveTimeFormat() { - const use24 = greeterUse24HourClock; - const secs = greeterShowSeconds; - const pad = greeterPadHours12Hour; - if (use24) - return secs ? "hh:mm:ss" : "hh:mm"; - if (pad) - return secs ? "hh:mm:ss AP" : "hh:mm AP"; - return secs ? "h:mm:ss AP" : "h:mm AP"; - } - - function getEffectiveLockDateFormat() { - const fmt = (greeterLockDateFormat !== undefined && greeterLockDateFormat !== "") ? greeterLockDateFormat : lockDateFormat; - return fmt && fmt.length > 0 ? fmt : Locale.LongFormat; - } - - function getEffectiveWallpaperFillMode() { - return (greeterWallpaperFillMode && greeterWallpaperFillMode !== "") ? greeterWallpaperFillMode : wallpaperFillMode; - } - - function getEffectiveFontFamily() { - return (greeterFontFamily && greeterFontFamily !== "") ? greeterFontFamily : fontFamily; - } - - function getFilteredScreens(componentId) { - const prefs = screenPreferences && screenPreferences[componentId] || ["all"]; - if (prefs.includes("all")) { - return Quickshell.screens; - } - return Quickshell.screens.filter(screen => prefs.includes(screen.name)); - } - - FileView { - id: settingsFile - path: root.configPath - blockLoading: false - blockWrites: true - atomicWrites: false - watchChanges: false - printErrors: true - onLoaded: { - parseSettings(settingsFile.text()); - } - onLoadFailed: error => { - console.warn("Failed to load greetd settings:", error); - root.parseSettings(""); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml deleted file mode 100644 index fa82315..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml +++ /dev/null @@ -1,1908 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Qt.labs.folderlistmodel -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell.Services.Greetd -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Lock - -Item { - id: root - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - readonly property string xdgDataDirs: Quickshell.env("XDG_DATA_DIRS") - property string screenName: "" - property string hyprlandCurrentLayout: "" - property string hyprlandKeyboard: "" - property int hyprlandLayoutCount: 0 - property bool isPrimaryScreen: !Quickshell.screens?.length || screenName === Quickshell.screens[0]?.name - - signal launchRequested - - property bool weatherInitialized: false - property bool awaitingExternalAuth: false - property bool pendingPasswordResponse: false - property bool passwordSubmitRequested: false - property bool cancelingExternalAuthForPassword: false - property int defaultAuthTimeoutMs: 10000 - property int externalAuthTimeoutMs: 30000 - property int memoryFlushDelayMs: 120 - property string pendingLaunchCommand: "" - property var pendingLaunchEnv: [] - property int passwordFailureCount: 0 - property int passwordAttemptLimitHint: 0 - property string authFeedbackMessage: "" - property string greetdPamText: "" - property string systemAuthPamText: "" - property string commonAuthPamText: "" - property string passwordAuthPamText: "" - property string systemLoginPamText: "" - property string systemLocalLoginPamText: "" - property string commonAuthPcPamText: "" - property string loginPamText: "" - property string faillockConfigText: "" - property bool greeterWallpaperOverrideExists: false - property string externalAuthAutoStartedForUser: "" - property int passwordSessionTransitionRetryCount: 0 - property int maxPasswordSessionTransitionRetries: 2 - property bool fprintdProbeComplete: false - property bool fprintdHasDevice: false - // Falls back to PAM-only detection until the fprintd D-Bus probe completes. - readonly property bool greeterPamHasFprint: greeterPamStackHasModule("pam_fprintd") && (!fprintdProbeComplete || fprintdHasDevice) - readonly property bool greeterPamHasU2f: greeterPamStackHasModule("pam_u2f") - readonly property bool greeterExternalAuthAvailable: (greeterPamHasFprint && GreetdSettings.greeterEnableFprint) || (greeterPamHasU2f && GreetdSettings.greeterEnableU2f) - readonly property bool greeterPamHasExternalAuth: greeterPamHasFprint || greeterPamHasU2f - - function initWeatherService() { - if (weatherInitialized) - return; - if (!GreetdSettings.settingsLoaded) - return; - if (!GreetdSettings.weatherEnabled) - return; - weatherInitialized = true; - WeatherService.addRef(); - WeatherService.forceRefresh(); - } - - function stripPamComment(line) { - if (!line) - return ""; - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("//")) - return ""; - const hashIdx = trimmed.indexOf("//"); - if (hashIdx >= 0) - return trimmed.substring(0, hashIdx).trim(); - return trimmed; - } - - function pamModuleEnabled(pamText, moduleName) { - if (!pamText || !moduleName) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(moduleName)) - return true; - } - return false; - } - - function pamTextIncludesFile(pamText, filename) { - if (!pamText || !filename) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(filename) && (line.includes("include") || line.includes("substack") || line.startsWith("@include"))) - return true; - } - return false; - } - - function greeterPamStackHasModule(moduleName) { - if (pamModuleEnabled(greetdPamText, moduleName)) - return true; - const includedPamStacks = [ - ["system-auth", systemAuthPamText], - ["common-auth", commonAuthPamText], - ["password-auth", passwordAuthPamText], - ["system-login", systemLoginPamText], - ["system-local-login", systemLocalLoginPamText], - ["common-auth-pc", commonAuthPcPamText], - ["login", loginPamText] - ]; - for (let i = 0; i < includedPamStacks.length; i++) { - const stack = includedPamStacks[i]; - if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName)) - return true; - } - return false; - } - - function usesPamLockoutPolicy(pamText) { - if (!pamText) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes("pam_faillock.so") || line.includes("pam_tally2.so") || line.includes("pam_tally.so")) - return true; - } - return false; - } - - function parsePamLineDenyValue(pamText) { - if (!pamText) - return -1; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (!line.includes("pam_faillock.so") && !line.includes("pam_tally2.so") && !line.includes("pam_tally.so")) - continue; - const denyMatch = line.match(/\bdeny\s*=\s*(\d+)\b/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function parseFaillockDenyValue(configText) { - if (!configText) - return -1; - const lines = configText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - const denyMatch = line.match(/^deny\s*=\s*(\d+)\s*$/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function refreshPasswordAttemptPolicyHint() { - const pamSources = [greetdPamText, systemAuthPamText, commonAuthPamText, passwordAuthPamText, systemLoginPamText, systemLocalLoginPamText, commonAuthPcPamText, loginPamText]; - let lockoutConfigured = false; - let denyFromPam = -1; - for (let i = 0; i < pamSources.length; i++) { - const source = pamSources[i]; - if (!source) - continue; - if (usesPamLockoutPolicy(source)) - lockoutConfigured = true; - const denyValue = parsePamLineDenyValue(source); - if (denyValue >= 0 && (denyFromPam < 0 || denyValue < denyFromPam)) - denyFromPam = denyValue; - } - - if (!lockoutConfigured) { - passwordAttemptLimitHint = 0; - return; - } - - const denyFromConfig = parseFaillockDenyValue(faillockConfigText); - if (denyFromConfig >= 0) { - passwordAttemptLimitHint = denyFromConfig; - return; - } - - if (denyFromPam >= 0) { - passwordAttemptLimitHint = denyFromPam; - return; - } - - // pam_faillock default deny value when no explicit config is set. - passwordAttemptLimitHint = 3; - } - - function isLikelyLockoutMessage(message) { - const lower = (message || "").toLowerCase(); - return lower.includes("account is locked") || lower.includes("too many") || lower.includes("maximum number of") || lower.includes("auth_err"); - } - - function currentAuthMessage() { - if (GreeterState.pamState === "error") - return I18n.tr("Authentication error - try again"); - if (GreeterState.pamState === "max") - return I18n.tr("Too many failed attempts - account may be locked"); - if (GreeterState.pamState === "fail") { - if (passwordAttemptLimitHint > 0) { - const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint)); - const remaining = Math.max(passwordAttemptLimitHint - attempt, 0); - if (remaining > 0) { - return I18n.tr("Incorrect password - attempt %1 of %2 (lockout may follow)").arg(attempt).arg(passwordAttemptLimitHint); - } - return I18n.tr("Incorrect password - next failures may trigger account lockout"); - } - return I18n.tr("Incorrect password"); - } - return ""; - } - - function clearAuthFeedback() { - GreeterState.pamState = ""; - authFeedbackMessage = ""; - } - - function resetPasswordSessionTransition(clearSubmitRequest) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - if (clearSubmitRequest) - passwordSubmitRequested = false; - } - - Connections { - target: GreetdSettings - function onSettingsLoadedChanged() { - if (GreetdSettings.settingsLoaded) { - initWeatherService(); - if (isPrimaryScreen) { - applyLastSuccessfulUser(); - finalizeSessionSelection(); - } - } - } - - function onRememberLastUserChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastUser && GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - applyLastSuccessfulUser(); - } - - function onRememberLastSessionChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastSession && GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - finalizeSessionSelection(); - } - } - - FileView { - id: greetdPamWatcher - path: "/etc/pam.d/greetd" - printErrors: false - onLoaded: { - root.greetdPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.greetdPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemAuthPamWatcher - path: "/etc/pam.d/system-auth" - printErrors: false - onLoaded: { - root.systemAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPamWatcher - path: "/etc/pam.d/common-auth" - printErrors: false - onLoaded: { - root.commonAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: passwordAuthPamWatcher - path: "/etc/pam.d/password-auth" - printErrors: false - onLoaded: { - root.passwordAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.passwordAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLoginPamWatcher - path: "/etc/pam.d/system-login" - printErrors: false - onLoaded: { - root.systemLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLocalLoginPamWatcher - path: "/etc/pam.d/system-local-login" - printErrors: false - onLoaded: { - root.systemLocalLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLocalLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPcPamWatcher - path: "/etc/pam.d/common-auth-pc" - printErrors: false - onLoaded: { - root.commonAuthPcPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPcPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: loginPamWatcher - path: "/etc/pam.d/login" - printErrors: false - onLoaded: { - root.loginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.loginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: faillockConfigWatcher - path: "/etc/security/faillock.conf" - printErrors: false - onLoaded: { - root.faillockConfigText = text(); - root.refreshPasswordAttemptPolicyHint(); - } - onLoadFailed: { - root.faillockConfigText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - Component.onCompleted: { - initWeatherService(); - refreshPasswordAttemptPolicyHint(); - - if (isPrimaryScreen) - applyLastSuccessfulUser(); - - if (CompositorService.isHyprland) - updateHyprlandLayout(); - - fprintdDeviceProbe.running = true; - } - - function applyLastSuccessfulUser() { - if (!GreetdSettings.settingsLoaded || !GreetdSettings.rememberLastUser) - return; - const lastUser = GreetdMemory.lastSuccessfulUser; - if (lastUser && !GreeterState.showPasswordInput && !GreeterState.username) { - GreeterState.username = lastUser; - GreeterState.usernameInput = lastUser; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(lastUser); - maybeAutoStartExternalAuth(); - } - } - - function submitUsername(rawValue) { - const user = (rawValue || "").trim(); - if (!user) - return; - if (GreeterState.username !== user) { - passwordFailureCount = 0; - clearAuthFeedback(); - externalAuthAutoStartedForUser = ""; - } - GreeterState.username = user; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(user); - GreeterState.passwordBuffer = ""; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - maybeAutoStartExternalAuth(); - } - - function submitBufferedPassword() { - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - // Some PAM stacks expect an explicit empty response to advance U2F/fprint or fail normally. - Greetd.respond(GreeterState.passwordBuffer || ""); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - return true; - } - - function requestPasswordSessionTransition() { - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && !hasPasswordBuffer) - return; - if (cancelingExternalAuthForPassword) - return; - if (passwordSessionTransitionRetryCount >= maxPasswordSessionTransitionRetries) { - pendingPasswordResponse = false; - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - resetPasswordSessionTransition(true); - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - return; - } - cancelingExternalAuthForPassword = true; - passwordSessionTransitionRetryCount = passwordSessionTransitionRetryCount + 1; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - Greetd.cancelSession(); - } - - function startAuthSession(submitPassword) { - submitPassword = submitPassword === true; - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (GreeterState.unlocking) - return; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (Greetd.state !== GreetdState.Inactive) { - if (pendingPasswordResponse && submitPassword) - submitBufferedPassword(); - else if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (cancelingExternalAuthForPassword) { - if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (!submitPassword && !hasPasswordBuffer && !root.greeterExternalAuthAvailable) - return; - pendingPasswordResponse = false; - passwordSubmitRequested = submitPassword; - awaitingExternalAuth = !submitPassword && !hasPasswordBuffer && root.greeterExternalAuthAvailable; - // Use greeterExternalAuthAvailable so systems with pam_fprintd but no hardware don't incur the 30 s wait. - const waitingOnPamExternalBeforePassword = submitPassword && root.greeterExternalAuthAvailable; - authTimeout.interval = (awaitingExternalAuth || waitingOnPamExternalBeforePassword) ? externalAuthTimeoutMs : defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.createSession(GreeterState.username); - } - - function maybeAutoStartExternalAuth() { - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (!root.greeterExternalAuthAvailable) - return; - if (GreeterState.unlocking || Greetd.state !== GreetdState.Inactive) - return; - if (passwordSubmitRequested || cancelingExternalAuthForPassword) - return; - if (GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0) - return; - if (externalAuthAutoStartedForUser === GreeterState.username) - return; - - externalAuthAutoStartedForUser = GreeterState.username; - startAuthSession(false); - } - - function isExternalAuthPrompt(message, responseRequired) { - // Non-response PAM messages commonly represent waiting states (fprint/U2F/token touch). - return !responseRequired; - } - - Component.onDestruction: { - if (weatherInitialized) - WeatherService.removeRef(); - } - - function updateHyprlandLayout() { - if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true; - } - } - - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - if (!mainKeyboard) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - return; - } - hyprlandKeyboard = mainKeyboard.name; - if (mainKeyboard.active_keymap) { - const parts = mainKeyboard.active_keymap.split(" "); - hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase(); - } else { - hyprlandCurrentLayout = ""; - } - hyprlandLayoutCount = mainKeyboard.layout ? mainKeyboard.layout.split(",").length : 0; - } catch (e) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - } - } - } - } - - // Probe fprintd D-Bus for physically enrolled scanners to eliminate PAM stack false-positives. - Process { - id: fprintdDeviceProbe - running: false - // sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable, - // keeping the PAM-only fallback active in those cases. - command: ["sh", "-c", - "command -v gdbus >/dev/null 2>&1 || { echo PROBE_UNAVAILABLE; exit 0; }; " + - "gdbus call --system " + - "--dest net.reactivated.Fprint " + - "--object-path /net/reactivated/Fprint/Manager " + - "--method net.reactivated.Fprint.Manager.GetDevices 2>/dev/null " + - "|| echo PROBE_UNAVAILABLE"] - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("PROBE_UNAVAILABLE")) - return; // PAM-only fallback stays active - root.fprintdHasDevice = text.includes("objectpath"); - root.fprintdProbeComplete = true; - root.maybeAutoStartExternalAuth(); - } - } - onExited: function(exitCode, exitStatus) { - if (!root.fprintdProbeComplete) - root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") - updateHyprlandLayout(); - } - } - - Connections { - target: GreetdMemory - enabled: isPrimaryScreen - function onLastSuccessfulUserChanged() { - applyLastSuccessfulUser(); - } - function onMemoryReadyChanged() { - finalizeSessionSelection(); - } - } - - Connections { - target: GreeterState - function onUsernameChanged() { - if (GreeterState.username) { - PortalService.getGreeterUserProfileImage(GreeterState.username); - } - } - } - - FileView { - id: greeterWallpaperOverrideFile - path: GreetdSettings.greeterWallpaperOverridePath - printErrors: false - watchChanges: true - onLoaded: root.greeterWallpaperOverrideExists = true - onLoadFailed: root.greeterWallpaperOverrideExists = false - } - - Connections { - target: GreetdSettings - function onGreeterWallpaperOverridePathChanged() { - if (!GreetdSettings.greeterWallpaperOverridePath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - function onGreeterWallpaperPathChanged() { - if (!GreetdSettings.greeterWallpaperPath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - } - - DankBackdrop { - anchors.fill: parent - screenName: root.screenName - visible: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return false; - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return !currentWallpaper || currentWallpaper === "" || (currentWallpaper && currentWallpaper.startsWith("#")); - } - } - - Image { - id: wallpaperBackground - - anchors.fill: parent - source: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return encodeFileUrl(GreetdSettings.greeterWallpaperOverridePath); - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; - } - fillMode: Theme.getFillMode(GreetdSettings.getEffectiveWallpaperFillMode()) - smooth: true - asynchronous: false - cache: true - visible: source !== "" - layer.enabled: true - - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - blur: 0.8 - blurMax: 32 - blurMultiplier: 1 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.4 - } - - SystemClock { - id: systemClock - precision: SystemClock.Seconds - } - - Rectangle { - anchors.fill: parent - color: "transparent" - - Item { - id: clockContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: 60 - width: parent.width - height: clockText.implicitHeight - - Row { - id: clockText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - spacing: 0 - - property string fullTimeStr: { - const format = GreetdSettings.getEffectiveTimeFormat(); - return systemClock.date.toLocaleTimeString(I18n.locale(), format); - } - property var timeParts: fullTimeStr.split(':') - property string hours: timeParts[0] || "" - property string minutes: timeParts[1] || "" - property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : "" - property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '') - property string ampm: { - const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i); - return match ? match[0].trim() : ""; - } - property bool hasSeconds: timeParts.length > 2 - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[1] : clockText.hours.length > 0 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - } - - StyledText { - width: 75 - text: clockText.minutes.length > 0 ? clockText.minutes[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.minutes.length > 1 ? clockText.minutes[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockText.hasSeconds ? ":" : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 0 ? clockText.seconds[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 1 ? clockText.seconds[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 20 - text: " " - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - - StyledText { - text: clockText.ampm - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - } - } - - StyledText { - id: dateText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: clockContainer.bottom - anchors.topMargin: 4 - text: { - return systemClock.date.toLocaleDateString(I18n.locale(), GreetdSettings.getEffectiveLockDateFormat()); - } - font.pixelSize: Theme.fontSizeXLarge - color: "white" - opacity: 0.9 - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dateText.bottom - anchors.topMargin: Theme.spacingL - width: 380 - height: 140 - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - RowLayout { - spacing: Theme.spacingL - Layout.fillWidth: true - - DankCircularImage { - Layout.preferredWidth: 60 - Layout.preferredHeight: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - if (PortalService.profileImage.startsWith("/")) - return encodeFileUrl(PortalService.profileImage); - return PortalService.profileImage; - } - fallbackIcon: "person" - visible: GreetdSettings.lockScreenShowProfileImage - } - - Rectangle { - property bool showPassword: false - - Layout.fillWidth: true - Layout.preferredHeight: 60 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: inputField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) - border.width: inputField.activeFocus ? 2 : 1 - - DankIcon { - id: lockIcon - - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - name: GreeterState.showPasswordInput ? "lock" : "person" - size: 20 - color: inputField.activeFocus ? Theme.primary : Theme.surfaceVariantText - } - - TextInput { - id: inputField - - property bool syncingFromState: false - - anchors.fill: parent - anchors.leftMargin: lockIcon.width + Theme.spacingM * 2 - anchors.rightMargin: { - let margin = Theme.spacingM; - if (GreeterState.showPasswordInput && revealButton.visible) { - margin += revealButton.width; - } - if (externalAuthButton.visible) { - margin += externalAuthButton.width; - } - if (virtualKeyboardButton.visible) { - margin += virtualKeyboardButton.width; - } - if (enterButton.visible) { - margin += enterButton.width + 2; - } - return margin; - } - opacity: 0 - focus: true - echoMode: GreeterState.showPasswordInput ? (parent.showPassword ? TextInput.Normal : TextInput.Password) : TextInput.Normal - onTextChanged: { - if (syncingFromState) - return; - if (GreeterState.showPasswordInput) { - GreeterState.passwordBuffer = text; - if (!text || text.length === 0) - root.passwordSubmitRequested = false; - } else { - GreeterState.usernameInput = text; - } - } - onAccepted: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (text.trim()) { - root.submitUsername(text); - syncingFromState = true; - text = ""; - syncingFromState = false; - } - } - } - - Component.onCompleted: { - syncingFromState = true; - text = GreeterState.showPasswordInput ? GreeterState.passwordBuffer : GreeterState.usernameInput; - syncingFromState = false; - if (isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - onVisibleChanged: { - if (visible && isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - } - - KeyboardController { - id: keyboard_controller - target: inputField - rootObject: root - } - - StyledText { - id: placeholder - - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.unlocking) { - return I18n.tr("Logging in..."); - } - if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) { - return I18n.tr("Authenticating..."); - } - if (GreeterState.showPasswordInput) { - return I18n.tr("Password..."); - } - return I18n.tr("Username..."); - } - color: (GreeterState.unlocking || (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse)) ? Theme.primary : Theme.outline - font.pixelSize: Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.showPasswordInput) { - if (parent.showPassword) { - return GreeterState.passwordBuffer; - } - return "•".repeat(GreeterState.passwordBuffer.length); - } - return GreeterState.usernameInput; - } - color: Theme.surfaceText - font.pixelSize: (GreeterState.showPasswordInput && !parent.showPassword) ? Theme.fontSizeLarge : Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length > 0 : GreeterState.usernameInput.length > 0) ? 1 : 0 - clip: true - elide: Text.ElideNone - horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - DankActionButton { - id: revealButton - - anchors.right: externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: parent.showPassword ? "visibility_off" : "visibility" - buttonSize: 32 - visible: GreeterState.showPasswordInput && GreeterState.passwordBuffer.length > 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: parent.showPassword = !parent.showPassword - } - DankActionButton { - id: externalAuthButton - - anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: root.greeterPamHasFprint ? "fingerprint" : "key" - buttonSize: 32 - visible: GreeterState.showPasswordInput && root.greeterExternalAuthAvailable && GreeterState.passwordBuffer.length === 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: root.startAuthSession(false) - } - DankActionButton { - id: virtualKeyboardButton - - anchors.right: enterButton.visible ? enterButton.left : parent.right - anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard" - buttonSize: 32 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: { - if (keyboard_controller.isKeyboardActive) { - keyboard_controller.hide(); - } else { - keyboard_controller.show(); - } - } - } - - DankActionButton { - id: enterButton - - anchors.right: parent.right - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard_return" - buttonSize: 36 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: true - onClicked: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (inputField.text.trim()) { - root.submitUsername(inputField.text); - inputField.text = ""; - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - Layout.fillWidth: true - Layout.preferredHeight: 38 - Layout.topMargin: -Theme.spacingS - Layout.bottomMargin: -Theme.spacingS - text: root.authFeedbackMessage - color: Theme.error - font.pixelSize: Theme.fontSizeSmall - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 2 - opacity: root.authFeedbackMessage !== "" ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 0 - Layout.preferredWidth: switchUserRow.width + Theme.spacingL * 2 - Layout.preferredHeight: 40 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: GreeterState.showPasswordInput ? 1 : 0 - enabled: GreeterState.showPasswordInput - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: switchUserRow - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "people" - size: Theme.iconSize - 4 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Switch User") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: !GreeterState.unlocking && Greetd.state === GreetdState.Inactive && GreeterState.showPasswordInput - onClicked: { - GreeterState.reset(); - root.externalAuthAutoStartedForUser = ""; - inputField.text = ""; - PortalService.profileImage = ""; - } - } - } - } - } - - Row { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXL - spacing: Theme.spacingL - - Item { - width: keyboardLayoutRow.width - height: keyboardLayoutRow.height - anchors.verticalCenter: parent.verticalCenter - visible: { - if (CompositorService.isNiri) { - return NiriService.keyboardLayoutNames.length > 1; - } else if (CompositorService.isHyprland) { - return hyprlandLayoutCount > 1; - } - return false; - } - - Row { - id: keyboardLayoutRow - spacing: 4 - - Item { - width: Theme.iconSize - height: Theme.iconSize - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: "white" - anchors.centerIn: parent - } - } - - Item { - width: childrenRect.width - height: Theme.iconSize - - StyledText { - text: { - if (CompositorService.isNiri) { - const layout = NiriService.getCurrentKeyboardLayoutName(); - if (!layout) - return ""; - const parts = layout.split(" "); - if (parts.length > 0) { - return parts[0].substring(0, 2).toUpperCase(); - } - return layout.substring(0, 2).toUpperCase(); - } else if (CompositorService.isHyprland) { - return hyprlandCurrentLayout; - } - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: keyboardLayoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]); - updateHyprlandLayout(); - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: { - const keyboardVisible = (CompositorService.isNiri && NiriService.keyboardLayoutNames.length > 1) || (CompositorService.isHyprland && hyprlandLayoutCount > 1); - return keyboardVisible && GreetdSettings.weatherEnabled && WeatherService.weather.available; - } - } - - Row { - spacing: 6 - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: (GreetdSettings.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) - - DankIcon { - name: NetworkService.networkStatus === "ethernet" ? "lan" : NetworkService.wifiSignalIcon - size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" - } - - DankIcon { - name: "bluetooth" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: BluetoothService.available && BluetoothService.enabled - } - - DankIcon { - name: { - if (!AudioService.sink?.audio) { - return "volume_up"; - } - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) { - return "volume_down"; - } - return "volume_up"; - } - size: Theme.iconSize - 2 - color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" - anchors.verticalCenter: parent.verticalCenter - visible: AudioService.sink && AudioService.sink.audio - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) - } - - Row { - spacing: 4 - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - - return "battery_1_bar"; - } - size: Theme.iconSize - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return "white"; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryLevel + "%" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - DankActionButton { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Theme.spacingXL - visible: GreetdSettings.lockScreenShowPowerActions - iconName: "power_settings_new" - iconColor: Theme.error - buttonSize: 40 - onClicked: powerMenu.show() - } - - Item { - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: Theme.spacingXL - width: Math.max(200, currentSessionMetrics.width + 80) - height: 60 - - StyledTextMetrics { - id: currentSessionMetrics - text: root.currentSessionName - } - - property real longestSessionWidth: { - let maxWidth = 0; - for (var i = 0; i < sessionMetricsRepeater.count; i++) { - const item = sessionMetricsRepeater.itemAt(i); - if (item && item.width > maxWidth) { - maxWidth = item.width; - } - } - return maxWidth; - } - - Repeater { - id: sessionMetricsRepeater - model: GreeterState.sessionList - delegate: StyledTextMetrics { - text: modelData - } - } - - DankDropdown { - id: sessionDropdown - anchors.fill: parent - text: "" - description: "" - currentValue: root.currentSessionName - options: GreeterState.sessionList - enableFuzzySearch: GreeterState.sessionList.length > 5 - popupWidthOffset: 0 - popupWidth: Math.max(250, parent.longestSessionWidth + 100) - openUpwards: true - alignPopupRight: true - onValueChanged: value => { - const idx = GreeterState.sessionList.indexOf(value); - if (idx < 0) - return; - GreeterState.currentSessionIndex = idx; - GreeterState.selectedSession = GreeterState.sessionExecs[idx]; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[idx]; - } - } - } - } - - property string currentSessionName: GreeterState.sessionList[GreeterState.currentSessionIndex] || "" - - function finalizeSessionSelection() { - if (GreeterState.sessionList.length === 0) - return; - if (!GreetdMemory.memoryReady) - return; - if (!GreetdSettings.settingsLoaded) - return; - - const savedSession = GreetdSettings.rememberLastSession ? GreetdMemory.lastSessionId : ""; - if (savedSession && GreetdSettings.rememberLastSession) { - for (var i = 0; i < GreeterState.sessionPaths.length; i++) { - if (GreeterState.sessionPaths[i] === savedSession) { - GreeterState.currentSessionIndex = i; - GreeterState.selectedSession = GreeterState.sessionExecs[i] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[i]; - return; - } - } - } - - GreeterState.currentSessionIndex = 0; - GreeterState.selectedSession = GreeterState.sessionExecs[0] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[0] || ""; - } - - property var sessionDirs: { - const homeDir = Quickshell.env("HOME") || ""; - const dirs = ["/usr/share/wayland-sessions", "/usr/share/xsessions", "/usr/local/share/wayland-sessions", "/usr/local/share/xsessions"]; - - if (homeDir) { - dirs.push(homeDir + "/.local/share/wayland-sessions"); - dirs.push(homeDir + "/.local/share/xsessions"); - } - - if (xdgDataDirs) { - xdgDataDirs.split(":").forEach(dir => { - if (dir) { - dirs.push(dir + "/wayland-sessions"); - dirs.push(dir + "/xsessions"); - } - }); - } - return dirs; - } - - property var _pendingFiles: ({}) - property int _pendingCount: 0 - - function _addSession(path, name, exec) { - if (!name || !exec || GreeterState.sessionList.includes(name)) - return; - GreeterState.sessionList = GreeterState.sessionList.concat([name]); - GreeterState.sessionExecs = GreeterState.sessionExecs.concat([exec]); - GreeterState.sessionPaths = GreeterState.sessionPaths.concat([path]); - } - - function _parseDesktopFile(content, path) { - let name = ""; - let exec = ""; - const lines = content.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!name && line.startsWith("Name=")) - name = line.substring(5).trim(); - else if (!exec && line.startsWith("Exec=")) - exec = line.substring(5).trim(); - if (name && exec) - break; - } - _addSession(path, name, exec); - } - - function _loadDesktopFile(filePath) { - if (_pendingFiles[filePath]) - return; - _pendingFiles[filePath] = true; - _pendingCount++; - - const loader = desktopFileLoader.createObject(root, { - "filePath": filePath - }); - } - - function _onFileLoaded(filePath) { - _pendingCount--; - if (_pendingCount === 0) - Qt.callLater(finalizeSessionSelection); - } - - Component { - id: desktopFileLoader - - FileView { - id: fv - property string filePath: "" - path: filePath - - onLoaded: { - root._parseDesktopFile(text(), filePath); - root._onFileLoaded(filePath); - fv.destroy(); - } - - onLoadFailed: { - root._onFileLoaded(filePath); - fv.destroy(); - } - } - } - - Repeater { - model: isPrimaryScreen ? sessionDirs : [] - - Item { - required property string modelData - - FolderListModel { - folder: encodeFileUrl(modelData) - nameFilters: ["*.desktop"] - showDirs: false - showDotAndDotDot: false - - onStatusChanged: { - if (status !== FolderListModel.Ready) - return; - for (let i = 0; i < count; i++) { - let fp = get(i, "filePath"); - if (fp.startsWith("file://")) - fp = fp.substring(7); - root._loadDesktopFile(fp); - } - } - } - } - } - - Connections { - target: Greetd - enabled: isPrimaryScreen - - function onAuthMessage(message, error, responseRequired, echoResponse) { - if (responseRequired) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - awaitingExternalAuth = false; - pendingPasswordResponse = true; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && hasPasswordBuffer) - passwordSubmitRequested = true; - if (passwordSubmitRequested && !root.submitBufferedPassword()) - passwordSubmitRequested = false; - if (passwordSubmitRequested || hasPasswordBuffer) { - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - } else { - authTimeout.stop(); - } - return; - } - pendingPasswordResponse = false; - const externalPrompt = root.isExternalAuthPrompt(message, responseRequired); - if (!passwordSubmitRequested) - awaitingExternalAuth = root.greeterExternalAuthAvailable && externalPrompt; - if (awaitingExternalAuth || (passwordSubmitRequested && externalPrompt && root.greeterPamHasExternalAuth)) - authTimeout.interval = externalAuthTimeoutMs; - else - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.respond(""); - } - - function onStateChanged() { - if (Greetd.state === GreetdState.Inactive) { - const resumePasswordSubmit = cancelingExternalAuthForPassword && passwordSubmitRequested; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - cancelingExternalAuthForPassword = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - if (resumePasswordSubmit) { - Qt.callLater(function() { - root.startAuthSession(true); - }); - return; - } - resetPasswordSessionTransition(true); - } - } - - function onReadyToLaunch() { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - passwordFailureCount = 0; - clearAuthFeedback(); - const sessionCmd = GreeterState.selectedSession || GreeterState.sessionExecs[GreeterState.currentSessionIndex]; - const sessionPath = GreeterState.selectedSessionPath || GreeterState.sessionPaths[GreeterState.currentSessionIndex]; - if (!sessionCmd) { - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - return; - } - - GreeterState.unlocking = true; - launchTimeout.restart(); - if (GreetdSettings.rememberLastSession) { - GreetdMemory.setLastSessionId(sessionPath); - } else if (GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - if (GreetdSettings.rememberLastUser) { - GreetdMemory.setLastSuccessfulUser(GreeterState.username); - } else if (GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - pendingLaunchCommand = sessionCmd; - pendingLaunchEnv = ["XDG_SESSION_TYPE=wayland"]; - memoryFlushTimer.restart(); - } - - function onAuthFailure(message) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - if (isLikelyLockoutMessage(message)) { - GreeterState.pamState = "max"; - } else { - GreeterState.pamState = "fail"; - passwordFailureCount = passwordFailureCount + 1; - } - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - - function onError(error) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: memoryFlushTimer - interval: memoryFlushDelayMs - onTriggered: { - if (!pendingLaunchCommand) - return; - const sessionCommand = pendingLaunchCommand; - const launchEnv = pendingLaunchEnv; - pendingLaunchCommand = ""; - pendingLaunchEnv = []; - Greetd.launch(sessionCommand.split(" "), launchEnv); - } - } - - Timer { - id: authTimeout - interval: defaultAuthTimeoutMs - onTriggered: { - if (GreeterState.unlocking || Greetd.state === GreetdState.Inactive) - return; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: launchTimeout - interval: 8000 - onTriggered: { - if (!GreeterState.unlocking) - return; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: placeholderDelay - interval: 4000 - onTriggered: clearAuthFeedback() - } - - LockPowerMenu { - id: powerMenu - showLogout: false - powerActionConfirmOverride: GreetdSettings.powerActionConfirm - powerActionHoldDurationOverride: GreetdSettings.powerActionHoldDuration - powerMenuActionsOverride: GreetdSettings.powerMenuActions - powerMenuDefaultActionOverride: GreetdSettings.powerMenuDefaultAction - powerMenuGridLayoutOverride: GreetdSettings.powerMenuGridLayout - requiredActions: ["poweroff"] - onClosed: { - if (isPrimaryScreen && inputField && inputField.forceActiveFocus) { - Qt.callLater(() => inputField.forceActiveFocus()); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml deleted file mode 100644 index ac57de7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml +++ /dev/null @@ -1,30 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell - -Singleton { - id: root - - property string passwordBuffer: "" - property string username: "" - property string usernameInput: "" - property bool showPasswordInput: false - property string selectedSession: "" - property string selectedSessionPath: "" - property string pamState: "" - property bool unlocking: false - - property var sessionList: [] - property var sessionExecs: [] - property var sessionPaths: [] - property int currentSessionIndex: 0 - - function reset() { - showPasswordInput = false; - username = ""; - usernameInput = ""; - passwordBuffer = ""; - pamState = ""; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml deleted file mode 100644 index a8af5df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml +++ /dev/null @@ -1,34 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Services.Greetd -import qs.Common - -Variants { - model: Quickshell.screens - - PanelWindow { - id: root - - property var modelData - - screen: modelData - anchors { - left: true - right: true - top: true - bottom: true - } - exclusionMode: ExclusionMode.Normal - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive - color: "transparent" - - GreeterContent { - anchors.fill: parent - screenName: root.screen?.name ?? "" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md deleted file mode 100644 index 4ac5a77..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md +++ /dev/null @@ -1,277 +0,0 @@ -# Dank (dms) Greeter - -A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the aesthetics of the dms lock screen. - -## Features - -- **Multi user**: Login with any system user -- **dms sync**: Sync settings with dms for consistent styling between shell and greeter -- **Multiple compositors**: The `dms-greeter` wrapper supports niri, Hyprland, sway, scroll, miracle-wm, labwc, and mangowc. -- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/greetd` -- **Session Memory**: Remembers last selected session and user - - Can be disabled via `settings.json` keys: `greeterRememberLastSession` and `greeterRememberLastUser` - -## Installation - -### Arch Linux - -Arch linux users can install [greetd-dms-greeter-git](https://aur.archlinux.org/packages/greetd-dms-greeter-git) from the AUR. - -```bash -paru -S greetd-dms-greeter-git -# Or with yay -yay -S greetd-dms-greeter-git -``` - -### Debian / openSUSE - -Official packages are available from the [DankLinux OBS repository](https://software.opensuse.org/download/package?package=dms-greeter&project=home%3AAvengeMedia%3Adanklinux). Add the repo for your distribution and install: - -```bash -# Debian 13 -sudo apt install dms-greeter # after adding the repo - -# openSUSE Tumbleweed -zypper install dms-greeter # after adding the repo -``` - -See the [Installation guide](https://danklinux.com/docs/dankgreeter/installation) for full repository setup. - -If you previously installed manually, remove legacy files first: - -```bash -sudo rm -f /usr/local/bin/dms-greeter -sudo rm -rf /etc/xdg/quickshell/dms-greeter -``` - -Then complete setup: - -```bash -dms greeter enable -dms greeter sync -``` - -#### Syncing themes (Optional) - -To sync your wallpaper and theme with the greeter login screen, follow the manual setup below: - -

        -Manual theme syncing - -```bash -# Add yourself to greeter group -sudo usermod -aG greeter - -# Set ACLs to allow greeter to traverse your directories -setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state - -# Set group ownership on config directories -sudo chgrp -R greeter ~/.config/DankMaterialShell -sudo chgrp -R greeter ~/.local/state/DankMaterialShell -sudo chgrp -R greeter ~/.cache/DankMaterialShell -sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.cache/DankMaterialShell ~/.cache/quickshell - -# Create symlinks -sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json -sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json -sudo ln -sf ~/.cache/DankMaterialShell/dms-colors.json /var/cache/dms-greeter/colors.json - -# Logout and login for group membership to take effect -``` - -
        - -### Fedora / RHEL / Rocky / Alma - -Install from COPR or build the RPM: - -```bash -# From COPR (when available) -sudo dnf copr enable avenge/dms -sudo dnf install dms-greeter - -# Or build locally -cd /path/to/DankMaterialShell -rpkg local -sudo rpm -ivh x86_64/dms-greeter-*.rpm -``` - -The package automatically: -- Creates the greeter user -- Sets up directories and permissions -- Configures greetd with auto-detected compositor -- Applies SELinux contexts - -Then complete setup: - -```bash -dms greeter enable -dms greeter sync -``` - -#### Syncing themes (Optional) - -Run: - -```bash -dms greeter sync -``` - -Then logout/login to see your wallpaper on the greeter. - -### Automatic - -The easiest thing is to run `dms greeter install` or `dms` for interactive installation. -On Debian/openSUSE, this now prefers the `dms-greeter` package when the OBS repo is configured. - -### Manual (fallback only) - -Use this only if no package is available for your distro. - -1. Install `greetd` (in most distro's standard repositories) and `quickshell` - -2. Create the greeter user (if not already created by greetd): -```bash -sudo groupadd -r greeter -sudo useradd -r -g greeter -d /var/lib/greeter -s /bin/bash -c "System Greeter" greeter -sudo mkdir -p /var/lib/greeter -sudo chown greeter:greeter /var/lib/greeter -``` - -3. Clone the dms project to `/etc/xdg/quickshell/dms-greeter`: -```bash -sudo git clone https://github.com/AvengeMedia/DankMaterialShell.git /etc/xdg/quickshell/dms-greeter -``` - -4. Copy `Modules/Greetd/assets/dms-greeter` to `/usr/local/bin/dms-greeter`: -```bash -sudo cp /etc/xdg/quickshell/dms-greeter/Modules/Greetd/assets/dms-greeter /usr/local/bin/dms-greeter -sudo chmod +x /usr/local/bin/dms-greeter -``` - -5. Create greeter cache directory with proper permissions: -```bash -sudo mkdir -p /var/cache/dms-greeter -sudo chown : /var/cache/dms-greeter -sudo chmod 2770 /var/cache/dms-greeter -``` - -6. Edit or create `/etc/greetd/config.toml`: -```toml -[terminal] -vt = 1 - -[default_session] -user = "greeter" -# Change compositor to another wrapper-supported compositor if preferred -command = "/usr/local/bin/dms-greeter --command niri" -``` - -7. Disable existing display manager and enable greetd: -```bash -sudo systemctl disable gdm sddm lightdm -sudo systemctl enable greetd -``` - -8. (Optional) Set up theme syncing using the manual ACL method described in the Configuration → Personalization section below - -#### Legacy installation (deprecated) - -If you prefer the old method with separate shell scripts and config files: -1. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd` -2. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh` -3. Edit the config file and replace `_DMS_PATH_` with your DMS installation path -4. Configure greetd to use `/usr/local/bin/start-dms-greetd.sh` - -### NixOS - -To install the greeter on NixOS add the repo to your flake inputs as described in the readme. Then somewhere in your NixOS config add this to imports: -```nix -imports = [ - inputs.dank-material-shell.nixosModules.greeter -] -``` - -Enable the greeter with this in your NixOS config: -```nix -programs.dank-material-shell.greeter = { - enable = true; - compositor.name = "niri"; # or set to hyprland - configHome = "/home/user"; # optionally copyies that users DMS settings (and wallpaper if set) to the greeters data directory as root before greeter starts -}; -``` - -## Usage - -### Using dms-greeter wrapper (recommended) - -The `dms-greeter` wrapper simplifies running the greeter with any compositor: - -```bash -dms-greeter --command niri -dms-greeter --command hyprland -dms-greeter --command sway -dms-greeter --command mangowc -dms-greeter --command niri -C /path/to/custom-niri.kdl -dms-greeter --command niri --remember-last-user false --remember-last-session false -``` - -Configure greetd to use it in `/etc/greetd/config.toml`: -```toml -[terminal] -vt = 1 - -[default_session] -user = "greeter" -command = "/usr/bin/dms-greeter --command niri" -``` - -### Manual usage - -To run dms in greeter mode you can also manually set environment variables: - -```bash -DMS_RUN_GREETER=1 qs -p /path/to/dms -``` - -### Configuration - -#### Compositor - -For current wrapper-based installs, the `dms-greeter` wrapper supports niri, hyprland, sway, scroll, miracle-wm, labwc, and mangowc. - -Only niri currently has a generated greeter config path managed by `dms greeter sync`. - -- niri: `dms greeter sync` writes the generated greeter config to `/etc/greetd/niri/config.kdl`. Add local manual tweaks in `/etc/greetd/niri_overrides.kdl`. -- Other wrapper-supported compositors use the wrapper-generated config by default. If you need a custom compositor config, add `-C /path/to/config` to the `dms-greeter` command in `/etc/greetd/config.toml`. - -#### Personalization - -The greeter can be personalized with wallpapers, themes, weather, clock formats, and more - configured exactly the same as dms. - -**Easiest method:** Run `dms greeter sync` to automatically sync your DMS theme with the greeter. - -**Manual method:** You can manually synchronize configurations if you want greeter settings to always mirror your shell: - -```bash -# Add yourself to the greeter group -sudo usermod -aG greeter $USER - -# Set ACLs to allow greeter user to traverse your home directory -setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state - -# Set group permissions on DMS directories -sudo chgrp -R greeter ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell -sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell - -# Create symlinks for theme files -sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json -sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json -sudo ln -sf ~/.cache/DankMaterialShell/dms-colors.json /var/cache/dms-greeter/colors.json - -# Logout and login for group membership to take effect -``` - -**Advanced:** You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable or the `--cache-dir` flag when using `dms-greeter`. The default is `/var/cache/dms-greeter`. - -The cache directory should be owned by `:` with `2770` permissions. If the greeter user is not available yet, DMS falls back to `root:`. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter deleted file mode 100755 index 5d3419c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter +++ /dev/null @@ -1,424 +0,0 @@ -#!/bin/bash - -set -e - -COMPOSITOR="" -COMPOSITOR_CONFIG="" -DMS_PATH="dms-greeter" -CACHE_DIR="/var/cache/dms-greeter" -REMEMBER_LAST_SESSION="" -REMEMBER_LAST_USER="" -DEBUG_MODE=0 - -show_help() { - cat << EOF -dms-greeter - DankMaterialShell greeter launcher - -Usage: dms-greeter --command COMPOSITOR [OPTIONS] - -Required: - --command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, miracle, mango, or labwc) - -Options: - -C, --config PATH Custom compositor config file - -p, --path PATH DMS path (config name or absolute path) - (default: dms-greeter) - --cache-dir PATH Cache directory for greeter data - (default: /var/cache/dms-greeter) - --remember-last-session BOOL - Persist selected session to greeter memory - (BOOL: true/false, default: from settings.json) - --remember-last-user BOOL - Persist last successful username to greeter memory - (BOOL: true/false, default: from settings.json) - --no-save-session Alias for --remember-last-session false - --no-save-username Alias for --remember-last-user false - --debug Enable verbose startup logging to stderr - -h, --help Show this help message - -Examples: - dms-greeter --command niri - dms-greeter --command hyprland -C /etc/greetd/custom-hypr.conf - dms-greeter --command sway -p /home/user/.config/quickshell/custom-dms - dms-greeter --command scroll -p /home/user/.config/quickshell/custom-dms - dms-greeter --command niri --cache-dir /tmp/dmsgreeter - dms-greeter --command niri --no-save-session --no-save-username - dms-greeter --command mango - dms-greeter --command labwc -EOF -} - -require_command() { - local cmd="$1" - if ! command -v "$cmd" >/dev/null 2>&1; then - echo "Error: required command '$cmd' was not found in PATH" >&2 - exit 1 - fi -} - -normalize_bool_flag() { - local flag_name="$1" - local value="$2" - local normalized="${value,,}" - - case "$normalized" in - 1|true|yes|on) - echo "1" - ;; - 0|false|no|off) - echo "0" - ;; - *) - echo "Error: $flag_name must be true/false (or 1/0, yes/no, on/off)" >&2 - exit 1 - ;; - esac -} - -exec_compositor() { - local log_tag="$1" - shift - - if [[ "$DEBUG_MODE" == "1" ]]; then - exec "$@" - fi - - if command -v systemd-cat >/dev/null 2>&1; then - exec "$@" > >(systemd-cat -t "dms-greeter/$log_tag" -p info) 2>&1 - fi - - exec "$@" -} - -while [[ $# -gt 0 ]]; do - case $1 in - --command) - COMPOSITOR="$2" - shift 2 - ;; - -C|--config) - COMPOSITOR_CONFIG="$2" - shift 2 - ;; - -p|--path) - DMS_PATH="$2" - shift 2 - ;; - --cache-dir) - CACHE_DIR="$2" - shift 2 - ;; - --remember-last-session) - REMEMBER_LAST_SESSION="$2" - shift 2 - ;; - --remember-last-user) - REMEMBER_LAST_USER="$2" - shift 2 - ;; - --no-save-session) - REMEMBER_LAST_SESSION="0" - shift - ;; - --no-save-username) - REMEMBER_LAST_USER="0" - shift - ;; - --debug) - DEBUG_MODE=1 - shift - ;; - -h|--help) - show_help - exit 0 - ;; - *) - echo "Unknown option: $1" >&2 - show_help - exit 1 - ;; - esac -done - -if [[ -z "$COMPOSITOR" ]]; then - echo "Error: --command COMPOSITOR is required" >&2 - show_help - exit 1 -fi - -locate_dms_config() { - local config_name="$1" - local search_paths=() - - local config_home="${XDG_CONFIG_HOME:-$HOME/.config}" - search_paths+=("$config_home/quickshell/$config_name") - - search_paths+=("/usr/share/quickshell/$config_name") - - local config_dirs="${XDG_CONFIG_DIRS:-/etc/xdg}" - IFS=':' read -ra dirs <<< "$config_dirs" - for dir in "${dirs[@]}"; do - if [[ -n "$dir" ]]; then - search_paths+=("$dir/quickshell/$config_name") - fi - done - - for path in "${search_paths[@]}"; do - if [[ -f "$path/shell.qml" ]]; then - echo "$path" - return 0 - fi - done - - return 1 -} - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm -export DMS_RUN_GREETER=1 - -if [[ ! -d "$CACHE_DIR" ]]; then - echo "Error: cache directory '$CACHE_DIR' does not exist." >&2 - echo " Run 'dms greeter sync' to initialize it, or pass --cache-dir to an existing directory." >&2 - exit 1 -fi - -export DMS_GREET_CFG_DIR="$CACHE_DIR" - -if [[ -n "$REMEMBER_LAST_SESSION" ]]; then - DMS_GREET_REMEMBER_LAST_SESSION=$(normalize_bool_flag "--remember-last-session" "$REMEMBER_LAST_SESSION") - export DMS_GREET_REMEMBER_LAST_SESSION - if [[ "$DMS_GREET_REMEMBER_LAST_SESSION" == "1" ]]; then - DMS_SAVE_SESSION=true - else - DMS_SAVE_SESSION=false - fi - export DMS_SAVE_SESSION -fi - -if [[ -n "$REMEMBER_LAST_USER" ]]; then - DMS_GREET_REMEMBER_LAST_USER=$(normalize_bool_flag "--remember-last-user" "$REMEMBER_LAST_USER") - export DMS_GREET_REMEMBER_LAST_USER - if [[ "$DMS_GREET_REMEMBER_LAST_USER" == "1" ]]; then - DMS_SAVE_USERNAME=true - else - DMS_SAVE_USERNAME=false - fi - export DMS_SAVE_USERNAME -fi - -export HOME="$CACHE_DIR" -export XDG_STATE_HOME="$CACHE_DIR/.local/state" -export XDG_DATA_HOME="$CACHE_DIR/.local/share" -export XDG_CACHE_HOME="$CACHE_DIR/.cache" - - -# Keep greeter VT clean by default; callers can override via env or --debug. -if [[ -z "${RUST_LOG:-}" ]]; then - export RUST_LOG=warn -fi -if [[ -z "${NIRI_LOG:-}" ]]; then - export NIRI_LOG=warn -fi - -if command -v qs >/dev/null 2>&1; then - QS_BIN="qs" -elif command -v quickshell >/dev/null 2>&1; then - QS_BIN="quickshell" -else - echo "Error: neither 'qs' nor 'quickshell' was found in PATH" >&2 - exit 1 -fi - -QS_CMD="$QS_BIN" -if [[ "$DMS_PATH" == /* ]]; then - QS_CMD="$QS_BIN -p $DMS_PATH" -else - RESOLVED_PATH=$(locate_dms_config "$DMS_PATH") - if [[ $? -eq 0 && -n "$RESOLVED_PATH" ]]; then - if [[ "$DEBUG_MODE" == "1" ]]; then - echo "Located DMS config at: $RESOLVED_PATH" >&2 - fi - QS_CMD="$QS_BIN -p $RESOLVED_PATH" - else - echo "Error: Could not find DMS config '$DMS_PATH' (shell.qml) in any valid config path" >&2 - exit 1 - fi -fi - -case "$COMPOSITOR" in - niri) - require_command "niri" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - # base/default config - cat > "$TEMP_CONFIG" << NIRI_EOF -hotkey-overlay { - skip-at-startup -} - -environment { - DMS_RUN_GREETER "1" -} - -debug { - keep-max-bpc-unchanged -} - -gestures { - hot-corners { - off - } -} - -layout { - background-color "#000000" -} -NIRI_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - fi - # Append includes if override_files exist - OVERRIDE_FILES=( - /usr/share/greetd/niri_overrides.kdl # for building into a system image - /etc/greetd/niri_overrides.kdl # for local overrides - ) - for override_file in "${OVERRIDE_FILES[@]}"; do - if [[ -e "$override_file" ]]; then - # TODO: maybe move to optional=true when Niri Next drops, so we can avoid these checks ;-) - cat >> "$TEMP_CONFIG" << NIRI_EOF - -include "$override_file" -NIRI_EOF - fi - done - # Append spawn command - cat >> "$TEMP_CONFIG" << NIRI_EOF - -spawn-at-startup "sh" "-c" "$QS_CMD; niri msg action quit --skip-confirmation" -NIRI_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - exec_compositor "niri" niri -c "$COMPOSITOR_CONFIG" - ;; - - hyprland) - if ! command -v start-hyprland >/dev/null 2>&1 && ! command -v Hyprland >/dev/null 2>&1; then - echo "Error: neither 'start-hyprland' nor 'Hyprland' was found in PATH" >&2 - exit 1 - fi - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << HYPRLAND_EOF -env = DMS_RUN_GREETER,1 - -misc { - disable_hyprland_logo = true -} - -exec-once = sh -c "$QS_CMD; hyprctl dispatch exit" -HYPRLAND_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << HYPRLAND_EOF - -exec-once = sh -c "$QS_CMD; hyprctl dispatch exit" -HYPRLAND_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - if command -v start-hyprland >/dev/null 2>&1; then - exec_compositor "hyprland" start-hyprland -- --config "$COMPOSITOR_CONFIG" - else - exec_compositor "hyprland" Hyprland -c "$COMPOSITOR_CONFIG" - fi - ;; - - sway) - require_command "sway" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << SWAY_EOF -exec "$QS_CMD; swaymsg exit" -SWAY_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << SWAY_EOF - -exec "$QS_CMD; swaymsg exit" -SWAY_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "sway" sway --unsupported-gpu -c "$COMPOSITOR_CONFIG" - ;; - - scroll) - require_command "scroll" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << SCROLL_EOF -exec "$QS_CMD; scrollmsg exit" -SCROLL_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << SCROLL_EOF - -exec "$QS_CMD; scrollmsg exit" -SCROLL_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "scroll" scroll -c "$COMPOSITOR_CONFIG" - ;; - - miracle|miracle-wm) - require_command "miracle-wm" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << MIRACLE_EOF -exec "$QS_CMD; miraclemsg exit" -MIRACLE_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << MIRACLE_EOF - -exec "$QS_CMD; miraclemsg exit" -MIRACLE_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "miracle" miracle-wm -c "$COMPOSITOR_CONFIG" - ;; - - labwc) - require_command "labwc" - if [[ -n "$COMPOSITOR_CONFIG" ]]; then - exec_compositor "labwc" labwc --config "$COMPOSITOR_CONFIG" --session "$QS_CMD" - else - exec_compositor "labwc" labwc --session "$QS_CMD" - fi - ;; - - mango|mangowc) - require_command "mango" - if [[ -n "$COMPOSITOR_CONFIG" ]]; then - exec_compositor "mango" mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit" - else - exec_compositor "mango" mango -s "$QS_CMD && mmsg -d quit" - fi - ;; - - *) - echo "Error: Unsupported compositor: $COMPOSITOR" >&2 - echo "Supported compositors: niri, hyprland, sway, scroll, miracle, mango, labwc" >&2 - exit 1 - ;; -esac diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf deleted file mode 100644 index 33eefcd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf +++ /dev/null @@ -1,3 +0,0 @@ -env = DMS_RUN_GREETER,1 - -exec = sh -c "qs -p _DMS_PATH_; hyprctl dispatch exit" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl deleted file mode 100644 index dfc4703..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl +++ /dev/null @@ -1,23 +0,0 @@ -hotkey-overlay { - skip-at-startup -} - -environment { - DMS_RUN_GREETER "1" -} - -spawn-at-startup "sh" "-c" "qs -p _DMS_PATH_; niri msg action quit --skip-confirmation" - -debug { - keep-max-bpc-unchanged -} - -gestures { - hot-corners { - off - } -} - -layout { - background-color "#000000" -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh deleted file mode 100755 index c23b479..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm -if command -v start-hyprland >/dev/null 2>&1; then - exec start-hyprland -- -c /etc/greetd/dms-hypr.conf -else - exec Hyprland -c /etc/greetd/dms-hypr.conf -fi diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh deleted file mode 100755 index d31db65..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm - -exec niri -c /etc/greetd/dms-niri.kdl diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml deleted file mode 100644 index 639389c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml +++ /dev/null @@ -1,41 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankActionButton { - id: customButtonKeyboard - circular: false - property string text: "" - width: 40 - height: 40 - property bool isShift: false - color: Theme.surface - - property bool isIcon: text === "keyboard_hide" || text === "Backspace" || text === "Enter" - - DankIcon { - anchors.centerIn: parent - name: { - if (parent.text === "keyboard_hide") return "keyboard_hide" - if (parent.text === "Backspace") return "backspace" - if (parent.text === "Enter") return "keyboard_return" - return "" - } - size: 20 - color: Theme.surfaceText - visible: parent.isIcon - } - - StyledText { - id: contentItem - anchors.centerIn: parent - text: parent.text - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Normal - visible: !parent.isIcon - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml deleted file mode 100644 index 0486890..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml +++ /dev/null @@ -1,102 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -PanelWindow { - id: root - - property bool active: false - - signal fadeCompleted - signal fadeCancelled - - visible: active - color: "transparent" - - WlrLayershell.namespace: "dms:fade-to-dpms" - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None - - anchors { - left: true - right: true - top: true - bottom: true - } - - Rectangle { - id: fadeOverlay - anchors.fill: parent - color: "black" - opacity: 0 - - onOpacityChanged: { - if (opacity >= 0.99 && root.active) { - root.fadeCompleted(); - } - } - } - - SequentialAnimation { - id: fadeSeq - running: false - - NumberAnimation { - target: fadeOverlay - property: "opacity" - from: 0.0 - to: 1.0 - duration: SettingsData.fadeToDpmsGracePeriod * 1000 - easing.type: Easing.OutCubic - } - } - - function startFade() { - if (!SettingsData.fadeToDpmsEnabled) - return; - active = true; - fadeOverlay.opacity = 0.0; - fadeSeq.stop(); - fadeSeq.start(); - } - - function cancelFade() { - fadeSeq.stop(); - fadeOverlay.opacity = 0.0; - active = false; - fadeCancelled(); - } - - MouseArea { - anchors.fill: parent - enabled: root.active - onClicked: root.cancelFade() - onPressed: root.cancelFade() - } - - FocusScope { - anchors.fill: parent - focus: root.active - - Keys.onPressed: event => { - root.cancelFade(); - event.accepted = true; - } - } - - Component.onCompleted: { - if (active) { - forceActiveFocus(); - } - } - - onActiveChanged: { - if (active) { - forceActiveFocus(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml deleted file mode 100644 index c73a59a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml +++ /dev/null @@ -1,102 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -PanelWindow { - id: root - - property bool active: false - - signal fadeCompleted - signal fadeCancelled - - visible: active - color: "transparent" - - WlrLayershell.namespace: "dms:fade-to-lock" - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None - - anchors { - left: true - right: true - top: true - bottom: true - } - - Rectangle { - id: fadeOverlay - anchors.fill: parent - color: "black" - opacity: 0 - - onOpacityChanged: { - if (opacity >= 0.99 && root.active) { - root.fadeCompleted(); - } - } - } - - SequentialAnimation { - id: fadeSeq - running: false - - NumberAnimation { - target: fadeOverlay - property: "opacity" - from: 0.0 - to: 1.0 - duration: SettingsData.fadeToLockGracePeriod * 1000 - easing.type: Easing.OutCubic - } - } - - function startFade() { - if (!SettingsData.fadeToLockEnabled) - return; - active = true; - fadeOverlay.opacity = 0.0; - fadeSeq.stop(); - fadeSeq.start(); - } - - function cancelFade() { - fadeSeq.stop(); - fadeOverlay.opacity = 0.0; - active = false; - fadeCancelled(); - } - - MouseArea { - anchors.fill: parent - enabled: root.active - onClicked: root.cancelFade() - onPressed: root.cancelFade() - } - - FocusScope { - anchors.fill: parent - focus: root.active - - Keys.onPressed: event => { - root.cancelFade(); - event.accepted = true; - } - } - - Component.onCompleted: { - if (active) { - forceActiveFocus(); - } - } - - onActiveChanged: { - if (active) { - forceActiveFocus(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml deleted file mode 100644 index cfc0c61..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml +++ /dev/null @@ -1,344 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: root - property Item target - height: 60 * 5 - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - color: Theme.surfaceContainerHigh - - signal dismissed - - property double rowSpacing: 0.01 * width // horizontal spacing between keyboard - property double columnSpacing: 0.02 * height // vertical spacing between keyboard - property bool shift: false //Boolean for the shift state - property bool symbols: false //Boolean for the symbol state - property double columns: 10 // Number of column - property double rows: 4 // Number of row - - property string strShift: '\u2191' - property string strBackspace: "Backspace" - property string strEnter: "Enter" - property string strClose: "keyboard_hide" - - property var modelKeyboard: { - "row_1": [{ - "text": 'q', - "symbol": '1', - "width": 1 - }, { - "text": 'w', - "symbol": '2', - "width": 1 - }, { - "text": 'e', - "symbol": '3', - "width": 1 - }, { - "text": 'r', - "symbol": '4', - "width": 1 - }, { - "text": 't', - "symbol": '5', - "width": 1 - }, { - "text": 'y', - "symbol": '6', - "width": 1 - }, { - "text": 'u', - "symbol": '7', - "width": 1 - }, { - "text": 'i', - "symbol": '8', - "width": 1 - }, { - "text": 'o', - "symbol": '9', - "width": 1 - }, { - "text": 'p', - "symbol": '0', - "width": 1 - }], - "row_2": [{ - "text": 'a', - "symbol": '-', - "width": 1 - }, { - "text": 's', - "symbol": '/', - "width": 1 - }, { - "text": 'd', - "symbol": ':', - "width": 1 - }, { - "text": 'f', - "symbol": ';', - "width": 1 - }, { - "text": 'g', - "symbol": '(', - "width": 1 - }, { - "text": 'h', - "symbol": ')', - "width": 1 - }, { - "text": 'j', - "symbol": '€', - "width": 1 - }, { - "text": 'k', - "symbol": '&', - "width": 1 - }, { - "text": 'l', - "symbol": '@', - "width": 1 - }], - "row_3": [{ - "text": strShift, - "symbol": strShift, - "width": 1.5 - }, { - "text": 'z', - "symbol": '.', - "width": 1 - }, { - "text": 'x', - "symbol": ',', - "width": 1 - }, { - "text": 'c', - "symbol": '?', - "width": 1 - }, { - "text": 'v', - "symbol": '!', - "width": 1 - }, { - "text": 'b', - "symbol": "'", - "width": 1 - }, { - "text": 'n', - "symbol": "%", - "width": 1 - }, { - "text": 'm', - "symbol": '"', - "width": 1 - }, { - "text": strBackspace, - "symbol": strBackspace, - "width": 1.5 - }], - "row_4": [{ - "text": strClose, - "symbol": strClose, - "width": 1.5 - }, { - "text": "123", - "symbol": 'ABC', - "width": 1.5 - }, { - "text": ' ', - "symbol": ' ', - "width": 4.5 - }, { - "text": '.', - "symbol": '.', - "width": 1 - }, { - "text": strEnter, - "symbol": strEnter, - "width": 1.5 - }] - } - - //Here is the corresponding table between the ascii and the key event - property var tableKeyEvent: { - "_0": Qt.Key_0, - "_1": Qt.Key_1, - "_2": Qt.Key_2, - "_3": Qt.Key_3, - "_4": Qt.Key_4, - "_5": Qt.Key_5, - "_6": Qt.Key_6, - "_7": Qt.Key_7, - "_8": Qt.Key_8, - "_9": Qt.Key_9, - "_a": Qt.Key_A, - "_b": Qt.Key_B, - "_c": Qt.Key_C, - "_d": Qt.Key_D, - "_e": Qt.Key_E, - "_f": Qt.Key_F, - "_g": Qt.Key_G, - "_h": Qt.Key_H, - "_i": Qt.Key_I, - "_j": Qt.Key_J, - "_k": Qt.Key_K, - "_l": Qt.Key_L, - "_m": Qt.Key_M, - "_n": Qt.Key_N, - "_o": Qt.Key_O, - "_p": Qt.Key_P, - "_q": Qt.Key_Q, - "_r": Qt.Key_R, - "_s": Qt.Key_S, - "_t": Qt.Key_T, - "_u": Qt.Key_U, - "_v": Qt.Key_V, - "_w": Qt.Key_W, - "_x": Qt.Key_X, - "_y": Qt.Key_Y, - "_z": Qt.Key_Z, - "_←": Qt.Key_Backspace, - "_return": Qt.Key_Return, - "_ ": Qt.Key_Space, - "_-": Qt.Key_Minus, - "_/": Qt.Key_Slash, - "_:": Qt.Key_Colon, - "_;": Qt.Key_Semicolon, - "_(": Qt.Key_BracketLeft, - "_)": Qt.Key_BracketRight, - "_€": parseInt( - "20ac", - 16) // I didn't find the appropriate Qt event so I used the hex format - , - "_&": Qt.Key_Ampersand, - "_@": Qt.Key_At, - '_"': Qt.Key_QuoteDbl, - "_.": Qt.Key_Period, - "_,": Qt.Key_Comma, - "_?": Qt.Key_Question, - "_!": Qt.Key_Exclam, - "_'": Qt.Key_Apostrophe, - "_%": Qt.Key_Percent, - "_*": Qt.Key_Asterisk -} - -Item { -id: keyboard_container -anchors.left: parent.left -anchors.leftMargin: 5 -anchors.right: parent.right -anchors.top: parent.top -anchors.topMargin: 5 -anchors.bottom: parent.bottom -anchors.bottomMargin: 5 - -//One column which contains 5 rows -Column { -spacing: columnSpacing - -Row { -id: row_1 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_1"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_2 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_2"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_3 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_3"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing -isShift: shift && text === strShift - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_4 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_4"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -} -} -signal clicked(string text) - -Connections { -target: root -function onClicked(text) { -if (!keyboard_controller.target) -return -if (text === strShift) { -root.shift = !root.shift -} else if (text === '123') { -root.symbols = true -} else if (text === 'ABC') { -root.symbols = false -} else if (text === strEnter) { -if (keyboard_controller.target.accepted) { -keyboard_controller.target.accepted() -} -} else if (text === strClose) { -root.dismissed() -} else { -if (text === strBackspace) { -var current = keyboard_controller.target.text -keyboard_controller.target.text = current.slice(0, current.length - 1) -} else { -var charToInsert = root.symbols ? text : (root.shift ? text.toUpperCase -() : text) -var current = keyboard_controller.target.text -var cursorPos = keyboard_controller.target.cursorPosition -keyboard_controller.target.text = current.slice(0, -cursorPos) + charToInsert + current.slice(cursorPos) -keyboard_controller.target.cursorPosition = cursorPos + 1 -} - -if (root.shift && text !== strShift) -root.shift = false -} -} -} -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml deleted file mode 100644 index 09d77a5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml +++ /dev/null @@ -1,40 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick - -Item { - id: keyboard_controller - - // reference on the TextInput - property Item target - //Booléan on the state of the keyboard - property bool isKeyboardActive: false - - property var rootObject - - function show() { - if (!isKeyboardActive && keyboard === null) { - keyboard = keyboardComponent.createObject( - keyboard_controller.rootObject) - keyboard.target = keyboard_controller.target - keyboard.dismissed.connect(hide) - isKeyboardActive = true - } else - console.log("The keyboard is already shown") - } - - function hide() { - if (isKeyboardActive && keyboard !== null) { - keyboard.destroy() - isKeyboardActive = false - } else - console.log("The keyboard is already hidden") - } - - // private - property Item keyboard: null - Component { - id: keyboardComponent - Keyboard {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml deleted file mode 100644 index 9a5a00f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml +++ /dev/null @@ -1,296 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import qs.Common -import qs.Services - -Scope { - id: root - - property string sharedPasswordBuffer: "" - property bool shouldLock: false - - onShouldLockChanged: { - IdleService.isShellLocked = shouldLock; - if (shouldLock && lockPowerOffArmed) { - lockStateCheck.restart(); - } - } - - Timer { - id: lockStateCheck - interval: 100 - repeat: false - onTriggered: { - if (sessionLock.locked && lockPowerOffArmed) { - pendingLock = false; - IdleService.monitorsOff = true; - CompositorService.powerOffMonitors(); - lockWakeAllowed = false; - lockWakeDebounce.restart(); - lockPowerOffArmed = false; - dpmsReapplyTimer.start(); - } - } - } - - property bool lockInitiatedLocally: false - property bool pendingLock: false - property bool lockPowerOffArmed: false - property bool lockWakeAllowed: false - - Component.onCompleted: { - IdleService.lockComponent = this; - if (SettingsData.lockAtStartup) - lock(); - } - - function notifyLoginctl(lockAction: bool) { - if (!SettingsData.loginctlLockIntegration || !DMSService.isConnected) - return; - if (lockAction) - DMSService.lockSession(() => {}); - else - DMSService.unlockSession(() => {}); - } - - function lock() { - if (SettingsData.customPowerActionLock?.length > 0) { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]); - return; - } - if (shouldLock || pendingLock) - return; - - lockInitiatedLocally = true; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - - if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) { - pendingLock = true; - notifyLoginctl(true); - return; - } - - shouldLock = true; - notifyLoginctl(true); - } - - function unlock() { - if (!shouldLock) - return; - lockInitiatedLocally = false; - notifyLoginctl(false); - shouldLock = false; - } - - function forceReset() { - lockInitiatedLocally = false; - pendingLock = false; - shouldLock = false; - } - - function activate() { - lock(); - } - - Connections { - target: SessionService - - function onSessionLocked() { - if (shouldLock || pendingLock) - return; - if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) { - pendingLock = true; - lockInitiatedLocally = false; - return; - } - lockInitiatedLocally = false; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - } - - function onSessionUnlocked() { - if (pendingLock) { - pendingLock = false; - lockInitiatedLocally = false; - return; - } - if (!shouldLock || lockInitiatedLocally) - return; - shouldLock = false; - } - - function onLoginctlStateChanged() { - if (SessionService.active && pendingLock) { - pendingLock = false; - lockInitiatedLocally = true; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - return; - } - if (SessionService.locked && !shouldLock && !pendingLock) { - lockInitiatedLocally = false; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - } - } - } - - Connections { - target: IdleService - - function onLockRequested() { - lock(); - } - } - - WlSessionLock { - id: sessionLock - - locked: shouldLock - - WlSessionLockSurface { - id: lockSurface - - property string currentScreenName: screen?.name ?? "" - property bool isActiveScreen: { - if (Quickshell.screens.length <= 1) - return true; - if (SettingsData.lockScreenActiveMonitor === "all") - return true; - return currentScreenName === SettingsData.lockScreenActiveMonitor; - } - - color: isActiveScreen ? "transparent" : SettingsData.lockScreenInactiveColor - - LockSurface { - anchors.fill: parent - visible: lockSurface.isActiveScreen - lock: sessionLock - sharedPasswordBuffer: root.sharedPasswordBuffer - screenName: lockSurface.currentScreenName - isLocked: shouldLock - onUnlockRequested: root.unlock() - onPasswordChanged: newPassword => { - root.sharedPasswordBuffer = newPassword; - } - } - } - } - - Connections { - target: sessionLock - - function onLockedChanged() { - if (sessionLock.locked) { - pendingLock = false; - if (lockPowerOffArmed && SettingsData.lockScreenPowerOffMonitorsOnLock) { - IdleService.monitorsOff = true; - CompositorService.powerOffMonitors(); - lockWakeAllowed = false; - lockWakeDebounce.restart(); - } - lockPowerOffArmed = false; - dpmsReapplyTimer.start(); - return; - } - - lockWakeAllowed = false; - if (IdleService.monitorsOff && SettingsData.lockScreenPowerOffMonitorsOnLock) { - IdleService.monitorsOff = false; - CompositorService.powerOnMonitors(); - } - } - } - - LockScreenDemo { - id: demoWindow - } - - IpcHandler { - target: "lock" - - function lock() { - root.lock(); - } - - function unlock() { - root.unlock(); - } - - function forceReset() { - root.forceReset(); - } - - function demo() { - demoWindow.showDemo(); - } - - function isLocked(): bool { - return sessionLock.locked; - } - - function status(): string { - return JSON.stringify({ - shouldLock: root.shouldLock, - sessionLockLocked: sessionLock.locked, - lockInitiatedLocally: root.lockInitiatedLocally, - pendingLock: root.pendingLock, - loginctlLocked: SessionService.locked, - loginctlActive: SessionService.active - }); - } - } - - Timer { - id: dpmsReapplyTimer - interval: 100 - repeat: false - onTriggered: IdleService.reapplyDpmsIfNeeded() - } - - Timer { - id: lockWakeDebounce - interval: 200 - repeat: false - onTriggered: { - if (!sessionLock.locked) - return; - if (!SettingsData.lockScreenPowerOffMonitorsOnLock) - return; - if (!IdleService.monitorsOff) { - lockWakeAllowed = true; - return; - } - if (lockWakeAllowed) { - IdleService.monitorsOff = false; - CompositorService.powerOnMonitors(); - } else { - lockWakeAllowed = true; - } - } - } - - MouseArea { - anchors.fill: parent - enabled: sessionLock.locked - hoverEnabled: enabled - onPressed: lockWakeDebounce.restart() - onPositionChanged: lockWakeDebounce.restart() - onWheel: lockWakeDebounce.restart() - } - - FocusScope { - anchors.fill: parent - focus: sessionLock.locked - - Keys.onPressed: event => { - if (!sessionLock.locked) - return; - lockWakeDebounce.restart(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml deleted file mode 100644 index 0a0ee84..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml +++ /dev/null @@ -1,820 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property bool isVisible: false - property bool showLogout: true - property int selectedIndex: 0 - property int selectedRow: 0 - property int selectedCol: 0 - property var visibleActions: [] - property int gridColumns: 3 - property int gridRows: 2 - property bool useGridLayout: false - - property string holdAction: "" - property int holdActionIndex: -1 - property real holdProgress: 0 - property bool showHoldHint: false - - property var powerActionConfirmOverride: undefined - property var powerActionHoldDurationOverride: undefined - property var powerMenuActionsOverride: undefined - property var powerMenuDefaultActionOverride: undefined - property var powerMenuGridLayoutOverride: undefined - property var requiredActions: [] - - readonly property bool needsConfirmation: powerActionConfirmOverride !== undefined ? powerActionConfirmOverride : SettingsData.powerActionConfirm - readonly property int holdDurationMs: (powerActionHoldDurationOverride !== undefined ? powerActionHoldDurationOverride : SettingsData.powerActionHoldDuration) * 1000 - - signal closed - - function updateVisibleActions() { - const allActions = powerMenuActionsOverride !== undefined ? powerMenuActionsOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"]); - const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false; - let filtered = allActions.filter(action => { - if (action === "hibernate" && !hibernateSupported) - return false; - if (action === "lock") - return false; - if (action === "restart") - return false; - if (action === "logout" && !showLogout) - return false; - return true; - }); - - for (const action of requiredActions) { - if (!filtered.includes(action)) - filtered.push(action); - } - - visibleActions = filtered; - - useGridLayout = powerMenuGridLayoutOverride !== undefined ? powerMenuGridLayoutOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false); - if (!useGridLayout) - return; - const count = visibleActions.length; - if (count === 0) { - gridColumns = 1; - gridRows = 1; - return; - } - - if (count <= 3) { - gridColumns = 1; - gridRows = count; - return; - } - - if (count === 4) { - gridColumns = 2; - gridRows = 2; - return; - } - - gridColumns = 3; - gridRows = Math.ceil(count / 3); - } - - function getDefaultActionIndex() { - const defaultAction = powerMenuDefaultActionOverride !== undefined ? powerMenuDefaultActionOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend"); - const index = visibleActions.indexOf(defaultAction); - return index >= 0 ? index : 0; - } - - function getActionAtIndex(index) { - if (index < 0 || index >= visibleActions.length) - return ""; - return visibleActions[index]; - } - - function getActionData(action) { - switch (action) { - case "reboot": - return { - "icon": "restart_alt", - "label": I18n.tr("Reboot"), - "key": "R" - }; - case "logout": - return { - "icon": "logout", - "label": I18n.tr("Log Out"), - "key": "X" - }; - case "poweroff": - return { - "icon": "power_settings_new", - "label": I18n.tr("Power Off"), - "key": "P" - }; - case "suspend": - return { - "icon": "bedtime", - "label": I18n.tr("Suspend"), - "key": "S" - }; - case "hibernate": - return { - "icon": "ac_unit", - "label": I18n.tr("Hibernate"), - "key": "H" - }; - default: - return { - "icon": "help", - "label": action, - "key": "?" - }; - } - } - - function actionNeedsConfirm(action) { - return action !== "lock" && action !== "restart"; - } - - function startHold(action, actionIndex) { - if (!needsConfirmation || !actionNeedsConfirm(action)) { - executeAction(action); - return; - } - holdAction = action; - holdActionIndex = actionIndex; - holdProgress = 0; - showHoldHint = false; - holdTimer.start(); - } - - function cancelHold() { - if (holdAction === "") - return; - const wasHolding = holdProgress > 0; - holdTimer.stop(); - if (wasHolding && holdProgress < 1) { - showHoldHint = true; - hintTimer.restart(); - } - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - } - - function completeHold() { - if (holdProgress < 1) { - cancelHold(); - return; - } - const action = holdAction; - holdTimer.stop(); - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - executeAction(action); - } - - function executeAction(action) { - if (!action) - return; - if (typeof SessionService === "undefined") - return; - hide(); - switch (action) { - case "logout": - SessionService.logout(); - break; - case "suspend": - SessionService.suspend(); - break; - case "hibernate": - SessionService.hibernate(); - break; - case "reboot": - SessionService.reboot(); - break; - case "poweroff": - SessionService.poweroff(); - break; - } - } - - function selectOption(action, actionIndex) { - startHold(action, actionIndex !== undefined ? actionIndex : -1); - } - - function show() { - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - showHoldHint = false; - updateVisibleActions(); - const defaultIndex = getDefaultActionIndex(); - if (useGridLayout) { - selectedRow = Math.floor(defaultIndex / gridColumns); - selectedCol = defaultIndex % gridColumns; - selectedIndex = defaultIndex; - } else { - selectedIndex = defaultIndex; - } - isVisible = true; - Qt.callLater(() => powerMenuFocusScope.forceActiveFocus()); - } - - function hide() { - cancelHold(); - isVisible = false; - closed(); - } - - function handleListNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - } - } - - function handleGridNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Left: - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Right: - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - } - } - - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.5) - visible: isVisible - z: 1000 - - MouseArea { - anchors.fill: parent - onClicked: root.hide() - } - - Timer { - id: holdTimer - interval: 16 - repeat: true - onTriggered: { - root.holdProgress = Math.min(1, root.holdProgress + (interval / root.holdDurationMs)); - if (root.holdProgress >= 1) { - stop(); - root.completeHold(); - } - } - } - - Timer { - id: hintTimer - interval: 2000 - onTriggered: root.showHoldHint = false - } - - FocusScope { - id: powerMenuFocusScope - anchors.fill: parent - focus: root.isVisible - - onVisibleChanged: { - if (visible) - Qt.callLater(() => forceActiveFocus()); - } - - Keys.onEscapePressed: root.hide() - Keys.onPressed: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (useGridLayout) { - handleGridNavigation(event, true); - } else { - handleListNavigation(event, true); - } - } - Keys.onReleased: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (useGridLayout) { - handleGridNavigation(event, false); - } else { - handleListNavigation(event, false); - } - } - - Rectangle { - anchors.centerIn: parent - width: useGridLayout ? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2) : 320 - height: contentItem.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outlineMedium - border.width: 1 - - Item { - id: contentItem - anchors.fill: parent - anchors.margins: Theme.spacingL - implicitHeight: headerRow.height + Theme.spacingM + (useGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight) + (root.needsConfirmation ? hintRow.height + Theme.spacingM : 0) - - Row { - id: headerRow - width: parent.width - height: 30 - - StyledText { - text: I18n.tr("Power Options") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - 150 - height: 1 - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - - Grid { - id: buttonGrid - visible: useGridLayout - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - columns: root.gridColumns - columnSpacing: Theme.spacingS - rowSpacing: Theme.spacingS - width: parent.width - - Repeater { - model: root.visibleActions - - Rectangle { - id: gridButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: (contentItem.width - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns - height: 100 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (mouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: gridProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: gridButtonRect.isHolding - layer.enabled: gridButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: gridProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (gridButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (gridButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: gridButtonRect.actionData.icon - size: Theme.iconSize + 8 - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: gridButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Rectangle { - width: 20 - height: 16 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: gridButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - 1 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedRow = Math.floor(index / root.gridColumns); - root.selectedCol = index % root.gridColumns; - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Column { - id: buttonColumn - visible: !useGridLayout - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.spacingS - - Repeater { - model: root.visibleActions - - Rectangle { - id: listButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (listMouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: listProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: listButtonRect.isHolding - layer.enabled: listButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: listProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (listButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (listButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: listButtonRect.actionData.icon - size: Theme.iconSize + 4 - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: listButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 28 - height: 20 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: listButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - - MouseArea { - id: listMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Row { - id: hintRow - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingXS - visible: root.needsConfirmation - opacity: root.showHoldHint ? 1 : 0.5 - - Behavior on opacity { - NumberAnimation { - duration: 150 - } - } - - DankIcon { - name: root.showHoldHint ? "warning" : "touch_app" - size: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - readonly property real totalMs: root.holdDurationMs - readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress)) - readonly property real durationSec: root.holdDurationMs / 1000 - text: { - if (root.showHoldHint) - return I18n.tr("Hold longer to confirm"); - if (root.holdProgress > 0) { - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(remainingMs); - return I18n.tr("Hold to confirm (%1s)").arg(Math.ceil(remainingMs / 1000)); - } - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs); - return I18n.tr("Hold to confirm (%1s)").arg(durationSec); - } - font.pixelSize: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Component.onCompleted: updateVisibleActions() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml deleted file mode 100644 index b296e98..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml +++ /dev/null @@ -1,1707 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import QtQuick.Window -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string passwordBuffer: "" - property bool demoMode: false - property string screenName: "" - property bool unlocking: false - property string pamState: "" - property string hyprlandCurrentLayout: "" - property string hyprlandKeyboard: "" - property int hyprlandLayoutCount: 0 - property bool lockerReadySent: false - property bool lockerReadyArmed: false - - signal unlockRequested - - function resetLockState() { - lockerReadySent = false; - lockerReadyArmed = true; - unlocking = false; - pamState = ""; - if (pam) - pam.lockMessage = ""; - } - - function currentAuthFeedbackText() { - if (!pam) - return ""; - if (pam.u2fState === "insert" && !pam.u2fPending) - return I18n.tr("Insert your security key..."); - if (pam.u2fState === "waiting" && !pam.u2fPending) - return I18n.tr("Touch your security key..."); - if (pam.lockMessage && pam.lockMessage.length > 0) - return pam.lockMessage; - if (root.pamState === "error") - return I18n.tr("Authentication error - try again"); - if (root.pamState === "max") - return I18n.tr("Too many attempts - locked out"); - if (root.pamState === "fail") - return I18n.tr("Incorrect password - try again"); - if (pam.fprintState === "error") { - const detail = (pam.fprint.message || "").trim(); - return detail.length > 0 ? I18n.tr("Fingerprint error: %1").arg(detail) : I18n.tr("Fingerprint error"); - } - if (pam.fprintState === "max") - return I18n.tr("Maximum fingerprint attempts reached. Please use password."); - if (pam.fprintState === "fail") - return I18n.tr("Fingerprint not recognized (%1/%2). Please try again or use password.").arg(pam.fprint.tries).arg(SettingsData.maxFprintTries); - return ""; - } - - function authFeedbackIsHint() { - return pam && (pam.u2fState === "waiting" || pam.u2fState === "insert") && !pam.u2fPending; - } - - Component.onCompleted: { - WeatherService.addRef(); - UserInfoService.getUserInfo(); - - if (CompositorService.isHyprland) - updateHyprlandLayout(); - - lockerReadyArmed = true; - } - - Component.onDestruction: { - WeatherService.removeRef(); - } - - function sendLockerReadyOnce() { - if (lockerReadySent) - return; - if (root.unlocking) - return; - lockerReadySent = true; - if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) { - DMSService.sendRequest("loginctl.lockerReady", null, resp => { - if (resp?.error) - console.warn("lockerReady failed:", resp.error); - else - console.log("lockerReady sent (afterAnimating/afterRendering)"); - }); - } - } - - function maybeSend() { - if (!lockerReadyArmed) - return; - if (root.unlocking) - return; - if (!root.visible || root.opacity <= 0) - return; - Qt.callLater(() => { - if (root.visible && root.opacity > 0 && !root.unlocking) - sendLockerReadyOnce(); - }); - } - - Connections { - target: root.Window.window - enabled: target !== null - - function onAfterAnimating() { - maybeSend(); - } - function onAfterRendering() { - maybeSend(); - } - } - - onVisibleChanged: maybeSend() - onOpacityChanged: maybeSend() - - function updateHyprlandLayout() { - if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true; - } - } - - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - if (!mainKeyboard) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - return; - } - hyprlandKeyboard = mainKeyboard.name; - if (mainKeyboard.active_keymap) { - const parts = mainKeyboard.active_keymap.split(" "); - hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase(); - } else { - hyprlandCurrentLayout = ""; - } - hyprlandLayoutCount = mainKeyboard.layout ? mainKeyboard.layout.split(",").length : 0; - } catch (e) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - } - } - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") - updateHyprlandLayout(); - } - } - - Loader { - anchors.fill: parent - active: { - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return !currentWallpaper || (currentWallpaper && currentWallpaper.startsWith("#")); - } - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: root.screenName - } - } - - Image { - id: wallpaperBackground - - anchors.fill: parent - source: { - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; - } - fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(screenName)) - smooth: true - asynchronous: false - cache: true - visible: source !== "" - layer.enabled: true - - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - blur: 0.8 - blurMax: 32 - blurMultiplier: 1 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.4 - } - - SystemClock { - id: systemClock - - precision: SystemClock.Seconds - } - - Rectangle { - anchors.fill: parent - color: "transparent" - - Item { - id: clockContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: 60 - width: parent.width - height: clockText.implicitHeight - visible: SettingsData.lockScreenShowTime - - Row { - id: clockText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - spacing: 0 - - property string fullTimeStr: { - const format = SettingsData.getEffectiveTimeFormat(); - return systemClock.date.toLocaleTimeString(Qt.locale(), format); - } - property var timeParts: fullTimeStr.split(':') - property string hours: timeParts[0] || "" - property string minutes: timeParts[1] || "" - property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : "" - property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '') - property string ampm: { - const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i); - return match ? match[0].trim() : ""; - } - property bool hasSeconds: timeParts.length > 2 - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[1] : clockText.hours.length > 0 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - } - - StyledText { - width: 75 - text: clockText.minutes.length > 0 ? clockText.minutes[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.minutes.length > 1 ? clockText.minutes[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockText.hasSeconds ? ":" : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 0 ? clockText.seconds[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 1 ? clockText.seconds[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 20 - text: " " - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - - StyledText { - text: clockText.ampm - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - } - } - - StyledText { - id: dateText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: clockContainer.bottom - anchors.topMargin: 4 - visible: SettingsData.lockScreenShowDate - text: { - if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) { - return systemClock.date.toLocaleDateString(I18n.locale(), SettingsData.lockDateFormat); - } - return systemClock.date.toLocaleDateString(I18n.locale(), Locale.LongFormat); - } - font.pixelSize: Theme.fontSizeXLarge - color: "white" - opacity: 0.9 - } - - Item { - id: lockNotificationPanel - - readonly property int notificationMode: SettingsData.lockScreenNotificationMode - readonly property var notifications: NotificationService.groupedNotifications - readonly property int totalCount: { - let count = 0; - for (const group of notifications) { - count += group.count || 0; - } - return count; - } - readonly property bool hasNotifications: totalCount > 0 - readonly property var appNameGroups: { - const groups = {}; - for (const group of notifications) { - const appName = (group.appName || "Unknown").toLowerCase(); - if (!groups[appName]) { - groups[appName] = { - appName: group.appName || I18n.tr("Unknown"), - count: 0, - latestNotification: group.latestNotification - }; - } - groups[appName].count += group.count || 0; - if (group.latestNotification && (!groups[appName].latestNotification || group.latestNotification.time > groups[appName].latestNotification.time)) { - groups[appName].latestNotification = group.latestNotification; - } - } - return Object.values(groups).sort((a, b) => b.count - a.count); - } - - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dateText.visible ? dateText.bottom : clockContainer.bottom - anchors.topMargin: Theme.spacingM - width: Math.min(380, parent.width - Theme.spacingXL * 2) - height: notificationMode === 0 || !hasNotifications ? 0 : contentLoader.height - visible: notificationMode > 0 && hasNotifications - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Loader { - id: contentLoader - anchors.left: parent.left - anchors.right: parent.right - active: lockNotificationPanel.notificationMode > 0 && lockNotificationPanel.hasNotifications - sourceComponent: { - switch (lockNotificationPanel.notificationMode) { - case 1: - return countOnlyComponent; - case 2: - return appNamesComponent; - case 3: - return fullContentComponent; - default: - return null; - } - } - } - - Component { - id: countOnlyComponent - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: lockNotificationPanel.totalCount === 1 ? I18n.tr("1 notification") : I18n.tr("%1 notifications").arg(lockNotificationPanel.totalCount) - font.pixelSize: Theme.fontSizeMedium - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - Component { - id: appNamesComponent - - Rectangle { - width: parent.width - height: Math.min(appNamesColumn.implicitHeight + Theme.spacingM * 2, 200) - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - clip: true - - Flickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: appNamesColumn.implicitHeight - clip: true - boundsBehavior: Flickable.StopAtBounds - - Column { - id: appNamesColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: lockNotificationPanel.appNameGroups.slice(0, 5) - - Row { - required property var modelData - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: Theme.iconSize - 4 - color: "white" - opacity: 0.8 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.appName || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: "white" - elide: Text.ElideRight - width: parent.width - Theme.iconSize - countBadge.width - Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: countBadge - width: countText.implicitWidth + Theme.spacingS * 2 - height: 20 - radius: 10 - color: Qt.rgba(1, 1, 1, 0.2) - visible: modelData.count > 1 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: countText - anchors.centerIn: parent - text: modelData.count > 99 ? "99+" : modelData.count.toString() - font.pixelSize: Theme.fontSizeSmall - color: "white" - } - } - } - } - - StyledText { - visible: lockNotificationPanel.appNameGroups.length > 5 - text: I18n.tr("+ %1 more").arg(lockNotificationPanel.appNameGroups.length - 5) - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - } - } - } - } - } - - Component { - id: fullContentComponent - - Rectangle { - width: parent.width - height: Math.min(fullContentColumn.implicitHeight + Theme.spacingM * 2, 280) - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - clip: true - - Flickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: fullContentColumn.implicitHeight - clip: true - boundsBehavior: Flickable.StopAtBounds - - Column { - id: fullContentColumn - width: parent.width - spacing: Theme.spacingM - - Repeater { - model: { - const items = []; - for (const group of lockNotificationPanel.appNameGroups) { - if (group.latestNotification && items.length < 5) { - items.push(group.latestNotification); - } - } - return items; - } - - Rectangle { - required property var modelData - required property int index - width: parent.width - height: notifContent.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - 4 - color: Qt.rgba(1, 1, 1, 0.05) - - Column { - id: notifContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingS - spacing: 2 - - Row { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: modelData.appName || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: "white" - opacity: 0.7 - elide: Text.ElideRight - width: parent.width - timeText.implicitWidth - Theme.spacingXS - } - - StyledText { - id: timeText - text: modelData.timeStr || "" - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.5 - } - } - - StyledText { - width: parent.width - text: modelData.summary || "" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: "white" - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - width: parent.width - text: { - const body = modelData.body || ""; - return body.replace(/<[^>]*>/g, '').replace(/\n/g, ' '); - } - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.8 - elide: Text.ElideRight - maximumLineCount: 2 - wrapMode: Text.WordWrap - visible: text.length > 0 - } - } - } - } - - StyledText { - visible: lockNotificationPanel.appNameGroups.length > 5 - text: I18n.tr("+ %1 more").arg(lockNotificationPanel.appNameGroups.length - 5) - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - } - } - } - } - } - } - - ColumnLayout { - id: passwordLayout - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: lockNotificationPanel.visible ? lockNotificationPanel.bottom : (dateText.visible ? dateText.bottom : clockContainer.bottom) - anchors.topMargin: Theme.spacingL - spacing: Theme.spacingM - width: 380 - - RowLayout { - spacing: Theme.spacingL - Layout.fillWidth: true - - DankCircularImage { - Layout.preferredWidth: 60 - Layout.preferredHeight: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - if (PortalService.profileImage.startsWith("/")) - return encodeFileUrl(PortalService.profileImage); - return PortalService.profileImage; - } - fallbackIcon: "person" - visible: SettingsData.lockScreenShowProfileImage - } - - Rectangle { - property bool showPassword: false - - Layout.fillWidth: true - Layout.preferredHeight: 60 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) - border.width: passwordField.activeFocus ? 2 : 1 - visible: SettingsData.lockScreenShowPasswordField || root.passwordBuffer.length > 0 - - Item { - id: lockIconContainer - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - - DankIcon { - id: lockIcon - - anchors.centerIn: parent - name: { - if (pam.u2fPending) - return "passkey"; - if (pam.fprint.tries >= SettingsData.maxFprintTries) - return "fingerprint_off"; - if (pam.fprint.active) - return "fingerprint"; - if (pam.u2f.active) - return "passkey"; - return "lock"; - } - size: 20 - color: { - if (pam.fprint.tries >= SettingsData.maxFprintTries) - return Theme.error; - if (pam.u2fState !== "") - return Theme.tertiary; - return passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText; - } - opacity: pam.passwd.active ? 0 : 1 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - TextInput { - id: passwordField - - anchors.fill: parent - anchors.leftMargin: lockIconContainer.width + Theme.spacingM * 2 - anchors.rightMargin: { - let margin = Theme.spacingM; - if (loadingSpinner.visible) { - margin += loadingSpinner.width; - } - if (enterButton.visible) { - margin += enterButton.width + 2; - } - if (virtualKeyboardButton.visible) { - margin += virtualKeyboardButton.width; - } - if (revealButton.visible) { - margin += revealButton.width; - } - return margin; - } - opacity: 0 - focus: true - enabled: !demoMode - activeFocusOnTab: !demoMode - echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password - onTextChanged: { - if (!demoMode) { - root.passwordBuffer = text; - } - } - onAccepted: { - if (!demoMode && !root.unlocking && !pam.passwd.active && !pam.u2fPending) { - pam.passwd.start(); - } - } - Keys.onPressed: event => { - if (demoMode) { - return; - } - - if (root.unlocking) { - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Escape) { - if (pam.u2fPending) { - pam.cancelU2fPending(); - event.accepted = true; - return; - } - clear(); - } - - if (pam.passwd.active) { - console.log("PAM is active, ignoring input"); - event.accepted = true; - return; - } - } - - Component.onCompleted: { - if (!demoMode) { - forceActiveFocus(); - } - } - - onVisibleChanged: { - if (visible && !demoMode) { - forceActiveFocus(); - } - } - - onActiveFocusChanged: { - if (!activeFocus && !demoMode && visible && passwordField && !powerMenu.isVisible) { - Qt.callLater(() => { - if (passwordField && passwordField.forceActiveFocus) { - passwordField.forceActiveFocus(); - } - }); - } - } - - onEnabledChanged: { - if (enabled && !demoMode && visible && passwordField && !powerMenu.isVisible) { - Qt.callLater(() => { - if (passwordField && passwordField.forceActiveFocus) { - passwordField.forceActiveFocus(); - } - }); - } - } - } - - KeyboardController { - id: keyboardController - target: passwordField - rootObject: root - } - - StyledText { - id: placeholder - - anchors.left: lockIconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (demoMode) { - return ""; - } - if (root.unlocking) { - return "Unlocking..."; - } - if (pam.u2fPending) { - if (pam.u2fState === "insert") - return "Insert your security key..."; - return "Touch your security key..."; - } - if (pam.passwd.active) { - return "Authenticating..."; - } - return "Password..."; - } - color: root.unlocking ? Theme.primary : (pam.passwd.active ? Theme.primary : Theme.outline) - font.pixelSize: Theme.fontSizeMedium - opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.left: lockIconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (demoMode) { - return "••••••••"; - } - if (parent.showPassword) { - return root.passwordBuffer; - } - return "•".repeat(root.passwordBuffer.length); - } - color: Theme.surfaceText - font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge - opacity: (demoMode || root.passwordBuffer.length > 0) ? 1 : 0 - clip: true - elide: Text.ElideNone - horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - DankActionButton { - id: revealButton - - anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: parent.showPassword ? "visibility_off" : "visibility" - buttonSize: 32 - visible: !demoMode && root.passwordBuffer.length > 0 && !pam.passwd.active && !root.unlocking - enabled: visible - onClicked: parent.showPassword = !parent.showPassword - } - DankActionButton { - id: virtualKeyboardButton - - anchors.right: enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right) - anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard" - buttonSize: 32 - visible: !demoMode && !pam.passwd.active && !root.unlocking && !pam.u2fPending - enabled: visible - onClicked: { - if (keyboardController.isKeyboardActive) { - keyboardController.hide(); - } else { - keyboardController.show(); - } - } - } - - Rectangle { - id: loadingSpinner - - anchors.right: enterButton.visible ? enterButton.left : parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 24 - height: 24 - radius: 12 - color: "transparent" - visible: !demoMode && (pam.passwd.active || root.unlocking) - - DankIcon { - anchors.centerIn: parent - name: "check_circle" - size: 20 - color: Theme.primary - visible: root.unlocking - - SequentialAnimation on scale { - running: root.unlocking - - NumberAnimation { - from: 0 - to: 1.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - NumberAnimation { - from: 1.2 - to: 1 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - } - } - - Item { - anchors.fill: parent - visible: pam.passwd.active && !root.unlocking - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.centerIn: parent - color: "transparent" - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) - border.width: 2 - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.centerIn: parent - color: "transparent" - border.color: Theme.primary - border.width: 2 - - Rectangle { - width: parent.width - height: parent.height / 2 - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - } - - RotationAnimation on rotation { - running: pam.passwd.active && !root.unlocking - loops: Animation.Infinite - duration: Anims.durLong - from: 0 - to: 360 - } - } - } - } - - DankActionButton { - id: enterButton - - anchors.right: parent.right - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard_return" - buttonSize: 36 - visible: (demoMode || (!pam.passwd.active && !root.unlocking && !pam.u2fPending)) - enabled: !demoMode - onClicked: { - if (!demoMode && !root.unlocking && !pam.u2fPending) { - pam.passwd.start(); - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - id: authFeedbackText - - Layout.fillWidth: true - Layout.preferredHeight: text.length > 0 ? Math.min(implicitHeight, Math.ceil(Theme.fontSizeSmall * 4.5)) : 0 - text: root.currentAuthFeedbackText() - color: root.authFeedbackIsHint() ? Theme.outline : Theme.error - font.pixelSize: Theme.fontSizeSmall - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 3 - elide: Text.ElideRight - opacity: text.length > 0 ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Row { - anchors.top: passwordLayout.bottom - anchors.topMargin: Theme.spacingS - anchors.horizontalCenter: passwordLayout.horizontalCenter - spacing: 4 - opacity: DMSService.capsLockState ? 1 : 0 - - DankIcon { - name: "shift_lock" - size: 14 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Caps Lock is on") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: Theme.spacingXL - text: I18n.tr("DEMO MODE - Click anywhere to exit") - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - visible: demoMode - } - - Row { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXL - spacing: Theme.spacingL - visible: SettingsData.lockScreenShowSystemIcons - - Item { - width: keyboardLayoutRow.width - height: keyboardLayoutRow.height - anchors.verticalCenter: parent.verticalCenter - visible: { - if (CompositorService.isNiri) { - return NiriService.keyboardLayoutNames.length > 1; - } else if (CompositorService.isHyprland) { - return hyprlandLayoutCount > 1; - } - return false; - } - - Row { - id: keyboardLayoutRow - spacing: 4 - - Item { - width: Theme.iconSize - height: Theme.iconSize - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: "white" - anchors.centerIn: parent - } - } - - Item { - width: childrenRect.width - height: Theme.iconSize - - StyledText { - text: { - if (CompositorService.isNiri) { - const layout = NiriService.getCurrentKeyboardLayoutName(); - if (!layout) - return ""; - const parts = layout.split(" "); - if (parts.length > 0) { - return parts[0].substring(0, 2).toUpperCase(); - } - return layout.substring(0, 2).toUpperCase(); - } else if (CompositorService.isHyprland) { - return hyprlandCurrentLayout; - } - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: keyboardLayoutArea - anchors.fill: parent - enabled: !demoMode - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]); - updateHyprlandLayout(); - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer - } - - Row { - spacing: Theme.spacingS - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer - anchors.verticalCenter: parent.verticalCenter - - Item { - width: 20 - height: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - - Loader { - active: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing - - sourceComponent: Component { - Ref { - service: CavaService - } - } - } - - Timer { - running: !CavaService.cavaAvailable && MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing - interval: 256 - repeat: true - onTriggered: { - CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25]; - } - } - - Row { - anchors.centerIn: parent - spacing: 1.5 - - Repeater { - model: 6 - delegate: Rectangle { - required property int index - - width: 2 - height: { - if (MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing && CavaService.values.length > index) { - const rawLevel = CavaService.values[index] || 0; - const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100; - const maxHeight = Theme.iconSize - 2; - const minHeight = 3; - return minHeight + (scaledLevel / 100) * (maxHeight - minHeight); - } - return 3; - } - radius: 1.5 - color: "white" - anchors.verticalCenter: parent.verticalCenter - - Behavior on height { - NumberAnimation { - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.standardDecel - } - } - } - } - } - } - - StyledText { - text: { - const player = MprisController.activePlayer; - if (!player?.trackTitle) - return ""; - const title = player.trackTitle; - const artist = player.trackArtist || ""; - return artist ? title + " • " + artist : title; - } - font.pixelSize: Theme.fontSizeLarge - color: "white" - opacity: 0.9 - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: Math.min(implicitWidth, 400) - wrapMode: Text.NoWrap - maximumLineCount: 1 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: prevArea.containsMouse ? Qt.rgba(255, 255, 255, 0.2) : "transparent" - visible: MprisController.activePlayer - opacity: (MprisController.activePlayer?.canGoPrevious ?? false) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 12 - color: "white" - } - - MouseArea { - id: prevArea - anchors.fill: parent - enabled: MprisController.activePlayer?.canGoPrevious ?? false - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.verticalCenter: parent.verticalCenter - color: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? Qt.rgba(255, 255, 255, 0.9) : Qt.rgba(255, 255, 255, 0.2) - visible: MprisController.activePlayer - - DankIcon { - anchors.centerIn: parent - name: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 14 - color: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? "black" : "white" - } - - MouseArea { - anchors.fill: parent - enabled: MprisController.activePlayer - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.activePlayer?.togglePlaying() - } - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: nextArea.containsMouse ? Qt.rgba(255, 255, 255, 0.2) : "transparent" - visible: MprisController.activePlayer - opacity: (MprisController.activePlayer?.canGoNext ?? false) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 12 - color: "white" - } - - MouseArea { - id: nextArea - anchors.fill: parent - enabled: MprisController.activePlayer?.canGoNext ?? false - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.activePlayer?.next() - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer && WeatherService.weather.available - } - - Row { - spacing: 6 - visible: WeatherService.weather.available - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) - - DankIcon { - name: "screen_record" - size: Theme.iconSize - 2 - color: NiriService.hasActiveCast ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NiriService.hasCasts - } - - DankIcon { - name: { - if (NetworkService.wifiToggling) - return "sync"; - switch (NetworkService.networkStatus) { - case "ethernet": - return "lan"; - case "vpn": - return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon; - default: - return NetworkService.wifiSignalIcon; - } - } - size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkAvailable - } - - DankIcon { - name: "vpn_lock" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.vpnAvailable && NetworkService.vpnConnected - } - - DankIcon { - name: "bluetooth" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: BluetoothService.available && BluetoothService.enabled - } - - DankIcon { - name: { - if (!AudioService.sink?.audio) { - return "volume_up"; - } - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) { - return "volume_down"; - } - return "volume_up"; - } - size: Theme.iconSize - 2 - color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" - anchors.verticalCenter: parent.verticalCenter - visible: AudioService.sink && AudioService.sink.audio - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) - } - - Row { - spacing: 4 - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - - return "battery_1_bar"; - } - size: Theme.iconSize - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return "white"; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryLevel + "%" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - DankActionButton { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Theme.spacingXL - visible: SettingsData.lockScreenShowPowerActions - iconName: "power_settings_new" - iconColor: Theme.error - buttonSize: 40 - onClicked: { - if (demoMode) { - console.log("Demo: Power Menu"); - } else { - powerMenu.show(); - } - } - } - } - - Pam { - id: pam - lockSecured: !demoMode - onUnlockRequested: { - root.unlocking = true; - lockerReadyArmed = false; - passwordField.text = ""; - root.passwordBuffer = ""; - root.unlockRequested(); - } - onStateChanged: { - root.pamState = state; - if (state !== "") { - root.unlocking = false; - placeholderDelay.restart(); - passwordField.text = ""; - root.passwordBuffer = ""; - } - } - onU2fPendingChanged: { - if (u2fPending) { - passwordField.text = ""; - root.passwordBuffer = ""; - if (keyboardController.isKeyboardActive) - keyboardController.hide(); - } - } - } - - Connections { - target: pam - - function onUnlockInProgressChanged() { - if (!pam.unlockInProgress && root.unlocking) - root.unlocking = false; - } - } - - Binding { - target: pam - property: "buffer" - value: root.passwordBuffer - } - - Timer { - id: placeholderDelay - - interval: 4000 - onTriggered: root.pamState = "" - } - - MouseArea { - anchors.fill: parent - enabled: demoMode - onClicked: root.unlockRequested() - } - - LockPowerMenu { - id: powerMenu - showLogout: true - onClosed: { - if (!demoMode && passwordField && passwordField.forceActiveFocus) { - Qt.callLater(() => passwordField.forceActiveFocus()); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml deleted file mode 100644 index e13eac9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml +++ /dev/null @@ -1,46 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland - -PanelWindow { - id: root - - property bool demoActive: false - - visible: demoActive - - anchors { - top: true - bottom: true - left: true - right: true - } - - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive - - color: "transparent" - - function showDemo(): void { - console.log("Showing lock screen demo"); - demoActive = true; - } - - function hideDemo(): void { - console.log("Hiding lock screen demo"); - demoActive = false; - } - - Loader { - anchors.fill: parent - active: demoActive - sourceComponent: LockScreenContent { - demoMode: true - screenName: root.screen?.name ?? "" - onUnlockRequested: root.hideDemo() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml deleted file mode 100644 index 9d1beae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml +++ /dev/null @@ -1,73 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Wayland -import qs.Common - -FocusScope { - id: root - - required property WlSessionLock lock - required property string sharedPasswordBuffer - required property string screenName - required property bool isLocked - - signal passwordChanged(string newPassword) - signal unlockRequested - - Keys.onPressed: event => { - if (videoScreensaver.active && videoScreensaver.inputEnabled) { - videoScreensaver.dismiss(); - event.accepted = true; - } - } - - Rectangle { - anchors.fill: parent - color: "transparent" - } - - LockScreenContent { - id: lockContent - - anchors.fill: parent - demoMode: false - passwordBuffer: root.sharedPasswordBuffer - screenName: root.screenName - enabled: !videoScreensaver.active - focus: !videoScreensaver.active - opacity: videoScreensaver.active ? 0 : 1 - onUnlockRequested: root.unlockRequested() - onPasswordBufferChanged: { - if (root.sharedPasswordBuffer !== passwordBuffer) { - root.passwordChanged(passwordBuffer); - } - } - - Behavior on opacity { - NumberAnimation { - duration: 200 - } - } - } - - VideoScreensaver { - id: videoScreensaver - anchors.fill: parent - screenName: root.screenName - } - - Component.onCompleted: forceActiveFocus() - - onIsLockedChanged: { - if (isLocked) { - forceActiveFocus(); - lockContent.resetLockState(); - if (SettingsData.lockScreenVideoEnabled) { - videoScreensaver.start(); - } - return; - } - lockContent.unlocking = false; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml deleted file mode 100644 index f5e7859..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml +++ /dev/null @@ -1,405 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Services.Pam -import qs.Common - -Scope { - id: root - - property bool lockSecured: false - property bool unlockInProgress: false - - readonly property alias passwd: passwd - readonly property alias fprint: fprint - readonly property alias u2f: u2f - property string lockMessage - property string state - property string fprintState - property string u2fState - property bool u2fPending: false - property string buffer - - signal flashMsg - signal unlockRequested - - function resetAuthFlows(): void { - passwd.abort(); - fprint.abort(); - u2f.abort(); - errorRetry.running = false; - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - passwdActiveTimeout.running = false; - unlockRequestTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - root.unlockInProgress = false; - } - - function recoverFromAuthStall(newState: string): void { - resetAuthFlows(); - root.state = newState; - flashMsg(); - stateReset.restart(); - fprint.checkAvail(); - u2f.checkAvail(); - } - - function completeUnlock(): void { - if (!root.unlockInProgress) { - root.unlockInProgress = true; - passwd.abort(); - fprint.abort(); - u2f.abort(); - errorRetry.running = false; - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - unlockRequestTimeout.restart(); - unlockRequested(); - } - } - - function proceedAfterPrimaryAuth(): void { - if (SettingsData.enableU2f && SettingsData.u2fMode === "and" && u2f.available) { - u2f.startForSecondFactor(); - } else { - completeUnlock(); - } - } - - function cancelU2fPending(): void { - if (!root.u2fPending) - return; - u2f.abort(); - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - fprint.checkAvail(); - } - - FileView { - id: dankshellConfigWatcher - - path: "/etc/pam.d/dankshell" - printErrors: false - } - - FileView { - id: nixosMarker - - path: "/etc/NIXOS" - printErrors: false - } - - FileView { - id: u2fConfigWatcher - - path: "/etc/pam.d/dankshell-u2f" - printErrors: false - } - - // Detects Nix-installed DMS on non-NixOS systems - readonly property bool runningFromNixStore: Quickshell.shellDir.startsWith("/nix/store/") - - PamContext { - id: passwd - - config: dankshellConfigWatcher.loaded ? "dankshell" : "login" - configDirectory: (dankshellConfigWatcher.loaded || nixosMarker.loaded || root.runningFromNixStore) ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam" - - onMessageChanged: { - if (message.startsWith("The account is locked")) { - root.lockMessage = message; - } else if (root.lockMessage && message.endsWith(" left to unlock)")) { - root.lockMessage += "\n" + message; - } else if (root.lockMessage && message && message.length > 0) { - root.lockMessage = ""; - } - } - - onResponseRequiredChanged: { - if (!responseRequired) - return; - - respond(root.buffer); - } - - onCompleted: res => { - if (res === PamResult.Success) { - if (!root.unlockInProgress) { - fprint.abort(); - root.proceedAfterPrimaryAuth(); - } - return; - } - - unlockRequestTimeout.running = false; - root.unlockInProgress = false; - root.u2fPending = false; - root.u2fState = ""; - u2fPendingTimeout.running = false; - u2f.abort(); - - if (res === PamResult.Error) - root.state = "error"; - else if (res === PamResult.MaxTries) - root.state = "max"; - else if (res === PamResult.Failed) - root.state = "fail"; - - root.flashMsg(); - stateReset.restart(); - } - } - - Connections { - target: passwd - - function onActiveChanged() { - if (passwd.active) { - passwdActiveTimeout.restart(); - } else { - passwdActiveTimeout.running = false; - } - } - } - - PamContext { - id: fprint - - property bool available: SettingsData.lockFingerprintReady - property int tries - property int errorTries - - function checkAvail(): void { - if (!available || !SettingsData.enableFprint || !root.lockSecured) { - abort(); - return; - } - - tries = 0; - errorTries = 0; - start(); - } - - config: "fprint" - configDirectory: Quickshell.shellDir + "/assets/pam" - - onCompleted: res => { - if (!available) - return; - - if (res === PamResult.Success) { - if (!root.unlockInProgress) { - passwd.abort(); - root.proceedAfterPrimaryAuth(); - } - return; - } - - if (res === PamResult.Error) { - root.fprintState = "error"; - errorTries++; - if (errorTries < 5) { - abort(); - errorRetry.restart(); - } - } else if (res === PamResult.MaxTries) { - tries++; - if (tries < SettingsData.maxFprintTries) { - root.fprintState = "fail"; - start(); - } else { - root.fprintState = "max"; - abort(); - } - } - - root.flashMsg(); - fprintStateReset.start(); - } - } - - PamContext { - id: u2f - - property bool available: SettingsData.lockU2fReady - - function checkAvail(): void { - if (!available || !SettingsData.enableU2f || !root.lockSecured) { - abort(); - return; - } - - if (SettingsData.u2fMode === "or") { - start(); - } - } - - function startForSecondFactor(): void { - if (!available || !SettingsData.enableU2f) { - root.completeUnlock(); - return; - } - abort(); - root.u2fPending = true; - root.u2fState = ""; - u2fPendingTimeout.restart(); - start(); - } - - config: u2fConfigWatcher.loaded ? "dankshell-u2f" : "u2f" - configDirectory: u2fConfigWatcher.loaded ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam" - - onMessageChanged: { - if (message.toLowerCase().includes("touch")) - root.u2fState = "waiting"; - } - - onCompleted: res => { - if (!available || root.unlockInProgress) - return; - - if (res === PamResult.Success) { - root.completeUnlock(); - return; - } - - if (res === PamResult.Error || res === PamResult.MaxTries || res === PamResult.Failed) { - abort(); - - if (root.u2fPending) { - if (root.u2fState === "waiting") { - // AND mode: device was found but auth failed → back to password - root.u2fPending = false; - root.u2fState = ""; - fprint.checkAvail(); - } else { - // AND mode: no device found → keep pending, show "Insert...", retry - root.u2fState = "insert"; - u2fErrorRetry.restart(); - } - } else { - // OR mode: prompt to insert key, silently retry - root.u2fState = "insert"; - u2fErrorRetry.restart(); - } - } - } - } - - Timer { - id: errorRetry - - interval: 800 - onTriggered: fprint.start() - } - - Timer { - id: u2fErrorRetry - - interval: 800 - onTriggered: u2f.start() - } - - Timer { - id: u2fPendingTimeout - - interval: 30000 - onTriggered: root.cancelU2fPending() - } - - Timer { - id: passwdActiveTimeout - - interval: 15000 - onTriggered: { - if (passwd.active) - root.recoverFromAuthStall("error"); - } - } - - Timer { - id: unlockRequestTimeout - - interval: 8000 - onTriggered: { - if (root.unlockInProgress) - root.recoverFromAuthStall("error"); - } - } - - Timer { - id: stateReset - - interval: 4000 - onTriggered: { - if (root.state !== "max") - root.state = ""; - } - } - - Timer { - id: fprintStateReset - - interval: 4000 - onTriggered: { - root.fprintState = ""; - fprint.errorTries = 0; - } - } - - onLockSecuredChanged: { - if (lockSecured) { - SettingsData.refreshAuthAvailability(); - root.state = ""; - root.fprintState = ""; - root.u2fState = ""; - root.u2fPending = false; - root.lockMessage = ""; - root.resetAuthFlows(); - fprint.checkAvail(); - u2f.checkAvail(); - } else { - root.resetAuthFlows(); - } - } - - Connections { - target: SettingsData - - function onEnableFprintChanged(): void { - fprint.checkAvail(); - } - - function onLockFingerprintReadyChanged(): void { - fprint.checkAvail(); - } - - function onEnableU2fChanged(): void { - u2f.checkAvail(); - } - - function onLockU2fReadyChanged(): void { - u2f.checkAvail(); - } - - function onU2fModeChanged(): void { - if (root.lockSecured) { - u2f.abort(); - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - unlockRequestTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - u2f.checkAvail(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml deleted file mode 100644 index 129f507..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml +++ /dev/null @@ -1,200 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Io -import qs.Common -import qs.Services - -Item { - id: root - - required property string screenName - property bool active: false - property string videoSource: "" - property bool inputEnabled: false - property point lastMousePos: Qt.point(-1, -1) - property bool mouseInitialized: false - property var videoPlayer: null - - signal dismissed - - visible: active - z: 1000 - - Rectangle { - id: background - anchors.fill: parent - color: "black" - visible: root.active - } - - Timer { - id: inputEnableTimer - interval: 500 - onTriggered: root.inputEnabled = true - } - - Process { - id: videoPicker - property string result: "" - property string folder: "" - - command: ["sh", "-c", "find '" + folder + "' -maxdepth 1 -type f \\( " + "-iname '*.mp4' -o -iname '*.mkv' -o -iname '*.webm' -o " + "-iname '*.mov' -o -iname '*.avi' -o -iname '*.m4v' " + "\\) 2>/dev/null | shuf -n1"] - - stdout: SplitParser { - onRead: data => { - const path = data.trim(); - if (path) { - videoPicker.result = path; - root.videoSource = "file://" + path; - } - } - } - - onExited: exitCode => { - if (exitCode !== 0 || !videoPicker.result) { - console.warn("VideoScreensaver: no video found in folder"); - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("No video found in folder")); - root.dismiss(); - } - } - } - - Process { - id: fileChecker - command: ["test", "-d", SettingsData.lockScreenVideoPath] - - onExited: exitCode => { - const isDir = exitCode === 0; - const videoPath = SettingsData.lockScreenVideoPath; - - if (isDir) { - videoPicker.folder = videoPath; - videoPicker.running = true; - } else if (SettingsData.lockScreenVideoCycling) { - const parentFolder = videoPath.substring(0, videoPath.lastIndexOf('/')); - videoPicker.folder = parentFolder; - videoPicker.running = true; - } else { - root.videoSource = "file://" + videoPath; - } - } - } - - function createVideoPlayer() { - if (videoPlayer) - return true; - - try { - videoPlayer = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - Video { - anchors.fill: parent - fillMode: VideoOutput.PreserveAspectCrop - loops: MediaPlayer.Infinite - volume: 0 - } - `, background, "VideoScreensaver.VideoPlayer"); - - videoPlayer.errorOccurred.connect((error, errorString) => { - console.warn("VideoScreensaver: playback error:", errorString); - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("Playback error: ") + errorString); - root.dismiss(); - }); - - return true; - } catch (e) { - console.warn("VideoScreensaver: Failed to create video player:", e); - return false; - } - } - - function destroyVideoPlayer() { - if (videoPlayer) { - videoPlayer.stop(); - videoPlayer.destroy(); - videoPlayer = null; - } - } - - function start() { - if (!SettingsData.lockScreenVideoEnabled || !SettingsData.lockScreenVideoPath) - return; - - if (!MultimediaService.available) { - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("QtMultimedia is not available")); - return; - } - - if (!createVideoPlayer()) - return; - - videoPicker.result = ""; - videoPicker.folder = ""; - inputEnabled = false; - mouseInitialized = false; - lastMousePos = Qt.point(-1, -1); - active = true; - inputEnableTimer.start(); - fileChecker.running = true; - } - - function dismiss() { - if (!active) - return; - destroyVideoPlayer(); - inputEnabled = false; - active = false; - videoSource = ""; - dismissed(); - } - - onVideoSourceChanged: { - if (videoSource && active && videoPlayer) { - videoPlayer.source = videoSource; - videoPlayer.play(); - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - enabled: root.active && root.inputEnabled - hoverEnabled: true - propagateComposedEvents: false - - onPositionChanged: mouse => { - if (!root.mouseInitialized) { - root.lastMousePos = Qt.point(mouse.x, mouse.y); - root.mouseInitialized = true; - return; - } - var dx = Math.abs(mouse.x - root.lastMousePos.x); - var dy = Math.abs(mouse.y - root.lastMousePos.y); - if (dx > 5 || dy > 5) { - root.dismiss(); - } - } - onClicked: root.dismiss() - onPressed: root.dismiss() - onWheel: root.dismiss() - } - - Connections { - target: IdleService - - function onLockRequested() { - if (SettingsData.lockScreenVideoEnabled && !root.active) { - root.start(); - } - } - - function onFadeToLockRequested() { - if (SettingsData.lockScreenVideoEnabled && !root.active) { - IdleService.cancelFadeToLock(); - root.start(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml deleted file mode 100644 index e294695..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml +++ /dev/null @@ -1,531 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool fileDialogOpen: false - property string currentFileName: "" - property url currentFileUrl - property bool confirmationDialogOpen: false - property string pendingAction: "" - property url pendingFileUrl - property string lastSavedFileContent: "" - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool showSettingsMenu: false - property string pendingSaveContent: "" - property var slideout: null - - signal hideRequested - signal previewRequested(string content) - - Ref { - service: NotepadStorageService - } - - Connections { - target: slideout - enabled: slideout !== null - function onAboutToHide() { - textEditor.autoSaveToSession() - } - } - - function hasUnsavedChanges() { - return textEditor.hasUnsavedChanges(); - } - - function hasUnsavedTemporaryContent() { - return hasUnsavedChanges(); - } - - function createNewTab() { - performCreateNewTab(); - } - - function performCreateNewTab() { - NotepadStorageService.createNewTab(); - textEditor.text = ""; - textEditor.lastSavedContent = ""; - textEditor.contentLoaded = true; - textEditor.textArea.forceActiveFocus(); - } - - function closeTab(tabIndex) { - if (tabIndex === NotepadStorageService.currentTabIndex && hasUnsavedChanges()) { - root.pendingAction = "close_tab_" + tabIndex; - root.confirmationDialogOpen = true; - confirmationDialogLoader.active = true; - if (confirmationDialogLoader.item) - confirmationDialogLoader.item.open(); - } else { - performCloseTab(tabIndex); - } - } - - function performCloseTab(tabIndex) { - NotepadStorageService.closeTab(tabIndex); - Qt.callLater(() => { - textEditor.loadCurrentTabContent(); - }); - } - - function switchToTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length) - return; - if (textEditor.contentLoaded) { - textEditor.autoSaveToSession(); - } - - NotepadStorageService.switchToTab(tabIndex); - Qt.callLater(() => { - textEditor.loadCurrentTabContent(); - if (currentTab) { - root.currentFileName = currentTab.fileName || ""; - root.currentFileUrl = currentTab.fileUrl || ""; - } - }); - } - - function saveToFile(fileUrl) { - if (!currentTab) - return; - var content = textEditor.text; - var filePath = fileUrl.toString().replace(/^file:\/\//, ''); - - saveFileView.path = ""; - pendingSaveContent = content; - saveFileView.path = filePath; - - Qt.callLater(() => { - saveFileView.setText(pendingSaveContent); - }); - } - - function loadFromFile(fileUrl) { - if (hasUnsavedTemporaryContent()) { - root.pendingFileUrl = fileUrl; - root.pendingAction = "load_file"; - root.confirmationDialogOpen = true; - confirmationDialogLoader.active = true; - if (confirmationDialogLoader.item) - confirmationDialogLoader.item.open(); - } else { - performLoadFromFile(fileUrl); - } - } - - function performLoadFromFile(fileUrl) { - const filePath = fileUrl.toString().replace(/^file:\/\//, ''); - const fileName = filePath.split('/').pop(); - - loadFileView.path = ""; - loadFileView.path = filePath; - - if (loadFileView.waitForJob()) { - Qt.callLater(() => { - var content = loadFileView.text(); - if (currentTab && content !== undefined && content !== null) { - textEditor.text = content; - textEditor.lastSavedContent = content; - textEditor.contentLoaded = true; - root.lastSavedFileContent = content; - - NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { - title: fileName, - filePath: filePath, - isTemporary: false - }); - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - textEditor.saveCurrentTabContent(); - } - }); - } - } - - Column { - anchors.fill: parent - spacing: Theme.spacingM - - NotepadTabs { - id: tabBar - width: parent.width - contentLoaded: textEditor.contentLoaded - - onTabSwitched: tabIndex => { - switchToTab(tabIndex); - } - - onTabClosed: tabIndex => { - closeTab(tabIndex); - } - - onNewTabRequested: { - createNewTab(); - } - } - - NotepadTextEditor { - id: textEditor - width: parent.width - height: parent.height - tabBar.height - Theme.spacingM * 2 - - onSaveRequested: { - if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - var fileUrl = "file://" + currentTab.filePath; - saveToFile(fileUrl); - } else { - root.fileDialogOpen = true; - saveBrowserLoader.active = true; - if (saveBrowserLoader.item) - saveBrowserLoader.item.open(); - } - } - - onOpenRequested: { - textEditor.autoSaveToSession(); - if (textEditor.text.length > 0) { - createNewTab(); - } - - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - } - - onNewRequested: { - textEditor.autoSaveToSession(); - createNewTab(); - } - - onPreviewRequested: { - textEditor.togglePreview(); - } - - onEscapePressed: { - textEditor.autoSaveToSession() - root.hideRequested() - } - - onSettingsRequested: { - showSettingsMenu = !showSettingsMenu; - } - } - } - - NotepadSettings { - id: notepadSettings - anchors.fill: parent - isVisible: showSettingsMenu - onSettingsRequested: showSettingsMenu = !showSettingsMenu - onFindRequested: { - showSettingsMenu = false; - textEditor.showSearch(); - } - } - - FileView { - id: saveFileView - blockWrites: true - preload: false - atomicWrites: true - printErrors: true - - onSaved: { - if (currentTab && saveFileView.path && pendingSaveContent) { - NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { - hasUnsavedChanges: false, - lastSavedContent: pendingSaveContent - }); - root.lastSavedFileContent = pendingSaveContent; - pendingSaveContent = ""; - } - } - - onSaveFailed: error => { - pendingSaveContent = ""; - } - } - - FileView { - id: loadFileView - blockLoading: true - preload: true - atomicWrites: true - printErrors: true - - onLoadFailed: error => {} - } - - LazyLoader { - id: saveBrowserLoader - active: false - - FileBrowserSurfaceModal { - id: saveBrowser - - browserTitle: I18n.tr("Save Notepad File") - browserIcon: "save" - browserType: "notepad_save" - fileExtensions: ["*.txt", "*.md", "*.*"] - allowStacking: true - saveMode: true - defaultFileName: { - if (currentTab && currentTab.title && currentTab.title !== "Untitled") { - return currentTab.title; - } else if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - return currentTab.filePath.split('/').pop(); - } else { - return "note.txt"; - } - } - - onFileSelected: path => { - root.fileDialogOpen = false; - const cleanPath = decodeURI(path.toString().replace(/^file:\/\//, '')); - const fileName = cleanPath.split('/').pop(); - const fileUrl = "file://" + cleanPath; - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - - if (currentTab) { - NotepadStorageService.saveTabAs(NotepadStorageService.currentTabIndex, cleanPath); - } - - saveToFile(fileUrl); - - if (root.pendingAction === "new") { - Qt.callLater(() => { - createNewTab(); - }); - } else if (root.pendingAction === "open") { - Qt.callLater(() => { - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - }); - } else if (root.pendingAction.startsWith("close_tab_")) { - Qt.callLater(() => { - var tabIndex = parseInt(root.pendingAction.split("_")[2]); - performCloseTab(tabIndex); - }); - } - root.pendingAction = ""; - - close(); - } - - onDialogClosed: { - root.fileDialogOpen = false; - } - } - } - - LazyLoader { - id: loadBrowserLoader - active: false - - FileBrowserSurfaceModal { - id: loadBrowser - - browserTitle: I18n.tr("Open Notepad File") - browserIcon: "folder_open" - browserType: "notepad_load" - fileExtensions: ["*.txt", "*.md", "*.*"] - allowStacking: true - - onFileSelected: path => { - root.fileDialogOpen = false; - const cleanPath = path.toString().replace(/^file:\/\//, ''); - const fileName = cleanPath.split('/').pop(); - const fileUrl = "file://" + cleanPath; - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - - loadFromFile(fileUrl); - close(); - } - - onDialogClosed: { - root.fileDialogOpen = false; - } - } - } - - LazyLoader { - id: confirmationDialogLoader - active: false - - DankModal { - id: confirmationDialog - - modalWidth: 400 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 180 - shouldBeVisible: false - allowStacking: true - - onBackgroundClicked: { - close(); - root.confirmationDialogOpen = false; - } - - content: Component { - FocusScope { - anchors.fill: parent - focus: true - implicitHeight: contentColumn.implicitHeight - - Keys.onEscapePressed: event => { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - event.accepted = true; - } - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Unsaved Changes") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: root.pendingAction === "new" ? I18n.tr("You have unsaved changes. Save before creating a new file?") : root.pendingAction.startsWith("close_tab_") ? I18n.tr("You have unsaved changes. Save before closing this tab?") : root.pendingAction === "load_file" || root.pendingAction === "open" ? I18n.tr("You have unsaved changes. Save before opening a file?") : I18n.tr("You have unsaved changes. Save before continuing?") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(80, discardText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: discardArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: discardText - anchors.centerIn: parent - text: I18n.tr("Don't Save") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: discardArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - if (root.pendingAction === "new") { - createNewTab(); - } else if (root.pendingAction === "open") { - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - } else if (root.pendingAction === "load_file") { - performLoadFromFile(root.pendingFileUrl); - } else if (root.pendingAction.startsWith("close_tab_")) { - var tabIndex = parseInt(root.pendingAction.split("_")[2]); - performCloseTab(tabIndex); - } - root.pendingAction = ""; - root.pendingFileUrl = ""; - } - } - } - - Rectangle { - width: Math.max(70, saveAsText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: saveAsArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: saveAsText - anchors.centerIn: parent - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: saveAsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - root.fileDialogOpen = true; - saveBrowserLoader.active = true; - if (saveBrowserLoader.item) - saveBrowserLoader.item.open(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml deleted file mode 100644 index 9265ddf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml +++ /dev/null @@ -1,367 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property bool isVisible: false - property var cachedFontFamilies: [] - property var cachedMonoFamilies: [] - property bool fontsEnumerated: false - - signal settingsRequested - signal findRequested - - function enumerateFonts() { - var fonts = ["Default"]; - var availableFonts = Qt.fontFamilies(); - var rootFamilies = []; - var seenFamilies = new Set(); - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - if (fontName === Theme.defaultFontFamily) - continue; - var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function (match, suffix) { - return match; - }).trim(); - if (!seenFamilies.has(rootName) && rootName !== "") { - seenFamilies.add(rootName); - rootFamilies.push(rootName); - } - } - cachedFontFamilies = fonts.concat(rootFamilies.sort()); - var monoFonts = ["Default"]; - var monoFamilies = []; - var seenMonoFamilies = new Set(); - for (var j = 0; j < availableFonts.length; j++) { - var fontName2 = availableFonts[j]; - if (fontName2.startsWith(".")) - continue; - if (fontName2 === SettingsData.defaultMonoFontFamily) - continue; - var lowerName = fontName2.toLowerCase(); - if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { - var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim(); - if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") { - seenMonoFamilies.add(rootName2); - monoFamilies.push(rootName2); - } - } - } - cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()); - fontsEnumerated = true; - } - - Component.onCompleted: { - if (!fontsEnumerated) { - enumerateFonts(); - } - } - - MouseArea { - anchors.fill: parent - visible: root.isVisible - onClicked: root.settingsRequested() - z: 50 - } - - Rectangle { - id: settingsMenu - visible: root.isVisible - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - width: 360 - height: settingsColumn.implicitHeight + Theme.spacingXL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, Theme.notepadTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - z: 100 - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: parent.z - 1 - } - - Column { - id: settingsColumn - width: parent.width - Theme.spacingXL * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingXL - spacing: Theme.spacingS - - Rectangle { - width: parent.width - height: 36 - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Notepad Font Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Use Monospace Font") - description: "Toggle fonts" - checked: SettingsData.notepadUseMonospace - onToggled: checked => { - SettingsData.notepadUseMonospace = checked; - } - } - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Show Line Numbers") - description: "Display line numbers in editor" - checked: SettingsData.notepadShowLineNumbers - onToggled: checked => { - SettingsData.notepadShowLineNumbers = checked; - } - } - - StyledRect { - width: parent.width - height: 60 - radius: Theme.cornerRadius - color: "transparent" - - StateLayer { - anchors.fill: parent - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - stateColor: Theme.primary - cornerRadius: parent.radius - onClicked: root.findRequested() - } - - Row { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "search" - size: Theme.iconSize - 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Find in Text") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Open search bar to find text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Rectangle { - width: parent.width - height: visible ? (fontDropdown.height + Theme.spacingS) : 0 - color: "transparent" - visible: !SettingsData.notepadUseMonospace - - DankDropdown { - id: fontDropdown - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Font Family") - options: cachedFontFamilies - currentValue: { - if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "") - return "Default (Global)"; - else - return SettingsData.notepadFontFamily; - } - enableFuzzySearch: true - onValueChanged: value => { - if (value && (value.startsWith("Default") || value === "Default (Global)")) { - SettingsData.notepadFontFamily = ""; - } else { - SettingsData.notepadFontFamily = value; - } - } - } - } - - Rectangle { - width: parent.width - height: fontSizeRow.height + Theme.spacingS - color: "transparent" - - Row { - id: fontSizeRow - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - fontSizeControls.width - Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Font Size") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: SettingsData.notepadFontSize + "px" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - } - } - - Row { - id: fontSizeControls - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 32 - iconName: "remove" - iconSize: Theme.iconSizeSmall - enabled: SettingsData.notepadFontSize > 8 - backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - iconColor: Theme.surfaceText - onClicked: { - var newSize = Math.max(8, SettingsData.notepadFontSize - 1); - SettingsData.notepadFontSize = newSize; - } - } - - Rectangle { - width: 60 - height: 32 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: SettingsData.notepadFontSize + "px" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - DankActionButton { - buttonSize: 32 - iconName: "add" - iconSize: Theme.iconSizeSmall - enabled: SettingsData.notepadFontSize < 48 - backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - iconColor: Theme.surfaceText - onClicked: { - var newSize = Math.min(48, SettingsData.notepadFontSize + 1); - SettingsData.notepadFontSize = newSize; - } - } - } - } - } - - Rectangle { - width: parent.width - height: transparencySliderColumn.height + Theme.spacingS - color: "transparent" - - Column { - id: transparencySliderColumn - width: parent.width - spacing: Theme.spacingS - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Custom Transparency") - description: "Override global transparency for Notepad" - checked: SettingsData.notepadTransparencyOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency; - } else { - SettingsData.notepadTransparencyOverride = -1; - } - } - } - - DankSlider { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - height: 24 - visible: SettingsData.notepadTransparencyOverride >= 0 - value: Math.round((SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : SettingsData.popupTransparency) * 100) - minimum: 0 - maximum: 100 - unit: "" - showValue: true - wheelEnabled: false - onSliderValueChanged: newValue => { - if (SettingsData.notepadTransparencyOverride >= 0) { - SettingsData.notepadTransparencyOverride = newValue / 100; - } - } - } - } - } - - StyledText { - width: parent.width - text: SettingsData.notepadUseMonospace ? "Using global monospace font from Settings → Personalization" : "Global fonts can be configured in Settings → Personalization" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - wrapMode: Text.WordWrap - opacity: 0.8 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml deleted file mode 100644 index 05a21d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml +++ /dev/null @@ -1,285 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Column { - id: root - - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool contentLoaded: false - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - readonly property real tabItemSize: 128 + Theme.spacingXS - - signal tabSwitched(int tabIndex) - signal tabClosed(int tabIndex) - signal newTabRequested - - function hasUnsavedChangesForTab(tab) { - if (!tab) - return false; - - if (tab.id === currentTab?.id) { - return root.parent?.hasUnsavedChanges ? root.parent.hasUnsavedChanges() : false; - } - return false; - } - - spacing: Theme.spacingXS - - Row { - width: parent.width - height: 36 - spacing: Theme.spacingXS - - ScrollView { - width: parent.width - newTabButton.width - Theme.spacingXS - height: parent.height - clip: true - - ScrollBar.horizontal.visible: false - ScrollBar.vertical.visible: false - - Row { - spacing: Theme.spacingXS - - Repeater { - model: NotepadStorageService.tabs - - delegate: Item { - id: delegateItem - required property int index - required property var modelData - - readonly property bool isActive: NotepadStorageService.currentTabIndex === index - readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse - readonly property real tabWidth: 128 - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property int targetIndex: -1 - property int originalIndex: -1 - property real dragAxisOffset: 0 - - Timer { - id: longPressTimer - interval: 200 - repeat: false - onTriggered: { - if (NotepadStorageService.tabs.length > 1) { - delegateItem.longPressing = true - } - } - } - - readonly property real shiftOffset: { - if (root.draggedIndex < 0) - return 0 - if (index === root.draggedIndex) - return 0 - var dragIdx = root.draggedIndex - var dropIdx = root.dropTargetIndex - var myIdx = index - var shiftAmount = root.tabItemSize - if (dropIdx < 0) - return 0 - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount - return 0 - } - - width: tabWidth - height: 32 - z: dragging ? 100 : 0 - - transform: Translate { - x: shiftOffset - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: tabVisual - anchors.fill: parent - z: 1 - layer.enabled: dragging - layer.smooth: true - - transform: Translate { - x: dragging ? dragAxisOffset : 0 - } - - Rectangle { - id: tabRect - anchors.fill: parent - radius: Theme.cornerRadius - color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0) - border.width: isActive || dragging ? 0 : 1 - border.color: dragging ? Theme.primary : Theme.outlineMedium - clip: true - - Row { - id: tabContent - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - id: tabText - width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0) - text: { - var prefix = "" - if (hasUnsavedChangesForTab(modelData)) { - prefix = "● " - } - return prefix + (modelData.title || "Untitled") - } - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.primary : Theme.surfaceText - font.weight: isActive ? Font.Medium : Font.Normal - elide: Text.ElideMiddle - maximumLineCount: 1 - wrapMode: Text.NoWrap - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: tabCloseButton - width: 20 - height: 20 - radius: Theme.cornerRadius - color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0) - visible: NotepadStorageService.tabs.length > 1 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "close" - size: 14 - color: Theme.surfaceTextMedium - anchors.centerIn: parent - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - z: 100 - - onClicked: root.tabClosed(index) - } - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - MouseArea { - id: tabMouseArea - anchors.fill: parent - hoverEnabled: true - preventStealing: dragging || longPressing - cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) { - delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y) - longPressTimer.start() - } - } - - onReleased: mouse => { - longPressTimer.stop() - var wasDragging = delegateItem.dragging - var didReorder = wasDragging && delegateItem.targetIndex >= 0 && delegateItem.targetIndex !== delegateItem.originalIndex - - if (didReorder) { - root.suppressShiftAnimation = true - NotepadStorageService.reorderTab(delegateItem.originalIndex, delegateItem.targetIndex) - } - - delegateItem.longPressing = false - delegateItem.dragging = false - delegateItem.dragAxisOffset = 0 - delegateItem.targetIndex = -1 - delegateItem.originalIndex = -1 - root.draggedIndex = -1 - root.dropTargetIndex = -1 - if (didReorder) { - Qt.callLater(() => { - root.suppressShiftAnimation = false - }) - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return - root.tabSwitched(index) - } - - onPositionChanged: mouse => { - if (delegateItem.longPressing && !delegateItem.dragging) { - var distance = Math.sqrt(Math.pow(mouse.x - delegateItem.dragStartPos.x, 2) + Math.pow(mouse.y - delegateItem.dragStartPos.y, 2)) - if (distance > 5) { - delegateItem.dragging = true - delegateItem.targetIndex = index - delegateItem.originalIndex = index - root.draggedIndex = index - root.dropTargetIndex = index - } - } - - if (!delegateItem.dragging) - return - - var axisOffset = mouse.x - delegateItem.dragStartPos.x - delegateItem.dragAxisOffset = axisOffset - - var itemSize = root.tabItemSize - var rawSlot = axisOffset / itemSize - var slotOffset = rawSlot >= 0 - ? Math.floor(rawSlot + 0.4) - : Math.ceil(rawSlot - 0.4) - var tabCount = NotepadStorageService.tabs.length - var newTargetIndex = Math.max(0, Math.min(tabCount - 1, delegateItem.originalIndex + slotOffset)) - - if (newTargetIndex !== delegateItem.targetIndex) { - delegateItem.targetIndex = newTargetIndex - root.dropTargetIndex = newTargetIndex - } - } - } - } - } - } - } - - DankActionButton { - id: newTabButton - width: 32 - height: 32 - iconName: "add" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.newTabRequested() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml deleted file mode 100644 index 7ea0b27..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml +++ /dev/null @@ -1,924 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -pragma ComponentBehavior: Bound - -Column { - id: root - - Component.onCompleted: { - if (PluginService.isPluginLoaded("dankNotepadModule")) { - pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "") - } - } - - property alias text: textArea.text - property alias textArea: textArea - property bool contentLoaded: false - property string lastSavedContent: "" - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool searchVisible: false - property string searchQuery: "" - property var searchMatches: [] - property int currentMatchIndex: -1 - property int matchCount: 0 - property bool inlinePreviewVisible: false - property string previewMode: "split" // split | full - property string pluginHighlightedHtml: "" - property string lastPluginContent: "" - property int loadRequestId: 0 - - signal saveRequested() - signal openRequested() - signal newRequested() - signal previewRequested() - signal escapePressed() - signal contentChanged() - signal settingsRequested() - - function hasUnsavedChanges() { - if (!currentTab || !contentLoaded) { - return false - } - - if (currentTab.isTemporary) { - return textArea.text.length > 0 - } - return textArea.text !== lastSavedContent - } - - function loadCurrentTabContent() { - if (!currentTab) return - - const requestedTabId = currentTab.id - const requestId = ++loadRequestId - contentLoaded = false - NotepadStorageService.loadTabContent( - NotepadStorageService.currentTabIndex, - (content) => { - const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex - ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] - : null - if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId) - return - - lastSavedContent = content - textArea.text = content - contentLoaded = true - syncContentToPlugin() - } - ) - } - - function saveCurrentTabContent() { - if (!currentTab || !contentLoaded) return - - NotepadStorageService.saveTabContent( - NotepadStorageService.currentTabIndex, - textArea.text - ) - lastSavedContent = textArea.text - } - - function autoSaveToSession() { - if (!currentTab || !contentLoaded) return - saveCurrentTabContent() - } - - function setTextDocumentLineHeight() { - return - } - - property string lastTextForLineModel: "" - property var lineModel: [] - - function updateLineModel() { - if (!SettingsData.notepadShowLineNumbers) { - lineModel = [] - lastTextForLineModel = "" - return - } - - if (textArea.text !== lastTextForLineModel || lineModel.length === 0) { - lastTextForLineModel = textArea.text - lineModel = textArea.text.split('\n') - } - } - - function performSearch() { - let matches = [] - currentMatchIndex = -1 - - if (!searchQuery || searchQuery.length === 0) { - searchMatches = [] - matchCount = 0 - textArea.select(0, 0) - return - } - - const text = textArea.text - const query = searchQuery.toLowerCase() - let index = 0 - - while (index < text.length) { - const foundIndex = text.toLowerCase().indexOf(query, index) - if (foundIndex === -1) break - - matches.push({ - start: foundIndex, - end: foundIndex + searchQuery.length - }) - index = foundIndex + 1 - } - - searchMatches = matches - matchCount = matches.length - - if (matchCount > 0) { - currentMatchIndex = 0 - highlightCurrentMatch() - } else { - textArea.select(0, 0) - } - } - - function highlightCurrentMatch() { - if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) { - const match = searchMatches[currentMatchIndex] - - textArea.cursorPosition = match.start - textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters) - - const flickable = textArea.parent - if (flickable && flickable.contentY !== undefined) { - const lineHeight = textArea.font.pixelSize * 1.5 - const approxLine = textArea.text.substring(0, match.start).split('\n').length - const targetY = approxLine * lineHeight - flickable.height / 2 - flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height)) - } - } - } - - function findNext() { - if (matchCount === 0 || searchMatches.length === 0) return - - currentMatchIndex = (currentMatchIndex + 1) % matchCount - highlightCurrentMatch() - } - - function findPrevious() { - if (matchCount === 0 || searchMatches.length === 0) return - - currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1 - highlightCurrentMatch() - } - - function showSearch() { - searchVisible = true - Qt.callLater(() => { - searchField.forceActiveFocus() - }) - } - - function togglePreview() { - if (!inlinePreviewVisible) { - inlinePreviewVisible = true - previewMode = "split" - } else if (previewMode === "split") { - previewMode = "full" - } else { - inlinePreviewVisible = false - previewMode = "split" - } - syncContentToPlugin() - } - - function renderPreviewHtml() { - if (!inlinePreviewVisible) return "" - return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "

        Rendering preview…

        " - } - - function syncContentToPlugin() { - if (!PluginService.isPluginLoaded("dankNotepadModule")) - return - - if (!currentTab) - return - - const filePath = currentTab?.filePath || "" - const ext = filePath.split('.').pop().toLowerCase() - const content = textArea.text - - if (content === lastPluginContent && SettingsData.getBuiltInPluginSetting("dankNotepadModule", "previewActive", false) === inlinePreviewVisible) { - return - } - - lastPluginContent = content - SettingsData.setBuiltInPluginSetting("dankNotepadModule", "previewActive", inlinePreviewVisible) - SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFilePath", filePath) - SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFileExtension", ext) - SettingsData.setBuiltInPluginSetting("dankNotepadModule", "sourceContent", content) - SettingsData.setBuiltInPluginSetting("dankNotepadModule", "updatedAt", Date.now()) - } - - function hideSearch() { - searchVisible = false - searchQuery = "" - searchMatches = [] - matchCount = 0 - currentMatchIndex = -1 - textArea.select(0, 0) - textArea.forceActiveFocus() - } - - function copyPlainTextToClipboard() { - if (!inlinePreviewVisible || !textArea.text) return - - const content = textArea.text - if (content.length > 0) { - const proc = Qt.createQmlObject(` - import QtQuick - import Quickshell.Io - Process { - property string content: "" - command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"] - environment: { "CONTENT": content } - running: false - }`, - root, - "copyProc" - ) - proc.content = content - proc.running = true - proc.exited.connect(() => { - ToastService.showInfo(I18n.tr("Copied to clipboard")) - proc.destroy() - }) - } - } - - function copyHtmlToClipboard() { - if (!inlinePreviewVisible || !pluginHighlightedHtml) return - - if (pluginHighlightedHtml.length > 0) { - const proc = Qt.createQmlObject(` - import QtQuick - import Quickshell.Io - Process { - property string content: "" - command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"] - environment: { "CONTENT": content } - running: false - }`, - root, - "copyProcHtml" - ) - proc.content = pluginHighlightedHtml - proc.running = true - proc.exited.connect(() => { - ToastService.showInfo(I18n.tr("HTML copied to clipboard")) - proc.destroy() - }) - } - } - - spacing: Theme.spacingM - - StyledRect { - id: searchBar - width: parent.width - height: 48 - visible: searchVisible - opacity: searchVisible ? 1 : 0 - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: searchField.activeFocus ? Theme.primary : Theme.outlineMedium - border.width: searchField.activeFocus ? 2 : 1 - radius: Theme.cornerRadius - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - // Search icon - DankIcon { - Layout.alignment: Qt.AlignVCenter - name: "search" - size: Theme.iconSize - 2 - color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText - } - - // Search input field - TextInput { - id: searchField - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - height: 32 - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - verticalAlignment: TextInput.AlignVCenter - selectByMouse: true - clip: true - - Component.onCompleted: { - text = root.searchQuery - } - - Connections { - target: root - function onSearchQueryChanged() { - if (searchField.text !== root.searchQuery) { - searchField.text = root.searchQuery - } - } - } - - onTextChanged: { - if (root.searchQuery !== text) { - root.searchQuery = text - root.performSearch() - } - } - Keys.onEscapePressed: event => { - root.hideSearch() - event.accepted = true - } - Keys.onReturnPressed: event => { - if (event.modifiers & Qt.ShiftModifier) { - root.findPrevious() - } else { - root.findNext() - } - event.accepted = true - } - Keys.onEnterPressed: event => { - if (event.modifiers & Qt.ShiftModifier) { - root.findPrevious() - } else { - root.findNext() - } - event.accepted = true - } - } - - // Placeholder text - StyledText { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - text: I18n.tr("Find in note...") - font: searchField.font - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - visible: searchField.text.length === 0 && !searchField.activeFocus - Layout.leftMargin: -(searchField.width - 20) // Position over the input field - } - - // Match count display - StyledText { - Layout.alignment: Qt.AlignVCenter - text: matchCount > 0 ? "%1/%2".arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? I18n.tr("No matches") : "" - font.pixelSize: Theme.fontSizeSmall - color: matchCount > 0 ? Theme.primary : Theme.surfaceTextMedium - visible: searchQuery.length > 0 - Layout.rightMargin: Theme.spacingS - } - - // Navigation buttons - DankActionButton { - id: prevButton - Layout.alignment: Qt.AlignVCenter - iconName: "keyboard_arrow_up" - iconSize: Theme.iconSize - iconColor: matchCount > 0 ? Theme.surfaceText : Theme.surfaceTextAlpha - enabled: matchCount > 0 - onClicked: root.findPrevious() - } - - DankActionButton { - id: nextButton - Layout.alignment: Qt.AlignVCenter - iconName: "keyboard_arrow_down" - iconSize: Theme.iconSize - iconColor: matchCount > 0 ? Theme.surfaceText : Theme.surfaceTextAlpha - enabled: matchCount > 0 - onClicked: root.findNext() - } - - DankActionButton { - id: closeSearchButton - Layout.alignment: Qt.AlignVCenter - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.surfaceText - onClicked: root.hideSearch() - } - } - } - - StyledRect { - width: parent.width - height: parent.height - bottomControls.height - Theme.spacingM - (searchVisible ? searchBar.height + Theme.spacingM : 0) - color: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, Theme.notepadTransparency) - border.color: Theme.outlineMedium - border.width: 1 - radius: Theme.cornerRadius - - RowLayout { - id: editorPreviewRow - anchors.fill: parent - anchors.margins: 1 - spacing: Theme.spacingM - - Item { - id: editorPane - visible: !inlinePreviewVisible || previewMode === "split" - Layout.fillHeight: true - Layout.fillWidth: !inlinePreviewVisible || previewMode === "split" - Layout.preferredWidth: inlinePreviewVisible ? parent.width * 0.55 : parent.width - clip: true - - DankFlickable { - id: flickable - anchors.fill: parent - clip: true - contentWidth: width - 11 - - Rectangle { - id: lineNumberArea - anchors.left: parent.left - anchors.top: parent.top - width: SettingsData.notepadShowLineNumbers ? Math.max(30, 32 + Theme.spacingXS) : 0 - height: textArea.contentHeight + textArea.topPadding + textArea.bottomPadding - color: "transparent" - visible: SettingsData.notepadShowLineNumbers - - ListView { - id: lineNumberList - anchors.top: parent.top - anchors.topMargin: textArea.topPadding - anchors.right: parent.right - anchors.rightMargin: 2 - width: 32 - height: textArea.contentHeight - model: SettingsData.notepadShowLineNumbers ? root.lineModel : [] - interactive: false - spacing: 0 - - delegate: Item { - id: lineDelegate - required property int index - required property string modelData - width: 32 - height: measuringText.contentHeight - - Text { - id: measuringText - width: textArea.width - textArea.leftPadding - textArea.rightPadding - text: modelData || " " - font: textArea.font - wrapMode: Text.Wrap - visible: false - } - - StyledText { - anchors.right: parent.right - anchors.rightMargin: 4 - anchors.top: parent.top - text: index + 1 - font.family: textArea.font.family - font.pixelSize: textArea.font.pixelSize - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - horizontalAlignment: Text.AlignRight - } - } - } - } - - TextArea.flickable: TextArea { - id: textArea - placeholderText: "" - placeholderTextColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - font.family: SettingsData.notepadUseMonospace ? SettingsData.monoFontFamily : (SettingsData.notepadFontFamily || SettingsData.fontFamily) - font.pixelSize: SettingsData.notepadFontSize * SettingsData.fontScale - font.letterSpacing: 0 - color: Theme.surfaceText - selectedTextColor: Theme.background - selectionColor: Theme.primary - selectByMouse: true - selectByKeyboard: true - wrapMode: TextArea.Wrap - focus: true - activeFocusOnTab: true - textFormat: TextEdit.PlainText - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase - persistentSelection: true - tabStopDistance: 40 - leftPadding: (SettingsData.notepadShowLineNumbers ? lineNumberArea.width + Theme.spacingXS : Theme.spacingM) - topPadding: Theme.spacingM - rightPadding: Theme.spacingM - bottomPadding: Theme.spacingM - cursorDelegate: Rectangle { - width: 1.5 - radius: 1 - color: Theme.surfaceText - x: textArea.cursorRectangle.x - y: textArea.cursorRectangle.y - height: textArea.cursorRectangle.height - opacity: 1.0 - - SequentialAnimation on opacity { - running: textArea.activeFocus - loops: Animation.Infinite - PropertyAnimation { from: 1.0; to: 0.0; duration: 650; easing.type: Easing.InOutQuad } - PropertyAnimation { from: 0.0; to: 1.0; duration: 650; easing.type: Easing.InOutQuad } - } - } - - Component.onCompleted: { - loadCurrentTabContent() - setTextDocumentLineHeight() - root.updateLineModel() - Qt.callLater(() => { - textArea.forceActiveFocus() - }) - } - - Connections { - target: NotepadStorageService - function onCurrentTabIndexChanged() { - loadCurrentTabContent() - Qt.callLater(() => { - textArea.forceActiveFocus() - }) - } - function onTabsChanged() { - if (NotepadStorageService.tabs.length > 0 && !contentLoaded) { - loadCurrentTabContent() - } - } - } - - Connections { - target: SettingsData - function onNotepadShowLineNumbersChanged() { - root.updateLineModel() - } - } - - onTextChanged: { - if (contentLoaded && text !== lastSavedContent) { - autoSaveTimer.restart() - } - root.contentChanged() - root.updateLineModel() - pluginSyncTimer.restart() - } - - Keys.onEscapePressed: (event) => { - root.escapePressed() - event.accepted = true - } - - Keys.onPressed: (event) => { - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_S: - event.accepted = true - root.saveRequested() - break - case Qt.Key_O: - event.accepted = true - root.openRequested() - break - case Qt.Key_N: - event.accepted = true - root.newRequested() - break - case Qt.Key_A: - event.accepted = true - textArea.selectAll() - break - case Qt.Key_F: - event.accepted = true - root.showSearch() - break - case Qt.Key_P: - if (PluginService.isPluginLoaded("dankNotepadModule")) { - event.accepted = true - root.previewRequested() - } - break - } - } - } - - background: Rectangle { - color: "transparent" - } - } - - StyledText { - id: placeholderOverlay - text: I18n.tr("Start typing your notes here...") - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - font.family: textArea.font.family - font.pixelSize: textArea.font.pixelSize - visible: textArea.text.length === 0 - anchors.left: textArea.left - anchors.top: textArea.top - anchors.leftMargin: textArea.leftPadding - anchors.topMargin: textArea.topPadding - z: textArea.z + 1 - } - } - } - - Rectangle { - id: previewDivider - visible: inlinePreviewVisible && previewMode === "split" - Layout.fillHeight: true - Layout.preferredWidth: 1 - color: Theme.outlineMedium - } - - Item { - id: previewPane - visible: inlinePreviewVisible - Layout.fillHeight: true - Layout.fillWidth: previewMode === "full" - Layout.preferredWidth: previewMode === "full" ? parent.width : parent.width * 0.45 - clip: true - - // Preview header with copy buttons - Rectangle { - id: previewHeader - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: 36 - color: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, Theme.notepadTransparency) - z: 2 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - // Copy plain text button - DankActionButton { - iconName: "content_copy" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceTextMedium - onClicked: copyPlainTextToClipboard() - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Copy Text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - - Rectangle { - width: 1 - height: 20 - color: Theme.outlineVariant - anchors.verticalCenter: parent.verticalCenter - } - - // Copy HTML button - DankActionButton { - iconName: "code" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceTextMedium - onClicked: copyHtmlToClipboard() - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Copy HTML") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - DankFlickable { - id: previewFlickable - anchors.top: previewHeader.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.topMargin: Theme.spacingS - clip: true - contentWidth: width - 11 - contentHeight: previewText.paintedHeight + Theme.spacingM * 2 - - Text { - id: previewText - width: parent.width - Theme.spacingM - padding: Theme.spacingM - wrapMode: Text.WordWrap - textFormat: Text.RichText - text: inlinePreviewVisible ? renderPreviewHtml() : "" - color: Theme.surfaceText - font.family: SettingsData.notepadFontFamily || SettingsData.fontFamily - font.pixelSize: Theme.fontSizeMedium - linkColor: Theme.primary - - onLinkActivated: url => Qt.openUrlExternally(url) - } - } - } - } - } - - Column { - id: bottomControls - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: 32 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - Row { - spacing: Theme.spacingS - DankActionButton { - iconName: "save" - iconSize: Theme.iconSize - 2 - iconColor: Theme.primary - enabled: currentTab && (hasUnsavedChanges() || textArea.text.length > 0) - onClicked: root.saveRequested() - } - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Row { - spacing: Theme.spacingS - DankActionButton { - iconName: "folder_open" - iconSize: Theme.iconSize - 2 - iconColor: Theme.secondary - onClicked: root.openRequested() - } - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Open") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Row { - spacing: Theme.spacingS - DankActionButton { - iconName: "note_add" - iconSize: Theme.iconSize - 2 - iconColor: Theme.surfaceText - onClicked: root.newRequested() - } - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("New") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Row { - spacing: Theme.spacingS - visible: PluginService.isPluginLoaded("dankNotepadModule") - DankActionButton { - iconName: inlinePreviewVisible ? "visibility" : "visibility_off" - iconSize: Theme.iconSize - 2 - iconColor: Theme.surfaceText - enabled: textArea.text.length > 0 - onClicked: root.previewRequested() - } - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Preview") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - iconSize: Theme.iconSize - 2 - iconColor: Theme.surfaceText - onClicked: root.settingsRequested() - } - } - - Row { - width: parent.width - spacing: Theme.spacingL - - StyledText { - text: { - const len = textArea.text.length; - if (len === 0) return I18n.tr("Empty"); - return len === 1 - ? I18n.tr("%1 character").arg(len) - : I18n.tr("%1 characters").arg(len); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - - StyledText { - text: textArea.lineCount === 1 - ? I18n.tr("Line: %1").arg(textArea.lineCount) - : I18n.tr("Lines: %1").arg(textArea.lineCount) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - visible: textArea.text.length > 0 - opacity: 1.0 - } - - StyledText { - text: { - if (autoSaveTimer.running) { - return I18n.tr("Auto-saving...") - } - - if (hasUnsavedChanges()) { - if (currentTab && currentTab.isTemporary) { - return I18n.tr("Unsaved note...") - } else { - return I18n.tr("Unsaved changes") - } - } else { - return I18n.tr("Saved") - } - } - font.pixelSize: Theme.fontSizeSmall - color: { - if (autoSaveTimer.running) { - return Theme.primary - } - - if (hasUnsavedChanges()) { - return Theme.warning - } else { - return Theme.success - } - } - opacity: textArea.text.length > 0 ? 1.0 : 0.0 - } - } - } - - Timer { - id: autoSaveTimer - interval: 2000 - repeat: false - onTriggered: { - autoSaveToSession() - } - } - - Timer { - id: pluginSyncTimer - interval: 350 - repeat: false - onTriggered: syncContentToPlugin() - } - - Connections { - target: SettingsData - function onBuiltInPluginSettingsChanged() { - if (PluginService.isPluginLoaded("dankNotepadModule")) { - pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "") - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml deleted file mode 100644 index 5e033e5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml +++ /dev/null @@ -1,277 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - required property var historyItem - property bool isSelected: false - property bool keyboardNavigationActive: false - property bool descriptionExpanded: NotificationService.expandedMessages[historyItem?.id ? (historyItem.id + "_hist") : ""] || false - property bool __initialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (root) - root.__initialized = true; - }); - } - - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real iconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real collapsedContentHeight: iconSize + cardPadding - readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight - - width: parent ? parent.width : 400 - height: baseCardHeight + contentItem.extraHeight - radius: Theme.cornerRadius - clip: false - readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: root.radius - targetColor: root.color - borderColor: root.border.color - borderWidth: root.border.width - shadowEnabled: root.shadowsAllowed - } - - color: { - if (isSelected && keyboardNavigationActive) - return Theme.primaryPressed; - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (isSelected && keyboardNavigationActive) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5); - if (historyItem.urgency === 2) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05); - } - border.width: { - if (isSelected && keyboardNavigationActive) - return 1.5; - if (historyItem.urgency === 2) - return 2; - return 0; - } - - Behavior on border.color { - enabled: root.__initialized - ColorAnimation { - duration: root.__initialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - visible: historyItem.urgency === 2 - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: Theme.primary - } - GradientStop { - position: 0.02 - color: Theme.primary - } - GradientStop { - position: 0.021 - color: "transparent" - } - } - } - - Item { - id: contentItem - - readonly property real expandedTextHeight: descriptionText.contentHeight - readonly property real twoLineHeight: descriptionText.font.pixelSize * 1.2 * 2 - readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > twoLineHeight + 2) ? (expandedTextHeight - twoLineHeight) : 0 - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - height: collapsedContentHeight + extraHeight - - DankCircularImage { - id: iconContainer - readonly property string rawImage: historyItem.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: iconSize - height: iconSize - anchors.left: parent.left - anchors.top: parent.top - - imageSource: { - if (hasNotificationImage) - return historyItem.image; - if (imageHasSpecialPrefix) - return ""; - const appIcon = historyItem.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - hasImage: hasNotificationImage - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return historyItem.appIcon || iconFromImage || ""; - } - fallbackText: { - const appName = historyItem.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - - Rectangle { - anchors.fill: parent - anchors.margins: -2 - radius: width / 2 - color: "transparent" - border.color: root.color - border.width: 5 - visible: parent.hasImage - antialiasing: true - } - } - - Rectangle { - anchors.left: iconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: contentSpacing - color: "transparent" - - Column { - width: parent.width - anchors.top: parent.top - spacing: Theme.notificationContentSpacing - - Row { - width: parent.width - spacing: Theme.spacingXS - readonly property real reservedTrailingWidth: historySeparator.implicitWidth + Math.max(historyTimeText.implicitWidth, 72) + spacing - - StyledText { - id: historyTitleText - width: Math.min(implicitWidth, Math.max(0, parent.width - parent.reservedTrailingWidth)) - text: { - let title = historyItem.summary || ""; - const appName = historyItem.appName || ""; - const prefix = appName + " • "; - if (appName && title.toLowerCase().startsWith(prefix.toLowerCase())) { - title = title.substring(prefix.length); - } - return title; - } - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - StyledText { - id: historySeparator - text: (historyTitleText.text.length > 0 && historyTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - StyledText { - id: historyTimeText - text: NotificationService.formatHistoryTime(historyItem.timestamp) - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - visible: text.length > 0 - } - } - - StyledText { - id: descriptionText - property bool hasMoreText: truncated - - text: historyItem.htmlBody || historyItem.body || "" - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: descriptionExpanded ? Text.ElideNone : Text.ElideRight - maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2) - wrapMode: Text.WordWrap - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) { - const messageId = historyItem?.id ? (historyItem.id + "_hist") : ""; - NotificationService.toggleMessageExpansion(messageId); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - onReleased: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.rightMargin: Theme.spacingL - iconName: "close" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: NotificationService.removeFromHistory(historyItem.id) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml deleted file mode 100644 index 69fea41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml +++ /dev/null @@ -1,387 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string selectedFilterKey: "all" - property var keyboardController: null - property bool keyboardActive: false - property int selectedIndex: -1 - property bool showKeyboardHints: false - - function getStartOfDay(date) { - const d = new Date(date); - d.setHours(0, 0, 0, 0); - return d; - } - - function getFilterRange(key) { - const now = new Date(); - const startOfToday = getStartOfDay(now); - const startOfYesterday = new Date(startOfToday.getTime() - 86400000); - - switch (key) { - case "all": - return { - start: null, - end: null - }; - case "1h": - return { - start: new Date(now.getTime() - 3600000), - end: null - }; - case "today": - return { - start: startOfToday, - end: null - }; - case "yesterday": - return { - start: startOfYesterday, - end: startOfToday - }; - case "older": - return { - start: null, - end: getOlderCutoff() - }; - case "7d": - return { - start: new Date(now.getTime() - 7 * 86400000), - end: null - }; - case "30d": - return { - start: new Date(now.getTime() - 30 * 86400000), - end: null - }; - default: - return { - start: null, - end: null - }; - } - } - - function countForFilter(key) { - const range = getFilterRange(key); - if (!range.start && !range.end) - return NotificationService.historyList.length; - return NotificationService.historyList.filter(n => { - const ts = n.timestamp; - if (range.start && ts < range.start.getTime()) - return false; - if (range.end && ts >= range.end.getTime()) - return false; - return true; - }).length; - } - - readonly property var allFilters: [ - { - label: I18n.tr("All", "notification history filter"), - key: "all", - maxDays: 0 - }, - { - label: I18n.tr("Last hour", "notification history filter"), - key: "1h", - maxDays: 1 - }, - { - label: I18n.tr("Today", "notification history filter"), - key: "today", - maxDays: 1 - }, - { - label: I18n.tr("Yesterday", "notification history filter"), - key: "yesterday", - maxDays: 2 - }, - { - label: I18n.tr("7 days", "notification history filter"), - key: "7d", - maxDays: 7 - }, - { - label: I18n.tr("30 days", "notification history filter"), - key: "30d", - maxDays: 30 - }, - { - label: I18n.tr("Older", "notification history filter for content older than other filters"), - key: "older", - maxDays: 0 - } - ] - - function filterRelevantForRetention(filter) { - const retention = SettingsData.notificationHistoryMaxAgeDays; - if (filter.key === "older") { - if (retention === 0) - return true; - return retention > 2 && retention < 7 || retention > 30; - } - if (retention === 0) - return true; - if (filter.maxDays === 0) - return true; - return filter.maxDays <= retention; - } - - function getOlderCutoff() { - const retention = SettingsData.notificationHistoryMaxAgeDays; - const now = new Date(); - if (retention === 0 || retention > 30) - return new Date(now.getTime() - 30 * 86400000); - if (retention >= 7) - return new Date(now.getTime() - 7 * 86400000); - const startOfToday = getStartOfDay(now); - return new Date(startOfToday.getTime() - 86400000); - } - - readonly property var visibleFilters: { - const result = []; - const retention = SettingsData.notificationHistoryMaxAgeDays; - for (let i = 0; i < allFilters.length; i++) { - const f = allFilters[i]; - if (!filterRelevantForRetention(f)) - continue; - const count = countForFilter(f.key); - if (f.key === "all" || count > 0) { - result.push({ - label: f.label, - key: f.key, - count: count - }); - } - } - return result; - } - - onVisibleFiltersChanged: { - let found = false; - for (let i = 0; i < visibleFilters.length; i++) { - if (visibleFilters[i].key === selectedFilterKey) { - found = true; - break; - } - } - if (!found) - selectedFilterKey = "all"; - } - - function getFilteredHistory() { - const range = getFilterRange(selectedFilterKey); - if (!range.start && !range.end) - return NotificationService.historyList; - return NotificationService.historyList.filter(n => { - const ts = n.timestamp; - if (range.start && ts < range.start.getTime()) - return false; - if (range.end && ts >= range.end.getTime()) - return false; - return true; - }); - } - - function getChipIndex() { - for (let i = 0; i < visibleFilters.length; i++) { - if (visibleFilters[i].key === selectedFilterKey) - return i; - } - return 0; - } - - function enableAutoScroll() { - } - - function removeWithScrollPreserve(itemId) { - historyListView.savedY = historyListView.contentY; - NotificationService.removeFromHistory(itemId); - Qt.callLater(() => { - historyListView.forceLayout(); - }); - } - - Column { - anchors.fill: parent - spacing: Theme.spacingS - - DankFilterChips { - id: filterChips - width: parent.width - currentIndex: root.getChipIndex() - showCounts: true - model: root.visibleFilters - onSelectionChanged: index => { - if (index >= 0 && index < root.visibleFilters.length) { - root.selectedFilterKey = root.visibleFilters[index].key; - } - } - } - - DankListView { - id: historyListView - width: parent.width - height: parent.height - filterChips.height - Theme.spacingS - clip: true - spacing: Theme.spacingS - readonly property real horizontalShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - readonly property real verticalShadowGutter: Theme.snap(Math.max(Theme.spacingS, 8), 1) - readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - topMargin: verticalShadowGutter - bottomMargin: verticalShadowGutter - - model: ScriptModel { - id: historyModel - values: root.getFilteredHistory() - objectProp: "id" - } - - NotificationEmptyState { - visible: historyListView.count === 0 - y: Theme.spacingL - anchors.horizontalCenter: parent.horizontalCenter - } - - delegate: Item { - id: delegateRoot - required property var modelData - required property int index - - property real swipeOffset: 0 - property bool isDismissing: false - readonly property real dismissThreshold: width * 0.35 - property bool __delegateInitialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (delegateRoot) - delegateRoot.__delegateInitialized = true; - }); - } - - width: ListView.view.width - height: historyCard.height + historyListView.delegateShadowGutter - clip: false - - HistoryNotificationCard { - id: historyCard - width: Math.max(0, parent.width - (historyListView.horizontalShadowGutter * 2)) - y: historyListView.delegateShadowGutter / 2 - x: historyListView.horizontalShadowGutter + delegateRoot.swipeOffset - historyItem: modelData - isSelected: root.keyboardActive && root.selectedIndex === index - keyboardNavigationActive: root.keyboardActive - opacity: 1 - Math.abs(delegateRoot.swipeOffset) / (delegateRoot.width * 0.5) - - Behavior on x { - enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized - NumberAnimation { - duration: Theme.notificationExitDuration - easing.type: Theme.standardEasing - } - } - - Behavior on opacity { - enabled: delegateRoot.__delegateInitialized - NumberAnimation { - duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0 - } - } - } - - DragHandler { - id: swipeDragHandler - target: null - yAxis.enabled: false - xAxis.enabled: true - - onActiveChanged: { - if (active || delegateRoot.isDismissing) - return; - if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) { - delegateRoot.isDismissing = true; - root.removeWithScrollPreserve(delegateRoot.modelData?.id || ""); - } else { - delegateRoot.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (delegateRoot.isDismissing) - return; - delegateRoot.swipeOffset = translation.x; - } - } - } - } - } - - function selectNext() { - if (historyModel.values.length === 0) - return; - keyboardActive = true; - selectedIndex = Math.min(selectedIndex + 1, historyModel.values.length - 1); - historyListView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function selectPrevious() { - if (historyModel.values.length === 0) - return; - if (selectedIndex <= 0) { - keyboardActive = false; - selectedIndex = -1; - return; - } - selectedIndex = Math.max(selectedIndex - 1, 0); - historyListView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function clearSelected() { - if (selectedIndex < 0 || selectedIndex >= historyModel.values.length) - return; - const item = historyModel.values[selectedIndex]; - NotificationService.removeFromHistory(item.id); - if (historyModel.values.length === 0) { - keyboardActive = false; - selectedIndex = -1; - } else { - selectedIndex = Math.min(selectedIndex, historyModel.values.length - 1); - } - } - - function handleKey(event) { - if (event.key === Qt.Key_Down || event.key === 16777237) { - if (!keyboardActive) { - keyboardActive = true; - selectedIndex = 0; - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_Up || event.key === 16777235) { - if (keyboardActive) { - selectPrevious(); - } - event.accepted = true; - } else if (keyboardActive && (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace)) { - clearSelected(); - event.accepted = true; - } else if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) && (event.modifiers & Qt.ShiftModifier)) { - NotificationService.clearHistory(); - keyboardActive = false; - selectedIndex = -1; - event.accepted = true; - } else if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints; - event.accepted = true; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml deleted file mode 100644 index 855163d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml +++ /dev/null @@ -1,311 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankListView { - id: listView - - property var keyboardController: null - property bool keyboardActive: false - property bool autoScrollDisabled: false - property bool isAnimatingExpansion: false - property alias listContentHeight: listView.contentHeight - property real stableContentHeight: 0 - property bool cardAnimateExpansion: true - property bool listInitialized: false - property int swipingCardIndex: -1 - property real swipingCardOffset: 0 - property real __pendingStableHeight: 0 - property real __heightUpdateThreshold: 20 - readonly property real shadowBlurPx: Theme.elevationEnabled ? ((Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined) ? Theme.elevationLevel1.blurPx : 4) : 0 - readonly property real shadowHorizontalGutter: Theme.snap(Math.max(Theme.spacingS, Math.min(32, shadowBlurPx * 1.5 + 6)), 1) - readonly property real shadowVerticalGutter: Theme.snap(Math.max(Theme.spacingXS, 6), 1) - readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - - Component.onCompleted: { - Qt.callLater(() => { - if (listView) { - listView.listInitialized = true; - listView.stableContentHeight = listView.contentHeight; - } - }); - } - - Timer { - id: heightUpdateDebounce - interval: Theme.mediumDuration + 20 - repeat: false - onTriggered: { - if (!listView.isAnimatingExpansion && Math.abs(listView.__pendingStableHeight - listView.stableContentHeight) > listView.__heightUpdateThreshold) { - listView.stableContentHeight = listView.__pendingStableHeight; - } - } - } - - onContentHeightChanged: { - if (!isAnimatingExpansion) { - __pendingStableHeight = contentHeight; - if (Math.abs(contentHeight - stableContentHeight) > __heightUpdateThreshold) { - heightUpdateDebounce.restart(); - } else { - stableContentHeight = contentHeight; - } - } - } - - onIsAnimatingExpansionChanged: { - if (isAnimatingExpansion) { - heightUpdateDebounce.stop(); - let delta = 0; - for (let i = 0; i < count; i++) { - const item = itemAtIndex(i); - if (item && item.children[0] && item.children[0].isAnimating) { - const targetDelegateHeight = item.children[0].targetHeight + listView.delegateShadowGutter; - delta += targetDelegateHeight - item.height; - } - } - const targetHeight = contentHeight + delta; - // During expansion, always update immediately without threshold check - stableContentHeight = targetHeight; - } else { - __pendingStableHeight = contentHeight; - heightUpdateDebounce.stop(); - stableContentHeight = __pendingStableHeight; - } - } - - clip: true - model: NotificationService.groupedNotifications - spacing: Theme.spacingL - topMargin: shadowVerticalGutter - bottomMargin: shadowVerticalGutter - - onIsUserScrollingChanged: { - if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) { - autoScrollDisabled = true; - } - } - - function enableAutoScroll() { - autoScrollDisabled = false; - } - - Timer { - id: positionPreservationTimer - interval: 200 - running: keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion - repeat: true - onTriggered: { - if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion) { - keyboardController.ensureVisible(); - } - } - } - - Timer { - id: expansionEnsureVisibleTimer - interval: Theme.mediumDuration + 50 - repeat: false - onTriggered: { - if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) { - keyboardController.ensureVisible(); - } - } - } - - NotificationEmptyState { - visible: listView.count === 0 - y: 20 - anchors.horizontalCenter: parent.horizontalCenter - } - - onModelChanged: { - if (!keyboardController || !keyboardController.keyboardNavigationActive) { - return; - } - keyboardController.rebuildFlatNavigation(); - Qt.callLater(() => { - if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) { - keyboardController.ensureVisible(); - } - }); - } - - delegate: Item { - id: delegateRoot - required property var modelData - required property int index - - readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false) - property real swipeOffset: 0 - property bool isDismissing: false - readonly property real dismissThreshold: width * 0.35 - property bool __delegateInitialized: false - - readonly property bool isAdjacentToSwipe: listView.count >= 2 && listView.swipingCardIndex !== -1 && (index === listView.swipingCardIndex - 1 || index === listView.swipingCardIndex + 1) - readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? listView.swipingCardOffset * 0.10 : 0 - readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(listView.swipingCardOffset) / width * 0.02 : 1.0 - readonly property real swipeFadeStartOffset: width * 0.75 - readonly property real swipeFadeDistance: Math.max(1, width - swipeFadeStartOffset) - - Component.onCompleted: { - Qt.callLater(() => { - if (delegateRoot) - delegateRoot.__delegateInitialized = true; - }); - } - - width: ListView.view.width - height: notificationCard.height + listView.delegateShadowGutter - clip: false - - NotificationCard { - id: notificationCard - width: Math.max(0, parent.width - (listView.shadowHorizontalGutter * 2)) - y: listView.delegateShadowGutter / 2 - x: listView.shadowHorizontalGutter + delegateRoot.swipeOffset + delegateRoot.adjacentSwipeInfluence - listLevelAdjacentScaleInfluence: delegateRoot.adjacentScaleInfluence - listLevelScaleAnimationsEnabled: listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe - notificationGroup: modelData - keyboardNavigationActive: listView.keyboardActive - animateExpansion: listView.cardAnimateExpansion && listView.listInitialized - opacity: { - const swipeAmount = Math.abs(delegateRoot.swipeOffset); - if (swipeAmount <= delegateRoot.swipeFadeStartOffset) - return 1; - const fadeProgress = (swipeAmount - delegateRoot.swipeFadeStartOffset) / delegateRoot.swipeFadeDistance; - return Math.max(0, 1 - fadeProgress); - } - onIsAnimatingChanged: { - if (isAnimating) { - listView.isAnimatingExpansion = true; - } else { - Qt.callLater(() => { - if (!notificationCard || !listView) - return; - let anyAnimating = false; - for (let i = 0; i < listView.count; i++) { - const item = listView.itemAtIndex(i); - if (item && item.children[0] && item.children[0].isAnimating) { - anyAnimating = true; - break; - } - } - listView.isAnimatingExpansion = anyAnimating; - }); - } - } - - isGroupSelected: { - if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) - return false; - keyboardController.selectionVersion; - const selection = keyboardController.getCurrentSelection(); - return selection.type === "group" && selection.groupIndex === index; - } - - selectedNotificationIndex: { - if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) - return -1; - keyboardController.selectionVersion; - const selection = keyboardController.getCurrentSelection(); - return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1; - } - - Behavior on x { - enabled: !swipeDragHandler.active && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on opacity { - enabled: listView.listInitialized - NumberAnimation { - duration: listView.listInitialized ? Theme.shortDuration : 0 - } - } - } - - DragHandler { - id: swipeDragHandler - target: null - yAxis.enabled: false - xAxis.enabled: true - - onActiveChanged: { - if (active) { - listView.swipingCardIndex = index; - return; - } - listView.swipingCardIndex = -1; - listView.swipingCardOffset = 0; - if (delegateRoot.isDismissing) - return; - if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) { - delegateRoot.isDismissing = true; - swipeDismissAnim.to = delegateRoot.swipeOffset > 0 ? delegateRoot.width : -delegateRoot.width; - swipeDismissAnim.start(); - } else { - delegateRoot.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (delegateRoot.isDismissing) - return; - delegateRoot.swipeOffset = translation.x; - listView.swipingCardOffset = translation.x; - } - } - - NumberAnimation { - id: swipeDismissAnim - target: delegateRoot - property: "swipeOffset" - to: 0 - duration: Theme.notificationExitDuration - easing.type: Easing.OutCubic - onStopped: NotificationService.dismissGroup(delegateRoot.modelData?.key || "") - } - } - - Connections { - target: NotificationService - - function onGroupedNotificationsChanged() { - if (!keyboardController) { - return; - } - - if (keyboardController.isTogglingGroup) { - keyboardController.rebuildFlatNavigation(); - return; - } - - keyboardController.rebuildFlatNavigation(); - - if (keyboardController.keyboardNavigationActive) { - Qt.callLater(() => { - if (!autoScrollDisabled) { - keyboardController.ensureVisible(); - } - }); - } - } - - function onExpandedGroupsChanged() { - if (!keyboardController || !keyboardController.keyboardNavigationActive) - return; - expansionEnsureVisibleTimer.restart(); - } - - function onExpandedMessagesChanged() { - if (!keyboardController || !keyboardController.keyboardNavigationActive) - return; - expansionEnsureVisibleTimer.restart(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml deleted file mode 100644 index 7e404df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml +++ /dev/null @@ -1,1073 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Effects -import Quickshell -import Quickshell.Services.Notifications -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var notificationGroup - property bool expanded: (NotificationService.expandedGroups[notificationGroup && notificationGroup.key] || false) - property bool descriptionExpanded: (NotificationService.expandedMessages[(notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""] || false) - property bool userInitiatedExpansion: false - property bool isAnimating: false - property bool animateExpansion: true - - property bool isGroupSelected: false - property int selectedNotificationIndex: -1 - property bool keyboardNavigationActive: false - property int swipingNotificationIndex: -1 - property real swipingNotificationOffset: 0 - property real listLevelAdjacentScaleInfluence: 1.0 - property bool listLevelScaleAnimationsEnabled: true - - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real iconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real collapsedDismissOffset: 5 - readonly property real badgeSize: compactMode ? 16 : 18 - readonly property real actionButtonHeight: compactMode ? 20 : 24 - readonly property real collapsedContentHeight: Math.max(iconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) - readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing - - width: parent ? parent.width : 400 - height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight) - readonly property real targetHeight: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight) - radius: Theme.cornerRadius - scale: (cardHoverHandler.hovered ? 1.004 : 1.0) * listLevelAdjacentScaleInfluence - readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - readonly property var shadowElevation: Theme.elevationLevel1 - readonly property real baseShadowBlurPx: (shadowElevation && shadowElevation.blurPx !== undefined) ? shadowElevation.blurPx : 4 - readonly property real hoverShadowBlurBoost: cardHoverHandler.hovered ? Math.min(2, baseShadowBlurPx * 0.25) : 0 - property real shadowBlurPx: shadowsAllowed ? (baseShadowBlurPx + hoverShadowBlurBoost) : 0 - property real shadowOffsetXPx: shadowsAllowed ? Theme.elevationOffsetX(shadowElevation) : 0 - property real shadowOffsetYPx: shadowsAllowed ? (Theme.elevationOffsetY(shadowElevation, 1) + (cardHoverHandler.hovered ? 0.35 : 0)) : 0 - property bool __initialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (root) - root.__initialized = true; - }); - } - - Behavior on scale { - enabled: listLevelScaleAnimationsEnabled - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowBlurPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetXPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetYPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.color { - enabled: root.__initialized - ColorAnimation { - duration: root.__initialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - color: { - if (isGroupSelected && keyboardNavigationActive) { - return Theme.primaryPressed; - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return Theme.primaryHoverLight; - } - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (isGroupSelected && keyboardNavigationActive) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5); - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2); - } - if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05); - } - border.width: { - if (isGroupSelected && keyboardNavigationActive) { - return 1.5; - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return 1; - } - if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { - return 2; - } - return 0; - } - clip: false - - HoverHandler { - id: cardHoverHandler - } - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: root.shadowElevation - targetRadius: root.radius - targetColor: root.color - borderColor: root.border.color - borderWidth: root.border.width - shadowBlurPx: root.shadowBlurPx - shadowSpreadPx: 0 - shadowOffsetX: root.shadowOffsetXPx - shadowOffsetY: root.shadowOffsetYPx - shadowColor: root.shadowElevation ? Theme.elevationShadowColor(root.shadowElevation) : "transparent" - shadowEnabled: root.shadowsAllowed - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - visible: notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: Theme.primary - } - GradientStop { - position: 0.02 - color: Theme.primary - } - GradientStop { - position: 0.021 - color: "transparent" - } - } - opacity: 1.0 - } - - Item { - id: collapsedContent - - readonly property real expandedTextHeight: descriptionText.contentHeight - readonly property real collapsedLineCount: compactMode ? 1 : 2 - readonly property real collapsedLineHeight: Theme.fontSizeSmall * 1.2 * collapsedLineCount - readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > collapsedLineHeight + 2) ? (expandedTextHeight - collapsedLineHeight) : 0 - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - height: collapsedContentHeight + extraHeight - visible: !expanded - - DankCircularImage { - id: iconContainer - readonly property string rawImage: notificationGroup?.latestNotification?.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: iconSize - height: iconSize - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: descriptionExpanded ? Math.max(0, Theme.fontSizeSmall * 1.2 + (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) / 2 - iconSize / 2) : Math.max(0, Theme.fontSizeSmall * 1.2 + (textContainer.height - Theme.fontSizeSmall * 1.2) / 2 - iconSize / 2) - - imageSource: { - if (hasNotificationImage) - return notificationGroup.latestNotification.cleanImage; - if (imageHasSpecialPrefix) - return ""; - const appIcon = notificationGroup?.latestNotification?.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - hasImage: hasNotificationImage - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return notificationGroup?.latestNotification?.appIcon || iconFromImage || ""; - } - fallbackText: { - const appName = notificationGroup?.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - - Rectangle { - anchors.fill: parent - anchors.margins: -2 - radius: width / 2 - color: "transparent" - border.color: root.color - border.width: 5 - visible: parent.hasImage - antialiasing: true - } - - Rectangle { - width: badgeSize - height: badgeSize - radius: badgeSize / 2 - color: Theme.primary - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: -2 - anchors.rightMargin: -2 - visible: (notificationGroup?.count || 0) > 1 - - StyledText { - anchors.centerIn: parent - text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString() - color: Theme.primaryText - font.pixelSize: compactMode ? 8 : 9 - font.weight: Font.Bold - } - } - } - - Rectangle { - id: textContainer - - anchors.left: iconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: contentSpacing - color: "transparent" - - Column { - width: parent.width - anchors.top: parent.top - spacing: Theme.notificationContentSpacing - - Row { - id: collapsedHeaderRow - width: parent.width - spacing: Theme.spacingXS - visible: (collapsedHeaderAppNameText.text.length > 0 || collapsedHeaderTimeText.text.length > 0) - - StyledText { - id: collapsedHeaderAppNameText - text: notificationGroup?.appName || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, parent.width - collapsedHeaderSeparator.implicitWidth - collapsedHeaderTimeText.implicitWidth - parent.spacing * 2) - } - - StyledText { - id: collapsedHeaderSeparator - text: (collapsedHeaderAppNameText.text.length > 0 && collapsedHeaderTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - - StyledText { - id: collapsedHeaderTimeText - text: notificationGroup?.latestNotification?.timeStr || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - } - - StyledText { - id: collapsedTitleText - width: parent.width - text: notificationGroup?.latestNotification?.summary || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - id: descriptionText - property string fullText: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.htmlBody) || "" - property bool hasMoreText: truncated - - text: fullText - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: Text.ElideRight - maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2) - wrapMode: Text.WordWrap - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) { - root.userInitiatedExpansion = true; - const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""; - NotificationService.toggleMessageExpansion(messageId); - Qt.callLater(() => { - if (root && !root.isAnimating) - root.userInitiatedExpansion = false; - }); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - onReleased: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - } - } - } - } - } - - Column { - id: expandedContent - objectName: "expandedContent" - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: compactMode ? Theme.spacingXS : Theme.spacingS - visible: expanded - - Item { - width: parent.width - height: compactMode ? 32 : 40 - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: notificationGroup?.appName || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - } - - Rectangle { - width: badgeSize - height: badgeSize - radius: badgeSize / 2 - color: Theme.primary - visible: (notificationGroup?.count || 0) > 1 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - anchors.centerIn: parent - text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString() - color: Theme.primaryText - font.pixelSize: compactMode ? 8 : 9 - font.weight: Font.Bold - } - } - } - } - - Column { - width: parent.width - spacing: compactMode ? Theme.spacingS : Theme.spacingL - - Repeater { - id: notificationRepeater - objectName: "notificationRepeater" - model: notificationGroup?.notifications?.slice(0, 10) || [] - - delegate: Item { - id: expandedDelegateWrapper - required property var modelData - required property int index - readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] || false - readonly property bool isSelected: root.selectedNotificationIndex === index - readonly property bool actionsVisible: true - readonly property real expandedIconSize: compactMode ? Theme.notificationExpandedIconSizeCompact : Theme.notificationExpandedIconSizeNormal - - HoverHandler { - id: expandedDelegateHoverHandler - } - readonly property real expandedItemPadding: compactMode ? Theme.spacingS : Theme.spacingM - readonly property real expandedBaseHeight: expandedItemPadding * 2 + Math.max(expandedIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * 2) + actionButtonHeight + contentSpacing * 2 - property bool __delegateInitialized: false - property real swipeOffset: 0 - property bool isDismissing: false - readonly property real dismissThreshold: width * 0.35 - - Component.onCompleted: { - Qt.callLater(() => { - if (expandedDelegateWrapper) - expandedDelegateWrapper.__delegateInitialized = true; - }); - } - - width: parent.width - height: delegateRect.height - clip: true - - Rectangle { - id: delegateRect - width: parent.width - - readonly property bool isAdjacentToSwipe: root.swipingNotificationIndex !== -1 && (expandedDelegateWrapper.index === root.swipingNotificationIndex - 1 || expandedDelegateWrapper.index === root.swipingNotificationIndex + 1) - readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? root.swipingNotificationOffset * 0.10 : 0 - readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(root.swipingNotificationOffset) / width * 0.02 : 1.0 - - x: expandedDelegateWrapper.swipeOffset + adjacentSwipeInfluence - scale: adjacentScaleInfluence - transformOrigin: Item.Center - - Behavior on x { - enabled: !expandedSwipeHandler.active && !expandedDelegateWrapper.isDismissing - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on scale { - enabled: !expandedSwipeHandler.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - height: { - if (!messageExpanded) - return expandedBaseHeight; - const twoLineHeight = bodyText.font.pixelSize * 1.2 * 2; - if (bodyText.implicitHeight > twoLineHeight + 2) - return expandedBaseHeight + bodyText.implicitHeight - twoLineHeight; - return expandedBaseHeight; - } - radius: Theme.cornerRadius - color: isSelected ? Theme.primaryPressed : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 1 - - Behavior on border.color { - enabled: __delegateInitialized - ColorAnimation { - duration: __delegateInitialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: false - } - - Item { - anchors.fill: parent - anchors.margins: compactMode ? Theme.spacingS : Theme.spacingM - anchors.bottomMargin: contentSpacing - - DankCircularImage { - id: messageIcon - - readonly property string rawImage: modelData?.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: expandedIconSize - height: expandedIconSize - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: Theme.fontSizeSmall * 1.2 + (compactMode ? Theme.spacingXS : Theme.spacingS) - - imageSource: { - if (hasNotificationImage) - return modelData.cleanImage; - if (imageHasSpecialPrefix) - return ""; - const appIcon = modelData?.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return modelData?.appIcon || iconFromImage || ""; - } - - fallbackText: { - const appName = modelData?.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - } - - Item { - anchors.left: messageIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.top: parent.top - anchors.bottom: parent.bottom - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: buttonArea.top - anchors.bottomMargin: contentSpacing - spacing: Theme.notificationContentSpacing - - Row { - id: expandedDelegateHeaderRow - width: parent.width - spacing: Theme.spacingXS - visible: (expandedDelegateHeaderAppNameText.text.length > 0 || expandedDelegateHeaderTimeText.text.length > 0) - - StyledText { - id: expandedDelegateHeaderAppNameText - text: modelData?.appName || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, parent.width - expandedDelegateHeaderSeparator.implicitWidth - expandedDelegateHeaderTimeText.implicitWidth - parent.spacing * 2) - } - - StyledText { - id: expandedDelegateHeaderSeparator - text: (expandedDelegateHeaderAppNameText.text.length > 0 && expandedDelegateHeaderTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - - StyledText { - id: expandedDelegateHeaderTimeText - text: modelData?.timeStr || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - } - - StyledText { - id: expandedDelegateTitleText - width: parent.width - text: modelData?.summary || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - id: bodyText - property bool hasMoreText: truncated - - text: modelData?.htmlBody || "" - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: messageExpanded ? Text.ElideNone : Text.ElideRight - maximumLineCount: messageExpanded ? -1 : 2 - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || messageExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (bodyText.hasMoreText || messageExpanded)) { - root.userInitiatedExpansion = true; - NotificationService.toggleMessageExpansion(modelData?.notification?.id || ""); - Qt.callLater(() => { - if (root && !root.isAnimating) - root.userInitiatedExpansion = false; - }); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) { - mouse.accepted = false; - } - } - onReleased: mouse => { - if (parent.hoveredLink) { - mouse.accepted = false; - } - } - } - } - } - - Item { - id: buttonArea - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: actionButtonHeight + contentSpacing - - Row { - visible: expandedDelegateWrapper.actionsVisible - opacity: visible ? 1 : 0 - anchors.right: parent.right - anchors.bottom: parent.bottom - spacing: contentSpacing - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Repeater { - model: modelData?.actions || [] - - Rectangle { - property bool isHovered: false - - width: Math.max(expandedActionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: expandedActionText - text: { - const baseText = modelData.text || I18n.tr("Open"); - if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0)) - return `${baseText} (${index + 1})`; - return baseText; - } - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - elide: Text.ElideRight - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: { - if (modelData && modelData.invoke) - modelData.invoke(); - } - } - } - } - - Rectangle { - id: expandedDelegateDismissBtn - property bool isHovered: false - - visible: expandedDelegateWrapper.actionsVisible - opacity: visible ? 1 : 0 - width: Math.max(expandedClearText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - StyledText { - id: expandedClearText - text: I18n.tr("Dismiss") - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: NotificationService.dismissNotification(modelData) - } - } - } - } - } - } - } - - DragHandler { - id: expandedSwipeHandler - target: null - xAxis.enabled: true - yAxis.enabled: false - grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType - - onActiveChanged: { - if (active) { - root.swipingNotificationIndex = expandedDelegateWrapper.index; - } else { - root.swipingNotificationIndex = -1; - root.swipingNotificationOffset = 0; - } - if (active || expandedDelegateWrapper.isDismissing) - return; - if (Math.abs(expandedDelegateWrapper.swipeOffset) > expandedDelegateWrapper.dismissThreshold) { - expandedDelegateWrapper.isDismissing = true; - expandedSwipeDismissAnim.start(); - } else { - expandedDelegateWrapper.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (expandedDelegateWrapper.isDismissing) - return; - expandedDelegateWrapper.swipeOffset = translation.x; - root.swipingNotificationOffset = translation.x; - } - } - - NumberAnimation { - id: expandedSwipeDismissAnim - target: expandedDelegateWrapper - property: "swipeOffset" - to: expandedDelegateWrapper.swipeOffset > 0 ? expandedDelegateWrapper.width : -expandedDelegateWrapper.width - duration: Theme.notificationExitDuration - easing.type: Easing.OutCubic - onStopped: NotificationService.dismissNotification(modelData) - } - } - } - } - } - - Row { - visible: !expanded - anchors.right: clearButton.visible ? clearButton.left : parent.right - anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL - anchors.top: collapsedContent.bottom - anchors.topMargin: contentSpacing + collapsedDismissOffset - spacing: contentSpacing - - Repeater { - model: notificationGroup?.latestNotification?.actions || [] - - Rectangle { - property bool isHovered: false - - width: Math.max(collapsedActionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: collapsedActionText - text: { - const baseText = modelData.text || I18n.tr("Open"); - if (keyboardNavigationActive && isGroupSelected) { - return `${baseText} (${index + 1})`; - } - return baseText; - } - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - elide: Text.ElideRight - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: { - if (modelData && modelData.invoke) { - modelData.invoke(); - } - } - } - } - } - } - - Rectangle { - id: clearButton - - property bool isHovered: false - readonly property int actionCount: (notificationGroup?.latestNotification?.actions || []).length - - visible: !expanded && actionCount < 3 - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL - anchors.top: collapsedContent.bottom - anchors.topMargin: contentSpacing + collapsedDismissOffset - width: Math.max(collapsedClearText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: collapsedClearText - text: I18n.tr("Dismiss") - color: clearButton.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: clearButton.isHovered = true - onExited: clearButton.isHovered = false - onClicked: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - MouseArea { - anchors.fill: parent - visible: !expanded && (notificationGroup?.count || 0) > 1 && !descriptionExpanded - cursorShape: Qt.PointingHandCursor - onClicked: { - root.userInitiatedExpansion = true; - NotificationService.toggleGroupExpansion(notificationGroup?.key || ""); - } - z: -1 - } - - Item { - id: fixedControls - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.rightMargin: Theme.spacingL - width: compactMode ? 52 : 60 - height: compactMode ? 24 : 28 - - DankActionButton { - anchors.left: parent.left - anchors.top: parent.top - visible: (notificationGroup?.count || 0) > 1 - iconName: expanded ? "expand_less" : "expand_more" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: { - root.userInitiatedExpansion = true; - NotificationService.toggleGroupExpansion(notificationGroup?.key || ""); - } - } - - DankActionButton { - anchors.right: parent.right - anchors.top: parent.top - iconName: "close" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - Behavior on height { - enabled: root.__initialized && root.userInitiatedExpansion && root.animateExpansion - NumberAnimation { - duration: root.expanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasized - onRunningChanged: { - if (running) { - root.isAnimating = true; - } else { - root.isAnimating = false; - root.userInitiatedExpansion = false; - } - } - } - } - - Menu { - id: notificationCardContextMenu - width: 220 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - id: setNotificationRulesItem - text: I18n.tr("Set notification rules") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationGroup?.appName || ""; - const desktopEntry = notificationGroup?.latestNotification?.desktopEntry || ""; - SettingsData.addNotificationRuleForNotification(appName, desktopEntry); - PopoutService.openSettingsWithTab("notifications"); - } - } - - MenuItem { - id: muteUnmuteItem - readonly property bool isMuted: SettingsData.isAppMuted(notificationGroup?.appName || "", notificationGroup?.latestNotification?.desktopEntry || "") - text: isMuted ? I18n.tr("Unmute popups for %1").arg(notificationGroup?.appName || I18n.tr("this app")) : I18n.tr("Mute popups for %1").arg(notificationGroup?.appName || I18n.tr("this app")) - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationGroup?.appName || ""; - const desktopEntry = notificationGroup?.latestNotification?.desktopEntry || ""; - if (isMuted) { - SettingsData.removeMuteRuleForApp(appName, desktopEntry); - } else { - SettingsData.addMuteRuleForApp(appName, desktopEntry); - NotificationService.dismissGroup(notificationGroup?.key || ""); - } - } - } - - MenuItem { - text: I18n.tr("Dismiss") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - z: -2 - onClicked: mouse => { - if (mouse.button === Qt.RightButton && notificationGroup) { - notificationCardContextMenu.popup(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml deleted file mode 100644 index b7b616b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml +++ /dev/null @@ -1,321 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:notification-center-popout" - fullHeightSurface: true - - property bool notificationHistoryVisible: false - property var triggerScreen: null - property real stablePopupHeight: 400 - property real _lastAlignedContentHeight: -1 - property bool _pendingSizedOpen: false - - function updateStablePopupHeight() { - const item = contentLoader.item; - if (item && !root.shouldBeVisible) { - const notificationList = findChild(item, "notificationList"); - if (notificationList && typeof notificationList.forceLayout === "function") { - notificationList.forceLayout(); - } - } - const target = item ? Theme.px(item.implicitHeight, dpr) : 400; - if (Math.abs(target - _lastAlignedContentHeight) < 0.5) - return; - _lastAlignedContentHeight = target; - stablePopupHeight = target; - } - - NotificationKeyboardController { - id: keyboardController - listView: null - isOpen: root.shouldBeVisible - onClose: () => { - notificationHistoryVisible = false; - } - } - - popupWidth: triggerScreen ? Math.min(500, Math.max(380, triggerScreen.width - 48)) : 400 - popupHeight: stablePopupHeight - positioning: "" - animationScaleCollapsed: 0.94 - animationOffset: 0 - suspendShadowWhileResizing: false - - screen: triggerScreen - - function toggle() { - notificationHistoryVisible = !notificationHistoryVisible; - } - - function openSized() { - if (!notificationHistoryVisible) - return; - - primeContent(); - if (contentLoader.item) { - updateStablePopupHeight(); - _pendingSizedOpen = false; - Qt.callLater(() => { - if (!notificationHistoryVisible) - return; - updateStablePopupHeight(); - open(); - clearPrimedContent(); - }); - return; - } - - _pendingSizedOpen = true; - } - - onBackgroundClicked: { - notificationHistoryVisible = false; - } - - onNotificationHistoryVisibleChanged: { - if (notificationHistoryVisible) { - openSized(); - } else { - _pendingSizedOpen = false; - clearPrimedContent(); - close(); - } - } - - function setupKeyboardNavigation() { - if (!contentLoader.item) - return; - contentLoader.item.externalKeyboardController = keyboardController; - - const notificationList = findChild(contentLoader.item, "notificationList"); - const notificationHeader = findChild(contentLoader.item, "notificationHeader"); - - if (notificationList) { - keyboardController.listView = notificationList; - notificationList.keyboardController = keyboardController; - } - if (notificationHeader) { - notificationHeader.keyboardController = keyboardController; - } - - keyboardController.reset(); - keyboardController.rebuildFlatNavigation(); - } - - Connections { - target: contentLoader - function onLoaded() { - root.updateStablePopupHeight(); - if (root._pendingSizedOpen && root.notificationHistoryVisible) { - Qt.callLater(() => { - if (!root._pendingSizedOpen || !root.notificationHistoryVisible) - return; - root.updateStablePopupHeight(); - root._pendingSizedOpen = false; - root.open(); - root.clearPrimedContent(); - }); - return; - } - if (root.shouldBeVisible) - Qt.callLater(root.setupKeyboardNavigation); - } - } - - Connections { - target: contentLoader.item - function onImplicitHeightChanged() { - root.updateStablePopupHeight(); - } - } - - onDprChanged: updateStablePopupHeight() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - NotificationService.onOverlayOpen(); - updateStablePopupHeight(); - if (contentLoader.item) - Qt.callLater(setupKeyboardNavigation); - } else { - NotificationService.onOverlayClose(); - keyboardController.keyboardNavigationActive = false; - NotificationService.expandedGroups = {}; - NotificationService.expandedMessages = {}; - } - } - - function findChild(parent, objectName) { - if (parent.objectName === objectName) { - return parent; - } - for (let i = 0; i < parent.children.length; i++) { - const child = parent.children[i]; - const result = findChild(child, objectName); - if (result) { - return result; - } - } - return null; - } - - content: Component { - Rectangle { - id: notificationContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var externalKeyboardController: null - property real cachedHeaderHeight: 32 - readonly property real settingsMaxHeight: { - const screenH = root.screen ? root.screen.height : 1080; - const maxPopupH = screenH * 0.8; - const overhead = cachedHeaderHeight + Theme.spacingL * 2 + Theme.spacingM * 2; - return Math.max(200, maxPopupH - overhead - 150); - } - implicitHeight: { - let baseHeight = Theme.spacingL * 2; - baseHeight += cachedHeaderHeight; - baseHeight += Theme.spacingM * 2; - - const settingsHeight = notificationSettings.expanded ? Math.min(notificationSettings.naturalContentHeight, settingsMaxHeight) : 0; - const currentListHeight = root.shouldBeVisible ? notificationList.stableContentHeight : notificationList.listContentHeight; - let listHeight = notificationHeader.currentTab === 0 ? currentListHeight : Math.max(200, NotificationService.historyList.length * 80); - if (notificationHeader.currentTab === 0 && NotificationService.groupedNotifications.length === 0) { - listHeight = 200; - } - if (notificationHeader.currentTab === 1 && NotificationService.historyList.length === 0) { - listHeight = 200; - } - - const maxContentArea = 600; - const availableListSpace = Math.max(200, maxContentArea - settingsHeight); - - baseHeight += settingsHeight; - baseHeight += Math.min(listHeight, availableListSpace); - - const maxHeight = root.screen ? root.screen.height * 0.8 : Screen.height * 0.8; - return Math.max(300, Math.min(baseHeight, maxHeight)); - } - - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - notificationHistoryVisible = false; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Left) { - if (notificationHeader.currentTab > 0) { - notificationHeader.currentTab = 0; - event.accepted = true; - } - return; - } - - if (event.key === Qt.Key_Right) { - if (notificationHeader.currentTab === 0 && SettingsData.notificationHistoryEnabled) { - notificationHeader.currentTab = 1; - event.accepted = true; - } - return; - } - if (notificationHeader.currentTab === 1) { - historyList.handleKey(event); - return; - } - if (externalKeyboardController) { - externalKeyboardController.handleKey(event); - } - } - - Connections { - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => { - notificationContent.forceActiveFocus(); - }); - } else { - notificationContent.focus = false; - } - } - target: root - } - - FocusScope { - id: contentColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - focus: true - - Column { - id: contentColumnInner - anchors.fill: parent - spacing: Theme.spacingM - - NotificationHeader { - id: notificationHeader - objectName: "notificationHeader" - onHeightChanged: notificationContent.cachedHeaderHeight = height - } - - NotificationSettings { - id: notificationSettings - expanded: notificationHeader.showSettings - maxAllowedHeight: notificationContent.settingsMaxHeight - } - - Item { - visible: notificationHeader.currentTab === 0 - width: parent.width - height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2 - - KeyboardNavigatedNotificationList { - id: notificationList - objectName: "notificationList" - anchors.fill: parent - anchors.leftMargin: -shadowHorizontalGutter - anchors.rightMargin: -shadowHorizontalGutter - anchors.topMargin: -(shadowVerticalGutter + delegateShadowGutter / 2) - anchors.bottomMargin: -(shadowVerticalGutter + delegateShadowGutter / 2) - cardAnimateExpansion: true - } - } - - HistoryNotificationList { - id: historyList - visible: notificationHeader.currentTab === 1 - width: parent.width - height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2 - } - } - } - - NotificationKeyboardHints { - id: keyboardHints - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - showHints: notificationHeader.currentTab === 0 ? (externalKeyboardController && externalKeyboardController.showKeyboardHints) || false : historyList.showKeyboardHints - z: 200 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml deleted file mode 100644 index da8746e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml +++ /dev/null @@ -1,34 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - width: parent.width - height: 200 - visible: NotificationService.notifications.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - width: parent.width * 0.8 - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "notifications_none" - size: Theme.iconSizeLarge + 16 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3) - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr("Nothing to see here") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3) - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml deleted file mode 100644 index 201e716..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml +++ /dev/null @@ -1,158 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property var keyboardController: null - property bool showSettings: false - property int currentTab: 0 - - onCurrentTabChanged: { - if (currentTab === 1 && !SettingsData.notificationHistoryEnabled) - currentTab = 0; - } - - Connections { - target: SettingsData - function onNotificationHistoryEnabledChanged() { - if (!SettingsData.notificationHistoryEnabled) - root.currentTab = 0; - } - } - - width: parent.width - height: headerColumn.implicitHeight - - DankTooltipV2 { - id: sharedTooltip - } - - Column { - id: headerColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(titleRow.implicitHeight, actionsRow.implicitHeight) - - Row { - id: titleRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Notifications") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - id: doNotDisturbButton - iconName: SessionData.doNotDisturb ? "notifications_off" : "notifications" - iconColor: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - onClicked: SessionData.setDoNotDisturb(!SessionData.doNotDisturb) - onEntered: sharedTooltip.show(I18n.tr("Do Not Disturb"), doNotDisturbButton, 0, 0, "bottom") - onExited: sharedTooltip.hide() - } - } - - Row { - id: actionsRow - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: helpButton - iconName: "info" - iconColor: (keyboardController && keyboardController.showKeyboardHints) ? Theme.primary : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - visible: keyboardController !== null - anchors.verticalCenter: parent.verticalCenter - onClicked: { - if (keyboardController) - keyboardController.showKeyboardHints = !keyboardController.showKeyboardHints; - } - } - - DankActionButton { - id: settingsButton - iconName: "settings" - iconColor: root.showSettings ? Theme.primary : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - onClicked: root.showSettings = !root.showSettings - } - - Rectangle { - id: clearAllButton - width: clearButtonContent.implicitWidth + Theme.spacingM * 2 - height: Theme.iconSize + Theme.spacingS - radius: Theme.cornerRadius - visible: root.currentTab === 0 ? NotificationService.notifications.length > 0 : NotificationService.historyList.length > 0 - color: clearArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Row { - id: clearButtonContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "delete_sweep" - size: Theme.iconSizeSmall - color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Clear") - font.pixelSize: Theme.fontSizeSmall - color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: clearArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.currentTab === 0) { - NotificationService.clearAllNotifications(); - } else { - NotificationService.clearHistory(); - } - } - } - } - } - } - - DankButtonGroup { - id: tabGroup - width: parent.width - currentIndex: root.currentTab - buttonHeight: 32 - buttonPadding: Theme.spacingM - checkEnabled: false - textSize: Theme.fontSizeSmall - visible: SettingsData.notificationHistoryEnabled - model: [I18n.tr("Current", "notification center tab") + " (" + NotificationService.notifications.length + ")", I18n.tr("History", "notification center tab") + " (" + NotificationService.historyList.length + ")"] - onSelectionChanged: (index, selected) => { - if (selected) - root.currentTab = index; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml deleted file mode 100644 index eda12c0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml +++ /dev/null @@ -1,556 +0,0 @@ -import QtQuick -import qs.Services - -QtObject { - id: controller - - property var listView: null - property bool isOpen: false - property var onClose: null - - property int selectionVersion: 0 - - property bool keyboardNavigationActive: false - property int selectedFlatIndex: 0 - property var flatNavigation: [] - property bool showKeyboardHints: false - - property string selectedNotificationId: "" - property string selectedGroupKey: "" - property string selectedItemType: "" - property bool isTogglingGroup: false - property bool isRebuilding: false - - function rebuildFlatNavigation() { - isRebuilding = true; - - const nav = []; - const groups = NotificationService.groupedNotifications; - - for (var i = 0; i < groups.length; i++) { - const group = groups[i]; - const isExpanded = NotificationService.expandedGroups[group.key] || false; - - nav.push({ - "type": "group", - "groupIndex": i, - "notificationIndex": -1, - "groupKey": group.key, - "notificationId": "" - }); - - if (isExpanded) { - const notifications = group.notifications || []; - const maxNotifications = Math.min(notifications.length, 10); - for (var j = 0; j < maxNotifications; j++) { - const notifId = String(notifications[j] && notifications[j].notification && notifications[j].notification.id ? notifications[j].notification.id : ""); - nav.push({ - "type": "notification", - "groupIndex": i, - "notificationIndex": j, - "groupKey": group.key, - "notificationId": notifId - }); - } - } - } - - flatNavigation = nav; - updateSelectedIndexFromId(); - isRebuilding = false; - } - - function updateSelectedIndexFromId() { - if (!keyboardNavigationActive) { - return; - } - - for (var i = 0; i < flatNavigation.length; i++) { - const item = flatNavigation[i]; - - if (selectedItemType === "group" && item.type === "group" && item.groupKey === selectedGroupKey) { - selectedFlatIndex = i; - selectionVersion++; // Trigger UI update - return; - } else if (selectedItemType === "notification" && item.type === "notification" && String(item.notificationId) === String(selectedNotificationId)) { - selectedFlatIndex = i; - selectionVersion++; // Trigger UI update - return; - } - } - - // If not found, try to find the same group but select the group header instead - if (selectedItemType === "notification") { - for (var j = 0; j < flatNavigation.length; j++) { - const groupItem = flatNavigation[j]; - if (groupItem.type === "group" && groupItem.groupKey === selectedGroupKey) { - selectedFlatIndex = j; - selectedItemType = "group"; - selectedNotificationId = ""; - selectionVersion++; // Trigger UI update - return; - } - } - } - - // If still not found, clamp to valid range and update - if (flatNavigation.length > 0) { - selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1); - selectedFlatIndex = Math.max(selectedFlatIndex, 0); - updateSelectedIdFromIndex(); - selectionVersion++; // Trigger UI update - } - } - - function updateSelectedIdFromIndex() { - if (selectedFlatIndex >= 0 && selectedFlatIndex < flatNavigation.length) { - const item = flatNavigation[selectedFlatIndex]; - selectedItemType = item.type; - selectedGroupKey = item.groupKey; - selectedNotificationId = item.notificationId; - } - } - - function reset() { - selectedFlatIndex = 0; - keyboardNavigationActive = false; - showKeyboardHints = false; - // Reset keyboardActive when modal is reset - if (listView) { - listView.keyboardActive = false; - } - rebuildFlatNavigation(); - } - - function selectNext() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = Math.min(selectedFlatIndex + 1, flatNavigation.length - 1); - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function selectNextWrapping() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = (selectedFlatIndex + 1) % flatNavigation.length; - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function selectPrevious() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = Math.max(selectedFlatIndex - 1, 0); - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function toggleGroupExpanded() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - - // Prevent expanding groups with < 2 notifications - const notificationCount = group.notifications ? group.notifications.length : 0; - if (notificationCount < 2) - return; - const wasExpanded = NotificationService.expandedGroups[group.key] || false; - const groupIndex = currentItem.groupIndex; - - isTogglingGroup = true; - NotificationService.toggleGroupExpansion(group.key); - rebuildFlatNavigation(); - - // Smart selection after toggle - if (!wasExpanded) { - // Just expanded - move to first notification in the group - for (var i = 0; i < flatNavigation.length; i++) { - if (flatNavigation[i].type === "notification" && flatNavigation[i].groupIndex === groupIndex) { - selectedFlatIndex = i; - break; - } - } - } else { - // Just collapsed - stay on the group header - for (var i = 0; i < flatNavigation.length; i++) { - if (flatNavigation[i].type === "group" && flatNavigation[i].groupIndex === groupIndex) { - selectedFlatIndex = i; - break; - } - } - } - - isTogglingGroup = false; - } - - function handleEnterKey() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - if (currentItem.type === "group") { - const notificationCount = group.notifications ? group.notifications.length : 0; - if (notificationCount >= 2) { - toggleGroupExpanded(); - } else { - executeAction(0); - } - } else if (currentItem.type === "notification") { - executeAction(0); - } - } - - function toggleTextExpanded() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - let messageId = ""; - - if (currentItem.type === "group") { - messageId = group.latestNotification?.notification?.id + "_desc"; - } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) { - messageId = group.notifications[currentItem.notificationIndex]?.notification?.id + "_desc"; - } - - if (messageId) { - NotificationService.toggleMessageExpansion(messageId); - } - } - - function executeAction(actionIndex) { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - let actions = []; - - if (currentItem.type === "group") { - actions = group.latestNotification?.actions || []; - } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) { - actions = group.notifications[currentItem.notificationIndex]?.actions || []; - } - - if (actionIndex >= 0 && actionIndex < actions.length) { - const action = actions[actionIndex]; - if (action.invoke) { - action.invoke(); - if (onClose) - onClose(); - } - } - } - - function clearSelected() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - if (currentItem.type === "group") { - NotificationService.dismissGroup(group.key); - } else if (currentItem.type === "notification") { - const notification = group.notifications[currentItem.notificationIndex]; - NotificationService.dismissNotification(notification); - } - - rebuildFlatNavigation(); - - if (flatNavigation.length === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - } else { - selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1); - updateSelectedIdFromIndex(); - ensureVisible(); - } - } - - function findRepeater(parent) { - if (!parent || !parent.children) { - return null; - } - for (var i = 0; i < parent.children.length; i++) { - const child = parent.children[i]; - if (child.objectName === "notificationRepeater") { - return child; - } - const found = findRepeater(child); - if (found) { - return found; - } - } - return null; - } - - function ensureVisible() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length || !listView) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - - if (keyboardNavigationActive && currentItem && currentItem.groupIndex >= 0) { - if (currentItem.type === "notification") { - const groupDelegate = listView.itemAtIndex(currentItem.groupIndex); - if (groupDelegate && groupDelegate.children && groupDelegate.children.length > 0) { - const notificationCard = groupDelegate.children[0]; - const repeater = findRepeater(notificationCard); - - if (repeater && currentItem.notificationIndex < repeater.count) { - const notificationItem = repeater.itemAt(currentItem.notificationIndex); - if (notificationItem) { - const itemPos = notificationItem.mapToItem(listView.contentItem, 0, 0); - const itemY = itemPos.y; - const itemHeight = notificationItem.height; - - const viewportTop = listView.contentY; - const viewportBottom = listView.contentY + listView.height; - - if (itemY < viewportTop) { - listView.contentY = itemY - 20; - } else if (itemY + itemHeight > viewportBottom) { - listView.contentY = itemY + itemHeight - listView.height + 20; - } - } - } - } - } else { - listView.positionViewAtIndex(currentItem.groupIndex, ListView.Contain); - } - - listView.forceLayout(); - } - } - - function handleKey(event) { - if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) && (event.modifiers & Qt.ShiftModifier)) { - NotificationService.clearAllNotifications(); - rebuildFlatNavigation(); - if (flatNavigation.length === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - } else { - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - } - selectionVersion++; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Escape) { - if (keyboardNavigationActive) { - keyboardNavigationActive = false; - event.accepted = true; - } else { - if (onClose) - onClose(); - event.accepted = true; - } - } else if (event.key === Qt.Key_Down || event.key === 16777237) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); // Ensure we have fresh navigation data - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - // Set keyboardActive on listView to show highlight - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - event.accepted = true; - } else { - selectNext(); - event.accepted = true; - } - } else if (event.key === Qt.Key_Up || event.key === 16777235) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); // Ensure we have fresh navigation data - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - // Set keyboardActive on listView to show highlight - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - event.accepted = true; - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - // Reset keyboardActive when navigation is disabled - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - event.accepted = true; - return; - } else { - selectPrevious(); - event.accepted = true; - } - } else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - } else { - selectPrevious(); - } - event.accepted = true; - } else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - } else { - selectPrevious(); - } - event.accepted = true; - } else if (keyboardNavigationActive) { - if (event.key === Qt.Key_Space) { - toggleGroupExpanded(); - event.accepted = true; - } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - handleEnterKey(); - event.accepted = true; - } else if (event.key === Qt.Key_E) { - toggleTextExpanded(); - event.accepted = true; - } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) { - clearSelected(); - event.accepted = true; - } else if (event.key === Qt.Key_Tab) { - selectNext(); - event.accepted = true; - } else if (event.key === Qt.Key_Backtab) { - selectPrevious(); - event.accepted = true; - } else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) { - const actionIndex = event.key - Qt.Key_1; - executeAction(actionIndex); - event.accepted = true; - } - } - - if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints; - event.accepted = true; - } - } - - // Get current selection info for UI - function getCurrentSelection() { - if (!keyboardNavigationActive || selectedFlatIndex < 0 || selectedFlatIndex >= flatNavigation.length) { - return { - "type": "", - "groupIndex": -1, - "notificationIndex": -1 - }; - } - const result = flatNavigation[selectedFlatIndex] || { - "type": "", - "groupIndex": -1, - "notificationIndex": -1 - }; - return result; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml deleted file mode 100644 index 78ba2d5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml +++ /dev/null @@ -1,50 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool showHints: false - - height: 80 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Theme.primary - border.width: 2 - opacity: showHints ? 1 : 0 - z: 100 - - Column { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingS - spacing: 2 - - StyledText { - text: I18n.tr("↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml deleted file mode 100644 index 97364c7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml +++ /dev/null @@ -1,449 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool expanded: false - property real maxAllowedHeight: 0 - readonly property real naturalContentHeight: contentColumn.height + Theme.spacingL * 2 - - width: parent.width - height: expanded ? (maxAllowedHeight > 0 ? Math.min(naturalContentHeight, maxAllowedHeight) : naturalContentHeight) : 0 - visible: expanded - clip: true - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 1 - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - opacity: expanded ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - readonly property var timeoutOptions: [ - { - "text": I18n.tr("Never"), - "value": 0 - }, - { - "text": I18n.tr("1 second"), - "value": 1000 - }, - { - "text": I18n.tr("3 seconds"), - "value": 3000 - }, - { - "text": I18n.tr("5 seconds"), - "value": 5000 - }, - { - "text": I18n.tr("8 seconds"), - "value": 8000 - }, - { - "text": I18n.tr("10 seconds"), - "value": 10000 - }, - { - "text": I18n.tr("15 seconds"), - "value": 15000 - }, - { - "text": I18n.tr("30 seconds"), - "value": 30000 - }, - { - "text": I18n.tr("1 minute"), - "value": 60000 - }, - { - "text": I18n.tr("2 minutes"), - "value": 120000 - }, - { - "text": I18n.tr("5 minutes"), - "value": 300000 - }, - { - "text": I18n.tr("10 minutes"), - "value": 600000 - } - ] - - function getTimeoutText(value) { - if (value === undefined || value === null || isNaN(value)) { - return I18n.tr("5 seconds"); - } - - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].value === value) { - return timeoutOptions[i].text; - } - } - if (value === 0) { - return I18n.tr("Never"); - } - if (value < 1000) { - return value + "ms"; - } - if (value < 60000) { - return Math.round(value / 1000) + " " + I18n.tr("seconds"); - } - return Math.round(value / 60000) + " " + I18n.tr("minutes"); - } - - Flickable { - id: settingsFlickable - anchors.fill: parent - contentHeight: contentColumn.height + Theme.spacingL * 2 - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.DragAndOvershootBounds - interactive: root.naturalContentHeight > root.height - - Column { - id: contentColumn - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Notification Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - } - - Item { - width: parent.width - height: Math.max(dndRow.implicitHeight, dndToggle.implicitHeight) + Theme.spacingS - - Row { - id: dndRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: SessionData.doNotDisturb ? "notifications_off" : "notifications" - size: Theme.iconSizeSmall - color: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Do Not Disturb") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: dndToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SessionData.doNotDisturb - onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb) - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - StyledText { - text: I18n.tr("Notification Timeouts") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - DankDropdown { - text: I18n.tr("Low Priority") - description: I18n.tr("Timeout for low priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutLow) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutLow", timeoutOptions[i].value); - break; - } - } - } - } - - DankDropdown { - text: I18n.tr("Normal Priority") - description: I18n.tr("Timeout for normal priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutNormal", timeoutOptions[i].value); - break; - } - } - } - } - - DankDropdown { - text: I18n.tr("Critical Priority") - description: I18n.tr("Timeout for critical priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutCritical", timeoutOptions[i].value); - break; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - Item { - width: parent.width - height: Math.max(overlayRow.implicitHeight, overlayToggle.implicitHeight) + Theme.spacingS - - Row { - id: overlayRow - anchors.left: parent.left - anchors.right: overlayToggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "notifications_active" - size: Theme.iconSizeSmall - color: SettingsData.notificationOverlayEnabled ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: overlayRow.width - Theme.iconSizeSmall - Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Notification Overlay") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.Wrap - } - - StyledText { - width: parent.width - text: I18n.tr("Display all priorities over fullscreen apps") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.Wrap - } - } - } - - DankToggle { - id: overlayToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationOverlayEnabled - onToggled: toggled => SettingsData.set("notificationOverlayEnabled", toggled) - } - } - - Item { - width: parent.width - height: Math.max(privacyRow.implicitHeight, privacyToggle.implicitHeight) + Theme.spacingS - - Row { - id: privacyRow - anchors.left: parent.left - anchors.right: privacyToggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "privacy_tip" - size: Theme.iconSizeSmall - color: SettingsData.notificationPopupPrivacyMode ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: privacyRow.width - Theme.iconSizeSmall - Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Privacy Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.Wrap - } - - StyledText { - width: parent.width - text: I18n.tr("Hide notification content until expanded") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.Wrap - } - } - } - - DankToggle { - id: privacyToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationPopupPrivacyMode - onToggled: toggled => SettingsData.set("notificationPopupPrivacyMode", toggled) - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - StyledText { - text: I18n.tr("History Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - Item { - width: parent.width - height: Math.max(lowRow.implicitHeight, lowToggle.implicitHeight) + Theme.spacingS - - Row { - id: lowRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "low_priority" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveLow ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Low Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: lowToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveLow - onToggled: toggled => SettingsData.set("notificationHistorySaveLow", toggled) - } - } - - Item { - width: parent.width - height: Math.max(normalRow.implicitHeight, normalToggle.implicitHeight) + Theme.spacingS - - Row { - id: normalRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "notifications" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveNormal ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Normal Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: normalToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveNormal - onToggled: toggled => SettingsData.set("notificationHistorySaveNormal", toggled) - } - } - - Item { - width: parent.width - height: Math.max(criticalRow.implicitHeight, criticalToggle.implicitHeight) + Theme.spacingS - - Row { - id: criticalRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "priority_high" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveCritical ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Critical Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: criticalToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveCritical - onToggled: toggled => SettingsData.set("notificationHistorySaveCritical", toggled) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopup.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopup.qml deleted file mode 100644 index 8c9f7f4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopup.qml +++ /dev/null @@ -1,1164 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Services.Notifications -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: win - - WindowBlur { - targetWindow: win - blurX: content.x + content.cardInset + swipeTx.x + tx.x - blurY: content.y + content.cardInset + swipeTx.y + tx.y - blurWidth: !win._finalized ? Math.max(0, content.width - content.cardInset * 2) : 0 - blurHeight: !win._finalized ? Math.max(0, content.height - content.cardInset * 2) : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:notification-popup" - - required property var notificationData - required property string notificationId - readonly property bool hasValidData: notificationData && notificationData.notification - readonly property alias hovered: cardHoverHandler.hovered - property int screenY: 0 - property bool exiting: false - property bool _isDestroying: false - property bool _finalized: false - property real _lastReportedAlignedHeight: -1 - property real _storedTopMargin: 0 - property real _storedBottomMargin: 0 - readonly property string clearText: I18n.tr("Dismiss") - property bool descriptionExpanded: false - readonly property bool hasExpandableBody: (notificationData?.htmlBody || "").replace(/<[^>]*>/g, "").trim().length > 0 - onDescriptionExpandedChanged: { - popupHeightChanged(); - } - onImplicitHeightChanged: { - const aligned = Theme.px(implicitHeight, dpr); - if (Math.abs(aligned - _lastReportedAlignedHeight) < 0.5) - return; - _lastReportedAlignedHeight = aligned; - popupHeightChanged(); - } - - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real popupIconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real contentBottomClearance: 8 - readonly property real actionButtonHeight: compactMode ? 20 : 24 - readonly property real collapsedContentHeight: Math.max(popupIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) + contentBottomClearance - readonly property real privacyCollapsedContentHeight: Math.max(popupIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2) + contentBottomClearance - readonly property real basePopupHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing - readonly property real basePopupHeightPrivacy: cardPadding * 2 + privacyCollapsedContentHeight + actionButtonHeight + contentSpacing - - signal entered - signal exitStarted - signal exitFinished - signal popupHeightChanged - - function startExit() { - if (exiting || _isDestroying) { - return; - } - exiting = true; - exitStarted(); - exitAnim.restart(); - exitWatchdog.restart(); - if (NotificationService.removeFromVisibleNotifications) - NotificationService.removeFromVisibleNotifications(win.notificationData); - } - - function forceExit() { - if (_isDestroying) { - return; - } - _isDestroying = true; - exiting = true; - visible = false; - exitWatchdog.stop(); - finalizeExit("forced"); - } - - function finalizeExit(reason) { - if (_finalized) { - return; - } - - _finalized = true; - _isDestroying = true; - exitWatchdog.stop(); - wrapperConn.enabled = false; - wrapperConn.target = null; - win.exitFinished(); - } - - visible: !_finalized - WlrLayershell.layer: { - const envLayer = Quickshell.env("DMS_NOTIFICATION_LAYER"); - if (envLayer) { - switch (envLayer) { - case "bottom": - return WlrLayershell.Bottom; - case "overlay": - return WlrLayershell.Overlay; - case "background": - return WlrLayershell.Background; - case "top": - return WlrLayershell.Top; - } - } - - if (!notificationData) - return WlrLayershell.Top; - - SettingsData.notificationOverlayEnabled; - - const shouldUseOverlay = (SettingsData.notificationOverlayEnabled) || (notificationData.urgency === NotificationUrgency.Critical); - - return shouldUseOverlay ? WlrLayershell.Overlay : WlrLayershell.Top; - } - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - readonly property real contentImplicitWidth: screen ? Math.min(400, Math.max(320, screen.width * 0.23)) : 380 - readonly property real contentImplicitHeight: { - if (SettingsData.notificationPopupPrivacyMode && !descriptionExpanded) - return basePopupHeightPrivacy; - if (!descriptionExpanded) - return basePopupHeight; - const bodyTextHeight = bodyText.contentHeight || 0; - const collapsedBodyHeight = Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2); - if (bodyTextHeight > collapsedBodyHeight + 2) - return basePopupHeight + bodyTextHeight - collapsedBodyHeight; - return basePopupHeight; - } - implicitWidth: contentImplicitWidth + (windowShadowPad * 2) - implicitHeight: contentImplicitHeight + (windowShadowPad * 2) - - Behavior on implicitHeight { - enabled: !exiting && !_isDestroying - NumberAnimation { - id: implicitHeightAnim - duration: descriptionExpanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasized - } - } - - onHasValidDataChanged: { - if (!hasValidData && !exiting && !_isDestroying) { - forceExit(); - } - } - Component.onCompleted: { - _lastReportedAlignedHeight = Theme.px(implicitHeight, dpr); - _storedTopMargin = getTopMargin(); - _storedBottomMargin = getBottomMargin(); - if (SettingsData.notificationPopupPrivacyMode) - descriptionExpanded = false; - if (hasValidData) { - Qt.callLater(() => enterX.restart()); - } else { - forceExit(); - } - } - onNotificationDataChanged: { - if (!_isDestroying) { - if (SettingsData.notificationPopupPrivacyMode) - descriptionExpanded = false; - wrapperConn.target = win.notificationData || null; - notificationConn.target = (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null; - } - } - onEntered: { - if (!_isDestroying) { - enterDelay.start(); - } - } - Component.onDestruction: { - _isDestroying = true; - exitWatchdog.stop(); - if (notificationData && notificationData.timer) { - notificationData.timer.stop(); - } - } - - property bool isTopCenter: SettingsData.notificationPopupPosition === -1 - property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter - property bool isCenterPosition: isTopCenter || isBottomCenter - readonly property real maxPopupShadowBlurPx: Math.max((Theme.elevationLevel3 && Theme.elevationLevel3.blurPx !== undefined) ? Theme.elevationLevel3.blurPx : 12, (Theme.elevationLevel4 && Theme.elevationLevel4.blurPx !== undefined) ? Theme.elevationLevel4.blurPx : 16) - readonly property real maxPopupShadowOffsetXPx: Math.max(Math.abs(Theme.elevationOffsetX(Theme.elevationLevel3)), Math.abs(Theme.elevationOffsetX(Theme.elevationLevel4))) - readonly property real maxPopupShadowOffsetYPx: Math.max(Math.abs(Theme.elevationOffsetY(Theme.elevationLevel3, 6)), Math.abs(Theme.elevationOffsetY(Theme.elevationLevel4, 8))) - readonly property real windowShadowPad: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + Math.max(maxPopupShadowOffsetXPx, maxPopupShadowOffsetYPx) + 8), dpr) : 0 - - anchors.top: true - anchors.left: true - anchors.bottom: false - anchors.right: false - - mask: contentInputMask - - Region { - id: contentInputMask - item: contentMaskRect - } - - Item { - id: contentMaskRect - visible: false - x: content.x - y: content.y - width: alignedWidth - height: alignedHeight - } - - margins { - top: getWindowTopMargin() - bottom: 0 - left: getWindowLeftMargin() - right: 0 - } - - function getBarInfo() { - if (!screen) - return { - topBar: 0, - bottomBar: 0, - leftBar: 0, - rightBar: 0 - }; - return SettingsData.getAdjacentBarInfo(screen, SettingsData.notificationPopupPosition, { - id: "notification-popup", - screenPreferences: [screen.name], - autoHide: false - }); - } - - function getTopMargin() { - const popupPos = SettingsData.notificationPopupPosition; - const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left; - if (!isTop) - return 0; - - const barInfo = getBarInfo(); - const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance; - return base + screenY; - } - - function getBottomMargin() { - const popupPos = SettingsData.notificationPopupPosition; - const isBottom = isBottomCenter || popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right; - if (!isBottom) - return 0; - - const barInfo = getBarInfo(); - const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance; - return base + screenY; - } - - function getLeftMargin() { - if (isCenterPosition) - return screen ? (screen.width - alignedWidth) / 2 : 0; - - const popupPos = SettingsData.notificationPopupPosition; - const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom; - if (!isLeft) - return 0; - - const barInfo = getBarInfo(); - return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance; - } - - function getRightMargin() { - if (isCenterPosition) - return 0; - - const popupPos = SettingsData.notificationPopupPosition; - const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right; - if (!isRight) - return 0; - - const barInfo = getBarInfo(); - return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance; - } - - function getContentX() { - if (!screen) - return 0; - - const popupPos = SettingsData.notificationPopupPosition; - const barLeft = getLeftMargin(); - const barRight = getRightMargin(); - - if (isCenterPosition) - return Theme.snap((screen.width - alignedWidth) / 2, dpr); - if (popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom) - return Theme.snap(barLeft, dpr); - return Theme.snap(screen.width - alignedWidth - barRight, dpr); - } - - function getContentY() { - if (!screen) - return 0; - - const popupPos = SettingsData.notificationPopupPosition; - const barTop = getTopMargin(); - const barBottom = getBottomMargin(); - const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left; - if (isTop) - return Theme.snap(barTop, dpr); - return Theme.snap(screen.height - alignedHeight - barBottom, dpr); - } - - function getWindowLeftMargin() { - if (!screen) - return 0; - return Theme.snap(getContentX() - windowShadowPad, dpr); - } - - function getWindowTopMargin() { - if (!screen) - return 0; - return Theme.snap(getContentY() - windowShadowPad, dpr); - } - - readonly property bool screenValid: win.screen && !_isDestroying - readonly property real dpr: screenValid ? CompositorService.getScreenScale(win.screen) : 1 - readonly property real alignedWidth: Theme.px(Math.max(0, implicitWidth - (windowShadowPad * 2)), dpr) - readonly property real alignedHeight: Theme.px(Math.max(0, implicitHeight - (windowShadowPad * 2)), dpr) - - Item { - id: content - - x: Theme.snap(windowShadowPad, dpr) - y: Theme.snap(windowShadowPad, dpr) - width: alignedWidth - height: alignedHeight - visible: !win._finalized - scale: cardHoverHandler.hovered ? 1.01 : 1.0 - transformOrigin: Item.Center - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - property real swipeOffset: 0 - readonly property real dismissThreshold: isCenterPosition ? height * 0.4 : width * 0.35 - readonly property real swipeFadeStartRatio: 0.75 - readonly property real swipeTravelDistance: isCenterPosition ? height : width - readonly property real swipeFadeStartOffset: swipeTravelDistance * swipeFadeStartRatio - readonly property real swipeFadeDistance: Math.max(1, swipeTravelDistance - swipeFadeStartOffset) - readonly property bool swipeActive: swipeDragHandler.active - property bool swipeDismissing: false - - readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled - readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3 - readonly property real cardInset: Theme.snap(4, win.dpr) - readonly property real shadowRenderPadding: shadowsAllowed ? Theme.snap(Math.max(16, shadowBlurPx + Math.max(Math.abs(shadowOffsetX), Math.abs(shadowOffsetY)) + 8), win.dpr) : 0 - property real shadowBlurPx: shadowsAllowed ? (elevLevel && elevLevel.blurPx !== undefined ? elevLevel.blurPx : 12) : 0 - property real shadowOffsetX: shadowsAllowed ? Theme.elevationOffsetX(elevLevel) : 0 - property real shadowOffsetY: shadowsAllowed ? Theme.elevationOffsetY(elevLevel, 6) : 0 - - Behavior on shadowBlurPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetX { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetY { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - ElevationShadow { - id: bgShadowLayer - anchors.fill: parent - anchors.margins: -content.shadowRenderPadding - level: content.elevLevel - fallbackOffset: 6 - shadowBlurPx: content.shadowBlurPx - shadowOffsetX: content.shadowOffsetX - shadowOffsetY: content.shadowOffsetY - shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent" - shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed - layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - - sourceRect.anchors.fill: undefined - sourceRect.x: content.shadowRenderPadding + content.cardInset - sourceRect.y: content.shadowRenderPadding + content.cardInset - sourceRect.width: Math.max(0, content.width - (content.cardInset * 2)) - sourceRect.height: Math.max(0, content.height - (content.cardInset * 2)) - sourceRect.radius: Theme.cornerRadius - sourceRect.color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - sourceRect.border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08) - sourceRect.border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0 - - Rectangle { - x: bgShadowLayer.sourceRect.x - y: bgShadowLayer.sourceRect.y - width: bgShadowLayer.sourceRect.width - height: bgShadowLayer.sourceRect.height - radius: bgShadowLayer.sourceRect.radius - visible: notificationData && notificationData.urgency === NotificationUrgency.Critical - opacity: 1 - clip: true - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - position: 0 - color: Theme.primary - } - - GradientStop { - position: 0.02 - color: Theme.primary - } - - GradientStop { - position: 0.021 - color: "transparent" - } - } - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: content.cardInset - radius: Theme.cornerRadius - color: "transparent" - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - Item { - id: backgroundContainer - anchors.fill: parent - anchors.margins: content.cardInset - clip: true - - HoverHandler { - id: cardHoverHandler - } - - Connections { - target: cardHoverHandler - function onHoveredChanged() { - if (!notificationData || win.exiting || win._isDestroying) - return; - if (cardHoverHandler.hovered) { - if (notificationData.timer) - notificationData.timer.stop(); - } else if (notificationData.popup && notificationData.timer) { - notificationData.timer.restart(); - } - } - } - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - Item { - id: notificationContent - - readonly property real expandedTextHeight: bodyText.contentHeight || 0 - readonly property real collapsedBodyHeight: Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2) - readonly property real effectiveCollapsedHeight: (SettingsData.notificationPopupPrivacyMode && !descriptionExpanded) ? win.privacyCollapsedContentHeight : win.collapsedContentHeight - readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > collapsedBodyHeight + 2) ? (expandedTextHeight - collapsedBodyHeight) : 0 - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - height: effectiveCollapsedHeight + extraHeight - clip: SettingsData.notificationPopupPrivacyMode && !descriptionExpanded - - DankCircularImage { - id: iconContainer - - readonly property string rawImage: notificationData?.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - readonly property bool needsImagePersist: hasNotificationImage && rawImage.startsWith("image://qsimage/") && !notificationData.persistedImagePath - - width: popupIconSize - height: popupIconSize - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: { - if (SettingsData.notificationPopupPrivacyMode && !descriptionExpanded) { - const headerSummary = Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2; - return Math.max(0, headerSummary / 2 - popupIconSize / 2); - } - if (descriptionExpanded) - return Math.max(0, Theme.fontSizeSmall * 1.2 + (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) / 2 - popupIconSize / 2); - return Math.max(0, Theme.fontSizeSmall * 1.2 + (textContainer.height - Theme.fontSizeSmall * 1.2) / 2 - popupIconSize / 2); - } - - imageSource: { - if (!notificationData) - return ""; - if (hasNotificationImage) - return notificationData.cleanImage || ""; - if (imageHasSpecialPrefix) - return ""; - const appIcon = notificationData.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - hasImage: hasNotificationImage - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return notificationData?.appIcon || iconFromImage || ""; - } - fallbackText: { - const appName = notificationData?.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - - onImageStatusChanged: { - if (imageStatus === Image.Ready && needsImagePersist) { - const cachePath = NotificationService.getImageCachePath(notificationData); - saveImageToFile(cachePath); - } - } - - onImageSaved: filePath => { - if (!notificationData) - return; - notificationData.persistedImagePath = filePath; - const wrapperId = notificationData.notification?.id?.toString() || ""; - if (wrapperId) - NotificationService.updateHistoryImage(wrapperId, filePath); - } - } - - Column { - id: textContainer - - anchors.left: iconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.top: parent.top - spacing: Theme.notificationContentSpacing - - Row { - id: headerRow - width: parent.width - spacing: Theme.spacingXS - visible: headerAppNameText.text.length > 0 || headerTimeText.text.length > 0 - - StyledText { - id: headerAppNameText - text: notificationData ? (notificationData.appName || "") : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, parent.width - headerSeparator.implicitWidth - headerTimeText.implicitWidth - parent.spacing * 2) - } - - StyledText { - id: headerSeparator - text: (headerAppNameText.text.length > 0 && headerTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - - StyledText { - id: headerTimeText - text: notificationData ? (notificationData.timeStr || "") : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - } - - StyledText { - text: notificationData ? (notificationData.summary || "") : "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - id: bodyText - property bool hasMoreText: truncated - - text: notificationData ? (notificationData.htmlBody || "") : "" - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: descriptionExpanded ? Text.ElideNone : Text.ElideRight - horizontalAlignment: Text.AlignLeft - maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2) - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - visible: text.length > 0 - opacity: (SettingsData.notificationPopupPrivacyMode && !descriptionExpanded) ? 0 : 1 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (bodyText.hasMoreText || descriptionExpanded)) - win.descriptionExpanded = !win.descriptionExpanded; - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - onReleased: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - } - } - - StyledText { - text: I18n.tr("Message Content", "notification privacy mode placeholder") - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - visible: SettingsData.notificationPopupPrivacyMode && !descriptionExpanded && win.hasExpandableBody - } - } - } - - DankActionButton { - id: closeButton - - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: cardPadding - anchors.rightMargin: Theme.spacingL - iconName: "close" - iconSize: compactMode ? 14 : 16 - buttonSize: compactMode ? 20 : 24 - z: 15 - - onClicked: { - if (notificationData && !win.exiting) - notificationData.popup = false; - } - } - - DankActionButton { - id: expandButton - - anchors.right: closeButton.left - anchors.rightMargin: Theme.spacingXS - anchors.top: parent.top - anchors.topMargin: cardPadding - iconName: descriptionExpanded ? "expand_less" : "expand_more" - iconSize: compactMode ? 14 : 16 - buttonSize: compactMode ? 20 : 24 - z: 15 - visible: SettingsData.notificationPopupPrivacyMode && win.hasExpandableBody - - onClicked: { - if (win.hasExpandableBody) - win.descriptionExpanded = !win.descriptionExpanded; - } - } - - Row { - visible: cardHoverHandler.hovered - opacity: visible ? 1 : 0 - anchors.right: clearButton.visible ? clearButton.left : parent.right - anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL - anchors.top: notificationContent.bottom - anchors.topMargin: contentSpacing - spacing: contentSpacing - z: 20 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Repeater { - model: notificationData ? (notificationData.actions || []) : [] - - Rectangle { - property bool isHovered: false - - width: Math.max(actionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: actionText - - text: modelData.text || "Open" - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - elide: Text.ElideRight - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: { - if (modelData && modelData.invoke) - modelData.invoke(); - if (notificationData && !win.exiting) - notificationData.popup = false; - } - } - } - } - } - - Rectangle { - id: clearButton - - property bool isHovered: false - readonly property int actionCount: notificationData ? (notificationData.actions || []).length : 0 - - visible: actionCount < 3 && cardHoverHandler.hovered - opacity: visible ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL - anchors.top: notificationContent.bottom - anchors.topMargin: contentSpacing - width: Math.max(clearTextLabel.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - z: 20 - - StyledText { - id: clearTextLabel - - text: win.clearText - color: clearButton.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onEntered: clearButton.isHovered = true - onExited: clearButton.isHovered = false - onClicked: { - if (notificationData && !win.exiting) - NotificationService.dismissNotification(notificationData); - } - } - } - - MouseArea { - id: cardHoverArea - - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - z: -1 - onClicked: mouse => { - if (!notificationData || win.exiting) - return; - if (mouse.button === Qt.RightButton) { - popupContextMenu.popup(); - } else if (mouse.button === Qt.LeftButton) { - const canExpand = bodyText.hasMoreText || win.descriptionExpanded || (SettingsData.notificationPopupPrivacyMode && win.hasExpandableBody); - if (canExpand) { - win.descriptionExpanded = !win.descriptionExpanded; - } else if (notificationData.actions && notificationData.actions.length > 0) { - notificationData.actions[0].invoke(); - NotificationService.dismissNotification(notificationData); - } else { - notificationData.popup = false; - } - } - } - } - } - - DragHandler { - id: swipeDragHandler - target: null - xAxis.enabled: !isCenterPosition - yAxis.enabled: isCenterPosition - - onActiveChanged: { - if (active || win.exiting || content.swipeDismissing) - return; - - if (Math.abs(content.swipeOffset) > content.dismissThreshold) { - content.swipeDismissing = true; - swipeDismissAnim.start(); - } else { - content.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (win.exiting) - return; - - const raw = isCenterPosition ? translation.y : translation.x; - if (isTopCenter) { - content.swipeOffset = Math.min(0, raw); - } else if (isBottomCenter) { - content.swipeOffset = Math.max(0, raw); - } else { - const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom; - content.swipeOffset = isLeft ? Math.min(0, raw) : Math.max(0, raw); - } - } - } - - opacity: { - const swipeAmount = Math.abs(content.swipeOffset); - if (swipeAmount <= content.swipeFadeStartOffset) - return 1; - const fadeProgress = (swipeAmount - content.swipeFadeStartOffset) / content.swipeFadeDistance; - return Math.max(0, 1 - fadeProgress); - } - - Behavior on opacity { - enabled: !content.swipeActive - NumberAnimation { - duration: Theme.shortDuration - } - } - - Behavior on swipeOffset { - enabled: !content.swipeActive && !content.swipeDismissing - NumberAnimation { - duration: Theme.notificationExitDuration - easing.type: Theme.standardEasing - } - } - - NumberAnimation { - id: swipeDismissAnim - target: content - property: "swipeOffset" - to: isTopCenter ? -content.height : isBottomCenter ? content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width) - duration: Theme.notificationExitDuration - easing.type: Easing.OutCubic - onStopped: { - NotificationService.dismissNotification(notificationData); - win.forceExit(); - } - } - - transform: [ - Translate { - id: swipeTx - x: isCenterPosition ? 0 : content.swipeOffset - y: isCenterPosition ? content.swipeOffset : 0 - }, - Translate { - id: tx - x: { - if (isCenterPosition) - return 0; - const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom; - return isLeft ? -Anims.slidePx : Anims.slidePx; - } - y: isTopCenter ? -Anims.slidePx : isBottomCenter ? Anims.slidePx : 0 - } - ] - } - - NumberAnimation { - id: enterX - - target: tx - property: isCenterPosition ? "y" : "x" - from: { - if (isTopCenter) - return -Anims.slidePx; - if (isBottomCenter) - return Anims.slidePx; - const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom; - return isLeft ? -Anims.slidePx : Anims.slidePx; - } - to: 0 - duration: Theme.notificationEnterDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: isCenterPosition ? Theme.expressiveCurves.standardDecel : Theme.expressiveCurves.emphasizedDecel - onStopped: { - if (!win.exiting && !win._isDestroying) { - if (isCenterPosition) { - if (Math.abs(tx.y) < 0.5) - win.entered(); - } else { - if (Math.abs(tx.x) < 0.5) - win.entered(); - } - } - } - } - - ParallelAnimation { - id: exitAnim - - onStopped: finalizeExit("animStopped") - - PropertyAnimation { - target: tx - property: isCenterPosition ? "y" : "x" - from: 0 - to: { - if (isTopCenter) - return -Anims.slidePx; - if (isBottomCenter) - return Anims.slidePx; - const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom; - return isLeft ? -Anims.slidePx : Anims.slidePx; - } - duration: Theme.notificationExitDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedAccel - } - - NumberAnimation { - target: content - property: "opacity" - from: 1 - to: 0 - duration: Theme.notificationExitDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.standardAccel - } - - NumberAnimation { - target: content - property: "scale" - from: 1 - to: 0.98 - duration: Theme.notificationExitDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedAccel - } - } - - Connections { - id: wrapperConn - - function onPopupChanged() { - if (!win.notificationData || win._isDestroying) - return; - if (!win.notificationData.popup && !win.exiting) - startExit(); - } - - target: win.notificationData || null - ignoreUnknownSignals: true - enabled: !win._isDestroying - } - - Connections { - id: notificationConn - - function onDropped() { - if (!win._isDestroying && !win.exiting) - forceExit(); - } - - target: (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null - ignoreUnknownSignals: true - enabled: !win._isDestroying - } - - Timer { - id: enterDelay - - interval: 160 - repeat: false - onTriggered: { - if (notificationData && notificationData.timer && !exiting && !_isDestroying) - notificationData.timer.start(); - } - } - - Timer { - id: exitWatchdog - - interval: 600 - repeat: false - onTriggered: finalizeExit("watchdog") - } - - Behavior on screenY { - id: screenYAnim - - enabled: !exiting && !_isDestroying - - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.standardDecel - } - } - - Menu { - id: popupContextMenu - width: 220 - contentHeight: 130 - margins: -1 - popupType: Popup.Window - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - id: setNotificationRulesItem - text: I18n.tr("Set notification rules") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationData?.appName || ""; - const desktopEntry = notificationData?.desktopEntry || ""; - SettingsData.addNotificationRuleForNotification(appName, desktopEntry); - PopoutService.openSettingsWithTab("notifications"); - } - } - - MenuItem { - id: muteUnmuteItem - readonly property bool isMuted: SettingsData.isAppMuted(notificationData?.appName || "", notificationData?.desktopEntry || "") - text: isMuted ? I18n.tr("Unmute popups for %1").arg(notificationData?.appName || I18n.tr("this app")) : I18n.tr("Mute popups for %1").arg(notificationData?.appName || I18n.tr("this app")) - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationData?.appName || ""; - const desktopEntry = notificationData?.desktopEntry || ""; - if (isMuted) { - SettingsData.removeMuteRuleForApp(appName, desktopEntry); - } else { - SettingsData.addMuteRuleForApp(appName, desktopEntry); - if (notificationData && !exiting) - NotificationService.dismissNotification(notificationData); - } - } - } - - MenuItem { - text: I18n.tr("Dismiss") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (notificationData && !exiting) - NotificationService.dismissNotification(notificationData); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopupManager.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopupManager.qml deleted file mode 100644 index 02bfc0f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopupManager.qml +++ /dev/null @@ -1,239 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services - -QtObject { - id: manager - - property var modelData - property int topMargin: 0 - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real popupIconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real actionButtonHeight: compactMode ? 20 : 24 - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real popupSpacing: compactMode ? 0 : Theme.spacingXS - readonly property real collapsedContentHeight: Math.max(popupIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) - readonly property int baseNotificationHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing + popupSpacing - property var popupWindows: [] - property var destroyingWindows: new Set() - property var pendingDestroys: [] - property int destroyDelayMs: 100 - property Component popupComponent - - popupComponent: Component { - NotificationPopup { - onExitFinished: manager._onPopupExitFinished(this) - onPopupHeightChanged: manager._onPopupHeightChanged(this) - } - } - - property Connections notificationConnections - - notificationConnections: Connections { - function onVisibleNotificationsChanged() { - manager._sync(NotificationService.visibleNotifications); - } - - target: NotificationService - } - - property Timer sweeper - - property Timer destroyTimer: Timer { - interval: destroyDelayMs - running: false - repeat: false - onTriggered: manager._processDestroyQueue() - } - - function _processDestroyQueue() { - if (pendingDestroys.length === 0) - return; - const p = pendingDestroys.shift(); - if (p && p.destroy) { - try { - p.destroy(); - } catch (e) {} - } - if (pendingDestroys.length > 0) - destroyTimer.restart(); - } - - function _scheduleDestroy(p) { - if (!p) - return; - pendingDestroys.push(p); - if (!destroyTimer.running) - destroyTimer.restart(); - } - - sweeper: Timer { - interval: 500 - running: false - repeat: true - onTriggered: { - const toRemove = []; - for (const p of popupWindows) { - if (!p) { - toRemove.push(p); - continue; - } - const isZombie = p.status === Component.Null || (!p.visible && !p.exiting) || (!p.notificationData && !p._isDestroying) || (!p.hasValidData && !p._isDestroying); - if (isZombie) { - toRemove.push(p); - if (p.forceExit) { - p.forceExit(); - } else if (p.destroy) { - try { - p.destroy(); - } catch (e) {} - } - } - } - if (toRemove.length) { - popupWindows = popupWindows.filter(p => toRemove.indexOf(p) === -1); - _repositionAll(); - } - if (popupWindows.length === 0) - sweeper.stop(); - } - } - - function _hasWindowFor(w) { - return popupWindows.some(p => p && p.notificationData === w && !p._isDestroying && p.status !== Component.Null); - } - - function _isValidWindow(p) { - return p && p.status !== Component.Null && !p._isDestroying && p.hasValidData; - } - - function _isFocusedScreen() { - if (!SettingsData.notificationFocusedMonitor) - return true; - const focused = CompositorService.getFocusedScreen(); - return focused && manager.modelData && focused.name === manager.modelData.name; - } - - function _sync(newWrappers) { - for (const p of popupWindows.slice()) { - if (!_isValidWindow(p) || p.exiting) - continue; - if (p.notificationData && newWrappers.indexOf(p.notificationData) === -1) { - p.notificationData.removedByLimit = true; - p.notificationData.popup = false; - } - } - for (const w of newWrappers) { - if (w && !_hasWindowFor(w) && _isFocusedScreen()) - _insertAtTop(w); - } - } - - function _popupHeight(p) { - return (p.alignedHeight || p.implicitHeight || (baseNotificationHeight - popupSpacing)) + popupSpacing; - } - - function _insertAtTop(wrapper) { - if (!wrapper) - return; - const notificationId = wrapper?.notification ? wrapper.notification.id : ""; - const win = popupComponent.createObject(null, { - "notificationData": wrapper, - "notificationId": notificationId, - "screenY": topMargin, - "screen": manager.modelData - }); - if (!win) - return; - if (!win.hasValidData) { - win.destroy(); - return; - } - popupWindows.unshift(win); - _repositionAll(); - if (!sweeper.running) - sweeper.start(); - } - - function _repositionAll() { - const active = popupWindows.filter(p => _isValidWindow(p) && p.notificationData?.popup && !p.exiting); - - const pinnedSlots = []; - for (const p of active) { - if (!p.hovered) - continue; - pinnedSlots.push({ - y: p.screenY, - end: p.screenY + _popupHeight(p) - }); - } - pinnedSlots.sort((a, b) => a.y - b.y); - - let currentY = topMargin; - for (const win of active) { - if (win.hovered) - continue; - for (const slot of pinnedSlots) { - if (currentY >= slot.y - 1 && currentY < slot.end) - currentY = slot.end; - } - win.screenY = currentY; - currentY += _popupHeight(win); - } - } - - function _onPopupHeightChanged(p) { - if (!p || p.exiting || p._isDestroying) - return; - if (popupWindows.indexOf(p) === -1) - return; - _repositionAll(); - } - - function _onPopupExitFinished(p) { - if (!p) - return; - const windowId = p.toString(); - if (destroyingWindows.has(windowId)) - return; - destroyingWindows.add(windowId); - const i = popupWindows.indexOf(p); - if (i !== -1) { - popupWindows.splice(i, 1); - popupWindows = popupWindows.slice(); - } - if (NotificationService.releaseWrapper && p.notificationData) - NotificationService.releaseWrapper(p.notificationData); - _scheduleDestroy(p); - Qt.callLater(() => destroyingWindows.delete(windowId)); - _repositionAll(); - } - - function cleanupAllWindows() { - sweeper.stop(); - destroyTimer.stop(); - pendingDestroys = []; - for (const p of popupWindows.slice()) { - if (p) { - try { - if (p.forceExit) { - p.forceExit(); - } else if (p.destroy) { - p.destroy(); - } - } catch (e) {} - } - } - popupWindows = []; - destroyingWindows.clear(); - } - - onPopupWindowsChanged: { - if (popupWindows.length > 0 && !sweeper.running) { - sweeper.start(); - } else if (popupWindows.length === 0 && sweeper.running) { - sweeper.stop(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/AudioOutputOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/AudioOutputOSD.qml deleted file mode 100644 index 1bea1e5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/AudioOutputOSD.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - property string deviceName: "" - property string deviceIcon: "speaker" - - osdWidth: Math.min(Math.max(120, Theme.iconSize + textMetrics.width + Theme.spacingS * 4), Screen.width - Theme.spacingM * 2) - osdHeight: 40 + Theme.spacingS * 2 - autoHideInterval: 2500 - enableMouseInteraction: false - - TextMetrics { - id: textMetrics - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - font.family: Theme.fontFamily - text: root.deviceName - } - - Connections { - target: AudioService - - function onAudioOutputCycled(name, icon) { - if (!SettingsData.osdAudioOutputEnabled) - return; - root.deviceName = name; - root.deviceIcon = icon; - root.show(); - } - } - - content: Item { - property int gap: Theme.spacingS - - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 40 - - DankIcon { - id: iconItem - width: Theme.iconSize - height: Theme.iconSize - x: parent.gap - anchors.verticalCenter: parent.verticalCenter - name: root.deviceIcon - size: Theme.iconSize - color: Theme.primary - } - - StyledText { - id: textItem - x: parent.gap * 2 + Theme.iconSize - width: parent.width - Theme.iconSize - parent.gap * 3 - anchors.verticalCenter: parent.verticalCenter - text: root.deviceName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/BrightnessOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/BrightnessOSD.qml deleted file mode 100644 index 7f83578..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/BrightnessOSD.qml +++ /dev/null @@ -1,274 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - readonly property bool useVertical: isVerticalLayout - property int _displayBrightness: 0 - - function _syncBrightness() { - _displayBrightness = DisplayService.brightnessLevel; - } - - osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) - osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2) - autoHideInterval: 3000 - enableMouseInteraction: true - - Connections { - target: DisplayService - function onBrightnessChanged(showOsd) { - root._syncBrightness(); - if (showOsd && SettingsData.osdBrightnessEnabled) - root.show(); - } - } - - content: Loader { - anchors.fill: parent - sourceComponent: useVertical ? verticalContent : horizontalContent - } - - Component { - id: horizontalContent - - Item { - property int gap: Theme.spacingS - - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 40 - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - x: parent.gap - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") - return "brightness_medium"; - if (deviceInfo.name.includes("kbd")) - return "keyboard"; - return "lightbulb"; - } - size: Theme.iconSize - color: Theme.primary - } - } - - DankSlider { - id: brightnessSlider - - width: parent.width - Theme.iconSize - parent.gap * 3 - height: 40 - x: parent.gap * 2 + Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - minimum: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo) - return 1; - if (SessionData.getBrightnessExponential(deviceInfo.id)) - return 1; - return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; - } - maximum: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo) - return 100; - if (SessionData.getBrightnessExponential(deviceInfo.id)) - return 100; - return deviceInfo.displayMax || 100; - } - enabled: DisplayService.brightnessAvailable - showValue: true - unit: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo) - return "%"; - if (SessionData.getBrightnessExponential(deviceInfo.id)) - return "%"; - return deviceInfo.class === "ddc" ? "" : "%"; - } - thumbOutlineColor: Theme.surfaceContainer - alwaysShowValue: SettingsData.osdAlwaysShowValue - - onSliderValueChanged: newValue => { - if (!DisplayService.brightnessAvailable) - return; - DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true); - resetHideTimer(); - } - - onContainsMouseChanged: setChildHovered(containsMouse) - - Binding on value { - value: root._displayBrightness - when: !brightnessSlider.isDragging - } - } - } - } - - Component { - id: verticalContent - - Item { - anchors.fill: parent - property int gap: Theme.spacingS - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - anchors.horizontalCenter: parent.horizontalCenter - y: gap - - DankIcon { - anchors.centerIn: parent - name: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") - return "brightness_medium"; - if (deviceInfo.name.includes("kbd")) - return "keyboard"; - return "lightbulb"; - } - size: Theme.iconSize - color: Theme.primary - } - } - - Item { - id: vertSlider - width: 12 - height: parent.height - Theme.iconSize - gap * 3 - 24 - anchors.horizontalCenter: parent.horizontalCenter - y: gap * 2 + Theme.iconSize - - property bool dragging: false - property int value: 50 - - Binding on value { - value: root._displayBrightness - when: !vertSlider.dragging - } - - readonly property int minimum: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo) - return 1; - if (SessionData.getBrightnessExponential(deviceInfo.id)) - return 1; - return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; - } - - readonly property int maximum: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo) - return 100; - if (SessionData.getBrightnessExponential(deviceInfo.id)) - return 100; - return deviceInfo.displayMax || 100; - } - - Rectangle { - id: vertTrack - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.outline - radius: Theme.cornerRadius - } - - Rectangle { - id: vertFill - width: parent.width - height: { - const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum); - return ratio * parent.height; - } - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - radius: Theme.cornerRadius - } - - Rectangle { - id: vertHandle - width: 24 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum); - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Theme.surfaceContainer - } - - MouseArea { - id: vertSliderArea - anchors.fill: parent - anchors.margins: -12 - enabled: DisplayService.brightnessAvailable - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onContainsMouseChanged: setChildHovered(containsMouse) - - onPressed: mouse => { - vertSlider.dragging = true; - updateBrightness(mouse); - } - - onReleased: vertSlider.dragging = false - - onPositionChanged: mouse => { - if (pressed) - updateBrightness(mouse); - } - - onClicked: mouse => updateBrightness(mouse) - - function updateBrightness(mouse) { - if (!DisplayService.brightnessAvailable) - return; - const ratio = 1.0 - (mouse.y / height); - const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum)); - vertSlider.value = newValue; - DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true); - resetHideTimer(); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: gap - text: { - const deviceInfo = DisplayService.getCurrentDeviceInfo(); - const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false; - const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%"; - return vertSlider.value + unit; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - visible: SettingsData.osdAlwaysShowValue - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/CapsLockOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/CapsLockOSD.qml deleted file mode 100644 index b37a86b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/CapsLockOSD.qml +++ /dev/null @@ -1,37 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - osdWidth: Theme.iconSize + Theme.spacingS * 2 - osdHeight: Theme.iconSize + Theme.spacingS * 2 - autoHideInterval: 2000 - enableMouseInteraction: false - - property bool lastCapsLockState: false - - Connections { - target: DMSService - - function onCapsLockStateChanged() { - if (lastCapsLockState !== DMSService.capsLockState && SettingsData.osdCapsLockEnabled) { - root.show() - } - lastCapsLockState = DMSService.capsLockState - } - } - - Component.onCompleted: { - lastCapsLockState = DMSService.capsLockState - } - - content: DankIcon { - anchors.centerIn: parent - name: DMSService.capsLockState ? "shift_lock" : "shift_lock_off" - size: Theme.iconSize - color: Theme.primary - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/IdleInhibitorOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/IdleInhibitorOSD.qml deleted file mode 100644 index e08c216..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/IdleInhibitorOSD.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - osdWidth: Theme.iconSize + Theme.spacingS * 2 - osdHeight: Theme.iconSize + Theme.spacingS * 2 - autoHideInterval: 2000 - enableMouseInteraction: false - - Connections { - target: SessionService - function onInhibitorChanged() { - if (SettingsData.osdIdleInhibitorEnabled) { - root.show() - } - } - } - - content: DankIcon { - anchors.centerIn: parent - name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle" - size: Theme.iconSize - color: SessionService.idleInhibited ? Theme.primary : Theme.outline - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaPlaybackOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaPlaybackOSD.qml deleted file mode 100644 index 270a9d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaPlaybackOSD.qml +++ /dev/null @@ -1,319 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets -import Quickshell.Services.Mpris - -DankOSD { - id: root - - readonly property bool useVertical: isVerticalLayout - readonly property var player: MprisController.activePlayer - - osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(280, Screen.width - Theme.spacingM * 2) - osdHeight: useVertical ? (Theme.iconSize * 2) : (40 + Theme.spacingS * 2) - autoHideInterval: 3000 - enableMouseInteraction: true - - property string _displayIcon: "music_note" - - function updatePlaybackIcon() { - if (!player) { - _displayIcon = "music_note"; - iconDebounce.stop(); - return; - } - let icon = "music_note"; - switch (player.playbackState) { - case MprisPlaybackState.Playing: - icon = "pause"; - break; - case MprisPlaybackState.Paused: - case MprisPlaybackState.Stopped: - icon = "play_arrow"; - break; - } - if (icon === _displayIcon) - return; - iconDebounce.pendingIcon = icon; - iconDebounce.restart(); - } - - function togglePlaying() { - if (player?.canTogglePlaying) { - player.togglePlaying(); - } - } - - property bool _pendingShow: false - - Timer { - id: iconDebounce - interval: 150 - property string pendingIcon: "music_note" - onTriggered: root._displayIcon = pendingIcon - } - - Image { - id: artPreloader - source: TrackArtService._bgArtSource - visible: false - asynchronous: true - cache: true - } - - onPlayerChanged: { - if (!player) { - _pendingShow = false; - hide(); - } - } - - Connections { - target: TrackArtService - function onLoadingChanged() { - if (TrackArtService.loading || !root._pendingShow) - return; - if (!TrackArtService._bgArtSource || artPreloader.status === Image.Ready) { - root._pendingShow = false; - root.show(); - } - } - } - - Connections { - target: artPreloader - function onStatusChanged() { - if (!root._pendingShow || TrackArtService.loading) - return; - switch (artPreloader.status) { - case Image.Ready: - case Image.Error: - root._pendingShow = false; - root.show(); - break; - } - } - } - - Connections { - target: player - - function handleUpdate() { - if (!root.player?.trackTitle) - return; - if (!SettingsData.osdMediaPlaybackEnabled) - return; - - root.updatePlaybackIcon(); - TrackArtService.loadArtwork(player.trackArtUrl); - - if (!player.trackArtUrl || player.trackArtUrl === "") { - root.show(); - return; - } - if (TrackArtService.loading) { - root._pendingShow = true; - return; - } - if (!TrackArtService._bgArtSource || artPreloader.status === Image.Ready) { - root.show(); - return; - } - root._pendingShow = true; - } - - function onTrackArtUrlChanged() { - TrackArtService.loadArtwork(player.trackArtUrl); - } - function onIsPlayingChanged() { - handleUpdate(); - } - function onTrackChanged() { - if (!useVertical) - handleUpdate(); - } - } - - content: Loader { - anchors.fill: parent - sourceComponent: useVertical ? verticalContent : horizontalContent - } - - Component { - id: horizontalContent - - Item { - property int gap: Theme.spacingS - - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 40 - - MouseArea { - anchors.fill: parent - onClicked: root.hide() - } - - Item { - id: bgContainer - anchors.fill: parent - visible: TrackArtService._bgArtSource !== "" - - Image { - id: bgImage - anchors.centerIn: parent - width: Math.max(parent.width, parent.height) - height: width - source: TrackArtService._bgArtSource - fillMode: Image.PreserveAspectCrop - asynchronous: true - cache: true - visible: false - } - - Item { - id: blurredBg - anchors.fill: parent - visible: false - - MultiEffect { - anchors.centerIn: parent - width: bgImage.width - height: bgImage.height - source: bgImage - blurEnabled: true - blurMax: 64 - blur: 0.3 - saturation: -0.2 - brightness: -0.25 - } - } - - Rectangle { - id: bgMask - anchors.fill: parent - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - MultiEffect { - anchors.fill: parent - source: blurredBg - maskEnabled: true - maskSource: bgMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - opacity: 0.7 - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surface - opacity: 0.3 - } - } - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - x: parent.gap - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: root._displayIcon - size: Theme.iconSize - color: playPauseButton.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: playPauseButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - togglePlaying(); - root.hide(); - } - } - } - - Column { - x: parent.gap * 2 + Theme.iconSize - width: parent.width - Theme.iconSize - parent.gap * 3 - anchors.verticalCenter: parent.verticalCenter - spacing: 3 - - StyledText { - id: topText - width: parent.width - text: player ? `${player.trackTitle || I18n.tr("Unknown Title")}` : "" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - wrapMode: Text.NoWrap - elide: Text.ElideRight - } - - StyledText { - id: bottomText - width: parent.width - text: player ? ((player.trackArtist || I18n.tr("Unknown Artist")) + (player.trackAlbum ? ` • ${player.trackAlbum}` : "")) : "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Light - color: Theme.surfaceText - wrapMode: Text.NoWrap - elide: Text.ElideRight - } - } - } - } - - Component { - id: verticalContent - - Item { - property int gap: Theme.spacingS - - MouseArea { - anchors.fill: parent - onClicked: root.hide() - } - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - anchors.centerIn: parent - y: gap - - DankIcon { - anchors.centerIn: parent - name: root._displayIcon - size: Theme.iconSize - color: playPauseButtonVert.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: playPauseButtonVert - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - togglePlaying(); - root.hide(); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml deleted file mode 100644 index 147d81e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml +++ /dev/null @@ -1,264 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - readonly property bool useVertical: isVerticalLayout - readonly property var player: MprisController.activePlayer - readonly property bool volumeSupported: player?.volumeSupported ?? false - property bool _suppressNewPlayer: false - property int _displayVolume: 0 - - function _syncVolume() { - if (!player) - return; - _displayVolume = Math.min(100, Math.round(player.volume * 100)); - } - - onPlayerChanged: { - _suppressNewPlayer = true; - _suppressTimer.restart(); - _syncVolume(); - } - - Timer { - id: _suppressTimer - interval: 2000 - onTriggered: _suppressNewPlayer = false - } - - osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) - osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2) - autoHideInterval: 3000 - enableMouseInteraction: true - - function getVolumeIcon(volume) { - if (!player) - return "music_note"; - if (volume === 0) - return "music_off"; - return "music_note"; - } - - function toggleMute() { - if (!player) - return; - player.volume = player.volume > 0 ? 0 : 1; - } - - function setVolume(volumePercent) { - if (!player) - return; - player.volume = volumePercent / 100; - resetHideTimer(); - } - - Connections { - target: player - - function onVolumeChanged() { - root._syncVolume(); - if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer) - root.show(); - } - } - - content: Loader { - anchors.fill: parent - sourceComponent: useVertical ? verticalContent : horizontalContent - } - - Component { - id: horizontalContent - - Item { - property int gap: Theme.spacingS - - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 40 - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - x: parent.gap - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: getVolumeIcon(player?.volume ?? 0) - size: Theme.iconSize - color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: muteButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: toggleMute() - onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse) - } - } - - DankSlider { - id: volumeSlider - - width: parent.width - Theme.iconSize - parent.gap * 3 - height: 40 - x: parent.gap * 2 + Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - minimum: 0 - maximum: 100 - enabled: volumeSupported - showValue: true - unit: "%" - thumbOutlineColor: Theme.surfaceContainer - valueOverride: root._displayVolume - alwaysShowValue: SettingsData.osdAlwaysShowValue - - Component.onCompleted: { - root._syncVolume(); - value = root._displayVolume; - } - - onSliderValueChanged: newValue => setVolume(newValue) - - onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse) - - Binding on value { - value: root._displayVolume - when: !volumeSlider.pressed - } - } - } - } - - Component { - id: verticalContent - - Item { - anchors.fill: parent - property int gap: Theme.spacingS - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - anchors.horizontalCenter: parent.horizontalCenter - y: gap - - DankIcon { - anchors.centerIn: parent - name: getVolumeIcon(player?.volume ?? 0) - size: Theme.iconSize - color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: muteButtonVert - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: toggleMute() - onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse) - } - } - - Item { - id: vertSlider - width: 12 - height: parent.height - Theme.iconSize - gap * 3 - 24 - anchors.horizontalCenter: parent.horizontalCenter - y: gap * 2 + Theme.iconSize - - property bool dragging: false - property int value: root._displayVolume - - Rectangle { - id: vertTrack - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.outline - radius: Theme.cornerRadius - } - - Rectangle { - id: vertFill - width: parent.width - height: (vertSlider.value / 100) * parent.height - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - radius: Theme.cornerRadius - } - - Rectangle { - id: vertHandle - width: 24 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = vertSlider.value / 100; - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Theme.surfaceContainer - } - - MouseArea { - id: vertSliderArea - anchors.fill: parent - anchors.margins: -12 - enabled: volumeSupported - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse) - - onPressed: mouse => { - vertSlider.dragging = true; - updateVolume(mouse); - } - - onReleased: vertSlider.dragging = false - - onPositionChanged: mouse => { - if (pressed) - updateVolume(mouse); - } - - onClicked: mouse => updateVolume(mouse) - - function updateVolume(mouse) { - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(100, Math.round(ratio * 100))); - setVolume(volume); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: gap - text: vertSlider.value + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - visible: SettingsData.osdAlwaysShowValue - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MicMuteOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MicMuteOSD.qml deleted file mode 100644 index 71162ac..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MicMuteOSD.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - osdWidth: Theme.iconSize + Theme.spacingS * 2 - osdHeight: Theme.iconSize + Theme.spacingS * 2 - autoHideInterval: 2000 - enableMouseInteraction: false - - Connections { - target: AudioService - function onMicMuteChanged() { - if (SettingsData.osdMicMuteEnabled) { - root.show() - } - } - } - - content: DankIcon { - anchors.centerIn: parent - name: AudioService.source && AudioService.source.audio && AudioService.source.audio.muted ? "mic_off" : "mic" - size: Theme.iconSize - color: AudioService.source && AudioService.source.audio && AudioService.source.audio.muted ? Theme.error : Theme.primary - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/PowerProfileOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/PowerProfileOSD.qml deleted file mode 100644 index 11b008f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/PowerProfileOSD.qml +++ /dev/null @@ -1,43 +0,0 @@ -import QtQuick -import Quickshell.Services.UPower -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - property int currentProfile: 0 - property string profileIcon: "settings" - - osdWidth: Theme.iconSize + Theme.spacingS * 2 - osdHeight: Theme.iconSize + Theme.spacingS * 2 - autoHideInterval: 2000 - enableMouseInteraction: false - - Connections { - target: PowerProfileWatcher - - function onProfileChanged(profile) { - if (SettingsData.osdPowerProfileEnabled) { - root.currentProfile = profile; - root.profileIcon = Theme.getPowerProfileIcon(profile); - root.show(); - } - } - } - - Component.onCompleted: { - if (SettingsData.osdPowerProfileEnabled && typeof PowerProfileWatcher !== "undefined") { - root.currentProfile = PowerProfileWatcher.currentProfile; - root.profileIcon = Theme.getPowerProfileIcon(PowerProfileWatcher.currentProfile); - } - } - - content: DankIcon { - anchors.centerIn: parent - name: root.profileIcon - size: Theme.iconSize - color: Theme.primary - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/VolumeOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/VolumeOSD.qml deleted file mode 100644 index 89c07b7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/VolumeOSD.qml +++ /dev/null @@ -1,254 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankOSD { - id: root - - readonly property bool useVertical: isVerticalLayout - property int _displayVolume: 0 - - function _syncVolume() { - if (!AudioService.sink?.audio) - return; - _displayVolume = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); - } - - osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) - osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2) - autoHideInterval: 3000 - enableMouseInteraction: true - - Connections { - target: AudioService.sink?.audio ?? null - - function onVolumeChanged() { - root._syncVolume(); - if (SettingsData.osdVolumeEnabled) - root.show(); - } - - function onMutedChanged() { - if (SettingsData.osdVolumeEnabled) - root.show(); - } - } - - Connections { - target: AudioService - - function onSinkChanged() { - root._syncVolume(); - if (root.shouldBeVisible && SettingsData.osdVolumeEnabled) - root.show(); - } - } - - content: Loader { - anchors.fill: parent - sourceComponent: useVertical ? verticalContent : horizontalContent - } - - Component { - id: horizontalContent - - Item { - property int gap: Theme.spacingS - - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 40 - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - x: parent.gap - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up" - size: Theme.iconSize - color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: muteButton - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: AudioService.toggleMute() - onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse) - } - } - - DankSlider { - id: volumeSlider - - width: parent.width - Theme.iconSize - parent.gap * 3 - height: 40 - x: parent.gap * 2 + Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - minimum: 0 - maximum: AudioService.sinkMaxVolume - enabled: AudioService.sink?.audio ?? false - showValue: true - unit: "%" - thumbOutlineColor: Theme.surfaceContainer - valueOverride: root._displayVolume - alwaysShowValue: SettingsData.osdAlwaysShowValue - - Component.onCompleted: { - root._syncVolume(); - value = root._displayVolume; - } - - onSliderValueChanged: newValue => { - if (!AudioService.sink?.audio) - return; - SessionData.suppressOSDTemporarily(); - AudioService.sink.audio.volume = newValue / 100; - resetHideTimer(); - } - - onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse) - - Binding on value { - value: root._displayVolume - when: !volumeSlider.pressed - } - } - } - } - - Component { - id: verticalContent - - Item { - anchors.fill: parent - property int gap: Theme.spacingS - - Rectangle { - width: Theme.iconSize - height: Theme.iconSize - radius: Theme.iconSize / 2 - color: "transparent" - anchors.horizontalCenter: parent.horizontalCenter - y: gap - - DankIcon { - anchors.centerIn: parent - name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up" - size: Theme.iconSize - color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: muteButtonVert - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: AudioService.toggleMute() - onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse) - } - } - - Item { - id: vertSlider - width: 12 - height: parent.height - Theme.iconSize - gap * 3 - 24 - anchors.horizontalCenter: parent.horizontalCenter - y: gap * 2 + Theme.iconSize - - property bool dragging: false - property int value: root._displayVolume - - Rectangle { - id: vertTrack - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.outline - radius: Theme.cornerRadius - } - - Rectangle { - id: vertFill - width: parent.width - height: (vertSlider.value / AudioService.sinkMaxVolume) * parent.height - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - radius: Theme.cornerRadius - } - - Rectangle { - id: vertHandle - width: 24 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = vertSlider.value / AudioService.sinkMaxVolume; - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Theme.surfaceContainer - } - - MouseArea { - id: vertSliderArea - anchors.fill: parent - anchors.margins: -12 - enabled: AudioService.sink?.audio ?? false - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse) - - onPressed: mouse => { - vertSlider.dragging = true; - updateVolume(mouse); - } - - onReleased: vertSlider.dragging = false - - onPositionChanged: mouse => { - if (pressed) - updateVolume(mouse); - } - - onClicked: mouse => updateVolume(mouse) - - function updateVolume(mouse) { - if (!AudioService.sink?.audio) - return; - const maxVol = AudioService.sinkMaxVolume; - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol))); - SessionData.suppressOSDTemporarily(); - AudioService.sink.audio.volume = volume / 100; - resetHideTimer(); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: gap - text: vertSlider.value + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - visible: SettingsData.osdAlwaysShowValue - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/BasePill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/BasePill.qml deleted file mode 100644 index 7dea95a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/BasePill.qml +++ /dev/null @@ -1,195 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property var axis: null - property string section: "center" - property var popoutTarget: null - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property alias content: contentLoader.sourceComponent - property bool isVerticalOrientation: axis?.isVertical ?? false - property bool isFirst: false - property bool isLast: false - property real sectionSpacing: 0 - property bool enableBackgroundHover: true - property bool enableCursor: true - readonly property bool isMouseHovered: mouseArea.containsMouse - property bool isLeftBarEdge: false - property bool isRightBarEdge: false - property bool isTopBarEdge: false - property bool isBottomBarEdge: false - readonly property real dpr: parentScreen ? CompositorService.getScreenScale(parentScreen) : 1 - readonly property real horizontalPadding: (barConfig?.removeWidgetPadding ?? false) ? 0 : Theme.snap((barConfig?.widgetPadding ?? 12) * (widgetThickness / 30), dpr) - readonly property real visualWidth: Theme.snap(isVerticalOrientation ? widgetThickness : (contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0), dpr) - readonly property real visualHeight: Theme.snap(isVerticalOrientation ? (contentLoader.item ? (contentLoader.item.implicitHeight + horizontalPadding * 2) : 0) : widgetThickness, dpr) - readonly property alias visualContent: visualContent - readonly property real barEdgeExtension: 1000 - readonly property real gapExtension: sectionSpacing - readonly property real leftMargin: !isVerticalOrientation ? (isLeftBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0 - readonly property real rightMargin: !isVerticalOrientation ? (isRightBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0 - readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0 - readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0 - - signal clicked - signal rightClicked(real rootX, real rootY) - signal wheel(var wheelEvent) - - function triggerRipple(sourceItem, mouseX, mouseY) { - const pos = sourceItem.mapToItem(visualContent, mouseX, mouseY); - rippleLayer.trigger(pos.x, pos.y); - } - - width: isVerticalOrientation ? barThickness : visualWidth - height: isVerticalOrientation ? visualHeight : barThickness - - Item { - id: visualContent - width: root.visualWidth - height: root.visualHeight - anchors.centerIn: parent - - Rectangle { - id: outline - anchors.centerIn: parent - width: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.width + borderWidth * 2; - } - height: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.height + borderWidth * 2; - } - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: "transparent" - border.width: { - if (barConfig?.widgetOutlineEnabled ?? false) { - return barConfig?.widgetOutlineThickness ?? 1; - } - return 0; - } - border.color: { - if (!(barConfig?.widgetOutlineEnabled ?? false)) { - return "transparent"; - } - const colorOption = barConfig?.widgetOutlineColor || "primary"; - const opacity = barConfig?.widgetOutlineOpacity ?? 1.0; - switch (colorOption) { - case "surfaceText": - return Theme.withAlpha(Theme.surfaceText, opacity); - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - default: - return Theme.withAlpha(Theme.primary, opacity); - } - } - } - - Rectangle { - id: background - anchors.fill: parent - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: { - if (barConfig?.noBackground ?? false) { - return "transparent"; - } - - const rawTransparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0; - const isHovered = root.enableBackgroundHover && (mouseArea.containsMouse || (root.isHovered || false)); - const transparency = isHovered ? Math.max(0.3, rawTransparency) : rawTransparency; - const baseColor = isHovered ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.widgetBaseBackgroundColor; - - if (Theme.widgetBackgroundHasAlpha) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency); - } - return Theme.withAlpha(baseColor, transparency); - } - } - - DankRipple { - id: rippleLayer - rippleColor: Theme.surfaceText - cornerRadius: background.radius - } - - Loader { - id: contentLoader - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - } - } - - MouseArea { - id: mouseArea - z: -1 - x: -root.leftMargin - y: -root.topMargin - width: root.width + root.leftMargin + root.rightMargin - height: root.height + root.topMargin + root.bottomMargin - hoverEnabled: true - cursorShape: root.enableCursor ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: function (mouse) { - if (mouse.button === Qt.RightButton) { - const rPos = mouseArea.mapToItem(root, mouse.x, mouse.y); - root.rightClicked(rPos.x, rPos.y); - return; - } - const ripplePos = mouseArea.mapToItem(visualContent, mouse.x, mouse.y); - rippleLayer.trigger(ripplePos.x, ripplePos.y); - if (popoutTarget) { - // Ensure bar context is set first if supported - if (popoutTarget.setBarContext) { - const pos = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const bottomGap = root.barConfig ? (root.barConfig.bottomGap !== undefined ? root.barConfig.bottomGap : 0) : 0; - popoutTarget.setBarContext(pos, bottomGap); - } - - if (popoutTarget.setTriggerPosition) { - const globalPos = root.visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig); - popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig); - } - } - root.clicked(); - } - onWheel: function (wheelEvent) { - wheelEvent.accepted = false; - root.wheel(wheelEvent); - } - } - - property bool _blurRegistered: false - readonly property bool _shouldBlur: BlurService.enabled && blurBarWindow && blurBarWindow.registerBlurWidget && !(barConfig?.noBackground ?? false) && root.visible && root.width > 0 - - on_ShouldBlurChanged: _updateBlurRegistration() - - function _updateBlurRegistration() { - if (_shouldBlur && !_blurRegistered) { - blurBarWindow.registerBlurWidget(visualContent); - _blurRegistered = true; - } else if (!_shouldBlur && _blurRegistered) { - if (blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualContent); - _blurRegistered = false; - } - } - - Component.onCompleted: _updateBlurRegistration() - Component.onDestruction: { - if (_blurRegistered && blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualContent); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ColorSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ColorSetting.qml deleted file mode 100644 index 5ef3190..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ColorSetting.qml +++ /dev/null @@ -1,104 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - property color defaultValue: Theme.primary - property color value: defaultValue - - width: parent.width - spacing: Theme.spacingS - - property bool isInitialized: false - - function loadValue() { - const settings = findSettings(); - if (settings && settings.pluginService) { - const loadedValue = settings.loadValue(settingKey, defaultValue); - value = loadedValue; - isInitialized = true; - } - } - - Component.onCompleted: { - Qt.callLater(loadValue); - } - - onValueChanged: { - if (!isInitialized) - return; - const settings = findSettings(); - if (settings) { - settings.saveValue(settingKey, value); - } - } - - function findSettings() { - let item = parent; - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item; - } - item = item.parent; - } - return null; - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - width: 100 - height: 36 - radius: Theme.cornerRadius - color: root.value - border.color: Theme.outlineStrong - border.width: 2 - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (PopoutService && PopoutService.colorPickerModal) { - PopoutService.colorPickerModal.selectedColor = root.value; - PopoutService.colorPickerModal.pickerTitle = root.label; - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - root.value = selectedColor; - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - - StyledText { - text: root.value.toString() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginComponent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginComponent.qml deleted file mode 100644 index 1fd7ab8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginComponent.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var pluginService: null - property string pluginId: "" - property string instanceId: "" - property var instanceData: null - - property real widgetWidth: 200 - property real widgetHeight: 200 - property real minWidth: 100 - property real minHeight: 100 - - readonly property bool isInstance: instanceId !== "" && instanceData !== null - readonly property var instanceConfig: instanceData?.config ?? {} - - property var pluginData: isInstance ? instanceConfig : _globalPluginData - property var _globalPluginData: ({}) - - Component.onCompleted: loadPluginData() - onPluginServiceChanged: loadPluginData() - onPluginIdChanged: loadPluginData() - onInstanceDataChanged: { - if (isInstance) - Qt.callLater(() => { - pluginData = instanceConfig; - }); - } - - Connections { - target: pluginService - enabled: pluginService !== null - - function onPluginDataChanged(changedPluginId) { - if (changedPluginId !== pluginId) - return; - loadPluginData(); - } - } - - function loadPluginData() { - if (!pluginService || !pluginId) { - _globalPluginData = {}; - return; - } - if (isInstance) { - pluginData = instanceConfig; - return; - } - _globalPluginData = SettingsData.getPluginSettingsForPlugin(pluginId); - } - - function getData(key, defaultValue) { - if (!pluginService || !pluginId) - return defaultValue; - return pluginService.loadPluginData(pluginId, key, defaultValue); - } - - function setData(key, value) { - if (!pluginService || !pluginId) - return; - pluginService.savePluginData(pluginId, key, value); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginWrapper.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginWrapper.qml deleted file mode 100644 index c7a5c76..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginWrapper.qml +++ /dev/null @@ -1,758 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - required property string pluginId - required property var screen - - property var builtinComponent: null - property var pluginService: null - property string instanceId: "" - property var instanceData: null - property bool widgetEnabled: true - - readonly property bool isBuiltin: pluginId === "desktopClock" || pluginId === "systemMonitor" - readonly property var activeComponent: isBuiltin ? builtinComponent : PluginService.pluginDesktopComponents[pluginId] ?? null - - readonly property bool showOnOverlay: instanceData?.config?.showOnOverlay ?? false - readonly property bool showOnOverview: instanceData?.config?.showOnOverview ?? false - readonly property bool showOnOverviewOnly: instanceData?.config?.showOnOverviewOnly ?? false - readonly property bool overviewActive: CompositorService.isNiri && NiriService.inOverview - readonly property bool clickThrough: instanceData?.config?.clickThrough ?? false - readonly property bool syncPositionAcrossScreens: instanceData?.config?.syncPositionAcrossScreens ?? false - - Connections { - target: PluginService - enabled: !root.isBuiltin - - function onPluginLoaded(loadedPluginId) { - if (loadedPluginId === root.pluginId) - contentLoader.reloadComponent(); - } - - function onPluginUnloaded(unloadedPluginId) { - if (unloadedPluginId === root.pluginId) - contentLoader.reloadComponent(); - } - } - - readonly property string settingsKey: instanceId ? instanceId : pluginId - readonly property bool isInstance: instanceId !== "" && instanceData !== null - readonly property bool usePluginService: pluginService !== null && !isInstance - - QtObject { - id: instanceScopedPluginService - - readonly property var availablePlugins: PluginService.availablePlugins - readonly property var loadedPlugins: PluginService.loadedPlugins - readonly property var pluginDesktopComponents: PluginService.pluginDesktopComponents - - signal pluginDataChanged(string pluginId) - signal pluginLoaded(string pluginId) - signal pluginUnloaded(string pluginId) - - function loadPluginData(pluginId, key, defaultValue) { - const cfg = root.instanceData?.config; - if (cfg && key in cfg) - return cfg[key]; - return SettingsData.getPluginSetting(pluginId, key, defaultValue); - } - - function savePluginData(pluginId, key, value) { - if (!root.instanceId) - return false; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, updates); - Qt.callLater(() => pluginDataChanged(pluginId)); - return true; - } - - function getPluginVariants(pluginId) { - return PluginService.getPluginVariants(pluginId); - } - - function isPluginLoaded(pluginId) { - return PluginService.isPluginLoaded(pluginId); - } - } - readonly property string screenKey: SettingsData.getScreenDisplayName(screen) - readonly property string positionKey: syncPositionAcrossScreens ? "_synced" : screenKey - - readonly property int screenWidth: screen?.width ?? 1920 - readonly property int screenHeight: screen?.height ?? 1080 - - readonly property bool useGhostPreview: !CompositorService.isNiri - - property real previewX: widgetX - property real previewY: widgetY - property real previewWidth: widgetWidth - property real previewHeight: widgetHeight - - readonly property bool hasSavedPosition: { - if (isInstance) - return instanceData?.positions?.[positionKey]?.x !== undefined; - if (usePluginService) - return pluginService.loadPluginData(pluginId, "desktopX_" + positionKey, null) !== null; - return SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "x", null) !== null; - } - - readonly property bool hasSavedSize: { - if (isInstance) - return instanceData?.positions?.[positionKey]?.width !== undefined; - if (usePluginService) - return pluginService.loadPluginData(pluginId, "desktopWidth_" + positionKey, null) !== null; - return SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "width", null) !== null; - } - - property real savedX: { - if (isInstance) { - const val = instanceData?.positions?.[positionKey]?.x; - if (val === undefined) - return screenWidth / 2 - savedWidth / 2; - return syncPositionAcrossScreens ? val * screenWidth : val; - } - if (usePluginService) { - const val = pluginService.loadPluginData(pluginId, "desktopX_" + positionKey, null); - if (val === null) - return screenWidth / 2 - savedWidth / 2; - return syncPositionAcrossScreens ? val * screenWidth : val; - } - const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "x", null); - if (val === null) - return screenWidth / 2 - savedWidth / 2; - return syncPositionAcrossScreens ? val * screenWidth : val; - } - property real savedY: { - if (isInstance) { - const val = instanceData?.positions?.[positionKey]?.y; - if (val === undefined) - return screenHeight / 2 - savedHeight / 2; - return syncPositionAcrossScreens ? val * screenHeight : val; - } - if (usePluginService) { - const val = pluginService.loadPluginData(pluginId, "desktopY_" + positionKey, null); - if (val === null) - return screenHeight / 2 - savedHeight / 2; - return syncPositionAcrossScreens ? val * screenHeight : val; - } - const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "y", null); - if (val === null) - return screenHeight / 2 - savedHeight / 2; - return syncPositionAcrossScreens ? val * screenHeight : val; - } - property real savedWidth: { - if (isInstance) { - const val = instanceData?.positions?.[positionKey]?.width; - if (val === undefined) - return 280; - return val; - } - if (usePluginService) { - const val = pluginService.loadPluginData(pluginId, "desktopWidth_" + positionKey, null); - if (val === null) - return 200; - return val; - } - const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "width", null); - if (val === null) - return 280; - return val; - } - property real savedHeight: { - if (isInstance) { - const val = instanceData?.positions?.[positionKey]?.height; - if (val === undefined) - return forceSquare ? savedWidth : 180; - return forceSquare ? savedWidth : val; - } - if (usePluginService) { - const val = pluginService.loadPluginData(pluginId, "desktopHeight_" + positionKey, null); - if (val === null) - return forceSquare ? savedWidth : 200; - return forceSquare ? savedWidth : val; - } - const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "height", null); - if (val === null) - return forceSquare ? savedWidth : 180; - return forceSquare ? savedWidth : val; - } - - property real dragOverrideX: -1 - property real dragOverrideY: -1 - property real dragOverrideW: -1 - property real dragOverrideH: -1 - - readonly property real effectiveX: dragOverrideX >= 0 ? dragOverrideX : savedX - readonly property real effectiveY: dragOverrideY >= 0 ? dragOverrideY : savedY - readonly property real effectiveW: dragOverrideW >= 0 ? dragOverrideW : savedWidth - readonly property real effectiveH: dragOverrideH >= 0 ? dragOverrideH : savedHeight - - readonly property real widgetX: Math.max(0, Math.min(effectiveX, screenWidth - widgetWidth)) - readonly property real widgetY: Math.max(0, Math.min(effectiveY, screenHeight - widgetHeight)) - readonly property real widgetWidth: Math.max(minWidth, Math.min(effectiveW, screenWidth)) - readonly property real widgetHeight: Math.max(minHeight, Math.min(effectiveH, screenHeight)) - - function clearDragOverrides() { - dragOverrideX = -1; - dragOverrideY = -1; - dragOverrideW = -1; - dragOverrideH = -1; - } - - property real minWidth: contentLoader.item?.minWidth ?? 100 - property real minHeight: contentLoader.item?.minHeight ?? 100 - property bool forceSquare: contentLoader.item?.forceSquare ?? false - property bool isInteracting: dragArea.pressed || resizeArea.pressed - - property var _gridSettingsTrigger: SettingsData.desktopWidgetGridSettings - readonly property int gridSize: { - void _gridSettingsTrigger; - return SettingsData.getDesktopWidgetGridSetting(screenKey, "size", 40); - } - readonly property bool gridEnabled: { - void _gridSettingsTrigger; - return SettingsData.getDesktopWidgetGridSetting(screenKey, "enabled", false); - } - - function snapToGrid(value) { - return Math.round(value / gridSize) * gridSize; - } - - function savePosition(finalX, finalY) { - const xVal = syncPositionAcrossScreens ? finalX / screenWidth : finalX; - const yVal = syncPositionAcrossScreens ? finalY / screenHeight : finalY; - if (isInstance && instanceData) { - SettingsData.updateDesktopWidgetInstancePosition(instanceId, positionKey, { - x: xVal, - y: yVal - }); - return; - } - if (usePluginService) { - pluginService.savePluginData(pluginId, "desktopX_" + positionKey, xVal); - pluginService.savePluginData(pluginId, "desktopY_" + positionKey, yVal); - return; - } - SettingsData.updateDesktopWidgetPosition(pluginId, positionKey, { - x: xVal, - y: yVal - }); - } - - function saveSize(finalW, finalH) { - const sizeVal = forceSquare ? Math.max(finalW, finalH) : finalW; - const heightVal = forceSquare ? sizeVal : finalH; - if (isInstance && instanceData) { - SettingsData.updateDesktopWidgetInstancePosition(instanceId, positionKey, { - width: sizeVal, - height: heightVal - }); - return; - } - if (usePluginService) { - pluginService.savePluginData(pluginId, "desktopWidth_" + positionKey, sizeVal); - pluginService.savePluginData(pluginId, "desktopHeight_" + positionKey, heightVal); - return; - } - SettingsData.updateDesktopWidgetPosition(pluginId, positionKey, { - width: sizeVal, - height: heightVal - }); - } - - PanelWindow { - id: widgetWindow - screen: root.screen - visible: { - if (!root.widgetEnabled || root.activeComponent === null) - return false; - if (root.showOnOverviewOnly) - return root.overviewActive; - return true; - } - color: "transparent" - - Region { - id: emptyMask - } - - mask: root.clickThrough ? emptyMask : null - - WlrLayershell.namespace: "dms:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "") - WlrLayershell.layer: { - if (root.isInteracting && !CompositorService.useHyprlandFocusGrab) - return WlrLayer.Overlay; - if (root.showOnOverlay) - return WlrLayer.Overlay; - if (root.overviewActive && (root.showOnOverview || root.showOnOverviewOnly)) - return WlrLayer.Overlay; - return WlrLayer.Bottom; - } - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: { - if (!root.isInteracting) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - HyprlandFocusGrab { - active: CompositorService.isHyprland && root.isInteracting - windows: [widgetWindow] - } - - Item { - anchors.fill: parent - focus: root.isInteracting - - Keys.onPressed: event => { - if (!root.isInteracting) - return; - switch (event.key) { - case Qt.Key_G: - SettingsData.setDesktopWidgetGridSetting(root.screenKey, "enabled", !root.gridEnabled); - event.accepted = true; - break; - case Qt.Key_Z: - SettingsData.setDesktopWidgetGridSetting(root.screenKey, "size", Math.max(10, root.gridSize - 10)); - event.accepted = true; - break; - case Qt.Key_X: - SettingsData.setDesktopWidgetGridSetting(root.screenKey, "size", Math.min(200, root.gridSize + 10)); - event.accepted = true; - break; - } - } - } - - anchors { - left: true - top: true - } - - WlrLayershell.margins { - left: root.widgetX - top: root.widgetY - } - - implicitWidth: root.widgetWidth - implicitHeight: root.widgetHeight - - Loader { - id: contentLoader - anchors.fill: parent - active: root.widgetEnabled && root.activeComponent !== null - sourceComponent: root.activeComponent - - function reloadComponent() { - active = false; - active = true; - } - - function updateInstanceData() { - if (!item || item.instanceData === undefined) - return; - item.instanceData = root.instanceData; - } - - Connections { - target: root - enabled: contentLoader.item !== null - - function onInstanceDataChanged() { - contentLoader.updateInstanceData(); - } - } - - onLoaded: { - if (!item) - return; - - if (item.pluginService !== undefined) { - item.pluginService = root.isInstance ? instanceScopedPluginService : root.pluginService; - } - if (item.pluginId !== undefined) - item.pluginId = root.pluginId; - if (item.instanceId !== undefined) - item.instanceId = root.instanceId; - if (item.instanceData !== undefined) - item.instanceData = root.instanceData; - if (!root.hasSavedSize) { - const defW = item.defaultWidth ?? item.widgetWidth ?? 280; - const defH = item.defaultHeight ?? item.widgetHeight ?? 180; - const finalW = Math.max(root.minWidth, Math.min(defW, root.screenWidth)); - const finalH = Math.max(root.minHeight, Math.min(defH, root.screenHeight)); - root.saveSize(finalW, finalH); - } - if (!root.hasSavedPosition) { - const finalX = Math.max(0, Math.min(root.screenWidth / 2 - root.widgetWidth / 2, root.screenWidth - root.widgetWidth)); - const finalY = Math.max(0, Math.min(root.screenHeight / 2 - root.widgetHeight / 2, root.screenHeight - root.widgetHeight)); - root.savePosition(finalX, finalY); - } - if (item.widgetWidth !== undefined) - item.widgetWidth = Qt.binding(() => contentLoader.width); - if (item.widgetHeight !== undefined) - item.widgetHeight = Qt.binding(() => contentLoader.height); - } - } - - Rectangle { - id: interactionBorder - anchors.fill: parent - color: "transparent" - border.color: Theme.primary - border.width: 2 - radius: Theme.cornerRadius - visible: root.isInteracting && !root.useGhostPreview - opacity: 0.8 - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - width: 48 - height: 48 - topLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - color: Theme.primary - opacity: resizeArea.pressed ? 1 : 0.6 - } - } - - MouseArea { - id: dragArea - anchors.fill: parent - acceptedButtons: Qt.RightButton - enabled: !root.clickThrough - cursorShape: pressed ? Qt.ClosedHandCursor : Qt.ArrowCursor - - property point startPos - property real startX - property real startY - - onPressed: mouse => { - startPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y); - startX = root.widgetX; - startY = root.widgetY; - root.previewX = root.widgetX; - root.previewY = root.widgetY; - root.dragOverrideX = root.widgetX; - root.dragOverrideY = root.widgetY; - } - - onPositionChanged: mouse => { - if (!pressed) - return; - const currentPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y); - let newX = Math.max(0, Math.min(startX + currentPos.x - startPos.x, root.screenWidth - root.widgetWidth)); - let newY = Math.max(0, Math.min(startY + currentPos.y - startPos.y, root.screenHeight - root.widgetHeight)); - if (root.gridEnabled) { - newX = Math.max(0, Math.min(root.snapToGrid(newX), root.screenWidth - root.widgetWidth)); - newY = Math.max(0, Math.min(root.snapToGrid(newY), root.screenHeight - root.widgetHeight)); - } - if (root.useGhostPreview) { - root.previewX = newX; - root.previewY = newY; - return; - } - root.dragOverrideX = newX; - root.dragOverrideY = newY; - } - - onReleased: { - const finalX = root.useGhostPreview ? root.previewX : root.dragOverrideX; - const finalY = root.useGhostPreview ? root.previewY : root.dragOverrideY; - root.savePosition(finalX, finalY); - root.clearDragOverrides(); - } - } - - MouseArea { - id: resizeArea - width: 48 - height: 48 - anchors.right: parent.right - anchors.bottom: parent.bottom - acceptedButtons: Qt.RightButton - enabled: !root.clickThrough - cursorShape: pressed ? Qt.SizeFDiagCursor : Qt.ArrowCursor - - property point startPos - property real startWidth - property real startHeight - - onPressed: mouse => { - startPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y); - startWidth = root.widgetWidth; - startHeight = root.widgetHeight; - root.previewWidth = root.widgetWidth; - root.previewHeight = root.widgetHeight; - root.dragOverrideW = root.widgetWidth; - root.dragOverrideH = root.widgetHeight; - } - - onPositionChanged: mouse => { - if (!pressed) - return; - const currentPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y); - let newW = Math.max(root.minWidth, Math.min(startWidth + currentPos.x - startPos.x, root.screenWidth - root.widgetX)); - let newH = Math.max(root.minHeight, Math.min(startHeight + currentPos.y - startPos.y, root.screenHeight - root.widgetY)); - if (root.gridEnabled) { - newW = Math.max(root.minWidth, root.snapToGrid(newW)); - newH = Math.max(root.minHeight, root.snapToGrid(newH)); - } - if (root.forceSquare) { - const size = Math.max(newW, newH); - newW = Math.min(size, root.screenWidth - root.widgetX); - newH = Math.min(size, root.screenHeight - root.widgetY); - } - if (root.useGhostPreview) { - root.previewWidth = newW; - root.previewHeight = newH; - return; - } - root.dragOverrideW = newW; - root.dragOverrideH = newH; - } - - onReleased: { - const finalW = root.useGhostPreview ? root.previewWidth : root.dragOverrideW; - const finalH = root.useGhostPreview ? root.previewHeight : root.dragOverrideH; - root.saveSize(finalW, finalH); - root.clearDragOverrides(); - } - } - } - - Loader { - active: root.isInteracting && root.useGhostPreview - - sourceComponent: PanelWindow { - id: ghostPreviewWindow - screen: root.screen - color: "transparent" - - anchors { - left: true - right: true - top: true - bottom: true - } - - mask: Region {} - - WlrLayershell.namespace: "dms:desktop-widget-preview" - WlrLayershell.layer: WlrLayer.Bottom - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - Item { - id: gridOverlay - anchors.fill: parent - visible: root.gridEnabled - opacity: 0.3 - - Repeater { - model: Math.ceil(root.screenWidth / root.gridSize) - - Rectangle { - required property int index - x: index * root.gridSize - y: 0 - width: 1 - height: root.screenHeight - color: Theme.primary - } - } - - Repeater { - model: Math.ceil(root.screenHeight / root.gridSize) - - Rectangle { - required property int index - x: 0 - y: index * root.gridSize - width: root.screenWidth - height: 1 - color: Theme.primary - } - } - } - - Rectangle { - x: root.previewX - y: root.previewY - width: root.previewWidth - height: root.previewHeight - color: "transparent" - border.color: Theme.primary - border.width: 2 - radius: Theme.cornerRadius - - Rectangle { - width: 48 - height: 48 - anchors { - right: parent.right - bottom: parent.bottom - } - topLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - color: Theme.primary - opacity: resizeArea.pressed ? 1 : 0.6 - } - } - } - } - - Loader { - active: root.isInteracting && root.gridEnabled && !root.useGhostPreview - - sourceComponent: PanelWindow { - screen: root.screen - color: "transparent" - - anchors { - left: true - right: true - top: true - bottom: true - } - - mask: Region {} - - WlrLayershell.namespace: "dms:desktop-widget-grid" - WlrLayershell.layer: root.overviewActive && (root.showOnOverview || root.showOnOverviewOnly) ? WlrLayer.Overlay : WlrLayer.Background - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - Item { - anchors.fill: parent - opacity: 0.3 - - Repeater { - model: Math.ceil(root.screenWidth / root.gridSize) - - Rectangle { - required property int index - x: index * root.gridSize - y: 0 - width: 1 - height: root.screenHeight - color: Theme.primary - } - } - - Repeater { - model: Math.ceil(root.screenHeight / root.gridSize) - - Rectangle { - required property int index - x: 0 - y: index * root.gridSize - width: root.screenWidth - height: 1 - color: Theme.primary - } - } - } - } - } - - Loader { - active: root.isInteracting - - sourceComponent: PanelWindow { - id: helperWindow - screen: root.screen - color: "transparent" - - WlrLayershell.namespace: "dms:desktop-widget-helper" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - bottom: true - left: true - right: true - } - - implicitHeight: 60 - - Rectangle { - id: helperContent - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingL - width: helperRow.implicitWidth + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - color: Theme.surface - - Row { - id: helperRow - anchors.centerIn: parent - spacing: Theme.spacingM - height: parent.height - - DankIcon { - name: "grid_on" - size: 16 - color: root.gridEnabled ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Text { - text: root.gridEnabled ? I18n.tr("Grid: ON", "Widget grid snap status") : I18n.tr("Grid: OFF", "Widget grid snap status") - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.fontFamily - color: root.gridEnabled ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - width: 1 - height: 16 - color: Theme.outline - anchors.verticalCenter: parent.verticalCenter - } - - Text { - text: root.gridSize + "px" - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.fontFamily - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - width: 1 - height: 16 - color: Theme.outline - anchors.verticalCenter: parent.verticalCenter - } - - Text { - text: I18n.tr("G: grid • Z/X: size", "Widget grid keyboard hints") - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.fontFamily - font.italic: true - color: Theme.surfaceText - opacity: 0.7 - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSetting.qml deleted file mode 100644 index 5f636f5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSetting.qml +++ /dev/null @@ -1,132 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - property var defaultValue: [] - property var items: defaultValue - property Component delegate: null - - width: parent.width - spacing: Theme.spacingM - - Component.onCompleted: { - const settings = findSettings() - if (settings) { - items = settings.loadValue(settingKey, defaultValue) - } - } - - onItemsChanged: { - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, items) - } - } - - function findSettings() { - let item = parent - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item - } - item = item.parent - } - return null - } - - function addItem(item) { - items = items.concat([item]) - } - - function removeItem(index) { - const newItems = items.slice() - newItems.splice(index, 1) - items = newItems - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.items - delegate: root.delegate ? root.delegate : defaultDelegate - } - - StyledText { - text: I18n.tr("No items added yet") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: root.items.length === 0 - } - } - - Component { - id: defaultDelegate - StyledRect { - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: modelData - color: Theme.surfaceText - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 60 - height: 28 - color: removeArea.containsMouse ? Theme.errorHover : Theme.error - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Remove") - color: Theme.errorText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - } - - MouseArea { - id: removeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.removeItem(index) - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSettingWithInput.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSettingWithInput.qml deleted file mode 100644 index 8da4fb6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSettingWithInput.qml +++ /dev/null @@ -1,256 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - property var fields: [] - property var defaultValue: [] - property var items: defaultValue - - width: parent.width - spacing: Theme.spacingM - - property bool isLoading: false - - Component.onCompleted: { - loadValue() - } - - function loadValue() { - const settings = findSettings() - if (settings) { - isLoading = true - items = settings.loadValue(settingKey, defaultValue) - isLoading = false - } - } - - onItemsChanged: { - if (isLoading) { - return - } - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, items) - } - } - - function findSettings() { - let item = parent - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item - } - item = item.parent - } - return null - } - - function addItem(item) { - items = items.concat([item]) - } - - function removeItem(index) { - const newItems = items.slice() - newItems.splice(index, 1) - items = newItems - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - - Flow { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.fields - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - width: modelData.width || 200 - } - } - } - - Flow { - id: inputRow - width: parent.width - spacing: Theme.spacingS - - property var inputFields: [] - - Repeater { - id: inputRepeater - model: root.fields - - DankTextField { - width: modelData.width || 200 - placeholderText: modelData.placeholder || "" - - Component.onCompleted: { - inputRow.inputFields.push(this) - } - - Keys.onReturnPressed: { - addButton.clicked() - } - } - } - - DankButton { - id: addButton - width: 50 - height: 36 - text: I18n.tr("Add") - - onClicked: { - let newItem = {} - let hasValue = false - - for (let i = 0; i < root.fields.length; i++) { - const field = root.fields[i] - const input = inputRow.inputFields[i] - const value = input.text.trim() - - if (value !== "") { - hasValue = true - } - - if (field.required && value === "") { - return - } - - newItem[field.id] = value || (field.default || "") - } - - if (hasValue) { - root.addItem(newItem) - for (let i = 0; i < inputRow.inputFields.length; i++) { - inputRow.inputFields[i].text = "" - } - if (inputRow.inputFields.length > 0) { - inputRow.inputFields[0].forceActiveFocus() - } - } - } - } - } - - StyledText { - text: I18n.tr("Current Items") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - visible: root.items.length > 0 - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.items - - StyledRect { - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - required property int index - required property var modelData - - Row { - id: itemRow - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - property var itemData: parent.modelData - - Repeater { - model: root.fields - - StyledText { - required property int index - required property var modelData - - text: { - const field = modelData - const item = itemRow.itemData - if (!field || !field.id || !item) { - return "" - } - const value = item[field.id] - return value || "" - } - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - width: modelData ? (modelData.width || 200) : 200 - elide: Text.ElideRight - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 60 - height: 28 - color: removeArea.containsMouse ? Theme.errorHover : Theme.error - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Remove") - color: Theme.onError - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - } - - MouseArea { - id: removeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.removeItem(index) - } - } - } - } - } - - StyledText { - text: I18n.tr("No items added yet") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: root.items.length === 0 - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginComponent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginComponent.qml deleted file mode 100644 index 85dd32d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginComponent.qml +++ /dev/null @@ -1,333 +0,0 @@ -import QtQuick -import Quickshell.Io -import qs.Common - -Item { - id: root - - property string layerNamespacePlugin: "plugin" - - property var axis: null - property string section: "center" - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property string pluginId: "" - property var pluginService: null - - property string visibilityCommand: "" - property int visibilityInterval: 0 - property bool conditionVisible: true - property bool _visibilityOverride: false - property bool _visibilityOverrideValue: true - - readonly property bool effectiveVisible: { - if (_visibilityOverride) - return _visibilityOverrideValue; - if (!visibilityCommand) - return true; - return conditionVisible; - } - - property Component horizontalBarPill: null - property Component verticalBarPill: null - property Component popoutContent: null - property real popoutWidth: 400 - property real popoutHeight: 0 - property var pillClickAction: null - property var pillRightClickAction: null - - property Component controlCenterWidget: null - property string ccWidgetIcon: "" - property string ccWidgetPrimaryText: "" - property string ccWidgetSecondaryText: "" - property bool ccWidgetIsActive: false - property bool ccWidgetIsToggle: true - property Component ccDetailContent: null - property real ccDetailHeight: 250 - - signal ccWidgetToggled - signal ccWidgetExpanded - - property var pluginData: ({}) - property var variants: [] - - readonly property bool isVertical: axis?.isVertical ?? false - readonly property bool hasHorizontalPill: horizontalBarPill !== null - readonly property bool hasVerticalPill: verticalBarPill !== null - readonly property bool hasPopout: popoutContent !== null - - readonly property int iconSize: Theme.barIconSize(barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - readonly property int iconSizeLarge: Theme.barIconSize(barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - - Component.onCompleted: { - loadPluginData(); - if (visibilityCommand) - Qt.callLater(checkVisibility); - } - - onPluginServiceChanged: { - loadPluginData(); - } - - onPluginIdChanged: { - loadPluginData(); - } - - Connections { - target: pluginService - function onPluginDataChanged(changedPluginId) { - if (changedPluginId === pluginId) { - loadPluginData(); - } - } - } - - function loadPluginData() { - if (!pluginService || !pluginId) { - pluginData = {}; - variants = []; - return; - } - pluginData = SettingsData.getPluginSettingsForPlugin(pluginId); - variants = pluginService.getPluginVariants(pluginId); - } - - function checkVisibility() { - if (!visibilityCommand) { - conditionVisible = true; - return; - } - visibilityProcess.running = true; - } - - function setVisibilityOverride(visible) { - _visibilityOverride = true; - _visibilityOverrideValue = visible; - } - - function clearVisibilityOverride() { - _visibilityOverride = false; - if (visibilityCommand) - checkVisibility(); - } - - onVisibilityCommandChanged: { - if (visibilityCommand) - Qt.callLater(checkVisibility); - else - conditionVisible = true; - } - - onVisibilityIntervalChanged: { - if (visibilityInterval > 0 && visibilityCommand) { - visibilityTimer.restart(); - } else { - visibilityTimer.stop(); - } - } - - Timer { - id: visibilityTimer - interval: root.visibilityInterval * 1000 - repeat: true - running: root.visibilityInterval > 0 && root.visibilityCommand !== "" - onTriggered: root.checkVisibility() - } - - Process { - id: visibilityProcess - command: ["sh", "-c", root.visibilityCommand] - running: false - onExited: (exitCode, exitStatus) => { - root.conditionVisible = (exitCode === 0); - } - } - - function createVariant(variantName, variantConfig) { - if (!pluginService || !pluginId) { - return null; - } - return pluginService.createPluginVariant(pluginId, variantName, variantConfig); - } - - function removeVariant(variantId) { - if (!pluginService || !pluginId) { - return; - } - pluginService.removePluginVariant(pluginId, variantId); - } - - function updateVariant(variantId, variantConfig) { - if (!pluginService || !pluginId) { - return; - } - pluginService.updatePluginVariant(pluginId, variantId, variantConfig); - } - - width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0) - height: isVertical ? (hasVerticalPill ? verticalPill.height : 0) : (hasHorizontalPill ? horizontalPill.height : 0) - - BasePill { - id: horizontalPill - visible: !isVertical && hasHorizontalPill - opacity: root.effectiveVisible ? 1 : 0 - axis: root.axis - section: root.section - popoutTarget: hasPopout ? pluginPopout : null - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - content: root.horizontalBarPill - - states: State { - name: "hidden" - when: !root.effectiveVisible - PropertyChanges { - target: horizontalPill - width: 0 - } - } - - transitions: Transition { - NumberAnimation { - properties: "width,opacity" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - onClicked: { - if (pillClickAction) { - if (pillClickAction.length === 0) { - pillClickAction(); - } else { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width); - pillClickAction(pos.x, pos.y, pos.width, section, currentScreen); - } - } else if (hasPopout) { - pluginPopout.toggle(); - } - } - onRightClicked: { - if (pillRightClickAction) { - if (pillRightClickAction.length === 0) { - pillRightClickAction(); - } else { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width); - pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen); - } - } - } - } - - BasePill { - id: verticalPill - visible: isVertical && hasVerticalPill - opacity: root.effectiveVisible ? 1 : 0 - axis: root.axis - section: root.section - popoutTarget: hasPopout ? pluginPopout : null - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - content: root.verticalBarPill - isVerticalOrientation: true - - states: State { - name: "hidden" - when: !root.effectiveVisible - PropertyChanges { - target: verticalPill - height: 0 - } - } - - transitions: Transition { - NumberAnimation { - properties: "height,opacity" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - onClicked: { - if (pillClickAction) { - if (pillClickAction.length === 0) { - pillClickAction(); - } else { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width); - pillClickAction(pos.x, pos.y, pos.width, section, currentScreen); - } - } else if (hasPopout) { - pluginPopout.toggle(); - } - } - onRightClicked: { - if (pillRightClickAction) { - if (pillRightClickAction.length === 0) { - pillRightClickAction(); - } else { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width); - pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen); - } - } - } - } - - function closePopout() { - if (pluginPopout) { - pluginPopout.close(); - } - } - - function triggerPopout() { - if (pillClickAction) { - if (pillClickAction.length === 0) { - pillClickAction(); - return; - } - const pill = isVertical ? verticalPill : horizontalPill; - const globalPos = pill.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, pill.width); - pillClickAction(pos.x, pos.y, pos.width, section, currentScreen); - return; - } - if (!hasPopout) - return; - - const pill = isVertical ? verticalPill : horizontalPill; - const globalPos = pill.visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, pill.visualWidth, barSpacing, barPosition, barConfig); - - pluginPopout.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, barSpacing, barConfig); - pluginPopout.toggle(); - } - - PluginPopout { - id: pluginPopout - contentWidth: root.popoutWidth - contentHeight: root.popoutHeight - pluginContent: root.popoutContent - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml deleted file mode 100644 index 5d40826..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string pluginId: "" - property var pluginInstance: null - property bool isCompoundPill: false - property bool isSmallToggle: false - - readonly property bool hasDetail: pluginInstance?.ccDetailContent !== null - readonly property string iconName: pluginInstance?.ccWidgetIcon || "extension" - readonly property string primaryText: pluginInstance?.ccWidgetPrimaryText || "Plugin" - readonly property string secondaryText: pluginInstance?.ccWidgetSecondaryText || "" - readonly property bool isActive: pluginInstance?.ccWidgetIsActive || false - readonly property Component detailContent: pluginInstance?.ccDetailContent || null - readonly property real detailHeight: pluginInstance?.ccDetailHeight || 250 - - signal toggled() - signal expanded() - - Component.onCompleted: { - if (pluginInstance) { - pluginInstance.ccWidgetToggled.connect(handleToggled) - pluginInstance.ccWidgetExpanded.connect(handleExpanded) - } - } - - function handleToggled() { - toggled() - } - - function handleExpanded() { - expanded() - } - - function invokeToggle() { - if (pluginInstance) { - pluginInstance.ccWidgetToggled() - } - } - - function invokeExpand() { - if (pluginInstance) { - pluginInstance.ccWidgetExpanded() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginPopout.qml deleted file mode 100644 index acd24b9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginPopout.qml +++ /dev/null @@ -1,83 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:plugins:" + layerNamespacePlugin - - property var triggerScreen: null - property Component pluginContent: null - property real contentWidth: 400 - property real contentHeight: 0 - - popupWidth: contentWidth - popupHeight: contentHeight - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: popoutContainer - - implicitHeight: popoutColumn.implicitHeight + Theme.spacingL * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => { - popoutContainer.forceActiveFocus(); - }); - } - } - } - - Column { - id: popoutColumn - width: parent.width - Theme.spacingS * 2 - x: Theme.spacingS - y: Theme.spacingS - spacing: Theme.spacingS - - Loader { - id: popoutContentLoader - width: parent.width - sourceComponent: root.pluginContent - - onLoaded: { - if (item && "closePopout" in item) { - item.closePopout = function () { - root.close(); - }; - } - if (item && "parentPopout" in item) { - item.parentPopout = root; - } - if (item) { - root.contentHeight = Qt.binding(() => item.implicitHeight + Theme.spacingS * 2); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginSettings.qml deleted file mode 100644 index 2ba5d05..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginSettings.qml +++ /dev/null @@ -1,311 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - required property string pluginId - property var pluginService: null - default property list content - - signal settingChanged - - property var variants: [] - property alias variantsModel: variantsListModel - - implicitHeight: hasPermission ? settingsColumn.implicitHeight : errorText.implicitHeight - height: implicitHeight - - readonly property bool isDesktopPlugin: { - if (!pluginService?.availablePlugins || !pluginId) - return false; - const plugin = pluginService.availablePlugins[pluginId]; - return plugin?.type === "desktop"; - } - - readonly property bool hasPermission: { - if (!pluginService?.availablePlugins || !pluginId) - return true; - const plugin = pluginService.availablePlugins[pluginId]; - if (!plugin) - return true; - const permissions = Array.isArray(plugin.permissions) ? plugin.permissions : []; - return permissions.indexOf("settings_write") !== -1; - } - - Component.onCompleted: { - loadVariants(); - } - - onPluginServiceChanged: { - if (pluginService) { - loadVariants(); - for (let i = 0; i < content.length; i++) { - const child = content[i]; - if (child.loadValue) { - child.loadValue(); - } - } - } - } - - onContentChanged: { - for (let i = 0; i < content.length; i++) { - const item = content[i]; - if (item instanceof Item) { - item.parent = settingsColumn; - } - } - } - - Connections { - target: pluginService - enabled: pluginService !== null - - function onPluginDataChanged(changedPluginId) { - if (changedPluginId === pluginId) { - loadVariants(); - reloadChildValues(); - } - } - } - - function reloadChildValues() { - for (let i = 0; i < content.length; i++) { - const child = content[i]; - if (child.loadValue) { - child.loadValue(); - } - } - } - - function loadVariants() { - if (!pluginService?.getPluginVariants || !pluginId) { - variants = []; - return; - } - variants = pluginService.getPluginVariants(pluginId); - syncVariantsToModel(); - } - - function syncVariantsToModel() { - variantsListModel.clear(); - for (let i = 0; i < variants.length; i++) { - variantsListModel.append(variants[i]); - } - } - - onVariantsChanged: { - syncVariantsToModel(); - } - - ListModel { - id: variantsListModel - } - - function createVariant(variantName, variantConfig) { - if (!pluginService?.createPluginVariant || !pluginId) { - return null; - } - return pluginService.createPluginVariant(pluginId, variantName, variantConfig); - } - - function removeVariant(variantId) { - if (!pluginService?.removePluginVariant || !pluginId) { - return; - } - pluginService.removePluginVariant(pluginId, variantId); - } - - function updateVariant(variantId, variantConfig) { - if (!pluginService?.updatePluginVariant || !pluginId) { - return; - } - pluginService.updatePluginVariant(pluginId, variantId, variantConfig); - } - - function saveValue(key, value) { - if (!pluginService) { - return; - } - if (!hasPermission) { - console.warn("PluginSettings: Plugin", pluginId, "does not have settings_write permission"); - return; - } - if (pluginService.savePluginData) { - pluginService.savePluginData(pluginId, key, value); - settingChanged(); - } - } - - function loadValue(key, defaultValue) { - if (pluginService && pluginService.loadPluginData) { - return pluginService.loadPluginData(pluginId, key, defaultValue); - } - return defaultValue; - } - - function saveState(key, value) { - if (!pluginService) - return; - if (pluginService.savePluginState) - pluginService.savePluginState(pluginId, key, value); - } - - function loadState(key, defaultValue) { - if (pluginService && pluginService.loadPluginState) - return pluginService.loadPluginState(pluginId, key, defaultValue); - return defaultValue; - } - - function clearState() { - if (pluginService && pluginService.clearPluginState) - pluginService.clearPluginState(pluginId); - } - - function findFlickable(item) { - var current = item?.parent; - while (current) { - if (current.contentY !== undefined && current.contentHeight !== undefined) { - return current; - } - current = current.parent; - } - return null; - } - - function ensureItemVisible(item) { - if (!item) - return; - var flickable = findFlickable(root); - if (!flickable) - return; - var itemGlobalY = item.mapToItem(null, 0, 0).y; - var itemHeight = item.height; - var flickableGlobalY = flickable.mapToItem(null, 0, 0).y; - var viewportHeight = flickable.height; - - var itemRelativeY = itemGlobalY - flickableGlobalY; - var viewportTop = 0; - var viewportBottom = viewportHeight; - - if (itemRelativeY < viewportTop) { - flickable.contentY = Math.max(0, flickable.contentY - (viewportTop - itemRelativeY) - Theme.spacingL); - } else if (itemRelativeY + itemHeight > viewportBottom) { - flickable.contentY = Math.min(flickable.contentHeight - viewportHeight, flickable.contentY + (itemRelativeY + itemHeight - viewportBottom) + Theme.spacingL); - } - } - - StyledText { - id: errorText - visible: pluginService && !root.hasPermission - anchors.fill: parent - text: I18n.tr("This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json") - color: Theme.error - font.pixelSize: Theme.fontSizeMedium - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - Column { - id: settingsColumn - visible: root.hasPermission - width: parent.width - spacing: Theme.spacingM - - Item { - id: desktopDisplaySettings - visible: root.isDesktopPlugin - width: parent.width - height: visible ? displaySettingsColumn.implicitHeight : 0 - - Column { - id: displaySettingsColumn - width: parent.width - spacing: Theme.spacingS - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.3 - visible: root.content.length > 0 - } - - StyledText { - text: I18n.tr("Display Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Choose which displays show this widget") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - } - - DankToggle { - width: parent.width - text: I18n.tr("All displays") - checked: { - const prefs = root.loadValue("displayPreferences", ["all"]); - return Array.isArray(prefs) && (prefs.includes("all") || prefs.length === 0); - } - onToggled: isChecked => { - if (isChecked) { - root.saveValue("displayPreferences", ["all"]); - } else { - root.saveValue("displayPreferences", []); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: { - const prefs = root.loadValue("displayPreferences", ["all"]); - return !Array.isArray(prefs) || (!prefs.includes("all") && prefs.length >= 0); - } - - Repeater { - model: Quickshell.screens - - DankToggle { - required property var modelData - width: parent.width - text: SettingsData.getScreenDisplayName(modelData) - description: modelData.width + "×" + modelData.height - checked: { - const prefs = root.loadValue("displayPreferences", ["all"]); - if (!Array.isArray(prefs) || prefs.includes("all")) - return false; - return prefs.some(p => p.name === modelData.name); - } - onToggled: isChecked => { - var prefs = root.loadValue("displayPreferences", ["all"]); - if (!Array.isArray(prefs) || prefs.includes("all")) { - prefs = []; - } - prefs = prefs.filter(p => p.name !== modelData.name); - if (isChecked) { - prefs.push({ - name: modelData.name, - model: modelData.model || "" - }); - } - root.saveValue("displayPreferences", prefs); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PopoutComponent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PopoutComponent.qml deleted file mode 100644 index 7ccf637..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PopoutComponent.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - property string headerText: "" - property string detailsText: "" - property bool showCloseButton: false - property var closePopout: null - property var parentPopout: null - property alias headerActions: headerActionsLoader.sourceComponent - - readonly property int headerHeight: popoutHeader.visible ? popoutHeader.height : 0 - readonly property int detailsHeight: popoutDetails.visible ? popoutDetails.implicitHeight : 0 - - spacing: 0 - - Item { - id: popoutHeader - width: parent.width - height: 40 - visible: headerText.length > 0 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.headerText - font.pixelSize: Theme.fontSizeLarge + 4 - font.weight: Font.Bold - color: Theme.surfaceText - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Loader { - id: headerActionsLoader - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: closeButton - width: 32 - height: 32 - radius: 16 - color: closeArea.containsMouse ? Theme.errorHover : "transparent" - visible: root.showCloseButton - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - if (root.closePopout) { - root.closePopout(); - } - } - } - } - } - } - - StyledText { - id: popoutDetails - width: parent.width - leftPadding: Theme.spacingS - bottomPadding: Theme.spacingS - text: root.detailsText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: detailsText.length > 0 - wrapMode: Text.WordWrap - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SelectionSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SelectionSetting.qml deleted file mode 100644 index 0f8fac0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SelectionSetting.qml +++ /dev/null @@ -1,91 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - required property var options - property string defaultValue: "" - property string value: defaultValue - - width: parent.width - spacing: Theme.spacingS - - function loadValue() { - const settings = findSettings() - if (settings && settings.pluginService) { - value = settings.loadValue(settingKey, defaultValue) - } - } - - Component.onCompleted: { - loadValue() - } - - readonly property var optionLabels: { - const labels = [] - for (let i = 0; i < options.length; i++) { - labels.push(options[i].label || options[i]) - } - return labels - } - - readonly property var valueToLabel: { - const map = {} - for (let i = 0; i < options.length; i++) { - const opt = options[i] - if (typeof opt === 'object') { - map[opt.value] = opt.label - } else { - map[opt] = opt - } - } - return map - } - - readonly property var labelToValue: { - const map = {} - for (let i = 0; i < options.length; i++) { - const opt = options[i] - if (typeof opt === 'object') { - map[opt.label] = opt.value - } else { - map[opt] = opt - } - } - return map - } - - onValueChanged: { - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, value) - } - } - - function findSettings() { - let item = parent - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item - } - item = item.parent - } - return null - } - - DankDropdown { - width: parent.width - text: root.label - description: root.description - currentValue: root.valueToLabel[root.value] || root.value - options: root.optionLabels - onValueChanged: newValue => { - root.value = root.labelToValue[newValue] || newValue - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SliderSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SliderSetting.qml deleted file mode 100644 index f540fd4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SliderSetting.qml +++ /dev/null @@ -1,81 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - property int defaultValue: 0 - property int value: defaultValue - property int minimum: 0 - property int maximum: 100 - property string leftIcon: "" - property string rightIcon: "" - property string unit: "" - - width: parent.width - spacing: Theme.spacingS - - function loadValue() { - const settings = findSettings() - if (settings && settings.pluginService) { - value = settings.loadValue(settingKey, defaultValue) - } - } - - Component.onCompleted: { - loadValue() - } - - onValueChanged: { - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, value) - } - } - - function findSettings() { - let item = parent - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item - } - item = item.parent - } - return null - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - - DankSlider { - width: parent.width - value: root.value - minimum: root.minimum - maximum: root.maximum - leftIcon: root.leftIcon - rightIcon: root.rightIcon - unit: root.unit - wheelEnabled: false - thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - onSliderValueChanged: newValue => { - root.value = newValue - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/StringSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/StringSetting.qml deleted file mode 100644 index 849807b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/StringSetting.qml +++ /dev/null @@ -1,84 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - required property string settingKey - required property string label - property string description: "" - property string placeholder: "" - property string defaultValue: "" - property string value: defaultValue - - width: parent.width - spacing: Theme.spacingS - - property bool isInitialized: false - - function loadValue() { - const settings = findSettings(); - if (settings && settings.pluginService) { - const loadedValue = settings.loadValue(settingKey, defaultValue); - if (textField.activeFocus && isInitialized) - return; - value = loadedValue; - textField.text = loadedValue; - isInitialized = true; - } - } - - Component.onCompleted: { - Qt.callLater(loadValue); - } - - function commit() { - if (!isInitialized) - return; - if (textField.text === value) - return; - value = textField.text; - const settings = findSettings(); - if (settings) - settings.saveValue(settingKey, value); - } - - function findSettings() { - let item = parent; - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item; - } - item = item.parent; - } - return null; - } - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - - DankTextField { - id: textField - width: parent.width - placeholderText: root.placeholder - onEditingFinished: root.commit() - onActiveFocusChanged: { - if (!activeFocus) - root.commit(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ToggleSetting.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ToggleSetting.qml deleted file mode 100644 index 3a6eae5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ToggleSetting.qml +++ /dev/null @@ -1,81 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Row { - id: root - - required property string settingKey - required property string label - property string description: "" - property bool defaultValue: false - property bool value: defaultValue - - width: parent.width - spacing: Theme.spacingM - - property bool isInitialized: false - - function loadValue() { - const settings = findSettings() - if (settings && settings.pluginService) { - const loadedValue = settings.loadValue(settingKey, defaultValue) - value = loadedValue - isInitialized = true - } - } - - Component.onCompleted: { - Qt.callLater(loadValue) - } - - onValueChanged: { - if (!isInitialized) return - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, value) - } - } - - function findSettings() { - let item = parent - while (item) { - if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item - } - item = item.parent - } - return null - } - - Column { - width: parent.width - toggle.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: root.label - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - visible: root.description !== "" - } - } - - DankToggle { - id: toggle - anchors.verticalCenter: parent.verticalCenter - checked: root.value - onToggled: isChecked => { - root.value = isChecked - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/DisksView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/DisksView.qml deleted file mode 100644 index 5a8e688..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/DisksView.qml +++ /dev/null @@ -1,346 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - function formatSpeed(bytesPerSec) { - if (bytesPerSec < 1024) - return bytesPerSec.toFixed(0) + " B/s"; - if (bytesPerSec < 1024 * 1024) - return (bytesPerSec / 1024).toFixed(1) + " KB/s"; - if (bytesPerSec < 1024 * 1024 * 1024) - return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s"; - return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(2) + " GB/s"; - } - - Component.onCompleted: { - DgopService.addRef(["disk", "diskmounts"]); - } - - Component.onDestruction: { - DgopService.removeRef(["disk", "diskmounts"]); - } - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 80 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - RowLayout { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXL - - Column { - Layout.fillWidth: true - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "storage" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Disk I/O", "disk io header in system monitor") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - spacing: Theme.spacingL - - Row { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Read:", "disk read label") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: root.formatSpeed(DgopService.diskReadRate) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: Theme.primary - } - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Write:", "disk write label") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: root.formatSpeed(DgopService.diskWriteRate) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: Theme.warning - } - } - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "folder" - size: Theme.iconSize - 2 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Mount Points", "mount points header in system monitor") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: Theme.outlineLight - } - - DankListView { - id: mountListView - - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - spacing: 4 - - model: DgopService.diskMounts - - delegate: Rectangle { - required property var modelData - required property int index - - width: mountListView.width - height: 60 - radius: Theme.cornerRadius - color: mountMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent" - - readonly property real usedPct: { - const pctStr = modelData?.percent ?? "0%"; - return parseFloat(pctStr.replace("%", "")) / 100; - } - - MouseArea { - id: mountMouseArea - anchors.fill: parent - hoverEnabled: true - } - - RowLayout { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - Column { - Layout.fillWidth: true - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingS - - DankIcon { - name: { - const mp = modelData?.mount ?? ""; - if (mp === "/") - return "home"; - if (mp === "/home") - return "person"; - if (mp.includes("boot")) - return "memory"; - if (mp.includes("media") || mp.includes("mnt")) - return "usb"; - return "folder"; - } - size: Theme.iconSize - 4 - color: Theme.surfaceText - opacity: 0.8 - } - - StyledText { - text: modelData?.mount ?? "" - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingS - - StyledText { - text: modelData?.device ?? "" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData?.fstype ?? "" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - } - } - - Column { - Layout.preferredWidth: 200 - spacing: Theme.spacingXS - - Rectangle { - width: parent.width - height: 8 - radius: 4 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width * Math.min(1, parent.parent.parent.parent.usedPct) - height: parent.height - radius: 4 - color: { - const pct = parent.parent.parent.parent.usedPct; - if (pct > 0.95) - return Theme.error; - if (pct > 0.85) - return Theme.warning; - return Theme.primary; - } - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - } - - Row { - anchors.right: parent.right - spacing: Theme.spacingS - - StyledText { - text: modelData?.used ?? "" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - } - - StyledText { - text: "/" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData?.size ?? "" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - } - } - - StyledText { - Layout.preferredWidth: 50 - text: modelData?.percent ?? "" - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: { - const pct = parent.parent.usedPct; - if (pct > 0.95) - return Theme.error; - if (pct > 0.85) - return Theme.warning; - return Theme.surfaceText; - } - horizontalAlignment: Text.AlignRight - } - } - } - - Rectangle { - anchors.centerIn: parent - width: 300 - height: 80 - radius: Theme.cornerRadius - color: "transparent" - visible: DgopService.diskMounts.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "storage" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No mount points found", "empty state in disk mounts list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/PerformanceView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/PerformanceView.qml deleted file mode 100644 index c793d92..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/PerformanceView.qml +++ /dev/null @@ -1,304 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - readonly property int historySize: 60 - - property var cpuHistory: [] - property var memoryHistory: [] - property var networkRxHistory: [] - property var networkTxHistory: [] - property var diskReadHistory: [] - property var diskWriteHistory: [] - - function formatBytes(bytes) { - if (bytes < 1024) - return bytes.toFixed(0) + " B/s"; - if (bytes < 1024 * 1024) - return (bytes / 1024).toFixed(1) + " KB/s"; - if (bytes < 1024 * 1024 * 1024) - return (bytes / (1024 * 1024)).toFixed(1) + " MB/s"; - return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s"; - } - - function addToHistory(arr, val) { - const newArr = arr.slice(); - newArr.push(val); - if (newArr.length > historySize) - newArr.shift(); - return newArr; - } - - function sampleData() { - cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage); - memoryHistory = addToHistory(memoryHistory, DgopService.memoryUsage); - networkRxHistory = addToHistory(networkRxHistory, DgopService.networkRxRate); - networkTxHistory = addToHistory(networkTxHistory, DgopService.networkTxRate); - diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate); - diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate); - } - - Component.onCompleted: { - DgopService.addRef(["cpu", "memory", "network", "disk", "diskmounts", "system"]); - } - - Component.onDestruction: { - DgopService.removeRef(["cpu", "memory", "network", "disk", "diskmounts", "system"]); - } - - SystemClock { - id: sampleClock - precision: SystemClock.Seconds - onDateChanged: { - if (date.getSeconds() % 1 === 0) - root.sampleData(); - } - } - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: (root.height - Theme.spacingM * 2) / 2 - spacing: Theme.spacingM - - PerformanceCard { - Layout.fillWidth: true - Layout.fillHeight: true - title: "CPU" - icon: "memory" - value: DgopService.cpuUsage.toFixed(1) + "%" - subtitle: DgopService.cpuModel || (DgopService.cpuCores + " cores") - accentColor: Theme.primary - history: root.cpuHistory - maxValue: 100 - showSecondary: false - extraInfo: DgopService.cpuTemperature > 0 ? (DgopService.cpuTemperature.toFixed(0) + "°C") : "" - extraInfoColor: DgopService.cpuTemperature > 80 ? Theme.error : (DgopService.cpuTemperature > 60 ? Theme.warning : Theme.surfaceVariantText) - } - - PerformanceCard { - Layout.fillWidth: true - Layout.fillHeight: true - title: I18n.tr("Memory") - icon: "sd_card" - value: DgopService.memoryUsage.toFixed(1) + "%" - subtitle: DgopService.formatSystemMemory(DgopService.usedMemoryKB) + " / " + DgopService.formatSystemMemory(DgopService.totalMemoryKB) - accentColor: Theme.secondary - history: root.memoryHistory - maxValue: 100 - showSecondary: false - extraInfo: DgopService.totalSwapKB > 0 ? ("Swap: " + DgopService.formatSystemMemory(DgopService.usedSwapKB)) : "" - extraInfoColor: Theme.surfaceVariantText - } - } - - RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: (root.height - Theme.spacingM * 2) / 2 - spacing: Theme.spacingM - - PerformanceCard { - Layout.fillWidth: true - Layout.fillHeight: true - title: I18n.tr("Network") - icon: "swap_horiz" - value: "↓ " + root.formatBytes(DgopService.networkRxRate) - subtitle: "↑ " + root.formatBytes(DgopService.networkTxRate) - accentColor: Theme.info - history: root.networkRxHistory - history2: root.networkTxHistory - maxValue: 0 - showSecondary: true - extraInfo: "" - extraInfoColor: Theme.surfaceVariantText - } - - PerformanceCard { - Layout.fillWidth: true - Layout.fillHeight: true - title: I18n.tr("Disk") - icon: "storage" - value: "R: " + root.formatBytes(DgopService.diskReadRate) - subtitle: "W: " + root.formatBytes(DgopService.diskWriteRate) - accentColor: Theme.warning - history: root.diskReadHistory - history2: root.diskWriteHistory - maxValue: 0 - showSecondary: true - extraInfo: { - const rootMount = DgopService.diskMounts.find(m => m.mountpoint === "/"); - if (rootMount) { - const usedPct = ((rootMount.used || 0) / Math.max(1, rootMount.total || 1) * 100).toFixed(0); - return "/ " + usedPct + "% used"; - } - return ""; - } - extraInfoColor: Theme.surfaceVariantText - } - } - } - - component PerformanceCard: Rectangle { - id: card - - property string title: "" - property string icon: "" - property string value: "" - property string subtitle: "" - property color accentColor: Theme.primary - property var history: [] - property var history2: null - property real maxValue: 100 - property bool showSecondary: false - property string extraInfo: "" - property color extraInfoColor: Theme.surfaceVariantText - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.outlineLight - border.width: 1 - - Canvas { - id: graphCanvas - anchors.fill: parent - anchors.margins: 4 - renderStrategy: Canvas.Cooperative - - property var hist: card.history - property var hist2: card.history2 - - onHistChanged: requestPaint() - onHist2Changed: requestPaint() - onWidthChanged: requestPaint() - onHeightChanged: requestPaint() - - onPaint: { - const ctx = getContext("2d"); - ctx.reset(); - ctx.clearRect(0, 0, width, height); - - if (!hist || hist.length < 2) - return; - - let max = card.maxValue; - if (max <= 0) { - max = 1; - for (let k = 0; k < hist.length; k++) - max = Math.max(max, hist[k]); - if (hist2) { - for (let l = 0; l < hist2.length; l++) - max = Math.max(max, hist2[l]); - } - max *= 1.1; - } - - const c = card.accentColor; - const grad = ctx.createLinearGradient(0, 0, 0, height); - grad.addColorStop(0, Qt.rgba(c.r, c.g, c.b, 0.25)); - grad.addColorStop(1, Qt.rgba(c.r, c.g, c.b, 0.02)); - - ctx.fillStyle = grad; - ctx.beginPath(); - ctx.moveTo(0, height); - for (let i = 0; i < hist.length; i++) { - const x = (width / (root.historySize - 1)) * i; - const y = height - (hist[i] / max) * height * 0.8; - ctx.lineTo(x, y); - } - ctx.lineTo((width / (root.historySize - 1)) * (hist.length - 1), height); - ctx.closePath(); - ctx.fill(); - - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.8); - ctx.lineWidth = 2; - ctx.beginPath(); - for (let j = 0; j < hist.length; j++) { - const px = (width / (root.historySize - 1)) * j; - const py = height - (hist[j] / max) * height * 0.8; - j === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py); - } - ctx.stroke(); - - if (hist2 && hist2.length >= 2 && card.showSecondary) { - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.4); - ctx.lineWidth = 1.5; - ctx.setLineDash([4, 4]); - ctx.beginPath(); - for (let m = 0; m < hist2.length; m++) { - const sx = (width / (root.historySize - 1)) * m; - const sy = height - (hist2[m] / max) * height * 0.8; - m === 0 ? ctx.moveTo(sx, sy) : ctx.lineTo(sx, sy); - } - ctx.stroke(); - ctx.setLineDash([]); - } - } - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - - DankIcon { - name: card.icon - size: Theme.iconSize - color: card.accentColor - } - - StyledText { - text: card.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: card.extraInfo - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: card.extraInfoColor - visible: card.extraInfo.length > 0 - } - } - - Item { - Layout.fillHeight: true - } - - StyledText { - text: card.value - font.pixelSize: Theme.fontSizeXLarge - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - text: card.subtitle - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - elide: Text.ElideRight - Layout.fillWidth: true - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessContextMenu.qml deleted file mode 100644 index 7c48b5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessContextMenu.qml +++ /dev/null @@ -1,341 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Popup { - id: processContextMenu - - property var processData: null - property int selectedIndex: -1 - property bool keyboardNavigation: false - property var parentFocusItem: null - - signal menuClosed - signal processKilled - - readonly property var menuItems: [ - { - text: I18n.tr("Copy PID"), - icon: "tag", - action: copyPid, - enabled: true - }, - { - text: I18n.tr("Copy Name"), - icon: "content_copy", - action: copyName, - enabled: true - }, - { - text: I18n.tr("Copy Full Command"), - icon: "code", - action: copyFullCommand, - enabled: true - }, - { - type: "separator" - }, - { - text: I18n.tr("Kill Process"), - icon: "close", - action: killProcess, - enabled: true, - dangerous: true - }, - { - text: I18n.tr("Force Kill (SIGKILL)"), - icon: "dangerous", - action: forceKillProcess, - enabled: processData && processData.pid > 1000, - dangerous: true - } - ] - - readonly property int visibleItemCount: { - let count = 0; - for (let i = 0; i < menuItems.length; i++) { - if (menuItems[i].type !== "separator") - count++; - } - return count; - } - - function show(x, y, fromKeyboard) { - let finalX = x; - let finalY = y; - - if (processContextMenu.parent) { - const parentWidth = processContextMenu.parent.width; - const parentHeight = processContextMenu.parent.height; - const menuWidth = processContextMenu.width; - const menuHeight = processContextMenu.height; - - if (finalX + menuWidth > parentWidth) - finalX = Math.max(0, parentWidth - menuWidth); - if (finalY + menuHeight > parentHeight) - finalY = Math.max(0, parentHeight - menuHeight); - } - - processContextMenu.x = finalX; - processContextMenu.y = finalY; - keyboardNavigation = fromKeyboard || false; - selectedIndex = fromKeyboard ? 0 : -1; - open(); - } - - function selectNext() { - if (visibleItemCount === 0) - return; - let current = selectedIndex; - let next = current; - do { - next = (next + 1) % menuItems.length; - } while (menuItems[next].type === "separator" && next !== current) - selectedIndex = next; - } - - function selectPrevious() { - if (visibleItemCount === 0) - return; - let current = selectedIndex; - let prev = current; - do { - prev = (prev - 1 + menuItems.length) % menuItems.length; - } while (menuItems[prev].type === "separator" && prev !== current) - selectedIndex = prev; - } - - function activateSelected() { - if (selectedIndex < 0 || selectedIndex >= menuItems.length) - return; - const item = menuItems[selectedIndex]; - if (item.type === "separator" || !item.enabled) - return; - item.action(); - } - - function copyPid() { - if (processData) - Quickshell.execDetached(["dms", "cl", "copy", processData.pid.toString()]); - close(); - } - - function copyName() { - if (processData) { - const name = processData.command || ""; - Quickshell.execDetached(["dms", "cl", "copy", name]); - } - close(); - } - - function copyFullCommand() { - if (processData) { - const fullCmd = processData.fullCommand || processData.command || ""; - Quickshell.execDetached(["dms", "cl", "copy", fullCmd]); - } - close(); - } - - function killProcess() { - if (processData) - Quickshell.execDetached(["kill", processData.pid.toString()]); - processKilled(); - close(); - } - - function forceKillProcess() { - if (processData) - Quickshell.execDetached(["kill", "-9", processData.pid.toString()]); - processKilled(); - close(); - } - - width: 200 - height: menuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: false - closePolicy: Popup.CloseOnEscape - - onClosed: { - closePolicy = Popup.CloseOnEscape; - keyboardNavigation = false; - selectedIndex = -1; - menuClosed(); - if (parentFocusItem) - Qt.callLater(() => parentFocusItem.forceActiveFocus()); - } - - onOpened: { - outsideClickTimer.start(); - if (keyboardNavigation) - Qt.callLater(() => keyboardHandler.forceActiveFocus()); - } - - Timer { - id: outsideClickTimer - interval: 100 - onTriggered: processContextMenu.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside - } - - background: Rectangle { - color: "transparent" - } - - contentItem: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - - Item { - id: keyboardHandler - anchors.fill: parent - focus: keyboardNavigation - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Down: - case Qt.Key_J: - keyboardNavigation = true; - selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - case Qt.Key_K: - keyboardNavigation = true; - selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - case Qt.Key_Space: - activateSelected(); - event.accepted = true; - return; - case Qt.Key_Escape: - case Qt.Key_Left: - case Qt.Key_H: - close(); - event.accepted = true; - return; - } - } - } - - Column { - id: menuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 1 - - Repeater { - model: menuItems - - Item { - width: parent.width - height: modelData.type === "separator" ? 5 : 32 - visible: modelData.type !== "separator" || index > 0 - - property int itemVisibleIndex: { - let count = 0; - for (let i = 0; i < index; i++) { - if (menuItems[i].type !== "separator") - count++; - } - return count; - } - - Rectangle { - visible: modelData.type === "separator" - width: parent.width - Theme.spacingS * 2 - height: 1 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.15) - } - - Rectangle { - id: menuItem - visible: modelData.type !== "separator" - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: { - if (!modelData.enabled) - return "transparent"; - const isSelected = keyboardNavigation && selectedIndex === index; - if (modelData.dangerous) { - if (isSelected) - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2); - return menuItemArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"; - } - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2); - return menuItemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"; - } - opacity: modelData.enabled ? 1 : 0.5 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: modelData.icon || "" - size: 16 - color: { - if (!modelData.enabled) - return Theme.surfaceVariantText; - const isSelected = keyboardNavigation && selectedIndex === index; - if (modelData.dangerous && (menuItemArea.containsMouse || isSelected)) - return Theme.error; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.text || "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - color: { - if (!modelData.enabled) - return Theme.surfaceVariantText; - const isSelected = keyboardNavigation && selectedIndex === index; - if (modelData.dangerous && (menuItemArea.containsMouse || isSelected)) - return Theme.error; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: menuItemRipple - rippleColor: modelData.dangerous ? Theme.error : Theme.surfaceText - cornerRadius: menuItem.radius - } - - MouseArea { - id: menuItemArea - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: modelData.enabled ?? false - onEntered: { - keyboardNavigation = false; - selectedIndex = index; - } - onPressed: mouse => menuItemRipple.trigger(mouse.x, mouse.y) - onClicked: modelData.action() - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessListPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessListPopout.qml deleted file mode 100644 index 3adbe07..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessListPopout.qml +++ /dev/null @@ -1,535 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Modules.ProcessList -import qs.Services -import qs.Widgets - -DankPopout { - id: processListPopout - - layerNamespace: "dms:process-list-popout" - - property var parentWidget: null - property var triggerScreen: null - property string searchText: "" - property string expandedPid: "" - property string processFilter: "all" - - function hide() { - close(); - if (processContextMenu.visible) - processContextMenu.close(); - } - - function show() { - open(); - } - - popupWidth: Math.round(Theme.fontSizeMedium * 46) - popupHeight: Math.round(Theme.fontSizeMedium * 39) - triggerWidth: 55 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: { - if (processContextMenu.visible) - processContextMenu.close(); - close(); - } - - onShouldBeVisibleChanged: { - if (!shouldBeVisible) { - searchText = ""; - expandedPid = ""; - processFilter = "all"; - } - } - - Ref { - service: DgopService - } - - ProcessContextMenu { - id: processContextMenu - } - - content: Component { - Rectangle { - id: processListContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - radius: Theme.cornerRadius - color: "transparent" - clip: true - focus: true - - Component.onCompleted: { - if (processListPopout.shouldBeVisible) - searchField.forceActiveFocus(); - processContextMenu.parent = processListContent; - processContextMenu.parentFocusItem = processListContent; - } - - Keys.onPressed: event => { - if (processContextMenu.visible) - return; - - switch (event.key) { - case Qt.Key_Escape: - if (processListPopout.searchText.length > 0) { - processListPopout.searchText = ""; - event.accepted = true; - return; - } - if (processesView.keyboardNavigationActive) { - processesView.reset(); - event.accepted = true; - return; - } - processListPopout.close(); - event.accepted = true; - return; - case Qt.Key_F: - if (event.modifiers & Qt.ControlModifier) { - searchField.forceActiveFocus(); - event.accepted = true; - return; - } - break; - } - - processesView.handleKey(event); - } - - Connections { - target: processListPopout - function onShouldBeVisibleChanged() { - if (processListPopout.shouldBeVisible) { - Qt.callLater(() => searchField.forceActiveFocus()); - } else { - processesView.reset(); - processFilterGroup.currentIndex = 0; - } - } - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "analytics" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Processes") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - Layout.fillWidth: true - } - - DankButtonGroup { - id: processFilterGroup - Layout.minimumWidth: implicitWidth - model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")] - currentIndex: 0 - checkEnabled: false - buttonHeight: Math.round(Theme.fontSizeSmall * 2.4) - minButtonWidth: 0 - buttonPadding: Theme.spacingM - textSize: Theme.fontSizeSmall - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - switch (index) { - case 0: - processListPopout.processFilter = "all"; - return; - case 1: - processListPopout.processFilter = "user"; - return; - case 2: - processListPopout.processFilter = "system"; - return; - } - } - } - - DankTextField { - id: searchField - Layout.fillWidth: true - Layout.minimumWidth: Theme.fontSizeMedium * 8 - Layout.preferredHeight: Theme.fontSizeMedium * 2.5 - placeholderText: I18n.tr("Search...") - leftIconName: "search" - showClearButton: true - text: processListPopout.searchText - onTextChanged: processListPopout.searchText = text - ignoreUpDownKeys: true - keyForwardTargets: [processListContent] - } - } - - Item { - id: statsContainer - Layout.fillWidth: true - Layout.preferredHeight: Math.max(leftInfo.height, gaugesRow.height) + Theme.spacingS - - function compactMem(kb) { - if (kb < 1024 * 1024) { - const mb = kb / 1024; - return mb >= 100 ? mb.toFixed(0) + " MB" : mb.toFixed(1) + " MB"; - } - const gb = kb / (1024 * 1024); - return gb >= 10 ? gb.toFixed(0) + " GB" : gb.toFixed(1) + " GB"; - } - - readonly property real gaugeSize: Theme.fontSizeMedium * 6.5 - - readonly property var enabledGpusWithTemp: { - if (!SessionData.enabledGpuPciIds || SessionData.enabledGpuPciIds.length === 0) - return []; - const result = []; - for (const gpu of DgopService.availableGpus) { - if (SessionData.enabledGpuPciIds.indexOf(gpu.pciId) !== -1 && gpu.temperature > 0) - result.push(gpu); - } - return result; - } - readonly property bool hasGpu: enabledGpusWithTemp.length > 0 - - Row { - id: leftInfo - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Theme.fontSizeMedium * 3 - height: width - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - - SystemLogo { - anchors.centerIn: parent - width: parent.width * 0.7 - height: width - colorOverride: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS / 2 - - StyledText { - text: DgopService.hostname || "localhost" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - text: DgopService.distribution || "Linux" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - Row { - spacing: Theme.spacingS - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "schedule" - size: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.shortUptime || "--" - font.pixelSize: Theme.fontSizeSmall - 1 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - StyledText { - text: DgopService.processCount + " " + I18n.tr("procs", "short for processes") - font.pixelSize: Theme.fontSizeSmall - 1 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - } - } - } - - Row { - id: gaugesRow - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - CircleGauge { - width: statsContainer.gaugeSize - height: statsContainer.gaugeSize - value: DgopService.cpuUsage / 100 - label: DgopService.cpuUsage.toFixed(0) + "%" - sublabel: "CPU" - detail: DgopService.cpuTemperature > 0 ? (DgopService.cpuTemperature.toFixed(0) + "°") : "" - accentColor: DgopService.cpuUsage > 80 ? Theme.error : (DgopService.cpuUsage > 50 ? Theme.warning : Theme.primary) - detailColor: DgopService.cpuTemperature > 85 ? Theme.error : (DgopService.cpuTemperature > 70 ? Theme.warning : Theme.surfaceVariantText) - } - - CircleGauge { - width: statsContainer.gaugeSize - height: statsContainer.gaugeSize - value: DgopService.memoryUsage / 100 - label: statsContainer.compactMem(DgopService.usedMemoryKB) - sublabel: I18n.tr("Memory") - detail: DgopService.totalSwapKB > 0 ? ("+" + statsContainer.compactMem(DgopService.usedSwapKB)) : "" - accentColor: DgopService.memoryUsage > 90 ? Theme.error : (DgopService.memoryUsage > 70 ? Theme.warning : Theme.secondary) - } - - CircleGauge { - width: statsContainer.gaugeSize - height: statsContainer.gaugeSize - visible: statsContainer.hasGpu - - readonly property var gpu: statsContainer.enabledGpusWithTemp[0] ?? null - readonly property color vendorColor: { - const vendor = (gpu?.vendor ?? "").toLowerCase(); - if (vendor.includes("nvidia")) - return Theme.success; - if (vendor.includes("amd")) - return Theme.error; - if (vendor.includes("intel")) - return Theme.info; - return Theme.info; - } - - value: Math.min(1, (gpu?.temperature ?? 0) / 100) - label: (gpu?.temperature ?? 0) > 0 ? ((gpu?.temperature ?? 0).toFixed(0) + "°C") : "--" - sublabel: "GPU" - accentColor: { - const temp = gpu?.temperature ?? 0; - if (temp > 85) - return Theme.error; - if (temp > 70) - return Theme.warning; - return vendorColor; - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - clip: true - - ProcessesView { - id: processesView - anchors.fill: parent - anchors.margins: Theme.spacingS - searchText: processListPopout.searchText - expandedPid: processListPopout.expandedPid - processFilter: processListPopout.processFilter - contextMenu: processContextMenu - onExpandedPidChanged: processListPopout.expandedPid = expandedPid - } - } - } - } - } - - component CircleGauge: Item { - id: gaugeRoot - - property real value: 0 - property string label: "" - property string sublabel: "" - property string detail: "" - property color accentColor: Theme.primary - property color detailColor: Theme.surfaceVariantText - - readonly property real thickness: Math.max(4, Math.min(width, height) / 15) - readonly property real glowExtra: thickness * 1.4 - readonly property real arcPadding: (thickness + glowExtra) / 2 - - readonly property real innerDiameter: width - (arcPadding + thickness + glowExtra) * 2 - readonly property real maxTextWidth: innerDiameter * 0.9 - readonly property real baseLabelSize: Math.round(width * 0.18) - readonly property real labelSize: Math.round(Math.min(baseLabelSize, maxTextWidth / Math.max(1, label.length * 0.65))) - readonly property real sublabelSize: Math.round(Math.min(width * 0.13, maxTextWidth / Math.max(1, sublabel.length * 0.7))) - readonly property real detailSize: Math.round(Math.min(width * 0.12, maxTextWidth / Math.max(1, detail.length * 0.65))) - - property real animValue: 0 - - onValueChanged: animValue = Math.min(1, Math.max(0, value)) - - Behavior on animValue { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Easing.OutCubic - } - } - - Component.onCompleted: animValue = Math.min(1, Math.max(0, value)) - - Canvas { - id: glowCanvas - anchors.fill: parent - onPaint: { - const ctx = getContext("2d"); - ctx.reset(); - const cx = width / 2; - const cy = height / 2; - const radius = (Math.min(width, height) / 2) - gaugeRoot.arcPadding; - const startAngle = -Math.PI * 0.5; - const endAngle = Math.PI * 1.5; - - ctx.lineCap = "round"; - - if (gaugeRoot.animValue > 0) { - const prog = startAngle + (endAngle - startAngle) * gaugeRoot.animValue; - ctx.beginPath(); - ctx.arc(cx, cy, radius, startAngle, prog); - ctx.strokeStyle = Qt.rgba(gaugeRoot.accentColor.r, gaugeRoot.accentColor.g, gaugeRoot.accentColor.b, 0.2); - ctx.lineWidth = gaugeRoot.thickness + gaugeRoot.glowExtra; - ctx.stroke(); - } - } - - Connections { - target: gaugeRoot - function onAnimValueChanged() { - glowCanvas.requestPaint(); - } - function onAccentColorChanged() { - glowCanvas.requestPaint(); - } - function onWidthChanged() { - glowCanvas.requestPaint(); - } - function onHeightChanged() { - glowCanvas.requestPaint(); - } - } - - Component.onCompleted: requestPaint() - } - - Canvas { - id: arcCanvas - anchors.fill: parent - onPaint: { - const ctx = getContext("2d"); - ctx.reset(); - const cx = width / 2; - const cy = height / 2; - const radius = (Math.min(width, height) / 2) - gaugeRoot.arcPadding; - const startAngle = -Math.PI * 0.5; - const endAngle = Math.PI * 1.5; - - ctx.lineCap = "round"; - - ctx.beginPath(); - ctx.arc(cx, cy, radius, startAngle, endAngle); - ctx.strokeStyle = Qt.rgba(gaugeRoot.accentColor.r, gaugeRoot.accentColor.g, gaugeRoot.accentColor.b, 0.1); - ctx.lineWidth = gaugeRoot.thickness; - ctx.stroke(); - - if (gaugeRoot.animValue > 0) { - const prog = startAngle + (endAngle - startAngle) * gaugeRoot.animValue; - ctx.beginPath(); - ctx.arc(cx, cy, radius, startAngle, prog); - ctx.strokeStyle = gaugeRoot.accentColor; - ctx.lineWidth = gaugeRoot.thickness; - ctx.stroke(); - } - } - - Connections { - target: gaugeRoot - function onAnimValueChanged() { - arcCanvas.requestPaint(); - } - function onAccentColorChanged() { - arcCanvas.requestPaint(); - } - function onWidthChanged() { - arcCanvas.requestPaint(); - } - function onHeightChanged() { - arcCanvas.requestPaint(); - } - } - - Component.onCompleted: requestPaint() - } - - Column { - anchors.centerIn: parent - spacing: 1 - - StyledText { - text: gaugeRoot.label - font.pixelSize: gaugeRoot.labelSize - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: gaugeRoot.sublabel - font.pixelSize: gaugeRoot.sublabelSize - font.weight: Font.Medium - color: gaugeRoot.accentColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: gaugeRoot.detail - font.pixelSize: gaugeRoot.detailSize - font.family: SettingsData.monoFontFamily - color: gaugeRoot.detailColor - anchors.horizontalCenter: parent.horizontalCenter - visible: gaugeRoot.detail.length > 0 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessesView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessesView.qml deleted file mode 100644 index 181cf15..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessesView.qml +++ /dev/null @@ -1,769 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string searchText: "" - property string expandedPid: "" - property var contextMenu: null - property string processFilter: "all" // "all", "user", "system" - - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property int forceRefreshCount: 0 - - readonly property bool pauseUpdates: (contextMenu?.visible ?? false) || expandedPid.length > 0 - readonly property bool shouldUpdate: !pauseUpdates || forceRefreshCount > 0 - property var cachedProcesses: [] - - signal openContextMenuRequested(int index, real x, real y, bool fromKeyboard) - - onFilteredProcessesChanged: { - if (!shouldUpdate) - return; - cachedProcesses = filteredProcesses; - if (forceRefreshCount > 0) - forceRefreshCount--; - } - - onShouldUpdateChanged: { - if (shouldUpdate) - cachedProcesses = filteredProcesses; - } - - readonly property var filteredProcesses: { - if (!DgopService.allProcesses || DgopService.allProcesses.length === 0) - return []; - - let procs = DgopService.allProcesses.slice(); - - if (processFilter === "user") { - procs = procs.filter(p => p.username === UserInfoService.username); - } else if (processFilter === "system") { - procs = procs.filter(p => p.username !== UserInfoService.username); - } - - if (searchText.length > 0) { - const search = searchText.toLowerCase(); - procs = procs.filter(p => { - const cmd = (p.command || "").toLowerCase(); - const fullCmd = (p.fullCommand || "").toLowerCase(); - const pid = p.pid.toString(); - return cmd.includes(search) || fullCmd.includes(search) || pid.includes(search); - }); - } - - const asc = DgopService.sortAscending; - procs.sort((a, b) => { - let valueA, valueB, result; - switch (DgopService.currentSort) { - case "cpu": - valueA = a.cpu || 0; - valueB = b.cpu || 0; - result = valueB - valueA; - break; - case "memory": - valueA = a.memoryKB || 0; - valueB = b.memoryKB || 0; - result = valueB - valueA; - break; - case "name": - valueA = (a.command || "").toLowerCase(); - valueB = (b.command || "").toLowerCase(); - result = valueA.localeCompare(valueB); - break; - case "pid": - valueA = a.pid || 0; - valueB = b.pid || 0; - result = valueA - valueB; - break; - default: - return 0; - } - return asc ? -result : result; - }); - - return procs; - } - - function selectNext() { - if (cachedProcesses.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, cachedProcesses.length - 1); - ensureVisible(); - } - - function selectPrevious() { - if (cachedProcesses.length === 0) - return; - keyboardNavigationActive = true; - if (selectedIndex <= 0) { - selectedIndex = -1; - keyboardNavigationActive = false; - return; - } - selectedIndex = selectedIndex - 1; - ensureVisible(); - } - - function selectFirst() { - if (cachedProcesses.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = 0; - ensureVisible(); - } - - function selectLast() { - if (cachedProcesses.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = cachedProcesses.length - 1; - ensureVisible(); - } - - function toggleExpand() { - if (selectedIndex < 0 || selectedIndex >= cachedProcesses.length) - return; - const process = cachedProcesses[selectedIndex]; - const pidStr = (process?.pid ?? -1).toString(); - expandedPid = (expandedPid === pidStr) ? "" : pidStr; - } - - function openContextMenu() { - if (selectedIndex < 0 || selectedIndex >= cachedProcesses.length) - return; - const delegate = processListView.itemAtIndex(selectedIndex); - if (!delegate) - return; - const process = cachedProcesses[selectedIndex]; - if (!process || !contextMenu) - return; - contextMenu.processData = process; - const itemPos = delegate.mapToItem(contextMenu.parent, delegate.width / 2, delegate.height / 2); - contextMenu.parentFocusItem = root; - contextMenu.show(itemPos.x, itemPos.y, true); - } - - function reset() { - selectedIndex = -1; - keyboardNavigationActive = false; - expandedPid = ""; - } - - function forceRefresh(count) { - forceRefreshCount = count || 3; - } - - function ensureVisible() { - if (selectedIndex < 0) - return; - processListView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function handleKey(event) { - switch (event.key) { - case Qt.Key_Down: - selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - selectPrevious(); - event.accepted = true; - return; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectNext(); - event.accepted = true; - } - return; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectPrevious(); - event.accepted = true; - } - return; - case Qt.Key_Home: - selectFirst(); - event.accepted = true; - return; - case Qt.Key_End: - selectLast(); - event.accepted = true; - return; - case Qt.Key_Space: - if (keyboardNavigationActive) { - toggleExpand(); - event.accepted = true; - } - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (keyboardNavigationActive) { - toggleExpand(); - event.accepted = true; - } - return; - case Qt.Key_Menu: - case Qt.Key_F10: - if (keyboardNavigationActive && selectedIndex >= 0) { - openContextMenu(); - event.accepted = true; - } - return; - } - } - - Component.onCompleted: { - DgopService.addRef(["processes", "cpu", "memory", "system"]); - cachedProcesses = filteredProcesses; - } - - Component.onDestruction: { - DgopService.removeRef(["processes", "cpu", "memory", "system"]); - } - - ColumnLayout { - anchors.fill: parent - spacing: 0 - - Item { - Layout.fillWidth: true - Layout.preferredHeight: 36 - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: 0 - - SortableHeader { - Layout.fillWidth: true - Layout.minimumWidth: 200 - text: I18n.tr("Name") - sortKey: "name" - currentSort: DgopService.currentSort - sortAscending: DgopService.sortAscending - onClicked: DgopService.toggleSort("name") - alignment: Text.AlignLeft - } - - SortableHeader { - Layout.preferredWidth: 100 - text: "CPU" - sortKey: "cpu" - currentSort: DgopService.currentSort - sortAscending: DgopService.sortAscending - onClicked: DgopService.toggleSort("cpu") - } - - SortableHeader { - Layout.preferredWidth: 100 - text: I18n.tr("Memory") - sortKey: "memory" - currentSort: DgopService.currentSort - sortAscending: DgopService.sortAscending - onClicked: DgopService.toggleSort("memory") - } - - SortableHeader { - Layout.preferredWidth: 80 - text: "PID" - sortKey: "pid" - currentSort: DgopService.currentSort - sortAscending: DgopService.sortAscending - onClicked: DgopService.toggleSort("pid") - } - - Item { - Layout.preferredWidth: 40 - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: Theme.outlineLight - } - - DankListView { - id: processListView - - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - spacing: 2 - - add: root.searchText.length > 0 ? ListViewTransitions.add : null - remove: root.searchText.length > 0 ? ListViewTransitions.remove : null - displaced: root.searchText.length > 0 ? ListViewTransitions.displaced : null - move: root.searchText.length > 0 ? ListViewTransitions.move : null - - model: ScriptModel { - values: root.cachedProcesses - objectProp: "pid" - } - - delegate: ProcessItem { - required property var modelData - required property int index - - width: processListView.width - process: modelData - isExpanded: root.expandedPid === (modelData?.pid ?? -1).toString() - isSelected: root.keyboardNavigationActive && root.selectedIndex === index - contextMenu: root.contextMenu - onToggleExpand: { - const pidStr = (modelData?.pid ?? -1).toString(); - root.expandedPid = (root.expandedPid === pidStr) ? "" : pidStr; - } - onClicked: { - root.keyboardNavigationActive = true; - root.selectedIndex = index; - } - onContextMenuRequested: (mouseX, mouseY) => { - if (root.contextMenu) { - root.contextMenu.processData = modelData; - root.contextMenu.parentFocusItem = root; - const globalPos = mapToItem(root.contextMenu.parent, mouseX, mouseY); - root.contextMenu.show(globalPos.x, globalPos.y, false); - } - } - } - - Rectangle { - anchors.centerIn: parent - width: 300 - height: 100 - radius: Theme.cornerRadius - color: "transparent" - visible: root.cachedProcesses.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: root.searchText.length > 0 ? "search_off" : "hourglass_empty" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No matching processes", "empty state in process list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - visible: root.searchText.length > 0 - } - } - } - } - } - - component SortableHeader: Item { - id: headerItem - - property string text: "" - property string sortKey: "" - property string currentSort: "" - property bool sortAscending: false - property int alignment: Text.AlignHCenter - - signal clicked - - readonly property bool isActive: sortKey === currentSort - - height: 36 - - Rectangle { - anchors.fill: parent - anchors.margins: 2 - radius: Theme.cornerRadius - color: headerItem.isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : (headerMouseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.06) : "transparent") - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - } - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: 4 - - Item { - Layout.fillWidth: headerItem.alignment === Text.AlignLeft - visible: headerItem.alignment !== Text.AlignLeft - } - - StyledText { - text: headerItem.text - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: headerItem.isActive ? Font.Bold : Font.Medium - color: headerItem.isActive ? Theme.primary : Theme.surfaceText - opacity: headerItem.isActive ? 1 : 0.8 - } - - DankIcon { - name: headerItem.sortAscending ? "arrow_upward" : "arrow_downward" - size: Theme.fontSizeSmall - color: Theme.primary - visible: headerItem.isActive - } - - Item { - Layout.fillWidth: headerItem.alignment !== Text.AlignLeft - visible: headerItem.alignment === Text.AlignLeft - } - } - - MouseArea { - id: headerMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: headerItem.clicked() - } - } - - component ProcessItem: Rectangle { - id: processItemRoot - - property var process: null - property bool isExpanded: false - property bool isSelected: false - property var contextMenu: null - - signal toggleExpand - signal clicked - signal contextMenuRequested(real mouseX, real mouseY) - - readonly property int processPid: process?.pid ?? 0 - readonly property real processCpu: process?.cpu ?? 0 - readonly property int processMemKB: process?.memoryKB ?? 0 - readonly property string processCmd: process?.command ?? "" - readonly property string processFullCmd: process?.fullCommand ?? processCmd - - height: isExpanded ? (44 + expandedRect.height + Theme.spacingXS) : 44 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15); - return processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"; - } - border.color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - return processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"; - } - border.width: 1 - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - MouseArea { - id: processMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - processItemRoot.contextMenuRequested(mouse.x, mouse.y); - return; - } - processItemRoot.clicked(); - processItemRoot.toggleExpand(); - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 44 - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: 0 - - Item { - Layout.fillWidth: true - Layout.minimumWidth: 200 - height: parent.height - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: DgopService.getProcessIcon(processItemRoot.processCmd) - size: Theme.iconSize - 4 - color: { - if (processItemRoot.processCpu > 80) - return Theme.error; - if (processItemRoot.processCpu > 50) - return Theme.warning; - return Theme.surfaceText; - } - opacity: 0.8 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: processItemRoot.processCmd - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: Math.min(implicitWidth, 280) - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Item { - Layout.preferredWidth: 100 - height: parent.height - - Rectangle { - anchors.centerIn: parent - width: 70 - height: 24 - radius: Theme.cornerRadius - color: { - if (processItemRoot.processCpu > 80) - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.15); - if (processItemRoot.processCpu > 50) - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12); - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.06); - } - - StyledText { - anchors.centerIn: parent - text: DgopService.formatCpuUsage(processItemRoot.processCpu) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: { - if (processItemRoot.processCpu > 80) - return Theme.error; - if (processItemRoot.processCpu > 50) - return Theme.warning; - return Theme.surfaceText; - } - } - } - } - - Item { - Layout.preferredWidth: 100 - height: parent.height - - Rectangle { - anchors.centerIn: parent - width: 70 - height: 24 - radius: Theme.cornerRadius - color: { - if (processItemRoot.processMemKB > 2 * 1024 * 1024) - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.15); - if (processItemRoot.processMemKB > 1024 * 1024) - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12); - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.06); - } - - StyledText { - anchors.centerIn: parent - text: DgopService.formatMemoryUsage(processItemRoot.processMemKB) - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - font.weight: Font.Bold - color: { - if (processItemRoot.processMemKB > 2 * 1024 * 1024) - return Theme.error; - if (processItemRoot.processMemKB > 1024 * 1024) - return Theme.warning; - return Theme.surfaceText; - } - } - } - } - - Item { - Layout.preferredWidth: 80 - height: parent.height - - StyledText { - anchors.centerIn: parent - text: processItemRoot.processPid > 0 ? processItemRoot.processPid.toString() : "" - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - } - } - - Item { - Layout.preferredWidth: 40 - height: parent.height - - DankIcon { - anchors.centerIn: parent - name: processItemRoot.isExpanded ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - } - } - } - } - - Rectangle { - id: expandedRect - width: parent.width - Theme.spacingM * 2 - height: processItemRoot.isExpanded ? (expandedContent.implicitHeight + Theme.spacingS * 2) : 0 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - 2 - color: Qt.rgba(Theme.surfaceContainerHigh.r, Theme.surfaceContainerHigh.g, Theme.surfaceContainerHigh.b, 0.6) - clip: true - visible: processItemRoot.isExpanded - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Column { - id: expandedContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingS - spacing: Theme.spacingXS - - RowLayout { - width: parent.width - spacing: Theme.spacingS - - StyledText { - id: cmdLabel - text: I18n.tr("Full Command:", "process detail label") - font.pixelSize: Theme.fontSizeSmall - 2 - font.weight: Font.Bold - color: Theme.surfaceVariantText - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - id: cmdText - text: processItemRoot.processFullCmd - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - elide: Text.ElideMiddle - } - - Rectangle { - id: copyBtn - Layout.preferredWidth: 24 - Layout.preferredHeight: 24 - Layout.alignment: Qt.AlignVCenter - radius: Theme.cornerRadius - 2 - color: copyMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "content_copy" - size: 14 - color: copyMouseArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: copyMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", processItemRoot.processFullCmd]); - } - } - } - } - - Row { - spacing: Theme.spacingL - - Row { - spacing: Theme.spacingXS - - StyledText { - text: "PPID:" - font.pixelSize: Theme.fontSizeSmall - 2 - font.weight: Font.Bold - color: Theme.surfaceVariantText - } - - StyledText { - text: (processItemRoot.process?.ppid ?? 0) > 0 ? processItemRoot.process.ppid.toString() : "--" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - } - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: "Mem:" - font.pixelSize: Theme.fontSizeSmall - 2 - font.weight: Font.Bold - color: Theme.surfaceVariantText - } - - StyledText { - text: (processItemRoot.process?.memoryPercent ?? 0).toFixed(1) + "%" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/SystemView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/SystemView.qml deleted file mode 100644 index 244129d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/SystemView.qml +++ /dev/null @@ -1,386 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - Component.onCompleted: { - DgopService.addRef(["system", "cpu"]); - } - - Component.onDestruction: { - DgopService.removeRef(["system", "cpu"]); - } - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: systemInfoColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - ColumnLayout { - id: systemInfoColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "computer" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("System Information", "system info header in system monitor") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - GridLayout { - Layout.fillWidth: true - columns: 2 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingXL - - InfoRow { - label: I18n.tr("Hostname", "system info label") - value: DgopService.hostname || "--" - } - InfoRow { - label: I18n.tr("Distribution", "system info label") - value: DgopService.distribution || "--" - } - InfoRow { - label: I18n.tr("Kernel", "system info label") - value: DgopService.kernelVersion || "--" - } - InfoRow { - label: I18n.tr("Architecture", "system info label") - value: DgopService.architecture || "--" - } - InfoRow { - label: I18n.tr("CPU") - value: DgopService.cpuModel || ("" + DgopService.cpuCores + " cores") - } - InfoRow { - label: I18n.tr("Uptime") - value: DgopService.uptime || "--" - } - InfoRow { - label: I18n.tr("Load Average", "system info label") - value: DgopService.loadAverage || "--" - } - InfoRow { - label: I18n.tr("Processes") - value: DgopService.processCount > 0 ? DgopService.processCount.toString() : "--" - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingS - - DankIcon { - name: "developer_board" - size: Theme.iconSize - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("GPU Monitoring", "gpu section header in system monitor") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: Theme.outlineLight - } - - DankListView { - id: gpuListView - - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - spacing: 8 - - model: DgopService.availableGpus - - delegate: Rectangle { - required property var modelData - required property int index - - width: gpuListView.width - height: 80 - radius: Theme.cornerRadius - color: { - const vendor = (modelData?.vendor ?? "").toLowerCase(); - if (vendor.includes("nvidia")) - return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.08); - if (vendor.includes("amd")) - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08); - if (vendor.includes("intel")) - return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: { - const vendor = (modelData?.vendor ?? "").toLowerCase(); - if (vendor.includes("nvidia")) - return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.2); - if (vendor.includes("amd")) - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2); - if (vendor.includes("intel")) - return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.2); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2); - } - border.width: 1 - - readonly property bool tempEnabled: { - const pciId = modelData?.pciId ?? ""; - if (!pciId) - return false; - return SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.indexOf(pciId) !== -1 : false; - } - - RowLayout { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "developer_board" - size: Theme.iconSize + 4 - color: { - const vendor = (modelData?.vendor ?? "").toLowerCase(); - if (vendor.includes("nvidia")) - return Theme.success; - if (vendor.includes("amd")) - return Theme.error; - if (vendor.includes("intel")) - return Theme.info; - return Theme.surfaceVariantText; - } - } - - Column { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: modelData?.displayName ?? I18n.tr("Unknown GPU", "fallback gpu name") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - } - - Row { - spacing: Theme.spacingS - - StyledText { - text: modelData?.vendor ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData?.driver ?? "").length > 0 - } - - StyledText { - text: modelData?.driver ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData?.driver ?? "").length > 0 - } - } - - StyledText { - text: modelData?.pciId ?? "" - font.pixelSize: Theme.fontSizeSmall - 2 - font.family: SettingsData.monoFontFamily - color: Theme.surfaceVariantText - opacity: 0.7 - } - } - - Rectangle { - width: 70 - height: 32 - radius: Theme.cornerRadius - color: parent.parent.tempEnabled ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.15) - border.color: tempMouseArea.containsMouse ? Theme.outline : "transparent" - border.width: 1 - - Row { - id: tempRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "thermostat" - size: 16 - color: { - if (!parent.parent.parent.parent.tempEnabled) - return Theme.surfaceVariantText; - const temp = modelData?.temperature ?? 0; - if (temp > 85) - return Theme.error; - if (temp > 70) - return Theme.warning; - return Theme.surfaceText; - } - opacity: parent.parent.parent.parent.tempEnabled ? 1 : 0.5 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!parent.parent.parent.parent.tempEnabled) - return I18n.tr("Off"); - const temp = modelData?.temperature ?? 0; - return temp > 0 ? (temp.toFixed(0) + "°C") : "--"; - } - font.pixelSize: Theme.fontSizeSmall - font.family: parent.parent.parent.parent.tempEnabled ? SettingsData.monoFontFamily : "" - font.weight: parent.parent.parent.parent.tempEnabled ? Font.Bold : Font.Normal - color: { - if (!parent.parent.parent.parent.tempEnabled) - return Theme.surfaceVariantText; - const temp = modelData?.temperature ?? 0; - if (temp > 85) - return Theme.error; - if (temp > 70) - return Theme.warning; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: tempMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const pciId = modelData?.pciId; - if (!pciId) - return; - - const enabledIds = SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.slice() : []; - const idx = enabledIds.indexOf(pciId); - const wasEnabled = idx !== -1; - - if (!wasEnabled) { - enabledIds.push(pciId); - DgopService.addGpuPciId(pciId); - } else { - enabledIds.splice(idx, 1); - DgopService.removeGpuPciId(pciId); - } - - SessionData.setEnabledGpuPciIds(enabledIds); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - } - } - } - - Rectangle { - anchors.centerIn: parent - width: 300 - height: 100 - radius: Theme.cornerRadius - color: "transparent" - visible: DgopService.availableGpus.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "developer_board_off" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No GPUs detected", "empty state in gpu list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } - - component InfoRow: RowLayout { - property string label: "" - property string value: "" - - Layout.fillWidth: true - spacing: Theme.spacingS - - StyledText { - text: label + ":" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: 100 - } - - StyledText { - text: value - font.pixelSize: Theme.fontSizeSmall - font.family: SettingsData.monoFontFamily - color: Theme.surfaceText - Layout.fillWidth: true - elide: Text.ElideRight - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AboutTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AboutTab.qml deleted file mode 100644 index 67c2c21..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AboutTab.qml +++ /dev/null @@ -1,900 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: aboutTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool isHyprland: CompositorService.isHyprland - property bool isNiri: CompositorService.isNiri - property bool isSway: CompositorService.isSway - property bool isScroll: CompositorService.isScroll - property bool isMiracle: CompositorService.isMiracle - property bool isDwl: CompositorService.isDwl - property bool isLabwc: CompositorService.isLabwc - - property string compositorName: { - if (isHyprland) - return "hyprland"; - if (isSway) - return "sway"; - if (isScroll) - return "scroll"; - if (isMiracle) - return "miracle"; - if (isDwl) - return "mangowc"; - if (isLabwc) - return "labwc"; - return "niri"; - } - - property string compositorLogo: { - if (isHyprland) - return "/assets/hyprland.svg"; - if (isSway) - return "/assets/sway.svg"; - if (isScroll) - return "/assets/sway.svg"; - if (isMiracle) - return "/assets/miraclewm.svg"; - if (isDwl) - return "/assets/mango.png"; - if (isLabwc) - return "/assets/labwc.png"; - return "/assets/niri.svg"; - } - - property string compositorUrl: { - if (isHyprland) - return "https://hypr.land"; - if (isSway) - return "https://swaywm.org"; - if (isScroll) - return "https://github.com/dawsers/scroll"; - if (isMiracle) - return "https://github.com/miracle-wm-org/miracle-wm"; - if (isDwl) - return "https://github.com/DreamMaoMao/mangowc"; - if (isLabwc) - return "https://labwc.github.io/"; - return "https://github.com/niri-wm/niri"; - } - - property string compositorTooltip: { - if (isHyprland) - return I18n.tr("Hyprland Website"); - if (isSway) - return I18n.tr("Sway Website"); - if (isScroll) - return I18n.tr("Scroll GitHub"); - if (isMiracle) - return I18n.tr("Scroll GitHub"); - if (isDwl) - return I18n.tr("mangowc GitHub"); - if (isLabwc) - return I18n.tr("LabWC Website"); - return I18n.tr("niri GitHub"); - } - - property string dmsDiscordUrl: "https://discord.gg/ppWTpKmPgT" - property string dmsDiscordTooltip: I18n.tr("niri/dms Discord") - - property string compositorDiscordUrl: { - if (isHyprland) - return "https://discord.com/invite/hQ9XvMUjjr"; - if (isDwl) - return "https://discord.gg/CPjbDxesh5"; - return ""; - } - - property string compositorDiscordTooltip: { - if (isHyprland) - return I18n.tr("Hyprland Discord Server"); - if (isDwl) - return I18n.tr("mangowc Discord Server"); - return ""; - } - - property string redditUrl: "https://reddit.com/r/niri" - property string redditTooltip: I18n.tr("r/niri Subreddit") - - property string ircUrl: "https://web.libera.chat/gamja/?channels=#labwc" - property string ircTooltip: I18n.tr("LabWC IRC Channel") - - property bool showMatrix: isNiri && !isHyprland && !isSway && !isScroll && !isMiracle && !isDwl && !isLabwc - property bool showCompositorDiscord: isHyprland || isDwl - property bool showReddit: isNiri && !isHyprland && !isSway && !isScroll && !isMiracle && !isDwl && !isLabwc - property bool showIrc: isLabwc - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - // ASCII Art Header - StyledRect { - width: parent.width - height: asciiSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: asciiSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: parent.width < 350 ? Theme.spacingM : Theme.spacingL - - property bool compactLogo: parent.width < 400 - property bool hideLogo: parent.width < 280 - - Image { - id: logoImage - - visible: !parent.hideLogo - anchors.verticalCenter: parent.verticalCenter - width: parent.compactLogo ? 80 : 120 - height: width * (569.94629 / 506.50931) - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg" - layer.enabled: true - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - Text { - anchors.verticalCenter: parent.verticalCenter - text: "DANK LINUX" - font.pixelSize: parent.compactLogo ? 32 : 48 - font.weight: Font.Bold - font.family: interFont.name - color: Theme.surfaceText - antialiasing: true - - FontLoader { - id: interFont - source: Qt.resolvedUrl("../../assets/fonts/inter/InterVariable.ttf") - } - } - } - - StyledText { - text: { - if (!SystemUpdateService.shellVersion && !DMSService.cliVersion) - return "dms"; - - let version = SystemUpdateService.shellVersion || ""; - let cliVersion = DMSService.cliVersion || ""; - - // Debian/Ubuntu/OpenSUSE git format: 1.0.3+git2264.c5c5ce84 - let match = version.match(/^([\d.]+)\+git(\d+)\./); - if (match) { - return `dms (git) v${match[1]}-${match[2]}`; - } - - // Fedora COPR git format: 0.0.git.2267.d430cae9 - match = version.match(/^[\d.]+\.git\.(\d+)\./); - if (match) { - function extractBaseVersion(value) { - if (!value) - return ""; - let baseMatch = value.match(/(\d+\.\d+\.\d+)/); - if (baseMatch) - return baseMatch[1]; - baseMatch = value.match(/(\d+\.\d+)/); - if (baseMatch) - return baseMatch[1]; - return ""; - } - - let baseVersion = extractBaseVersion(cliVersion); - if (!baseVersion) - baseVersion = extractBaseVersion(SystemUpdateService.semverVersion); - if (baseVersion) { - return `dms (git) v${baseVersion}-${match[1]}`; - } - return `dms (git) v${match[1]}`; - } - - // Stable release format: 1.0.3 - match = version.match(/^([\d.]+)$/); - if (match) { - return `dms v${match[1]}`; - } - - if (!version && cliVersion) { - match = cliVersion.match(/^([\d.]+)\+git(\d+)\./); - if (match) { - return `dms (git) v${match[1]}-${match[2]}`; - } - match = cliVersion.match(/^([\d.]+)$/); - if (match) { - return `dms v${match[1]}`; - } - return `dms ${cliVersion}`; - } - - return `dms ${version}`; - } - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Bold - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - - StyledText { - visible: SystemUpdateService.shellCodename.length > 0 - text: `"${SystemUpdateService.shellCodename}"` - font.pixelSize: Theme.fontSizeMedium - font.italic: true - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - - Row { - id: resourceButtonsRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingS - - property bool compactMode: parent.width < 450 - - DankButton { - id: docsButton - text: resourceButtonsRow.compactMode ? "" : I18n.tr("Docs") - iconName: "menu_book" - iconSize: 18 - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: Qt.openUrlExternally("https://danklinux.com/docs") - onHoveredChanged: { - if (hovered) - resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Docs") + " - danklinux.com/docs" : "danklinux.com/docs", docsButton, 0, 0, "bottom"); - else - resourceTooltip.hide(); - } - } - - DankButton { - id: pluginsButton - text: resourceButtonsRow.compactMode ? "" : I18n.tr("Plugins") - iconName: "extension" - iconSize: 18 - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: Qt.openUrlExternally("https://plugins.danklinux.com") - onHoveredChanged: { - if (hovered) - resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Plugins") + " - plugins.danklinux.com" : "plugins.danklinux.com", pluginsButton, 0, 0, "bottom"); - else - resourceTooltip.hide(); - } - } - - DankButton { - id: githubButton - text: resourceButtonsRow.compactMode ? "" : I18n.tr("GitHub") - iconName: "code" - iconSize: 18 - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: Qt.openUrlExternally("https://github.com/AvengeMedia/DankMaterialShell") - onHoveredChanged: { - if (hovered) - resourceTooltip.show(resourceButtonsRow.compactMode ? "GitHub - AvengeMedia/DankMaterialShell" : "github.com/AvengeMedia/DankMaterialShell", githubButton, 0, 0, "bottom"); - else - resourceTooltip.hide(); - } - } - - DankButton { - id: kofiButton - text: resourceButtonsRow.compactMode ? "" : I18n.tr("Ko-fi") - iconName: "favorite" - iconSize: 18 - backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - textColor: Theme.primary - onClicked: Qt.openUrlExternally("https://ko-fi.com/danklinux") - onHoveredChanged: { - if (hovered) - resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Ko-fi") + " - ko-fi.com/danklinux" : "ko-fi.com/danklinux", kofiButton, 0, 0, "bottom"); - else - resourceTooltip.hide(); - } - } - } - - DankTooltipV2 { - id: resourceTooltip - } - - Item { - id: communityIcons - anchors.horizontalCenter: parent.horizontalCenter - height: 24 - width: { - let baseWidth = compositorButton.width + dmsDiscordButton.width + Theme.spacingM; - if (showMatrix) { - baseWidth += matrixButton.width + 4; - } - if (showIrc) { - baseWidth += ircButton.width + Theme.spacingM; - } - if (showCompositorDiscord) { - baseWidth += compositorDiscordButton.width + Theme.spacingM; - } - if (showReddit) { - baseWidth += redditButton.width + Theme.spacingM; - } - return baseWidth; - } - - Item { - id: compositorButton - width: 24 - height: 24 - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: -2 - x: 0 - - property bool hovered: false - property string tooltipText: compositorTooltip - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + compositorLogo - sourceSize: Qt.size(24, 24) - smooth: true - fillMode: Image.PreserveAspectFit - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally(compositorUrl) - } - } - - Item { - id: matrixButton - width: 30 - height: 24 - x: compositorButton.x + compositorButton.width + 4 - visible: showMatrix - - property bool hovered: false - property string tooltipText: I18n.tr("niri Matrix Chat") - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/matrix-logo-white.svg" - sourceSize: Qt.size(28, 18) - smooth: true - fillMode: Image.PreserveAspectFit - layer.enabled: true - - layer.effect: MultiEffect { - colorization: 1 - colorizationColor: Theme.surfaceText - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally("https://matrix.to/#/#niri:matrix.org") - } - } - - Item { - id: ircButton - width: 24 - height: 24 - x: compositorButton.x + compositorButton.width + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: showIrc - - property bool hovered: false - property string tooltipText: ircTooltip - - DankIcon { - anchors.centerIn: parent - name: "forum" - size: 20 - color: Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally(ircUrl) - } - } - - Item { - id: dmsDiscordButton - width: 20 - height: 20 - x: { - if (showMatrix) - return matrixButton.x + matrixButton.width + Theme.spacingM; - if (showIrc) - return ircButton.x + ircButton.width + Theme.spacingM; - return compositorButton.x + compositorButton.width + Theme.spacingM; - } - anchors.verticalCenter: parent.verticalCenter - - property bool hovered: false - property string tooltipText: dmsDiscordTooltip - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/discord.svg" - sourceSize: Qt.size(20, 20) - smooth: true - fillMode: Image.PreserveAspectFit - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally(dmsDiscordUrl) - } - } - - Item { - id: compositorDiscordButton - width: 20 - height: 20 - x: dmsDiscordButton.x + dmsDiscordButton.width + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: showCompositorDiscord - - property bool hovered: false - property string tooltipText: compositorDiscordTooltip - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/discord.svg" - sourceSize: Qt.size(20, 20) - smooth: true - fillMode: Image.PreserveAspectFit - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally(compositorDiscordUrl) - } - } - - Item { - id: redditButton - width: 20 - height: 20 - x: showCompositorDiscord ? compositorDiscordButton.x + compositorDiscordButton.width + Theme.spacingM : dmsDiscordButton.x + dmsDiscordButton.width + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: showReddit - - property bool hovered: false - property string tooltipText: redditTooltip - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/reddit.svg" - sourceSize: Qt.size(20, 20) - smooth: true - fillMode: Image.PreserveAspectFit - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: parent.hovered = true - onExited: parent.hovered = false - onClicked: Qt.openUrlExternally(redditUrl) - } - } - } - } - } - - // Project Information - StyledRect { - width: parent.width - height: projectSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: projectSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("About") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr('dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.').arg(Theme.primary) - textFormat: Text.RichText - font.pixelSize: Theme.fontSizeMedium - linkColor: Theme.primary - onLinkActivated: url => Qt.openUrlExternally(url) - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - - StyledRect { - visible: DMSService.isConnected - width: parent.width - height: backendSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: backendSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "dns" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Backend") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingL - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("Version") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: DMSService.cliVersion || "—" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - width: 1 - height: 32 - color: Theme.outlineVariant - } - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("API") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `v${DMSService.apiVersion}` - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - width: 1 - height: 32 - color: Theme.outlineVariant - } - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: 4 - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Connected") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: DMSService.capabilities.length > 0 - - StyledText { - text: I18n.tr("Capabilities") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Flow { - width: parent.width - spacing: 6 - - Repeater { - model: DMSService.capabilities - - Rectangle { - width: capText.implicitWidth + 16 - height: 26 - radius: 13 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - StyledText { - id: capText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: toolsSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: toolsSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "build" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Tools") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - DankButton { - text: I18n.tr("Show Welcome") - iconName: "waving_hand" - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: FirstLaunchService.showWelcome() - } - - DankButton { - text: I18n.tr("System Check") - iconName: "vital_signs" - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: FirstLaunchService.showDoctor() - } - } - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr('MIT License').arg(Theme.surfaceVariantText) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - textFormat: Text.RichText - wrapMode: Text.NoWrap - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - - // Community tooltip - positioned absolutely above everything - Rectangle { - id: communityTooltip - parent: aboutTab - z: 1000 - - property var hoveredButton: { - if (compositorButton.hovered) - return compositorButton; - if (matrixButton.visible && matrixButton.hovered) - return matrixButton; - if (ircButton.visible && ircButton.hovered) - return ircButton; - if (dmsDiscordButton.hovered) - return dmsDiscordButton; - if (compositorDiscordButton.visible && compositorDiscordButton.hovered) - return compositorDiscordButton; - if (redditButton.visible && redditButton.hovered) - return redditButton; - return null; - } - - property string tooltipText: hoveredButton ? hoveredButton.tooltipText : "" - - visible: hoveredButton !== null && tooltipText !== "" - width: tooltipLabel.implicitWidth + 24 - height: tooltipLabel.implicitHeight + 12 - - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 0 - border.color: Theme.outlineMedium - - x: hoveredButton ? hoveredButton.mapToItem(aboutTab, hoveredButton.width / 2, 0).x - width / 2 : 0 - y: hoveredButton ? communityIcons.mapToItem(aboutTab, 0, 0).y - height - 8 : 0 - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: communityTooltip.radius - targetColor: communityTooltip.color - borderColor: communityTooltip.border.color - borderWidth: communityTooltip.border.width - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowEnabled: Theme.elevationEnabled - } - - StyledText { - id: tooltipLabel - anchors.centerIn: parent - text: communityTooltip.tooltipText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml deleted file mode 100644 index c054791..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml +++ /dev/null @@ -1,747 +0,0 @@ -import QtQuick -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var outputDevices: [] - property var inputDevices: [] - property bool showEditDialog: false - property var editingDevice: null - property string editingDeviceType: "" - property string newDeviceName: "" - property bool isReloadingAudio: false - property var hiddenOutputDeviceNames: SessionData.hiddenOutputDeviceNames ?? [] - property var hiddenInputDeviceNames: SessionData.hiddenInputDeviceNames ?? [] - property bool showHiddenOutputDevices: false - property bool showHiddenInputDevices: false - - function persistHiddenOutputDeviceNames(deviceNames) { - const uniqueNames = [...new Set(deviceNames)]; - hiddenOutputDeviceNames = uniqueNames; - SessionData.setHiddenOutputDeviceNames(uniqueNames); - } - - function persistHiddenInputDeviceNames(deviceNames) { - const uniqueNames = [...new Set(deviceNames)]; - hiddenInputDeviceNames = uniqueNames; - SessionData.setHiddenInputDeviceNames(uniqueNames); - } - - function updateDeviceList() { - const allNodes = Pipewire.nodes.values; - - // Sort devices: active first, then alphabetically by name - const sortDevices = (a, b) => { - if (a === AudioService.sink && b !== AudioService.sink) - return -1; - if (b === AudioService.sink && a !== AudioService.sink) - return 1; - const nameA = AudioService.displayName(a).toLowerCase(); - const nameB = AudioService.displayName(b).toLowerCase(); - return nameA.localeCompare(nameB); - }; - - const outputs = allNodes.filter(node => { - return node.audio && node.isSink && !node.isStream; - }); - outputDevices = outputs.sort(sortDevices); - - const inputs = allNodes.filter(node => { - return node.audio && !node.isSink && !node.isStream; - }); - - const sortInputs = (a, b) => { - if (a === AudioService.source && b !== AudioService.source) - return -1; - if (b === AudioService.source && a !== AudioService.source) - return 1; - const nameA = AudioService.displayName(a).toLowerCase(); - const nameB = AudioService.displayName(b).toLowerCase(); - return nameA.localeCompare(nameB); - }; - - inputDevices = inputs.sort(sortInputs); - } - - Component.onCompleted: { - hiddenOutputDeviceNames = SessionData.hiddenOutputDeviceNames ?? []; - hiddenInputDeviceNames = SessionData.hiddenInputDeviceNames ?? []; - updateDeviceList(); - } - - Connections { - target: Pipewire.nodes - function onValuesChanged() { - root.updateDeviceList(); - } - } - - Connections { - target: AudioService - function onWireplumberReloadStarted() { - root.isReloadingAudio = true; - } - function onWireplumberReloadCompleted(success) { - Qt.callLater(() => { - delayTimer.start(); - }); - } - function onDeviceAliasChanged(nodeName, newAlias) { - root.updateDeviceList(); - } - } - - Timer { - id: delayTimer - interval: 2000 - repeat: false - onTriggered: { - root.isReloadingAudio = false; - root.updateDeviceList(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "audio" - tags: ["audio", "device", "output", "speaker"] - title: I18n.tr("Output Devices", "Audio settings: speaker/headphone devices") - settingKey: "audioOutputDevices" - iconName: "volume_up" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Set custom names for your audio output devices", "Audio settings description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Repeater { - model: root.outputDevices.filter(d => !root.hiddenOutputDeviceNames.includes(d.name)) - - delegate: Column { - required property var modelData - width: parent?.width ?? 0 - spacing: 0 - - DeviceAliasRow { - deviceNode: modelData - deviceType: "output" - showHideButton: true - - onEditRequested: device => { - root.editingDevice = device; - root.editingDeviceType = "output"; - root.newDeviceName = AudioService.displayName(device); - root.showEditDialog = true; - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - - onHideRequested: device => { - root.persistHiddenOutputDeviceNames([...root.hiddenOutputDeviceNames, device.name]); - } - } - - Item { - width: parent.width - height: 36 - - StyledText { - id: maxVolLabel - text: I18n.tr("Max Volume", "Audio settings: maximum volume limit per device") + " · " + maxVolSlider.value + "%" - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM + Theme.iconSize + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - DankSlider { - id: maxVolSlider - anchors.left: maxVolLabel.right - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - height: 36 - minimum: 100 - maximum: 200 - step: 5 - showValue: true - wheelEnabled: false - centerMinimum: true - unit: "%" - onSliderValueChanged: newValue => { - SessionData.setDeviceMaxVolume(modelData.name, newValue); - } - } - - Binding { - target: maxVolSlider - property: "value" - value: SessionData.deviceMaxVolumes[modelData.name] ?? 100 - when: !maxVolSlider.isDragging - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No output devices found", "Audio settings empty state") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: root.outputDevices.filter(d => !root.hiddenOutputDeviceNames.includes(d.name)).length === 0 && root.hiddenOutputDeviceNames.length === 0 - topPadding: Theme.spacingM - } - - Column { - width: parent.width - spacing: 0 - visible: root.hiddenOutputDeviceNames.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hidden (%1)", "count of hidden audio devices").arg(root.hiddenOutputDeviceNames.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - name: root.showHiddenOutputDevices ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.showHiddenOutputDevices = !root.showHiddenOutputDevices - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.showHiddenOutputDevices - - Repeater { - model: root.outputDevices.filter(d => root.hiddenOutputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - deviceNode: modelData - deviceType: "output" - isHidden: true - showHideButton: true - - onHideRequested: device => { - root.persistHiddenOutputDeviceNames(root.hiddenOutputDeviceNames.filter(n => n !== device.name)); - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - } - } - } - } - } - } - - SettingsCard { - tab: "audio" - tags: ["audio", "device", "input", "microphone"] - title: I18n.tr("Input Devices") - settingKey: "audioInputDevices" - iconName: "mic" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Set custom names for your audio input devices", "Audio settings description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Repeater { - model: root.inputDevices.filter(d => !root.hiddenInputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - - deviceNode: modelData - deviceType: "input" - showHideButton: true - - onEditRequested: device => { - root.editingDevice = device; - root.editingDeviceType = "input"; - root.newDeviceName = AudioService.displayName(device); - root.showEditDialog = true; - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - - onHideRequested: device => { - root.persistHiddenInputDeviceNames([...root.hiddenInputDeviceNames, device.name]); - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No input devices found", "Audio settings empty state") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: root.inputDevices.filter(d => !root.hiddenInputDeviceNames.includes(d.name)).length === 0 && root.hiddenInputDeviceNames.length === 0 - topPadding: Theme.spacingM - } - - Column { - width: parent.width - spacing: 0 - visible: root.hiddenInputDeviceNames.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hidden (%1)", "count of hidden audio devices").arg(root.hiddenInputDeviceNames.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - name: root.showHiddenInputDevices ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.showHiddenInputDevices = !root.showHiddenInputDevices - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.showHiddenInputDevices - - Repeater { - model: root.inputDevices.filter(d => root.hiddenInputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - deviceNode: modelData - deviceType: "input" - isHidden: true - showHideButton: true - - onHideRequested: device => { - root.persistHiddenInputDeviceNames(root.hiddenInputDeviceNames.filter(n => n !== device.name)); - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - } - } - } - } - } - } - } - } - - Rectangle { - id: loadingOverlay - anchors.fill: parent - color: Theme.withAlpha(Theme.surface, 0.9) - visible: root.isReloadingAudio - z: 100 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingL - - Rectangle { - width: 80 - height: 80 - radius: 40 - color: Theme.primaryContainer - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - id: spinningIcon - name: "refresh" - size: 40 - color: Theme.primary - anchors.centerIn: parent - - RotationAnimator { - target: spinningIcon - from: 0 - to: 360 - duration: 1500 - loops: Animation.Infinite - running: loadingOverlay.visible - } - } - } - - Column { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: I18n.tr("Restarting audio system...", "Loading overlay while WirePlumber restarts") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("This may take a few seconds", "Loading overlay subtitle") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - id: dialogOverlay - anchors.fill: parent - visible: root.showEditDialog - color: Theme.withAlpha(Theme.surface, 0.8) - z: 1000 - - MouseArea { - anchors.fill: parent - onClicked: { - root.showEditDialog = false; - } - } - - Rectangle { - id: editDialog - anchors.centerIn: parent - width: Math.min(500, parent.width - Theme.spacingL * 4) - height: dialogContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineMedium - - MouseArea { - anchors.fill: parent - onClicked: {} - } - - Column { - id: dialogContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.editingDeviceType === "input" ? "mic" : "speaker" - size: Theme.iconSize + 8 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - 8 - spacing: 4 - - StyledText { - text: I18n.tr("Set Custom Device Name", "Audio device rename dialog title") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - width: parent.width - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.editingDevice?.name ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - - StyledText { - visible: AudioService.hasDeviceAlias(root.editingDevice?.name ?? "") - text: I18n.tr("Original: %1", "Shows the original device name before renaming").arg(AudioService.originalName(root.editingDevice)) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - opacity: 0.7 - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Name", "Audio device rename dialog field label") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - id: nameInput - width: parent.width - placeholderText: I18n.tr("Enter device name...", "Audio device rename dialog placeholder") - text: root.newDeviceName - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - showClearButton: true - - onTextChanged: { - root.newDeviceName = text; - } - - Keys.onReturnPressed: { - if (text.trim() !== "") { - saveButtonMouseArea.clicked(null); - } - } - - Keys.onEscapePressed: { - root.showEditDialog = false; - } - - Component.onCompleted: { - Qt.callLater(() => { - forceActiveFocus(); - selectAll(); - }); - } - } - - StyledText { - width: parent.width - text: I18n.tr("Press Enter and the audio system will restart to apply the change", "Audio device rename dialog hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingM - layoutDirection: Qt.RightToLeft - - Rectangle { - id: saveButton - width: saveButtonContent.width + Theme.spacingL * 2 - height: Theme.buttonHeight - radius: Theme.cornerRadius - color: saveButtonMouseArea.containsMouse ? Theme.primaryContainer : Theme.primary - enabled: root.newDeviceName.trim() !== "" - opacity: enabled ? 1.0 : 0.5 - - Row { - id: saveButtonContent - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "check" - size: Theme.iconSize - 4 - color: Theme.onPrimary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.onPrimary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: saveButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: { - if (root.editingDevice && root.newDeviceName.trim() !== "") { - AudioService.setDeviceAlias(root.editingDevice.name, root.newDeviceName); - root.showEditDialog = false; - } - } - } - } - - Rectangle { - width: cancelButtonText.width + Theme.spacingL * 2 - height: Theme.buttonHeight - radius: Theme.cornerRadius - color: cancelButtonMouseArea.containsMouse ? Theme.surfaceHover : "transparent" - border.width: 1 - border.color: Theme.outline - - StyledText { - id: cancelButtonText - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.centerIn: parent - } - - MouseArea { - id: cancelButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.showEditDialog = false; - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml deleted file mode 100644 index d477bb9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml +++ /dev/null @@ -1,463 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - property var config: ({}) - property bool configLoaded: false - property bool configError: false - property bool saving: false - - readonly property var maxHistoryOptions: [ - { - text: "25", - value: 25 - }, - { - text: "50", - value: 50 - }, - { - text: "100", - value: 100 - }, - { - text: "200", - value: 200 - }, - { - text: "500", - value: 500 - }, - { - text: "1,000", - value: 1000 - }, - { - text: "10,000", - value: 10000 - }, - { - text: "15,000", - value: 15000 - }, - { - text: "20,000", - value: 20000 - }, - { - text: "30,000", - value: 30000 - }, - { - text: "50,000", - value: 50000 - }, - { - text: "100,000", - value: 100000 - }, - { - text: "∞", - value: -1 - } - ] - - readonly property var maxEntrySizeOptions: [ - { - text: "1 MB", - value: 1048576 - }, - { - text: "2 MB", - value: 2097152 - }, - { - text: "5 MB", - value: 5242880 - }, - { - text: "10 MB", - value: 10485760 - }, - { - text: "20 MB", - value: 20971520 - }, - { - text: "50 MB", - value: 52428800 - } - ] - - readonly property var autoClearOptions: [ - { - text: I18n.tr("Never"), - value: 0 - }, - { - text: I18n.tr("1 day"), - value: 1 - }, - { - text: I18n.tr("3 days"), - value: 3 - }, - { - text: I18n.tr("7 days"), - value: 7 - }, - { - text: I18n.tr("14 days"), - value: 14 - }, - { - text: I18n.tr("30 days"), - value: 30 - }, - { - text: I18n.tr("90 days"), - value: 90 - } - ] - - readonly property var maxPinnedOptions: [ - { - text: "5", - value: 5 - }, - { - text: "10", - value: 10 - }, - { - text: "15", - value: 15 - }, - { - text: "25", - value: 25 - }, - { - text: "50", - value: 50 - }, - { - text: "100", - value: 100 - } - ] - - function getMaxHistoryText(value) { - if (value <= 0) - return "∞"; - for (let opt of maxHistoryOptions) { - if (opt.value === value) - return opt.text; - } - return value.toLocaleString(); - } - - function getMaxEntrySizeText(value) { - for (let opt of maxEntrySizeOptions) { - if (opt.value === value) - return opt.text; - } - const mb = Math.round(value / 1048576); - return mb + " MB"; - } - - function getAutoClearText(value) { - for (let opt of autoClearOptions) { - if (opt.value === value) - return opt.text; - } - return value + " " + I18n.tr("days"); - } - - function getMaxPinnedText(value) { - for (let opt of maxPinnedOptions) { - if (opt.value === value) - return opt.text; - } - return value.toString(); - } - - function loadConfig() { - configLoaded = false; - configError = false; - DMSService.sendRequest("clipboard.getConfig", null, response => { - if (response.error) { - configError = true; - return; - } - config = response.result || {}; - configLoaded = true; - }); - } - - function saveConfig(key, value) { - const params = {}; - params[key] = value; - saving = true; - DMSService.sendRequest("clipboard.setConfig", params, response => { - saving = false; - if (response.error) { - ToastService.showError(I18n.tr("Failed to save clipboard setting"), response.error); - return; - } - const updated = JSON.parse(JSON.stringify(config)); - updated[key] = value; - config = updated; - }); - } - - Component.onCompleted: { - if (DMSService.isConnected) - loadConfig(); - } - - Connections { - target: DMSService - function onIsConnectedChanged() { - if (DMSService.isConnected) - loadConfig(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - Rectangle { - width: parent.width - height: warningContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - visible: !DMSService.isConnected || configError - - Row { - id: warningContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - font.pixelSize: Theme.fontSizeSmall - text: !DMSService.isConnected ? I18n.tr("DMS service is not connected. Clipboard settings are unavailable.") : I18n.tr("Failed to load clipboard configuration.") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "history", "limit"] - title: I18n.tr("History Settings") - iconName: "history" - visible: configLoaded - - SettingsDropdownRow { - id: maxHistoryDropdown - tab: "clipboard" - tags: ["clipboard", "history", "max", "limit"] - settingKey: "maxHistory" - text: I18n.tr("Maximum History") - description: I18n.tr("Maximum number of clipboard entries to keep") - options: root.maxHistoryOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getMaxHistoryText(root.config.maxHistory ?? 100); - } - - onValueChanged: value => { - for (let opt of root.maxHistoryOptions) { - if (opt.text === value) { - root.saveConfig("maxHistory", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - maxHistoryDropdown.currentValue = root.getMaxHistoryText(root.config.maxHistory ?? 100); - } - } - } - - SettingsDropdownRow { - id: maxEntrySizeDropdown - tab: "clipboard" - tags: ["clipboard", "entry", "size", "limit"] - settingKey: "maxEntrySize" - text: I18n.tr("Maximum Entry Size") - description: I18n.tr("Maximum size per clipboard entry") - options: root.maxEntrySizeOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getMaxEntrySizeText(root.config.maxEntrySize ?? 5242880); - } - - onValueChanged: value => { - for (let opt of root.maxEntrySizeOptions) { - if (opt.text === value) { - root.saveConfig("maxEntrySize", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - maxEntrySizeDropdown.currentValue = root.getMaxEntrySizeText(root.config.maxEntrySize ?? 5242880); - } - } - } - - SettingsDropdownRow { - id: autoClearDaysDropdown - tab: "clipboard" - tags: ["clipboard", "auto", "clear", "days"] - settingKey: "autoClearDays" - text: I18n.tr("Auto-Clear After") - description: I18n.tr("Automatically delete entries older than this") - options: root.autoClearOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getAutoClearText(root.config.autoClearDays ?? 0); - } - - onValueChanged: value => { - for (let opt of root.autoClearOptions) { - if (opt.text === value) { - root.saveConfig("autoClearDays", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - autoClearDaysDropdown.currentValue = root.getAutoClearText(root.config.autoClearDays ?? 0); - } - } - } - - SettingsDropdownRow { - id: maxPinnedDropdown - tab: "clipboard" - tags: ["clipboard", "pinned", "max", "limit"] - settingKey: "maxPinned" - text: I18n.tr("Maximum Pinned Entries") - description: I18n.tr("Maximum number of entries that can be saved") - options: root.maxPinnedOptions.map(opt => opt.text) - - function updateValue() { - if (root.configLoaded) { - currentValue = root.getMaxPinnedText(root.config.maxPinned ?? 25); - } - } - - Component.onCompleted: { - updateValue(); - } - - onValueChanged: value => { - for (let opt of root.maxPinnedOptions) { - if (opt.text === value) { - root.saveConfig("maxPinned", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigLoadedChanged() { - if (root.configLoaded) { - maxPinnedDropdown.updateValue(); - } - } - function onConfigChanged() { - maxPinnedDropdown.updateValue(); - } - } - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "behavior"] - title: I18n.tr("Behavior") - iconName: "settings" - visible: configLoaded - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "clear", "startup"] - settingKey: "clearAtStartup" - text: I18n.tr("Clear at Startup") - description: I18n.tr("Clear all history when server starts") - checked: root.config.clearAtStartup ?? false - onToggled: checked => root.saveConfig("clearAtStartup", checked) - } - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "enter", "paste", "behavior"] - settingKey: "clipboardEnterToPaste" - text: I18n.tr("Enter to Paste") - description: I18n.tr("Press Enter to paste, Shift+Enter to copy", "Clipboard behavior setting description") - checked: SettingsData.clipboardEnterToPaste - onToggled: checked => SettingsData.set("clipboardEnterToPaste", checked) - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "advanced", "disable"] - title: I18n.tr("Advanced") - iconName: "tune" - collapsible: true - expanded: false - visible: configLoaded - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "disable", "history"] - settingKey: "disabled" - text: I18n.tr("Disable History Persistence") - description: I18n.tr("Clipboard works but nothing saved to disk") - checked: root.config.disabled ?? false - onToggled: checked => root.saveConfig("disabled", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml deleted file mode 100644 index a4bd87d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml +++ /dev/null @@ -1,1563 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: dankBarTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedBarId: "default" - - property var selectedBarConfig: { - selectedBarId; - SettingsData.barConfigs; - const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0]; - } - - property bool selectedBarIsVertical: { - selectedBarId; - const pos = selectedBarConfig?.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - } - - Timer { - id: horizontalBarChangeDebounce - interval: 500 - repeat: false - onTriggered: { - const verticalBars = SettingsData.barConfigs.filter(cfg => { - const pos = cfg.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - }); - - verticalBars.forEach(bar => { - if (!bar.enabled) - return; - SettingsData.updateBarConfig(bar.id, { - enabled: false - }); - Qt.callLater(() => SettingsData.updateBarConfig(bar.id, { - enabled: true - })); - }); - } - } - - function _isBarActive(c) { - if (!c.enabled) - return false; - const prefs = c.screenPreferences || ["all"]; - if (prefs.length > 0) - return true; - return (c.showOnLastDisplay ?? true) && Quickshell.screens.length === 1; - } - - function notifyHorizontalBarChange() { - const configs = SettingsData.barConfigs; - if (configs.length < 2) - return; - - const hasHorizontal = configs.some(c => { - if (!_isBarActive(c)) - return false; - const p = c.position ?? SettingsData.Position.Top; - return p === SettingsData.Position.Top || p === SettingsData.Position.Bottom; - }); - if (!hasHorizontal) - return; - - const hasVertical = configs.some(c => { - if (!_isBarActive(c)) - return false; - const p = c.position ?? SettingsData.Position.Top; - return p === SettingsData.Position.Left || p === SettingsData.Position.Right; - }); - if (!hasVertical) - return; - - horizontalBarChangeDebounce.restart(); - } - - function createNewBar() { - if (SettingsData.barConfigs.length >= 4) - return; - const defaultBar = SettingsData.getBarConfig("default"); - if (!defaultBar) - return; - const newId = "bar" + Date.now(); - const newBar = { - id: newId, - name: "Bar " + (SettingsData.barConfigs.length + 1), - enabled: true, - position: defaultBar.position ?? 0, - screenPreferences: [], - showOnLastDisplay: false, - leftWidgets: defaultBar.leftWidgets || [], - centerWidgets: defaultBar.centerWidgets || [], - rightWidgets: defaultBar.rightWidgets || [], - spacing: defaultBar.spacing ?? 4, - innerPadding: defaultBar.innerPadding ?? 4, - bottomGap: defaultBar.bottomGap ?? 0, - transparency: defaultBar.transparency ?? 1.0, - widgetTransparency: defaultBar.widgetTransparency ?? 1.0, - squareCorners: defaultBar.squareCorners ?? false, - noBackground: defaultBar.noBackground ?? false, - gothCornersEnabled: defaultBar.gothCornersEnabled ?? false, - gothCornerRadiusOverride: defaultBar.gothCornerRadiusOverride ?? false, - gothCornerRadiusValue: defaultBar.gothCornerRadiusValue ?? 12, - borderEnabled: defaultBar.borderEnabled ?? false, - borderColor: defaultBar.borderColor || "surfaceText", - borderOpacity: defaultBar.borderOpacity ?? 1.0, - borderThickness: defaultBar.borderThickness ?? 1, - widgetOutlineEnabled: defaultBar.widgetOutlineEnabled ?? false, - widgetOutlineColor: defaultBar.widgetOutlineColor || "primary", - widgetOutlineOpacity: defaultBar.widgetOutlineOpacity ?? 1.0, - widgetOutlineThickness: defaultBar.widgetOutlineThickness ?? 1, - widgetPadding: defaultBar.widgetPadding ?? 8, - maximizeWidgetIcons: defaultBar.maximizeWidgetIcons ?? false, - maximizeWidgetText: defaultBar.maximizeWidgetText ?? false, - removeWidgetPadding: defaultBar.removeWidgetPadding ?? false, - fontScale: defaultBar.fontScale ?? 1.0, - iconScale: defaultBar.iconScale ?? 1.0, - autoHide: defaultBar.autoHide ?? false, - autoHideDelay: defaultBar.autoHideDelay ?? 250, - showOnWindowsOpen: defaultBar.showOnWindowsOpen ?? false, - openOnOverview: defaultBar.openOnOverview ?? false, - visible: defaultBar.visible ?? true, - popupGapsAuto: defaultBar.popupGapsAuto ?? true, - popupGapsManual: defaultBar.popupGapsManual ?? 4, - maximizeDetection: defaultBar.maximizeDetection ?? true, - scrollEnabled: defaultBar.scrollEnabled ?? true, - scrollXBehavior: defaultBar.scrollXBehavior ?? "column", - scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace", - shadowIntensity: defaultBar.shadowIntensity ?? 0, - shadowOpacity: defaultBar.shadowOpacity ?? 60, - shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit", - shadowDirection: defaultBar.shadowDirection ?? "top", - shadowColorMode: defaultBar.shadowColorMode ?? "default", - shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000" - }; - SettingsData.addBarConfig(newBar); - selectedBarId = newId; - } - - function deleteBar(barId) { - if (barId === "default") - return; - if (SettingsData.barConfigs.length <= 1) - return; - SettingsData.deleteBarConfig(barId); - selectedBarId = "default"; - } - - function toggleBarEnabled(barId) { - if (barId === "default") - return; - const config = SettingsData.getBarConfig(barId); - if (!config) - return; - SettingsData.updateBarConfig(barId, { - enabled: !config.enabled - }); - } - - function getBarScreenPreferences(barId) { - const config = SettingsData.getBarConfig(barId); - return config?.screenPreferences || ["all"]; - } - - function setBarScreenPreferences(barId, prefs) { - SettingsData.updateBarConfig(barId, { - screenPreferences: prefs - }); - notifyHorizontalBarChange(); - } - - function getBarShowOnLastDisplay(barId) { - const config = SettingsData.getBarConfig(barId); - return config?.showOnLastDisplay ?? true; - } - - function setBarShowOnLastDisplay(barId, value) { - SettingsData.updateBarConfig(barId, { - showOnLastDisplay: value - }); - if (Quickshell.screens.length === 1) - notifyHorizontalBarChange(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - iconName: "dashboard" - title: I18n.tr("Bar Configurations") - settingKey: "barConfigurations" - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - Layout.fillWidth: true - } - - DankButton { - text: I18n.tr("Add Bar") - iconName: "add" - buttonHeight: 32 - visible: SettingsData.barConfigs.length < 4 - onClicked: dankBarTab.createNewBar() - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: SettingsData.barConfigs - - Rectangle { - id: barCard - required property var modelData - required property int index - - width: parent.width - height: barCardContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: dankBarTab.selectedBarId === modelData.id ? Theme.withAlpha(Theme.primary, 0.15) : Theme.surfaceVariant - border.width: dankBarTab.selectedBarId === modelData.id ? 2 : 0 - border.color: Theme.primary - - Row { - id: barCardContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Column { - width: parent.width - deleteBtn.width - Theme.spacingM - spacing: Theme.spacingXS / 2 - - StyledText { - text: barCard.modelData.name || "Bar " + (barCard.index + 1) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - switch (cfg?.position ?? SettingsData.Position.Top) { - case SettingsData.Position.Top: - return I18n.tr("Top"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom"); - case SettingsData.Position.Left: - return I18n.tr("Left"); - case SettingsData.Position.Right: - return I18n.tr("Right"); - default: - return I18n.tr("Top"); - } - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - const prefs = cfg?.screenPreferences || ["all"]; - if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) - return I18n.tr("All displays"); - return prefs.length === 1 - ? I18n.tr("%1 display").arg(prefs.length) - : I18n.tr("%1 displays").arg(prefs.length); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - const left = cfg?.leftWidgets?.length || 0; - const center = cfg?.centerWidgets?.length || 0; - const right = cfg?.rightWidgets?.length || 0; - return I18n.tr("%1 widgets").replace("%1", left + center + right); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - visible: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - return !cfg?.enabled && barCard.modelData.id !== "default"; - } - } - - StyledText { - text: I18n.tr("Disabled") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - horizontalAlignment: Text.AlignLeft - visible: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - return !cfg?.enabled && barCard.modelData.id !== "default"; - } - } - } - } - - DankActionButton { - id: deleteBtn - buttonSize: 32 - iconName: "delete" - iconSize: 16 - backgroundColor: Theme.withAlpha(Theme.error, 0.15) - iconColor: Theme.error - visible: barCard.modelData.id !== "default" - enabled: SettingsData.barConfigs.length > 1 - anchors.verticalCenter: parent.verticalCenter - onClicked: dankBarTab.deleteBar(barCard.modelData.id) - } - } - - MouseArea { - anchors.fill: parent - z: -1 - cursorShape: Qt.PointingHandCursor - onClicked: dankBarTab.selectedBarId = barCard.modelData.id - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - SettingsCard { - iconName: selectedBarConfig?.enabled ? "visibility" : "visibility_off" - title: I18n.tr("Enable Bar") - visible: selectedBarId !== "default" - - SettingsToggleRow { - text: I18n.tr("Toggle visibility of this bar configuration") - checked: { - selectedBarId; - return selectedBarConfig?.enabled ?? false; - } - onToggled: toggled => dankBarTab.toggleBarEnabled(selectedBarId) - } - } - - SettingsCard { - iconName: "display_settings" - title: I18n.tr("Display Assignment") - settingKey: "barDisplay" - visible: selectedBarConfig?.enabled - - StyledText { - width: parent.width - text: I18n.tr("Configure which displays show \"%1\"").replace("%1", selectedBarConfig?.name || "this bar") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Column { - id: displayAssignmentColumn - width: parent.width - spacing: Theme.spacingS - - property bool showingAll: { - const prefs = selectedBarConfig?.screenPreferences || ["all"]; - return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - } - - SettingsToggleRow { - text: I18n.tr("All displays") - checked: displayAssignmentColumn.showingAll - onToggled: checked => { - if (checked) { - dankBarTab.setBarScreenPreferences(selectedBarId, ["all"]); - } else { - dankBarTab.setBarScreenPreferences(selectedBarId, []); - } - } - } - - SettingsToggleRow { - text: I18n.tr("Show on Last Display") - checked: selectedBarConfig?.showOnLastDisplay ?? true - visible: !displayAssignmentColumn.showingAll - onToggled: checked => dankBarTab.setBarShowOnLastDisplay(selectedBarId, checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: !displayAssignmentColumn.showingAll - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !displayAssignmentColumn.showingAll - - Repeater { - model: Quickshell.screens - - delegate: SettingsToggleRow { - id: screenToggle - required property var modelData - - text: SettingsData.getScreenDisplayName(modelData) - description: modelData.width + "×" + modelData.height + " • " + (SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name) - checked: { - const prefs = selectedBarConfig?.screenPreferences || []; - if (typeof prefs[0] === "string" && prefs[0] === "all") - return false; - return SettingsData.isScreenInPreferences(modelData, prefs); - } - onToggled: checked => { - let currentPrefs = selectedBarConfig?.screenPreferences || []; - if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") - currentPrefs = []; - - const screenModelIndex = SettingsData.getScreenModelIndex(modelData); - - let newPrefs = currentPrefs.filter(pref => { - if (typeof pref === "string") - return false; - if (pref.modelIndex !== undefined && screenModelIndex >= 0) - return !(pref.model === modelData.model && pref.modelIndex === screenModelIndex); - return pref.name !== modelData.name || pref.model !== modelData.model; - }); - - if (checked) { - const prefObj = { - name: modelData.name, - model: modelData.model || "" - }; - if (screenModelIndex >= 0) - prefObj.modelIndex = screenModelIndex; - newPrefs.push(prefObj); - } - - dankBarTab.setBarScreenPreferences(selectedBarId, newPrefs); - } - } - } - } - } - } - - SettingsCard { - iconName: "vertical_align_center" - title: I18n.tr("Position") - settingKey: "barPosition" - visible: selectedBarConfig?.enabled - - Item { - width: parent.width - height: positionButtonGroup.height - - DankButtonGroup { - id: positionButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")] - currentIndex: { - selectedBarId; - const config = SettingsData.getBarConfig(selectedBarId); - const pos = config?.position ?? 0; - switch (pos) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return 1; - case SettingsData.Position.Left: - return 2; - case SettingsData.Position.Right: - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newPos = 0; - switch (index) { - case 0: - newPos = SettingsData.Position.Top; - break; - case 1: - newPos = SettingsData.Position.Bottom; - break; - case 2: - newPos = SettingsData.Position.Left; - break; - case 3: - newPos = SettingsData.Position.Right; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - position: newPos - }); - notifyHorizontalBarChange(); - } - } - } - } - - SettingsCard { - iconName: "visibility_off" - title: I18n.tr("Visibility") - settingKey: "barVisibility" - visible: selectedBarConfig?.enabled - - SettingsToggleRow { - text: I18n.tr("Auto-hide") - checked: selectedBarConfig?.autoHide ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - autoHide: toggled - }); - notifyHorizontalBarChange(); - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: selectedBarConfig?.autoHide ?? false - leftPadding: Theme.spacingM - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: hideDelaySlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Hide Delay") - value: selectedBarConfig?.autoHideDelay ?? 250 - minimum: 0 - maximum: 2000 - unit: "ms" - defaultValue: 250 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - autoHideDelay: newValue - }); - } - - Binding { - target: hideDelaySlider - property: "value" - value: selectedBarConfig?.autoHideDelay ?? 250 - restoreMode: Binding.RestoreBinding - } - } - - SettingsToggleRow { - width: parent.width - parent.leftPadding - visible: CompositorService.isNiri || CompositorService.isHyprland - text: I18n.tr("Hide When Windows Open") - checked: selectedBarConfig?.showOnWindowsOpen ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - showOnWindowsOpen: toggled - }); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Manual Show/Hide") - checked: selectedBarConfig?.visible ?? true - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - visible: toggled - }); - notifyHorizontalBarChange(); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Click Through") - checked: selectedBarConfig?.clickThrough ?? false - onToggled: toggled => SettingsData.updateBarConfig(selectedBarId, { - clickThrough: toggled - }) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview") - checked: selectedBarConfig?.openOnOverview ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - openOnOverview: toggled - }); - } - } - } - - SettingsToggleCard { - iconName: "fit_screen" - title: I18n.tr("Maximize Detection") - description: I18n.tr("Remove gaps and border when windows are maximized") - visible: selectedBarConfig?.enabled && (CompositorService.isNiri || CompositorService.isHyprland) - checked: selectedBarConfig?.maximizeDetection ?? true - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeDetection: checked - }) - } - - SettingsToggleCard { - iconName: "mouse" - title: I18n.tr("Scroll Wheel") - description: I18n.tr("Control workspaces and columns by scrolling on the bar") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.scrollEnabled ?? true - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - scrollEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Y Axis") - model: CompositorService.isNiri ? [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")] : [I18n.tr("None"), I18n.tr("Workspace")] - currentIndex: { - switch (selectedBarConfig?.scrollYBehavior || "workspace") { - case "none": - return 0; - case "workspace": - return 1; - case "column": - return 2; - default: - return 1; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let behavior = "workspace"; - switch (index) { - case 0: - behavior = "none"; - break; - case 1: - behavior = "workspace"; - break; - case 2: - behavior = "column"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - scrollYBehavior: behavior - }); - } - } - - SettingsButtonGroupRow { - text: I18n.tr("X Axis") - visible: CompositorService.isNiri - model: [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")] - currentIndex: { - switch (selectedBarConfig?.scrollXBehavior || "column") { - case "none": - return 0; - case "workspace": - return 1; - case "column": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let behavior = "column"; - switch (index) { - case 0: - behavior = "none"; - break; - case 1: - behavior = "workspace"; - break; - case 2: - behavior = "column"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - scrollXBehavior: behavior - }); - } - } - } - - SettingsCard { - iconName: "space_bar" - title: I18n.tr("Spacing") - settingKey: "barSpacing" - visible: selectedBarConfig?.enabled - - SettingsSliderRow { - id: edgeSpacingSlider - text: I18n.tr("Edge Spacing") - value: selectedBarConfig?.spacing ?? 4 - minimum: 0 - maximum: 32 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - spacing: finalValue - }); - } - - Binding { - target: edgeSpacingSlider - property: "value" - value: selectedBarConfig?.spacing ?? 4 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: exclusiveZoneSlider - text: I18n.tr("Exclusive Zone Offset") - value: selectedBarConfig?.bottomGap ?? 0 - minimum: -50 - maximum: 50 - defaultValue: 0 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - bottomGap: finalValue - }); - } - - Binding { - target: exclusiveZoneSlider - property: "value" - value: selectedBarConfig?.bottomGap ?? 0 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: sizeSlider - text: I18n.tr("Size") - value: selectedBarConfig?.innerPadding ?? 4 - minimum: -8 - maximum: 24 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - innerPadding: finalValue - }); - } - - Binding { - target: sizeSlider - property: "value" - value: selectedBarConfig?.innerPadding ?? 4 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetPaddingSlider - text: I18n.tr("Padding") - value: selectedBarConfig?.widgetPadding ?? 8 - minimum: 0 - maximum: 32 - unit: "px" - defaultValue: 8 - opacity: (selectedBarConfig?.removeWidgetPadding ?? false) ? 0.5 : 1.0 - enabled: !(selectedBarConfig?.removeWidgetPadding ?? false) - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetPadding: newValue - }); - } - - Binding { - target: widgetPaddingSlider - property: "value" - value: selectedBarConfig?.widgetPadding ?? 12 - restoreMode: Binding.RestoreBinding - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Auto Popup Gaps") - checked: selectedBarConfig?.popupGapsAuto ?? true - onToggled: checked => { - SettingsData.updateBarConfig(selectedBarId, { - popupGapsAuto: checked - }); - } - } - - Column { - width: parent.width - leftPadding: Theme.spacingM - spacing: Theme.spacingM - visible: !(selectedBarConfig?.popupGapsAuto ?? true) - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: popupGapsManualSlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Manual Gap Size") - value: selectedBarConfig?.popupGapsManual ?? 4 - minimum: 0 - maximum: 50 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - popupGapsManual: finalValue - }); - } - - Binding { - target: popupGapsManualSlider - property: "value" - value: selectedBarConfig?.popupGapsManual ?? 4 - restoreMode: Binding.RestoreBinding - } - } - } - } - - SettingsSliderCard { - id: fontScaleSliderCard - iconName: "text_fields" - title: I18n.tr("Font Scale") - description: I18n.tr("Scale DankBar font sizes independently") - visible: selectedBarConfig?.enabled - minimum: 50 - maximum: 200 - value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - fontScale: newValue / 100 - }); - } - - Binding { - target: fontScaleSliderCard - property: "value" - value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderCard { - id: iconScaleSliderCard - iconName: "interests" - title: I18n.tr("Icon Scale") - description: I18n.tr("Scale DankBar icon sizes independently") - visible: selectedBarConfig?.enabled - minimum: 50 - maximum: 200 - value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - iconScale: newValue / 100 - }); - } - - Binding { - target: iconScaleSliderCard - property: "value" - value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100) - restoreMode: Binding.RestoreBinding - } - } - - SettingsCard { - iconName: "opacity" - title: I18n.tr("Transparency") - settingKey: "barTransparency" - visible: selectedBarConfig?.enabled - - SettingsSliderRow { - id: barTransparencySlider - text: I18n.tr("Bar Transparency") - value: (selectedBarConfig?.transparency ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - transparency: finalValue / 100 - }); - } - - Binding { - target: barTransparencySlider - property: "value" - value: (selectedBarConfig?.transparency ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetTransparencySlider - text: I18n.tr("Widget Transparency") - value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetTransparency: finalValue / 100 - }); - } - - Binding { - target: widgetTransparencySlider - property: "value" - value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - } - - SettingsCard { - id: shadowCard - iconName: "layers" - title: I18n.tr("Shadow Override", "bar shadow settings card") - settingKey: "barShadow" - collapsible: true - expanded: true - visible: selectedBarConfig?.enabled - - readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0 - readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom" - readonly property string directionSource: selectedBarConfig?.shadowDirectionMode ?? "inherit" - - StyledText { - width: parent.width - text: I18n.tr("Enable a custom override below to set per-bar shadow intensity, opacity, and color.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - SettingsToggleRow { - text: I18n.tr("Custom Shadow Override") - description: I18n.tr("Override the global shadow with per-bar settings") - checked: shadowCard.shadowActive - onToggled: checked => { - if (checked) { - SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: 12, - shadowOpacity: 60 - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: 0 - }); - } - } - } - - SettingsSliderRow { - visible: shadowCard.shadowActive - text: I18n.tr("Intensity", "shadow intensity slider") - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: 12 - value: selectedBarConfig?.shadowIntensity ?? 0 - onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: newValue - }) - } - - SettingsSliderRow { - visible: shadowCard.shadowActive - text: I18n.tr("Opacity") - minimum: 10 - maximum: 100 - unit: "%" - defaultValue: 60 - value: selectedBarConfig?.shadowOpacity ?? 60 - onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { - shadowOpacity: newValue - }) - } - - SettingsDropdownRow { - visible: shadowCard.shadowActive - text: I18n.tr("Direction Source", "bar shadow direction source") - description: I18n.tr("Choose how this bar resolves shadow direction") - settingKey: "barShadowDirectionSource" - options: [I18n.tr("Inherit Global (Default)", "bar shadow direction source option"), I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"), I18n.tr("Manual", "bar shadow direction source option")] - currentValue: { - switch (shadowCard.directionSource) { - case "autoBar": - return I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"); - case "manual": - return I18n.tr("Manual", "bar shadow direction source option"); - default: - return I18n.tr("Inherit Global (Default)", "bar shadow direction source option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Auto (Bar-aware)", "bar shadow direction source option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "autoBar" - }); - } else if (value === I18n.tr("Manual", "bar shadow direction source option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "manual" - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "inherit" - }); - } - } - } - - SettingsDropdownRow { - visible: shadowCard.shadowActive && shadowCard.directionSource === "manual" - text: I18n.tr("Manual Direction", "bar manual shadow direction") - description: I18n.tr("Use a fixed shadow direction for this bar") - settingKey: "barShadowDirectionManual" - options: [I18n.tr("Top", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] - currentValue: { - switch (selectedBarConfig?.shadowDirection) { - case "topLeft": - return I18n.tr("Top Left", "shadow direction option"); - case "topRight": - return I18n.tr("Top Right", "shadow direction option"); - case "bottom": - return I18n.tr("Bottom", "shadow direction option"); - default: - return I18n.tr("Top", "shadow direction option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Top Left", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "topLeft" - }); - } else if (value === I18n.tr("Top Right", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "topRight" - }); - } else if (value === I18n.tr("Bottom", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "bottom" - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "top" - }); - } - } - } - - Column { - visible: shadowCard.shadowActive - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - } - - Item { - width: parent.width - height: shadowColorGroup.implicitHeight - - DankButtonGroup { - id: shadowColorGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS - minButtonWidth: parent.width < 420 ? 36 : 56 - textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default (Black)"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: { - switch (selectedBarConfig?.shadowColorMode || "default") { - case "surface": - return 1; - case "primary": - return 2; - case "secondary": - return 3; - case "custom": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let mode = "default"; - switch (index) { - case 1: - mode = "surface"; - break; - case 2: - mode = "primary"; - break; - case 3: - mode = "secondary"; - break; - case 4: - mode = "custom"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - shadowColorMode: mode - }); - } - } - } - - Rectangle { - visible: selectedBarConfig?.shadowColorMode === "custom" - width: 32 - height: 32 - radius: 16 - color: selectedBarConfig?.shadowCustomColor ?? "#000000" - border.color: Theme.outline - border.width: 1 - anchors.horizontalCenter: parent.horizontalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.updateBarConfig(selectedBarId, { - shadowCustomColor: color.toString() - }); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - - SettingsCard { - iconName: "rounded_corner" - title: I18n.tr("Corners & Background") - settingKey: "barCorners" - collapsible: true - expanded: false - visible: selectedBarConfig?.enabled - - SettingsToggleRow { - text: I18n.tr("Square Corners") - checked: selectedBarConfig?.squareCorners ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - squareCorners: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("No Background") - checked: selectedBarConfig?.noBackground ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - noBackground: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Maximize Widget Icons") - checked: selectedBarConfig?.maximizeWidgetIcons ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeWidgetIcons: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Maximize Widget Text") - checked: selectedBarConfig?.maximizeWidgetText ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeWidgetText: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Remove Widget Padding") - checked: selectedBarConfig?.removeWidgetPadding ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - removeWidgetPadding: checked - }) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Goth Corners") - checked: selectedBarConfig?.gothCornersEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - gothCornersEnabled: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Corner Radius Override") - checked: selectedBarConfig?.gothCornerRadiusOverride ?? false - visible: selectedBarConfig?.gothCornersEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - gothCornerRadiusOverride: checked - }) - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: (selectedBarConfig?.gothCornersEnabled ?? false) && (selectedBarConfig?.gothCornerRadiusOverride ?? false) - leftPadding: Theme.spacingM - - SettingsSliderRow { - id: gothCornerRadiusSlider - width: parent.width - parent.leftPadding - text: I18n.tr("Goth Corner Radius") - value: selectedBarConfig?.gothCornerRadiusValue ?? 12 - minimum: 0 - maximum: 64 - defaultValue: 12 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - gothCornerRadiusValue: finalValue - }); - } - - Binding { - target: gothCornerRadiusSlider - property: "value" - value: selectedBarConfig?.gothCornerRadiusValue ?? 12 - restoreMode: Binding.RestoreBinding - } - } - } - } - - SettingsToggleCard { - iconName: "border_style" - title: I18n.tr("Border") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.borderEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - borderEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.borderColor || "surfaceText") { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "surfaceText"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - borderColor: newColor - }); - } - } - - SettingsSliderRow { - id: borderOpacitySlider - text: I18n.tr("Opacity") - value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - borderOpacity: finalValue / 100 - }); - } - - Binding { - target: borderOpacitySlider - property: "value" - value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: borderThicknessSlider - text: I18n.tr("Thickness") - value: selectedBarConfig?.borderThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - borderThickness: finalValue - }); - } - - Binding { - target: borderThicknessSlider - property: "value" - value: selectedBarConfig?.borderThickness ?? 1 - restoreMode: Binding.RestoreBinding - } - } - } - - SettingsToggleCard { - iconName: "highlight" - title: I18n.tr("Widget Outline") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.widgetOutlineEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.widgetOutlineColor || "primary") { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "primary"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineColor: newColor - }); - } - } - - SettingsSliderRow { - id: widgetOutlineOpacitySlider - text: I18n.tr("Opacity") - value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineOpacity: finalValue / 100 - }); - } - - Binding { - target: widgetOutlineOpacitySlider - property: "value" - value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetOutlineThicknessSlider - text: I18n.tr("Thickness") - value: selectedBarConfig?.widgetOutlineThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineThickness: finalValue - }); - } - - Binding { - target: widgetOutlineThicknessSlider - property: "value" - value: selectedBarConfig?.widgetOutlineThickness ?? 1 - restoreMode: Binding.RestoreBinding - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml deleted file mode 100644 index 4c23596..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml +++ /dev/null @@ -1,477 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property string searchQuery: "" - property var filteredWidgets: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property var parentModal: null - - signal widgetAdded(string widgetType) - - function updateFilteredWidgets() { - const allWidgets = DesktopWidgetRegistry.registeredWidgetsList || []; - var filtered = []; - - if (!searchQuery || searchQuery.length === 0) { - filtered = allWidgets.slice(); - } else { - var query = searchQuery.toLowerCase(); - for (var i = 0; i < allWidgets.length; i++) { - var widget = allWidgets[i]; - var name = widget.name ? widget.name.toLowerCase() : ""; - var description = widget.description ? widget.description.toLowerCase() : ""; - var id = widget.id ? widget.id.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) - filtered.push(widget); - } - } - - filtered.sort((a, b) => { - if (a.featured !== b.featured) - return a.featured ? -1 : 1; - return 0; - }); - - filteredWidgets = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1); - } - - function selectPrevious() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function selectWidget() { - if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length) - return; - var widget = filteredWidgets[selectedIndex]; - addWidget(widget); - } - - function addWidget(widget) { - const widgetType = widget.id; - const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(widgetType); - const name = widget.name || widgetType; - SettingsData.createDesktopWidgetInstance(widgetType, name, defaultConfig); - root.widgetAdded(widgetType); - root.hide(); - } - - function show() { - updateFilteredWidgets(); - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "desktopWidgetBrowser" - title: I18n.tr("Add Desktop Widget") - minimumSize: Qt.size(400, 350) - implicitWidth: 500 - implicitHeight: 550 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - updateFilteredWidgets(); - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - return; - } - searchQuery = ""; - filteredWidgets = []; - selectedIndex = -1; - keyboardNavigationActive = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - Connections { - target: DesktopWidgetRegistry - function onRegistryChanged() { - if (root.visible) - root.updateFilteredWidgets(); - } - } - - FocusScope { - id: widgetKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.keyboardNavigationActive) { - root.selectWidget(); - } else if (root.filteredWidgets.length > 0) { - root.addWidget(root.filteredWidgets[0]); - } - event.accepted = true; - return; - } - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_P: - case Qt.Key_K: - root.selectPrevious(); - event.accepted = true; - return; - } - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - id: titleBar - width: parent.width - height: 48 - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Add Desktop Widget") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - } - - Item { - width: parent.width - height: parent.height - titleBar.height - - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Select a widget to add to your desktop. Each widget is a separate instance with its own settings.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - } - - DankTextField { - id: searchField - width: parent.width - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search widgets...") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [widgetKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredWidgets(); - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.hide(); - event.accepted = true; - return; - } - if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) - event.accepted = false; - } - } - - DankListView { - id: widgetList - - width: parent.width - height: parent.height - y - spacing: Theme.spacingS - model: root.filteredWidgets - clip: true - - delegate: Rectangle { - id: delegateRoot - - required property var modelData - required property int index - - width: widgetList.width - height: 72 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceVariant, 0.3) - border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - width: 44 - height: 44 - radius: Theme.cornerRadius - color: Theme.primarySelected - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: delegateRoot.modelData.icon || "widgets" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 44 - Theme.iconSize - Theme.spacingM * 3 - - Row { - spacing: Theme.spacingS - - StyledText { - text: delegateRoot.modelData.name || delegateRoot.modelData.id - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Rectangle { - visible: delegateRoot.modelData.featured || false - width: featuredWidgetRow.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - border.color: Theme.withAlpha(Theme.secondary, 0.4) - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - Row { - id: featuredWidgetRow - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: "star" - size: 10 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("featured") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - font.weight: Font.Medium - } - } - } - - Rectangle { - visible: delegateRoot.modelData.type === "plugin" - width: pluginLabel.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: pluginLabel - anchors.centerIn: parent - text: I18n.tr("Plugin") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - } - } - } - - StyledText { - text: delegateRoot.modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - maximumLineCount: 2 - visible: text !== "" - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.addWidget(delegateRoot.modelData) - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - footer: Item { - width: widgetList.width - height: emptyText.visible ? 60 : 0 - - StyledText { - id: emptyText - visible: root.filteredWidgets.length === 0 - text: root.searchQuery.length > 0 ? I18n.tr("No widgets match your search") : I18n.tr("No widgets available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml deleted file mode 100644 index 4852d6b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml +++ /dev/null @@ -1,460 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets -import qs.Modules.Settings.DesktopWidgetSettings as DWS - -SettingsCard { - id: root - - required property var instanceData - property bool isExpanded: false - property bool confirmingDelete: false - - readonly property string instanceId: instanceData?.id ?? "" - readonly property string widgetType: instanceData?.widgetType ?? "" - readonly property var widgetDef: DesktopWidgetRegistry.getWidget(widgetType) - readonly property string widgetName: instanceData?.name ?? widgetDef?.name ?? widgetType - - signal deleteRequested - signal duplicateRequested - - property Component clockSettingsComponent: Component { - DWS.ClockSettings {} - } - - property Component systemMonitorSettingsComponent: Component { - DWS.SystemMonitorSettings {} - } - - property Component pluginSettingsComponent: Component { - DWS.PluginDesktopWidgetSettings { - instanceId: root.instanceId - instanceData: root.instanceData - widgetType: root.widgetType - widgetDef: root.widgetDef - } - } - - width: parent?.width ?? 400 - iconName: widgetDef?.icon ?? "widgets" - title: widgetName - collapsible: true - expanded: isExpanded - - onExpandedChanged: isExpanded = expanded - - headerActions: [ - DankToggle { - checked: instanceData?.enabled ?? true - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - enabled: isChecked - }); - } - }, - DankActionButton { - id: menuButton - iconName: "more_vert" - onClicked: { - if (actionsMenu.opened) { - actionsMenu.close(); - return; - } - actionsMenu.open(); - } - - Popup { - id: actionsMenu - x: -width + parent.width - y: parent.height + Theme.spacingXS - width: 160 - padding: Theme.spacingXS - modal: false - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onClosed: root.confirmingDelete = false - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Theme.outlineLight - border.width: 1 - } - - contentItem: Column { - spacing: 2 - - Rectangle { - width: parent.width - height: Theme.iconSizeLarge - radius: Theme.cornerRadius - color: duplicateArea.containsMouse ? Theme.primaryHover : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "content_copy" - size: Theme.iconSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Duplicate") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: duplicateArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - actionsMenu.close(); - root.duplicateRequested(); - } - } - } - - Rectangle { - width: parent.width - height: Theme.iconSizeLarge - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.errorHover : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: root.confirmingDelete ? "warning" : "delete" - size: Theme.iconSizeSmall - color: Theme.error - } - - StyledText { - text: root.confirmingDelete ? I18n.tr("Confirm Delete") : I18n.tr("Delete") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - } - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.confirmingDelete) { - actionsMenu.close(); - root.deleteRequested(); - return; - } - root.confirmingDelete = true; - } - } - } - } - } - } - ] - - Column { - width: parent.width - spacing: 0 - visible: root.isExpanded - opacity: visible ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Item { - width: parent.width - height: nameRow.height + Theme.spacingM * 2 - - Row { - id: nameRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 80 - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: parent.width - 80 - Theme.spacingM - text: root.widgetName - onEditingFinished: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - name: text - }); - } - } - } - } - - SettingsDivider {} - - Item { - width: parent.width - height: groupRow.height + Theme.spacingM * 2 - visible: (SettingsData.desktopWidgetGroups || []).length > 0 - - Row { - id: groupRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Group") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 80 - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - id: groupDropdown - width: parent.width - 80 - Theme.spacingM - compactMode: true - - property var groupsData: { - const groups = SettingsData.desktopWidgetGroups || []; - const items = [ - { - value: "", - label: I18n.tr("None") - } - ]; - for (const g of groups) { - items.push({ - value: g.id, - label: g.name - }); - } - return items; - } - - options: groupsData.map(g => g.label) - currentValue: { - const currentGroup = root.instanceData?.group ?? ""; - const item = groupsData.find(g => g.value === currentGroup); - return item?.label ?? I18n.tr("None"); - } - - onValueChanged: value => { - if (!root.instanceId) - return; - const item = groupsData.find(g => g.label === value); - const groupId = item?.value ?? ""; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - group: groupId || null - }); - } - } - } - } - - SettingsDivider { - visible: (SettingsData.desktopWidgetGroups || []).length > 0 - } - - SettingsToggleRow { - text: I18n.tr("Show on Overlay") - checked: instanceData?.config?.showOnOverlay ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverlay: isChecked - }); - } - } - - SettingsDivider { - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview") - checked: instanceData?.config?.showOnOverview ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverview: isChecked - }); - } - } - - SettingsDivider { - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview Only") - checked: instanceData?.config?.showOnOverviewOnly ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverviewOnly: isChecked - }); - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Click Through") - description: I18n.tr("Allow clicks to pass through the widget") - checked: instanceData?.config?.clickThrough ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - clickThrough: isChecked - }); - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Sync Position Across Screens") - description: I18n.tr("Use the same position and size on all displays") - checked: instanceData?.config?.syncPositionAcrossScreens ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - if (isChecked) - SettingsData.syncDesktopWidgetPositionToAllScreens(root.instanceId); - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - syncPositionAcrossScreens: isChecked - }); - } - } - - SettingsDivider {} - - Item { - width: parent.width - height: ipcColumn.height + Theme.spacingM * 2 - - Column { - id: ipcColumn - x: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Command") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: ipcText.height + Theme.spacingS * 2 - radius: Theme.cornerRadius / 2 - color: Theme.surfaceHover - - Row { - x: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - width: parent.width - Theme.spacingS * 2 - - StyledText { - id: ipcText - text: "dms ipc call desktopWidget toggleOverlay " + root.instanceId - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.monoFontFamily - color: Theme.surfaceVariantText - width: parent.width - copyBtn.width - Theme.spacingS - elide: Text.ElideMiddle - anchors.verticalCenter: parent.verticalCenter - } - - DankButton { - id: copyBtn - iconName: "content_copy" - backgroundColor: "transparent" - textColor: Theme.surfaceText - buttonHeight: 28 - horizontalPadding: 4 - anchors.verticalCenter: parent.verticalCenter - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", "dms ipc call desktopWidget toggleOverlay " + root.instanceId]); - ToastService.showInfo(I18n.tr("Copied to clipboard")); - } - } - } - } - } - } - - SettingsDivider {} - - Loader { - id: settingsLoader - width: parent.width - active: root.isExpanded && root.widgetType !== "" - - sourceComponent: { - switch (root.widgetType) { - case "desktopClock": - return clockSettingsComponent; - case "systemMonitor": - return systemMonitorSettingsComponent; - default: - return pluginSettingsComponent; - } - } - - onLoaded: { - if (!item) - return; - item.instanceId = root.instanceId; - item.instanceData = Qt.binding(() => root.instanceData); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml deleted file mode 100644 index 7bd02b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml +++ /dev/null @@ -1,163 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? {} - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - width: parent?.width ?? 400 - spacing: 0 - - SettingsDropdownRow { - text: I18n.tr("Clock Style") - options: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked")] - currentValue: { - switch (cfg.style) { - case "analog": - return I18n.tr("Analog"); - case "stacked": - return I18n.tr("Stacked"); - default: - return I18n.tr("Digital"); - } - } - onValueChanged: value => { - switch (value) { - case I18n.tr("Analog"): - root.updateConfig("style", "analog"); - return; - case I18n.tr("Stacked"): - root.updateConfig("style", "stacked"); - return; - default: - root.updateConfig("style", "digital"); - } - } - } - - SettingsDivider { - visible: cfg.style === "analog" - } - - SettingsToggleRow { - visible: cfg.style === "analog" - text: I18n.tr("Show Hour Numbers") - checked: cfg.showAnalogNumbers ?? false - onToggled: checked => root.updateConfig("showAnalogNumbers", checked) - } - - SettingsDivider { - visible: cfg.style === "analog" - } - - SettingsToggleRow { - visible: cfg.style === "analog" - text: I18n.tr("Show Seconds") - checked: cfg.showAnalogSeconds ?? true - onToggled: checked => root.updateConfig("showAnalogSeconds", checked) - } - - SettingsDivider { - visible: cfg.style === "digital" || cfg.style === "stacked" - } - - SettingsToggleRow { - visible: cfg.style === "digital" || cfg.style === "stacked" - text: I18n.tr("Show Seconds") - checked: cfg.showDigitalSeconds ?? false - onToggled: checked => root.updateConfig("showDigitalSeconds", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Show Date") - checked: cfg.showDate ?? true - onToggled: checked => root.updateConfig("showDate", checked) - } - - SettingsDivider {} - - SettingsSliderRow { - text: I18n.tr("Transparency") - minimum: 0 - maximum: 100 - value: Math.round((cfg.transparency ?? 0.8) * 100) - unit: "%" - onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100) - } - - SettingsDivider {} - - SettingsColorPicker { - colorMode: cfg.colorMode ?? "primary" - customColor: cfg.customColor ?? "#ffffff" - onColorModeSelected: mode => root.updateConfig("colorMode", mode) - onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString()) - } - - SettingsDivider {} - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml deleted file mode 100644 index 949e33f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml +++ /dev/null @@ -1,137 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - property string widgetType: "" - property var widgetDef: null - - readonly property var cfg: instanceData?.config ?? {} - readonly property string settingsPath: widgetDef?.settingsComponent ?? "" - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - QtObject { - id: instanceScopedPluginService - - readonly property var availablePlugins: PluginService.availablePlugins - readonly property var loadedPlugins: PluginService.loadedPlugins - readonly property var pluginDesktopComponents: PluginService.pluginDesktopComponents - - signal pluginDataChanged(string pluginId) - signal pluginLoaded(string pluginId) - signal pluginUnloaded(string pluginId) - - function loadPluginData(pluginId, key, defaultValue) { - const cfg = root.instanceData?.config; - if (cfg && key in cfg) - return cfg[key]; - return SettingsData.getPluginSetting(root.widgetType, key, defaultValue); - } - - function savePluginData(pluginId, key, value) { - root.updateConfig(key, value); - Qt.callLater(() => pluginDataChanged(root.widgetType)); - return true; - } - - function getPluginVariants(pluginId) { - return PluginService.getPluginVariants(pluginId); - } - - function isPluginLoaded(pluginId) { - return PluginService.isPluginLoaded(pluginId); - } - } - - width: parent?.width ?? 400 - spacing: 0 - - Loader { - id: pluginSettingsLoader - width: parent.width - active: root.settingsPath !== "" - - source: root.settingsPath - - onLoaded: { - if (!item) - return; - if (item.instanceId !== undefined) - item.instanceId = root.instanceId; - if (item.instanceData !== undefined) - item.instanceData = Qt.binding(() => root.instanceData); - if (item.pluginService !== undefined) - item.pluginService = instanceScopedPluginService; - if (item.reloadChildValues) - Qt.callLater(item.reloadChildValues); - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.settingsPath === "" - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml deleted file mode 100644 index 5ff156f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml +++ /dev/null @@ -1,444 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? {} - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - width: parent?.width ?? 400 - spacing: 0 - - SettingsToggleRow { - text: I18n.tr("Show Header") - checked: cfg.showHeader ?? true - onToggled: checked => root.updateConfig("showHeader", checked) - } - - SettingsDivider {} - - Item { - width: parent.width - height: graphIntervalColumn.height + Theme.spacingM * 2 - - Column { - id: graphIntervalColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Graph Time Range") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankButtonGroup { - model: ["1m", "5m", "10m", "30m"] - currentIndex: { - switch (cfg.graphInterval ?? 60) { - case 60: - return 0; - case 300: - return 1; - case 600: - return 2; - case 1800: - return 3; - default: - return 0; - } - } - buttonHeight: 32 - minButtonWidth: 48 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const values = [60, 300, 600, 1800]; - root.updateConfig("graphInterval", values[index]); - } - } - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("CPU") - checked: cfg.showCpu ?? true - onToggled: checked => root.updateConfig("showCpu", checked) - } - - SettingsDivider { - visible: cfg.showCpu ?? true - } - - SettingsToggleRow { - visible: cfg.showCpu ?? true - text: I18n.tr("CPU Graph") - checked: cfg.showCpuGraph ?? true - onToggled: checked => root.updateConfig("showCpuGraph", checked) - } - - SettingsDivider { - visible: cfg.showCpu ?? true - } - - SettingsToggleRow { - visible: cfg.showCpu ?? true - text: I18n.tr("CPU Temperature") - checked: cfg.showCpuTemp ?? true - onToggled: checked => root.updateConfig("showCpuTemp", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("GPU Temperature") - checked: cfg.showGpuTemp ?? false - onToggled: checked => root.updateConfig("showGpuTemp", checked) - } - - SettingsDivider { - visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0 - } - - Item { - width: parent.width - height: gpuSelectColumn.height + Theme.spacingM * 2 - visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0 - - Column { - id: gpuSelectColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("GPU") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: DgopService.availableGpus - - Rectangle { - required property var modelData - - readonly property bool isSelected: (cfg.gpuPciId ?? "") === modelData.pciId - - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: isSelected ? Theme.primarySelected : Theme.surfaceHover - border.color: isSelected ? Theme.primary : "transparent" - border.width: 2 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "videocam" - size: Theme.iconSizeSmall - color: isSelected ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSizeSmall - Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: modelData.displayName || "Unknown GPU" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - } - - StyledText { - text: modelData.driver || "" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - visible: text !== "" - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.updateConfig("gpuPciId", modelData.pciId) - } - } - } - } - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Memory") - checked: cfg.showMemory ?? true - onToggled: checked => root.updateConfig("showMemory", checked) - } - - SettingsDivider { - visible: cfg.showMemory ?? true - } - - SettingsToggleRow { - visible: cfg.showMemory ?? true - text: I18n.tr("Memory Graph") - checked: cfg.showMemoryGraph ?? true - onToggled: checked => root.updateConfig("showMemoryGraph", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Network") - checked: cfg.showNetwork ?? true - onToggled: checked => root.updateConfig("showNetwork", checked) - } - - SettingsDivider { - visible: cfg.showNetwork ?? true - } - - SettingsToggleRow { - visible: cfg.showNetwork ?? true - text: I18n.tr("Network Graph") - checked: cfg.showNetworkGraph ?? true - onToggled: checked => root.updateConfig("showNetworkGraph", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Disk") - checked: cfg.showDisk ?? true - onToggled: checked => root.updateConfig("showDisk", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Top Processes") - checked: cfg.showTopProcesses ?? false - onToggled: checked => root.updateConfig("showTopProcesses", checked) - } - - SettingsDivider { - visible: cfg.showTopProcesses ?? false - } - - Item { - width: parent.width - height: topProcessesColumn.height + Theme.spacingM * 2 - visible: cfg.showTopProcesses ?? false - - Column { - id: topProcessesColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - processCountButtons.width - Theme.spacingM - text: I18n.tr("Process Count") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankButtonGroup { - id: processCountButtons - model: ["3", "5", "10"] - currentIndex: { - switch (cfg.topProcessCount ?? 3) { - case 3: - return 0; - case 5: - return 1; - case 10: - return 2; - default: - return 0; - } - } - buttonHeight: 32 - minButtonWidth: 36 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const values = [3, 5, 10]; - root.updateConfig("topProcessCount", values[index]); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - sortByButtons.width - Theme.spacingM - text: I18n.tr("Sort By") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankButtonGroup { - id: sortByButtons - model: ["CPU", "MEM"] - currentIndex: (cfg.topProcessSortBy ?? "cpu") === "cpu" ? 0 : 1 - buttonHeight: 32 - minButtonWidth: 48 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - root.updateConfig("topProcessSortBy", index === 0 ? "cpu" : "memory"); - } - } - } - } - } - - SettingsDivider {} - - SettingsDropdownRow { - text: I18n.tr("Layout") - options: [I18n.tr("Auto"), I18n.tr("Grid"), I18n.tr("List")] - currentValue: { - switch (cfg.layoutMode ?? "auto") { - case "grid": - return I18n.tr("Grid"); - case "list": - return I18n.tr("List"); - default: - return I18n.tr("Auto"); - } - } - onValueChanged: value => { - switch (value) { - case I18n.tr("Grid"): - root.updateConfig("layoutMode", "grid"); - return; - case I18n.tr("List"): - root.updateConfig("layoutMode", "list"); - return; - default: - root.updateConfig("layoutMode", "auto"); - } - } - } - - SettingsDivider {} - - SettingsSliderRow { - text: I18n.tr("Transparency") - minimum: 0 - maximum: 100 - value: Math.round((cfg.transparency ?? 0.8) * 100) - unit: "%" - onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100) - } - - SettingsDivider {} - - SettingsColorPicker { - colorMode: cfg.colorMode ?? "primary" - customColor: cfg.customColor ?? "#ffffff" - onColorModeSelected: mode => root.updateConfig("colorMode", mode) - onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString()) - } - - SettingsDivider {} - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml deleted file mode 100644 index 5fb2794..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml +++ /dev/null @@ -1,708 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var expandedStates: ({}) - property var groupCollapsedStates: ({}) - property var parentModal: null - property string editingGroupId: "" - property string newGroupName: "" - - readonly property var allInstances: SettingsData.desktopWidgetInstances || [] - readonly property var allGroups: SettingsData.desktopWidgetGroups || [] - - function showWidgetBrowser() { - widgetBrowserLoader.active = true; - if (widgetBrowserLoader.item) - widgetBrowserLoader.item.show(); - } - - function showDesktopPluginBrowser() { - desktopPluginBrowserLoader.active = true; - if (desktopPluginBrowserLoader.item) - desktopPluginBrowserLoader.item.show(); - } - - LazyLoader { - id: widgetBrowserLoader - active: false - - DesktopWidgetBrowser { - parentModal: root.parentModal - onWidgetAdded: widgetType => { - ToastService.showInfo(I18n.tr("Widget added")); - } - } - } - - LazyLoader { - id: desktopPluginBrowserLoader - active: false - - PluginBrowser { - parentModal: root.parentModal - typeFilter: "desktop-widget" - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "widgets" - title: I18n.tr("Desktop Widgets") - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Add and configure widgets that appear on your desktop") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Add Widget") - iconName: "add" - onClicked: root.showWidgetBrowser() - } - - DankButton { - text: I18n.tr("Browse Plugins") - iconName: "store" - onClicked: root.showDesktopPluginBrowser() - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "folder" - title: I18n.tr("Groups") - collapsible: true - expanded: root.allGroups.length > 0 - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Organize widgets into collapsible groups") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingS - width: parent.width - - DankTextField { - id: newGroupField - width: parent.width - addGroupBtn.width - Theme.spacingS - placeholderText: I18n.tr("New group name...") - text: root.newGroupName - onTextChanged: root.newGroupName = text - onAccepted: { - if (!text.trim()) - return; - SettingsData.createDesktopWidgetGroup(text.trim()); - root.newGroupName = ""; - text = ""; - } - } - - DankButton { - id: addGroupBtn - iconName: "add" - text: I18n.tr("Add") - enabled: root.newGroupName.trim().length > 0 - onClicked: { - SettingsData.createDesktopWidgetGroup(root.newGroupName.trim()); - root.newGroupName = ""; - newGroupField.text = ""; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: root.allGroups.length > 0 - - Repeater { - model: root.allGroups - - Rectangle { - id: groupItem - required property var modelData - required property int index - - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: groupMouseArea.containsMouse ? Theme.surfaceHover : Theme.surfaceContainer - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "folder" - size: Theme.iconSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Loader { - active: root.editingGroupId === groupItem.modelData.id - width: active ? parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3 : 0 - height: active ? 32 : 0 - anchors.verticalCenter: parent.verticalCenter - - sourceComponent: DankTextField { - text: groupItem.modelData.name - onAccepted: { - if (!text.trim()) - return; - SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, { - name: text.trim() - }); - root.editingGroupId = ""; - } - onEditingFinished: { - if (!text.trim()) - return; - SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, { - name: text.trim() - }); - root.editingGroupId = ""; - } - Component.onCompleted: forceActiveFocus() - } - } - - StyledText { - visible: root.editingGroupId !== groupItem.modelData.id - text: groupItem.modelData.name - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3 - } - - DankActionButton { - id: deleteGroupBtn - iconName: "delete" - anchors.verticalCenter: parent.verticalCenter - onClicked: { - SettingsData.removeDesktopWidgetGroup(groupItem.modelData.id); - ToastService.showInfo(I18n.tr("Group removed")); - } - } - } - - MouseArea { - id: groupMouseArea - anchors.fill: parent - hoverEnabled: true - onDoubleClicked: root.editingGroupId = groupItem.modelData.id - } - } - } - } - } - } - - Repeater { - model: root.allGroups - - Column { - id: groupSection - required property var modelData - required property int index - - readonly property string groupId: modelData.id - readonly property var groupInstances: root.allInstances.filter(inst => inst.group === groupId) - - width: mainColumn.width - spacing: Theme.spacingM - visible: groupInstances.length > 0 - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: (root.groupCollapsedStates[groupSection.groupId] ?? false) ? "expand_more" : "expand_less" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "folder" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: groupSection.modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "(" + groupSection.groupInstances.length + ")" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - var states = Object.assign({}, root.groupCollapsedStates); - states[groupSection.groupId] = !(states[groupSection.groupId] ?? false); - root.groupCollapsedStates = states; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !(root.groupCollapsedStates[groupSection.groupId] ?? false) - leftPadding: Theme.spacingM - - Repeater { - model: ScriptModel { - objectProp: "id" - values: groupSection.groupInstances - } - - Item { - id: groupDelegateItem - required property var modelData - required property int index - - property bool held: groupDragArea.pressed - property real originalY: y - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = root.allInstances; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - width: groupSection.width - Theme.spacingM - height: groupCard.height - z: held ? 2 : 1 - - DesktopWidgetInstanceCard { - id: groupCard - width: parent.width - headerLeftPadding: 20 - instanceData: groupDelegateItem.liveInstanceData - isExpanded: root.expandedStates[groupDelegateItem.instanceIdRef] ?? false - - onExpandedChanged: { - if (expanded === (root.expandedStates[groupDelegateItem.instanceIdRef] ?? false)) - return; - var states = Object.assign({}, root.expandedStates); - states[groupDelegateItem.instanceIdRef] = expanded; - root.expandedStates = states; - } - - onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(groupDelegateItem.instanceIdRef) - - onDeleteRequested: { - SettingsData.removeDesktopWidgetInstance(groupDelegateItem.instanceIdRef); - ToastService.showInfo(I18n.tr("Widget removed")); - } - } - - MouseArea { - id: groupDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: 50 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: groupDelegateItem.held ? groupDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - groupDelegateItem.z = 2; - groupDelegateItem.originalY = groupDelegateItem.y; - } - onReleased: { - groupDelegateItem.z = 1; - if (!drag.active) { - groupDelegateItem.y = groupDelegateItem.originalY; - return; - } - const spacing = Theme.spacingM; - const itemH = groupDelegateItem.height + spacing; - var newIndex = Math.round(groupDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, groupSection.groupInstances.length - 1)); - if (newIndex !== groupDelegateItem.index) - SettingsData.reorderDesktopWidgetInstanceInGroup(groupDelegateItem.instanceIdRef, groupSection.groupId, newIndex); - groupDelegateItem.y = groupDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingL - 2 - y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: groupDragArea.containsMouse || groupDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !groupDragArea.pressed && !groupDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - - Column { - id: ungroupedSection - width: parent.width - spacing: Theme.spacingM - visible: ungroupedInstances.length > 0 - - readonly property var ungroupedInstances: root.allInstances.filter(inst => { - if (!inst.group) - return true; - return !root.allGroups.some(g => g.id === inst.group); - }) - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.allGroups.length > 0 - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: (root.groupCollapsedStates["_ungrouped"] ?? false) ? "expand_more" : "expand_less" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "widgets" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Ungrouped") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "(" + ungroupedSection.ungroupedInstances.length + ")" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - var states = Object.assign({}, root.groupCollapsedStates); - states["_ungrouped"] = !(states["_ungrouped"] ?? false); - root.groupCollapsedStates = states; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !(root.groupCollapsedStates["_ungrouped"] ?? false) - leftPadding: root.allGroups.length > 0 ? Theme.spacingM : 0 - - Repeater { - model: ScriptModel { - objectProp: "id" - values: ungroupedSection.ungroupedInstances - } - - Item { - id: ungroupedDelegateItem - required property var modelData - required property int index - - property bool held: ungroupedDragArea.pressed - property real originalY: y - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = root.allInstances; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - width: ungroupedSection.width - (root.allGroups.length > 0 ? Theme.spacingM : 0) - height: ungroupedCard.height - z: held ? 2 : 1 - - DesktopWidgetInstanceCard { - id: ungroupedCard - width: parent.width - headerLeftPadding: 20 - instanceData: ungroupedDelegateItem.liveInstanceData - isExpanded: root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false - - onExpandedChanged: { - if (expanded === (root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false)) - return; - var states = Object.assign({}, root.expandedStates); - states[ungroupedDelegateItem.instanceIdRef] = expanded; - root.expandedStates = states; - } - - onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef) - - onDeleteRequested: { - SettingsData.removeDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef); - ToastService.showInfo(I18n.tr("Widget removed")); - } - } - - MouseArea { - id: ungroupedDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: 50 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: ungroupedDelegateItem.held ? ungroupedDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - ungroupedDelegateItem.z = 2; - ungroupedDelegateItem.originalY = ungroupedDelegateItem.y; - } - onReleased: { - ungroupedDelegateItem.z = 1; - if (!drag.active) { - ungroupedDelegateItem.y = ungroupedDelegateItem.originalY; - return; - } - const spacing = Theme.spacingM; - const itemH = ungroupedDelegateItem.height + spacing; - var newIndex = Math.round(ungroupedDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, ungroupedSection.ungroupedInstances.length - 1)); - if (newIndex !== ungroupedDelegateItem.index) - SettingsData.reorderDesktopWidgetInstanceInGroup(ungroupedDelegateItem.instanceIdRef, null, newIndex); - ungroupedDelegateItem.y = ungroupedDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingL - 2 - y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: ungroupedDragArea.containsMouse || ungroupedDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !ungroupedDragArea.pressed && !ungroupedDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - StyledText { - visible: root.allInstances.length === 0 - text: I18n.tr("No widgets added. Click \"Add Widget\" to get started.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - SettingsCard { - width: parent.width - iconName: "info" - title: I18n.tr("Help") - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: 40 - height: 40 - radius: 20 - color: Theme.primarySelected - - DankIcon { - anchors.centerIn: parent - name: "drag_pan" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 40 - Theme.spacingM - - StyledText { - text: I18n.tr("Move Widget") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Right-click and drag anywhere on the widget") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: 40 - height: 40 - radius: 20 - color: Theme.primarySelected - - DankIcon { - anchors.centerIn: parent - name: "open_in_full" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 40 - Theme.spacingM - - StyledText { - text: I18n.tr("Resize Widget") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Right-click and drag the bottom-right corner") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml deleted file mode 100644 index b6e253b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml +++ /dev/null @@ -1,1837 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import qs.Common -import qs.Services - -Singleton { - id: root - - readonly property bool hasOutputBackend: WlrOutputService.wlrOutputAvailable - readonly property var wlrOutputs: WlrOutputService.outputs - property var outputs: ({}) - property var savedOutputs: ({}) - property var allOutputs: buildAllOutputsMap() - - property var includeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingInclude: false - property bool fixingInclude: false - - property var pendingChanges: ({}) - property var pendingNiriChanges: ({}) - property var pendingHyprlandChanges: ({}) - property var originalNiriSettings: null - property var originalHyprlandSettings: null - property var originalOutputs: null - property string originalDisplayNameMode: "" - property bool formatChanged: originalDisplayNameMode !== "" && originalDisplayNameMode !== SettingsData.displayNameMode - property bool hasPendingChanges: Object.keys(pendingChanges).length > 0 || Object.keys(pendingNiriChanges).length > 0 || Object.keys(pendingHyprlandChanges).length > 0 || formatChanged - - property bool validatingConfig: false - property string validationError: "" - - property var currentOutputSet: [] - property string matchedProfile: "" - property bool profilesLoading: false - property var validatedProfiles: ({}) - property bool manualActivation: false - - signal changesApplied(var changeDescriptions) - signal changesConfirmed - signal changesReverted - signal profileActivated(string profileId, string profileName) - signal profileSaved(string profileId, string profileName) - signal profileDeleted(string profileId) - signal profileError(string message) - - function buildCurrentOutputSet() { - const connected = []; - for (const name in outputs) { - const output = outputs[name]; - connected.push(getOutputIdentifier(output, name)); - } - return connected.sort(); - } - - function getOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - if (CompositorService.isNiri) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return output.make + " " + output.model; - } - return outputName; - } - - function validateProfiles() { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profilesDir = getProfilesDir(); - const ext = getProfileExtension(); - - if (!profilesDir) { - validatedProfiles = {}; - return; - } - - const profileIds = Object.keys(profiles); - if (profileIds.length === 0) { - validatedProfiles = {}; - return; - } - - const fileChecks = profileIds.map(id => profilesDir + "/" + id + ext).join(" "); - Proc.runCommand("validate-profiles", ["sh", "-c", `for f in ${fileChecks}; do [ -f "$f" ] && echo "$f"; done`], (output, exitCode) => { - const existingFiles = new Set(output.trim().split("\n").filter(f => f)); - const validated = {}; - for (const profileId of profileIds) { - const profileFile = profilesDir + "/" + profileId + ext; - if (existingFiles.has(profileFile)) - validated[profileId] = profiles[profileId]; - else - SettingsData.removeDisplayProfile(compositor, profileId); - } - validatedProfiles = validated; - matchedProfile = findMatchingProfile(); - }); - } - - function findMatchingProfile() { - const profiles = validatedProfiles; - - console.log("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet)); - - let bestMatch = ""; - let bestScore = -1; - let bestUpdatedAt = 0; - - for (const profileId in profiles) { - const profile = profiles[profileId]; - const profileSet = new Set(profile.outputSet); - - console.log("[Profile Match] Checking", profile.name, "outputSet:", JSON.stringify(profile.outputSet)); - - let allCurrentPresent = true; - for (const output of currentOutputSet) { - if (!profileSet.has(output)) { - console.log("[Profile Match] - Missing output:", output); - allCurrentPresent = false; - break; - } - } - if (!allCurrentPresent) { - console.log("[Profile Match] - SKIP: not all current outputs present"); - continue; - } - - const disconnectedCount = profile.outputSet.length - currentOutputSet.length; - const score = currentOutputSet.length * 100 - disconnectedCount; - const updatedAt = profile.updatedAt || profile.createdAt || 0; - console.log("[Profile Match] - MATCH score:", score, "(disconnected:", disconnectedCount, "updatedAt:", updatedAt + ")"); - - if (score > bestScore || (score === bestScore && updatedAt > bestUpdatedAt)) { - bestScore = score; - bestMatch = profileId; - bestUpdatedAt = updatedAt; - } - } - console.log("[Profile Match] Best match:", bestMatch, "score:", bestScore); - return bestMatch; - } - - function getProfilesDir() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return configDir + "/niri/dms/profiles"; - case "hyprland": - return configDir + "/hypr/dms/profiles"; - case "dwl": - return configDir + "/mango/dms/profiles"; - default: - return ""; - } - } - - function getProfileExtension() { - return CompositorService.compositor === "niri" ? ".kdl" : ".conf"; - } - - function createProfile(name) { - const compositor = CompositorService.compositor; - const profileId = "profile_" + Date.now() + "_" + Math.random().toString(36).substr(2, 6); - const outputSet = buildCurrentOutputSet(); - const now = Date.now(); - - const profileData = { - "id": profileId, - "name": name, - "outputSet": outputSet, - "createdAt": now, - "updatedAt": now - }; - - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const paths = getConfigPaths(); - if (!paths) { - profileError(I18n.tr("Compositor not supported")); - return; - } - - profilesLoading = true; - Proc.runCommand("create-profile-dir", ["mkdir", "-p", profilesDir], (output, exitCode) => { - if (exitCode !== 0) { - profilesLoading = false; - profileError(I18n.tr("Failed to create profiles directory")); - return; - } - Proc.runCommand("copy-profile", ["cp", "-L", paths.outputsFile, profileFile], (output2, exitCode2) => { - if (exitCode2 !== 0) { - profilesLoading = false; - profileError(I18n.tr("Failed to save profile file")); - return; - } - SettingsData.setDisplayProfile(compositor, profileId, profileData); - SettingsData.setActiveDisplayProfile(compositor, profileId); - const updated = JSON.parse(JSON.stringify(validatedProfiles)); - updated[profileId] = profileData; - validatedProfiles = updated; - Proc.runCommand("link-new-profile", ["ln", "-sf", profileFile, paths.outputsFile], () => { - profilesLoading = false; - currentOutputSet = outputSet; - matchedProfile = profileId; - profileSaved(profileId, name); - }); - }); - }); - } - - function renameProfile(profileId, newName) { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profile = profiles[profileId]; - if (!profile) { - profileError(I18n.tr("Profile not found")); - return; - } - profile.name = newName; - profile.updatedAt = Date.now(); - SettingsData.setDisplayProfile(compositor, profileId, profile); - } - - function deleteProfile(profileId) { - const compositor = CompositorService.compositor; - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const isActive = SettingsData.getActiveDisplayProfile(compositor) === profileId; - - profilesLoading = true; - Proc.runCommand("delete-profile", ["rm", "-f", profileFile], (output, exitCode) => { - profilesLoading = false; - SettingsData.removeDisplayProfile(compositor, profileId); - if (isActive) { - SettingsData.setActiveDisplayProfile(compositor, ""); - backendWriteOutputsConfig(allOutputs); - } - const updated = JSON.parse(JSON.stringify(validatedProfiles)); - delete updated[profileId]; - validatedProfiles = updated; - matchedProfile = findMatchingProfile(); - profileDeleted(profileId); - }); - } - - function activateProfile(profileId) { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profile = profiles[profileId]; - if (!profile) { - profileError(I18n.tr("Profile not found")); - return; - } - - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const paths = getConfigPaths(); - if (!paths) - return; - - manualActivation = true; - profilesLoading = true; - Proc.runCommand("activate-profile", ["ln", "-sf", profileFile, paths.outputsFile], (output, exitCode) => { - if (exitCode !== 0) { - profilesLoading = false; - manualActivation = false; - profileError(I18n.tr("Failed to activate profile - file not found")); - return; - } - SettingsData.setActiveDisplayProfile(compositor, profileId); - - const reloadCmd = CompositorService.isNiri ? ["niri", "msg", "action", "reload-config-or-panic"] : CompositorService.isHyprland ? ["hyprctl", "reload"] : []; - if (reloadCmd.length > 0) { - Proc.runCommand("reload-compositor", reloadCmd, (output2, exitCode2) => { - profilesLoading = false; - WlrOutputService.requestState(); - profileActivated(profileId, profile.name); - manualActivationTimer.restart(); - }); - } else { - profilesLoading = false; - profileActivated(profileId, profile.name); - manualActivationTimer.restart(); - } - }); - } - - Timer { - id: manualActivationTimer - interval: 2000 - onTriggered: root.manualActivation = false - } - - Timer { - id: autoSelectDebounceTimer - interval: 800 - onTriggered: root.doAutoSelectProfile() - } - - // ! TODO - auto profile switching is buggy on niri and other compositors, might need a longer debounce before updating output configuration idk - function autoSelectProfile() { - return; // disabled - autoSelectDebounceTimer.restart(); - } - - function doAutoSelectProfile() { - return; // disabled - if (!SettingsData.displayProfileAutoSelect || manualActivation) - return; - currentOutputSet = buildCurrentOutputSet(); - const matched = findMatchingProfile(); - matchedProfile = matched; - if (matched && matched !== SettingsData.getActiveDisplayProfile(CompositorService.compositor)) - activateProfile(matched); - } - - function deleteDisconnectedOutput(outputName) { - if (outputs[outputName]?.connected) - return; - - const updated = JSON.parse(JSON.stringify(savedOutputs)); - delete updated[outputName]; - savedOutputs = updated; - - const mergedOutputs = {}; - for (const name in outputs) - mergedOutputs[name] = outputs[name]; - for (const name in updated) - mergedOutputs[name] = updated[name]; - - backendWriteOutputsConfig(mergedOutputs); - } - - function buildAllOutputsMap() { - const result = {}; - for (const name in savedOutputs) { - result[name] = Object.assign({}, savedOutputs[name], { - "connected": false - }); - } - for (const name in outputs) { - result[name] = Object.assign({}, outputs[name], { - "connected": true - }); - } - return result; - } - - onOutputsChanged: { - allOutputs = buildAllOutputsMap(); - currentOutputSet = buildCurrentOutputSet(); - matchedProfile = findMatchingProfile(); - // ! TODO - auto profile switching disabled for now - // if (SettingsData.displayProfileAutoSelect) - // Qt.callLater(autoSelectProfile); - } - onSavedOutputsChanged: allOutputs = buildAllOutputsMap() - - Connections { - target: WlrOutputService - function onStateChanged() { - root.outputs = root.buildOutputsMap(); - root.reloadSavedOutputs(); - } - } - - Component.onCompleted: { - outputs = buildOutputsMap(); - reloadSavedOutputs(); - checkIncludeStatus(); - currentOutputSet = buildCurrentOutputSet(); - validateProfiles(); - } - - function reloadSavedOutputs() { - const paths = getConfigPaths(); - if (!paths) { - savedOutputs = {}; - return; - } - - Proc.runCommand("load-saved-outputs", ["cat", paths.outputsFile], (content, exitCode) => { - if (exitCode !== 0 || !content.trim()) { - savedOutputs = {}; - return; - } - const parsed = parseOutputsConfig(content); - const filtered = filterDisconnectedOnly(parsed); - savedOutputs = filtered; - - if (CompositorService.isHyprland) { - initHyprlandSettingsFromConfig(parsed); - syncHyprlandVrrFromConfig(parsed); - } - if (CompositorService.isNiri) - syncNiriVrrFromConfig(parsed); - }); - } - - function initHyprlandSettingsFromConfig(parsedOutputs) { - const current = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - let changed = false; - - for (const outputName in parsedOutputs) { - const output = parsedOutputs[outputName]; - const settings = output.hyprlandSettings; - if (!settings) - continue; - - if (current[outputName]) - continue; - - const hasSettings = settings.colorManagement || settings.bitdepth || settings.sdrBrightness !== undefined || settings.sdrSaturation !== undefined; - if (!hasSettings) - continue; - - current[outputName] = {}; - if (settings.colorManagement) - current[outputName].colorManagement = settings.colorManagement; - if (settings.bitdepth) - current[outputName].bitdepth = settings.bitdepth; - if (settings.sdrBrightness !== undefined) - current[outputName].sdrBrightness = settings.sdrBrightness; - if (settings.sdrSaturation !== undefined) - current[outputName].sdrSaturation = settings.sdrSaturation; - changed = true; - } - - if (changed) { - SettingsData.hyprlandOutputSettings = current; - SettingsData.saveSettings(); - } - } - - function syncHyprlandVrrFromConfig(parsedOutputs) { - const current = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - let changed = false; - for (const outputName in parsedOutputs) { - const settings = parsedOutputs[outputName]?.hyprlandSettings; - const fromConfig = settings?.vrrFullscreenOnly ?? false; - const stored = current[outputName]?.vrrFullscreenOnly ?? false; - if (fromConfig === stored) - continue; - if (!current[outputName]) - current[outputName] = {}; - if (fromConfig) - current[outputName].vrrFullscreenOnly = true; - else - delete current[outputName].vrrFullscreenOnly; - changed = true; - } - if (changed) { - SettingsData.hyprlandOutputSettings = current; - SettingsData.saveSettings(); - } - } - - function syncNiriVrrFromConfig(parsedOutputs) { - let changed = false; - for (const outputName in parsedOutputs) { - const output = parsedOutputs[outputName]; - const current = SettingsData.getNiriOutputSetting(outputName, "vrrOnDemand", false); - const fromConfig = output.vrr_on_demand ?? false; - if (current === fromConfig) - continue; - SettingsData.setNiriOutputSetting(outputName, "vrrOnDemand", fromConfig || undefined); - changed = true; - } - if (changed) - SettingsData.saveSettings(); - } - - function filterDisconnectedOnly(parsedOutputs) { - const result = {}; - const liveNames = Object.keys(outputs); - const liveByIdentifier = {}; - for (const name of liveNames) { - const o = outputs[name]; - if (o?.make && o?.model) { - const serial = o.serial || "Unknown"; - const id = (o.make + " " + o.model + " " + serial).trim(); - liveByIdentifier[id] = true; - liveByIdentifier[o.make + " " + o.model] = true; - } - liveByIdentifier[name] = true; - } - - for (const savedName in parsedOutputs) { - const trimmed = savedName.trim(); - if (!liveByIdentifier[trimmed]) - result[savedName] = parsedOutputs[savedName]; - } - return result; - } - - function parseOutputsConfig(content) { - switch (CompositorService.compositor) { - case "niri": - return parseNiriOutputs(content); - case "hyprland": - return parseHyprlandOutputs(content); - case "dwl": - return parseMangoOutputs(content); - default: - return {}; - } - } - - function parseNiriOutputs(content) { - const result = {}; - const outputRegex = /output\s+"([^"]+)"\s*\{([^}]*)\}/g; - let match; - while ((match = outputRegex.exec(content)) !== null) { - const name = match[1]; - const body = match[2]; - - const modeMatch = body.match(/mode\s+"(\d+)x(\d+)@([\d.]+)"/); - const posMatch = body.match(/position\s+x=(-?\d+)\s+y=(-?\d+)/); - const scaleMatch = body.match(/scale\s+([\d.]+)/); - const transformMatch = body.match(/transform\s+"([^"]+)"/); - const vrrMatch = body.match(/variable-refresh-rate/); - const vrrOnDemandMatch = body.match(/variable-refresh-rate\s+on-demand=true/); - - result[name] = { - "name": name, - "logical": { - "x": posMatch ? parseInt(posMatch[1]) : 0, - "y": posMatch ? parseInt(posMatch[2]) : 0, - "scale": scaleMatch ? parseFloat(scaleMatch[1]) : 1.0, - "transform": transformMatch ? transformMatch[1] : "Normal" - }, - "modes": modeMatch ? [ - { - "width": parseInt(modeMatch[1]), - "height": parseInt(modeMatch[2]), - "refresh_rate": Math.round(parseFloat(modeMatch[3]) * 1000) - } - ] : [], - "current_mode": 0, - "vrr_enabled": !!vrrMatch, - "vrr_on_demand": !!vrrOnDemandMatch, - "vrr_supported": true - }; - } - return result; - } - - function parseHyprlandOutputs(content) { - const result = {}; - const lines = content.split("\n"); - for (const line of lines) { - const disableMatch = line.match(/^\s*monitor\s*=\s*([^,]+),\s*disable\s*$/); - if (disableMatch) { - const name = disableMatch[1].trim(); - result[name] = { - "name": name, - "logical": { - "x": 0, - "y": 0, - "scale": 1.0, - "transform": "Normal" - }, - "modes": [], - "current_mode": -1, - "vrr_enabled": false, - "vrr_supported": false, - "hyprlandSettings": { - "disabled": true - } - }; - continue; - } - const match = line.match(/^\s*monitor\s*=\s*([^,]+),\s*(\d+)x(\d+)@([\d.]+),\s*(-?\d+)x(-?\d+),\s*([\d.]+)/); - if (!match) - continue; - const name = match[1].trim(); - const rest = line.substring(line.indexOf(match[7]) + match[7].length); - - let transform = 0, vrrMode = 0, bitdepth = undefined, cm = undefined; - let sdrBrightness = undefined, sdrSaturation = undefined; - - const transformMatch = rest.match(/,\s*transform,\s*(\d+)/); - if (transformMatch) - transform = parseInt(transformMatch[1]); - - const vrrMatch = rest.match(/,\s*vrr,\s*(\d+)/); - if (vrrMatch) - vrrMode = parseInt(vrrMatch[1]); - - const bitdepthMatch = rest.match(/,\s*bitdepth,\s*(\d+)/); - if (bitdepthMatch) - bitdepth = parseInt(bitdepthMatch[1]); - - const cmMatch = rest.match(/,\s*cm,\s*(\w+)/); - if (cmMatch) - cm = cmMatch[1]; - - const sdrBrightnessMatch = rest.match(/,\s*sdrbrightness,\s*([\d.]+)/); - if (sdrBrightnessMatch) - sdrBrightness = parseFloat(sdrBrightnessMatch[1]); - - const sdrSaturationMatch = rest.match(/,\s*sdrsaturation,\s*([\d.]+)/); - if (sdrSaturationMatch) - sdrSaturation = parseFloat(sdrSaturationMatch[1]); - - let mirror = ""; - const mirrorMatch = rest.match(/,\s*mirror,\s*([^,\s]+)/); - if (mirrorMatch) - mirror = mirrorMatch[1]; - - result[name] = { - "name": name, - "logical": { - "x": parseInt(match[5]), - "y": parseInt(match[6]), - "scale": parseFloat(match[7]), - "transform": hyprlandToTransform(transform) - }, - "modes": [ - { - "width": parseInt(match[2]), - "height": parseInt(match[3]), - "refresh_rate": Math.round(parseFloat(match[4]) * 1000) - } - ], - "current_mode": 0, - "vrr_enabled": vrrMode >= 1, - "vrr_supported": true, - "hyprlandSettings": { - "bitdepth": bitdepth, - "colorManagement": cm, - "sdrBrightness": sdrBrightness, - "sdrSaturation": sdrSaturation, - "vrrFullscreenOnly": vrrMode === 2 ? true : undefined - }, - "mirror": mirror - }; - } - return result; - } - - function hyprlandToTransform(value) { - switch (value) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function parseMangoOutputs(content) { - const result = {}; - const lines = content.split("\n"); - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed.startsWith("monitorrule=")) - continue; - - const params = {}; - for (const pair of trimmed.substring("monitorrule=".length).split(",")) { - const colonIdx = pair.indexOf(":"); - if (colonIdx < 0) - continue; - params[pair.substring(0, colonIdx).trim()] = pair.substring(colonIdx + 1).trim(); - } - - const name = params.name; - if (!name) - continue; - - result[name] = { - "name": name, - "logical": { - "x": parseInt(params.x || "0"), - "y": parseInt(params.y || "0"), - "scale": parseFloat(params.scale || "1"), - "transform": mangoToTransform(parseInt(params.rr || "0")) - }, - "modes": [ - { - "width": parseInt(params.width || "1920"), - "height": parseInt(params.height || "1080"), - "refresh_rate": parseFloat(params.refresh || "60") * 1000 - } - ], - "current_mode": 0, - "vrr_enabled": parseInt(params.vrr || "0") === 1, - "vrr_supported": true - }; - } - return result; - } - - function mangoToTransform(value) { - switch (value) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function getConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "outputsFile": configDir + "/niri/dms/outputs.kdl", - "grepPattern": 'include.*"dms/outputs.kdl"', - "includeLine": 'include "dms/outputs.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "outputsFile": configDir + "/hypr/dms/outputs.conf", - "grepPattern": 'source.*dms/outputs.conf', - "includeLine": "source = ./dms/outputs.conf" - }; - case "dwl": - return { - "configFile": configDir + "/mango/config.conf", - "outputsFile": configDir + "/mango/dms/outputs.conf", - "grepPattern": 'source.*dms/outputs.conf', - "includeLine": "source=./dms/outputs.conf" - }; - default: - return null; - } - } - - function checkIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "dwl") { - includeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "outputs.kdl" : "outputs.conf"; - const compositorArg = (compositor === "dwl") ? "mangowc" : compositor; - - checkingInclude = true; - Proc.runCommand("check-outputs-include", ["dms", "config", "resolve-include", compositorArg, filename], (output, exitCode) => { - checkingInclude = false; - if (exitCode !== 0) { - includeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - includeStatus = JSON.parse(output.trim()); - } catch (e) { - includeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixOutputsInclude() { - const paths = getConfigPaths(); - if (!paths) - return; - - fixingInclude = true; - const outputsDir = paths.outputsFile.substring(0, paths.outputsFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - - Proc.runCommand("fix-outputs-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${outputsDir}" && ` + `touch "${paths.outputsFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingInclude = false; - if (exitCode !== 0) - return; - checkIncludeStatus(); - WlrOutputService.requestState(); - }); - } - - function buildOutputsMap() { - const map = {}; - for (const output of wlrOutputs) { - const normalizedModes = (output.modes || []).map(m => ({ - "id": m.id, - "width": m.width, - "height": m.height, - "refresh_rate": m.refresh, - "preferred": m.preferred ?? false - })); - map[output.name] = { - "name": output.name, - "make": output.make || "", - "model": output.model || "", - "serial": output.serialNumber || "", - "modes": normalizedModes, - "current_mode": normalizedModes.findIndex(m => m.id === output.currentMode?.id), - "vrr_supported": output.adaptiveSyncSupported ?? false, - "vrr_enabled": output.adaptiveSync === 1, - "logical": { - "x": output.x ?? 0, - "y": output.y ?? 0, - "width": output.currentMode?.width ?? 1920, - "height": output.currentMode?.height ?? 1080, - "scale": output.scale ?? 1.0, - "transform": mapWlrTransform(output.transform) - } - }; - } - return map; - } - - function mapWlrTransform(wlrTransform) { - switch (wlrTransform) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function mapTransformToWlr(transform) { - switch (transform) { - case "Normal": - return 0; - case "90": - return 1; - case "180": - return 2; - case "270": - return 3; - case "Flipped": - return 4; - case "Flipped90": - return 5; - case "Flipped180": - return 6; - case "Flipped270": - return 7; - default: - return 0; - } - } - - function backendFetchOutputs() { - WlrOutputService.requestState(); - } - - function backendWriteOutputsConfig(outputsData) { - switch (CompositorService.compositor) { - case "niri": - NiriService.generateOutputsConfig(outputsData); - break; - case "hyprland": - HyprlandService.generateOutputsConfig(outputsData, buildMergedHyprlandSettings()); - break; - case "dwl": - DwlService.generateOutputsConfig(outputsData); - break; - default: - WlrOutputService.applyOutputsConfig(outputsData, outputs); - break; - } - } - - function normalizeOutputPositions(outputsData) { - const names = Object.keys(outputsData); - if (names.length === 0) - return outputsData; - - let minX = Infinity; - let minY = Infinity; - - for (const name of names) { - const output = outputsData[name]; - if (!output.logical) - continue; - minX = Math.min(minX, output.logical.x); - minY = Math.min(minY, output.logical.y); - } - - if (minX === Infinity || (minX === 0 && minY === 0)) - return outputsData; - - const normalized = JSON.parse(JSON.stringify(outputsData)); - for (const name of names) { - if (!normalized[name].logical) - continue; - normalized[name].logical.x -= minX; - normalized[name].logical.y -= minY; - } - - return normalized; - } - - function buildOutputsWithPendingChanges() { - const result = {}; - - for (const outputName in savedOutputs) { - if (!outputs[outputName]) - result[outputName] = JSON.parse(JSON.stringify(savedOutputs[outputName])); - } - - for (const outputName in outputs) { - result[outputName] = JSON.parse(JSON.stringify(outputs[outputName])); - } - - for (const outputName in pendingChanges) { - if (!result[outputName]) - continue; - const changes = pendingChanges[outputName]; - if (changes.position && result[outputName].logical) { - result[outputName].logical.x = changes.position.x; - result[outputName].logical.y = changes.position.y; - } - if (changes.mode !== undefined && result[outputName].modes) { - for (var i = 0; i < result[outputName].modes.length; i++) { - if (formatMode(result[outputName].modes[i]) === changes.mode) { - result[outputName].current_mode = i; - break; - } - } - } - if (changes.scale !== undefined && result[outputName].logical) - result[outputName].logical.scale = changes.scale; - if (changes.transform !== undefined && result[outputName].logical) - result[outputName].logical.transform = changes.transform; - if (changes.vrr !== undefined) - result[outputName].vrr_enabled = changes.vrr; - if (changes.mirror !== undefined) - result[outputName].mirror = changes.mirror; - } - return normalizeOutputPositions(result); - } - - function backendUpdateOutputPosition(outputName, x, y) { - if (!outputs || !outputs[outputName]) - return; - const updatedOutputs = {}; - for (const name in outputs) { - const output = outputs[name]; - if (name === outputName && output.logical) { - updatedOutputs[name] = JSON.parse(JSON.stringify(output)); - updatedOutputs[name].logical.x = x; - updatedOutputs[name].logical.y = y; - } else { - updatedOutputs[name] = output; - } - } - outputs = updatedOutputs; - } - - function backendUpdateOutputScale(outputName, scale) { - if (!outputs || !outputs[outputName]) - return; - const updatedOutputs = {}; - for (const name in outputs) { - const output = outputs[name]; - if (name === outputName && output.logical) { - updatedOutputs[name] = JSON.parse(JSON.stringify(output)); - updatedOutputs[name].logical.scale = scale; - } else { - updatedOutputs[name] = output; - } - } - outputs = updatedOutputs; - } - - function getOutputDisplayName(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - if (CompositorService.isNiri) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return output.make + " " + output.model; - } - return outputName; - } - - function getNiriOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return outputName; - } - - function getNiriSetting(output, outputName, key, defaultValue) { - if (!CompositorService.isNiri) - return defaultValue; - const identifier = getNiriOutputIdentifier(output, outputName); - const pending = pendingNiriChanges[identifier]; - if (pending && pending[key] !== undefined) - return pending[key]; - return SettingsData.getNiriOutputSetting(identifier, key, defaultValue); - } - - function setNiriSetting(output, outputName, key, value) { - if (!CompositorService.isNiri) - return; - initOriginalNiriSettings(); - const identifier = getNiriOutputIdentifier(output, outputName); - const newPending = JSON.parse(JSON.stringify(pendingNiriChanges)); - if (!newPending[identifier]) - newPending[identifier] = {}; - newPending[identifier][key] = value; - pendingNiriChanges = newPending; - } - - function initOriginalNiriSettings() { - if (originalNiriSettings) - return; - originalNiriSettings = JSON.parse(JSON.stringify(SettingsData.niriOutputSettings)); - } - - function getHyprlandOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) - return "desc:" + output.make + " " + output.model + " " + (output?.serial || "Unknown"); - return outputName; - } - - function getHyprlandSetting(output, outputName, key, defaultValue) { - if (!CompositorService.isHyprland) - return defaultValue; - const identifier = getHyprlandOutputIdentifier(output, outputName); - const pending = pendingHyprlandChanges[identifier]; - if (pending && (key in pending)) { - const val = pending[key]; - return (val !== null && val !== undefined) ? val : defaultValue; - } - return SettingsData.getHyprlandOutputSetting(identifier, key, defaultValue); - } - - function setHyprlandSetting(output, outputName, key, value) { - if (!CompositorService.isHyprland) - return; - initOriginalHyprlandSettings(); - const identifier = getHyprlandOutputIdentifier(output, outputName); - const newPending = JSON.parse(JSON.stringify(pendingHyprlandChanges)); - if (!newPending[identifier]) - newPending[identifier] = {}; - newPending[identifier][key] = value; - pendingHyprlandChanges = newPending; - } - - function initOriginalHyprlandSettings() { - if (originalHyprlandSettings) - return; - originalHyprlandSettings = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - } - - function initOriginalOutputs() { - if (!originalOutputs) - originalOutputs = JSON.parse(JSON.stringify(outputs)); - } - - function setPendingChange(outputName, key, value) { - initOriginalOutputs(); - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[outputName]) - newPending[outputName] = {}; - newPending[outputName][key] = value; - pendingChanges = newPending; - - if (key === "scale") { - recalculateAdjacentPositions(outputName, value); - backendUpdateOutputScale(outputName, value); - } - } - - function recalculateAdjacentPositions(changedOutput, newScale) { - const output = outputs[changedOutput]; - if (!output?.logical) - return; - const oldPhys = getPhysicalSize(output); - const oldLogicalW = Math.round(oldPhys.w / (output.logical.scale || 1.0)); - const newLogicalW = Math.round(oldPhys.w / newScale); - - const changedX = getPendingValue(changedOutput, "position")?.x ?? output.logical.x; - const changedY = getPendingValue(changedOutput, "position")?.y ?? output.logical.y; - - for (const name in outputs) { - if (name === changedOutput) - continue; - const other = outputs[name]; - if (!other?.logical) - continue; - const otherX = getPendingValue(name, "position")?.x ?? other.logical.x; - const otherY = getPendingValue(name, "position")?.y ?? other.logical.y; - const otherSize = getLogicalSize(other); - const otherRight = otherX + otherSize.w; - - if (Math.abs(changedX - otherRight) < 5) { - const newX = otherRight; - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[changedOutput]) - newPending[changedOutput] = {}; - newPending[changedOutput].position = { - "x": newX, - "y": changedY - }; - pendingChanges = newPending; - backendUpdateOutputPosition(changedOutput, newX, changedY); - return; - } - - const changedRight = changedX + oldLogicalW; - if (Math.abs(otherX - changedRight) < 5) { - const newOtherX = changedX + newLogicalW; - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[name]) - newPending[name] = {}; - newPending[name].position = { - "x": newOtherX, - "y": otherY - }; - pendingChanges = newPending; - backendUpdateOutputPosition(name, newOtherX, otherY); - } - } - } - - function getPendingValue(outputName, key) { - if (!pendingChanges[outputName]) - return undefined; - return pendingChanges[outputName][key]; - } - - function getEffectiveValue(outputName, key, originalValue) { - const pending = getPendingValue(outputName, key); - return pending !== undefined ? pending : originalValue; - } - - function clearPendingChanges() { - pendingChanges = {}; - pendingNiriChanges = {}; - pendingHyprlandChanges = {}; - originalOutputs = null; - originalNiriSettings = null; - originalHyprlandSettings = null; - originalDisplayNameMode = ""; - } - - function discardChanges() { - if (originalDisplayNameMode !== "") { - SettingsData.displayNameMode = originalDisplayNameMode; - SettingsData.saveSettings(); - } - backendFetchOutputs(); - clearPendingChanges(); - } - - function applyChanges() { - if (!hasPendingChanges) - return; - const changeDescriptions = []; - - if (formatChanged) { - const formatLabel = SettingsData.displayNameMode === "model" ? I18n.tr("Model") : I18n.tr("Name"); - changeDescriptions.push(I18n.tr("Config Format") + " → " + formatLabel); - } - - for (const outputName in pendingChanges) { - const changes = pendingChanges[outputName]; - if (changes.position) - changeDescriptions.push(outputName + ": " + I18n.tr("Position") + " → " + changes.position.x + ", " + changes.position.y); - if (changes.mode) - changeDescriptions.push(outputName + ": " + I18n.tr("Mode") + " → " + changes.mode); - if (changes.scale !== undefined) - changeDescriptions.push(outputName + ": " + I18n.tr("Scale") + " → " + changes.scale); - if (changes.transform) - changeDescriptions.push(outputName + ": " + I18n.tr("Transform") + " → " + getTransformLabel(changes.transform)); - if (changes.vrr !== undefined) - changeDescriptions.push(outputName + ": " + I18n.tr("VRR") + " → " + (changes.vrr ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - } - - for (const outputId in pendingNiriChanges) { - const changes = pendingNiriChanges[outputId]; - if (changes.disabled !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Disabled") + " → " + (changes.disabled ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.vrrOnDemand !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("VRR On-Demand") + " → " + (changes.vrrOnDemand ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - if (changes.focusAtStartup !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Focus at Startup") + " → " + (changes.focusAtStartup ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.hotCorners !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Hot Corners") + " → " + I18n.tr("Modified")); - if (changes.layout !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Layout") + " → " + I18n.tr("Modified")); - } - - for (const outputId in pendingHyprlandChanges) { - const changes = pendingHyprlandChanges[outputId]; - if (changes.disabled !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Disabled") + " → " + (changes.disabled ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.bitdepth !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Bit Depth") + " → " + changes.bitdepth); - if (changes.colorManagement !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Color Management") + " → " + changes.colorManagement); - if (changes.sdrBrightness !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("SDR Brightness") + " → " + changes.sdrBrightness); - if (changes.sdrSaturation !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("SDR Saturation") + " → " + changes.sdrSaturation); - if (changes.supportsHdr !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Force HDR") + " → " + (changes.supportsHdr ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.supportsWideColor !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Force Wide Color") + " → " + (changes.supportsWideColor ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.vrrFullscreenOnly !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("VRR Fullscreen Only") + " → " + (changes.vrrFullscreenOnly ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - } - - if (CompositorService.isNiri) { - validateAndApplyNiriConfig(changeDescriptions); - return; - } - - changesApplied(changeDescriptions); - - if (formatChanged) - SettingsData.saveSettings(); - - if (CompositorService.isHyprland) - commitHyprlandSettingsChanges(); - - const mergedOutputs = buildOutputsWithPendingChanges(); - backendWriteOutputsConfig(mergedOutputs); - } - - function validateAndApplyNiriConfig(changeDescriptions) { - validatingConfig = true; - validationError = ""; - - const mergedOutputs = buildOutputsWithPendingChanges(); - const mergedNiriSettings = buildMergedNiriSettings(); - const configContent = generateNiriOutputsKdl(mergedOutputs, mergedNiriSettings); - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const tempFile = configDir + "/niri/dms/.outputs-validate-tmp.kdl"; - - Proc.runCommand("niri-validate-write-tmp", ["sh", "-c", `mkdir -p "$(dirname "${tempFile}")" && cat > "${tempFile}" << 'EOF'\n${configContent}EOF`], (output, writeExitCode) => { - if (writeExitCode !== 0) { - validatingConfig = false; - validationError = I18n.tr("Failed to write temp file for validation"); - ToastService.showError(I18n.tr("Config validation failed"), validationError, "", "display-config"); - return; - } - Proc.runCommand("niri-validate-config", ["sh", "-c", `niri validate -c "${tempFile}" 2>&1`], (validateOutput, validateExitCode) => { - validatingConfig = false; - Proc.runCommand("niri-validate-cleanup", ["rm", "-f", tempFile], () => {}); - if (validateExitCode !== 0) { - validationError = validateOutput.trim() || I18n.tr("Invalid configuration"); - ToastService.showError(I18n.tr("Config validation failed"), validationError, "", "display-config"); - return; - } - changesApplied(changeDescriptions); - if (formatChanged) - SettingsData.saveSettings(); - commitNiriSettingsChanges(); - backendWriteOutputsConfig(mergedOutputs); - }); - }); - } - - function buildMergedNiriSettings() { - const merged = JSON.parse(JSON.stringify(SettingsData.niriOutputSettings)); - for (const outputId in pendingNiriChanges) { - if (!merged[outputId]) - merged[outputId] = {}; - for (const key in pendingNiriChanges[outputId]) { - merged[outputId][key] = pendingNiriChanges[outputId][key]; - } - } - return merged; - } - - function commitNiriSettingsChanges() { - for (const outputId in pendingNiriChanges) { - for (const key in pendingNiriChanges[outputId]) { - SettingsData.setNiriOutputSetting(outputId, key, pendingNiriChanges[outputId][key]); - } - } - } - - function buildMergedHyprlandSettings() { - const merged = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - for (const outputId in pendingHyprlandChanges) { - if (!merged[outputId]) - merged[outputId] = {}; - for (const key in pendingHyprlandChanges[outputId]) { - const val = pendingHyprlandChanges[outputId][key]; - if (val === null || val === undefined) - delete merged[outputId][key]; - else - merged[outputId][key] = val; - } - } - return merged; - } - - function commitHyprlandSettingsChanges() { - for (const outputId in pendingHyprlandChanges) { - for (const key in pendingHyprlandChanges[outputId]) { - const val = pendingHyprlandChanges[outputId][key]; - if (val === null || val === undefined) - SettingsData.removeHyprlandOutputSetting(outputId, key); - else - SettingsData.setHyprlandOutputSetting(outputId, key, val); - } - } - } - - function generateNiriOutputsKdl(outputsData, niriSettings) { - let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`; - const sortedNames = Object.keys(outputsData).sort((a, b) => { - const la = outputsData[a].logical || {}; - const lb = outputsData[b].logical || {}; - return (la.x ?? 0) - (lb.x ?? 0) || (la.y ?? 0) - (lb.y ?? 0); - }); - for (const outputName of sortedNames) { - const output = outputsData[outputName]; - const identifier = getNiriOutputIdentifier(output, outputName); - const settings = niriSettings[identifier] || {}; - kdlContent += `output "${identifier}" {\n`; - if (settings.disabled) { - kdlContent += ` off\n}\n\n`; - continue; - } - if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) { - const mode = output.modes[output.current_mode]; - kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`; - } - if (output.logical) { - kdlContent += ` scale ${output.logical.scale ?? 1.0}\n`; - if (output.logical.transform && output.logical.transform !== "Normal") { - const transformMap = { - "Normal": "normal", - "90": "90", - "180": "180", - "270": "270", - "Flipped": "flipped", - "Flipped90": "flipped-90", - "Flipped180": "flipped-180", - "Flipped270": "flipped-270" - }; - kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`; - } - if (output.logical.x !== undefined && output.logical.y !== undefined) - kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`; - } - if (settings.vrrOnDemand) { - kdlContent += ` variable-refresh-rate on-demand=true\n`; - } else if (output.vrr_enabled) { - kdlContent += ` variable-refresh-rate\n`; - } - if (settings.focusAtStartup) - kdlContent += ` focus-at-startup\n`; - if (settings.backdropColor) - kdlContent += ` backdrop-color "${settings.backdropColor}"\n`; - kdlContent += generateHotCornersBlock(settings); - kdlContent += generateLayoutBlock(settings); - kdlContent += `}\n\n`; - } - return kdlContent; - } - - function generateHotCornersBlock(settings) { - if (!settings.hotCorners) - return ""; - const hc = settings.hotCorners; - if (hc.off) - return ` hot-corners {\n off\n }\n`; - const corners = hc.corners || []; - if (corners.length === 0) - return ""; - let block = ` hot-corners {\n`; - for (const corner of corners) - block += ` ${corner}\n`; - block += ` }\n`; - return block; - } - - function generateLayoutBlock(settings) { - if (!settings.layout) - return ""; - const layout = settings.layout; - const hasSettings = layout.gaps !== undefined || layout.defaultColumnWidth || layout.presetColumnWidths || layout.alwaysCenterSingleColumn !== undefined; - if (!hasSettings) - return ""; - let block = ` layout {\n`; - if (layout.gaps !== undefined) - block += ` gaps ${layout.gaps}\n`; - if (layout.defaultColumnWidth?.type === "proportion") { - const val = layout.defaultColumnWidth.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` default-column-width { proportion ${formatted}; }\n`; - } - if (layout.presetColumnWidths && layout.presetColumnWidths.length > 0) { - block += ` preset-column-widths {\n`; - for (const preset of layout.presetColumnWidths) { - if (preset.type === "proportion") { - const val = preset.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` proportion ${formatted}\n`; - } - } - block += ` }\n`; - } - if (layout.alwaysCenterSingleColumn !== undefined) - block += layout.alwaysCenterSingleColumn ? ` always-center-single-column\n` : ` always-center-single-column false\n`; - block += ` }\n`; - return block; - } - - function confirmChanges() { - clearPendingChanges(); - changesConfirmed(); - } - - function revertChanges() { - const hadFormatChange = originalDisplayNameMode !== ""; - const hadNiriChanges = originalNiriSettings !== null; - const hadHyprlandChanges = originalHyprlandSettings !== null; - - if (hadFormatChange) { - SettingsData.displayNameMode = originalDisplayNameMode; - SettingsData.saveSettings(); - } - - if (hadNiriChanges) { - SettingsData.niriOutputSettings = JSON.parse(JSON.stringify(originalNiriSettings)); - SettingsData.saveSettings(); - } - - if (hadHyprlandChanges) { - SettingsData.hyprlandOutputSettings = JSON.parse(JSON.stringify(originalHyprlandSettings)); - SettingsData.saveSettings(); - } - - pendingHyprlandChanges = {}; - pendingNiriChanges = {}; - - if (!originalOutputs && !hadNiriChanges && !hadHyprlandChanges) { - if (hadFormatChange) - backendWriteOutputsConfig(buildOutputsWithPendingChanges()); - clearPendingChanges(); - changesReverted(); - return; - } - - const original = originalOutputs ? JSON.parse(JSON.stringify(originalOutputs)) : buildOutputsWithPendingChanges(); - for (const name in savedOutputs) { - if (!original[name]) - original[name] = JSON.parse(JSON.stringify(savedOutputs[name])); - } - backendWriteOutputsConfig(original); - clearPendingChanges(); - if (originalOutputs) - outputs = original; - changesReverted(); - } - - function getOutputBounds() { - if (!allOutputs || Object.keys(allOutputs).length === 0) - return { - "minX": 0, - "minY": 0, - "maxX": 1920, - "maxY": 1080, - "width": 1920, - "height": 1080 - }; - - let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; - - for (const name in allOutputs) { - const output = allOutputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x + size.w); - maxY = Math.max(maxY, y + size.h); - } - - if (minX === Infinity) - return { - "minX": 0, - "minY": 0, - "maxX": 1920, - "maxY": 1080, - "width": 1920, - "height": 1080 - }; - return { - "minX": minX, - "minY": minY, - "maxX": maxX, - "maxY": maxY, - "width": maxX - minX, - "height": maxY - minY - }; - } - - function isRotated(transform) { - switch (transform) { - case "90": - case "270": - case "Flipped90": - case "Flipped270": - return true; - default: - return false; - } - } - - function getPhysicalSize(output) { - if (!output) - return { - "w": 1920, - "h": 1080 - }; - - let w = 1920, h = 1080; - if (output.modes && output.current_mode !== undefined) { - const mode = output.modes[output.current_mode]; - if (mode) { - w = mode.width || 1920; - h = mode.height || 1080; - } - } else if (output.logical) { - const scale = output.logical.scale || 1.0; - w = Math.round((output.logical.width || 1920) * scale); - h = Math.round((output.logical.height || 1080) * scale); - } - - if (output.logical && isRotated(output.logical.transform)) - return { - "w": h, - "h": w - }; - return { - "w": w, - "h": h - }; - } - - function getLogicalSize(output) { - if (!output) - return { - "w": 1920, - "h": 1080 - }; - - const phys = getPhysicalSize(output); - const scale = output.logical?.scale || 1.0; - - return { - "w": Math.round(phys.w / scale), - "h": Math.round(phys.h / scale) - }; - } - - function checkOverlap(testName, testX, testY, testW, testH) { - for (const name in outputs) { - if (name === testName) - continue; - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - if (!(testX + testW <= x || testX >= x + size.w || testY + testH <= y || testY >= y + size.h)) - return true; - } - return false; - } - - function snapToEdges(testName, posX, posY, testW, testH) { - const snapThreshold = 200; - let snappedX = posX; - let snappedY = posY; - let bestXDist = snapThreshold; - let bestYDist = snapThreshold; - - for (const name in outputs) { - if (name === testName) - continue; - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - - const rightEdge = x + size.w; - const bottomEdge = y + size.h; - const testRight = posX + testW; - const testBottom = posY + testH; - - const xSnaps = [ - { - "val": rightEdge, - "dist": Math.abs(posX - rightEdge) - }, - { - "val": x - testW, - "dist": Math.abs(testRight - x) - }, - { - "val": x, - "dist": Math.abs(posX - x) - }, - { - "val": rightEdge - testW, - "dist": Math.abs(testRight - rightEdge) - } - ]; - - const ySnaps = [ - { - "val": bottomEdge, - "dist": Math.abs(posY - bottomEdge) - }, - { - "val": y - testH, - "dist": Math.abs(testBottom - y) - }, - { - "val": y, - "dist": Math.abs(posY - y) - }, - { - "val": bottomEdge - testH, - "dist": Math.abs(testBottom - bottomEdge) - } - ]; - - for (const snap of xSnaps) { - if (snap.dist < bestXDist) { - bestXDist = snap.dist; - snappedX = snap.val; - } - } - - for (const snap of ySnaps) { - if (snap.dist < bestYDist) { - bestYDist = snap.dist; - snappedY = snap.val; - } - } - } - - if (checkOverlap(testName, snappedX, snappedY, testW, testH)) { - if (!checkOverlap(testName, snappedX, posY, testW, testH)) - return Qt.point(snappedX, posY); - if (!checkOverlap(testName, posX, snappedY, testW, testH)) - return Qt.point(posX, snappedY); - return Qt.point(posX, posY); - } - return Qt.point(snappedX, snappedY); - } - - function findBestSnapPosition(testName, posX, posY, testW, testH) { - const outputNames = Object.keys(outputs).filter(n => n !== testName); - - if (outputNames.length === 0) - return Qt.point(posX, posY); - - let bestPos = null; - let bestDist = Infinity; - - for (const name of outputNames) { - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - - const candidates = [ - { - "px": x + size.w, - "py": y - }, - { - "px": x - testW, - "py": y - }, - { - "px": x, - "py": y + size.h - }, - { - "px": x, - "py": y - testH - }, - { - "px": x + size.w, - "py": y + size.h - testH - }, - { - "px": x - testW, - "py": y + size.h - testH - }, - { - "px": x + size.w - testW, - "py": y + size.h - }, - { - "px": x + size.w - testW, - "py": y - testH - } - ]; - - for (const c of candidates) { - if (checkOverlap(testName, c.px, c.py, testW, testH)) - continue; - const dist = Math.hypot(c.px - posX, c.py - posY); - if (dist < bestDist) { - bestDist = dist; - bestPos = Qt.point(c.px, c.py); - } - } - } - - return bestPos || Qt.point(posX, posY); - } - - function formatMode(mode) { - if (!mode) - return ""; - return mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3); - } - - function getTransformLabel(transform) { - switch (transform) { - case "Normal": - return I18n.tr("Normal"); - case "90": - return I18n.tr("90°"); - case "180": - return I18n.tr("180°"); - case "270": - return I18n.tr("270°"); - case "Flipped": - return I18n.tr("Flipped"); - case "Flipped90": - return I18n.tr("Flipped 90°"); - case "Flipped180": - return I18n.tr("Flipped 180°"); - case "Flipped270": - return I18n.tr("Flipped 270°"); - default: - return I18n.tr("Normal"); - } - } - - function getTransformValue(label) { - if (label === I18n.tr("Normal")) - return "Normal"; - if (label === I18n.tr("90°")) - return "90"; - if (label === I18n.tr("180°")) - return "180"; - if (label === I18n.tr("270°")) - return "270"; - if (label === I18n.tr("Flipped")) - return "Flipped"; - if (label === I18n.tr("Flipped 90°")) - return "Flipped90"; - if (label === I18n.tr("Flipped 180°")) - return "Flipped180"; - if (label === I18n.tr("Flipped 270°")) - return "Flipped270"; - return "Normal"; - } - - function setOriginalDisplayNameMode(mode) { - if (originalDisplayNameMode === "") - originalDisplayNameMode = mode; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml deleted file mode 100644 index 7c36e4b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml +++ /dev/null @@ -1,310 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - property string outputName: "" - property var outputData: null - property bool expanded: false - - width: parent.width - spacing: 0 - - Rectangle { - width: parent.width - height: headerRow.implicitHeight + Theme.spacingS * 2 - color: headerMouse.containsMouse ? Theme.withAlpha(Theme.primary, 0.1) : "transparent" - radius: Theme.cornerRadius / 2 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.expanded ? "expand_more" : "chevron_right" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compositor Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: headerMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.expanded = !root.expanded - } - } - - Column { - id: settingsColumn - width: parent.width - spacing: Theme.spacingS - visible: root.expanded - topPadding: Theme.spacingS - - property int currentBitdepth: { - DisplayConfigState.pendingHyprlandChanges; - return DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "bitdepth", 8); - } - property bool is10Bit: currentBitdepth === 10 - - property string currentCm: { - DisplayConfigState.pendingHyprlandChanges; - return DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - } - property bool isHdrMode: currentCm === "hdr" || currentCm === "hdredid" - - DankToggle { - width: parent.width - text: I18n.tr("Disable Output") - checked: DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "disabled", false) - onToggled: checked => DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "disabled", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Mirror Display") - addHorizontalPadding: true - - property var otherOutputs: { - const list = [I18n.tr("None")]; - for (const name in DisplayConfigState.outputs) { - if (name !== root.outputName) - list.push(name); - } - return list; - } - options: otherOutputs - - currentValue: { - DisplayConfigState.pendingChanges; - const pending = DisplayConfigState.getPendingValue(root.outputName, "mirror"); - const val = pending !== undefined ? pending : (root.outputData.mirror || ""); - return val === "" ? I18n.tr("None") : val; - } - - onValueChanged: value => { - const realVal = value === I18n.tr("None") ? "" : value; - DisplayConfigState.setPendingChange(root.outputName, "mirror", realVal); - } - } - - DankToggle { - width: parent.width - text: I18n.tr("10-bit Color") - description: I18n.tr("Enable 10-bit color depth for wider color gamut and HDR support") - checked: settingsColumn.is10Bit - onToggled: checked => { - if (checked) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "bitdepth", 10); - } else { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "bitdepth", null); - if (settingsColumn.isHdrMode) - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: settingsColumn.is10Bit - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Color Gamut") - addHorizontalPadding: true - currentValue: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - return cmLabelMap[val] || I18n.tr("Auto (Wide)"); - } - options: [I18n.tr("Auto (Wide)"), I18n.tr("Wide (BT2020)"), "DCI-P3", "Apple P3", "Adobe RGB", "EDID", "HDR", I18n.tr("HDR (EDID)")] - - property var cmValueMap: ({ - [I18n.tr("Auto (Wide)")]: "auto", - [I18n.tr("Wide (BT2020)")]: "wide", - "DCI-P3": "dcip3", - "Apple P3": "dp3", - "Adobe RGB": "adobe", - "EDID": "edid", - "HDR": "hdr", - [I18n.tr("HDR (EDID)")]: "hdredid" - }) - - property var cmLabelMap: ({ - "auto": I18n.tr("Auto (Wide)"), - "wide": I18n.tr("Wide (BT2020)"), - "dcip3": "DCI-P3", - "dp3": "Apple P3", - "adobe": "Adobe RGB", - "edid": "EDID", - "hdr": "HDR", - "hdredid": I18n.tr("HDR (EDID)") - }) - - onValueChanged: value => { - const cmValue = cmValueMap[value] || "auto"; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "colorManagement", cmValue); - } - } - - Rectangle { - width: parent.width - Theme.spacingM * 2 - anchors.horizontalCenter: parent.horizontalCenter - height: warningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius / 2 - color: Theme.withAlpha(Theme.warning, 0.15) - border.color: Theme.withAlpha(Theme.warning, 0.3) - border.width: 1 - visible: settingsColumn.isHdrMode - - Column { - id: warningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingS - DankIcon { - name: "warning" - size: Theme.iconSize - 4 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: I18n.tr("Experimental Feature") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - } - StyledText { - text: I18n.tr("HDR mode is experimental. Verify your monitor supports HDR before enabling.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: settingsColumn.isHdrMode - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - StyledText { - text: I18n.tr("HDR Tone Mapping") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - leftPadding: Theme.spacingM - } - - Row { - width: parent.width - Theme.spacingM * 2 - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("SDR Brightness") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: "1.0 - 2.0" - text: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", null); - return val !== null ? val.toString() : ""; - } - onEditingFinished: { - const trimmed = text.trim(); - if (!trimmed) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val < 0.1 || val > 5.0) - return; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", parseFloat(val.toFixed(2))); - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("SDR Saturation") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: "0.5 - 1.5" - text: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", null); - return val !== null ? val.toString() : ""; - } - onEditingFinished: { - const trimmed = text.trim(); - if (!trimmed) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val < 0.0 || val > 3.0) - return; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", parseFloat(val.toFixed(2))); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml deleted file mode 100644 index f5f270b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - width: parent.width - height: warningContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - - readonly property bool showError: DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included - readonly property bool showSetup: !DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && DisplayConfigState.hasOutputBackend && !DisplayConfigState.checkingInclude - - Column { - id: warningContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (root.showSetup) - return I18n.tr("First Time Setup"); - if (root.showError) - return I18n.tr("Outputs Include Missing"); - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (root.showSetup) - return I18n.tr("Click 'Setup' to create the outputs config and add include to your compositor config."); - if (root.showError) - return I18n.tr("dms/outputs config exists but is not included in your compositor config. Display changes won't persist."); - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: root.showError || root.showSetup - text: { - if (DisplayConfigState.fixingInclude) - return I18n.tr("Fixing..."); - if (root.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } - backgroundColor: Theme.primary - textColor: Theme.primaryText - enabled: !DisplayConfigState.fixingInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: DisplayConfigState.fixOutputsInclude() - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml deleted file mode 100644 index accdfd7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml +++ /dev/null @@ -1,82 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: root - - property var filteredOutputs: { - const all = DisplayConfigState.allOutputs || {}; - const keys = Object.keys(all); - if (SettingsData.displayShowDisconnected) - return keys; - return keys.filter(k => all[k]?.connected); - } - - property var filteredBounds: { - const all = DisplayConfigState.allOutputs || {}; - let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; - for (const name of filteredOutputs) { - const output = all[name]; - if (!output?.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = DisplayConfigState.getLogicalSize(output); - const w = size.w || 1920; - const h = size.h || 1080; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x + w); - maxY = Math.max(maxY, y + h); - } - if (minX === Infinity) - return { - minX: 0, - minY: 0, - width: 1920, - height: 1080 - }; - return { - minX: minX, - minY: minY, - width: maxX - minX, - height: maxY - minY - }; - } - - width: parent.width - height: 280 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - border.color: Theme.outline - border.width: 1 - - Item { - id: canvas - anchors.fill: parent - anchors.margins: Theme.spacingL - - property var bounds: root.filteredBounds - property real scaleFactor: { - if (bounds.width === 0 || bounds.height === 0) - return 0.1; - const padding = Theme.spacingL * 2; - const scaleX = (width - padding) / bounds.width; - const scaleY = (height - padding) / bounds.height; - return Math.min(scaleX, scaleY); - } - property point offset: Qt.point((width - bounds.width * scaleFactor) / 2 - bounds.minX * scaleFactor, (height - bounds.height * scaleFactor) / 2 - bounds.minY * scaleFactor) - - Repeater { - model: root.filteredOutputs - - delegate: MonitorRect { - required property string modelData - outputName: modelData - outputData: DisplayConfigState.allOutputs[modelData] - canvasScaleFactor: canvas.scaleFactor - canvasOffset: canvas.offset - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml deleted file mode 100644 index 0209e5f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml +++ /dev/null @@ -1,159 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - required property string outputName - required property var outputData - required property real canvasScaleFactor - required property point canvasOffset - - property bool isConnected: outputData?.connected ?? false - property bool isDragging: false - property point originalLogical: Qt.point(0, 0) - property point snappedLogical: Qt.point(0, 0) - property bool isValidPosition: true - - property var physSize: DisplayConfigState.getPhysicalSize(outputData) - property var logicalSize: DisplayConfigState.getLogicalSize(outputData) - - x: isDragging ? x : (outputData?.logical?.x ?? 0) * canvasScaleFactor + canvasOffset.x - y: isDragging ? y : (outputData?.logical?.y ?? 0) * canvasScaleFactor + canvasOffset.y - width: logicalSize.w * canvasScaleFactor - height: logicalSize.h * canvasScaleFactor - radius: Theme.cornerRadius - opacity: isConnected ? 1.0 : 0.5 - - color: { - if (!isConnected) - return Theme.surfaceContainerHighest; - if (!isValidPosition) - return Theme.withAlpha(Theme.error, 0.3); - if (isDragging) - return Theme.withAlpha(Theme.primary, 0.4); - if (dragArea.containsMouse) - return Theme.withAlpha(Theme.primary, 0.2); - return Theme.surfaceContainerHigh; - } - - border.color: { - if (!isConnected) - return Theme.outline; - if (!isValidPosition) - return Theme.error; - if (isDragging) - return Theme.primary; - if (CompositorService.getFocusedScreen()?.name === outputName) - return Theme.primary; - return Theme.outline; - } - border.width: isDragging ? 3 : 2 - z: isDragging ? 100 : (isConnected ? 1 : 0) - - Rectangle { - id: snapPreview - visible: root.isDragging && root.isValidPosition && SettingsData.displaySnapToEdge - x: root.snappedLogical.x * root.canvasScaleFactor + root.canvasOffset.x - root.x - y: root.snappedLogical.y * root.canvasScaleFactor + root.canvasOffset.y - root.y - width: parent.width - height: parent.height - radius: Theme.cornerRadius - color: "transparent" - border.color: Theme.primary - border.width: 2 - opacity: 0.6 - } - - Column { - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: root.isConnected ? "desktop_windows" : "desktop_access_disabled" - size: Math.min(24, Math.min(root.width * 0.3, root.height * 0.25)) - color: root.isConnected ? (root.isValidPosition ? Theme.primary : Theme.error) : Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayConfigState.getOutputDisplayName(root.outputData, root.outputName) - font.pixelSize: Math.max(10, Math.min(14, root.width * 0.12)) - font.weight: Font.Medium - color: root.isConnected ? Theme.surfaceText : Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - elide: Text.ElideMiddle - width: Math.min(implicitWidth, root.width - 8) - } - - StyledText { - text: root.isConnected ? (root.physSize.w + "x" + root.physSize.h) : I18n.tr("Disconnected") - font.pixelSize: Math.max(8, Math.min(11, root.width * 0.09)) - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - MouseArea { - id: dragArea - anchors.fill: parent - hoverEnabled: true - enabled: root.isConnected - cursorShape: !root.isConnected ? Qt.ArrowCursor : (root.isDragging ? Qt.ClosedHandCursor : Qt.OpenHandCursor) - drag.target: root.isConnected ? root : null - drag.axis: Drag.XAndYAxis - drag.threshold: 0 - - onPressed: mouse => { - if (!root.isConnected) - return; - root.isDragging = true; - root.originalLogical = Qt.point(root.outputData?.logical?.x ?? 0, root.outputData?.logical?.y ?? 0); - root.snappedLogical = root.originalLogical; - root.isValidPosition = true; - } - - onPositionChanged: mouse => { - if (!root.isDragging || !root.isConnected) - return; - let posX = Math.round((root.x - root.canvasOffset.x) / root.canvasScaleFactor); - let posY = Math.round((root.y - root.canvasOffset.y) / root.canvasScaleFactor); - - const size = DisplayConfigState.getLogicalSize(root.outputData); - - const snapped = SettingsData.displaySnapToEdge ? DisplayConfigState.snapToEdges(root.outputName, posX, posY, size.w, size.h) : Qt.point(posX, posY); - root.snappedLogical = snapped; - root.isValidPosition = SettingsData.displaySnapToEdge ? !DisplayConfigState.checkOverlap(root.outputName, snapped.x, snapped.y, size.w, size.h) : true; - } - - onReleased: { - if (!root.isDragging || !root.isConnected) - return; - root.isDragging = false; - - const size = DisplayConfigState.getLogicalSize(root.outputData); - const finalX = root.snappedLogical.x; - const finalY = root.snappedLogical.y; - - if (SettingsData.displaySnapToEdge && DisplayConfigState.checkOverlap(root.outputName, finalX, finalY, size.w, size.h)) { - root.isValidPosition = true; - return; - } - - if (finalX === root.originalLogical.x && finalY === root.originalLogical.y) - return; - - DisplayConfigState.initOriginalOutputs(); - DisplayConfigState.backendUpdateOutputPosition(root.outputName, finalX, finalY); - DisplayConfigState.setPendingChange(root.outputName, "position", { - "x": finalX, - "y": finalY - }); - } - } - - Drag.active: dragArea.drag.active && root.isConnected -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml deleted file mode 100644 index da9a4a7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml +++ /dev/null @@ -1,368 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - property string outputName: "" - property var outputData: null - property bool expanded: false - - width: parent.width - spacing: 0 - - Rectangle { - width: parent.width - height: headerRow.implicitHeight + Theme.spacingS * 2 - color: headerMouse.containsMouse ? Theme.withAlpha(Theme.primary, 0.1) : "transparent" - radius: Theme.cornerRadius / 2 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.expanded ? "expand_more" : "chevron_right" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compositor Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: headerMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.expanded = !root.expanded - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: root.expanded - topPadding: Theme.spacingS - - DankToggle { - width: parent.width - text: I18n.tr("Disable Output") - checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "disabled", false) - onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "disabled", checked) - } - - DankToggle { - width: parent.width - text: I18n.tr("Focus at Startup") - checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "focusAtStartup", false) - onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "focusAtStartup", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Hot Corners") - addHorizontalPadding: true - - property var hotCornersData: { - void (DisplayConfigState.pendingNiriChanges); - return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null); - } - - currentValue: { - if (!hotCornersData) - return I18n.tr("Inherit"); - if (hotCornersData.off) - return I18n.tr("Off"); - const corners = hotCornersData.corners || []; - if (corners.length === 0) - return I18n.tr("Inherit"); - if (corners.length === 4) - return I18n.tr("All"); - return I18n.tr("Select..."); - } - options: [I18n.tr("Inherit"), I18n.tr("Off"), I18n.tr("All"), I18n.tr("Select...")] - - onValueChanged: value => { - switch (value) { - case I18n.tr("Inherit"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", null); - break; - case I18n.tr("Off"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "off": true - }); - break; - case I18n.tr("All"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": ["top-left", "top-right", "bottom-left", "bottom-right"] - }); - break; - case I18n.tr("Select..."): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": [] - }); - break; - } - } - } - - Item { - width: parent.width - height: hotCornersGroup.implicitHeight - clip: true - - property var hotCornersData: { - void (DisplayConfigState.pendingNiriChanges); - return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null); - } - - visible: hotCornersData && !hotCornersData.off && hotCornersData.corners !== undefined - - DankButtonGroup { - id: hotCornersGroup - anchors.horizontalCenter: parent.horizontalCenter - selectionMode: "multi" - checkEnabled: false - buttonHeight: 32 - buttonPadding: parent.width < 400 ? Theme.spacingXS : Theme.spacingM - minButtonWidth: parent.width < 400 ? 28 : 56 - textSize: parent.width < 400 ? 11 : Theme.fontSizeMedium - model: [I18n.tr("Top Left"), I18n.tr("Top Right"), I18n.tr("Bottom Left"), I18n.tr("Bottom Right")] - - property var cornerKeys: ["top-left", "top-right", "bottom-left", "bottom-right"] - - currentSelection: { - const hcData = parent.hotCornersData; - if (!hcData?.corners) - return []; - return hcData.corners.map(key => { - const idx = cornerKeys.indexOf(key); - return idx >= 0 ? model[idx] : null; - }).filter(v => v !== null); - } - - onSelectionChanged: (index, selected) => { - const corners = currentSelection.map(label => { - const idx = model.indexOf(label); - return idx >= 0 ? cornerKeys[idx] : null; - }).filter(v => v !== null); - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": corners - }); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - Item { - width: parent.width - height: layoutColumn.implicitHeight - - Column { - id: layoutColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Layout Overrides") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("Override global layout settings for this output") - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceVariantText, 0.7) - wrapMode: Text.WordWrap - width: parent.width - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Window Gaps (px)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - if (layout?.gaps === undefined) - return ""; - return layout.gaps.toString(); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim(); - if (!trimmed) { - delete layout.gaps; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const val = parseInt(trimmed); - if (isNaN(val) || val < 0) - return; - layout.gaps = val; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Default Width (%)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - if (!layout?.defaultColumnWidth) - return ""; - if (layout.defaultColumnWidth.type !== "proportion") - return ""; - const percent = layout.defaultColumnWidth.value * 100; - return parseFloat(percent.toFixed(4)).toString(); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim().replace("%", ""); - if (!trimmed) { - delete layout.defaultColumnWidth; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val <= 0 || val > 100) - return; - layout.defaultColumnWidth = { - "type": "proportion", - "value": parseFloat((val / 100).toFixed(6)) - }; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Preset Widths (%)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "e.g. 33.33, 50, 66.67" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceVariantText, 0.7) - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - const presets = layout?.presetColumnWidths || []; - if (presets.length === 0) - return ""; - return presets.filter(p => p.type === "proportion").map(p => parseFloat((p.value * 100).toFixed(4))).join(", "); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim(); - if (!trimmed) { - delete layout.presetColumnWidths; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const parts = trimmed.split(/[,\s]+/).filter(s => s); - const presets = []; - for (const part of parts) { - const val = parseFloat(part.replace("%", "")); - if (!isNaN(val) && val > 0 && val <= 100) - presets.push({ - "type": "proportion", - "value": parseFloat((val / 100).toFixed(6)) - }); - } - if (presets.length === 0) { - delete layout.presetColumnWidths; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - presets.sort((a, b) => a.value - b.value); - layout.presetColumnWidths = presets; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Center Single Column") - property var layoutData: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null) - checked: layoutData?.alwaysCenterSingleColumn ?? false - onToggled: checked => { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - if (checked) { - layout.alwaysCenterSingleColumn = true; - } else { - delete layout.alwaysCenterSingleColumn; - } - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml deleted file mode 100644 index 93ab124..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - width: parent.width - height: messageContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: messageContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Monitor Configuration") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Display configuration is not available. WLR output management protocol not supported.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml deleted file mode 100644 index 0da1175..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml +++ /dev/null @@ -1,352 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property string outputName - required property var outputData - property bool isConnected: outputData?.connected ?? false - - width: parent.width - height: settingsColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, isConnected ? 0.5 : 0.3) - border.color: Theme.withAlpha(Theme.outline, 0.3) - border.width: 1 - opacity: isConnected ? 1.0 : 0.7 - - Column { - id: settingsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.isConnected ? "desktop_windows" : "desktop_access_disabled" - size: Theme.iconSize - 4 - color: root.isConnected ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - (disconnectedBadge.visible ? disconnectedBadge.width + deleteButton.width + Theme.spacingS * 2 : 0) - spacing: 2 - - StyledText { - text: DisplayConfigState.getOutputDisplayName(root.outputData, root.outputName) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: root.isConnected ? Theme.surfaceText : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: (root.outputData?.model ?? "") + (root.outputData?.make ? " - " + root.outputData.make : "") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - id: disconnectedBadge - visible: !root.isConnected - width: disconnectedText.implicitWidth + Theme.spacingM - height: disconnectedText.implicitHeight + Theme.spacingXS - radius: height / 2 - color: Theme.withAlpha(Theme.outline, 0.3) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: disconnectedText - text: I18n.tr("Disconnected") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.centerIn: parent - } - } - - Rectangle { - id: deleteButton - visible: !root.isConnected - width: 28 - height: 28 - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.errorHover : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: DisplayConfigState.deleteDisconnectedOutput(root.outputName) - } - } - } - - DankDropdown { - width: parent.width - text: I18n.tr("Resolution & Refresh") - visible: root.isConnected - currentValue: { - const pendingMode = DisplayConfigState.getPendingValue(root.outputName, "mode"); - if (pendingMode) - return pendingMode; - const data = DisplayConfigState.outputs[root.outputName]; - if (!data?.modes || data?.current_mode === undefined) - return "Auto"; - const mode = data.modes[data.current_mode]; - return mode ? DisplayConfigState.formatMode(mode) : "Auto"; - } - options: { - const data = DisplayConfigState.outputs[root.outputName]; - if (!data?.modes) - return ["Auto"]; - const opts = []; - for (var i = 0; i < data.modes.length; i++) { - opts.push(DisplayConfigState.formatMode(data.modes[i])); - } - return opts; - } - onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "mode", value) - } - - StyledText { - visible: !root.isConnected - text: I18n.tr("Configuration will be preserved when this display reconnects") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: root.isConnected - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Scale") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Item { - id: scaleContainer - width: parent.width - height: scaleDropdown.visible ? scaleDropdown.height : scaleInput.height - - property bool customMode: false - property string currentScale: { - const pendingScale = DisplayConfigState.getPendingValue(root.outputName, "scale"); - if (pendingScale !== undefined) - return parseFloat(pendingScale.toFixed(2)).toString(); - const scale = DisplayConfigState.outputs[root.outputName]?.logical?.scale ?? 1.0; - return parseFloat(scale.toFixed(2)).toString(); - } - - DankDropdown { - id: scaleDropdown - width: parent.width - dropdownWidth: parent.width - visible: !scaleContainer.customMode - currentValue: scaleContainer.currentScale - options: { - const standard = ["0.5", "0.75", "1", "1.25", "1.5", "1.75", "2", "2.5", "3", I18n.tr("Custom...")]; - const current = scaleContainer.currentScale; - if (standard.slice(0, -1).includes(current)) - return standard; - const opts = [...standard.slice(0, -1), current, standard[standard.length - 1]]; - return opts.sort((a, b) => { - if (a === I18n.tr("Custom...")) - return 1; - if (b === I18n.tr("Custom...")) - return -1; - return parseFloat(a) - parseFloat(b); - }); - } - onValueChanged: value => { - if (value === I18n.tr("Custom...")) { - scaleContainer.customMode = true; - scaleInput.text = scaleContainer.currentScale; - scaleInput.forceActiveFocus(); - scaleInput.selectAll(); - return; - } - DisplayConfigState.setPendingChange(root.outputName, "scale", parseFloat(value)); - } - } - - DankTextField { - id: scaleInput - width: parent.width - height: 40 - visible: scaleContainer.customMode - placeholderText: "0.5 - 4.0" - - function applyValue() { - const val = parseFloat(text); - if (isNaN(val) || val < 0.25 || val > 4) { - text = scaleContainer.currentScale; - scaleContainer.customMode = false; - return; - } - DisplayConfigState.setPendingChange(root.outputName, "scale", parseFloat(val.toFixed(2))); - scaleContainer.customMode = false; - } - - onAccepted: applyValue() - onEditingFinished: applyValue() - Keys.onEscapePressed: { - text = scaleContainer.currentScale; - scaleContainer.customMode = false; - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Transform") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - width: parent.width - dropdownWidth: parent.width - currentValue: { - const pendingTransform = DisplayConfigState.getPendingValue(root.outputName, "transform"); - if (pendingTransform) - return DisplayConfigState.getTransformLabel(pendingTransform); - const data = DisplayConfigState.outputs[root.outputName]; - return DisplayConfigState.getTransformLabel(data?.logical?.transform ?? "Normal"); - } - options: [I18n.tr("Normal"), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")] - onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value)) - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && !CompositorService.isDwl && !CompositorService.isHyprland && !CompositorService.isNiri && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - checked: { - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - if (pendingVrr !== undefined) - return pendingVrr; - return DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false; - } - onToggled: checked => DisplayConfigState.setPendingChange(root.outputName, "vrr", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && CompositorService.isHyprland && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - options: [I18n.tr("Off"), I18n.tr("On"), I18n.tr("Fullscreen Only")] - currentValue: { - DisplayConfigState.pendingHyprlandChanges; - if (DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "vrrFullscreenOnly", false)) - return I18n.tr("Fullscreen Only"); - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - const vrrEnabled = pendingVrr !== undefined ? pendingVrr : (DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false); - if (vrrEnabled) - return I18n.tr("On"); - return I18n.tr("Off"); - } - onValueChanged: value => { - const off = I18n.tr("Off"); - const fullscreen = I18n.tr("Fullscreen Only"); - DisplayConfigState.setPendingChange(root.outputName, "vrr", value !== off); - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "vrrFullscreenOnly", value === fullscreen || null); - } - } - - DankDropdown { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && CompositorService.isNiri && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - options: [I18n.tr("Off"), I18n.tr("On"), I18n.tr("On-Demand")] - currentValue: { - DisplayConfigState.pendingNiriChanges; - if (DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "vrrOnDemand", false)) - return I18n.tr("On-Demand"); - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - const vrrEnabled = pendingVrr !== undefined ? pendingVrr : (DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false); - if (!vrrEnabled) - return I18n.tr("Off"); - return I18n.tr("On"); - } - onValueChanged: value => { - const off = I18n.tr("Off"); - const onDemand = I18n.tr("On-Demand"); - DisplayConfigState.setPendingChange(root.outputName, "vrr", value !== off); - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "vrrOnDemand", value === onDemand || null); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.2) - visible: compositorSettingsLoader.active - } - - Loader { - id: compositorSettingsLoader - width: parent.width - active: root.isConnected && compositorSettingsSource !== "" - source: compositorSettingsSource - - property string compositorSettingsSource: { - switch (CompositorService.compositor) { - case "niri": - return "NiriOutputSettings.qml"; - case "hyprland": - return "HyprlandOutputSettings.qml"; - default: - return ""; - } - } - - onLoaded: { - item.outputName = root.outputName; - item.outputData = root.outputData; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml deleted file mode 100644 index 61b373d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml +++ /dev/null @@ -1,540 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals -import qs.Services -import qs.Widgets -import qs.Modules.Settings.DisplayConfig - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string selectedProfileId: SettingsData.getActiveDisplayProfile(CompositorService.compositor) - property bool showNewProfileDialog: false - property bool showDeleteConfirmDialog: false - property bool showRenameDialog: false - property string newProfileName: "" - property string renameProfileName: "" - - function getProfileOptions() { - const profiles = DisplayConfigState.validatedProfiles; - const options = []; - for (const id in profiles) - options.push(profiles[id].name); - return options; - } - - function getProfileIds() { - return Object.keys(DisplayConfigState.validatedProfiles); - } - - function getProfileIdByName(name) { - const profiles = DisplayConfigState.validatedProfiles; - for (const id in profiles) { - if (profiles[id].name === name) - return id; - } - return ""; - } - - function getProfileNameById(id) { - const profiles = DisplayConfigState.validatedProfiles; - return profiles[id]?.name || ""; - } - - Connections { - target: DisplayConfigState - function onChangesApplied(changeDescriptions) { - confirmationModal.changes = changeDescriptions; - confirmationModal.open(); - } - function onChangesConfirmed() { - } - function onChangesReverted() { - } - function onProfileActivated(profileId, profileName) { - root.selectedProfileId = profileId; - ToastService.showInfo(I18n.tr("Profile activated: %1").arg(profileName)); - } - function onProfileSaved(profileId, profileName) { - root.selectedProfileId = profileId; - ToastService.showInfo(I18n.tr("Profile saved: %1").arg(profileName)); - } - function onProfileDeleted(profileId) { - root.selectedProfileId = SettingsData.getActiveDisplayProfile(CompositorService.compositor); - ToastService.showInfo(I18n.tr("Profile deleted")); - } - function onProfileError(message) { - ToastService.showError(I18n.tr("Profile error"), message); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - IncludeWarningBox { - width: parent.width - } - - StyledRect { - width: parent.width - height: profileSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - visible: DisplayConfigState.hasOutputBackend - - Column { - id: profileSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "tune" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - autoSelectColumn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Display Profiles") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Save and switch between display configurations") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - // ! TODO - auto profile switching is buggy on niri and other compositors - Column { - id: autoSelectColumn - visible: false // disabled for now - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Auto") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankToggle { - id: autoSelectToggle - checked: false // disabled for now - enabled: false - onToggled: checked => { - // disabled for now - // SettingsData.displayProfileAutoSelect = checked; - // SettingsData.saveSettings(); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: !root.showNewProfileDialog && !root.showDeleteConfirmDialog && !root.showRenameDialog - - DankDropdown { - id: profileDropdown - width: parent.width - newButton.width - deleteButton.width - Theme.spacingS * 2 - compactMode: true - dropdownWidth: width - options: root.getProfileOptions() - currentValue: root.getProfileNameById(root.selectedProfileId) - emptyText: I18n.tr("No profiles") - onValueChanged: value => { - const profileId = root.getProfileIdByName(value); - if (profileId && profileId !== root.selectedProfileId) - DisplayConfigState.activateProfile(profileId); - } - } - - DankButton { - id: newButton - iconName: "add" - text: "" - buttonHeight: 40 - horizontalPadding: Theme.spacingM - backgroundColor: Theme.surfaceContainer - textColor: Theme.surfaceText - onClicked: { - root.newProfileName = ""; - root.showNewProfileDialog = true; - } - } - - DankButton { - id: deleteButton - iconName: "delete" - text: "" - buttonHeight: 40 - horizontalPadding: Theme.spacingM - backgroundColor: Theme.surfaceContainer - textColor: Theme.error - enabled: root.selectedProfileId !== "" - onClicked: root.showDeleteConfirmDialog = true - } - } - - Rectangle { - width: parent.width - height: newProfileRow.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.showNewProfileDialog - - Row { - id: newProfileRow - anchors.centerIn: parent - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingS - - DankTextField { - id: newProfileField - width: parent.width - createButton.width - cancelNewButton.width - Theme.spacingS * 2 - placeholderText: I18n.tr("Profile name") - text: root.newProfileName - onTextChanged: root.newProfileName = text - onAccepted: { - if (text.trim()) - DisplayConfigState.createProfile(text.trim()); - root.showNewProfileDialog = false; - } - Component.onCompleted: forceActiveFocus() - } - - DankButton { - id: createButton - text: I18n.tr("Create") - enabled: root.newProfileName.trim() !== "" - onClicked: { - DisplayConfigState.createProfile(root.newProfileName.trim()); - root.showNewProfileDialog = false; - } - } - - DankButton { - id: cancelNewButton - text: I18n.tr("Cancel") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: root.showNewProfileDialog = false - } - } - } - - Rectangle { - width: parent.width - height: deleteConfirmColumn.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.showDeleteConfirmDialog - - Column { - id: deleteConfirmColumn - anchors.centerIn: parent - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Delete profile \"%1\"?").arg(root.getProfileNameById(root.selectedProfileId)) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingS - anchors.right: parent.right - - DankButton { - text: I18n.tr("Delete") - backgroundColor: Theme.error - textColor: Theme.primaryText - onClicked: { - DisplayConfigState.deleteProfile(root.selectedProfileId); - root.showDeleteConfirmDialog = false; - } - } - - DankButton { - text: I18n.tr("Cancel") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: root.showDeleteConfirmDialog = false - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: DisplayConfigState.matchedProfile !== "" - - DankIcon { - name: "check_circle" - size: 16 - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Matches profile: %1").arg(root.getProfileNameById(DisplayConfigState.matchedProfile)) - font.pixelSize: Theme.fontSizeSmall - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - StyledRect { - width: parent.width - height: monitorConfigSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - visible: DisplayConfigState.hasOutputBackend - - Column { - id: monitorConfigSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - (displayFormatColumn.visible ? displayFormatColumn.width + Theme.spacingM : 0) - (snapColumn.visible ? snapColumn.width + Theme.spacingM : 0) - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Monitor Configuration") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Arrange displays and configure resolution, refresh rate, and VRR") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Column { - id: snapColumn - visible: true - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Snap") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankToggle { - id: snapToggle - checked: SettingsData.displaySnapToEdge - onToggled: checked => { - SettingsData.displaySnapToEdge = checked; - SettingsData.saveSettings(); - } - } - } - - Column { - id: displayFormatColumn - visible: !CompositorService.isDwl - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Config Format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankButtonGroup { - id: displayFormatGroup - model: [I18n.tr("Name"), I18n.tr("Model")] - currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const newMode = index === 1 ? "model" : "system"; - DisplayConfigState.setOriginalDisplayNameMode(SettingsData.displayNameMode); - SettingsData.displayNameMode = newMode; - } - - Connections { - target: SettingsData - function onDisplayNameModeChanged() { - displayFormatGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0; - } - } - } - } - } - - MonitorCanvas { - width: parent.width - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - visible: { - const all = DisplayConfigState.allOutputs || {}; - const disconnected = Object.keys(all).filter(k => !all[k]?.connected); - return disconnected.length > 0; - } - - StyledText { - text: { - const all = DisplayConfigState.allOutputs || {}; - const disconnected = Object.keys(all).filter(k => !all[k]?.connected); - if (SettingsData.displayShowDisconnected) - return I18n.tr("%1 disconnected").arg(disconnected.length); - return I18n.tr("%1 disconnected (hidden)").arg(disconnected.length); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SettingsData.displayShowDisconnected ? I18n.tr("Hide") : I18n.tr("Show") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SettingsData.displayShowDisconnected = !SettingsData.displayShowDisconnected; - SettingsData.saveSettings(); - } - } - } - } - - Repeater { - model: { - const keys = Object.keys(DisplayConfigState.allOutputs || {}); - if (SettingsData.displayShowDisconnected) - return keys; - return keys.filter(k => DisplayConfigState.allOutputs[k]?.connected); - } - - delegate: OutputCard { - required property string modelData - outputName: modelData - outputData: DisplayConfigState.allOutputs[modelData] - } - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingS - visible: DisplayConfigState.hasPendingChanges - layoutDirection: Qt.RightToLeft - - DankButton { - text: I18n.tr("Apply Changes") - iconName: "check" - onClicked: DisplayConfigState.applyChanges() - } - - DankButton { - text: I18n.tr("Discard") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: DisplayConfigState.discardChanges() - } - } - } - } - - NoBackendMessage { - width: parent.width - visible: !DisplayConfigState.hasOutputBackend - } - } - } - - DisplayConfirmationModal { - id: confirmationModal - onConfirmed: DisplayConfigState.confirmChanges() - onReverted: DisplayConfigState.revertChanges() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml deleted file mode 100644 index 59f6513..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml +++ /dev/null @@ -1,522 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - function getBarComponentsFromSettings() { - const bars = SettingsData.barConfigs || []; - return bars.map(bar => ({ - "id": "bar:" + bar.id, - "name": bar.name || "Bar", - "description": I18n.tr("Individual bar configuration"), - "icon": "toolbar", - "barId": bar.id - })); - } - - property var variantComponents: getVariantComponentsList() - - function getVariantComponentsList() { - return [...getBarComponentsFromSettings(), - { - "id": "dock", - "name": I18n.tr("Application Dock"), - "description": I18n.tr("Bottom dock for pinned and running applications"), - "icon": "dock" - }, - { - "id": "notifications", - "name": I18n.tr("Notification Popups"), - "description": I18n.tr("Notification toast popups"), - "icon": "notifications" - }, - { - "id": "wallpaper", - "name": I18n.tr("Wallpaper"), - "description": I18n.tr("Desktop background images"), - "icon": "wallpaper" - }, - { - "id": "osd", - "name": I18n.tr("On-Screen Displays"), - "description": I18n.tr("Volume, brightness, and other system OSDs"), - "icon": "picture_in_picture" - }, - { - "id": "toast", - "name": I18n.tr("Toast Messages"), - "description": I18n.tr("System toast notifications"), - "icon": "campaign" - }, - { - "id": "notepad", - "name": I18n.tr("Notepad Slideout"), - "description": I18n.tr("Quick note-taking slideout panel"), - "icon": "sticky_note_2" - } - ]; - } - - Connections { - target: SettingsData - function onBarConfigsChanged() { - variantComponents = getVariantComponentsList(); - } - } - - function getScreenPreferences(componentId) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - const barConfig = SettingsData.getBarConfig(barId); - return barConfig?.screenPreferences || ["all"]; - } - return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]; - } - - function setScreenPreferences(componentId, screenNames) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - SettingsData.updateBarConfig(barId, { - "screenPreferences": screenNames - }); - return; - } - var prefs = SettingsData.screenPreferences || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs[componentId] = screenNames; - SettingsData.set("screenPreferences", newPrefs); - } - - function getShowOnLastDisplay(componentId) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - const barConfig = SettingsData.getBarConfig(barId); - return barConfig?.showOnLastDisplay ?? true; - } - return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false; - } - - function setShowOnLastDisplay(componentId, enabled) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - SettingsData.updateBarConfig(barId, { - "showOnLastDisplay": enabled - }); - return; - } - var prefs = SettingsData.showOnLastDisplay || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs[componentId] = enabled; - SettingsData.set("showOnLastDisplay", newPrefs); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: screensInfoSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: screensInfoSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Connected Displays") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Configure which displays show shell components") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Screens (%1)").arg(Quickshell.screens.length) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Display Name Format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - DankButtonGroup { - id: displayModeGroup - model: [I18n.tr("Name"), I18n.tr("Model")] - currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.displayNameMode = index === 1 ? "model" : "system"; - SettingsData.saveSettings(); - } - - Connections { - target: SettingsData - function onDisplayNameModeChanged() { - displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0; - } - } - } - } - } - } - - Repeater { - model: Quickshell.screens - - delegate: Rectangle { - width: parent.width - height: screenRow.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 0 - - Row { - id: screenRow - - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - DankIcon { - name: "desktop_windows" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS / 2 - - StyledText { - text: SettingsData.getScreenDisplayName(modelData) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingS - - property var wlrOutput: WlrOutputService.wlrOutputAvailable ? WlrOutputService.getOutput(modelData.name) : null - property var currentMode: wlrOutput?.currentMode - - StyledText { - text: { - if (parent.currentMode) { - return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz"; - } - return modelData.width + "×" + modelData.height; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - - Repeater { - model: root.variantComponents - - delegate: StyledRect { - width: parent.width - height: componentSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: componentSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Show on screens:") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Column { - property string componentId: modelData.id - - width: parent.width - spacing: Theme.spacingXS - - DankToggle { - width: parent.width - text: I18n.tr("All displays") - description: I18n.tr("Show on all connected displays") - checked: { - var prefs = root.getScreenPreferences(parent.componentId); - return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - } - onToggled: checked => { - if (checked) { - root.setScreenPreferences(parent.componentId, ["all"]); - } else { - root.setScreenPreferences(parent.componentId, []); - const cid = parent.componentId; - if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) { - root.setShowOnLastDisplay(cid, true); - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Focused monitor only") - description: I18n.tr("Show notifications only on the currently focused monitor") - visible: parent.componentId === "notifications" - checked: SettingsData.notificationFocusedMonitor - onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked) - } - - DankToggle { - width: parent.width - text: I18n.tr("Show on Last Display") - description: I18n.tr("Always show when there's only one connected display") - checked: root.getShowOnLastDisplay(parent.componentId) - visible: { - const prefs = root.getScreenPreferences(parent.componentId); - const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - const cid = parent.componentId; - const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:"); - return !isAll && isRelevantComponent; - } - onToggled: checked => { - root.setShowOnLastDisplay(parent.componentId, checked); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: { - var prefs = root.getScreenPreferences(parent.componentId); - return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: { - var prefs = root.getScreenPreferences(parent.componentId); - return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); - } - - Repeater { - model: Quickshell.screens - - delegate: DankToggle { - property var screenData: modelData - property string componentId: parent.parent.componentId - - width: parent.width - text: SettingsData.getScreenDisplayName(screenData) - description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name) - checked: { - var prefs = root.getScreenPreferences(componentId); - if (typeof prefs[0] === "string" && prefs[0] === "all") - return false; - return SettingsData.isScreenInPreferences(screenData, prefs); - } - onToggled: checked => { - var currentPrefs = root.getScreenPreferences(componentId); - if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") { - currentPrefs = []; - } - - const screenModelIndex = SettingsData.getScreenModelIndex(screenData); - - var newPrefs = currentPrefs.filter(pref => { - if (typeof pref === "string") - return false; - if (pref.modelIndex !== undefined && screenModelIndex >= 0) { - return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex); - } - return pref.name !== screenData.name || pref.model !== screenData.model; - }); - - if (checked) { - const prefObj = { - "name": screenData.name, - "model": screenData.model || "" - }; - if (screenModelIndex >= 0) { - prefObj.modelIndex = screenModelIndex; - } - newPrefs.push(prefObj); - } - - root.setScreenPreferences(componentId, newPrefs); - } - } - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml deleted file mode 100644 index 9b281a3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml +++ /dev/null @@ -1,657 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - FileBrowserModal { - id: dockLogoFileBrowser - browserTitle: I18n.tr("Select Dock Launcher Logo") - browserIcon: "image" - browserType: "generic" - filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"] - onFileSelected: path => SettingsData.set("dockLauncherLogoCustomPath", path.replace("file://", "")) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "dock_to_bottom" - title: I18n.tr("Dock Visibility") - settingKey: "dockVisibility" - - SettingsToggleRow { - settingKey: "showDock" - tags: ["dock", "show", "display", "enable"] - text: I18n.tr("Show Dock") - description: I18n.tr("Display a dock with pinned and running applications") - checked: SettingsData.showDock - onToggled: checked => SettingsData.setShowDock(checked) - } - - SettingsToggleRow { - settingKey: "dockAutoHide" - tags: ["dock", "autohide", "hide", "hover"] - text: I18n.tr("Auto-hide Dock") - description: I18n.tr("Always hide the dock and reveal it when hovering near the dock area") - checked: SettingsData.dockAutoHide - visible: SettingsData.showDock - onToggled: checked => { - if (checked && SettingsData.dockSmartAutoHide) { - SettingsData.set("dockSmartAutoHide", false); - } - SettingsData.set("dockAutoHide", checked); - } - } - - SettingsToggleRow { - settingKey: "dockSmartAutoHide" - tags: ["dock", "smart", "autohide", "windows", "overlap", "intelligent"] - text: I18n.tr("Intelligent Auto-hide") - description: I18n.tr("Show dock when floating windows don't overlap its area") - checked: SettingsData.dockSmartAutoHide - visible: SettingsData.showDock && (CompositorService.isNiri || CompositorService.isHyprland) - onToggled: checked => { - if (checked && SettingsData.dockAutoHide) { - SettingsData.set("dockAutoHide", false); - } - SettingsData.set("dockSmartAutoHide", checked); - } - } - - SettingsToggleRow { - settingKey: "dockOpenOnOverview" - tags: ["dock", "overview", "niri"] - text: I18n.tr("Show on Overview") - description: I18n.tr("Always show the dock when niri's overview is open") - checked: SettingsData.dockOpenOnOverview - visible: CompositorService.isNiri - onToggled: checked => SettingsData.set("dockOpenOnOverview", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "swap_vert" - title: I18n.tr("Position") - settingKey: "dockPosition" - - Item { - width: parent.width - height: dockPositionButtonGroup.height - - DankButtonGroup { - id: dockPositionButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")] - currentIndex: { - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return 1; - case SettingsData.Position.Left: - return 2; - case SettingsData.Position.Right: - return 3; - default: - return 1; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.setDockPosition(SettingsData.Position.Top); - break; - case 1: - SettingsData.setDockPosition(SettingsData.Position.Bottom); - break; - case 2: - SettingsData.setDockPosition(SettingsData.Position.Left); - break; - case 3: - SettingsData.setDockPosition(SettingsData.Position.Right); - break; - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Behavior") - settingKey: "dockBehavior" - - SettingsToggleRow { - settingKey: "dockIsolateDisplays" - tags: ["dock", "isolate", "monitor", "multi-monitor"] - text: I18n.tr("Isolate Displays") - description: I18n.tr("Only show windows from the current monitor on each dock") - checked: SettingsData.dockIsolateDisplays - onToggled: checked => SettingsData.set("dockIsolateDisplays", checked) - } - - SettingsToggleRow { - settingKey: "dockGroupByApp" - tags: ["dock", "group", "windows", "app"] - text: I18n.tr("Group by App") - description: I18n.tr("Group multiple windows of the same app together with a window count indicator") - checked: SettingsData.dockGroupByApp - onToggled: checked => SettingsData.set("dockGroupByApp", checked) - } - - SettingsToggleRow { - settingKey: "dockRestoreSpecialWorkspaceOnClick" - tags: ["dock", "hyprland", "special", "workspace", "restore"] - text: I18n.tr("Restore Special Workspace Windows") - description: I18n.tr("When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window") - checked: SettingsData.dockRestoreSpecialWorkspaceOnClick - visible: CompositorService.isHyprland - onToggled: checked => SettingsData.set("dockRestoreSpecialWorkspaceOnClick", checked) - } - - SettingsButtonGroupRow { - settingKey: "dockIndicatorStyle" - tags: ["dock", "indicator", "style", "circle", "line"] - text: I18n.tr("Indicator Style") - model: [I18n.tr("Circle", "dock indicator style option"), I18n.tr("Line", "dock indicator style option")] - buttonPadding: Theme.spacingS - minButtonWidth: 44 - textSize: Theme.fontSizeSmall - currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1 - onSelectionChanged: (index, selected) => { - if (selected) { - SettingsData.set("dockIndicatorStyle", index === 0 ? "circle" : "line"); - } - } - } - - SettingsSliderRow { - settingKey: "dockMaxVisibleApps" - tags: ["dock", "overflow", "max", "apps", "limit"] - text: I18n.tr("Max Pinned Apps (0 = Unlimited)") - minimum: 0 - maximum: 30 - value: SettingsData.dockMaxVisibleApps - defaultValue: 0 - unit: "" - onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleApps", newValue) - } - - SettingsSliderRow { - settingKey: "dockMaxVisibleRunningApps" - tags: ["dock", "overflow", "max", "running", "apps", "limit"] - text: I18n.tr("Max Running Apps (0 = Unlimited)") - minimum: 0 - maximum: 30 - value: SettingsData.dockMaxVisibleRunningApps - defaultValue: 0 - unit: "" - onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleRunningApps", newValue) - } - - SettingsToggleRow { - settingKey: "dockShowOverflowBadge" - tags: ["dock", "overflow", "badge", "count", "indicator"] - text: I18n.tr("Show Overflow Badge Count") - description: I18n.tr("Displays count when overflow is active") - checked: SettingsData.dockShowOverflowBadge - onToggled: checked => SettingsData.set("dockShowOverflowBadge", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Launcher Button") - settingKey: "dockLauncher" - - SettingsToggleRow { - settingKey: "dockLauncherEnabled" - tags: ["dock", "launcher", "button", "apps"] - text: I18n.tr("Show Launcher Button") - checked: SettingsData.dockLauncherEnabled - onToggled: checked => SettingsData.set("dockLauncherEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.dockLauncherEnabled - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Icon") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: logoModeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: logoModeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: { - const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")]; - if (CompositorService.isNiri) { - modes.push("niri"); - } else if (CompositorService.isHyprland) { - modes.push("Hyprland"); - } else if (CompositorService.isDwl) { - modes.push("mango"); - } else if (CompositorService.isSway) { - modes.push("Sway"); - } else if (CompositorService.isScroll) { - modes.push("Scroll"); - } else if (CompositorService.isMiracle) { - modes.push("Miracle"); - } else { - modes.push(I18n.tr("Compositor")); - } - modes.push(I18n.tr("Custom")); - return modes; - } - currentIndex: { - if (SettingsData.dockLauncherLogoMode === "apps") - return 0; - if (SettingsData.dockLauncherLogoMode === "os") - return 1; - if (SettingsData.dockLauncherLogoMode === "dank") - return 2; - if (SettingsData.dockLauncherLogoMode === "compositor") - return 3; - if (SettingsData.dockLauncherLogoMode === "custom") - return 4; - return 0; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockLauncherLogoMode", "apps"); - break; - case 1: - SettingsData.set("dockLauncherLogoMode", "os"); - break; - case 2: - SettingsData.set("dockLauncherLogoMode", "dank"); - break; - case 3: - SettingsData.set("dockLauncherLogoMode", "compositor"); - break; - case 4: - SettingsData.set("dockLauncherLogoMode", "custom"); - break; - } - } - } - } - } - - Row { - width: parent.width - visible: SettingsData.dockLauncherLogoMode === "custom" - spacing: Theme.spacingM - - StyledRect { - width: parent.width - selectButton.width - Theme.spacingM - height: 36 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: Theme.outlineStrong - border.width: 1 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: SettingsData.dockLauncherLogoCustomPath || I18n.tr("Select an image file...") - font.pixelSize: Theme.fontSizeMedium - color: SettingsData.dockLauncherLogoCustomPath ? Theme.surfaceText : Theme.outlineButton - width: parent.width - Theme.spacingM * 2 - elide: Text.ElideMiddle - } - } - - DankActionButton { - id: selectButton - iconName: "folder_open" - width: 36 - height: 36 - onClicked: dockLogoFileBrowser.open() - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.dockLauncherLogoMode !== "apps" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color Override") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: colorOverrideRow.implicitHeight - clip: true - - Row { - id: colorOverrideRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - DankButtonGroup { - id: colorModeGroup - buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.parent.width < 480 ? 44 : 64 - textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")] - currentIndex: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override === "") - return 0; - if (override === "primary") - return 1; - if (override === "surface") - return 2; - return 3; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockLauncherLogoColorOverride", ""); - break; - case 1: - SettingsData.set("dockLauncherLogoColorOverride", "primary"); - break; - case 2: - SettingsData.set("dockLauncherLogoColorOverride", "surface"); - break; - case 3: - const currentOverride = SettingsData.dockLauncherLogoColorOverride; - const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface"; - if (isPreset) { - SettingsData.set("dockLauncherLogoColorOverride", "#ffffff"); - } - break; - } - } - } - - Rectangle { - id: colorPickerCircle - visible: { - const override = SettingsData.dockLauncherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - width: 36 - height: 36 - radius: 18 - color: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override !== "" && override !== "primary" && override !== "surface") - return override; - return "#ffffff"; - } - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.dockLauncherLogoColorOverride; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dock Launcher Logo Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("dockLauncherLogoColorOverride", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoSizeOffset" - tags: ["dock", "launcher", "logo", "size", "offset", "scale"] - text: I18n.tr("Size Offset") - minimum: -12 - maximum: 12 - value: SettingsData.dockLauncherLogoSizeOffset - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoSizeOffset", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: { - const override = SettingsData.dockLauncherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoBrightness" - tags: ["dock", "launcher", "logo", "brightness", "color"] - text: I18n.tr("Brightness") - minimum: 0 - maximum: 100 - value: Math.round(SettingsData.dockLauncherLogoBrightness * 100) - unit: "%" - defaultValue: 50 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoBrightness", newValue / 100) - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoContrast" - tags: ["dock", "launcher", "logo", "contrast", "color"] - text: I18n.tr("Contrast") - minimum: 0 - maximum: 200 - value: Math.round(SettingsData.dockLauncherLogoContrast * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoContrast", newValue / 100) - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "photo_size_select_large" - title: I18n.tr("Sizing") - settingKey: "dockSizing" - - SettingsSliderRow { - settingKey: "dockIconSize" - tags: ["dock", "icon", "size", "scale"] - text: I18n.tr("Icon Size") - value: SettingsData.dockIconSize - minimum: 24 - maximum: 96 - unit: "px" - defaultValue: 48 - onSliderValueChanged: newValue => SettingsData.set("dockIconSize", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "space_bar" - title: I18n.tr("Spacing") - settingKey: "dockSpacing" - collapsible: true - expanded: false - - SettingsSliderRow { - text: I18n.tr("Padding") - value: SettingsData.dockSpacing - minimum: 0 - maximum: 32 - defaultValue: 8 - onSliderValueChanged: newValue => SettingsData.set("dockSpacing", newValue) - } - - SettingsSliderRow { - text: I18n.tr("Exclusive Zone Offset") - value: SettingsData.dockBottomGap - minimum: -100 - maximum: 100 - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockBottomGap", newValue) - } - - SettingsSliderRow { - text: I18n.tr("Margin") - value: SettingsData.dockMargin - minimum: 0 - maximum: 100 - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockMargin", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "opacity" - title: I18n.tr("Transparency") - settingKey: "dockTransparency" - - SettingsSliderRow { - text: I18n.tr("Dock Transparency") - value: Math.round(SettingsData.dockTransparency * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 85 - onSliderValueChanged: newValue => SettingsData.set("dockTransparency", newValue / 100) - } - } - - SettingsCard { - width: parent.width - iconName: "border_style" - title: I18n.tr("Border") - settingKey: "dockBorder" - collapsible: true - expanded: false - - SettingsToggleRow { - text: I18n.tr("Border") - description: I18n.tr("Add a border around the dock") - checked: SettingsData.dockBorderEnabled - onToggled: checked => SettingsData.set("dockBorderEnabled", checked) - } - - SettingsButtonGroupRow { - text: I18n.tr("Border Color") - description: I18n.tr("Choose the border accent color") - visible: SettingsData.dockBorderEnabled - model: [I18n.tr("Surface", "color option"), I18n.tr("Secondary", "color option"), I18n.tr("Primary", "color option")] - buttonPadding: Theme.spacingS - minButtonWidth: 44 - textSize: Theme.fontSizeSmall - currentIndex: { - switch (SettingsData.dockBorderColor) { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockBorderColor", "surfaceText"); - break; - case 1: - SettingsData.set("dockBorderColor", "secondary"); - break; - case 2: - SettingsData.set("dockBorderColor", "primary"); - break; - } - } - } - - SettingsSliderRow { - text: I18n.tr("Border Opacity") - visible: SettingsData.dockBorderEnabled - value: SettingsData.dockBorderOpacity * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("dockBorderOpacity", newValue / 100) - } - - SettingsSliderRow { - text: I18n.tr("Border Thickness") - visible: SettingsData.dockBorderEnabled - value: SettingsData.dockBorderThickness - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderValueChanged: newValue => SettingsData.set("dockBorderThickness", newValue) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml deleted file mode 100644 index 7d08c5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml +++ /dev/null @@ -1,663 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - function formatGammaTime(isoString) { - if (!isoString) - return ""; - try { - const date = new Date(isoString); - if (isNaN(date.getTime())) - return ""; - return date.toLocaleTimeString(Qt.locale(), "HH:mm"); - } catch (e) { - return ""; - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: gammaSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: gammaSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "brightness_6" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Gamma Control") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: nightModeToggle - - width: parent.width - text: I18n.tr("Night Mode") - description: DisplayService.gammaControlAvailable ? I18n.tr("Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.") : I18n.tr("Gamma control not available. Requires DMS API v6+.") - checked: DisplayService.nightModeEnabled - enabled: DisplayService.gammaControlAvailable - onToggled: checked => { - DisplayService.toggleNightMode(); - } - - Connections { - function onNightModeEnabledChanged() { - nightModeToggle.checked = DisplayService.nightModeEnabled; - } - - target: DisplayService - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - visible: DisplayService.gammaControlAvailable - - SettingsSliderRow { - id: nightTempSlider - settingKey: "nightModeTemperature" - tags: ["gamma", "night", "temperature", "kelvin", "warm", "color", "blue light"] - width: parent.width - parent.leftPadding - parent.rightPadding - text: SessionData.nightModeAutoEnabled ? I18n.tr("Night Temperature") : I18n.tr("Color Temperature") - description: SessionData.nightModeAutoEnabled ? I18n.tr("Color temperature for night mode") : I18n.tr("Warm color temperature to apply") - minimum: 2500 - maximum: 6000 - step: 100 - unit: "K" - value: SessionData.nightModeTemperature - onSliderValueChanged: newValue => { - SessionData.setNightModeTemperature(newValue); - if (SessionData.nightModeHighTemperature < newValue) - SessionData.setNightModeHighTemperature(newValue); - } - } - - SettingsSliderRow { - id: dayTempSlider - settingKey: "nightModeHighTemperature" - tags: ["gamma", "day", "temperature", "kelvin", "color"] - width: parent.width - parent.leftPadding - parent.rightPadding - text: I18n.tr("Day Temperature") - description: I18n.tr("Color temperature for day time") - minimum: SessionData.nightModeTemperature - maximum: 10000 - step: 100 - unit: "K" - value: Math.max(SessionData.nightModeHighTemperature, SessionData.nightModeTemperature) - visible: SessionData.nightModeAutoEnabled - onSliderValueChanged: newValue => SessionData.setNightModeHighTemperature(newValue) - } - } - - DankToggle { - id: automaticToggle - width: parent.width - text: I18n.tr("Automatic Control") - description: I18n.tr("Only adjust gamma based on time or location rules.") - checked: SessionData.nightModeAutoEnabled - visible: DisplayService.gammaControlAvailable - onToggled: checked => { - if (checked && !DisplayService.nightModeEnabled) { - DisplayService.toggleNightMode(); - } else if (!checked && DisplayService.nightModeEnabled) { - DisplayService.toggleNightMode(); - } - SessionData.setNightModeAutoEnabled(checked); - } - - Connections { - target: SessionData - function onNightModeAutoEnabledChanged() { - automaticToggle.checked = SessionData.nightModeAutoEnabled; - } - } - } - - Column { - id: automaticSettings - width: parent.width - spacing: Theme.spacingS - visible: SessionData.nightModeAutoEnabled && DisplayService.gammaControlAvailable - - Connections { - target: SessionData - function onNightModeAutoEnabledChanged() { - automaticSettings.visible = SessionData.nightModeAutoEnabled; - } - } - - Item { - width: parent.width - height: 45 + Theme.spacingM - - DankTabBar { - id: modeTabBarNight - width: 200 - height: 45 - anchors.horizontalCenter: parent.horizontalCenter - model: [ - { - "text": I18n.tr("Time"), - "icon": "access_time" - }, - { - "text": I18n.tr("Location"), - "icon": "place" - } - ] - - Component.onCompleted: { - currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; - Qt.callLater(updateIndicator); - } - - onTabClicked: index => { - DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time"); - currentIndex = index; - } - - Connections { - target: SessionData - function onNightModeAutoModeChanged() { - modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; - Qt.callLater(modeTabBarNight.updateIndicator); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.nightModeAutoMode === "time" - - Column { - spacing: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: Theme.spacingM - - StyledText { - text: "" - width: 50 - height: 20 - } - - StyledText { - text: I18n.tr("Hour") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Minute") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Start") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeStartHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) { - hours.push(i.toString()); - } - return hours; - } - onValueChanged: value => { - SessionData.setNightModeStartHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setNightModeStartMinute(parseInt(value)); - } - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("End") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeEndHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) { - hours.push(i.toString()); - } - return hours; - } - onValueChanged: value => { - SessionData.setNightModeEndHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setNightModeEndMinute(parseInt(value)); - } - } - } - } - } - - Column { - property bool isLocationMode: SessionData.nightModeAutoMode === "location" - visible: isLocationMode - spacing: Theme.spacingM - width: parent.width - - DankToggle { - id: ipLocationToggle - width: parent.width - text: I18n.tr("Use IP Location") - description: I18n.tr("Automatically detect location based on IP address") - checked: SessionData.nightModeUseIPLocation || false - onToggled: checked => { - SessionData.setNightModeUseIPLocation(checked); - } - - Connections { - target: SessionData - function onNightModeUseIPLocationChanged() { - ipLocationToggle.checked = SessionData.nightModeUseIPLocation; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - leftPadding: Theme.spacingM - visible: !SessionData.nightModeUseIPLocation - - StyledText { - text: I18n.tr("Manual Coordinates") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Row { - spacing: Theme.spacingL - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.latitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lat = parseFloat(text); - if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { - SessionData.setLatitude(lat); - } - } - } - } - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.longitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lon = parseFloat(text); - if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { - SessionData.setLongitude(lon); - } - } - } - } - } - - StyledText { - text: I18n.tr("Uses sunrise/sunset times to automatically adjust night mode based on your location.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - parent.leftPadding - wrapMode: Text.WordWrap - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: gammaStatusSection.visible - } - - Column { - id: gammaStatusSection - width: parent.width - spacing: Theme.spacingM - visible: DisplayService.nightModeEnabled && DisplayService.gammaCurrentTemp > 0 - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: DisplayService.gammaIsDay ? "light_mode" : "dark_mode" - size: Theme.iconSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Status") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: tempColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: tempColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "device_thermostat" - size: Theme.iconSize - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayService.gammaCurrentTemp + "K" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Current Temp") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: periodColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: periodColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: DisplayService.gammaIsDay ? "wb_sunny" : "nightlight" - size: Theme.iconSize - color: DisplayService.gammaIsDay ? "#FFA726" : "#7E57C2" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayService.gammaIsDay ? I18n.tr("Daytime") : I18n.tr("Night") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Current Period") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.nightModeAutoMode === "location" && (DisplayService.gammaSunriseTime || DisplayService.gammaSunsetTime) - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: sunriseColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaSunriseTime - - Column { - id: sunriseColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "wb_twilight" - size: Theme.iconSize - color: "#FF7043" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaSunriseTime) - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Sunrise") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: sunsetColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaSunsetTime - - Column { - id: sunsetColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "wb_twilight" - size: Theme.iconSize - color: "#5C6BC0" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaSunsetTime) - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Sunset") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - width: parent.width - height: nextChangeRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaNextTransition - - Row { - id: nextChangeRow - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "schedule" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Next Transition") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaNextTransition) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml deleted file mode 100644 index b3d3a41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml +++ /dev/null @@ -1,784 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property bool greeterFprintToggleAvailable: SettingsData.greeterFingerprintCanEnable || SettingsData.greeterEnableFprint - readonly property bool greeterU2fToggleAvailable: SettingsData.greeterU2fCanEnable || SettingsData.greeterEnableU2f - - function greeterFingerprintDescription() { - const source = SettingsData.greeterFingerprintSource; - const reason = SettingsData.greeterFingerprintReason; - - if (source === "pam") { - switch (reason) { - case "configured_externally": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled. PAM already provides fingerprint auth.") : I18n.tr("PAM already provides fingerprint auth. Enable this to show it at login."); - case "missing_enrollment": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.") : I18n.tr("PAM provides fingerprint auth, but no prints are enrolled yet."); - case "missing_reader": - return I18n.tr("PAM provides fingerprint auth, but no reader was detected."); - default: - return I18n.tr("PAM provides fingerprint auth, but availability could not be confirmed."); - } - } - - switch (reason) { - case "ready": - return SettingsData.greeterEnableFprint ? I18n.tr("Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.") : I18n.tr("Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled."); - case "missing_enrollment": - if (SettingsData.greeterEnableFprint) - return I18n.tr("Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync."); - return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later."); - case "missing_reader": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled, but no fingerprint reader was detected.") : I18n.tr("No fingerprint reader detected."); - case "missing_pam_support": - return I18n.tr("Not available — install fprintd and pam_fprintd, or configure greetd PAM."); - default: - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled, but fingerprint availability could not be confirmed.") : I18n.tr("Fingerprint availability could not be confirmed."); - } - } - - function greeterU2fDescription() { - const source = SettingsData.greeterU2fSource; - const reason = SettingsData.greeterU2fReason; - - if (source === "pam") { - return SettingsData.greeterEnableU2f ? I18n.tr("Enabled. PAM already provides security-key auth.") : I18n.tr("PAM already provides security-key auth. Enable this to show it at login."); - } - - switch (reason) { - case "ready": - return SettingsData.greeterEnableU2f ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Available."); - case "missing_key_registration": - if (SettingsData.greeterEnableU2f) - return I18n.tr("Enabled, but no registered security key was found yet. Register a key and run Sync."); - return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later."); - case "missing_pam_support": - return I18n.tr("Not available — install or configure pam_u2f, or configure greetd PAM."); - default: - return SettingsData.greeterEnableU2f ? I18n.tr("Enabled, but security-key availability could not be confirmed.") : I18n.tr("Security-key availability could not be confirmed."); - } - } - - function refreshAuthDetection() { - SettingsData.refreshAuthAvailability(); - } - - onVisibleChanged: { - if (visible) - refreshAuthDetection(); - } - - ConfirmModal { - id: greeterActionConfirm - } - - FileBrowserModal { - id: greeterWallpaperBrowserModal - browserTitle: I18n.tr("Select greeter background image") - browserIcon: "wallpaper" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif"] - onFileSelected: path => { - SettingsData.set("greeterWallpaperPath", path); - close(); - } - } - - property string greeterStatusText: "" - property bool greeterStatusRunning: false - property bool greeterSyncRunning: false - property bool greeterInstallActionRunning: false - property string greeterStatusStdout: "" - property string greeterStatusStderr: "" - property string greeterSyncStdout: "" - property string greeterSyncStderr: "" - property string greeterSudoProbeStderr: "" - property string greeterTerminalFallbackStderr: "" - property bool greeterTerminalFallbackFromPrecheck: false - property var cachedFontFamilies: [] - property bool fontsEnumerated: false - property bool greeterBinaryExists: false - property bool greeterEnabled: false - readonly property bool greeterInstalled: greeterBinaryExists || greeterEnabled - - readonly property string greeterActionLabel: { - if (!root.greeterInstalled) - return I18n.tr("Install"); - if (!root.greeterEnabled) - return I18n.tr("Activate"); - return I18n.tr("Uninstall"); - } - readonly property string greeterActionIcon: { - if (!root.greeterInstalled) - return "download"; - if (!root.greeterEnabled) - return "login"; - return "delete"; - } - readonly property var greeterActionCommand: { - if (!root.greeterInstalled) - return ["dms", "greeter", "install", "--terminal"]; - if (!root.greeterEnabled) - return ["dms", "greeter", "enable", "--terminal"]; - return ["dms", "greeter", "uninstall", "--terminal", "--yes"]; - } - property string greeterPendingAction: "" - - function checkGreeterInstallState() { - greetdEnabledCheckProcess.running = true; - greeterBinaryCheckProcess.running = true; - } - - function runGreeterStatus() { - greeterStatusText = ""; - greeterStatusStdout = ""; - greeterStatusStderr = ""; - greeterStatusRunning = true; - greeterStatusProcess.running = true; - } - - function runGreeterInstallAction() { - root.greeterPendingAction = !root.greeterInstalled ? "install" : !root.greeterEnabled ? "activate" : "uninstall"; - greeterStatusText = I18n.tr("Opening terminal: ") + root.greeterActionLabel + "…"; - greeterInstallActionRunning = true; - greeterInstallActionProcess.running = true; - } - - function promptGreeterActionConfirm() { - var title, message, confirmText; - if (!root.greeterInstalled) { - title = I18n.tr("Install Greeter", "greeter action confirmation"); - message = I18n.tr("Install the DMS greeter? A terminal will open for sudo authentication."); - confirmText = I18n.tr("Install"); - } else if (!root.greeterEnabled) { - title = I18n.tr("Activate Greeter", "greeter action confirmation"); - message = I18n.tr("Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings."); - confirmText = I18n.tr("Activate"); - } else { - title = I18n.tr("Uninstall Greeter", "greeter action confirmation"); - message = I18n.tr("Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication."); - confirmText = I18n.tr("Uninstall"); - } - greeterActionConfirm.showWithOptions({ - "title": title, - "message": message, - "confirmText": confirmText, - "cancelText": I18n.tr("Cancel"), - "confirmColor": Theme.primary, - "onConfirm": () => root.runGreeterInstallAction(), - "onCancel": () => {} - }); - } - - function runGreeterSync() { - greeterSyncStdout = ""; - greeterSyncStderr = ""; - greeterSudoProbeStderr = ""; - greeterTerminalFallbackStderr = ""; - greeterTerminalFallbackFromPrecheck = false; - greeterStatusText = I18n.tr("Checking whether sudo authentication is needed…"); - greeterSyncRunning = true; - greeterSudoProbeProcess.running = true; - } - - function launchGreeterSyncTerminalFallback(fromPrecheck, statusText) { - greeterTerminalFallbackFromPrecheck = fromPrecheck; - if (statusText && statusText !== "") - greeterStatusText = statusText; - greeterTerminalFallbackStderr = ""; - greeterTerminalFallbackProcess.running = true; - } - - function enumerateFonts() { - if (fontsEnumerated) - return; - var fonts = []; - var availableFonts = Qt.fontFamilies(); - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - fonts.push(fontName); - } - fonts.sort(); - fonts.unshift("Default"); - cachedFontFamilies = fonts; - fontsEnumerated = true; - } - - Component.onCompleted: { - refreshAuthDetection(); - Qt.callLater(enumerateFonts); - Qt.callLater(checkGreeterInstallState); - } - - Process { - id: greetdEnabledCheckProcess - command: ["systemctl", "is-enabled", "greetd"] - running: false - - stdout: StdioCollector { - onStreamFinished: root.greeterEnabled = text.trim() === "enabled" - } - } - - Process { - id: greeterBinaryCheckProcess - command: ["sh", "-c", "test -f /usr/bin/dms-greeter || test -f /usr/local/bin/dms-greeter"] - running: false - - onExited: exitCode => { - root.greeterBinaryExists = (exitCode === 0); - } - } - - Process { - id: greeterStatusProcess - command: ["dms", "greeter", "status"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - root.greeterStatusStdout = text || ""; - } - } - - stderr: StdioCollector { - onStreamFinished: root.greeterStatusStderr = text || "" - } - - onExited: exitCode => { - root.greeterStatusRunning = false; - const out = (root.greeterStatusStdout || "").trim(); - const err = (root.greeterStatusStderr || "").trim(); - if (exitCode === 0) { - root.greeterStatusText = out !== "" ? out : I18n.tr("No status output."); - if (err !== "") - root.greeterStatusText = root.greeterStatusText + "\n\nstderr:\n" + err; - return; - } - var failure = I18n.tr("Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.", "greeter status error") + " (exit " + exitCode + ")"; - if (out !== "") - failure = failure + "\n\n" + out; - if (err !== "") - failure = failure + "\n\nstderr:\n" + err; - root.greeterStatusText = failure; - } - } - - Process { - id: greeterSyncProcess - command: ["dms", "greeter", "sync", "--yes"] - running: false - - stdout: StdioCollector { - onStreamFinished: root.greeterSyncStdout = text || "" - } - - stderr: StdioCollector { - onStreamFinished: root.greeterSyncStderr = text || "" - } - - onExited: exitCode => { - root.greeterSyncRunning = false; - const out = (root.greeterSyncStdout || "").trim(); - const err = (root.greeterSyncStderr || "").trim(); - if (exitCode === 0) { - var success = I18n.tr("Sync completed successfully."); - if (out !== "") - success = success + "\n\n" + out; - if (err !== "") - success = success + "\n\nstderr:\n" + err; - root.greeterStatusText = success; - } else { - var failure = I18n.tr("Sync failed in background mode. Trying terminal mode so you can authenticate interactively.") + " (exit " + exitCode + ")"; - if (out !== "") - failure = failure + "\n\n" + out; - if (err !== "") - failure = failure + "\n\nstderr:\n" + err; - root.greeterStatusText = failure; - root.launchGreeterSyncTerminalFallback(false, ""); - } - root.checkGreeterInstallState(); - } - } - - Process { - id: greeterSudoProbeProcess - command: ["sudo", "-n", "true"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.greeterSudoProbeStderr = text || "" - } - - onExited: exitCode => { - const err = (root.greeterSudoProbeStderr || "").trim(); - if (exitCode === 0) { - root.greeterStatusText = I18n.tr("Running greeter sync…"); - greeterSyncProcess.running = true; - return; - } - - var authNeeded = I18n.tr("Sync needs sudo authentication. Opening terminal so you can use password or fingerprint."); - if (err !== "") - authNeeded = authNeeded + "\n\n" + err; - root.launchGreeterSyncTerminalFallback(true, authNeeded); - } - } - - Process { - id: greeterTerminalFallbackProcess - command: ["dms", "greeter", "sync", "--terminal", "--yes"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.greeterTerminalFallbackStderr = text || "" - } - - onExited: exitCode => { - root.greeterSyncRunning = false; - if (exitCode === 0) { - var launched = root.greeterTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete sync authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete sync there; it will close automatically when done."); - root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + launched : launched; - return; - } - var fallback = I18n.tr("Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.") + " (exit " + exitCode + ")"; - const err = (root.greeterTerminalFallbackStderr || "").trim(); - if (err !== "") - fallback = fallback + "\n\nstderr:\n" + err; - root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + fallback : fallback; - } - } - - Process { - id: greeterInstallActionProcess - command: root.greeterActionCommand - running: false - - onExited: exitCode => { - root.greeterInstallActionRunning = false; - const pending = root.greeterPendingAction; - root.greeterPendingAction = ""; - if (exitCode === 0) { - if (pending === "install") - root.greeterStatusText = I18n.tr("Install complete. Greeter has been installed."); - else if (pending === "activate") - root.greeterStatusText = I18n.tr("Greeter activated. greetd is now enabled."); - else - root.greeterStatusText = I18n.tr("Uninstall complete. Greeter has been removed."); - } else { - root.greeterStatusText = I18n.tr("Action failed or terminal was closed.") + " (exit " + exitCode + ")"; - } - root.checkGreeterInstallState(); - } - } - - readonly property var _lockDateFormatPresets: [ - { - format: "", - label: I18n.tr("System Default", "date format option") - }, - { - format: "ddd d", - label: I18n.tr("Day Date", "date format option") - }, - { - format: "ddd MMM d", - label: I18n.tr("Day Month Date", "date format option") - }, - { - format: "MMM d", - label: I18n.tr("Month Date", "date format option") - }, - { - format: "M/d", - label: I18n.tr("Numeric (M/D)", "date format option") - }, - { - format: "d/M", - label: I18n.tr("Numeric (D/M)", "date format option") - }, - { - format: "ddd d MMM yyyy", - label: I18n.tr("Full with Year", "date format option") - }, - { - format: "yyyy-MM-dd", - label: I18n.tr("ISO Date", "date format option") - }, - { - format: "dddd, MMMM d", - label: I18n.tr("Full Day & Month", "date format option") - } - ] - readonly property var _wallpaperFillModes: ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"] - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "info" - title: I18n.tr("Greeter Status") - settingKey: "greeterStatus" - - StyledText { - text: I18n.tr("Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - Item { - width: 1 - height: Theme.spacingS - } - - Rectangle { - width: parent.width - height: Math.min(180, statusTextArea.implicitHeight + Theme.spacingM * 2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - - StyledText { - id: statusTextArea - anchors.fill: parent - anchors.margins: Theme.spacingM - text: root.greeterStatusRunning ? I18n.tr("Checking…", "greeter status loading") : (root.greeterStatusText || I18n.tr("Click Refresh to check status.", "greeter status placeholder")) - font.pixelSize: Theme.fontSizeSmall - font.family: "monospace" - color: root.greeterStatusRunning ? Theme.surfaceVariantText : Theme.surfaceText - wrapMode: Text.Wrap - verticalAlignment: Text.AlignTop - } - } - - Item { - width: 1 - height: Theme.spacingM - } - - RowLayout { - width: parent.width - spacing: Theme.spacingS - - DankButton { - text: root.greeterActionLabel - iconName: root.greeterActionIcon - horizontalPadding: Theme.spacingL - onClicked: root.promptGreeterActionConfirm() - enabled: !root.greeterInstallActionRunning && !root.greeterSyncRunning - } - - Item { - Layout.fillWidth: true - } - - DankButton { - text: I18n.tr("Refresh") - iconName: "refresh" - horizontalPadding: Theme.spacingL - onClicked: root.runGreeterStatus() - enabled: !root.greeterStatusRunning - } - - DankButton { - text: I18n.tr("Sync") - iconName: "sync" - horizontalPadding: Theme.spacingL - onClicked: root.runGreeterSync() - enabled: root.greeterInstalled && !root.greeterSyncRunning && !root.greeterInstallActionRunning - } - } - } - - SettingsCard { - width: parent.width - iconName: "fingerprint" - title: I18n.tr("Login Authentication") - settingKey: "greeterAuth" - - StyledText { - text: I18n.tr("Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "greeterEnableFprint" - tags: ["greeter", "fingerprint", "fprintd", "login", "auth"] - text: I18n.tr("Enable fingerprint at login") - description: root.greeterFingerprintDescription() - descriptionColor: (SettingsData.greeterFingerprintReason === "ready" || SettingsData.greeterFingerprintReason === "configured_externally") ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.greeterEnableFprint - enabled: root.greeterFprintToggleAvailable - onToggled: checked => SettingsData.set("greeterEnableFprint", checked) - } - - SettingsToggleRow { - settingKey: "greeterEnableU2f" - tags: ["greeter", "u2f", "security", "key", "login", "auth"] - text: I18n.tr("Enable security key at login") - description: root.greeterU2fDescription() - descriptionColor: (SettingsData.greeterU2fReason === "ready" || SettingsData.greeterU2fReason === "configured_externally") ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.greeterEnableU2f - enabled: root.greeterU2fToggleAvailable - onToggled: checked => SettingsData.set("greeterEnableU2f", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "palette" - title: I18n.tr("Greeter Appearance") - settingKey: "greeterAppearance" - - StyledText { - text: I18n.tr("Font") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsDropdownRow { - settingKey: "greeterFontFamily" - tags: ["greeter", "font", "typography"] - text: I18n.tr("Greeter font") - description: I18n.tr("Font used on the login screen") - options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"] - currentValue: (!SettingsData.greeterFontFamily || SettingsData.greeterFontFamily === "" || SettingsData.greeterFontFamily === Theme.defaultFontFamily) ? "Default" : (SettingsData.greeterFontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("greeterFontFamily", ""); - else - SettingsData.set("greeterFontFamily", value); - } - } - - StyledText { - text: I18n.tr("Time format") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsToggleRow { - settingKey: "greeterUse24Hour" - tags: ["greeter", "time", "24hour"] - text: I18n.tr("24-hour clock") - description: I18n.tr("Greeter only — does not affect main clock") - checked: SettingsData.greeterUse24HourClock - onToggled: checked => SettingsData.set("greeterUse24HourClock", checked) - } - - SettingsToggleRow { - settingKey: "greeterShowSeconds" - tags: ["greeter", "time", "seconds"] - text: I18n.tr("Show seconds") - checked: SettingsData.greeterShowSeconds - onToggled: checked => SettingsData.set("greeterShowSeconds", checked) - } - - SettingsToggleRow { - settingKey: "greeterPadHours" - tags: ["greeter", "time", "12hour"] - text: I18n.tr("Pad hours (02:00 vs 2:00)") - visible: !SettingsData.greeterUse24HourClock - checked: SettingsData.greeterPadHours12Hour - onToggled: checked => SettingsData.set("greeterPadHours12Hour", checked) - } - - StyledText { - text: I18n.tr("Date format on greeter") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsDropdownRow { - settingKey: "greeterLockDateFormat" - tags: ["greeter", "date", "format"] - text: I18n.tr("Date format") - description: I18n.tr("Greeter only — format for the date on the login screen") - options: root._lockDateFormatPresets.map(p => p.label) - currentValue: { - var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || ""; - var match = root._lockDateFormatPresets.find(p => p.format === current); - return match ? match.label : (current ? I18n.tr("Custom: ") + current : root._lockDateFormatPresets[0].label); - } - onValueChanged: value => { - var preset = root._lockDateFormatPresets.find(p => p.label === value); - SettingsData.set("greeterLockDateFormat", preset ? preset.format : ""); - } - } - - StyledText { - text: I18n.tr("Background") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - StyledText { - text: I18n.tr("Use a custom image for the login screen, or leave empty to use your desktop wallpaper.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - Row { - width: parent.width - spacing: Theme.spacingS - - DankTextField { - id: greeterWallpaperPathField - width: parent.width - browseGreeterWallpaperButton.width - Theme.spacingS - placeholderText: I18n.tr("Use desktop wallpaper") - text: SettingsData.greeterWallpaperPath - backgroundColor: Theme.surfaceContainerHighest - onTextChanged: { - if (text !== SettingsData.greeterWallpaperPath) - SettingsData.set("greeterWallpaperPath", text); - } - } - - DankButton { - id: browseGreeterWallpaperButton - text: I18n.tr("Browse") - horizontalPadding: Theme.spacingL - onClicked: greeterWallpaperBrowserModal.open() - } - } - - SettingsDropdownRow { - settingKey: "greeterWallpaperFillMode" - tags: ["greeter", "wallpaper", "background", "fill"] - text: I18n.tr("Wallpaper fill mode") - description: I18n.tr("How the background image is scaled") - options: root._wallpaperFillModes.map(m => I18n.tr(m, "wallpaper fill mode")) - currentValue: { - var mode = (SettingsData.greeterWallpaperFillMode && SettingsData.greeterWallpaperFillMode !== "") ? SettingsData.greeterWallpaperFillMode : (SettingsData.wallpaperFillMode || "Fill"); - var idx = root._wallpaperFillModes.indexOf(mode); - return idx >= 0 ? I18n.tr(root._wallpaperFillModes[idx], "wallpaper fill mode") : I18n.tr("Fill", "wallpaper fill mode"); - } - onValueChanged: value => { - var idx = root._wallpaperFillModes.map(m => I18n.tr(m, "wallpaper fill mode")).indexOf(value); - if (idx >= 0) - SettingsData.set("greeterWallpaperFillMode", root._wallpaperFillModes[idx]); - } - } - - StyledText { - text: I18n.tr("Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - topPadding: Theme.spacingS - } - } - - SettingsCard { - width: parent.width - iconName: "history" - title: I18n.tr("Greeter Behavior") - settingKey: "greeterBehavior" - - StyledText { - text: I18n.tr("Convenience options for the login screen. Sync to apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "greeterRememberLastSession" - tags: ["greeter", "session", "remember", "login"] - text: I18n.tr("Remember last session") - description: I18n.tr("Pre-select the last used session on the greeter") - checked: SettingsData.greeterRememberLastSession - onToggled: checked => SettingsData.set("greeterRememberLastSession", checked) - } - - SettingsToggleRow { - settingKey: "greeterRememberLastUser" - tags: ["greeter", "user", "remember", "login", "username"] - text: I18n.tr("Remember last user") - description: I18n.tr("Pre-fill the last successful username on the greeter") - checked: SettingsData.greeterRememberLastUser - onToggled: checked => SettingsData.set("greeterRememberLastUser", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "extension" - title: I18n.tr("Dependencies & documentation") - settingKey: "greeterDeps" - - StyledText { - text: I18n.tr("DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - StyledText { - text: I18n.tr("Installation and PAM setup: see the ") + "DankGreeter docs " + I18n.tr("or run ") + "'dms greeter install'." - textFormat: Text.RichText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - linkColor: Theme.primary - width: parent.width - wrapMode: Text.Wrap - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml deleted file mode 100644 index 6bf5d54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml +++ /dev/null @@ -1,672 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: keybindsTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedCategory: "" - property string searchQuery: "" - property string expandedKey: "" - property bool showingNewBind: false - - property int _lastDataVersion: -1 - property var _cachedCategories: [] - property var _filteredBinds: [] - property real _savedScrollY: 0 - property bool _preserveScroll: false - property string _editingKey: "" - - function _updateFiltered() { - const allBinds = KeybindsService.getFlatBinds(); - if (!searchQuery && !selectedCategory) { - _filteredBinds = allBinds; - return; - } - - const q = searchQuery.toLowerCase(); - const isOverrideFilter = selectedCategory === "__overrides__"; - const result = []; - - for (let i = 0; i < allBinds.length; i++) { - const group = allBinds[i]; - if (q) { - let keyMatch = false; - for (let k = 0; k < group.keys.length; k++) { - if (group.keys[k].key.toLowerCase().indexOf(q) !== -1) { - keyMatch = true; - break; - } - } - if (!keyMatch && group.desc.toLowerCase().indexOf(q) === -1 && group.action.toLowerCase().indexOf(q) === -1) - continue; - } - if (isOverrideFilter) { - let hasOverride = false; - for (let k = 0; k < group.keys.length; k++) { - if (group.keys[k].isOverride) { - hasOverride = true; - break; - } - } - if (!hasOverride) - continue; - } else if (selectedCategory && group.category !== selectedCategory) { - continue; - } - result.push(group); - } - _filteredBinds = result; - } - - function _updateCategories() { - _cachedCategories = ["__overrides__"].concat(KeybindsService.getCategories()); - } - - function getCategoryLabel(cat) { - if (cat === "__overrides__") - return I18n.tr("Overrides"); - return cat; - } - - function toggleExpanded(action) { - expandedKey = expandedKey === action ? "" : action; - } - - function startNewBind() { - showingNewBind = true; - expandedKey = ""; - } - - function cancelNewBind() { - showingNewBind = false; - } - - function saveNewBind(bindData) { - KeybindsService.saveBind("", bindData); - _editingKey = bindData.key; - expandedKey = bindData.action; - } - - function _onSaveSuccess() { - if (showingNewBind) { - showingNewBind = false; - selectedCategory = ""; - } - } - - function scrollToTop() { - flickable.contentY = 0; - } - - function _scrollToExpandedItem() { - for (let i = 0; i < bindsRepeater.count; i++) { - const item = bindsRepeater.itemAt(i); - if (item && item.modelData.action === expandedKey) { - const itemY = item.mapToItem(flickable.contentItem, 0, 0).y; - const itemH = item.height; - const viewH = flickable.height; - if (itemY >= flickable.contentY && itemY + itemH <= flickable.contentY + viewH) - return; - flickable.contentY = Math.max(0, Math.min(itemY - viewH / 4, flickable.contentHeight - viewH)); - return; - } - } - flickable.contentY = _savedScrollY; - } - - Timer { - id: searchDebounce - interval: 150 - onTriggered: keybindsTab._updateFiltered() - } - - Connections { - target: KeybindsService - function onBindsLoaded() { - const savedY = keybindsTab._savedScrollY; - const wasPreserving = keybindsTab._preserveScroll; - keybindsTab._lastDataVersion = KeybindsService._dataVersion; - keybindsTab._updateCategories(); - keybindsTab._updateFiltered(); - keybindsTab._preserveScroll = false; - if (wasPreserving) { - if (keybindsTab.expandedKey) - Qt.callLater(keybindsTab._scrollToExpandedItem); - else - Qt.callLater(() => flickable.contentY = savedY); - } - } - function onBindSaved(key) { - keybindsTab._savedScrollY = flickable.contentY; - keybindsTab._preserveScroll = true; - } - function onBindSaveCompleted(success) { - if (success) - keybindsTab._onSaveSuccess(); - } - function onBindRemoved(key) { - keybindsTab._savedScrollY = flickable.contentY; - keybindsTab._preserveScroll = true; - } - } - - function _ensureCurrentProvider() { - if (!KeybindsService.available) - return; - const cachedProvider = KeybindsService.keybinds?.provider; - const targetProvider = KeybindsService.currentProvider; - if (cachedProvider !== targetProvider || KeybindsService._dataVersion === 0) { - KeybindsService.loadBinds(); - return; - } - if (_lastDataVersion !== KeybindsService._dataVersion) { - _lastDataVersion = KeybindsService._dataVersion; - _updateCategories(); - _updateFiltered(); - } - } - - Component.onCompleted: _ensureCurrentProvider() - - onVisibleChanged: { - if (!visible) - return; - Qt.callLater(scrollToTop); - _ensureCurrentProvider(); - } - - DankFlickable { - id: flickable - anchors.fill: parent - clip: true - contentWidth: width - contentHeight: contentColumn.implicitHeight - - Column { - id: contentColumn - width: flickable.width - spacing: Theme.spacingL - topPadding: Theme.spacingXL - bottomPadding: Theme.spacingXL - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: headerSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: headerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM * 2 - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Keyboard Shortcuts") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - readonly property string bindsFile: KeybindsService.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf" - text: I18n.tr("Click any shortcut to edit. Changes save to %1").arg(bindsFile) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - DankTextField { - id: searchField - width: parent.width - addButton.width - Theme.spacingM - placeholderText: I18n.tr("Search keybinds...") - leftIconName: "search" - onTextChanged: { - keybindsTab.searchQuery = text; - searchDebounce.restart(); - } - } - - DankActionButton { - id: addButton - width: searchField.height - height: searchField.height - circular: false - iconName: "add" - iconSize: Theme.iconSize - iconColor: Theme.primary - anchors.verticalCenter: parent.verticalCenter - enabled: !keybindsTab.showingNewBind - opacity: enabled ? 1 : 0.5 - onClicked: keybindsTab.startNewBind() - } - } - } - } - - StyledRect { - id: warningBox - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: warningSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - - readonly property var status: KeybindsService.dmsStatus - readonly property bool showError: !status.included && status.exists - readonly property bool showWarning: status.included && status.overriddenBy > 0 - readonly property bool showSetup: !status.exists - - color: (showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : "transparent" - border.color: (showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: 1 - visible: (showError || showWarning || showSetup) && !KeybindsService.loading - - Column { - id: warningSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: warningBox.showWarning ? "info" : "warning" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (warningBox.showSetup) - return I18n.tr("First Time Setup"); - if (warningBox.showError) - return I18n.tr("Binds Include Missing"); - if (warningBox.showWarning) - return I18n.tr("Possible Override Conflicts"); - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - } - - StyledText { - readonly property string bindsFile: KeybindsService.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf" - text: { - if (warningBox.showSetup) - return I18n.tr("Click 'Setup' to create %1 and add include to config.").arg(bindsFile); - if (warningBox.showError) - return I18n.tr("%1 exists but is not included in config. Custom keybinds will not work until this is fixed.").arg(bindsFile); - if (warningBox.showWarning) { - const count = warningBox.status.overriddenBy; - return I18n.ntr( - "%1 DMS bind may be overridden by config binds that come after the include.", - "%1 DMS binds may be overridden by config binds that come after the include.", - count - ).arg(count); - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: warningBox.showError || warningBox.showSetup - text: { - if (KeybindsService.fixing) - return I18n.tr("Fixing..."); - if (warningBox.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } - backgroundColor: Theme.primary - textColor: Theme.primaryText - enabled: !KeybindsService.fixing - anchors.verticalCenter: parent.verticalCenter - onClicked: KeybindsService.fixDmsBindsInclude() - } - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: categorySection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: categorySection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Flow { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - readonly property real chipHeight: allChip.implicitHeight + Theme.spacingM - width: allChip.implicitWidth + Theme.spacingL - height: chipHeight - radius: chipHeight / 2 - color: !keybindsTab.selectedCategory ? Theme.primary : Theme.surfaceContainerHighest - - StyledText { - id: allChip - text: I18n.tr("All") - font.pixelSize: Theme.fontSizeSmall - color: !keybindsTab.selectedCategory ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - keybindsTab.selectedCategory = ""; - keybindsTab._updateFiltered(); - } - } - } - - Repeater { - model: keybindsTab._cachedCategories - - delegate: Rectangle { - required property string modelData - required property int index - - readonly property real chipHeight: catText.implicitHeight + Theme.spacingM - width: catText.implicitWidth + Theme.spacingL - height: chipHeight - radius: chipHeight / 2 - color: keybindsTab.selectedCategory === modelData ? Theme.primary : (modelData === "__overrides__" ? Theme.withAlpha(Theme.primary, 0.15) : Theme.surfaceContainerHighest) - - StyledText { - id: catText - text: keybindsTab.getCategoryLabel(modelData) - font.pixelSize: Theme.fontSizeSmall - color: keybindsTab.selectedCategory === modelData ? Theme.primaryText : (modelData === "__overrides__" ? Theme.primary : Theme.surfaceVariantText) - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - keybindsTab.selectedCategory = modelData; - keybindsTab._updateFiltered(); - } - } - } - } - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: newBindSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Theme.outlineVariant - border.width: 1 - visible: keybindsTab.showingNewBind - - Column { - id: newBindSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "add" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("New Keybind") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - KeybindItem { - width: parent.width - isNew: true - isExpanded: true - bindData: ({ - keys: [ - { - key: "", - source: "dms", - isOverride: true - } - ], - action: "", - desc: "" - }) - panelWindow: keybindsTab.parentModal - onSaveBind: (originalKey, newData) => keybindsTab.saveNewBind(newData) - onCancelEdit: keybindsTab.cancelNewBind() - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: bindsListHeader.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: bindsListHeader - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "list" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (KeybindsService.loading) - return I18n.tr("Shortcuts"); - const count = keybindsTab._filteredBinds.length; - return count === 1 - ? I18n.tr("Shortcut (%1)").arg(count) - : I18n.tr("Shortcuts (%1)").arg(count); - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: KeybindsService.loading - - DankIcon { - id: loadingIcon - name: "sync" - size: 20 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - RotationAnimation on rotation { - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - running: KeybindsService.loading - } - } - - StyledText { - text: I18n.tr("Loading keybinds...") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("No keybinds found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !KeybindsService.loading && keybindsTab._filteredBinds.length === 0 - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - id: bindsRepeater - model: ScriptModel { - values: keybindsTab._filteredBinds - objectProp: "action" - } - - delegate: Item { - required property var modelData - required property int index - - width: parent.width - height: bindItem.height - - KeybindItem { - id: bindItem - width: Math.min(650, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - bindData: modelData - isExpanded: keybindsTab.expandedKey === modelData.action - panelWindow: keybindsTab.parentModal - onToggleExpand: keybindsTab.toggleExpanded(modelData.action) - onSaveBind: (originalKey, newData) => { - KeybindsService.saveBind(originalKey, newData); - keybindsTab._editingKey = newData.key; - keybindsTab.expandedKey = newData.action; - } - onRemoveBind: key => { - const remainingKey = bindItem.keys.find(k => k.key !== key)?.key ?? ""; - KeybindsService.removeBind(key); - keybindsTab._editingKey = remainingKey; - } - onIsExpandedChanged: { - if (!isExpanded || !keybindsTab._editingKey) - return; - const keyExists = keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - - onKeysChanged: { - if (!isExpanded || !keybindsTab._editingKey) - return; - const keyExists = keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - - Connections { - target: keybindsTab - function on_EditingKeyChanged() { - if (!bindItem.isExpanded || !keybindsTab._editingKey) - return; - const keyExists = bindItem.keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - bindItem.restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml deleted file mode 100644 index 8705d42..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml +++ /dev/null @@ -1,1306 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - FileBrowserModal { - id: logoFileBrowser - browserTitle: I18n.tr("Select Launcher Logo") - browserIcon: "image" - browserType: "generic" - filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"] - onFileSelected: path => SettingsData.set("launcherLogoCustomPath", path.replace("file://", "")) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Launcher Button Logo") - settingKey: "launcherLogo" - - StyledText { - width: parent.width - text: I18n.tr("Choose the logo displayed on the launcher button in DankBar") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Item { - width: parent.width - height: logoModeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: logoModeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: { - const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")]; - if (CompositorService.isNiri) { - modes.push("niri"); - } else if (CompositorService.isHyprland) { - modes.push("Hyprland"); - } else if (CompositorService.isDwl) { - modes.push("mango"); - } else if (CompositorService.isSway) { - modes.push("Sway"); - } else if (CompositorService.isScroll) { - modes.push("Scroll"); - } else if (CompositorService.isMiracle) { - modes.push("Miracle"); - } else { - modes.push(I18n.tr("Compositor")); - } - modes.push(I18n.tr("Custom")); - return modes; - } - currentIndex: { - if (SettingsData.launcherLogoMode === "apps") - return 0; - if (SettingsData.launcherLogoMode === "os") - return 1; - if (SettingsData.launcherLogoMode === "dank") - return 2; - if (SettingsData.launcherLogoMode === "compositor") - return 3; - if (SettingsData.launcherLogoMode === "custom") - return 4; - return 0; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("launcherLogoMode", "apps"); - break; - case 1: - SettingsData.set("launcherLogoMode", "os"); - break; - case 2: - SettingsData.set("launcherLogoMode", "dank"); - break; - case 3: - SettingsData.set("launcherLogoMode", "compositor"); - break; - case 4: - SettingsData.set("launcherLogoMode", "custom"); - break; - } - } - } - } - - Row { - width: parent.width - visible: SettingsData.launcherLogoMode === "custom" - spacing: Theme.spacingM - - StyledRect { - width: parent.width - selectButton.width - Theme.spacingM - height: 36 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: Theme.outlineStrong - border.width: 1 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: SettingsData.launcherLogoCustomPath || I18n.tr("Select an image file...") - font.pixelSize: Theme.fontSizeMedium - color: SettingsData.launcherLogoCustomPath ? Theme.surfaceText : Theme.outlineButton - width: parent.width - Theme.spacingM * 2 - elide: Text.ElideMiddle - } - } - - DankActionButton { - id: selectButton - iconName: "folder_open" - width: 36 - height: 36 - onClicked: logoFileBrowser.open() - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.launcherLogoMode !== "apps" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color Override") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: colorOverrideRow.implicitHeight - clip: true - - Row { - id: colorOverrideRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - DankButtonGroup { - id: colorModeGroup - buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.parent.width < 480 ? 44 : 64 - textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")] - currentIndex: { - const override = SettingsData.launcherLogoColorOverride; - if (override === "") - return 0; - if (override === "primary") - return 1; - if (override === "surface") - return 2; - return 3; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("launcherLogoColorOverride", ""); - break; - case 1: - SettingsData.set("launcherLogoColorOverride", "primary"); - break; - case 2: - SettingsData.set("launcherLogoColorOverride", "surface"); - break; - case 3: - const currentOverride = SettingsData.launcherLogoColorOverride; - const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface"; - if (isPreset) { - SettingsData.set("launcherLogoColorOverride", "#ffffff"); - } - break; - } - } - } - - Rectangle { - id: colorPickerCircle - visible: { - const override = SettingsData.launcherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - width: 36 - height: 36 - radius: 18 - color: { - const override = SettingsData.launcherLogoColorOverride; - if (override !== "" && override !== "primary" && override !== "surface") - return override; - return "#ffffff"; - } - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("launcherLogoColorOverride", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - - SettingsSliderRow { - settingKey: "launcherLogoSizeOffset" - tags: ["launcher", "logo", "size", "offset", "scale"] - text: I18n.tr("Size Offset") - minimum: -12 - maximum: 12 - value: SettingsData.launcherLogoSizeOffset - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoSizeOffset", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: { - const override = SettingsData.launcherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - - SettingsSliderRow { - settingKey: "launcherLogoBrightness" - tags: ["launcher", "logo", "brightness", "color"] - text: I18n.tr("Brightness") - minimum: 0 - maximum: 100 - value: Math.round(SettingsData.launcherLogoBrightness * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoBrightness", newValue / 100) - } - - SettingsSliderRow { - settingKey: "launcherLogoContrast" - tags: ["launcher", "logo", "contrast", "color"] - text: I18n.tr("Contrast") - minimum: 0 - maximum: 200 - value: Math.round(SettingsData.launcherLogoContrast * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoContrast", newValue / 100) - } - - SettingsToggleRow { - settingKey: "launcherLogoColorInvertOnMode" - tags: ["launcher", "logo", "invert", "mode", "color"] - text: I18n.tr("Invert on mode change") - checked: SettingsData.launcherLogoColorInvertOnMode - onToggled: checked => SettingsData.set("launcherLogoColorInvertOnMode", checked) - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "terminal" - title: I18n.tr("Launch Prefix") - settingKey: "launchPrefix" - - StyledText { - width: parent.width - text: I18n.tr("Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.launchPrefix - placeholderText: I18n.tr("Enter launch prefix (e.g., 'uwsm-app')") - onTextEdited: SettingsData.set("launchPrefix", text) - } - } - - SettingsCard { - width: parent.width - iconName: "sort_by_alpha" - title: I18n.tr("Sorting & Layout") - settingKey: "launcherSorting" - - SettingsToggleRow { - settingKey: "sortAppsAlphabetically" - tags: ["launcher", "sort", "alphabetically", "apps", "order"] - text: I18n.tr("Sort Alphabetically") - description: I18n.tr("When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.") - checked: SettingsData.sortAppsAlphabetically - onToggled: checked => SettingsData.set("sortAppsAlphabetically", checked) - } - - SettingsSliderRow { - settingKey: "appLauncherGridColumns" - tags: ["launcher", "grid", "columns", "layout"] - text: I18n.tr("Grid Columns") - description: I18n.tr("Adjust the number of columns in grid view mode.") - minimum: 2 - maximum: 8 - value: SettingsData.appLauncherGridColumns - defaultValue: 5 - onSliderValueChanged: newValue => SettingsData.set("appLauncherGridColumns", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Appearance", "launcher appearance settings") - settingKey: "dankLauncherV2Appearance" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Size", "launcher size option") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: sizeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: sizeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 400 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 400 ? 60 : 80 - textSize: parent.width < 400 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: ["1", "2", "3", "4"] - currentIndex: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 0; - case "compact": - return 1; - case "large": - return 3; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - var sizes = ["micro", "compact", "medium", "large"]; - SettingsData.set("dankLauncherV2Size", sizes[index]); - } - } - } - } - - SettingsToggleRow { - settingKey: "dankLauncherV2ShowFooter" - tags: ["launcher", "footer", "hints", "shortcuts"] - text: I18n.tr("Show Footer", "launcher footer visibility") - description: I18n.tr("Show mode tabs and keyboard hints at the bottom.", "launcher footer description") - checked: SettingsData.dankLauncherV2ShowFooter - enabled: SettingsData.dankLauncherV2Size !== "micro" - onToggled: checked => SettingsData.set("dankLauncherV2ShowFooter", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2UnloadOnClose" - tags: ["launcher", "unload", "close", "memory", "vram"] - text: I18n.tr("Unload on Close") - description: I18n.tr("Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.") - checked: SettingsData.dankLauncherV2UnloadOnClose - onToggled: checked => SettingsData.set("dankLauncherV2UnloadOnClose", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2BorderEnabled" - tags: ["launcher", "border", "outline"] - text: I18n.tr("Border", "launcher border option") - checked: SettingsData.dankLauncherV2BorderEnabled - onToggled: checked => SettingsData.set("dankLauncherV2BorderEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.dankLauncherV2BorderEnabled - - SettingsSliderRow { - settingKey: "dankLauncherV2BorderThickness" - tags: ["launcher", "border", "thickness"] - text: I18n.tr("Thickness", "border thickness") - minimum: 1 - maximum: 6 - value: SettingsData.dankLauncherV2BorderThickness - defaultValue: 2 - unit: "px" - onSliderValueChanged: newValue => SettingsData.set("dankLauncherV2BorderThickness", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Color", "border color") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: borderColorGroup.implicitHeight - clip: true - - DankButtonGroup { - id: borderColorGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 400 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 400 ? 50 : 70 - textSize: parent.width < 400 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Primary", "primary color"), I18n.tr("Secondary", "secondary color"), I18n.tr("Outline", "outline color"), I18n.tr("Text", "text color")] - currentIndex: SettingsData.dankLauncherV2BorderColor === "secondary" ? 1 : SettingsData.dankLauncherV2BorderColor === "outline" ? 2 : SettingsData.dankLauncherV2BorderColor === "surfaceText" ? 3 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("dankLauncherV2BorderColor", index === 1 ? "secondary" : index === 2 ? "outline" : index === 3 ? "surfaceText" : "primary"); - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "open_in_new" - title: I18n.tr("Niri Integration").replace("Niri", "niri") - visible: CompositorService.isNiri - - SettingsToggleRow { - settingKey: "spotlightCloseNiriOverview" - tags: ["launcher", "niri", "overview", "close", "launch"] - text: I18n.tr("Close Overview on Launch") - description: I18n.tr("Auto-close Niri overview when launching apps.") - checked: SettingsData.spotlightCloseNiriOverview - onToggled: checked => SettingsData.set("spotlightCloseNiriOverview", checked) - } - - SettingsToggleRow { - settingKey: "niriOverviewOverlayEnabled" - tags: ["launcher", "niri", "overview", "overlay", "enable"] - text: I18n.tr("Enable Overview Overlay") - description: I18n.tr("Show launcher overlay when typing in Niri overview. Disable to use another launcher.") - checked: SettingsData.niriOverviewOverlayEnabled - onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked) - } - } - - SettingsCard { - id: builtInPluginsCard - width: parent.width - iconName: "extension" - title: "DMS" - settingKey: "builtInPlugins" - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ["dms_settings", "dms_notepad", "dms_sysmon", "dms_settings_search"] - - delegate: Rectangle { - id: pluginDelegate - required property string modelData - required property int index - readonly property var plugin: AppSearchService.builtInPlugins[modelData] - - width: parent.width - height: 56 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: pluginDelegate.plugin?.cornerIcon ?? "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: pluginDelegate.plugin?.name ?? pluginDelegate.modelData - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: pluginDelegate.plugin?.comment ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankTextField { - id: triggerField - width: 60 - visible: pluginDelegate.plugin?.isLauncher === true - anchors.verticalCenter: parent.verticalCenter - placeholderText: I18n.tr("Trigger") - onTextEdited: SettingsData.setBuiltInPluginSetting(pluginDelegate.modelData, "trigger", text) - Component.onCompleted: text = SettingsData.getBuiltInPluginSetting(pluginDelegate.modelData, "trigger", pluginDelegate.plugin?.defaultTrigger ?? "") - } - - DankToggle { - id: enableToggle - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.getBuiltInPluginSetting(pluginDelegate.modelData, "enabled", true) - onToggled: SettingsData.setBuiltInPluginSetting(pluginDelegate.modelData, "enabled", checked) - } - } - } - } - } - } - - SettingsCard { - id: pluginVisibilityCard - width: parent.width - iconName: "filter_list" - title: I18n.tr("Plugin Visibility") - settingKey: "pluginVisibility" - - property var allLauncherPlugins: { - SettingsData.launcherPluginVisibility; - SettingsData.launcherPluginOrder; - SettingsData.dankLauncherV2IncludeFilesInAll; - SettingsData.dankLauncherV2IncludeFoldersInAll; - var plugins = []; - var builtIn = AppSearchService.getBuiltInLauncherPlugins() || {}; - for (var pluginId in builtIn) { - var plugin = builtIn[pluginId]; - plugins.push({ - id: pluginId, - name: plugin.name || pluginId, - icon: plugin.cornerIcon || "extension", - iconType: "material", - isBuiltIn: true, - isVirtual: false, - trigger: AppSearchService.getBuiltInPluginTrigger(pluginId) || "" - }); - } - var thirdParty = PluginService.getLauncherPlugins() || {}; - for (var pluginId in thirdParty) { - var plugin = thirdParty[pluginId]; - var rawIcon = plugin.icon || "extension"; - plugins.push({ - id: pluginId, - name: plugin.name || pluginId, - icon: rawIcon.startsWith("material:") ? rawIcon.substring(9) : rawIcon.startsWith("unicode:") ? rawIcon.substring(8) : rawIcon, - iconType: rawIcon.startsWith("unicode:") ? "unicode" : "material", - isBuiltIn: false, - isVirtual: false, - trigger: PluginService.getPluginTrigger(pluginId) || "" - }); - } - if (SettingsData.dankLauncherV2IncludeFilesInAll) { - plugins.push({ - id: "__files", - name: I18n.tr("Files"), - icon: "insert_drive_file", - iconType: "material", - isBuiltIn: false, - isVirtual: true, - trigger: "/" - }); - } - if (SettingsData.dankLauncherV2IncludeFoldersInAll) { - plugins.push({ - id: "__folders", - name: I18n.tr("Folders"), - icon: "folder", - iconType: "material", - isBuiltIn: false, - isVirtual: true, - trigger: "/" - }); - } - return SettingsData.getOrderedLauncherPlugins(plugins); - } - - function reorderPlugin(fromIndex, toIndex) { - if (fromIndex === toIndex) - return; - var currentOrder = allLauncherPlugins.map(p => p.id); - var item = currentOrder.splice(fromIndex, 1)[0]; - currentOrder.splice(toIndex, 0, item); - SettingsData.setLauncherPluginOrder(currentOrder); - } - - StyledText { - width: parent.width - text: I18n.tr("Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: pluginVisibilityColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: pluginVisibilityCard.allLauncherPlugins - - delegate: Item { - id: visibilityDelegateItem - required property var modelData - required property int index - - property bool held: pluginDragArea.pressed - property real originalY: y - - width: pluginVisibilityColumn.width - height: 52 - z: held ? 2 : 1 - - Rectangle { - id: visibilityDelegate - width: parent.width - height: 52 - radius: Theme.cornerRadius - color: visibilityDelegateItem.held ? Theme.surfaceHover : Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - - Row { - anchors.left: parent.left - anchors.leftMargin: 28 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Item { - width: Theme.iconSize - height: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - visible: visibilityDelegateItem.modelData.iconType !== "unicode" - name: visibilityDelegateItem.modelData.icon - size: Theme.iconSize - color: Theme.primary - } - - StyledText { - anchors.centerIn: parent - visible: visibilityDelegateItem.modelData.iconType === "unicode" - text: visibilityDelegateItem.modelData.icon - font.pixelSize: Theme.iconSize - color: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Row { - spacing: Theme.spacingS - - StyledText { - text: visibilityDelegateItem.modelData.name - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Rectangle { - visible: visibilityDelegateItem.modelData.isBuiltIn - width: dmsBadgeLabel.implicitWidth + Theme.spacingS - height: 16 - radius: 8 - color: Theme.primaryContainer - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: dmsBadgeLabel - anchors.centerIn: parent - text: "DMS" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - - StyledText { - text: visibilityDelegateItem.modelData.trigger ? I18n.tr("Trigger: %1").arg(visibilityDelegateItem.modelData.trigger) : I18n.tr("No trigger") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankToggle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - checked: { - switch (visibilityDelegateItem.modelData.id) { - case "__files": - return SettingsData.dankLauncherV2IncludeFilesInAll; - case "__folders": - return SettingsData.dankLauncherV2IncludeFoldersInAll; - default: - return SettingsData.getPluginAllowWithoutTrigger(visibilityDelegateItem.modelData.id); - } - } - onToggled: function (isChecked) { - switch (visibilityDelegateItem.modelData.id) { - case "__files": - SettingsData.set("dankLauncherV2IncludeFilesInAll", isChecked); - break; - case "__folders": - SettingsData.set("dankLauncherV2IncludeFoldersInAll", isChecked); - break; - default: - SettingsData.setPluginAllowWithoutTrigger(visibilityDelegateItem.modelData.id, isChecked); - } - } - } - } - - MouseArea { - id: pluginDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 28 - height: parent.height - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: visibilityDelegateItem.held ? visibilityDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - visibilityDelegateItem.originalY = visibilityDelegateItem.y; - } - - onReleased: { - if (!drag.active) { - visibilityDelegateItem.y = visibilityDelegateItem.originalY; - return; - } - const spacing = Theme.spacingS; - const itemH = visibilityDelegateItem.height + spacing; - var newIndex = Math.round(visibilityDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, pluginVisibilityCard.allLauncherPlugins.length - 1)); - pluginVisibilityCard.reorderPlugin(visibilityDelegateItem.index, newIndex); - visibilityDelegateItem.y = visibilityDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: pluginDragArea.containsMouse || pluginDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !pluginDragArea.pressed && !pluginDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No launcher plugins installed.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: pluginVisibilityCard.allLauncherPlugins.length === 0 - } - } - } - - SettingsCard { - width: parent.width - iconName: "search" - title: I18n.tr("Search Options") - settingKey: "searchOptions" - - SettingsToggleRow { - settingKey: "searchAppActions" - tags: ["launcher", "search", "actions", "shortcuts"] - text: I18n.tr("Search App Actions") - description: I18n.tr("Include desktop actions (shortcuts) in search results.") - checked: SessionData.searchAppActions - onToggled: checked => SessionData.setSearchAppActions(checked) - } - - SettingsToggleRow { - settingKey: "rememberLastQuery" - tags: ["launcher", "remember", "last", "search", "query"] - text: I18n.tr("Remember Last Query") - description: I18n.tr("Autofill last remembered query when opened") - checked: SettingsData.rememberLastQuery - onToggled: checked => SettingsData.set("rememberLastQuery", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2IncludeFilesInAll" - tags: ["launcher", "files", "dsearch", "all", "results", "indexed"] - text: I18n.tr("Include Files in All Tab") - description: I18n.tr("Merge indexed file results into the All tab (requires dsearch).") - checked: SettingsData.dankLauncherV2IncludeFilesInAll - onToggled: checked => SettingsData.set("dankLauncherV2IncludeFilesInAll", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2IncludeFoldersInAll" - tags: ["launcher", "folders", "dirs", "dsearch", "all", "results", "indexed"] - text: I18n.tr("Include Folders in All Tab") - description: I18n.tr("Merge indexed folder results into the All tab (requires dsearch).") - checked: SettingsData.dankLauncherV2IncludeFoldersInAll - onToggled: checked => SettingsData.set("dankLauncherV2IncludeFoldersInAll", checked) - } - } - - SettingsCard { - id: hiddenAppsCard - width: parent.width - iconName: "visibility_off" - title: I18n.tr("Hidden Apps") - settingKey: "hiddenApps" - - property var hiddenAppsModel: { - SessionData.hiddenApps; - const apps = []; - const allApps = AppSearchService.applications || []; - for (const hiddenId of SessionData.hiddenApps) { - const app = allApps.find(a => (a.id || a.execString || a.exec) === hiddenId); - if (app) { - apps.push({ - id: hiddenId, - name: app.name || hiddenId, - icon: app.icon || "", - comment: app.comment || "" - }); - } else { - apps.push({ - id: hiddenId, - name: hiddenId, - icon: "", - comment: "" - }); - } - } - return apps.sort((a, b) => a.name.localeCompare(b.name)); - } - - StyledText { - width: parent.width - text: I18n.tr("Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: hiddenAppsList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: hiddenAppsCard.hiddenAppsModel - - delegate: Rectangle { - width: hiddenAppsList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: modelData.comment || modelData.id - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "visibility" - iconSize: 18 - iconColor: Theme.primary - onClicked: SessionData.showApp(modelData.id) - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No hidden apps.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: hiddenAppsCard.hiddenAppsModel.length === 0 - } - } - } - - SettingsCard { - id: appOverridesCard - width: parent.width - iconName: "edit" - title: I18n.tr("App Customizations") - settingKey: "appOverrides" - - property var overridesModel: { - SessionData.appOverrides; - const items = []; - const allApps = AppSearchService.applications || []; - for (const appId in SessionData.appOverrides) { - const override = SessionData.appOverrides[appId]; - const app = allApps.find(a => (a.id || a.execString || a.exec) === appId); - items.push({ - id: appId, - name: override.name || app?.name || appId, - originalName: app?.name || appId, - icon: override.icon || app?.icon || "", - hasOverride: true - }); - } - return items.sort((a, b) => a.name.localeCompare(b.name)); - } - - StyledText { - width: parent.width - text: I18n.tr("Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: overridesList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: appOverridesCard.overridesModel - - delegate: Rectangle { - width: overridesList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: modelData.originalName !== modelData.name ? modelData.originalName : modelData.id - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "delete" - iconSize: 18 - iconColor: Theme.error - onClicked: SessionData.clearAppOverride(modelData.id) - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No app customizations.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: appOverridesCard.overridesModel.length === 0 - } - } - } - - SettingsCard { - id: recentAppsCard - width: parent.width - iconName: "history" - title: I18n.tr("Recently Used Apps") - settingKey: "recentApps" - collapsible: true - expanded: false - - property var rankedAppsModel: { - var ranking = AppUsageHistoryData.appUsageRanking; - if (!ranking) - return []; - var apps = []; - for (var appId in ranking) { - var appData = ranking[appId]; - apps.push({ - "id": appId, - "name": appData.name, - "exec": appData.exec, - "icon": appData.icon, - "comment": appData.comment, - "usageCount": appData.usageCount, - "lastUsed": appData.lastUsed - }); - } - apps.sort(function (a, b) { - if (a.usageCount !== b.usageCount) - return b.usageCount - a.usageCount; - return a.name.localeCompare(b.name); - }); - return apps.slice(0, 20); - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - clearAllButton.width - Theme.spacingM - text: I18n.tr("Apps are ordered by usage frequency, then last used, then alphabetically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - id: clearAllButton - iconName: "delete_sweep" - iconSize: Theme.iconSize - 2 - iconColor: Theme.error - anchors.verticalCenter: parent.verticalCenter - onClicked: { - AppUsageHistoryData.appUsageRanking = {}; - AppUsageHistoryData.saveSettings(); - } - } - } - - Column { - id: rankedAppsList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: recentAppsCard.rankedAppsModel - - delegate: Rectangle { - width: rankedAppsList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: (index + 1).toString() - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - width: 20 - anchors.verticalCenter: parent.verticalCenter - } - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name || I18n.tr("Unknown App") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: { - if (!modelData.lastUsed) - return I18n.tr("Never used"); - var date = new Date(modelData.lastUsed); - var now = new Date(); - var diffMs = now - date; - var diffMins = Math.floor(diffMs / (1000 * 60)); - var diffHours = Math.floor(diffMs / (1000 * 60 * 60)); - var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); - if (diffMins < 1) - return I18n.tr("Last launched just now"); - if (diffMins < 60) - return diffMins === 1 ? I18n.tr("Last launched %1 minute ago").arg(diffMins) : I18n.tr("Last launched %1 minutes ago").arg(diffMins); - if (diffHours < 24) - return diffHours === 1 ? I18n.tr("Last launched %1 hour ago").arg(diffHours) : I18n.tr("Last launched %1 hours ago").arg(diffHours); - if (diffDays < 7) - return diffDays === 1 ? I18n.tr("Last launched %1 day ago").arg(diffDays) : I18n.tr("Last launched %1 days ago").arg(diffDays); - return I18n.tr("Last launched %1").arg(date.toLocaleDateString()); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - circular: true - iconName: "close" - iconSize: 16 - iconColor: Theme.error - onClicked: { - var currentRanking = Object.assign({}, AppUsageHistoryData.appUsageRanking || {}); - delete currentRanking[modelData.id]; - AppUsageHistoryData.appUsageRanking = currentRanking; - AppUsageHistoryData.saveSettings(); - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No apps have been launched yet.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: recentAppsCard.rankedAppsModel.length === 0 - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml deleted file mode 100644 index d4f7f5e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml +++ /dev/null @@ -1,91 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: localeTab - - readonly property string _systemDefaultLabel: I18n.tr("System Default") - - function _localeDisplayName(localeCode) { - if (!I18n.presentLocales[localeCode]) - return; - const nativeName = I18n.presentLocales[localeCode].nativeLanguageName; - return nativeName[0].toUpperCase() + nativeName.slice(1); - } - - function _allLocaleOptions() { - return [_systemDefaultLabel].concat(Object.keys(I18n.presentLocales).map(_localeDisplayName)); - } - - function _codeForDisplayName(displayName) { - if (displayName === _systemDefaultLabel) - return ""; - for (const code of Object.keys(I18n.presentLocales)) { - if (_localeDisplayName(code) === displayName) - return code; - } - return ""; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "locale" - tags: ["locale", "language", "country"] - title: I18n.tr("Locale Settings") - iconName: "language" - - SettingsDropdownRow { - id: localeDropdown - tab: "locale" - tags: ["locale", "language", "country"] - settingKey: "locale" - text: I18n.tr("Current Locale") - description: I18n.tr("Change the locale used by the DMS interface.") - options: localeTab._allLocaleOptions() - enableFuzzySearch: true - - Component.onCompleted: { - currentValue = SessionData.locale ? localeTab._localeDisplayName(SessionData.locale) : localeTab._systemDefaultLabel; - } - - onValueChanged: value => { - SessionData.set("locale", localeTab._codeForDisplayName(value)); - } - } - - SettingsDropdownRow { - id: timeLocaleDropdown - tab: "locale" - tags: ["locale", "time", "date", "format", "region"] - settingKey: "timeLocale" - text: I18n.tr("Time & Date Locale") - description: I18n.tr("Change the locale used for date and time formatting, independent of the interface language.") - options: localeTab._allLocaleOptions() - enableFuzzySearch: true - - Component.onCompleted: { - currentValue = SessionData.timeLocale ? localeTab._localeDisplayName(SessionData.timeLocale) : localeTab._systemDefaultLabel; - } - - onValueChanged: value => { - SessionData.set("timeLocale", localeTab._codeForDisplayName(value)); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml deleted file mode 100644 index d86589c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml +++ /dev/null @@ -1,458 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property bool lockFprintToggleAvailable: SettingsData.lockFingerprintCanEnable || SettingsData.enableFprint - readonly property bool lockU2fToggleAvailable: SettingsData.lockU2fCanEnable || SettingsData.enableU2f - - function lockFingerprintDescription() { - switch (SettingsData.lockFingerprintReason) { - case "ready": - return SettingsData.enableFprint ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Use fingerprint authentication for the lock screen."); - case "missing_enrollment": - if (SettingsData.enableFprint) - return I18n.tr("Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints."); - return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later."); - case "missing_reader": - return SettingsData.enableFprint ? I18n.tr("Enabled, but no fingerprint reader was detected.") : I18n.tr("No fingerprint reader detected."); - case "missing_pam_support": - return I18n.tr("Not available — install fprintd and pam_fprintd."); - default: - return SettingsData.enableFprint ? I18n.tr("Enabled, but fingerprint availability could not be confirmed.") : I18n.tr("Fingerprint availability could not be confirmed."); - } - } - - function lockU2fDescription() { - switch (SettingsData.lockU2fReason) { - case "ready": - return SettingsData.enableU2f ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Use a security key for lock screen authentication.", "lock screen U2F security key setting"); - case "missing_key_registration": - if (SettingsData.enableU2f) - return I18n.tr("Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated."); - return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later."); - case "missing_pam_support": - return I18n.tr("Not available — install or configure pam_u2f."); - default: - return SettingsData.enableU2f ? I18n.tr("Enabled, but security-key availability could not be confirmed.") : I18n.tr("Security-key availability could not be confirmed."); - } - } - - function refreshAuthDetection() { - SettingsData.refreshAuthAvailability(); - } - - Component.onCompleted: refreshAuthDetection() - onVisibleChanged: { - if (visible) - refreshAuthDetection(); - } - - FileBrowserModal { - id: videoBrowserModal - browserTitle: I18n.tr("Select Video or Folder") - browserIcon: "movie" - browserType: "video" - showHiddenFiles: false - fileExtensions: ["*.mp4", "*.mkv", "*.webm", "*.mov", "*.avi", "*.m4v"] - onFileSelected: path => SettingsData.set("lockScreenVideoPath", path) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen layout") - settingKey: "lockLayout" - - SettingsToggleRow { - settingKey: "lockScreenShowPowerActions" - tags: ["lock", "screen", "power", "actions", "shutdown", "reboot"] - text: I18n.tr("Show Power Actions", "Enable power action icon on the lock screen window") - checked: SettingsData.lockScreenShowPowerActions - onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowSystemIcons" - tags: ["lock", "screen", "system", "icons", "status"] - text: I18n.tr("Show System Icons", "Enable system status icons on the lock screen window") - checked: SettingsData.lockScreenShowSystemIcons - onToggled: checked => SettingsData.set("lockScreenShowSystemIcons", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowTime" - tags: ["lock", "screen", "time", "clock", "display"] - text: I18n.tr("Show System Time", "Enable system time display on the lock screen window") - checked: SettingsData.lockScreenShowTime - onToggled: checked => SettingsData.set("lockScreenShowTime", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowDate" - tags: ["lock", "screen", "date", "calendar", "display"] - text: I18n.tr("Show System Date", "Enable system date display on the lock screen window") - checked: SettingsData.lockScreenShowDate - onToggled: checked => SettingsData.set("lockScreenShowDate", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowProfileImage" - tags: ["lock", "screen", "profile", "image", "avatar", "picture"] - text: I18n.tr("Show Profile Image", "Enable profile image display on the lock screen window") - checked: SettingsData.lockScreenShowProfileImage - onToggled: checked => SettingsData.set("lockScreenShowProfileImage", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowPasswordField" - tags: ["lock", "screen", "password", "field", "input", "visible"] - text: I18n.tr("Show Password Field", "Enable password field display on the lock screen window") - description: I18n.tr("If the field is hidden, it will appear as soon as a key is pressed.") - checked: SettingsData.lockScreenShowPasswordField - onToggled: checked => SettingsData.set("lockScreenShowPasswordField", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowMediaPlayer" - tags: ["lock", "screen", "media", "player", "music", "mpris"] - text: I18n.tr("Show Media Player", "Enable media player controls on the lock screen window") - checked: SettingsData.lockScreenShowMediaPlayer - onToggled: checked => SettingsData.set("lockScreenShowMediaPlayer", checked) - } - - SettingsDropdownRow { - settingKey: "lockScreenNotificationMode" - tags: ["lock", "screen", "notification", "notifications", "privacy"] - text: I18n.tr("Notification Display", "lock screen notification privacy setting") - description: I18n.tr("Control what notification information is shown on the lock screen", "lock screen notification privacy setting") - options: [I18n.tr("Disabled", "lock screen notification mode option"), I18n.tr("Count Only", "lock screen notification mode option"), I18n.tr("App Names", "lock screen notification mode option"), I18n.tr("Full Content", "lock screen notification mode option")] - currentValue: options[SettingsData.lockScreenNotificationMode] || options[0] - onValueChanged: value => { - const idx = options.indexOf(value); - if (idx >= 0) { - SettingsData.set("lockScreenNotificationMode", idx); - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen behaviour") - settingKey: "lockBehavior" - - StyledText { - text: I18n.tr("loginctl not available - lock integration requires DMS socket connection") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - visible: !SessionService.loginctlAvailable - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "loginctlLockIntegration" - tags: ["lock", "screen", "loginctl", "dbus", "integration", "external"] - text: I18n.tr("Enable loginctl lock integration") - description: I18n.tr("Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen") - checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - enabled: SessionService.loginctlAvailable - onToggled: checked => { - if (!SessionService.loginctlAvailable) - return; - SettingsData.set("loginctlLockIntegration", checked); - } - } - - SettingsToggleRow { - settingKey: "lockBeforeSuspend" - tags: ["lock", "screen", "suspend", "sleep", "automatic"] - text: I18n.tr("Lock before suspend") - description: I18n.tr("Automatically lock the screen when the system prepares to suspend") - checked: SettingsData.lockBeforeSuspend - visible: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - onToggled: checked => SettingsData.set("lockBeforeSuspend", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenPowerOffMonitorsOnLock" - tags: ["lock", "screen", "monitor", "display", "dpms", "power"] - text: I18n.tr("Power off monitors on lock") - description: I18n.tr("Turn off all displays immediately when the lock screen activates") - checked: SettingsData.lockScreenPowerOffMonitorsOnLock - onToggled: checked => SettingsData.set("lockScreenPowerOffMonitorsOnLock", checked) - } - - SettingsToggleRow { - settingKey: "lockAtStartup" - tags: ["lock", "screen", "startup", "start", "boot", "login", "automatic"] - text: I18n.tr("Lock at startup") - description: I18n.tr("Automatically lock the screen when DMS starts") - checked: SettingsData.lockAtStartup - onToggled: checked => SettingsData.set("lockAtStartup", checked) - } - - StyledText { - text: I18n.tr("Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - topPadding: Theme.spacingS - } - - SettingsToggleRow { - settingKey: "enableFprint" - tags: ["lock", "screen", "fingerprint", "authentication", "biometric", "fprint"] - text: I18n.tr("Enable fingerprint authentication") - description: root.lockFingerprintDescription() - descriptionColor: SettingsData.lockFingerprintReason === "ready" ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.enableFprint - enabled: root.lockFprintToggleAvailable - onToggled: checked => SettingsData.set("enableFprint", checked) - } - - SettingsToggleRow { - settingKey: "enableU2f" - tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "fido", "authentication", "hardware"] - text: I18n.tr("Enable security key authentication", "Enable FIDO2/U2F hardware security key for lock screen") - description: root.lockU2fDescription() - descriptionColor: SettingsData.lockU2fReason === "ready" ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.enableU2f - enabled: root.lockU2fToggleAvailable - onToggled: checked => SettingsData.set("enableU2f", checked) - } - - SettingsDropdownRow { - settingKey: "u2fMode" - tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "mode", "factor", "second"] - text: I18n.tr("Security key mode", "lock screen U2F security key mode setting") - description: I18n.tr("'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.", "lock screen U2F security key mode setting") - visible: SettingsData.enableU2f - options: [I18n.tr("Alternative (OR)", "U2F mode option: key works as standalone unlock method"), I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint")] - currentValue: SettingsData.u2fMode === "and" ? I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint") : I18n.tr("Alternative (OR)", "U2F mode option: key works as standalone unlock method") - onValueChanged: value => { - if (value === I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint")) - SettingsData.set("u2fMode", "and"); - else - SettingsData.set("u2fMode", "or"); - } - } - } - - SettingsCard { - width: parent.width - iconName: "movie" - title: I18n.tr("Video Screensaver") - settingKey: "videoScreensaver" - - StyledText { - visible: !MultimediaService.available - text: I18n.tr("QtMultimedia is not available - video screensaver requires qt multimedia services") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - width: parent.width - wrapMode: Text.WordWrap - } - - SettingsToggleRow { - settingKey: "lockScreenVideoEnabled" - tags: ["lock", "screen", "video", "screensaver", "animation", "movie"] - text: I18n.tr("Enable Video Screensaver") - description: I18n.tr("Play a video when the screen locks.") - enabled: MultimediaService.available - checked: SettingsData.lockScreenVideoEnabled - onToggled: checked => SettingsData.set("lockScreenVideoEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: SettingsData.lockScreenVideoEnabled && MultimediaService.available - - StyledText { - text: I18n.tr("Video Path") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("Path to a video file or folder containing videos") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outlineVariant - wrapMode: Text.WordWrap - width: parent.width - } - - Row { - width: parent.width - spacing: Theme.spacingS - - DankTextField { - id: videoPathField - width: parent.width - browseVideoButton.width - Theme.spacingS - placeholderText: I18n.tr("/path/to/videos") - text: SettingsData.lockScreenVideoPath - backgroundColor: Theme.surfaceContainerHighest - onTextChanged: { - if (text !== SettingsData.lockScreenVideoPath) { - SettingsData.set("lockScreenVideoPath", text); - } - } - } - - DankButton { - id: browseVideoButton - text: I18n.tr("Browse") - onClicked: videoBrowserModal.open() - } - } - } - - SettingsToggleRow { - settingKey: "lockScreenVideoCycling" - tags: ["lock", "screen", "video", "screensaver", "cycling", "random", "shuffle"] - text: I18n.tr("Automatic Cycling") - description: I18n.tr("Pick a different random video each time from the same folder") - visible: SettingsData.lockScreenVideoEnabled && MultimediaService.available - enabled: MultimediaService.available - checked: SettingsData.lockScreenVideoCycling - onToggled: checked => SettingsData.set("lockScreenVideoCycling", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "monitor" - title: I18n.tr("Lock Screen Display") - settingKey: "lockDisplay" - visible: Quickshell.screens.length > 1 - - StyledText { - text: I18n.tr("Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsDropdownRow { - id: lockScreenMonitorDropdown - settingKey: "lockScreenActiveMonitor" - tags: ["lock", "screen", "monitor", "display", "active"] - text: I18n.tr("Active Lock Screen Monitor") - options: { - var opts = [I18n.tr("All Monitors")]; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - opts.push(SettingsData.getScreenDisplayName(screens[i])); - } - return opts; - } - - Component.onCompleted: { - if (SettingsData.lockScreenActiveMonitor === "all") { - currentValue = I18n.tr("All Monitors"); - return; - } - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === SettingsData.lockScreenActiveMonitor) { - currentValue = SettingsData.getScreenDisplayName(screens[i]); - return; - } - } - currentValue = I18n.tr("All Monitors"); - } - - onValueChanged: value => { - if (value === I18n.tr("All Monitors")) { - SettingsData.set("lockScreenActiveMonitor", "all"); - return; - } - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === value) { - SettingsData.set("lockScreenActiveMonitor", screens[i].name); - return; - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.lockScreenActiveMonitor !== "all" - - Column { - width: parent.width - inactiveColorPreview.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Inactive Monitor Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Color displayed on monitors without the lock screen") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - } - - Rectangle { - id: inactiveColorPreview - width: 48 - height: 48 - radius: Theme.cornerRadius - color: SettingsData.lockScreenInactiveColor - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.lockScreenInactiveColor; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Inactive Monitor Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("lockScreenInactiveColor", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml deleted file mode 100644 index a844a86..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml +++ /dev/null @@ -1,119 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "music_note" - title: I18n.tr("Media Player Settings") - settingKey: "mediaPlayer" - - SettingsToggleRow { - text: I18n.tr("Wave Progress Bars") - description: I18n.tr("Use animated wave progress bars for media playback") - checked: SettingsData.waveProgressEnabled - onToggled: checked => SettingsData.set("waveProgressEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Scroll song title") - description: I18n.tr("Scroll title if it doesn't fit in widget") - checked: SettingsData.scrollTitleEnabled - onToggled: checked => SettingsData.set("scrollTitleEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Audio Visualizer") - description: I18n.tr("Show cava audio visualizer in media widget") - checked: SettingsData.audioVisualizerEnabled - onToggled: checked => SettingsData.set("audioVisualizerEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Adaptive Media Width") - description: I18n.tr("Shrink the media widget to fit shorter song titles while still respecting the configured maximum size") - checked: SettingsData.mediaAdaptiveWidthEnabled - onToggled: checked => SettingsData.set("mediaAdaptiveWidthEnabled", checked) - } - - SettingsDropdownRow { - property var scrollOptsInternal: ["volume", "song", "nothing"] - property var scrollOptsDisplay: [I18n.tr("Change Volume", "media scroll wheel option"), I18n.tr("Change Song", "media scroll wheel option"), I18n.tr("Nothing", "media scroll wheel option")] - - text: I18n.tr("Scroll Wheel") - description: I18n.tr("Scroll wheel behavior on media widget") - settingKey: "audioScrollMode" - tags: ["media", "music", "scroll"] - options: scrollOptsDisplay - currentValue: { - const idx = scrollOptsInternal.indexOf(SettingsData.audioScrollMode); - return idx >= 0 ? scrollOptsDisplay[idx] : scrollOptsDisplay[0]; - } - onValueChanged: value => { - const idx = scrollOptsDisplay.indexOf(value); - if (idx >= 0) - SettingsData.set("audioScrollMode", scrollOptsInternal[idx]); - } - } - - Item { - width: parent.width - height: audioWheelScrollAmountColumn.height - visible: SettingsData.audioScrollMode == "volume" - opacity: visible ? 1 : 0 - - Column { - id: audioWheelScrollAmountColumn - x: Theme.spacingL - width: 120 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Adjust volume per scroll indent") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: 100 - height: 28 - placeholderText: "5" - text: SettingsData.audioWheelScrollAmount - maximumLength: 2 - font.pixelSize: Theme.fontSizeSmall - topPadding: Theme.spacingXS - bottomPadding: Theme.spacingXS - onEditingFinished: SettingsData.set("audioWheelScrollAmount", parseInt(text, 10)) - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml deleted file mode 100644 index a82cdbe..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml +++ /dev/null @@ -1,112 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property var muxTypeOptions: [ - "tmux", - "zellij" - ] - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "mux" - tags: ["mux", "multiplexer", "tmux", "zellij", "type"] - title: I18n.tr("Multiplexer") - iconName: "terminal" - - SettingsDropdownRow { - tab: "mux" - tags: ["mux", "multiplexer", "tmux", "zellij", "type", "backend"] - settingKey: "muxType" - text: I18n.tr("Multiplexer Type") - description: I18n.tr("Terminal multiplexer backend to use") - options: root.muxTypeOptions - currentValue: SettingsData.muxType - onValueChanged: value => SettingsData.set("muxType", value) - } - } - - SettingsCard { - tab: "mux" - tags: ["mux", "terminal", "custom", "command", "script"] - title: I18n.tr("Terminal") - iconName: "desktop_windows" - - SettingsToggleRow { - tab: "mux" - tags: ["mux", "custom", "command", "override"] - settingKey: "muxUseCustomCommand" - text: I18n.tr("Use Custom Command") - description: I18n.tr("Override terminal with a custom command or script") - checked: SettingsData.muxUseCustomCommand - onToggled: checked => SettingsData.set("muxUseCustomCommand", checked) - } - - Column { - width: parent?.width ?? 0 - spacing: Theme.spacingS - visible: SettingsData.muxUseCustomCommand - - StyledText { - width: parent.width - text: I18n.tr("The custom command used when attaching to sessions (receives the session name as the first argument)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.muxCustomCommand - placeholderText: I18n.tr("Enter command or script path") - onTextEdited: SettingsData.set("muxCustomCommand", text) - } - } - } - - SettingsCard { - tab: "mux" - tags: ["mux", "session", "filter", "exclude", "hide"] - title: I18n.tr("Session Filter") - iconName: "filter_list" - - Column { - width: parent?.width ?? 0 - spacing: Theme.spacingS - - StyledText { - width: parent.width - text: I18n.tr("Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.muxSessionFilter - placeholderText: I18n.tr("e.g., scratch, /^tmp_.*/, build") - onTextEdited: SettingsData.set("muxSessionFilter", text) - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml deleted file mode 100644 index b9b2566..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml +++ /dev/null @@ -1,1999 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -Item { - id: networkTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string expandedVpnUuid: "" - property string expandedWifiSsid: "" - property string expandedEthDevice: "" - property int maxPinnedWifiNetworks: 3 - - Component.onCompleted: { - NetworkService.addRef(); - } - - Component.onDestruction: { - NetworkService.removeRef(); - } - - function openVpnFileBrowser() { - vpnFileBrowserLoader.active = true; - if (vpnFileBrowserLoader.item) - vpnFileBrowserLoader.item.open(); - } - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v) - if (typeof value === "string" && value.length > 0) - return [value] - return [] - } - - function getPinnedWifiNetworks() { - const pins = SettingsData.wifiNetworkPins || {} - return normalizePinList(pins["preferredWifi"]) - } - - function toggleWifiPin(ssid) { - const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {})) - let pinnedList = normalizePinList(pins["preferredWifi"]) - const pinIndex = pinnedList.indexOf(ssid) - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1) - } else { - pinnedList.unshift(ssid) - if (pinnedList.length > maxPinnedWifiNetworks) - pinnedList = pinnedList.slice(0, maxPinnedWifiNetworks) - } - - if (pinnedList.length > 0) - pins["preferredWifi"] = pinnedList - else - delete pins["preferredWifi"] - - SettingsData.set("wifiNetworkPins", pins) - } - - LazyLoader { - id: vpnFileBrowserLoader - active: false - - FileBrowserModal { - browserTitle: I18n.tr("Import VPN") - browserIcon: "vpn_key" - browserType: "vpn" - fileExtensions: VPNService.getFileFilter() - - onFileSelected: path => { - VPNService.importVpn(path.replace("file://", "")); - } - } - } - - ConfirmModal { - id: deleteVpnConfirm - } - - ConfirmModal { - id: forgetNetworkConfirm - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(600, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: overviewSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: overviewSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "lan" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Network Status") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Overview of your network connections") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Grid { - columns: 2 - columnSpacing: Theme.spacingL - rowSpacing: Theme.spacingS - width: parent.width - - StyledText { - text: I18n.tr("Backend") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: NetworkService.backend || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - Row { - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: { - switch (NetworkService.networkStatus) { - case "ethernet": - case "wifi": - return Theme.success; - case "disconnected": - return Theme.error; - default: - return Theme.warning; - } - } - } - - StyledText { - text: { - switch (NetworkService.networkStatus) { - case "ethernet": - return I18n.tr("Ethernet"); - case "wifi": - return I18n.tr("WiFi"); - case "disconnected": - return I18n.tr("Disconnected"); - default: - return NetworkService.networkStatus || I18n.tr("Unknown"); - } - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - StyledText { - text: I18n.tr("Primary") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: NetworkService.primaryConnection.length > 0 - } - StyledText { - text: NetworkService.primaryConnection || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - visible: NetworkService.primaryConnection.length > 0 - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: NetworkService.backend === "networkmanager" && NetworkService.ethernetConnected && NetworkService.wifiConnected - - StyledText { - text: I18n.tr("Preference") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - preferenceLabel.width - preferenceButtons.width - Theme.spacingM * 2 - height: 1 - } - - DankButtonGroup { - id: preferenceButtons - model: [I18n.tr("Auto"), I18n.tr("Ethernet"), I18n.tr("WiFi")] - currentIndex: { - switch (NetworkService.userPreference) { - case "ethernet": - return 1; - case "wifi": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - NetworkService.setNetworkPreference("auto"); - break; - case 1: - NetworkService.setNetworkPreference("ethernet"); - break; - case 2: - NetworkService.setNetworkPreference("wifi"); - break; - } - } - } - } - - StyledText { - id: preferenceLabel - visible: false - text: I18n.tr("Preference") - } - } - } - - StyledRect { - width: parent.width - height: ethernetSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: NetworkService.ethernetConnected || (NetworkService.ethernetDevices?.length ?? 0) > 0 - - Column { - id: ethernetSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "settings_ethernet" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Ethernet") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const devices = NetworkService.ethernetDevices; - const connected = devices.filter(d => d.connected).length; - if (devices.length === 0) - return I18n.tr("No adapters"); - if (connected === 0) - return devices.length === 1 - ? I18n.tr("%1 adapter, none connected").arg(devices.length) - : I18n.tr("%1 adapters, none connected").arg(devices.length); - return I18n.tr("%1 connected").arg(connected); - } - font.pixelSize: Theme.fontSizeSmall - color: NetworkService.ethernetConnected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Column { - width: parent.width - spacing: 4 - visible: NetworkService.ethernetDevices.length > 0 - - StyledText { - text: I18n.tr("Adapters") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Repeater { - model: NetworkService.ethernetDevices - - delegate: Rectangle { - id: ethDeviceDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.connected || false - readonly property bool isExpanded: networkTab.expandedEthDevice === modelData.name - - width: parent.width - height: isExpanded ? 56 + ethExpandedContent.height : 56 - radius: Theme.cornerRadius - color: ethDeviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: isConnected ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: ethDeviceActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: 20 - color: isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - StyledText { - text: modelData.name || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: isConnected ? Theme.primary : Theme.surfaceText - font.weight: isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: { - switch (modelData.state) { - case "activated": - return I18n.tr("Connected"); - case "disconnected": - return I18n.tr("Disconnected"); - case "unavailable": - return I18n.tr("Unavailable"); - default: - return modelData.state || I18n.tr("Unknown"); - } - } - font.pixelSize: Theme.fontSizeSmall - color: isConnected ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData.ip || "").length > 0 - } - - StyledText { - text: modelData.ip || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData.ip || "").length > 0 - } - } - } - } - - Row { - id: ethDeviceActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: ethExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: isConnected - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: ethExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedEthDevice = ""; - } else { - networkTab.expandedEthDevice = modelData.name; - NetworkService.fetchWiredNetworkInfo(NetworkService.ethernetConnectionUuid); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: ethDisconnectBtn.containsMouse ? Theme.errorHover : "transparent" - visible: isConnected - - DankIcon { - anchors.centerIn: parent - name: "link_off" - size: 18 - color: ethDisconnectBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: ethDisconnectBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: NetworkService.disconnectEthernetDevice(modelData.name) - } - } - } - - MouseArea { - id: ethDeviceMouseArea - anchors.fill: parent - anchors.rightMargin: ethDeviceActions.width + Theme.spacingM - hoverEnabled: true - } - } - - Column { - id: ethExpandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: ethDetailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: ethDetailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Flow { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: { - const fields = []; - const dev = modelData; - if (!dev) - return fields; - - if (dev.ip) - fields.push({ - label: I18n.tr("IP"), - value: dev.ip - }); - if (dev.speed && dev.speed > 0) - fields.push({ - label: I18n.tr("Speed"), - value: dev.speed + " Mbps" - }); - if (dev.hwAddress) - fields.push({ - label: I18n.tr("MAC"), - value: dev.hwAddress - }); - if (dev.driver) - fields.push({ - label: I18n.tr("Driver"), - value: dev.driver - }); - fields.push({ - label: I18n.tr("State"), - value: dev.state || I18n.tr("Unknown") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: ethFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: ethFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Item { - width: parent.width - height: NetworkService.networkWiredInfoLoading ? 40 : 0 - visible: NetworkService.networkWiredInfoLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: wiredLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: NetworkService.networkWiredInfoLoading - loops: Animation.Infinite - NumberAnimation { - target: wiredLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: wiredLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - wiredLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wiredConnections.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - StyledText { - text: I18n.tr("Saved Configurations") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Repeater { - model: NetworkService.wiredConnections - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: wiredMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: modelData.isActive ? 2 : 0 - border.color: Theme.primary - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: 20 - color: modelData.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.id || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: modelData.isActive ? Theme.primary : Theme.surfaceText - font.weight: modelData.isActive ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData.isActive ? I18n.tr("Active") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: modelData.isActive - } - } - } - - MouseArea { - id: wiredMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!modelData.isActive) { - NetworkService.connectToSpecificWiredConfig(modelData.uuid); - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: wifiSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: wifiSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: NetworkService.wifiEnabled ? "wifi" : "wifi_off" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - wifiControls.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("WiFi") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (NetworkService.wifiToggling) - return I18n.tr("Toggling..."); - if (!NetworkService.wifiEnabled) - return I18n.tr("Disabled"); - if (NetworkService.wifiConnected) - return NetworkService.currentWifiSSID; - return I18n.tr("Not connected"); - } - font.pixelSize: Theme.fontSizeSmall - color: NetworkService.wifiConnected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: wifiControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - iconName: "wifi_find" - buttonSize: 32 - visible: NetworkService.backend === "networkmanager" && NetworkService.wifiEnabled && !NetworkService.wifiToggling - onClicked: PopoutService.showHiddenNetworkModal() - } - - DankActionButton { - iconName: "refresh" - buttonSize: 32 - visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling && !NetworkService.isScanning - onClicked: NetworkService.scanWifi() - } - - DankToggle { - checked: NetworkService.wifiEnabled - enabled: !NetworkService.wifiToggling - onToggled: NetworkService.toggleWifiRadio() - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: NetworkService.wifiEnabled && (NetworkService.wifiDevices?.length ?? 0) > 1 - - StyledText { - text: I18n.tr("WiFi Device") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - wifiDeviceLabel.width - wifiDeviceDropdown.width - Theme.spacingM * 2 - height: 1 - } - - DankDropdown { - id: wifiDeviceDropdown - dropdownWidth: 150 - popupWidth: 180 - currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto") - options: { - const devices = NetworkService.wifiDevices; - if (!devices || devices.length === 0) - return [I18n.tr("Auto")]; - return [I18n.tr("Auto")].concat(devices.map(d => d.name)); - } - onValueChanged: value => { - const deviceName = value === I18n.tr("Auto") ? "" : value; - NetworkService.setWifiDeviceOverride(deviceName); - } - } - } - - StyledText { - id: wifiDeviceLabel - visible: false - text: I18n.tr("WiFi Device") - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - visible: NetworkService.wifiEnabled - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wifiInterface.length > 0 - - Row { - width: parent.width - height: 24 - - StyledText { - text: I18n.tr("Interface:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: NetworkService.wifiInterface || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - height: 24 - visible: NetworkService.wifiIP.length > 0 - - StyledText { - text: I18n.tr("IP Address:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: NetworkService.wifiIP || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - height: 24 - visible: NetworkService.wifiConnected - - StyledText { - text: I18n.tr("Signal:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - const s = NetworkService.wifiSignalStrength; - if (s >= 50) - return "wifi"; - if (s >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: 18 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: NetworkService.wifiSignalStrength + "%" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - } - } - } - - Item { - width: parent.width - height: Theme.spacingS - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Networks") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - StyledText { - text: NetworkService.wifiNetworks?.length ?? 0 - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - width: parent.width - height: 80 - visible: NetworkService.isScanning && (NetworkService.wifiNetworks?.length ?? 0) === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: scanningIcon - name: "wifi_find" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - - SequentialAnimation { - running: NetworkService.isScanning - loops: Animation.Infinite - NumberAnimation { - target: scanningIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: scanningIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - scanningIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Scanning...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: (NetworkService.wifiNetworks?.length ?? 0) > 0 - - Repeater { - model: { - const ssid = NetworkService.currentWifiSSID; - const networks = NetworkService.wifiNetworks || []; - const pinnedList = networkTab.getPinnedWifiNetworks(); - - let sorted = [...networks]; - sorted.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.ssid) - const bPinnedIndex = pinnedList.indexOf(b.ssid) - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1 - if (bPinnedIndex === -1) - return -1 - return aPinnedIndex - bPinnedIndex - } - if (a.ssid === ssid) - return -1; - if (b.ssid === ssid) - return 1; - return b.signal - a.signal; - }); - return sorted; - } - - delegate: Rectangle { - id: wifiNetworkDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID - readonly property bool isPinned: networkTab.getPinnedWifiNetworks().includes(modelData.ssid) - readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid - - width: parent.width - height: isExpanded ? 56 + wifiExpandedContent.height : 56 - radius: Theme.cornerRadius - color: wifiNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: isConnected ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: wifiNetworkActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: { - const s = modelData.signal || 0; - if (s >= 50) - return "wifi"; - if (s >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: 20 - color: isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: modelData.ssid || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: isConnected ? Theme.primary : Theme.surfaceText - font.weight: isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - } - - DankIcon { - name: "push_pin" - size: 14 - color: Theme.primary - visible: isPinned - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "visibility_off" - size: 14 - color: Theme.surfaceVariantText - visible: modelData.hidden || false - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open")) - font.pixelSize: Theme.fontSizeSmall - color: isConnected ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.saved - } - - StyledText { - text: I18n.tr("Saved") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: modelData.saved - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.hidden || false - } - - StyledText { - text: I18n.tr("Hidden") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.hidden || false - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData.signal + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Row { - id: wifiNetworkActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: wifiExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: isConnected || modelData.saved - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: wifiExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedWifiSsid = ""; - } else { - networkTab.expandedWifiSsid = modelData.ssid; - NetworkService.fetchNetworkInfo(modelData.ssid); - } - } - } - } - - DankActionButton { - iconName: "qr_code" - buttonSize: 28 - visible: modelData.secured && modelData.saved - onClicked: { - PopoutService.showWifiQRCodeModal(modelData.ssid); - } - } - - DankActionButton { - iconName: isPinned ? "push_pin" : "push_pin" - buttonSize: 28 - iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText - onClicked: { - networkTab.toggleWifiPin(modelData.ssid) - } - } - - DankActionButton { - iconName: "delete" - buttonSize: 28 - iconColor: Theme.error - visible: modelData.saved || isConnected - onClicked: { - forgetNetworkConfirm.showWithOptions({ - title: I18n.tr("Forget Network"), - message: I18n.tr("Forget \"%1\"?").arg(modelData.ssid), - confirmText: I18n.tr("Forget"), - confirmColor: Theme.error, - onConfirm: () => NetworkService.forgetWifiNetwork(modelData.ssid) - }); - } - } - } - - MouseArea { - id: wifiNetworkMouseArea - - anchors.fill: parent - anchors.rightMargin: wifiNetworkActions.width + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isConnected) { - NetworkService.disconnectWifi(); - return; - } - NetworkService.connectToWifi(modelData.ssid); - } - } - } - - Column { - id: wifiExpandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: wifiDetailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: wifiDetailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: NetworkService.networkInfoLoading ? 40 : 0 - visible: NetworkService.networkInfoLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: wifiInfoLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: NetworkService.networkInfoLoading - loops: Animation.Infinite - NumberAnimation { - target: wifiInfoLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: wifiInfoLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - wifiInfoLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: !NetworkService.networkInfoLoading - - Repeater { - model: { - const fields = []; - const net = modelData; - if (!net) - return fields; - - fields.push({ - label: I18n.tr("Signal"), - value: net.signal + "%" - }); - if (net.frequency) - fields.push({ - label: I18n.tr("Frequency"), - value: (net.frequency / 1000).toFixed(1) + " GHz" - }); - if (net.channel) - fields.push({ - label: I18n.tr("Channel"), - value: String(net.channel) - }); - if (net.rate) - fields.push({ - label: I18n.tr("Rate"), - value: net.rate + " Mbps" - }); - if (net.mode) - fields.push({ - label: I18n.tr("Mode"), - value: net.mode - }); - if (net.bssid) - fields.push({ - label: I18n.tr("BSSID"), - value: net.bssid - }); - fields.push({ - label: I18n.tr("Security"), - value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: wifiFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: wifiFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Row { - spacing: Theme.spacingS - visible: (modelData.saved || isConnected) && DMSService.apiVersion > 13 - - DankToggle { - id: autoconnectToggle - text: I18n.tr("Autoconnect") - checked: modelData.autoconnect || false - onToggled: checked => { - NetworkService.setWifiAutoconnect(modelData.ssid, checked); - } - } - } - } - } - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: vpnSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DMSNetworkService.vpnAvailable - - Column { - id: vpnSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - vpnHeaderControls.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("VPN") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (!DMSNetworkService.connected) - return I18n.tr("Disconnected"); - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) - return names[0] || I18n.tr("Connected"); - return names[0] + " +" + (names.length - 1); - } - font.pixelSize: Theme.fontSizeSmall - color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: vpnHeaderControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - height: 28 - radius: 14 - width: importVpnRow.width + Theme.spacingM * 2 - color: importVpnArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - opacity: VPNService.importing ? 0.5 : 1.0 - - Row { - id: importVpnRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: VPNService.importing ? "sync" : "add" - size: Theme.fontSizeSmall - color: Theme.primary - } - - StyledText { - text: I18n.tr("Import") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - } - - MouseArea { - id: importVpnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !VPNService.importing - onClicked: networkTab.openVpnFileBrowser() - } - } - - Rectangle { - height: 28 - radius: 14 - width: disconnectAllRow.width + Theme.spacingM * 2 - color: disconnectAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: DMSNetworkService.connected - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - Row { - id: disconnectAllRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "link_off" - size: Theme.fontSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Disconnect") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: disconnectAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.disconnectAllActive() - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Item { - width: parent.width - height: 100 - visible: DMSNetworkService.profiles.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "vpn_key_off" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No VPN profiles") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Click Import to add a .ovpn or .conf") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: DMSNetworkService.profiles.length > 0 - - Repeater { - model: DMSNetworkService.profiles - - delegate: Rectangle { - id: vpnProfileRow - required property var modelData - required property int index - - readonly property bool isActive: DMSNetworkService.isActiveUuid(modelData.uuid) - readonly property bool isExpanded: networkTab.expandedVpnUuid === modelData.uuid - readonly property var configData: isExpanded ? VPNService.editConfig : null - - width: parent.width - height: isExpanded ? 56 + vpnExpandedContent.height : 56 - radius: Theme.cornerRadius - color: vpnRowArea.containsMouse ? Theme.primaryHoverLight : (isActive ? Theme.primaryPressed : Theme.surfaceLight) - border.width: isActive ? 2 : 0 - border.color: Theme.primary - opacity: DMSNetworkService.isBusy ? 0.6 : 1.0 - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - MouseArea { - id: vpnRowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.toggle(modelData.uuid) - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - height: 56 - Theme.spacingS * 2 - spacing: Theme.spacingS - - DankIcon { - name: isActive ? "vpn_lock" : "vpn_key_off" - size: 20 - color: isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - 28 - 28 - Theme.spacingS * 4 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: isActive ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: VPNService.getVpnTypeFromProfile(modelData) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.left: parent.left - } - } - - Item { - width: Theme.spacingXS - height: 1 - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: vpnExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: vpnExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedVpnUuid = ""; - } else { - networkTab.expandedVpnUuid = modelData.uuid; - VPNService.getConfig(modelData.uuid); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: vpnDeleteBtn.containsMouse ? Theme.errorHover : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: vpnDeleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: vpnDeleteBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deleteVpnConfirm.showWithOptions({ - title: I18n.tr("Delete VPN"), - message: I18n.tr("Delete \"%1\"?").arg(modelData.name), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => VPNService.deleteVpn(modelData.uuid) - }); - } - } - } - } - - Column { - id: vpnExpandedContent - width: parent.width - spacing: Theme.spacingXS - visible: isExpanded - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineLight - } - - Item { - width: parent.width - height: VPNService.configLoading ? 40 : 0 - visible: VPNService.configLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: vpnLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: VPNService.configLoading - loops: Animation.Infinite - NumberAnimation { - target: vpnLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: vpnLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - vpnLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: !VPNService.configLoading && configData - - Repeater { - model: { - if (!configData) - return []; - const fields = []; - const data = configData.data || {}; - - if (data.remote) - fields.push({ - label: I18n.tr("Server"), - value: data.remote - }); - if (configData.username || data.username) - fields.push({ - label: I18n.tr("Username"), - value: configData.username || data.username - }); - if (data.cipher) - fields.push({ - label: I18n.tr("Cipher"), - value: data.cipher - }); - if (data.auth) - fields.push({ - label: I18n.tr("Auth"), - value: data.auth - }); - if (data["proto-tcp"] === "yes" || data["proto-tcp"] === "no") - fields.push({ - label: I18n.tr("Protocol"), - value: data["proto-tcp"] === "yes" ? "TCP" : "UDP" - }); - if (data["tunnel-mtu"]) - fields.push({ - label: I18n.tr("MTU"), - value: data["tunnel-mtu"] - }); - if (data["connection-type"]) - fields.push({ - label: I18n.tr("Auth Type"), - value: data["connection-type"] - }); - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: vpnFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: vpnFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Autoconnect") - checked: configData ? (configData.autoconnect || false) : false - visible: !VPNService.configLoading && configData !== null - onToggled: checked => { - VPNService.updateConfig(modelData.uuid, {autoconnect: checked}); - } - } - - Item { - width: 1 - height: Theme.spacingXS - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml deleted file mode 100644 index c43a5e2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml +++ /dev/null @@ -1,900 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - Component.onCompleted: { - if (SettingsData._pendingExpandNotificationRules) { - SettingsData._pendingExpandNotificationRules = false; - notificationRulesCard.userToggledCollapse = true; - notificationRulesCard.expanded = true; - SettingsData._pendingNotificationRuleIndex = -1; - } - } - - readonly property var mutedRules: { - var rules = SettingsData.notificationRules || []; - var out = []; - for (var i = 0; i < rules.length; i++) { - if ((rules[i].action || "").toString().toLowerCase() === "mute") - out.push({ - rule: rules[i], - index: i - }); - } - return out; - } - - readonly property var timeoutOptions: [ - { - text: I18n.tr("Never"), - value: 0 - }, - { - text: I18n.tr("1 second"), - value: 1000 - }, - { - text: I18n.tr("3 seconds"), - value: 3000 - }, - { - text: I18n.tr("5 seconds"), - value: 5000 - }, - { - text: I18n.tr("8 seconds"), - value: 8000 - }, - { - text: I18n.tr("10 seconds"), - value: 10000 - }, - { - text: I18n.tr("15 seconds"), - value: 15000 - }, - { - text: I18n.tr("30 seconds"), - value: 30000 - }, - { - text: I18n.tr("1 minute"), - value: 60000 - }, - { - text: I18n.tr("2 minutes"), - value: 120000 - }, - { - text: I18n.tr("5 minutes"), - value: 300000 - }, - { - text: I18n.tr("10 minutes"), - value: 600000 - } - ] - - readonly property var notificationRuleFieldOptions: [ - { - value: "appName", - label: I18n.tr("App Names", "notification rule match field option") - }, - { - value: "desktopEntry", - label: I18n.tr("Desktop Entry", "notification rule match field option") - }, - { - value: "summary", - label: I18n.tr("Summary", "notification rule match field option") - }, - { - value: "body", - label: I18n.tr("Body", "notification rule match field option") - } - ] - - readonly property var notificationRuleMatchTypeOptions: [ - { - value: "contains", - label: I18n.tr("Contains", "notification rule match type option") - }, - { - value: "exact", - label: I18n.tr("Exact", "notification rule match type option") - }, - { - value: "regex", - label: I18n.tr("Regex", "notification rule match type option") - } - ] - - readonly property var notificationRuleActionOptions: [ - { - value: "default", - label: I18n.tr("Default", "notification rule action option") - }, - { - value: "mute", - label: I18n.tr("Mute Popups", "notification rule action option") - }, - { - value: "ignore", - label: I18n.tr("Ignore Completely", "notification rule action option") - }, - { - value: "popup_only", - label: I18n.tr("Popup Only", "notification rule action option") - }, - { - value: "no_history", - label: I18n.tr("No History", "notification rule action option") - } - ] - - readonly property var notificationRuleUrgencyOptions: [ - { - value: "default", - label: I18n.tr("Default", "notification rule urgency option") - }, - { - value: "low", - label: I18n.tr("Low Priority", "notification rule urgency option") - }, - { - value: "normal", - label: I18n.tr("Normal Priority", "notification rule urgency option") - }, - { - value: "critical", - label: I18n.tr("Critical Priority", "notification rule urgency option") - } - ] - - function getTimeoutText(value) { - if (value === undefined || value === null || isNaN(value)) - return I18n.tr("5 seconds"); - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].value === value) - return timeoutOptions[i].text; - } - if (value === 0) - return I18n.tr("Never"); - if (value < 1000) - return value + "ms"; - if (value < 60000) - return Math.round(value / 1000) + " " + I18n.tr("seconds"); - return Math.round(value / 60000) + " " + I18n.tr("minutes"); - } - - function getRuleOptionLabel(options, value, fallback) { - for (let i = 0; i < options.length; i++) { - if (options[i].value === value) - return options[i].label; - } - return fallback; - } - - function getRuleOptionValue(options, label, fallback) { - for (let i = 0; i < options.length; i++) { - if (options[i].label === label) - return options[i].value; - } - return fallback; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "notifications" - title: I18n.tr("Notification Popups") - settingKey: "notificationPopups" - - SettingsDropdownRow { - settingKey: "notificationPopupPosition" - tags: ["notification", "popup", "position", "screen", "location"] - text: I18n.tr("Popup Position") - description: I18n.tr("Choose where notification popups appear on screen") - currentValue: { - if (SettingsData.notificationPopupPosition === -1) - return I18n.tr("Top Center", "screen position option"); - switch (SettingsData.notificationPopupPosition) { - case SettingsData.Position.Top: - return I18n.tr("Top Right", "screen position option"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom Left", "screen position option"); - case SettingsData.Position.Left: - return I18n.tr("Top Left", "screen position option"); - case SettingsData.Position.Right: - return I18n.tr("Bottom Right", "screen position option"); - case SettingsData.Position.BottomCenter: - return I18n.tr("Bottom Center", "screen position option"); - default: - return I18n.tr("Top Right", "screen position option"); - } - } - options: [I18n.tr("Top Right", "screen position option"), I18n.tr("Top Left", "screen position option"), I18n.tr("Top Center", "screen position option"), I18n.tr("Bottom Center", "screen position option"), I18n.tr("Bottom Right", "screen position option"), I18n.tr("Bottom Left", "screen position option")] - onValueChanged: value => { - switch (value) { - case I18n.tr("Top Right", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Top); - break; - case I18n.tr("Top Left", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Left); - break; - case I18n.tr("Top Center", "screen position option"): - SettingsData.set("notificationPopupPosition", -1); - break; - case I18n.tr("Bottom Center", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.BottomCenter); - break; - case I18n.tr("Bottom Right", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Right); - break; - case I18n.tr("Bottom Left", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom); - break; - } - SettingsData.sendTestNotifications(); - } - } - - SettingsToggleRow { - settingKey: "notificationOverlayEnabled" - tags: ["notification", "overlay", "fullscreen", "priority"] - text: I18n.tr("Notification Overlay") - description: I18n.tr("Display all priorities over fullscreen apps") - checked: SettingsData.notificationOverlayEnabled - onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked) - } - - SettingsToggleRow { - settingKey: "notificationCompactMode" - tags: ["notification", "compact", "size", "display", "mode"] - text: I18n.tr("Compact") - description: I18n.tr("Use smaller notification cards") - checked: SettingsData.notificationCompactMode - onToggled: checked => SettingsData.set("notificationCompactMode", checked) - } - - SettingsToggleRow { - settingKey: "notificationPopupShadowEnabled" - tags: ["notification", "popup", "shadow", "radius", "rounded"] - text: I18n.tr("Popup Shadow") - description: I18n.tr("Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.") - checked: SettingsData.notificationPopupShadowEnabled - onToggled: checked => SettingsData.set("notificationPopupShadowEnabled", checked) - } - - SettingsToggleRow { - settingKey: "notificationPopupPrivacyMode" - tags: ["notification", "popup", "privacy", "body", "content", "hide"] - text: I18n.tr("Privacy Mode") - description: I18n.tr("Hide notification content until expanded; popups show collapsed by default") - checked: SettingsData.notificationPopupPrivacyMode - onToggled: checked => SettingsData.set("notificationPopupPrivacyMode", checked) - } - - SettingsToggleRow { - settingKey: "notificationFocusedMonitor" - tags: ["notification", "popup", "focused", "monitor", "display", "screen", "active"] - text: I18n.tr("Focused Monitor Only") - description: I18n.tr("Show notification popups only on the currently focused monitor") - checked: SettingsData.notificationFocusedMonitor - onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked) - } - - Item { - width: parent.width - height: notificationAnimationColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: notificationAnimationColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.top: parent.top - anchors.topMargin: Theme.spacingM - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Animation Speed") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - } - - StyledText { - text: I18n.tr("Control animation duration for notification popups and history") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - - DankButtonGroup { - id: notificationSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingM - minButtonWidth: parent.width < 480 ? 44 : 56 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.notificationAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("notificationAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onNotificationAnimationSpeedChanged() { - notificationSpeedGroup.currentIndex = SettingsData.notificationAnimationSpeed; - } - } - } - - SettingsSliderRow { - id: animationDurationSlider - settingKey: "notificationCustomAnimationDuration" - tags: ["notification", "animation", "duration", "custom", "speed"] - text: I18n.tr("Duration") - description: I18n.tr("Base duration for animations (drag to use Custom)") - minimum: 100 - maximum: 800 - value: Theme.notificationAnimationBaseDuration - unit: "ms" - defaultValue: 400 - onSliderValueChanged: newValue => { - if (SettingsData.notificationAnimationSpeed !== SettingsData.AnimationSpeed.Custom) { - SettingsData.set("notificationAnimationSpeed", SettingsData.AnimationSpeed.Custom); - } - SettingsData.set("notificationCustomAnimationDuration", newValue); - } - - Connections { - target: Theme - function onNotificationAnimationBaseDurationChanged() { - animationDurationSlider.value = Theme.notificationAnimationBaseDuration; - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "notifications_off" - title: I18n.tr("Do Not Disturb") - settingKey: "doNotDisturb" - - SettingsToggleRow { - settingKey: "doNotDisturb" - tags: ["notification", "dnd", "mute", "silent", "suppress"] - text: I18n.tr("Enable Do Not Disturb") - description: I18n.tr("Suppress notification popups while enabled") - checked: SessionData.doNotDisturb - onToggled: checked => SessionData.setDoNotDisturb(checked) - } - } - - SettingsCard { - id: notificationRulesCard - width: parent.width - iconName: "rule_settings" - title: I18n.tr("Notification Rules") - settingKey: "notificationRules" - tags: ["notification", "rules", "mute", "ignore", "priority", "regex", "history"] - collapsible: true - expanded: false - - headerActions: [ - DankActionButton { - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: JSON.stringify(SettingsData.notificationRules) !== JSON.stringify(SettingsData.getDefaultNotificationRules()) - backgroundColor: Theme.surfaceContainer - iconColor: Theme.surfaceVariantText - onClicked: SettingsData.resetNotificationRules() - }, - DankActionButton { - buttonSize: 36 - iconName: "add" - iconSize: 20 - backgroundColor: Theme.surfaceContainer - iconColor: Theme.primary - onClicked: { - SettingsData.addNotificationRule(); - notificationRulesCard.userToggledCollapse = true; - notificationRulesCard.expanded = true; - } - } - ] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: SettingsData.notificationRules - - delegate: Rectangle { - id: ruleItem - width: parent.width - height: ruleColumn.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Column { - id: ruleColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - id: ruleLabel - text: I18n.tr("Rule") + " " + (index + 1) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - ruleLabel.implicitWidth - enableToggle.width - deleteBtn.width - Theme.spacingS * 3) - height: 1 - } - - DankToggle { - id: enableToggle - width: 40 - height: 24 - hideText: true - checked: modelData.enabled !== false - onToggled: checked => SettingsData.updateNotificationRuleField(index, "enabled", checked) - } - - Item { - id: deleteBtn - width: 28 - height: 28 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeNotificationRule(index) - } - } - } - - Column { - width: parent.width - spacing: 2 - - StyledText { - text: I18n.tr("Pattern") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - text: modelData.pattern || "" - font.pixelSize: Theme.fontSizeSmall - placeholderText: I18n.tr("Pattern") - onEditingFinished: SettingsData.updateNotificationRuleField(index, "pattern", text) - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Field") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 165 - currentValue: root.getRuleOptionLabel(root.notificationRuleFieldOptions, modelData.field, root.notificationRuleFieldOptions[0].label) - options: root.notificationRuleFieldOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "field", root.getRuleOptionValue(root.notificationRuleFieldOptions, value, "appName")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Type") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - currentValue: root.getRuleOptionLabel(root.notificationRuleMatchTypeOptions, modelData.matchType, root.notificationRuleMatchTypeOptions[0].label) - options: root.notificationRuleMatchTypeOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "matchType", root.getRuleOptionValue(root.notificationRuleMatchTypeOptions, value, "contains")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Action") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 170 - currentValue: root.getRuleOptionLabel(root.notificationRuleActionOptions, modelData.action, root.notificationRuleActionOptions[0].label) - options: root.notificationRuleActionOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "action", root.getRuleOptionValue(root.notificationRuleActionOptions, value, "default")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Priority") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 165 - currentValue: root.getRuleOptionLabel(root.notificationRuleUrgencyOptions, modelData.urgency, root.notificationRuleUrgencyOptions[0].label) - options: root.notificationRuleUrgencyOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "urgency", root.getRuleOptionValue(root.notificationRuleUrgencyOptions, value, "default")) - } - } - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "volume_off" - title: I18n.tr("Muted Apps") - settingKey: "mutedApps" - tags: ["notification", "mute", "unmute", "popup"] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: mutedRules.length > 0 ? I18n.tr("Apps with notification popups muted. Unmute or delete to remove.") : I18n.tr("No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: mutedRules - - delegate: Rectangle { - width: parent.width - height: mutedRow.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Row { - id: mutedRow - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - StyledText { - id: mutedAppLabel - text: (modelData.rule && modelData.rule.pattern) ? modelData.rule.pattern : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - parent.spacing - mutedAppLabel.width - unmuteBtn.width - deleteBtn.width - Theme.spacingS * 5) - height: 1 - } - - DankButton { - id: unmuteBtn - text: I18n.tr("Unmute") - backgroundColor: Theme.surfaceContainer - textColor: Theme.primary - onClicked: SettingsData.removeNotificationRule(modelData.index) - } - - Item { - id: deleteBtn - width: 28 - height: 28 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeNotificationRule(modelData.index) - } - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen", "lock screen notifications settings card") - settingKey: "lockScreenNotifications" - - SettingsDropdownRow { - settingKey: "lockScreenNotificationMode" - tags: ["lock", "screen", "notification", "notifications", "privacy"] - text: I18n.tr("Notification Display", "lock screen notification privacy setting") - description: I18n.tr("Control what notification information is shown on the lock screen", "lock screen notification privacy setting") - options: [I18n.tr("Disabled", "lock screen notification mode option"), I18n.tr("Count Only", "lock screen notification mode option"), I18n.tr("App Names", "lock screen notification mode option"), I18n.tr("Full Content", "lock screen notification mode option")] - currentValue: options[SettingsData.lockScreenNotificationMode] || options[0] - onValueChanged: value => { - const idx = options.indexOf(value); - if (idx >= 0) { - SettingsData.set("lockScreenNotificationMode", idx); - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "timer" - title: I18n.tr("Notification Timeouts") - settingKey: "notificationTimeouts" - collapsible: true - expanded: false - - SettingsDropdownRow { - settingKey: "notificationTimeoutLow" - tags: ["notification", "timeout", "low", "priority", "duration"] - text: I18n.tr("Low Priority") - description: I18n.tr("Timeout for low priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutLow", root.timeoutOptions[i].value); - break; - } - } - } - } - - SettingsDropdownRow { - settingKey: "notificationTimeoutNormal" - tags: ["notification", "timeout", "normal", "priority", "duration"] - text: I18n.tr("Normal Priority") - description: I18n.tr("Timeout for normal priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutNormal", root.timeoutOptions[i].value); - break; - } - } - } - } - - SettingsDropdownRow { - settingKey: "notificationTimeoutCritical" - tags: ["notification", "timeout", "critical", "priority", "duration"] - text: I18n.tr("Critical Priority") - description: I18n.tr("Timeout for critical priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutCritical", root.timeoutOptions[i].value); - break; - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "history" - title: I18n.tr("History Settings") - settingKey: "notificationHistory" - - SettingsToggleRow { - settingKey: "notificationHistoryEnabled" - tags: ["notification", "history", "enable", "disable", "save"] - text: I18n.tr("Enable History", "notification history toggle label") - description: I18n.tr("Save dismissed notifications to history", "notification history toggle description") - checked: SettingsData.notificationHistoryEnabled - onToggled: checked => SettingsData.set("notificationHistoryEnabled", checked) - } - - SettingsSliderRow { - settingKey: "notificationHistoryMaxCount" - tags: ["notification", "history", "max", "count", "limit"] - text: I18n.tr("Maximum History") - description: I18n.tr("Maximum number of notifications to keep", "notification history limit") - value: SettingsData.notificationHistoryMaxCount - minimum: 10 - maximum: 200 - step: 10 - unit: "" - defaultValue: 50 - onSliderValueChanged: newValue => SettingsData.set("notificationHistoryMaxCount", newValue) - } - - SettingsDropdownRow { - settingKey: "notificationHistoryMaxAgeDays" - tags: ["notification", "history", "max", "age", "days", "retention"] - text: I18n.tr("History Retention", "notification history retention settings label") - description: I18n.tr("Auto-delete notifications older than this", "notification history setting") - currentValue: { - switch (SettingsData.notificationHistoryMaxAgeDays) { - case 0: - return I18n.tr("Forever", "notification history retention option"); - case 1: - return I18n.tr("1 day", "notification history retention option"); - case 3: - return I18n.tr("3 days", "notification history retention option"); - case 7: - return I18n.tr("7 days", "notification history retention option"); - case 14: - return I18n.tr("14 days", "notification history retention option"); - case 30: - return I18n.tr("30 days", "notification history retention option"); - default: - return SettingsData.notificationHistoryMaxAgeDays + " " + I18n.tr("days"); - } - } - options: [I18n.tr("Forever", "notification history retention option"), I18n.tr("1 day", "notification history retention option"), I18n.tr("3 days", "notification history retention option"), I18n.tr("7 days", "notification history retention option"), I18n.tr("14 days", "notification history retention option"), I18n.tr("30 days", "notification history retention option")] - onValueChanged: value => { - let days = 7; - if (value === I18n.tr("Forever", "notification history retention option")) - days = 0; - else if (value === I18n.tr("1 day", "notification history retention option")) - days = 1; - else if (value === I18n.tr("3 days", "notification history retention option")) - days = 3; - else if (value === I18n.tr("7 days", "notification history retention option")) - days = 7; - else if (value === I18n.tr("14 days", "notification history retention option")) - days = 14; - else if (value === I18n.tr("30 days", "notification history retention option")) - days = 30; - SettingsData.set("notificationHistoryMaxAgeDays", days); - } - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveLow" - tags: ["notification", "history", "save", "low", "priority"] - text: I18n.tr("Low Priority") - description: I18n.tr("Save low priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveLow - onToggled: checked => SettingsData.set("notificationHistorySaveLow", checked) - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveNormal" - tags: ["notification", "history", "save", "normal", "priority"] - text: I18n.tr("Normal Priority") - description: I18n.tr("Save normal priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveNormal - onToggled: checked => SettingsData.set("notificationHistorySaveNormal", checked) - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveCritical" - tags: ["notification", "history", "save", "critical", "priority"] - text: I18n.tr("Critical Priority") - description: I18n.tr("Save critical priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveCritical - onToggled: checked => SettingsData.set("notificationHistorySaveCritical", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml deleted file mode 100644 index 4bf26d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("On-screen Displays") - settingKey: "osd" - - SettingsDropdownRow { - settingKey: "osdPosition" - text: I18n.tr("OSD Position") - description: I18n.tr("Choose where on-screen displays appear on screen") - currentValue: { - switch (SettingsData.osdPosition) { - case SettingsData.Position.Top: - return I18n.tr("Top Right", "screen position option"); - case SettingsData.Position.Left: - return I18n.tr("Top Left", "screen position option"); - case SettingsData.Position.TopCenter: - return I18n.tr("Top Center", "screen position option"); - case SettingsData.Position.Right: - return I18n.tr("Bottom Right", "screen position option"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom Left", "screen position option"); - case SettingsData.Position.BottomCenter: - return I18n.tr("Bottom Center", "screen position option"); - case SettingsData.Position.LeftCenter: - return I18n.tr("Left Center", "screen position option"); - case SettingsData.Position.RightCenter: - return I18n.tr("Right Center", "screen position option"); - default: - return I18n.tr("Bottom Center", "screen position option"); - } - } - options: [I18n.tr("Top Right", "screen position option"), I18n.tr("Top Left", "screen position option"), I18n.tr("Top Center", "screen position option"), I18n.tr("Bottom Right", "screen position option"), I18n.tr("Bottom Left", "screen position option"), I18n.tr("Bottom Center", "screen position option"), I18n.tr("Left Center", "screen position option"), I18n.tr("Right Center", "screen position option")] - onValueChanged: value => { - if (value === I18n.tr("Top Right", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Top); - } else if (value === I18n.tr("Top Left", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Left); - } else if (value === I18n.tr("Top Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.TopCenter); - } else if (value === I18n.tr("Bottom Right", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Right); - } else if (value === I18n.tr("Bottom Left", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Bottom); - } else if (value === I18n.tr("Bottom Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.BottomCenter); - } else if (value === I18n.tr("Left Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.LeftCenter); - } else if (value === I18n.tr("Right Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.RightCenter); - } - } - } - - SettingsToggleRow { - settingKey: "osdAlwaysShowValue" - text: I18n.tr("Always Show Percentage") - description: I18n.tr("Display volume and brightness percentage values in OSD popups") - checked: SettingsData.osdAlwaysShowValue - onToggled: checked => SettingsData.set("osdAlwaysShowValue", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - settingKey: "osdVolumeEnabled" - text: I18n.tr("Volume") - description: I18n.tr("Show on-screen display when volume changes") - checked: SettingsData.osdVolumeEnabled - onToggled: checked => SettingsData.set("osdVolumeEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMediaVolumeEnabled" - text: I18n.tr("Media Volume") - description: I18n.tr("Show on-screen display when media player volume changes") - checked: SettingsData.osdMediaVolumeEnabled - onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMediaPlaybackEnabled" - text: I18n.tr("Media Playback") - description: I18n.tr("Show on-screen display when media player status changes") - checked: SettingsData.osdMediaPlaybackEnabled - onToggled: checked => SettingsData.set("osdMediaPlaybackEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdBrightnessEnabled" - text: I18n.tr("Brightness") - description: I18n.tr("Show on-screen display when brightness changes") - checked: SettingsData.osdBrightnessEnabled - onToggled: checked => SettingsData.set("osdBrightnessEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdIdleInhibitorEnabled" - text: I18n.tr("Idle Inhibitor") - description: I18n.tr("Show on-screen display when idle inhibitor state changes") - checked: SettingsData.osdIdleInhibitorEnabled - onToggled: checked => SettingsData.set("osdIdleInhibitorEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMicMuteEnabled" - text: I18n.tr("Microphone Mute") - description: I18n.tr("Show on-screen display when microphone is muted/unmuted") - checked: SettingsData.osdMicMuteEnabled - onToggled: checked => SettingsData.set("osdMicMuteEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdCapsLockEnabled" - text: I18n.tr("Caps Lock") - description: I18n.tr("Show on-screen display when caps lock state changes") - checked: SettingsData.osdCapsLockEnabled - onToggled: checked => SettingsData.set("osdCapsLockEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdPowerProfileEnabled" - text: I18n.tr("Power Profile") - description: I18n.tr("Show on-screen display when power profile changes") - checked: SettingsData.osdPowerProfileEnabled - onToggled: checked => SettingsData.set("osdPowerProfileEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdAudioOutputEnabled" - text: I18n.tr("Audio Output Switch") - description: I18n.tr("Show on-screen display when cycling audio output devices") - checked: SettingsData.osdAudioOutputEnabled - onToggled: checked => SettingsData.set("osdAudioOutputEnabled", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml deleted file mode 100644 index b1f0a6f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml +++ /dev/null @@ -1,856 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allPlugins: [] - property string searchQuery: "" - property var filteredPlugins: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property bool isLoading: false - property var parentModal: null - property bool pendingInstallHandled: false - property string typeFilter: "" - - function updateFilteredPlugins() { - var filtered = []; - var query = searchQuery ? searchQuery.toLowerCase() : ""; - - for (var i = 0; i < allPlugins.length; i++) { - var plugin = allPlugins[i]; - var isFirstParty = plugin.firstParty || false; - - if (!SessionData.showThirdPartyPlugins && !isFirstParty) - continue; - if (typeFilter !== "") { - var hasCapability = plugin.capabilities && plugin.capabilities.includes(typeFilter); - if (!hasCapability) - continue; - } - - if (query.length === 0) { - filtered.push(plugin); - continue; - } - - var name = plugin.name ? plugin.name.toLowerCase() : ""; - var description = plugin.description ? plugin.description.toLowerCase() : ""; - var author = plugin.author ? plugin.author.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || author.indexOf(query) !== -1) - filtered.push(plugin); - } - - filtered.sort((a, b) => { - if (a.featured !== b.featured) - return a.featured ? -1 : 1; - if (a.firstParty !== b.firstParty) - return a.firstParty ? -1 : 1; - return 0; - }); - - filteredPlugins = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredPlugins.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredPlugins.length - 1); - } - - function selectPrevious() { - if (filteredPlugins.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function installPlugin(pluginName, enableAfterInstall) { - ToastService.showInfo(I18n.tr("Installing: %1", "installation progress").arg(pluginName)); - DMSService.install(pluginName, response => { - if (response.error) { - ToastService.showError(I18n.tr("Install failed: %1", "installation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Installed: %1", "installation success").arg(pluginName)); - PluginService.scanPlugins(); - refreshPlugins(); - if (enableAfterInstall) { - Qt.callLater(() => { - PluginService.enablePlugin(pluginName); - const plugin = PluginService.availablePlugins[pluginName]; - if (plugin?.type === "desktop") { - const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(pluginName); - SettingsData.createDesktopWidgetInstance(pluginName, plugin.name || pluginName, defaultConfig); - } - hide(); - }); - } - }); - } - - function refreshPlugins() { - isLoading = true; - DMSService.listPlugins(); - if (DMSService.apiVersion >= 8) - DMSService.listInstalled(); - } - - function checkPendingInstall() { - if (!PopoutService.pendingPluginInstall || pendingInstallHandled) - return; - pendingInstallHandled = true; - var pluginId = PopoutService.pendingPluginInstall; - PopoutService.pendingPluginInstall = ""; - urlInstallConfirm.showWithOptions({ - "title": I18n.tr("Install Plugin", "plugin installation dialog title"), - "message": I18n.tr("Install plugin '%1' from the DMS registry?", "plugin installation confirmation").arg(pluginId), - "confirmText": I18n.tr("Install", "install action button"), - "cancelText": I18n.tr("Cancel"), - "onConfirm": () => installPlugin(pluginId, true), - "onCancel": () => hide() - }); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => browserSearchField.forceActiveFocus()); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "pluginBrowser" - title: I18n.tr("Browse Plugins", "plugin browser window title") - minimumSize: Qt.size(450, 400) - implicitWidth: 600 - implicitHeight: 650 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - pendingInstallHandled = false; - refreshPlugins(); - Qt.callLater(() => { - browserSearchField.forceActiveFocus(); - checkPendingInstall(); - }); - return; - } - allPlugins = []; - searchQuery = ""; - filteredPlugins = []; - selectedIndex = -1; - keyboardNavigationActive = false; - isLoading = false; - } - - Connections { - target: DMSService - - function onPluginsListReceived(plugins) { - root.isLoading = false; - root.allPlugins = plugins; - root.updateFilteredPlugins(); - } - - function onInstalledPluginsReceived(plugins) { - var pluginMap = {}; - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.id) - pluginMap[plugin.id] = true; - if (plugin.name) - pluginMap[plugin.name] = true; - } - var updated = root.allPlugins.map(p => { - var isInstalled = pluginMap[p.name] || pluginMap[p.id] || false; - return Object.assign({}, p, { - "installed": isInstalled - }); - }); - root.allPlugins = updated; - root.updateFilteredPlugins(); - } - } - - ConfirmModal { - id: urlInstallConfirm - } - - FocusScope { - id: browserKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - } - } - - Item { - id: browserContent - anchors.fill: parent - anchors.margins: Theme.spacingL - - Item { - id: headerArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: Math.max(headerIcon.height, headerText.height, refreshButton.height, closeButton.height) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - DankIcon { - id: headerIcon - name: "store" - size: Theme.iconSize - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: headerText - text: I18n.tr("Browse Plugins", "plugin browser header") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.left: headerIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankButton { - id: thirdPartyButton - text: SessionData.showThirdPartyPlugins ? I18n.tr("Hide 3rd Party") : I18n.tr("Show 3rd Party") - iconName: SessionData.showThirdPartyPlugins ? "visibility_off" : "visibility" - height: 28 - onClicked: { - if (SessionData.showThirdPartyPlugins) { - SessionData.setShowThirdPartyPlugins(false); - root.updateFilteredPlugins(); - return; - } - thirdPartyConfirmLoader.active = true; - if (thirdPartyConfirmLoader.item) - thirdPartyConfirmLoader.item.show(); - } - } - - DankActionButton { - id: refreshButton - iconName: "refresh" - iconSize: 18 - iconColor: Theme.primary - visible: !root.isLoading - onClicked: root.refreshPlugins() - } - - DankActionButton { - visible: windowControls.supported - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: root.hide() - } - } - } - - StyledText { - id: descriptionText - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerArea.bottom - anchors.topMargin: Theme.spacingM - text: I18n.tr("Install plugins from the DMS plugin registry", "plugin browser description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - DankTextField { - id: browserSearchField - anchors.left: parent.left - anchors.right: parent.right - anchors.top: descriptionText.bottom - anchors.topMargin: Theme.spacingM - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search plugins...", "plugin search placeholder") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [browserKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredPlugins(); - } - } - - Item { - id: listArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: browserSearchField.bottom - anchors.topMargin: Theme.spacingM - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingM - - Item { - anchors.fill: parent - visible: root.isLoading - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "sync" - size: 48 - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - - RotationAnimator on rotation { - from: 0 - to: -360 - duration: 1000 - loops: Animation.Infinite - running: root.isLoading - } - } - - StyledText { - text: I18n.tr("Loading...", "loading indicator") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - DankListView { - id: pluginBrowserList - - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingS - model: ScriptModel { - values: root.filteredPlugins - } - clip: true - visible: !root.isLoading - add: null - displaced: null - - ScrollBar.vertical: DankScrollbar { - id: browserScrollbar - } - - delegate: Rectangle { - width: pluginBrowserList.width - height: pluginDelegateColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - property bool isInstalled: modelData.installed || false - property bool isFirstParty: modelData.firstParty || false - property bool isFeatured: modelData.featured || false - property bool isCompatible: PluginService.checkPluginCompatibility(modelData.requires_dms) - color: isSelected ? Theme.primarySelected : Theme.withAlpha(Theme.surfaceVariant, 0.3) - border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2) - border.width: isSelected ? 2 : 1 - - Column { - id: pluginDelegateColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon || "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - installButton.width - Theme.spacingM - spacing: 2 - - Row { - spacing: Theme.spacingXS - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - height: 16 - width: featuredRow.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.secondary, 0.15) - border.color: Theme.withAlpha(Theme.secondary, 0.4) - border.width: 1 - visible: isFeatured - anchors.verticalCenter: parent.verticalCenter - - Row { - id: featuredRow - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: "star" - size: 10 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("featured") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - height: 16 - width: firstPartyText.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.primary, 0.15) - border.color: Theme.withAlpha(Theme.primary, 0.4) - border.width: 1 - visible: isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: firstPartyText - anchors.centerIn: parent - text: I18n.tr("official") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - font.weight: Font.Medium - } - } - - Rectangle { - height: 16 - width: thirdPartyText.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.warning, 0.15) - border.color: Theme.withAlpha(Theme.warning, 0.4) - border.width: 1 - visible: !isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: thirdPartyText - anchors.centerIn: parent - text: I18n.tr("3rd party") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.warning - font.weight: Font.Medium - } - } - } - - StyledText { - text: { - const author = I18n.tr("by %1", "author attribution").arg(modelData.author || I18n.tr("Unknown", "unknown author")); - const source = modelData.repo ? ` • ${I18n.tr("source", "source code link")}` : ""; - return author + source; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - linkColor: Theme.primary - textFormat: Text.RichText - elide: Text.ElideRight - width: parent.width - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - - Rectangle { - id: installButton - - property string buttonState: { - if (isInstalled) - return "installed"; - if (!isCompatible) - return "incompatible"; - return "available"; - } - - width: buttonState === "incompatible" ? incompatRow.implicitWidth + Theme.spacingM * 2 : 80 - height: 32 - radius: Theme.cornerRadius - anchors.verticalCenter: parent.verticalCenter - color: { - switch (buttonState) { - case "installed": - return Theme.surfaceVariant; - case "incompatible": - return Theme.withAlpha(Theme.warning, 0.15); - default: - return Theme.primary; - } - } - opacity: buttonState === "available" && installMouseArea.containsMouse ? 0.9 : 1 - border.width: buttonState !== "available" ? 1 : 0 - border.color: buttonState === "incompatible" ? Theme.warning : Theme.outline - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: incompatRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: { - switch (installButton.buttonState) { - case "installed": - return "check"; - case "incompatible": - return "warning"; - default: - return "download"; - } - } - size: 14 - color: { - switch (installButton.buttonState) { - case "installed": - return Theme.surfaceText; - case "incompatible": - return Theme.warning; - default: - return Theme.surface; - } - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - switch (installButton.buttonState) { - case "installed": - return I18n.tr("Installed", "installed status"); - case "incompatible": - return I18n.tr("Requires %1", "version requirement").arg(modelData.requires_dms); - default: - return I18n.tr("Install", "install action button"); - } - } - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: { - switch (installButton.buttonState) { - case "installed": - return Theme.surfaceText; - case "incompatible": - return Theme.warning; - default: - return Theme.surface; - } - } - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: installMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: installButton.buttonState === "available" ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: installButton.buttonState === "available" - onClicked: { - const isDesktop = modelData.type === "desktop"; - root.installPlugin(modelData.name, isDesktop); - } - } - } - } - - StyledText { - text: modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - visible: modelData.description && modelData.description.length > 0 - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: modelData.capabilities && modelData.capabilities.length > 0 - - Repeater { - model: modelData.capabilities || [] - - Rectangle { - height: 18 - width: capabilityText.implicitWidth + Theme.spacingXS * 2 - radius: 9 - color: Theme.withAlpha(Theme.primary, 0.1) - border.color: Theme.withAlpha(Theme.primary, 0.3) - border.width: 1 - - StyledText { - id: capabilityText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - } - } - } - } - - StyledText { - anchors.centerIn: listArea - text: I18n.tr("No plugins found", "empty plugin list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !root.isLoading && root.filteredPlugins.length === 0 - } - } - } - } - - LazyLoader { - id: thirdPartyConfirmLoader - active: false - - FloatingWindow { - id: thirdPartyConfirmModal - - property bool disablePopupTransparency: true - - function show() { - visible = true; - } - - function hide() { - visible = false; - } - - objectName: "thirdPartyConfirm" - title: I18n.tr("Third-Party Plugin Warning") - implicitWidth: 500 - implicitHeight: 350 - color: Theme.surfaceContainer - visible: false - - FocusScope { - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - thirdPartyConfirmModal.hide(); - event.accepted = true; - } - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Third-Party Plugin Warning") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - parent.spacing * 2 - Theme.iconSize - parent.children[1].implicitWidth - closeConfirmBtn.width - height: 1 - } - - DankActionButton { - id: closeConfirmBtn - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - anchors.verticalCenter: parent.verticalCenter - onClicked: thirdPartyConfirmModal.hide() - } - } - - StyledText { - width: parent.width - text: I18n.tr("Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - wrapMode: Text.WordWrap - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("• Plugins may contain bugs or security issues") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("• Review code before installation when possible") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("• Install only from trusted sources") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Item { - width: parent.width - height: parent.height - parent.spacing * 3 - y - } - - Row { - anchors.right: parent.right - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Cancel") - iconName: "close" - onClicked: thirdPartyConfirmModal.hide() - } - - DankButton { - text: I18n.tr("I Understand") - iconName: "check" - onClicked: { - SessionData.setShowThirdPartyPlugins(true); - root.updateFilteredPlugins(); - thirdPartyConfirmModal.hide(); - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml deleted file mode 100644 index 39a5d1e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml +++ /dev/null @@ -1,439 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var pluginData: null - property string expandedPluginId: "" - property bool hasUpdate: false - property bool isReloading: false - property var sharedTooltip: null - - property string pluginId: pluginData ? pluginData.id : "" - property string pluginDirectoryName: { - if (pluginData && pluginData.pluginDirectory) { - var path = pluginData.pluginDirectory; - return path.substring(path.lastIndexOf('/') + 1); - } - return pluginId; - } - property string pluginName: pluginData ? (pluginData.name || pluginData.id) : "" - property string pluginVersion: pluginData ? (pluginData.version || "1.0.0") : "" - property string pluginAuthor: pluginData ? (pluginData.author || "Unknown") : "" - property string pluginDescription: pluginData ? (pluginData.description || "") : "" - property string pluginIcon: pluginData ? (pluginData.icon || "extension") : "extension" - property string pluginSettingsPath: pluginData ? (pluginData.settingsPath || "") : "" - property var pluginPermissions: pluginData ? (pluginData.permissions || []) : [] - property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== "" - property bool isDesktopPlugin: pluginData ? (pluginData.type === "desktop") : false - property bool showSettings: hasSettings && !isDesktopPlugin - property bool isSystemPlugin: pluginData ? (pluginData.source === "system") : false - property string requiresDms: pluginData ? (pluginData.requires_dms || "") : "" - property bool meetsRequirements: requiresDms ? PluginService.checkPluginCompatibility(requiresDms) : true - - Connections { - target: SystemUpdateService - function onSemverVersionChanged() { - root.meetsRequirementsChanged(); - } - } - property bool isExpanded: expandedPluginId === pluginId - property bool isLoaded: { - PluginService.loadedPlugins; - return PluginService.loadedPlugins[pluginId] !== undefined; - } - - width: parent.width - height: pluginItemColumn.implicitHeight + Theme.spacingM * 2 + settingsContainer.height - radius: Theme.cornerRadius - color: (pluginMouseArea.containsMouse || updateArea.containsMouse || uninstallArea.containsMouse || reloadArea.containsMouse) ? Theme.surfacePressed : (isExpanded ? Theme.surfaceContainerHighest : Theme.surfaceContainerHigh) - border.width: 0 - - MouseArea { - id: pluginMouseArea - anchors.fill: parent - anchors.bottomMargin: root.isExpanded ? settingsContainer.height : 0 - hoverEnabled: true - cursorShape: root.showSettings ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: root.showSettings - onClicked: { - root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId; - } - } - - Column { - id: pluginItemColumn - width: parent.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.pluginIcon - size: Theme.iconSize - color: root.isLoaded ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - toggleRow.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingXS - width: parent.width - - StyledText { - text: root.pluginName - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - width: incompatIcon.width + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.error, 0.15) - visible: !root.meetsRequirements - anchors.verticalCenter: parent.verticalCenter - - Row { - anchors.centerIn: parent - spacing: 2 - - DankIcon { - id: incompatIcon - name: "warning" - size: 12 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Requires DMS %1").arg(root.requiresDms), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - DankIcon { - name: root.showSettings ? (root.isExpanded ? "expand_less" : "expand_more") : "" - size: 16 - color: root.showSettings ? Theme.primary : "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: root.showSettings - } - - Rectangle { - width: desktopLabel.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - visible: root.isDesktopPlugin - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: desktopLabel - anchors.centerIn: parent - text: I18n.tr("Desktop Widget") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - } - } - } - - StyledText { - text: I18n.tr("v%1 by %2").arg(root.pluginVersion).arg(root.pluginAuthor) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: toggleRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: updateArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: DMSService.dmsAvailable && root.isLoaded && root.hasUpdate && !root.isSystemPlugin - - DankIcon { - anchors.centerIn: parent - name: "download" - size: 16 - color: updateArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: updateArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginName = root.pluginName; - const currentPluginId = root.pluginId; - DMSService.update(currentPluginName, response => { - if (response.error) { - ToastService.showError("Update failed: " + response.error); - return; - } - ToastService.showInfo("Plugin updated: " + currentPluginName); - PluginService.forceRescanPlugin(currentPluginId); - if (DMSService.apiVersion >= 8) - DMSService.listInstalled(); - }); - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Update Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: uninstallArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: DMSService.dmsAvailable && !root.isSystemPlugin - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 16 - color: uninstallArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: uninstallArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginName = root.pluginName; - DMSService.uninstall(currentPluginName, response => { - if (response.error) { - ToastService.showError("Uninstall failed: " + response.error); - return; - } - ToastService.showInfo("Plugin uninstalled: " + currentPluginName); - PluginService.scanPlugins(); - if (root.isExpanded) - root.expandedPluginId = ""; - }); - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Uninstall Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: reloadArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: root.isLoaded - - DankIcon { - anchors.centerIn: parent - name: "refresh" - size: 16 - color: reloadArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: reloadArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginId = root.pluginId; - const currentPluginName = root.pluginName; - root.isReloading = true; - if (PluginService.reloadPlugin(currentPluginId)) { - ToastService.showInfo("Plugin reloaded: " + currentPluginName); - return; - } - ToastService.showError("Failed to reload plugin: " + currentPluginName); - root.isReloading = false; - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Reload Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - DankToggle { - id: pluginToggle - anchors.verticalCenter: parent.verticalCenter - checked: root.isLoaded - onToggled: isChecked => { - const currentPluginId = root.pluginId; - const currentPluginName = root.pluginName; - - if (isChecked) { - if (PluginService.enablePlugin(currentPluginId)) { - ToastService.showInfo("Plugin enabled: " + currentPluginName); - return; - } - ToastService.showError("Failed to enable plugin: " + currentPluginName); - return; - } - if (PluginService.disablePlugin(currentPluginId)) { - ToastService.showInfo("Plugin disabled: " + currentPluginName); - if (root.isExpanded) - root.expandedPluginId = ""; - return; - } - ToastService.showError("Failed to disable plugin: " + currentPluginName); - } - } - } - } - - StyledText { - width: parent.width - text: root.pluginDescription - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - visible: root.pluginDescription !== "" - horizontalAlignment: Text.AlignLeft - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: root.pluginPermissions && Array.isArray(root.pluginPermissions) && root.pluginPermissions.length > 0 - - Repeater { - model: root.pluginPermissions - - Rectangle { - height: 20 - width: permissionText.implicitWidth + Theme.spacingXS * 2 - radius: 10 - color: Theme.withAlpha(Theme.primary, 0.1) - border.color: Theme.withAlpha(Theme.primary, 0.3) - border.width: 1 - - StyledText { - id: permissionText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.primary - } - } - } - } - } - - FocusScope { - id: settingsContainer - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: root.isExpanded && root.showSettings ? (settingsLoader.item ? settingsLoader.item.implicitHeight + Theme.spacingL * 2 : 0) : 0 - clip: true - focus: root.isExpanded && root.showSettings - - Keys.onPressed: event => { - event.accepted = true; - } - - Rectangle { - anchors.fill: parent - color: Theme.surfaceContainerHighest - radius: Theme.cornerRadius - anchors.topMargin: Theme.spacingXS - border.width: 0 - } - - Loader { - id: settingsLoader - anchors.fill: parent - anchors.margins: Theme.spacingL - active: root.isExpanded && root.showSettings && root.isLoaded - asynchronous: false - - source: { - if (active && root.pluginSettingsPath) { - var path = root.pluginSettingsPath; - if (!path.startsWith("file://")) { - path = "file://" + path; - } - return path; - } - return ""; - } - - onLoaded: { - if (item && typeof PluginService !== "undefined") { - item.pluginService = PluginService; - } - if (item && typeof PopoutService !== "undefined" && "popoutService" in item) { - item.popoutService = PopoutService; - } - if (item) { - Qt.callLater(() => { - settingsContainer.focus = true; - item.forceActiveFocus(); - }); - } - } - } - - StyledText { - anchors.centerIn: parent - text: !root.isLoaded ? "Enable plugin to access settings" : (settingsLoader.status === Loader.Error ? "Failed to load settings" : "No configurable settings") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: root.isExpanded && (!settingsLoader.active || settingsLoader.status === Loader.Error) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml deleted file mode 100644 index 1f83a0f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml +++ /dev/null @@ -1,450 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FocusScope { - id: pluginsTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string expandedPluginId: "" - property bool isRefreshingPlugins: false - property var parentModal: null - property var installedPluginsData: ({}) - property bool isReloading: false - property alias sharedTooltip: sharedTooltip - - focus: true - - DankTooltipV2 { - id: sharedTooltip - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: headerColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: headerColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Plugin Management") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Manage and configure plugins for extending DMS functionality") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - width: parent.width - height: dmsWarningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.warning, 0.1) - border.color: Theme.warning - border.width: 1 - visible: !DMSService.dmsAvailable - - Column { - id: dmsWarningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "warning" - size: 16 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("DMS Plugin Manager Unavailable") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - id: incompatWarning - property var incompatPlugins: [] - width: parent.width - height: incompatWarningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.error, 0.1) - border.color: Theme.error - border.width: 1 - visible: incompatPlugins.length > 0 - - function refresh() { - incompatPlugins = PluginService.getIncompatiblePlugins(); - } - - Component.onCompleted: Qt.callLater(refresh) - - Column { - id: incompatWarningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "error" - size: 16 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Incompatible Plugins Loaded") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("Some plugins require a newer version of DMS:") + " " + incompatWarning.incompatPlugins.map(p => p.name + " (" + p.requires_dms + ")").join(", ") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Connections { - target: PluginService - function onPluginLoaded() { - incompatWarning.refresh(); - } - function onPluginUnloaded() { - incompatWarning.refresh(); - } - } - - Connections { - target: SystemUpdateService - function onSemverVersionChanged() { - incompatWarning.refresh(); - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Browse") - iconName: "store" - enabled: DMSService.dmsAvailable - onClicked: { - showPluginBrowser(); - } - } - - DankButton { - text: I18n.tr("Scan") - iconName: "refresh" - onClicked: { - pluginsTab.isRefreshingPlugins = true; - PluginService.scanPlugins(); - if (DMSService.dmsAvailable) { - DMSService.listInstalled(); - } - pluginsTab.refreshPluginList(); - } - } - - DankButton { - text: I18n.tr("Create Dir") - iconName: "create_new_folder" - onClicked: { - PluginService.createPluginDirectory(); - ToastService.showInfo("Created plugin directory: " + PluginService.pluginDirectory); - } - } - } - } - } - - StyledRect { - width: parent.width - height: directoryColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: directoryColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Plugin Directory") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: PluginService.pluginDirectory - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.family: "monospace" - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Place plugin directories here. Each plugin should have a plugin.json manifest file.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - width: parent.width - height: Math.max(200, availableColumn.implicitHeight + Theme.spacingL * 2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: availableColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Plugins") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Column { - width: parent.width - spacing: Theme.spacingM - - Repeater { - id: pluginRepeater - model: PluginService.availablePluginsList - - PluginListItem { - pluginData: modelData - expandedPluginId: pluginsTab.expandedPluginId - hasUpdate: { - if (DMSService.apiVersion < 8) - return false; - return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false; - } - isReloading: pluginsTab.isReloading - sharedTooltip: pluginsTab.sharedTooltip - onExpandedPluginIdChanged: { - pluginsTab.expandedPluginId = expandedPluginId; - } - onIsReloadingChanged: { - pluginsTab.isReloading = isReloading; - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No plugins found.") + "\n" + I18n.tr("Place plugins in %1").arg(PluginService.pluginDirectory) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: pluginRepeater.model && pluginRepeater.model.length === 0 - } - } - } - } - } - } - - function refreshPluginList() { - pluginsTab.isRefreshingPlugins = false; - } - - Connections { - target: PluginService - function onPluginLoaded() { - refreshPluginList(); - if (isReloading) { - isReloading = false; - } - } - function onPluginUnloaded() { - refreshPluginList(); - if (!isReloading && pluginsTab.expandedPluginId !== "" && !PluginService.isPluginLoaded(pluginsTab.expandedPluginId)) { - pluginsTab.expandedPluginId = ""; - } - } - function onPluginListUpdated() { - if (DMSService.apiVersion >= 8) { - DMSService.listInstalled(); - } - refreshPluginList(); - } - function onPluginDataChanged(pluginId) { - var plugin = PluginService.availablePlugins[pluginId]; - if (!plugin || !PluginService.isPluginLoaded(pluginId)) - return; - var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); - if (isLauncher) { - pluginsTab.isReloading = true; - PluginService.reloadPlugin(pluginId); - } - } - } - - Connections { - target: DMSService - function onPluginsListReceived(plugins) { - if (!pluginBrowserLoader.item) - return; - pluginBrowserLoader.item.isLoading = false; - pluginBrowserLoader.item.allPlugins = plugins; - pluginBrowserLoader.item.updateFilteredPlugins(); - } - function onInstalledPluginsReceived(plugins) { - var pluginMap = {}; - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - var hasUpdate = plugin.hasUpdate || false; - if (plugin.id) { - pluginMap[plugin.id] = hasUpdate; - } - if (plugin.name) { - pluginMap[plugin.name] = hasUpdate; - } - } - installedPluginsData = pluginMap; - Qt.callLater(refreshPluginList); - } - function onOperationSuccess(message) { - ToastService.showInfo(message); - } - function onOperationError(error) { - ToastService.showError(error); - } - } - - Component.onCompleted: { - if (DMSService.dmsAvailable && DMSService.apiVersion >= 8) - DMSService.listInstalled(); - if (PopoutService.pendingPluginInstall) - Qt.callLater(showPluginBrowser); - } - - Connections { - target: PopoutService - function onPendingPluginInstallChanged() { - if (PopoutService.pendingPluginInstall) - showPluginBrowser(); - } - } - - LazyLoader { - id: pluginBrowserLoader - active: false - - PluginBrowser { - id: pluginBrowserItem - - Component.onCompleted: { - pluginBrowserItem.parentModal = pluginsTab.parentModal; - } - } - } - - function showPluginBrowser() { - pluginBrowserLoader.active = true; - if (pluginBrowserLoader.item) - pluginBrowserLoader.item.show(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml deleted file mode 100644 index 7282d34..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml +++ /dev/null @@ -1,598 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property var timeoutOptions: [I18n.tr("Never"), I18n.tr("1 minute"), I18n.tr("2 minutes"), I18n.tr("3 minutes"), I18n.tr("5 minutes"), I18n.tr("10 minutes"), I18n.tr("15 minutes"), I18n.tr("20 minutes"), I18n.tr("30 minutes"), I18n.tr("1 hour"), I18n.tr("1 hour 30 minutes"), I18n.tr("2 hours"), I18n.tr("3 hours")] - readonly property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800] - - function getTimeoutIndex(timeout) { - var idx = timeoutValues.indexOf(timeout); - return idx >= 0 ? idx : 0; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "schedule" - title: I18n.tr("Idle Settings") - settingKey: "idleSettings" - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Power source") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - - Item { - width: Theme.spacingS - height: 1 - visible: BatteryService.batteryAvailable - } - - DankButtonGroup { - id: powerCategory - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - model: [I18n.tr("AC Power"), I18n.tr("Battery")] - currentIndex: 0 - selectionMode: "single" - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - } - } - } - - SettingsToggleRow { - settingKey: "fadeToLockEnabled" - tags: ["fade", "lock", "screen", "idle", "grace period"] - text: I18n.tr("Fade to lock screen") - description: I18n.tr("Gradually fade the screen before locking with a configurable grace period") - checked: SettingsData.fadeToLockEnabled - onToggled: checked => SettingsData.set("fadeToLockEnabled", checked) - } - - SettingsToggleRow { - settingKey: "fadeToDpmsEnabled" - tags: ["fade", "dpms", "monitor", "screen", "idle", "grace period"] - text: I18n.tr("Fade to monitor off") - description: I18n.tr("Gradually fade the screen before turning off monitors with a configurable grace period") - checked: SettingsData.fadeToDpmsEnabled - onToggled: checked => SettingsData.set("fadeToDpmsEnabled", checked) - } - - SettingsToggleRow { - settingKey: "lockBeforeSuspend" - tags: ["lock", "suspend", "sleep", "security"] - text: I18n.tr("Lock before suspend") - description: I18n.tr("Automatically lock the screen when the system prepares to suspend") - checked: SettingsData.lockBeforeSuspend - visible: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - onToggled: checked => SettingsData.set("lockBeforeSuspend", checked) - } - - SettingsDropdownRow { - id: fadeGracePeriodDropdown - settingKey: "fadeToLockGracePeriod" - tags: ["fade", "grace", "period", "timeout", "lock"] - property var periodOptions: [I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("4 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds"), I18n.tr("15 seconds"), I18n.tr("20 seconds"), I18n.tr("30 seconds")] - property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30] - - text: I18n.tr("Lock fade grace period") - options: periodOptions - visible: SettingsData.fadeToLockEnabled - enabled: SettingsData.fadeToLockEnabled - - Component.onCompleted: { - const currentPeriod = SettingsData.fadeToLockGracePeriod; - const index = periodValues.indexOf(currentPeriod); - currentValue = index >= 0 ? periodOptions[index] : I18n.tr("5 seconds"); - } - - onValueChanged: value => { - const index = periodOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("fadeToLockGracePeriod", periodValues[index]); - } - } - - SettingsDropdownRow { - id: fadeDpmsGracePeriodDropdown - settingKey: "fadeToDpmsGracePeriod" - tags: ["fade", "grace", "period", "timeout", "dpms", "monitor"] - property var periodOptions: [I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("4 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds"), I18n.tr("15 seconds"), I18n.tr("20 seconds"), I18n.tr("30 seconds")] - property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30] - - text: I18n.tr("Monitor fade grace period") - options: periodOptions - visible: SettingsData.fadeToDpmsEnabled - enabled: SettingsData.fadeToDpmsEnabled - - Component.onCompleted: { - const currentPeriod = SettingsData.fadeToDpmsGracePeriod; - const index = periodValues.indexOf(currentPeriod); - currentValue = index >= 0 ? periodOptions[index] : I18n.tr("5 seconds"); - } - - onValueChanged: value => { - const index = periodOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("fadeToDpmsGracePeriod", periodValues[index]); - } - } - SettingsDropdownRow { - id: powerProfileDropdown - settingKey: "powerProfile" - tags: ["power", "profile", "performance", "balanced", "saver", "battery"] - property var profileOptions: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)] - property var profileValues: ["", "0", "1", "2"] - - width: parent.width - addHorizontalPadding: true - text: I18n.tr("Switch to power profile") - options: profileOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentProfile = powerCategory.currentIndex === 0 ? SettingsData.acProfileName : SettingsData.batteryProfileName; - const index = powerProfileDropdown.profileValues.indexOf(currentProfile); - powerProfileDropdown.currentValue = powerProfileDropdown.profileOptions[index]; - } - } - - Component.onCompleted: { - const currentProfile = powerCategory.currentIndex === 0 ? SettingsData.acProfileName : SettingsData.batteryProfileName; - const index = profileValues.indexOf(currentProfile); - currentValue = profileOptions[index]; - } - - onValueChanged: value => { - const index = profileOptions.indexOf(value); - if (index >= 0) { - const profileValue = profileValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acProfileName", profileValue); - } else { - SettingsData.set("batteryProfileName", profileValue); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - id: lockDropdown - settingKey: "lockTimeout" - tags: ["lock", "timeout", "idle", "automatic", "security"] - text: I18n.tr("Automatically lock after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout; - lockDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acLockTimeout", timeout); - } else { - SettingsData.set("batteryLockTimeout", timeout); - } - } - } - - SettingsDropdownRow { - id: monitorDropdown - settingKey: "monitorTimeout" - tags: ["monitor", "display", "screen", "timeout", "off", "idle"] - text: I18n.tr("Turn off monitors after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout; - monitorDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acMonitorTimeout", timeout); - } else { - SettingsData.set("batteryMonitorTimeout", timeout); - } - } - } - - SettingsDropdownRow { - id: suspendDropdown - settingKey: "suspendTimeout" - tags: ["suspend", "sleep", "timeout", "idle", "system"] - text: I18n.tr("Suspend system after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout; - suspendDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acSuspendTimeout", timeout); - } else { - SettingsData.set("batterySuspendTimeout", timeout); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SessionService.hibernateSupported - - StyledText { - text: I18n.tr("Suspend behavior") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - leftPadding: Theme.spacingM - } - - DankButtonGroup { - id: suspendBehaviorSelector - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Suspend"), I18n.tr("Hibernate"), I18n.tr("Suspend then Hibernate")] - selectionMode: "single" - checkEnabled: false - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior; - suspendBehaviorSelector.currentIndex = behavior; - } - } - - Component.onCompleted: { - const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior; - currentIndex = behavior; - } - - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acSuspendBehavior", index); - } else { - SettingsData.set("batterySuspendBehavior", index); - } - } - } - } - - StyledText { - text: I18n.tr("Idle monitoring not supported - requires newer Quickshell version") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - visible: !IdleService.idleMonitorAvailable - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Power Menu Customization") - settingKey: "powerMenu" - - StyledText { - text: I18n.tr("Customize which actions appear in the power menu") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "powerMenuGridLayout" - tags: ["power", "menu", "grid", "layout", "list"] - text: I18n.tr("Use Grid Layout") - description: I18n.tr("Display power menu actions in a grid instead of a list") - checked: SettingsData.powerMenuGridLayout - onToggled: checked => SettingsData.set("powerMenuGridLayout", checked) - } - - SettingsDropdownRow { - id: defaultActionDropdown - settingKey: "powerMenuDefaultAction" - tags: ["power", "menu", "default", "action", "reboot", "logout", "shutdown"] - text: I18n.tr("Default selected action") - options: [I18n.tr("Reboot"), I18n.tr("Log Out"), I18n.tr("Power Off"), I18n.tr("Lock"), I18n.tr("Suspend"), I18n.tr("Restart DMS"), I18n.tr("Hibernate")] - property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"] - - Component.onCompleted: { - const currentAction = SettingsData.powerMenuDefaultAction || "logout"; - const index = actionValues.indexOf(currentAction); - currentValue = index >= 0 ? options[index] : I18n.tr("Log Out"); - } - - onValueChanged: value => { - const index = options.indexOf(value); - if (index < 0) - return; - SettingsData.set("powerMenuDefaultAction", actionValues[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: [ - { - key: "reboot", - label: I18n.tr("Show Reboot") - }, - { - key: "logout", - label: I18n.tr("Show Log Out") - }, - { - key: "poweroff", - label: I18n.tr("Show Power Off") - }, - { - key: "lock", - label: I18n.tr("Show Lock") - }, - { - key: "suspend", - label: I18n.tr("Show Suspend") - }, - { - key: "restart", - label: I18n.tr("Show Restart DMS"), - desc: I18n.tr("Restart the DankMaterialShell") - }, - { - key: "hibernate", - label: I18n.tr("Show Hibernate"), - desc: I18n.tr("Only visible if hibernate is supported by your system"), - hibernate: true - } - ] - - SettingsToggleRow { - required property var modelData - settingKey: "powerMenuAction_" + modelData.key - tags: ["power", "menu", "action", "show", modelData.key] - text: modelData.label - description: modelData.desc || "" - visible: !modelData.hibernate || SessionService.hibernateSupported - checked: SettingsData.powerMenuActions.includes(modelData.key) - onToggled: checked => { - let actions = [...SettingsData.powerMenuActions]; - if (checked && !actions.includes(modelData.key)) { - actions.push(modelData.key); - } else if (!checked) { - actions = actions.filter(a => a !== modelData.key); - } - SettingsData.set("powerMenuActions", actions); - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "check_circle" - title: I18n.tr("Power Action Confirmation") - settingKey: "powerConfirmation" - - SettingsToggleRow { - settingKey: "powerActionConfirm" - tags: ["power", "confirm", "hold", "button", "safety"] - text: I18n.tr("Hold to Confirm Power Actions") - description: I18n.tr("Require holding button/key to confirm power off, restart, suspend, hibernate and logout") - checked: SettingsData.powerActionConfirm - onToggled: checked => SettingsData.set("powerActionConfirm", checked) - } - - SettingsDropdownRow { - id: holdDurationDropdown - settingKey: "powerActionHoldDuration" - tags: ["power", "hold", "duration", "confirm", "time"] - property var durationOptions: [I18n.tr("250 ms"), I18n.tr("500 ms"), I18n.tr("750 ms"), I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds")] - property var durationValues: [0.25, 0.5, 0.75, 1, 2, 3, 5, 10] - - text: I18n.tr("Hold Duration") - options: durationOptions - visible: SettingsData.powerActionConfirm - - Component.onCompleted: { - const currentDuration = SettingsData.powerActionHoldDuration; - const index = durationValues.indexOf(currentDuration); - currentValue = index >= 0 ? durationOptions[index] : I18n.tr("500 ms"); - } - - onValueChanged: value => { - const index = durationOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("powerActionHoldDuration", durationValues[index]); - } - } - } - - SettingsCard { - width: parent.width - iconName: "developer_mode" - title: I18n.tr("Custom Power Actions") - settingKey: "customPowerActions" - - Repeater { - model: [ - { - key: "customPowerActionLock", - label: I18n.tr("Custom Lock Command"), - placeholder: "/usr/bin/myLock.sh" - }, - { - key: "customPowerActionLogout", - label: I18n.tr("Custom Logout Command"), - placeholder: "/usr/bin/myLogout.sh" - }, - { - key: "customPowerActionSuspend", - label: I18n.tr("Custom Suspend Command"), - placeholder: "/usr/bin/mySuspend.sh" - }, - { - key: "customPowerActionHibernate", - label: I18n.tr("Custom Hibernate Command"), - placeholder: "/usr/bin/myHibernate.sh" - }, - { - key: "customPowerActionReboot", - label: I18n.tr("Custom Reboot Command"), - placeholder: "/usr/bin/myReboot.sh" - }, - { - key: "customPowerActionPowerOff", - label: I18n.tr("Custom Power Off Command"), - placeholder: "/usr/bin/myPowerOff.sh" - } - ] - - Column { - required property var modelData - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - placeholderText: modelData.placeholder - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - var val = SettingsData[modelData.key]; - if (val) - text = val; - } - - onTextEdited: { - SettingsData.set(modelData.key, text.trim()); - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Advanced") - settingKey: "powerAdvanced" - collapsible: true - expanded: false - - SettingsSliderRow { - settingKey: "batteryChargeLimit" - tags: ["battery", "charge", "limit", "percentage", "power"] - text: I18n.tr("Battery Charge Limit") - description: I18n.tr("Note: this only changes the percentage, it does not actually limit charging.") - value: SettingsData.batteryChargeLimit - minimum: 50 - maximum: 100 - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("batteryChargeLimit", newValue) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml deleted file mode 100644 index 437dc47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml +++ /dev/null @@ -1,1702 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -Item { - id: printerTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool showAddPrinter: false - property bool manualEntryMode: false - property string manualHost: "" - property string manualPort: "631" - property string manualProtocol: "ipp" - property bool testingConnection: false - property var testConnectionResult: null - property string newPrinterName: "" - property string selectedDeviceUri: "" - property var selectedDevice: null - property string selectedPpd: "" - property string newPrinterLocation: "" - property string newPrinterInfo: "" - property var suggestedPPDs: [] - - function resetAddPrinterForm() { - manualEntryMode = false; - manualHost = ""; - manualPort = "631"; - manualProtocol = "ipp"; - testingConnection = false; - testConnectionResult = null; - newPrinterName = ""; - selectedDeviceUri = ""; - selectedDevice = null; - selectedPpd = ""; - newPrinterLocation = ""; - newPrinterInfo = ""; - suggestedPPDs = []; - } - - Connections { - target: CupsService - function onPpdsChanged() { - if (printerTab.manualEntryMode && printerTab.testConnectionResult?.success) - printerTab.selectDriverlessPPD(); - } - } - - function selectDriverlessPPD() { - if (printerTab.selectedPpd || CupsService.ppds.length === 0) - return; - - const probeModel = printerTab.testConnectionResult?.data?.makeModel || ""; - let suggested = []; - - // Try to find a model-specific PPD match - if (probeModel) { - const normalizedModel = probeModel.toLowerCase().replace(/[^a-z0-9]/g, ""); - const modelMatches = CupsService.ppds.filter(p => { - const normalizedPPD = (p.makeModel || "").toLowerCase().replace(/[^a-z0-9]/g, ""); - return normalizedPPD.includes(normalizedModel) || normalizedModel.includes(normalizedPPD); - }); - if (modelMatches.length > 0) - suggested = suggested.concat(modelMatches); - } - - // Always include driverless as an option - const driverless = CupsService.ppds.filter(p => p.name === "driverless" || p.name === "everywhere"); - for (const d of driverless) { - if (!suggested.find(s => s.name === d.name)) - suggested.push(d); - } - - if (suggested.length > 0) { - printerTab.selectedPpd = suggested[0].name; - printerTab.suggestedPPDs = suggested; - } - } - - function selectDevice(device) { - if (!device) - return; - selectedDevice = device; - selectedDeviceUri = device.uri; - if (!newPrinterName) { - newPrinterName = CupsService.suggestPrinterName(device); - } - if (device.location && !newPrinterLocation) { - newPrinterLocation = CupsService.decodeUri(device.location); - } - suggestedPPDs = CupsService.getMatchingPPDs(device); - if (suggestedPPDs.length > 0 && !selectedPpd) { - selectedPpd = suggestedPPDs[0].name; - } - } - - Component.onCompleted: { - CupsService.getClasses(); - } - - ConfirmModal { - id: deletePrinterConfirm - } - - ConfirmModal { - id: purgeJobsConfirm - } - - ConfirmModal { - id: deleteClassConfirm - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(600, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: overviewSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: overviewSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "print" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("CUPS Print Server") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Grid { - columns: 2 - columnSpacing: Theme.spacingL - rowSpacing: Theme.spacingS - width: parent.width - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - Row { - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: CupsService.cupsAvailable ? Theme.success : Theme.error - } - - StyledText { - text: CupsService.cupsAvailable ? I18n.tr("Available") : I18n.tr("Unavailable") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - StyledText { - text: I18n.tr("Printers") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: CupsService.printerNames.length.toString() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Total Jobs") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: CupsService.getTotalJobsNum().toString() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - } - } - - StyledRect { - width: parent.width - height: addPrinterSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable - - Column { - id: addPrinterSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - addPrinterToggleBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Add Printer") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Configure a new printer") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - id: addPrinterToggleBtn - width: 28 - height: 28 - radius: 14 - color: addPrinterToggleArea.containsMouse ? Theme.surfacePressed : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: printerTab.showAddPrinter ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: addPrinterToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.showAddPrinter = !printerTab.showAddPrinter; - if (printerTab.showAddPrinter) { - if (CupsService.devices.length === 0) { - CupsService.getDevices(); - CupsService.getPPDs(); - } - } else { - printerTab.resetAddPrinterForm(); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: printerTab.showAddPrinter - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - width: discoverRow.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - color: !printerTab.manualEntryMode ? Theme.primary : (discoverArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight) - - Row { - id: discoverRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "search" - size: 16 - color: !printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Discover Devices", "Toggle button to scan for printers via mDNS/Avahi") - font.pixelSize: Theme.fontSizeSmall - color: !printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: discoverArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.manualEntryMode = false; - printerTab.testConnectionResult = null; - printerTab.testingConnection = false; - } - } - } - - Rectangle { - width: manualRow.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - color: printerTab.manualEntryMode ? Theme.primary : (manualArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight) - - Row { - id: manualRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "edit" - size: 16 - color: printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Add by Address", "Toggle button to manually add a printer by IP or hostname") - font.pixelSize: Theme.fontSizeSmall - color: printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: manualArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.manualEntryMode = true; - printerTab.selectedDevice = null; - printerTab.selectedDeviceUri = ""; - if (CupsService.ppds.length === 0) - CupsService.getPPDs(); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: !printerTab.manualEntryMode - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Device") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: deviceDropdown - dropdownWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2 - popupWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2 - enableFuzzySearch: true - emptyText: I18n.tr("No devices found") - currentValue: { - if (CupsService.loadingDevices) - return I18n.tr("Scanning..."); - if (printerTab.selectedDevice) - return CupsService.getDeviceDisplayName(printerTab.selectedDevice); - return I18n.tr("Select device..."); - } - options: CupsService.filteredDevices.map(d => CupsService.getDeviceDisplayName(d)) - onValueChanged: value => { - const filtered = CupsService.filteredDevices; - const device = filtered.find(d => CupsService.getDeviceDisplayName(d) === value); - if (device) - printerTab.selectDevice(device); - } - } - - DankActionButton { - id: scanDevicesBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - enabled: !CupsService.loadingDevices - onClicked: CupsService.getDevices() - - RotationAnimation on rotation { - running: CupsService.loadingDevices - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: printerTab.selectedDevice !== null - - Item { - width: 80 - height: 1 - } - - StyledText { - text: CupsService.getDeviceSubtitle(printerTab.selectedDevice) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - 80 - Theme.spacingS - elide: Text.ElideRight - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: printerTab.manualEntryMode - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Host", "Label for printer IP address or hostname input field") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("IP address or hostname", "Placeholder text for manual printer address input") - text: printerTab.manualHost - onTextEdited: { - printerTab.manualHost = text; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Port", "Label for printer port number input field") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: 80 - placeholderText: "631" - text: printerTab.manualPort - onTextEdited: { - printerTab.manualPort = text; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Protocol", "Label for printer protocol selector, e.g. ipp, ipps, lpd, socket") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: protocolDropdown - dropdownWidth: 120 - popupWidth: 120 - currentValue: printerTab.manualProtocol - options: ["ipp", "ipps", "lpd", "socket"] - onValueChanged: value => { - printerTab.manualProtocol = value; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Item { - width: 80 - height: 1 - } - - DankButton { - text: printerTab.testingConnection ? I18n.tr("Testing...", "Button state while testing printer connection") : I18n.tr("Test Connection", "Button to test connection to a printer by IP address") - iconName: printerTab.testingConnection ? "sync" : "lan" - buttonHeight: 36 - enabled: printerTab.manualHost.length > 0 && !printerTab.testingConnection - onClicked: { - printerTab.testingConnection = true; - printerTab.testConnectionResult = null; - const port = parseInt(printerTab.manualPort) || 631; - CupsService.testConnection(printerTab.manualHost, port, printerTab.manualProtocol, response => { - printerTab.testingConnection = false; - if (response.error) { - printerTab.testConnectionResult = { - "success": false, - "error": response.error - }; - } else if (response.result) { - printerTab.testConnectionResult = { - "success": response.result.reachable === true, - "data": response.result - }; - if (response.result.reachable) { - if (response.result.uri) - printerTab.selectedDeviceUri = response.result.uri; - if (response.result.name && !printerTab.newPrinterName) - printerTab.newPrinterName = response.result.name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 32) || "Printer"; - // Load PPDs if not loaded yet, then select driverless - if (CupsService.ppds.length === 0) { - CupsService.getPPDs(); - } - selectDriverlessPPD(); - } - } - }); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: printerTab.testConnectionResult !== null - - Row { - spacing: Theme.spacingS - - Item { - width: 80 - height: 1 - } - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: printerTab.testConnectionResult?.success ? Theme.success : Theme.error - } - - StyledText { - text: printerTab.testConnectionResult?.success ? I18n.tr("Printer reachable", "Status message when test connection to printer succeeds") : I18n.tr("Connection failed", "Status message when test connection to printer fails") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: printerTab.testConnectionResult?.success ? Theme.success : Theme.error - } - } - - Row { - spacing: Theme.spacingS - visible: printerTab.testConnectionResult?.success && (printerTab.testConnectionResult?.data?.makeModel || printerTab.testConnectionResult?.data?.info) - - Item { - width: 80 - height: 1 - } - - StyledText { - text: printerTab.testConnectionResult?.data?.makeModel || printerTab.testConnectionResult?.data?.info || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Row { - spacing: Theme.spacingS - visible: !printerTab.testConnectionResult?.success && printerTab.testConnectionResult?.data?.error - - Item { - width: 80 - height: 1 - } - - StyledText { - text: printerTab.testConnectionResult?.data?.error || printerTab.testConnectionResult?.error || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.parent.width - 80 - Theme.spacingS - wrapMode: Text.WordWrap - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Driver") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: ppdDropdown - dropdownWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2 - popupWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2 - enableFuzzySearch: true - emptyText: I18n.tr("No drivers found") - currentValue: { - if (CupsService.loadingPPDs) - return I18n.tr("Loading..."); - if (printerTab.selectedPpd) { - const ppd = CupsService.ppds.find(p => p.name === printerTab.selectedPpd); - if (ppd) { - const isSuggested = printerTab.suggestedPPDs.some(s => s.name === ppd.name); - return (isSuggested ? "★ " : "") + (ppd.makeModel || ppd.name); - } - return printerTab.selectedPpd; - } - return printerTab.suggestedPPDs.length > 0 ? I18n.tr("Recommended available") : I18n.tr("Select driver..."); - } - options: { - const suggested = printerTab.suggestedPPDs.map(p => "★ " + (p.makeModel || p.name)); - const others = CupsService.ppds.filter(p => !printerTab.suggestedPPDs.some(s => s.name === p.name)).map(p => p.makeModel || p.name); - return suggested.concat(others); - } - onValueChanged: value => { - const cleanValue = value.replace(/^★ /, ""); - const ppd = CupsService.ppds.find(p => (p.makeModel || p.name) === cleanValue); - if (ppd) - printerTab.selectedPpd = ppd.name; - } - } - - DankActionButton { - id: refreshPpdsBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - enabled: !CupsService.loadingPPDs - onClicked: CupsService.getPPDs() - - RotationAnimation on rotation { - running: CupsService.loadingPPDs - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Printer name (no spaces)") - text: printerTab.newPrinterName - onTextEdited: printerTab.newPrinterName = text.replace(/\s/g, "-") - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Location") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Optional location") - text: printerTab.newPrinterLocation - onTextEdited: printerTab.newPrinterLocation = text - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Description") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Optional description") - text: printerTab.newPrinterInfo - onTextEdited: printerTab.newPrinterInfo = text - } - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingS - layoutDirection: Qt.RightToLeft - - DankButton { - text: CupsService.creatingPrinter ? I18n.tr("Creating...") : I18n.tr("Create Printer") - iconName: CupsService.creatingPrinter ? "sync" : "add" - buttonHeight: 36 - enabled: printerTab.newPrinterName.length > 0 && printerTab.selectedDeviceUri.length > 0 && printerTab.selectedPpd.length > 0 && !CupsService.creatingPrinter - onClicked: { - CupsService.createPrinter(printerTab.newPrinterName, printerTab.selectedDeviceUri, printerTab.selectedPpd, { - location: printerTab.newPrinterLocation, - information: printerTab.newPrinterInfo - }); - printerTab.resetAddPrinterForm(); - printerTab.showAddPrinter = false; - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: printersSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable - - Column { - id: printersSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "print" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - refreshBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Printers") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const count = CupsService.printerNames.length; - if (count === 0) - return I18n.tr("No printers configured"); - return I18n.ntr("%1 printer", "%1 printers", count).arg(count); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankActionButton { - id: refreshBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - onClicked: CupsService.getState() - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Item { - width: parent.width - height: 80 - visible: CupsService.printerNames.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "print_disabled" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No printers found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: CupsService.printerNames.length > 0 - - Repeater { - model: CupsService.printerNames - - delegate: Rectangle { - id: printerDelegate - required property string modelData - required property int index - - readonly property var printerData: CupsService.getPrinterData(modelData) - readonly property bool isExpanded: CupsService.expandedPrinter === modelData || hasJobs - readonly property bool hasJobs: (printerData?.jobs?.length ?? 0) > 0 - readonly property bool isIdle: printerData?.state === "idle" - readonly property bool isStopped: printerData?.state === "stopped" - - width: parent.width - height: isExpanded ? 56 + expandedContent.height : 56 - radius: Theme.cornerRadius - color: printerMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: CupsService.selectedPrinter === modelData ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: printerActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: isStopped ? "print_disabled" : "print" - size: 20 - color: isStopped ? Theme.error : (isIdle ? Theme.primary : Theme.warning) - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: CupsService.selectedPrinter === modelData ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: CupsService.getPrinterStateTranslation(printerData?.state || "") - font.pixelSize: Theme.fontSizeSmall - color: { - switch (printerData?.state) { - case "idle": - return Theme.primary; - case "stopped": - return Theme.error; - case "processing": - return Theme.warning; - default: - return Theme.surfaceVariantText; - } - } - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (printerData?.jobs?.length ?? 0) > 0 - } - - StyledText { - text: I18n.ntr("%1 job", "%1 jobs", printerData?.jobs?.length ?? 0).arg(printerData?.jobs?.length ?? 0) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (printerData?.jobs?.length ?? 0) > 0 - } - } - } - } - - Row { - id: printerActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: expandBtn.containsMouse ? Theme.surfacePressed : "transparent" - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: expandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - CupsService.expandedPrinter = isExpanded ? "" : modelData; - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: deleteBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deletePrinterConfirm.showWithOptions({ - title: I18n.tr("Delete Printer"), - message: I18n.tr("Delete \"%1\"?").arg(modelData), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => CupsService.deletePrinter(modelData) - }); - } - } - } - } - - MouseArea { - id: printerMouseArea - anchors.fill: parent - anchors.rightMargin: printerActions.width + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - CupsService.setSelectedPrinter(modelData); - } - } - } - - Column { - id: expandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: detailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: detailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Flow { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: { - const fields = []; - const p = printerData; - if (!p) - return fields; - - fields.push({ - label: I18n.tr("State"), - value: CupsService.getPrinterStateTranslation(p.state) - }); - if (p.stateReason && p.stateReason !== "none") - fields.push({ - label: I18n.tr("Reason"), - value: CupsService.getPrinterStateReasonTranslation(p.stateReason) - }); - if (p.makeModel) - fields.push({ - label: I18n.tr("Model"), - value: p.makeModel - }); - if (p.location) - fields.push({ - label: I18n.tr("Location"), - value: p.location - }); - fields.push({ - label: I18n.tr("Accepting"), - value: p.accepting ? I18n.tr("Yes") : I18n.tr("No") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: fieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: fieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - height: 28 - width: pauseResumeRow.width + Theme.spacingM * 2 - radius: 14 - color: pauseResumeArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: pauseResumeRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: isStopped ? "play_arrow" : "pause" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: isStopped ? I18n.tr("Resume") : I18n.tr("Pause") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: pauseResumeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isStopped) { - CupsService.resumePrinter(modelData); - } else { - CupsService.pausePrinter(modelData); - } - } - } - } - - Rectangle { - height: 28 - width: testPageRow.width + Theme.spacingM * 2 - radius: 14 - color: testPageArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: testPageRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "description" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Test Page") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: testPageArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.printTestPage(modelData) - } - } - - Rectangle { - height: 28 - width: acceptRejectRow.width + Theme.spacingM * 2 - radius: 14 - color: acceptRejectArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: acceptRejectRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: printerData?.accepting ? "block" : "check_circle" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: printerData?.accepting ? I18n.tr("Reject Jobs") : I18n.tr("Accept Jobs") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: acceptRejectArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (printerData?.accepting) { - CupsService.rejectJobs(modelData); - } else { - CupsService.acceptJobs(modelData); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: (printerData?.jobs?.length ?? 0) > 0 - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Jobs") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - Rectangle { - height: 24 - width: purgeRow.width + Theme.spacingM * 2 - radius: 12 - color: purgeArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - - Row { - id: purgeRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "delete_sweep" - size: 14 - color: purgeArea.containsMouse ? Theme.error : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Clear All") - font.pixelSize: Theme.fontSizeSmall - 1 - color: purgeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: purgeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - purgeJobsConfirm.showWithOptions({ - title: I18n.tr("Clear All Jobs"), - message: I18n.tr("Cancel all jobs for \"%1\"?").arg(modelData), - confirmText: I18n.tr("Clear"), - confirmColor: Theme.error, - onConfirm: () => CupsService.purgeJobs(modelData) - }); - } - } - } - } - - Repeater { - model: printerData?.jobs ?? [] - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 44 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHighest - border.width: 1 - border.color: Theme.outlineLight - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: jobActions.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "description" - size: 18 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 1 - width: parent.width - 18 - Theme.spacingS - - StyledText { - text: "[" + modelData.id + "] " + CupsService.getJobStateTranslation(modelData.state) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const size = Math.round((modelData.size || 0) / 1024); - const date = new Date(modelData.timeCreated); - return size + " KB • " + date.toLocaleString(Qt.locale(), Locale.ShortFormat); - } - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - anchors.left: parent.left - } - } - } - - Row { - id: jobActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: holdJobBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: modelData.state === "pending" - - DankIcon { - anchors.centerIn: parent - name: "pause" - size: 14 - color: Theme.surfaceVariantText - } - - MouseArea { - id: holdJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.holdJob(modelData.id) - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: restartJobBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: modelData.state === "pending-held" || modelData.state === "completed" || modelData.state === "aborted" - - DankIcon { - anchors.centerIn: parent - name: "replay" - size: 14 - color: Theme.surfaceVariantText - } - - MouseArea { - id: restartJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.restartJob(modelData.id) - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: cancelJobBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 14 - color: cancelJobBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: cancelJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.cancelJob(printerDelegate.modelData, modelData.id) - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: classesSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable && CupsService.printerClasses.length > 0 - - Column { - id: classesSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "workspaces" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - refreshClassesBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Printer Classes") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.ntr("%1 class", "%1 classes", CupsService.printerClasses.length).arg(CupsService.printerClasses.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankActionButton { - id: refreshClassesBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - onClicked: CupsService.getClasses() - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Column { - width: parent.width - spacing: 4 - - Repeater { - model: CupsService.printerClasses - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: classMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.right: classActions.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "workspaces" - size: 20 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: I18n.ntr("%1 printer", "%1 printers", modelData.members?.length ?? 0).arg(modelData.members?.length ?? 0) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Row { - id: classActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: deleteClassBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteClassBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteClassBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deleteClassConfirm.showWithOptions({ - title: I18n.tr("Delete Class"), - message: I18n.tr("Delete class \"%1\"?").arg(modelData.name), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => CupsService.deleteClass(modelData.name) - }); - } - } - } - } - - MouseArea { - id: classMouseArea - anchors.fill: parent - anchors.rightMargin: classActions.width + Theme.spacingM - hoverEnabled: true - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml deleted file mode 100644 index 022e131..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml +++ /dev/null @@ -1,175 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "find_replace" - title: I18n.tr("App ID Substitutions") - settingKey: "appIdSubstitutions" - tags: ["app", "icon", "substitution", "replacement", "pattern", "window", "class", "regex"] - - headerActions: [ - DankActionButton { - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: JSON.stringify(SettingsData.appIdSubstitutions) !== JSON.stringify(SettingsData.getDefaultAppIdSubstitutions()) - backgroundColor: Theme.surfaceContainer - iconColor: Theme.surfaceVariantText - onClicked: SettingsData.resetAppIdSubstitutions() - }, - DankActionButton { - buttonSize: 36 - iconName: "add" - iconSize: 20 - backgroundColor: Theme.surfaceContainer - iconColor: Theme.primary - onClicked: SettingsData.addAppIdSubstitution("", "", "exact") - } - ] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Map window class names to icon names for proper icon display") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: SettingsData.appIdSubstitutions - - delegate: Rectangle { - id: subItem - width: parent.width - height: subColumn.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Column { - id: subColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: (parent.width - deleteBtn.width - Theme.spacingS) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("Pattern") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - id: patternField - width: parent.width - text: modelData.pattern - font.pixelSize: Theme.fontSizeSmall - onEditingFinished: SettingsData.updateAppIdSubstitution(index, text, replacementField.text, modelData.type) - } - } - - Column { - width: (parent.width - deleteBtn.width - Theme.spacingS) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("Replacement") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - id: replacementField - width: parent.width - text: modelData.replacement - font.pixelSize: Theme.fontSizeSmall - onEditingFinished: SettingsData.updateAppIdSubstitution(index, patternField.text, text, modelData.type) - } - } - - Item { - id: deleteBtn - width: 32 - height: 40 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeAppIdSubstitution(index) - } - } - } - - Column { - width: 120 - spacing: 2 - - StyledText { - text: I18n.tr("Type") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: 120 - currentValue: modelData.type - options: ["exact", "contains", "regex"] - onValueChanged: value => SettingsData.updateAppIdSubstitution(index, modelData.pattern, modelData.replacement, value) - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml deleted file mode 100644 index a8e9958..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml +++ /dev/null @@ -1,168 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "sounds" - tags: ["sound", "audio", "notification", "volume"] - title: I18n.tr("System Sounds") - settingKey: "systemSounds" - iconName: SettingsData.soundsEnabled ? "volume_up" : "volume_off" - visible: AudioService.soundsAvailable - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "enable", "system"] - settingKey: "soundsEnabled" - text: I18n.tr("Enable System Sounds") - description: I18n.tr("Play sounds for system events") - checked: SettingsData.soundsEnabled - onToggled: checked => SettingsData.set("soundsEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.soundsEnabled - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "theme", "system"] - settingKey: "useSystemSoundTheme" - visible: AudioService.gsettingsAvailable - text: I18n.tr("Use System Theme") - description: I18n.tr("Use sound theme from system settings") - checked: SettingsData.useSystemSoundTheme - onToggled: checked => SettingsData.set("useSystemSoundTheme", checked) - } - - SettingsDropdownRow { - tab: "sounds" - tags: ["sound", "theme", "select"] - settingKey: "soundTheme" - visible: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0 - enabled: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0 - text: I18n.tr("Sound Theme") - description: I18n.tr("Select system sound theme") - options: AudioService.availableSoundThemes - currentValue: { - const theme = AudioService.currentSoundTheme; - if (theme && AudioService.availableSoundThemes.includes(theme)) - return theme; - return AudioService.availableSoundThemes.length > 0 ? AudioService.availableSoundThemes[0] : ""; - } - onValueChanged: value => { - if (value && value !== AudioService.currentSoundTheme) - AudioService.setSoundTheme(value); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: AudioService.gsettingsAvailable - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "login", "startup", "boot"] - settingKey: "soundLogin" - text: I18n.tr("Login") - description: I18n.tr("Play sound after logging in") - checked: SettingsData.soundLogin - onToggled: checked => SettingsData.set("soundLogin", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "notification", "new"] - settingKey: "soundNewNotification" - text: I18n.tr("New Notification") - description: I18n.tr("Play sound when new notification arrives") - checked: SettingsData.soundNewNotification - onToggled: checked => SettingsData.set("soundNewNotification", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "volume", "changed"] - settingKey: "soundVolumeChanged" - text: I18n.tr("Volume Changed") - description: I18n.tr("Play sound when volume is adjusted") - checked: SettingsData.soundVolumeChanged - onToggled: checked => SettingsData.set("soundVolumeChanged", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "power", "plugged"] - settingKey: "soundPluggedIn" - visible: BatteryService.batteryAvailable - text: I18n.tr("Plugged In") - description: I18n.tr("Play sound when power cable is connected") - checked: SettingsData.soundPluggedIn - onToggled: checked => SettingsData.set("soundPluggedIn", checked) - } - } - } - - Rectangle { - width: parent.width - height: notAvailableText.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - visible: !AudioService.soundsAvailable - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: notAvailableText - font.pixelSize: Theme.fontSizeSmall - text: I18n.tr("System sounds are not available. Install %1 for sound support.").arg("qt6-multimedia") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml deleted file mode 100644 index 5a61dbb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml +++ /dev/null @@ -1,142 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "refresh" - title: I18n.tr("System Updater") - settingKey: "systemUpdater" - - SettingsToggleRow { - text: I18n.tr("Hide Updater Widget", "When updater widget is used, then hide it if no update found") - description: I18n.tr("When updater widget is used, then hide it if no update found") - checked: SettingsData.updaterHideWidget - onToggled: checked => { - SettingsData.set("updaterHideWidget", checked); - } - } - - SettingsToggleRow { - text: I18n.tr("Use Custom Command") - description: I18n.tr("Use custom command for update your system") - checked: SettingsData.updaterUseCustomCommand - onToggled: checked => { - if (!checked) { - updaterCustomCommand.text = ""; - updaterTerminalCustomClass.text = ""; - SettingsData.set("updaterCustomCommand", ""); - SettingsData.set("updaterTerminalAdditionalParams", ""); - } - SettingsData.set("updaterUseCustomCommand", checked); - } - } - - FocusScope { - width: parent.width - Theme.spacingM * 2 - height: customCommandColumn.implicitHeight - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - - Column { - id: customCommandColumn - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("System update custom command") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: updaterCustomCommand - width: parent.width - placeholderText: "myPkgMngr --sysupdate" - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - if (SettingsData.updaterCustomCommand) { - text = SettingsData.updaterCustomCommand; - } - } - - onTextEdited: SettingsData.set("updaterCustomCommand", text.trim()) - - MouseArea { - anchors.fill: parent - onPressed: mouse => { - updaterCustomCommand.forceActiveFocus(); - mouse.accepted = false; - } - } - } - } - } - - FocusScope { - width: parent.width - Theme.spacingM * 2 - height: terminalParamsColumn.implicitHeight - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - - Column { - id: terminalParamsColumn - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Terminal custom additional parameters") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: updaterTerminalCustomClass - width: parent.width - placeholderText: "-T udpClass" - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - if (SettingsData.updaterTerminalAdditionalParams) { - text = SettingsData.updaterTerminalAdditionalParams; - } - } - - onTextEdited: SettingsData.set("updaterTerminalAdditionalParams", text.trim()) - - MouseArea { - anchors.fill: parent - onPressed: mouse => { - updaterTerminalCustomClass.forceActiveFocus(); - mouse.accepted = false; - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml deleted file mode 100644 index 1df32c7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml +++ /dev/null @@ -1,697 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allThemes: [] - property string searchQuery: "" - property var filteredThemes: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property bool isLoading: false - property var parentModal: null - property bool pendingInstallHandled: false - property string pendingApplyThemeId: "" - - function updateFilteredThemes() { - var filtered = []; - var query = searchQuery ? searchQuery.toLowerCase() : ""; - - for (var i = 0; i < allThemes.length; i++) { - var theme = allThemes[i]; - - if (query.length === 0) { - filtered.push(theme); - continue; - } - - var name = theme.name ? theme.name.toLowerCase() : ""; - var description = theme.description ? theme.description.toLowerCase() : ""; - var author = theme.author ? theme.author.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || author.indexOf(query) !== -1) - filtered.push(theme); - } - - filteredThemes = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredThemes.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredThemes.length - 1); - } - - function selectPrevious() { - if (filteredThemes.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function installTheme(themeId, themeName, applyAfterInstall) { - ToastService.showInfo(I18n.tr("Installing: %1", "installation progress").arg(themeName)); - DMSService.installTheme(themeId, response => { - if (response.error) { - ToastService.showError(I18n.tr("Install failed: %1", "installation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Installed: %1", "installation success").arg(themeName)); - if (applyAfterInstall) - pendingApplyThemeId = themeId; - refreshThemes(); - }); - } - - function applyInstalledTheme(themeId, installedThemes) { - for (var i = 0; i < installedThemes.length; i++) { - var theme = installedThemes[i]; - if (theme.id === themeId) { - var sourceDir = theme.sourceDir || theme.id; - var themePath = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes/" + sourceDir + "/theme.json"; - SettingsData.set("customThemeFile", themePath); - Theme.switchThemeCategory("registry", "custom"); - Theme.switchTheme("custom", true, true); - hide(); - return; - } - } - } - - function uninstallTheme(themeId, themeName) { - ToastService.showInfo(I18n.tr("Uninstalling: %1", "uninstallation progress").arg(themeName)); - DMSService.uninstallTheme(themeId, response => { - if (response.error) { - ToastService.showError(I18n.tr("Uninstall failed: %1", "uninstallation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Uninstalled: %1", "uninstallation success").arg(themeName)); - refreshThemes(); - }); - } - - function refreshThemes() { - isLoading = true; - DMSService.listThemes(); - DMSService.listInstalledThemes(); - } - - function checkPendingInstall() { - if (!PopoutService.pendingThemeInstall || pendingInstallHandled) - return; - pendingInstallHandled = true; - var themeId = PopoutService.pendingThemeInstall; - PopoutService.pendingThemeInstall = ""; - urlInstallConfirm.showWithOptions({ - "title": I18n.tr("Install Theme", "theme installation dialog title"), - "message": I18n.tr("Install theme '%1' from the DMS registry?", "theme installation confirmation").arg(themeId), - "confirmText": I18n.tr("Install", "install action button"), - "cancelText": I18n.tr("Cancel"), - "onConfirm": () => installTheme(themeId, themeId, true), - "onCancel": () => hide() - }); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => browserSearchField.forceActiveFocus()); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "themeBrowser" - title: I18n.tr("Browse Themes", "theme browser window title") - minimumSize: Qt.size(550, 450) - implicitWidth: 700 - implicitHeight: 700 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - pendingInstallHandled = false; - refreshThemes(); - Qt.callLater(() => { - browserSearchField.forceActiveFocus(); - checkPendingInstall(); - }); - return; - } - allThemes = []; - searchQuery = ""; - filteredThemes = []; - selectedIndex = -1; - keyboardNavigationActive = false; - isLoading = false; - } - - ConfirmModal { - id: urlInstallConfirm - } - - Connections { - target: DMSService - function onThemesListReceived(themes) { - isLoading = false; - allThemes = themes; - updateFilteredThemes(); - } - function onInstalledThemesReceived(themes) { - if (!pendingApplyThemeId) - return; - var themeId = pendingApplyThemeId; - pendingApplyThemeId = ""; - applyInstalledTheme(themeId, themes); - } - } - - FocusScope { - id: browserKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - } - } - - Item { - id: browserContent - anchors.fill: parent - anchors.margins: Theme.spacingL - - Item { - id: headerArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: Math.max(headerIcon.height, headerText.height, refreshButton.height, closeButton.height) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - DankIcon { - id: headerIcon - name: "palette" - size: Theme.iconSize - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: headerText - text: I18n.tr("Browse Themes", "theme browser header") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.left: headerIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: refreshButton - iconName: "refresh" - iconSize: 18 - iconColor: Theme.primary - visible: !root.isLoading - onClicked: root.refreshThemes() - } - - DankActionButton { - visible: windowControls.supported - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: root.hide() - } - } - } - - StyledText { - id: descriptionText - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerArea.bottom - anchors.topMargin: Theme.spacingM - text: I18n.tr("Install color themes from the DMS theme registry", "theme browser description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - DankTextField { - id: browserSearchField - anchors.left: parent.left - anchors.right: parent.right - anchors.top: descriptionText.bottom - anchors.topMargin: Theme.spacingM - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search themes...", "theme search placeholder") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [browserKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredThemes(); - } - } - - Item { - id: listArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: browserSearchField.bottom - anchors.topMargin: Theme.spacingM - anchors.bottom: parent.bottom - - Item { - anchors.fill: parent - visible: root.isLoading - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "sync" - size: 48 - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - - RotationAnimator on rotation { - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - running: root.isLoading - } - } - - StyledText { - text: I18n.tr("Loading...", "loading indicator") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - DankListView { - id: themeBrowserList - - anchors.fill: parent - spacing: Theme.spacingS - model: ScriptModel { - values: root.filteredThemes - } - clip: true - visible: !root.isLoading - - ScrollBar.vertical: DankScrollbar { - id: browserScrollbar - } - - delegate: Rectangle { - id: themeDelegate - width: themeBrowserList.width - height: hasPreview ? 140 : themeDelegateContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - property bool isInstalled: modelData.installed || false - property bool isFirstParty: modelData.firstParty || false - property bool hasVariants: modelData.hasVariants || false - property var variants: modelData.variants || null - property string selectedVariantId: { - if (!hasVariants || !variants) - return ""; - if (variants.type === "multi") { - const mode = Theme.isLightMode ? "light" : "dark"; - const defaults = variants.defaults?.[mode] || variants.defaults?.dark || {}; - return (defaults.flavor || "") + (defaults.accent ? "-" + defaults.accent : ""); - } - return variants.default || (variants.options?.[0]?.id ?? ""); - } - property string previewPath: { - const baseDir = "/tmp/dankdots-plugin-registry/themes/" + (modelData.sourceDir || modelData.id); - const mode = Theme.isLightMode ? "light" : "dark"; - if (hasVariants && selectedVariantId) { - if (variants?.type === "multi") - return baseDir + "/preview-" + selectedVariantId + ".svg"; - return baseDir + "/preview-" + selectedVariantId + "-" + mode + ".svg"; - } - return baseDir + "/preview-" + mode + ".svg"; - } - property bool hasPreview: previewImage.status === Image.Ready - color: isSelected ? Theme.primarySelected : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - id: themeDelegateContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - width: hasPreview ? 180 : 0 - height: parent.height - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - visible: hasPreview - - Image { - id: previewImage - anchors.fill: parent - anchors.margins: 2 - source: "file://" + previewPath - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - } - } - - DankIcon { - name: "palette" - size: 48 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: !hasPreview - } - - Column { - width: parent.width - (hasPreview ? 180 : 48) - Theme.spacingM - installButton.width - Theme.spacingM - spacing: 6 - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingXS - width: parent.width - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - height: 18 - width: versionText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: versionText - anchors.centerIn: parent - text: modelData.version || "1.0.0" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - } - } - - Rectangle { - height: 18 - width: firstPartyText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) - border.width: 1 - visible: isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: firstPartyText - anchors.centerIn: parent - text: I18n.tr("official") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - } - - Rectangle { - height: 18 - width: variantsText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.15) - border.color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.4) - border.width: 1 - visible: themeDelegate.hasVariants - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: variantsText - anchors.centerIn: parent - text: { - if (themeDelegate.variants?.type === "multi") - return I18n.tr("%1 variants").arg(themeDelegate.variants?.accents?.length ?? 0); - return I18n.tr("%1 variants").arg(themeDelegate.variants?.options?.length ?? 0); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.secondary - font.weight: Font.Medium - } - } - } - - StyledText { - text: I18n.tr("by %1", "author attribution").arg(modelData.author || I18n.tr("Unknown", "unknown author")) - font.pixelSize: Theme.fontSizeMedium - color: Theme.outline - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - maximumLineCount: themeDelegate.hasVariants ? 2 : 3 - elide: Text.ElideRight - visible: modelData.description && modelData.description.length > 0 - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: themeDelegate.hasVariants && themeDelegate.variants?.type !== "multi" - - Repeater { - model: themeDelegate.variants?.options ?? [] - - Rectangle { - property bool isActive: themeDelegate.selectedVariantId === modelData.id - height: 22 - width: variantChipText.implicitWidth + Theme.spacingS * 2 - radius: 11 - color: isActive ? Theme.primary : Theme.surfaceContainerHigh - border.color: isActive ? Theme.primary : Theme.outline - border.width: 1 - - StyledText { - id: variantChipText - anchors.centerIn: parent - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.primaryText : Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: themeDelegate.selectedVariantId = modelData.id - } - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: themeDelegate.hasVariants && themeDelegate.variants?.type === "multi" - - Repeater { - model: themeDelegate.variants?.accents ?? [] - - Rectangle { - width: 18 - height: 18 - radius: 9 - color: modelData.color || Theme.primary - border.color: Theme.outline - border.width: 1 - - DankTooltipV2 { - id: accentTooltip - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: accentTooltip.show(modelData.name || modelData.id, parent, 0, 0, "top") - onExited: accentTooltip.hide() - } - } - } - } - } - - Rectangle { - id: installButton - width: 90 - height: 36 - radius: Theme.cornerRadius - anchors.verticalCenter: parent.verticalCenter - color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.surfaceVariant) : Theme.primary - opacity: installMouseArea.containsMouse || uninstallMouseArea.containsMouse ? 0.9 : 1 - border.width: isInstalled ? 1 : 0 - border.color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.outline) : "transparent" - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: isInstalled ? (uninstallMouseArea.containsMouse ? "delete" : "check") : "download" - size: 16 - color: isInstalled ? (uninstallMouseArea.containsMouse ? "white" : Theme.surfaceText) : Theme.surface - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!isInstalled) - return I18n.tr("Install", "install action button"); - if (uninstallMouseArea.containsMouse) - return I18n.tr("Uninstall", "uninstall action button"); - return I18n.tr("Installed", "installed status"); - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: isInstalled ? (uninstallMouseArea.containsMouse ? "white" : Theme.surfaceText) : Theme.surface - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: installMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - visible: !isInstalled - onClicked: root.installTheme(modelData.id, modelData.name, false) - } - - MouseArea { - id: uninstallMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - visible: isInstalled - onClicked: root.uninstallTheme(modelData.id, modelData.name) - } - } - } - } - } - - StyledText { - anchors.centerIn: listArea - text: I18n.tr("No themes found", "empty theme list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !root.isLoading && root.filteredThemes.length === 0 - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml deleted file mode 100644 index ce080c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml +++ /dev/null @@ -1,3016 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: themeColorsTab - - property var cachedIconThemes: SettingsData.availableIconThemes - property var cachedCursorThemes: SettingsData.availableCursorThemes - property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label) - property var installedRegistryThemes: [] - property var templateDetection: [] - - property var cursorIncludeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingCursorInclude: false - property bool fixingCursorInclude: false - - function getCursorConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "cursorFile": configDir + "/niri/dms/cursor.kdl", - "grepPattern": 'include.*"dms/cursor.kdl"', - "includeLine": 'include "dms/cursor.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "cursorFile": configDir + "/hypr/dms/cursor.conf", - "grepPattern": 'source.*dms/cursor.conf', - "includeLine": "source = ./dms/cursor.conf" - }; - case "dwl": - return { - "configFile": configDir + "/mango/config.conf", - "cursorFile": configDir + "/mango/dms/cursor.conf", - "grepPattern": 'source.*dms/cursor.conf', - "includeLine": "source=./dms/cursor.conf" - }; - default: - return null; - } - } - - function checkCursorIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "dwl") { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "cursor.kdl" : "cursor.conf"; - const compositorArg = (compositor === "dwl") ? "mangowc" : compositor; - - checkingCursorInclude = true; - Proc.runCommand("check-cursor-include", ["dms", "config", "resolve-include", compositorArg, filename], (output, exitCode) => { - checkingCursorInclude = false; - if (exitCode !== 0) { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - cursorIncludeStatus = JSON.parse(output.trim()); - } catch (e) { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixCursorInclude() { - const paths = getCursorConfigPaths(); - if (!paths) - return; - fixingCursorInclude = true; - const cursorDir = paths.cursorFile.substring(0, paths.cursorFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - Proc.runCommand("fix-cursor-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${cursorDir}" && ` + `touch "${paths.cursorFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingCursorInclude = false; - if (exitCode !== 0) - return; - checkCursorIncludeStatus(); - SettingsData.updateCompositorCursor(); - }); - } - - function isTemplateDetected(templateId) { - if (!templateDetection || templateDetection.length === 0) - return true; - var item = templateDetection.find(i => i.id === templateId); - return !item || item.detected !== false; - } - - function getTemplateDescription(templateId, baseDescription) { - if (isTemplateDetected(templateId)) - return baseDescription; - if (baseDescription) - return baseDescription + " · " + I18n.tr("Not detected"); - return I18n.tr("Not detected"); - } - - function getTemplateDescriptionColor(templateId) { - if (isTemplateDetected(templateId)) - return Theme.surfaceVariantText; - return Theme.warning; - } - - function openBlurBorderColorPicker() { - PopoutService.colorPickerModal.selectedColor = SettingsData.blurBorderCustomColor ?? "#ffffff"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Blur Border Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.set("blurBorderCustomColor", color.toString()); - }; - PopoutService.colorPickerModal.open(); - } - - function openM3ShadowColorPicker() { - PopoutService.colorPickerModal.selectedColor = SettingsData.m3ElevationCustomColor ?? "#000000"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Shadow Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.set("m3ElevationCustomColor", color.toString()); - }; - PopoutService.colorPickerModal.show(); - } - - function formatThemeAutoTime(isoString) { - if (!isoString) - return ""; - try { - const date = new Date(isoString); - if (isNaN(date.getTime())) - return ""; - return date.toLocaleTimeString(Qt.locale(), "HH:mm"); - } catch (e) { - return ""; - } - } - - Component.onCompleted: { - SettingsData.detectAvailableIconThemes(); - SettingsData.detectAvailableCursorThemes(); - if (DMSService.dmsAvailable) - DMSService.listInstalledThemes(); - if (PopoutService.pendingThemeInstall) - Qt.callLater(() => showThemeBrowser()); - Proc.runCommand("template-check", ["dms", "matugen", "check"], (output, exitCode) => { - if (exitCode !== 0) - return; - try { - themeColorsTab.templateDetection = JSON.parse(output.trim()); - } catch (e) {} - }); - if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl) - checkCursorIncludeStatus(); - } - - Connections { - target: DMSService - function onInstalledThemesReceived(themes) { - themeColorsTab.installedRegistryThemes = themes; - } - } - - Connections { - target: PopoutService - function onPendingThemeInstallChanged() { - if (PopoutService.pendingThemeInstall) - showThemeBrowser(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "theme" - tags: ["color", "palette", "theme", "appearance"] - title: I18n.tr("Theme Color") - settingKey: "themeColor" - iconName: "palette" - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - property string registryThemeName: { - if (Theme.currentThemeCategory !== "registry") - return ""; - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json")) - return t.name; - } - return ""; - } - text: { - if (Theme.currentTheme === Theme.dynamic) - return I18n.tr("Current Theme: %1", "current theme label").arg(I18n.tr("Dynamic", "dynamic theme name")); - if (Theme.currentThemeCategory === "registry" && registryThemeName) - return I18n.tr("Current Theme: %1", "current theme label").arg(registryThemeName); - return I18n.tr("Current Theme: %1", "current theme label").arg(Theme.getThemeColors(Theme.currentThemeName).name); - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (Theme.currentTheme === Theme.dynamic) - return I18n.tr("Material colors generated from wallpaper", "dynamic theme description"); - if (Theme.currentThemeCategory === "registry") - return I18n.tr("Color theme from DMS registry", "registry theme description"); - if (Theme.currentTheme === Theme.custom) - return I18n.tr("Custom theme loaded from JSON file", "custom theme description"); - return I18n.tr("Material Design inspired color themes", "generic theme description"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - wrapMode: Text.WordWrap - width: Math.min(parent.width, 400) - horizontalAlignment: Text.AlignHCenter - } - } - - Column { - id: themeCategoryColumn - spacing: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - - Item { - width: parent.width - height: themeCategoryGroup.implicitHeight - clip: true - - DankButtonGroup { - id: themeCategoryGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 420 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 420 ? 44 : 64 - textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium - property bool isRegistryTheme: Theme.currentThemeCategory === "registry" - property int pendingIndex: -1 - property int computedIndex: { - if (isRegistryTheme) - return 3; - if (Theme.currentTheme === Theme.dynamic) - return 1; - if (Theme.currentThemeName === "custom") - return 2; - return 0; - } - - model: DMSService.dmsAvailable ? [I18n.tr("Generic", "theme category option"), I18n.tr("Auto", "theme category option"), I18n.tr("Custom", "theme category option"), I18n.tr("Browse", "theme category option")] : [I18n.tr("Generic", "theme category option"), I18n.tr("Auto", "theme category option"), I18n.tr("Custom", "theme category option")] - currentIndex: pendingIndex >= 0 ? pendingIndex : computedIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0) - return; - const idx = pendingIndex; - pendingIndex = -1; - switch (idx) { - case 0: - Theme.switchThemeCategory("generic", "blue"); - break; - case 1: - if (ToastService.wallpaperErrorStatus === "matugen_missing") - ToastService.showError(I18n.tr("matugen not found - install matugen package for dynamic theming", "matugen error")); - else if (ToastService.wallpaperErrorStatus === "error") - ToastService.showError(I18n.tr("Wallpaper processing failed - check wallpaper path", "wallpaper error")); - else - Theme.switchThemeCategory("dynamic", Theme.dynamic); - break; - case 2: - Theme.switchThemeCategory("custom", "custom"); - break; - case 3: - Theme.switchThemeCategory("registry", ""); - break; - } - } - } - } - - Item { - width: parent.width - height: genericColorGrid.implicitHeight + Math.ceil(genericColorGrid.dotSize * 0.05) - visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom" - - Grid { - id: genericColorGrid - property var colorList: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"] - property int dotSize: parent.width < 300 ? 28 : 32 - columns: Math.ceil(colorList.length / 2) - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Repeater { - model: genericColorGrid.colorList - - Rectangle { - required property string modelData - property string themeName: modelData - width: genericColorGrid.dotSize - height: genericColorGrid.dotSize - radius: width / 2 - color: Theme.getThemeColors(themeName).primary - border.color: Theme.outline - border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1 - scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1 - - Rectangle { - width: nameText.contentWidth + Theme.spacingS * 2 - height: nameText.contentHeight + Theme.spacingXS * 2 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - anchors.bottom: parent.top - anchors.bottomMargin: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - visible: mouseArea.containsMouse - - StyledText { - id: nameText - text: Theme.getThemeColors(parent.parent.themeName).name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.centerIn: parent - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.switchTheme(parent.themeName) - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentTheme === Theme.dynamic && Theme.currentThemeCategory !== "registry" - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledRect { - width: 120 - height: 90 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = Theme.wallpaperPath; - if (!wp || wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: Theme.wallpaperPath && !Theme.wallpaperPath.startsWith("#") - sourceSize.width: 120 - sourceSize.height: 120 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: autoWallpaperMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#") ? Theme.wallpaperPath : "transparent" - visible: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#") - } - - Rectangle { - id: autoWallpaperMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? "error" : "palette" - size: Theme.iconSizeLarge - color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceVariantText - visible: !Theme.wallpaperPath - } - } - - Column { - width: parent.width - 120 - Theme.spacingM - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (ToastService.wallpaperErrorStatus === "error") - return I18n.tr("Wallpaper Error", "wallpaper error status"); - if (ToastService.wallpaperErrorStatus === "matugen_missing") - return I18n.tr("Matugen Missing", "matugen not found status"); - if (Theme.wallpaperPath) - return Theme.wallpaperPath.split('/').pop(); - return I18n.tr("No wallpaper selected", "no wallpaper status"); - } - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - - StyledText { - text: { - if (ToastService.wallpaperErrorStatus === "error") - return I18n.tr("Wallpaper processing failed", "wallpaper processing error"); - if (ToastService.wallpaperErrorStatus === "matugen_missing") - return I18n.tr("Install matugen package for dynamic theming", "matugen installation hint"); - if (Theme.wallpaperPath) - return Theme.wallpaperPath; - return I18n.tr("Dynamic colors from wallpaper", "dynamic colors description"); - } - font.pixelSize: Theme.fontSizeSmall - color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 2 - width: parent.width - wrapMode: Text.WordWrap - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["matugen", "palette", "algorithm", "dynamic"] - settingKey: "matugenScheme" - text: I18n.tr("Matugen Palette") - description: I18n.tr("Select the palette algorithm used for wallpaper-based colors") - options: cachedMatugenSchemes - currentValue: Theme.getMatugenScheme(SettingsData.matugenScheme).label - enabled: Theme.matugenAvailable - opacity: enabled ? 1 : 0.4 - onValueChanged: value => { - for (var i = 0; i < Theme.availableMatugenSchemes.length; i++) { - var option = Theme.availableMatugenSchemes[i]; - if (option.label === value) { - SettingsData.setMatugenScheme(option.value); - break; - } - } - } - } - - StyledText { - text: { - var scheme = Theme.getMatugenScheme(SettingsData.matugenScheme); - return scheme.description + " (" + scheme.value + ")"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - } - - SettingsSliderRow { - tab: "theme" - tags: ["matugen", "contrast", "dynamic"] - settingKey: "matugenContrast" - text: I18n.tr("Matugen Contrast") - description: I18n.tr("Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)") - value: Math.round(SettingsData.matugenContrast * 100) - minimum: -100 - maximum: 100 - unit: "%" - defaultValue: 0 - enabled: Theme.matugenAvailable - opacity: enabled ? 1 : 0.4 - onSliderDragFinished: finalValue => SettingsData.setMatugenContrast(finalValue / 100) - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentThemeName === "custom" && Theme.currentThemeCategory !== "registry" - - Row { - width: parent.width - spacing: Theme.spacingM - - DankActionButton { - buttonSize: 48 - iconName: "folder_open" - iconSize: Theme.iconSize - backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - iconColor: Theme.primary - onClicked: fileBrowserModal.open() - } - - Column { - width: parent.width - 48 - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: SettingsData.customThemeFile ? SettingsData.customThemeFile.split('/').pop() : I18n.tr("No custom theme file", "no custom theme file status") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - - StyledText { - text: SettingsData.customThemeFile || I18n.tr("Click to select a custom theme JSON file", "custom theme file hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - } - } - - Column { - id: registrySection - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentThemeCategory === "registry" - - Grid { - id: themeGrid - property int cardWidth: registrySection.width < 350 ? 100 : 140 - property int cardHeight: registrySection.width < 350 ? 72 : 100 - columns: Math.max(1, Math.floor((registrySection.width + spacing) / (cardWidth + spacing))) - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - visible: themeColorsTab.installedRegistryThemes.length > 0 - - Repeater { - model: themeColorsTab.installedRegistryThemes - - Rectangle { - id: themeCard - property bool isActive: Theme.currentThemeCategory === "registry" && Theme.currentThemeName === "custom" && SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((modelData.sourceDir || modelData.id) + "/theme.json") - property bool hasVariants: modelData.hasVariants || false - property var variants: modelData.variants || null - property string selectedVariant: hasVariants ? SettingsData.getRegistryThemeVariant(modelData.id, variants?.default || "") : "" - property string previewPath: { - const baseDir = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes/" + (modelData.sourceDir || modelData.id); - const mode = Theme.isLightMode ? "light" : "dark"; - if (hasVariants && selectedVariant) - return baseDir + "/preview-" + selectedVariant + "-" + mode + ".svg"; - return baseDir + "/preview-" + mode + ".svg"; - } - width: themeGrid.cardWidth - height: themeGrid.cardHeight - radius: Theme.cornerRadius - color: Theme.surfaceVariant - border.color: isActive ? Theme.primary : Theme.outline - border.width: isActive ? 2 : 1 - scale: isActive ? 1.03 : 1 - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Image { - id: previewImage - anchors.fill: parent - anchors.margins: 2 - source: "file://" + themeCard.previewPath - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - } - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: themeGrid.cardWidth < 120 ? 24 : 32 - color: Theme.primary - visible: previewImage.status === Image.Error || previewImage.status === Image.Null - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: themeGrid.cardWidth < 120 ? 18 : 22 - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.6) - - StyledText { - anchors.centerIn: parent - text: modelData.name - font.pixelSize: themeGrid.cardWidth < 120 ? Theme.fontSizeSmall - 2 : Theme.fontSizeSmall - color: "white" - font.weight: Font.Medium - elide: Text.ElideRight - width: parent.width - Theme.spacingXS * 2 - horizontalAlignment: Text.AlignHCenter - } - } - - Rectangle { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 16 : 20 - height: width - radius: width / 2 - color: Theme.primary - visible: themeCard.isActive - - DankIcon { - anchors.centerIn: parent - name: "check" - size: themeGrid.cardWidth < 120 ? 10 : 14 - color: Theme.surface - } - } - - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 16 : 20 - height: width - radius: width / 2 - color: Theme.secondary - visible: themeCard.hasVariants && !deleteButton.visible - - StyledText { - anchors.centerIn: parent - text: { - if (themeCard.variants?.type === "multi") - return themeCard.variants?.accents?.length || 0; - return themeCard.variants?.options?.length || 0; - } - font.pixelSize: themeGrid.cardWidth < 120 ? Theme.fontSizeSmall - 4 : Theme.fontSizeSmall - 2 - color: Theme.surface - font.weight: Font.Bold - } - } - - MouseArea { - id: cardMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const themesDir = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes"; - const themePath = themesDir + "/" + (modelData.sourceDir || modelData.id) + "/theme.json"; - SettingsData.set("customThemeFile", themePath); - Theme.switchTheme("custom", true, true); - } - } - - Rectangle { - id: deleteButton - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 18 : 24 - height: width - radius: width / 2 - color: deleteMouseArea.containsMouse ? Theme.error : Qt.rgba(0, 0, 0, 0.6) - opacity: cardMouseArea.containsMouse || deleteMouseArea.containsMouse ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - anchors.centerIn: parent - name: "close" - size: themeGrid.cardWidth < 120 ? 10 : 14 - color: "white" - } - - MouseArea { - id: deleteMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - ToastService.showInfo(I18n.tr("Uninstalling: %1", "uninstallation progress").arg(modelData.name)); - DMSService.uninstallTheme(modelData.id, response => { - if (response.error) { - ToastService.showError(I18n.tr("Uninstall failed: %1", "uninstallation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Uninstalled: %1", "uninstallation success").arg(modelData.name)); - DMSService.listInstalledThemes(); - }); - } - } - } - } - } - } - - StyledText { - text: I18n.tr("No themes installed. Browse themes to install from the registry.", "no registry themes installed hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: themeColorsTab.installedRegistryThemes.length === 0 - horizontalAlignment: Text.AlignHCenter - } - - DankButton { - text: I18n.tr("Browse Themes", "browse themes button") - iconName: "store" - anchors.horizontalCenter: parent.horizontalCenter - onClicked: showThemeBrowser() - } - } - - Column { - id: variantSelector - width: parent.width - spacing: Theme.spacingS - visible: activeThemeId !== "" && activeThemeVariants !== null && (isMultiVariant || (activeThemeVariants.options && activeThemeVariants.options.length > 0)) - - property string activeThemeId: { - switch (Theme.currentThemeCategory) { - case "registry": - if (Theme.currentTheme !== "custom") - return ""; - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json")) - return t.id; - } - return ""; - case "custom": - return Theme.currentThemeId || ""; - default: - return ""; - } - } - property var activeThemeVariants: { - if (!activeThemeId) - return null; - switch (Theme.currentThemeCategory) { - case "registry": - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (t.id === activeThemeId && t.hasVariants) - return t.variants; - } - return null; - case "custom": - return Theme.currentThemeVariants || null; - default: - return null; - } - } - property bool isMultiVariant: activeThemeVariants?.type === "multi" - property string colorMode: Theme.isLightMode ? "light" : "dark" - property var multiDefaults: { - if (!isMultiVariant || !activeThemeVariants?.defaults) - return {}; - return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {}; - } - property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults, colorMode) : multiDefaults - property string selectedFlavor: { - var sf = storedMulti.flavor || multiDefaults.flavor || ""; - for (var i = 0; i < flavorOptions.length; i++) { - if (flavorOptions[i].id === sf) - return sf; - } - if (flavorOptions.length > 0) - return flavorOptions[0].id; - return sf; - } - property string selectedAccent: storedMulti.accent || multiDefaults.accent || "" - property var flavorOptions: { - if (!isMultiVariant || !activeThemeVariants?.flavors) - return []; - return activeThemeVariants.flavors.filter(f => { - if (f.mode) - return f.mode === colorMode || f.mode === "both"; - return !!f[colorMode]; - }); - } - property var flavorNames: flavorOptions.map(f => f.name) - property int flavorIndex: { - for (var i = 0; i < flavorOptions.length; i++) { - if (flavorOptions[i].id === selectedFlavor) - return i; - } - return 0; - } - property string selectedVariant: activeThemeId ? SettingsData.getRegistryThemeVariant(activeThemeId, activeThemeVariants?.default || "") : "" - property var variantNames: { - if (!activeThemeVariants?.options) - return []; - return activeThemeVariants.options.map(v => v.name); - } - property int selectedIndex: { - if (!activeThemeVariants?.options || !selectedVariant) - return 0; - for (var i = 0; i < activeThemeVariants.options.length; i++) { - if (activeThemeVariants.options[i].id === selectedVariant) - return i; - } - return 0; - } - - Item { - width: parent.width - height: flavorButtonGroup.implicitHeight - clip: true - visible: variantSelector.isMultiVariant && variantSelector.flavorOptions.length > 1 - - DankButtonGroup { - id: flavorButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - property int _count: variantSelector.flavorNames.length - property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width - buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL) - minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem))) - textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium) - checkEnabled: _maxPerItem >= 55 - property int pendingIndex: -1 - model: variantSelector.flavorNames - currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.flavorIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0 || pendingIndex >= variantSelector.flavorOptions.length) - return; - const flavorId = variantSelector.flavorOptions[pendingIndex]?.id; - const idx = pendingIndex; - pendingIndex = -1; - if (!flavorId || flavorId === variantSelector.selectedFlavor) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent, variantSelector.colorMode); - } - } - } - - Item { - width: parent.width - height: accentColorsGrid.implicitHeight - visible: variantSelector.isMultiVariant && variantSelector.activeThemeVariants?.accents?.length > 0 - - Grid { - id: accentColorsGrid - property int accentCount: variantSelector.activeThemeVariants?.accents?.length ?? 0 - property int dotSize: parent.width < 300 ? 28 : 32 - columns: accentCount > 0 ? Math.ceil(accentCount / 2) : 1 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Repeater { - model: variantSelector.activeThemeVariants?.accents || [] - - Rectangle { - required property var modelData - required property int index - property string accentId: modelData.id - property bool isSelected: accentId === variantSelector.selectedAccent - width: accentColorsGrid.dotSize - height: accentColorsGrid.dotSize - radius: width / 2 - color: modelData.color || modelData[variantSelector.selectedFlavor]?.primary || Theme.primary - border.color: Theme.outline - border.width: isSelected ? 2 : 1 - scale: isSelected ? 1.1 : 1 - - Rectangle { - width: accentNameText.contentWidth + Theme.spacingS * 2 - height: accentNameText.contentHeight + Theme.spacingXS * 2 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - anchors.bottom: parent.top - anchors.bottomMargin: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - visible: accentMouseArea.containsMouse - - StyledText { - id: accentNameText - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.centerIn: parent - } - } - - MouseArea { - id: accentMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (parent.isSelected) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId, variantSelector.colorMode); - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } - - Item { - width: parent.width - height: variantButtonGroup.implicitHeight - clip: true - visible: !variantSelector.isMultiVariant && variantSelector.variantNames.length > 0 - - DankButtonGroup { - id: variantButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - property int _count: variantSelector.variantNames.length - property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width - buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL) - minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem))) - textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium) - checkEnabled: _maxPerItem >= 55 - property int pendingIndex: -1 - model: variantSelector.variantNames - currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.selectedIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0 || !variantSelector.activeThemeVariants?.options) - return; - const variantId = variantSelector.activeThemeVariants.options[pendingIndex]?.id; - const idx = pendingIndex; - pendingIndex = -1; - if (!variantId || variantId === variantSelector.selectedVariant) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeVariant(variantSelector.activeThemeId, variantId); - } - } - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["automatic", "color", "mode", "schedule", "sunrise", "sunset"] - title: I18n.tr("Automatic Color Mode") - settingKey: "automaticColorMode" - iconName: "schedule" - - Column { - width: parent.width - spacing: Theme.spacingM - - DankToggle { - id: themeModeAutoToggle - width: parent.width - text: I18n.tr("Automatic Control") - checked: SessionData.themeModeAutoEnabled - onToggled: checked => { - SessionData.setThemeModeAutoEnabled(checked); - } - - Connections { - target: SessionData - function onThemeModeAutoEnabledChanged() { - themeModeAutoToggle.checked = SessionData.themeModeAutoEnabled; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoEnabled - - DankToggle { - width: parent.width - text: I18n.tr("Share Gamma Control Settings") - checked: SessionData.themeModeShareGammaSettings - onToggled: checked => { - SessionData.setThemeModeShareGammaSettings(checked); - } - } - - Item { - width: parent.width - height: 45 + Theme.spacingM - - DankTabBar { - id: themeModeTabBar - width: 200 - height: 45 - anchors.horizontalCenter: parent.horizontalCenter - model: [ - { - "text": I18n.tr("Time", "theme auto mode tab"), - "icon": "access_time" - }, - { - "text": I18n.tr("Location", "theme auto mode tab"), - "icon": "place" - } - ] - - Component.onCompleted: { - currentIndex = SessionData.themeModeAutoMode === "location" ? 1 : 0; - Qt.callLater(updateIndicator); - } - - onTabClicked: index => { - SessionData.setThemeModeAutoMode(index === 1 ? "location" : "time"); - currentIndex = index; - } - - Connections { - target: SessionData - function onThemeModeAutoModeChanged() { - themeModeTabBar.currentIndex = SessionData.themeModeAutoMode === "location" ? 1 : 0; - Qt.callLater(themeModeTabBar.updateIndicator); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoMode === "time" && !SessionData.themeModeShareGammaSettings - - Column { - spacing: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: Theme.spacingM - - StyledText { - text: "" - width: 50 - height: 20 - } - - StyledText { - text: I18n.tr("Hour") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Minute") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Start") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeStartHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) - hours.push(i.toString()); - return hours; - } - onValueChanged: value => { - SessionData.setThemeModeStartHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeStartMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setThemeModeStartMinute(parseInt(value)); - } - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("End") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeEndHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) - hours.push(i.toString()); - return hours; - } - onValueChanged: value => { - SessionData.setThemeModeEndHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeEndMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setThemeModeEndMinute(parseInt(value)); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoMode === "location" && !SessionData.themeModeShareGammaSettings - - DankToggle { - id: themeModeIpLocationToggle - width: parent.width - text: I18n.tr("Use IP Location") - checked: SessionData.nightModeUseIPLocation || false - onToggled: checked => { - SessionData.setNightModeUseIPLocation(checked); - } - - Connections { - target: SessionData - function onNightModeUseIPLocationChanged() { - themeModeIpLocationToggle.checked = SessionData.nightModeUseIPLocation; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !SessionData.nightModeUseIPLocation - - StyledText { - text: I18n.tr("Manual Coordinates") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - - Row { - spacing: Theme.spacingL - anchors.horizontalCenter: parent.horizontalCenter - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.latitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lat = parseFloat(text); - if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { - SessionData.setLatitude(lat); - } - } - } - } - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.longitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lon = parseFloat(text); - if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { - SessionData.setLongitude(lon); - } - } - } - } - } - - StyledText { - text: I18n.tr("Uses sunrise/sunset times based on your location.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("Using shared settings from Gamma Control") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - visible: SessionData.themeModeShareGammaSettings - } - - Rectangle { - width: parent.width - height: statusRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Row { - id: statusRow - anchors.centerIn: parent - spacing: Theme.spacingL - width: parent.width - Theme.spacingM * 2 - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: SessionData.themeModeAutoEnabled ? Theme.success : Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Automation") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - StyledText { - text: SessionData.themeModeAutoEnabled ? I18n.tr("Enabled") : I18n.tr("Disabled") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingS - - DankIcon { - name: SessionData.isLightMode ? "light_mode" : "dark_mode" - size: Theme.iconSize - color: SessionData.isLightMode ? "#FFA726" : "#7E57C2" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SessionData.isLightMode ? I18n.tr("Light Mode") : I18n.tr("Dark Mode") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("Active") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - visible: SessionData.themeModeAutoEnabled && SessionData.themeModeNextTransition - - Row { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "schedule" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Next Transition") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: themeColorsTab.formatThemeAutoTime(SessionData.themeModeNextTransition) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - } - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["light", "dark", "mode", "appearance"] - title: I18n.tr("Color Mode") - settingKey: "colorMode" - iconName: "contrast" - - SettingsToggleRow { - tab: "theme" - tags: ["light", "dark", "mode"] - settingKey: "isLightMode" - text: I18n.tr("Light Mode") - description: I18n.tr("Use light theme instead of dark theme") - checked: SessionData.isLightMode - onToggled: checked => { - Theme.screenTransition(); - Theme.setLightMode(checked); - } - } - } - - SettingsCard { - tab: "theme" - tags: ["transparency", "opacity", "widget", "styling"] - title: I18n.tr("Widget Styling") - settingKey: "widgetStyling" - iconName: "opacity" - - SettingsButtonGroupRow { - tab: "theme" - tags: ["widget", "style", "colorful", "default"] - settingKey: "widgetColorMode" - text: I18n.tr("Widget Style") - description: I18n.tr("Change bar appearance") - model: [I18n.tr("Default", "widget style option"), I18n.tr("Colorful", "widget style option")] - currentIndex: SettingsData.widgetColorMode === "colorful" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("widgetColorMode", index === 1 ? "colorful" : "default"); - } - } - - SettingsButtonGroupRow { - tab: "theme" - tags: ["widget", "background", "color"] - settingKey: "widgetBackgroundColor" - text: I18n.tr("Widget Background Color") - description: I18n.tr("Choose the background color for widgets") - model: ["sth", "s", "sc", "sch"] - buttonHeight: 20 - minButtonWidth: 32 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 2 - spacing: 1 - currentIndex: { - switch (SettingsData.widgetBackgroundColor) { - case "sth": - return 0; - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const colorOptions = ["sth", "s", "sc", "sch"]; - SettingsData.set("widgetBackgroundColor", colorOptions[index]); - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["control", "center", "tile", "button", "color", "active"] - settingKey: "controlCenterTileColorMode" - text: I18n.tr("Control Center Tile Color") - description: I18n.tr("Active tile background and icon color", "control center tile color setting description") - options: [I18n.tr("Primary", "tile color option"), I18n.tr("Primary Container", "tile color option"), I18n.tr("Secondary", "tile color option"), I18n.tr("Surface Variant", "tile color option")] - currentValue: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return I18n.tr("Primary Container", "tile color option"); - case "secondary": - return I18n.tr("Secondary", "tile color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "tile color option"); - default: - return I18n.tr("Primary", "tile color option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary Container", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "primaryContainer"); - } else if (value === I18n.tr("Secondary", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "secondary"); - } else if (value === I18n.tr("Surface Variant", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "surfaceVariant"); - } else { - SettingsData.set("controlCenterTileColorMode", "primary"); - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["button", "color", "primary", "accent"] - settingKey: "buttonColorMode" - text: I18n.tr("Button Color") - description: I18n.tr("Color for primary action buttons") - options: [I18n.tr("Primary", "button color option"), I18n.tr("Primary Container", "button color option"), I18n.tr("Secondary", "button color option"), I18n.tr("Surface Variant", "button color option")] - currentValue: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return I18n.tr("Primary Container", "button color option"); - case "secondary": - return I18n.tr("Secondary", "button color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "button color option"); - default: - return I18n.tr("Primary", "button color option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary Container", "button color option")) { - SettingsData.set("buttonColorMode", "primaryContainer"); - } else if (value === I18n.tr("Secondary", "button color option")) { - SettingsData.set("buttonColorMode", "secondary"); - } else if (value === I18n.tr("Surface Variant", "button color option")) { - SettingsData.set("buttonColorMode", "surfaceVariant"); - } else { - SettingsData.set("buttonColorMode", "primary"); - } - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["popup", "transparency", "opacity", "modal"] - settingKey: "popupTransparency" - text: I18n.tr("Popup Transparency") - description: I18n.tr("Controls opacity of all popouts, modals, and their content layers") - value: Math.round(SettingsData.popupTransparency * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("popupTransparency", newValue / 100) - } - - SettingsSliderRow { - tab: "theme" - tags: ["corner", "radius", "rounded", "square"] - settingKey: "cornerRadius" - text: I18n.tr("Corner Radius") - description: I18n.tr("0 = square corners") - value: SettingsData.cornerRadius - minimum: 0 - maximum: 32 - unit: "px" - defaultValue: 12 - onSliderValueChanged: newValue => SettingsData.setCornerRadius(newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "lift", "m3", "material"] - settingKey: "m3ElevationEnabled" - text: I18n.tr("Shadows") - description: I18n.tr("Material inspired shadows and elevation on modals, popouts, and dialogs") - checked: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("m3ElevationEnabled", checked) - } - - SettingsSliderRow { - tab: "theme" - tags: ["elevation", "shadow", "intensity", "blur", "m3"] - settingKey: "m3ElevationIntensity" - text: I18n.tr("Shadow Intensity") - description: I18n.tr("Controls the base blur radius and offset of shadows") - value: SettingsData.m3ElevationIntensity ?? 12 - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: 12 - visible: SettingsData.m3ElevationEnabled ?? true - onSliderValueChanged: newValue => SettingsData.set("m3ElevationIntensity", newValue) - } - - SettingsSliderRow { - tab: "theme" - tags: ["elevation", "shadow", "opacity", "transparency", "m3"] - settingKey: "m3ElevationOpacity" - text: I18n.tr("Shadow Opacity") - description: I18n.tr("Controls the transparency of the shadow") - value: SettingsData.m3ElevationOpacity ?? 30 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 30 - visible: SettingsData.m3ElevationEnabled ?? true - onSliderValueChanged: newValue => SettingsData.set("m3ElevationOpacity", newValue) - } - - SettingsDropdownRow { - tab: "theme" - tags: ["elevation", "shadow", "color", "m3"] - settingKey: "m3ElevationColorMode" - text: I18n.tr("Shadow Color") - description: I18n.tr("Base color for shadows (opacity is applied automatically)") - options: [I18n.tr("Default (Black)", "shadow color option"), I18n.tr("Text Color", "shadow color option"), I18n.tr("Primary", "shadow color option"), I18n.tr("Surface Variant", "shadow color option"), I18n.tr("Custom", "shadow color option")] - currentValue: { - switch (SettingsData.m3ElevationColorMode) { - case "text": - return I18n.tr("Text Color", "shadow color option"); - case "primary": - return I18n.tr("Primary", "shadow color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "shadow color option"); - case "custom": - return I18n.tr("Custom", "shadow color option"); - default: - return I18n.tr("Default (Black)", "shadow color option"); - } - } - visible: SettingsData.m3ElevationEnabled ?? true - onValueChanged: value => { - if (value === I18n.tr("Primary", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "primary"); - } else if (value === I18n.tr("Surface Variant", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "surfaceVariant"); - } else if (value === I18n.tr("Custom", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "custom"); - openM3ShadowColorPicker(); - } else if (value === I18n.tr("Text Color", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "text"); - } else { - SettingsData.set("m3ElevationColorMode", "default"); - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["elevation", "shadow", "direction", "light", "advanced", "m3"] - settingKey: "m3ElevationLightDirection" - text: I18n.tr("Light Direction") - description: I18n.tr("Controls shadow cast direction for elevation layers") - options: [I18n.tr("Auto (Bar-aware)", "shadow direction option"), I18n.tr("Top (Default)", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] - currentValue: { - switch (SettingsData.m3ElevationLightDirection) { - case "autoBar": - return I18n.tr("Auto (Bar-aware)", "shadow direction option"); - case "topLeft": - return I18n.tr("Top Left", "shadow direction option"); - case "topRight": - return I18n.tr("Top Right", "shadow direction option"); - case "bottom": - return I18n.tr("Bottom", "shadow direction option"); - default: - return I18n.tr("Top (Default)", "shadow direction option"); - } - } - visible: SettingsData.m3ElevationEnabled ?? true - onValueChanged: value => { - if (value === I18n.tr("Auto (Bar-aware)", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "autoBar"); - } else if (value === I18n.tr("Top Left", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "topLeft"); - } else if (value === I18n.tr("Top Right", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "topRight"); - } else if (value === I18n.tr("Bottom", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "bottom"); - } else { - SettingsData.set("m3ElevationLightDirection", "top"); - } - } - } - - Item { - visible: (SettingsData.m3ElevationEnabled ?? true) && SettingsData.m3ElevationColorMode === "custom" - width: parent.width - implicitHeight: 36 - height: implicitHeight - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Shadow Color") - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - width: 26 - height: 26 - radius: 13 - color: SettingsData.m3ElevationCustomColor ?? "#000000" - border.color: Theme.outline - border.width: 1 - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: openM3ShadowColorPicker() - } - } - } - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "modal", "dialog", "m3"] - settingKey: "modalElevationEnabled" - text: I18n.tr("Modal Shadows") - description: I18n.tr("Shadow elevation on modals and dialogs") - checked: SettingsData.modalElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("modalElevationEnabled", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "popout", "popup", "osd", "dropdown", "m3"] - settingKey: "popoutElevationEnabled" - text: I18n.tr("Popout Shadows") - description: I18n.tr("Shadow elevation on popouts, OSDs, and dropdowns") - checked: SettingsData.popoutElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("popoutElevationEnabled", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "bar", "panel", "navigation", "m3"] - settingKey: "barElevationEnabled" - text: I18n.tr("Bar Shadows") - description: I18n.tr("Shadow elevation on bars and panels") - checked: SettingsData.barElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("barElevationEnabled", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["blur", "background", "transparency", "glass", "frosted"] - title: I18n.tr("Background Blur") - settingKey: "blurEnabled" - iconName: "blur_on" - - SettingsToggleRow { - tab: "theme" - tags: ["blur", "background", "transparency", "glass", "frosted"] - settingKey: "blurEnabled" - text: I18n.tr("Background Blur") - description: BlurService.available ? I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.") : I18n.tr("Requires a newer version of Quickshell") - checked: SettingsData.blurEnabled ?? false - enabled: BlurService.available - onToggled: checked => SettingsData.set("blurEnabled", checked) - } - - SettingsDropdownRow { - tab: "theme" - tags: ["blur", "border", "outline", "edge"] - settingKey: "blurBorderColor" - text: I18n.tr("Blur Border Color") - description: I18n.tr("Border color around blurred surfaces") - visible: SettingsData.blurEnabled - options: [I18n.tr("Outline", "blur border color"), I18n.tr("Primary", "blur border color"), I18n.tr("Secondary", "blur border color"), I18n.tr("Text Color", "blur border color"), I18n.tr("Custom", "blur border color")] - currentValue: { - switch (SettingsData.blurBorderColor) { - case "primary": - return I18n.tr("Primary", "blur border color"); - case "secondary": - return I18n.tr("Secondary", "blur border color"); - case "surfaceText": - return I18n.tr("Text Color", "blur border color"); - case "custom": - return I18n.tr("Custom", "blur border color"); - default: - return I18n.tr("Outline", "blur border color"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary", "blur border color")) { - SettingsData.set("blurBorderColor", "primary"); - } else if (value === I18n.tr("Secondary", "blur border color")) { - SettingsData.set("blurBorderColor", "secondary"); - } else if (value === I18n.tr("Text Color", "blur border color")) { - SettingsData.set("blurBorderColor", "surfaceText"); - } else if (value === I18n.tr("Custom", "blur border color")) { - SettingsData.set("blurBorderColor", "custom"); - openBlurBorderColorPicker(); - } else { - SettingsData.set("blurBorderColor", "outline"); - } - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["blur", "border", "opacity"] - settingKey: "blurBorderOpacity" - text: I18n.tr("Blur Border Opacity") - visible: SettingsData.blurEnabled - value: Math.round((SettingsData.blurBorderOpacity ?? 1.0) * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100) - } - } - - SettingsCard { - tab: "theme" - tags: ["niri", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("Niri Layout Overrides").replace("Niri", "niri") - settingKey: "niriLayout" - iconName: "crop_square" - visible: CompositorService.isNiri - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.niriLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("niriLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("niriLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows") - visible: SettingsData.niriLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("niriLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.niriLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("niriLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows") - visible: SettingsData.niriLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("niriLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border/focus-ring width") - checked: SettingsData.niriLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutBorderSize", 2); - return; - } - SettingsData.set("niriLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border and focus ring") - visible: SettingsData.niriLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.niriLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"] - title: I18n.tr("Hyprland Layout Overrides") - settingKey: "hyprlandLayout" - iconName: "crop_square" - visible: CompositorService.isHyprland - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.hyprlandLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("hyprlandLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("hyprlandLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gaps_in and gaps_out)") - visible: SettingsData.hyprlandLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window rounding instead of theme radius") - checked: SettingsData.hyprlandLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("hyprlandLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverride" - text: I18n.tr("Window Rounding") - description: I18n.tr("Rounded corners for windows (decoration.rounding)") - visible: SettingsData.hyprlandLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.hyprlandLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutBorderSize", 2); - return; - } - SettingsData.set("hyprlandLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (general.border_size)") - visible: SettingsData.hyprlandLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("MangoWC Layout Overrides") - settingKey: "mangoLayout" - iconName: "crop_square" - visible: CompositorService.isDwl - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.mangoLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("mangoLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("mangoLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gappih/gappiv/gappoh/gappov)") - visible: SettingsData.mangoLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.mangoLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("mangoLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows (border_radius)") - visible: SettingsData.mangoLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.mangoLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutBorderSize", 2); - return; - } - SettingsData.set("mangoLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (borderpx)") - visible: SettingsData.mangoLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.mangoLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["modal", "darken", "background", "overlay"] - title: I18n.tr("Modal Background") - settingKey: "modalBackground" - iconName: "layers" - - SettingsToggleRow { - tab: "theme" - tags: ["modal", "darken", "background", "overlay"] - settingKey: "modalDarkenBackground" - text: I18n.tr("Darken Modal Background") - description: I18n.tr("Show darkened overlay behind modal dialogs") - checked: SettingsData.modalDarkenBackground - onToggled: checked => SettingsData.set("modalDarkenBackground", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["applications", "portal", "dark", "terminal"] - title: I18n.tr("Applications") - settingKey: "applications" - iconName: "apps" - - SettingsToggleRow { - tab: "theme" - tags: ["portal", "sync", "dark", "mode"] - settingKey: "syncModeWithPortal" - text: I18n.tr("Sync Mode with Portal") - description: I18n.tr("Sync dark mode with settings portals for system-wide theme hints") - checked: SettingsData.syncModeWithPortal - onToggled: checked => SettingsData.set("syncModeWithPortal", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["terminal", "dark", "always"] - settingKey: "terminalsAlwaysDark" - text: I18n.tr("Terminals - Always use Dark Theme") - description: I18n.tr("Force terminal applications to always use dark color schemes") - checked: SettingsData.terminalsAlwaysDark - onToggled: checked => SettingsData.set("terminalsAlwaysDark", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "theme", "size"] - title: I18n.tr("Cursor Theme") - settingKey: "cursorTheme" - iconName: "mouse" - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledRect { - id: cursorWarningBox - width: parent.width - height: cursorWarningContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - - readonly property bool showError: themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included - readonly property bool showSetup: !themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && !themeColorsTab.checkingCursorInclude - - Row { - id: cursorWarningContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (cursorFixButton.visible ? cursorFixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Cursor Config Not Configured") : I18n.tr("Cursor Include Missing") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.warning - } - - StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Click 'Setup' to create cursor config and add include to your compositor config.") : I18n.tr("dms/cursor config exists but is not included. Cursor settings won't apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankButton { - id: cursorFixButton - visible: cursorWarningBox.showError || cursorWarningBox.showSetup - text: themeColorsTab.fixingCursorInclude ? I18n.tr("Fixing...") : (cursorWarningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background - enabled: !themeColorsTab.fixingCursorInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: themeColorsTab.fixCursorInclude() - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "theme"] - settingKey: "cursorTheme" - text: I18n.tr("Cursor Theme") - description: I18n.tr("Mouse pointer appearance") - currentValue: SettingsData.cursorSettings.theme - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 236 - options: cachedCursorThemes - onValueChanged: value => { - SettingsData.setCursorTheme(value); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "size"] - settingKey: "cursorSize" - text: I18n.tr("Cursor Size") - description: I18n.tr("Mouse pointer size in pixels") - value: SettingsData.cursorSettings.size - minimum: 12 - maximum: 128 - unit: "px" - defaultValue: 24 - onSliderValueChanged: newValue => SettingsData.setCursorSize(newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["cursor", "hide", "typing"] - settingKey: "cursorHideWhenTyping" - text: I18n.tr("Hide When Typing") - description: I18n.tr("Hide cursor when pressing keyboard keys") - visible: CompositorService.isNiri || CompositorService.isHyprland - checked: { - if (CompositorService.isNiri) - return SettingsData.cursorSettings.niri?.hideWhenTyping || false; - if (CompositorService.isHyprland) - return SettingsData.cursorSettings.hyprland?.hideOnKeyPress || false; - return false; - } - onToggled: checked => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (CompositorService.isNiri) { - if (!updated.niri) - updated.niri = {}; - updated.niri.hideWhenTyping = checked; - } else if (CompositorService.isHyprland) { - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.hideOnKeyPress = checked; - } - SettingsData.set("cursorSettings", updated); - } - } - - SettingsToggleRow { - tab: "theme" - tags: ["cursor", "hide", "touch"] - settingKey: "cursorHideOnTouch" - text: I18n.tr("Hide on Touch") - description: I18n.tr("Hide cursor when using touch input") - visible: CompositorService.isHyprland - checked: SettingsData.cursorSettings.hyprland?.hideOnTouch || false - onToggled: checked => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.hideOnTouch = checked; - SettingsData.set("cursorSettings", updated); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["cursor", "hide", "timeout", "inactive"] - settingKey: "cursorHideAfterInactive" - text: I18n.tr("Auto-Hide Timeout") - description: I18n.tr("Hide cursor after inactivity (0 = disabled)") - value: { - if (CompositorService.isNiri) - return SettingsData.cursorSettings.niri?.hideAfterInactiveMs || 0; - if (CompositorService.isHyprland) - return SettingsData.cursorSettings.hyprland?.inactiveTimeout || 0; - if (CompositorService.isDwl) - return SettingsData.cursorSettings.dwl?.cursorHideTimeout || 0; - return 0; - } - minimum: 0 - maximum: CompositorService.isNiri ? 5000 : 10 - unit: CompositorService.isNiri ? "ms" : "s" - defaultValue: 0 - onSliderValueChanged: newValue => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (CompositorService.isNiri) { - if (!updated.niri) - updated.niri = {}; - updated.niri.hideAfterInactiveMs = newValue; - } else if (CompositorService.isHyprland) { - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.inactiveTimeout = newValue; - } else if (CompositorService.isDwl) { - if (!updated.dwl) - updated.dwl = {}; - updated.dwl.cursorHideTimeout = newValue; - } - SettingsData.set("cursorSettings", updated); - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["icon", "theme", "system"] - title: I18n.tr("Icon Theme") - settingKey: "iconTheme" - iconName: "interests" - - SettingsDropdownRow { - tab: "theme" - tags: ["icon", "theme", "system"] - settingKey: "iconTheme" - text: I18n.tr("Icon Theme") - description: I18n.tr("DankShell & System Icons (requires restart)") - currentValue: SettingsData.iconTheme - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 236 - options: cachedIconThemes - onValueChanged: value => { - SettingsData.setIconTheme(value); - if (Quickshell.env("QT_QPA_PLATFORMTHEME") != "gtk3" && Quickshell.env("QT_QPA_PLATFORMTHEME") != "qt6ct" && Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") != "qt6ct") { - ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", "qt theme env error body")); - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["matugen", "templates", "theming"] - title: I18n.tr("Matugen Templates") - settingKey: "matugenTemplates" - iconName: "auto_awesome" - collapsible: true - expanded: false - visible: Theme.matugenAvailable - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "user", "templates"] - settingKey: "runUserMatugenTemplates" - text: I18n.tr("Run User Templates") - description: "" - checked: SettingsData.runUserMatugenTemplates - onToggled: checked => SettingsData.set("runUserMatugenTemplates", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "dms", "templates"] - settingKey: "runDmsMatugenTemplates" - text: I18n.tr("Run DMS Templates") - description: "" - checked: SettingsData.runDmsMatugenTemplates - onToggled: checked => SettingsData.set("runDmsMatugenTemplates", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "gtk", "template"] - settingKey: "matugenTemplateGtk" - text: "GTK" - description: getTemplateDescription("gtk", "") - descriptionColor: getTemplateDescriptionColor("gtk") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateGtk - onToggled: checked => SettingsData.set("matugenTemplateGtk", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "niri", "template"] - settingKey: "matugenTemplateNiri" - text: "niri" - description: getTemplateDescription("niri", "") - descriptionColor: getTemplateDescriptionColor("niri") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateNiri - onToggled: checked => SettingsData.set("matugenTemplateNiri", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "hyprland", "template"] - settingKey: "matugenTemplateHyprland" - text: "Hyprland" - description: getTemplateDescription("hyprland", "") - descriptionColor: getTemplateDescriptionColor("hyprland") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateHyprland - onToggled: checked => SettingsData.set("matugenTemplateHyprland", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "mangowc", "template"] - settingKey: "matugenTemplateMangowc" - text: "mangowc" - description: getTemplateDescription("mangowc", "") - descriptionColor: getTemplateDescriptionColor("mangowc") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateMangowc - onToggled: checked => SettingsData.set("matugenTemplateMangowc", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "qt5ct", "template"] - settingKey: "matugenTemplateQt5ct" - text: "qt5ct" - description: getTemplateDescription("qt5ct", "") - descriptionColor: getTemplateDescriptionColor("qt5ct") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateQt5ct - onToggled: checked => SettingsData.set("matugenTemplateQt5ct", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "qt6ct", "template"] - settingKey: "matugenTemplateQt6ct" - text: "qt6ct" - description: getTemplateDescription("qt6ct", "") - descriptionColor: getTemplateDescriptionColor("qt6ct") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateQt6ct - onToggled: checked => SettingsData.set("matugenTemplateQt6ct", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "firefox", "template"] - settingKey: "matugenTemplateFirefox" - text: "Firefox" - description: getTemplateDescription("firefox", "") - descriptionColor: getTemplateDescriptionColor("firefox") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateFirefox - onToggled: checked => SettingsData.set("matugenTemplateFirefox", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "pywalfox", "template"] - settingKey: "matugenTemplatePywalfox" - text: "pywalfox" - description: getTemplateDescription("pywalfox", "") - descriptionColor: getTemplateDescriptionColor("pywalfox") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplatePywalfox - onToggled: checked => SettingsData.set("matugenTemplatePywalfox", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "zenbrowser", "template"] - settingKey: "matugenTemplateZenBrowser" - text: "zenbrowser" - description: getTemplateDescription("zenbrowser", "") - descriptionColor: getTemplateDescriptionColor("zenbrowser") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateZenBrowser - onToggled: checked => SettingsData.set("matugenTemplateZenBrowser", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "vesktop", "discord", "template"] - settingKey: "matugenTemplateVesktop" - text: "vesktop" - description: getTemplateDescription("vesktop", "") - descriptionColor: getTemplateDescriptionColor("vesktop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateVesktop - onToggled: checked => SettingsData.set("matugenTemplateVesktop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "equibop", "discord", "template"] - settingKey: "matugenTemplateEquibop" - text: "equibop" - description: getTemplateDescription("equibop", "") - descriptionColor: getTemplateDescriptionColor("equibop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateEquibop - onToggled: checked => SettingsData.set("matugenTemplateEquibop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "ghostty", "terminal", "template"] - settingKey: "matugenTemplateGhostty" - text: "Ghostty" - description: getTemplateDescription("ghostty", "") - descriptionColor: getTemplateDescriptionColor("ghostty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateGhostty - onToggled: checked => SettingsData.set("matugenTemplateGhostty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "kitty", "terminal", "template"] - settingKey: "matugenTemplateKitty" - text: "kitty" - description: getTemplateDescription("kitty", "") - descriptionColor: getTemplateDescriptionColor("kitty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateKitty - onToggled: checked => SettingsData.set("matugenTemplateKitty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "foot", "terminal", "template"] - settingKey: "matugenTemplateFoot" - text: "foot" - description: getTemplateDescription("foot", "") - descriptionColor: getTemplateDescriptionColor("foot") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateFoot - onToggled: checked => SettingsData.set("matugenTemplateFoot", checked) - } - - SettingsDivider { - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - } - - SettingsToggleRow { - id: neovimThemeToggle - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovim" - text: "neovim" - description: getTemplateDescription("nvim", I18n.tr("Required plugin: ") + "https://github.com/AvengeMedia/base46") - descriptionColor: getTemplateDescriptionColor("nvim") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateNeovim - onToggled: checked => SettingsData.set("matugenTemplateNeovim", checked) - } - - SettingsDropdownRow { - text: I18n.tr("Dark mode base") - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "Base to derive dark theme from" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - currentValue: SettingsData.matugenTemplateNeovimSettings?.dark?.baseTheme ?? "github_dark" - options: ["aquarium", "ashes", "aylin", "ayu_dark", "bearded-arc", "carbonfox", "catppuccin", "chadracula", "chadracula-evondev", "chadtain", "chocolate", "darcula-dark", "dark_horizon", "decay", "default-dark", "doomchad", "eldritch", "embark", "everblush", "everforest", "falcon", "flexoki", "flouromachine", "gatekeeper", "github_dark", "gruvbox", "gruvchad", "hiberbee", "horizon", "jabuti", "jellybeans", "kanagawa", "kanagawa-dragon", "material-darker", "material-deep-ocean", "melange", "midnight_breeze", "mito-laser", "monekai", "monochrome", "mountain", "neofusion", "nightfox", "nightlamp", "nightowl", "nord", "obsidian-ember", "oceanic-next", "onedark", "onenord", "oxocarbon", "palenight", "pastelDark", "pastelbeans", "penumbra_dark", "poimandres", "radium", "rosepine", "rxyhn", "scaryforest", "seoul256_dark", "solarized_dark", "solarized_osaka", "starlight", "sweetpastel", "tokyodark", "tokyonight", "tomorrow_night", "tundra", "vesper", "vscode_dark", "wombat", "yoru", "zenburn"] - enableFuzzySearch: true - onValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.dark.baseTheme = value; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsDropdownRow { - text: I18n.tr("Light mode base") - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "Base to derive light theme from" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - currentValue: SettingsData.matugenTemplateNeovimSettings?.light?.baseTheme ?? "github_light" - options: ["ayu_light", "blossom_light", "catppuccin-latte", "default-light", "everforest_light", "flex-light", "flexoki-light", "github_light", "gruvbox_light", "material-lighter", "nano-light", "oceanic-light", "one_light", "onenord_light", "penumbra_light", "rosepine-dawn", "seoul256_light", "solarized_light", "sunrise_breeze", "vscode_light"] - enableFuzzySearch: true - onValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.light.baseTheme = value; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsSliderRow { - text: I18n.tr("Dark mode harmony") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "How much should the base dark theme be tinted" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - minimum: 0 - maximum: 100 - value: (SettingsData.matugenTemplateNeovimSettings?.dark?.harmony ?? 0.5) * 100 - defaultValue: 50 - onSliderValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.dark.harmony = value / 100; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsSliderRow { - text: I18n.tr("Light mode harmony") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "How much should the base light theme be tinted" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - minimum: 0 - maximum: 100 - value: (SettingsData.matugenTemplateNeovimSettings?.light?.harmony ?? 0.5) * 100 - defaultValue: 50 - onSliderValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.light.harmony = value / 100; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsToggleRow { - text: I18n.tr("Follow DMS background color") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSetBackground" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - checked: SettingsData.matugenTemplateNeovimSetBackground ?? true - onToggled: checked => SettingsData.set("matugenTemplateNeovimSetBackground", checked) - } - - SettingsDivider { - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "alacritty", "terminal", "template"] - settingKey: "matugenTemplateAlacritty" - text: "Alacritty" - description: getTemplateDescription("alacritty", "") - descriptionColor: getTemplateDescriptionColor("alacritty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateAlacritty - onToggled: checked => SettingsData.set("matugenTemplateAlacritty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "wezterm", "terminal", "template"] - settingKey: "matugenTemplateWezterm" - text: "WezTerm" - description: getTemplateDescription("wezterm", "") - descriptionColor: getTemplateDescriptionColor("wezterm") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateWezterm - onToggled: checked => SettingsData.set("matugenTemplateWezterm", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "dgop", "template"] - settingKey: "matugenTemplateDgop" - text: "dgop" - description: getTemplateDescription("dgop", "") - descriptionColor: getTemplateDescriptionColor("dgop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateDgop - onToggled: checked => SettingsData.set("matugenTemplateDgop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "kcolorscheme", "kde", "template"] - settingKey: "matugenTemplateKcolorscheme" - text: "KColorScheme" - description: getTemplateDescription("kcolorscheme", "") - descriptionColor: getTemplateDescriptionColor("kcolorscheme") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateKcolorscheme - onToggled: checked => SettingsData.set("matugenTemplateKcolorscheme", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "vscode", "code", "template"] - settingKey: "matugenTemplateVscode" - text: "VS Code" - description: getTemplateDescription("vscode", "") - descriptionColor: getTemplateDescriptionColor("vscode") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateVscode - onToggled: checked => SettingsData.set("matugenTemplateVscode", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "emacs", "template"] - settingKey: "matugenTemplateEmacs" - text: "Emacs" - description: getTemplateDescription("emacs", "") - descriptionColor: getTemplateDescriptionColor("emacs") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateEmacs - onToggled: checked => SettingsData.set("matugenTemplateEmacs", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "zed", "template"] - settingKey: "matugenTemplateZed" - text: "Zed" - description: getTemplateDescription("zed", "") - descriptionColor: getTemplateDescriptionColor("zed") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateZed - onToggled: checked => SettingsData.set("matugenTemplateZed", checked) - } - } - - Rectangle { - width: parent.width - height: warningText.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: warningText - font.pixelSize: Theme.fontSizeSmall - text: I18n.tr("The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - - SettingsCard { - tab: "theme" - tags: ["system", "app", "theming", "gtk", "qt"] - title: I18n.tr("System App Theming") - settingKey: "systemAppTheming" - iconName: "brush" - visible: Theme.matugenAvailable - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "folder" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Apply GTK Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.primary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.applyGtkColors() - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "settings" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Apply Qt Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.primary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.applyQtColors() - } - } - } - - StyledText { - text: I18n.tr('Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.').arg(Theme.primary) - textFormat: Text.RichText - linkColor: Theme.primary - onLinkActivated: url => Qt.openUrlExternally(url) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignHCenter - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - } - - FileBrowserModal { - id: fileBrowserModal - browserTitle: I18n.tr("Select Custom Theme", "custom theme file browser title") - filterExtensions: ["*.json"] - showHiddenFiles: true - - function selectCustomTheme() { - shouldBeVisible = true; - } - - onFileSelected: function (filePath) { - if (filePath.endsWith(".json")) { - SettingsData.set("customThemeFile", filePath); - Theme.switchTheme("custom"); - close(); - } - } - } - - LazyLoader { - id: themeBrowserLoader - active: false - - ThemeBrowser { - id: themeBrowserItem - } - } - - function showThemeBrowser() { - themeBrowserLoader.active = true; - if (themeBrowserLoader.item) - themeBrowserLoader.item.show(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml deleted file mode 100644 index 61f4d43..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml +++ /dev/null @@ -1,1148 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property string _systemDefaultLabel: I18n.tr("System Default") - - function weekStartQt() { - if (SettingsData.firstDayOfWeek < 0 || SettingsData.firstDayOfWeek >= 7) - return Qt.locale().firstDayOfWeek; - return SettingsData.firstDayOfWeek; - } - - function weekStartJs() { - return weekStartQt() % 7; - } - - function _dayNames() { - return Array(7).fill(0).map((_, i) => new Date(Date.UTC(2026, 2, 1 + i, 0, 0, 0)).toLocaleDateString(I18n.locale(), "dddd")).map(d => d[0].toUpperCase() + d.slice(1)); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "time" - tags: ["time", "clock", "format", "24hour"] - title: I18n.tr("Time Format") - settingKey: "timeFormat" - iconName: "schedule" - - SettingsToggleRow { - tab: "time" - tags: ["time", "24hour", "format"] - settingKey: "use24HourClock" - text: I18n.tr("24-Hour Format") - description: I18n.tr("Use 24-hour time format instead of 12-hour AM/PM") - checked: SettingsData.use24HourClock - onToggled: checked => SettingsData.set("use24HourClock", checked) - } - - SettingsToggleRow { - tab: "time" - tags: ["time", "seconds", "clock"] - settingKey: "showSeconds" - text: I18n.tr("Show Seconds") - description: I18n.tr("Display seconds in the clock") - checked: SettingsData.showSeconds - onToggled: checked => SettingsData.set("showSeconds", checked) - } - - SettingsToggleRow { - tab: "time" - tags: ["time", "12hour", "format", "padding", "leading", "zero"] - settingKey: "padHours12Hour" - text: I18n.tr("Pad Hours") - description: "02:31 PM vs 2:31 PM" - checked: SettingsData.padHours12Hour - onToggled: checked => SettingsData.set("padHours12Hour", checked) - visible: !SettingsData.use24HourClock - } - } - - SettingsCard { - tab: "time" - tags: ["date", "format", "calendar"] - title: I18n.tr("Date Format") - settingKey: "dateFormat" - iconName: "calendar_today" - - SettingsToggleRow { - tab: "time" - tags: ["show", "week"] - settingKey: "showWeekNumber" - text: I18n.tr("Show Week Number") - description: I18n.tr("Show week number in the calendar") - checked: SettingsData.showWeekNumber - onToggled: checked => SettingsData.set("showWeekNumber", checked) - } - - SettingsDropdownRow { - tab: "time" - tags: ["first", "day", "week"] - settingKey: "firstDayOfWeek" - text: I18n.tr("First Day of Week") - options: [root._systemDefaultLabel].concat(root._dayNames()) - currentValue: { - if (SettingsData.firstDayOfWeek < 0 || SettingsData.firstDayOfWeek >= 7) - return root._systemDefaultLabel; - return root._dayNames()[root.weekStartJs()]; - } - onValueChanged: value => { - if (value === root._systemDefaultLabel) { - SettingsData.set("firstDayOfWeek", -1); - return; - } - SettingsData.set("firstDayOfWeek", root._dayNames().indexOf(value)); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "time" - tags: ["date", "format", "topbar"] - settingKey: "clockDateFormat" - text: I18n.tr("Top Bar Format") - description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(I18n.locale(), "ddd d")) - options: [I18n.tr("System Default", "date format option"), I18n.tr("Day Date", "date format option"), I18n.tr("Day Month Date", "date format option"), I18n.tr("Month Date", "date format option"), I18n.tr("Numeric (M/D)", "date format option"), I18n.tr("Numeric (D/M)", "date format option"), I18n.tr("Full with Year", "date format option"), I18n.tr("ISO Date", "date format option"), I18n.tr("Full Day & Month", "date format option"), I18n.tr("Custom...", "date format option")] - currentValue: { - if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) - return I18n.tr("System Default", "date format option"); - const presets = [ - { - "format": "ddd d", - "label": I18n.tr("Day Date", "date format option") - }, - { - "format": "ddd MMM d", - "label": I18n.tr("Day Month Date", "date format option") - }, - { - "format": "MMM d", - "label": I18n.tr("Month Date", "date format option") - }, - { - "format": "M/d", - "label": I18n.tr("Numeric (M/D)", "date format option") - }, - { - "format": "d/M", - "label": I18n.tr("Numeric (D/M)", "date format option") - }, - { - "format": "ddd d MMM yyyy", - "label": I18n.tr("Full with Year", "date format option") - }, - { - "format": "yyyy-MM-dd", - "label": I18n.tr("ISO Date", "date format option") - }, - { - "format": "dddd, MMMM d", - "label": I18n.tr("Full Day & Month", "date format option") - } - ]; - const match = presets.find(p => p.format === SettingsData.clockDateFormat); - return match ? match.label : I18n.tr("Custom: ") + SettingsData.clockDateFormat; - } - onValueChanged: value => { - const formatMap = {}; - formatMap[I18n.tr("System Default", "date format option")] = ""; - formatMap[I18n.tr("Day Date", "date format option")] = "ddd d"; - formatMap[I18n.tr("Day Month Date", "date format option")] = "ddd MMM d"; - formatMap[I18n.tr("Month Date", "date format option")] = "MMM d"; - formatMap[I18n.tr("Numeric (M/D)", "date format option")] = "M/d"; - formatMap[I18n.tr("Numeric (D/M)", "date format option")] = "d/M"; - formatMap[I18n.tr("Full with Year", "date format option")] = "ddd d MMM yyyy"; - formatMap[I18n.tr("ISO Date", "date format option")] = "yyyy-MM-dd"; - formatMap[I18n.tr("Full Day & Month", "date format option")] = "dddd, MMMM d"; - if (value === I18n.tr("Custom...", "date format option")) { - customFormatInput.visible = true; - } else { - customFormatInput.visible = false; - SettingsData.set("clockDateFormat", formatMap[value]); - } - } - } - - DankTextField { - id: customFormatInput - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - visible: false - placeholderText: I18n.tr("Enter custom top bar format (e.g., ddd MMM d)") - text: SettingsData.clockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.set("clockDateFormat", text); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "time" - tags: ["date", "format", "lock", "screen"] - settingKey: "lockDateFormat" - text: I18n.tr("Lock Screen Format") - description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(I18n.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(I18n.locale(), Locale.LongFormat)) - options: [I18n.tr("System Default", "date format option"), I18n.tr("Day Date", "date format option"), I18n.tr("Day Month Date", "date format option"), I18n.tr("Month Date", "date format option"), I18n.tr("Numeric (M/D)", "date format option"), I18n.tr("Numeric (D/M)", "date format option"), I18n.tr("Full with Year", "date format option"), I18n.tr("ISO Date", "date format option"), I18n.tr("Full Day & Month", "date format option"), I18n.tr("Custom...", "date format option")] - currentValue: { - if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) - return I18n.tr("System Default", "date format option"); - const presets = [ - { - "format": "ddd d", - "label": I18n.tr("Day Date", "date format option") - }, - { - "format": "ddd MMM d", - "label": I18n.tr("Day Month Date", "date format option") - }, - { - "format": "MMM d", - "label": I18n.tr("Month Date", "date format option") - }, - { - "format": "M/d", - "label": I18n.tr("Numeric (M/D)", "date format option") - }, - { - "format": "d/M", - "label": I18n.tr("Numeric (D/M)", "date format option") - }, - { - "format": "ddd d MMM yyyy", - "label": I18n.tr("Full with Year", "date format option") - }, - { - "format": "yyyy-MM-dd", - "label": I18n.tr("ISO Date", "date format option") - }, - { - "format": "dddd, MMMM d", - "label": I18n.tr("Full Day & Month", "date format option") - } - ]; - const match = presets.find(p => p.format === SettingsData.lockDateFormat); - return match ? match.label : I18n.tr("Custom: ") + SettingsData.lockDateFormat; - } - onValueChanged: value => { - const formatMap = {}; - formatMap[I18n.tr("System Default", "date format option")] = ""; - formatMap[I18n.tr("Day Date", "date format option")] = "ddd d"; - formatMap[I18n.tr("Day Month Date", "date format option")] = "ddd MMM d"; - formatMap[I18n.tr("Month Date", "date format option")] = "MMM d"; - formatMap[I18n.tr("Numeric (M/D)", "date format option")] = "M/d"; - formatMap[I18n.tr("Numeric (D/M)", "date format option")] = "d/M"; - formatMap[I18n.tr("Full with Year", "date format option")] = "ddd d MMM yyyy"; - formatMap[I18n.tr("ISO Date", "date format option")] = "yyyy-MM-dd"; - formatMap[I18n.tr("Full Day & Month", "date format option")] = "dddd, MMMM d"; - if (value === I18n.tr("Custom...", "date format option")) { - customLockFormatInput.visible = true; - } else { - customLockFormatInput.visible = false; - SettingsData.set("lockDateFormat", formatMap[value]); - } - } - } - - DankTextField { - id: customLockFormatInput - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - visible: false - placeholderText: I18n.tr("Enter custom lock screen format (e.g., dddd, MMMM d)") - text: SettingsData.lockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.set("lockDateFormat", text); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Rectangle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - height: formatHelp.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: formatHelp - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Format Legend") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingL - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("• d - Day (1-31)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• dd - Day (01-31)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• ddd - Day name (Mon)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• dddd - Day name (Monday)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• M - Month (1-12)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("• MM - Month (01-12)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• MMM - Month (Jan)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• MMMM - Month (January)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• yy - Year (24)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• yyyy - Year (2024)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - - SettingsCard { - tab: "time" - tags: ["weather", "enable", "forecast"] - title: I18n.tr("Weather") - settingKey: "weather" - iconName: "cloud" - - SettingsToggleRow { - tab: "time" - tags: ["weather", "enable"] - settingKey: "weatherEnabled" - text: I18n.tr("Enable Weather") - description: I18n.tr("Show weather information in top bar and control center") - checked: SettingsData.weatherEnabled - onToggled: checked => SettingsData.set("weatherEnabled", checked) - } - - Column { - width: parent.width - spacing: 0 - visible: SettingsData.weatherEnabled - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "imperial", "fahrenheit", "units"] - settingKey: "useFahrenheit" - text: I18n.tr("Use Imperial Units") - description: I18n.tr("Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)") - checked: SettingsData.useFahrenheit - onToggled: checked => SettingsData.set("useFahrenheit", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: !SettingsData.useFahrenheit - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "wind", "speed", "units", "metric"] - settingKey: "windSpeedUnit" - text: I18n.tr("Wind Speed in m/s") - description: I18n.tr("Use meters per second instead of km/h for wind speed") - checked: SettingsData.windSpeedUnit === "ms" - onToggled: checked => SettingsData.set("windSpeedUnit", checked ? "ms" : "kmh") - visible: !SettingsData.useFahrenheit - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "location", "auto", "gps"] - settingKey: "useAutoLocation" - text: I18n.tr("Auto Location") - description: I18n.tr("Automatically determine your location using your IP address") - checked: SettingsData.useAutoLocation - onToggled: checked => SettingsData.set("useAutoLocation", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !SettingsData.useAutoLocation - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: locationContent.height - - Column { - id: locationContent - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Location") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: latitudeInput - width: parent.width - height: 48 - placeholderText: "40.7128" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: longitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 0) - text = coords[0].trim(); - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 0) - latitudeInput.text = coords[0].trim(); - } - } - } - - onTextEdited: { - if (text && longitudeInput.text) { - const coords = text + "," + longitudeInput.text; - SessionData.weatherCoordinates = coords; - SessionData.saveSettings(); - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: longitudeInput - width: parent.width - height: 48 - placeholderText: "-74.0060" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: locationSearchInput - keyNavigationBacktab: latitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 1) - text = coords[1].trim(); - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 1) - longitudeInput.text = coords[1].trim(); - } - } - } - - onTextEdited: { - if (text && latitudeInput.text) { - const coords = latitudeInput.text + "," + text; - SessionData.weatherCoordinates = coords; - SessionData.saveSettings(); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Location Search") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - } - - DankLocationSearch { - id: locationSearchInput - width: parent.width - currentLocation: "" - placeholderText: I18n.tr("New York, NY") - keyNavigationBacktab: longitudeInput - onLocationSelected: (displayName, coordinates) => { - SettingsData.setWeatherLocation(displayName, coordinates); - const coords = coordinates.split(','); - if (coords.length >= 2) { - latitudeInput.text = coords[0].trim(); - longitudeInput.text = coords[1].trim(); - } - } - } - } - } - } - } - } - } - - SettingsCard { - tab: "time" - tags: ["weather", "current", "display"] - title: I18n.tr("Current Weather") - settingKey: "weather" - iconName: "visibility" - visible: SettingsData.weatherEnabled - - Column { - width: parent.width - spacing: Theme.spacingL - visible: !WeatherService.weather.available - - DankIcon { - name: "cloud_off" - size: Theme.iconSize * 2 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Weather Data Available") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: WeatherService.weather.available - - Item { - width: parent.width - height: 70 - - DankIcon { - id: refreshButton - name: "refresh" - size: Theme.iconSize - 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - anchors.right: parent.right - anchors.top: parent.top - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - onClicked: { - refreshButton.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimer.restart(); - } - enabled: parent.enabled - } - - Timer { - id: refreshTimer - interval: 2000 - onTriggered: refreshButton.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButton.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - width: weatherIcon.width + tempColumn.width + sunriseColumn.width + Theme.spacingM * 2 - height: 70 - - DankIcon { - id: weatherIcon - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize * 1.5 - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - } - } - - Column { - id: tempColumn - spacing: Theme.spacingXS - anchors.left: weatherIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - - Item { - width: tempText.width + unitText.width + Theme.spacingXS - height: tempText.height - - StyledText { - id: tempText - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge + 4 - color: Theme.surfaceText - font.weight: Font.Light - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: unitText - text: SettingsData.useFahrenheit ? "F" : "C" - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.left: tempText.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (WeatherService.weather.available) - SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit); - } - enabled: WeatherService.weather.available - } - } - } - - StyledText { - property var feelsLike: SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp) - text: I18n.tr("Feels Like %1°").arg(feelsLike) - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - } - - StyledText { - text: WeatherService.weather.city || "" - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - visible: text.length > 0 - } - } - - Column { - id: sunriseColumn - spacing: Theme.spacingXS - anchors.left: tempColumn.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: WeatherService.weather.sunrise && WeatherService.weather.sunset - - Item { - width: sunriseIcon.width + sunriseText.width + Theme.spacingXS - height: sunriseIcon.height - - DankIcon { - id: sunriseIcon - name: "wb_twilight" - size: Theme.iconSize - 6 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: sunriseText - text: WeatherService.weather.sunrise || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: sunriseIcon.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - width: sunsetIcon.width + sunsetText.width + Theme.spacingXS - height: sunsetIcon.height - - DankIcon { - id: sunsetIcon - name: "bedtime" - size: Theme.iconSize - 6 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: sunsetText - text: WeatherService.weather.sunset || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: sunsetIcon.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - GridLayout { - width: parent.width - height: 95 - columns: 6 - columnSpacing: Theme.spacingS - rowSpacing: 0 - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "device_thermostat" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Feels Like") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: (SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp)) + "°" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "humidity_low" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Humidity") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: WeatherService.weather.humidity ? WeatherService.weather.humidity + "%" : "--" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "air" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Wind") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - id: windText - text: { - SettingsData.windSpeedUnit; - SettingsData.useFahrenheit; - return WeatherService.formatSpeed(WeatherService.weather.wind) || "--"; - } - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: SettingsData.useFahrenheit ? Qt.ArrowCursor : Qt.PointingHandCursor - enabled: !SettingsData.useFahrenheit - onClicked: SettingsData.set("windSpeedUnit", SettingsData.windSpeedUnit === "kmh" ? "ms" : "kmh") - } - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "speed" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Pressure") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: { - if (!WeatherService.weather.pressure) - return "--"; - if (SettingsData.useFahrenheit) - return (WeatherService.weather.pressure * 0.02953).toFixed(2) + " inHg"; - return WeatherService.weather.pressure + " hPa"; - } - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "rainy" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Rain Chance") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: WeatherService.weather.precipitationProbability ? WeatherService.weather.precipitationProbability + "%" : "0%" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "wb_sunny" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Visibility") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: I18n.tr("Good") - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml deleted file mode 100644 index 8648acb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml +++ /dev/null @@ -1,490 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - property var cachedFontFamilies: [] - property var cachedMonoFamilies: [] - property bool fontsEnumerated: false - - function enumerateFonts() { - var fonts = []; - var availableFonts = Qt.fontFamilies(); - - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - fonts.push(fontName); - } - fonts.sort(); - fonts.unshift("Default"); - cachedFontFamilies = fonts; - cachedMonoFamilies = fonts; - } - - Timer { - id: fontEnumerationTimer - interval: 50 - running: false - onTriggered: { - if (fontsEnumerated) - return; - enumerateFonts(); - fontsEnumerated = true; - } - } - - Component.onCompleted: { - fontEnumerationTimer.start(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "typography" - tags: ["font", "family", "text", "typography"] - title: I18n.tr("Typography") - settingKey: "typography" - iconName: "text_fields" - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "family", "normal", "text"] - settingKey: "fontFamily" - text: I18n.tr("Normal Font") - description: I18n.tr("Select the font family for UI text") - options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"] - currentValue: SettingsData.fontFamily === Theme.defaultFontFamily ? "Default" : (SettingsData.fontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("fontFamily", Theme.defaultFontFamily); - else - SettingsData.set("fontFamily", value); - } - } - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "monospace", "code", "terminal"] - settingKey: "monoFontFamily" - text: I18n.tr("Monospace Font") - description: I18n.tr("Select monospace font for process list and technical displays") - options: root.fontsEnumerated ? root.cachedMonoFamilies : ["Default"] - currentValue: SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily ? "Default" : (SettingsData.monoFontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("monoFontFamily", SettingsData.defaultMonoFontFamily); - else - SettingsData.set("monoFontFamily", value); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "weight", "bold", "light"] - settingKey: "fontWeight" - text: I18n.tr("Font Weight") - description: I18n.tr("Select font weight for UI text") - options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"] - currentValue: { - switch (SettingsData.fontWeight) { - case Font.Thin: - return "Thin"; - case Font.ExtraLight: - return "Extra Light"; - case Font.Light: - return "Light"; - case Font.Normal: - return "Regular"; - case Font.Medium: - return "Medium"; - case Font.DemiBold: - return "Demi Bold"; - case Font.Bold: - return "Bold"; - case Font.ExtraBold: - return "Extra Bold"; - case Font.Black: - return "Black"; - default: - return "Regular"; - } - } - onValueChanged: value => { - var weight; - switch (value) { - case "Thin": - weight = Font.Thin; - break; - case "Extra Light": - weight = Font.ExtraLight; - break; - case "Light": - weight = Font.Light; - break; - case "Regular": - weight = Font.Normal; - break; - case "Medium": - weight = Font.Medium; - break; - case "Demi Bold": - weight = Font.DemiBold; - break; - case "Bold": - weight = Font.Bold; - break; - case "Extra Bold": - weight = Font.ExtraBold; - break; - case "Black": - weight = Font.Black; - break; - default: - weight = Font.Normal; - break; - } - SettingsData.set("fontWeight", weight); - } - } - - SettingsSliderRow { - tab: "typography" - tags: ["font", "scale", "size", "zoom"] - settingKey: "fontScale" - text: I18n.tr("Font Scale") - description: I18n.tr("Scale all font sizes throughout the shell") - minimum: 75 - maximum: 150 - value: Math.round(SettingsData.fontScale * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("fontScale", newValue / 100) - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration"] - title: I18n.tr("Animation Speed") - settingKey: "animationSpeed" - iconName: "animation" - - Item { - width: parent.width - height: animationSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: animationSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.animationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("animationSpeed", index); - } - - Connections { - target: SettingsData - function onAnimationSpeedChanged() { - animationSpeedGroup.currentIndex = SettingsData.animationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: durationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed"] - settingKey: "customAnimationDuration" - text: I18n.tr("Animation Duration") - description: I18n.tr("Globally scale all animation durations") - minimum: 0 - maximum: 1000 - value: Theme.currentAnimationBaseDuration - unit: "ms" - defaultValue: 200 - onSliderValueChanged: newValue => { - SettingsData.set("animationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("customAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onAnimationSpeedChanged() { - if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) - return; - durationSlider.value = Theme.currentAnimationBaseDuration; - } - } - - Connections { - target: Theme - function onCurrentAnimationBaseDurationChanged() { - if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) - return; - durationSlider.value = Theme.currentAnimationBaseDuration; - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "typography" - tags: ["animation", "sync", "popout", "modal", "global"] - settingKey: "syncComponentAnimationSpeeds" - text: I18n.tr("Sync Popouts & Modals") - description: I18n.tr("Popouts and Modals follow global Animation Speed (disable to customize independently)") - checked: SettingsData.syncComponentAnimationSpeeds - onToggled: checked => SettingsData.set("syncComponentAnimationSpeeds", checked) - - Connections { - target: SettingsData - function onSyncComponentAnimationSpeedsChanged() { - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration", "popout", "sync"] - title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Popouts")) - settingKey: "popoutAnimationSpeed" - iconName: "open_in_new" - - Item { - width: parent.width - height: popoutSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: popoutSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.popoutAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("popoutAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onPopoutAnimationSpeedChanged() { - popoutSpeedGroup.currentIndex = SettingsData.popoutAnimationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: popoutDurationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed", "popout"] - settingKey: "popoutCustomAnimationDuration" - text: I18n.tr("Custom Duration") - description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Popouts")) - minimum: 0 - maximum: 1000 - value: Theme.popoutAnimationDuration - unit: "ms" - defaultValue: 150 - onSliderValueChanged: newValue => { - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("popoutAnimationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("popoutCustomAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onPopoutAnimationSpeedChanged() { - if (SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - popoutDurationSlider.value = Theme.popoutAnimationDuration; - } - } - - Connections { - target: Theme - function onPopoutAnimationDurationChanged() { - if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - popoutDurationSlider.value = Theme.popoutAnimationDuration; - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration", "modal", "sync"] - title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Modals")) - settingKey: "modalAnimationSpeed" - iconName: "web_asset" - - Item { - width: parent.width - height: modalSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: modalSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.modalAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("modalAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onModalAnimationSpeedChanged() { - modalSpeedGroup.currentIndex = SettingsData.modalAnimationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: modalDurationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed", "modal"] - settingKey: "modalCustomAnimationDuration" - text: I18n.tr("Custom Duration") - description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Modals")) - minimum: 0 - maximum: 1000 - value: Theme.modalAnimationDuration - unit: "ms" - defaultValue: 150 - onSliderValueChanged: newValue => { - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("modalAnimationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("modalCustomAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onModalAnimationSpeedChanged() { - if (SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - modalDurationSlider.value = Theme.modalAnimationDuration; - } - } - - Connections { - target: Theme - function onModalAnimationDurationChanged() { - if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - modalDurationSlider.value = Theme.modalAnimationDuration; - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "ripple", "effect", "material", "feedback"] - title: I18n.tr("Ripple Effects") - settingKey: "enableRippleEffects" - iconName: "radio_button_unchecked" - - SettingsToggleRow { - tab: "typography" - tags: ["animation", "ripple", "effect", "material", "click"] - settingKey: "enableRippleEffects" - text: I18n.tr("Enable Ripple Effects") - description: I18n.tr("Show Material Design ripple animations on interactive elements") - checked: SettingsData.enableRippleEffects ?? true - onToggled: newValue => SettingsData.set("enableRippleEffects", newValue) - - Connections { - target: SettingsData - function onEnableRippleEffectsChanged() { - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml deleted file mode 100644 index c0f83c1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml +++ /dev/null @@ -1,1368 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedMonitorName: { - var screens = Quickshell.screens; - return screens.length > 0 ? screens[0].name : ""; - } - property string currentWallpaper: { - if (!SessionData.perMonitorWallpaper) - return SessionData.wallpaperPath; - var map = SessionData.monitorWallpapers; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name !== selectedMonitorName) - continue; - var screen = screens[i]; - if (map[screen.name] !== undefined) - return map[screen.name]; - if (screen.model && map[screen.model] !== undefined) - return map[screen.model]; - var displayName = SettingsData.getScreenDisplayName(screen); - if (displayName && map[displayName] !== undefined) - return map[displayName]; - break; - } - return SessionData.wallpaperPath; - } - - Component.onCompleted: { - WallpaperCyclingService.cyclingActive; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "wallpaper" - tags: ["background", "image", "picture"] - title: I18n.tr("Wallpaper") - settingKey: "wallpaper" - iconName: "wallpaper" - - Row { - width: parent.width - spacing: Theme.spacingL - - StyledRect { - id: wallpaperPreview - width: 160 - height: 90 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = root.currentWallpaper; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: wallpaperMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: root.currentWallpaper.startsWith("#") ? root.currentWallpaper : "transparent" - visible: root.currentWallpaper !== "" && root.currentWallpaper.startsWith("#") - } - - Rectangle { - id: wallpaperMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "image" - size: Theme.iconSizeLarge + 8 - color: Theme.surfaceVariantText - visible: root.currentWallpaper === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: wallpaperMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openMainWallpaperBrowser() - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = root.currentWallpaper.startsWith("#") ? root.currentWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Wallpaper Color", "wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor); - } else { - SessionData.setWallpaperColor(selectedColor); - } - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - visible: root.currentWallpaper !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, ""); - } else { - if (Theme.currentTheme === Theme.dynamic) - Theme.switchTheme("blue"); - SessionData.clearWallpaper(); - } - } - } - } - } - } - - MouseArea { - id: wallpaperMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - Column { - width: parent.width - 160 - Theme.spacingL - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: root.currentWallpaper ? root.currentWallpaper.split('/').pop() : I18n.tr("No wallpaper selected") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.currentWallpaper - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.currentWallpaper !== "" - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight - visible: root.currentWallpaper !== "" - - DankActionButton { - buttonSize: 32 - iconName: "skip_previous" - iconSize: Theme.iconSizeSmall - enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") - opacity: enabled ? 1 : 0.5 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceText - onClicked: { - if (SessionData.perMonitorWallpaper) { - WallpaperCyclingService.cyclePrevForMonitor(selectedMonitorName); - } else { - WallpaperCyclingService.cyclePrevManually(); - } - } - } - - DankActionButton { - buttonSize: 32 - iconName: "skip_next" - iconSize: Theme.iconSizeSmall - enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") - opacity: enabled ? 1 : 0.5 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceText - onClicked: { - if (SessionData.perMonitorWallpaper) { - WallpaperCyclingService.cycleNextForMonitor(selectedMonitorName); - } else { - WallpaperCyclingService.cycleNextManually(); - } - } - } - } - } - } - - Item { - width: parent.width - height: fillModeGroup.height - visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") - - DankButtonGroup { - id: fillModeGroup - property var internalModes: ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"] - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile V", "wallpaper fill mode"), I18n.tr("Tile H", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")] - selectionMode: "single" - buttonHeight: 28 - minButtonWidth: 48 - buttonPadding: Theme.spacingS - checkIconSize: 0 - textSize: Theme.fontSizeSmall - checkEnabled: false - currentIndex: { - var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; - return internalModes.indexOf(mode); - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaperFillMode(selectedMonitorName, internalModes[index]); - } else { - SettingsData.set("wallpaperFillMode", internalModes[index]); - } - } - - Connections { - target: SettingsData - function onWallpaperFillModeChanged() { - if (SessionData.perMonitorWallpaper) - return; - fillModeGroup.currentIndex = fillModeGroup.internalModes.indexOf(SettingsData.wallpaperFillMode); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - if (!SessionData.perMonitorWallpaper) - return; - fillModeGroup.currentIndex = Qt.binding(() => { - var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; - return fillModeGroup.internalModes.indexOf(mode); - }); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: SessionData.wallpaperPath !== "" - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["per-mode", "light", "dark", "theme"] - settingKey: "perModeWallpaper" - visible: SessionData.wallpaperPath !== "" - text: I18n.tr("Per-Mode Wallpapers") - description: I18n.tr("Set different wallpapers for light and dark mode") - checked: SessionData.perModeWallpaper - onToggled: toggled => SessionData.setPerModeWallpaper(toggled) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perModeWallpaper - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - Row { - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingL - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Light Mode") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledRect { - width: parent.width - height: width * 9 / 16 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = SessionData.wallpaperPathLight; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper !== "" && !lightWallpaper.startsWith("#"); - } - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: lightMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper.startsWith("#") ? lightWallpaper : "transparent"; - } - visible: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper !== "" && lightWallpaper.startsWith("#"); - } - } - - Rectangle { - id: lightMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "light_mode" - size: Theme.iconSizeLarge - color: Theme.surfaceVariantText - visible: SessionData.wallpaperPathLight === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: lightModeMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openLightWallpaperBrowser() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - var lightWallpaper = SessionData.wallpaperPathLight; - PopoutService.colorPickerModal.selectedColor = lightWallpaper.startsWith("#") ? lightWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Light Mode Color", "light mode wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SessionData.wallpaperPathLight = selectedColor; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - visible: SessionData.wallpaperPathLight !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SessionData.wallpaperPathLight = ""; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - } - } - } - } - } - - MouseArea { - id: lightModeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - StyledText { - text: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper ? lightWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Dark Mode") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledRect { - width: parent.width - height: width * 9 / 16 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = SessionData.wallpaperPathDark; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper !== "" && !darkWallpaper.startsWith("#"); - } - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: darkMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper.startsWith("#") ? darkWallpaper : "transparent"; - } - visible: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper !== "" && darkWallpaper.startsWith("#"); - } - } - - Rectangle { - id: darkMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "dark_mode" - size: Theme.iconSizeLarge - color: Theme.surfaceVariantText - visible: SessionData.wallpaperPathDark === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: darkModeMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openDarkWallpaperBrowser() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - var darkWallpaper = SessionData.wallpaperPathDark; - PopoutService.colorPickerModal.selectedColor = darkWallpaper.startsWith("#") ? darkWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dark Mode Color", "dark mode wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SessionData.wallpaperPathDark = selectedColor; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - visible: SessionData.wallpaperPathDark !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SessionData.wallpaperPathDark = ""; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - } - } - } - } - } - - MouseArea { - id: darkModeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - StyledText { - text: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper ? darkWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: CompositorService.isNiri - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["blur", "overview", "niri"] - settingKey: "blurWallpaperOnOverview" - visible: CompositorService.isNiri - text: I18n.tr("Blur on Overview") - description: I18n.tr("Blur wallpaper when niri overview is open") - checked: SettingsData.blurWallpaperOnOverview - onToggled: checked => SettingsData.set("blurWallpaperOnOverview", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: SessionData.wallpaperPath !== "" - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["per-monitor", "multi-monitor", "display"] - settingKey: "perMonitorWallpaper" - visible: SessionData.wallpaperPath !== "" - text: I18n.tr("Per-Monitor Wallpapers") - description: I18n.tr("Set different wallpapers for each connected monitor") - checked: SessionData.perMonitorWallpaper - onToggled: toggled => SessionData.setPerMonitorWallpaper(toggled) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perMonitorWallpaper - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["monitor", "display", "screen"] - settingKey: "selectedMonitor" - width: parent.width - Theme.spacingM * 2 - text: I18n.tr("Wallpaper Monitor") - description: I18n.tr("Select monitor to configure wallpaper") - currentValue: { - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === selectedMonitorName) { - return SettingsData.getScreenDisplayName(screens[i]); - } - } - return I18n.tr("No monitors", "no monitors available label"); - } - options: { - var screenNames = []; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - screenNames.push(SettingsData.getScreenDisplayName(screens[i])); - } - return screenNames; - } - onValueChanged: value => { - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === value) { - selectedMonitorName = screens[i].name; - return; - } - } - } - } - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["matugen", "target", "monitor", "theming"] - settingKey: "matugenTargetMonitor" - width: parent.width - Theme.spacingM * 2 - text: I18n.tr("Matugen Target Monitor") - description: I18n.tr("Monitor whose wallpaper drives dynamic theming colors") - currentValue: { - var screens = Quickshell.screens; - if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") { - return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " " + I18n.tr("(Default)", "default monitor label suffix") : I18n.tr("No monitors", "no monitors available label"); - } - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === SettingsData.matugenTargetMonitor) { - return SettingsData.getScreenDisplayName(screens[i]); - } - } - return SettingsData.matugenTargetMonitor; - } - options: { - var screenNames = []; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - var label = SettingsData.getScreenDisplayName(screens[i]); - if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) { - label += " " + I18n.tr("(Default)", "default monitor label suffix"); - } - screenNames.push(label); - } - return screenNames; - } - onValueChanged: value => { - var cleanValue = value.replace(" " + I18n.tr("(Default)", "default monitor label suffix"), ""); - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) { - SettingsData.setMatugenTargetMonitor(screens[i].name); - return; - } - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper - } - - SettingsToggleRow { - id: cyclingToggle - tab: "wallpaper" - tags: ["cycling", "automatic", "rotate", "slideshow"] - settingKey: "wallpaperCyclingEnabled" - visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper - text: I18n.tr("Automatic Cycling") - description: I18n.tr("Automatically cycle through wallpapers in the same folder") - checked: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled - onToggled: toggled => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingEnabled(selectedMonitorName, toggled); - } else { - SessionData.setWallpaperCyclingEnabled(toggled); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - cyclingToggle.checked = Qt.binding(() => { - return SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled; - }); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - Row { - spacing: Theme.spacingL - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Mode:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 200 - height: 45 + Theme.spacingM - - DankTabBar { - id: modeTabBar - width: 200 - height: 45 - model: [ - { - "text": I18n.tr("Interval", "wallpaper cycling mode tab"), - "icon": "schedule" - }, - { - "text": I18n.tr("Time", "wallpaper cycling mode tab"), - "icon": "access_time" - } - ] - currentIndex: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0; - } - return SessionData.wallpaperCyclingMode === "time" ? 1 : 0; - } - onTabClicked: index => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingMode(selectedMonitorName, index === 1 ? "time" : "interval"); - } else { - SessionData.setWallpaperCyclingMode(index === 1 ? "time" : "interval"); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - modeTabBar.currentIndex = Qt.binding(() => { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0; - } - return SessionData.wallpaperCyclingMode === "time" ? 1 : 0; - }); - Qt.callLater(modeTabBar.updateIndicator); - } - } - } - } - } - - SettingsDropdownRow { - id: intervalDropdown - property var intervalOptions: [I18n.tr("5 seconds", "wallpaper interval"), I18n.tr("10 seconds", "wallpaper interval"), I18n.tr("15 seconds", "wallpaper interval"), I18n.tr("20 seconds", "wallpaper interval"), I18n.tr("25 seconds", "wallpaper interval"), I18n.tr("30 seconds", "wallpaper interval"), I18n.tr("35 seconds", "wallpaper interval"), I18n.tr("40 seconds", "wallpaper interval"), I18n.tr("45 seconds", "wallpaper interval"), I18n.tr("50 seconds", "wallpaper interval"), I18n.tr("55 seconds", "wallpaper interval"), I18n.tr("1 minute", "wallpaper interval"), I18n.tr("5 minutes", "wallpaper interval"), I18n.tr("15 minutes", "wallpaper interval"), I18n.tr("30 minutes", "wallpaper interval"), I18n.tr("1 hour", "wallpaper interval"), I18n.tr("1 hour 30 minutes", "wallpaper interval"), I18n.tr("2 hours", "wallpaper interval"), I18n.tr("3 hours", "wallpaper interval"), I18n.tr("4 hours", "wallpaper interval"), I18n.tr("6 hours", "wallpaper interval"), I18n.tr("8 hours", "wallpaper interval"), I18n.tr("12 hours", "wallpaper interval")] - - property var intervalValues: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 300, 900, 1800, 3600, 5400, 7200, 10800, 14400, 21600, 28800, 43200] - tab: "wallpaper" - tags: ["interval", "cycling", "time", "frequency"] - settingKey: "wallpaperCyclingInterval" - width: parent.width - Theme.spacingM * 2 - visible: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "interval"; - } - return SessionData.wallpaperCyclingMode === "interval"; - } - text: I18n.tr("Interval") - description: I18n.tr("How often to change wallpaper") - options: intervalOptions - currentValue: { - var currentSeconds; - if (SessionData.perMonitorWallpaper) { - currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval; - } else { - currentSeconds = SessionData.wallpaperCyclingInterval; - } - const index = intervalValues.indexOf(currentSeconds); - return index >= 0 ? intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval"); - } - onValueChanged: value => { - const index = intervalOptions.indexOf(value); - if (index < 0) - return; - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingInterval(selectedMonitorName, intervalValues[index]); - } else { - SessionData.setWallpaperCyclingInterval(intervalValues[index]); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - Qt.callLater(() => { - var currentSeconds; - if (SessionData.perMonitorWallpaper) { - currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval; - } else { - currentSeconds = SessionData.wallpaperCyclingInterval; - } - const index = intervalDropdown.intervalValues.indexOf(currentSeconds); - intervalDropdown.currentValue = index >= 0 ? intervalDropdown.intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval"); - }); - } - } - } - - Row { - spacing: Theme.spacingM - visible: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time"; - } - return SessionData.wallpaperCyclingMode === "time"; - } - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Daily at:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - id: timeTextField - width: 100 - height: 40 - text: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } - return SessionData.wallpaperCyclingTime; - } - placeholderText: "00:00" - maximumLength: 5 - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - onAccepted: { - var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text); - if (isValid) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingTime(selectedMonitorName, text); - } else { - SessionData.setWallpaperCyclingTime(text); - } - } else { - if (SessionData.perMonitorWallpaper) { - text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - text = SessionData.wallpaperCyclingTime; - } - } - } - onEditingFinished: { - var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text); - if (isValid) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingTime(selectedMonitorName, text); - } else { - SessionData.setWallpaperCyclingTime(text); - } - } else { - if (SessionData.perMonitorWallpaper) { - text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - text = SessionData.wallpaperCyclingTime; - } - } - } - anchors.verticalCenter: parent.verticalCenter - - validator: RegularExpressionValidator { - regularExpression: /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/ - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - Qt.callLater(() => { - if (SessionData.perMonitorWallpaper) { - timeTextField.text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - timeTextField.text = SessionData.wallpaperCyclingTime; - } - }); - } - } - } - - StyledText { - text: I18n.tr("24-hour format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["transition", "effect", "animation", "change"] - settingKey: "wallpaperTransition" - text: I18n.tr("Transition Effect") - description: I18n.tr("Visual effect used when wallpaper changes") - - function getTransitionLabel(t) { - switch (t) { - case "random": - return I18n.tr("Random", "wallpaper transition option"); - case "none": - return I18n.tr("None", "wallpaper transition option"); - case "fade": - return I18n.tr("Fade", "wallpaper transition option"); - case "wipe": - return I18n.tr("Wipe", "wallpaper transition option"); - case "disc": - return I18n.tr("Disc", "wallpaper transition option"); - case "stripes": - return I18n.tr("Stripes", "wallpaper transition option"); - case "iris bloom": - return I18n.tr("Iris Bloom", "wallpaper transition option"); - case "pixelate": - return I18n.tr("Pixelate", "wallpaper transition option"); - case "portal": - return I18n.tr("Portal", "wallpaper transition option"); - default: - return t.charAt(0).toUpperCase() + t.slice(1); - } - } - - currentValue: getTransitionLabel(SessionData.wallpaperTransition) - options: [I18n.tr("Random", "wallpaper transition option")].concat(SessionData.availableWallpaperTransitions.map(t => getTransitionLabel(t))) - onValueChanged: value => { - const transitionMap = {}; - transitionMap[I18n.tr("Random", "wallpaper transition option")] = "random"; - SessionData.availableWallpaperTransitions.forEach(t => { - transitionMap[getTransitionLabel(t)] = t; - }); - SessionData.setWallpaperTransition(transitionMap[value] || value.toLowerCase()); - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SessionData.wallpaperTransition === "random" - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - StyledText { - text: I18n.tr("Include Transitions") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Select which transitions to include in randomization") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - Theme.spacingM * 2 - } - - DankButtonGroup { - id: transitionGroup - width: parent.width - Theme.spacingM * 2 - selectionMode: "multi" - model: SessionData.availableWallpaperTransitions.filter(t => t !== "none") - initialSelection: SessionData.includedTransitions - currentSelection: SessionData.includedTransitions - - onSelectionChanged: (index, selected) => { - const transition = model[index]; - let newIncluded = SessionData.includedTransitions.slice(); - - if (selected && !newIncluded.includes(transition)) { - newIncluded.push(transition); - } else if (!selected && newIncluded.includes(transition)) { - newIncluded = newIncluded.filter(t => t !== transition); - } - - SessionData.includedTransitions = newIncluded; - } - } - } - } - - SettingsCard { - tab: "wallpaper" - tags: ["external", "disable", "swww", "hyprpaper", "swaybg"] - title: I18n.tr("External Wallpaper Management", "wallpaper settings external management") - settingKey: "disableWallpaper" - iconName: "wallpaper" - - SettingsToggleRow { - tab: "wallpaper" - tags: ["disable", "external", "management"] - settingKey: "disableWallpapers" - text: I18n.tr("Disable Built-in Wallpapers", "wallpaper settings disable toggle") - description: I18n.tr("Use an external wallpaper manager like swww, hyprpaper, or swaybg.", "wallpaper settings disable description") - checked: { - var prefs = SettingsData.screenPreferences?.wallpaper; - if (!prefs) - return false; - if (Array.isArray(prefs) && prefs.length === 0) - return true; - return false; - } - onToggled: checked => { - var prefs = SettingsData.screenPreferences || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs.wallpaper = checked ? [] : ["all"]; - SettingsData.set("screenPreferences", newPrefs); - } - } - } - - SettingsCard { - tab: "wallpaper" - tags: ["blur", "layer", "niri", "compositor"] - title: I18n.tr("Blur Wallpaper Layer") - settingKey: "blurWallpaper" - visible: CompositorService.isNiri - - SettingsToggleRow { - tab: "wallpaper" - tags: ["blur", "duplicate", "layer", "compositor"] - settingKey: "blurredWallpaperLayer" - text: I18n.tr("Duplicate Wallpaper with Blur") - description: I18n.tr("Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.") - checked: SettingsData.blurredWallpaperLayer - onToggled: checked => SettingsData.set("blurredWallpaperLayer", checked) - } - } - } - } - - function openMainWallpaperBrowser() { - mainWallpaperBrowserLoader.active = true; - if (mainWallpaperBrowserLoader.item) - mainWallpaperBrowserLoader.item.open(); - } - - function openLightWallpaperBrowser() { - lightWallpaperBrowserLoader.active = true; - if (lightWallpaperBrowserLoader.item) - lightWallpaperBrowserLoader.item.open(); - } - - function openDarkWallpaperBrowser() { - darkWallpaperBrowserLoader.active = true; - if (darkWallpaperBrowserLoader.item) - darkWallpaperBrowserLoader.item.open(); - } - - LazyLoader { - id: mainWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title") - browserIcon: "wallpaper" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, path); - } else { - SessionData.setWallpaper(path); - } - close(); - } - } - } - - LazyLoader { - id: lightWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title") - browserIcon: "light_mode" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - SessionData.wallpaperPathLight = path; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - close(); - } - } - } - - LazyLoader { - id: darkWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title") - browserIcon: "dark_mode" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - SessionData.wallpaperPathDark = path; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - close(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml deleted file mode 100644 index 817e980..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml +++ /dev/null @@ -1,382 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allWidgets: [] - property string targetSection: "" - property string searchQuery: "" - property var filteredWidgets: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property var parentModal: null - - signal widgetSelected(string widgetId, string targetSection) - - function updateFilteredWidgets() { - if (!searchQuery || searchQuery.length === 0) { - filteredWidgets = allWidgets.slice(); - return; - } - - var filtered = []; - var query = searchQuery.toLowerCase(); - - for (var i = 0; i < allWidgets.length; i++) { - var widget = allWidgets[i]; - var text = widget.text ? widget.text.toLowerCase() : ""; - var description = widget.description ? widget.description.toLowerCase() : ""; - var id = widget.id ? widget.id.toLowerCase() : ""; - - if (text.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) - filtered.push(widget); - } - - filteredWidgets = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - onAllWidgetsChanged: { - updateFilteredWidgets(); - } - - function selectNext() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1); - } - - function selectPrevious() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function selectWidget() { - if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length) - return; - var widget = filteredWidgets[selectedIndex]; - root.widgetSelected(widget.id, root.targetSection); - root.hide(); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "widgetSelectionPopup" - title: I18n.tr("Add Widget") - minimumSize: Qt.size(400, 350) - implicitWidth: 500 - implicitHeight: 550 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - return; - } - allWidgets = []; - targetSection = ""; - searchQuery = ""; - filteredWidgets = []; - selectedIndex = -1; - keyboardNavigationActive = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - FocusScope { - id: widgetKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.keyboardNavigationActive) { - root.selectWidget(); - } else if (root.filteredWidgets.length > 0) { - var firstWidget = root.filteredWidgets[0]; - root.widgetSelected(firstWidget.id, root.targetSection); - root.hide(); - } - event.accepted = true; - return; - } - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_P: - case Qt.Key_K: - root.selectPrevious(); - event.accepted = true; - return; - } - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - id: titleBar - width: parent.width - height: 48 - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Rectangle { - anchors.fill: parent - color: Theme.surfaceContainer - opacity: 0.5 - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Add Widget to %1 Section").arg(root.targetSection) - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - } - - Item { - width: parent.width - height: parent.height - titleBar.height - - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Select a widget to add. You can add multiple instances of the same widget if needed.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - } - - DankTextField { - id: searchField - width: parent.width - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search widgets...") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [widgetKeyHandler] - onTextEdited: { - root.searchQuery = text; - updateFilteredWidgets(); - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.hide(); - event.accepted = true; - return; - } - if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) - event.accepted = false; - } - } - - DankListView { - id: widgetList - - width: parent.width - height: parent.height - y - spacing: Theme.spacingS - model: root.filteredWidgets - clip: true - - delegate: Rectangle { - width: widgetList.width - height: 60 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - Theme.iconSize - Theme.spacingM * 3 - - StyledText { - text: modelData.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.widgetSelected(modelData.id, root.targetSection); - root.hide(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml deleted file mode 100644 index bec5ff1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml +++ /dev/null @@ -1,180 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property var deviceNode - property string deviceType: "output" - - property bool showHideButton: false - property bool isHidden: false - - signal editRequested(var deviceNode) - signal resetRequested(var deviceNode) - signal hideRequested(var deviceNode) - - width: parent?.width ?? 0 - height: deviceRowContent.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.surfaceHover : "transparent" - - readonly property bool hasCustomAlias: AudioService.hasDeviceAlias(deviceNode?.name ?? "") - readonly property string displayedName: AudioService.displayName(deviceNode) - - Row { - id: deviceRowContent - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.deviceType === "input" ? "mic" : "speaker" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM * 3 - buttonsRow.width - spacing: 2 - - StyledText { - text: root.displayedName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - - Column { - width: parent.width - spacing: 2 - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: root.deviceNode?.name ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - (customAliasLabel.visible ? customAliasLabel.width + Theme.spacingS : 0) - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - id: customAliasLabel - visible: root.hasCustomAlias - height: customAliasText.implicitHeight + 4 - width: customAliasText.implicitWidth + Theme.spacingS * 2 - radius: 3 - color: Theme.withAlpha(Theme.primary, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: customAliasText - text: I18n.tr("Custom") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.primary - font.weight: Font.Medium - anchors.centerIn: parent - } - } - } - - StyledText { - visible: root.hasCustomAlias - text: I18n.tr("Original: %1").arg(AudioService.originalName(root.deviceNode)) - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - opacity: 0.6 - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - id: buttonsRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - id: resetButton - visible: root.hasCustomAlias - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - tooltipText: I18n.tr("Reset to default name") - anchors.verticalCenter: parent.verticalCenter - onClicked: { - root.resetRequested(root.deviceNode); - } - } - - DankActionButton { - id: hideButton - visible: root.showHideButton - buttonSize: 36 - iconName: root.isHidden ? "visibility" : "visibility_off" - iconSize: 20 - backgroundColor: Theme.surfaceContainerHigh - iconColor: root.isHidden ? Theme.primary : Theme.surfaceVariantText - tooltipText: root.isHidden ? I18n.tr("Show device") : I18n.tr("Hide device") - anchors.verticalCenter: parent.verticalCenter - onClicked: { - root.hideRequested(root.deviceNode); - } - } - - DankActionButton { - id: editButton - buttonSize: 36 - iconName: "edit" - iconSize: 20 - backgroundColor: Theme.buttonBg - iconColor: Theme.buttonText - tooltipText: I18n.tr("Set custom name") - anchors.verticalCenter: parent.verticalCenter - visible: !root.isHidden - onClicked: { - root.editRequested(root.deviceNode); - } - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - hoverEnabled: true - propagateComposedEvents: true - z: -1 - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml deleted file mode 100644 index 5e49936..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml +++ /dev/null @@ -1,117 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string text: "" - property string description: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - property alias model: buttonGroup.model - property alias currentIndex: buttonGroup.currentIndex - property alias selectionMode: buttonGroup.selectionMode - property alias buttonHeight: buttonGroup.buttonHeight - property alias minButtonWidth: buttonGroup.minButtonWidth - property alias buttonPadding: buttonGroup.buttonPadding - property alias checkIconSize: buttonGroup.checkIconSize - property alias textSize: buttonGroup.textSize - property alias spacing: buttonGroup.spacing - property alias checkEnabled: buttonGroup.checkEnabled - - signal selectionChanged(int index, bool selected) - - width: parent?.width ?? 0 - height: 60 - - Row { - id: contentRow - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Column { - width: parent.width - buttonGroup.width - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - visible: root.text !== "" - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: root.description !== "" - horizontalAlignment: Text.AlignLeft - } - } - - DankButtonGroup { - id: buttonGroup - anchors.verticalCenter: parent.verticalCenter - selectionMode: "single" - onSelectionChanged: (index, selected) => root.selectionChanged(index, selected) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml deleted file mode 100644 index 65642a0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml +++ /dev/null @@ -1,199 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string title: "" - property string iconName: "" - property bool collapsible: false - property bool expanded: true - property real headerLeftPadding: 0 - - default property alias content: contentColumn.children - property alias headerActions: headerActionsRow.children - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - height: { - var hasHeader = root.title !== "" || root.iconName !== ""; - if (collapsed) - return headerRow.height + Theme.spacingL * 2; - var h = Theme.spacingL * 2 + contentColumn.height; - if (hasHeader) - h += headerRow.height + Theme.spacingM; - return h; - } - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - readonly property bool collapsed: collapsible && !expanded - readonly property bool hasHeader: root.title !== "" || root.iconName !== "" - property bool userToggledCollapse: false - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) { - return p; - } - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (settingKey) { - let flickable = findParentFlickable(); - if (flickable) { - SettingsSearchService.registerCard(settingKey, root, flickable); - } - } - } - - Component.onDestruction: { - if (settingKey) { - SettingsSearchService.unregisterCard(settingKey); - } - } - - Behavior on height { - enabled: root.userToggledCollapse - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - onRunningChanged: { - if (!running) - root.userToggledCollapse = false; - } - } - } - - Rectangle { - id: highlightBorder - anchors.fill: parent - anchors.margins: -2 - radius: root.radius + 2 - color: "transparent" - border.width: 2 - border.color: Theme.primary - opacity: root.isHighlighted ? 1 : 0 - visible: opacity > 0 - z: 100 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Column { - id: mainColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: root.hasHeader ? Theme.spacingM : 0 - clip: true - - Item { - id: headerRow - width: parent.width - height: root.hasHeader ? Math.max(headerIcon.height, headerText.height, headerActionsRow.height) : 0 - visible: root.hasHeader - - Row { - anchors.left: parent.left - anchors.leftMargin: root.headerLeftPadding - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - StyledText { - id: headerText - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: root.title !== "" - width: implicitWidth - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: headerActionsRow - anchors.right: root.collapsible ? caretIcon.left : parent.right - anchors.rightMargin: root.collapsible ? Theme.spacingS : 0 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - } - - DankIcon { - id: caretIcon - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - name: root.expanded ? "expand_less" : "expand_more" - size: Theme.iconSize - 2 - color: Theme.surfaceVariantText - visible: root.collapsible - } - - MouseArea { - anchors.left: parent.left - anchors.right: headerActionsRow.left - anchors.top: parent.top - anchors.bottom: parent.bottom - enabled: root.collapsible - cursorShape: root.collapsible ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - root.userToggledCollapse = true; - root.expanded = !root.expanded; - } - } - - MouseArea { - visible: root.collapsible - anchors.left: caretIcon.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.leftMargin: -Theme.spacingS - enabled: root.collapsible - cursorShape: root.collapsible ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - root.userToggledCollapse = true; - root.expanded = !root.expanded; - } - } - } - - Column { - id: contentColumn - width: parent.width - spacing: Theme.spacingM - visible: !root.collapsed - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml deleted file mode 100644 index 68011fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml +++ /dev/null @@ -1,119 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string colorMode: "primary" - property color customColor: "#ffffff" - property string pickerTitle: I18n.tr("Choose Color") - - signal colorModeSelected(string mode) - signal customColorSelected(color selectedColor) - - width: parent?.width ?? 0 - height: colorColumn.height + Theme.spacingM * 2 - - Column { - id: colorColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: [ - { - id: "primary", - label: I18n.tr("Primary"), - color: Theme.primary - }, - { - id: "secondary", - label: I18n.tr("Secondary"), - color: Theme.secondary - }, - { - id: "custom", - label: I18n.tr("Custom"), - color: root.customColor - } - ] - - Rectangle { - required property var modelData - required property int index - - width: (parent.width - Theme.spacingS * 2) / 3 - height: 60 - radius: Theme.cornerRadius - color: root.colorMode === modelData.id ? Theme.primarySelected : Theme.surfaceHover - border.color: root.colorMode === modelData.id ? Theme.primary : "transparent" - border.width: 2 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: modelData.color - border.color: Theme.outline - border.width: 1 - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - visible: modelData.id === "custom" - anchors.centerIn: parent - name: "colorize" - size: 14 - color: Theme.background - } - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData.id !== "custom") { - root.colorModeSelected(modelData.id); - return; - } - PopoutService.colorPickerModal.selectedColor = root.customColor; - PopoutService.colorPickerModal.pickerTitle = root.pickerTitle; - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - root.customColorSelected(selectedColor); - root.colorModeSelected("custom"); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml deleted file mode 100644 index ba453fd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml +++ /dev/null @@ -1,103 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - property var displayPreferences: [] - - signal preferencesChanged(var preferences) - - property bool localAllDisplays: true - - onDisplayPreferencesChanged: { - if (!Array.isArray(displayPreferences) || displayPreferences.length === 0) { - localAllDisplays = true; - return; - } - localAllDisplays = displayPreferences.includes("all"); - } - - width: parent?.width ?? 0 - height: displayColumn.height + Theme.spacingM * 2 - - Column { - id: displayColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Displays") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankToggle { - width: parent.width - text: I18n.tr("All displays") - checked: root.localAllDisplays - onToggled: isChecked => { - root.localAllDisplays = isChecked; - if (isChecked) { - root.preferencesChanged(["all"]); - return; - } - var screens = []; - for (var i = 0; i < Quickshell.screens.length; i++) { - var s = Quickshell.screens[i]; - screens.push({ - name: s.name, - model: s.model || "" - }); - } - root.preferencesChanged(screens); - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !root.localAllDisplays - - Repeater { - model: Quickshell.screens - - DankToggle { - required property var modelData - - property bool localChecked: { - const prefs = root.displayPreferences; - if (!Array.isArray(prefs) || prefs.includes("all")) - return true; - return prefs.some(p => p.name === modelData.name); - } - - width: parent.width - text: SettingsData.getScreenDisplayName(modelData) - description: modelData.width + "×" + modelData.height - checked: localChecked - onToggled: isChecked => { - localChecked = isChecked; - var prefs = JSON.parse(JSON.stringify(root.displayPreferences)); - if (!Array.isArray(prefs) || prefs.includes("all")) - prefs = []; - prefs = prefs.filter(p => p.name !== modelData.name); - if (isChecked) { - prefs.push({ - name: modelData.name, - model: modelData.model || "" - }); - } - root.preferencesChanged(prefs); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml deleted file mode 100644 index 86d9fe7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml +++ /dev/null @@ -1,11 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common - -Rectangle { - width: parent?.width ?? 0 - height: 1 - color: Theme.outline - opacity: 0.15 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml deleted file mode 100644 index c5ec3a6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml +++ /dev/null @@ -1,60 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankDropdown { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - addHorizontalPadding: true - usePopupTransparency: false - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml deleted file mode 100644 index 5bdd91a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml +++ /dev/null @@ -1,108 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - - property string title: "" - property string description: "" - property string iconName: "" - property alias value: slider.value - property alias minimum: slider.minimum - property alias maximum: slider.maximum - property alias unit: slider.unit - property int defaultValue: -1 - - signal sliderValueChanged(int newValue) - signal sliderDragFinished(int finalValue) - width: parent?.width ?? 0 - height: Theme.spacingL * 2 + contentColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - headerIcon.width - (root.defaultValue >= 0 ? resetButton.width + Theme.spacingS : 0) - Theme.spacingM - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.title !== "" - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.description !== "" - } - } - - DankActionButton { - id: resetButton - anchors.verticalCenter: parent.verticalCenter - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: root.defaultValue >= 0 && slider.value !== root.defaultValue - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - onClicked: { - slider.value = root.defaultValue; - root.sliderValueChanged(root.defaultValue); - root.sliderDragFinished(root.defaultValue); - } - } - } - - DankSlider { - id: slider - width: parent.width - height: 32 - showValue: true - wheelEnabled: false - thumbOutlineColor: Theme.surfaceContainerHigh - onSliderValueChanged: newValue => root.sliderValueChanged(newValue) - onSliderDragFinished: finalValue => root.sliderDragFinished(finalValue) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml deleted file mode 100644 index b1ada84..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml +++ /dev/null @@ -1,148 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string text: "" - property string description: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - property alias value: slider.value - property alias minimum: slider.minimum - property alias maximum: slider.maximum - property alias step: slider.step - property alias unit: slider.unit - property alias wheelEnabled: slider.wheelEnabled - property alias thumbOutlineColor: slider.thumbOutlineColor - property int defaultValue: -1 - - signal sliderValueChanged(int newValue) - signal sliderDragFinished(int finalValue) - width: parent?.width ?? 0 - height: headerRow.height + Theme.spacingXS + slider.height - - Column { - id: contentColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Row { - id: headerRow - width: parent.width - height: labelColumn.height - spacing: Theme.spacingS - - Column { - id: labelColumn - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - resetButtonContainer.width - Theme.spacingS - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - visible: root.text !== "" - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: root.description !== "" - horizontalAlignment: Text.AlignLeft - } - } - - Item { - id: resetButtonContainer - width: root.defaultValue >= 0 ? 36 : 0 - height: 36 - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - id: resetButton - anchors.centerIn: parent - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: root.defaultValue >= 0 && slider.value !== root.defaultValue - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - onClicked: { - slider.value = root.defaultValue; - root.sliderValueChanged(root.defaultValue); - root.sliderDragFinished(root.defaultValue); - } - } - } - } - - DankSlider { - id: slider - width: parent.width - height: 32 - showValue: true - wheelEnabled: false - thumbOutlineColor: Theme.surfaceContainerHigh - onSliderValueChanged: newValue => root.sliderValueChanged(newValue) - onSliderDragFinished: finalValue => root.sliderDragFinished(finalValue) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml deleted file mode 100644 index c36fb7c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml +++ /dev/null @@ -1,120 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - - property string title: "" - property string description: "" - property string iconName: "" - property bool checked: false - property bool enabled: true - - default property alias content: expandedContent.children - readonly property bool hasContent: expandedContent.children.length > 0 - - signal toggled(bool checked) - - width: parent?.width ?? 0 - height: Theme.spacingL * 2 + mainColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingM - - Item { - width: parent.width - height: headerColumn.height - - Column { - id: headerColumn - anchors.left: parent.left - anchors.right: toggleSwitch.left - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingM - width: parent.width - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - StyledText { - id: headerText - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: root.title !== "" - width: parent.width - (headerIcon.visible ? headerIcon.width + parent.spacing : 0) - horizontalAlignment: Text.AlignLeft - } - } - - StyledText { - id: descriptionText - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.description !== "" - } - } - - DankToggle { - id: toggleSwitch - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - hideText: true - checked: root.checked - enabled: root.enabled - onToggled: checked => root.toggled(checked) - } - - StateLayer { - anchors.fill: parent - disabled: !root.enabled - stateColor: Theme.primary - cornerRadius: root.radius - onClicked: { - if (!root.enabled) - return; - root.toggled(!root.checked); - } - } - } - - Column { - id: expandedContent - width: parent.width - spacing: Theme.spacingM - visible: root.checked && root.hasContent - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml deleted file mode 100644 index 684b639..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml +++ /dev/null @@ -1,58 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankToggle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml deleted file mode 100644 index 1ecd451..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml +++ /dev/null @@ -1,390 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var variant: ({}) - property bool expanded: false - - signal expandToggled(bool isExpanded) - signal deleteRequested - signal nameChanged(string newName) - signal configChanged(string key, var value) - - readonly property var cfg: variant.config || {} - - function updateConfig(key, value) { - var newConfig = JSON.parse(JSON.stringify(cfg)); - newConfig[key] = value; - root.configChanged("config", newConfig); - } - - width: parent?.width ?? 0 - height: variantColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - clip: true - - Column { - id: variantColumn - width: parent.width - spacing: 0 - - Item { - width: parent.width - height: headerContent.height + Theme.spacingM * 2 - - Row { - id: headerContent - x: Theme.spacingM - y: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingM - - DankIcon { - name: root.expanded ? "expand_less" : "expand_more" - size: Theme.iconSize - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - deleteBtn.width - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: root.variant.name || "Unnamed" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - } - - StyledText { - property var features: { - var f = []; - if (root.cfg.showCpu) - f.push("CPU"); - if (root.cfg.showMemory) - f.push("RAM"); - if (root.cfg.showNetwork) - f.push("Net"); - if (root.cfg.showDisk) - f.push("Disk"); - if (root.cfg.showGpuTemp) - f.push("GPU"); - return f; - } - text: features.length > 0 ? features.join(", ") : I18n.tr("No features enabled") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - } - } - - Rectangle { - id: deleteBtn - width: 32 - height: 32 - radius: 16 - color: deleteMouse.containsMouse ? Theme.error : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 16 - color: deleteMouse.containsMouse ? Theme.background : Theme.surfaceVariantText - } - - MouseArea { - id: deleteMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.deleteRequested() - } - } - } - - MouseArea { - anchors.fill: parent - anchors.rightMargin: deleteBtn.width + Theme.spacingM - cursorShape: Qt.PointingHandCursor - onClicked: root.expandToggled(!root.expanded) - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.expanded - - SettingsDivider {} - - Item { - width: parent.width - height: nameRow.height + Theme.spacingM * 2 - - Row { - id: nameRow - x: Theme.spacingM - y: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingM - text: root.variant.name || "" - onEditingFinished: { - if (text !== root.variant.name) - root.nameChanged(text); - } - } - } - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Header") - checked: root.cfg.showHeader ?? true - onToggled: checked => root.updateConfig("showHeader", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU") - checked: root.cfg.showCpu ?? true - onToggled: checked => root.updateConfig("showCpu", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU Graph") - visible: root.cfg.showCpu - checked: root.cfg.showCpuGraph ?? true - onToggled: checked => root.updateConfig("showCpuGraph", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU Temp") - visible: root.cfg.showCpu - checked: root.cfg.showCpuTemp ?? true - onToggled: checked => root.updateConfig("showCpuTemp", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory") - checked: root.cfg.showMemory ?? true - onToggled: checked => root.updateConfig("showMemory", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory Graph") - visible: root.cfg.showMemory - checked: root.cfg.showMemoryGraph ?? true - onToggled: checked => root.updateConfig("showMemoryGraph", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory in GB") - visible: root.cfg.showMemory - checked: root.cfg.showInGb ?? false - onToggled: checked => root.updateConfig("showInGb", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Network") - checked: root.cfg.showNetwork ?? true - onToggled: checked => root.updateConfig("showNetwork", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Network Graph") - visible: root.cfg.showNetwork - checked: root.cfg.showNetworkGraph ?? true - onToggled: checked => root.updateConfig("showNetworkGraph", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Disk") - checked: root.cfg.showDisk ?? true - onToggled: checked => root.updateConfig("showDisk", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show GPU Temperature") - checked: root.cfg.showGpuTemp ?? false - onToggled: checked => root.updateConfig("showGpuTemp", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: root.cfg.showGpuTemp && DgopService.availableGpus.length > 0 - - Item { - width: 1 - height: Theme.spacingS - } - - Repeater { - model: DgopService.availableGpus - - Rectangle { - required property var modelData - - width: (parent?.width ?? 0) - Theme.spacingM * 2 - x: Theme.spacingM - height: 40 - radius: Theme.cornerRadius - color: root.cfg.gpuPciId === modelData.pciId ? Theme.primarySelected : Theme.surfaceContainer - border.color: root.cfg.gpuPciId === modelData.pciId ? Theme.primary : "transparent" - border.width: 2 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "videocam" - size: Theme.iconSizeSmall - color: root.cfg.gpuPciId === modelData.pciId ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.displayName || "Unknown GPU" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - Theme.iconSizeSmall - Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.updateConfig("gpuPciId", modelData.pciId) - } - } - } - - Item { - width: 1 - height: Theme.spacingS - } - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Top Processes") - checked: root.cfg.showTopProcesses ?? false - onToggled: checked => root.updateConfig("showTopProcesses", checked) - } - - SettingsDivider {} - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - topPadding: Theme.spacingM - bottomPadding: Theme.spacingM - spacing: Theme.spacingS - - Row { - width: parent.width - - StyledText { - id: transparencyLabel - text: I18n.tr("Transparency") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - transparencyLabel.width - transparencyValue.width - height: 1 - } - - StyledText { - id: transparencyValue - text: transparencySlider.value + "%" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - DankSlider { - id: transparencySlider - width: parent.width - minimum: 0 - maximum: 100 - value: Math.round((root.cfg.transparency ?? 0.8) * 100) - showValue: false - wheelEnabled: false - onSliderDragFinished: finalValue => root.updateConfig("transparency", finalValue / 100) - } - } - - Item { - width: 1 - height: Theme.spacingM - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml deleted file mode 100644 index 86bc391..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml +++ /dev/null @@ -1,1145 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: widgetsTab - - property var parentModal: null - property string selectedBarId: "default" - - property var selectedBarConfig: { - selectedBarId; - SettingsData.barConfigs; - const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0]; - } - - property bool selectedBarIsVertical: { - selectedBarId; - const pos = selectedBarConfig?.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - } - - property bool hasMultipleBars: SettingsData.barConfigs.length > 1 - - DankTooltipV2 { - id: sharedTooltip - } - - property var baseWidgetDefinitions: { - var coreWidgets = [ - { - "id": "layout", - "text": I18n.tr("Layout"), - "description": I18n.tr("Display and switch DWL layouts"), - "icon": "view_quilt", - "enabled": CompositorService.isDwl && DwlService.dwlAvailable, - "warning": !CompositorService.isDwl ? I18n.tr("Requires DWL compositor") : (!DwlService.dwlAvailable ? I18n.tr("DWL service not available") : undefined) - }, - { - "id": "launcherButton", - "text": I18n.tr("App Launcher"), - "description": I18n.tr("Quick access to application launcher"), - "icon": "apps", - "enabled": true - }, - { - "id": "workspaceSwitcher", - "text": I18n.tr("Workspace Switcher"), - "description": I18n.tr("Shows current workspace and allows switching"), - "icon": "view_module", - "enabled": true - }, - { - "id": "focusedWindow", - "text": I18n.tr("Focused Window"), - "description": I18n.tr("Display currently focused application title"), - "icon": "window", - "enabled": true - }, - { - "id": "runningApps", - "text": I18n.tr("Running Apps"), - "description": I18n.tr("Shows all running applications with focus indication"), - "icon": "apps", - "enabled": true - }, - { - "id": "appsDock", - "text": I18n.tr("Apps Dock"), - "description": I18n.tr("Pinned and running apps with drag-and-drop"), - "icon": "dock_to_bottom", - "enabled": true - }, - { - "id": "clock", - "text": I18n.tr("Clock"), - "description": I18n.tr("Current time and date display"), - "icon": "schedule", - "enabled": true - }, - { - "id": "weather", - "text": I18n.tr("Weather Widget"), - "description": I18n.tr("Current weather conditions and temperature"), - "icon": "wb_sunny", - "enabled": true - }, - { - "id": "music", - "text": I18n.tr("Media Controls"), - "description": I18n.tr("Control currently playing media"), - "icon": "music_note", - "enabled": true - }, - { - "id": "clipboard", - "text": I18n.tr("Clipboard Manager"), - "description": I18n.tr("Access clipboard history"), - "icon": "content_paste", - "enabled": true - }, - { - "id": "cpuUsage", - "text": I18n.tr("CPU Usage"), - "description": I18n.tr("CPU usage indicator"), - "icon": "memory", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "memUsage", - "text": I18n.tr("Memory Usage"), - "description": I18n.tr("Memory usage indicator"), - "icon": "developer_board", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "diskUsage", - "text": I18n.tr("Disk Usage"), - "description": I18n.tr("Percentage"), - "icon": "storage", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "cpuTemp", - "text": I18n.tr("CPU Temperature"), - "description": I18n.tr("CPU temperature display"), - "icon": "device_thermostat", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "gpuTemp", - "text": I18n.tr("GPU Temperature"), - "description": I18n.tr("GPU temperature display"), - "icon": "auto_awesome_mosaic", - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : I18n.tr("This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics."), - "enabled": DgopService.dgopAvailable - }, - { - "id": "systemTray", - "text": I18n.tr("System Tray"), - "description": I18n.tr("System notification area icons"), - "icon": "notifications", - "enabled": true - }, - { - "id": "privacyIndicator", - "text": I18n.tr("Privacy Indicator"), - "description": I18n.tr("Shows when microphone, camera, or screen sharing is active"), - "icon": "privacy_tip", - "enabled": true - }, - { - "id": "controlCenterButton", - "text": I18n.tr("Control Center"), - "description": I18n.tr("Access to system controls and settings"), - "icon": "settings", - "enabled": true - }, - { - "id": "notificationButton", - "text": I18n.tr("Notification Center"), - "description": I18n.tr("Access to notifications and do not disturb"), - "icon": "notifications", - "enabled": true - }, - { - "id": "battery", - "text": I18n.tr("Battery"), - "description": I18n.tr("Battery level and power management"), - "icon": "battery_std", - "enabled": true - }, - { - "id": "vpn", - "text": I18n.tr("VPN"), - "description": I18n.tr("VPN status and quick connect"), - "icon": "vpn_lock", - "enabled": true - }, - { - "id": "idleInhibitor", - "text": I18n.tr("Idle Inhibitor"), - "description": I18n.tr("Prevent screen timeout"), - "icon": "motion_sensor_active", - "enabled": true - }, - { - "id": "capsLockIndicator", - "text": I18n.tr("Caps Lock Indicator"), - "description": I18n.tr("Shows when caps lock is active"), - "icon": "shift_lock", - "enabled": true - }, - { - "id": "spacer", - "text": I18n.tr("Spacer"), - "description": I18n.tr("Customizable empty space"), - "icon": "more_horiz", - "enabled": true - }, - { - "id": "separator", - "text": I18n.tr("Separator"), - "description": I18n.tr("Visual divider between widgets"), - "icon": "remove", - "enabled": true - }, - { - "id": "network_speed_monitor", - "text": I18n.tr("Network Speed Monitor"), - "description": I18n.tr("Network download and upload speed display"), - "icon": "network_check", - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined, - "enabled": DgopService.dgopAvailable - }, - { - "id": "keyboard_layout_name", - "text": I18n.tr("Keyboard Layout Name"), - "description": I18n.tr("Displays the active keyboard layout and allows switching"), - "icon": "keyboard" - }, - { - "id": "notepadButton", - "text": I18n.tr("Notepad"), - "description": I18n.tr("Quick access to notepad"), - "icon": "assignment", - "enabled": true - }, - { - "id": "colorPicker", - "text": I18n.tr("Color Picker"), - "description": I18n.tr("Quick access to color picker"), - "icon": "palette", - "enabled": true - }, - { - "id": "systemUpdate", - "text": I18n.tr("System Update"), - "description": I18n.tr("Check for system updates"), - "icon": "update", - "enabled": SystemUpdateService.distributionSupported - }, - { - "id": "powerMenuButton", - "text": I18n.tr("Power"), - "description": I18n.tr("Display the power system menu"), - "icon": "power_settings_new", - "enabled": true - }, - ]; - - var allPluginVariants = PluginService.getAllPluginVariants(); - for (var i = 0; i < allPluginVariants.length; i++) { - var variant = allPluginVariants[i]; - coreWidgets.push({ - "id": variant.fullId, - "text": variant.name, - "description": variant.description, - "icon": variant.icon, - "enabled": variant.loaded, - "warning": !variant.loaded ? I18n.tr("Plugin is disabled - enable in Plugins settings to use") : undefined - }); - } - - return coreWidgets; - } - - property var defaultLeftWidgets: [ - { - "id": "launcherButton", - "enabled": true - }, - { - "id": "workspaceSwitcher", - "enabled": true - }, - { - "id": "focusedWindow", - "enabled": true - } - ] - property var defaultCenterWidgets: [ - { - "id": "music", - "enabled": true - }, - { - "id": "clock", - "enabled": true - }, - { - "id": "weather", - "enabled": true - } - ] - property var defaultRightWidgets: [ - { - "id": "systemTray", - "enabled": true - }, - { - "id": "clipboard", - "enabled": true - }, - { - "id": "notificationButton", - "enabled": true - }, - { - "id": "battery", - "enabled": true - }, - { - "id": "controlCenterButton", - "enabled": true - } - ] - - function getWidgetsForSection(sectionId) { - switch (sectionId) { - case "left": - return selectedBarConfig?.leftWidgets || []; - case "center": - return selectedBarConfig?.centerWidgets || []; - case "right": - return selectedBarConfig?.rightWidgets || []; - default: - return []; - } - } - - function setWidgetsForSection(sectionId, widgets) { - switch (sectionId) { - case "left": - SettingsData.updateBarConfig(selectedBarId, { - leftWidgets: widgets - }); - break; - case "center": - SettingsData.updateBarConfig(selectedBarId, { - centerWidgets: widgets - }); - break; - case "right": - SettingsData.updateBarConfig(selectedBarId, { - rightWidgets: widgets - }); - break; - } - } - - function getWidgetsForPopup() { - return baseWidgetDefinitions.filter(widget => { - if (widget.warning && widget.warning.includes("Plugin is disabled")) - return false; - if (widget.enabled === false) - return false; - return true; - }); - } - - function addWidgetToSection(widgetId, targetSection) { - var widgetObj = { - "id": widgetId, - "enabled": true - }; - if (widgetId === "spacer") - widgetObj.size = 20; - if (widgetId === "gpuTemp") { - widgetObj.selectedGpuIndex = 0; - widgetObj.pciId = ""; - } - if (widgetId === "controlCenterButton") { - widgetObj.showNetworkIcon = SettingsData.controlCenterShowNetworkIcon; - widgetObj.showBluetoothIcon = SettingsData.controlCenterShowBluetoothIcon; - widgetObj.showAudioIcon = SettingsData.controlCenterShowAudioIcon; - widgetObj.showAudioPercent = SettingsData.controlCenterShowAudioPercent; - widgetObj.showVpnIcon = SettingsData.controlCenterShowVpnIcon; - widgetObj.showBrightnessIcon = SettingsData.controlCenterShowBrightnessIcon; - widgetObj.showBrightnessPercent = SettingsData.controlCenterShowBrightnessPercent; - widgetObj.showMicIcon = SettingsData.controlCenterShowMicIcon; - widgetObj.showMicPercent = SettingsData.controlCenterShowMicPercent; - widgetObj.showBatteryIcon = SettingsData.controlCenterShowBatteryIcon; - widgetObj.showPrinterIcon = SettingsData.controlCenterShowPrinterIcon; - widgetObj.showScreenSharingIcon = SettingsData.controlCenterShowScreenSharingIcon; - widgetObj.controlCenterGroupOrder = ["network", "vpn", "bluetooth", "audio", "microphone", "brightness", "battery", "printer", "screenSharing"]; - } - if (widgetId === "runningApps") { - widgetObj.runningAppsCompactMode = SettingsData.runningAppsCompactMode; - widgetObj.runningAppsGroupByApp = SettingsData.runningAppsGroupByApp; - widgetObj.runningAppsCurrentWorkspace = SettingsData.runningAppsCurrentWorkspace; - widgetObj.runningAppsCurrentMonitor = false; - } - if (widgetId === "diskUsage") { - widgetObj.mountPath = "/"; - widgetObj.diskUsageMode = 0; - } - if (widgetId === "cpuUsage" || widgetId === "memUsage" || widgetId === "cpuTemp" || widgetId === "gpuTemp") - widgetObj.minimumWidth = true; - if (widgetId === "memUsage") - widgetObj.showInGb = false; - - var widgets = getWidgetsForSection(targetSection).slice(); - widgets.push(widgetObj); - setWidgetsForSection(targetSection, widgets); - } - - function removeWidgetFromSection(sectionId, widgetIndex) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex >= 0 && widgetIndex < widgets.length) - widgets.splice(widgetIndex, 1); - setWidgetsForSection(sectionId, widgets); - } - - function cloneWidgetData(widget) { - if (typeof widget === "string") - return { - "id": widget, - "enabled": true - }; - var result = { - "id": widget.id, - "enabled": widget.enabled - }; - var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"]; - for (var i = 0; i < keys.length; i++) { - if (widget[keys[i]] !== undefined) - result[keys[i]] = widget[keys[i]]; - } - return result; - } - - function handleItemEnabledChanged(sectionId, itemId, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - var widgetId = typeof widget === "string" ? widget : widget.id; - if (widgetId !== itemId) - continue; - var newWidget = cloneWidgetData(widget); - newWidget.enabled = enabled; - widgets[i] = newWidget; - break; - } - setWidgetsForSection(sectionId, widgets); - } - - function handleItemOrderChanged(sectionId, newOrder) { - setWidgetsForSection(sectionId, newOrder); - } - - function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var widget = widgets[widgetIndex]; - var widgetId = typeof widget === "string" ? widget : widget.id; - if (widgetId !== "spacer") - return; - var newWidget = cloneWidgetData(widget); - newWidget.size = newSize; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.selectedGpuIndex = selectedGpuIndex; - newWidget.pciId = pciId; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.mountPath = mountPath; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget[settingName] = value; - - if (!value) { - switch (settingName) { - case "showAudioIcon": - newWidget.showAudioPercent = false; - break; - case "showMicIcon": - newWidget.showMicPercent = false; - break; - case "showBrightnessIcon": - newWidget.showBrightnessPercent = false; - break; - } - } - - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleControlCenterGroupOrderChanged(sectionId, widgetIndex, groupOrder) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var previousWidget = widgets[widgetIndex]; - var newWidget = cloneWidgetData(previousWidget); - newWidget.controlCenterGroupOrder = groupOrder.slice(); - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handlePrivacySettingChanged(sectionId, widgetIndex, settingName, value) { - switch (settingName) { - case "showMicIcon": - SettingsData.set("privacyShowMicIcon", value); - break; - case "showCameraIcon": - SettingsData.set("privacyShowCameraIcon", value); - break; - case "showScreenSharingIcon": - SettingsData.set("privacyShowScreenShareIcon", value); - break; - } - } - - function handleMinimumWidthChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.minimumWidth = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleShowSwapChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.showSwap = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleShowInGbChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.showInGb = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleDiskUsageModeChanged(sectionId, widgetIndex, mode) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.diskUsageMode = mode; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget[settingName] = value; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleCompactModeChanged(sectionId, widgetId, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - var currentId = typeof widget === "string" ? widget : widget.id; - if (currentId !== widgetId) - continue; - - var newWidget = cloneWidgetData(widget); - switch (widgetId) { - case "music": - newWidget.mediaSize = value; - break; - case "clock": - newWidget.clockCompactMode = value; - break; - case "focusedWindow": - newWidget.focusedWindowCompactMode = value; - break; - case "runningApps": - newWidget.runningAppsCompactMode = value; - break; - case "keyboard_layout_name": - newWidget.keyboardLayoutNameCompactMode = value; - break; - } - widgets[i] = newWidget; - break; - } - setWidgetsForSection(sectionId, widgets); - } - - function getItemsForSection(sectionId) { - var widgets = []; - var widgetData = getWidgetsForSection(sectionId); - widgetData.forEach(widget => { - var isString = typeof widget === "string"; - var widgetId = isString ? widget : widget.id; - var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId); - if (!widgetDef) - return; - - var item = Object.assign({}, widgetDef); - item.enabled = isString ? true : widget.enabled; - if (!isString) { - if (widget.size !== undefined) - item.size = widget.size; - if (widget.selectedGpuIndex !== undefined) - item.selectedGpuIndex = widget.selectedGpuIndex; - if (widget.pciId !== undefined) - item.pciId = widget.pciId; - if (widget.mountPath !== undefined) - item.mountPath = widget.mountPath; - if (widget.diskUsageMode !== undefined) - item.diskUsageMode = widget.diskUsageMode; - if (widget.showNetworkIcon !== undefined) - item.showNetworkIcon = widget.showNetworkIcon; - if (widget.showBluetoothIcon !== undefined) - item.showBluetoothIcon = widget.showBluetoothIcon; - if (widget.showAudioIcon !== undefined) - item.showAudioIcon = widget.showAudioIcon; - if (widget.showAudioPercent !== undefined) - item.showAudioPercent = widget.showAudioPercent; - if (widget.showVpnIcon !== undefined) - item.showVpnIcon = widget.showVpnIcon; - if (widget.showBrightnessIcon !== undefined) - item.showBrightnessIcon = widget.showBrightnessIcon; - if (widget.showBrightnessPercent !== undefined) - item.showBrightnessPercent = widget.showBrightnessPercent; - if (widget.showMicIcon !== undefined) - item.showMicIcon = widget.showMicIcon; - if (widget.showMicPercent !== undefined) - item.showMicPercent = widget.showMicPercent; - if (widget.showBatteryIcon !== undefined) - item.showBatteryIcon = widget.showBatteryIcon; - if (widget.showPrinterIcon !== undefined) - item.showPrinterIcon = widget.showPrinterIcon; - if (widget.showScreenSharingIcon !== undefined) - item.showScreenSharingIcon = widget.showScreenSharingIcon; - if (widget.controlCenterGroupOrder !== undefined) - item.controlCenterGroupOrder = widget.controlCenterGroupOrder; - if (widget.minimumWidth !== undefined) - item.minimumWidth = widget.minimumWidth; - if (widget.showSwap !== undefined) - item.showSwap = widget.showSwap; - if (widget.showInGb !== undefined) - item.showInGb = widget.showInGb; - if (widget.mediaSize !== undefined) - item.mediaSize = widget.mediaSize; - if (widget.clockCompactMode !== undefined) - item.clockCompactMode = widget.clockCompactMode; - if (widget.focusedWindowCompactMode !== undefined) - item.focusedWindowCompactMode = widget.focusedWindowCompactMode; - if (widget.runningAppsCompactMode !== undefined) - item.runningAppsCompactMode = widget.runningAppsCompactMode; - if (widget.runningAppsGroupByApp !== undefined) - item.runningAppsGroupByApp = widget.runningAppsGroupByApp; - if (widget.runningAppsCurrentWorkspace !== undefined) - item.runningAppsCurrentWorkspace = widget.runningAppsCurrentWorkspace; - if (widget.runningAppsCurrentMonitor !== undefined) - item.runningAppsCurrentMonitor = widget.runningAppsCurrentMonitor; - if (widget.keyboardLayoutNameCompactMode !== undefined) - item.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode; - if (widget.barMaxVisibleApps !== undefined) - item.barMaxVisibleApps = widget.barMaxVisibleApps; - if (widget.barMaxVisibleRunningApps !== undefined) - item.barMaxVisibleRunningApps = widget.barMaxVisibleRunningApps; - if (widget.barShowOverflowBadge !== undefined) - item.barShowOverflowBadge = widget.barShowOverflowBadge; - if (widget.trayUseInlineExpansion !== undefined) - item.trayUseInlineExpansion = widget.trayUseInlineExpansion; - } - widgets.push(item); - }); - return widgets; - } - - Component.onCompleted: { - const leftWidgets = selectedBarConfig?.leftWidgets; - const centerWidgets = selectedBarConfig?.centerWidgets; - const rightWidgets = selectedBarConfig?.rightWidgets; - - if (!leftWidgets) - setWidgetsForSection("left", defaultLeftWidgets); - if (!centerWidgets) - setWidgetsForSection("center", defaultCenterWidgets); - if (!rightWidgets) - setWidgetsForSection("right", defaultRightWidgets); - - const sections = ["left", "center", "right"]; - sections.forEach(sectionId => { - var widgets = getWidgetsForSection(sectionId).slice(); - var updated = false; - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - if (typeof widget === "object" && widget.id === "spacer" && !widget.size) { - widgets[i] = Object.assign({}, widget, { - "size": 20 - }); - updated = true; - } - } - if (updated) - setWidgetsForSection(sectionId, widgets); - }); - } - - LazyLoader { - id: widgetSelectionPopupLoader - active: false - - WidgetSelectionPopup { - id: widgetSelectionPopupItem - parentModal: widgetsTab.parentModal - onWidgetSelected: (widgetId, targetSection) => { - widgetsTab.addWidgetToSection(widgetId, targetSection); - } - } - } - - function showWidgetSelectionPopup(sectionId) { - widgetSelectionPopupLoader.active = true; - if (!widgetSelectionPopupLoader.item) - return; - widgetSelectionPopupLoader.item.targetSection = sectionId; - widgetSelectionPopupLoader.item.allWidgets = widgetsTab.getWidgetsForPopup(); - widgetSelectionPopupLoader.item.show(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: barSelectorContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - visible: hasMultipleBars - - Column { - id: barSelectorContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "toolbar" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Select Bar") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankButtonGroup { - id: barSelectorGroup - width: parent.width - model: SettingsData.barConfigs.map(cfg => cfg.name || ("Bar " + (SettingsData.barConfigs.indexOf(cfg) + 1))) - currentIndex: { - const idx = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return idx >= 0 ? idx : 0; - } - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (index >= 0 && index < SettingsData.barConfigs.length) - selectedBarId = SettingsData.barConfigs[index].id; - } - } - } - } - - StyledRect { - width: parent.width - height: widgetManagementHeader.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: widgetManagementHeader - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "widgets" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - text: I18n.tr("Widget Management") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Item { - height: 1 - Layout.fillWidth: true - } - - Rectangle { - width: resetContentRow.implicitWidth + Theme.spacingM * 2 - height: 28 - radius: Theme.cornerRadius - color: resetArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariant - Layout.alignment: Qt.AlignVCenter - border.width: 0 - - Row { - id: resetContentRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "refresh" - size: 14 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Reset") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: resetArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - setWidgetsForSection("left", defaultLeftWidgets); - setWidgetsForSection("center", defaultCenterWidgets); - setWidgetsForSection("right", defaultRightWidgets); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: leftSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: leftSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Top Section") : I18n.tr("Left Section") - titleIcon: "format_align_left" - sectionId: "left" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("left") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - - StyledRect { - width: parent.width - height: centerSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: centerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Middle Section") : I18n.tr("Center Section") - titleIcon: "format_align_center" - sectionId: "center" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("center") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - - StyledRect { - width: parent.width - height: rightSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: rightSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Bottom Section") : I18n.tr("Right Section") - titleIcon: "format_align_right" - sectionId: "right" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("right") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml deleted file mode 100644 index 88c1270..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml +++ /dev/null @@ -1,2940 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets -import qs.Services - -Column { - id: root - - property var items: [] - property var allWidgets: [] - property string title: "" - property string titleIcon: "widgets" - property string sectionId: "" - - DankTooltipV2 { - id: sharedTooltip - } - - signal itemEnabledChanged(string sectionId, string itemId, bool enabled) - signal itemOrderChanged(var newOrder) - signal addWidget(string sectionId) - signal removeWidget(string sectionId, int widgetIndex) - signal spacerSizeChanged(string sectionId, int widgetIndex, int newSize) - signal compactModeChanged(string widgetId, var value) - signal gpuSelectionChanged(string sectionId, int widgetIndex, int selectedIndex) - signal diskMountSelectionChanged(string sectionId, int widgetIndex, string mountPath) - signal controlCenterSettingChanged(string sectionId, int widgetIndex, string settingName, bool value) - signal controlCenterGroupOrderChanged(string sectionId, int widgetIndex, var groupOrder) - signal privacySettingChanged(string sectionId, int widgetIndex, string settingName, bool value) - signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled) - signal showSwapChanged(string sectionId, int widgetIndex, bool enabled) - signal showInGbChanged(string sectionId, int widgetIndex, bool enabled) - signal diskUsageModeChanged(string sectionId, int widgetIndex, int mode) - signal overflowSettingChanged(string sectionId, int widgetIndex, string settingName, var value) - - function cloneWidgetData(widget) { - var result = { - "id": widget.id, - "enabled": widget.enabled - }; - var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"]; - for (var i = 0; i < keys.length; i++) { - if (widget[keys[i]] !== undefined) - result[keys[i]] = widget[keys[i]]; - } - return result; - } - - width: parent.width - height: implicitHeight - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingM - - DankIcon { - name: root.titleIcon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Column { - id: itemsList - - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.items - - delegate: Item { - id: delegateItem - - property bool held: dragArea.pressed - property real originalY: y - - width: itemsList.width - height: 70 - z: held ? 2 : 1 - - Rectangle { - id: itemBackground - - anchors.fill: parent - anchors.margins: 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.8) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - DankIcon { - name: "drag_indicator" - size: Theme.iconSize - 4 - color: Theme.outline - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM + 8 - anchors.verticalCenter: parent.verticalCenter - opacity: 0.8 - } - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: modelData.enabled ? Theme.primary : Theme.outline - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM * 2 + 40 - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM * 3 + 40 + Theme.iconSize - anchors.right: actionButtons.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: modelData.enabled ? Theme.surfaceText : Theme.outline - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: { - if (modelData.id === "gpuTemp") { - var selectedIdx = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0; - if (DgopService.availableGpus && DgopService.availableGpus.length > selectedIdx) { - var gpu = DgopService.availableGpus[selectedIdx]; - return gpu.driver ? gpu.driver.toUpperCase() : ""; - } - return I18n.tr("No GPU detected"); - } - return modelData.description; - } - font.pixelSize: Theme.fontSizeSmall - color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - } - } - - Row { - id: actionButtons - - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: gpuMenuButton - visible: modelData.id === "gpuTemp" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - gpuContextMenu.widgetData = modelData; - gpuContextMenu.sectionId = root.sectionId; - gpuContextMenu.widgetIndex = index; - - var buttonPos = gpuMenuButton.mapToItem(root, 0, 0); - var popupWidth = gpuContextMenu.width; - var popupHeight = gpuContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + gpuMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + gpuMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - gpuContextMenu.x = xPos; - gpuContextMenu.y = yPos; - gpuContextMenu.open(); - } - } - - Item { - width: 120 - height: 32 - visible: modelData.id === "diskUsage" - DankDropdown { - id: diskMountDropdown - anchors.fill: parent - currentValue: { - const mountPath = modelData.mountPath || "/"; - if (mountPath === "/") { - return "root (/)"; - } - return mountPath; - } - options: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return ["root (/)"]; - } - return DgopService.diskMounts.map(mount => { - if (mount.mount === "/") { - return "root (/)"; - } - return mount.mount; - }); - } - onValueChanged: value => { - const newPath = value === "root (/)" ? "/" : value; - root.diskMountSelectionChanged(root.sectionId, index, newPath); - } - } - } - - DankActionButton { - id: diskMenuButton - visible: modelData.id === "diskUsage" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - diskUsageContextMenu.widgetData = modelData; - diskUsageContextMenu.sectionId = root.sectionId; - diskUsageContextMenu.widgetIndex = index; - - var buttonPos = diskMenuButton.mapToItem(root, 0, 0); - var xPos = buttonPos.x - diskUsageContextMenu.width - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + diskMenuButton.width + Theme.spacingS; - var yPos = buttonPos.y - diskUsageContextMenu.height / 2 + diskMenuButton.height / 2; - if (yPos < 0) - yPos = Theme.spacingS; - else if (yPos + diskUsageContextMenu.height > root.height) - yPos = root.height - diskUsageContextMenu.height - Theme.spacingS; - - diskUsageContextMenu.x = xPos; - diskUsageContextMenu.y = yPos; - diskUsageContextMenu.open(); - } - } - - Item { - width: 32 - height: 32 - visible: modelData.warning !== undefined && modelData.warning !== "" - - DankIcon { - name: "warning" - size: 20 - color: Theme.error - anchors.centerIn: parent - opacity: warningArea.containsMouse ? 1.0 : 0.8 - } - - MouseArea { - id: warningArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - } - - Rectangle { - id: warningTooltip - - property string warningText: (modelData.warning !== undefined && modelData.warning !== "") ? modelData.warning : "" - - width: Math.min(250, warningTooltipText.implicitWidth) + Theme.spacingM * 2 - height: warningTooltipText.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outline - border.width: 0 - visible: warningArea.containsMouse && warningText !== "" - opacity: visible ? 1 : 0 - x: -width - Theme.spacingS - y: (parent.height - height) / 2 - z: 100 - - StyledText { - id: warningTooltipText - anchors.centerIn: parent - anchors.margins: Theme.spacingS - text: warningTooltip.warningText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: Math.min(250, implicitWidth) - wrapMode: Text.WordWrap - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - DankActionButton { - id: minimumWidthButton - buttonSize: 28 - visible: modelData.id === "cpuUsage" || modelData.id === "memUsage" || modelData.id === "cpuTemp" || modelData.id === "gpuTemp" - iconName: "straighten" - iconSize: 16 - iconColor: (modelData.minimumWidth !== undefined ? modelData.minimumWidth : true) ? Theme.primary : Theme.outline - onClicked: { - var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true; - root.minimumWidthChanged(root.sectionId, index, !currentEnabled); - } - onEntered: { - var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true; - const tooltipText = currentEnabled ? "Force Padding" : "Dynamic Width"; - sharedTooltip.show(tooltipText, minimumWidthButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - DankActionButton { - id: memMenuButton - visible: modelData.id === "memUsage" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - memUsageContextMenu.widgetData = modelData; - memUsageContextMenu.sectionId = root.sectionId; - memUsageContextMenu.widgetIndex = index; - - var buttonPos = memMenuButton.mapToItem(root, 0, 0); - var popupWidth = memUsageContextMenu.width; - var popupHeight = memUsageContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + memMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + memMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - memUsageContextMenu.x = xPos; - memUsageContextMenu.y = yPos; - memUsageContextMenu.open(); - } - } - - DankActionButton { - id: musicMenuButton - visible: modelData.id === "music" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - musicContextMenu.widgetData = modelData; - musicContextMenu.sectionId = root.sectionId; - musicContextMenu.widgetIndex = index; - - var buttonPos = musicMenuButton.mapToItem(root, 0, 0); - var popupWidth = musicContextMenu.width; - var popupHeight = musicContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + musicMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + musicMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - musicContextMenu.x = xPos; - musicContextMenu.y = yPos; - musicContextMenu.open(); - } - } - - DankActionButton { - id: runningAppsMenuButton - visible: modelData.id === "runningApps" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - runningAppsContextMenu.widgetData = modelData; - runningAppsContextMenu.sectionId = root.sectionId; - runningAppsContextMenu.widgetIndex = index; - - var buttonPos = runningAppsMenuButton.mapToItem(root, 0, 0); - var popupWidth = runningAppsContextMenu.width; - var popupHeight = runningAppsContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + runningAppsMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + runningAppsMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - runningAppsContextMenu.x = xPos; - runningAppsContextMenu.y = yPos; - runningAppsContextMenu.open(); - } - } - - Row { - spacing: Theme.spacingXS - visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "keyboard_layout_name" || modelData.id === "appsDock" || modelData.id === "systemTray" - - DankActionButton { - id: compactModeButton - buttonSize: 28 - visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "keyboard_layout_name" - iconName: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - return isCompact ? "zoom_out" : "zoom_in"; - } - iconSize: 16 - iconColor: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - return isCompact ? Theme.primary : Theme.outline; - } - onClicked: { - const currentValue = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - root.compactModeChanged(modelData.id, !currentValue); - } - onEntered: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - const tooltipText = isCompact ? "Full Size" : "Compact"; - sharedTooltip.show(tooltipText, compactModeButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - DankActionButton { - id: appsDockMenuButton - buttonSize: 32 - visible: modelData.id === "appsDock" - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - appsDockContextMenu.widgetData = modelData; - appsDockContextMenu.sectionId = root.sectionId; - appsDockContextMenu.widgetIndex = index; - - var buttonPos = appsDockMenuButton.mapToItem(root, 0, 0); - var popupWidth = appsDockContextMenu.width; - var popupHeight = appsDockContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + appsDockMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + appsDockMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - appsDockContextMenu.x = xPos; - appsDockContextMenu.y = yPos; - appsDockContextMenu.open(); - } - } - - DankActionButton { - id: trayMenuButton - buttonSize: 32 - visible: modelData.id === "systemTray" - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - trayContextMenu.widgetData = modelData; - trayContextMenu.sectionId = root.sectionId; - trayContextMenu.widgetIndex = index; - - var buttonPos = trayMenuButton.mapToItem(root, 0, 0); - var popupWidth = trayContextMenu.width; - var popupHeight = trayContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + trayMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + trayMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - trayContextMenu.x = xPos; - trayContextMenu.y = yPos; - trayContextMenu.open(); - } - } - - Rectangle { - id: compactModeTooltip - width: tooltipText.contentWidth + Theme.spacingM * 2 - height: tooltipText.contentHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outline - border.width: 0 - visible: false - opacity: visible ? 1 : 0 - x: -width - Theme.spacingS - y: (parent.height - height) / 2 - z: 100 - - StyledText { - id: tooltipText - anchors.centerIn: parent - text: I18n.tr("Compact Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - DankActionButton { - id: ccMenuButton - visible: modelData.id === "controlCenterButton" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - controlCenterContextMenu.widgetData = modelData; - controlCenterContextMenu.sectionId = root.sectionId; - controlCenterContextMenu.widgetIndex = index; - controlCenterContextMenu.controlCenterGroups = controlCenterContextMenu.getOrderedControlCenterGroups(); - - var buttonPos = ccMenuButton.mapToItem(root, 0, 0); - var popupWidth = controlCenterContextMenu.width; - var popupHeight = controlCenterContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + ccMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + ccMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - controlCenterContextMenu.x = xPos; - controlCenterContextMenu.y = yPos; - controlCenterContextMenu.open(); - } - } - - DankActionButton { - id: privacyMenuButton - visible: modelData.id === "privacyIndicator" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - privacyContextMenu.widgetData = modelData; - privacyContextMenu.sectionId = root.sectionId; - privacyContextMenu.widgetIndex = index; - - var buttonPos = privacyMenuButton.mapToItem(root, 0, 0); - var popupWidth = privacyContextMenu.width; - var popupHeight = privacyContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + privacyMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + privacyMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - privacyContextMenu.x = xPos; - privacyContextMenu.y = yPos; - privacyContextMenu.open(); - } - } - - DankActionButton { - id: visibilityButton - visible: modelData.id !== "spacer" - buttonSize: 32 - iconName: modelData.enabled ? "visibility" : "visibility_off" - iconSize: 18 - iconColor: modelData.enabled ? Theme.primary : Theme.outline - onClicked: { - root.itemEnabledChanged(root.sectionId, modelData.id, !modelData.enabled); - } - onEntered: { - const tooltipText = modelData.enabled ? "Hide" : "Show"; - sharedTooltip.show(tooltipText, visibilityButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - Row { - visible: modelData.id === "spacer" - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var currentSize = modelData.size || 20; - var newSize = Math.max(5, currentSize - 5); - root.spacerSizeChanged(root.sectionId, index, newSize); - } - } - - StyledText { - text: (modelData.size || 20).toString() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var currentSize = modelData.size || 20; - var newSize = Math.min(5000, currentSize + 5); - root.spacerSizeChanged(root.sectionId, index, newSize); - } - } - } - - DankActionButton { - buttonSize: 32 - iconName: "close" - iconSize: 18 - iconColor: Theme.error - onClicked: { - root.removeWidget(root.sectionId, index); - } - } - } - - MouseArea { - id: dragArea - - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: 60 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: held ? delegateItem : undefined - drag.axis: Drag.YAxis - drag.minimumY: -delegateItem.height - drag.maximumY: itemsList.height - preventStealing: true - onPressed: { - delegateItem.z = 2; - delegateItem.originalY = delegateItem.y; - } - onReleased: { - delegateItem.z = 1; - if (drag.active) { - var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing)); - newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1)); - if (newIndex !== index) { - var newItems = root.items.slice(); - var draggedItem = newItems.splice(index, 1)[0]; - newItems.splice(newIndex, 0, draggedItem); - root.itemOrderChanged(newItems.map(item => root.cloneWidgetData(item))); - } - } - delegateItem.x = 0; - delegateItem.y = delegateItem.originalY; - } - } - - Behavior on y { - enabled: !dragArea.held && !dragArea.drag.active - - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - Rectangle { - width: 200 - height: 40 - radius: Theme.cornerRadius - color: addButtonArea.containsMouse ? Theme.primaryContainer : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: I18n.tr("Add Widget") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - anchors.centerIn: parent - } - - MouseArea { - id: addButtonArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.addWidget(root.sectionId); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Popup { - id: memUsageContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 200 - height: 80 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: swapToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "swap_horiz" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show Swap") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: swapToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: memUsageContextMenu.widgetData?.showSwap ?? false - onToggled: { - root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled); - } - } - - MouseArea { - id: swapToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - swapToggle.checked = !swapToggle.checked; - root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, swapToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: gbToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "straighten" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show in GB") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: gbToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: memUsageContextMenu.widgetData?.showInGb ?? false - onToggled: { - root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled); - } - } - - MouseArea { - id: gbToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - gbToggle.checked = !gbToggle.checked; - root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, gbToggle.checked); - } - } - } - } - } - } - - Popup { - id: trayContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 220 - height: contentColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: trayOverflowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "arrow_selector_tool" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Use Inline Expansion") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: trayOverflowToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false - } - - MouseArea { - id: trayOverflowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const newValue = !(trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false); - root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayUseInlineExpansion", newValue); - } - } - } - } - } - } - - Popup { - id: diskUsageContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 240 - height: diskMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: diskMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Disk Usage Display") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Repeater { - model: [ - { - label: I18n.tr("Percentage"), - mode: 0, - icon: "percent" - }, - { - label: I18n.tr("Total"), - mode: 1, - icon: "storage" - }, - { - label: I18n.tr("Remaining"), - mode: 2, - icon: "hourglass_empty" - }, - { - label: I18n.tr("Remaining / Total"), - mode: 3, - icon: "pie_chart" - } - ] - - delegate: Rectangle { - required property var modelData - required property int index - - width: diskMenuColumn.width - height: 32 - radius: Theme.cornerRadius - color: diskOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - function isSelected() { - return (diskUsageContextMenu.currentWidgetData?.diskUsageMode ?? 0) === modelData.mode; - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: modelData.icon - size: 16 - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: isSelected() ? Theme.primary : Theme.surfaceText - font.weight: isSelected() ? Font.Medium : Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 16 - color: Theme.primary - visible: isSelected() - } - - MouseArea { - id: diskOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.diskUsageModeChanged(diskUsageContextMenu.sectionId, diskUsageContextMenu.widgetIndex, modelData.mode); - diskUsageContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: controlCenterContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - readonly property real minimumContentWidth: controlCenterContentMetrics.implicitWidth + Theme.spacingS * 2 - readonly property real controlCenterRowHeight: 32 - readonly property real controlCenterRowSpacing: 1 - readonly property real controlCenterGroupVerticalPadding: Theme.spacingXS * 2 - readonly property real controlCenterMenuSpacing: 2 - width: Math.max(220, minimumContentWidth) - height: getControlCenterPopupHeight(controlCenterGroups) - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onClosed: { - cancelControlCenterDrag(); - } - - readonly property var defaultControlCenterGroups: [ - { - id: "network", - rows: [ - { - icon: "lan", - label: I18n.tr("Network"), - setting: "showNetworkIcon" - } - ] - }, - { - id: "vpn", - rows: [ - { - icon: "vpn_lock", - label: I18n.tr("VPN"), - setting: "showVpnIcon" - } - ] - }, - { - id: "bluetooth", - rows: [ - { - icon: "bluetooth", - label: I18n.tr("Bluetooth"), - setting: "showBluetoothIcon" - } - ] - }, - { - id: "audio", - rows: [ - { - icon: "volume_up", - label: I18n.tr("Audio"), - setting: "showAudioIcon" - }, - { - icon: "percent", - label: I18n.tr("Volume"), - setting: "showAudioPercent" - } - ] - }, - { - id: "microphone", - rows: [ - { - icon: "mic", - label: I18n.tr("Microphone"), - setting: "showMicIcon" - }, - { - icon: "percent", - label: I18n.tr("Microphone Volume"), - setting: "showMicPercent" - } - ] - }, - { - id: "brightness", - rows: [ - { - icon: "brightness_high", - label: I18n.tr("Brightness"), - setting: "showBrightnessIcon" - }, - { - icon: "percent", - label: I18n.tr("Brightness Value"), - setting: "showBrightnessPercent" - } - ] - }, - { - id: "battery", - rows: [ - { - icon: "battery_full", - label: I18n.tr("Battery"), - setting: "showBatteryIcon" - } - ] - }, - { - id: "printer", - rows: [ - { - icon: "print", - label: I18n.tr("Printer"), - setting: "showPrinterIcon" - } - ] - }, - { - id: "screenSharing", - rows: [ - { - icon: "screen_record", - label: I18n.tr("Screen Sharing"), - setting: "showScreenSharingIcon" - } - ] - } - ] - property var controlCenterGroups: defaultControlCenterGroups - property int draggedControlCenterGroupIndex: -1 - property int controlCenterGroupDropIndex: -1 - - function updateControlCenterGroupDropIndex(draggedIndex, localY) { - const totalGroups = controlCenterGroups.length; - let dropIndex = totalGroups; - - for (let i = 0; i < totalGroups; i++) { - const delegate = groupRepeater.itemAt(i); - if (!delegate) - continue; - - const midpoint = delegate.y + delegate.height / 2; - if (localY < midpoint) { - dropIndex = i; - break; - } - } - - controlCenterGroupDropIndex = Math.max(0, Math.min(totalGroups, dropIndex)); - draggedControlCenterGroupIndex = draggedIndex; - } - - function finishControlCenterDrag() { - if (draggedControlCenterGroupIndex < 0) { - controlCenterGroupDropIndex = -1; - return; - } - - const fromIndex = draggedControlCenterGroupIndex; - let toIndex = controlCenterGroupDropIndex; - - draggedControlCenterGroupIndex = -1; - controlCenterGroupDropIndex = -1; - - if (toIndex < 0 || toIndex > controlCenterGroups.length || toIndex === fromIndex || toIndex === fromIndex + 1) - return; - - const groups = controlCenterGroups.slice(); - const moved = groups.splice(fromIndex, 1)[0]; - - if (toIndex > fromIndex) - toIndex -= 1; - - groups.splice(toIndex, 0, moved); - controlCenterGroups = groups; - const reorderedGroupIds = groups.map(group => group.id); - root.controlCenterGroupOrderChanged(sectionId, widgetIndex, reorderedGroupIds); - } - - function cancelControlCenterDrag() { - draggedControlCenterGroupIndex = -1; - controlCenterGroupDropIndex = -1; - } - - function getControlCenterGroupHeight(group) { - const rowCount = group?.rows?.length ?? 0; - if (rowCount <= 0) - return controlCenterGroupVerticalPadding; - - return rowCount * controlCenterRowHeight + Math.max(0, rowCount - 1) * controlCenterRowSpacing + controlCenterGroupVerticalPadding; - } - - function getControlCenterPopupHeight(groups) { - const orderedGroups = groups || []; - let totalHeight = Theme.spacingS * 2; - - for (let i = 0; i < orderedGroups.length; i++) { - totalHeight += getControlCenterGroupHeight(orderedGroups[i]); - if (i < orderedGroups.length - 1) - totalHeight += controlCenterMenuSpacing; - } - - return totalHeight; - } - - function getOrderedControlCenterGroups() { - const baseGroups = defaultControlCenterGroups.slice(); - const currentWidget = contentItem.getCurrentWidgetData(); - const savedOrder = currentWidget?.controlCenterGroupOrder; - if (!savedOrder || !savedOrder.length) - return baseGroups; - - const groupMap = {}; - for (let i = 0; i < baseGroups.length; i++) - groupMap[baseGroups[i].id] = baseGroups[i]; - - const orderedGroups = []; - for (let i = 0; i < savedOrder.length; i++) { - const groupId = savedOrder[i]; - const group = groupMap[groupId]; - if (group) { - orderedGroups.push(group); - delete groupMap[groupId]; - } - } - - for (let i = 0; i < baseGroups.length; i++) { - const group = baseGroups[i]; - if (groupMap[group.id]) - orderedGroups.push(group); - } - - return orderedGroups; - } - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - function getCurrentWidgetData() { - const widgets = root.items || []; - if (controlCenterContextMenu.widgetIndex >= 0 && controlCenterContextMenu.widgetIndex < widgets.length) - return widgets[controlCenterContextMenu.widgetIndex]; - return controlCenterContextMenu.widgetData; - } - - Column { - id: menuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Item { - id: controlCenterContentMetrics - visible: false - implicitWidth: 16 + Theme.spacingS + 16 + Theme.spacingS + longestControlCenterLabelMetrics.advanceWidth + Theme.spacingM + 40 + Theme.spacingS * 2 + Theme.spacingM - } - - TextMetrics { - id: longestControlCenterLabelMetrics - font.pixelSize: Theme.fontSizeSmall - text: { - const labels = [I18n.tr("Network"), I18n.tr("VPN"), I18n.tr("Bluetooth"), I18n.tr("Audio"), I18n.tr("Volume"), I18n.tr("Microphone"), I18n.tr("Microphone Volume"), I18n.tr("Brightness"), I18n.tr("Brightness Value"), I18n.tr("Battery"), I18n.tr("Printer"), I18n.tr("Screen Sharing")]; - let longest = ""; - for (let i = 0; i < labels.length; i++) { - if (labels[i].length > longest.length) - longest = labels[i]; - } - return longest; - } - } - - Repeater { - id: groupRepeater - model: controlCenterContextMenu.controlCenterGroups - - delegate: Item { - id: delegateRoot - - required property var modelData - required property int index - - function getCheckedState(settingName) { - const wd = controlCenterContextMenu.contentItem.getCurrentWidgetData(); - switch (settingName) { - case "showNetworkIcon": - return wd?.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon; - case "showVpnIcon": - return wd?.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon; - case "showBluetoothIcon": - return wd?.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon; - case "showAudioIcon": - return wd?.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon; - case "showAudioPercent": - return wd?.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent; - case "showMicIcon": - return wd?.showMicIcon ?? SettingsData.controlCenterShowMicIcon; - case "showMicPercent": - return wd?.showMicPercent ?? SettingsData.controlCenterShowMicPercent; - case "showBrightnessIcon": - return wd?.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon; - case "showBrightnessPercent": - return wd?.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent; - case "showBatteryIcon": - return wd?.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; - case "showPrinterIcon": - return wd?.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; - case "showScreenSharingIcon": - return wd?.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; - default: - return false; - } - } - - readonly property string rootSetting: modelData.rows[0]?.setting ?? "" - readonly property bool rootEnabled: rootSetting ? getCheckedState(rootSetting) : true - readonly property bool isDragged: controlCenterContextMenu.draggedControlCenterGroupIndex === index - readonly property bool showDropIndicatorAbove: controlCenterContextMenu.controlCenterGroupDropIndex === index - readonly property bool showDropIndicatorBelow: controlCenterContextMenu.controlCenterGroupDropIndex === controlCenterContextMenu.controlCenterGroups.length && index === controlCenterContextMenu.controlCenterGroups.length - 1 - - width: menuColumn.width - height: groupBackground.height - - Rectangle { - id: groupBackground - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: groupContent.implicitHeight + Theme.spacingXS * 2 - radius: Theme.cornerRadius - color: isDragged ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.18) : (groupHoverArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent") - opacity: isDragged ? 0.75 : 1.0 - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: -1 - height: 2 - radius: 1 - color: Theme.primary - visible: showDropIndicatorAbove - z: 3 - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: -1 - height: 2 - radius: 1 - color: Theme.primary - visible: showDropIndicatorBelow - z: 3 - } - - Item { - id: groupContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: Theme.spacingXS - implicitHeight: groupColumn.implicitHeight - - Column { - id: groupColumn - anchors.left: parent.left - anchors.right: parent.right - spacing: 1 - - Repeater { - id: groupColumnRepeater - model: modelData.rows - - delegate: Rectangle { - required property var modelData - required property int index - - readonly property var rowData: modelData - readonly property bool isFirstRow: index === 0 - readonly property bool rowEnabled: isFirstRow ? true : delegateRoot.rootEnabled - readonly property bool computedCheckedState: rowEnabled ? getCheckedState(rowData.setting) : false - readonly property bool rowHovered: rowEnabled && (toggleArea.containsMouse || (isFirstRow && groupDragHandleArea.containsMouse)) - - width: groupColumn.width - height: 32 - radius: Theme.cornerRadius - opacity: rowEnabled ? 1.0 : 0.5 - color: rowHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: toggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "drag_indicator" - size: 16 - color: groupDragHandleArea.pressed || isDragged ? Theme.primary : Theme.outline - visible: isFirstRow - } - - MouseArea { - id: groupDragHandleArea - anchors.fill: parent - hoverEnabled: true - preventStealing: true - enabled: isFirstRow - cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor - - onPressed: mouse => { - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - } - onPositionChanged: mouse => { - if (!pressed) - return; - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - } - onReleased: mouse => { - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - controlCenterContextMenu.finishControlCenterDrag(); - } - onCanceled: { - controlCenterContextMenu.cancelControlCenterDrag(); - } - } - } - - DankIcon { - name: rowData.icon - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: rowData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: toggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - enabled: rowEnabled - checked: computedCheckedState - - onToggled: { - if (!rowEnabled) - return; - root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, rowData.setting, toggled); - } - } - - MouseArea { - id: toggleArea - anchors.fill: parent - anchors.leftMargin: 16 + Theme.spacingS * 2 - hoverEnabled: true - cursorShape: rowEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: rowEnabled && controlCenterContextMenu.draggedControlCenterGroupIndex < 0 - onPressed: { - if (!rowEnabled) - return; - root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, rowData.setting, !computedCheckedState); - } - } - } - } - } - - MouseArea { - id: groupHoverArea - anchors.fill: parent - hoverEnabled: true - enabled: false - } - } - } - } - } - } - } - - Popup { - id: privacyContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 200 - height: 160 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onOpened: { - console.log("Privacy context menu opened"); - } - - onClosed: { - console.log("Privacy Center context menu closed"); - } - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - - Column { - id: menuPrivacyColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Always on icons") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: micToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "mic" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Microphone") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: micToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowMicIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", toggled); - } - } - - MouseArea { - id: micToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - micToggle.checked = !micToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", micToggle.checked); - } - } - } - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: cameraToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "camera_video" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Camera") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: cameraToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowCameraIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", toggled); - } - } - - MouseArea { - id: cameraToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - cameraToggle.checked = !cameraToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", cameraToggle.checked); - } - } - } - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: screenshareToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "screen_share" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Screen sharing") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: screenshareToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowScreenShareIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", toggled); - } - } - - MouseArea { - id: screenshareToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - screenshareToggle.checked = !screenshareToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", screenshareToggle.checked); - } - } - } - } - } - } - - Popup { - id: gpuContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 250 - height: gpuMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: gpuMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Repeater { - model: DgopService.availableGpus || [] - - delegate: Rectangle { - required property var modelData - required property int index - - width: gpuMenuColumn.width - height: 40 - radius: Theme.cornerRadius - color: gpuOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - property bool isSelected: { - var selectedIdx = gpuContextMenu.widgetData ? (gpuContextMenu.widgetData.selectedGpuIndex !== undefined ? gpuContextMenu.widgetData.selectedGpuIndex : 0) : 0; - return index === selectedIdx; - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: checkIcon.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "memory" - size: 18 - color: isSelected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.driver ? modelData.driver.toUpperCase() : "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: isSelected ? Theme.primary : Theme.surfaceText - } - - StyledText { - text: modelData.displayName || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: 180 - } - } - } - - DankIcon { - id: checkIcon - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 18 - color: Theme.primary - visible: isSelected - } - - MouseArea { - id: gpuOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.gpuSelectionChanged(gpuContextMenu.sectionId, gpuContextMenu.widgetIndex, index); - gpuContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: musicContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 180 - height: musicMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: musicMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Repeater { - model: [ - { - icon: "photo_size_select_small", - label: I18n.tr("Small"), - sizeValue: 0 - }, - { - icon: "photo_size_select_actual", - label: I18n.tr("Medium"), - sizeValue: 1 - }, - { - icon: "photo_size_select_large", - label: I18n.tr("Large"), - sizeValue: 2 - }, - { - icon: "fit_screen", - label: I18n.tr("Largest"), - sizeValue: 3 - } - ] - - delegate: Rectangle { - required property var modelData - required property int index - - function isSelected() { - var wd = musicContextMenu.widgetData; - var currentSize = wd?.mediaSize ?? SettingsData.mediaSize; - return currentSize === modelData.sizeValue; - } - - width: musicMenuColumn.width - height: Math.max(18, Theme.fontSizeSmall) + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: musicOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: modelData.icon - size: 18 - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - font.weight: isSelected() ? Font.Medium : Font.Normal - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 16 - color: Theme.primary - visible: isSelected() - } - - MouseArea { - id: musicOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.compactModeChanged("music", modelData.sizeValue); - musicContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: runningAppsContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 240 - height: runningAppsMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: runningAppsMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Running Apps Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raCompactArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "zoom_in" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compact Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raCompactToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCompactMode ?? SettingsData.runningAppsCompactMode - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCompactMode", toggled); - } - } - - MouseArea { - id: raCompactArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raCompactToggle.checked = !raCompactToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCompactMode", raCompactToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raGroupArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "apps" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Group by App") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raGroupToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsGroupByApp ?? SettingsData.runningAppsGroupByApp - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsGroupByApp", toggled); - } - } - - MouseArea { - id: raGroupArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raGroupToggle.checked = !raGroupToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsGroupByApp", raGroupToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raWorkspaceArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "workspaces" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Workspace", "Running apps filter: only show apps from the active workspace") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raWorkspaceToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCurrentWorkspace ?? SettingsData.runningAppsCurrentWorkspace - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentWorkspace", toggled); - } - } - - MouseArea { - id: raWorkspaceArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raWorkspaceToggle.checked = !raWorkspaceToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentWorkspace", raWorkspaceToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raDisplayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "monitor" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Monitor", "Running apps filter: only show apps from the same monitor") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raDisplayToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCurrentMonitor ?? SettingsData.runningAppsCurrentMonitor - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentMonitor", toggled); - } - } - - MouseArea { - id: raDisplayArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raDisplayToggle.checked = !raDisplayToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentMonitor", raDisplayToggle.checked); - } - } - } - } - } - } - - Popup { - id: appsDockContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - // Dynamically get current widget data from the items list - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 320 - height: appsDockMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: appsDockMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Apps Dock Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - } - - StyledText { - text: I18n.tr("Overflow") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max Pinned Apps") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - var newVal = Math.max(0, current - 1); - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleApps", newVal); - } - } - - StyledText { - text: { - var val = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - return val === 0 ? I18n.tr("All") : val; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 30 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - var newVal = current + 1; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleApps", newVal); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max Running Apps") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - var newVal = Math.max(0, current - 1); - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal); - } - } - - StyledText { - text: { - var val = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - return val === 0 ? I18n.tr("All") : val; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 30 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - var newVal = current + 1; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: badgeToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show Badge") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: badgeToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: appsDockContextMenu.currentWidgetData?.barShowOverflowBadge ?? SettingsData.barShowOverflowBadge - onToggled: { - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barShowOverflowBadge", toggled); - } - } - - MouseArea { - id: badgeToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - badgeToggle.checked = !badgeToggle.checked; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barShowOverflowBadge", badgeToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - StyledText { - text: I18n.tr("Visual Effects") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - topPadding: Theme.spacingXS - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: hideIndicatorsArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hide Indicators") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: hideIndicatorsToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockHideIndicators - onToggled: { - SettingsData.set("appsDockHideIndicators", toggled); - } - } - - MouseArea { - id: hideIndicatorsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - hideIndicatorsToggle.checked = !hideIndicatorsToggle.checked; - SettingsData.set("appsDockHideIndicators", hideIndicatorsToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: colorizeActiveArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "palette" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Colorize Active") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: colorizeActiveToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockColorizeActive - onToggled: { - SettingsData.set("appsDockColorizeActive", toggled); - } - } - - MouseArea { - id: colorizeActiveArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - colorizeActiveToggle.checked = !colorizeActiveToggle.checked; - SettingsData.set("appsDockColorizeActive", colorizeActiveToggle.checked); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.appsDockColorizeActive - leftPadding: Theme.spacingL + Theme.spacingS - - StyledText { - text: I18n.tr("Active Color") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 90 - } - - DankButtonGroup { - anchors.verticalCenter: parent.verticalCenter - model: ["pri", "sec", "pc", "err", "ok"] - buttonHeight: 22 - minButtonWidth: 32 - buttonPadding: 4 - checkIconSize: 10 - textSize: 9 - spacing: 1 - currentIndex: { - switch (SettingsData.appsDockActiveColorMode) { - case "secondary": - return 1; - case "primaryContainer": - return 2; - case "error": - return 3; - case "success": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["primary", "secondary", "primaryContainer", "error", "success"]; - SettingsData.set("appsDockActiveColorMode", modes[index]); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: enlargeOnHoverArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "zoom_in" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Enlarge on Hover") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: enlargeOnHoverToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockEnlargeOnHover - onToggled: { - SettingsData.set("appsDockEnlargeOnHover", toggled); - } - } - - MouseArea { - id: enlargeOnHoverArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - enlargeOnHoverToggle.checked = !enlargeOnHoverToggle.checked; - SettingsData.set("appsDockEnlargeOnHover", enlargeOnHoverToggle.checked); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.appsDockEnlargeOnHover - - StyledText { - text: I18n.tr("Enlargement %") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockEnlargePercentage; - var newVal = Math.max(100, current - 5); - SettingsData.set("appsDockEnlargePercentage", newVal); - } - } - - StyledText { - text: SettingsData.appsDockEnlargePercentage + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 50 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockEnlargePercentage; - var newVal = Math.min(150, current + 5); - SettingsData.set("appsDockEnlargePercentage", newVal); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Icon Size %") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockIconSizePercentage; - var newVal = Math.max(50, current - 5); - SettingsData.set("appsDockIconSizePercentage", newVal); - } - } - - StyledText { - text: SettingsData.appsDockIconSizePercentage + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 50 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockIconSizePercentage; - var newVal = Math.min(200, current + 5); - SettingsData.set("appsDockIconSizePercentage", newVal); - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml deleted file mode 100644 index 5e1310e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml +++ /dev/null @@ -1,685 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property var windowRulesIncludeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingInclude: false - property bool fixingInclude: false - property var windowRules: [] - property var activeWindows: getActiveWindows() - - signal rulesChanged - - function getActiveWindows() { - const toplevels = ToplevelManager.toplevels?.values || []; - return toplevels.map(t => ({ - appId: t.appId || "", - title: t.title || "" - })); - } - - Connections { - target: ToplevelManager.toplevels - function onValuesChanged() { - root.activeWindows = root.getActiveWindows(); - } - } - - function getWindowRulesConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "rulesFile": configDir + "/niri/dms/windowrules.kdl", - "grepPattern": 'include.*"dms/windowrules.kdl"', - "includeLine": 'include "dms/windowrules.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "rulesFile": configDir + "/hypr/dms/windowrules.conf", - "grepPattern": 'source.*dms/windowrules.conf', - "includeLine": "source = ./dms/windowrules.conf" - }; - default: - return null; - } - } - - function loadWindowRules() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") { - windowRules = []; - return; - } - - Proc.runCommand("load-windowrules", ["dms", "config", "windowrules", "list", compositor], (output, exitCode) => { - if (exitCode !== 0) { - windowRules = []; - return; - } - try { - const result = JSON.parse(output.trim()); - const allRules = result.rules || []; - windowRules = allRules.filter(r => (r.source || "").includes("dms/windowrules")); - if (result.dmsStatus) { - windowRulesIncludeStatus = { - "exists": result.dmsStatus.exists, - "included": result.dmsStatus.included - }; - } - } catch (e) { - windowRules = []; - } - }); - } - - function removeRule(ruleId) { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") - return; - - Proc.runCommand("remove-windowrule", ["dms", "config", "windowrules", "remove", compositor, ruleId], (output, exitCode) => { - if (exitCode === 0) { - loadWindowRules(); - rulesChanged(); - } - }); - } - - function reorderRules(fromIndex, toIndex) { - if (fromIndex === toIndex) - return; - - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") - return; - - let ids = windowRules.map(r => r.id); - const [moved] = ids.splice(fromIndex, 1); - ids.splice(toIndex, 0, moved); - - Proc.runCommand("reorder-windowrules", ["dms", "config", "windowrules", "reorder", compositor, JSON.stringify(ids)], (output, exitCode) => { - if (exitCode === 0) { - loadWindowRules(); - rulesChanged(); - } - }); - } - - function checkWindowRulesIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "windowrules.kdl" : "windowrules.conf"; - checkingInclude = true; - Proc.runCommand("check-windowrules-include", ["dms", "config", "resolve-include", compositor, filename], (output, exitCode) => { - checkingInclude = false; - if (exitCode !== 0) { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - windowRulesIncludeStatus = JSON.parse(output.trim()); - } catch (e) { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixWindowRulesInclude() { - const paths = getWindowRulesConfigPaths(); - if (!paths) - return; - fixingInclude = true; - const rulesDir = paths.rulesFile.substring(0, paths.rulesFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - Proc.runCommand("fix-windowrules-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${rulesDir}" && ` + `touch "${paths.rulesFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingInclude = false; - if (exitCode !== 0) - return; - checkWindowRulesIncludeStatus(); - loadWindowRules(); - }); - } - - function openRuleModal(window) { - if (!PopoutService.windowRuleModalLoader) - return; - PopoutService.windowRuleModalLoader.active = true; - if (PopoutService.windowRuleModalLoader.item) { - PopoutService.windowRuleModalLoader.item.onRuleSubmitted.connect(loadWindowRules); - PopoutService.windowRuleModalLoader.item.show(window || null); - } - } - - function editRule(rule) { - if (!PopoutService.windowRuleModalLoader) - return; - PopoutService.windowRuleModalLoader.active = true; - if (PopoutService.windowRuleModalLoader.item) { - PopoutService.windowRuleModalLoader.item.onRuleSubmitted.connect(loadWindowRules); - PopoutService.windowRuleModalLoader.item.showEdit(rule); - } - } - - Component.onCompleted: { - if (CompositorService.isNiri || CompositorService.isHyprland) { - checkWindowRulesIncludeStatus(); - loadWindowRules(); - } - } - - DankFlickable { - id: flickable - anchors.fill: parent - clip: true - contentWidth: width - contentHeight: contentColumn.implicitHeight - - Column { - id: contentColumn - width: flickable.width - spacing: Theme.spacingL - topPadding: Theme.spacingXL - bottomPadding: Theme.spacingXL - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: headerSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: headerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "select_window" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Window Rules") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - Layout.fillWidth: true - } - - StyledText { - text: I18n.tr("Define rules for window behavior. Saves to %1").arg(CompositorService.isNiri ? "dms/windowrules.kdl" : "dms/windowrules.conf") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - Layout.fillWidth: true - } - } - - DankActionButton { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - circular: false - iconName: "add" - iconSize: Theme.iconSize - iconColor: Theme.primary - onClicked: root.openRuleModal() - } - } - - RowLayout { - width: parent.width - spacing: Theme.spacingM - visible: root.activeWindows.length > 0 - - StyledText { - text: I18n.tr("Create rule for:") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - Layout.alignment: Qt.AlignVCenter - } - - DankDropdown { - id: windowSelector - Layout.fillWidth: true - dropdownWidth: 400 - compactMode: true - emptyText: I18n.tr("Select a window...") - options: root.activeWindows.map(w => { - const label = w.appId + (w.title ? " - " + w.title : ""); - return label.length > 60 ? label.substring(0, 57) + "..." : label; - }) - onValueChanged: value => { - if (!value) - return; - const index = options.indexOf(value); - if (index < 0 || index >= root.activeWindows.length) - return; - const window = root.activeWindows[index]; - root.openRuleModal(window); - currentValue = ""; - } - } - } - } - } - - StyledRect { - id: warningBox - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: warningSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - - readonly property bool showError: root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included - readonly property bool showSetup: !root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && !root.checkingInclude && (CompositorService.isNiri || CompositorService.isHyprland) - - Row { - id: warningSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: warningBox.showSetup ? I18n.tr("Window Rules Not Configured") : I18n.tr("Window Rules Include Missing") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.warning - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - readonly property string rulesFile: CompositorService.isNiri ? "dms/windowrules.kdl" : "dms/windowrules.conf" - text: warningBox.showSetup ? I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg(rulesFile) : I18n.tr("%1 exists but is not included. Window rules won't apply.").arg(rulesFile) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: warningBox.showError || warningBox.showSetup - text: root.fixingInclude ? I18n.tr("Fixing...") : (warningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background - enabled: !root.fixingInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: root.fixWindowRulesInclude() - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: rulesSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: rulesSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "list" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - text: I18n.tr("Rules (%1)").arg(root.windowRules?.length ?? 0) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - Layout.fillWidth: true - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !root.windowRules || root.windowRules.length === 0 - - Item { - width: 1 - height: Theme.spacingM - } - - DankIcon { - name: "select_window" - size: 40 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - opacity: 0.5 - } - - StyledText { - text: I18n.tr("No window rules configured") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: 1 - height: Theme.spacingM - } - } - - Column { - id: rulesListColumn - width: parent.width - spacing: Theme.spacingXS - visible: root.windowRules && root.windowRules.length > 0 - - Repeater { - model: ScriptModel { - objectProp: "id" - values: root.windowRules || [] - } - - delegate: Item { - id: ruleDelegateItem - required property var modelData - required property int index - - property bool held: ruleDragArea.pressed - property real originalY: y - - readonly property string ruleIdRef: modelData.id - readonly property var liveRuleData: { - const rules = root.windowRules || []; - return rules.find(r => r.id === ruleIdRef) ?? modelData; - } - readonly property string displayName: { - const name = liveRuleData.name || ""; - if (name) - return name; - const m = liveRuleData.matchCriteria || {}; - return m.appId || m.title || I18n.tr("Unnamed Rule"); - } - - width: rulesListColumn.width - height: ruleCard.height - z: held ? 2 : 1 - - Rectangle { - id: ruleCard - width: parent.width - height: ruleContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: ruleDelegateItem.liveRuleData.enabled !== false ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, 0.4) - - RowLayout { - id: ruleContent - anchors.fill: parent - anchors.margins: Theme.spacingM - anchors.leftMargin: 28 - spacing: Theme.spacingM - - ColumnLayout { - Layout.fillWidth: true - spacing: 2 - - StyledText { - text: ruleDelegateItem.displayName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: ruleDelegateItem.liveRuleData.enabled !== false ? Theme.surfaceText : Theme.surfaceVariantText - elide: Text.ElideRight - Layout.fillWidth: true - } - - StyledText { - text: { - const m = ruleDelegateItem.liveRuleData.matchCriteria || {}; - let parts = []; - if (m.appId) - parts.push(m.appId); - if (m.title) - parts.push("title: " + m.title); - return parts.length > 0 ? parts.join(" · ") : I18n.tr("No match criteria"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - Layout.fillWidth: true - } - - Flow { - Layout.fillWidth: true - Layout.topMargin: 4 - spacing: Theme.spacingXS - visible: { - const a = ruleDelegateItem.liveRuleData.actions || {}; - return Object.keys(a).some(k => a[k] !== undefined && a[k] !== null && a[k] !== ""); - } - - Repeater { - model: { - const a = ruleDelegateItem.liveRuleData.actions || {}; - const labels = { - "opacity": I18n.tr("Opacity"), - "openFloating": I18n.tr("Float"), - "openMaximized": I18n.tr("Maximize"), - "openMaximizedToEdges": I18n.tr("Max Edges"), - "openFullscreen": I18n.tr("Fullscreen"), - "openFocused": I18n.tr("Focus"), - "openOnOutput": I18n.tr("Output"), - "openOnWorkspace": I18n.tr("Workspace"), - "defaultColumnWidth": I18n.tr("Width"), - "defaultWindowHeight": I18n.tr("Height"), - "variableRefreshRate": I18n.tr("VRR"), - "blockOutFrom": I18n.tr("Block Out"), - "defaultColumnDisplay": I18n.tr("Display"), - "scrollFactor": I18n.tr("Scroll"), - "cornerRadius": I18n.tr("Radius"), - "clipToGeometry": I18n.tr("Clip"), - "tiledState": I18n.tr("Tiled"), - "minWidth": I18n.tr("Min W"), - "maxWidth": I18n.tr("Max W"), - "minHeight": I18n.tr("Min H"), - "maxHeight": I18n.tr("Max H"), - "tile": I18n.tr("Tile"), - "nofocus": I18n.tr("No Focus"), - "noborder": I18n.tr("No Border"), - "noshadow": I18n.tr("No Shadow"), - "nodim": I18n.tr("No Dim"), - "noblur": I18n.tr("No Blur"), - "noanim": I18n.tr("No Anim"), - "norounding": I18n.tr("No Round"), - "pin": I18n.tr("Pin"), - "opaque": I18n.tr("Opaque"), - "size": I18n.tr("Size"), - "move": I18n.tr("Move"), - "monitor": I18n.tr("Monitor"), - "workspace": I18n.tr("Workspace") - }; - return Object.keys(a).filter(k => a[k] !== undefined && a[k] !== null && a[k] !== "").map(k => { - const val = a[k]; - if (typeof val === "boolean") - return labels[k] || k; - return (labels[k] || k) + ": " + val; - }); - } - - delegate: Rectangle { - required property string modelData - width: chipText.implicitWidth + Theme.spacingS * 2 - height: 20 - radius: 10 - color: Theme.withAlpha(Theme.primary, 0.15) - - StyledText { - id: chipText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - } - } - - RowLayout { - Layout.alignment: Qt.AlignVCenter - spacing: 2 - - DankActionButton { - buttonSize: 28 - iconName: "edit" - iconSize: 16 - backgroundColor: "transparent" - iconColor: Theme.surfaceVariantText - onClicked: root.editRule(ruleDelegateItem.liveRuleData) - } - - DankActionButton { - id: deleteBtn - buttonSize: 28 - iconName: "delete" - iconSize: 16 - backgroundColor: "transparent" - iconColor: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.removeRule(ruleDelegateItem.ruleIdRef) - } - } - } - } - } - - MouseArea { - id: ruleDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: ruleCard.height - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: ruleDelegateItem.held ? ruleDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - ruleDelegateItem.z = 2; - ruleDelegateItem.originalY = ruleDelegateItem.y; - } - onReleased: { - ruleDelegateItem.z = 1; - if (!drag.active) { - ruleDelegateItem.y = ruleDelegateItem.originalY; - return; - } - const spacing = Theme.spacingXS; - const itemH = ruleDelegateItem.height + spacing; - var newIndex = Math.round(ruleDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, (root.windowRules?.length ?? 1) - 1)); - if (newIndex !== ruleDelegateItem.index) - root.reorderRules(ruleDelegateItem.index, newIndex); - ruleDelegateItem.y = ruleDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingM - 2 - y: (ruleCard.height / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: ruleDragArea.containsMouse || ruleDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !ruleDragArea.pressed && !ruleDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml deleted file mode 100644 index 99955fd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml +++ /dev/null @@ -1,526 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "view_module" - title: I18n.tr("Workspace Settings") - settingKey: "workspaceSettings" - - SettingsToggleRow { - settingKey: "showWorkspaceIndex" - tags: ["workspace", "index", "numbers", "labels"] - text: I18n.tr("Workspace Index Numbers") - description: I18n.tr("Show workspace index numbers in the top bar workspace switcher") - checked: SettingsData.showWorkspaceIndex - onToggled: checked => SettingsData.set("showWorkspaceIndex", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspaceName" - tags: ["workspace", "name", "labels"] - text: I18n.tr("Workspace Names") - description: I18n.tr("Show workspace name on horizontal bars, and first letter on vertical bars") - checked: SettingsData.showWorkspaceName - onToggled: checked => SettingsData.set("showWorkspaceName", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspacePadding" - tags: ["workspace", "padding", "minimum"] - text: I18n.tr("Workspace Padding") - description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available") - checked: SettingsData.showWorkspacePadding - onToggled: checked => SettingsData.set("showWorkspacePadding", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspaceApps" - tags: ["workspace", "apps", "icons", "applications"] - text: I18n.tr("Show Workspace Apps") - description: I18n.tr("Display application icons in workspace indicators") - checked: SettingsData.showWorkspaceApps - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("showWorkspaceApps", checked) - } - - Item { - width: parent.width - height: maxAppsColumn.height - visible: SettingsData.showWorkspaceApps - opacity: visible ? 1 : 0 - - Column { - id: maxAppsColumn - x: Theme.spacingL - width: 120 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max apps to show") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: 100 - height: 28 - placeholderText: "3" - text: SettingsData.maxWorkspaceIcons - maximumLength: 2 - font.pixelSize: Theme.fontSizeSmall - topPadding: Theme.spacingXS - bottomPadding: Theme.spacingXS - onEditingFinished: SettingsData.set("maxWorkspaceIcons", parseInt(text, 10)) - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - SettingsSliderRow { - visible: SettingsData.showWorkspaceApps - text: I18n.tr("Icon Size") - value: SettingsData.workspaceAppIconSizeOffset - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("workspaceAppIconSizeOffset", newValue) - } - - SettingsToggleRow { - settingKey: "groupWorkspaceApps" - tags: ["workspace", "apps", "icons", "group", "grouped", "collapse"] - text: I18n.tr("Group Workspace Apps") - description: I18n.tr("Group repeated application icons in unfocused workspaces") - checked: SettingsData.groupWorkspaceApps - visible: SettingsData.showWorkspaceApps - onToggled: checked => SettingsData.set("groupWorkspaceApps", checked) - } - - SettingsToggleRow { - settingKey: "workspaceActiveAppHighlightEnabled" - tags: ["workspace", "apps", "icons", "highlight", "active", "focused"] - text: I18n.tr("Highlight Active Workspace App") - description: I18n.tr("Highlight the currently focused app inside workspace indicators") - checked: SettingsData.workspaceActiveAppHighlightEnabled - visible: SettingsData.showWorkspaceApps - onToggled: checked => SettingsData.set("workspaceActiveAppHighlightEnabled", checked) - } - - SettingsToggleRow { - settingKey: "workspaceFollowFocus" - tags: ["workspace", "focus", "follow", "monitor"] - text: I18n.tr("Follow Monitor Focus") - description: I18n.tr("Show workspaces of the currently focused monitor") - checked: SettingsData.workspaceFollowFocus - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - onToggled: checked => SettingsData.set("workspaceFollowFocus", checked) - } - - SettingsToggleRow { - settingKey: "showOccupiedWorkspacesOnly" - tags: ["workspace", "occupied", "active", "windows"] - text: I18n.tr("Show Occupied Workspaces Only") - description: I18n.tr("Display only workspaces that contain windows") - checked: SettingsData.showOccupiedWorkspacesOnly - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("showOccupiedWorkspacesOnly", checked) - } - - SettingsToggleRow { - settingKey: "reverseScrolling" - tags: ["workspace", "scroll", "scrolling", "reverse", "direction"] - text: I18n.tr("Reverse Scrolling Direction") - description: I18n.tr("Reverse workspace switch direction when scrolling over the bar") - checked: SettingsData.reverseScrolling - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("reverseScrolling", checked) - } - - SettingsToggleRow { - settingKey: "workspaceDragReorder" - tags: ["workspace", "drag", "reorder", "sort", "move"] - text: I18n.tr("Drag to Reorder") - description: I18n.tr("Drag workspace indicators to reorder them") - checked: SettingsData.workspaceDragReorder - visible: CompositorService.isNiri - onToggled: checked => SettingsData.set("workspaceDragReorder", checked) - } - - SettingsToggleRow { - settingKey: "dwlShowAllTags" - tags: ["dwl", "tags", "workspace"] - text: I18n.tr("Show All Tags") - description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)") - checked: SettingsData.dwlShowAllTags - visible: CompositorService.isDwl - onToggled: checked => SettingsData.set("dwlShowAllTags", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "palette" - title: I18n.tr("Workspace Appearance") - settingKey: "workspaceAppearance" - - SettingsButtonGroupRow { - text: I18n.tr("Focused Color") - model: ["pri", "s", "sc", "sch", "none"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - case "none": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch", "none"]; - SettingsData.set("workspaceColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsButtonGroupRow { - text: I18n.tr("Occupied Color") - model: ["none", "sec", "s", "sc", "sch", "schh"] - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceOccupiedColorMode) { - case "sec": - return 1; - case "s": - return 2; - case "sc": - return 3; - case "sch": - return 4; - case "schh": - return 5; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["none", "sec", "s", "sc", "sch", "schh"]; - SettingsData.set("workspaceOccupiedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - } - - SettingsButtonGroupRow { - text: I18n.tr("Unfocused Color") - model: ["def", "s", "sc", "sch"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUnfocusedColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch"]; - SettingsData.set("workspaceUnfocusedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - } - - SettingsButtonGroupRow { - text: I18n.tr("Urgent Color") - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - model: ["err", "pri", "sec", "s", "sc"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUrgentColorMode) { - case "primary": - return 1; - case "secondary": - return 2; - case "s": - return 3; - case "sc": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "primary", "secondary", "s", "sc"]; - SettingsData.set("workspaceUrgentColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - settingKey: "workspaceFocusedBorderEnabled" - tags: ["workspace", "border", "outline", "focused", "ring"] - text: I18n.tr("Focused Border") - description: I18n.tr("Show an outline ring around the focused workspace indicator") - checked: SettingsData.workspaceFocusedBorderEnabled - onToggled: checked => SettingsData.set("workspaceFocusedBorderEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.workspaceFocusedBorderEnabled - leftPadding: Theme.spacingM - - SettingsButtonGroupRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Border Color") - model: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")] - currentIndex: { - switch (SettingsData.workspaceFocusedBorderColor) { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "primary"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.set("workspaceFocusedBorderColor", newColor); - } - } - - SettingsSliderRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Thickness") - value: SettingsData.workspaceFocusedBorderThickness - minimum: 1 - maximum: 6 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("workspaceFocusedBorderThickness", newValue) - } - } - } - - SettingsCard { - width: parent.width - iconName: "label" - title: I18n.tr("Named Workspace Icons") - settingKey: "workspaceIcons" - visible: SettingsData.hasNamedWorkspaces() - - StyledText { - width: parent.width - text: I18n.tr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - Repeater { - model: SettingsData.getNamedWorkspaces() - - Rectangle { - width: parent.width - height: workspaceIconRow.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.5) - border.width: 0 - - Row { - id: workspaceIconRow - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: "\"" + modelData + "\"" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 150 - elide: Text.ElideRight - } - - DankIconPicker { - id: iconPicker - anchors.verticalCenter: parent.verticalCenter - - Component.onCompleted: { - var iconData = SettingsData.getWorkspaceNameIcon(modelData); - if (iconData) { - setIcon(iconData.value, iconData.type); - } - } - - onIconSelected: (iconName, iconType) => { - SettingsData.setWorkspaceNameIcon(modelData, { - "type": iconType, - "value": iconName - }); - setIcon(iconName, iconType); - } - - Connections { - target: SettingsData - function onWorkspaceIconsUpdated() { - var iconData = SettingsData.getWorkspaceNameIcon(modelData); - if (iconData) { - iconPicker.setIcon(iconData.value, iconData.type); - } else { - iconPicker.setIcon("", "icon"); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer - border.width: 0 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "close" - size: 16 - color: clearMouseArea.containsMouse ? Theme.error : Theme.outline - anchors.centerIn: parent - } - - MouseArea { - id: clearMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeWorkspaceNameIcon(modelData) - } - } - - Item { - width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4 - height: 1 - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml deleted file mode 100644 index 49cdb93..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml +++ /dev/null @@ -1,329 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: systemUpdatePopout - - layerNamespace: "dms:system-update" - - property var parentWidget: null - property var triggerScreen: null - - Ref { - service: SystemUpdateService - } - - popupWidth: 400 - popupHeight: 500 - triggerWidth: 55 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: close() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - if (SystemUpdateService.updateCount === 0 && !SystemUpdateService.isChecking) { - SystemUpdateService.checkForUpdates(); - } - } - } - - content: Component { - Rectangle { - id: updaterPanel - - color: "transparent" - - Column { - width: parent.width - Theme.spacingL * 2 - height: parent.height - Theme.spacingL * 2 - x: Theme.spacingL - y: Theme.spacingL - spacing: Theme.spacingL - - Item { - width: parent.width - height: 40 - - StyledText { - text: I18n.tr("System Updates") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: { - if (SystemUpdateService.isChecking) - return I18n.tr("Checking..."); - if (SystemUpdateService.hasError) - return I18n.tr("Error"); - if (SystemUpdateService.updateCount === 0) - return I18n.tr("Up to date"); - return SystemUpdateService.updateCount === 1 - ? I18n.tr("%1 update").arg(SystemUpdateService.updateCount) - : I18n.tr("%1 updates").arg(SystemUpdateService.updateCount); - } - font.pixelSize: Theme.fontSizeMedium - color: { - if (SystemUpdateService.hasError) - return Theme.error; - return Theme.surfaceText; - } - } - - DankActionButton { - id: checkForUpdatesButton - buttonSize: 28 - iconName: "refresh" - iconSize: 18 - z: 15 - iconColor: Theme.surfaceText - enabled: !SystemUpdateService.isChecking - opacity: enabled ? 1.0 : 0.5 - onClicked: { - SystemUpdateService.checkForUpdates(); - } - - RotationAnimation { - target: checkForUpdatesButton - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: SystemUpdateService.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - checkForUpdatesButton.rotation = 0; - } - } - } - } - } - } - - Rectangle { - width: parent.width - height: { - let usedHeight = 40 + Theme.spacingL; - usedHeight += 48 + Theme.spacingL; - return parent.height - usedHeight; - } - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 0 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - anchors.rightMargin: 0 - - StyledText { - id: statusText - width: parent.width - text: { - if (SystemUpdateService.hasError) { - return I18n.tr("Failed to check for updates:\n%1").arg(SystemUpdateService.errorMessage); - } - if (!SystemUpdateService.helperAvailable) { - return I18n.tr("No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates."); - } - if (SystemUpdateService.isChecking) { - return I18n.tr("Checking for updates..."); - } - if (SystemUpdateService.updateCount === 0) { - return I18n.tr("Your system is up to date!"); - } - return SystemUpdateService.updateCount === 1 - ? I18n.tr("Found %1 package to update:").arg(SystemUpdateService.updateCount) - : I18n.tr("Found %1 packages to update:").arg(SystemUpdateService.updateCount); - } - font.pixelSize: Theme.fontSizeMedium - color: { - if (SystemUpdateService.hasError) - return Theme.errorText; - return Theme.surfaceText; - } - wrapMode: Text.WordWrap - visible: SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking - } - - DankListView { - id: packagesList - - width: parent.width - height: parent.height - (SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking ? statusText.height + Theme.spacingM : 0) - visible: SystemUpdateService.updateCount > 0 && !SystemUpdateService.isChecking && !SystemUpdateService.hasError - clip: true - spacing: Theme.spacingXS - - model: SystemUpdateService.availableUpdates - - delegate: Rectangle { - width: ListView.view.width - Theme.spacingM - height: 48 - radius: Theme.cornerRadius - color: packageMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent" - border.color: Theme.outlineLight - border.width: 0 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.spacingM - spacing: 2 - - StyledText { - width: parent.width - text: modelData.name || "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - } - - StyledText { - width: parent.width - text: `${modelData.currentVersion} → ${modelData.newVersion}` - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - } - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - MouseArea { - id: packageMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - } - } - } - } - } - - Row { - width: parent.width - height: 48 - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: parent.height - radius: Theme.cornerRadius - color: updateMouseArea.containsMouse ? Theme.primaryHover : Theme.secondaryHover - opacity: SystemUpdateService.updateCount > 0 ? 1.0 : 0.5 - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "system_update_alt" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Update All") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: updateMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: SystemUpdateService.updateCount > 0 - onClicked: { - SystemUpdateService.runUpdates(); - systemUpdatePopout.close(); - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: parent.height - radius: Theme.cornerRadius - color: closeMouseArea.containsMouse ? Theme.errorPressed : Theme.secondaryHover - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "close" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - systemUpdatePopout.close(); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml deleted file mode 100644 index 2d1356e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml +++ /dev/null @@ -1,444 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WlrLayershell.namespace: "dms:toast" - - property var modelData - property bool shouldBeVisible: false - property real frozenWidth: 0 - readonly property string copiedText: I18n.tr("Copied!") - - readonly property real dpr: modelData ? CompositorService.getScreenScale(modelData) : 1 - readonly property real shadowBuffer: 5 - readonly property real toastY: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2 - - Connections { - target: ToastService - function onToastVisibleChanged() { - if (ToastService.toastVisible) { - shouldBeVisible = true; - visible = true; - } else { - frozenWidth = toast.width; - shouldBeVisible = false; - closeTimer.restart(); - } - } - } - - Timer { - id: closeTimer - interval: Theme.mediumDuration + 50 - onTriggered: { - if (!shouldBeVisible) { - visible = false; - } - } - } - - screen: modelData - visible: shouldBeVisible - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - - readonly property real toastWidth: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth - readonly property real toastHeight: toastContent.height + Theme.spacingL * 2 - - anchors { - top: true - left: true - } - - WlrLayershell.margins { - left: Math.max(0, Theme.snap((modelData?.width ?? 1920) / 2 - toastWidth / 2 - shadowBuffer, dpr)) - top: Math.max(0, Theme.snap(toastY - shadowBuffer, dpr)) - } - - implicitWidth: toastWidth + (shadowBuffer * 2) - implicitHeight: toastHeight + (shadowBuffer * 2) - - Rectangle { - id: toast - - property bool expanded: false - - Connections { - target: ToastService - function onResetToastState() { - toast.expanded = false; - } - } - - x: shadowBuffer - y: shadowBuffer - width: root.toastWidth - height: root.toastHeight - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - return Theme.error; - case ToastService.levelWarn: - return Theme.warning; - case ToastService.levelInfo: - return Theme.surfaceContainer; - default: - return Theme.surfaceContainer; - } - } - radius: Theme.cornerRadius - opacity: shouldBeVisible ? 1 : 0 - - Column { - id: toastContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Theme.spacingL - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(Theme.iconSize + 8, messageText.implicitHeight) - - DankIcon { - id: statusIcon - name: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - return "error"; - case ToastService.levelWarn: - return "warning"; - case ToastService.levelInfo: - return "info"; - default: - return "info"; - } - } - size: Theme.iconSize - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: messageText - text: ToastService.currentMessage - font.pixelSize: Theme.fontSizeMedium - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - font.weight: Font.Medium - anchors.left: statusIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: ToastService.hasDetails ? expandButton.left : parent.right - anchors.rightMargin: ToastService.hasDetails ? Theme.spacingS : 0 - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankActionButton { - id: expandButton - iconName: toast.expanded ? "expand_less" : "expand_more" - iconSize: Theme.iconSize - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSize + 8 - anchors.right: closeButton.left - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - visible: ToastService.hasDetails - - onClicked: { - toast.expanded = !toast.expanded; - if (toast.expanded) { - ToastService.stopTimer(); - } else { - ToastService.restartTimer(); - } - } - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSize + 8 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: ToastService.hasDetails || ToastService.currentLevel === ToastService.levelError - - onClicked: { - ToastService.hideToast(); - } - } - } - - Rectangle { - width: parent.width - height: detailsColumn.height + Theme.spacingS * 2 - color: ToastService.currentDetails.length > 0 ? Qt.rgba(0, 0, 0, 0.2) : "transparent" - radius: Theme.cornerRadius / 2 - visible: toast.expanded && ToastService.hasDetails - anchors.horizontalCenter: parent.horizontalCenter - - Column { - id: detailsColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Item { - width: parent.width - Theme.spacingS * 2 - height: detailsText.implicitHeight - anchors.horizontalCenter: parent.horizontalCenter - visible: ToastService.currentDetails.length > 0 - - StyledText { - id: detailsText - text: ToastService.currentDetails - font.pixelSize: Theme.fontSizeSmall - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - anchors.left: parent.left - anchors.right: copyDetailsButton.left - anchors.rightMargin: Theme.spacingS - wrapMode: Text.Wrap - } - - DankActionButton { - id: copyDetailsButton - iconName: "content_copy" - iconSize: Theme.iconSizeSmall - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSizeSmall + 8 - anchors.right: parent.right - anchors.top: parent.top - - property bool showTooltip: false - - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", ToastService.currentDetails]); - showTooltip = true; - detailsTooltipTimer.start(); - } - - Timer { - id: detailsTooltipTimer - interval: 1500 - onTriggered: copyDetailsButton.showTooltip = false - } - - Rectangle { - visible: copyDetailsButton.showTooltip - width: detailsTooltipLabel.implicitWidth + 16 - height: detailsTooltipLabel.implicitHeight + 8 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - y: -height - 4 - x: -width / 2 + copyDetailsButton.width / 2 - - StyledText { - id: detailsTooltipLabel - anchors.centerIn: parent - text: root.copiedText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - } - } - - Rectangle { - width: parent.width - Theme.spacingS * 2 - height: commandText.height + Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(0, 0, 0, 0.3) - radius: Theme.cornerRadius / 2 - visible: ToastService.currentCommand.length > 0 - - StyledText { - id: commandText - text: ToastService.currentCommand - font.pixelSize: Theme.fontSizeSmall - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - isMonospace: true - anchors.left: parent.left - anchors.right: copyButton.visible ? copyButton.left : parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingS / 2 - anchors.rightMargin: Theme.spacingS / 2 - wrapMode: Text.Wrap - } - - DankActionButton { - id: copyButton - iconName: "content_copy" - iconSize: Theme.iconSizeSmall - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSizeSmall + 8 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingS / 2 - visible: ToastService.currentCommand.length > 0 - - property bool showTooltip: false - - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", ToastService.currentCommand]); - showTooltip = true; - tooltipTimer.start(); - } - - Timer { - id: tooltipTimer - interval: 1500 - onTriggered: copyButton.showTooltip = false - } - - Rectangle { - visible: copyButton.showTooltip - width: tooltipLabel.implicitWidth + 16 - height: tooltipLabel.implicitHeight + 8 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - y: -height - 4 - x: -width / 2 + copyButton.width / 2 - - StyledText { - id: tooltipLabel - anchors.centerIn: parent - text: root.copiedText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - } - } - } - } - } - - MouseArea { - anchors.fill: parent - visible: !ToastService.hasDetails - onClicked: ToastService.hideToast() - } - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel3 - fallbackOffset: 6 - targetRadius: toast.radius - targetColor: toast.color - shadowOpacity: Theme.elevationLevel3 && Theme.elevationLevel3.alpha !== undefined ? Theme.elevationLevel3.alpha : 0.3 - shadowEnabled: Theme.elevationEnabled - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: false - } - - Behavior on width { - enabled: false - } - } - - mask: Region { - item: toast - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml deleted file mode 100644 index 8430b01..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml +++ /dev/null @@ -1,658 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Widgets -import qs.Services - -Variants { - model: { - if (SessionData.isGreeterMode) { - return Quickshell.screens; - } - return SettingsData.getFilteredScreens("wallpaper"); - } - - PanelWindow { - id: wallpaperWindow - - required property var modelData - - screen: modelData - - WlrLayershell.layer: WlrLayer.Background - WlrLayershell.exclusionMode: ExclusionMode.Ignore - - anchors.top: true - anchors.bottom: true - anchors.left: true - anchors.right: true - - color: "transparent" - - mask: Region { - item: Item {} - } - - Item { - id: root - anchors.fill: parent - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string source: SessionData.getMonitorWallpaper(modelData.name) || "" - property bool isColorSource: source.startsWith("#") - property string transitionType: SessionData.wallpaperTransition - property string actualTransitionType: transitionType - property bool isInitialized: false - - Connections { - target: SessionData - function onIsLightModeChanged() { - if (SessionData.perModeWallpaper) { - var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""; - if (newSource !== root.source) { - root.source = newSource; - } - } - } - } - onTransitionTypeChanged: { - if (transitionType !== "random") { - actualTransitionType = transitionType; - return; - } - actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)]; - } - - property real transitionProgress: 0 - property real shaderFillMode: getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - property vector4d fillColor: Qt.vector4d(0, 0, 0, 1) - property real edgeSmoothness: 0.1 - - property real wipeDirection: 0 - property real discCenterX: 0.5 - property real discCenterY: 0.5 - property real stripesCount: 16 - property real stripesAngle: 0 - - readonly property bool transitioning: transitionAnimation.running - property bool effectActive: false - property bool _renderSettling: true - property bool _overviewBlurSettling: false - property bool useNextForEffect: false - property string pendingWallpaper: "" - property string _deferredSource: "" - readonly property bool overviewBlurActive: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && currentWallpaper.source !== "" - - Connections { - target: currentWallpaper - function onStatusChanged() { - if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) - return; - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - function _recheckScreenScale() { - const newScale = CompositorService.getScreenScale(modelData); - if (newScale !== root.screenScale) { - console.info("WallpaperBackground: screen scale corrected for", modelData.name + ":", root.screenScale, "->", newScale); - root.screenScale = newScale; - } - } - - Connections { - target: wallpaperWindow - function onWidthChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - function onHeightChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: NiriService - function onDisplayScalesChanged() { - root._recheckScreenScale(); - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: WlrOutputService - function onWlrOutputAvailableChanged() { - root._recheckScreenScale(); - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: NiriService - function onInOverviewChanged() { - root._overviewBlurSettling = true; - overviewBlurSettleTimer.restart(); - } - } - - Connections { - target: SettingsData - function onBlurWallpaperOnOverviewChanged() { - root._overviewBlurSettling = true; - overviewBlurSettleTimer.restart(); - } - } - - Connections { - target: CompositorService - function onRandrDataReady() { - if (root._deferredSource) { - const src = root._deferredSource; - root._deferredSource = ""; - root.setWallpaperImmediate(src); - } else { - root._recheckScreenScale(); - } - } - } - - Connections { - target: IdleService - function onIsShellLockedChanged() { - if (!IdleService.isShellLocked) { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - } - - Timer { - id: renderSettleTimer - interval: 1000 - onTriggered: root._renderSettling = false - } - - Timer { - id: overviewBlurSettleTimer - interval: 150 - onTriggered: root._overviewBlurSettling = false - } - - function getFillMode(modeName) { - switch (modeName) { - case "Stretch": - return Image.Stretch; - case "Fit": - case "PreserveAspectFit": - return Image.PreserveAspectFit; - case "Fill": - case "PreserveAspectCrop": - return Image.PreserveAspectCrop; - case "Tile": - return Image.Tile; - case "TileVertically": - return Image.TileVertically; - case "TileHorizontally": - return Image.TileHorizontally; - case "Pad": - return Image.Pad; - default: - return Image.PreserveAspectCrop; - } - } - - Component.onCompleted: { - if (typeof wallpaperWindow.updatesEnabled !== "undefined") - wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || root.overviewBlurActive || root._overviewBlurSettling || root.pendingWallpaper !== "" || root._deferredSource !== "" || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading); - - if (!source) { - root._renderSettling = false; - } - isInitialized = true; - } - - onSourceChanged: { - if (!source || source.startsWith("#")) { - setWallpaperImmediate(""); - return; - } - - const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source); - - if (!isInitialized || !currentWallpaper.source) { - if (!CompositorService.randrReady) { - _deferredSource = formattedSource; - return; - } - setWallpaperImmediate(formattedSource); - return; - } - if (CompositorService.isNiri && SessionData.isSwitchingMode) { - setWallpaperImmediate(formattedSource); - return; - } - changeWallpaper(formattedSource); - } - - function setWallpaperImmediate(newSource) { - transitionAnimation.stop(); - root.transitionProgress = 0.0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - root.screenScale = CompositorService.getScreenScale(modelData); - currentWallpaper.source = newSource; - nextWallpaper.source = ""; - } - - function startTransition() { - currentWallpaper.layer.enabled = true; - nextWallpaper.layer.enabled = true; - root.useNextForEffect = true; - root.effectActive = true; - if (srcCurrent.scheduleUpdate) - srcCurrent.scheduleUpdate(); - if (srcNext.scheduleUpdate) - srcNext.scheduleUpdate(); - transitionDelayTimer.start(); - } - - Timer { - id: transitionDelayTimer - interval: 16 - repeat: false - onTriggered: transitionAnimation.start() - } - - function changeWallpaper(newPath, force) { - if (!force && newPath === currentWallpaper.source) - return; - if (!newPath || newPath.startsWith("#")) - return; - root.screenScale = CompositorService.getScreenScale(modelData); - if (root.transitioning || root.effectActive) { - root.pendingWallpaper = newPath; - return; - } - if (!currentWallpaper.source) { - setWallpaperImmediate(newPath); - return; - } - - if (root.transitionType === "random") { - root.actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)]; - } - - if (root.actualTransitionType === "none") { - setWallpaperImmediate(newPath); - return; - } - - switch (root.actualTransitionType) { - case "wipe": - root.wipeDirection = Math.random() * 4; - break; - case "disc": - case "pixelate": - case "portal": - root.discCenterX = Math.random(); - root.discCenterY = Math.random(); - break; - case "stripes": - root.stripesCount = Math.round(Math.random() * 20 + 4); - root.stripesAngle = Math.random() * 360; - break; - } - - root._renderSettling = true; - renderSettleTimer.restart(); - - nextWallpaper.source = newPath; - - if (nextWallpaper.status === Image.Ready) - root.startTransition(); - } - - Loader { - anchors.fill: parent - active: !root.source || root.isColorSource - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: modelData.name - } - } - - readonly property int maxTextureSize: 8192 - property real screenScale: 1 - property int textureWidth: Math.min(Math.round(modelData.width * screenScale), maxTextureSize) - property int textureHeight: Math.min(Math.round(modelData.height * screenScale), maxTextureSize) - - Image { - id: currentWallpaper - anchors.fill: parent - visible: true - opacity: 1 - layer.enabled: false - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - } - - Image { - id: nextWallpaper - anchors.fill: parent - visible: source !== "" - opacity: 0 - layer.enabled: false - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - - onStatusChanged: { - if (status !== Image.Ready) - return; - if (root.actualTransitionType === "none") { - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = source; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - } else if (!root.transitioning) { - root.startTransition(); - } - } - } - - ShaderEffectSource { - id: srcCurrent - sourceItem: root.effectActive ? currentWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - ShaderEffectSource { - id: srcNext - sourceItem: root.effectActive ? nextWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - Rectangle { - id: dummyRect - width: 1 - height: 1 - visible: false - color: "transparent" - } - - ShaderEffectSource { - id: srcDummy - sourceItem: dummyRect - hideSource: true - live: false - mipmap: false - recursive: false - } - - Loader { - id: effectLoader - anchors.fill: parent - active: root.effectActive - - function getTransitionComponent(type) { - switch (type) { - case "fade": - return fadeComp; - case "wipe": - return wipeComp; - case "disc": - return discComp; - case "stripes": - return stripesComp; - case "iris bloom": - return irisComp; - case "pixelate": - return pixelateComp; - case "portal": - return portalComp; - default: - return null; - } - } - - sourceComponent: getTransitionComponent(root.actualTransitionType) - } - - Component { - id: fadeComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_fade.frag.qsb") - } - } - - Component { - id: wipeComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real direction: root.wipeDirection - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_wipe.frag.qsb") - } - } - - Component { - id: discComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_disc.frag.qsb") - } - } - - Component { - id: stripesComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real stripeCount: root.stripesCount - property real angle: root.stripesAngle - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_stripes.frag.qsb") - } - } - - Component { - id: irisComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real centerX: 0.5 - property real centerY: 0.5 - property real aspectRatio: root.width / root.height - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_iris_bloom.frag.qsb") - } - } - - Component { - id: pixelateComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real aspectRatio: root.width / root.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_pixelate.frag.qsb") - } - } - - Component { - id: portalComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_portal.frag.qsb") - } - } - - NumberAnimation { - id: transitionAnimation - target: root - property: "transitionProgress" - from: 0.0 - to: 1.0 - duration: root.actualTransitionType === "none" ? 0 : 1000 - easing.type: Easing.InOutCubic - onFinished: { - if (nextWallpaper.source && nextWallpaper.status === Image.Ready) { - currentWallpaper.source = nextWallpaper.source; - } - root.useNextForEffect = false; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - currentWallpaper.layer.enabled = false; - nextWallpaper.layer.enabled = false; - root._renderSettling = true; - renderSettleTimer.restart(); - root.effectActive = false; - - if (!root.pendingWallpaper) - return; - var pending = root.pendingWallpaper; - root.pendingWallpaper = ""; - Qt.callLater(() => root.changeWallpaper(pending, true)); - } - } - - Loader { - id: overviewBlurLoader - anchors.fill: parent - active: root.overviewBlurActive - - sourceComponent: MultiEffect { - anchors.fill: parent - source: effectLoader.active ? effectLoader.item : currentWallpaper - blurEnabled: true - blur: 0.8 - blurMax: 75 - autoPaddingEnabled: false - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml deleted file mode 100644 index 1933035..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml +++ /dev/null @@ -1,291 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Services - -Scope { - id: overviewScope - - property bool overviewOpen: false - - Loader { - id: hyprlandLoader - active: overviewScope.overviewOpen - asynchronous: false - - sourceComponent: Variants { - id: overviewVariants - model: Quickshell.screens - - PanelWindow { - id: root - required property var modelData - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen) - property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id) - - screen: modelData - visible: overviewScope.overviewOpen - color: "transparent" - - WlrLayershell.namespace: "dms:workspace-overview" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!overviewScope.overviewOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - HyprlandFocusGrab { - id: grab - windows: [root] - active: false - property bool hasBeenActivated: false - onActiveChanged: { - if (active) { - hasBeenActivated = true - } - } - onCleared: () => { - if (hasBeenActivated && overviewScope.overviewOpen) { - overviewScope.overviewOpen = false - } - } - } - - Connections { - target: overviewScope - function onOverviewOpenChanged() { - if (overviewScope.overviewOpen) { - grab.hasBeenActivated = false - if (CompositorService.useHyprlandFocusGrab) - delayedGrabTimer.start() - } else { - delayedGrabTimer.stop() - grab.active = false - grab.hasBeenActivated = false - } - } - } - - Connections { - target: root - function onMonitorIsFocusedChanged() { - if (!CompositorService.useHyprlandFocusGrab) - return; - if (overviewScope.overviewOpen && root.monitorIsFocused && !grab.active) { - grab.hasBeenActivated = false - grab.active = true - } else if (overviewScope.overviewOpen && !root.monitorIsFocused && grab.active) { - grab.active = false - } - } - } - - Timer { - id: delayedGrabTimer - interval: 150 - repeat: false - onTriggered: { - if (CompositorService.useHyprlandFocusGrab && overviewScope.overviewOpen && root.monitorIsFocused) { - grab.active = true - } - } - } - - Timer { - id: closeTimer - interval: Theme.expressiveDurations.expressiveDefaultSpatial + 120 - onTriggered: { - root.visible = false - } - } - - Rectangle { - id: background - anchors.fill: parent - color: "black" - opacity: overviewScope.overviewOpen ? 0.5 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - MouseArea { - anchors.fill: parent - onClicked: mouse => { - const localPos = mapToItem(contentContainer, mouse.x, mouse.y) - if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) { - overviewScope.overviewOpen = false - closeTimer.restart() - } - } - } - } - - Item { - id: contentContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 100 - width: childrenRect.width - height: childrenRect.height - - opacity: overviewScope.overviewOpen ? 1 : 0 - transform: [scaleTransform, motionTransform] - - Scale { - id: scaleTransform - origin.x: contentContainer.width / 2 - origin.y: contentContainer.height / 2 - xScale: overviewScope.overviewOpen ? 1 : 0.96 - yScale: overviewScope.overviewOpen ? 1 : 0.96 - - Behavior on xScale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - Behavior on yScale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - } - - Translate { - id: motionTransform - x: 0 - y: overviewScope.overviewOpen ? 0 : Theme.spacingL - - Behavior on y { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - Loader { - id: overviewLoader - active: overviewScope.overviewOpen - asynchronous: false - - sourceComponent: OverviewWidget { - panelWindow: root - overviewOpen: overviewScope.overviewOpen - } - } - } - - FocusScope { - id: focusScope - anchors.fill: parent - visible: overviewScope.overviewOpen - focus: overviewScope.overviewOpen && root.monitorIsFocused - - Keys.onEscapePressed: event => { - if (!root.monitorIsFocused) return - overviewScope.overviewOpen = false - closeTimer.restart() - event.accepted = true - } - - Keys.onPressed: event => { - if (!root.monitorIsFocused) return - - if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) { - if (!overviewLoader.item) return - - const thisMonitorWorkspaceIds = overviewLoader.item.thisMonitorWorkspaceIds - if (thisMonitorWorkspaceIds.length === 0) return - - const currentId = root.monitor.activeWorkspace?.id ?? thisMonitorWorkspaceIds[0] - const currentIndex = thisMonitorWorkspaceIds.indexOf(currentId) - - let targetIndex - if (event.key === Qt.Key_Left) { - targetIndex = currentIndex - 1 - if (targetIndex < 0) targetIndex = thisMonitorWorkspaceIds.length - 1 - } else { - targetIndex = currentIndex + 1 - if (targetIndex >= thisMonitorWorkspaceIds.length) targetIndex = 0 - } - - const targetId = thisMonitorWorkspaceIds[targetIndex] - Hyprland.dispatch("workspace " + targetId) - event.accepted = true - } - } - - onVisibleChanged: { - if (visible && overviewScope.overviewOpen && root.monitorIsFocused) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } - } - - Connections { - target: root - function onMonitorIsFocusedChanged() { - if (root.monitorIsFocused && overviewScope.overviewOpen) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } - } - } - } - - onVisibleChanged: { - if (visible && overviewScope.overviewOpen) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } else if (!visible) { - grab.active = false - } - } - - Connections { - target: overviewScope - function onOverviewOpenChanged() { - if (overviewScope.overviewOpen) { - closeTimer.stop() - root.visible = true - Qt.callLater(() => focusScope.forceActiveFocus()) - } else { - closeTimer.restart() - grab.active = false - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml deleted file mode 100644 index c7b1bf7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ /dev/null @@ -1,322 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Modals.DankLauncherV2 -import qs.Services - -Scope { - id: niriOverviewScope - - property bool searchActive: false - property string searchActiveScreen: "" - property bool isClosing: false - property bool releaseKeyboard: false - readonly property bool spotlightModalOpen: PopoutService.dankLauncherV2Modal?.spotlightOpen ?? false - property bool overlayActive: NiriService.inOverview || searchActive - - function showSpotlight(screenName) { - isClosing = false; - releaseKeyboard = false; - searchActive = true; - searchActiveScreen = screenName; - } - - function hideSpotlight() { - if (!searchActive) - return; - isClosing = true; - } - - function hideAndReleaseKeyboard() { - releaseKeyboard = true; - hideSpotlight(); - } - - function resetState() { - searchActive = false; - searchActiveScreen = ""; - isClosing = false; - releaseKeyboard = false; - } - - Connections { - target: NiriService - function onInOverviewChanged() { - if (NiriService.inOverview) { - resetState(); - return; - } - if (!searchActive) { - resetState(); - return; - } - isClosing = true; - } - - function onCurrentOutputChanged() { - if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput) - return; - hideSpotlight(); - } - } - - onSpotlightModalOpenChanged: { - if (spotlightModalOpen && searchActive) - hideSpotlight(); - } - - Loader { - id: niriOverlayLoader - active: overlayActive || isClosing - asynchronous: false - sourceComponent: Variants { - id: overlayVariants - model: Quickshell.screens - - PanelWindow { - id: overlayWindow - required property var modelData - - readonly property real dpr: CompositorService.getScreenScale(screen) - readonly property bool isActiveScreen: screen.name === NiriService.currentOutput - readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing - readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen - readonly property bool overlayVisible: NiriService.inOverview || niriOverviewScope.isClosing - property bool hasActivePopout: !!PopoutManager.currentPopoutsByScreen[screen.name] - property bool hasActiveModal: !!ModalManager.currentModalsByScreen[screen.name] - - Connections { - target: PopoutManager - function onPopoutChanged() { - overlayWindow.hasActivePopout = !!PopoutManager.currentPopoutsByScreen[overlayWindow.screen.name]; - } - } - - Connections { - target: ModalManager - function onModalChanged() { - overlayWindow.hasActiveModal = !!ModalManager.currentModalsByScreen[overlayWindow.screen.name]; - } - } - - screen: modelData - visible: overlayVisible - color: "transparent" - - WlrLayershell.namespace: "dms:niri-overview-spotlight" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!NiriService.inOverview) - return WlrKeyboardFocus.None; - if (!isActiveScreen) - return WlrKeyboardFocus.None; - if (niriOverviewScope.releaseKeyboard) - return WlrKeyboardFocus.None; - if (hasActivePopout || hasActiveModal) - return WlrKeyboardFocus.None; - return WlrKeyboardFocus.Exclusive; - } - - mask: Region { - item: overlayVisible && spotlightContainer.visible ? spotlightContainer : null - } - - onShouldShowSpotlightChanged: { - if (shouldShowSpotlight) { - if (launcherContent?.controller) { - launcherContent.controller.searchMode = SessionData.niriOverviewLastMode || "apps"; - launcherContent.controller.performSearch(); - } - return; - } - if (!isActiveScreen) - return; - Qt.callLater(() => keyboardFocusScope.forceActiveFocus()); - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - FocusScope { - id: keyboardFocusScope - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing) - return; - if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) { - NiriService.toggleOverview(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Left) { - NiriService.moveColumnLeft(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Right) { - NiriService.moveColumnRight(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Up) { - NiriService.moveWorkspaceUp(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Down) { - NiriService.moveWorkspaceDown(); - event.accepted = true; - return; - } - - if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) { - event.accepted = false; - return; - } - - if (event.isAutoRepeat || !event.text) - return; - if (!launcherContent?.searchField) - return; - const trimmedText = event.text.trim(); - launcherContent.searchField.text = trimmedText; - launcherContent.controller.setSearchQuery(trimmedText); - niriOverviewScope.showSpotlight(overlayWindow.screen.name); - Qt.callLater(() => launcherContent.searchField.forceActiveFocus()); - event.accepted = true; - } - } - - Item { - id: spotlightContainer - x: Theme.snap((parent.width - width) / 2, overlayWindow.dpr) - y: Theme.snap((parent.height - height) / 2, overlayWindow.dpr) - - readonly property int baseWidth: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 500; - case "medium": - return 720; - case "large": - return 860; - default: - return 620; - } - } - readonly property int baseHeight: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 480; - case "medium": - return 720; - case "large": - return 860; - default: - return 600; - } - } - width: Math.min(baseWidth, overlayWindow.screen.width - 100) - height: Math.min(baseHeight, overlayWindow.screen.height - 100) - - readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen - - scale: overlayWindow.shouldShowSpotlight ? 1.0 : 0.96 - opacity: overlayWindow.shouldShowSpotlight ? 1 : 0 - visible: overlayWindow.shouldShowSpotlight || animatingOut - enabled: overlayWindow.shouldShowSpotlight - - layer.enabled: visible - layer.smooth: false - layer.textureSize: layer.enabled ? Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr)) : Qt.size(0, 0) - - Behavior on scale { - id: scaleAnimation - NumberAnimation { - duration: Theme.expressiveDurations.fast - easing.type: Easing.BezierSpline - easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveFastSpatial : Theme.expressiveCurves.standardAccel - onRunningChanged: { - if (running || !spotlightContainer.animatingOut) - return; - niriOverviewScope.resetState(); - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.fast - easing.type: Easing.BezierSpline - easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveFastSpatial : Theme.expressiveCurves.standardAccel - } - } - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Theme.outlineMedium - border.width: 1 - } - - LauncherContent { - id: launcherContent - anchors.fill: parent - anchors.margins: 0 - - property var fakeParentModal: QtObject { - property bool spotlightOpen: spotlightContainer.visible - property bool isClosing: niriOverviewScope.isClosing - function hide() { - if (niriOverviewScope.searchActive) { - niriOverviewScope.hideSpotlight(); - return; - } - NiriService.toggleOverview(); - } - } - - Connections { - target: launcherContent.searchField - function onTextChanged() { - if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive) - return; - niriOverviewScope.hideSpotlight(); - } - } - - Component.onCompleted: { - parentModal = fakeParentModal; - } - - Connections { - target: launcherContent.controller - function onItemExecuted() { - niriOverviewScope.releaseKeyboard = true; - } - function onModeChanged(mode) { - if (launcherContent.controller.autoSwitchedToFiles) - return; - SessionData.setNiriOverviewLastMode(mode); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml deleted file mode 100644 index 03d39fb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml +++ /dev/null @@ -1,443 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - required property var panelWindow - required property bool overviewOpen - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen) - readonly property real dpr: CompositorService.getScreenScale(panelWindow.screen) - readonly property int workspacesShown: SettingsData.overviewRows * SettingsData.overviewColumns - - readonly property var allWorkspaces: Hyprland.workspaces?.values || [] - readonly property var allWorkspaceIds: { - const workspaces = allWorkspaces; - if (!workspaces || workspaces.length === 0) - return []; - try { - const ids = workspaces.map(ws => ws?.id).filter(id => id !== null && id !== undefined); - return ids.sort((a, b) => a - b); - } catch (e) { - return []; - } - } - - readonly property var thisMonitorWorkspaceIds: { - const workspaces = allWorkspaces; - const mon = monitor; - if (!workspaces || workspaces.length === 0 || !mon) - return []; - try { - const filtered = workspaces.filter(ws => ws?.monitor?.name === mon.name); - return filtered.map(ws => ws?.id).filter(id => id !== null && id !== undefined).sort((a, b) => a - b); - } catch (e) { - return []; - } - } - - readonly property var displayedWorkspaceIds: { - if (!allWorkspaceIds || allWorkspaceIds.length === 0) { - const result = []; - for (let i = 1; i <= workspacesShown; i++) { - result.push(i); - } - return result; - } - - try { - const maxExisting = Math.max(...allWorkspaceIds); - const totalNeeded = Math.max(workspacesShown, allWorkspaceIds.length); - const result = []; - - for (let i = 1; i <= maxExisting; i++) { - result.push(i); - } - - let nextId = maxExisting + 1; - while (result.length < totalNeeded) { - result.push(nextId); - nextId++; - } - - return result; - } catch (e) { - const result = []; - for (let i = 1; i <= workspacesShown; i++) { - result.push(i); - } - return result; - } - } - - readonly property int minWorkspaceId: displayedWorkspaceIds.length > 0 ? displayedWorkspaceIds[0] : 1 - readonly property int maxWorkspaceId: displayedWorkspaceIds.length > 0 ? displayedWorkspaceIds[displayedWorkspaceIds.length - 1] : workspacesShown - readonly property int displayWorkspaceCount: displayedWorkspaceIds.length - - readonly property int effectiveColumns: SettingsData.overviewColumns - readonly property int effectiveRows: Math.max(SettingsData.overviewRows, Math.ceil(displayWorkspaceCount / effectiveColumns)) - - function getWorkspaceMonitorName(workspaceId) { - if (!allWorkspaces || !workspaceId) - return ""; - try { - const ws = allWorkspaces.find(w => w?.id === workspaceId); - return ws?.monitor?.name ?? ""; - } catch (e) { - return ""; - } - } - - function workspaceHasWindows(workspaceId) { - if (!workspaceId) - return false; - try { - const workspace = allWorkspaces.find(ws => ws?.id === workspaceId); - if (!workspace) - return false; - const toplevels = workspace?.toplevels?.values || []; - return toplevels.length > 0; - } catch (e) { - return false; - } - } - - property bool monitorIsFocused: monitor?.focused ?? false - property real scale: SettingsData.overviewScale - property color activeBorderColor: Theme.primary - - readonly property real monitorPhysicalWidth: panelWindow.screen ? (panelWindow.screen.width / root.dpr) : (monitor?.width ?? 1920) - readonly property real monitorPhysicalHeight: panelWindow.screen ? (panelWindow.screen.height / root.dpr) : (monitor?.height ?? 1080) - property real workspaceImplicitWidth: monitorPhysicalWidth * root.scale - property real workspaceImplicitHeight: monitorPhysicalHeight * root.scale - - property int workspaceZ: 0 - property int windowZ: 1 - property int monitorLabelZ: 2 - property int windowDraggingZ: 99999 - property real workspaceSpacing: 5 - - property int draggingFromWorkspace: -1 - property int draggingTargetWorkspace: -1 - - implicitWidth: overviewBackground.implicitWidth + Theme.spacingL * 2 - implicitHeight: overviewBackground.implicitHeight + Theme.spacingL * 2 - - Component.onCompleted: { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Hyprland.refreshMonitors(); - } - - onOverviewOpenChanged: { - if (overviewOpen) { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Hyprland.refreshMonitors(); - } - } - - Rectangle { - id: overviewBackground - property real padding: 10 - anchors.fill: parent - anchors.margins: Theme.spacingL - - implicitWidth: workspaceColumnLayout.implicitWidth + padding * 2 - implicitHeight: workspaceColumnLayout.implicitHeight + padding * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: Theme.cornerRadius - targetColor: Theme.surfaceContainer - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - ColumnLayout { - id: workspaceColumnLayout - - z: root.workspaceZ - anchors.centerIn: parent - spacing: workspaceSpacing - - Repeater { - model: root.effectiveRows - delegate: RowLayout { - id: row - property int rowIndex: index - spacing: workspaceSpacing - - Repeater { - model: root.effectiveColumns - Rectangle { - id: workspace - property int colIndex: index - property int workspaceIndex: rowIndex * root.effectiveColumns + colIndex - property int workspaceValue: (root.displayedWorkspaceIds && workspaceIndex < root.displayedWorkspaceIds.length) ? root.displayedWorkspaceIds[workspaceIndex] : -1 - property bool workspaceExists: (root.allWorkspaceIds && workspaceValue > 0) ? root.allWorkspaceIds.includes(workspaceValue) : false - property var workspaceObj: (workspaceExists && Hyprland.workspaces?.values) ? Hyprland.workspaces.values.find(ws => ws?.id === workspaceValue) : null - property bool isActive: workspaceObj?.active ?? false - property bool isOnThisMonitor: (workspaceObj && root.monitor) ? (workspaceObj.monitor?.name === root.monitor.name) : true - property bool hasWindows: (workspaceValue > 0) ? root.workspaceHasWindows(workspaceValue) : false - property string workspaceMonitorName: (workspaceValue > 0) ? root.getWorkspaceMonitorName(workspaceValue) : "" - property color defaultWorkspaceColor: workspaceExists ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, 0.3) - property color hoveredWorkspaceColor: Qt.lighter(defaultWorkspaceColor, 1.1) - property color hoveredBorderColor: Theme.surfaceVariant - property bool hoveredWhileDragging: false - property bool shouldShowActiveIndicator: isActive && isOnThisMonitor && hasWindows - - visible: workspaceValue !== -1 - - implicitWidth: root.workspaceImplicitWidth - implicitHeight: root.workspaceImplicitHeight - color: hoveredWhileDragging ? hoveredWorkspaceColor : defaultWorkspaceColor - radius: Theme.cornerRadius - border.width: 2 - border.color: hoveredWhileDragging ? hoveredBorderColor : (shouldShowActiveIndicator ? root.activeBorderColor : "transparent") - - StyledText { - anchors.centerIn: parent - text: workspaceValue - font.pixelSize: Theme.fontSizeXLarge * 6 - font.weight: Font.DemiBold - color: Theme.withAlpha(Theme.surfaceText, workspaceExists ? 0.2 : 0.1) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - MouseArea { - id: workspaceArea - anchors.fill: parent - acceptedButtons: Qt.LeftButton - onClicked: { - if (root.draggingTargetWorkspace === -1) { - root.overviewOpen = false; - Hyprland.dispatch(`workspace ${workspaceValue}`); - } - } - } - - DropArea { - anchors.fill: parent - onEntered: { - root.draggingTargetWorkspace = workspaceValue; - if (root.draggingFromWorkspace == root.draggingTargetWorkspace) - return; - hoveredWhileDragging = true; - } - onExited: { - hoveredWhileDragging = false; - if (root.draggingTargetWorkspace == workspaceValue) - root.draggingTargetWorkspace = -1; - } - } - } - } - } - } - } - - Item { - id: windowSpace - anchors.centerIn: parent - implicitWidth: workspaceColumnLayout.implicitWidth - implicitHeight: workspaceColumnLayout.implicitHeight - - Repeater { - model: ScriptModel { - values: { - const workspaces = root.allWorkspaces; - const minId = root.minWorkspaceId; - const maxId = root.maxWorkspaceId; - - if (!workspaces || workspaces.length === 0) - return []; - - try { - const result = []; - for (const workspace of workspaces) { - const wsId = workspace?.id ?? -1; - if (wsId >= minId && wsId <= maxId) { - const toplevels = workspace?.toplevels?.values || []; - for (const toplevel of toplevels) { - result.push(toplevel); - } - } - } - return result; - } catch (e) { - console.error("OverviewWidget filter error:", e); - return []; - } - } - } - delegate: OverviewWindow { - id: window - required property var modelData - - overviewOpen: root.overviewOpen - readonly property int windowWorkspaceId: modelData?.workspace?.id ?? -1 - - function getWorkspaceIndex() { - if (!root.displayedWorkspaceIds || root.displayedWorkspaceIds.length === 0) - return 0; - if (!windowWorkspaceId || windowWorkspaceId < 0) - return 0; - try { - for (let i = 0; i < root.displayedWorkspaceIds.length; i++) { - if (root.displayedWorkspaceIds[i] === windowWorkspaceId) { - return i; - } - } - return 0; - } catch (e) { - return 0; - } - } - - readonly property int workspaceIndex: getWorkspaceIndex() - readonly property int workspaceColIndex: workspaceIndex % root.effectiveColumns - readonly property int workspaceRowIndex: Math.floor(workspaceIndex / root.effectiveColumns) - - toplevel: modelData - scale: root.scale - monitorDpr: root.dpr - availableWorkspaceWidth: root.workspaceImplicitWidth - availableWorkspaceHeight: root.workspaceImplicitHeight - widgetMonitorId: root.monitor.id - - xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - - z: atInitPosition ? root.windowZ : root.windowDraggingZ - property bool atInitPosition: (initX == x && initY == y) - - Drag.hotSpot.x: width / 2 - Drag.hotSpot.y: height / 2 - - MouseArea { - id: dragArea - anchors.fill: parent - hoverEnabled: true - onEntered: window.hovered = true - onExited: window.hovered = false - acceptedButtons: Qt.LeftButton | Qt.MiddleButton - drag.target: parent - - onPressed: mouse => { - root.draggingFromWorkspace = windowData?.workspace.id; - window.pressed = true; - window.Drag.active = true; - window.Drag.source = window; - window.Drag.hotSpot.x = mouse.x; - window.Drag.hotSpot.y = mouse.y; - } - - onReleased: { - const targetWorkspace = root.draggingTargetWorkspace; - window.pressed = false; - window.Drag.active = false; - root.draggingFromWorkspace = -1; - root.draggingTargetWorkspace = -1; - - if (targetWorkspace !== -1 && targetWorkspace !== windowData?.workspace.id) { - Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace},address:${windowData?.address}`); - Qt.callLater(() => { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Qt.callLater(() => { - window.x = window.initX; - window.y = window.initY; - }); - }); - } else { - window.x = window.initX; - window.y = window.initY; - } - } - - onClicked: event => { - if (!windowData || !windowData.address) - return; - if (event.button === Qt.LeftButton) { - root.overviewOpen = false; - Hyprland.dispatch(`focuswindow address:${windowData.address}`); - event.accepted = true; - } else if (event.button === Qt.MiddleButton) { - Hyprland.dispatch(`closewindow address:${windowData.address}`); - event.accepted = true; - } - } - } - } - } - } - - Item { - id: monitorLabelSpace - anchors.centerIn: parent - implicitWidth: workspaceColumnLayout.implicitWidth - implicitHeight: workspaceColumnLayout.implicitHeight - z: root.monitorLabelZ - - Repeater { - model: root.effectiveRows - delegate: Item { - id: labelRow - property int rowIndex: index - y: (root.workspaceImplicitHeight + workspaceSpacing) * rowIndex - width: parent.width - height: root.workspaceImplicitHeight - - Repeater { - model: root.effectiveColumns - delegate: Item { - id: labelItem - property int colIndex: index - property int workspaceIndex: labelRow.rowIndex * root.effectiveColumns + colIndex - property int workspaceValue: (root.displayedWorkspaceIds && workspaceIndex < root.displayedWorkspaceIds.length) ? root.displayedWorkspaceIds[workspaceIndex] : -1 - property bool workspaceExists: (root.allWorkspaceIds && workspaceValue > 0) ? root.allWorkspaceIds.includes(workspaceValue) : false - property string workspaceMonitorName: (workspaceValue > 0) ? root.getWorkspaceMonitorName(workspaceValue) : "" - - x: (root.workspaceImplicitWidth + workspaceSpacing) * colIndex - width: root.workspaceImplicitWidth - height: root.workspaceImplicitHeight - - Rectangle { - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingS - width: monitorNameText.contentWidth + Theme.spacingS * 2 - height: monitorNameText.contentHeight + Theme.spacingXS * 2 - radius: Theme.cornerRadius - color: Theme.surface - visible: labelItem.workspaceExists && labelItem.workspaceMonitorName !== "" - - StyledText { - id: monitorNameText - anchors.centerIn: parent - text: labelItem.workspaceMonitorName - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml deleted file mode 100644 index 4389971..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml +++ /dev/null @@ -1,142 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import qs.Common - -Item { - id: root - property var toplevel - property var scale - required property bool overviewOpen - property var availableWorkspaceWidth - property var availableWorkspaceHeight - property bool restrictToWorkspace: true - property real monitorDpr: 1 - - readonly property var windowData: toplevel?.lastIpcObject || null - readonly property var monitorObj: toplevel?.monitor - readonly property var monitorData: monitorObj?.lastIpcObject || null - readonly property real effectiveScale: root.scale / root.monitorDpr - - property real initX: Math.max(((windowData?.at?.[0] ?? 0) - (monitorData?.x ?? 0) - (monitorData?.reserved?.[0] ?? 0)) * effectiveScale, 0) + xOffset - property real initY: Math.max(((windowData?.at?.[1] ?? 0) - (monitorData?.y ?? 0) - (monitorData?.reserved?.[1] ?? 0)) * effectiveScale, 0) + yOffset - property real xOffset: 0 - property real yOffset: 0 - property int widgetMonitorId: 0 - - property var targetWindowWidth: (windowData?.size?.[0] ?? 100) * effectiveScale - property var targetWindowHeight: (windowData?.size?.[1] ?? 100) * effectiveScale - property bool hovered: false - property bool pressed: false - - property var iconToWindowRatio: 0.25 - property var iconToWindowRatioCompact: 0.45 - property var entry: DesktopEntries.heuristicLookup(Paths.moddedAppId(windowData?.class ?? "")) - property var iconPath: Paths.getAppIcon(windowData?.class ?? "", entry) || Quickshell.iconPath("application-x-executable", "image-missing") - property bool compactMode: Theme.fontSizeSmall * 4 > targetWindowHeight || Theme.fontSizeSmall * 4 > targetWindowWidth - - x: initX - y: initY - width: Math.min((windowData?.size?.[0] ?? 100) * effectiveScale, availableWorkspaceWidth) - height: Math.min((windowData?.size?.[1] ?? 100) * effectiveScale, availableWorkspaceHeight) - opacity: (monitorObj?.id ?? -1) == widgetMonitorId ? 1 : 0.4 - - Rectangle { - id: maskRect - width: root.width - height: root.height - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: maskRect - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Behavior on x { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on y { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on width { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on height { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - ScreencopyView { - id: windowPreview - anchors.fill: parent - captureSource: root.overviewOpen ? root.toplevel?.wayland : null - live: true - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: pressed ? Theme.withAlpha(Theme.surfaceContainerHigh, 0.5) : - hovered ? Theme.withAlpha(Theme.surfaceVariant, 0.3) : - Theme.withAlpha(Theme.surfaceContainer, 0.1) - border.color: Theme.withAlpha(Theme.outline, 0.3) - border.width: 1 - } - - ColumnLayout { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.fontSizeSmall * 0.5 - - Image { - id: windowIcon - property var iconSize: { - return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / (root.monitorData?.scale ?? 1) - } - Layout.alignment: Qt.AlignHCenter - source: root.iconPath - width: iconSize - height: iconSize - sourceSize: Qt.size(iconSize, iconSize) - - Behavior on width { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on height { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml deleted file mode 100644 index 1307fad..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml +++ /dev/null @@ -1,32 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -PluginSettings { - id: root - pluginId: "colorDemo" - - StyledText { - width: parent.width - text: "Color Demo Settings" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - width: parent.width - text: "Choose a custom color to display in the bar widget" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - ColorSetting { - settingKey: "customColor" - label: "Custom Color" - description: "Choose a custom color to display in the widget" - defaultValue: Theme.primary - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml deleted file mode 100644 index 6b90845..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - property color customColor: pluginData.customColor || Theme.primary - - horizontalBarPill: Component { - Row { - spacing: Theme.spacingS - - Rectangle { - width: 20 - height: 20 - radius: 4 - color: root.customColor - border.color: Theme.outlineStrong - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.customColor.toString() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - verticalBarPill: Component { - Column { - spacing: Theme.spacingXS - - Rectangle { - width: 20 - height: 20 - radius: 4 - color: root.customColor - border.color: Theme.outlineStrong - border.width: 1 - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.customColor.toString() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json deleted file mode 100644 index 45bf33a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "colorDemo", - "name": "Color Demo", - "description": "Demonstrates color picker plugin setting", - "version": "1.0.0", - "author": "DMS", - "icon": "palette", - "type": "widget", - "component": "./ColorDemoWidget.qml", - "settings": "./ColorDemoSettings.qml", - "permissions": ["settings_read", "settings_write"] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml deleted file mode 100644 index 7d61900..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml +++ /dev/null @@ -1,138 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - property bool isEnabled: pluginData.isEnabled || false - property var options: pluginData.options || ["Option A", "Option B", "Option C"] - - ccWidgetIcon: isEnabled ? "settings" : "settings" - ccWidgetPrimaryText: "Detail Example" - ccWidgetSecondaryText: { - if (isEnabled) { - const selected = pluginData.selectedOption || "Option A" - return selected - } - return "Disabled" - } - ccWidgetIsActive: isEnabled - - onCcWidgetToggled: { - isEnabled = !isEnabled - if (pluginService) { - pluginService.savePluginData("controlCenterDetailExample", "isEnabled", isEnabled) - } - } - - ccDetailContent: Component { - Rectangle { - id: detailRoot - implicitHeight: detailColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - visible: true - - property var options: ["Option A", "Option B", "Option C"] - property string currentSelection: SettingsData.getPluginSetting("controlCenterDetailExample", "selectedOption", "Option A") - - Column { - id: detailColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - StyledText { - text: "Detail Example Settings" - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: "Select an option below:" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - Repeater { - model: detailRoot.options - - Rectangle { - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: optionMouseArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - border.color: detailRoot.currentSelection === modelData ? Theme.primary : "transparent" - border.width: detailRoot.currentSelection === modelData ? 2 : 0 - - MouseArea { - id: optionMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - z: 100 - onClicked: { - SettingsData.setPluginSetting("controlCenterDetailExample", "selectedOption", modelData) - detailRoot.currentSelection = modelData - PluginService.pluginDataChanged("controlCenterDetailExample") - ToastService.showInfo("Option Selected", modelData) - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - enabled: false - - DankIcon { - name: detailRoot.currentSelection === modelData ? "radio_button_checked" : "radio_button_unchecked" - color: detailRoot.currentSelection === modelData ? Theme.primary : Theme.surfaceVariantText - size: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData - color: detailRoot.currentSelection === modelData ? Theme.primary : Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - } - } - - horizontalBarPill: Component { - Row { - spacing: Theme.spacingXS - - DankIcon { - name: root.isEnabled ? "settings" : "settings_off" - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.iconSize - 4 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - const selected = root.pluginData.selectedOption || "Option A" - return selected.substring(0, 1) - } - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeMedium - anchors.verticalCenter: parent.verticalCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json deleted file mode 100644 index 00fc9f9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "controlCenterDetailExample", - "name": "CC Detail Example", - "description": "Example plugin with Control Center detail dropdown", - "version": "1.0.0", - "author": "DankMaterialShell", - "type": "widget", - "capabilities": ["control-center"], - "component": "./DetailExampleWidget.qml", - "icon": "settings", - "permissions": ["settings_read", "settings_write"] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml deleted file mode 100644 index 450d538..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml +++ /dev/null @@ -1,68 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - property bool isEnabled: pluginData.isEnabled || false - property int clickCount: pluginData.clickCount || 0 - - ccWidgetIcon: isEnabled ? "toggle_on" : "toggle_off" - ccWidgetPrimaryText: "Example Toggle" - ccWidgetSecondaryText: isEnabled ? `Active • ${clickCount} clicks` : "Inactive" - ccWidgetIsActive: isEnabled - - onCcWidgetToggled: { - isEnabled = !isEnabled - clickCount += 1 - if (pluginService) { - pluginService.savePluginData("controlCenterExample", "isEnabled", isEnabled) - pluginService.savePluginData("controlCenterExample", "clickCount", clickCount) - } - ToastService.showInfo("Example Toggle", isEnabled ? "Activated!" : "Deactivated!") - } - - horizontalBarPill: Component { - Row { - spacing: Theme.spacingXS - - DankIcon { - name: root.isEnabled ? "toggle_on" : "toggle_off" - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.iconSize - 4 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: `${root.clickCount}` - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeMedium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - verticalBarPill: Component { - Column { - spacing: Theme.spacingXS - - DankIcon { - name: root.isEnabled ? "toggle_on" : "toggle_off" - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.iconSize - 4 - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: `${root.clickCount}` - color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json deleted file mode 100644 index f573ae6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "controlCenterExample", - "name": "CC Toggle Example", - "description": "Example plugin with Control Center toggle widget", - "version": "1.0.0", - "author": "DankMaterialShell", - "type": "widget", - "capabilities": ["control-center"], - "component": "./ControlCenterExampleWidget.qml", - "icon": "toggle_on", - "permissions": ["settings_read", "settings_write"] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml deleted file mode 100644 index 55ac34c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml +++ /dev/null @@ -1,172 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins - -DesktopPluginComponent { - id: root - - minWidth: 120 - minHeight: 120 - - property bool showSeconds: pluginData.showSeconds ?? true - property bool showDate: pluginData.showDate ?? true - property string clockStyle: pluginData.clockStyle ?? "analog" - property real backgroundOpacity: (pluginData.backgroundOpacity ?? 50) / 100 - - SystemClock { - id: systemClock - precision: root.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } - - Rectangle { - id: background - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: root.backgroundOpacity - } - - Loader { - anchors.fill: parent - anchors.margins: Theme.spacingM - sourceComponent: root.clockStyle === "digital" ? digitalClock : analogClock - } - - Component { - id: analogClock - - Item { - id: analogClockRoot - - property real clockSize: Math.min(width, height) - (root.showDate ? 30 : 0) - - Item { - id: clockFace - width: analogClockRoot.clockSize - height: analogClockRoot.clockSize - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - - Repeater { - model: 12 - - Rectangle { - required property int index - property real markAngle: index * 30 - property real markRadius: clockFace.width / 2 - 8 - - x: clockFace.width / 2 + markRadius * Math.sin(markAngle * Math.PI / 180) - width / 2 - y: clockFace.height / 2 - markRadius * Math.cos(markAngle * Math.PI / 180) - height / 2 - width: index % 3 === 0 ? 8 : 4 - height: width - radius: width / 2 - color: index % 3 === 0 ? Theme.primary : Theme.outlineVariant - } - } - - Rectangle { - id: hourHand - property int hours: systemClock.date?.getHours() % 12 ?? 0 - property int minutes: systemClock.date?.getMinutes() ?? 0 - - x: clockFace.width / 2 - width / 2 - y: clockFace.height / 2 - height + 4 - width: 6 - height: clockFace.height * 0.25 - radius: 3 - color: Theme.primary - antialiasing: true - transformOrigin: Item.Bottom - rotation: (hours + minutes / 60) * 30 - } - - Rectangle { - id: minuteHand - property int minutes: systemClock.date?.getMinutes() ?? 0 - property int seconds: systemClock.date?.getSeconds() ?? 0 - - x: clockFace.width / 2 - width / 2 - y: clockFace.height / 2 - height + 4 - width: 4 - height: clockFace.height * 0.35 - radius: 2 - color: Theme.onSurface - antialiasing: true - transformOrigin: Item.Bottom - rotation: (minutes + seconds / 60) * 6 - } - - Rectangle { - id: secondHand - visible: root.showSeconds - property int seconds: systemClock.date?.getSeconds() ?? 0 - - x: clockFace.width / 2 - width / 2 - y: clockFace.height / 2 - height + 4 - width: 2 - height: clockFace.height * 0.4 - radius: 1 - color: Theme.error - antialiasing: true - transformOrigin: Item.Bottom - rotation: seconds * 6 - } - - Rectangle { - anchors.centerIn: parent - width: 10 - height: 10 - radius: 5 - color: Theme.primary - } - } - - Text { - visible: root.showDate - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingXS - text: systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - } - - Component { - id: digitalClock - - Item { - id: digitalRoot - - property real timeFontSize: Math.min(width * 0.16, height * (root.showDate ? 0.4 : 0.5)) - property real dateFontSize: Math.max(Theme.fontSizeSmall, timeFontSize * 0.35) - - Text { - id: timeText - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: root.showDate ? -digitalRoot.dateFontSize * 0.8 : 0 - text: systemClock.date?.toLocaleTimeString(Qt.locale(), root.showSeconds ? "hh:mm:ss" : "hh:mm") ?? "" - font.pixelSize: digitalRoot.timeFontSize - font.weight: Font.Bold - font.family: "monospace" - color: Theme.primary - } - - Text { - id: dateText - visible: root.showDate - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: timeText.bottom - anchors.topMargin: Theme.spacingXS - text: systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? "" - font.pixelSize: digitalRoot.dateFontSize - color: Theme.surfaceText - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml deleted file mode 100644 index 94063b7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml +++ /dev/null @@ -1,45 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "exampleDesktopClock" - - SelectionSetting { - settingKey: "clockStyle" - label: I18n.tr("Clock Style") - options: [ - { - label: I18n.tr("Analog"), - value: "analog" - }, - { - label: I18n.tr("Digital"), - value: "digital" - } - ] - defaultValue: "analog" - } - - ToggleSetting { - settingKey: "showSeconds" - label: I18n.tr("Show Seconds") - defaultValue: true - } - - ToggleSetting { - settingKey: "showDate" - label: I18n.tr("Show Date") - defaultValue: true - } - - SliderSetting { - settingKey: "backgroundOpacity" - label: I18n.tr("Background Opacity") - defaultValue: 50 - minimum: 0 - maximum: 100 - unit: "%" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json deleted file mode 100644 index efa80c8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "exampleDesktopClock", - "name": "Desktop Clock", - "description": "An example desktop widget displaying an analog clock", - "version": "1.0.0", - "author": "DankMaterialShell", - "type": "desktop", - "capabilities": ["desktop-widget", "clock"], - "component": "./DesktopClock.qml", - "icon": "schedule", - "settings": "./DesktopClockSettings.qml", - "requires_dms": ">=1.2.0", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml deleted file mode 100644 index aa38bc9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml +++ /dev/null @@ -1,97 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "exampleEmojiPlugin" - - // Header section to explain what this plugin does - StyledText { - width: parent.width - text: "Emoji Cycler Settings" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - width: parent.width - text: "Configure which emojis appear in your bar, how quickly they cycle, and how many show at once." - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - // Dropdown to select which emoji set to use - SelectionSetting { - settingKey: "emojiSet" - label: "Emoji Set" - description: "Choose which collection of emojis to cycle through" - options: [ - {label: "Happy & Sad", value: "happySad"}, - {label: "Hearts", value: "hearts"}, - {label: "Hand Gestures", value: "hands"}, - {label: "All Mixed", value: "mixed"} - ] - defaultValue: "happySad" - - // Update the actual emoji array when selection changes - onValueChanged: { - const sets = { - "happySad": ["😊", "😢", "😂", "😭", "😍", "😡"], - "hearts": ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍"], - "hands": ["👍", "👎", "👊", "✌️", "🤘", "👌", "✋", "🤚"], - "mixed": ["😊", "❤️", "👍", "🎉", "🔥", "✨", "🌟", "💯"] - } - const newEmojis = sets[value] || sets["happySad"] - root.saveValue("emojis", newEmojis) - } - - Component.onCompleted: { - // Initialize the emojis array on first load - const currentSet = value || defaultValue - const sets = { - "happySad": ["😊", "😢", "😂", "😭", "😍", "😡"], - "hearts": ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍"], - "hands": ["👍", "👎", "👊", "✌️", "🤘", "👌", "✋", "🤚"], - "mixed": ["😊", "❤️", "👍", "🎉", "🔥", "✨", "🌟", "💯"] - } - const emojis = sets[currentSet] || sets["happySad"] - root.saveValue("emojis", emojis) - } - } - - // Slider to control how fast emojis cycle (in milliseconds) - SliderSetting { - settingKey: "cycleInterval" - label: "Cycle Speed" - description: "How quickly emojis rotate (in seconds)" - defaultValue: 3000 - minimum: 500 - maximum: 10000 - unit: "ms" - leftIcon: "schedule" - } - - // Slider to control max emojis shown in the bar - SliderSetting { - settingKey: "maxBarEmojis" - label: "Max Bar Emojis" - description: "Maximum number of emojis to display in the bar at once" - defaultValue: 3 - minimum: 1 - maximum: 8 - unit: "" - rightIcon: "emoji_emotions" - } - - StyledText { - width: parent.width - text: "💡 Tip: Click the emoji widget in your bar to open the emoji picker and copy any emoji to your clipboard!" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml deleted file mode 100644 index 6142692..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml +++ /dev/null @@ -1,151 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - layerNamespacePlugin: "emoji-cycler" - - property var enabledEmojis: pluginData.emojis || ["😊", "😢", "❤️"] - property int cycleInterval: pluginData.cycleInterval || 3000 - property int maxBarEmojis: pluginData.maxBarEmojis || 3 - - property int currentIndex: 0 - property var displayedEmojis: [] - - Timer { - interval: root.cycleInterval - running: true - repeat: true - onTriggered: { - if (root.enabledEmojis.length > 0) { - root.currentIndex = (root.currentIndex + 1) % root.enabledEmojis.length - root.updateDisplayedEmojis() - } - } - } - - function updateDisplayedEmojis() { - const maxToShow = Math.min(root.maxBarEmojis, root.enabledEmojis.length) - let emojis = [] - for (let i = 0; i < maxToShow; i++) { - const idx = (root.currentIndex + i) % root.enabledEmojis.length - emojis.push(root.enabledEmojis[idx]) - } - root.displayedEmojis = emojis - } - - Component.onCompleted: { - updateDisplayedEmojis() - } - - onEnabledEmojisChanged: updateDisplayedEmojis() - onMaxBarEmojisChanged: updateDisplayedEmojis() - - horizontalBarPill: Component { - Row { - id: emojiRow - spacing: Theme.spacingXS - - Repeater { - model: root.displayedEmojis - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeLarge - } - } - } - } - - verticalBarPill: Component { - Column { - id: emojiColumn - spacing: Theme.spacingXS - - Repeater { - model: root.displayedEmojis - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeMedium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - popoutContent: Component { - PopoutComponent { - id: popoutColumn - - headerText: "Emoji Picker" - detailsText: "Click an emoji to copy it to clipboard" - showCloseButton: true - - property var allEmojis: [ - "😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃", - "😉", "😊", "😇", "🥰", "😍", "🤩", "😘", "😗", "😚", "😙", - "😋", "😛", "😜", "🤪", "😝", "🤑", "🤗", "🤭", "🤫", "🤔", - "🤐", "🤨", "😐", "😑", "😶", "😏", "😒", "🙄", "😬", "🤥", - "😌", "😔", "😪", "🤤", "😴", "😷", "🤒", "🤕", "🤢", "🤮", - "🤧", "🥵", "🥶", "😶‍🌫️", "😵", "😵‍💫", "🤯", "🤠", "🥳", "😎", - "🤓", "🧐", "😕", "😟", "🙁", "☹️", "😮", "😯", "😲", "😳", - "🥺", "😦", "😧", "😨", "😰", "😥", "😢", "😭", "😱", "😖", - "😣", "😞", "😓", "😩", "😫", "🥱", "😤", "😡", "😠", "🤬", - "❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔", - "❤️‍🔥", "❤️‍🩹", "💕", "💞", "💓", "💗", "💖", "💘", "💝", "💟", - "👍", "👎", "👊", "✊", "🤛", "🤜", "🤞", "✌️", "🤟", "🤘", - "👌", "🤌", "🤏", "👈", "👉", "👆", "👇", "☝️", "✋", "🤚" - ] - - Item { - width: parent.width - implicitHeight: root.popoutHeight - popoutColumn.headerHeight - popoutColumn.detailsHeight - Theme.spacingXL - - DankGridView { - id: emojiGrid - anchors.horizontalCenter: parent.horizontalCenter - width: Math.floor(parent.width / 50) * 50 - height: parent.height - clip: true - cellWidth: 50 - cellHeight: 50 - model: popoutColumn.allEmojis - - delegate: StyledRect { - width: 45 - height: 45 - radius: Theme.cornerRadius - color: emojiMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainerHigh - border.width: 0 - - StyledText { - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeXLarge - } - - MouseArea { - id: emojiMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", modelData]) - ToastService.showInfo("Copied " + modelData + " to clipboard") - popoutColumn.closePopout() - } - } - } - } - } - } - } - - popoutWidth: 400 - popoutHeight: 500 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md deleted file mode 100644 index 9102dda..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Emoji Cycler Plugin - -An example dms plugin that displays cycling emojis in your bar with an emoji picker popout. - -## Features - -- **Cycling Emojis**: Automatically rotates through your selected emoji set in the bar -- **Emoji Picker**: Click the widget to open a grid of 120+ emojis -- **Copy to Clipboard**: Click any emoji in the picker to copy it to clipboard -- **Customizable**: Choose emoji sets, cycle speed, and max emojis shown - -## Installation - -1. Copy this directory to `~/.config/DankMaterialShell/plugins/ExampleEmojiPlugin` -2. Open DMS Settings → Plugins -3. Click "Scan for Plugins" -4. Enable "Emoji Cycler" -5. Add `exampleEmojiPlugin` to your DankBar widget list - -## Settings - -### Emoji Set -Choose from different emoji collections: -- **Happy & Sad**: Mix of emotional faces -- **Hearts**: Various colored hearts -- **Hand Gestures**: Thumbs up, peace signs, etc. -- **All Mixed**: A bit of everything - -### Cycle Speed -Control how fast emojis rotate (500ms - 10000ms) - -### Max Bar Emojis -How many emojis to display at once (1-8) - -## Usage - -**In the bar**: Watch emojis cycle through automatically -**Click the widget**: Opens emoji picker with 120+ emojis -**Click any emoji**: Copies it to clipboard and shows toast - -## Example Code Highlights - -This plugin demonstrates: -- Using `PluginComponent` for bar integration -- `SelectionSetting`, `SliderSetting` for configuration -- Timer-based animation -- Popout content with grid layout -- External command execution (`Quickshell.execDetached`) -- Toast notifications (`ToastService.show`) -- Dynamic settings loading/saving - -Perfect template for creating your own DMS plugins! diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json deleted file mode 100644 index ef16d01..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "exampleEmojiPlugin", - "name": "Emoji Cycler", - "description": "Display cycling emojis in your bar with a handy emoji picker popout", - "version": "1.0.0", - "author": "AvengeMedia", - "type": "widget", - "capabilities": ["emoji-search", "clipboard", "dankbar-widget"], - "component": "./EmojiWidget.qml", - "icon": "mood", - "settings": "./EmojiSettings.qml", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md deleted file mode 100644 index 833572e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# Example with Variants Plugin - -This plugin demonstrates the dynamic variant system for DankMaterialShell plugins. - -## What are Variants? - -Variants allow a single plugin to create multiple widget instances with different configurations. Each variant appears as a separate widget option in the Bar Settings "Add Widget" menu. - -## How It Works - -### Plugin Architecture - -1. **Single Component**: The plugin defines one widget component (`VariantWidget.qml`) -2. **Variant Data**: Each variant stores its configuration in plugin settings -3. **Dynamic Creation**: Variants are created through the plugin's settings UI -4. **Widget ID Format**: Variants use the format `pluginId:variantId` (e.g., `exampleVariants:variant_1234567890`) - -### Widget Properties - -Each variant widget receives: -- `pluginService`: Reference to PluginService -- `pluginId`: The base plugin ID (e.g., "exampleVariants") -- `variantId`: The specific variant ID (e.g., "variant_1234567890") -- `variantData`: The variant's configuration object - -### Variant Configuration - -This example stores: -```javascript -{ - id: "variant_1234567890", - name: "My Variant", - text: "Display Text", - icon: "star", - color: "#FF5722" -} -``` - -## Creating Your Own Variant Plugin - -### 1. Widget Component - -Create a widget that accepts variant data: - -```qml -Rectangle { - property var pluginService: null - property string pluginId: "" - property string variantId: "" - property var variantData: null - - // Use variantData for configuration - property string displayText: variantData?.text || "Default" -} -``` - -### 2. Settings Component - -Provide UI to manage variants: - -```qml -FocusScope { - property var pluginService: null - - // Create variant - pluginService.createPluginVariant(pluginId, variantName, variantConfig) - - // Remove variant - pluginService.removePluginVariant(pluginId, variantId) - - // Update variant - pluginService.updatePluginVariant(pluginId, variantId, variantConfig) - - // Get all variants - var variants = pluginService.getPluginVariants(pluginId) -} -``` - -### 3. Plugin Manifest - -Standard plugin manifest - no special configuration needed: - -```json -{ - "id": "yourPlugin", - "name": "Your Plugin", - "component": "./Widget.qml", - "settings": "./Settings.qml" -} -``` - -## Use Cases - -- **Script Runner**: Multiple variants running different scripts -- **System Monitors**: Different monitoring targets (CPU, GPU, Network) -- **Quick Launchers**: Different apps or commands per variant -- **Custom Indicators**: Different data sources or APIs -- **Time Zones**: Multiple clocks for different time zones - -## API Reference - -### PluginService Functions - -- `getPluginVariants(pluginId)`: Get all variants for a plugin -- `getAllPluginVariants()`: Get all variants across all plugins -- `createPluginVariant(pluginId, name, config)`: Create new variant -- `removePluginVariant(pluginId, variantId)`: Delete variant -- `updatePluginVariant(pluginId, variantId, config)`: Update variant -- `getPluginVariantData(pluginId, variantId)`: Get specific variant data - -### Widget Properties - -- `pluginId`: Base plugin identifier -- `variantId`: Variant identifier (null if no variant) -- `variantData`: Variant configuration object -- `pluginService`: PluginService reference diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml deleted file mode 100644 index d5ea1d2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml +++ /dev/null @@ -1,303 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "exampleVariants" - - onVariantsChanged: { - variantsModel.clear() - for (var i = 0; i < variants.length; i++) { - variantsModel.append(variants[i]) - } - } - - StyledText { - width: parent.width - text: "Variant Manager" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - width: parent.width - text: "Create multiple widget variants with different text, icons, and colors" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - StyledRect { - width: parent.width - height: addVariantColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: addVariantColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: "Add New Variant" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: "Name" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: nameField - width: parent.width - placeholderText: "Variant Name" - } - } - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: "Icon" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: iconField - width: parent.width - placeholderText: "star" - } - } - - Column { - width: (parent.width - Theme.spacingM * 2) / 3 - spacing: Theme.spacingXS - - StyledText { - text: "Text" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: textField - width: parent.width - placeholderText: "Display Text" - } - } - } - - DankButton { - text: "Create Variant" - iconName: "add" - onClicked: { - if (!nameField.text) { - ToastService.showError("Please enter a variant name") - return - } - - var variantConfig = { - text: textField.text || nameField.text, - icon: iconField.text || "widgets" - } - - createVariant(nameField.text, variantConfig) - ToastService.showInfo("Variant created: " + nameField.text) - - nameField.text = "" - iconField.text = "" - textField.text = "" - } - } - } - } - - StyledRect { - width: parent.width - height: Math.max(200, variantsColumn.implicitHeight + Theme.spacingL * 2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: variantsColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: "Existing Variants" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - ListView { - width: parent.width - height: Math.max(100, contentHeight) - clip: true - spacing: Theme.spacingXS - - model: ListModel { - id: variantsModel - } - - delegate: StyledRect { - required property var model - width: ListView.view.width - height: variantRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: variantMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainer - - Row { - id: variantRow - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Item { - width: Theme.iconSize - height: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: model.icon || "widgets" - size: Theme.iconSize - color: Theme.surfaceText - width: Theme.iconSize - height: Theme.iconSize - clip: true - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - Theme.iconSize - deleteButton.width - Theme.spacingM * 4 - - StyledText { - text: model.name || "Unnamed" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - } - - StyledText { - text: "Text: " + (model.text || "") + " | Icon: " + (model.icon || "") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - } - } - - Rectangle { - id: deleteButton - width: 32 - height: 32 - radius: 16 - color: deleteArea.containsMouse ? Theme.error : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 16 - color: deleteArea.containsMouse ? Theme.onError : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - removeVariant(model.id) - ToastService.showInfo("Variant removed: " + model.name) - } - } - } - } - - MouseArea { - id: variantMouseArea - anchors.fill: parent - hoverEnabled: true - propagateComposedEvents: true - } - } - - StyledText { - anchors.centerIn: parent - text: "No variants created yet" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: variantsModel.count === 0 - } - } - } - } - - StyledRect { - width: parent.width - height: instructionsColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surface - - Column { - id: instructionsColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "How to Use Variants" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: "1. Create variants with different names, icons, and text\n2. Go to Bar Settings and click 'Add Widget'\n3. Each variant will appear as a separate widget option\n4. Add variants to your bar just like any other widget" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - lineHeight: 1.4 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml deleted file mode 100644 index e5b077f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - property string variantId: "" - property var variantData: null - - property string displayText: variantData?.text || "Default Text" - property string displayIcon: variantData?.icon || "widgets" - - horizontalBarPill: Component { - Row { - spacing: 3 - - DankIcon { - name: root.displayIcon - size: Theme.iconSize - 8 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.displayText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - verticalBarPill: Component { - Column { - spacing: 1 - - DankIcon { - name: root.displayIcon - size: Theme.iconSize - 8 - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.displayText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json deleted file mode 100644 index 9e3cad4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "exampleVariants", - "name": "Example with Variants", - "description": "Demonstrates dynamic variant creation for plugins", - "version": "1.0.0", - "author": "DMS", - "type": "widget", - "capabilities": ["multiple-usecases", "variants"], - "component": "./VariantWidget.qml", - "icon": "widgets", - "settings": "./VariantSettings.qml", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml deleted file mode 100644 index 81040b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml +++ /dev/null @@ -1,140 +0,0 @@ -import QtQuick -import Quickshell -import qs.Services - -Item { - id: root - - // Plugin properties - property var pluginService: null - property string trigger: "#" - - // Plugin interface signals - signal itemsChanged() - - Component.onCompleted: { - console.info("LauncherExample: Plugin loaded") - - // Load custom trigger from settings - if (pluginService) { - trigger = pluginService.loadPluginData("launcherExample", "trigger", "#") - } - } - - // Required function: Get items for launcher - function getItems(query) { - const baseItems = [ - { - name: "Test Item 1", - icon: "material:lightbulb", - comment: "This is a test item that shows a toast notification", - action: "toast:Test Item 1 executed!", - categories: ["LauncherExample"] - }, - { - name: "Test Item 2", - icon: "material:star", - comment: "Another test item with different action", - action: "toast:Test Item 2 clicked!", - categories: ["LauncherExample"] - }, - { - name: "Test Item 3", - icon: "material:favorite", - comment: "Third test item for demonstration", - action: "toast:Test Item 3 activated!", - categories: ["LauncherExample"] - }, - { - name: "Unicode Icon Example", - icon: "unicode:🚀", - comment: "Demonstrates unicode/emoji icon support", - action: "toast:Unicode icons work great!", - categories: ["LauncherExample"] - }, - { - name: "Example Copy Action", - icon: "material:content_copy", - comment: "Demonstrates copying text to clipboard", - action: "copy:This text was copied by the launcher plugin!", - categories: ["LauncherExample"] - }, - { - name: "Example Script Action", - icon: "material:terminal", - comment: "Demonstrates running a simple command", - action: "script:echo 'Hello from launcher plugin!'", - categories: ["LauncherExample"] - } - ] - - if (!query || query.length === 0) { - return baseItems - } - - // Filter items based on query - const lowerQuery = query.toLowerCase() - return baseItems.filter(item => { - return item.name.toLowerCase().includes(lowerQuery) || - item.comment.toLowerCase().includes(lowerQuery) - }) - } - - // Required function: Execute item action - function executeItem(item) { - if (!item || !item.action) { - console.warn("LauncherExample: Invalid item or action") - return - } - - console.log("LauncherExample: Executing item:", item.name, "with action:", item.action) - - const actionParts = item.action.split(":") - const actionType = actionParts[0] - const actionData = actionParts.slice(1).join(":") - - switch (actionType) { - case "toast": - showToast(actionData) - break - case "copy": - copyToClipboard(actionData) - break - case "script": - runScript(actionData) - break - default: - console.warn("LauncherExample: Unknown action type:", actionType) - showToast("Unknown action: " + actionType) - } - } - - // Helper functions for different action types - function showToast(message) { - if (typeof ToastService !== "undefined") { - ToastService.showInfo("LauncherExample", message) - } else { - console.log("LauncherExample Toast:", message) - } - } - - function copyToClipboard(text) { - Quickshell.execDetached(["dms", "cl", "copy", text]) - showToast("Copied to clipboard: " + text) - } - - function runScript(command) { - console.log("LauncherExample: Would run script:", command) - showToast("Script executed: " + command) - - // In a real plugin, you might create a Process component here - // For demo purposes, we just show what would happen - } - - // Watch for trigger changes - onTriggerChanged: { - if (pluginService) { - pluginService.savePluginData("launcherExample", "trigger", trigger) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml deleted file mode 100644 index e30aaa8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml +++ /dev/null @@ -1,244 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Widgets - -FocusScope { - id: root - - property var pluginService: null - - implicitHeight: settingsColumn.implicitHeight - height: implicitHeight - - Column { - id: settingsColumn - anchors.fill: parent - anchors.margins: 16 - spacing: 16 - - Text { - text: "Launcher Example Plugin Settings" - font.pixelSize: 18 - font.weight: Font.Bold - color: "#FFFFFF" - } - - Text { - text: "This plugin demonstrates the launcher plugin system with example items and actions." - font.pixelSize: 14 - color: "#CCFFFFFF" - wrapMode: Text.WordWrap - width: parent.width - 32 - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 12 - width: parent.width - 32 - - Text { - text: "Trigger Configuration" - font.pixelSize: 16 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Text { - text: noTriggerToggle.checked ? "Items will always show in the launcher (no trigger needed)." : "Set the trigger text to activate this plugin. Type the trigger in the launcher to filter to this plugin's items." - font.pixelSize: 12 - color: "#CCFFFFFF" - wrapMode: Text.WordWrap - width: parent.width - } - - Row { - spacing: 12 - - CheckBox { - id: noTriggerToggle - text: "No trigger (always show)" - checked: loadSettings("noTrigger", false) - - contentItem: Text { - text: noTriggerToggle.text - font.pixelSize: 14 - color: "#FFFFFF" - leftPadding: noTriggerToggle.indicator.width + 8 - verticalAlignment: Text.AlignVCenter - } - - indicator: Rectangle { - implicitWidth: 20 - implicitHeight: 20 - radius: 4 - border.color: noTriggerToggle.checked ? "#4CAF50" : "#60FFFFFF" - border.width: 2 - color: noTriggerToggle.checked ? "#4CAF50" : "transparent" - - Rectangle { - width: 12 - height: 12 - anchors.centerIn: parent - radius: 2 - color: "#FFFFFF" - visible: noTriggerToggle.checked - } - } - - onCheckedChanged: { - saveSettings("noTrigger", checked) - if (checked) { - saveSettings("trigger", "") - } else { - saveSettings("trigger", triggerField.text || "#") - } - } - } - } - - Row { - spacing: 12 - anchors.left: parent.left - anchors.right: parent.right - visible: !noTriggerToggle.checked - - Text { - text: "Trigger:" - font.pixelSize: 14 - color: "#FFFFFF" - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - id: triggerField - width: 100 - height: 40 - text: loadSettings("trigger", "#") - placeholderText: "#" - backgroundColor: "#30FFFFFF" - textColor: "#FFFFFF" - - onTextEdited: { - const newTrigger = text.trim() - saveSettings("trigger", newTrigger || "#") - saveSettings("noTrigger", newTrigger === "") - } - } - - Text { - text: "Examples: #, !, @, !ex, etc." - font.pixelSize: 12 - color: "#AAFFFFFF" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 8 - width: parent.width - 32 - - Text { - text: "Example Items:" - font.pixelSize: 14 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Column { - spacing: 4 - leftPadding: 16 - - Text { - text: "• Test Item 1, 2, 3 - Show toast notifications" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - - Text { - text: "• Example Copy Action - Copy text to clipboard" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - - Text { - text: "• Example Script Action - Demonstrate script execution" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - } - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 8 - width: parent.width - 32 - - Text { - text: "Usage:" - font.pixelSize: 14 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Column { - spacing: 4 - leftPadding: 16 - bottomPadding: 24 - - Text { - text: "1. Open Launcher (Ctrl+Space or click launcher button)" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - - Text { - text: noTriggerToggle.checked ? "2. Items are always visible in the launcher" : "2. Type your trigger (default: #) to filter to this plugin" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - - Text { - text: noTriggerToggle.checked ? "3. Search works normally with plugin items included" : "3. Optionally add search terms: '# test' to find test items" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - - Text { - text: "4. Select an item and press Enter to execute its action" - font.pixelSize: 12 - color: "#CCFFFFFF" - } - } - } - } - - function saveSettings(key, value) { - if (pluginService) { - pluginService.savePluginData("launcherExample", key, value) - } - } - - function loadSettings(key, defaultValue) { - if (pluginService) { - return pluginService.loadPluginData("launcherExample", key, defaultValue) - } - return defaultValue - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md deleted file mode 100644 index db34b83..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md +++ /dev/null @@ -1,244 +0,0 @@ -# LauncherExample Plugin - -A demonstration plugin that showcases the DMS launcher plugin system capabilities. - -## Purpose - -This plugin serves as a comprehensive example for developers creating launcher plugins for DMS. It demonstrates: - -- **Plugin Structure**: Proper manifest, launcher, and settings components -- **Trigger System**: Customizable trigger strings for plugin activation (including empty triggers) -- **Item Management**: Providing searchable items to the launcher -- **Action Execution**: Handling different types of actions (toast, copy, script) -- **Settings Integration**: Configurable plugin settings with persistence - -## Features - -### Example Items -- **Test Items 1-3**: Demonstrate toast notifications -- **Copy Action**: Shows clipboard integration -- **Script Action**: Demonstrates command execution - -### Trigger System -- **Default Trigger**: `#` (configurable in settings) -- **Empty Trigger Option**: Items can always be visible without needing a trigger -- **Usage**: Type `#` in launcher to filter to this plugin (when trigger is set) -- **Search**: Type `# test` to search within plugin items - -### Action Types -- `toast:message` - Shows toast notification -- `copy:text` - Copies text to clipboard -- `script:command` - Executes shell command (demo only) - -## File Structure - -``` -PLUGINS/LauncherExample/ -├── plugin.json # Plugin manifest -├── LauncherExampleLauncher.qml # Main launcher component -├── LauncherExampleSettings.qml # Settings interface -└── README.md # This documentation -``` - -## Installation - -1. **Plugin Directory**: Copy to `~/.config/DankMaterialShell/plugins/LauncherExample` -2. **Enable Plugin**: Settings → Plugins → Enable "LauncherExample" -3. **Configure**: Set custom trigger in plugin settings if desired - -## Usage - -### With Trigger (Default) -1. Open launcher (Ctrl+Space or launcher button) -2. Type `#` to activate plugin trigger -3. Browse available items or add search terms -4. Press Enter to execute selected item - -### Without Trigger (Empty Trigger Mode) -1. Enable "No trigger (always show)" in plugin settings -2. Open launcher - plugin items are always visible -3. Search works normally with plugin items included -4. Press Enter to execute selected item - -### Search Examples -- `#` - Show all plugin items (with trigger enabled) -- `# test` - Show items matching "test" -- `# copy` - Show items matching "copy" -- `test` - Show all items matching "test" (with empty trigger enabled) - -## Developer Guide - -### Plugin Contract - -**Launcher Component Requirements**: -```qml -// Required properties -property var pluginService: null -property string trigger: "#" - -// Required signals -signal itemsChanged() - -// Required functions -function getItems(query): array -function executeItem(item): void - -// Optional functions (for Shift+Enter paste support) -function getPasteText(item): string|null -function getPasteArgs(item): array|null -``` - -**Item Structure**: -```javascript -{ - name: "Item Name", // Display name - icon: "icon_name", // Icon (optional, see Icon Types below) - comment: "Description", // Subtitle text - action: "type:data", // Action to execute - categories: ["PluginName"] // Category array -} -``` - -**Icon Types**: - -The `icon` field supports four formats: - -1. **Material Design Icons** - Use `material:` prefix: - ```javascript - icon: "material:lightbulb" // Material Symbols Rounded font - ``` - Examples: `material:star`, `material:favorite`, `material:settings` - -2. **Unicode/Emoji Icons** - Use `unicode:` prefix: - ```javascript - icon: "unicode:🚀" // Unicode character or emoji - ``` - Display any Unicode character or emoji as the icon. Examples: `unicode:😀`, `unicode:⚡`, `unicode:🎨` - -3. **Desktop Theme Icons** - Use icon name directly: - ```javascript - icon: "firefox" // Uses system icon theme - ``` - Examples: `firefox`, `chrome`, `folder`, `text-editor` - -4. **No Icon** - Omit the `icon` field entirely: - ```javascript - { - name: "😀 Grinning Face", - // No icon field - comment: "Copy emoji", - action: "copy:😀", - categories: ["MyPlugin"] - } - ``` - When icon is omitted, the launcher hides the icon area and displays only text - -**Action Format**: `type:data` where: -- `type` - Action handler (toast, copy, script, etc.) -- `data` - Action-specific data - -### Settings Integration -```qml -// Save setting -pluginService.savePluginData("pluginId", "key", value) - -// Load setting -pluginService.loadPluginData("pluginId", "key", defaultValue) -``` - -### Trigger Configuration - -The trigger can be configured in two ways: - -1. **Empty Trigger** (No Trigger Mode): - - Check "No trigger (always show)" in settings - - Saves `trigger: ""` and `noTrigger: true` - - Items always appear in launcher alongside regular apps - -2. **Custom Trigger**: - - Enter any string (e.g., `#`, `!`, `@`, `!ex`) - - Uncheck "No trigger" checkbox - - Items only appear when trigger is typed - -### Manifest Structure -```json -{ - "id": "launcherExample", - "name": "LauncherExample", - "type": "launcher", - "capabilities": ["launcher"], - "component": "./LauncherExampleLauncher.qml", - "settings": "./LauncherExampleSettings.qml", - "permissions": ["settings_read", "settings_write"] -} -``` - -Note: The `trigger` field in the manifest is optional and serves as the default trigger value. - -## Extending This Plugin - -### Adding New Items -```qml -function getItems(query) { - return [ - { - name: "My Item", - icon: "custom_icon", - comment: "Does something cool", - action: "custom:action_data", - categories: ["LauncherExample"] - } - ] -} -``` - -### Adding New Actions -```qml -function executeItem(item) { - const actionParts = item.action.split(":") - const actionType = actionParts[0] - const actionData = actionParts.slice(1).join(":") - - switch (actionType) { - case "custom": - handleCustomAction(actionData) - break - } -} -``` - -### Custom Trigger Logic -```qml -Component.onCompleted: { - if (pluginService) { - trigger = pluginService.loadPluginData("launcherExample", "trigger", "#") - } -} - -onTriggerChanged: { - if (pluginService) { - pluginService.savePluginData("launcherExample", "trigger", trigger) - } -} -``` - -## Best Practices - -1. **Unique Triggers**: Choose triggers that don't conflict with other plugins -2. **Clear Descriptions**: Write helpful item comments -3. **Error Handling**: Gracefully handle action failures -4. **Performance**: Return results quickly in getItems() -5. **Cleanup**: Destroy temporary objects in executeItem() -6. **Empty Trigger Support**: Consider if your plugin should support empty trigger mode - -## Testing - -Test the plugin by: -1. Installing and enabling in DMS -2. Testing with trigger enabled -3. Testing with empty trigger (no trigger mode) -4. Trying each action type -5. Testing search functionality -6. Verifying settings persistence - -This plugin provides a solid foundation for building more sophisticated launcher plugins with custom functionality! diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json deleted file mode 100644 index c95b302..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "launcherExample", - "name": "LauncherExample", - "description": "Example launcher plugin demonstrating the launcher plugin system", - "version": "1.0.0", - "author": "DMS Team", - "icon": "extension", - "type": "launcher", - "capabilities": ["clipboard", "command-execution"], - "component": "./LauncherExampleLauncher.qml", - "settings": "./LauncherExampleSettings.qml", - "trigger": "#", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml deleted file mode 100644 index 2e85570..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import Quickshell -import qs.Services - -QtObject { - id: root - - property var pluginService: null - property string trigger: "img" - - signal itemsChanged - - readonly property var images: [ - { - name: "DankDash", - imageUrl: "https://danklinux.com/img/dankdash.png", - comment: "DankMaterialShell Dashboard" - }, - { - name: "Control Center", - imageUrl: "https://danklinux.com/img/cc.png", - comment: "System Control Center" - }, - { - name: "Desktop", - imageUrl: "https://danklinux.com/img/desktop.png", - comment: "Desktop Environment" - }, - { - name: "Search", - imageUrl: "https://danklinux.com/img/dsearch.png", - comment: "Application Search" - }, - { - name: "Theme Registry", - imageUrl: "https://danklinux.com/img/blog/v1.2/themeregistry.png", - comment: "Theme Registry Browser" - }, - { - name: "Monitor Settings", - imageUrl: "https://danklinux.com/img/blog/v1.2/monitordark.png", - comment: "Display Configuration" - } - ] - - function getItems(query) { - const lowerQuery = query ? query.toLowerCase().trim() : ""; - - if (lowerQuery.length === 0) { - return images.map(img => ({ - name: img.name, - icon: "material:image", - comment: img.comment, - action: "view:" + img.imageUrl, - categories: ["Image Gallery"], - imageUrl: img.imageUrl - })); - } - - return images.filter(img => img.name.toLowerCase().includes(lowerQuery) || img.comment.toLowerCase().includes(lowerQuery)).map(img => ({ - name: img.name, - icon: "material:image", - comment: img.comment, - action: "view:" + img.imageUrl, - categories: ["Image Gallery"], - imageUrl: img.imageUrl - })); - } - - function executeItem(item) { - if (!item?.action) - return; - const actionParts = item.action.split(":"); - const actionType = actionParts[0]; - const actionData = actionParts.slice(1).join(":"); - - if (actionType === "view") { - if (typeof ToastService !== "undefined") { - ToastService.showInfo("Image Gallery", "Viewing: " + item.name); - } - } - } - - function getContextMenuActions(item) { - if (!item) - return []; - return [ - { - icon: "open_in_new", - text: "Open in Browser", - action: () => { - const url = item.imageUrl || ""; - if (url) { - Qt.openUrlExternally(url); - } - } - }, - { - icon: "content_copy", - text: "Copy URL", - action: () => { - const url = item.imageUrl || ""; - if (url) { - Quickshell.execDetached(["dms", "cl", "copy", url]); - if (typeof ToastService !== "undefined") { - ToastService.showInfo("Copied", url); - } - } - } - } - ]; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md deleted file mode 100644 index 13b608d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# LauncherImageExample - -Example launcher plugin demonstrating tile mode with URL-based images. - -## Features - -- **Tile Mode**: Uses `viewMode: "tile"` in plugin.json to display results as image tiles -- **Enforced View Mode**: Uses `viewModeEnforced: true` to lock the view to tile mode (users cannot change it) -- **URL Images**: Demonstrates using `imageUrl` property for remote images - -## Usage - -1. Open the launcher (DankLauncherV2) -2. Type `img` to activate the plugin -3. Browse DankMaterialShell screenshots in tile view - -## Plugin Configuration - -```json -{ - "viewMode": "tile", - "viewModeEnforced": true -} -``` - -- `viewMode`: Sets the default view mode ("list", "grid", or "tile") -- `viewModeEnforced`: When true, users cannot switch view modes for this plugin - -## Item Data Structure - -To display images in tile mode, set `imageUrl` directly on the item: - -```javascript -{ - name: "Image Title", - icon: "material:image", - comment: "Image description", - categories: ["Category"], - imageUrl: "https://example.com/image.png" -} -``` - -The `imageUrl` property supports remote URLs or local files, use `file://` prefix for local files. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json deleted file mode 100644 index a3069e1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "launcherImageExample", - "name": "Image Gallery Example", - "description": "Example launcher plugin demonstrating tile mode with images", - "version": "1.0.0", - "author": "DMS Team", - "icon": "photo_library", - "type": "launcher", - "trigger": "img", - "viewMode": "tile", - "viewModeEnforced": true, - "component": "./LauncherImageExample.qml", - "permissions": [] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md deleted file mode 100644 index e4f556f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md +++ /dev/null @@ -1,294 +0,0 @@ -# PopoutService for Plugins - -## Overview - -The `PopoutService` singleton provides plugins with access to all DankMaterialShell popouts and modals. It's automatically injected into plugin widgets and daemons, enabling them to control shell UI elements. - -## Automatic Injection - -The `popoutService` property is automatically injected into: - -- Widget plugins (loaded in DankBar) -- Daemon plugins (background services) -- Plugin settings components - -**Required**: Declare the property in your plugin component: - -```qml -property var popoutService: null -``` - -**Note**: Without this declaration, the service cannot be injected and you'll see errors like `Cannot assign to non-existent property "popoutService"` - -## API Reference - -### Popouts (DankPopout-based) - -| Component | Open | Close | Toggle | -| ------------------- | -------------------------- | --------------------------- | ---------------------------- | -| Control Center | `openControlCenter()` | `closeControlCenter()` | `toggleControlCenter()` | -| Notification Center | `openNotificationCenter()` | `closeNotificationCenter()` | `toggleNotificationCenter()` | -| App Drawer | `openAppDrawer()` | `closeAppDrawer()` | `toggleAppDrawer()` | -| Process List | `openProcessList()` | `closeProcessList()` | `toggleProcessList()` | -| DankDash | `openDankDash(tab)` | `closeDankDash()` | `toggleDankDash(tab)` | -| Battery | `openBattery()` | `closeBattery()` | `toggleBattery()` | -| VPN | `openVpn()` | `closeVpn()` | `toggleVpn()` | -| System Update | `openSystemUpdate()` | `closeSystemUpdate()` | `toggleSystemUpdate()` | - -### Modals (DankModal-based) - -| Modal | Show | Hide | Notes | -| ------------------ | ------------------------- | ------------------------- | -------------------------------------------------- | -| Settings | `openSettings()` | `closeSettings()` | Full settings interface | -| Clipboard History | `openClipboardHistory()` | `closeClipboardHistory()` | Clipboard integration | -| Launcher | `openDankLauncherV2()` | `closeDankLauncherV2()` | Command launcher, also has `toggleDankLauncherV2()` | -| Power Menu | `openPowerMenu()` | `closePowerMenu()` | Also has `togglePowerMenu()` | -| Process List Modal | `showProcessListModal()` | `hideProcessListModal()` | Fullscreen version, has `toggleProcessListModal()` | -| Color Picker | `showColorPicker()` | `hideColorPicker()` | Theme color selection | -| Notification | `showNotificationModal()` | `hideNotificationModal()` | Notification details | -| WiFi Password | `showWifiPasswordModal()` | `hideWifiPasswordModal()` | Network authentication | -| Network Info | `showNetworkInfoModal()` | `hideNetworkInfoModal()` | Network details | - -### Slideouts - -| Component | Open | Close | Toggle | -| --------- | --------------- | ---------------- | ----------------- | -| Notepad | `openNotepad()` | `closeNotepad()` | `toggleNotepad()` | - -## Usage Examples - -### Simple Widget with Popout Control - -```qml -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property var popoutService: null - - width: 100 - height: 30 - color: Theme.surfaceContainerHigh - radius: Theme.cornerRadius - - MouseArea { - anchors.fill: parent - onClicked: popoutService?.toggleControlCenter() - } - - StyledText { - anchors.centerIn: parent - text: "Settings" - } -} -``` - -### Daemon with Event-Driven Popouts - -```qml -import QtQuick -import qs.Services - -Item { - id: root - - property var popoutService: null - - Connections { - target: NotificationService - - function onNotificationReceived(notification) { - if (notification.urgency === "critical") { - popoutService?.openNotificationCenter() - } - } - } - - Connections { - target: BatteryService - - function onPercentageChanged() { - if (BatteryService.percentage < 10 && !BatteryService.isCharging) { - popoutService?.openBattery() - } - } - } -} -``` - -### Widget with Multiple Popout Options - -```qml -import QtQuick -import QtQuick.Controls -import qs.Common - -Rectangle { - property var popoutService: null - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onClicked: (mouse) => { - if (mouse.button === Qt.RightButton) { - contextMenu.popup() - } else { - popoutService?.toggleControlCenter() - } - } - } - - Menu { - id: contextMenu - - MenuItem { - text: "Settings" - onClicked: popoutService?.openSettings() - } - - MenuItem { - text: "Notifications" - onClicked: popoutService?.toggleNotificationCenter() - } - - MenuItem { - text: "Power Menu" - onClicked: popoutService?.openPowerMenu() - } - } -} -``` - -## Implementation Details - -### Service Architecture - -`PopoutService` is a singleton that holds references to popout instances: - -```qml -// Services/PopoutService.qml -Singleton { - id: root - - property var controlCenterPopout: null - property var notificationCenterPopout: null - // ... other popout references - - function toggleControlCenter() { - controlCenterPopout?.toggle() - } - // ... other control functions -} -``` - -### Reference Assignment - -References are assigned in `DMSShell.qml` when popouts are loaded: - -```qml -LazyLoader { - ControlCenterPopout { - id: controlCenterPopout - - Component.onCompleted: { - PopoutService.controlCenterPopout = controlCenterPopout - } - } -} -``` - -### Plugin Injection - -The service is injected in three locations: - -1. **DMSShell.qml** (daemon plugins): - -```qml -Instantiator { - delegate: Loader { - onLoaded: { - if (item) { - item.popoutService = PopoutService - } - } - } -} -``` - -2. **WidgetHost.qml** (widget plugins): - -```qml -onLoaded: { - if (item.popoutService !== undefined) { - item.popoutService = PopoutService - } -} -``` - -3. **CenterSection.qml** (center widgets): - -```qml -onLoaded: { - if (item.popoutService !== undefined) { - item.popoutService = PopoutService - } -} -``` - -4. **PluginsTab.qml** (settings): - -```qml -onLoaded: { - if (item && typeof PopoutService !== "undefined") { - item.popoutService = PopoutService - } -} -``` - -## Best Practices - -1. **Use Optional Chaining**: Always use `?.` to handle null cases - - ```qml - popoutService?.toggleControlCenter() - ``` - -2. **Check Availability**: Some popouts may not be available - - ```qml - if (popoutService && popoutService.controlCenterPopout) { - popoutService.toggleControlCenter() - } - ``` - -3. **Lazy Loading**: First access may activate lazy loaders - this is normal - -4. **Feature Detection**: Some popouts require specific features - - ```qml - if (BatteryService.batteryAvailable) { - popoutService?.openBattery() - } - ``` - -5. **User Intent**: Only trigger popouts based on user actions or critical events - -## Example Plugin - -See `PLUGINS/PopoutControlExample/` for a complete working example that demonstrates: - -- Widget creation with popout controls -- Menu-based popout selection -- Proper service usage -- Error handling - -## Limitations - -- Popouts are shared across all plugins - avoid conflicts -- Some popouts may be compositor or feature-dependent -- Lazy-loaded popouts need activation before use -- Multi-monitor considerations apply to positioned popouts diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml deleted file mode 100644 index 374af30..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml +++ /dev/null @@ -1,98 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "popoutControlExample" - - StyledText { - width: parent.width - text: "Popout Control Settings" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StyledText { - width: parent.width - text: "Choose which popout/modal will open when clicking the widget" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - SelectionSetting { - settingKey: "selectedPopout" - label: "Popout to Open" - description: "Select which popout or modal opens when you click the widget" - options: [ - { - label: "Control Center", - value: "controlCenter" - }, - { - label: "Notification Center", - value: "notificationCenter" - }, - { - label: "App Drawer", - value: "appDrawer" - }, - { - label: "Process List", - value: "processList" - }, - { - label: "DankDash", - value: "dankDash" - }, - { - label: "Battery Info", - value: "battery" - }, - { - label: "VPN", - value: "vpn" - }, - { - label: "System Update", - value: "systemUpdate" - }, - { - label: "Settings", - value: "settings" - }, - { - label: "Clipboard History", - value: "clipboardHistory" - }, - { - label: "Spotlight", - value: "spotlight" - }, - { - label: "Power Menu", - value: "powerMenu" - }, - { - label: "Color Picker", - value: "colorPicker" - }, - { - label: "Notepad", - value: "notepad" - } - ] - defaultValue: "controlCenter" - } - - StyledText { - width: parent.width - text: "💡 Tip: The widget displays the name of the selected popout and opens it when clicked!" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml deleted file mode 100644 index fdbf89f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml +++ /dev/null @@ -1,93 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - property var popoutService: null - - property string selectedPopout: pluginData.selectedPopout || "controlCenter" - - property var popoutActions: ({ - "controlCenter": (x, y, w, s, scr) => popoutService?.toggleControlCenter(x, y, w, s, scr), - "notificationCenter": (x, y, w, s, scr) => popoutService?.toggleNotificationCenter(x, y, w, s, scr), - "appDrawer": (x, y, w, s, scr) => popoutService?.toggleAppDrawer(x, y, w, s, scr), - "processList": (x, y, w, s, scr) => popoutService?.toggleProcessList(x, y, w, s, scr), - "dankDash": (x, y, w, s, scr) => popoutService?.toggleDankDash(0, x, y, w, s, scr), - "battery": (x, y, w, s, scr) => popoutService?.toggleBattery(x, y, w, s, scr), - "vpn": (x, y, w, s, scr) => popoutService?.toggleVpn(x, y, w, s, scr), - "systemUpdate": (x, y, w, s, scr) => popoutService?.toggleSystemUpdate(x, y, w, s, scr), - "settings": () => popoutService?.openSettings(), - "clipboardHistory": () => popoutService?.openClipboardHistory(), - "spotlight": () => popoutService?.toggleDankLauncherV2(), - "powerMenu": () => popoutService?.togglePowerMenu(), - "colorPicker": () => popoutService?.showColorPicker(), - "notepad": () => popoutService?.toggleNotepad() - }) - - property var popoutNames: ({ - "controlCenter": "Control Center", - "notificationCenter": "Notification Center", - "appDrawer": "App Drawer", - "processList": "Process List", - "dankDash": "DankDash", - "battery": "Battery Info", - "vpn": "VPN", - "systemUpdate": "System Update", - "settings": "Settings", - "clipboardHistory": "Clipboard", - "spotlight": "Spotlight", - "powerMenu": "Power Menu", - "colorPicker": "Color Picker", - "notepad": "Notepad" - }) - - pillClickAction: (x, y, width, section, screen) => { - if (popoutActions[selectedPopout]) { - popoutActions[selectedPopout](x, y, width, section, screen); - } - } - - horizontalBarPill: Component { - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "widgets" - color: Theme.primary - font.pixelSize: Theme.iconSize - 6 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: popoutNames[selectedPopout] || "Popouts" - color: Theme.primary - font.pixelSize: Theme.fontSizeMedium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - verticalBarPill: Component { - Column { - spacing: Theme.spacingXS - - DankIcon { - name: "widgets" - color: Theme.primary - font.pixelSize: Theme.iconSize - 6 - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: popoutNames[selectedPopout] || "Popouts" - color: Theme.primary - font.pixelSize: Theme.fontSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md deleted file mode 100644 index d1fb54a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md +++ /dev/null @@ -1,208 +0,0 @@ -# Popout Control Example Plugin - -This example plugin demonstrates: -- Using `PopoutService` to trigger positioned popouts and modals -- Using `pillClickAction` with position parameters -- Using `PluginSettings` with dropdown selection -- Dynamic widget text based on settings - -The `pillClickAction` receives position parameters `(x, y, width, section, screen)` which are passed to PopoutService functions to properly position popouts relative to the widget. - -## PopoutService API - -The `PopoutService` is automatically injected into plugin widgets and daemons as `popoutService`. It provides access to all shell popouts and modals. - -### Available Popouts - -#### Control Center -```qml -popoutService.openControlCenter() -popoutService.closeControlCenter() -popoutService.toggleControlCenter() -``` - -#### Notification Center -```qml -popoutService.openNotificationCenter() -popoutService.closeNotificationCenter() -popoutService.toggleNotificationCenter() -``` - -#### App Drawer -```qml -popoutService.openAppDrawer() -popoutService.closeAppDrawer() -popoutService.toggleAppDrawer() -``` - -#### Process List (Popout) -```qml -popoutService.openProcessList() -popoutService.closeProcessList() -popoutService.toggleProcessList() -``` - -#### DankDash -```qml -popoutService.openDankDash(tabIndex) // tabIndex: 0=Calendar, 1=Media, 2=Weather -popoutService.closeDankDash() -popoutService.toggleDankDash(tabIndex) -``` - -#### Battery Popout -```qml -popoutService.openBattery() -popoutService.closeBattery() -popoutService.toggleBattery() -``` - -#### VPN Popout -```qml -popoutService.openVpn() -popoutService.closeVpn() -popoutService.toggleVpn() -``` - -#### System Update Popout -```qml -popoutService.openSystemUpdate() -popoutService.closeSystemUpdate() -popoutService.toggleSystemUpdate() -``` - -### Available Modals - -#### Settings Modal -```qml -popoutService.openSettings() -popoutService.closeSettings() -``` - -#### Clipboard History Modal -```qml -popoutService.openClipboardHistory() -popoutService.closeClipboardHistory() -``` - -#### Launcher Modal -```qml -popoutService.openDankLauncherV2() -popoutService.closeDankLauncherV2() -popoutService.toggleDankLauncherV2() -``` - -#### Power Menu Modal -```qml -popoutService.openPowerMenu() -popoutService.closePowerMenu() -popoutService.togglePowerMenu() -``` - -#### Process List Modal (fullscreen) -```qml -popoutService.showProcessListModal() -popoutService.hideProcessListModal() -popoutService.toggleProcessListModal() -``` - -#### Color Picker Modal -```qml -popoutService.showColorPicker() -popoutService.hideColorPicker() -``` - -#### Notification Modal -```qml -popoutService.showNotificationModal() -popoutService.hideNotificationModal() -``` - -#### WiFi Password Modal -```qml -popoutService.showWifiPasswordModal() -popoutService.hideWifiPasswordModal() -``` - -#### Network Info Modal -```qml -popoutService.showNetworkInfoModal() -popoutService.hideNetworkInfoModal() -``` - -#### Notepad Slideout -```qml -popoutService.openNotepad() -popoutService.closeNotepad() -popoutService.toggleNotepad() -``` - -## Usage in Plugins - -### Widget Plugins - -```qml -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property var popoutService: null // REQUIRED: Must declare for injection - - MouseArea { - anchors.fill: parent - onClicked: { - popoutService?.toggleControlCenter() - } - } -} -``` - -### Daemon Plugins - -```qml -import QtQuick -import qs.Services - -Item { - id: root - - property var popoutService: null // REQUIRED: Must declare for injection - - Connections { - target: NotificationService - function onNotificationReceived() { - popoutService?.openNotificationCenter() - } - } -} -``` - -**Important**: The `popoutService` property **must** be declared in your plugin component. Without it, you'll get errors like: -``` -Error: Cannot assign to non-existent property "popoutService" -``` - -## Example Use Cases - -1. **Custom Launcher**: Create a widget that opens the app drawer -2. **Quick Settings**: Toggle control center from a custom button -3. **Notification Manager**: Open notification center on new notifications -4. **System Monitor**: Open process list on high CPU usage -5. **Power Management**: Trigger power menu from a custom widget - -## Installation - -1. Copy the plugin directory to `~/.config/DankMaterialShell/plugins/` -2. Open Settings → Plugins -3. Click "Scan for Plugins" -4. Enable "Popout Control Example" -5. Add `popoutControlExample` to your DankBar widget list - -## Notes - -- The `popoutService` property is automatically injected - no manual setup required -- Always use optional chaining (`?.`) when calling methods to handle null cases -- Popouts are lazily loaded - first access may activate the loader -- Some popouts require specific system features to be available diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json deleted file mode 100644 index 02042a0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "popoutControlExample", - "name": "Popout Control Example", - "description": "Example widget demonstrating PopoutService usage with pillClickAction", - "version": "1.0.0", - "author": "DankMaterialShell", - "type": "widget", - "capabilities": ["dankbar-widget"], - "component": "./PopoutControlWidget.qml", - "icon": "widgets", - "settings": "./PopoutControlSettings.qml", - "permissions": ["settings_read", "settings_write"] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml deleted file mode 100644 index 42e4001..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml +++ /dev/null @@ -1,174 +0,0 @@ -import QtQuick -import Quickshell -import qs.Services - -Item { - id: root - - property var pluginService: null - property string trigger: "n" - - signal itemsChanged - - property var notes: [] - property int maxNotes: 50 - - Component.onCompleted: { - if (!pluginService) - return; - trigger = pluginService.loadPluginData("quickNotesExample", "trigger", "n"); - maxNotes = pluginService.loadPluginData("quickNotesExample", "maxNotes", 50); - - // Load notes from plugin STATE (persistent across sessions, separate file) - notes = pluginService.loadPluginState("quickNotesExample", "notes", []); - } - - function getItems(query) { - const items = []; - - if (query && query.trim().length > 0) { - const text = query.trim(); - items.push({ - name: "Save note: " + text, - icon: "material:note_add", - comment: "Save as a new note", - action: "add:" + text, - categories: ["Quick Notes"] - }); - - items.push({ - name: "Copy: " + text, - icon: "material:content_copy", - comment: "Copy text to clipboard", - action: "copy:" + text, - categories: ["Quick Notes"] - }); - } - - const filteredNotes = query ? notes.filter(n => n.text.toLowerCase().includes(query.toLowerCase())) : notes; - - for (let i = 0; i < Math.min(20, filteredNotes.length); i++) { - const note = filteredNotes[i]; - const age = _formatAge(note.timestamp); - items.push({ - name: note.text, - icon: "material:sticky_note_2", - comment: age + " — select to copy, hold for options", - action: "copy:" + note.text, - categories: ["Quick Notes"] - }); - } - - if (notes.length > 0 && !query) { - items.push({ - name: "Clear all notes (" + notes.length + ")", - icon: "material:delete_sweep", - comment: "Remove all saved notes", - action: "clear:", - categories: ["Quick Notes"] - }); - } - - return items; - } - - function executeItem(item) { - if (!item?.action) - return; - - const colonIdx = item.action.indexOf(":"); - const actionType = item.action.substring(0, colonIdx); - const actionData = item.action.substring(colonIdx + 1); - - switch (actionType) { - case "add": - addNote(actionData); - break; - case "copy": - copyToClipboard(actionData); - break; - case "remove": - removeNote(actionData); - break; - case "clear": - clearAllNotes(); - break; - default: - showToast("Unknown action: " + actionType); - } - } - - function addNote(text) { - if (!text) - return; - - const existing = notes.findIndex(n => n.text === text); - if (existing !== -1) - notes.splice(existing, 1); - - notes.unshift({ - text: text, - timestamp: Date.now() - }); - - if (notes.length > maxNotes) - notes = notes.slice(0, maxNotes); - - _saveNotes(); - showToast("Note saved"); - } - - function removeNote(text) { - notes = notes.filter(n => n.text !== text); - _saveNotes(); - showToast("Note removed"); - } - - function clearAllNotes() { - notes = []; - pluginService.clearPluginState("quickNotesExample"); - showToast("All notes cleared"); - itemsChanged(); - } - - function _saveNotes() { - if (!pluginService) - return; - // Save to plugin STATE — writes to quickNotesExample_state.json - // This is separate from plugin SETTINGS (plugin_settings.json) - pluginService.savePluginState("quickNotesExample", "notes", notes); - itemsChanged(); - } - - function copyToClipboard(text) { - Quickshell.execDetached(["dms", "cl", "copy", text]); - showToast("Copied to clipboard"); - } - - function showToast(message) { - if (typeof ToastService !== "undefined") - ToastService.showInfo("Quick Notes", message); - } - - function _formatAge(timestamp) { - if (!timestamp) - return ""; - const seconds = Math.floor((Date.now() - timestamp) / 1000); - if (seconds < 60) - return "just now"; - const minutes = Math.floor(seconds / 60); - if (minutes < 60) - return minutes + "m ago"; - const hours = Math.floor(minutes / 60); - if (hours < 24) - return hours + "h ago"; - const days = Math.floor(hours / 24); - return days + "d ago"; - } - - onTriggerChanged: { - if (!pluginService) - return; - pluginService.savePluginData("quickNotesExample", "trigger", trigger); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml deleted file mode 100644 index 9659614..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml +++ /dev/null @@ -1,263 +0,0 @@ -import QtQuick -import qs.Widgets - -FocusScope { - id: root - - property var pluginService: null - - implicitHeight: settingsColumn.implicitHeight - height: implicitHeight - - Column { - id: settingsColumn - anchors.fill: parent - anchors.margins: 16 - spacing: 16 - - Text { - text: "Quick Notes Settings" - font.pixelSize: 18 - font.weight: Font.Bold - color: "#FFFFFF" - } - - Text { - text: "Demonstrates the plugin state API — notes are stored in a separate state file (quickNotesExample_state.json) rather than plugin_settings.json." - font.pixelSize: 14 - color: "#CCFFFFFF" - wrapMode: Text.WordWrap - width: parent.width - 32 - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 12 - width: parent.width - 32 - - Text { - text: "Trigger Configuration" - font.pixelSize: 16 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Row { - spacing: 12 - anchors.left: parent.left - anchors.right: parent.right - - Text { - text: "Trigger:" - font.pixelSize: 14 - color: "#FFFFFF" - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - id: triggerField - width: 100 - height: 40 - text: loadSettings("trigger", "n") - placeholderText: "n" - backgroundColor: "#30FFFFFF" - textColor: "#FFFFFF" - - onTextEdited: { - saveSettings("trigger", text.trim() || "n"); - } - } - } - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 12 - width: parent.width - 32 - - Text { - text: "Storage" - font.pixelSize: 16 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Row { - spacing: 12 - - Text { - text: "Max notes:" - font.pixelSize: 14 - color: "#FFFFFF" - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - id: maxNotesField - width: 80 - height: 40 - text: loadSettings("maxNotes", 50).toString() - placeholderText: "50" - backgroundColor: "#30FFFFFF" - textColor: "#FFFFFF" - - onTextEdited: { - const val = parseInt(text); - if (!isNaN(val) && val > 0) - saveSettings("maxNotes", val); - } - } - } - - Text { - text: { - const count = loadState("notes", []).length; - return "Currently storing " + count + " note(s)"; - } - font.pixelSize: 12 - color: "#AAFFFFFF" - } - - Rectangle { - width: clearRow.implicitWidth + 24 - height: clearRow.implicitHeight + 16 - radius: 8 - color: clearMouseArea.containsMouse ? "#40FF5252" : "#30FF5252" - - Row { - id: clearRow - anchors.centerIn: parent - spacing: 8 - - Text { - text: "🗑" - font.pixelSize: 14 - anchors.verticalCenter: parent.verticalCenter - } - - Text { - text: "Clear all notes" - font.pixelSize: 14 - color: "#FF5252" - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: clearMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (pluginService) { - pluginService.clearPluginState("quickNotesExample"); - } - } - } - } - } - - Rectangle { - width: parent.width - 32 - height: 1 - color: "#30FFFFFF" - } - - Column { - spacing: 8 - width: parent.width - 32 - - Text { - text: "API Usage (for plugin developers):" - font.pixelSize: 14 - font.weight: Font.Medium - color: "#FFFFFF" - } - - Column { - spacing: 4 - leftPadding: 16 - bottomPadding: 24 - - Text { - text: "• pluginService.savePluginState(id, key, value)" - font.pixelSize: 12 - color: "#CCFFFFFF" - font.family: "monospace" - } - - Text { - text: " Writes to ~/.local/state/.../id_state.json" - font.pixelSize: 11 - color: "#AAFFFFFF" - } - - Text { - text: "• pluginService.loadPluginState(id, key, default)" - font.pixelSize: 12 - color: "#CCFFFFFF" - font.family: "monospace" - } - - Text { - text: " Reads from the per-plugin state file" - font.pixelSize: 11 - color: "#AAFFFFFF" - } - - Text { - text: "• pluginService.clearPluginState(id)" - font.pixelSize: 12 - color: "#CCFFFFFF" - font.family: "monospace" - } - - Text { - text: " Clears all state for a plugin" - font.pixelSize: 11 - color: "#AAFFFFFF" - } - - Text { - text: "• pluginService.removePluginStateKey(id, key)" - font.pixelSize: 12 - color: "#CCFFFFFF" - font.family: "monospace" - } - - Text { - text: " Removes a single key from plugin state" - font.pixelSize: 11 - color: "#AAFFFFFF" - } - } - } - } - - function saveSettings(key, value) { - if (pluginService) - pluginService.savePluginData("quickNotesExample", key, value); - } - - function loadSettings(key, defaultValue) { - if (pluginService) - return pluginService.loadPluginData("quickNotesExample", key, defaultValue); - return defaultValue; - } - - function loadState(key, defaultValue) { - if (pluginService) - return pluginService.loadPluginState("quickNotesExample", key, defaultValue); - return defaultValue; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json deleted file mode 100644 index fcf3458..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "quickNotesExample", - "name": "Quick Notes", - "description": "Example launcher plugin demonstrating the plugin state API for persistent data like history and notes", - "version": "1.0.0", - "author": "DankMaterialShell", - "icon": "sticky_note_2", - "type": "launcher", - "capabilities": ["clipboard"], - "component": "./QuickNotesLauncher.qml", - "settings": "./QuickNotesSettings.qml", - "trigger": "n", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md deleted file mode 100644 index f7bed6a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md +++ /dev/null @@ -1,1665 +0,0 @@ -# Plugin System - -Create widgets for DankBar and Control Center using dynamically-loaded QML components. - -## Plugin Registry - -Browse and discover community plugins at **https://plugins.danklinux.com/** - -## Overview - -Plugins let you add custom widgets to DankBar and Control Center. They're discovered from `~/.config/DankMaterialShell/plugins/` and managed via PluginService. - -## Architecture - -### Core Components - -1. **PluginService** (`Services/PluginService.qml`) - - Singleton service managing plugin lifecycle - - Discovers plugins from `$CONFIGPATH/DankMaterialShell/plugins/` - - Handles loading, unloading, and state management - - Provides data persistence for plugin settings - -2. **PluginsTab** (`Modules/Settings/PluginsTab.qml`) - - UI for managing available plugins - - Access plugin settings - -3. **PluginsTab Settings** (`Modules/Settings/PluginsTab.qml`) - - Accordion-style plugin configuration interface - - Dynamically loads plugin settings components inline - - Provides consistent settings interface with proper focus handling - -4. **DankBar Integration** (`Modules/DankBar/DankBar.qml`) - - Renders plugin widgets in the bar - - Merges plugin components with built-in widgets - - Supports left, center, and right sections - - Supports any dankbar position (top/left/right/bottom) - -## Plugin Structure - -Each plugin must be a directory in `$CONFIGPATH/DankMaterialShell/plugins/` containing: - -``` -$CONFIGPATH/DankMaterialShell/plugins/YourPlugin/ -├── plugin.json # Required: Plugin manifest -├── YourWidget.qml # Required: Widget component -├── YourSettings.qml # Optional: Settings UI -└── *.js # Optional: JavaScript utilities -``` - -### Plugin Manifest (plugin.json) - -The manifest file defines plugin metadata and configuration. - -**JSON Schema:** See `plugin-schema.json` for the complete specification and validation schema. - -```json -{ - "id": "yourPlugin", - "name": "Your Plugin Name", - "description": "Brief description of what your plugin does", - "version": "1.0.0", - "author": "Your Name", - "type": "widget", - "capabilities": ["thing-my-plugin-does"], - "component": "./YourWidget.qml", - "icon": "material_icon_name", - "settings": "./YourSettings.qml", - "requires_dms": ">=0.1.0", - "requires": ["some-system-tool"], - "permissions": [ - "settings_read", - "settings_write" - ] -} -``` - -**Required Fields:** -- `id`: Unique plugin identifier (camelCase, no spaces) -- `name`: Human-readable plugin name -- `description`: Short description of plugin functionality (displayed in UI) -- `version`: Semantic version string (e.g., "1.0.0") -- `author`: Plugin creator name or email -- `type`: Plugin type - "widget", "daemon", "launcher", or "desktop" -- `capabilities`: Array of plugin capabilities (e.g., ["dankbar-widget"], ["control-center"], ["monitoring"]) -- `component`: Relative path to main QML component file - -**Required for Launcher Type:** -- `trigger`: Trigger string for launcher activation (e.g., "=", "#", "!") - -**Optional Fields:** -- `icon`: Material Design icon name (displayed in UI) -- `settings`: Path to settings component (enables settings UI) -- `requires_dms`: Minimum DMS version requirement (e.g., ">=0.1.18", ">0.1.0") -- `requires`: Array of required system tools/dependencies (e.g., ["curl", "jq"]) -- `permissions`: Required DMS permissions (e.g., ["settings_read", "settings_write"]) - -**Permissions:** - -The plugin system enforces permissions when settings are accessed: -- `settings_read`: Required to read plugin settings (currently not enforced) -- `settings_write`: **Required** to use PluginSettings component and save settings - -If your plugin includes a settings component but doesn't declare `settings_write` permission, users will see an error message instead of the settings UI. - -### Widget Component - -The main widget component uses the **PluginComponent** wrapper which provides automatic property injection and bar integration: - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - // Define horizontal bar pill, for top and bottom DankBar positions (optional) - horizontalBarPill: Component { - StyledRect { - width: content.implicitWidth + Theme.spacingM * 2 - height: parent.widgetThickness - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - StyledText { - id: content - anchors.centerIn: parent - text: "Hello World" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - } - } - } - - // Define vertical bar pill, for left and right DankBar positions (optional) - verticalBarPill: Component { - // Same as horizontal but optimized for vertical layout - } - - // Define popout content, opens when clicking the bar pill (optional) - popoutContent: Component { - PopoutComponent { - headerText: "My Plugin" - detailsText: "Optional description text goes here" - showCloseButton: true - - // Your popout content goes here - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: "Popout Content" - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - } - } - } - } - - // Popout dimensions (required if popoutContent is set) - popoutWidth: 400 - popoutHeight: 300 -} -``` - -**PluginComponent Properties (automatically injected):** -- `axis`: Bar axis information (horizontal/vertical) -- `section`: Bar section ("left", "center", "right") -- `parentScreen`: Screen reference for multi-monitor support -- `widgetThickness`: Recommended widget size perpendicular to bar -- `barThickness`: Bar thickness parallel to edge - -**Component Options:** -- `horizontalBarPill`: Component shown in horizontal bars -- `verticalBarPill`: Component shown in vertical bars -- `popoutContent`: Optional popout window content -- `popoutWidth`: Popout window width -- `popoutHeight`: Popout window height -- `pillClickAction`: Custom click handler function (overrides popout) -- `pillRightClickAction`: Custom right click handler function - -### Control Center Integration - -Add your plugin to Control Center by defining CC properties: - -```qml -PluginComponent { - ccWidgetIcon: "toggle_on" - ccWidgetPrimaryText: "My Feature" - ccWidgetSecondaryText: isEnabled ? "Active" : "Inactive" - ccWidgetIsActive: isEnabled - - onCcWidgetToggled: { - isEnabled = !isEnabled - if (pluginService) { - pluginService.savePluginData("myPlugin", "isEnabled", isEnabled) - } - } - - ccDetailContent: Component { - Rectangle { - implicitHeight: 200 - color: Theme.surfaceContainerHigh - radius: Theme.cornerRadius - // Your detail UI here - } - } - - horizontalBarPill: Component { /* ... */ } -} -``` - -**CC Properties:** -- `ccWidgetIcon`: Material icon name -- `ccWidgetPrimaryText`: Main label -- `ccWidgetSecondaryText`: Subtitle/status -- `ccWidgetIsActive`: Active state styling -- `ccDetailContent`: Optional dropdown panel (use for CompoundPill) - -**Signals:** -- `ccWidgetToggled()`: Fired when icon clicked -- `ccWidgetExpanded()`: Fired when expand area clicked (CompoundPill only) - -**Widget Sizing:** -- 25% width → SmallToggleButton (icon only) -- 50% width → ToggleButton (no detail) or CompoundPill (with detail) -- Users can resize in edit mode - -**Custom Click Actions:** - -Override default popout with `pillClickAction` and `pillRightClickAction`: - -```qml -pillClickAction: () => { - Process.exec("bash", ["-c", "notify-send 'Clicked!'"]) -} - -// Or with position params: (x, y, width, section, screen) -pillClickAction: (x, y, width, section, screen) => { - popoutService?.toggleControlCenter(x, y, width, section, screen) -} - -pillRightClickAction: () => { - Process.exec("bash", ["-c", "notify-send 'Right clicked!'"]) -} - -pillRightClickAction: (x, y, width, section, screen) => { - popoutService?.toggleControlCenter(x, y, width, section, screen) -} -``` - -The PluginComponent automatically handles: -- Bar orientation detection -- Click handlers for popouts -- Proper positioning and anchoring -- Theme integration - -### PopoutComponent - -PopoutComponent provides a consistent header/content layout for plugin popouts: - -```qml -import qs.Modules.Plugins - -PopoutComponent { - headerText: "Header Title" // Main header text (bold, large) - detailsText: "Description text" // Optional description (smaller, gray) - showCloseButton: true // Show X button in top-right - - // Access to exposed properties for dynamic sizing - readonly property int headerHeight // Height of header area - readonly property int detailsHeight // Height of description area - - // Your content here - use parent.width for full width - // Calculate available height: root.popoutHeight - headerHeight - detailsHeight - spacing - DankGridView { - width: parent.width - height: parent.height - // ... - } -} -``` - -**PopoutComponent Properties:** -- `headerText`: Main header text (optional, hidden if empty) -- `detailsText`: Description text below header (optional, hidden if empty) -- `showCloseButton`: Show close button in header (default: false) -- `closePopout`: Function to close popout (auto-injected by PluginPopout) -- `headerHeight`: Readonly height of header (0 if not visible) -- `detailsHeight`: Readonly height of description (0 if not visible) - -The component automatically handles spacing and layout. Content children are rendered below the description with proper padding. - -### Settings Component - -Optional settings UI loaded inline in the PluginsTab accordion interface. Use the simplified settings API with auto-storage components: - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "yourPlugin" - - StringSetting { - settingKey: "apiKey" - label: "API Key" - description: "Your API key for accessing the service" - placeholder: "Enter API key..." - } - - ToggleSetting { - settingKey: "notifications" - label: "Enable Notifications" - description: "Show desktop notifications for updates" - defaultValue: true - } - - SelectionSetting { - settingKey: "updateInterval" - label: "Update Interval" - description: "How often to refresh data" - options: [ - {label: "1 minute", value: "60"}, - {label: "5 minutes", value: "300"}, - {label: "15 minutes", value: "900"} - ] - defaultValue: "300" - } - - ListSetting { - id: itemList - settingKey: "items" - label: "Saved Items" - description: "List of configured items" - delegate: Component { - StyledRect { - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: modelData.name - color: Theme.surfaceText - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 60 - height: 28 - color: removeArea.containsMouse ? Theme.errorHover : Theme.error - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: "Remove" - color: Theme.errorText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - } - - MouseArea { - id: removeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: itemList.removeItem(index) - } - } - } - } - } -} -``` - -**Available Setting Components:** - -All settings automatically save on change and load on component creation. - -**How Default Values Work:** - -Each setting component has a `defaultValue` property that is used when no saved value exists. Define sensible defaults in your settings UI: - -```qml -StringSetting { - settingKey: "apiKey" - defaultValue: "" // Empty string if no key saved -} - -ToggleSetting { - settingKey: "enabled" - defaultValue: true // Enabled by default -} - -ListSettingWithInput { - settingKey: "locations" - defaultValue: [] // Empty array if no locations saved -} -``` - -1. **PluginSettings** - Root wrapper for all plugin settings - - `pluginId`: Your plugin ID (required) - - Auto-handles storage and provides saveValue/loadValue to children - - Place all other setting components inside this wrapper - -2. **StringSetting** - Text input field - - `settingKey`: Storage key (required) - - `label`: Display label (required) - - `description`: Help text (optional) - - `placeholder`: Input placeholder (optional) - - `defaultValue`: Default value (optional, default: `""`) - - Layout: Vertical stack (label, description, input field) - -3. **ToggleSetting** - Boolean toggle switch - - `settingKey`: Storage key (required) - - `label`: Display label (required) - - `description`: Help text (optional) - - `defaultValue`: Default boolean (optional, default: `false`) - - Layout: Horizontal (label/description left, toggle right) - -4. **SelectionSetting** - Dropdown menu - - `settingKey`: Storage key (required) - - `label`: Display label (required) - - `description`: Help text (optional) - - `options`: Array of `{label, value}` objects or simple strings (required) - - `defaultValue`: Default value (optional, default: `""`) - - Layout: Horizontal (label/description left, dropdown right) - - Stores the `value` field, displays the `label` field - -5. **ListSetting** - Manage list of items (manual add/remove) - - `settingKey`: Storage key (required) - - `label`: Display label (required) - - `description`: Help text (optional) - - `defaultValue`: Default array (optional, default: `[]`) - - `delegate`: Custom item delegate Component (optional) - - `addItem(item)`: Add item to list - - `removeItem(index)`: Remove item from list - - Use when you need custom UI for adding items - -6. **ListSettingWithInput** - Complete list management with built-in form - - `settingKey`: Storage key (required) - - `label`: Display label (required) - - `description`: Help text (optional) - - `defaultValue`: Default array (optional, default: `[]`) - - `fields`: Array of field definitions (required) - - `id`: Field ID in saved object (required) - - `label`: Column header text (required) - - `placeholder`: Input placeholder (optional) - - `width`: Column width in pixels (optional, default 200) - - `required`: Must have value to add (optional, default false) - - `default`: Default value if empty (optional) - - Automatically generates: - - Column headers from field labels - - Input fields with placeholders - - Add button with validation - - List display showing all field values - - Remove buttons for each item - - Best for collecting structured data (servers, locations, etc.) - -**Complete Settings Example:** - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - pluginId: "myPlugin" - - StyledText { - width: parent.width - text: "General Settings" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StringSetting { - settingKey: "apiKey" - label: "API Key" - description: "Your service API key" - placeholder: "sk-..." - defaultValue: "" - } - - ToggleSetting { - settingKey: "enabled" - label: "Enable Feature" - description: "Turn this feature on or off" - defaultValue: true - } - - SelectionSetting { - settingKey: "theme" - label: "Theme" - description: "Choose your preferred theme" - options: [ - {label: "Dark", value: "dark"}, - {label: "Light", value: "light"}, - {label: "Auto", value: "auto"} - ] - defaultValue: "dark" - } - - ListSettingWithInput { - settingKey: "locations" - label: "Locations" - description: "Track multiple locations" - defaultValue: [] - fields: [ - {id: "name", label: "Name", placeholder: "Home", width: 150, required: true}, - {id: "timezone", label: "Timezone", placeholder: "America/New_York", width: 200, required: true} - ] - } -} -``` - -**Key Benefits:** -- Zero boilerplate - just define your settings -- Automatic persistence to `settings.json` -- Clean, consistent UI across all plugins -- No manual `pluginService` calls needed -- Proper layout and spacing handled automatically - -## PluginService API - -### Properties - -```qml -PluginService.pluginDirectory: string -// Path to plugins directory ($CONFIGPATH/DankMaterialShell/plugins) - -PluginService.availablePlugins: object -// Map of all discovered plugins {pluginId: pluginInfo} - -PluginService.loadedPlugins: object -// Map of currently loaded plugins {pluginId: pluginInfo} - -PluginService.pluginWidgetComponents: object -// Map of loaded widget components {pluginId: Component} -``` - -### Functions - -```qml -// Plugin Management -PluginService.loadPlugin(pluginId: string): bool -PluginService.unloadPlugin(pluginId: string): bool -PluginService.reloadPlugin(pluginId: string): bool -PluginService.enablePlugin(pluginId: string): bool -PluginService.disablePlugin(pluginId: string): bool - -// Plugin Discovery -PluginService.scanPlugins(): void -PluginService.getAvailablePlugins(): array -PluginService.getLoadedPlugins(): array -PluginService.isPluginLoaded(pluginId: string): bool -PluginService.getWidgetComponents(): object - -// Data Persistence -PluginService.savePluginData(pluginId: string, key: string, value: any): bool -PluginService.loadPluginData(pluginId: string, key: string, defaultValue: any): any - -// Global Variables - Shared state across all plugin instances -PluginService.getGlobalVar(pluginId: string, varName: string, defaultValue: any): any -PluginService.setGlobalVar(pluginId: string, varName: string, value: any): void -``` - -### Signals - -```qml -PluginService.pluginLoaded(pluginId: string) -PluginService.pluginUnloaded(pluginId: string) -PluginService.pluginLoadFailed(pluginId: string, error: string) -PluginService.globalVarChanged(pluginId: string, varName: string) -``` - -## Plugin Global Variables - -Plugins can share state across multiple instances using global variables. This is useful when you have the same widget displayed on multiple monitors or multiple instances of the same widget on different bars. - -### Why Use Global Variables? - -Unlike regular properties which are scoped to each component instance, global variables are synchronized across all instances of your plugin. This enables: - -- **Multi-monitor consistency**: Same data displayed across all monitors -- **Multi-instance widgets**: Multiple instances of the same widget sharing state -- **Cross-component communication**: Share data between widget and settings components - -### Using PluginGlobalVar - -The `PluginGlobalVar` helper component provides reactive global variable access: - -```qml -import QtQuick -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - PluginGlobalVar { - id: globalCounter - varName: "counter" - defaultValue: 0 - } - - horizontalBarPill: Component { - StyledRect { - width: content.implicitWidth + Theme.spacingM * 2 - height: parent.widgetThickness - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - StyledText { - id: content - anchors.centerIn: parent - text: "Count: " + globalCounter.value - color: Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - onClicked: globalCounter.set(globalCounter.value + 1) - } - } - } -} -``` - -**PluginGlobalVar Properties:** -- `varName` (required): Name of the global variable -- `defaultValue` (optional): Default value if not set -- `value` (readonly): Current value of the global variable - -**PluginGlobalVar Methods:** -- `set(newValue)`: Update the global variable (triggers reactivity across all instances) - -### Using PluginService API Directly - -For more control, use the PluginService API directly: - -```qml -import QtQuick -import qs.Services -import qs.Modules.Plugins - -PluginComponent { - property int counter: PluginService.getGlobalVar("myPlugin", "counter", 0) - - Connections { - target: PluginService - function onGlobalVarChanged(pluginId, varName) { - if (pluginId === "myPlugin" && varName === "counter") { - counter = PluginService.getGlobalVar("myPlugin", "counter", 0) - } - } - } - - horizontalBarPill: Component { - StyledRect { - MouseArea { - anchors.fill: parent - onClicked: { - const current = PluginService.getGlobalVar("myPlugin", "counter", 0) - PluginService.setGlobalVar("myPlugin", "counter", current + 1) - } - } - } - } -} -``` - -### Global Variables vs Settings - -**Global Variables** (`getGlobalVar`/`setGlobalVar`): -- Runtime state only (not persisted to disk) -- Synchronized across all plugin instances -- Changes trigger `globalVarChanged` signal for reactivity -- Use for: counters, current selection, temporary UI state - -**Settings** (`savePluginData`/`loadPluginData`): -- Persisted to `settings.json` across sessions -- Loaded once per plugin instance -- Use for: user preferences, API keys, configuration - -### Important Notes - -1. **Reactivity**: Global variables are reactive - all instances update when a value changes -2. **Namespacing**: Variables are namespaced by plugin ID to avoid conflicts -3. **Type Safety**: Values can be any QML/JavaScript type (numbers, strings, objects, arrays) -4. **Not Persistent**: Global variables are cleared when the shell restarts (use settings for persistence) -5. **Performance**: Efficient for frequent updates - changes only trigger updates for the specific variable - -## Creating a Plugin - -### Step 1: Create Plugin Directory - -```bash -mkdir -p $CONFIGPATH/DankMaterialShell/plugins/MyPlugin -cd $CONFIGPATH/DankMaterialShell/plugins/MyPlugin -``` - -### Step 2: Create Manifest - -Create `plugin.json`: - -```json -{ - "id": "myPlugin", - "name": "My Plugin", - "description": "A sample plugin", - "version": "1.0.0", - "author": "Your Name", - "type": "widget", - "capabilities": ["my-functionality"], - "component": "./MyWidget.qml", - "icon": "extension", - "settings": "./MySettings.qml", - "requires_dms": ">=0.1.0", - "permissions": ["settings_read", "settings_write"] -} -``` - -### Step 3: Create Widget Component - -Create `MyWidget.qml`: - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - horizontalBarPill: Component { - StyledRect { - width: textItem.implicitWidth + Theme.spacingM * 2 - height: parent.widgetThickness - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - StyledText { - id: textItem - anchors.centerIn: parent - text: "Hello World" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - } - } - } - - verticalBarPill: Component { - StyledRect { - width: parent.widgetThickness - height: textItem.implicitWidth + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - StyledText { - id: textItem - anchors.centerIn: parent - text: "Hello" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeSmall - rotation: 90 - } - } - } -} -``` - -**Note:** Use `PluginComponent` wrapper for automatic property injection and bar integration. Define separate components for horizontal and vertical orientations. - -### Step 4: Create Settings Component (Optional) - -Create `MySettings.qml`: - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - pluginId: "myPlugin" - - StyledText { - width: parent.width - text: "Configure your plugin settings" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - StringSetting { - settingKey: "text" - label: "Display Text" - description: "Text shown in the bar widget" - placeholder: "Hello World" - defaultValue: "Hello World" - } - - ToggleSetting { - settingKey: "showIcon" - label: "Show Icon" - description: "Display an icon next to the text" - defaultValue: true - } -} -``` - -### Step 5: Enable Plugin - -1. Run the shell: `qs -p $CONFIGPATH/quickshell/dms/shell.qml` -2. Open Settings (Ctrl+,) -3. Navigate to Plugins tab -4. Click "Scan for Plugins" -5. Enable your plugin with the toggle switch -6. Add the plugin to your DankBar configuration - -## Adding Plugin to DankBar - -After enabling a plugin, add it to the bar: - -1. Open Settings → Appearance → DankBar Layout -2. Add a new widget entry with your plugin ID -3. Choose section (left, center, right) -4. Save and reload - -Or edit `$CONFIGPATH/quickshell/dms/config.json`: - -```json -{ - "dankBarLeftWidgets": [ - {"widgetId": "myPlugin", "enabled": true} - ] -} -``` - -## Best Practices - -1. **Use Existing Widgets**: Leverage `qs.Widgets` components (DankIcon, DankToggle, etc.) for consistency -2. **Follow Theme**: Use `Theme` singleton for colors, spacing, and fonts -3. **Data Persistence**: Use PluginService data APIs instead of manual file operations -4. **Error Handling**: Gracefully handle missing dependencies and invalid data -5. **Performance**: Keep widgets lightweight, avoid long operations that block the UI loop -6. **Responsive Design**: Adapt to `compactMode` and different screen sizes -7. **Documentation**: Include README.md explaining plugin usage -8. **Versioning**: Use semantic versioning for updates -9. **Dependencies**: Document external library requirements - -## Clipboard Access - -Plugins that need to copy text to the clipboard should use the built-in `dms cl copy` command through Quickshell's `execDetached` function. - -### Correct Method - -Import Quickshell and use `execDetached` with `dms cl copy`: - -```qml -import QtQuick -import Quickshell - -Item { - function copyToClipboard(text) { - Quickshell.execDetached(["dms", "cl", "copy", text]) - } -} -``` - -### Example Usage - -From the ExampleEmojiPlugin (EmojiWidget.qml): - -```qml -MouseArea { - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", modelData]) - ToastService.showInfo("Copied " + modelData + " to clipboard") - popoutColumn.closePopout() - } -} -``` - -### Important Notes - -1. **Do NOT** use `globalThis.clipboard` or similar JavaScript APIs - they don't exist in the QML runtime -2. **Always** import `Quickshell` at the top of your QML file -3. Consider showing a toast notification to confirm the copy action to users - -### Dependencies - -This method uses the built-in DMS clipboard functionality which has native Wayland support. - -## Running External Commands - -Plugins that need to execute external commands and capture their output should use the `Proc` singleton, which provides debounced command execution with automatic cleanup. - -### Correct Method - -Import the `Proc` singleton from `qs.Common` and use `runCommand`: - -```qml -import QtQuick -import qs.Common - -Item { - function fetchData() { - Proc.runCommand( - "myPlugin.fetchData", - ["curl", "-s", "https://api.example.com/data"], - (stdout, exitCode) => { - if (exitCode === 0) { - console.log("Success:", stdout) - processData(stdout) - } else { - console.error("Command failed with exit code:", exitCode) - } - }, - 100 - ) - } -} -``` - -### Function Signature - -```qml -Proc.runCommand(id, command, callback, debounceMs) -``` - -**Parameters:** -- `id` (string): Unique identifier for this command. Used for debouncing - multiple calls with the same ID within the debounce window will only execute the last one -- `command` (array): Command and arguments as an array (e.g., `["sh", "-c", "echo hello"]`) -- `callback` (function): Callback function receiving `(stdout, exitCode)` when the command completes - - `stdout` (string): Captured standard output from the command - - `exitCode` (number): Exit code of the process (0 typically means success) -- `debounceMs` (number, optional): Debounce delay in milliseconds. Defaults to 50ms if not specified - -### Key Features - -1. **Automatic Cleanup**: Process objects are automatically destroyed after completion -2. **Debouncing**: Rapid successive calls with the same ID are debounced, only executing the last one -3. **Output Capture**: Automatically captures stdout for processing -4. **Error Handling**: Exit codes are passed to the callback for error detection - -### Example Usage - -#### Simple Command Execution - -```qml -import QtQuick -import qs.Common - -Item { - function checkNetwork() { - Proc.runCommand( - "myPlugin.ping", - ["ping", "-c", "1", "8.8.8.8"], - (output, exitCode) => { - if (exitCode === 0) { - console.log("Network is up") - } else { - console.log("Network is down") - } - } - ) - } -} -``` - -#### Parsing Command Output - -```qml -import QtQuick -import qs.Common - -Item { - property var diskUsage: ({}) - - function updateDiskUsage() { - Proc.runCommand( - "myPlugin.df", - ["df", "-h", "/home"], - (output, exitCode) => { - if (exitCode === 0) { - const lines = output.trim().split("\n") - if (lines.length > 1) { - const parts = lines[1].split(/\s+/) - diskUsage = { - total: parts[1], - used: parts[2], - available: parts[3], - percent: parts[4] - } - } - } - } - ) - } -} -``` - -#### Shell Commands with Pipes - -```qml -import QtQuick -import qs.Common - -Item { - function getTopProcess() { - Proc.runCommand( - "myPlugin.topProcess", - ["sh", "-c", "ps aux | sort -nrk 3,3 | head -n 1"], - (output, exitCode) => { - if (exitCode === 0) { - console.log("Top process:", output) - } - } - ) - } -} -``` - -#### Debouncing Rapid Updates - -```qml -import QtQuick -import qs.Common -import qs.Widgets - -Item { - DankTextField { - id: searchField - placeholderText: "Search files..." - - onTextChanged: { - Proc.runCommand( - "myPlugin.search", - ["find", "/home", "-name", "*" + text + "*"], - (output, exitCode) => { - if (exitCode === 0) { - updateSearchResults(output) - } - }, - 500 - ) - } - } -} -``` - -### Important Notes - -1. **Unique IDs**: Use descriptive, namespaced IDs (e.g., `"myPlugin.actionName"`) to avoid conflicts -2. **Debouncing**: Use appropriate debounce delays for your use case: - - Fast updates (50-100ms): System monitoring, real-time data - - User input (300-500ms): Search fields, text input processing - - Network requests (500-1000ms): API calls, web scraping -3. **Error Handling**: Always check the exit code in your callback before processing output -4. **Shell Commands**: Use `["sh", "-c", "command"]` for complex shell commands with pipes or redirects -5. **Security**: Sanitize user input before passing to commands to prevent command injection -6. **Performance**: Avoid running expensive commands too frequently - use debouncing wisely - -### Comparison with Other Methods - -**Proc.runCommand** vs **Quickshell.execDetached**: -- Use `Proc.runCommand` when you need to capture output or check exit codes -- Use `Quickshell.execDetached` for fire-and-forget operations (like clipboard copy) - -**Proc.runCommand** vs **Process component**: -- Use `Proc.runCommand` for simple, one-off command executions with automatic cleanup -- Use `Process` component for long-running processes or when you need fine-grained control - -## Debugging - -### Console Logging - -View plugin logs: - -```bash -qs -v -p $CONFIGPATH/quickshell/dms/shell.qml -``` - -Look for lines prefixed with: -- `PluginService:` - Service operations -- `PluginsTab:` - UI interactions -- `PluginsTab:` - Settings loading and accordion interface - -### Common Issues - -1. **Plugin Not Detected** - - Check plugin.json syntax (use `jq` or JSON validator) - - Verify directory is in `$CONFIGPATH/DankMaterialShell/plugins/` - - Click "Scan for Plugins" in Settings - -2. **Widget Not Displaying** - - Ensure plugin is enabled in Settings - - Add plugin ID to DankBar widget list - - Check widget width/height properties - -3. **Settings Not Loading** - - Verify `settings` path in plugin.json - - Check settings component for errors - - Ensure plugin is enabled and loaded - - Review PluginsTab console output for injection issues - -4. **Data Not Persisting** - - Confirm pluginService.savePluginData() calls (with injection) - - Check `$CONFIGPATH/DankMaterialShell/settings.json` for pluginSettings data - - Verify plugin has settings permissions - - Ensure PluginService was properly injected into settings component - -## Security Considerations - -Plugins run with full QML runtime access. Only install plugins from trusted sources. - -**Permissions System:** -- `settings_read`: Read plugin configuration (not currently enforced) -- `settings_write`: **Required** to use PluginSettings - write plugin configuration (enforced) -- `process`: Execute system commands (not currently enforced) -- `network`: Network access (not currently enforced) - -Currently, only `settings_write` is enforced by the PluginSettings component. - -## API Stability - -The plugin API is currently **experimental**. Breaking changes may occur in minor version updates. Pin to specific DMS versions for production use. - -**Roadmap:** -- Plugin marketplace/repository -- Sandboxed plugin execution -- Enhanced permission system -- Plugin update notifications -- Inter-plugin communication - -## Launcher Plugins - -Launcher plugins extend the DMS application launcher by adding custom searchable items with trigger-based filtering. - -### Overview - -Launcher plugins enable you to: -- Add custom items to the launcher/app drawer -- Use trigger strings for quick filtering (e.g., `!`, `#`, `@`) -- Execute custom actions when items are selected -- Provide searchable, categorized content -- Integrate seamlessly with the existing launcher - -### Plugin Type Configuration - -To create a launcher plugin, set the plugin type in `plugin.json`: - -```json -{ - "id": "myLauncher", - "name": "My Launcher Plugin", - "description": "A custom launcher plugin for quick actions", - "version": "1.0.0", - "author": "Your Name", - "type": "launcher", - "capabilities": ["show-thing"], - "component": "./MyLauncher.qml", - "trigger": "#", - "icon": "search", - "settings": "./MySettings.qml", - "requires_dms": ">=0.1.18", - "permissions": ["settings_read", "settings_write"] -} -``` - -### Launcher Component Contract - -Create `MyLauncher.qml` with the following interface: - -```qml -import QtQuick -import qs.Services - -Item { - id: root - - // Required properties - property var pluginService: null - property string trigger: "#" - - // Required signals - signal itemsChanged() - - // Required: Return array of launcher items - function getItems(query) { - return [ - { - name: "Item Name", - icon: "icon_name", - comment: "Description", - action: "type:data", - categories: ["MyLauncher"] - } - ] - } - - // Required: Execute item action - function executeItem(item) { - const [type, data] = item.action.split(":", 2) - // Handle action based on type - } - - Component.onCompleted: { - if (pluginService) { - trigger = pluginService.loadPluginData("myLauncher", "trigger", "#") - } - } -} -``` - -### Item Structure - -Each item returned by `getItems()` must include: - -- `name` (string): Display name shown in launcher -- `icon` (string, optional): Icon specification (see Icon Types below) -- `comment` (string): Description/subtitle text -- `action` (string): Action identifier in `type:data` format -- `categories` (array): Array containing your plugin name - -### Icon Types - -The `icon` field supports four formats: - -**1. Material Design Icons** - Use the `material:` prefix: -```javascript -{ - name: "My Item", - icon: "material:lightbulb", // Material Symbols Rounded font - comment: "Uses Material Design icon", - action: "toast:Hello!", - categories: ["MyPlugin"] -} -``` -Available icons: Any icon from Material Symbols font (e.g., `lightbulb`, `star`, `favorite`, `settings`, `terminal`, `translate`, `sentiment_satisfied`) - -**2. Unicode/Emoji Icons** - Use the `unicode:` prefix: -```javascript -{ - name: "Grinning Face", - icon: "unicode:😀", // Unicode character or emoji - comment: "Copy emoji to clipboard", - action: "copy:😀", - categories: ["MyPlugin"] -} -``` -Display any Unicode character or emoji as the icon. The character is rendered at 70-80% of the icon size with proper theming. Perfect for emoji pickers, symbol selectors, or character libraries. - -**3. Desktop Theme Icons** - Use icon name directly: -```javascript -{ - name: "Firefox", - icon: "firefox", // Uses system icon theme - comment: "Launches Firefox browser", - action: "exec:firefox", - categories: ["MyPlugin"] -} -``` -Uses the user's installed icon theme. Common examples: `firefox`, `chrome`, `folder`, `text-editor` - -**4. No Icon** - Omit the `icon` field entirely: -```javascript -{ - name: "😀 Grinning Face", - // No icon field - emoji/unicode in name displays without icon area - comment: "Copy emoji to clipboard", - action: "copy:😀", - categories: ["MyPlugin"] -} -``` -When `icon` is omitted, the launcher hides the icon area and displays only the text, giving full width to the item name. Useful when you want emojis or symbols to be part of the item name itself. - -### Trigger System - -Triggers control when your plugin's items appear in the launcher: - -**Empty Trigger Mode** (No trigger): -- Items always visible alongside regular apps -- Search includes your items automatically -- Configure by saving empty trigger: `trigger: ""` - -**Custom Trigger Mode**: -- Items only appear when trigger is typed -- Example: Type `#` to show only your plugin's items -- Type `# query` to search within your plugin -- Configure any string: `#`, `!`, `@`, `!custom`, etc. - -### Trigger Configuration in Settings - -Provide a settings component with trigger configuration: - -```qml -import QtQuick -import QtQuick.Controls -import qs.Widgets - -FocusScope { - id: root - - property var pluginService: null - - Column { - spacing: 12 - - CheckBox { - id: noTriggerToggle - text: "No trigger (always show)" - checked: loadSettings("noTrigger", false) - - onCheckedChanged: { - saveSettings("noTrigger", checked) - if (checked) { - saveSettings("trigger", "") - } else { - saveSettings("trigger", triggerField.text || "#") - } - } - } - - DankTextField { - id: triggerField - visible: !noTriggerToggle.checked - text: loadSettings("trigger", "#") - placeholderText: "#" - - onTextEdited: { - saveSettings("trigger", text || "#") - } - } - } - - function saveSettings(key, value) { - if (pluginService) { - pluginService.savePluginData("myLauncher", key, value) - } - } - - function loadSettings(key, defaultValue) { - if (pluginService) { - return pluginService.loadPluginData("myLauncher", key, defaultValue) - } - return defaultValue - } -} -``` - -### Action Execution - -Handle different action types in `executeItem()`: - -```qml -function executeItem(item) { - const actionParts = item.action.split(":") - const actionType = actionParts[0] - const actionData = actionParts.slice(1).join(":") - - switch (actionType) { - case "toast": - if (typeof ToastService !== "undefined") { - ToastService.showInfo("Plugin", actionData) - } - break - case "copy": - // Copy to clipboard - break - case "script": - // Execute command - break - default: - console.warn("Unknown action:", actionType) - } -} -``` - -### Search and Filtering - -The launcher automatically handles search when: - -**With empty trigger**: -- Your items appear in all searches -- No prefix needed - -**With custom trigger**: -- Type trigger alone: Shows all your items -- Type trigger + query: Filters your items by query -- The query parameter is passed to your `getItems(query)` function - -Example `getItems()` implementation: - -```qml -function getItems(query) { - const allItems = [ - {name: "Item 1", ...}, - {name: "Item 2", ...}, - {name: "Test Item", ...} - ] - - if (!query || query.length === 0) { - return allItems - } - - const lowerQuery = query.toLowerCase() - return allItems.filter(item => { - return item.name.toLowerCase().includes(lowerQuery) || - item.comment.toLowerCase().includes(lowerQuery) - }) -} -``` - -### Integration Flow - -1. User opens launcher -2. If empty trigger: Your items appear alongside apps -3. If custom trigger: User types trigger (e.g., `#`) -4. Launcher calls `getItems(query)` on your plugin -5. Your items displayed with your plugin's category -6. User selects item and presses Enter -7. Launcher calls `executeItem(item)` on your plugin - -### Best Practices - -1. **Unique Triggers**: Choose non-conflicting trigger strings -2. **Fast Response**: Return results quickly from `getItems()` -3. **Clear Names**: Use descriptive item names and comments -4. **Error Handling**: Gracefully handle failures in `executeItem()` -5. **Cleanup**: Destroy temporary objects after use -6. **Empty Trigger Support**: Consider if your plugin benefits from always being visible - -### Example Plugin - -See `PLUGINS/LauncherExample/` for a complete working example demonstrating: -- Trigger configuration (including empty trigger mode) -- Multiple action types (toast, copy, script) -- Search/filtering implementation -- Settings integration -- Proper error handling - -## Desktop Plugins - -Desktop plugins are widgets that appear directly on the desktop background layer. They can be dragged, resized, and positioned freely by the user. - -### Overview - -Desktop plugins enable you to: -- Display widgets on the desktop background -- Support drag-and-drop positioning -- Support resize via corner handles -- Persist position and size across sessions -- Provide settings for customization - -### Plugin Type Configuration - -To create a desktop plugin, set the plugin type in `plugin.json`: - -```json -{ - "id": "myDesktopWidget", - "name": "My Desktop Widget", - "description": "A custom desktop widget", - "version": "1.0.0", - "author": "Your Name", - "type": "desktop", - "capabilities": ["desktop-widget"], - "component": "./MyWidget.qml", - "icon": "widgets", - "settings": "./MySettings.qml", - "permissions": ["settings_read", "settings_write"] -} -``` - -### Desktop Widget Component Contract - -Create your widget component (`MyWidget.qml`) with the following interface: - -```qml -import QtQuick -import qs.Common - -Item { - id: root - - // Injected properties (provided by DesktopPluginWrapper) - property var pluginService: null - property string pluginId: "" - property bool editMode: false - property real widgetWidth: 200 - property real widgetHeight: 200 - - // Optional: Define minimum size constraints - property real minWidth: 100 - property real minHeight: 100 - - // Your widget content - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: 0.85 - - // Widget content here - Text { - anchors.centerIn: parent - text: "Hello Desktop!" - color: Theme.surfaceText - } - } -} -``` - -### Injected Properties - -Desktop widgets receive these properties automatically: - -- `pluginService`: Reference to PluginService for data persistence -- `pluginId`: The plugin's unique identifier -- `editMode`: Boolean indicating if the user is in edit mode (dragging/resizing) -- `widgetWidth`: Current width of the widget container -- `widgetHeight`: Current height of the widget container - -### Optional Properties - -Define these properties on your widget to customize behavior: - -- `minWidth`: Minimum allowed width (default: 100) -- `minHeight`: Minimum allowed height (default: 100) - -### Loading and Saving Data - -Use the injected `pluginService` to persist widget-specific data: - -```qml -property string myValue: pluginService ? pluginService.loadPluginData(pluginId, "myValue", "default") : "default" - -Connections { - target: pluginService - function onPluginDataChanged(changedPluginId) { - if (changedPluginId !== pluginId) return; - root.myValue = pluginService.loadPluginData(pluginId, "myValue", "default"); - } -} - -function saveMyValue(value) { - if (pluginService) { - pluginService.savePluginData(pluginId, "myValue", value); - } -} -``` - -### Position and Size Persistence - -Position (`desktopX`, `desktopY`) and size (`desktopWidth`, `desktopHeight`) are automatically persisted by the `DesktopPluginWrapper`. You don't need to handle this in your widget. - -### Edit Mode - -When `editMode` is true, the user is repositioning or resizing the widget. You can use this to: -- Show visual indicators -- Disable interactive elements -- Display additional controls - -```qml -Rectangle { - anchors.fill: parent - border.color: root.editMode ? Theme.primary : "transparent" - border.width: root.editMode ? 2 : 0 - - // Content that should be disabled during edit mode - MouseArea { - anchors.fill: parent - enabled: !root.editMode - onClicked: doSomething() - } -} -``` - -### Settings Component - -Create a settings component using `PluginSettings`: - -```qml -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - pluginId: "myDesktopWidget" - - ToggleSetting { - settingKey: "showBorder" - label: "Show Border" - description: "Display a border around the widget" - defaultValue: true - } - - SelectionSetting { - settingKey: "theme" - label: "Theme" - options: [ - {label: "Light", value: "light"}, - {label: "Dark", value: "dark"} - ] - defaultValue: "dark" - } -} -``` - -### User Interaction - -Desktop widgets support: - -1. **Drag**: Click and drag anywhere on the widget (when in edit mode) -2. **Resize**: Drag the bottom-right corner handle (when in edit mode) -3. **Edit Mode Toggle**: Click the edit button in the bottom-right corner of the screen - -### Example Plugin - -See `PLUGINS/ExampleDesktopClock/` for a complete working example demonstrating: -- Analog and digital clock styles -- Settings integration -- Responsive sizing -- Edit mode handling - -## Resources - -- **Plugin Schema**: `plugin-schema.json` - JSON Schema for validation -- **Example Plugins**: - - [Emoji Picker](./ExampleEmojiPlugin/) - - [WorldClock](https://github.com/rochacbruno/WorldClock) - - [LauncherExample](./LauncherExample/) - - [Calculator](https://github.com/rochacbruno/DankCalculator) - - [Desktop Clock](./ExampleDesktopClock/) -- **PluginService**: `Services/PluginService.qml` -- **Settings UI**: `Modules/Settings/PluginsTab.qml` -- **DankBar Integration**: `Modules/DankBar/DankBar.qml` -- **Launcher Integration**: `Modules/AppDrawer/AppLauncher.qml` -- **Desktop Widget Integration**: `Modules/DesktopWidgetLayer.qml` -- **Theme Reference**: `Common/Theme.qml` -- **Widget Library**: `Widgets/` - -## Contributing - -Share your plugins with the community: - -1. Create a public repository with your plugin -2. Validate your `plugin.json` against `plugin-schema.json` -3. Include comprehensive README.md -4. Add example screenshots -5. Document dependencies and permissions - -For plugin system improvements, submit issues or PRs to the main DMS repository. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md deleted file mode 100644 index be1373a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md +++ /dev/null @@ -1,132 +0,0 @@ -# Theme Property Reference for Plugins - -Quick reference for commonly used Theme properties in plugin development. - -## Font Sizes - -```qml -Theme.fontSizeSmall // 12px (scaled) -Theme.fontSizeMedium // 14px (scaled) -Theme.fontSizeLarge // 16px (scaled) -Theme.fontSizeXLarge // 20px (scaled) -``` - -**Note**: These are scaled by `SettingsData.fontScale` - -## Icon Sizes - -```qml -Theme.iconSizeSmall // 16px -Theme.iconSize // 24px (default) -Theme.iconSizeLarge // 32px -``` - -## Spacing - -```qml -Theme.spacingXS // Extra small -Theme.spacingS // Small -Theme.spacingM // Medium -Theme.spacingL // Large -Theme.spacingXL // Extra large -``` - -## Border Radius - -```qml -Theme.cornerRadius // Standard corner radius -Theme.cornerRadiusSmall // Smaller radius -Theme.cornerRadiusLarge // Larger radius -``` - -## Colors - -### Surface Colors -```qml -Theme.surface -Theme.surfaceContainerLow -Theme.surfaceContainer -Theme.surfaceContainerHigh -Theme.surfaceContainerHighest -``` - -### Text Colors -```qml -Theme.onSurface // Primary text on surface -Theme.onSurfaceVariant // Secondary text on surface -Theme.outline // Border/divider color -``` - -### Semantic Colors -```qml -Theme.primary -Theme.onPrimary -Theme.secondary -Theme.onSecondary -Theme.error -Theme.warning -Theme.success -``` - -### Special Functions -```qml -Theme.popupBackground() // Popup background with opacity -``` - -## Common Patterns - -### Icon with Text -```qml -DankIcon { - name: "icon_name" - color: Theme.onSurface - font.pixelSize: Theme.iconSize -} - -StyledText { - text: "Label" - color: Theme.onSurface - font.pixelSize: Theme.fontSizeMedium -} -``` - -### Container with Border -```qml -Rectangle { - color: Theme.surfaceContainerHigh - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 -} -``` - -### Hover Effect -```qml -MouseArea { - hoverEnabled: true - onEntered: parent.color = Qt.lighter(Theme.surfaceContainerHigh, 1.1) - onExited: parent.color = Theme.surfaceContainerHigh -} -``` - -## Common Mistakes - -❌ **Wrong**: -```qml -font.pixelSize: Theme.fontSizeS // Property doesn't exist -font.pixelSize: Theme.iconSizeS // Property doesn't exist -``` - -✅ **Correct**: -```qml -font.pixelSize: Theme.fontSizeSmall // Use full name -font.pixelSize: Theme.iconSizeSmall // Use full name -``` - -## Checking Available Properties - -To see all available Theme properties, check `Common/Theme.qml` or use: - -```bash -grep "property" Common/Theme.qml -``` diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md deleted file mode 100644 index 159b58d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Wallpaper Watcher Daemon - -Run a script whenever your wallpaper changes. - -## What it does - -This daemon monitors wallpaper changes and executes a script you specify. The new wallpaper path gets passed as the first argument to your script. - -## Setup - -1. Enable the plugin in Settings → Plugins -2. Configure the script path in the plugin settings -3. Make sure your script is executable (`chmod +x /path/to/script.sh`) - -## Example script - -```bash -#!/bin/bash -echo "New wallpaper: $1" -# Do something with the wallpaper path -``` - -Save this to a file, make it executable, and point the plugin to it. - -## Use cases - -- Generate color schemes from the new wallpaper -- Update theme files based on wallpaper colors -- Send notifications when wallpaper changes -- Sync wallpaper info to other devices -- Log wallpaper history - -## Notes - -- Script errors show up as toast notifications -- Script output goes to console logs -- The daemon runs invisibly in the background diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml deleted file mode 100644 index ffed6c1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Modules.Plugins - -PluginComponent { - id: root - - property string scriptPath: pluginData.scriptPath || "" - property var popoutService: null - - Connections { - target: SessionData - function onWallpaperPathChanged() { - if (scriptPath) { - var scriptProcess = scriptProcessComponent.createObject(root, { - wallpaperPath: SessionData.wallpaperPath - }) - scriptProcess.running = true - } - } - } - - Component { - id: scriptProcessComponent - - Process { - property string wallpaperPath: "" - - command: [scriptPath, wallpaperPath] - - stdout: StdioCollector { - onStreamFinished: { - if (text.trim()) { - console.log("WallpaperWatcherDaemon script output:", text.trim()) - } - } - } - - stderr: StdioCollector { - onStreamFinished: { - if (text.trim()) { - ToastService.showError("Wallpaper Change Script Error", text.trim()) - } - } - } - - onExited: (exitCode) => { - if (exitCode !== 0) { - ToastService.showError("Wallpaper Change Script Error", "Script exited with code: " + exitCode) - } - destroy() - } - } - } - - Component.onCompleted: { - console.info("WallpaperWatcherDaemon: Started monitoring wallpaper changes") - } - - Component.onDestruction: { - console.info("WallpaperWatcherDaemon: Stopped monitoring wallpaper changes") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml deleted file mode 100644 index 5f8c2c0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Plugins - -PluginSettings { - id: root - pluginId: "wallpaperWatcherDaemon" - - StyledText { - text: "Wallpaper Change Hook" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - } - - StringSetting { - settingKey: "scriptPath" - label: "Script Path" - description: "Path to a script that will be executed when the wallpaper changes. The new wallpaper path will be passed as the first argument." - placeholder: "/path/to/your/script.sh" - defaultValue: "" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json deleted file mode 100644 index 6e08395..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "wallpaperWatcherDaemon", - "name": "Wallpaper Watcher Daemon", - "description": "Background daemon that monitors wallpaper changes and logs them", - "version": "1.0.0", - "author": "DankMaterialShell", - "type": "daemon", - "capabilities": ["wallpaper", "monitoring"], - "component": "./WallpaperWatcherDaemon.qml", - "icon": "wallpaper", - "settings": "./WallpaperWatcherSettings.qml", - "permissions": [ - "settings_read", - "settings_write" - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json deleted file mode 100644 index 2f7e172..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://danklinux.com/schemas/plugin.json", - "title": "DankMaterialShell Plugin Manifest", - "description": "Schema for DankMaterialShell plugin.json manifest files", - "type": "object", - "required": [ - "id", - "name", - "description", - "version", - "author", - "type", - "capabilities", - "component" - ], - "properties": { - "id": { - "type": "string", - "description": "Unique plugin identifier (camelCase, no spaces)", - "pattern": "^[a-zA-Z][a-zA-Z0-9]*$" - }, - "name": { - "type": "string", - "description": "Human-readable plugin name", - "minLength": 1 - }, - "description": { - "type": "string", - "description": "Short description of plugin functionality", - "minLength": 1 - }, - "version": { - "type": "string", - "description": "Semantic version string (e.g., '1.0.0')", - "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$" - }, - "author": { - "type": "string", - "description": "Plugin creator name or email", - "minLength": 1 - }, - "type": { - "type": "string", - "description": "Plugin type", - "enum": ["widget", "daemon", "launcher", "desktop"] - }, - "capabilities": { - "type": "array", - "description": "Array of plugin capabilities", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "component": { - "type": "string", - "description": "Relative path to main QML component file", - "pattern": "^\\./.*\\.qml$" - }, - "trigger": { - "type": "string", - "description": "Trigger string for launcher activation (required for launcher type)" - }, - "icon": { - "type": "string", - "description": "Material Design icon name" - }, - "settings": { - "type": "string", - "description": "Path to settings component QML file", - "pattern": "^\\./.*\\.qml$" - }, - "requires_dms": { - "type": "string", - "description": "Minimum DMS version requirement (e.g., '>=0.1.18', '>0.1.0')", - "pattern": "^(>=?|<=?|=|>|<)\\d+\\.\\d+\\.\\d+$" - }, - "requires": { - "type": "array", - "description": "Array of required system tools/dependencies", - "items": { - "type": "string" - } - }, - "permissions": { - "type": "array", - "description": "Required capabilities", - "items": { - "type": "string", - "enum": [ - "settings_read", - "settings_write", - "process", - "network" - ] - } - } - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "launcher" - } - } - }, - "then": { - "required": ["trigger"] - } - } - ], - "additionalProperties": true -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/README.md deleted file mode 100644 index df85295..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/README.md +++ /dev/null @@ -1,241 +0,0 @@ -# DMS Quickshell Interface - -QML-based desktop shell interface for DankMaterialShell providing panels, widgets, and overlays. - -**See [root README](../README.md) for project overview and installation.** - -## Architecture - -**Modular QML Structure** -- `Modules/` - UI components (panels, widgets, overlays) -- `Services/` - System integration singletons (audio, network, bluetooth) -- `Widgets/` - Reusable UI controls -- `Common/` - Shared resources and themes - -**Technology Stack** -- [Quickshell](https://quickshell.org/) - QML-based shell framework -- Qt/QtQuick - UI rendering and controls -- Material Design 3 - Design system and theming - -## Development - -**Run the shell:** -```bash -quickshell -p quickshell/ -``` - -**Code formatting:** -```bash -qmlfmt -t 4 -i 4 -b 250 -w path/to/file.qml -make lint-qml # Run from repo root; requires quickshell/.qmlls.ini (generated by `qs -p quickshell/`) - # Uses Qt 6 qmllint. Override path with QMLLINT=/path/to/qmllint if needed. - # Auto-detects `qmllint6`, Fedora's `qmllint-qt6`, `/usr/lib/qt6/bin/qmllint`, then `qmllint`. -``` - -## Components - -**Panels & Bars** -- `Modules/TopBar/` - Multi-monitor status bars with workspace switching -- `Modules/DankBar/` - Customizable widget bar with plugin support -- `Modules/Dock/` - Application dock with window management - -**System Controls** -- `Modules/ControlCenter/` - WiFi, Bluetooth, audio, display settings -- `Modules/Notifications/` - Notification center with popups -- `Modules/Greetd/` - Login greeter interface - -**Overlays** -- `Modules/Spotlight/` - Application and file launcher -- `Modules/Overview/` - Workspace overview -- `Modules/Lock/` - Screen lock system - -**Utilities** -- `Modules/ProcessList/` - System monitoring and process management -- `Modules/Calendar/` - Calendar widget with event sync -- `Modules/Weather/` - Weather display - -## Services - -Singletons providing system integration: - -**Media & Audio** -- `AudioService` - PipeWire/PulseAudio volume and device control -- `MprisController` - Media player integration - -**Network** -- `NetworkService` - NetworkManager WiFi control -- `BluetoothService` - BlueZ Bluetooth management - -**Display** -- `DisplayService` - Brightness control and night mode -- `WallpaperService` - Wallpaper management and effects - -**System** -- `BatteryService` - Battery status and power profiles -- `IdleService` - Idle detection and inhibit locks -- `ClipboardService` - Clipboard history with images -- `DgopService` - System metrics (CPU, RAM, GPU) - -**Integration** -- `NiriService` - Niri workspace integration -- `HyprlandService` - Hyprland workspace integration -- `PluginService` - Plugin discovery and lifecycle - -## Widgets - -Reusable Material Design 3 components in `Widgets/`: - -- `DankIcon` - Icon component with Material font -- `DankSlider` - Enhanced slider with animations -- `DankToggle` - Toggle switch component -- `DankTabBar` - Tab bar implementation -- `DankGridView` - Grid layout with adaptive columns -- `DankListView` - Scrollable list view -- `DankTextField` - Text input with validation -- `DankDropdown` - Dropdown selection -- `DankPopout` - Base for overlay components -- `StateLayer` - Material interaction states - -## Theming - -**Dynamic Color Schemes** - -Wallpaper-based theming using [matugen](https://github.com/InioX/matugen): - -```qml -import qs.Common - -Rectangle { - color: Theme.container - border.color: Theme.outline -} -``` - -Theme singleton provides Material Design 3 color system, spacing, fonts, and elevation. - -**Application Themes** - -Templates in `scripts/templates/` generate themes for: -- GTK 3/4 -- Qt5/Qt6 -- Alacritty, Kitty, Ghostty, Foot, Wezterm terminals -- Neovim -- VSCode/VSCodium -- Firefox - -## Multi-Monitor Support - -Per-monitor panel instances using Quickshell `Variants`: - -```qml -Variants { - model: Quickshell.screens - PanelWindow { - screen: modelData - // Per-screen configuration - } -} -``` - -Workspace switchers adapt to compositor (Niri/Hyprland). - -## Plugin System - -External plugins in `~/.config/DankMaterialShell/plugins/`: - -**Widget plugins** - UI components in DankBar -**Daemon plugins** - Background processes without UI - -Plugin manifest (`plugin.json`): -```json -{ - "id": "pluginId", - "name": "Plugin Name", - "version": "1.0.0", - "type": "widget", - "component": "./Widget.qml", - "settings": "./Settings.qml", - "permissions": ["settings_read", "settings_write"] -} -``` - -Plugins access `pluginService` for persistent data: -```qml -pluginService.savePluginData("pluginId", "key", value) -pluginService.loadPluginData("pluginId", "key", defaultValue) -``` - -## IPC Integration - -Backend IPC socket communication: - -```qml -import Quickshell.Io - -Process { - command: ["dms", "ipc", "call", "spotlight", "toggle"] - running: true -} -``` - -Common IPC commands exposed through services for reactive property bindings. - -## Code Conventions - -**Component Structure:** -```qml -import QtQuick -import Quickshell -import qs.Common -import qs.Services - -Item { - id: root - - property type name: value - - signal customSignal(type param) - - Component { /* children */ } -} -``` - -**Services (Singletons):** -```qml -import QtQuick -import Quickshell -pragma Singleton -pragma ComponentBehavior: Bound - -Singleton { - id: root - - property bool featureAvailable: false - property type currentValue: defaultValue - - function performAction(param) { /* implementation */ } -} -``` - -**Guidelines:** -- Use `Theme.propertyName` for consistent styling -- Bind directly to service properties for reactivity -- Use `DankIcon` for all icons -- Implement feature detection and graceful degradation -- 4-space indentation, no unnecessary comments - -## Translation - -Internationalization using POEditor: - -```bash -export POEDITOR_API_TOKEN="token" -export POEDITOR_PROJECT_ID="id" -python3 scripts/i18nsync.py sync -``` - -Pre-commit hook checks translation sync status. - -## License - -MIT License - See [LICENSE](../LICENSE) for details. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml deleted file mode 100644 index 1c8413f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml +++ /dev/null @@ -1,985 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - property var applications: [] - property var _cachedCategories: null - property var _cachedVisibleApps: null - property var _hiddenAppsSet: new Set() - - property var _transformCache: ({}) - property var _cachedDefaultSections: [] - property var _cachedDefaultFlatModel: [] - property bool _defaultCacheValid: false - property int cacheVersion: 0 - - readonly property int maxResults: 10 - readonly property int frecencySampleSize: 10 - - readonly property var timeBuckets: [ - { - "maxDays": 4, - "weight": 100 - }, - { - "maxDays": 14, - "weight": 70 - }, - { - "maxDays": 31, - "weight": 50 - }, - { - "maxDays": 90, - "weight": 30 - }, - { - "maxDays": 99999, - "weight": 10 - } - ] - - function refreshApplications() { - applications = DesktopEntries.applications.values; - _cachedCategories = null; - _cachedVisibleApps = null; - invalidateLauncherCache(); - } - - function invalidateLauncherCache() { - _transformCache = {}; - _defaultCacheValid = false; - _cachedDefaultSections = []; - _cachedDefaultFlatModel = []; - cacheVersion++; - } - - function getOrTransformApp(app, transformFn) { - const id = app.id || app.execString || app.exec || ""; - if (!id) - return transformFn(app); - const cached = _transformCache[id]; - if (cached) { - const currentIcon = app.icon || ""; - const cachedSourceIcon = cached._sourceIcon || ""; - if (currentIcon === cachedSourceIcon) - return cached; - } - const transformed = transformFn(app); - transformed._sourceIcon = app.icon || ""; - _transformCache[id] = transformed; - return transformed; - } - - function getCachedDefaultSections() { - if (!_defaultCacheValid) - return null; - return _cachedDefaultSections; - } - - function setCachedDefaultSections(sections, flatModel) { - _cachedDefaultSections = sections.map(function (s) { - return Object.assign({}, s, { - items: s.items ? s.items.slice() : [] - }); - }); - _cachedDefaultFlatModel = flatModel.slice(); - _defaultCacheValid = true; - } - - function isCacheValid() { - return _defaultCacheValid; - } - - function _rebuildHiddenSet() { - _hiddenAppsSet = new Set(SessionData.hiddenApps || []); - _cachedVisibleApps = null; - } - - function isAppHidden(app) { - if (!app) - return false; - const appId = app.id || app.execString || app.exec || ""; - return _hiddenAppsSet.has(appId); - } - - function getVisibleApplications() { - if (_cachedVisibleApps === null) { - const seen = new Set(); - _cachedVisibleApps = applications.filter(app => { - if (isAppHidden(app)) - return false; - const id = app.id; - if (id && seen.has(id)) - return false; - if (id) - seen.add(id); - return true; - }); - } - return _cachedVisibleApps.map(app => applyAppOverride(app)); - } - - Connections { - target: SessionData - function onHiddenAppsChanged() { - root._rebuildHiddenSet(); - root.invalidateLauncherCache(); - } - function onAppOverridesChanged() { - root._cachedVisibleApps = null; - root.invalidateLauncherCache(); - } - } - - Connections { - target: AppUsageHistoryData - function onAppUsageRankingChanged() { - root.invalidateLauncherCache(); - } - } - - function applyAppOverride(app) { - if (!app) - return app; - const appId = app.id || app.execString || app.exec || ""; - const override = SessionData.getAppOverride(appId); - if (!override) - return app; - return Object.assign({}, app, { - name: override.name || app.name, - icon: override.icon || app.icon, - comment: override.comment || app.comment, - _override: override - }); - } - - readonly property string dmsLogoPath: Qt.resolvedUrl("../assets/danklogo2.svg") - - readonly property var builtInPlugins: ({ - "dms_settings": { - id: "dms_settings", - name: I18n.tr("Settings", "settings window title"), - icon: "svg+corner:" + dmsLogoPath + "|settings", - cornerIcon: "settings", - comment: "DMS", - action: "ipc:settings", - categories: ["Settings", "System"], - defaultTrigger: "", - isLauncher: false - }, - "dms_notepad": { - id: "dms_notepad", - name: I18n.tr("Notepad", "Notepad"), - icon: "svg+corner:" + dmsLogoPath + "|description", - cornerIcon: "description", - comment: "DMS", - action: "ipc:notepad", - categories: ["Office", "Utility"], - defaultTrigger: "", - isLauncher: false - }, - "dms_sysmon": { - id: "dms_sysmon", - name: I18n.tr("System Monitor", "sysmon window title"), - icon: "svg+corner:" + dmsLogoPath + "|monitor_heart", - cornerIcon: "monitor_heart", - comment: "DMS", - action: "ipc:processlist", - categories: ["System", "Monitor"], - defaultTrigger: "", - isLauncher: false - }, - "dms_colorpicker": { - id: "dms_colorpicker", - name: I18n.tr("Color Picker"), - icon: "svg+corner:" + dmsLogoPath + "|palette", - cornerIcon: "palette", - comment: "DMS", - action: "ipc:color-picker", - categories: ["Graphics", "Utility"], - defaultTrigger: "", - isLauncher: false - }, - "dms_settings_search": { - id: "dms_settings_search", - name: I18n.tr("Settings", "settings window title"), - cornerIcon: "search", - comment: "DMS", - defaultTrigger: "?", - isLauncher: true - } - }) - - function getBuiltInPluginTrigger(pluginId) { - const plugin = builtInPlugins[pluginId]; - if (!plugin) - return null; - return SettingsData.getBuiltInPluginSetting(pluginId, "trigger", plugin.defaultTrigger); - } - - readonly property var coreApps: { - SettingsData.builtInPluginSettings; - const apps = []; - for (const pluginId in builtInPlugins) { - if (!SettingsData.getBuiltInPluginSetting(pluginId, "enabled", true)) - continue; - const plugin = builtInPlugins[pluginId]; - if (plugin.isLauncher) - continue; - apps.push({ - name: plugin.name, - icon: plugin.icon, - comment: plugin.comment, - action: plugin.action, - categories: plugin.categories, - isCore: true, - builtInPluginId: pluginId, - cornerIcon: plugin.cornerIcon - }); - } - return apps; - } - - function getBuiltInLauncherPlugins() { - const result = {}; - for (const pluginId in builtInPlugins) { - const plugin = builtInPlugins[pluginId]; - if (!plugin.isLauncher) - continue; - if (!SettingsData.getBuiltInPluginSetting(pluginId, "enabled", true)) - continue; - result[pluginId] = plugin; - } - return result; - } - - function getBuiltInLauncherTriggers() { - const triggers = {}; - const launchers = getBuiltInLauncherPlugins(); - for (const pluginId in launchers) { - const trigger = getBuiltInPluginTrigger(pluginId); - if (trigger && trigger.trim() !== "") - triggers[trigger] = pluginId; - } - return triggers; - } - - function getBuiltInLauncherPluginsWithEmptyTrigger() { - const result = []; - const launchers = getBuiltInLauncherPlugins(); - for (const pluginId in launchers) { - const trigger = getBuiltInPluginTrigger(pluginId); - if (!trigger || trigger.trim() === "") - result.push(pluginId); - } - return result; - } - - function getBuiltInLauncherItems(pluginId, query) { - if (pluginId !== "dms_settings_search") - return []; - - SettingsSearchService.search(query); - const results = SettingsSearchService.results; - const items = []; - for (let i = 0; i < results.length; i++) { - const r = results[i]; - items.push({ - name: r.label, - icon: "material:" + r.icon, - comment: r.category, - action: "settings_nav:" + r.tabIndex + ":" + r.section, - categories: ["Settings"], - isCore: true, - isBuiltInLauncher: true, - builtInPluginId: pluginId - }); - } - return items; - } - - function executeBuiltInLauncherItem(item) { - if (!item?.action) - return false; - - const parts = item.action.split(":"); - if (parts[0] !== "settings_nav") - return false; - - const tabIndex = parseInt(parts[1]); - const section = parts.slice(2).join(":"); - SettingsSearchService.navigateToSection(section); - PopoutService.openSettingsWithTabIndex(tabIndex); - return true; - } - - function getCoreApps(query) { - if (!query || query.length === 0) - return coreApps; - const lowerQuery = query.toLowerCase(); - return coreApps.filter(app => app.name.toLowerCase().includes(lowerQuery) || app.comment.toLowerCase().includes(lowerQuery)); - } - - function executeCoreApp(app) { - if (!app?.action) - return false; - - const parts = app.action.split(":"); - if (parts[0] !== "ipc") - return false; - - switch (parts[1]) { - case "settings": - PopoutService.focusOrToggleSettings(); - return true; - case "notepad": - PopoutService.toggleNotepad(); - return true; - case "processlist": - PopoutService.toggleProcessListModal(); - return true; - case "color-picker": - PopoutService.showColorPicker(); - return true; - } - return false; - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - root.refreshApplications(); - } - } - - Component.onCompleted: { - _rebuildHiddenSet(); - refreshApplications(); - } - - function tokenize(text) { - return text.toLowerCase().trim().split(/[\s\-_]+/).filter(w => w.length > 0); - } - - function wordBoundaryMatch(text, query) { - const textWords = tokenize(text); - const queryWords = tokenize(query); - - if (queryWords.length === 0) - return false; - if (queryWords.length > textWords.length) - return false; - - for (var i = 0; i <= textWords.length - queryWords.length; i++) { - let allMatch = true; - for (var j = 0; j < queryWords.length; j++) { - if (!textWords[i + j].startsWith(queryWords[j])) { - allMatch = false; - break; - } - } - if (allMatch) - return true; - } - return false; - } - - function levenshteinDistance(s1, s2) { - const len1 = s1.length; - const len2 = s2.length; - const matrix = []; - - for (var i = 0; i <= len1; i++) { - matrix[i] = [i]; - } - for (var j = 0; j <= len2; j++) { - matrix[0][j] = j; - } - - for (var i = 1; i <= len1; i++) { - for (var j = 1; j <= len2; j++) { - const cost = s1[i - 1] === s2[j - 1] ? 0 : 1; - matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost); - } - } - return matrix[len1][len2]; - } - - function fuzzyMatchScore(text, query) { - const queryLower = query.toLowerCase(); - const maxDistance = query.length <= 2 ? 0 : query.length === 3 ? 1 : query.length <= 6 ? 2 : 3; - - let bestScore = 0; - - const distance = levenshteinDistance(text.toLowerCase(), queryLower); - if (distance <= maxDistance) { - const maxLen = Math.max(text.length, query.length); - bestScore = 1 - (distance / maxLen); - } - - const words = tokenize(text); - for (const word of words) { - const wordDistance = levenshteinDistance(word, queryLower); - if (wordDistance <= maxDistance) { - const maxLen = Math.max(word.length, query.length); - const score = 1 - (wordDistance / maxLen); - bestScore = Math.max(bestScore, score); - } - } - - return bestScore; - } - - function calculateFrecency(app) { - const usageRanking = AppUsageHistoryData.appUsageRanking || {}; - const appId = app.id || (app.execString || app.exec || ""); - const idVariants = [appId, appId.replace(".desktop", ""), app.id, app.id ? app.id.replace(".desktop", "") : null].filter(id => id); - - let usageData = null; - for (const variant of idVariants) { - if (usageRanking[variant]) { - usageData = usageRanking[variant]; - break; - } - } - - if (!usageData || !usageData.usageCount) { - return { - "frecency": 0, - "daysSinceUsed": 999999 - }; - } - - const usageCount = usageData.usageCount || 0; - const lastUsed = usageData.lastUsed || 0; - const now = Date.now(); - const daysSinceUsed = (now - lastUsed) / (1000 * 60 * 60 * 24); - - let timeBucketWeight = 10; - for (const bucket of timeBuckets) { - if (daysSinceUsed <= bucket.maxDays) { - timeBucketWeight = bucket.weight; - break; - } - } - - const contextBonus = 100; - const sampleSize = Math.min(usageCount, frecencySampleSize); - const frecency = (timeBucketWeight * contextBonus * sampleSize) / 100; - - return { - "frecency": frecency, - "daysSinceUsed": daysSinceUsed - }; - } - - function searchApplications(query) { - if (!query || query.length === 0) - return getVisibleApplications(); - if (applications.length === 0) - return []; - - const queryLower = query.toLowerCase().trim(); - const scoredApps = []; - const results = []; - const visibleApps = getVisibleApplications(); - - for (const app of visibleApps) { - const name = (app.name || "").toLowerCase(); - const genericName = (app.genericName || "").toLowerCase(); - const comment = (app.comment || "").toLowerCase(); - const id = (app.id || "").toLowerCase(); - const keywords = app.keywords ? app.keywords.map(k => k.toLowerCase()) : []; - - let textScore = 0; - let matchType = "none"; - - if (name === queryLower) { - textScore = 10000; - matchType = "exact"; - } else if (name.startsWith(queryLower)) { - textScore = 5000; - matchType = "prefix"; - } else if (wordBoundaryMatch(name, queryLower)) { - textScore = 3000; - matchType = "word_boundary"; - } else if (name.includes(queryLower)) { - textScore = 500; - matchType = "substring"; - } else if (genericName && genericName.startsWith(queryLower)) { - textScore = 800; - matchType = "generic_prefix"; - } else if (genericName && genericName.includes(queryLower)) { - textScore = 400; - matchType = "generic"; - } else if (id && id.includes(queryLower)) { - textScore = 350; - matchType = "id"; - } - - if (matchType === "none" && keywords.length > 0) { - for (const keyword of keywords) { - if (keyword.startsWith(queryLower)) { - textScore = 300; - matchType = "keyword_prefix"; - break; - } else if (keyword.includes(queryLower)) { - textScore = 150; - matchType = "keyword"; - break; - } - } - } - - if (matchType === "none" && comment && comment.includes(queryLower)) { - textScore = 50; - matchType = "comment"; - } - - if (matchType === "none") { - const fuzzyScore = fuzzyMatchScore(name, queryLower); - if (fuzzyScore > 0) { - textScore = fuzzyScore * 100; - matchType = "fuzzy"; - } - } - - if (matchType !== "none") { - const frecencyData = calculateFrecency(app); - - results.push({ - "app": app, - "textScore": textScore, - "frecency": frecencyData.frecency, - "daysSinceUsed": frecencyData.daysSinceUsed, - "matchType": matchType - }); - } - } - - for (const result of results) { - const frecencyBonus = result.frecency > 0 ? Math.min(result.frecency, 2000) : 0; - const recencyBonus = result.daysSinceUsed < 1 ? 1500 : result.daysSinceUsed < 7 ? 1000 : result.daysSinceUsed < 30 ? 500 : 0; - - const finalScore = result.textScore + frecencyBonus + recencyBonus; - - scoredApps.push({ - "app": result.app, - "score": finalScore - }); - } - - if (SessionData.searchAppActions) { - const actionResults = searchAppActions(queryLower, visibleApps); - for (const actionResult of actionResults) { - scoredApps.push({ - app: actionResult.app, - score: actionResult.score - }); - } - } - - scoredApps.sort((a, b) => b.score - a.score); - return scoredApps.slice(0, maxResults).map(item => item.app); - } - - function searchAppActions(query, apps) { - const results = []; - for (const app of apps) { - if (!app.actions || app.actions.length === 0) - continue; - for (const action of app.actions) { - const actionName = (action.name || "").toLowerCase(); - if (!actionName) - continue; - - let score = 0; - if (actionName === query) { - score = 8000; - } else if (actionName.startsWith(query)) { - score = 4000; - } else if (actionName.includes(query)) { - score = 400; - } - - if (score > 0) { - results.push({ - app: { - name: action.name, - icon: action.icon || app.icon, - comment: app.name, - categories: app.categories || [], - isAction: true, - parentApp: app, - actionData: action - }, - score: score - }); - } - } - } - return results; - } - - function getCategoriesForApp(app) { - if (!app?.categories) - return []; - - const categoryMap = { - "AudioVideo": I18n.tr("Media"), - "Audio": I18n.tr("Media"), - "Video": I18n.tr("Media"), - "Development": I18n.tr("Development"), - "TextEditor": I18n.tr("Development"), - "IDE": I18n.tr("Development"), - "Education": I18n.tr("Education"), - "Game": I18n.tr("Games"), - "Graphics": I18n.tr("Graphics"), - "Photography": I18n.tr("Graphics"), - "Network": I18n.tr("Internet"), - "WebBrowser": I18n.tr("Internet"), - "Email": I18n.tr("Internet"), - "Office": I18n.tr("Office"), - "WordProcessor": I18n.tr("Office"), - "Spreadsheet": I18n.tr("Office"), - "Presentation": I18n.tr("Office"), - "Science": I18n.tr("Science"), - "Settings": I18n.tr("Settings"), - "System": I18n.tr("System"), - "Utility": I18n.tr("Utilities"), - "Accessories": I18n.tr("Utilities"), - "FileManager": I18n.tr("Utilities"), - "TerminalEmulator": I18n.tr("Utilities") - }; - - const mappedCategories = new Set(); - - for (const cat of app.categories) { - if (categoryMap[cat]) - mappedCategories.add(categoryMap[cat]); - } - - return Array.from(mappedCategories); - } - - property var categoryIcons: ({ - "All": "apps", - "Media": "music_video", - "Development": "code", - "Games": "sports_esports", - "Graphics": "photo_library", - "Internet": "web", - "Office": "content_paste", - "Settings": "settings", - "System": "host", - "Utilities": "build" - }) - - function getCategoryIcon(category) { - // Check if it's a plugin category - const pluginIcon = getPluginCategoryIcon(category); - if (pluginIcon) { - return pluginIcon; - } - return categoryIcons[category] || "folder"; - } - - function getAllCategories() { - if (_cachedCategories) - return _cachedCategories; - - const categories = new Set([I18n.tr("All")]); - for (const app of applications) { - const appCategories = getCategoriesForApp(app); - appCategories.forEach(cat => categories.add(cat)); - } - - // Include categories from core apps (e.g. DMS Settings) - for (const app of coreApps) { - const appCategories = getCategoriesForApp(app); - appCategories.forEach(cat => categories.add(cat)); - } - - const pluginCategories = getPluginCategories(); - pluginCategories.forEach(cat => categories.add(cat)); - - _cachedCategories = Array.from(categories).sort(); - return _cachedCategories; - } - - function getAppsInCategory(category) { - const visibleApps = getVisibleApplications(); - if (category === I18n.tr("All")) - return visibleApps; - - const pluginItems = getPluginItems(category, ""); - if (pluginItems.length > 0) - return pluginItems; - - return visibleApps.filter(app => { - const appCategories = getCategoriesForApp(app); - return appCategories.includes(category); - }); - } - - // Plugin launcher support functions - function getPluginCategories() { - if (typeof PluginService === "undefined") { - return []; - } - - const categories = []; - const launchers = PluginService.getLauncherPlugins(); - - for (const pluginId in launchers) { - const plugin = launchers[pluginId]; - const categoryName = plugin.name || pluginId; - categories.push(categoryName); - } - - return categories; - } - - function getPluginCategoryIcon(category) { - if (typeof PluginService === "undefined") - return null; - - const launchers = PluginService.getLauncherPlugins(); - for (const pluginId in launchers) { - const plugin = launchers[pluginId]; - if ((plugin.name || pluginId) === category) { - return plugin.icon || "extension"; - } - } - return null; - } - - function getAllPluginItems() { - if (typeof PluginService === "undefined") { - return []; - } - - let allItems = []; - const launchers = PluginService.getLauncherPlugins(); - - for (const pluginId in launchers) { - const categoryName = launchers[pluginId].name || pluginId; - const items = getPluginItems(categoryName, ""); - allItems = allItems.concat(items); - } - - return allItems; - } - - function getPluginItems(category, query) { - if (typeof PluginService === "undefined") - return []; - - const launchers = PluginService.getLauncherPlugins(); - for (const pluginId in launchers) { - const plugin = launchers[pluginId]; - if ((plugin.name || pluginId) === category) { - return getPluginItemsForPlugin(pluginId, query); - } - } - return []; - } - - function getPluginItemsForPlugin(pluginId, query) { - if (typeof PluginService === "undefined") { - return []; - } - - let instance = PluginService.pluginInstances[pluginId]; - let isPersistent = true; - - if (!instance) { - const component = PluginService.pluginLauncherComponents[pluginId]; - if (!component) - return []; - - try { - instance = component.createObject(root, { - "pluginService": PluginService - }); - isPersistent = false; - } catch (e) { - console.warn("AppSearchService: Error creating temporary plugin instance", pluginId, ":", e); - return []; - } - } - - if (!instance) - return []; - - try { - if (typeof instance.getItems === "function") { - const items = instance.getItems(query || ""); - if (!isPersistent) - instance.destroy(); - return items || []; - } - - if (!isPersistent) { - instance.destroy(); - } - } catch (e) { - console.warn("AppSearchService: Error getting items from plugin", pluginId, ":", e); - if (!isPersistent) - instance.destroy(); - } - - return []; - } - - function executePluginItem(item, pluginId) { - if (typeof PluginService === "undefined") - return false; - - let instance = PluginService.pluginInstances[pluginId]; - let isPersistent = true; - - if (!instance) { - const component = PluginService.pluginLauncherComponents[pluginId]; - if (!component) - return false; - - try { - instance = component.createObject(root, { - "pluginService": PluginService - }); - isPersistent = false; - } catch (e) { - console.warn("AppSearchService: Error creating temporary plugin instance for execution", pluginId, ":", e); - return false; - } - } - - if (!instance) - return false; - - try { - if (typeof instance.executeItem === "function") { - instance.executeItem(item); - if (!isPersistent) - instance.destroy(); - return true; - } - - if (!isPersistent) { - instance.destroy(); - } - } catch (e) { - console.warn("AppSearchService: Error executing item from plugin", pluginId, ":", e); - if (!isPersistent) - instance.destroy(); - } - - return false; - } - - function getPluginPasteText(pluginId, item) { - if (typeof PluginService === "undefined") - return null; - - const instance = PluginService.pluginInstances[pluginId]; - if (!instance) - return null; - - if (typeof instance.getPasteText === "function") { - return instance.getPasteText(item); - } - - return null; - } - - function getPluginPasteArgs(pluginId, item) { - if (typeof PluginService === "undefined") - return null; - - const instance = PluginService.pluginInstances[pluginId]; - if (!instance) - return null; - - if (typeof instance.getPasteArgs === "function") - return instance.getPasteArgs(item); - - if (typeof instance.getPasteText === "function") { - const text = instance.getPasteText(item); - if (text) - return ["dms", "cl", "copy", text]; - } - - return null; - } - - function searchPluginItems(query) { - if (typeof PluginService === "undefined") - return []; - - let allItems = []; - const launchers = PluginService.getLauncherPlugins(); - - for (const pluginId in launchers) { - const items = getPluginItemsForPlugin(pluginId, query); - allItems = allItems.concat(items); - } - - return allItems; - } - - function getPluginLauncherCategories(pluginId) { - if (typeof PluginService === "undefined") - return []; - - const instance = PluginService.pluginInstances[pluginId]; - if (!instance) - return []; - - if (typeof instance.getCategories !== "function") - return []; - - try { - return instance.getCategories() || []; - } catch (e) { - console.warn("AppSearchService: Error getting categories from plugin", pluginId, ":", e); - return []; - } - } - - function setPluginLauncherCategory(pluginId, categoryId) { - if (typeof PluginService === "undefined") - return; - - const instance = PluginService.pluginInstances[pluginId]; - if (!instance) - return; - - if (typeof instance.setCategory !== "function") - return; - - try { - instance.setCategory(categoryId); - } catch (e) { - console.warn("AppSearchService: Error setting category on plugin", pluginId, ":", e); - } - } - - function pluginHasCategories(pluginId) { - if (typeof PluginService === "undefined") - return false; - - const instance = PluginService.pluginInstances[pluginId]; - if (!instance) - return false; - - return typeof instance.getCategories === "function"; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml deleted file mode 100644 index 015fedc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml +++ /dev/null @@ -1,1075 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services - -Singleton { - id: root - - readonly property PwNode sink: Pipewire.defaultAudioSink - readonly property PwNode source: Pipewire.defaultAudioSource - - readonly property bool soundsAvailable: MultimediaService.available - property bool gsettingsAvailable: false - property var availableSoundThemes: [] - property string currentSoundTheme: "" - property var soundFilePaths: ({}) - - property var volumeChangeSound: null - property var powerPlugSound: null - property var powerUnplugSound: null - property var normalNotificationSound: null - property var criticalNotificationSound: null - property var loginSound: null - property real notificationsVolume: 1.0 - property bool notificationsAudioMuted: false - - property var mediaDevices: null - property var mediaDevicesConnections: null - - property var deviceAliases: ({}) - property string wireplumberConfigPath: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/wireplumber/wireplumber.conf.d/51-dms-audio-aliases.conf" - property bool wireplumberReloading: false - - readonly property int sinkMaxVolume: { - const name = sink?.name ?? ""; - if (!name) - return 100; - return SessionData.deviceMaxVolumes[name] ?? 100; - } - - signal micMuteChanged - signal audioOutputCycled(string deviceName, string deviceIcon) - signal deviceAliasChanged(string nodeName, string newAlias) - signal wireplumberReloadStarted - signal wireplumberReloadCompleted(bool success) - - function getMaxVolumePercent(node) { - if (!node?.name) - return 100; - return SessionData.deviceMaxVolumes[node.name] ?? 100; - } - - Connections { - target: SessionData - function onDeviceMaxVolumesChanged() { - if (!root.sink?.audio) - return; - const maxVol = root.sinkMaxVolume; - const currentPercent = Math.round(root.sink.audio.volume * 100); - if (currentPercent > maxVol) - root.sink.audio.volume = maxVol / 100; - } - } - - // Used in playLoginSoundIfApplicable() - Process { - id: loginSoundChecker - onExited: (exitCode) => { - if (exitCode === 0) { - playLoginSound(); - } - } -} - - function getAvailableSinks() { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - return Pipewire.nodes.values.filter(node => node.audio && node.isSink && !node.isStream && !hidden.includes(node.name)); - } - - function cycleAudioOutput() { - const sinks = getAvailableSinks(); - if (sinks.length < 2) - return null; - - const currentName = root.sink?.name ?? ""; - const currentIndex = sinks.findIndex(s => s.name === currentName); - const nextIndex = (currentIndex + 1) % sinks.length; - const nextSink = sinks[nextIndex]; - Pipewire.preferredDefaultAudioSink = nextSink; - const name = displayName(nextSink); - audioOutputCycled(name, sinkIcon(nextSink)); - return name; - } - - function getDeviceAlias(nodeName) { - if (!nodeName) - return null; - return deviceAliases[nodeName] || null; - } - - function hasDeviceAlias(nodeName) { - if (!nodeName) - return false; - return deviceAliases.hasOwnProperty(nodeName) && deviceAliases[nodeName] !== null && deviceAliases[nodeName] !== ""; - } - - function setDeviceAlias(nodeName, customAlias) { - if (!nodeName) { - console.error("AudioService: Cannot set alias - nodeName is empty"); - return false; - } - - if (!customAlias || customAlias.trim() === "") { - return removeDeviceAlias(nodeName); - } - - const trimmedAlias = customAlias.trim(); - - const updated = Object.assign({}, deviceAliases); - updated[nodeName] = trimmedAlias; - deviceAliases = updated; - - writeWireplumberConfig(); - deviceAliasChanged(nodeName, trimmedAlias); - return true; - } - - function removeDeviceAlias(nodeName) { - if (!nodeName) - return false; - - if (!hasDeviceAlias(nodeName)) - return false; - - const updated = Object.assign({}, deviceAliases); - delete updated[nodeName]; - deviceAliases = updated; - - writeWireplumberConfig(); - deviceAliasChanged(nodeName, ""); - return true; - } - - function writeWireplumberConfig() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/wireplumber/wireplumber.conf.d"; - const configContent = generateWireplumberConfig(); - - const shellCmd = `mkdir -p "${configDir}" && cat > "${wireplumberConfigPath}" << 'EOFCONFIG' -${configContent} -EOFCONFIG -`; - - Proc.runCommand("writeWireplumberConfig", ["sh", "-c", shellCmd], (output, exitCode) => { - if (exitCode !== 0) { - console.error("AudioService: Failed to write WirePlumber config. Exit code:", exitCode); - console.error("AudioService: Error output:", output); - ToastService.showError(I18n.tr("Failed to save audio config"), output || ""); - return; - } - - reloadWireplumberConfig(); - }, 0); - } - - function generateWireplumberConfig() { - let config = "# Generated by DankMaterialShell - Audio Device Aliases\n"; - config += "# Do not edit manually - changes will be overwritten\n"; - config += "# Last updated: " + new Date().toISOString() + "\n\n"; - - const aliasKeys = Object.keys(deviceAliases); - if (aliasKeys.length === 0) { - config += "# No device aliases configured\n"; - return config; - } - - const alsaAliases = []; - const bluezAliases = []; - const otherAliases = []; - - for (const nodeName of aliasKeys) { - const alias = deviceAliases[nodeName]; - if (!alias) - continue; - - const rule = { - nodeName: nodeName, - alias: alias - }; - - if (nodeName.includes("alsa")) { - alsaAliases.push(rule); - } else if (nodeName.includes("bluez")) { - bluezAliases.push(rule); - } else { - otherAliases.push(rule); - } - } - - if (alsaAliases.length > 0) { - config += "monitor.alsa.rules = [\n"; - for (let i = 0; i < alsaAliases.length; i++) { - const rule = alsaAliases[i]; - config += " {\n"; - config += ` matches = [ { "node.name" = "${rule.nodeName}" } ]\n`; - config += ` actions = { update-props = { "node.description" = "${rule.alias}" } }\n`; - config += " }"; - if (i < alsaAliases.length - 1) - config += ","; - config += "\n"; - } - config += "]\n\n"; - } - - if (bluezAliases.length > 0) { - config += "monitor.bluez.rules = [\n"; - for (let i = 0; i < bluezAliases.length; i++) { - const rule = bluezAliases[i]; - config += " {\n"; - config += ` matches = [ { "node.name" = "${rule.nodeName}" } ]\n`; - config += ` actions = { update-props = { "node.description" = "${rule.alias}" } }\n`; - config += " }"; - if (i < bluezAliases.length - 1) - config += ","; - config += "\n"; - } - config += "]\n\n"; - } - - if (otherAliases.length > 0) { - config += "# Other device aliases (RAOP, USB, and other devices)\n"; - config += "wireplumber.rules = [\n"; - for (let i = 0; i < otherAliases.length; i++) { - const rule = otherAliases[i]; - config += " {\n"; - config += ` matches = [\n`; - config += ` { "node.name" = "${rule.nodeName}" }\n`; - config += ` ]\n`; - config += ` actions = {\n`; - config += ` update-props = {\n`; - config += ` "node.description" = "${rule.alias}"\n`; - config += ` "node.nick" = "${rule.alias}"\n`; - config += ` "device.description" = "${rule.alias}"\n`; - config += ` }\n`; - config += ` }\n`; - config += " }"; - if (i < otherAliases.length - 1) - config += ","; - config += "\n"; - } - config += "]\n"; - } - - return config; - } - - function reloadWireplumberConfig() { - if (wireplumberReloading) { - return; - } - - wireplumberReloading = true; - wireplumberReloadStarted(); - - Proc.runCommand("restartWireplumber", ["systemctl", "--user", "restart", "wireplumber"], (output, exitCode) => { - wireplumberReloading = false; - - if (exitCode === 0) { - ToastService.showInfo(I18n.tr("Audio system restarted"), I18n.tr("Device names updated")); - wireplumberReloadCompleted(true); - } else { - console.error("AudioService: Failed to restart WirePlumber:", output); - ToastService.showError(I18n.tr("Failed to restart audio system"), output); - wireplumberReloadCompleted(false); - } - }, 5000); - } - - function loadDeviceAliases() { - const configPath = wireplumberConfigPath; - - Proc.runCommand("readWireplumberConfig", ["cat", configPath], (output, exitCode) => { - if (exitCode !== 0) { - console.log("AudioService: No existing WirePlumber config found"); - return; - } - - const aliases = {}; - const lines = output.split('\n'); - let currentNodeName = null; - - for (const line of lines) { - const nodeNameMatch = line.match(/"node\.name"\s*=\s*"([^"]+)"/); - if (nodeNameMatch) { - currentNodeName = nodeNameMatch[1]; - } - - const descriptionMatch = line.match(/"node\.description"\s*=\s*"([^"]+)"/); - if (descriptionMatch && currentNodeName) { - aliases[currentNodeName] = descriptionMatch[1]; - currentNodeName = null; - } - } - - if (Object.keys(aliases).length > 0) { - deviceAliases = aliases; - console.log("AudioService: Loaded", Object.keys(aliases).length, "device aliases"); - } - }, 0); - } - - Connections { - target: root.sink?.audio ?? null - - function onVolumeChanged() { - if (SessionData.suppressOSD) - return; - root.playVolumeChangeSoundIfEnabled(); - } - } - - function checkGsettings() { - Proc.runCommand("checkGsettings", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null"], (output, exitCode) => { - gsettingsAvailable = (exitCode === 0); - if (gsettingsAvailable) { - scanSoundThemes(); - getCurrentSoundTheme(); - } - }, 0); - } - - function scanSoundThemes() { - const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS"); - const searchPaths = xdgDataDirs && xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat(Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))) : ["/usr/share", "/usr/local/share", Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))]; - - const basePaths = searchPaths.map(p => p + "/sounds").join(" "); - const script = ` - for base_dir in ${basePaths}; do - [ -d "$base_dir" ] || continue - for theme_dir in "$base_dir"/*; do - [ -d "$theme_dir/stereo" ] || continue - basename "$theme_dir" - done - done | sort -u - `; - - Proc.runCommand("scanSoundThemes", ["sh", "-c", script], (output, exitCode) => { - if (exitCode === 0 && output.trim()) { - const themes = output.trim().split('\n').filter(t => t && t.length > 0); - availableSoundThemes = themes; - } else { - availableSoundThemes = []; - } - }, 0); - } - - function getCurrentSoundTheme() { - Proc.runCommand("getCurrentSoundTheme", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null | sed \"s/'//g\""], (output, exitCode) => { - if (exitCode === 0 && output.trim()) { - currentSoundTheme = output.trim(); - console.log("AudioService: Current system sound theme:", currentSoundTheme); - if (SettingsData.useSystemSoundTheme) { - discoverSoundFiles(currentSoundTheme); - } - } else { - currentSoundTheme = ""; - console.log("AudioService: No system sound theme found"); - } - }, 0); - } - - function setSoundTheme(themeName) { - if (!themeName || themeName === currentSoundTheme) { - return; - } - - Proc.runCommand("setSoundTheme", ["sh", "-c", `gsettings set org.gnome.desktop.sound theme-name '${themeName}'`], (output, exitCode) => { - if (exitCode === 0) { - currentSoundTheme = themeName; - if (SettingsData.useSystemSoundTheme) { - discoverSoundFiles(themeName); - } - } - }, 0); - } - - function discoverSoundFiles(themeName) { - if (!themeName) { - soundFilePaths = {}; - if (soundsAvailable) { - destroySoundPlayers(); - createSoundPlayers(); - } - return; - } - - const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS"); - const searchPaths = xdgDataDirs && xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat(Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))) : ["/usr/share", "/usr/local/share", Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))]; - - const extensions = ["oga", "ogg", "wav", "mp3", "flac"]; - const themesToSearch = themeName !== "freedesktop" ? `${themeName} freedesktop` : themeName; - - const script = ` - for event_key in audio-volume-change power-plug power-unplug message message-new-instant desktop-login; do - found=0 - - case "$event_key" in - message) - names="dialog-information message message-lowpriority bell" - ;; - message-new-instant) - names="dialog-warning message-new-instant message-highlight" - ;; - *) - names="$event_key" - ;; - esac - - for theme in ${themesToSearch}; do - for event_name in $names; do - for base_path in ${searchPaths.join(" ")}; do - sounds_path="$base_path/sounds" - for ext in ${extensions.join(" ")}; do - file_path="$sounds_path/$theme/stereo/$event_name.$ext" - if [ -f "$file_path" ]; then - echo "$event_key=$file_path" - found=1 - break - fi - done - [ $found -eq 1 ] && break - done - [ $found -eq 1 ] && break - done - [ $found -eq 1 ] && break - done - done - `; - - Proc.runCommand("discoverSoundFiles", ["sh", "-c", script], (output, exitCode) => { - const paths = {}; - if (exitCode === 0 && output.trim()) { - const lines = output.trim().split('\n'); - for (let line of lines) { - const parts = line.split('='); - if (parts.length === 2) { - paths[parts[0]] = "file://" + parts[1]; - } - } - } - soundFilePaths = paths; - - if (soundsAvailable) { - destroySoundPlayers(); - createSoundPlayers(); - } - }, 0); - } - - function getSoundPath(soundEvent) { - const soundMap = { - "audio-volume-change": "../assets/sounds/freedesktop/audio-volume-change.wav", - "power-plug": "../assets/sounds/plasma/power-plug.wav", - "power-unplug": "../assets/sounds/plasma/power-unplug.wav", - "message": "../assets/sounds/freedesktop/message.wav", - "message-new-instant": "../assets/sounds/freedesktop/message-new-instant.wav", - "desktop-login": "../assets/sounds/freedesktop/desktop-login.wav" - }; - - const specialConditions = { - "smooth": ["audio-volume-change"] - }; - - const themeLower = currentSoundTheme.toLowerCase(); - if (SettingsData.useSystemSoundTheme && specialConditions[themeLower]?.includes(soundEvent)) { - const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav"); - console.log("AudioService: Using bundled sound (special condition) for", soundEvent, ":", bundledPath); - return bundledPath; - } - - if (SettingsData.useSystemSoundTheme && soundFilePaths[soundEvent]) { - console.log("AudioService: Using system sound for", soundEvent, ":", soundFilePaths[soundEvent]); - return soundFilePaths[soundEvent]; - } - - const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav"); - console.log("AudioService: Using bundled sound for", soundEvent, ":", bundledPath); - return bundledPath; - } - - function reloadSounds() { - console.log("AudioService: Reloading sounds, useSystemSoundTheme:", SettingsData.useSystemSoundTheme, "currentSoundTheme:", currentSoundTheme); - if (SettingsData.useSystemSoundTheme && currentSoundTheme) { - discoverSoundFiles(currentSoundTheme); - } else { - soundFilePaths = {}; - if (soundsAvailable) { - destroySoundPlayers(); - createSoundPlayers(); - } - } - } - - function setupMediaDevices() { - if (!soundsAvailable || mediaDevices) { - return; - } - - try { - mediaDevices = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaDevices { - id: devices - Component.onCompleted: { - console.log("AudioService: MediaDevices initialized, default output:", defaultAudioOutput?.description) - } - } - `, root, "AudioService.MediaDevices"); - - if (mediaDevices) { - mediaDevicesConnections = Qt.createQmlObject(` - import QtQuick - Connections { - target: root.mediaDevices - function onDefaultAudioOutputChanged() { - console.log("AudioService: Default audio output changed, recreating sound players") - root.destroySoundPlayers() - root.createSoundPlayers() - } - } - `, root, "AudioService.MediaDevicesConnections"); - } - } catch (e) { - console.log("AudioService: MediaDevices not available, using default audio output"); - mediaDevices = null; - } - } - - function destroySoundPlayers() { - if (volumeChangeSound) { - volumeChangeSound.destroy(); - volumeChangeSound = null; - } - if (powerPlugSound) { - powerPlugSound.destroy(); - powerPlugSound = null; - } - if (powerUnplugSound) { - powerUnplugSound.destroy(); - powerUnplugSound = null; - } - if (normalNotificationSound) { - normalNotificationSound.destroy(); - normalNotificationSound = null; - } - if (criticalNotificationSound) { - criticalNotificationSound.destroy(); - criticalNotificationSound = null; - } - if (loginSound) { - loginSound.destroy(); - loginSound = null; - } - } - - function createSoundPlayers() { - if (!soundsAvailable) { - return; - } - - setupMediaDevices(); - - try { - const deviceProperty = mediaDevices ? `device: root.mediaDevices.defaultAudioOutput\n ` : ""; - - const volumeChangePath = getSoundPath("audio-volume-change"); - volumeChangeSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${volumeChangePath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.VolumeChangeSound"); - - const powerPlugPath = getSoundPath("power-plug"); - powerPlugSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${powerPlugPath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.PowerPlugSound"); - - const powerUnplugPath = getSoundPath("power-unplug"); - powerUnplugSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${powerUnplugPath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.PowerUnplugSound"); - - const messagePath = getSoundPath("message"); - normalNotificationSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${messagePath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.NormalNotificationSound"); - - const messageNewInstantPath = getSoundPath("message-new-instant"); - criticalNotificationSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${messageNewInstantPath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.CriticalNotificationSound"); - - const loginPath = getSoundPath("desktop-login"); - loginSound = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - MediaPlayer { - source: "${loginPath}" - audioOutput: AudioOutput { - ${deviceProperty}volume: notificationsVolume - } - } - `, root, "AudioService.LoginSound"); - - } catch (e) { - console.warn("AudioService: Error creating sound players:", e); - } - } - - function isMediaPlaying() { - return MprisController.activePlayer?.isPlaying ?? false; - } - - function playVolumeChangeSound() { - if (!soundsAvailable || !volumeChangeSound || notificationsAudioMuted || isMediaPlaying()) - return; - volumeChangeSound.play(); - } - - function playPowerPlugSound() { - if (!soundsAvailable || !powerPlugSound || notificationsAudioMuted || isMediaPlaying()) - return; - powerPlugSound.play(); - } - - function playPowerUnplugSound() { - if (!soundsAvailable || !powerUnplugSound || notificationsAudioMuted || isMediaPlaying()) - return; - powerUnplugSound.play(); - } - - function playNormalNotificationSound() { - if (!soundsAvailable || !normalNotificationSound || SessionData.doNotDisturb || notificationsAudioMuted || isMediaPlaying()) - return; - normalNotificationSound.play(); - } - - function playCriticalNotificationSound() { - if (!soundsAvailable || !criticalNotificationSound || SessionData.doNotDisturb || notificationsAudioMuted || isMediaPlaying()) - return; - criticalNotificationSound.play(); - } - - function playLoginSound() { - if (!soundsAvailable || !loginSound || notificationsAudioMuted || isMediaPlaying()) { - return; - } - loginSound.play(); - } - - function playLoginSoundIfApplicable() { - if (SettingsData.soundsEnabled && SettingsData.soundLogin && !notificationsAudioMuted) { - // plays login sound on session start, but only if a specific file doesn't exist, - // to prevent it from playing on every DMS restart during the session - const runtimeDir = Quickshell.env("XDG_RUNTIME_DIR"); - const sessionId = Quickshell.env("XDG_SESSION_ID") || "0"; - - if (!runtimeDir) return; - - const loginFile = `${runtimeDir}/danklinux.login-${sessionId}`; - - // if file doesn't exist, touch it (0) - // If it exists, do nothing (1) - loginSoundChecker.command = ["sh", "-c", `[ ! -f ${loginFile} ] && touch ${loginFile}`]; - loginSoundChecker.running = true; - } - } - - function playVolumeChangeSoundIfEnabled() { - if (SettingsData.soundsEnabled && SettingsData.soundVolumeChanged && !notificationsAudioMuted) { - playVolumeChangeSound(); - } - } - - function sinkIcon(node) { - if (!node) - return "speaker"; - - const props = node.properties || {}; - const formFactor = (props["device.form-factor"] || "").toLowerCase(); - - switch (formFactor) { - case "headphone": - case "headset": - case "hands-free": - case "handset": - return "headset"; - case "tv": - case "monitor": - return "tv"; - case "speaker": - case "computer": - case "hifi": - case "portable": - case "car": - return "speaker"; - } - - const bus = (props["device.bus"] || "").toLowerCase(); - if (bus === "bluetooth") - return "headset"; - - const name = (node.name || "").toLowerCase(); - if (name.includes("hdmi")) - return "tv"; - if (name.includes("iec958") || name.includes("spdif")) - return "speaker"; - - if (bus === "usb") - return "headset"; - - return "speaker"; - } - - function displayName(node) { - if (!node) { - return ""; - } - - // FIRST: Check if we have a custom alias in our deviceAliases map - // This ensures we always show the user's custom name, regardless of - // whether WirePlumber has applied it to the node properties yet - if (node.name && deviceAliases[node.name]) { - return deviceAliases[node.name]; - } - - // Check node.properties["node.description"] for WirePlumber-applied aliases - // This is the live property updated by WirePlumber rules - if (node.properties && node.properties["node.description"]) { - const desc = node.properties["node.description"]; - if (desc !== node.name) { - return desc; - } - } - - // Check cached description as fallback - if (node.description && node.description !== node.name) { - return node.description; - } - - // Fallback to device description property - if (node.properties && node.properties["device.description"]) { - return node.properties["device.description"]; - } - - // Fallback to nickname - if (node.nickname && node.nickname !== node.name) { - return node.nickname; - } - - // Fallback to friendly names based on node name patterns - if (node.name.includes("analog-stereo")) { - return "Built-in Audio Analog Stereo"; - } - if (node.name.includes("bluez")) { - return "Bluetooth Audio"; - } - if (node.name.includes("usb")) { - return "USB Audio"; - } - if (node.name.includes("hdmi")) { - return "HDMI Audio"; - } - - return node.name; - } - - function originalName(node) { - if (!node) { - return ""; - } - - // Get the original name without checking for custom aliases - // Check pattern-based friendly names FIRST (before device.description) - // This ensures we show user-friendly names like "Built-in Audio Analog Stereo" - // instead of hardware chip names like "ALC274 Analog" - if (node.name.includes("analog-stereo")) { - return "Built-in Audio Analog Stereo"; - } - if (node.name.includes("bluez")) { - return "Bluetooth Audio"; - } - if (node.name.includes("usb")) { - return "USB Audio"; - } - if (node.name.includes("hdmi")) { - return "HDMI Audio"; - } - if (node.name.includes("raop_sink")) { - // Extract friendly name from RAOP node name - const match = node.name.match(/raop_sink\.([^.]+)/); - if (match) { - return match[1].replace(/-/g, " "); - } - } - - // Fallback to device.description property - if (node.properties && node.properties["device.description"]) { - return node.properties["device.description"]; - } - - // Fallback to nickname - if (node.nickname && node.nickname !== node.name) { - return node.nickname; - } - - return node.name; - } - - function subtitle(name) { - if (!name) { - return ""; - } - - if (name.includes('usb-')) { - if (name.includes('SteelSeries')) { - return "USB Gaming Headset"; - } - if (name.includes('Generic')) { - return "USB Audio Device"; - } - return "USB Audio"; - } - - if (name.includes('pci-')) { - if (name.includes('01_00.1') || name.includes('01:00.1')) { - return "NVIDIA GPU Audio"; - } - return "PCI Audio"; - } - - if (name.includes('bluez')) { - return "Bluetooth Audio"; - } - if (name.includes('analog')) { - return "Built-in Audio"; - } - if (name.includes('hdmi')) { - return "HDMI Audio"; - } - - return ""; - } - - PwObjectTracker { - objects: Pipewire.nodes.values.filter(node => node.audio && !node.isStream) - } - - Connections { - target: Pipewire - function onDefaultAudioSinkChanged() { - if (soundsAvailable) { - Qt.callLater(root.destroySoundPlayers); - Qt.callLater(root.createSoundPlayers); - } - } - } - - function setVolume(percentage) { - if (!root.sink?.audio) - return "No audio sink available"; - - const maxVol = root.sinkMaxVolume; - const clampedVolume = Math.max(0, Math.min(maxVol, percentage)); - root.sink.audio.volume = clampedVolume / 100; - return `Volume set to ${clampedVolume}%`; - } - - function toggleMute() { - if (!root.sink?.audio) { - return "No audio sink available"; - } - - root.sink.audio.muted = !root.sink.audio.muted; - return root.sink.audio.muted ? "Audio muted" : "Audio unmuted"; - } - - function setMicVolume(percentage) { - if (!root.source?.audio) { - return "No audio source available"; - } - - const clampedVolume = Math.max(0, Math.min(100, percentage)); - root.source.audio.volume = clampedVolume / 100; - return `Microphone volume set to ${clampedVolume}%`; - } - - function toggleMicMute() { - if (!root.source?.audio) { - return "No audio source available"; - } - - root.source.audio.muted = !root.source.audio.muted; - return root.source.audio.muted ? "Microphone muted" : "Microphone unmuted"; - } - - IpcHandler { - target: "audio" - - function setvolume(percentage: string): string { - return root.setVolume(parseInt(percentage)); - } - - function increment(step: string): string { - if (!root.sink?.audio) - return "No audio sink available"; - - if (root.sink.audio.muted) - root.sink.audio.muted = false; - - const maxVol = root.sinkMaxVolume; - const currentVolume = Math.round(root.sink.audio.volume * 100); - const stepValue = parseInt(step || "5"); - const newVolume = Math.max(0, Math.min(maxVol, currentVolume + stepValue)); - - root.sink.audio.volume = newVolume / 100; - return `Volume increased to ${newVolume}%`; - } - - function decrement(step: string): string { - if (!root.sink?.audio) - return "No audio sink available"; - - if (root.sink.audio.muted) - root.sink.audio.muted = false; - - const maxVol = root.sinkMaxVolume; - const currentVolume = Math.round(root.sink.audio.volume * 100); - const stepValue = parseInt(step || "5"); - const newVolume = Math.max(0, Math.min(maxVol, currentVolume - stepValue)); - - root.sink.audio.volume = newVolume / 100; - return `Volume decreased to ${newVolume}%`; - } - - function mute(): string { - return root.toggleMute(); - } - - function setmic(percentage: string): string { - return root.setMicVolume(parseInt(percentage)); - } - - function micmute(): string { - const result = root.toggleMicMute(); - root.micMuteChanged(); - return result; - } - - function status(): string { - let result = "Audio Status:\n"; - - if (root.sink?.audio) { - const volume = Math.round(root.sink.audio.volume * 100); - const muteStatus = root.sink.audio.muted ? " (muted)" : ""; - const maxVol = root.sinkMaxVolume; - result += `Output: ${volume}%${muteStatus} (max: ${maxVol}%)\n`; - } else { - result += "Output: No sink available\n"; - } - - if (root.source?.audio) { - const micVolume = Math.round(root.source.audio.volume * 100); - const muteStatus = root.source.audio.muted ? " (muted)" : ""; - result += `Input: ${micVolume}%${muteStatus}`; - } else { - result += "Input: No source available"; - } - - return result; - } - - function getmaxvolume(): string { - return `${root.sinkMaxVolume}`; - } - - function setmaxvolume(percent: string): string { - if (!root.sink?.name) - return "No audio sink available"; - const val = parseInt(percent); - if (isNaN(val)) - return "Invalid percentage"; - SessionData.setDeviceMaxVolume(root.sink.name, val); - return `Max volume set to ${SessionData.getDeviceMaxVolume(root.sink.name)}%`; - } - - function getmaxvolumefor(nodeName: string): string { - if (!nodeName) - return "No node name specified"; - return `${SessionData.getDeviceMaxVolume(nodeName)}`; - } - - function setmaxvolumefor(nodeName: string, percent: string): string { - if (!nodeName) - return "No node name specified"; - const val = parseInt(percent); - if (isNaN(val)) - return "Invalid percentage"; - SessionData.setDeviceMaxVolume(nodeName, val); - return `Max volume for ${nodeName} set to ${SessionData.getDeviceMaxVolume(nodeName)}%`; - } - - function cycleoutput(): string { - const result = root.cycleAudioOutput(); - if (!result) - return "Only one audio output available"; - return `Switched to: ${result}`; - } - } - - Connections { - target: SettingsData - function onUseSystemSoundThemeChanged() { - reloadSounds(); - } - } - - Component.onCompleted: { - if (soundsAvailable) { - checkGsettings(); - Qt.callLater(createSoundPlayers); - } - - loadDeviceAliases(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml deleted file mode 100644 index 0ae2450..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml +++ /dev/null @@ -1,171 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.I3 - -Singleton { - id: root - - property var widgetRegistry: ({}) - property var dankBarRepeater: null - - signal widgetRegistered(string widgetId, string screenName) - signal widgetUnregistered(string widgetId, string screenName) - - function registerWidget(widgetId, screenName, widgetRef) { - if (!widgetId || !screenName || !widgetRef) - return; - if (typeof widgetRegistry !== "object" || widgetRegistry === null) - widgetRegistry = ({}); - - if (!widgetRegistry[widgetId]) - widgetRegistry[widgetId] = {}; - - widgetRegistry[widgetId][screenName] = widgetRef; - widgetRegistered(widgetId, screenName); - } - - function unregisterWidget(widgetId, screenName) { - if (!widgetId || !screenName) - return; - if (typeof widgetRegistry !== "object" || widgetRegistry === null) - return; - if (!widgetRegistry[widgetId]) - return; - - delete widgetRegistry[widgetId][screenName]; - if (Object.keys(widgetRegistry[widgetId]).length === 0) - delete widgetRegistry[widgetId]; - - widgetUnregistered(widgetId, screenName); - } - - function getWidget(widgetId, screenName) { - if (!widgetRegistry[widgetId]) - return null; - if (screenName) - return widgetRegistry[widgetId][screenName] || null; - - const screens = Object.keys(widgetRegistry[widgetId]); - return screens.length > 0 ? widgetRegistry[widgetId][screens[0]] : null; - } - - function getWidgetOnFocusedScreen(widgetId) { - if (!widgetRegistry[widgetId]) - return null; - - const focusedScreen = getFocusedScreenName(); - if (focusedScreen && widgetRegistry[widgetId][focusedScreen]) - return widgetRegistry[widgetId][focusedScreen]; - - const screens = Object.keys(widgetRegistry[widgetId]); - return screens.length > 0 ? widgetRegistry[widgetId][screens[0]] : null; - } - - function getFocusedScreenName() { - if (CompositorService.isHyprland && Hyprland.focusedWorkspace?.monitor) - return Hyprland.focusedWorkspace.monitor.name; - if (CompositorService.isNiri && NiriService.currentOutput) - return NiriService.currentOutput; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs?.monitor?.name || ""; - } - return ""; - } - - function getRegisteredWidgetIds() { - return Object.keys(widgetRegistry); - } - - function hasWidget(widgetId) { - return widgetRegistry[widgetId] && Object.keys(widgetRegistry[widgetId]).length > 0; - } - - function triggerWidgetPopout(widgetId) { - const widget = getWidgetOnFocusedScreen(widgetId); - if (!widget) - return false; - - if (typeof widget.triggerPopout === "function") { - widget.triggerPopout(); - return true; - } - - const signalMap = { - "battery": "toggleBatteryPopup", - "vpn": "toggleVpnPopup", - "layout": "toggleLayoutPopup", - "clock": "clockClicked", - "cpuUsage": "cpuClicked", - "memUsage": "ramClicked", - "cpuTemp": "cpuTempClicked", - "gpuTemp": "gpuTempClicked" - }; - - const signalName = signalMap[widgetId]; - if (signalName && typeof widget[signalName] === "function") { - widget[signalName](); - return true; - } - - if (typeof widget.clicked === "function") { - widget.clicked(); - return true; - } - - if (widget.popoutTarget?.toggle) { - widget.popoutTarget.toggle(); - return true; - } - - return false; - } - - function getBarWindowForScreen(screenName) { - if (!dankBarRepeater) - return null; - - for (var i = 0; i < dankBarRepeater.count; i++) { - const loader = dankBarRepeater.itemAt(i); - if (!loader?.item) - continue; - - const barItem = loader.item; - if (!barItem.barVariants?.instances) - continue; - - for (var j = 0; j < barItem.barVariants.instances.length; j++) { - const barInstance = barItem.barVariants.instances[j]; - if (barInstance.modelData?.name === screenName) - return barInstance; - } - } - return null; - } - - function getBarWindowOnFocusedScreen() { - const focusedScreen = getFocusedScreenName(); - if (!focusedScreen) - return getFirstBarWindow(); - return getBarWindowForScreen(focusedScreen) || getFirstBarWindow(); - } - - function getFirstBarWindow() { - if (!dankBarRepeater || dankBarRepeater.count === 0) - return null; - - const loader = dankBarRepeater.itemAt(0); - if (!loader?.item) - return null; - - const barItem = loader.item; - if (!barItem.barVariants?.instances || barItem.barVariants.instances.length === 0) - return null; - - return barItem.barVariants.instances[0]; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml deleted file mode 100644 index e7cea56..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml +++ /dev/null @@ -1,271 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Services.UPower -import qs.Common - -Singleton { - id: root - - property bool suppressSound: true - property bool previousPluggedState: false - - readonly property var scale: 100 / SettingsData.batteryChargeLimit - - Timer { - id: startupTimer - interval: 500 - repeat: false - running: true - onTriggered: root.suppressSound = false - } - - readonly property string preferredBatteryOverride: Quickshell.env("DMS_PREFERRED_BATTERY") - - // List of laptop batteries - readonly property var batteries: UPower.devices.values.filter(dev => dev.isLaptopBattery) - - readonly property bool usePreferred: preferredBatteryOverride && preferredBatteryOverride.length > 0 - - // Main battery (for backward compatibility) - readonly property UPowerDevice device: { - var preferredDev; - if (usePreferred) { - preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase())); - } - return preferredDev || batteries[0] || null; - } - // Whether at least one battery is available - readonly property bool batteryAvailable: batteries.length > 0 - // Aggregated charge level (percentage) - readonly property real batteryLevel: { - if (!batteryAvailable) - return 0; - if (batteryCapacity === 0) { - if (usePreferred && device && device.ready) - return Math.round(device.percentage * 100 * scale); - const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0); - if (validBatteries.length === 0) - return 0; - const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length; - return Math.round(avgPercentage * 100 * scale); - } - return Math.round((batteryEnergy * 100) / batteryCapacity * scale); - } - readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging) - - // Is the system plugged in (Is not running on battery) - readonly property bool isPluggedIn: !UPower.onBattery - readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20 - - onIsPluggedInChanged: { - if (suppressSound || !batteryAvailable) { - previousPluggedState = isPluggedIn; - return; - } - - if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) { - if (isPluggedIn && !previousPluggedState) { - AudioService.playPowerPlugSound(); - } else if (!isPluggedIn && previousPluggedState) { - AudioService.playPowerUnplugSound(); - } - } - - const profileValue = BatteryService.isPluggedIn ? SettingsData.acProfileName : SettingsData.batteryProfileName; - - if (profileValue !== "") { - const targetProfile = parseInt(profileValue); - if (!isNaN(targetProfile) && PowerProfiles.profile !== targetProfile) { - PowerProfiles.profile = targetProfile; - } - } - - previousPluggedState = isPluggedIn; - } - - // Aggregated charge/discharge rate - readonly property real changeRate: { - if (!batteryAvailable) - return 0; - if (usePreferred && device && device.ready) - return device.changeRate; - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0; - } - - // Aggregated battery health - readonly property string batteryHealth: { - if (!batteryAvailable) - return "N/A"; - - // If a preferred battery is selected and ready - if (usePreferred && device && device.ready && device.healthSupported) - return `${Math.round(device.healthPercentage)}%`; - - // Otherwise, calculate the average health of all laptop batteries - const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0); - if (validBatteries.length === 0) - return "N/A"; - - const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length; - return `${Math.round(avgHealth)}%`; - } - - readonly property real batteryEnergy: { - if (!batteryAvailable) - return 0; - if (usePreferred && device && device.ready) - return device.energy; - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0; - } - - // Total battery capacity (Wh) - readonly property real batteryCapacity: { - if (!batteryAvailable) - return 0; - if (usePreferred && device && device.ready) - return device.energyCapacity; - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0; - } - - function translateBatteryState(state) { - switch (state) { - case UPowerDeviceState.Charging: - return I18n.tr("Charging", "battery status"); - case UPowerDeviceState.Discharging: - return I18n.tr("Discharging", "battery status"); - case UPowerDeviceState.Empty: - return I18n.tr("Empty", "battery status"); - case UPowerDeviceState.FullyCharged: - return I18n.tr("Fully Charged", "battery status"); - case UPowerDeviceState.PendingCharge: - return I18n.tr("Pending Charge", "battery status"); - case UPowerDeviceState.PendingDischarge: - return I18n.tr("Pending Discharge", "battery status"); - default: - return I18n.tr("Unknown", "battery status"); - } - } - - // Aggregated battery status - readonly property string batteryStatus: { - if (!batteryAvailable) { - return I18n.tr("No Battery", "battery status"); - } - - if (isCharging && !batteries.some(b => b.changeRate > 0)) - return I18n.tr("Plugged In", "battery status"); - - const states = batteries.map(b => b.state); - if (states.every(s => s === states[0])) - return translateBatteryState(states[0]); - - return isCharging ? I18n.tr("Charging", "battery status") : (isPluggedIn ? I18n.tr("Plugged In", "battery status") : I18n.tr("Discharging", "battery status")); - } - - readonly property bool suggestPowerSaver: false - - readonly property var bluetoothDevices: { - const btDevices = []; - const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers]; - - for (var i = 0; i < UPower.devices.count; i++) { - const dev = UPower.devices.get(i); - if (dev && dev.ready && bluetoothTypes.includes(dev.type)) { - btDevices.push({ - "name": dev.model || UPowerDeviceType.toString(dev.type), - "percentage": Math.round(dev.percentage * 100), - "type": dev.type - }); - } - } - return btDevices; - } - - // Format time remaining for charge/discharge - function formatTimeRemaining() { - if (!batteryAvailable) { - return "Unknown"; - } - - let totalTime = 0; - totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate); - const avgTime = Math.abs(totalTime * 3600); - if (!avgTime || avgTime <= 0 || avgTime > 86400) - return "Unknown"; - - const hours = Math.floor(avgTime / 3600); - const minutes = Math.floor((avgTime % 3600) / 60); - return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; - } - - function getBatteryIcon() { - if (!batteryAvailable) { - return "power"; - } - - if (isCharging) { - if (batteryLevel >= 90) { - return "battery_charging_full"; - } - if (batteryLevel >= 80) { - return "battery_charging_90"; - } - if (batteryLevel >= 60) { - return "battery_charging_80"; - } - if (batteryLevel >= 50) { - return "battery_charging_60"; - } - if (batteryLevel >= 30) { - return "battery_charging_50"; - } - if (batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } - if (isPluggedIn) { - if (batteryLevel >= 90) { - return "battery_charging_full"; - } - if (batteryLevel >= 80) { - return "battery_charging_90"; - } - if (batteryLevel >= 60) { - return "battery_charging_80"; - } - if (batteryLevel >= 50) { - return "battery_charging_60"; - } - if (batteryLevel >= 30) { - return "battery_charging_50"; - } - if (batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } - if (batteryLevel >= 95) { - return "battery_full"; - } - if (batteryLevel >= 85) { - return "battery_6_bar"; - } - if (batteryLevel >= 70) { - return "battery_5_bar"; - } - if (batteryLevel >= 55) { - return "battery_4_bar"; - } - if (batteryLevel >= 40) { - return "battery_3_bar"; - } - if (batteryLevel >= 25) { - return "battery_2_bar"; - } - return "battery_1_bar"; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml deleted file mode 100644 index 4de300e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml +++ /dev/null @@ -1,523 +0,0 @@ -pragma Singleton - -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Bluetooth -import qs.Services - -Singleton { - id: root - - readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter - readonly property bool available: adapter !== null - readonly property bool enabled: (adapter && adapter.enabled) ?? false - readonly property bool discovering: (adapter && adapter.discovering) ?? false - readonly property var devices: adapter ? adapter.devices : null - readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth") - readonly property bool connected: { - if (!adapter || !adapter.devices) { - return false - } - - let isConnected = false - adapter.devices.values.forEach(dev => { if (dev.connected) isConnected = true }) - return isConnected - } - readonly property var pairedDevices: { - if (!adapter || !adapter.devices) { - return [] - } - - return adapter.devices.values.filter(dev => { - return dev && (dev.paired || dev.trusted) - }) - } - readonly property var allDevicesWithBattery: { - if (!adapter || !adapter.devices) { - return [] - } - - return adapter.devices.values.filter(dev => { - return dev && dev.batteryAvailable && dev.battery > 0 - }) - } - - function sortDevices(devices) { - return devices.sort((a, b) => { - const aName = a.name || a.deviceName || "" - const bName = b.name || b.deviceName || "" - const aAddr = a.address || "" - const bAddr = b.address || "" - - const aHasRealName = aName.includes(" ") && aName.length > 3 - const bHasRealName = bName.includes(" ") && bName.length > 3 - - if (aHasRealName && !bHasRealName) return -1 - if (!aHasRealName && bHasRealName) return 1 - - if (aHasRealName && bHasRealName) { - return aName.localeCompare(bName) - } - - return aAddr.localeCompare(bAddr) - }) - } - - function getDeviceIcon(device) { - if (!device) { - return "bluetooth" - } - - const name = (device.name || device.deviceName || "").toLowerCase() - const icon = (device.icon || "").toLowerCase() - - const audioKeywords = ["headset", "audio", "headphone", "airpod", "arctis"] - if (audioKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) { - return "headset" - } - - if (icon.includes("mouse") || name.includes("mouse")) { - return "mouse" - } - - if (icon.includes("keyboard") || name.includes("keyboard")) { - return "keyboard" - } - - const phoneKeywords = ["phone", "iphone", "android", "samsung"] - if (phoneKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) { - return "smartphone" - } - - if (icon.includes("watch") || name.includes("watch")) { - return "watch" - } - - if (icon.includes("speaker") || name.includes("speaker")) { - return "speaker" - } - - if (icon.includes("display") || name.includes("tv")) { - return "tv" - } - - return "bluetooth" - } - - function canConnect(device) { - if (!device) { - return false - } - - return !device.paired && !device.pairing && !device.blocked - } - - function getSignalStrength(device) { - if (!device || device.signalStrength === undefined || device.signalStrength <= 0) { - return "Unknown" - } - - const signal = device.signalStrength - if (signal >= 80) { - return "Excellent" - } - if (signal >= 60) { - return "Good" - } - if (signal >= 40) { - return "Fair" - } - if (signal >= 20) { - return "Poor" - } - - return "Very Poor" - } - - function getSignalIcon(device) { - if (!device || device.signalStrength === undefined || device.signalStrength <= 0) { - return "signal_cellular_null" - } - - const signal = device.signalStrength - if (signal >= 80) { - return "signal_cellular_4_bar" - } - if (signal >= 60) { - return "signal_cellular_3_bar" - } - if (signal >= 40) { - return "signal_cellular_2_bar" - } - if (signal >= 20) { - return "signal_cellular_1_bar" - } - - return "signal_cellular_0_bar" - } - - function isDeviceBusy(device) { - if (!device) { - return false - } - return device.pairing || device.state === BluetoothDeviceState.Disconnecting || device.state === BluetoothDeviceState.Connecting - } - - function connectDeviceWithTrust(device) { - if (!device) { - return - } - - device.trusted = true - device.connect() - } - - function pairDevice(device, callback) { - if (!device) { - if (callback) callback({error: "Invalid device"}) - return - } - - // The DMS backend actually implements a bluez agent, so we can pair anything - if (enhancedPairingAvailable) { - const devicePath = getDevicePath(device) - DMSService.bluetoothPair(devicePath, callback) - return - } - - // Quickshell does not implement a bluez agent, so we can try to pair but only with devices that don't require a passcode - device.trusted = true - device.connect() - if (callback) callback({success: true}) - } - - function getCardName(device) { - if (!device) { - return "" - } - return `bluez_card.${device.address.replace(/:/g, "_")}` - } - - function getDevicePath(device) { - if (!device || !device.address) { - return "" - } - const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0" - return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}` - } - - function isAudioDevice(device) { - if (!device) { - return false - } - const icon = getDeviceIcon(device) - return icon === "headset" || icon === "speaker" - } - - function getCodecInfo(codecName) { - const codec = codecName.replace(/-/g, "_").toUpperCase() - - const codecMap = { - "LDAC": { - "name": "LDAC", - "description": "Highest quality • Higher battery usage", - "qualityColor": "#4CAF50" - }, - "APTX_HD": { - "name": "aptX HD", - "description": "High quality • Balanced battery", - "qualityColor": "#FF9800" - }, - "APTX": { - "name": "aptX", - "description": "Good quality • Low latency", - "qualityColor": "#FF9800" - }, - "AAC": { - "name": "AAC", - "description": "Balanced quality and battery", - "qualityColor": "#2196F3" - }, - "SBC_XQ": { - "name": "SBC-XQ", - "description": "Enhanced SBC • Better compatibility", - "qualityColor": "#2196F3" - }, - "SBC": { - "name": "SBC", - "description": "Basic quality • Universal compatibility", - "qualityColor": "#9E9E9E" - }, - "MSBC": { - "name": "mSBC", - "description": "Modified SBC • Optimized for speech", - "qualityColor": "#9E9E9E" - }, - "CVSD": { - "name": "CVSD", - "description": "Basic speech codec • Legacy compatibility", - "qualityColor": "#9E9E9E" - } - } - - return codecMap[codec] || { - "name": codecName, - "description": "Unknown codec", - "qualityColor": "#9E9E9E" - } - } - - property var deviceCodecs: ({}) - - function updateDeviceCodec(deviceAddress, codec) { - deviceCodecs[deviceAddress] = codec - deviceCodecsChanged() - } - - function refreshDeviceCodec(device) { - if (!device || !device.connected || !isAudioDevice(device)) { - return - } - - const cardName = getCardName(device) - codecQueryProcess.cardName = cardName - codecQueryProcess.deviceAddress = device.address - codecQueryProcess.availableCodecs = [] - codecQueryProcess.parsingTargetCard = false - codecQueryProcess.detectedCodec = "" - codecQueryProcess.running = true - } - - function getCurrentCodec(device, callback) { - if (!device || !device.connected || !isAudioDevice(device)) { - callback("") - return - } - - const cardName = getCardName(device) - codecQueryProcess.cardName = cardName - codecQueryProcess.callback = callback - codecQueryProcess.availableCodecs = [] - codecQueryProcess.parsingTargetCard = false - codecQueryProcess.detectedCodec = "" - codecQueryProcess.running = true - } - - function getAvailableCodecs(device, callback) { - if (!device || !device.connected || !isAudioDevice(device)) { - callback([], "") - return - } - - const cardName = getCardName(device) - codecFullQueryProcess.cardName = cardName - codecFullQueryProcess.callback = callback - codecFullQueryProcess.availableCodecs = [] - codecFullQueryProcess.parsingTargetCard = false - codecFullQueryProcess.detectedCodec = "" - codecFullQueryProcess.running = true - } - - function switchCodec(device, profileName, callback) { - if (!device || !isAudioDevice(device)) { - callback(false, "Invalid device") - return - } - - const cardName = getCardName(device) - codecSwitchProcess.cardName = cardName - codecSwitchProcess.profile = profileName - codecSwitchProcess.callback = callback - codecSwitchProcess.running = true - } - - Process { - id: codecQueryProcess - - property string cardName: "" - property string deviceAddress: "" - property var callback: null - property bool parsingTargetCard: false - property string detectedCodec: "" - property var availableCodecs: [] - - command: ["pactl", "list", "cards"] - - onExited: (exitCode, exitStatus) => { - if (exitCode === 0 && detectedCodec) { - if (deviceAddress) { - root.updateDeviceCodec(deviceAddress, detectedCodec) - } - if (callback) { - callback(detectedCodec) - } - } else if (callback) { - callback("") - } - - parsingTargetCard = false - detectedCodec = "" - availableCodecs = [] - deviceAddress = "" - callback = null - } - - stdout: SplitParser { - splitMarker: "\n" - onRead: data => { - let line = data.trim() - - if (line.includes(`Name: ${codecQueryProcess.cardName}`)) { - codecQueryProcess.parsingTargetCard = true - return - } - - if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) { - codecQueryProcess.parsingTargetCard = false - return - } - - if (codecQueryProcess.parsingTargetCard) { - if (line.startsWith("Active Profile:")) { - let profile = line.split(": ")[1] || "" - let activeCodec = codecQueryProcess.availableCodecs.find(c => { - return c.profile === profile - }) - if (activeCodec) { - codecQueryProcess.detectedCodec = activeCodec.name - } - return - } - if (line.includes("codec") && line.includes("available: yes")) { - let parts = line.split(": ") - if (parts.length >= 2) { - let profile = parts[0].trim() - let description = parts[1] - let codecMatch = description.match(/codec ([^\)\s]+)/i) - let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN" - let codecInfo = root.getCodecInfo(codecName) - if (codecInfo && !codecQueryProcess.availableCodecs.some(c => { - return c.profile === profile - })) { - let newCodecs = codecQueryProcess.availableCodecs.slice() - newCodecs.push({ - "name": codecInfo.name, - "profile": profile, - "description": codecInfo.description, - "qualityColor": codecInfo.qualityColor - }) - codecQueryProcess.availableCodecs = newCodecs - } - } - } - } - } - } - } - - Process { - id: codecFullQueryProcess - - property string cardName: "" - property var callback: null - property bool parsingTargetCard: false - property string detectedCodec: "" - property var availableCodecs: [] - - command: ["pactl", "list", "cards"] - - onExited: function (exitCode, exitStatus) { - if (callback) { - callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "") - } - parsingTargetCard = false - detectedCodec = "" - availableCodecs = [] - callback = null - } - - stdout: SplitParser { - splitMarker: "\n" - onRead: data => { - let line = data.trim() - - if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) { - codecFullQueryProcess.parsingTargetCard = true - return - } - - if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) { - codecFullQueryProcess.parsingTargetCard = false - return - } - - if (codecFullQueryProcess.parsingTargetCard) { - if (line.startsWith("Active Profile:")) { - let profile = line.split(": ")[1] || "" - let activeCodec = codecFullQueryProcess.availableCodecs.find(c => { - return c.profile === profile - }) - if (activeCodec) { - codecFullQueryProcess.detectedCodec = activeCodec.name - } - return - } - if (line.includes("codec") && line.includes("available: yes")) { - let parts = line.split(": ") - if (parts.length >= 2) { - let profile = parts[0].trim() - let description = parts[1] - let codecMatch = description.match(/codec ([^\)\s]+)/i) - let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN" - let codecInfo = root.getCodecInfo(codecName) - if (codecInfo && !codecFullQueryProcess.availableCodecs.some(c => { - return c.profile === profile - })) { - let newCodecs = codecFullQueryProcess.availableCodecs.slice() - newCodecs.push({ - "name": codecInfo.name, - "profile": profile, - "description": codecInfo.description, - "qualityColor": codecInfo.qualityColor - }) - codecFullQueryProcess.availableCodecs = newCodecs - } - } - } - } - } - } - } - - Process { - id: codecSwitchProcess - - property string cardName: "" - property string profile: "" - property var callback: null - - command: ["pactl", "set-card-profile", cardName, profile] - - onExited: function (exitCode, exitStatus) { - if (callback) { - callback(exitCode === 0, exitCode === 0 ? "Codec switched successfully" : "Failed to switch codec") - } - - // If successful, refresh the codec for this device - if (exitCode === 0) { - if (root.adapter && root.adapter.devices) { - root.adapter.devices.values.forEach(device => { - if (device && root.getCardName(device) === cardName) { - Qt.callLater(() => root.refreshDeviceCodec(device)) - } - }) - } - } - - callback = null - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml deleted file mode 100644 index 40a3aeb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml +++ /dev/null @@ -1,113 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland // ! Import is needed despite what qmlls says -import qs.Common - -Singleton { - id: root - - property bool quickshellSupported: false - property bool compositorSupported: false - property bool available: quickshellSupported && compositorSupported - readonly property bool enabled: available && (SettingsData.blurEnabled ?? false) - - readonly property color borderColor: { - if (!enabled) - return "transparent"; - const opacity = SettingsData.blurBorderOpacity ?? 0.5; - switch (SettingsData.blurBorderColor ?? "outline") { - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "surfaceText": - return Theme.withAlpha(Theme.surfaceText, opacity); - case "custom": - return Theme.withAlpha(SettingsData.blurBorderCustomColor ?? "#ffffff", opacity); - default: - return Theme.withAlpha(Theme.outline, opacity); - } - } - readonly property int borderWidth: enabled ? 1 : 0 - - function hoverColor(baseColor, hoverAlpha) { - if (!enabled) - return baseColor; - return Theme.withAlpha(baseColor, hoverAlpha ?? 0.15); - } - - function createBlurRegion(targetWindow) { - if (!available) - return null; - - try { - const region = Qt.createQmlObject(` - import Quickshell - Region {} - `, targetWindow, "BlurRegion"); - targetWindow.BackgroundEffect.blurRegion = region; - return region; - } catch (e) { - console.warn("BlurService: Failed to create blur region:", e); - return null; - } - } - - function reapplyBlurRegion(targetWindow, region) { - if (!region || !available) - return; - try { - targetWindow.BackgroundEffect.blurRegion = region; - region.changed(); - } catch (e) {} - } - - function destroyBlurRegion(targetWindow, region) { - if (!region) - return; - try { - targetWindow.BackgroundEffect.blurRegion = null; - } catch (e) {} - region.destroy(); - } - - Process { - id: blurProbe - running: false - command: ["dms", "blur", "check"] - - stdout: StdioCollector { - onStreamFinished: { - root.compositorSupported = text.trim() === "supported"; - if (root.compositorSupported) - console.info("BlurService: Compositor supports ext-background-effect-v1"); - else - console.info("BlurService: Compositor does not support ext-background-effect-v1"); - } - } - - onExited: exitCode => { - if (exitCode !== 0) - console.warn("BlurService: blur probe failed with code:", exitCode); - } - } - - Component.onCompleted: { - try { - const test = Qt.createQmlObject(` - import Quickshell - Region { radius: 0 } - `, root, "BlurAvailabilityTest"); - test.destroy(); - quickshellSupported = true; - console.info("BlurService: Quickshell blur support available"); - blurProbe.running = true; - } catch (e) { - console.info("BlurService: BackgroundEffect not available - blur disabled. Requires a newer version of Quickshell."); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml deleted file mode 100644 index 1146f7b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml +++ /dev/null @@ -1,317 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool khalAvailable: false - property var eventsByDate: ({}) - property bool isLoading: false - property string lastError: "" - property date lastStartDate - property date lastEndDate - property string khalDateFormat: "MM/dd/yyyy" - - function checkKhalAvailability() { - if (!khalCheckProcess.running) - khalCheckProcess.running = true - } - - function detectKhalDateFormat() { - if (!khalFormatProcess.running) - khalFormatProcess.running = true - } - - function parseKhalDateFormat(formatExample) { - let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy") - return { format: qtFormat, parser: null } - } - - - function loadCurrentMonth() { - if (!root.khalAvailable) - return - - let today = new Date() - let firstDay = new Date(today.getFullYear(), today.getMonth(), 1) - let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0) - // Add padding - let startDate = new Date(firstDay) - startDate.setDate(startDate.getDate() - firstDay.getDay() - 7) - let endDate = new Date(lastDay) - endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7) - loadEvents(startDate, endDate) - } - - function loadEvents(startDate, endDate) { - if (!root.khalAvailable) { - return - } - if (eventsProcess.running) { - return - } - // Store last requested date range for refresh timer - root.lastStartDate = startDate - root.lastEndDate = endDate - root.isLoading = true - // Format dates for khal using detected format - let startDateStr = Qt.formatDate(startDate, root.khalDateFormat) - let endDateStr = Qt.formatDate(endDate, root.khalDateFormat) - eventsProcess.requestStartDate = startDate - eventsProcess.requestEndDate = endDate - eventsProcess.command = ["khal", "list", "--json", "title", "--json", "description", "--json", "start-date", "--json", "start-time", "--json", "end-date", "--json", "end-time", "--json", "all-day", "--json", "location", "--json", "url", startDateStr, endDateStr] - eventsProcess.running = true - } - - function getEventsForDate(date) { - let dateKey = Qt.formatDate(date, "yyyy-MM-dd") - return root.eventsByDate[dateKey] || [] - } - - function hasEventsForDate(date) { - let events = getEventsForDate(date) - return events.length > 0 - } - - // Initialize on component completion - Component.onCompleted: { - detectKhalDateFormat() - } - - // Process for detecting khal date format - Process { - id: khalFormatProcess - - command: ["khal", "printformats"] - running: false - onExited: exitCode => { - if (exitCode !== 0) { - checkKhalAvailability() - } - } - - stdout: StdioCollector { - onStreamFinished: { - let lines = text.split('\n') - for (let line of lines) { - if (line.startsWith('dateformat:')) { - let formatExample = line.substring(line.indexOf(':') + 1).trim() - let formatInfo = parseKhalDateFormat(formatExample) - root.khalDateFormat = formatInfo.format - break - } - } - checkKhalAvailability() - } - } - } - - // Process for checking khal configuration - Process { - id: khalCheckProcess - - command: ["khal", "list", "today"] - running: false - onExited: exitCode => { - root.khalAvailable = (exitCode === 0) - if (exitCode === 0) { - loadCurrentMonth() - } - } - } - - // Process for loading events - Process { - id: eventsProcess - - property date requestStartDate - property date requestEndDate - property string rawOutput: "" - - running: false - onExited: exitCode => { - root.isLoading = false - if (exitCode !== 0) { - root.lastError = "Failed to load events (exit code: " + exitCode + ")" - return - } - try { - let newEventsByDate = {} - let lines = eventsProcess.rawOutput.split('\n') - for (let line of lines) { - line = line.trim() - if (!line || line === "[]") - continue - - // Parse JSON line - let dayEvents = JSON.parse(line) - // Process each event in this day's array - for (let event of dayEvents) { - if (!event.title) - continue - - // Parse start and end dates using detected format - let startDate, endDate - if (event['start-date']) { - startDate = Date.fromLocaleString(I18n.locale(), event['start-date'], root.khalDateFormat) - } else { - startDate = new Date() - } - if (event['end-date']) { - endDate = Date.fromLocaleString(I18n.locale(), event['end-date'], root.khalDateFormat) - } else { - endDate = new Date(startDate) - } - // Create start/end times - let startTime = new Date(startDate) - let endTime = new Date(endDate) - if (event['start-time'] - && event['all-day'] !== "True") { - // Parse time if available and not all-day - let timeStr = event['start-time'] - if (timeStr) { - // Match time with optional seconds and AM/PM - let timeParts = timeStr.match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i) - if (timeParts) { - let hours = parseInt(timeParts[1]) - let minutes = parseInt(timeParts[2]) - - // Handle AM/PM conversion if present - if (timeParts[3]) { - let period = timeParts[3].toUpperCase() - if (period === 'PM' && hours !== 12) { - hours += 12 - } else if (period === 'AM' && hours === 12) { - hours = 0 - } - } - - startTime.setHours(hours, minutes) - if (event['end-time']) { - let endTimeParts = event['end-time'].match( - /(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i) - if (endTimeParts) { - let endHours = parseInt(endTimeParts[1]) - let endMinutes = parseInt(endTimeParts[2]) - - // Handle AM/PM conversion if present - if (endTimeParts[3]) { - let endPeriod = endTimeParts[3].toUpperCase() - if (endPeriod === 'PM' && endHours !== 12) { - endHours += 12 - } else if (endPeriod === 'AM' && endHours === 12) { - endHours = 0 - } - } - - endTime.setHours(endHours, endMinutes) - } - } else { - // Default to 1 hour duration on same day - endTime = new Date(startTime) - endTime.setHours( - startTime.getHours() + 1) - } - } - } - } - // Create unique ID for this event (to track multi-day events) - let eventId = event.title + "_" + event['start-date'] - + "_" + (event['start-time'] || 'allday') - // Create event object template - let extractedUrl = "" - if (!event.url && event.description) { - let urlMatch = event.description.match(/https?:\/\/[^\s]+/) - if (urlMatch) { - extractedUrl = urlMatch[0] - } - } - let eventTemplate = { - "id": eventId, - "title": event.title || "Untitled Event", - "start": startTime, - "end": endTime, - "location": event.location || "", - "description": event.description || "", - "url": event.url || extractedUrl, - "calendar": "", - "color": "", - "allDay": event['all-day'] === "True", - "isMultiDay": startDate.toDateString( - ) !== endDate.toDateString() - } - // Add event to each day it spans - let currentDate = new Date(startDate) - while (currentDate <= endDate) { - let dateKey = Qt.formatDate(currentDate, - "yyyy-MM-dd") - if (!newEventsByDate[dateKey]) - newEventsByDate[dateKey] = [] - - // Check if this exact event is already added to this date (prevent duplicates) - let existingEvent = newEventsByDate[dateKey].find( - e => { - return e.id === eventId - }) - if (existingEvent) { - // Move to next day without adding duplicate - currentDate.setDate(currentDate.getDate() + 1) - continue - } - // Create a copy of the event for this date - let dayEvent = Object.assign({}, eventTemplate) - // For multi-day events, adjust the display time for this specific day - if (currentDate.getTime() === startDate.getTime()) { - // First day - use original start time - dayEvent.start = new Date(startTime) - } else { - // Subsequent days - start at beginning of day for all-day events - dayEvent.start = new Date(currentDate) - if (!dayEvent.allDay) - dayEvent.start.setHours(0, 0, 0, 0) - } - if (currentDate.getTime() === endDate.getTime()) { - // Last day - use original end time - dayEvent.end = new Date(endTime) - } else { - // Earlier days - end at end of day for all-day events - dayEvent.end = new Date(currentDate) - if (!dayEvent.allDay) - dayEvent.end.setHours(23, 59, 59, 999) - } - newEventsByDate[dateKey].push(dayEvent) - // Move to next day - currentDate.setDate(currentDate.getDate() + 1) - } - } - } - // Sort events by start time within each date - for (let dateKey in newEventsByDate) { - newEventsByDate[dateKey].sort((a, b) => { - return a.start.getTime( - ) - b.start.getTime() - }) - } - root.eventsByDate = newEventsByDate - root.lastError = "" - } catch (error) { - root.lastError = "Failed to parse events JSON: " + error.toString() - root.eventsByDate = {} - } - // Reset for next run - eventsProcess.rawOutput = "" - } - - stdout: SplitParser { - splitMarker: "\n" - onRead: data => { - eventsProcess.rawOutput += data + "\n" - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml deleted file mode 100644 index d3e5717..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml +++ /dev/null @@ -1,76 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io - -Singleton { - id: root - - property list values: Array(6) - property int refCount: 0 - property bool cavaAvailable: false - - Process { - id: cavaCheck - - command: ["which", "cava"] - running: false - onExited: exitCode => { - root.cavaAvailable = exitCode === 0 && Quickshell.env("DMS_DISABLE_CAVA") !== "1"; - } - } - - Component.onCompleted: { - cavaCheck.running = true; - } - - Process { - id: cavaProcess - - running: root.cavaAvailable && root.refCount > 0 - command: ["sh", "-c", `cat <<'CAVACONF' | cava -p /dev/stdin -[general] -framerate=25 -bars=6 -autosens=0 -sensitivity=30 -lower_cutoff_freq=50 -higher_cutoff_freq=12000 - -[output] -method=raw -raw_target=/dev/stdout -data_format=ascii -channels=mono -mono_option=average - -[smoothing] -noise_reduction=35 -integral=90 -gravity=95 -ignore=2 -monstercat=1.5 -CAVACONF`] - - onRunningChanged: { - if (!running) { - root.values = Array(6).fill(0); - } - } - - stdout: SplitParser { - splitMarker: "\n" - onRead: data => { - if (root.refCount > 0 && data.length > 0) { - const parts = data.split(";"); - if (parts.length >= 6) { - const points = [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10), parseInt(parts[3], 10), parseInt(parts[4], 10), parseInt(parts[5], 10)]; - root.values = points; - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml deleted file mode 100644 index 562a513..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml +++ /dev/null @@ -1,108 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property string currentVersion: "1.4" - readonly property bool changelogEnabled: false - - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell" - readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion - - property bool checkComplete: false - property bool changelogDismissed: false - - readonly property bool shouldShowChangelog: { - if (!checkComplete) - return false; - if (!changelogEnabled) - return false; - if (changelogDismissed) - return false; - if (typeof FirstLaunchService !== "undefined" && FirstLaunchService.isFirstLaunch) - return false; - return true; - } - - signal changelogRequested - signal changelogCompleted - - Component.onCompleted: { - if (!changelogEnabled) - return; - if (FirstLaunchService.checkComplete) - handleFirstLaunchResult(); - } - - function handleFirstLaunchResult() { - if (FirstLaunchService.isFirstLaunch) { - checkComplete = true; - changelogDismissed = true; - touchMarkerProcess.running = true; - } else { - changelogCheckProcess.running = true; - } - } - - Connections { - target: FirstLaunchService - - function onCheckCompleteChanged() { - if (FirstLaunchService.checkComplete && root.changelogEnabled && !root.checkComplete) - root.handleFirstLaunchResult(); - } - } - - function showChangelog() { - changelogRequested(); - } - - function dismissChangelog() { - changelogDismissed = true; - touchMarkerProcess.running = true; - changelogCompleted(); - } - - Process { - id: changelogCheckProcess - - command: ["sh", "-c", "[ -f '" + changelogMarkerPath + "' ] && echo 'seen' || echo 'show'"] - running: false - - stdout: SplitParser { - onRead: data => { - const result = data.trim(); - root.checkComplete = true; - - switch (result) { - case "seen": - root.changelogDismissed = true; - break; - case "show": - root.changelogRequested(); - break; - } - } - } - } - - Process { - id: touchMarkerProcess - - command: ["sh", "-c", "mkdir -p '" + configDir + "' && touch '" + changelogMarkerPath + "'"] - running: false - - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("ChangelogService: Failed to create changelog marker"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml deleted file mode 100644 index 4c09255..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml +++ /dev/null @@ -1,275 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property int longTextThreshold: 200 - - readonly property bool clipboardAvailable: DMSService.isConnected && (DMSService.capabilities.length === 0 || DMSService.capabilities.includes("clipboard")) - readonly property bool wtypeAvailable: SessionService.wtypeAvailable - - property var internalEntries: [] - property var clipboardEntries: [] - property var unpinnedEntries: [] - property var pinnedEntries: [] - property int pinnedCount: 0 - property int totalCount: 0 - property string searchText: "" - property int selectedIndex: 0 - property bool keyboardNavigationActive: false - property int refCount: 0 - - signal historyCopied - signal historyCleared - - Process { - id: wtypeProcess - command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"] - running: false - } - - Timer { - id: pasteTimer - interval: 200 - repeat: false - onTriggered: wtypeProcess.running = true - } - - function updateFilteredModel() { - const query = searchText.trim(); - let filtered = []; - - if (query.length === 0) { - filtered = internalEntries; - } else { - const lowerQuery = query.toLowerCase(); - filtered = internalEntries.filter(entry => entry.preview.toLowerCase().includes(lowerQuery)); - } - - filtered.sort((a, b) => { - if (a.pinned !== b.pinned) - return b.pinned ? 1 : -1; - return b.id - a.id; - }); - - clipboardEntries = filtered; - unpinnedEntries = filtered.filter(e => !e.pinned); - totalCount = clipboardEntries.length; - - if (unpinnedEntries.length === 0) { - keyboardNavigationActive = false; - selectedIndex = 0; - return; - } - if (selectedIndex >= unpinnedEntries.length) { - selectedIndex = unpinnedEntries.length - 1; - } - } - - function refresh() { - if (!clipboardAvailable) { - return; - } - DMSService.sendRequest("clipboard.getHistory", null, function (response) { - if (response.error) { - console.warn("ClipboardService: Failed to get history:", response.error); - return; - } - internalEntries = response.result || []; - pinnedEntries = internalEntries.filter(e => e.pinned); - pinnedCount = pinnedEntries.length; - updateFilteredModel(); - }); - } - - function reset() { - searchText = ""; - selectedIndex = 0; - keyboardNavigationActive = false; - internalEntries = []; - clipboardEntries = []; - unpinnedEntries = []; - } - - function copyEntry(entry, closeCallback) { - DMSService.sendRequest("clipboard.copyEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - ToastService.showError(I18n.tr("Failed to copy entry")); - return; - } - ToastService.showInfo(entry.isImage ? I18n.tr("Image copied to clipboard") : I18n.tr("Copied to clipboard")); - historyCopied(); - if (closeCallback) { - closeCallback(); - } - }); - } - - function pasteEntry(entry, closeCallback) { - if (!wtypeAvailable) { - ToastService.showError(I18n.tr("wtype not available - install wtype for paste support")); - return; - } - DMSService.sendRequest("clipboard.copyEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - ToastService.showError(I18n.tr("Failed to copy entry")); - return; - } - if (closeCallback) { - closeCallback(); - } - pasteTimer.start(); - }); - } - - function pasteSelected(closeCallback) { - if (!keyboardNavigationActive || clipboardEntries.length === 0 || selectedIndex < 0 || selectedIndex >= clipboardEntries.length) { - return; - } - pasteEntry(clipboardEntries[selectedIndex], closeCallback); - } - - function deleteEntry(entry) { - DMSService.sendRequest("clipboard.deleteEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - console.warn("ClipboardService: Failed to delete entry:", response.error); - return; - } - internalEntries = internalEntries.filter(e => e.id !== entry.id); - updateFilteredModel(); - if (clipboardEntries.length === 0) { - keyboardNavigationActive = false; - selectedIndex = 0; - return; - } - if (selectedIndex >= clipboardEntries.length) { - selectedIndex = clipboardEntries.length - 1; - } - }); - } - - function deletePinnedEntry(entry, confirmDialog) { - if (!confirmDialog) { - return; - } - confirmDialog.show(I18n.tr("Delete Saved Item?"), I18n.tr("This will permanently remove this saved clipboard item. This action cannot be undone."), function () { - DMSService.sendRequest("clipboard.deleteEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - console.warn("ClipboardService: Failed to delete entry:", response.error); - return; - } - internalEntries = internalEntries.filter(e => e.id !== entry.id); - updateFilteredModel(); - ToastService.showInfo(I18n.tr("Saved item deleted")); - }); - }, function () {}); - } - - function pinEntry(entry) { - DMSService.sendRequest("clipboard.getPinnedCount", null, function (countResponse) { - if (countResponse.error) { - ToastService.showError(I18n.tr("Failed to check pin limit")); - return; - } - - const maxPinned = 25; - if (countResponse.result.count >= maxPinned) { - ToastService.showError(I18n.tr("Maximum pinned entries reached") + " (" + maxPinned + ")"); - return; - } - - DMSService.sendRequest("clipboard.pinEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - ToastService.showError(I18n.tr("Failed to pin entry")); - return; - } - ToastService.showInfo(I18n.tr("Entry pinned")); - refresh(); - }); - }); - } - - function unpinEntry(entry) { - DMSService.sendRequest("clipboard.unpinEntry", { - "id": entry.id - }, function (response) { - if (response.error) { - ToastService.showError(I18n.tr("Failed to unpin entry")); - return; - } - ToastService.showInfo(I18n.tr("Entry unpinned")); - refresh(); - }); - } - - function clearAll() { - const hasPinned = pinnedCount > 0; - const savedCount = pinnedCount; - DMSService.sendRequest("clipboard.clearHistory", null, function (response) { - if (response.error) { - console.warn("ClipboardService: Failed to clear history:", response.error); - return; - } - refresh(); - historyCleared(); - if (hasPinned) { - ToastService.showInfo(I18n.tr("History cleared. %1 pinned entries kept.").arg(savedCount)); - } - }); - } - - function getEntryPreview(entry) { - return entry.preview || ""; - } - - function getEntryType(entry) { - if (entry.isImage) { - return "image"; - } - if (entry.size > longTextThreshold) { - return "long_text"; - } - return "text"; - } - - function hashedPinnedEntry(entryHash) { - if (!entryHash) { - return false; - } - return pinnedEntries.some(pinnedEntry => pinnedEntry.hash === entryHash); - } - - onClipboardAvailableChanged: { - if (!clipboardAvailable || refCount <= 0) - return; - refresh(); - } - - Connections { - target: DMSService - enabled: root.refCount > 0 - function onClipboardStateUpdate(data) { - const newHistory = data.history || []; - internalEntries = newHistory; - pinnedEntries = newHistory.filter(e => e.pinned); - pinnedCount = pinnedEntries.length; - updateFilteredModel(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml deleted file mode 100644 index d327ea2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml +++ /dev/null @@ -1,677 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.I3 -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common - -Singleton { - id: root - - property bool isHyprland: false - property bool isNiri: false - property bool isDwl: false - property bool isSway: false - property bool isScroll: false - property bool isMiracle: false - property bool isLabwc: false - property string compositor: "unknown" - readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1" - - readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE") - readonly property string niriSocket: Quickshell.env("NIRI_SOCKET") - readonly property string swaySocket: Quickshell.env("SWAYSOCK") - readonly property string scrollSocket: Quickshell.env("SWAYSOCK") - readonly property string miracleSocket: Quickshell.env("MIRACLESOCK") - readonly property string labwcPid: Quickshell.env("LABWC_PID") - property bool useNiriSorting: isNiri && NiriService - - property var randrScales: ({}) - property bool randrReady: false - signal randrDataReady - - property var sortedToplevels: [] - property bool _sortScheduled: false - - signal toplevelsChanged - - function fetchRandrData() { - Proc.runCommand("randr", ["dms", "randr", "--json"], (output, exitCode) => { - if (exitCode === 0 && output) { - try { - const data = JSON.parse(output.trim()); - if (data.outputs && Array.isArray(data.outputs)) { - const scales = {}; - for (const out of data.outputs) { - if (out.name && out.scale > 0) - scales[out.name] = out.scale; - } - randrScales = scales; - } - } catch (e) { - console.warn("CompositorService: failed to parse randr data:", e); - } - } - randrReady = true; - randrDataReady(); - }, 0, 3000); - } - - function getScreenScale(screen) { - if (!screen) - return 1; - - if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) { - return screen.devicePixelRatio || 1; - } - - const randrScale = randrScales[screen.name]; - if (randrScale !== undefined && randrScale > 0) - return Math.round(randrScale * 20) / 20; - - if (WlrOutputService.wlrOutputAvailable && screen) { - const wlrOutput = WlrOutputService.getOutput(screen.name); - if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) { - return Math.round(wlrOutput.scale * 20) / 20; - } - } - - if (isNiri && screen) { - const niriScale = NiriService.displayScales[screen.name]; - if (niriScale !== undefined) - return niriScale; - } - - if (isHyprland && screen) { - const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name); - if (hyprlandMonitor?.scale !== undefined) - return hyprlandMonitor.scale; - } - - if (isDwl && screen) { - const dwlScale = DwlService.getOutputScale(screen.name); - if (dwlScale !== undefined && dwlScale > 0) - return dwlScale; - } - - return screen?.devicePixelRatio || 1; - } - - function getFocusedScreen() { - let screenName = ""; - if (isHyprland && Hyprland.focusedWorkspace?.monitor) - screenName = Hyprland.focusedWorkspace.monitor.name; - else if (isNiri && NiriService.currentOutput) - screenName = NiriService.currentOutput; - else if (isSway || isScroll || isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - screenName = focusedWs?.monitor?.name || ""; - } else if (isDwl && DwlService.activeOutput) - screenName = DwlService.activeOutput; - - if (!screenName) - return Quickshell.screens.length > 0 ? Quickshell.screens[0] : null; - - for (let i = 0; i < Quickshell.screens.length; i++) { - if (Quickshell.screens[i].name === screenName) - return Quickshell.screens[i]; - } - return Quickshell.screens.length > 0 ? Quickshell.screens[0] : null; - } - - Timer { - id: sortDebounceTimer - interval: 100 - repeat: false - onTriggered: { - _sortScheduled = false; - sortedToplevels = computeSortedToplevels(); - toplevelsChanged(); - } - } - - function scheduleSort() { - if (_sortScheduled) - return; - _sortScheduled = true; - sortDebounceTimer.restart(); - } - - Connections { - target: ToplevelManager.toplevels - function onValuesChanged() { - root.scheduleSort(); - } - } - Connections { - target: isHyprland ? Hyprland : null - enabled: isHyprland - - function onRawEvent(event) { - if (event.name === "openwindow" || event.name === "closewindow" || event.name === "movewindow" || event.name === "movewindowv2" || event.name === "workspace" || event.name === "workspacev2" || event.name === "focusedmon" || event.name === "focusedmonv2" || event.name === "activewindow" || event.name === "activewindowv2" || event.name === "changefloatingmode" || event.name === "fullscreen" || event.name === "moveintogroup" || event.name === "moveoutofgroup") { - try { - Hyprland.refreshToplevels(); - } catch (e) {} - root.scheduleSort(); - } - } - } - Connections { - target: NiriService - function onWindowsChanged() { - root.scheduleSort(); - } - } - - Component.onCompleted: { - fetchRandrData(); - detectCompositor(); - scheduleSort(); - Qt.callLater(() => { - NiriService.generateNiriLayoutConfig(); - HyprlandService.generateLayoutConfig(); - DwlService.generateLayoutConfig(); - }); - } - - Connections { - target: DwlService - function onStateChanged() { - if (isDwl && !isHyprland && !isNiri) { - scheduleSort(); - } - } - } - - function computeSortedToplevels() { - if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) - return []; - - if (useNiriSorting) - return NiriService.sortToplevels(ToplevelManager.toplevels.values); - - if (isHyprland) - return sortHyprlandToplevelsSafe(); - - return Array.from(ToplevelManager.toplevels.values); - } - - function _get(o, path, fallback) { - try { - let v = o; - for (let i = 0; i < path.length; i++) { - if (v === null || v === undefined) - return fallback; - v = v[path[i]]; - } - return (v === undefined || v === null) ? fallback : v; - } catch (e) { - return fallback; - } - } - - function sortHyprlandToplevelsSafe() { - if (!Hyprland.toplevels || !Hyprland.toplevels.values) - return []; - - const items = Array.from(Hyprland.toplevels.values); - - function _get(o, path, fb) { - try { - let v = o; - for (let k of path) { - if (v == null) - return fb; - v = v[k]; - } - return (v == null) ? fb : v; - } catch (e) { - return fb; - } - } - - let snap = []; - for (let i = 0; i < items.length; i++) { - const t = items[i]; - if (!t) - continue; - const addr = t.address || ""; - if (!addr) - continue; - const li = t.lastIpcObject || null; - - const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], ""); - const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER); - const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER); - - const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER); - - const at = _get(li, ["at"], null); - let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9; - let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9; - - const relX = Number.isFinite(monX) ? (atX - monX) : atX; - const relY = Number.isFinite(monY) ? (atY - monY) : atY; - - snap.push({ - monKey: String(monName), - monOrderX: Number.isFinite(monX) ? monX : Number.MAX_SAFE_INTEGER, - monOrderY: Number.isFinite(monY) ? monY : Number.MAX_SAFE_INTEGER, - wsId: (typeof wsId === "number") ? wsId : Number.MAX_SAFE_INTEGER, - x: relX, - y: relY, - title: t.title || "", - address: addr, - wayland: t.wayland - }); - } - - const groups = new Map(); - for (const it of snap) { - const key = it.monKey + "::" + it.wsId; - if (!groups.has(key)) - groups.set(key, []); - groups.get(key).push(it); - } - - let groupList = []; - for (const [key, arr] of groups) { - const repr = arr[0]; - groupList.push({ - key, - monKey: repr.monKey, - monOrderX: repr.monOrderX, - monOrderY: repr.monOrderY, - wsId: repr.wsId, - items: arr - }); - } - - groupList.sort((a, b) => { - if (a.monOrderX !== b.monOrderX) - return a.monOrderX - b.monOrderX; - if (a.monOrderY !== b.monOrderY) - return a.monOrderY - b.monOrderY; - if (a.monKey !== b.monKey) - return a.monKey.localeCompare(b.monKey); - if (a.wsId !== b.wsId) - return a.wsId - b.wsId; - return 0; - }); - - const COLUMN_THRESHOLD = 48; - const JITTER_Y = 6; - - let ordered = []; - for (const g of groupList) { - const arr = g.items; - - const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b); - let colCenters = []; - if (xs.length > 0) { - for (const x of xs) { - if (colCenters.length === 0) { - colCenters.push(x); - } else { - const last = colCenters[colCenters.length - 1]; - if (x - last >= COLUMN_THRESHOLD) { - colCenters.push(x); - } - } - } - } else { - colCenters = [0]; - } - - for (const it of arr) { - let bestCol = 0; - let bestDist = Number.POSITIVE_INFINITY; - for (let ci = 0; ci < colCenters.length; ci++) { - const d = Math.abs(it.x - colCenters[ci]); - if (d < bestDist) { - bestDist = d; - bestCol = ci; - } - } - it._col = bestCol; - } - - arr.sort((a, b) => { - if (a._col !== b._col) - return a._col - b._col; - - const dy = a.y - b.y; - if (Math.abs(dy) > JITTER_Y) - return dy; - - if (a.title !== b.title) - return a.title.localeCompare(b.title); - if (a.address !== b.address) - return a.address.localeCompare(b.address); - return 0; - }); - - ordered.push.apply(ordered, arr); - } - - return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined); - } - - function filterCurrentWorkspace(toplevels, screen) { - if (useNiriSorting) - return NiriService.filterCurrentWorkspace(toplevels, screen); - if (isHyprland) - return filterHyprlandCurrentWorkspaceSafe(toplevels, screen); - return toplevels; - } - - function filterCurrentDisplay(toplevels, screenName) { - if (!toplevels || toplevels.length === 0 || !screenName) - return toplevels; - if (useNiriSorting) - return NiriService.filterCurrentDisplay(toplevels, screenName); - if (isHyprland) - return filterHyprlandCurrentDisplaySafe(toplevels, screenName); - return toplevels; - } - - function filterHyprlandCurrentDisplaySafe(toplevels, screenName) { - if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) - return toplevels; - - let monitorWindows = new Set(); - try { - const hy = Array.from(Hyprland.toplevels.values); - for (const t of hy) { - const mon = _get(t, ["monitor", "name"], ""); - if (mon === screenName && t.wayland) - monitorWindows.add(t.wayland); - } - } catch (e) {} - - return toplevels.filter(w => monitorWindows.has(w)); - } - - function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) { - if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) - return toplevels; - - let currentWorkspaceId = null; - try { - if (Hyprland.monitors) { - const monitor = Hyprland.monitors.values.find(m => m.name === screenName); - if (monitor) - currentWorkspaceId = _get(monitor, ["activeWorkspace", "id"], null); - } - - if (currentWorkspaceId === null) { - const hy = Array.from(Hyprland.toplevels.values); - for (const t of hy) { - const mon = _get(t, ["monitor", "name"], ""); - const wsId = _get(t, ["workspace", "id"], null); - const active = !!_get(t, ["activated"], false); - if (mon === screenName && wsId !== null) { - if (active) { - currentWorkspaceId = wsId; - break; - } - if (currentWorkspaceId === null) - currentWorkspaceId = wsId; - } - } - } - - if (currentWorkspaceId === null && Hyprland.workspaces) { - const wss = Array.from(Hyprland.workspaces.values); - const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null); - for (const ws of wss) { - const monName = _get(ws, ["monitor", "name"], ""); - const wsId = _get(ws, ["id"], null); - if (monName === screenName && wsId !== null) { - if (focusedId !== null && wsId === focusedId) { - currentWorkspaceId = wsId; - break; - } - if (currentWorkspaceId === null) - currentWorkspaceId = wsId; - } - } - } - } catch (e) { - console.warn("CompositorService: workspace snapshot failed:", e); - } - - if (currentWorkspaceId === null) - return toplevels; - - let map = new Map(); - try { - const hy = Array.from(Hyprland.toplevels.values); - for (const t of hy) { - const wsId = _get(t, ["workspace", "id"], null); - if (t && t.wayland && wsId !== null) - map.set(t.wayland, wsId); - } - } catch (e) {} - - return toplevels.filter(w => map.get(w) === currentWorkspaceId); - } - - Timer { - id: compositorInitTimer - interval: 100 - running: true - repeat: false - onTriggered: { - detectCompositor(); - Qt.callLater(() => { - NiriService.generateNiriLayoutConfig(); - HyprlandService.generateLayoutConfig(); - DwlService.generateLayoutConfig(); - }); - } - } - - function detectCompositor() { - if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !scrollSocket && !miracleSocket && !labwcPid) { - isHyprland = true; - isNiri = false; - isDwl = false; - isSway = false; - isScroll = false; - isMiracle = false; - isLabwc = false; - compositor = "hyprland"; - console.info("CompositorService: Detected Hyprland"); - return; - } - - if (niriSocket && niriSocket.length > 0) { - Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => { - if (exitCode === 0) { - isNiri = true; - isHyprland = false; - isDwl = false; - isSway = false; - isScroll = false; - isMiracle = false; - isLabwc = false; - compositor = "niri"; - console.info("CompositorService: Detected Niri with socket:", niriSocket); - NiriService.generateNiriBlurrule(); - } - }, 0); - return; - } - - if (swaySocket && swaySocket.length > 0 && !scrollSocket && scrollSocket.length == 0 && !miracleSocket) { - Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => { - if (exitCode === 0) { - isNiri = false; - isHyprland = false; - isDwl = false; - isSway = true; - isScroll = false; - isMiracle = false; - isLabwc = false; - compositor = "sway"; - console.info("CompositorService: Detected Sway with socket:", swaySocket); - } - }, 0); - return; - } - - if (miracleSocket && miracleSocket.length > 0) { - Proc.runCommand("miracleSocketCheck", ["test", "-S", miracleSocket], (output, exitCode) => { - if (exitCode === 0) { - isNiri = false; - isHyprland = false; - isDwl = false; - isSway = false; - isScroll = false; - isMiracle = true; - isLabwc = false; - compositor = "miracle"; - console.info("CompositorService: Detected Miracle WM with socket:", miracleSocket); - } - }, 0); - return; - } - - if (scrollSocket && scrollSocket.length > 0 && !miracleSocket) { - Proc.runCommand("scrollSocketCheck", ["test", "-S", scrollSocket], (output, exitCode) => { - if (exitCode === 0) { - isNiri = false; - isHyprland = false; - isDwl = false; - isSway = false; - isScroll = true; - isMiracle = false; - isLabwc = false; - compositor = "scroll"; - console.info("CompositorService: Detected Scroll with socket:", scrollSocket); - } - }, 0); - return; - } - - if (labwcPid && labwcPid.length > 0) { - isHyprland = false; - isNiri = false; - isDwl = false; - isSway = false; - isScroll = false; - isMiracle = false; - isLabwc = true; - compositor = "labwc"; - console.info("CompositorService: Detected LabWC with PID:", labwcPid); - return; - } - - if (DMSService.dmsAvailable) { - Qt.callLater(checkForDwl); - } else { - isHyprland = false; - isNiri = false; - isDwl = false; - isSway = false; - isScroll = false; - isMiracle = false; - isLabwc = false; - compositor = "unknown"; - console.warn("CompositorService: No compositor detected"); - } - } - - Connections { - target: DMSService - function onCapabilitiesReceived() { - if (!isHyprland && !isNiri && !isDwl && !isLabwc) { - checkForDwl(); - } - } - } - - function checkForDwl() { - if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) { - isHyprland = false; - isNiri = false; - isDwl = true; - isSway = false; - isScroll = false; - isMiracle = false; - isLabwc = false; - compositor = "dwl"; - console.info("CompositorService: Detected DWL via DMS capability"); - } - } - - function powerOffMonitors() { - if (isNiri) - return NiriService.powerOffMonitors(); - if (isHyprland) - return Hyprland.dispatch("dpms off"); - if (isDwl) - return _dwlPowerOffMonitors(); - if (isSway || isScroll || isMiracle) { - try { - I3.dispatch("output * dpms off"); - } catch (_) {} - return; - } - if (isLabwc) { - Quickshell.execDetached(["dms", "dpms", "off"]); - } - console.warn("CompositorService: Cannot power off monitors, unknown compositor"); - } - - function powerOnMonitors() { - if (isNiri) - return NiriService.powerOnMonitors(); - if (isHyprland) - return Hyprland.dispatch("dpms on"); - if (isDwl) - return _dwlPowerOnMonitors(); - if (isSway || isScroll || isMiracle) { - try { - I3.dispatch("output * dpms on"); - } catch (_) {} - return; - } - if (isLabwc) { - Quickshell.execDetached(["dms", "dpms", "on"]); - } - console.warn("CompositorService: Cannot power on monitors, unknown compositor"); - } - - function _dwlPowerOffMonitors() { - if (!Quickshell.screens || Quickshell.screens.length === 0) { - console.warn("CompositorService: No screens available for DWL power off"); - return; - } - - for (let i = 0; i < Quickshell.screens.length; i++) { - const screen = Quickshell.screens[i]; - if (screen && screen.name) { - Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + screen.name]); - } - } - } - - function _dwlPowerOnMonitors() { - if (!Quickshell.screens || Quickshell.screens.length === 0) { - console.warn("CompositorService: No screens available for DWL power on"); - return; - } - - for (let i = 0; i < Quickshell.screens.length; i++) { - const screen = Quickshell.screens[i]; - if (screen && screen.name) { - Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name]); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml deleted file mode 100644 index a88655d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml +++ /dev/null @@ -1,860 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - property int refCount: 0 - - onRefCountChanged: { - if (refCount > 0) { - ensureSubscription(); - } else if (refCount === 0 && DMSService.activeSubscriptions.includes("cups")) { - DMSService.removeSubscription("cups"); - } - } - - function ensureSubscription() { - if (refCount <= 0) - return; - if (!DMSService.isConnected) - return; - if (DMSService.activeSubscriptions.includes("cups")) - return; - if (DMSService.activeSubscriptions.includes("all")) - return; - DMSService.addSubscription("cups"); - if (cupsAvailable) { - getState(); - } - } - - property var printerNames: [] - property var printers: [] - property string selectedPrinter: "" - property string expandedPrinter: "" - - property bool cupsAvailable: false - property bool stateInitialized: false - - property var devices: [] - property var ppds: [] - property var printerClasses: [] - - readonly property var filteredDevices: { - if (!devices || devices.length === 0) - return []; - const bareProtocols = ["ipp", "ipps", "http", "https", "lpd", "socket", "beh", "dnssd", "mdns", "smb", "file", "cups-brf"]; - - // First pass: filter out invalid/bare protocol entries - const validDevices = devices.filter(d => { - if (!d.uri) - return false; - const uriLower = d.uri.toLowerCase(); - for (let proto of bareProtocols) { - if (uriLower === proto || uriLower === proto + ":") - return false; - } - if (d.class === "network" && d.info === "Backend Error Handler") - return false; - return true; - }); - - // Second pass: prefer IPP over LPD for the same printer - // _printer._tcp (LPD) doesn't work well with driverless printing - // _ipp._tcp or _ipps._tcp (IPP) should be preferred - const ippDeviceHosts = new Set(); - for (const d of validDevices) { - if (!d.uri) - continue; - // Extract hostname from dnssd URIs like dnssd://Name%20[mac]._ipp._tcp.local - const ippMatch = d.uri.match(/dnssd:\/\/[^/]*\._ipps?\._tcp/); - if (ippMatch) { - // Extract the unique identifier (usually MAC address in brackets) - const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i); - if (macMatch) - ippDeviceHosts.add(macMatch[1].toLowerCase()); - } - } - - // Filter out _printer._tcp devices when we have _ipp._tcp for the same printer - return validDevices.filter(d => { - if (!d.uri) - return true; - // If this is an LPD device, check if we have an IPP alternative - if (d.uri.includes("._printer._tcp")) { - const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i); - if (macMatch && ippDeviceHosts.has(macMatch[1].toLowerCase())) { - return false; // Skip LPD device, we have IPP - } - } - return true; - }); - } - - function decodeUri(str) { - if (!str) - return ""; - try { - return decodeURIComponent(str.replace(/\+/g, " ")); - } catch (e) { - return str; - } - } - - function getDeviceDisplayName(device) { - if (!device) - return ""; - let name = ""; - if (device.info && device.info.length > 0) { - name = decodeUri(device.info); - } else if (device.makeModel && device.makeModel.length > 0) { - name = decodeUri(device.makeModel); - } else { - return decodeUri(device.uri); - } - if (device.ip) - return name + " (" + device.ip + ")"; - return name; - } - - function getDeviceSubtitle(device) { - if (!device) - return ""; - const parts = []; - switch (device.class) { - case "direct": - parts.push(I18n.tr("Local")); - break; - case "network": - parts.push(I18n.tr("Network")); - break; - case "file": - parts.push(I18n.tr("File")); - break; - default: - if (device.class) - parts.push(device.class); - } - if (device.location) - parts.push(decodeUri(device.location)); - return parts.join(" • "); - } - - function suggestPrinterName(device) { - if (!device) - return ""; - let name = device.info || device.makeModel || ""; - name = name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); - return name.substring(0, 32) || "Printer"; - } - - function getMatchingPPDs(device) { - if (!device || !ppds || ppds.length === 0) - return []; - const isDnssd = device.uri && (device.uri.startsWith("dnssd://") || device.uri.startsWith("ipp://") || device.uri.startsWith("ipps://")); - if (isDnssd) { - const driverless = ppds.filter(p => p.name === "driverless" || p.name === "everywhere" || (p.makeModel && p.makeModel.toLowerCase().includes("driverless"))); - if (driverless.length > 0) - return driverless; - } - if (!device.makeModel) - return []; - const makeModelLower = device.makeModel.toLowerCase(); - const words = makeModelLower.split(/[\s_-]+/).filter(w => w.length > 2); - return ppds.filter(p => { - if (!p.makeModel) - return false; - const ppdLower = p.makeModel.toLowerCase(); - return words.some(w => ppdLower.includes(w)); - }).slice(0, 10); - } - - property bool loadingDevices: false - property bool loadingPPDs: false - property bool loadingClasses: false - property bool creatingPrinter: false - - signal cupsStateUpdate - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - Component.onCompleted: { - if (socketPath && socketPath.length > 0) { - checkDMSCapabilities(); - } - } - - Connections { - target: DMSService - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkDMSCapabilities(); - ensureSubscription(); - } - } - } - - Connections { - target: DMSService - enabled: DMSService.isConnected - - function onCupsStateUpdate(data) { - console.log("CupsService: Subscription update received"); - getState(); - } - - function onCapabilitiesChanged() { - checkDMSCapabilities(); - } - } - - function checkDMSCapabilities() { - if (!DMSService.isConnected) - return; - if (DMSService.capabilities.length === 0) - return; - cupsAvailable = DMSService.capabilities.includes("cups"); - - if (cupsAvailable && !stateInitialized) { - stateInitialized = true; - getState(); - } - } - - function getState() { - if (!cupsAvailable) - return; - DMSService.sendRequest("cups.getPrinters", null, response => { - if (response.result) { - updatePrinters(response.result); - fetchAllJobs(); - } - }); - } - - function updatePrinters(printersData) { - printerNames = printersData.map(p => p.name); - - let printersObj = {}; - for (var i = 0; i < printersData.length; i++) { - let printer = printersData[i]; - printersObj[printer.name] = { - "name": printer.name, - "uri": printer.uri || "", - "state": printer.state, - "stateReason": printer.stateReason, - "location": printer.location || "", - "info": printer.info || "", - "makeModel": printer.makeModel || "", - "accepting": printer.accepting !== false, - "jobs": [] - }; - } - printers = printersObj; - - if (printerNames.length > 0) { - if (selectedPrinter.length > 0) { - if (!printerNames.includes(selectedPrinter)) { - selectedPrinter = printerNames[0]; - } - } else { - selectedPrinter = printerNames[0]; - } - } - } - - function fetchAllJobs() { - for (var i = 0; i < printerNames.length; i++) { - fetchJobsForPrinter(printerNames[i]); - } - } - - function fetchJobsForPrinter(printerName) { - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.getJobs", params, response => { - if (response.result && printers[printerName]) { - let updatedPrinters = Object.assign({}, printers); - updatedPrinters[printerName].jobs = response.result; - printers = updatedPrinters; - } - }); - } - - function getSelectedPrinter() { - return selectedPrinter; - } - - function setSelectedPrinter(printerName) { - if (printerNames.length > 0) { - if (printerNames.includes(printerName)) { - selectedPrinter = printerName; - } else { - selectedPrinter = printerNames[0]; - } - } - } - - function getPrintersNum() { - if (!cupsAvailable) - return 0; - - return printerNames.length; - } - - function getPrintersNames() { - if (!cupsAvailable) - return []; - - return printerNames; - } - - function getTotalJobsNum() { - if (!cupsAvailable) - return 0; - - var result = 0; - for (var i = 0; i < printerNames.length; i++) { - var printerName = printerNames[i]; - if (printers[printerName] && printers[printerName].jobs) { - result += printers[printerName].jobs.length; - } - } - return result; - } - - function getCurrentPrinterState() { - if (!cupsAvailable || !selectedPrinter) - return ""; - - var printer = printers[selectedPrinter]; - return printer.state; - } - - function getCurrentPrinterStatePrettyShort() { - if (!cupsAvailable || !selectedPrinter) - return ""; - - var printer = printers[selectedPrinter]; - return getPrinterStateTranslation(printer.state) + " (" + getPrinterStateReasonTranslation(printer.stateReason) + ")"; - } - - function getCurrentPrinterStatePretty() { - if (!cupsAvailable || !selectedPrinter) - return ""; - - var printer = printers[selectedPrinter]; - return getPrinterStateTranslation(printer.state) + " (" + I18n.tr("Reason") + ": " + getPrinterStateReasonTranslation(printer.stateReason) + ")"; - } - - function getCurrentPrinterJobs() { - if (!cupsAvailable || !selectedPrinter) - return []; - - return getJobs(selectedPrinter); - } - - function getJobs(printerName) { - if (!cupsAvailable) - return ""; - - var printer = printers[printerName]; - return printer.jobs; - } - - function getJobsNum(printerName) { - if (!cupsAvailable) - return 0; - - var printer = printers[printerName]; - return printer.jobs.length; - } - - function pausePrinter(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.pausePrinter", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to pause printer"), response.error); - } else { - getState(); - } - }); - } - - function resumePrinter(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.resumePrinter", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to resume printer"), response.error); - } else { - getState(); - } - }); - } - - function cancelJob(printerName, jobID) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName, - "jobID": jobID - }; - - DMSService.sendRequest("cups.cancelJob", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to cancel selected job"), response.error); - } else { - fetchJobsForPrinter(printerName); - } - }); - } - - function purgeJobs(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.purgeJobs", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to cancel all jobs"), response.error); - } else { - fetchJobsForPrinter(printerName); - } - }); - } - - function getDevices() { - if (!cupsAvailable) - return; - loadingDevices = true; - DMSService.sendRequest("cups.getDevices", null, response => { - loadingDevices = false; - if (response.result) { - devices = response.result; - } - }); - } - - function getPPDs() { - if (!cupsAvailable) - return; - loadingPPDs = true; - DMSService.sendRequest("cups.getPPDs", null, response => { - loadingPPDs = false; - if (response.result) { - ppds = response.result; - } - }); - } - - function getClasses() { - if (!cupsAvailable) - return; - loadingClasses = true; - DMSService.sendRequest("cups.getClasses", null, response => { - loadingClasses = false; - if (response.result) { - printerClasses = response.result; - } - }); - } - - function testConnection(host, port, protocol, callback) { - if (!cupsAvailable) - return; - const params = { - "host": host, - "port": port, - "protocol": protocol - }; - - DMSService.sendRequest("cups.testConnection", params, response => { - if (callback) - callback(response); - }); - } - - function createPrinter(name, deviceURI, ppd, options) { - if (!cupsAvailable) - return; - creatingPrinter = true; - const params = { - "name": name, - "deviceURI": deviceURI, - "ppd": ppd - }; - if (options) { - if (options.shared !== undefined) - params.shared = options.shared; - if (options.location) - params.location = options.location; - if (options.information) - params.information = options.information; - if (options.errorPolicy) - params.errorPolicy = options.errorPolicy; - } - - DMSService.sendRequest("cups.createPrinter", params, response => { - creatingPrinter = false; - if (response.error) { - ToastService.showError(I18n.tr("Failed to create printer"), response.error); - } else { - ToastService.showInfo(I18n.tr("Printer created successfully")); - getState(); - } - }); - } - - function deletePrinter(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.deletePrinter", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to delete printer"), response.error); - } else { - ToastService.showInfo(I18n.tr("Printer deleted")); - if (selectedPrinter === printerName) { - selectedPrinter = ""; - } - getState(); - } - }); - } - - function acceptJobs(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.acceptJobs", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to enable job acceptance"), response.error); - } else { - getState(); - } - }); - } - - function rejectJobs(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.rejectJobs", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to disable job acceptance"), response.error); - } else { - getState(); - } - }); - } - - function setPrinterShared(printerName, shared) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName, - "shared": shared - }; - - DMSService.sendRequest("cups.setPrinterShared", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to update sharing"), response.error); - } else { - getState(); - } - }); - } - - function setPrinterLocation(printerName, location) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName, - "location": location - }; - - DMSService.sendRequest("cups.setPrinterLocation", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to update location"), response.error); - } else { - getState(); - } - }); - } - - function setPrinterInfo(printerName, info) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName, - "info": info - }; - - DMSService.sendRequest("cups.setPrinterInfo", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to update description"), response.error); - } else { - getState(); - } - }); - } - - function printTestPage(printerName) { - if (!cupsAvailable) - return; - const params = { - "printerName": printerName - }; - - DMSService.sendRequest("cups.printTestPage", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to print test page"), response.error); - } else { - ToastService.showInfo(I18n.tr("Test page sent to printer")); - fetchJobsForPrinter(printerName); - } - }); - } - - function moveJob(jobID, destPrinter) { - if (!cupsAvailable) - return; - const params = { - "jobID": jobID, - "destPrinter": destPrinter - }; - - DMSService.sendRequest("cups.moveJob", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to move job"), response.error); - } else { - fetchAllJobs(); - } - }); - } - - function restartJob(jobID) { - if (!cupsAvailable) - return; - const params = { - "jobID": jobID - }; - - DMSService.sendRequest("cups.restartJob", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to restart job"), response.error); - } else { - fetchAllJobs(); - } - }); - } - - function holdJob(jobID, holdUntil) { - if (!cupsAvailable) - return; - const params = { - "jobID": jobID - }; - if (holdUntil) { - params.holdUntil = holdUntil; - } - - DMSService.sendRequest("cups.holdJob", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to hold job"), response.error); - } else { - fetchAllJobs(); - } - }); - } - - function addPrinterToClass(className, printerName) { - if (!cupsAvailable) - return; - const params = { - "className": className, - "printerName": printerName - }; - - DMSService.sendRequest("cups.addPrinterToClass", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to add printer to class"), response.error); - } else { - getClasses(); - } - }); - } - - function removePrinterFromClass(className, printerName) { - if (!cupsAvailable) - return; - const params = { - "className": className, - "printerName": printerName - }; - - DMSService.sendRequest("cups.removePrinterFromClass", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to remove printer from class"), response.error); - } else { - getClasses(); - } - }); - } - - function deleteClass(className) { - if (!cupsAvailable) - return; - const params = { - "className": className - }; - - DMSService.sendRequest("cups.deleteClass", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to delete class"), response.error); - } else { - getClasses(); - } - }); - } - - function getPrinterData(printerName) { - if (!printers || !printers[printerName]) - return null; - return printers[printerName]; - } - - function getJobStateTranslation(state) { - switch (state) { - case "pending": - return I18n.tr("Pending"); - case "pending-held": - return I18n.tr("Held"); - case "processing": - return I18n.tr("Processing"); - case "processing-stopped": - return I18n.tr("Stopped"); - case "canceled": - return I18n.tr("Canceled"); - case "aborted": - return I18n.tr("Aborted"); - case "completed": - return I18n.tr("Completed"); - default: - return state; - } - } - - readonly property var states: ({ - "idle": I18n.tr("Idle"), - "processing": I18n.tr("Processing"), - "stopped": I18n.tr("Stopped") - }) - - readonly property var reasonsGeneral: ({ - "none": I18n.tr("None"), - "other": I18n.tr("Other") - }) - - readonly property var reasonsSupplies: ({ - "toner-low": I18n.tr("Toner Low"), - "toner-empty": I18n.tr("Toner Empty"), - "marker-supply-low": I18n.tr("Marker Supply Low"), - "marker-supply-empty": I18n.tr("Marker Supply Empty"), - "marker-waste-almost-full": I18n.tr("Marker Waste Almost Full"), - "marker-waste-full": I18n.tr("Marker Waste Full") - }) - - readonly property var reasonsMedia: ({ - "media-low": I18n.tr("Media Low"), - "media-empty": I18n.tr("Media Empty"), - "media-needed": I18n.tr("Media Needed"), - "media-jam": I18n.tr("Media Jam") - }) - - readonly property var reasonsParts: ({ - "cover-open": I18n.tr("Cover Open"), - "door-open": I18n.tr("Door Open"), - "interlock-open": I18n.tr("Interlock Open"), - "output-tray-missing": I18n.tr("Output Tray Missing"), - "output-area-almost-full": I18n.tr("Output Area Almost Full"), - "output-area-full": I18n.tr("Output Area Full") - }) - - readonly property var reasonsErrors: ({ - "paused": I18n.tr("Paused"), - "shutdown": I18n.tr("Shutdown"), - "connecting-to-device": I18n.tr("Connecting to Device"), - "timed-out": I18n.tr("Timed Out"), - "stopping": I18n.tr("Stopping"), - "stopped-partly": I18n.tr("Stopped Partly") - }) - - readonly property var reasonsService: ({ - "spool-area-full": I18n.tr("Spool Area Full"), - "cups-missing-filter-warning": I18n.tr("CUPS Missing Filter Warning"), - "cups-insecure-filter-warning": I18n.tr("CUPS Insecure Filter Warning") - }) - - readonly property var reasonsConnectivity: ({ - "offline-report": I18n.tr("Offline Report"), - "moving-to-paused": I18n.tr("Moving to Paused") - }) - - readonly property var severitySuffixes: ({ - "-error": I18n.tr("Error"), - "-warning": I18n.tr("Warning"), - "-report": I18n.tr("Report") - }) - - function getPrinterStateTranslation(state) { - return states[state] || state; - } - - function getPrinterStateReasonTranslation(reason) { - let allReasons = Object.assign({}, reasonsGeneral, reasonsSupplies, reasonsMedia, reasonsParts, reasonsErrors, reasonsService, reasonsConnectivity); - - let basReason = reason; - let suffix = ""; - - for (let s in severitySuffixes) { - if (reason.endsWith(s)) { - basReason = reason.slice(0, -s.length); - suffix = severitySuffixes[s]; - break; - } - } - - let translation = allReasons[basReason] || basReason; - return suffix ? translation + " (" + suffix + ")" : translation; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml deleted file mode 100644 index e234cf4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml +++ /dev/null @@ -1,944 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - property bool networkAvailable: false - property string backend: "" - - property string networkStatus: "disconnected" - property string primaryConnection: "" - - property string ethernetIP: "" - property string ethernetInterface: "" - property bool ethernetConnected: false - property string ethernetConnectionUuid: "" - property var ethernetDevices: [] - - property var wiredConnections: [] - - property string wifiIP: "" - property string wifiInterface: "" - property bool wifiConnected: false - property bool wifiEnabled: true - property string wifiConnectionUuid: "" - property string wifiDevicePath: "" - property string activeAccessPointPath: "" - property var wifiDevices: [] - property string wifiDeviceOverride: SessionData.wifiDeviceOverride || "" - property string connectingDevice: "" - - property string currentWifiSSID: "" - property int wifiSignalStrength: 0 - property var wifiNetworks: [] - property var savedConnections: [] - property var ssidToConnectionName: ({}) - property var wifiSignalIcon: { - if (!wifiConnected) { - return "wifi_off"; - } - if (wifiSignalStrength >= 50) { - return "wifi"; - } - if (wifiSignalStrength >= 25) { - return "wifi_2_bar"; - } - return "wifi_1_bar"; - } - - property string userPreference: "auto" - property bool isConnecting: false - property string connectingSSID: "" - property string connectionError: "" - - property bool isScanning: false - property bool autoScan: false - - property bool wifiAvailable: true - property bool wifiToggling: false - property bool changingPreference: false - property string targetPreference: "" - property var savedWifiNetworks: [] - property string connectionStatus: "" - property string lastConnectionError: "" - property bool passwordDialogShouldReopen: false - property bool autoRefreshEnabled: false - property string wifiPassword: "" - property string forgetSSID: "" - - property var vpnProfiles: [] - property var vpnActive: [] - property bool vpnAvailable: false - property bool vpnIsBusy: false - property string lastConnectedVpnUuid: "" - property string pendingVpnUuid: "" - property var vpnBusyStartTime: 0 - - property alias profiles: root.vpnProfiles - property alias activeConnections: root.vpnActive - property var activeUuids: vpnActive.map(v => v.uuid).filter(u => !!u) - property var activeNames: vpnActive.map(v => v.name).filter(n => !!n) - property string activeUuid: activeUuids.length > 0 ? activeUuids[0] : "" - property string activeName: activeNames.length > 0 ? activeNames[0] : "" - property string activeDevice: vpnActive.length > 0 ? (vpnActive[0].device || "") : "" - property string activeState: vpnActive.length > 0 ? (vpnActive[0].state || "") : "" - property bool vpnConnected: activeUuids.length > 0 - property alias available: root.vpnAvailable - property alias isBusy: root.vpnIsBusy - property alias connected: root.vpnConnected - - property string networkInfoSSID: "" - property string networkInfoDetails: "" - property bool networkInfoLoading: false - - property string networkWiredInfoUUID: "" - property string networkWiredInfoDetails: "" - property bool networkWiredInfoLoading: false - - property int refCount: 0 - property bool stateInitialized: false - - property string credentialsToken: "" - property string credentialsSSID: "" - property string credentialsSetting: "" - property var credentialsFields: [] - property var credentialsHints: [] - property string credentialsReason: "" - property bool credentialsRequested: false - - property string pendingConnectionSSID: "" - property var pendingConnectionStartTime: 0 - property bool wasConnecting: false - - signal networksUpdated - signal connectionChanged - signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo) - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - readonly property string effectiveWifiDevice: { - if (!wifiDeviceOverride) - return ""; - const deviceExists = wifiDevices.some(d => d.name === wifiDeviceOverride); - return deviceExists ? wifiDeviceOverride : ""; - } - - Component.onCompleted: { - root.userPreference = SettingsData.networkPreference; - lastConnectedVpnUuid = SessionData.vpnLastConnected || ""; - if (socketPath && socketPath.length > 0) { - checkDMSCapabilities(); - } - } - - Connections { - target: DMSService - - function onNetworkStateUpdate(data) { - const networksCount = data.wifiNetworks?.length ?? "null"; - console.log("DMSNetworkService: Subscription update received, networks:", networksCount); - updateState(data); - } - } - - Connections { - target: DMSService - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkDMSCapabilities(); - } - } - } - - Connections { - target: DMSService - enabled: DMSService.isConnected - - function onCapabilitiesChanged() { - checkDMSCapabilities(); - } - - function onCredentialsRequest(data) { - handleCredentialsRequest(data); - } - } - - function checkDMSCapabilities() { - if (!DMSService.isConnected) { - return; - } - - if (DMSService.capabilities.length === 0) { - return; - } - - networkAvailable = DMSService.capabilities.includes("network"); - - if (networkAvailable && !stateInitialized) { - stateInitialized = true; - getState(); - } - } - - function handleCredentialsRequest(data) { - credentialsToken = data.token || ""; - credentialsSSID = data.ssid || ""; - credentialsSetting = data.setting || "802-11-wireless-security"; - credentialsFields = data.fields || ["psk"]; - credentialsHints = data.hints || []; - credentialsReason = data.reason || "Credentials required"; - credentialsRequested = true; - - const connType = data.connType || ""; - const connName = data.name || data.connectionId || ""; - const vpnService = data.vpnService || ""; - const fInfo = data.fieldsInfo || []; - - credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason, connType, connName, vpnService, fInfo); - } - - function addRef() { - refCount++; - if (refCount === 1 && networkAvailable) { - startAutoScan(); - } - } - - function removeRef() { - refCount = Math.max(0, refCount - 1); - if (refCount === 0) { - stopAutoScan(); - } - } - - property bool initialStateFetched: false - - function getState() { - if (!networkAvailable) - return; - DMSService.sendRequest("network.getState", null, response => { - if (response.result) { - updateState(response.result); - if (!initialStateFetched && response.result.wifiEnabled && (!response.result.wifiNetworks || response.result.wifiNetworks.length === 0)) { - initialStateFetched = true; - Qt.callLater(() => scanWifi()); - } - } - }); - } - - function updateState(state) { - const previousConnecting = isConnecting; - const previousConnectingSSID = connectingSSID; - - backend = state.backend || ""; - vpnAvailable = networkAvailable && backend === "networkmanager"; - networkStatus = state.networkStatus || "disconnected"; - primaryConnection = state.primaryConnection || ""; - - ethernetIP = state.ethernetIP || ""; - ethernetInterface = state.ethernetDevice || ""; - ethernetConnected = state.ethernetConnected || false; - ethernetConnectionUuid = state.ethernetConnectionUuid || ""; - ethernetDevices = state.ethernetDevices || []; - - wiredConnections = state.wiredConnections || []; - - wifiIP = state.wifiIP || ""; - wifiInterface = state.wifiDevice || ""; - wifiConnected = state.wifiConnected || false; - wifiEnabled = state.wifiEnabled !== undefined ? state.wifiEnabled : true; - wifiConnectionUuid = state.wifiConnectionUuid || ""; - wifiDevicePath = state.wifiDevicePath || ""; - activeAccessPointPath = state.activeAccessPointPath || ""; - wifiDevices = state.wifiDevices || []; - connectingDevice = state.connectingDevice || ""; - - currentWifiSSID = state.wifiSSID || ""; - wifiSignalStrength = state.wifiSignal || 0; - - if (state.wifiNetworks) { - wifiNetworks = state.wifiNetworks; - - const saved = []; - const mapping = {}; - for (const network of state.wifiNetworks) { - if (network.saved) { - saved.push({ - ssid: network.ssid, - saved: true - }); - mapping[network.ssid] = network.ssid; - } - } - savedConnections = saved; - savedWifiNetworks = saved; - ssidToConnectionName = mapping; - - networksUpdated(); - } - - if (state.vpnProfiles) { - vpnProfiles = state.vpnProfiles; - } - - const previousVpnActive = vpnActive; - vpnActive = state.vpnActive || []; - - if (vpnConnected && activeUuid) { - lastConnectedVpnUuid = activeUuid; - SessionData.setVpnLastConnected(activeUuid); - } - - if (vpnIsBusy) { - const busyDuration = Date.now() - vpnBusyStartTime; - const timeout = 30000; - - if (busyDuration > timeout) { - console.warn("DMSNetworkService: VPN operation timed out after", timeout, "ms"); - vpnIsBusy = false; - pendingVpnUuid = ""; - vpnBusyStartTime = 0; - } else if (pendingVpnUuid) { - const isPendingVpnActive = activeUuids.includes(pendingVpnUuid); - if (isPendingVpnActive) { - vpnIsBusy = false; - pendingVpnUuid = ""; - vpnBusyStartTime = 0; - } - } else { - const previousCount = previousVpnActive ? previousVpnActive.length : 0; - const currentCount = vpnActive ? vpnActive.length : 0; - - if (previousCount !== currentCount) { - vpnIsBusy = false; - vpnBusyStartTime = 0; - } - } - } - - isConnecting = state.isConnecting || false; - connectingSSID = state.connectingSSID || ""; - connectionError = state.lastError || ""; - lastConnectionError = state.lastError || ""; - - if (pendingConnectionSSID) { - if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) { - const elapsed = Date.now() - pendingConnectionStartTime; - console.info("DMSNetworkService: Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms"); - ToastService.showInfo(`Connected to ${pendingConnectionSSID}`); - - if (userPreference === "wifi" || userPreference === "auto") { - setConnectionPriority("wifi"); - } - - pendingConnectionSSID = ""; - connectionStatus = "connected"; - } else if (previousConnecting && !isConnecting && !wifiConnected) { - const isCancellationError = connectionError === "user-canceled"; - const isBadCredentials = connectionError === "bad-credentials"; - - if (isCancellationError) { - connectionStatus = "cancelled"; - pendingConnectionSSID = ""; - } else if (isBadCredentials) { - connectionStatus = "invalid_password"; - pendingConnectionSSID = ""; - } else { - if (connectionError) { - ToastService.showError(I18n.tr("Failed to connect to %1").arg(pendingConnectionSSID)); - } - connectionStatus = "failed"; - pendingConnectionSSID = ""; - } - } - } - - wasConnecting = isConnecting; - - connectionChanged(); - } - - function connectToSpecificWiredConfig(uuid) { - if (!networkAvailable || isConnecting) - return; - isConnecting = true; - connectionError = ""; - connectionStatus = "connecting"; - - const params = { - uuid: uuid - }; - - DMSService.sendRequest("network.ethernet.connect.config", params, response => { - if (response.error) { - connectionError = response.error; - lastConnectionError = response.error; - connectionStatus = "failed"; - ToastService.showError(I18n.tr("Failed to activate configuration"), response.error); - } else { - connectionError = ""; - connectionStatus = "connected"; - ToastService.showInfo(I18n.tr("Configuration activated")); - } - - isConnecting = false; - }); - } - - function scanWifi() { - if (!networkAvailable || isScanning || !wifiEnabled) - return; - isScanning = true; - const params = effectiveWifiDevice ? { - device: effectiveWifiDevice - } : null; - DMSService.sendRequest("network.wifi.scan", params, response => { - isScanning = false; - if (response.error) { - console.warn("DMSNetworkService: WiFi scan failed:", response.error); - } else { - Qt.callLater(() => getState()); - } - }); - } - - function scanWifiNetworks() { - scanWifi(); - } - - function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false) { - if (!networkAvailable || isConnecting) - return; - pendingConnectionSSID = ssid; - pendingConnectionStartTime = Date.now(); - connectionError = ""; - connectionStatus = "connecting"; - credentialsRequested = false; - - const params = { - ssid: ssid - }; - if (effectiveWifiDevice) - params.device = effectiveWifiDevice; - if (hidden) - params.hidden = true; - - if (DMSService.apiVersion >= 7) { - if (password || username) { - params.password = password; - if (username) - params.username = username; - if (anonymousIdentity) - params.anonymousIdentity = anonymousIdentity; - if (domainSuffixMatch) - params.domainSuffixMatch = domainSuffixMatch; - params.interactive = false; - } else { - params.interactive = true; - } - } else { - if (password) - params.password = password; - if (username) - params.username = username; - if (anonymousIdentity) - params.anonymousIdentity = anonymousIdentity; - if (domainSuffixMatch) - params.domainSuffixMatch = domainSuffixMatch; - } - - DMSService.sendRequest("network.wifi.connect", params, response => { - if (response.error) { - if (connectionStatus === "cancelled") - return; - connectionError = response.error; - lastConnectionError = response.error; - pendingConnectionSSID = ""; - connectionStatus = "failed"; - ToastService.showError(I18n.tr("Failed to start connection to %1").arg(ssid)); - } - }); - } - - function disconnectWifi() { - if (!networkAvailable || !wifiInterface) - return; - const params = effectiveWifiDevice ? { - device: effectiveWifiDevice - } : null; - DMSService.sendRequest("network.wifi.disconnect", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to disconnect WiFi"), response.error); - } else { - ToastService.showInfo(I18n.tr("Disconnected from WiFi")); - currentWifiSSID = ""; - connectionStatus = ""; - } - }); - } - - function submitCredentials(token, secrets, save) { - console.log("submitCredentials: networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion); - - if (!networkAvailable || DMSService.apiVersion < 7) { - console.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion); - return; - } - - const params = { - token: token, - secrets: secrets, - save: save || false - }; - - credentialsRequested = false; - - DMSService.sendRequest("network.credentials.submit", params, response => { - if (response.error) { - console.warn("DMSNetworkService: Failed to submit credentials:", response.error); - } - }); - } - - function cancelCredentials(token) { - if (!networkAvailable || DMSService.apiVersion < 7) - return; - const params = { - token: token - }; - - credentialsRequested = false; - pendingConnectionSSID = ""; - connectionStatus = "cancelled"; - - DMSService.sendRequest("network.credentials.cancel", params, response => { - if (response.error) { - console.warn("DMSNetworkService: Failed to cancel credentials:", response.error); - } - }); - } - - function forgetWifiNetwork(ssid) { - if (!networkAvailable) - return; - forgetSSID = ssid; - DMSService.sendRequest("network.wifi.forget", { - ssid: ssid - }, response => { - if (response.error) { - console.warn("Failed to forget network:", response.error); - } else { - ToastService.showInfo(I18n.tr("Forgot network %1").arg(ssid)); - - savedConnections = savedConnections.filter(s => s.ssid !== ssid); - savedWifiNetworks = savedWifiNetworks.filter(s => s.ssid !== ssid); - - const updated = [...wifiNetworks]; - for (const network of updated) { - if (network.ssid === ssid) { - network.saved = false; - if (network.connected) { - network.connected = false; - currentWifiSSID = ""; - } - } - } - wifiNetworks = updated; - networksUpdated(); - } - forgetSSID = ""; - }); - } - - function toggleWifiRadio() { - if (!networkAvailable || wifiToggling) - return; - wifiToggling = true; - DMSService.sendRequest("network.wifi.toggle", null, response => { - wifiToggling = false; - - if (response.error) { - console.warn("Failed to toggle WiFi:", response.error); - } else if (response.result) { - wifiEnabled = response.result.enabled; - ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled")); - } - }); - } - - function enableWifiDevice() { - if (!networkAvailable) - return; - DMSService.sendRequest("network.wifi.enable", null, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to enable WiFi"), response.error); - } else { - ToastService.showInfo(I18n.tr("WiFi enabled")); - } - }); - } - - function setNetworkPreference(preference) { - if (!networkAvailable) - return; - userPreference = preference; - changingPreference = true; - targetPreference = preference; - SettingsData.set("networkPreference", preference); - - DMSService.sendRequest("network.preference.set", { - preference: preference - }, response => { - changingPreference = false; - targetPreference = ""; - - if (response.error) { - console.warn("Failed to set network preference:", response.error); - } - }); - } - - function setConnectionPriority(type) { - if (type === "wifi") { - setNetworkPreference("wifi"); - } else if (type === "ethernet") { - setNetworkPreference("ethernet"); - } - } - - function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false) { - connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch, hidden); - setNetworkPreference("wifi"); - } - - function toggleNetworkConnection(type) { - if (!networkAvailable) - return; - if (type === "ethernet") { - if (ethernetConnected) { - DMSService.sendRequest("network.ethernet.disconnect", null, null); - } else { - DMSService.sendRequest("network.ethernet.connect", null, null); - } - } - } - - function disconnectEthernetDevice(deviceName) { - if (!networkAvailable) - return; - DMSService.sendRequest("network.ethernet.disconnect", { - device: deviceName - }, null); - } - - function startAutoScan() { - autoScan = true; - autoRefreshEnabled = true; - if (networkAvailable && wifiEnabled) { - scanWifi(); - } - } - - function stopAutoScan() { - autoScan = false; - autoRefreshEnabled = false; - } - - function fetchWiredNetworkInfo(uuid) { - if (!networkAvailable) - return; - networkWiredInfoUUID = uuid; - networkWiredInfoLoading = true; - networkWiredInfoDetails = "Loading network information..."; - - DMSService.sendRequest("network.ethernet.info", { - uuid: uuid - }, response => { - networkWiredInfoLoading = false; - - if (response.error) { - networkWiredInfoDetails = "Failed to fetch network information"; - } else if (response.result) { - formatWiredNetworkInfo(response.result); - } - }); - } - - function formatWiredNetworkInfo(info) { - let details = ""; - - if (!info) { - details = "Network information not found or network not available."; - } else { - details += "Interface: " + info.iface + "\\n"; - details += "Driver: " + info.driver + "\\n"; - details += "MAC Addr: " + info.hwAddr + "\\n"; - details += "Speed: " + info.speed + " Mb/s\\n\\n"; - - details += "IPv4 information:\\n"; - - for (const ip4 of info.IPv4s.ips) { - details += " IPv4 address: " + ip4 + "\\n"; - } - details += " Gateway: " + info.IPv4s.gateway + "\\n"; - details += " DNS: " + info.IPv4s.dns + "\\n"; - - if (info.IPv6s.ips) { - details += "\\nIPv6 information:\\n"; - - for (const ip6 of info.IPv6s.ips) { - details += " IPv6 address: " + ip6 + "\\n"; - } - if (info.IPv6s.gateway.length > 0) { - details += " Gateway: " + info.IPv6s.gateway + "\\n"; - } - if (info.IPv6s.dns.length > 0) { - details += " DNS: " + info.IPv6s.dns + "\\n"; - } - } - } - - networkWiredInfoDetails = details; - } - - function fetchNetworkInfo(ssid) { - if (!networkAvailable) - return; - networkInfoSSID = ssid; - networkInfoLoading = true; - networkInfoDetails = "Loading network information..."; - - DMSService.sendRequest("network.info", { - ssid: ssid - }, response => { - networkInfoLoading = false; - - if (response.error) { - networkInfoDetails = "Failed to fetch network information"; - } else if (response.result) { - formatNetworkInfo(response.result); - } - }); - } - - function formatNetworkInfo(info) { - let details = ""; - - if (!info || !info.bands || info.bands.length === 0) { - details = "Network information not found or network not available."; - } else { - for (const band of info.bands) { - const freqGHz = band.frequency / 1000; - let bandName = "Unknown"; - if (band.frequency >= 2400 && band.frequency <= 2500) { - bandName = "2.4 GHz"; - } else if (band.frequency >= 5000 && band.frequency <= 6000) { - bandName = "5 GHz"; - } else if (band.frequency >= 6000) { - bandName = "6 GHz"; - } - - const statusPrefix = band.connected ? "● " : " "; - const statusSuffix = band.connected ? " (Connected)" : ""; - - details += statusPrefix + bandName + statusSuffix + " - " + band.signal + "%\\n"; - details += " Channel " + band.channel + " (" + freqGHz.toFixed(1) + " GHz) • " + band.rate + " Mbit/s\\n"; - details += " BSSID: " + band.bssid + "\\n"; - details += " Mode: " + band.mode + "\\n"; - details += " Security: " + (band.secured ? "Secured" : "Open") + "\\n"; - if (band.saved) { - details += " Status: Saved network\\n"; - } - details += "\\n"; - } - } - - networkInfoDetails = details; - } - - function getNetworkInfo(ssid) { - const network = wifiNetworks.find(n => n.ssid === ssid); - if (!network) { - return null; - } - - return { - "ssid": network.ssid, - "signal": network.signal, - "secured": network.secured, - "saved": network.saved, - "connected": network.connected, - "bssid": network.bssid - }; - } - - function getWiredNetworkInfo(uuid) { - const network = wiredConnections.find(n => n.uuid === uuid); - if (!network) { - return null; - } - - return { - "uuid": uuid - }; - } - - function refreshVpnProfiles() { - if (!vpnAvailable) - return; - DMSService.sendRequest("network.vpn.profiles", null, response => { - if (response.result) { - vpnProfiles = response.result; - } - }); - } - - function refreshVpnActive() { - if (!vpnAvailable) - return; - DMSService.sendRequest("network.vpn.active", null, response => { - if (response.result) { - vpnActive = response.result; - } - }); - } - - function connectVpn(uuidOrName, singleActive = false) { - if (!vpnAvailable || vpnIsBusy) - return; - vpnIsBusy = true; - pendingVpnUuid = uuidOrName; - vpnBusyStartTime = Date.now(); - - const params = { - uuidOrName: uuidOrName, - singleActive: singleActive - }; - - DMSService.sendRequest("network.vpn.connect", params, response => { - if (response.error) { - vpnIsBusy = false; - pendingVpnUuid = ""; - vpnBusyStartTime = 0; - ToastService.showError(I18n.tr("Failed to connect VPN"), response.error); - } - }); - } - - function connect(uuidOrName, singleActive = false) { - connectVpn(uuidOrName, singleActive); - } - - function disconnectVpn(uuidOrName) { - if (!vpnAvailable || vpnIsBusy) - return; - vpnIsBusy = true; - pendingVpnUuid = ""; - vpnBusyStartTime = Date.now(); - - const params = { - uuidOrName: uuidOrName - }; - - DMSService.sendRequest("network.vpn.disconnect", params, response => { - if (response.error) { - vpnIsBusy = false; - vpnBusyStartTime = 0; - ToastService.showError(I18n.tr("Failed to disconnect VPN"), response.error); - } - }); - } - - function disconnect(uuidOrName) { - disconnectVpn(uuidOrName); - } - - function disconnectAllVpns() { - if (!vpnAvailable || vpnIsBusy) - return; - vpnIsBusy = true; - pendingVpnUuid = ""; - - DMSService.sendRequest("network.vpn.disconnectAll", null, response => { - if (response.error) { - vpnIsBusy = false; - ToastService.showError(I18n.tr("Failed to disconnect VPNs"), response.error); - } - }); - } - - function disconnectAllActive() { - disconnectAllVpns(); - } - - function toggleVpn(uuid) { - if (uuid) { - if (isActiveVpnUuid(uuid)) { - disconnectVpn(uuid); - } else { - connectVpn(uuid); - } - return; - } - - if (vpnConnected) { - disconnectAllVpns(); - return; - } - - const targetUuid = lastConnectedVpnUuid || (vpnProfiles.length > 0 ? vpnProfiles[0].uuid : ""); - if (targetUuid) { - connectVpn(targetUuid); - } - } - - function toggle(uuid) { - toggleVpn(uuid); - } - - function isActiveVpnUuid(uuid) { - return activeUuids && activeUuids.indexOf(uuid) !== -1; - } - - function isActiveUuid(uuid) { - return isActiveVpnUuid(uuid); - } - - function refreshNetworkState() { - if (networkAvailable) { - getState(); - } - } - - function setWifiDeviceOverride(deviceName) { - SessionData.setWifiDeviceOverride(deviceName || ""); - if (networkAvailable && wifiEnabled) { - scanWifi(); - } - } - - function setWifiAutoconnect(ssid, autoconnect) { - if (!networkAvailable || DMSService.apiVersion <= 13) - return; - const params = { - ssid: ssid, - autoconnect: autoconnect - }; - - DMSService.sendRequest("network.wifi.setAutoconnect", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to update autoconnect"), response.error); - } else { - ToastService.showInfo(autoconnect ? I18n.tr("Autoconnect enabled") : I18n.tr("Autoconnect disabled")); - Qt.callLater(() => getState()); - } - }); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml deleted file mode 100644 index 217b96a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml +++ /dev/null @@ -1,757 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool dmsAvailable: false - property var capabilities: [] - property int apiVersion: 0 - property string cliVersion: "" - readonly property int expectedApiVersion: 1 - property var availablePlugins: [] - property var installedPlugins: [] - property var availableThemes: [] - property var installedThemes: [] - property bool isConnected: false - property bool isConnecting: false - property bool subscribeConnected: false - readonly property bool forceExtWorkspace: false - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - property var pendingRequests: ({}) - property var clipboardRequestIds: ({}) - property int requestIdCounter: 0 - property bool shownOutdatedError: false - property string updateCommand: "dms update" - property bool checkingUpdateCommand: false - - signal pluginsListReceived(var plugins) - signal installedPluginsReceived(var plugins) - signal searchResultsReceived(var plugins) - signal themesListReceived(var themes) - signal installedThemesReceived(var themes) - signal themeSearchResultsReceived(var themes) - signal operationSuccess(string message) - signal operationError(string error) - signal connectionStateChanged - - signal networkStateUpdate(var data) - signal cupsStateUpdate(var data) - signal loginctlStateUpdate(var data) - signal loginctlEvent(var event) - signal capabilitiesReceived - signal credentialsRequest(var data) - signal bluetoothPairingRequest(var data) - signal dwlStateUpdate(var data) - signal brightnessStateUpdate(var data) - signal brightnessDeviceUpdate(var device) - signal extWorkspaceStateUpdate(var data) - signal wlrOutputStateUpdate(var data) - signal evdevStateUpdate(var data) - signal gammaStateUpdate(var data) - signal themeAutoStateUpdate(var data) - signal openUrlRequested(string url) - signal appPickerRequested(var data) - signal screensaverStateUpdate(var data) - signal clipboardStateUpdate(var data) - signal locationStateUpdate(var data) - - property bool capsLockState: false - property bool screensaverInhibited: false - property var screensaverInhibitors: [] - - property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "freedesktop.screensaver", "gamma", "theme.auto", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput", "evdev", "browser", "dbus", "clipboard", "location"] - - Component.onCompleted: { - if (socketPath && socketPath.length > 0) { - detectUpdateCommand(); - } - } - - function detectUpdateCommand() { - checkingUpdateCommand = true; - checkAurHelper.running = true; - } - - function startSocketConnection() { - if (socketPath && socketPath.length > 0) { - testProcess.running = true; - } - } - - Process { - id: checkAurHelper - command: ["sh", "-c", "command -v paru || command -v yay"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const helper = text.trim(); - if (helper.includes("paru")) { - checkDmsPackage.helper = "paru"; - checkDmsPackage.running = true; - } else if (helper.includes("yay")) { - checkDmsPackage.helper = "yay"; - checkDmsPackage.running = true; - } else { - updateCommand = "dms update"; - checkingUpdateCommand = false; - startSocketConnection(); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - updateCommand = "dms update"; - checkingUpdateCommand = false; - startSocketConnection(); - } - } - } - - Process { - id: checkDmsPackage - property string helper: "" - command: ["sh", "-c", "pacman -Qi dms-shell-git 2>/dev/null || pacman -Qi dms-shell-bin 2>/dev/null"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("dms-shell-git")) { - updateCommand = checkDmsPackage.helper + " -S dms-shell-git"; - } else if (text.includes("dms-shell-bin")) { - updateCommand = checkDmsPackage.helper + " -S dms-shell-bin"; - } else { - updateCommand = "dms update"; - } - checkingUpdateCommand = false; - startSocketConnection(); - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - updateCommand = "dms update"; - checkingUpdateCommand = false; - startSocketConnection(); - } - } - } - - Process { - id: testProcess - command: ["test", "-S", root.socketPath] - - onExited: exitCode => { - if (exitCode === 0) { - root.dmsAvailable = true; - connectSocket(); - } else { - root.dmsAvailable = false; - } - } - } - - function connectSocket() { - if (!dmsAvailable || isConnected || isConnecting) { - return; - } - - isConnecting = true; - requestSocket.connected = true; - } - - DankSocket { - id: requestSocket - path: root.socketPath - connected: false - - onConnectionStateChanged: { - if (connected) { - root.isConnected = true; - root.isConnecting = false; - root.connectionStateChanged(); - subscribeSocket.connected = true; - } else { - root.isConnected = false; - root.isConnecting = false; - root.apiVersion = 0; - root.capabilities = []; - root.connectionStateChanged(); - } - } - - parser: SplitParser { - onRead: line => { - if (!line || line.length === 0) - return; - - let response; - try { - response = JSON.parse(line); - } catch (e) { - console.warn("DMSService: Failed to parse request response:", line.substring(0, 100)); - return; - } - const isClipboard = clipboardRequestIds[response.id]; - if (isClipboard) - delete clipboardRequestIds[response.id]; - else - console.log("DMSService: Request socket <<", line); - handleResponse(response); - } - } - } - - DankSocket { - id: subscribeSocket - path: root.socketPath - connected: false - - onConnectionStateChanged: { - root.subscribeConnected = connected; - if (connected) { - sendSubscribeRequest(); - } - } - - parser: SplitParser { - onRead: line => { - if (!line || line.length === 0) - return; - - let response; - try { - response = JSON.parse(line); - } catch (e) { - console.warn("DMSService: Failed to parse subscription event:", line.substring(0, 100)); - return; - } - if (!line.includes("clipboard")) - console.log("DMSService: Subscribe socket <<", line); - handleSubscriptionEvent(response); - } - } - } - - function sendSubscribeRequest() { - const request = { - "method": "subscribe" - }; - - if (activeSubscriptions.length > 0) { - request.params = { - "services": activeSubscriptions - }; - console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions)); - } else { - console.log("DMSService: Subscribing to all services"); - } - - subscribeSocket.send(request); - } - - function subscribe(services) { - if (!Array.isArray(services)) { - services = [services]; - } - - activeSubscriptions = services; - - if (subscribeConnected) { - subscribeSocket.connected = false; - Qt.callLater(() => { - subscribeSocket.connected = true; - }); - } - } - - function addSubscription(service) { - if (activeSubscriptions.includes("all")) - return; - if (!activeSubscriptions.includes(service)) { - const newSubs = [...activeSubscriptions, service]; - subscribe(newSubs); - } - } - - function removeSubscription(service) { - if (activeSubscriptions.includes("all")) { - const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace", "browser", "location"]; - const filtered = allServices.filter(s => s !== service); - subscribe(filtered); - } else { - const filtered = activeSubscriptions.filter(s => s !== service); - if (filtered.length === 0) { - console.warn("DMSService: Cannot remove last subscription"); - return; - } - subscribe(filtered); - } - } - - function subscribeAll() { - subscribe(["all"]); - } - - function subscribeAllExcept(excludeServices) { - if (!Array.isArray(excludeServices)) { - excludeServices = [excludeServices]; - } - - const allServices = ["network", "loginctl", "freedesktop", "gamma", "theme.auto", "bluetooth", "cups", "dwl", "brightness", "extworkspace", "browser", "dbus", "location"]; - const filtered = allServices.filter(s => !excludeServices.includes(s)); - subscribe(filtered); - } - - function handleSubscriptionEvent(response) { - if (response.error) { - if (response.error.includes("unknown method") && response.error.includes("subscribe")) { - if (!shownOutdatedError) { - console.error("DMSService: Server does not support subscribe method"); - ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand); - shownOutdatedError = true; - } - } - return; - } - - if (!response.result) { - return; - } - - const service = response.result.service; - const data = response.result.data; - - if (service === "server") { - apiVersion = data.apiVersion || 0; - cliVersion = data.cliVersion || ""; - capabilities = data.capabilities || []; - - console.info("DMSService: Connected (API v" + apiVersion + ", CLI " + cliVersion + ") -", JSON.stringify(capabilities)); - - if (apiVersion < expectedApiVersion) { - ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")"); - } - - capabilitiesReceived(); - } else if (service === "network") { - networkStateUpdate(data); - } else if (service === "network.credentials") { - credentialsRequest(data); - } else if (service === "loginctl") { - if (data.event) { - loginctlEvent(data); - } else { - loginctlStateUpdate(data); - } - } else if (service === "bluetooth.pairing") { - bluetoothPairingRequest(data); - } else if (service === "cups") { - cupsStateUpdate(data); - } else if (service === "dwl") { - dwlStateUpdate(data); - } else if (service === "brightness") { - brightnessStateUpdate(data); - } else if (service === "brightness.update") { - if (data.device) { - brightnessDeviceUpdate(data.device); - } - } else if (service === "extworkspace") { - extWorkspaceStateUpdate(data); - } else if (service === "wlroutput") { - wlrOutputStateUpdate(data); - } else if (service === "evdev") { - if (data.capsLock !== undefined) { - capsLockState = data.capsLock; - } - evdevStateUpdate(data); - } else if (service === "gamma") { - gammaStateUpdate(data); - } else if (service === "theme.auto") { - themeAutoStateUpdate(data); - } else if (service === "browser.open_requested") { - if (data.target) { - if (data.requestType === "url" || !data.requestType) { - openUrlRequested(data.target); - } else { - appPickerRequested(data); - } - } else if (data.url) { - openUrlRequested(data.url); - } - } else if (service === "freedesktop.screensaver") { - screensaverInhibited = data.inhibited || false; - screensaverInhibitors = data.inhibitors || []; - screensaverStateUpdate(data); - } else if (service === "dbus") { - dbusSignalReceived(data.subscriptionId || "", data); - } else if (service === "clipboard") { - clipboardStateUpdate(data); - } else if (service === "location") { - locationStateUpdate(data); - } - } - - function sendRequest(method, params, callback) { - if (!isConnected) { - console.warn("DMSService.sendRequest: Not connected, method:", method); - if (callback) { - callback({ - "error": "not connected to DMS socket" - }); - } - return; - } - - requestIdCounter++; - const id = Date.now() + requestIdCounter; - const request = { - "id": id, - "method": method - }; - - if (params) { - request.params = params; - } - - if (callback) - pendingRequests[id] = callback; - - if (method.startsWith("clipboard")) { - clipboardRequestIds[id] = true; - } else { - console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method); - } - requestSocket.send(request); - } - - function handleResponse(response) { - const callback = pendingRequests[response.id]; - - if (callback) { - delete pendingRequests[response.id]; - callback(response); - } - } - - function ping(callback) { - sendRequest("ping", null, callback); - } - - function listPlugins(callback) { - sendRequest("plugins.list", null, response => { - if (response.result) { - availablePlugins = response.result; - pluginsListReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function listInstalled(callback) { - sendRequest("plugins.listInstalled", null, response => { - if (response.result) { - installedPlugins = response.result; - installedPluginsReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function search(query, category, compositor, capability, callback) { - const params = { - "query": query - }; - if (category) { - params.category = category; - } - if (compositor) { - params.compositor = compositor; - } - if (capability) { - params.capability = capability; - } - - sendRequest("plugins.search", params, response => { - if (response.result) { - searchResultsReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function install(pluginName, callback) { - sendRequest("plugins.install", { - "name": pluginName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalled(); - } - }); - } - - function uninstall(pluginName, callback) { - sendRequest("plugins.uninstall", { - "name": pluginName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalled(); - } - }); - } - - function update(pluginName, callback) { - sendRequest("plugins.update", { - "name": pluginName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalled(); - } - }); - } - - function listThemes(callback) { - sendRequest("themes.list", null, response => { - if (response.result) { - availableThemes = response.result; - themesListReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function listInstalledThemes(callback) { - sendRequest("themes.listInstalled", null, response => { - if (response.result) { - installedThemes = response.result; - installedThemesReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function searchThemes(query, callback) { - sendRequest("themes.search", { - "query": query - }, response => { - if (response.result) { - themeSearchResultsReceived(response.result); - } - if (callback) { - callback(response); - } - }); - } - - function installTheme(themeName, callback) { - sendRequest("themes.install", { - "name": themeName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalledThemes(); - } - }); - } - - function uninstallTheme(themeName, callback) { - sendRequest("themes.uninstall", { - "name": themeName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalledThemes(); - } - }); - } - - function updateTheme(themeName, callback) { - sendRequest("themes.update", { - "name": themeName - }, response => { - if (callback) { - callback(response); - } - if (!response.error) { - listInstalledThemes(); - } - }); - } - - function lockSession(callback) { - sendRequest("loginctl.lock", null, callback); - } - - function unlockSession(callback) { - sendRequest("loginctl.unlock", null, callback); - } - - function bluetoothPair(devicePath, callback) { - sendRequest("bluetooth.pair", { - "device": devicePath - }, callback); - } - - function bluetoothConnect(devicePath, callback) { - sendRequest("bluetooth.connect", { - "device": devicePath - }, callback); - } - - function bluetoothDisconnect(devicePath, callback) { - sendRequest("bluetooth.disconnect", { - "device": devicePath - }, callback); - } - - function bluetoothRemove(devicePath, callback) { - sendRequest("bluetooth.remove", { - "device": devicePath - }, callback); - } - - function bluetoothTrust(devicePath, callback) { - sendRequest("bluetooth.trust", { - "device": devicePath - }, callback); - } - - function bluetoothSubmitPairing(token, secrets, accept, callback) { - sendRequest("bluetooth.pairing.submit", { - "token": token, - "secrets": secrets, - "accept": accept - }, callback); - } - - function bluetoothCancelPairing(token, callback) { - sendRequest("bluetooth.pairing.cancel", { - "token": token - }, callback); - } - - signal dbusSignalReceived(string subscriptionId, var data) - - property var dbusSubscriptions: ({}) - - function dbusCall(bus, dest, path, iface, method, args, callback) { - sendRequest("dbus.call", { - "bus": bus, - "dest": dest, - "path": path, - "interface": iface, - "method": method, - "args": args || [] - }, callback); - } - - function dbusGetProperty(bus, dest, path, iface, property, callback) { - sendRequest("dbus.getProperty", { - "bus": bus, - "dest": dest, - "path": path, - "interface": iface, - "property": property - }, callback); - } - - function dbusSetProperty(bus, dest, path, iface, property, value, callback) { - sendRequest("dbus.setProperty", { - "bus": bus, - "dest": dest, - "path": path, - "interface": iface, - "property": property, - "value": value - }, callback); - } - - function dbusGetAllProperties(bus, dest, path, iface, callback) { - sendRequest("dbus.getAllProperties", { - "bus": bus, - "dest": dest, - "path": path, - "interface": iface - }, callback); - } - - function dbusIntrospect(bus, dest, path, callback) { - sendRequest("dbus.introspect", { - "bus": bus, - "dest": dest, - "path": path || "/" - }, callback); - } - - function dbusListNames(bus, callback) { - sendRequest("dbus.listNames", { - "bus": bus - }, callback); - } - - function dbusSubscribe(bus, sender, path, iface, member, callback) { - sendRequest("dbus.subscribe", { - "bus": bus, - "sender": sender || "", - "path": path || "", - "interface": iface || "", - "member": member || "" - }, response => { - if (!response.error && response.result?.subscriptionId) { - dbusSubscriptions[response.result.subscriptionId] = true; - } - if (callback) - callback(response); - }); - } - - function dbusUnsubscribe(subscriptionId, callback) { - sendRequest("dbus.unsubscribe", { - "subscriptionId": subscriptionId - }, response => { - if (!response.error) { - delete dbusSubscriptions[subscriptionId]; - } - if (callback) - callback(response); - }); - } - - function renameWorkspace(name, callback) { - sendRequest("extworkspace.renameWorkspace", { - "name": name - }, callback); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml deleted file mode 100644 index 63efcb0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml +++ /dev/null @@ -1,184 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool dsearchAvailable: false - property int searchIdCounter: 0 - property int indexVersion: 0 - property bool supportsTypeFilter: false - property bool versionChecked: false - - signal searchResultsReceived(var results) - signal statsReceived(var stats) - signal errorOccurred(string error) - - Process { - id: checkProcess - command: ["sh", "-c", "command -v dsearch"] - running: true - - stdout: SplitParser { - onRead: line => { - if (line && line.trim().length > 0) { - root.dsearchAvailable = true; - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.dsearchAvailable = false; - } else { - root._checkVersion(); - } - } - } - - function _checkVersion() { - Proc.runCommand("dsearch-version", ["dsearch", "version", "--json"], (stdout, exitCode) => { - root.versionChecked = true; - if (exitCode !== 0) - return; - const response = JSON.parse(stdout); - root.indexVersion = response.index_schema || 0; - root.supportsTypeFilter = root.indexVersion >= 2; - }); - } - - function ping(callback) { - if (!dsearchAvailable) { - if (callback) { - callback({ - "error": "dsearch not available" - }); - } - return; - } - - Proc.runCommand("dsearch-ping", ["dsearch", "ping", "--json"], (stdout, exitCode) => { - if (callback) { - if (exitCode === 0) { - try { - const response = JSON.parse(stdout); - callback({ - "result": response - }); - } catch (e) { - callback({ - "error": "failed to parse ping response" - }); - } - } else { - callback({ - "error": "ping failed" - }); - } - } - }); - } - - function search(query, params, callback) { - if (!query || query.length === 0) { - if (callback) { - callback({ - "error": "query is required" - }); - } - return; - } - - if (!dsearchAvailable) { - if (callback) { - callback({ - "error": "dsearch not available" - }); - } - return; - } - - const args = ["dsearch", "search", query, "--json"]; - - if (params) { - if (params.limit !== undefined) { - args.push("-n", String(params.limit)); - } - if (params.type) { - args.push("-t", params.type); - } - if (params.ext) { - args.push("-e", params.ext); - } - if (params.folder) { - args.push("--folder", params.folder); - } - if (params.field) { - args.push("-f", params.field); - } - if (params.fuzzy) { - args.push("--fuzzy"); - } - if (params.sort) { - args.push("--sort", params.sort); - } - if (params.desc !== undefined) { - args.push("--desc=" + (params.desc ? "true" : "false")); - } - if (params.minSize !== undefined) { - args.push("--min-size", String(params.minSize)); - } - if (params.maxSize !== undefined) { - args.push("--max-size", String(params.maxSize)); - } - } - - const procId = "dsearch-search-" + (params?.type || "all"); - Proc.runCommand(procId, args, (stdout, exitCode) => { - if (exitCode === 0) { - try { - const response = JSON.parse(stdout); - searchResultsReceived(response); - if (callback) { - callback({ - "result": response - }); - } - } catch (e) { - const error = "failed to parse search response"; - errorOccurred(error); - if (callback) { - callback({ - "error": error - }); - } - } - } else if (exitCode === 124) { - const error = "search timed out"; - errorOccurred(error); - if (callback) { - callback({ - "error": error - }); - } - } else { - const error = "search failed"; - errorOccurred(error); - if (callback) { - callback({ - "error": error - }); - } - } - }, 100, 5000); - } - - function rediscover() { - checkProcess.running = true; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml deleted file mode 100644 index c9913e9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml +++ /dev/null @@ -1,94 +0,0 @@ -pragma Singleton - -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io - -Singleton { - id: root - - property var _cache: ({}) - - function resolveIconPath(moddedAppId) { - if (!moddedAppId) - return ""; - - if (_cache[moddedAppId] !== undefined) - return _cache[moddedAppId]; - - const result = (function() { - // 1. Try heuristic lookup (standard) - const entry = DesktopEntries.heuristicLookup(moddedAppId); - let icon = Quickshell.iconPath(entry?.icon, true); - if (icon && icon !== "") - return icon; - - // 2. Try the appId itself as an icon name - icon = Quickshell.iconPath(moddedAppId, true); - if (icon && icon !== "") - return icon; - - // 3. Try variations of the appId (lowercase, last part) - const appIds = [moddedAppId.toLowerCase()]; - const lastPart = moddedAppId.split('.').pop(); - if (lastPart && lastPart !== moddedAppId) { - appIds.push(lastPart); - appIds.push(lastPart.toLowerCase()); - } - - for (const id of appIds) { - icon = Quickshell.iconPath(id, true); - if (icon && icon !== "") - return icon; - } - - // 4. Deep search in all desktop entries (if the above fail) - // This is slow-ish but only happens once for failed icons - const strippedId = moddedAppId.replace(/-bin$/, "").toLowerCase(); - const allEntries = DesktopEntries.applications.values; - for (let i = 0; i < allEntries.length; i++) { - const e = allEntries[i]; - const eId = (e.id || "").toLowerCase(); - const eName = (e.name || "").toLowerCase(); - const eExec = (e.execString || "").toLowerCase(); - - if (eId.includes(strippedId) || eName.includes(strippedId) || eExec.includes(strippedId)) { - icon = Quickshell.iconPath(e.icon, true); - if (icon && icon !== "") - return icon; - } - } - - // 5. Nix/Guix specific store check (as a last resort) - for (const appId of appIds) { - let execPath = entry?.execString?.replace(/\/bin.*/, ""); - if (!execPath) - continue; - - if (execPath.startsWith("/nix/store/") || execPath.startsWith("/gnu/store/")) { - const basePath = execPath; - const sizes = ["256x256", "128x128", "64x64", "48x48", "32x32", "24x24", "16x16"]; - - let iconPath = `${basePath}/share/icons/hicolor/scalable/apps/${appId}.svg`; - icon = Quickshell.iconPath(iconPath, true); - if (icon && icon !== "") - return icon; - - for (const size of sizes) { - iconPath = `${basePath}/share/icons/hicolor/${size}/apps/${appId}.png`; - icon = Quickshell.iconPath(iconPath, true); - if (icon && icon !== "") - return icon; - } - } - } - - return ""; - })(); - - _cache[moddedAppId] = result; - return result; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml deleted file mode 100644 index 0e2ea6f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml +++ /dev/null @@ -1,232 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - property var registeredWidgets: ({}) - property var registeredWidgetsList: [] - - signal registryChanged - - Component.onCompleted: { - registerBuiltins(); - Qt.callLater(syncPluginWidgets); - } - - Connections { - target: PluginService - function onPluginLoaded(pluginId) { - const plugin = PluginService.availablePlugins[pluginId]; - if (plugin?.type === "desktop") - syncPluginWidgets(); - } - function onPluginUnloaded(pluginId) { - syncPluginWidgets(); - } - function onPluginListUpdated() { - syncPluginWidgets(); - } - } - - function registerBuiltins() { - registerWidget({ - id: "desktopClock", - name: I18n.tr("Desktop Clock", "Desktop clock widget name"), - icon: "schedule", - description: I18n.tr("Analog, digital, or stacked clock display", "Desktop clock widget description"), - type: "builtin", - component: "qs.Modules.BuiltinDesktopPlugins.DesktopClockWidget", - settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.ClockSettings", - defaultConfig: getDefaultClockConfig(), - defaultSize: { - width: 280, - height: 180 - } - }); - - registerWidget({ - id: "systemMonitor", - name: I18n.tr("System Monitor", "System monitor widget name"), - icon: "monitoring", - description: I18n.tr("CPU, memory, network, and disk monitoring", "System monitor widget description"), - type: "builtin", - component: "qs.Modules.BuiltinDesktopPlugins.SystemMonitorWidget", - settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.SystemMonitorSettings", - defaultConfig: getDefaultSystemMonitorConfig(), - defaultSize: { - width: 320, - height: 480 - } - }); - } - - function getDefaultClockConfig() { - return { - style: "analog", - transparency: 0.8, - colorMode: "primary", - customColor: "#ffffff", - showDate: true, - showAnalogNumbers: false, - showAnalogSeconds: true, - displayPreferences: ["all"] - }; - } - - function getDefaultSystemMonitorConfig() { - return { - showHeader: true, - transparency: 0.8, - colorMode: "primary", - customColor: "#ffffff", - showCpu: true, - showCpuGraph: true, - showCpuTemp: true, - showGpuTemp: false, - gpuPciId: "", - showMemory: true, - showMemoryGraph: true, - showNetwork: true, - showNetworkGraph: true, - showDisk: true, - showTopProcesses: false, - topProcessCount: 3, - topProcessSortBy: "cpu", - layoutMode: "auto", - graphInterval: 60, - displayPreferences: ["all"] - }; - } - - function registerWidget(widgetDef) { - if (!widgetDef?.id) - return; - - const newMap = Object.assign({}, registeredWidgets); - newMap[widgetDef.id] = widgetDef; - registeredWidgets = newMap; - _updateWidgetsList(); - registryChanged(); - } - - function unregisterWidget(widgetId) { - if (!registeredWidgets[widgetId]) - return; - - const newMap = Object.assign({}, registeredWidgets); - delete newMap[widgetId]; - registeredWidgets = newMap; - _updateWidgetsList(); - registryChanged(); - } - - function getWidget(widgetType) { - return registeredWidgets[widgetType] ?? null; - } - - function getDefaultConfig(widgetType) { - const widget = getWidget(widgetType); - if (!widget) - return {}; - - if (widget.type === "builtin") { - switch (widgetType) { - case "desktopClock": - return getDefaultClockConfig(); - case "systemMonitor": - return getDefaultSystemMonitorConfig(); - default: - return widget.defaultConfig ?? {}; - } - } - - return widget.defaultConfig ?? {}; - } - - function getDefaultSize(widgetType) { - const widget = getWidget(widgetType); - return widget?.defaultSize ?? { - width: 200, - height: 200 - }; - } - - function syncPluginWidgets() { - const desktopPlugins = PluginService.pluginDesktopComponents; - const availablePlugins = PluginService.availablePlugins; - const currentPluginIds = []; - - for (const pluginId in desktopPlugins) { - currentPluginIds.push(pluginId); - const plugin = availablePlugins[pluginId]; - if (!plugin) - continue; - - if (registeredWidgets[pluginId]?.type === "plugin") - continue; - - registerWidget({ - id: pluginId, - name: plugin.name || pluginId, - icon: plugin.icon || "extension", - description: plugin.description || "", - type: "plugin", - component: null, - settingsComponent: plugin.settingsPath || null, - defaultConfig: { - displayPreferences: ["all"] - }, - defaultSize: { - width: 200, - height: 200 - }, - pluginInfo: plugin - }); - } - - const toRemove = []; - for (const widgetId in registeredWidgets) { - const widget = registeredWidgets[widgetId]; - if (widget.type !== "plugin") - continue; - if (!currentPluginIds.includes(widgetId)) - toRemove.push(widgetId); - } - - for (const widgetId of toRemove) { - unregisterWidget(widgetId); - } - } - - function _updateWidgetsList() { - const result = []; - for (const key in registeredWidgets) { - result.push(registeredWidgets[key]); - } - result.sort((a, b) => { - if (a.type === "builtin" && b.type !== "builtin") - return -1; - if (a.type !== "builtin" && b.type === "builtin") - return 1; - return (a.name || "").localeCompare(b.name || ""); - }); - registeredWidgetsList = result; - } - - function getBuiltinWidgets() { - return registeredWidgetsList.filter(w => w.type === "builtin"); - } - - function getPluginWidgets() { - return registeredWidgetsList.filter(w => w.type === "plugin"); - } - - function getAllWidgets() { - return registeredWidgetsList; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml deleted file mode 100644 index e63c5c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml +++ /dev/null @@ -1,778 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property int refCount: 0 - property int updateInterval: refCount > 0 ? 3000 : 30000 - property bool isUpdating: false - property bool dgopAvailable: false - - property var moduleRefCounts: ({}) - property var enabledModules: [] - property var gpuPciIds: [] - property var gpuPciIdRefCounts: ({}) - property int processLimit: 20 - property string processSort: "cpu" - property bool noCpu: false - property int dgopProcessPid: 0 - - // Cursor data for accurate CPU calculations - property string cpuCursor: "" - property string procCursor: "" - property int cpuSampleCount: 0 - property int processSampleCount: 0 - - property real cpuUsage: 0 - property real cpuFrequency: 0 - property real cpuTemperature: 0 - property int cpuCores: 1 - property string cpuModel: "" - property var perCoreCpuUsage: [] - - property real memoryUsage: 0 - property real totalMemoryMB: 0 - property real usedMemoryMB: 0 - property real freeMemoryMB: 0 - property real availableMemoryMB: 0 - property int totalMemoryKB: 0 - property int usedMemoryKB: 0 - property int totalSwapKB: 0 - property int usedSwapKB: 0 - - property real networkRxRate: 0 - property real networkTxRate: 0 - property var lastNetworkStats: null - property var networkInterfaces: [] - - property real diskReadRate: 0 - property real diskWriteRate: 0 - property var lastDiskStats: null - property var diskMounts: [] - property var diskDevices: [] - - property var processes: [] - property var allProcesses: [] - property string currentSort: "cpu" - property bool sortAscending: false - property var availableGpus: [] - - property string kernelVersion: "" - property string distribution: "" - property string hostname: "" - property string architecture: "" - property string loadAverage: "" - property int processCount: 0 - property int threadCount: 0 - property string bootTime: "" - property string motherboard: "" - property string biosVersion: "" - property string uptime: "" - property string shortUptime: "" - - property int historySize: 60 - property var cpuHistory: [] - property var memoryHistory: [] - property var networkHistory: ({ - "rx": [], - "tx": [] - }) - property var diskHistory: ({ - "read": [], - "write": [] - }) - - function addRef(modules = null) { - refCount++; - let modulesChanged = false; - - if (modules) { - const modulesToAdd = Array.isArray(modules) ? modules : [modules]; - for (const module of modulesToAdd) { - const currentCount = moduleRefCounts[module] || 0; - moduleRefCounts[module] = currentCount + 1; - - // Add to enabled modules if not already there - if (enabledModules.indexOf(module) === -1) { - enabledModules.push(module); - modulesChanged = true; - } - } - } - - if (modulesChanged || refCount === 1) { - enabledModules = enabledModules.slice(); // Force property change - moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change - updateAllStats(); - } else if (gpuPciIds.length > 0 && refCount > 0) { - // If we have GPU PCI IDs and active modules, make sure to update - // This handles the case where PCI IDs were loaded after modules were added - updateAllStats(); - } - } - - function removeRef(modules = null) { - refCount = Math.max(0, refCount - 1); - let modulesChanged = false; - - if (modules) { - const modulesToRemove = Array.isArray(modules) ? modules : [modules]; - for (const module of modulesToRemove) { - const currentCount = moduleRefCounts[module] || 0; - if (currentCount > 1) { - moduleRefCounts[module] = currentCount - 1; - } else if (currentCount === 1) { - delete moduleRefCounts[module]; - const index = enabledModules.indexOf(module); - if (index > -1) { - enabledModules.splice(index, 1); - modulesChanged = true; - } - } - } - } - - if (modulesChanged) { - enabledModules = enabledModules.slice(); // Force property change - moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change - - // Clear cursor data when CPU or process modules are no longer active - if (!enabledModules.includes("cpu")) { - cpuCursor = ""; - cpuSampleCount = 0; - } - if (!enabledModules.includes("processes")) { - procCursor = ""; - processSampleCount = 0; - } - } - } - - function setGpuPciIds(pciIds) { - gpuPciIds = Array.isArray(pciIds) ? pciIds : []; - } - - function addGpuPciId(pciId) { - const currentCount = gpuPciIdRefCounts[pciId] || 0; - gpuPciIdRefCounts[pciId] = currentCount + 1; - - // Add to gpuPciIds array if not already there - if (!gpuPciIds.includes(pciId)) { - gpuPciIds = gpuPciIds.concat([pciId]); - } - - gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts); - } - - function removeGpuPciId(pciId) { - const currentCount = gpuPciIdRefCounts[pciId] || 0; - if (currentCount > 1) { - gpuPciIdRefCounts[pciId] = currentCount - 1; - } else if (currentCount === 1) { - // Remove completely when count reaches 0 - delete gpuPciIdRefCounts[pciId]; - const index = gpuPciIds.indexOf(pciId); - if (index > -1) { - gpuPciIds = gpuPciIds.slice(); - gpuPciIds.splice(index, 1); - } - - // Clear temperature data for this GPU when no longer monitored - if (availableGpus && availableGpus.length > 0) { - const updatedGpus = availableGpus.slice(); - for (var i = 0; i < updatedGpus.length; i++) { - if (updatedGpus[i].pciId === pciId) { - updatedGpus[i] = Object.assign({}, updatedGpus[i], { - "temperature": 0 - }); - } - } - availableGpus = updatedGpus; - } - } - - // Force property change notification - gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts); - } - - function setProcessOptions(limit = 20, sort = "cpu", disableCpu = false) { - processLimit = limit; - processSort = sort; - noCpu = disableCpu; - } - - function updateAllStats() { - if (dgopAvailable && refCount > 0 && enabledModules.length > 0) { - isUpdating = true; - dgopProcess.running = true; - } else { - isUpdating = false; - } - } - - function initializeGpuMetadata() { - if (!dgopAvailable) - return; - gpuInitProcess.running = true; - } - - function initializeSystemMetadata() { - if (!dgopAvailable) - return; - systemInitProcess.running = true; - } - - function buildDgopCommand() { - const cmd = ["dgop", "meta", "--json"]; - - if (enabledModules.length === 0) { - // Don't run if no modules are needed - return []; - } - - // Replace 'gpu' with 'gpu-temp' when we have PCI IDs to monitor - const finalModules = []; - for (const module of enabledModules) { - if (module === "gpu" && gpuPciIds.length > 0) { - finalModules.push("gpu-temp"); - } else if (module !== "gpu") { - finalModules.push(module); - } - } - - // Add gpu-temp module automatically when we have PCI IDs to monitor - if (gpuPciIds.length > 0 && finalModules.indexOf("gpu-temp") === -1) { - finalModules.push("gpu-temp"); - } - - if (enabledModules.indexOf("all") !== -1) { - cmd.push("--modules", "all"); - } else if (finalModules.length > 0) { - const moduleList = finalModules.join(","); - cmd.push("--modules", moduleList); - } else { - return []; - } - - // Add cursor data if available for accurate CPU percentages - if ((enabledModules.includes("cpu") || enabledModules.includes("all")) && cpuCursor) { - cmd.push("--cpu-cursor", cpuCursor); - } - if ((enabledModules.includes("processes") || enabledModules.includes("all")) && procCursor) { - cmd.push("--proc-cursor", procCursor); - } - - if (gpuPciIds.length > 0) { - cmd.push("--gpu-pci-ids", gpuPciIds.join(",")); - } - - if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) { - cmd.push("--limit", "100"); // Get more data for client sorting - cmd.push("--sort", "cpu"); // Always get CPU sorted data - if (noCpu) { - cmd.push("--no-cpu"); - } - } - - return cmd; - } - - function parseData(data) { - if (data.cpu) { - const cpu = data.cpu; - cpuSampleCount++; - - cpuUsage = Math.round((cpu.usage || 0) * 10) / 10; - cpuFrequency = Math.round(cpu.frequency || 0); - cpuTemperature = Math.round(cpu.temperature || 0); - cpuCores = cpu.count || 1; - cpuModel = cpu.model || ""; - perCoreCpuUsage = cpu.coreUsage || []; - addToHistory(cpuHistory, cpuUsage); - - if (cpu.cursor) { - cpuCursor = cpu.cursor; - } - } - - if (data.memory) { - const mem = data.memory; - const totalKB = mem.total || 0; - const availableKB = mem.available || 0; - const freeKB = mem.free || 0; - const usedKB = mem.used !== undefined ? mem.used : (totalKB - availableKB); - - totalMemoryMB = Math.round(totalKB / 1024); - availableMemoryMB = Math.round(availableKB / 1024); - freeMemoryMB = Math.round(freeKB / 1024); - usedMemoryMB = Math.round(usedKB / 1024); - const rawMemUsage = mem.usedPercent !== undefined ? mem.usedPercent : (totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0); - memoryUsage = Math.round(rawMemUsage * 10) / 10; - - totalMemoryKB = totalKB; - usedMemoryKB = usedKB; - totalSwapKB = mem.swaptotal || 0; - usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0); - - addToHistory(memoryHistory, memoryUsage); - } - - if (data.network && Array.isArray(data.network)) { - networkInterfaces = data.network; - - let totalRx = 0; - let totalTx = 0; - for (const iface of data.network) { - totalRx += iface.rx || 0; - totalTx += iface.tx || 0; - } - - if (lastNetworkStats) { - const timeDiff = updateInterval / 1000; - const rxDiff = totalRx - lastNetworkStats.rx; - const txDiff = totalTx - lastNetworkStats.tx; - networkRxRate = Math.max(0, rxDiff / timeDiff); - networkTxRate = Math.max(0, txDiff / timeDiff); - addToHistory(networkHistory.rx, networkRxRate / 1024); - addToHistory(networkHistory.tx, networkTxRate / 1024); - } - lastNetworkStats = { - "rx": totalRx, - "tx": totalTx - }; - } - - if (data.disk && Array.isArray(data.disk)) { - diskDevices = data.disk; - - let totalRead = 0; - let totalWrite = 0; - for (const disk of data.disk) { - totalRead += (disk.read || 0) * 512; - totalWrite += (disk.write || 0) * 512; - } - - if (lastDiskStats) { - const timeDiff = updateInterval / 1000; - const readDiff = totalRead - lastDiskStats.read; - const writeDiff = totalWrite - lastDiskStats.write; - diskReadRate = Math.max(0, readDiff / timeDiff); - diskWriteRate = Math.max(0, writeDiff / timeDiff); - addToHistory(diskHistory.read, diskReadRate / (1024 * 1024)); - addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024)); - } - lastDiskStats = { - "read": totalRead, - "write": totalWrite - }; - } - - if (data.diskmounts) { - diskMounts = data.diskmounts || []; - } - - if (data.processes && Array.isArray(data.processes)) { - const newProcesses = []; - processSampleCount++; - const ourPid = dgopProcessPid; - - for (const proc of data.processes) { - if (ourPid > 0 && proc.pid === ourPid) - continue; - - const cpuUsage = processSampleCount >= 2 ? (proc.cpu || 0) : 0; - - newProcesses.push({ - "pid": proc.pid || 0, - "ppid": proc.ppid || 0, - "cpu": cpuUsage, - "memoryPercent": proc.memoryPercent || proc.pssPercent || 0, - "memoryKB": proc.memoryKB || proc.pssKB || 0, - "command": proc.command || "", - "fullCommand": proc.fullCommand || "", - "username": proc.username || "", - "displayName": (proc.command && proc.command.length > 15) ? proc.command.substring(0, 15) + "..." : (proc.command || "") - }); - } - allProcesses = newProcesses; - applySorting(); - - if (data.cursor) { - procCursor = data.cursor; - } - } - - const gpuData = (data.gpu && data.gpu.gpus) || data.gpus; - if (gpuData && Array.isArray(gpuData)) { - // Check if this is temperature update data (has PCI IDs being monitored) - if (gpuPciIds.length > 0 && availableGpus && availableGpus.length > 0) { - // This is temperature data - merge with existing GPU metadata - const updatedGpus = availableGpus.slice(); - for (var i = 0; i < updatedGpus.length; i++) { - const existingGpu = updatedGpus[i]; - const tempGpu = gpuData.find(g => g.pciId === existingGpu.pciId); - // Only update temperature if this GPU's PCI ID is being monitored - if (tempGpu && gpuPciIds.includes(existingGpu.pciId)) { - updatedGpus[i] = Object.assign({}, existingGpu, { - "temperature": tempGpu.temperature || 0 - }); - } - } - availableGpus = updatedGpus; - } else { - // This is initial GPU metadata - set the full list - const gpuList = []; - for (const gpu of gpuData) { - let displayName = gpu.displayName || gpu.name || "Unknown GPU"; - let fullName = gpu.fullName || gpu.name || "Unknown GPU"; - - gpuList.push({ - "driver": gpu.driver || "", - "vendor": gpu.vendor || "", - "displayName": displayName, - "fullName": fullName, - "pciId": gpu.pciId || "", - "temperature": gpu.temperature || 0 - }); - } - availableGpus = gpuList; - } - } - - if (data.system) { - const sys = data.system; - loadAverage = sys.loadavg || ""; - processCount = sys.processes || 0; - threadCount = sys.threads || 0; - bootTime = sys.boottime || ""; - updateUptime(); - } - - const hwData = data.hardware || (data.hostname || data.kernel || data.distro || data.arch) ? data : null; - if (hwData) { - hostname = hwData.hostname || ""; - kernelVersion = hwData.kernel || ""; - distribution = hwData.distro || ""; - architecture = hwData.arch || ""; - motherboard = (hwData.bios && hwData.bios.motherboard) || ""; - biosVersion = (hwData.bios && hwData.bios.version) || ""; - } - - isUpdating = false; - } - - function addToHistory(array, value) { - array.push(value); - if (array.length > historySize) { - array.shift(); - } - } - - function getProcessIcon(command) { - const cmd = command.toLowerCase(); - if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser") || cmd.includes("chromium")) { - return "web"; - } - if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim")) { - return "code"; - } - if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh")) { - return "terminal"; - } - if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify")) { - return "music_note"; - } - if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv")) { - return "play_circle"; - } - if (cmd.includes("systemd") || cmd.includes("elogind") || cmd.includes("kernel") || cmd.includes("kthread") || cmd.includes("kworker")) { - return "settings"; - } - return "memory"; - } - - function formatCpuUsage(cpu) { - return (cpu || 0).toFixed(1) + "%"; - } - - function formatMemoryUsage(memoryKB) { - const mem = memoryKB || 0; - if (mem < 1024) { - return mem.toFixed(0) + " KB"; - } else if (mem < 1024 * 1024) { - return (mem / 1024).toFixed(1) + " MB"; - } else { - return (mem / (1024 * 1024)).toFixed(1) + " GB"; - } - } - - function formatSystemMemory(memoryKB) { - const mem = memoryKB || 0; - if (mem === 0) { - return "--"; - } - if (mem < 1024 * 1024) { - return (mem / 1024).toFixed(0) + " MB"; - } else { - return (mem / (1024 * 1024)).toFixed(1) + " GB"; - } - } - - function killProcess(pid) { - if (pid > 0) { - Quickshell.execDetached("kill", [pid.toString()]); - } - } - - function updateUptime() { - if (!bootTime) { - uptime = ""; - shortUptime = ""; - return; - } - - const bootDate = new Date(bootTime.replace(" ", "T")); - if (isNaN(bootDate.getTime())) { - uptime = ""; - shortUptime = ""; - return; - } - - const now = new Date(); - const seconds = Math.floor((now - bootDate) / 1000); - const days = Math.floor(seconds / 86400); - const hours = Math.floor((seconds % 86400) / 3600); - const minutes = Math.floor((seconds % 3600) / 60); - - const parts = []; - if (days > 0) - parts.push(`${days} day${days === 1 ? "" : "s"}`); - if (hours > 0) - parts.push(`${hours} hour${hours === 1 ? "" : "s"}`); - if (minutes > 0) - parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`); - - uptime = parts.length > 0 ? `up ${parts.join(", ")}` : `up ${seconds} seconds`; - - var shortStr = "up"; - if (days > 0) - shortStr += ` ${days}d`; - if (hours > 0) - shortStr += ` ${hours}h`; - if (minutes > 0) - shortStr += ` ${minutes}m`; - shortUptime = shortStr; - } - - function setSortBy(newSortBy) { - if (newSortBy !== currentSort) { - currentSort = newSortBy; - sortAscending = false; - applySorting(); - } - } - - function toggleSort(column) { - if (column === currentSort) { - sortAscending = !sortAscending; - } else { - currentSort = column; - sortAscending = false; - } - applySorting(); - } - - function applySorting() { - if (!allProcesses || allProcesses.length === 0) - return; - - const asc = sortAscending; - const sorted = allProcesses.slice(); - sorted.sort((a, b) => { - let valueA, valueB, result; - - switch (currentSort) { - case "cpu": - valueA = a.cpu || 0; - valueB = b.cpu || 0; - result = valueB - valueA; - break; - case "memory": - valueA = a.memoryKB || 0; - valueB = b.memoryKB || 0; - result = valueB - valueA; - break; - case "name": - valueA = (a.command || "").toLowerCase(); - valueB = (b.command || "").toLowerCase(); - result = valueA.localeCompare(valueB); - break; - case "pid": - valueA = a.pid || 0; - valueB = b.pid || 0; - result = valueA - valueB; - break; - default: - return 0; - } - return asc ? -result : result; - }); - - processes = sorted.slice(0, processLimit); - } - - Timer { - id: updateTimer - interval: root.updateInterval - running: root.dgopAvailable && root.refCount > 0 && root.enabledModules.length > 0 - repeat: true - triggeredOnStart: true - onTriggered: root.updateAllStats() - } - - Process { - id: dgopProcess - command: root.buildDgopCommand() - running: false - onStarted: dgopProcessPid = processId ?? 0 - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("Dgop process failed with exit code:", exitCode); - isUpdating = false; - } - } - stdout: StdioCollector { - onStreamFinished: { - if (text.trim()) { - try { - const data = JSON.parse(text.trim()); - parseData(data); - } catch (e) { - console.warn("Failed to parse dgop JSON:", e); - console.warn("Raw text was:", text.substring(0, 200)); - isUpdating = false; - } - } - } - } - } - - Process { - id: gpuInitProcess - command: ["dgop", "gpu", "--json"] - running: false - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("GPU init process failed with exit code:", exitCode); - } - } - stdout: StdioCollector { - onStreamFinished: { - if (text.trim()) { - try { - const data = JSON.parse(text.trim()); - parseData(data); - } catch (e) { - console.warn("Failed to parse GPU init JSON:", e); - } - } - } - } - } - - Process { - id: systemInitProcess - command: ["dgop", "hardware", "--json"] - running: false - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("System init process failed with exit code:", exitCode); - } - } - stdout: StdioCollector { - onStreamFinished: { - if (text.trim()) { - try { - const data = JSON.parse(text.trim()); - parseData(data); - } catch (e) { - console.warn("Failed to parse system init JSON:", e); - } - } - } - } - } - - Process { - id: dgopCheckProcess - command: ["which", "dgop"] - running: false - onExited: exitCode => { - dgopAvailable = (exitCode === 0); - if (dgopAvailable) { - initializeGpuMetadata(); - initializeSystemMetadata(); - if (SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.length > 0) { - for (const pciId of SessionData.enabledGpuPciIds) { - addGpuPciId(pciId); - } - if (refCount > 0 && enabledModules.length > 0) { - updateAllStats(); - } - } - } else { - console.warn("dgop is not installed or not in PATH"); - } - } - } - - Process { - id: osReleaseProcess - command: ["cat", "/etc/os-release"] - running: false - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("Failed to read /etc/os-release"); - } - } - stdout: StdioCollector { - onStreamFinished: { - if (text.trim()) { - try { - const lines = text.trim().split('\n'); - let prettyName = ""; - let name = ""; - - for (const line of lines) { - const trimmedLine = line.trim(); - if (trimmedLine.startsWith('PRETTY_NAME=')) { - prettyName = trimmedLine.substring(12).replace(/^["']|["']$/g, ''); - } else if (trimmedLine.startsWith('NAME=')) { - name = trimmedLine.substring(5).replace(/^["']|["']$/g, ''); - } - } - - // Prefer PRETTY_NAME, fallback to NAME - const distroName = prettyName || name || "Linux"; - distribution = distroName; - console.info("Detected distribution:", distroName); - } catch (e) { - console.warn("Failed to parse /etc/os-release:", e); - distribution = "Linux"; - } - } - } - } - } - - Component.onCompleted: { - dgopCheckProcess.running = true; - osReleaseProcess.running = true; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml deleted file mode 100644 index 553dd26..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml +++ /dev/null @@ -1,1170 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool brightnessAvailable: devices.length > 0 - property var devices: [] - property var deviceBrightness: ({}) - property var deviceBrightnessUserSet: ({}) - property var deviceMaxCache: ({}) - property var userControlledDevices: ({}) - property var pendingOsdDevices: ({}) - property int brightnessVersion: 0 - property string currentDevice: "" - property string lastIpcDevice: "" - property int brightnessLevel: { - brightnessVersion; - const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice); - if (!deviceToUse) { - return 50; - } - - return getDeviceBrightness(deviceToUse); - } - property int maxBrightness: 100 - property bool brightnessInitialized: false - property bool suppressOsd: true - - signal brightnessChanged(bool showOsd) - signal deviceSwitched - - property bool nightModeActive: nightModeEnabled - - property bool nightModeEnabled: false - property bool automationAvailable: false - property bool gammaControlAvailable: false - - property var gammaState: ({}) - property int gammaCurrentTemp: gammaState?.currentTemp ?? 0 - property string gammaNextTransition: gammaState?.nextTransition ?? "" - property string gammaSunriseTime: gammaState?.sunriseTime ?? "" - property string gammaSunsetTime: gammaState?.sunsetTime ?? "" - property string gammaDawnTime: gammaState?.dawnTime ?? "" - property string gammaNightTime: gammaState?.nightTime ?? "" - property bool gammaIsDay: gammaState?.isDay ?? true - property real gammaSunPosition: gammaState?.sunPosition ?? 0 - property int gammaLowTemp: gammaState?.config?.LowTemp ?? 0 - property int gammaHighTemp: gammaState?.config?.HighTemp ?? 0 - - function markDeviceUserControlled(deviceId) { - const newControlled = Object.assign({}, userControlledDevices); - newControlled[deviceId] = Date.now(); - userControlledDevices = newControlled; - } - - function isDeviceUserControlled(deviceId) { - const controlTime = userControlledDevices[deviceId]; - if (!controlTime) { - return false; - } - return (Date.now() - controlTime) < 1000; - } - - function clearDeviceUserControlled(deviceId) { - const newControlled = Object.assign({}, userControlledDevices); - delete newControlled[deviceId]; - userControlledDevices = newControlled; - } - - function markDevicePendingOsd(deviceId) { - const newPending = Object.assign({}, pendingOsdDevices); - newPending[deviceId] = true; - pendingOsdDevices = newPending; - } - - function clearDevicePendingOsd(deviceId) { - const newPending = Object.assign({}, pendingOsdDevices); - delete newPending[deviceId]; - pendingOsdDevices = newPending; - } - - function updateSingleDevice(device) { - if (device.class === "leds") { - return; - } - - const isUserControlled = isDeviceUserControlled(device.id); - if (isUserControlled) { - return; - } - - const deviceIndex = devices.findIndex(d => d.id === device.id); - if (deviceIndex !== -1) { - const newDevices = [...devices]; - const cachedMax = deviceMaxCache[device.id]; - - let displayMax = cachedMax || (device.class === "ddc" ? device.max : 100); - if (displayMax > 0 && !cachedMax) { - const newCache = Object.assign({}, deviceMaxCache); - newCache[device.id] = displayMax; - deviceMaxCache = newCache; - } - - newDevices[deviceIndex] = { - "id": device.id, - "name": device.id, - "class": device.class, - "current": device.current, - "percentage": device.currentPercent, - "max": device.max, - "backend": device.backend, - "displayMax": displayMax - }; - devices = newDevices; - } - - const isExponential = SessionData.getBrightnessExponential(device.id); - const userSetValue = deviceBrightnessUserSet[device.id]; - - let displayValue = device.currentPercent; - if (isExponential) { - if (userSetValue !== undefined) { - const exponent = SessionData.getBrightnessExponent(device.id); - const expectedHardware = Math.round(Math.pow(userSetValue / 100.0, exponent) * 100.0); - if (Math.abs(device.currentPercent - expectedHardware) > 2) { - const newUserSet = Object.assign({}, deviceBrightnessUserSet); - delete newUserSet[device.id]; - deviceBrightnessUserSet = newUserSet; - SessionData.clearBrightnessUserSetValue(device.id); - displayValue = linearToExponential(device.currentPercent, device.id); - } else { - displayValue = userSetValue; - } - } else { - displayValue = linearToExponential(device.currentPercent, device.id); - } - } - - const oldValue = deviceBrightness[device.id]; - const newBrightness = Object.assign({}, deviceBrightness); - newBrightness[device.id] = displayValue; - deviceBrightness = newBrightness; - brightnessVersion++; - - const isPendingOsd = pendingOsdDevices[device.id] === true; - if (isPendingOsd) { - clearDevicePendingOsd(device.id); - if (!suppressOsd) { - brightnessChanged(true); - } - return; - } - - if (!brightnessInitialized || oldValue === displayValue) { - return; - } - if (suppressOsd) { - return; - } - brightnessChanged(true); - } - - function updateFromBrightnessState(state) { - if (!state || !state.devices) { - return; - } - - const newMaxCache = Object.assign({}, deviceMaxCache); - devices = state.devices.map(d => { - const cachedMax = deviceMaxCache[d.id]; - let displayMax = cachedMax || (d.class === "ddc" ? d.max : 100); - if (displayMax > 0 && !cachedMax) { - newMaxCache[d.id] = displayMax; - } - return { - "id": d.id, - "name": d.id, - "class": d.class, - "current": d.current, - "percentage": d.currentPercent, - "max": d.max, - "backend": d.backend, - "displayMax": displayMax - }; - }); - deviceMaxCache = newMaxCache; - - const newBrightness = {}; - let anyDeviceBrightnessChanged = false; - - for (const device of state.devices) { - const isExponential = SessionData.getBrightnessExponential(device.id); - const userSetValue = deviceBrightnessUserSet[device.id]; - const oldValue = deviceBrightness[device.id]; - - if (isExponential) { - if (userSetValue !== undefined) { - newBrightness[device.id] = userSetValue; - } else { - newBrightness[device.id] = linearToExponential(device.currentPercent, device.id); - } - } else { - newBrightness[device.id] = device.currentPercent; - } - - const newValue = newBrightness[device.id]; - if (oldValue !== undefined && oldValue !== newValue) { - anyDeviceBrightnessChanged = true; - } - } - deviceBrightness = newBrightness; - brightnessVersion++; - - brightnessAvailable = devices.length > 0; - - if (devices.length > 0 && !currentDevice) { - const lastDevice = SessionData.lastBrightnessDevice || ""; - const deviceExists = devices.some(d => d.id === lastDevice); - if (deviceExists) { - setCurrentDevice(lastDevice, false); - } else { - const backlight = devices.find(d => d.class === "backlight"); - const nonKbdDevice = devices.find(d => !d.id.includes("kbd")); - const defaultDevice = backlight || nonKbdDevice || devices[0]; - setCurrentDevice(defaultDevice.id, false); - } - } - - const shouldShowOsd = brightnessInitialized && anyDeviceBrightnessChanged; - - if (!brightnessInitialized) { - brightnessInitialized = true; - } - - if (shouldShowOsd) { - brightnessChanged(true); - } - } - - function setBrightness(percentage, device, suppressOsd) { - const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice()); - if (!actualDevice) { - console.warn("DisplayService: No device selected for brightness change"); - return; - } - - if (actualDevice !== lastIpcDevice) { - lastIpcDevice = actualDevice; - } - - const deviceInfo = getCurrentDeviceInfoByName(actualDevice); - const isExponential = SessionData.getBrightnessExponential(actualDevice); - - let minValue = 0; - let maxValue = 100; - - switch (true) { - case isExponential: - minValue = 1; - maxValue = 100; - break; - default: - minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0; - maxValue = deviceInfo?.displayMax || 100; - break; - } - - if (maxValue <= 0) { - console.warn("DisplayService: Invalid max value for device", actualDevice, "- skipping brightness change"); - return; - } - - const clampedValue = Math.max(minValue, Math.min(maxValue, percentage)); - - if (!DMSService.isConnected) { - console.warn("DisplayService: Not connected to DMS"); - return; - } - - const isLedDevice = deviceInfo?.class === "leds"; - - if (suppressOsd) { - markDeviceUserControlled(actualDevice); - } else if (!isLedDevice) { - markDevicePendingOsd(actualDevice); - } - - const newBrightness = Object.assign({}, deviceBrightness); - newBrightness[actualDevice] = clampedValue; - deviceBrightness = newBrightness; - brightnessVersion++; - - if (isLedDevice && !suppressOsd) { - brightnessChanged(true); - } - - if (isExponential) { - const newUserSet = Object.assign({}, deviceBrightnessUserSet); - newUserSet[actualDevice] = clampedValue; - deviceBrightnessUserSet = newUserSet; - SessionData.setBrightnessUserSetValue(actualDevice, clampedValue); - } - - const params = { - "device": actualDevice, - "percent": clampedValue - }; - if (isExponential) { - params.exponential = true; - params.exponent = SessionData.getBrightnessExponent(actualDevice); - } - - DMSService.sendRequest("brightness.setBrightness", params, response => { - if (response.error) { - console.error("DisplayService: Failed to set brightness:", response.error); - ToastService.showError(I18n.tr("Failed to set brightness"), response.error, "", "brightness"); - } else { - ToastService.dismissCategory("brightness"); - } - }); - } - - function setCurrentDevice(deviceName, saveToSession = false) { - if (currentDevice === deviceName) { - return; - } - - currentDevice = deviceName; - lastIpcDevice = deviceName; - - if (saveToSession) { - SessionData.setLastBrightnessDevice(deviceName); - } - - deviceSwitched(); - } - - function getDeviceBrightness(deviceName) { - if (!deviceName) { - return 50; - } - - if (deviceName in deviceBrightness) { - return deviceBrightness[deviceName]; - } - - return 50; - } - - function linearToExponential(linearPercent, deviceName) { - const exponent = SessionData.getBrightnessExponent(deviceName); - const hardwarePercent = linearPercent / 100.0; - const normalizedPercent = Math.pow(hardwarePercent, 1.0 / exponent); - return Math.round(normalizedPercent * 100.0); - } - - function getDefaultDevice() { - for (const device of devices) { - if (device.class === "backlight") { - return device.id; - } - } - return devices.length > 0 ? devices[0].id : ""; - } - - function getPinnedDeviceForFocusedScreen() { - const focusedScreen = CompositorService.getFocusedScreen(); - if (!focusedScreen) - return ""; - - const pins = SettingsData.brightnessDevicePins || {}; - const screenKey = SettingsData.getScreenDisplayName(focusedScreen); - if (!screenKey) - return ""; - - const pinnedDevice = pins[screenKey]; - if (!pinnedDevice) - return ""; - - const deviceExists = devices.some(d => d.id === pinnedDevice); - if (!deviceExists) - return ""; - - return pinnedDevice; - } - - function getPreferredDevice() { - const pinned = getPinnedDeviceForFocusedScreen(); - if (pinned) - return pinned; - - return getDefaultDevice(); - } - - function getCurrentDeviceInfo() { - const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice); - if (!deviceToUse) { - return null; - } - - for (const device of devices) { - if (device.id === deviceToUse) { - return device; - } - } - return null; - } - - function isCurrentDeviceReady() { - const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice); - return deviceToUse !== ""; - } - - function getCurrentDeviceInfoByName(deviceName) { - if (!deviceName) { - return null; - } - - for (const device of devices) { - if (device.id === deviceName) { - return device; - } - } - return null; - } - - function getDeviceMax(deviceName) { - const deviceInfo = getCurrentDeviceInfoByName(deviceName); - if (!deviceInfo) { - return 100; - } - return deviceInfo.displayMax || 100; - } - - // Night Mode Functions - Simplified - function enableNightMode() { - if (!gammaControlAvailable) { - ToastService.showWarning("Night mode failed: DMS gamma control not available"); - return; - } - - nightModeEnabled = true; - SessionData.setNightModeEnabled(true); - - DMSService.sendRequest("wayland.gamma.setEnabled", { - "enabled": true - }, response => { - if (response.error) { - console.error("DisplayService: Failed to enable gamma control:", response.error); - ToastService.showError(I18n.tr("Failed to enable night mode"), response.error, "", "night-mode"); - nightModeEnabled = false; - SessionData.setNightModeEnabled(false); - return; - } - ToastService.dismissCategory("night-mode"); - - if (SessionData.nightModeAutoEnabled) { - startAutomation(); - } else { - applyNightModeDirectly(); - } - }); - } - - function disableNightMode() { - nightModeEnabled = false; - SessionData.setNightModeEnabled(false); - - if (!gammaControlAvailable) { - return; - } - - DMSService.sendRequest("wayland.gamma.setEnabled", { - "enabled": false - }, response => { - if (response.error) { - console.error("DisplayService: Failed to disable gamma control:", response.error); - ToastService.showError(I18n.tr("Failed to disable night mode"), response.error, "", "night-mode"); - } else { - ToastService.dismissCategory("night-mode"); - } - }); - } - - function toggleNightMode() { - if (nightModeEnabled) { - disableNightMode(); - } else { - enableNightMode(); - } - } - - function applyNightModeDirectly() { - const temperature = SessionData.nightModeTemperature || 4000; - - DMSService.sendRequest("wayland.gamma.setManualTimes", { - "sunrise": null, - "sunset": null - }, response => { - if (response.error) { - console.error("DisplayService: Failed to clear manual times:", response.error); - return; - } - - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": false - }, response => { - if (response.error) { - console.error("DisplayService: Failed to disable IP location:", response.error); - return; - } - - DMSService.sendRequest("wayland.gamma.setTemperature", { - "low": temperature, - "high": temperature - }, response => { - if (response.error) { - console.error("DisplayService: Failed to set temperature:", response.error); - ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); - } else { - ToastService.dismissCategory("night-mode"); - } - }); - }); - }); - } - - function startAutomation() { - if (!automationAvailable) { - return; - } - - const mode = SessionData.nightModeAutoMode || "time"; - - switch (mode) { - case "time": - startTimeBasedMode(); - break; - case "location": - startLocationBasedMode(); - break; - } - } - - function startTimeBasedMode() { - const temperature = SessionData.nightModeTemperature || 4000; - const highTemp = SessionData.nightModeHighTemperature || 6500; - const sunriseHour = SessionData.nightModeEndHour; - const sunriseMinute = SessionData.nightModeEndMinute; - const sunsetHour = SessionData.nightModeStartHour; - const sunsetMinute = SessionData.nightModeStartMinute; - - const sunrise = `${String(sunriseHour).padStart(2, '0')}:${String(sunriseMinute).padStart(2, '0')}`; - const sunset = `${String(sunsetHour).padStart(2, '0')}:${String(sunsetMinute).padStart(2, '0')}`; - - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": false - }, response => { - if (response.error) { - console.error("DisplayService: Failed to disable IP location:", response.error); - return; - } - - DMSService.sendRequest("wayland.gamma.setTemperature", { - "low": temperature, - "high": highTemp - }, response => { - if (response.error) { - console.error("DisplayService: Failed to set temperature:", response.error); - ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); - return; - } - - DMSService.sendRequest("wayland.gamma.setManualTimes", { - "sunrise": sunrise, - "sunset": sunset - }, response => { - if (response.error) { - console.error("DisplayService: Failed to set manual times:", response.error); - ToastService.showError(I18n.tr("Failed to set night mode schedule"), response.error, "", "night-mode"); - } else { - ToastService.dismissCategory("night-mode"); - } - }); - }); - }); - } - - function startLocationBasedMode() { - const temperature = SessionData.nightModeTemperature || 4000; - const highTemp = SessionData.nightModeHighTemperature || 6500; - - DMSService.sendRequest("wayland.gamma.setManualTimes", { - "sunrise": null, - "sunset": null - }, response => { - if (response.error) { - console.error("DisplayService: Failed to clear manual times:", response.error); - return; - } - - DMSService.sendRequest("wayland.gamma.setTemperature", { - "low": temperature, - "high": highTemp - }, response => { - if (response.error) { - console.error("DisplayService: Failed to set temperature:", response.error); - ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); - return; - } - - if (SessionData.nightModeUseIPLocation) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": true - }, response => { - if (response.error) { - console.error("DisplayService: Failed to enable IP location:", response.error); - ToastService.showError(I18n.tr("Failed to enable IP location"), response.error, "", "night-mode"); - } else { - ToastService.dismissCategory("night-mode"); - } - }); - } else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { - DMSService.sendRequest("wayland.gamma.setUseIPLocation", { - "use": false - }, response => { - if (response.error) { - console.error("DisplayService: Failed to disable IP location:", response.error); - return; - } - - DMSService.sendRequest("wayland.gamma.setLocation", { - "latitude": SessionData.latitude, - "longitude": SessionData.longitude - }, response => { - if (response.error) { - console.error("DisplayService: Failed to set location:", response.error); - ToastService.showError(I18n.tr("Failed to set night mode location"), response.error, "", "night-mode"); - } else { - ToastService.dismissCategory("night-mode"); - } - }); - }); - } else { - console.warn("DisplayService: Location mode selected but no coordinates set and IP location disabled"); - } - }); - }); - } - - function setNightModeAutomationMode(mode) { - SessionData.setNightModeAutoMode(mode); - } - - function evaluateNightMode() { - if (!nightModeEnabled) { - return; - } - - if (SessionData.nightModeAutoEnabled) { - restartTimer.nextAction = "automation"; - restartTimer.start(); - } else { - restartTimer.nextAction = "direct"; - restartTimer.start(); - } - } - - function checkGammaControlAvailability() { - if (!DMSService.isConnected) { - return; - } - - if (DMSService.apiVersion < 6) { - gammaControlAvailable = false; - automationAvailable = false; - return; - } - - if (!DMSService.capabilities.includes("gamma")) { - gammaControlAvailable = false; - automationAvailable = false; - return; - } - - DMSService.sendRequest("wayland.gamma.getState", null, response => { - if (response.error) { - gammaControlAvailable = false; - automationAvailable = false; - console.error("DisplayService: Gamma control not available:", response.error); - } else { - gammaControlAvailable = true; - automationAvailable = true; - - if (nightModeEnabled) { - DMSService.sendRequest("wayland.gamma.setEnabled", { - "enabled": true - }, enableResponse => { - if (enableResponse.error) { - console.error("DisplayService: Failed to enable gamma control on startup:", enableResponse.error); - return; - } - - evaluateNightMode(); - }); - } - } - }); - } - - Timer { - id: restartTimer - property string nextAction: "" - interval: 250 - repeat: false - - onTriggered: { - if (nextAction === "automation") { - startAutomation(); - } else if (nextAction === "direct") { - applyNightModeDirectly(); - } - nextAction = ""; - } - } - - function rescanDevices() { - if (!DMSService.isConnected) { - return; - } - - DMSService.sendRequest("brightness.rescan", null, response => { - if (response.error) { - console.error("DisplayService: Failed to rescan brightness devices:", response.error); - } - }); - } - - function updateDeviceBrightnessDisplay(deviceName) { - brightnessVersion++; - brightnessChanged(); - } - - Timer { - id: osdSuppressTimer - interval: 2000 - running: true - onTriggered: suppressOsd = false - } - - Component.onCompleted: { - nightModeEnabled = SessionData.nightModeEnabled; - deviceBrightnessUserSet = Object.assign({}, SessionData.brightnessUserSetValues); - if (DMSService.isConnected) { - checkGammaControlAvailability(); - } - } - - Timer { - id: screenChangeRescanTimer - property int rescanAttempt: 0 - interval: 3000 - repeat: false - onTriggered: { - rescanDevices(); - rescanAttempt++; - if (rescanAttempt < 3) { - interval = rescanAttempt === 1 ? 5000 : 8000; - restart(); - } else { - rescanAttempt = 0; - interval = 3000; - } - } - } - - Connections { - target: Quickshell - - function onScreensChanged() { - screenChangeRescanTimer.rescanAttempt = 0; - screenChangeRescanTimer.interval = 3000; - screenChangeRescanTimer.restart(); - } - } - - Connections { - target: DMSService - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkGammaControlAvailability(); - } else { - brightnessAvailable = false; - gammaControlAvailable = false; - automationAvailable = false; - } - } - - function onCapabilitiesReceived() { - checkGammaControlAvailability(); - } - - function onBrightnessStateUpdate(data) { - updateFromBrightnessState(data); - } - - function onBrightnessDeviceUpdate(device) { - updateSingleDevice(device); - } - - function onLoginctlEvent(event) { - if (event.event === "unlock" || event.event === "resume") { - suppressOsd = true; - osdSuppressTimer.restart(); - evaluateNightMode(); - } - } - - function onGammaStateUpdate(data) { - root.gammaState = data; - } - } - - // Session Data Connections - Connections { - target: SessionData - - function onNightModeEnabledChanged() { - nightModeEnabled = SessionData.nightModeEnabled; - evaluateNightMode(); - } - - function onNightModeAutoEnabledChanged() { - evaluateNightMode(); - } - function onNightModeAutoModeChanged() { - evaluateNightMode(); - } - function onNightModeStartHourChanged() { - evaluateNightMode(); - } - function onNightModeStartMinuteChanged() { - evaluateNightMode(); - } - function onNightModeEndHourChanged() { - evaluateNightMode(); - } - function onNightModeEndMinuteChanged() { - evaluateNightMode(); - } - function onNightModeTemperatureChanged() { - evaluateNightMode(); - } - function onNightModeHighTemperatureChanged() { - evaluateNightMode(); - } - function onLatitudeChanged() { - evaluateNightMode(); - } - function onLongitudeChanged() { - evaluateNightMode(); - } - function onNightModeUseIPLocationChanged() { - evaluateNightMode(); - } - } - - // IPC Handler for external control - IpcHandler { - function set(percentage: string, device: string): string { - if (!root.brightnessAvailable) - return "Brightness control not available"; - - const value = parseInt(percentage); - if (isNaN(value)) - return "Invalid brightness value: " + percentage; - - const actualDevice = device || root.getPreferredDevice(); - - if (actualDevice && !root.devices.some(d => d.id === actualDevice)) - return "Device not found: " + actualDevice; - - const deviceInfo = actualDevice ? root.getCurrentDeviceInfoByName(actualDevice) : null; - const minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0; - const clampedValue = Math.max(minValue, Math.min(100, value)); - - root.lastIpcDevice = actualDevice; - if (actualDevice && actualDevice !== root.currentDevice) - root.setCurrentDevice(actualDevice, false); - - root.setBrightness(clampedValue, actualDevice); - - return actualDevice ? "Brightness set to " + clampedValue + "% on " + actualDevice : "Brightness set to " + clampedValue + "%"; - } - - function increment(step: string, device: string): string { - if (!root.brightnessAvailable) - return "Brightness control not available"; - - const actualDevice = device || root.getPreferredDevice(); - - if (actualDevice && !root.devices.some(d => d.id === actualDevice)) - return "Device not found: " + actualDevice; - - const stepValue = parseInt(step || "5"); - - root.lastIpcDevice = actualDevice; - if (actualDevice && actualDevice !== root.currentDevice) - root.setCurrentDevice(actualDevice, false); - - const isExponential = SessionData.getBrightnessExponential(actualDevice); - const currentBrightness = root.getDeviceBrightness(actualDevice); - const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice); - - const maxValue = isExponential ? 100 : (deviceInfo?.displayMax || 100); - const newBrightness = Math.min(maxValue, currentBrightness + stepValue); - - root.setBrightness(newBrightness, actualDevice); - - return "Brightness increased by " + stepValue + "%" + (device ? " on " + actualDevice : ""); - } - - function decrement(step: string, device: string): string { - if (!root.brightnessAvailable) - return "Brightness control not available"; - - const actualDevice = device || root.getPreferredDevice(); - - if (actualDevice && !root.devices.some(d => d.id === actualDevice)) - return "Device not found: " + actualDevice; - - const stepValue = parseInt(step || "5"); - - root.lastIpcDevice = actualDevice; - if (actualDevice && actualDevice !== root.currentDevice) - root.setCurrentDevice(actualDevice, false); - - const isExponential = SessionData.getBrightnessExponential(actualDevice); - const currentBrightness = root.getDeviceBrightness(actualDevice); - const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice); - - let minValue = 0; - switch (true) { - case isExponential: - minValue = 1; - break; - case deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc"): - minValue = 1; - break; - default: - minValue = 0; - break; - } - - const newBrightness = Math.max(minValue, currentBrightness - stepValue); - - root.setBrightness(newBrightness, actualDevice); - - return "Brightness decreased by " + stepValue + "%" + (device ? " on " + actualDevice : ""); - } - - function status(): string { - if (!root.brightnessAvailable) { - return "Brightness control not available"; - } - - return "Device: " + root.currentDevice + " - Brightness: " + root.brightnessLevel + "%"; - } - - function list(): string { - if (!root.brightnessAvailable) { - return "No brightness devices available"; - } - - let result = "Available devices:\n"; - for (const device of root.devices) { - const isExp = SessionData.getBrightnessExponential(device.id); - result += device.id + " (" + device.class + ")" + (isExp ? " [exponential]" : "") + "\n"; - } - return result; - } - - function enableExponential(device: string): string { - const targetDevice = device || root.currentDevice; - if (!targetDevice) { - return "No device specified"; - } - - if (!root.devices.some(d => d.id === targetDevice)) { - return "Device not found: " + targetDevice; - } - - SessionData.setBrightnessExponential(targetDevice, true); - return "Exponential mode enabled for " + targetDevice; - } - - function disableExponential(device: string): string { - const targetDevice = device || root.currentDevice; - if (!targetDevice) { - return "No device specified"; - } - - if (!root.devices.some(d => d.id === targetDevice)) { - return "Device not found: " + targetDevice; - } - - SessionData.setBrightnessExponential(targetDevice, false); - return "Exponential mode disabled for " + targetDevice; - } - - function toggleExponential(device: string): string { - const targetDevice = device || root.currentDevice; - if (!targetDevice) { - return "No device specified"; - } - - if (!root.devices.some(d => d.id === targetDevice)) { - return "Device not found: " + targetDevice; - } - - const currentState = SessionData.getBrightnessExponential(targetDevice); - SessionData.setBrightnessExponential(targetDevice, !currentState); - return "Exponential mode " + (!currentState ? "enabled" : "disabled") + " for " + targetDevice; - } - - target: "brightness" - } - - IpcHandler { - function toggle(): string { - root.toggleNightMode(); - return root.nightModeEnabled ? "Night mode enabled" : "Night mode disabled"; - } - - function enable(): string { - root.enableNightMode(); - return "Night mode enabled"; - } - - function disable(): string { - root.disableNightMode(); - return "Night mode disabled"; - } - - function status(): string { - if (!root.gammaControlAvailable) - return "Night mode: unavailable (no gamma control)"; - - const parts = ["Night mode: " + (root.nightModeEnabled ? "enabled" : "disabled")]; - - if (root.gammaCurrentTemp > 0) - parts.push("Current temperature: " + root.gammaCurrentTemp + "K"); - - parts.push("Target night temperature: " + SessionData.nightModeTemperature + "K"); - - if (SessionData.nightModeAutoEnabled) { - parts.push("Target day temperature: " + SessionData.nightModeHighTemperature + "K"); - parts.push("Automation: " + SessionData.nightModeAutoMode); - parts.push("Period: " + (root.gammaIsDay ? "day" : "night")); - - if (root.gammaNextTransition) - parts.push("Next transition: " + root.gammaNextTransition); - if (root.gammaSunriseTime) - parts.push("Sunrise: " + root.gammaSunriseTime); - if (root.gammaSunsetTime) - parts.push("Sunset: " + root.gammaSunsetTime); - } - - return parts.join("\n"); - } - - function getCurrentTemp(): string { - if (!root.gammaControlAvailable) - return "Gamma control not available"; - if (root.gammaCurrentTemp <= 0) - return "No current temperature reported"; - return root.gammaCurrentTemp.toString(); - } - - function getTargetTemp(): string { - return SessionData.nightModeTemperature.toString(); - } - - function getDayTemp(): string { - return SessionData.nightModeHighTemperature.toString(); - } - - function setTargetTemp(value: string): string { - if (!value) - return "Usage: night setTargetTemp <2500-6000>"; - - const temp = parseInt(value); - if (isNaN(temp)) - return "Invalid temperature: " + value; - if (temp < 2500 || temp > 6000) - return "Temperature must be between 2500K and 6000K"; - - const rounded = Math.round(temp / 500) * 500; - SessionData.setNightModeTemperature(rounded); - - if (root.nightModeEnabled) { - switch (true) { - case SessionData.nightModeAutoEnabled: - root.startAutomation(); - break; - default: - root.applyNightModeDirectly(); - break; - } - } - - if (rounded !== temp) - return "Night temperature set to " + rounded + "K (rounded from " + temp + "K)"; - return "Night temperature set to " + rounded + "K"; - } - - function setDayTemp(value: string): string { - if (!value) - return "Usage: night setDayTemp <2500-6500>"; - - const temp = parseInt(value); - if (isNaN(temp)) - return "Invalid temperature: " + value; - if (temp < 2500 || temp > 6500) - return "Temperature must be between 2500K and 6500K"; - - const rounded = Math.round(temp / 500) * 500; - SessionData.setNightModeHighTemperature(rounded); - - if (root.nightModeEnabled && SessionData.nightModeAutoEnabled) - root.startAutomation(); - - if (rounded !== temp) - return "Day temperature set to " + rounded + "K (rounded from " + temp + "K)"; - return "Day temperature set to " + rounded + "K"; - } - - function getSchedule(): string { - if (!SessionData.nightModeAutoEnabled) - return "Automation disabled"; - - const parts = ["Mode: " + SessionData.nightModeAutoMode]; - parts.push("Period: " + (root.gammaIsDay ? "day" : "night")); - - if (root.gammaDawnTime) - parts.push("Dawn: " + root.gammaDawnTime); - if (root.gammaSunriseTime) - parts.push("Sunrise: " + root.gammaSunriseTime); - if (root.gammaSunsetTime) - parts.push("Sunset: " + root.gammaSunsetTime); - if (root.gammaNightTime) - parts.push("Night: " + root.gammaNightTime); - if (root.gammaNextTransition) - parts.push("Next transition: " + root.gammaNextTransition); - if (root.gammaSunPosition > 0) - parts.push("Sun position: " + root.gammaSunPosition.toFixed(2) + "°"); - - return parts.join("\n"); - } - - target: "night" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml deleted file mode 100644 index 564e561..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml +++ /dev/null @@ -1,454 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) - readonly property string mangoDmsDir: configDir + "/mango/dms" - readonly property string outputsPath: mangoDmsDir + "/outputs.conf" - readonly property string layoutPath: mangoDmsDir + "/layout.conf" - readonly property string cursorPath: mangoDmsDir + "/cursor.conf" - - property int _lastGapValue: -1 - - property bool dwlAvailable: false - property var outputs: ({}) - property var tagCount: 9 - property var layouts: [] - property string activeOutput: "" - property var outputScales: ({}) - property string currentKeyboardLayout: { - if (!outputs || !activeOutput) - return ""; - const output = outputs[activeOutput]; - return (output && output.kbLayout) || ""; - } - - signal stateChanged - - Connections { - target: SettingsData - function onBarConfigsChanged() { - if (!CompositorService.isDwl) - return; - const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - if (newGaps === root._lastGapValue) - return; - root._lastGapValue = newGaps; - generateLayoutConfig(); - } - } - - Connections { - target: CompositorService - function onIsDwlChanged() { - if (CompositorService.isDwl) - generateLayoutConfig(); - } - } - - Connections { - target: DMSService - function onCapabilitiesReceived() { - checkCapabilities(); - } - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkCapabilities(); - } else { - dwlAvailable = false; - } - } - function onDwlStateUpdate(data) { - if (dwlAvailable) { - handleStateUpdate(data); - } - } - } - - Component.onCompleted: { - if (DMSService.dmsAvailable) - checkCapabilities(); - if (dwlAvailable) - refreshOutputScales(); - if (CompositorService.isDwl) - Qt.callLater(generateLayoutConfig); - } - - function checkCapabilities() { - if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) { - dwlAvailable = false; - return; - } - - const hasDwl = DMSService.capabilities.includes("dwl"); - if (hasDwl && !dwlAvailable) { - dwlAvailable = true; - console.info("DwlService: DWL capability detected"); - requestState(); - refreshOutputScales(); - } else if (!hasDwl) { - dwlAvailable = false; - } - } - - function requestState() { - if (!DMSService.isConnected || !dwlAvailable) { - return; - } - - DMSService.sendRequest("dwl.getState", null, response => { - if (response.result) { - handleStateUpdate(response.result); - } - }); - } - - function handleStateUpdate(state) { - outputs = state.outputs || {}; - tagCount = state.tagCount || 9; - layouts = state.layouts || []; - activeOutput = state.activeOutput || ""; - stateChanged(); - } - - function setTags(outputName, tagmask, toggleTagset) { - if (!DMSService.isConnected || !dwlAvailable) { - return; - } - - DMSService.sendRequest("dwl.setTags", { - "output": outputName, - "tagmask": tagmask, - "toggleTagset": toggleTagset - }, response => { - if (response.error) { - console.warn("DwlService: setTags error:", response.error); - } - }); - } - - function setClientTags(outputName, andTags, xorTags) { - if (!DMSService.isConnected || !dwlAvailable) { - return; - } - - DMSService.sendRequest("dwl.setClientTags", { - "output": outputName, - "andTags": andTags, - "xorTags": xorTags - }, response => { - if (response.error) { - console.warn("DwlService: setClientTags error:", response.error); - } - }); - } - - function setLayout(outputName, index) { - if (!DMSService.isConnected || !dwlAvailable) { - return; - } - - DMSService.sendRequest("dwl.setLayout", { - "output": outputName, - "index": index - }, response => { - if (response.error) { - console.warn("DwlService: setLayout error:", response.error); - } - }); - } - - function getOutputState(outputName) { - if (!outputs || !outputs[outputName]) { - return null; - } - return outputs[outputName]; - } - - function getActiveTags(outputName) { - const output = getOutputState(outputName); - if (!output || !output.tags) { - return []; - } - return output.tags.filter(tag => tag.state === 1).map(tag => tag.tag); - } - - function getTagsWithClients(outputName) { - const output = getOutputState(outputName); - if (!output || !output.tags) { - return []; - } - return output.tags.filter(tag => tag.clients > 0).map(tag => tag.tag); - } - - function getUrgentTags(outputName) { - const output = getOutputState(outputName); - if (!output || !output.tags) { - return []; - } - return output.tags.filter(tag => tag.state === 2).map(tag => tag.tag); - } - - function switchToTag(outputName, tagIndex) { - const tagmask = 1 << tagIndex; - setTags(outputName, tagmask, 0); - } - - function toggleTag(outputName, tagIndex) { - const output = getOutputState(outputName); - if (!output || !output.tags) { - console.log("toggleTag: no output or tags for", outputName); - return; - } - - let currentMask = 0; - output.tags.forEach(tag => { - if (tag.state === 1) { - currentMask |= (1 << tag.tag); - } - }); - - const clickedMask = 1 << tagIndex; - const newMask = currentMask ^ clickedMask; - - console.log("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2)); - - if (newMask === 0) { - console.log("toggleTag: newMask is 0, switching to tag", tagIndex); - setTags(outputName, 1 << tagIndex, 0); - } else { - console.log("toggleTag: setting combined mask", newMask); - setTags(outputName, newMask, 0); - } - } - - function quit() { - Quickshell.execDetached(["mmsg", "-d", "quit"]); - } - - Process { - id: scaleQueryProcess - command: ["mmsg", "-A"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - try { - const newScales = {}; - const lines = text.trim().split('\n'); - for (const line of lines) { - const parts = line.trim().split(/\s+/); - if (parts.length >= 3 && parts[1] === "scale_factor") { - const outputName = parts[0]; - const scale = parseFloat(parts[2]); - if (!isNaN(scale)) { - newScales[outputName] = scale; - } - } - } - outputScales = newScales; - } catch (e) { - console.warn("DwlService: Failed to parse mmsg output:", e); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("DwlService: mmsg failed with exit code:", exitCode); - } - } - } - - function refreshOutputScales() { - if (!dwlAvailable) - return; - scaleQueryProcess.running = true; - } - - function getOutputScale(outputName) { - return outputScales[outputName]; - } - - function getVisibleTags(outputName) { - const output = getOutputState(outputName); - if (!output || !output.tags) { - return []; - } - - const visibleTags = new Set(); - - output.tags.forEach(tag => { - if (tag.state === 1 || tag.clients > 0) { - visibleTags.add(tag.tag); - } - }); - - return Array.from(visibleTags).sort((a, b) => a - b); - } - - function generateOutputsConfig(outputsData) { - if (!outputsData || Object.keys(outputsData).length === 0) - return; - let lines = ["# Auto-generated by DMS - do not edit manually", ""]; - - for (const outputName in outputsData) { - const output = outputsData[outputName]; - if (!output) - continue; - let width = 1920; - let height = 1080; - let refreshRate = 60; - if (output.modes && output.current_mode !== undefined) { - const mode = output.modes[output.current_mode]; - if (mode) { - width = mode.width || 1920; - height = mode.height || 1080; - refreshRate = Math.round((mode.refresh_rate || 60000) / 1000); - } - } - - const x = output.logical?.x ?? 0; - const y = output.logical?.y ?? 0; - const scale = output.logical?.scale ?? 1.0; - const transform = transformToMango(output.logical?.transform ?? "Normal"); - const vrr = output.vrr_enabled ? 1 : 0; - - const rule = ["name:" + outputName, "width:" + width, "height:" + height, "refresh:" + refreshRate, "x:" + x, "y:" + y, "scale:" + scale, "rr:" + transform, "vrr:" + vrr].join(","); - - lines.push("monitorrule=" + rule); - } - - lines.push(""); - - const content = lines.join("\n"); - - Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("DwlService: Failed to write outputs config:", output); - return; - } - console.info("DwlService: Generated outputs config at", outputsPath); - if (CompositorService.isDwl) - reloadConfig(); - }); - } - - function reloadConfig() { - Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => { - if (exitCode !== 0) - console.warn("DwlService: mmsg reload_config failed:", output); - }); - } - - function generateLayoutConfig() { - if (!CompositorService.isDwl) - return; - - const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; - const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4; - const defaultBorderSize = 2; - - const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutRadiusOverride >= 0) ? SettingsData.mangoLayoutRadiusOverride : defaultRadius; - const gaps = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutGapsOverride >= 0) ? SettingsData.mangoLayoutGapsOverride : defaultGaps; - const borderSize = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutBorderSize >= 0) ? SettingsData.mangoLayoutBorderSize : defaultBorderSize; - - let content = `# Auto-generated by DMS - do not edit manually -border_radius=${cornerRadius} -gappih=${gaps} -gappiv=${gaps} -gappoh=${gaps} -gappov=${gaps} -borderpx=${borderSize} -`; - - Proc.runCommand("mango-write-layout", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("DwlService: Failed to write layout config:", output); - return; - } - console.info("DwlService: Generated layout config at", layoutPath); - reloadConfig(); - }); - } - - function transformToMango(transform) { - switch (transform) { - case "Normal": - return 0; - case "90": - return 1; - case "180": - return 2; - case "270": - return 3; - case "Flipped": - return 4; - case "Flipped90": - return 5; - case "Flipped180": - return 6; - case "Flipped270": - return 7; - default: - return 0; - } - } - - function generateCursorConfig() { - if (!CompositorService.isDwl) - return; - - console.log("DwlService: Generating cursor config..."); - - const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null; - if (!settings) { - Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("DwlService: Failed to write cursor config:", output); - }); - return; - } - - const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme; - const size = settings.size || 24; - const hideTimeout = settings.dwl?.cursorHideTimeout || 0; - - const isDefaultConfig = !themeName && size === 24 && hideTimeout === 0; - if (isDefaultConfig) { - Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("DwlService: Failed to write cursor config:", output); - }); - return; - } - - let content = `# Auto-generated by DMS - do not edit manually -cursor_size=${size}`; - - if (themeName) - content += `\ncursor_theme=${themeName}`; - - if (hideTimeout > 0) - content += `\ncursor_hide_timeout=${hideTimeout}`; - - content += `\n`; - - Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("DwlService: Failed to write cursor config:", output); - return; - } - console.info("DwlService: Generated cursor config at", cursorPath); - reloadConfig(); - }); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml deleted file mode 100644 index 48a8f9a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml +++ /dev/null @@ -1,277 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - property bool extWorkspaceAvailable: false - property var groups: [] - property var _cachedWorkspaces: ({}) - - signal stateChanged - - Connections { - target: DMSService - function onCapabilitiesReceived() { - checkCapabilities(); - } - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkCapabilities(); - } else { - extWorkspaceAvailable = false; - } - } - function onExtWorkspaceStateUpdate(data) { - if (extWorkspaceAvailable) { - handleStateUpdate(data); - } - } - } - - Component.onCompleted: { - if (DMSService.dmsAvailable) { - checkCapabilities(); - } - } - - function checkCapabilities() { - if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) { - extWorkspaceAvailable = false; - return; - } - - const hasExtWorkspace = DMSService.capabilities.includes("extworkspace"); - if (hasExtWorkspace && !extWorkspaceAvailable) { - if (typeof CompositorService !== "undefined") { - const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle); - if (!useExtWorkspace) { - console.info("ExtWorkspaceService: ext-workspace available but compositor has native support"); - extWorkspaceAvailable = false; - return; - } - } - extWorkspaceAvailable = true; - console.info("ExtWorkspaceService: ext-workspace capability detected"); - DMSService.addSubscription("extworkspace"); - requestState(); - } else if (!hasExtWorkspace) { - extWorkspaceAvailable = false; - } - } - - function requestState() { - if (!DMSService.isConnected || !extWorkspaceAvailable) { - return; - } - - DMSService.sendRequest("extworkspace.getState", null, response => { - if (response.result) { - handleStateUpdate(response.result); - } - }); - } - - function handleStateUpdate(state) { - groups = state.groups || []; - if (groups.length === 0) { - console.warn("ExtWorkspaceService: Received empty workspace groups from backend"); - } else { - console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups"); - } - stateChanged(); - } - - function activateWorkspace(workspaceID, groupID = "") { - if (!DMSService.isConnected || !extWorkspaceAvailable) { - return; - } - - DMSService.sendRequest("extworkspace.activateWorkspace", { - "workspaceID": workspaceID, - "groupID": groupID - }, response => { - if (response.error) { - console.warn("ExtWorkspaceService: activateWorkspace error:", response.error); - } - }); - } - - function deactivateWorkspace(workspaceID, groupID = "") { - if (!DMSService.isConnected || !extWorkspaceAvailable) { - return; - } - - DMSService.sendRequest("extworkspace.deactivateWorkspace", { - "workspaceID": workspaceID, - "groupID": groupID - }, response => { - if (response.error) { - console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error); - } - }); - } - - function removeWorkspace(workspaceID, groupID = "") { - if (!DMSService.isConnected || !extWorkspaceAvailable) { - return; - } - - DMSService.sendRequest("extworkspace.removeWorkspace", { - "workspaceID": workspaceID, - "groupID": groupID - }, response => { - if (response.error) { - console.warn("ExtWorkspaceService: removeWorkspace error:", response.error); - } - }); - } - - function createWorkspace(groupID, name) { - if (!DMSService.isConnected || !extWorkspaceAvailable) { - return; - } - - DMSService.sendRequest("extworkspace.createWorkspace", { - "groupID": groupID, - "name": name - }, response => { - if (response.error) { - console.warn("ExtWorkspaceService: createWorkspace error:", response.error); - } - }); - } - - function getGroupForOutput(outputName) { - for (const group of groups) { - if (group.outputs && group.outputs.includes(outputName)) { - return group; - } - } - return null; - } - - function getWorkspacesForOutput(outputName) { - const group = getGroupForOutput(outputName); - return group ? (group.workspaces || []) : []; - } - - function getActiveWorkspaces() { - const active = []; - for (const group of groups) { - if (!group.workspaces) - continue; - for (const ws of group.workspaces) { - if (ws.active) { - active.push({ - workspace: ws, - group: group, - outputs: group.outputs || [] - }); - } - } - } - return active; - } - - function getActiveWorkspaceForOutput(outputName) { - const group = getGroupForOutput(outputName); - if (!group || !group.workspaces) - return null; - - for (const ws of group.workspaces) { - if (ws.active) { - return ws; - } - } - return null; - } - - function getVisibleWorkspaces(outputName) { - const workspaces = getWorkspacesForOutput(outputName); - let visible = workspaces.filter(ws => !ws.hidden); - - const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0); - if (hasValidCoordinates) { - visible = visible.sort((a, b) => { - const coordsA = a.coordinates || [0, 0]; - const coordsB = b.coordinates || [0, 0]; - if (coordsA[0] !== coordsB[0]) - return coordsA[0] - coordsB[0]; - return coordsA[1] - coordsB[1]; - }); - } - - const cacheKey = outputName; - if (!_cachedWorkspaces[cacheKey]) { - _cachedWorkspaces[cacheKey] = { - workspaces: [], - lastNames: [] - }; - } - - const cache = _cachedWorkspaces[cacheKey]; - const currentNames = visible.map(ws => ws.name || ws.id); - const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames); - - if (namesChanged || cache.workspaces.length !== visible.length) { - cache.workspaces = visible.map(ws => ({ - id: ws.id, - name: ws.name, - coordinates: ws.coordinates, - state: ws.state, - active: ws.active, - urgent: ws.urgent, - hidden: ws.hidden - })); - cache.lastNames = currentNames; - return cache.workspaces; - } - - for (let i = 0; i < visible.length; i++) { - const src = visible[i]; - const dst = cache.workspaces[i]; - dst.id = src.id; - dst.name = src.name; - dst.coordinates = src.coordinates; - dst.state = src.state; - dst.active = src.active; - dst.urgent = src.urgent; - dst.hidden = src.hidden; - } - - return cache.workspaces; - } - - function getUrgentWorkspaces() { - const urgent = []; - for (const group of groups) { - if (!group.workspaces) - continue; - for (const ws of group.workspaces) { - if (ws.urgent) { - urgent.push({ - workspace: ws, - group: group, - outputs: group.outputs || [] - }); - } - } - } - return urgent; - } - - function switchToWorkspace(outputName, workspaceName) { - const workspaces = getWorkspacesForOutput(outputName); - for (const ws of workspaces) { - if (ws.name === workspaceName || ws.id === workspaceName) { - activateWorkspace(ws.name || ws.id); - return; - } - } - console.warn("ExtWorkspaceService: workspace not found:", workspaceName); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml deleted file mode 100644 index 8b7acd3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml +++ /dev/null @@ -1,111 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell" - readonly property string settingsPath: configDir + "/settings.json" - readonly property string firstLaunchMarkerPath: configDir + "/.firstlaunch" - - property bool isFirstLaunch: false - property bool checkComplete: false - property bool greeterDismissed: false - property int requestedStartPage: 0 - - readonly property bool shouldShowGreeter: checkComplete && isFirstLaunch && !greeterDismissed - - signal greeterRequested - signal greeterCompleted - - function showGreeter(startPage) { - requestedStartPage = startPage || 0; - greeterRequested(); - } - - function showWelcome() { - showGreeter(0); - } - - function showDoctor() { - showGreeter(1); - } - - Component.onCompleted: { - checkFirstLaunch(); - } - - function checkFirstLaunch() { - firstLaunchCheckProcess.running = true; - } - - function markFirstLaunchComplete() { - greeterDismissed = true; - touchMarkerProcess.running = true; - greeterCompleted(); - } - - function dismissGreeter() { - greeterDismissed = true; - } - - Process { - id: firstLaunchCheckProcess - - command: ["sh", "-c", ` - SETTINGS='` + settingsPath + `' - MARKER='` + firstLaunchMarkerPath + `' - if [ -f "$MARKER" ]; then - echo 'skip' - elif [ -f "$SETTINGS" ]; then - echo 'existing_user' - else - echo 'first' - fi - `] - running: false - - stdout: SplitParser { - onRead: data => { - const result = data.trim(); - - if (result === "first") { - root.isFirstLaunch = true; - console.info("FirstLaunchService: First launch detected, greeter will be shown"); - } else if (result === "existing_user") { - root.isFirstLaunch = false; - console.info("FirstLaunchService: Existing user detected, silently creating marker"); - touchMarkerProcess.running = true; - } else { - root.isFirstLaunch = false; - } - - root.checkComplete = true; - - if (root.isFirstLaunch) - root.greeterRequested(); - } - } - } - - Process { - id: touchMarkerProcess - - command: ["sh", "-c", "mkdir -p '" + configDir + "' && touch '" + firstLaunchMarkerPath + "'"] - running: false - - onExited: exitCode => { - if (exitCode === 0) { - console.info("FirstLaunchService: First launch marker created"); - } else { - console.warn("FirstLaunchService: Failed to create first launch marker"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml deleted file mode 100644 index 20096ef..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml +++ /dev/null @@ -1,338 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Hyprland -import qs.Common - -Singleton { - id: root - - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) - readonly property string hyprDmsDir: configDir + "/hypr/dms" - readonly property string outputsPath: hyprDmsDir + "/outputs.conf" - readonly property string layoutPath: hyprDmsDir + "/layout.conf" - readonly property string cursorPath: hyprDmsDir + "/cursor.conf" - readonly property string windowrulesPath: hyprDmsDir + "/windowrules.conf" - - property int _lastGapValue: -1 - - Component.onCompleted: { - if (CompositorService.isHyprland) { - Qt.callLater(generateLayoutConfig); - ensureWindowrulesConfig(); - } - } - - function ensureWindowrulesConfig() { - Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("HyprlandService: Failed to ensure windowrules.conf:", output); - }); - } - - Connections { - target: SettingsData - function onBarConfigsChanged() { - if (!CompositorService.isHyprland) - return; - const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - if (newGaps === root._lastGapValue) - return; - root._lastGapValue = newGaps; - generateLayoutConfig(); - } - } - - Connections { - target: CompositorService - function onIsHyprlandChanged() { - if (CompositorService.isHyprland) - generateLayoutConfig(); - } - } - - function getOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output.make && output.model) - return "desc:" + output.make + " " + output.model + " " + (output.serial || "Unknown"); - return outputName; - } - - function generateOutputsConfig(outputsData, hyprlandSettings) { - if (!outputsData || Object.keys(outputsData).length === 0) - return; - - const settings = hyprlandSettings || SettingsData.hyprlandOutputSettings; - let lines = ["# Auto-generated by DMS - do not edit manually", ""]; - let monitorv2Blocks = []; - - for (const outputName in outputsData) { - const output = outputsData[outputName]; - if (!output) - continue; - - const identifier = getOutputIdentifier(output, outputName); - const outputSettings = settings[identifier] || {}; - - if (outputSettings.disabled) { - lines.push("monitor = " + identifier + ", disable"); - continue; - } - - let resolution = "preferred"; - if (output.modes && output.current_mode !== undefined) { - const mode = output.modes[output.current_mode]; - if (mode) - resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3); - } - - const x = output.logical?.x ?? 0; - const y = output.logical?.y ?? 0; - const position = x + "x" + y; - const scale = output.logical?.scale ?? 1.0; - - let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale; - - const transform = transformToHyprland(output.logical?.transform ?? "Normal"); - if (transform !== 0) - monitorLine += ", transform, " + transform; - - if (output.vrr_supported) { - const vrrMode = outputSettings.vrrFullscreenOnly ? 2 : (output.vrr_enabled ? 1 : 0); - monitorLine += ", vrr, " + vrrMode; - } - - if (output.mirror && output.mirror.length > 0) - monitorLine += ", mirror, " + output.mirror; - - if (outputSettings.bitdepth && outputSettings.bitdepth !== 8) - monitorLine += ", bitdepth, " + outputSettings.bitdepth; - - if (outputSettings.colorManagement && outputSettings.colorManagement !== "auto") - monitorLine += ", cm, " + outputSettings.colorManagement; - - if (outputSettings.sdrBrightness !== undefined && outputSettings.sdrBrightness !== 1.0) - monitorLine += ", sdrbrightness, " + outputSettings.sdrBrightness; - - if (outputSettings.sdrSaturation !== undefined && outputSettings.sdrSaturation !== 1.0) - monitorLine += ", sdrsaturation, " + outputSettings.sdrSaturation; - - lines.push(monitorLine); - - const needsMonitorv2 = outputSettings.supportsHdr || outputSettings.supportsWideColor || outputSettings.sdrMinLuminance !== undefined || outputSettings.sdrMaxLuminance !== undefined || outputSettings.minLuminance !== undefined || outputSettings.maxLuminance !== undefined || outputSettings.maxAvgLuminance !== undefined; - - if (needsMonitorv2) { - let block = "monitorv2 {\n"; - block += " output = " + identifier + "\n"; - - if (outputSettings.supportsWideColor) - block += " supports_wide_color = true\n"; - if (outputSettings.supportsHdr) - block += " supports_hdr = true\n"; - if (outputSettings.sdrMinLuminance !== undefined) - block += " sdr_min_luminance = " + outputSettings.sdrMinLuminance + "\n"; - if (outputSettings.sdrMaxLuminance !== undefined) - block += " sdr_max_luminance = " + outputSettings.sdrMaxLuminance + "\n"; - if (outputSettings.minLuminance !== undefined) - block += " min_luminance = " + outputSettings.minLuminance + "\n"; - if (outputSettings.maxLuminance !== undefined) - block += " max_luminance = " + outputSettings.maxLuminance + "\n"; - if (outputSettings.maxAvgLuminance !== undefined) - block += " max_avg_luminance = " + outputSettings.maxAvgLuminance + "\n"; - - block += "}"; - monitorv2Blocks.push(block); - } - } - - if (monitorv2Blocks.length > 0) { - lines.push(""); - for (const block of monitorv2Blocks) - lines.push(block); - } - - lines.push(""); - - const content = lines.join("\n"); - - Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("HyprlandService: Failed to write outputs config:", output); - return; - } - console.info("HyprlandService: Generated outputs config at", outputsPath); - if (CompositorService.isHyprland) - reloadConfig(); - }); - } - - function reloadConfig() { - Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => { - if (exitCode !== 0) - console.warn("HyprlandService: hyprctl reload failed:", output); - }); - } - - function generateLayoutConfig() { - if (!CompositorService.isHyprland) - return; - - const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; - const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4; - const defaultBorderSize = 2; - - const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutRadiusOverride >= 0) ? SettingsData.hyprlandLayoutRadiusOverride : defaultRadius; - const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps; - const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize; - - let content = `# Auto-generated by DMS - do not edit manually - -general { - gaps_in = ${gaps} - gaps_out = ${gaps} - border_size = ${borderSize} -} - -decoration { - rounding = ${cornerRadius} -} -`; - - Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("HyprlandService: Failed to write layout config:", output); - return; - } - console.info("HyprlandService: Generated layout config at", layoutPath); - reloadConfig(); - }); - } - - function transformToHyprland(transform) { - switch (transform) { - case "Normal": - return 0; - case "90": - return 1; - case "180": - return 2; - case "270": - return 3; - case "Flipped": - return 4; - case "Flipped90": - return 5; - case "Flipped180": - return 6; - case "Flipped270": - return 7; - default: - return 0; - } - } - - function hyprlandToTransform(value) { - switch (value) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function generateCursorConfig() { - if (!CompositorService.isHyprland) - return; - - const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null; - if (!settings) { - Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("HyprlandService: Failed to write cursor config:", output); - }); - return; - } - - const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme; - const size = settings.size || 24; - const hideOnKeyPress = settings.hyprland?.hideOnKeyPress || false; - const hideOnTouch = settings.hyprland?.hideOnTouch || false; - const inactiveTimeout = settings.hyprland?.inactiveTimeout || 0; - - const hasTheme = themeName && themeName.length > 0; - const hasNonDefaultSize = size !== 24; - const hasCursorSettings = hideOnKeyPress || hideOnTouch || inactiveTimeout > 0; - - if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) { - Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("HyprlandService: Failed to write cursor config:", output); - }); - return; - } - - let lines = ["# Auto-generated by DMS - do not edit manually", ""]; - - if (hasTheme) { - lines.push(`env = HYPRCURSOR_THEME,${themeName}`); - lines.push(`env = XCURSOR_THEME,${themeName}`); - } - lines.push(`env = HYPRCURSOR_SIZE,${size}`); - lines.push(`env = XCURSOR_SIZE,${size}`); - - if (hasCursorSettings) { - lines.push(""); - lines.push("cursor {"); - if (hideOnKeyPress) - lines.push(" hide_on_key_press = true"); - if (hideOnTouch) - lines.push(" hide_on_touch = true"); - if (inactiveTimeout > 0) - lines.push(` inactive_timeout = ${inactiveTimeout}`); - lines.push("}"); - } - - lines.push(""); - const content = lines.join("\n"); - - Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("HyprlandService: Failed to write cursor config:", output); - return; - } - if (hasTheme) - Proc.runCommand("hyprctl-setcursor", ["hyprctl", "setcursor", themeName, String(size)], () => {}); - reloadConfig(); - }); - } - - function renameWorkspace(newName) { - if (!Hyprland.focusedWorkspace) - return; - const wsId = Hyprland.focusedWorkspace.id; - if (!wsId) - return; - const fullName = wsId + " " + newName; - Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("HyprlandService: Failed to rename workspace:", output); - } - }); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml deleted file mode 100644 index 9965e47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml +++ /dev/null @@ -1,191 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -Singleton { - id: root - - readonly property bool idleMonitorAvailable: { - try { - return typeof IdleMonitor !== "undefined"; - } catch (e) { - return false; - } - } - - readonly property bool idleInhibitorAvailable: { - try { - return typeof IdleInhibitor !== "undefined"; - } catch (e) { - return false; - } - } - - property bool enabled: true - property bool respectInhibitors: true - property bool _enableGate: true - - readonly property bool externalInhibitActive: DMSService.screensaverInhibited - - readonly property bool isOnBattery: BatteryService.batteryAvailable && !BatteryService.isPluggedIn - readonly property int monitorTimeout: isOnBattery ? SettingsData.batteryMonitorTimeout : SettingsData.acMonitorTimeout - readonly property int lockTimeout: isOnBattery ? SettingsData.batteryLockTimeout : SettingsData.acLockTimeout - readonly property int suspendTimeout: isOnBattery ? SettingsData.batterySuspendTimeout : SettingsData.acSuspendTimeout - readonly property int suspendBehavior: isOnBattery ? SettingsData.batterySuspendBehavior : SettingsData.acSuspendBehavior - - readonly property bool mediaPlaying: MprisController.activePlayer !== null && MprisController.activePlayer.isPlaying - - onMonitorTimeoutChanged: _rearmIdleMonitors() - onLockTimeoutChanged: _rearmIdleMonitors() - onSuspendTimeoutChanged: _rearmIdleMonitors() - - function _rearmIdleMonitors() { - _enableGate = false; - Qt.callLater(() => { - _enableGate = true; - }); - } - - signal lockRequested - signal fadeToLockRequested - signal cancelFadeToLock - signal fadeToDpmsRequested - signal cancelFadeToDpms - signal requestMonitorOff - signal requestMonitorOn - signal requestSuspend - - property var monitorOffMonitor: null - property var lockMonitor: null - property var suspendMonitor: null - property var lockComponent: null - property bool monitorsOff: false - property bool isShellLocked: false - - function wake() { - requestMonitorOn(); - } - - function reapplyDpmsIfNeeded() { - if (monitorsOff) - CompositorService.powerOffMonitors(); - } - - function createIdleMonitors() { - if (!idleMonitorAvailable) { - console.info("IdleService: IdleMonitor not available, skipping creation"); - return; - } - - try { - const qmlString = ` - import QtQuick - import Quickshell.Wayland - - IdleMonitor { - enabled: false - respectInhibitors: true - timeout: 0 - } - `; - - monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor"); - monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout > 0 ? root.monitorTimeout : 86400); - monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors); - monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0); - monitorOffMonitor.isIdleChanged.connect(function () { - if (monitorOffMonitor.isIdle) { - if (SettingsData.fadeToDpmsEnabled) { - root.fadeToDpmsRequested(); - } else { - root.requestMonitorOff(); - } - } else { - if (SettingsData.fadeToDpmsEnabled) { - root.cancelFadeToDpms(); - } - root.requestMonitorOn(); - } - }); - - lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor"); - lockMonitor.timeout = Qt.binding(() => root.lockTimeout > 0 ? root.lockTimeout : 86400); - lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors); - lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0); - lockMonitor.isIdleChanged.connect(function () { - if (lockMonitor.isIdle) { - if (SettingsData.fadeToLockEnabled) { - root.fadeToLockRequested(); - } else { - root.lockRequested(); - } - } else { - if (SettingsData.fadeToLockEnabled) { - root.cancelFadeToLock(); - } - } - }); - - suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor"); - suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout > 0 ? root.suspendTimeout : 86400); - suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors); - suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0); - suspendMonitor.isIdleChanged.connect(function () { - if (suspendMonitor.isIdle) { - root.requestSuspend(); - } - }); - } catch (e) { - console.warn("IdleService: Error creating IdleMonitors:", e); - } - } - - Connections { - target: root - function onRequestMonitorOff() { - monitorsOff = true; - CompositorService.powerOffMonitors(); - } - - function onRequestMonitorOn() { - monitorsOff = false; - CompositorService.powerOnMonitors(); - } - - function onRequestSuspend() { - SessionService.suspendWithBehavior(root.suspendBehavior); - } - } - - onExternalInhibitActiveChanged: { - if (externalInhibitActive) { - const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", "); - console.info("IdleService: External idle inhibit active from:", apps || "unknown"); - SessionService.idleInhibited = true; - SessionService.inhibitReason = "External app: " + (apps || "unknown"); - } else { - console.info("IdleService: External idle inhibit released"); - SessionService.idleInhibited = false; - SessionService.inhibitReason = "Keep system awake"; - } - } - - Component.onCompleted: { - if (!idleMonitorAvailable) { - console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell."); - } else { - console.info("IdleService: Initialized with idle monitoring support"); - createIdleMonitors(); - } - - if (externalInhibitActive) { - const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", "); - SessionService.idleInhibited = true; - SessionService.inhibitReason = "External app: " + (apps || "unknown"); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml deleted file mode 100644 index 470831b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml +++ /dev/null @@ -1,528 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -// ! Even though qmlls says this is unused, it is wrong -import qs.Common -import "../Common/KeybindActions.js" as Actions - -Singleton { - id: root - - Component.onCompleted: { - if (!shortcutInhibitorAvailable) { - console.warn("[KeybindsService] ShortcutInhibitor is not available in this environment, keybinds editor disabled."); - } - } - - readonly property bool shortcutInhibitorAvailable: { - try { - return typeof ShortcutInhibitor !== "undefined"; - } catch (e) { - return false; - } - } - - property bool available: (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl) && shortcutInhibitorAvailable - property string currentProvider: { - if (CompositorService.isNiri) - return "niri"; - if (CompositorService.isHyprland) - return "hyprland"; - if (CompositorService.isDwl) - return "mangowc"; - return ""; - } - - readonly property string cheatsheetProvider: { - if (CompositorService.isNiri) - return "niri"; - if (CompositorService.isHyprland) - return "hyprland"; - if (CompositorService.isDwl) - return "mangowc"; - return ""; - } - property bool cheatsheetAvailable: cheatsheetProvider !== "" - property bool cheatsheetLoading: false - property var cheatsheet: ({}) - - property bool loading: false - property bool saving: false - property bool fixing: false - property string lastError: "" - property bool dmsBindsIncluded: true - - property var dmsStatus: ({ - "exists": true, - "included": true, - "includePosition": -1, - "totalIncludes": 0, - "bindsAfterDms": 0, - "effective": true, - "overriddenBy": 0, - "statusMessage": "" - }) - - property var _rawData: null - property var keybinds: ({}) - property var _allBinds: ({}) - property var _categories: [] - property var _flatCache: [] - property var displayList: [] - property int _dataVersion: 0 - property string _pendingSavedKey: "" - - readonly property var categoryOrder: Actions.getCategoryOrder() - readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) - readonly property string compositorConfigDir: { - switch (currentProvider) { - case "niri": - return configDir + "/niri"; - case "hyprland": - return configDir + "/hypr"; - case "mangowc": - return configDir + "/mango"; - default: - return ""; - } - } - readonly property string dmsBindsPath: { - switch (currentProvider) { - case "niri": - return compositorConfigDir + "/dms/binds.kdl"; - case "hyprland": - case "mangowc": - return compositorConfigDir + "/dms/binds.conf"; - default: - return ""; - } - } - readonly property string mainConfigPath: { - switch (currentProvider) { - case "niri": - return compositorConfigDir + "/config.kdl"; - case "hyprland": - return compositorConfigDir + "/hyprland.conf"; - case "mangowc": - return compositorConfigDir + "/config.conf"; - default: - return ""; - } - } - readonly property var actionTypes: Actions.getActionTypes() - readonly property var dmsActions: getDmsActions() - - signal bindsLoaded - signal bindSaved(string key) - signal bindSaveCompleted(bool success) - signal bindRemoved(string key) - signal dmsBindsFixed - signal cheatsheetLoaded - - Connections { - target: CompositorService - function onCompositorChanged() { - if (!CompositorService.isNiri) - return; - Qt.callLater(root.loadBinds); - } - } - - Connections { - target: NiriService - enabled: CompositorService.isNiri - function onConfigReloaded() { - Qt.callLater(root.loadBinds, false); - } - } - - Process { - id: cheatsheetProcess - running: false - - stdout: StdioCollector { - onStreamFinished: { - try { - root.cheatsheet = JSON.parse(text); - } catch (e) { - console.error("[KeybindsService] Failed to parse cheatsheet:", e); - root.cheatsheet = {}; - } - root.cheatsheetLoading = false; - root.cheatsheetLoaded(); - } - } - - onExited: exitCode => { - if (exitCode === 0) - return; - console.warn("[KeybindsService] Cheatsheet load failed with code:", exitCode); - root.cheatsheetLoading = false; - } - } - - Process { - id: loadProcess - running: false - - stdout: StdioCollector { - onStreamFinished: { - try { - root._rawData = JSON.parse(text); - root._processData(); - } catch (e) { - console.error("[KeybindsService] Failed to parse binds:", e); - } - root.loading = false; - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - console.warn("[KeybindsService] Load process failed with code:", exitCode); - root.loading = false; - } - } - } - - Process { - id: saveProcess - running: false - - stderr: StdioCollector { - onStreamFinished: { - if (!text.trim()) - return; - root.lastError = text.trim(); - ToastService.showError(I18n.tr("Failed to save keybind"), "", root.lastError, "keybinds"); - } - } - - onExited: exitCode => { - root.saving = false; - if (exitCode !== 0) { - console.error("[KeybindsService] Save failed with code:", exitCode); - root.bindSaveCompleted(false); - return; - } - root.lastError = ""; - root.bindSaveCompleted(true); - root.loadBinds(false); - } - } - - Process { - id: removeProcess - running: false - - stderr: StdioCollector { - onStreamFinished: { - if (!text.trim()) - return; - root.lastError = text.trim(); - ToastService.showError(I18n.tr("Failed to remove keybind"), "", root.lastError, "keybinds"); - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - console.error("[KeybindsService] Remove failed with code:", exitCode); - return; - } - root.lastError = ""; - root.loadBinds(false); - } - } - - Process { - id: fixProcess - running: false - - stderr: StdioCollector { - onStreamFinished: { - if (!text.trim()) - return; - root.lastError = text.trim(); - ToastService.showError(I18n.tr("Failed to add binds include"), "", root.lastError, "keybinds"); - } - } - - onExited: exitCode => { - root.fixing = false; - if (exitCode !== 0) { - console.error("[KeybindsService] Fix failed with code:", exitCode); - return; - } - root.lastError = ""; - root.dmsBindsIncluded = true; - root.dmsBindsFixed(); - const bindsFile = root.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf"; - ToastService.showInfo(I18n.tr("Binds include added"), I18n.tr("%1 is now included in config").arg(bindsFile), "", "keybinds"); - Qt.callLater(root.forceReload); - } - } - - function fixDmsBindsInclude() { - if (fixing || dmsBindsIncluded || !compositorConfigDir) - return; - fixing = true; - const timestamp = Math.floor(Date.now() / 1000); - const backupPath = `${mainConfigPath}.dmsbackup${timestamp}`; - let script; - switch (currentProvider) { - case "niri": - script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.kdl" && cp "${mainConfigPath}" "${backupPath}" && echo 'include "dms/binds.kdl"' >> "${mainConfigPath}"`; - break; - case "hyprland": - script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.conf" && cp "${mainConfigPath}" "${backupPath}" && echo 'source = ./dms/binds.conf' >> "${mainConfigPath}"`; - break; - case "mangowc": - script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.conf" && cp "${mainConfigPath}" "${backupPath}" && echo 'source = ./dms/binds.conf' >> "${mainConfigPath}"`; - break; - default: - fixing = false; - return; - } - fixProcess.command = ["sh", "-c", script]; - fixProcess.running = true; - } - - function forceReload() { - _allBinds = {}; - _flatCache = []; - _categories = []; - loadBinds(true); - } - - function loadCheatsheet(provider) { - if (cheatsheetProcess.running) - return; - const target = provider || cheatsheetProvider; - if (!target) - return; - cheatsheetLoading = true; - cheatsheetProcess.command = ["dms", "keybinds", "show", target]; - cheatsheetProcess.running = true; - } - - function loadBinds(showLoading) { - if (loadProcess.running || !available) - return; - const hasData = Object.keys(_allBinds).length > 0; - loading = showLoading !== false && !hasData; - loadProcess.command = ["dms", "keybinds", "show", currentProvider]; - loadProcess.running = true; - } - - function _processData() { - keybinds = _rawData || {}; - dmsBindsIncluded = _rawData?.dmsBindsIncluded ?? true; - const status = _rawData?.dmsStatus; - if (status) { - dmsStatus = { - "exists": status.exists ?? true, - "included": status.included ?? true, - "includePosition": status.includePosition ?? -1, - "totalIncludes": status.totalIncludes ?? 0, - "bindsAfterDms": status.bindsAfterDms ?? 0, - "effective": status.effective ?? true, - "overriddenBy": status.overriddenBy ?? 0, - "statusMessage": status.statusMessage ?? "" - }; - } - - if (!_rawData?.binds) { - _allBinds = {}; - _categories = []; - _flatCache = []; - displayList = []; - _dataVersion++; - bindsLoaded(); - if (_pendingSavedKey) { - bindSaved(_pendingSavedKey); - _pendingSavedKey = ""; - } - return; - } - - const processed = {}; - const bindsData = _rawData.binds; - for (const cat in bindsData) { - const binds = bindsData[cat]; - for (var i = 0; i < binds.length; i++) { - const bind = binds[i]; - const targetCat = Actions.isDmsAction(bind.action) ? "DMS" : cat; - if (!processed[targetCat]) - processed[targetCat] = []; - processed[targetCat].push(bind); - } - } - - const sortedCats = Object.keys(processed).sort((a, b) => { - const ai = categoryOrder.indexOf(a); - const bi = categoryOrder.indexOf(b); - return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi); - }); - - const grouped = []; - const actionMap = {}; - for (var ci = 0; ci < sortedCats.length; ci++) { - const category = sortedCats[ci]; - const binds = processed[category]; - if (!binds) - continue; - for (var i = 0; i < binds.length; i++) { - const bind = binds[i]; - const action = bind.action || ""; - const keyData = { - "key": bind.key || "", - "source": bind.source || "config", - "isOverride": bind.source === "dms", - "cooldownMs": bind.cooldownMs || 0, - "flags": bind.flags || "", - "allowWhenLocked": bind.allowWhenLocked || false, - "allowInhibiting": bind.allowInhibiting, - "repeat": bind.repeat - }; - if (actionMap[action]) { - actionMap[action].keys.push(keyData); - if (!actionMap[action].desc && bind.desc) - actionMap[action].desc = bind.desc; - if (!actionMap[action].conflict && bind.conflict) - actionMap[action].conflict = bind.conflict; - } else { - const entry = { - "category": category, - "action": action, - "desc": bind.desc || "", - "keys": [keyData], - "conflict": bind.conflict || null - }; - actionMap[action] = entry; - grouped.push(entry); - } - } - } - - const list = []; - for (const cat of sortedCats) { - list.push({ - "id": "cat:" + cat, - "type": "category", - "name": cat - }); - const binds = processed[cat]; - if (!binds) - continue; - for (const bind of binds) - list.push({ - "id": "bind:" + bind.key, - "type": "bind", - "key": bind.key, - "desc": bind.desc - }); - } - - _allBinds = processed; - _categories = sortedCats; - _flatCache = grouped; - displayList = list; - _dataVersion++; - bindsLoaded(); - if (_pendingSavedKey) { - bindSaved(_pendingSavedKey); - _pendingSavedKey = ""; - } - } - - function getCategories() { - return _categories; - } - - function getFlatBinds() { - return _flatCache; - } - - function saveBind(originalKey, bindData) { - if (!bindData.key || !Actions.isValidAction(bindData.action)) - return; - saving = true; - const cmd = ["dms", "keybinds", "set", currentProvider, bindData.key, bindData.action, "--desc", bindData.desc || ""]; - if (originalKey && originalKey !== bindData.key) - cmd.push("--replace-key", originalKey); - if (bindData.cooldownMs > 0) - cmd.push("--cooldown-ms", String(bindData.cooldownMs)); - if (bindData.allowWhenLocked) - cmd.push("--allow-when-locked"); - if (bindData.repeat === false) - cmd.push("--no-repeat"); - if (bindData.allowInhibiting === false) - cmd.push("--no-inhibiting"); - if (bindData.flags) - cmd.push("--flags", bindData.flags); - saveProcess.command = cmd; - saveProcess.running = true; - _pendingSavedKey = bindData.key; - } - - function removeBind(key) { - if (!key) - return; - removeProcess.command = ["dms", "keybinds", "remove", currentProvider, key]; - removeProcess.running = true; - bindRemoved(key); - } - - function isDmsAction(action) { - return Actions.isDmsAction(action); - } - - function isValidAction(action) { - return Actions.isValidAction(action); - } - - function getActionType(action) { - return Actions.getActionType(action); - } - - function getActionLabel(action) { - return Actions.getActionLabel(action, currentProvider); - } - - function getCompositorCategories() { - return Actions.getCompositorCategories(currentProvider); - } - - function getCompositorActions(category) { - return Actions.getCompositorActions(currentProvider, category); - } - - function getDmsActions() { - return Actions.getDmsActions(CompositorService.isNiri, CompositorService.isHyprland); - } - - function buildSpawnAction(command, args) { - return Actions.buildSpawnAction(command, args); - } - - function buildShellAction(shellCmd, shell) { - return Actions.buildShellAction(currentProvider, shellCmd, shell); - } - - function getShellFromAction(action) { - return Actions.getShellFromAction(action); - } - - function parseSpawnCommand(action) { - return Actions.parseSpawnCommand(action); - } - - function parseShellCommand(action) { - return Actions.parseShellCommand(action); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml deleted file mode 100644 index 97d8745..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml +++ /dev/null @@ -1,987 +0,0 @@ -pragma Singleton - -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool isActive: false - property string networkStatus: "disconnected" - property string primaryConnection: "" - - property string ethernetIP: "" - property string ethernetInterface: "" - property bool ethernetConnected: false - property string ethernetConnectionUuid: "" - - property var wiredConnections: [] - - property string wifiIP: "" - property string wifiInterface: "" - property bool wifiConnected: false - property bool wifiEnabled: true - property string wifiConnectionUuid: "" - property string wifiDevicePath: "" - property string activeAccessPointPath: "" - - property string currentWifiSSID: "" - property int wifiSignalStrength: 0 - property var wifiNetworks: [] - property var savedConnections: [] - property var ssidToConnectionName: { - - } - property var wifiSignalIcon: { - if (!wifiConnected || networkStatus !== "wifi") { - return "wifi_off" - } - if (wifiSignalStrength >= 50) { - return "wifi" - } - if (wifiSignalStrength >= 25) { - return "wifi_2_bar" - } - return "wifi_1_bar" - } - - property string userPreference: "auto" // "auto", "wifi", "ethernet" - property bool isConnecting: false - property string connectingSSID: "" - property string connectionError: "" - - property bool isScanning: false - property bool wifiAvailable: true - property bool wifiToggling: false - property bool changingPreference: false - property string targetPreference: "" - property var savedWifiNetworks: [] - property string connectionStatus: "" - property string lastConnectionError: "" - property bool passwordDialogShouldReopen: false - property string wifiPassword: "" - property string forgetSSID: "" - - readonly property var lowPriorityCmd: ["nice", "-n", "19", "ionice", "-c3"] - - property string networkInfoSSID: "" - property string networkInfoDetails: "" - property bool networkInfoLoading: false - - property string networkWiredInfoUUID: "" - property string networkWiredInfoDetails: "" - property bool networkWiredInfoLoading: false - - signal networksUpdated - signal connectionChanged - - function splitNmcliFields(line) { - const parts = [] - let cur = "" - let escape = false - for (var i = 0; i < line.length; i++) { - const ch = line[i] - if (escape) { - cur += ch - escape = false - } else if (ch === '\\') { - escape = true - } else if (ch === ':') { - parts.push(cur) - cur = "" - } else { - cur += ch - } - } - parts.push(cur) - return parts - } - - Component.onCompleted: { - root.userPreference = SettingsData.networkPreference - } - - function activate() { - if (!isActive) { - isActive = true - console.info("LegacyNetworkService: Activating...") - doRefreshNetworkState() - } - } - - - function doRefreshNetworkState() { - updatePrimaryConnection() - updateDeviceStates() - updateActiveConnections() - updateWifiState() - } - - function updatePrimaryConnection() { - primaryConnectionQuery.running = true - } - - Process { - id: primaryConnectionQuery - command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "PrimaryConnection"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/objectpath '([^']+)'/) - if (match && match[1] !== '/') { - root.primaryConnection = match[1] - getPrimaryConnectionType.running = true - } else { - root.primaryConnection = "" - root.networkStatus = "disconnected" - } - } - } - } - - Process { - id: getPrimaryConnectionType - command: root.primaryConnection ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.primaryConnection, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Connection.Active", "Type"]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("802-3-ethernet")) { - root.networkStatus = "ethernet" - } else if (text.includes("802-11-wireless")) { - root.networkStatus = "wifi" - } - root.connectionChanged() - } - } - } - - function updateDeviceStates() { - getEthernetDevice.running = true - getWifiDevice.running = true - } - - Process { - id: getEthernetDevice - command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const lines = text.trim().split('\n') - let ethernetInterface = "" - - for (const line of lines) { - const splitParts = line.split(':') - const device = splitParts[0] - const type = splitParts.length > 1 ? splitParts[1] : "" - if (type === "ethernet") { - ethernetInterface = device - break - } - } - - if (ethernetInterface) { - root.ethernetInterface = ethernetInterface - getEthernetDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", ethernetInterface]) - getEthernetDevicePath.running = true - } else { - root.ethernetInterface = "" - root.ethernetConnected = false - } - } - } - } - - Process { - id: getEthernetDevicePath - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/objectpath '([^']+)'/) - if (match && match[1] !== '/') { - checkEthernetState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"]) - checkEthernetState.running = true - } else { - root.ethernetInterface = "" - root.ethernetConnected = false - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.ethernetInterface = "" - root.ethernetConnected = false - } - } - } - - Process { - id: checkEthernetState - running: false - - stdout: StdioCollector { - onStreamFinished: { - const isConnected = text.includes("uint32 100") - root.ethernetConnected = isConnected - if (isConnected) { - getEthernetIP.running = true - } else { - root.ethernetIP = "" - } - } - } - } - - Process { - id: getEthernetIP - command: root.ethernetInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.ethernetInterface]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/) - if (match) { - root.ethernetIP = match[1] - } - } - } - } - - Process { - id: getWifiDevice - command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const lines = text.trim().split('\n') - let wifiInterface = "" - - for (const line of lines) { - const splitParts = line.split(':') - const device = splitParts[0] - const type = splitParts.length > 1 ? splitParts[1] : "" - if (type === "wifi") { - wifiInterface = device - break - } - } - - if (wifiInterface) { - root.wifiInterface = wifiInterface - getWifiDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", wifiInterface]) - getWifiDevicePath.running = true - } else { - root.wifiInterface = "" - root.wifiConnected = false - } - } - } - } - - Process { - id: getWifiDevicePath - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/objectpath '([^']+)'/) - if (match && match[1] !== '/') { - root.wifiDevicePath = match[1] - checkWifiState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"]) - checkWifiState.running = true - } else { - root.wifiInterface = "" - root.wifiConnected = false - root.wifiDevicePath = "" - root.activeAccessPointPath = "" - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.wifiInterface = "" - root.wifiConnected = false - } - } - } - - Process { - id: checkWifiState - running: false - - stdout: StdioCollector { - onStreamFinished: { - root.wifiConnected = text.includes("uint32 100") - if (root.wifiConnected) { - getWifiIP.running = true - getCurrentWifiInfo.running = true - getActiveAccessPoint.running = true - if (root.currentWifiSSID === "") { - if (root.wifiConnectionUuid) { - resolveWifiSSID.running = true - } - if (root.wifiInterface) { - resolveWifiSSIDFromDevice.running = true - } - } - } else { - root.wifiIP = "" - root.currentWifiSSID = "" - root.wifiSignalStrength = 0 - root.activeAccessPointPath = "" - } - } - } - } - - Process { - id: getWifiIP - command: root.wifiInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.wifiInterface]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/) - if (match) { - root.wifiIP = match[1] - } - } - } - } - - Process { - id: getActiveAccessPoint - command: root.wifiDevicePath ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.wifiDevicePath, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint"]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const match = text.match(/objectpath '([^']+)'/) - if (match && match[1] !== '/') { - root.activeAccessPointPath = match[1] - } else { - root.activeAccessPointPath = "" - } - } - } - } - - Process { - id: getCurrentWifiInfo - command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "ACTIVE,SIGNAL,SSID", "device", "wifi", "list", "ifname", root.wifiInterface, "--rescan", "no"]) : [] - running: false - - stdout: SplitParser { - splitMarker: "\n" - onRead: line => { - if (line.startsWith("yes:")) { - const rest = line.substring(4) - const parts = root.splitNmcliFields(rest) - if (parts.length >= 2) { - const signal = parseInt(parts[0]) - console.log("Current WiFi signal strength:", signal) - root.wifiSignalStrength = isNaN(signal) ? 0 : signal - root.currentWifiSSID = parts[1] - console.log("Current WiFi SSID:", root.currentWifiSSID) - } - return - } - } - } - } - - function updateActiveConnections() { - getActiveConnections.running = true - } - - Process { - id: getActiveConnections - command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "UUID,TYPE,DEVICE,STATE", "connection", "show", "--active"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const lines = text.trim().split('\n') - for (const line of lines) { - const parts = line.split(':') - if (parts.length >= 4) { - const uuid = parts[0] - const type = parts[1] - const device = parts[2] - const state = parts[3] - if (type === "802-3-ethernet" && state === "activated") { - root.ethernetConnectionUuid = uuid - } else if (type === "802-11-wireless" && state === "activated") { - root.wifiConnectionUuid = uuid - } - } - } - } - } - } - - // Resolve SSID from active WiFi connection UUID when scans don't mark any row as ACTIVE. - Process { - id: resolveWifiSSID - command: root.wifiConnectionUuid ? lowPriorityCmd.concat(["nmcli", "-g", "802-11-wireless.ssid", "connection", "show", "uuid", root.wifiConnectionUuid]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const ssid = text.trim() - if (ssid) { - root.currentWifiSSID = ssid - } - } - } - } - - // Fallback 2: Resolve SSID from device info (GENERAL.CONNECTION usually matches SSID for WiFi) - Process { - id: resolveWifiSSIDFromDevice - command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "GENERAL.CONNECTION", "device", "show", root.wifiInterface]) : [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (!root.currentWifiSSID) { - const name = text.trim() - if (name) { - root.currentWifiSSID = name - } - } - } - } - } - - function updateWifiState() { - checkWifiEnabled.running = true - } - - Process { - id: checkWifiEnabled - command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "WirelessEnabled"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - root.wifiEnabled = text.includes("true") - root.wifiAvailable = true // Always available if we can check it - } - } - } - - function scanWifi() { - if (root.isScanning || !root.wifiEnabled) { - return - } - - root.isScanning = true - requestWifiScan.running = true - } - - Process { - id: requestWifiScan - command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "dev", "wifi", "rescan", "ifname", root.wifiInterface]) : [] - running: false - - onExited: exitCode => { - if (exitCode === 0) { - scanWifiNetworks() - } else { - console.warn("WiFi scan request failed") - root.isScanning = false - } - } - } - - function scanWifiNetworks() { - if (!root.wifiInterface) { - root.isScanning = false - return - } - - getWifiNetworks.running = true - getSavedConnections.running = true - } - - Process { - id: getWifiNetworks - command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,BSSID", "dev", "wifi", "list", "ifname", root.wifiInterface]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const networks = [] - const lines = text.trim().split('\n') - const seen = new Set() - - for (const line of lines) { - const parts = root.splitNmcliFields(line) - if (parts.length >= 4 && parts[0]) { - const ssid = parts[0] - if (!seen.has(ssid)) { - seen.add(ssid) - const signal = parseInt(parts[1]) || 0 - - networks.push({ - "ssid": ssid, - "signal": signal, - "secured": parts[2] !== "", - "bssid": parts[3], - "connected": ssid === root.currentWifiSSID, - "saved": false - }) - } - } - } - - networks.sort((a, b) => b.signal - a.signal) - root.wifiNetworks = networks - root.isScanning = false - root.networksUpdated() - } - } - } - - Process { - id: getSavedConnections - command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep ':802-11-wireless$' | cut -d: -f1 | while read name; do ssid=$(nmcli -g 802-11-wireless.ssid connection show \"$name\"); echo \"$ssid:$name\"; done"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - const saved = [] - const mapping = {} - const lines = text.trim().split('\n') - - for (const line of lines) { - const parts = line.trim().split(':') - if (parts.length >= 2) { - const ssid = parts[0] - const connectionName = parts[1] - if (ssid && ssid.length > 0 && connectionName && connectionName.length > 0) { - saved.push({ - "ssid": ssid, - "saved": true - }) - mapping[ssid] = connectionName - } - } - } - - root.savedConnections = saved - root.savedWifiNetworks = saved - root.ssidToConnectionName = mapping - - const updated = [...root.wifiNetworks] - for (const network of updated) { - network.saved = saved.some(s => s.ssid === network.ssid) - } - root.wifiNetworks = updated - } - } - } - - function connectToWifi(ssid, password = "", username = "") { - if (root.isConnecting) { - return - } - - root.isConnecting = true - root.connectingSSID = ssid - root.connectionError = "" - root.connectionStatus = "connecting" - - if (!password && root.ssidToConnectionName[ssid]) { - const connectionName = root.ssidToConnectionName[ssid] - wifiConnector.command = lowPriorityCmd.concat(["nmcli", "connection", "up", connectionName]) - } else if (password) { - wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid, "password", password]) - } else { - wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid]) - } - wifiConnector.running = true - } - - Process { - id: wifiConnector - running: false - - property bool connectionSucceeded: false - - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("successfully")) { - wifiConnector.connectionSucceeded = true - ToastService.showInfo(`Connected to ${root.connectingSSID}`) - root.connectionError = "" - root.connectionStatus = "connected" - - if (root.userPreference === "wifi" || root.userPreference === "auto") { - setConnectionPriority("wifi") - } - } - } - } - - stderr: StdioCollector { - onStreamFinished: { - root.connectionError = text - root.lastConnectionError = text - if (!wifiConnector.connectionSucceeded && text.trim() !== "") { - if (text.includes("password") || text.includes("authentication")) { - root.connectionStatus = "invalid_password" - root.passwordDialogShouldReopen = true - } else { - root.connectionStatus = "failed" - } - } - } - } - - onExited: exitCode => { - if (exitCode === 0 || wifiConnector.connectionSucceeded) { - if (!wifiConnector.connectionSucceeded) { - ToastService.showInfo(`Connected to ${root.connectingSSID}`) - root.connectionStatus = "connected" - } - } else { - if (root.connectionStatus === "") { - root.connectionStatus = "failed" - } - if (root.connectionStatus === "invalid_password") { - ToastService.showError(`Invalid password for ${root.connectingSSID}`) - } else { - ToastService.showError(`Failed to connect to ${root.connectingSSID}`) - } - } - - wifiConnector.connectionSucceeded = false - root.isConnecting = false - root.connectingSSID = "" - doRefreshNetworkState() - } - } - - function disconnectWifi() { - if (!root.wifiInterface) { - return - } - - wifiDisconnector.command = lowPriorityCmd.concat(["nmcli", "dev", "disconnect", root.wifiInterface]) - wifiDisconnector.running = true - } - - Process { - id: wifiDisconnector - running: false - - onExited: exitCode => { - if (exitCode === 0) { - ToastService.showInfo("Disconnected from WiFi") - root.currentWifiSSID = "" - root.connectionStatus = "" - } - doRefreshNetworkState() - } - } - - function forgetWifiNetwork(ssid) { - root.forgetSSID = ssid - const connectionName = root.ssidToConnectionName[ssid] || ssid - networkForgetter.command = lowPriorityCmd.concat(["nmcli", "connection", "delete", connectionName]) - networkForgetter.running = true - } - - Process { - id: networkForgetter - running: false - - onExited: exitCode => { - if (exitCode === 0) { - ToastService.showInfo(`Forgot network ${root.forgetSSID}`) - - root.savedConnections = root.savedConnections.filter(s => s.ssid !== root.forgetSSID) - root.savedWifiNetworks = root.savedWifiNetworks.filter(s => s.ssid !== root.forgetSSID) - - const updated = [...root.wifiNetworks] - for (const network of updated) { - if (network.ssid === root.forgetSSID) { - network.saved = false - if (network.connected) { - network.connected = false - root.currentWifiSSID = "" - } - } - } - root.wifiNetworks = updated - root.networksUpdated() - doRefreshNetworkState() - } - root.forgetSSID = "" - } - } - - function toggleWifiRadio() { - if (root.wifiToggling) { - return - } - - root.wifiToggling = true - const targetState = root.wifiEnabled ? "off" : "on" - wifiRadioToggler.targetState = targetState - wifiRadioToggler.command = lowPriorityCmd.concat(["nmcli", "radio", "wifi", targetState]) - wifiRadioToggler.running = true - } - - Process { - id: wifiRadioToggler - running: false - - property string targetState: "" - - onExited: exitCode => { - root.wifiToggling = false - if (exitCode === 0) { - ToastService.showInfo(targetState === "on" ? "WiFi enabled" : "WiFi disabled") - } - doRefreshNetworkState() - } - } - - function setNetworkPreference(preference) { - root.userPreference = preference - root.changingPreference = true - root.targetPreference = preference - SettingsData.set("networkPreference", preference) - - if (preference === "wifi") { - setConnectionPriority("wifi") - } else if (preference === "ethernet") { - setConnectionPriority("ethernet") - } - } - - function setConnectionPriority(type) { - if (type === "wifi") { - setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"]) - } else if (type === "ethernet") { - setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"]) - } - setRouteMetrics.running = true - } - - Process { - id: setRouteMetrics - running: false - - onExited: exitCode => { - console.log("Set route metrics process exited with code:", exitCode) - if (exitCode === 0) { - restartConnections.running = true - } - } - } - - Process { - id: restartConnections - command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f UUID,TYPE connection show --active | " + "grep -E '802-11-wireless|802-3-ethernet' | cut -d: -f1 | " + "xargs -I {} sh -c 'nmcli connection down {} && nmcli connection up {}'"]) - running: false - - onExited: { - root.changingPreference = false - root.targetPreference = "" - doRefreshNetworkState() - } - } - - - function fetchNetworkInfo(ssid) { - root.networkInfoSSID = ssid - root.networkInfoLoading = true - root.networkInfoDetails = "Loading network information..." - wifiInfoFetcher.running = true - } - - Process { - id: wifiInfoFetcher - command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,FREQ,RATE,MODE,CHAN,WPA-FLAGS,RSN-FLAGS,ACTIVE,BSSID", "dev", "wifi", "list"]) - running: false - - stdout: StdioCollector { - onStreamFinished: { - let details = "" - if (text.trim()) { - const lines = text.trim().split('\n') - const bands = [] - - for (const line of lines) { - const parts = line.split(':') - if (parts.length >= 11 && parts[0] === root.networkInfoSSID) { - const signal = parts[1] || "0" - const security = parts[2] || "Open" - const freq = parts[3] || "Unknown" - const rate = parts[4] || "Unknown" - const channel = parts[6] || "Unknown" - const isActive = parts[9] === "yes" - let colonCount = 0 - let bssidStart = -1 - for (var i = 0; i < line.length; i++) { - if (line[i] === ':') { - colonCount++ - if (colonCount === 10) { - bssidStart = i + 1 - break - } - } - } - const bssid = bssidStart >= 0 ? line.substring(bssidStart).replace(/\\:/g, ":") : "" - - let band = "Unknown" - const freqNum = parseInt(freq) - if (freqNum >= 2400 && freqNum <= 2500) { - band = "2.4 GHz" - } else if (freqNum >= 5000 && freqNum <= 6000) { - band = "5 GHz" - } else if (freqNum >= 6000) { - band = "6 GHz" - } - - bands.push({ - "band": band, - "freq": freq, - "channel": channel, - "signal": signal, - "rate": rate, - "security": security, - "isActive": isActive, - "bssid": bssid - }) - } - } - - if (bands.length > 0) { - bands.sort((a, b) => { - if (a.isActive && !b.isActive) { - return -1 - } - if (!a.isActive && b.isActive) { - return 1 - } - return parseInt(b.signal) - parseInt(a.signal) - }) - - for (var i = 0; i < bands.length; i++) { - const b = bands[i] - if (b.isActive) { - details += "● " + b.band + " (Connected) - " + b.signal + "%\\n" - } else { - details += " " + b.band + " - " + b.signal + "%\\n" - } - details += " Channel " + b.channel + " (" + b.freq + " MHz) • " + b.rate + " Mbit/s\\n" - details += " " + b.bssid - if (i < bands.length - 1) { - details += "\\n\\n" - } - } - } - } - - if (details === "") { - details = "Network information not found or network not available." - } - - root.networkInfoDetails = details - root.networkInfoLoading = false - } - } - - onExited: exitCode => { - root.networkInfoLoading = false - if (exitCode !== 0) { - root.networkInfoDetails = "Failed to fetch network information" - } - } - } - - function enableWifiDevice() { - wifiDeviceEnabler.running = true - } - - Process { - id: wifiDeviceEnabler - command: lowPriorityCmd.concat(["sh", "-c", "WIFI_DEV=$(nmcli -t -f DEVICE,TYPE device | grep wifi | cut -d: -f1 | head -1); if [ -n \"$WIFI_DEV\" ]; then nmcli device connect \"$WIFI_DEV\"; else echo \"No WiFi device found\"; exit 1; fi"]) - running: false - - onExited: exitCode => { - if (exitCode === 0) { - ToastService.showInfo("WiFi enabled") - } else { - ToastService.showError("Failed to enable WiFi") - } - doRefreshNetworkState() - } - } - - function connectToWifiAndSetPreference(ssid, password) { - connectToWifi(ssid, password) - setNetworkPreference("wifi") - } - - function toggleNetworkConnection(type) { - if (type === "ethernet") { - if (root.networkStatus === "ethernet") { - ethernetDisconnector.running = true - } else { - ethernetConnector.running = true - } - } - } - - Process { - id: ethernetDisconnector - command: lowPriorityCmd.concat(["sh", "-c", "nmcli device disconnect $(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1)"]) - running: false - - onExited: function (exitCode) { - doRefreshNetworkState() - } - } - - Process { - id: ethernetConnector - command: lowPriorityCmd.concat(["sh", "-c", "ETH_DEV=$(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1); if [ -n \"$ETH_DEV\" ]; then nmcli device connect \"$ETH_DEV\"; else echo \"No ethernet device found\"; exit 1; fi"]) - running: false - - onExited: function (exitCode) { - doRefreshNetworkState() - } - } - - function getNetworkInfo(ssid) { - const network = root.wifiNetworks.find(n => n.ssid === ssid) - if (!network) { - return null - } - - return { - "ssid": network.ssid, - "signal": network.signal, - "secured": network.secured, - "saved": network.saved, - "connected": network.connected, - "bssid": network.bssid - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml deleted file mode 100644 index 0fde587..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml +++ /dev/null @@ -1,55 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property bool locationAvailable: DMSService.isConnected && (DMSService.capabilities.length === 0 || DMSService.capabilities.includes("location")) - readonly property bool valid: latitude !== 0 || longitude !== 0 - - property var latitude: 0.0 - property var longitude: 0.0 - - signal locationChanged(var data) - - onLocationAvailableChanged: { - if (locationAvailable && !valid) - getState(); - } - - Connections { - target: DMSService - - function onLocationStateUpdate(data) { - if (!locationAvailable) - return; - handleStateUpdate(data); - } - } - - function handleStateUpdate(data) { - const lat = data.latitude; - const lon = data.longitude; - if (lat === 0 && lon === 0) - return; - - root.latitude = lat; - root.longitude = lon; - root.locationChanged(data); - } - - function getState() { - if (!locationAvailable) - return; - - DMSService.sendRequest("location.getState", null, response => { - if (response.result) - handleStateUpdate(response.result); - }); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml deleted file mode 100644 index 44ad135..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml +++ /dev/null @@ -1,78 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Services.Mpris -import qs.Common - -Singleton { - id: root - - readonly property list availablePlayers: Mpris.players.values - property MprisPlayer activePlayer: null - - onAvailablePlayersChanged: _resolveActivePlayer() - Component.onCompleted: _resolveActivePlayer() - - Instantiator { - model: root.availablePlayers - delegate: Connections { - required property MprisPlayer modelData - target: modelData - function onIsPlayingChanged() { - if (modelData.isPlaying) - root._resolveActivePlayer(); - } - } - } - - function _resolveActivePlayer(): void { - const playing = availablePlayers.find(p => p.isPlaying); - if (playing) { - activePlayer = playing; - _persistIdentity(playing.identity); - return; - } - if (activePlayer && availablePlayers.indexOf(activePlayer) >= 0) - return; - const savedId = SessionData.lastPlayerIdentity; - if (savedId) { - const match = availablePlayers.find(p => p.identity === savedId); - if (match) { - activePlayer = match; - return; - } - } - activePlayer = availablePlayers.find(p => p.canControl && p.canPlay) ?? null; - if (activePlayer) - _persistIdentity(activePlayer.identity); - } - - function setActivePlayer(player: MprisPlayer): void { - activePlayer = player; - if (player) - _persistIdentity(player.identity); - } - - function _persistIdentity(identity: string): void { - if (identity && SessionData.lastPlayerIdentity !== identity) - SessionData.set("lastPlayerIdentity", identity); - } - - Timer { - interval: 1000 - running: root.activePlayer?.playbackState === MprisPlaybackState.Playing - repeat: true - onTriggered: root.activePlayer?.positionChanged() - } - - function previousOrRewind(): void { - if (!activePlayer) - return; - if (activePlayer.position > 8 && activePlayer.canSeek) - activePlayer.position = 0; - else if (activePlayer.canGoPrevious) - activePlayer.previous(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml deleted file mode 100644 index f570c72..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml +++ /dev/null @@ -1,35 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - property bool available: false - - function detectAvailability() { - try { - const testObj = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - Item {} - `, root, "MultimediaService.TestComponent"); - if (testObj) { - testObj.destroy(); - } - available = true; - return true; - } catch (e) { - available = false; - return false; - } - } - - Component.onCompleted: { - if (!detectAvailability()) { - console.warn("MultimediaService: QtMultimedia not available"); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml deleted file mode 100644 index c2f941c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml +++ /dev/null @@ -1,230 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property var sessions: [] - property bool loading: false - - property bool tmuxAvailable: false - property bool zellijAvailable: false - readonly property bool currentMuxAvailable: muxType === "zellij" ? zellijAvailable : tmuxAvailable - - readonly property string muxType: SettingsData.muxType - readonly property string displayName: muxType === "zellij" ? "Zellij" : "Tmux" - - readonly property var terminalFlags: ({ - "ghostty": ["-e"], - "kitty": ["-e"], - "alacritty": ["-e"], - "foot": [], - "wezterm": ["start", "--"], - "gnome-terminal": ["--"], - "xterm": ["-e"], - "konsole": ["-e"], - "st": ["-e"], - "terminator": ["-e"], - "xfce4-terminal": ["-e"] - }) - - function getTerminalFlag(terminal) { - return terminalFlags[terminal] ?? ["-e"] - } - - readonly property string terminal: Quickshell.env("TERMINAL") || "ghostty" - - function _terminalPrefix() { - return [terminal].concat(getTerminalFlag(terminal)) - } - - Process { - id: tmuxCheckProcess - command: ["which", "tmux"] - running: false - onExited: (code) => { root.tmuxAvailable = (code === 0) } - } - - Process { - id: zellijCheckProcess - command: ["which", "zellij"] - running: false - onExited: (code) => { root.zellijAvailable = (code === 0) } - } - - function checkAvailability() { - tmuxCheckProcess.running = true - zellijCheckProcess.running = true - } - - Component.onCompleted: checkAvailability() - - Process { - id: listProcess - running: false - - stdout: StdioCollector { - onStreamFinished: { - try { - if (root.muxType === "zellij") - root._parseZellijSessions(text) - else - root._parseTmuxSessions(text) - } catch (e) { - console.error("[MuxService] Error parsing sessions:", e) - root.sessions = [] - } - root.loading = false - } - } - - stderr: SplitParser { - onRead: (line) => { - if (line.trim()) - console.error("[MuxService] stderr:", line) - } - } - - onExited: (code) => { - if (code !== 0 && code !== 1) { - console.warn("[MuxService] Process exited with code:", code) - root.sessions = [] - } - root.loading = false - } - } - - function refreshSessions() { - if (!root.currentMuxAvailable) { - root.sessions = [] - return - } - - root.loading = true - - if (listProcess.running) - listProcess.running = false - - if (root.muxType === "zellij") - listProcess.command = ["zellij", "list-sessions", "--no-formatting"] - else - listProcess.command = ["tmux", "list-sessions", "-F", "#{session_name}|#{session_windows}|#{session_attached}"] - - Qt.callLater(function () { - listProcess.running = true - }) - } - - function _isSessionExcluded(name) { - var filter = SettingsData.muxSessionFilter.trim() - if (filter.length === 0) - return false - var parts = filter.split(",") - for (var i = 0; i < parts.length; i++) { - var pattern = parts[i].trim() - if (pattern.length === 0) - continue - if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) { - try { - var re = new RegExp(pattern.slice(1, -1)) - if (re.test(name)) - return true - } catch (e) {} - } else { - if (name.toLowerCase() === pattern.toLowerCase()) - return true - } - } - return false - } - - function _parseTmuxSessions(output) { - var sessionList = [] - var lines = output.trim().split('\n') - - for (var i = 0; i < lines.length; i++) { - var line = lines[i].trim() - if (line.length === 0) - continue - - var parts = line.split('|') - if (parts.length >= 3 && !_isSessionExcluded(parts[0])) { - sessionList.push({ - name: parts[0], - windows: parts[1], - attached: parts[2] === "1" - }) - } - } - - root.sessions = sessionList - } - - function _parseZellijSessions(output) { - var sessionList = [] - var lines = output.trim().split('\n') - - for (var i = 0; i < lines.length; i++) { - var line = lines[i].trim() - if (line.length === 0) - continue - - var exited = line.includes("(EXITED") - var bracketIdx = line.indexOf(" [") - var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim() - - if (!_isSessionExcluded(name)) { - sessionList.push({ - name: name, - windows: "N/A", - attached: !exited - }) - } - } - - root.sessions = sessionList - } - - function attachToSession(name) { - if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) { - Quickshell.execDetached([SettingsData.muxCustomCommand, name]) - } else if (root.muxType === "zellij") { - Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name])) - } else { - Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name])) - } - } - - function createSession(name) { - if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) { - Quickshell.execDetached([SettingsData.muxCustomCommand, name]) - } else if (root.muxType === "zellij") { - Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name])) - } else { - Quickshell.execDetached(_terminalPrefix().concat(["tmux", "new-session", "-s", name])) - } - } - - readonly property bool supportsRename: muxType !== "zellij" - - function renameSession(oldName, newName) { - if (root.muxType === "zellij") - return - Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName]) - Qt.callLater(refreshSessions) - } - - function killSession(name) { - if (root.muxType === "zellij") { - Quickshell.execDetached(["zellij", "kill-session", name]) - } else { - Quickshell.execDetached(["tmux", "kill-session", "-t", name]) - } - Qt.callLater(refreshSessions) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml deleted file mode 100644 index 38383d2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml +++ /dev/null @@ -1,313 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - property bool networkAvailable: activeService !== null - property string backend: activeService?.backend ?? "" - property string networkStatus: activeService?.networkStatus ?? "disconnected" - property string primaryConnection: activeService?.primaryConnection ?? "" - - property string ethernetIP: activeService?.ethernetIP ?? "" - property string ethernetInterface: activeService?.ethernetInterface ?? "" - property bool ethernetConnected: activeService?.ethernetConnected ?? false - property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? "" - property var ethernetDevices: activeService?.ethernetDevices ?? [] - - property var wiredConnections: activeService?.wiredConnections ?? [] - - property string wifiIP: activeService?.wifiIP ?? "" - property string wifiInterface: activeService?.wifiInterface ?? "" - property bool wifiConnected: activeService?.wifiConnected ?? false - property bool wifiEnabled: activeService?.wifiEnabled ?? true - property string wifiConnectionUuid: activeService?.wifiConnectionUuid ?? "" - property string wifiDevicePath: activeService?.wifiDevicePath ?? "" - property string activeAccessPointPath: activeService?.activeAccessPointPath ?? "" - property var wifiDevices: activeService?.wifiDevices ?? [] - property string wifiDeviceOverride: activeService?.wifiDeviceOverride ?? "" - property string connectingDevice: activeService?.connectingDevice ?? "" - - property string currentWifiSSID: activeService?.currentWifiSSID ?? "" - property int wifiSignalStrength: activeService?.wifiSignalStrength ?? 0 - property var wifiNetworks: activeService?.wifiNetworks ?? [] - property var savedConnections: activeService?.savedConnections ?? [] - property var ssidToConnectionName: activeService?.ssidToConnectionName ?? ({}) - property var wifiSignalIcon: activeService?.wifiSignalIcon ?? "wifi_off" - - property string userPreference: activeService?.userPreference ?? "auto" - property bool isConnecting: activeService?.isConnecting ?? false - property string connectingSSID: activeService?.connectingSSID ?? "" - property string connectionError: activeService?.connectionError ?? "" - - property bool isScanning: activeService?.isScanning ?? false - property bool autoScan: activeService?.autoScan ?? false - - property bool wifiAvailable: activeService?.wifiAvailable ?? true - property bool wifiToggling: activeService?.wifiToggling ?? false - property bool changingPreference: activeService?.changingPreference ?? false - property string targetPreference: activeService?.targetPreference ?? "" - property var savedWifiNetworks: activeService?.savedWifiNetworks ?? [] - property string connectionStatus: activeService?.connectionStatus ?? "" - property string lastConnectionError: activeService?.lastConnectionError ?? "" - property bool passwordDialogShouldReopen: activeService?.passwordDialogShouldReopen ?? false - property bool autoRefreshEnabled: activeService?.autoRefreshEnabled ?? false - property string wifiPassword: activeService?.wifiPassword ?? "" - property string forgetSSID: activeService?.forgetSSID ?? "" - - property string networkInfoSSID: activeService?.networkInfoSSID ?? "" - property string networkInfoDetails: activeService?.networkInfoDetails ?? "" - property bool networkInfoLoading: activeService?.networkInfoLoading ?? false - - property string networkWiredInfoUUID: activeService?.networkWiredInfoUUID ?? "" - property string networkWiredInfoDetails: activeService?.networkWiredInfoDetails ?? "" - property bool networkWiredInfoLoading: activeService?.networkWiredInfoLoading ?? false - - property int refCount: activeService?.refCount ?? 0 - property bool stateInitialized: activeService?.stateInitialized ?? false - - property bool subscriptionConnected: activeService?.subscriptionConnected ?? false - - property var vpnProfiles: activeService?.vpnProfiles ?? [] - property var vpnActive: activeService?.vpnActive ?? [] - property bool vpnAvailable: activeService?.vpnAvailable ?? false - property bool vpnIsBusy: activeService?.vpnIsBusy ?? false - property bool vpnConnected: activeService?.vpnConnected ?? false - property string vpnActiveUuid: activeService?.activeUuid ?? "" - property string vpnActiveName: activeService?.activeName ?? "" - - property string credentialsToken: activeService?.credentialsToken ?? "" - property string credentialsSSID: activeService?.credentialsSSID ?? "" - property string credentialsSetting: activeService?.credentialsSetting ?? "" - property var credentialsFields: activeService?.credentialsFields ?? [] - property var credentialsHints: activeService?.credentialsHints ?? [] - property string credentialsReason: activeService?.credentialsReason ?? "" - property bool credentialsRequested: activeService?.credentialsRequested ?? false - - signal networksUpdated - signal connectionChanged - signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo) - - property bool usingLegacy: false - property var activeService: null - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - Component.onCompleted: { - console.info("NetworkService: Initializing..."); - if (!socketPath || socketPath.length === 0) { - console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService"); - useLegacyService(); - } else { - console.log("NetworkService: DMS_SOCKET found, waiting for capabilities..."); - } - } - - Connections { - target: DMSNetworkService - - function onNetworkAvailableChanged() { - if (!activeService && DMSNetworkService.networkAvailable) { - console.info("NetworkService: Network capability detected, using DMSNetworkService"); - activeService = DMSNetworkService; - usingLegacy = false; - console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable); - connectSignals(); - } else if (!activeService && !DMSNetworkService.networkAvailable && socketPath && socketPath.length > 0) { - console.info("NetworkService: Network capability not available in DMS, using LegacyNetworkService"); - useLegacyService(); - } - } - } - - function useLegacyService() { - activeService = LegacyNetworkService; - usingLegacy = true; - console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable); - if (LegacyNetworkService.activate) { - LegacyNetworkService.activate(); - } - connectSignals(); - } - - function connectSignals() { - if (activeService) { - if (activeService.networksUpdated) { - activeService.networksUpdated.connect(root.networksUpdated); - } - if (activeService.connectionChanged) { - activeService.connectionChanged.connect(root.connectionChanged); - } - if (activeService.credentialsNeeded) { - activeService.credentialsNeeded.connect(root.credentialsNeeded); - } - } - } - - function addRef() { - if (activeService && activeService.addRef) { - activeService.addRef(); - } - } - - function removeRef() { - if (activeService && activeService.removeRef) { - activeService.removeRef(); - } - } - - function getState() { - if (activeService && activeService.getState) { - activeService.getState(); - } - } - - function scanWifi() { - if (activeService && activeService.scanWifi) { - activeService.scanWifi(); - } - } - - function scanWifiNetworks() { - if (activeService && activeService.scanWifiNetworks) { - activeService.scanWifiNetworks(); - } - } - - function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "") { - if (activeService && activeService.connectToWifi) { - activeService.connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch); - } - } - - function disconnectWifi() { - if (activeService && activeService.disconnectWifi) { - activeService.disconnectWifi(); - } - } - - function forgetWifiNetwork(ssid) { - if (activeService && activeService.forgetWifiNetwork) { - activeService.forgetWifiNetwork(ssid); - } - } - - function toggleWifiRadio() { - if (activeService && activeService.toggleWifiRadio) { - activeService.toggleWifiRadio(); - } - } - - function enableWifiDevice() { - if (activeService && activeService.enableWifiDevice) { - activeService.enableWifiDevice(); - } - } - - function setNetworkPreference(preference) { - if (activeService && activeService.setNetworkPreference) { - activeService.setNetworkPreference(preference); - } - } - - function setConnectionPriority(type) { - if (activeService && activeService.setConnectionPriority) { - activeService.setConnectionPriority(type); - } - } - - function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "") { - if (activeService && activeService.connectToWifiAndSetPreference) { - activeService.connectToWifiAndSetPreference(ssid, password, username, anonymousIdentity, domainSuffixMatch); - } - } - - function toggleNetworkConnection(type) { - if (activeService && activeService.toggleNetworkConnection) { - activeService.toggleNetworkConnection(type); - } - } - - function disconnectEthernetDevice(deviceName) { - if (activeService && activeService.disconnectEthernetDevice) { - activeService.disconnectEthernetDevice(deviceName); - } - } - - function startAutoScan() { - if (activeService && activeService.startAutoScan) { - activeService.startAutoScan(); - } - } - - function stopAutoScan() { - if (activeService && activeService.stopAutoScan) { - activeService.stopAutoScan(); - } - } - - function fetchNetworkInfo(ssid) { - if (activeService && activeService.fetchNetworkInfo) { - activeService.fetchNetworkInfo(ssid); - } - } - - function fetchWiredNetworkInfo(uuid) { - if (activeService && activeService.fetchWiredNetworkInfo) { - activeService.fetchWiredNetworkInfo(uuid); - } - } - - function getNetworkInfo(ssid) { - if (activeService && activeService.getNetworkInfo) { - return activeService.getNetworkInfo(ssid); - } - return null; - } - - function getWiredNetworkInfo(uuid) { - if (activeService && activeService.getWiredNetworkInfo) { - return activeService.getWiredNetworkInfo(uuid); - } - return null; - } - - function refreshNetworkState() { - if (activeService && activeService.refreshNetworkState) { - activeService.refreshNetworkState(); - } - } - - function connectToSpecificWiredConfig(uuid) { - if (activeService && activeService.connectToSpecificWiredConfig) { - activeService.connectToSpecificWiredConfig(uuid); - } - } - - function submitCredentials(token, secrets, save) { - if (activeService && activeService.submitCredentials) { - activeService.submitCredentials(token, secrets, save); - } - } - - function cancelCredentials(token) { - if (activeService && activeService.cancelCredentials) { - activeService.cancelCredentials(token); - } - } - - function setWifiAutoconnect(ssid, autoconnect) { - if (activeService && activeService.setWifiAutoconnect) { - activeService.setWifiAutoconnect(ssid, autoconnect); - } - } - - function setWifiDeviceOverride(deviceName) { - if (activeService && activeService.setWifiDeviceOverride) { - activeService.setWifiDeviceOverride(deviceName); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml deleted file mode 100644 index 49748eb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml +++ /dev/null @@ -1,1494 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - readonly property string socketPath: Quickshell.env("NIRI_SOCKET") - - property var workspaces: ({}) - property var allWorkspaces: [] - property int focusedWorkspaceIndex: 0 - property string focusedWorkspaceId: "" - property var currentOutputWorkspaces: [] - property string currentOutput: "" - - property var outputs: ({}) - property var windows: [] - property var displayScales: ({}) - - property var _realOutputs: ({}) - - property bool inOverview: false - - property var casts: [] - property bool hasCasts: casts.length > 0 - property bool hasActiveCast: casts.some(c => c.is_active) - - property int currentKeyboardLayoutIndex: 0 - property var keyboardLayoutNames: [] - - property string configValidationOutput: "" - property bool hasInitialConnection: false - property bool suppressConfigToast: true - property bool suppressNextConfigToast: false - property bool matugenSuppression: false - property bool configGenerationPending: false - - readonly property string screenshotsDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.PicturesLocation)) + "/Screenshots" - property string pendingScreenshotPath: "" - - signal windowUrgentChanged - signal configReloaded - - function setWorkspaces(newMap) { - root.workspaces = newMap; - root.allWorkspaces = Object.values(newMap).sort((a, b) => a.idx - b.idx); - } - - function validate() { - validateProcess.running = true; - } - - Component.onCompleted: fetchOutputs() - - Timer { - id: suppressToastTimer - interval: 3000 - onTriggered: root.suppressConfigToast = false - } - - Timer { - id: suppressResetTimer - interval: 5000 - onTriggered: root.matugenSuppression = false - } - - Timer { - id: configGenerationDebounce - interval: 100 - onTriggered: root.doGenerateNiriLayoutConfig() - } - - property int _lastGapValue: -1 - - Connections { - target: SettingsData - function onBarConfigsChanged() { - const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - if (newGaps === root._lastGapValue) - return; - root._lastGapValue = newGaps; - generateNiriLayoutConfig(); - } - } - - Process { - id: validateProcess - command: ["niri", "validate"] - running: false - - stderr: StdioCollector { - onStreamFinished: { - const lines = text.split('\n'); - const trimmedLines = lines.map(line => line.replace(/\s+$/, '')).filter(line => line.length > 0); - configValidationOutput = trimmedLines.join('\n').trim(); - } - } - - onExited: exitCode => { - if (exitCode === 0) { - configValidationOutput = ""; - } else if (hasInitialConnection && configValidationOutput.length > 0) { - ToastService.showError("niri: failed to load config", configValidationOutput, "", "niri-config"); - } - } - } - - Process { - id: writeConfigProcess - property string configContent: "" - property string configPath: "" - - onExited: exitCode => { - if (exitCode === 0) { - console.info("NiriService: Generated layout config at", configPath); - return; - } - console.warn("NiriService: Failed to write layout config, exit code:", exitCode); - } - } - - Process { - id: writeAlttabProcess - property string alttabContent: "" - property string alttabPath: "" - - onExited: exitCode => { - if (exitCode === 0) { - console.info("NiriService: Generated alttab config at", alttabPath); - return; - } - console.warn("NiriService: Failed to write alttab config, exit code:", exitCode); - } - } - - Process { - id: writeBlurruleProcess - property string blurrulePath: "" - - onExited: exitCode => { - if (exitCode === 0) { - console.info("NiriService: Generated wpblur config at", blurrulePath); - return; - } - console.warn("NiriService: Failed to write wpblur config, exit code:", exitCode); - } - } - - Process { - id: writeCursorProcess - property string cursorContent: "" - property string cursorPath: "" - - onExited: exitCode => { - if (exitCode === 0) { - console.info("NiriService: Generated cursor config at", cursorPath); - return; - } - console.warn("NiriService: Failed to write cursor config, exit code:", exitCode); - } - } - - DankSocket { - id: eventStreamSocket - path: root.socketPath - connected: CompositorService.isNiri - - onConnectionStateChanged: { - if (connected) { - send('"EventStream"'); - fetchOutputs(); - } - } - - parser: SplitParser { - onRead: line => { - try { - const event = JSON.parse(line); - handleNiriEvent(event); - } catch (e) { - console.warn("NiriService: Failed to parse event:", line, e); - } - } - } - } - - DankSocket { - id: requestSocket - path: root.socketPath - connected: CompositorService.isNiri - } - - function fetchOutputs() { - if (!CompositorService.isNiri) - return; - Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode); - return; - } - try { - const outputsData = JSON.parse(output); - outputs = outputsData; - console.info("NiriService: Loaded", Object.keys(outputsData).length, "outputs"); - updateDisplayScales(); - if (windows.length > 0) { - windows = sortWindowsByLayout(windows); - } - } catch (e) { - console.warn("NiriService: Failed to parse outputs:", e); - } - }); - } - - function updateDisplayScales() { - if (!outputs || Object.keys(outputs).length === 0) - return; - const scales = {}; - for (const outputName in outputs) { - const output = outputs[outputName]; - if (output.logical && output.logical.scale !== undefined) { - scales[outputName] = output.logical.scale; - } - } - - displayScales = scales; - } - - function sortWindowsByLayout(windowList) { - const enriched = windowList.map(w => { - const ws = workspaces[w.workspace_id]; - if (!ws) { - return { - "window": w, - "outputX": 999999, - "outputY": 999999, - "wsIdx": 999999, - "col": 999999, - "row": 999999 - }; - } - - const outputInfo = outputs[ws.output]; - const outputX = (outputInfo && outputInfo.logical) ? outputInfo.logical.x : 999999; - const outputY = (outputInfo && outputInfo.logical) ? outputInfo.logical.y : 999999; - - const pos = w.layout?.pos_in_scrolling_layout; - const col = (pos && pos.length >= 2) ? pos[0] : 999999; - const row = (pos && pos.length >= 2) ? pos[1] : 999999; - - return { - "window": w, - "outputX": outputX, - "outputY": outputY, - "wsIdx": ws.idx, - "col": col, - "row": row - }; - }); - - enriched.sort((a, b) => { - if (a.outputX !== b.outputX) - return a.outputX - b.outputX; - if (a.outputY !== b.outputY) - return a.outputY - b.outputY; - if (a.wsIdx !== b.wsIdx) - return a.wsIdx - b.wsIdx; - if (a.col !== b.col) - return a.col - b.col; - if (a.row !== b.row) - return a.row - b.row; - return a.window.id - b.window.id; - }); - - return enriched.map(e => e.window); - } - - function handleNiriEvent(event) { - const eventType = Object.keys(event)[0]; - - switch (eventType) { - case 'WorkspacesChanged': - handleWorkspacesChanged(event.WorkspacesChanged); - break; - case 'WorkspaceActivated': - handleWorkspaceActivated(event.WorkspaceActivated); - break; - case 'WorkspaceActiveWindowChanged': - handleWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged); - break; - case 'WindowFocusChanged': - handleWindowFocusChanged(event.WindowFocusChanged); - break; - case 'WindowsChanged': - handleWindowsChanged(event.WindowsChanged); - break; - case 'WindowClosed': - handleWindowClosed(event.WindowClosed); - break; - case 'WindowOpenedOrChanged': - handleWindowOpenedOrChanged(event.WindowOpenedOrChanged); - break; - case 'WindowLayoutsChanged': - handleWindowLayoutsChanged(event.WindowLayoutsChanged); - break; - case 'OutputsChanged': - handleOutputsChanged(event.OutputsChanged); - break; - case 'OverviewOpenedOrClosed': - handleOverviewChanged(event.OverviewOpenedOrClosed); - break; - case 'ConfigLoaded': - handleConfigLoaded(event.ConfigLoaded); - break; - case 'KeyboardLayoutsChanged': - handleKeyboardLayoutsChanged(event.KeyboardLayoutsChanged); - break; - case 'KeyboardLayoutSwitched': - handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched); - break; - case 'WorkspaceUrgencyChanged': - handleWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged); - break; - case 'WindowUrgencyChanged': - handleWindowUrgencyChanged(event.WindowUrgencyChanged); - break; - case 'ScreenshotCaptured': - handleScreenshotCaptured(event.ScreenshotCaptured); - break; - case 'CastsChanged': - handleCastsChanged(event.CastsChanged); - break; - case 'CastStartedOrChanged': - handleCastStartedOrChanged(event.CastStartedOrChanged); - break; - case 'CastStopped': - handleCastStopped(event.CastStopped); - break; - } - } - - function handleWorkspacesChanged(data) { - const newWorkspaces = {}; - - for (const ws of data.workspaces) { - const oldWs = root.workspaces[ws.id]; - newWorkspaces[ws.id] = ws; - if (oldWs && oldWs.active_window_id !== undefined) { - newWorkspaces[ws.id].active_window_id = oldWs.active_window_id; - } - } - - setWorkspaces(newWorkspaces); - - focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.is_focused); - if (focusedWorkspaceIndex >= 0) { - const focusedWs = allWorkspaces[focusedWorkspaceIndex]; - focusedWorkspaceId = focusedWs.id; - currentOutput = focusedWs.output || ""; - } else { - focusedWorkspaceIndex = 0; - focusedWorkspaceId = ""; - } - - updateCurrentOutputWorkspaces(); - } - - function handleWorkspaceActivated(data) { - const ws = root.workspaces[data.id]; - if (!ws) { - return; - } - const output = ws.output; - - const updatedWorkspaces = {}; - - for (const id in root.workspaces) { - const workspace = root.workspaces[id]; - const got_activated = workspace.id === data.id; - - const updatedWs = {}; - for (let prop in workspace) { - updatedWs[prop] = workspace[prop]; - } - - if (workspace.output === output) { - updatedWs.is_active = got_activated; - } - - if (data.focused) { - updatedWs.is_focused = got_activated; - } - - updatedWorkspaces[id] = updatedWs; - } - - setWorkspaces(updatedWorkspaces); - - focusedWorkspaceId = data.id; - focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.id === data.id); - - if (focusedWorkspaceIndex >= 0) { - currentOutput = allWorkspaces[focusedWorkspaceIndex].output || ""; - } - - updateCurrentOutputWorkspaces(); - } - - function handleWindowFocusChanged(data) { - const focusedWindowId = data.id; - - let focusedWindow = null; - const updatedWindows = []; - - for (var i = 0; i < windows.length; i++) { - const w = windows[i]; - const updatedWindow = {}; - - for (let prop in w) { - updatedWindow[prop] = w[prop]; - } - - updatedWindow.is_focused = (w.id === focusedWindowId); - if (updatedWindow.is_focused) { - focusedWindow = updatedWindow; - } - - updatedWindows.push(updatedWindow); - } - - windows = updatedWindows; - - if (focusedWindow) { - const ws = root.workspaces[focusedWindow.workspace_id]; - if (ws && ws.active_window_id !== focusedWindowId) { - const updatedWs = {}; - for (let prop in ws) { - updatedWs[prop] = ws[prop]; - } - updatedWs.active_window_id = focusedWindowId; - - const updatedWorkspaces = {}; - for (const id in root.workspaces) { - updatedWorkspaces[id] = id === focusedWindow.workspace_id ? updatedWs : root.workspaces[id]; - } - setWorkspaces(updatedWorkspaces); - } - } - } - - function handleWorkspaceActiveWindowChanged(data) { - const ws = root.workspaces[data.workspace_id]; - if (ws) { - const updatedWs = {}; - for (let prop in ws) { - updatedWs[prop] = ws[prop]; - } - updatedWs.active_window_id = data.active_window_id; - - const updatedWorkspaces = {}; - for (const id in root.workspaces) { - updatedWorkspaces[id] = id === data.workspace_id ? updatedWs : root.workspaces[id]; - } - setWorkspaces(updatedWorkspaces); - } - - const updatedWindows = []; - - for (var i = 0; i < windows.length; i++) { - const w = windows[i]; - const updatedWindow = {}; - - for (let prop in w) { - updatedWindow[prop] = w[prop]; - } - - if (data.active_window_id !== null && data.active_window_id !== undefined) { - updatedWindow.is_focused = (w.id == data.active_window_id); - } else { - updatedWindow.is_focused = w.workspace_id == data.workspace_id ? false : w.is_focused; - } - - updatedWindows.push(updatedWindow); - } - - windows = updatedWindows; - } - - function handleWindowsChanged(data) { - windows = sortWindowsByLayout(data.windows); - } - - function handleWindowClosed(data) { - windows = windows.filter(w => w.id !== data.id); - } - - function handleWindowOpenedOrChanged(data) { - if (!data.window) - return; - const window = data.window; - const existingIndex = windows.findIndex(w => w.id === window.id); - - if (existingIndex >= 0) { - const updatedWindows = [...windows]; - updatedWindows[existingIndex] = window; - windows = sortWindowsByLayout(updatedWindows); - } else { - windows = sortWindowsByLayout([...windows, window]); - } - } - - function handleWindowLayoutsChanged(data) { - if (!data.changes) - return; - const updatedWindows = [...windows]; - let hasChanges = false; - - for (const change of data.changes) { - const windowId = change[0]; - const layoutData = change[1]; - - const windowIndex = updatedWindows.findIndex(w => w.id === windowId); - if (windowIndex < 0) - continue; - const updatedWindow = {}; - for (var prop in updatedWindows[windowIndex]) { - updatedWindow[prop] = updatedWindows[windowIndex][prop]; - } - updatedWindow.layout = layoutData; - updatedWindows[windowIndex] = updatedWindow; - hasChanges = true; - } - - if (!hasChanges) - return; - windows = sortWindowsByLayout(updatedWindows); - } - - function handleOutputsChanged(data) { - if (!data.outputs) - return; - outputs = data.outputs; - updateDisplayScales(); - windows = sortWindowsByLayout(windows); - } - - function handleOverviewChanged(data) { - inOverview = data.is_open; - } - - function handleConfigLoaded(data) { - if (data.failed) { - validateProcess.running = true; - return; - } - - configValidationOutput = ""; - ToastService.dismissCategory("niri-config"); - fetchOutputs(); - configReloaded(); - - if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) { - ToastService.showInfo("niri: config reloaded", "", "", "niri-config"); - } else if (suppressNextConfigToast) { - suppressNextConfigToast = false; - suppressResetTimer.stop(); - } - - if (!hasInitialConnection) { - hasInitialConnection = true; - suppressToastTimer.start(); - } - } - - function handleKeyboardLayoutsChanged(data) { - keyboardLayoutNames = data.keyboard_layouts.names; - currentKeyboardLayoutIndex = data.keyboard_layouts.current_idx; - } - - function handleKeyboardLayoutSwitched(data) { - currentKeyboardLayoutIndex = data.idx; - } - - function handleWorkspaceUrgencyChanged(data) { - const ws = root.workspaces[data.id]; - if (!ws) - return; - const updatedWs = {}; - for (let prop in ws) { - updatedWs[prop] = ws[prop]; - } - updatedWs.is_urgent = data.urgent; - - const updatedWorkspaces = {}; - for (const id in root.workspaces) { - updatedWorkspaces[id] = id === data.id ? updatedWs : root.workspaces[id]; - } - setWorkspaces(updatedWorkspaces); - - windowUrgentChanged(); - } - - function handleWindowUrgencyChanged(data) { - const windowIndex = windows.findIndex(w => w.id === data.id); - if (windowIndex < 0) - return; - const updatedWindows = [...windows]; - const updatedWindow = {}; - for (let prop in updatedWindows[windowIndex]) { - updatedWindow[prop] = updatedWindows[windowIndex][prop]; - } - updatedWindow.is_urgent = data.urgent; - updatedWindows[windowIndex] = updatedWindow; - windows = updatedWindows; - - windowUrgentChanged(); - } - - function handleScreenshotCaptured(data) { - if (!data.path) - return; - if (pendingScreenshotPath && data.path === pendingScreenshotPath) { - const editor = Quickshell.env("DMS_SCREENSHOT_EDITOR"); - let command; - if (editor === "satty" || !editor) { - command = ["satty", "-f", data.path]; - } else if (editor === "swappy") { - command = ["swappy", "-f", data.path]; - } else { - // Custom command with %path% placeholder - command = editor.split(" ").map(arg => arg === "%path%" ? data.path : arg); - } - Quickshell.execDetached({ - "command": command - }); - pendingScreenshotPath = ""; - } - } - - function handleCastsChanged(data) { - casts = data.casts || []; - } - - function handleCastStartedOrChanged(data) { - if (!data.cast) - return; - const cast = data.cast; - const existingIndex = casts.findIndex(c => c.stream_id === cast.stream_id); - if (existingIndex >= 0) { - const updatedCasts = [...casts]; - updatedCasts[existingIndex] = cast; - casts = updatedCasts; - } else { - casts = [...casts, cast]; - } - } - - function handleCastStopped(data) { - casts = casts.filter(c => c.stream_id !== data.stream_id); - } - - function updateCurrentOutputWorkspaces() { - if (!currentOutput) { - currentOutputWorkspaces = allWorkspaces; - return; - } - - const outputWs = allWorkspaces.filter(w => w.output === currentOutput); - currentOutputWorkspaces = outputWs; - } - - function send(request) { - if (!CompositorService.isNiri || !requestSocket.connected) - return false; - requestSocket.send(request); - return true; - } - - function doScreenTransition() { - return send({ - "Action": { - "DoScreenTransition": { - "delay_ms": 0 - } - } - }); - } - - function toggleOverview() { - return send({ - "Action": { - "ToggleOverview": {} - } - }); - } - - function moveColumnLeft() { - return send({ - "Action": { - "FocusColumnLeft": {} - } - }); - } - - function moveColumnRight() { - return send({ - "Action": { - "FocusColumnRight": {} - } - }); - } - - function moveWorkspaceDown() { - return send({ - "Action": { - "FocusWorkspaceDown": {} - } - }); - } - - function moveWorkspaceUp() { - return send({ - "Action": { - "FocusWorkspaceUp": {} - } - }); - } - - function switchToWorkspace(workspaceIndex) { - return send({ - "Action": { - "FocusWorkspace": { - "reference": { - "Index": workspaceIndex - } - } - } - }); - } - - function focusWindow(windowId) { - return send({ - "Action": { - "FocusWindow": { - "id": windowId - } - } - }); - } - - function powerOffMonitors() { - return send({ - "Action": { - "PowerOffMonitors": {} - } - }); - } - - function powerOnMonitors() { - return send({ - "Action": { - "PowerOnMonitors": {} - } - }); - } - - function cycleKeyboardLayout() { - return send({ - "Action": { - "SwitchLayout": { - "layout": "Next" - } - } - }); - } - - function quit() { - return send({ - "Action": { - "Quit": { - "skip_confirmation": true - } - } - }); - } - - function screenshot() { - pendingScreenshotPath = ""; - const timestamp = Date.now(); - const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`; - pendingScreenshotPath = path; - - return send({ - "Action": { - "Screenshot": { - "show_pointer": true, - "path": path - } - } - }); - } - - function screenshotScreen() { - pendingScreenshotPath = ""; - const timestamp = Date.now(); - const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`; - pendingScreenshotPath = path; - - return send({ - "Action": { - "ScreenshotScreen": { - "write_to_disk": true, - "show_pointer": true, - "path": path - } - } - }); - } - - function screenshotWindow() { - pendingScreenshotPath = ""; - const timestamp = Date.now(); - const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`; - pendingScreenshotPath = path; - - return send({ - "Action": { - "ScreenshotWindow": { - "write_to_disk": true, - "show_pointer": true, - "path": path - } - } - }); - } - - function getCurrentOutputWorkspaceNumbers() { - return currentOutputWorkspaces.map(w => w.idx + 1); - } - - function getCurrentOutputWorkspaces() { - return currentOutputWorkspaces.slice(); - } - - function getCurrentWorkspaceNumber() { - if (focusedWorkspaceIndex >= 0 && focusedWorkspaceIndex < allWorkspaces.length) { - return allWorkspaces[focusedWorkspaceIndex].idx; - } - return 1; - } - - function getCurrentKeyboardLayoutName() { - if (currentKeyboardLayoutIndex >= 0 && currentKeyboardLayoutIndex < keyboardLayoutNames.length) { - return keyboardLayoutNames[currentKeyboardLayoutIndex]; - } - return ""; - } - - function suppressNextToast() { - matugenSuppression = true; - suppressResetTimer.restart(); - } - - function findNiriWindow(toplevel) { - if (!toplevel.appId) - return null; - - for (var j = 0; j < windows.length; j++) { - const niriWindow = windows[j]; - if (niriWindow.app_id === toplevel.appId) { - if (!niriWindow.title || niriWindow.title === toplevel.title) { - return { - "niriIndex": j, - "niriWindow": niriWindow - }; - } - } - } - return null; - } - - function sortToplevels(toplevels) { - if (!toplevels || toplevels.length === 0 || !CompositorService.isNiri || windows.length === 0) { - return [...toplevels]; - } - - const usedToplevels = new Set(); - const enrichedToplevels = []; - - for (const niriWindow of sortWindowsByLayout(windows)) { - let bestMatch = null; - let bestScore = -1; - - for (const toplevel of toplevels) { - if (usedToplevels.has(toplevel)) - continue; - if (toplevel.appId === niriWindow.app_id) { - let score = 1; - - if (niriWindow.title && toplevel.title) { - if (toplevel.title === niriWindow.title) { - score = 3; - } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) { - score = 2; - } - } - - if (score > bestScore) { - bestScore = score; - bestMatch = toplevel; - if (score === 3) - break; - } - } - } - - if (!bestMatch) - continue; - usedToplevels.add(bestMatch); - - const workspace = workspaces[niriWindow.workspace_id]; - const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false; - - const enrichedToplevel = { - "appId": bestMatch.appId, - "title": bestMatch.title, - "activated": isFocused, - "niriWindowId": niriWindow.id, - "niriWorkspaceId": niriWindow.workspace_id, - "activate": function () { - return NiriService.focusWindow(niriWindow.id); - }, - "close": function () { - if (bestMatch.close) { - return bestMatch.close(); - } - return false; - } - }; - - for (let prop in bestMatch) { - if (!(prop in enrichedToplevel)) { - enrichedToplevel[prop] = bestMatch[prop]; - } - } - - enrichedToplevels.push(enrichedToplevel); - } - - for (const toplevel of toplevels) { - if (!usedToplevels.has(toplevel)) { - enrichedToplevels.push(toplevel); - } - } - - return enrichedToplevels; - } - - function _matchAndEnrichToplevels(toplevels, niriWindows) { - const usedToplevels = new Set(); - const result = []; - - for (const niriWindow of niriWindows) { - let bestMatch = null; - let bestScore = -1; - - for (const toplevel of toplevels) { - if (usedToplevels.has(toplevel)) - continue; - if (toplevel.appId !== niriWindow.app_id) - continue; - - let score = 1; - if (niriWindow.title && toplevel.title) { - if (toplevel.title === niriWindow.title) { - score = 3; - } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) { - score = 2; - } - } - - if (score > bestScore) { - bestScore = score; - bestMatch = toplevel; - if (score === 3) - break; - } - } - - if (!bestMatch) - continue; - usedToplevels.add(bestMatch); - - const workspace = workspaces[niriWindow.workspace_id]; - const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false; - - const enrichedToplevel = { - "appId": bestMatch.appId, - "title": bestMatch.title, - "activated": isFocused, - "niriWindowId": niriWindow.id, - "niriWorkspaceId": niriWindow.workspace_id, - "activate": function () { - return NiriService.focusWindow(niriWindow.id); - }, - "close": function () { - if (bestMatch.close) - return bestMatch.close(); - return false; - } - }; - - for (let prop in bestMatch) { - if (!(prop in enrichedToplevel)) - enrichedToplevel[prop] = bestMatch[prop]; - } - - result.push(enrichedToplevel); - } - - return result; - } - - function filterCurrentWorkspace(toplevels, screenName) { - let currentWorkspaceId = null; - - for (var i = 0; i < allWorkspaces.length; i++) { - const ws = allWorkspaces[i]; - if (ws.output === screenName && ws.is_active) { - currentWorkspaceId = ws.id; - break; - } - } - - if (currentWorkspaceId === null) - return toplevels; - - if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined) - return toplevels.filter(t => t.niriWorkspaceId === currentWorkspaceId); - - return _matchAndEnrichToplevels(toplevels, windows.filter(nw => nw.workspace_id === currentWorkspaceId)); - } - - function filterCurrentDisplay(toplevels, screenName) { - if (!toplevels || toplevels.length === 0 || !screenName) - return toplevels; - - const outputWorkspaceIds = new Set(); - for (var i = 0; i < allWorkspaces.length; i++) { - const ws = allWorkspaces[i]; - if (ws.output === screenName) - outputWorkspaceIds.add(ws.id); - } - - if (outputWorkspaceIds.size === 0) - return toplevels; - - if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined) - return toplevels.filter(t => outputWorkspaceIds.has(t.niriWorkspaceId)); - - return _matchAndEnrichToplevels(toplevels, windows.filter(nw => outputWorkspaceIds.has(nw.workspace_id))); - } - - function generateNiriLayoutConfig() { - if (!CompositorService.isNiri || configGenerationPending) - return; - suppressNextToast(); - configGenerationPending = true; - configGenerationDebounce.restart(); - } - - function doGenerateNiriLayoutConfig() { - console.log("NiriService: Generating layout config..."); - - const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; - const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4; - const defaultBorderSize = 2; - - const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius; - const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps; - const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize; - - const dmsWarning = `// ! DO NOT EDIT ! - // ! AUTO-GENERATED BY DMS ! - // ! CHANGES WILL BE OVERWRITTEN ! - // ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE ! - - `; - - const configContent = dmsWarning + `layout { - gaps ${gaps} - - border { - width ${borderSize} - } - - focus-ring { - width ${borderSize} - } - } - window-rule { - geometry-corner-radius ${cornerRadius} - clip-to-geometry true - tiled-state true - draw-border-with-background false - }`; - - const alttabContent = dmsWarning + `recent-windows { - highlight { - corner-radius ${cornerRadius} - } - }`; - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const niriDmsDir = configDir + "/niri/dms"; - const configPath = niriDmsDir + "/layout.kdl"; - const alttabPath = niriDmsDir + "/alttab.kdl"; - - writeConfigProcess.configContent = configContent; - writeConfigProcess.configPath = configPath; - writeConfigProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${configPath}" << 'EOF'\n${configContent}\nEOF`]; - writeConfigProcess.running = true; - - writeAlttabProcess.alttabContent = alttabContent; - writeAlttabProcess.alttabPath = alttabPath; - writeAlttabProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${alttabPath}" << 'EOF'\n${alttabContent}\nEOF`]; - writeAlttabProcess.running = true; - - for (const name of ["outputs", "binds", "cursor", "windowrules", "colors", "alttab", "layout"]) { - const path = niriDmsDir + "/" + name + ".kdl"; - Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => { - if (exitCode !== 0) - console.warn("NiriService: Failed to ensure " + name + ".kdl, exit code:", exitCode); - }); - } - - configGenerationPending = false; - } - - function generateNiriBlurrule() { - console.log("NiriService: Generating wpblur config..."); - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const niriDmsDir = configDir + "/niri/dms"; - const blurrulePath = niriDmsDir + "/wpblur.kdl"; - const sourceBlurrulePath = Paths.strip(Qt.resolvedUrl("niri-wpblur.kdl")); - - writeBlurruleProcess.blurrulePath = blurrulePath; - writeBlurruleProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cp --no-preserve=mode "${sourceBlurrulePath}" "${blurrulePath}"`]; - writeBlurruleProcess.running = true; - } - - function generateNiriCursorConfig() { - if (!CompositorService.isNiri) - return; - - console.log("NiriService: Generating cursor config..."); - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const niriDmsDir = configDir + "/niri/dms"; - const cursorPath = niriDmsDir + "/cursor.kdl"; - - const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null; - if (!settings) { - writeCursorProcess.cursorContent = ""; - writeCursorProcess.cursorPath = cursorPath; - writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`]; - writeCursorProcess.running = true; - return; - } - - const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme; - const size = settings.size || 24; - const hideWhenTyping = settings.niri?.hideWhenTyping || false; - const hideAfterMs = settings.niri?.hideAfterInactiveMs || 0; - - const isDefaultConfig = !themeName && size === 24 && !hideWhenTyping && hideAfterMs === 0; - if (isDefaultConfig) { - writeCursorProcess.cursorContent = ""; - writeCursorProcess.cursorPath = cursorPath; - writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`]; - writeCursorProcess.running = true; - return; - } - - const dmsWarning = `// ! DO NOT EDIT ! -// ! AUTO-GENERATED BY DMS ! -// ! CHANGES WILL BE OVERWRITTEN ! -// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE ! - -`; - - let cursorContent = dmsWarning + `cursor {\n`; - - if (themeName) - cursorContent += ` xcursor-theme "${themeName}"\n`; - - cursorContent += ` xcursor-size ${size}\n`; - - if (hideWhenTyping) - cursorContent += ` hide-when-typing\n`; - - if (hideAfterMs > 0) - cursorContent += ` hide-after-inactive-ms ${hideAfterMs}\n`; - - cursorContent += `}`; - - writeCursorProcess.cursorContent = cursorContent; - writeCursorProcess.cursorPath = cursorPath; - - const escapedCursorContent = cursorContent.replace(/'/g, "'\\''"); - - writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && printf '%s' '${escapedCursorContent}' > "${cursorPath}"`]; - writeCursorProcess.running = true; - } - - function updateOutputPosition(outputName, x, y) { - if (!outputs || !outputs[outputName]) - return; - const updatedOutputs = {}; - for (const name in outputs) { - const output = outputs[name]; - if (name === outputName && output.logical) { - updatedOutputs[name] = JSON.parse(JSON.stringify(output)); - updatedOutputs[name].logical.x = x; - updatedOutputs[name].logical.y = y; - } else { - updatedOutputs[name] = output; - } - } - outputs = updatedOutputs; - } - - function applyOutputConfig(outputName, config, callback) { - if (!CompositorService.isNiri || !outputName) { - if (callback) - callback(false, "Invalid config"); - return; - } - - const commands = []; - - if (config.position !== undefined) { - commands.push(`niri msg output "${outputName}" position ${config.position.x} ${config.position.y}`); - } - - if (config.mode !== undefined) { - commands.push(`niri msg output "${outputName}" mode ${config.mode}`); - } - - if (config.vrr !== undefined) { - commands.push(`niri msg output "${outputName}" vrr ${config.vrr ? "on" : "off"}`); - } - - if (config.scale !== undefined) { - commands.push(`niri msg output "${outputName}" scale ${config.scale}`); - } - - if (config.transform !== undefined) { - commands.push(`niri msg output "${outputName}" transform "${config.transform}"`); - } - - if (commands.length === 0) { - if (callback) - callback(true, "No changes"); - return; - } - - const fullCommand = commands.join(" && "); - Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("NiriService: Failed to apply output config:", output); - if (callback) - callback(false, output); - return; - } - console.info("NiriService: Applied output config for", outputName); - fetchOutputs(); - if (callback) - callback(true, "Success"); - }); - } - - function getOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output.make && output.model) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return outputName; - } - - function generateOutputsConfig(outputsData) { - const data = outputsData || outputs; - if (!data || Object.keys(data).length === 0) - return; - let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`; - - const sortedNames = Object.keys(data).sort((a, b) => { - const la = data[a].logical || {}; - const lb = data[b].logical || {}; - return (la.x ?? 0) - (lb.x ?? 0) || (la.y ?? 0) - (lb.y ?? 0); - }); - for (const outputName of sortedNames) { - const output = data[outputName]; - const identifier = getOutputIdentifier(output, outputName); - const niriSettings = SettingsData.getNiriOutputSettings(identifier); - - kdlContent += `output "${identifier}" {\n`; - - if (niriSettings.disabled) { - kdlContent += ` off\n`; - } - - if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) { - const mode = output.modes[output.current_mode]; - kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`; - } - - if (output.logical) { - kdlContent += ` scale ${output.logical.scale || 1.0}\n`; - - if (output.logical.transform && output.logical.transform !== "Normal") { - const transformMap = { - "Normal": "normal", - "90": "90", - "180": "180", - "270": "270", - "Flipped": "flipped", - "Flipped90": "flipped-90", - "Flipped180": "flipped-180", - "Flipped270": "flipped-270" - }; - kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`; - } - - if (output.logical.x !== undefined && output.logical.y !== undefined) { - kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`; - } - } - - if (output.vrr_enabled || niriSettings.vrrOnDemand) { - const vrrOnDemand = niriSettings.vrrOnDemand ?? false; - kdlContent += vrrOnDemand ? ` variable-refresh-rate on-demand=true\n` : ` variable-refresh-rate\n`; - } - - if (niriSettings.focusAtStartup) { - kdlContent += ` focus-at-startup\n`; - } - - if (niriSettings.backdropColor) { - kdlContent += ` backdrop-color "${niriSettings.backdropColor}"\n`; - } - - kdlContent += generateHotCornersBlock(niriSettings); - kdlContent += generateLayoutBlock(niriSettings); - - kdlContent += `}\n\n`; - } - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const niriDmsDir = configDir + "/niri/dms"; - const outputsPath = niriDmsDir + "/outputs.kdl"; - - Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => { - if (exitCode !== 0) { - console.warn("NiriService: Failed to write outputs config:", output); - return; - } - console.info("NiriService: Generated outputs config at", outputsPath); - }); - } - - function generateHotCornersBlock(niriSettings) { - if (!niriSettings.hotCorners) - return ""; - const hc = niriSettings.hotCorners; - if (hc.off) - return ` hot-corners {\n off\n }\n`; - const corners = hc.corners || []; - if (corners.length === 0) - return ""; - let block = ` hot-corners {\n`; - for (const corner of corners) { - block += ` ${corner}\n`; - } - block += ` }\n`; - return block; - } - - function generateLayoutBlock(niriSettings) { - if (!niriSettings.layout) - return ""; - const layout = niriSettings.layout; - const hasSettings = layout.gaps !== undefined || layout.defaultColumnWidth || layout.presetColumnWidths || layout.alwaysCenterSingleColumn !== undefined; - if (!hasSettings) - return ""; - let block = ` layout {\n`; - if (layout.gaps !== undefined) - block += ` gaps ${layout.gaps}\n`; - if (layout.defaultColumnWidth?.type === "proportion") { - const val = layout.defaultColumnWidth.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` default-column-width { proportion ${formatted}; }\n`; - } - if (layout.presetColumnWidths && layout.presetColumnWidths.length > 0) { - block += ` preset-column-widths {\n`; - for (const preset of layout.presetColumnWidths) { - if (preset.type === "proportion") { - const val = preset.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` proportion ${formatted}\n`; - } - } - block += ` }\n`; - } - if (layout.alwaysCenterSingleColumn !== undefined) - block += layout.alwaysCenterSingleColumn ? ` always-center-single-column\n` : ` always-center-single-column false\n`; - block += ` }\n`; - return block; - } - - function renameWorkspace(name) { - if (!name || name.trim() === "") { - return send({ - "Action": { - "UnsetWorkspaceName": { - "workspace": null - } - } - }); - } - return send({ - "Action": { - "SetWorkspaceName": { - "name": name, - "workspace": null - } - } - }); - } - - function moveWorkspaceToIndex(workspaceIdx, targetIndex) { - return send({ - "Action": { - "MoveWorkspaceToIndex": { - "index": targetIndex, - "reference": { - "Index": workspaceIdx - } - } - } - }); - } - - IpcHandler { - function screenshot(): string { - if (!CompositorService.isNiri) { - return "NIRI_NOT_AVAILABLE"; - } - if (NiriService.screenshot()) { - return "SCREENSHOT_SUCCESS"; - } - return "SCREENSHOT_FAILED"; - } - - function screenshotScreen(): string { - if (!CompositorService.isNiri) { - return "NIRI_NOT_AVAILABLE"; - } - if (NiriService.screenshotScreen()) { - return "SCREENSHOT_SCREEN_SUCCESS"; - } - return "SCREENSHOT_SCREEN_FAILED"; - } - - function screenshotWindow(): string { - if (!CompositorService.isNiri) { - return "NIRI_NOT_AVAILABLE"; - } - if (NiriService.screenshotWindow()) { - return "SCREENSHOT_WINDOW_SUCCESS"; - } - return "SCREENSHOT_WINDOW_FAILED"; - } - - target: "niri" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml deleted file mode 100644 index 3a6257a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml +++ /dev/null @@ -1,473 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import QtCore -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property int refCount: 0 - - readonly property string baseDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell") - readonly property string filesDir: baseDir + "/notepad-files" - readonly property string metadataPath: baseDir + "/notepad-session.json" - - property var tabs: [] - property int currentTabIndex: 0 - property var tabsBeingCreated: ({}) - property bool metadataLoaded: false - - Component.onCompleted: { - ensureDirectories() - } - - FileView { - id: metadataFile - path: root.refCount > 0 ? root.metadataPath : "" - blockWrites: true - atomicWrites: true - - onLoaded: { - try { - var data = JSON.parse(text()) - root.tabs = data.tabs || [] - root.currentTabIndex = data.currentTabIndex || 0 - root.metadataLoaded = true - root.validateTabs() - } catch(e) { - console.warn("Failed to parse notepad metadata:", e) - root.createDefaultTab() - } - } - - onLoadFailed: { - root.createDefaultTab() - } - } - - onRefCountChanged: { - if (refCount === 1 && !metadataLoaded) { - metadataFile.path = "" - metadataFile.path = root.metadataPath - } - } - - function ensureDirectories() { - mkdirProcess.running = true - } - - function loadMetadata() { - metadataFile.path = "" - metadataFile.path = root.metadataPath - } - - function createDefaultTab() { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" - var fullPath = baseDir + "/" + filePath - - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated - - root.createEmptyFile(fullPath, function() { - root.tabs = [{ - id: id, - title: I18n.tr("Untitled"), - filePath: filePath, - isTemporary: true, - lastModified: new Date().toISOString(), - cursorPosition: 0, - scrollPosition: 0 - }] - root.currentTabIndex = 0 - - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - root.saveMetadata() - }) - } - - function saveMetadata() { - var metadata = { - version: 1, - currentTabIndex: currentTabIndex, - tabs: tabs - } - metadataFile.setText(JSON.stringify(metadata, null, 2)) - } - - function getTabById(tabId) { - for (var i = 0; i < tabs.length; i++) { - if (tabs[i].id === tabId) - return tabs[i] - } - return null - } - - function loadTabContent(tabIndex, callback) { - if (tabIndex < 0 || tabIndex >= tabs.length) { - callback("") - return - } - - var tab = tabs[tabIndex] - var requestTabId = tab.id - var fullPath = tab.isTemporary - ? baseDir + "/" + tab.filePath - : tab.filePath - - if (tabsBeingCreated[tab.id]) { - Qt.callLater(() => { - loadTabContent(tabIndex, callback) - }) - return - } - - var fileChecker = fileExistsComponent.createObject(root, { - path: fullPath, - callback: (exists) => { - var currentTab = root.getTabById(requestTabId) - var currentPath = currentTab - ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath) - : "" - - if (!currentTab || currentPath !== fullPath) { - callback("") - return - } - - if (exists) { - var loader = tabFileLoaderComponent.createObject(root, { - path: fullPath, - callback: callback - }) - } else { - console.warn("Tab file does not exist:", fullPath) - callback("") - } - } - }) - } - - function saveTabContent(tabIndex, content) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var tab = tabs[tabIndex] - var fullPath = tab.isTemporary - ? baseDir + "/" + tab.filePath - : tab.filePath - - var saver = tabFileSaverComponent.createObject(root, { - path: fullPath, - content: content, - tabIndex: tabIndex - }) - } - - function createNewTab() { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" - var fullPath = baseDir + "/" + filePath - - var newTab = { - id: id, - title: I18n.tr("Untitled"), - filePath: filePath, - isTemporary: true, - lastModified: new Date().toISOString(), - cursorPosition: 0, - scrollPosition: 0 - } - - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated - createEmptyFile(fullPath, function() { - var newTabs = tabs.slice() - newTabs.push(newTab) - tabs = newTabs - currentTabIndex = tabs.length - 1 - - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - saveMetadata() - }) - - return newTab - } - - function closeTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var newTabs = tabs.slice() - - if (newTabs.length <= 1) { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" - - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated - createEmptyFile(baseDir + "/" + filePath, function() { - newTabs[0] = { - id: id, - title: I18n.tr("Untitled"), - filePath: filePath, - isTemporary: true, - lastModified: new Date().toISOString(), - cursorPosition: 0, - scrollPosition: 0 - } - currentTabIndex = 0 - tabs = newTabs - - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - saveMetadata() - }) - return - } else { - var tabToDelete = newTabs[tabIndex] - if (tabToDelete && tabToDelete.isTemporary) { - deleteFile(baseDir + "/" + tabToDelete.filePath) - } - - newTabs.splice(tabIndex, 1) - if (currentTabIndex >= newTabs.length) { - currentTabIndex = newTabs.length - 1 - } else if (currentTabIndex > tabIndex) { - currentTabIndex -= 1 - } - } - - tabs = newTabs - saveMetadata() - - } - - function switchToTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - currentTabIndex = tabIndex - saveMetadata() - } - - function reorderTab(fromIndex, toIndex) { - if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length) - return - if (fromIndex === toIndex) - return - - var newTabs = tabs.slice() - var moved = newTabs.splice(fromIndex, 1)[0] - newTabs.splice(toIndex, 0, moved) - tabs = newTabs - - if (currentTabIndex === fromIndex) { - currentTabIndex = toIndex - } else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) { - currentTabIndex-- - } else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) { - currentTabIndex++ - } - - saveMetadata() - } - - function saveTabAs(tabIndex, userPath) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var tab = tabs[tabIndex] - var fileName = userPath.split('/').pop() - - if (tab.isTemporary) { - var tempPath = baseDir + "/" + tab.filePath - copyFile(tempPath, userPath) - deleteFile(tempPath) - } - - var newTabs = tabs.slice() - newTabs[tabIndex] = Object.assign({}, tab, { - title: fileName, - filePath: userPath, - isTemporary: false, - lastModified: new Date().toISOString() - }) - tabs = newTabs - saveMetadata() - - } - - function updateTabMetadata(tabIndex, properties) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var newTabs = tabs.slice() - var updatedTab = Object.assign({}, newTabs[tabIndex], properties) - updatedTab.lastModified = new Date().toISOString() - newTabs[tabIndex] = updatedTab - tabs = newTabs - saveMetadata() - - } - - function validateTabs() { - var validTabs = [] - for (var i = 0; i < tabs.length; i++) { - var tab = tabs[i] - validTabs.push(tab) - } - tabs = validTabs - - if (tabs.length === 0) { - root.createDefaultTab() - } - } - - Component { - id: tabFileLoaderComponent - FileView { - property var callback - blockLoading: true - preload: true - - onLoaded: { - callback(text()) - destroy() - } - - onLoadFailed: { - callback("") - destroy() - } - } - } - - Component { - id: fileExistsComponent - Process { - property string path - property var callback - command: ["test", "-f", path] - - Component.onCompleted: running = true - - onExited: (exitCode) => { - callback(exitCode === 0) - destroy() - } - } - } - - Component { - id: tabFileSaverComponent - FileView { - property string content - property int tabIndex - property var creationCallback - - blockWrites: false - atomicWrites: true - - Component.onCompleted: setText(content) - - onSaved: { - if (tabIndex >= 0) { - root.updateTabMetadata(tabIndex, {}) - } - if (creationCallback) { - creationCallback() - } - destroy() - } - - onSaveFailed: { - console.error("Failed to save tab content") - if (creationCallback) { - creationCallback() - } - destroy() - } - } - } - - function createEmptyFile(path, callback) { - var cleanPath = decodeURI(path.toString()) - - if (!cleanPath.startsWith("/")) { - cleanPath = baseDir + "/" + cleanPath - } - - var creator = fileCreatorComponent.createObject(root, { - filePath: cleanPath, - creationCallback: callback - }) - } - - function copyFile(source, destination) { - copyProcess.source = source - copyProcess.destination = destination - copyProcess.running = true - } - - function deleteFile(path) { - deleteProcess.filePath = path - deleteProcess.running = true - } - - Component { - id: fileCreatorComponent - QtObject { - property string filePath - property var creationCallback - - Component.onCompleted: { - var touchProcess = touchProcessComponent.createObject(this, { - filePath: filePath, - callback: creationCallback - }) - } - } - } - - Component { - id: touchProcessComponent - Process { - property string filePath - property var callback - command: ["touch", filePath] - - Component.onCompleted: running = true - - onExited: (exitCode) => { - if (callback) callback() - destroy() - } - } - } - - Process { - id: copyProcess - property string source - property string destination - command: ["cp", source, destination] - } - - Process { - id: deleteProcess - property string filePath - command: ["rm", "-f", filePath] - } - - Process { - id: mkdirProcess - command: ["mkdir", "-p", root.baseDir, root.filesDir] - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml deleted file mode 100644 index 0615b58..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml +++ /dev/null @@ -1,1237 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Services.Notifications -import qs.Common -import "../Common/markdown2html.js" as Markdown2Html - -Singleton { - id: root - - readonly property list notifications: [] - readonly property list allWrappers: [] - readonly property list popups: allWrappers.filter(n => n && n.popup) - - property var historyList: [] - readonly property string historyFile: Paths.strip(Paths.cache) + "/notification_history.json" - readonly property string imageCacheDir: Paths.strip(Paths.cache) + "/notification_images" - property bool historyLoaded: false - property int historyEntryCounter: 0 - - property list notificationQueue: [] - property list visibleNotifications: [] - property int maxVisibleNotifications: 4 - property bool addGateBusy: false - property int enterAnimMs: 400 - property int seqCounter: 0 - property bool bulkDismissing: false - - property int maxQueueSize: 32 - property int maxIngressPerSecond: 20 - property double _lastIngressSec: 0 - property int _ingressCountThisSec: 0 - - property var _dismissQueue: [] - property int _dismissBatchSize: 8 - property int _dismissTickMs: 8 - property bool _suspendGrouping: false - property var _groupCache: ({ - "notifications": [], - "popups": [] - }) - property bool _groupsDirty: false - - Component.onCompleted: { - _recomputeGroups(); - Quickshell.execDetached(["mkdir", "-p", Paths.strip(Paths.cache)]); - Quickshell.execDetached(["mkdir", "-p", imageCacheDir]); - } - - FileView { - id: historyFileView - path: root.historyFile - printErrors: false - onLoaded: root.loadHistory() - onLoadFailed: error => { - if (error === 2) { - root.historyLoaded = true; - historyFileView.writeAdapter(); - } - } - - JsonAdapter { - id: historyAdapter - property var notifications: [] - } - } - - Timer { - id: historySaveTimer - interval: 200 - onTriggered: root.performSaveHistory() - } - - function _makeHistoryEntryId(sourceId, timestamp) { - historyEntryCounter += 1; - const safeSource = sourceId && sourceId !== "" ? sourceId : "notification"; - return safeSource + "_" + (timestamp || Date.now()) + "_" + historyEntryCounter; - } - - function getImageCachePath(wrapper) { - const ts = wrapper.time ? wrapper.time.getTime() : Date.now(); - const id = wrapper.notification?.id?.toString() || "0"; - return imageCacheDir + "/notif_" + ts + "_" + id + ".png"; - } - - function updateHistoryImage(wrapperId, imagePath) { - const idx = historyList.findIndex(n => n.sourceNotificationId === wrapperId || n.id === wrapperId); - if (idx < 0) - return; - const item = historyList[idx]; - const updated = { - id: item.id, - sourceNotificationId: item.sourceNotificationId || item.id, - summary: item.summary, - body: item.body, - htmlBody: item.htmlBody, - appName: item.appName, - appIcon: item.appIcon, - image: "file://" + imagePath, - urgency: item.urgency, - timestamp: item.timestamp, - desktopEntry: item.desktopEntry - }; - const newList = historyList.slice(); - newList[idx] = updated; - historyList = newList; - saveHistory(); - } - - function addToHistory(wrapper) { - if (!wrapper) - return; - const urg = typeof wrapper.urgency === "number" ? wrapper.urgency : 1; - const imageUrl = wrapper.image || ""; - let persistableImage = ""; - if (wrapper.persistedImagePath) { - persistableImage = "file://" + wrapper.persistedImagePath; - } else if (imageUrl && !imageUrl.startsWith("image://qsimage/")) { - persistableImage = imageUrl; - } - const sourceNotificationId = wrapper.notification?.id?.toString() || ""; - const timestamp = wrapper.time.getTime(); - const data = { - id: _makeHistoryEntryId(sourceNotificationId, timestamp), - sourceNotificationId: sourceNotificationId, - summary: wrapper.summary || "", - body: wrapper.body || "", - htmlBody: wrapper.htmlBody || wrapper.body || "", - appName: wrapper.appName || "", - appIcon: wrapper.appIcon || "", - image: persistableImage, - urgency: urg, - timestamp: timestamp, - desktopEntry: wrapper.desktopEntry || "" - }; - let newList = [data, ...historyList]; - if (newList.length > SettingsData.notificationHistoryMaxCount) { - newList = newList.slice(0, SettingsData.notificationHistoryMaxCount); - } - historyList = newList; - saveHistory(); - } - - function saveHistory() { - historySaveTimer.restart(); - } - - function performSaveHistory() { - try { - historyAdapter.notifications = historyList; - historyFileView.writeAdapter(); - } catch (e) { - console.warn("NotificationService: save history failed:", e); - } - } - - function loadHistory() { - try { - const maxAgeDays = SettingsData.notificationHistoryMaxAgeDays; - const now = Date.now(); - const maxAgeMs = maxAgeDays > 0 ? maxAgeDays * 24 * 60 * 60 * 1000 : 0; - const loaded = []; - const seenIds = {}; - let needsRewrite = false; - - for (const item of historyAdapter.notifications || []) { - if (maxAgeMs > 0 && (now - item.timestamp) > maxAgeMs) - continue; - const urg = typeof item.urgency === "number" ? item.urgency : 1; - const body = item.body || ""; - let htmlBody = item.htmlBody || _resolveHtmlBody(body); - if (htmlBody) { - htmlBody = htmlBody.replace(/]*>/gi, ""); - } - const sourceNotificationId = (item.sourceNotificationId || item.id || "").toString(); - let historyId = (item.id || "").toString(); - if (!historyId || seenIds[historyId]) { - historyId = _makeHistoryEntryId(sourceNotificationId, item.timestamp || now); - needsRewrite = true; - } - if (!item.sourceNotificationId) - needsRewrite = true; - seenIds[historyId] = true; - loaded.push({ - id: historyId, - sourceNotificationId: sourceNotificationId, - summary: item.summary || "", - body: body, - htmlBody: htmlBody, - appName: item.appName || "", - appIcon: item.appIcon || "", - image: item.image || "", - urgency: urg, - timestamp: item.timestamp || 0, - desktopEntry: item.desktopEntry || "" - }); - } - historyList = loaded; - historyLoaded = true; - if ((maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length) || needsRewrite) - saveHistory(); - } catch (e) { - console.warn("NotificationService: load history failed:", e); - historyLoaded = true; - } - } - - function _deleteCachedImage(imagePath) { - if (!imagePath || !imagePath.startsWith("file://")) - return; - const filePath = imagePath.replace("file://", ""); - if (filePath.startsWith(imageCacheDir)) { - Quickshell.execDetached(["rm", "-f", filePath]); - } - } - - function removeFromHistory(notificationId) { - const idx = historyList.findIndex(n => n.id === notificationId); - if (idx >= 0) { - _deleteCachedImage(historyList[idx].image); - historyList = historyList.filter((_, i) => i !== idx); - saveHistory(); - return true; - } - return false; - } - - function clearHistory() { - for (const item of historyList) { - _deleteCachedImage(item.image); - } - historyList = []; - saveHistory(); - } - - function getHistoryTimeRange(timestamp) { - const now = new Date(); - const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - const itemDate = new Date(timestamp); - const itemDay = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); - const diffDays = Math.floor((today - itemDay) / (1000 * 60 * 60 * 24)); - if (diffDays === 0) - return 0; - if (diffDays === 1) - return 1; - return 2; - } - - function getHistoryCountForRange(range) { - if (range === -1) - return historyList.length; - return historyList.filter(n => getHistoryTimeRange(n.timestamp) === range).length; - } - - function formatHistoryTime(timestamp) { - root.timeUpdateTick; - root.clockFormatChanged; - const now = new Date(); - const date = new Date(timestamp); - const diff = now.getTime() - timestamp; - const minutes = Math.floor(diff / 60000); - const hours = Math.floor(minutes / 60); - if (hours < 1) { - if (minutes < 1) - return I18n.tr("now"); - return I18n.tr("%1m ago").arg(minutes); - } - const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - const itemDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - const daysDiff = Math.floor((nowDate - itemDate) / (1000 * 60 * 60 * 24)); - const timeStr = SettingsData.use24HourClock ? date.toLocaleTimeString(Qt.locale(), "HH:mm") : date.toLocaleTimeString(Qt.locale(), "h:mm AP"); - if (daysDiff === 0) - return timeStr; - try { - const localeName = (typeof I18n !== "undefined" && I18n.locale) ? I18n.locale().name : "en-US"; - const weekday = date.toLocaleDateString(localeName, { - weekday: "long" - }); - return weekday + ", " + timeStr; - } catch (e) { - return timeStr; - } - } - - function _nowSec() { - return Date.now() / 1000.0; - } - - function _ingressAllowed(urgency) { - const t = _nowSec(); - if (t - _lastIngressSec >= 1.0) { - _lastIngressSec = t; - _ingressCountThisSec = 0; - } - _ingressCountThisSec += 1; - if (urgency === NotificationUrgency.Critical) { - return true; - } - return _ingressCountThisSec <= maxIngressPerSecond; - } - - function _enqueuePopup(wrapper) { - if (notificationQueue.length >= maxQueueSize) { - const gk = getGroupKey(wrapper); - let idx = notificationQueue.findIndex(w => w && getGroupKey(w) === gk && w.urgency !== NotificationUrgency.Critical); - if (idx === -1) { - idx = notificationQueue.findIndex(w => w && w.urgency !== NotificationUrgency.Critical); - } - if (idx === -1) { - idx = 0; - } - const victim = notificationQueue[idx]; - if (victim) { - victim.popup = false; - } - notificationQueue.splice(idx, 1); - } - notificationQueue = [...notificationQueue, wrapper]; - } - - function _initWrapperPersistence(wrapper) { - const timeoutMs = wrapper.timer ? wrapper.timer.interval : 5000; - const isCritical = wrapper && wrapper.urgency === NotificationUrgency.Critical; - wrapper.isPersistent = isCritical || (timeoutMs === 0); - } - - function _shouldSaveToHistory(urgency, forceDisable) { - if (forceDisable === true) - return false; - if (!SettingsData.notificationHistoryEnabled) - return false; - switch (urgency) { - case NotificationUrgency.Low: - return SettingsData.notificationHistorySaveLow; - case NotificationUrgency.Critical: - return SettingsData.notificationHistorySaveCritical; - default: - return SettingsData.notificationHistorySaveNormal; - } - } - - function _resolveAppNameForRule(notif) { - if (!notif) - return ""; - if (notif.appName && notif.appName !== "") - return notif.appName; - const entry = DesktopEntries.heuristicLookup(notif.desktopEntry); - if (entry && entry.name) - return entry.name; - return ""; - } - - function _ruleFieldValue(field, info) { - switch ((field || "").toString()) { - case "desktopEntry": - return info.desktopEntry; - case "summary": - return info.summary; - case "body": - return info.body; - case "appName": - default: - return info.appName; - } - } - - function _coerceRuleUrgency(value, fallbackUrgency) { - if (typeof value === "number" && value >= NotificationUrgency.Low && value <= NotificationUrgency.Critical) - return value; - - const mapped = (value || "default").toString().toLowerCase(); - switch (mapped) { - case "low": - return NotificationUrgency.Low; - case "normal": - return NotificationUrgency.Normal; - case "critical": - return NotificationUrgency.Critical; - default: - return fallbackUrgency; - } - } - - function _matchesNotificationRule(rule, info) { - if (!rule) - return false; - if (rule.enabled === false) - return false; - - const pattern = (rule.pattern || "").toString(); - if (!pattern.trim()) - return false; - - const value = (_ruleFieldValue(rule.field, info) || "").toString(); - const matchType = (rule.matchType || "contains").toString().toLowerCase(); - - if (matchType === "exact") - return value.toLowerCase() === pattern.toLowerCase(); - if (matchType === "regex") { - try { - return new RegExp(pattern, "i").test(value); - } catch (e) { - console.warn("NotificationService: invalid notification rule regex:", pattern); - return false; - } - } - - return value.toLowerCase().includes(pattern.toLowerCase()); - } - - function _evaluateNotificationPolicy(notif) { - const baseUrgency = typeof notif.urgency === "number" ? notif.urgency : NotificationUrgency.Normal; - const policy = { - "drop": false, - "disablePopup": false, - "hideFromCenter": false, - "disableHistory": false, - "urgency": baseUrgency - }; - - const rules = SettingsData.notificationRules || []; - if (!rules.length) - return policy; - - const info = { - "appName": _resolveAppNameForRule(notif), - "desktopEntry": notif.desktopEntry || "", - "summary": notif.summary || "", - "body": notif.body || "" - }; - - for (const rule of rules) { - if (!_matchesNotificationRule(rule, info)) - continue; - - const action = (rule.action || "default").toString().toLowerCase(); - switch (action) { - case "ignore": - policy.drop = true; - break; - case "mute": - policy.disablePopup = true; - break; - case "popup_only": - policy.hideFromCenter = true; - policy.disableHistory = true; - break; - case "no_history": - policy.disableHistory = true; - break; - default: - break; - } - - policy.urgency = _coerceRuleUrgency(rule.urgency, policy.urgency); - return policy; - } - - return policy; - } - - function pruneHistory() { - const maxAgeDays = SettingsData.notificationHistoryMaxAgeDays; - if (maxAgeDays <= 0) - return; - - const now = Date.now(); - const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000; - const toRemove = historyList.filter(item => (now - item.timestamp) > maxAgeMs); - const pruned = historyList.filter(item => (now - item.timestamp) <= maxAgeMs); - - if (pruned.length !== historyList.length) { - for (const item of toRemove) { - _deleteCachedImage(item.image); - } - historyList = pruned; - saveHistory(); - } - } - - function deleteHistory() { - for (const item of historyList) { - _deleteCachedImage(item.image); - } - historyList = []; - historyAdapter.notifications = []; - historyFileView.writeAdapter(); - } - - function onOverlayOpen() { - popupsDisabled = true; - addGate.stop(); - addGateBusy = false; - - notificationQueue = []; - for (const w of visibleNotifications) { - if (w) { - w.popup = false; - } - } - visibleNotifications = []; - _recomputeGroupsLater(); - pruneHistory(); - } - - function onOverlayClose() { - popupsDisabled = false; - processQueue(); - } - - Timer { - id: addGate - interval: 80 - running: false - repeat: false - onTriggered: { - addGateBusy = false; - processQueue(); - } - } - - Timer { - id: timeUpdateTimer - interval: 30000 - repeat: true - running: root.allWrappers.length > 0 || visibleNotifications.length > 0 - triggeredOnStart: false - onTriggered: { - root.timeUpdateTick = !root.timeUpdateTick; - } - } - - Timer { - id: dismissPump - interval: _dismissTickMs - repeat: true - running: false - onTriggered: { - let n = Math.min(_dismissBatchSize, _dismissQueue.length); - for (var i = 0; i < n; ++i) { - const w = _dismissQueue.pop(); - try { - if (w && w.notification) { - w.notification.dismiss(); - } - } catch (e) {} - } - if (_dismissQueue.length === 0) { - dismissPump.stop(); - _suspendGrouping = false; - bulkDismissing = false; - popupsDisabled = false; - _recomputeGroupsLater(); - } - } - } - - Timer { - id: groupsDebounce - interval: 16 - repeat: false - onTriggered: _recomputeGroups() - } - - property bool timeUpdateTick: false - property bool clockFormatChanged: false - - readonly property var groupedNotifications: _groupCache.notifications - readonly property var groupedPopups: _groupCache.popups - - property var expandedGroups: ({}) - property var expandedMessages: ({}) - property bool popupsDisabled: false - - NotificationServer { - id: server - - keepOnReload: false - actionsSupported: true - actionIconsSupported: true - bodyHyperlinksSupported: true - bodyImagesSupported: true - bodyMarkupSupported: true - imageSupported: true - inlineReplySupported: true - persistenceSupported: true - - onNotification: notif => { - notif.tracked = true; - - const policy = _evaluateNotificationPolicy(notif); - if (policy.drop) { - try { - notif.dismiss(); - } catch (e) {} - return; - } - - if (!_ingressAllowed(policy.urgency)) { - if (policy.urgency !== NotificationUrgency.Critical) { - try { - notif.dismiss(); - } catch (e) {} - return; - } - } - - if (SettingsData.soundsEnabled && SettingsData.soundNewNotification) { - if (policy.urgency === NotificationUrgency.Critical) { - AudioService.playCriticalNotificationSound(); - } else { - AudioService.playNormalNotificationSound(); - } - } - - const shouldShowPopup = !root.popupsDisabled && !SessionData.doNotDisturb && !policy.disablePopup; - const isTransient = notif.transient; - const shouldKeepInCenter = !isTransient && !policy.hideFromCenter; - - if (!shouldShowPopup && !shouldKeepInCenter) { - try { - notif.dismiss(); - } catch (e) {} - return; - } - - const wrapper = notifComponent.createObject(root, { - "popup": shouldShowPopup, - "notification": notif, - "urgencyOverride": policy.urgency - }); - - if (wrapper) { - root.allWrappers.push(wrapper); - if (shouldKeepInCenter) { - root.notifications.push(wrapper); - if (_shouldSaveToHistory(wrapper.urgency, policy.disableHistory)) { - root.addToHistory(wrapper); - } - } - Qt.callLater(() => { - _initWrapperPersistence(wrapper); - }); - - if (shouldShowPopup) { - _enqueuePopup(wrapper); - processQueue(); - } - } - - _recomputeGroupsLater(); - } - } - - component NotifWrapper: QtObject { - id: wrapper - - property bool popup: false - property bool removedByLimit: false - property bool isPersistent: true - property int seq: 0 - property string persistedImagePath: "" - - onPopupChanged: { - if (!popup) { - removeFromVisibleNotifications(wrapper); - } - } - - readonly property Timer timer: Timer { - interval: { - if (!wrapper.notification) - return 5000; - switch (wrapper.urgency) { - case NotificationUrgency.Low: - return SettingsData.notificationTimeoutLow; - case NotificationUrgency.Critical: - return SettingsData.notificationTimeoutCritical; - default: - return SettingsData.notificationTimeoutNormal; - } - } - repeat: false - running: false - onTriggered: { - if (interval > 0) { - wrapper.popup = false; - } - } - } - - readonly property date time: new Date() - readonly property string timeStr: { - root.timeUpdateTick; - root.clockFormatChanged; - - const now = new Date(); - const diff = now.getTime() - time.getTime(); - const minutes = Math.floor(diff / 60000); - const hours = Math.floor(minutes / 60); - - if (hours < 1) { - if (minutes < 1) { - return "now"; - } - return `${minutes}m ago`; - } - - const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - const timeDate = new Date(time.getFullYear(), time.getMonth(), time.getDate()); - const daysDiff = Math.floor((nowDate - timeDate) / (1000 * 60 * 60 * 24)); - - if (daysDiff === 0) { - return formatTime(time); - } - - try { - const localeName = (typeof I18n !== "undefined" && I18n.locale) ? I18n.locale().name : "en-US"; - const weekday = time.toLocaleDateString(localeName, { - weekday: "long" - }); - return `${weekday}, ${formatTime(time)}`; - } catch (e) { - return formatTime(time); - } - } - - function formatTime(date) { - let use24Hour = true; - try { - if (typeof SettingsData !== "undefined" && SettingsData.use24HourClock !== undefined) { - use24Hour = SettingsData.use24HourClock; - } - } catch (e) { - use24Hour = true; - } - - if (use24Hour) { - return date.toLocaleTimeString(Qt.locale(), "HH:mm"); - } else { - return date.toLocaleTimeString(Qt.locale(), "h:mm AP"); - } - } - - required property Notification notification - readonly property string summary: (notification?.summary ?? "").replace(/]*>/gi, "") - readonly property string body: (notification?.body ?? "").replace(/]*>/gi, "") - readonly property string htmlBody: root._resolveHtmlBody(body) - readonly property string appIcon: notification?.appIcon ?? "" - readonly property string appName: { - if (!notification) - return "app"; - if (notification.appName == "") { - const entry = DesktopEntries.heuristicLookup(notification.desktopEntry); - if (entry && entry.name) - return entry.name.toLowerCase(); - } - return notification.appName || "app"; - } - readonly property string desktopEntry: notification?.desktopEntry ?? "" - readonly property string image: notification?.image ?? "" - readonly property string cleanImage: { - if (!image) - return ""; - return Paths.strip(image); - } - property int urgencyOverride: notification?.urgency ?? NotificationUrgency.Normal - readonly property int urgency: urgencyOverride - readonly property list actions: notification?.actions ?? [] - - readonly property Connections conn: Connections { - target: wrapper.notification?.Retainable ?? null - - function onDropped(): void { - root.allWrappers = root.allWrappers.filter(w => w !== wrapper); - root.notifications = root.notifications.filter(w => w !== wrapper); - - if (root.bulkDismissing) { - return; - } - - const groupKey = getGroupKey(wrapper); - const remainingInGroup = root.notifications.filter(n => getGroupKey(n) === groupKey); - - if (remainingInGroup.length <= 1) { - clearGroupExpansionState(groupKey); - } - - cleanupExpansionStates(); - root._recomputeGroupsLater(); - } - - function onAboutToDestroy(): void { - wrapper.destroy(); - } - } - } - - Component { - id: notifComponent - NotifWrapper {} - } - - function dismissAllPopups() { - for (const w of visibleNotifications) { - if (w) { - w.popup = false; - } - } - visibleNotifications = []; - notificationQueue = []; - } - - function clearAllNotifications() { - if (!notifications.length) { - return; - } - bulkDismissing = true; - popupsDisabled = true; - addGate.stop(); - addGateBusy = false; - notificationQueue = []; - - for (const w of allWrappers) { - if (w) { - w.popup = false; - } - } - visibleNotifications = []; - - _dismissQueue = notifications.slice(); - if (notifications.length) { - notifications = []; - } - expandedGroups = {}; - expandedMessages = {}; - - _suspendGrouping = true; - - if (!dismissPump.running && _dismissQueue.length) { - dismissPump.start(); - } - } - - function dismissNotification(wrapper) { - if (!wrapper || !wrapper.notification) { - return; - } - wrapper.popup = false; - wrapper.notification.dismiss(); - } - - function disablePopups(disable) { - popupsDisabled = disable; - if (disable) { - notificationQueue = []; - for (const notif of visibleNotifications) { - notif.popup = false; - } - visibleNotifications = []; - } - } - - property bool _processingQueue: false - - function processQueue() { - if (addGateBusy || _processingQueue) - return; - if (popupsDisabled) - return; - if (SessionData.doNotDisturb) - return; - if (notificationQueue.length === 0) - return; - - _processingQueue = true; - - const next = notificationQueue.shift(); - if (!next) { - _processingQueue = false; - return; - } - - next.seq = ++seqCounter; - - const activePopups = visibleNotifications.filter(n => n && n.popup); - let evicted = null; - if (activePopups.length >= maxVisibleNotifications) { - const unhovered = activePopups.filter(n => n.timer?.running); - const pool = unhovered.length > 0 ? unhovered : activePopups; - evicted = pool.reduce((min, n) => (n.seq < min.seq) ? n : min, pool[0]); - if (evicted) - evicted.removedByLimit = true; - } - - if (evicted) { - visibleNotifications = [...visibleNotifications.filter(n => n !== evicted), next]; - } else { - visibleNotifications = [...visibleNotifications, next]; - } - - if (evicted) - evicted.popup = false; - next.popup = true; - - if (next.timer.interval > 0) - next.timer.start(); - - addGateBusy = true; - addGate.restart(); - _processingQueue = false; - } - - function removeFromVisibleNotifications(wrapper) { - visibleNotifications = visibleNotifications.filter(n => n !== wrapper); - processQueue(); - } - - function releaseWrapper(w) { - visibleNotifications = visibleNotifications.filter(n => n !== w); - notificationQueue = notificationQueue.filter(n => n !== w); - - if (w && w.destroy && !w.isPersistent && notifications.indexOf(w) === -1) { - Qt.callLater(() => { - try { - w.destroy(); - } catch (e) {} - }); - } - } - - function _decodeEntities(s) { - s = s.replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(parseInt(n, 10))); - s = s.replace(/&#x([0-9a-fA-F]+);/g, (_, n) => String.fromCodePoint(parseInt(n, 16))); - return s.replace(/&([a-zA-Z][a-zA-Z0-9]*);/g, (match, name) => { - switch (name) { - case "amp": - return "&"; - case "lt": - return "<"; - case "gt": - return ">"; - case "quot": - return "\""; - case "apos": - return "'"; - case "nbsp": - return "\u00A0"; - case "ndash": - return "\u2013"; - case "mdash": - return "\u2014"; - case "lsquo": - return "\u2018"; - case "rsquo": - return "\u2019"; - case "ldquo": - return "\u201C"; - case "rdquo": - return "\u201D"; - case "bull": - return "\u2022"; - case "hellip": - return "\u2026"; - case "trade": - return "\u2122"; - case "copy": - return "\u00A9"; - case "reg": - return "\u00AE"; - case "deg": - return "\u00B0"; - case "plusmn": - return "\u00B1"; - case "times": - return "\u00D7"; - case "divide": - return "\u00F7"; - case "micro": - return "\u00B5"; - case "middot": - return "\u00B7"; - case "laquo": - return "\u00AB"; - case "raquo": - return "\u00BB"; - case "larr": - return "\u2190"; - case "rarr": - return "\u2192"; - case "uarr": - return "\u2191"; - case "darr": - return "\u2193"; - default: - return match; - } - }); - } - - function _resolveHtmlBody(body) { - if (!body) - return ""; - - let result = body; - - if (/<\/?[a-z][\s\S]*>/i.test(body)) { - result = body; - } else { - // Decode percent-encoded URLs (e.g. https%3A%2F%2F → https://) - let processed = body.replace(/\bhttps?%3A%2F%2F[^\s]+/gi, match => { - try { - return decodeURIComponent(match); - } catch (e) { - return match; - } - }); - - if (/&(#\d+|#x[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]+);/.test(processed)) { - const decoded = _decodeEntities(processed); - if (/<\/?[a-z][\s\S]*>/i.test(decoded)) - result = decoded; - else - result = Markdown2Html.markdownToHtml(decoded); - } else { - result = Markdown2Html.markdownToHtml(processed); - } - } - - // Strip out image tags to prevent IP tracking - return result.replace(/]*>/gi, ""); - } - - function getGroupKey(wrapper) { - if (wrapper.desktopEntry && wrapper.desktopEntry !== "") { - return wrapper.desktopEntry.toLowerCase(); - } - - return wrapper.appName.toLowerCase(); - } - - function _recomputeGroups() { - if (_suspendGrouping) { - _groupsDirty = true; - return; - } - _groupCache = { - "notifications": _calcGroupedNotifications(), - "popups": _calcGroupedPopups() - }; - _groupsDirty = false; - } - - function _recomputeGroupsLater() { - _groupsDirty = true; - if (!groupsDebounce.running) { - groupsDebounce.start(); - } - } - - function _calcGroupedNotifications() { - const groups = {}; - - for (const notif of notifications) { - if (!notif || !notif.notification) - continue; - const groupKey = getGroupKey(notif); - if (!groups[groupKey]) { - groups[groupKey] = { - "key": groupKey, - "appName": notif.appName, - "notifications": [], - "latestNotification": null, - "count": 0, - "hasInlineReply": false - }; - } - - groups[groupKey].notifications.unshift(notif); - groups[groupKey].latestNotification = groups[groupKey].notifications[0]; - groups[groupKey].count = groups[groupKey].notifications.length; - - if (notif.notification?.hasInlineReply) - groups[groupKey].hasInlineReply = true; - } - - return Object.values(groups).sort((a, b) => { - if (!a.latestNotification || !b.latestNotification) - return 0; - const aUrgency = a.latestNotification.urgency ?? NotificationUrgency.Low; - const bUrgency = b.latestNotification.urgency ?? NotificationUrgency.Low; - if (aUrgency !== bUrgency) { - return bUrgency - aUrgency; - } - return b.latestNotification.time.getTime() - a.latestNotification.time.getTime(); - }); - } - - function _calcGroupedPopups() { - const groups = {}; - - for (const notif of popups) { - if (!notif || !notif.notification) - continue; - const groupKey = getGroupKey(notif); - if (!groups[groupKey]) { - groups[groupKey] = { - "key": groupKey, - "appName": notif.appName, - "notifications": [], - "latestNotification": null, - "count": 0, - "hasInlineReply": false - }; - } - - groups[groupKey].notifications.unshift(notif); - groups[groupKey].latestNotification = groups[groupKey].notifications[0]; - groups[groupKey].count = groups[groupKey].notifications.length; - - if (notif.notification?.hasInlineReply) - groups[groupKey].hasInlineReply = true; - } - - return Object.values(groups).sort((a, b) => { - if (!a.latestNotification || !b.latestNotification) - return 0; - return b.latestNotification.time.getTime() - a.latestNotification.time.getTime(); - }); - } - - function toggleGroupExpansion(groupKey) { - let newExpandedGroups = {}; - for (const key in expandedGroups) { - newExpandedGroups[key] = expandedGroups[key]; - } - newExpandedGroups[groupKey] = !newExpandedGroups[groupKey]; - expandedGroups = newExpandedGroups; - } - - function dismissGroup(groupKey) { - const group = groupedNotifications.find(g => g.key === groupKey); - if (group) { - for (const notif of group.notifications) { - if (notif && notif.notification) { - notif.notification.dismiss(); - } - } - } else { - for (const notif of allWrappers) { - if (notif && notif.notification && getGroupKey(notif) === groupKey) { - notif.notification.dismiss(); - } - } - } - } - - function clearGroupExpansionState(groupKey) { - let newExpandedGroups = {}; - for (const key in expandedGroups) { - if (key !== groupKey && expandedGroups[key]) { - newExpandedGroups[key] = true; - } - } - expandedGroups = newExpandedGroups; - } - - function cleanupExpansionStates() { - const currentGroupKeys = new Set(groupedNotifications.map(g => g.key)); - const currentMessageIds = new Set(); - for (const group of groupedNotifications) { - for (const notif of group.notifications) { - if (notif && notif.notification) { - currentMessageIds.add(notif.notification.id); - } - } - } - let newExpandedGroups = {}; - for (const key in expandedGroups) { - if (currentGroupKeys.has(key) && expandedGroups[key]) { - newExpandedGroups[key] = true; - } - } - expandedGroups = newExpandedGroups; - let newExpandedMessages = {}; - for (const messageId in expandedMessages) { - if (currentMessageIds.has(messageId) && expandedMessages[messageId]) { - newExpandedMessages[messageId] = true; - } - } - expandedMessages = newExpandedMessages; - } - - function toggleMessageExpansion(messageId) { - let newExpandedMessages = {}; - for (const key in expandedMessages) { - newExpandedMessages[key] = expandedMessages[key]; - } - newExpandedMessages[messageId] = !newExpandedMessages[messageId]; - expandedMessages = newExpandedMessages; - } - - Connections { - target: SessionData - function onDoNotDisturbChanged() { - if (SessionData.doNotDisturb) { - // Hide all current popups when DND is enabled - for (const notif of visibleNotifications) { - notif.popup = false; - } - visibleNotifications = []; - notificationQueue = []; - } else { - // Re-enable popup processing when DND is disabled - processQueue(); - } - } - } - - Connections { - target: typeof SettingsData !== "undefined" ? SettingsData : null - function onUse24HourClockChanged() { - root.clockFormatChanged = !root.clockFormatChanged; - } - function onNotificationHistoryMaxAgeDaysChanged() { - root.pruneHistory(); - } - function onNotificationHistoryEnabledChanged() { - if (!SettingsData.notificationHistoryEnabled) { - root.deleteHistory(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml deleted file mode 100644 index 03f9be6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml +++ /dev/null @@ -1,876 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Qt.labs.folderlistmodel -import Quickshell -import qs.Common -import qs.Services - -Singleton { - id: root - - property var availablePlugins: ({}) - property var loadedPlugins: ({}) - property var pluginWidgetComponents: ({}) - property var pluginDaemonComponents: ({}) - property var pluginLauncherComponents: ({}) - property var pluginDesktopComponents: ({}) - property var availablePluginsList: [] - property string pluginDirectory: { - var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation); - var configDirStr = configDir.toString(); - if (configDirStr.startsWith("file://")) { - configDirStr = configDirStr.substring(7); - } - return configDirStr + "/DankMaterialShell/plugins"; - } - property string systemPluginDirectory: "/etc/xdg/quickshell/dms-plugins" - - property var knownManifests: ({}) - property var pathToPluginId: ({}) - property var pluginInstances: ({}) - property var globalVars: ({}) - - property var _stateCache: ({}) - property var _stateLoaded: ({}) - property var _stateWriters: ({}) - property var _stateDirtyPlugins: ({}) - property bool _stateDirCreated: false - - signal pluginLoaded(string pluginId) - signal pluginUnloaded(string pluginId) - signal pluginLoadFailed(string pluginId, string error) - signal pluginDataChanged(string pluginId) - signal pluginStateChanged(string pluginId) - signal pluginListUpdated - signal globalVarChanged(string pluginId, string varName) - signal requestLauncherUpdate(string pluginId) - - Timer { - id: resyncDebounce - interval: 120 - repeat: false - onTriggered: resyncAll() - } - - Timer { - id: _stateWriteTimer - interval: 150 - repeat: false - onTriggered: root._flushDirtyStates() - } - - Component.onCompleted: { - userWatcher.folder = Paths.toFileUrl(root.pluginDirectory); - systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory); - Qt.callLater(resyncAll); - } - - FolderListModel { - id: userWatcher - showDirs: true - showFiles: false - showDotAndDotDot: false - - onCountChanged: resyncDebounce.restart() - onStatusChanged: { - if (status === FolderListModel.Ready) - resyncDebounce.restart(); - } - } - - FolderListModel { - id: systemWatcher - showDirs: true - showFiles: false - showDotAndDotDot: false - - onCountChanged: resyncDebounce.restart() - onStatusChanged: { - if (status === FolderListModel.Ready) - resyncDebounce.restart(); - } - } - - function snapshotModel(model, sourceTag) { - const out = []; - const n = model.count; - const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory; - for (let i = 0; i < n; i++) { - let dirPath = model.get(i, "filePath"); - if (dirPath.startsWith("file://")) { - dirPath = dirPath.substring(7); - } - if (!dirPath.startsWith(baseDir)) { - continue; - } - const manifestPath = dirPath + "/plugin.json"; - out.push({ - path: manifestPath, - source: sourceTag - }); - } - return out; - } - - function resyncAll() { - const userList = snapshotModel(userWatcher, "user"); - const sysList = snapshotModel(systemWatcher, "system"); - const seenPaths = {}; - - function consider(entry) { - const key = entry.path; - seenPaths[key] = true; - const prev = knownManifests[key]; - if (!prev) { - loadPluginManifestFile(entry.path, entry.source, Date.now()); - } - } - for (let i = 0; i < userList.length; i++) - consider(userList[i]); - for (let i = 0; i < sysList.length; i++) - consider(sysList[i]); - - const removed = []; - for (const path in knownManifests) { - if (!seenPaths[path]) - removed.push(path); - } - if (removed.length) { - removed.forEach(function (path) { - const pid = pathToPluginId[path]; - if (pid) { - unregisterPluginByPath(path, pid); - } - delete knownManifests[path]; - delete pathToPluginId[path]; - }); - _updateAvailablePluginsList(); - pluginListUpdated(); - } - } - - function loadPluginManifestFile(manifestPathNoScheme, sourceTag, mtimeEpochMs) { - const manifestId = "m_" + Math.random().toString(36).slice(2); - const qml = ` - import QtQuick - import Quickshell.Io - FileView { - id: fv - property string absPath: "" - onLoaded: { - try { - let raw = text() - if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1) - const manifest = JSON.parse(raw) - root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs}) - } catch (e) { - console.error("PluginService: bad manifest", absPath, e.message) - knownManifests[absPath] = { mtime: ${mtimeEpochMs}, source: "${sourceTag}", bad: true } - } - fv.destroy() - } - onLoadFailed: (err) => { - console.warn("PluginService: manifest load failed", absPath, err) - fv.destroy() - } - } - `; - - const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId); - loader.absPath = manifestPathNoScheme; - loader.path = manifestPathNoScheme; - } - - function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) { - if (!manifest || !manifest.id || !manifest.name || !manifest.component) { - console.error("PluginService: invalid manifest fields:", absPath); - knownManifests[absPath] = { - mtime: mtimeEpochMs, - source: sourceTag, - bad: true - }; - return; - } - - const dir = absPath.substring(0, absPath.lastIndexOf('/')); - let comp = manifest.component; - if (comp.startsWith("./")) - comp = comp.slice(2); - let settings = manifest.settings; - if (settings && settings.startsWith("./")) - settings = settings.slice(2); - - const info = {}; - for (const k in manifest) - info[k] = manifest[k]; - - let perms = manifest.permissions; - if (typeof perms === "string") { - perms = perms.split(/\s*,\s*/); - } - if (!Array.isArray(perms)) { - perms = []; - } - info.permissions = perms.map(p => String(p).trim()); - - info.manifestPath = absPath; - info.pluginDirectory = dir; - info.componentPath = dir + "/" + comp; - info.settingsPath = settings ? (dir + "/" + settings) : null; - info.loaded = isPluginLoaded(manifest.id); - info.type = manifest.type || "widget"; - info.source = sourceTag; - info.requires_dms = manifest.requires_dms || null; - - const existing = availablePlugins[manifest.id]; - const shouldReplace = (!existing) || (existing && existing.source === "system" && sourceTag === "user"); - - if (shouldReplace) { - if (existing && existing.loaded && existing.source !== sourceTag) { - unloadPlugin(manifest.id); - } - const newMap = Object.assign({}, availablePlugins); - newMap[manifest.id] = info; - availablePlugins = newMap; - pathToPluginId[absPath] = manifest.id; - knownManifests[absPath] = { - mtime: mtimeEpochMs, - source: sourceTag - }; - _updateAvailablePluginsList(); - pluginListUpdated(); - const enabled = info.type === "desktop" || SettingsData.getPluginSetting(manifest.id, "enabled", false); - if (enabled && !info.loaded) - loadPlugin(manifest.id); - } else { - knownManifests[absPath] = { - mtime: mtimeEpochMs, - source: sourceTag, - shadowedBy: existing.source - }; - pathToPluginId[absPath] = manifest.id; - } - } - - function unregisterPluginByPath(absPath, pluginId) { - const current = availablePlugins[pluginId]; - if (current && current.manifestPath === absPath) { - if (current.loaded) - unloadPlugin(pluginId); - const newMap = Object.assign({}, availablePlugins); - delete newMap[pluginId]; - availablePlugins = newMap; - } - } - - function loadPlugin(pluginId, bustCache) { - const plugin = availablePlugins[pluginId]; - if (!plugin) { - console.error("PluginService: Plugin not found:", pluginId); - pluginLoadFailed(pluginId, "Plugin not found"); - return false; - } - - if (plugin.loaded) { - return true; - } - - const isDaemon = plugin.type === "daemon"; - const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); - const isDesktop = plugin.type === "desktop"; - - const prevInstance = pluginInstances[pluginId]; - if (prevInstance) { - prevInstance.destroy(); - const newInstances = Object.assign({}, pluginInstances); - delete newInstances[pluginId]; - pluginInstances = newInstances; - } - - try { - let url = "file://" + plugin.componentPath; - if (bustCache) - url += "?t=" + Date.now(); - const comp = Qt.createComponent(url, Component.PreferSynchronous); - if (comp.status === Component.Error) { - console.error("PluginService: component error", pluginId, comp.errorString()); - pluginLoadFailed(pluginId, comp.errorString()); - return false; - } - - if (isDaemon) { - const newDaemons = Object.assign({}, pluginDaemonComponents); - newDaemons[pluginId] = comp; - pluginDaemonComponents = newDaemons; - } else if (isLauncher) { - const instance = comp.createObject(root, { - "pluginService": root - }); - if (!instance) { - console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString()); - pluginLoadFailed(pluginId, comp.errorString()); - return false; - } - const newInstances = Object.assign({}, pluginInstances); - newInstances[pluginId] = instance; - pluginInstances = newInstances; - - const newLaunchers = Object.assign({}, pluginLauncherComponents); - newLaunchers[pluginId] = comp; - pluginLauncherComponents = newLaunchers; - } else if (isDesktop) { - const newDesktop = Object.assign({}, pluginDesktopComponents); - newDesktop[pluginId] = comp; - pluginDesktopComponents = newDesktop; - } else { - const newComponents = Object.assign({}, pluginWidgetComponents); - newComponents[pluginId] = comp; - pluginWidgetComponents = newComponents; - } - - plugin.loaded = true; - const newLoaded = Object.assign({}, loadedPlugins); - newLoaded[pluginId] = plugin; - loadedPlugins = newLoaded; - - pluginLoaded(pluginId); - return true; - } catch (e) { - console.error("PluginService: Error loading plugin:", pluginId, e.message); - pluginLoadFailed(pluginId, e.message); - return false; - } - } - - function unloadPlugin(pluginId) { - const plugin = loadedPlugins[pluginId]; - if (!plugin) { - console.warn("PluginService: Plugin not loaded:", pluginId); - return false; - } - - try { - const isDaemon = plugin.type === "daemon"; - const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); - const isDesktop = plugin.type === "desktop"; - - const instance = pluginInstances[pluginId]; - if (instance) { - instance.destroy(); - const newInstances = Object.assign({}, pluginInstances); - delete newInstances[pluginId]; - pluginInstances = newInstances; - } - - if (isDaemon && pluginDaemonComponents[pluginId]) { - const newDaemons = Object.assign({}, pluginDaemonComponents); - delete newDaemons[pluginId]; - pluginDaemonComponents = newDaemons; - } else if (isLauncher && pluginLauncherComponents[pluginId]) { - const newLaunchers = Object.assign({}, pluginLauncherComponents); - delete newLaunchers[pluginId]; - pluginLauncherComponents = newLaunchers; - } else if (isDesktop && pluginDesktopComponents[pluginId]) { - const newDesktop = Object.assign({}, pluginDesktopComponents); - delete newDesktop[pluginId]; - pluginDesktopComponents = newDesktop; - } else if (pluginWidgetComponents[pluginId]) { - const newComponents = Object.assign({}, pluginWidgetComponents); - delete newComponents[pluginId]; - pluginWidgetComponents = newComponents; - } - - plugin.loaded = false; - const newLoaded = Object.assign({}, loadedPlugins); - delete newLoaded[pluginId]; - loadedPlugins = newLoaded; - - _cleanupPluginStateWriter(pluginId); - pluginUnloaded(pluginId); - return true; - } catch (error) { - console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message); - return false; - } - } - - function getWidgetComponents() { - return pluginWidgetComponents; - } - - function getDaemonComponents() { - return pluginDaemonComponents; - } - - function getDesktopComponents() { - return pluginDesktopComponents; - } - - function getAvailablePlugins() { - return availablePluginsList; - } - - function _updateAvailablePluginsList() { - const result = []; - for (const key in availablePlugins) { - result.push(availablePlugins[key]); - } - availablePluginsList = result; - } - - function getPluginVariants(pluginId) { - const plugin = availablePlugins[pluginId]; - if (!plugin) { - return []; - } - const variants = SettingsData.getPluginSetting(pluginId, "variants", []); - return variants; - } - - function getAllPluginVariants() { - const result = []; - for (const pluginId in availablePlugins) { - const plugin = availablePlugins[pluginId]; - if (plugin.type !== "widget") { - continue; - } - const variants = getPluginVariants(pluginId); - if (variants.length === 0) { - result.push({ - pluginId: pluginId, - variantId: null, - fullId: pluginId, - name: plugin.name, - icon: plugin.icon || "extension", - description: plugin.description || "Plugin widget", - loaded: plugin.loaded - }); - } else { - for (let i = 0; i < variants.length; i++) { - const variant = variants[i]; - result.push({ - pluginId: pluginId, - variantId: variant.id, - fullId: pluginId + ":" + variant.id, - name: plugin.name + " - " + variant.name, - icon: variant.icon || plugin.icon || "extension", - description: variant.description || plugin.description || "Plugin widget variant", - loaded: plugin.loaded - }); - } - } - } - return result; - } - - function createPluginVariant(pluginId, variantName, variantConfig) { - const variants = getPluginVariants(pluginId); - const variantId = "variant_" + Date.now(); - const newVariant = Object.assign({}, variantConfig, { - id: variantId, - name: variantName - }); - variants.push(newVariant); - SettingsData.setPluginSetting(pluginId, "variants", variants); - pluginDataChanged(pluginId); - return variantId; - } - - function removePluginVariant(pluginId, variantId) { - const variants = getPluginVariants(pluginId); - const newVariants = variants.filter(function (v) { - return v.id !== variantId; - }); - SettingsData.setPluginSetting(pluginId, "variants", newVariants); - - const fullId = pluginId + ":" + variantId; - removeWidgetFromDankBar(fullId); - - pluginDataChanged(pluginId); - } - - function removeWidgetFromDankBar(widgetId) { - function filterWidget(widget) { - const id = typeof widget === "string" ? widget : widget.id; - return id !== widgetId; - } - - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return; - const leftWidgets = defaultBar.leftWidgets || []; - const centerWidgets = defaultBar.centerWidgets || []; - const rightWidgets = defaultBar.rightWidgets || []; - - const newLeft = leftWidgets.filter(filterWidget); - const newCenter = centerWidgets.filter(filterWidget); - const newRight = rightWidgets.filter(filterWidget); - - if (newLeft.length !== leftWidgets.length) { - SettingsData.setDankBarLeftWidgets(newLeft); - } - if (newCenter.length !== centerWidgets.length) { - SettingsData.setDankBarCenterWidgets(newCenter); - } - if (newRight.length !== rightWidgets.length) { - SettingsData.setDankBarRightWidgets(newRight); - } - } - - function updatePluginVariant(pluginId, variantId, variantConfig) { - const variants = getPluginVariants(pluginId); - for (let i = 0; i < variants.length; i++) { - if (variants[i].id === variantId) { - variants[i] = Object.assign({}, variants[i], variantConfig); - break; - } - } - SettingsData.setPluginSetting(pluginId, "variants", variants); - pluginDataChanged(pluginId); - } - - function getPluginVariantData(pluginId, variantId) { - const variants = getPluginVariants(pluginId); - for (let i = 0; i < variants.length; i++) { - if (variants[i].id === variantId) { - return variants[i]; - } - } - return null; - } - - function getLoadedPlugins() { - const result = []; - for (const key in loadedPlugins) { - result.push(loadedPlugins[key]); - } - return result; - } - - function isPluginLoaded(pluginId) { - return loadedPlugins[pluginId] !== undefined; - } - - function enablePlugin(pluginId) { - SettingsData.setPluginSetting(pluginId, "enabled", true); - return loadPlugin(pluginId); - } - - function disablePlugin(pluginId) { - SettingsData.setPluginSetting(pluginId, "enabled", false); - return unloadPlugin(pluginId); - } - - function reloadPlugin(pluginId) { - if (isPluginLoaded(pluginId)) - unloadPlugin(pluginId); - return loadPlugin(pluginId, true); - } - - function togglePlugin(pluginId) { - let instance = pluginInstances[pluginId]; - - // Lazy instantiate daemon plugins on first toggle - // This respects the daemon lifecycle (not instantiated on load) - // while supporting toggle functionality for slideout-capable daemons - if (!instance && pluginDaemonComponents[pluginId]) { - const comp = pluginDaemonComponents[pluginId]; - const newInstance = comp.createObject(root, { - "pluginId": pluginId, - "pluginService": root - }); - if (newInstance) { - const newInstances = Object.assign({}, pluginInstances); - newInstances[pluginId] = newInstance; - pluginInstances = newInstances; - instance = newInstance; - } - } - - if (instance && typeof instance.toggle === "function") { - instance.toggle(); - return true; - } - return false; - } - - function savePluginData(pluginId, key, value) { - SettingsData.setPluginSetting(pluginId, key, value); - pluginDataChanged(pluginId); - return true; - } - - function loadPluginData(pluginId, key, defaultValue) { - return SettingsData.getPluginSetting(pluginId, key, defaultValue); - } - - function getPluginPath(pluginId) { - const plugin = availablePlugins[pluginId]; - if (!plugin) - return ""; - return plugin.pluginDirectory || ""; - } - - function saveAllPluginSettings() { - SettingsData.savePluginSettings(); - } - - function getPluginStatePath(pluginId) { - return Paths.strip(Paths.state) + "/plugins/" + pluginId + "_state.json"; - } - - function loadPluginState(pluginId, key, defaultValue) { - if (!_stateLoaded[pluginId]) - _loadStateFromDisk(pluginId); - const state = _stateCache[pluginId]; - if (!state) - return defaultValue; - return state[key] !== undefined ? state[key] : defaultValue; - } - - function savePluginState(pluginId, key, value) { - if (!_stateLoaded[pluginId]) - _loadStateFromDisk(pluginId); - if (!_stateCache[pluginId]) - _stateCache[pluginId] = {}; - _stateCache[pluginId][key] = value; - _stateDirtyPlugins[pluginId] = true; - _stateWriteTimer.restart(); - pluginStateChanged(pluginId); - } - - function clearPluginState(pluginId) { - _stateCache[pluginId] = {}; - _stateLoaded[pluginId] = true; - _flushStateToDisk(pluginId); - pluginStateChanged(pluginId); - } - - function removePluginStateKey(pluginId, key) { - if (!_stateCache[pluginId]) - return; - delete _stateCache[pluginId][key]; - _stateDirtyPlugins[pluginId] = true; - _stateWriteTimer.restart(); - pluginStateChanged(pluginId); - } - - function _ensureStateDir() { - if (_stateDirCreated) - return; - _stateDirCreated = true; - Paths.mkdir(Paths.state + "/plugins"); - } - - function _loadStateFromDisk(pluginId) { - _stateLoaded[pluginId] = true; - _ensureStateDir(); - const path = getPluginStatePath(pluginId); - const escapedPath = path.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); - try { - const qml = 'import QtQuick; import Quickshell.Io; FileView { path: "' + escapedPath + '"; blockLoading: true; blockWrites: true; atomicWrites: true }'; - const fv = Qt.createQmlObject(qml, root, "sf_" + pluginId); - const raw = fv.text(); - if (raw && raw.trim()) { - _stateCache[pluginId] = JSON.parse(raw); - } else { - _stateCache[pluginId] = {}; - } - _stateWriters[pluginId] = fv; - } catch (e) { - _stateCache[pluginId] = {}; - } - } - - function _flushStateToDisk(pluginId) { - _ensureStateDir(); - const content = JSON.stringify(_stateCache[pluginId] || {}, null, 2); - if (_stateWriters[pluginId]) { - _stateWriters[pluginId].setText(content); - return; - } - const path = getPluginStatePath(pluginId); - const escapedPath = path.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); - try { - const qml = 'import QtQuick; import Quickshell.Io; FileView { path: "' + escapedPath + '"; blockWrites: true; atomicWrites: true }'; - const fv = Qt.createQmlObject(qml, root, "sw_" + pluginId); - _stateWriters[pluginId] = fv; - fv.loaded.connect(function () { - fv.setText(content); - }); - fv.loadFailed.connect(function () { - fv.setText(content); - }); - } catch (e) { - console.warn("PluginService: Failed to write state for", pluginId, e.message); - } - } - - function _flushDirtyStates() { - const dirty = _stateDirtyPlugins; - _stateDirtyPlugins = {}; - for (const pluginId in dirty) - _flushStateToDisk(pluginId); - } - - function _cleanupPluginStateWriter(pluginId) { - if (!_stateWriters[pluginId]) - return; - _stateWriters[pluginId].destroy(); - delete _stateWriters[pluginId]; - } - - function scanPlugins() { - const userUrl = Paths.toFileUrl(root.pluginDirectory); - const systemUrl = Paths.toFileUrl(root.systemPluginDirectory); - userWatcher.folder = ""; - userWatcher.folder = userUrl; - systemWatcher.folder = ""; - systemWatcher.folder = systemUrl; - resyncDebounce.restart(); - } - - function forceRescanPlugin(pluginId) { - const plugin = availablePlugins[pluginId]; - if (plugin && plugin.manifestPath) { - const manifestPath = plugin.manifestPath; - const source = plugin.source || "user"; - delete knownManifests[manifestPath]; - const newMap = Object.assign({}, availablePlugins); - delete newMap[pluginId]; - availablePlugins = newMap; - loadPluginManifestFile(manifestPath, source, Date.now()); - } - } - - function createPluginDirectory() { - const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }"); - if (mkdirProcess.status === Component.Ready) { - const process = mkdirProcess.createObject(root); - process.command = ["mkdir", "-p", pluginDirectory]; - process.exited.connect(function (exitCode) { - if (exitCode !== 0) { - console.error("PluginService: Failed to create plugin directory, exit code:", exitCode); - } - process.destroy(); - }); - process.running = true; - return true; - } else { - console.error("PluginService: Failed to create mkdir process"); - return false; - } - } - - // Launcher plugin helper functions - function getLauncherPlugins() { - const launchers = {}; - - // Check plugins that have launcher components - for (const pluginId in pluginLauncherComponents) { - const plugin = availablePlugins[pluginId]; - if (plugin && plugin.loaded) { - launchers[pluginId] = plugin; - } - } - return launchers; - } - - function getLauncherPlugin(pluginId) { - const plugin = availablePlugins[pluginId]; - if (plugin && plugin.loaded && pluginLauncherComponents[pluginId]) { - return plugin; - } - return null; - } - - function getPluginTrigger(pluginId) { - const plugin = getLauncherPlugin(pluginId); - if (plugin) { - // Check if noTrigger is set (always active mode) - const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false); - if (noTrigger) { - return ""; - } - // Otherwise load the custom trigger, defaulting to plugin manifest trigger - const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!"); - return customTrigger; - } - return null; - } - - function getAllPluginTriggers() { - const triggers = {}; - const launchers = getLauncherPlugins(); - - for (const pluginId in launchers) { - const trigger = getPluginTrigger(pluginId); - if (trigger && trigger.trim() !== "") { - triggers[trigger] = pluginId; - } - } - return triggers; - } - - function getPluginsWithEmptyTrigger() { - const plugins = []; - const launchers = getLauncherPlugins(); - - for (const pluginId in launchers) { - const trigger = getPluginTrigger(pluginId); - if (!trigger || trigger.trim() === "") { - plugins.push(pluginId); - } - } - return plugins; - } - - function getPluginViewPreference(pluginId) { - const plugin = availablePlugins[pluginId]; - if (!plugin) - return null; - - return { - mode: plugin.viewMode || null, - enforced: plugin.viewModeEnforced === true - }; - } - - function getGlobalVar(pluginId, varName, defaultValue) { - if (globalVars[pluginId] && varName in globalVars[pluginId]) { - return globalVars[pluginId][varName]; - } - return defaultValue; - } - - function setGlobalVar(pluginId, varName, value) { - const newGlobals = Object.assign({}, globalVars); - if (!newGlobals[pluginId]) { - newGlobals[pluginId] = {}; - } - newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId]); - newGlobals[pluginId][varName] = value; - globalVars = newGlobals; - globalVarChanged(pluginId, varName); - } - - function checkPluginCompatibility(requiresDms) { - if (!requiresDms) - return true; - return SystemUpdateService.checkVersionRequirement(requiresDms, SystemUpdateService.getParsedShellVersion()); - } - - function getIncompatiblePlugins() { - const result = []; - for (const pluginId in availablePlugins) { - const plugin = availablePlugins[pluginId]; - if (plugin.loaded && plugin.requires_dms && !checkPluginCompatibility(plugin.requires_dms)) { - result.push(plugin); - } - } - return result; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml deleted file mode 100644 index 5238d04..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml +++ /dev/null @@ -1,40 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1" - - property bool polkitAvailable: false - property var agent: null - - function createPolkitAgent() { - try { - const qmlString = ` - import QtQuick - import Quickshell.Services.Polkit - - PolkitAgent { - } - ` - - agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent") - polkitAvailable = true - console.info("PolkitService: Initialized successfully") - } catch (e) { - polkitAvailable = false - console.warn("PolkitService: Polkit not available - authentication prompts disabled. This requires a newer version of Quickshell.") - } - } - - Component.onCompleted: { - if (disablePolkitIntegration) { - return - } - createPolkitAgent() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml deleted file mode 100644 index c6e8a09..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml +++ /dev/null @@ -1,709 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -Singleton { - id: root - - property var controlCenterPopout: null - property var controlCenterLoader: null - property var notificationCenterPopout: null - property var notificationCenterLoader: null - property var appDrawerPopout: null - property var appDrawerLoader: null - property var processListPopout: null - property var processListPopoutLoader: null - property var dankDashPopout: null - property var dankDashPopoutLoader: null - property var batteryPopout: null - property var batteryPopoutLoader: null - property var vpnPopout: null - property var vpnPopoutLoader: null - property var systemUpdatePopout: null - property var systemUpdateLoader: null - property var layoutPopout: null - property var layoutPopoutLoader: null - property var clipboardHistoryPopout: null - property var clipboardHistoryPopoutLoader: null - - property var settingsModal: null - property var settingsModalLoader: null - property var clipboardHistoryModal: null - property var dankLauncherV2Modal: null - property var dankLauncherV2ModalLoader: null - property var powerMenuModal: null - property var processListModal: null - property var processListModalLoader: null - property var colorPickerModal: null - property var notificationModal: null - property var wifiPasswordModal: null - property var wifiPasswordModalLoader: null - property var wifiQRCodeModal: null - property var wifiQRCodeModalLoader: null - property var polkitAuthModal: null - property var polkitAuthModalLoader: null - property var bluetoothPairingModal: null - property var networkInfoModal: null - property var windowRuleModalLoader: null - - property var notepadSlideouts: [] - - property string pendingThemeInstall: "" - property string pendingPluginInstall: "" - - function setPosition(popout, x, y, width, section, screen) { - if (popout && popout.setTriggerPosition && arguments.length >= 6) { - popout.setTriggerPosition(x, y, width, section, screen); - } - } - - function openControlCenter(x, y, width, section, screen) { - if (controlCenterPopout) { - setPosition(controlCenterPopout, x, y, width, section, screen); - controlCenterPopout.open(); - } - } - - function closeControlCenter() { - controlCenterPopout?.close(); - } - - function unloadControlCenter() { - if (!controlCenterLoader) - return; - controlCenterPopout = null; - controlCenterLoader.active = false; - } - - function toggleControlCenter(x, y, width, section, screen) { - if (controlCenterPopout) { - setPosition(controlCenterPopout, x, y, width, section, screen); - controlCenterPopout.toggle(); - } - } - - function openNotificationCenter(x, y, width, section, screen) { - if (notificationCenterPopout) { - setPosition(notificationCenterPopout, x, y, width, section, screen); - notificationCenterPopout.open(); - } - } - - function closeNotificationCenter() { - notificationCenterPopout?.close(); - } - - function unloadNotificationCenter() { - if (!notificationCenterLoader) - return; - notificationCenterPopout = null; - notificationCenterLoader.active = false; - } - - function toggleNotificationCenter(x, y, width, section, screen) { - if (notificationCenterPopout) { - setPosition(notificationCenterPopout, x, y, width, section, screen); - notificationCenterPopout.toggle(); - } - } - - function openAppDrawer(x, y, width, section, screen) { - if (appDrawerPopout) { - setPosition(appDrawerPopout, x, y, width, section, screen); - appDrawerPopout.open(); - } - } - - function closeAppDrawer() { - appDrawerPopout?.close(); - } - - function unloadAppDrawer() { - if (!appDrawerLoader) - return; - appDrawerPopout = null; - appDrawerLoader.active = false; - } - - function toggleAppDrawer(x, y, width, section, screen) { - if (appDrawerPopout) { - setPosition(appDrawerPopout, x, y, width, section, screen); - appDrawerPopout.toggle(); - } - } - - function openProcessList(x, y, width, section, screen) { - if (processListPopout) { - setPosition(processListPopout, x, y, width, section, screen); - processListPopout.open(); - } - } - - function closeProcessList() { - processListPopout?.close(); - } - - function unloadProcessListPopout() { - if (!processListPopoutLoader) - return; - processListPopout = null; - processListPopoutLoader.active = false; - } - - function toggleProcessList(x, y, width, section, screen) { - if (processListPopout) { - setPosition(processListPopout, x, y, width, section, screen); - processListPopout.toggle(); - } - } - - property bool _dankDashWantsOpen: false - property bool _dankDashWantsToggle: false - property int _dankDashPendingTab: 0 - property real _dankDashPendingX: 0 - property real _dankDashPendingY: 0 - property real _dankDashPendingWidth: 0 - property string _dankDashPendingSection: "" - property var _dankDashPendingScreen: null - property bool _dankDashHasPosition: false - - function _storeDankDashPosition(x, y, width, section, screen, hasPos) { - _dankDashPendingX = x; - _dankDashPendingY = y; - _dankDashPendingWidth = width; - _dankDashPendingSection = section; - _dankDashPendingScreen = screen; - _dankDashHasPosition = hasPos; - } - - function openDankDash(tabIndex, x, y, width, section, screen) { - _dankDashPendingTab = tabIndex || 0; - if (dankDashPopout) { - if (arguments.length >= 6) - setPosition(dankDashPopout, x, y, width, section, screen); - dankDashPopout.currentTabIndex = _dankDashPendingTab; - dankDashPopout.dashVisible = true; - return; - } - if (!dankDashPopoutLoader) - return; - _storeDankDashPosition(x, y, width, section, screen, arguments.length >= 6); - _dankDashWantsOpen = true; - _dankDashWantsToggle = false; - dankDashPopoutLoader.active = true; - } - - function closeDankDash() { - if (dankDashPopout) - dankDashPopout.dashVisible = false; - } - - function unloadDankDash() { - if (!dankDashPopoutLoader) - return; - dankDashPopout = null; - dankDashPopoutLoader.active = false; - } - - function toggleDankDash(tabIndex, x, y, width, section, screen) { - _dankDashPendingTab = tabIndex || 0; - if (dankDashPopout) { - if (arguments.length >= 6) - setPosition(dankDashPopout, x, y, width, section, screen); - if (dankDashPopout.dashVisible) { - dankDashPopout.dashVisible = false; - } else { - dankDashPopout.currentTabIndex = _dankDashPendingTab; - dankDashPopout.dashVisible = true; - } - return; - } - if (!dankDashPopoutLoader) - return; - _storeDankDashPosition(x, y, width, section, screen, arguments.length >= 6); - _dankDashWantsToggle = true; - _dankDashWantsOpen = false; - dankDashPopoutLoader.active = true; - } - - function _onDankDashPopoutLoaded() { - if (!dankDashPopout) - return; - - if (_dankDashHasPosition) - setPosition(dankDashPopout, _dankDashPendingX, _dankDashPendingY, _dankDashPendingWidth, _dankDashPendingSection, _dankDashPendingScreen); - - if (_dankDashWantsOpen) { - _dankDashWantsOpen = false; - dankDashPopout.currentTabIndex = _dankDashPendingTab; - dankDashPopout.dashVisible = true; - return; - } - if (_dankDashWantsToggle) { - _dankDashWantsToggle = false; - if (dankDashPopout.dashVisible) { - dankDashPopout.dashVisible = false; - } else { - dankDashPopout.currentTabIndex = _dankDashPendingTab; - dankDashPopout.dashVisible = true; - } - } - } - - function openBattery(x, y, width, section, screen) { - if (batteryPopout) { - setPosition(batteryPopout, x, y, width, section, screen); - batteryPopout.open(); - } - } - - function closeBattery() { - batteryPopout?.close(); - } - - function unloadBattery() { - if (!batteryPopoutLoader) - return; - batteryPopout = null; - batteryPopoutLoader.active = false; - } - - function toggleBattery(x, y, width, section, screen) { - if (batteryPopout) { - setPosition(batteryPopout, x, y, width, section, screen); - batteryPopout.toggle(); - } - } - - function openVpn(x, y, width, section, screen) { - if (vpnPopout) { - setPosition(vpnPopout, x, y, width, section, screen); - vpnPopout.open(); - } - } - - function closeVpn() { - vpnPopout?.close(); - } - - function unloadVpn() { - if (!vpnPopoutLoader) - return; - vpnPopout = null; - vpnPopoutLoader.active = false; - } - - function toggleVpn(x, y, width, section, screen) { - if (vpnPopout) { - setPosition(vpnPopout, x, y, width, section, screen); - vpnPopout.toggle(); - } - } - - function openSystemUpdate(x, y, width, section, screen) { - if (systemUpdatePopout) { - setPosition(systemUpdatePopout, x, y, width, section, screen); - systemUpdatePopout.open(); - } - } - - function closeSystemUpdate() { - systemUpdatePopout?.close(); - } - - function unloadSystemUpdate() { - if (!systemUpdateLoader) - return; - systemUpdatePopout = null; - systemUpdateLoader.active = false; - } - - function toggleSystemUpdate(x, y, width, section, screen) { - if (systemUpdatePopout) { - setPosition(systemUpdatePopout, x, y, width, section, screen); - systemUpdatePopout.toggle(); - } - } - - property bool _settingsWantsOpen: false - property bool _settingsWantsToggle: false - - property string _settingsPendingTab: "" - property int _settingsPendingTabIndex: -1 - - function openSettings() { - if (settingsModal) { - settingsModal.show(); - } else if (settingsModalLoader) { - _settingsWantsOpen = true; - _settingsWantsToggle = false; - settingsModalLoader.activeAsync = true; - } - } - - function openSettingsWithTab(tabName: string) { - if (settingsModal) { - settingsModal.showWithTabName(tabName); - return; - } - if (settingsModalLoader) { - _settingsPendingTab = tabName; - _settingsWantsOpen = true; - _settingsWantsToggle = false; - settingsModalLoader.activeAsync = true; - } - } - - function openSettingsWithTabIndex(tabIndex: int) { - if (settingsModal) { - settingsModal.showWithTab(tabIndex); - return; - } - if (settingsModalLoader) { - _settingsPendingTabIndex = tabIndex; - _settingsWantsOpen = true; - _settingsWantsToggle = false; - settingsModalLoader.activeAsync = true; - } - } - - function closeSettings() { - settingsModal?.close(); - } - - function toggleSettings() { - if (settingsModal) { - settingsModal.toggle(); - } else if (settingsModalLoader) { - _settingsWantsToggle = true; - _settingsWantsOpen = false; - settingsModalLoader.activeAsync = true; - } - } - - function toggleSettingsWithTab(tabName: string) { - if (settingsModal) { - var idx = settingsModal.resolveTabIndex(tabName); - if (idx >= 0) - settingsModal.currentTabIndex = idx; - settingsModal.toggle(); - return; - } - if (settingsModalLoader) { - _settingsPendingTab = tabName; - _settingsWantsToggle = true; - _settingsWantsOpen = false; - settingsModalLoader.activeAsync = true; - } - } - - function focusOrToggleSettings() { - if (settingsModal?.visible) { - const settingsTitle = I18n.tr("Settings", "settings window title"); - for (const toplevel of ToplevelManager.toplevels.values) { - if (toplevel.title !== "Settings" && toplevel.title !== settingsTitle) - continue; - if (toplevel.activated) { - settingsModal.hide(); - return; - } - toplevel.activate(); - return; - } - } - openSettings(); - } - - function focusOrToggleSettingsWithTab(tabName: string) { - if (settingsModal?.visible) { - const settingsTitle = I18n.tr("Settings", "settings window title"); - for (const toplevel of ToplevelManager.toplevels.values) { - if (toplevel.title !== "Settings" && toplevel.title !== settingsTitle) - continue; - if (toplevel.activated) { - settingsModal.hide(); - return; - } - var idx = settingsModal.resolveTabIndex(tabName); - if (idx >= 0) - settingsModal.currentTabIndex = idx; - toplevel.activate(); - return; - } - } - openSettingsWithTab(tabName); - } - - function unloadSettings() { - if (settingsModalLoader) { - settingsModal = null; - settingsModalLoader.active = false; - } - } - - function _onSettingsModalLoaded() { - if (_settingsWantsOpen) { - _settingsWantsOpen = false; - if (_settingsPendingTabIndex >= 0) { - settingsModal?.showWithTab(_settingsPendingTabIndex); - _settingsPendingTabIndex = -1; - } else if (_settingsPendingTab) { - settingsModal?.showWithTabName(_settingsPendingTab); - _settingsPendingTab = ""; - } else { - settingsModal?.show(); - } - return; - } - if (_settingsWantsToggle) { - _settingsWantsToggle = false; - if (_settingsPendingTabIndex >= 0) { - settingsModal.currentTabIndex = _settingsPendingTabIndex; - _settingsPendingTabIndex = -1; - } else if (_settingsPendingTab) { - var idx = settingsModal?.resolveTabIndex(_settingsPendingTab) ?? -1; - if (idx >= 0) - settingsModal.currentTabIndex = idx; - _settingsPendingTab = ""; - } - settingsModal?.toggle(); - } - } - - function openClipboardHistory() { - clipboardHistoryModal?.show(); - } - - function closeClipboardHistory() { - clipboardHistoryModal?.close(); - } - - function unloadClipboardHistoryPopout() { - if (!clipboardHistoryPopoutLoader) - return; - clipboardHistoryPopout = null; - clipboardHistoryPopoutLoader.active = false; - } - - function unloadLayoutPopout() { - if (!layoutPopoutLoader) - return; - layoutPopout = null; - layoutPopoutLoader.active = false; - } - - property bool _dankLauncherV2WantsOpen: false - property bool _dankLauncherV2WantsToggle: false - property string _dankLauncherV2PendingQuery: "" - property string _dankLauncherV2PendingMode: "" - - function openDankLauncherV2() { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.show(); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2WantsOpen = true; - _dankLauncherV2WantsToggle = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function openDankLauncherV2WithQuery(query: string) { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.showWithQuery(query); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2PendingQuery = query; - _dankLauncherV2WantsOpen = true; - _dankLauncherV2WantsToggle = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function openDankLauncherV2WithMode(mode: string) { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.showWithMode(mode); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2PendingMode = mode; - _dankLauncherV2WantsOpen = true; - _dankLauncherV2WantsToggle = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function closeDankLauncherV2() { - dankLauncherV2Modal?.hide(); - } - - function unloadDankLauncherV2() { - if (dankLauncherV2ModalLoader) { - dankLauncherV2Modal = null; - dankLauncherV2ModalLoader.active = false; - } - } - - function toggleDankLauncherV2() { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.toggle(); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2WantsToggle = true; - _dankLauncherV2WantsOpen = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function toggleDankLauncherV2WithMode(mode: string) { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.toggleWithMode(mode); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2PendingMode = mode; - _dankLauncherV2WantsToggle = true; - _dankLauncherV2WantsOpen = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function toggleDankLauncherV2WithQuery(query: string) { - if (dankLauncherV2Modal) { - dankLauncherV2Modal.toggleWithQuery(query); - } else if (dankLauncherV2ModalLoader) { - _dankLauncherV2PendingQuery = query; - _dankLauncherV2WantsOpen = true; - _dankLauncherV2WantsToggle = false; - dankLauncherV2ModalLoader.active = true; - } - } - - function _onDankLauncherV2ModalLoaded() { - if (_dankLauncherV2WantsOpen) { - _dankLauncherV2WantsOpen = false; - if (_dankLauncherV2PendingQuery) { - dankLauncherV2Modal?.showWithQuery(_dankLauncherV2PendingQuery); - _dankLauncherV2PendingQuery = ""; - } else if (_dankLauncherV2PendingMode) { - dankLauncherV2Modal?.showWithMode(_dankLauncherV2PendingMode); - _dankLauncherV2PendingMode = ""; - } else { - dankLauncherV2Modal?.show(); - } - return; - } - if (_dankLauncherV2WantsToggle) { - _dankLauncherV2WantsToggle = false; - if (_dankLauncherV2PendingMode) { - dankLauncherV2Modal?.toggleWithMode(_dankLauncherV2PendingMode); - _dankLauncherV2PendingMode = ""; - } else { - dankLauncherV2Modal?.toggle(); - } - } - } - - function openPowerMenu() { - powerMenuModal?.openCentered(); - } - - function closePowerMenu() { - powerMenuModal?.close(); - } - - function togglePowerMenu() { - if (powerMenuModal) { - if (powerMenuModal.shouldBeVisible) { - powerMenuModal.close(); - } else { - powerMenuModal.openCentered(); - } - } - } - - function showProcessListModal() { - if (processListModal) { - processListModal.show(); - } else if (processListModalLoader) { - processListModalLoader.active = true; - Qt.callLater(() => processListModal?.show()); - } - } - - function hideProcessListModal() { - processListModal?.hide(); - } - - function toggleProcessListModal() { - if (processListModal) { - processListModal.toggle(); - } else if (processListModalLoader) { - processListModalLoader.active = true; - Qt.callLater(() => processListModal?.show()); - } - } - - function showColorPicker() { - colorPickerModal?.show(); - } - - function hideColorPicker() { - colorPickerModal?.close(); - } - - function showNotificationModal() { - notificationModal?.show(); - } - - function hideNotificationModal() { - notificationModal?.close(); - } - - function showWifiPasswordModal(ssid) { - if (wifiPasswordModalLoader) - wifiPasswordModalLoader.active = true; - if (wifiPasswordModal) - wifiPasswordModal.show(ssid); - } - - function showWifiQRCodeModal(ssid) { - if (wifiQRCodeModalLoader) - wifiQRCodeModalLoader.active = true; - if (wifiQRCodeModal) - wifiQRCodeModal.show(ssid); - } - - function showHiddenNetworkModal() { - if (wifiPasswordModalLoader) - wifiPasswordModalLoader.active = true; - if (wifiPasswordModal) - wifiPasswordModal.showHidden(); - } - - function hideWifiPasswordModal() { - wifiPasswordModal?.hide(); - } - - function showNetworkInfoModal() { - networkInfoModal?.show(); - } - - function hideNetworkInfoModal() { - networkInfoModal?.close(); - } - - function openNotepad() { - if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.show(); - } - } - - function closeNotepad() { - if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.hide(); - } - } - - function toggleNotepad() { - if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.toggle(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml deleted file mode 100644 index 73c0a9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml +++ /dev/null @@ -1,316 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property bool accountsServiceAvailable: false - property string systemProfileImage: "" - property string profileImage: "" - property bool settingsPortalAvailable: false - property int systemColorScheme: 0 - - property bool freedeskAvailable: false - property string colorSchemeCommand: "" - property string pendingProfileImage: "" - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - function init() { - } - - function getSystemProfileImage() { - if (!freedeskAvailable) - return; - const username = Quickshell.env("USER"); - if (!username) - return; - DMSService.sendRequest("freedesktop.accounts.getUserIconFile", { - "username": username - }, response => { - if (response.result && response.result.success) { - const iconFile = response.result.value || ""; - if (iconFile && iconFile !== "" && iconFile !== "/var/lib/AccountsService/icons/") { - systemProfileImage = iconFile; - if (!profileImage || profileImage === "") { - profileImage = iconFile; - } - } - } - }); - } - - function getUserProfileImage(username) { - if (!username) { - profileImage = ""; - return; - } - if (Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true") { - profileImage = ""; - return; - } - - if (!freedeskAvailable) { - profileImage = ""; - return; - } - - DMSService.sendRequest("freedesktop.accounts.getUserIconFile", { - "username": username - }, response => { - if (response.result && response.result.success) { - const icon = response.result.value || ""; - if (icon && icon !== "" && icon !== "/var/lib/AccountsService/icons/") { - profileImage = icon; - } else { - profileImage = ""; - } - } else { - profileImage = ""; - } - }); - } - - function setProfileImage(imagePath) { - if (accountsServiceAvailable) { - pendingProfileImage = imagePath; - setSystemProfileImage(imagePath || ""); - } else { - profileImage = imagePath; - } - } - - function getSystemColorScheme() { - if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) { - return; - } - if (!freedeskAvailable) - return; - DMSService.sendRequest("freedesktop.settings.getColorScheme", null, response => { - if (response.result) { - systemColorScheme = response.result.value || 0; - } - }); - } - - function setLightMode(isLightMode) { - if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) { - return; - } - setSystemColorScheme(isLightMode); - } - - function setSystemColorScheme(isLightMode) { - if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) { - return; - } - - const targetScheme = isLightMode ? "default" : "prefer-dark"; - - if (colorSchemeCommand === "gsettings") { - Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", targetScheme]); - } - if (colorSchemeCommand === "dconf") { - Quickshell.execDetached(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", `'${targetScheme}'`]); - } - } - - function setSystemIconTheme(themeName) { - if (!settingsPortalAvailable || !freedeskAvailable) - return; - DMSService.sendRequest("freedesktop.settings.setIconTheme", { - "iconTheme": themeName - }, response => { - if (response.error) { - console.warn("PortalService: Failed to set icon theme:", response.error); - } - }); - } - - function setSystemProfileImage(imagePath) { - if (!accountsServiceAvailable || !freedeskAvailable) - return; - DMSService.sendRequest("freedesktop.accounts.setIconFile", { - "path": imagePath || "" - }, response => { - if (response.error) { - console.warn("PortalService: Failed to set icon file:", response.error); - - const errorMsg = response.error.toString(); - let userMessage = I18n.tr("Failed to set profile image"); - - if (errorMsg.includes("too large")) { - userMessage = I18n.tr("Profile image is too large. Please use a smaller image."); - } else if (errorMsg.includes("permission")) { - userMessage = I18n.tr("Permission denied to set profile image."); - } else if (errorMsg.includes("not found") || errorMsg.includes("does not exist")) { - userMessage = I18n.tr("Selected image file not found."); - } else { - userMessage = I18n.tr("Failed to set profile image: %1").arg(errorMsg.split(":").pop().trim()); - } - - Quickshell.execDetached(["notify-send", "-u", "normal", "-a", "DMS", "-i", "error", I18n.tr("Profile Image Error"), userMessage]); - - pendingProfileImage = ""; - } else { - profileImage = pendingProfileImage; - pendingProfileImage = ""; - Qt.callLater(() => getSystemProfileImage()); - } - }); - } - - Component.onCompleted: { - if (socketPath && socketPath.length > 0) { - checkDMSCapabilities(); - } else { - console.info("PortalService: DMS_SOCKET not set"); - } - colorSchemeDetector.running = true; - } - - Connections { - target: DMSService - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkDMSCapabilities(); - } - } - } - - Connections { - target: DMSService - enabled: DMSService.isConnected - - function onCapabilitiesChanged() { - checkDMSCapabilities(); - } - } - - function checkDMSCapabilities() { - if (!DMSService.isConnected) { - return; - } - - if (DMSService.capabilities.length === 0) { - return; - } - - freedeskAvailable = DMSService.capabilities.includes("freedesktop"); - if (freedeskAvailable) { - checkAccountsService(); - checkSettingsPortal(); - } else { - console.info("PortalService: freedesktop capability not available in DMS"); - } - } - - function checkAccountsService() { - if (!freedeskAvailable) - return; - DMSService.sendRequest("freedesktop.getState", null, response => { - if (response.result && response.result.accounts) { - accountsServiceAvailable = response.result.accounts.available || false; - if (accountsServiceAvailable) { - getSystemProfileImage(); - } - } - }); - } - - function checkSettingsPortal() { - if (!freedeskAvailable) - return; - DMSService.sendRequest("freedesktop.getState", null, response => { - if (response.result && response.result.settings) { - settingsPortalAvailable = response.result.settings.available || false; - if (settingsPortalAvailable && SettingsData.syncModeWithPortal) { - getSystemColorScheme(); - } - } - }); - } - - function getGreeterUserProfileImage(username) { - if (!username) { - profileImage = ""; - return; - } - userProfileCheckProcess.command = ["bash", "-c", `uid=$(id -u ${username} 2>/dev/null) && [ -n "$uid" ] && dbus-send --system --print-reply --dest=org.freedesktop.Accounts /org/freedesktop/Accounts/User$uid org.freedesktop.DBus.Properties.Get string:org.freedesktop.Accounts.User string:IconFile 2>/dev/null | grep -oP 'string "\\K[^"]+' || echo ""`]; - userProfileCheckProcess.running = true; - } - - Process { - id: userProfileCheckProcess - command: [] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const trimmed = text.trim(); - if (trimmed && trimmed !== "" && !trimmed.includes("Error") && trimmed !== "/var/lib/AccountsService/icons/") { - root.profileImage = trimmed; - } else { - root.profileImage = ""; - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.profileImage = ""; - } - } - } - - Process { - id: colorSchemeDetector - command: ["bash", "-c", "command -v gsettings || command -v dconf"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - const cmd = text.trim(); - if (cmd.includes("gsettings")) { - root.colorSchemeCommand = "gsettings"; - } else if (cmd.includes("dconf")) { - root.colorSchemeCommand = "dconf"; - } - } - } - } - - IpcHandler { - target: "profile" - - function getImage(): string { - return root.profileImage; - } - - function setImage(path: string): string { - if (!path) { - return "ERROR: No path provided"; - } - - const absolutePath = path.startsWith("/") ? path : `${StandardPaths.writableLocation(StandardPaths.HomeLocation)}/${path}`; - - try { - root.setProfileImage(absolutePath); - return "SUCCESS: Profile image set to " + absolutePath; - } catch (e) { - return "ERROR: Failed to set profile image: " + e.toString(); - } - } - - function clearImage(): string { - root.setProfileImage(""); - return "SUCCESS: Profile image cleared"; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml deleted file mode 100644 index bab3517..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml +++ /dev/null @@ -1,36 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Services.UPower - -Singleton { - id: root - - property int currentProfile: -1 - property int previousProfile: -1 - - signal profileChanged(int profile) - - Connections { - target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null - - function onProfileChanged() { - if (typeof PowerProfiles !== "undefined") { - root.previousProfile = root.currentProfile; - root.currentProfile = PowerProfiles.profile; - if (root.previousProfile !== -1) { - root.profileChanged(root.currentProfile); - } - } - } - } - - Component.onCompleted: { - if (typeof PowerProfiles !== "undefined") { - root.currentProfile = PowerProfiles.profile; - root.previousProfile = PowerProfiles.profile; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml deleted file mode 100644 index 4908862..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml +++ /dev/null @@ -1,155 +0,0 @@ -pragma Singleton - -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Services.Pipewire -import qs.Services - -Singleton { - id: root - - readonly property bool microphoneActive: { - if (!Pipewire.ready || !Pipewire.nodes?.values) { - return false - } - - for (let i = 0; i < Pipewire.nodes.values.length; i++) { - const node = Pipewire.nodes.values[i] - if (!node) { - continue - } - - if ((node.type & PwNodeType.AudioInStream) === PwNodeType.AudioInStream) { - if (!looksLikeSystemVirtualMic(node)) { - if (node.audio && node.audio.muted) { - return false - } - return true - } - } - } - return false - } - - PwObjectTracker { - objects: Pipewire.nodes.values.filter(node => !node.isStream) - } - - readonly property bool cameraActive: { - if (!Pipewire.ready || !Pipewire.nodes?.values) { - return false - } - - for (let i = 0; i < Pipewire.nodes.values.length; i++) { - const node = Pipewire.nodes.values[i] - if (!node || !node.ready) { - continue - } - - if (node.properties && node.properties["media.class"] === "Stream/Input/Video") { - if (node.properties["stream.is-live"] === "true") { - return true - } - } - } - return false - } - - readonly property bool screensharingActive: { - if (CompositorService.isNiri && NiriService.hasActiveCast) { - return true - } - - if (!Pipewire.ready || !Pipewire.nodes?.values) { - return false - } - - for (let i = 0; i < Pipewire.nodes.values.length; i++) { - const node = Pipewire.nodes.values[i] - if (!node || !node.ready) { - continue - } - - if ((node.type & PwNodeType.VideoSource) === PwNodeType.VideoSource) { - if (looksLikeScreencast(node)) { - return true - } - } - - if (node.properties && node.properties["media.class"] === "Stream/Output/Video") { - if (looksLikeScreencast(node)) { - return true - } - } - - if (node.properties && node.properties["media.class"] === "Stream/Input/Audio") { - const mediaName = (node.properties["media.name"] || "").toLowerCase() - const appName = (node.properties["application.name"] || "").toLowerCase() - - if (mediaName.includes("desktop") || appName.includes("screen") || appName === "obs") { - if (node.properties["stream.is-live"] === "true") { - if (node.audio && node.audio.muted) { - return false - } - return true - } - } - } - } - return false - } - - readonly property bool anyPrivacyActive: microphoneActive || cameraActive || screensharingActive - - function looksLikeSystemVirtualMic(node) { - if (!node) { - return false - } - const name = (node.name || "").toLowerCase() - const mediaName = (node.properties && node.properties["media.name"] || "").toLowerCase() - const appName = (node.properties && node.properties["application.name"] || "").toLowerCase() - const combined = name + " " + mediaName + " " + appName - return /cava|monitor|system/.test(combined) - } - - function looksLikeScreencast(node) { - if (!node) { - return false - } - const appName = (node.properties && node.properties["application.name"] || "").toLowerCase() - const nodeName = (node.name || "").toLowerCase() - const mediaName = (node.properties && node.properties["media.name"] || "").toLowerCase() - const combined = appName + " " + nodeName + " " + mediaName - return /xdg-desktop-portal|xdpw|screencast|screen-cast|screen|gnome shell|kwin|obs|niri/.test(combined) - } - - function getMicrophoneStatus() { - return microphoneActive ? "active" : "inactive" - } - - function getCameraStatus() { - return cameraActive ? "active" : "inactive" - } - - function getScreensharingStatus() { - return screensharingActive ? "active" : "inactive" - } - - function getPrivacySummary() { - const active = [] - if (microphoneActive) { - active.push("microphone") - } - if (cameraActive) { - active.push("camera") - } - if (screensharingActive) { - active.push("screensharing") - } - - return active.length > 0 ? `Privacy active: ${active.join(", ")}` : "No privacy concerns detected" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml deleted file mode 100644 index 7f5a1ed..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml +++ /dev/null @@ -1,619 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Hyprland -import Quickshell.I3 -import Quickshell.Wayland -import qs.Common - -Singleton { - id: root - - property bool hasUwsm: false - property bool isElogind: false - property bool hibernateSupported: false - property bool inhibitorAvailable: true - property bool idleInhibited: false - property string inhibitReason: "Keep system awake" - property string nvidiaCommand: "" - - readonly property bool nativeInhibitorAvailable: { - try { - return typeof IdleInhibitor !== "undefined"; - } catch (e) { - return false; - } - } - - property bool loginctlAvailable: false - property bool wtypeAvailable: false - property string sessionId: "" - property string sessionPath: "" - property bool locked: false - property bool active: false - property bool idleHint: false - property bool lockedHint: false - property bool preparingForSleep: false - property string sessionType: "" - property string userName: "" - property string seat: "" - property string display: "" - - signal sessionLocked - signal sessionUnlocked - signal sessionResumed - signal loginctlStateChanged - - property bool stateInitialized: false - - readonly property string socketPath: Quickshell.env("DMS_SOCKET") - - Timer { - id: sessionInitTimer - interval: 200 - running: true - repeat: false - onTriggered: { - detectElogindProcess.running = true; - detectHibernateProcess.running = true; - detectPrimeRunProcess.running = true; - detectWtypeProcess.running = true; - console.info("SessionService: Native inhibitor available:", nativeInhibitorAvailable); - if (!SettingsData.loginctlLockIntegration) { - console.log("SessionService: loginctl lock integration disabled by user"); - return; - } - if (socketPath && socketPath.length > 0) { - checkDMSCapabilities(); - } else { - console.log("SessionService: DMS_SOCKET not set"); - } - } - } - - Process { - id: detectUwsmProcess - running: false - command: ["which", "uwsm"] - - onExited: function (exitCode) { - hasUwsm = (exitCode === 0); - } - } - - Process { - id: detectElogindProcess - running: false - command: ["sh", "-c", "ps -eo comm= | grep -E '^(elogind|elogind-daemon)$'"] - - onExited: function (exitCode) { - console.log("SessionService: Elogind detection exited with code", exitCode); - isElogind = (exitCode === 0); - } - } - - Process { - id: detectHibernateProcess - running: false - command: ["grep", "-q", "disk", "/sys/power/state"] - - onExited: function (exitCode) { - hibernateSupported = (exitCode === 0); - } - } - - Process { - id: hibernateProcess - running: false - - property string errorOutput: "" - - stderr: SplitParser { - splitMarker: "\n" - onRead: data => hibernateProcess.errorOutput += data.trim() - } - - onExited: function (exitCode) { - if (exitCode === 0) { - errorOutput = ""; - return; - } - ToastService.showError("Hibernate failed", errorOutput); - errorOutput = ""; - } - } - - Process { - id: detectWtypeProcess - running: false - command: ["which", "wtype"] - onExited: exitCode => { - wtypeAvailable = (exitCode === 0); - } - } - - Process { - id: detectPrimeRunProcess - running: false - command: ["which", "prime-run"] - - onExited: function (exitCode) { - if (exitCode === 0) { - nvidiaCommand = "prime-run"; - } else { - detectNvidiaOffloadProcess.running = true; - } - } - } - - Process { - id: detectNvidiaOffloadProcess - running: false - command: ["which", "nvidia-offload"] - - onExited: function (exitCode) { - if (exitCode === 0) { - nvidiaCommand = "nvidia-offload"; - } - } - } - - Process { - id: uwsmLogout - command: ["uwsm", "stop"] - running: false - - stdout: SplitParser { - splitMarker: "\n" - onRead: data => { - if (data.trim().toLowerCase().includes("not running")) { - _logout(); - } - } - } - - onExited: function (exitCode) { - if (exitCode === 0) { - return; - } - _logout(); - } - } - - function escapeShellArg(arg) { - return "'" + arg.replace(/'/g, "'\\''") + "'"; - } - - function needsShellExecution(prefix) { - if (!prefix || prefix.length === 0) - return false; - return /[;&|<>()$`\\"']/.test(prefix); - } - - function parseEnvVars(envVarsStr) { - if (!envVarsStr || envVarsStr.trim().length === 0) - return {}; - const envObj = {}; - const pairs = envVarsStr.trim().split(/\s+/); - for (const pair of pairs) { - const eqIndex = pair.indexOf("="); - if (eqIndex > 0) { - const key = pair.substring(0, eqIndex); - const value = pair.substring(eqIndex + 1); - envObj[key] = value; - } - } - return envObj; - } - - function launchDesktopEntry(desktopEntry, useNvidia) { - let cmd = desktopEntry.command; - - const appId = desktopEntry.id || desktopEntry.execString || desktopEntry.exec || ""; - const override = SessionData.getAppOverride(appId); - - const dgpu = useNvidia || (override?.launchOnDgpu && nvidiaCommand); - if (dgpu && nvidiaCommand) - cmd = [nvidiaCommand].concat(cmd); - - if (override?.extraFlags) { - const extraArgs = override.extraFlags.trim().split(/\s+/).filter(arg => arg.length > 0); - cmd = cmd.concat(extraArgs); - } - - const userPrefix = SettingsData.launchPrefix?.trim() || ""; - const defaultPrefix = Quickshell.env("DMS_DEFAULT_LAUNCH_PREFIX") || ""; - const prefix = userPrefix.length > 0 ? userPrefix : defaultPrefix; - const workDir = desktopEntry.workingDirectory || Quickshell.env("HOME"); - const cursorEnv = typeof SettingsData.getCursorEnvironment === "function" ? SettingsData.getCursorEnvironment() : {}; - - const overrideEnv = override?.envVars ? parseEnvVars(override.envVars) : {}; - const finalEnv = Object.assign({}, cursorEnv, overrideEnv); - - if (desktopEntry.runInTerminal) { - const terminal = Quickshell.env("TERMINAL") || "xterm"; - const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" "); - const shellCmd = prefix.length > 0 ? `${prefix} ${escapedCmd}` : escapedCmd; - Quickshell.execDetached({ - command: [terminal, "-e", "sh", "-c", shellCmd], - workingDirectory: workDir, - environment: finalEnv - }); - return; - } - - if (prefix.length > 0 && needsShellExecution(prefix)) { - const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" "); - Quickshell.execDetached({ - command: ["sh", "-c", `${prefix} ${escapedCmd}`], - workingDirectory: workDir, - environment: finalEnv - }); - return; - } - - if (prefix.length > 0) - cmd = prefix.split(" ").concat(cmd); - - Quickshell.execDetached({ - command: cmd, - workingDirectory: workDir, - environment: finalEnv - }); - } - - function launchDesktopAction(desktopEntry, action, useNvidia) { - let cmd = action.command; - - const appId = desktopEntry.id || desktopEntry.execString || desktopEntry.exec || ""; - const override = SessionData.getAppOverride(appId); - const dgpu = useNvidia || (override?.launchOnDgpu && nvidiaCommand); - if (dgpu && nvidiaCommand) - cmd = [nvidiaCommand].concat(cmd); - - const userPrefix = SettingsData.launchPrefix?.trim() || ""; - const defaultPrefix = Quickshell.env("DMS_DEFAULT_LAUNCH_PREFIX") || ""; - const prefix = userPrefix.length > 0 ? userPrefix : defaultPrefix; - const workDir = desktopEntry.workingDirectory || Quickshell.env("HOME"); - const cursorEnv = typeof SettingsData.getCursorEnvironment === "function" ? SettingsData.getCursorEnvironment() : {}; - - if (prefix.length > 0 && needsShellExecution(prefix)) { - const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" "); - Quickshell.execDetached({ - command: ["sh", "-c", `${prefix} ${escapedCmd}`], - workingDirectory: workDir, - environment: cursorEnv - }); - return; - } - - if (prefix.length > 0) - cmd = prefix.split(" ").concat(cmd); - - Quickshell.execDetached({ - command: cmd, - workingDirectory: workDir, - environment: cursorEnv - }); - } - - // * Session management - function logout() { - if (hasUwsm) { - uwsmLogout.running = true; - } - _logout(); - } - - function _logout() { - if (SettingsData.customPowerActionLogout.length === 0) { - if (CompositorService.isNiri) { - NiriService.quit(); - return; - } - - if (CompositorService.isDwl) { - DwlService.quit(); - return; - } - - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - try { - I3.dispatch("exit"); - } catch (_) {} - return; - } - - Hyprland.dispatch("exit"); - } else { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLogout]); - } - } - - function suspend() { - if (SettingsData.customPowerActionSuspend.length === 0) { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"]); - } else { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionSuspend]); - } - } - - function hibernate() { - hibernateProcess.errorOutput = ""; - if (SettingsData.customPowerActionHibernate.length > 0) { - hibernateProcess.command = ["sh", "-c", SettingsData.customPowerActionHibernate]; - } else { - hibernateProcess.command = [isElogind ? "loginctl" : "systemctl", "hibernate"]; - } - hibernateProcess.running = true; - } - - function suspendThenHibernate() { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend-then-hibernate"]); - } - - function suspendWithBehavior(behavior) { - if (behavior === SettingsData.SuspendBehavior.Hibernate) { - hibernate(); - } else if (behavior === SettingsData.SuspendBehavior.SuspendThenHibernate) { - suspendThenHibernate(); - } else { - suspend(); - } - } - - function reboot() { - if (SettingsData.customPowerActionReboot.length === 0) { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"]); - } else { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionReboot]); - } - } - - function poweroff() { - if (SettingsData.customPowerActionPowerOff.length === 0) { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "poweroff"]); - } else { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionPowerOff]); - } - } - - // * Idle Inhibitor - signal inhibitorChanged - - function enableIdleInhibit() { - if (idleInhibited) { - return; - } - console.log("SessionService: Enabling idle inhibit (native:", nativeInhibitorAvailable, ")"); - idleInhibited = true; - inhibitorChanged(); - } - - function disableIdleInhibit() { - if (!idleInhibited) { - return; - } - console.log("SessionService: Disabling idle inhibit (native:", nativeInhibitorAvailable, ")"); - idleInhibited = false; - inhibitorChanged(); - } - - function toggleIdleInhibit() { - if (idleInhibited) { - disableIdleInhibit(); - } else { - enableIdleInhibit(); - } - } - - function setInhibitReason(reason) { - inhibitReason = reason; - - if (idleInhibited && !nativeInhibitorAvailable) { - const wasActive = idleInhibited; - idleInhibited = false; - - Qt.callLater(() => { - if (wasActive) { - idleInhibited = true; - } - }); - } - } - - Process { - id: idleInhibitProcess - - command: { - if (!idleInhibited || nativeInhibitorAvailable) { - return ["true"]; - } - - console.log("SessionService: Starting systemd/elogind inhibit process"); - return [isElogind ? "elogind-inhibit" : "systemd-inhibit", "--what=idle", "--who=quickshell", `--why=${inhibitReason}`, "--mode=block", "sleep", "infinity"]; - } - - running: idleInhibited && !nativeInhibitorAvailable - - onRunningChanged: { - console.log("SessionService: Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")"); - } - - onExited: function (exitCode) { - if (idleInhibited && exitCode !== 0 && !nativeInhibitorAvailable) { - console.warn("SessionService: Inhibitor process crashed with exit code:", exitCode); - idleInhibited = false; - ToastService.showWarning("Idle inhibitor failed"); - } - } - } - - Connections { - target: DMSService - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkDMSCapabilities(); - } - } - - function onCapabilitiesReceived() { - syncSleepInhibitor(); - } - } - - Connections { - target: DMSService - enabled: DMSService.isConnected - - function onCapabilitiesChanged() { - checkDMSCapabilities(); - } - } - - Connections { - target: SettingsData - - function onLoginctlLockIntegrationChanged() { - if (SettingsData.loginctlLockIntegration) { - if (socketPath && socketPath.length > 0 && loginctlAvailable) { - if (!stateInitialized) { - stateInitialized = true; - getLoginctlState(); - syncLockBeforeSuspend(); - } - } - } else { - stateInitialized = false; - } - syncSleepInhibitor(); - } - - function onLockBeforeSuspendChanged() { - if (SettingsData.loginctlLockIntegration) { - syncLockBeforeSuspend(); - } - syncSleepInhibitor(); - } - } - - Connections { - target: DMSService - enabled: SettingsData.loginctlLockIntegration - - function onLoginctlStateUpdate(data) { - updateLoginctlState(data); - } - - function onLoginctlEvent(event) { - handleLoginctlEvent(event); - } - } - - function checkDMSCapabilities() { - if (!DMSService.isConnected) { - return; - } - - if (DMSService.capabilities.length === 0) { - return; - } - - if (DMSService.capabilities.includes("loginctl")) { - loginctlAvailable = true; - if (SettingsData.loginctlLockIntegration && !stateInitialized) { - stateInitialized = true; - getLoginctlState(); - syncLockBeforeSuspend(); - } - } else { - loginctlAvailable = false; - console.log("SessionService: loginctl capability not available in DMS"); - } - } - - function getLoginctlState() { - if (!loginctlAvailable) - return; - DMSService.sendRequest("loginctl.getState", null, response => { - if (response.result) { - updateLoginctlState(response.result); - } - }); - } - - function syncLockBeforeSuspend() { - if (!loginctlAvailable) - return; - DMSService.sendRequest("loginctl.setLockBeforeSuspend", { - enabled: SettingsData.lockBeforeSuspend - }, response => { - if (response.error) { - console.warn("SessionService: Failed to sync lock before suspend:", response.error); - } else { - console.log("SessionService: Synced lock before suspend:", SettingsData.lockBeforeSuspend); - } - }); - } - - function syncSleepInhibitor() { - if (!loginctlAvailable) - return; - if (!DMSService.apiVersion || DMSService.apiVersion < 4) - return; - DMSService.sendRequest("loginctl.setSleepInhibitorEnabled", { - enabled: SettingsData.loginctlLockIntegration && SettingsData.lockBeforeSuspend - }, response => { - if (response.error) { - console.warn("SessionService: Failed to sync sleep inhibitor:", response.error); - } else { - console.log("SessionService: Synced sleep inhibitor:", SettingsData.loginctlLockIntegration); - } - }); - } - - function updateLoginctlState(state) { - const wasLocked = locked; - const wasSleeping = preparingForSleep; - - sessionId = state.sessionId || ""; - sessionPath = state.sessionPath || ""; - locked = state.locked || false; - active = state.active || false; - idleHint = state.idleHint || false; - lockedHint = state.lockedHint || false; - preparingForSleep = state.preparingForSleep || false; - sessionType = state.sessionType || ""; - userName = state.userName || ""; - seat = state.seat || ""; - display = state.display || ""; - - if (locked && !wasLocked) { - sessionLocked(); - } else if (!locked && wasLocked) { - sessionUnlocked(); - } - - if (wasSleeping && !preparingForSleep) { - sessionResumed(); - } - - loginctlStateChanged(); - } - - function handleLoginctlEvent(event) { - if (event.event === "Lock") { - locked = true; - lockedHint = true; - sessionLocked(); - } else if (event.event === "Unlock") { - locked = false; - lockedHint = false; - sessionUnlocked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml deleted file mode 100644 index 97e5d11..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml +++ /dev/null @@ -1,240 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property string query: "" - property var results: [] - property string targetSection: "" - property string highlightSection: "" - property var registeredCards: ({}) - property var settingsIndex: [] - property bool indexLoaded: false - property var _translatedCache: [] - - readonly property var conditionMap: ({ - "isNiri": () => CompositorService.isNiri, - "isHyprland": () => CompositorService.isHyprland, - "isDwl": () => CompositorService.isDwl, - "keybindsAvailable": () => KeybindsService.available, - "soundsAvailable": () => AudioService.soundsAvailable, - "cupsAvailable": () => CupsService.cupsAvailable, - "networkNotLegacy": () => !NetworkService.usingLegacy, - "dmsConnected": () => DMSService.isConnected && DMSService.apiVersion >= 23, - "matugenAvailable": () => Theme.matugenAvailable - }) - - Component.onCompleted: indexFile.reload() - - FileView { - id: indexFile - path: Qt.resolvedUrl("../translations/settings_search_index.json") - onLoaded: { - try { - root.settingsIndex = JSON.parse(text()); - root.indexLoaded = true; - root._rebuildTranslationCache(); - } catch (e) { - console.warn("SettingsSearchService: Failed to parse index:", e); - root.settingsIndex = []; - root._translatedCache = []; - } - } - onLoadFailed: error => console.warn("SettingsSearchService: Failed to load index:", error) - } - - function registerCard(settingKey, item, flickable) { - if (!settingKey) - return; - registeredCards[settingKey] = { - item: item, - flickable: flickable - }; - if (targetSection === settingKey) - scrollTimer.restart(); - } - - function unregisterCard(settingKey) { - if (!settingKey) - return; - let cards = registeredCards; - delete cards[settingKey]; - registeredCards = cards; - } - - function navigateToSection(section) { - targetSection = section; - if (registeredCards[section]) - scrollTimer.restart(); - } - - function scrollToTarget() { - if (!targetSection) - return; - const entry = registeredCards[targetSection]; - if (!entry || !entry.item || !entry.flickable) - return; - const flickable = entry.flickable; - const item = entry.item; - const contentItem = flickable.contentItem; - - if (!contentItem) - return; - const mapped = item.mapToItem(contentItem, 0, 0); - const maxY = Math.max(0, flickable.contentHeight - flickable.height); - const targetY = Math.min(maxY, Math.max(0, mapped.y - 16)); - flickable.contentY = targetY; - - highlightSection = targetSection; - targetSection = ""; - highlightTimer.restart(); - } - - function clearHighlight() { - highlightSection = ""; - } - - Timer { - id: scrollTimer - interval: 50 - onTriggered: root.scrollToTarget() - } - - Timer { - id: highlightTimer - interval: 2500 - onTriggered: root.highlightSection = "" - } - - function checkCondition(item) { - if (!item.conditionKey) - return true; - const condFn = conditionMap[item.conditionKey]; - if (!condFn) - return true; - return condFn(); - } - - function translateItem(item) { - return { - section: item.section, - label: I18n.tr(item.label), - tabIndex: item.tabIndex, - category: I18n.tr(item.category), - keywords: item.keywords || [], - icon: item.icon || "settings", - description: item.description ? I18n.tr(item.description) : "", - conditionKey: item.conditionKey - }; - } - - function _rebuildTranslationCache() { - var cache = []; - for (var i = 0; i < settingsIndex.length; i++) { - var item = settingsIndex[i]; - var t = translateItem(item); - cache.push({ - section: t.section, - label: t.label, - tabIndex: t.tabIndex, - category: t.category, - keywords: t.keywords, - icon: t.icon, - description: t.description, - conditionKey: t.conditionKey, - labelLower: t.label.toLowerCase(), - categoryLower: t.category.toLowerCase() - }); - } - _translatedCache = cache; - } - - function search(text) { - query = text; - if (!text) { - results = []; - return; - } - - var queryLower = text.toLowerCase().trim(); - var queryWords = queryLower.split(/\s+/).filter(w => w.length > 0); - var scored = []; - var cache = _translatedCache; - - for (var i = 0; i < cache.length; i++) { - var entry = cache[i]; - if (!checkCondition(entry)) - continue; - - var labelLower = entry.labelLower; - var categoryLower = entry.categoryLower; - var score = 0; - - if (labelLower === queryLower) { - score = 10000; - } else if (labelLower.startsWith(queryLower)) { - score = 5000; - } else if (labelLower.includes(queryLower)) { - score = 1000; - } else if (categoryLower.includes(queryLower)) { - score = 500; - } - - if (score === 0) { - var keywords = entry.keywords; - for (var k = 0; k < keywords.length; k++) { - if (keywords[k].startsWith(queryLower)) { - score = 800; - break; - } - if (keywords[k].includes(queryLower) && score < 400) { - score = 400; - } - } - } - - if (score === 0 && queryWords.length > 1) { - var allMatch = true; - for (var w = 0; w < queryWords.length; w++) { - var word = queryWords[w]; - if (labelLower.includes(word)) - continue; - var inKeywords = false; - for (var k = 0; k < entry.keywords.length; k++) { - if (entry.keywords[k].includes(word)) { - inKeywords = true; - break; - } - } - if (!inKeywords && !categoryLower.includes(word)) { - allMatch = false; - break; - } - } - if (allMatch) - score = 300; - } - - if (score > 0) { - scored.push({ - item: entry, - score: score - }); - } - } - - scored.sort((a, b) => b.score - a.score); - results = scored.slice(0, 15).map(s => s.item); - } - - function clear() { - query = ""; - results = []; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml deleted file mode 100644 index 53ca7ad..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml +++ /dev/null @@ -1,396 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common - -Singleton { - id: root - - property int refCount: 0 - property var availableUpdates: [] - property bool isChecking: false - property bool hasError: false - property string errorMessage: "" - property string updChecker: "" - property string pkgManager: "" - property string distribution: "" - property bool distributionSupported: false - property string shellVersion: "" - property string shellCodename: "" - property string semverVersion: "" - - function getParsedShellVersion() { - return parseVersion(semverVersion); - } - - readonly property var archBasedUCSettings: { - "listUpdatesSettings": { - "params": [], - "correctExitCodes": [0, 2] // Exit code 0 = updates available, 2 = no updates - }, - "parserSettings": { - "lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/, - "entryProducer": function (match) { - return { - "name": match[1], - "currentVersion": match[2], - "newVersion": match[3], - "description": `${match[1]} ${match[2]} → ${match[3]}` - }; - } - } - } - - readonly property var archBasedPMSettings: function(requiresSudo) { - return { - "listUpdatesSettings": { - "params": ["-Qu"], - "correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates - }, - "upgradeSettings": { - "params": ["-Syu"], - "requiresSudo": requiresSudo - }, - "parserSettings": { - "lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/, - "entryProducer": function (match) { - return { - "name": match[1], - "currentVersion": match[2], - "newVersion": match[3], - "description": `${match[1]} ${match[2]} → ${match[3]}` - }; - } - } - } - } - - readonly property var fedoraBasedPMSettings: { - "listUpdatesSettings": { - "params": ["list", "--upgrades", "--quiet", "--color=never"], - "correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates - }, - "upgradeSettings": { - "params": ["upgrade"], - "requiresSudo": true - }, - "parserSettings": { - "lineRegex": /^([^\s]+)\s+([^\s]+)\s+.*$/, - "entryProducer": function (match) { - return { - "name": match[1], - "currentVersion": "", - "newVersion": match[2], - "description": `${match[1]} → ${match[2]}` - }; - } - } - } - - readonly property var updateCheckerParams: { - "checkupdates": archBasedUCSettings - } - readonly property var packageManagerParams: { - "yay": archBasedPMSettings(false), - "paru": archBasedPMSettings(false), - "pacman": archBasedPMSettings(true), - "dnf": fedoraBasedPMSettings - } - readonly property list supportedDistributions: ["arch", "artix", "cachyos", "manjaro", "endeavouros", "fedora"] - readonly property int updateCount: availableUpdates.length - readonly property bool helperAvailable: pkgManager !== "" && distributionSupported - - Process { - id: distributionDetection - command: ["sh", "-c", "cat /etc/os-release | grep '^ID=' | cut -d'=' -f2 | tr -d '\"'"] - running: true - - onExited: exitCode => { - if (exitCode === 0) { - distribution = stdout.text.trim().toLowerCase(); - distributionSupported = supportedDistributions.includes(distribution); - - if (distributionSupported) { - updateFinderDetection.running = true; - pkgManagerDetection.running = true; - checkForUpdates(); - } else { - console.warn("SystemUpdate: Unsupported distribution:", distribution); - } - } else { - console.warn("SystemUpdate: Failed to detect distribution"); - } - } - - stdout: StdioCollector {} - - Component.onCompleted: { - versionDetection.running = true; - } - } - - Process { - id: versionDetection - command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -d .git ]; then echo "(git) $(git rev-parse --short HEAD)"; elif [ -f VERSION ]; then cat VERSION; fi`] - - stdout: StdioCollector { - onStreamFinished: { - shellVersion = text.trim(); - } - } - } - - Process { - id: semverDetection - command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -f VERSION ]; then cat VERSION; fi`] - running: true - - stdout: StdioCollector { - onStreamFinished: { - semverVersion = text.trim(); - } - } - } - - Process { - id: codenameDetection - command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -f CODENAME ]; then cat CODENAME; fi`] - running: true - - stdout: StdioCollector { - onStreamFinished: { - shellCodename = text.trim(); - } - } - } - - Process { - id: updateFinderDetection - command: ["sh", "-c", "which checkupdates"] - - onExited: exitCode => { - if (exitCode === 0) { - const exeFound = stdout.text.trim(); - updChecker = exeFound.split('/').pop(); - } else { - console.warn("SystemUpdate: No update checker found. Will use package manager."); - } - } - - stdout: StdioCollector {} - } - - Process { - id: pkgManagerDetection - command: ["sh", "-c", "which paru || which yay || which pacman || which dnf"] - - onExited: exitCode => { - if (exitCode === 0) { - const exeFound = stdout.text.trim(); - pkgManager = exeFound.split('/').pop(); - } else { - console.warn("SystemUpdate: No package manager found"); - } - } - - stdout: StdioCollector {} - } - - Process { - id: updateChecker - - onExited: exitCode => { - isChecking = false; - const correctExitCodes = updChecker.length > 0 ? [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.correctExitCodes) : [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.correctExitCodes); - if (correctExitCodes.includes(exitCode)) { - parseUpdates(stdout.text); - hasError = false; - errorMessage = ""; - } else { - hasError = true; - errorMessage = "Failed to check for updates"; - console.warn("SystemUpdate: Update check failed with code:", exitCode); - } - } - - stdout: StdioCollector {} - } - - Process { - id: updater - onExited: exitCode => { - checkForUpdates(); - } - } - - function checkForUpdates() { - if (!distributionSupported || (!pkgManager && !updChecker) || isChecking) - return; - isChecking = true; - hasError = false; - if (pkgManager === "paru" || pkgManager === "yay") { - const repoCmd = updChecker.length > 0 ? updChecker : `${pkgManager} -Qu`; - updateChecker.command = ["sh", "-c", `(${repoCmd} 2>/dev/null; ${pkgManager} -Qua 2>/dev/null) || true`]; - } else if (updChecker.length > 0) { - updateChecker.command = [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.params); - } else { - updateChecker.command = [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.params); - } - updateChecker.running = true; - } - - function parseUpdates(output) { - const lines = output.trim().split('\n').filter(line => line.trim()); - const updates = []; - - const regex = packageManagerParams[pkgManager].parserSettings.lineRegex; - const entryProducer = packageManagerParams[pkgManager].parserSettings.entryProducer; - - for (const line of lines) { - const match = line.match(regex); - if (match) { - updates.push(entryProducer(match)); - } - } - - availableUpdates = updates; - } - - function runUpdates() { - if (!distributionSupported || !pkgManager || updateCount === 0) - return; - const terminal = Quickshell.env("TERMINAL") || "xterm"; - - if (SettingsData.updaterUseCustomCommand && SettingsData.updaterCustomCommand.length > 0) { - const updateCommand = `${SettingsData.updaterCustomCommand} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`; - const termClass = SettingsData.updaterTerminalAdditionalParams; - - var finalCommand = [terminal]; - if (termClass.length > 0) { - finalCommand = finalCommand.concat(termClass.split(" ")); - } - finalCommand.push("-e"); - finalCommand.push("sh"); - finalCommand.push("-c"); - finalCommand.push(updateCommand); - updater.command = finalCommand; - } else { - const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" "); - const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : ""; - const updateCommand = `${sudo} ${pkgManager} ${params} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`; - - updater.command = [terminal, "-e", "sh", "-c", updateCommand]; - } - updater.running = true; - } - - Timer { - interval: 30 * 60 * 1000 - repeat: true - running: refCount > 0 && distributionSupported && (pkgManager || updChecker) - onTriggered: checkForUpdates() - } - - IpcHandler { - target: "systemupdater" - - function updatestatus(): string { - if (root.isChecking) { - return "ERROR: already checking"; - } - if (!distributionSupported) { - return "ERROR: distribution not supported"; - } - if (!pkgManager && !updChecker) { - return "ERROR: update checker not available"; - } - root.checkForUpdates(); - return "SUCCESS: Now checking..."; - } - } - - function parseVersion(versionStr) { - if (!versionStr || typeof versionStr !== "string") - return { - major: 0, - minor: 0, - patch: 0 - }; - - let v = versionStr.trim(); - if (v.startsWith("v")) - v = v.substring(1); - - const dashIdx = v.indexOf("-"); - if (dashIdx !== -1) - v = v.substring(0, dashIdx); - - const plusIdx = v.indexOf("+"); - if (plusIdx !== -1) - v = v.substring(0, plusIdx); - - const parts = v.split("."); - return { - major: parseInt(parts[0], 10) || 0, - minor: parseInt(parts[1], 10) || 0, - patch: parseInt(parts[2], 10) || 0 - }; - } - - function compareVersions(v1, v2) { - if (v1.major !== v2.major) - return v1.major - v2.major; - if (v1.minor !== v2.minor) - return v1.minor - v2.minor; - return v1.patch - v2.patch; - } - - function checkVersionRequirement(requirementStr, currentVersion) { - if (!requirementStr || typeof requirementStr !== "string") - return true; - - const req = requirementStr.trim(); - let operator = ""; - let versionPart = req; - - if (req.startsWith(">=")) { - operator = ">="; - versionPart = req.substring(2); - } else if (req.startsWith("<=")) { - operator = "<="; - versionPart = req.substring(2); - } else if (req.startsWith(">")) { - operator = ">"; - versionPart = req.substring(1); - } else if (req.startsWith("<")) { - operator = "<"; - versionPart = req.substring(1); - } else if (req.startsWith("=")) { - operator = "="; - versionPart = req.substring(1); - } else { - operator = ">="; - } - - const reqVersion = parseVersion(versionPart); - const cmp = compareVersions(currentVersion, reqVersion); - - switch (operator) { - case ">=": - return cmp >= 0; - case ">": - return cmp > 0; - case "<=": - return cmp <= 0; - case "<": - return cmp < 0; - case "=": - return cmp === 0; - default: - return cmp >= 0; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml deleted file mode 100644 index 7684f90..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml +++ /dev/null @@ -1,174 +0,0 @@ -pragma Singleton - -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - readonly property int levelInfo: 0 - readonly property int levelWarn: 1 - readonly property int levelError: 2 - property string currentMessage: "" - property int currentLevel: levelInfo - property bool toastVisible: false - property var toastQueue: [] - property string currentDetails: "" - property string currentCommand: "" - property bool hasDetails: false - property string wallpaperErrorStatus: "" - property int maxQueueSize: 3 - property var lastErrorTime: ({}) - property int errorThrottleMs: 1000 - property string currentCategory: "" - - function showToast(message, level = levelInfo, details = "", command = "", category = "") { - const now = Date.now() - const messageKey = message + level - - if (level === levelError) { - const lastTime = lastErrorTime[messageKey] || 0 - if (now - lastTime < errorThrottleMs) { - return - } - lastErrorTime[messageKey] = now - } - - if (category && level === levelError) { - if (currentCategory === category && toastVisible && currentLevel === levelError) { - currentMessage = message - currentDetails = details || "" - currentCommand = command || "" - hasDetails = currentDetails.length > 0 || currentCommand.length > 0 - resetToastState() - if (hasDetails) { - toastTimer.interval = 8000 - } else { - toastTimer.interval = 5000 - } - toastTimer.restart() - return - } - - toastQueue = toastQueue.filter(t => t.category !== category) - } - - const isDuplicate = toastQueue.some(toast => - toast.message === message && toast.level === level - ) - if (isDuplicate) { - return - } - - if (toastQueue.length >= maxQueueSize) { - if (level === levelError) { - toastQueue = toastQueue.filter(t => t.level !== levelError).slice(0, maxQueueSize - 1) - } else { - return - } - } - - toastQueue.push({ - "message": message, - "level": level, - "details": details, - "command": command, - "category": category - }) - if (!toastVisible) { - processQueue() - } - } - - function showInfo(message, details = "", command = "", category = "") { - showToast(message, levelInfo, details, command, category) - } - - function showWarning(message, details = "", command = "", category = "") { - showToast(message, levelWarn, details, command, category) - } - - function showError(message, details = "", command = "", category = "") { - showToast(message, levelError, details, command, category) - } - - function dismissCategory(category) { - if (!category) { - return - } - - if (currentCategory === category && toastVisible) { - hideToast() - return - } - - toastQueue = toastQueue.filter(t => t.category !== category) - } - - function hideToast() { - toastVisible = false - currentMessage = "" - currentDetails = "" - currentCommand = "" - currentCategory = "" - hasDetails = false - currentLevel = levelInfo - toastTimer.stop() - resetToastState() - if (toastQueue.length > 0) { - processQueue() - } - } - - function processQueue() { - if (toastQueue.length === 0) { - return - } - - const toast = toastQueue.shift() - currentMessage = toast.message - currentLevel = toast.level - currentDetails = toast.details || "" - currentCommand = toast.command || "" - currentCategory = toast.category || "" - hasDetails = currentDetails.length > 0 || currentCommand.length > 0 - toastVisible = true - resetToastState() - - if (toast.level === levelError && hasDetails) { - toastTimer.interval = 8000 - toastTimer.start() - } else { - toastTimer.interval = toast.level === levelError ? 5000 : toast.level === levelWarn ? 3000 : 1500 - toastTimer.start() - } - } - - signal resetToastState - - function stopTimer() { - toastTimer.stop() - } - - function restartTimer() { - if (hasDetails && currentLevel === levelError) { - toastTimer.interval = 8000 - toastTimer.restart() - } - } - - function clearWallpaperError() { - wallpaperErrorStatus = "" - } - - Timer { - id: toastTimer - - interval: 5000 - running: false - repeat: false - onTriggered: hideToast() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml deleted file mode 100644 index e2c6ea5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml +++ /dev/null @@ -1,49 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick -import Quickshell.Services.Mpris -import qs.Common - -Singleton { - id: root - - property string _lastArtUrl: "" - property string _bgArtSource: "" - property bool loading: false - - function loadArtwork(url) { - if (!url || url === "") { - _bgArtSource = ""; - _lastArtUrl = ""; - loading = false; - return; - } - if (url === _lastArtUrl) - return; - _lastArtUrl = url; - - if (url.startsWith("http://") || url.startsWith("https://")) { - _bgArtSource = url; - loading = false; - return; - } - - loading = true; - const localUrl = url; - const filePath = url.startsWith("file://") ? url.substring(7) : url; - Proc.runCommand("trackart", ["test", "-f", filePath], (output, exitCode) => { - if (_lastArtUrl !== localUrl) - return; - _bgArtSource = exitCode === 0 ? localUrl : ""; - loading = false; - }, 200); - } - - property MprisPlayer activePlayer: MprisController.activePlayer - - onActivePlayerChanged: { - loadArtwork(activePlayer?.trackArtUrl ?? ""); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml deleted file mode 100644 index 8378e01..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml +++ /dev/null @@ -1,35 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - property string username: "" - property string fullName: "" - property string profilePicture: "" - property string hostname: "" - property bool profileAvailable: false - - function getUserInfo() { - Proc.runCommand("userInfo", ["sh", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""], (output, exitCode) => { - if (exitCode !== 0) { - root.username = "User"; - root.fullName = "User"; - root.hostname = "System"; - return; - } - const parts = output.trim().split("|"); - if (parts.length >= 3) { - root.username = parts[0] || ""; - root.fullName = parts[1] || parts[0] || ""; - root.hostname = parts[2] || ""; - } - }, 0); - } - - Component.onCompleted: getUserInfo() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml deleted file mode 100644 index effc54e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml +++ /dev/null @@ -1,221 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common - -Singleton { - id: root - - readonly property bool available: DMSNetworkService.vpnAvailable - - property var plugins: [] - property var allExtensions: [] - property bool importing: false - property string importError: "" - - property var editConfig: null - property bool configLoading: false - - property bool pluginsLoading: false - - signal importComplete(string uuid, string name) - signal configLoaded(var config) - signal configUpdated - signal vpnDeleted(string uuid) - - Component.onCompleted: { - if (available) { - fetchPlugins(); - } - } - - Connections { - target: DMSNetworkService - function onVpnAvailableChanged() { - if (DMSNetworkService.vpnAvailable && plugins.length === 0) { - fetchPlugins(); - } - } - } - - function fetchPlugins() { - if (!available || pluginsLoading) - return; - pluginsLoading = true; - - DMSService.sendRequest("network.vpn.plugins", null, response => { - pluginsLoading = false; - if (response.error) { - console.warn("VPNService: Failed to fetch plugins:", response.error); - return; - } - if (!response.result) - return; - plugins = response.result; - const extSet = new Set(); - for (const plugin of response.result) { - for (const ext of plugin.fileExtensions || []) { - extSet.add(ext); - } - } - allExtensions = Array.from(extSet); - }); - } - - function importVpn(filePath, name = "") { - if (!available || importing) - return; - importing = true; - importError = ""; - - const params = { - file: filePath - }; - if (name) - params.name = name; - - DMSService.sendRequest("network.vpn.import", params, response => { - importing = false; - - if (response.error) { - importError = response.error; - ToastService.showError(I18n.tr("Failed to import VPN"), response.error); - return; - } - - if (!response.result) - return; - if (response.result.success) { - ToastService.showInfo(I18n.tr("VPN imported: %1").arg(response.result.name || "")); - DMSNetworkService.refreshVpnProfiles(); - importComplete(response.result.uuid || "", response.result.name || ""); - return; - } - - importError = response.result.error || "Import failed"; - ToastService.showError(I18n.tr("Failed to import VPN"), importError); - }); - } - - function getConfig(uuidOrName) { - if (!available) - return; - configLoading = true; - editConfig = null; - - DMSService.sendRequest("network.vpn.getConfig", { - uuid: uuidOrName - }, response => { - configLoading = false; - - if (response.error) { - ToastService.showError(I18n.tr("Failed to load VPN config"), response.error); - return; - } - - if (response.result) { - editConfig = response.result; - configLoaded(response.result); - } - }); - } - - function updateConfig(uuid, updates) { - if (!available) - return; - const params = { - uuid: uuid - }; - if (updates.name !== undefined) - params.name = updates.name; - if (updates.autoconnect !== undefined) - params.autoconnect = updates.autoconnect; - if (updates.data !== undefined) - params.data = updates.data; - - DMSService.sendRequest("network.vpn.updateConfig", params, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to update VPN"), response.error); - return; - } - ToastService.showInfo(I18n.tr("VPN configuration updated")); - DMSNetworkService.refreshVpnProfiles(); - getConfig(uuid); - configUpdated(); - }); - } - - function deleteVpn(uuidOrName) { - if (!available) - return; - DMSService.sendRequest("network.vpn.delete", { - uuid: uuidOrName - }, response => { - if (response.error) { - ToastService.showError(I18n.tr("Failed to delete VPN"), response.error); - return; - } - ToastService.showInfo(I18n.tr("VPN deleted")); - DMSNetworkService.refreshVpnProfiles(); - vpnDeleted(uuidOrName); - }); - } - - function getFileFilter() { - if (allExtensions.length === 0) { - return ["*.ovpn", "*.conf"]; - } - return allExtensions.map(e => "*" + e); - } - - function getExtensionsForPlugin(serviceType) { - const plugin = plugins.find(p => p.serviceType === serviceType); - if (!plugin) - return ["*.conf"]; - return (plugin.fileExtensions || [".conf"]).map(e => "*" + e); - } - - function getPluginName(serviceType) { - if (!serviceType) - return "VPN"; - - const plugin = plugins.find(p => p.serviceType === serviceType); - if (plugin) - return plugin.name; - - const svc = serviceType.toLowerCase(); - if (svc.includes("openvpn")) - return "OpenVPN"; - if (svc.includes("wireguard")) - return "WireGuard"; - if (svc.includes("openconnect")) - return "OpenConnect"; - if (svc.includes("fortissl") || svc.includes("forti")) - return "Fortinet"; - if (svc.includes("strongswan")) - return "IPsec (strongSwan)"; - if (svc.includes("libreswan")) - return "IPsec (Libreswan)"; - if (svc.includes("l2tp")) - return "L2TP/IPsec"; - if (svc.includes("pptp")) - return "PPTP"; - if (svc.includes("vpnc")) - return "Cisco (vpnc)"; - if (svc.includes("sstp")) - return "SSTP"; - - const parts = serviceType.split('.'); - return parts[parts.length - 1] || "VPN"; - } - - function getVpnTypeFromProfile(profile) { - if (!profile) - return "VPN"; - if (profile.type === "wireguard") - return "WireGuard"; - return getPluginName(profile.serviceType); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml deleted file mode 100644 index a07c563..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml +++ /dev/null @@ -1,495 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import qs.Common -import qs.Services - -Singleton { - id: root - - property bool cyclingActive: false - readonly property bool fullscreenShowing: { - if (!ToplevelManager.toplevels?.values) - return false; - for (const toplevel of ToplevelManager.toplevels.values) { - if (toplevel.fullscreen && toplevel.activated) - return true; - } - return false; - } - readonly property bool shouldPauseCycling: fullscreenShowing || SessionService.locked - property string cachedCyclingTime: SessionData.wallpaperCyclingTime - property int cachedCyclingInterval: SessionData.wallpaperCyclingInterval - property string lastTimeCheck: "" - property var monitorTimers: ({}) - property var monitorLastTimeChecks: ({}) - property var monitorProcesses: ({}) - - Component { - id: monitorTimerComponent - Timer { - property string targetScreen: "" - running: false - repeat: true - onTriggered: { - if (typeof WallpaperCyclingService !== "undefined" && targetScreen !== "" && !WallpaperCyclingService.shouldPauseCycling) { - WallpaperCyclingService.cycleNextForMonitor(targetScreen); - } - } - } - } - - Component { - id: monitorProcessComponent - Process { - property string targetScreenName: "" - property string currentWallpaper: "" - property bool goToPrevious: false - running: false - stdout: StdioCollector { - onStreamFinished: { - if (text && text.trim()) { - const files = text.trim().split('\n').filter(file => file.length > 0); - if (files.length <= 1) - return; - const wallpaperList = files.sort(); - const currentPath = currentWallpaper; - let currentIndex = wallpaperList.findIndex(path => path === currentPath); - if (currentIndex === -1) - currentIndex = 0; - let targetIndex; - if (goToPrevious) { - targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1; - } else { - targetIndex = (currentIndex + 1) % wallpaperList.length; - } - const targetWallpaper = wallpaperList[targetIndex]; - if (targetWallpaper && targetWallpaper !== currentPath) { - if (targetScreenName) { - SessionData.setMonitorWallpaper(targetScreenName, targetWallpaper); - } else { - SessionData.setWallpaper(targetWallpaper); - } - } - } - } - } - } - } - - Connections { - target: SessionData - - function onWallpaperCyclingEnabledChanged() { - updateCyclingState(); - } - - function onWallpaperCyclingModeChanged() { - updateCyclingState(); - } - - function onWallpaperCyclingIntervalChanged() { - cachedCyclingInterval = SessionData.wallpaperCyclingInterval; - if (SessionData.wallpaperCyclingMode === "interval") { - updateCyclingState(); - } - } - - function onWallpaperCyclingTimeChanged() { - cachedCyclingTime = SessionData.wallpaperCyclingTime; - if (SessionData.wallpaperCyclingMode === "time") { - updateCyclingState(); - } - } - - function onPerMonitorWallpaperChanged() { - updateCyclingState(); - } - - function onMonitorCyclingSettingsChanged() { - updateCyclingState(); - } - } - - Connections { - target: SessionService - - function onSessionUnlocked() { - if (SessionData.wallpaperCyclingEnabled || SessionData.perMonitorWallpaper) { - updateCyclingState(); - } - } - } - - function updateCyclingState() { - if (SessionData.perMonitorWallpaper) { - stopCycling(); - updatePerMonitorCycling(); - } else if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath) { - startCycling(); - stopAllMonitorCycling(); - } else { - stopCycling(); - stopAllMonitorCycling(); - } - } - - function updatePerMonitorCycling() { - if (typeof Quickshell === "undefined") - return; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - var screenName = screens[i].name; - var settings = SessionData.getMonitorCyclingSettings(screenName); - var wallpaper = SessionData.getMonitorWallpaper(screenName); - - if (settings.enabled && wallpaper && !wallpaper.startsWith("#")) { - startMonitorCycling(screenName, settings); - } else { - stopMonitorCycling(screenName); - } - } - } - - function stopAllMonitorCycling() { - var screenNames = Object.keys(monitorTimers); - for (var i = 0; i < screenNames.length; i++) { - stopMonitorCycling(screenNames[i]); - } - } - - function startCycling() { - switch (SessionData.wallpaperCyclingMode) { - case "interval": - lastTimeCheck = ""; - intervalTimer.interval = cachedCyclingInterval * 1000; - intervalTimer.start(); - cyclingActive = true; - break; - case "time": - intervalTimer.stop(); - cyclingActive = true; - checkTimeBasedCycling(); - break; - } - } - - function stopCycling() { - intervalTimer.stop(); - cyclingActive = false; - } - - function startMonitorCycling(screenName, settings) { - switch (settings.mode) { - case "interval": - { - var newChecks = Object.assign({}, monitorLastTimeChecks); - delete newChecks[screenName]; - monitorLastTimeChecks = newChecks; - - var timer = monitorTimers[screenName]; - if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) { - var newTimers = Object.assign({}, monitorTimers); - var newTimer = monitorTimerComponent.createObject(root); - newTimer.targetScreen = screenName; - newTimers[screenName] = newTimer; - monitorTimers = newTimers; - timer = newTimer; - } - if (timer) { - timer.interval = settings.interval * 1000; - timer.start(); - } - break; - } - case "time": - { - var existingTimer = monitorTimers[screenName]; - if (existingTimer) { - existingTimer.stop(); - existingTimer.destroy(); - var newTimers = Object.assign({}, monitorTimers); - delete newTimers[screenName]; - monitorTimers = newTimers; - } - - var newChecks = Object.assign({}, monitorLastTimeChecks); - newChecks[screenName] = ""; - monitorLastTimeChecks = newChecks; - break; - } - } - } - - function stopMonitorCycling(screenName) { - var timer = monitorTimers[screenName]; - if (timer) { - timer.stop(); - timer.destroy(); - var newTimers = Object.assign({}, monitorTimers); - delete newTimers[screenName]; - monitorTimers = newTimers; - } - - var process = monitorProcesses[screenName]; - if (process) { - process.destroy(); - var newProcesses = Object.assign({}, monitorProcesses); - delete newProcesses[screenName]; - monitorProcesses = newProcesses; - } - - var newChecks = Object.assign({}, monitorLastTimeChecks); - delete newChecks[screenName]; - monitorLastTimeChecks = newChecks; - } - - function cycleToNextWallpaper(screenName, wallpaperPath) { - const currentWallpaper = wallpaperPath || SessionData.wallpaperPath; - if (!currentWallpaper) - return; - const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')); - - if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) { - // Use per-monitor process - var process = monitorProcesses[screenName]; - if (!process) { - var newProcesses = Object.assign({}, monitorProcesses); - var newProcess = monitorProcessComponent.createObject(root); - newProcesses[screenName] = newProcess; - monitorProcesses = newProcesses; - process = newProcess; - } - - if (process) { - process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`]; - process.targetScreenName = screenName; - process.currentWallpaper = currentWallpaper; - process.goToPrevious = false; - process.running = true; - } - } else { - // Use global process for fallback - cyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`]; - cyclingProcess.targetScreenName = screenName || ""; - cyclingProcess.currentWallpaper = currentWallpaper; - cyclingProcess.running = true; - } - } - - function cycleToPrevWallpaper(screenName, wallpaperPath) { - const currentWallpaper = wallpaperPath || SessionData.wallpaperPath; - if (!currentWallpaper) - return; - const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')); - - if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) { - // Use per-monitor process (same as next, but with prev flag) - var process = monitorProcesses[screenName]; - if (!process) { - var newProcesses = Object.assign({}, monitorProcesses); - var newProcess = monitorProcessComponent.createObject(root); - newProcesses[screenName] = newProcess; - monitorProcesses = newProcesses; - process = newProcess; - } - - if (process) { - process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`]; - process.targetScreenName = screenName; - process.currentWallpaper = currentWallpaper; - process.goToPrevious = true; - process.running = true; - } - } else { - // Use global process for fallback - prevCyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`]; - prevCyclingProcess.targetScreenName = screenName || ""; - prevCyclingProcess.currentWallpaper = currentWallpaper; - prevCyclingProcess.running = true; - } - } - - function cycleNextManually() { - if (SessionData.wallpaperPath) { - cycleToNextWallpaper(); - // Restart timers if cycling is active - if (cyclingActive && SessionData.wallpaperCyclingEnabled) { - if (SessionData.wallpaperCyclingMode === "interval") { - intervalTimer.interval = cachedCyclingInterval * 1000; - intervalTimer.restart(); - } - } - } - } - - function cyclePrevManually() { - if (SessionData.wallpaperPath) { - cycleToPrevWallpaper(); - // Restart timers if cycling is active - if (cyclingActive && SessionData.wallpaperCyclingEnabled) { - if (SessionData.wallpaperCyclingMode === "interval") { - intervalTimer.interval = cachedCyclingInterval * 1000; - intervalTimer.restart(); - } - } - } - } - - function cycleNextForMonitor(screenName) { - if (!screenName) - return; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - if (currentWallpaper) { - cycleToNextWallpaper(screenName, currentWallpaper); - } - } - - function cyclePrevForMonitor(screenName) { - if (!screenName) - return; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - if (currentWallpaper) { - cycleToPrevWallpaper(screenName, currentWallpaper); - } - } - - function checkTimeBasedCycling() { - if (shouldPauseCycling) - return; - const currentTime = Qt.formatTime(systemClock.date, "hh:mm"); - - if (!SessionData.perMonitorWallpaper) { - if (currentTime === cachedCyclingTime && currentTime !== lastTimeCheck) { - lastTimeCheck = currentTime; - cycleToNextWallpaper(); - } else if (currentTime !== cachedCyclingTime) { - lastTimeCheck = ""; - } - } else { - checkPerMonitorTimeBasedCycling(currentTime); - } - } - - function checkPerMonitorTimeBasedCycling(currentTime) { - if (typeof Quickshell === "undefined") - return; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - var screenName = screens[i].name; - var settings = SessionData.getMonitorCyclingSettings(screenName); - var wallpaper = SessionData.getMonitorWallpaper(screenName); - - if (settings.enabled && settings.mode === "time" && wallpaper && !wallpaper.startsWith("#")) { - var lastCheck = monitorLastTimeChecks[screenName] || ""; - - if (currentTime === settings.time && currentTime !== lastCheck) { - var newChecks = Object.assign({}, monitorLastTimeChecks); - newChecks[screenName] = currentTime; - monitorLastTimeChecks = newChecks; - cycleNextForMonitor(screenName); - } else if (currentTime !== settings.time) { - var newChecks = Object.assign({}, monitorLastTimeChecks); - newChecks[screenName] = ""; - monitorLastTimeChecks = newChecks; - } - } - } - } - - Timer { - id: intervalTimer - interval: cachedCyclingInterval * 1000 - running: false - repeat: true - onTriggered: { - if (shouldPauseCycling) - return; - cycleToNextWallpaper(); - } - } - - SystemClock { - id: systemClock - precision: SystemClock.Minutes - onDateChanged: { - if ((SessionData.wallpaperCyclingMode === "time" && cyclingActive) || SessionData.perMonitorWallpaper) { - checkTimeBasedCycling(); - } - } - } - - Process { - id: cyclingProcess - - property string targetScreenName: "" - property string currentWallpaper: "" - - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (text && text.trim()) { - const files = text.trim().split('\n').filter(file => file.length > 0); - if (files.length <= 1) - return; - const wallpaperList = files.sort(); - const currentPath = cyclingProcess.currentWallpaper; - let currentIndex = wallpaperList.findIndex(path => path === currentPath); - if (currentIndex === -1) - currentIndex = 0; - - const nextIndex = (currentIndex + 1) % wallpaperList.length; - const nextWallpaper = wallpaperList[nextIndex]; - - if (nextWallpaper && nextWallpaper !== currentPath) { - if (cyclingProcess.targetScreenName) { - SessionData.setMonitorWallpaper(cyclingProcess.targetScreenName, nextWallpaper); - } else { - SessionData.setWallpaper(nextWallpaper); - } - } - } - } - } - } - - Process { - id: prevCyclingProcess - - property string targetScreenName: "" - property string currentWallpaper: "" - - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (text && text.trim()) { - const files = text.trim().split('\n').filter(file => file.length > 0); - if (files.length <= 1) - return; - const wallpaperList = files.sort(); - const currentPath = prevCyclingProcess.currentWallpaper; - let currentIndex = wallpaperList.findIndex(path => path === currentPath); - if (currentIndex === -1) - currentIndex = 0; - - const prevIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1; - const prevWallpaper = wallpaperList[prevIndex]; - - if (prevWallpaper && prevWallpaper !== currentPath) { - if (prevCyclingProcess.targetScreenName) { - SessionData.setMonitorWallpaper(prevCyclingProcess.targetScreenName, prevWallpaper); - } else { - SessionData.setWallpaper(prevWallpaper); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml deleted file mode 100644 index 134789e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml +++ /dev/null @@ -1,914 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Modules.Greetd -import "../Common/suncalc.js" as SunCalc - -Singleton { - id: root - - property int refCount: 0 - - property var selectedDate: new Date() - property var weather: ({ - "available": false, - "loading": true, - "temp": 0, - "tempF": 0, - "feelsLike": 0, - "feelsLikeF": 0, - "city": "", - "country": "", - "wCode": 0, - "humidity": 0, - "wind": "", - "sunrise": "06:00", - "sunset": "18:00", - "uv": 0, - "pressure": 0, - "precipitationProbability": 0, - "isDay": true, - "forecast": [] - }) - - property var location: null - property int updateInterval: 900000 // 15 minutes - property int retryAttempts: 0 - property int maxRetryAttempts: 3 - property int retryDelay: 30000 - property int lastFetchTime: 0 - property int minFetchInterval: 30000 - property int persistentRetryCount: 0 - - readonly property var lowPriorityCmd: ["nice", "-n", "19", "ionice", "-c3"] - readonly property var curlBaseCmd: ["curl", "-sS", "--fail", "--connect-timeout", "3", "--max-time", "6", "--limit-rate", "100k", "--compressed"] - - property var weatherIcons: ({ - "0": "clear_day", - "1": "clear_day", - "2": "partly_cloudy_day", - "3": "cloud", - "45": "foggy", - "48": "foggy", - "51": "rainy", - "53": "rainy", - "55": "rainy", - "56": "rainy", - "57": "rainy", - "61": "rainy", - "63": "rainy", - "65": "rainy", - "66": "rainy", - "67": "rainy", - "71": "cloudy_snowing", - "73": "cloudy_snowing", - "75": "snowing_heavy", - "77": "cloudy_snowing", - "80": "rainy", - "81": "rainy", - "82": "rainy", - "85": "cloudy_snowing", - "86": "snowing_heavy", - "95": "thunderstorm", - "96": "thunderstorm", - "99": "thunderstorm" - }) - - property var nightWeatherIcons: ({ - "0": "clear_night", - "1": "clear_night", - "2": "partly_cloudy_night", - "3": "cloud", - "45": "foggy", - "48": "foggy", - "51": "rainy", - "53": "rainy", - "55": "rainy", - "56": "rainy", - "57": "rainy", - "61": "rainy", - "63": "rainy", - "65": "rainy", - "66": "rainy", - "67": "rainy", - "71": "cloudy_snowing", - "73": "cloudy_snowing", - "75": "snowing_heavy", - "77": "cloudy_snowing", - "80": "rainy", - "81": "rainy", - "82": "rainy", - "85": "cloudy_snowing", - "86": "snowing_heavy", - "95": "thunderstorm", - "96": "thunderstorm", - "99": "thunderstorm" - }) - - function getWeatherIcon(code, isDay) { - if (typeof isDay === "undefined") { - isDay = weather.isDay; - } - const iconMap = isDay ? weatherIcons : nightWeatherIcons; - return iconMap[String(code)] || "cloud"; - } - - function getWeatherCondition(code) { - const conditions = { - "0": I18n.tr("Clear Sky"), - "1": I18n.tr("Clear Sky"), - "2": I18n.tr("Partly Cloudy"), - "3": I18n.tr("Overcast"), - "45": I18n.tr("Fog"), - "48": I18n.tr("Fog"), - "51": I18n.tr("Drizzle"), - "53": I18n.tr("Drizzle"), - "55": I18n.tr("Drizzle"), - "56": I18n.tr("Freezing Drizzle"), - "57": I18n.tr("Freezing Drizzle"), - "61": I18n.tr("Light Rain"), - "63": I18n.tr("Rain"), - "65": I18n.tr("Heavy Rain"), - "66": I18n.tr("Light Rain"), - "67": I18n.tr("Heavy Rain"), - "71": I18n.tr("Light Snow"), - "73": I18n.tr("Snow"), - "75": I18n.tr("Heavy Snow"), - "77": I18n.tr("Snow"), - "80": I18n.tr("Light Rain"), - "81": I18n.tr("Rain"), - "82": I18n.tr("Heavy Rain"), - "85": I18n.tr("Light Snow Showers"), - "86": I18n.tr("Heavy Snow Showers"), - "95": I18n.tr("Thunderstorm"), - "96": I18n.tr("Thunderstorm with Hail"), - "99": I18n.tr("Thunderstorm with Hail") - }; - return conditions[String(code)] || I18n.tr("Unknown"); - } - - property var moonPhaseNames: ["moon_new", "moon_waxing_crescent", "moon_first_quarter", "moon_waxing_gibbous", "moon_full", "moon_waning_gibbous", "moon_last_quarter", "moon_waning_crescent"] - - function getMoonPhase(date) { - const phases = moonPhaseNames; - const iconCount = phases.length; - const moon = SunCalc.getMoonIllumination(date); - const index = ((Math.floor(moon.phase * iconCount + 0.5) % iconCount) + iconCount) % iconCount; - - return phases[index]; - } - - function getMoonAngle(date) { - if (!location) { - return; - } - const pos = SunCalc.getMoonPosition(date, location.latitude, location.longitude); - return pos.parralacticAngle; - } - - function getLocation() { - return location; - } - - function getSunDeclination(date) { - return SunCalc.sunCoords(SunCalc.toDays(date)).dec * 180 / Math.PI; - } - - function getSunTimes(date) { - if (!location) { - return null; - } - return SunCalc.getTimes(date, location.latitude, location.longitude, location.elevation); - } - - function getEcliptic(date, points = 60) { - if (!location) { - return null; - } - const lat = location.latitude; - const lon = location.longitude; - const times = SunCalc.getTimes(date, lat, lon); - const solarNoon = times.solarNoon; - - const eclipticPoints = []; - - const sunIsNorth = getSunDeclination(date) > lat; - const transitAzimuth = sunIsNorth ? 0 : Math.PI; - - for (let i = 0; i <= points; i++) { - const t = new Date(solarNoon.getTime() + (i / points) * 24 * 60 * 60 * 1000); - const pos = SunCalc.getPosition(t, lat, lon); - - let h = (((pos.azimuth - transitAzimuth) / (2 * Math.PI)) + 1) % 1; - h = Math.max(0, Math.min(1, h)); - let v = Math.sin(pos.altitude); - v = Math.max(-1, Math.min(1, v)); - - eclipticPoints.push({ - h, - v - }); - } - - const sortedEntries = eclipticPoints.sort((a, b) => a.h - b.h); - return sortedEntries; - } - - function getCurrentSunTime(date) { - const times = getSunTimes(date); - if (!times) { - return; - } - const dateObj = new Date(date); - - const periods = [ - { - name: I18n.tr("Dawn (Astronomical Twilight)"), - start: new Date(times.nightEnd), - end: new Date(times.nauticalDawn) - }, - { - name: I18n.tr("Dawn (Nautical Twilight)"), - start: new Date(times.nauticalDawn), - end: new Date(times.dawn) - }, - { - name: I18n.tr("Dawn (Civil Twilight)"), - start: new Date(times.dawn), - end: new Date(times.sunrise) - }, - { - name: I18n.tr("Sunrise"), - start: new Date(times.sunrise), - end: new Date(times.sunriseEnd) - }, - { - name: I18n.tr("Golden Hour"), - start: new Date(times.sunriseEnd), - end: new Date(times.goldenHourEnd) - }, - { - name: I18n.tr("Morning"), - start: new Date(times.goldenHourEnd), - end: new Date(times.solarNoon) - }, - { - name: I18n.tr("Afternoon"), - start: new Date(times.solarNoon), - end: new Date(times.goldenHour) - }, - { - name: I18n.tr("Golden Hour"), - start: new Date(times.goldenHour), - end: new Date(times.sunsetStart) - }, - { - name: I18n.tr("Sunset"), - start: new Date(times.sunsetStart), - end: new Date(times.sunset) - }, - { - name: I18n.tr("Dusk (Civil Twighlight)"), - start: new Date(times.sunset), - end: new Date(times.dusk) - }, - { - name: I18n.tr("Dusk (Nautical Twilight)"), - start: new Date(times.dusk), - end: new Date(times.nauticalDusk) - }, - { - name: I18n.tr("Dusk (Astronomical Twilight)"), - start: new Date(times.nauticalDusk), - end: new Date(times.night) - }, - ]; - - const sunrise = new Date(times.nightEnd); - const sunset = new Date(times.night); - const dayPercent = dateObj > sunrise && dateObj < sunset ? (dateObj - sunrise) / (sunset - sunrise) : 0; - - for (let i = 0; i < periods.length; i++) { - const { - name, - start, - end - } = periods[i]; - if (dateObj >= start && dateObj < end) { - const percent = (dateObj - start) / (end - start); - return { - period: name, - periodIndex: i, - periodPercent: Math.min(Math.max(percent, 0), 1), - dayPercent: dayPercent - }; - } - } - - return { - period: I18n.tr("Night"), - periodIndex: 0, - periodPercent: 0, - dayPercent: dayPercent - }; - } - - function getSkyArcPosition(date, isSun) { - if (!location) { - return null; - } - const lat = location.latitude; - const lon = location.longitude; - - const pos = isSun ? SunCalc.getPosition(date, lat, lon) : SunCalc.getMoonPosition(date, lat, lon); - - const sunIsNorth = getSunDeclination(date) > lat; - const transitAzimuth = sunIsNorth ? 0 : Math.PI; - - let h = (((pos.azimuth - transitAzimuth) / (2 * Math.PI)) + 1) % 1; - h = Math.max(0, Math.min(1, h)); - // let v = pos.altitude / (Math.PI/2) - let v = Math.sin(pos.altitude); - v = Math.max(-1, Math.min(1, v)); - - return { - h, - v - }; - } - - function formatTemp(celsius, includeUnits = true, unitsShort = true) { - if (celsius == null) { - return null; - } - const value = SettingsData.useFahrenheit ? Math.round(celsius * (9 / 5) + 32) : celsius; - const unit = unitsShort ? "°" : (SettingsData.useFahrenheit ? "°F" : "°C"); - return includeUnits ? value + unit : value; - } - - function formatSpeed(kmh, includeUnits = true) { - if (kmh == null) { - return null; - } - if (SettingsData.useFahrenheit) { - const value = Math.round(kmh * 0.621371); - return includeUnits ? value + " mph" : value; - } - if (SettingsData.windSpeedUnit === "ms") { - const value = (kmh / 3.6).toFixed(1); - return includeUnits ? value + " m/s" : value; - } - return includeUnits ? kmh + " km/h" : kmh; - } - - function formatPressure(hpa, includeUnits = true) { - if (hpa == null) { - return null; - } - const value = SettingsData.useFahrenheit ? (hpa * 0.02953).toFixed(2) : hpa; - const unit = SettingsData.useFahrenheit ? "inHg" : "hPa"; - return includeUnits ? value + " " + unit : value; - } - - function formatPercent(percent, includeUnits = true) { - if (percent == null) { - return null; - } - const value = percent; - const unit = "%"; - return includeUnits ? value + unit : value; - } - - function formatVisibility(distance) { - if (distance == null) { - return null; - } - var value; - var unit; - if (SettingsData.useFahrenheit) { - value = (distance / 1609.344).toFixed(1); - unit = "mi"; - if (value < 1) { - value = Math.round(value * 5280 / 50) * 50; - unit = "ft"; - } - } else { - value = distance; - unit = "m"; - if (value > 1000) { - value = (value / 1000).toFixed(1); - unit = "km"; - } - } - - return value + " " + unit; - } - - function formatTime(isoString) { - if (!isoString) - return "--"; - - try { - const date = new Date(isoString); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return "--"; - } - } - - function calendarDayDifference(date1, date2) { - const d1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate()); - const d2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate()); - return Math.floor((d2 - d1) / (1000 * 60 * 60 * 24)); - } - - function calendarHourDifference(date1, date2) { - const d1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate(), date1.getHours()); - const d2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate(), date2.getHours()); - return Math.floor((d2 - d1) / (1000 * 60 * 60)); - } - - function formatForecastDay(isoString, index) { - if (!isoString) - return "--"; - - if (index === 0) - return I18n.tr("Today"); - if (index === 1) - return I18n.tr("Tomorrow"); - - const date = new Date(); - date.setDate(date.getDate() + index); - const locale = I18n.locale(); - return locale.dayName(date.getDay(), Locale.ShortFormat); - } - - function getWeatherApiUrl() { - if (!location) { - return null; - } - - const params = ["latitude=" + location.latitude, "longitude=" + location.longitude, "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,weather_code,surface_pressure,wind_speed_10m", "daily=sunrise,sunset,temperature_2m_max,temperature_2m_min,weather_code,precipitation_probability_max", "hourly=temperature_2m,weather_code,precipitation_probability,wind_speed_10m,apparent_temperature,relative_humidity_2m,surface_pressure,visibility,cloud_cover", "timezone=auto", "forecast_days=7"]; - - return "https://api.open-meteo.com/v1/forecast?" + params.join('&'); - } - - function getGeocodingUrl(query) { - return "https://geocoding-api.open-meteo.com/v1/search?name=" + encodeURIComponent(query) + "&count=1&language=en&format=json"; - } - - function addRef() { - refCount++; - - if (refCount === 1 && !weather.available && SettingsData.weatherEnabled) { - fetchWeather(); - } - } - - function removeRef() { - refCount = Math.max(0, refCount - 1); - } - - function updateLocation() { - const useAuto = SessionData.isGreeterMode ? GreetdSettings.useAutoLocation : SettingsData.useAutoLocation; - const coords = SessionData.isGreeterMode ? GreetdSettings.weatherCoordinates : SettingsData.weatherCoordinates; - const cityName = SessionData.isGreeterMode ? GreetdSettings.weatherLocation : SettingsData.weatherLocation; - - if (useAuto) { - getLocationFromService(); - return; - } - - if (coords) { - const parts = coords.split(","); - if (parts.length === 2) { - const lat = parseFloat(parts[0]); - const lon = parseFloat(parts[1]); - if (!isNaN(lat) && !isNaN(lon)) { - getLocationFromCoords(lat, lon); - return; - } - } - } - - if (cityName) - getLocationFromCity(cityName); - } - - function getLocationFromCoords(lat, lon) { - const url = "https://nominatim.openstreetmap.org/reverse?lat=" + lat + "&lon=" + lon + "&format=json&addressdetails=1&accept-language=en"; - reverseGeocodeFetcher.command = lowPriorityCmd.concat(curlBaseCmd).concat(["-H", "User-Agent: DankMaterialShell Weather Widget", url]); - reverseGeocodeFetcher.running = true; - } - - function getLocationFromCity(city) { - cityGeocodeFetcher.command = lowPriorityCmd.concat(curlBaseCmd).concat([getGeocodingUrl(city)]); - cityGeocodeFetcher.running = true; - } - - function getLocationFromService() { - if (!LocationService.valid) - return; - getLocationFromCoords(LocationService.latitude, LocationService.longitude); - } - - function fetchWeather() { - if (root.refCount === 0 || !SettingsData.weatherEnabled) { - return; - } - - if (!location) { - updateLocation(); - return; - } - - if (weatherFetcher.running) { - return; - } - - const now = Date.now(); - if (now - root.lastFetchTime < root.minFetchInterval) { - return; - } - - const apiUrl = getWeatherApiUrl(); - if (!apiUrl) { - return; - } - - root.lastFetchTime = now; - root.weather.loading = true; - const weatherCmd = lowPriorityCmd.concat(["curl", "-sS", "--fail", "--connect-timeout", "3", "--max-time", "6", "--limit-rate", "150k", "--compressed"]); - weatherFetcher.command = weatherCmd.concat([apiUrl]); - weatherFetcher.running = true; - } - - function forceRefresh() { - root.lastFetchTime = 0; // Reset throttle - fetchWeather(); - } - - function nextInterval() { - const jitter = Math.floor(Math.random() * 15000) - 7500; - return Math.max(60000, root.updateInterval + jitter); - } - - function handleWeatherSuccess() { - root.retryAttempts = 0; - root.persistentRetryCount = 0; - if (persistentRetryTimer.running) { - persistentRetryTimer.stop(); - } - if (updateTimer.interval !== root.updateInterval) { - updateTimer.interval = root.updateInterval; - } - } - - function handleWeatherFailure() { - root.retryAttempts++; - if (root.retryAttempts < root.maxRetryAttempts) { - retryTimer.start(); - } else { - root.retryAttempts = 0; - if (!root.weather.available) { - root.weather.loading = false; - } - const backoffDelay = Math.min(60000 * Math.pow(2, persistentRetryCount), 300000); - persistentRetryCount++; - persistentRetryTimer.interval = backoffDelay; - persistentRetryTimer.start(); - } - } - - Process { - id: reverseGeocodeFetcher - running: false - - stdout: StdioCollector { - onStreamFinished: { - const raw = text.trim(); - if (!raw || raw[0] !== "{") { - root.handleWeatherFailure(); - return; - } - - try { - const data = JSON.parse(raw); - const address = data.address || {}; - - root.location = { - city: address.hamlet || address.city || address.town || address.village || I18n.tr("Unknown"), - country: address.country || I18n.tr("Unknown"), - latitude: parseFloat(data.lat), - longitude: parseFloat(data.lon) - }; - - fetchWeather(); - } catch (e) { - root.handleWeatherFailure(); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.handleWeatherFailure(); - } - } - } - - Process { - id: cityGeocodeFetcher - running: false - - stdout: StdioCollector { - onStreamFinished: { - const raw = text.trim(); - if (!raw || raw[0] !== "{") { - root.handleWeatherFailure(); - return; - } - - try { - const data = JSON.parse(raw); - const results = data.results; - - if (!results || results.length === 0) { - throw new Error("No results found"); - } - - const result = results[0]; - - root.location = { - city: result.name, - country: result.country, - latitude: result.latitude, - longitude: result.longitude, - elevation: data.elevation - }; - - fetchWeather(); - } catch (e) { - root.handleWeatherFailure(); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.handleWeatherFailure(); - } - } - } - - Process { - id: weatherFetcher - running: false - - stdout: StdioCollector { - onStreamFinished: { - const raw = text.trim(); - if (!raw || raw[0] !== "{") { - root.handleWeatherFailure(); - return; - } - - try { - const data = JSON.parse(raw); - - if (!data.current || !data.daily || !data.hourly) { - throw new Error("Required weather data fields missing"); - } - - const hourly = data.hourly; - const hourly_forecast = []; - if (hourly.time && hourly.time.length > 0) { - for (let i = 0; i < hourly.time.length; i++) { - const tempMinC = hourly.temperature_2m_min?.[i] || 0; - const tempMaxC = hourly.temperature_2m_max?.[i] || 0; - const tempMinF = tempMinC * 9 / 5 + 32; - const tempMaxF = tempMaxC * 9 / 5 + 32; - - const tempC = hourly.temperature_2m?.[i] || 0; - const tempF = tempC * 9 / 5 + 32; - const feelsLikeC = hourly.apparent_temperature?.[i] || tempC; - const feelsLikeF = feelsLikeC * 9 / 5 + 32; - - const sunrise = new Date(data.daily.sunrise?.[Math.floor(i / 24)]); - const sunset = new Date(data.daily.sunset?.[Math.floor(i / 24)]); - const time = new Date(hourly.time[i]); - const isDay = sunrise < time && time < sunset; - - hourly_forecast.push({ - "time": formatTime(hourly.time[i]), - "rawTime": hourly.time[i], - "temp": Math.round(tempC), - "tempF": Math.round(tempF), - "feelsLike": Math.round(feelsLikeC), - "feelsLikeF": Math.round(feelsLikeF), - "wCode": hourly.weather_code?.[i] || 0, - "humidity": Math.round(hourly.relative_humidity_2m?.[i] || 0), - "wind": Math.round(hourly.wind_speed_10m?.[i] || 0), - "pressure": Math.round(hourly.surface_pressure?.[i] || 0), - "precipitationProbability": Math.round(hourly.precipitation_probability?.[i] || 0), - "visibility": Math.round(hourly.visibility?.[i] || 0), - "isDay": isDay - }); - } - } - - const daily = data.daily; - const forecast = []; - if (daily.time && daily.time.length > 0) { - for (let i = 0; i < daily.time.length; i++) { - const tempMinC = daily.temperature_2m_min?.[i] || 0; - const tempMaxC = daily.temperature_2m_max?.[i] || 0; - const tempMinF = (tempMinC * 9 / 5 + 32); - const tempMaxF = (tempMaxC * 9 / 5 + 32); - - forecast.push({ - "day": formatForecastDay(daily.time[i], i), - "wCode": daily.weather_code?.[i] || 0, - "tempMin": Math.round(tempMinC), - "tempMax": Math.round(tempMaxC), - "tempMinF": Math.round(tempMinF), - "tempMaxF": Math.round(tempMaxF), - "precipitationProbability": Math.round(daily.precipitation_probability_max?.[i] || 0), - "sunrise": daily.sunrise?.[i] ? formatTime(daily.sunrise[i]) : "", - "sunset": daily.sunset?.[i] ? formatTime(daily.sunset[i]) : "", - "rawSunrise": daily.sunrise?.[i] || "", - "rawSunset": daily.sunset?.[i] || "" - }); - } - } - - const current = data.current; - const currentUnits = data.current_units || {}; - - const tempC = current.temperature_2m || 0; - const tempF = tempC * 9 / 5 + 32; - const feelsLikeC = current.apparent_temperature || tempC; - const feelsLikeF = feelsLikeC * 9 / 5 + 32; - - root.weather = { - "available": true, - "loading": false, - "temp": Math.round(tempC), - "tempF": Math.round(tempF), - "feelsLike": Math.round(feelsLikeC), - "feelsLikeF": Math.round(feelsLikeF), - "city": root.location?.city || I18n.tr("Unknown"), - "country": root.location?.country || I18n.tr("Unknown"), - "wCode": current.weather_code || 0, - "humidity": Math.round(current.relative_humidity_2m || 0), - "wind": Math.round(current.wind_speed_10m || 0), - "sunrise": formatTime(daily.sunrise?.[0]) || "06:00", - "sunset": formatTime(daily.sunset?.[0]) || "18:00", - "rawSunrise": daily.sunrise?.[0] || "", - "rawSunset": daily.sunset?.[0] || "", - "uv": 0, - "pressure": Math.round(current.surface_pressure || 0), - "precipitationProbability": Math.round(daily.precipitation_probability_max?.[0] || 0), - "isDay": Boolean(current.is_day), - "forecast": forecast, - "hourlyForecast": hourly_forecast - }; - root.handleWeatherSuccess(); - } catch (e) { - root.handleWeatherFailure(); - } - } - } - - onExited: exitCode => { - if (exitCode !== 0) { - root.handleWeatherFailure(); - } - } - } - - Timer { - id: updateTimer - interval: nextInterval() - running: root.refCount > 0 && SettingsData.weatherEnabled && !SessionData.isGreeterMode - repeat: true - triggeredOnStart: true - onTriggered: { - root.fetchWeather(); - interval = nextInterval(); - } - } - - Timer { - id: retryTimer - interval: root.retryDelay - running: false - repeat: false - onTriggered: { - root.fetchWeather(); - } - } - - Timer { - id: persistentRetryTimer - interval: 60000 - running: false - repeat: false - onTriggered: { - if (!root.weather.available) { - root.weather.loading = true; - } - root.fetchWeather(); - } - } - - Connections { - target: LocationService - - function onLocationChanged(data) { - if (!SettingsData.useAutoLocation) - return; - if (data.latitude === 0 && data.longitude === 0) - return; - root.getLocationFromCoords(data.latitude, data.longitude); - } - } - - Component.onCompleted: { - SettingsData.weatherCoordinatesChanged.connect(() => { - root.location = null; - root.weather = { - "available": false, - "loading": true, - "temp": 0, - "tempF": 0, - "feelsLike": 0, - "feelsLikeF": 0, - "city": "", - "country": "", - "wCode": 0, - "humidity": 0, - "wind": "", - "sunrise": "06:00", - "sunset": "18:00", - "uv": 0, - "pressure": 0, - "precipitationProbability": 0, - "isDay": true, - "forecast": [] - }; - root.lastFetchTime = 0; - root.forceRefresh(); - }); - - SettingsData.weatherLocationChanged.connect(() => { - root.location = null; - root.lastFetchTime = 0; - root.forceRefresh(); - }); - - SettingsData.useAutoLocationChanged.connect(() => { - root.location = null; - root.weather = { - "available": false, - "loading": true, - "temp": 0, - "tempF": 0, - "feelsLike": 0, - "feelsLikeF": 0, - "city": "", - "country": "", - "wCode": 0, - "humidity": 0, - "wind": "", - "sunrise": "06:00", - "sunset": "18:00", - "uv": 0, - "pressure": 0, - "precipitationProbability": 0, - "isDay": true, - "forecast": [] - }; - root.lastFetchTime = 0; - root.forceRefresh(); - }); - - SettingsData.weatherEnabledChanged.connect(() => { - if (SettingsData.weatherEnabled && root.refCount > 0 && !root.weather.available) { - root.forceRefresh(); - } else if (!SettingsData.weatherEnabled) { - updateTimer.stop(); - retryTimer.stop(); - persistentRetryTimer.stop(); - if (weatherFetcher.running) { - weatherFetcher.running = false; - } - } - }); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml deleted file mode 100644 index 655a485..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml +++ /dev/null @@ -1,346 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell - -Singleton { - id: root - - property bool wlrOutputAvailable: false - property var outputs: [] - property int serial: 0 - - signal stateChanged - signal configurationApplied(bool success, string message) - - Connections { - target: DMSService - - function onCapabilitiesReceived() { - checkCapabilities(); - } - - function onConnectionStateChanged() { - if (DMSService.isConnected) { - checkCapabilities(); - return; - } - wlrOutputAvailable = false; - } - - function onWlrOutputStateUpdate(data) { - if (!wlrOutputAvailable) { - return; - } - handleStateUpdate(data); - } - } - - Component.onCompleted: { - if (!DMSService.dmsAvailable) { - return; - } - checkCapabilities(); - } - - function checkCapabilities() { - if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) { - wlrOutputAvailable = false; - return; - } - - const hasWlrOutput = DMSService.capabilities.includes("wlroutput"); - if (hasWlrOutput && !wlrOutputAvailable) { - wlrOutputAvailable = true; - console.info("WlrOutputService: wlr-output-management capability detected"); - requestState(); - return; - } - - if (!hasWlrOutput) { - wlrOutputAvailable = false; - } - } - - function requestState() { - if (!DMSService.isConnected || !wlrOutputAvailable) { - return; - } - - DMSService.sendRequest("wlroutput.getState", null, response => { - if (!response.result) { - return; - } - handleStateUpdate(response.result); - }); - } - - function handleStateUpdate(state) { - outputs = state.outputs || []; - serial = state.serial || 0; - - if (outputs.length === 0) { - console.warn("WlrOutputService: Received empty outputs list"); - } else { - console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial); - outputs.forEach((output, index) => { - console.log("WlrOutputService: Output", index, "-", output.name, "enabled:", output.enabled, "mode:", output.currentMode ? output.currentMode.width + "x" + output.currentMode.height + "@" + (output.currentMode.refresh / 1000) + "Hz" : "none"); - }); - } - stateChanged(); - } - - function getOutput(name) { - for (const output of outputs) { - if (output.name === name) { - return output; - } - } - return null; - } - - function getEnabledOutputs() { - return outputs.filter(output => output.enabled); - } - - function applyConfiguration(heads, callback) { - if (!DMSService.isConnected || !wlrOutputAvailable) { - if (callback) { - callback(false, "Not connected"); - } - return; - } - - console.log("WlrOutputService: Applying configuration for", heads.length, "outputs"); - heads.forEach((head, index) => { - console.log("WlrOutputService: Head", index, "- name:", head.name, "enabled:", head.enabled, "modeId:", head.modeId, "customMode:", JSON.stringify(head.customMode), "position:", JSON.stringify(head.position), "scale:", head.scale, "transform:", head.transform, "adaptiveSync:", head.adaptiveSync); - }); - - DMSService.sendRequest("wlroutput.applyConfiguration", { - "heads": heads - }, response => { - const success = !response.error; - const message = response.error || response.result?.message || ""; - - if (response.error) { - console.warn("WlrOutputService: applyConfiguration error:", response.error); - } else { - console.log("WlrOutputService: Configuration applied successfully"); - } - - configurationApplied(success, message); - if (callback) { - callback(success, message); - } - }); - } - - function testConfiguration(heads, callback) { - if (!DMSService.isConnected || !wlrOutputAvailable) { - if (callback) { - callback(false, "Not connected"); - } - return; - } - - console.log("WlrOutputService: Testing configuration for", heads.length, "outputs"); - - DMSService.sendRequest("wlroutput.testConfiguration", { - "heads": heads - }, response => { - const success = !response.error; - const message = response.error || response.result?.message || ""; - - if (response.error) { - console.warn("WlrOutputService: testConfiguration error:", response.error); - } else { - console.log("WlrOutputService: Configuration test passed"); - } - - if (callback) { - callback(success, message); - } - }); - } - - function setOutputEnabled(outputName, enabled, callback) { - const output = getOutput(outputName); - if (!output) { - console.warn("WlrOutputService: Output not found:", outputName); - if (callback) { - callback(false, "Output not found"); - } - return; - } - - const heads = [ - { - "name": outputName, - "enabled": enabled - } - ]; - - if (enabled && output.currentMode) { - heads[0].modeId = output.currentMode.id; - } - - applyConfiguration(heads, callback); - } - - function setOutputMode(outputName, modeId, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "modeId": modeId - } - ]; - - applyConfiguration(heads, callback); - } - - function setOutputCustomMode(outputName, width, height, refresh, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "customMode": { - "width": width, - "height": height, - "refresh": refresh - } - } - ]; - - applyConfiguration(heads, callback); - } - - function setOutputPosition(outputName, x, y, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "position": { - "x": x, - "y": y - } - } - ]; - - applyConfiguration(heads, callback); - } - - function setOutputScale(outputName, scale, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "scale": scale - } - ]; - - applyConfiguration(heads, callback); - } - - function setOutputTransform(outputName, transform, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "transform": transform - } - ]; - - applyConfiguration(heads, callback); - } - - function setOutputAdaptiveSync(outputName, state, callback) { - const heads = [ - { - "name": outputName, - "enabled": true, - "adaptiveSync": state - } - ]; - - applyConfiguration(heads, callback); - } - - function configureOutput(config, callback) { - const heads = [config]; - applyConfiguration(heads, callback); - } - - function configureMultipleOutputs(configs, callback) { - applyConfiguration(configs, callback); - } - - // High-level apply matching the generateOutputsConfig() pattern used by - // NiriService, HyprlandService and DwlService. Instead of writing a - // config file, the changes are applied directly via the - // wlr-output-management protocol. - function applyOutputsConfig(outputsData, connectedOutputs) { - if (!wlrOutputAvailable) - return; - const heads = []; - for (const name in outputsData) { - if (!connectedOutputs[name]) - continue; - const output = outputsData[name]; - const mode = (output.modes && output.current_mode >= 0) ? output.modes[output.current_mode] : null; - const enabled = !!mode; - const head = { - "name": name, - "enabled": enabled - }; - - if (enabled) { - if (mode.id !== undefined) - head.modeId = mode.id; - else - head.customMode = { - "width": mode.width, - "height": mode.height, - "refresh": mode.refresh_rate - }; - - if (output.logical) { - head.position = { - "x": output.logical.x ?? 0, - "y": output.logical.y ?? 0 - }; - head.scale = output.logical.scale ?? 1.0; - head.transform = transformFromName(output.logical.transform); - } - } - heads.push(head); - } - - if (heads.length > 0) - applyConfiguration(heads); - } - - function transformFromName(name) { - switch (name) { - case "Normal": - return 0; - case "90": - return 1; - case "180": - return 2; - case "270": - return 3; - case "Flipped": - return 4; - case "Flipped90": - return 5; - case "Flipped180": - return 6; - case "Flipped270": - return 7; - default: - return 0; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl deleted file mode 100644 index 3d58802..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl +++ /dev/null @@ -1,9 +0,0 @@ -// ! DO NOT EDIT ! -// ! AUTO-GENERATED BY DMS ! -// ! CHANGES WILL BE OVERWRITTEN ! -// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE ! - -layer-rule { - match namespace="dms:blurwallpaper" - place-within-backdrop true -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/ripple.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/ripple.frag deleted file mode 100644 index 2552bb6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/ripple.frag +++ /dev/null @@ -1,61 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float widthPx; - float heightPx; - float cornerRadiusPx; - float rippleCenterX; - float rippleCenterY; - float rippleRadius; - float rippleOpacity; - float offsetX; - float offsetY; - float parentWidth; - float parentHeight; - vec4 rippleCol; -} ubuf; - -float sdRoundRect(vec2 p, vec2 b, float r) { - vec2 q = abs(p) - (b - vec2(r)); - return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r; -} - -void main() { - if (ubuf.rippleOpacity <= 0.0 || ubuf.rippleRadius <= 0.0) { - fragColor = vec4(0.0); - return; - } - - vec2 px = qt_TexCoord0 * vec2(ubuf.widthPx, ubuf.heightPx) + vec2(ubuf.offsetX, ubuf.offsetY); - - float circleD = length(px - vec2(ubuf.rippleCenterX, ubuf.rippleCenterY)) - ubuf.rippleRadius; - float aaCircle = max(fwidth(circleD), 0.001); - float circleMask = 1.0 - smoothstep(-aaCircle, aaCircle, circleD); - if (circleMask <= 0.0) { - fragColor = vec4(0.0); - return; - } - - float rrMask = 1.0; - if (ubuf.cornerRadiusPx > 0.0) { - vec2 halfSize = vec2(ubuf.parentWidth, ubuf.parentHeight) * 0.5; - float r = clamp(ubuf.cornerRadiusPx, 0.0, min(halfSize.x, halfSize.y)); - float rrD = sdRoundRect(px - halfSize, halfSize, r); - float aaRR = max(fwidth(rrD), 0.001); - rrMask = 1.0 - smoothstep(-aaRR, aaRR, rrD); - } - - float mask = circleMask * rrMask; - if (mask <= 0.0) { - fragColor = vec4(0.0); - return; - } - - float a = ubuf.rippleCol.a * ubuf.rippleOpacity * mask * ubuf.qt_Opacity; - fragColor = vec4(ubuf.rippleCol.rgb * a, a); -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_disc.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_disc.frag deleted file mode 100644 index 254ae41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_disc.frag +++ /dev/null @@ -1,126 +0,0 @@ -// ===== wp_disc.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; // Current wallpaper -layout(binding = 2) uniform sampler2D source2; // Next wallpaper - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; // Transition progress (0.0 to 1.0) - float centerX; // X coordinate of disc center (0.0 to 1.0) - float centerY; // Y coordinate of disc center (0.0 to 1.0) - float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth) - float aspectRatio; // Width / Height of the screen - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - - // Sample textures with fill mode - vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - // Map smoothness from 0.0-1.0 to 0.001-0.5 range - // Using a non-linear mapping for better control - float mappedSmoothness = mix(0.001, 0.5, ubuf.smoothness * ubuf.smoothness); - - // Adjust UV coordinates to compensate for aspect ratio - // This makes distances circular instead of elliptical - vec2 adjustedUV = vec2(uv.x * ubuf.aspectRatio, uv.y); - vec2 adjustedCenter = vec2(ubuf.centerX * ubuf.aspectRatio, ubuf.centerY); - - // Calculate distance in aspect-corrected space - float dist = distance(adjustedUV, adjustedCenter); - - // Calculate the maximum possible distance (corner to corner) - // This ensures the disc can cover the entire screen - float maxDistX = max(ubuf.centerX * ubuf.aspectRatio, - (1.0 - ubuf.centerX) * ubuf.aspectRatio); - float maxDistY = max(ubuf.centerY, 1.0 - ubuf.centerY); - float maxDist = length(vec2(maxDistX, maxDistY)); - - // Scale progress to cover the maximum distance - // Add extra range for smoothness to ensure complete coverage - // Adjust smoothness for aspect ratio to maintain consistent visual appearance - float adjustedSmoothness = mappedSmoothness * max(1.0, ubuf.aspectRatio); - float radius = ubuf.progress * (maxDist + adjustedSmoothness); - - // Use smoothstep for a smooth edge transition - float factor = smoothstep(radius - adjustedSmoothness, radius + adjustedSmoothness, dist); - - // Mix the textures (factor = 0 inside disc, 1 outside) - fragColor = mix(color2, color1, factor); - - if (ubuf.progress <= 0.0) fragColor = color1; - - fragColor *= ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_fade.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_fade.frag deleted file mode 100644 index 31a404d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_fade.frag +++ /dev/null @@ -1,91 +0,0 @@ -// ===== wp_fade.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; -layout(binding = 2) uniform sampler2D source2; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; - - // Fill mode parameters - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; // Width of source1 image - float imageHeight1; // Height of source1 image - float imageWidth2; // Width of source2 image - float imageHeight2; // Height of source2 image - float screenWidth; // Screen width - float screenHeight; // Screen height - vec4 fillColor; // Fill color for empty areas (default: black) -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - - // Sample textures with fill mode - vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - // Mix the two textures based on progress value - fragColor = mix(color1, color2, ubuf.progress) * ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_iris_bloom.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_iris_bloom.frag deleted file mode 100644 index 548d5bd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_iris_bloom.frag +++ /dev/null @@ -1,119 +0,0 @@ -// ===== wp_iris_bloom.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; -layout(binding = 2) uniform sampler2D source2; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; - float centerX; - float centerY; - float smoothness; - float aspectRatio; - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - float edgeSoft = mix(0.001, 0.45, ubuf.smoothness * ubuf.smoothness); - - vec2 center = vec2(ubuf.centerX, ubuf.centerY); - vec2 acUv = vec2(uv.x * ubuf.aspectRatio, uv.y); - vec2 acCenter = vec2(center.x * ubuf.aspectRatio, center.y); - vec2 q = acUv - acCenter; - - float maxX = max(center.x * ubuf.aspectRatio, (1.0 - center.x) * ubuf.aspectRatio); - float maxY = max(center.y, 1.0 - center.y); - float maxDist = length(vec2(maxX, maxY)); - - float p = ubuf.progress; - p = p * p * (3.0 - 2.0 * p); - - float radius = p * maxDist; - - // squash factor for the "eye" slit - float squash = mix(0.2, 1.0, p); - q.y /= squash; - - float dist = length(q); - float t = smoothstep(radius - edgeSoft, radius + edgeSoft, dist); - - vec4 col = mix(color2, color1, t); - - if (ubuf.progress <= 0.0) col = color1; - if (ubuf.progress >= 1.0) col = color2; - - fragColor = col * ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_pixelate.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_pixelate.frag deleted file mode 100644 index 2b6fb53..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_pixelate.frag +++ /dev/null @@ -1,125 +0,0 @@ -// ===== wp_pixelate.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; // Current wallpaper (underlay) -layout(binding = 2) uniform sampler2D source2; // Next wallpaper (pixelated overlay → sharp) - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; // 0..1 - float centerX; // (unused, API compat) - float centerY; // (unused) - float smoothness; // controls starting block size (0..1) - float aspectRatio; // (unused) - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -vec2 quantizeUV(vec2 uv, float cellPx) { - vec2 screenSize = vec2(max(1.0, ubuf.screenWidth), max(1.0, ubuf.screenHeight)); - float cell = max(1.0, ceil(cellPx)); // integer pixel cells - vec2 grid = floor(uv * screenSize / cell) * cell + 0.5 * cell; - return grid / screenSize; -} - -void main() { - vec2 uv = qt_TexCoord0; - - vec4 oldCol = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - - float p = clamp(ubuf.progress, 0.0, 1.0); - float pe = p * p * (3.0 - 2.0 * p); // smootherstep for opacity - - // Screen-relative starting cell size: - // smoothness=0 → ~10% of min(screen), smoothness=1 → ~80% of min(screen) - float s = clamp(ubuf.smoothness, 0.0, 1.0); - float minSide = min(max(1.0, ubuf.screenWidth), max(1.0, ubuf.screenHeight)); - float startPx = mix(minSide * 0.10, minSide * 0.80, s); // big and obvious even on small screens - - // Cell size shrinks continuously from startPx → 1 as p grows - float cellPx = mix(startPx, 1.0, p); - - // Sample next as pixelated overlay - vec2 uvq = quantizeUV(uv, cellPx); - vec4 newPix = sampleWithFillMode(source2, uvq, ubuf.imageWidth2, ubuf.imageHeight2); - - // As we approach the end, sharpen the next from pixelated → full-res - float sharpen = smoothstep(0.75, 1.0, p); // only near the end - vec4 newFull = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - vec4 newCol = mix(newPix, newFull, sharpen); - - vec4 outColor = mix(oldCol, newCol, pe); - - // Snaps - if (p <= 0.0) outColor = oldCol; - if (p >= 1.0) outColor = newFull; - - fragColor = outColor * ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_portal.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_portal.frag deleted file mode 100644 index 21e939c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_portal.frag +++ /dev/null @@ -1,124 +0,0 @@ -// ===== wp_portal.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; // Current wallpaper (shrinks away) -layout(binding = 2) uniform sampler2D source2; // Next wallpaper (underneath) - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; // 0..1 - float centerX; // 0..1 - float centerY; // 0..1 - float smoothness; // 0..1 (edge softness) - float aspectRatio; // width / height - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - - vec4 oldCol = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 newCol = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - // Edge softness - float edgeSoft = mix(0.001, 0.45, ubuf.smoothness * ubuf.smoothness); - - // Aspect-corrected distance from center (keep circle round) - vec2 center = vec2(ubuf.centerX, ubuf.centerY); - vec2 acUv = vec2(uv.x * ubuf.aspectRatio, uv.y); - vec2 acCenter = vec2(center.x * ubuf.aspectRatio, center.y); - float dist = length(acUv - acCenter); - - // Max radius from center to cover screen - float maxDistX = max(center.x * ubuf.aspectRatio, (1.0 - center.x) * ubuf.aspectRatio); - float maxDistY = max(center.y, 1.0 - center.y); - float maxDist = length(vec2(maxDistX, maxDistY)); - - // Smooth easing for a friendly feel - float p = ubuf.progress; - p = p * p * (3.0 - 2.0 * p); - - // Portal radius shrinks from full to zero (bias by edgeSoft so it vanishes cleanly) - float radius = (1.0 - p) * (maxDist + edgeSoft) - edgeSoft; - - // Inside circle = old wallpaper; outside = new wallpaper - float t = smoothstep(radius - edgeSoft, radius + edgeSoft, dist); - // When radius is large: t ~ 0 inside (old), ~1 outside (new) - // As radius shrinks, old area collapses to center. - - vec4 col = mix(oldCol, newCol, t); - - // Snaps - if (ubuf.progress <= 0.0) col = oldCol; // full old at start - if (ubuf.progress >= 1.0) col = newCol; // full new at end - - fragColor = col * ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_stripes.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_stripes.frag deleted file mode 100644 index fcc216b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_stripes.frag +++ /dev/null @@ -1,205 +0,0 @@ -// ===== wp_stripes.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; // Current wallpaper -layout(binding = 2) uniform sampler2D source2; // Next wallpaper - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; // Transition progress (0.0 to 1.0) - float stripeCount; // Number of stripes (default 12.0) - float angle; // Angle of stripes in degrees (default 30.0) - float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth) - float aspectRatio; // Width / Height of the screen - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - - // Sample textures with fill mode - vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - // Map smoothness from 0.0-1.0 to 0.001-0.3 range - // Using a non-linear mapping for better control at low values - float mappedSmoothness = mix(0.001, 0.3, ubuf.smoothness * ubuf.smoothness); - - // Use values directly without forcing defaults - float stripes = (ubuf.stripeCount > 0.0) ? ubuf.stripeCount : 12.0; - float angleRad = radians(ubuf.angle); - float edgeSmooth = mappedSmoothness; - - // Create a coordinate system for stripes based on angle - // At 0°: vertical stripes (divide by x) - // At 45°: diagonal stripes - // At 90°: horizontal stripes (divide by y) - - // Transform coordinates based on angle - float cosA = cos(angleRad); - float sinA = sin(angleRad); - - // Project the UV position onto the stripe direction - // This gives us the position along the stripe direction - float stripeCoord = uv.x * cosA + uv.y * sinA; - - // Perpendicular coordinate (for edge movement) - float perpCoord = -uv.x * sinA + uv.y * cosA; - - // Calculate the range of perpCoord based on angle - // This determines how far edges need to travel to fully cover the screen - float minPerp = min(min(0.0 * -sinA + 0.0 * cosA, 1.0 * -sinA + 0.0 * cosA), - min(0.0 * -sinA + 1.0 * cosA, 1.0 * -sinA + 1.0 * cosA)); - float maxPerp = max(max(0.0 * -sinA + 0.0 * cosA, 1.0 * -sinA + 0.0 * cosA), - max(0.0 * -sinA + 1.0 * cosA, 1.0 * -sinA + 1.0 * cosA)); - - // Determine which stripe we're in - float stripePos = stripeCoord * stripes; - int stripeIndex = int(floor(stripePos)); - - // Determine if this is an odd or even stripe - bool isOddStripe = mod(float(stripeIndex), 2.0) != 0.0; - - // Calculate the progress for this specific stripe with wave delay - // Use absolute stripe position for consistent delay across all stripes - float normalizedStripePos = clamp(stripePos / stripes, 0.0, 1.0); - - // Increased delay and better distribution - float maxDelay = 0.1; - float stripeDelay = normalizedStripePos * maxDelay; - - // Better progress mapping that uses the full 0.0-1.0 range - // Map progress so that: - // - First stripe starts at progress = 0.0 - // - Last stripe finishes at progress = 1.0 - float stripeProgress; - if (ubuf.progress <= stripeDelay) { - stripeProgress = 0.0; - } else if (ubuf.progress >= (stripeDelay + (1.0 - maxDelay))) { - stripeProgress = 1.0; - } else { - // Scale the progress within the active window for this stripe - float activeStart = stripeDelay; - float activeEnd = stripeDelay + (1.0 - maxDelay); - stripeProgress = (ubuf.progress - activeStart) / (activeEnd - activeStart); - } - - // Use gentler easing curve - stripeProgress = stripeProgress * stripeProgress * (3.0 - 2.0 * stripeProgress); // Smootherstep instead of smoothstep - - // Use the perpendicular coordinate for edge comparison - float yPos = perpCoord; - - // Calculate edge position for this stripe - // Use the actual perpendicular coordinate range for this angle - float perpRange = maxPerp - minPerp; - float margin = edgeSmooth * 2.0; // Simplified margin calculation - float edgePosition; - if (isOddStripe) { - // Odd stripes: edge moves from max to min - edgePosition = maxPerp + margin - stripeProgress * (perpRange + margin * 2.0); - } else { - // Even stripes: edge moves from min to max - edgePosition = minPerp - margin + stripeProgress * (perpRange + margin * 2.0); - } - - // Determine which wallpaper to show based on rotated position - float mask; - if (isOddStripe) { - // Odd stripes reveal new wallpaper from bottom - mask = smoothstep(edgePosition - edgeSmooth, edgePosition + edgeSmooth, yPos); - } else { - // Even stripes reveal new wallpaper from top - mask = 1.0 - smoothstep(edgePosition - edgeSmooth, edgePosition + edgeSmooth, yPos); - } - - // Mix the wallpapers - fragColor = mix(color1, color2, mask); - - // Force exact values at start and end to prevent any bleed-through - if (ubuf.progress <= 0.0) { - fragColor = color1; // Only show old wallpaper at start - } else if (ubuf.progress >= 1.0) { - fragColor = color2; // Only show new wallpaper at end - } else { - // Add manga-style edge shadow only during transition - float edgeDist = abs(yPos - edgePosition); - float shadowStrength = 1.0 - smoothstep(0.0, edgeSmooth * 2.5, edgeDist); - shadowStrength *= 0.2 * (1.0 - abs(stripeProgress - 0.5) * 2.0); - fragColor.rgb *= (1.0 - shadowStrength); - - // Add slight vignette during transition for dramatic effect - float vignette = 1.0 - ubuf.progress * 0.1 * (1.0 - abs(stripeProgress - 0.5) * 2.0); - fragColor.rgb *= vignette; - } - - fragColor *= ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_wipe.frag b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_wipe.frag deleted file mode 100644 index 5fc6d32..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_wipe.frag +++ /dev/null @@ -1,129 +0,0 @@ -// ===== wp_wipe.frag ===== -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source1; // Current wallpaper -layout(binding = 2) uniform sampler2D source2; // Next wallpaper - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float progress; // Transition progress (0.0 to 1.0) - float direction; // 0=left, 1=right, 2=up, 3=down - float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth) - - float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad - float imageWidth1; - float imageHeight1; - float imageWidth2; - float imageHeight2; - float screenWidth; - float screenHeight; - vec4 fillColor; -} ubuf; - -vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = uv; - - if (ubuf.fillMode < 0.5) { - transformedUV = uv; - } - else if (ubuf.fillMode < 1.5) { - float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5; - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imagePixel = (screenPixel - offset) / scale; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - else if (ubuf.fillMode < 2.5) { - float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight); - vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale; - vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize; - transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5; - } - else if (ubuf.fillMode < 3.5) { - transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight)); - } - else if (ubuf.fillMode < 4.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(uv.x, fract(tileUV.y)); - } - else if (ubuf.fillMode < 5.5) { - vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight); - transformedUV = vec2(fract(tileUV.x), uv.y); - } - else { - vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight); - vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5; - vec2 imagePixel = screenPixel - imageOffset; - transformedUV = imagePixel / vec2(imgWidth, imgHeight); - } - - return transformedUV; -} - -vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) { - vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight); - - if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) { - return texture(tex, transformedUV); - } - - if (transformedUV.x < 0.0 || transformedUV.x > 1.0 || - transformedUV.y < 0.0 || transformedUV.y > 1.0) { - return ubuf.fillColor; - } - - return texture(tex, transformedUV); -} - -void main() { - vec2 uv = qt_TexCoord0; - - // Sample textures with fill mode - vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1); - vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2); - - // Map smoothness from 0.0-1.0 to 0.001-0.5 range - // Using a non-linear mapping for better control - float mappedSmoothness = mix(0.001, 0.5, ubuf.smoothness * ubuf.smoothness); - - float edge = 0.0; - float factor = 0.0; - - // Extend the progress range to account for smoothness - // This ensures the transition completes fully at the edges - float extendedProgress = ubuf.progress * (1.0 + 2.0 * mappedSmoothness) - mappedSmoothness; - - // Calculate edge position based on direction - // As progress goes from 0 to 1, we reveal source2 (new wallpaper) - if (ubuf.direction < 0.5) { - // Wipe from right to left (new image enters from right) - edge = 1.0 - extendedProgress; - factor = smoothstep(edge - mappedSmoothness, edge + mappedSmoothness, uv.x); - fragColor = mix(color1, color2, factor); - } - else if (ubuf.direction < 1.5) { - // Wipe from left to right (new image enters from left) - edge = extendedProgress; - factor = smoothstep(edge - mappedSmoothness, edge + mappedSmoothness, uv.x); - fragColor = mix(color2, color1, factor); - } - else if (ubuf.direction < 2.5) { - // Wipe from bottom to top (new image enters from bottom) - edge = 1.0 - extendedProgress; - factor = smoothstep(edge - mappedSmoothness, edge + mappedSmoothness, uv.y); - fragColor = mix(color1, color2, factor); - } - else { - // Wipe from top to bottom (new image enters from top) - edge = extendedProgress; - factor = smoothstep(edge - mappedSmoothness, edge + mappedSmoothness, uv.y); - fragColor = mix(color2, color1, factor); - } - - fragColor *= ubuf.qt_Opacity; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/ripple.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/ripple.frag.qsb deleted file mode 100644 index 5b5595a..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/ripple.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_disc.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_disc.frag.qsb deleted file mode 100644 index 364ba25..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_disc.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_fade.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_fade.frag.qsb deleted file mode 100644 index a914695..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_fade.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_iris_bloom.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_iris_bloom.frag.qsb deleted file mode 100644 index 565a761..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_iris_bloom.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_pixelate.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_pixelate.frag.qsb deleted file mode 100644 index 85236a5..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_pixelate.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_portal.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_portal.frag.qsb deleted file mode 100644 index 6ae2fec..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_portal.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_stripes.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_stripes.frag.qsb deleted file mode 100644 index e3d28b8..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_stripes.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_wipe.frag.qsb b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_wipe.frag.qsb deleted file mode 100644 index 8336454..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Shaders/qsb/wp_wipe.frag.qsb and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/VERSION b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/VERSION deleted file mode 100644 index 4233a09..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/VERSION +++ /dev/null @@ -1 +0,0 @@ -v1.5-beta diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppIconRenderer.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppIconRenderer.qml deleted file mode 100644 index 9cdb71b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppIconRenderer.qml +++ /dev/null @@ -1,130 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Widgets -import qs.Common -import qs.Services - -Item { - id: root - - required property string iconValue - required property int iconSize - property string fallbackText: "A" - property color iconColor: Theme.surfaceText - property color colorOverride: "transparent" - property real brightnessOverride: 0.0 - property real contrastOverride: 0.0 - property real saturationOverride: 0.0 - property color fallbackBackgroundColor: Theme.surfaceLight - property color fallbackTextColor: Theme.primary - property real materialIconSizeAdjustment: Theme.spacingM - property real unicodeIconScale: 0.7 - property real fallbackTextScale: 0.4 - property real iconMargins: 0 - property real fallbackLeftMargin: 0 - property real fallbackRightMargin: 0 - property real fallbackTopMargin: 0 - property real fallbackBottomMargin: 0 - - readonly property bool isMaterial: iconValue && iconValue.startsWith("material:") - readonly property bool isUnicode: iconValue && iconValue.startsWith("unicode:") - readonly property bool isSvgCorner: iconValue && iconValue.startsWith("svg+corner:") - readonly property bool isSvg: iconValue && !isSvgCorner && iconValue.startsWith("svg:") - readonly property bool isImage: iconValue && iconValue.startsWith("image:") - readonly property bool hasColorOverride: colorOverride.a > 0 - readonly property string materialName: isMaterial ? iconValue.substring(9) : "" - readonly property string unicodeChar: isUnicode ? iconValue.substring(8) : "" - readonly property string imagePath: isImage ? iconValue.substring(6) : "" - readonly property string svgSource: { - if (isSvgCorner) { - const parts = iconValue.substring(11).split("|"); - return parts[0] || ""; - } - if (isSvg) - return iconValue.substring(4); - return ""; - } - readonly property string svgCornerIcon: isSvgCorner ? (iconValue.substring(11).split("|")[1] || "") : "" - readonly property bool hasSpecialPrefix: isMaterial || isUnicode || isSvg || isSvgCorner || isImage - readonly property string iconPath: { - if (hasSpecialPrefix || !iconValue) - return ""; - return Paths.resolveIconPath(iconValue); - } - - visible: iconValue !== undefined && iconValue !== "" - - DankIcon { - anchors.centerIn: parent - name: root.materialName - size: root.iconSize - root.materialIconSizeAdjustment - color: root.hasColorOverride ? root.colorOverride : root.iconColor - visible: root.isMaterial - } - - StyledText { - anchors.centerIn: parent - text: root.unicodeChar - font.pixelSize: root.iconSize * root.unicodeIconScale - color: root.hasColorOverride ? root.colorOverride : root.iconColor - visible: root.isUnicode - } - - DankSVGIcon { - anchors.centerIn: parent - source: root.svgSource - size: root.iconSize - cornerIcon: root.svgCornerIcon - colorOverride: root.colorOverride - brightnessOverride: root.brightnessOverride - contrastOverride: root.contrastOverride - saturationOverride: root.saturationOverride - visible: root.isSvg || root.isSvgCorner - } - - CachingImage { - id: cachingImg - anchors.fill: parent - imagePath: root.imagePath - maxCacheSize: root.iconSize * 2 - visible: root.isImage && status === Image.Ready - } - - Loader { - id: iconImgLoader - anchors.fill: parent - anchors.margins: root.iconMargins - active: !root.hasSpecialPrefix && root.iconPath !== "" - sourceComponent: IconImage { - anchors.fill: parent - source: root.iconPath - backer.sourceSize: Qt.size(root.iconSize * 2, root.iconSize * 2) - mipmap: true - asynchronous: true - visible: status === Image.Ready - } - } - - Rectangle { - id: fallbackRect - - anchors.fill: parent - anchors.leftMargin: root.fallbackLeftMargin - anchors.rightMargin: root.fallbackRightMargin - anchors.topMargin: root.fallbackTopMargin - anchors.bottomMargin: root.fallbackBottomMargin - visible: !root.hasSpecialPrefix && (root.iconPath === "" || !iconImgLoader.item || iconImgLoader.item.status !== Image.Ready) - color: root.fallbackBackgroundColor - radius: Theme.cornerRadius - border.width: 0 - border.color: Theme.primarySelected - - StyledText { - anchors.centerIn: parent - text: root.fallbackText - font.pixelSize: root.iconSize * root.fallbackTextScale - color: root.fallbackTextColor - font.weight: Font.Bold - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherGridDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherGridDelegate.qml deleted file mode 100644 index f18bd94..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherGridDelegate.qml +++ /dev/null @@ -1,126 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - required property var model - required property int index - required property var gridView - property int cellWidth: 120 - property int cellHeight: 120 - property int minIconSize: 32 - property int maxIconSize: 64 - property real iconSizeRatio: 0.5 - property bool hoverUpdatesSelection: true - property bool keyboardNavigationActive: false - property int currentIndex: -1 - property bool isPlugin: model?.isPlugin || false - property real mouseAreaLeftMargin: 0 - property real mouseAreaRightMargin: 0 - property real mouseAreaBottomMargin: 0 - property real iconFallbackLeftMargin: 0 - property real iconFallbackRightMargin: 0 - property real iconFallbackBottomMargin: 0 - property real iconMaterialSizeAdjustment: 0 - property real iconUnicodeScale: 0.8 - - signal itemClicked(int index, var modelData) - signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) - signal keyboardNavigationReset - - width: cellWidth - 1 - height: cellHeight - 1 - radius: Theme.cornerRadius - color: currentIndex === index ? Theme.primaryPressed : mouseArea.containsMouse ? Theme.primaryPressed : "transparent" - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - Item { - width: iconRenderer.computedIconSize - height: iconRenderer.computedIconSize - anchors.horizontalCenter: parent.horizontalCenter - - AppIconRenderer { - id: iconRenderer - property int computedIconSize: Math.min(root.maxIconSize, Math.max(root.minIconSize, root.cellWidth * root.iconSizeRatio)) - - width: computedIconSize - height: computedIconSize - iconValue: (model.icon && model.icon !== "") ? model.icon : "" - iconSize: computedIconSize - fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A" - materialIconSizeAdjustment: root.iconMaterialSizeAdjustment - unicodeIconScale: root.iconUnicodeScale - fallbackTextScale: Math.min(28, computedIconSize * 0.5) / computedIconSize - iconMargins: 0 - fallbackLeftMargin: root.iconFallbackLeftMargin - fallbackRightMargin: root.iconFallbackRightMargin - fallbackBottomMargin: root.iconFallbackBottomMargin - } - - DankIcon { - visible: model.pinned === true - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: -4 - anchors.bottomMargin: -4 - name: "push_pin" - size: 14 - color: Theme.primary - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - width: root.cellWidth - 12 - text: model.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - maximumLineCount: 1 - wrapMode: Text.NoWrap - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - anchors.leftMargin: root.mouseAreaLeftMargin - anchors.rightMargin: root.mouseAreaRightMargin - anchors.bottomMargin: root.mouseAreaBottomMargin - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - z: 10 - onEntered: { - if (root.hoverUpdatesSelection && !root.keyboardNavigationActive) - root.gridView.currentIndex = root.index; - } - onPositionChanged: { - root.keyboardNavigationReset(); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - root.itemClicked(root.index, root.model); - } - } - onPressAndHold: mouse => { - const globalPos = mapToItem(null, mouse.x, mouse.y); - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); - } - onPressed: mouse => { - if (mouse.button === Qt.RightButton) { - const globalPos = mapToItem(null, mouse.x, mouse.y); - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); - mouse.accepted = true; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherListDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherListDelegate.qml deleted file mode 100644 index 281ad60..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/AppLauncherListDelegate.qml +++ /dev/null @@ -1,140 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property var model - required property int index - required property var listView - property int itemHeight: 60 - property int iconSize: 40 - property bool showDescription: true - property bool hoverUpdatesSelection: true - property bool keyboardNavigationActive: false - property bool isCurrentItem: false - property bool isPlugin: model?.isPlugin || false - property real mouseAreaLeftMargin: 0 - property real mouseAreaRightMargin: 0 - property real mouseAreaBottomMargin: 0 - property real iconMargins: 0 - property real iconFallbackLeftMargin: 0 - property real iconFallbackRightMargin: 0 - property real iconFallbackBottomMargin: 0 - property real iconMaterialSizeAdjustment: Theme.spacingM - property real iconUnicodeScale: 0.7 - - signal itemClicked(int index, var modelData) - signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) - signal keyboardNavigationReset - - width: listView.width - height: itemHeight - radius: Theme.cornerRadius - color: isCurrentItem ? Theme.primaryPressed : mouseArea.containsMouse ? Theme.primaryPressed : "transparent" - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingL - - AppIconRenderer { - width: root.iconSize - height: root.iconSize - anchors.verticalCenter: parent.verticalCenter - iconValue: (model.icon && model.icon !== "") ? model.icon : "" - iconSize: root.iconSize - fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A" - iconMargins: root.iconMargins - fallbackLeftMargin: root.iconFallbackLeftMargin - fallbackRightMargin: root.iconFallbackRightMargin - fallbackBottomMargin: root.iconFallbackBottomMargin - materialIconSizeAdjustment: root.iconMaterialSizeAdjustment - unicodeIconScale: root.iconUnicodeScale - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: (model.icon !== undefined && model.icon !== "") ? (parent.width - root.iconSize - Theme.spacingL) : parent.width - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - width: parent.width - (pinIcon.visible ? pinIcon.width + Theme.spacingXS : 0) - text: model.name || "" - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - wrapMode: Text.NoWrap - maximumLineCount: 1 - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: pinIcon - visible: model.pinned === true - name: "push_pin" - size: Theme.fontSizeMedium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - width: parent.width - text: model.comment || "Application" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - maximumLineCount: 1 - visible: root.showDescription && model.comment && model.comment.length > 0 - } - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - anchors.leftMargin: root.mouseAreaLeftMargin - anchors.rightMargin: root.mouseAreaRightMargin - anchors.bottomMargin: root.mouseAreaBottomMargin - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - z: 10 - onEntered: { - if (root.hoverUpdatesSelection && !root.keyboardNavigationActive) - root.listView.currentIndex = root.index; - } - onPositionChanged: { - root.keyboardNavigationReset(); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - root.itemClicked(root.index, root.model); - } - } - onPressAndHold: mouse => { - const globalPos = mapToItem(null, mouse.x, mouse.y); - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); - } - onPressed: mouse => { - if (mouse.button === Qt.RightButton) { - const globalPos = mapToItem(null, mouse.x, mouse.y); - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); - mouse.accepted = true; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/CachingImage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/CachingImage.qml deleted file mode 100644 index 5ffec09..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/CachingImage.qml +++ /dev/null @@ -1,102 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property string imagePath: "" - property int maxCacheSize: 512 - property int status: isAnimated ? animatedImg.status : staticImg.status - property int fillMode: Image.PreserveAspectCrop - - readonly property bool isRemoteUrl: imagePath.startsWith("http://") || imagePath.startsWith("https://") - readonly property bool isAnimated: { - if (!imagePath) - return false; - const lower = imagePath.toLowerCase(); - return lower.endsWith(".gif") || lower.endsWith(".webp"); - } - readonly property string normalizedPath: { - if (!imagePath) - return ""; - if (isRemoteUrl) - return imagePath; - if (imagePath.startsWith("file://")) - return imagePath.substring(7); - return imagePath; - } - - function djb2Hash(str) { - if (!str) - return ""; - let hash = 5381; - for (let i = 0; i < str.length; i++) { - hash = ((hash << 5) + hash) + str.charCodeAt(i); - hash = hash & 0x7FFFFFFF; - } - return hash.toString(16).padStart(8, '0'); - } - - readonly property string imageHash: normalizedPath ? djb2Hash(normalizedPath) : "" - readonly property string cachePath: imageHash && !isRemoteUrl && !isAnimated ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : "" - readonly property string encodedImagePath: { - if (!normalizedPath) - return ""; - if (isRemoteUrl) - return normalizedPath; - return "file://" + normalizedPath.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - AnimatedImage { - id: animatedImg - anchors.fill: parent - visible: root.isAnimated - asynchronous: true - fillMode: root.fillMode - source: root.isAnimated ? root.imagePath : "" - playing: visible && status === AnimatedImage.Ready - } - - Image { - id: staticImg - anchors.fill: parent - visible: !root.isAnimated - asynchronous: true - fillMode: root.fillMode - sourceSize.width: root.maxCacheSize - sourceSize.height: root.maxCacheSize - smooth: true - - onStatusChanged: { - if (source == root.cachePath && status === Image.Error) { - source = root.encodedImagePath; - return; - } - if (root.isRemoteUrl || source != root.encodedImagePath || status !== Image.Ready || !root.cachePath) - return; - Paths.mkdir(Paths.imagecache); - const grabPath = root.cachePath; - if (visible && width > 0 && height > 0 && Window.window?.visible) { - grabToImage(res => res.saveToFile(grabPath)); - } - } - } - - onImagePathChanged: { - if (!imagePath) { - staticImg.source = ""; - return; - } - if (isAnimated) - return; - if (isRemoteUrl) { - staticImg.source = imagePath; - return; - } - Paths.mkdir(Paths.imagecache); - const hash = djb2Hash(normalizedPath); - const cPath = hash ? `${Paths.stringify(Paths.imagecache)}/${hash}@${maxCacheSize}x${maxCacheSize}.png` : ""; - const encoded = "file://" + normalizedPath.split('/').map(s => encodeURIComponent(s)).join('/'); - staticImg.source = cPath || encoded; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankActionButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankActionButton.qml deleted file mode 100644 index c23e84b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankActionButton.qml +++ /dev/null @@ -1,44 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - property string iconName: "" - property int iconSize: Theme.iconSize - 4 - property color iconColor: Theme.surfaceText - property color backgroundColor: "transparent" - property bool circular: true - property bool enabled: true - property int buttonSize: 32 - property var tooltipText: null - property string tooltipSide: "bottom" - - signal clicked - signal entered - signal exited - - width: buttonSize - height: buttonSize - radius: Theme.cornerRadius - color: backgroundColor - - DankIcon { - anchors.centerIn: parent - name: root.iconName - size: root.iconSize - color: root.iconColor - } - - StateLayer { - disabled: !root.enabled - stateColor: Theme.primary - cornerRadius: root.radius - onClicked: root.clicked() - onEntered: root.entered() - onExited: root.exited() - tooltipText: root.tooltipText - tooltipSide: root.tooltipSide - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankAlbumArt.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankAlbumArt.qml deleted file mode 100644 index d5f8d10..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankAlbumArt.qml +++ /dev/null @@ -1,161 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import Quickshell.Services.Mpris -import qs.Common -import qs.Services - -Item { - id: root - - property MprisPlayer activePlayer - property string artUrl: (activePlayer?.trackArtUrl) || "" - property string lastValidArtUrl: "" - property alias albumArtStatus: albumArt.imageStatus - property real albumSize: Math.min(width, height) * 0.88 - property bool showAnimation: true - property real animationScale: 1.0 - - onArtUrlChanged: { - if (artUrl && albumArt.status !== Image.Error) { - lastValidArtUrl = artUrl; - } - } - - Loader { - active: activePlayer?.playbackState === MprisPlaybackState.Playing && showAnimation - sourceComponent: Component { - Ref { - service: CavaService - } - } - } - - Shape { - id: morphingBlob - width: parent.width * 1.1 - height: parent.height * 1.1 - anchors.centerIn: parent - visible: CavaService.cavaAvailable && activePlayer?.playbackState === MprisPlaybackState.Playing && showAnimation - asynchronous: false - antialiasing: true - preferredRendererType: Shape.CurveRenderer - z: 0 - layer.enabled: false - - readonly property real centerX: width / 2 - readonly property real centerY: height / 2 - readonly property real baseRadius: Math.min(width, height) * 0.41 * root.animationScale - readonly property int segments: 28 - - property var audioLevels: { - if (!CavaService.cavaAvailable || CavaService.values.length === 0) { - return [0.5, 0.3, 0.7, 0.4, 0.6, 0.5, 0.8, 0.2, 0.9, 0.6]; - } - return CavaService.values; - } - - property var smoothedLevels: [0.5, 0.3, 0.7, 0.4, 0.6, 0.5, 0.8, 0.2, 0.9, 0.6] - property var cubics: [] - - Connections { - target: CavaService - function onValuesChanged() { - if (morphingBlob.visible) { - morphingBlob.updatePath(); - } - } - } - - Component { - id: cubicSegment - PathCubic {} - } - - Component.onCompleted: { - shapePath.pathElements.push(Qt.createQmlObject('import QtQuick; import QtQuick.Shapes; PathMove {}', shapePath)); - - for (let i = 0; i < segments; i++) { - const seg = cubicSegment.createObject(shapePath); - shapePath.pathElements.push(seg); - cubics.push(seg); - } - - updatePath(); - } - - function updatePath() { - if (cubics.length === 0) - return; - - const alpha = 0.35; - const minLen = Math.min(smoothedLevels.length, audioLevels.length); - for (let i = 0; i < minLen; i++) { - smoothedLevels[i] += alpha * (audioLevels[i] - smoothedLevels[i]); - } - - const angleStep = 2 * Math.PI / segments; - const tension3 = 0.16666667; - const startMove = shapePath.pathElements[0]; - - const points = new Array(segments); - for (let i = 0; i < segments; i++) { - const angle = i * angleStep; - const audioIndex = i % 10; - const rawLevel = smoothedLevels[audioIndex] || 0; - const clampedLevel = rawLevel < 0 ? 0 : (rawLevel > 100 ? 100 : rawLevel); - const audioLevel = Math.max(0.15, Math.sqrt(clampedLevel * 0.01)) * 0.5; - const radius = baseRadius * (1.0 + audioLevel); - points[i] = { - x: centerX + Math.cos(angle) * radius, - y: centerY + Math.sin(angle) * radius - }; - } - - startMove.x = points[0].x; - startMove.y = points[0].y; - - for (let i = 0; i < segments; i++) { - const p0 = points[(i + segments - 1) % segments]; - const p1 = points[i]; - const p2 = points[(i + 1) % segments]; - const p3 = points[(i + 2) % segments]; - - const seg = cubics[i]; - seg.control1X = p1.x + (p2.x - p0.x) * tension3; - seg.control1Y = p1.y + (p2.y - p0.y) * tension3; - seg.control2X = p2.x - (p3.x - p1.x) * tension3; - seg.control2Y = p2.y - (p3.y - p1.y) * tension3; - seg.x = p2.x; - seg.y = p2.y; - } - } - - ShapePath { - id: shapePath - fillColor: Theme.primary - strokeColor: "transparent" - strokeWidth: 0 - joinStyle: ShapePath.RoundJoin - fillRule: ShapePath.WindingFill - } - } - - DankCircularImage { - id: albumArt - width: albumSize - height: albumSize - anchors.centerIn: parent - z: 1 - - imageSource: artUrl || lastValidArtUrl || "" - fallbackIcon: "album" - border.color: Theme.primary - border.width: 2 - - onImageSourceChanged: { - if (imageSource && imageStatus !== Image.Error) { - lastValidArtUrl = imageSource; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankBackdrop.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankBackdrop.qml deleted file mode 100644 index 3db7c0c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankBackdrop.qml +++ /dev/null @@ -1,64 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common - -Item { - id: root - - anchors.fill: parent - - property string screenName: "" - property bool isColorWallpaper: { - var currentWallpaper = SessionData.getMonitorWallpaper(screenName) - return currentWallpaper && currentWallpaper.startsWith("#") - } - - Rectangle { - anchors.fill: parent - color: isColorWallpaper ? SessionData.getMonitorWallpaper(screenName) : Theme.background - } - - Rectangle { - x: parent.width * 0.7 - y: -parent.height * 0.3 - width: parent.width * 0.8 - height: parent.height * 1.5 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) - rotation: 35 - visible: !isColorWallpaper - } - - Rectangle { - x: parent.width * 0.85 - y: -parent.height * 0.2 - width: parent.width * 0.4 - height: parent.height * 1.2 - color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.12) - rotation: 35 - visible: !isColorWallpaper - } - - Image { - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.leftMargin: Theme.spacingXL * 2 - anchors.bottomMargin: Theme.spacingXL * 2 - width: 200 - height: width * (569.94629 / 506.50931) - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg" - opacity: 0.25 - visible: !isColorWallpaper - layer.enabled: true - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButton.qml deleted file mode 100644 index ea8a202..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButton.qml +++ /dev/null @@ -1,99 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string text: "" - property string iconName: "" - property int iconSize: Theme.iconSizeSmall - property bool enabled: true - property bool hovered: mouseArea.containsMouse - property bool pressed: mouseArea.pressed - property color backgroundColor: Theme.buttonBg - property color textColor: Theme.buttonText - property int buttonHeight: 40 - property int horizontalPadding: Theme.spacingL - property bool enableScaleAnimation: false - property bool enableRipple: typeof SettingsData !== "undefined" ? (SettingsData.enableRippleEffects ?? true) : true - - signal clicked - - width: Math.max(contentRow.implicitWidth + horizontalPadding * 2, 64) - height: buttonHeight - radius: Theme.cornerRadius - color: backgroundColor - opacity: enabled ? 1 : 0.4 - scale: (enableScaleAnimation && pressed) ? 0.98 : 1.0 - - Behavior on scale { - enabled: enableScaleAnimation && Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankAnim { - duration: 100 - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - - Rectangle { - id: stateLayer - anchors.fill: parent - radius: parent.radius - color: { - if (pressed) - return Theme.withAlpha(root.textColor, 0.20); - if (hovered) - return Theme.withAlpha(root.textColor, 0.12); - return "transparent"; - } - - Behavior on color { - ColorAnimation { - duration: Theme.shorterDuration - easing.type: Theme.standardEasing - } - } - } - - DankRipple { - id: rippleLayer - rippleColor: root.textColor - cornerRadius: root.radius - enableRipple: root.enableRipple - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: root.iconName - size: root.iconSize - color: root.textColor - visible: root.iconName !== "" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: root.textColor - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: root.enabled - onPressed: mouse => { - if (root.enableRipple) - rippleLayer.trigger(mouse.x, mouse.y); - } - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButtonGroup.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButtonGroup.qml deleted file mode 100644 index 02e145e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankButtonGroup.qml +++ /dev/null @@ -1,236 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Row { - id: root - - property var model: [] - property int currentIndex: -1 - property string selectionMode: "single" - property bool multiSelect: selectionMode === "multi" - property var initialSelection: [] - property var currentSelection: initialSelection - property bool checkEnabled: true - property int buttonHeight: 40 - property int minButtonWidth: 64 - property int buttonPadding: Theme.spacingL - property int checkIconSize: Theme.iconSizeSmall - property int textSize: Theme.fontSizeMedium - property bool userInteracted: false - - signal selectionChanged(int index, bool selected) - signal animationCompleted - - spacing: Theme.spacingXS - - Timer { - id: animationTimer - interval: Theme.shortDuration - onTriggered: { - root.userInteracted = false; - root.animationCompleted(); - } - } - - function isSelected(index) { - if (multiSelect) { - return repeater.itemAt(index)?.selected || false; - } - return index === currentIndex; - } - - function selectItem(index) { - userInteracted = true; - if (multiSelect) { - const modelValue = model[index]; - let newSelection = [...currentSelection]; - const isCurrentlySelected = newSelection.includes(modelValue); - - if (isCurrentlySelected) { - newSelection = newSelection.filter(item => item !== modelValue); - } else { - newSelection.push(modelValue); - } - - currentSelection = newSelection; - selectionChanged(index, !isCurrentlySelected); - animationTimer.restart(); - } else { - const oldIndex = currentIndex; - selectionChanged(index, true); - if (oldIndex !== index && oldIndex >= 0) { - selectionChanged(oldIndex, false); - } - animationTimer.restart(); - } - } - - Repeater { - id: repeater - model: ScriptModel { - values: root.model - } - - delegate: Rectangle { - id: segment - - property bool selected: multiSelect ? root.currentSelection.includes(modelData) : (index === root.currentIndex) - property bool hovered: mouseArea.containsMouse - property bool pressed: mouseArea.pressed - property bool isFirst: index === 0 - property bool isLast: index === repeater.count - 1 - property bool visualFirst: I18n.isRtl ? isLast : isFirst - property bool visualLast: I18n.isRtl ? isFirst : isLast - property bool prevSelected: index > 0 ? root.isSelected(index - 1) : false - property bool nextSelected: index < repeater.count - 1 ? root.isSelected(index + 1) : false - - width: Math.max(contentItem.implicitWidth + root.buttonPadding * 2, root.minButtonWidth) + (selected ? 4 : 0) - height: root.buttonHeight - - color: selected ? Theme.buttonBg : Theme.withAlpha(Theme.surfaceVariant, Theme.popupTransparency) - border.color: "transparent" - border.width: 0 - - topLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius) - bottomLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius) - topRightRadius: (visualLast || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius) - bottomRightRadius: (visualLast || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius) - - Behavior on width { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on topLeftRadius { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on topRightRadius { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on bottomLeftRadius { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on bottomRightRadius { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - enabled: root.userInteracted - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Rectangle { - id: stateLayer - anchors.fill: parent - topLeftRadius: parent.topLeftRadius - bottomLeftRadius: parent.bottomLeftRadius - topRightRadius: parent.topRightRadius - bottomRightRadius: parent.bottomRightRadius - color: { - if (pressed) - return selected ? Theme.buttonPressed : Theme.surfaceTextHover; - if (hovered) - return selected ? Theme.buttonHover : Theme.surfaceTextHover; - return "transparent"; - } - - Behavior on color { - ColorAnimation { - duration: Theme.shorterDuration - easing.type: Theme.standardEasing - } - } - } - - DankRipple { - id: segmentRipple - cornerRadius: Theme.cornerRadius - rippleColor: segment.selected ? Theme.buttonText : Theme.surfaceVariantText - } - - Item { - id: contentItem - anchors.centerIn: parent - implicitWidth: contentRow.implicitWidth - implicitHeight: contentRow.implicitHeight - - Row { - id: contentRow - spacing: Theme.spacingS - - DankIcon { - id: checkIcon - name: "check" - size: root.checkIconSize - color: segment.selected ? Theme.buttonText : Theme.surfaceVariantText - visible: root.checkEnabled && segment.selected - opacity: segment.selected ? 1 : 0 - scale: segment.selected ? 1 : 0.6 - anchors.verticalCenter: parent.verticalCenter - - Behavior on opacity { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on scale { - enabled: root.userInteracted - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - } - - StyledText { - id: buttonText - text: typeof modelData === "string" ? modelData : modelData.text || "" - font.pixelSize: root.textSize - font.weight: segment.selected ? Font.Medium : Font.Normal - color: segment.selected ? Theme.buttonText : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => segmentRipple.trigger(mouse.x, mouse.y) - onClicked: root.selectItem(index) - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCircularImage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCircularImage.qml deleted file mode 100644 index 36cbfe4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCircularImage.qml +++ /dev/null @@ -1,171 +0,0 @@ -import QtQuick -import QtQuick.Window -import QtQuick.Effects -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string imageSource: "" - property string fallbackIcon: "notifications" - property string fallbackText: "" - property bool hasImage: imageSource !== "" - readonly property bool shouldProbe: imageSource !== "" && !imageSource.startsWith("image://") - // Probe with AnimatedImage first; once loaded, check frameCount to decide. - readonly property bool isAnimated: shouldProbe && probe.status === Image.Ready && probe.frameCount > 1 - readonly property var activeImage: isAnimated ? probe : staticImage - property int imageStatus: activeImage.status - - signal imageSaved(string filePath) - - property string _pendingSavePath: "" - property var _attachedWindow: root.Window.window - - on_AttachedWindowChanged: { - if (_attachedWindow && _pendingSavePath !== "") { - Qt.callLater(function () { - if (root._pendingSavePath !== "") { - let path = root._pendingSavePath; - root._pendingSavePath = ""; - root.saveImageToFile(path); - } - }); - } - } - - function saveImageToFile(filePath) { - if (activeImage.status !== Image.Ready) - return false; - - if (!activeImage.Window.window) { - _pendingSavePath = filePath; - return true; - } - - activeImage.grabToImage(function (result) { - if (result && result.saveToFile(filePath)) { - root.imageSaved(filePath); - } - }); - return true; - } - - radius: width / 2 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - border.color: "transparent" - border.width: 0 - - // Probe: loads as AnimatedImage to detect frame count. - AnimatedImage { - id: probe - anchors.fill: parent - anchors.margins: 2 - asynchronous: true - fillMode: Image.PreserveAspectCrop - smooth: true - mipmap: true - cache: true - visible: false - source: root.shouldProbe ? root.imageSource : "" - } - - // Static fallback: used once probe confirms the image is not animated. - Image { - id: staticImage - anchors.fill: parent - anchors.margins: 2 - asynchronous: true - fillMode: Image.PreserveAspectCrop - smooth: true - mipmap: true - cache: true - visible: false - sourceSize.width: Math.max(width * 2, 128) - sourceSize.height: Math.max(height * 2, 128) - source: !root.shouldProbe ? root.imageSource : "" - } - - // Once the probe loads, if not animated, hand off to Image and unload probe. - Connections { - target: probe - function onStatusChanged() { - if (!root.shouldProbe) - return; - switch (probe.status) { - case Image.Ready: - if (probe.frameCount <= 1) { - staticImage.source = root.imageSource; - probe.source = ""; - } - break; - case Image.Error: - staticImage.source = root.imageSource; - probe.source = ""; - break; - } - } - } - - // If imageSource changes, reset: re-probe with AnimatedImage. - onImageSourceChanged: { - if (root.shouldProbe) { - staticImage.source = ""; - probe.source = root.imageSource; - } else { - probe.source = ""; - staticImage.source = root.imageSource; - } - } - - MultiEffect { - anchors.fill: parent - anchors.margins: 2 - source: root.activeImage - maskEnabled: true - maskSource: circularMask - visible: root.activeImage.status === Image.Ready && root.imageSource !== "" - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - - Item { - id: circularMask - anchors.centerIn: parent - width: parent.width - 4 - height: parent.height - 4 - layer.enabled: true - layer.smooth: true - visible: false - - Rectangle { - anchors.fill: parent - radius: width / 2 - color: "black" - antialiasing: true - } - } - - AppIconRenderer { - anchors.centerIn: parent - width: Math.round(parent.width * 0.75) - height: width - visible: (root.activeImage.status !== Image.Ready || root.imageSource === "") && root.fallbackIcon !== "" - iconValue: root.fallbackIcon - iconSize: width - iconColor: Theme.surfaceVariantText - materialIconSizeAdjustment: 0 - fallbackText: root.fallbackText - fallbackBackgroundColor: "transparent" - fallbackTextColor: Theme.surfaceVariantText - } - - StyledText { - anchors.centerIn: parent - visible: root.imageSource === "" && root.fallbackIcon === "" && root.fallbackText !== "" - text: root.fallbackText - font.pixelSize: Math.max(12, parent.width * 0.5) - font.weight: Font.Bold - color: Theme.surfaceVariantText - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCollapsibleSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCollapsibleSection.qml deleted file mode 100644 index 0ed0e59..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankCollapsibleSection.qml +++ /dev/null @@ -1,130 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Widgets - -ColumnLayout { - id: root - - required property string title - property string description: "" - property bool expanded: false - property bool showBackground: false - property alias headerColor: headerRect.color - - signal toggleRequested - - spacing: Theme.spacingS - Layout.fillWidth: true - - Rectangle { - id: headerRect - Layout.fillWidth: true - Layout.preferredHeight: Math.max(titleRow.implicitHeight + Theme.paddingM * 2, 48) - radius: Theme.cornerRadius - color: "transparent" - - RowLayout { - id: titleRow - anchors.fill: parent - anchors.leftMargin: Theme.paddingM - anchors.rightMargin: Theme.paddingM - spacing: Theme.spacingM - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - Layout.fillWidth: true - } - - DankIcon { - name: "expand_more" - size: Theme.iconSizeSmall - rotation: root.expanded ? 180 : 0 - - Behavior on rotation { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankAnim { - duration: Theme.shortDuration - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - } - } - - StateLayer { - anchors.fill: parent - onClicked: { - root.toggleRequested(); - root.expanded = !root.expanded; - } - } - } - - default property alias content: contentColumn.data - - Item { - id: contentWrapper - Layout.fillWidth: true - Layout.preferredHeight: root.expanded ? (contentColumn.implicitHeight + Theme.spacingS * 2) : 0 - clip: true - - Behavior on Layout.preferredHeight { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankAnim { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - - Rectangle { - id: backgroundRect - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: root.showBackground && root.expanded ? 1.0 : 0.0 - visible: root.showBackground - - Behavior on opacity { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankAnim { - duration: Theme.shortDuration - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - } - - ColumnLayout { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - y: Theme.spacingS - anchors.leftMargin: Theme.paddingM - anchors.rightMargin: Theme.paddingM - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingS - opacity: root.expanded ? 1.0 : 0.0 - - Behavior on opacity { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankAnim { - duration: Theme.shortDuration - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - - StyledText { - id: descriptionText - Layout.fillWidth: true - Layout.topMargin: root.description !== "" ? Theme.spacingXS : 0 - Layout.bottomMargin: root.description !== "" ? Theme.spacingS : 0 - visible: root.description !== "" - text: root.description - color: Theme.surfaceTextSecondary - font.pixelSize: Theme.fontSizeSmall - wrapMode: Text.Wrap - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankDropdown.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankDropdown.qml deleted file mode 100644 index 05b962a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankDropdown.qml +++ /dev/null @@ -1,456 +0,0 @@ -import "../Common/fzf.js" as Fzf -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - function checkParentDisablesTransparency() { - let p = parent; - while (p) { - if (p.disablePopupTransparency === true) - return true; - p = p.parent; - } - return false; - } - - property string text: "" - property string description: "" - property string currentValue: "" - property var options: [] - property var optionIcons: [] - property bool enableFuzzySearch: false - property var optionIconMap: ({}) - - function rebuildIconMap() { - const map = {}; - for (let i = 0; i < options.length; i++) { - if (optionIcons.length > i) - map[options[i]] = optionIcons[i]; - } - optionIconMap = map; - } - - onOptionsChanged: rebuildIconMap() - onOptionIconsChanged: rebuildIconMap() - - property int popupWidthOffset: 0 - property int maxPopupHeight: 400 - property bool openUpwards: false - property int popupWidth: 0 - property bool alignPopupRight: false - property int dropdownWidth: 200 - property bool compactMode: text === "" && description === "" - property bool addHorizontalPadding: false - property string emptyText: "" - property bool usePopupTransparency: !checkParentDisablesTransparency() - - signal valueChanged(string value) - - function closeDropdownMenu() { - dropdownMenu.close(); - } - - function resetSearch() { - searchField.text = ""; - dropdownMenu.fzfFinder = null; - dropdownMenu.searchQuery = ""; - dropdownMenu.selectedIndex = -1; - } - - width: compactMode ? dropdownWidth : parent.width - implicitHeight: compactMode ? 40 : Math.max(60, labelColumn.implicitHeight + Theme.spacingM) - - Component.onDestruction: { - if (dropdownMenu.visible) - dropdownMenu.close(); - } - - Column { - id: labelColumn - - anchors.left: parent.left - anchors.right: dropdown.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: root.addHorizontalPadding ? Theme.spacingM : 0 - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingXS - visible: !root.compactMode - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: description.length > 0 - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - id: dropdown - - width: root.compactMode ? parent.width : (root.popupWidth === -1 ? undefined : (root.popupWidth > 0 ? root.popupWidth : root.dropdownWidth)) - height: 40 - anchors.right: parent.right - anchors.rightMargin: root.addHorizontalPadding && !root.compactMode ? Theme.spacingM : 0 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: dropdownArea.containsMouse || dropdownMenu.visible ? Theme.surfaceContainerHigh : (root.usePopupTransparency ? Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) : Theme.surfaceContainer) - border.color: dropdownMenu.visible ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: dropdownMenu.visible ? 2 : 1 - - MouseArea { - id: dropdownArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (dropdownMenu.visible) { - dropdownMenu.close(); - return; - } - - dropdownMenu.open(); - - let currentIndex = root.options.indexOf(root.currentValue); - listView.positionViewAtIndex(currentIndex, ListView.Beginning); - - const pos = dropdown.mapToItem(Overlay.overlay, 0, 0); - const popupW = dropdownMenu.width; - const popupH = dropdownMenu.height; - const overlayH = Overlay.overlay.height; - const goUp = root.openUpwards || pos.y + dropdown.height + popupH + 4 > overlayH; - dropdownMenu.x = root.alignPopupRight ? pos.x + dropdown.width - popupW : pos.x - (root.popupWidthOffset / 2); - dropdownMenu.y = goUp ? pos.y - popupH - 4 : pos.y + dropdown.height + 4; - if (root.enableFuzzySearch) - searchField.forceActiveFocus(); - } - } - - Row { - id: contentRow - - anchors.left: parent.left - anchors.right: expandIcon.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.optionIconMap[root.currentValue] ?? "" - size: 18 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: name !== "" - } - - StyledText { - text: root.currentValue - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: contentRow.width - (contentRow.children[0].visible ? contentRow.children[0].width + contentRow.spacing : 0) - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - - DankIcon { - id: expandIcon - - name: dropdownMenu.visible ? "expand_less" : "expand_more" - size: 20 - color: Theme.surfaceText - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingS - - Behavior on rotation { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Popup { - id: dropdownMenu - - property string searchQuery: "" - property var filteredOptions: { - if (!root.enableFuzzySearch || searchQuery.length === 0) - return root.options; - if (!fzfFinder) - return root.options; - return fzfFinder.find(searchQuery).map(r => r.item); - } - property int selectedIndex: -1 - property var fzfFinder: null - - function initFinder() { - fzfFinder = new Fzf.Finder(root.options, { - "selector": option => option, - "limit": 50, - "casing": "case-insensitive", - "sort": true, - "tiebreakers": [(a, b, selector) => selector(a.item).length - selector(b.item).length] - }); - } - - function selectNext() { - if (filteredOptions.length === 0) - return; - selectedIndex = (selectedIndex + 1) % filteredOptions.length; - listView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function selectPrevious() { - if (filteredOptions.length === 0) - return; - selectedIndex = selectedIndex <= 0 ? filteredOptions.length - 1 : selectedIndex - 1; - listView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function selectCurrent() { - if (selectedIndex < 0 || selectedIndex >= filteredOptions.length) - return; - root.currentValue = filteredOptions[selectedIndex]; - root.valueChanged(filteredOptions[selectedIndex]); - close(); - } - - onOpened: { - selectedIndex = -1; - if (searchField.text.length > 0) { - initFinder(); - searchQuery = searchField.text; - } else { - fzfFinder = null; - searchQuery = ""; - } - } - - parent: Overlay.overlay - width: root.popupWidth === -1 ? undefined : (root.popupWidth > 0 ? root.popupWidth : (dropdown.width + root.popupWidthOffset)) - height: { - let h = root.enableFuzzySearch ? 54 : 0; - if (root.options.length === 0 && root.emptyText !== "") - h += 32; - else - h += Math.min(filteredOptions.length, 10) * 36; - return Math.min(root.maxPopupHeight, h + 16); - } - padding: 0 - modal: true - dim: false - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: "transparent" - } - - contentItem: Rectangle { - id: contentSurface - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1) - border.color: Theme.primary - border.width: 2 - radius: Theme.cornerRadius - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: contentSurface.radius - targetColor: contentSurface.color - borderColor: contentSurface.border.color - borderWidth: contentSurface.border.width - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - - Rectangle { - id: searchContainer - - width: parent.width - height: 42 - visible: root.enableFuzzySearch - radius: Theme.cornerRadius - color: root.usePopupTransparency ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : Theme.surfaceContainerHigh - - DankTextField { - id: searchField - - anchors.fill: parent - anchors.margins: 1 - placeholderText: I18n.tr("Search...") - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - onTextChanged: searchDebounce.restart() - Keys.onDownPressed: dropdownMenu.selectNext() - Keys.onUpPressed: dropdownMenu.selectPrevious() - Keys.onReturnPressed: dropdownMenu.selectCurrent() - Keys.onEnterPressed: dropdownMenu.selectCurrent() - Keys.onPressed: event => { - if (!(event.modifiers & Qt.ControlModifier)) - return; - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - dropdownMenu.selectNext(); - event.accepted = true; - break; - case Qt.Key_P: - case Qt.Key_K: - dropdownMenu.selectPrevious(); - event.accepted = true; - break; - } - } - - Timer { - id: searchDebounce - interval: 50 - onTriggered: { - if (!dropdownMenu.fzfFinder) - dropdownMenu.initFinder(); - dropdownMenu.searchQuery = searchField.text; - dropdownMenu.selectedIndex = -1; - } - } - } - } - - Item { - width: 1 - height: Theme.spacingXS - visible: root.enableFuzzySearch - } - - Item { - width: parent.width - height: 32 - visible: root.options.length === 0 && root.emptyText !== "" - - StyledText { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.emptyText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - } - - DankListView { - id: listView - - width: parent.width - height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0) - (root.options.length === 0 && root.emptyText !== "" ? 32 : 0) - clip: true - visible: root.options.length > 0 - model: ScriptModel { - values: dropdownMenu.filteredOptions - } - spacing: 2 - - interactive: true - flickDeceleration: 1500 - maximumFlickVelocity: 2000 - boundsBehavior: Flickable.DragAndOvershootBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - delegate: Rectangle { - id: delegateRoot - - required property var modelData - required property int index - property bool isSelected: dropdownMenu.selectedIndex === index - property bool isCurrentValue: root.currentValue === modelData - property string iconName: root.optionIconMap[modelData] ?? "" - - width: ListView.view.width - height: 32 - radius: Theme.cornerRadius - color: isSelected ? Theme.primaryHover : optionArea.containsMouse ? Theme.primaryHoverLight : "transparent" - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: delegateRoot.iconName - size: 18 - color: delegateRoot.isCurrentValue ? Theme.primary : Theme.surfaceText - visible: name !== "" - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: delegateRoot.modelData - font.pixelSize: Theme.fontSizeMedium - color: delegateRoot.isCurrentValue ? Theme.primary : Theme.surfaceText - font.weight: delegateRoot.isCurrentValue ? Font.Medium : Font.Normal - width: root.popupWidth > 0 ? undefined : (delegateRoot.width - parent.x - Theme.spacingS * 2) - elide: root.popupWidth > 0 ? Text.ElideNone : Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - - MouseArea { - id: optionArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.currentValue = delegateRoot.modelData; - root.valueChanged(delegateRoot.modelData); - root.closeDropdownMenu(); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFilterChips.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFilterChips.qml deleted file mode 100644 index 0a00831..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFilterChips.qml +++ /dev/null @@ -1,108 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Flow { - id: root - - property var model: [] - property int currentIndex: 0 - property int chipHeight: 32 - property int chipPadding: Theme.spacingM - property bool showCheck: true - property bool showCounts: true - - signal selectionChanged(int index) - - spacing: Theme.spacingS - width: parent ? parent.width : 400 - - Repeater { - model: root.model - - Rectangle { - id: chip - required property var modelData - required property int index - - property bool selected: index === root.currentIndex - property bool hovered: mouseArea.containsMouse - property bool pressed: mouseArea.pressed - property string label: typeof modelData === "string" ? modelData : (modelData.label || "") - property int count: typeof modelData === "object" ? (modelData.count || 0) : 0 - property bool showCount: root.showCounts && count > 0 - - width: contentRow.implicitWidth + root.chipPadding * 2 - height: root.chipHeight - radius: height / 2 - - color: selected ? Theme.primary : Theme.surfaceVariant - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: { - if (pressed) - return chip.selected ? Theme.primaryPressed : Theme.surfaceTextHover; - if (hovered) - return chip.selected ? Theme.primaryHover : Theme.surfaceTextHover; - return "transparent"; - } - - Behavior on color { - ColorAnimation { - duration: Theme.shorterDuration - easing.type: Theme.standardEasing - } - } - } - - DankRipple { - id: chipRipple - cornerRadius: chip.radius - rippleColor: chip.selected ? Theme.primaryText : Theme.surfaceVariantText - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "check" - size: 16 - anchors.verticalCenter: parent.verticalCenter - color: Theme.primaryText - visible: root.showCheck && chip.selected - } - - StyledText { - text: chip.label + (chip.showCount ? " (" + chip.count + ")" : "") - font.pixelSize: Theme.fontSizeSmall - font.weight: chip.selected ? Font.Medium : Font.Normal - color: chip.selected ? Theme.primaryText : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => chipRipple.trigger(mouse.x, mouse.y) - onClicked: { - root.currentIndex = chip.index; - root.selectionChanged(chip.index); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFlickable.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFlickable.qml deleted file mode 100644 index 6c93f3c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankFlickable.qml +++ /dev/null @@ -1,179 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Widgets -import "ScrollConstants.js" as Scroll - -Flickable { - id: flickable - - property alias verticalScrollBar: vbar - property real mouseWheelSpeed: Scroll.mouseWheelSpeed - property real momentumVelocity: 0 - property bool isMomentumActive: false - property real friction: Scroll.friction - property bool _scrollBarActive: false - - flickDeceleration: Scroll.flickDeceleration - maximumFlickVelocity: Scroll.maximumFlickVelocity - boundsBehavior: Flickable.StopAtBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - WheelHandler { - id: wheelHandler - - property real touchpadSpeed: Scroll.touchpadSpeed - property real momentumRetention: Scroll.momentumRetention - property real lastWheelTime: 0 - property real momentum: 0 - property var velocitySamples: [] - property bool sessionUsedMouseWheel: false - - function startMomentum() { - flickable.isMomentumActive = true; - momentumAnim.running = true; - } - - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - - onWheel: event => { - vbar._scrollBarActive = true; - vbar.hideTimer.restart(); - - const currentTime = Date.now(); - const timeDelta = currentTime - lastWheelTime; - lastWheelTime = currentTime; - - const hasPixel = event.pixelDelta && event.pixelDelta.y !== 0; - const deltaY = event.angleDelta.y; - const isTraditionalMouse = !hasPixel && Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - const isHighDpiMouse = !hasPixel && !isTraditionalMouse && deltaY !== 0; - const isTouchpad = hasPixel; - - if (isTraditionalMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - flickable.isMomentumActive = false; - velocitySamples = []; - momentum = 0; - flickable.momentumVelocity = 0; - - const lines = Math.round(Math.abs(deltaY) / 120); - const scrollAmount = (deltaY > 0 ? -lines : lines) * flickable.mouseWheelSpeed; - let newY = flickable.contentY + scrollAmount; - newY = Math.max(0, Math.min(flickable.contentHeight - flickable.height, newY)); - - if (flickable.flicking) { - flickable.cancelFlick(); - } - - flickable.contentY = newY; - } else if (isHighDpiMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - flickable.isMomentumActive = false; - velocitySamples = []; - momentum = 0; - flickable.momentumVelocity = 0; - - let delta = deltaY / 8 * touchpadSpeed; - let newY = flickable.contentY - delta; - newY = Math.max(0, Math.min(flickable.contentHeight - flickable.height, newY)); - - if (flickable.flicking) { - flickable.cancelFlick(); - } - - flickable.contentY = newY; - } else if (isTouchpad) { - sessionUsedMouseWheel = false; - momentumAnim.running = false; - flickable.isMomentumActive = false; - - let delta = event.pixelDelta.y * touchpadSpeed; - - velocitySamples.push({ - "delta": delta, - "time": currentTime - }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); - - if (velocitySamples.length > 1) { - const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); - const timeSpan = currentTime - velocitySamples[0].time; - if (timeSpan > 0) { - flickable.momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); - } - } - - if (timeDelta < Scroll.momentumTimeThreshold) { - momentum = momentum * momentumRetention + delta * Scroll.momentumDeltaFactor; - delta += momentum; - } else { - momentum = 0; - } - - let newY = flickable.contentY - delta; - newY = Math.max(0, Math.min(flickable.contentHeight - flickable.height, newY)); - - if (flickable.flicking) { - flickable.cancelFlick(); - } - - flickable.contentY = newY; - } - - event.accepted = true; - } - - onActiveChanged: { - if (!active) { - if (!sessionUsedMouseWheel && Math.abs(flickable.momentumVelocity) >= Scroll.minMomentumVelocity) { - startMomentum(); - } else { - velocitySamples = []; - flickable.momentumVelocity = 0; - } - } - } - } - - onMovementStarted: { - vbar._scrollBarActive = true; - vbar.hideTimer.stop(); - } - onMovementEnded: vbar.hideTimer.restart() - - FrameAnimation { - id: momentumAnim - running: false - - onTriggered: { - const dt = frameTime; - const newY = flickable.contentY - flickable.momentumVelocity * dt; - const maxY = Math.max(0, flickable.contentHeight - flickable.height); - - if (newY < 0 || newY > maxY) { - flickable.contentY = newY < 0 ? 0 : maxY; - running = false; - flickable.isMomentumActive = false; - flickable.momentumVelocity = 0; - return; - } - - flickable.contentY = newY; - flickable.momentumVelocity *= Math.pow(flickable.friction, dt / 0.016); - - if (Math.abs(flickable.momentumVelocity) < Scroll.momentumStopThreshold) { - running = false; - flickable.isMomentumActive = false; - flickable.momentumVelocity = 0; - } - } - } - - ScrollBar.vertical: DankScrollbar { - id: vbar - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankGridView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankGridView.qml deleted file mode 100644 index c670d0f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankGridView.qml +++ /dev/null @@ -1,175 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Widgets -import "ScrollConstants.js" as Scroll - -GridView { - id: gridView - - property real momentumVelocity: 0 - property bool isMomentumActive: false - property real friction: Scroll.friction - - flickDeceleration: Scroll.flickDeceleration - maximumFlickVelocity: Scroll.maximumFlickVelocity - boundsBehavior: Flickable.StopAtBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - onMovementStarted: { - vbar._scrollBarActive = true; - vbar.hideTimer.stop(); - } - onMovementEnded: vbar.hideTimer.restart() - - WheelHandler { - id: wheelHandler - - property real mouseWheelSpeed: Scroll.mouseWheelSpeed - property real touchpadSpeed: Scroll.touchpadSpeed - property real momentumRetention: Scroll.momentumRetention - property real lastWheelTime: 0 - property real momentum: 0 - property var velocitySamples: [] - property bool sessionUsedMouseWheel: false - - function startMomentum() { - isMomentumActive = true; - momentumAnim.running = true; - } - - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - onWheel: event => { - vbar._scrollBarActive = true; - vbar.hideTimer.restart(); - - const currentTime = Date.now(); - const timeDelta = currentTime - lastWheelTime; - lastWheelTime = currentTime; - - const hasPixel = event.pixelDelta && event.pixelDelta.y !== 0; - const deltaY = event.angleDelta.y; - const isTraditionalMouse = !hasPixel && Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - const isHighDpiMouse = !hasPixel && !isTraditionalMouse && deltaY !== 0; - const isTouchpad = hasPixel; - - if (isTraditionalMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - isMomentumActive = false; - velocitySamples = []; - momentum = 0; - momentumVelocity = 0; - - const lines = Math.round(Math.abs(deltaY) / 120); - const scrollAmount = (deltaY > 0 ? -lines : lines) * cellHeight * 0.35; - let newY = contentY + scrollAmount; - newY = Math.max(0, Math.min(contentHeight - height, newY)); - - if (flicking) { - cancelFlick(); - } - - contentY = newY; - } else if (isHighDpiMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - isMomentumActive = false; - velocitySamples = []; - momentum = 0; - momentumVelocity = 0; - - let delta = deltaY / 120 * cellHeight * 1.2; - let newY = contentY - delta; - newY = Math.max(0, Math.min(contentHeight - height, newY)); - - if (flicking) { - cancelFlick(); - } - - contentY = newY; - } else if (isTouchpad) { - sessionUsedMouseWheel = false; - momentumAnim.running = false; - isMomentumActive = false; - - let delta = event.pixelDelta.y * touchpadSpeed; - - velocitySamples.push({ - "delta": delta, - "time": currentTime - }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); - - if (velocitySamples.length > 1) { - const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); - const timeSpan = currentTime - velocitySamples[0].time; - if (timeSpan > 0) { - momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); - } - } - - if (timeDelta < Scroll.momentumTimeThreshold) { - momentum = momentum * momentumRetention + delta * Scroll.momentumDeltaFactor; - delta += momentum; - } else { - momentum = 0; - } - - let newY = contentY - delta; - newY = Math.max(0, Math.min(contentHeight - height, newY)); - - if (flicking) { - cancelFlick(); - } - - contentY = newY; - } - - event.accepted = true; - } - onActiveChanged: { - if (!active) { - if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= Scroll.minMomentumVelocity) { - startMomentum(); - } else { - velocitySamples = []; - momentumVelocity = 0; - } - } - } - } - - FrameAnimation { - id: momentumAnim - running: false - - onTriggered: { - const dt = frameTime; - const newY = contentY - momentumVelocity * dt; - const maxY = Math.max(0, contentHeight - height); - - if (newY < 0 || newY > maxY) { - contentY = newY < 0 ? 0 : maxY; - running = false; - isMomentumActive = false; - momentumVelocity = 0; - return; - } - - contentY = newY; - momentumVelocity *= Math.pow(friction, dt / 0.016); - - if (Math.abs(momentumVelocity) < Scroll.momentumStopThreshold) { - running = false; - isMomentumActive = false; - momentumVelocity = 0; - } - } - } - - ScrollBar.vertical: DankScrollbar { - id: vbar - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIcon.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIcon.qml deleted file mode 100644 index e80b93a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIcon.qml +++ /dev/null @@ -1,77 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property alias name: icon.text - property alias size: icon.font.pixelSize - property alias color: icon.color - property bool filled: false - property real fill: filled ? 1.0 : 0.0 - property int grade: Theme.isLightMode ? 0 : -25 - property int weight: filled ? 500 : 400 - - implicitWidth: Math.round(size) - implicitHeight: Math.round(size) - - signal rotationCompleted - - FontLoader { - id: materialSymbolsFont - source: Qt.resolvedUrl("../assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf") - } - - StyledText { - id: icon - - anchors.fill: parent - - font.family: materialSymbolsFont.name - font.pixelSize: Theme.fontSizeMedium - font.weight: root.weight - color: Theme.surfaceText - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - antialiasing: true - - Behavior on color { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankColorAnim { - duration: Theme.shorterDuration - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - font.variableAxes: { - "FILL": root.fill.toFixed(1), - "GRAD": root.grade, - "opsz": 24, - "wght": root.weight - } - - Behavior on font.weight { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on fill { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Timer { - id: rotationTimer - interval: 16 - repeat: false - onTriggered: root.rotationCompleted() - } - - onRotationChanged: { - rotationTimer.restart(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIconPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIconPicker.qml deleted file mode 100644 index 3738525..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankIconPicker.qml +++ /dev/null @@ -1,259 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string currentIcon: "" - property string iconType: "icon" - - signal iconSelected(string iconName, string iconType) - - width: 240 - height: 32 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: iconPopup.visible ? Theme.primary : Theme.outline - border.width: 1 - - property var iconCategories: [ - { - "name": I18n.tr("Numbers"), - "icons": ["looks_one", "looks_two", "looks_3", "looks_4", "looks_5", "looks_6", "filter_1", "filter_2", "filter_3", "filter_4", "filter_5", "filter_6", "filter_7", "filter_8", "filter_9", "filter_9_plus", "plus_one", "exposure_plus_1", "exposure_plus_2"] - }, - { - "name": I18n.tr("Workspace"), - "icons": ["work", "laptop", "desktop_windows", "folder", "view_module", "dashboard", "apps", "grid_view"] - }, - { - "name": I18n.tr("Development"), - "icons": ["code", "terminal", "bug_report", "build", "engineering", "integration_instructions", "data_object", "schema", "api", "webhook"] - }, - { - "name": I18n.tr("Communication"), - "icons": ["chat", "mail", "forum", "message", "video_call", "call", "contacts", "group", "notifications", "campaign"] - }, - { - "name": I18n.tr("Media"), - "icons": ["music_note", "headphones", "mic", "videocam", "photo", "movie", "library_music", "album", "radio", "volume_up"] - }, - { - "name": I18n.tr("System"), - "icons": ["memory", "storage", "developer_board", "monitor", "keyboard", "mouse", "battery_std", "wifi", "bluetooth", "security", "settings"] - }, - { - "name": I18n.tr("Navigation"), - "icons": ["home", "arrow_forward", "arrow_back", "expand_more", "expand_less", "menu", "close", "search", "filter_list", "sort"] - }, - { - "name": I18n.tr("Actions"), - "icons": ["add", "remove", "edit", "delete", "save", "download", "upload", "share", "content_copy", "content_paste", "content_cut", "undo", "redo"] - }, - { - "name": I18n.tr("Status"), - "icons": ["check", "error", "warning", "info", "done", "pending", "schedule", "update", "sync", "offline_bolt"] - }, - { - "name": I18n.tr("Fun"), - "icons": ["celebration", "cake", "star", "favorite", "pets", "sports_esports", "local_fire_department", "bolt", "auto_awesome", "diamond"] - } - ] - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (iconPopup.visible) { - iconPopup.close(); - return; - } - const pos = root.mapToItem(Overlay.overlay, 0, 0); - const popupHeight = 500; - const overlayHeight = Overlay.overlay?.height ?? 800; - iconPopup.x = pos.x; - if (pos.y + root.height + popupHeight + 4 > overlayHeight) { - iconPopup.y = pos.y - popupHeight - 4; - } else { - iconPopup.y = pos.y + root.height + 4; - } - iconPopup.open(); - } - } - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: (root.iconType === "icon" && root.currentIcon) ? root.currentIcon : (root.iconType === "text" ? "text_fields" : "add") - size: 16 - color: root.currentIcon ? Theme.surfaceText : Theme.outline - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.currentIcon ? root.currentIcon : I18n.tr("Choose icon") - font.pixelSize: Theme.fontSizeSmall - color: root.currentIcon ? Theme.surfaceText : Theme.outline - anchors.verticalCenter: parent.verticalCenter - width: 160 - elide: Text.ElideRight - } - } - - DankIcon { - name: iconPopup.visible ? "expand_less" : "expand_more" - size: 16 - color: Theme.outline - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - } - - Popup { - id: iconPopup - - parent: Overlay.overlay - width: 320 - height: Math.min(500, dropdownContent.implicitHeight + 32) - padding: 0 - modal: true - dim: false - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: "transparent" - } - - contentItem: Rectangle { - id: contentSurface - color: Theme.surface - radius: Theme.cornerRadius - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: contentSurface.radius - targetColor: contentSurface.color - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: closeMouseArea.containsMouse ? Theme.errorHover : "transparent" - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - z: 1 - - DankIcon { - name: "close" - size: 16 - color: closeMouseArea.containsMouse ? Theme.error : Theme.outline - anchors.centerIn: parent - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: iconPopup.close() - } - } - - DankFlickable { - anchors.fill: parent - anchors.margins: Theme.spacingS - contentHeight: dropdownContent.height - clip: true - pressDelay: 0 - - Column { - id: dropdownContent - width: parent.width - spacing: Theme.spacingM - - Repeater { - model: root.iconCategories - - Column { - required property var modelData - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - - Flow { - width: parent.width - spacing: 4 - - Repeater { - model: modelData.icons - - Rectangle { - required property string modelData - width: 36 - height: 36 - radius: Theme.cornerRadius - color: iconMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0) - border.color: root.currentIcon === modelData ? Theme.primary : Theme.withAlpha(Theme.primary, 0) - border.width: 2 - - DankIcon { - name: parent.modelData - size: 20 - color: root.currentIcon === parent.modelData ? Theme.primary : Theme.surfaceText - anchors.centerIn: parent - } - - MouseArea { - id: iconMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.iconSelected(parent.modelData, "icon"); - iconPopup.close(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - } - } - } - - function setIcon(iconName, type) { - root.iconType = type; - root.iconType = "icon"; - root.currentIcon = iconName; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankListView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankListView.qml deleted file mode 100644 index 41bdc9b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankListView.qml +++ /dev/null @@ -1,213 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets -import "ScrollConstants.js" as Scroll - -ListView { - id: listView - - property real scrollBarTopMargin: 0 - property real mouseWheelSpeed: Scroll.mouseWheelSpeed - property real savedY: 0 - property bool justChanged: false - property bool isUserScrolling: false - property real momentumVelocity: 0 - property bool isMomentumActive: false - property real friction: Scroll.friction - - flickDeceleration: Scroll.flickDeceleration - maximumFlickVelocity: Scroll.maximumFlickVelocity - boundsBehavior: Flickable.StopAtBounds - boundsMovement: Flickable.FollowBoundsBehavior - pressDelay: 0 - flickableDirection: Flickable.VerticalFlick - - add: ListViewTransitions.add - remove: ListViewTransitions.remove - displaced: ListViewTransitions.displaced - move: ListViewTransitions.move - - onMovementStarted: { - isUserScrolling = true; - vbar._scrollBarActive = true; - vbar.hideTimer.stop(); - } - onMovementEnded: { - isUserScrolling = false; - vbar.hideTimer.restart(); - } - - onContentYChanged: { - if (!justChanged && isUserScrolling) { - savedY = contentY; - } - justChanged = false; - } - - onModelChanged: { - justChanged = true; - contentY = savedY; - } - - WheelHandler { - id: wheelHandler - property real touchpadSpeed: Scroll.touchpadSpeed - property real lastWheelTime: 0 - property real momentum: 0 - property var velocitySamples: [] - property bool sessionUsedMouseWheel: false - - function startMomentum() { - isMomentumActive = true; - momentumAnim.running = true; - } - - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - - onWheel: event => { - isUserScrolling = true; - vbar._scrollBarActive = true; - vbar.hideTimer.restart(); - - const currentTime = Date.now(); - const timeDelta = currentTime - lastWheelTime; - lastWheelTime = currentTime; - - const hasPixel = event.pixelDelta && event.pixelDelta.y !== 0; - const deltaY = event.angleDelta.y; - const isTraditionalMouse = !hasPixel && Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - const isHighDpiMouse = !hasPixel && !isTraditionalMouse && deltaY !== 0; - const isTouchpad = hasPixel; - - if (isTraditionalMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - isMomentumActive = false; - velocitySamples = []; - momentum = 0; - momentumVelocity = 0; - - const lines = Math.round(Math.abs(deltaY) / 120); - const scrollAmount = (deltaY > 0 ? -lines : lines) * mouseWheelSpeed; - let newY = listView.contentY + scrollAmount; - const maxY = Math.max(0, listView.contentHeight - listView.height + listView.originY); - newY = Math.max(listView.originY, Math.min(maxY, newY)); - - if (listView.flicking) { - listView.cancelFlick(); - } - - listView.contentY = newY; - savedY = newY; - } else if (isHighDpiMouse) { - sessionUsedMouseWheel = true; - momentumAnim.running = false; - isMomentumActive = false; - velocitySamples = []; - momentum = 0; - momentumVelocity = 0; - - let delta = deltaY / 8 * touchpadSpeed; - let newY = listView.contentY - delta; - const maxY = Math.max(0, listView.contentHeight - listView.height + listView.originY); - newY = Math.max(listView.originY, Math.min(maxY, newY)); - - if (listView.flicking) { - listView.cancelFlick(); - } - - listView.contentY = newY; - savedY = newY; - } else if (isTouchpad) { - sessionUsedMouseWheel = false; - momentumAnim.running = false; - isMomentumActive = false; - - let delta = event.pixelDelta.y * touchpadSpeed; - - velocitySamples.push({ - "delta": delta, - "time": currentTime - }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); - - if (velocitySamples.length > 1) { - const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); - const timeSpan = currentTime - velocitySamples[0].time; - if (timeSpan > 0) { - momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); - } - } - - if (timeDelta < Scroll.momentumTimeThreshold) { - momentum = momentum * Scroll.momentumRetention + delta * Scroll.momentumDeltaFactor; - delta += momentum; - } else { - momentum = 0; - } - - let newY = listView.contentY - delta; - const maxY = Math.max(0, listView.contentHeight - listView.height + listView.originY); - newY = Math.max(listView.originY, Math.min(maxY, newY)); - - if (listView.flicking) { - listView.cancelFlick(); - } - - listView.contentY = newY; - savedY = newY; - } - - event.accepted = true; - } - - onActiveChanged: { - if (!active) { - isUserScrolling = false; - if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= Scroll.minMomentumVelocity) { - startMomentum(); - } else { - velocitySamples = []; - momentumVelocity = 0; - } - } - } - } - - FrameAnimation { - id: momentumAnim - running: false - - onTriggered: { - const dt = frameTime; - const newY = contentY - momentumVelocity * dt; - const maxY = Math.max(0, contentHeight - height + originY); - const minY = originY; - - if (newY < minY || newY > maxY) { - contentY = newY < minY ? minY : maxY; - savedY = contentY; - running = false; - isMomentumActive = false; - momentumVelocity = 0; - return; - } - - contentY = newY; - savedY = newY; - momentumVelocity *= Math.pow(friction, dt / 0.016); - - if (Math.abs(momentumVelocity) < Scroll.momentumStopThreshold) { - running = false; - isMomentumActive = false; - momentumVelocity = 0; - } - } - } - - ScrollBar.vertical: DankScrollbar { - id: vbar - topPadding: listView.scrollBarTopMargin - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankLocationSearch.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankLocationSearch.qml deleted file mode 100644 index d58538a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankLocationSearch.qml +++ /dev/null @@ -1,266 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - activeFocusOnTab: true - - KeyNavigation.tab: keyNavigationTab - KeyNavigation.backtab: keyNavigationBacktab - - onActiveFocusChanged: { - if (activeFocus) { - locationInput.forceActiveFocus(); - } - } - - property string currentLocation: "" - property string placeholderText: I18n.tr("Search for a location...") - property bool _internalChange: false - property bool isLoading: false - property string currentSearchText: "" - property Item keyNavigationTab: null - property Item keyNavigationBacktab: null - - signal locationSelected(string displayName, string coordinates) - - function resetSearchState() { - locationSearchTimer.stop(); - dropdownHideTimer.stop(); - isLoading = false; - searchResultsModel.clear(); - } - - width: parent.width - height: searchInputField.height + (searchDropdown.visible ? searchDropdown.height : 0) - - ListModel { - id: searchResultsModel - } - - Timer { - id: locationSearchTimer - - interval: 500 - running: false - repeat: false - onTriggered: { - if (locationInput.text.length > 2) { - searchResultsModel.clear(); - root.isLoading = true; - const searchLocation = locationInput.text; - root.currentSearchText = searchLocation; - const encodedLocation = encodeURIComponent(searchLocation); - const searchUrl = "https://nominatim.openstreetmap.org/search?q=" + encodedLocation + "&format=json&limit=5&addressdetails=1"; - Proc.runCommand("locationSearch", ["dms", "dl", "-4", "--timeout", "10", searchUrl], (output, exitCode) => { - root.isLoading = false; - if (exitCode !== 0) { - searchResultsModel.clear(); - return; - } - if (root.currentSearchText !== locationInput.text) - return; - const raw = output.trim(); - searchResultsModel.clear(); - if (!raw || raw[0] !== "[") { - return; - } - try { - const data = JSON.parse(raw); - if (data.length === 0) { - return; - } - for (var i = 0; i < Math.min(data.length, 5); i++) { - const location = data[i]; - if (location.display_name && location.lat && location.lon) { - const parts = location.display_name.split(', '); - let cleanName = parts[0]; - if (parts.length > 1) { - const state = parts[parts.length - 2]; - if (state && state !== cleanName) - cleanName += `, ${state}`; - } - const query = `${location.lat},${location.lon}`; - searchResultsModel.append({ - "name": cleanName, - "query": query - }); - } - } - } catch (e) {} - }); - } - } - } - - Timer { - id: dropdownHideTimer - - interval: 200 - running: false - repeat: false - onTriggered: { - if (!locationInput.getActiveFocus() && !searchDropdown.hovered) - root.resetSearchState(); - } - } - - Item { - id: searchInputField - - width: parent.width - height: 48 - - DankTextField { - id: locationInput - - width: parent.width - height: parent.height - leftIconName: "search" - placeholderText: root.placeholderText - text: "" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: root.keyNavigationTab - keyNavigationBacktab: root.keyNavigationBacktab - onTextEdited: { - if (root._internalChange) - return; - if (getActiveFocus()) { - if (text.length > 2) { - root.isLoading = true; - locationSearchTimer.restart(); - } else { - root.resetSearchState(); - } - } - } - onFocusStateChanged: hasFocus => { - if (hasFocus) { - dropdownHideTimer.stop(); - } else { - dropdownHideTimer.start(); - } - } - } - - DankIcon { - name: root.isLoading ? "hourglass_empty" : (searchResultsModel.count > 0 ? "check_circle" : "error") - size: Theme.iconSize - 4 - color: root.isLoading ? Theme.surfaceVariantText : (searchResultsModel.count > 0 ? Theme.primary : Theme.error) - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - opacity: (locationInput.getActiveFocus() && locationInput.text.length > 2) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledRect { - id: searchDropdown - - property bool hovered: false - - width: parent.width - height: Math.min(Math.max(searchResultsModel.count * 38 + Theme.spacingS * 2, 50), 200) - y: searchInputField.height - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Theme.primarySelected - border.width: 1 - visible: locationInput.getActiveFocus() && locationInput.text.length > 2 && (searchResultsModel.count > 0 || root.isLoading) - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: { - parent.hovered = true; - dropdownHideTimer.stop(); - } - onExited: { - parent.hovered = false; - if (!locationInput.getActiveFocus()) - dropdownHideTimer.start(); - } - acceptedButtons: Qt.NoButton - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - DankListView { - id: searchResultsList - - anchors.fill: parent - clip: true - model: searchResultsModel - spacing: 2 - - delegate: StyledRect { - width: searchResultsList.width - height: 36 - radius: Theme.cornerRadius - color: resultMouseArea.containsMouse ? Theme.surfaceLight : "transparent" - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: "place" - size: Theme.iconSize - 6 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: model.name || "Unknown" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.width - 30 - } - } - - MouseArea { - id: resultMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root._internalChange = true; - const selectedName = model.name; - const selectedQuery = model.query; - locationInput.text = selectedName; - root.locationSelected(selectedName, selectedQuery); - root.resetSearchState(); - locationInput.setFocus(false); - root._internalChange = false; - } - } - } - } - - StyledText { - anchors.centerIn: parent - text: root.isLoading ? "Searching..." : "No locations found" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: searchResultsList.count === 0 && locationInput.text.length > 2 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNFIcon.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNFIcon.qml deleted file mode 100644 index 67d2f69..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNFIcon.qml +++ /dev/null @@ -1,164 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property string name: "" - property int size: Theme.fontSizeMedium - property alias color: icon.color - - width: size - height: size - visible: text.length > 0 - - // This is for file browser, particularly - might want another map later for app IDs - readonly property var iconMap: ({ - // --- Distribution logos --- - "debian": "\u{f08da}", - "arch": "\u{f08c7}", - "archcraft": "\u{f345}", - "guix": "\u{f325}", - "fedora": "\u{f08db}", - "nixos": "\u{f1105}", - "ubuntu": "\u{f0548}", - "gentoo": "\u{f08e8}", - "endeavouros": "\u{f322}", - "manjaro": "\u{f160a}", - "opensuse": "\u{f314}", - "artix": "\u{f31f}", - "void": "\u{f32e}", - - // --- special types --- - "folder": "\u{F024B}", - "file": "\u{F0214}", - - // --- special filenames (no extension) --- - "docker": "\u{F0868}", - "makefile": "\u{F09EE}", - "license": "\u{F09EE}", - "readme": "\u{F0354}", - - // --- programming languages --- - "rs": "\u{F1617}", - "dart": "\u{e798}", - "go": "\u{F07D3}", - "py": "\u{F0320}", - "js": "\u{F031E}", - "jsx": "\u{F031E}", - "ts": "\u{F06E6}", - "tsx": "\u{F06E6}", - "java": "\u{F0B37}", - "c": "\u{F0671}", - "cpp": "\u{F0672}", - "cxx": "\u{F0672}", - "h": "\u{F0672}", - "hpp": "\u{F0672}", - "cs": "\u{F031B}", - "html": "\u{e60e}", - "htm": "\u{e60e}", - "css": "\u{E6b8}", - "scss": "\u{F031C}", - "less": "\u{F031C}", - "md": "\u{F0354}", - "markdown": "\u{F0354}", - "json": "\u{eb0f}", - "jsonc": "\u{eb0f}", - "yaml": "\u{e8eb}", - "yml": "\u{e8eb}", - "xml": "\u{F09EE}", - "sql": "\u{f1c0}", - - // --- scripts / shells --- - "sh": "\u{f0bc1}", - "bash": "\u{f0bc1}", - "zsh": "\u{f0bc1}", - "fish": "\u{f0bc1}", - "ps1": "\u{f0bc1}", - "bat": "\u{f0bc1}", - - // --- data / config --- - "toml": "\u{e6b2}", - "ini": "\u{F09EE}", - "conf": "\u{F09EE}", - "cfg": "\u{F09EE}", - "csv": "\u{eefc}", - "tsv": "\u{F021C}", - - // --- docs / office --- - "pdf": "\u{F0226}", - "doc": "\u{F09EE}", - "docx": "\u{F09EE}", - "rtf": "\u{F09EE}", - "ppt": "\u{F09EE}", - "pptx": "\u{F09EE}", - "log": "\u{F09EE}", - "xls": "\u{F021C}", - "xlsx": "\u{F021C}", - - // --- images --- - "ico": "\u{F021F}", - - // --- audio / video --- - "mp3": "\u{e638}", - "wav": "\u{e638}", - "flac": "\u{e638}", - "ogg": "\u{e638}", - "mp4": "\u{f0567}", - "mkv": "\u{f0567}", - "webm": "\u{f0567}", - "mov": "\u{f0567}", - - // --- archives / packages --- - "zip": "\u{e6aa}", - "tar": "\u{f003c}", - "gz": "\u{f003c}", - "bz2": "\u{f003c}", - "7z": "\u{f003c}", - - // --- containers / infra / cloud --- - "dockerfile": "\u{F0868}", - "yml.k8s": "\u{F09EE}", - "yaml.k8s": "\u{F09EE}", - "tf": "\u{F09EE}", - "tfvars": "\u{F09EE}", - - // --- moon phases - "moon_new": "\u{F0F64}", - "moon_waxing_crescent": "\u{F0F67}", - "moon_first_quarter": "\u{F0F61}", - "moon_waxing_gibbous": "\u{F0F68}", - "moon_full": "\u{F0F62}", - "moon_waning_gibbous": "\u{F0F66}", - "moon_last_quarter": "\u{F0F63}", - "moon_waning_crescent": "\u{F0F65}" - }) - - readonly property string text: iconMap[name] || iconMap["file"] || "" - - function getIconForFile(fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("dockerfile")) { - return "docker"; - } - const ext = fileName.split('.').pop(); - return ext || ""; - } - - FontLoader { - id: firaCodeFont - source: Qt.resolvedUrl("../assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf") - } - - StyledText { - id: icon - - anchors.centerIn: parent - - font.family: firaCodeFont.name - font.pixelSize: root.size - color: Theme.surfaceText - text: root.text - antialiasing: true - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNumberStepper.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNumberStepper.qml deleted file mode 100644 index f4dcf5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankNumberStepper.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtCore -import QtQuick -import qs.Common - -Column { - id: root - property string text: "" - property var incrementTooltipText: "" - property var decrementTooltipText: "" - property var onIncrement: undefined - property var onDecrement: undefined - property string incrementIconName: "keyboard_arrow_up" - property string decrementIconName: "keyboard_arrow_down" - - property bool incrementEnabled: true - property bool decrementEnabled: true - - property color textColor: Theme.surfaceText - property color iconColor: Theme.withAlpha(Theme.surfaceText, 0.5) - property color backgroundColor: Theme.primary - - property int textSize: Theme.fontSizeSmall - property var iconSize: 12 - property int buttonSize: 20 - property int horizontalPadding: Theme.spacingL - - readonly property bool effectiveIncrementEnabled: root.onIncrement ? root.incrementEnabled : false - readonly property bool effectiveDecrementEnabled: root.onDecrement ? root.decrementEnabled : false - - - width: Math.max(buttonSize * 2, root.implicitWidth + horizontalPadding * 2) - spacing: 4 - - DankActionButton { - anchors.horizontalCenter: parent.horizontalCenter - enabled: root.effectiveIncrementEnabled - iconColor: root.effectiveIncrementEnabled ? root.iconColor : Theme.blendAlpha(root.iconColor, 0.5) - iconSize: root.iconSize - buttonSize: root.buttonSize - iconName: root.incrementIconName - onClicked: if (typeof root.onIncrement === 'function') root.onIncrement() - tooltipText: root.incrementTooltipText - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - Item { width: 5; height: 1 } - StyledText { - isMonospace: true - text: root.text - font.pixelSize: root.textSize - color: root.textColor - } - Item { width: 5; height: 1 } - } - - DankActionButton { - anchors.horizontalCenter: parent.horizontalCenter - enabled: root.effectiveDecrementEnabled - iconColor: root.effectiveDecrementEnabled ? root.iconColor : Theme.blendAlpha(root.iconColor, 0.5) - iconSize: root.iconSize - buttonSize: root.buttonSize - iconName: root.decrementIconName - onClicked: if (typeof root.onDecrement === 'function') root.onDecrement() - tooltipText: root.decrementTooltipText - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml deleted file mode 100644 index 0eb0e5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml +++ /dev/null @@ -1,334 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services - -PanelWindow { - id: root - - property string blurNamespace: "dms:osd" - WlrLayershell.namespace: blurNamespace - - property alias content: contentLoader.sourceComponent - property alias contentLoader: contentLoader - property var modelData - property bool shouldBeVisible: false - property int autoHideInterval: 2000 - property bool enableMouseInteraction: false - property real osdWidth: Theme.iconSize + Theme.spacingS * 2 - property real osdHeight: Theme.iconSize + Theme.spacingS * 2 - property int animationDuration: Theme.mediumDuration - property var animationEasing: Theme.emphasizedEasing - - signal osdShown - signal osdHidden - - function show() { - if (SessionData.suppressOSD) - return; - if (shouldBeVisible) { - hideTimer.restart(); - return; - } - OSDManager.showOSD(root); - closeTimer.stop(); - shouldBeVisible = true; - visible = true; - hideTimer.restart(); - osdShown(); - } - - function hide() { - shouldBeVisible = false; - closeTimer.restart(); - } - - function resetHideTimer() { - if (shouldBeVisible) { - hideTimer.restart(); - } - } - - function updateHoverState() { - let isHovered = (enableMouseInteraction && mouseArea.containsMouse) || osdContainer.childHovered; - if (enableMouseInteraction) { - if (isHovered) { - hideTimer.stop(); - } else if (shouldBeVisible) { - hideTimer.restart(); - } - } - } - - function setChildHovered(hovered) { - osdContainer.childHovered = hovered; - updateHoverState(); - } - - screen: modelData - visible: false - - Connections { - target: Quickshell - function onScreensChanged() { - if (!root.visible && !root.shouldBeVisible) - return; - const currentScreenName = root.screen?.name; - if (!currentScreenName) { - root.hide(); - return; - } - for (let i = 0; i < Quickshell.screens.length; i++) { - if (Quickshell.screens[i].name === currentScreenName) - return; - } - root.shouldBeVisible = false; - root.visible = false; - hideTimer.stop(); - closeTimer.stop(); - osdHidden(); - } - } - - WlrLayershell.layer: { - switch (Quickshell.env("DMS_OSD_LAYER")) { - case "bottom": - console.warn("DankOSD: 'bottom' layer is not valid for OSDs. Defaulting to 'overlay' layer."); - return WlrLayershell.Overlay; - case "background": - console.warn("DankOSD: 'background' layer is not valid for OSDs. Defaulting to 'overlay' layer."); - return WlrLayershell.Overlay; - case "top": - return WlrLayershell.Top; - default: - return WlrLayershell.Overlay; - } - } - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - WindowBlur { - targetWindow: root - blurX: shadowBuffer - blurY: shadowBuffer - blurWidth: shouldBeVisible ? alignedWidth : 0 - blurHeight: shouldBeVisible ? alignedHeight : 0 - blurRadius: Theme.cornerRadius - } - - color: "transparent" - - readonly property real dpr: CompositorService.getScreenScale(screen) - readonly property real screenWidth: screen.width - readonly property real screenHeight: screen.height - readonly property real shadowBuffer: 15 - readonly property real alignedWidth: Theme.px(osdWidth, dpr) - readonly property real alignedHeight: Theme.px(osdHeight, dpr) - - readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter - - readonly property real barThickness: { - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar || !(defaultBar.visible ?? true)) - return 0; - const innerPadding = defaultBar.innerPadding ?? 4; - const widgetThickness = Math.max(20, 26 + innerPadding * 0.6); - return Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding)); - } - - readonly property real barOffset: { - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar || !(defaultBar.visible ?? true)) - return 0; - const spacing = defaultBar.spacing ?? 4; - const bottomGap = defaultBar.bottomGap ?? 0; - return barThickness + spacing + bottomGap; - } - - readonly property real dockThickness: { - if (!SettingsData.showDock) - return 0; - return SettingsData.dockIconSize + SettingsData.dockSpacing * 2 + 10; - } - - readonly property real dockOffset: { - if (!SettingsData.showDock || SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide) - return 0; - return dockThickness + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin; - } - - readonly property real alignedX: { - const margin = Theme.spacingM; - const centerX = (screenWidth - alignedWidth) / 2; - - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - const barPos = defaultBar?.position ?? SettingsData.Position.Top; - - switch (SettingsData.osdPosition) { - case SettingsData.Position.Left: - case SettingsData.Position.Bottom: - const leftBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0; - const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0; - return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr); - case SettingsData.Position.Top: - case SettingsData.Position.Right: - const rightBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0; - const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0; - return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr); - case SettingsData.Position.LeftCenter: - const leftCenterBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0; - const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0; - return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr); - case SettingsData.Position.RightCenter: - const rightCenterBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0; - const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0; - return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr); - case SettingsData.Position.TopCenter: - case SettingsData.Position.BottomCenter: - default: - return Theme.snap(centerX, dpr); - } - } - - readonly property real alignedY: { - const margin = Theme.spacingM; - const centerY = (screenHeight - alignedHeight) / 2; - - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - const barPos = defaultBar?.position ?? SettingsData.Position.Top; - - switch (SettingsData.osdPosition) { - case SettingsData.Position.Top: - case SettingsData.Position.Left: - case SettingsData.Position.TopCenter: - const topBarOffset = barPos === SettingsData.Position.Top ? barOffset : 0; - const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0; - return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr); - case SettingsData.Position.Right: - case SettingsData.Position.Bottom: - case SettingsData.Position.BottomCenter: - const bottomBarOffset = barPos === SettingsData.Position.Bottom ? barOffset : 0; - const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0; - return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr); - case SettingsData.Position.LeftCenter: - case SettingsData.Position.RightCenter: - default: - return Theme.snap(centerY, dpr); - } - } - - anchors { - top: true - left: true - } - - WlrLayershell.margins { - left: Math.max(0, Theme.snap(alignedX - shadowBuffer, dpr)) - top: Math.max(0, Theme.snap(alignedY - shadowBuffer, dpr)) - } - - implicitWidth: alignedWidth + (shadowBuffer * 2) - implicitHeight: alignedHeight + (shadowBuffer * 2) - - Timer { - id: hideTimer - - interval: autoHideInterval - repeat: false - onTriggered: { - if (!enableMouseInteraction || !mouseArea.containsMouse) { - hide(); - } else { - hideTimer.restart(); - } - } - } - - Timer { - id: closeTimer - interval: animationDuration + 50 - onTriggered: { - if (!shouldBeVisible) { - visible = false; - osdHidden(); - } - } - } - - Item { - id: osdContainer - x: shadowBuffer - y: shadowBuffer - width: alignedWidth - height: alignedHeight - opacity: shouldBeVisible ? 1 : 0 - scale: shouldBeVisible ? 1 : 0.9 - - property bool childHovered: false - readonly property real popupSurfaceAlpha: Theme.popupTransparency - - Rectangle { - id: background - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, osdContainer.popupSurfaceAlpha) - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - z: -1 - } - - ElevationShadow { - id: bgShadowLayer - anchors.fill: parent - visible: osdContainer.popupSurfaceAlpha >= 0.95 - z: -1 - level: Theme.elevationLevel3 - fallbackOffset: 6 - targetRadius: Theme.cornerRadius - targetColor: Theme.withAlpha(Theme.surfaceContainer, osdContainer.popupSurfaceAlpha) - borderColor: Theme.outlineMedium - borderWidth: 1 - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: enableMouseInteraction - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - z: -1 - onContainsMouseChanged: updateHoverState() - } - - onChildHoveredChanged: updateHoverState() - - Loader { - id: contentLoader - anchors.fill: parent - active: root.visible - asynchronous: false - } - - Behavior on opacity { - NumberAnimation { - duration: animationDuration - easing.type: animationEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: animationDuration - easing.type: animationEasing - } - } - } - - mask: Region { - item: bgShadowLayer - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankPopout.qml deleted file mode 100644 index fb5f0b0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankPopout.qml +++ /dev/null @@ -1,620 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services - -Item { - id: root - - property string layerNamespace: "dms:popout" - property alias content: contentLoader.sourceComponent - property alias contentLoader: contentLoader - property Component overlayContent: null - property alias overlayLoader: overlayLoader - property real popupWidth: 400 - property real popupHeight: 300 - property real triggerX: 0 - property real triggerY: 0 - property real triggerWidth: 40 - property string triggerSection: "" - property string positioning: "center" - property int animationDuration: Theme.popoutAnimationDuration - property real animationScaleCollapsed: 0.96 - property real animationOffset: Theme.spacingL - property list animationEnterCurve: Theme.expressiveCurves.expressiveDefaultSpatial - property list animationExitCurve: Theme.expressiveCurves.emphasized - property bool suspendShadowWhileResizing: false - property bool shouldBeVisible: false - property var customKeyboardFocus: null - property bool backgroundInteractive: true - property bool contentHandlesKeys: false - property bool fullHeightSurface: false - property bool _primeContent: false - property bool _resizeActive: false - property real _surfaceMarginLeft: 0 - property real _surfaceW: 0 - - property real storedBarThickness: Theme.barHeight - 4 - property real storedBarSpacing: 4 - property var storedBarConfig: null - property var adjacentBarInfo: ({ - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }) - property var screen: null - - readonly property real effectiveBarThickness: { - const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4; - return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing; - } - - readonly property var barBounds: { - if (!screen) - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - return SettingsData.getBarBounds(screen, effectiveBarThickness, effectiveBarPosition, storedBarConfig); - } - - readonly property real barX: barBounds.x - readonly property real barY: barBounds.y - readonly property real barWidth: barBounds.width - readonly property real barHeight: barBounds.height - readonly property real barWingSize: barBounds.wingSize - - signal opened - signal popoutClosed - signal backgroundClicked - - property var _lastOpenedScreen: null - - property int effectiveBarPosition: 0 - property real effectiveBarBottomGap: 0 - readonly property string autoBarShadowDirection: { - const section = triggerSection || "center"; - switch (effectiveBarPosition) { - case SettingsData.Position.Top: - if (section === "left") - return "topLeft"; - if (section === "right") - return "topRight"; - return "top"; - case SettingsData.Position.Bottom: - if (section === "left") - return "bottomLeft"; - if (section === "right") - return "bottomRight"; - return "bottom"; - case SettingsData.Position.Left: - if (section === "left") - return "topLeft"; - if (section === "right") - return "bottomLeft"; - return "left"; - case SettingsData.Position.Right: - if (section === "left") - return "topRight"; - if (section === "right") - return "bottomRight"; - return "right"; - default: - return "top"; - } - } - readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection - - // Snapshot mask geometry to prevent background damage on bar updates - property real _frozenMaskX: 0 - property real _frozenMaskY: 0 - property real _frozenMaskWidth: 0 - property real _frozenMaskHeight: 0 - - function setBarContext(position, bottomGap) { - effectiveBarPosition = position !== undefined ? position : 0; - effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0; - } - - function primeContent() { - _primeContent = true; - } - - function clearPrimedContent() { - _primeContent = false; - } - - function setTriggerPosition(x, y, width, section, targetScreen, barPosition, barThickness, barSpacing, barConfig) { - triggerX = x; - triggerY = y; - triggerWidth = width; - triggerSection = section; - screen = targetScreen; - - storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4); - storedBarSpacing = barSpacing !== undefined ? barSpacing : 4; - storedBarConfig = barConfig; - - const pos = barPosition !== undefined ? barPosition : 0; - const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0; - - adjacentBarInfo = SettingsData.getAdjacentBarInfo(targetScreen, pos, barConfig); - setBarContext(pos, bottomGap); - } - - readonly property bool useBackgroundWindow: !CompositorService.isHyprland || CompositorService.useHyprlandFocusGrab - - function updateSurfacePosition() { - if (useBackgroundWindow && shouldBeVisible) { - _surfaceMarginLeft = alignedX - shadowBuffer; - _surfaceW = alignedWidth + shadowBuffer * 2; - } - } - - function open() { - if (!screen) - return; - closeTimer.stop(); - - // Snapshot mask geometry - _frozenMaskX = maskX; - _frozenMaskY = maskY; - _frozenMaskWidth = maskWidth; - _frozenMaskHeight = maskHeight; - - if (_lastOpenedScreen !== null && _lastOpenedScreen !== screen) { - contentWindow.visible = false; - if (useBackgroundWindow) - backgroundWindow.visible = false; - } - _lastOpenedScreen = screen; - - shouldBeVisible = true; - if (useBackgroundWindow) { - _surfaceMarginLeft = alignedX - shadowBuffer; - _surfaceW = alignedWidth + shadowBuffer * 2; - } - Qt.callLater(() => { - if (shouldBeVisible && screen) { - if (useBackgroundWindow) - backgroundWindow.visible = true; - contentWindow.visible = true; - PopoutManager.showPopout(root); - opened(); - } - }); - } - - function close() { - shouldBeVisible = false; - _primeContent = false; - PopoutManager.popoutChanged(); - closeTimer.restart(); - } - - function toggle() { - shouldBeVisible ? close() : open(); - } - - Connections { - target: Quickshell - function onScreensChanged() { - if (!shouldBeVisible || !screen) - return; - const currentScreenName = screen.name; - let screenStillExists = false; - for (let i = 0; i < Quickshell.screens.length; i++) { - if (Quickshell.screens[i].name === currentScreenName) { - screenStillExists = true; - break; - } - } - if (!screenStillExists) { - close(); - } - } - } - - Timer { - id: closeTimer - interval: animationDuration - onTriggered: { - if (!shouldBeVisible) { - contentWindow.visible = false; - if (useBackgroundWindow) - backgroundWindow.visible = false; - PopoutManager.hidePopout(root); - popoutClosed(); - } - } - } - - readonly property real screenWidth: screen ? screen.width : 0 - readonly property real screenHeight: screen ? screen.height : 0 - readonly property real dpr: screen ? screen.devicePixelRatio : 1 - - readonly property var shadowLevel: Theme.elevationLevel3 - readonly property real shadowFallbackOffset: 6 - readonly property real shadowRenderPadding: (Theme.elevationEnabled && SettingsData.popoutElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, effectiveShadowDirection, shadowFallbackOffset, 8, 16) : 0 - readonly property real shadowMotionPadding: Math.max(0, animationOffset) - readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr) - readonly property real alignedWidth: Theme.px(popupWidth, dpr) - readonly property real alignedHeight: Theme.px(popupHeight, dpr) - - onAlignedHeightChanged: { - if (!suspendShadowWhileResizing || !shouldBeVisible) - return; - _resizeActive = true; - resizeSettleTimer.restart(); - } - onShouldBeVisibleChanged: { - if (!shouldBeVisible) { - _resizeActive = false; - resizeSettleTimer.stop(); - } - } - - Timer { - id: resizeSettleTimer - interval: 80 - repeat: false - onTriggered: root._resizeActive = false - } - - readonly property real alignedX: Theme.snap((() => { - const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true; - const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4; - const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue; - - switch (effectiveBarPosition) { - case SettingsData.Position.Left: - return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX)); - case SettingsData.Position.Right: - return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX - popupWidth)); - default: - const rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2); - const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap; - const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap); - return Math.max(minX, Math.min(maxX, rawX)); - } - })(), dpr) - - readonly property real alignedY: Theme.snap((() => { - const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true; - const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4; - const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue; - - switch (effectiveBarPosition) { - case SettingsData.Position.Bottom: - return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY - popupHeight)); - case SettingsData.Position.Top: - return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY)); - default: - const rawY = triggerY - (popupHeight / 2); - const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap; - const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap); - return Math.max(minY, Math.min(maxY, rawY)); - } - })(), dpr) - - readonly property real triggeringBarLeftExclusion: (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? Math.max(0, barX + barWidth) : 0 - readonly property real triggeringBarTopExclusion: (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? Math.max(0, barY + barHeight) : 0 - readonly property real triggeringBarRightExclusion: (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? Math.max(0, screenWidth - barX) : 0 - readonly property real triggeringBarBottomExclusion: (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? Math.max(0, screenHeight - barY) : 0 - - readonly property real maskX: { - const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0; - return Math.max(triggeringBarLeftExclusion, adjacentLeftBar); - } - - readonly property real maskY: { - const adjacentTopBar = adjacentBarInfo?.topBar ?? 0; - return Math.max(triggeringBarTopExclusion, adjacentTopBar); - } - - readonly property real maskWidth: { - const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0; - const rightExclusion = Math.max(triggeringBarRightExclusion, adjacentRightBar); - return Math.max(100, screenWidth - maskX - rightExclusion); - } - - readonly property real maskHeight: { - const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0; - const bottomExclusion = Math.max(triggeringBarBottomExclusion, adjacentBottomBar); - return Math.max(100, screenHeight - maskY - bottomExclusion); - } - - PanelWindow { - id: backgroundWindow - screen: root.screen - visible: false - color: "transparent" - Component.onCompleted: { - if (typeof updatesEnabled !== "undefined" && !root.overlayContent) - updatesEnabled = false; - } - - WlrLayershell.namespace: root.layerNamespace + ":background" - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - top: true - left: true - right: true - bottom: true - } - - mask: Region { - item: maskRect - } - - Rectangle { - id: maskRect - visible: false - color: "transparent" - x: root._frozenMaskX - y: root._frozenMaskY - width: (shouldBeVisible && backgroundInteractive) ? root._frozenMaskWidth : 0 - height: (shouldBeVisible && backgroundInteractive) ? root._frozenMaskHeight : 0 - } - - MouseArea { - x: root._frozenMaskX - y: root._frozenMaskY - width: root._frozenMaskWidth - height: root._frozenMaskHeight - hoverEnabled: false - enabled: shouldBeVisible && backgroundInteractive - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: mouse => { - const clickX = mouse.x + root._frozenMaskX; - const clickY = mouse.y + root._frozenMaskY; - const outsideContent = clickX < root.alignedX || clickX > root.alignedX + root.alignedWidth || clickY < root.alignedY || clickY > root.alignedY + root.alignedHeight; - - if (!outsideContent) - return; - backgroundClicked(); - } - } - - Loader { - id: overlayLoader - anchors.fill: parent - active: root.overlayContent !== null && backgroundWindow.visible - sourceComponent: root.overlayContent - } - } - - PanelWindow { - id: contentWindow - screen: root.screen - visible: false - color: "transparent" - - WindowBlur { - id: popoutBlur - targetWindow: contentWindow - readonly property real s: Math.min(1, contentContainer.scaleValue) - blurX: contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) - blurY: contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) - blurWidth: (shouldBeVisible && contentWrapper.opacity > 0) ? contentContainer.width * s : 0 - blurHeight: (shouldBeVisible && contentWrapper.opacity > 0) ? contentContainer.height * s : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: root.layerNamespace - WlrLayershell.layer: { - switch (Quickshell.env("DMS_POPOUT_LAYER")) { - case "bottom": - console.warn("DankPopout: 'bottom' layer is not valid for popouts. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "background": - console.warn("DankPopout: 'background' layer is not valid for popouts. Defaulting to 'top' layer."); - return WlrLayershell.Top; - case "overlay": - return WlrLayershell.Overlay; - default: - return WlrLayershell.Top; - } - } - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (customKeyboardFocus !== null) - return customKeyboardFocus; - if (!shouldBeVisible) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - readonly property bool _fullHeight: useBackgroundWindow && root.fullHeightSurface - - anchors { - left: true - top: true - right: !useBackgroundWindow - bottom: _fullHeight || !useBackgroundWindow - } - - WlrLayershell.margins { - left: useBackgroundWindow ? root._surfaceMarginLeft : 0 - top: (useBackgroundWindow && !_fullHeight) ? (root.alignedY - shadowBuffer) : 0 - } - - implicitWidth: useBackgroundWindow ? root._surfaceW : 0 - implicitHeight: (useBackgroundWindow && !_fullHeight) ? (root.alignedHeight + shadowBuffer * 2) : 0 - - mask: useBackgroundWindow ? contentInputMask : null - - Region { - id: contentInputMask - item: contentMaskRect - } - - Item { - id: contentMaskRect - visible: false - x: contentContainer.x - y: contentContainer.y - width: shouldBeVisible ? root.alignedWidth : 0 - height: shouldBeVisible ? root.alignedHeight : 0 - } - - MouseArea { - anchors.fill: parent - enabled: !useBackgroundWindow && shouldBeVisible && backgroundInteractive - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - z: -1 - onClicked: mouse => { - const clickX = mouse.x; - const clickY = mouse.y; - const outsideContent = clickX < root.alignedX || clickX > root.alignedX + root.alignedWidth || clickY < root.alignedY || clickY > root.alignedY + root.alignedHeight; - if (!outsideContent) - return; - backgroundClicked(); - } - } - - Item { - id: contentContainer - x: useBackgroundWindow ? shadowBuffer : root.alignedX - y: (useBackgroundWindow && !contentWindow._fullHeight) ? shadowBuffer : root.alignedY - width: root.alignedWidth - height: root.alignedHeight - - readonly property bool barTop: effectiveBarPosition === SettingsData.Position.Top - readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom - readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left - readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right - readonly property real offsetX: barLeft ? root.animationOffset : (barRight ? -root.animationOffset : 0) - readonly property real offsetY: barBottom ? -root.animationOffset : (barTop ? root.animationOffset : 0) - - property real animX: 0 - property real animY: 0 - property real scaleValue: root.animationScaleCollapsed - - onOffsetXChanged: animX = Theme.snap(root.shouldBeVisible ? 0 : offsetX, root.dpr) - onOffsetYChanged: animY = Theme.snap(root.shouldBeVisible ? 0 : offsetY, root.dpr) - - Connections { - target: root - function onShouldBeVisibleChanged() { - contentContainer.animX = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetX, root.dpr); - contentContainer.animY = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetY, root.dpr); - contentContainer.scaleValue = root.shouldBeVisible ? 1.0 : root.animationScaleCollapsed; - } - } - - Behavior on animX { - NumberAnimation { - duration: root.animationDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Behavior on animY { - NumberAnimation { - duration: root.animationDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Behavior on scaleValue { - NumberAnimation { - duration: root.animationDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - ElevationShadow { - id: shadowSource - width: parent.width - height: parent.height - opacity: contentWrapper.opacity - scale: contentWrapper.scale - x: contentWrapper.x - y: contentWrapper.y - level: root.shadowLevel - direction: root.effectiveShadowDirection - fallbackOffset: root.shadowFallbackOffset - targetRadius: Theme.cornerRadius - targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive) - } - - Item { - id: contentWrapper - anchors.centerIn: parent - width: parent.width - height: parent.height - opacity: shouldBeVisible ? 1 : 0 - visible: opacity > 0 - scale: contentContainer.scaleValue - x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) - y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) - - layer.enabled: contentWrapper.opacity < 1 - layer.smooth: false - layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0) - - Behavior on opacity { - NumberAnimation { - duration: animationDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve - } - } - - Loader { - id: contentLoader - anchors.fill: parent - active: root._primeContent || shouldBeVisible || contentWindow.visible - asynchronous: false - } - } - - Rectangle { - width: parent.width - height: parent.height - x: contentWrapper.x - y: contentWrapper.y - opacity: contentWrapper.opacity - scale: contentWrapper.scale - visible: contentWrapper.visible - radius: Theme.cornerRadius - color: "transparent" - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.borderWidth - z: 100 - } - } - - Item { - id: focusHelper - parent: contentContainer - anchors.fill: parent - visible: !root.contentHandlesKeys - enabled: !root.contentHandlesKeys - focus: !root.contentHandlesKeys - Keys.onPressed: event => { - if (root.contentHandlesKeys) - return; - if (event.key === Qt.Key_Escape) { - close(); - event.accepted = true; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankRipple.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankRipple.qml deleted file mode 100644 index 94501d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankRipple.qml +++ /dev/null @@ -1,104 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property color rippleColor: Theme.primary - property real cornerRadius: 0 - property bool enableRipple: typeof SettingsData !== "undefined" ? (SettingsData.enableRippleEffects ?? true) : true - - property real _rippleX: 0 - property real _rippleY: 0 - property real _rippleMaxRadius: 0 - readonly property alias animating: rippleAnim.running - - anchors.fill: parent - - function trigger(x, y) { - if (!enableRipple || Theme.currentAnimationSpeed === SettingsData.AnimationSpeed.None) - return; - - _rippleX = x; - _rippleY = y; - - const dist = (ox, oy) => ox * ox + oy * oy; - _rippleMaxRadius = Math.sqrt(Math.max(dist(x, y), dist(x, height - y), dist(width - x, y), dist(width - x, height - y))); - - rippleAnim.restart(); - } - - SequentialAnimation { - id: rippleAnim - - PropertyAction { - target: rippleFx - property: "rippleCenterX" - value: root._rippleX - } - PropertyAction { - target: rippleFx - property: "rippleCenterY" - value: root._rippleY - } - PropertyAction { - target: rippleFx - property: "rippleRadius" - value: 0 - } - PropertyAction { - target: rippleFx - property: "rippleOpacity" - value: 0.10 - } - - ParallelAnimation { - DankAnim { - target: rippleFx - property: "rippleRadius" - from: 0 - to: root._rippleMaxRadius - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.bezierCurve: Theme.expressiveCurves.standardDecel - } - SequentialAnimation { - PauseAnimation { - duration: Math.round(Theme.expressiveDurations.expressiveDefaultSpatial * 0.6) - } - DankAnim { - target: rippleFx - property: "rippleOpacity" - to: 0 - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.bezierCurve: Theme.expressiveCurves.standard - } - } - } - } - - ShaderEffect { - id: rippleFx - visible: rippleAnim.running - - property real rippleCenterX: 0 - property real rippleCenterY: 0 - property real rippleRadius: 0 - property real rippleOpacity: 0 - - x: Math.max(0, rippleCenterX - rippleRadius) - y: Math.max(0, rippleCenterY - rippleRadius) - width: Math.max(0, Math.min(root.width, rippleCenterX + rippleRadius) - x) - height: Math.max(0, Math.min(root.height, rippleCenterY + rippleRadius) - y) - - property real widthPx: width - property real heightPx: height - property real cornerRadiusPx: root.cornerRadius - property real offsetX: x - property real offsetY: y - property real parentWidth: root.width - property real parentHeight: root.height - property vector4d rippleCol: Qt.vector4d(root.rippleColor.r, root.rippleColor.g, root.rippleColor.b, root.rippleColor.a) - - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/ripple.frag.qsb") - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSVGIcon.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSVGIcon.qml deleted file mode 100644 index 0cf11bc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSVGIcon.qml +++ /dev/null @@ -1,81 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Widgets -import qs.Common - -Item { - id: root - - required property string source - property int size: 24 - property string cornerIcon: "" - property int cornerIconSize: Math.max(10, size * 0.4) - property color cornerIconColor: Theme.surfaceText - property color cornerIconBackground: Theme.surface - property color colorOverride: "transparent" - property real brightnessOverride: 0.0 - property real contrastOverride: 0.0 - property real saturationOverride: 0.0 - - readonly property bool hasCornerIcon: cornerIcon !== "" - readonly property bool hasColorOverride: colorOverride.a > 0 - readonly property bool hasColorEffect: hasColorOverride || brightnessOverride !== 0.0 || contrastOverride !== 0.0 || saturationOverride !== 0.0 - readonly property string resolvedSource: { - if (!source) - return ""; - if (source.startsWith("file://")) - return source; - if (source.startsWith("/")) - return "file://" + source; - if (source.startsWith("qrc:")) - return source; - return source; - } - - implicitWidth: size - implicitHeight: size - - IconImage { - id: iconImage - anchors.fill: parent - source: root.resolvedSource - smooth: true - mipmap: true - asynchronous: true - implicitSize: root.size * 2 - backer.sourceSize.width: root.size * 2 - backer.sourceSize.height: root.size * 2 - backer.cache: true - layer.enabled: root.hasColorEffect - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: root.saturationOverride - colorization: root.hasColorOverride ? 1 : 0 - colorizationColor: root.colorOverride - brightness: root.brightnessOverride - contrast: root.contrastOverride - } - } - - Rectangle { - visible: root.hasCornerIcon - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: -2 - anchors.bottomMargin: -2 - width: root.cornerIconSize + 4 - height: root.cornerIconSize + 4 - radius: width / 2 - color: root.cornerIconBackground - border.width: 1 - border.color: Theme.surfaceLight - - DankIcon { - anchors.centerIn: parent - name: root.cornerIcon - size: root.cornerIconSize - color: root.cornerIconColor - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankScrollbar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankScrollbar.qml deleted file mode 100644 index c5d2d70..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankScrollbar.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common - -ScrollBar { - id: scrollbar - - property var targetFlickable: null - readonly property var _target: targetFlickable ?? parent - - property bool _scrollBarActive: false - property alias hideTimer: hideScrollBarTimer - property bool _isParentMoving: _target && (_target.moving || _target.flicking || _target.isMomentumActive) - property bool _shouldShow: pressed || hovered || active || _isParentMoving || _scrollBarActive - - policy: (_target && _target.contentHeight > _target.height) ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff - minimumSize: 0.08 - implicitWidth: 10 - interactive: true - hoverEnabled: true - z: 1000 - opacity: (policy !== ScrollBar.AlwaysOff && _shouldShow) ? 1.0 : 0.0 - visible: policy !== ScrollBar.AlwaysOff - - Behavior on opacity { - NumberAnimation { - duration: 160 - easing.type: Easing.OutQuad - } - } - - contentItem: Rectangle { - implicitWidth: 6 - radius: width / 2 - color: scrollbar.pressed ? Theme.primary : scrollbar._shouldShow ? Theme.outline : Theme.outlineMedium - opacity: scrollbar.pressed ? 1.0 : scrollbar._shouldShow ? 1.0 : 0.6 - } - - background: Item {} - - Timer { - id: hideScrollBarTimer - interval: 1200 - onTriggered: scrollbar._scrollBarActive = false - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSeekbar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSeekbar.qml deleted file mode 100644 index 85f13a5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSeekbar.qml +++ /dev/null @@ -1,262 +0,0 @@ -import QtQuick -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property MprisPlayer activePlayer - property real seekPreviewRatio: -1 - readonly property real playerValue: { - if (!activePlayer || activePlayer.length <= 0) - return 0; - const pos = (activePlayer.position || 0) % Math.max(1, activePlayer.length); - const calculatedRatio = pos / activePlayer.length; - return Math.max(0, Math.min(1, calculatedRatio)); - } - property real value: seekPreviewRatio >= 0 ? seekPreviewRatio : playerValue - property bool isSeeking: false - property bool isDraggingSeek: false - property real committedSeekRatio: -1 - property int previewSettleChecksRemaining: 0 - property real dragThreshold: 4 - property int holdIndicatorDelay: 180 - - function clampRatio(ratio) { - return Math.max(0, Math.min(1, ratio)); - } - - function ratioForPosition(position) { - if (!activePlayer || activePlayer.length <= 0) - return 0; - return clampRatio(position / activePlayer.length); - } - - function positionForRatio(ratio) { - if (!activePlayer || activePlayer.length <= 0) - return 0; - const rawPosition = clampRatio(ratio) * activePlayer.length; - return Math.min(rawPosition, activePlayer.length * 0.99); - } - - function updatePreviewFromMouse(mouseX, width) { - if (!activePlayer || activePlayer.length <= 0 || width <= 0) - return; - seekPreviewRatio = clampRatio(mouseX / width); - } - - function clearCommittedSeekPreview() { - previewSettleTimer.stop(); - committedSeekRatio = -1; - previewSettleChecksRemaining = 0; - if (!isSeeking) - seekPreviewRatio = -1; - } - - function beginCommittedSeekPreview(position) { - seekPreviewRatio = ratioForPosition(position); - committedSeekRatio = seekPreviewRatio; - previewSettleChecksRemaining = 15; - previewSettleTimer.restart(); - } - - function handleSeekPressed(mouse, width, mouseArea, holdTimer) { - isSeeking = true; - isDraggingSeek = false; - mouseArea.pressX = mouse.x; - clearCommittedSeekPreview(); - holdTimer.restart(); - if (activePlayer && activePlayer.length > 0 && activePlayer.canSeek) { - updatePreviewFromMouse(mouse.x, width); - mouseArea.pendingSeekPosition = positionForRatio(seekPreviewRatio); - } - } - - function handleSeekReleased(mouseArea, holdTimer) { - holdTimer.stop(); - isSeeking = false; - isDraggingSeek = false; - if (mouseArea.pendingSeekPosition >= 0 && activePlayer && activePlayer.canSeek && activePlayer.length > 0) { - const clamped = Math.min(mouseArea.pendingSeekPosition, activePlayer.length * 0.99); - activePlayer.position = clamped; - mouseArea.pendingSeekPosition = -1; - beginCommittedSeekPreview(clamped); - } else { - seekPreviewRatio = -1; - } - } - - function handleSeekPositionChanged(mouse, width, mouseArea) { - if (mouseArea.pressed && isSeeking && activePlayer && activePlayer.length > 0 && activePlayer.canSeek) { - if (!isDraggingSeek && Math.abs(mouse.x - mouseArea.pressX) >= dragThreshold) - isDraggingSeek = true; - updatePreviewFromMouse(mouse.x, width); - mouseArea.pendingSeekPosition = positionForRatio(seekPreviewRatio); - } - } - - function handleSeekCanceled(mouseArea, holdTimer) { - holdTimer.stop(); - isSeeking = false; - isDraggingSeek = false; - mouseArea.pendingSeekPosition = -1; - clearCommittedSeekPreview(); - } - - Timer { - id: previewSettleTimer - interval: 80 - repeat: true - onTriggered: { - if (root.isSeeking || root.committedSeekRatio < 0) { - stop(); - return; - } - - const previewSettled = Math.abs(root.playerValue - root.committedSeekRatio) <= 0.0015; - if (previewSettled || root.previewSettleChecksRemaining <= 0) { - root.clearCommittedSeekPreview(); - return; - } - - root.previewSettleChecksRemaining -= 1; - } - } - - implicitHeight: 20 - - Loader { - anchors.fill: parent - visible: activePlayer && activePlayer.length > 0 - sourceComponent: SettingsData.waveProgressEnabled ? waveProgressComponent : flatProgressComponent - z: 1 - - Component { - id: waveProgressComponent - - M3WaveProgress { - value: root.value - actualValue: root.playerValue - showActualPlaybackState: root.isSeeking - actualProgressColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.45) - isPlaying: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing - - MouseArea { - id: waveMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: activePlayer && activePlayer.canSeek && activePlayer.length > 0 - - property real pendingSeekPosition: -1 - property real pressX: 0 - - Timer { - id: waveHoldIndicatorTimer - interval: root.holdIndicatorDelay - repeat: false - onTriggered: { - if (parent.pressed && root.isSeeking) - root.isDraggingSeek = true; - } - } - - onPressed: mouse => root.handleSeekPressed(mouse, parent.width, waveMouseArea, waveHoldIndicatorTimer) - onReleased: root.handleSeekReleased(waveMouseArea, waveHoldIndicatorTimer) - onPositionChanged: mouse => root.handleSeekPositionChanged(mouse, parent.width, waveMouseArea) - onCanceled: root.handleSeekCanceled(waveMouseArea, waveHoldIndicatorTimer) - } - } - } - - Component { - id: flatProgressComponent - - Item { - property real lineWidth: 3 - property color trackColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.40) - property color fillColor: Theme.primary - property color playheadColor: Theme.primary - property color actualProgressColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.45) - readonly property real midY: height / 2 - - Rectangle { - width: parent.width - height: parent.lineWidth - anchors.verticalCenter: parent.verticalCenter - color: parent.trackColor - radius: height / 2 - } - - Rectangle { - width: Math.max(0, Math.min(parent.width, parent.width * root.value)) - height: parent.lineWidth - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - color: parent.fillColor - radius: height / 2 - Behavior on width { - NumberAnimation { - duration: 80 - } - } - } - - Rectangle { - visible: root.isDraggingSeek - width: 2 - height: Math.max(parent.lineWidth + 4, 10) - radius: width / 2 - color: parent.actualProgressColor - x: Math.max(0, Math.min(parent.width, parent.width * root.playerValue)) - width / 2 - y: parent.midY - height / 2 - z: 2 - } - - Rectangle { - id: playhead - width: 3 - height: Math.max(parent.lineWidth + 8, 14) - radius: width / 2 - color: parent.playheadColor - x: Math.max(0, Math.min(parent.width, parent.width * root.value)) - width / 2 - y: parent.midY - height / 2 - z: 3 - Behavior on x { - NumberAnimation { - duration: 80 - } - } - } - - MouseArea { - id: flatMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: activePlayer && activePlayer.canSeek && activePlayer.length > 0 - - property real pendingSeekPosition: -1 - property real pressX: 0 - - Timer { - id: flatHoldIndicatorTimer - interval: root.holdIndicatorDelay - repeat: false - onTriggered: { - if (parent.pressed && root.isSeeking) - root.isDraggingSeek = true; - } - } - - onPressed: mouse => root.handleSeekPressed(mouse, parent.width, flatMouseArea, flatHoldIndicatorTimer) - onReleased: root.handleSeekReleased(flatMouseArea, flatHoldIndicatorTimer) - onPositionChanged: mouse => root.handleSeekPositionChanged(mouse, parent.width, flatMouseArea) - onCanceled: root.handleSeekCanceled(flatMouseArea, flatHoldIndicatorTimer) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlideout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlideout.qml deleted file mode 100644 index d346322..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlideout.qml +++ /dev/null @@ -1,209 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -pragma ComponentBehavior: Bound - -PanelWindow { - id: root - - property string layerNamespace: "dms:slideout" - WlrLayershell.namespace: layerNamespace - - property bool isVisible: false - property var targetScreen: null - property var modelData: null - property real slideoutWidth: 480 - property bool expandable: false - property bool expandedWidth: false - property real expandedWidthValue: 960 - property Component content: null - property string title: "" - property alias container: contentContainer - property real customTransparency: -1 - signal aboutToHide - - function show() { - visible = true - isVisible = true - } - - function hide() { - aboutToHide() - isVisible = false - } - - function toggle() { - if (isVisible) { - hide() - } else { - show() - } - } - - visible: isVisible - screen: modelData - - anchors.top: true - anchors.bottom: true - anchors.right: true - - implicitWidth: expandable ? expandedWidthValue : slideoutWidth - implicitHeight: modelData ? modelData.height : 800 - - color: "transparent" - - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: 0 - WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None - - readonly property real dpr: CompositorService.getScreenScale(root.screen) - readonly property real alignedWidth: Theme.px(expandable && expandedWidth ? expandedWidthValue : slideoutWidth, dpr) - readonly property real alignedHeight: Theme.px(modelData ? modelData.height : 800, dpr) - - mask: Region { - item: Rectangle { - x: root.width - alignedWidth - y: 0 - width: alignedWidth - height: root.height - } - } - - Item { - id: slideContainer - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - width: alignedWidth - height: alignedHeight - - property real slideOffset: alignedWidth - - Connections { - target: root - function onIsVisibleChanged() { - slideContainer.slideOffset = root.isVisible ? 0 : slideContainer.width - } - } - - Behavior on slideOffset { - NumberAnimation { - id: slideAnimation - duration: 450 - easing.type: Easing.OutCubic - - onRunningChanged: { - if (!running && !isVisible) { - root.visible = false - } - } - } - } - - Behavior on width { - NumberAnimation { - duration: 250 - easing.type: Easing.OutCubic - } - } - - Item { - id: contentRect - layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - layer.smooth: false - layer.textureSize: Qt.size(width * root.dpr, height * root.dpr) - opacity: 1 - - readonly property real effectiveTransparency: customTransparency >= 0 ? customTransparency : SettingsData.popupTransparency - - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width - x: Theme.snap(slideContainer.slideOffset, root.dpr) - - Rectangle { - anchors.fill: parent - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, contentRect.effectiveTransparency) - radius: Theme.cornerRadius - } - - Column { - id: headerColumn - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - visible: root.title !== "" - - Row { - width: parent.width - height: 32 - - Column { - width: parent.width - buttonRow.width - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - Row { - id: buttonRow - spacing: Theme.spacingXS - - DankActionButton { - id: expandButton - iconName: root.expandedWidth ? "unfold_less" : "unfold_more" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - visible: root.expandable - onClicked: root.expandedWidth = !root.expandedWidth - - transform: Rotation { - angle: 90 - origin.x: expandButton.width / 2 - origin.y: expandButton.height / 2 - } - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - } - } - - Item { - id: contentContainer - anchors.top: root.title !== "" ? headerColumn.bottom : parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.topMargin: root.title !== "" ? 0 : Theme.spacingL - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - anchors.bottomMargin: Theme.spacingL - - Loader { - anchors.fill: parent - sourceComponent: root.content - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlider.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlider.qml deleted file mode 100644 index f91a75e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankSlider.qml +++ /dev/null @@ -1,294 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: slider - - property int value: 50 - property int minimum: 0 - property int maximum: 100 - property int step: 1 - property string leftIcon: "" - property string rightIcon: "" - property bool enabled: true - property string unit: "%" - property bool showValue: true - property bool isDragging: false - property bool wheelEnabled: true - property bool centerMinimum: false - property real valueOverride: -1 - property bool alwaysShowValue: false - readonly property bool containsMouse: sliderMouseArea.containsMouse - - property color thumbOutlineColor: Theme.surfaceContainer - property color trackColor: enabled ? Theme.outline : Theme.outline - - signal sliderValueChanged(int newValue) - signal sliderDragFinished(int finalValue) - - height: 48 - - function updateValueFromPosition(x) { - let ratio = Math.max(0, Math.min(1, (x - sliderHandle.width / 2) / (sliderTrack.width - sliderHandle.width))); - if (centerMinimum) - ratio = Math.max(0, (ratio - 0.5) * 2); - let rawValue = minimum + ratio * (maximum - minimum); - let newValue = step > 1 ? Math.round(rawValue / step) * step : Math.round(rawValue); - newValue = Math.max(minimum, Math.min(maximum, newValue)); - if (newValue !== value) { - value = newValue; - sliderValueChanged(newValue); - } - } - - Row { - anchors.centerIn: parent - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: slider.leftIcon - size: Theme.iconSize - color: slider.enabled ? Theme.surfaceText : Theme.onSurface_38 - anchors.verticalCenter: parent.verticalCenter - visible: slider.leftIcon.length > 0 - } - - StyledRect { - id: sliderTrack - - property int leftIconWidth: slider.leftIcon.length > 0 ? Theme.iconSize : 0 - property int rightIconWidth: slider.rightIcon.length > 0 ? Theme.iconSize : 0 - - width: parent.width - (leftIconWidth + rightIconWidth + (slider.leftIcon.length > 0 ? Theme.spacingM : 0) + (slider.rightIcon.length > 0 ? Theme.spacingM : 0)) - height: 12 - radius: Theme.cornerRadius - color: slider.trackColor - anchors.verticalCenter: parent.verticalCenter - clip: false - - StyledRect { - id: sliderFill - height: parent.height - radius: Theme.cornerRadius - width: { - const range = slider.maximum - slider.minimum; - const rawRatio = range === 0 ? 0 : (slider.value - slider.minimum) / range; - const ratio = slider.centerMinimum ? (0.5 + rawRatio * 0.5) : rawRatio; - const travel = sliderTrack.width - sliderHandle.width; - const center = (travel * ratio) + sliderHandle.width / 2; - return Math.max(0, Math.min(sliderTrack.width, center)); - } - color: slider.enabled ? Theme.primary : Theme.withAlpha(Theme.onSurface, 0.12) - } - - StyledRect { - id: sliderHandle - - property bool active: sliderMouseArea.containsMouse || sliderMouseArea.pressed || slider.isDragging - - width: 8 - height: 24 - radius: Theme.cornerRadius - x: { - const range = slider.maximum - slider.minimum; - const rawRatio = range === 0 ? 0 : (slider.value - slider.minimum) / range; - const ratio = slider.centerMinimum ? (0.5 + rawRatio * 0.5) : rawRatio; - const travel = sliderTrack.width - width; - return Math.max(0, Math.min(travel, travel * ratio)); - } - anchors.verticalCenter: parent.verticalCenter - color: slider.enabled ? Theme.primary : Theme.withAlpha(Theme.onSurface, 0.12) - border.width: 3 - border.color: slider.thumbOutlineColor - - StyledRect { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.onPrimary - opacity: slider.enabled ? (sliderMouseArea.pressed ? 0.16 : (sliderMouseArea.containsMouse ? 0.08 : 0)) : 0 - visible: opacity > 0 - } - - StyledRect { - anchors.centerIn: parent - width: parent.width + 20 - height: parent.height + 20 - radius: width / 2 - color: "transparent" - border.width: 2 - border.color: Theme.primary - opacity: slider.enabled && slider.focus ? 0.3 : 0 - visible: opacity > 0 - } - - Rectangle { - id: ripple - anchors.centerIn: parent - width: 0 - height: 0 - radius: width / 2 - color: Theme.onPrimary - opacity: 0 - - function start() { - opacity = 0.16; - width = 0; - height = 0; - rippleAnimation.start(); - } - - SequentialAnimation { - id: rippleAnimation - NumberAnimation { - target: ripple - properties: "width,height" - to: 28 - duration: 180 - } - NumberAnimation { - target: ripple - property: "opacity" - to: 0 - duration: 150 - } - } - } - - TapHandler { - acceptedButtons: Qt.LeftButton - onPressedChanged: { - if (pressed && slider.enabled) { - ripple.start(); - } - } - } - - scale: active ? 1.05 : 1.0 - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Item { - id: sliderContainer - - anchors.fill: parent - - MouseArea { - id: sliderMouseArea - - property bool isDragging: false - - anchors.fill: parent - anchors.topMargin: -10 - anchors.bottomMargin: -10 - hoverEnabled: true - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: slider.enabled - preventStealing: true - acceptedButtons: Qt.LeftButton - onWheel: wheelEvent => { - if (!slider.wheelEnabled) { - wheelEvent.accepted = false; - return; - } - let wheelStep = slider.step > 1 ? slider.step : Math.max(1, (maximum - minimum) / 100); - let newValue = wheelEvent.angleDelta.y > 0 ? Math.min(maximum, value + wheelStep) : Math.max(minimum, value - wheelStep); - if (slider.step > 1) - newValue = Math.round(newValue / slider.step) * slider.step; - newValue = Math.round(newValue); - if (newValue !== value) { - value = newValue; - sliderValueChanged(newValue); - } - wheelEvent.accepted = true; - } - onPressed: mouse => { - if (slider.enabled) { - slider.isDragging = true; - sliderMouseArea.isDragging = true; - updateValueFromPosition(mouse.x); - } - } - onReleased: { - if (slider.enabled) { - slider.isDragging = false; - sliderMouseArea.isDragging = false; - slider.sliderDragFinished(slider.value); - } - } - onPositionChanged: mouse => { - if (pressed && slider.isDragging && slider.enabled) { - updateValueFromPosition(mouse.x); - } - } - onClicked: mouse => { - if (slider.enabled && !slider.isDragging) { - updateValueFromPosition(mouse.x); - } - } - } - } - - StyledRect { - id: valueTooltip - - width: tooltipText.reservedWidth + Theme.spacingS * 2 - height: tooltipText.contentHeight + Theme.spacingXS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outline - border.width: 1 - anchors.bottom: parent.top - anchors.bottomMargin: Theme.spacingM - x: Math.max(0, Math.min(parent.width - width, sliderHandle.x + sliderHandle.width / 2 - width / 2)) - visible: slider.alwaysShowValue ? slider.showValue : ((sliderMouseArea.containsMouse && slider.showValue) || (slider.isDragging && slider.showValue)) - opacity: visible ? 1 : 0 - - NumericText { - id: tooltipText - - text: (slider.valueOverride >= 0 ? Math.round(slider.valueOverride) : slider.value) + slider.unit - reserveText: { - let widest = ""; - const samples = [slider.minimum, slider.maximum]; - if (slider.valueOverride >= 0) - samples.push(slider.valueOverride); - for (let i = 0; i < samples.length; i++) { - const candidate = Math.round(samples[i]) + slider.unit; - if (candidate.length > widest.length) - widest = candidate; - } - return widest; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.centerIn: parent - font.hintingPreference: Font.PreferFullHinting - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - DankIcon { - name: slider.rightIcon - size: Theme.iconSize - color: slider.enabled ? Theme.surfaceText : Theme.onSurface_38 - anchors.verticalCenter: parent.verticalCenter - visible: slider.rightIcon.length > 0 - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTabBar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTabBar.qml deleted file mode 100644 index d3b72f1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTabBar.qml +++ /dev/null @@ -1,263 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -FocusScope { - id: tabBar - - property alias model: tabRepeater.model - property int currentIndex: 0 - property int spacing: Theme.spacingL - property int tabHeight: 56 - property bool showIcons: true - property bool equalWidthTabs: true - property bool enableArrowNavigation: true - property Item nextFocusTarget: null - property Item previousFocusTarget: null - - signal tabClicked(int index) - signal actionTriggered(int index) - - focus: false - activeFocusOnTab: true - height: tabHeight - - KeyNavigation.tab: nextFocusTarget - KeyNavigation.down: nextFocusTarget - KeyNavigation.backtab: previousFocusTarget - KeyNavigation.up: previousFocusTarget - - Keys.onPressed: event => { - if (!tabBar.activeFocus || tabRepeater.count === 0) - return; - function findSelectableIndex(startIndex, step) { - let idx = startIndex; - for (let i = 0; i < tabRepeater.count; i++) { - idx = (idx + step + tabRepeater.count) % tabRepeater.count; - const item = tabRepeater.itemAt(idx); - if (item && !item.isAction) - return idx; - } - return -1; - } - - const goToIndex = nextIndex => { - if (nextIndex >= 0 && nextIndex !== tabBar.currentIndex) { - tabBar.currentIndex = nextIndex; - tabBar.tabClicked(nextIndex); - } - }; - - const resolveTarget = item => { - if (!item) - return null; - - if (item.focusTarget) - return resolveTarget(item.focusTarget); - - return item; - }; - - const focusItem = item => { - const target = resolveTarget(item); - if (!target) - return false; - - if (target.requestFocus) { - Qt.callLater(() => target.requestFocus()); - return true; - } - - if (target.forceActiveFocus) { - Qt.callLater(() => target.forceActiveFocus()); - return true; - } - - return false; - }; - - if (event.key === Qt.Key_Right && tabBar.enableArrowNavigation) { - const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : -1; - const nextIndex = findSelectableIndex(baseIndex, 1); - if (nextIndex >= 0) { - goToIndex(nextIndex); - event.accepted = true; - } - } else if (event.key === Qt.Key_Left && tabBar.enableArrowNavigation) { - const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : 0; - const nextIndex = findSelectableIndex(baseIndex, -1); - if (nextIndex >= 0) { - goToIndex(nextIndex); - event.accepted = true; - } - } else if (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier)) { - if (focusItem(tabBar.previousFocusTarget)) { - event.accepted = true; - } - } else if (event.key === Qt.Key_Tab || event.key === Qt.Key_Down) { - if (focusItem(tabBar.nextFocusTarget)) { - event.accepted = true; - } - } else if (event.key === Qt.Key_Up) { - if (focusItem(tabBar.previousFocusTarget)) { - event.accepted = true; - } - } - } - - Row { - id: tabRow - anchors.fill: parent - spacing: tabBar.spacing - - Repeater { - id: tabRepeater - - Item { - id: tabItem - property bool isAction: modelData && modelData.isAction === true - property bool isActive: !isAction && tabBar.currentIndex === index - property bool hasIcon: tabBar.showIcons && modelData && modelData.icon && modelData.icon.length > 0 - property bool hasText: modelData && modelData.text && modelData.text.length > 0 - - width: tabBar.equalWidthTabs ? (tabBar.width - tabBar.spacing * Math.max(0, tabRepeater.count - 1)) / Math.max(1, tabRepeater.count) : Math.max(contentCol.implicitWidth + Theme.spacingXL, 64) - height: tabBar.tabHeight - - Column { - id: contentCol - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: modelData.icon || "" - anchors.horizontalCenter: parent.horizontalCenter - size: Theme.iconSize - color: tabItem.isActive ? Theme.primary : Theme.surfaceText - visible: hasIcon - } - - StyledText { - text: modelData.text || "" - anchors.horizontalCenter: parent.horizontalCenter - font.pixelSize: Theme.fontSizeMedium - color: tabItem.isActive ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - visible: hasText - } - } - - Rectangle { - id: stateLayer - anchors.fill: parent - color: Theme.surfaceTint - opacity: tabArea.pressed ? 0.12 : (tabArea.containsMouse ? 0.08 : 0) - visible: opacity > 0 - radius: Theme.cornerRadius - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - DankRipple { - id: tabRipple - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: tabArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => tabRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (tabItem.isAction) { - tabBar.actionTriggered(index); - } else { - tabBar.tabClicked(index); - } - } - } - } - } - } - - Rectangle { - id: indicator - y: parent.height + 7 - height: 3 - width: 60 - topLeftRadius: Theme.cornerRadius - topRightRadius: Theme.cornerRadius - bottomLeftRadius: 0 - bottomRightRadius: 0 - color: Theme.primary - visible: false - - property bool animationEnabled: false - property bool initialSetupComplete: false - - Behavior on x { - enabled: indicator.animationEnabled - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on width { - enabled: indicator.animationEnabled - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - width: parent.width - height: 1 - y: parent.height + 10 - color: Theme.outlineStrong - } - - function updateIndicator() { - if (tabRepeater.count === 0 || currentIndex < 0 || currentIndex >= tabRepeater.count) { - return; - } - - const item = tabRepeater.itemAt(currentIndex); - if (!item || item.isAction) { - return; - } - - const tabPos = item.mapToItem(tabBar, 0, 0); - const tabCenterX = tabPos.x + item.width / 2; - const indicatorWidth = 60; - - if (tabPos.x < 10 && currentIndex > 0) { - Qt.callLater(updateIndicator); - return; - } - - if (!indicator.initialSetupComplete) { - indicator.animationEnabled = false; - indicator.width = indicatorWidth; - indicator.x = tabCenterX - indicatorWidth / 2; - indicator.visible = true; - indicator.initialSetupComplete = true; - indicator.animationEnabled = true; - } else { - indicator.width = indicatorWidth; - indicator.x = tabCenterX - indicatorWidth / 2; - indicator.visible = true; - } - } - - onCurrentIndexChanged: { - Qt.callLater(updateIndicator); - } - onWidthChanged: Qt.callLater(updateIndicator) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTextField.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTextField.qml deleted file mode 100644 index 456ee2c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTextField.qml +++ /dev/null @@ -1,271 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - KeyNavigation.tab: keyNavigationTab - KeyNavigation.backtab: keyNavigationBacktab - - function checkParentDisablesTransparency() { - let p = parent; - while (p) { - if (p.disablePopupTransparency === true) - return true; - p = p.parent; - } - return false; - } - - property alias text: textInput.text - property string placeholderText: "" - property alias font: textInput.font - property alias textColor: textInput.color - property alias enabled: textInput.enabled - property alias echoMode: textInput.echoMode - property alias validator: textInput.validator - property alias maximumLength: textInput.maximumLength - property string leftIconName: "" - property int leftIconSize: Theme.iconSize - property color leftIconColor: Theme.surfaceVariantText - property color leftIconFocusedColor: Theme.primary - property bool showClearButton: false - property bool showPasswordToggle: false - property bool passwordVisible: false - property bool usePopupTransparency: !checkParentDisablesTransparency() - property color backgroundColor: usePopupTransparency ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : Theme.surfaceContainerHigh - property color focusedBorderColor: Theme.primary - property color normalBorderColor: Theme.outlineMedium - property color placeholderColor: Theme.outlineButton - property int borderWidth: 1 - property int focusedBorderWidth: 2 - property real cornerRadius: Theme.cornerRadius - readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0) - readonly property real rightPadding: { - let p = Theme.spacingS; - if (showPasswordToggle) - p += 20 + Theme.spacingXS; - if (showClearButton && text.length > 0) - p += 20 + Theme.spacingXS; - return p; - } - property real topPadding: Theme.spacingS - property real bottomPadding: Theme.spacingS - property bool ignoreLeftRightKeys: false - property bool ignoreUpDownKeys: false - property bool ignoreTabKeys: false - property var keyForwardTargets: [] - property Item keyNavigationTab: null - property Item keyNavigationBacktab: null - - signal textEdited - signal editingFinished - signal accepted - signal focusStateChanged(bool hasFocus) - - function getActiveFocus() { - return textInput.activeFocus; - } - function setFocus(value) { - textInput.focus = value; - } - function forceActiveFocus() { - textInput.forceActiveFocus(); - } - function selectAll() { - textInput.selectAll(); - } - function clear() { - textInput.clear(); - } - function insertText(str) { - textInput.insert(textInput.cursorPosition, str); - } - - width: 200 - height: Math.round(Theme.fontSizeMedium * 3) - radius: cornerRadius - color: backgroundColor - border.color: textInput.activeFocus ? focusedBorderColor : normalBorderColor - border.width: textInput.activeFocus ? focusedBorderWidth : borderWidth - - DankIcon { - id: leftIcon - - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - name: leftIconName - size: leftIconSize - color: textInput.activeFocus ? leftIconFocusedColor : leftIconColor - visible: leftIconName !== "" - } - - TextInput { - id: textInput - - anchors.left: leftIcon.visible ? leftIcon.right : parent.left - anchors.leftMargin: Theme.spacingM - anchors.right: rightButtonsRow.left - anchors.rightMargin: rightButtonsRow.visible ? Theme.spacingS : Theme.spacingM - anchors.top: parent.top - anchors.topMargin: root.topPadding - anchors.bottom: parent.bottom - anchors.bottomMargin: root.bottomPadding - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - selectionColor: Theme.primaryContainer - selectedTextColor: Theme.primary - horizontalAlignment: TextInput.AlignLeft - verticalAlignment: TextInput.AlignVCenter - selectByMouse: !root.ignoreLeftRightKeys - clip: true - activeFocusOnTab: true - KeyNavigation.tab: root.keyNavigationTab - KeyNavigation.backtab: root.keyNavigationBacktab - onTextChanged: root.textEdited() - onEditingFinished: root.editingFinished() - onAccepted: root.accepted() - onActiveFocusChanged: root.focusStateChanged(activeFocus) - Keys.forwardTo: root.keyForwardTargets - Keys.onLeftPressed: event => { - if (root.ignoreLeftRightKeys) { - event.accepted = true; - } else { - // Allow normal TextInput cursor movement - event.accepted = false; - } - } - Keys.onRightPressed: event => { - if (root.ignoreLeftRightKeys) { - event.accepted = true; - } else { - event.accepted = false; - } - } - Keys.onPressed: event => { - if (root.ignoreTabKeys && (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab)) { - event.accepted = false; - for (var i = 0; i < root.keyForwardTargets.length; i++) { - if (root.keyForwardTargets[i]) - root.keyForwardTargets[i].Keys.pressed(event); - } - return; - } - if (root.ignoreUpDownKeys && (event.key === Qt.Key_Up || event.key === Qt.Key_Down)) { - event.accepted = false; - for (var i = 0; i < root.keyForwardTargets.length; i++) { - if (root.keyForwardTargets[i]) - root.keyForwardTargets[i].Keys.pressed(event); - } - return; - } - if ((event.modifiers & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier)) && root.keyForwardTargets.length > 0) { - for (var i = 0; i < root.keyForwardTargets.length; i++) { - if (root.keyForwardTargets[i]) - root.keyForwardTargets[i].Keys.pressed(event); - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton - } - } - - Row { - id: rightButtonsRow - - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - visible: showPasswordToggle || (showClearButton && text.length > 0) - - StyledRect { - id: passwordToggleButton - - width: 20 - height: 20 - radius: 10 - color: passwordToggleArea.containsMouse ? Theme.outlineStrong : "transparent" - visible: showPasswordToggle - - DankIcon { - anchors.centerIn: parent - name: passwordVisible ? "visibility_off" : "visibility" - size: 14 - color: passwordToggleArea.containsMouse ? Theme.outline : Theme.surfaceVariantText - } - - MouseArea { - id: passwordToggleArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: passwordVisible = !passwordVisible - } - } - - StyledRect { - id: clearButton - - width: 20 - height: 20 - radius: 10 - color: clearArea.containsMouse ? Theme.outlineStrong : "transparent" - visible: showClearButton && text.length > 0 - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 14 - color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText - } - - MouseArea { - id: clearArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: textInput.text = "" - } - } - } - - StyledText { - id: placeholderLabel - - anchors.fill: textInput - text: root.placeholderText - font: textInput.font - color: placeholderColor - horizontalAlignment: Text.AlignLeft - verticalAlignment: textInput.verticalAlignment - visible: textInput.text.length === 0 && !textInput.activeFocus - elide: I18n.isRtl ? Text.ElideLeft : Text.ElideRight - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankToggle.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankToggle.qml deleted file mode 100644 index 3b19a5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankToggle.qml +++ /dev/null @@ -1,195 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: toggle - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - // API - property bool checked: false - property bool enabled: true - property bool toggling: false - property string text: "" - property string description: "" - property color descriptionColor: Theme.surfaceVariantText - property bool hideText: false - - signal clicked - signal toggled(bool checked) - signal toggleCompleted(bool checked) - - readonly property bool showText: text && !hideText - - readonly property int trackWidth: 52 - readonly property int trackHeight: 30 - readonly property int insetCircle: 24 - - width: showText ? parent.width : trackWidth - height: showText ? Math.max(trackHeight, textColumn.implicitHeight + Theme.spacingM * 2) : trackHeight - - function handleClick() { - if (!enabled) - return; - clicked(); - toggled(!checked); - } - - StyledRect { - id: background - anchors.fill: parent - radius: showText ? Theme.cornerRadius : 0 - color: "transparent" - visible: showText - - StateLayer { - visible: showText - disabled: !toggle.enabled - stateColor: Theme.primary - cornerRadius: parent.radius - onClicked: toggle.handleClick() - } - } - - Row { - anchors.left: parent.left - anchors.right: toggleTrack.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - visible: showText - - Column { - id: textColumn - width: parent.width - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: toggle.text - font.pixelSize: Appearance.fontSize.normal - font.weight: Font.Medium - opacity: toggle.enabled ? 1 : 0.4 - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: toggle.description - font.pixelSize: Appearance.fontSize.small - color: toggle.descriptionColor - wrapMode: Text.WordWrap - width: parent.width - visible: toggle.description.length > 0 - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - id: toggleTrack - - width: showText ? trackWidth : Math.max(parent.width, trackWidth) - height: showText ? trackHeight : Math.max(parent.height, trackHeight) - anchors.right: parent.right - anchors.rightMargin: showText ? Theme.spacingM : 0 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - - // Distinguish disabled checked vs unchecked so unchecked disabled switches don't look enabled - color: !toggle.enabled ? (toggle.checked ? Qt.alpha(Theme.surfaceText, 0.12) : "transparent") : (toggle.checked ? Theme.primary : Theme.surfaceVariantAlpha) - opacity: toggle.toggling ? 0.6 : 1 - - // M3 disabled unchecked border: on surface 12% opacity - border.color: toggle.checked ? "transparent" : (!toggle.enabled ? Qt.alpha(Theme.surfaceText, 0.12) : Theme.outline) - - readonly property int pad: Math.round((height - thumb.width) / 2) - readonly property int edgeLeft: pad - readonly property int edgeRight: width - thumb.width - pad - - StyledRect { - id: thumb - - width: toggle.checked ? insetCircle : insetCircle - 4 - height: toggle.checked ? insetCircle : insetCircle - 4 - radius: Theme.cornerRadius - anchors.verticalCenter: parent.verticalCenter - - // M3 disabled thumb: - // checked = solid surface | unchecked = outlined off-state thumb - color: !toggle.enabled ? (toggle.checked ? Theme.surface : "transparent") : (toggle.checked ? Theme.surface : Theme.outline) - border.color: !toggle.enabled ? (toggle.checked ? "transparent" : Qt.alpha(Theme.surfaceText, 0.38)) : Theme.outline - border.width: (toggle.checked && toggle.enabled) ? 1 : 2 - - x: toggle.checked ? toggleTrack.edgeRight : toggleTrack.edgeLeft - - Behavior on x { - SequentialAnimation { - NumberAnimation { - duration: Appearance.anim.durations.normal - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.emphasizedDecel - } - ScriptAction { - script: { - toggle.toggleCompleted(toggle.checked); - } - } - } - } - - Behavior on color { - ColorAnimation { - duration: Appearance.anim.durations.normal - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - Behavior on border.width { - NumberAnimation { - duration: Appearance.anim.durations.normal - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - DankIcon { - id: checkIcon - anchors.centerIn: parent - name: "check" - size: 20 - // M3 disabled icon: on surface 38% - color: toggle.enabled ? Theme.surfaceText : Qt.alpha(Theme.surfaceText, 0.38) - filled: true - opacity: (toggle.checked && toggle.enabled) ? 1 : 0 - scale: (toggle.checked && toggle.enabled) ? 1 : 0.6 - - Behavior on opacity { - NumberAnimation { - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasized - } - } - Behavior on scale { - NumberAnimation { - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasized - } - } - } - } - - StateLayer { - disabled: !toggle.enabled - stateColor: Theme.primary - cornerRadius: parent.radius - onClicked: toggle.handleClick() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltip.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltip.qml deleted file mode 100644 index 0e57de9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltip.qml +++ /dev/null @@ -1,92 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -PanelWindow { - id: root - - WlrLayershell.namespace: "dms:tooltip" - - property string text: "" - property real targetX: 0 - property real targetY: 0 - property var targetScreen: null - property bool alignLeft: false - property bool alignRight: false - - function show(text, x, y, screen, leftAlign, rightAlign) { - root.text = text; - if (screen) { - targetScreen = screen; - const screenX = screen.x || 0; - targetX = x - screenX; - } else { - targetScreen = null; - targetX = x; - } - targetY = y; - alignLeft = leftAlign ?? false; - alignRight = rightAlign ?? false; - visible = true; - } - - function hide() { - visible = false; - } - - screen: targetScreen - implicitWidth: Math.min(300, Math.max(120, textContent.implicitWidth + Theme.spacingM * 2)) - implicitHeight: textContent.implicitHeight + Theme.spacingS * 2 - color: "transparent" - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - - anchors { - top: true - left: true - } - - margins { - left: { - const screenWidth = targetScreen?.width ?? Screen.width - if (alignLeft) { - return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX))) - } else if (alignRight) { - return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth))) - } else { - return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2))) - } - } - top: { - const screenHeight = targetScreen?.height ?? Screen.height - if (alignLeft || alignRight) { - return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2))) - } else { - return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY))) - } - } - } - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - - Text { - id: textContent - - anchors.centerIn: parent - text: root.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.NoWrap - maximumLineCount: 1 - elide: Text.ElideRight - width: Math.min(implicitWidth, 300 - Theme.spacingM * 2) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltipV2.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltipV2.qml deleted file mode 100644 index 6cd53c8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankTooltipV2.qml +++ /dev/null @@ -1,154 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common - -Item { - id: root - - property string text: "" - - function show(text, item, offsetX, offsetY, preferredSide) { - if (!item) - return; - - let windowContentItem = item.Window?.window?.contentItem; - if (!windowContentItem) { - let current = item; - while (current) { - if (current.Window?.window?.contentItem) { - windowContentItem = current.Window.window.contentItem; - break; - } - current = current.parent; - } - } - if (!windowContentItem) - return; - - tooltip.parent = windowContentItem; - tooltip.text = text; - - const itemPos = item.mapToItem(windowContentItem, 0, 0); - const parentWidth = windowContentItem.width; - const parentHeight = windowContentItem.height; - const tooltipWidth = tooltip.implicitWidth; - const tooltipHeight = tooltip.implicitHeight; - - const side = preferredSide || _determineBestSide(itemPos, item, parentWidth, parentHeight, tooltipWidth, tooltipHeight); - - let targetX = 0; - let targetY = 0; - - switch (side) { - case "left": - targetX = itemPos.x - tooltipWidth - 8; - targetY = itemPos.y + (item.height - tooltipHeight) / 2; - break; - case "right": - targetX = itemPos.x + item.width + 8; - targetY = itemPos.y + (item.height - tooltipHeight) / 2; - break; - case "top": - targetX = itemPos.x + (item.width - tooltipWidth) / 2; - targetY = itemPos.y - tooltipHeight - 8; - break; - case "bottom": - default: - targetX = itemPos.x + (item.width - tooltipWidth) / 2; - targetY = itemPos.y + item.height + 8; - break; - } - - tooltip.x = Math.max(4, Math.min(parentWidth - tooltipWidth - 4, targetX + (offsetX || 0))); - tooltip.y = Math.max(4, Math.min(parentHeight - tooltipHeight - 4, targetY + (offsetY || 0))); - - tooltip.open(); - } - - function _determineBestSide(itemPos, item, parentWidth, parentHeight, tooltipWidth, tooltipHeight) { - const itemCenterX = itemPos.x + item.width / 2; - const itemCenterY = itemPos.y + item.height / 2; - - const spaceLeft = itemPos.x; - const spaceRight = parentWidth - (itemPos.x + item.width); - const spaceTop = itemPos.y; - const spaceBottom = parentHeight - (itemPos.y + item.height); - - if (spaceRight >= tooltipWidth + 16) { - return "right"; - } - if (spaceLeft >= tooltipWidth + 16) { - return "left"; - } - if (spaceBottom >= tooltipHeight + 16) { - return "bottom"; - } - if (spaceTop >= tooltipHeight + 16) { - return "top"; - } - - if (itemCenterX > parentWidth / 2) { - return "left"; - } - return "right"; - } - - function hide() { - tooltip.close(); - } - - Popup { - id: tooltip - - property string text: "" - - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - closePolicy: Popup.NoAutoClose - modal: false - dim: false - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - } - - contentItem: Text { - id: textContent - - width: Math.min(implicitWidth, 500) - text: tooltip.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.NoWrap - maximumLineCount: 1 - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - enter: Transition { - NumberAnimation { - property: "opacity" - from: 0 - to: 1 - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - exit: Transition { - NumberAnimation { - property: "opacity" - from: 1 - to: 0 - duration: Theme.shorterDuration - easing.type: Theme.standardEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/FloatingWindowControls.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/FloatingWindowControls.qml deleted file mode 100644 index b56291e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/FloatingWindowControls.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick - -Item { - id: root - - readonly property real edgeSize: 8 - required property var targetWindow - property bool supported: typeof targetWindow.startSystemMove === "function" - readonly property bool canMaximize: targetWindow.minimumSize.width !== targetWindow.maximumSize.width || targetWindow.minimumSize.height !== targetWindow.maximumSize.height - - anchors.fill: parent - - function tryStartMove() { - if (!supported) - return; - targetWindow.startSystemMove(); - } - - function tryStartResize(edges) { - if (!supported || !canMaximize) - return; - targetWindow.startSystemResize(edges); - } - - function tryToggleMaximize() { - if (!supported || !canMaximize) - return; - targetWindow.maximized = !targetWindow.maximized; - } - - MouseArea { - visible: root.supported && root.canMaximize - height: root.edgeSize - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: 6 - anchors.rightMargin: 6 - cursorShape: Qt.SizeVerCursor - onPressed: root.tryStartResize(Qt.TopEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.topMargin: 6 - anchors.bottomMargin: 6 - cursorShape: Qt.SizeHorCursor - onPressed: root.tryStartResize(Qt.LeftEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.topMargin: 6 - anchors.bottomMargin: 6 - cursorShape: Qt.SizeHorCursor - onPressed: root.tryStartResize(Qt.RightEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - height: root.edgeSize - anchors.left: parent.left - anchors.top: parent.top - cursorShape: Qt.SizeFDiagCursor - onPressed: root.tryStartResize(Qt.LeftEdge | Qt.TopEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - height: root.edgeSize - anchors.right: parent.right - anchors.top: parent.top - cursorShape: Qt.SizeBDiagCursor - onPressed: root.tryStartResize(Qt.RightEdge | Qt.TopEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - height: root.edgeSize - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.leftMargin: 6 - anchors.rightMargin: 6 - cursorShape: Qt.SizeVerCursor - onPressed: root.tryStartResize(Qt.BottomEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - height: root.edgeSize - anchors.left: parent.left - anchors.bottom: parent.bottom - cursorShape: Qt.SizeBDiagCursor - onPressed: root.tryStartResize(Qt.LeftEdge | Qt.BottomEdge) - } - - MouseArea { - visible: root.supported && root.canMaximize - width: root.edgeSize - height: root.edgeSize - anchors.right: parent.right - anchors.bottom: parent.bottom - cursorShape: Qt.SizeFDiagCursor - onPressed: root.tryStartResize(Qt.RightEdge | Qt.BottomEdge) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/KeybindItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/KeybindItem.qml deleted file mode 100644 index a68cc4a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/KeybindItem.qml +++ /dev/null @@ -1,1840 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets -import "../Common/KeyUtils.js" as KeyUtils -import "../Common/KeybindActions.js" as Actions - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var bindData: ({}) - property bool isExpanded: false - property var panelWindow: null - property bool recording: false - property bool isNew: false - property string restoreKey: "" - - property int editingKeyIndex: -1 - property string editKey: "" - property string editAction: "" - property string editDesc: "" - property int editCooldownMs: 0 - property string editFlags: "" - property bool editAllowWhenLocked: false - property var editRepeat: undefined - property var editAllowInhibiting: undefined - property int _savedCooldownMs: -1 - property string _savedFlags: "" - property var _savedAllowWhenLocked: undefined - property var _savedRepeat: undefined - property var _savedAllowInhibiting: undefined - property bool hasChanges: false - property string _actionType: "" - property bool addingNewKey: false - property bool useCustomCompositor: false - property var _shortcutInhibitor: null - property bool _altShiftGhost: false - - readonly property bool _shortcutInhibitorAvailable: { - try { - return typeof ShortcutInhibitor !== "undefined"; - } catch (e) { - return false; - } - } - - readonly property var keys: bindData.keys || [] - readonly property bool hasOverride: { - for (var i = 0; i < keys.length; i++) { - if (keys[i].isOverride) - return true; - } - return false; - } - readonly property var configConflict: bindData.conflict || null - readonly property bool hasConfigConflict: configConflict !== null - readonly property string _originalKey: editingKeyIndex >= 0 && editingKeyIndex < keys.length ? keys[editingKeyIndex].key : "" - readonly property var _conflicts: editKey ? KeyUtils.getConflictingBinds(editKey, bindData.action, KeybindsService.getFlatBinds()) : [] - readonly property bool hasConflict: _conflicts.length > 0 - - readonly property real _inputHeight: Math.round(Theme.fontSizeMedium * 3) - readonly property real _chipHeight: Math.round(Theme.fontSizeSmall * 2.3) - readonly property real _buttonHeight: Math.round(Theme.fontSizeMedium * 2.3) - readonly property real _keysColumnWidth: Math.round(Theme.fontSizeSmall * 12) - readonly property real _labelWidth: Math.round(Theme.fontSizeSmall * 5) - - signal toggleExpand - signal saveBind(string originalKey, var newData) - signal removeBind(string key) - signal cancelEdit - - implicitHeight: contentColumn.implicitHeight - height: implicitHeight - - Component.onDestruction: _destroyShortcutInhibitor() - - Component.onCompleted: { - if (isNew && isExpanded) - resetEdits(); - } - - onIsExpandedChanged: { - if (!isExpanded) - return; - if (restoreKey) { - restoreToKey(restoreKey); - } else { - resetEdits(); - } - } - - onRestoreKeyChanged: { - if (!isExpanded || !restoreKey) - return; - restoreToKey(restoreKey); - } - - function restoreToKey(keyToFind) { - for (var i = 0; i < keys.length; i++) { - if (keys[i].key === keyToFind) { - editingKeyIndex = i; - editKey = keyToFind; - editAction = bindData.action || ""; - editDesc = bindData.desc || ""; - if (_savedCooldownMs >= 0) { - editCooldownMs = _savedCooldownMs; - _savedCooldownMs = -1; - } else { - editCooldownMs = keys[i].cooldownMs || 0; - } - if (_savedFlags) { - editFlags = _savedFlags; - _savedFlags = ""; - } else { - editFlags = keys[i].flags || ""; - } - if (_savedAllowWhenLocked !== undefined) { - editAllowWhenLocked = _savedAllowWhenLocked; - _savedAllowWhenLocked = undefined; - } else { - editAllowWhenLocked = keys[i].allowWhenLocked || false; - } - if (_savedRepeat !== undefined) { - editRepeat = _savedRepeat; - _savedRepeat = undefined; - } else { - editRepeat = keys[i].repeat; - } - if (_savedAllowInhibiting !== undefined) { - editAllowInhibiting = _savedAllowInhibiting; - _savedAllowInhibiting = undefined; - } else { - editAllowInhibiting = keys[i].allowInhibiting; - } - hasChanges = false; - _actionType = Actions.getActionType(editAction); - useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(KeybindsService.currentProvider, editAction); - return; - } - } - resetEdits(); - } - - onEditActionChanged: { - _actionType = Actions.getActionType(editAction); - } - - function resetEdits() { - addingNewKey = false; - editingKeyIndex = keys.length > 0 ? 0 : -1; - editKey = editingKeyIndex >= 0 ? keys[editingKeyIndex].key : ""; - editAction = bindData.action || ""; - editDesc = bindData.desc || ""; - editCooldownMs = editingKeyIndex >= 0 ? (keys[editingKeyIndex].cooldownMs || 0) : 0; - editFlags = editingKeyIndex >= 0 ? (keys[editingKeyIndex].flags || "") : ""; - editAllowWhenLocked = editingKeyIndex >= 0 ? (keys[editingKeyIndex].allowWhenLocked || false) : false; - editRepeat = editingKeyIndex >= 0 ? keys[editingKeyIndex].repeat : undefined; - editAllowInhibiting = editingKeyIndex >= 0 ? keys[editingKeyIndex].allowInhibiting : undefined; - hasChanges = false; - _actionType = Actions.getActionType(editAction); - useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(KeybindsService.currentProvider, editAction); - } - - function startAddingNewKey() { - addingNewKey = true; - editingKeyIndex = -1; - editKey = ""; - hasChanges = true; - } - - function selectKeyForEdit(index) { - if (index < 0 || index >= keys.length) - return; - addingNewKey = false; - editingKeyIndex = index; - editKey = keys[index].key; - editCooldownMs = keys[index].cooldownMs || 0; - editFlags = keys[index].flags || ""; - editAllowWhenLocked = keys[index].allowWhenLocked || false; - editRepeat = keys[index].repeat; - editAllowInhibiting = keys[index].allowInhibiting; - hasChanges = false; - } - - function updateEdit(changes) { - if (changes.key !== undefined) - editKey = changes.key; - if (changes.action !== undefined) - editAction = changes.action; - if (changes.desc !== undefined) - editDesc = changes.desc; - if (changes.cooldownMs !== undefined) - editCooldownMs = changes.cooldownMs; - if (changes.flags !== undefined) - editFlags = changes.flags; - if (changes.allowWhenLocked !== undefined) - editAllowWhenLocked = changes.allowWhenLocked; - if (changes.repeat !== undefined) - editRepeat = changes.repeat; - if (changes.allowInhibiting !== undefined) - editAllowInhibiting = changes.allowInhibiting; - const hasKey = editingKeyIndex >= 0 && editingKeyIndex < keys.length; - const origKey = hasKey ? keys[editingKeyIndex].key : ""; - const origCooldown = hasKey ? (keys[editingKeyIndex].cooldownMs || 0) : 0; - const origFlags = hasKey ? (keys[editingKeyIndex].flags || "") : ""; - const origAllowWhenLocked = hasKey ? (keys[editingKeyIndex].allowWhenLocked || false) : false; - const origRepeat = hasKey ? keys[editingKeyIndex].repeat : undefined; - const origAllowInhibiting = hasKey ? keys[editingKeyIndex].allowInhibiting : undefined; - hasChanges = editKey !== origKey || editAction !== (bindData.action || "") || editDesc !== (bindData.desc || "") || editCooldownMs !== origCooldown || editFlags !== origFlags || editAllowWhenLocked !== origAllowWhenLocked || editRepeat !== origRepeat || editAllowInhibiting !== origAllowInhibiting; - } - - function canSave() { - if (!editKey) - return false; - if (!Actions.isValidAction(editAction)) - return false; - return true; - } - - function doSave() { - if (!canSave()) - return; - const origKey = addingNewKey ? "" : _originalKey; - let desc = editDesc; - if (expandedLoader.item?.currentTitle !== undefined) - desc = expandedLoader.item.currentTitle; - _savedCooldownMs = editCooldownMs; - _savedFlags = editFlags; - _savedAllowWhenLocked = editAllowWhenLocked; - _savedRepeat = editRepeat; - _savedAllowInhibiting = editAllowInhibiting; - saveBind(origKey, { - "key": editKey, - "action": editAction, - "desc": desc, - "cooldownMs": editCooldownMs, - "flags": editFlags, - "allowWhenLocked": editAllowWhenLocked, - "repeat": editRepeat, - "allowInhibiting": editAllowInhibiting - }); - hasChanges = false; - addingNewKey = false; - } - - function _createShortcutInhibitor() { - if (!_shortcutInhibitorAvailable || _shortcutInhibitor) - return; - const qmlString = ` - import QtQuick - import Quickshell.Wayland - - ShortcutInhibitor { - enabled: false - window: null - } - `; - - _shortcutInhibitor = Qt.createQmlObject(qmlString, root, "KeybindItem.ShortcutInhibitor"); - _shortcutInhibitor.enabled = Qt.binding(() => root.recording); - _shortcutInhibitor.window = Qt.binding(() => root.panelWindow); - } - - function _destroyShortcutInhibitor() { - if (_shortcutInhibitor) { - _shortcutInhibitor.enabled = false; - _shortcutInhibitor.destroy(); - _shortcutInhibitor = null; - } - } - - function startRecording() { - _destroyShortcutInhibitor(); - _createShortcutInhibitor(); - recording = true; - } - - function stopRecording() { - recording = false; - _destroyShortcutInhibitor(); - } - - Column { - id: contentColumn - width: parent.width - spacing: 0 - - Rectangle { - id: collapsedRect - width: parent.width - height: Math.max(root._inputHeight + Theme.spacingM, keysColumn.implicitHeight + Theme.spacingM * 2) - radius: root.isExpanded ? 0 : Theme.cornerRadius - topLeftRadius: Theme.cornerRadius - topRightRadius: Theme.cornerRadius - color: root.hasOverride ? Theme.surfaceContainer : Theme.surfaceContainerHighest - border.color: root.hasOverride ? Theme.outlineVariant : "transparent" - border.width: root.hasOverride ? 1 : 0 - - RowLayout { - id: collapsedContent - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - Column { - id: keysColumn - Layout.preferredWidth: root._keysColumnWidth - Layout.alignment: Qt.AlignVCenter - spacing: Theme.spacingXS - - Repeater { - model: root.keys - - delegate: Rectangle { - required property var modelData - required property int index - - property bool isSelected: root.isExpanded && root.editingKeyIndex === index && !root.addingNewKey - - width: root._keysColumnWidth - height: root._chipHeight - radius: root._chipHeight / 4 - color: isSelected ? Theme.primary : Theme.surfaceVariant - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: chipArea.pressed ? Theme.surfaceTextHover : (chipArea.containsMouse ? Theme.surfaceTextHover : "transparent") - } - - StyledText { - text: modelData.key - font.pixelSize: Theme.fontSizeSmall - font.weight: parent.isSelected ? Font.Medium : Font.Normal - isMonospace: true - color: parent.isSelected ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - width: parent.width - Theme.spacingS - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - } - - MouseArea { - id: chipArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.selectKeyForEdit(index); - if (!root.isExpanded) - root.toggleExpand(); - } - } - } - } - } - - ColumnLayout { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - spacing: 2 - - StyledText { - text: root.bindData.desc || root.bindData.action || I18n.tr("No action") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - } - - RowLayout { - spacing: Theme.spacingS - Layout.fillWidth: true - - StyledText { - text: root.bindData.category || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - - Rectangle { - width: 4 - height: 4 - radius: 2 - color: Theme.surfaceVariantText - visible: root.hasOverride && (root.bindData.category ?? "") - } - - StyledText { - text: I18n.tr("Override") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: root.hasOverride && !root.hasConfigConflict - } - - DankIcon { - name: "warning" - size: Theme.iconSizeSmall - color: Theme.primary - visible: root.hasConfigConflict - } - - StyledText { - text: I18n.tr("Overridden by config") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: root.hasConfigConflict - } - - Item { - Layout.fillWidth: true - } - } - } - - DankIcon { - name: root.isExpanded ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - Layout.alignment: Qt.AlignVCenter - } - } - - MouseArea { - anchors.fill: parent - anchors.leftMargin: root._keysColumnWidth + Theme.spacingM * 2 - cursorShape: Qt.PointingHandCursor - onClicked: root.toggleExpand() - } - } - - Loader { - id: expandedLoader - width: parent.width - active: root.isExpanded - visible: status === Loader.Ready - asynchronous: true - sourceComponent: expandedComponent - } - } - - Component { - id: expandedComponent - - Rectangle { - id: expandedRect - width: parent ? parent.width : 0 - height: expandedContent.implicitHeight + Theme.spacingL * 2 - color: Theme.surfaceContainerHigh - border.color: root.hasOverride ? Theme.outlineVariant : "transparent" - border.width: root.hasOverride ? 1 : 0 - bottomLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - - property alias currentTitle: titleField.text - - ColumnLayout { - id: expandedContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: conflictColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, 0.15) - border.color: Theme.withAlpha(Theme.primary, 0.3) - border.width: 1 - visible: root.hasConfigConflict - - Column { - id: conflictColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - RowLayout { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "warning" - size: Theme.iconSizeSmall - color: Theme.primary - } - - StyledText { - text: I18n.tr("This bind is overridden by config.kdl") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - } - } - - StyledText { - text: I18n.tr("Config action: %1").arg(root.configConflict?.action ?? "") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - } - - StyledText { - text: I18n.tr("To use this DMS bind, remove or change the keybind in your config.kdl") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root.keys.length > 1 || root.addingNewKey - - StyledText { - text: I18n.tr("Keys") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - Flow { - Layout.fillWidth: true - spacing: Theme.spacingXS - - Repeater { - model: root.keys - - delegate: Rectangle { - required property var modelData - required property int index - - property bool isSelected: root.editingKeyIndex === index && !root.addingNewKey - - width: editKeyChipText.implicitWidth + Theme.spacingM - height: root._chipHeight - radius: root._chipHeight / 4 - color: isSelected ? Theme.primary : Theme.surfaceVariant - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: editKeyChipArea.pressed ? Theme.surfaceTextHover : (editKeyChipArea.containsMouse && !parent.isSelected ? Theme.surfaceTextHover : "transparent") - } - - StyledText { - id: editKeyChipText - text: modelData.key - font.pixelSize: Theme.fontSizeSmall - font.weight: parent.isSelected ? Font.Medium : Font.Normal - isMonospace: true - color: parent.isSelected ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - id: editKeyChipArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.selectKeyForEdit(index) - } - } - } - - Rectangle { - width: root._chipHeight - height: root._chipHeight - radius: root._chipHeight / 4 - color: root.addingNewKey ? Theme.primary : Theme.surfaceVariant - visible: !root.isNew - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: addKeyArea.pressed ? Theme.surfaceTextHover : (addKeyArea.containsMouse && !root.addingNewKey ? Theme.surfaceTextHover : "transparent") - } - - DankIcon { - name: "add" - size: Theme.iconSizeSmall - color: root.addingNewKey ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - id: addKeyArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.startAddingNewKey() - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - - StyledText { - text: root.addingNewKey ? I18n.tr("New Key") : I18n.tr("Key") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - FocusScope { - id: captureScope - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - focus: root.recording - - Component.onCompleted: { - if (root.recording) - forceActiveFocus(); - } - - Connections { - target: root - function onRecordingChanged() { - if (root.recording) - captureScope.forceActiveFocus(); - } - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: root.recording ? Theme.primaryContainer : Theme.surfaceContainer - border.color: root.recording ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: root.recording ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - StyledText { - text: root.editKey || (root.recording ? I18n.tr("Press key...") : I18n.tr("Click to capture")) - font.pixelSize: Theme.fontSizeMedium - isMonospace: root.editKey ? true : false - color: root.editKey ? Theme.surfaceText : Theme.surfaceVariantText - width: parent.width - recordBtn.width - parent.spacing - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - } - - DankActionButton { - id: recordBtn - width: root._chipHeight - height: root._chipHeight - anchors.verticalCenter: parent.verticalCenter - circular: false - iconName: root.recording ? "close" : "radio_button_checked" - iconSize: Theme.iconSizeSmall - iconColor: root.recording ? Theme.error : Theme.primary - onClicked: root.recording ? root.stopRecording() : root.startRecording() - } - } - } - - Keys.onPressed: event => { - if (!root.recording) - return; - event.accepted = true; - - switch (event.key) { - case Qt.Key_Control: - case Qt.Key_Shift: - case Qt.Key_Alt: - case Qt.Key_Meta: - return; - } - - if (event.key === 0 && (event.modifiers & Qt.AltModifier)) { - root._altShiftGhost = true; - return; - } - - let mods = KeyUtils.modsFromEvent(event.modifiers); - let qtKey = event.key; - - if (root._altShiftGhost && (event.modifiers & Qt.AltModifier) && !mods.includes("Shift")) { - mods.push("Shift"); - } - root._altShiftGhost = false; - - if (qtKey === Qt.Key_Backtab) { - qtKey = Qt.Key_Tab; - if (!mods.includes("Shift")) - mods.push("Shift"); - } - - const key = KeyUtils.xkbKeyFromQtKey(qtKey); - if (!key) { - console.warn("[KeybindItem] Unknown key:", event.key, "mods:", event.modifiers); - return; - } - - root.updateEdit({ - "key": KeyUtils.formatToken(mods, key) - }); - root.stopRecording(); - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: root.recording ? Qt.CrossCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - - onClicked: { - if (!root.recording) - root.startRecording(); - } - - onWheel: wheel => { - if (!root.recording) { - wheel.accepted = false; - return; - } - wheel.accepted = true; - - const mods = []; - if (wheel.modifiers & Qt.ControlModifier) - mods.push("Ctrl"); - if (wheel.modifiers & Qt.ShiftModifier) - mods.push("Shift"); - if (wheel.modifiers & Qt.AltModifier) - mods.push("Alt"); - if (wheel.modifiers & Qt.MetaModifier) - mods.push("Super"); - - let wheelKey = ""; - if (wheel.angleDelta.y > 0) - wheelKey = "WheelScrollUp"; - else if (wheel.angleDelta.y < 0) - wheelKey = "WheelScrollDown"; - else if (wheel.angleDelta.x > 0) - wheelKey = "WheelScrollRight"; - else if (wheel.angleDelta.x < 0) - wheelKey = "WheelScrollLeft"; - - if (!wheelKey) - return; - root.updateEdit({ - "key": KeyUtils.formatToken(mods, wheelKey) - }); - root.stopRecording(); - } - } - } - - Rectangle { - Layout.preferredWidth: root._inputHeight - Layout.preferredHeight: root._inputHeight - radius: Theme.cornerRadius - color: root.addingNewKey ? Theme.primary : Theme.surfaceVariant - visible: root.keys.length === 1 && !root.isNew - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: singleAddKeyArea.pressed ? Theme.surfaceTextHover : (singleAddKeyArea.containsMouse && !root.addingNewKey ? Theme.surfaceTextHover : "transparent") - } - - DankIcon { - name: "add" - size: Theme.iconSizeSmall + 2 - color: root.addingNewKey ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - id: singleAddKeyArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.startAddingNewKey() - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - visible: root.hasConflict - Layout.leftMargin: root._labelWidth + Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSizeSmall - color: Theme.primary - } - - StyledText { - text: I18n.tr("Conflicts with: %1").arg(root._conflicts.map(c => c.desc).join(", ")) - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - Layout.fillWidth: true - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Type") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - - Repeater { - model: KeybindsService.actionTypes - - delegate: Rectangle { - id: typeDelegate - required property var modelData - required property int index - - readonly property var tooltipTexts: ({ - "dms": I18n.tr("DMS shell actions (launcher, clipboard, etc.)"), - "compositor": I18n.tr("Niri compositor actions (focus, move, etc.)"), - "spawn": I18n.tr("Run a program (e.g., firefox, kitty)"), - "shell": I18n.tr("Run a shell command (e.g., notify-send)") - }) - - Layout.fillWidth: true - Layout.preferredHeight: root._buttonHeight - radius: Theme.cornerRadius - color: root._actionType === modelData.id ? Theme.surfaceContainerHighest : Theme.surfaceContainer - border.color: root._actionType === modelData.id ? Theme.outline : (typeArea.containsMouse ? Theme.outlineVariant : "transparent") - border.width: 1 - - RowLayout { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: typeDelegate.modelData.icon - size: Theme.iconSizeSmall - color: root._actionType === typeDelegate.modelData.id ? Theme.surfaceText : Theme.surfaceVariantText - } - - StyledText { - text: typeDelegate.modelData.label - font.pixelSize: Theme.fontSizeSmall - color: root._actionType === typeDelegate.modelData.id ? Theme.surfaceText : Theme.surfaceVariantText - visible: typeDelegate.width > 100 - } - } - - MouseArea { - id: typeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - switch (typeDelegate.modelData.id) { - case "dms": - root.updateEdit({ - "action": KeybindsService.dmsActions[0].id, - "desc": KeybindsService.dmsActions[0].label - }); - break; - case "compositor": - root.updateEdit({ - "action": "close-window", - "desc": "Close Window" - }); - break; - case "spawn": - root.updateEdit({ - "action": "spawn ", - "desc": "" - }); - break; - case "shell": - root.updateEdit({ - "action": "spawn sh -c \"\"", - "desc": "" - }); - break; - } - } - onContainsMouseChanged: { - if (containsMouse) { - typeTooltip.show(typeDelegate.tooltipTexts[typeDelegate.modelData.id], typeDelegate, 0, 0, "bottom"); - } else { - typeTooltip.hide(); - } - } - } - } - } - } - - DankTooltipV2 { - id: typeTooltip - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "dms" - - StyledText { - text: I18n.tr("Action") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankDropdown { - Layout.fillWidth: true - compactMode: true - currentValue: KeybindsService.getActionLabel(root.editAction) || I18n.tr("Select...") - options: KeybindsService.getDmsActions().map(a => a.label) - enableFuzzySearch: true - maxPopupHeight: 300 - onValueChanged: value => { - const actions = KeybindsService.getDmsActions(); - for (const act of actions) { - if (act.label === value) { - root.updateEdit({ - "action": act.id, - "desc": act.label - }); - return; - } - } - } - } - } - - RowLayout { - id: dmsArgsRow - Layout.fillWidth: true - spacing: Theme.spacingM - - readonly property var argConfig: Actions.getActionArgConfig(KeybindsService.currentProvider, root.editAction) - readonly property var parsedArgs: argConfig?.type === "dms" ? Actions.parseDmsActionArgs(root.editAction) : null - readonly property var dmsActionArgs: Actions.getDmsActionArgs() - readonly property bool hasAmountArg: parsedArgs?.base ? (dmsActionArgs[parsedArgs.base]?.args?.some(a => a.name === "amount") ?? false) : false - readonly property bool hasDeviceArg: parsedArgs?.base ? (dmsActionArgs[parsedArgs.base]?.args?.some(a => a.name === "device") ?? false) : false - readonly property bool hasTabArg: parsedArgs?.base ? (dmsActionArgs[parsedArgs.base]?.args?.some(a => a.name === "tab") ?? false) : false - - visible: root._actionType === "dms" && argConfig?.type === "dms" - - StyledText { - text: I18n.tr("Amount") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - visible: dmsArgsRow.hasAmountArg - } - - DankTextField { - id: dmsAmountField - Layout.preferredWidth: Math.round(Theme.fontSizeMedium * 5.5) - Layout.preferredHeight: root._inputHeight - placeholderText: "5" - visible: dmsArgsRow.hasAmountArg - - Connections { - target: dmsArgsRow - function onParsedArgsChanged() { - const newText = dmsArgsRow.parsedArgs?.args?.amount || ""; - if (dmsAmountField.text !== newText) - dmsAmountField.text = newText; - } - } - - Component.onCompleted: { - text = dmsArgsRow.parsedArgs?.args?.amount || ""; - } - - onEditingFinished: { - if (!dmsArgsRow.parsedArgs) - return; - const newArgs = Object.assign({}, dmsArgsRow.parsedArgs.args); - newArgs.amount = text || "5"; - root.updateEdit({ - "action": Actions.buildDmsAction(dmsArgsRow.parsedArgs.base, newArgs) - }); - } - } - - StyledText { - text: "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: dmsArgsRow.hasAmountArg - } - - StyledText { - text: I18n.tr("Device") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.leftMargin: dmsArgsRow.hasAmountArg ? Theme.spacingM : 0 - Layout.preferredWidth: dmsArgsRow.hasAmountArg ? -1 : root._labelWidth - visible: dmsArgsRow.hasDeviceArg - } - - DankTextField { - id: dmsDeviceField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - placeholderText: I18n.tr("leave empty for default") - visible: dmsArgsRow.hasDeviceArg - - Connections { - target: dmsArgsRow - function onParsedArgsChanged() { - const newText = dmsArgsRow.parsedArgs?.args?.device || ""; - if (dmsDeviceField.text !== newText) - dmsDeviceField.text = newText; - } - } - - Component.onCompleted: { - text = dmsArgsRow.parsedArgs?.args?.device || ""; - } - - onEditingFinished: { - if (!dmsArgsRow.parsedArgs) - return; - const newArgs = Object.assign({}, dmsArgsRow.parsedArgs.args); - newArgs.device = text; - root.updateEdit({ - "action": Actions.buildDmsAction(dmsArgsRow.parsedArgs.base, newArgs) - }); - } - } - - Item { - Layout.fillWidth: true - visible: !dmsArgsRow.hasDeviceArg && !dmsArgsRow.hasTabArg - } - - StyledText { - text: I18n.tr("Tab") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - visible: dmsArgsRow.hasTabArg - } - - DankDropdown { - id: dmsTabDropdown - Layout.fillWidth: true - compactMode: true - visible: dmsArgsRow.hasTabArg - currentValue: { - const tab = dmsArgsRow.parsedArgs?.args?.tab || ""; - switch (tab) { - case "media": - return I18n.tr("Media"); - case "wallpaper": - return I18n.tr("Wallpaper"); - case "weather": - return I18n.tr("Weather"); - default: - return I18n.tr("Overview"); - } - } - options: [I18n.tr("Overview"), I18n.tr("Media"), I18n.tr("Wallpaper"), I18n.tr("Weather")] - onValueChanged: value => { - if (!dmsArgsRow.parsedArgs) - return; - const newArgs = Object.assign({}, dmsArgsRow.parsedArgs.args); - switch (value) { - case I18n.tr("Media"): - newArgs.tab = "media"; - break; - case I18n.tr("Wallpaper"): - newArgs.tab = "wallpaper"; - break; - case I18n.tr("Weather"): - newArgs.tab = "weather"; - break; - default: - newArgs.tab = ""; - break; - } - root.updateEdit({ - "action": Actions.buildDmsAction(dmsArgsRow.parsedArgs.base, newArgs) - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "compositor" && !root.useCustomCompositor - - StyledText { - text: I18n.tr("Action") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankDropdown { - id: compositorCatDropdown - Layout.preferredWidth: Math.round(Theme.fontSizeMedium * 8.5) - compactMode: true - currentValue: { - const base = root.editAction.split(" ")[0]; - const cats = KeybindsService.getCompositorCategories(); - for (const cat of cats) { - const actions = KeybindsService.getCompositorActions(cat); - for (const act of actions) { - if (act.id === base) - return cat; - } - } - return cats[0] || "Window"; - } - options: KeybindsService.getCompositorCategories() - } - - DankDropdown { - Layout.fillWidth: true - compactMode: true - currentValue: KeybindsService.getActionLabel(root.editAction) || I18n.tr("Select...") - options: KeybindsService.getCompositorActions(compositorCatDropdown.currentValue).map(a => a.label) - enableFuzzySearch: true - maxPopupHeight: 300 - onValueChanged: value => { - const actions = KeybindsService.getCompositorActions(compositorCatDropdown.currentValue); - for (const act of actions) { - if (act.label === value) { - root.updateEdit({ - "action": act.id, - "desc": act.label - }); - return; - } - } - } - } - - Rectangle { - Layout.preferredWidth: root._inputHeight - Layout.preferredHeight: root._inputHeight - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: customToggleArea.pressed ? Theme.surfaceTextHover : (customToggleArea.containsMouse ? Theme.surfaceTextHover : "transparent") - } - - DankIcon { - name: "edit" - size: Theme.iconSizeSmall + 2 - color: Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - id: customToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.useCustomCompositor = true - } - } - } - - RowLayout { - id: optionsRow - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "compositor" && !root.useCustomCompositor && Actions.getActionArgConfig(KeybindsService.currentProvider, root.editAction) - - readonly property var argConfig: Actions.getActionArgConfig(KeybindsService.currentProvider, root.editAction) - readonly property var parsedArgs: Actions.parseCompositorActionArgs(KeybindsService.currentProvider, root.editAction) - - StyledText { - text: I18n.tr("Options") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - - DankTextField { - id: argValueField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - - readonly property string _argName: optionsRow.argConfig?.config?.args[0]?.name || "value" - - visible: { - const cfg = optionsRow.argConfig; - if (!cfg?.config?.args) - return false; - const firstArg = cfg.config.args[0]; - return firstArg && (firstArg.type === "text" || firstArg.type === "number"); - } - placeholderText: optionsRow.argConfig?.config?.args[0]?.placeholder || "" - - Connections { - target: optionsRow - function onParsedArgsChanged() { - const argName = argValueField._argName; - const newText = optionsRow.parsedArgs?.args[argName] || ""; - if (argValueField.text !== newText) - argValueField.text = newText; - } - } - - Component.onCompleted: { - text = optionsRow.parsedArgs?.args[_argName] || ""; - } - - onEditingFinished: { - const cfg = optionsRow.argConfig; - if (!cfg) - return; - const parsed = optionsRow.parsedArgs; - const args = Object.assign({}, parsed?.args || {}); - args[_argName] = text; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, parsed?.base || cfg.base, args) - }); - } - } - - RowLayout { - visible: { - const cfg = optionsRow.argConfig; - if (!cfg) - return false; - switch (cfg.base) { - case "move-column-to-workspace": - case "move-column-to-workspace-down": - case "move-column-to-workspace-up": - return true; - } - return false; - } - spacing: Theme.spacingXS - - DankToggle { - id: focusToggle - checked: optionsRow.parsedArgs?.args?.focus !== false - onToggled: newChecked => { - const cfg = optionsRow.argConfig; - if (!cfg) - return; - const parsed = optionsRow.parsedArgs; - const args = {}; - if (cfg.base === "move-column-to-workspace") - args.index = parsed?.args?.index || ""; - if (!newChecked) - args.focus = false; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, cfg.base, args) - }); - } - } - - StyledText { - text: I18n.tr("Follow focus") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - visible: optionsRow.argConfig?.base?.startsWith("screenshot") ?? false - spacing: Theme.spacingM - - RowLayout { - visible: optionsRow.argConfig?.base !== "screenshot-window" - spacing: Theme.spacingXS - - DankToggle { - id: showPointerToggle - checked: optionsRow.parsedArgs?.args["show-pointer"] === true - onToggled: newChecked => { - const parsed = optionsRow.parsedArgs; - const base = parsed?.base || "screenshot"; - const args = Object.assign({}, parsed?.args || {}); - args["show-pointer"] = newChecked; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, base, args) - }); - } - } - - StyledText { - text: I18n.tr("Pointer") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - visible: optionsRow.argConfig?.base !== "screenshot" - spacing: Theme.spacingXS - - DankToggle { - id: writeToDiskToggle - checked: optionsRow.parsedArgs?.args["write-to-disk"] === true - onToggled: newChecked => { - const parsed = optionsRow.parsedArgs; - const base = parsed?.base || "screenshot-screen"; - const args = Object.assign({}, parsed?.args || {}); - args["write-to-disk"] = newChecked; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, base, args) - }); - } - } - - StyledText { - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - RowLayout { - visible: optionsRow.argConfig?.base === "quit" - spacing: Theme.spacingXS - - DankToggle { - checked: optionsRow.parsedArgs?.args["skip-confirmation"] === true - onToggled: newChecked => { - const args = newChecked ? { - "skip-confirmation": true - } : {}; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, "quit", args) - }); - } - } - - StyledText { - text: I18n.tr("Skip confirmation") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "compositor" && root.useCustomCompositor - - StyledText { - text: I18n.tr("Custom") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankTextField { - id: customCompositorField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - placeholderText: I18n.tr("e.g., focus-workspace 3, resize-column -10") - text: root._actionType === "compositor" ? root.editAction : "" - onTextChanged: { - if (root._actionType !== "compositor") - return; - root.updateEdit({ - "action": text - }); - } - } - - Rectangle { - Layout.preferredWidth: root._inputHeight - Layout.preferredHeight: root._inputHeight - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: presetToggleArea.pressed ? Theme.surfaceTextHover : (presetToggleArea.containsMouse ? Theme.surfaceTextHover : "transparent") - } - - DankIcon { - name: "list" - size: Theme.iconSizeSmall + 2 - color: Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - id: presetToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.useCustomCompositor = false; - root.updateEdit({ - "action": "close-window", - "desc": "Close Window" - }); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "spawn" - - StyledText { - text: I18n.tr("Command") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankTextField { - id: spawnTextField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - placeholderText: I18n.tr("e.g., firefox, kitty --title foo") - readonly property var _parsed: root._actionType === "spawn" ? Actions.parseSpawnCommand(root.editAction) : null - text: _parsed ? (_parsed.command + " " + _parsed.args.join(" ")).trim() : "" - onTextChanged: { - if (root._actionType !== "spawn") - return; - const parts = text.trim().split(" ").filter(p => p); - const action = parts.length > 0 ? "spawn " + parts.join(" ") : "spawn "; - root.updateEdit({ - "action": action - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: root._actionType === "shell" - - StyledText { - text: I18n.tr("Shell") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankTextField { - id: shellTextField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - placeholderText: I18n.tr("e.g., notify-send 'Hello' && sleep 1") - text: root._actionType === "shell" ? Actions.parseShellCommand(root.editAction) : "" - onTextChanged: { - if (root._actionType !== "shell") - return; - var shell = Actions.getShellFromAction(root.editAction); - root.updateEdit({ - "action": Actions.buildShellAction(KeybindsService.currentProvider, text, shell) - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Title") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankTextField { - id: titleField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight - placeholderText: I18n.tr("Hotkey overlay title (optional)") - text: root.editDesc - onTextChanged: root.updateEdit({ - "desc": text - }) - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: KeybindsService.currentProvider === "hyprland" - - StyledText { - text: I18n.tr("Flags") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - Flow { - Layout.fillWidth: true - spacing: Theme.spacingM - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editFlags.indexOf("e") !== -1 - onToggled: newChecked => { - let flags = root.editFlags.split("").filter(f => f !== "e"); - if (newChecked) - flags.push("e"); - root.updateEdit({ - "flags": flags.join("") - }); - } - } - - StyledText { - text: I18n.tr("Repeat") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editFlags.indexOf("l") !== -1 - onToggled: newChecked => { - let flags = root.editFlags.split("").filter(f => f !== "l"); - if (newChecked) - flags.push("l"); - root.updateEdit({ - "flags": flags.join("") - }); - } - } - - StyledText { - text: I18n.tr("Locked") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editFlags.indexOf("r") !== -1 - onToggled: newChecked => { - let flags = root.editFlags.split("").filter(f => f !== "r"); - if (newChecked) - flags.push("r"); - root.updateEdit({ - "flags": flags.join("") - }); - } - } - - StyledText { - text: I18n.tr("Release") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editFlags.indexOf("o") !== -1 - onToggled: newChecked => { - let flags = root.editFlags.split("").filter(f => f !== "o"); - if (newChecked) - flags.push("o"); - root.updateEdit({ - "flags": flags.join("") - }); - } - } - - StyledText { - text: I18n.tr("Long press") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: KeybindsService.currentProvider === "niri" - - StyledText { - text: I18n.tr("Cooldown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - DankTextField { - id: cooldownField - Layout.preferredWidth: Math.round(Theme.fontSizeMedium * 7) - Layout.preferredHeight: root._inputHeight - placeholderText: "0" - - Connections { - target: root - function onEditCooldownMsChanged() { - const newText = root.editCooldownMs > 0 ? String(root.editCooldownMs) : ""; - if (cooldownField.text !== newText) - cooldownField.text = newText; - } - } - - Component.onCompleted: { - text = root.editCooldownMs > 0 ? String(root.editCooldownMs) : ""; - } - - onTextChanged: { - const val = parseInt(text) || 0; - if (val !== root.editCooldownMs) - root.updateEdit({ - "cooldownMs": val - }); - } - } - - StyledText { - text: I18n.tr("ms") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - Item { - Layout.fillWidth: true - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - visible: KeybindsService.currentProvider === "niri" - - StyledText { - text: I18n.tr("Options") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - Layout.preferredWidth: root._labelWidth - } - - Flow { - Layout.fillWidth: true - spacing: Theme.spacingM - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editRepeat !== false - onToggled: newChecked => { - root.updateEdit({ - "repeat": newChecked ? undefined : false - }); - } - } - - StyledText { - text: I18n.tr("Repeat") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editAllowWhenLocked - onToggled: newChecked => { - root.updateEdit({ - "allowWhenLocked": newChecked - }); - } - } - - StyledText { - text: I18n.tr("When locked") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - RowLayout { - spacing: Theme.spacingXS - - DankToggle { - checked: root.editAllowInhibiting !== false - onToggled: newChecked => { - root.updateEdit({ - "allowInhibiting": newChecked ? undefined : false - }); - } - } - - StyledText { - text: I18n.tr("Inhibitable") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingM - - DankActionButton { - Layout.preferredWidth: root._buttonHeight - Layout.preferredHeight: root._buttonHeight - circular: false - iconName: "delete" - iconSize: Theme.iconSize - 4 - iconColor: Theme.error - visible: root.editingKeyIndex >= 0 && root.editingKeyIndex < root.keys.length && root.keys[root.editingKeyIndex].isOverride && !root.isNew - onClicked: root.removeBind(root._originalKey) - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: !root.canSave() ? I18n.tr("Set key and action to save") : (root.hasChanges ? I18n.tr("Unsaved changes") : I18n.tr("No changes")) - font.pixelSize: Theme.fontSizeSmall - color: root.hasChanges ? Theme.surfaceText : Theme.surfaceVariantText - visible: !root.isNew - } - - DankButton { - text: I18n.tr("Cancel") - buttonHeight: root._buttonHeight - backgroundColor: Theme.surfaceContainer - textColor: Theme.surfaceText - visible: root.hasChanges || root.isNew - onClicked: { - if (root.isNew) { - root.cancelEdit(); - } else { - root.resetEdits(); - root.toggleExpand(); - } - } - } - - DankButton { - text: root.isNew ? I18n.tr("Add") : I18n.tr("Save") - buttonHeight: root._buttonHeight - enabled: root.canSave() - visible: root.hasChanges || root.isNew - onClicked: root.doSave() - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/M3WaveProgress.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/M3WaveProgress.qml deleted file mode 100644 index 051e092..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/M3WaveProgress.qml +++ /dev/null @@ -1,274 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import qs.Common - -Item { - id: root - - property real value: 0 - property real actualValue: value - property bool showActualPlaybackState: false - property real lineWidth: 2 - property real wavelength: 20 - property real amp: 1.6 - property real phase: 0.0 - property bool isPlaying: false - property real currentAmp: 1.6 - property color trackColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.40) - property color fillColor: Theme.primary - property color playheadColor: Theme.primary - property color actualProgressColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.45) - - property real dpr: (root.window ? root.window.devicePixelRatio : 1) - function snap(v) { - return Math.round(v * dpr) / dpr; - } - - readonly property real playX: snap(root.width * root.value) - readonly property real actualX: snap(root.width * root.actualValue) - readonly property real midY: snap(height / 2) - readonly property bool previewAhead: root.showActualPlaybackState && root.value > root.actualValue - readonly property bool previewBehind: root.showActualPlaybackState && root.value < root.actualValue - readonly property real previewGapStartX: Math.min(root.playX, root.actualX) - readonly property real previewGapEndX: Math.max(root.playX, root.actualX) - - Behavior on currentAmp { - NumberAnimation { - duration: 300 - easing.type: Easing.OutCubic - } - } - onIsPlayingChanged: currentAmp = isPlaying ? amp : 0 - - Shape { - id: flatTrack - anchors.fill: parent - antialiasing: true - preferredRendererType: Shape.CurveRenderer - layer.enabled: true - - ShapePath { - strokeColor: root.trackColor - strokeWidth: snap(root.lineWidth) - capStyle: ShapePath.RoundCap - joinStyle: ShapePath.RoundJoin - fillColor: "transparent" - PathMove { - id: flatStart - x: Math.min(root.width, snap(root.playX + playhead.width / 2)) - y: root.midY - } - PathLine { - id: flatEnd - x: root.width - y: root.midY - } - } - } - - Item { - id: waveClip - anchors.fill: parent - clip: true - - readonly property real startX: snap(root.lineWidth / 2) - readonly property real aaBias: (0.25 / root.dpr) - readonly property real endX: root.previewAhead ? Math.max(startX, Math.min(root.actualX - aaBias, width)) : Math.max(startX, Math.min(root.playX - startX - aaBias, width)) - readonly property real gapStartX: root.previewAhead ? Math.max(startX, Math.min(root.actualX + aaBias, width)) : Math.max(startX, Math.min(root.playX + playhead.width / 2, width)) - readonly property real gapEndX: root.previewAhead ? Math.max(gapStartX, Math.min(root.playX - playhead.width / 2 - aaBias, width)) : Math.max(gapStartX, Math.min(root.actualX - aaBias, width)) - - Rectangle { - id: mask - anchors.top: parent.top - anchors.bottom: parent.bottom - x: 0 - width: waveClip.endX - color: "transparent" - clip: true - - Shape { - id: waveShape - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width + 4 * root.wavelength - antialiasing: true - preferredRendererType: Shape.CurveRenderer - x: waveOffsetX - - ShapePath { - id: wavePath - strokeColor: root.fillColor - strokeWidth: snap(root.lineWidth) - capStyle: ShapePath.RoundCap - joinStyle: ShapePath.RoundJoin - fillColor: "transparent" - PathSvg { - id: waveSvg - path: "" - } - } - } - } - - Rectangle { - id: actualMask - anchors.top: parent.top - anchors.bottom: parent.bottom - x: waveClip.gapStartX - width: Math.max(0, waveClip.gapEndX - waveClip.gapStartX) - color: "transparent" - clip: true - visible: (root.previewBehind || root.previewAhead) && width > 0 - - Shape { - anchors.top: parent.top - anchors.bottom: parent.bottom - width: root.width + 4 * root.wavelength - antialiasing: true - preferredRendererType: Shape.CurveRenderer - x: waveOffsetX - - ShapePath { - strokeColor: root.actualProgressColor - strokeWidth: snap(root.lineWidth) - capStyle: ShapePath.RoundCap - joinStyle: ShapePath.RoundJoin - fillColor: "transparent" - PathSvg { - path: waveSvg.path - } - } - } - } - - Rectangle { - id: startCap - width: snap(root.lineWidth) - height: snap(root.lineWidth) - radius: width / 2 - color: root.fillColor - x: waveClip.startX - width / 2 - y: waveY(waveClip.startX) - height / 2 - visible: waveClip.endX > waveClip.startX - z: 2 - } - - Rectangle { - id: endCap - width: snap(root.lineWidth) - height: snap(root.lineWidth) - radius: width / 2 - color: root.fillColor - x: waveClip.endX - width / 2 - y: waveY(waveClip.endX) - height / 2 - visible: waveClip.endX > waveClip.startX - z: 2 - } - - Rectangle { - id: actualEndCap - width: snap(root.lineWidth) - height: snap(root.lineWidth) - radius: width / 2 - color: root.actualProgressColor - x: waveClip.gapEndX - width / 2 - y: waveY(waveClip.gapEndX) - height / 2 - visible: (root.previewBehind || root.previewAhead) && actualMask.width > 0 - z: 2 - } - - Rectangle { - id: actualMarker - width: 2 - height: Math.max(root.lineWidth + 4, 10) - radius: width / 2 - color: root.actualProgressColor - x: root.actualX - width / 2 - y: root.midY - height / 2 - visible: root.showActualPlaybackState - z: 2 - } - } - - Rectangle { - id: playhead - width: 3.5 - height: Math.max(root.lineWidth + 12, 16) - radius: width / 2 - color: root.playheadColor - x: root.playX - width / 2 - y: root.midY - height / 2 - z: 3 - } - - property real k: (2 * Math.PI) / Math.max(1e-6, wavelength) - function wrapMod(a, m) { - let r = a % m; - return r < 0 ? r + m : r; - } - function waveY(x, amplitude = root.currentAmp, phaseOffset = root.phase) { - return root.midY + amplitude * Math.sin((x / root.wavelength) * 2 * Math.PI + phaseOffset); - } - - readonly property real waveOffsetX: -wrapMod(phase / k, wavelength) - - FrameAnimation { - running: root.visible && (root.isPlaying || root.currentAmp > 0) - onTriggered: { - if (root.isPlaying) - root.phase += 0.03 * frameTime * 60; - startCap.y = waveY(waveClip.startX) - startCap.height / 2; - endCap.y = waveY(waveClip.endX) - endCap.height / 2; - actualEndCap.y = waveY(waveClip.gapEndX) - actualEndCap.height / 2; - } - } - - function buildStaticWave() { - const start = waveClip.startX - 2 * root.wavelength; - const end = width + 2 * root.wavelength; - if (end <= start) { - waveSvg.path = ""; - return; - } - - const kLocal = k; - const halfPeriod = root.wavelength / 2; - function y0(x) { - return root.midY + root.currentAmp * Math.sin(kLocal * x); - } - function dy0(x) { - return root.currentAmp * Math.cos(kLocal * x) * kLocal; - } - - let x0 = start; - let d = `M ${x0} ${y0(x0)}`; - while (x0 < end) { - const x1 = Math.min(x0 + halfPeriod, end); - const dx = x1 - x0; - const yA = y0(x0), yB = y0(x1); - const dyA = dy0(x0), dyB = dy0(x1); - const c1x = x0 + dx / 3; - const c1y = yA + (dyA * dx) / 3; - const c2x = x1 - dx / 3; - const c2y = yB - (dyB * dx) / 3; - d += ` C ${c1x} ${c1y} ${c2x} ${c2y} ${x1} ${yB}`; - x0 = x1; - } - waveSvg.path = d; - } - - Component.onCompleted: { - currentAmp = isPlaying ? amp : 0; - buildStaticWave(); - } - onWidthChanged: { - flatEnd.x = width; - buildStaticWave(); - } - onHeightChanged: buildStaticWave() - onCurrentAmpChanged: buildStaticWave() - onWavelengthChanged: { - k = (2 * Math.PI) / Math.max(1e-6, wavelength); - buildStaticWave(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/NumericText.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/NumericText.qml deleted file mode 100644 index fc78c2d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/NumericText.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQuick -import qs.Common - -StyledText { - id: root - - property string reserveText: "" - readonly property real reservedWidth: reserveText !== "" ? Math.max(contentWidth, reserveMetrics.width) : contentWidth - - isMonospace: true - wrapMode: Text.NoWrap - - StyledTextMetrics { - id: reserveMetrics - isMonospace: root.isMonospace - font.pixelSize: root.font.pixelSize - font.family: root.font.family - font.weight: root.font.weight - font.hintingPreference: root.font.hintingPreference - text: root.reserveText - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/PluginGlobalVar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/PluginGlobalVar.qml deleted file mode 100644 index 6a95a97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/PluginGlobalVar.qml +++ /dev/null @@ -1,30 +0,0 @@ -import QtQuick -import qs.Services - -Item { - id: root - - required property string varName - property var defaultValue: undefined - - readonly property var value: { - const pid = parent?.pluginId ?? "" - if (!pid || !PluginService.globalVars[pid]) { - return defaultValue - } - return PluginService.globalVars[pid][varName] ?? defaultValue - } - - function set(newValue) { - const pid = parent?.pluginId ?? "" - if (pid) { - PluginService.setGlobalVar(pid, varName, newValue) - } else { - console.warn("PluginGlobalVar: Cannot set", varName, "- no pluginId from parent") - } - } - - visible: false - width: 0 - height: 0 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/ScrollConstants.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/ScrollConstants.js deleted file mode 100644 index 22d314f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/ScrollConstants.js +++ /dev/null @@ -1,14 +0,0 @@ -.pragma library - -const friction = 0.96; -const touchpadSpeed = 3.5; -const mouseWheelSpeed = 60; -const momentumRetention = 0.92; -const momentumDeltaFactor = 0.15; -const maxMomentumVelocity = 2500; -const minMomentumVelocity = 50; -const momentumStopThreshold = 5; -const velocitySampleWindowMs = 100; -const momentumTimeThreshold = 50; -const flickDeceleration = 1500; -const maximumFlickVelocity = 2000; diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StateLayer.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StateLayer.qml deleted file mode 100644 index 8969d93..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StateLayer.qml +++ /dev/null @@ -1,74 +0,0 @@ -import QtQuick -import qs.Common - -MouseArea { - id: root - - property bool disabled: false - property color stateColor: Theme.surfaceText - property real cornerRadius: parent && parent.radius !== undefined ? parent.radius : Theme.cornerRadius - property var tooltipText: null - property string tooltipSide: "bottom" - property bool enableRipple: typeof SettingsData !== "undefined" ? (SettingsData.enableRippleEffects ?? true) : true - - readonly property real stateOpacity: disabled ? 0 : pressed ? 0.12 : containsMouse ? 0.08 : 0 - - anchors.fill: parent - cursorShape: disabled ? undefined : Qt.PointingHandCursor - hoverEnabled: true - - onPressed: mouse => { - if (!disabled && enableRipple) { - rippleLayer.trigger(mouse.x, mouse.y); - } - } - - Rectangle { - id: stateRect - anchors.fill: parent - radius: root.cornerRadius - color: Qt.rgba(stateColor.r, stateColor.g, stateColor.b, stateOpacity) - - Behavior on color { - enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None - DankColorAnim { - duration: Theme.shorterDuration - easing.bezierCurve: Theme.expressiveCurves.standardDecel - } - } - } - - DankRipple { - id: rippleLayer - anchors.fill: parent - rippleColor: root.stateColor - cornerRadius: root.cornerRadius - enableRipple: root.enableRipple - } - - Timer { - id: hoverDelay - interval: 400 - repeat: false - onTriggered: { - tooltip.show(root.tooltipText, root, 0, 0, root.tooltipSide); - } - } - - onEntered: { - if (!tooltipText) - return; - hoverDelay.restart(); - } - - onExited: { - if (!tooltipText) - return; - hoverDelay.stop(); - tooltip.hide(); - } - - DankTooltipV2 { - id: tooltip - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledRect.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledRect.qml deleted file mode 100644 index 03ab84b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledRect.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - color: "transparent" - radius: Appearance.rounding.normal - - readonly property var standardAnimation: { - "duration": Appearance.anim.durations.normal, - "easing.type": Easing.BezierSpline, - "easing.bezierCurve": Appearance.anim.curves.standard - } - - Behavior on radius { - NumberAnimation { - duration: standardAnimation.duration - easing.type: standardAnimation["easing.type"] - easing.bezierCurve: standardAnimation["easing.bezierCurve"] - } - } - - Behavior on opacity { - NumberAnimation { - duration: standardAnimation.duration - easing.type: standardAnimation["easing.type"] - easing.bezierCurve: standardAnimation["easing.bezierCurve"] - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledText.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledText.qml deleted file mode 100644 index 3c07ab1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledText.qml +++ /dev/null @@ -1,49 +0,0 @@ -import QtQuick -import qs.Common - -Text { - property bool isMonospace: false - - FontLoader { - id: interFont - source: Qt.resolvedUrl("../assets/fonts/inter/InterVariable.ttf") - } - - FontLoader { - id: firaCodeFont - source: Qt.resolvedUrl("../assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf") - } - - readonly property string resolvedFontFamily: { - const requestedFont = isMonospace ? Theme.monoFontFamily : Theme.fontFamily; - const defaultFont = isMonospace ? Theme.defaultMonoFontFamily : Theme.defaultFontFamily; - - if (requestedFont === defaultFont) { - return isMonospace ? firaCodeFont.name : interFont.name; - } - return requestedFont; - } - - readonly property var standardAnimation: { - "duration": Appearance.anim.durations.normal, - "easing.type": Easing.BezierSpline, - "easing.bezierCurve": Appearance.anim.curves.standard - } - - color: Theme.surfaceText - font.pixelSize: Appearance.fontSize.normal - font.family: resolvedFontFamily - font.weight: Theme.fontWeight - wrapMode: Text.WordWrap - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - //renderType: Text.NativeRendering - - Behavior on opacity { - NumberAnimation { - duration: standardAnimation.duration - easing.type: standardAnimation["easing.type"] - easing.bezierCurve: standardAnimation["easing.bezierCurve"] - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledTextMetrics.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledTextMetrics.qml deleted file mode 100644 index b297385..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/StyledTextMetrics.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services - -TextMetrics { - property bool isMonospace: false - - readonly property string resolvedFontFamily: { - const requestedFont = isMonospace ? SettingsData.monoFontFamily : SettingsData.fontFamily; - const defaultFont = isMonospace ? Theme.defaultMonoFontFamily : Theme.defaultFontFamily; - - if (requestedFont === defaultFont) { - const availableFonts = Qt.fontFamilies(); - if (!availableFonts.includes(requestedFont)) { - return isMonospace ? "Monospace" : "DejaVu Sans"; - } - } - return requestedFont; - } - - font.pixelSize: Appearance.fontSize.normal - font.family: resolvedFontFamily - font.weight: SettingsData.fontWeight -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/SystemLogo.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/SystemLogo.qml deleted file mode 100644 index 19922e5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/SystemLogo.qml +++ /dev/null @@ -1,84 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import qs.Common -import qs.Widgets - -Item { - id: root - - property string colorOverride: "" - property real brightnessOverride: 0.5 - property real contrastOverride: 1 - - readonly property bool hasColorOverride: colorOverride !== "" - - property bool useNerdFont: false - property string nerdFontIcon: "" - - IconImage { - id: iconImage - anchors.fill: parent - visible: !root.useNerdFont - - smooth: true - asynchronous: true - layer.enabled: hasColorOverride - - layer.effect: MultiEffect { - colorization: 1 - colorizationColor: colorOverride - brightness: brightnessOverride - contrast: contrastOverride - } - } - - DankNFIcon { - id: nfIcon - anchors.centerIn: parent - visible: root.useNerdFont - name: root.nerdFontIcon - size: Math.min(root.width, root.height) - color: hasColorOverride ? colorOverride : Theme.surfaceText - } - - Component.onCompleted: { - Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $NAME"], (nameOutput, nameExitCode) => { - if (nameExitCode === 0 && nameOutput.trim() === "RaveOS") { - iconImage.source = "file://" + Theme.shellDir + "/assets/raveos-logo.svg" - return - } - - Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $ID"], (output, exitCode) => { - if (!root || exitCode !== 0 || !output) return - const distroId = output.trim() - if (!distroId) return - - const supportedDistroNFs = ["debian", "arch", "archcraft", "fedora", "nixos", "ubuntu", "guix", "gentoo", "endeavouros", "manjaro", "opensuse"] - if (supportedDistroNFs.includes(distroId)) { - if (!root) return - root.useNerdFont = true - root.nerdFontIcon = distroId - return - } - - Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $LOGO"], (logoOutput, logoExitCode) => { - if (!root || !iconImage || logoExitCode !== 0 || !logoOutput) return - const logo = logoOutput.trim() - if (!logo) return - - if (logo === "cachyos") { - iconImage.source = "file:///usr/share/icons/cachyos.svg" - return - } - if (logo === "guix-icon") { - iconImage.source = "file:///run/current-system/profile/share/icons/hicolor/scalable/apps/guix-icon.svg" - return - } - iconImage.source = Quickshell.iconPath(logo, true) - }, 0) - }, 0) - }, 0) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnDetailContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnDetailContent.qml deleted file mode 100644 index 0ca0e56..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnDetailContent.qml +++ /dev/null @@ -1,235 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentPopout: null - property string expandedUuid: "" - property int listHeight: 180 - - implicitHeight: 32 + 1 + listHeight + Theme.spacingS * 4 + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - FileBrowserSurfaceModal { - id: fileBrowser - browserTitle: I18n.tr("Import VPN") - browserIcon: "vpn_key" - browserType: "vpn" - fileExtensions: VPNService.getFileFilter() - parentPopout: root.parentPopout - - onFileSelected: path => { - VPNService.importVpn(path.replace("file://", "")); - } - } - - ConfirmModal { - id: deleteConfirm - } - - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - RowLayout { - spacing: Theme.spacingS - width: parent.width - - StyledText { - text: { - if (!DMSNetworkService.connected) - return I18n.tr("Active: None"); - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) - return I18n.tr("Active: %1").arg(names[0] || "VPN"); - return I18n.tr("Active: %1 +%2").arg(names[0]).arg(names.length - 1); - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - Layout.fillWidth: true - } - - Rectangle { - height: 28 - radius: 14 - color: importArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - width: 90 - Layout.alignment: Qt.AlignVCenter - opacity: VPNService.importing ? 0.5 : 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: VPNService.importing ? "sync" : "add" - size: Theme.fontSizeSmall - color: Theme.primary - } - - StyledText { - text: I18n.tr("Import") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - } - - MouseArea { - id: importArea - anchors.fill: parent - hoverEnabled: true - cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !VPNService.importing - onClicked: fileBrowser.open() - } - } - - Rectangle { - height: 28 - radius: 14 - color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: DMSNetworkService.connected - width: 100 - Layout.alignment: Qt.AlignVCenter - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "link_off" - size: Theme.fontSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Disconnect") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: discAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.disconnectAllActive() - } - } - - DankActionButton { - Layout.alignment: Qt.AlignVCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("network"); - } - } - } - - Rectangle { - height: 1 - width: parent.width - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Item { - width: parent.width - height: root.listHeight - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: DMSNetworkService.profiles.length === 0 - - DankIcon { - name: "vpn_key_off" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No VPN profiles") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Click Import to add a .ovpn or .conf") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - DankListView { - id: vpnListView - anchors.fill: parent - visible: DMSNetworkService.profiles.length > 0 - spacing: 4 - cacheBuffer: 200 - clip: true - - model: ScriptModel { - values: DMSNetworkService.profiles - objectProp: "uuid" - } - - delegate: VpnProfileDelegate { - required property var modelData - width: vpnListView.width - profile: modelData - isExpanded: root.expandedUuid === modelData.uuid - onToggleExpand: { - if (root.expandedUuid === modelData.uuid) { - root.expandedUuid = ""; - return; - } - root.expandedUuid = modelData.uuid; - VPNService.getConfig(modelData.uuid); - } - onDeleteRequested: { - deleteConfirm.showWithOptions({ - "title": I18n.tr("Delete VPN"), - "message": I18n.tr("Delete \"%1\"?").arg(modelData.name), - "confirmText": I18n.tr("Delete"), - "confirmColor": Theme.error, - "onConfirm": () => VPNService.deleteVpn(modelData.uuid) - }); - } - } - } - } - - Item { - width: 1 - height: Theme.spacingS - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnProfileDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnProfileDelegate.qml deleted file mode 100644 index e859456..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/VpnProfileDelegate.qml +++ /dev/null @@ -1,287 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property var profile - property bool isExpanded: false - - signal toggleExpand - signal deleteRequested - - readonly property bool isActive: DMSNetworkService.activeUuids?.includes(profile?.uuid) ?? false - readonly property bool isHovered: rowArea.containsMouse || expandBtn.containsMouse || deleteBtn.containsMouse - readonly property var configData: isExpanded ? VPNService.editConfig : null - readonly property var configFields: buildConfigFields() - - height: isExpanded ? 46 + expandedContent.height : 46 - radius: Theme.cornerRadius - color: isHovered ? Theme.primaryHoverLight : (isActive ? Theme.primaryPressed : Theme.surfaceLight) - border.width: isActive ? 2 : 1 - border.color: isActive ? Theme.primary : Theme.outlineLight - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - clip: true - - function buildConfigFields() { - if (!configData) - return []; - const fields = []; - const data = configData.data || {}; - if (data.remote) - fields.push({ - "key": "server", - "label": I18n.tr("Server"), - "value": data.remote - }); - if (configData.username || data.username) - fields.push({ - "key": "user", - "label": I18n.tr("Username"), - "value": configData.username || data.username - }); - if (data.cipher) - fields.push({ - "key": "cipher", - "label": I18n.tr("Cipher"), - "value": data.cipher - }); - if (data.auth) - fields.push({ - "key": "auth", - "label": I18n.tr("Auth"), - "value": data.auth - }); - if (data["proto-tcp"] === "yes" || data["proto-tcp"] === "no") - fields.push({ - "key": "proto", - "label": I18n.tr("Protocol"), - "value": data["proto-tcp"] === "yes" ? "TCP" : "UDP" - }); - if (data["tunnel-mtu"]) - fields.push({ - "key": "mtu", - "label": I18n.tr("MTU"), - "value": data["tunnel-mtu"] - }); - if (data["connection-type"]) - fields.push({ - "key": "conntype", - "label": I18n.tr("Auth Type"), - "value": data["connection-type"] - }); - return fields; - } - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - MouseArea { - id: rowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.toggle(profile.uuid) - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - height: 46 - Theme.spacingS * 2 - spacing: Theme.spacingS - - DankIcon { - name: isActive ? "vpn_lock" : "vpn_key_off" - size: 20 - color: isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 1 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - 28 - 28 - Theme.spacingS * 4 - - StyledText { - text: profile?.name ?? "" - font.pixelSize: Theme.fontSizeMedium - color: isActive ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: VPNService.getVpnTypeFromProfile(profile) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - wrapMode: Text.NoWrap - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - } - - Item { - width: Theme.spacingXS - height: 1 - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: expandBtn.containsMouse ? Theme.surfacePressed : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: expandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.toggleExpand() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: deleteBtn.containsMouse ? Theme.errorHover : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.deleteRequested() - } - } - } - - Column { - id: expandedContent - width: parent.width - spacing: Theme.spacingXS - visible: isExpanded - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineLight - } - - Item { - width: parent.width - height: VPNService.configLoading ? 40 : 0 - visible: VPNService.configLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "sync" - size: 16 - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: !VPNService.configLoading && configData - - Repeater { - model: configFields - - delegate: Rectangle { - required property var modelData - - width: fieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceLight - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: fieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Autoconnect") - checked: configData ? (configData.autoconnect || false) : false - visible: !VPNService.configLoading && configData !== null - onToggled: checked => { - VPNService.updateConfig(profile.uuid, { - autoconnect: checked - }); - } - } - - Item { - width: 1 - height: Theme.spacingXS - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/WindowBlur.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/WindowBlur.qml deleted file mode 100644 index 3b45212..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/WindowBlur.qml +++ /dev/null @@ -1,65 +0,0 @@ -import QtQuick -import qs.Services - -Item { - id: root - - visible: false - - required property var targetWindow - property var blurItem: null - property real blurX: 0 - property real blurY: 0 - property real blurWidth: 0 - property real blurHeight: 0 - property real blurRadius: 0 - - property var _region: null - - function _apply() { - if (!BlurService.enabled || !targetWindow) { - _cleanup(); - return; - } - - if (!_region) - _region = BlurService.createBlurRegion(targetWindow); - - if (!_region) - return; - - _region.item = Qt.binding(() => root.blurItem); - _region.x = Qt.binding(() => root.blurX); - _region.y = Qt.binding(() => root.blurY); - _region.width = Qt.binding(() => root.blurWidth); - _region.height = Qt.binding(() => root.blurHeight); - _region.radius = Qt.binding(() => root.blurRadius); - } - - function _cleanup() { - if (!_region) - return; - BlurService.destroyBlurRegion(targetWindow, _region); - _region = null; - } - - Connections { - target: BlurService - function onEnabledChanged() { - root._apply(); - } - } - - Connections { - target: root.targetWindow - function onVisibleChanged() { - if (root.targetWindow && root.targetWindow.visible) { - root._region = null; - root._apply(); - } - } - } - - Component.onCompleted: _apply() - Component.onDestruction: _cleanup() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/dank.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/dank.svg deleted file mode 100644 index 73ba0b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/dank.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo.svg deleted file mode 100644 index 879bf30..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo.svg +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo2.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo2.svg deleted file mode 100644 index 1ee6d51..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogo2.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogonormal.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogonormal.svg deleted file mode 100644 index 4ebbc58..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/danklogonormal.svg +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/discord.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/discord.svg deleted file mode 100644 index 646fd68..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/discord.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/InterVariable.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/InterVariable.ttf deleted file mode 100644 index 4ab79e0..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/InterVariable.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/LICENSE.txt b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/LICENSE.txt deleted file mode 100644 index 9b2ca37..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/LICENSE.txt +++ /dev/null @@ -1,92 +0,0 @@ -Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION AND CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/README.md deleted file mode 100644 index d719589..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/inter/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# Inter - -Inter is a typeface carefully crafted & designed for computer screens. -Inter features a tall x-height to aid in readability of mixed-case and lower-case text. -Inter is a [variable font](https://rsms.me/inter/#variable) with -several [OpenType features](https://rsms.me/inter/#features), like contextual alternates that adjusts punctuation depending on the shape of surrounding glyphs, slashed zero for when you need to disambiguate "0" from "o", tabular numbers, etc. - -[**Download Inter font files…**](https://github.com/rsms/inter/releases/latest) - -
        - -[![Sample](misc/readme/intro.png)](https://rsms.me/inter/) - - -### Quick questions - -- **Where can I get Inter?** [Here](https://github.com/rsms/inter/releases/latest) -- **I think I found a bug. How can I let you know?** [Open an issue here](https://github.com/rsms/inter/issues/new?template=bug_report.md) -- **I have a question. Where can I get help?** [Post in Discussions Q&A](https://github.com/rsms/inter/discussions/categories/q-a) -- **Should I use Inter from Google Fonts?** No, unless you have no other choice. - (outdated, no italics) -- **Can I legally use Inter for my purpose?** Most likely _yes!_ Inter is free and open source. - ([Read the license](LICENSE.txt) for details.) - - -## Using & installing Inter - -[**Download the latest font files…**](https://github.com/rsms/inter/releases/latest) - -Using Inter on a web page: - -```html - - -``` - -```css -:root { font-family: 'Inter', sans-serif; } -@supports (font-variation-settings: normal) { - :root { font-family: 'Inter var', sans-serif; } -} -``` - -For web pages, there's an official [CDN distribution](https://rsms.me/inter/inter.css) that you can use directly without having to host the font files yourself: - -```html - - -``` - - -### Alternate distributions - -- [NPM `inter-ui`](https://www.npmjs.com/package/inter-ui) -- [Homebrew `font-inter`](https://github.com/Homebrew/homebrew-cask-fonts) -- [Ubuntu `fonts-inter`](https://packages.ubuntu.com/search?keywords=fonts-inter) -- [List of Inter available on various Linux distributions…](https://repology.org/project/fonts:inter/versions) -- [Google Fonts](https://fonts.google.com/specimen/Inter) - -**Disclaimer:** Alternate distributions may not always be up-to-date. - - -## Notable uses of Inter - -- [ElementaryOS](https://elementary.io/) -- [Figma](https://figma.com/) -- [GitLab](https://gitlab.com/) -- [Guggenheim museums](https://www.pentagram.com/work/guggenheim-3) ([case study](https://www.pentagram.com/work/guggenheim-3/)) -- [ISO (International Organization for Standardization)](https://www.iso.org/) ([case study](https://www.motherbird.com.au/projects/iso/)) -- [Minimalissimo magazine](https://minimalissimo.com/) -- [Mozilla](https://mozilla.design/firefox/typography/) -- [NASA](https://www.nasa.gov/specials/artemis-ii/) -- [Pixar Presto](https://en.wikipedia.org/wiki/Presto_(animation_software)) -- [Switzerland, Canton of Zurich](https://www.zh.ch/) -- [Unity](https://unity.com/) -- [Zurich Airport](https://flughafen-zuerich.ch/) - - -> **Have you made something nice with Inter?**
        -> [Please share in Show & Tell! →](https://github.com/rsms/inter/discussions/categories/show-and-tell) - - -### Notable forks - -- [Open Runde](https://github.com/lauridskern/open-runde) is a rounded variant of Inter -- [Interalia](https://github.com/Shavian-info/interalia) extends Inter with Shavian characters -- [Raveo](https://github.com/jakubfoglar/raveo) is a "warmer version" of Inter - - -## Supporters & contributors - -A wholehearted **Thank You** to everyone who supports the Inter project! - -Special thanks to -[@thundernixon](https://github.com/thundernixon) and -[@KatjaSchimmel](https://github.com/KatjaSchimmel) -who have put in significant effort into making Inter what it is through -their contributions ♡ - -See [graphs/contributors](https://github.com/rsms/inter/graphs/contributors) -for a complete list of all contributors. - - -## Contributing to this project - -For instructions on how to work with the source files and how to -[compile & build font files](CONTRIBUTING.md#compiling-font-files), -refer to [**CONTRIBUTING.md**](CONTRIBUTING.md). - -Inter is licensed under the [SIL Open Font License](LICENSE.txt) - - -## Creating derivative fonts - -Inter is open source which means you can make your own versions with your own changes. -However when doing so, please [**read LICENSE.txt carefully.**](LICENSE.txt) It is a standard **SIL Open Font License 1.1**: - -> The goals of the Open Font License (OFL) are to stimulate worldwide -> development of collaborative font projects, to support the font creation -> efforts of academic and linguistic communities, and to provide a free and -> open framework in which fonts may be shared and improved in partnership -> with others. -> -> The OFL allows the licensed fonts to be used, studied, modified and -> redistributed freely as long as they are not sold by themselves. The -> fonts, including any derivative works, can be bundled, embedded, -> redistributed and/or sold with any software provided that any reserved -> names are not used by derivative works. The fonts and derivatives, -> however, cannot be released under any other type of license. The -> requirement for fonts to remain under this license does not apply -> to any document created using the fonts or their derivatives. - -While you are allowed to use Inter commercially, i.e. bundled with product or service which makes you money, you are NOT allowed to sell Inter itself or derivatives of Inter. If you would like to do so, please [reach out](https://github.com/rsms) and we can talk about it. - -Inter a trademark of Rasmus Andersson (DBA: RSMS) - -"Inter" is a Reserved Font Name by Rasmus Andersson -([font vendor code RSMS.](https://learn.microsoft.com/en-us/typography/vendors/#r)) - - -## Design - -_This section discusses some of the design choices made for Inter._ - -Inter can be classified as a geometric neo-grotesque, similar in style to Roboto, Apple San Francisco, Akkurat, Asap, Lucida Grande and more. Some trade-offs were made in order to make this typeface work really well at small sizes: - -- Early versions of Inter was not suitable for very large sizes because of some small-scale glyph optimizations (like "pits" and "traps") that help rasterization at small sizes but stand out and interfere at large sizes. However today Inter works well at large sizes and a [Display subfamily](https://github.com/rsms/inter/releases/tag/display-beta-1) is in the works for really large "display" sizes. - -- Rasterized at sizes below 12px, some stems—like the horizontal center of "E", "F", or vertical center of "m"—are drawn with two semi-opaque pixels instead of one solid. This is because we "prioritize" (optimize for) higher-density rasterizations. If we move these stems to an off-center position—so that they can be drawn sharply at e.g. 11px—text will be less legible at higher resolutions. - -Inter is a [variable font](https://rsms.me/inter/#variable) and is in addition also distributed as a set of traditional distinct font files in the following styles: - -| Roman (upright) name | Italic name | Weight -| -------------------- | -------------------- | ------------ -| Thin | Thin Italic | 100 -| Extra Light | Extra Light Italic | 200 -| Light | Light Italic | 300 -| Regular | Italic | 400 -| Medium | Medium Italic | 500 -| Semi Bold | Semi Bold Italic | 600 -| Bold | Bold Italic | 700 -| Extra Bold | Extra Bold Italic | 800 -| Black | Black Italic | 900 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/LICENSE deleted file mode 100644 index d645695..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/README.md deleted file mode 100644 index 724f231..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/README.md +++ /dev/null @@ -1,141 +0,0 @@ -## Material Symbols / Material Icons - -These are two different official icon sets from Google, using the same underlying designs. Material Symbols is the current set, introduced in April 2022, built on variable font technology. Material Icons is the classic set, but no longer updated. More details below. - -The icons can be browsed in a more user-friendly way at https://fonts.google.com/icons. Use the popdown menu near top left to choose between the two sets; Material Symbols is the default. - -The icons are designed under the [material design guidelines](https://material.io/guidelines/). - -## Icon Requests - -We’d love to support your icon needs! Please submit your request here on GitHub as an issue. - -Please note that Google Fonts does not accept user submissions of finished icon designs! There are fairly strict guidelines for Material icons, plus Google has upstream source files from which this repo is generated. Therefore, Google does not accept pull requests for icon files (whether new icon suggestions, or fixes for existing icons). Concepts are appreciated—just don’t design SVGs and submit them via pull request. - -However, users are perfectly welcome to point at outside files or images as examples—for the kind of thing they want, but they won’t just be taken “as is.” This works especially well if you have multiple examples for a single icon, to help us understand the “essence” of the idea. - -> For example, there is a fairly universal conceptual logo/icon for “agender,” so if you were proposing Google add an agender icon in the Material style, either mentioning that, or pointing at https://www.google.com/search?q=agender+icon would be a helpful tip. - -### Third-party logos - -Currently, Google does not include 3rd-party logos among the Material Symbols or Material Icons due to legal reasons. Some 3rd-party logos that were included in the past have since been removed. - -## npm Packages - -Google does not currently maintain the npm package for this repo, past v3 (2016). However, user @marella is hosting the following. He tells us these are automatically updated and published using GitHub Actions. Note: Google does **not** monitor or vet these packages. - -### [material-symbols](https://github.com/marella/material-symbols/tree/main/material-symbols#readme) [![npm](https://img.shields.io/npm/v/material-symbols)](https://www.npmjs.com/package/material-symbols) [![install size](https://packagephobia.com/badge?p=material-symbols)](https://packagephobia.com/result?p=material-symbols) - -- Only WOFF2 variable fonts and CSS for Material Symbols -- Includes outlined, rounded, and sharp icons and all variations of fill, weight, grade, and optical size -- Supports Sass - -### [material-icons](https://github.com/marella/material-icons#readme) [![npm](https://img.shields.io/npm/v/material-icons)](https://www.npmjs.com/package/material-icons) [![install size](https://packagephobia.com/badge?p=material-icons)](https://packagephobia.com/result?p=material-icons) [![Downloads](https://img.shields.io/npm/dm/material-icons)](https://www.npmjs.com/package/material-icons) - -- Only WOFF2, WOFF fonts and CSS -- Includes outlined, round, sharp and two-tone icons -- Supports Sass - -### [@material-design-icons/font](https://github.com/marella/material-design-icons/tree/main/font#readme) [![npm (scoped)](https://img.shields.io/npm/v/@material-design-icons/font)](https://www.npmjs.com/package/@material-design-icons/font) [![install size](https://packagephobia.com/badge?p=@material-design-icons/font)](https://packagephobia.com/result?p=@material-design-icons/font) - -- Only WOFF2 fonts and CSS -- Lighter version of `material-icons` package -- Doesn't support [older browsers](https://caniuse.com/woff2) such as Internet Explorer because of dropping WOFF (v1) - -### [@material-design-icons/svg](https://github.com/marella/material-design-icons/tree/main/svg#readme) [![npm (scoped)](https://img.shields.io/npm/v/@material-design-icons/svg)](https://www.npmjs.com/package/@material-design-icons/svg) [![install size](https://packagephobia.com/badge?p=@material-design-icons/svg)](https://packagephobia.com/result?p=@material-design-icons/svg) - -- Only SVGs -- Optimizes SVGs using SVGO - -## Material Symbols - -These newer icons can be browsed in a more user-friendly way at https://fonts.google.com/icons. Use the popdown menu near top left to choose between the two sets; Material Symbols is the default. - -These icons were built/designed as variable fonts first (based on the 24 px designs from Material Icons). There are three separate Material Symbols variable fonts, which also have static icons available (but those do not have all the variations available, as that would be hundreds of styles): -- Outlined -- Rounded -- Sharp -- Note that although there is no separate Filled font, the Fill axis allows access to filled styles, in all three fonts. It can also be manipulated for an animated fill effect, to indicate user selection. - -Each of the fonts has these design axes, which can be varied in CSS, or in many more modern design apps: -- Optical Size (opsz) from 20 to 48 px. The default is 24. -- Weight from 100 (Thin) to 700 (Bold). Regular is 400. -- Grade from -50 to 200. The default is 0 (zero). -50 is suggested for reversed contrast (e.g. white icons on black background) -- Fill from 0 to 100. The default is 0 (zero). - -The following directories in this repo contain specifically Material Symbols (not Material Icons) content: -- symbols -- variablefont - -What is currently _not_ available in Material Symbols? -- only the 20 and 24 px versions are designed with perfect pixel-grid alignment -- the only pre-made fonts are the variable fonts -- there are no two-tone icons - -## Material Icons - -The icons can be browsed in a more user-friendly way at https://fonts.google.com/icons?icon.set=Material+Icons - -These classic icons are available in five distinct styles: -- Outlined -- Filled (the font version is just called Material Icons, as this is the oldest style) -- Rounded -- Sharp -- Two tone - -The following directories in this repo contain specifically Material Icons (not Material Symbols) content: -- android -- font -- ios -- png -- src - -What is currently _not_ available in Material Icons? -- variable fonts -- weights other than Regular -- grades other than Regular -- a means to animate Fill transitions -- new icons (since updates were halted in 2022) - -## Material Icons update history - -### 4.0.0 Update -* 2020 Aug 31 -* Restructured repository, updated assets. - -### 3.0.1 Update -* 2016 Sep 01 -* Changed license in package.json. -* Added missing device symbol sprites. - -### 3.0.0 Update -* 2016 Aug 25 -* License change to Apache 2.0! - -### 2.0 -* 2016 May 28 - -## Getting Started - -Read the [developer guide](https://developers.google.com/fonts/docs/material_icons) on how to use the material design icons in your project. - -### Using a font - -The `font` and `variablefont` folders contain pre-generated font files that can be included in a project. This is especially convenient for the web; however, it is generally better to link to the web font hosted on Google Fonts: - -```html - -``` - -```html - -``` -Read more on [Material Symbols](https://developers.google.com/fonts/docs/material_symbols/) or [Material Icons](https://developers.google.com/fonts/docs/material_icons/) in the Google Fonts developer guide. - - -## License - -We have made these icons available for you to incorporate into your products under the [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt). Feel free to remix and re-share these icons and documentation in your products. -We'd love attribution in your app's *about* screen, but it's not required. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].codepoints b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].codepoints deleted file mode 100644 index be20939..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].codepoints +++ /dev/null @@ -1,4102 +0,0 @@ -10k e951 -10mp e952 -11mp e953 -123 eb8d -12mp e954 -13mp e955 -14mp e956 -15mp e957 -16mp e958 -17mp e959 -18_up_rating f8fd -18mp e95a -19mp e95b -1k e95c -1k_plus e95d -1x_mobiledata efcd -1x_mobiledata_badge f7f1 -20mp e95e -21mp e95f -22mp e960 -23mp e961 -24fps_select f3f2 -24mp e962 -2d ef37 -2k e963 -2k_plus e964 -2mp e965 -30fps efce -30fps_select efcf -360 e577 -3d ed38 -3d_rotation e84d -3g_mobiledata efd0 -3g_mobiledata_badge f7f0 -3k e966 -3k_plus e967 -3mp e968 -3p efd1 -4g_mobiledata efd2 -4g_mobiledata_badge f7ef -4g_plus_mobiledata efd3 -4k e072 -4k_plus e969 -4mp e96a -50mp f6f3 -5g ef38 -5g_mobiledata_badge f7ee -5k e96b -5k_plus e96c -5mp e96d -60fps efd4 -60fps_select efd5 -6_ft_apart f21e -6k e96e -6k_plus e96f -6mp e970 -7k e971 -7k_plus e972 -7mp e973 -8k e974 -8k_plus e975 -8mp e976 -9k e977 -9k_plus e978 -9mp e979 -abc eb94 -ac_unit eb3b -access_alarm e855 -access_alarms e855 -access_time efd6 -access_time_filled efd6 -accessibility e84e -accessibility_new e92c -accessible e914 -accessible_forward e934 -accessible_menu f34e -account_balance e84f -account_balance_wallet e850 -account_box e851 -account_child e852 -account_child_invert e659 -account_circle f20b -account_circle_filled f20b -account_circle_off f7b3 -account_tree e97a -action_key f502 -activity_zone e1e6 -acupuncture f2c4 -acute e4cb -ad e65a -ad_group e65b -ad_group_off eae5 -ad_off f7b2 -ad_units f2eb -adaptive_audio_mic f4cc -adaptive_audio_mic_off f4cb -adb e60e -add e145 -add_2 f3dd -add_a_photo e439 -add_ad e72a -add_alarm e856 -add_alert e003 -add_box e146 -add_business e729 -add_call f0b7 -add_card eb86 -add_chart ef3c -add_circle e3ba -add_circle_outline e3ba -add_column_left f425 -add_column_right f424 -add_comment e266 -add_diamond f49c -add_home f8eb -add_home_work f8ed -add_ic_call f0b7 -add_link e178 -add_location e567 -add_location_alt ef3a -add_moderator e97d -add_notes e091 -add_photo_alternate e43e -add_reaction e1d3 -add_road ef3b -add_row_above f423 -add_row_below f422 -add_shopping_cart e854 -add_task f23a -add_to_drive e65c -add_to_home_screen f2b9 -add_to_photos e39d -add_to_queue e05c -add_triangle f48e -addchart ef3c -adf_scanner eada -adjust e39e -admin_meds e48d -admin_panel_settings ef3d -ads_click e762 -agender f888 -agriculture ea79 -air efd8 -air_freshener e2ca -air_purifier e97e -air_purifier_gen e829 -airline_seat_flat e630 -airline_seat_flat_angled e631 -airline_seat_individual_suite e632 -airline_seat_legroom_extra e633 -airline_seat_legroom_normal e634 -airline_seat_legroom_reduced e635 -airline_seat_recline_extra e636 -airline_seat_recline_normal e637 -airline_stops e7d0 -airlines e7ca -airplane_ticket efd9 -airplanemode_active e53d -airplanemode_inactive e194 -airplay e055 -airport_shuttle eb3c -airware f154 -airwave f154 -alarm e855 -alarm_add e856 -alarm_off e857 -alarm_on e858 -alarm_pause f35b -alarm_smart_wake f6b0 -album e019 -align_center e356 -align_end f797 -align_flex_center f796 -align_flex_end f795 -align_flex_start f794 -align_horizontal_center e00f -align_horizontal_left e00d -align_horizontal_right e010 -align_items_stretch f793 -align_justify_center f792 -align_justify_flex_end f791 -align_justify_flex_start f790 -align_justify_space_around f78f -align_justify_space_between f78e -align_justify_space_even f78d -align_justify_stretch f78c -align_self_stretch f78b -align_space_around f78a -align_space_between f789 -align_space_even f788 -align_start f787 -align_stretch f786 -align_vertical_bottom e015 -align_vertical_center e011 -align_vertical_top e00c -all_inbox e97f -all_inclusive eb3d -all_match e093 -all_out e90b -allergies e094 -allergy e64e -alt_route f184 -alternate_email e0e6 -altitude f873 -ambient_screen f6c4 -ambulance f803 -amend f802 -amp_stories ea13 -analytics ef3e -anchor f1cd -android e859 -android_cell_4_bar ef06 -android_cell_4_bar_alert ef09 -android_cell_4_bar_off ef08 -android_cell_4_bar_plus ef07 -android_cell_5_bar ef02 -android_cell_5_bar_alert ef05 -android_cell_5_bar_off ef04 -android_cell_5_bar_plus ef03 -android_cell_dual_4_bar ef0d -android_cell_dual_4_bar_alert ef0f -android_cell_dual_4_bar_plus ef0e -android_cell_dual_5_bar ef0a -android_cell_dual_5_bar_alert ef0c -android_cell_dual_5_bar_plus ef0b -android_wifi_3_bar ef16 -android_wifi_3_bar_alert ef1b -android_wifi_3_bar_lock ef1a -android_wifi_3_bar_off ef19 -android_wifi_3_bar_plus ef18 -android_wifi_3_bar_question ef17 -android_wifi_4_bar ef10 -android_wifi_4_bar_alert ef15 -android_wifi_4_bar_lock ef14 -android_wifi_4_bar_off ef13 -android_wifi_4_bar_plus ef12 -android_wifi_4_bar_question ef11 -animated_images f49a -animation e71c -announcement e87f -aod f2e6 -aod_tablet f89f -aod_watch f6ac -apartment ea40 -api f1b7 -apk_document f88e -apk_install f88f -app_badging f72f -app_blocking f2e5 -app_promo f2cd -app_registration ef40 -app_settings_alt f2d9 -app_shortcut f2df -apparel ef7b -approval e982 -approval_delegation f84a -approval_delegation_off f2c5 -apps e5c3 -apps_outage e7cc -aq f55a -aq_indoor f55b -ar_on_you ef7c -ar_stickers e983 -architecture ea3b -archive e149 -area_chart e770 -arming_countdown e78a -arrow_and_edge f5d7 -arrow_back e5c4 -arrow_back_2 f43a -arrow_back_ios e5e0 -arrow_back_ios_new e2ea -arrow_circle_down f181 -arrow_circle_left eaa7 -arrow_circle_right eaaa -arrow_circle_up f182 -arrow_cool_down f4b6 -arrow_downward e5db -arrow_downward_alt e984 -arrow_drop_down e5c5 -arrow_drop_down_circle e5c6 -arrow_drop_up e5c7 -arrow_forward e5c8 -arrow_forward_ios e5e1 -arrow_insert f837 -arrow_left e5de -arrow_left_alt ef7d -arrow_menu_close f3d3 -arrow_menu_open f3d2 -arrow_or_edge f5d6 -arrow_outward f8ce -arrow_range f69b -arrow_right e5df -arrow_right_alt e941 -arrow_selector_tool f82f -arrow_shape_up eef6 -arrow_shape_up_stack eef7 -arrow_shape_up_stack_2 eef8 -arrow_split ea04 -arrow_top_left f72e -arrow_top_right f72d -arrow_upload_progress f3f4 -arrow_upload_ready f3f5 -arrow_upward e5d8 -arrow_upward_alt e986 -arrow_warm_up f4b5 -arrows_input f394 -arrows_more_down f8ab -arrows_more_up f8ac -arrows_output f393 -arrows_outward f72c -art_track e060 -article ef42 -article_person f368 -article_shortcut f587 -artist e01a -aspect_ratio e85b -assessment f0cc -assignment e85d -assignment_add f848 -assignment_globe eeec -assignment_ind e85e -assignment_late e85f -assignment_return e860 -assignment_returned e861 -assignment_turned_in e862 -assist_walker f8d5 -assistant e39f -assistant_device e987 -assistant_direction e988 -assistant_navigation e989 -assistant_on_hub f6c1 -assistant_photo f0c6 -assured_workload eb6f -asterisk f525 -astrophotography_auto f1d9 -astrophotography_off f1da -atm e573 -atr ebc7 -attach_email ea5e -attach_file e226 -attach_file_add f841 -attach_file_off f4d9 -attach_money e227 -attachment e2bc -attractions ea52 -attribution efdb -audio_description f58c -audio_file eb82 -audio_video_receiver f5d3 -audiotrack e405 -auto_activity_zone f8ad -auto_awesome e65f -auto_awesome_mosaic e660 -auto_awesome_motion e661 -auto_delete ea4c -auto_detect_voice f83e -auto_draw_solid e98a -auto_fix e663 -auto_fix_high e663 -auto_fix_normal e664 -auto_fix_off e665 -auto_graph e4fb -auto_label f6be -auto_meeting_room f6bf -auto_mode ec20 -auto_read_pause f219 -auto_read_play f216 -auto_schedule e214 -auto_stories e666 -auto_stories_off f267 -auto_timer ef7f -auto_towing e71e -auto_transmission f53f -auto_videocam f6c0 -autofps_select efdc -automation f421 -autopause f6b6 -autopay f84b -autoplay f6b5 -autorenew e863 -autostop f682 -av1 f4b0 -av_timer e01b -avc f4af -avg_pace f6bb -avg_time f813 -award_meal f241 -award_star f612 -azm f6ec -baby_changing_station f19b -back_hand e764 -back_to_tab f72b -background_dot_large f79e -background_dot_small f514 -background_grid_small f79d -background_replace f20a -backlight_high f7ed -backlight_high_off f4ef -backlight_low f7ec -backpack f19c -backspace e14a -backup e864 -backup_table ef43 -badge ea67 -badge_critical_battery f156 -badminton f2a8 -bakery_dining ea53 -balance eaf6 -balcony e58f -ballot e172 -bar_chart e26b -bar_chart_4_bars f681 -bar_chart_off f411 -barcode e70b -barcode_reader f85c -barcode_scanner e70c -barefoot f871 -batch_prediction f0f5 -bath_bedrock f286 -bath_outdoor f6fb -bath_private f6fa -bath_public_large f6f9 -bath_soak f2a0 -bathroom efdd -bathtub ea41 -battery_0_bar ebdc -battery_1_bar f09c -battery_20 f09c -battery_2_bar f09d -battery_30 f09d -battery_3_bar f09e -battery_4_bar f09f -battery_50 f09e -battery_5_bar f0a0 -battery_60 f09f -battery_6_bar f0a1 -battery_80 f0a0 -battery_90 f0a1 -battery_alert e19c -battery_android_0 f30d -battery_android_1 f30c -battery_android_2 f30b -battery_android_3 f30a -battery_android_4 f309 -battery_android_5 f308 -battery_android_6 f307 -battery_android_alert f306 -battery_android_bolt f305 -battery_android_frame_1 f257 -battery_android_frame_2 f256 -battery_android_frame_3 f255 -battery_android_frame_4 f254 -battery_android_frame_5 f253 -battery_android_frame_6 f252 -battery_android_frame_alert f251 -battery_android_frame_bolt f250 -battery_android_frame_full f24f -battery_android_frame_plus f24e -battery_android_frame_question f24d -battery_android_frame_share f24c -battery_android_frame_shield f24b -battery_android_full f304 -battery_android_plus f303 -battery_android_question f302 -battery_android_share f301 -battery_android_shield f300 -battery_change f7eb -battery_charging_20 f0a2 -battery_charging_30 f0a3 -battery_charging_50 f0a4 -battery_charging_60 f0a5 -battery_charging_80 f0a6 -battery_charging_90 f0a7 -battery_charging_full e1a3 -battery_error f7ea -battery_full e1a5 -battery_full_alt f13b -battery_horiz_000 f8ae -battery_horiz_050 f8af -battery_horiz_075 f8b0 -battery_low f155 -battery_plus f7e9 -battery_profile e206 -battery_saver efde -battery_share f67e -battery_status_good f67d -battery_std e1a5 -battery_unknown e1a6 -battery_vert_005 f8b1 -battery_vert_020 f8b2 -battery_vert_050 f8b3 -battery_very_low f156 -beach_access eb3e -bed efdf -bedroom_baby efe0 -bedroom_child efe1 -bedroom_parent efe2 -bedtime f159 -bedtime_off eb76 -beenhere e52d -beer_meal f285 -bento f1f4 -bia f6eb -bid_landscape e678 -bid_landscape_disabled ef81 -bigtop_updates e669 -bike_dock f47b -bike_lane f47a -bike_scooter ef45 -biotech ea3a -blanket e828 -blender efe3 -blind f8d6 -blinds e286 -blinds_closed ec1f -block f08c -blood_pressure e097 -bloodtype efe4 -bluetooth e1a7 -bluetooth_audio e60f -bluetooth_connected e1a8 -bluetooth_disabled e1a9 -bluetooth_drive efe5 -bluetooth_searching e60f -blur_circular e3a2 -blur_linear e3a3 -blur_medium e84c -blur_off e3a4 -blur_on e3a5 -blur_short e8cf -boat_bus f36d -boat_railway f36c -body_fat e098 -body_system e099 -bolt ea0b -bomb f568 -book e86e -book_2 f53e -book_3 f53d -book_4 f53c -book_5 f53b -book_6 f3df -book_online f2e4 -book_ribbon f3e7 -bookmark e8e7 -bookmark_add e598 -bookmark_added e599 -bookmark_bag f410 -bookmark_border e8e7 -bookmark_check f457 -bookmark_flag f456 -bookmark_heart f455 -bookmark_manager f7b1 -bookmark_remove e59a -bookmark_star f454 -bookmarks e98b -books_movies_and_music ef82 -border_all e228 -border_bottom e229 -border_clear e22a -border_color e22b -border_horizontal e22c -border_inner e22d -border_left e22e -border_outer e22f -border_right e230 -border_style e231 -border_top e232 -border_vertical e233 -borg f40d -bottom_app_bar e730 -bottom_drawer e72d -bottom_navigation e98c -bottom_panel_close f72a -bottom_panel_open f729 -bottom_right_click f684 -bottom_sheets e98d -box f5a4 -box_add f5a5 -box_edit f5a6 -boy eb67 -brand_awareness e98e -brand_family f4f1 -branding_watermark e06b -breakfast_dining ea54 -breaking_news ea08 -breaking_news_alt_1 f0ba -breastfeeding f856 -brick f388 -briefcase_meal f246 -brightness_1 e3fa -brightness_2 f036 -brightness_3 e3a8 -brightness_4 e3a9 -brightness_5 e3aa -brightness_6 e3ab -brightness_7 e3ac -brightness_alert f5cf -brightness_auto e1ab -brightness_empty f7e8 -brightness_high e1ac -brightness_low e1ad -brightness_medium e1ae -bring_your_own_ip e016 -broadcast_on_home f8f8 -broadcast_on_personal f8f9 -broken_image e3ad -browse eb13 -browse_activity f8a5 -browse_gallery ebd1 -browser_not_supported ef47 -browser_updated e7cf -brunch_dining ea73 -brush e3ae -bubble ef83 -bubble_chart e6dd -bubbles f64e -bucket_check ef2a -bug_report e868 -build f8cd -build_circle ef48 -bungalow e591 -burst_mode e43c -bus_alert e98f -bus_railway f36b -business e7ee -business_center eb3f -business_chip f84c -business_messages ef84 -buttons_alt e72f -cabin e589 -cable efe6 -cable_car f479 -cached e86a -cadence f4b4 -cake e7e9 -cake_add f85b -calculate ea5f -calendar_add_on ef85 -calendar_apps_script f0bb -calendar_check f243 -calendar_clock f540 -calendar_lock f242 -calendar_meal f296 -calendar_meal_2 f240 -calendar_month ebcc -calendar_today e935 -calendar_view_day e936 -calendar_view_month efe7 -calendar_view_week efe8 -call f0d4 -call_end f0bc -call_end_alt f0bc -call_log e08e -call_made e0b2 -call_merge e0b3 -call_missed e0b4 -call_missed_outgoing e0e4 -call_quality f652 -call_received e0b5 -call_split e0b6 -call_to_action e06c -camera e3af -camera_alt e412 -camera_enhance e8fc -camera_front f2c9 -camera_indoor efe9 -camera_outdoor efea -camera_rear f2c8 -camera_roll e3b3 -camera_video f7a6 -cameraswitch efeb -campaign ef49 -camping f8a2 -cancel e888 -cancel_presentation e0e9 -cancel_schedule_send ea39 -candle f588 -candlestick_chart ead4 -cannabis f2f3 -captive_portal f728 -capture f727 -car_crash ebf2 -car_defrost_left f344 -car_defrost_low_left f343 -car_defrost_low_right f342 -car_defrost_mid_left f278 -car_defrost_mid_low_left f341 -car_defrost_mid_low_right f277 -car_defrost_mid_right f340 -car_defrost_right f33f -car_fan_low_left f33e -car_fan_low_mid_left f33d -car_fan_low_right f33c -car_fan_mid_left f33b -car_fan_mid_low_right f33a -car_fan_mid_right f339 -car_fan_recirculate f338 -car_gear f337 -car_lock f336 -car_mirror_heat f335 -car_rental ea55 -car_repair ea56 -car_tag f4e3 -card_giftcard e8f6 -card_membership e8f7 -card_travel e8f8 -cardio_load f4b9 -cardiology e09c -cards e991 -cards_star f375 -carpenter f1f8 -carry_on_bag eb08 -carry_on_bag_checked eb0b -carry_on_bag_inactive eb0a -carry_on_bag_question eb09 -cases e992 -casino eb40 -cast e307 -cast_connected e308 -cast_for_education efec -cast_pause f5f0 -cast_warning f5ef -castle eab1 -category e574 -category_search f437 -celebration ea65 -cell_merge f82e -cell_tower ebba -cell_wifi e0ec -center_focus_strong e3b4 -center_focus_weak e3b5 -chair efed -chair_alt efee -chair_counter f29f -chair_fireplace f29e -chair_umbrella f29d -chalet e585 -change_circle e2e7 -change_history e86b -charger e2ae -charging_station f2e3 -chart_data e473 -chat e0c9 -chat_add_on f0f3 -chat_apps_script f0bd -chat_bubble e0cb -chat_bubble_outline e0cb -chat_dashed eeed -chat_error f7ac -chat_info f52b -chat_paste_go f6bd -chat_paste_go_2 f3cb -check e5ca -check_box e834 -check_box_outline_blank e835 -check_circle f0be -check_circle_filled f0be -check_circle_outline f0be -check_circle_unread f27e -check_in_out f6f6 -check_indeterminate_small f88a -check_small f88b -checkbook e70d -checked_bag eb0c -checked_bag_question eb0d -checklist e6b1 -checklist_rtl e6b3 -checkroom f19e -cheer f6a8 -chef_hat f357 -chess f5e7 -chess_bishop f261 -chess_bishop_2 f262 -chess_king f25f -chess_king_2 f260 -chess_knight f25e -chess_pawn f3b6 -chess_pawn_2 f25d -chess_queen f25c -chess_rook f25b -chevron_backward f46b -chevron_forward f46a -chevron_left e5cb -chevron_right e5cc -child_care eb41 -child_friendly eb42 -child_hat ef30 -chip_extraction f821 -chips e993 -chrome_reader_mode e86d -chromecast_2 f17b -chromecast_device e83c -chronic ebb2 -church eaae -cinematic_blur f853 -circle ef4a -circle_notifications e994 -circles e7ea -circles_ext e7ec -clarify f0bf -class e86e -clean_hands f21f -cleaning e995 -cleaning_bucket f8b4 -cleaning_services f0ff -clear e5cd -clear_all e0b8 -clear_day f157 -clear_night f159 -climate_mini_split f8b5 -clinical_notes e09e -clock_arrow_down f382 -clock_arrow_up f381 -clock_loader_10 f726 -clock_loader_20 f725 -clock_loader_40 f724 -clock_loader_60 f723 -clock_loader_80 f722 -clock_loader_90 f721 -close e5cd -close_fullscreen f1cf -close_small f508 -closed_caption e996 -closed_caption_add f4ae -closed_caption_disabled f1dc -closed_caption_off e996 -cloud f15c -cloud_alert f3cc -cloud_circle e2be -cloud_done e2bf -cloud_download e2c0 -cloud_lock f386 -cloud_off e2c1 -cloud_queue f15c -cloud_sync eb5a -cloud_upload e2c3 -cloudy f15c -cloudy_filled f15c -cloudy_snowing e810 -co2 e7b0 -co_present eaf0 -code e86f -code_blocks f84d -code_off e4f3 -coffee efef -coffee_maker eff0 -cognition e09f -cognition_2 f3b5 -collapse_all e944 -collapse_content f507 -collections e3d3 -collections_bookmark e431 -color_lens e40a -colorize e3b8 -colors e997 -combine_columns f420 -comedy_mask f4d6 -comic_bubble f5dd -comment e24c -comment_bank ea4e -comments_disabled e7a2 -commit eaf5 -communication e27c -communities eb16 -communities_filled eb16 -commute e940 -compare e3b9 -compare_arrows e915 -compass_calibration e57c -component_exchange f1e7 -compost e761 -compress e94d -computer e31e -computer_arrow_up f2f7 -computer_cancel f2f6 -concierge f561 -conditions e0a0 -confirmation_number e638 -congenital e0a1 -connect_without_contact f223 -connected_tv e998 -connecting_airports e7c9 -construction ea3c -contact_emergency f8d1 -contact_mail e0d0 -contact_page f22e -contact_phone f0c0 -contact_phone_filled f0c0 -contact_support e94c -contactless ea71 -contactless_off f858 -contacts e0ba -contacts_product e999 -content_copy e14d -content_cut e14e -content_paste e14f -content_paste_go ea8e -content_paste_off e4f8 -content_paste_search ea9b -contextual_token f486 -contextual_token_add f485 -contract f5a0 -contract_delete f5a2 -contract_edit f5a1 -contrast eb37 -contrast_circle f49f -contrast_rtl_off ec72 -contrast_square f4a0 -control_camera e074 -control_point e3ba -control_point_duplicate e3bb -controller_gen e83d -conversation ef2f -conversion_path f0c1 -conversion_path_off f7b4 -convert_to_text f41f -conveyor_belt f867 -cookie eaac -cookie_off f79a -cooking e2b6 -cool_to_dry e276 -copy_all e2ec -copyright e90c -coronavirus f221 -corporate_fare f1d0 -cottage e587 -counter_0 f785 -counter_1 f784 -counter_2 f783 -counter_3 f782 -counter_4 f781 -counter_5 f780 -counter_6 f77f -counter_7 f77e -counter_8 f77d -counter_9 f77c -countertops f1f7 -create f097 -create_new_folder e2cc -credit_card e8a1 -credit_card_clock f438 -credit_card_gear f52d -credit_card_heart f52c -credit_card_off e4f4 -credit_score eff1 -crib e588 -crisis_alert ebe9 -crop e3be -crop_16_9 e3bc -crop_3_2 e3bd -crop_5_4 e3bf -crop_7_5 e3c0 -crop_9_16 f549 -crop_din e3c6 -crop_free e3c2 -crop_landscape e3c3 -crop_original e3f4 -crop_portrait e3c5 -crop_rotate e437 -crop_square e3c6 -crossword f5e5 -crowdsource eb18 -crown ecb3 -cruelty_free e799 -css eb93 -csv e6cf -currency_bitcoin ebc5 -currency_exchange eb70 -currency_franc eafa -currency_lira eaef -currency_pound eaf1 -currency_ruble eaec -currency_rupee eaf7 -currency_rupee_circle f460 -currency_yen eafb -currency_yuan eaf9 -curtains ec1e -curtains_closed ec1d -custom_typography e732 -cut f08b -cycle f854 -cyclone ebd5 -dangerous e99a -dark_mode e51c -dashboard e871 -dashboard_2 f3ea -dashboard_customize e99b -data_alert f7f6 -data_array ead1 -data_check f7f2 -data_exploration e76f -data_info_alert f7f5 -data_loss_prevention e2dc -data_object ead3 -data_saver_off eff2 -data_saver_on eff3 -data_table e99c -data_thresholding eb9f -data_usage eff2 -database f20e -database_off f414 -database_search f38e -database_upload f3dc -dataset f8ee -dataset_linked f8ef -date_range e916 -deblur eb77 -deceased e0a5 -decimal_decrease f82d -decimal_increase f82c -deck ea42 -dehaze e3c7 -delete e92e -delete_forever e92b -delete_history f518 -delete_outline e92e -delete_sweep e16c -delivery_dining eb28 -delivery_truck_bolt f3a2 -delivery_truck_speed f3a1 -demography e489 -density_large eba9 -density_medium eb9e -density_small eba8 -dentistry e0a6 -departure_board e576 -deployed_code f720 -deployed_code_account f51b -deployed_code_alert f5f2 -deployed_code_history f5f3 -deployed_code_update f5f4 -dermatology e0a7 -description e873 -deselect ebb6 -design_services f10a -desk f8f4 -deskphone f7fa -desktop_access_disabled e99d -desktop_cloud f3db -desktop_cloud_stack f3be -desktop_landscape f45e -desktop_landscape_add f439 -desktop_mac e30b -desktop_portrait f45d -desktop_windows e30c -destruction f585 -details e3c8 -detection_and_zone e29f -detector e282 -detector_alarm e1f7 -detector_battery e204 -detector_co e2af -detector_offline e223 -detector_smoke e285 -detector_status e1e8 -developer_board e30d -developer_board_off e4ff -developer_guide e99e -developer_mode f2e2 -developer_mode_tv e874 -device_band f2f5 -device_hub e335 -device_reset e8b3 -device_thermostat e1ff -device_unknown f2e1 -devices e326 -devices_fold ebde -devices_fold_2 f406 -devices_off f7a5 -devices_other e337 -devices_wearables f6ab -dew_point f879 -diagnosis e0a8 -diagonal_line f41e -dialer_sip e0bb -dialogs e99f -dialpad e0bc -diamond ead5 -diamond_shine f2b2 -dictionary f539 -difference eb7d -digital_out_of_home f1de -digital_wellbeing ef86 -dine_heart f29c -dine_in f295 -dine_lamp f29b -dining eff4 -dinner_dining ea57 -directions e52e -directions_alt f880 -directions_alt_off f881 -directions_bike e52f -directions_boat eff5 -directions_boat_filled eff5 -directions_bus eff6 -directions_bus_filled eff6 -directions_car eff7 -directions_car_filled eff7 -directions_off f10f -directions_railway eff8 -directions_railway_2 f462 -directions_railway_filled eff8 -directions_run e566 -directions_subway effa -directions_subway_filled effa -directions_transit effa -directions_transit_filled effa -directions_walk e536 -directory_sync e394 -dirty_lens ef4b -disabled_by_default f230 -disabled_visible e76e -disc_full e610 -discover_tune e018 -dishwasher e9a0 -dishwasher_gen e832 -display_external_input f7e7 -display_settings eb97 -distance f6ea -diversity_1 f8d7 -diversity_2 f8d8 -diversity_3 f8d9 -diversity_4 f857 -dns e875 -do_disturb f08c -do_disturb_alt f08d -do_disturb_off f08e -do_disturb_on f08f -do_not_disturb f08d -do_not_disturb_alt f08c -do_not_disturb_off f08e -do_not_disturb_on f08f -do_not_disturb_on_total_silence effb -do_not_step f19f -do_not_touch f1b0 -dock f2e0 -dock_to_bottom f7e6 -dock_to_left f7e5 -dock_to_right f7e4 -docs ea7d -docs_add_on f0c2 -docs_apps_script f0c3 -document_scanner e5fa -document_search f385 -domain e7ee -domain_add eb62 -domain_disabled e0ef -domain_verification ef4c -domain_verification_off f7b0 -domino_mask f5e4 -done e876 -done_all e877 -done_outline e92f -donut_large e917 -donut_small e918 -door_back effc -door_front effd -door_open e77c -door_sensor e28a -door_sliding effe -doorbell efff -doorbell_3p e1e7 -doorbell_chime e1f3 -double_arrow ea50 -downhill_skiing e509 -download f090 -download_2 f523 -download_done f091 -download_for_offline f000 -downloading f001 -draft e66d -draft_orders e7b3 -drafts e151 -drag_click f71f -drag_handle e25d -drag_indicator e945 -drag_pan f71e -draw e746 -draw_abstract f7f8 -draw_collage f7f7 -drawing_recognition eb00 -dresser e210 -drive_eta eff7 -drive_export f41d -drive_file_move e9a1 -drive_file_move_outline e9a1 -drive_file_move_rtl e9a1 -drive_file_rename_outline e9a2 -drive_folder_upload e9a3 -drive_fusiontable e678 -drone f25a -drone_2 f259 -dropdown e9a4 -dropper_eye f351 -dry f1b3 -dry_cleaning ea58 -dual_screen f6cf -duo e9a5 -dvr e1b2 -dynamic_feed ea14 -dynamic_form f1bf -e911_avatar f11a -e911_emergency f119 -e_mobiledata f002 -e_mobiledata_badge f7e3 -ear_sound f356 -earbud_case f327 -earbud_left f326 -earbud_right f325 -earbuds f003 -earbuds_2 f324 -earbuds_battery f004 -early_on e2ba -earthquake f64f -east f1df -ecg f80f -ecg_heart f6e9 -eco ea35 -eda f6e8 -edgesensor_high f2ef -edgesensor_low f2ee -edit f097 -edit_arrow_down f380 -edit_arrow_up f37f -edit_attributes e578 -edit_audio f42d -edit_calendar e742 -edit_document f88c -edit_location e568 -edit_location_alt e1c5 -edit_note e745 -edit_notifications e525 -edit_off e950 -edit_road ef4d -edit_square f88d -editor_choice f528 -egg eacc -egg_alt eac8 -eject e8fb -elderly f21a -elderly_woman eb69 -electric_bike eb1b -electric_bolt ec1c -electric_car eb1c -electric_meter ec1b -electric_moped eb1d -electric_rickshaw eb1e -electric_scooter eb1f -electrical_services f102 -elevation f6e7 -elevator f1a0 -email e159 -emergency e1eb -emergency_heat f15d -emergency_heat_2 f4e5 -emergency_home e82a -emergency_recording ebf4 -emergency_share ebf6 -emergency_share_off f59e -emoji_emotions ea22 -emoji_events ea23 -emoji_flags f0c6 -emoji_food_beverage ea1b -emoji_language f4cd -emoji_nature ea1c -emoji_objects ea24 -emoji_people ea1d -emoji_symbols ea1e -emoji_transportation ea1f -emoticon e5f3 -empty_dashboard f844 -enable f188 -encrypted e593 -encrypted_add f429 -encrypted_add_circle f42a -encrypted_minus_circle f428 -encrypted_off f427 -endocrinology e0a9 -energy e9a6 -energy_program_saving f15f -energy_program_time_used f161 -energy_savings_leaf ec1a -engineering ea3d -enhanced_encryption e63f -ent e0aa -enterprise e70e -enterprise_off eb4d -equal f77b -equalizer e01d -eraser_size_1 f3fc -eraser_size_2 f3fb -eraser_size_3 f3fa -eraser_size_4 f3f9 -eraser_size_5 f3f8 -error f8b6 -error_circle_rounded f8b6 -error_med e49b -error_outline f8b6 -escalator f1a1 -escalator_warning f1ac -euro ea15 -euro_symbol e926 -ev_charger e56d -ev_mobiledata_badge f7e2 -ev_shadow ef8f -ev_shadow_add f580 -ev_shadow_minus f57f -ev_station e56d -event e878 -event_available e614 -event_busy e615 -event_list f683 -event_note e616 -event_repeat eb7b -event_seat e903 -event_upcoming f238 -exclamation f22f -exercise f6e6 -exit_to_app e879 -expand e94f -expand_all e946 -expand_circle_down e7cd -expand_circle_right f591 -expand_circle_up f5d2 -expand_content f830 -expand_less e5ce -expand_more e5cf -expansion_panels ef90 -expension_panels ef90 -experiment e686 -explicit e01e -explore e87a -explore_nearby e538 -explore_off e9a8 -explosion f685 -export_notes e0ac -exposure e3f6 -exposure_neg_1 e3cb -exposure_neg_2 e3cc -exposure_plus_1 e800 -exposure_plus_2 e3ce -exposure_zero e3cf -extension e87b -extension_off e4f5 -eye_tracking f4c9 -eyeglasses f6ee -eyeglasses_2 f2c7 -eyeglasses_2_sound f265 -face f008 -face_2 f8da -face_3 f8db -face_4 f8dc -face_5 f8dd -face_6 f8de -face_down f402 -face_left f401 -face_nod f400 -face_retouching_natural ef4e -face_retouching_off f007 -face_right f3ff -face_shake f3fe -face_unlock f008 -face_up f3fd -fact_check f0c5 -factory ebbc -falling f60d -familiar_face_and_zone e21c -family_group eef2 -family_history e0ad -family_home eb26 -family_link eb19 -family_restroom f1a2 -family_star f527 -fan_focus f334 -fan_indirect f333 -farsight_digital f559 -fast_forward e01f -fast_rewind e020 -fastfood e57a -faucet e278 -favorite e87e -favorite_border e87e -fax ead8 -feature_search e9a9 -featured_play_list e06d -featured_seasonal_and_gifts ef91 -featured_video e06e -feed f009 -feedback e87f -female e590 -femur f891 -femur_alt f892 -fence f1f6 -fertile f6e5 -festival ea68 -fiber_dvr e05d -fiber_manual_record e061 -fiber_new e05e -fiber_pin e06a -fiber_smart_record e062 -file_copy e173 -file_copy_off f4d8 -file_download f090 -file_download_done f091 -file_download_off e4fe -file_export f3b2 -file_json f3bb -file_map e2c5 -file_map_stack f3e2 -file_open eaf3 -file_png f3bc -file_present ea0e -file_save f17f -file_save_off e505 -file_upload f09b -file_upload_off f886 -files ea85 -filter e3d3 -filter_1 e3d0 -filter_2 e3d1 -filter_3 e3d2 -filter_4 e3d4 -filter_5 e3d5 -filter_6 e3d6 -filter_7 e3d7 -filter_8 e3d8 -filter_9 e3d9 -filter_9_plus e3da -filter_alt ef4f -filter_alt_off eb32 -filter_arrow_right f3d1 -filter_b_and_w e3db -filter_center_focus e3dc -filter_drama e3dd -filter_frames e3de -filter_hdr e3df -filter_list e152 -filter_list_alt e94e -filter_list_off eb57 -filter_none e3e0 -filter_retrolux e3e1 -filter_tilt_shift e3e2 -filter_vintage e3e3 -finance e6bf -finance_chip f84e -finance_mode ef92 -find_in_page e880 -find_replace e881 -fingerprint e90d -fingerprint_off f49d -fire_extinguisher f1d8 -fire_hydrant f1a3 -fire_truck f8f2 -fireplace ea43 -first_page e5dc -fit_page f77a -fit_page_height f397 -fit_page_width f396 -fit_screen ea10 -fit_width f779 -fitness_center eb43 -fitness_tracker f463 -fitness_trackers eef1 -flag f0c6 -flag_2 f40f -flag_check f3d8 -flag_circle eaf8 -flag_filled f0c6 -flaky ef50 -flare e3e4 -flash_auto e3e5 -flash_off e3e6 -flash_on e3e7 -flashlight_off f00a -flashlight_on f00b -flatware f00c -flex_direction f778 -flex_no_wrap f777 -flex_wrap f776 -flight e539 -flight_class e7cb -flight_land e904 -flight_takeoff e905 -flights_and_hotels e9ab -flightsmode ef93 -flip e3e8 -flip_camera_android ea37 -flip_camera_ios ea38 -flip_to_back e882 -flip_to_front e883 -float_landscape_2 f45c -float_portrait_2 f45b -flood ebe6 -floor f6e4 -floor_lamp e21e -flourescent f07d -flowchart f38d -flowsheet e0ae -fluid e483 -fluid_balance f80d -fluid_med f80c -fluorescent f07d -flutter f1dd -flutter_dash e00b -flyover f478 -fmd_bad f00e -fmd_good f1db -foggy e818 -folded_hands f5ed -folder e2c7 -folder_check f3d7 -folder_check_2 f3d6 -folder_code f3c8 -folder_copy ebbd -folder_data f586 -folder_delete eb34 -folder_eye f3d5 -folder_info f395 -folder_limited f4e4 -folder_managed f775 -folder_match f3d4 -folder_off eb83 -folder_open e2c8 -folder_shared e2c9 -folder_special e617 -folder_supervised f774 -folder_zip eb2c -follow_the_signs f222 -font_download e167 -font_download_off e4f9 -food_bank f1f2 -foot_bones f893 -footprint f87d -for_you e9ac -forest ea99 -fork_left eba0 -fork_right ebac -fork_spoon f3e4 -forklift f868 -format_align_center e234 -format_align_justify e235 -format_align_left e236 -format_align_right e237 -format_bold e238 -format_clear e239 -format_color_fill e23a -format_color_reset e23b -format_color_text e23c -format_h1 f85d -format_h2 f85e -format_h3 f85f -format_h4 f860 -format_h5 f861 -format_h6 f862 -format_image_left f863 -format_image_right f864 -format_indent_decrease e23d -format_indent_increase e23e -format_ink_highlighter f82b -format_italic e23f -format_letter_spacing f773 -format_letter_spacing_2 f618 -format_letter_spacing_standard f617 -format_letter_spacing_wide f616 -format_letter_spacing_wider f615 -format_line_spacing e240 -format_list_bulleted e241 -format_list_bulleted_add f849 -format_list_numbered e242 -format_list_numbered_rtl e267 -format_overline eb65 -format_paint e243 -format_paragraph f865 -format_quote e244 -format_quote_off f413 -format_shapes e25e -format_size e245 -format_strikethrough e246 -format_text_clip f82a -format_text_overflow f829 -format_text_wrap f828 -format_textdirection_l_to_r e247 -format_textdirection_r_to_l e248 -format_textdirection_vertical f4b8 -format_underlined e249 -format_underlined_squiggle f885 -forms_add_on f0c7 -forms_apps_script f0c8 -fort eaad -forum e8af -forward f57a -forward_10 e056 -forward_30 e057 -forward_5 e058 -forward_circle f6f5 -forward_media f6f4 -forward_to_inbox f187 -foundation f200 -fragrance f345 -frame_bug eeef -frame_exclamation eeee -frame_inspect f772 -frame_person f8a6 -frame_person_mic f4d5 -frame_person_off f7d1 -frame_reload f771 -frame_source f770 -free_breakfast eb44 -free_cancellation e748 -front_hand e769 -front_loader f869 -full_coverage eb12 -full_hd f58b -full_stacked_bar_chart f212 -fullscreen e5d0 -fullscreen_exit e5d1 -fullscreen_portrait f45a -function f866 -functions e24a -funicular f477 -g_mobiledata f010 -g_mobiledata_badge f7e1 -g_translate e927 -gallery_thumbnail f86f -gamepad e30f -games e30f -garage f011 -garage_check f28d -garage_door e714 -garage_home e82d -garage_money f28c -garden_cart f8a9 -gas_meter ec19 -gastroenterology e0f1 -gate e277 -gavel e90e -general_device e6de -generating_tokens e749 -genetics e0f3 -genres e6ee -gesture e155 -gesture_select f657 -get_app f090 -gif e908 -gif_2 f40e -gif_box e7a3 -girl eb68 -gite e58b -glass_cup f6e3 -globe e64c -globe_asia f799 -globe_book f3c9 -globe_location_pin f35d -globe_uk f798 -glucose e4a0 -glyphs f8a3 -go_to_line f71d -golf_course eb45 -gondola_lift f476 -google_home_devices e715 -google_plus_reshare f57a -google_tv_remote f5db -google_wifi f579 -gpp_bad f012 -gpp_good f013 -gpp_maybe f014 -gps_fixed e55c -gps_not_fixed e1b7 -gps_off e1b6 -grade f09a -gradient e3e9 -grading ea4f -grain e3ea -graph_1 f3a0 -graph_2 f39f -graph_3 f39e -graph_4 f39d -graph_5 f39c -graph_6 f39b -graph_7 f346 -graphic_eq e1b8 -grass f205 -grid_3x3 f015 -grid_3x3_off f67c -grid_4x4 f016 -grid_goldenratio f017 -grid_guides f76f -grid_off e3eb -grid_on e3ec -grid_view e9b0 -grocery ef97 -group ea21 -group_add e7f0 -group_off e747 -group_remove e7ad -group_search f3ce -group_work e886 -grouped_bar_chart f211 -groups f233 -groups_2 f8df -groups_3 f8e0 -guardian f4c1 -gynecology e0f4 -h_mobiledata f018 -h_mobiledata_badge f7e0 -h_plus_mobiledata f019 -h_plus_mobiledata_badge f7df -hail e9b1 -hallway e6f8 -hanami_dango f23f -hand_bones f894 -hand_gesture ef9c -hand_gesture_off f3f3 -hand_meal f294 -hand_package f293 -handheld_controller f4c6 -handshake ebcb -handwriting_recognition eb02 -handyman f10b -hangout_video e0c1 -hangout_video_off e0c2 -hard_disk f3da -hard_drive f80e -hard_drive_2 f7a4 -hardware ea59 -hd e052 -hdr_auto f01a -hdr_auto_select f01b -hdr_enhanced_select ef51 -hdr_off e3ed -hdr_off_select f01c -hdr_on e3ee -hdr_on_select f01d -hdr_plus f01e -hdr_plus_off e3ef -hdr_strong e3f1 -hdr_weak e3f2 -head_mounted_device f4c5 -headphones f01f -headphones_battery f020 -headset f01f -headset_mic e311 -headset_off e33a -healing e3f3 -health_and_beauty ef9d -health_and_safety e1d5 -health_cross f2c3 -health_metrics f6e2 -heap_snapshot_large f76e -heap_snapshot_multiple f76d -heap_snapshot_thumbnail f76c -hearing e023 -hearing_aid f464 -hearing_aid_disabled f3b0 -hearing_aid_disabled_left f2ec -hearing_aid_left f2ed -hearing_disabled f104 -heart_broken eac2 -heart_check f60a -heart_minus f883 -heart_plus f884 -heart_smile f292 -heat f537 -heat_pump ec18 -heat_pump_balance e27e -height ea16 -helicopter f60c -help e8fd -help_center f1c0 -help_clinic f810 -help_outline e8fd -hematology e0f6 -hevc f021 -hexagon eb39 -hide ef9e -hide_image f022 -hide_source f023 -high_chair f29a -high_density f79c -high_quality e024 -high_res f54b -highlight e25f -highlight_alt ef52 -highlight_keyboard_focus f510 -highlight_mouse_cursor f511 -highlight_off e888 -highlight_text_cursor f512 -highlighter_size_1 f76b -highlighter_size_2 f76a -highlighter_size_3 f769 -highlighter_size_4 f768 -highlighter_size_5 f767 -hiking e50a -history e8b3 -history_2 f3e6 -history_edu ea3e -history_off f4da -history_toggle_off f17d -hive eaa6 -hls eb8a -hls_off eb8c -holiday_village e58a -home e9b2 -home_and_garden ef9f -home_app_logo e295 -home_filled e9b2 -home_health e4b9 -home_improvement_and_tools efa0 -home_iot_device e283 -home_max f024 -home_max_dots e849 -home_mini f025 -home_pin f14d -home_repair_service f100 -home_speaker f11c -home_storage f86c -home_work f030 -horizontal_distribute e014 -horizontal_rule f108 -horizontal_split e947 -host f3d9 -hot_tub eb46 -hotel e549 -hotel_class e743 -hourglass ebff -hourglass_arrow_down f37e -hourglass_arrow_up f37d -hourglass_bottom ea5c -hourglass_disabled ef53 -hourglass_empty e88b -hourglass_full e88c -hourglass_pause f38c -hourglass_top ea5b -house ea44 -house_siding f202 -house_with_shield e786 -houseboat e584 -household_supplies efa1 -hov f475 -how_to_reg e174 -how_to_vote e175 -hr_resting f6ba -html eb7e -http e902 -https e899 -hub e9f4 -humerus f895 -humerus_alt f896 -humidity_high f163 -humidity_indoor f558 -humidity_low f164 -humidity_mid f165 -humidity_percentage f87e -hvac f10e -hvac_max_defrost f332 -ice_skating e50b -icecream ea69 -id_card f4ca -identity_aware_proxy e2dd -identity_platform ebb7 -ifl e025 -iframe f71b -iframe_off f71c -image e3f4 -image_arrow_up f317 -image_aspect_ratio e3f5 -image_inset f247 -image_not_supported f116 -image_search e43f -imagesearch_roller e9b4 -imagesmode efa2 -immunology e0fb -import_contacts e0e0 -import_export e8d5 -important_devices e912 -in_home_mode e833 -inactive_order e0fc -inbox e156 -inbox_customize f859 -inbox_text f399 -inbox_text_asterisk f360 -inbox_text_person f35e -inbox_text_share f35c -incomplete_circle e79b -indeterminate_check_box e909 -indeterminate_question_box f56d -info e88e -info_i f59b -infrared f87c -ink_eraser e6d0 -ink_eraser_off e7e3 -ink_highlighter e6d1 -ink_highlighter_move f524 -ink_marker e6d2 -ink_pen e6d3 -ink_selection ef52 -inpatient e0fe -input e890 -input_circle f71a -insert_chart f0cc -insert_chart_filled f0cc -insert_chart_outlined f0cc -insert_comment e24c -insert_drive_file e66d -insert_emoticon ea22 -insert_invitation e878 -insert_link e250 -insert_page_break eaca -insert_photo e3f4 -insert_text f827 -insights f092 -install_desktop eb71 -install_mobile f2cd -instant_mix e026 -integration_instructions ef54 -interactive_space f7ff -interests e7c8 -interpreter_mode e83b -inventory e179 -inventory_2 e1a1 -invert_colors e891 -invert_colors_off e0c4 -ios e027 -ios_share e6b8 -iron e583 -iso e3f6 -jamboard_kiosk e9b5 -japanese_curry f284 -japanese_flag f283 -javascript eb7c -join f84f -join_full f84f -join_inner eaf4 -join_left eaf2 -join_right eaea -joystick f5ee -jump_to_element f719 -kanji_alcohol f23e -kayaking e50c -kebab_dining e842 -keep f026 -keep_off e6f9 -keep_pin f026 -keep_public f56f -kettle e2b9 -key e73c -key_off eb84 -key_vertical f51a -key_visualizer f199 -keyboard e312 -keyboard_alt f028 -keyboard_arrow_down e313 -keyboard_arrow_left e314 -keyboard_arrow_right e315 -keyboard_arrow_up e316 -keyboard_backspace e317 -keyboard_capslock e318 -keyboard_capslock_badge f7de -keyboard_command_key eae7 -keyboard_control_key eae6 -keyboard_double_arrow_down ead0 -keyboard_double_arrow_left eac3 -keyboard_double_arrow_right eac9 -keyboard_double_arrow_up eacf -keyboard_external_input f7dd -keyboard_full f7dc -keyboard_hide e31a -keyboard_keys f67b -keyboard_lock f492 -keyboard_lock_off f491 -keyboard_off f67a -keyboard_onscreen f7db -keyboard_option_key eae8 -keyboard_previous_language f7da -keyboard_return e31b -keyboard_tab e31c -keyboard_tab_rtl ec73 -keyboard_voice e31d -kid_star f526 -king_bed ea45 -kitchen eb47 -kitesurfing e50d -lab_panel e103 -lab_profile e104 -lab_research f80b -label e893 -label_important e948 -label_important_outline e948 -label_off e9b6 -label_outline e893 -labs e105 -lan eb2f -landscape e564 -landscape_2 f4c4 -landscape_2_edit f310 -landscape_2_off f4c3 -landslide ebd7 -language e894 -language_chinese_array f766 -language_chinese_cangjie f765 -language_chinese_dayi f764 -language_chinese_pinyin f763 -language_chinese_quick f762 -language_chinese_wubi f761 -language_french f760 -language_gb_english f75f -language_international f75e -language_japanese_kana f513 -language_korean_latin f75d -language_pinyin f75c -language_spanish f5e9 -language_us f759 -language_us_colemak f75b -language_us_dvorak f75a -laps f6b9 -laptop e31e -laptop_car f3cd -laptop_chromebook e31f -laptop_mac e320 -laptop_windows e321 -lasso_select eb03 -last_page e5dd -launch e89e -laundry e2a8 -layers e53b -layers_clear e53c -lda e106 -leaderboard f20c -leak_add e3f8 -leak_remove e3f9 -left_click f718 -left_panel_close f717 -left_panel_open f716 -legend_toggle f11b -lens e3fa -lens_blur f029 -letter_switch f758 -library_add e03c -library_add_check e9b7 -library_books e02f -library_music e030 -license eb04 -lift_to_talk efa3 -light f02a -light_group e28b -light_mode e518 -light_off e9b8 -lightbulb e90f -lightbulb_2 f3e3 -lightbulb_circle ebfe -lightbulb_outline e90f -lightning_stand efa4 -line_axis ea9a -line_curve f757 -line_end f826 -line_end_arrow f81d -line_end_arrow_notch f81c -line_end_circle f81b -line_end_diamond f81a -line_end_square f819 -line_start f825 -line_start_arrow f818 -line_start_arrow_notch f817 -line_start_circle f816 -line_start_diamond f815 -line_start_square f814 -line_style e919 -line_weight e91a -linear_scale e260 -link e250 -link_off e16f -linked_camera e438 -linked_services f535 -liquor ea60 -list e896 -list_alt e0ee -list_alt_add f756 -list_alt_check f3de -lists e9b9 -live_help e0c6 -live_tv e63a -living f02b -local_activity e553 -local_airport e53d -local_atm e53e -local_bar e540 -local_cafe eb44 -local_car_wash e542 -local_convenience_store e543 -local_dining e561 -local_drink e544 -local_fire_department ef55 -local_florist e545 -local_gas_station e546 -local_grocery_store e8cc -local_hospital e548 -local_hotel e549 -local_laundry_service e54a -local_library e54b -local_mall e54c -local_movies e8da -local_offer f05b -local_parking e54f -local_pharmacy e550 -local_phone f0d4 -local_pizza e552 -local_play e553 -local_police ef56 -local_post_office e554 -local_printshop e8ad -local_see e557 -local_shipping e558 -local_taxi e559 -location_automation f14f -location_away f150 -location_chip f850 -location_city e7f1 -location_disabled e1b6 -location_home f152 -location_off e0c7 -location_on f1db -location_pin f1db -location_searching e1b7 -locator_tag f8c1 -lock e899 -lock_clock ef57 -lock_open e898 -lock_open_circle f361 -lock_open_right f656 -lock_outline e899 -lock_person f8f3 -lock_reset eade -login ea77 -logo_dev ead6 -logout e9ba -looks e3fc -looks_3 e3fb -looks_4 e3fd -looks_5 e3fe -looks_6 e3ff -looks_one e400 -looks_two e401 -loop e863 -loupe e402 -low_density f79b -low_priority e16d -lowercase f48a -loyalty e89a -lte_mobiledata f02c -lte_mobiledata_badge f7d9 -lte_plus_mobiledata f02d -lte_plus_mobiledata_badge f7d8 -luggage f235 -lunch_dining ea61 -lyrics ec0b -macro_auto f6f2 -macro_off f8d2 -magic_button f136 -magic_exchange f7f4 -magic_tether f7d7 -magnification_large f83d -magnification_small f83c -magnify_docked f7d6 -magnify_fullscreen f7d5 -mail e159 -mail_asterisk eef4 -mail_lock ec0a -mail_off f48b -mail_outline e159 -mail_shield f249 -male e58e -man e4eb -man_2 f8e1 -man_3 f8e2 -man_4 f8e3 -manage_accounts f02e -manage_history ebe7 -manage_search f02f -manga f5e3 -manufacturing e726 -map e55b -map_pin_heart f298 -map_pin_review f297 -map_search f3ca -maps_home_work f030 -maps_ugc ef58 -margin e9bb -mark_as_unread e9bc -mark_chat_read f18b -mark_chat_unread f189 -mark_email_read f18c -mark_email_unread f18a -mark_unread_chat_alt eb9d -markdown f552 -markdown_copy f553 -markdown_paste f554 -markunread e159 -markunread_mailbox e89b -masked_transitions e72e -masked_transitions_add f42b -masks f218 -massage f2c2 -match_case f6f1 -match_case_off f36f -match_word f6f0 -matter e907 -maximize e930 -meal_dinner f23d -meal_lunch f23c -measuring_tape f6af -media_bluetooth_off f031 -media_bluetooth_on f032 -media_link f83f -media_output f4f2 -media_output_off f4f3 -mediation efa7 -medical_information ebed -medical_mask f80a -medical_services f109 -medication f033 -medication_liquid ea87 -meeting_room eb4f -memory e322 -memory_alt f7a3 -menstrual_health f6e1 -menu e5d2 -menu_book ea19 -menu_book_2 f291 -menu_open e9bd -merge eb98 -merge_type e252 -message e0c9 -metabolism e10b -metro f474 -mfg_nest_yale_lock f11d -mic e31d -mic_alert f392 -mic_double f5d1 -mic_external_off ef59 -mic_external_on ef5a -mic_none e31d -mic_off e02b -microbiology e10c -microwave f204 -microwave_gen e847 -military_tech ea3f -mimo e9be -mimo_disconnect e9bf -mindfulness f6e0 -minimize e931 -minor_crash ebf1 -mintmark efa9 -missed_video_call f0ce -missed_video_call_filled f0ce -missing_controller e701 -mist e188 -mitre f547 -mixture_med e4c8 -mms e618 -mobile e7ba -mobile_2 f2db -mobile_3 f2da -mobile_alert f2d3 -mobile_arrow_down f2cd -mobile_arrow_right f2d2 -mobile_arrow_up_right f2b9 -mobile_block f2e5 -mobile_camera f44e -mobile_camera_front f2c9 -mobile_camera_rear f2c8 -mobile_cancel f2ea -mobile_cast f2cc -mobile_charge f2e3 -mobile_chat f79f -mobile_check f073 -mobile_code f2e2 -mobile_dots f2d0 -mobile_friendly f073 -mobile_gear f2d9 -mobile_hand f323 -mobile_hand_left f313 -mobile_hand_left_off f312 -mobile_hand_off f314 -mobile_info f2dc -mobile_landscape ed3e -mobile_layout f2bf -mobile_lock_landscape f2d8 -mobile_lock_portrait f2be -mobile_loupe f322 -mobile_menu f2d1 -mobile_off e201 -mobile_question f2e1 -mobile_rotate f2d5 -mobile_rotate_lock f2d6 -mobile_screen_share f2df -mobile_screensaver f321 -mobile_sensor_hi f2ef -mobile_sensor_lo f2ee -mobile_share f2df -mobile_share_stack f2de -mobile_sound f2e8 -mobile_sound_2 f318 -mobile_sound_off f7aa -mobile_speaker f320 -mobile_text f2eb -mobile_text_2 f2e6 -mobile_theft f2a9 -mobile_ticket f2e4 -mobile_vibrate f2cb -mobile_wrench f2b0 -mobiledata_off f034 -mode f097 -mode_comment e253 -mode_cool f166 -mode_cool_off f167 -mode_dual f557 -mode_edit f097 -mode_edit_outline f097 -mode_fan f168 -mode_fan_off ec17 -mode_heat f16a -mode_heat_cool f16b -mode_heat_off f16d -mode_night f036 -mode_of_travel e7ce -mode_off_on f16f -mode_standby f037 -model_training f0cf -modeling f3aa -monetization_on e263 -money e57d -money_bag f3ee -money_off f038 -money_off_csred f038 -money_range f245 -monitor ef5b -monitor_heart eaa2 -monitor_weight f039 -monitor_weight_gain f6df -monitor_weight_loss f6de -monitoring f190 -monochrome_photos e403 -monorail f473 -mood ea22 -mood_bad e7f3 -moon_stars f34f -mop e28d -moped eb28 -moped_package f28b -more e619 -more_down f196 -more_horiz e5d3 -more_time ea5d -more_up f197 -more_vert e5d4 -mosque eab2 -motion_blur f0d0 -motion_mode f842 -motion_photos_auto f03a -motion_photos_off e9c0 -motion_photos_on e9c1 -motion_photos_pause f227 -motion_photos_paused f227 -motion_play f40b -motion_sensor_active e792 -motion_sensor_alert e784 -motion_sensor_idle e783 -motion_sensor_urgent e78e -motorcycle e91b -mountain_flag f5e2 -mountain_steam f282 -mouse e323 -mouse_lock f490 -mouse_lock_off f48f -move e740 -move_down eb61 -move_group f715 -move_item f1ff -move_location e741 -move_selection_down f714 -move_selection_left f713 -move_selection_right f712 -move_selection_up f711 -move_to_inbox e168 -move_up eb64 -moved_location e594 -movie e404 -movie_creation e404 -movie_edit f840 -movie_filter e43a -movie_info e02d -movie_off f499 -movie_speaker f2a3 -moving e501 -moving_beds e73d -moving_ministry e73e -mp e9c3 -multicooker e293 -multiline_chart e6df -multimodal_hand_eye f41b -multiple_airports efab -multiple_stop f1b9 -museum ea36 -music_cast eb1a -music_history f2c1 -music_note e405 -music_note_add f391 -music_off e440 -music_video e063 -my_location e55c -mystery f5e1 -nat ef5c -nature e406 -nature_people e407 -navigate_before e5cb -navigate_next e5cc -navigation e55d -near_me e569 -near_me_disabled f1ef -nearby e6b7 -nearby_error f03b -nearby_off f03c -nephrology e10d -nest_audio ebbf -nest_cam_floodlight f8b7 -nest_cam_indoor f11e -nest_cam_iq f11f -nest_cam_iq_outdoor f120 -nest_cam_magnet_mount f8b8 -nest_cam_outdoor f121 -nest_cam_stand f8b9 -nest_cam_wall_mount f8ba -nest_cam_wired_stand ec16 -nest_clock_farsight_analog f8bb -nest_clock_farsight_digital f8bc -nest_connect f122 -nest_detect f123 -nest_display f124 -nest_display_max f125 -nest_doorbell_visitor f8bd -nest_eco_leaf f8be -nest_farsight_cool f27d -nest_farsight_dual f27c -nest_farsight_eco f27b -nest_farsight_heat f27a -nest_farsight_seasonal f279 -nest_farsight_weather f8bf -nest_found_savings f8c0 -nest_gale_wifi f579 -nest_heat_link_e f126 -nest_heat_link_gen_3 f127 -nest_hello_doorbell e82c -nest_locator_tag f8c1 -nest_mini e789 -nest_multi_room f8c2 -nest_protect e68e -nest_remote f5db -nest_remote_comfort_sensor f12a -nest_secure_alarm f12b -nest_sunblock f8c3 -nest_tag f8c1 -nest_thermostat e68f -nest_thermostat_e_eu f12d -nest_thermostat_gen_3 f12e -nest_thermostat_sensor f12f -nest_thermostat_sensor_eu f130 -nest_thermostat_zirconium_eu f131 -nest_true_radiant f8c4 -nest_wake_on_approach f8c5 -nest_wake_on_press f8c6 -nest_wifi_gale f132 -nest_wifi_mistral f133 -nest_wifi_point f134 -nest_wifi_point_vento f134 -nest_wifi_pro f56b -nest_wifi_pro_2 f56a -nest_wifi_router f133 -network_cell e1b9 -network_check e640 -network_intel_node f371 -network_intelligence efac -network_intelligence_history f5f6 -network_intelligence_update f5f5 -network_locked e61a -network_manage f7ab -network_node f56e -network_ping ebca -network_wifi e1ba -network_wifi_1_bar ebe4 -network_wifi_1_bar_locked f58f -network_wifi_2_bar ebd6 -network_wifi_2_bar_locked f58e -network_wifi_3_bar ebe1 -network_wifi_3_bar_locked f58d -network_wifi_locked f532 -neurology e10e -new_label e609 -new_releases ef76 -new_window f710 -news e032 -newsmode efad -newspaper eb81 -newsstand e9c4 -next_plan ef5d -next_week e16a -nfc e1bb -nfc_off f369 -night_shelter f1f1 -night_sight_auto f1d7 -night_sight_auto_off f1f9 -night_sight_max f6c3 -nightlife ea62 -nightlight f03d -nightlight_round f03d -nights_stay f174 -no_accounts f03e -no_adult_content f8fe -no_backpack f237 -no_crash ebf0 -no_drinks f1a5 -no_encryption f03f -no_encryption_gmailerrorred f03f -no_flash f1a6 -no_food f1a7 -no_luggage f23b -no_meals f1d6 -no_meeting_room eb4e -no_photography f1a8 -no_sim e1ce -no_sound e710 -no_stroller f1af -no_transfer f1d5 -noise_aware ebec -noise_control_off ebf3 -noise_control_on f8a8 -nordic_walking e50e -north f1e0 -north_east f1e1 -north_west f1e2 -not_accessible f0fe -not_accessible_forward f54a -not_interested f08c -not_listed_location e575 -not_started f0d1 -note e66d -note_add e89c -note_alt f040 -note_stack f562 -note_stack_add f563 -notes e26c -notification_add e399 -notification_important e004 -notification_multiple e6c2 -notification_settings f367 -notification_sound f353 -notifications e7f5 -notifications_active e7f7 -notifications_none e7f5 -notifications_off e7f6 -notifications_paused e7f8 -notifications_unread f4fe -numbers eac7 -nutrition e110 -ods e6e8 -odt e6e9 -offline_bolt e932 -offline_pin e90a -offline_pin_off f4d0 -offline_share f2de -oil_barrel ec15 -okonomiyaki f281 -on_device_training ebfd -on_hub_device e6c3 -oncology e114 -ondemand_video e63a -online_prediction f0eb -onsen f6f8 -opacity e91c -open_in_browser e89d -open_in_full f1ce -open_in_new e89e -open_in_new_down f70f -open_in_new_off e4f6 -open_in_phone f2d2 -open_jam efae -open_run f4b7 -open_with e89f -ophthalmology e115 -oral_disease e116 -orbit f426 -order_approve f812 -order_play f811 -orders eb14 -orthopedics f897 -other_admission e47b -other_houses e58c -outbound e1ca -outbox ef5f -outbox_alt eb17 -outdoor_garden e205 -outdoor_grill ea47 -outgoing_mail f0d2 -outlet f1d4 -outlined_flag f0c6 -outpatient e118 -outpatient_med e119 -output ebbe -output_circle f70e -oven e9c7 -oven_gen e843 -overview e4a7 -overview_key f7d4 -owl f3b4 -oxygen_saturation e4de -p2p f52a -pace f6b8 -pacemaker e656 -package e48f -package_2 f569 -padding e9c8 -padel f2a7 -page_control e731 -page_footer f383 -page_header f384 -page_info f614 -page_menu_ios eefb -pageless f509 -pages e7f9 -pageview e8a0 -paid f041 -palette e40a -pallet f86a -pan_tool e925 -pan_tool_alt ebb9 -pan_zoom f655 -panorama e40b -panorama_fish_eye e40c -panorama_horizontal e40d -panorama_photosphere e9c9 -panorama_vertical e40e -panorama_wide_angle e40f -paragliding e50f -parent_child_dining f22d -park ea63 -parking_meter f28a -parking_sign f289 -parking_valet f288 -partly_cloudy_day f172 -partly_cloudy_night f174 -partner_exchange f7f9 -partner_heart ef2e -partner_reports efaf -party_mode e7fa -passkey f87f -password f042 -password_2 f4a9 -password_2_off f4a8 -patient_list e653 -pattern f043 -pause e034 -pause_circle e1a2 -pause_circle_filled e1a2 -pause_circle_outline e1a2 -pause_presentation e0ea -payment e8a1 -payment_arrow_down f2c0 -payment_card f2a1 -payments ef63 -pedal_bike eb29 -pediatrics e11d -pen_size_1 f755 -pen_size_2 f754 -pen_size_3 f753 -pen_size_4 f752 -pen_size_5 f751 -pending ef64 -pending_actions f1bb -pentagon eb50 -people ea21 -people_alt ea21 -people_outline ea21 -percent eb58 -percent_discount f244 -performance_max e51a -pergola e203 -perm_camera_mic e8a2 -perm_contact_calendar e8a3 -perm_data_setting e8a4 -perm_device_information f2dc -perm_identity f0d3 -perm_media e8a7 -perm_phone_msg e8a8 -perm_scan_wifi e8a9 -person f0d3 -person_2 f8e4 -person_3 f8e5 -person_4 f8e6 -person_add ea4d -person_add_alt ea4d -person_add_disabled e9cb -person_alert f567 -person_apron f5a3 -person_book f5e8 -person_cancel f566 -person_celebrate f7fe -person_check f565 -person_edit f4fa -person_filled f0d3 -person_heart f290 -person_off e510 -person_outline f0d3 -person_pin e55a -person_pin_circle e56a -person_play f7fd -person_raised_hand f59a -person_remove ef66 -person_search f106 -person_shield e384 -personal_bag eb0e -personal_bag_off eb0f -personal_bag_question eb10 -personal_injury e6da -personal_places e703 -personal_video e63b -pest_control f0fa -pest_control_rodent f0fd -pet_supplies efb1 -pets e91d -phishing ead7 -phone f0d4 -phone_alt f0d4 -phone_android f2db -phone_bluetooth_speaker e61b -phone_callback e649 -phone_disabled e9cc -phone_enabled e9cd -phone_forwarded e61c -phone_in_talk e61d -phone_iphone f2da -phone_locked e61e -phone_missed e61f -phone_paused e620 -phonelink e326 -phonelink_erase f2ea -phonelink_lock f2be -phonelink_off f7a5 -phonelink_ring f2e8 -phonelink_ring_off f7aa -phonelink_setup f2d9 -photo e432 -photo_album e411 -photo_auto_merge f530 -photo_camera e412 -photo_camera_back ef68 -photo_camera_front ef69 -photo_filter e43b -photo_frame f0d9 -photo_library e413 -photo_prints efb2 -photo_size_select_actual e432 -photo_size_select_large e433 -photo_size_select_small e434 -php eb8f -physical_therapy e11e -piano e521 -piano_off e520 -pickleball f2a6 -picture_as_pdf e415 -picture_in_picture e8aa -picture_in_picture_alt e911 -picture_in_picture_center f550 -picture_in_picture_large f54f -picture_in_picture_medium f54e -picture_in_picture_mobile f517 -picture_in_picture_off f52f -picture_in_picture_small f54d -pie_chart f0da -pie_chart_filled f0da -pie_chart_outline f0da -pie_chart_outlined f0da -pill e11f -pill_off f809 -pin f045 -pin_drop e55e -pin_end e767 -pin_invoke e763 -pinboard f3ab -pinboard_unread f3ac -pinch eb38 -pinch_zoom_in f1fa -pinch_zoom_out f1fb -pip f64d -pip_exit f70d -pivot_table_chart e9ce -place f1db -place_item f1f0 -plagiarism ea5a -plane_contrails f2ac -planet f387 -planner_banner_ad_pt e692 -planner_review e694 -play_arrow e037 -play_circle e1c4 -play_disabled ef6a -play_for_work e906 -play_lesson f047 -play_music e6ee -play_pause f137 -play_shapes f7fc -playground f28e -playground_2 f28f -playing_cards f5dc -playlist_add e03b -playlist_add_check e065 -playlist_add_check_circle e7e6 -playlist_add_circle e7e5 -playlist_play e05f -playlist_remove eb80 -plug_connect f35a -plumbing f107 -plus_one e800 -podcasts f048 -podiatry e120 -podium f7fb -point_of_sale f17e -point_scan f70c -poker_chip f49b -policy ea17 -policy_alert f407 -poll f0cc -polyline ebbb -polymer e8ab -pool eb48 -portable_wifi_off f087 -portrait e851 -position_bottom_left f70b -position_bottom_right f70a -position_top_right f709 -post e705 -post_add ea20 -potted_plant f8aa -power e63c -power_input e336 -power_off e646 -power_rounded f8c7 -power_settings_circle f418 -power_settings_new f8c7 -prayer_times f838 -precision_manufacturing f049 -pregnancy f5f1 -pregnant_woman f5f1 -preliminary e7d8 -prescriptions e121 -present_to_all e0df -preview f1c5 -preview_off f7af -price_change f04a -price_check f04b -print e8ad -print_add f7a2 -print_connect f7a1 -print_disabled e9cf -print_error f7a0 -print_lock f651 -priority e19f -priority_high e645 -privacy f148 -privacy_tip f0dc -private_connectivity e744 -problem e122 -procedure e651 -process_chart f855 -production_quantity_limits e1d1 -productivity e296 -progress_activity e9d0 -prompt_suggestion f4f6 -propane ec14 -propane_tank ec13 -psychiatry e123 -psychology ea4a -psychology_alt f8ea -public e80b -public_off f1ca -publish e255 -published_with_changes f232 -pulmonology e124 -pulse_alert f501 -punch_clock eaa8 -push_pin f10d -qr_code ef6b -qr_code_2 e00a -qr_code_2_add f658 -qr_code_scanner f206 -query_builder efd6 -query_stats e4fc -question_answer e8af -question_exchange f7f3 -question_mark eb8b -queue e03c -queue_music e03d -queue_play_next e066 -quick_phrases e7d1 -quick_reference e46e -quick_reference_all f801 -quick_reorder eb15 -quickreply ef6c -quiet_time f159 -quiet_time_active eb76 -quiz f04c -r_mobiledata f04d -radar f04e -radio e03e -radio_button_checked e837 -radio_button_partial f560 -radio_button_unchecked e836 -radiology e125 -railway_alert e9d1 -railway_alert_2 f461 -rainy f176 -rainy_heavy f61f -rainy_light f61e -rainy_snow f61d -ramen_dining ea64 -ramp_left eb9c -ramp_right eb96 -range_hood e1ea -rate_review e560 -rate_review_rtl e706 -raven f555 -raw_off f04f -raw_on f050 -read_more ef6d -readiness_score f6dd -real_estate_agent e73a -rear_camera f6c2 -rebase f845 -rebase_edit f846 -receipt e8b0 -receipt_long ef6e -receipt_long_off f40a -recent_actors e03f -recent_patient f808 -recenter f4c0 -recommend e9d2 -record_voice_over e91f -rectangle eb54 -recycling e760 -redeem e8f6 -redo e15a -reduce_capacity f21c -refresh e5d5 -regular_expression f750 -relax f6dc -release_alert f654 -remember_me f051 -reminder e6c6 -reminders_alt e6c6 -remote_gen e83e -remove e15b -remove_circle f08f -remove_circle_outline f08f -remove_done e9d3 -remove_from_queue e067 -remove_moderator e9d4 -remove_red_eye e8f4 -remove_road ebfc -remove_selection e9d5 -remove_shopping_cart e928 -reopen_window f708 -reorder e8fe -repartition f8e8 -repeat e040 -repeat_on e9d6 -repeat_one e041 -repeat_one_on e9d7 -replace_audio f451 -replace_image f450 -replace_video f44f -replay e042 -replay_10 e059 -replay_30 e05a -replay_5 e05b -replay_circle_filled e9d8 -reply e15e -reply_all e15f -report f052 -report_gmailerrorred f052 -report_off e170 -report_problem f083 -request_page f22c -request_quote f1b6 -reset_brightness f482 -reset_exposure f266 -reset_focus f481 -reset_image f824 -reset_iso f480 -reset_settings f47f -reset_shadow f47e -reset_shutter_speed f47d -reset_tv e9d9 -reset_white_balance f47c -reset_wrench f56c -resize f707 -respiratory_rate e127 -responsive_layout e9da -rest_area f22a -restart_alt f053 -restaurant e56c -restaurant_menu e561 -restore e8b3 -restore_from_trash e938 -restore_page e929 -resume f7d0 -reviews f07c -rewarded_ads efb6 -rheumatology e128 -rib_cage f898 -rice_bowl f1f5 -right_click f706 -right_panel_close f705 -right_panel_open f704 -ring_volume f0dd -ring_volume_filled f0dd -ripples e9db -road f472 -robot f882 -robot_2 f5d0 -rocket eba5 -rocket_launch eb9b -roller_shades ec12 -roller_shades_closed ec11 -roller_skating ebcd -roofing f201 -room f1db -room_preferences f1b8 -room_service eb49 -rotate_90_degrees_ccw e418 -rotate_90_degrees_cw eaab -rotate_auto f417 -rotate_left e419 -rotate_right e41a -roundabout_left eb99 -roundabout_right eba3 -rounded_corner e920 -route eacd -router e328 -router_off f2f4 -routine e20c -rowing e921 -rss_feed e0e5 -rsvp f055 -rtt e9ad -rubric eb27 -rule f1c2 -rule_folder f1c9 -rule_settings f64c -run_circle ef6f -running_with_errors e51d -rv_hookup e642 -safety_check ebef -safety_check_off f59d -safety_divider e1cc -sailing e502 -salinity f876 -sanitizer f21d -satellite e562 -satellite_alt eb3a -sauna f6f7 -save e161 -save_alt f090 -save_as eb60 -save_clock f398 -saved_search ea11 -savings e2eb -scale eb5f -scan f74e -scan_delete f74f -scanner e329 -scatter_plot e268 -scene e2a7 -schedule efd6 -schedule_send ea0a -schema e4fd -school e80c -science ea4b -science_off f542 -scooter f471 -score e269 -scoreboard ebd0 -screen_lock_landscape f2d8 -screen_lock_portrait f2be -screen_lock_rotation f2d6 -screen_record f679 -screen_rotation f2d5 -screen_rotation_alt ebee -screen_rotation_up f678 -screen_search_desktop ef70 -screen_share e0e2 -screenshot f056 -screenshot_frame f677 -screenshot_frame_2 f374 -screenshot_keyboard f7d3 -screenshot_monitor ec08 -screenshot_region f7d2 -screenshot_tablet f697 -script f45f -scrollable_header e9dc -scuba_diving ebce -sd e9dd -sd_card e623 -sd_card_alert f057 -sd_storage e623 -sdk e720 -search e8b6 -search_activity f3e5 -search_check f800 -search_check_2 f469 -search_gear eefa -search_hands_free e696 -search_insights f4bc -search_off ea76 -seat_cool_left f331 -seat_cool_right f330 -seat_heat_left f32f -seat_heat_right f32e -seat_vent_left f32d -seat_vent_right f32c -security e32a -security_key f503 -security_update f2cd -security_update_good f073 -security_update_warning f2d3 -segment e94b -select f74d -select_all e162 -select_check_box f1fe -select_to_speak f7cf -select_window e6fa -select_window_2 f4c8 -select_window_off e506 -self_care f86d -self_improvement ea78 -sell f05b -send e163 -send_and_archive ea0c -send_money e8b7 -send_time_extension eadb -send_to_mobile f2d2 -sensor_door f1b5 -sensor_occupied ec10 -sensor_window f1b4 -sensors e51e -sensors_krx f556 -sensors_krx_off f515 -sensors_off e51f -sentiment_calm f6a7 -sentiment_content f6a6 -sentiment_dissatisfied e811 -sentiment_excited f6a5 -sentiment_extremely_dissatisfied f194 -sentiment_frustrated f6a4 -sentiment_neutral e812 -sentiment_sad f6a3 -sentiment_satisfied e813 -sentiment_satisfied_alt e813 -sentiment_stressed f6a2 -sentiment_very_dissatisfied e814 -sentiment_very_satisfied e815 -sentiment_worried f6a1 -serif f4ac -server_person f3bd -service_toolbox e717 -set_meal f1ea -settings e8b8 -settings_accessibility f05d -settings_account_box f835 -settings_alert f143 -settings_applications e8b9 -settings_b_roll f625 -settings_backup_restore e8ba -settings_bluetooth e8bb -settings_brightness e8bd -settings_cell f2d1 -settings_cinematic_blur f624 -settings_ethernet e8be -settings_heart f522 -settings_input_antenna e8bf -settings_input_component e8c1 -settings_input_composite e8c1 -settings_input_hdmi e8c2 -settings_input_svideo e8c3 -settings_motion_mode f833 -settings_night_sight f832 -settings_overscan e8c4 -settings_panorama f831 -settings_phone e8c5 -settings_photo_camera f834 -settings_power e8c6 -settings_remote e8c7 -settings_seating ef2d -settings_slow_motion f623 -settings_suggest f05e -settings_system_daydream e1c3 -settings_timelapse f622 -settings_video_camera f621 -settings_voice e8c8 -settop_component e2ac -severe_cold ebd3 -shadow e9df -shadow_add f584 -shadow_minus f583 -shape_line f8d3 -shape_recognition eb01 -shapes e602 -share e80d -share_eta e5f7 -share_location f05f -share_off f6cb -share_reviews f8a4 -share_windows f613 -shaved_ice f225 -sheets_rtl f823 -shelf_auto_hide f703 -shelf_position f702 -shelves f86e -shield e9e0 -shield_lock f686 -shield_locked f592 -shield_moon eaa9 -shield_person f650 -shield_question f529 -shield_toggle f2ad -shield_watch f30f -shield_with_heart e78f -shield_with_house e78d -shift e5f2 -shift_lock f7ae -shift_lock_off f483 -shop e8c9 -shop_2 e8ca -shop_two e8ca -shopping_bag f1cc -shopping_bag_speed f39a -shopping_basket e8cb -shopping_cart e8cc -shopping_cart_checkout eb88 -shopping_cart_off f4f7 -shoppingmode efb7 -short_stay e4d0 -short_text e261 -shortcut f57a -show_chart e6e1 -shower f061 -shuffle e043 -shuffle_on e9e1 -shutter_speed e43d -shutter_speed_add f57e -shutter_speed_minus f57d -sick f220 -side_navigation e9e2 -sign_language ebe5 -sign_language_2 f258 -signal_cellular_0_bar f0a8 -signal_cellular_1_bar f0a9 -signal_cellular_2_bar f0aa -signal_cellular_3_bar f0ab -signal_cellular_4_bar e1c8 -signal_cellular_add f7a9 -signal_cellular_alt e202 -signal_cellular_alt_1_bar ebdf -signal_cellular_alt_2_bar ebe3 -signal_cellular_connected_no_internet_0_bar f0ac -signal_cellular_connected_no_internet_4_bar e1cd -signal_cellular_no_sim e1ce -signal_cellular_nodata f062 -signal_cellular_null e1cf -signal_cellular_off e1d0 -signal_cellular_pause f5a7 -signal_disconnected f239 -signal_wifi_0_bar f0b0 -signal_wifi_4_bar f065 -signal_wifi_4_bar_lock e1e1 -signal_wifi_bad f064 -signal_wifi_connected_no_internet_4 f064 -signal_wifi_off e1da -signal_wifi_statusbar_4_bar f065 -signal_wifi_statusbar_not_connected f0ef -signal_wifi_statusbar_null f067 -signature f74c -signpost eb91 -sim_card e32b -sim_card_alert f057 -sim_card_download f068 -simulation f3e1 -single_bed ea48 -sip f069 -siren f3a7 -siren_check f3a6 -siren_open f3a5 -siren_question f3a4 -skateboarding e511 -skeleton f899 -skillet f543 -skillet_cooktop f544 -skip_next e044 -skip_previous e045 -skull f89a -skull_list f370 -slab_serif f4ab -sledding e512 -sleep e213 -sleep_score f6b7 -slide_library f822 -sliders e9e3 -slideshow e41b -slow_motion_video e068 -smart_button f1c1 -smart_card_reader f4a5 -smart_card_reader_off f4a6 -smart_display f06a -smart_outlet e844 -smart_screen f2d0 -smart_toy f06c -smartphone e7ba -smartphone_camera f44e -smb_share f74b -smoke_free eb4a -smoking_rooms eb4b -sms e625 -sms_failed e87f -snippet_folder f1c7 -snooze e046 -snowboarding e513 -snowing e80f -snowing_heavy f61c -snowmobile e503 -snowshoeing e514 -soap f1b2 -soba ef36 -social_distance e1cb -social_leaderboard f6a0 -solar_power ec0f -solo_dining ef35 -sort e164 -sort_by_alpha e053 -sos ebf7 -sound_detection_dog_barking f149 -sound_detection_glass_break f14a -sound_detection_loud_sound f14b -sound_sampler f6b4 -soup_kitchen e7d3 -source f1c8 -source_environment e527 -source_notes e12d -south f1e3 -south_america e7e4 -south_east f1e4 -south_west f1e5 -spa eb4c -space_bar e256 -space_dashboard e66b -spatial_audio ebeb -spatial_audio_off ebe8 -spatial_speaker f4cf -spatial_tracking ebea -speaker e32d -speaker_group e32e -speaker_notes e8cd -speaker_notes_off e92a -speaker_phone e0d2 -special_character f74a -specific_gravity f872 -speech_to_text f8a7 -speed e9e4 -speed_0_25 f4d4 -speed_0_2x f498 -speed_0_5 f4e2 -speed_0_5x f497 -speed_0_75 f4d3 -speed_0_7x f496 -speed_1_2 f4e1 -speed_1_25 f4d2 -speed_1_2x f495 -speed_1_5 f4e0 -speed_1_5x f494 -speed_1_75 f4d1 -speed_1_7x f493 -speed_2x f4eb -speed_camera f470 -spellcheck e8ce -split_scene f3bf -split_scene_down f2ff -split_scene_left f2fe -split_scene_right f2fd -split_scene_up f2fc -splitscreen f06d -splitscreen_add f4fd -splitscreen_bottom f676 -splitscreen_landscape f459 -splitscreen_left f675 -splitscreen_portrait f458 -splitscreen_right f674 -splitscreen_top f673 -splitscreen_vertical_add f4fc -spo2 f6db -spoke e9a7 -sports ea30 -sports_and_outdoors efb8 -sports_bar f1f3 -sports_baseball ea51 -sports_basketball ea26 -sports_cricket ea27 -sports_esports ea28 -sports_football ea29 -sports_golf ea2a -sports_gymnastics ebc4 -sports_handball ea33 -sports_hockey ea2b -sports_kabaddi ea34 -sports_martial_arts eae9 -sports_mma ea2c -sports_motorsports ea2d -sports_rugby ea2e -sports_score f06e -sports_soccer ea2f -sports_tennis ea32 -sports_volleyball ea31 -sprinkler e29a -sprint f81f -square eb36 -square_dot f3b3 -square_foot ea49 -ssid_chart eb66 -stack f609 -stack_group f359 -stack_hexagon f41c -stack_off f608 -stack_star f607 -stacked_bar_chart e9e6 -stacked_email e6c7 -stacked_inbox e6c9 -stacked_line_chart f22b -stacks f500 -stadia_controller f135 -stadium eb90 -stairs f1a9 -stairs_2 f46c -star f09a -star_border f09a -star_border_purple500 f09a -star_half e839 -star_outline f09a -star_purple500 f09a -star_rate f0ec -star_rate_half ec45 -star_shine f31d -stars e8d0 -stars_2 f31c -start e089 -stat_0 e697 -stat_1 e698 -stat_2 e699 -stat_3 e69a -stat_minus_1 e69b -stat_minus_2 e69c -stat_minus_3 e69d -stay_current_landscape ed3e -stay_current_portrait e7ba -stay_primary_landscape ed3e -stay_primary_portrait f2d3 -steering_wheel_heat f32b -step f6fe -step_into f701 -step_out f700 -step_over f6ff -steppers e9e7 -steps f6da -stethoscope f805 -stethoscope_arrow f807 -stethoscope_check f806 -sticky_note e9e8 -sticky_note_2 f1fc -stock_media f570 -stockpot f545 -stop e047 -stop_circle ef71 -stop_screen_share e0e3 -storage e1db -store e8d1 -store_mall_directory e8d1 -storefront ea12 -storm f070 -straight eb95 -straighten e41c -strategy f5df -stream e9e9 -stream_apps f79f -streetview e56e -stress_management f6d9 -strikethrough_s e257 -stroke_full f749 -stroke_partial f748 -stroller f1ae -style e41d -styler e273 -stylus f604 -stylus_brush f366 -stylus_fountain_pen f365 -stylus_highlighter f364 -stylus_laser_pointer f747 -stylus_note f603 -stylus_pen f363 -stylus_pencil f362 -subdirectory_arrow_left e5d9 -subdirectory_arrow_right e5da -subheader e9ea -subject e8d2 -subscript f111 -subscriptions e064 -subtitles e048 -subtitles_gear f355 -subtitles_off ef72 -subway e56f -subway_walk f287 -summarize f071 -sunny e81a -sunny_snowing e819 -superscript f112 -supervised_user_circle e939 -supervised_user_circle_off f60e -supervisor_account e8d3 -support ef73 -support_agent f0e2 -surfing e515 -surgical e131 -surround_sound e049 -swap_calls e0d7 -swap_driving_apps e69e -swap_driving_apps_wheel e69f -swap_horiz e8d4 -swap_horizontal_circle e933 -swap_vert e8d5 -swap_vertical_circle e8d6 -sweep e6ac -swipe e9ec -swipe_down eb53 -swipe_down_alt eb30 -swipe_left eb59 -swipe_left_alt eb33 -swipe_right eb52 -swipe_right_alt eb56 -swipe_up eb2e -swipe_up_alt eb35 -swipe_vertical eb51 -switch e1f4 -switch_access f6fd -switch_access_2 f506 -switch_access_3 f34d -switch_access_shortcut e7e1 -switch_access_shortcut_add e7e2 -switch_account e9ed -switch_camera e41e -switch_left f1d1 -switch_right f1d2 -switch_video e41f -switches e733 -sword_rose f5de -swords f889 -symptoms e132 -synagogue eab0 -sync e627 -sync_alt ea18 -sync_arrow_down f37c -sync_arrow_up f37b -sync_desktop f41a -sync_disabled e628 -sync_lock eaee -sync_problem e629 -sync_saved_locally f820 -sync_saved_locally_off f264 -syringe e133 -system_security_update f2cd -system_security_update_good f073 -system_security_update_warning f2d3 -system_update f2cd -system_update_alt e8d7 -tab e8d8 -tab_close f745 -tab_close_inactive f3d0 -tab_close_right f746 -tab_duplicate f744 -tab_group f743 -tab_inactive f43b -tab_move f742 -tab_new_right f741 -tab_recent f740 -tab_search f2f2 -tab_unselected e8d9 -table f191 -table_bar ead2 -table_chart e265 -table_chart_view f6ef -table_convert f3c7 -table_edit f3c6 -table_eye f466 -table_lamp e1f2 -table_large f299 -table_restaurant eac6 -table_rows f101 -table_rows_narrow f73f -table_sign ef2c -table_view f1be -tablet e32f -tablet_android e330 -tablet_camera f44d -tablet_mac e331 -tabs e9ee -tactic f564 -tag e9ef -tag_faces ea22 -takeout_dining ea74 -takeout_dining_2 ef34 -tamper_detection_off e82e -tamper_detection_on f8c8 -tap_and_play f2cc -tapas f1e9 -target e719 -task f075 -task_alt e2e6 -tatami_seat ef33 -taunt f69f -taxi_alert ef74 -team_dashboard e013 -temp_preferences_custom f8c9 -temp_preferences_eco f8ca -temple_buddhist eab3 -temple_hindu eaaf -tenancy f0e3 -terminal eb8e -terrain e564 -text_ad e728 -text_compare f3c5 -text_decrease eadd -text_fields e262 -text_fields_alt e9f1 -text_format e165 -text_increase eae2 -text_rotate_up e93a -text_rotate_vertical e93b -text_rotation_angledown e93c -text_rotation_angleup e93d -text_rotation_down e93e -text_rotation_none e93f -text_select_end f73e -text_select_jump_to_beginning f73d -text_select_jump_to_end f73c -text_select_move_back_character f73b -text_select_move_back_word f73a -text_select_move_down f739 -text_select_move_forward_character f738 -text_select_move_forward_word f737 -text_select_move_up f736 -text_select_start f735 -text_snippet f1c6 -text_to_speech f1bc -text_up f49e -textsms e625 -texture e421 -texture_add f57c -texture_minus f57b -theater_comedy ea66 -theaters e8da -thermometer e846 -thermometer_add f582 -thermometer_gain f6d8 -thermometer_loss f6d7 -thermometer_minus f581 -thermostat f076 -thermostat_arrow_down f37a -thermostat_arrow_up f379 -thermostat_auto f077 -thermostat_carbon f178 -things_to_do eb2a -thread_unread f4f9 -threat_intelligence eaed -thumb_down f578 -thumb_down_alt f578 -thumb_down_filled f578 -thumb_down_off f578 -thumb_down_off_alt f578 -thumb_up f577 -thumb_up_alt f577 -thumb_up_filled f577 -thumb_up_off f577 -thumb_up_off_alt f577 -thumbnail_bar f734 -thumbs_up_double eefc -thumbs_up_down e8dd -thunderstorm ebdb -tibia f89b -tibia_alt f89c -tile_large f3c3 -tile_medium f3c2 -tile_small f3c1 -time_auto f0e4 -time_to_leave eff7 -timelapse e422 -timeline e922 -timer e425 -timer_1 f2af -timer_10 e423 -timer_10_alt_1 efbf -timer_10_select f07a -timer_2 f2ae -timer_3 e424 -timer_3_alt_1 efc0 -timer_3_select f07b -timer_5 f4b1 -timer_5_shutter f4b2 -timer_arrow_down f378 -timer_arrow_up f377 -timer_off e426 -timer_pause f4bb -timer_play f4ba -tips_and_updates e79a -tire_repair ebc8 -title e264 -titlecase f489 -toast efc1 -toc e8de -today e8df -toggle_off e9f5 -toggle_on e9f6 -token ea25 -toll e8e0 -tonality e427 -tonality_2 f2b4 -toolbar e9f7 -tools_flat_head f8cb -tools_installation_kit e2ab -tools_ladder e2cb -tools_level e77b -tools_phillips f8cc -tools_pliers_wire_stripper e2aa -tools_power_drill e1e9 -tools_wrench f8cd -tooltip e9f8 -tooltip_2 f3ed -top_panel_close f733 -top_panel_open f732 -topic f1c8 -tornado e199 -total_dissolved_solids f877 -touch_app e913 -touch_double f38b -touch_long f38a -touch_triple f389 -touchpad_mouse f687 -touchpad_mouse_off f4e6 -tour ef75 -toys e332 -toys_and_games efc2 -toys_fan f887 -track_changes e8e1 -trackpad_input f4c7 -trackpad_input_2 f409 -trackpad_input_3 f408 -traffic e565 -traffic_jam f46f -trail_length eb5e -trail_length_medium eb63 -trail_length_short eb6d -train e570 -tram e571 -transcribe f8ec -transfer_within_a_station e572 -transform e428 -transgender e58d -transit_enterexit e579 -transit_ticket f3f1 -transition_chop f50e -transition_dissolve f50d -transition_fade f50c -transition_push f50b -transition_slide f50a -translate e8e2 -translate_indic f263 -transportation e21d -travel ef93 -travel_explore e2db -travel_luggage_and_bags efc3 -trending_down e8e3 -trending_flat e8e4 -trending_up e8e5 -trip e6fb -trip_origin e57b -trolley f86b -trolley_cable_car f46e -trophy ea23 -troubleshoot e1d2 -try f07c -tsunami ebd8 -tsv e6d6 -tty f1aa -tune e429 -tungsten f07d -turn_left eba6 -turn_right ebab -turn_sharp_left eba7 -turn_sharp_right ebaa -turn_slight_left eba4 -turn_slight_right eb9a -turned_in e8e7 -turned_in_not e8e7 -tv e63b -tv_displays f3ec -tv_gen e830 -tv_guide e1dc -tv_next f3eb -tv_off e647 -tv_options_edit_channels e1dd -tv_options_input_settings e1de -tv_remote f5d9 -tv_signin e71b -tv_with_assistant e785 -two_pager f51f -two_pager_store f3c4 -two_wheeler e9f9 -type_specimen f8f0 -u_turn_left eba1 -u_turn_right eba2 -udon ef32 -ulna_radius f89d -ulna_radius_alt f89e -umbrella f1ad -unarchive e169 -undo e166 -unfold_less e5d6 -unfold_less_double f8cf -unfold_more e5d7 -unfold_more_double f8d0 -ungroup f731 -universal_currency e9fa -universal_currency_alt e734 -universal_local e9fb -unknown_2 f49f -unknown_5 e6a5 -unknown_7 f49e -unknown_document f804 -unknown_med eabd -unlicense eb05 -unpaved_road f46d -unpin e6f9 -unpublished f236 -unsubscribe e0eb -upcoming f07e -update e923 -update_disabled e075 -upgrade f0fb -upi_pay f3cf -upload f09b -upload_2 f521 -upload_file e9fc -uppercase f488 -urology e137 -usb e1e0 -usb_off e4fa -user_attributes e708 -vaccines e138 -vacuum efc5 -valve e224 -vape_free ebc6 -vaping_rooms ebcf -variable_add f51e -variable_insert f51d -variable_remove f51c -variables f851 -ventilator e139 -verified ef76 -verified_off f30e -verified_user f013 -vertical_align_bottom e258 -vertical_align_center e259 -vertical_align_top e25a -vertical_distribute e076 -vertical_shades ec0e -vertical_shades_closed ec0d -vertical_split e949 -vibration f2cb -video_call e070 -video_camera_back f07f -video_camera_back_add f40c -video_camera_front f080 -video_camera_front_off f83b -video_chat f8a0 -video_file eb87 -video_label e071 -video_library e04a -video_search efc6 -video_settings ea75 -video_stable f081 -videocam e04b -videocam_alert f390 -videocam_off e04c -videogame_asset e338 -videogame_asset_off e500 -view_agenda e8e9 -view_apps f376 -view_array e8ea -view_carousel e8eb -view_column e8ec -view_column_2 f847 -view_comfy e42a -view_comfy_alt eb73 -view_compact e42b -view_compact_alt eb74 -view_cozy eb75 -view_day e8ed -view_headline e8ee -view_in_ar efc9 -view_in_ar_new efc9 -view_in_ar_off f61b -view_kanban eb7f -view_list e8ef -view_module e8f0 -view_object_track f432 -view_quilt e8f1 -view_real_size f4c2 -view_sidebar f114 -view_stream e8f2 -view_timeline eb85 -view_week e8f3 -vignette e435 -vignette_2 f2b3 -villa e586 -visibility e8f4 -visibility_lock f653 -visibility_off e8f5 -vital_signs e650 -vitals e13b -vo2_max f4aa -voice_chat e62e -voice_over_off e94a -voice_selection f58a -voice_selection_off f42c -voicemail e0d9 -voicemail_2 f352 -volcano ebda -volume_down e04d -volume_down_alt e79c -volume_mute e04e -volume_off e04f -volume_up e050 -volunteer_activism ea70 -voting_chip f852 -vpn_key e0da -vpn_key_alert f6cc -vpn_key_off eb7a -vpn_lock e62f -vpn_lock_2 f350 -vr180_create2d efca -vr180_create2d_off f571 -vrpano f082 -wall_art efcb -wall_lamp e2b4 -wallet f8ff -wallpaper e1bc -wallpaper_slideshow f672 -wand_shine f31f -wand_stars f31e -ward e13c -warehouse ebb8 -warning f083 -warning_amber f083 -warning_off f7ad -wash f1b1 -washoku f280 -watch e334 -watch_arrow f2ca -watch_button_press f6aa -watch_check f468 -watch_later efd6 -watch_off eae3 -watch_screentime f6ae -watch_vibration f467 -watch_wake f6a9 -water f084 -water_bottle f69d -water_bottle_large f69e -water_damage f203 -water_do f870 -water_drop e798 -water_ec f875 -water_full f6d6 -water_heater e284 -water_lock f6ad -water_loss f6d5 -water_lux f874 -water_medium f6d4 -water_orp f878 -water_ph f87a -water_pump f5d8 -water_voc f87b -waterfall_chart ea00 -waves e176 -waving_hand e766 -wb_auto e42c -wb_cloudy f15c -wb_incandescent e42e -wb_iridescent f07d -wb_shade ea01 -wb_sunny e430 -wb_twilight e1c6 -wc e63d -weather_hail f67f -weather_mix f60b -weather_snowy e2cd -web e051 -web_asset e069 -web_asset_off ef47 -web_stories e595 -web_traffic ea03 -webhook eb92 -weekend e16b -weight e13d -west f1e6 -whatshot e80e -wheelchair_pickup f1ab -where_to_vote e177 -widget_medium f3ba -widget_small f3b9 -widget_width f3b8 -widgets e1bd -width f730 -width_full f8f5 -width_normal f8f6 -width_wide f8f7 -wifi e63e -wifi_1_bar e4ca -wifi_2_bar e4d9 -wifi_add f7a8 -wifi_calling ef77 -wifi_calling_1 f0e7 -wifi_calling_2 f0f6 -wifi_calling_3 f0e7 -wifi_calling_bar_1 f44c -wifi_calling_bar_2 f44b -wifi_calling_bar_3 f44a -wifi_channel eb6a -wifi_find eb31 -wifi_home f671 -wifi_lock e1e1 -wifi_notification f670 -wifi_off e648 -wifi_password eb6b -wifi_protected_setup f0fc -wifi_proxy f7a7 -wifi_tethering e1e2 -wifi_tethering_error ead9 -wifi_tethering_off f087 -wind_power ec0c -window f088 -window_closed e77e -window_open e78c -window_sensor e2bb -windshield_defrost_auto f248 -windshield_defrost_front f32a -windshield_defrost_rear f329 -windshield_heat_front f328 -wine_bar f1e8 -woman e13e -woman_2 f8e7 -work e943 -work_alert f5f7 -work_history ec09 -work_off e942 -work_outline e943 -work_update f5f8 -workflow ea04 -workspace_premium e7af -workspaces ea0f -workspaces_outline ea0f -wounds_injuries e13f -wrap_text e25b -wrist f69c -wrong_location ef78 -wysiwyg f1c3 -yakitori ef31 -yard f089 -yoshoku f27f -your_trips eb2b -youtube_activity f85a -youtube_searched_for e8fa -zone_person_alert e781 -zone_person_idle e77a -zone_person_urgent e788 -zoom_in e8ff -zoom_in_map eb2d -zoom_out e900 -zoom_out_map e56b diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf deleted file mode 100644 index cb10ab3..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].woff2 b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].woff2 deleted file mode 100644 index fe6620f..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/material-design-icons/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].woff2 and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Bold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Bold.ttf deleted file mode 100644 index e17fa68..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Bold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Light.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Light.ttf deleted file mode 100644 index 00d414f..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Light.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Medium.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Medium.ttf deleted file mode 100644 index 41e642b..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Medium.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf deleted file mode 100644 index fd06617..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Regular.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Retina.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Retina.ttf deleted file mode 100644 index 2fc3a8f..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-Retina.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-SemiBold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-SemiBold.ttf deleted file mode 100644 index a1c7043..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFont-SemiBold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Bold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Bold.ttf deleted file mode 100644 index 2bb59ce..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Bold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Light.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Light.ttf deleted file mode 100644 index 4ebcd4e..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Light.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Medium.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Medium.ttf deleted file mode 100644 index 7a70f81..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Medium.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Regular.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Regular.ttf deleted file mode 100644 index 328e61d..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Regular.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Retina.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Retina.ttf deleted file mode 100644 index c270c8b..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-Retina.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-SemiBold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-SemiBold.ttf deleted file mode 100644 index 52af36b..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontMono-SemiBold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Bold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Bold.ttf deleted file mode 100644 index 71f6c68..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Bold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Light.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Light.ttf deleted file mode 100644 index 2c82ec5..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Light.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Medium.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Medium.ttf deleted file mode 100644 index b0fbdf4..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Medium.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Regular.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Regular.ttf deleted file mode 100644 index e791e1c..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Regular.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Retina.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Retina.ttf deleted file mode 100644 index 0d606e3..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-Retina.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-SemiBold.ttf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-SemiBold.ttf deleted file mode 100644 index ab8e78d..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/FiraCodeNerdFontPropo-SemiBold.ttf and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/LICENSE deleted file mode 100644 index 805e0b3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2014, The Fira Code Project Authors (https://github.com/tonsky/FiraCode) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/README.md deleted file mode 100644 index d40a728..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/fonts/nerd-fonts/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Nerd Fonts - -This is an archived font from the Nerd Fonts release v3.4.0. - -For more information see: -* https://github.com/ryanoasis/nerd-fonts/ -* https://github.com/ryanoasis/nerd-fonts/releases/latest/ - -# Fira Code - -**Fira Code** is a free monospaced font with programming ligatures. - -For more information have a look at the upstream website: https://github.com/tonsky/FiraCode - -Version: 6.2 - -## Which font? - -### TL;DR - -* Pick your font family: - * If you are limited to monospaced fonts (because of your terminal, etc) then pick a font with `Nerd Font Mono` (or `NFM`). - * If you want to have bigger icons (usually around 1.5 normal letters wide) pick a font without `Mono` i.e. `Nerd Font` (or `NF`). Most terminals support this, but ymmv. - * If you work in a proportional context (GUI elements or edit a presentation etc) pick a font with `Nerd Font Propo` (or `NFP`). - -### Ligatures - -Ligatures are generally preserved in the patched fonts. -Nerd Fonts `v2.0.0` had no ligatures in the `Nerd Font Mono` fonts, this has been dropped with `v2.1.0`. -If you have a ligature-aware terminal and don't want ligatures you can (usually) disable them in the terminal settings. - -### Explanation - -Once you narrow down your font choice of family (`Droid Sans`, `Inconsolata`, etc) and style (`bold`, `italic`, etc) you have 2 main choices: - -#### `Option 1: Download already patched font` - - * For a stable version download a font package from the [release page](https://github.com/ryanoasis/nerd-fonts/releases) - * Or download the development version from the folders here - -#### `Option 2: Patch your own font` - - * Patch your own variations with the various options provided by the font patcher (i.e. not include all symbols for smaller font size) - -For more information see: [The FAQ](https://github.com/ryanoasis/nerd-fonts/wiki/FAQ-and-Troubleshooting#which-font) - -[SIL-RFN]:http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web_fonts_and_RFNs#14cbfd4a diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/hyprland.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/hyprland.svg deleted file mode 100644 index 06cc08f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/hyprland.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/labwc.png b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/labwc.png deleted file mode 100644 index e60bec3..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/labwc.png and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/mango.png b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/mango.png deleted file mode 100644 index a995f57..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/mango.png and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/matrix-logo-white.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/matrix-logo-white.svg deleted file mode 100644 index ad927fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/matrix-logo-white.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - matrix logo white - Created with Sketch. - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/miraclewm.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/miraclewm.svg deleted file mode 100644 index 6fdd1e0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/miraclewm.svg +++ /dev/null @@ -1,1198 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/niri.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/niri.svg deleted file mode 100644 index 5bd2de0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/niri.svg +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/fprint b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/fprint deleted file mode 100644 index 770a8a4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/fprint +++ /dev/null @@ -1,3 +0,0 @@ -#%PAM-1.0 - -auth required pam_fprintd.so max-tries=1 timeout=5 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/login b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/login deleted file mode 100644 index c221e11..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/login +++ /dev/null @@ -1,5 +0,0 @@ -#%PAM-1.0 -auth required pam_env.so -auth sufficient pam_unix.so try_first_pass nullok -auth required pam_deny.so -account required pam_unix.so diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/u2f b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/u2f deleted file mode 100644 index bdac4ce..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/pam/u2f +++ /dev/null @@ -1,3 +0,0 @@ -#%PAM-1.0 - -auth required pam_u2f.so cue nouserok timeout=10 diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/raveos-logo.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/raveos-logo.svg deleted file mode 100755 index f6cd901..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/raveos-logo.svg +++ /dev/null @@ -1,2766 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/reddit.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/reddit.svg deleted file mode 100644 index 4ead26b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/reddit.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/CREDITS b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/CREDITS deleted file mode 100644 index d3bf575..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/CREDITS +++ /dev/null @@ -1,77 +0,0 @@ -alarm-clock-elapsed - Copyright: Tim/corsica_s - URL: http://www.freesound.org/samplesViewSingle.php?id=67091 - License: CC-BY-SA (relicensed with permission from author) - -audio-channel-front-center -audio-channel-front-left -audio-channel-front-right -audio-channel-rear-center -audio-channel-rear-left -audio-channel-rear-right -audio-channel-side-left -audio-channel-side-right -audio-test-signal - Copyright: The ALSA developers - URL: http://git.alsa-project.org/?p=alsa-utils.git;a=tree;f=speaker-test/samples;hb=HEAD - License: GPLv2+ - -audio-volume-change - Copyright: Lucas McCallister - URL: http://www.freesound.org/samplesViewSingle.php?id=67091 - License: CC-BY-SA (relicensed with permission from author) - -trash-empty - Copyright: Dr. Richard Boulanger et al - URL: http://www.archive.org/details/Berklee44v10 - License: CC-BY Attribution 3.0 Unported - -complete - Copyright: Dr. Richard Boulanger et al - URL: http://www.archive.org/details/Berklee44v11 - License: CC-BY Attribution 3.0 Unported - -bell - Copyright: Dr. Richard Boulanger et al - URL: http://www.archive.org/details/Berklee44v12 - License: CC-BY Attribution 3.0 Unported - - -camera-shutter -screen-capture - Copyright: freesound user horsthorstensen - URL: http://www.freesound.org/samplesViewSingle.php?id=72714 - License: CC-BY-SA (relicensed with permission from author) - -device-added -device-removed -power-plug -power-unplug -network-connectivity-established -network-connectivity-lost -message -dialog-information -dialog-warning - Copyright: Ivica Bukvic - URL: http://gnome-look.org/content/show.php/%22Borealis%22+sound+theme?content=12584 - License: CC-BY-SA - - -message-new-instant - -phone-incoming-call -phone-outgoing-busy -phone-outgoing-calling - Copyright: Damien Sandras - URL: http://git.gnome.org/cgit/ekiga/tree/sounds - License: GPLv2+ - -service-login -service-logout - Copyright: The Pidgin developers - License: GPLv2 - -suspend-error - Created by Richard Hughes - Copyright: Red Hat, Inc. - License: CC-BY-SA diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.oga b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.oga deleted file mode 100644 index e4a33dc..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.oga and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.wav deleted file mode 100644 index 24bcc44..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/audio-volume-change.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.oga b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.oga deleted file mode 100644 index b7da8e9..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.oga and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.wav deleted file mode 100644 index d511248..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/desktop-login.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.oga b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.oga deleted file mode 100644 index e6bdd7a..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.oga and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.wav deleted file mode 100644 index a663b3e..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message-new-instant.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.oga b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.oga deleted file mode 100644 index e96c3a1..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.oga and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.wav deleted file mode 100644 index 34702c0..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/freedesktop/message.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/LICENSE deleted file mode 100644 index 0000c85..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/LICENSE +++ /dev/null @@ -1,107 +0,0 @@ -Creative Commons Attribution-ShareAlike 4.0 International - -Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an "as-is" basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. - -Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors - -Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor's permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. - -Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public : wiki.creativecommons.org/Considerations_for_licensees - -Creative Commons Attribution-ShareAlike 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. - -Section 1 – Definitions. - -a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. -b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. -c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. -d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. -e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. -f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. -g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. -h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. -i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. -j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. -k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. -l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. -m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. -Section 2 – Scope. - -a. License grant. -1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: -A. reproduce and Share the Licensed Material, in whole or in part; and -B. produce, reproduce, and Share Adapted Material. -2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. -3. Term. The term of this Public License is specified in Section 6(a). -4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. -5. Downstream recipients. -A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. -B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply. -C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. -6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). -b. Other rights. -1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. -2. Patent and trademark rights are not licensed under this Public License. -3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. -Section 3 – License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the following conditions. - -a. Attribution. -1. If You Share the Licensed Material (including in modified form), You must: -A. retain the following if it is supplied by the Licensor with the Licensed Material: -i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); -ii. a copyright notice; -iii. a notice that refers to this Public License; -iv. a notice that refers to the disclaimer of warranties; -v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; - -B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and -C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. -2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. -3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. -b. ShareAlike.In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. -1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. -2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. -3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. -Section 4 – Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: - -a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; -b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and -c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. -For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. -Section 5 – Disclaimer of Warranties and Limitation of Liability. - -a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. -b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. -c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. -Section 6 – Term and Termination. - -a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. -b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: -1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or -2. upon express reinstatement by the Licensor. -c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. -d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. -e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. -Section 7 – Other Terms and Conditions. - -a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. -b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. -Section 8 – Interpretation. - -a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. -b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. -c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. -d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. -Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the "Licensor." The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/README.md deleted file mode 100644 index 1bc47a1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Dream Sounds: Harmony 2 - -## Sound theme for KDE Plasma 6 - -- Instrumental and skeuomorphic sounds; -- Designed for [KDE Plasma 6](https://kde.org/plasma-desktop/); -- Follows [freedesktop's sound naming spec](https://specifications.freedesktop.org/sound-naming-spec/sound-naming-spec-latest.html); -- Made with [LMMS](https://lmms.io/) and [Tenacity](https://tenacityaudio.org/). - -## Installation - -### Pling/KDE Store - -Get the theme from [here](https://www.pling.com/p/2134858/). - -### Arch User Repository - -I maintain an AUR package called `harmony2`. Get it from [here](https://aur.archlinux.org/packages/harmony2) or with your preferred AUR helper (e.g.: `yay -S harmony2`). - -### This repo - -1. Download a package from the releases or clone the repository; -2. Copy the `stereo` folder and the `index.theme` file in `/usr/share/sounds/harmony2` or `~/.local/share/sounds/harmony2`; -3. Set the theme in your System Settings under the "Sound theme" section. - -## Exporting - -**Note**: in order to use most of these sounds in the LMMS project, you need the OmegaGMGS2 soundfont by Rick Simon. Download it in your LMMS working directory, under `samples/soundfonts`. - -To export all the sounds from LMMS: - -1. Make sure the various tracks (each corresponding to one sound) you want to export are enabled (their green light on the left must be on); -2. Go to File > Export Tracks... and choose a directory to export the sounds in; -3. In the encoding settings choose "Compressed OGG-File (*.ogg)" as the file format, 48000 Hz as the samplerate and 320 KBit/s as the bitrate in order to match the official sounds; -4. Click "Start" and wait for the process to finish. - -One annoying thing is that LMMS always exports the tracks with a number prefix in front of every file name. To solve this I found a simple Bash routine to rename all the files and get rid of the prefix: - -```bash -for fp in ./*_*; do - mv "$fp" "${fp#*_}" -done -``` - ---- - -🄯 2024 - 2025 Gianmarco Gargiulo - CC BY-SA 4.0 International (check the LICENSE file) diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.ogg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.ogg deleted file mode 100644 index 591e1cf..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.ogg and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.wav deleted file mode 100644 index 718432e..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-plug.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.ogg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.ogg deleted file mode 100644 index cce1f61..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.ogg and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.wav b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.wav deleted file mode 100644 index 82a0086..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/plasma/power-unplug.wav and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/wavconvert.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/wavconvert.sh deleted file mode 100755 index edad073..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sounds/wavconvert.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Convert freedesktop sounds -cd freedesktop -for file in *.oga; do - if [ -f "$file" ]; then - echo "Converting $file to WAV..." - ffmpeg -i "$file" -acodec pcm_s16le -ar 44100 -ac 2 "${file%.oga}.wav" - fi -done - -# Convert plasma sounds -cd ../plasma -for file in *.ogg; do - if [ -f "$file" ]; then - echo "Converting $file to WAV..." - ffmpeg -i "$file" -acodec pcm_s16le -ar 44100 -ac 2 "${file%.ogg}.wav" - fi -done - -echo "Conversion complete!" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sway.svg b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sway.svg deleted file mode 100644 index 96397c5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/assets/sway.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/alacritty.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/alacritty.toml deleted file mode 100644 index 7bcc962..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/alacritty.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsalacritty] -input_path = 'SHELL_DIR/matugen/templates/alacritty.toml' -output_path = 'CONFIG_DIR/alacritty/dank-theme.toml' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/base.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/base.toml deleted file mode 100644 index 8d17029..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/base.toml +++ /dev/null @@ -1 +0,0 @@ -[config] diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/dgop.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/dgop.toml deleted file mode 100644 index dcfa244..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/dgop.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsdgop] -input_path = 'SHELL_DIR/matugen/templates/dgop.json' -output_path = 'CONFIG_DIR/dgop/colors.json' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/emacs.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/emacs.toml deleted file mode 100644 index aac56ab..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/emacs.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsemacs] -input_path = 'SHELL_DIR/matugen/templates/dank-emacs.el' -output_path = 'EMACS_DIR/themes/dank-emacs-theme.el' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/equibop.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/equibop.toml deleted file mode 100644 index 3a4d4da..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/equibop.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsequibop] -input_path = 'SHELL_DIR/matugen/templates/vesktop.css' -output_path = 'CONFIG_DIR/equibop/themes/dank-discord.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/firefox.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/firefox.toml deleted file mode 100644 index 3f048d2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/firefox.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsfirefox] -input_path = 'SHELL_DIR/matugen/templates/firefox-userchrome.css' -output_path = 'CONFIG_DIR/DankMaterialShell/firefox.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/foot.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/foot.toml deleted file mode 100644 index 9c37498..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/foot.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsfoot] -input_path = 'SHELL_DIR/matugen/templates/foot.ini' -output_path = 'CONFIG_DIR/foot/dank-colors.ini' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/ghostty.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/ghostty.toml deleted file mode 100644 index 057a3d5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/ghostty.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsghostty] -input_path = 'SHELL_DIR/matugen/templates/ghostty.conf' -output_path = 'CONFIG_DIR/ghostty/themes/dankcolors' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-dark.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-dark.toml deleted file mode 100644 index 573e8bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-dark.toml +++ /dev/null @@ -1,7 +0,0 @@ -[templates.dmsgtk3] -input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css' -output_path = 'CONFIG_DIR/gtk-3.0/dank-colors.css' - -[templates.dmsgtk4] -input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css' -output_path = 'CONFIG_DIR/gtk-4.0/dank-colors.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-light.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-light.toml deleted file mode 100644 index 91b21b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/gtk3-light.toml +++ /dev/null @@ -1,7 +0,0 @@ -[templates.dmsgtk3] -input_path = 'SHELL_DIR/matugen/templates/gtk-light-colors.css' -output_path = 'CONFIG_DIR/gtk-3.0/dank-colors.css' - -[templates.dmsgtk4] -input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css' -output_path = 'CONFIG_DIR/gtk-4.0/dank-colors.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/hyprland.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/hyprland.toml deleted file mode 100644 index 21553b8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/hyprland.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmshyprland] -input_path = 'SHELL_DIR/matugen/templates/hypr-colors.conf' -output_path = 'CONFIG_DIR/hypr/dms/colors.conf' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kcolorscheme.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kcolorscheme.toml deleted file mode 100644 index bf022ab..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kcolorscheme.toml +++ /dev/null @@ -1,11 +0,0 @@ -[templates.dmskcolorscheme] -input_path = 'SHELL_DIR/matugen/templates/kcolorscheme.colors' -output_path = 'DATA_DIR/color-schemes/DankMatugen.colors' - -[templates.dmslightkcolorscheme] -input_path = 'SHELL_DIR/matugen/templates/light-kcolorscheme.colors' -output_path = 'DATA_DIR/color-schemes/DankMatugenLight.colors' - -[templates.dmsdarkkcolorscheme] -input_path = 'SHELL_DIR/matugen/templates/dark-kcolorscheme.colors' -output_path = 'DATA_DIR/color-schemes/DankMatugenDark.colors' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kitty.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kitty.toml deleted file mode 100644 index a8bc15f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/kitty.toml +++ /dev/null @@ -1,7 +0,0 @@ -[templates.dmskitty] -input_path = 'SHELL_DIR/matugen/templates/kitty.conf' -output_path = 'CONFIG_DIR/kitty/dank-theme.conf' - -[templates.dmskittytabs] -input_path = 'SHELL_DIR/matugen/templates/kitty-tabs.conf' -output_path = 'CONFIG_DIR/kitty/dank-tabs.conf' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/mangowc.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/mangowc.toml deleted file mode 100644 index 8853142..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/mangowc.toml +++ /dev/null @@ -1,4 +0,0 @@ -[templates.dmsmango] -input_path = 'SHELL_DIR/matugen/templates/mango-colors.conf' -output_path = 'CONFIG_DIR/mango/dms/colors.conf' -post_hook = 'sh -c "mmsg -d reload_config 2>&1 || true"' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/neovim.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/neovim.toml deleted file mode 100644 index 80723d6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/neovim.toml +++ /dev/null @@ -1,7 +0,0 @@ -[templates.dmsneovim-colors] -input_path = 'SHELL_DIR/matugen/templates/neovim-colors.lua' -output_path = 'CONFIG_DIR/nvim/colors/dms.lua' - -[templates.dmsneovim-lualine] -input_path = 'SHELL_DIR/matugen/templates/neovim-lualine.lua' -output_path = 'CONFIG_DIR/nvim/lua/lualine/themes/dms.lua' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/niri.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/niri.toml deleted file mode 100644 index 1179d36..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/niri.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsniri] -input_path = 'SHELL_DIR/matugen/templates/niri-colors.kdl' -output_path = 'CONFIG_DIR/niri/dms/colors.kdl' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/pywalfox.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/pywalfox.toml deleted file mode 100644 index 40a3c5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/pywalfox.toml +++ /dev/null @@ -1,4 +0,0 @@ -[templates.dmspywalfox] -input_path = 'SHELL_DIR/matugen/templates/pywalfox-colors.json' -output_path = 'CACHE_DIR/wal/dank-pywalfox.json' -post_hook = 'sh -c "command -v pywalfox && test -f ~/.cache/wal/colors.json && pywalfox update"' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt5ct.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt5ct.toml deleted file mode 100644 index 52a664b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt5ct.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsqt5ct] -input_path = 'SHELL_DIR/matugen/templates/qtct-colors.conf' -output_path = 'CONFIG_DIR/qt5ct/colors/matugen.conf' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt6ct.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt6ct.toml deleted file mode 100644 index c39a8bd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/qt6ct.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsqt6ct] -input_path = 'SHELL_DIR/matugen/templates/qtct-colors.conf' -output_path = 'CONFIG_DIR/qt6ct/colors/matugen.conf' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/vesktop.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/vesktop.toml deleted file mode 100644 index c87c5bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/vesktop.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmsvesktop] -input_path = 'SHELL_DIR/matugen/templates/vesktop.css' -output_path = 'CONFIG_DIR/vesktop/themes/dank-discord.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/wezterm.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/wezterm.toml deleted file mode 100644 index 47a3944..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/wezterm.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmswezterm] -input_path = 'SHELL_DIR/matugen/templates/wezterm.toml' -output_path = 'CONFIG_DIR/wezterm/colors/dank-theme.toml' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zed.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zed.toml deleted file mode 100644 index 7443572..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zed.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmszed] -input_path = 'SHELL_DIR/matugen/templates/dank-zed.json' -output_path = 'CONFIG_DIR/zed/themes/dank-zed-theme.json' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zenbrowser.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zenbrowser.toml deleted file mode 100644 index 6cd4eca..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/configs/zenbrowser.toml +++ /dev/null @@ -1,3 +0,0 @@ -[templates.dmszenbrowser] -input_path = 'SHELL_DIR/matugen/templates/zen-userchrome.css' -output_path = 'CONFIG_DIR/DankMaterialShell/zen.css' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/dms-theme.vsix b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/dms-theme.vsix deleted file mode 100644 index fb2b161..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/dms-theme.vsix and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/alacritty.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/alacritty.toml deleted file mode 100644 index b9295fd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/alacritty.toml +++ /dev/null @@ -1,31 +0,0 @@ -[colors.primary] -background = '{{colors.background.default.hex}}' -foreground = '{{colors.on_surface.default.hex}}' - -[colors.selection] -text = '{{colors.on_surface.default.hex}}' -background = '{{colors.primary_container.default.hex}}' - -[colors.cursor] -text = '{{colors.background.default.hex}}' -cursor = '{{colors.primary.default.hex}}' - -[colors.normal] -black = '{{dank16.color0.default.hex}}' -red = '{{dank16.color1.default.hex}}' -green = '{{dank16.color2.default.hex}}' -yellow = '{{dank16.color3.default.hex}}' -blue = '{{dank16.color4.default.hex}}' -magenta = '{{dank16.color5.default.hex}}' -cyan = '{{dank16.color6.default.hex}}' -white = '{{dank16.color7.default.hex}}' - -[colors.bright] -black = '{{dank16.color8.default.hex}}' -red = '{{dank16.color9.default.hex}}' -green = '{{dank16.color10.default.hex}}' -yellow = '{{dank16.color11.default.hex}}' -blue = '{{dank16.color12.default.hex}}' -magenta = '{{dank16.color13.default.hex}}' -cyan = '{{dank16.color14.default.hex}}' -white = '{{dank16.color15.default.hex}}' diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-emacs.el b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-emacs.el deleted file mode 100644 index 452bf94..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-emacs.el +++ /dev/null @@ -1,381 +0,0 @@ -;;; dank-emacs-theme.el --- Enhanced theme using Matugen SCSS variables with dank16 colors - -;; Copyright (C) 2025 - -;; Author: Generated (Enhanced) -;; Version: 1.3 -;; Package-Requires: ((emacs "24.1")) -;; Keywords: faces - -;;; Commentary: - -;; An enhanced theme using Matugen SCSS variables integrated with dank16 colors: -;; - Rich color palette from dank16 for vibrant syntax highlighting -;; - Improved contrast and readability -;; - Better source block distinction with refined backgrounds -;; - Enhanced org-mode styling with hidden asterisks -;; - Superior visual hierarchy and modern aesthetics - -;;; Code: - -(deftheme dank-emacs "Enhanced theme using Matugen variables with dank16 color integration.") - -;; Define all the color variables (replaced by template processor) -(let* ((bg "{{colors.background.default.hex}}") - (err "{{dank16.color1.default.hex}}") ; Red from dank16 - (err-container "{{colors.error_container.default.hex}}") - (on-background "{{colors.on_background.default.hex}}") - (on-err "{{colors.on_error.default.hex}}") - (on-err-container "{{colors.on_error_container.default.hex}}") - (on-primary "{{colors.on_primary.default.hex}}") - (on-primary-container "{{colors.on_primary_container.default.hex}}") - (on-secondary "{{colors.on_secondary.default.hex}}") - (on-secondary-container "{{colors.on_secondary_container.default.hex}}") - (on-surface "{{colors.on_surface.default.hex}}") - (on-surface-variant "{{colors.on_surface_variant.default.hex}}") - (on-tertiary "{{colors.on_tertiary.default.hex}}") - (on-tertiary-container "{{colors.on_tertiary_container.default.hex}}") - (outline-color "{{colors.outline.default.hex}}") - (outline-variant "{{colors.outline_variant.default.hex}}") - (primary "{{colors.primary.default.hex}}") - (primary-container "{{colors.primary_container.default.hex}}") - (secondary "{{colors.secondary.default.hex}}") - (secondary-container "{{colors.secondary_container.default.hex}}") - (shadow "{{colors.shadow.default.hex}}") - (surface "{{colors.surface.default.hex}}") - (surface-container "{{colors.surface_container_high.default.hex}}") - (surface-container-high "{{colors.surface_container_highest.default.hex}}") - (surface-container-highest "{{colors.surface_container_high.default.hex}}") - (surface-container-low "{{colors.surface_container_low.default.hex}}") - (surface-container-lowest "{{colors.surface_container_lowest.default.hex}}") - (surface-variant "{{colors.surface_variant.default.hex}}") - (tertiary "{{colors.tertiary.default.hex}}") - (tertiary-container "{{colors.tertiary_container.default.hex}}") - - ;; Enhanced dank16 colors for better syntax highlighting - (dank-red "{{dank16.color1.default.hex}}") ; Bright red - (dank-red-alt "{{dank16.color9.default.hex}}") ; Alternative red - (dank-green "{{dank16.color2.default.hex}}") ; Vibrant green - (dank-green-bright "{{dank16.color10.default.hex}}") ; Bright green - (dank-yellow "{{dank16.color3.default.hex}}") ; Warm yellow - (dank-yellow-bright "{{dank16.color11.default.hex}}") ; Bright yellow - (dank-blue "{{dank16.color4.default.hex}}") ; Blue-green - (dank-magenta "{{dank16.color5.default.hex}}") ; Teal-magenta - (dank-cyan "{{dank16.color6.default.hex}}") ; Bright cyan - (dank-cyan-bright "{{dank16.color12.default.hex}}") ; Brightest cyan - (dank-cyan-dark "{{dank16.color13.default.hex}}") ; Dark cyan - (dank-teal "{{dank16.color14.default.hex}}") ; Dark teal - (dank-fg "{{dank16.color7.default.hex}}") ; Light foreground - (dank-gray "{{dank16.color8.default.hex}}") ; Gray - (dank-white "{{dank16.color15.default.hex}}") ; White - - ;; Map success colors to green - (success "{{dank16.color2.default.hex}}") - (on-success "{{colors.on_tertiary.default.hex}}") - (success-container "{{colors.tertiary_container.default.hex}}") - (on-success-container "{{colors.on_tertiary_container.default.hex}}") - - ;; Map fixed colors - (primary-fixed "{{colors.primary_fixed.default.hex}}") - (primary-fixed-dim "{{colors.primary_fixed_dim.default.hex}}") - (secondary-fixed "{{colors.secondary_fixed.default.hex}}") - (secondary-fixed-dim "{{colors.secondary_fixed_dim.default.hex}}") - (tertiary-fixed "{{colors.tertiary_fixed.default.hex}}") - (tertiary-fixed-dim "{{colors.tertiary_fixed_dim.default.hex}}") - (on-primary-fixed "{{colors.on_primary_fixed.default.hex}}") - (on-primary-fixed-variant "{{colors.on_primary_fixed_variant.default.hex}}") - (on-secondary-fixed "{{colors.on_secondary_fixed.default.hex}}") - (on-secondary-fixed-variant "{{colors.on_secondary_fixed_variant.default.hex}}") - (on-tertiary-fixed "{{colors.on_tertiary_fixed.default.hex}}") - (on-tertiary-fixed-variant "{{colors.on_tertiary_fixed_variant.default.hex}}") - - ;; Map inverse colors - (inverse-on-surface "{{colors.inverse_on_surface.default.hex}}") - (inverse-primary "{{colors.inverse_primary.default.hex}}") - (inverse-surface "{{colors.inverse_surface.default.hex}}") - - ;; Terminal colors from dank16 - (term0 "{{dank16.color0.default.hex}}") - (term1 "{{dank16.color1.default.hex}}") - (term2 "{{dank16.color2.default.hex}}") - (term3 "{{dank16.color3.default.hex}}") - (term4 "{{dank16.color4.default.hex}}") - (term5 "{{dank16.color5.default.hex}}") - (term6 "{{dank16.color6.default.hex}}") - (term7 "{{dank16.color7.default.hex}}") - (term8 "{{dank16.color8.default.hex}}") - (term9 "{{dank16.color9.default.hex}}") - (term10 "{{dank16.color10.default.hex}}") - (term11 "{{dank16.color11.default.hex}}") - (term12 "{{dank16.color12.default.hex}}") - (term13 "{{dank16.color13.default.hex}}") - (term14 "{{dank16.color14.default.hex}}") - (term15 "{{dank16.color15.default.hex}}")) - - (custom-theme-set-faces - 'dank-emacs - ;; Basic faces - `(default ((t (:background ,bg :foreground ,on-background)))) - `(cursor ((t (:background ,dank-cyan-bright)))) - `(highlight ((t (:background ,primary-container :foreground ,on-primary-container)))) - `(region ((t (:background ,primary-container :foreground ,dank-cyan-bright :extend t)))) - `(secondary-selection ((t (:background ,secondary-container :foreground ,on-secondary-container :extend t)))) - `(isearch ((t (:background ,dank-yellow :foreground ,bg :weight bold)))) - `(lazy-highlight ((t (:background ,secondary-container :foreground ,dank-yellow-bright)))) - `(vertical-border ((t (:foreground ,surface-variant)))) - `(border ((t (:background ,surface-variant :foreground ,surface-variant)))) - `(fringe ((t (:background ,surface :foreground ,dank-gray)))) - `(shadow ((t (:foreground ,dank-gray)))) - `(link ((t (:foreground ,dank-cyan-bright :underline t)))) - `(link-visited ((t (:foreground ,dank-magenta :underline t)))) - `(success ((t (:foreground ,success)))) - `(warning ((t (:foreground ,dank-yellow)))) - `(error ((t (:foreground ,err)))) - `(match ((t (:background ,dank-yellow :foreground ,bg :weight bold)))) - - ;; Font-lock - enhanced with dank16 colors for vibrant syntax highlighting - `(font-lock-builtin-face ((t (:foreground ,dank-cyan-bright)))) - `(font-lock-comment-face ((t (:foreground ,dank-gray :slant italic)))) - `(font-lock-comment-delimiter-face ((t (:foreground ,outline-variant)))) - `(font-lock-constant-face ((t (:foreground ,dank-yellow-bright :weight bold)))) - `(font-lock-doc-face ((t (:foreground ,dank-fg :slant italic)))) - `(font-lock-function-name-face ((t (:foreground ,dank-cyan :weight bold)))) - `(font-lock-keyword-face ((t (:foreground ,dank-red-alt :weight bold)))) - `(font-lock-string-face ((t (:foreground ,dank-green)))) - `(font-lock-type-face ((t (:foreground ,dank-yellow)))) - `(font-lock-variable-name-face ((t (:foreground ,dank-fg)))) - `(font-lock-warning-face ((t (:foreground ,err :weight bold)))) - `(font-lock-preprocessor-face ((t (:foreground ,dank-teal)))) - `(font-lock-negation-char-face ((t (:foreground ,dank-red)))) - - ;; Show paren - `(show-paren-match ((t (:background ,primary-container :foreground ,dank-cyan-bright :weight bold)))) - `(show-paren-mismatch ((t (:background ,err-container :foreground ,on-err-container :weight bold)))) - - ;; Mode line - improved status bar styling - `(mode-line ((t (:background ,surface-container :foreground ,on-surface :box nil)))) - `(mode-line-inactive ((t (:background ,surface :foreground ,dank-gray :box nil)))) - `(mode-line-buffer-id ((t (:foreground ,dank-cyan :weight bold)))) - `(mode-line-emphasis ((t (:foreground ,dank-cyan :weight bold)))) - `(mode-line-highlight ((t (:foreground ,dank-cyan-bright :box nil)))) - - ;; Improved Source blocks - seamless integration - `(org-block ((t (:background ,surface-container-low :extend t :inherit fixed-pitch)))) - `(org-block-begin-line ((t (:background ,surface-container-low :foreground ,dank-teal :extend t :slant italic :inherit fixed-pitch)))) - `(org-block-end-line ((t (:background ,surface-container-low :foreground ,dank-teal :extend t :slant italic :inherit fixed-pitch)))) - `(org-code ((t (:background ,surface-container-low :foreground ,dank-yellow-bright :inherit fixed-pitch)))) - `(org-verbatim ((t (:background ,surface-container-low :foreground ,dank-cyan :inherit fixed-pitch)))) - `(org-meta-line ((t (:foreground ,dank-gray :slant italic)))) - - ;; Org mode with enhanced colors and hidden asterisks - `(org-level-1 ((t (:foreground ,dank-cyan :weight bold :height 1.2)))) - `(org-level-2 ((t (:foreground ,dank-blue :weight bold :height 1.1)))) - `(org-level-3 ((t (:foreground ,dank-magenta :weight bold)))) - `(org-level-4 ((t (:foreground ,dank-green :weight bold)))) - `(org-level-5 ((t (:foreground ,dank-yellow :weight bold)))) - `(org-level-6 ((t (:foreground ,dank-cyan-bright :weight bold)))) - `(org-level-7 ((t (:foreground ,dank-red-alt :weight bold)))) - `(org-level-8 ((t (:foreground ,dank-teal :weight bold)))) - `(org-document-title ((t (:foreground ,dank-cyan :weight bold :height 1.3)))) - `(org-document-info ((t (:foreground ,dank-blue)))) - `(org-todo ((t (:foreground ,dank-red :weight bold)))) - `(org-done ((t (:foreground ,success :weight bold)))) - `(org-headline-done ((t (:foreground ,dank-gray)))) - `(org-hide ((t (:foreground ,bg)))) - `(org-ellipsis ((t (:foreground ,dank-blue :underline nil)))) - `(org-table ((t (:foreground ,dank-magenta :inherit fixed-pitch)))) - `(org-formula ((t (:foreground ,dank-yellow-bright :inherit fixed-pitch)))) - `(org-checkbox ((t (:foreground ,dank-cyan :weight bold :inherit fixed-pitch)))) - `(org-date ((t (:foreground ,dank-teal :underline t)))) - `(org-special-keyword ((t (:foreground ,dank-gray :slant italic)))) - `(org-tag ((t (:foreground ,dank-gray :weight normal)))) - - ;; Magit with enhanced diff colors - `(magit-section-highlight ((t (:background ,surface-container-low)))) - `(magit-diff-hunk-heading ((t (:background ,surface-container :foreground ,dank-gray)))) - `(magit-diff-hunk-heading-highlight ((t (:background ,surface-container-high :foreground ,on-surface)))) - `(magit-diff-context ((t (:foreground ,dank-gray)))) - `(magit-diff-context-highlight ((t (:background ,surface-container-low :foreground ,on-surface)))) - `(magit-diff-added ((t (:background ,success-container :foreground ,dank-green-bright)))) - `(magit-diff-added-highlight ((t (:background ,success-container :foreground ,dank-green-bright :weight bold)))) - `(magit-diff-removed ((t (:background ,err-container :foreground ,dank-red-alt)))) - `(magit-diff-removed-highlight ((t (:background ,err-container :foreground ,dank-red-alt :weight bold)))) - `(magit-hash ((t (:foreground ,dank-gray)))) - `(magit-branch-local ((t (:foreground ,dank-blue :weight bold)))) - `(magit-branch-remote ((t (:foreground ,dank-cyan :weight bold)))) - - ;; Company - `(company-tooltip ((t (:background ,surface-container :foreground ,on-surface)))) - `(company-tooltip-selection ((t (:background ,primary-container :foreground ,dank-cyan-bright)))) - `(company-tooltip-common ((t (:foreground ,dank-cyan)))) - `(company-tooltip-common-selection ((t (:foreground ,dank-cyan-bright :weight bold)))) - `(company-tooltip-annotation ((t (:foreground ,dank-yellow)))) - `(company-scrollbar-fg ((t (:background ,dank-cyan)))) - `(company-scrollbar-bg ((t (:background ,surface-variant)))) - `(company-preview ((t (:foreground ,dank-gray :slant italic)))) - `(company-preview-common ((t (:foreground ,dank-cyan :slant italic)))) - - ;; Ido - `(ido-first-match ((t (:foreground ,dank-cyan :weight bold)))) - `(ido-only-match ((t (:foreground ,dank-green :weight bold)))) - `(ido-subdir ((t (:foreground ,dank-blue)))) - `(ido-indicator ((t (:foreground ,dank-red)))) - `(ido-virtual ((t (:foreground ,dank-gray)))) - - ;; Helm - `(helm-selection ((t (:background ,primary-container :foreground ,dank-cyan-bright)))) - `(helm-match ((t (:foreground ,dank-cyan :weight bold)))) - `(helm-source-header ((t (:background ,surface-container-high :foreground ,dank-cyan :weight bold :height 1.1)))) - `(helm-candidate-number ((t (:foreground ,dank-yellow :weight bold)))) - `(helm-ff-directory ((t (:foreground ,dank-cyan :weight bold)))) - `(helm-ff-file ((t (:foreground ,on-surface)))) - `(helm-ff-executable ((t (:foreground ,dank-green)))) - - ;; corfu - `(corfu-default ((t (:background ,surface-container :foreground ,on-surface)))) - `(corfu-current ((t (:background ,primary-container :foreground ,dank-cyan-bright)))) - - ;; Which-key - `(which-key-key-face ((t (:foreground ,dank-cyan :weight bold)))) - `(which-key-separator-face ((t (:foreground ,outline-variant)))) - `(which-key-command-description-face ((t (:foreground ,on-surface)))) - `(which-key-group-description-face ((t (:foreground ,dank-blue)))) - `(which-key-special-key-face ((t (:foreground ,dank-yellow :weight bold)))) - - ;; Line numbers - `(line-number ((t (:foreground ,dank-gray :inherit fixed-pitch)))) - `(line-number-current-line ((t (:foreground ,dank-cyan :weight bold :inherit fixed-pitch)))) - - ;; Parenthesis matching - `(sp-show-pair-match-face ((t (:background ,primary-container :foreground ,dank-cyan-bright)))) - `(sp-show-pair-mismatch-face ((t (:background ,err-container :foreground ,on-err-container)))) - - ;; Rainbow delimiters - vibrant colors - `(rainbow-delimiters-depth-1-face ((t (:foreground ,dank-cyan)))) - `(rainbow-delimiters-depth-2-face ((t (:foreground ,dank-yellow)))) - `(rainbow-delimiters-depth-3-face ((t (:foreground ,dank-green)))) - `(rainbow-delimiters-depth-4-face ((t (:foreground ,dank-blue)))) - `(rainbow-delimiters-depth-5-face ((t (:foreground ,dank-magenta)))) - `(rainbow-delimiters-depth-6-face ((t (:foreground ,dank-cyan-bright)))) - `(rainbow-delimiters-depth-7-face ((t (:foreground ,dank-yellow-bright)))) - `(rainbow-delimiters-depth-8-face ((t (:foreground ,dank-green-bright)))) - `(rainbow-delimiters-depth-9-face ((t (:foreground ,dank-red-alt)))) - `(rainbow-delimiters-mismatched-face ((t (:foreground ,err :weight bold)))) - `(rainbow-delimiters-unmatched-face ((t (:foreground ,err :weight bold)))) - - ;; Dired - `(dired-directory ((t (:foreground ,dank-cyan :weight bold)))) - `(dired-ignored ((t (:foreground ,dank-gray)))) - `(dired-flagged ((t (:foreground ,dank-red)))) - `(dired-marked ((t (:foreground ,dank-yellow :weight bold)))) - `(dired-symlink ((t (:foreground ,dank-magenta :slant italic)))) - `(dired-header ((t (:foreground ,dank-cyan :weight bold :height 1.1)))) - - ;; Terminal colors - `(term-color-black ((t (:foreground ,term0 :background ,term0)))) - `(term-color-red ((t (:foreground ,term1 :background ,term1)))) - `(term-color-green ((t (:foreground ,term2 :background ,term2)))) - `(term-color-yellow ((t (:foreground ,term3 :background ,term3)))) - `(term-color-blue ((t (:foreground ,term4 :background ,term4)))) - `(term-color-magenta ((t (:foreground ,term5 :background ,term5)))) - `(term-color-cyan ((t (:foreground ,term6 :background ,term6)))) - `(term-color-white ((t (:foreground ,term7 :background ,term7)))) - - ;; EShell - `(eshell-prompt ((t (:foreground ,dank-cyan :weight bold)))) - `(eshell-ls-directory ((t (:foreground ,dank-cyan :weight bold)))) - `(eshell-ls-symlink ((t (:foreground ,dank-magenta :slant italic)))) - `(eshell-ls-executable ((t (:foreground ,dank-green)))) - `(eshell-ls-archive ((t (:foreground ,dank-yellow)))) - `(eshell-ls-backup ((t (:foreground ,dank-gray)))) - `(eshell-ls-clutter ((t (:foreground ,dank-red)))) - `(eshell-ls-missing ((t (:foreground ,dank-red)))) - `(eshell-ls-product ((t (:foreground ,on-surface-variant)))) - `(eshell-ls-readonly ((t (:foreground ,dank-gray)))) - `(eshell-ls-special ((t (:foreground ,dank-blue)))) - `(eshell-ls-unreadable ((t (:foreground ,dank-gray)))) - - ;; Improved markdown mode - `(markdown-header-face ((t (:foreground ,dank-cyan :weight bold)))) - `(markdown-header-face-1 ((t (:foreground ,dank-cyan :weight bold :height 1.2)))) - `(markdown-header-face-2 ((t (:foreground ,dank-blue :weight bold :height 1.1)))) - `(markdown-header-face-3 ((t (:foreground ,dank-magenta :weight bold)))) - `(markdown-header-face-4 ((t (:foreground ,dank-green :weight bold)))) - `(markdown-inline-code-face ((t (:foreground ,dank-yellow-bright :background ,surface-container-low :inherit fixed-pitch)))) - `(markdown-code-face ((t (:background ,surface-container-low :extend t :inherit fixed-pitch)))) - `(markdown-pre-face ((t (:background ,surface-container-low :inherit fixed-pitch)))) - `(markdown-table-face ((t (:foreground ,dank-magenta :inherit fixed-pitch)))) - - ;; Web mode - `(web-mode-html-tag-face ((t (:foreground ,dank-cyan)))) - `(web-mode-html-tag-bracket-face ((t (:foreground ,dank-gray)))) - `(web-mode-html-attr-name-face ((t (:foreground ,dank-yellow)))) - `(web-mode-html-attr-value-face ((t (:foreground ,dank-green)))) - `(web-mode-css-selector-face ((t (:foreground ,dank-cyan)))) - `(web-mode-css-property-name-face ((t (:foreground ,dank-blue)))) - `(web-mode-css-string-face ((t (:foreground ,dank-green)))) - - ;; Flycheck - `(flycheck-error ((t (:underline (:style wave :color ,err))))) - `(flycheck-warning ((t (:underline (:style wave :color ,dank-yellow))))) - `(flycheck-info ((t (:underline (:style wave :color ,dank-blue))))) - `(flycheck-fringe-error ((t (:foreground ,err)))) - `(flycheck-fringe-warning ((t (:foreground ,dank-yellow)))) - `(flycheck-fringe-info ((t (:foreground ,dank-blue)))) - - ;; Mini-buffer customization - `(minibuffer-prompt ((t (:foreground ,dank-cyan :weight bold)))) - - ;; Improved search highlighting - `(lsp-face-highlight-textual ((t (:background ,primary-container :foreground ,dank-cyan-bright :weight bold)))) - `(lsp-face-highlight-read ((t (:background ,secondary-container :foreground ,dank-yellow-bright :weight bold)))) - `(lsp-face-highlight-write ((t (:background ,tertiary-container :foreground ,dank-green-bright :weight bold)))) - - ;; Info and help modes - `(info-title-1 ((t (:foreground ,dank-cyan :weight bold :height 1.3)))) - `(info-title-2 ((t (:foreground ,dank-blue :weight bold :height 1.2)))) - `(info-title-3 ((t (:foreground ,dank-magenta :weight bold :height 1.1)))) - `(info-title-4 ((t (:foreground ,dank-green :weight bold)))) - `(Info-quoted ((t (:foreground ,dank-yellow)))) - `(info-menu-header ((t (:foreground ,dank-cyan :weight bold)))) - `(info-menu-star ((t (:foreground ,dank-cyan)))) - `(info-node ((t (:foreground ,dank-blue :weight bold)))) - - ;; Tabs - `(tab-bar ((t (:background ,surface-container :foreground ,on-surface :box nil)))) - `(tab-bar-tab ((t (:background ,surface-container-high :foreground ,dank-cyan :weight bold :box nil)))) - `(tab-bar-tab-inactive ((t (:background ,surface :foreground ,dank-gray :box nil)))) - - `(tab-line ((t (:background ,surface-container :foreground ,on-surface :box nil)))) - `(tab-line-tab ((t (:background ,surface :foreground ,dank-gray :box nil)))) - `(tab-line-tab-current ((t (:background ,surface-container-high :foreground ,dank-cyan :weight bold :box nil)))) - `(tab-line-tab-inactive ((t (:background ,surface :foreground ,dank-gray :box nil)))) - `(tab-line-highlight ((t (:background ,surface-container-highest :foreground ,dank-cyan-bright)))) - - `(centaur-tabs-default ((t (:background ,surface-container :foreground ,on-surface)))) - `(centaur-tabs-selected ((t (:background ,surface-container-high :foreground ,dank-cyan :weight bold)))) - `(centaur-tabs-unselected ((t (:background ,surface :foreground ,dank-gray)))) - `(centaur-tabs-selected-modified ((t (:background ,surface-container-high :foreground ,dank-yellow :weight bold)))) - `(centaur-tabs-unselected-modified ((t (:background ,surface :foreground ,dank-yellow)))) - `(centaur-tabs-active-bar-face ((t (:background ,dank-cyan)))) - - ;; Fixed-pitch faces - `(fixed-pitch ((t (:family "monospace")))) - `(fixed-pitch-serif ((t (:family "monospace serif")))) - - ;; Variable-pitch face - `(variable-pitch ((t (:family "sans serif")))) - )) - -;; Add org-mode hooks for hiding leading stars -(with-eval-after-load 'org - (setq org-hide-leading-stars t) - (setq org-startup-indented t)) - -;;;###autoload -(when load-file-name - (add-to-list 'custom-theme-load-path - (file-name-as-directory (file-name-directory load-file-name)))) - -(provide-theme 'dank-emacs) -;;; dank-emacs-theme.el ends here diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-zed.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-zed.json deleted file mode 100644 index dd10415..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank-zed.json +++ /dev/null @@ -1,1523 +0,0 @@ -{ - "$schema": "https://zed.dev/schema/themes/v0.2.0.json", - "name": "Dynamic Base16 DankShell", - "author": "Adarsh219", - "themes": [ - { - "name": "DankShell Dark", - "appearance": "dark", - "style": { - "accents": [ - "{{colors.primary.dark.hex}}", - "{{colors.secondary.dark.hex}}", - "{{colors.tertiary.dark.hex}}" - ], - "background.appearance": "opaque", - "border": "{{colors.outline_variant.dark.hex}}", - "border.variant": "{{colors.outline.dark.hex}}", - "border.focused": "{{colors.primary.dark.hex}}", - "border.selected": "{{colors.primary.dark.hex}}", - "border.transparent": null, - "border.disabled": "{{colors.outline_variant.dark.hex}}60", - "elevated_surface.background": "{{colors.surface_container_high.dark.hex}}", - "surface.background": "{{colors.surface.dark.hex}}", - "background": "{{colors.surface_dim.dark.hex}}", - "element.background": "{{colors.surface_container.dark.hex}}", - "element.hover": "{{colors.surface_container_high.dark.hex}}", - "element.active": "{{colors.surface_container_highest.dark.hex}}", - "element.selected": "{{colors.secondary_container.dark.hex}}", - "element.disabled": "{{colors.surface_variant.dark.hex}}", - "drop_target.background": "{{colors.primary_container.dark.hex}}80", - "ghost_element.background": null, - "ghost_element.hover": "{{colors.surface_container.dark.hex}}80", - "ghost_element.active": "{{colors.surface_container_high.dark.hex}}", - "ghost_element.selected": "{{colors.secondary_container.dark.hex}}80", - "ghost_element.disabled": "{{colors.surface_variant.dark.hex}}60", - "text": "{{colors.on_surface.dark.hex}}", - "text.muted": "{{colors.on_surface_variant.dark.hex}}", - "text.placeholder": "{{colors.on_surface_variant.dark.hex}}99", - "text.disabled": "{{colors.on_surface.dark.hex}}60", - "text.accent": "{{colors.primary.dark.hex}}", - "icon": "{{colors.on_surface.dark.hex}}", - "icon.muted": "{{colors.on_surface_variant.dark.hex}}", - "icon.disabled": "{{colors.on_surface.dark.hex}}60", - "icon.placeholder": "{{colors.on_surface_variant.dark.hex}}80", - "icon.accent": "{{colors.primary.dark.hex}}", - "status_bar.background": "{{colors.surface_dim.dark.hex}}", - "title_bar.background": "{{colors.surface_dim.dark.hex}}", - "title_bar.inactive_background": "{{colors.surface_dim.dark.hex}}", - "toolbar.background": "{{colors.background.dark.hex}}", - "tab_bar.background": "{{colors.surface.dark.hex}}", - "tab.inactive_background": "{{colors.surface.dark.hex}}", - "tab.active_background": "{{colors.background.dark.hex}}", - "search.match_background": "{{dank16.color3.dark.hex}}50", - "search.active_match_background": "{{dank16.color9.dark.hex}}66", - "panel.background": "{{colors.surface.dark.hex}}", - "panel.focused_border": null, - "pane.focused_border": null, - "scrollbar.thumb.background": "{{colors.on_surface_variant.dark.hex}}50", - "scrollbar.thumb.hover_background": "{{colors.on_surface_variant.dark.hex}}80", - "scrollbar.thumb.border": "{{colors.outline_variant.dark.hex}}40", - "scrollbar.track.background": null, - "scrollbar.track.border": "{{colors.outline_variant.dark.hex}}20", - "editor.foreground": "{{colors.on_surface.dark.hex}}", - "editor.background": "{{colors.background.dark.hex}}", - "editor.gutter.background": "{{colors.surface_dim.dark.hex}}", - "editor.subheader.background": "{{colors.surface.dark.hex}}", - "editor.indent_guide": "{{colors.outline_variant.dark.hex}}22", - "editor.indent_guide_active": "{{colors.primary.dark.hex}}99", - "editor.active_line.background": "{{colors.surface_container.dark.hex}}66", - "editor.highlighted_line.background": "{{colors.surface_container.dark.hex}}66", - "editor.line_number": "{{colors.on_surface_variant.dark.hex}}", - "editor.active_line_number": "{{colors.primary.dark.hex}}", - "editor.invisible": "{{colors.outline_variant.dark.hex}}33", - "editor.wrap_guide": "{{colors.outline_variant.dark.hex}}22", - "editor.active_wrap_guide": "{{colors.outline.dark.hex}}80", - "editor.document_highlight.read_background": "{{colors.primary_container.dark.hex}}60", - "editor.document_highlight.write_background": "{{colors.secondary_container.dark.hex}}80", - "terminal.background": "{{colors.background.dark.hex}}", - "terminal.foreground": "{{colors.on_surface.dark.hex}}", - "terminal.bright_foreground": "{{dank16.color15.dark.hex}}", - "terminal.dim_foreground": "{{colors.on_surface_variant.dark.hex}}", - "terminal.ansi.black": "{{dank16.color0.dark.hex}}", - "terminal.ansi.bright_black": "{{dank16.color8.dark.hex}}", - "terminal.ansi.dim_black": "{{dank16.color0.dark.hex}}", - "terminal.ansi.red": "{{dank16.color1.dark.hex}}", - "terminal.ansi.bright_red": "{{dank16.color9.dark.hex}}", - "terminal.ansi.dim_red": "{{dank16.color1.dark.hex}}", - "terminal.ansi.green": "{{dank16.color2.dark.hex}}", - "terminal.ansi.bright_green": "{{dank16.color10.dark.hex}}", - "terminal.ansi.dim_green": "{{dank16.color2.dark.hex}}", - "terminal.ansi.yellow": "{{dank16.color3.dark.hex}}", - "terminal.ansi.bright_yellow": "{{dank16.color11.dark.hex}}", - "terminal.ansi.dim_yellow": "{{dank16.color3.dark.hex}}", - "terminal.ansi.blue": "{{dank16.color4.dark.hex}}", - "terminal.ansi.bright_blue": "{{dank16.color12.dark.hex}}", - "terminal.ansi.dim_blue": "{{dank16.color4.dark.hex}}", - "terminal.ansi.magenta": "{{dank16.color5.dark.hex}}", - "terminal.ansi.bright_magenta": "{{dank16.color13.dark.hex}}", - "terminal.ansi.dim_magenta": "{{dank16.color5.dark.hex}}", - "terminal.ansi.cyan": "{{dank16.color6.dark.hex}}", - "terminal.ansi.bright_cyan": "{{dank16.color14.dark.hex}}", - "terminal.ansi.dim_cyan": "{{dank16.color6.dark.hex}}", - "terminal.ansi.white": "{{dank16.color7.dark.hex}}", - "terminal.ansi.bright_white": "{{dank16.color15.dark.hex}}", - "terminal.ansi.dim_white": "{{dank16.color7.dark.hex}}", - "link_text.hover": "{{colors.primary.dark.hex}}", - "version_control.added": "{{dank16.color2.dark.hex}}", - "version_control.modified": "{{dank16.color3.dark.hex}}", - "version_control.word_added": "{{dank16.color2.dark.hex}}33", - "version_control.word_deleted": "{{dank16.color1.dark.hex}}33", - "version_control.deleted": "{{dank16.color1.dark.hex}}", - "conflict": "{{colors.error.dark.hex}}", - "conflict.background": "{{colors.error_container.dark.hex}}80", - "conflict.border": "{{colors.on_error_container.dark.hex}}", - "created": "{{dank16.color2.dark.hex}}", - "created.background": "{{dank16.color2.dark.hex}}1A", - "created.border": "{{dank16.color2.dark.hex}}", - "deleted": "{{dank16.color1.dark.hex}}", - "deleted.background": "{{dank16.color1.dark.hex}}1A", - "deleted.border": "{{dank16.color1.dark.hex}}", - "error": "{{colors.error.dark.hex}}", - "error.background": "{{colors.error_container.dark.hex}}", - "error.border": "{{colors.on_error_container.dark.hex}}", - "hidden": "{{colors.outline_variant.dark.hex}}", - "hidden.background": "{{colors.outline_variant.dark.hex}}1A", - "hidden.border": "{{colors.outline_variant.dark.hex}}60", - "hint": "{{colors.primary.dark.hex}}", - "hint.background": "{{colors.primary_container.dark.hex}}80", - "hint.border": "{{colors.on_primary_container.dark.hex}}", - "ignored": "{{colors.on_surface_variant.dark.hex}}60", - "ignored.background": "{{colors.surface_variant.dark.hex}}40", - "ignored.border": "{{colors.outline_variant.dark.hex}}40", - "info": "{{colors.primary.dark.hex}}", - "info.background": "{{colors.primary_container.dark.hex}}80", - "info.border": "{{colors.on_primary_container.dark.hex}}", - "modified": "{{dank16.color3.dark.hex}}", - "modified.background": "{{dank16.color3.dark.hex}}1A", - "modified.border": "{{dank16.color3.dark.hex}}", - "predictive": "{{colors.on_surface_variant.dark.hex}}80", - "predictive.border": "{{colors.outline.dark.hex}}", - "predictive.background": "{{colors.surface_container_highest.dark.hex}}80", - "renamed": "{{dank16.color4.dark.hex}}", - "renamed.border": "{{dank16.color4.dark.hex}}", - "renamed.background": "{{dank16.color4.dark.hex}}1A", - "success": "{{dank16.color2.dark.hex}}", - "success.background": "{{dank16.color2.dark.hex}}1A", - "success.border": "{{dank16.color2.dark.hex}}", - "unreachable": "{{colors.on_surface_variant.dark.hex}}60", - "unreachable.background": "{{colors.surface_variant.dark.hex}}40", - "unreachable.border": "{{colors.outline_variant.dark.hex}}60", - "warning": "{{colors.tertiary_fixed_dim.dark.hex}}", - "warning.background": "{{colors.tertiary_container.dark.hex}}80", - "warning.border": "{{colors.on_tertiary_container.dark.hex}}", - "players": [ - { - "cursor": "{{dank16.color4.dark.hex}}", - "background": "{{dank16.color4.dark.hex}}80", - "selection": "{{dank16.color4.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color1.dark.hex}}", - "background": "{{dank16.color1.dark.hex}}80", - "selection": "{{dank16.color1.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color3.dark.hex}}", - "background": "{{dank16.color3.dark.hex}}80", - "selection": "{{dank16.color3.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color5.dark.hex}}", - "background": "{{dank16.color5.dark.hex}}80", - "selection": "{{dank16.color5.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color6.dark.hex}}", - "background": "{{dank16.color6.dark.hex}}80", - "selection": "{{dank16.color6.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color9.dark.hex}}", - "background": "{{dank16.color9.dark.hex}}80", - "selection": "{{dank16.color9.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color10.dark.hex}}", - "background": "{{dank16.color10.dark.hex}}80", - "selection": "{{dank16.color10.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color2.dark.hex}}", - "background": "{{dank16.color2.dark.hex}}80", - "selection": "{{dank16.color2.dark.hex}}3D" - } - ], - "syntax": { - "attribute": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "boolean": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "comment": { - "color": "{{dank16.color8.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "comment.doc": { - "color": "{{dank16.color8.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "constant": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "constructor": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "embedded": { - "color": "{{colors.on_surface.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "emphasis": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "emphasis.strong": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": 700 - }, - "enum": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "function": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "keyword": { - "color": "{{dank16.color5.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "label": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "link_text": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "link_uri": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": "normal", - "font_weight": null - }, - "number": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "operator": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "property": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation": { - "color": "{{colors.on_surface_variant.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.bracket": { - "color": "{{colors.outline.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.delimiter": { - "color": "{{colors.outline.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.list_marker": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.special": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "selector": { - "color": "{{dank16.color3.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "selector.pseudo": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string": { - "color": "{{dank16.color2.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.escape": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.regex": { - "color": "{{dank16.color10.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special.symbol": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "tag": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "text.literal": { - "color": "{{dank16.color2.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "title": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": 700 - }, - "type": { - "color": "{{dank16.color3.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "variable": { - "color": "{{colors.on_surface.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "variable.special": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "variant": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - } - } - } - }, - { - "name": "DankShell Light", - "appearance": "light", - "style": { - "accents": [ - "{{colors.primary.light.hex}}", - "{{colors.secondary.light.hex}}", - "{{colors.tertiary.light.hex}}" - ], - "background.appearance": "opaque", - "border": "{{colors.outline_variant.light.hex}}", - "border.variant": "{{colors.outline.light.hex}}", - "border.focused": "{{colors.primary.light.hex}}", - "border.selected": "{{colors.primary.light.hex}}", - "border.transparent": null, - "border.disabled": "{{colors.outline_variant.light.hex}}60", - "elevated_surface.background": "{{colors.surface_container_high.light.hex}}", - "surface.background": "{{colors.surface.light.hex}}", - "background": "{{colors.surface_dim.light.hex}}", - "element.background": "{{colors.surface_container.light.hex}}", - "element.hover": "{{colors.surface_container_high.light.hex}}", - "element.active": "{{colors.surface_container_highest.light.hex}}", - "element.selected": "{{colors.secondary_container.light.hex}}", - "element.disabled": "{{colors.surface_variant.light.hex}}", - "drop_target.background": "{{colors.primary_container.light.hex}}80", - "ghost_element.background": null, - "ghost_element.hover": "{{colors.surface_container.light.hex}}80", - "ghost_element.active": "{{colors.surface_container_high.light.hex}}", - "ghost_element.selected": "{{colors.secondary_container.light.hex}}80", - "ghost_element.disabled": "{{colors.surface_variant.light.hex}}60", - "text": "{{colors.on_surface.light.hex}}", - "text.muted": "{{colors.on_surface_variant.light.hex}}", - "text.placeholder": "{{colors.on_surface_variant.light.hex}}99", - "text.disabled": "{{colors.on_surface.light.hex}}60", - "text.accent": "{{colors.primary.light.hex}}", - "icon": "{{colors.on_surface.light.hex}}", - "icon.muted": "{{colors.on_surface_variant.light.hex}}", - "icon.disabled": "{{colors.on_surface.light.hex}}60", - "icon.placeholder": "{{colors.on_surface_variant.light.hex}}80", - "icon.accent": "{{colors.primary.light.hex}}", - "status_bar.background": "{{colors.surface_dim.light.hex}}", - "title_bar.background": "{{colors.surface_dim.light.hex}}", - "title_bar.inactive_background": "{{colors.surface_dim.light.hex}}", - "toolbar.background": "{{colors.background.light.hex}}", - "tab_bar.background": "{{colors.surface.light.hex}}", - "tab.inactive_background": "{{colors.surface.light.hex}}", - "tab.active_background": "{{colors.background.light.hex}}", - "search.match_background": "{{dank16.color3.light.hex}}50", - "search.active_match_background": "{{dank16.color9.light.hex}}66", - "panel.background": "{{colors.surface.light.hex}}", - "panel.focused_border": null, - "pane.focused_border": null, - "scrollbar.thumb.background": "{{colors.on_surface_variant.light.hex}}50", - "scrollbar.thumb.hover_background": "{{colors.on_surface_variant.light.hex}}C0", - "scrollbar.thumb.border": "{{colors.outline_variant.light.hex}}40", - "scrollbar.track.background": null, - "scrollbar.track.border": "{{colors.outline_variant.light.hex}}20", - "editor.foreground": "{{colors.on_surface.light.hex}}", - "editor.background": "{{colors.background.light.hex}}", - "editor.gutter.background": "{{colors.surface_dim.light.hex}}", - "editor.subheader.background": "{{colors.surface.light.hex}}", - "editor.indent_guide": "{{colors.outline_variant.light.hex}}22", - "editor.indent_guide_active": "{{colors.outline.light.hex}}99", - "editor.active_line.background": "{{colors.surface_container.light.hex}}66", - "editor.highlighted_line.background": "{{colors.surface_container.light.hex}}66", - "editor.line_number": "{{colors.on_surface_variant.light.hex}}", - "editor.active_line_number": "{{colors.primary.light.hex}}", - "editor.invisible": "{{colors.outline_variant.light.hex}}33", - "editor.wrap_guide": "{{colors.outline_variant.light.hex}}22", - "editor.active_wrap_guide": "{{colors.outline.light.hex}}80", - "editor.document_highlight.read_background": "{{colors.primary_container.light.hex}}60", - "editor.document_highlight.write_background": "{{colors.secondary_container.light.hex}}80", - "terminal.background": "{{colors.background.light.hex}}", - "terminal.foreground": "{{colors.on_surface.light.hex}}", - "terminal.bright_foreground": "{{dank16.color15.light.hex}}", - "terminal.dim_foreground": "{{colors.on_surface_variant.light.hex}}", - "terminal.ansi.black": "{{dank16.color0.light.hex}}", - "terminal.ansi.bright_black": "{{dank16.color8.light.hex}}", - "terminal.ansi.dim_black": "{{dank16.color0.light.hex}}", - "terminal.ansi.red": "{{dank16.color1.light.hex}}", - "terminal.ansi.bright_red": "{{dank16.color9.light.hex}}", - "terminal.ansi.dim_red": "{{dank16.color1.light.hex}}", - "terminal.ansi.green": "{{dank16.color2.light.hex}}", - "terminal.ansi.bright_green": "{{dank16.color10.light.hex}}", - "terminal.ansi.dim_green": "{{dank16.color2.light.hex}}", - "terminal.ansi.yellow": "{{dank16.color3.light.hex}}", - "terminal.ansi.bright_yellow": "{{dank16.color11.light.hex}}", - "terminal.ansi.dim_yellow": "{{dank16.color3.light.hex}}", - "terminal.ansi.blue": "{{dank16.color4.light.hex}}", - "terminal.ansi.bright_blue": "{{dank16.color12.light.hex}}", - "terminal.ansi.dim_blue": "{{dank16.color4.light.hex}}", - "terminal.ansi.magenta": "{{dank16.color5.light.hex}}", - "terminal.ansi.bright_magenta": "{{dank16.color13.light.hex}}", - "terminal.ansi.dim_magenta": "{{dank16.color5.light.hex}}", - "terminal.ansi.cyan": "{{dank16.color6.light.hex}}", - "terminal.ansi.bright_cyan": "{{dank16.color14.light.hex}}", - "terminal.ansi.dim_cyan": "{{dank16.color6.light.hex}}", - "terminal.ansi.white": "{{dank16.color7.light.hex}}", - "terminal.ansi.bright_white": "{{dank16.color15.light.hex}}", - "terminal.ansi.dim_white": "{{dank16.color7.light.hex}}", - "link_text.hover": "{{colors.primary.light.hex}}", - "version_control.added": "{{dank16.color2.light.hex}}", - "version_control.modified": "{{dank16.color3.light.hex}}", - "version_control.word_added": "{{dank16.color2.light.hex}}33", - "version_control.word_deleted": "{{dank16.color1.light.hex}}33", - "version_control.deleted": "{{dank16.color1.light.hex}}", - "conflict": "{{colors.error.light.hex}}", - "conflict.background": "{{colors.error_container.light.hex}}80", - "conflict.border": "{{colors.on_error_container.light.hex}}", - "created": "{{dank16.color2.light.hex}}", - "created.background": "{{dank16.color2.light.hex}}1A", - "created.border": "{{dank16.color2.light.hex}}", - "deleted": "{{dank16.color1.light.hex}}", - "deleted.background": "{{dank16.color1.light.hex}}1A", - "deleted.border": "{{dank16.color1.light.hex}}", - "error": "{{colors.error.light.hex}}", - "error.background": "{{colors.error_container.light.hex}}", - "error.border": "{{colors.on_error_container.light.hex}}", - "hidden": "{{colors.outline_variant.light.hex}}", - "hidden.background": "{{colors.outline_variant.light.hex}}1A", - "hidden.border": "{{colors.outline_variant.light.hex}}60", - "hint": "{{colors.primary.light.hex}}", - "hint.background": "{{colors.primary_container.light.hex}}80", - "hint.border": "{{colors.on_primary_container.light.hex}}", - "ignored": "{{colors.on_surface_variant.light.hex}}60", - "ignored.background": "{{colors.surface_variant.light.hex}}40", - "ignored.border": "{{colors.outline_variant.light.hex}}40", - "info": "{{colors.primary.light.hex}}", - "info.background": "{{colors.primary_container.light.hex}}80", - "info.border": "{{colors.on_primary_container.light.hex}}", - "modified": "{{dank16.color3.light.hex}}", - "modified.background": "{{dank16.color3.light.hex}}1A", - "modified.border": "{{dank16.color3.light.hex}}", - "predictive": "{{colors.on_surface_variant.light.hex}}80", - "predictive.border": "{{colors.outline.light.hex}}", - "predictive.background": "{{colors.surface_container_highest.light.hex}}80", - "renamed": "{{dank16.color4.light.hex}}", - "renamed.border": "{{dank16.color4.light.hex}}", - "renamed.background": "{{dank16.color4.light.hex}}1A", - "success": "{{dank16.color2.light.hex}}", - "success.background": "{{dank16.color2.light.hex}}1A", - "success.border": "{{dank16.color2.light.hex}}", - "unreachable": "{{colors.on_surface_variant.light.hex}}60", - "unreachable.background": "{{colors.surface_variant.light.hex}}40", - "unreachable.border": "{{colors.outline_variant.light.hex}}60", - "warning": "{{colors.tertiary_fixed_dim.light.hex}}", - "warning.background": "{{colors.tertiary_container.light.hex}}80", - "warning.border": "{{colors.on_tertiary_container.light.hex}}", - "players": [ - { - "cursor": "{{dank16.color4.light.hex}}", - "background": "{{dank16.color4.light.hex}}80", - "selection": "{{dank16.color4.light.hex}}3D" - }, - { - "cursor": "{{dank16.color1.light.hex}}", - "background": "{{dank16.color1.light.hex}}80", - "selection": "{{dank16.color1.light.hex}}3D" - }, - { - "cursor": "{{dank16.color3.light.hex}}", - "background": "{{dank16.color3.light.hex}}80", - "selection": "{{dank16.color3.light.hex}}3D" - }, - { - "cursor": "{{dank16.color5.light.hex}}", - "background": "{{dank16.color5.light.hex}}80", - "selection": "{{dank16.color5.light.hex}}3D" - }, - { - "cursor": "{{dank16.color6.light.hex}}", - "background": "{{dank16.color6.light.hex}}80", - "selection": "{{dank16.color6.light.hex}}3D" - }, - { - "cursor": "{{dank16.color9.light.hex}}", - "background": "{{dank16.color9.light.hex}}80", - "selection": "{{dank16.color9.light.hex}}3D" - }, - { - "cursor": "{{dank16.color10.light.hex}}", - "background": "{{dank16.color10.light.hex}}80", - "selection": "{{dank16.color10.light.hex}}3D" - }, - { - "cursor": "{{dank16.color2.light.hex}}", - "background": "{{dank16.color2.light.hex}}80", - "selection": "{{dank16.color2.light.hex}}3D" - } - ], - "syntax": { - "attribute": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "boolean": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "comment": { - "color": "{{dank16.color8.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "comment.doc": { - "color": "{{dank16.color8.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "constant": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "constructor": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "embedded": { - "color": "{{colors.on_surface.light.hex}}", - "font_style": null, - "font_weight": null - }, - "emphasis": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "emphasis.strong": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": 700 - }, - "enum": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "function": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "keyword": { - "color": "{{dank16.color5.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "label": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "link_text": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "link_uri": { - "color": "{{dank16.color6.light.hex}}", - "font_style": "normal", - "font_weight": null - }, - "number": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "operator": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "property": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation": { - "color": "{{colors.on_surface_variant.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.bracket": { - "color": "{{colors.outline.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.delimiter": { - "color": "{{colors.outline.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.list_marker": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.special": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "selector": { - "color": "{{dank16.color3.light.hex}}", - "font_style": null, - "font_weight": null - }, - "selector.pseudo": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string": { - "color": "{{dank16.color2.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.escape": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.regex": { - "color": "{{dank16.color10.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special.symbol": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "tag": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "text.literal": { - "color": "{{dank16.color2.light.hex}}", - "font_style": null, - "font_weight": null - }, - "title": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": 700 - }, - "type": { - "color": "{{dank16.color3.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "variable": { - "color": "{{colors.on_surface.light.hex}}", - "font_style": null, - "font_weight": null - }, - "variable.special": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "variant": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - } - } - } - }, - { - "name": "DankShell Dark Transparent", - "appearance": "dark", - "style": { - "accents": [ - "{{colors.primary.dark.hex}}", - "{{colors.secondary.dark.hex}}", - "{{colors.tertiary.dark.hex}}" - ], - "background.appearance": "blurred", - "border": "{{colors.outline_variant.dark.hex}}", - "border.variant": "{{colors.outline.dark.hex}}", - "border.focused": "{{colors.primary.dark.hex}}", - "border.selected": "{{colors.primary.dark.hex}}", - "border.transparent": null, - "border.disabled": "{{colors.outline_variant.dark.hex}}60", - "elevated_surface.background": "{{colors.surface_container_high.dark.hex}}B6", - "surface.background": "{{colors.surface.dark.hex}}B6", - "background": null, - "element.background": "{{colors.surface_container.dark.hex}}B6", - "element.hover": "{{colors.surface_container_high.dark.hex}}B6", - "element.active": "{{colors.surface_container_highest.dark.hex}}B6", - "element.selected": "{{colors.secondary_container.dark.hex}}B6", - "element.disabled": "{{colors.surface_variant.dark.hex}}B6", - "drop_target.background": "{{colors.primary_container.dark.hex}}80", - "ghost_element.background": null, - "ghost_element.hover": "{{colors.surface_container.dark.hex}}80", - "ghost_element.active": "{{colors.surface_container_high.dark.hex}}B6", - "ghost_element.selected": "{{colors.secondary_container.dark.hex}}80", - "ghost_element.disabled": "{{colors.surface_variant.dark.hex}}60", - "text": "{{colors.on_surface.dark.hex}}", - "text.muted": "{{colors.on_surface_variant.dark.hex}}", - "text.placeholder": "{{colors.on_surface_variant.dark.hex}}99", - "text.disabled": "{{colors.on_surface.dark.hex}}60", - "text.accent": "{{colors.primary.dark.hex}}", - "icon": "{{colors.on_surface.dark.hex}}", - "icon.muted": "{{colors.on_surface_variant.dark.hex}}", - "icon.disabled": "{{colors.on_surface.dark.hex}}60", - "icon.placeholder": "{{colors.on_surface_variant.dark.hex}}80", - "icon.accent": "{{colors.primary.dark.hex}}", - "status_bar.background": "{{colors.surface_dim.dark.hex}}B6", - "title_bar.background": "{{colors.surface_dim.dark.hex}}B6", - "title_bar.inactive_background": "{{colors.surface_dim.dark.hex}}B6", - "toolbar.background": "{{colors.background.dark.hex}}B6", - "tab_bar.background": "{{colors.surface.dark.hex}}B6", - "tab.inactive_background": "{{colors.surface.dark.hex}}B6", - "tab.active_background": "{{colors.background.dark.hex}}B6", - "search.match_background": "{{dank16.color3.dark.hex}}50", - "search.active_match_background": "{{dank16.color9.dark.hex}}66", - "panel.background": "{{colors.surface.dark.hex}}B6", - "panel.focused_border": null, - "pane.focused_border": null, - "scrollbar.thumb.background": "{{colors.on_surface_variant.dark.hex}}50", - "scrollbar.thumb.hover_background": "{{colors.on_surface_variant.dark.hex}}80", - "scrollbar.thumb.border": "{{colors.outline_variant.dark.hex}}40", - "scrollbar.track.background": null, - "scrollbar.track.border": "{{colors.outline_variant.dark.hex}}20", - "editor.foreground": "{{colors.on_surface.dark.hex}}", - "editor.background": "{{colors.background.dark.hex}}B6", - "editor.gutter.background": "{{colors.surface_dim.dark.hex}}B6", - "editor.subheader.background": "{{colors.surface.dark.hex}}B6", - "editor.indent_guide": "{{colors.outline_variant.dark.hex}}22", - "editor.indent_guide_active": "{{colors.primary.dark.hex}}99", - "editor.active_line.background": "{{colors.surface_container.dark.hex}}66", - "editor.highlighted_line.background": "{{colors.surface_container.dark.hex}}66", - "editor.line_number": "{{colors.on_surface_variant.dark.hex}}", - "editor.active_line_number": "{{colors.primary.dark.hex}}", - "editor.invisible": "{{colors.outline_variant.dark.hex}}33", - "editor.wrap_guide": "{{colors.outline_variant.dark.hex}}22", - "editor.active_wrap_guide": "{{colors.outline.dark.hex}}80", - "editor.document_highlight.read_background": "{{colors.primary_container.dark.hex}}60", - "editor.document_highlight.write_background": "{{colors.secondary_container.dark.hex}}80", - "terminal.background": "{{colors.background.dark.hex}}B6", - "terminal.foreground": "{{colors.on_surface.dark.hex}}", - "terminal.bright_foreground": "{{dank16.color15.dark.hex}}", - "terminal.dim_foreground": "{{colors.on_surface_variant.dark.hex}}", - "terminal.ansi.black": "{{dank16.color0.dark.hex}}", - "terminal.ansi.bright_black": "{{dank16.color8.dark.hex}}", - "terminal.ansi.dim_black": "{{dank16.color0.dark.hex}}", - "terminal.ansi.red": "{{dank16.color1.dark.hex}}", - "terminal.ansi.bright_red": "{{dank16.color9.dark.hex}}", - "terminal.ansi.dim_red": "{{dank16.color1.dark.hex}}", - "terminal.ansi.green": "{{dank16.color2.dark.hex}}", - "terminal.ansi.bright_green": "{{dank16.color10.dark.hex}}", - "terminal.ansi.dim_green": "{{dank16.color2.dark.hex}}", - "terminal.ansi.yellow": "{{dank16.color3.dark.hex}}", - "terminal.ansi.bright_yellow": "{{dank16.color11.dark.hex}}", - "terminal.ansi.dim_yellow": "{{dank16.color3.dark.hex}}", - "terminal.ansi.blue": "{{dank16.color4.dark.hex}}", - "terminal.ansi.bright_blue": "{{dank16.color12.dark.hex}}", - "terminal.ansi.dim_blue": "{{dank16.color4.dark.hex}}", - "terminal.ansi.magenta": "{{dank16.color5.dark.hex}}", - "terminal.ansi.bright_magenta": "{{dank16.color13.dark.hex}}", - "terminal.ansi.dim_magenta": "{{dank16.color5.dark.hex}}", - "terminal.ansi.cyan": "{{dank16.color6.dark.hex}}", - "terminal.ansi.bright_cyan": "{{dank16.color14.dark.hex}}", - "terminal.ansi.dim_cyan": "{{dank16.color6.dark.hex}}", - "terminal.ansi.white": "{{dank16.color7.dark.hex}}", - "terminal.ansi.bright_white": "{{dank16.color15.dark.hex}}", - "terminal.ansi.dim_white": "{{dank16.color7.dark.hex}}", - "link_text.hover": "{{colors.primary.dark.hex}}", - "version_control.added": "{{dank16.color2.dark.hex}}", - "version_control.modified": "{{dank16.color3.dark.hex}}", - "version_control.word_added": "{{dank16.color2.dark.hex}}33", - "version_control.word_deleted": "{{dank16.color1.dark.hex}}33", - "version_control.deleted": "{{dank16.color1.dark.hex}}", - "conflict": "{{colors.error.dark.hex}}", - "conflict.background": "{{colors.error_container.dark.hex}}80", - "conflict.border": "{{colors.on_error_container.dark.hex}}", - "created": "{{dank16.color2.dark.hex}}", - "created.background": "{{dank16.color2.dark.hex}}1A", - "created.border": "{{dank16.color2.dark.hex}}", - "deleted": "{{dank16.color1.dark.hex}}", - "deleted.background": "{{dank16.color1.dark.hex}}1A", - "deleted.border": "{{dank16.color1.dark.hex}}", - "error": "{{colors.error.dark.hex}}", - "error.background": "{{colors.error_container.dark.hex}}", - "error.border": "{{colors.on_error_container.dark.hex}}", - "hidden": "{{colors.outline_variant.dark.hex}}", - "hidden.background": "{{colors.outline_variant.dark.hex}}1A", - "hidden.border": "{{colors.outline_variant.dark.hex}}60", - "hint": "{{colors.primary.dark.hex}}", - "hint.background": "{{colors.primary_container.dark.hex}}80", - "hint.border": "{{colors.on_primary_container.dark.hex}}", - "ignored": "{{colors.on_surface_variant.dark.hex}}60", - "ignored.background": "{{colors.surface_variant.dark.hex}}40", - "ignored.border": "{{colors.outline_variant.dark.hex}}40", - "info": "{{colors.primary.dark.hex}}", - "info.background": "{{colors.primary_container.dark.hex}}80", - "info.border": "{{colors.on_primary_container.dark.hex}}", - "modified": "{{dank16.color3.dark.hex}}", - "modified.background": "{{dank16.color3.dark.hex}}1A", - "modified.border": "{{dank16.color3.dark.hex}}", - "predictive": "{{colors.on_surface_variant.dark.hex}}80", - "predictive.border": "{{colors.outline.dark.hex}}", - "predictive.background": "{{colors.surface_container_highest.dark.hex}}80", - "renamed": "{{dank16.color4.dark.hex}}", - "renamed.border": "{{dank16.color4.dark.hex}}", - "renamed.background": "{{dank16.color4.dark.hex}}1A", - "success": "{{dank16.color2.dark.hex}}", - "success.background": "{{dank16.color2.dark.hex}}1A", - "success.border": "{{dank16.color2.dark.hex}}", - "unreachable": "{{colors.on_surface_variant.dark.hex}}60", - "unreachable.background": "{{colors.surface_variant.dark.hex}}40", - "unreachable.border": "{{colors.outline_variant.dark.hex}}60", - "warning": "{{colors.tertiary_fixed_dim.dark.hex}}", - "warning.background": "{{colors.tertiary_container.dark.hex}}80", - "warning.border": "{{colors.on_tertiary_container.dark.hex}}", - "players": [ - { - "cursor": "{{dank16.color4.dark.hex}}", - "background": "{{dank16.color4.dark.hex}}80", - "selection": "{{dank16.color4.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color1.dark.hex}}", - "background": "{{dank16.color1.dark.hex}}80", - "selection": "{{dank16.color1.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color3.dark.hex}}", - "background": "{{dank16.color3.dark.hex}}80", - "selection": "{{dank16.color3.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color5.dark.hex}}", - "background": "{{dank16.color5.dark.hex}}80", - "selection": "{{dank16.color5.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color6.dark.hex}}", - "background": "{{dank16.color6.dark.hex}}80", - "selection": "{{dank16.color6.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color9.dark.hex}}", - "background": "{{dank16.color9.dark.hex}}80", - "selection": "{{dank16.color9.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color10.dark.hex}}", - "background": "{{dank16.color10.dark.hex}}80", - "selection": "{{dank16.color10.dark.hex}}3D" - }, - { - "cursor": "{{dank16.color2.dark.hex}}", - "background": "{{dank16.color2.dark.hex}}80", - "selection": "{{dank16.color2.dark.hex}}3D" - } - ], - "syntax": { - "attribute": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "boolean": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "comment": { - "color": "{{dank16.color8.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "comment.doc": { - "color": "{{dank16.color8.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "constant": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "constructor": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "embedded": { - "color": "{{colors.on_surface.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "emphasis": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "emphasis.strong": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": 700 - }, - "enum": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "function": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "keyword": { - "color": "{{dank16.color5.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "label": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "link_text": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "link_uri": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": "normal", - "font_weight": null - }, - "number": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "operator": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "property": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation": { - "color": "{{colors.on_surface_variant.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.bracket": { - "color": "{{colors.outline.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.delimiter": { - "color": "{{colors.outline.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.list_marker": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.special": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "selector": { - "color": "{{dank16.color3.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "selector.pseudo": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string": { - "color": "{{dank16.color2.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.escape": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.regex": { - "color": "{{dank16.color10.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special.symbol": { - "color": "{{dank16.color6.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "tag": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "text.literal": { - "color": "{{dank16.color2.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "title": { - "color": "{{dank16.color1.dark.hex}}", - "font_style": null, - "font_weight": 700 - }, - "type": { - "color": "{{dank16.color3.dark.hex}}", - "font_style": "italic", - "font_weight": null - }, - "variable": { - "color": "{{colors.on_surface.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "variable.special": { - "color": "{{dank16.color9.dark.hex}}", - "font_style": null, - "font_weight": null - }, - "variant": { - "color": "{{dank16.color4.dark.hex}}", - "font_style": null, - "font_weight": null - } - } - } - }, - { - "name": "DankShell Light Transparent", - "appearance": "light", - "style": { - "accents": [ - "{{colors.primary.light.hex}}", - "{{colors.secondary.light.hex}}", - "{{colors.tertiary.light.hex}}" - ], - "background.appearance": "blurred", - "border": "{{colors.outline_variant.light.hex}}", - "border.variant": "{{colors.outline.light.hex}}", - "border.focused": "{{colors.primary.light.hex}}", - "border.selected": "{{colors.primary.light.hex}}", - "border.transparent": null, - "border.disabled": "{{colors.outline_variant.light.hex}}60", - "elevated_surface.background": "{{colors.surface_container_high.light.hex}}B6", - "surface.background": "{{colors.surface.light.hex}}B6", - "background": null, - "element.background": "{{colors.surface_container.light.hex}}B6", - "element.hover": "{{colors.surface_container_high.light.hex}}B6", - "element.active": "{{colors.surface_container_highest.light.hex}}B6", - "element.selected": "{{colors.secondary_container.light.hex}}B6", - "element.disabled": "{{colors.surface_variant.light.hex}}B6", - "drop_target.background": "{{colors.primary_container.light.hex}}80", - "ghost_element.background": null, - "ghost_element.hover": "{{colors.surface_container.light.hex}}80", - "ghost_element.active": "{{colors.surface_container_high.light.hex}}B6", - "ghost_element.selected": "{{colors.secondary_container.light.hex}}80", - "ghost_element.disabled": "{{colors.surface_variant.light.hex}}60", - "text": "{{colors.on_surface.light.hex}}", - "text.muted": "{{colors.on_surface_variant.light.hex}}", - "text.placeholder": "{{colors.on_surface_variant.light.hex}}99", - "text.disabled": "{{colors.on_surface.light.hex}}60", - "text.accent": "{{colors.primary.light.hex}}", - "icon": "{{colors.on_surface.light.hex}}", - "icon.muted": "{{colors.on_surface_variant.light.hex}}", - "icon.disabled": "{{colors.on_surface.light.hex}}60", - "icon.placeholder": "{{colors.on_surface_variant.light.hex}}80", - "icon.accent": "{{colors.primary.light.hex}}", - "status_bar.background": "{{colors.surface_dim.light.hex}}B6", - "title_bar.background": "{{colors.surface_dim.light.hex}}B6", - "title_bar.inactive_background": "{{colors.surface_dim.light.hex}}B6", - "toolbar.background": "{{colors.background.light.hex}}B6", - "tab_bar.background": "{{colors.surface.light.hex}}B6", - "tab.inactive_background": "{{colors.surface.light.hex}}B6", - "tab.active_background": "{{colors.background.light.hex}}B6", - "search.match_background": "{{dank16.color3.light.hex}}50", - "search.active_match_background": "{{dank16.color9.light.hex}}66", - "panel.background": "{{colors.surface.light.hex}}B6", - "panel.focused_border": null, - "pane.focused_border": null, - "scrollbar.thumb.background": "{{colors.on_surface_variant.light.hex}}50", - "scrollbar.thumb.hover_background": "{{colors.on_surface_variant.light.hex}}C0", - "scrollbar.thumb.border": "{{colors.outline_variant.light.hex}}40", - "scrollbar.track.background": null, - "scrollbar.track.border": "{{colors.outline_variant.light.hex}}20", - "editor.foreground": "{{colors.on_surface.light.hex}}", - "editor.background": "{{colors.background.light.hex}}B6", - "editor.gutter.background": "{{colors.surface_dim.light.hex}}B6", - "editor.subheader.background": "{{colors.surface.light.hex}}B6", - "editor.indent_guide": "{{colors.outline_variant.light.hex}}22", - "editor.indent_guide_active": "{{colors.outline.light.hex}}99", - "editor.active_line.background": "{{colors.surface_container.light.hex}}66", - "editor.highlighted_line.background": "{{colors.surface_container.light.hex}}66", - "editor.line_number": "{{colors.on_surface_variant.light.hex}}", - "editor.active_line_number": "{{colors.primary.light.hex}}", - "editor.invisible": "{{colors.outline_variant.light.hex}}33", - "editor.wrap_guide": "{{colors.outline_variant.light.hex}}22", - "editor.active_wrap_guide": "{{colors.outline.light.hex}}80", - "editor.document_highlight.read_background": "{{colors.primary_container.light.hex}}60", - "editor.document_highlight.write_background": "{{colors.secondary_container.light.hex}}80", - "terminal.background": "{{colors.background.light.hex}}B6", - "terminal.foreground": "{{colors.on_surface.light.hex}}", - "terminal.bright_foreground": "{{dank16.color15.light.hex}}", - "terminal.dim_foreground": "{{colors.on_surface_variant.light.hex}}", - "terminal.ansi.black": "{{dank16.color0.light.hex}}", - "terminal.ansi.bright_black": "{{dank16.color8.light.hex}}", - "terminal.ansi.dim_black": "{{dank16.color0.light.hex}}", - "terminal.ansi.red": "{{dank16.color1.light.hex}}", - "terminal.ansi.bright_red": "{{dank16.color9.light.hex}}", - "terminal.ansi.dim_red": "{{dank16.color1.light.hex}}", - "terminal.ansi.green": "{{dank16.color2.light.hex}}", - "terminal.ansi.bright_green": "{{dank16.color10.light.hex}}", - "terminal.ansi.dim_green": "{{dank16.color2.light.hex}}", - "terminal.ansi.yellow": "{{dank16.color3.light.hex}}", - "terminal.ansi.bright_yellow": "{{dank16.color11.light.hex}}", - "terminal.ansi.dim_yellow": "{{dank16.color3.light.hex}}", - "terminal.ansi.blue": "{{dank16.color4.light.hex}}", - "terminal.ansi.bright_blue": "{{dank16.color12.light.hex}}", - "terminal.ansi.dim_blue": "{{dank16.color4.light.hex}}", - "terminal.ansi.magenta": "{{dank16.color5.light.hex}}", - "terminal.ansi.bright_magenta": "{{dank16.color13.light.hex}}", - "terminal.ansi.dim_magenta": "{{dank16.color5.light.hex}}", - "terminal.ansi.cyan": "{{dank16.color6.light.hex}}", - "terminal.ansi.bright_cyan": "{{dank16.color14.light.hex}}", - "terminal.ansi.dim_cyan": "{{dank16.color6.light.hex}}", - "terminal.ansi.white": "{{dank16.color7.light.hex}}", - "terminal.ansi.bright_white": "{{dank16.color15.light.hex}}", - "terminal.ansi.dim_white": "{{dank16.color7.light.hex}}", - "link_text.hover": "{{colors.primary.light.hex}}", - "version_control.added": "{{dank16.color2.light.hex}}", - "version_control.modified": "{{dank16.color3.light.hex}}", - "version_control.word_added": "{{dank16.color2.light.hex}}33", - "version_control.word_deleted": "{{dank16.color1.light.hex}}33", - "version_control.deleted": "{{dank16.color1.light.hex}}", - "conflict": "{{colors.error.light.hex}}", - "conflict.background": "{{colors.error_container.light.hex}}80", - "conflict.border": "{{colors.on_error_container.light.hex}}", - "created": "{{dank16.color2.light.hex}}", - "created.background": "{{dank16.color2.light.hex}}1A", - "created.border": "{{dank16.color2.light.hex}}", - "deleted": "{{dank16.color1.light.hex}}", - "deleted.background": "{{dank16.color1.light.hex}}1A", - "deleted.border": "{{dank16.color1.light.hex}}", - "error": "{{colors.error.light.hex}}", - "error.background": "{{colors.error_container.light.hex}}", - "error.border": "{{colors.on_error_container.light.hex}}", - "hidden": "{{colors.outline_variant.light.hex}}", - "hidden.background": "{{colors.outline_variant.light.hex}}1A", - "hidden.border": "{{colors.outline_variant.light.hex}}60", - "hint": "{{colors.primary.light.hex}}", - "hint.background": "{{colors.primary_container.light.hex}}80", - "hint.border": "{{colors.on_primary_container.light.hex}}", - "ignored": "{{colors.on_surface_variant.light.hex}}60", - "ignored.background": "{{colors.surface_variant.light.hex}}40", - "ignored.border": "{{colors.outline_variant.light.hex}}40", - "info": "{{colors.primary.light.hex}}", - "info.background": "{{colors.primary_container.light.hex}}80", - "info.border": "{{colors.on_primary_container.light.hex}}", - "modified": "{{dank16.color3.light.hex}}", - "modified.background": "{{dank16.color3.light.hex}}1A", - "modified.border": "{{dank16.color3.light.hex}}", - "predictive": "{{colors.on_surface_variant.light.hex}}80", - "predictive.border": "{{colors.outline.light.hex}}", - "predictive.background": "{{colors.surface_container_highest.light.hex}}80", - "renamed": "{{dank16.color4.light.hex}}", - "renamed.border": "{{dank16.color4.light.hex}}", - "renamed.background": "{{dank16.color4.light.hex}}1A", - "success": "{{dank16.color2.light.hex}}", - "success.background": "{{dank16.color2.light.hex}}1A", - "success.border": "{{dank16.color2.light.hex}}", - "unreachable": "{{colors.on_surface_variant.light.hex}}60", - "unreachable.background": "{{colors.surface_variant.light.hex}}40", - "unreachable.border": "{{colors.outline_variant.light.hex}}60", - "warning": "{{colors.tertiary_fixed_dim.light.hex}}", - "warning.background": "{{colors.tertiary_container.light.hex}}80", - "warning.border": "{{colors.on_tertiary_container.light.hex}}", - "players": [ - { - "cursor": "{{dank16.color4.light.hex}}", - "background": "{{dank16.color4.light.hex}}80", - "selection": "{{dank16.color4.light.hex}}3D" - }, - { - "cursor": "{{dank16.color1.light.hex}}", - "background": "{{dank16.color1.light.hex}}80", - "selection": "{{dank16.color1.light.hex}}3D" - }, - { - "cursor": "{{dank16.color3.light.hex}}", - "background": "{{dank16.color3.light.hex}}80", - "selection": "{{dank16.color3.light.hex}}3D" - }, - { - "cursor": "{{dank16.color5.light.hex}}", - "background": "{{dank16.color5.light.hex}}80", - "selection": "{{dank16.color5.light.hex}}3D" - }, - { - "cursor": "{{dank16.color6.light.hex}}", - "background": "{{dank16.color6.light.hex}}80", - "selection": "{{dank16.color6.light.hex}}3D" - }, - { - "cursor": "{{dank16.color9.light.hex}}", - "background": "{{dank16.color9.light.hex}}80", - "selection": "{{dank16.color9.light.hex}}3D" - }, - { - "cursor": "{{dank16.color10.light.hex}}", - "background": "{{dank16.color10.light.hex}}80", - "selection": "{{dank16.color10.light.hex}}3D" - }, - { - "cursor": "{{dank16.color2.light.hex}}", - "background": "{{dank16.color2.light.hex}}80", - "selection": "{{dank16.color2.light.hex}}3D" - } - ], - "syntax": { - "attribute": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "boolean": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "comment": { - "color": "{{dank16.color8.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "comment.doc": { - "color": "{{dank16.color8.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "constant": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "constructor": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "embedded": { - "color": "{{colors.on_surface.light.hex}}", - "font_style": null, - "font_weight": null - }, - "emphasis": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "emphasis.strong": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": 700 - }, - "enum": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "function": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "keyword": { - "color": "{{dank16.color5.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "label": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "link_text": { - "color": "{{dank16.color4.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "link_uri": { - "color": "{{dank16.color6.light.hex}}", - "font_style": "normal", - "font_weight": null - }, - "number": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "operator": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "property": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation": { - "color": "{{colors.on_surface_variant.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.bracket": { - "color": "{{colors.outline.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.delimiter": { - "color": "{{colors.outline.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.list_marker": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "punctuation.special": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": null - }, - "selector": { - "color": "{{dank16.color3.light.hex}}", - "font_style": null, - "font_weight": null - }, - "selector.pseudo": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string": { - "color": "{{dank16.color2.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.escape": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.regex": { - "color": "{{dank16.color10.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "string.special.symbol": { - "color": "{{dank16.color6.light.hex}}", - "font_style": null, - "font_weight": null - }, - "tag": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - }, - "text.literal": { - "color": "{{dank16.color2.light.hex}}", - "font_style": null, - "font_weight": null - }, - "title": { - "color": "{{dank16.color1.light.hex}}", - "font_style": null, - "font_weight": 700 - }, - "type": { - "color": "{{dank16.color3.light.hex}}", - "font_style": "italic", - "font_weight": null - }, - "variable": { - "color": "{{colors.on_surface.light.hex}}", - "font_style": null, - "font_weight": null - }, - "variable.special": { - "color": "{{dank16.color9.light.hex}}", - "font_style": null, - "font_weight": null - }, - "variant": { - "color": "{{dank16.color4.light.hex}}", - "font_style": null, - "font_weight": null - } - } - } - } - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank.json deleted file mode 100644 index 15e5a77..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dank.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "dank16": { - "color0": {"dark": "{{dank16.color0.dark.hex}}", "light": "{{dank16.color0.light.hex}}", "default": "{{dank16.color0.default.hex}}"}, - "color1": {"dark": "{{dank16.color1.dark.hex}}", "light": "{{dank16.color1.light.hex}}", "default": "{{dank16.color1.default.hex}}"}, - "color2": {"dark": "{{dank16.color2.dark.hex}}", "light": "{{dank16.color2.light.hex}}", "default": "{{dank16.color2.default.hex}}"}, - "color3": {"dark": "{{dank16.color3.dark.hex}}", "light": "{{dank16.color3.light.hex}}", "default": "{{dank16.color3.default.hex}}"}, - "color4": {"dark": "{{dank16.color4.dark.hex}}", "light": "{{dank16.color4.light.hex}}", "default": "{{dank16.color4.default.hex}}"}, - "color5": {"dark": "{{dank16.color5.dark.hex}}", "light": "{{dank16.color5.light.hex}}", "default": "{{dank16.color5.default.hex}}"}, - "color6": {"dark": "{{dank16.color6.dark.hex}}", "light": "{{dank16.color6.light.hex}}", "default": "{{dank16.color6.default.hex}}"}, - "color7": {"dark": "{{dank16.color7.dark.hex}}", "light": "{{dank16.color7.light.hex}}", "default": "{{dank16.color7.default.hex}}"}, - "color8": {"dark": "{{dank16.color8.dark.hex}}", "light": "{{dank16.color8.light.hex}}", "default": "{{dank16.color8.default.hex}}"}, - "color9": {"dark": "{{dank16.color9.dark.hex}}", "light": "{{dank16.color9.light.hex}}", "default": "{{dank16.color9.default.hex}}"}, - "color10": {"dark": "{{dank16.color10.dark.hex}}", "light": "{{dank16.color10.light.hex}}", "default": "{{dank16.color10.default.hex}}"}, - "color11": {"dark": "{{dank16.color11.dark.hex}}", "light": "{{dank16.color11.light.hex}}", "default": "{{dank16.color11.default.hex}}"}, - "color12": {"dark": "{{dank16.color12.dark.hex}}", "light": "{{dank16.color12.light.hex}}", "default": "{{dank16.color12.default.hex}}"}, - "color13": {"dark": "{{dank16.color13.dark.hex}}", "light": "{{dank16.color13.light.hex}}", "default": "{{dank16.color13.default.hex}}"}, - "color14": {"dark": "{{dank16.color14.dark.hex}}", "light": "{{dank16.color14.light.hex}}", "default": "{{dank16.color14.default.hex}}"}, - "color15": {"dark": "{{dank16.color15.dark.hex}}", "light": "{{dank16.color15.light.hex}}", "default": "{{dank16.color15.default.hex}}"} - }, - "colors": { - "dark": { - "background": "{{colors.background.dark.hex}}", - "error": "{{colors.error.dark.hex}}", - "error_container": "{{colors.error_container.dark.hex}}", - "inverse_on_surface": "{{colors.inverse_on_surface.dark.hex}}", - "inverse_primary": "{{colors.inverse_primary.dark.hex}}", - "inverse_surface": "{{colors.inverse_surface.dark.hex}}", - "on_background": "{{colors.on_background.dark.hex}}", - "on_error": "{{colors.on_error.dark.hex}}", - "on_error_container": "{{colors.on_error_container.dark.hex}}", - "on_primary": "{{colors.on_primary.dark.hex}}", - "on_primary_container": "{{colors.on_primary_container.dark.hex}}", - "on_primary_fixed": "{{colors.on_primary_fixed.dark.hex}}", - "on_primary_fixed_variant": "{{colors.on_primary_fixed_variant.dark.hex}}", - "on_secondary": "{{colors.on_secondary.dark.hex}}", - "on_secondary_container": "{{colors.on_secondary_container.dark.hex}}", - "on_secondary_fixed": "{{colors.on_secondary_fixed.dark.hex}}", - "on_secondary_fixed_variant": "{{colors.on_secondary_fixed_variant.dark.hex}}", - "on_surface": "{{colors.on_surface.dark.hex}}", - "on_surface_variant": "{{colors.on_surface_variant.dark.hex}}", - "on_tertiary": "{{colors.on_tertiary.dark.hex}}", - "on_tertiary_container": "{{colors.on_tertiary_container.dark.hex}}", - "on_tertiary_fixed": "{{colors.on_tertiary_fixed.dark.hex}}", - "on_tertiary_fixed_variant": "{{colors.on_tertiary_fixed_variant.dark.hex}}", - "outline": "{{colors.outline.dark.hex}}", - "outline_variant": "{{colors.outline_variant.dark.hex}}", - "primary": "{{colors.primary.dark.hex}}", - "primary_container": "{{colors.primary_container.dark.hex}}", - "primary_fixed": "{{colors.primary_fixed.dark.hex}}", - "primary_fixed_dim": "{{colors.primary_fixed_dim.dark.hex}}", - "scrim": "{{colors.scrim.dark.hex}}", - "secondary": "{{colors.secondary.dark.hex}}", - "secondary_container": "{{colors.secondary_container.dark.hex}}", - "secondary_fixed": "{{colors.secondary_fixed.dark.hex}}", - "secondary_fixed_dim": "{{colors.secondary_fixed_dim.dark.hex}}", - "shadow": "{{colors.shadow.dark.hex}}", - "source_color": "{{colors.source_color.dark.hex}}", - "surface": "{{colors.background.dark.hex}}", - "surface_bright": "{{colors.surface_bright.dark.hex}}", - "surface_container": "{{colors.surface.dark.hex}}", - "surface_container_high": "{{colors.surface_container.dark.hex}}", - "surface_container_highest": "{{colors.surface_container_high.dark.hex}}", - "surface_container_low": "{{colors.surface_container_low.dark.hex}}", - "surface_container_lowest": "{{colors.surface_container_lowest.dark.hex}}", - "surface_dim": "{{colors.surface_dim.dark.hex}}", - "surface_tint": "{{colors.surface_tint.dark.hex}}", - "surface_variant": "{{colors.surface_variant.dark.hex}}", - "tertiary": "{{colors.tertiary.dark.hex}}", - "tertiary_container": "{{colors.tertiary_container.dark.hex}}", - "tertiary_fixed": "{{colors.tertiary_fixed.dark.hex}}", - "tertiary_fixed_dim": "{{colors.tertiary_fixed_dim.dark.hex}}" - }, - "light": { - "background": "{{colors.background.light.hex}}", - "error": "{{colors.error.light.hex}}", - "error_container": "{{colors.error_container.light.hex}}", - "inverse_on_surface": "{{colors.inverse_on_surface.light.hex}}", - "inverse_primary": "{{colors.inverse_primary.light.hex}}", - "inverse_surface": "{{colors.inverse_surface.light.hex}}", - "on_background": "{{colors.on_background.light.hex}}", - "on_error": "{{colors.on_error.light.hex}}", - "on_error_container": "{{colors.on_error_container.light.hex}}", - "on_primary": "{{colors.on_primary.light.hex}}", - "on_primary_container": "{{colors.on_primary_container.light.hex}}", - "on_primary_fixed": "{{colors.on_primary_fixed.light.hex}}", - "on_primary_fixed_variant": "{{colors.on_primary_fixed_variant.light.hex}}", - "on_secondary": "{{colors.on_secondary.light.hex}}", - "on_secondary_container": "{{colors.on_secondary_container.light.hex}}", - "on_secondary_fixed": "{{colors.on_secondary_fixed.light.hex}}", - "on_secondary_fixed_variant": "{{colors.on_secondary_fixed_variant.light.hex}}", - "on_surface": "{{colors.on_surface.light.hex}}", - "on_surface_variant": "{{colors.on_surface_variant.light.hex}}", - "on_tertiary": "{{colors.on_tertiary.light.hex}}", - "on_tertiary_container": "{{colors.on_tertiary_container.light.hex}}", - "on_tertiary_fixed": "{{colors.on_tertiary_fixed.light.hex}}", - "on_tertiary_fixed_variant": "{{colors.on_tertiary_fixed_variant.light.hex}}", - "outline": "{{colors.outline.light.hex}}", - "outline_variant": "{{colors.outline_variant.light.hex}}", - "primary": "{{colors.primary.light.hex}}", - "primary_container": "{{colors.primary_container.light.hex}}", - "primary_fixed": "{{colors.primary_fixed.light.hex}}", - "primary_fixed_dim": "{{colors.primary_fixed_dim.light.hex}}", - "scrim": "{{colors.scrim.light.hex}}", - "secondary": "{{colors.secondary.light.hex}}", - "secondary_container": "{{colors.secondary_container.light.hex}}", - "secondary_fixed": "{{colors.secondary_fixed.light.hex}}", - "secondary_fixed_dim": "{{colors.secondary_fixed_dim.light.hex}}", - "shadow": "{{colors.shadow.light.hex}}", - "source_color": "{{colors.source_color.light.hex}}", - "surface": "{{colors.background.light.hex}}", - "surface_bright": "{{colors.surface_bright.light.hex}}", - "surface_container": "{{colors.surface.light.hex}}", - "surface_container_high": "{{colors.surface_container.light.hex}}", - "surface_container_highest": "{{colors.surface_container_high.light.hex}}", - "surface_container_low": "{{colors.surface_container_low.light.hex}}", - "surface_container_lowest": "{{colors.surface_container_lowest.light.hex}}", - "surface_dim": "{{colors.surface_dim.light.hex}}", - "surface_tint": "{{colors.surface_tint.light.hex}}", - "surface_variant": "{{colors.surface_variant.light.hex}}", - "tertiary": "{{colors.tertiary.light.hex}}", - "tertiary_container": "{{colors.tertiary_container.light.hex}}", - "tertiary_fixed": "{{colors.tertiary_fixed.light.hex}}", - "tertiary_fixed_dim": "{{colors.tertiary_fixed_dim.light.hex}}" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dark-kcolorscheme.colors b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dark-kcolorscheme.colors deleted file mode 100644 index 9773930..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dark-kcolorscheme.colors +++ /dev/null @@ -1,146 +0,0 @@ -[KDE] -contrast=4 - -[General] -ColorScheme=DankMatugen -Name=Dank Shell (matugen) - -[ColorEffects:Disabled] -Color={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ColorAmount=0 -ColorEffect=0 -ContrastAmount=0.65 -ContrastEffect=1 -IntensityAmount=0.1 -IntensityEffect=2 - -[ColorEffects:Inactive] -ChangeSelectionColor=true -Color={{colors.outline.default.red}},{{colors.outline.default.green}},{{colors.outline.default.blue}} -ColorAmount=0.025 -ColorEffect=2 -ContrastAmount=0.1 -ContrastEffect=2 -Enable=false -IntensityAmount=0 -IntensityEffect=0 - -[Colors:Button] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Complementary] -BackgroundAlternate={{colors.surface_container.default.red}},{{colors.surface_container.default.green}},{{colors.surface_container.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header][Inactive] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Selection] -BackgroundAlternate={{colors.primary_container.default.red}},{{colors.primary_container.default.green}},{{colors.primary_container.default.blue}} -BackgroundNormal={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Tooltip] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:View] -BackgroundAlternate={{colors.surface_container_low.default.red}},{{colors.surface_container_low.default.green}},{{colors.surface_container_low.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Window] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[WM] -activeBackground={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -activeBlend={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -activeForeground={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -inactiveBackground={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -inactiveBlend={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -inactiveForeground={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dgop.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dgop.json deleted file mode 100644 index 8b31662..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/dgop.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "ui": { - "border_primary": "{{colors.primary.default.hex}}", - "border_secondary": "{{colors.secondary.default.hex}}", - "header_background": "{{colors.primary.default.hex}}", - "header_text": "{{colors.on_primary.default.hex}}", - "footer_background": "{{colors.surface.default.hex}}", - "footer_text": "{{colors.on_surface_variant.default.hex}}", - "text_primary": "{{colors.on_surface.default.hex}}", - "text_secondary": "{{colors.on_surface_variant.default.hex}}", - "text_accent": "{{colors.primary.default.hex}}", - "selection_background": "{{colors.primary.default.hex}}", - "selection_text": "{{colors.on_primary.default.hex}}" - }, - "charts": { - "network_download": "{{colors.primary.default.hex}}", - "network_upload": "{{colors.primary_container.default.hex}}", - "network_line": "{{colors.secondary.default.hex}}", - "cpu_core_low": "{{colors.primary_container.default.hex}}", - "cpu_core_medium": "{{colors.primary.default.hex}}", - "cpu_core_high": "{{colors.tertiary.default.hex}}", - "disk_read": "{{colors.primary.default.hex}}", - "disk_write": "{{colors.primary_container.default.hex}}" - }, - "progress_bars": { - "memory_low": "{{colors.primary_container.default.hex}}", - "memory_medium": "{{colors.primary.default.hex}}", - "memory_high": "{{colors.tertiary.default.hex}}", - "disk_low": "{{colors.primary_container.default.hex}}", - "disk_medium": "{{colors.primary.default.hex}}", - "disk_high": "{{colors.tertiary.default.hex}}", - "cpu_low": "{{colors.primary_container.default.hex}}", - "cpu_medium": "{{colors.primary.default.hex}}", - "cpu_high": "{{colors.tertiary.default.hex}}", - "progress_background": "{{colors.surface_container.default.hex}}" - }, - "temperature": { - "cold": "{{colors.primary_container.default.hex}}", - "warm": "{{colors.primary.default.hex}}", - "hot": "{{colors.tertiary.default.hex}}", - "danger": "{{colors.error.default.hex}}" - }, - "status": { - "success": "#22C55E", - "warning": "#F59E0B", - "error": "{{colors.error.default.hex}}", - "info": "{{colors.primary.default.hex}}" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/firefox-userchrome.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/firefox-userchrome.css deleted file mode 100644 index 07436cc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/firefox-userchrome.css +++ /dev/null @@ -1,138 +0,0 @@ -@media -moz-pref("userChrome.theme-material") { - :root { - --md-sys-color-primary: {{colors.primary.light.hex}}; - --md-sys-color-surface-tint: {{colors.primary.light.hex}}; - --md-sys-color-on-primary: {{colors.on_primary.light.hex}}; - --md-sys-color-primary-container: {{colors.primary_container.light.hex}}; - --md-sys-color-on-primary-container: {{colors.on_primary_container.light.hex}}; - --md-sys-color-secondary: {{colors.secondary.light.hex}}; - --md-sys-color-on-secondary: {{colors.on_secondary.light.hex}}; - --md-sys-color-secondary-container: {{colors.secondary_container.light.hex}}; - --md-sys-color-on-secondary-container: {{colors.on_secondary_container.light.hex}}; - --md-sys-color-tertiary: {{colors.tertiary.light.hex}}; - --md-sys-color-on-tertiary: {{colors.on_tertiary.light.hex}}; - --md-sys-color-tertiary-container: {{colors.tertiary_container.light.hex}}; - --md-sys-color-on-tertiary-container: {{colors.on_tertiary_container.light.hex}}; - --md-sys-color-error: {{colors.error.light.hex}}; - --md-sys-color-on-error: {{colors.on_error.light.hex}}; - --md-sys-color-error-container: {{colors.error_container.light.hex}}; - --md-sys-color-on-error-container: {{colors.on_error_container.light.hex}}; - --md-sys-color-background: {{colors.background.light.hex}}; - --md-sys-color-on-background: {{colors.on_background.light.hex}}; - --md-sys-color-surface: {{colors.background.light.hex}}; - --md-sys-color-on-surface: {{colors.on_surface.light.hex}}; - --md-sys-color-surface-variant: {{colors.surface_variant.light.hex}}; - --md-sys-color-on-surface-variant: {{colors.on_surface_variant.light.hex}}; - --md-sys-color-outline: {{colors.outline.light.hex}}; - --md-sys-color-outline-variant: {{colors.outline_variant.light.hex}}; - --md-sys-color-shadow: {{colors.shadow.light.hex}}; - --md-sys-color-scrim: {{colors.scrim.light.hex}}; - --md-sys-color-inverse-surface: {{colors.inverse_surface.light.hex}}; - --md-sys-color-inverse-on-surface: {{colors.inverse_on_surface.light.hex}}; - --md-sys-color-inverse-primary: {{colors.inverse_primary.light.hex}}; - --md-sys-color-primary-fixed: {{colors.primary_fixed.light.hex}}; - --md-sys-color-on-primary-fixed: {{colors.on_primary_fixed.light.hex}}; - --md-sys-color-primary-fixed-dim: {{colors.primary_fixed_dim.light.hex}}; - --md-sys-color-on-primary-fixed-variant: {{colors.on_primary_fixed_variant.light.hex}}; - --md-sys-color-secondary-fixed: {{colors.secondary_fixed.light.hex}}; - --md-sys-color-on-secondary-fixed: {{colors.on_secondary_fixed.light.hex}}; - --md-sys-color-secondary-fixed-dim: {{colors.secondary_fixed_dim.light.hex}}; - --md-sys-color-on-secondary-fixed-variant: {{colors.on_secondary_fixed_variant.light.hex}}; - --md-sys-color-tertiary-fixed: {{colors.tertiary_fixed.light.hex}}; - --md-sys-color-on-tertiary-fixed: {{colors.on_tertiary_fixed.light.hex}}; - --md-sys-color-tertiary-fixed-dim: {{colors.tertiary_fixed_dim.light.hex}}; - --md-sys-color-on-tertiary-fixed-variant: {{colors.on_tertiary_fixed_variant.light.hex}}; - --md-sys-color-surface-dim: {{colors.surface_dim.light.hex}}; - --md-sys-color-surface-bright: {{colors.surface_bright.light.hex}}; - --md-sys-color-surface-container-lowest: {{colors.surface_container_lowest.light.hex}}; - --md-sys-color-surface-container-low: {{colors.surface_container_low.light.hex}}; - --md-sys-color-surface-container: {{colors.background.light.hex}}; - --md-sys-color-surface-container-high: {{colors.background.light.hex}}; - --md-sys-color-surface-container-highest: {{colors.background.light.hex}}; - - --m3-radius: 12px; - --m3-radius-sm: 10px; - --m3-elev-0: none; - --m3-elev-1: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 8%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 6%, transparent); - --m3-elev-2: 0 2px 6px color-mix(in srgb, var(--md-sys-color-shadow) 10%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 6%, transparent); - --m3-elev-3: 0 11px 7px color-mix(in srgb, var(--md-sys-color-shadow) 19%, transparent), 0 13px 25px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent); - --m3-elev-4: 0 14px 12px color-mix(in srgb, var(--md-sys-color-shadow) 17%, transparent), 0 20px 40px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent); - --m3-elev-5: 0 17px 17px color-mix(in srgb, var(--md-sys-color-shadow) 15%, transparent), 0 27px 55px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent); - - --tab-height: 34px; - --urlbar-height: 38px; - - --state-hover: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent); - --state-press: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent); - - --focus-ring: 0 0 0 2px color-mix(in srgb, var(--md-sys-color-primary) 70%, transparent); - } -} - -@media (prefers-color-scheme: dark) { - :root { - --md-sys-color-primary: {{colors.primary.dark.hex}}; - --md-sys-color-surface-tint: {{colors.primary.dark.hex}}; - --md-sys-color-on-primary: {{colors.on_primary.dark.hex}}; - --md-sys-color-primary-container: {{colors.primary_container.dark.hex}}; - --md-sys-color-on-primary-container: {{colors.on_primary_container.dark.hex}}; - --md-sys-color-secondary: {{colors.secondary.dark.hex}}; - --md-sys-color-on-secondary: {{colors.on_secondary.dark.hex}}; - --md-sys-color-secondary-container: {{colors.secondary_container.dark.hex}}; - --md-sys-color-on-secondary-container: {{colors.on_secondary_container.dark.hex}}; - --md-sys-color-tertiary: {{colors.tertiary.dark.hex}}; - --md-sys-color-on-tertiary: {{colors.on_tertiary.dark.hex}}; - --md-sys-color-tertiary-container: {{colors.tertiary_container.dark.hex}}; - --md-sys-color-on-tertiary-container: {{colors.on_tertiary_container.dark.hex}}; - --md-sys-color-error: {{colors.error.dark.hex}}; - --md-sys-color-on-error: {{colors.on_error.dark.hex}}; - --md-sys-color-error-container: {{colors.error_container.dark.hex}}; - --md-sys-color-on-error-container: {{colors.on_error_container.dark.hex}}; - --md-sys-color-background: {{colors.background.dark.hex}}; - --md-sys-color-on-background: {{colors.on_background.dark.hex}}; - --md-sys-color-surface: {{colors.surface.dark.hex}}; - --md-sys-color-on-surface: {{colors.on_surface.dark.hex}}; - --md-sys-color-surface-variant: {{colors.surface_variant.dark.hex}}; - --md-sys-color-on-surface-variant: {{colors.on_surface_variant.dark.hex}}; - --md-sys-color-outline: {{colors.outline.dark.hex}}; - --md-sys-color-outline-variant: {{colors.outline_variant.dark.hex}}; - --md-sys-color-shadow: {{colors.shadow.dark.hex}}; - --md-sys-color-scrim: {{colors.scrim.dark.hex}}; - --md-sys-color-inverse-surface: {{colors.inverse_surface.dark.hex}}; - --md-sys-color-inverse-on-surface: {{colors.inverse_on_surface.dark.hex}}; - --md-sys-color-inverse-primary: {{colors.inverse_primary.dark.hex}}; - --md-sys-color-primary-fixed: {{colors.primary_fixed.dark.hex}}; - --md-sys-color-on-primary-fixed: {{colors.on_primary_fixed.dark.hex}}; - --md-sys-color-primary-fixed-dim: {{colors.primary_fixed_dim.dark.hex}}; - --md-sys-color-on-primary-fixed-variant: {{colors.on_primary_fixed_variant.dark.hex}}; - --md-sys-color-secondary-fixed: {{colors.secondary_fixed.dark.hex}}; - --md-sys-color-on-secondary-fixed: {{colors.on_secondary_fixed.dark.hex}}; - --md-sys-color-secondary-fixed-dim: {{colors.secondary_fixed_dim.dark.hex}}; - --md-sys-color-on-secondary-fixed-variant: {{colors.on_secondary_fixed_variant.dark.hex}}; - --md-sys-color-tertiary-fixed: {{colors.tertiary_fixed.dark.hex}}; - --md-sys-color-on-tertiary-fixed: {{colors.on_tertiary_fixed.dark.hex}}; - --md-sys-color-tertiary-fixed-dim: {{colors.tertiary_fixed_dim.dark.hex}}; - --md-sys-color-on-tertiary-fixed-variant: {{colors.on_tertiary_fixed_variant.dark.hex}}; - --md-sys-color-surface-dim: {{colors.surface_dim.dark.hex}}; - --md-sys-color-surface-bright: {{colors.surface_bright.dark.hex}}; - --md-sys-color-surface-container-lowest: {{colors.surface_container_lowest.dark.hex}}; - --md-sys-color-surface-container-low: {{colors.surface_container_low.dark.hex}}; - --md-sys-color-surface-container: {{colors.surface_container.dark.hex}}; - --md-sys-color-surface-container-high: {{colors.surface_container_high.dark.hex}}; - --md-sys-color-surface-container-highest: {{colors.surface_container_highest.dark.hex}}; - - --m3-elev-1: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 50%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 35%, transparent); - --m3-elev-2: 0 4px 10px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 35%, transparent); - --m3-elev-3: 0 11px 7px color-mix(in srgb, var(--md-sys-color-shadow) 45%, transparent), 0 13px 25px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent); - --m3-elev-4: 0 14px 12px color-mix(in srgb, var(--md-sys-color-shadow) 42%, transparent), 0 20px 40px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent); - --m3-elev-5: 0 17px 17px color-mix(in srgb, var(--md-sys-color-shadow) 40%, transparent), 0 27px 55px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent); - - --state-hover: color-mix(in srgb, var(--md-sys-color-on-surface) 6%, transparent); - --state-press: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent); - } -} - -/* idk if this even works, but the suggestion in the material updated readme bricks symbols no matter how many fallbacks I add */ -:root { - font-family: system-ui, "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !important; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/foot.ini b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/foot.ini deleted file mode 100644 index 32270ea..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/foot.ini +++ /dev/null @@ -1,25 +0,0 @@ -[colors-dark] -foreground={{colors.on_surface.default.hex_stripped}} -background={{colors.background.default.hex_stripped}} -selection-foreground={{colors.on_surface.default.hex_stripped}} -selection-background={{colors.primary_container.default.hex_stripped}} -cursor = {{colors.background.default.hex_stripped}} {{colors.primary.default.hex_stripped}} - -regular0={{dank16.color0.default.hex_stripped}} -regular1={{dank16.color1.default.hex_stripped}} -regular2={{dank16.color2.default.hex_stripped}} -regular3={{dank16.color3.default.hex_stripped}} -regular4={{dank16.color4.default.hex_stripped}} -regular5={{dank16.color5.default.hex_stripped}} -regular6={{dank16.color6.default.hex_stripped}} -regular7={{dank16.color7.default.hex_stripped}} -bright0={{dank16.color8.default.hex_stripped}} -bright1={{dank16.color9.default.hex_stripped}} -bright2={{dank16.color10.default.hex_stripped}} -bright3={{dank16.color11.default.hex_stripped}} -bright4={{dank16.color12.default.hex_stripped}} -bright5={{dank16.color13.default.hex_stripped}} -bright6={{dank16.color14.default.hex_stripped}} -bright7={{dank16.color15.default.hex_stripped}} - -dim-blend-towards=<* if {{ is_dark_mode }} *>black<* else *>white<* endif *> diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/ghostty.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/ghostty.conf deleted file mode 100644 index 2fe2721..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/ghostty.conf +++ /dev/null @@ -1,22 +0,0 @@ -background = {{colors.background.default.hex}} -foreground = {{colors.on_surface.default.hex}} -cursor-color = {{colors.primary.default.hex}} -selection-background = {{colors.primary_container.default.hex}} -selection-foreground = {{colors.on_surface.default.hex}} - -palette = 0={{dank16.color0.default.hex}} -palette = 1={{dank16.color1.default.hex}} -palette = 2={{dank16.color2.default.hex}} -palette = 3={{dank16.color3.default.hex}} -palette = 4={{dank16.color4.default.hex}} -palette = 5={{dank16.color5.default.hex}} -palette = 6={{dank16.color6.default.hex}} -palette = 7={{dank16.color7.default.hex}} -palette = 8={{dank16.color8.default.hex}} -palette = 9={{dank16.color9.default.hex}} -palette = 10={{dank16.color10.default.hex}} -palette = 11={{dank16.color11.default.hex}} -palette = 12={{dank16.color12.default.hex}} -palette = 13={{dank16.color13.default.hex}} -palette = 14={{dank16.color14.default.hex}} -palette = 15={{dank16.color15.default.hex}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-colors.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-colors.css deleted file mode 100644 index 2d181aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-colors.css +++ /dev/null @@ -1,48 +0,0 @@ -/* -* GTK Colors -* Generated with Matugen -*/ - -/* via thairanaru on GitHub: */ - -/* Destructive colors are basically error colors */ -@define-color destructive_bg_color {{colors.error.default.hex}}; -@define-color destructive_fg_color {{colors.on_error.default.hex}}; -/* Follow material spec */ -@define-color error_bg_color {{colors.error.default.hex}}; -@define-color error_fg_color {{colors.on_error.default.hex}}; -/* Follow material spec (also I think looks nicer) */ -@define-color accent_fg_color {{colors.on_primary.default.hex}}; -@define-color accent_bg_color {{colors.primary.default.hex}}; -/* Use surface instead of background */ -@define-color window_bg_color {{colors.surface.default.hex}}; -@define-color window_fg_color {{colors.on_surface.default.hex}}; -/* Make it more similar to Adwaita */ -@define-color view_bg_color {{colors.surface.default.hex}}; -@define-color view_fg_color {{colors.on_surface.default.hex}}; -@define-color headerbar_bg_color {{colors.surface.default.hex}}; -@define-color headerbar_fg_color {{colors.on_surface.default.hex}}; -@define-color sidebar_bg_color {{colors.surface_container.default.hex}}; -@define-color sidebar_fg_color {{colors.on_surface.default.hex}}; -/* There is only like one application I know that uses this, and there isn't a good way to get -a color between surface and surface container so I think just giving this surface is a good enough fallback*/ -@define-color secondary_sidebar_bg_color {{colors.surface.default.hex}}; -@define-color secondary_sidebar_fg_color {{colors.on_surface.default.hex}}; -@define-color card_bg_color {{colors.surface_container.default.hex}}; -@define-color card_fg_color {{colors.on_surface.default.hex}}; -@define-color overview_bg_color {{colors.surface_container.default.hex}}; -@define-color overview_fg_color {{colors.on_surface.default.hex}}; -@define-color popover_bg_color {{colors.surface_container.default.hex}}; -@define-color popover_fg_color {{colors.on_surface.default.hex}}; -@define-color dialog_bg_color {{colors.surface.default.hex}}; -@define-color dialog_fg_color {{colors.on_surface.default.hex}}; - -/* Backdrop/unfocused states - prevents white flash on window unfocus */ -@define-color headerbar_backdrop_color @window_bg_color; -@define-color sidebar_backdrop_color @sidebar_bg_color; -@define-color theme_unfocused_fg_color @window_fg_color; -@define-color theme_unfocused_text_color @view_fg_color; -@define-color theme_unfocused_bg_color @window_bg_color; -@define-color theme_unfocused_base_color @window_bg_color; -@define-color theme_unfocused_selected_bg_color @accent_bg_color; -@define-color theme_unfocused_selected_fg_color @accent_fg_color; diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-light-colors.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-light-colors.css deleted file mode 100644 index a8d52d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/gtk-light-colors.css +++ /dev/null @@ -1,7823 +0,0 @@ -/* -* GTK Colors -* Generated with Matugen -*/ - -/* Upstream adw-gtk3, I couldnt get light mode colors to work without it */ - -@define-color blue_1 #99c1f1; -@define-color blue_2 #62a0ea; -@define-color blue_3 #3584e4; -@define-color blue_4 #1c71d8; -@define-color blue_5 #1a5fb4; -@define-color green_1 #8ff0a4; -@define-color green_2 #57e389; -@define-color green_3 #33d17a; -@define-color green_4 #2ec27e; -@define-color green_5 #26a269; -@define-color yellow_1 #f9f06b; -@define-color yellow_2 #f8e45c; -@define-color yellow_3 #f6d32d; -@define-color yellow_4 #f5c211; -@define-color yellow_5 #e5a50a; -@define-color orange_1 #ffbe6f; -@define-color orange_2 #ffa348; -@define-color orange_3 #ff7800; -@define-color orange_4 #e66100; -@define-color orange_5 #c64600; -@define-color red_1 #f66151; -@define-color red_2 #ed333b; -@define-color red_3 #e01b24; -@define-color red_4 #c01c28; -@define-color red_5 #a51d2d; -@define-color purple_1 #dc8add; -@define-color purple_2 #c061cb; -@define-color purple_3 #9141ac; -@define-color purple_4 #813d9c; -@define-color purple_5 #613583; -@define-color brown_1 #cdab8f; -@define-color brown_2 #b5835a; -@define-color brown_3 #986a44; -@define-color brown_4 #865e3c; -@define-color brown_5 #63452c; -@define-color light_1 #ffffff; -@define-color light_2 #f6f5f4; -@define-color light_3 #deddda; -@define-color light_4 #c0bfbc; -@define-color light_5 #9a9996; -@define-color dark_1 #77767b; -@define-color dark_2 #5e5c64; -@define-color dark_3 #3d3846; -@define-color dark_4 #241f31; -@define-color dark_5 #000000; -@define-color accent_bg_color @blue_3; -@define-color accent_fg_color white; -@define-color destructive_bg_color @red_3; -@define-color destructive_fg_color white; -@define-color success_bg_color @green_4; -@define-color success_fg_color white; -@define-color warning_bg_color @yellow_5; -@define-color warning_fg_color rgba(0,0,0,0.8); -@define-color error_bg_color @red_3; -@define-color error_fg_color white; -@define-color accent_color mix(@accent_bg_color,black,0.17); -@define-color destructive_color mix(@destructive_bg_color,black,0.17); -@define-color success_color mix(@success_bg_color,black,0.17); -@define-color warning_color mix(@warning_bg_color,black,0.17); -@define-color error_color mix(@error_bg_color,black,0.17); -@define-color window_bg_color #fafafb; -@define-color window_fg_color #323233; -@define-color view_bg_color #ffffff; -@define-color view_fg_color #333334; -@define-color headerbar_bg_color #ebebed; -@define-color headerbar_fg_color #2f2f30; -@define-color headerbar_border_color rgba(0, 0, 6, 0.8); -@define-color headerbar_backdrop_color @window_bg_color; -@define-color headerbar_shade_color rgba(0, 0, 6, 0.12); -@define-color headerbar_darker_shade_color rgba(0, 0, 6, 0.12); -@define-color sidebar_bg_color #ebebed; -@define-color sidebar_fg_color #2f2f30; -@define-color sidebar_backdrop_color #f2f2f4; -@define-color sidebar_shade_color rgba(0, 0, 6, 0.07); -@define-color sidebar_border_color rgba(0, 0, 6, 0.07); -@define-color card_bg_color #ffffff; -@define-color card_fg_color #333334; -@define-color card_shade_color rgba(0, 0, 6, 0.07); -@define-color dialog_bg_color #fafafb; -@define-color dialog_fg_color #323233; -@define-color popover_bg_color #ffffff; -@define-color popover_fg_color #333334; -@define-color popover_shade_color rgba(0, 0, 6, 0.07); -@define-color thumbnail_bg_color #ffffff; -@define-color thumbnail_fg_color #333334; -@define-color shade_color rgba(0, 0, 6, 0.07); -@define-color scrollbar_outline_color white; -@define-color panel_bg_color black; -@define-color panel_fg_color white; -@define-color theme_fg_color @window_fg_color; -@define-color theme_text_color @view_fg_color; -@define-color theme_bg_color @window_bg_color; -@define-color theme_base_color @view_bg_color; -@define-color theme_selected_bg_color @accent_bg_color; -@define-color theme_selected_fg_color @accent_fg_color; -@define-color insensitive_bg_color mix(@window_bg_color,@view_bg_color,0.4); -@define-color insensitive_fg_color alpha(@window_fg_color,0.5); -@define-color insensitive_base_color @view_bg_color; -@define-color theme_unfocused_fg_color mix(@window_fg_color,@window_bg_color,0.5); -@define-color theme_unfocused_text_color @view_fg_color; -@define-color theme_unfocused_bg_color @window_bg_color; -@define-color theme_unfocused_base_color @window_bg_color; -@define-color theme_unfocused_selected_bg_color @accent_bg_color; -@define-color theme_unfocused_selected_fg_color @accent_fg_color; -@define-color unfocused_insensitive_color mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5); -@define-color borders mix(currentColor,@window_bg_color,0.85); -@define-color unfocused_borders mix(currentColor,@window_bg_color,0.81); -@define-color warning_color @warning_color; -@define-color error_color @error_color; -@define-color success_color @success_color; -@define-color wm_title shade(@window_fg_color, 1.8); -@define-color wm_unfocused_title mix(@window_fg_color,@window_bg_color,0.5); -@define-color wm_highlight alpha(white,0.5); -@define-color wm_borders_edge alpha(white,0.5); -@define-color wm_bg_a shade(@window_bg_color, 1.2); -@define-color wm_bg_b @window_bg_color; -@define-color wm_shadow alpha(black, 0.35); -@define-color wm_border alpha(black, 0.18); -@define-color wm_button_hover_color_a shade(@window_bg_color, 1.3); -@define-color wm_button_hover_color_b @window_bg_color; -@define-color wm_button_active_color_a shade(@window_bg_color, 0.85); -@define-color wm_button_active_color_b shade(@window_bg_color, 0.89); -@define-color wm_button_active_color_c shade(@window_bg_color, 0.9); -@define-color content_view_bg @view_bg_color; -@define-color text_view_bg @view_bg_color; -* { - padding: 0; - -GtkToolButton-icon-spacing: 4; - -GtkTextView-error-underline-color: @error_bg_color; - -GtkScrolledWindow-scrollbar-spacing: 0; - -GtkToolItemGroup-expander-size: 11; - -GtkWidget-text-handle-width: 20; - -GtkWidget-text-handle-height: 24; - -GtkDialog-button-spacing: 4; - -GtkDialog-action-area-border: 0; - outline-color: alpha(currentColor,0.3); - outline-style: dashed; - outline-offset: -3px; - outline-width: 1px; - -gtk-outline-radius: 7px; - -gtk-secondary-caret-color: @accent_bg_color; -} - -.background { - color: @window_fg_color; - background-color: @window_bg_color; -} -.background:backdrop { - text-shadow: none; - -gtk-icon-shadow: none; -} - -*:disabled { - -gtk-icon-effect: dim; -} - -.gtkstyle-fallback { - color: @window_fg_color; - background-color: @window_bg_color; -} -.gtkstyle-fallback:hover { - color: @window_fg_color; - background-color: shade(@window_bg_color,1.1); -} -.gtkstyle-fallback:active { - color: @window_fg_color; - background-color: shade(@window_bg_color,0.9); -} -.gtkstyle-fallback:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_bg_color,@view_bg_color,0.4); -} -.gtkstyle-fallback:selected { - color: @accent_fg_color; - background-color: @accent_bg_color; -} - -.osd .scale-popup, .app-notification, -.app-notification.frame, .csd popover.background.touch-selection, .csd popover.background.magnifier, popover.background.touch-selection, popover.background.magnifier, .csd popover.background.osd, popover.background.osd, -.osd { - color: rgba(255, 255, 255, 0.9); - border: none; - background-color: rgba(0, 0, 0, 0.7); - background-clip: padding-box; -} - -treeview.view:selected:focus, treeview.view:selected, headerbar entry selection, .titlebar entry selection, -entry selection, spinbutton:not(.vertical) selection, flowbox flowboxchild:selected, .view text selection:focus, iconview text selection:focus, .view text selection, iconview text selection, -textview text selection:focus, -textview text selection, .view:selected, iconview:selected, -.view text:selected, -iconview text:selected, -textview text:selected { - background-color: alpha(@accent_bg_color,0.25); -} -.selection-mode button.titlebutton, treeview.view:selected:focus, treeview.view:selected, headerbar entry selection, .titlebar entry selection, -entry selection, spinbutton:not(.vertical) selection, flowbox flowboxchild:selected, .view text selection:focus, iconview text selection:focus, .view text selection, iconview text selection, -textview text selection:focus, -textview text selection, .view:selected, iconview:selected, -.view text:selected, -iconview text:selected, -textview text:selected { - color: @window_fg_color; -} -.view, iconview, -.view text, -iconview text, -textview text { - color: @view_fg_color; - background-color: @view_bg_color; - caret-color: shade(@view_fg_color,1.05); -} -.view:disabled, iconview:disabled, -.view text:disabled, -iconview text:disabled, -textview text:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_bg_color,@view_bg_color,0.4); -} -.view:selected:focus, iconview:selected:focus, .view:selected, iconview:selected, -textview text:selected:focus, -.view text:selected, -iconview text:selected, -textview text:selected { - border-radius: 9px; -} - -textview border { - background-color: mix(@window_bg_color,@view_bg_color,0.5); -} - -.rubberband, -rubberband, -XfdesktopIconView.view .rubberband, -.content-view rubberband, -.content-view .rubberband, -treeview.view rubberband, -flowbox rubberband { - border: 1px solid @accent_color; - background-color: alpha(@accent_color,0.2); -} - -flowbox flowboxchild { - padding: 3px; -} -flowbox flowboxchild:selected { - outline-offset: -2px; -} - -.content-view .tile { - margin: 2px; - background-color: transparent; - border-radius: 0; - padding: 0; -} -.content-view .tile:backdrop { - background-color: transparent; -} -.content-view .tile:active, .content-view .tile:selected { - background-color: transparent; -} -.content-view .tile:disabled { - background-color: transparent; -} - -headerbar entry selection, .titlebar entry selection { - background-color: alpha(@accent_bg_color,0.25); -} -.selection-mode button.titlebutton, label:selected, headerbar entry selection, .titlebar entry selection { - color: @window_fg_color; -} -label { - caret-color: currentColor; -} -label selection { - background-color: @accent_bg_color; - color: @accent_fg_color; -} -label:disabled { - color: alpha(@window_fg_color,0.5); -} -button label:disabled { - color: inherit; -} -label:disabled:backdrop { - color: alpha(@window_fg_color,0.5); -} -button label:disabled:backdrop { - color: inherit; -} -label.error { - color: @error_bg_color; -} -label.error:disabled { - color: alpha(@error_bg_color,0.5); -} -label.error:disabled:backdrop { - color: alpha(@error_bg_color,0.4); -} - -assistant.csd .sidebar { - border-top-style: none; -} -assistant .sidebar label { - padding: 6px 12px; -} -assistant .sidebar label.highlight { - background-color: alpha(currentColor,0.1); -} - -.dim-label, .welcome .dim-label, -headerbar .subtitle, .titlebar:not(headerbar) .subtitle, label.separator { - opacity: 0.55; - text-shadow: none; -} - -.large-title { - font-weight: 300; - font-size: 24pt; -} - -.title-1 { - font-weight: 800; - font-size: 20pt; -} - -.title-2 { - font-weight: 800; - font-size: 15pt; -} - -.title-3 { - font-weight: 700; - font-size: 15pt; -} - -.title-4 { - font-weight: 700; - font-size: 13pt; -} - -.heading { - font-weight: 700; - font-size: 11pt; -} - -.body { - font-weight: 400; - font-size: 11pt; -} - -.caption-heading { - font-weight: 700; - font-size: 9pt; -} - -.caption { - font-weight: 400; - font-size: 9pt; -} - -@keyframes spin { - to { - -gtk-icon-transform: rotate(1turn); - } -} -spinner { - background: none; -} -spinner:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -spinner { - opacity: 0; - -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); -} -spinner:checked { - opacity: 1; - animation: spin 1s linear infinite; -} -spinner:checked:disabled { - opacity: 0.5; -} - -@keyframes needs_attention { - from { - background-image: -gtk-gradient(radial, center center, 0, center center, 0.01, to(@accent_bg_color), to(transparent)); - } - to { - background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(@accent_bg_color), to(transparent)); - } -} -notebook > header > tabs > arrow, -button { - min-height: 24px; - min-width: 16px; - padding: 4px 10px; - border: 1px solid; - border-color: transparent; - border-radius: 9px; - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - font-weight: bold; - -gtk-outline-radius: 7px; - color: @window_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); -} -notebook > header > tabs > arrow, -button { - outline: 0 solid transparent; - outline-offset: 4px; - transition: outline-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -notebook > header > tabs > arrow:focus, -button:focus { - outline-color: alpha(@accent_color,0.5); - outline-width: 2px; - outline-offset: -2px; -} -button.sidebar-button, notebook > header > tabs > arrow, notebook > header > tabs > arrow.flat, -button.flat { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - transition: none; -} -button.sidebar-button:hover, notebook > header > tabs > arrow:hover, -button.flat:hover { - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -button.sidebar-button:hover:active, notebook > header > tabs > arrow:hover:active, -button.flat:hover:active { - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} - -notebook > header > tabs > arrow:hover, -button:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; - -gtk-icon-effect: highlight; -} -notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, -button:active, -button:checked { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -notebook > header > tabs > arrow:active:hover, notebook > header > tabs > arrow:checked:hover, -button:active:hover, -button:checked:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.65); -} -notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, -button:active, -button:checked { - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, -button:active, -button:checked { - outline: 0 solid transparent; - outline-offset: 4px; - transition: outline-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -notebook > header > tabs > arrow:active:focus, notebook > header > tabs > arrow:checked:focus, -button:active:focus, -button:checked:focus { - outline-color: alpha(@accent_color,0.5); - outline-width: 2px; - outline-offset: -2px; -} -notebook > header > tabs > arrow:backdrop, -button:backdrop.flat, -button:backdrop { - transition: 200ms ease-out; - -gtk-icon-effect: none; -} -button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, -button.flat:backdrop, -button.flat:disabled, -button.flat:backdrop:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} - -notebook > header > tabs > arrow:disabled, -button:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -notebook > header > tabs > arrow:disabled:active, notebook > header > tabs > arrow:disabled:checked, -button:disabled:active, -button:disabled:checked { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; -} -notebook > header > tabs > arrow.image-button, -button.image-button { - min-width: 24px; - padding-left: 4px; - padding-right: 4px; -} -notebook > header > tabs > arrow.text-button, -button.text-button { - padding-left: 10px; - padding-right: 10px; -} -notebook > header > tabs > arrow.text-button.image-button, -button.text-button.image-button { - padding-left: 4px; - padding-right: 4px; -} -notebook > header > tabs > arrow.text-button.image-button label, -button.text-button.image-button label { - padding-left: 4px; - padding-right: 4px; -} -combobox:drop(active) button.combo, notebook > header > tabs > arrow:drop(active), -button:drop(active) { - color: @accent_bg_color; - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 1px @accent_bg_color; -} - -row:selected button { - border-color: mix(black,@accent_bg_color,0.85); -} -row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled), -row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled) { - color: @window_fg_color; - border-color: transparent; -} - -button.osd { - min-width: 32px; - min-height: 32px; -} -button.osd.image-button { - min-width: 34px; -} -button.osd { - color: rgba(255, 255, 255, 0.9); - border-radius: 5px; - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; - border: none; - box-shadow: none; -} -button.osd:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; - border: none; - box-shadow: none; -} -button.osd:active, -button.osd:checked { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; - border: none; - box-shadow: none; -} -button.osd:disabled:backdrop, -button.osd:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; - border: none; -} -button.osd:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.7)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; - border: none; -} -.app-notification button, -.app-notification.frame button, .csd popover.background.touch-selection button, .csd popover.background.magnifier button, popover.background.touch-selection button, popover.background.magnifier button, -.osd button { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.app-notification button:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, -.osd button:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; -} -.app-notification button:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, .app-notification button:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, -.osd button:active:backdrop, -.osd button:active, -.osd button:checked:backdrop, -.osd button:checked { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} -.app-notification button:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, -.osd button:disabled:backdrop, -.osd button:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.app-notification button:backdrop, popover.background.touch-selection button:backdrop, popover.background.magnifier button:backdrop, -.osd button:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.7)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.app-notification button.flat, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, -.osd button.flat { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; - text-shadow: 0 1px black; - -gtk-icon-shadow: 0 1px black; -} -.app-notification button.flat:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, -.osd button.flat:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; -} -.app-notification button.flat:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, -.osd button.flat:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; - background-image: none; - border-color: transparent; - box-shadow: none; -} -.app-notification button.flat:backdrop, popover.background.touch-selection button.flat:backdrop, popover.background.magnifier button.flat:backdrop, -.osd button.flat:backdrop { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -.app-notification button.flat:active, popover.background.touch-selection button.flat:active, popover.background.magnifier button.flat:active, .app-notification button.flat:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, -.osd button.flat:active, -.osd button.flat:checked { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} - -button.suggested-action { - color: white; - outline-color: alpha(@accent_color,0.5); - background-color: mix(white,@accent_bg_color,0.9); -} -button.suggested-action.flat { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: @accent_bg_color; -} -button.suggested-action:hover { - color: white; - background-color: mix(white,@accent_bg_color,0.85); - box-shadow: none; -} -button.suggested-action:active, -button.suggested-action:checked { - color: white; - background-color: mix(white,@accent_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -button.suggested-action:active:hover, -button.suggested-action:checked:hover { - background-color: mix(white,@accent_bg_color,0.65); -} -button.suggested-action.flat:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(@accent_bg_color,0.8); -} -button.suggested-action:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -button.suggested-action:disabled:active, -button.suggested-action:disabled:checked { - color: alpha(white,0.5); - background-color: mix(white,@accent_bg_color,0.7); - box-shadow: none; -} -.osd button.suggested-action { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.osd button.suggested-action:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; -} -.osd button.suggested-action:active:backdrop, -.osd button.suggested-action:active, -.osd button.suggested-action:checked:backdrop, -.osd button.suggested-action:checked { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} -.osd button.suggested-action:disabled:backdrop, -.osd button.suggested-action:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.osd button.suggested-action:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(alpha(@accent_bg_color,0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -button.destructive-action { - color: @destructive_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.9); -} -button.destructive-action.flat { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: @destructive_color; -} -button.destructive-action:hover { - color: @destructive_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.2),0.9); -} -button.destructive-action:focus { - outline-color: @destructive_color; -} -button.destructive-action:active, -button.destructive-action:checked { - color: @destructive_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.35),0.9); -} -button.destructive-action:active:hover, -button.destructive-action:checked:hover { - color: @destructive_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.4),0.9); -} -button.destructive-action.flat:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(@destructive_bg_color,0.8); -} -button.destructive-action:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -button.destructive-action:disabled:active, -button.destructive-action:disabled:checked { - color: alpha(@destructive_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.7); - box-shadow: none; -} -.osd button.destructive-action { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.osd button.destructive-action:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; -} -.osd button.destructive-action:active:backdrop, -.osd button.destructive-action:active, -.osd button.destructive-action:checked:backdrop, -.osd button.destructive-action:checked { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} -.osd button.destructive-action:disabled:backdrop, -.osd button.destructive-action:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.osd button.destructive-action:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(alpha(alpha(currentColor,0.15),0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.stack-switcher > button { - outline-offset: -3px; -} -.stack-switcher > button > label { - padding-left: 6px; - padding-right: 6px; -} -.stack-switcher > button > image { - padding-left: 6px; - padding-right: 6px; - padding-top: 3px; - padding-bottom: 3px; -} -.stack-switcher > button.text-button { - padding-left: 10px; - padding-right: 10px; -} -.stack-switcher > button.image-button { - padding-left: 2px; - padding-right: 2px; -} -.stack-switcher > button.needs-attention:active > label, -.stack-switcher > button.needs-attention:active > image, -.stack-switcher > button.needs-attention:checked > label, -.stack-switcher > button.needs-attention:checked > image { - animation: none; - background-image: none; -} -button.font separator, -button.file separator { - background-color: transparent; -} -button.font > box > box > label { - font-weight: bold; -} -.primary-toolbar button { - -gtk-icon-shadow: none; -} -button.circular { - border-radius: 9999px; - -gtk-outline-radius: 9999px; - padding: 4px; -} -button.circular label { - padding: 0; -} -button.circular:not(.flat):not(.osd):not(:checked):not(:active):not(:disabled):not(:backdrop) { - color: @window_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - border-color: transparent; -} -button.circular:hover:not(.osd):not(:checked):not(:active):not(:disabled):not(:backdrop) { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; - border-color: transparent; -} -button.circular { - background-origin: padding-box, border-box; - background-clip: padding-box, border-box; -} - -stacksidebar row.needs-attention > label, -.stack-switcher > button.needs-attention > label, -.stack-switcher > button.needs-attention > image { - animation: needs_attention 150ms ease-in; - background-image: radial-gradient(farthest-side, @accent_color 96%, transparent); - background-size: 6px 6px; - background-repeat: no-repeat; - background-position: right 3px; -} -stacksidebar row.needs-attention > label:dir(rtl), -.stack-switcher > button.needs-attention > label:dir(rtl), -.stack-switcher > button.needs-attention > image:dir(rtl) { - background-position: left 3px; -} - -.inline-toolbar toolbutton > button { - color: @window_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); -} -.inline-toolbar toolbutton > button:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; -} -.inline-toolbar toolbutton > button:active, .inline-toolbar toolbutton > button:checked { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.inline-toolbar toolbutton > button:active:hover, .inline-toolbar toolbutton > button:checked:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.65); -} -.inline-toolbar toolbutton > button:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -.inline-toolbar toolbutton > button:disabled:active, .inline-toolbar toolbutton > button:disabled:checked { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; -} -.inline-toolbar toolbutton > button:backdrop { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -.inline-toolbar toolbutton > button:backdrop:active, .inline-toolbar toolbutton > button:backdrop:checked { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.7); -} -.inline-toolbar toolbutton > button:backdrop:active:hover, .inline-toolbar toolbutton > button:backdrop:checked:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.6); -} -.inline-toolbar toolbutton > button:backdrop:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -.inline-toolbar toolbutton > button:backdrop:disabled:active, .inline-toolbar toolbutton > button:backdrop:disabled:checked { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.7); -} - -modelbutton.flat, -.menuitem.button.flat { - min-height: 32px; - padding-left: 5px; - padding-right: 5px; - border-radius: 9px; - outline-offset: -2px; -} -modelbutton.flat:hover, -.menuitem.button.flat:hover { - background-color: alpha(currentColor,0.1); -} -modelbutton.flat:selected, -.menuitem.button.flat:selected { - background-color: alpha(currentColor,0.1); -} - -modelbutton.flat arrow { - background: none; -} -modelbutton.flat arrow:hover { - background: none; -} -modelbutton.flat arrow.left { - -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); -} -modelbutton.flat arrow.right { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); -} - -button.color { - padding: 4px; -} -button.color colorswatch:only-child, button.color colorswatch:only-child overlay { - border-radius: 0; -} -.osd button.color colorswatch:only-child { - box-shadow: none; -} -.osd button.color:disabled colorswatch:only-child, .osd button.color:backdrop colorswatch:only-child, .osd button.color:active colorswatch:only-child, .osd button.color:checked colorswatch:only-child, button.color:disabled colorswatch:only-child, button.color:backdrop colorswatch:only-child, button.color:active colorswatch:only-child, button.color:checked colorswatch:only-child { - box-shadow: none; -} - -list row button.image-button:not(.flat):hover { - background-color: alpha(currentColor,0.04); -} -list row button.image-button:not(.flat):active { - background-color: alpha(currentColor,0.08); -} -list row button.image-button:not(.flat):checked { - background-color: alpha(@accent_bg_color,0.25); -} -list row button.image-button:not(.flat):checked:hover { - background-color: alpha(@accent_bg_color,0.32); -} -list row button.image-button:not(.flat):checked:active { - background-color: alpha(@accent_bg_color,0.39); -} - -button.toggle:not(.image-button) { - padding-left: 8px; - padding-right: 8px; -} - -.osd .linked > button { - border-color: transparent; -} - -.linked:not(.vertical) > combobox > box > button.combo, filechooser .path-bar.linked > button, .xfce4-panel.background button menu .linked button, headerbar .linked.raised button:not(:only-child), -headerbar .linked button:not(:only-child), headerbar > .stack-switcher.linked > button:not(:only-child), .titlebar .linked.raised button:not(:only-child), -.titlebar .linked button:not(:only-child), .titlebar > .stack-switcher.linked > button:not(:only-child), -.linked:not(.vertical) > entry, .linked:not(.vertical) > spinbutton:not(.vertical), -.inline-toolbar button, -.linked > button, toolbar.inline-toolbar toolbutton > button.flat { - border-left-color: alpha(currentColor,0.15); - border-right-color: alpha(currentColor,0.15); - border-right-style: none; - border-radius: 0; - -gtk-outline-radius: 0; -} - -combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > combobox:first-child > box > button.combo, filechooser .path-bar.linked > button:dir(rtl):last-child, filechooser .path-bar.linked > button:dir(ltr):first-child, .xfce4-panel.background button menu .linked button:first-child, -headerbar .linked button:first-child:not(:only-child), -.titlebar .linked button:first-child:not(:only-child), -.linked:not(.vertical) > entry:first-child, .linked:not(.vertical) > spinbutton:first-child:not(.vertical), -.inline-toolbar button:first-child, -.linked > button:first-child, toolbar.inline-toolbar toolbutton:first-child > button.flat { - border-left-color: transparent; - border-top-left-radius: 9px; - border-bottom-left-radius: 9px; - -gtk-outline-top-left-radius: 9px; - -gtk-outline-bottom-left-radius: 9px; -} -combobox.linked button:not(button):focus:nth-child(2):dir(rtl), .linked:not(.vertical) > combobox:first-child > box > button.combo:not(button):focus, filechooser .path-bar.linked > button:not(button):focus:dir(rtl):last-child, .xfce4-panel.background button menu .linked button:not(button):focus:first-child, -headerbar .linked button:not(button):focus:first-child:not(:only-child), -.titlebar .linked button:not(button):focus:first-child:not(:only-child), -.linked:not(.vertical) > entry:not(button):focus:first-child, .linked:not(.vertical) > spinbutton:not(button):focus:first-child:not(.vertical), -.inline-toolbar button:not(button):focus:first-child, -.linked > button:not(button):focus:first-child, toolbar.inline-toolbar toolbutton:first-child > button.flat:not(button):focus { - border-left-color: alpha(@accent_color,0.5); -} - -combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > combobox:last-child > box > button.combo, filechooser .path-bar.linked > button:dir(rtl):first-child, filechooser .path-bar.linked > button:dir(ltr):last-child, .xfce4-panel.background button menu .linked button:last-child, -headerbar .linked button:last-child:not(:only-child), -.titlebar .linked button:last-child:not(:only-child), -.linked:not(.vertical) > entry:last-child, .linked:not(.vertical) > spinbutton:last-child:not(.vertical), -.inline-toolbar button:last-child, -.linked > button:last-child, toolbar.inline-toolbar toolbutton:last-child > button.flat { - border-right-color: transparent; - border-right-style: solid; - border-top-right-radius: 9px; - border-bottom-right-radius: 9px; - -gtk-outline-top-right-radius: 9px; - -gtk-outline-bottom-right-radius: 9px; -} -combobox.linked button:not(button):focus:nth-child(2):dir(ltr), .linked:not(.vertical) > combobox:last-child > box > button.combo:not(button):focus, filechooser .path-bar.linked > button:not(button):focus:dir(rtl):first-child, .xfce4-panel.background button menu .linked button:not(button):focus:last-child, -headerbar .linked button:not(button):focus:last-child:not(:only-child), -.titlebar .linked button:not(button):focus:last-child:not(:only-child), -.linked:not(.vertical) > entry:not(button):focus:last-child, .linked:not(.vertical) > spinbutton:not(button):focus:last-child:not(.vertical), -.inline-toolbar button:not(button):focus:last-child, -.linked > button:not(button):focus:last-child, toolbar.inline-toolbar toolbutton:last-child > button.flat:not(button):focus { - border-right-color: alpha(@accent_color,0.5); -} - -.linked:not(.vertical) > combobox:only-child > box > button.combo, filechooser .path-bar.linked > button:only-child, .xfce4-panel.background button menu .linked button:only-child, -headerbar .linked button:only-child:not(:only-child), -.titlebar .linked button:only-child:not(:only-child), -.linked:not(.vertical) > entry:only-child, .linked:not(.vertical) > spinbutton:only-child:not(.vertical), -.inline-toolbar button:only-child, -.linked > button:only-child, toolbar.inline-toolbar toolbutton:only-child > button.flat { - border-style: solid; - border-radius: 9px; - -gtk-outline-radius: 9px; -} - -.xfce4-panel.background button menu .linked button, headerbar .linked.raised button:not(:only-child), -headerbar .linked button:not(:only-child), headerbar > .stack-switcher.linked > button:not(:only-child), .titlebar .linked.raised button:not(:only-child), -.titlebar .linked button:not(:only-child), .titlebar > .stack-switcher.linked > button:not(:only-child), -.linked:not(.vertical) > entry, .linked:not(.vertical) > spinbutton:not(.vertical), -.inline-toolbar button, -.linked > button { - border-left-color: alpha(currentColor,0.15); - border-right-color: alpha(currentColor,0.15); -} -.linked.vertical > combobox > box > button.combo, -.linked.vertical > entry, .linked.vertical > spinbutton:not(.vertical), -.linked.vertical > button { - border-top-color: alpha(currentColor,0.15); - border-bottom-color: alpha(currentColor,0.15); - border-style: solid none none none; - border-radius: 0; - -gtk-outline-radius: 0; -} - -.linked.vertical > combobox:first-child > box > button.combo, -.linked.vertical > entry:first-child, .linked.vertical > spinbutton:first-child:not(.vertical), -.linked.vertical > button:first-child { - border-top-color: transparent; - border-top-left-radius: 9px; - border-top-right-radius: 9px; - -gtk-outline-top-left-radius: 9px; - -gtk-outline-top-right-radius: 9px; -} - -.linked.vertical > combobox:last-child > box > button.combo, -.linked.vertical > entry:last-child, .linked.vertical > spinbutton:last-child:not(.vertical), -.linked.vertical > button:last-child { - border-bottom-color: transparent; - border-bottom-style: solid; - border-bottom-left-radius: 9px; - border-bottom-right-radius: 9px; - -gtk-outline-bottom-left-radius: 9px; - -gtk-outline-bottom-right-radius: 9px; -} - -.linked.vertical > combobox:only-child > box > button.combo, -.linked.vertical > entry:only-child, .linked.vertical > spinbutton:only-child:not(.vertical), -.linked.vertical > button:only-child { - border-style: solid; - border-radius: 9px; - -gtk-outline-radius: 9px; -} - -.linked.vertical > entry, .linked.vertical > spinbutton:not(.vertical), -.linked.vertical > button { - border-top-color: alpha(currentColor,0.15); - border-bottom-color: alpha(currentColor,0.15); -} -.scale-popup button:hover, calendar.button, button:link, -button:visited, button:link:hover, button:link:active, button:link:checked, -button:visited:hover, -button:visited:active, -button:visited:checked, modelbutton.flat, -.menuitem.button.flat, list row button.image-button:not(.flat) { - background-color: transparent; - background-image: none; - border-color: transparent; - box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} - -messagedialog.csd.background button.text-button.suggested-action, .content list button.suggested-action, .content list > row:not(:selected):hover button.suggested-action, -list.content button.suggested-action, -list.content > row:not(:selected):hover button.suggested-action, -list.view.frame button.suggested-action, -list.view.frame > row:not(:selected):hover button.suggested-action, popover.background button.suggested-action, headerbar.selection-mode button, headerbar.selection-mode button.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button, .titlebar.selection-mode button.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action, -headerbar .linked button.suggested-action:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action, .titlebar .linked.raised button.suggested-action, -.titlebar .linked button.suggested-action:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action, headerbar .linked entry ~ .suggested-action.image-button, .titlebar .linked entry ~ .suggested-action.image-button, headerbar button.suggested-action:not(.titlebutton), .titlebar button.suggested-action:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:checked, .titlebar viewswitcher button.suggested-action.radio:checked { - color: @accent_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.9); -} -messagedialog.csd.background button.text-button.suggested-action:hover, .content list button.suggested-action:hover, .content list > row:not(:selected):hover button.suggested-action:hover, -list.content button.suggested-action:hover, -list.content > row:not(:selected):hover button.suggested-action:hover, -list.view.frame button.suggested-action:hover, -list.view.frame > row:not(:selected):hover button.suggested-action:hover, popover.background button.suggested-action:hover, headerbar.selection-mode button:hover, headerbar.selection-mode button.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:hover, .titlebar.selection-mode button.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:hover, -headerbar .linked button.suggested-action:hover:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:hover, .titlebar .linked.raised button.suggested-action:hover, -.titlebar .linked button.suggested-action:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:hover, headerbar .linked entry ~ .suggested-action.image-button:hover, .titlebar .linked entry ~ .suggested-action.image-button:hover, headerbar button.suggested-action:hover:not(.titlebutton), .titlebar button.suggested-action:hover:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:hover:checked, .titlebar viewswitcher button.suggested-action.radio:hover:checked { - color: @accent_fg_color; - background-color: mix(@accent_fg_color,@accent_bg_color,0.85); - box-shadow: none; -} -messagedialog.csd.background button.text-button.suggested-action:active, .content list button.suggested-action:active, .content list > row:not(:selected):hover button.suggested-action:active, -list.content button.suggested-action:active, -list.content > row:not(:selected):hover button.suggested-action:active, -list.view.frame button.suggested-action:active, -list.view.frame > row:not(:selected):hover button.suggested-action:active, popover.background button.suggested-action:active, headerbar.selection-mode button:active, headerbar.selection-mode button.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:active, .titlebar.selection-mode button.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:active, -headerbar .linked button.suggested-action:active:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:active, .titlebar .linked.raised button.suggested-action:active, -.titlebar .linked button.suggested-action:active:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:active, headerbar .linked entry ~ .suggested-action.image-button:active, .titlebar .linked entry ~ .suggested-action.image-button:active, headerbar button.suggested-action:active:not(.titlebutton), .titlebar button.suggested-action:active:not(.titlebutton), messagedialog.csd.background button.text-button.suggested-action:checked, .content list button.suggested-action:checked, .content list > row:not(:selected):hover button.suggested-action:checked, -list.content button.suggested-action:checked, -list.content > row:not(:selected):hover button.suggested-action:checked, -list.view.frame button.suggested-action:checked, -list.view.frame > row:not(:selected):hover button.suggested-action:checked, popover.background button.suggested-action:checked, headerbar.selection-mode button:checked, headerbar.selection-mode button.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:checked, .titlebar.selection-mode button.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:checked, -headerbar .linked button.suggested-action:checked:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:checked, .titlebar .linked.raised button.suggested-action:checked, -.titlebar .linked button.suggested-action:checked:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:checked, headerbar .linked entry ~ .suggested-action.image-button:checked, .titlebar .linked entry ~ .suggested-action.image-button:checked, headerbar button.suggested-action:checked:not(.titlebutton), .titlebar button.suggested-action:checked:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:checked, .titlebar viewswitcher button.suggested-action.radio:checked { - color: @accent_fg_color; - background-color: mix(@accent_fg_color,alpha(@accent_bg_color,0.5),0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -messagedialog.csd.background button.text-button.suggested-action:active:hover, .content list button.suggested-action:active:hover, .content list > row:not(:selected):hover button.suggested-action:active:hover, -list.content button.suggested-action:active:hover, -list.content > row:not(:selected):hover button.suggested-action:active:hover, -list.view.frame button.suggested-action:active:hover, popover.background button.suggested-action:active:hover, headerbar.selection-mode button:active:hover, headerbar.selection-mode button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:active:hover, .titlebar.selection-mode button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:active:hover, -headerbar .linked button.suggested-action:active:hover:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:active:hover, .titlebar .linked.raised button.suggested-action:active:hover, -.titlebar .linked button.suggested-action:active:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:active:hover, headerbar .linked entry ~ .suggested-action.image-button:active:hover, .titlebar .linked entry ~ .suggested-action.image-button:active:hover, headerbar button.suggested-action:active:hover:not(.titlebutton), .titlebar button.suggested-action:active:hover:not(.titlebutton), messagedialog.csd.background button.text-button.suggested-action:checked:hover, .content list button.suggested-action:checked:hover, .content list > row:not(:selected):hover button.suggested-action:checked:hover, -list.content button.suggested-action:checked:hover, -list.content > row:not(:selected):hover button.suggested-action:checked:hover, -list.view.frame button.suggested-action:checked:hover, popover.background button.suggested-action:checked:hover, headerbar.selection-mode button:checked:hover, headerbar.selection-mode button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:checked:hover, .titlebar.selection-mode button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:checked:hover, -headerbar .linked button.suggested-action:checked:hover:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:checked:hover, .titlebar .linked.raised button.suggested-action:checked:hover, -.titlebar .linked button.suggested-action:checked:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:checked:hover, headerbar .linked entry ~ .suggested-action.image-button:checked:hover, .titlebar .linked entry ~ .suggested-action.image-button:checked:hover, headerbar button.suggested-action:checked:hover:not(.titlebutton), .titlebar button.suggested-action:checked:hover:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:checked:hover, .titlebar viewswitcher button.suggested-action.radio:checked:hover { - background-color: mix(@accent_fg_color,alpha(@accent_bg_color,0.5),0.65); -} -messagedialog.csd.background button.text-button.suggested-action:backdrop, .content list button.suggested-action:backdrop, .content list > row:not(:selected):hover button.suggested-action:backdrop, -list.content button.suggested-action:backdrop, -list.content > row:not(:selected):hover button.suggested-action:backdrop, -list.view.frame button.suggested-action:backdrop, -list.view.frame > row:not(:selected):hover button.suggested-action:backdrop, popover.background button.suggested-action:backdrop, headerbar.selection-mode button:backdrop, headerbar.selection-mode button.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:backdrop, .titlebar.selection-mode button.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:backdrop, -headerbar .linked button.suggested-action:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:backdrop, .titlebar .linked.raised button.suggested-action:backdrop, -.titlebar .linked button.suggested-action:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:backdrop, headerbar .linked entry ~ .suggested-action.image-button:backdrop, .titlebar .linked entry ~ .suggested-action.image-button:backdrop, headerbar button.suggested-action:backdrop:not(.titlebutton), .titlebar button.suggested-action:backdrop:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:backdrop:checked, .titlebar viewswitcher button.suggested-action.radio:backdrop:checked { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,alpha(@accent_bg_color,0.5),0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -messagedialog.csd.background button.text-button.suggested-action:disabled, .content list button.suggested-action:disabled, .content list > row:not(:selected):hover button.suggested-action:disabled, -list.content button.suggested-action:disabled, -list.content > row:not(:selected):hover button.suggested-action:disabled, -list.view.frame button.suggested-action:disabled, -list.view.frame > row:not(:selected):hover button.suggested-action:disabled, popover.background button.suggested-action:disabled, headerbar.selection-mode button:disabled, headerbar.selection-mode button.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:disabled, .titlebar.selection-mode button.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:disabled, -headerbar .linked button.suggested-action:disabled:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:disabled, .titlebar .linked.raised button.suggested-action:disabled, -.titlebar .linked button.suggested-action:disabled:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:disabled, headerbar .linked entry ~ .suggested-action.image-button:disabled, .titlebar .linked entry ~ .suggested-action.image-button:disabled, headerbar button.suggested-action:disabled:not(.titlebutton), .titlebar button.suggested-action:disabled:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:disabled:checked, .titlebar viewswitcher button.suggested-action.radio:disabled:checked { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,alpha(@accent_bg_color,0.5),0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -messagedialog.csd.background button.text-button.suggested-action:disabled:backdrop, .content list button.suggested-action:disabled:backdrop, .content list > row:not(:selected):hover button.suggested-action:disabled:backdrop, -list.content button.suggested-action:disabled:backdrop, -list.content > row:not(:selected):hover button.suggested-action:disabled:backdrop, -list.view.frame button.suggested-action:disabled:backdrop, popover.background button.suggested-action:disabled:backdrop, headerbar.selection-mode button:disabled:backdrop, headerbar.selection-mode button.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar.selection-mode button:disabled:backdrop, .titlebar.selection-mode button.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar button.suggested-action.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.suggested-action.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.suggested-action:disabled:backdrop, -headerbar .linked button.suggested-action:disabled:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button.suggested-action:disabled:backdrop, .titlebar .linked.raised button.suggested-action:disabled:backdrop, -.titlebar .linked button.suggested-action:disabled:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button.suggested-action:disabled:backdrop, headerbar .linked entry ~ .suggested-action.image-button:disabled:backdrop, .titlebar .linked entry ~ .suggested-action.image-button:disabled:backdrop, headerbar button.suggested-action:disabled:backdrop:not(.titlebutton), .titlebar button.suggested-action:disabled:backdrop:not(.titlebutton), headerbar viewswitcher button.suggested-action.radio:disabled:backdrop:checked, .titlebar viewswitcher button.suggested-action.radio:disabled:backdrop:checked { - color: alpha(mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5),0.5); - background-color: mix(mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5),alpha(@accent_bg_color,0.5),0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} - -messagedialog.csd.background button.text-button.destructive-action, .content list button.destructive-action, .content list > row:not(:selected):hover button.destructive-action, -list.content button.destructive-action, -list.content > row:not(:selected):hover button.destructive-action, -list.view.frame button.destructive-action, -list.view.frame > row:not(:selected):hover button.destructive-action, popover.background button.destructive-action, headerbar button.destructive-action.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action, -headerbar .linked button.destructive-action:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action, .titlebar .linked.raised button.destructive-action, -.titlebar .linked button.destructive-action:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action, headerbar .linked entry ~ .destructive-action.image-button, .titlebar .linked entry ~ .destructive-action.image-button, headerbar button.destructive-action:not(.titlebutton), .titlebar button.destructive-action:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:checked, .titlebar viewswitcher button.destructive-action.radio:checked { - color: @destructive_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.9); -} -messagedialog.csd.background button.text-button.destructive-action:hover, .content list button.destructive-action:hover, .content list > row:not(:selected):hover button.destructive-action:hover, -list.content button.destructive-action:hover, -list.content > row:not(:selected):hover button.destructive-action:hover, -list.view.frame button.destructive-action:hover, -list.view.frame > row:not(:selected):hover button.destructive-action:hover, popover.background button.destructive-action:hover, headerbar button.destructive-action.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:hover, -headerbar .linked button.destructive-action:hover:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:hover, .titlebar .linked.raised button.destructive-action:hover, -.titlebar .linked button.destructive-action:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:hover, headerbar .linked entry ~ .destructive-action.image-button:hover, .titlebar .linked entry ~ .destructive-action.image-button:hover, headerbar button.destructive-action:hover:not(.titlebutton), .titlebar button.destructive-action:hover:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:hover:checked, .titlebar viewswitcher button.destructive-action.radio:hover:checked { - color: @destructive_color; - background-color: mix(@destructive_color,alpha(currentColor,0.2),0.85); - box-shadow: none; -} -messagedialog.csd.background button.text-button.destructive-action:active, .content list button.destructive-action:active, .content list > row:not(:selected):hover button.destructive-action:active, -list.content button.destructive-action:active, -list.content > row:not(:selected):hover button.destructive-action:active, -list.view.frame button.destructive-action:active, -list.view.frame > row:not(:selected):hover button.destructive-action:active, popover.background button.destructive-action:active, headerbar button.destructive-action.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:active, -headerbar .linked button.destructive-action:active:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:active, .titlebar .linked.raised button.destructive-action:active, -.titlebar .linked button.destructive-action:active:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:active, headerbar .linked entry ~ .destructive-action.image-button:active, .titlebar .linked entry ~ .destructive-action.image-button:active, headerbar button.destructive-action:active:not(.titlebutton), .titlebar button.destructive-action:active:not(.titlebutton), messagedialog.csd.background button.text-button.destructive-action:checked, .content list button.destructive-action:checked, .content list > row:not(:selected):hover button.destructive-action:checked, -list.content button.destructive-action:checked, -list.content > row:not(:selected):hover button.destructive-action:checked, -list.view.frame button.destructive-action:checked, -list.view.frame > row:not(:selected):hover button.destructive-action:checked, popover.background button.destructive-action:checked, headerbar button.destructive-action.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:checked, -headerbar .linked button.destructive-action:checked:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:checked, .titlebar .linked.raised button.destructive-action:checked, -.titlebar .linked button.destructive-action:checked:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:checked, headerbar .linked entry ~ .destructive-action.image-button:checked, .titlebar .linked entry ~ .destructive-action.image-button:checked, headerbar button.destructive-action:checked:not(.titlebutton), .titlebar button.destructive-action:checked:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:checked, .titlebar viewswitcher button.destructive-action.radio:checked { - color: @destructive_color; - background-color: mix(@destructive_color,alpha(currentColor,0.35),0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -messagedialog.csd.background button.text-button.destructive-action:active:hover, .content list button.destructive-action:active:hover, .content list > row:not(:selected):hover button.destructive-action:active:hover, -list.content button.destructive-action:active:hover, -list.content > row:not(:selected):hover button.destructive-action:active:hover, -list.view.frame button.destructive-action:active:hover, popover.background button.destructive-action:active:hover, headerbar button.destructive-action.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:active:hover, -headerbar .linked button.destructive-action:active:hover:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:active:hover, .titlebar .linked.raised button.destructive-action:active:hover, -.titlebar .linked button.destructive-action:active:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:active:hover, headerbar .linked entry ~ .destructive-action.image-button:active:hover, .titlebar .linked entry ~ .destructive-action.image-button:active:hover, headerbar button.destructive-action:active:hover:not(.titlebutton), .titlebar button.destructive-action:active:hover:not(.titlebutton), messagedialog.csd.background button.text-button.destructive-action:checked:hover, .content list button.destructive-action:checked:hover, .content list > row:not(:selected):hover button.destructive-action:checked:hover, -list.content button.destructive-action:checked:hover, -list.content > row:not(:selected):hover button.destructive-action:checked:hover, -list.view.frame button.destructive-action:checked:hover, popover.background button.destructive-action:checked:hover, headerbar button.destructive-action.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:checked:hover, -headerbar .linked button.destructive-action:checked:hover:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:checked:hover, .titlebar .linked.raised button.destructive-action:checked:hover, -.titlebar .linked button.destructive-action:checked:hover:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:checked:hover, headerbar .linked entry ~ .destructive-action.image-button:checked:hover, .titlebar .linked entry ~ .destructive-action.image-button:checked:hover, headerbar button.destructive-action:checked:hover:not(.titlebutton), .titlebar button.destructive-action:checked:hover:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:checked:hover, .titlebar viewswitcher button.destructive-action.radio:checked:hover { - background-color: mix(@destructive_color,alpha(currentColor,0.35),0.65); -} -messagedialog.csd.background button.text-button.destructive-action:backdrop, .content list button.destructive-action:backdrop, .content list > row:not(:selected):hover button.destructive-action:backdrop, -list.content button.destructive-action:backdrop, -list.content > row:not(:selected):hover button.destructive-action:backdrop, -list.view.frame button.destructive-action:backdrop, -list.view.frame > row:not(:selected):hover button.destructive-action:backdrop, popover.background button.destructive-action:backdrop, headerbar button.destructive-action.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:backdrop, -headerbar .linked button.destructive-action:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:backdrop, .titlebar .linked.raised button.destructive-action:backdrop, -.titlebar .linked button.destructive-action:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:backdrop, headerbar .linked entry ~ .destructive-action.image-button:backdrop, .titlebar .linked entry ~ .destructive-action.image-button:backdrop, headerbar button.destructive-action:backdrop:not(.titlebutton), .titlebar button.destructive-action:backdrop:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:backdrop:checked, .titlebar viewswitcher button.destructive-action.radio:backdrop:checked { - color: alpha(@destructive_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -messagedialog.csd.background button.text-button.destructive-action:disabled, .content list button.destructive-action:disabled, .content list > row:not(:selected):hover button.destructive-action:disabled, -list.content button.destructive-action:disabled, -list.content > row:not(:selected):hover button.destructive-action:disabled, -list.view.frame button.destructive-action:disabled, -list.view.frame > row:not(:selected):hover button.destructive-action:disabled, popover.background button.destructive-action:disabled, headerbar button.destructive-action.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:disabled, -headerbar .linked button.destructive-action:disabled:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:disabled, .titlebar .linked.raised button.destructive-action:disabled, -.titlebar .linked button.destructive-action:disabled:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:disabled, headerbar .linked entry ~ .destructive-action.image-button:disabled, .titlebar .linked entry ~ .destructive-action.image-button:disabled, headerbar button.destructive-action:disabled:not(.titlebutton), .titlebar button.destructive-action:disabled:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:disabled:checked, .titlebar viewswitcher button.destructive-action.radio:disabled:checked { - color: alpha(@destructive_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -messagedialog.csd.background button.text-button.destructive-action:disabled:backdrop, .content list button.destructive-action:disabled:backdrop, .content list > row:not(:selected):hover button.destructive-action:disabled:backdrop, -list.content button.destructive-action:disabled:backdrop, -list.content > row:not(:selected):hover button.destructive-action:disabled:backdrop, -list.view.frame button.destructive-action:disabled:backdrop, popover.background button.destructive-action:disabled:backdrop, headerbar button.destructive-action.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:disabled:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:disabled:backdrop, -headerbar .linked button.destructive-action:disabled:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:disabled:backdrop, .titlebar .linked.raised button.destructive-action:disabled:backdrop, -.titlebar .linked button.destructive-action:disabled:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:disabled:backdrop, headerbar .linked entry ~ .destructive-action.image-button:disabled:backdrop, .titlebar .linked entry ~ .destructive-action.image-button:disabled:backdrop, headerbar button.destructive-action:disabled:backdrop:not(.titlebutton), .titlebar button.destructive-action:disabled:backdrop:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:disabled:backdrop:checked, .titlebar viewswitcher button.destructive-action.radio:disabled:backdrop:checked { - color: alpha(@destructive_color,0.5); - background-color: mix(@destructive_color,alpha(currentColor,0.15),0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -messagedialog.csd.background button.text-button.destructive-action:focus, .content list button.destructive-action:focus, .content list > row:not(:selected):hover button.destructive-action:focus, -list.content button.destructive-action:focus, -list.content > row:not(:selected):hover button.destructive-action:focus, -list.view.frame button.destructive-action:focus, -list.view.frame > row:not(:selected):hover button.destructive-action:focus, popover.background button.destructive-action:focus, headerbar button.destructive-action.text-button:focus:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.destructive-action.text-button:focus:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.destructive-action:focus, -headerbar .linked button.destructive-action:focus:not(:only-child), headerbar > .stack-switcher.linked > button.destructive-action:focus, .titlebar .linked.raised button.destructive-action:focus, -.titlebar .linked button.destructive-action:focus:not(:only-child), .titlebar > .stack-switcher.linked > button.destructive-action:focus, headerbar .linked entry ~ .destructive-action.image-button:focus, .titlebar .linked entry ~ .destructive-action.image-button:focus, headerbar button.destructive-action:focus:not(.titlebutton), .titlebar button.destructive-action:focus:not(.titlebutton), headerbar viewswitcher button.destructive-action.radio:focus:checked, .titlebar viewswitcher button.destructive-action.radio:focus:checked { - outline-color: @destructive_color; -} - -spinbutton:not(.vertical), -entry { - min-height: 34px; - padding-left: 8px; - padding-right: 8px; - border: 1px solid; - border-radius: 9px; - transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - color: @view_fg_color; - border-color: transparent; - background-color: alpha(currentColor,0.1); - box-shadow: inset 0 0 0 1px alpha(alpha(@accent_color,0.5),0); -} -spinbutton:not(.vertical) image.left, -entry image.left { - margin-right: 6px; -} -spinbutton:not(.vertical) image.right, -entry image.right { - margin-left: 6px; -} -spinbutton.flat:not(.vertical), -entry.flat:focus, -entry.flat:backdrop, -entry.flat:disabled, -entry.flat:backdrop:disabled, -entry.flat { - min-height: 0; - padding: 2px; - background-color: transparent; - border-color: transparent; - border-radius: 0; -} -spinbutton:focus:not(.vertical), -entry:focus { - box-shadow: inset 0 0 0 1px alpha(@accent_color,0.5); - border-color: alpha(@accent_color,0.5); - transition: 300ms ease-in-out; - transition-property: border, box-shadow; -} -spinbutton:disabled:not(.vertical), -entry:disabled { - color: alpha(@window_fg_color,0.5); - border-color: transparent; - background-color: mix(currentColor,@window_bg_color,0.95); -} -spinbutton.error:not(.vertical), -entry.error { - color: @error_bg_color; - border-color: @error_bg_color; -} -spinbutton.error:focus:not(.vertical), -entry.error:focus { - box-shadow: inset 0 0 0 1px @error_bg_color; - border-color: @error_bg_color; - transition: 300ms ease-in-out; - transition-property: border, box-shadow; -} -spinbutton.error:not(.vertical) selection, -entry.error selection { - background-color: @error_bg_color; -} -spinbutton.warning:not(.vertical), -entry.warning { - color: @warning_bg_color; - border-color: @warning_bg_color; -} -spinbutton.warning:focus:not(.vertical), -entry.warning:focus { - box-shadow: inset 0 0 0 1px @warning_bg_color; - border-color: @warning_bg_color; - transition: 300ms ease-in-out; - transition-property: border, box-shadow; -} -spinbutton.warning:not(.vertical) selection, -entry.warning selection { - background-color: @warning_bg_color; -} -spinbutton:not(.vertical) image, -entry image { - color: mix(@window_fg_color,@view_bg_color,0.2); -} -spinbutton:not(.vertical) image:hover, -entry image:hover { - color: @window_fg_color; -} -spinbutton:not(.vertical) image:active, -entry image:active { - color: @accent_bg_color; -} -spinbutton:drop(active):not(.vertical), -entry:drop(active):focus, -entry:drop(active) { - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 1px @accent_bg_color; -} -.osd spinbutton:not(.vertical), -.osd entry { - color: white; - border-color: rgba(0, 0, 0, 0.9); - background-color: rgba(0, 0, 0, 0.5); - background-clip: padding-box; - box-shadow: none; - text-shadow: 0 1px black; - -gtk-icon-shadow: 0 1px black; -} -.osd spinbutton:focus:not(.vertical), -.osd entry:focus { - color: white; - border-color: @accent_bg_color; - background-color: rgba(0, 0, 0, 0.5); - background-clip: padding-box; - box-shadow: inset 0 0 0 1px alpha(@accent_color,0.5); - text-shadow: 0 1px black; - -gtk-icon-shadow: 0 1px black; -} -.osd spinbutton:backdrop:not(.vertical), -.osd entry:backdrop { - color: white; - border-color: rgba(0, 0, 0, 0.9); - background-color: rgba(0, 0, 0, 0.5); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.osd spinbutton:disabled:not(.vertical), -.osd entry:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: rgba(0, 0, 0, 0.9); - background-color: rgba(0, 0, 0, 0.5); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -spinbutton:not(.vertical) progress, -entry progress { - margin: 2px -6px; - background-color: transparent; - background-image: none; - border-radius: 0; - border-width: 0 0 2px; - border-color: @accent_bg_color; - border-style: solid; - box-shadow: none; -} -.linked:not(.vertical) > spinbutton:focus:not(.vertical) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:focus:not(.vertical) + button, .linked:not(.vertical) > spinbutton:focus:not(.vertical) + combobox > box > button.combo, -.linked:not(.vertical) > spinbutton:focus:not(.vertical) + entry, -.linked:not(.vertical) > entry:focus + button, -.linked:not(.vertical) > entry:focus + combobox > box > button.combo, -.linked:not(.vertical) > entry:focus + spinbutton:not(.vertical), -.linked:not(.vertical) > entry:focus + entry { - border-left-color: alpha(@accent_color,0.5); -} -.linked:not(.vertical) > spinbutton:focus.error:not(.vertical) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:focus.error:not(.vertical) + button, .linked:not(.vertical) > spinbutton:focus.error:not(.vertical) + combobox > box > button.combo, -.linked:not(.vertical) > spinbutton:focus.error:not(.vertical) + entry, -.linked:not(.vertical) > entry:focus.error + button, -.linked:not(.vertical) > entry:focus.error + combobox > box > button.combo, -.linked:not(.vertical) > entry:focus.error + spinbutton:not(.vertical), -.linked:not(.vertical) > entry:focus.error + entry { - border-left-color: @error_bg_color; -} -.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + combobox > box > button.combo, -.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + entry, -.linked:not(.vertical) > entry:drop(active) + button, -.linked:not(.vertical) > entry:drop(active) + combobox > box > button.combo, -.linked:not(.vertical) > entry:drop(active) + spinbutton:not(.vertical), -.linked:not(.vertical) > entry:drop(active) + entry { - border-left-color: @accent_bg_color; -} -.linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):not(.vertical), -.linked.vertical > entry:not(:disabled) + entry:not(:disabled), -.linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):not(.vertical) { - border-top-color: mix(alpha(currentColor,0.15),@view_bg_color,0.7); -} -.linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled):backdrop, .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):backdrop:not(.vertical), -.linked.vertical > entry:not(:disabled) + entry:not(:disabled):backdrop, -.linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):backdrop:not(.vertical) { - border-top-color: mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.7); -} -.linked.vertical > spinbutton:disabled:not(.vertical) + spinbutton:disabled:not(.vertical), .linked.vertical > spinbutton:disabled:not(.vertical) + entry:disabled, -.linked.vertical > entry:disabled + spinbutton:disabled:not(.vertical), -.linked.vertical > entry:disabled + entry:disabled { - border-top-color: mix(alpha(currentColor,0.15),@view_bg_color,0.7); -} -.linked.vertical > spinbutton:not(.vertical) + spinbutton:focus:not(:only-child):not(.vertical), -.linked.vertical > spinbutton:not(.vertical) + entry:focus:not(:only-child), -.linked.vertical > entry + spinbutton:focus:not(:only-child):not(.vertical), -.linked.vertical > entry + entry:focus:not(:only-child) { - border-top-color: alpha(@accent_color,0.5); -} -.linked.vertical > spinbutton:not(.vertical) + spinbutton:focus.error:not(:only-child):not(.vertical), -.linked.vertical > spinbutton:not(.vertical) + entry:focus.error:not(:only-child), -.linked.vertical > entry + spinbutton:focus.error:not(:only-child):not(.vertical), -.linked.vertical > entry + entry:focus.error:not(:only-child) { - border-top-color: @error_bg_color; -} -.linked.vertical > spinbutton:not(.vertical) + spinbutton:drop(active):not(:only-child):not(.vertical), -.linked.vertical > spinbutton:not(.vertical) + entry:drop(active):not(:only-child), -.linked.vertical > entry + spinbutton:drop(active):not(:only-child):not(.vertical), -.linked.vertical > entry + entry:drop(active):not(:only-child) { - border-top-color: @accent_bg_color; -} -.linked.vertical > spinbutton:focus:not(:only-child):not(.vertical) + spinbutton:not(.vertical), -.linked.vertical > spinbutton:focus:not(:only-child):not(.vertical) + entry, -.linked.vertical > spinbutton:focus:not(:only-child):not(.vertical) + button, -.linked.vertical > spinbutton:focus:not(:only-child):not(.vertical) + combobox > box > button.combo, -.linked.vertical > entry:focus:not(:only-child) + spinbutton:not(.vertical), -.linked.vertical > entry:focus:not(:only-child) + entry, -.linked.vertical > entry:focus:not(:only-child) + button, -.linked.vertical > entry:focus:not(:only-child) + combobox > box > button.combo { - border-top-color: alpha(@accent_color,0.5); -} -.linked.vertical > spinbutton:focus.error:not(:only-child):not(.vertical) + spinbutton:not(.vertical), -.linked.vertical > spinbutton:focus.error:not(:only-child):not(.vertical) + entry, -.linked.vertical > spinbutton:focus.error:not(:only-child):not(.vertical) + button, -.linked.vertical > spinbutton:focus.error:not(:only-child):not(.vertical) + combobox > box > button.combo, -.linked.vertical > entry:focus.error:not(:only-child) + spinbutton:not(.vertical), -.linked.vertical > entry:focus.error:not(:only-child) + entry, -.linked.vertical > entry:focus.error:not(:only-child) + button, -.linked.vertical > entry:focus.error:not(:only-child) + combobox > box > button.combo { - border-top-color: @error_bg_color; -} -.linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + spinbutton:not(.vertical), -.linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + entry, -.linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + button, -.linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + combobox > box > button.combo, -.linked.vertical > entry:drop(active):not(:only-child) + spinbutton:not(.vertical), -.linked.vertical > entry:drop(active):not(:only-child) + entry, -.linked.vertical > entry:drop(active):not(:only-child) + button, -.linked.vertical > entry:drop(active):not(:only-child) + combobox > box > button.combo { - border-top-color: @accent_bg_color; -} -spinbutton.error:not(.vertical), -entry.error { - color: @error_bg_color; -} - -treeview entry:focus:dir(rtl), treeview entry:focus:dir(ltr) { - background-color: @view_bg_color; - transition-property: color, background; -} -treeview entry.flat, treeview entry { - border-radius: 0; - background-image: none; - background-color: @view_bg_color; -} -treeview entry.flat:focus, treeview entry:focus { - border-color: @accent_bg_color; -} - -.entry-tag { - padding: 5px; - margin-top: 2px; - margin-bottom: 2px; -} -:dir(ltr) .entry-tag { - margin-left: 8px; - margin-right: -5px; -} -:dir(rtl) .entry-tag { - margin-left: -5px; - margin-right: 8px; -} -.entry-tag { - border-style: none; - color: @accent_fg_color; - background-color: @accent_bg_color; -} -.entry-tag:hover { - background-color: mix(white,@accent_bg_color,0.9); -} -:backdrop .entry-tag { - color: @window_bg_color; - background-color: @accent_bg_color; -} -.entry-tag.button { - background-color: transparent; - color: alpha(@accent_fg_color,0.7); -} -:not(:backdrop) .entry-tag.button:hover { - border: 1px solid @accent_bg_color; - color: @accent_fg_color; -} -:not(:backdrop) .entry-tag.button:active { - background-color: @accent_bg_color; - color: alpha(@accent_fg_color,0.7); -} - -button:link > label, -button:visited > label, button:link, -button:visited, -*:link { - color: @accent_color; -} -button:link > label:visited, -button:visited > label:visited, -button:visited, -*:link:visited { - color: mix(@accent_color,@view_fg_color,0.2); -} -*:selected button:link > label:visited, -*:selected button:visited > label:visited, -*:selected button:visited, -*:selected *:link:visited { - color: mix(@accent_fg_color,mix(@accent_color,@view_fg_color,0.2),0.4); -} -button:link > label:hover, -button:visited > label:hover, -button:hover:visited, -*:link:hover { - color: mix(white,@accent_color,0.9); -} -*:selected button:link > label:hover, -*:selected button:visited > label:hover, -*:selected button:hover:visited, -*:selected *:link:hover { - color: mix(@accent_fg_color,mix(white,@accent_color,0.9),0.1); -} -button:link > label:active, -button:visited > label:active, -button:active:visited, -*:link:active { - color: @accent_color; -} -*:selected button:link > label:active, -*:selected button:visited > label:active, -*:selected button:active:visited, -*:selected *:link:active { - color: mix(@accent_fg_color,@accent_color,0.2); -} -button:link > label:backdrop, -button:visited > label:backdrop, -button:backdrop:visited, -*:link:backdrop:backdrop:hover, -*:link:backdrop:backdrop:hover:selected, -*:link:backdrop { - color: alpha(@accent_color,0.9); -} -button:link > label:disabled, -button:visited > label:disabled, -button:disabled:visited, -*:link:disabled, -*:link:disabled:backdrop { - color: alpha(mix(white,black,0.5),0.8); -} -button:link > label:selected, -button:visited > label:selected, -button:selected:visited, *:selected button:link > label, -*:selected button:visited > label, -*:selected button:visited, -*:link:selected, -*:selected *:link { - color: mix(@accent_fg_color,@accent_color,0.2); -} - -button:link, -button:visited { - text-shadow: none; - font-weight: 400; -} -button:link:hover, button:link:active, button:link:checked, -button:visited:hover, -button:visited:active, -button:visited:checked { - text-shadow: none; -} -button:link, -button:visited { - outline: 0 solid transparent; - outline-offset: 4px; - transition: outline-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -button:link:focus, -button:visited:focus { - outline-color: alpha(@accent_color,0.5); - outline-width: 2px; - outline-offset: -2px; -} -button:link > label, -button:visited > label { - text-decoration-line: underline; -} - -spinbutton:not(.vertical) { - padding: 0; -} -.osd spinbutton:not(.vertical) entry, spinbutton:not(.vertical) entry { - min-width: 28px; - margin: 0; - background: none; - background-color: transparent; - border: none; - border-radius: 0; - box-shadow: none; -} -spinbutton:not(.vertical) entry:backdrop:disabled { - background-color: transparent; -} -spinbutton:not(.vertical) button { - min-height: 16px; - margin: 0; - padding-bottom: 0; - padding-top: 0; - color: mix(@window_fg_color,@view_bg_color,0.1); - background-color: transparent; - border-style: none none none solid; - border-color: alpha(currentColor,0.15); - border-radius: 0; - box-shadow: none; -} -spinbutton:not(.vertical) button:dir(rtl) { - border-style: none solid none none; -} -spinbutton:not(.vertical) button:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; - background-color: alpha(currentColor,0.1); -} -spinbutton:not(.vertical) button:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; - background-color: transparent; -} -spinbutton:not(.vertical) button:active { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -spinbutton:not(.vertical) button:active:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.65); -} -spinbutton:not(.vertical) button:active { - background-color: alpha(currentColor,0.15); -} -spinbutton:not(.vertical) button:dir(ltr):last-child { - border-radius: 0 9px 9px 0; -} -spinbutton:not(.vertical) button:dir(rtl):first-child { - border-radius: 9px 0 0 9px; -} -.osd spinbutton:not(.vertical) button { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: rgba(255, 255, 255, 0.9); - border-style: none none none solid; - border-color: alpha(rgba(0, 0, 0, 0.9),0.7); - border-radius: 0; - box-shadow: none; - -gtk-icon-shadow: 0 1px black; -} -.osd spinbutton:not(.vertical) button:dir(rtl) { - border-style: none solid none none; -} -.osd spinbutton:not(.vertical) button:hover { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: rgba(255, 255, 255, 0.9); - border-color: alpha(black,0.5); - background-color: alpha(rgba(255, 255, 255, 0.9),0.1); - -gtk-icon-shadow: 0 1px black; - box-shadow: none; -} -.osd spinbutton:not(.vertical) button:backdrop { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: rgba(255, 255, 255, 0.9); - border-color: alpha(black,0.5); - -gtk-icon-shadow: none; - box-shadow: none; -} -.osd spinbutton:not(.vertical) button:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: rgba(255, 255, 255, 0.5); - border-color: alpha(black,0.5); - -gtk-icon-shadow: none; - box-shadow: none; -} -.osd spinbutton:not(.vertical) button:dir(ltr):last-child { - border-radius: 0 9px 9px 0; -} -.osd spinbutton:not(.vertical) button:dir(rtl):first-child { - border-radius: 9px 0 0 9px; -} -spinbutton.vertical:disabled { - color: alpha(@window_fg_color,0.5); -} -spinbutton.vertical:drop(active) { - border-color: transparent; - box-shadow: none; -} -spinbutton.vertical entry { - min-height: 32px; - min-width: 32px; - padding: 0; - border-radius: 0; -} -spinbutton.vertical button { - min-height: 32px; - min-width: 32px; - padding: 0; -} -spinbutton.vertical button.up { - border-color: alpha(currentColor,0.15); - border-radius: 9px 9px 0 0; - border-style: none none solid none; -} -spinbutton.vertical button.down { - border-color: alpha(currentColor,0.15); - border-radius: 0 0 9px 9px; - border-style: solid none none none; -} -.osd spinbutton.vertical button:first-child { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.osd spinbutton.vertical button:first-child:hover { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.25); - background-clip: padding-box; -} -.osd spinbutton.vertical button:first-child:active { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} -.osd spinbutton.vertical button:first-child:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.osd spinbutton.vertical button:first-child:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.7)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -treeview spinbutton:not(.vertical) { - min-height: 0; - border-style: none; - border-radius: 0; -} -treeview spinbutton:not(.vertical) entry { - min-height: 0; - padding: 1px 2px; -} -spinbutton { - font-feature-settings: "tnum"; -} - -combobox arrow { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); - min-height: 16px; - min-width: 16px; -} -combobox:drop(active) { - box-shadow: none; -} -searchbar > revealer > box, -.location-bar, .inline-toolbar, toolbar { - -GtkWidget-window-dragging: true; - padding: 4px; - background-color: @window_bg_color; -} -searchbar > revealer > box:backdrop, -.location-bar:backdrop, .inline-toolbar:backdrop, toolbar:backdrop { - background-color: @window_bg_color; -} - -toolbar { - padding: 4px 3px 3px 4px; -} -.osd toolbar { - background-color: transparent; -} -toolbar.osd { - padding: 13px; - border: none; - border-radius: 5px; - background-color: rgba(0, 0, 0, 0.7); -} -toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { - border-radius: 0; -} -toolbar.horizontal separator { - margin: 0 7px 1px 6px; -} -toolbar.vertical separator { - margin: 6px 1px 7px 0; -} -toolbar:not(.inline-toolbar):not(.osd) > *:not(.toggle):not(.popup) > * { - margin-right: 1px; - margin-bottom: 1px; -} - -.inline-toolbar { - background-color: @window_bg_color; - border-color: alpha(currentColor,0.15); - border-style: solid; - padding: 3px; - border-width: 0 1px 1px; - border-radius: 0 0 5px 5px; -} - -searchbar > revealer > box, -.location-bar { - border-width: 0 0 1px; - border-style: solid; - border-color: alpha(currentColor,0.15); - padding: 3px; -} - -searchbar > revealer > box { - margin: -6px; - padding: 6px; -} - -.primary-toolbar, .toolbar { - background-color: @window_bg_color; -} -.primary-toolbar:backdrop, .toolbar:backdrop { - background-color: @window_bg_color; -} - -.titlebar:not(headerbar), -headerbar { - padding: 0 6px; - min-height: 46px; - border-width: 0 0 1px; - border-style: solid; - border-color: @headerbar_shade_color; - border-radius: 0; - background: @headerbar_bg_color linear-gradient(to top, @headerbar_bg_color, @headerbar_bg_color); -} -.titlebar:backdrop:not(headerbar), -headerbar:backdrop { - background-color: @headerbar_backdrop_color; - background-image: none; - transition: 200ms ease-out; -} -.titlebar:not(headerbar) .title, -headerbar .title { - padding-left: 12px; - padding-right: 12px; - font-weight: bold; -} -.titlebar:not(headerbar) .subtitle, -headerbar .subtitle { - font-size: smaller; - padding-left: 12px; - padding-right: 12px; -} -.titlebar:not(headerbar) stackswitcher button:checked:backdrop, -.titlebar:not(headerbar) button.toggle:checked:backdrop, -headerbar stackswitcher button:checked:backdrop, -headerbar button.toggle:checked:backdrop { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.7); -} -.titlebar:not(headerbar) stackswitcher button:checked:backdrop:hover, -.titlebar:not(headerbar) button.toggle:checked:backdrop:hover, -headerbar stackswitcher button:checked:backdrop:hover, -headerbar button.toggle:checked:backdrop:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.6); -} -.selection-mode .titlebar:not(headerbar), .selection-mode.titlebar:not(headerbar), -.selection-mode headerbar, -headerbar.selection-mode { - color: @accent_fg_color; - border-color: mix(black,@accent_bg_color,0.85); - background: @accent_bg_color linear-gradient(to top, @accent_bg_color, @accent_bg_color); -} -.selection-mode .titlebar:backdrop:not(headerbar), .selection-mode.titlebar:backdrop:not(headerbar), -.selection-mode headerbar:backdrop, -headerbar.selection-mode:backdrop { - background-color: @accent_bg_color; - background-image: none; - box-shadow: inset 0 1px mix(alpha(white,0.5),@accent_bg_color,0.4); -} -.selection-mode .titlebar:backdrop:not(headerbar) label, .selection-mode.titlebar:backdrop:not(headerbar) label, -.selection-mode headerbar:backdrop label, -headerbar.selection-mode:backdrop label { - text-shadow: none; - color: @accent_fg_color; -} -.selection-mode .titlebar:not(headerbar) .subtitle:link, .selection-mode.titlebar:not(headerbar) .subtitle:link, -.selection-mode headerbar .subtitle:link, -headerbar.selection-mode .subtitle:link { - color: mix(@accent_fg_color,@accent_color,0.2); -} -.selection-mode .titlebar:not(headerbar) button, .selection-mode.titlebar:not(headerbar) button, -.selection-mode headerbar button, -headerbar.selection-mode button { - color: @accent_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.9); -} -.selection-mode .titlebar:not(headerbar) button.flat, .selection-mode.titlebar:not(headerbar) button.flat, -.selection-mode headerbar button.flat, -headerbar.selection-mode button.flat { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} - -.selection-mode .titlebar:not(headerbar) button:hover, .selection-mode.titlebar:not(headerbar) button:hover, -.selection-mode headerbar button:hover, -headerbar.selection-mode button:hover { - color: @accent_fg_color; - background-color: mix(@accent_fg_color,@accent_bg_color,0.85); - box-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button:active, .selection-mode .titlebar:not(headerbar) button:checked, .selection-mode.titlebar:not(headerbar) button:active, .selection-mode.titlebar:not(headerbar) button:checked, -.selection-mode headerbar button:active, -.selection-mode headerbar button:checked, -.selection-mode headerbar button.toggle:checked, -.selection-mode headerbar button.toggle:active, -headerbar.selection-mode button:active, -headerbar.selection-mode button:checked, -headerbar.selection-mode button.toggle:checked, -headerbar.selection-mode button.toggle:active { - color: @accent_fg_color; - background-color: mix(@accent_fg_color,@accent_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button:active:hover, .selection-mode .titlebar:not(headerbar) button:checked:hover, .selection-mode.titlebar:not(headerbar) button:active:hover, .selection-mode.titlebar:not(headerbar) button:checked:hover, -.selection-mode headerbar button:active:hover, -.selection-mode headerbar button:checked:hover, -.selection-mode headerbar button.toggle:checked:hover, -.selection-mode headerbar button.toggle:active:hover, -headerbar.selection-mode button:active:hover, -headerbar.selection-mode button:checked:hover, -headerbar.selection-mode button.toggle:checked:hover, -headerbar.selection-mode button.toggle:active:hover { - background-color: mix(@accent_fg_color,@accent_bg_color,0.65); -} -.selection-mode .titlebar:not(headerbar) button:backdrop, .selection-mode.titlebar:not(headerbar) button:backdrop, -.selection-mode headerbar button:backdrop.flat, -.selection-mode headerbar button:backdrop, -headerbar.selection-mode button:backdrop.flat, -headerbar.selection-mode button:backdrop { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; - -gtk-icon-effect: none; - border-color: transparent; -} -.selection-mode .titlebar:not(headerbar) button:backdrop:active, .selection-mode .titlebar:not(headerbar) button:backdrop:checked, .selection-mode.titlebar:not(headerbar) button:backdrop:active, .selection-mode.titlebar:not(headerbar) button:backdrop:checked, -.selection-mode headerbar button:backdrop.flat:active, -.selection-mode headerbar button:backdrop.flat:checked, -.selection-mode headerbar button:backdrop:active, -.selection-mode headerbar button:backdrop:checked, -headerbar.selection-mode button:backdrop.flat:active, -headerbar.selection-mode button:backdrop.flat:checked, -headerbar.selection-mode button:backdrop:active, -headerbar.selection-mode button:backdrop:checked { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.7); -} -.selection-mode .titlebar:not(headerbar) button:backdrop:active:hover, .selection-mode .titlebar:not(headerbar) button:backdrop:checked:hover, .selection-mode.titlebar:not(headerbar) button:backdrop:active:hover, .selection-mode.titlebar:not(headerbar) button:backdrop:checked:hover, -.selection-mode headerbar button:backdrop.flat:active:hover, -.selection-mode headerbar button:backdrop.flat:checked:hover, -.selection-mode headerbar button:backdrop:active:hover, -.selection-mode headerbar button:backdrop:checked:hover, -headerbar.selection-mode button:backdrop.flat:active:hover, -headerbar.selection-mode button:backdrop.flat:checked:hover, -headerbar.selection-mode button:backdrop:active:hover, -headerbar.selection-mode button:backdrop:checked:hover { - background-color: mix(@accent_fg_color,@accent_bg_color,0.6); -} -.selection-mode .titlebar:not(headerbar) button:backdrop:disabled, .selection-mode.titlebar:not(headerbar) button:backdrop:disabled, -.selection-mode headerbar button:backdrop.flat:disabled, -.selection-mode headerbar button:backdrop:disabled, -headerbar.selection-mode button:backdrop.flat:disabled, -headerbar.selection-mode button:backdrop:disabled { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button:backdrop:disabled:active, .selection-mode .titlebar:not(headerbar) button:backdrop:disabled:checked, .selection-mode.titlebar:not(headerbar) button:backdrop:disabled:active, .selection-mode.titlebar:not(headerbar) button:backdrop:disabled:checked, -.selection-mode headerbar button:backdrop.flat:disabled:active, -.selection-mode headerbar button:backdrop.flat:disabled:checked, -.selection-mode headerbar button:backdrop:disabled:active, -.selection-mode headerbar button:backdrop:disabled:checked, -headerbar.selection-mode button:backdrop.flat:disabled:active, -headerbar.selection-mode button:backdrop.flat:disabled:checked, -headerbar.selection-mode button:backdrop:disabled:active, -headerbar.selection-mode button:backdrop:disabled:checked { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.7); -} -.selection-mode .titlebar:not(headerbar) button.flat:backdrop, .selection-mode .titlebar:not(headerbar) button.flat:disabled, .selection-mode.titlebar:not(headerbar) button.flat:backdrop, .selection-mode.titlebar:not(headerbar) button.flat:disabled, -.selection-mode headerbar button.flat:backdrop, -.selection-mode headerbar button.flat:disabled, -.selection-mode headerbar button.flat:backdrop:disabled, -headerbar.selection-mode button.flat:backdrop, -headerbar.selection-mode button.flat:disabled, -headerbar.selection-mode button.flat:backdrop:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} - -.selection-mode .titlebar:not(headerbar) button:disabled, .selection-mode.titlebar:not(headerbar) button:disabled, -.selection-mode headerbar button:disabled, -headerbar.selection-mode button:disabled { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button:disabled:active, .selection-mode .titlebar:not(headerbar) button:disabled:checked, .selection-mode.titlebar:not(headerbar) button:disabled:active, .selection-mode.titlebar:not(headerbar) button:disabled:checked, -.selection-mode headerbar button:disabled:active, -.selection-mode headerbar button:disabled:checked, -headerbar.selection-mode button:disabled:active, -headerbar.selection-mode button:disabled:checked { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,@accent_bg_color,0.7); - box-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button.suggested-action, .selection-mode.titlebar:not(headerbar) button.suggested-action, -.selection-mode headerbar button.suggested-action, -headerbar.selection-mode button.suggested-action { - color: @window_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - border-color: mix(black,@accent_bg_color,0.85); -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:hover, .selection-mode.titlebar:not(headerbar) button.suggested-action:hover, -.selection-mode headerbar button.suggested-action:hover, -headerbar.selection-mode button.suggested-action:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:active, .selection-mode.titlebar:not(headerbar) button.suggested-action:active, -.selection-mode headerbar button.suggested-action:active, -headerbar.selection-mode button.suggested-action:active { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:active:hover, .selection-mode.titlebar:not(headerbar) button.suggested-action:active:hover, -.selection-mode headerbar button.suggested-action:active:hover, -headerbar.selection-mode button.suggested-action:active:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.65); -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:disabled, .selection-mode.titlebar:not(headerbar) button.suggested-action:disabled, -.selection-mode headerbar button.suggested-action:disabled, -headerbar.selection-mode button.suggested-action:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:backdrop, .selection-mode.titlebar:not(headerbar) button.suggested-action:backdrop, -.selection-mode headerbar button.suggested-action:backdrop, -headerbar.selection-mode button.suggested-action:backdrop { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -.selection-mode .titlebar:not(headerbar) button.suggested-action:backdrop:disabled, .selection-mode.titlebar:not(headerbar) button.suggested-action:backdrop:disabled, -.selection-mode headerbar button.suggested-action:backdrop:disabled, -headerbar.selection-mode button.suggested-action:backdrop:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -.selection-mode .titlebar:not(headerbar) .selection-menu, .selection-mode.titlebar:not(headerbar) .selection-menu, -.selection-mode headerbar .selection-menu:backdrop, -.selection-mode headerbar .selection-menu, -headerbar.selection-mode .selection-menu:backdrop, -headerbar.selection-mode .selection-menu { - border-color: alpha(@accent_bg_color,0); - background-color: alpha(@accent_bg_color,0); - background-image: none; - box-shadow: none; - min-height: 20px; - padding: 6px 10px; -} -.selection-mode .titlebar:not(headerbar) .selection-menu arrow, .selection-mode.titlebar:not(headerbar) .selection-menu arrow, -.selection-mode headerbar .selection-menu:backdrop arrow, -.selection-mode headerbar .selection-menu arrow, -headerbar.selection-mode .selection-menu:backdrop arrow, -headerbar.selection-mode .selection-menu arrow { - -GtkArrow-arrow-scaling: 1; -} -.selection-mode .titlebar:not(headerbar) .selection-menu .arrow, .selection-mode.titlebar:not(headerbar) .selection-menu .arrow, -.selection-mode headerbar .selection-menu:backdrop .arrow, -.selection-mode headerbar .selection-menu .arrow, -headerbar.selection-mode .selection-menu:backdrop .arrow, -headerbar.selection-mode .selection-menu .arrow { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); - color: alpha(@accent_fg_color,0.5); - -gtk-icon-shadow: none; -} -.tiled .titlebar:not(headerbar), .tiled-top .titlebar:not(headerbar), .tiled-right .titlebar:not(headerbar), .tiled-bottom .titlebar:not(headerbar), .tiled-left .titlebar:not(headerbar), .maximized .titlebar:not(headerbar), .fullscreen .titlebar:not(headerbar), -.tiled headerbar:backdrop, -.tiled headerbar, -.tiled-top headerbar:backdrop, -.tiled-top headerbar, -.tiled-right headerbar:backdrop, -.tiled-right headerbar, -.tiled-bottom headerbar:backdrop, -.tiled-bottom headerbar, -.tiled-left headerbar:backdrop, -.tiled-left headerbar, -.maximized headerbar:backdrop, -.maximized headerbar, -.fullscreen headerbar:backdrop, -.fullscreen headerbar { - border-radius: 0; -} -.default-decoration.titlebar:not(headerbar), -headerbar.default-decoration { - min-height: 36px; - padding: 0 6px 0 6px; -} -.default-decoration.titlebar:not(headerbar) button.titlebutton, -headerbar.default-decoration button.titlebutton { - border-radius: 100%; -} -.titlebar:not(headerbar) separator.titlebutton, -headerbar separator.titlebutton { - opacity: 0; -} -.solid-csd .titlebar:dir(rtl):not(headerbar), .solid-csd .titlebar:dir(ltr):not(headerbar), -.solid-csd headerbar:backdrop:dir(rtl), -.solid-csd headerbar:backdrop:dir(ltr), -.solid-csd headerbar:dir(rtl), -.solid-csd headerbar:dir(ltr) { - margin-left: -1px; - margin-right: -1px; - margin-top: -1px; - border-radius: 0; - box-shadow: none; -} - -headerbar entry, -headerbar spinbutton, -headerbar separator:not(.sidebar), -headerbar button { - margin-top: 6px; - margin-bottom: 6px; -} -headerbar switch { - margin-top: 9px; - margin-bottom: 9px; -} -headerbar.titlebar headerbar:not(.titlebar) { - background: none; - box-shadow: none; -} - -.background .titlebar:backdrop, .background .titlebar { - border-top-left-radius: 15px; - border-top-right-radius: 15px; -} - -.background.tiled .titlebar:backdrop, .background.tiled .titlebar, -.background.tiled-top .titlebar:backdrop, -.background.tiled-top .titlebar, -.background.tiled-right .titlebar:backdrop, -.background.tiled-right .titlebar, -.background.tiled-bottom .titlebar:backdrop, -.background.tiled-bottom .titlebar, -.background.tiled-left .titlebar:backdrop, -.background.tiled-left .titlebar, -.background.maximized .titlebar:backdrop, -.background.maximized .titlebar, -.background.solid-csd .titlebar:backdrop, -.background.solid-csd .titlebar { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -window separator:first-child + headerbar:backdrop, window separator:first-child + headerbar, window headerbar:first-child:backdrop, window headerbar:first-child { - border-top-left-radius: 15px; -} -window headerbar:last-child:backdrop, window headerbar:last-child { - border-top-right-radius: 15px; -} -window stack headerbar:first-child:backdrop, window stack headerbar:first-child, window stack headerbar:last-child:backdrop, window stack headerbar:last-child { - border-top-left-radius: 15px; - border-top-right-radius: 15px; -} -window.tiled headerbar, window.tiled headerbar:first-child, window.tiled headerbar:last-child, window.tiled headerbar:only-child, window.tiled headerbar:backdrop, window.tiled headerbar:backdrop:first-child, window.tiled headerbar:backdrop:last-child, window.tiled headerbar:backdrop:only-child, window.tiled-top headerbar, window.tiled-top headerbar:first-child, window.tiled-top headerbar:last-child, window.tiled-top headerbar:only-child, window.tiled-top headerbar:backdrop, window.tiled-top headerbar:backdrop:first-child, window.tiled-top headerbar:backdrop:last-child, window.tiled-top headerbar:backdrop:only-child, window.tiled-right headerbar, window.tiled-right headerbar:first-child, window.tiled-right headerbar:last-child, window.tiled-right headerbar:only-child, window.tiled-right headerbar:backdrop, window.tiled-right headerbar:backdrop:first-child, window.tiled-right headerbar:backdrop:last-child, window.tiled-right headerbar:backdrop:only-child, window.tiled-bottom headerbar, window.tiled-bottom headerbar:first-child, window.tiled-bottom headerbar:last-child, window.tiled-bottom headerbar:only-child, window.tiled-bottom headerbar:backdrop, window.tiled-bottom headerbar:backdrop:first-child, window.tiled-bottom headerbar:backdrop:last-child, window.tiled-bottom headerbar:backdrop:only-child, window.tiled-left headerbar, window.tiled-left headerbar:first-child, window.tiled-left headerbar:last-child, window.tiled-left headerbar:only-child, window.tiled-left headerbar:backdrop, window.tiled-left headerbar:backdrop:first-child, window.tiled-left headerbar:backdrop:last-child, window.tiled-left headerbar:backdrop:only-child, window.maximized headerbar, window.maximized headerbar:first-child, window.maximized headerbar:last-child, window.maximized headerbar:only-child, window.maximized headerbar:backdrop, window.maximized headerbar:backdrop:first-child, window.maximized headerbar:backdrop:last-child, window.maximized headerbar:backdrop:only-child, window.fullscreen headerbar, window.fullscreen headerbar:first-child, window.fullscreen headerbar:last-child, window.fullscreen headerbar:only-child, window.fullscreen headerbar:backdrop, window.fullscreen headerbar:backdrop:first-child, window.fullscreen headerbar:backdrop:last-child, window.fullscreen headerbar:backdrop:only-child, window.solid-csd headerbar, window.solid-csd headerbar:first-child, window.solid-csd headerbar:last-child, window.solid-csd headerbar:only-child, window.solid-csd headerbar:backdrop, window.solid-csd headerbar:backdrop:first-child, window.solid-csd headerbar:backdrop:last-child, window.solid-csd headerbar:backdrop:only-child { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -window.csd > .titlebar:not(headerbar) { - padding: 0; - background-color: transparent; - background-image: none; - border-style: none; - border-color: transparent; - box-shadow: none; -} -.titlebar:not(headerbar) separator { - background-color: alpha(currentColor,0.15); -} -.titlebar:not(headerbar) separator:backdrop { - background-color: mix(currentColor,@window_bg_color,0.81); -} - -window.devel headerbar.titlebar:not(.selection-mode) { - background: @window_bg_color cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, linear-gradient(to right, transparent 65%, alpha(@accent_bg_color,0.2)), linear-gradient(to top, mix(black,@headerbar_bg_color,0.97), @headerbar_bg_color 3px, mix(white,@headerbar_bg_color,0.94)); -} -window.devel headerbar.titlebar:not(.selection-mode):backdrop { - background: @headerbar_backdrop_color cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, image(@headerbar_backdrop_color); -} - -headerbar { - box-shadow: 0 1px alpha(@headerbar_shade_color,0.3); -} - -headerbar:not(.selection-mode), headerbar:not(.selection-mode) entry, .titlebar:not(.selection-mode), .titlebar:not(.selection-mode) entry { - color: @headerbar_fg_color; -} -headerbar:not(.selection-mode):backdrop, -headerbar:not(.selection-mode) entry:backdrop, .titlebar:not(.selection-mode):backdrop, -.titlebar:not(.selection-mode) entry:backdrop { - color: mix(@headerbar_fg_color,@headerbar_bg_color,0.5); -} -headerbar:not(.selection-mode) entry:disabled, .titlebar:not(.selection-mode) entry:disabled { - color: mix(@headerbar_fg_color,@headerbar_bg_color,0.5); -} -headerbar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action), .titlebar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action) { - color: @headerbar_fg_color; -} -headerbar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action):backdrop, .titlebar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action):backdrop { - color: mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5); -} -headerbar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action):disabled, .titlebar:not(.selection-mode) button:not(.suggested-action):not(.destructive-action):disabled { - color: mix(@headerbar_fg_color,@headerbar_bg_color,0.5); -} -headerbar:not(.selection-mode) switch image, .titlebar:not(.selection-mode) switch image { - color: transparent; -} -headerbar button:not(.titlebutton), headerbar button:not(.titlebutton):backdrop, .titlebar button:not(.titlebutton), .titlebar button:not(.titlebutton):backdrop { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar .linked.raised button:not(:only-child):not(:first-child), -headerbar .linked button:not(:only-child):not(:first-child), headerbar > .stack-switcher.linked > button:not(:only-child):not(:first-child), .titlebar .linked.raised button:not(:only-child):not(:first-child), -.titlebar .linked button:not(:only-child):not(:first-child), .titlebar > .stack-switcher.linked > button:not(:only-child):not(:first-child) { - border-left-color: alpha(currentColor,0.15); -} -headerbar .linked.raised button:not(:only-child):not(:last-child), -headerbar .linked button:not(:only-child):not(:last-child), headerbar > .stack-switcher.linked > button:not(:only-child):not(:last-child), .titlebar .linked.raised button:not(:only-child):not(:last-child), -.titlebar .linked button:not(:only-child):not(:last-child), .titlebar > .stack-switcher.linked > button:not(:only-child):not(:last-child) { - border-right-color: alpha(currentColor,0.15); -} -headerbar .linked.raised button:not(:only-child):first-child, -headerbar .linked button:not(:only-child):first-child, headerbar > .stack-switcher.linked > button:not(:only-child):first-child, .titlebar .linked.raised button:not(:only-child):first-child, -.titlebar .linked button:not(:only-child):first-child, .titlebar > .stack-switcher.linked > button:not(:only-child):first-child { - border-left-color: transparent; -} -headerbar .linked.raised button:not(:only-child):last-child, -headerbar .linked button:not(:only-child):last-child, headerbar > .stack-switcher.linked > button:not(:only-child):last-child, .titlebar .linked.raised button:not(:only-child):last-child, -.titlebar .linked button:not(:only-child):last-child, .titlebar > .stack-switcher.linked > button:not(:only-child):last-child { - border-right-color: transparent; -} -headerbar .linked.raised button:not(:only-child):first-child:not(:backdrop):checked, headerbar .linked.raised button:not(:only-child):first-child:not(:backdrop):active, headerbar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):checked, headerbar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):active, -headerbar .linked button:not(:only-child):first-child:not(:backdrop):checked, -headerbar .linked button:not(:only-child):first-child:not(:backdrop):active, -headerbar .linked button:not(:only-child):not(:last-child):not(:backdrop):checked, -headerbar .linked button:not(:only-child):not(:last-child):not(:backdrop):active, headerbar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):checked, headerbar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):active, headerbar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):checked, headerbar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):active, .titlebar .linked.raised button:not(:only-child):first-child:not(:backdrop):checked, .titlebar .linked.raised button:not(:only-child):first-child:not(:backdrop):active, .titlebar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):checked, .titlebar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):active, -.titlebar .linked button:not(:only-child):first-child:not(:backdrop):checked, -.titlebar .linked button:not(:only-child):first-child:not(:backdrop):active, -.titlebar .linked button:not(:only-child):not(:last-child):not(:backdrop):checked, -.titlebar .linked button:not(:only-child):not(:last-child):not(:backdrop):active, .titlebar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):checked, .titlebar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):active, .titlebar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):checked, .titlebar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):active { - box-shadow: inset -1px 0 alpha(currentColor,0.15); -} -headerbar .linked.raised button:not(:only-child):first-child:not(:backdrop):checked + button, headerbar .linked.raised button:not(:only-child):first-child:not(:backdrop):active + button, headerbar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):checked + button, headerbar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):active + button, -headerbar .linked button:not(:only-child):first-child:not(:backdrop):checked + button, -headerbar .linked button:not(:only-child):first-child:not(:backdrop):active + button, -headerbar .linked button:not(:only-child):not(:last-child):not(:backdrop):checked + button, -headerbar .linked button:not(:only-child):not(:last-child):not(:backdrop):active + button, headerbar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):checked + button, headerbar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):active + button, headerbar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):checked + button, headerbar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):active + button, .titlebar .linked.raised button:not(:only-child):first-child:not(:backdrop):checked + button, .titlebar .linked.raised button:not(:only-child):first-child:not(:backdrop):active + button, .titlebar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):checked + button, .titlebar .linked.raised button:not(:only-child):not(:last-child):not(:backdrop):active + button, -.titlebar .linked button:not(:only-child):first-child:not(:backdrop):checked + button, -.titlebar .linked button:not(:only-child):first-child:not(:backdrop):active + button, -.titlebar .linked button:not(:only-child):not(:last-child):not(:backdrop):checked + button, -.titlebar .linked button:not(:only-child):not(:last-child):not(:backdrop):active + button, .titlebar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):checked + button, .titlebar > .stack-switcher.linked > button:not(:only-child):first-child:not(:backdrop):active + button, .titlebar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):checked + button, .titlebar > .stack-switcher.linked > button:not(:only-child):not(:last-child):not(:backdrop):active + button { - border-left-color: transparent; -} -headerbar.selection-mode button:hover:backdrop, .titlebar.selection-mode button:hover:backdrop { - color: alpha(@accent_fg_color,0.5); - background-color: mix(@accent_fg_color,alpha(@accent_bg_color,0.5),0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar entry, .titlebar entry { - min-height: 32px; - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -headerbar entry:backdrop, .titlebar entry:backdrop { - color: mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5); - outline-color: alpha(@accent_color,0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.9); -} -headerbar entry:disabled, .titlebar entry:disabled { - color: alpha(mix(@headerbar_fg_color,@headerbar_bg_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_bg_color,0.5),@headerbar_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -headerbar entry:disabled:backdrop, .titlebar entry:disabled:backdrop { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -headerbar entry image.left, .titlebar entry image.left { - margin-right: 6px; -} -headerbar entry image.right, .titlebar entry image.right { - margin-left: 6px; -} -headerbar entry image, .titlebar entry image { - color: mix(@window_fg_color,@view_bg_color,0.2); -} -headerbar entry image:hover, .titlebar entry image:hover { - color: @headerbar_fg_color; -} -headerbar entry image:active, .titlebar entry image:active { - color: @accent_bg_color; -} -headerbar entry image:backdrop, .titlebar entry image:backdrop { - color: mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.2); -} -headerbar entry.error, .titlebar entry.error { - color: @error_bg_color; - border-color: @error_bg_color; -} -headerbar entry.error:focus, .titlebar entry.error:focus { - box-shadow: inset 0 0 0 1px @error_bg_color; - border-color: @error_bg_color; - transition: 300ms ease-in-out; - transition-property: border, box-shadow; -} -headerbar entry.error selection, .titlebar entry.error selection { - background-color: @error_bg_color; -} -headerbar entry.warning, .titlebar entry.warning { - color: @warning_bg_color; - border-color: @warning_bg_color; -} -headerbar entry.warning:focus, .titlebar entry.warning:focus { - box-shadow: inset 0 0 0 1px @warning_bg_color; - border-color: @warning_bg_color; - transition: 300ms ease-in-out; - transition-property: border, box-shadow; -} -headerbar entry.warning selection, .titlebar entry.warning selection { - background-color: @warning_bg_color; -} -headerbar entry.flat:focus, headerbar entry.flat:backdrop, headerbar entry.flat:disabled, headerbar entry.flat:backdrop:disabled, headerbar entry.flat, .titlebar entry.flat:focus, .titlebar entry.flat:backdrop, .titlebar entry.flat:disabled, .titlebar entry.flat:backdrop:disabled, .titlebar entry.flat { - min-height: 0; - padding: 2px; - background-color: transparent; - border-color: transparent; - border-radius: 0; -} -headerbar entry:drop(active):focus, headerbar entry:drop(active), .titlebar entry:drop(active):focus, .titlebar entry:drop(active) { - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 1px @accent_bg_color; -} -headerbar entry progress, .titlebar entry progress { - margin: 2px -6px; - background-color: transparent; - background-image: none; - border-radius: 0; - border-width: 0 0 2px; - border-color: @accent_bg_color; - border-style: solid; - box-shadow: none; -} -headerbar entry progress:backdrop, .titlebar entry progress:backdrop { - background-color: transparent; -} -headerbar .linked entry:not(:first-child), .titlebar .linked entry:not(:first-child) { - border-left-color: alpha(currentColor,0.15); -} -headerbar .linked entry:not(:first-child):backdrop, .titlebar .linked entry:not(:first-child):backdrop { - border-left-color: alpha(currentColor,0.15); -} -headerbar switch:backdrop, .titlebar switch:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); - border-color: mix(currentColor,@window_bg_color,0.81); - background-color: mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.3); - text-shadow: none; - transition: 200ms ease-out; -} -headerbar switch:backdrop:checked, .titlebar switch:backdrop:checked { - color: @window_bg_color; - background-color: alpha(@accent_bg_color,0.5); -} -headerbar switch:backdrop:checked:disabled, .titlebar switch:backdrop:checked:disabled { - background-color: alpha(@accent_bg_color,0.3); -} -headerbar switch:backdrop:disabled, .titlebar switch:backdrop:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -headerbar switch:backdrop slider, .titlebar switch:backdrop slider { - transition: 200ms ease-out; - background-color: mix(@view_bg_color,mix(white,@view_bg_color,0.2),0.7); -} -headerbar switch:backdrop:checked > slider, .titlebar switch:backdrop:checked > slider { - background-color: mix(@view_bg_color,mix(white,@view_bg_color,0.2),0.7); -} -headerbar switch:backdrop:disabled slider, .titlebar switch:backdrop:disabled slider { - background-color: mix(@view_bg_color,mix(white,@view_bg_color,0.2),0.4); -} -headerbar switch:disabled, .titlebar switch:disabled { - background-color: shade(mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.3),0.96); -} -headerbar switch:disabled:backdrop, .titlebar switch:disabled:backdrop { - background-color: mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.3); -} -headerbar:not(:backdrop), .titlebar:not(:backdrop) { - transition: 50ms ease-in; - transition-property: background-color, background-image, box-shadow, border-color, color, text-shadow; -} -headerbar .right, .titlebar .right { - margin-left: -4px; -} -headerbar .right separator, .titlebar .right separator { - min-width: 0; -} -headerbar .left, .titlebar .left { - margin-right: -4px; -} -headerbar .left separator, .titlebar .left separator { - min-width: 0; -} - -.ssd .titlebar { - border-width: 0; - padding: 0px 4px; - min-height: 36px; - border-bottom: 1px solid @headerbar_shade_color; -} -.default-decoration .title { - color: @headerbar_fg_color; -} -.default-decoration .title:backdrop { - color: mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5); -} - -button.titlebutton:not(.appmenu), -headerbar.default-decoration button.titlebutton, .default-decoration.titlebar:not(headerbar) button.titlebutton, .ssd .titlebar.default-decoration button.titlebutton { - background-color: alpha(currentColor,0.1); - min-height: 24px; - min-width: 24px; - margin: 0 4px; - padding: 0; -} -button.titlebutton:hover:not(.appmenu), -headerbar.default-decoration button.titlebutton:hover, .default-decoration.titlebar:not(headerbar) button.titlebutton:hover, .ssd .titlebar.default-decoration button.titlebutton:hover { - background-color: alpha(currentColor,0.15); -} -button.titlebutton:active:not(.appmenu), -headerbar.default-decoration button.titlebutton:active, .default-decoration.titlebar:not(headerbar) button.titlebutton:active, .ssd .titlebar.default-decoration button.titlebutton:active { - background-color: alpha(currentColor,0.3); -} -button.titlebutton:backdrop:not(.appmenu), -headerbar.default-decoration button.titlebutton:backdrop, .default-decoration.titlebar:not(headerbar) button.titlebutton:backdrop, .ssd .titlebar.default-decoration button.titlebutton:backdrop { - background: alpha(currentColor,0.1); -} -button.titlebutton:backdrop:hover:not(.appmenu), -headerbar.default-decoration button.titlebutton:backdrop:hover, .default-decoration.titlebar:not(headerbar) button.titlebutton:backdrop:hover, .ssd .titlebar.default-decoration button.titlebutton:backdrop:hover { - background: alpha(currentColor,0.15); -} - -headerbar button.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button, -headerbar .linked button:not(:only-child), headerbar > .stack-switcher.linked > button, .titlebar .linked.raised button, -.titlebar .linked button:not(:only-child), .titlebar > .stack-switcher.linked > button, headerbar .linked entry ~ .image-button, .titlebar .linked entry ~ .image-button { - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -headerbar button.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:backdrop, -headerbar .linked button:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button:backdrop, .titlebar .linked.raised button:backdrop, -.titlebar .linked button:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button:backdrop, headerbar .linked entry ~ .image-button:backdrop, .titlebar .linked entry ~ .image-button:backdrop { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:hover, -headerbar .linked button:hover:not(:only-child), headerbar > .stack-switcher.linked > button:hover, .titlebar .linked.raised button:hover, -.titlebar .linked button:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:hover, headerbar .linked entry ~ .image-button:hover, .titlebar .linked entry ~ .image-button:hover { - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.85); - box-shadow: none; -} -headerbar button.text-button:hover:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:hover:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:hover:backdrop, -headerbar .linked button:hover:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button:hover:backdrop, .titlebar .linked.raised button:hover:backdrop, -.titlebar .linked button:hover:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button:hover:backdrop, headerbar .linked entry ~ .image-button:hover:backdrop, .titlebar .linked entry ~ .image-button:hover:backdrop { - color: mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.85); - box-shadow: none; -} -headerbar button.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active, -headerbar .linked button:active:not(:only-child), headerbar > .stack-switcher.linked > button:active, .titlebar .linked.raised button:active, -.titlebar .linked button:active:not(:only-child), .titlebar > .stack-switcher.linked > button:active, headerbar .linked entry ~ .image-button:active, .titlebar .linked entry ~ .image-button:active, headerbar button.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked, -headerbar .linked button:checked:not(:only-child), headerbar > .stack-switcher.linked > button:checked, .titlebar .linked.raised button:checked, -.titlebar .linked button:checked:not(:only-child), .titlebar > .stack-switcher.linked > button:checked, headerbar .linked entry ~ .image-button:checked, .titlebar .linked entry ~ .image-button:checked { - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:hover, -headerbar .linked button:active:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:hover, .titlebar .linked.raised button:active:hover, -.titlebar .linked button:active:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:hover, headerbar .linked entry ~ .image-button:active:hover, .titlebar .linked entry ~ .image-button:active:hover, headerbar button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:hover, -headerbar .linked button:checked:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:hover, .titlebar .linked.raised button:checked:hover, -.titlebar .linked button:checked:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:hover, headerbar .linked entry ~ .image-button:checked:hover, .titlebar .linked entry ~ .image-button:checked:hover { - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.65); -} -headerbar button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:hover, -headerbar .linked button:active:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:hover, .titlebar .linked.raised button:active:hover, -.titlebar .linked button:active:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:hover, headerbar .linked entry ~ .image-button:active:hover, .titlebar .linked entry ~ .image-button:active:hover, headerbar button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:hover, -headerbar .linked button:checked:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:hover, .titlebar .linked.raised button:checked:hover, -.titlebar .linked button:checked:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:hover, headerbar .linked entry ~ .image-button:checked:hover, .titlebar .linked entry ~ .image-button:checked:hover { - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button.text-button:active:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:hover:hover, -headerbar .linked button:active:hover:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:hover:hover, .titlebar .linked.raised button:active:hover:hover, -.titlebar .linked button:active:hover:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:hover:hover, headerbar .linked entry ~ .image-button:active:hover:hover, .titlebar .linked entry ~ .image-button:active:hover:hover, headerbar button.text-button:checked:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:hover:hover, -headerbar .linked button:checked:hover:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:hover:hover, .titlebar .linked.raised button:checked:hover:hover, -.titlebar .linked button:checked:hover:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:hover:hover, headerbar .linked entry ~ .image-button:checked:hover:hover, .titlebar .linked entry ~ .image-button:checked:hover:hover { - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.65); -} -headerbar button.text-button:active:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:backdrop, -headerbar .linked button:active:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button:active:backdrop, .titlebar .linked.raised button:active:backdrop, -.titlebar .linked button:active:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button:active:backdrop, headerbar .linked entry ~ .image-button:active:backdrop, .titlebar .linked entry ~ .image-button:active:backdrop, headerbar button.text-button:checked:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:backdrop:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:backdrop, -headerbar .linked button:checked:backdrop:not(:only-child), headerbar > .stack-switcher.linked > button:checked:backdrop, .titlebar .linked.raised button:checked:backdrop, -.titlebar .linked button:checked:backdrop:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:backdrop, headerbar .linked entry ~ .image-button:checked:backdrop, .titlebar .linked entry ~ .image-button:checked:backdrop { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.7); -} -headerbar button.text-button:active:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:backdrop:hover, -headerbar .linked button:active:backdrop:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:backdrop:hover, .titlebar .linked.raised button:active:backdrop:hover, -.titlebar .linked button:active:backdrop:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:backdrop:hover, headerbar .linked entry ~ .image-button:active:backdrop:hover, .titlebar .linked entry ~ .image-button:active:backdrop:hover, headerbar button.text-button:checked:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:backdrop:hover, -headerbar .linked button:checked:backdrop:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:backdrop:hover, .titlebar .linked.raised button:checked:backdrop:hover, -.titlebar .linked button:checked:backdrop:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:backdrop:hover, headerbar .linked entry ~ .image-button:checked:backdrop:hover, .titlebar .linked entry ~ .image-button:checked:backdrop:hover { - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.6); -} -headerbar button.text-button:active:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:backdrop:hover, -headerbar .linked button:active:backdrop:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:backdrop:hover, .titlebar .linked.raised button:active:backdrop:hover, -.titlebar .linked button:active:backdrop:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:backdrop:hover, headerbar .linked entry ~ .image-button:active:backdrop:hover, .titlebar .linked entry ~ .image-button:active:backdrop:hover, headerbar button.text-button:checked:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:backdrop:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:backdrop:hover, -headerbar .linked button:checked:backdrop:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:backdrop:hover, .titlebar .linked.raised button:checked:backdrop:hover, -.titlebar .linked button:checked:backdrop:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:backdrop:hover, headerbar .linked entry ~ .image-button:checked:backdrop:hover, .titlebar .linked entry ~ .image-button:checked:backdrop:hover { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.7); -} -headerbar button.text-button:active:backdrop:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:active:backdrop:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:active:backdrop:hover:hover, -headerbar .linked button:active:backdrop:hover:hover:not(:only-child), headerbar > .stack-switcher.linked > button:active:backdrop:hover:hover, .titlebar .linked.raised button:active:backdrop:hover:hover, -.titlebar .linked button:active:backdrop:hover:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:active:backdrop:hover:hover, headerbar .linked entry ~ .image-button:active:backdrop:hover:hover, .titlebar .linked entry ~ .image-button:active:backdrop:hover:hover, headerbar button.text-button:checked:backdrop:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:checked:backdrop:hover:hover:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:checked:backdrop:hover:hover, -headerbar .linked button:checked:backdrop:hover:hover:not(:only-child), headerbar > .stack-switcher.linked > button:checked:backdrop:hover:hover, .titlebar .linked.raised button:checked:backdrop:hover:hover, -.titlebar .linked button:checked:backdrop:hover:hover:not(:only-child), .titlebar > .stack-switcher.linked > button:checked:backdrop:hover:hover, headerbar .linked entry ~ .image-button:checked:backdrop:hover:hover, .titlebar .linked entry ~ .image-button:checked:backdrop:hover:hover { - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.6); -} -headerbar button.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:disabled, -headerbar .linked button:disabled:not(:only-child), headerbar > .stack-switcher.linked > button:disabled, .titlebar .linked.raised button:disabled, -.titlebar .linked button:disabled:not(:only-child), .titlebar > .stack-switcher.linked > button:disabled, headerbar .linked entry ~ .image-button:disabled, .titlebar .linked entry ~ .image-button:disabled { - color: alpha(mix(@headerbar_fg_color,@headerbar_bg_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_bg_color,0.5),@headerbar_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -headerbar button.text-button:backdrop:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.text-button:backdrop:disabled:not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button:backdrop:disabled, -headerbar .linked button:backdrop:disabled:not(:only-child), headerbar > .stack-switcher.linked > button:backdrop:disabled, .titlebar .linked.raised button:backdrop:disabled, -.titlebar .linked button:backdrop:disabled:not(:only-child), .titlebar > .stack-switcher.linked > button:backdrop:disabled, headerbar .linked entry ~ .image-button:backdrop:disabled, .titlebar .linked entry ~ .image-button:backdrop:disabled { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button.default.text-button:not(:backdrop):not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.default.text-button:not(:backdrop):not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.default:not(:backdrop):not(.suggested-action):not(.destructive-action), -headerbar .linked button.default:not(:backdrop):not(.suggested-action):not(.destructive-action):not(:only-child), headerbar > .stack-switcher.linked > button.default:not(:backdrop):not(.suggested-action):not(.destructive-action), .titlebar .linked.raised button.default:not(:backdrop):not(.suggested-action):not(.destructive-action), -.titlebar .linked button.default:not(:backdrop):not(.suggested-action):not(.destructive-action):not(:only-child), .titlebar > .stack-switcher.linked > button.default:not(:backdrop):not(.suggested-action):not(.destructive-action), headerbar .linked entry ~ .default.image-button:not(:backdrop):not(.suggested-action):not(.destructive-action), .titlebar .linked entry ~ .default.image-button:not(:backdrop):not(.suggested-action):not(.destructive-action) { - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -headerbar button.flat.text-button:not(:hover):not(:active):not(.suggested-action):not(.destructive-action):not(:disabled), .titlebar button.flat.text-button:not(:hover):not(:active):not(.suggested-action):not(.destructive-action):not(:disabled), headerbar .linked.raised button.flat:not(:hover):not(:active), -headerbar .linked button.flat:not(:hover):not(:active):not(:only-child), headerbar > .stack-switcher.linked > button.flat:not(:hover):not(:active), .titlebar .linked.raised button.flat:not(:hover):not(:active), -.titlebar .linked button.flat:not(:hover):not(:active):not(:only-child), .titlebar > .stack-switcher.linked > button.flat:not(:hover):not(:active), headerbar .linked entry ~ .flat.image-button:not(:hover):not(:active), .titlebar .linked entry ~ .flat.image-button:not(:hover):not(:active) { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button:hover:not(.titlebutton), .titlebar button:hover:not(.titlebutton), headerbar viewswitcher button.radio:hover:checked, .titlebar viewswitcher button.radio:hover:checked { - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -headerbar button:hover:backdrop:not(.titlebutton), .titlebar button:hover:backdrop:not(.titlebutton), headerbar viewswitcher button.radio:hover:backdrop:checked, .titlebar viewswitcher button.radio:hover:backdrop:checked { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.9); - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button:active:not(.titlebutton), .titlebar button:active:not(.titlebutton), headerbar button:checked:not(.titlebutton), .titlebar button:checked:not(.titlebutton), headerbar viewswitcher button.radio:checked, .titlebar viewswitcher button.radio:checked { - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button:active:hover:not(.titlebutton), .titlebar button:active:hover:not(.titlebutton), headerbar button:checked:hover:not(.titlebutton), .titlebar button:checked:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:hover, .titlebar viewswitcher button.radio:checked:hover { - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.65); -} -headerbar button:active:hover:not(.titlebutton), .titlebar button:active:hover:not(.titlebutton), headerbar button:checked:hover:not(.titlebutton), .titlebar button:checked:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:hover, .titlebar viewswitcher button.radio:checked:hover { - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -headerbar button:active:hover:hover:not(.titlebutton), .titlebar button:active:hover:hover:not(.titlebutton), headerbar button:checked:hover:hover:not(.titlebutton), .titlebar button:checked:hover:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:hover:hover, .titlebar viewswitcher button.radio:checked:hover:hover { - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.65); -} -headerbar button:active:backdrop:not(.titlebutton), .titlebar button:active:backdrop:not(.titlebutton), headerbar button:checked:backdrop:not(.titlebutton), .titlebar button:checked:backdrop:not(.titlebutton), headerbar viewswitcher button.radio:checked:backdrop, .titlebar viewswitcher button.radio:checked:backdrop { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.7); -} -headerbar button:active:backdrop:hover:not(.titlebutton), .titlebar button:active:backdrop:hover:not(.titlebutton), headerbar button:checked:backdrop:hover:not(.titlebutton), .titlebar button:checked:backdrop:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:backdrop:hover, .titlebar viewswitcher button.radio:checked:backdrop:hover { - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.6); -} -headerbar button:active:backdrop:hover:not(.titlebutton), .titlebar button:active:backdrop:hover:not(.titlebutton), headerbar button:checked:backdrop:hover:not(.titlebutton), .titlebar button:checked:backdrop:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:backdrop:hover, .titlebar viewswitcher button.radio:checked:backdrop:hover { - color: alpha(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),0.5); - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.7); -} -headerbar button:active:backdrop:hover:hover:not(.titlebutton), .titlebar button:active:backdrop:hover:hover:not(.titlebutton), headerbar button:checked:backdrop:hover:hover:not(.titlebutton), .titlebar button:checked:backdrop:hover:hover:not(.titlebutton), headerbar viewswitcher button.radio:checked:backdrop:hover:hover, .titlebar viewswitcher button.radio:checked:backdrop:hover:hover { - background-color: mix(mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5),@headerbar_backdrop_color,0.6); -} -headerbar button.default:not(:backdrop):not(.suggested-action):not(.destructive-action):not(.titlebutton), .titlebar button.default:not(:backdrop):not(.suggested-action):not(.destructive-action):not(.titlebutton), headerbar viewswitcher button.default.radio:not(:backdrop):not(.suggested-action):not(.destructive-action):checked, .titlebar viewswitcher button.default.radio:not(:backdrop):not(.suggested-action):not(.destructive-action):checked { - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -headerbar button.flat:not(:hover):not(:active):not(.titlebutton), .titlebar button.flat:not(:hover):not(:active):not(.titlebutton), headerbar viewswitcher button.flat.radio:not(:hover):not(:active):checked, .titlebar viewswitcher button.flat.radio:not(:hover):not(:active):checked { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -.path-bar button.text-button, .path-bar button.image-button, .path-bar button { - padding-left: 4px; - padding-right: 4px; -} -.path-bar button.text-button.image-button label { - padding-left: 0; - padding-right: 0; -} -.path-bar button.text-button.image-button label:last-child, .path-bar button label:last-child { - padding-right: 8px; -} -.path-bar button.text-button.image-button label:first-child, .path-bar button label:first-child { - padding-left: 8px; -} -.path-bar button image { - padding-left: 4px; - padding-right: 4px; -} -.path-bar button.slider-button { - padding-left: 0; - padding-right: 0; -} - -* { - -GtkTreeView-horizontal-separator: 4; - -GtkTreeView-grid-line-width: 1; - -GtkTreeView-grid-line-pattern: ""; - -GtkTreeView-tree-line-width: 1; - -GtkTreeView-tree-line-pattern: ""; - -GtkTreeView-expander-size: 16; -} - -treeview.view { - border-left-color: mix(@window_fg_color,@view_bg_color,0.5); - border-top-color: @window_bg_color; -} -treeview.view:selected:focus, treeview.view:selected { - border-radius: 0; -} -treeview.view:selected:backdrop, treeview.view:selected { - border-left-color: mix(@accent_fg_color,@accent_bg_color,0.5); - border-top-color: alpha(@window_fg_color,0.1); -} -treeview.view:disabled { - color: alpha(@window_fg_color,0.5); -} -treeview.view:disabled:selected { - color: mix(@accent_fg_color,@accent_bg_color,0.6); -} -treeview.view:disabled:selected:backdrop { - color: mix(@window_bg_color,@accent_bg_color,0.7); -} -treeview.view.separator { - min-height: 2px; - color: @window_bg_color; -} -treeview.view:drop(active) { - border-style: solid none; - border-width: 1px; - border-color: mix(black,@accent_bg_color,0.85); -} -treeview.view:drop(active).after { - border-top-style: none; -} -treeview.view:drop(active).before { - border-bottom-style: none; -} -treeview.view.expander { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); -} -treeview.view.expander:dir(rtl) { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); -} -treeview.view.expander { - color: mix(@view_fg_color,@view_bg_color,0.3); -} -treeview.view.expander:hover { - color: @view_fg_color; -} -treeview.view.expander:checked { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); -} -treeview.view.progressbar { - color: @view_bg_color; - background-color: @accent_bg_color; - background-image: image(@accent_bg_color); - box-shadow: none; -} -treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { - color: @accent_bg_color; - background-image: image(@view_bg_color); -} -treeview.view.progressbar:selected:focus:backdrop, treeview.view.progressbar:selected:backdrop { - color: @accent_bg_color; - background-color: @window_bg_color; -} -treeview.view.progressbar:backdrop { - color: @window_bg_color; - background-image: none; - box-shadow: none; -} -treeview.view.trough { - background-color: alpha(@window_fg_color,0.1); -} -treeview.view.trough:selected:focus, treeview.view.trough:selected { - background-color: alpha(@accent_fg_color,0.3); -} -treeview.view header button { - padding: 3px 6px; - color: mix(@view_fg_color,@view_bg_color,0.6); - background-image: none; - background-color: @view_bg_color; - border-bottom: 1px solid mix(currentColor,@window_bg_color,0.85); - border-right: none; - border-left: none; - border-radius: 0; - box-shadow: none; - text-shadow: none; - font-size: smaller; -} -treeview.view header button:hover { - color: mix(@view_fg_color,@view_bg_color,0.3); - transition: none; - background-image: none; -} -treeview.view header button:active { - color: mix(@view_fg_color,@view_bg_color,0.25); - transition: none; - background-color: @view_bg_color; -} -treeview.view header button:disabled { - border-color: @window_bg_color; - background-image: none; -} -treeview.view header button:last-child:backdrop, treeview.view header button:last-child { - border-right-style: none; -} -treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, -treeview.view header.button.dnd:active, -treeview.view header.button.dnd:selected, -treeview.view header.button.dnd:hover, -treeview.view header.button.dnd { - padding: 3px 6px; - color: @accent_fg_color; - background-image: none; - background-color: @accent_bg_color; - border-style: none; - border-radius: 0; - box-shadow: none; - text-shadow: none; - transition: none; - font-size: smaller; -} -treeview.view acceleditor > label { - background-color: @accent_bg_color; -} - -treeview.view:not(:backdrop):not(:selected):hover { - background-color: alpha(currentColor,0.04); -} - -menubar, -.menubar { - -GtkWidget-window-dragging: true; - padding: 0; -} -menubar:backdrop, -.menubar:backdrop { - background-color: @window_bg_color; -} -menubar > menuitem, -.menubar > menuitem { - border-radius: 9px; - min-height: 16px; - padding: 4px 8px; -} -menubar > menuitem menu:dir(rtl), menubar > menuitem menu:dir(ltr), -.menubar > menuitem menu:dir(rtl), -.menubar > menuitem menu:dir(ltr) { - border-radius: 9px; - padding: 6px; -} -menubar > menuitem menu:dir(rtl) menuitem, menubar > menuitem menu:dir(ltr) menuitem, -.menubar > menuitem menu:dir(rtl) menuitem, -.menubar > menuitem menu:dir(ltr) menuitem { - border-radius: 9px; -} -menubar > menuitem:hover, -.menubar > menuitem:hover { - background-color: alpha(currentColor,0.1); -} -menubar > menuitem:disabled, -.menubar > menuitem:disabled { - color: alpha(@window_fg_color,0.5); - box-shadow: none; -} -menubar .csd.popup decoration, -.menubar .csd.popup decoration { - border-radius: 9px; -} - -.background.popup { - background-color: transparent; -} - -menu, -.menu, -.context-menu { - margin: 4px; - padding: 6px; - background-color: @popover_bg_color; - border: 1px solid mix(currentColor,@window_bg_color,0.85); -} -menu separator, -.menu separator, -.context-menu separator { - margin: 6px 0; -} -.csd menu, -.csd .menu, -.csd .context-menu { - border: none; - border-radius: 9px; -} -menu menuitem, -.menu menuitem, -.context-menu menuitem { - min-height: 16px; - min-width: 40px; - padding: 4px 6px; - text-shadow: none; - font-weight: normal; - border-radius: 9px; -} -menu menuitem:hover, -.menu menuitem:hover, -.context-menu menuitem:hover { - color: @window_fg_color; - background-color: alpha(currentColor,0.1); -} -menu menuitem:disabled, -.menu menuitem:disabled, -.context-menu menuitem:disabled { - color: alpha(@window_fg_color,0.5); -} -menu menuitem arrow, -.menu menuitem arrow, -.context-menu menuitem arrow { - min-height: 16px; - min-width: 16px; -} -menu menuitem arrow:dir(ltr), -.menu menuitem arrow:dir(ltr), -.context-menu menuitem arrow:dir(ltr) { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); - margin-left: 10px; -} -menu menuitem arrow:dir(rtl), -.menu menuitem arrow:dir(rtl), -.context-menu menuitem arrow:dir(rtl) { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); - margin-right: 10px; -} -menu menuitem label:dir(rtl), menu menuitem label:dir(ltr), -.menu menuitem label:dir(rtl), -.menu menuitem label:dir(ltr), -.context-menu menuitem label:dir(rtl), -.context-menu menuitem label:dir(ltr) { - color: inherit; -} -menu > arrow, -.menu > arrow, -.context-menu > arrow { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - min-height: 16px; - min-width: 16px; - padding: 4px; - background-color: @popover_bg_color; - border-radius: 0; -} -menu > arrow.top, -.menu > arrow.top, -.context-menu > arrow.top { - margin-top: -4px; - border-bottom: 1px solid mix(@window_fg_color,@view_bg_color,0.9); - border-top-right-radius: 9px; - border-top-left-radius: 9px; - -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); -} -menu > arrow.bottom, -.menu > arrow.bottom, -.context-menu > arrow.bottom { - margin-top: 8px; - margin-bottom: -12px; - border-top: 1px solid mix(@window_fg_color,@view_bg_color,0.9); - border-bottom-right-radius: 9px; - border-bottom-left-radius: 9px; - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); -} -menu > arrow:hover, -.menu > arrow:hover, -.context-menu > arrow:hover { - background-color: mix(@window_fg_color,@view_bg_color,0.9); -} -menu > arrow:disabled, -.menu > arrow:disabled, -.context-menu > arrow:disabled { - color: transparent; - background-color: transparent; - border-color: transparent; -} - -menuitem accelerator { - color: alpha(currentColor,0.55); -} -menuitem check, -menuitem radio { - min-height: 16px; - min-width: 16px; -} -menuitem check:dir(ltr), -menuitem radio:dir(ltr) { - margin-right: 7px; -} -menuitem check:dir(rtl), -menuitem radio:dir(rtl) { - margin-left: 7px; -} - -popover.background { - padding: 2px; - background-color: @popover_bg_color; - box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.09), 0 2px 8px 3px rgba(0, 0, 0, 0.05); -} -.csd popover.background, popover.background { - border: 1px solid mix(currentColor,@window_bg_color,0.85); - border-radius: 15px; -} -.csd popover.background { - background-clip: padding-box; - border-color: rgba(0, 0, 0, 0.14); -} -popover.background > list, -popover.background > .view, -popover.background > toolbar { - border-style: none; - background-color: transparent; -} -.csd popover.background.touch-selection, .csd popover.background.magnifier, popover.background.touch-selection, popover.background.magnifier { - border: 1px solid rgba(255, 255, 255, 0.1); -} -popover.background separator { - margin: 6px 0; -} -popover.background list separator { - margin: 0px; -} - -popover.background button { - color: @popover_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@popover_fg_color,@popover_bg_color,0.9); -} -popover.background button.flat:not(:hover):not(:active) { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -popover.background button:hover { - color: @popover_fg_color; - background-color: mix(@popover_fg_color,@popover_bg_color,0.85); - box-shadow: none; -} -popover.background button:active, popover.background button:checked { - color: @popover_fg_color; - background-color: mix(@popover_fg_color,@popover_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -popover.background button:active:hover, popover.background button:checked:hover { - background-color: mix(@popover_fg_color,@popover_bg_color,0.65); -} -popover.background button:disabled { - color: alpha(mix(@popover_fg_color,@popover_bg_color,0.5),0.5); - background-color: mix(mix(@popover_fg_color,@popover_bg_color,0.5),@popover_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -popover.background entry { - color: @popover_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@popover_fg_color,@popover_bg_color,0.9); -} -popover.background entry:disabled { - color: mix(@popover_fg_color,@popover_bg_color,0.5); - outline-color: alpha(@accent_color,0.5); - background-color: mix(mix(@popover_fg_color,@popover_bg_color,0.5),@popover_bg_color,0.9); -} - -popover.background modelbutton.flat { - padding-left: 16px; - padding-right: 16px; -} -popover.background modelbutton.flat, -popover.background .menuitem.button.flat { - color: @popover_fg_color; -} -popover.background modelbutton.flat:disabled label, -popover.background .menuitem.button.flat:disabled label { - color: mix(@popover_fg_color,@popover_bg_color,0.5); -} -popover.background modelbutton.flat:backdrop:hover, -popover.background .menuitem.button.flat:backdrop:hover { - background-color: alpha(currentColor,0.04); -} - -popover.menu > stack { - margin: -6px; -} - -notebook > header { - padding: 1px; - border-width: 1px; - background-clip: padding-box; - background-color: @window_bg_color; - border-color: alpha(currentColor,0.15); -} -notebook > header tabs { - margin: -1px; -} -notebook > header.top > tabs > tab:hover, notebook > header.bottom > tabs > tab:hover, notebook > header.left > tabs > tab:hover, notebook > header.right > tabs > tab:hover { - background-color: alpha(currentColor,0.07); -} -notebook > header.top { - border-bottom-style: solid; -} -notebook > header.top > tabs { - margin-bottom: -2px; -} -notebook > header.top > tabs > tab:not(.reorderable-page):hover { - box-shadow: inset 0 -4px alpha(currentColor,0.15); -} -notebook > header.top > tabs > tab:not(.reorderable-page):checked { - box-shadow: inset 0 -4px @accent_bg_color; -} -notebook > header.bottom { - border-top-style: solid; -} -notebook > header.bottom > tabs { - margin-top: -2px; -} -notebook > header.bottom > tabs > tab:not(.reorderable-page):hover { - box-shadow: inset 0 4px alpha(currentColor,0.15); -} -notebook > header.bottom > tabs > tab:not(.reorderable-page):checked { - box-shadow: inset 0 4px @accent_bg_color; -} -notebook > header.left { - border-right-style: solid; -} -notebook > header.left > tabs { - margin-right: -2px; -} -notebook > header.left > tabs > tab:not(.reorderable-page):hover { - box-shadow: inset -4px 0 alpha(currentColor,0.15); -} -notebook > header.left > tabs > tab:not(.reorderable-page):checked { - box-shadow: inset -4px 0 @accent_bg_color; -} -notebook > header.right { - border-left-style: solid; -} -notebook > header.right > tabs { - margin-left: -2px; -} -notebook > header.right > tabs > tab:not(.reorderable-page):hover { - box-shadow: inset 4px 0 alpha(currentColor,0.15); -} -notebook > header.right > tabs > tab:not(.reorderable-page):checked { - box-shadow: inset 4px 0 @accent_bg_color; -} -notebook > header.top > tabs > arrow { - border-top-style: none; -} -notebook > header.bottom > tabs > arrow { - border-bottom-style: none; -} -notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { - margin-left: -5px; - margin-right: -5px; - padding-left: 4px; - padding-right: 4px; -} -notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { - -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); -} -notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); -} - -notebook > header.left > tabs > arrow { - border-left-style: none; -} -notebook > header.right > tabs > arrow { - border-right-style: none; -} -notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { - margin-top: -5px; - margin-bottom: -5px; - padding-top: 4px; - padding-bottom: 4px; -} -notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { - -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); -} -notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); -} - -notebook > header > tabs > arrow { - min-height: 16px; - min-width: 16px; - border-radius: 0; -} -notebook > header > tabs > arrow:hover:not(:active) { - box-shadow: none; -} -notebook > header > tabs > arrow:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -notebook > header tab { - min-height: 30px; - min-width: 30px; - padding: 3px 12px; - color: @window_fg_color; - font-weight: normal; - border-width: 0px; - border-color: transparent; -} -notebook > header tab.reorderable-page { - -gtk-outline-radius: 11px; - margin: 4px 2px; - border-radius: 9px; -} -notebook > header tab.reorderable-page { - outline: 0 solid transparent; - outline-offset: 4px; - transition: outline-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -notebook > header tab.reorderable-page:focus { - outline-color: alpha(@accent_color,0.5); - outline-width: 2px; - outline-offset: -2px; -} -notebook > header tab.reorderable-page:hover { - background-color: alpha(currentColor,0.07); - box-shadow: none; -} -notebook > header tab.reorderable-page:checked { - background-color: alpha(currentColor,0.1); - box-shadow: none; -} -notebook > header tab.reorderable-page:checked:hover { - background-color: alpha(currentColor,0.12); -} -notebook > header tab button.flat { - color: alpha(currentColor,0.3); - padding: 0; - margin-top: 4px; - margin-bottom: 4px; - min-width: 20px; - min-height: 20px; - border-radius: 100%; -} -notebook > header tab button.flat:hover { - color: currentColor; - background-color: alpha(currentColor,0.15); -} -notebook > header tab button.flat:active { - background-color: alpha(currentColor,0.3); -} -notebook > header tab button.flat, notebook > header tab button.flat:backdrop { - color: alpha(currentColor,0.3); -} -notebook > header tab button.flat:last-child { - margin-left: 4px; - margin-right: -4px; -} -notebook > header tab button.flat:first-child { - margin-left: -4px; - margin-right: 4px; -} -notebook > header.top tabs, notebook > header.bottom tabs { - padding-left: 4px; - padding-right: 4px; -} -notebook > header.top tabs:not(:only-child), notebook > header.bottom tabs:not(:only-child) { - margin-left: 3px; - margin-right: 3px; -} -notebook > header.top tabs:not(:only-child):first-child, notebook > header.bottom tabs:not(:only-child):first-child { - margin-left: -1px; -} -notebook > header.top tabs:not(:only-child):last-child, notebook > header.bottom tabs:not(:only-child):last-child { - margin-right: -1px; -} -notebook > header.top tabs tab, notebook > header.bottom tabs tab { - margin-left: 4px; - margin-right: 4px; -} -notebook > header.top tabs tab.reorderable-page, notebook > header.bottom tabs tab.reorderable-page { - border-style: none; - margin-left: 0px; - margin-right: 0px; -} -notebook > header.left tabs, notebook > header.right tabs { - padding-top: 4px; - padding-bottom: 4px; -} -notebook > header.left tabs:not(:only-child), notebook > header.right tabs:not(:only-child) { - margin-top: 3px; - margin-bottom: 3px; -} -notebook > header.left tabs:not(:only-child):first-child, notebook > header.right tabs:not(:only-child):first-child { - margin-top: -1px; -} -notebook > header.left tabs:not(:only-child):last-child, notebook > header.right tabs:not(:only-child):last-child { - margin-bottom: -1px; -} -notebook > header.left tabs tab, notebook > header.right tabs tab { - margin-top: 4px; - margin-bottom: 4px; -} -notebook > header.left tabs tab.reorderable-page, notebook > header.right tabs tab.reorderable-page { - border-style: none solid; - margin-top: 0px; - margin-bottom: 0px; -} -notebook > header.top tab { - padding-bottom: 4px; -} -notebook > header.bottom tab { - padding-top: 4px; -} -notebook > stack:not(:only-child) { - background-color: @view_bg_color; -} - -* { - -GtkScrollbar-has-backward-stepper: false; - -GtkScrollbar-has-forward-stepper: false; -} - -scrollbar { - background-color: @view_bg_color; - transition: all 200ms linear; -} -scrollbar slider { - color: @window_fg_color; - min-width: 8px; - min-height: 8px; - margin: -1px; - border: 4px solid transparent; - border-radius: 10px; - background-clip: padding-box; - background-color: alpha(currentColor,0.2); - transition: all 200ms linear; -} -scrollbar slider:hover { - background-color: alpha(currentColor,0.4); -} -scrollbar slider:hover:active { - background-color: alpha(currentColor,0.6); -} -scrollbar slider:disabled { - background-color: transparent; -} -scrollbar.fine-tune slider, scrollbar.fine-tune slider:hover, scrollbar.fine-tune slider:active { - background-color: alpha(@accent_color,0.6); -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering) { - border-color: transparent; - opacity: 0.4; - background-color: transparent; - transition-property: background-color, min-height, min-width; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering) slider { - margin: 0; - min-width: 3px; - min-height: 3px; - background-color: @window_fg_color; - border: 1px solid white; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering) button { - min-width: 5px; - min-height: 5px; - background-color: @window_fg_color; - background-clip: padding-box; - border-radius: 100%; - border: 1px solid white; - -gtk-icon-source: none; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering).horizontal slider { - margin: 0 2px; - min-width: 40px; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering).horizontal button { - margin: 1px 2px; - min-width: 5px; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering).vertical slider { - margin: 2px 0; - min-height: 40px; -} -scrollbar.overlay-indicator:not(.dragging):not(.hovering).vertical button { - margin: 2px 1px; - min-height: 5px; -} -scrollbar.overlay-indicator.dragging, scrollbar.overlay-indicator.hovering { - opacity: 0.8; -} -scrollbar.horizontal slider { - min-width: 40px; -} -scrollbar.vertical slider { - min-height: 40px; -} -scrollbar button { - padding: 0; - min-width: 12px; - min-height: 12px; - border-style: none; - border-radius: 0; - transition-property: min-height, min-width, color; - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(currentColor,0.2); -} -scrollbar button:hover { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(currentColor,0.4); -} -scrollbar button:active, scrollbar button:checked { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(currentColor,0.6); -} -scrollbar button:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(currentColor,0.2); -} -scrollbar.vertical button.down { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); -} -scrollbar.vertical button.up { - -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); -} -scrollbar.horizontal button.down { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); -} -scrollbar.horizontal button.up { - -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); -} - -treeview ~ scrollbar.vertical { - border-top: 1px solid mix(currentColor,@window_bg_color,0.85); - margin-top: -1px; -} - -switch { - outline-offset: -4px; - padding: 3px; - border-radius: 14px; - color: @window_fg_color; - background-color: alpha(currentColor,0.15); -} -switch:hover:not(:checked) { - background-color: alpha(currentColor,0.2); -} -switch:checked { - color: @accent_fg_color; - background-color: @accent_bg_color; -} -switch:checked:hover { - background-image: image(alpha(currentColor,0.1)); -} -switch:checked:hover:active { - background-image: image(rgba(0, 0, 0, 0.2)); -} -switch:checked:disabled { - background-color: alpha(@accent_bg_color,0.5); -} -switch:disabled { - color: alpha(@window_fg_color,0.5); - border-color: transparent; - background-color: mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.3); - text-shadow: none; -} -switch slider { - margin: 0px; - min-width: 20px; - min-height: 20px; - background-color: mix(white,@view_bg_color,0.2); - border: 1px solid transparent; - border-radius: 50%; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - -gtk-outline-radius: 20px; -} -switch image { - color: transparent; -} -switch:hover slider { - background-color: white; -} -switch:checked > slider { - background-color: white; -} -switch:disabled slider { - background-color: mix(@view_bg_color,mix(white,@view_bg_color,0.2),0.5); - box-shadow: none; -} -row:selected switch { - box-shadow: none; - border-color: mix(black,@accent_bg_color,0.8); -} -row:selected switch:backdrop { - border-color: mix(black,@accent_bg_color,0.8); -} -row:selected switch > slider:checked, row:selected switch > slider { - border-color: mix(black,@accent_bg_color,0.8); -} - -.view.content-view.check:not(list), -.content-view:not(list) check { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: transparent; - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: none; - -gtk-icon-shadow: none; -} - -.view.content-view.check:hover:not(list), -.content-view:not(list) check:hover { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: transparent; - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: none; - -gtk-icon-shadow: none; -} - -.view.content-view.check:active:not(list), -.content-view:not(list) check:active { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: transparent; - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: none; - -gtk-icon-shadow: none; -} - -.view.content-view.check:backdrop:not(list), -.content-view:not(list) check:backdrop { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: transparent; - background-color: alpha(@window_fg_color,0.5); - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: none; - -gtk-icon-shadow: none; -} - -.view.content-view.check:checked:not(list), -.content-view:not(list) check:checked { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: rgba(255, 255, 255, 0.9); - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); - -gtk-icon-shadow: none; -} - -.view.content-view.check:checked:hover:not(list), -.content-view:not(list) check:checked:hover { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: rgba(255, 255, 255, 0.9); - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); - -gtk-icon-shadow: none; -} - -.view.content-view.check:checked:active:not(list), -.content-view:not(list) check:checked:active { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: rgba(255, 255, 255, 0.9); - background-color: @accent_bg_color; - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); - -gtk-icon-shadow: none; -} - -.view.content-view.check:backdrop:checked:not(list), -.content-view:not(list) check:backdrop:checked { - margin: 4px; - min-width: 32px; - min-height: 32px; - color: rgba(255, 255, 255, 0.7); - background-color: alpha(@window_fg_color,0.5); - border-radius: 5px; - background-image: none; - transition: 200ms; - box-shadow: none; - border-width: 0; - -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); - -gtk-icon-shadow: none; -} - -checkbutton.text-button, radiobutton.text-button { - padding: 2px 0; - outline-offset: 0; -} -checkbutton.text-button label:not(:only-child):first-child, radiobutton.text-button label:not(:only-child):first-child { - margin-left: 4px; -} -checkbutton.text-button label:not(:only-child):last-child, radiobutton.text-button label:not(:only-child):last-child { - margin-right: 4px; -} - -check, -radio { - margin: 0 4px; - padding: 1px; - min-height: 14px; - min-width: 14px; - border: 2px solid; - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - -gtk-icon-source: none; -} -check:only-child, -radio:only-child { - margin: 0; -} -popover check.left:dir(rtl), -popover radio.left:dir(rtl) { - margin-left: 0; - margin-right: 12px; -} -popover check.right:dir(ltr), -popover radio.right:dir(ltr) { - margin-left: 12px; - margin-right: 0; -} -check, -radio { - background-clip: padding-box; - background-image: image(transparent); - border-color: alpha(currentColor,0.15); - box-shadow: none; - color: @window_fg_color; -} -check:hover:not(:checked):not(:indeterminate), -radio:hover:not(:checked):not(:indeterminate) { - border-color: alpha(currentColor,0.2); -} -check:active, -radio:active { - box-shadow: none; -} -check:disabled, -radio:disabled { - box-shadow: none; - background-image: image(transparent); - color: alpha(@window_fg_color,0.5); - border-color: alpha(currentColor,0.15); -} -check:checked, -radio:checked { - background-clip: border-box; - background-image: image(@accent_bg_color); - border-color: @accent_bg_color; - box-shadow: none; - color: @accent_fg_color; -} -check:checked:hover:not(:checked):not(:indeterminate), -radio:checked:hover:not(:checked):not(:indeterminate) { - border-color: alpha(currentColor,0.2); -} -check:checked:active, -radio:checked:active { - box-shadow: none; -} -check:checked:disabled, -radio:checked:disabled { - box-shadow: none; - background-image: image(@accent_bg_color); - color: alpha(@accent_fg_color,0.5); - border-color: @accent_bg_color; -} -check:indeterminate, -radio:indeterminate { - background-clip: border-box; - background-image: image(@accent_bg_color); - border-color: @accent_bg_color; - box-shadow: none; - color: @accent_fg_color; -} -check:indeterminate:hover:not(:checked):not(:indeterminate), -radio:indeterminate:hover:not(:checked):not(:indeterminate) { - border-color: alpha(currentColor,0.2); -} -check:indeterminate:active, -radio:indeterminate:active { - box-shadow: none; -} -check:indeterminate:disabled, -radio:indeterminate:disabled { - box-shadow: none; - background-image: image(@accent_bg_color); - color: alpha(@accent_fg_color,0.5); - border-color: @accent_bg_color; -} -row:selected check, -row:selected radio { - border-color: mix(black,@accent_bg_color,0.8); -} -.osd check, -.osd radio { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.osd check:hover, -.osd radio:hover { - color: white; - border-color: transparent; - background-color: rgba(0, 0, 0, 0.65); - background-clip: padding-box; -} -.osd check:active, -.osd radio:active { - color: white; - border-color: transparent; - background-color: mix(black,currentColor,0.2); - background-clip: padding-box; -} -.osd check:backdrop, -.osd radio:backdrop { - color: rgba(255, 255, 255, 0.9); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.7)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.osd check:disabled, -.osd radio:disabled { - color: rgba(255, 255, 255, 0.5); - border-color: transparent; - background-color: transparent; - background-image: image(rgba(0, 0, 0, 0.5)); - background-clip: padding-box; - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -menu menuitem check, -menu menuitem radio { - margin: 0; - padding: 0; -} -menu menuitem check, menu menuitem check:hover, menu menuitem check:disabled, menu menuitem check:not(:checked), menu menuitem check:not(:checked):hover, menu menuitem check:not(:checked):disabled, menu menuitem check:checked, menu menuitem check:checked:hover, menu menuitem check:checked:disabled, menu menuitem check:indeterminate, menu menuitem check:indeterminate:hover, menu menuitem check:indeterminate:disabled, -menu menuitem radio, -menu menuitem radio:hover, -menu menuitem radio:disabled, -menu menuitem radio:not(:checked), -menu menuitem radio:not(:checked):hover, -menu menuitem radio:not(:checked):disabled, -menu menuitem radio:checked, -menu menuitem radio:checked:hover, -menu menuitem radio:checked:disabled, -menu menuitem radio:indeterminate, -menu menuitem radio:indeterminate:hover, -menu menuitem radio:indeterminate:disabled { - min-height: 14px; - min-width: 14px; - padding: 1px; - background-image: none; - background-color: transparent; - box-shadow: none; - -gtk-icon-shadow: none; - color: inherit; - border-width: 1px; - border-color: alpha(currentColor,0.4); -} - -check { - border-radius: 6px; -} -check:checked { - -gtk-icon-source: image(-gtk-recolor(url("assets/check-symbolic.svg")), -gtk-recolor(url("assets/check-symbolic.symbolic.png"))); -} -check:indeterminate { - -gtk-icon-source: image(-gtk-recolor(url("assets/dash-symbolic.svg")), -gtk-recolor(url("assets/dash-symbolic.symbolic.png"))); -} -menu menuitem check, -menu menuitem check:hover, -menu menuitem check:disabled, -menu menuitem check:checked, -menu menuitem check:checked:hover, -menu menuitem check:checked:disabled, -menu menuitem check:indeterminate, -menu menuitem check:indeterminate:hover, -menu menuitem check:indeterminate:disabled { - border: none; -} - -treeview.view radio:selected:focus, treeview.view radio:selected, -radio { - border-radius: 100%; -} -treeview.view radio:checked:selected, -radio:checked { - -gtk-icon-source: image(-gtk-recolor(url("assets/bullet-symbolic.svg")), -gtk-recolor(url("assets/bullet-symbolic.symbolic.png"))); -} -treeview.view radio:indeterminate:selected, -radio:indeterminate { - -gtk-icon-source: image(-gtk-recolor(url("assets/dash-symbolic.svg")), -gtk-recolor(url("assets/dash-symbolic.symbolic.png"))); -} - -menu menuitem radio:checked:not(:backdrop), menu menuitem radio:indeterminate:not(:backdrop), -menu menuitem check:checked:not(:backdrop), -menu menuitem check:indeterminate:not(:backdrop) { - transition: none; -} - -treeview.view check:selected:focus, treeview.view check:selected, -treeview.view radio:selected:focus, -treeview.view radio:selected { - color: @accent_fg_color; - border-color: mix(black,@accent_bg_color,0.85); -} - -treeview.view check:selected:focus, treeview.view check:selected { - border-radius: 6px; -} - -progressbar trough, scale fill, scale trough { - border-radius: 9px; - background-color: alpha(currentColor,0.15); -} -progressbar trough:disabled, scale fill:disabled, scale trough:disabled { - background-color: alpha(alpha(currentColor,0.15),0.5); -} -row:selected progressbar trough, progressbar row:selected trough, row:selected scale fill, scale row:selected fill, row:selected scale trough, scale row:selected trough { - border-color: mix(black,@accent_bg_color,0.85); -} -.osd progressbar trough, progressbar .osd trough, .osd scale fill, scale .osd fill, .osd scale trough, scale .osd trough { - border-color: rgba(0, 0, 0, 0.9); - background-color: rgba(0, 0, 0, 0.7); -} -.osd progressbar trough:disabled, progressbar .osd trough:disabled, .osd scale fill:disabled, scale .osd fill:disabled, .osd scale trough:disabled, scale .osd trough:disabled { - background-color: rgba(0, 0, 0, 0.5); -} - -progressbar progress, scale highlight { - border-radius: 9px; - background-color: @accent_bg_color; - color: @accent_fg_color; -} -progressbar progress:disabled, scale highlight:disabled { - background-color: mix(@accent_bg_color,@view_bg_color,0.5); - border-color: transparent; -} -row:selected progressbar progress, progressbar row:selected progress, row:selected scale highlight, scale row:selected highlight { - border-color: mix(black,@accent_bg_color,0.85); -} -.osd progressbar progress, progressbar .osd progress, .osd scale highlight, scale .osd highlight { - border-color: rgba(0, 0, 0, 0.9); -} -.osd progressbar progress:disabled, progressbar .osd progress:disabled, .osd scale highlight:disabled, scale .osd highlight:disabled { - border-color: transparent; -} - -scale { - min-height: 10px; - min-width: 10px; - padding: 12px; -} -scale slider { - min-height: 18px; - min-width: 18px; - margin: -9px; -} -scale.fine-tune.horizontal { - padding-top: 9px; - padding-bottom: 9px; - min-height: 16px; -} -scale.fine-tune.vertical { - padding-left: 9px; - padding-right: 9px; - min-width: 16px; -} -scale.fine-tune slider { - margin: -6px; -} -scale.fine-tune fill, -scale.fine-tune highlight, -scale.fine-tune trough { - border-radius: 5px; - -gtk-outline-radius: 7px; -} -scale trough { - outline-offset: 2px; - -gtk-outline-radius: 5px; -} -scale.horizontal trough { - min-height: 4px; -} -scale.vertical trough { - min-width: 4px; -} -scale fill:backdrop, scale fill { - background-color: mix(currentColor,@window_bg_color,0.85); -} -scale fill:disabled:backdrop, scale fill:disabled { - border-color: transparent; - background-color: transparent; -} -.osd scale fill { - background-color: mix(rgba(255, 255, 255, 0.9),rgba(0, 0, 0, 0.9),0.75); -} -.osd scale fill:disabled:backdrop, .osd scale fill:disabled { - border-color: transparent; - background-color: transparent; -} -scale slider { - background-color: mix(white,@view_bg_color,0.2); - box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.25); - border: 1px solid transparent; - border-radius: 100%; - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - transition-property: background, border, box-shadow; -} -scale slider:hover { - background-color: white; -} -scale slider:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; - background-color: mix(@view_bg_color,mix(white,@view_bg_color,0.2),0.5); - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15); -} -scale slider:backdrop { - transition: 200ms ease-out; - box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.15); -} -scale slider:backdrop:disabled { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15); -} -row:selected scale slider:disabled, row:selected scale slider { - border-color: mix(black,@accent_bg_color,0.85); -} -.osd scale slider { - background-color: mix(white,@view_bg_color,0.2); - box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.25); - border: 1px solid transparent; -} -.osd scale slider:hover { - background-color: white; -} -.osd scale slider:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} -.osd scale slider:backdrop { - transition: 200ms ease-out; - box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.2); -} -.osd scale slider:backdrop:disabled { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} -scale marks, -scale value { - color: alpha(currentColor,0.55); - font-feature-settings: "tnum"; -} -scale.horizontal marks.top { - margin-bottom: 6px; - margin-top: -12px; -} -scale.horizontal.fine-tune marks.top { - margin-bottom: 6px; - margin-top: -9px; -} -scale.horizontal marks.bottom { - margin-top: 6px; - margin-bottom: -12px; -} -scale.horizontal.fine-tune marks.bottom { - margin-top: 6px; - margin-bottom: -9px; -} -scale.vertical marks.top { - margin-right: 6px; - margin-left: -12px; -} -scale.vertical.fine-tune marks.top { - margin-right: 6px; - margin-left: -9px; -} -scale.vertical marks.bottom { - margin-left: 6px; - margin-right: -12px; -} -scale.vertical.fine-tune marks.bottom { - margin-left: 6px; - margin-right: -9px; -} -scale.horizontal indicator { - min-height: 6px; - min-width: 1px; -} -scale.horizontal.fine-tune indicator { - min-height: 3px; -} -scale.vertical indicator { - min-height: 1px; - min-width: 6px; -} -scale.vertical.fine-tune indicator { - min-width: 3px; -} -scale.horizontal.marks-before:not(.marks-after) slider { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); - min-height: 28px; - min-width: 23px; - margin-top: -14px; - background-position: top; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-top: -11px; -} -scale.horizontal.marks-before:not(.marks-after) slider:hover { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); - min-height: 28px; - min-width: 23px; - margin-top: -14px; - background-position: top; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-top: -11px; -} -scale.horizontal.marks-before:not(.marks-after) slider:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-disabled.png"), url("assets/slider-horz-scale-has-marks-above-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-top: -14px; - background-position: top; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-top: -11px; -} -scale.horizontal.marks-before:not(.marks-after) slider:backdrop { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-disabled.png"), url("assets/slider-horz-scale-has-marks-above-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-top: -14px; - background-position: top; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-top: -11px; -} -scale.horizontal.marks-before:not(.marks-after) slider:backdrop:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-disabled.png"), url("assets/slider-horz-scale-has-marks-above-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-top: -14px; - background-position: top; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-top: -11px; -} -scale.horizontal.marks-after:not(.marks-before) slider { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below.png"), url("assets/slider-horz-scale-has-marks-below@2.png")); - min-height: 28px; - min-width: 23px; - margin-bottom: -14px; - background-position: bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-bottom: -11px; -} -scale.horizontal.marks-after:not(.marks-before) slider:hover { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below.png"), url("assets/slider-horz-scale-has-marks-below@2.png")); - min-height: 28px; - min-width: 23px; - margin-bottom: -14px; - background-position: bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-bottom: -11px; -} -scale.horizontal.marks-after:not(.marks-before) slider:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-disabled.png"), url("assets/slider-horz-scale-has-marks-below-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-bottom: -14px; - background-position: bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-bottom: -11px; -} -scale.horizontal.marks-after:not(.marks-before) slider:backdrop { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-disabled.png"), url("assets/slider-horz-scale-has-marks-below-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-bottom: -14px; - background-position: bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-bottom: -11px; -} -scale.horizontal.marks-after:not(.marks-before) slider:backdrop:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-disabled.png"), url("assets/slider-horz-scale-has-marks-below-disabled@2.png")); - min-height: 28px; - min-width: 23px; - margin-bottom: -14px; - background-position: bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.horizontal.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-bottom: -11px; -} -scale.vertical.marks-before:not(.marks-after) slider { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above.png"), url("assets/slider-vert-scale-has-marks-above@2.png")); - min-height: 23px; - min-width: 28px; - margin-left: -14px; - background-position: left bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-left: -11px; -} -scale.vertical.marks-before:not(.marks-after) slider:hover { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above.png"), url("assets/slider-vert-scale-has-marks-above@2.png")); - min-height: 23px; - min-width: 28px; - margin-left: -14px; - background-position: left bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-left: -11px; -} -scale.vertical.marks-before:not(.marks-after) slider:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-disabled.png"), url("assets/slider-vert-scale-has-marks-above-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-left: -14px; - background-position: left bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-left: -11px; -} -scale.vertical.marks-before:not(.marks-after) slider:backdrop { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-disabled.png"), url("assets/slider-vert-scale-has-marks-above-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-left: -14px; - background-position: left bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-left: -11px; -} -scale.vertical.marks-before:not(.marks-after) slider:backdrop:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-disabled.png"), url("assets/slider-vert-scale-has-marks-above-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-left: -14px; - background-position: left bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-before:not(.marks-after).fine-tune slider { - margin: -7px; - margin-left: -11px; -} -scale.vertical.marks-after:not(.marks-before) slider { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below.png"), url("assets/slider-vert-scale-has-marks-below@2.png")); - min-height: 23px; - min-width: 28px; - margin-right: -14px; - background-position: right bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-right: -11px; -} -scale.vertical.marks-after:not(.marks-before) slider:hover { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below.png"), url("assets/slider-vert-scale-has-marks-below@2.png")); - min-height: 23px; - min-width: 28px; - margin-right: -14px; - background-position: right bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-right: -11px; -} -scale.vertical.marks-after:not(.marks-before) slider:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-disabled.png"), url("assets/slider-vert-scale-has-marks-below-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-right: -14px; - background-position: right bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-right: -11px; -} -scale.vertical.marks-after:not(.marks-before) slider:backdrop { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-disabled.png"), url("assets/slider-vert-scale-has-marks-below-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-right: -14px; - background-position: right bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-right: -11px; -} -scale.vertical.marks-after:not(.marks-before) slider:backdrop:disabled { - margin: -10px; - border-style: none; - border-radius: 0; - background-color: transparent; - background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-disabled.png"), url("assets/slider-vert-scale-has-marks-below-disabled@2.png")); - min-height: 23px; - min-width: 28px; - margin-right: -14px; - background-position: right bottom; - background-repeat: no-repeat; - box-shadow: none; -} -scale.vertical.marks-after:not(.marks-before).fine-tune slider { - margin: -7px; - margin-right: -11px; -} -scale.color { - min-height: 0; - min-width: 0; -} -scale.color trough { - background-image: image(mix(currentColor,@window_bg_color,0.85)); - background-repeat: no-repeat; -} -scale.color.horizontal { - padding: 0 0 15px 0; -} -scale.color.horizontal trough { - padding-bottom: 4px; - background-position: 0 -3px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} -scale.color.horizontal slider:dir(ltr):hover, scale.color.horizontal slider:dir(ltr):backdrop, scale.color.horizontal slider:dir(ltr):disabled, scale.color.horizontal slider:dir(ltr):backdrop:disabled, scale.color.horizontal slider:dir(ltr), scale.color.horizontal slider:dir(rtl):hover, scale.color.horizontal slider:dir(rtl):backdrop, scale.color.horizontal slider:dir(rtl):disabled, scale.color.horizontal slider:dir(rtl):backdrop:disabled, scale.color.horizontal slider:dir(rtl) { - margin-bottom: -15px; - margin-top: 6px; -} -scale.color.vertical:dir(ltr) { - padding: 0 0 0 15px; -} -scale.color.vertical:dir(ltr) trough { - padding-left: 4px; - background-position: 3px 0; - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -scale.color.vertical:dir(ltr) slider:hover, scale.color.vertical:dir(ltr) slider:backdrop, scale.color.vertical:dir(ltr) slider:disabled, scale.color.vertical:dir(ltr) slider:backdrop:disabled, scale.color.vertical:dir(ltr) slider { - margin-left: -15px; - margin-right: 6px; -} -scale.color.vertical:dir(rtl) { - padding: 0 15px 0 0; -} -scale.color.vertical:dir(rtl) trough { - padding-right: 4px; - background-position: -3px 0; - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -scale.color.vertical:dir(rtl) slider:hover, scale.color.vertical:dir(rtl) slider:backdrop, scale.color.vertical:dir(rtl) slider:disabled, scale.color.vertical:dir(rtl) slider:backdrop:disabled, scale.color.vertical:dir(rtl) slider { - margin-right: -15px; - margin-left: 6px; -} -scale.color.fine-tune.horizontal:dir(ltr), scale.color.fine-tune.horizontal:dir(rtl) { - padding: 0 0 12px 0; -} -scale.color.fine-tune.horizontal:dir(ltr) trough, scale.color.fine-tune.horizontal:dir(rtl) trough { - padding-bottom: 7px; - background-position: 0 -6px; -} -scale.color.fine-tune.horizontal:dir(ltr) slider, scale.color.fine-tune.horizontal:dir(rtl) slider { - margin-bottom: -15px; - margin-top: 6px; -} -scale.color.fine-tune.vertical:dir(ltr) { - padding: 0 0 0 12px; -} -scale.color.fine-tune.vertical:dir(ltr) trough { - padding-left: 7px; - background-position: 6px 0; -} -scale.color.fine-tune.vertical:dir(ltr) slider { - margin-left: -15px; - margin-right: 6px; -} -scale.color.fine-tune.vertical:dir(rtl) { - padding: 0 12px 0 0; -} -scale.color.fine-tune.vertical:dir(rtl) trough { - padding-right: 7px; - background-position: -6px 0; -} -scale.color.fine-tune.vertical:dir(rtl) slider { - margin-right: -15px; - margin-left: 6px; -} - -progressbar.horizontal trough, -progressbar.horizontal progress { - min-height: 8px; -} -progressbar.vertical trough, -progressbar.vertical progress { - min-width: 8px; -} -progressbar.horizontal progress { - margin: 0 -1px; -} -progressbar.vertical progress { - margin: -1px 0; -} -progressbar { - font-size: smaller; - color: alpha(@window_fg_color,0.4); - font-feature-settings: "tnum"; -} -progressbar:backdrop { - box-shadow: none; - transition: 200ms ease-out; -} -progressbar progress { - border-radius: 8px; -} -progressbar progress.left { - border-top-left-radius: 8px; - border-bottom-left-radius: 8px; -} -progressbar progress.right { - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; -} -progressbar progress.top { - border-top-right-radius: 8px; - border-top-left-radius: 8px; -} -progressbar progress.bottom { - border-bottom-right-radius: 8px; - border-bottom-left-radius: 8px; -} -progressbar.osd { - min-width: 3px; - min-height: 3px; - background-color: transparent; -} -progressbar.osd trough { - border-style: none; - border-radius: 0; - background-color: transparent; - box-shadow: none; -} -progressbar.osd progress { - border-style: none; - border-radius: 0; -} -progressbar trough.empty progress { - all: unset; -} - -levelbar.horizontal block { - min-height: 8px; -} -levelbar.horizontal.continuous block:first-child, levelbar.horizontal.continuous block:last-child { - border-radius: 8px; -} -levelbar.horizontal.discrete block { - margin: 0 1px; - min-width: 32px; -} -levelbar.horizontal.discrete block:first-child { - border-radius: 8px 0 0 8px; -} -levelbar.horizontal.discrete block:last-child { - border-radius: 0 8px 8px 0; -} -levelbar.vertical block { - min-width: 8px; -} -levelbar.vertical.continuous block:first-child, levelbar.vertical.continuous block:last-child { - border-radius: 8px; -} -levelbar.vertical.discrete block { - margin: 1px 0; - min-height: 32px; -} -levelbar.vertical.discrete block:first-child { - border-radius: 8px 8px 0 0; -} -levelbar.vertical.discrete block:last-child { - border-radius: 0 0 8px 8px; -} -levelbar:backdrop { - transition: 200ms ease-out; -} -levelbar trough { - border: 0px solid; - padding: 0; - border-radius: 8px; - background-color: alpha(currentColor,0.15); -} -levelbar trough:backdrop { - background-color: mix(mix(currentColor,@window_bg_color,0.81),@window_bg_color,0.3); -} -levelbar block { - border: 0px solid; - border-radius: 0; -} -levelbar block.low { - border-color: shade(@warning_bg_color,0.8); - background-color: @warning_bg_color; -} -levelbar block.low:backdrop { - border-color: @warning_bg_color; -} -levelbar block.high, levelbar block:not(.empty) { - border-color: shade(@accent_bg_color,0.8); - background-color: @accent_bg_color; -} -levelbar block.high:backdrop, levelbar block:not(.empty):backdrop { - border-color: @accent_bg_color; -} -levelbar block.full { - border-color: shade(@success_bg_color,0.8); - background-color: @success_bg_color; -} -levelbar block.full:backdrop { - border-color: @success_bg_color; -} -levelbar block.empty { - background-color: transparent; - border-color: alpha(@window_fg_color,0.2); -} -levelbar block.empty:backdrop { - border-color: alpha(mix(@window_fg_color,@window_bg_color,0.5),0.15); -} - -printdialog paper { - color: @window_fg_color; - border: 1px solid mix(currentColor,@window_bg_color,0.85); - background: white; - padding: 0; - border-radius: 0; - box-shadow: none; -} -printdialog paper:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); - border-color: mix(currentColor,@window_bg_color,0.81); -} -printdialog .dialog-action-box { - margin: 12px; -} - -frame > border, -.frame { - box-shadow: none; - margin: 0; - padding: 0; - border: 1px solid mix(currentColor,@window_bg_color,0.85); -} -frame > border.flat, -.frame.flat { - border-style: none; -} - -actionbar > revealer > box { - padding: 6px; - border-top: 1px solid mix(currentColor,@window_bg_color,0.85); -} - -scrolledwindow viewport.frame { - border-style: none; -} -scrolledwindow overshoot.top { - background-image: -gtk-gradient(radial, center top, 0, center top, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))), -gtk-gradient(radial, center top, 0, center top, 0.6, from(alpha(@window_fg_color,0.07)), to(alpha(@window_fg_color,0))); - background-size: 100% 5%, 100% 100%; - background-repeat: no-repeat; - background-position: center top; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.top:backdrop { - background-image: -gtk-gradient(radial, center top, 0, center top, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))); - background-size: 100% 5%; - background-repeat: no-repeat; - background-position: center top; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.bottom { - background-image: -gtk-gradient(radial, center bottom, 0, center bottom, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))), -gtk-gradient(radial, center bottom, 0, center bottom, 0.6, from(alpha(@window_fg_color,0.07)), to(alpha(@window_fg_color,0))); - background-size: 100% 5%, 100% 100%; - background-repeat: no-repeat; - background-position: center bottom; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.bottom:backdrop { - background-image: -gtk-gradient(radial, center bottom, 0, center bottom, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))); - background-size: 100% 5%; - background-repeat: no-repeat; - background-position: center bottom; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.left { - background-image: -gtk-gradient(radial, left center, 0, left center, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))), -gtk-gradient(radial, left center, 0, left center, 0.6, from(alpha(@window_fg_color,0.07)), to(alpha(@window_fg_color,0))); - background-size: 5% 100%, 100% 100%; - background-repeat: no-repeat; - background-position: left center; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.left:backdrop { - background-image: -gtk-gradient(radial, left center, 0, left center, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))); - background-size: 5% 100%; - background-repeat: no-repeat; - background-position: left center; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.right { - background-image: -gtk-gradient(radial, right center, 0, right center, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))), -gtk-gradient(radial, right center, 0, right center, 0.6, from(alpha(@window_fg_color,0.07)), to(alpha(@window_fg_color,0))); - background-size: 5% 100%, 100% 100%; - background-repeat: no-repeat; - background-position: right center; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow overshoot.right:backdrop { - background-image: -gtk-gradient(radial, right center, 0, right center, 0.5, to(@window_fg_color), to(alpha(@window_fg_color,0))); - background-size: 5% 100%; - background-repeat: no-repeat; - background-position: right center; - background-color: transparent; - border: none; - box-shadow: none; -} -scrolledwindow junction { - border-color: transparent; - border-image: linear-gradient(to bottom, mix(currentColor,@window_bg_color,0.85) 1px, transparent 1px) 0 0 0 1/0 1px stretch; - background-color: @view_bg_color; -} -scrolledwindow junction:dir(rtl) { - border-image-slice: 0 1 0 0; -} - -separator { - background: mix(currentColor,@window_bg_color,0.85); - min-width: 1px; - min-height: 1px; -} - -list { - color: @view_fg_color; - background-color: @view_bg_color; - border-color: @card_shade_color; -} -list row { - padding: 2px; - outline-color: alpha(@accent_color,0.5); - outline-style: solid; - outline-offset: -3px; - outline-width: 2px; - -gtk-outline-radius: 9px; -} - -row { - transition: all 150ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -row:hover { - transition: none; -} -row:backdrop { - transition: 200ms ease-out; -} -row.activatable.has-open-popup, row.activatable:hover { - background-color: alpha(currentColor,0.07); -} -row.activatable:active { - background-color: alpha(currentColor,0.16); -} -row.activatable:backdrop:hover { - background-color: transparent; -} -row.activatable:selected { - color: @window_fg_color; -} -row.activatable:selected:active { - background-color: alpha(currentColor,0.19); -} -row.activatable:selected.has-open-popup, row.activatable:selected:hover { - background-color: alpha(currentColor,0.12); - color: @window_fg_color; -} -row.activatable:selected:backdrop { - background-color: alpha(currentColor,0.07); - color: @window_fg_color; -} -row:selected { - background-color: alpha(currentColor,0.1); -} - -.content list button, .content list > row:not(:selected):hover button, -list.content button, -list.content > row:not(:selected):hover button, -list.view.frame button, -list.view.frame > row:not(:selected):hover button { - color: @card_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@card_fg_color,@card_bg_color,0.9); -} -.content list button.flat:not(:hover):not(:active), .content list > row:not(:selected):hover button.flat:not(:hover):not(:active), -list.content button.flat:not(:hover):not(:active), -list.content > row:not(:selected):hover button.flat:not(:hover):not(:active), -list.view.frame button.flat:not(:hover):not(:active), -list.view.frame > row:not(:selected):hover button.flat:not(:hover):not(:active) { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -.content list button:hover, .content list > row:not(:selected):hover button:hover, -list.content button:hover, -list.content > row:not(:selected):hover button:hover, -list.view.frame button:hover, -list.view.frame > row:not(:selected):hover button:hover { - color: @card_fg_color; - background-color: mix(@card_fg_color,@card_bg_color,0.85); - box-shadow: none; -} -.content list button:active, .content list button:checked, .content list > row:not(:selected):hover button:active, .content list > row:not(:selected):hover button:checked, -list.content button:active, -list.content button:checked, -list.content > row:not(:selected):hover button:active, -list.content > row:not(:selected):hover button:checked, -list.view.frame button:active, -list.view.frame button:checked, -list.view.frame > row:not(:selected):hover button:active, -list.view.frame > row:not(:selected):hover button:checked { - color: @card_fg_color; - background-color: mix(@card_fg_color,@card_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.content list button:active:hover, .content list button:checked:hover, .content list > row:not(:selected):hover button:active:hover, .content list > row:not(:selected):hover button:checked:hover, -list.content button:active:hover, -list.content button:checked:hover, -list.content > row:not(:selected):hover button:active:hover, -list.content > row:not(:selected):hover button:checked:hover, -list.view.frame button:active:hover, -list.view.frame button:checked:hover, -list.view.frame > row:not(:selected):hover button:active:hover, -list.view.frame > row:not(:selected):hover button:checked:hover { - background-color: mix(@card_fg_color,@card_bg_color,0.65); -} -.content list button:disabled, .content list > row:not(:selected):hover button:disabled, -list.content button:disabled, -list.content > row:not(:selected):hover button:disabled, -list.view.frame button:disabled, -list.view.frame > row:not(:selected):hover button:disabled { - color: alpha(@card_fg_color,0.5); - background-color: mix(@card_fg_color,@card_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} -.content list entry, -list.content entry, -list.view.frame entry { - color: @card_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@card_fg_color,@card_bg_color,0.9); -} -.content list entry:disabled, -list.content entry:disabled, -list.view.frame entry:disabled { - color: alpha(@card_fg_color,0.5); - background-color: mix(@card_fg_color,@card_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; -} - -list.content .horizontal spinbutton entry { - border-top-left-radius: 9px; - border-bottom-left-radius: 9px; -} - -list.view.frame { - border-radius: 12px; -} -list.view.frame, list.view.frame:backdrop { - background-color: @card_bg_color; -} - -.app-notification, -.app-notification.frame { - padding: 10px; - border-radius: 0 0 15px 15px; - background-color: rgba(0, 0, 0, 0.7); - background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); - background-clip: padding-box; - border: none; -} -.app-notification:backdrop, -.app-notification.frame:backdrop { - background-image: none; - transition: 200ms ease-out; -} -.app-notification border, -.app-notification.frame border { - border: none; -} - -expander title > arrow { - min-width: 16px; - min-height: 16px; - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); -} -expander title > arrow:dir(rtl) { - -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); -} -expander title > arrow:hover { - color: mix(white,@window_fg_color,0.7); -} -expander title > arrow:disabled { - color: alpha(@window_fg_color,0.5); -} -expander title > arrow:disabled:backdrop { - color: mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5); -} -expander title > arrow:checked { - -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); -} - -calendar { - color: @view_fg_color; - border: 1px solid alpha(currentColor,0.15); -} -calendar:selected, calendar:backdrop:selected { - background-color: @accent_bg_color; - color: @accent_fg_color; - border-radius: 9px; -} -calendar.header { - border-bottom-color: alpha(currentColor,0.15); -} -calendar.header:backdrop { - border-bottom-color: alpha(currentColor,0.15); -} -calendar.button { - color: @view_fg_color; -} -calendar.button:hover { - background-color: alpha(currentColor,0.07); -} -calendar.button:active { - background-color: alpha(currentColor,0.16); -} -calendar.button:checked { - background-color: alpha(currentColor,0.1); -} -calendar.button:checked:hover { - background-color: alpha(currentColor,0.12); -} -calendar.button:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -calendar.button:disabled { - color: alpha(@window_fg_color,0.5); -} -calendar.highlight { - color: alpha(@window_fg_color,0.5); -} -calendar.highlight:backdrop { - color: mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5); -} -calendar:backdrop { - color: mix(@view_fg_color,@window_bg_color,0.5); - border-color: mix(currentColor,@window_bg_color,0.81); -} -calendar:indeterminate { - color: alpha(currentColor,0.1); -} - -messagedialog.csd.background button { - outline-color: alpha(@accent_color,0.5); - color: rgba(0, 0, 6, 0.8); - background-color: alpha(currentColor,0.1); -} -messagedialog.csd.background button:hover { - outline-color: alpha(@accent_color,0.5); - color: rgba(0, 0, 6, 0.8); - background-color: alpha(currentColor,0.15); -} -messagedialog.csd.background button:checked, messagedialog.csd.background button:active { - outline-color: alpha(@accent_color,0.5); - color: rgba(0, 0, 6, 0.8); - background-color: alpha(currentColor,0.3); -} -messagedialog.csd.background button:backdrop { - outline-color: transparent; - color: alpha(rgba(0, 0, 6, 0.8),0.5); - background-color: alpha(currentColor,0.1); -} -messagedialog.csd.background button:backdrop:hover { - background-color: alpha(currentColor,0.15); -} -messagedialog.csd.background button:backdrop:checked { - background-color: alpha(currentColor,0.3); -} -messagedialog.csd.background button:backdrop:active { - background-color: alpha(currentColor,0.3); -} -messagedialog.csd.background button:backdrop:checked:hover { - background-color: alpha(currentColor,0.35); -} -messagedialog.csd.background button:backdrop:checked:active { - background-color: alpha(currentColor,0.4); -} -messagedialog.csd.background button:disabled { - outline-color: transparent; - color: alpha(rgba(0, 0, 6, 0.8),0.5); - background-color: alpha(currentColor,0.1); -} -messagedialog .titlebar, messagedialog .titlebar:backdrop { - min-height: 20px; - background-image: none; - background: @dialog_bg_color; - color: @dialog_fg_color; - border-style: none; - border-top-left-radius: 15px; - border-top-right-radius: 15px; -} -messagedialog.csd.background { - border-bottom-left-radius: 15px; - border-bottom-right-radius: 15px; - background-color: @dialog_bg_color; - color: @dialog_fg_color; -} -messagedialog.csd .dialog-action-area { - margin: 0; - padding: 21px 24px 24px 24px; -} -messagedialog.csd .dialog-action-area button { - padding: 10px 20px; - margin: 0 10px; - border-radius: 12px; - -gtk-outline-radius: 10px; - border-left-style: none; - border-right-style: none; - border-color: transparent; -} - -filechooser .dialog-action-box { - border-top: 1px solid mix(currentColor,@window_bg_color,0.85); -} -filechooser #pathbarbox { - border-bottom: 1px solid @window_bg_color; -} - -filechooserbutton:drop(active) { - box-shadow: none; - border-color: transparent; -} - -.sidebar { - border-style: none; - background-color: @sidebar_bg_color; - color: @sidebar_fg_color; -} -.sidebar:backdrop { - background-color: @sidebar_backdrop_color; -} -stacksidebar.sidebar:dir(ltr) list, stacksidebar.sidebar.left list, stacksidebar.sidebar.left:dir(rtl) list, .sidebar:not(separator):dir(ltr), .sidebar:not(separator).left, .sidebar:not(separator).left:dir(rtl) { - border-right: 1px solid @sidebar_border_color; - border-left-style: none; -} - -stacksidebar.sidebar:dir(rtl) list, stacksidebar.sidebar.right list, .sidebar:not(separator):dir(rtl), .sidebar:not(separator).right { - border-left: 1px solid @sidebar_border_color; - border-right-style: none; -} - -.sidebar list { - background-color: transparent; -} -paned .sidebar.left, paned .sidebar.right, paned .sidebar.left:dir(rtl), paned .sidebar:dir(rtl), paned .sidebar:dir(ltr), paned .sidebar { - border-style: none; -} -.sidebar row { - border-radius: 9px; -} -.sidebar row:backdrop { - color: @sidebar_fg_color; -} -.sidebar row, .sidebar separator { - margin: 0 4px; -} - -stacksidebar row { - padding: 10px 4px; -} -stacksidebar row > label { - padding-left: 6px; - padding-right: 6px; -} -stacksidebar row.needs-attention > label { - background-size: 6px 6px, 0 0; -} - -separator.sidebar { - background-color: @sidebar_border_color; -} -separator.sidebar.selection-mode, .selection-mode separator.sidebar { - background-color: shade(@accent_bg_color,0.8); -} - -row image.sidebar-icon { - opacity: 0.7; -} - -placessidebar > viewport.frame { - border-style: none; -} -placessidebar row { - min-height: 36px; - padding: 0px; -} -placessidebar row > revealer { - padding: 0 14px; -} -placessidebar row:selected { - color: @accent_fg_color; -} -placessidebar row:disabled { - color: alpha(@window_fg_color,0.5); -} -placessidebar row:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -placessidebar row:backdrop:selected { - color: @window_bg_color; -} -placessidebar row:backdrop:disabled { - color: mix(mix(@window_fg_color,@window_bg_color,0.5),@window_bg_color,0.5); -} -placessidebar row image.sidebar-icon:dir(ltr) { - padding-right: 8px; -} -placessidebar row image.sidebar-icon:dir(rtl) { - padding-left: 8px; -} -placessidebar row label.sidebar-label:dir(ltr) { - padding-right: 2px; -} -placessidebar row label.sidebar-label:dir(rtl) { - padding-left: 2px; -} -button.sidebar-button { - min-height: 26px; - min-width: 26px; - margin-top: 3px; - margin-bottom: 3px; - padding: 0; - border-radius: 100%; - -gtk-outline-radius: 100%; -} -button.sidebar-button:not(:hover):not(:active) > image, button.sidebar-button:backdrop > image { - opacity: 0.7; -} - -placessidebar row:selected:active { - box-shadow: none; -} -placessidebar row.sidebar-placeholder-row { - padding: 0 8px; - min-height: 2px; - background-image: image(@accent_bg_color); - background-clip: content-box; -} -placessidebar row.sidebar-new-bookmark-row { - color: @accent_bg_color; -} -placessidebar row:drop(active):not(:disabled) { - color: @accent_bg_color; - box-shadow: inset 0 1px @accent_bg_color, inset 0 -1px @accent_bg_color; -} -placessidebar row:drop(active):not(:disabled):selected { - color: @accent_fg_color; - background-color: @accent_bg_color; -} - -placesview .server-list-button > image { - transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - -gtk-icon-transform: rotate(0turn); -} -placesview .server-list-button:checked > image { - transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - -gtk-icon-transform: rotate(-0.5turn); -} -placesview row.activatable:hover { - background-color: transparent; -} -placesview > actionbar > revealer > box > label { - padding-left: 8px; - padding-right: 8px; -} - -paned > separator { - min-width: 1px; - min-height: 1px; - -gtk-icon-source: none; - border-style: none; - background-color: transparent; - background-image: image(mix(currentColor,@window_bg_color,0.85)); - background-size: 1px 1px; -} -paned > separator:selected { - background-image: image(@accent_bg_color); -} -paned > separator:backdrop { - background-image: image(mix(currentColor,@window_bg_color,0.81)); -} -paned > separator.wide { - min-width: 5px; - min-height: 5px; - background-color: @window_bg_color; - background-image: image(mix(currentColor,@window_bg_color,0.85)), image(mix(currentColor,@window_bg_color,0.85)); - background-size: 1px 1px, 1px 1px; -} -paned > separator.wide:backdrop { - background-color: @window_bg_color; - background-image: image(mix(currentColor,@window_bg_color,0.81)), image(mix(currentColor,@window_bg_color,0.81)); -} -paned.horizontal > separator { - background-repeat: repeat-y; -} -paned.horizontal > separator:dir(ltr) { - margin: 0 -8px 0 0; - padding: 0 8px 0 0; - background-position: left; -} -paned.horizontal > separator:dir(rtl) { - margin: 0 0 0 -8px; - padding: 0 0 0 8px; - background-position: right; -} -paned.horizontal > separator.wide { - margin: 0; - padding: 0; - background-repeat: repeat-y, repeat-y; - background-position: left, right; -} -paned.vertical > separator { - margin: 0 0 -8px 0; - padding: 0 0 8px 0; - background-repeat: repeat-x; - background-position: top; -} -paned.vertical > separator.wide { - margin: 0; - padding: 0; - background-repeat: repeat-x, repeat-x; - background-position: bottom, top; -} - -infobar { - border-style: none; -} -infobar.info > revealer > box { - background-color: mix(@accent_bg_color,@window_bg_color,0.7); - color: @window_fg_color; - text-shadow: none; -} -infobar.info > revealer > box:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -infobar.info button { - background-color: mix(@accent_bg_color,@window_bg_color,0.5); -} -infobar.info button:hover { - background-color: mix(@accent_bg_color,@window_bg_color,0.35); -} -infobar.info button:checked, infobar.info button:active { - background-color: mix(@accent_bg_color,@window_bg_color,0.2); -} -infobar.info button:backdrop:not(:disabled) label, infobar.info button:backdrop:not(:disabled), infobar.info button:not(:disabled) label, infobar.info button:not(:disabled) { - color: @window_fg_color; -} -infobar.info button:disabled { - background-color: mix(@accent_bg_color,@window_bg_color,0.6); -} -infobar.info button:disabled label, infobar.info button:disabled { - color: alpha(mix(@window_fg_color,@accent_bg_color,0.3),0.6); -} -infobar.action.info:hover > revealer > box { - background-color: mix(@accent_bg_color,@window_bg_color,0.6); - box-shadow: inset 0 -1px mix(@accent_bg_color,@window_bg_color,0.3); -} -infobar.question > revealer > box { - background-color: mix(@accent_bg_color,@window_bg_color,0.7); - color: @window_fg_color; - text-shadow: none; -} -infobar.question > revealer > box:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -infobar.question button { - background-color: mix(@accent_bg_color,@window_bg_color,0.5); -} -infobar.question button:hover { - background-color: mix(@accent_bg_color,@window_bg_color,0.35); -} -infobar.question button:checked, infobar.question button:active { - background-color: mix(@accent_bg_color,@window_bg_color,0.2); -} -infobar.question button:backdrop:not(:disabled) label, infobar.question button:backdrop:not(:disabled), infobar.question button:not(:disabled) label, infobar.question button:not(:disabled) { - color: @window_fg_color; -} -infobar.question button:disabled { - background-color: mix(@accent_bg_color,@window_bg_color,0.6); -} -infobar.question button:disabled label, infobar.question button:disabled { - color: alpha(mix(@window_fg_color,@accent_bg_color,0.3),0.6); -} -infobar.action.question:hover > revealer > box { - background-color: mix(@accent_bg_color,@window_bg_color,0.6); - box-shadow: inset 0 -1px mix(@accent_bg_color,@window_bg_color,0.3); -} -infobar.warning > revealer > box { - background-color: mix(@warning_bg_color,@window_bg_color,0.7); - color: @window_fg_color; - text-shadow: none; -} -infobar.warning > revealer > box:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -infobar.warning button { - background-color: mix(@warning_bg_color,@window_bg_color,0.5); -} -infobar.warning button:hover { - background-color: mix(@warning_bg_color,@window_bg_color,0.35); -} -infobar.warning button:checked, infobar.warning button:active { - background-color: mix(@warning_bg_color,@window_bg_color,0.2); -} -infobar.warning button:backdrop:not(:disabled) label, infobar.warning button:backdrop:not(:disabled), infobar.warning button:not(:disabled) label, infobar.warning button:not(:disabled) { - color: @window_fg_color; -} -infobar.warning button:disabled { - background-color: mix(@warning_bg_color,@window_bg_color,0.6); -} -infobar.warning button:disabled label, infobar.warning button:disabled { - color: alpha(mix(@window_fg_color,@warning_bg_color,0.3),0.6); -} -infobar.action.warning:hover > revealer > box { - background-color: mix(@warning_bg_color,@window_bg_color,0.6); - box-shadow: inset 0 -1px mix(@warning_bg_color,@window_bg_color,0.3); -} -infobar.error > revealer > box { - background-color: mix(@error_bg_color,@window_bg_color,0.7); - color: @window_fg_color; - text-shadow: none; -} -infobar.error > revealer > box:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); -} -infobar.error button { - background-color: mix(@error_bg_color,@window_bg_color,0.5); -} -infobar.error button:hover { - background-color: mix(@error_bg_color,@window_bg_color,0.35); -} -infobar.error button:checked, infobar.error button:active { - background-color: mix(@error_bg_color,@window_bg_color,0.2); -} -infobar.error button:backdrop:not(:disabled) label, infobar.error button:backdrop:not(:disabled), infobar.error button:not(:disabled) label, infobar.error button:not(:disabled) { - color: @window_fg_color; -} -infobar.error button:disabled { - background-color: mix(@error_bg_color,@window_bg_color,0.6); -} -infobar.error button:disabled label, infobar.error button:disabled { - color: alpha(mix(@window_fg_color,@error_bg_color,0.3),0.6); -} -infobar.action.error:hover > revealer > box { - background-color: mix(@error_bg_color,@window_bg_color,0.6); - box-shadow: inset 0 -1px mix(@error_bg_color,@window_bg_color,0.3); -} -infobar .close { - min-width: 18px; - min-height: 18px; - padding: 4px; - border-radius: 50%; -} -infobar selection { - background-color: shade(@window_bg_color,0.9); -} -infobar *:link { - color: @accent_color; -} - -tooltip { - padding: 6px 10px; - border-radius: 9px; - box-shadow: none; - text-shadow: 0 1px black; -} -tooltip.background { - background-color: rgba(0, 0, 0, 0.8); - background-clip: padding-box; - border: 1px solid rgba(255, 255, 255, 0.1); -} -tooltip decoration { - background-color: transparent; -} -tooltip * { - padding: 4px; - background-color: transparent; - color: white; -} - -colorswatch:drop(active), colorswatch { - border-style: none; -} -colorswatch.top { - border-top-left-radius: 9.5px; - border-top-right-radius: 9.5px; -} -colorswatch.top overlay { - border-top-left-radius: 9px; - border-top-right-radius: 9px; -} -colorswatch.bottom { - border-bottom-left-radius: 9.5px; - border-bottom-right-radius: 9.5px; -} -colorswatch.bottom overlay { - border-bottom-left-radius: 9px; - border-bottom-right-radius: 9px; -} -colorswatch.left, colorswatch:first-child:not(.top) { - border-top-left-radius: 9.5px; - border-bottom-left-radius: 9.5px; -} -colorswatch.left overlay, colorswatch:first-child:not(.top) overlay { - border-top-left-radius: 9px; - border-bottom-left-radius: 9px; -} -colorswatch.right, colorswatch:last-child:not(.bottom) { - border-top-right-radius: 9.5px; - border-bottom-right-radius: 9.5px; -} -colorswatch.right overlay, colorswatch:last-child:not(.bottom) overlay { - border-top-right-radius: 9px; - border-bottom-right-radius: 9px; -} -colorswatch.dark { - outline-color: rgba(255, 255, 255, 0.6); -} -colorswatch.dark overlay { - color: white; -} -colorswatch.dark overlay:hover { - border-color: rgba(0, 0, 0, 0.8); -} -colorswatch.light { - outline-color: rgba(0, 0, 0, 0.6); -} -colorswatch.light overlay { - color: black; -} -colorswatch.light overlay:hover { - border-color: rgba(0, 0, 0, 0.5); -} -colorswatch:drop(active) { - box-shadow: none; -} -colorswatch:drop(active).light overlay { - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 2px shade(@accent_bg_color,0.93), inset 0 0 0 1px @accent_bg_color; -} -colorswatch:drop(active).dark overlay { - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.3), inset 0 0 0 1px @accent_bg_color; -} -colorswatch overlay { - border: 1px solid rgba(0, 0, 0, 0.3); -} -colorswatch overlay:hover { - box-shadow: inset 0 1px rgba(255, 255, 255, 0.4), inset 0 -1px rgba(0, 0, 0, 0.2); -} -colorswatch#add-color-button { - border-radius: 9px 9px 0 0; -} -colorswatch#add-color-button:only-child { - border-radius: 9px; -} -colorswatch#add-color-button overlay { - color: @window_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.9); -} -colorswatch#add-color-button overlay:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; -} -colorswatch:disabled { - opacity: 0.5; -} -colorswatch:disabled overlay { - border-color: rgba(0, 0, 0, 0.6); - box-shadow: none; -} -row:selected colorswatch { - box-shadow: 0 0 0 2px @accent_fg_color; -} -colorswatch#editor-color-sample { - border-radius: 4px; -} -colorswatch#editor-color-sample overlay { - border-radius: 4.5px; -} - -colorchooser .popover.osd { - border-radius: 5px; -} - -.checkerboard { - background-position: 0px 0px, 10px 10px; - background-size: 20px 20px; - background-image: linear-gradient(45deg, mix(currentColor,@window_bg_color,0.85) 25%, transparent 25%, transparent 75%, mix(currentColor,@window_bg_color,0.85) 75%, mix(currentColor,@window_bg_color,0.85) 100%), linear-gradient(45deg, mix(currentColor,@window_bg_color,0.85) 25%, @view_bg_color 25%, @view_bg_color 75%, mix(currentColor,@window_bg_color,0.85) 75%, mix(currentColor,@window_bg_color,0.85) 100%); -} - -.content-view { - background-color: shade(@window_bg_color,0.93); -} -.content-view:hover { - -gtk-icon-effect: highlight; -} -.osd .scale-popup button.flat { - border-style: none; - border-radius: 5px; -} -.scale-popup button:hover { - background-color: alpha(@window_fg_color,0.1); - border-radius: 5px; -} - -cursor-handle { - background-color: transparent; - background-image: none; - box-shadow: none; - border-style: none; -} -cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/text-select-start.png"), url("assets/text-select-start@2.png")); - padding-left: 10px; -} -cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/text-select-end.png"), url("assets/text-select-end@2.png")); - padding-right: 10px; -} -cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); -} -cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/text-select-start.png"), url("assets/text-select-start@2.png")); - padding-left: 10px; -} -cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/text-select-end.png"), url("assets/text-select-end@2.png")); - padding-right: 10px; -} -cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { - -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); -} - -.context-menu { - font: initial; -} - -.keycap { - min-width: 20px; - min-height: 25px; - margin-top: 2px; - padding-bottom: 3px; - padding-left: 6px; - padding-right: 6px; - color: @window_fg_color; - background-color: @view_bg_color; - border: 1px solid; - border-color: mix(mix(currentColor,@window_bg_color,0.85),@window_bg_color,0.5); - border-radius: 5px; - box-shadow: inset 0 -3px mix(@view_bg_color,@window_bg_color,0.8); - font-size: smaller; -} -.keycap:backdrop { - background-color: @window_bg_color; - color: mix(@window_fg_color,@window_bg_color,0.5); - transition: 200ms ease-out; -} - -:not(decoration):not(window):drop(active):focus, -:not(decoration):not(window):drop(active) { - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 1px @accent_bg_color; - caret-color: @accent_bg_color; -} - -stackswitcher button.text-button { - min-width: 100px; -} - -stackswitcher button.circular, -stackswitcher button.text-button.circular { - min-width: 32px; - min-height: 32px; - padding: 0; -} - -.lowres-icon { - -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); -} - -.icon-dropshadow { - -gtk-icon-shadow: 0 1px 12px rgba(0, 0, 0, 0.05), 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); -} - -popover.emoji-picker { - padding-left: 0; - padding-right: 0; -} -popover.emoji-picker entry.search { - margin: 3px 5px 5px 5px; -} - -button.emoji-section { - border-color: transparent; - border-width: 3px; - border-style: none none solid; - border-radius: 0; - margin: 2px 4px 2px 4px; - padding: 3px 0 0; - min-width: 32px; - min-height: 28px; - background: none; - box-shadow: none; - text-shadow: none; - outline-offset: -5px; -} -button.emoji-section:first-child { - margin-left: 7px; -} -button.emoji-section:last-child { - margin-right: 7px; -} -button.emoji-section:backdrop:not(:checked) { - border-color: transparent; -} -button.emoji-section:hover { - border-color: mix(currentColor,@window_bg_color,0.85); -} -button.emoji-section:checked { - border-color: alpha(currentColor,0.1); -} -button.emoji-section label { - padding: 0; - opacity: 0.55; -} -button.emoji-section:hover label { - opacity: 0.775; -} -button.emoji-section:checked label { - opacity: 1; -} - -popover.emoji-picker .emoji { - font-size: x-large; - padding: 6px; - border-radius: 9px; -} -popover.emoji-picker .emoji :focus, -popover.emoji-picker .emoji :hover { - background: alpha(currentColor,0.07); -} -popover.emoji-picker .emoji :active { - background: alpha(currentColor,0.16); -} - -popover.emoji-completion arrow { - border: none; - background: none; -} - -popover.emoji-completion contents row box { - padding: 2px 10px; -} - -popover.emoji-completion .emoji:hover { - background: alpha(currentColor,0.04); -} - -.flat.popup:not(.title) { - font-weight: normal; -} - -statusbar { - font-size: small; -} - -scrolledwindow list:not(.content) { - padding: 6px 0; -} -scrolledwindow list row { - margin: 0 6px; - border-radius: 9px; -} -scrolledwindow list separator.horizontal { - margin: 6px; -} - -decoration { - border-radius: 15px 15px 0 0; - border-width: 0px; - box-shadow: 0 3px 8px 1px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(0, 0, 0, 0.05); - margin: 10px; -} -decoration:backdrop { - box-shadow: 0 3px 8px 1px transparent, 0 2px 6px 2px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.02); - transition: 200ms ease-out; -} -.maximized decoration, .fullscreen decoration { - border-radius: 0; - box-shadow: none; -} -.tiled decoration, .tiled-top decoration, .tiled-right decoration, .tiled-bottom decoration, .tiled-left decoration { - border-radius: 0; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 0 0 20px transparent; -} -.tiled decoration:backdrop, .tiled-top decoration:backdrop, .tiled-right decoration:backdrop, .tiled-bottom decoration:backdrop, .tiled-left decoration:backdrop { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 0 0 20px transparent; -} -.popup decoration { - box-shadow: none; -} -.ssd decoration { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3); -} -.ssd decoration:backdrop { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} -.ssd.maximized decoration, .ssd.maximized decoration:backdrop { - box-shadow: none; -} -.csd.popup decoration { - border-radius: 9px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px alpha(rgba(0, 0, 0, 0.05),0.9); -} -tooltip.csd decoration { - border-radius: 5px; - box-shadow: none; -} -messagedialog.csd decoration { - border-radius: 15px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px alpha(rgba(0, 0, 0, 0.05),0.9); -} -.solid-csd decoration { - margin: 0; - padding: 4px; - background-color: mix(currentColor,@window_bg_color,0.85); - border: solid 1px mix(currentColor,@window_bg_color,0.85); - border-radius: 0; - box-shadow: inset 0 0 0 5px mix(currentColor,@window_bg_color,0.85), inset 0 0 0 4px @headerbar_bg_color, inset 0 0 0 1px mix(currentColor,@window_bg_color,0.85); -} -.solid-csd decoration:backdrop { - box-shadow: inset 0 0 0 3px @window_bg_color; -} - -button.titlebutton { - padding: 2px; - margin: 0; - box-shadow: none; - border: none; - background: none; - text-shadow: none; -} -button.titlebutton:not(.appmenu) { - border-radius: 9999px; -} -button.titlebutton:backdrop { - -gtk-icon-shadow: none; -} - -.selection-mode headerbar button.titlebutton:backdrop, -.selection-mode .titlebar button.titlebutton:backdrop, -headerbar.selection-mode button.titlebutton:backdrop, -.titlebar.selection-mode button.titlebutton:backdrop { - -gtk-icon-shadow: none; -} - -.monospace { - font-family: monospace; -} - -window.csd.unified:not(.solid-csd):not(.fullscreen):not(.tiled):not(.tiled-top):not(.tiled-bottom):not(.tiled-left):not(.tiled-right):not(.maximized), -window.csd.unified:not(.solid-csd):not(.fullscreen):not(.tiled):not(.tiled-top):not(.tiled-bottom):not(.tiled-left):not(.tiled-right):not(.maximized) > decoration, -window.csd.unified:not(.solid-csd):not(.fullscreen):not(.tiled):not(.tiled-top):not(.tiled-bottom):not(.tiled-left):not(.tiled-right):not(.maximized) > decoration-overlay { - border-radius: 15px; -} - -window.csd.unified scrollbar { - background-color: @view_bg_color; - color: @window_fg_color; -} -window.csd.unified scrollbar trough { - margin: 7px; - transition: all 200ms linear; - border-radius: 10px; - background-color: alpha(currentColor,0.15); -} -window.csd.unified scrollbar trough > slider { - min-width: 8px; - min-height: 8px; - margin: -6px; - border: 6px solid transparent; - border-radius: 10px; - background-clip: padding-box; - transition: all 200ms linear; -} -window.csd.unified scrollbar.horizontal trough { - margin-top: 6px; - margin-bottom: 6px; -} -window.csd.unified scrollbar.vertical trough { - margin-left: 6px; - margin-right: 6px; -} -window.csd.unified scrollbar.overlay-indicator { - background: none; - color: inherit; - box-shadow: none; - padding: 0; -} -window.csd.unified scrollbar.overlay-indicator:not(.hovering) trough { - background-color: transparent; -} -window.csd.unified scrollbar.overlay-indicator.horizontal trough > slider { - min-width: 40px; -} -window.csd.unified scrollbar.overlay-indicator.horizontal.hovering trough > slider { - min-height: 8px; -} -window.csd.unified scrollbar.overlay-indicator.horizontal:not(.hovering) trough { - margin-top: 3px; - margin-bottom: 3px; -} -window.csd.unified scrollbar.overlay-indicator.vertical trough > slider { - min-height: 40px; -} -window.csd.unified scrollbar.overlay-indicator.vertical.hovering trough > slider { - min-width: 8px; -} -window.csd.unified scrollbar.overlay-indicator.vertical:not(.hovering) trough { - margin-left: 3px; - margin-right: 3px; -} -window.csd.unified scrollbar.horizontal trough > slider { - min-width: 40px; -} -window.csd.unified scrollbar.vertical trough > slider { - min-height: 40px; -} - -popover.combo { - padding: 0px; -} -popover.combo list { - border-style: none; - background-color: transparent; - min-width: 200px; - margin-top: 6px; - margin-bottom: 6px; -} -popover.combo list > row { - padding: 0px 8px 0px 8px; - min-height: 50px; -} -popover.combo list > row:not(:last-child) { - border-bottom: 1px solid alpha(mix(currentColor,@window_bg_color,0.85),0.5); -} -popover.combo list > row:first-child { - border-top-left-radius: 8px; - -gtk-outline-top-left-radius: 7px; - border-top-right-radius: 8px; - -gtk-outline-top-right-radius: 7px; -} -popover.combo list > row:last-child { - border-bottom-left-radius: 8px; - -gtk-outline-bottom-left-radius: 7px; - border-bottom-right-radius: 8px; - -gtk-outline-bottom-right-radius: 7px; -} -popover.combo overshoot.top { - border-top-left-radius: 8px; - -gtk-outline-top-left-radius: 7px; - border-top-right-radius: 8px; - -gtk-outline-top-right-radius: 7px; -} -popover.combo overshoot.bottom { - border-bottom-left-radius: 8px; - -gtk-outline-bottom-left-radius: 7px; - border-bottom-right-radius: 8px; - -gtk-outline-bottom-right-radius: 7px; -} -popover.combo scrollbar.vertical { - padding-top: 2px; - padding-bottom: 2px; -} -popover.combo scrollbar.vertical:dir(ltr) { - border-top-right-radius: 8px; - -gtk-outline-top-right-radius: 7px; - border-bottom-right-radius: 8px; - -gtk-outline-bottom-right-radius: 7px; -} -popover.combo scrollbar.vertical:dir(rtl) { - border-top-left-radius: 8px; - -gtk-outline-top-left-radius: 7px; - border-bottom-left-radius: 8px; - -gtk-outline-bottom-left-radius: 7px; -} - -row.expander { - padding: 0px; -} -row.expander image.expander-row-arrow:dir(ltr) { - margin-left: 6px; -} -row.expander image.expander-row-arrow:dir(rtl) { - margin-right: 6px; -} - -row.expander { - background-color: transparent; -} -row.expander list.nested > row { - background-color: transparent; - border-radius: 0; - border: none; -} -row.expander list.nested > row:not(:selected).activatable:hover { - background-color: alpha(currentColor,0.03); -} -row.expander list.nested > row:not(:selected).activatable:active { - background-color: alpha(currentColor,0.08); -} -row.expander list.nested { - background-color: alpha(@card_shade_color,0.5); - color: inherit; - border-radius: 0; - border-top: 1px solid alpha(currentColor,0.15); -} -row.expander image.expander-row-arrow { - transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -row.expander:checked image.expander-row-arrow { - -gtk-icon-transform: rotate(0turn); -} -row.expander:not(:checked) image.expander-row-arrow { - opacity: 0.55; - text-shadow: none; -} -row.expander:not(:checked) image.expander-row-arrow:dir(ltr) { - -gtk-icon-transform: rotate(-0.25turn); -} -row.expander:not(:checked) image.expander-row-arrow:dir(rtl) { - -gtk-icon-transform: rotate(0.25turn); -} -row.expander:checked image.expander-row-arrow:not(:disabled) { - color: @accent_bg_color; -} -row.expander image.expander-row-arrow:disabled { - color: alpha(@window_fg_color,0.5); -} - -list.content list { - background-color: transparent; - border-radius: 12px; -} -list.content { - background-color: transparent; - color: @card_fg_color; - border-radius: 12px; -} -list.content > row { - background-color: @card_bg_color; - color: @card_fg_color; - margin: 0; - transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -} -list.content > row:not(:last-child) { - box-shadow: inset 0 -1px @card_shade_color; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} -list.content > row:not(:first-child):not(:last-child) { - border-radius: 0; - border-left: 1px solid @card_shade_color; - border-right: 1px solid @card_shade_color; - -gtk-outline-radius: 0; -} -list.content > row:first-child { - border-top-left-radius: 12px; - border-top-right-radius: 12px; - border-top: 1px solid @card_shade_color; - border-left: 1px solid @card_shade_color; - border-right: 1px solid @card_shade_color; - -gtk-outline-radius: 12px 12px 0 0; -} -list.content > row:last-child { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 12px; - border-bottom-right-radius: 12px; - border-bottom: 1px solid @card_shade_color; - border-left: 1px solid @card_shade_color; - border-right: 1px solid @card_shade_color; - -gtk-outline-radius: 0 0 12px 12px; -} -list.content > row:only-child { - border: 1px solid @card_shade_color; - border-radius: 12px; - -gtk-outline-radius: 12px; -} -list.content > row:not(.expander):not(:active):hover.activatable:not(:selected), list.content > row.expander row.header:not(:active):hover.activatable:not(:selected) { - color: @card_fg_color; - background-color: mix(currentColor,@card_bg_color,0.96); -} -list.content + .inline-toolbar { - border-color: transparent; -} - -button.list-button:not(:active):not(:checked):not(:hover) { - color: @card_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@card_fg_color,@card_bg_color,0.9); -} - -keypad .digit { - font-size: 200%; - font-weight: bold; -} -keypad .letters { - font-size: 70%; -} -keypad .symbol { - font-size: 160%; -} - -headerbar viewswitcher button { - margin: 0 4px; -} -headerbar viewswitcher button.radio:checked, headerbar viewswitcher button.radio:hover:not(:backdrop) { - background: image(@headerbar_bg_color); -} -headerbar viewswitcher button:backdrop, headerbar viewswitcher button:hover:backdrop, headerbar viewswitcher button.radio:backdrop, headerbar viewswitcher button.radio:checked:backdrop, headerbar viewswitcher button.radio:hover:backdrop, headerbar viewswitcher button.radio:checked:hover:backdrop { - background: image(@headerbar_backdrop_color); - transition: none; -} -headerbar viewswitcher button.radio:checked:hover:not(:backdrop) { - background: image(@headerbar_bg_color); -} -headerbar viewswitcher button, headerbar viewswitcher button:hover:not(:backdrop), headerbar viewswitcher button:checked, headerbar viewswitcher button:active, headerbar viewswitcher button:checked:hover, headerbar viewswitcher button:active:hover { - background: image(@headerbar_bg_color); - transition: none; -} -headerbar viewswitcher button > stack > box { - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - border-radius: 9px; -} -headerbar viewswitcher button:hover > stack > box { - background-color: alpha(currentColor,0.07); -} -headerbar viewswitcher button:checked > stack > box, headerbar viewswitcher button:active > stack > box { - background-color: alpha(currentColor,0.1); -} -headerbar viewswitcher button:checked:hover > stack > box, headerbar viewswitcher button:backdrop:checked:hover > stack > box { - background-color: alpha(currentColor,0.19); -} - -viewswitcher, viewswitcher button { - margin: 0; - padding: 0; -} -viewswitcher button { - border-radius: 0; - border-top: 0; - border-bottom: 0; - box-shadow: none; - font-size: 1rem; - border-width: 0; -} -viewswitcher button:not(:checked):not(:hover) { - background: transparent; -} -viewswitcher button:not(:only-child):not(:last-child) { - border-right-width: 0px; -} -viewswitcher button:not(only-child):first-child:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):not(:hover) { - border-left-color: transparent; -} -viewswitcher button:not(only-child):last-child:not(:checked):not(:hover) { - border-right-color: transparent; -} -viewswitcher button:not(:checked):hover:not(:backdrop) { - background-image: none; -} -viewswitcher button:not(only-child):first-child:not(:checked):hover, viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { - border-left-color: alpha(currentColor,0.15); -} -viewswitcher button:not(only-child):last-child:not(:checked):hover { - border-right-color: alpha(currentColor,0.15); -} -headerbar viewswitcher button:not(:checked) { - background: none; -} -headerbar viewswitcher button:not(:checked):hover:not(:backdrop) { - background: none; -} -headerbar viewswitcher button:not(:checked):not(only-child):first-child:hover, headerbar viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), headerbar viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { - border-left-color: alpha(currentColor,0.15); -} -headerbar viewswitcher button:not(:checked):not(only-child):last-child:hover { - border-right-color: alpha(currentColor,0.15); -} -headerbar viewswitcher button:not(:checked):hover:backdrop, headerbar viewswitcher button:not(:checked):active:backdrop, headerbar viewswitcher button:not(:checked):active:hover:backdrop { - background: image(@headerbar_backdrop_color); -} -headerbar viewswitcher button:not(:checked):active, headerbar viewswitcher button:not(:checked):active:hover { - background: image(@headerbar_bg_color); -} -viewswitcher button > stack > box.narrow { - font-size: 0.75rem; - padding-top: 7px; - padding-bottom: 5px; -} -viewswitcher button > stack > box.narrow image, -viewswitcher button > stack > box.narrow label { - padding-left: 8px; - padding-right: 8px; -} -viewswitcher button > stack > box.wide { - padding: 8px 12px; -} -viewswitcher button > stack > box.wide image:dir(ltr) { - padding-left: 7px; -} -viewswitcher button > stack > box.wide image:dir(rtl) { - padding-right: 7px; -} -viewswitcher button > stack > box.wide label:dir(ltr) { - padding-right: 7px; -} -viewswitcher button > stack > box.wide label:dir(rtl) { - padding-left: 7px; -} -viewswitcher button > stack > box label.active { - font-weight: bold; -} -viewswitcher button.needs-attention:active > stack > box label, viewswitcher button.needs-attention:checked > stack > box label { - animation: none; - background-image: none; -} -viewswitcher button.needs-attention > stack > box label { - animation: needs_attention 150ms ease-in; - background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(@accent_bg_color), to(transparent)); - background-size: 6px 6px, 6px 6px; - background-repeat: no-repeat; - background-position: right 0px, right 1px; -} -viewswitcher button.needs-attention > stack > box label:backdrop { - background-size: 6px 6px, 0 0; -} -viewswitcher button.needs-attention > stack > box label:dir(rtl) { - background-position: left 0px, left 1px; -} - -viewswitcherbar actionbar > revealer > box { - padding: 0; -} - -viewswitchertitle viewswitcher { - margin-left: 12px; - margin-right: 12px; -} - -statuspage > scrolledwindow > viewport > box > clamp > box > .icon { - color: alpha(@window_fg_color,0.5); -} - -statuspage > scrolledwindow > viewport > box { - margin: 36px 12px; -} -statuspage > scrolledwindow > viewport > box > clamp:not(:last-child) > box { - margin-bottom: 36px; -} -statuspage > scrolledwindow > viewport > box > clamp > box > .icon:not(:last-child) { - margin-bottom: 36px; -} -statuspage > scrolledwindow > viewport > box > clamp > box > .title:not(:last-child) { - margin-bottom: 12px; -} - -row label.subtitle { - font-size: smaller; - opacity: 0.55; - text-shadow: none; -} -row > box.header { - margin-left: 12px; - margin-right: 12px; - min-height: 50px; -} -row > box.header > box.title { - margin-top: 8px; - margin-bottom: 8px; -} - -tabbar .box { - min-height: 38px; - background: @headerbar_bg_color; - border-bottom: 1px solid @headerbar_shade_color; -} -tabbar .box:backdrop { - color: mix(@headerbar_fg_color,@headerbar_backdrop_color,0.5); - background-color: @headerbar_backdrop_color; -} -tabbar scrolledwindow.pinned undershoot { - border: 0 solid mix(black,@window_bg_color,0.76); -} -tabbar scrolledwindow.pinned:dir(rtl) undershoot.left { - border-left-width: 1px; -} -tabbar scrolledwindow.pinned:dir(ltr) undershoot.right { - border-right-width: 1px; -} -tabbar scrolledwindow.pinned:backdrop undershoot { - border-color: mix(currentColor,@window_bg_color,0.81); -} -tabbar scrolledwindow.pinned tabbox:dir(ltr) { - padding-right: 1px; - box-shadow: inset -1px 0 alpha(currentColor,0.15); -} -tabbar scrolledwindow.pinned tabbox:dir(rtl) { - padding-left: 1px; - box-shadow: inset 1px 0 alpha(currentColor,0.15); -} -tabbar undershoot { - transition: none; -} -tabbar undershoot.left { - background: linear-gradient(to right, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0) 20px); -} -tabbar undershoot.right { - background: linear-gradient(to left, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0) 20px); -} -tabbar .needs-attention-left undershoot.left { - background: linear-gradient(to right, alpha(@accent_bg_color,0.7), alpha(@accent_bg_color,0.5) 1px, alpha(@accent_bg_color,0) 20px); -} -tabbar .needs-attention-right undershoot.right { - background: linear-gradient(to left, alpha(@accent_bg_color,0.7), alpha(@accent_bg_color,0.5) 1px, alpha(@accent_bg_color,0) 20px); -} -tabbar tab { - margin: 4px 3px; - border-style: none; - border-radius: 9px; - transition: background-color 150ms ease-in-out; - background-position: left; - background-repeat: no-repeat; -} -tabbar tab:hover { - background-color: alpha(currentColor,0.07); -} -tabbar tab:checked { - background-color: alpha(currentColor,0.1); -} -tabbar tab:checked:hover { - background-color: alpha(currentColor,0.12); -} -tabbar .start-action, -tabbar .end-action { - background-color: @headerbar_bg_color; - border-color: transparent; - border-style: solid; - transition: background-color 150ms ease-in-out; -} -tabbar .start-action:backdrop, -tabbar .end-action:backdrop { - border-color: transparent; - background-color: @headerbar_backdrop_color; -} -tabbar .start-action button, -tabbar .end-action button { - border: none; - border-radius: 0; -} -tabbar .start-action:dir(ltr), -tabbar .end-action:dir(rtl) { - border-right-width: 1px; -} -tabbar .start-action:dir(ltr) > *, -tabbar .end-action:dir(rtl) > * { - margin-right: 1px; -} -tabbar .start-action:dir(rtl), -tabbar .end-action:dir(ltr) { - border-left-width: 1px; -} -tabbar .start-action:dir(rtl) > *, -tabbar .end-action:dir(ltr) > * { - margin-left: 1px; -} - -.tab-drag-icon tab { - min-height: 26px; - background-color: alpha(currentColor,0.16); - box-shadow: 0 3px 9px 1px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(0, 0, 0, 0.23), inset 0 1px alpha(white,0.5); - margin: 25px; -} - -tabbar tab, -.tab-drag-icon tab { - padding: 6px; -} -tabbar tab.needs-attention, -.tab-drag-icon tab.needs-attention { - background-image: radial-gradient(ellipse at bottom, rgba(255, 255, 255, 0.8), alpha(@accent_bg_color,0.2) 15%, alpha(@accent_bg_color,0) 15%); -} -tabbar tab .tab-close-button, -tabbar tab .tab-indicator, -.tab-drag-icon tab .tab-close-button, -.tab-drag-icon tab .tab-indicator { - padding: 0; - margin: 0; - min-width: 24px; - min-height: 24px; - border-radius: 99px; - border: none; - box-shadow: none; - -gtk-icon-shadow: none; - text-shadow: none; - background: none; -} -tabbar tab .tab-close-button:hover, -tabbar tab .tab-indicator.clickable:hover, -.tab-drag-icon tab .tab-close-button:hover, -.tab-drag-icon tab .tab-indicator.clickable:hover { - background: alpha(@window_fg_color,0.15); -} -tabbar tab .tab-close-button:active, -tabbar tab .tab-indicator.clickable:active, -.tab-drag-icon tab .tab-close-button:active, -.tab-drag-icon tab .tab-indicator.clickable:active { - background: alpha(black,0.2); -} - -flap > dimming, -deck > dimming, -leaflet > dimming { - background: rgba(0, 0, 0, 0.12); -} -flap > border, -deck > border, -leaflet > border { - min-width: 1px; - min-height: 1px; - background: rgba(0, 0, 0, 0.05); -} -flap > shadow, -deck > shadow, -leaflet > shadow { - min-width: 56px; - min-height: 56px; -} -flap > shadow.left, -deck > shadow.left, -leaflet > shadow.left { - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to right, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); -} -flap > shadow.right, -deck > shadow.right, -leaflet > shadow.right { - background-image: linear-gradient(to left, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to left, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); -} -flap > shadow.up, -deck > shadow.up, -leaflet > shadow.up { - background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to bottom, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); -} -flap > shadow.down, -deck > shadow.down, -leaflet > shadow.down { - background-image: linear-gradient(to top, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to top, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); -} -flap > outline, -deck > outline, -leaflet > outline { - min-width: 1px; - min-height: 1px; - background: rgba(255, 255, 255, 0.2); -} - -avatar { - border-radius: 9999px; - -gtk-outline-radius: 9999px; - font-weight: bold; -} -avatar.color1 { - background-image: linear-gradient(#83b6ec, #337fdc); - color: #cfe1f5; -} -avatar.color2 { - background-image: linear-gradient(#7ad9f1, #0f9ac8); - color: #caeaf2; -} -avatar.color3 { - background-image: linear-gradient(#8de6b1, #29ae74); - color: #cef8d8; -} -avatar.color4 { - background-image: linear-gradient(#b5e98a, #6ab85b); - color: #e6f9d7; -} -avatar.color5 { - background-image: linear-gradient(#f8e359, #d29d09); - color: #f9f4e1; -} -avatar.color6 { - background-image: linear-gradient(#ffcb62, #d68400); - color: #ffead1; -} -avatar.color7 { - background-image: linear-gradient(#ffa95a, #ed5b00); - color: #ffe5c5; -} -avatar.color8 { - background-image: linear-gradient(#f78773, #e62d42); - color: #f8d2ce; -} -avatar.color9 { - background-image: linear-gradient(#e973ab, #e33b6a); - color: #fac7de; -} -avatar.color10 { - background-image: linear-gradient(#cb78d4, #9945b5); - color: #e7c2e8; -} -avatar.color11 { - background-image: linear-gradient(#9e91e8, #7a59ca); - color: #d5d2f5; -} -avatar.color12 { - background-image: linear-gradient(#e3cf9c, #b08952); - color: #f2eade; -} -avatar.color13 { - background-image: linear-gradient(#be916d, #785336); - color: #e5d6ca; -} -avatar.color14 { - background-image: linear-gradient(#c0bfbc, #6e6d71); - color: #d8d7d3; -} -avatar.contrasted { - color: #fff; -} -avatar.image { - background: none; -} - -window.preferences > deck > deck > box > stack > stack > scrolledwindow > viewport > clamp, -preferencespage > scrolledwindow > viewport > clamp { - margin: 0 12px; -} -window.preferences > deck > deck > box > stack > stack > scrolledwindow > viewport > clamp > list, -window.preferences > deck > deck > box > stack > stack > scrolledwindow > viewport > clamp > box > preferencesgroup, -preferencespage > scrolledwindow > viewport > clamp > list, -preferencespage > scrolledwindow > viewport > clamp > box > preferencesgroup { - margin-top: 24px; -} - -preferencesgroup > box > label:not(:first-child) { - margin-top: 6px; -} -preferencesgroup > box > box:not(:first-child) { - margin-top: 12px; -} - -tabbar .tab-indicator:not(.clickable) { - background: none; - box-shadow: none; - border-color: transparent; -} - -.windowhandle, .windowhandle * { - -GtkWidget-window-dragging: true; -} - -.heading.h4 { - color: @window_fg_color; -} - -window.csd.unified list.content spinbutton { - border: none; -} -window.csd.unified list.content spinbutton:focus { - box-shadow: inset 0 0 0 2px alpha(@accent_color,0.5); -} - -window.csd.unified .titlebar { - border-bottom: 0; - box-shadow: none; -} - -window.csd.unified .sidebar separator { - min-height: 0; -} -window.csd.unified .sidebar list row:backdrop:hover { - background-color: alpha(currentColor,0.07); -} - -window.rounded, -window.rounded actionbar { - border-radius: 0 0 15px 15px; -} -window.rounded decoration, -window.rounded actionbar decoration { - border-radius: 15px; -} - -window.flat headerbar { - box-shadow: none; -} - -.accent { - color: @accent_bg_color; -} - -.h1 { - font-size: 20pt; - font-weight: 300; -} - -.h2 { - font-size: 16pt; - font-weight: 200; -} - -.h3 { - font-size: 11pt; -} - -.h4, -.category-label { - color: shade(@window_fg_color,1.2); - font-weight: 700; -} - -.h4 { - padding-top: 0.5em; - padding-bottom: 0.5em; -} - -list .h4 { - padding-left: 0.5em; -} - -.storage-bar .trough { - padding: 8px 6px; - border: none; - border-radius: 9px 9px 0 0; - background-image: none; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 1px 3px 1px rgba(0, 0, 0, 0.07), 0 2px 6px 2px rgba(0, 0, 0, 0.03); -} -.storage-bar .fill-block { - padding: 8px 6px; - border: 1px solid rgba(0, 0, 0, 0.35); - border-top-width: 0; - border-right-width: 0; - border-bottom-width: 1px; - border-left-width: 0; - border-radius: 0; - border-bottom-color: shade(mix(currentColor,@window_bg_color,0.85),0.75); - background-color: shade(@view_bg_color,0.85); -} -.storage-bar .fill-block:first-child { - border-radius: 9px 0 0; -} -.storage-bar .fill-block:last-child { - border-radius: 0 9px 0 0; -} -.storage-bar .fill-block:only-child { - border-radius: 9px 9px 0 0; -} -.storage-bar .fill-block image { - -gtk-icon-style: symbolic; -} -.storage-bar .empty-block { - border-bottom-width: 1px; - border-bottom-color: shade(mix(currentColor,@window_bg_color,0.85),0.6); - background-color: shade(@view_bg_color,0.95); -} -.storage-bar .empty-block image { - color: black; -} -.storage-bar .app { - border-bottom-width: 1px; - border-bottom-color: shade(#dc8add,0.7); - background-color: #dc8add; -} -.storage-bar .app image { - color: white; -} -.storage-bar .audio { - border-bottom-width: 1px; - border-bottom-color: shade(#ffa348,0.8); - background-color: #ffa348; -} -.storage-bar .audio image { - color: black; -} -.storage-bar .files { - border-bottom-width: 1px; - border-bottom-color: shade(#99c1f1,0.8); - background-color: #99c1f1; -} -.storage-bar .files image { - color: black; -} -.storage-bar .photo { - border-bottom-width: 1px; - border-bottom-color: shade(#57e389,0.7); - background-color: #57e389; -} -.storage-bar .photo image { - color: black; -} -.storage-bar .video { - border-bottom-width: 1px; - border-bottom-color: shade(#f66151,0.8); - background-color: #f66151; -} -.storage-bar .video image { - color: white; -} -.storage-bar .legend { - padding: 8px; - border-radius: 50%; -} -.storage-bar .legend image { - color: black; -} -.storage-bar .disk-bar { - padding: 0; - border-radius: 9px; - background-color: #cdab8f; -} -.storage-bar .ext2, .storage-bar .ext3, .storage-bar .ext4, .storage-bar .fat16, .storage-bar .fat32, .storage-bar .btrfs, -.storage-bar .xfs, .storage-bar .ntfs, .storage-bar .luks, .storage-bar .lvm, .storage-bar .none, .storage-bar .swap, .storage-bar .unused { - border: none; - box-shadow: inset 0 -2px rgba(94, 92, 100, 0.5), inset 1px 0 rgba(94, 92, 100, 0.5), inset -1px 0 rgba(94, 92, 100, 0.5); -} -.storage-bar .swap { - background-color: #a51d2d; -} -.storage-bar .swap image { - color: white; -} -.storage-bar .ext4 { - background-color: #57e389; -} -.storage-bar .ext4 image { - color: black; -} -.storage-bar .ext3 { - background-color: #26a269; -} -.storage-bar .ext3 image { - color: white; -} -.storage-bar .ext2 { - background-color: #8ff0a4; -} -.storage-bar .ext2 image { - color: black; -} -.storage-bar .fat16, -.storage-bar .fat32 { - background-color: #f8e45c; -} -.storage-bar .fat16 image, -.storage-bar .fat32 image { - color: black; -} -.storage-bar .btrfs { - background-color: #1a5fb4; -} -.storage-bar .btrfs image { - color: white; -} -.storage-bar .xfs { - background-color: #99c1f1; -} -.storage-bar .xfs image { - color: black; -} -.storage-bar .ntfs { - background-color: #ffa348; -} -.storage-bar .ntfs image { - color: black; -} -.storage-bar .luks { - background-color: #c061cb; -} -.storage-bar .luks image { - color: black; -} -.storage-bar .lvm { - background-color: #dc8add; -} -.storage-bar .lvm image { - color: black; -} -.storage-bar .none { - background-color: #99c1f1; -} -.storage-bar .none image { - color: black; -} -.storage-bar .unused { - background-color: #cdab8f; -} -.storage-bar .unused image { - color: black; -} -.storage-bar .legend { - box-shadow: none; -} - -GraniteWidgetsPopOver { - -GraniteWidgetsPopOver-arrow-width: 21; - -GraniteWidgetsPopOver-arrow-height: 10; - -GraniteWidgetsPopOver-border-radius: 15px; - -GraniteWidgetsPopOver-border-width: 0; - -GraniteWidgetsPopOver-shadow-size: 12; - border: 1px solid @view_bg_color; - background: @view_bg_color; - color: @window_fg_color; -} -GraniteWidgetsPopOver .button { - background-image: none; - background: none; - border: none; -} -GraniteWidgetsPopOver .button:active, GraniteWidgetsPopOver .button:active:hover { - color: @accent_bg_color; -} -GraniteWidgetsPopOver > .frame { - border: none; -} -GraniteWidgetsPopOver .sidebar.view { - border: none; - background: none; -} - -GraniteWidgetsStaticNotebook .frame { - border: none; -} - -.popover_bg { - background-color: @view_bg_color; - background-image: none; - border: 1px solid @view_bg_color; - color: @window_fg_color; -} - -.deck { - background-color: @view_bg_color; -} - -paper, -.card { - transition: all 300ms cubic-bezier(0.25, 0.8, 0.25, 1); - border: none; - background-color: @view_bg_color; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 1px 3px 1px rgba(0, 0, 0, 0.07), 0 2px 6px 2px rgba(0, 0, 0, 0.03); -} -paper, paper.rounded, -.card, -.card.rounded { - border-radius: 12px; -} -paper.collapsed, -.card.collapsed { - background-color: @window_bg_color; -} - -.source-list { - -GtkTreeView-horizontal-separator: 1px; - -GtkTreeView-vertical-separator: 6px; - background-color: @window_bg_color; - border: solid mix(currentColor,@window_bg_color,0.85); - color: @window_fg_color; - border-right-width: 1px; -} -.source-list .category-expander { - color: transparent; -} -.source-list .badge { - background-image: none; - background-color: rgba(0, 0, 0, 0.4); - color: @window_bg_color; - border-radius: 10px; - padding: 0 6px; - margin: 0 3px; - border-width: 0; -} -.source-list .badge:selected:backdrop, .source-list .badge:selected:hover:backdrop { - background-color: rgba(0, 0, 0, 0.2); - color: shade(@window_bg_color,0.95); -} -.source-list row, -.source-list .list-row { - border: none; - padding: 0; -} -.source-list row > GtkLabel, -.source-list row > label, -.source-list .list-row > GtkLabel, -.source-list .list-row > label { - padding-left: 6px; - padding-right: 6px; -} - -.avatar { - border-radius: 999px; - box-shadow: none; -} - -.overlay-bar { - padding: 4px; -} - -.dynamic-notebook tab.reorderable-page { - padding: 8px; -} - -scale.temperature trough { - background-image: linear-gradient(to right, rgba(153, 193, 241, 0.4), #c0bfbc, #f9f06b); -} -scale.temperature:dir(rtl) trough { - background-image: linear-gradient(to left, rgba(153, 193, 241, 0.4), #c0bfbc, #f9f06b); -} -scale.warmth trough { - background-image: linear-gradient(to right, rgba(249, 240, 107, 0.4), rgba(229, 165, 10, 0.6)); -} -scale.warmth:dir(rtl) trough { - background-image: linear-gradient(to left, rgba(249, 240, 107, 0.4), rgba(229, 165, 10, 0.6)); -} - -.terminal, -.terminal text { - background-color: #3d3846; - color: white; - font-family: monospace; -} -.terminal selection, -.terminal text selection { - background-color: @accent_bg_color; - color: white; -} -.terminal:backdrop, -.terminal text:backdrop { - background-color: #5e5c64; - color: white; -} - -label.terminal { - padding: 1em; -} - -.welcome { - font-size: 10pt; - text-shadow: none; -} -.welcome .h1, .welcome .h3 { - color: shade(@window_fg_color,1.2); -} - -button.back-button, -button.back-button.text-button { - padding-right: 8px; - padding-left: 36px; - transition: background 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); - background-image: -gtk-icontheme("go-previous-symbolic"); - background-repeat: no-repeat no-repeat; - background-position: 5px 50%; - background-size: 21px; -} -.titlebar button.back-button, -.titlebar button.back-button.text-button { - background-color: @headerbar_bg_color; - background-image: -gtk-icontheme("go-previous-symbolic"); - background-repeat: no-repeat no-repeat; - background-position: 5px 50%; - background-size: 21px; - padding-left: 36px; - color: @headerbar_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.9); -} -.titlebar button.back-button:hover, -.titlebar button.back-button.text-button:hover { - background-image: -gtk-icontheme("go-previous-symbolic"); - background-repeat: no-repeat no-repeat; - background-position: 5px 50%; - background-size: 21px; - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.85); - box-shadow: none; -} -.titlebar button.back-button:active, -.titlebar button.back-button.text-button:active { - background-image: -gtk-icontheme("go-previous-symbolic"); - background-repeat: no-repeat no-repeat; - background-position: 5px 50%; - background-size: 21px; - color: @headerbar_fg_color; - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -.titlebar button.back-button:active:hover, -.titlebar button.back-button.text-button:active:hover { - background-color: mix(@headerbar_fg_color,@headerbar_bg_color,0.65); -} -button.back-button:dir(rtl), -button.back-button.text-button:dir(rtl) { - padding: 0.5em 0.6em; - padding-right: 36px; - padding-left: 8px; - background-image: -gtk-icontheme("go-next-symbolic"); - background-repeat: no-repeat no-repeat; - background-position: 90% 50%; -} - -.checkerboard { - box-shadow: 0px 1px 2px 0px alpha(mix(currentColor,@window_bg_color,0.85),0.5), 0px 0px 0px 1px alpha(mix(currentColor,@window_bg_color,0.85),0.5), 0px 2px 0px 0px alpha(mix(currentColor,@window_bg_color,0.85),0.5); - border-radius: 2px; -} - -.org-gnome-gedit notebook > header, .gedit-side-panel-paned notebook > header { - background-color: @headerbar_bg_color; -} -.org-gnome-gedit notebook > header:backdrop, .gedit-side-panel-paned notebook > header:backdrop { - background-color: @headerbar_backdrop_color; -} -.org-gnome-gedit notebook > header, .gedit-side-panel-paned notebook > header { - box-shadow: inset 0 -1px @headerbar_shade_color; -} - -.gedit-search-slider { - background: @window_bg_color; - border: 1px solid mix(currentColor,@window_bg_color,0.85); - border-top-style: none; - padding: 4px 8px; - border-radius: 0 0 9px 9px; -} -.gedit-search-slider button { - padding-top: 7px; - padding-bottom: 7px; -} - -.gedit-document-panel { - background-color: @window_bg_color; -} -.gedit-document-panel row.activatable { - padding: 6px; -} -.gedit-document-panel row button { - min-width: 22px; - min-height: 22px; - padding: 0; - margin: 0; - border: none; -} -.gedit-document-panel row:hover button:hover { - background-color: alpha(currentColor,0.15); -} -.gedit-document-panel row:hover button:active { - background-color: alpha(currentColor,0.3); -} -.gedit-document-panel row:hover:selected button:hover { - color: @window_fg_color; -} - -.XfceHeading { - background-color: @view_bg_color; - margin: 0; - padding: 0; - border-width: 0; -} - -XfdesktopIconView.view { - background: transparent; - color: rgba(255, 255, 255, 0.9); - border-radius: 9px; -} -XfdesktopIconView.view:active { - background: alpha(mix(black,@accent_bg_color,0.85),0.5); - text-shadow: 0 1px 1px black; -} -XfdesktopIconView.view .label { - text-shadow: 1px 1px 2px black; -} -XfdesktopIconView.view .rubberband { - border-radius: 0; -} - -.xfce4-panel.background { - border: none; - background-color: @panel_bg_color; - color: @panel_fg_color; - transition-duration: 250ms; -} -.xfce4-panel.background .tasklist button, -.xfce4-panel.background #actions-button, -.xfce4-panel.background #clock-button { - margin: 0 1px; -} -.xfce4-panel.background.horizontal .tasklist button { - margin: 0 1px; -} -.xfce4-panel.background.horizontal .tasklist button label { - padding-right: 3px; -} -.xfce4-panel.background.vertical .tasklist button { - margin: 1px 0; -} -.xfce4-panel.background.vertical .tasklist button label { - padding-bottom: 3px; -} -.xfce4-panel.background .tasklist image { - margin-left: 2px; - margin-right: 2px; -} -.xfce4-panel.background button label { - padding-left: 6px; - padding-right: 6px; -} -.xfce4-panel.background button { - padding: 0 6px; - min-height: 12px; - min-width: 12px; - border-radius: 24px; - color: @panel_fg_color; - transition-duration: 250ms; - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; -} -.xfce4-panel.background button:disabled { - background-color: transparent; - color: alpha(@panel_fg_color,0.2); -} -.xfce4-panel.background button:hover:not(:active):not(:checked) { - color: @panel_fg_color; - background-color: alpha(@panel_fg_color,0.25); - background-image: none; -} -.xfce4-panel.background button:checked { - background-color: alpha(@panel_fg_color,0.2); - color: @panel_fg_color; -} -.xfce4-panel.background button:checked:hover { - background-color: alpha(@panel_fg_color,0.35); -} -.xfce4-panel.background button:checked:disabled { - border-color: transparent; - background-color: transparent; - background-image: none; - box-shadow: inset 0 1px rgba(255, 255, 255, 0); - text-shadow: none; - -gtk-icon-shadow: none; - color: alpha(@panel_fg_color,0.2); -} -.xfce4-panel.background button:drop(active) { - color: @accent_bg_color; - border-color: @accent_bg_color; - box-shadow: inset 0 0 0 1px @accent_bg_color; -} -.xfce4-panel.background button entry { - caret-color: @view_fg_color; -} -.xfce4-panel.background button menu { - -gtk-icon-effect: none; - text-shadow: none; -} -.xfce4-panel.background button menu .linked button { - color: @view_fg_color; - outline-color: alpha(@accent_color,0.5); - background-color: mix(@view_fg_color,@popover_bg_color,0.9); -} -.xfce4-panel.background button menu .linked button:disabled { - color: alpha(@window_fg_color,0.5); - background-color: mix(@window_fg_color,@window_bg_color,0.95); - text-shadow: none; - -gtk-icon-shadow: none; - box-shadow: none; - border-color: alpha(mix(currentColor,@window_bg_color,0.85),0.5); -} -.xfce4-panel.background progressbar { - margin: 0; -} -.xfce4-panel.background progressbar.horizontal trough { - min-height: 6px; - padding: 0; -} -.xfce4-panel.background progressbar.horizontal progress { - min-height: 4px; -} -.xfce4-panel.background progressbar.vertical trough { - min-width: 6px; - padding: 0; -} -.xfce4-panel.background progressbar.vertical progress { - min-width: 4px; -} -.xfce4-panel.background progressbar progress { - border-radius: 0px; -} -.xfce4-panel.background progressbar trough { - background: shade(@panel_bg_color,0.7); - border-radius: 0px; - border-color: shade(@panel_bg_color,0.4); -} - -wnck-pager { - background-color: alpha(@panel_fg_color,0.1); -} -wnck-pager:selected { - background-color: shade(@accent_bg_color,0.88); -} -wnck-pager:hover { - background-color: @accent_bg_color; -} - -#xfwm-tabwin { - padding: 12px; - border-radius: 15px; - -XfwmTabwinWidget-icon-size: 64px; - -XfwmTabwinWidget-preview-size: 128px; -} -#xfwm-tabwin .tabwin-app-grid button { - min-width: 96px; - min-height: 96px; -} - -window#whiskermenu-window button { - transition: none; -} - -#whiskermenu-button { - transition: none; -} - -#XfceNotifyWindow { - border-radius: 9px; - background-color: @view_bg_color; -} - -.caja-desktop.caja-canvas-item, -.nemo-desktop.nemo-canvas-item { - color: @accent_fg_color; - text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); -} - -.nemo-properties-dialog .dialog-action-box .dialog-action-area { - margin: 2px 6px 4px; -} -.nemo-properties-dialog toolbar stackswitcher.linked button { - margin-right: 0; -} -.nemo-properties-dialog toolbar stackswitcher.linked button:backdrop { - color: mix(@window_fg_color,@window_bg_color,0.5); - background-color: @window_bg_color; -} - -.nemo-window .sidebar scrolledwindow.frame.nemo-places-sidebar { - border: none; -} -.nemo-window .sidebar viewport.frame box.vertical treeview.view.places-treeview { - background-image: image(@window_bg_color); - border-radius: 0; -} -.nemo-window .sidebar viewport.frame box.vertical treeview.view.places-treeview:selected { - background: @accent_bg_color; -} -.nemo-window .sidebar viewport.frame box.vertical treeview.view.places-treeview:not(:selected):not(:backdrop):hover { - background-image: image(alpha(@window_fg_color,0.05)); -} -.nemo-window .nemo-inactive-pane .view, -.nemo-window .nemo-inactive-pane iconview { - background-color: @window_bg_color; -} -.nemo-window .nemo-window-pane widget.entry { - border: 1px solid; - border-radius: 3px; - color: @window_fg_color; - border-color: @accent_bg_color; - background-color: @window_bg_color; -} -.nemo-window .nemo-window-pane widget.entry:selected { - border: 1px solid; - border-radius: 3px; - color: @accent_fg_color; - border-color: @accent_bg_color; - background-color: @accent_bg_color; -} -.nemo-window toolbar.horizontal.primary-toolbar { - border-bottom: 1px solid mix(currentColor,@window_bg_color,0.85); -} -.nemo-window toolbar.horizontal.primary-toolbar widget.linked.raised button:first-child widget { - -gtk-icon-source: -gtk-icontheme("go-previous-symbolic"); -} -.nemo-window toolbar.horizontal.primary-toolbar widget.linked.raised button:last-child widget { - -gtk-icon-source: -gtk-icontheme("go-next-symbolic"); -} -.nemo-window toolbar.horizontal.primary-toolbar toolitem box widget * { - min-height: 0; - min-width: 0; -} -.nemo-window toolbar.horizontal.primary-toolbar .linked button { - margin-right: 0; -} - -#MozillaGtkWidget.background selection:focus, #MozillaGtkWidget.background selection { - background-color: @accent_bg_color; - color: @accent_fg_color; -} - -terminal-window notebook > header.top tabs:not(:only-child):first-child, terminal-window notebook > header.bottom tabs:not(:only-child):first-child { - margin-left: 0px; -} -terminal-window notebook > header.top tabs:not(:only-child):last-child, terminal-window notebook > header.bottom tabs:not(:only-child):last-child { - margin-right: 0px; -} - -terminal-window notebook scrollbar slider { - margin: 0; - border-width: 3px; -} - -window.background.caja-navigation-window #Toolbar { - border-bottom: 1px solid mix(currentColor,@window_bg_color,0.85); -} -window.background.caja-navigation-window #Toolbar:backdrop { - background-color: @window_bg_color; - border-color: mix(currentColor,@window_bg_color,0.81); -} - -.caja-pathbar button { - min-width: 32px; - border-radius: 0; - border-right-width: 0; - margin-right: -3px; -} -.caja-pathbar button.slider-button:nth-child(odd) { - border-radius: 9px 0px 0px 9px; -} -.caja-pathbar button.slider-button:nth-child(even) { - border-radius: 0 9px 9px 0; - border-right-width: 1px; -} - -.caja-side-pane .frame { - border-style: solid none none none; -} - -.caja-notebook .view, .caja-notebook .view.frame, .caja-notebook .frame { - border-left: 0; - border-right: 0; -} - -.caja-side-pane + separator + box:backdrop { - background: @window_bg_color; -} - -.caja-navigation-window widget.view widget.entry, -.caja-desktop-window widget.view widget.entry { - background: mix(currentColor,@window_bg_color,0.95); - color: @window_fg_color; - border-color: mix(currentColor,@window_bg_color,0.85); -} -.caja-navigation-window widget.view widget.entry:selected, -.caja-desktop-window widget.view widget.entry:selected { - background: @accent_bg_color; - color: @accent_fg_color; -} - -#gnc-id-main-window treeview.view:not(:selected):hover { - background-color: mix(currentColor,@view_bg_color,0.93); -} - -gnc-id-sheet-list { - background-color: @window_bg_color; -} - -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content { - background-color: @window_bg_color; - border: none; - border-radius: 0; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content > row.activatable { - border: 1px solid mix(currentColor,@window_bg_color,0.85); - border-bottom-width: 0; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content > row.activatable:first-child { - border-top-left-radius: 12px; - border-top-right-radius: 12px; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content .geary-attachment-pane { - border-radius: 0 0 12px 12px; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content .geary-attachment-pane actionbar.background { - background-color: transparent; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content .geary-attachment-pane actionbar.background > revealer > box { - border-radius: 0 0 12px 12px; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content geary-composer-editor > box.background { - background-color: transparent; -} -geary-conversation-viewer#conversation_viewer list.background.conversation-listbox.content geary-composer-editor > box.background > actionbar > revealer > box { - border-radius: 0 0 12px 12px; -} -geary-conversation-viewer#conversation_viewer searchbar > revealer > box { - background-color: @view_bg_color; - border-color: mix(currentColor,@window_bg_color,0.85); -} - -.geary-folder-popover-list-row { - border-radius: 0; - margin: 0; -} - -.geary-main-window leaflet > leaflet > box:first-child { - background-color: @sidebar_bg_color; -} -.geary-main-window leaflet > leaflet > box:first-child:backdrop { - background-color: @sidebar_backdrop_color; -} - -.geary-main-window leaflet > box:first-child > .titlebar { - background-color: @sidebar_bg_color; - background-image: none; - border-bottom: transparent; - box-shadow: none; -} -.geary-main-window leaflet > box:first-child > .titlebar:backdrop { - background-color: @sidebar_backdrop_color; -} -.geary-main-window leaflet > box:first-child > .titlebar button { - background-color: transparent; -} -.geary-main-window leaflet > box:first-child > .titlebar button:hover { - background-color: alpha(currentColor,0.15); -} -.geary-main-window leaflet > box:first-child > .titlebar button:hover:active, .geary-main-window leaflet > box:first-child > .titlebar button:active, .geary-main-window leaflet > box:first-child > .titlebar button:hover:checked, .geary-main-window leaflet > box:first-child > .titlebar button:checked { - background-color: alpha(currentColor,0.3); -} -.geary-main-window leaflet > box:first-child > .titlebar button:backdrop { - background: transparent; -} -.geary-main-window leaflet > box:first-child > .titlebar button:backdrop:hover { - background: alpha(currentColor,0.15); -} -.geary-main-window leaflet > box:not(:first-child) > .titlebar { - border-bottom: transparent; - box-shadow: none; -} -.geary-main-window leaflet > box:not(:first-child) > .titlebar:backdrop { - background-image: none; - background-color: @headerbar_bg_color; -} - -.geary-main-window separator.sidebar { - background-color: mix(currentColor,@window_bg_color,0.85); -} - -.geary-main-window .titlebar .image-button { - padding: 0 6px; -} - -.geary-folder .sidebar.view:selected { - background-color: alpha(currentColor,0.1); -} -.geary-folder .sidebar.view:selected:hover { - background-color: alpha(currentColor,0.12); -} -.geary-folder .sidebar.view:hover { - background-color: alpha(currentColor,0.07); -} - -#DialogNotebook treeview.view:hover { - background-color: alpha(@accent_bg_color,0.5); -} - -.budgie-panel button { - min-height: 16px; - min-width: 16px; - padding: 0; - border-radius: 0; -} -.budgie-panel button.flat.launcher { - padding: 0; -} -.budgie-panel.horizontal button, -.budgie-panel #tasklist-button { - padding: 0 4px; -} -.budgie-panel.vertical button { - padding: 4px 0; -} -.budgie-panel.vertical #tasklist-button { - min-height: 32px; -} - -toolbar.toolbar box:not(.linked) > button { - font-weight: normal; -} - -window.background:not(.solid-csd):not(.csd) > notebook > header { - border: 0; -} -window.background:not(.solid-csd):not(.csd) > notebook > header tab { - margin: 0 1px; - border-radius: 9px; - box-shadow: none; -} -window.background:not(.solid-csd):not(.csd) > notebook > header tab:hover { - background-color: alpha(currentColor,0.07); -} -window.background:not(.solid-csd):not(.csd) > notebook > header tab:active, window.background:not(.solid-csd):not(.csd) > notebook > header tab:checked { - background-color: alpha(currentColor,0.1); -} -window.background:not(.solid-csd):not(.csd) > notebook > header tab:checked:hover { - background-color: alpha(currentColor,0.12); -} - -window.background:not(.solid-csd):not(.csd) > notebook > stack:not(:only-child) { - background-color: @window_bg_color; -} - -#settingsDialog .dialog-vbox.vertical tab { - box-shadow: none; - margin-right: 8px; - border-radius: 9px; -} -#settingsDialog .dialog-vbox.vertical tab:hover { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.85); - box-shadow: none; -} -#settingsDialog .dialog-vbox.vertical tab:checked { - color: @window_fg_color; - background-color: mix(@window_fg_color,@window_bg_color,0.7); - box-shadow: none; - text-shadow: none; - -gtk-icon-shadow: none; -} -#settingsDialog .dialog-vbox.vertical tab:checked:hover { - background-color: mix(@window_fg_color,@window_bg_color,0.65); -} - -/* Matugen Colors */ - -@define-color accent_color {{colors.primary_fixed_dim.default.hex}}; -@define-color accent_fg_color {{colors.on_primary_fixed.default.hex}}; -@define-color accent_bg_color {{colors.primary_fixed_dim.default.hex}}; -@define-color window_bg_color {{colors.background.default.hex}}; -@define-color window_fg_color {{colors.on_surface.default.hex}}; -@define-color headerbar_bg_color {{colors.background.default.hex}}; -@define-color headerbar_fg_color {{colors.on_surface.default.hex}}; -@define-color popover_bg_color {{colors.background.default.hex}}; -@define-color popover_fg_color {{colors.on_surface.default.hex}}; -@define-color view_bg_color {{colors.background.default.hex}}; -@define-color view_fg_color {{colors.on_surface.default.hex}}; -@define-color card_bg_color {{colors.background.default.hex}}; -@define-color card_fg_color {{colors.on_surface.default.hex}}; -@define-color sidebar_bg_color @window_bg_color; -@define-color sidebar_fg_color @window_fg_color; -@define-color sidebar_border_color @window_bg_color; -@define-color sidebar_backdrop_color @window_bg_color; diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/hypr-colors.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/hypr-colors.conf deleted file mode 100644 index 8f7a2fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/hypr-colors.conf +++ /dev/null @@ -1,25 +0,0 @@ -# ! Auto-generated file. Do not edit directly. -# Remove source = ./dms/colors.conf from your config to override. - -$primary = rgb({{colors.primary.default.hex_stripped}}) -$outline = rgb({{colors.outline.default.hex_stripped}}) -$error = rgb({{colors.error.default.hex_stripped}}) - -general { - col.active_border = $primary - col.inactive_border = $outline -} - -group { - col.border_active = $primary - col.border_inactive = $outline - col.border_locked_active = $error - col.border_locked_inactive = $outline - - groupbar { - col.active = $primary - col.inactive = $outline - col.locked_active = $error - col.locked_inactive = $outline - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kcolorscheme.colors b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kcolorscheme.colors deleted file mode 100644 index 0b33659..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kcolorscheme.colors +++ /dev/null @@ -1,146 +0,0 @@ -[KDE] -contrast=4 - -[General] -ColorScheme=DankMatugen -Name=Dank Shell (matugen) - -[ColorEffects:Disabled] -Color={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ColorAmount=0 -ColorEffect=0 -ContrastAmount=0.65 -ContrastEffect=1 -IntensityAmount=0.1 -IntensityEffect=2 - -[ColorEffects:Inactive] -ChangeSelectionColor=true -Color={{colors.outline.default.red}},{{colors.outline.default.green}},{{colors.outline.default.blue}} -ColorAmount=0.025 -ColorEffect=2 -ContrastAmount=0.1 -ContrastEffect=2 -Enable=false -IntensityAmount=0 -IntensityEffect=0 - -[Colors:Button] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Complementary] -BackgroundAlternate={{colors.surface_container.default.red}},{{colors.surface_container.default.green}},{{colors.surface_container.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header][Inactive] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Selection] -BackgroundAlternate={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -BackgroundNormal={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Tooltip] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:View] -BackgroundAlternate={{colors.surface_container_low.default.red}},{{colors.surface_container_low.default.green}},{{colors.surface_container_low.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Window] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -DecorationHover={{colors.inverse_primary.default.red}},{{colors.inverse_primary.default.green}},{{colors.inverse_primary.default.blue}} -ForegroundActive={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[WM] -activeBackground={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -activeBlend={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -activeForeground={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -inactiveBackground={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -inactiveBlend={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -inactiveForeground={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty-tabs.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty-tabs.conf deleted file mode 100644 index 78b708a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty-tabs.conf +++ /dev/null @@ -1,23 +0,0 @@ -tab_bar_edge top -tab_bar_style powerline -tab_powerline_style slanted -tab_bar_align left -tab_bar_min_tabs 2 -tab_bar_margin_width 0.0 -tab_bar_margin_height 2.5 1.5 -tab_bar_margin_color {{colors.background.default.hex}} - -tab_bar_background {{colors.background.default.hex}} - -active_tab_foreground {{colors.on_primary.default.hex}} -active_tab_background {{colors.primary.default.hex}} -active_tab_font_style bold - -inactive_tab_foreground {{colors.on_surface_variant.default.hex}} -inactive_tab_background {{colors.background.default.hex}} -inactive_tab_font_style normal - -tab_activity_symbol " ● " - -tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]" -active_tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty.conf deleted file mode 100644 index c140ff3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/kitty.conf +++ /dev/null @@ -1,25 +0,0 @@ -cursor {{colors.on_surface.default.hex}} -cursor_text_color {{colors.on_surface_variant.default.hex}} - -foreground {{colors.on_surface.default.hex}} -background {{colors.background.default.hex}} -selection_foreground {{colors.on_secondary.default.hex}} -selection_background {{colors.secondary_fixed_dim.default.hex}} -url_color {{colors.primary.default.hex}} - -color0 {{dank16.color0.default.hex}} -color1 {{dank16.color1.default.hex}} -color2 {{dank16.color2.default.hex}} -color3 {{dank16.color3.default.hex}} -color4 {{dank16.color4.default.hex}} -color5 {{dank16.color5.default.hex}} -color6 {{dank16.color6.default.hex}} -color7 {{dank16.color7.default.hex}} -color8 {{dank16.color8.default.hex}} -color9 {{dank16.color9.default.hex}} -color10 {{dank16.color10.default.hex}} -color11 {{dank16.color11.default.hex}} -color12 {{dank16.color12.default.hex}} -color13 {{dank16.color13.default.hex}} -color14 {{dank16.color14.default.hex}} -color15 {{dank16.color15.default.hex}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/light-kcolorscheme.colors b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/light-kcolorscheme.colors deleted file mode 100644 index 9773930..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/light-kcolorscheme.colors +++ /dev/null @@ -1,146 +0,0 @@ -[KDE] -contrast=4 - -[General] -ColorScheme=DankMatugen -Name=Dank Shell (matugen) - -[ColorEffects:Disabled] -Color={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ColorAmount=0 -ColorEffect=0 -ContrastAmount=0.65 -ContrastEffect=1 -IntensityAmount=0.1 -IntensityEffect=2 - -[ColorEffects:Inactive] -ChangeSelectionColor=true -Color={{colors.outline.default.red}},{{colors.outline.default.green}},{{colors.outline.default.blue}} -ColorAmount=0.025 -ColorEffect=2 -ContrastAmount=0.1 -ContrastEffect=2 -Enable=false -IntensityAmount=0 -IntensityEffect=0 - -[Colors:Button] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Complementary] -BackgroundAlternate={{colors.surface_container.default.red}},{{colors.surface_container.default.green}},{{colors.surface_container.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header][Inactive] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Selection] -BackgroundAlternate={{colors.primary_container.default.red}},{{colors.primary_container.default.green}},{{colors.primary_container.default.blue}} -BackgroundNormal={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Tooltip] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:View] -BackgroundAlternate={{colors.surface_container_low.default.red}},{{colors.surface_container_low.default.green}},{{colors.surface_container_low.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Window] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[WM] -activeBackground={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -activeBlend={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -activeForeground={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -inactiveBackground={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -inactiveBlend={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -inactiveForeground={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/mango-colors.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/mango-colors.conf deleted file mode 100644 index 72d8ece..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/mango-colors.conf +++ /dev/null @@ -1,6 +0,0 @@ -# ! Auto-generated file. Do not edit directly. -# Remove source = ./dms/colors.conf from your config to override. - -bordercolor = 0x{{colors.outline.default.hex_stripped}}ff -focuscolor = 0x{{colors.primary.default.hex_stripped}}ff -urgentcolor = 0x{{colors.error.default.hex_stripped}}ff diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-colors.lua b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-colors.lua deleted file mode 100644 index eb6db53..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-colors.lua +++ /dev/null @@ -1,94 +0,0 @@ -local present, base46 = pcall(require, "base46") -if not present or not base46._DMS_SUPPORT then - vim.notify( - "base46 plugin not found or incorrect, make sure to install AvengeMedia/base46", - vim.log.levels.ERROR, - { title = "dms integration" } - ) - return -end - -local config_home = vim.env.XDG_CONFIG_HOME -if config_home == nil or #config_home == 0 then - config_home = vim.fs.joinpath(vim.env.HOME, ".config") -end -local settings_file_path = vim.fs.joinpath(config_home, "DankMaterialShell", "settings.json") -local settings_file = io.open(settings_file_path, "r") -if settings_file == nil then - vim.notify( - "cannnot read dms settings file at '" .. settings_file_path .. "'", - vim.log.levels.ERROR, - { title = "dms integration" } - ) - return -end -local settings = vim.json.decode(settings_file:read("*a")) -settings_file:close() - -local function deepGet(t, k) - for _, s in ipairs(k) do - if type(t) ~= "table" then - return - end - t = t[s] - end - return t -end - -local mode = vim.system({ "dms", "ipc", "call", "theme", "getMode" }, { text = true }):wait().stdout -if mode ~= nil then - if mode:match("light") then - vim.o.background = "light" - elseif mode:match("dark") then - vim.o.background = "dark" - end -end - -local current_file_path = debug.getinfo(1, "S").source:sub(2) -local theme_base = deepGet(settings, { "matugenTemplateNeovimSettings", vim.o.background, "baseTheme" }) - or ("github_" .. vim.o.background) -local harmony = deepGet(settings, { "matugenTemplateNeovimSettings", vim.o.background, "harmony" }) or 0.5 -local theme_name = "dms" - -if not _G._matugen_theme_watcher then - local uv = vim.uv or vim.loop - _G._matugen_theme_watcher = { uv.new_fs_event(), uv.new_fs_event(), reload_timer = uv.new_timer() } - - local debounce_time = 100 -- ms - local function handler() - _G._matugen_theme_watcher.reload_timer:stop() - _G._matugen_theme_watcher.reload_timer:start( - debounce_time, - 0, - vim.schedule_wrap(function() - base46.theme_tables[theme_name] = nil - if vim.g.colors_name == theme_name then - vim.cmd.colorscheme(theme_name) - vim.notify("Theme reload", vim.log.levels.INFO, { title = "dms integration" }) - end - -- NOTE: contrary to what the documentation says, uv fs events usually do not manage to react to more than one edit. - -- I understand that this is not intended: some edit processes in a typical system (e.g. the one neovim uses with - -- multiple renames and changes) make things hard to follow for libuv. Therefore, a restart is the best option. - _G._matugen_theme_watcher[1]:stop() - _G._matugen_theme_watcher[2]:stop() - _G._matugen_theme_watcher[1]:start(current_file_path, {}, handler) - _G._matugen_theme_watcher[2]:start(settings_file_path, {}, handler) - end) - ) - end - _G._matugen_theme_watcher[1]:start(current_file_path, {}, handler) - _G._matugen_theme_watcher[2]:start(settings_file_path, {}, handler) -end - -if not base46.theme_tables[theme_name] or base46.theme_tables[theme_name].type ~= vim.o.background then - local builtin = vim.deepcopy(assert(base46.get_builtin_theme(theme_base))) - local harmonized = base46.theme_harmonize(builtin, "{{colors.source_color.default.hex}}", harmony) - if settings.matugenTemplateNeovimSetBackground ~= false then - harmonized = base46.theme_set_bg(harmonized, "{{colors.background.default.hex}}") - end - - base46.theme_tables[theme_name] = harmonized -end - -base46.load(theme_name) -vim.g.colors_name = theme_name diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-lualine.lua b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-lualine.lua deleted file mode 100644 index 0e86d5f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/neovim-lualine.lua +++ /dev/null @@ -1,3 +0,0 @@ --- NOTE: this file should never be accessed if AvengeMedia/base46 is not installed, --- the neovim-colors.lua template will fail first. -return require("lualine.themes._base46")("dms") diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/niri-colors.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/niri-colors.kdl deleted file mode 100644 index 3c6c034..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/niri-colors.kdl +++ /dev/null @@ -1,39 +0,0 @@ -// ! Auto-generated file. Do not edit directly. -// Remove `include "dms/colors.kdl"` from your config to override. - -layout { - background-color "transparent" - - focus-ring { - active-color "{{colors.primary.default.hex}}" - inactive-color "{{colors.outline.default.hex}}" - urgent-color "{{colors.error.default.hex}}" - } - - border { - active-color "{{colors.primary.default.hex}}" - inactive-color "{{colors.outline.default.hex}}" - urgent-color "{{colors.error.default.hex}}" - } - - shadow { - color "{{colors.shadow.default.hex}}70" - } - - tab-indicator { - active-color "{{colors.primary.default.hex}}" - inactive-color "{{colors.outline.default.hex}}" - urgent-color "{{colors.error.default.hex}}" - } - - insert-hint { - color "{{colors.primary.default.hex}}80" - } -} - -recent-windows { - highlight { - active-color "{{colors.primary_container.dark.hex}}" - urgent-color "{{colors.error.default.hex}}" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/pywalfox-colors.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/pywalfox-colors.json deleted file mode 100644 index bf0538b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/pywalfox-colors.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "wallpaper": "{{image}}", - "alpha": "100", - "colors": { - "color0": "{{colors.background.dark.hex}}", - "color1": "{{colors.surface_container_highest.light.hex}}", - "color2": "{{colors.surface_container_lowest.light.hex}}", - "color3": "{{colors.primary.light.hex}}", - "color4": "{{colors.tertiary_fixed.default.hex}}", - "color5": "{{colors.secondary.light.hex}}", - "color6": "{{colors.on_tertiary_fixed.default.hex}}", - "color7": "{{colors.surface_dim.light.hex}}", - "color8": "{{colors.on_secondary.light.hex}}", - "color9": "{{colors.error_container.default.hex}}", - "color10": "{{colors.primary.dark.hex}}", - "color11": "{{colors.on_error_container.default.hex}}", - "color12": "{{colors.on_primary_fixed_variant.default.hex}}", - "color13": "{{colors.secondary.dark.hex}}", - "color14": "{{colors.inverse_primary.default.hex}}", - "color15": "{{colors.on_surface.dark.hex}}" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/qtct-colors.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/qtct-colors.conf deleted file mode 100644 index fba0fb7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/qtct-colors.conf +++ /dev/null @@ -1,144 +0,0 @@ -[ColorScheme] -active_colors={{colors.on_surface.default.hex}}, {{colors.surface.default.hex}}, {{colors.surface_container.default.hex}}, {{colors.outline.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.outline_variant.default.hex}}, {{colors.on_surface.default.hex}}, {{colors.on_primary.default.hex}}, {{colors.on_surface.default.hex}}, {{colors.background.default.hex}}, {{colors.background.default.hex}}, {{colors.shadow.default.hex}}, {{colors.primary.default.hex}}, {{colors.on_primary.default.hex}}, {{colors.secondary.default.hex}}, {{colors.secondary.default.hex}}, {{colors.surface_container_low.default.hex}}, {{colors.surface.default.hex}}, {{colors.surface.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}} -disabled_colors={{colors.on_surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.surface_container.default.hex}}, {{colors.outline.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.outline_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.shadow.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}} -inactive_colors={{colors.on_surface_variant.default.hex}}, {{colors.surface.default.hex}}, {{colors.surface_container.default.hex}}, {{colors.outline.default.hex}}, {{colors.surface_variant.default.hex}}, {{colors.outline_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.surface.default.hex}}, {{colors.surface.default.hex}}, {{colors.shadow.default.hex}}, {{colors.secondary.default.hex}}, {{colors.on_secondary.default.hex}}, {{colors.secondary.default.hex}}, {{colors.secondary.default.hex}}, {{colors.surface_container_low.default.hex}}, {{colors.surface.default.hex}}, {{colors.surface.default.hex}}, {{colors.on_surface_variant.default.hex}}, {{colors.on_surface_variant.default.hex}} - -[ColorEffects:Disabled] -Color={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ColorAmount=0 -ColorEffect=0 -ContrastAmount=0.65 -ContrastEffect=1 -IntensityAmount=0.1 -IntensityEffect=2 - -[ColorEffects:Inactive] -ChangeSelectionColor=true -Color={{colors.outline.default.red}},{{colors.outline.default.green}},{{colors.outline.default.blue}} -ColorAmount=0.025 -ColorEffect=2 -ContrastAmount=0.1 -ContrastEffect=2 -Enable=false -IntensityAmount=0 -IntensityEffect=0 - -[Colors:Button] -BackgroundAlternate={{colors.surface_container.default.red}},{{colors.surface_container.default.green}},{{colors.surface_container.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Complementary] -BackgroundAlternate={{colors.surface_container.default.red}},{{colors.surface_container.default.green}},{{colors.surface_container.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Header][Inactive] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Selection] -BackgroundAlternate={{colors.primary_container.default.red}},{{colors.primary_container.default.green}},{{colors.primary_container.default.blue}} -BackgroundNormal={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_primary.default.red}},{{colors.on_primary.default.green}},{{colors.on_primary.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Tooltip] -BackgroundAlternate={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -BackgroundNormal={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:View] -BackgroundAlternate={{colors.surface_container_low.default.red}},{{colors.surface_container_low.default.green}},{{colors.surface_container_low.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[Colors:Window] -BackgroundAlternate={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -BackgroundNormal={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -DecorationFocus={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -DecorationHover={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundActive={{colors.primary.default.red}},{{colors.primary.default.green}},{{colors.primary.default.blue}} -ForegroundInactive={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -ForegroundLink={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundNegative={{colors.error.default.red}},{{colors.error.default.green}},{{colors.error.default.blue}} -ForegroundNeutral={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} -ForegroundNormal={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -ForegroundPositive={{colors.tertiary.default.red}},{{colors.tertiary.default.green}},{{colors.tertiary.default.blue}} -ForegroundVisited={{colors.secondary.default.red}},{{colors.secondary.default.green}},{{colors.secondary.default.blue}} - -[WM] -activeBackground={{colors.surface.default.red}},{{colors.surface.default.green}},{{colors.surface.default.blue}} -activeBlend={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -activeForeground={{colors.on_surface.default.red}},{{colors.on_surface.default.green}},{{colors.on_surface.default.blue}} -inactiveBackground={{colors.background.default.red}},{{colors.background.default.green}},{{colors.background.default.blue}} -inactiveBlend={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} -inactiveForeground={{colors.on_surface_variant.default.red}},{{colors.on_surface_variant.default.green}},{{colors.on_surface_variant.default.blue}} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/veskto-wip.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/veskto-wip.css deleted file mode 100644 index 47f5892..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/veskto-wip.css +++ /dev/null @@ -1,242 +0,0 @@ -/** - * @name DMS - * @description Material Design 3 theme generated by DankMaterialShell - * @author DankMaterialShell - * @version 2.0.0 - * @website https://github.com/bbedward/DankMaterialShell -*/ - -* { - font-family: 'Adwaita Sans', 'Inter Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; - - --app-bg: {{colors.background.default.hex}}; - --background-primary: {{colors.background.default.hex}}; - --background-secondary: {{colors.background.default.hex}}; - --background-secondary-alt: {{colors.background.default.hex}}; - --background-tertiary: {{colors.background.default.hex}}; - - --primary-500: {{colors.background.default.hex}}; - --primary-600: {{colors.background.default.hex}}; - --primary-630: {{colors.background.default.hex}}; - --primary-645: {{colors.background.default.hex}}; - --primary-660: {{colors.background.default.hex}}; - --primary-700: {{colors.background.default.hex}}; - - --channeltextarea-background: {{colors.background.default.hex}}; - --custom-channel-members-bg: {{colors.background.default.hex}}; - - --sidebar-background: {{colors.background.default.hex}}; - --sidebar-color: {{colors.background.default.hex}}; - --server-container: {{colors.background.default.hex}}; - --main-color: {{colors.background.default.hex}}; - --main-content-color: {{colors.background.default.hex}}; - - --profile-gradient-primary-color: {{colors.background.default.hex}}; - --profile-gradient-secondary-color: {{colors.background.default.hex}}; - --profile-body-background-color: {{colors.background.default.hex}}; - --bg-overlay-1: {{colors.background.default.hex}}; - --bg-overlay-2: {{colors.background.default.hex}}; - --bg-overlay-3: {{colors.background.default.hex}}; - --home-background: {{colors.background.default.hex}}; - - --__header-bar-background: {{colors.background.default.hex}} !important; - --header-secondary: {{colors.background.default.hex}}; - --channel-header-bg: {{colors.background.default.hex}}; - --__channel-header-background: {{colors.background.default.hex}} !important; - - --bg-base-tertiary: {{colors.background.default.hex}}; - - --card-primary-bg: {{colors.surface_container.default.hex}}; - --input-background: {{colors.surface_container.default.hex}}; - --autocomplete-bg: {{colors.surface_container.default.hex}}; - --background-nested-floating: {{colors.surface_container.default.hex}}; - --background-floating: {{colors.surface_container.default.hex}}; - --scrollbar-auto-track: {{colors.surface_container.default.hex}}; - --scrollbar-thin-track: {{colors.surface_container.default.hex}}; - - --border-subtle: {{colors.background.default.hex}}; - --background-base-lowest: {{colors.background.default.hex}}; - --background-surface-high: {{colors.background.default.hex}}; - - --button-secondary-background: {{colors.surface_container_high.default.hex}}; - --background-surface-higher: {{colors.surface_container_high.default.hex}}; - --background-base-lower: {{colors.surface_container_high.default.hex}}; - - --background-message-hover: color-mix(in srgb, {{colors.on_surface.default.hex}} 4%, transparent); - --button-secondary-background-hover: {{colors.surface_container_highest.default.hex}}; - --background-base-low: {{colors.surface_container_highest.default.hex}}; - --background-surface-highest: {{colors.surface_container_highest.default.hex}}; - --chat-background-default: {{colors.surface_container_highest.default.hex}}; - - --button-secondary-background-active: color-mix(in srgb, {{colors.surface_container_highest.default.hex}}, {{colors.primary.default.hex}} 20%); - - --scrollbar-auto-thumb: {{colors.outline.default.hex}}; - --scrollbar-thin-thumb: {{colors.outline.default.hex}}; - --interactive-muted: {{colors.outline.default.hex}}; - --text-muted: {{colors.outline.default.hex}}; - --background-modifier-hover: {{colors.surface_container_high.default.hex}}; - --background-modifier-active: {{colors.surface_container_highest.default.hex}}; - --background-modifier-accent: color-mix(in srgb, {{colors.primary.default.hex}} 12%, transparent); - --background-accent: color-mix(in srgb, {{colors.primary.default.hex}} 12%, transparent); - --background-mentioned: color-mix(in srgb, {{colors.primary.default.hex}} 8%, transparent); - --background-mentioned-hover: color-mix(in srgb, {{colors.primary.default.hex}} 12%, transparent); - --mention-foreground: {{colors.primary.default.hex}}; - --info-warning-foreground: {{colors.primary.default.hex}}; - - --input-border: {{colors.outline_variant.default.hex}}; - --border-normal: {{colors.outline_variant.default.hex}}; - --icon-secondary: {{colors.on_surface_variant.default.hex}}; - --icon-tertiary: {{colors.on_surface_variant.default.hex}}; - --channel-icon: {{colors.on_surface_variant.default.hex}}; - --channels-default: {{colors.on_surface_variant.default.hex}}; - --header-primary: {{colors.on_surface.default.hex}}; - --__lottieIconColor: {{colors.on_surface_variant.default.hex}}; - --interactive-normal: {{colors.on_surface_variant.default.hex}}; - - --red-400: {{colors.error.default.hex}}; - --background-modifier-selected: color-mix(in srgb, {{colors.primary.default.hex}} 15%, transparent); - - --notice-background-positive: {{colors.primary_container.default.hex}}; - --notice-text-positive: {{colors.on_primary_container.default.hex}}; - - --status-danger: {{colors.error.default.hex}}; - --button-outline-danger-border: {{colors.error.default.hex}}; - --button-outline-danger-text: {{colors.error.default.hex}}; - --button-danger-background: {{colors.error.default.hex}}; - - --yellow-300: {{colors.tertiary.default.hex}}; - - --brand-experiment: {{colors.primary.default.hex}}; - --brand-experiment-360: {{colors.primary.default.hex}}; - --brand-experiment-500: {{colors.primary.default.hex}}; - --profile-gradient-button-color: {{colors.primary.default.hex}}; - - --green-360: {{colors.primary.default.hex}}; - - --text-normal: {{colors.on_surface.default.hex}}; - --text-link: {{colors.primary.default.hex}}; - --interactive-active: {{colors.on_surface.default.hex}}; -} - -rect[fill="#d83a41"] { - fill: {{colors.error.default.hex}} !important; -} - -rect[fill="#cc954c"] { - fill: {{colors.tertiary.default.hex}} !important; -} - -rect[fill="#40a258"] { - fill: {{colors.primary.default.hex}} !important; -} - -[class*="repliedTextContent"], -[class*="repliedMessage"] [class*="username"], -[class*="repliedMessage"] [class*="repliedTextPreview"] { - color: {{colors.on_surface_variant.default.hex}} !important; - opacity: 0.9 !important; -} - -.guilds__5e434, -.scroller_ef3116 { - background: {{colors.surface.default.hex}} !important; -} - -.sidebarList__5e434, -.container__2637a, -.scroller__629e4 { - background: {{colors.surface.default.hex}} !important; -} - -.container_c8ffbb, -.members_c8ffbb, -.member_c8ffbb, -.membersWrap_c8ffbb { - background: {{colors.surface.default.hex}} !important; - background-image: none !important; -} - -.chatContent_f75fb0, -.messagesWrapper__36d07, -.chatGradient__36d07 { - background: {{colors.surface.default.hex}} !important; - background-image: none !important; -} - -.subtitleContainer_f75fb0, -.title_f75fb0, -.container__9293f, -.headerBar__8a7fc, -.title_c38106 { - background: {{colors.surface.default.hex}} !important; -} - -.panels__5e434 { - background: {{colors.surface_container.default.hex}} !important; -} - -.channelTextArea_f75fb0, -.form_f75fb0, -.wrapper__44df5, -.channelBottomBarArea_f75fb0, -.attachWrapper__0923f, -.themedBackground__74017, -.stackedBars__74017 { - background: {{colors.surface_container.default.hex}} !important; - background-image: none !important; -} - -.slateTextArea_ec4baf { - background: {{colors.surface_container.default.hex}} !important; - color: {{colors.on_surface.default.hex}} !important; -} - -.slateTextArea_ec4baf [data-slate-placeholder], -.slateTextArea_ec4baf [data-slate-node], -.slateTextArea_ec4baf span[data-slate-zero-width], -[data-slate-placeholder], -[class*="placeholder"], -[class*="slateTextArea"] [class*="placeholder"] { - color: {{colors.on_surface_variant.default.hex}} !important; - opacity: 0.7 !important; -} - -.message__5126c::before, -.mentioned__5126c::before, -.replying__5126c::before, -.ephemeral__5126c::before { - background: none !important; - background-image: none !important; -} - -[class*="mention"][class*="channel"], -a[href*="/channels/"][class*="mention"] { - color: {{colors.primary.default.hex}} !important; - background: {{colors.surface_container_high.default.hex}} !important; -} - -[class*="numberBadge"], -[class*="mentionsBadge"] { - background-color: {{colors.primary.default.hex}} !important; - color: {{colors.on_primary.default.hex}} !important; -} - -.newMessagesBar__0f481 { - background-color: {{colors.primary.default.hex}} !important; - color: {{colors.on_primary.default.hex}} !important; -} - -.divider__908e2 { - border-color: {{colors.primary.default.hex}} !important; -} - -[class*="channel"]:not([class*="muted"]) [class*="name"], -[class*="channel"]:not([class*="muted"]) [class*="link"] { - color: {{colors.on_surface.default.hex}} !important; -} - -[class*="channel"][class*="muted"] [class*="name"], -[class*="channel"][class*="muted"] [class*="link"] { - color: {{colors.on_surface_variant.default.hex}} !important; - opacity: 0.6 !important; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop-base.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop-base.css deleted file mode 100644 index 3890a45..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop-base.css +++ /dev/null @@ -1,217 +0,0 @@ -/** - * @name DMS Discord Base CSS - * @author DMS Team - * @version 3.0.0 - * @description Minimal Discord color theme - stock layout with DMS colors - * @source https://github.com/yourusername/dankdots -*/ - -body { - --font-primary: var(--font), 'gg sans'; - --font-display: var(--font), 'gg sans'; - --font-code: var(--code-font), 'gg mono'; -} - -@property --colors { - syntax: 'off | on'; - inherits: false; - initial-value: on; -} - -@container root style(--colors: on) { - .visual-refresh body, - .visual-refresh .theme-dark:not(.custom-user-profile-theme), - .visual-refresh .theme-light:not(.custom-user-profile-theme) { - --activity-card-background: var(--bg-3); - --autocomplete-bg: var(--bg-3); - --background-accent: var(--bg-4); - --background-floating: var(--bg-3); - --background-nested-floating: var(--bg-2); - --background-mentioned: color-mix(in srgb, var(--accent-2), transparent 90%); - --background-mentioned-hover: color-mix(in srgb, var(--accent-2), transparent 85%); - --background-message-highlight: color-mix(in srgb, var(--text-3), transparent 95%); - --background-message-highlight-hover: color-mix(in srgb, var(--text-3), transparent 92%); - --background-message-hover: var(--message-hover); - --background-primary: var(--bg-2); - --background-secondary: var(--bg-3); - --background-secondary-alt: var(--bg-3); - --background-tertiary: var(--bg-2); - --bg-base-primary: var(--bg-2); - --bg-base-secondary: var(--bg-2); - --bg-base-tertiary: var(--bg-3); - --background-mod-subtle: var(--hover); - --background-mod-normal: var(--active); - --background-mod-strong: var(--active-2); - --background-base-low: var(--bg-2); - --background-base-lower: var(--bg-2); - --background-base-lowest: var(--bg-2); - --background-surface-high: var(--bg-3); - --background-surface-higher: var(--bg-4); - --background-surface-highest: var(--bg-4); - --bg-surface-overlay: var(--bg-2); - --bg-surface-raised: var(--bg-3); - --chat-background-default: var(--bg-3); - --chat-text-muted: var(--text-5); - --input-background: var(--bg-3); - --modal-background: var(--bg-2); - --modal-footer-background: var(--bg-2); - --background-modifier-accent: var(--hover); - --background-modifier-active: var(--active); - --background-modifier-hover: var(--hover); - --background-modifier-selected: var(--active); - --bg-mod-faint: var(--hover); - --bg-mod-subtle: var(--bg-3); - --bg-mod-strong: var(--bg-3); - --bg-brand: var(--accent-2); - --border-faint: transparent; - --border-subtle: transparent; - --border-normal: transparent; - --border-strong: transparent; - --input-border: transparent; - --button-danger-background: var(--red-3); - --button-danger-background-active: var(--red-5); - --button-danger-background-hover: var(--red-4); - --button-danger-background-disabled: var(--red-5); - --button-danger-border: transparent; - --button-filled-brand-text: var(--text-0); - --button-filled-brand-background: var(--accent-3); - --button-filled-brand-background-active: var(--accent-5); - --button-filled-brand-background-hover: var(--accent-4); - --button-filled-brand-border: transparent; - --button-filled-brand-inverted-background: var(--text-1); - --button-filled-brand-inverted-background-active: var(--text-3); - --button-filled-brand-inverted-background-hover: var(--text-2); - --button-filled-brand-inverted-text: var(--bg-1); - --button-filled-white-background: var(--text-1); - --button-filled-white-background-active: var(--text-3); - --button-filled-white-background-hover: var(--text-2); - --button-filled-white-text: var(--bg-1); - --button-outline-danger-background: var(--bg-3); - --button-outline-danger-background-active: var(--text-5); - --button-outline-danger-background-hover: var(--bg-2); - --button-outline-danger-border: transparent; - --button-outline-danger-border-active: transparent; - --button-outline-danger-border-hover: transparent; - --button-outline-danger-text: var(--red-1); - --button-outline-danger-text-active: var(--red-1); - --button-outline-danger-text-hover: var(--red-1); - --button-outline-primary-background: transparent; - --button-outline-primary-background-active: var(--active); - --button-outline-primary-background-hover: var(--hover); - --button-outline-primary-border: transparent; - --button-outline-primary-border-active: transparent; - --button-outline-primary-border-hover: transparent; - --button-outline-primary-text: var(--text-3); - --button-outline-primary-text-active: var(--text-3); - --button-outline-primary-text-hover: var(--text-3); - --button-positive-background: var(--green-2); - --button-positive-background-active: var(--green-4); - --button-positive-background-hover: var(--green-3); - --button-positive-background-disabled: var(--green-4); - --button-positive-border: transparent; - --button-secondary-background: var(--bg-4); - --button-secondary-background-active: var(--text-5); - --button-secondary-background-hover: var(--bg-3); - --button-secondary-background-disabled: var(--bg-3); - --button-secondary-text: var(--text-3); - --button-transparent-background: var(--hover); - --button-transparent-background-active: var(--active-2); - --button-transparent-background-hover: var(--active); - --button-transparent-text: var(--text-3); - --redesign-button-secondary-text: var(--text-3); - --card-primary-bg: var(--bg-3); - --card-secondary-bg: var(--bg-4); - --channel-icon: var(--text-4); - --channels-default: var(--text-4); - --embed-title: var(--text-2); - --header-primary: var(--text-2); - --header-secondary: var(--text-4); - --header-muted: var(--text-4); - --icon-muted: var(--text-5); - --icon-primary: var(--text-3); - --icon-secondary: var(--text-4); - --icon-tertiary: var(--text-4); - --text-brand: var(--accent-1); - --text-danger: var(--red-1); - --text-link: var(--accent-1); - --text-low-contrast: var(--text-4); - --text-muted: var(--text-5); - --text-muted-on-default: var(--text-4); - --text-normal: var(--text-3); - --text-positive: var(--green-1); - --text-primary: var(--text-3); - --text-secondary: var(--text-4); - --text-warning: var(--yellow-1); - --text-default: var(--text-3); - --text-tertiary: var(--text-4); - --user-profile-overlay-background: var(--bg-2); - --user-profile-overlay-background-hover: var(--bg-4); - --status-danger: var(--red-2); - --status-danger-background: var(--red-3); - --status-danger-text: var(--white); - --status-dnd: var(--dnd); - --status-idle: var(--idle); - --status-offline: var(--offline); - --status-online: var(--online); - --status-positive: var(--green-2); - --status-positive-background: var(--green-2); - --status-positive-text: var(--white); - --status-speaking: var(--green-2); - --status-warning: var(--yellow-2); - --interactive-normal: var(--text-4); - --interactive-hover: var(--text-3); - --interactive-active: var(--text-3); - --interactive-muted: var(--text-5); - --mention-foreground: var(--accent-1); - --mention-background: color-mix(in srgb, var(--accent-2), transparent 90%); - --channel-text-area-placeholder: var(--text-5); - --message-reacted-text: var(--text-2); - --message-reacted-background: color-mix(in srgb, var(--accent-2), transparent 90%); - --custom-channel-members-bg: var(--bg-2); - --redesign-input-control-selected: var(--accent-2); - --scrollbar-auto-thumb: var(--bg-4); - --scrollbar-auto-track: transparent; - --scrollbar-thin-thumb: var(--bg-4); - --scrollbar-thin-track: transparent; - --white: var(--text-0); - --white-500: var(--text-0); - --redesign-button-overlay-alpha-text: var(--text-2); - --brand-360: var(--accent-2); - --brand-500: var(--accent-2); - --blurple-50: var(--accent-2); - --red-400: var(--red-2); - --red-500: var(--red-3); - --green-360: var(--green-2); - --primary-400: var(--text-4); - --deprecated-text-input-bg: var(--bg-3); - --deprecated-text-input-border: transparent; - --background-code: var(--bg-3); - } - - .visual-refresh { - .bg__960e4 { background: var(--bg-1); } - .base_c48ade { background: var(--bg-1); } - .colorPickerSwatch__459fb[style*="rgb(88, 101, 242)"], - .newBadge_faa96b, - .mentioned__5126c:before { background-color: var(--accent-2) !important; } - .botTagRegular__82f07 { background-color: var(--accent-2); } - .container__87bf1.checked__87bf1 { background-color: var(--accent-2) !important; } - .container__87bf1.checked__87bf1 .slider__87bf1 > svg > path { fill: var(--accent-2) !important; } - .newMessagesBar__0f481 { background-color: var(--accent-3); } - .barFill_a562c8 { background-color: var(--accent-2) !important; } - ::selection, - .highlight { background: var(--accent-3); color: var(--text-0); } - rect[fill='#82838b'] { fill: var(--offline); } - .status_a423bd[style='background-color: rgb(130, 131, 139);'] { background-color: var(--offline) !important; } - rect[fill='#43a25a'], - path[fill='#43a25a'], - path[fill='var(--status-positive)'] { fill: var(--online); } - .status_a423bd[style='background-color: rgb(67, 162, 90);'] { background-color: var(--online) !important; } - rect[fill='#ca9654'] { fill: var(--idle); } - .status_a423bd[style='background-color: rgb(202, 150, 84);'] { background-color: var(--idle) !important; } - rect[fill='#d83a42'] { fill: var(--dnd); } - .status_a423bd[style='background-color: rgb(216, 58, 66);'] { background-color: var(--dnd) !important; } - rect[fill='#9147ff'] { fill: var(--streaming); } - div[style*='background-color: rgb(67, 162, 90)'] { background-color: var(--online) !important; } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop.css deleted file mode 100644 index 3bc8670..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vesktop.css +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @name dms-midnight - * @description midnight-discord, generated by dms - * @author refact0r - * @version 1.6.2 - * @invite nz87hXyvcy - * @website https://github.com/refact0r/midnight-discord - * @source https://github.com/refact0r/midnight-discord/blob/master/midnight.theme.css - * @authorId 508863359777505290 - * @authorLink https://www.refact0r.dev -*/ - -/* IMPORTANT: make sure to enable dark mode in discord settings for the theme to apply properly!!! */ - -@import url('https://refact0r.github.io/midnight-discord/build/midnight.css'); - -/* customize things here */ -:root { - /* font, change to 'gg sans' for default discord font*/ - --font: 'gg sans'; - - /* top left corner text */ - --corner-text: 'Midnight'; - - /* color of status indicators and window controls */ - --online-indicator: {{colors.inverse_primary.default.hex}}; /* change to #23a55a for default green */ - --dnd-indicator: {{colors.error.default.hex}}; /* change to #f13f43 for default red */ - --idle-indicator: {{colors.tertiary_container.default.hex}}; /* change to #f0b232 for default yellow */ - --streaming-indicator: {{colors.on_primary.default.hex}}; /* change to #593695 for default purple */ - - /* accent colors */ - --accent-1: {{colors.tertiary.default.hex}}; /* links */ - --accent-2: {{colors.primary.default.hex}}; /* general unread/mention elements, some icons when active */ - --accent-3: {{colors.primary.default.hex}}; /* accent buttons */ - --accent-4: {{colors.surface_bright.default.hex}}; /* accent buttons when hovered */ - --accent-5: {{colors.primary_fixed_dim.default.hex}}; /* accent buttons when clicked */ - --mention: {{colors.surface.default.hex}}; /* mentions & mention messages */ - --mention-hover: {{colors.surface_bright.default.hex}}; /* mentions & mention messages when hovered */ - - /* text colors */ - --text-0: {{colors.surface.default.hex}}; /* text on colored elements */ - --text-1: {{colors.on_surface.default.hex}}; /* other normally white text */ - --text-2: {{colors.on_surface.default.hex}}; /* headings and important text */ - --text-3: {{colors.on_surface_variant.default.hex}}; /* normal text */ - --text-4: {{colors.on_surface_variant.default.hex}}; /* icon buttons and channels */ - --text-5: {{colors.outline.default.hex}}; /* muted channels/chats and timestamps */ - - /* background and dark colors */ - --bg-1: {{colors.surface_variant.default.hex}}; /* dark buttons when clicked */ - --bg-2: {{colors.surface_container_high.default.hex}}; /* dark buttons */ - --bg-3: {{colors.surface_container_low.default.hex}}; /* spacing, secondary elements */ - --bg-4: {{colors.surface.default.hex}}; /* main background color */ - --hover: {{colors.surface_bright.default.hex}}; /* channels and buttons when hovered */ - --active: {{colors.surface_bright.default.hex}}; /* channels and buttons when clicked or selected */ - --message-hover: {{colors.surface_bright.default.hex}}; /* messages when hovered */ - - /* amount of spacing and padding */ - --spacing: 12px; - - /* animations */ - /* ALL ANIMATIONS CAN BE DISABLED WITH REDUCED MOTION IN DISCORD SETTINGS */ - --list-item-transition: 0.2s ease; /* channels/members/settings hover transition */ - --unread-bar-transition: 0.2s ease; /* unread bar moving into view transition */ - --moon-spin-transition: 0.4s ease; /* moon icon spin */ - --icon-spin-transition: 1s ease; /* round icon button spin (settings, emoji, etc.) */ - - /* corner roundness (border-radius) */ - --roundness-xl: 22px; /* roundness of big panel outer corners */ - --roundness-l: 20px; /* popout panels */ - --roundness-m: 16px; /* smaller panels, images, embeds */ - --roundness-s: 12px; /* members, settings inputs */ - --roundness-xs: 10px; /* channels, buttons */ - --roundness-xxs: 8px; /* searchbar, small elements */ - - /* direct messages moon icon */ - /* change to block to show, none to hide */ - --discord-icon: none; /* discord icon */ - --moon-icon: block; /* moon icon */ - --moon-icon-url: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/Font_Awesome_5_solid_moon.svg'); /* custom icon url */ - --moon-icon-size: auto; - - /* filter uncolorable elements to fit theme */ - /* (just set to none, they're too much work to configure) */ - --login-bg-filter: saturate(0.3) hue-rotate(-15deg) brightness(0.4); /* login background artwork */ - --green-to-accent-3-filter: hue-rotate(56deg) saturate(1.43); /* add friend page explore icon */ - --blurple-to-accent-3-filter: hue-rotate(304deg) saturate(0.84) brightness(1.2); /* add friend page school icon */ -} - -/* Selected chat/friend text */ -.selected_f5eb4b, -.selected_f6f816 .link_d8bfb3 { - color: var(--text-0) !important; - background: var(--accent-3) !important; -} - -.selected_f6f816 .link_d8bfb3 * { - color: var(--text-0) !important; - fill: var(--text-0) !important; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-dark.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-dark.json deleted file mode 100644 index da59ffe..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-dark.json +++ /dev/null @@ -1,329 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell Dark", - "semanticHighlighting": true, - "colors": { - // - // Core foreground + background hierarchy - // - "foreground": "{{colors.on_surface.dark.hex}}", - "editor.background": "{{colors.background.dark.hex}}", - "editor.foreground": "{{colors.on_surface.dark.hex}}", - "errorForeground": "{{colors.error.dark.hex}}", - // - // Borders + dividers - // - "panel.border": "{{colors.outline_variant.dark.hex}}", - "panelTitle.activeBorder": "{{colors.primary.dark.hex}}", - "sideBar.border": "{{colors.outline_variant.dark.hex}}", - "editorGroup.border": "{{colors.outline_variant.dark.hex}}", - "tab.border": "{{colors.outline_variant.dark.hex}}", - "titleBar.border": "{{colors.outline_variant.dark.hex}}", - // - // Focus + active indicators - // - "focusBorder": "{{colors.primary.dark.hex}}", - "selection.background": "{{colors.primary_container.dark.hex}}99", - // - // Title bar, activity bar, sidebar - // - "titleBar.activeBackground": "{{colors.background.dark.hex}}", - "titleBar.activeForeground": "{{colors.on_surface.dark.hex}}", - "titleBar.inactiveForeground": "{{colors.outline.dark.hex}}", - "activityBar.background": "{{colors.background.dark.hex}}", - "activityBar.foreground": "{{colors.on_surface.dark.hex}}", - "activityBar.inactiveForeground": "{{colors.outline.dark.hex}}", - "activityBar.activeBorder": "{{colors.primary.dark.hex}}", - "activityBarBadge.background": "{{colors.primary.dark.hex}}", - "activityBarBadge.foreground": "{{colors.on_primary.dark.hex}}", - "sideBar.background": "{{colors.surface_container_low.dark.hex}}", - "sideBar.foreground": "{{colors.on_surface.dark.hex}}", - "statusBarItem.hoverBackground": "{{colors.surface_container_low.dark.hex}}", - "statusBarItem.activeBackground": "{{colors.surface_container.dark.hex}}", - "sideBarTitle.foreground": "{{colors.on_surface.dark.hex}}", - "panel.background": "{{colors.surface_container_low.dark.hex}}", - "panelTitle.activeForeground": "{{colors.on_surface.dark.hex}}", - "panelTitle.inactiveForeground": "{{colors.outline.dark.hex}}", - "sideBarSectionHeader.background": "{{colors.surface_container.dark.hex}}", - "sideBarSectionHeader.foreground": "{{colors.on_surface.dark.hex}}", - // - // Tabs + editor groups - // - "editorGroupHeader.tabsBackground": "{{colors.background.dark.hex}}", - "tab.activeBackground": "{{colors.surface_container_low.dark.hex}}", - "tab.inactiveBackground": "{{colors.background.dark.hex}}", - "tab.activeForeground": "{{colors.on_surface.dark.hex}}", - "tab.inactiveForeground": "{{colors.outline.dark.hex}}", - "tab.activeBorderTop": "{{colors.primary.dark.hex}}", - // - // Lists (files, search results, etc.) - // - "list.activeSelectionBackground": "{{colors.primary.dark.hex}}", - "list.activeSelectionForeground": "{{colors.on_primary.dark.hex}}", - "list.inactiveSelectionBackground": "{{colors.surface_container.dark.hex}}", - "list.hoverBackground": "{{colors.surface_container.dark.hex}}", - "list.hoverForeground": "{{colors.on_surface.dark.hex}}", - "list.focusForeground": "{{colors.on_surface.dark.hex}}", - "list.focusOutline": "{{colors.primary.dark.hex}}", - "list.focusBackground": "{{colors.surface_container_high.dark.hex}}", - "list.highlightForeground": "{{colors.primary.dark.hex}}", - "list.focusHighlightForeground": "{{colors.on_primary.dark.hex}}", - "list.errorForeground": "{{colors.error.dark.hex}}", - "list.warningForeground": "{{colors.secondary.dark.hex}}", - // - // Inputs + dropdowns - // - "input.background": "{{colors.surface_container_low.dark.hex}}", - "input.foreground": "{{colors.on_surface.dark.hex}}", - "input.border": "{{colors.outline_variant.dark.hex}}", - "input.placeholderForeground": "{{colors.outline.dark.hex}}", - "dropdown.background": "{{colors.surface_container_low.dark.hex}}", - "dropdown.foreground": "{{colors.on_surface.dark.hex}}", - "dropdown.border": "{{colors.outline_variant.dark.hex}}", - "quickInput.background": "{{colors.surface_container_low.dark.hex}}", - "quickInput.foreground": "{{colors.on_surface.dark.hex}}", - "widget.shadow": "{{colors.background.dark.hex}}80", - // - // Buttons - // - "button.background": "{{colors.primary.dark.hex}}", - "button.foreground": "{{colors.on_primary.dark.hex}}", - "button.hoverBackground": "{{colors.primary_container.dark.hex}}", - // - // Status bar - // - "statusBar.background": "{{colors.background.dark.hex}}", - "statusBar.foreground": "{{colors.on_surface.dark.hex}}", - "statusBar.border": "{{colors.outline_variant.dark.hex}}", - "statusBar.noFolderBackground": "{{colors.background.dark.hex}}", - "statusBar.noFolderForeground": "{{colors.on_surface.dark.hex}}", - "statusBar.debuggingBackground": "{{colors.error.dark.hex}}", - "statusBar.debuggingForeground": "{{colors.on_error.dark.hex}}", - // - // Notifications - // - "notificationCenterHeader.background": "{{colors.surface_container_low.dark.hex}}", - "notificationCenterHeader.foreground": "{{colors.on_surface.dark.hex}}", - "notificationCenter.border": "{{colors.outline_variant.dark.hex}}", - "notifications.background": "{{colors.surface_container_low.dark.hex}}", - "notifications.foreground": "{{colors.on_surface.dark.hex}}", - "notifications.border": "{{colors.outline_variant.dark.hex}}", - "notificationsErrorIcon.foreground": "{{colors.error.dark.hex}}", - "notificationsWarningIcon.foreground": "{{colors.secondary.dark.hex}}", - "notificationsInfoIcon.foreground": "{{colors.primary.dark.hex}}", - // - // Breadcrumbs - // - "breadcrumb.background": "{{colors.surface_container.dark.hex}}", - "breadcrumb.foreground": "{{colors.outline.dark.hex}}", - "breadcrumb.focusForeground": "{{colors.on_surface.dark.hex}}", - "breadcrumb.activeSelectionForeground": "{{colors.primary.dark.hex}}", - // - // Editor highlights + guides - // - "editorLineNumber.foreground": "{{colors.outline.dark.hex}}", - "editorLineNumber.activeForeground": "{{colors.primary.dark.hex}}", - "editorCursor.foreground": "{{colors.primary.dark.hex}}", - "editor.lineHighlightBackground": "{{colors.surface_container.dark.hex}}66", - "editor.wordHighlightBackground": "{{colors.secondary.dark.hex}}22", - "editor.wordHighlightStrongBackground": "{{colors.tertiary.dark.hex}}22", - "editor.selectionBackground": "{{colors.primary_container.dark.hex}}99", - "editor.inactiveSelectionBackground": "{{colors.primary_container.dark.hex}}33", - "editorWhitespace.foreground": "{{colors.outline.dark.hex}}66", - "editorIndentGuide.background1": "{{colors.outline.dark.hex}}33", - "editorIndentGuide.activeBackground1": "{{colors.primary.dark.hex}}99", - "editorOverviewRuler.border": "{{colors.outline_variant.dark.hex}}", - "editorOverviewRuler.errorForeground": "{{colors.error.dark.hex}}88", - "editorOverviewRuler.warningForeground": "{{colors.tertiary.dark.hex}}88", - "editorOverviewRuler.infoForeground": "{{colors.primary.dark.hex}}88", - "editorStickyScroll.background": "{{colors.background.dark.hex}}", - "editorStickyScrollHover.background": "{{colors.surface_container_low.dark.hex}}", - "editorBracketHighlight.unexpectedBracket.foreground": "{{colors.outline.dark.hex}}", - // - // Diff editor - // - "diffEditor.insertedTextBackground": "{{colors.secondary.dark.hex}}20", - "diffEditor.removedTextBackground": "{{colors.error.dark.hex}}20", - // - // Git - // - "gitDecoration.modifiedResourceForeground": "{{colors.primary.dark.hex}}", - "gitDecoration.addedResourceForeground": "{{colors.secondary.dark.hex}}", - "gitDecoration.deletedResourceForeground": "{{colors.error.dark.hex}}", - "gitDecoration.ignoredResourceForeground": "{{colors.outline.dark.hex}}", - // - // Peek, Hover, Widgets - // - "editorHoverWidget.background": "{{colors.surface_container_high.dark.hex}}", - "editorHoverWidget.border": "{{colors.outline.dark.hex}}", - "editorSuggestWidget.background": "{{colors.surface_container.dark.hex}}", - "editorSuggestWidget.foreground": "{{colors.on_surface.dark.hex}}", - "editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.dark.hex}}", - "editorSuggestWidget.highlightForeground": "{{colors.primary.dark.hex}}", - // - // Scrollbar - // - "scrollbarSlider.background": "{{colors.on_surface_variant.dark.hex}}50", - "scrollbarSlider.hoverBackground": "{{colors.on_surface_variant.dark.hex}}80", - "scrollbarSlider.activeBackground": "{{colors.on_surface_variant.dark.hex}}AA", - // - // Terminal (Dank16) - // - "terminal.background": "{{colors.background.dark.hex}}", - "terminal.foreground": "{{colors.on_surface.dark.hex}}", - "terminal.ansiBlack": "{{dank16.color0.dark.hex}}", - "terminal.ansiRed": "{{dank16.color1.dark.hex}}", - "terminal.ansiGreen": "{{dank16.color2.dark.hex}}", - "terminal.ansiYellow": "{{dank16.color3.dark.hex}}", - "terminal.ansiBlue": "{{dank16.color4.dark.hex}}", - "terminal.ansiMagenta": "{{dank16.color5.dark.hex}}", - "terminal.ansiCyan": "{{dank16.color6.dark.hex}}", - "terminal.ansiWhite": "{{dank16.color7.dark.hex}}", - "terminal.ansiBrightBlack": "{{dank16.color8.dark.hex}}", - "terminal.ansiBrightRed": "{{dank16.color9.dark.hex}}", - "terminal.ansiBrightGreen": "{{dank16.color10.dark.hex}}", - "terminal.ansiBrightYellow": "{{dank16.color11.dark.hex}}", - "terminal.ansiBrightBlue": "{{dank16.color12.dark.hex}}", - "terminal.ansiBrightMagenta": "{{dank16.color13.dark.hex}}", - "terminal.ansiBrightCyan": "{{dank16.color14.dark.hex}}", - "terminal.ansiBrightWhite": "{{dank16.color15.dark.hex}}", - "terminal.selectionBackground": "{{colors.primary_container.dark.hex}}99" - }, - // - // Token colors - // - "tokenColors": [ - { - "scope": ["comment"], - "settings": { - "foreground": "{{dank16.color8.dark.hex}}" - } - }, - { - "scope": ["keyword"], - "settings": { - "foreground": "{{dank16.color6.dark.hex}}" - } - }, - { - "scope": ["string"], - "settings": { - "foreground": "{{dank16.color3.dark.hex}}" - } - }, - { - "scope": ["constant", "constant.language", "constant.numeric"], - "settings": { - "foreground": "{{dank16.color12.dark.hex}}" - } - }, - { - "scope": ["variable"], - "settings": { - "foreground": "{{dank16.color15.dark.hex}}" - } - }, - { - "scope": ["entity.name.function"], - "settings": { - "foreground": "{{dank16.color2.dark.hex}}" - } - }, - { - "scope": ["entity.name.class", "support.type"], - "settings": { - "foreground": "{{dank16.color12.dark.hex}}" - } - }, - { - "scope": ["invalid"], - "settings": { - "foreground": "{{colors.error.dark.hex}}" - } - }, - { - "scope": ["markup.heading"], - "settings": { - "foreground": "{{colors.primary.dark.hex}}", - "fontStyle": "bold" - } - }, - { - "scope": ["entity.name.tag.yaml", "punctuation.definition.block.sequence.item.yaml"], - "settings": { - "foreground": "{{colors.on_surface.dark.hex}}" - } - }, - { - "scope": ["source.yaml string.unquoted", "source.yaml string.quoted"], - "settings": { - "foreground": "{{dank16.color3.dark.hex}}" - } - }, - { - "scope": ["constant.language.boolean.yaml", "constant.language.null.yaml"], - "settings": { - "foreground": "{{dank16.color12.dark.hex}}" - } - }, - { - "scope": ["punctuation.separator.key-value.mapping.yaml"], - "settings": { - "foreground": "{{colors.on_surface.dark.hex}}" - } - }, - { - "scope": ["entity.name.tag.toml", "support.type.property-name.toml"], - "settings": { - "foreground": "{{colors.on_surface.dark.hex}}" - } - }, - { - "scope": ["string.quoted.single.basic.line.toml", "string.quoted.double.basic.line.toml"], - "settings": { - "foreground": "{{dank16.color3.dark.hex}}" - } - }, - { - "scope": ["constant.language.boolean.toml", "constant.numeric.toml"], - "settings": { - "foreground": "{{dank16.color12.dark.hex}}" - } - }, - { - "scope": ["meta.object-literal.key", "support.type.property-name.json"], - "settings": { - "foreground": "{{colors.on_surface.dark.hex}}" - } - } - ], - // - // Semantic tokens - // - "semanticTokenColors": { - "variable": { - "foreground": "{{dank16.color15.dark.hex}}" - }, - "parameter": { - "foreground": "{{dank16.color7.dark.hex}}" - }, - "property": { - "foreground": "{{dank16.color4.dark.hex}}" - }, - "function": { - "foreground": "{{dank16.color2.dark.hex}}" - }, - "string": { - "foreground": "{{dank16.color3.dark.hex}}" - }, - "number": { - "foreground": "{{dank16.color12.dark.hex}}" - }, - "keyword": { - "foreground": "{{dank16.color6.dark.hex}}" - }, - "comment": { - "foreground": "{{dank16.color8.dark.hex}}" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-default.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-default.json deleted file mode 100644 index 3ba2522..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-default.json +++ /dev/null @@ -1,281 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell", - "semanticHighlighting": true, - "colors": { - "foreground": "{{colors.on_surface.default.hex}}", - "editor.background": "{{colors.background.default.hex}}", - "editor.foreground": "{{colors.on_surface.default.hex}}", - "errorForeground": "{{colors.error.default.hex}}", - "panel.border": "{{colors.outline_variant.default.hex}}", - "panelTitle.activeBorder": "{{colors.primary.default.hex}}", - "sideBar.border": "{{colors.outline_variant.default.hex}}", - "editorGroup.border": "{{colors.outline_variant.default.hex}}", - "tab.border": "{{colors.outline_variant.default.hex}}", - "titleBar.border": "{{colors.outline_variant.default.hex}}", - "focusBorder": "{{colors.primary.default.hex}}", - "selection.background": "{{colors.primary_container.default.hex}}99", - "titleBar.activeBackground": "{{colors.background.default.hex}}", - "titleBar.activeForeground": "{{colors.on_surface.default.hex}}", - "titleBar.inactiveForeground": "{{colors.outline.default.hex}}", - "activityBar.background": "{{colors.background.default.hex}}", - "activityBar.foreground": "{{colors.on_surface.default.hex}}", - "activityBar.inactiveForeground": "{{colors.outline.default.hex}}", - "activityBar.activeBorder": "{{colors.primary.default.hex}}", - "activityBarBadge.background": "{{colors.primary.default.hex}}", - "activityBarBadge.foreground": "{{colors.on_primary.default.hex}}", - "sideBar.background": "{{colors.surface_container_low.default.hex}}", - "sideBar.foreground": "{{colors.on_surface.default.hex}}", - "statusBarItem.hoverBackground": "{{colors.surface_container_low.default.hex}}", - "statusBarItem.activeBackground": "{{colors.surface_container.default.hex}}", - "sideBarTitle.foreground": "{{colors.on_surface.default.hex}}", - "panel.background": "{{colors.surface_container_low.default.hex}}", - "panelTitle.activeForeground": "{{colors.on_surface.default.hex}}", - "panelTitle.inactiveForeground": "{{colors.outline.default.hex}}", - "sideBarSectionHeader.background": "{{colors.surface_container.default.hex}}", - "sideBarSectionHeader.foreground": "{{colors.on_surface.default.hex}}", - "editorGroupHeader.tabsBackground": "{{colors.background.default.hex}}", - "tab.activeBackground": "{{colors.surface_container_low.default.hex}}", - "tab.inactiveBackground": "{{colors.background.default.hex}}", - "tab.activeForeground": "{{colors.on_surface.default.hex}}", - "tab.inactiveForeground": "{{colors.outline.default.hex}}", - "tab.activeBorderTop": "{{colors.primary.default.hex}}", - "list.activeSelectionBackground": "{{colors.primary.default.hex}}", - "list.activeSelectionForeground": "{{colors.on_primary.default.hex}}", - "list.inactiveSelectionBackground": "{{colors.surface_container.default.hex}}", - "list.hoverBackground": "{{colors.surface_container.default.hex}}", - "list.hoverForeground": "{{colors.on_surface.default.hex}}", - "list.focusForeground": "{{colors.on_surface.default.hex}}", - "list.focusOutline": "{{colors.primary.default.hex}}", - "list.focusBackground": "{{colors.surface_container_high.default.hex}}", - "list.highlightForeground": "{{colors.primary.default.hex}}", - "list.focusHighlightForeground": "{{colors.on_primary.default.hex}}", - "list.errorForeground": "{{colors.error.default.hex}}", - "list.warningForeground": "{{colors.secondary.default.hex}}", - "input.background": "{{colors.surface_container_low.default.hex}}", - "input.foreground": "{{colors.on_surface.default.hex}}", - "input.border": "{{colors.outline_variant.default.hex}}", - "input.placeholderForeground": "{{colors.outline.default.hex}}", - "dropdown.background": "{{colors.surface_container_low.default.hex}}", - "dropdown.foreground": "{{colors.on_surface.default.hex}}", - "dropdown.border": "{{colors.outline_variant.default.hex}}", - "quickInput.background": "{{colors.surface_container_low.default.hex}}", - "quickInput.foreground": "{{colors.on_surface.default.hex}}", - "widget.shadow": "{{colors.background.default.hex}}80", - "button.background": "{{colors.primary.default.hex}}", - "button.foreground": "{{colors.on_primary.default.hex}}", - "button.hoverBackground": "{{colors.primary_container.default.hex}}", - "statusBar.background": "{{colors.background.default.hex}}", - "statusBar.foreground": "{{colors.on_surface.default.hex}}", - "statusBar.border": "{{colors.outline_variant.default.hex}}", - "statusBar.noFolderBackground": "{{colors.background.default.hex}}", - "statusBar.noFolderForeground": "{{colors.on_surface.default.hex}}", - "statusBar.debuggingBackground": "{{colors.error.default.hex}}", - "statusBar.debuggingForeground": "{{colors.on_error.default.hex}}", - "notificationCenterHeader.background": "{{colors.surface_container_low.default.hex}}", - "notificationCenterHeader.foreground": "{{colors.on_surface.default.hex}}", - "notificationCenter.border": "{{colors.outline_variant.default.hex}}", - "notifications.background": "{{colors.surface_container_low.default.hex}}", - "notifications.foreground": "{{colors.on_surface.default.hex}}", - "notifications.border": "{{colors.outline_variant.default.hex}}", - "notificationsErrorIcon.foreground": "{{colors.error.default.hex}}", - "notificationsWarningIcon.foreground": "{{colors.secondary.default.hex}}", - "notificationsInfoIcon.foreground": "{{colors.primary.default.hex}}", - "breadcrumb.background": "{{colors.surface_container.default.hex}}", - "breadcrumb.foreground": "{{colors.outline.default.hex}}", - "breadcrumb.focusForeground": "{{colors.on_surface.default.hex}}", - "breadcrumb.activeSelectionForeground": "{{colors.primary.default.hex}}", - "editorLineNumber.foreground": "{{colors.outline.default.hex}}", - "editorLineNumber.activeForeground": "{{colors.primary.default.hex}}", - "editorCursor.foreground": "{{colors.primary.default.hex}}", - "editor.lineHighlightBackground": "{{colors.surface_container.default.hex}}66", - "editor.wordHighlightBackground": "{{colors.secondary.default.hex}}22", - "editor.wordHighlightStrongBackground": "{{colors.tertiary.default.hex}}22", - "editor.selectionBackground": "{{colors.primary_container.default.hex}}99", - "editor.inactiveSelectionBackground": "{{colors.primary_container.default.hex}}33", - "editorWhitespace.foreground": "{{colors.outline.default.hex}}66", - "editorIndentGuide.background1": "{{colors.outline.default.hex}}33", - "editorIndentGuide.activeBackground1": "{{colors.primary.default.hex}}99", - "editorOverviewRuler.border": "{{colors.outline_variant.default.hex}}", - "editorOverviewRuler.errorForeground": "{{colors.error.default.hex}}88", - "editorOverviewRuler.warningForeground": "{{colors.tertiary.default.hex}}88", - "editorOverviewRuler.infoForeground": "{{colors.primary.default.hex}}88", - "editorStickyScroll.background": "{{colors.background.default.hex}}", - "editorStickyScrollHover.background": "{{colors.surface_container_low.default.hex}}", - "editorBracketHighlight.unexpectedBracket.foreground": "{{colors.outline.default.hex}}", - "diffEditor.insertedTextBackground": "{{colors.secondary.default.hex}}20", - "diffEditor.removedTextBackground": "{{colors.error.default.hex}}20", - "gitDecoration.modifiedResourceForeground": "{{colors.primary.default.hex}}", - "gitDecoration.addedResourceForeground": "{{colors.secondary.default.hex}}", - "gitDecoration.deletedResourceForeground": "{{colors.error.default.hex}}", - "gitDecoration.ignoredResourceForeground": "{{colors.outline.default.hex}}", - "editorHoverWidget.background": "{{colors.surface_container_high.default.hex}}", - "editorHoverWidget.border": "{{colors.outline.default.hex}}", - "editorSuggestWidget.background": "{{colors.surface_container.default.hex}}", - "editorSuggestWidget.foreground": "{{colors.on_surface.default.hex}}", - "editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.default.hex}}", - "editorSuggestWidget.highlightForeground": "{{colors.primary.default.hex}}", - "scrollbarSlider.background": "{{colors.on_surface_variant.default.hex}}50", - "scrollbarSlider.hoverBackground": "{{colors.on_surface_variant.default.hex}}80", - "scrollbarSlider.activeBackground": "{{colors.on_surface_variant.default.hex}}AA", - "terminal.background": "{{colors.background.default.hex}}", - "terminal.foreground": "{{colors.on_surface.default.hex}}", - "terminal.ansiBlack": "{{dank16.color0.default.hex}}", - "terminal.ansiRed": "{{dank16.color1.default.hex}}", - "terminal.ansiGreen": "{{dank16.color2.default.hex}}", - "terminal.ansiYellow": "{{dank16.color3.default.hex}}", - "terminal.ansiBlue": "{{dank16.color4.default.hex}}", - "terminal.ansiMagenta": "{{dank16.color5.default.hex}}", - "terminal.ansiCyan": "{{dank16.color6.default.hex}}", - "terminal.ansiWhite": "{{dank16.color7.default.hex}}", - "terminal.ansiBrightBlack": "{{dank16.color8.default.hex}}", - "terminal.ansiBrightRed": "{{dank16.color9.default.hex}}", - "terminal.ansiBrightGreen": "{{dank16.color10.default.hex}}", - "terminal.ansiBrightYellow": "{{dank16.color11.default.hex}}", - "terminal.ansiBrightBlue": "{{dank16.color12.default.hex}}", - "terminal.ansiBrightMagenta": "{{dank16.color13.default.hex}}", - "terminal.ansiBrightCyan": "{{dank16.color14.default.hex}}", - "terminal.ansiBrightWhite": "{{dank16.color15.default.hex}}", - "terminal.selectionBackground": "{{colors.primary_container.default.hex}}99" - }, - "tokenColors": [ - { - "scope": ["comment"], - "settings": { - "foreground": "{{colors.outline.default.hex}}" - } - }, - { - "scope": ["keyword"], - "settings": { - "foreground": "{{dank16.color6.default.hex}}" - } - }, - { - "scope": ["string"], - "settings": { - "foreground": "{{dank16.color2.default.hex}}" - } - }, - { - "scope": ["constant", "constant.language", "constant.numeric"], - "settings": { - "foreground": "{{dank16.color12.default.hex}}" - } - }, - { - "scope": ["variable"], - "settings": { - "foreground": "{{colors.on_surface.default.hex}}" - } - }, - { - "scope": ["entity.name.function"], - "settings": { - "foreground": "{{dank16.color4.default.hex}}" - } - }, - { - "scope": ["entity.name.class", "support.type"], - "settings": { - "foreground": "{{colors.secondary.default.hex}}" - } - }, - { - "scope": ["invalid"], - "settings": { - "foreground": "{{colors.error.default.hex}}" - } - }, - { - "scope": ["markup.heading"], - "settings": { - "foreground": "{{colors.primary.default.hex}}", - "fontStyle": "bold" - } - }, - { - "scope": ["entity.name.tag.yaml", "punctuation.definition.block.sequence.item.yaml"], - "settings": { - "foreground": "{{colors.on_surface.default.hex}}" - } - }, - { - "scope": ["source.yaml string.unquoted", "source.yaml string.quoted"], - "settings": { - "foreground": "{{dank16.color3.default.hex}}" - } - }, - { - "scope": ["constant.language.boolean.yaml", "constant.language.null.yaml"], - "settings": { - "foreground": "{{dank16.color12.default.hex}}" - } - }, - { - "scope": ["punctuation.separator.key-value.mapping.yaml"], - "settings": { - "foreground": "{{colors.on_surface.default.hex}}" - } - }, - { - "scope": ["entity.name.tag.toml", "support.type.property-name.toml"], - "settings": { - "foreground": "{{colors.on_surface.default.hex}}" - } - }, - { - "scope": ["string.quoted.single.basic.line.toml", "string.quoted.double.basic.line.toml"], - "settings": { - "foreground": "{{dank16.color2.default.hex}}" - } - }, - { - "scope": ["constant.language.boolean.toml", "constant.numeric.toml"], - "settings": { - "foreground": "{{dank16.color12.default.hex}}" - } - }, - { - "scope": ["meta.object-literal.key", "support.type.property-name.json"], - "settings": { - "foreground": "{{colors.on_surface.default.hex}}" - } - } - ], - "semanticTokenColors": { - "variable": { - "foreground": "{{colors.on_surface.default.hex}}" - }, - "parameter": { - "foreground": "{{colors.on_surface.default.hex}}" - }, - "property": { - "foreground": "{{dank16.color4.default.hex}}" - }, - "function": { - "foreground": "{{dank16.color4.default.hex}}" - }, - "method": { - "foreground": "{{dank16.color4.default.hex}}" - }, - "type": { - "foreground": "{{colors.secondary.default.hex}}" - }, - "class": { - "foreground": "{{colors.secondary.default.hex}}" - }, - "string": { - "foreground": "{{dank16.color2.default.hex}}" - }, - "number": { - "foreground": "{{dank16.color12.default.hex}}" - }, - "keyword": { - "foreground": "{{dank16.color6.default.hex}}" - }, - "comment": { - "foreground": "{{colors.outline.default.hex}}" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-light.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-light.json deleted file mode 100644 index a2b2280..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/vscode-color-theme-light.json +++ /dev/null @@ -1,456 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell Light", - "semanticHighlighting": true, - "colors": { - "foreground": "{{colors.on_surface.light.hex}}", - "selection.background": "{{colors.primary_container.light.hex}}99", - "errorForeground": "{{colors.error.light.hex}}", - "focusBorder": "{{colors.primary.light.hex}}", - "editor.background": "{{colors.background.light.hex}}", - "editor.foreground": "{{colors.on_surface.light.hex}}", - "editorLineNumber.foreground": "{{colors.outline.light.hex}}", - "editorLineNumber.activeForeground": "{{colors.primary.light.hex}}", - "editorCursor.foreground": "{{colors.primary.light.hex}}", - "editor.selectionBackground": "{{colors.primary_container.light.hex}}B3", - "editor.inactiveSelectionBackground": "{{colors.primary_container.light.hex}}33", - "editor.lineHighlightBackground": "{{colors.surface_container.light.hex}}66", - "editor.lineHighlightBorder": "{{colors.outline_variant.light.hex}}18", - "editor.wordHighlightBackground": "{{colors.secondary.light.hex}}22", - "editor.wordHighlightStrongBackground": "{{colors.tertiary.light.hex}}22", - "editor.findMatchBackground": "{{colors.secondary.light.hex}}33", - "editor.findMatchHighlightBackground": "{{colors.secondary.light.hex}}22", - "editor.findRangeHighlightBackground": "{{colors.surface_container.light.hex}}33", - "editorWhitespace.foreground": "{{colors.outline.light.hex}}66", - "editorIndentGuide.background1": "{{colors.outline.light.hex}}99", - "editorIndentGuide.activeBackground1": "{{colors.primary.light.hex}}CC", - "editorBracketMatch.background": "{{colors.primary_container.light.hex}}33", - "editorBracketMatch.border": "{{colors.primary.light.hex}}", - "editorGutter.addedBackground": "{{colors.secondary.light.hex}}AA", - "editorGutter.modifiedBackground": "{{colors.tertiary.light.hex}}AA", - "editorGutter.deletedBackground": "{{colors.error.light.hex}}AA", - "editorError.foreground": "{{colors.error.light.hex}}", - "editorWarning.foreground": "{{colors.tertiary.light.hex}}", - "editorInfo.foreground": "{{colors.primary.light.hex}}", - "editorOverviewRuler.border": "{{colors.outline_variant.light.hex}}", - "editorOverviewRuler.errorForeground": "{{colors.error.light.hex}}88", - "editorOverviewRuler.warningForeground": "{{colors.tertiary.light.hex}}88", - "editorOverviewRuler.infoForeground": "{{colors.primary.light.hex}}88", - "editorWidget.background": "{{colors.surface_container.light.hex}}", - "editorWidget.border": "{{colors.outline_variant.light.hex}}", - "editorHoverWidget.background": "{{colors.surface_container_high.light.hex}}", - "editorHoverWidget.border": "{{colors.outline.light.hex}}", - "editorSuggestWidget.background": "{{colors.surface_container.light.hex}}", - "editorSuggestWidget.foreground": "{{colors.on_surface.light.hex}}", - "editorSuggestWidget.border": "{{colors.outline_variant.light.hex}}", - "editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.light.hex}}", - "editorSuggestWidget.highlightForeground": "{{colors.primary.light.hex}}", - "editorGroup.border": "{{colors.outline_variant.light.hex}}", - "editorGroup.dropBackground": "{{colors.primary_container.light.hex}}33", - "editorGroupHeader.tabsBackground": "{{colors.background.light.hex}}", - "editorGroupHeader.noTabsBackground": "{{colors.background.light.hex}}", - "tab.border": "{{colors.outline_variant.light.hex}}", - "tab.activeBackground": "{{colors.surface_container_high.light.hex}}", - "tab.inactiveBackground": "{{colors.surface_container.light.hex}}", - "tab.activeForeground": "{{colors.on_surface.light.hex}}", - "tab.inactiveForeground": "{{colors.outline.light.hex}}", - "tab.activeBorder": "{{colors.primary.light.hex}}", - "tab.unfocusedActiveBorder": "{{colors.outline.light.hex}}", - "activityBar.background": "{{colors.background.light.hex}}", - "activityBar.foreground": "{{colors.on_surface.light.hex}}", - "activityBar.inactiveForeground": "{{colors.outline.light.hex}}", - "activityBar.activeBorder": "{{colors.primary.light.hex}}", - "activityBar.activeBackground": "{{colors.background.light.hex}}", - "activityBarBadge.background": "{{colors.primary.light.hex}}", - "activityBarBadge.foreground": "{{colors.on_primary.light.hex}}", - "sideBar.background": "{{colors.surface_container.light.hex}}", - "sideBar.foreground": "{{colors.on_surface.light.hex}}", - "sideBar.border": "{{colors.outline_variant.light.hex}}", - "sideBarTitle.foreground": "{{colors.on_surface.light.hex}}", - "sideBarSectionHeader.background": "{{colors.surface_container_low.light.hex}}", - "sideBarSectionHeader.foreground": "{{colors.on_surface.light.hex}}", - "list.activeSelectionBackground": "{{colors.primary.light.hex}}", - "list.activeSelectionForeground": "{{colors.on_primary.light.hex}}", - "list.inactiveSelectionBackground": "{{colors.surface_container.light.hex}}", - "list.inactiveSelectionForeground": "{{colors.on_surface.light.hex}}", - "list.hoverBackground": "{{colors.surface_container.light.hex}}", - "list.hoverForeground": "{{colors.on_surface.light.hex}}", - "list.focusBackground": "{{colors.surface_container_high.light.hex}}", - "list.focusForeground": "{{colors.on_surface.light.hex}}", - "list.highlightForeground": "{{colors.primary.light.hex}}", - "list.focusHighlightForeground": "{{colors.on_primary.light.hex}}", - "list.errorForeground": "{{colors.error.light.hex}}", - "list.warningForeground": "{{colors.tertiary.light.hex}}", - "statusBar.background": "{{colors.surface_container.light.hex}}", - "statusBar.foreground": "{{colors.on_surface.light.hex}}", - "statusBar.border": "{{colors.outline_variant.light.hex}}", - "statusBar.noFolderBackground": "{{colors.surface_container.light.hex}}", - "statusBar.noFolderForeground": "{{colors.on_surface.light.hex}}", - "statusBar.debuggingBackground": "{{colors.error.light.hex}}", - "statusBar.debuggingForeground": "{{colors.on_error.light.hex}}", - "titleBar.activeBackground": "{{colors.background.light.hex}}", - "titleBar.activeForeground": "{{colors.on_surface.light.hex}}", - "titleBar.inactiveBackground": "{{colors.background.light.hex}}", - "titleBar.inactiveForeground": "{{colors.outline.light.hex}}", - "titleBar.border": "{{colors.outline_variant.light.hex}}", - "input.background": "{{colors.surface_container_low.light.hex}}", - "input.foreground": "{{colors.on_surface.light.hex}}", - "input.border": "{{colors.outline_variant.light.hex}}", - "input.placeholderForeground": "{{colors.outline.light.hex}}", - "inputOption.activeBorder": "{{colors.primary.light.hex}}", - "inputValidation.errorBackground": "{{colors.error_container.light.hex}}", - "inputValidation.errorBorder": "{{colors.error.light.hex}}", - "dropdown.background": "{{colors.surface_container_low.light.hex}}", - "dropdown.foreground": "{{colors.on_surface.light.hex}}", - "dropdown.border": "{{colors.outline_variant.light.hex}}", - "quickInput.background": "{{colors.surface_container.light.hex}}", - "quickInput.foreground": "{{colors.on_surface.light.hex}}", - "quickInputList.focusBackground": "{{colors.surface_container_high.light.hex}}", - "quickInputList.focusForeground": "{{colors.on_surface.light.hex}}", - "button.background": "{{colors.primary.light.hex}}", - "button.foreground": "{{colors.on_primary.light.hex}}", - "button.hoverBackground": "{{colors.primary_container.light.hex}}", - "badge.background": "{{colors.secondary.light.hex}}", - "badge.foreground": "{{colors.on_secondary.light.hex}}", - "panel.background": "{{colors.surface_container.light.hex}}", - "panel.border": "{{colors.outline_variant.light.hex}}", - "panelTitle.activeBorder": "{{colors.primary.light.hex}}", - "panelTitle.activeForeground": "{{colors.on_surface.light.hex}}", - "panelTitle.inactiveForeground": "{{colors.outline.light.hex}}", - "terminal.background": "{{colors.background.light.hex}}", - "terminal.foreground": "{{colors.on_surface.light.hex}}", - "terminal.ansiBlack": "{{dank16.color0.light.hex}}", - "terminal.ansiRed": "{{dank16.color1.light.hex}}", - "terminal.ansiGreen": "{{dank16.color2.light.hex}}", - "terminal.ansiYellow": "{{dank16.color3.light.hex}}", - "terminal.ansiBlue": "{{dank16.color4.light.hex}}", - "terminal.ansiMagenta": "{{dank16.color5.light.hex}}", - "terminal.ansiCyan": "{{dank16.color6.light.hex}}", - "terminal.ansiWhite": "{{dank16.color7.light.hex}}", - "terminal.ansiBrightBlack": "{{dank16.color8.light.hex}}", - "terminal.ansiBrightRed": "{{dank16.color9.light.hex}}", - "terminal.ansiBrightGreen": "{{dank16.color10.light.hex}}", - "terminal.ansiBrightYellow": "{{dank16.color11.light.hex}}", - "terminal.ansiBrightBlue": "{{dank16.color12.light.hex}}", - "terminal.ansiBrightMagenta": "{{dank16.color13.light.hex}}", - "terminal.ansiBrightCyan": "{{dank16.color14.light.hex}}", - "terminal.ansiBrightWhite": "{{dank16.color15.light.hex}}", - "terminal.selectionBackground": "{{colors.primary_container.light.hex}}99", - "gitDecoration.modifiedResourceForeground": "{{colors.primary.light.hex}}", - "gitDecoration.addedResourceForeground": "{{colors.secondary.light.hex}}", - "gitDecoration.stageModifiedResourceForeground": "{{colors.primary.light.hex}}", - "gitDecoration.stageDeletedResourceForeground": "{{colors.error.light.hex}}", - "gitDecoration.deletedResourceForeground": "{{colors.error.light.hex}}", - "gitDecoration.untrackedResourceForeground": "{{colors.secondary.light.hex}}", - "gitDecoration.ignoredResourceForeground": "{{colors.outline.light.hex}}", - "gitDecoration.conflictingResourceForeground": "{{colors.error_container.light.hex}}", - "gitDecoration.submoduleResourceForeground": "{{colors.primary.light.hex}}", - "peekView.border": "{{colors.primary.light.hex}}", - "peekViewEditor.background": "{{colors.surface_container_high.light.hex}}", - "peekViewResult.background": "{{colors.surface_container.light.hex}}", - "peekViewTitle.background": "{{colors.surface_container_low.light.hex}}", - "notificationCenter.border": "{{colors.outline_variant.light.hex}}", - "notifications.background": "{{colors.surface_container.light.hex}}", - "notifications.border": "{{colors.outline_variant.light.hex}}", - "breadcrumb.background": "{{colors.surface_container_high.light.hex}}", - "breadcrumb.foreground": "{{colors.outline.light.hex}}", - "breadcrumb.focusForeground": "{{colors.on_surface.light.hex}}", - "breadcrumb.activeSelectionForeground": "{{colors.primary.light.hex}}", - "scrollbarSlider.background": "{{colors.on_surface_variant.light.hex}}50", - "scrollbarSlider.hoverBackground": "{{colors.on_surface_variant.light.hex}}80", - "scrollbarSlider.activeBackground": "{{colors.on_surface_variant.light.hex}}AA", - "menubar.selectionBackground": "{{colors.primary_container.light.hex}}", - "menubar.selectionForeground": "{{colors.on_primary_container.light.hex}}", - "menu.background": "{{colors.surface_container.light.hex}}", - "menu.foreground": "{{colors.on_surface.light.hex}}", - "menu.selectionBackground": "{{colors.primary_container.light.hex}}", - "menu.selectionForeground": "{{colors.on_primary_container.light.hex}}", - "debugToolBar.background": "{{colors.surface_container.light.hex}}", - "debugExceptionWidget.background": "{{colors.surface_container.light.hex}}", - "debugExceptionWidget.border": "{{colors.error.light.hex}}" - }, - "tokenColors": [ - { - "name": "Comments", - "scope": [ - "comment", - "punctuation.definition.comment", - "string.comment" - ], - "settings": { - "foreground": "{{colors.outline.light.hex}}" - } - }, - { - "name": "Keywords and storage", - "scope": [ - "keyword", - "punctuation.definition.keyword", - "storage", - "storage.type" - ], - "settings": { - "foreground": "{{dank16.color6.light.hex}}" - } - }, - { - "name": "Strings", - "scope": [ - "string", - "string punctuation.section.embedded source" - ], - "settings": { - "foreground": "{{dank16.color2.light.hex}}" - } - }, - { - "name": "Constants and numbers", - "scope": [ - "constant.numeric", - "constant.language", - "constant.other", - "constant.character" - ], - "settings": { - "foreground": "{{dank16.color0.light.hex}}" - } - }, - { - "name": "Variables (plain)", - "scope": [ - "variable", - "variable.other" - ], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "name": "Parameters", - "scope": [ - "variable.parameter", - "variable.parameter.function" - ], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "name": "Object properties and keys", - "scope": [ - "meta.object-literal.key", - "meta.property.object", - "variable.other.property", - "support.type.property-name.json" - ], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "scope": ["entity.name.tag.yaml", "punctuation.definition.block.sequence.item.yaml", "punctuation.separator.key-value.mapping.yaml"], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "scope": ["source.yaml string.unquoted", "source.yaml string.quoted"], - "settings": { - "foreground": "{{dank16.color3.light.hex}}" - } - }, - { - "scope": ["constant.language.boolean.yaml", "constant.language.null.yaml"], - "settings": { - "foreground": "{{dank16.color0.light.hex}}" - } - }, - { - "scope": ["entity.name.tag.toml", "support.type.property-name.toml"], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "scope": ["string.quoted.single.basic.line.toml", "string.quoted.double.basic.line.toml"], - "settings": { - "foreground": "{{dank16.color2.light.hex}}" - } - }, - { - "scope": ["constant.language.boolean.toml", "constant.numeric.toml"], - "settings": { - "foreground": "{{dank16.color0.light.hex}}" - } - }, - { - "name": "Functions", - "scope": [ - "entity.name.function", - "support.function" - ], - "settings": { - "foreground": "{{dank16.color4.light.hex}}" - } - }, - { - "name": "Types and classes", - "scope": [ - "entity.name.type", - "entity.name.class", - "support.type" - ], - "settings": { - "foreground": "{{colors.secondary.light.hex}}" - } - }, - { - "name": "Language builtins and special variables", - "scope": [ - "support.class", - "support.variable", - "variable.language", - "support.constant" - ], - "settings": { - "foreground": "{{dank16.color4.light.hex}}" - } - }, - { - "name": "Invalid", - "scope": [ - "invalid" - ], - "settings": { - "foreground": "{{colors.error.light.hex}}" - } - }, - { - "name": "Invalid deprecated", - "scope": [ - "invalid.deprecated" - ], - "settings": { - "foreground": "{{colors.outline.light.hex}}" - } - }, - { - "name": "Headings", - "scope": [ - "markup.heading", - "markup.heading entity.name" - ], - "settings": { - "foreground": "{{colors.primary.light.hex}}", - "fontStyle": "bold" - } - }, - { - "name": "Bold", - "scope": [ - "markup.bold" - ], - "settings": { - "foreground": "{{colors.tertiary.light.hex}}", - "fontStyle": "bold" - } - }, - { - "name": "Italic", - "scope": [ - "markup.italic" - ], - "settings": { - "foreground": "{{colors.primary.light.hex}}", - "fontStyle": "italic" - } - }, - { - "name": "Underline", - "scope": [ - "markup.underline" - ], - "settings": { - "fontStyle": "underline" - } - }, - { - "name": "Quotes", - "scope": [ - "markup.quote" - ], - "settings": { - "foreground": "{{colors.outline.light.hex}}" - } - }, - { - "name": "Lists", - "scope": [ - "markup.list" - ], - "settings": { - "foreground": "{{colors.on_surface.light.hex}}" - } - }, - { - "name": "Inline code in prose", - "scope": [ - "markup.raw", - "markup.inline.raw" - ], - "settings": { - "foreground": "{{dank16.color4.light.hex}}" - } - } - ], - "semanticTokenColors": { - "variable": { - "foreground": "{{colors.on_surface.light.hex}}" - }, - "variable.readonly": { - "foreground": "{{dank16.color1.light.hex}}" - }, - "parameter": { - "foreground": "{{colors.on_surface.light.hex}}" - }, - "property": { - "foreground": "{{dank16.color4.light.hex}}" - }, - "function": { - "foreground": "{{dank16.color4.light.hex}}" - }, - "method": { - "foreground": "{{dank16.color4.light.hex}}" - }, - "type": { - "foreground": "{{colors.secondary.light.hex}}" - }, - "class": { - "foreground": "{{colors.secondary.light.hex}}" - }, - "typeParameter": { - "foreground": "{{colors.tertiary.light.hex}}" - }, - "enumMember": { - "foreground": "{{dank16.color1.light.hex}}" - }, - "string": { - "foreground": "{{dank16.color2.light.hex}}" - }, - "number": { - "foreground": "{{dank16.color1.light.hex}}" - }, - "comment": { - "foreground": "{{colors.outline.light.hex}}" - }, - "keyword": { - "foreground": "{{dank16.color6.light.hex}}" - }, - "operator": { - "foreground": "{{colors.on_surface.light.hex}}" - }, - "namespace": { - "foreground": "{{colors.on_surface.light.hex}}" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/wezterm.toml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/wezterm.toml deleted file mode 100644 index 1b7d8b3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/wezterm.toml +++ /dev/null @@ -1,13 +0,0 @@ -[colors] -background = '{{colors.background.default.hex}}' -foreground = '{{colors.on_surface.default.hex}}' - -cursor_bg = '{{colors.primary.default.hex}}' -cursor_fg = '{{colors.background.default.hex}}' -cursor_border = '{{colors.primary.default.hex}}' - -selection_bg = '{{colors.primary_container.default.hex}}' -selection_fg = '{{colors.on_surface.default.hex}}' - -ansi = ['{{dank16.color0.default.hex}}', '{{dank16.color1.default.hex}}', '{{dank16.color2.default.hex}}', '{{dank16.color3.default.hex}}', '{{dank16.color4.default.hex}}', '{{dank16.color5.default.hex}}', '{{dank16.color6.default.hex}}', '{{dank16.color7.default.hex}}'] -brights = ['{{dank16.color8.default.hex}}', '{{dank16.color9.default.hex}}', '{{dank16.color10.default.hex}}', '{{dank16.color11.default.hex}}', '{{dank16.color12.default.hex}}', '{{dank16.color13.default.hex}}', '{{dank16.color14.default.hex}}', '{{dank16.color15.default.hex}}'] diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/zen-userchrome.css b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/zen-userchrome.css deleted file mode 100644 index 3dc0eba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/templates/zen-userchrome.css +++ /dev/null @@ -1,112 +0,0 @@ -/* DMS Matugen Zen Browser Theme */ -:root { - --zen-primary-color: {{colors.primary_container.default.hex}} !important; - --toolbarbutton-icon-fill: {{colors.primary.default.hex}} !important; - --toolbar-field-color: {{colors.on_background.default.hex}} !important; - --tab-selected-textcolor: {{colors.primary.default.hex}} !important; - --toolbar-color: {{colors.on_background.default.hex}} !important; - --arrowpanel-color: {{colors.on_surface.default.hex}} !important; - --arrowpanel-background: {{colors.surface_container.default.hex}} !important; - --sidebar-text-color: {{colors.on_background.default.hex}} !important; - --zen-main-browser-background: {{colors.background.default.hex}} !important; -} - -.sidebar-placesTree { - background-color: {{colors.surface_container.default.hex}} !important; -} - -#zen-workspaces-button { - background-color: {{colors.surface_container.default.hex}} !important; -} - -#TabsToolbar { - background-color: {{colors.background.default.hex}} !important; -} - -.urlbar-background { - background-color: {{colors.surface_container.default.hex}} !important; -} - -.urlbar-input::selection { - color: {{colors.on_primary.default.hex}} !important; - background-color: {{colors.primary.default.hex}} !important; -} - -.urlbarView-url { - color: {{colors.on_surface_variant.default.hex}} !important; -} - -toolbar .toolbarbutton-1 { - &:not([disabled]) { - &:is([open], [checked]) - > :is( - .toolbarbutton-icon, - .toolbarbutton-text, - .toolbarbutton-badge-stack - ) { - fill: {{colors.primary.default.hex}} - } - } -} - -.identity-color-blue { - --identity-tab-color: {{dank16.color12.default.hex}} !important; - --identity-icon-color: {{dank16.color12.default.hex}} !important; -} - -.identity-color-turquoise { - --identity-tab-color: {{dank16.color6.default.hex}} !important; - --identity-icon-color: {{dank16.color6.default.hex}} !important; -} - -.identity-color-green { - --identity-tab-color: {{dank16.color10.default.hex}} !important; - --identity-icon-color: {{dank16.color10.default.hex}} !important; -} - -.identity-color-yellow { - --identity-tab-color: {{dank16.color11.default.hex}} !important; - --identity-icon-color: {{dank16.color11.default.hex}} !important; -} - -.identity-color-orange { - --identity-tab-color: {{dank16.color3.default.hex}} !important; - --identity-icon-color: {{dank16.color3.default.hex}} !important; -} - -.identity-color-red { - --identity-tab-color: {{dank16.color9.default.hex}} !important; - --identity-icon-color: {{dank16.color9.default.hex}} !important; -} - -.identity-color-pink { - --identity-tab-color: {{dank16.color13.default.hex}} !important; - --identity-icon-color: {{dank16.color13.default.hex}} !important; -} - -.identity-color-purple { - --identity-tab-color: {{dank16.color5.default.hex}} !important; - --identity-icon-color: {{dank16.color5.default.hex}} !important; -} - -#zen-appcontent-navbar-container { - background-color: {{colors.background.default.hex}} !important; -} - -#PanelUI-menu-button .toolbarbutton-icon, -#downloads-button .toolbarbutton-icon, -#unified-extensions-button .toolbarbutton-icon { - fill: {{colors.primary.default.hex}} !important; - color: {{colors.primary.default.hex}} !important; -} - -#PanelUI-menu-button .toolbarbutton-badge-stack, -#downloads-button .toolbarbutton-badge-stack, -#unified-extensions-button .toolbarbutton-badge-stack { - fill: {{colors.primary.default.hex}} !important; - color: {{colors.primary.default.hex}} !important; -} - -toolbar .toolbarbutton-1 > .toolbarbutton-icon { - fill: {{colors.primary.default.hex}} !important; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/CHANGELOG.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/CHANGELOG.md deleted file mode 100644 index c6dc197..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 1.0.0 - -- Initial release diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/LICENSE b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/LICENSE deleted file mode 100644 index bf72064..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 DankLinux - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/README.md deleted file mode 100644 index 56b4245..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Dynamic Base16 DankShell Theme - -A VSCode theme for [DankMaterialShell](https://github.com/AvengeMedia/DankMaterialShell). - -## How It Works - -1. Install this extension -2. Select one of the "Dynamic Base16 DankShell" themes in VSCode -3. DankMaterialShell automatically updates the theme files when you change themes. - -The theme files are located in your VSCode extensions directory and are updated by matugen when generating new colors. - -## Themes - -- **Dynamic Base16 DankShell** - Follows your current light/dark mode -- **Dynamic Base16 DankShell (Dark)** - Always dark variant -- **Dynamic Base16 DankShell (Light)** - Always light variant diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/danklogo.png b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/danklogo.png deleted file mode 100644 index 8c5b78a..0000000 Binary files a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/danklogo.png and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/package.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/package.json deleted file mode 100644 index 91be6c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "dms-theme", - "displayName": "DMS - Dank Material Shell Theme", - "description": "Dynamic theme using matugen & dank16 terminal colors - auto-updated by DankMaterialShell", - "publisher": "DankLinux", - "version": "0.0.3", - "icon": "danklogo.png", - "engines": { - "vscode": "^1.70.0" - }, - "categories": [ - "Themes" - ], - "keywords": [ - "dms", - "dank", - "material", - "dankshell", - "danklinux" - ], - "repository": { - "type": "git", - "url": "https://github.com/AvengeMedia/DankMaterialShell" - }, - "contributes": { - "themes": [ - { - "label": "Dynamic Base16 DankShell", - "uiTheme": "vs-dark", - "path": "./themes/dankshell-default.json", - "_watch": true - }, - { - "label": "Dynamic Base16 DankShell (Dark)", - "uiTheme": "vs-dark", - "path": "./themes/dankshell-dark.json", - "_watch": true - }, - { - "label": "Dynamic Base16 DankShell (Light)", - "uiTheme": "vs", - "path": "./themes/dankshell-light.json", - "_watch": true - } - ] - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-dark.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-dark.json deleted file mode 100644 index 2052853..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-dark.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell", - "colors": { - "editor.background": "#1a1a2e", - "editor.foreground": "#e4e4e7", - "editorLineNumber.foreground": "#71717a", - "editorLineNumber.activeForeground": "#e4e4e7", - "editorCursor.foreground": "#a78bfa", - "editor.selectionBackground": "#4c1d95", - "activityBar.background": "#1a1a2e", - "activityBar.foreground": "#e4e4e7", - "activityBarBadge.background": "#a78bfa", - "activityBarBadge.foreground": "#1a1a2e", - "sideBar.background": "#1a1a2e", - "sideBar.foreground": "#e4e4e7", - "statusBar.background": "#1a1a2e", - "statusBar.foreground": "#e4e4e7", - "titleBar.activeBackground": "#1a1a2e", - "titleBar.activeForeground": "#e4e4e7" - }, - "tokenColors": [ - { - "scope": ["comment"], - "settings": { "foreground": "#71717a", "fontStyle": "italic" } - }, - { - "scope": ["keyword"], - "settings": { "foreground": "#a78bfa" } - }, - { - "scope": ["string"], - "settings": { "foreground": "#34d399" } - } - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-default.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-default.json deleted file mode 100644 index 2052853..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-default.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell", - "colors": { - "editor.background": "#1a1a2e", - "editor.foreground": "#e4e4e7", - "editorLineNumber.foreground": "#71717a", - "editorLineNumber.activeForeground": "#e4e4e7", - "editorCursor.foreground": "#a78bfa", - "editor.selectionBackground": "#4c1d95", - "activityBar.background": "#1a1a2e", - "activityBar.foreground": "#e4e4e7", - "activityBarBadge.background": "#a78bfa", - "activityBarBadge.foreground": "#1a1a2e", - "sideBar.background": "#1a1a2e", - "sideBar.foreground": "#e4e4e7", - "statusBar.background": "#1a1a2e", - "statusBar.foreground": "#e4e4e7", - "titleBar.activeBackground": "#1a1a2e", - "titleBar.activeForeground": "#e4e4e7" - }, - "tokenColors": [ - { - "scope": ["comment"], - "settings": { "foreground": "#71717a", "fontStyle": "italic" } - }, - { - "scope": ["keyword"], - "settings": { "foreground": "#a78bfa" } - }, - { - "scope": ["string"], - "settings": { "foreground": "#34d399" } - } - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-light.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-light.json deleted file mode 100644 index 2052853..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/matugen/vsix-build/themes/dankshell-light.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "vscode://schemas/color-theme", - "name": "Dynamic Base16 DankShell", - "colors": { - "editor.background": "#1a1a2e", - "editor.foreground": "#e4e4e7", - "editorLineNumber.foreground": "#71717a", - "editorLineNumber.activeForeground": "#e4e4e7", - "editorCursor.foreground": "#a78bfa", - "editor.selectionBackground": "#4c1d95", - "activityBar.background": "#1a1a2e", - "activityBar.foreground": "#e4e4e7", - "activityBarBadge.background": "#a78bfa", - "activityBarBadge.foreground": "#1a1a2e", - "sideBar.background": "#1a1a2e", - "sideBar.foreground": "#e4e4e7", - "statusBar.background": "#1a1a2e", - "statusBar.foreground": "#e4e4e7", - "titleBar.activeBackground": "#1a1a2e", - "titleBar.activeForeground": "#e4e4e7" - }, - "tokenColors": [ - { - "scope": ["comment"], - "settings": { "foreground": "#71717a", "fontStyle": "italic" } - }, - { - "scope": ["keyword"], - "settings": { "foreground": "#a78bfa" } - }, - { - "scope": ["string"], - "settings": { "foreground": "#34d399" } - } - ] -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/qmlformat-all.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/qmlformat-all.sh deleted file mode 100755 index d1f4cb8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/qmlformat-all.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -# Find and format all QML files, then fix pragma ComponentBehavior -find . -name "*.qml" -exec sh -c ' - qmlfmt -t 4 -i 4 -b 250 -w "$1" - sed -i "s/pragma ComponentBehavior$/pragma ComponentBehavior: Bound/g" "$1" -' _ {} \; diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/gtk.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/gtk.sh deleted file mode 100755 index 454b0f2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/gtk.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -CONFIG_DIR="$1" - -if [ -z "$CONFIG_DIR" ]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -apply_gtk3_colors() { - local config_dir="$1" - - local gtk3_dir="$config_dir/gtk-3.0" - local dank_colors="$gtk3_dir/dank-colors.css" - local gtk_css="$gtk3_dir/gtk.css" - - if [ ! -f "$dank_colors" ]; then - echo "Error: dank-colors.css not found at $dank_colors" >&2 - echo "Run matugen first to generate theme files" >&2 - exit 1 - fi - - if [ -L "$gtk_css" ]; then - rm "$gtk_css" - elif [ -f "$gtk_css" ]; then - mv "$gtk_css" "$gtk_css.backup.$(date +%s)" - echo "Backed up existing gtk.css" - fi - - ln -s "dank-colors.css" "$gtk_css" - echo "Created symlink: $gtk_css -> dank-colors.css" -} - -apply_gtk4_colors() { - local config_dir="$1" - - local gtk4_dir="$config_dir/gtk-4.0" - local dank_colors="$gtk4_dir/dank-colors.css" - local gtk_css="$gtk4_dir/gtk.css" - local gtk4_import="@import url(\"dank-colors.css\");" - - if [ ! -f "$dank_colors" ]; then - echo "Error: GTK4 dank-colors.css not found at $dank_colors" >&2 - echo "Run matugen first to generate theme files" >&2 - exit 1 - fi - - if [ -f "$gtk_css" ] && grep -q '^@import url.*dank-colors\.css.*);$' "$gtk_css"; then - echo "GTK4 import already exists" - return - fi - - if [ -f "$gtk_css" ] && [ -s "$gtk_css" ]; then - sed -i "1i\\$gtk4_import" "$gtk_css" - else - echo "$gtk4_import" >"$gtk_css" - fi - echo "Updated GTK4 CSS import" -} - -mkdir -p "$CONFIG_DIR/gtk-3.0" "$CONFIG_DIR/gtk-4.0" - -apply_gtk3_colors "$CONFIG_DIR" -apply_gtk4_colors "$CONFIG_DIR" - -echo "GTK colors applied successfully" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/i18nsync.py b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/i18nsync.py deleted file mode 100755 index 42cc7a5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/i18nsync.py +++ /dev/null @@ -1,361 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import json -import os -import subprocess -from pathlib import Path -from urllib import request, parse - -REPO_ROOT = Path(__file__).parent.parent -EN_JSON = REPO_ROOT / "translations" / "en.json" -TEMPLATE_JSON = REPO_ROOT / "translations" / "template.json" -POEXPORTS_DIR = REPO_ROOT / "translations" / "poexports" -SYNC_STATE = REPO_ROOT / ".git" / "i18n_sync_state.json" - -LANGUAGES = { - "ja": "ja.json", - "zh-Hans": "zh_CN.json", - "zh-Hant": "zh_TW.json", - "pt-br": "pt.json", - "tr": "tr.json", - "it": "it.json", - "pl": "pl.json", - "es": "es.json", - "he": "he.json", - "hu": "hu.json", - "fa": "fa.json", - "fr": "fr.json", - "nl": "nl.json", - "ru": "ru.json", - "de": "de.json", - "sv": "sv.json" -} - -def error(msg): - print(f"\033[91mError: {msg}\033[0m", file=sys.stderr) - sys.exit(1) - -def warn(msg): - print(f"\033[93mWarning: {msg}\033[0m", file=sys.stderr) - -def info(msg): - print(f"\033[94m{msg}\033[0m") - -def success(msg): - print(f"\033[92m{msg}\033[0m") - -def get_env_or_error(var): - value = os.environ.get(var) - if not value: - error(f"{var} environment variable not set") - return value - -def poeditor_request(endpoint, data): - url = f"https://api.poeditor.com/v2/{endpoint}" - data_bytes = parse.urlencode(data).encode() - req = request.Request(url, data=data_bytes, method="POST") - - try: - with request.urlopen(req) as response: - return json.loads(response.read().decode()) - except Exception as e: - error(f"POEditor API request failed: {e}") - -def extract_strings(): - info("Extracting strings from QML files...") - extract_script = REPO_ROOT / "translations" / "extract_translations.py" - - if not extract_script.exists(): - error(f"Extract script not found: {extract_script}") - - result = subprocess.run([sys.executable, str(extract_script)], cwd=REPO_ROOT) - if result.returncode != 0: - error("String extraction failed") - - if not EN_JSON.exists(): - error(f"Extraction did not produce {EN_JSON}") - -def normalize_json(file_path): - if not file_path.exists(): - return {} - with open(file_path) as f: - return json.load(f) - -def json_changed(file_path, new_data): - old_data = normalize_json(file_path) - return json.dumps(old_data, sort_keys=True) != json.dumps(new_data, sort_keys=True) - -def upload_source_strings(api_token, project_id): - if not EN_JSON.exists(): - warn("No en.json to upload") - return False - - info("Uploading source strings to POEditor...") - - with open(EN_JSON, 'rb') as f: - boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW' - body = ( - f'--{boundary}\r\n' - f'Content-Disposition: form-data; name="api_token"\r\n\r\n' - f'{api_token}\r\n' - f'--{boundary}\r\n' - f'Content-Disposition: form-data; name="id"\r\n\r\n' - f'{project_id}\r\n' - f'--{boundary}\r\n' - f'Content-Disposition: form-data; name="updating"\r\n\r\n' - f'terms\r\n' - f'--{boundary}\r\n' - f'Content-Disposition: form-data; name="file"; filename="en.json"\r\n' - f'Content-Type: application/json\r\n\r\n' - ).encode() + f.read() + f'\r\n--{boundary}--\r\n'.encode() - - req = request.Request( - 'https://api.poeditor.com/v2/projects/upload', - data=body, - headers={'Content-Type': f'multipart/form-data; boundary={boundary}'} - ) - - try: - with request.urlopen(req) as response: - result = json.loads(response.read().decode()) - except Exception as e: - error(f"Upload failed: {e}") - - if result.get('response', {}).get('status') != 'success': - error(f"POEditor upload failed: {result}") - - terms = result.get('result', {}).get('terms', {}) - added = terms.get('added', 0) - updated = terms.get('updated', 0) - deleted = terms.get('deleted', 0) - - if added or updated or deleted: - success(f"POEditor updated: {added} added, {updated} updated, {deleted} deleted") - return True - else: - info("No changes uploaded to POEditor") - return False - -def download_translations(api_token, project_id): - info("Downloading translations from POEditor...") - - POEXPORTS_DIR.mkdir(parents=True, exist_ok=True) - any_changed = False - - for po_lang, filename in LANGUAGES.items(): - repo_file = POEXPORTS_DIR / filename - - info(f"Fetching {po_lang}...") - - export_resp = poeditor_request('projects/export', { - 'api_token': api_token, - 'id': project_id, - 'language': po_lang, - 'type': 'key_value_json' - }) - - if export_resp.get('response', {}).get('status') != 'success': - warn(f"Export request failed for {po_lang}") - continue - - url = export_resp.get('result', {}).get('url') - if not url: - warn(f"No export URL for {po_lang}") - continue - - try: - with request.urlopen(url) as response: - new_data = json.loads(response.read().decode()) - except Exception as e: - warn(f"Failed to download {po_lang}: {e}") - continue - - if json_changed(repo_file, new_data): - with open(repo_file, 'w') as f: - json.dump(new_data, f, ensure_ascii=False, indent=2, sort_keys=True) - f.write('\n') - success(f"Updated {filename}") - any_changed = True - else: - info(f"No changes for {filename}") - - return any_changed - -def check_sync_status(): - api_token = get_env_or_error('POEDITOR_API_TOKEN') - project_id = get_env_or_error('POEDITOR_PROJECT_ID') - - extract_strings() - - current_en = normalize_json(EN_JSON) - - if not SYNC_STATE.exists(): - return True - - with open(SYNC_STATE) as f: - state = json.load(f) - - last_en = state.get('en_json', {}) - last_translations = state.get('translations', {}) - - if json.dumps(current_en, sort_keys=True) != json.dumps(last_en, sort_keys=True): - return True - - for po_lang, filename in LANGUAGES.items(): - repo_file = POEXPORTS_DIR / filename - current_trans = normalize_json(repo_file) - last_trans = last_translations.get(filename, {}) - - if json.dumps(current_trans, sort_keys=True) != json.dumps(last_trans, sort_keys=True): - return True - - export_resp = poeditor_request('projects/export', { - 'api_token': api_token, - 'id': project_id, - 'language': list(LANGUAGES.keys())[0], - 'type': 'key_value_json' - }) - - if export_resp.get('response', {}).get('status') == 'success': - url = export_resp.get('result', {}).get('url') - if url: - try: - with request.urlopen(url) as response: - remote_data = json.loads(response.read().decode()) - first_file = POEXPORTS_DIR / list(LANGUAGES.values())[0] - local_data = normalize_json(first_file) - - if json.dumps(remote_data, sort_keys=True) != json.dumps(local_data, sort_keys=True): - return True - except: - pass - - return False - -def save_sync_state(): - state = { - 'en_json': normalize_json(EN_JSON), - 'translations': {} - } - - for filename in LANGUAGES.values(): - repo_file = POEXPORTS_DIR / filename - state['translations'][filename] = normalize_json(repo_file) - - SYNC_STATE.parent.mkdir(parents=True, exist_ok=True) - with open(SYNC_STATE, 'w') as f: - json.dump(state, f, indent=2) - -def main(): - if len(sys.argv) < 2: - error("Usage: i18nsync.py [check|sync|test|local]") - - command = sys.argv[1] - - if command == "test": - info("Running in test mode (no POEditor upload/download)") - extract_strings() - - current_en = normalize_json(EN_JSON) - current_template = normalize_json(TEMPLATE_JSON) - - success(f"✓ Extracted {len(current_en)} terms") - - terms_with_context = sum(1 for entry in current_en if entry.get('context') and entry['context'] != entry['term']) - if terms_with_context > 0: - success(f"✓ Found {terms_with_context} terms with custom contexts") - - info("\nFiles generated:") - info(f" - {EN_JSON}") - info(f" - {TEMPLATE_JSON}") - - sys.exit(0) - elif command == "check": - try: - if check_sync_status(): - error("i18n out of sync - run 'python3 scripts/i18nsync.py sync' first") - else: - success("i18n in sync") - sys.exit(0) - except SystemExit: - raise - except Exception as e: - error(f"Check failed: {e}") - - elif command == "sync": - api_token = get_env_or_error('POEDITOR_API_TOKEN') - project_id = get_env_or_error('POEDITOR_PROJECT_ID') - - extract_strings() - - current_en = normalize_json(EN_JSON) - staged_en = {} - - try: - result = subprocess.run( - ['git', 'show', f':{EN_JSON.relative_to(REPO_ROOT)}'], - capture_output=True, - text=True, - cwd=REPO_ROOT - ) - if result.returncode == 0: - staged_en = json.loads(result.stdout) - except: - pass - - strings_changed = json.dumps(current_en, sort_keys=True) != json.dumps(staged_en, sort_keys=True) - - if strings_changed: - upload_source_strings(api_token, project_id) - else: - info("No changes in source strings") - - translations_changed = download_translations(api_token, project_id) - - if strings_changed or translations_changed: - subprocess.run(['git', 'add', 'translations/'], cwd=REPO_ROOT) - save_sync_state() - success("Sync complete - changes staged for commit") - else: - save_sync_state() - info("Already in sync") - - elif command == "local": - info("Updating en.json locally (no POEditor sync)") - - old_en = normalize_json(EN_JSON) - old_terms = {entry['term']: entry for entry in old_en} if isinstance(old_en, list) else {} - - extract_strings() - - new_en = normalize_json(EN_JSON) - new_terms = {entry['term']: entry for entry in new_en} if isinstance(new_en, list) else {} - - added = set(new_terms.keys()) - set(old_terms.keys()) - removed = set(old_terms.keys()) - set(new_terms.keys()) - - if added: - info(f"\n+{len(added)} new terms:") - for term in sorted(added)[:20]: - print(f" + {term[:60]}...") - if len(added) > 20: - print(f" ... and {len(added) - 20} more") - - if removed: - info(f"\n-{len(removed)} removed terms:") - for term in sorted(removed)[:20]: - print(f" - {term[:60]}...") - if len(removed) > 20: - print(f" ... and {len(removed) - 20} more") - - success(f"\n✓ {len(new_en)} total terms") - - if not added and not removed: - info("No changes detected") - - else: - error(f"Unknown command: {command}") - -if __name__ == '__main__': - main() diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qmllint-entrypoints.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qmllint-entrypoints.sh deleted file mode 100755 index 41c5a74..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qmllint-entrypoints.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$( - CDPATH='' - cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -)" -repo_root="$( - CDPATH='' - cd -- "${script_dir}/../.." && pwd -)" -quickshell_dir="${repo_root}/quickshell" -qmlls_config="${quickshell_dir}/.qmlls.ini" - -# Resolve qmllint: honour QMLLINT, then try common Qt 6 binary names and -# install paths, and finally bare qmllint. We need the Qt 6 build (>= 6.x) -# because older Qt 5 qmllint doesn't understand --ignore-settings / -W. -resolve_qmllint() { - if [[ -n "${QMLLINT:-}" ]]; then - printf '%s\n' "${QMLLINT}" - return - fi - local candidate - for candidate in qmllint6 qmllint-qt6 /usr/lib/qt6/bin/qmllint qmllint; do - if command -v -- "${candidate}" >/dev/null 2>&1; then - printf '%s\n' "${candidate}" - return - fi - done - return 1 -} - -if ! qmllint_bin="$(resolve_qmllint)"; then - printf 'error: qmllint (Qt 6) not found in PATH (override with QMLLINT=/path/to/qmllint)\n' >&2 - exit 127 -fi - -print_broken_qmlls_link() { - local target="" - target="$(readlink -- "${qmlls_config}" 2>/dev/null || true)" - printf 'error: %s is a broken symlink. lint-qml requires a live Quickshell tooling VFS.\n' "${qmlls_config}" >&2 - if [[ -n "${target}" ]]; then - printf 'Broken target: %s\n' "${target}" >&2 - fi - print_vfs_recovery -} - -trim_ini_value() { - local value="$1" - value="${value#\"}" - value="${value%\"}" - printf '%s\n' "${value}" -} - -read_ini_value() { - local key="$1" - local file="$2" - local raw - - raw="$(sed -n "s/^${key}=//p" "${file}" | head -n 1)" - if [[ -z "${raw}" ]]; then - return 1 - fi - - trim_ini_value "${raw}" -} - -print_vfs_recovery() { - printf 'Generate it by starting the local shell config once, for example:\n' >&2 - printf ' dms -c %q run\n' "${quickshell_dir}" >&2 - printf ' qs -p %q\n' "${quickshell_dir}" >&2 -} - -if [[ -L "${qmlls_config}" && ! -e "${qmlls_config}" ]]; then - print_broken_qmlls_link - exit 1 -fi - -if [[ ! -e "${qmlls_config}" ]]; then - printf 'error: %s is missing. lint-qml requires the Quickshell tooling VFS.\n' "${qmlls_config}" >&2 - print_vfs_recovery - exit 1 -fi - -if ! build_dir="$(read_ini_value "buildDir" "${qmlls_config}")"; then - printf 'error: %s does not contain a buildDir entry.\n' "${qmlls_config}" >&2 - print_vfs_recovery - exit 1 -fi - -if ! import_paths_raw="$(read_ini_value "importPaths" "${qmlls_config}")"; then - printf 'error: %s does not contain an importPaths entry.\n' "${qmlls_config}" >&2 - print_vfs_recovery - exit 1 -fi - -if [[ ! -d "${build_dir}" || ! -f "${build_dir}/qs/qmldir" ]]; then - printf 'error: Quickshell tooling VFS is missing or stale: %s\n' "${build_dir}" >&2 - print_vfs_recovery - exit 1 -fi - -targets=( - "${quickshell_dir}/shell.qml" - "${quickshell_dir}/DMSShell.qml" - "${quickshell_dir}/DMSGreeter.qml" -) - -qmllint_args=( - --ignore-settings - -W 0 - -I "${build_dir}" -) - -IFS=':' read -r -a import_paths <<< "${import_paths_raw}" -for path in "${import_paths[@]}"; do - if [[ -n "${path}" ]]; then - qmllint_args+=(-I "${path}") - fi -done - -if ! output="$("${qmllint_bin}" "${qmllint_args[@]}" "${targets[@]}" 2>&1)"; then - printf '%s\n' "${output}" >&2 - exit 1 -fi - -if [[ -n "${output}" ]]; then - printf '%s\n' "${output}" -fi diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qt.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qt.sh deleted file mode 100755 index 3da2167..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/qt.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash - -CONFIG_DIR="$1" - -if [ -z "$CONFIG_DIR" ]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -apply_qt_colors() { - local config_dir="$1" - local color_scheme_path - color_scheme_path="$(dirname "$config_dir")/.local/share/color-schemes/DankMatugen.colors" - - if [ ! -f "$color_scheme_path" ]; then - echo "Error: Qt color scheme not found at $color_scheme_path" >&2 - echo "Run matugen first to generate theme files" >&2 - exit 1 - fi - - update_qt_config() { - local config_file="$1" - - if [ -f "$config_file" ]; then - if grep -q '^\[Appearance\]' "$config_file"; then - if grep -q '^custom_palette=' "$config_file"; then - sed -i 's/^custom_palette=.*/custom_palette=true/' "$config_file" - else - sed -i '/^\[Appearance\]/a custom_palette=true' "$config_file" - fi - - if grep -q '^color_scheme_path=' "$config_file"; then - sed -i "s|^color_scheme_path=.*|color_scheme_path=$color_scheme_path|" "$config_file" - else - sed -i "/^\\[Appearance\\]/a color_scheme_path=$color_scheme_path" "$config_file" - fi - else - { - echo "" - echo "[Appearance]" - echo "custom_palette=true" - echo "color_scheme_path=$color_scheme_path" - } >>"$config_file" - fi - else - printf '[Appearance]\\ncustom_palette=true\\ncolor_scheme_path=%s\\n' "$color_scheme_path" >"$config_file" - fi - } - - qt5_applied=false - qt6_applied=false - - if command -v qt5ct >/dev/null 2>&1; then - mkdir -p "$config_dir/qt5ct" - update_qt_config "$config_dir/qt5ct/qt5ct.conf" - echo "Applied Qt5ct configuration" - qt5_applied=true - fi - - if command -v qt6ct >/dev/null 2>&1; then - mkdir -p "$config_dir/qt6ct" - update_qt_config "$config_dir/qt6ct/qt6ct.conf" - echo "Applied Qt6ct configuration" - qt6_applied=true - fi - - if [ "$qt5_applied" = false ] && [ "$qt6_applied" = false ]; then - echo "Warning: Neither qt5ct nor qt6ct found" >&2 - echo "Install qt5ct or qt6ct for Qt application theming" >&2 - exit 1 - fi -} - -apply_qt_colors "$CONFIG_DIR" - -echo "Qt colors applied successfully" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/spam-notifications.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/spam-notifications.sh deleted file mode 100755 index 4a70c36..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/spam-notifications.sh +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env bash - -# Notification Spam Test Script - Sends 100 rapid notifications from fake apps - -echo "NOTIFICATION SPAM TEST - 100 RAPID NOTIFICATIONS" -echo "=============================================================" -echo "WARNING: This will send 100 notifications very quickly!" -echo "Press Ctrl+C to cancel, or wait 3 seconds to continue..." -sleep 3 - -# Arrays of fake app names and icons -APPS=( - "slack:mail-message-new" - "discord:internet-chat" - "teams:call-start" - "zoom:camera-video" - "spotify:audio-x-generic" - "chrome:web-browser" - "firefox:web-browser" - "vscode:text-editor" - "terminal:utilities-terminal" - "steam:applications-games" - "telegram:internet-chat" - "whatsapp:phone" - "signal:security-high" - "thunderbird:mail-client" - "calendar:office-calendar" - "notes:text-editor" - "todo:emblem-default" - "weather:weather-few-clouds" - "news:rss" - "reddit:web-browser" - "twitter:internet-web-browser" - "instagram:camera-photo" - "youtube:video-x-generic" - "netflix:media-playback-start" - "github:folder-development" - "gitlab:folder-development" - "jira:applications-office" - "notion:text-editor" - "obsidian:accessories-text-editor" - "dropbox:folder-remote" - "gdrive:folder-google-drive" - "onedrive:folder-cloud" - "backup:drive-harddisk" - "antivirus:security-high" - "vpn:network-vpn" - "torrent:network-server" - "docker:application-x-executable" - "kubernetes:applications-system" - "postgres:database" - "mongodb:database" - "redis:database" - "nginx:network-server" - "apache:network-server" - "jenkins:applications-development" - "gradle:applications-development" - "maven:applications-development" - "npm:package-x-generic" - "yarn:package-x-generic" - "pip:package-x-generic" - "apt:system-software-install" -) - -# Arrays of message types -TITLES=( - "New message" - "Update available" - "Download complete" - "Task finished" - "Build successful" - "Deployment complete" - "Sync complete" - "Backup finished" - "Security alert" - "New notification" - "Process complete" - "Upload finished" - "Connection established" - "Meeting starting" - "Reminder" - "Warning" - "Error occurred" - "Success" - "Failed" - "Pending" - "In progress" - "Scheduled" - "New activity" - "Status update" - "Alert" - "Information" - "Breaking news" - "Hot update" - "Trending" - "New release" -) - -MESSAGES=( - "Your request has been processed successfully" - "New content is available for download" - "Operation completed without errors" - "Check your inbox for updates" - "3 new items require your attention" - "Background task finished executing" - "All systems operational" - "Performance metrics updated" - "Configuration saved successfully" - "Database connection established" - "Cache cleared and rebuilt" - "Service restarted automatically" - "Logs have been rotated" - "Memory usage optimized" - "Network latency improved" - "Security scan completed - no threats" - "Automatic backup created" - "Files synchronized across devices" - "Updates installed successfully" - "New features are now available" - "Your subscription has been renewed" - "Report generated and ready" - "Analysis complete - view results" - "Queue processed: 42 items" - "Rate limit will reset in 5 minutes" - "API call successful (200 OK)" - "Webhook delivered successfully" - "Container started on port 8080" - "Build artifact uploaded" - "Test suite passed: 100/100" - "Coverage report: 95%" - "Dependencies updated to latest" - "Migration completed successfully" - "Index rebuilt for faster queries" - "SSL certificate renewed" - "Firewall rules updated" - "DNS propagation complete" - "CDN cache purged globally" - "Load balancer health check: OK" - "Cluster scaled to 5 nodes" -) - -# Urgency levels -URGENCY=("low" "normal") - -# Counter -COUNT=0 -TOTAL=100 - -echo "" -echo "Starting notification spam..." -echo "------------------------------" - -# Send notifications rapidly -for _ in $(seq 1 $TOTAL); do - # Pick random app, title, message, and urgency - APP=${APPS[$RANDOM % ${#APPS[@]}]} - APP_NAME=${APP%%:*} - APP_ICON=${APP#*:} - TITLE=${TITLES[$RANDOM % ${#TITLES[@]}]} - MESSAGE=${MESSAGES[$RANDOM % ${#MESSAGES[@]}]} - URG=${URGENCY[$RANDOM % ${#URGENCY[@]}]} - - # Add some variety with random numbers and timestamps - RAND_NUM=$((RANDOM % 1000)) - TIMESTAMP=$(date +"%H:%M:%S") - - # Randomly add extra details to some messages - if [ $((RANDOM % 3)) -eq 0 ]; then - MESSAGE="[$TIMESTAMP] $MESSAGE (#$RAND_NUM)" - fi - - # Send notification with very short delay - notify-send \ - -h "string:desktop-entry:$APP_NAME" \ - -i "$APP_ICON" \ - -u "$URG" \ - "$APP_NAME: $TITLE" \ - "$MESSAGE" & - - # Increment counter - COUNT=$((COUNT + 1)) - - # Show progress every 10 notifications - if [ $((COUNT % 10)) -eq 0 ]; then - echo " Sent $COUNT/$TOTAL notifications..." - fi - - # Tiny delay to prevent complete system freeze - # Adjust this value: smaller = faster spam, larger = slower spam - sleep 0.01 -done - -# Wait for all background notifications to complete -wait - -echo "" -echo "Spam test complete!" -echo "=============================================================" -echo "Statistics:" -echo " Total notifications sent: $TOTAL" -echo " Apps simulated: ${#APPS[@]}" -echo " Message variations: ${#MESSAGES[@]}" -echo " Time taken: ~$((TOTAL / 100)) seconds" -echo "" -echo "Check your notification center - it should be FULL!" -echo "Tip: You may want to clear all notifications after this test" -echo "" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/verify-notifications.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/verify-notifications.sh deleted file mode 100755 index 750dd99..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/scripts/verify-notifications.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash - -# Enhanced Notification System Test Script with Common Icons -# Uses icons that are more likely to be available on most systems - -echo "🔔 Testing Enhanced Notification System Features" -echo "=============================================================" - -# Check what icons are available -echo "Checking available icons..." -if [ -d "$HOME/.local/share/icons/Papirus" ]; then - echo "✓ Icon theme found" -else - echo "! Using fallback icons" -fi - -# Test 1: Basic notifications with markdown -echo "📱 Test 1: Basic notifications with markdown" -notify-send -h string:desktop-entry:org.gnome.Settings -i preferences-desktop "Settings" "**Bold text** and *italic text* with [links](https://example.com) and \`code blocks\`" -sleep 2 - -# Test 2: Media notifications with rich formatting (grouping) -echo "🎵 Test 2: Media notifications with rich formatting (grouping)" -notify-send -h string:desktop-entry:spotify -i audio-x-generic "Spotify" "**Now Playing:** *Song 1* by **Artist A**\n\nAlbum: ~Greatest Hits~\nDuration: \`3:45\`" -sleep 1 -notify-send -h string:desktop-entry:spotify -i audio-x-generic "Spotify" "**Now Playing:** *Song 2* by **Artist B**\n\n> From the album: \"New Releases\"\n- Track #4\n- \`4:12\`" -sleep 1 -notify-send -h string:desktop-entry:spotify -i audio-x-generic "Spotify" "**Now Playing:** *Song 3* by **Artist C**\n\n### Recently Added\n- [View on Spotify](https://spotify.com)\n- Duration: \`2:58\`" -sleep 2 - -# Test 3: System notifications with markdown (separate groups) -echo "🔋 Test 3: System notifications with markdown (separate apps)" -notify-send -h string:desktop-entry:org.gnome.PowerStats -i battery "Power Manager" "⚠️ **Battery Low:** \`15%\` remaining\n\n### Power Saving Tips:\n- Reduce screen brightness\n- *Close unnecessary apps*\n- [Power settings](settings://power)" -sleep 1 -notify-send -h string:desktop-entry:org.gnome.NetworkDisplays -i network-wired "Network Manager" "✅ **WiFi Connected:** *HomeNetwork*\n\n**Signal Strength:** Strong (85%)\n**IP Address:** \`192.168.1.100\`\n\n> Connection established successfully" -sleep 1 -notify-send -h string:desktop-entry:org.gnome.Software -i system-software-update "Software" "📦 **Updates Available**\n\n### Pending Updates:\n- **Firefox** (v119.0)\n- *System libraries* (security)\n- \`python-requests\` (dependency)\n\n[Install All](software://updates) | [View Details](software://details)" -sleep 2 - -# Test 4: Chat notifications with complex markdown (grouping) -echo "💬 Test 4: Chat notifications with complex markdown (grouping)" -notify-send -h string:desktop-entry:discord -i internet-chat "Discord" "**#general** - User1\n\nHello everyone! 👋\n\n> Just wanted to share this cool project I'm working on:\n- Built with **React** and *TypeScript*\n- Using \`styled-components\` for styling\n- [Check it out](https://github.com/user1/project)" -sleep 1 -notify-send -h string:desktop-entry:discord -i internet-chat "Discord" "**#general** - User2\n\nHey there! That looks awesome! 🚀\n\n### Quick question:\nDo you have any tips for:\n1. **State management** patterns?\n2. *Performance optimization*?\n3. Testing with \`jest\`?\n\n> I'm still learning React" -sleep 1 -notify-send -h string:desktop-entry:discord -i internet-chat "Discord" "**Direct Message** - john_doe\n\n*Private message from John* 💬\n\n**Subject:** Weekend plans\n\nHey! Want to grab coffee this weekend?\n\n### Suggestions:\n- ☕ Local café on Main St\n- 🥐 That new bakery downtown\n- 🏠 My place (I got a new espresso machine!)\n\n[Reply](discord://dm/john_doe) | [Call](discord://call/john_doe)" -sleep 2 - -# Test 5: Urgent notifications with markdown -echo "🚨 Test 5: Urgent notifications with markdown" -notify-send -u critical -i dialog-warning "Critical Alert" "🔥 **SYSTEM OVERHEATING** 🔥\n\n### Current Status:\n- **Temperature:** \`85°C\` (Critical)\n- **CPU Usage:** \`95%\`\n- *Thermal throttling active*\n\n> **Immediate Actions Required:**\n1. Close resource-intensive applications\n2. Check cooling system\n3. Reduce workload\n\n[System Monitor](gnome-system-monitor) | [Power Options](gnome-power-statistics)" -sleep 2 - -# Test 6: Notifications with actions and markdown -echo "⚡ Test 6: Action buttons with markdown" -notify-send -h string:desktop-entry:org.gnome.Software -i system-upgrade "Software" "📦 **System Updates Available**\n\n### Ready to Install:\n- **Security patches** (High priority)\n- *Feature updates* for 3 applications\n- \`kernel\` update (5.15.0 → 5.16.2)\n\n> **Recommended:** Install now for optimal security\n\n**Estimated time:** ~15 minutes\n**Restart required:** Yes\n\n[Install Now](software://install) | [Schedule Later](software://schedule)" -sleep 2 - -# Test 7: Multiple different apps with rich markdown -echo "📊 Test 7: Multiple different apps with rich markdown" -notify-send -h string:desktop-entry:thunderbird -i mail-message-new "Thunderbird" "📧 **New Messages** (3)\n\n### Recent Emails:\n1. **Sarah Johnson** - *Project Update*\n > \"The quarterly report is ready for review...\"\n \n2. **GitHub** - \`[user/repo]\` *Pull Request*\n > New PR: Fix memory leak in parser\n \n3. **Newsletter** - *Weekly Tech Digest*\n > This week: AI advancements, new frameworks...\n\n[Open Inbox](thunderbird://inbox) | [Mark All Read](thunderbird://markread)" -sleep 0.5 -notify-send -h string:desktop-entry:org.gnome.Calendar -i office-calendar "Calendar" "📅 **Upcoming Meeting**\n\n### Daily Standup\n- **Time:** 5 minutes\n- **Location:** *Conference Room A*\n- **Attendees:** Team Alpha (8 people)\n\n#### Agenda:\n1. Yesterday's progress\n2. Today's goals \n3. Blockers discussion\n\n> **Reminder:** Prepare your status update\n\n[Join Video Call](meet://standup) | [Reschedule](calendar://reschedule)" -sleep 0.5 -notify-send -h string:desktop-entry:org.gnome.Nautilus -i folder-downloads "Files" "📁 **Download Complete**\n\n### File Details:\n- **Name:** \`document.pdf\`\n- **Size:** *2.4 MB*\n- **Location:** ~/Downloads/\n- **Type:** PDF Document\n\n> **Security:** Scanned ✅ (No threats detected)\n\n**Recent Downloads:**\n- presentation.pptx (1 hour ago)\n- backup.zip (yesterday)\n\n[Open File](file://document.pdf) | [Show in Folder](nautilus://downloads)" -sleep 2 - -# notify-send --hint=boolean:resident:true "Resident Test" "Click an action - I should stay visible!" --action="Test Action" --action="Close Me" - -echo "" -echo "✅ Notification tests completed!" -echo "" -echo "📋 Enhanced Features Tested:" -echo " • Media notification replacement" -echo " • System notification grouping" -echo " • Conversation grouping and auto-expansion" -echo " • Urgency level handling" -echo " • Action button support" -echo " • Multi-app notification handling" -echo "" -echo "🎯 Check your notification popup and notification center to see the results!" -echo "" -echo "Note: Some icons may show as fallback (checkerboard) if icon themes aren't installed." -echo "To install more icons: sudo pacman -S papirus-icon-theme adwaita-icon-theme" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/shell.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/shell.qml deleted file mode 100644 index ae22e86..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/shell.qml +++ /dev/null @@ -1,36 +0,0 @@ -//@ pragma Env QSG_RENDER_LOOP=threaded -//@ pragma Env QT_MEDIA_BACKEND=ffmpeg -//@ pragma Env QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi -//@ pragma Env QT_FFMPEG_ENCODING_HW_DEVICE_TYPES=vaapi -//@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -//@ pragma Env QT_QUICK_CONTROLS_STYLE=Material -//@ pragma UseQApplication -// ! TODO - replace pragma AppId when next QS releases, remove from GO launch injection. - -import QtQuick -import Quickshell - -ShellRoot { - id: entrypoint - - readonly property bool runGreeter: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" - readonly property bool disableHotReload: Quickshell.env("DMS_DISABLE_HOT_RELOAD") === "1" || Quickshell.env("DMS_DISABLE_HOT_RELOAD") === "true" - - Component.onCompleted: { - Quickshell.watchFiles = !disableHotReload; - } - - Loader { - id: dmsShellLoader - asynchronous: false - sourceComponent: DMSShell {} - active: !entrypoint.runGreeter - } - - Loader { - id: dmsGreeterLoader - asynchronous: false - sourceComponent: DMSGreeter {} - active: entrypoint.runGreeter - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/systemd/tmpfiles-dms-greeter.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/systemd/tmpfiles-dms-greeter.conf deleted file mode 100644 index f5f3754..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/systemd/tmpfiles-dms-greeter.conf +++ /dev/null @@ -1,3 +0,0 @@ -# Path Mode User Group Age Argument -d /var/cache/dms-greeter 0750 greeter greeter - -d /var/lib/greeter 0755 greeter greeter - diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/README.md deleted file mode 100644 index 19fc178..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# DankMaterialShell Translations - -This directory contains translation files for DankMaterialShell extracted from all qsTr() calls in the QML codebase. - -## Files - -- **en.json** - Source language file with English strings and file references -- **template.json** - Empty template for creating new translations -- **extract_translations.py** - Script to regenerate translation files - -## POEditor Format - -The JSON files follow POEditor's import format: - -```json -[ - { - "term": "string to translate", - "context": "file:line", - "reference": "Modules/Settings/AboutTab.qml:45", - "comment": "" - } -] -``` - -### Field Descriptions - -- **term**: The source string in English (from qsTr() calls) -- **context**: Primary location where the string appears (file:line) -- **reference**: All locations where this string is used (comma-separated) -- **comment**: Additional notes for translators (currently empty) - -## How to Create a New Translation - -1. Copy `template.json` to your language code (e.g., `es.json` for Spanish) -2. Fill in the `translation` field for each entry: - ```json - { - "term": "Settings", - "translation": "Configuración", - "context": "Modals/Settings/SettingsModal.qml:147", - "reference": "Modals/Settings/SettingsModal.qml:147", - "comment": "" - } - ``` -3. Import to POEditor or use directly in your translation workflow - -## Regenerating Translation Files - -To update the translation files after code changes: - -```bash -cd /home/brandon/.config/quickshell/DankMaterialShellGit/translations -./extract_translations.py -``` - -This will scan all QML files and regenerate `en.json` and `template.json`. - -## Notes - -- Strings are deduplicated - if the same string appears in multiple locations, references are merged -- File paths are relative to the project root -- Line numbers are preserved for accurate context -- Empty strings and comments are reserved for translator notes diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/WORKFLOW.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/WORKFLOW.md deleted file mode 100644 index 1bd2da8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/WORKFLOW.md +++ /dev/null @@ -1,185 +0,0 @@ -# Translation Workflow for DankMaterialShell - -## POEditor Integration Guide - -### Initial Setup - -1. **Create POEditor Project** - - Go to https://poeditor.com - - Create new project "DankMaterialShell" - - Add languages you want to support (es, fr, de, etc.) - -2. **Import Source Strings** - - Upload `en.json` as the source language - - POEditor will detect 336 translatable strings - - Format: Key-Value JSON - -### Translation Workflow - -#### Method 1: Using POEditor (Recommended) - -1. **Upload source file** - ```bash - # Upload en.json to POEditor - ``` - -2. **Translate in POEditor** - - Use POEditor's web interface - - Invite translators - - Track progress per language - -3. **Export translations** - ```bash - # Download from POEditor as JSON - # Save to translations/{language_code}.json - # Example: translations/es.json, translations/fr.json - ``` - -4. **Test translations** - ```bash - # Set your locale and restart shell - export LANG=es_ES.UTF-8 - qs -p . - ``` - -#### Method 2: Manual Translation - -1. **Copy template** - ```bash - cp translations/template.json translations/es.json - ``` - -2. **Fill in translations** - ```json - { - "term": "Settings", - "context": "Modals/Settings/SettingsModal.qml:147", - "reference": "Modals/Settings/SettingsModal.qml:147", - "comment": "", - "translation": "Configuración" - } - ``` - -3. **Upload to POEditor** (optional) - -### Updating Translations After Code Changes - -1. **Re-extract strings** - ```bash - cd translations - python3 extract_translations.py - ``` - -2. **Upload updated en.json to POEditor** - - POEditor will detect new/removed strings - - Preserves existing translations - -3. **Download updated translations** - -### Translation File Format - -POEditor-compatible JSON format: - -```json -[ - { - "term": "source string in English", - "context": "file:line where it appears", - "reference": "full/path/to/file.qml:123", - "comment": "optional context for translators", - "translation": "translated string" - } -] -``` - -### Supported Languages - -The shell will auto-detect your system locale. Supported format: -- `es.json` → Spanish (es_ES, es_MX, etc.) -- `fr.json` → French (fr_FR, fr_CA, etc.) -- `de.json` → German -- `zh.json` → Chinese -- `ja.json` → Japanese -- `pt.json` → Portuguese -- etc. - -### Testing Translations - -1. **Change system locale** - ```bash - export LANG=es_ES.UTF-8 - export LC_ALL=es_ES.UTF-8 - ``` - -2. **Restart shell** - ```bash - qs -p . - ``` - -3. **Verify translations appear correctly** - -### File Structure - -``` -translations/ -├── en.json # Source language (English) -├── template.json # Empty template for new languages -├── es.json # Spanish translation -├── fr.json # French translation -├── extract_translations.py # Auto-extraction script -├── README.md # Technical documentation -└── WORKFLOW.md # This file -``` - -### Translation Statistics - -- **Total strings:** 336 unique terms -- **Most translated components:** - - Settings UI: 202 strings (60%) - - Weather: 25 strings (7%) - - System monitors: Various - - Modals: 43 strings (13%) - -### POEditor API Integration (Advanced) - -For automated sync, use POEditor's API: - -```bash -# Export from POEditor -curl -X POST https://api.poeditor.com/v2/projects/export \ - -d api_token="YOUR_TOKEN" \ - -d id="PROJECT_ID" \ - -d language="es" \ - -d type="key_value_json" - -# Import to POEditor -curl -X POST https://api.poeditor.com/v2/projects/upload \ - -d api_token="YOUR_TOKEN" \ - -d id="PROJECT_ID" \ - -d updating="terms_translations" \ - -d language="es" \ - -F file=@"translations/es.json" -``` - -### Best Practices - -1. **Context matters:** Use the reference field to understand where strings appear -2. **Test before committing:** Always test translations in the actual UI -3. **Keep synchronized:** Re-extract after significant UI changes -4. **Preserve formatting:** Keep placeholders like `%1`, `{0}` intact -5. **Cultural adaptation:** Some strings may need cultural context, not just literal translation - -### Troubleshooting - -**Translations not loading?** -- Check file exists: `~/.config/DankMaterialShell/translations/{language_code}.json` -- Verify JSON syntax: `python3 -m json.tool translations/es.json` -- Check console for errors: `qs -v -p .` - -**Wrong language loading?** -- Check system locale: `echo $LANG` -- Verify file naming: Must match locale prefix (es_ES → es.json) - -**Missing strings?** -- Re-run extraction: `python3 extract_translations.py` -- Compare with en.json to find new strings diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/en.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/en.json deleted file mode 100644 index 2e8d7a5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/en.json +++ /dev/null @@ -1,14342 +0,0 @@ -[ - { - "term": "%1 Animation Speed", - "context": "%1 Animation Speed", - "reference": "Modules/Settings/TypographyMotionTab.qml:300, Modules/Settings/TypographyMotionTab.qml:384", - "comment": "" - }, - { - "term": "%1 Sessions", - "context": "%1 Sessions", - "reference": "Modals/MuxModal.qml:297", - "comment": "" - }, - { - "term": "%1 active session", - "context": "%1 active session", - "reference": "Modals/MuxModal.qml:311", - "comment": "" - }, - { - "term": "%1 active sessions", - "context": "%1 active sessions", - "reference": "Modals/MuxModal.qml:312", - "comment": "" - }, - { - "term": "%1 adapter, none connected", - "context": "%1 adapter, none connected", - "reference": "Modules/Settings/NetworkTab.qml:344", - "comment": "" - }, - { - "term": "%1 adapters, none connected", - "context": "%1 adapters, none connected", - "reference": "Modules/Settings/NetworkTab.qml:345", - "comment": "" - }, - { - "term": "%1 character", - "context": "%1 character", - "reference": "Modules/Notepad/NotepadTextEditor.qml:850", - "comment": "" - }, - { - "term": "%1 characters", - "context": "%1 characters", - "reference": "Modules/Notepad/NotepadTextEditor.qml:851", - "comment": "" - }, - { - "term": "%1 connected", - "context": "%1 connected", - "reference": "Modules/Settings/NetworkTab.qml:346", - "comment": "" - }, - { - "term": "%1 custom animation duration", - "context": "%1 custom animation duration", - "reference": "Modules/Settings/TypographyMotionTab.qml:348, Modules/Settings/TypographyMotionTab.qml:432", - "comment": "" - }, - { - "term": "%1 disconnected", - "context": "%1 disconnected", - "reference": "Modules/Settings/DisplayConfigTab.qml:464", - "comment": "" - }, - { - "term": "%1 disconnected (hidden)", - "context": "%1 disconnected (hidden)", - "reference": "Modules/Settings/DisplayConfigTab.qml:465", - "comment": "" - }, - { - "term": "%1 display", - "context": "%1 display", - "reference": "Modules/Settings/DankBarTab.qml:315", - "comment": "" - }, - { - "term": "%1 displays", - "context": "%1 displays", - "reference": "Modules/Settings/DankBarTab.qml:316", - "comment": "" - }, - { - "term": "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.", - "context": "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.", - "reference": "Modules/Settings/KeybindsTab.qml:344", - "comment": "" - }, - { - "term": "%1 exists but is not included. Window rules won't apply.", - "context": "%1 exists but is not included. Window rules won't apply.", - "reference": "Modules/Settings/WindowRulesTab.qml:355", - "comment": "" - }, - { - "term": "%1 filtered", - "context": "%1 filtered", - "reference": "Modals/MuxModal.qml:314, Modals/MuxModal.qml:315", - "comment": "" - }, - { - "term": "%1 is now included in config", - "context": "%1 is now included in config", - "reference": "Services/KeybindsService.qml:265", - "comment": "" - }, - { - "term": "%1 issue found", - "context": "%1 issue found", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:232", - "comment": "greeter doctor page error count" - }, - { - "term": "%1 issues found", - "context": "%1 issues found", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:233", - "comment": "greeter doctor page error count" - }, - { - "term": "%1 notifications", - "context": "%1 notifications", - "reference": "Modules/Lock/LockScreenContent.qml:466", - "comment": "" - }, - { - "term": "%1 update", - "context": "%1 update", - "reference": "Modules/SystemUpdatePopout.qml:76", - "comment": "" - }, - { - "term": "%1 updates", - "context": "%1 updates", - "reference": "Modules/SystemUpdatePopout.qml:77", - "comment": "" - }, - { - "term": "%1 variants", - "context": "%1 variants", - "reference": "Modules/Settings/ThemeBrowser.qml:516, Modules/Settings/ThemeBrowser.qml:517", - "comment": "" - }, - { - "term": "%1 wallpaper • %2 / %3", - "context": "%1 wallpaper • %2 / %3", - "reference": "Modules/DankDash/WallpaperTab.qml:543", - "comment": "" - }, - { - "term": "%1 wallpapers • %2 / %3", - "context": "%1 wallpapers • %2 / %3", - "reference": "Modules/DankDash/WallpaperTab.qml:544", - "comment": "" - }, - { - "term": "%1 widgets", - "context": "%1 widgets", - "reference": "Modules/Settings/DankBarTab.qml:337", - "comment": "" - }, - { - "term": "%1 window", - "context": "%1 window", - "reference": "Modals/MuxModal.qml:482", - "comment": "" - }, - { - "term": "%1 windows", - "context": "%1 windows", - "reference": "Modals/MuxModal.qml:483", - "comment": "" - }, - { - "term": "%1m ago", - "context": "%1m ago", - "reference": "Services/NotificationService.qml:269", - "comment": "" - }, - { - "term": "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.", - "context": "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.", - "reference": "Modules/Settings/LockScreenTab.qml:251", - "comment": "lock screen U2F security key mode setting" - }, - { - "term": "(Default)", - "context": "(Default)", - "reference": "Modules/Settings/WallpaperTab.qml:859, Modules/Settings/WallpaperTab.qml:874, Modules/Settings/WallpaperTab.qml:881", - "comment": "default monitor label suffix" - }, - { - "term": "(Unnamed)", - "context": "(Unnamed)", - "reference": "Modules/Dock/DockContextMenu.qml:241, Modules/DankBar/Widgets/AppsDockContextMenu.qml:176", - "comment": "" - }, - { - "term": "+ %1 more", - "context": "+ %1 more", - "reference": "Modules/Lock/LockScreenContent.qml:546, Modules/Lock/LockScreenContent.qml:661", - "comment": "" - }, - { - "term": "/path/to/videos", - "context": "/path/to/videos", - "reference": "Modules/Settings/LockScreenTab.qml:315", - "comment": "" - }, - { - "term": "0 = square corners", - "context": "0 = square corners", - "reference": "Modules/Settings/ThemeColorsTab.qml:1635", - "comment": "" - }, - { - "term": "1 day", - "context": "1 day", - "reference": "Modules/Settings/NotificationsTab.qml:839, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:857, Modules/Settings/ClipboardTab.qml:103", - "comment": "notification history retention option" - }, - { - "term": "1 device connected", - "context": "1 device connected", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:37", - "comment": "KDE Connect status single device" - }, - { - "term": "1 event", - "context": "1 event", - "reference": "Modules/DankDash/Overview/CalendarOverviewCard.qml:178", - "comment": "" - }, - { - "term": "1 hour", - "context": "1 hour", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "1 hour 30 minutes", - "context": "1 hour 30 minutes", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "1 minute", - "context": "1 minute", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10, Modules/Settings/NotificationsTab.qml:65, Modules/Notifications/Center/NotificationSettings.qml:70", - "comment": "wallpaper interval" - }, - { - "term": "1 notification", - "context": "1 notification", - "reference": "Modules/Lock/LockScreenContent.qml:466", - "comment": "" - }, - { - "term": "1 second", - "context": "1 second", - "reference": "Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/PowerSleepTab.qml:482, Modules/Settings/NotificationsTab.qml:37, Modules/Notifications/Center/NotificationSettings.qml:42", - "comment": "" - }, - { - "term": "10 minutes", - "context": "10 minutes", - "reference": "Modules/Settings/PowerSleepTab.qml:10, Modules/Settings/NotificationsTab.qml:77, Modules/Notifications/Center/NotificationSettings.qml:82", - "comment": "" - }, - { - "term": "10 seconds", - "context": "10 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/PowerSleepTab.qml:482, Modules/Settings/NotificationsTab.qml:53, Modules/Notifications/Center/NotificationSettings.qml:58", - "comment": "wallpaper interval" - }, - { - "term": "10-bit Color", - "context": "10-bit Color", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:111", - "comment": "" - }, - { - "term": "12 hours", - "context": "12 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "14 days", - "context": "14 days", - "reference": "Modules/Settings/NotificationsTab.qml:845, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:863, Modules/Settings/ClipboardTab.qml:115", - "comment": "notification history retention option" - }, - { - "term": "15 minutes", - "context": "15 minutes", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "15 seconds", - "context": "15 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/NotificationsTab.qml:57, Modules/Notifications/Center/NotificationSettings.qml:62", - "comment": "wallpaper interval" - }, - { - "term": "180°", - "context": "180°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1797, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1818", - "comment": "" - }, - { - "term": "2 hours", - "context": "2 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "2 minutes", - "context": "2 minutes", - "reference": "Modules/Settings/PowerSleepTab.qml:10, Modules/Settings/NotificationsTab.qml:69, Modules/Notifications/Center/NotificationSettings.qml:74", - "comment": "" - }, - { - "term": "2 seconds", - "context": "2 seconds", - "reference": "Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/PowerSleepTab.qml:482", - "comment": "" - }, - { - "term": "20 minutes", - "context": "20 minutes", - "reference": "Modules/Settings/PowerSleepTab.qml:10", - "comment": "" - }, - { - "term": "20 seconds", - "context": "20 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129", - "comment": "wallpaper interval" - }, - { - "term": "24-Hour Format", - "context": "24-Hour Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:53", - "comment": "" - }, - { - "term": "24-hour clock", - "context": "24-hour clock", - "reference": "Modules/Settings/GreeterTab.qml:601", - "comment": "" - }, - { - "term": "24-hour format", - "context": "24-hour format", - "reference": "Modules/Settings/WallpaperTab.qml:1134", - "comment": "" - }, - { - "term": "25 seconds", - "context": "25 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "250 ms", - "context": "250 ms", - "reference": "Modules/Settings/PowerSleepTab.qml:482", - "comment": "" - }, - { - "term": "270°", - "context": "270°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1799, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1820", - "comment": "" - }, - { - "term": "3 days", - "context": "3 days", - "reference": "Modules/Settings/NotificationsTab.qml:841, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:859, Modules/Settings/ClipboardTab.qml:107", - "comment": "notification history retention option" - }, - { - "term": "3 hours", - "context": "3 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "3 minutes", - "context": "3 minutes", - "reference": "Modules/Settings/PowerSleepTab.qml:10", - "comment": "" - }, - { - "term": "3 seconds", - "context": "3 seconds", - "reference": "Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/PowerSleepTab.qml:482, Modules/Settings/NotificationsTab.qml:41, Modules/Notifications/Center/NotificationSettings.qml:46", - "comment": "" - }, - { - "term": "30 days", - "context": "30 days", - "reference": "Modules/Settings/NotificationsTab.qml:847, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:865, Modules/Settings/ClipboardTab.qml:119, Modules/Notifications/Center/HistoryNotificationList.qml:112", - "comment": "notification history filter | notification history retention option" - }, - { - "term": "30 minutes", - "context": "30 minutes", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:10", - "comment": "wallpaper interval" - }, - { - "term": "30 seconds", - "context": "30 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/NotificationsTab.qml:61, Modules/Notifications/Center/NotificationSettings.qml:66", - "comment": "wallpaper interval" - }, - { - "term": "35 seconds", - "context": "35 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "3rd party", - "context": "3rd party", - "reference": "Modules/Settings/PluginBrowser.qml:529", - "comment": "" - }, - { - "term": "4 hours", - "context": "4 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "4 seconds", - "context": "4 seconds", - "reference": "Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:129", - "comment": "" - }, - { - "term": "40 seconds", - "context": "40 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "45 seconds", - "context": "45 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "5 minutes", - "context": "5 minutes", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/WallpaperTab.qml:1020, Modules/Settings/WallpaperTab.qml:1044, Modules/Settings/PowerSleepTab.qml:10, Modules/Settings/NotificationsTab.qml:73, Modules/Notifications/Center/NotificationSettings.qml:78", - "comment": "wallpaper interval" - }, - { - "term": "5 seconds", - "context": "5 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996, Modules/Settings/PowerSleepTab.qml:103, Modules/Settings/PowerSleepTab.qml:114, Modules/Settings/PowerSleepTab.qml:129, Modules/Settings/PowerSleepTab.qml:140, Modules/Settings/PowerSleepTab.qml:482, Modules/Settings/NotificationsTab.qml:45, Modules/Settings/NotificationsTab.qml:160, Modules/Notifications/Center/NotificationSettings.qml:50, Modules/Notifications/Center/NotificationSettings.qml:89", - "comment": "wallpaper interval" - }, - { - "term": "50 seconds", - "context": "50 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "500 ms", - "context": "500 ms", - "reference": "Modules/Settings/PowerSleepTab.qml:482, Modules/Settings/PowerSleepTab.qml:492", - "comment": "" - }, - { - "term": "55 seconds", - "context": "55 seconds", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "6 hours", - "context": "6 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "7 days", - "context": "7 days", - "reference": "Modules/Settings/NotificationsTab.qml:843, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:861, Modules/Settings/ClipboardTab.qml:111, Modules/Notifications/Center/HistoryNotificationList.qml:107", - "comment": "notification history filter | notification history retention option" - }, - { - "term": "750 ms", - "context": "750 ms", - "reference": "Modules/Settings/PowerSleepTab.qml:482", - "comment": "" - }, - { - "term": "8 hours", - "context": "8 hours", - "reference": "Modules/Settings/WallpaperTab.qml:996", - "comment": "wallpaper interval" - }, - { - "term": "8 seconds", - "context": "8 seconds", - "reference": "Modules/Settings/NotificationsTab.qml:49, Modules/Notifications/Center/NotificationSettings.qml:54", - "comment": "" - }, - { - "term": "90 days", - "context": "90 days", - "reference": "Modules/Settings/ClipboardTab.qml:123", - "comment": "" - }, - { - "term": "90°", - "context": "90°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1795, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1816", - "comment": "" - }, - { - "term": "MIT License", - "context": "MIT License", - "reference": "Modules/Settings/AboutTab.qml:826", - "comment": "" - }, - { - "term": "A file with this name already exists. Do you want to overwrite it?", - "context": "A file with this name already exists. Do you want to overwrite it?", - "reference": "Modals/FileBrowser/FileBrowserOverwriteDialog.qml:61", - "comment": "" - }, - { - "term": "A modern desktop shell for Wayland compositors", - "context": "A modern desktop shell for Wayland compositors", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:55", - "comment": "greeter welcome page tagline" - }, - { - "term": "AC Power", - "context": "AC Power", - "reference": "Modules/Settings/PowerSleepTab.qml:59", - "comment": "" - }, - { - "term": "API", - "context": "API", - "reference": "Modules/Settings/AboutTab.qml:673", - "comment": "" - }, - { - "term": "Aborted", - "context": "Aborted", - "reference": "Services/CupsService.qml:769", - "comment": "" - }, - { - "term": "About", - "context": "About", - "reference": "Modals/Settings/SettingsSidebar.qml:322, Modules/Settings/AboutTab.qml:576", - "comment": "" - }, - { - "term": "Accent Color", - "context": "Accent Color", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:36", - "comment": "" - }, - { - "term": "Accept", - "context": "Accept", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:182, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:370", - "comment": "KDE Connect accept pairing button" - }, - { - "term": "Accept Jobs", - "context": "Accept Jobs", - "reference": "Modules/Settings/PrinterTab.qml:1306", - "comment": "" - }, - { - "term": "Accepting", - "context": "Accepting", - "reference": "Modules/Settings/PrinterTab.qml:1168", - "comment": "" - }, - { - "term": "Access clipboard history", - "context": "Access clipboard history", - "reference": "Modules/Settings/WidgetsTab.qml:102", - "comment": "" - }, - { - "term": "Access to notifications and do not disturb", - "context": "Access to notifications and do not disturb", - "reference": "Modules/Settings/WidgetsTab.qml:170", - "comment": "" - }, - { - "term": "Access to system controls and settings", - "context": "Access to system controls and settings", - "reference": "Modules/Settings/WidgetsTab.qml:163", - "comment": "" - }, - { - "term": "Action", - "context": "Action", - "reference": "Widgets/KeybindItem.qml:941, Widgets/KeybindItem.qml:1136, Modules/Settings/NotificationsTab.qml:586", - "comment": "" - }, - { - "term": "Action failed or terminal was closed.", - "context": "Action failed or terminal was closed.", - "reference": "Modules/Settings/GreeterTab.qml:385", - "comment": "" - }, - { - "term": "Actions", - "context": "Actions", - "reference": "Widgets/DankIconPicker.qml:51", - "comment": "" - }, - { - "term": "Activate", - "context": "Activate", - "reference": "Modules/Settings/GreeterTab.qml:122, Modules/Settings/GreeterTab.qml:170, Modules/ControlCenter/Details/NetworkDetail.qml:403", - "comment": "" - }, - { - "term": "Activate Greeter", - "context": "Activate Greeter", - "reference": "Modules/Settings/GreeterTab.qml:168", - "comment": "greeter action confirmation" - }, - { - "term": "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.", - "context": "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.", - "reference": "Modules/Settings/GreeterTab.qml:169", - "comment": "" - }, - { - "term": "Activation", - "context": "Activation", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:97", - "comment": "" - }, - { - "term": "Active", - "context": "Active", - "reference": "Modules/Settings/ThemeColorsTab.qml:1424, Modules/Settings/NetworkTab.qml:754, Modules/ControlCenter/Details/AudioInputDetail.qml:254, Modules/ControlCenter/Details/AudioOutputDetail.qml:263", - "comment": "" - }, - { - "term": "Active Color", - "context": "Active Color", - "reference": "Modules/Settings/WidgetsTabSection.qml:2742", - "comment": "" - }, - { - "term": "Active Lock Screen Monitor", - "context": "Active Lock Screen Monitor", - "reference": "Modules/Settings/LockScreenTab.qml:364", - "comment": "" - }, - { - "term": "Active tile background and icon color", - "context": "Active tile background and icon color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1557", - "comment": "control center tile color setting description" - }, - { - "term": "Active: %1", - "context": "Active: %1", - "reference": "Widgets/VpnDetailContent.qml:57", - "comment": "" - }, - { - "term": "Active: %1 +%2", - "context": "Active: %1 +%2", - "reference": "Widgets/VpnDetailContent.qml:58", - "comment": "" - }, - { - "term": "Active: None", - "context": "Active: None", - "reference": "Widgets/VpnDetailContent.qml:54", - "comment": "" - }, - { - "term": "Adapters", - "context": "Adapters", - "reference": "Modules/Settings/NetworkTab.qml:368", - "comment": "" - }, - { - "term": "Adaptive Media Width", - "context": "Adaptive Media Width", - "reference": "Modules/Settings/MediaPlayerTab.qml:50", - "comment": "" - }, - { - "term": "Add", - "context": "Add", - "reference": "Widgets/KeybindItem.qml:1830, Modules/Plugins/ListSettingWithInput.qml:126, Modules/Settings/DesktopWidgetsTab.qml:152", - "comment": "" - }, - { - "term": "Add Bar", - "context": "Add Bar", - "reference": "Modules/Settings/DankBarTab.qml:228", - "comment": "" - }, - { - "term": "Add Desktop Widget", - "context": "Add Desktop Widget", - "reference": "Modules/Settings/DesktopWidgetBrowser.qml:105, Modules/Settings/DesktopWidgetBrowser.qml:221", - "comment": "" - }, - { - "term": "Add Printer", - "context": "Add Printer", - "reference": "Modules/Settings/PrinterTab.qml:267", - "comment": "" - }, - { - "term": "Add Title", - "context": "Add Title", - "reference": "Modals/WindowRuleModal.qml:507", - "comment": "" - }, - { - "term": "Add Widget", - "context": "Add Widget", - "reference": "Modules/Settings/WidgetsTabSection.qml:804, Modules/Settings/WidgetSelectionPopup.qml:93, Modules/Settings/DesktopWidgetsTab.qml:95, Modules/ControlCenter/Components/EditControls.qml:61, Modules/ControlCenter/Components/EditControls.qml:164", - "comment": "" - }, - { - "term": "Add Widget to %1 Section", - "context": "Add Widget to %1 Section", - "reference": "Modules/Settings/WidgetSelectionPopup.qml:205", - "comment": "" - }, - { - "term": "Add a border around the dock", - "context": "Add a border around the dock", - "reference": "Modules/Settings/DockTab.qml:591", - "comment": "" - }, - { - "term": "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.", - "context": "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.", - "reference": "Modules/Settings/LauncherTab.qml:316", - "comment": "" - }, - { - "term": "Add and configure widgets that appear on your desktop", - "context": "Add and configure widgets that appear on your desktop", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:84", - "comment": "" - }, - { - "term": "Add by Address", - "context": "Add by Address", - "reference": "Modules/Settings/PrinterTab.qml:390", - "comment": "Toggle button to manually add a printer by IP or hostname" - }, - { - "term": "Adjust the number of columns in grid view mode.", - "context": "Adjust the number of columns in grid view mode.", - "reference": "Modules/Settings/LauncherTab.qml:349", - "comment": "" - }, - { - "term": "Adjust volume per scroll indent", - "context": "Adjust volume per scroll indent", - "reference": "Modules/Settings/MediaPlayerTab.qml:89", - "comment": "" - }, - { - "term": "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)", - "context": "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)", - "reference": "Modules/Settings/ThemeColorsTab.qml:538", - "comment": "" - }, - { - "term": "Advanced", - "context": "Advanced", - "reference": "Modules/Settings/PowerSleepTab.qml:579, Modules/Settings/ClipboardTab.qml:445", - "comment": "" - }, - { - "term": "Afternoon", - "context": "Afternoon", - "reference": "Services/WeatherService.qml:260", - "comment": "" - }, - { - "term": "All", - "context": "All", - "reference": "Modals/ProcessListModal.qml:377, Services/AppSearchService.qml:698, Services/AppSearchService.qml:719, dms-plugins/DankStickerSearch/DankStickerSearch.qml:101, Modals/DankLauncherV2/Controller.qml:662, Modals/DankLauncherV2/LauncherContent.qml:348, Modals/DankLauncherV2/LauncherContent.qml:624, Modules/ProcessList/ProcessListPopout.qml:155, Modules/Settings/WidgetsTabSection.qml:2476, Modules/Settings/WidgetsTabSection.qml:2530, Modules/Settings/KeybindsTab.qml:410, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:94, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:97, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:109, Modules/Notifications/Center/HistoryNotificationList.qml:87", - "comment": "notification history filter" - }, - { - "term": "All Monitors", - "context": "All Monitors", - "reference": "Modules/Settings/LockScreenTab.qml:366, Modules/Settings/LockScreenTab.qml:376, Modules/Settings/LockScreenTab.qml:386, Modules/Settings/LockScreenTab.qml:390", - "comment": "" - }, - { - "term": "All checks passed", - "context": "All checks passed", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:230", - "comment": "greeter doctor page success" - }, - { - "term": "All day", - "context": "All day", - "reference": "Modules/DankDash/Overview/CalendarOverviewCard.qml:496", - "comment": "" - }, - { - "term": "All displays", - "context": "All displays", - "reference": "Modules/Plugins/PluginSettings.qml:255, Modules/Settings/DisplayWidgetsTab.qml:401, Modules/Settings/DankBarTab.qml:313, Modules/Settings/DankBarTab.qml:450, Modules/Settings/Widgets/SettingsDisplayPicker.qml:43", - "comment": "" - }, - { - "term": "Allow clicks to pass through the widget", - "context": "Allow clicks to pass through the widget", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:344", - "comment": "" - }, - { - "term": "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close", - "context": "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close", - "reference": "Modals/FileBrowser/KeyboardHints.qml:35", - "comment": "" - }, - { - "term": "Alternative (OR)", - "context": "Alternative (OR)", - "reference": "Modules/Settings/LockScreenTab.qml:253, Modules/Settings/LockScreenTab.qml:254", - "comment": "U2F mode option: key works as standalone unlock method" - }, - { - "term": "Always Active", - "context": "Always Active", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:106", - "comment": "" - }, - { - "term": "Always Show Percentage", - "context": "Always Show Percentage", - "reference": "Modules/Settings/OSDTab.qml:78", - "comment": "" - }, - { - "term": "Always hide the dock and reveal it when hovering near the dock area", - "context": "Always hide the dock and reveal it when hovering near the dock area", - "reference": "Modules/Settings/DockTab.qml:52", - "comment": "" - }, - { - "term": "Always on icons", - "context": "Always on icons", - "reference": "Modules/Settings/WidgetsTabSection.qml:1744", - "comment": "" - }, - { - "term": "Always show a minimum of 3 workspaces, even if fewer are available", - "context": "Always show a minimum of 3 workspaces, even if fewer are available", - "reference": "Modules/Settings/WorkspacesTab.qml:51", - "comment": "" - }, - { - "term": "Always show the dock when niri's overview is open", - "context": "Always show the dock when niri's overview is open", - "reference": "Modules/Settings/DockTab.qml:82", - "comment": "" - }, - { - "term": "Always show when there's only one connected display", - "context": "Always show when there's only one connected display", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:432", - "comment": "" - }, - { - "term": "Amount", - "context": "Amount", - "reference": "Widgets/KeybindItem.qml:985", - "comment": "" - }, - { - "term": "Analog", - "context": "Analog", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:29, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:33, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:42, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:14", - "comment": "" - }, - { - "term": "Analog, digital, or stacked clock display", - "context": "Analog, digital, or stacked clock display", - "reference": "Services/DesktopWidgetRegistry.qml:41", - "comment": "Desktop clock widget description" - }, - { - "term": "Analyzing configuration...", - "context": "Analyzing configuration...", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:165", - "comment": "greeter doctor page loading text" - }, - { - "term": "Animation Duration", - "context": "Animation Duration", - "reference": "Modules/Settings/TypographyMotionTab.qml:242", - "comment": "" - }, - { - "term": "Animation Speed", - "context": "Animation Speed", - "reference": "Modules/Settings/TypographyMotionTab.qml:197, Modules/Settings/NotificationsTab.qml:316", - "comment": "" - }, - { - "term": "Anonymous Identity", - "context": "Anonymous Identity", - "reference": "Modals/WifiPasswordModal.qml:186", - "comment": "" - }, - { - "term": "Anonymous Identity (optional)", - "context": "Anonymous Identity (optional)", - "reference": "Modals/WifiPasswordModal.qml:590", - "comment": "" - }, - { - "term": "App Customizations", - "context": "App Customizations", - "reference": "Modules/Settings/LauncherTab.qml:1029", - "comment": "" - }, - { - "term": "App ID Substitutions", - "context": "App ID Substitutions", - "reference": "Modules/Settings/RunningAppsTab.qml:25", - "comment": "" - }, - { - "term": "App ID regex (e.g. ^firefox$)", - "context": "App ID regex (e.g. ^firefox$)", - "reference": "Modals/WindowRuleModal.qml:474", - "comment": "" - }, - { - "term": "App Launcher", - "context": "App Launcher", - "reference": "Modules/Settings/WidgetsTab.qml:45", - "comment": "" - }, - { - "term": "App Names", - "context": "App Names", - "reference": "Modules/Settings/LockScreenTab.qml:148, Modules/Settings/NotificationsTab.qml:85, Modules/Settings/NotificationsTab.qml:729", - "comment": "lock screen notification mode option | notification rule match field option" - }, - { - "term": "App Theming", - "context": "App Theming", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:98", - "comment": "greeter feature card title" - }, - { - "term": "Appearance", - "context": "Appearance", - "reference": "Modules/Settings/LauncherTab.qml:361", - "comment": "launcher appearance settings" - }, - { - "term": "Application Dock", - "context": "Application Dock", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:31", - "comment": "" - }, - { - "term": "Applications", - "context": "Applications", - "reference": "Modals/DankLauncherV2/Controller.qml:153, Modules/Settings/ThemeColorsTab.qml:2229, Modules/Dock/DockLauncherButton.qml:25", - "comment": "" - }, - { - "term": "Apply Changes", - "context": "Apply Changes", - "reference": "Modules/Settings/DisplayConfigTab.qml:513", - "comment": "" - }, - { - "term": "Apply GTK Colors", - "context": "Apply GTK Colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:2910", - "comment": "" - }, - { - "term": "Apply Qt Colors", - "context": "Apply Qt Colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:2944", - "comment": "" - }, - { - "term": "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.", - "context": "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.", - "reference": "Modules/Settings/GammaControlTab.qml:77", - "comment": "" - }, - { - "term": "Applying authentication changes…", - "context": "Applying authentication changes…", - "reference": "Common/settings/Processes.qml:483", - "comment": "" - }, - { - "term": "Apps", - "context": "Apps", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:353", - "comment": "" - }, - { - "term": "Apps Dock", - "context": "Apps Dock", - "reference": "Modules/Settings/WidgetsTab.qml:73", - "comment": "" - }, - { - "term": "Apps Dock Settings", - "context": "Apps Dock Settings", - "reference": "Modules/Settings/WidgetsTabSection.qml:2426", - "comment": "" - }, - { - "term": "Apps Icon", - "context": "Apps Icon", - "reference": "Modules/Settings/DockTab.qml:266, Modules/Settings/LauncherTab.qml:59", - "comment": "" - }, - { - "term": "Apps are ordered by usage frequency, then last used, then alphabetically.", - "context": "Apps are ordered by usage frequency, then last used, then alphabetically.", - "reference": "Modules/Settings/LauncherTab.qml:1175", - "comment": "" - }, - { - "term": "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.", - "context": "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.", - "reference": "Modules/Settings/LauncherTab.qml:1052", - "comment": "" - }, - { - "term": "Apps with notification popups muted. Unmute or delete to remove.", - "context": "Apps with notification popups muted. Unmute or delete to remove.", - "reference": "Modules/Settings/NotificationsTab.qml:641", - "comment": "" - }, - { - "term": "Architecture", - "context": "Architecture", - "reference": "Modules/ProcessList/SystemView.qml:72", - "comment": "system info label" - }, - { - "term": "Are you sure you want to kill session \"%1\"?", - "context": "Are you sure you want to kill session \"%1\"?", - "reference": "Modals/MuxModal.qml:101", - "comment": "" - }, - { - "term": "Arrange displays and configure resolution, refresh rate, and VRR", - "context": "Arrange displays and configure resolution, refresh rate, and VRR", - "reference": "Modules/Settings/DisplayConfigTab.qml:373", - "comment": "" - }, - { - "term": "Attach", - "context": "Attach", - "reference": "Modals/MuxModal.qml:591", - "comment": "" - }, - { - "term": "Audio", - "context": "Audio", - "reference": "Modals/Settings/SettingsSidebar.qml:245, Modules/Settings/WidgetsTabSection.qml:1239, Modules/Settings/WidgetsTabSection.qml:1448", - "comment": "" - }, - { - "term": "Audio Codec", - "context": "Audio Codec", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:644", - "comment": "" - }, - { - "term": "Audio Codec Selection", - "context": "Audio Codec Selection", - "reference": "Modules/ControlCenter/Details/BluetoothCodecSelector.qml:210", - "comment": "" - }, - { - "term": "Audio Devices", - "context": "Audio Devices", - "reference": "Modules/ControlCenter/Details/AudioOutputDetail.qml:37", - "comment": "" - }, - { - "term": "Audio Input", - "context": "Audio Input", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:127", - "comment": "" - }, - { - "term": "Audio Output", - "context": "Audio Output", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:119", - "comment": "" - }, - { - "term": "Audio Output Devices (", - "context": "Audio Output Devices (", - "reference": "Modules/DankDash/MediaDropdownOverlay.qml:249", - "comment": "" - }, - { - "term": "Audio Output Switch", - "context": "Audio Output Switch", - "reference": "Modules/Settings/OSDTab.qml:157", - "comment": "" - }, - { - "term": "Audio Visualizer", - "context": "Audio Visualizer", - "reference": "Modules/Settings/MediaPlayerTab.qml:43", - "comment": "" - }, - { - "term": "Audio system restarted", - "context": "Audio system restarted", - "reference": "Services/AudioService.qml:274", - "comment": "" - }, - { - "term": "Audio volume control", - "context": "Audio volume control", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:136", - "comment": "" - }, - { - "term": "Auth", - "context": "Auth", - "reference": "Widgets/VpnProfileDelegate.qml:57, Modules/Settings/NetworkTab.qml:1920", - "comment": "" - }, - { - "term": "Auth Type", - "context": "Auth Type", - "reference": "Widgets/VpnProfileDelegate.qml:75, Modules/Settings/NetworkTab.qml:1935", - "comment": "" - }, - { - "term": "Authenticate", - "context": "Authenticate", - "reference": "Modals/PolkitAuthModal.qml:381", - "comment": "" - }, - { - "term": "Authenticating...", - "context": "Authenticating...", - "reference": "Modules/Greetd/GreeterContent.qml:1018", - "comment": "" - }, - { - "term": "Authentication", - "context": "Authentication", - "reference": "Modals/PolkitAuthModal.qml:99", - "comment": "" - }, - { - "term": "Authentication Required", - "context": "Authentication Required", - "reference": "Modals/PolkitAuthModal.qml:227", - "comment": "" - }, - { - "term": "Authentication changes applied.", - "context": "Authentication changes applied.", - "reference": "Common/settings/Processes.qml:456", - "comment": "" - }, - { - "term": "Authentication changes apply automatically.", - "context": "Authentication changes apply automatically.", - "reference": "Modules/Settings/GreeterTab.qml:63, Modules/Settings/LockScreenTab.qml:18, Modules/Settings/LockScreenTab.qml:35", - "comment": "" - }, - { - "term": "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.", - "context": "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.", - "reference": "Modules/Settings/GreeterTab.qml:39", - "comment": "" - }, - { - "term": "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.", - "context": "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.", - "reference": "Common/settings/Processes.qml:286", - "comment": "" - }, - { - "term": "Authentication error - try again", - "context": "Authentication error - try again", - "reference": "Modules/Lock/LockScreenContent.qml:56, Modules/Greetd/GreeterContent.qml:233", - "comment": "" - }, - { - "term": "Authentication failed, please try again", - "context": "Authentication failed, please try again", - "reference": "Modals/PolkitAuthModal.qml:325", - "comment": "" - }, - { - "term": "Authorize", - "context": "Authorize", - "reference": "Modals/BluetoothPairingModal.qml:320, Modals/BluetoothPairingModal.qml:323", - "comment": "" - }, - { - "term": "Authorize pairing with ", - "context": "Authorize pairing with ", - "reference": "Modals/BluetoothPairingModal.qml:135", - "comment": "" - }, - { - "term": "Authorize service for ", - "context": "Authorize service for ", - "reference": "Modals/BluetoothPairingModal.qml:142", - "comment": "" - }, - { - "term": "Auto", - "context": "Auto", - "reference": "Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/NetworkTab.qml:260, Modules/Settings/NetworkTab.qml:883, Modules/Settings/NetworkTab.qml:887, Modules/Settings/NetworkTab.qml:888, Modules/Settings/NetworkTab.qml:891, Modules/Settings/DisplayConfigTab.qml:150, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:351, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:359, Modules/ControlCenter/Details/NetworkDetail.qml:117, Modules/ControlCenter/Details/NetworkDetail.qml:118, Modules/ControlCenter/Details/NetworkDetail.qml:121, Modules/ControlCenter/Details/NetworkDetail.qml:124", - "comment": "theme category option" - }, - { - "term": "Auto (Bar-aware)", - "context": "Auto (Bar-aware)", - "reference": "Modules/Settings/ThemeColorsTab.qml:1728, Modules/Settings/ThemeColorsTab.qml:1732, Modules/Settings/ThemeColorsTab.qml:1745, Modules/Settings/DankBarTab.qml:1120, Modules/Settings/DankBarTab.qml:1124, Modules/Settings/DankBarTab.qml:1132", - "comment": "bar shadow direction source option | shadow direction option" - }, - { - "term": "Auto (Wide)", - "context": "Auto (Wide)", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:143, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:145, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:148, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:159", - "comment": "" - }, - { - "term": "Auto Location", - "context": "Auto Location", - "reference": "Modules/Settings/TimeWeatherTab.qml:458", - "comment": "" - }, - { - "term": "Auto Popup Gaps", - "context": "Auto Popup Gaps", - "reference": "Modules/Settings/DankBarTab.qml:902", - "comment": "" - }, - { - "term": "Auto-Clear After", - "context": "Auto-Clear After", - "reference": "Modules/Settings/ClipboardTab.qml:347", - "comment": "" - }, - { - "term": "Auto-Hide Timeout", - "context": "Auto-Hide Timeout", - "reference": "Modules/Settings/ThemeColorsTab.qml:2407", - "comment": "" - }, - { - "term": "Auto-close Niri overview when launching apps.", - "context": "Auto-close Niri overview when launching apps.", - "reference": "Modules/Settings/LauncherTab.qml:500", - "comment": "" - }, - { - "term": "Auto-delete notifications older than this", - "context": "Auto-delete notifications older than this", - "reference": "Modules/Settings/NotificationsTab.qml:833", - "comment": "notification history setting" - }, - { - "term": "Auto-hide", - "context": "Auto-hide", - "reference": "Modules/Settings/DankBarTab.qml:594", - "comment": "" - }, - { - "term": "Auto-hide Dock", - "context": "Auto-hide Dock", - "reference": "Modules/Settings/DockTab.qml:51", - "comment": "" - }, - { - "term": "Auto-saving...", - "context": "Auto-saving...", - "reference": "Modules/Notepad/NotepadTextEditor.qml:870", - "comment": "" - }, - { - "term": "Autoconnect", - "context": "Autoconnect", - "reference": "Widgets/VpnProfileDelegate.qml:271, Modules/Settings/NetworkTab.qml:1495, Modules/Settings/NetworkTab.qml:1978", - "comment": "" - }, - { - "term": "Autoconnect disabled", - "context": "Autoconnect disabled", - "reference": "Services/DMSNetworkService.qml:939", - "comment": "" - }, - { - "term": "Autoconnect enabled", - "context": "Autoconnect enabled", - "reference": "Services/DMSNetworkService.qml:939", - "comment": "" - }, - { - "term": "Autofill last remembered query when opened", - "context": "Autofill last remembered query when opened", - "reference": "Modules/Settings/LauncherTab.qml:883", - "comment": "" - }, - { - "term": "Automatic Color Mode", - "context": "Automatic Color Mode", - "reference": "Modules/Settings/ThemeColorsTab.qml:1044", - "comment": "" - }, - { - "term": "Automatic Control", - "context": "Automatic Control", - "reference": "Modules/Settings/ThemeColorsTab.qml:1055, Modules/Settings/GammaControlTab.qml:139", - "comment": "" - }, - { - "term": "Automatic Cycling", - "context": "Automatic Cycling", - "reference": "Modules/Settings/WallpaperTab.qml:907, Modules/Settings/LockScreenTab.qml:336", - "comment": "" - }, - { - "term": "Automatically cycle through wallpapers in the same folder", - "context": "Automatically cycle through wallpapers in the same folder", - "reference": "Modules/Settings/WallpaperTab.qml:908", - "comment": "" - }, - { - "term": "Automatically delete entries older than this", - "context": "Automatically delete entries older than this", - "reference": "Modules/Settings/ClipboardTab.qml:348", - "comment": "" - }, - { - "term": "Automatically detect location based on IP address", - "context": "Automatically detect location based on IP address", - "reference": "Modules/Settings/GammaControlTab.qml:346", - "comment": "" - }, - { - "term": "Automatically determine your location using your IP address", - "context": "Automatically determine your location using your IP address", - "reference": "Modules/Settings/TimeWeatherTab.qml:459", - "comment": "" - }, - { - "term": "Automatically lock after", - "context": "Automatically lock after", - "reference": "Modules/Settings/PowerSleepTab.qml:201", - "comment": "" - }, - { - "term": "Automatically lock the screen when DMS starts", - "context": "Automatically lock the screen when DMS starts", - "reference": "Modules/Settings/LockScreenTab.qml:211", - "comment": "" - }, - { - "term": "Automatically lock the screen when the system prepares to suspend", - "context": "Automatically lock the screen when the system prepares to suspend", - "reference": "Modules/Settings/PowerSleepTab.qml:93, Modules/Settings/LockScreenTab.qml:192", - "comment": "" - }, - { - "term": "Automation", - "context": "Automation", - "reference": "Modules/Settings/ThemeColorsTab.qml:1381", - "comment": "" - }, - { - "term": "Available", - "context": "Available", - "reference": "Modules/Settings/PrinterTab.qml:202, Modules/ControlCenter/Details/AudioInputDetail.qml:254, Modules/ControlCenter/Details/AudioOutputDetail.qml:263", - "comment": "" - }, - { - "term": "Available Layouts", - "context": "Available Layouts", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:207", - "comment": "" - }, - { - "term": "Available Networks", - "context": "Available Networks", - "reference": "Modules/Settings/NetworkTab.qml:1009", - "comment": "" - }, - { - "term": "Available Plugins", - "context": "Available Plugins", - "reference": "Modules/Settings/PluginsTab.qml:300", - "comment": "" - }, - { - "term": "Available Screens (%1)", - "context": "Available Screens (%1)", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:199", - "comment": "" - }, - { - "term": "Available in Detailed and Forecast view modes", - "context": "Available in Detailed and Forecast view modes", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:121", - "comment": "" - }, - { - "term": "Available.", - "context": "Available.", - "reference": "Modules/Settings/GreeterTab.qml:63", - "comment": "" - }, - { - "term": "BSSID", - "context": "BSSID", - "reference": "Modules/Settings/NetworkTab.qml:1443", - "comment": "" - }, - { - "term": "Back", - "context": "Back", - "reference": "Modals/Greeter/GreeterModal.qml:285, Modules/DankBar/Widgets/SystemTrayBar.qml:1729", - "comment": "greeter back button" - }, - { - "term": "Backend", - "context": "Backend", - "reference": "Modules/Settings/AboutTab.qml:632, Modules/Settings/NetworkTab.qml:170", - "comment": "" - }, - { - "term": "Background", - "context": "Background", - "reference": "Modules/Settings/GreeterTab.qml:650", - "comment": "" - }, - { - "term": "Background Blur", - "context": "Background Blur", - "reference": "Modules/Settings/ThemeColorsTab.qml:1831, Modules/Settings/ThemeColorsTab.qml:1839", - "comment": "" - }, - { - "term": "Background Opacity", - "context": "Background Opacity", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:63, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:39", - "comment": "" - }, - { - "term": "Background authentication sync failed. Trying terminal mode.", - "context": "Background authentication sync failed. Trying terminal mode.", - "reference": "Common/settings/Processes.qml:467", - "comment": "" - }, - { - "term": "Background image", - "context": "Background image", - "reference": "Modals/Greeter/GreeterCompletePage.qml:382", - "comment": "greeter wallpaper description" - }, - { - "term": "Backlight device", - "context": "Backlight device", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:331", - "comment": "" - }, - { - "term": "Balance power and performance", - "context": "Balance power and performance", - "reference": "Common/Theme.qml:1487", - "comment": "power profile description" - }, - { - "term": "Balanced", - "context": "Balanced", - "reference": "Common/Theme.qml:1474", - "comment": "power profile option" - }, - { - "term": "Balanced palette with focused accents (default).", - "context": "Balanced palette with focused accents (default).", - "reference": "Common/Theme.qml:468", - "comment": "" - }, - { - "term": "Bar Configurations", - "context": "Bar Configurations", - "reference": "Modules/Settings/DankBarTab.qml:212", - "comment": "" - }, - { - "term": "Bar Shadows", - "context": "Bar Shadows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1820", - "comment": "" - }, - { - "term": "Bar Transparency", - "context": "Bar Transparency", - "reference": "Modules/Settings/DankBarTab.qml:1006", - "comment": "" - }, - { - "term": "Base color for shadows (opacity is applied automatically)", - "context": "Base color for shadows (opacity is applied automatically)", - "reference": "Modules/Settings/ThemeColorsTab.qml:1689", - "comment": "" - }, - { - "term": "Base duration for animations (drag to use Custom)", - "context": "Base duration for animations (drag to use Custom)", - "reference": "Modules/Settings/NotificationsTab.qml:359", - "comment": "" - }, - { - "term": "Battery", - "context": "Battery", - "reference": "Modules/Settings/WidgetsTabSection.qml:1284, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/PowerSleepTab.qml:59, Modules/Settings/WidgetsTab.qml:176, Modules/ControlCenter/Models/WidgetModel.qml:161, Modules/ControlCenter/Widgets/BatteryPill.qml:17", - "comment": "" - }, - { - "term": "Battery %1", - "context": "Battery %1", - "reference": "Modules/DankBar/Popouts/BatteryPopout.qml:396", - "comment": "" - }, - { - "term": "Battery Charge Limit", - "context": "Battery Charge Limit", - "reference": "Modules/Settings/PowerSleepTab.qml:587", - "comment": "" - }, - { - "term": "Battery and power management", - "context": "Battery and power management", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:162", - "comment": "" - }, - { - "term": "Battery level and power management", - "context": "Battery level and power management", - "reference": "Modules/Settings/WidgetsTab.qml:177", - "comment": "" - }, - { - "term": "Behavior", - "context": "Behavior", - "reference": "Modules/Settings/DockTab.qml:142, Modules/Settings/ClipboardTab.qml:417", - "comment": "" - }, - { - "term": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen", - "context": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen", - "reference": "Modules/Settings/LockScreenTab.qml:178", - "comment": "" - }, - { - "term": "Binds Include Missing", - "context": "Binds Include Missing", - "reference": "Modules/Settings/KeybindsTab.qml:328", - "comment": "" - }, - { - "term": "Binds include added", - "context": "Binds include added", - "reference": "Services/KeybindsService.qml:265", - "comment": "" - }, - { - "term": "Bit Depth", - "context": "Bit Depth", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1248", - "comment": "" - }, - { - "term": "Block Out", - "context": "Block Out", - "reference": "Modules/Settings/WindowRulesTab.qml:545", - "comment": "" - }, - { - "term": "Block Out From", - "context": "Block Out From", - "reference": "Modals/WindowRuleModal.qml:727", - "comment": "" - }, - { - "term": "Block notifications", - "context": "Block notifications", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:86", - "comment": "" - }, - { - "term": "Blocked", - "context": "Blocked", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:532", - "comment": "" - }, - { - "term": "Blue light filter", - "context": "Blue light filter", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:69", - "comment": "" - }, - { - "term": "Bluetooth", - "context": "Bluetooth", - "reference": "Modules/Settings/WidgetsTabSection.qml:1229, Modules/Settings/WidgetsTabSection.qml:1448, Modules/ControlCenter/Models/WidgetModel.qml:110, Modules/ControlCenter/Components/DragDropGrid.qml:313", - "comment": "bluetooth status" - }, - { - "term": "Bluetooth Settings", - "context": "Bluetooth Settings", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:96", - "comment": "" - }, - { - "term": "Bluetooth not available", - "context": "Bluetooth not available", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:115", - "comment": "" - }, - { - "term": "Blur Border Color", - "context": "Blur Border Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:130, Modules/Settings/ThemeColorsTab.qml:1850", - "comment": "" - }, - { - "term": "Blur Border Opacity", - "context": "Blur Border Opacity", - "reference": "Modules/Settings/ThemeColorsTab.qml:1888", - "comment": "" - }, - { - "term": "Blur Wallpaper Layer", - "context": "Blur Wallpaper Layer", - "reference": "Modules/Settings/WallpaperTab.qml:1272", - "comment": "" - }, - { - "term": "Blur on Overview", - "context": "Blur on Overview", - "reference": "Modules/Settings/WallpaperTab.qml:782", - "comment": "" - }, - { - "term": "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.", - "context": "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.", - "reference": "Modules/Settings/ThemeColorsTab.qml:1840", - "comment": "" - }, - { - "term": "Blur wallpaper when niri overview is open", - "context": "Blur wallpaper when niri overview is open", - "reference": "Modules/Settings/WallpaperTab.qml:783", - "comment": "" - }, - { - "term": "Body", - "context": "Body", - "reference": "Modules/Settings/NotificationsTab.qml:97", - "comment": "notification rule match field option" - }, - { - "term": "Border", - "context": "Border", - "reference": "Modules/Settings/DockTab.qml:584, Modules/Settings/DockTab.qml:590, Modules/Settings/LauncherTab.qml:432, Modules/Settings/DankBarTab.qml:1384", - "comment": "launcher border option" - }, - { - "term": "Border Color", - "context": "Border Color", - "reference": "Modules/Settings/DockTab.qml:597, Modules/Settings/WorkspacesTab.qml:368", - "comment": "" - }, - { - "term": "Border Opacity", - "context": "Border Opacity", - "reference": "Modules/Settings/DockTab.qml:634", - "comment": "" - }, - { - "term": "Border Size", - "context": "Border Size", - "reference": "Modules/Settings/ThemeColorsTab.qml:1990, Modules/Settings/ThemeColorsTab.qml:2093, Modules/Settings/ThemeColorsTab.qml:2196", - "comment": "" - }, - { - "term": "Border Thickness", - "context": "Border Thickness", - "reference": "Modules/Settings/DockTab.qml:645", - "comment": "" - }, - { - "term": "Border color around blurred surfaces", - "context": "Border color around blurred surfaces", - "reference": "Modules/Settings/ThemeColorsTab.qml:1851", - "comment": "" - }, - { - "term": "Border with BG", - "context": "Border with BG", - "reference": "Modals/WindowRuleModal.qml:713", - "comment": "" - }, - { - "term": "Bottom", - "context": "Bottom", - "reference": "Modules/Settings/ThemeColorsTab.qml:1728, Modules/Settings/ThemeColorsTab.qml:1738, Modules/Settings/ThemeColorsTab.qml:1751, Modules/Settings/DockTab.qml:102, Modules/Settings/DankBarTab.qml:286, Modules/Settings/DankBarTab.qml:542, Modules/Settings/DankBarTab.qml:1153, Modules/Settings/DankBarTab.qml:1161, Modules/Settings/DankBarTab.qml:1175", - "comment": "shadow direction option" - }, - { - "term": "Bottom Center", - "context": "Bottom Center", - "reference": "Modules/Settings/OSDTab.qml:45, Modules/Settings/OSDTab.qml:51, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:66, Modules/Settings/NotificationsTab.qml:227, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:244", - "comment": "screen position option" - }, - { - "term": "Bottom Left", - "context": "Bottom Left", - "reference": "Modules/Settings/OSDTab.qml:43, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:64, Modules/Settings/NotificationsTab.qml:221, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:250, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:144", - "comment": "screen position option" - }, - { - "term": "Bottom Right", - "context": "Bottom Right", - "reference": "Modules/Settings/OSDTab.qml:41, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:62, Modules/Settings/NotificationsTab.qml:225, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:247, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:144", - "comment": "screen position option" - }, - { - "term": "Bottom Section", - "context": "Bottom Section", - "reference": "Modules/Settings/WidgetsTab.qml:1087", - "comment": "" - }, - { - "term": "Bottom dock for pinned and running applications", - "context": "Bottom dock for pinned and running applications", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:32", - "comment": "" - }, - { - "term": "Brightness", - "context": "Brightness", - "reference": "Modules/Settings/WidgetsTabSection.qml:1269, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/DockTab.qml:484, Modules/Settings/LauncherTab.qml:276, Modules/Settings/OSDTab.qml:117", - "comment": "" - }, - { - "term": "Brightness Slider", - "context": "Brightness Slider", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:143", - "comment": "" - }, - { - "term": "Brightness Value", - "context": "Brightness Value", - "reference": "Modules/Settings/WidgetsTabSection.qml:1274, Modules/Settings/WidgetsTabSection.qml:1448", - "comment": "" - }, - { - "term": "Brightness control not available", - "context": "Brightness control not available", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:147, Modules/ControlCenter/Models/WidgetModel.qml:148", - "comment": "" - }, - { - "term": "Browse", - "context": "Browse", - "reference": "Modals/DankLauncherV2/Controller.qml:160, Modals/DankLauncherV2/Controller.qml:1235, Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/GreeterTab.qml:683, Modules/Settings/PluginsTab.qml:209, Modules/Settings/LockScreenTab.qml:327", - "comment": "theme category option" - }, - { - "term": "Browse Files", - "context": "Browse Files", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:151, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:322", - "comment": "KDE Connect browse tooltip" - }, - { - "term": "Browse Plugins", - "context": "Browse Plugins", - "reference": "Modules/Settings/PluginBrowser.qml:147, Modules/Settings/PluginBrowser.qml:257, Modules/Settings/DesktopWidgetsTab.qml:101", - "comment": "plugin browser header | plugin browser window title" - }, - { - "term": "Browse Themes", - "context": "Browse Themes", - "reference": "Modules/Settings/ThemeColorsTab.qml:790, Modules/Settings/ThemeBrowser.qml:146, Modules/Settings/ThemeBrowser.qml:243", - "comment": "browse themes button | theme browser header | theme browser window title" - }, - { - "term": "Browse or search plugins", - "context": "Browse or search plugins", - "reference": "Modals/DankLauncherV2/ResultsList.qml:488", - "comment": "" - }, - { - "term": "Button Color", - "context": "Button Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1588", - "comment": "" - }, - { - "term": "CPU", - "context": "CPU", - "reference": "Modules/ProcessList/SystemView.qml:76, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:86", - "comment": "" - }, - { - "term": "CPU Graph", - "context": "CPU Graph", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:97", - "comment": "" - }, - { - "term": "CPU Temperature", - "context": "CPU Temperature", - "reference": "Modules/Settings/WidgetsTab.qml:132, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:108", - "comment": "" - }, - { - "term": "CPU Usage", - "context": "CPU Usage", - "reference": "Modules/Settings/WidgetsTab.qml:108", - "comment": "" - }, - { - "term": "CPU temperature display", - "context": "CPU temperature display", - "reference": "Modules/Settings/WidgetsTab.qml:133", - "comment": "" - }, - { - "term": "CPU usage indicator", - "context": "CPU usage indicator", - "reference": "Modules/Settings/WidgetsTab.qml:109", - "comment": "" - }, - { - "term": "CPU, memory, network, and disk monitoring", - "context": "CPU, memory, network, and disk monitoring", - "reference": "Services/DesktopWidgetRegistry.qml:56", - "comment": "System monitor widget description" - }, - { - "term": "CUPS Insecure Filter Warning", - "context": "CUPS Insecure Filter Warning", - "reference": "Services/CupsService.qml:825", - "comment": "" - }, - { - "term": "CUPS Missing Filter Warning", - "context": "CUPS Missing Filter Warning", - "reference": "Services/CupsService.qml:824", - "comment": "" - }, - { - "term": "CUPS Print Server", - "context": "CUPS Print Server", - "reference": "Modules/Settings/PrinterTab.qml:163", - "comment": "" - }, - { - "term": "CUPS not available", - "context": "CUPS not available", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:202", - "comment": "" - }, - { - "term": "Camera", - "context": "Camera", - "reference": "Modules/Settings/WidgetsTabSection.qml:1825", - "comment": "" - }, - { - "term": "Cancel", - "context": "Cancel", - "reference": "Modals/WindowRuleModal.qml:1130, Modals/WorkspaceRenameModal.qml:161, Modals/BluetoothPairingModal.qml:272, Modals/PolkitAuthModal.qml:354, Modals/WifiPasswordModal.qml:691, Widgets/KeybindItem.qml:1814, Modals/DankLauncherV2/LauncherContent.qml:1033, Modals/FileBrowser/FileBrowserOverwriteDialog.qml:83, Modules/Settings/PluginBrowser.qml:122, Modules/Settings/PluginBrowser.qml:832, Modules/Settings/GreeterTab.qml:180, Modules/Settings/ThemeBrowser.qml:121, Modules/Settings/DisplayConfigTab.qml:256, Modules/Settings/DisplayConfigTab.qml:301, Modules/Settings/AudioTab.qml:726", - "comment": "" - }, - { - "term": "Cancel all jobs for \"%1\"?", - "context": "Cancel all jobs for \"%1\"?", - "reference": "Modules/Settings/PrinterTab.qml:1385", - "comment": "" - }, - { - "term": "Canceled", - "context": "Canceled", - "reference": "Services/CupsService.qml:767", - "comment": "" - }, - { - "term": "Cannot pair", - "context": "Cannot pair", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:557", - "comment": "" - }, - { - "term": "Capabilities", - "context": "Capabilities", - "reference": "Modules/Settings/AboutTab.qml:732", - "comment": "" - }, - { - "term": "Capacity", - "context": "Capacity", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:177, Modules/DankBar/Popouts/BatteryPopout.qml:333, Modules/DankBar/Popouts/BatteryPopout.qml:491", - "comment": "" - }, - { - "term": "Caps Lock", - "context": "Caps Lock", - "reference": "Modules/Settings/OSDTab.qml:141", - "comment": "" - }, - { - "term": "Caps Lock Indicator", - "context": "Caps Lock Indicator", - "reference": "Modules/Settings/WidgetsTab.qml:197", - "comment": "" - }, - { - "term": "Caps Lock is on", - "context": "Caps Lock is on", - "reference": "Modules/Lock/LockScreenContent.qml:1117", - "comment": "" - }, - { - "term": "Center Section", - "context": "Center Section", - "reference": "Modules/Settings/WidgetsTab.qml:1020", - "comment": "" - }, - { - "term": "Center Single Column", - "context": "Center Single Column", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:354", - "comment": "" - }, - { - "term": "Center Tiling", - "context": "Center Tiling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:47", - "comment": "" - }, - { - "term": "Certificate Password", - "context": "Certificate Password", - "reference": "Modals/WifiPasswordModal.qml:177", - "comment": "" - }, - { - "term": "Change Song", - "context": "Change Song", - "reference": "Modules/Settings/MediaPlayerTab.qml:58", - "comment": "media scroll wheel option" - }, - { - "term": "Change Volume", - "context": "Change Volume", - "reference": "Modules/Settings/MediaPlayerTab.qml:58", - "comment": "media scroll wheel option" - }, - { - "term": "Change bar appearance", - "context": "Change bar appearance", - "reference": "Modules/Settings/ThemeColorsTab.qml:1507", - "comment": "" - }, - { - "term": "Change the locale used by the DMS interface.", - "context": "Change the locale used by the DMS interface.", - "reference": "Modules/Settings/LocaleTab.qml:57", - "comment": "" - }, - { - "term": "Change the locale used for date and time formatting, independent of the interface language.", - "context": "Change the locale used for date and time formatting, independent of the interface language.", - "reference": "Modules/Settings/LocaleTab.qml:76", - "comment": "" - }, - { - "term": "Channel", - "context": "Channel", - "reference": "Modules/Settings/NetworkTab.qml:1428", - "comment": "" - }, - { - "term": "Charging", - "context": "Charging", - "reference": "Services/BatteryService.qml:136, Services/BatteryService.qml:165, Modules/ControlCenter/Widgets/BatteryPill.qml:25", - "comment": "battery status" - }, - { - "term": "Check for system updates", - "context": "Check for system updates", - "reference": "Modules/Settings/WidgetsTab.qml:247", - "comment": "" - }, - { - "term": "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.", - "context": "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.", - "reference": "Modules/Settings/GreeterTab.qml:451", - "comment": "" - }, - { - "term": "Checking for updates...", - "context": "Checking for updates...", - "reference": "Modules/SystemUpdatePopout.qml:147", - "comment": "" - }, - { - "term": "Checking whether sudo authentication is needed…", - "context": "Checking whether sudo authentication is needed…", - "reference": "Modules/Settings/GreeterTab.qml:193", - "comment": "" - }, - { - "term": "Checking...", - "context": "Checking...", - "reference": "Modules/SystemUpdatePopout.qml:70", - "comment": "" - }, - { - "term": "Checking…", - "context": "Checking…", - "reference": "Modules/Settings/GreeterTab.qml:473", - "comment": "greeter status loading" - }, - { - "term": "Choose Color", - "context": "Choose Color", - "reference": "Modals/DankColorPickerModal.qml:20, Modules/Settings/Widgets/SettingsColorPicker.qml:13", - "comment": "" - }, - { - "term": "Choose Dark Mode Color", - "context": "Choose Dark Mode Color", - "reference": "Modules/Settings/WallpaperTab.qml:706", - "comment": "dark mode wallpaper color picker title" - }, - { - "term": "Choose Dock Launcher Logo Color", - "context": "Choose Dock Launcher Logo Color", - "reference": "Modules/Settings/DockTab.qml:450", - "comment": "" - }, - { - "term": "Choose Launcher Logo Color", - "context": "Choose Launcher Logo Color", - "reference": "Modules/Settings/LauncherTab.qml:242", - "comment": "" - }, - { - "term": "Choose Light Mode Color", - "context": "Choose Light Mode Color", - "reference": "Modules/Settings/WallpaperTab.qml:516", - "comment": "light mode wallpaper color picker title" - }, - { - "term": "Choose Wallpaper Color", - "context": "Choose Wallpaper Color", - "reference": "Modules/Settings/WallpaperTab.qml:180", - "comment": "wallpaper color picker title" - }, - { - "term": "Choose a color", - "context": "Choose a color", - "reference": "Modules/ControlCenter/Widgets/ColorPickerPill.qml:14", - "comment": "" - }, - { - "term": "Choose colors from palette", - "context": "Choose colors from palette", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:180", - "comment": "" - }, - { - "term": "Choose how the weather widget is displayed", - "context": "Choose how the weather widget is displayed", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:12", - "comment": "" - }, - { - "term": "Choose how this bar resolves shadow direction", - "context": "Choose how this bar resolves shadow direction", - "reference": "Modules/Settings/DankBarTab.qml:1118", - "comment": "" - }, - { - "term": "Choose icon", - "context": "Choose icon", - "reference": "Widgets/DankIconPicker.qml:100", - "comment": "" - }, - { - "term": "Choose the background color for widgets", - "context": "Choose the background color for widgets", - "reference": "Modules/Settings/ThemeColorsTab.qml:1522", - "comment": "" - }, - { - "term": "Choose the border accent color", - "context": "Choose the border accent color", - "reference": "Modules/Settings/DockTab.qml:598", - "comment": "" - }, - { - "term": "Choose the logo displayed on the launcher button in DankBar", - "context": "Choose the logo displayed on the launcher button in DankBar", - "reference": "Modules/Settings/LauncherTab.qml:41", - "comment": "" - }, - { - "term": "Choose where notification popups appear on screen", - "context": "Choose where notification popups appear on screen", - "reference": "Modules/Settings/NotificationsTab.qml:213", - "comment": "" - }, - { - "term": "Choose where on-screen displays appear on screen", - "context": "Choose where on-screen displays appear on screen", - "reference": "Modules/Settings/OSDTab.qml:31", - "comment": "" - }, - { - "term": "Choose which displays show this widget", - "context": "Choose which displays show this widget", - "reference": "Modules/Plugins/PluginSettings.qml:246", - "comment": "" - }, - { - "term": "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.", - "context": "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.", - "reference": "Modules/Settings/LockScreenTab.qml:353", - "comment": "" - }, - { - "term": "Chroma Style", - "context": "Chroma Style", - "reference": "dms-plugins/DankNotepadModule/DankNotepadModuleSettings.qml:74", - "comment": "" - }, - { - "term": "Cipher", - "context": "Cipher", - "reference": "Widgets/VpnProfileDelegate.qml:51, Modules/Settings/NetworkTab.qml:1915", - "comment": "" - }, - { - "term": "Circle", - "context": "Circle", - "reference": "Modules/Settings/DockTab.qml:177", - "comment": "dock indicator style option" - }, - { - "term": "Class regex (e.g. ^firefox$)", - "context": "Class regex (e.g. ^firefox$)", - "reference": "Modals/WindowRuleModal.qml:474", - "comment": "" - }, - { - "term": "Clear", - "context": "Clear", - "reference": "Modules/Settings/PrinterTab.qml:1386, Modules/Notifications/Center/NotificationHeader.qml:117", - "comment": "" - }, - { - "term": "Clear All", - "context": "Clear All", - "reference": "Modals/Clipboard/ClipboardHeader.qml:76, Modals/Clipboard/ClipboardHistoryPopout.qml:148, Modals/Clipboard/ClipboardHistoryModal.qml:146, Modules/Settings/PrinterTab.qml:1370, Modules/DankBar/Widgets/ClipboardButton.qml:254", - "comment": "" - }, - { - "term": "Clear All Jobs", - "context": "Clear All Jobs", - "reference": "Modules/Settings/PrinterTab.qml:1384", - "comment": "" - }, - { - "term": "Clear History?", - "context": "Clear History?", - "reference": "Modals/Clipboard/ClipboardContent.qml:38, Modules/DankBar/DankBarContent.qml:639", - "comment": "" - }, - { - "term": "Clear Sky", - "context": "Clear Sky", - "reference": "Services/WeatherService.qml:122, Services/WeatherService.qml:123", - "comment": "" - }, - { - "term": "Clear all history when server starts", - "context": "Clear all history when server starts", - "reference": "Modules/Settings/ClipboardTab.qml:426", - "comment": "" - }, - { - "term": "Clear at Startup", - "context": "Clear at Startup", - "reference": "Modules/Settings/ClipboardTab.qml:425", - "comment": "" - }, - { - "term": "Click 'Setup' to create %1 and add include to config.", - "context": "Click 'Setup' to create %1 and add include to config.", - "reference": "Modules/Settings/KeybindsTab.qml:342", - "comment": "" - }, - { - "term": "Click 'Setup' to create %1 and add include to your compositor config.", - "context": "Click 'Setup' to create %1 and add include to your compositor config.", - "reference": "Modules/Settings/WindowRulesTab.qml:355", - "comment": "" - }, - { - "term": "Click 'Setup' to create cursor config and add include to your compositor config.", - "context": "Click 'Setup' to create cursor config and add include to your compositor config.", - "reference": "Modules/Settings/ThemeColorsTab.qml:2306", - "comment": "" - }, - { - "term": "Click 'Setup' to create the outputs config and add include to your compositor config.", - "context": "Click 'Setup' to create the outputs config and add include to your compositor config.", - "reference": "Modules/Settings/DisplayConfig/IncludeWarningBox.qml:63", - "comment": "" - }, - { - "term": "Click Import to add a .ovpn or .conf", - "context": "Click Import to add a .ovpn or .conf", - "reference": "Widgets/VpnDetailContent.qml:184, Modules/Settings/NetworkTab.qml:1678", - "comment": "" - }, - { - "term": "Click Refresh to check status.", - "context": "Click Refresh to check status.", - "reference": "Modules/Settings/GreeterTab.qml:473", - "comment": "greeter status placeholder" - }, - { - "term": "Click Through", - "context": "Click Through", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:343, Modules/Settings/DankBarTab.qml:679", - "comment": "" - }, - { - "term": "Click any shortcut to edit. Changes save to %1", - "context": "Click any shortcut to edit. Changes save to %1", - "reference": "Modules/Settings/KeybindsTab.qml:242", - "comment": "" - }, - { - "term": "Click to capture", - "context": "Click to capture", - "reference": "Widgets/KeybindItem.qml:662", - "comment": "" - }, - { - "term": "Click to select a custom theme JSON file", - "context": "Click to select a custom theme JSON file", - "reference": "Modules/Settings/ThemeColorsTab.qml:583", - "comment": "custom theme file hint" - }, - { - "term": "Clip", - "context": "Clip", - "reference": "Modules/Settings/WindowRulesTab.qml:549", - "comment": "" - }, - { - "term": "Clip to Geometry", - "context": "Clip to Geometry", - "reference": "Modals/WindowRuleModal.qml:705", - "comment": "" - }, - { - "term": "Clipboard", - "context": "Clipboard", - "reference": "Modals/Settings/SettingsSidebar.qml:257", - "comment": "" - }, - { - "term": "Clipboard History", - "context": "Clipboard History", - "reference": "Modals/Clipboard/ClipboardHeader.qml:34", - "comment": "" - }, - { - "term": "Clipboard Manager", - "context": "Clipboard Manager", - "reference": "Modules/Settings/WidgetsTab.qml:101", - "comment": "" - }, - { - "term": "Clipboard sent", - "context": "Clipboard sent", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:117, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:300", - "comment": "KDE Connect clipboard action | Phone Connect clipboard action" - }, - { - "term": "Clipboard works but nothing saved to disk", - "context": "Clipboard works but nothing saved to disk", - "reference": "Modules/Settings/ClipboardTab.qml:456", - "comment": "" - }, - { - "term": "Clock", - "context": "Clock", - "reference": "Modules/Settings/WidgetsTab.qml:80", - "comment": "" - }, - { - "term": "Clock Style", - "context": "Clock Style", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:28, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:11", - "comment": "" - }, - { - "term": "Close", - "context": "Close", - "reference": "Modules/SystemUpdatePopout.qml:307, Modals/NetworkWiredInfoModal.qml:129, Modals/MuxModal.qml:594, Modals/NetworkInfoModal.qml:129, Modules/DankBar/Widgets/RunningApps.qml:882", - "comment": "" - }, - { - "term": "Close All Windows", - "context": "Close All Windows", - "reference": "Modules/Dock/DockContextMenu.qml:546, Modules/DankBar/Widgets/AppsDockContextMenu.qml:445", - "comment": "" - }, - { - "term": "Close Overview on Launch", - "context": "Close Overview on Launch", - "reference": "Modules/Settings/LauncherTab.qml:499", - "comment": "" - }, - { - "term": "Close Window", - "context": "Close Window", - "reference": "dms-plugins/DankHyprlandWindows/DankHyprlandWindows.qml:141, Modules/Dock/DockContextMenu.qml:546, Modules/DankBar/Widgets/AppsDockContextMenu.qml:447", - "comment": "" - }, - { - "term": "Color", - "context": "Color", - "reference": "Modules/Settings/LauncherTab.qml:459, Modules/Settings/DankBarTab.qml:1193, Modules/Settings/DankBarTab.qml:1267, Modules/Settings/DankBarTab.qml:1392, Modules/Settings/DankBarTab.qml:1482, Modules/Settings/Widgets/SettingsColorPicker.qml:29", - "comment": "border color" - }, - { - "term": "Color Gamut", - "context": "Color Gamut", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:138", - "comment": "" - }, - { - "term": "Color Management", - "context": "Color Management", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1250", - "comment": "" - }, - { - "term": "Color Mode", - "context": "Color Mode", - "reference": "Modules/Settings/ThemeColorsTab.qml:1477", - "comment": "" - }, - { - "term": "Color Override", - "context": "Color Override", - "reference": "Modules/Settings/DockTab.qml:367, Modules/Settings/LauncherTab.qml:159", - "comment": "" - }, - { - "term": "Color Picker", - "context": "Color Picker", - "reference": "Services/AppSearchService.qml:201, Modules/Settings/WidgetsTab.qml:239, Modules/ControlCenter/Models/WidgetModel.qml:179, Modules/ControlCenter/Widgets/ColorPickerPill.qml:13", - "comment": "" - }, - { - "term": "Color Temperature", - "context": "Color Temperature", - "reference": "Modules/Settings/GammaControlTab.qml:105", - "comment": "" - }, - { - "term": "Color displayed on monitors without the lock screen", - "context": "Color displayed on monitors without the lock screen", - "reference": "Modules/Settings/LockScreenTab.qml:421", - "comment": "" - }, - { - "term": "Color for primary action buttons", - "context": "Color for primary action buttons", - "reference": "Modules/Settings/ThemeColorsTab.qml:1589", - "comment": "" - }, - { - "term": "Color temperature for day time", - "context": "Color temperature for day time", - "reference": "Modules/Settings/GammaControlTab.qml:125", - "comment": "" - }, - { - "term": "Color temperature for night mode", - "context": "Color temperature for night mode", - "reference": "Modules/Settings/GammaControlTab.qml:106", - "comment": "" - }, - { - "term": "Color theme for syntax highlighting.", - "context": "Color theme for syntax highlighting.", - "reference": "dms-plugins/DankNotepadModule/DankNotepadModuleSettings.qml:77", - "comment": "" - }, - { - "term": "Color theme for syntax highlighting. %1 themes available.", - "context": "Color theme for syntax highlighting. %1 themes available.", - "reference": "dms-plugins/DankNotepadModule/DankNotepadModuleSettings.qml:76", - "comment": "" - }, - { - "term": "Color theme from DMS registry", - "context": "Color theme from DMS registry", - "reference": "Modules/Settings/ThemeColorsTab.qml:246", - "comment": "registry theme description" - }, - { - "term": "Colorful", - "context": "Colorful", - "reference": "Modules/Settings/ThemeColorsTab.qml:1508", - "comment": "widget style option" - }, - { - "term": "Colorful mix of bright contrasting accents.", - "context": "Colorful mix of bright contrasting accents.", - "reference": "Common/Theme.qml:488", - "comment": "" - }, - { - "term": "Colorize Active", - "context": "Colorize Active", - "reference": "Modules/Settings/WidgetsTabSection.qml:2702", - "comment": "" - }, - { - "term": "Colors from wallpaper", - "context": "Colors from wallpaper", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:91", - "comment": "greeter feature card description" - }, - { - "term": "Column", - "context": "Column", - "reference": "Modules/Settings/DankBarTab.qml:729, Modules/Settings/DankBarTab.qml:766", - "comment": "" - }, - { - "term": "Column Display", - "context": "Column Display", - "reference": "Modals/WindowRuleModal.qml:749", - "comment": "" - }, - { - "term": "Column Width", - "context": "Column Width", - "reference": "Modals/WindowRuleModal.qml:619", - "comment": "" - }, - { - "term": "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).", - "context": "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).", - "reference": "Modules/Settings/MuxTab.qml:96", - "comment": "" - }, - { - "term": "Command", - "context": "Command", - "reference": "Widgets/KeybindItem.qml:1466, Modules/Settings/DesktopWidgetInstanceCard.qml:386", - "comment": "" - }, - { - "term": "Commands", - "context": "Commands", - "reference": "Modals/DankLauncherV2/Controller.qml:174", - "comment": "" - }, - { - "term": "Communication", - "context": "Communication", - "reference": "Widgets/DankIconPicker.qml:35", - "comment": "" - }, - { - "term": "Community themes", - "context": "Community themes", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:107", - "comment": "greeter feature card description" - }, - { - "term": "Compact", - "context": "Compact", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:15, Modules/Settings/NotificationsTab.qml:270", - "comment": "" - }, - { - "term": "Compact Mode", - "context": "Compact Mode", - "reference": "Modules/Settings/WidgetsTabSection.qml:596, Modules/Settings/WidgetsTabSection.qml:2203", - "comment": "" - }, - { - "term": "Completed", - "context": "Completed", - "reference": "Services/CupsService.qml:771", - "comment": "" - }, - { - "term": "Compositor", - "context": "Compositor", - "reference": "Modules/Settings/DockTab.qml:280, Modules/Settings/LauncherTab.qml:73", - "comment": "" - }, - { - "term": "Compositor Settings", - "context": "Compositor Settings", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:38, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:38", - "comment": "" - }, - { - "term": "Compositor not supported", - "context": "Compositor not supported", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:185", - "comment": "" - }, - { - "term": "Config Format", - "context": "Config Format", - "reference": "Modules/Settings/DisplayConfigTab.qml:413, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1212", - "comment": "" - }, - { - "term": "Config action: %1", - "context": "Config action: %1", - "reference": "Widgets/KeybindItem.qml:511", - "comment": "" - }, - { - "term": "Config validation failed", - "context": "Config validation failed", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1295, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1303", - "comment": "" - }, - { - "term": "Configuration", - "context": "Configuration", - "reference": "Modals/Settings/SettingsSidebar.qml:212", - "comment": "" - }, - { - "term": "Configuration activated", - "context": "Configuration activated", - "reference": "Services/DMSNetworkService.qml:388", - "comment": "" - }, - { - "term": "Configuration will be preserved when this display reconnects", - "context": "Configuration will be preserved when this display reconnects", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:136", - "comment": "" - }, - { - "term": "Configure", - "context": "Configure", - "reference": "Modals/Greeter/GreeterCompletePage.qml:356", - "comment": "greeter settings section header" - }, - { - "term": "Configure Keybinds", - "context": "Configure Keybinds", - "reference": "Modals/Greeter/GreeterCompletePage.qml:297", - "comment": "greeter configure keybinds link" - }, - { - "term": "Configure a new printer", - "context": "Configure a new printer", - "reference": "Modules/Settings/PrinterTab.qml:276", - "comment": "" - }, - { - "term": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.", - "context": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.", - "reference": "Modules/Settings/WorkspacesTab.qml:423", - "comment": "" - }, - { - "term": "Configure match criteria and actions", - "context": "Configure match criteria and actions", - "reference": "Modals/WindowRuleModal.qml:414", - "comment": "" - }, - { - "term": "Configure which displays show \"%1\"", - "context": "Configure which displays show \"%1\"", - "reference": "Modules/Settings/DankBarTab.qml:432", - "comment": "" - }, - { - "term": "Configure which displays show shell components", - "context": "Configure which displays show shell components", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:176", - "comment": "" - }, - { - "term": "Confirm", - "context": "Confirm", - "reference": "Modals/BluetoothPairingModal.qml:318", - "comment": "" - }, - { - "term": "Confirm Delete", - "context": "Confirm Delete", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:152", - "comment": "" - }, - { - "term": "Confirm Display Changes", - "context": "Confirm Display Changes", - "reference": "Modals/DisplayConfirmationModal.qml:80", - "comment": "" - }, - { - "term": "Confirm passkey for ", - "context": "Confirm passkey for ", - "reference": "Modals/BluetoothPairingModal.qml:131", - "comment": "" - }, - { - "term": "Conflicts with: %1", - "context": "Conflicts with: %1", - "reference": "Widgets/KeybindItem.qml:820", - "comment": "" - }, - { - "term": "Connect", - "context": "Connect", - "reference": "Modals/WifiPasswordModal.qml:733, Modules/ControlCenter/Details/BluetoothDetail.qml:616, Modules/ControlCenter/Details/NetworkDetail.qml:782", - "comment": "" - }, - { - "term": "Connect to Hidden Network", - "context": "Connect to Hidden Network", - "reference": "Modals/WifiPasswordModal.qml:336", - "comment": "" - }, - { - "term": "Connect to VPN", - "context": "Connect to VPN", - "reference": "Modals/WifiPasswordModal.qml:334", - "comment": "" - }, - { - "term": "Connect to Wi-Fi", - "context": "Connect to Wi-Fi", - "reference": "Modals/WifiPasswordModal.qml:337", - "comment": "" - }, - { - "term": "Connected", - "context": "Connected", - "reference": "Modules/Settings/AboutTab.qml:716, Modules/Settings/NetworkTab.qml:448, Modules/Settings/NetworkTab.qml:1201, Modules/Settings/NetworkTab.qml:1558, Modules/ControlCenter/Details/BluetoothDetail.qml:301, Modules/ControlCenter/Details/BluetoothDetail.qml:302, Modules/ControlCenter/Details/NetworkDetail.qml:609, Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:21, Modules/ControlCenter/Components/DragDropGrid.qml:337, Modules/ControlCenter/Components/DragDropGrid.qml:340, Modules/ControlCenter/Components/DragDropGrid.qml:342, Modules/ControlCenter/Components/DragDropGrid.qml:345", - "comment": "network status" - }, - { - "term": "Connected Device", - "context": "Connected Device", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:367", - "comment": "bluetooth status" - }, - { - "term": "Connected Displays", - "context": "Connected Displays", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:167", - "comment": "" - }, - { - "term": "Connecting to Device", - "context": "Connecting to Device", - "reference": "Services/CupsService.qml:816", - "comment": "" - }, - { - "term": "Connecting to clipboard service…", - "context": "Connecting to clipboard service…", - "reference": "Modals/Clipboard/ClipboardContent.qml:125, Modals/Clipboard/ClipboardContent.qml:184", - "comment": "" - }, - { - "term": "Connecting...", - "context": "Connecting...", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:297", - "comment": "" - }, - { - "term": "Connection failed", - "context": "Connection failed", - "reference": "Modules/Settings/PrinterTab.qml:639", - "comment": "Status message when test connection to printer fails" - }, - { - "term": "Contains", - "context": "Contains", - "reference": "Modules/Settings/NotificationsTab.qml:104", - "comment": "notification rule match type option" - }, - { - "term": "Content", - "context": "Content", - "reference": "Common/Theme.qml:475", - "comment": "matugen color scheme option" - }, - { - "term": "Content copied", - "context": "Content copied", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:262, dms-plugins/DankGifSearch/DankGifSearch.qml:209", - "comment": "" - }, - { - "term": "Contrast", - "context": "Contrast", - "reference": "Modules/Settings/DockTab.qml:496, Modules/Settings/LauncherTab.qml:288", - "comment": "" - }, - { - "term": "Control Center", - "context": "Control Center", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:149, Modules/Settings/WidgetsTab.qml:162", - "comment": "greeter feature card title" - }, - { - "term": "Control Center Tile Color", - "context": "Control Center Tile Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1556", - "comment": "" - }, - { - "term": "Control animation duration for notification popups and history", - "context": "Control animation duration for notification popups and history", - "reference": "Modules/Settings/NotificationsTab.qml:324", - "comment": "" - }, - { - "term": "Control currently playing media", - "context": "Control currently playing media", - "reference": "Modules/Settings/WidgetsTab.qml:95", - "comment": "" - }, - { - "term": "Control what notification information is shown on the lock screen", - "context": "Control what notification information is shown on the lock screen", - "reference": "Modules/Settings/LockScreenTab.qml:147, Modules/Settings/NotificationsTab.qml:728", - "comment": "lock screen notification privacy setting" - }, - { - "term": "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.", - "context": "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.", - "reference": "Modules/Settings/LauncherTab.qml:675", - "comment": "" - }, - { - "term": "Control workspaces and columns by scrolling on the bar", - "context": "Control workspaces and columns by scrolling on the bar", - "reference": "Modules/Settings/DankBarTab.qml:720", - "comment": "" - }, - { - "term": "Controls opacity of all popouts, modals, and their content layers", - "context": "Controls opacity of all popouts, modals, and their content layers", - "reference": "Modules/Settings/ThemeColorsTab.qml:1621", - "comment": "" - }, - { - "term": "Controls shadow cast direction for elevation layers", - "context": "Controls shadow cast direction for elevation layers", - "reference": "Modules/Settings/ThemeColorsTab.qml:1727", - "comment": "" - }, - { - "term": "Controls the base blur radius and offset of shadows", - "context": "Controls the base blur radius and offset of shadows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1659", - "comment": "" - }, - { - "term": "Controls the transparency of the shadow", - "context": "Controls the transparency of the shadow", - "reference": "Modules/Settings/ThemeColorsTab.qml:1674", - "comment": "" - }, - { - "term": "Convenience options for the login screen. Sync to apply.", - "context": "Convenience options for the login screen. Sync to apply.", - "reference": "Modules/Settings/GreeterTab.qml:724", - "comment": "" - }, - { - "term": "Cooldown", - "context": "Cooldown", - "reference": "Widgets/KeybindItem.qml:1659", - "comment": "" - }, - { - "term": "Copied GIF", - "context": "Copied GIF", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:283, dms-plugins/DankGifSearch/DankGifSearch.qml:230", - "comment": "" - }, - { - "term": "Copied MP4", - "context": "Copied MP4", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:293, dms-plugins/DankGifSearch/DankGifSearch.qml:240", - "comment": "" - }, - { - "term": "Copied WebP", - "context": "Copied WebP", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:273, dms-plugins/DankGifSearch/DankGifSearch.qml:220", - "comment": "" - }, - { - "term": "Copied to clipboard", - "context": "Copied to clipboard", - "reference": "Services/ClipboardService.qml:108, dms-plugins/DankStickerSearch/DankStickerSearch.qml:230, dms-plugins/DankLauncherKeys/DankLauncherKeys.qml:154, dms-plugins/DankGifSearch/DankGifSearch.qml:175, Modals/Settings/SettingsModal.qml:315, Modals/Settings/SettingsModal.qml:332, Modules/Notepad/NotepadTextEditor.qml:259, Modules/Settings/DesktopWidgetInstanceCard.qml:426", - "comment": "" - }, - { - "term": "Copied!", - "context": "Copied!", - "reference": "Modules/Toast.qml:16", - "comment": "" - }, - { - "term": "Copy", - "context": "Copy", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeys.qml:170", - "comment": "" - }, - { - "term": "Copy Content", - "context": "Copy Content", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:259, dms-plugins/DankGifSearch/DankGifSearch.qml:206", - "comment": "" - }, - { - "term": "Copy Full Command", - "context": "Copy Full Command", - "reference": "Modules/ProcessList/ProcessContextMenu.qml:33", - "comment": "" - }, - { - "term": "Copy HTML", - "context": "Copy HTML", - "reference": "Modules/Notepad/NotepadTextEditor.qml:712", - "comment": "" - }, - { - "term": "Copy Name", - "context": "Copy Name", - "reference": "Modules/ProcessList/ProcessContextMenu.qml:27", - "comment": "" - }, - { - "term": "Copy PID", - "context": "Copy PID", - "reference": "Modules/ProcessList/ProcessContextMenu.qml:21", - "comment": "" - }, - { - "term": "Copy Text", - "context": "Copy Text", - "reference": "Modules/Notepad/NotepadTextEditor.qml:690", - "comment": "" - }, - { - "term": "Copy path", - "context": "Copy path", - "reference": "Modals/DankLauncherV2/Controller.qml:1114", - "comment": "" - }, - { - "term": "Corner Radius", - "context": "Corner Radius", - "reference": "Modals/WindowRuleModal.qml:795, Modules/Settings/ThemeColorsTab.qml:1634", - "comment": "" - }, - { - "term": "Corner Radius Override", - "context": "Corner Radius Override", - "reference": "Modules/Settings/DankBarTab.qml:1344", - "comment": "" - }, - { - "term": "Corners & Background", - "context": "Corners & Background", - "reference": "Modules/Settings/DankBarTab.qml:1282", - "comment": "" - }, - { - "term": "Count Only", - "context": "Count Only", - "reference": "Modules/Settings/LockScreenTab.qml:148, Modules/Settings/NotificationsTab.qml:729", - "comment": "lock screen notification mode option" - }, - { - "term": "Cover Open", - "context": "Cover Open", - "reference": "Services/CupsService.qml:805", - "comment": "" - }, - { - "term": "Create", - "context": "Create", - "reference": "Modals/WindowRuleModal.qml:1154, Modules/Settings/DisplayConfigTab.qml:246", - "comment": "" - }, - { - "term": "Create Dir", - "context": "Create Dir", - "reference": "Modules/Settings/PluginsTab.qml:231", - "comment": "" - }, - { - "term": "Create Printer", - "context": "Create Printer", - "reference": "Modules/Settings/PrinterTab.qml:820", - "comment": "" - }, - { - "term": "Create Window Rule", - "context": "Create Window Rule", - "reference": "Modals/WindowRuleModal.qml:24", - "comment": "" - }, - { - "term": "Create a new %1 session (n)", - "context": "Create a new %1 session (n)", - "reference": "Modals/MuxModal.qml:388", - "comment": "" - }, - { - "term": "Create rule for:", - "context": "Create rule for:", - "reference": "Modules/Settings/WindowRulesTab.qml:280", - "comment": "" - }, - { - "term": "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.", - "context": "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.", - "reference": "Modules/Settings/NotificationsTab.qml:438", - "comment": "" - }, - { - "term": "Creating...", - "context": "Creating...", - "reference": "Modules/Settings/PrinterTab.qml:820", - "comment": "" - }, - { - "term": "Critical Priority", - "context": "Critical Priority", - "reference": "Modules/Settings/NotificationsTab.qml:154, Modules/Settings/NotificationsTab.qml:785, Modules/Settings/NotificationsTab.qml:892, Modules/Notifications/Center/NotificationSettings.qml:211, Modules/Notifications/Center/NotificationSettings.qml:432", - "comment": "notification rule urgency option" - }, - { - "term": "Current", - "context": "Current", - "reference": "Modules/Notifications/Center/NotificationHeader.qml:151", - "comment": "notification center tab" - }, - { - "term": "Current Items", - "context": "Current Items", - "reference": "Modules/Plugins/ListSettingWithInput.qml:162", - "comment": "" - }, - { - "term": "Current Locale", - "context": "Current Locale", - "reference": "Modules/Settings/LocaleTab.qml:56", - "comment": "" - }, - { - "term": "Current Monitor", - "context": "Current Monitor", - "reference": "Modules/Settings/WidgetsTabSection.qml:2359", - "comment": "Running apps filter: only show apps from the same monitor" - }, - { - "term": "Current Period", - "context": "Current Period", - "reference": "Modules/Settings/GammaControlTab.qml:532", - "comment": "" - }, - { - "term": "Current Status", - "context": "Current Status", - "reference": "Modules/Settings/GammaControlTab.qml:458", - "comment": "" - }, - { - "term": "Current Temp", - "context": "Current Temp", - "reference": "Modules/Settings/GammaControlTab.qml:497", - "comment": "" - }, - { - "term": "Current Theme: %1", - "context": "Current Theme: %1", - "reference": "Modules/Settings/ThemeColorsTab.qml:230, Modules/Settings/ThemeColorsTab.qml:232, Modules/Settings/ThemeColorsTab.qml:233", - "comment": "current theme label" - }, - { - "term": "Current Weather", - "context": "Current Weather", - "reference": "Modules/Settings/TimeWeatherTab.qml:633", - "comment": "" - }, - { - "term": "Current Workspace", - "context": "Current Workspace", - "reference": "Modules/Settings/WidgetsTabSection.qml:2307", - "comment": "Running apps filter: only show apps from the active workspace" - }, - { - "term": "Current time and date display", - "context": "Current time and date display", - "reference": "Modules/Settings/WidgetsTab.qml:81", - "comment": "" - }, - { - "term": "Current weather conditions and temperature", - "context": "Current weather conditions and temperature", - "reference": "Modules/Settings/WidgetsTab.qml:88", - "comment": "" - }, - { - "term": "Current: %1", - "context": "Current: %1", - "reference": "Modules/ControlCenter/Details/BluetoothCodecSelector.qml:224", - "comment": "" - }, - { - "term": "Cursor Config Not Configured", - "context": "Cursor Config Not Configured", - "reference": "Modules/Settings/ThemeColorsTab.qml:2299", - "comment": "" - }, - { - "term": "Cursor Include Missing", - "context": "Cursor Include Missing", - "reference": "Modules/Settings/ThemeColorsTab.qml:2299", - "comment": "" - }, - { - "term": "Cursor Size", - "context": "Cursor Size", - "reference": "Modules/Settings/ThemeColorsTab.qml:2347", - "comment": "" - }, - { - "term": "Cursor Theme", - "context": "Cursor Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:2257, Modules/Settings/ThemeColorsTab.qml:2331", - "comment": "" - }, - { - "term": "Custom", - "context": "Custom", - "reference": "Widgets/KeybindItem.qml:1403, dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:47, Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/ThemeColorsTab.qml:1690, Modules/Settings/ThemeColorsTab.qml:1700, Modules/Settings/ThemeColorsTab.qml:1711, Modules/Settings/ThemeColorsTab.qml:1853, Modules/Settings/ThemeColorsTab.qml:1863, Modules/Settings/ThemeColorsTab.qml:1875, Modules/Settings/TypographyMotionTab.qml:212, Modules/Settings/TypographyMotionTab.qml:315, Modules/Settings/TypographyMotionTab.qml:399, Modules/Settings/DockTab.qml:282, Modules/Settings/DockTab.qml:389, Modules/Settings/LauncherTab.qml:75, Modules/Settings/LauncherTab.qml:181, Modules/Settings/DankBarTab.qml:1211, Modules/Settings/NotificationsTab.qml:337, Modules/Settings/Widgets/SettingsColorPicker.qml:52, Modules/Settings/Widgets/DeviceAliasRow.qml:92", - "comment": "blur border color | shadow color option | theme category option" - }, - { - "term": "Custom Color", - "context": "Custom Color", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:56", - "comment": "" - }, - { - "term": "Custom Duration", - "context": "Custom Duration", - "reference": "Modules/Settings/TypographyMotionTab.qml:347, Modules/Settings/TypographyMotionTab.qml:431", - "comment": "" - }, - { - "term": "Custom Hibernate Command", - "context": "Custom Hibernate Command", - "reference": "Modules/Settings/PowerSleepTab.qml:529", - "comment": "" - }, - { - "term": "Custom Location", - "context": "Custom Location", - "reference": "Modules/Settings/TimeWeatherTab.qml:487", - "comment": "" - }, - { - "term": "Custom Lock Command", - "context": "Custom Lock Command", - "reference": "Modules/Settings/PowerSleepTab.qml:514", - "comment": "" - }, - { - "term": "Custom Logout Command", - "context": "Custom Logout Command", - "reference": "Modules/Settings/PowerSleepTab.qml:519", - "comment": "" - }, - { - "term": "Custom Name", - "context": "Custom Name", - "reference": "Modules/Settings/AudioTab.qml:616", - "comment": "Audio device rename dialog field label" - }, - { - "term": "Custom Power Actions", - "context": "Custom Power Actions", - "reference": "Modules/Settings/PowerSleepTab.qml:507", - "comment": "" - }, - { - "term": "Custom Power Off Command", - "context": "Custom Power Off Command", - "reference": "Modules/Settings/PowerSleepTab.qml:539", - "comment": "" - }, - { - "term": "Custom Reboot Command", - "context": "Custom Reboot Command", - "reference": "Modules/Settings/PowerSleepTab.qml:534", - "comment": "" - }, - { - "term": "Custom Shadow Color", - "context": "Custom Shadow Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1771", - "comment": "" - }, - { - "term": "Custom Shadow Override", - "context": "Custom Shadow Override", - "reference": "Modules/Settings/DankBarTab.qml:1072", - "comment": "" - }, - { - "term": "Custom Suspend Command", - "context": "Custom Suspend Command", - "reference": "Modules/Settings/PowerSleepTab.qml:524", - "comment": "" - }, - { - "term": "Custom Transparency", - "context": "Custom Transparency", - "reference": "Modules/Notepad/NotepadSettings.qml:324", - "comment": "" - }, - { - "term": "Custom power profile", - "context": "Custom power profile", - "reference": "Common/Theme.qml:1491", - "comment": "power profile description" - }, - { - "term": "Custom theme loaded from JSON file", - "context": "Custom theme loaded from JSON file", - "reference": "Modules/Settings/ThemeColorsTab.qml:248", - "comment": "custom theme description" - }, - { - "term": "Custom...", - "context": "Custom...", - "reference": "Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:183, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:270, Modules/Settings/DisplayConfig/OutputCard.qml:182, Modules/Settings/DisplayConfig/OutputCard.qml:188, Modules/Settings/DisplayConfig/OutputCard.qml:190, Modules/Settings/DisplayConfig/OutputCard.qml:196", - "comment": "date format option" - }, - { - "term": "Custom: ", - "context": "Custom: ", - "reference": "Modules/Settings/GreeterTab.qml:641, Modules/Settings/TimeWeatherTab.qml:170, Modules/Settings/TimeWeatherTab.qml:257", - "comment": "" - }, - { - "term": "Customizable empty space", - "context": "Customizable empty space", - "reference": "Modules/Settings/WidgetsTab.qml:205", - "comment": "" - }, - { - "term": "Customize which actions appear in the power menu", - "context": "Customize which actions appear in the power menu", - "reference": "Modules/Settings/PowerSleepTab.qml:357", - "comment": "" - }, - { - "term": "DDC/CI monitor", - "context": "DDC/CI monitor", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:333", - "comment": "" - }, - { - "term": "DEMO MODE - Click anywhere to exit", - "context": "DEMO MODE - Click anywhere to exit", - "reference": "Modules/Lock/LockScreenContent.qml:1135", - "comment": "" - }, - { - "term": "DMS Plugin Manager Unavailable", - "context": "DMS Plugin Manager Unavailable", - "reference": "Modules/Settings/PluginsTab.qml:115", - "comment": "" - }, - { - "term": "DMS Shortcuts", - "context": "DMS Shortcuts", - "reference": "Modals/Greeter/GreeterCompletePage.qml:136", - "comment": "greeter keybinds section header" - }, - { - "term": "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "context": "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "reference": "Modules/Settings/GreeterTab.qml:757", - "comment": "" - }, - { - "term": "DMS out of date", - "context": "DMS out of date", - "reference": "Services/DMSService.qml:320", - "comment": "" - }, - { - "term": "DMS service is not connected. Clipboard settings are unavailable.", - "context": "DMS service is not connected. Clipboard settings are unavailable.", - "reference": "Modules/Settings/ClipboardTab.qml:267", - "comment": "" - }, - { - "term": "DMS shell actions (launcher, clipboard, etc.)", - "context": "DMS shell actions (launcher, clipboard, etc.)", - "reference": "Widgets/KeybindItem.qml:854", - "comment": "" - }, - { - "term": "DMS_SOCKET not available", - "context": "DMS_SOCKET not available", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:219", - "comment": "" - }, - { - "term": "DWL service not available", - "context": "DWL service not available", - "reference": "Modules/Settings/WidgetsTab.qml:41", - "comment": "" - }, - { - "term": "Daily", - "context": "Daily", - "reference": "Modules/DankDash/WeatherTab.qml:860", - "comment": "" - }, - { - "term": "Daily at:", - "context": "Daily at:", - "reference": "Modules/Settings/WallpaperTab.qml:1061", - "comment": "" - }, - { - "term": "Dank", - "context": "Dank", - "reference": "Modules/Settings/DockTab.qml:266, Modules/Settings/LauncherTab.qml:59", - "comment": "" - }, - { - "term": "Dank Bar", - "context": "Dank Bar", - "reference": "Modals/Settings/SettingsSidebar.qml:109", - "comment": "" - }, - { - "term": "DankBar", - "context": "DankBar", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:114, Modals/Greeter/GreeterCompletePage.qml:405", - "comment": "greeter feature card title | greeter settings link" - }, - { - "term": "DankMaterialShell is ready to use", - "context": "DankMaterialShell is ready to use", - "reference": "Modals/Greeter/GreeterCompletePage.qml:112", - "comment": "greeter completion page subtitle" - }, - { - "term": "DankShell & System Icons (requires restart)", - "context": "DankShell & System Icons (requires restart)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2455", - "comment": "" - }, - { - "term": "Dark Mode", - "context": "Dark Mode", - "reference": "Modules/Settings/ThemeColorsTab.qml:1415, Modules/Settings/WallpaperTab.qml:582, Modules/ControlCenter/Models/WidgetModel.qml:77, Modules/ControlCenter/Components/DragDropGrid.qml:620", - "comment": "" - }, - { - "term": "Dark mode base", - "context": "Dark mode base", - "reference": "Modules/Settings/ThemeColorsTab.qml:2686", - "comment": "" - }, - { - "term": "Dark mode harmony", - "context": "Dark mode harmony", - "reference": "Modules/Settings/ThemeColorsTab.qml:2720", - "comment": "" - }, - { - "term": "Darken Modal Background", - "context": "Darken Modal Background", - "reference": "Modules/Settings/ThemeColorsTab.qml:2219", - "comment": "" - }, - { - "term": "Date Format", - "context": "Date Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:84", - "comment": "" - }, - { - "term": "Date format", - "context": "Date format", - "reference": "Modules/Settings/GreeterTab.qml:635", - "comment": "" - }, - { - "term": "Date format on greeter", - "context": "Date format on greeter", - "reference": "Modules/Settings/GreeterTab.qml:625", - "comment": "" - }, - { - "term": "Dawn (Astronomical Twilight)", - "context": "Dawn (Astronomical Twilight)", - "reference": "Services/WeatherService.qml:230", - "comment": "" - }, - { - "term": "Dawn (Civil Twilight)", - "context": "Dawn (Civil Twilight)", - "reference": "Services/WeatherService.qml:240", - "comment": "" - }, - { - "term": "Dawn (Nautical Twilight)", - "context": "Dawn (Nautical Twilight)", - "reference": "Services/WeatherService.qml:235", - "comment": "" - }, - { - "term": "Day Date", - "context": "Day Date", - "reference": "Modules/Settings/GreeterTab.qml:398, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:138, Modules/Settings/TimeWeatherTab.qml:175, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:225, Modules/Settings/TimeWeatherTab.qml:262", - "comment": "date format option" - }, - { - "term": "Day Month Date", - "context": "Day Month Date", - "reference": "Modules/Settings/GreeterTab.qml:402, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:142, Modules/Settings/TimeWeatherTab.qml:176, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:229, Modules/Settings/TimeWeatherTab.qml:263", - "comment": "date format option" - }, - { - "term": "Day Temperature", - "context": "Day Temperature", - "reference": "Modules/Settings/GammaControlTab.qml:124", - "comment": "" - }, - { - "term": "Daytime", - "context": "Daytime", - "reference": "Modules/Settings/GammaControlTab.qml:524", - "comment": "" - }, - { - "term": "Deck", - "context": "Deck", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:49", - "comment": "" - }, - { - "term": "Default", - "context": "Default", - "reference": "Modules/Settings/ThemeColorsTab.qml:1508, Modules/Settings/DockTab.qml:389, Modules/Settings/LauncherTab.qml:181, Modules/Settings/NotificationsTab.qml:119, Modules/Settings/NotificationsTab.qml:142", - "comment": "notification rule action option | notification rule urgency option | widget style option" - }, - { - "term": "Default (Black)", - "context": "Default (Black)", - "reference": "Modules/Settings/ThemeColorsTab.qml:1690, Modules/Settings/ThemeColorsTab.qml:1702, Modules/Settings/DankBarTab.qml:1211", - "comment": "shadow color option" - }, - { - "term": "Default Width (%)", - "context": "Default Width (%)", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:254", - "comment": "" - }, - { - "term": "Default selected action", - "context": "Default selected action", - "reference": "Modules/Settings/PowerSleepTab.qml:377", - "comment": "" - }, - { - "term": "Defaults", - "context": "Defaults", - "reference": "Modules/ControlCenter/Components/EditControls.qml:198", - "comment": "" - }, - { - "term": "Define rules for window behavior. Saves to %1", - "context": "Define rules for window behavior. Saves to %1", - "reference": "Modules/Settings/WindowRulesTab.qml:255", - "comment": "" - }, - { - "term": "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close", - "context": "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close", - "reference": "Modules/Notifications/Center/NotificationKeyboardHints.qml:35", - "comment": "" - }, - { - "term": "Delete", - "context": "Delete", - "reference": "Widgets/VpnDetailContent.qml:221, Modules/Settings/DesktopWidgetInstanceCard.qml:152, Modules/Settings/PrinterTab.qml:1094, Modules/Settings/PrinterTab.qml:1680, Modules/Settings/NetworkTab.qml:1825, Modules/Settings/DisplayConfigTab.qml:291", - "comment": "" - }, - { - "term": "Delete \"%1\"?", - "context": "Delete \"%1\"?", - "reference": "Widgets/VpnDetailContent.qml:220, Modules/Settings/PrinterTab.qml:1093, Modules/Settings/NetworkTab.qml:1824", - "comment": "" - }, - { - "term": "Delete Class", - "context": "Delete Class", - "reference": "Modules/Settings/PrinterTab.qml:1678", - "comment": "" - }, - { - "term": "Delete Printer", - "context": "Delete Printer", - "reference": "Modules/Settings/PrinterTab.qml:1092", - "comment": "" - }, - { - "term": "Delete Saved Item?", - "context": "Delete Saved Item?", - "reference": "Services/ClipboardService.qml:167", - "comment": "" - }, - { - "term": "Delete VPN", - "context": "Delete VPN", - "reference": "Widgets/VpnDetailContent.qml:219, Modules/Settings/NetworkTab.qml:1823", - "comment": "" - }, - { - "term": "Delete class \"%1\"?", - "context": "Delete class \"%1\"?", - "reference": "Modules/Settings/PrinterTab.qml:1679", - "comment": "" - }, - { - "term": "Delete profile \"%1\"?", - "context": "Delete profile \"%1\"?", - "reference": "Modules/Settings/DisplayConfigTab.qml:278", - "comment": "" - }, - { - "term": "Dependencies & documentation", - "context": "Dependencies & documentation", - "reference": "Modules/Settings/GreeterTab.qml:753", - "comment": "" - }, - { - "term": "Derives colors that closely match the underlying image.", - "context": "Derives colors that closely match the underlying image.", - "reference": "Common/Theme.qml:476", - "comment": "" - }, - { - "term": "Description", - "context": "Description", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:923, Modules/Settings/PrinterTab.qml:796", - "comment": "" - }, - { - "term": "Desktop", - "context": "Desktop", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:271", - "comment": "" - }, - { - "term": "Desktop Clock", - "context": "Desktop Clock", - "reference": "Services/DesktopWidgetRegistry.qml:39", - "comment": "Desktop clock widget name" - }, - { - "term": "Desktop Entry", - "context": "Desktop Entry", - "reference": "Modules/Settings/NotificationsTab.qml:89", - "comment": "notification rule match field option" - }, - { - "term": "Desktop Widget", - "context": "Desktop Widget", - "reference": "Modules/Settings/PluginListItem.qml:161", - "comment": "" - }, - { - "term": "Desktop Widgets", - "context": "Desktop Widgets", - "reference": "Modals/Settings/SettingsSidebar.qml:171, Modules/Settings/DesktopWidgetsTab.qml:75", - "comment": "" - }, - { - "term": "Desktop background images", - "context": "Desktop background images", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:44", - "comment": "" - }, - { - "term": "Detailed", - "context": "Detailed", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:23", - "comment": "" - }, - { - "term": "Details for \"%1\"", - "context": "Details for \"%1\"", - "reference": "Modals/NetworkWiredInfoModal.qml:69, Modals/NetworkInfoModal.qml:69", - "comment": "" - }, - { - "term": "Development", - "context": "Development", - "reference": "Services/AppSearchService.qml:639, Services/AppSearchService.qml:640, Services/AppSearchService.qml:641, Widgets/DankIconPicker.qml:31", - "comment": "" - }, - { - "term": "Device", - "context": "Device", - "reference": "Widgets/KeybindItem.qml:1032, Modules/Settings/PrinterTab.qml:423", - "comment": "" - }, - { - "term": "Device connections", - "context": "Device connections", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:111", - "comment": "" - }, - { - "term": "Device names updated", - "context": "Device names updated", - "reference": "Services/AudioService.qml:274", - "comment": "" - }, - { - "term": "Device paired", - "context": "Device paired", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:164, Modules/ControlCenter/Details/BluetoothDetail.qml:54", - "comment": "Phone Connect pairing action" - }, - { - "term": "Device unpaired", - "context": "Device unpaired", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:179, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:359", - "comment": "KDE Connect unpair action | Phone Connect unpair action" - }, - { - "term": "Digital", - "context": "Digital", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:29, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:37, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:18", - "comment": "" - }, - { - "term": "Direction Source", - "context": "Direction Source", - "reference": "Modules/Settings/DankBarTab.qml:1117", - "comment": "bar shadow direction source" - }, - { - "term": "Disable Autoconnect", - "context": "Disable Autoconnect", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:836", - "comment": "" - }, - { - "term": "Disable Built-in Wallpapers", - "context": "Disable Built-in Wallpapers", - "reference": "Modules/Settings/WallpaperTab.qml:1250", - "comment": "wallpaper settings disable toggle" - }, - { - "term": "Disable History Persistence", - "context": "Disable History Persistence", - "reference": "Modules/Settings/ClipboardTab.qml:455", - "comment": "" - }, - { - "term": "Disable Output", - "context": "Disable Output", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:76, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:63", - "comment": "" - }, - { - "term": "Disabled", - "context": "Disabled", - "reference": "Modules/Settings/ThemeColorsTab.qml:1389, Modules/Settings/LockScreenTab.qml:148, Modules/Settings/NetworkTab.qml:823, Modules/Settings/DankBarTab.qml:357, Modules/Settings/NotificationsTab.qml:729, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1226, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1232, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1234, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1246, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1260, Modules/ControlCenter/Components/DragDropGrid.qml:317", - "comment": "bluetooth status | lock screen notification mode option" - }, - { - "term": "Disabling WiFi...", - "context": "Disabling WiFi...", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:192, Modules/ControlCenter/Components/DragDropGrid.qml:293", - "comment": "network status" - }, - { - "term": "Disc", - "context": "Disc", - "reference": "Modules/Settings/WallpaperTab.qml:1167", - "comment": "wallpaper transition option" - }, - { - "term": "Discard", - "context": "Discard", - "reference": "Modules/Settings/DisplayConfigTab.qml:519", - "comment": "" - }, - { - "term": "Discharging", - "context": "Discharging", - "reference": "Services/BatteryService.qml:138, Services/BatteryService.qml:165", - "comment": "battery status" - }, - { - "term": "Disconnect", - "context": "Disconnect", - "reference": "Widgets/VpnDetailContent.qml:124, Modules/Settings/NetworkTab.qml:1629, Modules/ControlCenter/Details/BluetoothDetail.qml:616, Modules/ControlCenter/Details/NetworkDetail.qml:427, Modules/ControlCenter/Details/NetworkDetail.qml:782", - "comment": "" - }, - { - "term": "Disconnected", - "context": "Disconnected", - "reference": "Modules/Settings/NetworkTab.qml:215, Modules/Settings/NetworkTab.qml:450, Modules/Settings/NetworkTab.qml:1555, Modules/Settings/DisplayConfig/OutputCard.qml:74, Modules/Settings/DisplayConfig/MonitorRect.qml:93, Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:18", - "comment": "" - }, - { - "term": "Disconnected from WiFi", - "context": "Disconnected from WiFi", - "reference": "Services/DMSNetworkService.qml:480", - "comment": "" - }, - { - "term": "Discover Devices", - "context": "Discover Devices", - "reference": "Modules/Settings/PrinterTab.qml:352", - "comment": "Toggle button to scan for printers via mDNS/Avahi" - }, - { - "term": "Disk", - "context": "Disk", - "reference": "Modules/ProcessList/PerformanceView.qml:128, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:248", - "comment": "" - }, - { - "term": "Disk I/O", - "context": "Disk I/O", - "reference": "Modules/ProcessList/DisksView.qml:58", - "comment": "disk io header in system monitor" - }, - { - "term": "Disk Usage", - "context": "Disk Usage", - "reference": "Modules/Settings/WidgetsTab.qml:124, Modules/ControlCenter/Models/WidgetModel.qml:169, Modules/ControlCenter/Widgets/DiskUsagePill.qml:35", - "comment": "" - }, - { - "term": "Disk Usage Display", - "context": "Disk Usage Display", - "reference": "Modules/Settings/WidgetsTabSection.qml:1088", - "comment": "" - }, - { - "term": "Disks", - "context": "Disks", - "reference": "Modals/ProcessListModal.qml:315", - "comment": "" - }, - { - "term": "Dismiss", - "context": "Dismiss", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:35, Modules/Notifications/Popup/NotificationPopup.qml:1143, Modules/Notifications/Center/NotificationCard.qml:762, Modules/Notifications/Center/NotificationCard.qml:899, Modules/Notifications/Center/NotificationCard.qml:1044", - "comment": "" - }, - { - "term": "Display", - "context": "Display", - "reference": "Modules/Settings/WindowRulesTab.qml:546", - "comment": "" - }, - { - "term": "Display Assignment", - "context": "Display Assignment", - "reference": "Modules/Settings/DankBarTab.qml:426", - "comment": "" - }, - { - "term": "Display Control", - "context": "Display Control", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:141", - "comment": "greeter feature card title" - }, - { - "term": "Display Name Format", - "context": "Display Name Format", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:217", - "comment": "" - }, - { - "term": "Display Profiles", - "context": "Display Profiles", - "reference": "Modules/Settings/DisplayConfigTab.qml:124", - "comment": "" - }, - { - "term": "Display Settings", - "context": "Display Settings", - "reference": "Modules/Plugins/PluginSettings.qml:239", - "comment": "" - }, - { - "term": "Display a dock with pinned and running applications", - "context": "Display a dock with pinned and running applications", - "reference": "Modules/Settings/DockTab.qml:43", - "comment": "" - }, - { - "term": "Display all priorities over fullscreen apps", - "context": "Display all priorities over fullscreen apps", - "reference": "Modules/Settings/NotificationsTab.qml:262, Modules/Notifications/Center/NotificationSettings.qml:265", - "comment": "" - }, - { - "term": "Display and switch DWL layouts", - "context": "Display and switch DWL layouts", - "reference": "Modules/Settings/WidgetsTab.qml:38", - "comment": "" - }, - { - "term": "Display application icons in workspace indicators", - "context": "Display application icons in workspace indicators", - "reference": "Modules/Settings/WorkspacesTab.qml:60", - "comment": "" - }, - { - "term": "Display brightness control", - "context": "Display brightness control", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:144", - "comment": "" - }, - { - "term": "Display configuration is not available. WLR output management protocol not supported.", - "context": "Display configuration is not available. WLR output management protocol not supported.", - "reference": "Modules/Settings/DisplayConfig/NoBackendMessage.qml:50", - "comment": "" - }, - { - "term": "Display currently focused application title", - "context": "Display currently focused application title", - "reference": "Modules/Settings/WidgetsTab.qml:60", - "comment": "" - }, - { - "term": "Display hourly weather predictions", - "context": "Display hourly weather predictions", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:136", - "comment": "" - }, - { - "term": "Display only workspaces that contain windows", - "context": "Display only workspaces that contain windows", - "reference": "Modules/Settings/WorkspacesTab.qml:152", - "comment": "" - }, - { - "term": "Display power menu actions in a grid instead of a list", - "context": "Display power menu actions in a grid instead of a list", - "reference": "Modules/Settings/PowerSleepTab.qml:368", - "comment": "" - }, - { - "term": "Display seconds in the clock", - "context": "Display seconds in the clock", - "reference": "Modules/Settings/TimeWeatherTab.qml:64", - "comment": "" - }, - { - "term": "Display the power system menu", - "context": "Display the power system menu", - "reference": "Modules/Settings/WidgetsTab.qml:254", - "comment": "" - }, - { - "term": "Display volume and brightness percentage values in OSD popups", - "context": "Display volume and brightness percentage values in OSD popups", - "reference": "Modules/Settings/OSDTab.qml:79", - "comment": "" - }, - { - "term": "Displays", - "context": "Displays", - "reference": "Modals/Greeter/GreeterCompletePage.qml:373, Modals/Settings/SettingsSidebar.qml:206, Modules/Settings/Widgets/SettingsDisplayPicker.qml:36", - "comment": "greeter settings link" - }, - { - "term": "Displays count when overflow is active", - "context": "Displays count when overflow is active", - "reference": "Modules/Settings/DockTab.qml:217", - "comment": "" - }, - { - "term": "Displays the active keyboard layout and allows switching", - "context": "Displays the active keyboard layout and allows switching", - "reference": "Modules/Settings/WidgetsTab.qml:227", - "comment": "" - }, - { - "term": "Distribution", - "context": "Distribution", - "reference": "Modules/ProcessList/SystemView.qml:64", - "comment": "system info label" - }, - { - "term": "Diverse palette spanning the full spectrum.", - "context": "Diverse palette spanning the full spectrum.", - "reference": "Common/Theme.qml:500", - "comment": "" - }, - { - "term": "Do Not Disturb", - "context": "Do Not Disturb", - "reference": "Modules/Settings/NotificationsTab.qml:386, Modules/ControlCenter/Models/WidgetModel.qml:85, Modules/ControlCenter/Components/DragDropGrid.qml:622, Modules/Notifications/Center/NotificationHeader.qml:63, Modules/Notifications/Center/NotificationSettings.qml:151", - "comment": "" - }, - { - "term": "Dock", - "context": "Dock", - "reference": "Modals/Greeter/GreeterCompletePage.qml:422, Modals/Settings/SettingsSidebar.qml:185", - "comment": "greeter settings link" - }, - { - "term": "Dock & Launcher", - "context": "Dock & Launcher", - "reference": "Modals/Settings/SettingsSidebar.qml:179, Modals/Settings/SettingsSidebar.qml:575", - "comment": "" - }, - { - "term": "Dock Transparency", - "context": "Dock Transparency", - "reference": "Modules/Settings/DockTab.qml:571", - "comment": "" - }, - { - "term": "Dock Visibility", - "context": "Dock Visibility", - "reference": "Modules/Settings/DockTab.qml:36", - "comment": "" - }, - { - "term": "Docs", - "context": "Docs", - "reference": "Modals/Greeter/GreeterCompletePage.qml:468, Modules/Settings/AboutTab.qml:274, Modules/Settings/AboutTab.qml:282", - "comment": "greeter documentation link" - }, - { - "term": "Documents", - "context": "Documents", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:246", - "comment": "" - }, - { - "term": "Domain (optional)", - "context": "Domain (optional)", - "reference": "Modals/WifiPasswordModal.qml:621", - "comment": "" - }, - { - "term": "Don't Change", - "context": "Don't Change", - "reference": "Modules/Settings/PowerSleepTab.qml:154", - "comment": "" - }, - { - "term": "Don't Save", - "context": "Don't Save", - "reference": "Modules/Notepad/Notepad.qml:440", - "comment": "" - }, - { - "term": "Door Open", - "context": "Door Open", - "reference": "Services/CupsService.qml:806", - "comment": "" - }, - { - "term": "Downloads", - "context": "Downloads", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:251", - "comment": "" - }, - { - "term": "Drag to Reorder", - "context": "Drag to Reorder", - "reference": "Modules/Settings/WorkspacesTab.qml:171", - "comment": "" - }, - { - "term": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.", - "context": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.", - "reference": "Modules/Settings/WidgetsTab.qml:930", - "comment": "" - }, - { - "term": "Drag workspace indicators to reorder them", - "context": "Drag workspace indicators to reorder them", - "reference": "Modules/Settings/WorkspacesTab.qml:172", - "comment": "" - }, - { - "term": "Driver", - "context": "Driver", - "reference": "Modules/Settings/PrinterTab.qml:691, Modules/Settings/NetworkTab.qml:597", - "comment": "" - }, - { - "term": "Drizzle", - "context": "Drizzle", - "reference": "Services/WeatherService.qml:128, Services/WeatherService.qml:129, Services/WeatherService.qml:130", - "comment": "" - }, - { - "term": "Duplicate", - "context": "Duplicate", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:115", - "comment": "" - }, - { - "term": "Duplicate Wallpaper with Blur", - "context": "Duplicate Wallpaper with Blur", - "reference": "Modules/Settings/WallpaperTab.qml:1280", - "comment": "" - }, - { - "term": "Duration", - "context": "Duration", - "reference": "Modules/Settings/NotificationsTab.qml:358", - "comment": "" - }, - { - "term": "Dusk (Astronomical Twilight)", - "context": "Dusk (Astronomical Twilight)", - "reference": "Services/WeatherService.qml:285", - "comment": "" - }, - { - "term": "Dusk (Civil Twighlight)", - "context": "Dusk (Civil Twighlight)", - "reference": "Services/WeatherService.qml:275", - "comment": "" - }, - { - "term": "Dusk (Nautical Twilight)", - "context": "Dusk (Nautical Twilight)", - "reference": "Services/WeatherService.qml:280", - "comment": "" - }, - { - "term": "Dynamic", - "context": "Dynamic", - "reference": "Modules/Settings/ThemeColorsTab.qml:230", - "comment": "dynamic theme name" - }, - { - "term": "Dynamic Properties", - "context": "Dynamic Properties", - "reference": "Modals/WindowRuleModal.qml:670", - "comment": "" - }, - { - "term": "Dynamic Theming", - "context": "Dynamic Theming", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:90", - "comment": "greeter feature card title" - }, - { - "term": "Dynamic colors from wallpaper", - "context": "Dynamic colors from wallpaper", - "reference": "Modules/Settings/ThemeColorsTab.qml:488", - "comment": "dynamic colors description" - }, - { - "term": "Dynamic colors, presets", - "context": "Dynamic colors, presets", - "reference": "Modals/Greeter/GreeterCompletePage.qml:390", - "comment": "greeter theme description" - }, - { - "term": "Edge Spacing", - "context": "Edge Spacing", - "reference": "Modules/Settings/DankBarTab.qml:809", - "comment": "" - }, - { - "term": "Edit App", - "context": "Edit App", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:118, Modals/DankLauncherV2/LauncherContent.qml:846", - "comment": "" - }, - { - "term": "Edit Window Rule", - "context": "Edit Window Rule", - "reference": "Modals/WindowRuleModal.qml:24, Modals/WindowRuleModal.qml:405", - "comment": "" - }, - { - "term": "Education", - "context": "Education", - "reference": "Services/AppSearchService.qml:642", - "comment": "" - }, - { - "term": "Empty", - "context": "Empty", - "reference": "Services/BatteryService.qml:140, Modules/Notepad/NotepadTextEditor.qml:848", - "comment": "battery status" - }, - { - "term": "Enable 10-bit color depth for wider color gamut and HDR support", - "context": "Enable 10-bit color depth for wider color gamut and HDR support", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:112", - "comment": "" - }, - { - "term": "Enable Autoconnect", - "context": "Enable Autoconnect", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:836", - "comment": "" - }, - { - "term": "Enable Bar", - "context": "Enable Bar", - "reference": "Modules/Settings/DankBarTab.qml:411", - "comment": "" - }, - { - "term": "Enable Do Not Disturb", - "context": "Enable Do Not Disturb", - "reference": "Modules/Settings/NotificationsTab.qml:392", - "comment": "" - }, - { - "term": "Enable History", - "context": "Enable History", - "reference": "Modules/Settings/NotificationsTab.qml:809", - "comment": "notification history toggle label" - }, - { - "term": "Enable Overview Overlay", - "context": "Enable Overview Overlay", - "reference": "Modules/Settings/LauncherTab.qml:508", - "comment": "" - }, - { - "term": "Enable Ripple Effects", - "context": "Enable Ripple Effects", - "reference": "Modules/Settings/TypographyMotionTab.qml:476", - "comment": "" - }, - { - "term": "Enable System Sounds", - "context": "Enable System Sounds", - "reference": "Modules/Settings/SoundsTab.qml:36", - "comment": "" - }, - { - "term": "Enable Video Screensaver", - "context": "Enable Video Screensaver", - "reference": "Modules/Settings/LockScreenTab.qml:282", - "comment": "" - }, - { - "term": "Enable Weather", - "context": "Enable Weather", - "reference": "Modules/Settings/TimeWeatherTab.qml:400", - "comment": "" - }, - { - "term": "Enable WiFi", - "context": "Enable WiFi", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:244", - "comment": "" - }, - { - "term": "Enable a custom override below to set per-bar shadow intensity, opacity, and color.", - "context": "Enable a custom override below to set per-bar shadow intensity, opacity, and color.", - "reference": "Modules/Settings/DankBarTab.qml:1064", - "comment": "" - }, - { - "term": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", - "context": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", - "reference": "Modules/Settings/WallpaperTab.qml:1281", - "comment": "" - }, - { - "term": "Enable fingerprint at login", - "context": "Enable fingerprint at login", - "reference": "Modules/Settings/GreeterTab.qml:538", - "comment": "" - }, - { - "term": "Enable fingerprint authentication", - "context": "Enable fingerprint authentication", - "reference": "Modules/Settings/LockScreenTab.qml:228", - "comment": "" - }, - { - "term": "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.", - "context": "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.", - "reference": "Modules/Settings/GreeterTab.qml:528", - "comment": "" - }, - { - "term": "Enable loginctl lock integration", - "context": "Enable loginctl lock integration", - "reference": "Modules/Settings/LockScreenTab.qml:177", - "comment": "" - }, - { - "term": "Enable security key at login", - "context": "Enable security key at login", - "reference": "Modules/Settings/GreeterTab.qml:549", - "comment": "" - }, - { - "term": "Enable security key authentication", - "context": "Enable security key authentication", - "reference": "Modules/Settings/LockScreenTab.qml:239", - "comment": "Enable FIDO2/U2F hardware security key for lock screen" - }, - { - "term": "Enabled", - "context": "Enabled", - "reference": "Modules/Settings/ThemeColorsTab.qml:1389, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1226, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1234, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1260, Modules/ControlCenter/Components/DragDropGrid.qml:318", - "comment": "bluetooth status" - }, - { - "term": "Enabled, but fingerprint availability could not be confirmed.", - "context": "Enabled, but fingerprint availability could not be confirmed.", - "reference": "Modules/Settings/GreeterTab.qml:49, Modules/Settings/LockScreenTab.qml:28", - "comment": "" - }, - { - "term": "Enabled, but no fingerprint reader was detected.", - "context": "Enabled, but no fingerprint reader was detected.", - "reference": "Modules/Settings/GreeterTab.qml:45, Modules/Settings/LockScreenTab.qml:24", - "comment": "" - }, - { - "term": "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.", - "context": "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.", - "reference": "Modules/Settings/LockScreenTab.qml:21", - "comment": "" - }, - { - "term": "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.", - "context": "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.", - "reference": "Modules/Settings/GreeterTab.qml:42", - "comment": "" - }, - { - "term": "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.", - "context": "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.", - "reference": "Modules/Settings/LockScreenTab.qml:38", - "comment": "" - }, - { - "term": "Enabled, but no registered security key was found yet. Register a key and run Sync.", - "context": "Enabled, but no registered security key was found yet. Register a key and run Sync.", - "reference": "Modules/Settings/GreeterTab.qml:66", - "comment": "" - }, - { - "term": "Enabled, but security-key availability could not be confirmed.", - "context": "Enabled, but security-key availability could not be confirmed.", - "reference": "Modules/Settings/GreeterTab.qml:71, Modules/Settings/LockScreenTab.qml:43", - "comment": "" - }, - { - "term": "Enabled. PAM already provides fingerprint auth.", - "context": "Enabled. PAM already provides fingerprint auth.", - "reference": "Modules/Settings/GreeterTab.qml:27", - "comment": "" - }, - { - "term": "Enabled. PAM already provides security-key auth.", - "context": "Enabled. PAM already provides security-key auth.", - "reference": "Modules/Settings/GreeterTab.qml:58", - "comment": "" - }, - { - "term": "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.", - "context": "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.", - "reference": "Modules/Settings/GreeterTab.qml:29", - "comment": "" - }, - { - "term": "Enabling WiFi...", - "context": "Enabling WiFi...", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:192, Modules/ControlCenter/Components/DragDropGrid.qml:293", - "comment": "network status" - }, - { - "term": "End", - "context": "End", - "reference": "Modules/Settings/ThemeColorsTab.qml:1204, Modules/Settings/GammaControlTab.qml:295", - "comment": "" - }, - { - "term": "Enlarge on Hover", - "context": "Enlarge on Hover", - "reference": "Modules/Settings/WidgetsTabSection.qml:2801", - "comment": "" - }, - { - "term": "Enlargement %", - "context": "Enlargement %", - "reference": "Modules/Settings/WidgetsTabSection.qml:2840", - "comment": "" - }, - { - "term": "Enter 6-digit passkey", - "context": "Enter 6-digit passkey", - "reference": "Modals/BluetoothPairingModal.qml:211", - "comment": "" - }, - { - "term": "Enter PIN", - "context": "Enter PIN", - "reference": "Modals/BluetoothPairingModal.qml:176", - "comment": "" - }, - { - "term": "Enter PIN for ", - "context": "Enter PIN for ", - "reference": "Modals/BluetoothPairingModal.qml:137, Modals/WifiPasswordModal.qml:351", - "comment": "" - }, - { - "term": "Enter URL or text to share", - "context": "Enter URL or text to share", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:73", - "comment": "KDE Connect share input placeholder" - }, - { - "term": "Enter a new name for session \"%1\"", - "context": "Enter a new name for session \"%1\"", - "reference": "Modals/MuxModal.qml:90", - "comment": "" - }, - { - "term": "Enter a new name for this workspace", - "context": "Enter a new name for this workspace", - "reference": "Modals/WorkspaceRenameModal.qml:86", - "comment": "" - }, - { - "term": "Enter command or script path", - "context": "Enter command or script path", - "reference": "Modules/Settings/MuxTab.qml:78", - "comment": "" - }, - { - "term": "Enter credentials for ", - "context": "Enter credentials for ", - "reference": "Modals/WifiPasswordModal.qml:353, Modals/WifiPasswordModal.qml:358", - "comment": "" - }, - { - "term": "Enter custom lock screen format (e.g., dddd, MMMM d)", - "context": "Enter custom lock screen format (e.g., dddd, MMMM d)", - "reference": "Modules/Settings/TimeWeatherTab.qml:284", - "comment": "" - }, - { - "term": "Enter custom top bar format (e.g., ddd MMM d)", - "context": "Enter custom top bar format (e.g., ddd MMM d)", - "reference": "Modules/Settings/TimeWeatherTab.qml:197", - "comment": "" - }, - { - "term": "Enter device name...", - "context": "Enter device name...", - "reference": "Modules/Settings/AudioTab.qml:627", - "comment": "Audio device rename dialog placeholder" - }, - { - "term": "Enter filename...", - "context": "Enter filename...", - "reference": "Modals/FileBrowser/FileBrowserSaveRow.qml:24", - "comment": "" - }, - { - "term": "Enter launch prefix (e.g., 'uwsm-app')", - "context": "Enter launch prefix (e.g., 'uwsm-app')", - "reference": "Modules/Settings/LauncherTab.qml:325", - "comment": "" - }, - { - "term": "Enter network name and password", - "context": "Enter network name and password", - "reference": "Modals/WifiPasswordModal.qml:357", - "comment": "" - }, - { - "term": "Enter passkey for ", - "context": "Enter passkey for ", - "reference": "Modals/BluetoothPairingModal.qml:139", - "comment": "" - }, - { - "term": "Enter password for ", - "context": "Enter password for ", - "reference": "Modals/WifiPasswordModal.qml:355, Modals/WifiPasswordModal.qml:358", - "comment": "" - }, - { - "term": "Enter this passkey on ", - "context": "Enter this passkey on ", - "reference": "Modals/BluetoothPairingModal.qml:133", - "comment": "" - }, - { - "term": "Enter to Paste", - "context": "Enter to Paste", - "reference": "Modules/Settings/ClipboardTab.qml:435", - "comment": "" - }, - { - "term": "Enterprise", - "context": "Enterprise", - "reference": "Modules/Settings/NetworkTab.qml:1448", - "comment": "" - }, - { - "term": "Entry pinned", - "context": "Entry pinned", - "reference": "Services/ClipboardService.qml:202", - "comment": "" - }, - { - "term": "Entry unpinned", - "context": "Entry unpinned", - "reference": "Services/ClipboardService.qml:216", - "comment": "" - }, - { - "term": "Environment Variables", - "context": "Environment Variables", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:943", - "comment": "" - }, - { - "term": "Error", - "context": "Error", - "reference": "Modules/SystemUpdatePopout.qml:72, Services/CupsService.qml:834", - "comment": "" - }, - { - "term": "Errors", - "context": "Errors", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:248", - "comment": "greeter doctor page status card" - }, - { - "term": "Ethernet", - "context": "Ethernet", - "reference": "Modules/Settings/NetworkTab.qml:211, Modules/Settings/NetworkTab.qml:260, Modules/Settings/NetworkTab.qml:328, Modules/ControlCenter/Details/NetworkDetail.qml:136, Modules/ControlCenter/Components/DragDropGrid.qml:297, Modules/ControlCenter/Components/DragDropGrid.qml:300", - "comment": "network status" - }, - { - "term": "Exact", - "context": "Exact", - "reference": "Modules/Settings/NotificationsTab.qml:108", - "comment": "notification rule match type option" - }, - { - "term": "Exclusive Zone Offset", - "context": "Exclusive Zone Offset", - "reference": "Modules/Settings/DockTab.qml:546, Modules/Settings/DankBarTab.qml:830", - "comment": "" - }, - { - "term": "Experimental Feature", - "context": "Experimental Feature", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:200", - "comment": "" - }, - { - "term": "Explore", - "context": "Explore", - "reference": "Modals/Greeter/GreeterCompletePage.qml:453", - "comment": "greeter explore section header" - }, - { - "term": "Exponential", - "context": "Exponential", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:445", - "comment": "" - }, - { - "term": "Expressive", - "context": "Expressive", - "reference": "Common/Theme.qml:479", - "comment": "matugen color scheme option" - }, - { - "term": "Extend battery life", - "context": "Extend battery life", - "reference": "Common/Theme.qml:1485", - "comment": "power profile description" - }, - { - "term": "Extensible architecture", - "context": "Extensible architecture", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:123", - "comment": "greeter feature card description" - }, - { - "term": "External Wallpaper Management", - "context": "External Wallpaper Management", - "reference": "Modules/Settings/WallpaperTab.qml:1242", - "comment": "wallpaper settings external management" - }, - { - "term": "Extra Arguments", - "context": "Extra Arguments", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:969", - "comment": "" - }, - { - "term": "F1/I: Toggle • F10: Help", - "context": "F1/I: Toggle • F10: Help", - "reference": "Modals/FileBrowser/FileInfo.qml:200", - "comment": "" - }, - { - "term": "Fade", - "context": "Fade", - "reference": "Modules/Settings/WallpaperTab.qml:1163", - "comment": "wallpaper transition option" - }, - { - "term": "Fade to lock screen", - "context": "Fade to lock screen", - "reference": "Modules/Settings/PowerSleepTab.qml:74", - "comment": "" - }, - { - "term": "Fade to monitor off", - "context": "Fade to monitor off", - "reference": "Modules/Settings/PowerSleepTab.qml:83", - "comment": "" - }, - { - "term": "Failed to accept pairing", - "context": "Failed to accept pairing", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:161", - "comment": "Phone Connect error" - }, - { - "term": "Failed to activate configuration", - "context": "Failed to activate configuration", - "reference": "Services/DMSNetworkService.qml:384", - "comment": "" - }, - { - "term": "Failed to activate profile - file not found", - "context": "Failed to activate profile - file not found", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:273", - "comment": "" - }, - { - "term": "Failed to add binds include", - "context": "Failed to add binds include", - "reference": "Services/KeybindsService.qml:251", - "comment": "" - }, - { - "term": "Failed to add printer to class", - "context": "Failed to add printer to class", - "reference": "Services/CupsService.qml:710", - "comment": "" - }, - { - "term": "Failed to browse device", - "context": "Failed to browse device", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:143", - "comment": "Phone Connect error" - }, - { - "term": "Failed to cancel all jobs", - "context": "Failed to cancel all jobs", - "reference": "Services/CupsService.qml:439", - "comment": "" - }, - { - "term": "Failed to cancel selected job", - "context": "Failed to cancel selected job", - "reference": "Services/CupsService.qml:423", - "comment": "" - }, - { - "term": "Failed to check for updates:\n%1", - "context": "Failed to check for updates:\n%1", - "reference": "Modules/SystemUpdatePopout.qml:141", - "comment": "" - }, - { - "term": "Failed to check pin limit", - "context": "Failed to check pin limit", - "reference": "Services/ClipboardService.qml:185", - "comment": "" - }, - { - "term": "Failed to connect VPN", - "context": "Failed to connect VPN", - "reference": "Services/DMSNetworkService.qml:830", - "comment": "" - }, - { - "term": "Failed to connect to %1", - "context": "Failed to connect to %1", - "reference": "Services/DMSNetworkService.qml:355", - "comment": "" - }, - { - "term": "Failed to copy entry", - "context": "Failed to copy entry", - "reference": "Services/ClipboardService.qml:105, Services/ClipboardService.qml:125", - "comment": "" - }, - { - "term": "Failed to create printer", - "context": "Failed to create printer", - "reference": "Services/CupsService.qml:520", - "comment": "" - }, - { - "term": "Failed to create profiles directory", - "context": "Failed to create profiles directory", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:193", - "comment": "" - }, - { - "term": "Failed to delete VPN", - "context": "Failed to delete VPN", - "reference": "Services/VPNService.qml:157", - "comment": "" - }, - { - "term": "Failed to delete class", - "context": "Failed to delete class", - "reference": "Services/CupsService.qml:743", - "comment": "" - }, - { - "term": "Failed to delete printer", - "context": "Failed to delete printer", - "reference": "Services/CupsService.qml:537", - "comment": "" - }, - { - "term": "Failed to disable job acceptance", - "context": "Failed to disable job acceptance", - "reference": "Services/CupsService.qml:573", - "comment": "" - }, - { - "term": "Failed to disable night mode", - "context": "Failed to disable night mode", - "reference": "Services/DisplayService.qml:484", - "comment": "" - }, - { - "term": "Failed to disconnect VPN", - "context": "Failed to disconnect VPN", - "reference": "Services/DMSNetworkService.qml:854", - "comment": "" - }, - { - "term": "Failed to disconnect VPNs", - "context": "Failed to disconnect VPNs", - "reference": "Services/DMSNetworkService.qml:872", - "comment": "" - }, - { - "term": "Failed to disconnect WiFi", - "context": "Failed to disconnect WiFi", - "reference": "Services/DMSNetworkService.qml:478", - "comment": "" - }, - { - "term": "Failed to enable IP location", - "context": "Failed to enable IP location", - "reference": "Services/DisplayService.qml:624", - "comment": "" - }, - { - "term": "Failed to enable WiFi", - "context": "Failed to enable WiFi", - "reference": "Services/DMSNetworkService.qml:581", - "comment": "" - }, - { - "term": "Failed to enable job acceptance", - "context": "Failed to enable job acceptance", - "reference": "Services/CupsService.qml:557", - "comment": "" - }, - { - "term": "Failed to enable night mode", - "context": "Failed to enable night mode", - "reference": "Services/DisplayService.qml:456", - "comment": "" - }, - { - "term": "Failed to hold job", - "context": "Failed to hold job", - "reference": "Services/CupsService.qml:693", - "comment": "" - }, - { - "term": "Failed to import VPN", - "context": "Failed to import VPN", - "reference": "Services/VPNService.qml:84, Services/VPNService.qml:98", - "comment": "" - }, - { - "term": "Failed to launch SMS app", - "context": "Failed to launch SMS app", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:133", - "comment": "Phone Connect error" - }, - { - "term": "Failed to load VPN config", - "context": "Failed to load VPN config", - "reference": "Services/VPNService.qml:114", - "comment": "" - }, - { - "term": "Failed to load clipboard configuration.", - "context": "Failed to load clipboard configuration.", - "reference": "Modules/Settings/ClipboardTab.qml:267", - "comment": "" - }, - { - "term": "Failed to move job", - "context": "Failed to move job", - "reference": "Services/CupsService.qml:658", - "comment": "" - }, - { - "term": "Failed to parse plugin_settings.json", - "context": "Failed to parse plugin_settings.json", - "reference": "Common/SettingsData.qml:1380", - "comment": "" - }, - { - "term": "Failed to parse session.json", - "context": "Failed to parse session.json", - "reference": "Common/SessionData.qml:208, Common/SessionData.qml:287", - "comment": "" - }, - { - "term": "Failed to parse settings.json", - "context": "Failed to parse settings.json", - "reference": "Common/SettingsData.qml:1283, Common/SettingsData.qml:2783", - "comment": "" - }, - { - "term": "Failed to pause printer", - "context": "Failed to pause printer", - "reference": "Services/CupsService.qml:390", - "comment": "" - }, - { - "term": "Failed to pin entry", - "context": "Failed to pin entry", - "reference": "Services/ClipboardService.qml:199", - "comment": "" - }, - { - "term": "Failed to print test page", - "context": "Failed to print test page", - "reference": "Services/CupsService.qml:640", - "comment": "" - }, - { - "term": "Failed to reject pairing", - "context": "Failed to reject pairing", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:170", - "comment": "Phone Connect error" - }, - { - "term": "Failed to remove device", - "context": "Failed to remove device", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:725", - "comment": "" - }, - { - "term": "Failed to remove keybind", - "context": "Failed to remove keybind", - "reference": "Services/KeybindsService.qml:228", - "comment": "" - }, - { - "term": "Failed to remove printer from class", - "context": "Failed to remove printer from class", - "reference": "Services/CupsService.qml:727", - "comment": "" - }, - { - "term": "Failed to restart audio system", - "context": "Failed to restart audio system", - "reference": "Services/AudioService.qml:278", - "comment": "" - }, - { - "term": "Failed to restart job", - "context": "Failed to restart job", - "reference": "Services/CupsService.qml:674", - "comment": "" - }, - { - "term": "Failed to resume printer", - "context": "Failed to resume printer", - "reference": "Services/CupsService.qml:406", - "comment": "" - }, - { - "term": "Failed to ring device", - "context": "Failed to ring device", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:96", - "comment": "Phone Connect error" - }, - { - "term": "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.", - "context": "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.", - "reference": "Modules/Settings/GreeterTab.qml:274", - "comment": "greeter status error" - }, - { - "term": "Failed to save audio config", - "context": "Failed to save audio config", - "reference": "Services/AudioService.qml:163", - "comment": "" - }, - { - "term": "Failed to save clipboard setting", - "context": "Failed to save clipboard setting", - "reference": "Modules/Settings/ClipboardTab.qml:210", - "comment": "" - }, - { - "term": "Failed to save keybind", - "context": "Failed to save keybind", - "reference": "Services/KeybindsService.qml:202", - "comment": "" - }, - { - "term": "Failed to save profile file", - "context": "Failed to save profile file", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:199", - "comment": "" - }, - { - "term": "Failed to send clipboard", - "context": "Failed to send clipboard", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:114", - "comment": "Phone Connect error" - }, - { - "term": "Failed to send file", - "context": "Failed to send file", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:361, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:421", - "comment": "Phone Connect error" - }, - { - "term": "Failed to send ping", - "context": "Failed to send ping", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:105", - "comment": "Phone Connect error" - }, - { - "term": "Failed to set brightness", - "context": "Failed to set brightness", - "reference": "Services/DisplayService.qml:322", - "comment": "" - }, - { - "term": "Failed to set night mode location", - "context": "Failed to set night mode location", - "reference": "Services/DisplayService.qml:644", - "comment": "" - }, - { - "term": "Failed to set night mode schedule", - "context": "Failed to set night mode schedule", - "reference": "Services/DisplayService.qml:586", - "comment": "" - }, - { - "term": "Failed to set night mode temperature", - "context": "Failed to set night mode temperature", - "reference": "Services/DisplayService.qml:525, Services/DisplayService.qml:576, Services/DisplayService.qml:614", - "comment": "" - }, - { - "term": "Failed to set power profile", - "context": "Failed to set power profile", - "reference": "Modules/DankBar/Popouts/BatteryPopout.qml:30", - "comment": "" - }, - { - "term": "Failed to set profile image", - "context": "Failed to set profile image", - "reference": "Services/PortalService.qml:145", - "comment": "" - }, - { - "term": "Failed to set profile image: %1", - "context": "Failed to set profile image: %1", - "reference": "Services/PortalService.qml:154", - "comment": "" - }, - { - "term": "Failed to share", - "context": "Failed to share", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:341, dms-plugins/DankKDEConnect/DankKDEConnect.qml:349, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:407", - "comment": "Phone Connect error" - }, - { - "term": "Failed to start connection to %1", - "context": "Failed to start connection to %1", - "reference": "Services/DMSNetworkService.qml:465", - "comment": "" - }, - { - "term": "Failed to unpin entry", - "context": "Failed to unpin entry", - "reference": "Services/ClipboardService.qml:213", - "comment": "" - }, - { - "term": "Failed to update VPN", - "context": "Failed to update VPN", - "reference": "Services/VPNService.qml:140", - "comment": "" - }, - { - "term": "Failed to update autoconnect", - "context": "Failed to update autoconnect", - "reference": "Services/DMSNetworkService.qml:937", - "comment": "" - }, - { - "term": "Failed to update description", - "context": "Failed to update description", - "reference": "Services/CupsService.qml:624", - "comment": "" - }, - { - "term": "Failed to update location", - "context": "Failed to update location", - "reference": "Services/CupsService.qml:607", - "comment": "" - }, - { - "term": "Failed to update sharing", - "context": "Failed to update sharing", - "reference": "Services/CupsService.qml:590", - "comment": "" - }, - { - "term": "Failed to write temp file for validation", - "context": "Failed to write temp file for validation", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1294", - "comment": "" - }, - { - "term": "Features", - "context": "Features", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:75", - "comment": "greeter welcome page section header" - }, - { - "term": "Feels", - "context": "Feels", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:401", - "comment": "" - }, - { - "term": "Feels Like", - "context": "Feels Like", - "reference": "Modules/Settings/TimeWeatherTab.qml:889", - "comment": "" - }, - { - "term": "Feels Like %1°", - "context": "Feels Like %1°", - "reference": "Modules/DankDash/WeatherTab.qml:309, Modules/Settings/TimeWeatherTab.qml:776", - "comment": "weather feels like temperature" - }, - { - "term": "Fidelity", - "context": "Fidelity", - "reference": "Common/Theme.qml:483", - "comment": "matugen color scheme option" - }, - { - "term": "Field", - "context": "Field", - "reference": "Modules/Settings/NotificationsTab.qml:545", - "comment": "" - }, - { - "term": "File", - "context": "File", - "reference": "Services/CupsService.qml:137, Modals/DankLauncherV2/ResultItem.qml:185", - "comment": "" - }, - { - "term": "File Already Exists", - "context": "File Already Exists", - "reference": "Modals/FileBrowser/FileBrowserOverwriteDialog.qml:53", - "comment": "" - }, - { - "term": "File Information", - "context": "File Information", - "reference": "Modals/FileBrowser/FileInfo.qml:137", - "comment": "" - }, - { - "term": "File received from", - "context": "File received from", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:79", - "comment": "Phone Connect file share notification" - }, - { - "term": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch", - "context": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch", - "reference": "Modals/DankLauncherV2/ResultsList.qml:473", - "comment": "" - }, - { - "term": "Files", - "context": "Files", - "reference": "Modals/DankLauncherV2/Controller.qml:167, Modals/DankLauncherV2/Controller.qml:1028, Modals/DankLauncherV2/Controller.qml:1049, Modals/DankLauncherV2/LauncherContent.qml:358, Modals/DankLauncherV2/LauncherContent.qml:629, Modules/Settings/LauncherTab.qml:642", - "comment": "" - }, - { - "term": "Filesystem usage monitoring", - "context": "Filesystem usage monitoring", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:170", - "comment": "" - }, - { - "term": "Fill", - "context": "Fill", - "reference": "Modules/Settings/GreeterTab.qml:698, Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Find in Text", - "context": "Find in Text", - "reference": "Modules/Notepad/NotepadSettings.qml:185", - "comment": "" - }, - { - "term": "Find in note...", - "context": "Find in note...", - "reference": "Modules/Notepad/NotepadTextEditor.qml:381", - "comment": "" - }, - { - "term": "Fingerprint availability could not be confirmed.", - "context": "Fingerprint availability could not be confirmed.", - "reference": "Modules/Settings/GreeterTab.qml:49, Modules/Settings/LockScreenTab.qml:28", - "comment": "" - }, - { - "term": "Fingerprint error", - "context": "Fingerprint error", - "reference": "Modules/Lock/LockScreenContent.qml:63", - "comment": "" - }, - { - "term": "Fingerprint error: %1", - "context": "Fingerprint error: %1", - "reference": "Modules/Lock/LockScreenContent.qml:63", - "comment": "" - }, - { - "term": "Fingerprint not recognized (%1/%2). Please try again or use password.", - "context": "Fingerprint not recognized (%1/%2). Please try again or use password.", - "reference": "Modules/Lock/LockScreenContent.qml:68", - "comment": "" - }, - { - "term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.", - "context": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.", - "reference": "Modules/Settings/LockScreenTab.qml:22", - "comment": "" - }, - { - "term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.", - "context": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.", - "reference": "Modules/Settings/GreeterTab.qml:43", - "comment": "" - }, - { - "term": "Finish", - "context": "Finish", - "reference": "Modals/Greeter/GreeterModal.qml:304", - "comment": "greeter finish button" - }, - { - "term": "First Day of Week", - "context": "First Day of Week", - "reference": "Modules/Settings/TimeWeatherTab.qml:102", - "comment": "" - }, - { - "term": "First Time Setup", - "context": "First Time Setup", - "reference": "Modules/Settings/KeybindsTab.qml:326, Modules/Settings/DisplayConfig/IncludeWarningBox.qml:48", - "comment": "" - }, - { - "term": "Fit", - "context": "Fit", - "reference": "Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Fix Now", - "context": "Fix Now", - "reference": "Modules/Settings/ThemeColorsTab.qml:2317, Modules/Settings/WindowRulesTab.qml:367, Modules/Settings/KeybindsTab.qml:371, Modules/Settings/DisplayConfig/IncludeWarningBox.qml:84", - "comment": "" - }, - { - "term": "Fixing...", - "context": "Fixing...", - "reference": "Modules/Settings/ThemeColorsTab.qml:2317, Modules/Settings/WindowRulesTab.qml:367, Modules/Settings/KeybindsTab.qml:368, Modules/Settings/DisplayConfig/IncludeWarningBox.qml:81", - "comment": "" - }, - { - "term": "Flags", - "context": "Flags", - "reference": "Widgets/KeybindItem.qml:1552", - "comment": "" - }, - { - "term": "Flipped", - "context": "Flipped", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1801, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1822", - "comment": "" - }, - { - "term": "Flipped 180°", - "context": "Flipped 180°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1805, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1826", - "comment": "" - }, - { - "term": "Flipped 270°", - "context": "Flipped 270°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1807, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1828", - "comment": "" - }, - { - "term": "Flipped 90°", - "context": "Flipped 90°", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1803, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1824", - "comment": "" - }, - { - "term": "Float", - "context": "Float", - "reference": "Modals/WindowRuleModal.qml:527, Modules/Settings/WindowRulesTab.qml:535", - "comment": "" - }, - { - "term": "Focus", - "context": "Focus", - "reference": "Modals/WindowRuleModal.qml:544, Modules/Settings/WindowRulesTab.qml:539", - "comment": "" - }, - { - "term": "Focus at Startup", - "context": "Focus at Startup", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:70, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1236", - "comment": "" - }, - { - "term": "Focused Border", - "context": "Focused Border", - "reference": "Modules/Settings/WorkspacesTab.qml:354", - "comment": "" - }, - { - "term": "Focused Color", - "context": "Focused Color", - "reference": "Modules/Settings/WorkspacesTab.qml:196", - "comment": "" - }, - { - "term": "Focused Monitor Only", - "context": "Focused Monitor Only", - "reference": "Modules/Settings/NotificationsTab.qml:297", - "comment": "" - }, - { - "term": "Focused Window", - "context": "Focused Window", - "reference": "Modules/Settings/WidgetsTab.qml:59", - "comment": "" - }, - { - "term": "Focused monitor only", - "context": "Focused monitor only", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:422", - "comment": "" - }, - { - "term": "Fog", - "context": "Fog", - "reference": "Services/WeatherService.qml:126, Services/WeatherService.qml:127", - "comment": "" - }, - { - "term": "Folder", - "context": "Folder", - "reference": "Modals/DankLauncherV2/ResultItem.qml:185", - "comment": "" - }, - { - "term": "Folders", - "context": "Folders", - "reference": "Modals/DankLauncherV2/Controller.qml:1039, Modals/DankLauncherV2/Controller.qml:1049, Modals/DankLauncherV2/LauncherContent.qml:634, Modules/Settings/LauncherTab.qml:653", - "comment": "" - }, - { - "term": "Follow DMS background color", - "context": "Follow DMS background color", - "reference": "Modules/Settings/ThemeColorsTab.qml:2754", - "comment": "" - }, - { - "term": "Follow Monitor Focus", - "context": "Follow Monitor Focus", - "reference": "Modules/Settings/WorkspacesTab.qml:141", - "comment": "" - }, - { - "term": "Follow focus", - "context": "Follow focus", - "reference": "Widgets/KeybindItem.qml:1311", - "comment": "" - }, - { - "term": "Font", - "context": "Font", - "reference": "Modules/Settings/GreeterTab.qml:565", - "comment": "" - }, - { - "term": "Font Family", - "context": "Font Family", - "reference": "Modules/Notepad/NotepadSettings.qml:211", - "comment": "" - }, - { - "term": "Font Scale", - "context": "Font Scale", - "reference": "Modules/Settings/TypographyMotionTab.qml:183, Modules/Settings/DankBarTab.qml:951", - "comment": "" - }, - { - "term": "Font Size", - "context": "Font Size", - "reference": "Modules/Notepad/NotepadSettings.qml:245", - "comment": "" - }, - { - "term": "Font Weight", - "context": "Font Weight", - "reference": "Modules/Settings/TypographyMotionTab.qml:114", - "comment": "" - }, - { - "term": "Font used on the login screen", - "context": "Font used on the login screen", - "reference": "Modules/Settings/GreeterTab.qml:576", - "comment": "" - }, - { - "term": "Force HDR", - "context": "Force HDR", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1256", - "comment": "" - }, - { - "term": "Force Kill (SIGKILL)", - "context": "Force Kill (SIGKILL)", - "reference": "Modules/ProcessList/ProcessContextMenu.qml:49", - "comment": "" - }, - { - "term": "Force Wide Color", - "context": "Force Wide Color", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1258", - "comment": "" - }, - { - "term": "Force terminal applications to always use dark color schemes", - "context": "Force terminal applications to always use dark color schemes", - "reference": "Modules/Settings/ThemeColorsTab.qml:2248", - "comment": "" - }, - { - "term": "Forecast", - "context": "Forecast", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:27", - "comment": "" - }, - { - "term": "Forecast Days", - "context": "Forecast Days", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:127", - "comment": "" - }, - { - "term": "Forecast Not Available", - "context": "Forecast Not Available", - "reference": "Modules/DankDash/WeatherForecastCard.qml:115", - "comment": "" - }, - { - "term": "Forever", - "context": "Forever", - "reference": "Modules/Settings/NotificationsTab.qml:837, Modules/Settings/NotificationsTab.qml:852, Modules/Settings/NotificationsTab.qml:855", - "comment": "notification history retention option" - }, - { - "term": "Forget", - "context": "Forget", - "reference": "Modules/Settings/NetworkTab.qml:1313", - "comment": "" - }, - { - "term": "Forget \"%1\"?", - "context": "Forget \"%1\"?", - "reference": "Modules/Settings/NetworkTab.qml:1312", - "comment": "" - }, - { - "term": "Forget Device", - "context": "Forget Device", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:697", - "comment": "" - }, - { - "term": "Forget Network", - "context": "Forget Network", - "reference": "Modules/Settings/NetworkTab.qml:1311, Modules/ControlCenter/Details/NetworkDetail.qml:859", - "comment": "" - }, - { - "term": "Forgot network %1", - "context": "Forgot network %1", - "reference": "Services/DMSNetworkService.qml:538", - "comment": "" - }, - { - "term": "Format Legend", - "context": "Format Legend", - "reference": "Modules/Settings/TimeWeatherTab.qml:313", - "comment": "" - }, - { - "term": "Found %1 package to update:", - "context": "Found %1 package to update:", - "reference": "Modules/SystemUpdatePopout.qml:153", - "comment": "" - }, - { - "term": "Found %1 packages to update:", - "context": "Found %1 packages to update:", - "reference": "Modules/SystemUpdatePopout.qml:154", - "comment": "" - }, - { - "term": "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.", - "context": "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.", - "reference": "Modules/Settings/LauncherTab.qml:424", - "comment": "" - }, - { - "term": "Freezing Drizzle", - "context": "Freezing Drizzle", - "reference": "Services/WeatherService.qml:131, Services/WeatherService.qml:132", - "comment": "" - }, - { - "term": "Frequency", - "context": "Frequency", - "reference": "Modules/Settings/NetworkTab.qml:1423", - "comment": "" - }, - { - "term": "Fruit Salad", - "context": "Fruit Salad", - "reference": "Common/Theme.qml:487", - "comment": "matugen color scheme option" - }, - { - "term": "Full Command:", - "context": "Full Command:", - "reference": "Modules/ProcessList/ProcessesView.qml:681", - "comment": "process detail label" - }, - { - "term": "Full Content", - "context": "Full Content", - "reference": "Modules/Settings/LockScreenTab.qml:148, Modules/Settings/NotificationsTab.qml:729", - "comment": "lock screen notification mode option" - }, - { - "term": "Full Day & Month", - "context": "Full Day & Month", - "reference": "Modules/Settings/GreeterTab.qml:426, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:166, Modules/Settings/TimeWeatherTab.qml:182, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:253, Modules/Settings/TimeWeatherTab.qml:269", - "comment": "date format option" - }, - { - "term": "Full with Year", - "context": "Full with Year", - "reference": "Modules/Settings/GreeterTab.qml:418, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:158, Modules/Settings/TimeWeatherTab.qml:180, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:245, Modules/Settings/TimeWeatherTab.qml:267", - "comment": "date format option" - }, - { - "term": "Fullscreen", - "context": "Fullscreen", - "reference": "Modals/WindowRuleModal.qml:535, Modules/Settings/WindowRulesTab.qml:538", - "comment": "" - }, - { - "term": "Fullscreen Only", - "context": "Fullscreen Only", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:280, Modules/Settings/DisplayConfig/OutputCard.qml:284, Modules/Settings/DisplayConfig/OutputCard.qml:293", - "comment": "" - }, - { - "term": "Fully Charged", - "context": "Fully Charged", - "reference": "Services/BatteryService.qml:142", - "comment": "battery status" - }, - { - "term": "Fun", - "context": "Fun", - "reference": "Widgets/DankIconPicker.qml:59", - "comment": "" - }, - { - "term": "G: grid • Z/X: size", - "context": "G: grid • Z/X: size", - "reference": "Modules/Plugins/DesktopPluginWrapper.qml:746", - "comment": "Widget grid keyboard hints" - }, - { - "term": "GPU", - "context": "GPU", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:138", - "comment": "" - }, - { - "term": "GPU Monitoring", - "context": "GPU Monitoring", - "reference": "Modules/ProcessList/SystemView.qml:117", - "comment": "gpu section header in system monitor" - }, - { - "term": "GPU Temperature", - "context": "GPU Temperature", - "reference": "Modules/Settings/WidgetsTab.qml:140, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:116", - "comment": "" - }, - { - "term": "GPU temperature display", - "context": "GPU temperature display", - "reference": "Modules/Settings/WidgetsTab.qml:141", - "comment": "" - }, - { - "term": "GTK, Qt, IDEs, more", - "context": "GTK, Qt, IDEs, more", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:99", - "comment": "greeter feature card description" - }, - { - "term": "Games", - "context": "Games", - "reference": "Services/AppSearchService.qml:643", - "comment": "" - }, - { - "term": "Gamma Control", - "context": "Gamma Control", - "reference": "Modals/Settings/SettingsSidebar.qml:218, Modules/Settings/GammaControlTab.qml:64", - "comment": "" - }, - { - "term": "Gamma control not available. Requires DMS API v6+.", - "context": "Gamma control not available. Requires DMS API v6+.", - "reference": "Modules/Settings/GammaControlTab.qml:77", - "comment": "" - }, - { - "term": "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.", - "context": "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.", - "reference": "Modules/Settings/ThemeColorsTab.qml:2962", - "comment": "" - }, - { - "term": "Generic", - "context": "Generic", - "reference": "Modules/Settings/ThemeColorsTab.qml:289, Modules/Settings/ThemeColorsTab.qml:289", - "comment": "theme category option" - }, - { - "term": "Get Started", - "context": "Get Started", - "reference": "Modals/Greeter/GreeterModal.qml:295", - "comment": "greeter first page button" - }, - { - "term": "GitHub", - "context": "GitHub", - "reference": "Modules/Settings/AboutTab.qml:306", - "comment": "" - }, - { - "term": "Globally scale all animation durations", - "context": "Globally scale all animation durations", - "reference": "Modules/Settings/TypographyMotionTab.qml:243", - "comment": "" - }, - { - "term": "Golden Hour", - "context": "Golden Hour", - "reference": "Services/WeatherService.qml:250, Services/WeatherService.qml:265", - "comment": "" - }, - { - "term": "Good", - "context": "Good", - "reference": "Modules/Settings/TimeWeatherTab.qml:1134", - "comment": "" - }, - { - "term": "Goth Corner Radius", - "context": "Goth Corner Radius", - "reference": "Modules/Settings/DankBarTab.qml:1361", - "comment": "" - }, - { - "term": "Goth Corners", - "context": "Goth Corners", - "reference": "Modules/Settings/DankBarTab.qml:1336", - "comment": "" - }, - { - "term": "Gradually fade the screen before locking with a configurable grace period", - "context": "Gradually fade the screen before locking with a configurable grace period", - "reference": "Modules/Settings/PowerSleepTab.qml:75", - "comment": "" - }, - { - "term": "Gradually fade the screen before turning off monitors with a configurable grace period", - "context": "Gradually fade the screen before turning off monitors with a configurable grace period", - "reference": "Modules/Settings/PowerSleepTab.qml:84", - "comment": "" - }, - { - "term": "Graph Time Range", - "context": "Graph Time Range", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:48", - "comment": "" - }, - { - "term": "Graphics", - "context": "Graphics", - "reference": "Services/AppSearchService.qml:644, Services/AppSearchService.qml:645", - "comment": "" - }, - { - "term": "Greeter", - "context": "Greeter", - "reference": "Modals/Settings/SettingsSidebar.qml:298", - "comment": "" - }, - { - "term": "Greeter Appearance", - "context": "Greeter Appearance", - "reference": "Modules/Settings/GreeterTab.qml:561", - "comment": "" - }, - { - "term": "Greeter Behavior", - "context": "Greeter Behavior", - "reference": "Modules/Settings/GreeterTab.qml:720", - "comment": "" - }, - { - "term": "Greeter Status", - "context": "Greeter Status", - "reference": "Modules/Settings/GreeterTab.qml:447", - "comment": "" - }, - { - "term": "Greeter activated. greetd is now enabled.", - "context": "Greeter activated. greetd is now enabled.", - "reference": "Modules/Settings/GreeterTab.qml:381", - "comment": "" - }, - { - "term": "Greeter font", - "context": "Greeter font", - "reference": "Modules/Settings/GreeterTab.qml:575", - "comment": "" - }, - { - "term": "Greeter only — does not affect main clock", - "context": "Greeter only — does not affect main clock", - "reference": "Modules/Settings/GreeterTab.qml:602", - "comment": "" - }, - { - "term": "Greeter only — format for the date on the login screen", - "context": "Greeter only — format for the date on the login screen", - "reference": "Modules/Settings/GreeterTab.qml:636", - "comment": "" - }, - { - "term": "Grid", - "context": "Grid", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:351, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:355, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:364, Modules/DankBar/Popouts/DWLLayoutPopout.qml:48", - "comment": "" - }, - { - "term": "Grid Columns", - "context": "Grid Columns", - "reference": "Modules/Settings/LauncherTab.qml:348", - "comment": "" - }, - { - "term": "Grid: OFF", - "context": "Grid: OFF", - "reference": "Modules/Plugins/DesktopPluginWrapper.qml:716", - "comment": "Widget grid snap status" - }, - { - "term": "Grid: ON", - "context": "Grid: ON", - "reference": "Modules/Plugins/DesktopPluginWrapper.qml:716", - "comment": "Widget grid snap status" - }, - { - "term": "Group", - "context": "Group", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:240", - "comment": "" - }, - { - "term": "Group Workspace Apps", - "context": "Group Workspace Apps", - "reference": "Modules/Settings/WorkspacesTab.qml:121", - "comment": "" - }, - { - "term": "Group by App", - "context": "Group by App", - "reference": "Modules/Settings/WidgetsTabSection.qml:2255, Modules/Settings/DockTab.qml:157", - "comment": "" - }, - { - "term": "Group multiple windows of the same app together with a window count indicator", - "context": "Group multiple windows of the same app together with a window count indicator", - "reference": "Modules/Settings/DockTab.qml:158", - "comment": "" - }, - { - "term": "Group removed", - "context": "Group removed", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:237", - "comment": "" - }, - { - "term": "Group repeated application icons in unfocused workspaces", - "context": "Group repeated application icons in unfocused workspaces", - "reference": "Modules/Settings/WorkspacesTab.qml:122", - "comment": "" - }, - { - "term": "Groups", - "context": "Groups", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:112", - "comment": "" - }, - { - "term": "HDR (EDID)", - "context": "HDR (EDID)", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:145, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:155, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:166", - "comment": "" - }, - { - "term": "HDR Tone Mapping", - "context": "HDR Tone Mapping", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:229", - "comment": "" - }, - { - "term": "HDR mode is experimental. Verify your monitor supports HDR before enabling.", - "context": "HDR mode is experimental. Verify your monitor supports HDR before enabling.", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:208", - "comment": "" - }, - { - "term": "HSV", - "context": "HSV", - "reference": "Modals/DankColorPickerModal.qml:692", - "comment": "" - }, - { - "term": "HTML copied to clipboard", - "context": "HTML copied to clipboard", - "reference": "Modules/Notepad/NotepadTextEditor.qml:284", - "comment": "" - }, - { - "term": "Health", - "context": "Health", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:141, Modules/DankBar/Popouts/BatteryPopout.qml:298, Modules/DankBar/Popouts/BatteryPopout.qml:454", - "comment": "" - }, - { - "term": "Heavy Rain", - "context": "Heavy Rain", - "reference": "Services/WeatherService.qml:135, Services/WeatherService.qml:137, Services/WeatherService.qml:144", - "comment": "" - }, - { - "term": "Heavy Snow", - "context": "Heavy Snow", - "reference": "Services/WeatherService.qml:140", - "comment": "" - }, - { - "term": "Heavy Snow Showers", - "context": "Heavy Snow Showers", - "reference": "Services/WeatherService.qml:146", - "comment": "" - }, - { - "term": "Height", - "context": "Height", - "reference": "Modules/Settings/WindowRulesTab.qml:543", - "comment": "" - }, - { - "term": "Held", - "context": "Held", - "reference": "Services/CupsService.qml:761", - "comment": "" - }, - { - "term": "Help", - "context": "Help", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:614", - "comment": "" - }, - { - "term": "Hex", - "context": "Hex", - "reference": "Modals/DankColorPickerModal.qml:567", - "comment": "" - }, - { - "term": "Hibernate", - "context": "Hibernate", - "reference": "Modals/PowerMenuModal.qml:210, Modules/Lock/LockPowerMenu.qml:128, Modules/Settings/PowerSleepTab.qml:311, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Hidden", - "context": "Hidden", - "reference": "Modules/Settings/NetworkTab.qml:1228", - "comment": "" - }, - { - "term": "Hidden (%1)", - "context": "Hidden (%1)", - "reference": "Modules/Settings/AudioTab.qml:265, Modules/Settings/AudioTab.qml:409", - "comment": "count of hidden audio devices" - }, - { - "term": "Hidden Apps", - "context": "Hidden Apps", - "reference": "Modules/Settings/LauncherTab.qml:911", - "comment": "" - }, - { - "term": "Hidden Network", - "context": "Hidden Network", - "reference": "Modals/WifiPasswordModal.qml:252", - "comment": "" - }, - { - "term": "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.", - "context": "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.", - "reference": "Modules/Settings/LauncherTab.qml:941", - "comment": "" - }, - { - "term": "Hide", - "context": "Hide", - "reference": "Modules/Settings/DisplayConfigTab.qml:473", - "comment": "" - }, - { - "term": "Hide 3rd Party", - "context": "Hide 3rd Party", - "reference": "Modules/Settings/PluginBrowser.qml:273", - "comment": "" - }, - { - "term": "Hide App", - "context": "Hide App", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:112", - "comment": "" - }, - { - "term": "Hide Delay", - "context": "Hide Delay", - "reference": "Modules/Settings/DankBarTab.qml:620", - "comment": "" - }, - { - "term": "Hide Indicators", - "context": "Hide Indicators", - "reference": "Modules/Settings/WidgetsTabSection.qml:2649", - "comment": "" - }, - { - "term": "Hide Updater Widget", - "context": "Hide Updater Widget", - "reference": "Modules/Settings/SystemUpdaterTab.qml:29", - "comment": "When updater widget is used, then hide it if no update found" - }, - { - "term": "Hide When Typing", - "context": "Hide When Typing", - "reference": "Modules/Settings/ThemeColorsTab.qml:2361", - "comment": "" - }, - { - "term": "Hide When Windows Open", - "context": "Hide When Windows Open", - "reference": "Modules/Settings/DankBarTab.qml:643", - "comment": "" - }, - { - "term": "Hide cursor after inactivity (0 = disabled)", - "context": "Hide cursor after inactivity (0 = disabled)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2408", - "comment": "" - }, - { - "term": "Hide cursor when pressing keyboard keys", - "context": "Hide cursor when pressing keyboard keys", - "reference": "Modules/Settings/ThemeColorsTab.qml:2362", - "comment": "" - }, - { - "term": "Hide cursor when using touch input", - "context": "Hide cursor when using touch input", - "reference": "Modules/Settings/ThemeColorsTab.qml:2391", - "comment": "" - }, - { - "term": "Hide device", - "context": "Hide device", - "reference": "Modules/Settings/Widgets/DeviceAliasRow.qml:142", - "comment": "" - }, - { - "term": "Hide notification content until expanded", - "context": "Hide notification content until expanded", - "reference": "Modules/Notifications/Center/NotificationSettings.qml:316", - "comment": "" - }, - { - "term": "Hide notification content until expanded; popups show collapsed by default", - "context": "Hide notification content until expanded; popups show collapsed by default", - "reference": "Modules/Settings/NotificationsTab.qml:289", - "comment": "" - }, - { - "term": "Hide on Touch", - "context": "Hide on Touch", - "reference": "Modules/Settings/ThemeColorsTab.qml:2390", - "comment": "" - }, - { - "term": "High-fidelity palette that preserves source hues.", - "context": "High-fidelity palette that preserves source hues.", - "reference": "Common/Theme.qml:484", - "comment": "" - }, - { - "term": "Highlight Active Workspace App", - "context": "Highlight Active Workspace App", - "reference": "Modules/Settings/WorkspacesTab.qml:131", - "comment": "" - }, - { - "term": "Highlight the currently focused app inside workspace indicators", - "context": "Highlight the currently focused app inside workspace indicators", - "reference": "Modules/Settings/WorkspacesTab.qml:132", - "comment": "" - }, - { - "term": "History", - "context": "History", - "reference": "Modals/Clipboard/ClipboardHeader.qml:60, Modules/Notifications/Center/NotificationHeader.qml:151", - "comment": "notification center tab" - }, - { - "term": "History Retention", - "context": "History Retention", - "reference": "Modules/Settings/NotificationsTab.qml:832", - "comment": "notification history retention settings label" - }, - { - "term": "History Settings", - "context": "History Settings", - "reference": "Modules/Settings/NotificationsTab.qml:803, Modules/Settings/ClipboardTab.qml:278, Modules/Notifications/Center/NotificationSettings.qml:340", - "comment": "" - }, - { - "term": "History cleared. %1 pinned entries kept.", - "context": "History cleared. %1 pinned entries kept.", - "reference": "Services/ClipboardService.qml:232", - "comment": "" - }, - { - "term": "Hold Duration", - "context": "Hold Duration", - "reference": "Modules/Settings/PowerSleepTab.qml:485", - "comment": "" - }, - { - "term": "Hold longer to confirm", - "context": "Hold longer to confirm", - "reference": "Modals/PowerMenuModal.qml:792, Modules/Lock/LockPowerMenu.qml:800", - "comment": "" - }, - { - "term": "Hold to Confirm Power Actions", - "context": "Hold to Confirm Power Actions", - "reference": "Modules/Settings/PowerSleepTab.qml:472", - "comment": "" - }, - { - "term": "Hold to confirm (%1 ms)", - "context": "Hold to confirm (%1 ms)", - "reference": "Modals/PowerMenuModal.qml:795, Modals/PowerMenuModal.qml:799, Modules/Lock/LockPowerMenu.qml:803, Modules/Lock/LockPowerMenu.qml:807", - "comment": "" - }, - { - "term": "Hold to confirm (%1s)", - "context": "Hold to confirm (%1s)", - "reference": "Modals/PowerMenuModal.qml:796, Modals/PowerMenuModal.qml:800, Modules/Lock/LockPowerMenu.qml:804, Modules/Lock/LockPowerMenu.qml:808", - "comment": "" - }, - { - "term": "Home", - "context": "Home", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:241", - "comment": "" - }, - { - "term": "Host", - "context": "Host", - "reference": "Modules/Settings/PrinterTab.qml:501", - "comment": "Label for printer IP address or hostname input field" - }, - { - "term": "Hostname", - "context": "Hostname", - "reference": "Modules/ProcessList/SystemView.qml:60", - "comment": "system info label" - }, - { - "term": "Hot Corners", - "context": "Hot Corners", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:77, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1238", - "comment": "" - }, - { - "term": "Hotkey overlay title (optional)", - "context": "Hotkey overlay title (optional)", - "reference": "Widgets/KeybindItem.qml:1538", - "comment": "" - }, - { - "term": "Hour", - "context": "Hour", - "reference": "Modules/Settings/ThemeColorsTab.qml:1142, Modules/Settings/GammaControlTab.qml:232", - "comment": "" - }, - { - "term": "Hourly", - "context": "Hourly", - "reference": "Modules/DankDash/WeatherTab.qml:860", - "comment": "" - }, - { - "term": "Hourly Forecast Count", - "context": "Hourly Forecast Count", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:142", - "comment": "" - }, - { - "term": "How often to change wallpaper", - "context": "How often to change wallpaper", - "reference": "Modules/Settings/WallpaperTab.qml:1010", - "comment": "" - }, - { - "term": "How the background image is scaled", - "context": "How the background image is scaled", - "reference": "Modules/Settings/GreeterTab.qml:693", - "comment": "" - }, - { - "term": "Humidity", - "context": "Humidity", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:413, Modules/DankDash/WeatherTab.qml:84, Modules/DankDash/WeatherForecastCard.qml:80, Modules/Settings/TimeWeatherTab.qml:933", - "comment": "" - }, - { - "term": "Hyprland Discord Server", - "context": "Hyprland Discord Server", - "reference": "Modules/Settings/AboutTab.qml:98", - "comment": "" - }, - { - "term": "Hyprland Layout Overrides", - "context": "Hyprland Layout Overrides", - "reference": "Modules/Settings/ThemeColorsTab.qml:2005", - "comment": "" - }, - { - "term": "Hyprland Options", - "context": "Hyprland Options", - "reference": "Modals/WindowRuleModal.qml:928", - "comment": "" - }, - { - "term": "Hyprland Website", - "context": "Hyprland Website", - "reference": "Modules/Settings/AboutTab.qml:71", - "comment": "" - }, - { - "term": "I Understand", - "context": "I Understand", - "reference": "Modules/Settings/PluginBrowser.qml:838", - "comment": "" - }, - { - "term": "IP", - "context": "IP", - "reference": "Modules/Settings/NetworkTab.qml:582", - "comment": "" - }, - { - "term": "IP Address:", - "context": "IP Address:", - "reference": "Modules/Settings/NetworkTab.qml:945", - "comment": "" - }, - { - "term": "IP address or hostname", - "context": "IP address or hostname", - "reference": "Modules/Settings/PrinterTab.qml:511", - "comment": "Placeholder text for manual printer address input" - }, - { - "term": "ISO Date", - "context": "ISO Date", - "reference": "Modules/Settings/GreeterTab.qml:422, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:162, Modules/Settings/TimeWeatherTab.qml:181, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:249, Modules/Settings/TimeWeatherTab.qml:268", - "comment": "date format option" - }, - { - "term": "Icon", - "context": "Icon", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:903, Modules/Settings/DockTab.qml:247", - "comment": "" - }, - { - "term": "Icon Scale", - "context": "Icon Scale", - "reference": "Modules/Settings/DankBarTab.qml:976", - "comment": "" - }, - { - "term": "Icon Size", - "context": "Icon Size", - "reference": "Modules/Settings/DockTab.qml:518, Modules/Settings/WorkspacesTab.qml:109", - "comment": "" - }, - { - "term": "Icon Size %", - "context": "Icon Size %", - "reference": "Modules/Settings/WidgetsTabSection.qml:2891", - "comment": "" - }, - { - "term": "Icon Theme", - "context": "Icon Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:2446, Modules/Settings/ThemeColorsTab.qml:2454", - "comment": "" - }, - { - "term": "Idle", - "context": "Idle", - "reference": "Services/CupsService.qml:778", - "comment": "" - }, - { - "term": "Idle Inhibitor", - "context": "Idle Inhibitor", - "reference": "Modules/Settings/WidgetsTab.qml:190, Modules/Settings/OSDTab.qml:125", - "comment": "" - }, - { - "term": "Idle Settings", - "context": "Idle Settings", - "reference": "Modules/Settings/PowerSleepTab.qml:34", - "comment": "" - }, - { - "term": "Idle monitoring not supported - requires newer Quickshell version", - "context": "Idle monitoring not supported - requires newer Quickshell version", - "reference": "Modules/Settings/PowerSleepTab.qml:342", - "comment": "" - }, - { - "term": "If the field is hidden, it will appear as soon as a key is pressed.", - "context": "If the field is hidden, it will appear as soon as a key is pressed.", - "reference": "Modules/Settings/LockScreenTab.qml:130", - "comment": "" - }, - { - "term": "Ignore Completely", - "context": "Ignore Completely", - "reference": "Modules/Settings/NotificationsTab.qml:127", - "comment": "notification rule action option" - }, - { - "term": "Image", - "context": "Image", - "reference": "Modals/Clipboard/ClipboardEntry.qml:116", - "comment": "" - }, - { - "term": "Image copied to clipboard", - "context": "Image copied to clipboard", - "reference": "Services/ClipboardService.qml:108", - "comment": "" - }, - { - "term": "Import", - "context": "Import", - "reference": "Widgets/VpnDetailContent.qml:87, Modules/Settings/NetworkTab.qml:1592", - "comment": "" - }, - { - "term": "Import VPN", - "context": "Import VPN", - "reference": "Widgets/VpnDetailContent.qml:26, Modules/Settings/NetworkTab.qml:76", - "comment": "" - }, - { - "term": "Inactive Monitor Color", - "context": "Inactive Monitor Color", - "reference": "Modules/Settings/LockScreenTab.qml:415, Modules/Settings/LockScreenTab.qml:446", - "comment": "" - }, - { - "term": "Include Files in All Tab", - "context": "Include Files in All Tab", - "reference": "Modules/Settings/LauncherTab.qml:891", - "comment": "" - }, - { - "term": "Include Folders in All Tab", - "context": "Include Folders in All Tab", - "reference": "Modules/Settings/LauncherTab.qml:900", - "comment": "" - }, - { - "term": "Include Transitions", - "context": "Include Transitions", - "reference": "Modules/Settings/WallpaperTab.qml:1201", - "comment": "" - }, - { - "term": "Include desktop actions (shortcuts) in search results.", - "context": "Include desktop actions (shortcuts) in search results.", - "reference": "Modules/Settings/LauncherTab.qml:874", - "comment": "" - }, - { - "term": "Incompatible Plugins Loaded", - "context": "Incompatible Plugins Loaded", - "reference": "Modules/Settings/PluginsTab.qml:168", - "comment": "" - }, - { - "term": "Incorrect password", - "context": "Incorrect password", - "reference": "Modals/WifiPasswordModal.qml:369, Modules/Greetd/GreeterContent.qml:245", - "comment": "" - }, - { - "term": "Incorrect password - attempt %1 of %2 (lockout may follow)", - "context": "Incorrect password - attempt %1 of %2 (lockout may follow)", - "reference": "Modules/Greetd/GreeterContent.qml:241", - "comment": "" - }, - { - "term": "Incorrect password - next failures may trigger account lockout", - "context": "Incorrect password - next failures may trigger account lockout", - "reference": "Modules/Greetd/GreeterContent.qml:243", - "comment": "" - }, - { - "term": "Incorrect password - try again", - "context": "Incorrect password - try again", - "reference": "Modules/Lock/LockScreenContent.qml:60", - "comment": "" - }, - { - "term": "Indicator Style", - "context": "Indicator Style", - "reference": "Modules/Settings/DockTab.qml:176", - "comment": "" - }, - { - "term": "Individual Batteries", - "context": "Individual Batteries", - "reference": "Modules/DankBar/Popouts/BatteryPopout.qml:358", - "comment": "" - }, - { - "term": "Individual bar configuration", - "context": "Individual bar configuration", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:19", - "comment": "" - }, - { - "term": "Info", - "context": "Info", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:270", - "comment": "greeter doctor page status card" - }, - { - "term": "Inherit", - "context": "Inherit", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:87, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:92, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:97, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:101, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:225, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:262, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:312", - "comment": "" - }, - { - "term": "Inherit Global (Default)", - "context": "Inherit Global (Default)", - "reference": "Modules/Settings/DankBarTab.qml:1120, Modules/Settings/DankBarTab.qml:1128", - "comment": "bar shadow direction source option" - }, - { - "term": "Inhibitable", - "context": "Inhibitable", - "reference": "Widgets/KeybindItem.qml:1773", - "comment": "" - }, - { - "term": "Input Devices", - "context": "Input Devices", - "reference": "Modules/Settings/AudioTab.qml:319, Modules/ControlCenter/Details/AudioInputDetail.qml:37", - "comment": "" - }, - { - "term": "Input Volume Slider", - "context": "Input Volume Slider", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:153", - "comment": "" - }, - { - "term": "Insert your security key...", - "context": "Insert your security key...", - "reference": "Modules/Lock/LockScreenContent.qml:50", - "comment": "" - }, - { - "term": "Install", - "context": "Install", - "reference": "Modules/Settings/PluginBrowser.qml:121, Modules/Settings/PluginBrowser.qml:634, Modules/Settings/GreeterTab.qml:120, Modules/Settings/GreeterTab.qml:166, Modules/Settings/ThemeBrowser.qml:120, Modules/Settings/ThemeBrowser.qml:648", - "comment": "install action button" - }, - { - "term": "Install Greeter", - "context": "Install Greeter", - "reference": "Modules/Settings/GreeterTab.qml:164", - "comment": "greeter action confirmation" - }, - { - "term": "Install Plugin", - "context": "Install Plugin", - "reference": "Modules/Settings/PluginBrowser.qml:119", - "comment": "plugin installation dialog title" - }, - { - "term": "Install Theme", - "context": "Install Theme", - "reference": "Modules/Settings/ThemeBrowser.qml:118", - "comment": "theme installation dialog title" - }, - { - "term": "Install color themes from the DMS theme registry", - "context": "Install color themes from the DMS theme registry", - "reference": "Modules/Settings/ThemeBrowser.qml:290", - "comment": "theme browser description" - }, - { - "term": "Install complete. Greeter has been installed.", - "context": "Install complete. Greeter has been installed.", - "reference": "Modules/Settings/GreeterTab.qml:379", - "comment": "" - }, - { - "term": "Install failed: %1", - "context": "Install failed: %1", - "reference": "Modules/Settings/PluginBrowser.qml:85, Modules/Settings/ThemeBrowser.qml:68", - "comment": "installation error" - }, - { - "term": "Install matugen package for dynamic theming", - "context": "Install matugen package for dynamic theming", - "reference": "Modules/Settings/ThemeColorsTab.qml:485", - "comment": "matugen installation hint" - }, - { - "term": "Install plugin '%1' from the DMS registry?", - "context": "Install plugin '%1' from the DMS registry?", - "reference": "Modules/Settings/PluginBrowser.qml:120", - "comment": "plugin installation confirmation" - }, - { - "term": "Install plugins from the DMS plugin registry", - "context": "Install plugins from the DMS plugin registry", - "reference": "Modules/Settings/PluginBrowser.qml:321", - "comment": "plugin browser description" - }, - { - "term": "Install the DMS greeter? A terminal will open for sudo authentication.", - "context": "Install the DMS greeter? A terminal will open for sudo authentication.", - "reference": "Modules/Settings/GreeterTab.qml:165", - "comment": "" - }, - { - "term": "Install theme '%1' from the DMS registry?", - "context": "Install theme '%1' from the DMS registry?", - "reference": "Modules/Settings/ThemeBrowser.qml:119", - "comment": "theme installation confirmation" - }, - { - "term": "Installation and PAM setup: see the ", - "context": "Installation and PAM setup: see the ", - "reference": "Modules/Settings/GreeterTab.qml:765", - "comment": "" - }, - { - "term": "Installed", - "context": "Installed", - "reference": "Modules/Settings/PluginBrowser.qml:630, Modules/Settings/ThemeBrowser.qml:651", - "comment": "installed status" - }, - { - "term": "Installed: %1", - "context": "Installed: %1", - "reference": "Modules/Settings/PluginBrowser.qml:88, Modules/Settings/ThemeBrowser.qml:71", - "comment": "installation success" - }, - { - "term": "Installing: %1", - "context": "Installing: %1", - "reference": "Modules/Settings/PluginBrowser.qml:82, Modules/Settings/ThemeBrowser.qml:65", - "comment": "installation progress" - }, - { - "term": "Intelligent Auto-hide", - "context": "Intelligent Auto-hide", - "reference": "Modules/Settings/DockTab.qml:66", - "comment": "" - }, - { - "term": "Intensity", - "context": "Intensity", - "reference": "Modules/Settings/DankBarTab.qml:1091", - "comment": "shadow intensity slider" - }, - { - "term": "Interface:", - "context": "Interface:", - "reference": "Modules/Settings/NetworkTab.qml:925", - "comment": "" - }, - { - "term": "Interlock Open", - "context": "Interlock Open", - "reference": "Services/CupsService.qml:807", - "comment": "" - }, - { - "term": "Internet", - "context": "Internet", - "reference": "Services/AppSearchService.qml:646, Services/AppSearchService.qml:647, Services/AppSearchService.qml:648", - "comment": "" - }, - { - "term": "Interval", - "context": "Interval", - "reference": "Modules/Settings/WallpaperTab.qml:956, Modules/Settings/WallpaperTab.qml:1009", - "comment": "wallpaper cycling mode tab" - }, - { - "term": "Invalid configuration", - "context": "Invalid configuration", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1302", - "comment": "" - }, - { - "term": "Invert on mode change", - "context": "Invert on mode change", - "reference": "Modules/Settings/LauncherTab.qml:300", - "comment": "" - }, - { - "term": "Iris Bloom", - "context": "Iris Bloom", - "reference": "Modules/Settings/WallpaperTab.qml:1171", - "comment": "wallpaper transition option" - }, - { - "term": "Isolate Displays", - "context": "Isolate Displays", - "reference": "Modules/Settings/DockTab.qml:148", - "comment": "" - }, - { - "term": "Jobs", - "context": "Jobs", - "reference": "Modules/Settings/PrinterTab.qml:1339, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:181", - "comment": "" - }, - { - "term": "Jobs: ", - "context": "Jobs: ", - "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:19", - "comment": "" - }, - { - "term": "Keep Awake", - "context": "Keep Awake", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:93, Modules/ControlCenter/Components/DragDropGrid.qml:624", - "comment": "" - }, - { - "term": "Keep Changes", - "context": "Keep Changes", - "reference": "Modals/DisplayConfirmationModal.qml:168", - "comment": "" - }, - { - "term": "Keeping Awake", - "context": "Keeping Awake", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:624", - "comment": "" - }, - { - "term": "Kernel", - "context": "Kernel", - "reference": "Modules/ProcessList/SystemView.qml:68", - "comment": "system info label" - }, - { - "term": "Key", - "context": "Key", - "reference": "Widgets/KeybindItem.qml:621", - "comment": "" - }, - { - "term": "Keybind Sources", - "context": "Keybind Sources", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:144", - "comment": "" - }, - { - "term": "Keybinds", - "context": "Keybinds", - "reference": "Modals/Greeter/GreeterCompletePage.qml:413", - "comment": "greeter settings link" - }, - { - "term": "Keybinds Search Settings", - "context": "Keybinds Search Settings", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:70", - "comment": "" - }, - { - "term": "Keybinds shown alongside regular search results", - "context": "Keybinds shown alongside regular search results", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:107", - "comment": "" - }, - { - "term": "Keyboard Layout Name", - "context": "Keyboard Layout Name", - "reference": "Modules/Settings/WidgetsTab.qml:226", - "comment": "" - }, - { - "term": "Keyboard Shortcuts", - "context": "Keyboard Shortcuts", - "reference": "Modals/Settings/SettingsSidebar.qml:199, Modals/Settings/SettingsSidebar.qml:563, Modals/Clipboard/ClipboardHeader.qml:68, Modules/Settings/KeybindsTab.qml:232", - "comment": "" - }, - { - "term": "Keys", - "context": "Keys", - "reference": "Widgets/KeybindItem.qml:534", - "comment": "" - }, - { - "term": "Kill", - "context": "Kill", - "reference": "Modals/MuxModal.qml:102, Modals/MuxModal.qml:593", - "comment": "" - }, - { - "term": "Kill Process", - "context": "Kill Process", - "reference": "Modules/ProcessList/ProcessContextMenu.qml:42", - "comment": "" - }, - { - "term": "Kill Session", - "context": "Kill Session", - "reference": "Modals/MuxModal.qml:100", - "comment": "" - }, - { - "term": "Ko-fi", - "context": "Ko-fi", - "reference": "Modules/Settings/AboutTab.qml:322, Modules/Settings/AboutTab.qml:330", - "comment": "" - }, - { - "term": "LED device", - "context": "LED device", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:335", - "comment": "" - }, - { - "term": "LabWC IRC Channel", - "context": "LabWC IRC Channel", - "reference": "Modules/Settings/AboutTab.qml:108", - "comment": "" - }, - { - "term": "LabWC Website", - "context": "LabWC Website", - "reference": "Modules/Settings/AboutTab.qml:81", - "comment": "" - }, - { - "term": "Large", - "context": "Large", - "reference": "Modules/Settings/WidgetsTabSection.qml:2063", - "comment": "" - }, - { - "term": "Largest", - "context": "Largest", - "reference": "Modules/Settings/WidgetsTabSection.qml:2068", - "comment": "" - }, - { - "term": "Last hour", - "context": "Last hour", - "reference": "Modules/Notifications/Center/HistoryNotificationList.qml:92", - "comment": "notification history filter" - }, - { - "term": "Last launched %1", - "context": "Last launched %1", - "reference": "Modules/Settings/LauncherTab.qml:1268", - "comment": "" - }, - { - "term": "Last launched %1 day ago", - "context": "Last launched %1 day ago", - "reference": "Modules/Settings/LauncherTab.qml:1267", - "comment": "" - }, - { - "term": "Last launched %1 days ago", - "context": "Last launched %1 days ago", - "reference": "Modules/Settings/LauncherTab.qml:1267", - "comment": "" - }, - { - "term": "Last launched %1 hour ago", - "context": "Last launched %1 hour ago", - "reference": "Modules/Settings/LauncherTab.qml:1265", - "comment": "" - }, - { - "term": "Last launched %1 hours ago", - "context": "Last launched %1 hours ago", - "reference": "Modules/Settings/LauncherTab.qml:1265", - "comment": "" - }, - { - "term": "Last launched %1 minute ago", - "context": "Last launched %1 minute ago", - "reference": "Modules/Settings/LauncherTab.qml:1263", - "comment": "" - }, - { - "term": "Last launched %1 minutes ago", - "context": "Last launched %1 minutes ago", - "reference": "Modules/Settings/LauncherTab.qml:1263", - "comment": "" - }, - { - "term": "Last launched just now", - "context": "Last launched just now", - "reference": "Modules/Settings/LauncherTab.qml:1261", - "comment": "" - }, - { - "term": "Latitude", - "context": "Latitude", - "reference": "Modules/Settings/ThemeColorsTab.qml:1287, Modules/Settings/GammaControlTab.qml:379, Modules/Settings/TimeWeatherTab.qml:502", - "comment": "" - }, - { - "term": "Launch", - "context": "Launch", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:154, Modals/DankLauncherV2/Controller.qml:1102, Modals/DankLauncherV2/Controller.qml:1505", - "comment": "" - }, - { - "term": "Launch Prefix", - "context": "Launch Prefix", - "reference": "Modules/Settings/LauncherTab.qml:311", - "comment": "" - }, - { - "term": "Launch on dGPU", - "context": "Launch on dGPU", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:146, Modals/DankLauncherV2/ActionPanel.qml:61, Modules/Dock/DockContextMenu.qml:491, Modules/DankBar/Widgets/AppsDockContextMenu.qml:401", - "comment": "" - }, - { - "term": "Launch on dGPU by default", - "context": "Launch on dGPU by default", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:987", - "comment": "" - }, - { - "term": "Launcher", - "context": "Launcher", - "reference": "Modals/Settings/SettingsSidebar.qml:191", - "comment": "" - }, - { - "term": "Launcher Button", - "context": "Launcher Button", - "reference": "Modules/Settings/DockTab.qml:226", - "comment": "" - }, - { - "term": "Launcher Button Logo", - "context": "Launcher Button Logo", - "reference": "Modules/Settings/LauncherTab.qml:36", - "comment": "" - }, - { - "term": "Layout", - "context": "Layout", - "reference": "Modules/Settings/WidgetsTab.qml:37, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1240, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:350, Modules/DankBar/Popouts/DWLLayoutPopout.qml:167", - "comment": "" - }, - { - "term": "Layout Overrides", - "context": "Layout Overrides", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:193", - "comment": "" - }, - { - "term": "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.", - "context": "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.", - "reference": "Modules/Settings/GreeterTab.qml:708", - "comment": "" - }, - { - "term": "Left", - "context": "Left", - "reference": "Modules/Settings/DockTab.qml:102, Modules/Settings/DankBarTab.qml:288, Modules/Settings/DankBarTab.qml:542, Modules/DankBar/Popouts/BatteryPopout.qml:520", - "comment": "" - }, - { - "term": "Left Center", - "context": "Left Center", - "reference": "Modules/Settings/OSDTab.qml:47, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:68", - "comment": "screen position option" - }, - { - "term": "Left Section", - "context": "Left Section", - "reference": "Modules/Settings/WidgetsTab.qml:953", - "comment": "" - }, - { - "term": "Light Direction", - "context": "Light Direction", - "reference": "Modules/Settings/ThemeColorsTab.qml:1726", - "comment": "" - }, - { - "term": "Light Mode", - "context": "Light Mode", - "reference": "Modules/Settings/ThemeColorsTab.qml:1415, Modules/Settings/ThemeColorsTab.qml:1485, Modules/Settings/WallpaperTab.qml:392", - "comment": "" - }, - { - "term": "Light Rain", - "context": "Light Rain", - "reference": "Services/WeatherService.qml:133, Services/WeatherService.qml:136, Services/WeatherService.qml:142", - "comment": "" - }, - { - "term": "Light Snow", - "context": "Light Snow", - "reference": "Services/WeatherService.qml:138", - "comment": "" - }, - { - "term": "Light Snow Showers", - "context": "Light Snow Showers", - "reference": "Services/WeatherService.qml:145", - "comment": "" - }, - { - "term": "Light mode base", - "context": "Light mode base", - "reference": "Modules/Settings/ThemeColorsTab.qml:2703", - "comment": "" - }, - { - "term": "Light mode harmony", - "context": "Light mode harmony", - "reference": "Modules/Settings/ThemeColorsTab.qml:2737", - "comment": "" - }, - { - "term": "Line", - "context": "Line", - "reference": "Modules/Settings/DockTab.qml:177", - "comment": "dock indicator style option" - }, - { - "term": "Line: %1", - "context": "Line: %1", - "reference": "Modules/Notepad/NotepadTextEditor.qml:859", - "comment": "" - }, - { - "term": "Linear", - "context": "Linear", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:445", - "comment": "" - }, - { - "term": "Lines: %1", - "context": "Lines: %1", - "reference": "Modules/Notepad/NotepadTextEditor.qml:860", - "comment": "" - }, - { - "term": "List", - "context": "List", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:351, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:357, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:367", - "comment": "" - }, - { - "term": "Lively palette with saturated accents.", - "context": "Lively palette with saturated accents.", - "reference": "Common/Theme.qml:472", - "comment": "" - }, - { - "term": "Load Average", - "context": "Load Average", - "reference": "Modules/ProcessList/SystemView.qml:84", - "comment": "system info label" - }, - { - "term": "Loading codecs...", - "context": "Loading codecs...", - "reference": "Modules/ControlCenter/Details/BluetoothCodecSelector.qml:224", - "comment": "" - }, - { - "term": "Loading keybinds...", - "context": "Loading keybinds...", - "reference": "Modules/Settings/KeybindsTab.qml:582", - "comment": "" - }, - { - "term": "Loading trending...", - "context": "Loading trending...", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:153, dms-plugins/DankGifSearch/DankGifSearch.qml:96", - "comment": "" - }, - { - "term": "Loading...", - "context": "Loading...", - "reference": "Widgets/VpnProfileDelegate.qml:220, Modules/Settings/PluginBrowser.qml:389, Modules/Settings/PrinterTab.qml:707, Modules/Settings/ThemeBrowser.qml:357, Modules/Settings/NetworkTab.qml:681, Modules/Settings/NetworkTab.qml:1398, Modules/Settings/NetworkTab.qml:1884, Modules/DankDash/Overview/WeatherOverviewCard.qml:31", - "comment": "loading indicator" - }, - { - "term": "Local", - "context": "Local", - "reference": "Services/CupsService.qml:131", - "comment": "" - }, - { - "term": "Locale", - "context": "Locale", - "reference": "Modals/Settings/SettingsSidebar.qml:251", - "comment": "" - }, - { - "term": "Locale Settings", - "context": "Locale Settings", - "reference": "Modules/Settings/LocaleTab.qml:48", - "comment": "" - }, - { - "term": "Location", - "context": "Location", - "reference": "Modules/Settings/ThemeColorsTab.qml:1098, Modules/Settings/GammaControlTab.qml:188, Modules/Settings/PrinterTab.qml:775, Modules/Settings/PrinterTab.qml:1164", - "comment": "theme auto mode tab" - }, - { - "term": "Location Search", - "context": "Location Search", - "reference": "Modules/Settings/TimeWeatherTab.qml:602", - "comment": "" - }, - { - "term": "Lock", - "context": "Lock", - "reference": "Modals/PowerMenuModal.qml:198, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Lock Screen", - "context": "Lock Screen", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:158, Modals/Settings/SettingsSidebar.qml:292, Modules/Settings/NotificationsTab.qml:721", - "comment": "greeter feature card title | lock screen notifications settings card" - }, - { - "term": "Lock Screen Display", - "context": "Lock Screen Display", - "reference": "Modules/Settings/LockScreenTab.qml:348", - "comment": "" - }, - { - "term": "Lock Screen Format", - "context": "Lock Screen Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:216", - "comment": "" - }, - { - "term": "Lock Screen behaviour", - "context": "Lock Screen behaviour", - "reference": "Modules/Settings/LockScreenTab.qml:162", - "comment": "" - }, - { - "term": "Lock Screen layout", - "context": "Lock Screen layout", - "reference": "Modules/Settings/LockScreenTab.qml:83", - "comment": "" - }, - { - "term": "Lock at startup", - "context": "Lock at startup", - "reference": "Modules/Settings/LockScreenTab.qml:210", - "comment": "" - }, - { - "term": "Lock before suspend", - "context": "Lock before suspend", - "reference": "Modules/Settings/PowerSleepTab.qml:92, Modules/Settings/LockScreenTab.qml:191", - "comment": "" - }, - { - "term": "Lock fade grace period", - "context": "Lock fade grace period", - "reference": "Modules/Settings/PowerSleepTab.qml:106", - "comment": "" - }, - { - "term": "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "context": "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "reference": "Modules/Settings/LockScreenTab.qml:217", - "comment": "" - }, - { - "term": "Locked", - "context": "Locked", - "reference": "Widgets/KeybindItem.qml:1601", - "comment": "" - }, - { - "term": "Log Out", - "context": "Log Out", - "reference": "Modals/PowerMenuModal.qml:186, Modules/Lock/LockPowerMenu.qml:110, Modules/Settings/PowerSleepTab.qml:378, Modules/Settings/PowerSleepTab.qml:384", - "comment": "" - }, - { - "term": "Logging in...", - "context": "Logging in...", - "reference": "Modules/Greetd/GreeterContent.qml:1015", - "comment": "" - }, - { - "term": "Login", - "context": "Login", - "reference": "Modules/Settings/SoundsTab.qml:98", - "comment": "" - }, - { - "term": "Login Authentication", - "context": "Login Authentication", - "reference": "Modules/Settings/GreeterTab.qml:524", - "comment": "" - }, - { - "term": "Long", - "context": "Long", - "reference": "Modules/Settings/TypographyMotionTab.qml:212, Modules/Settings/TypographyMotionTab.qml:315, Modules/Settings/TypographyMotionTab.qml:399, Modules/Settings/NotificationsTab.qml:337", - "comment": "" - }, - { - "term": "Long Text", - "context": "Long Text", - "reference": "Modals/Clipboard/ClipboardEntry.qml:118", - "comment": "" - }, - { - "term": "Long press", - "context": "Long press", - "reference": "Widgets/KeybindItem.qml:1645", - "comment": "" - }, - { - "term": "Longitude", - "context": "Longitude", - "reference": "Modules/Settings/ThemeColorsTab.qml:1310, Modules/Settings/GammaControlTab.qml:402, Modules/Settings/TimeWeatherTab.qml:551", - "comment": "" - }, - { - "term": "Low Priority", - "context": "Low Priority", - "reference": "Modules/Settings/NotificationsTab.qml:146, Modules/Settings/NotificationsTab.qml:751, Modules/Settings/NotificationsTab.qml:874, Modules/Notifications/Center/NotificationSettings.qml:181, Modules/Notifications/Center/NotificationSettings.qml:364", - "comment": "notification rule urgency option" - }, - { - "term": "MAC", - "context": "MAC", - "reference": "Modules/Settings/NetworkTab.qml:592", - "comment": "" - }, - { - "term": "MTU", - "context": "MTU", - "reference": "Widgets/VpnProfileDelegate.qml:69, Modules/Settings/NetworkTab.qml:1930", - "comment": "" - }, - { - "term": "Make sure KDE Connect or Valent is running on your other devices", - "context": "Make sure KDE Connect or Valent is running on your other devices", - "reference": "dms-plugins/DankKDEConnect/components/EmptyState.qml:18", - "comment": "Phone Connect hint message" - }, - { - "term": "Manage and configure plugins for extending DMS functionality", - "context": "Manage and configure plugins for extending DMS functionality", - "reference": "Modules/Settings/PluginsTab.qml:80", - "comment": "" - }, - { - "term": "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.", - "context": "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.", - "reference": "Modules/Settings/DankBarTab.qml:220", - "comment": "" - }, - { - "term": "Management", - "context": "Management", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:87", - "comment": "" - }, - { - "term": "MangoWC Layout Overrides", - "context": "MangoWC Layout Overrides", - "reference": "Modules/Settings/ThemeColorsTab.qml:2108", - "comment": "" - }, - { - "term": "Manual", - "context": "Manual", - "reference": "Modules/Settings/DankBarTab.qml:1120, Modules/Settings/DankBarTab.qml:1126, Modules/Settings/DankBarTab.qml:1136", - "comment": "bar shadow direction source option" - }, - { - "term": "Manual Coordinates", - "context": "Manual Coordinates", - "reference": "Modules/Settings/ThemeColorsTab.qml:1272, Modules/Settings/GammaControlTab.qml:367", - "comment": "" - }, - { - "term": "Manual Direction", - "context": "Manual Direction", - "reference": "Modules/Settings/DankBarTab.qml:1150", - "comment": "bar manual shadow direction" - }, - { - "term": "Manual Gap Size", - "context": "Manual Gap Size", - "reference": "Modules/Settings/DankBarTab.qml:927", - "comment": "" - }, - { - "term": "Manual Show/Hide", - "context": "Manual Show/Hide", - "reference": "Modules/Settings/DankBarTab.qml:661", - "comment": "" - }, - { - "term": "Map window class names to icon names for proper icon display", - "context": "Map window class names to icon names for proper icon display", - "reference": "Modules/Settings/RunningAppsTab.qml:54", - "comment": "" - }, - { - "term": "Margin", - "context": "Margin", - "reference": "Modules/Settings/DockTab.qml:555", - "comment": "" - }, - { - "term": "Marker Supply Empty", - "context": "Marker Supply Empty", - "reference": "Services/CupsService.qml:792", - "comment": "" - }, - { - "term": "Marker Supply Low", - "context": "Marker Supply Low", - "reference": "Services/CupsService.qml:791", - "comment": "" - }, - { - "term": "Marker Waste Almost Full", - "context": "Marker Waste Almost Full", - "reference": "Services/CupsService.qml:793", - "comment": "" - }, - { - "term": "Marker Waste Full", - "context": "Marker Waste Full", - "reference": "Services/CupsService.qml:794", - "comment": "" - }, - { - "term": "Match Criteria", - "context": "Match Criteria", - "reference": "Modals/WindowRuleModal.qml:464", - "comment": "" - }, - { - "term": "Matches profile: %1", - "context": "Matches profile: %1", - "reference": "Modules/Settings/DisplayConfigTab.qml:323", - "comment": "" - }, - { - "term": "Material Colors", - "context": "Material Colors", - "reference": "Modals/DankColorPickerModal.qml:417", - "comment": "" - }, - { - "term": "Material Design inspired color themes", - "context": "Material Design inspired color themes", - "reference": "Modules/Settings/ThemeColorsTab.qml:249", - "comment": "generic theme description" - }, - { - "term": "Material colors generated from wallpaper", - "context": "Material colors generated from wallpaper", - "reference": "Modules/Settings/ThemeColorsTab.qml:244", - "comment": "dynamic theme description" - }, - { - "term": "Material inspired shadows and elevation on modals, popouts, and dialogs", - "context": "Material inspired shadows and elevation on modals, popouts, and dialogs", - "reference": "Modules/Settings/ThemeColorsTab.qml:1649", - "comment": "" - }, - { - "term": "Matugen Contrast", - "context": "Matugen Contrast", - "reference": "Modules/Settings/ThemeColorsTab.qml:537", - "comment": "" - }, - { - "term": "Matugen Missing", - "context": "Matugen Missing", - "reference": "Modules/Settings/ThemeColorsTab.qml:468", - "comment": "matugen not found status" - }, - { - "term": "Matugen Palette", - "context": "Matugen Palette", - "reference": "Modules/Settings/ThemeColorsTab.qml:504", - "comment": "" - }, - { - "term": "Matugen Target Monitor", - "context": "Matugen Target Monitor", - "reference": "Modules/Settings/WallpaperTab.qml:854", - "comment": "" - }, - { - "term": "Matugen Templates", - "context": "Matugen Templates", - "reference": "Modules/Settings/ThemeColorsTab.qml:2473", - "comment": "" - }, - { - "term": "Max Edges", - "context": "Max Edges", - "reference": "Modules/Settings/WindowRulesTab.qml:537", - "comment": "" - }, - { - "term": "Max H", - "context": "Max H", - "reference": "Modals/WindowRuleModal.qml:904, Modules/Settings/WindowRulesTab.qml:554", - "comment": "" - }, - { - "term": "Max Pinned Apps", - "context": "Max Pinned Apps", - "reference": "Modules/Settings/WidgetsTabSection.qml:2450", - "comment": "" - }, - { - "term": "Max Pinned Apps (0 = Unlimited)", - "context": "Max Pinned Apps (0 = Unlimited)", - "reference": "Modules/Settings/DockTab.qml:192", - "comment": "" - }, - { - "term": "Max Running Apps", - "context": "Max Running Apps", - "reference": "Modules/Settings/WidgetsTabSection.qml:2504", - "comment": "" - }, - { - "term": "Max Running Apps (0 = Unlimited)", - "context": "Max Running Apps (0 = Unlimited)", - "reference": "Modules/Settings/DockTab.qml:204", - "comment": "" - }, - { - "term": "Max Volume", - "context": "Max Volume", - "reference": "Modules/Settings/AudioTab.qml:187", - "comment": "Audio settings: maximum volume limit per device" - }, - { - "term": "Max W", - "context": "Max W", - "reference": "Modals/WindowRuleModal.qml:850, Modules/Settings/WindowRulesTab.qml:552", - "comment": "" - }, - { - "term": "Max apps to show", - "context": "Max apps to show", - "reference": "Modules/Settings/WorkspacesTab.qml:79", - "comment": "" - }, - { - "term": "Max to Edges", - "context": "Max to Edges", - "reference": "Modals/WindowRuleModal.qml:539", - "comment": "" - }, - { - "term": "Maximize", - "context": "Maximize", - "reference": "Modals/WindowRuleModal.qml:531, Modules/Settings/WindowRulesTab.qml:536", - "comment": "" - }, - { - "term": "Maximize Detection", - "context": "Maximize Detection", - "reference": "Modules/Settings/DankBarTab.qml:708", - "comment": "" - }, - { - "term": "Maximize Widget Icons", - "context": "Maximize Widget Icons", - "reference": "Modules/Settings/DankBarTab.qml:1305", - "comment": "" - }, - { - "term": "Maximize Widget Text", - "context": "Maximize Widget Text", - "reference": "Modules/Settings/DankBarTab.qml:1313", - "comment": "" - }, - { - "term": "Maximum Entry Size", - "context": "Maximum Entry Size", - "reference": "Modules/Settings/ClipboardTab.qml:317", - "comment": "" - }, - { - "term": "Maximum History", - "context": "Maximum History", - "reference": "Modules/Settings/NotificationsTab.qml:818, Modules/Settings/ClipboardTab.qml:287", - "comment": "" - }, - { - "term": "Maximum Pinned Entries", - "context": "Maximum Pinned Entries", - "reference": "Modules/Settings/ClipboardTab.qml:377", - "comment": "" - }, - { - "term": "Maximum fingerprint attempts reached. Please use password.", - "context": "Maximum fingerprint attempts reached. Please use password.", - "reference": "Modules/Lock/LockScreenContent.qml:66", - "comment": "" - }, - { - "term": "Maximum number of clipboard entries to keep", - "context": "Maximum number of clipboard entries to keep", - "reference": "Modules/Settings/ClipboardTab.qml:288", - "comment": "" - }, - { - "term": "Maximum number of entries that can be saved", - "context": "Maximum number of entries that can be saved", - "reference": "Modules/Settings/ClipboardTab.qml:378", - "comment": "" - }, - { - "term": "Maximum number of notifications to keep", - "context": "Maximum number of notifications to keep", - "reference": "Modules/Settings/NotificationsTab.qml:819", - "comment": "notification history limit" - }, - { - "term": "Maximum pinned entries reached", - "context": "Maximum pinned entries reached", - "reference": "Services/ClipboardService.qml:191", - "comment": "" - }, - { - "term": "Maximum size per clipboard entry", - "context": "Maximum size per clipboard entry", - "reference": "Modules/Settings/ClipboardTab.qml:318", - "comment": "" - }, - { - "term": "Media", - "context": "Media", - "reference": "Services/AppSearchService.qml:636, Services/AppSearchService.qml:637, Services/AppSearchService.qml:638, Widgets/DankIconPicker.qml:39, Widgets/KeybindItem.qml:1095, Widgets/KeybindItem.qml:1104, Widgets/KeybindItem.qml:1110, Modules/DankDash/DankDashPopout.qml:275", - "comment": "" - }, - { - "term": "Media Controls", - "context": "Media Controls", - "reference": "Modules/Settings/WidgetsTab.qml:94", - "comment": "" - }, - { - "term": "Media Empty", - "context": "Media Empty", - "reference": "Services/CupsService.qml:799", - "comment": "" - }, - { - "term": "Media Jam", - "context": "Media Jam", - "reference": "Services/CupsService.qml:801", - "comment": "" - }, - { - "term": "Media Low", - "context": "Media Low", - "reference": "Services/CupsService.qml:798", - "comment": "" - }, - { - "term": "Media Needed", - "context": "Media Needed", - "reference": "Services/CupsService.qml:800", - "comment": "" - }, - { - "term": "Media Playback", - "context": "Media Playback", - "reference": "Modules/Settings/OSDTab.qml:109", - "comment": "" - }, - { - "term": "Media Player", - "context": "Media Player", - "reference": "Modals/Settings/SettingsSidebar.qml:140", - "comment": "" - }, - { - "term": "Media Player Settings", - "context": "Media Player Settings", - "reference": "Modules/Settings/MediaPlayerTab.qml:25", - "comment": "" - }, - { - "term": "Media Players", - "context": "Media Players", - "reference": "Modules/DankDash/MediaPlayerTab.qml:662", - "comment": "" - }, - { - "term": "Media Players (", - "context": "Media Players (", - "reference": "Modules/DankDash/MediaDropdownOverlay.qml:403", - "comment": "" - }, - { - "term": "Media Volume", - "context": "Media Volume", - "reference": "Modules/Settings/OSDTab.qml:101", - "comment": "" - }, - { - "term": "Medium", - "context": "Medium", - "reference": "Modules/Settings/TypographyMotionTab.qml:212, Modules/Settings/TypographyMotionTab.qml:315, Modules/Settings/TypographyMotionTab.qml:399, Modules/Settings/WidgetsTabSection.qml:2058, Modules/Settings/NotificationsTab.qml:337", - "comment": "" - }, - { - "term": "Memory", - "context": "Memory", - "reference": "Modules/ProcessList/ProcessListPopout.qml:319, Modules/ProcessList/ProcessesView.qml:268, Modules/ProcessList/PerformanceView.qml:91, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:210", - "comment": "" - }, - { - "term": "Memory Graph", - "context": "Memory Graph", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:221", - "comment": "" - }, - { - "term": "Memory Usage", - "context": "Memory Usage", - "reference": "Modules/Settings/WidgetsTab.qml:116", - "comment": "" - }, - { - "term": "Memory usage indicator", - "context": "Memory usage indicator", - "reference": "Modules/Settings/WidgetsTab.qml:117", - "comment": "" - }, - { - "term": "Merge indexed file results into the All tab (requires dsearch).", - "context": "Merge indexed file results into the All tab (requires dsearch).", - "reference": "Modules/Settings/LauncherTab.qml:892", - "comment": "" - }, - { - "term": "Merge indexed folder results into the All tab (requires dsearch).", - "context": "Merge indexed folder results into the All tab (requires dsearch).", - "reference": "Modules/Settings/LauncherTab.qml:901", - "comment": "" - }, - { - "term": "Message", - "context": "Message", - "reference": "dms-plugins/DankKDEConnect/components/SmsDialog.qml:73", - "comment": "KDE Connect SMS message input placeholder" - }, - { - "term": "Message Content", - "context": "Message Content", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:670", - "comment": "notification privacy mode placeholder" - }, - { - "term": "Microphone", - "context": "Microphone", - "reference": "Modules/Settings/WidgetsTabSection.qml:1254, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/WidgetsTabSection.qml:1773", - "comment": "" - }, - { - "term": "Microphone Mute", - "context": "Microphone Mute", - "reference": "Modules/Settings/OSDTab.qml:133", - "comment": "" - }, - { - "term": "Microphone Volume", - "context": "Microphone Volume", - "reference": "Modules/Settings/WidgetsTabSection.qml:1259, Modules/Settings/WidgetsTabSection.qml:1448", - "comment": "" - }, - { - "term": "Microphone settings", - "context": "Microphone settings", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:128", - "comment": "" - }, - { - "term": "Microphone volume control", - "context": "Microphone volume control", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:154", - "comment": "" - }, - { - "term": "Middle Section", - "context": "Middle Section", - "reference": "Modules/Settings/WidgetsTab.qml:1020", - "comment": "" - }, - { - "term": "Min H", - "context": "Min H", - "reference": "Modals/WindowRuleModal.qml:877, Modules/Settings/WindowRulesTab.qml:553", - "comment": "" - }, - { - "term": "Min W", - "context": "Min W", - "reference": "Modals/WindowRuleModal.qml:823, Modules/Settings/WindowRulesTab.qml:551", - "comment": "" - }, - { - "term": "Minimal palette built around a single hue.", - "context": "Minimal palette built around a single hue.", - "reference": "Common/Theme.qml:492", - "comment": "" - }, - { - "term": "Minute", - "context": "Minute", - "reference": "Modules/Settings/ThemeColorsTab.qml:1150, Modules/Settings/GammaControlTab.qml:240", - "comment": "" - }, - { - "term": "Mirror Display", - "context": "Mirror Display", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:83", - "comment": "" - }, - { - "term": "Missing Environment Variables", - "context": "Missing Environment Variables", - "reference": "Modules/Settings/ThemeColorsTab.qml:2464", - "comment": "qt theme env error title" - }, - { - "term": "Modal Background", - "context": "Modal Background", - "reference": "Modules/Settings/ThemeColorsTab.qml:2211", - "comment": "" - }, - { - "term": "Modal Shadows", - "context": "Modal Shadows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1798", - "comment": "" - }, - { - "term": "Modals", - "context": "Modals", - "reference": "Modules/Settings/TypographyMotionTab.qml:384, Modules/Settings/TypographyMotionTab.qml:432", - "comment": "" - }, - { - "term": "Mode", - "context": "Mode", - "reference": "Modules/Settings/NetworkTab.qml:1438, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1220", - "comment": "" - }, - { - "term": "Mode:", - "context": "Mode:", - "reference": "Modules/Settings/WallpaperTab.qml:940", - "comment": "" - }, - { - "term": "Model", - "context": "Model", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:225, Modules/Settings/PrinterTab.qml:1159, Modules/Settings/DisplayConfigTab.qml:422, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1211", - "comment": "" - }, - { - "term": "Modified", - "context": "Modified", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:702, Modals/DankLauncherV2/LauncherContent.qml:709, Modals/DankLauncherV2/LauncherContent.qml:715, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1238, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1240", - "comment": "" - }, - { - "term": "Modular widget bar", - "context": "Modular widget bar", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:115", - "comment": "greeter feature card description" - }, - { - "term": "Monitor", - "context": "Monitor", - "reference": "Modals/WindowRuleModal.qml:1049, Modules/Settings/WindowRulesTab.qml:567", - "comment": "" - }, - { - "term": "Monitor Configuration", - "context": "Monitor Configuration", - "reference": "Modules/Settings/DisplayConfigTab.qml:364, Modules/Settings/DisplayConfig/NoBackendMessage.qml:41", - "comment": "" - }, - { - "term": "Monitor fade grace period", - "context": "Monitor fade grace period", - "reference": "Modules/Settings/PowerSleepTab.qml:132", - "comment": "" - }, - { - "term": "Monitor whose wallpaper drives dynamic theming colors", - "context": "Monitor whose wallpaper drives dynamic theming colors", - "reference": "Modules/Settings/WallpaperTab.qml:855", - "comment": "" - }, - { - "term": "Monochrome", - "context": "Monochrome", - "reference": "Common/Theme.qml:491", - "comment": "matugen color scheme option" - }, - { - "term": "Monocle", - "context": "Monocle", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:50", - "comment": "" - }, - { - "term": "Monospace Font", - "context": "Monospace Font", - "reference": "Modules/Settings/TypographyMotionTab.qml:88", - "comment": "" - }, - { - "term": "Month Date", - "context": "Month Date", - "reference": "Modules/Settings/GreeterTab.qml:406, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:146, Modules/Settings/TimeWeatherTab.qml:177, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:233, Modules/Settings/TimeWeatherTab.qml:264", - "comment": "date format option" - }, - { - "term": "Morning", - "context": "Morning", - "reference": "Services/WeatherService.qml:255", - "comment": "" - }, - { - "term": "Mount Points", - "context": "Mount Points", - "reference": "Modules/ProcessList/DisksView.qml:131", - "comment": "mount points header in system monitor" - }, - { - "term": "Mouse pointer appearance", - "context": "Mouse pointer appearance", - "reference": "Modules/Settings/ThemeColorsTab.qml:2332", - "comment": "" - }, - { - "term": "Mouse pointer size in pixels", - "context": "Mouse pointer size in pixels", - "reference": "Modules/Settings/ThemeColorsTab.qml:2348", - "comment": "" - }, - { - "term": "Move", - "context": "Move", - "reference": "Modals/WindowRuleModal.qml:1016, Modules/Settings/WindowRulesTab.qml:566", - "comment": "" - }, - { - "term": "Move Widget", - "context": "Move Widget", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:645", - "comment": "" - }, - { - "term": "Moving to Paused", - "context": "Moving to Paused", - "reference": "Services/CupsService.qml:830", - "comment": "" - }, - { - "term": "Multi-Monitor", - "context": "Multi-Monitor", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:130", - "comment": "greeter feature card title" - }, - { - "term": "Multiplexer", - "context": "Multiplexer", - "reference": "Modules/Settings/MuxTab.qml:31", - "comment": "" - }, - { - "term": "Multiplexer Type", - "context": "Multiplexer Type", - "reference": "Modules/Settings/MuxTab.qml:38", - "comment": "" - }, - { - "term": "Multiplexers", - "context": "Multiplexers", - "reference": "Modals/Settings/SettingsSidebar.qml:271", - "comment": "" - }, - { - "term": "Music", - "context": "Music", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:261", - "comment": "" - }, - { - "term": "Mute Popups", - "context": "Mute Popups", - "reference": "Modules/Settings/NotificationsTab.qml:123", - "comment": "notification rule action option" - }, - { - "term": "Mute popups for %1", - "context": "Mute popups for %1", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:1114, Modules/Notifications/Center/NotificationCard.qml:1016", - "comment": "" - }, - { - "term": "Muted", - "context": "Muted", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:375, Modules/ControlCenter/Components/DragDropGrid.qml:386", - "comment": "audio status" - }, - { - "term": "Muted Apps", - "context": "Muted Apps", - "reference": "Modules/Settings/NotificationsTab.qml:632", - "comment": "" - }, - { - "term": "Muted palette with subdued, calming tones.", - "context": "Muted palette with subdued, calming tones.", - "reference": "Common/Theme.qml:496", - "comment": "" - }, - { - "term": "NM not supported", - "context": "NM not supported", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:221", - "comment": "" - }, - { - "term": "Name", - "context": "Name", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:700, Modals/DankLauncherV2/LauncherContent.qml:709, Modals/DankLauncherV2/LauncherContent.qml:714, Modals/DankLauncherV2/LauncherContent.qml:883, Modules/ProcessList/ProcessesView.qml:249, Modules/Settings/DisplayWidgetsTab.qml:225, Modules/Settings/DesktopWidgetInstanceCard.qml:203, Modules/Settings/PrinterTab.qml:754, Modules/Settings/DisplayConfigTab.qml:422, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1211, Modules/Settings/Widgets/SystemMonitorVariantCard.qml:144", - "comment": "" - }, - { - "term": "Named Workspace Icons", - "context": "Named Workspace Icons", - "reference": "Modules/Settings/WorkspacesTab.qml:417", - "comment": "" - }, - { - "term": "Navigate", - "context": "Navigate", - "reference": "Modals/MuxModal.qml:590", - "comment": "" - }, - { - "term": "Navigation", - "context": "Navigation", - "reference": "Widgets/DankIconPicker.qml:47", - "comment": "" - }, - { - "term": "Network", - "context": "Network", - "reference": "Services/CupsService.qml:134, Modals/Settings/SettingsSidebar.qml:232, Modules/ProcessList/PerformanceView.qml:112, Modules/Settings/WidgetsTabSection.qml:1209, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:229, Modules/ControlCenter/Details/NetworkDetail.qml:88, Modules/ControlCenter/Models/WidgetModel.qml:101", - "comment": "" - }, - { - "term": "Network Graph", - "context": "Network Graph", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:240", - "comment": "" - }, - { - "term": "Network Info", - "context": "Network Info", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:450, Modules/ControlCenter/Details/NetworkDetail.qml:812", - "comment": "" - }, - { - "term": "Network Information", - "context": "Network Information", - "reference": "Modals/NetworkWiredInfoModal.qml:62, Modals/NetworkInfoModal.qml:62", - "comment": "" - }, - { - "term": "Network Name (SSID)", - "context": "Network Name (SSID)", - "reference": "Modals/WifiPasswordModal.qml:420", - "comment": "" - }, - { - "term": "Network Speed Monitor", - "context": "Network Speed Monitor", - "reference": "Modules/Settings/WidgetsTab.qml:218", - "comment": "" - }, - { - "term": "Network Status", - "context": "Network Status", - "reference": "Modules/Settings/NetworkTab.qml:139", - "comment": "" - }, - { - "term": "Network download and upload speed display", - "context": "Network download and upload speed display", - "reference": "Modules/Settings/WidgetsTab.qml:219", - "comment": "" - }, - { - "term": "Neutral", - "context": "Neutral", - "reference": "Common/Theme.qml:495", - "comment": "matugen color scheme option" - }, - { - "term": "Never", - "context": "Never", - "reference": "Modules/Settings/PowerSleepTab.qml:10, Modules/Settings/NotificationsTab.qml:33, Modules/Settings/NotificationsTab.qml:166, Modules/Settings/ClipboardTab.qml:99, Modules/Notifications/Center/NotificationSettings.qml:38, Modules/Notifications/Center/NotificationSettings.qml:98", - "comment": "" - }, - { - "term": "Never used", - "context": "Never used", - "reference": "Modules/Settings/LauncherTab.qml:1253", - "comment": "" - }, - { - "term": "New", - "context": "New", - "reference": "Modals/MuxModal.qml:592, Modules/Notepad/NotepadTextEditor.qml:806", - "comment": "" - }, - { - "term": "New Key", - "context": "New Key", - "reference": "Widgets/KeybindItem.qml:621", - "comment": "" - }, - { - "term": "New Keybind", - "context": "New Keybind", - "reference": "Modules/Settings/KeybindsTab.qml:489", - "comment": "" - }, - { - "term": "New Notification", - "context": "New Notification", - "reference": "Modules/Settings/SoundsTab.qml:108", - "comment": "" - }, - { - "term": "New Session", - "context": "New Session", - "reference": "Modals/MuxModal.qml:112, Modals/MuxModal.qml:381", - "comment": "" - }, - { - "term": "New Window Rule", - "context": "New Window Rule", - "reference": "Modals/WindowRuleModal.qml:405", - "comment": "" - }, - { - "term": "New York, NY", - "context": "New York, NY", - "reference": "Modules/Settings/TimeWeatherTab.qml:612", - "comment": "" - }, - { - "term": "New group name...", - "context": "New group name...", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:137", - "comment": "" - }, - { - "term": "Next", - "context": "Next", - "reference": "Modals/Greeter/GreeterModal.qml:295", - "comment": "greeter next button" - }, - { - "term": "Next Transition", - "context": "Next Transition", - "reference": "Modules/Settings/ThemeColorsTab.qml:1451, Modules/Settings/GammaControlTab.qml:643", - "comment": "" - }, - { - "term": "Night", - "context": "Night", - "reference": "Services/WeatherService.qml:313, Modules/Settings/GammaControlTab.qml:524", - "comment": "" - }, - { - "term": "Night Mode", - "context": "Night Mode", - "reference": "Modules/Settings/GammaControlTab.qml:76, Modules/ControlCenter/Models/WidgetModel.qml:68, Modules/ControlCenter/Components/DragDropGrid.qml:618", - "comment": "" - }, - { - "term": "Night Temperature", - "context": "Night Temperature", - "reference": "Modules/Settings/GammaControlTab.qml:105", - "comment": "" - }, - { - "term": "Night mode & gamma", - "context": "Night mode & gamma", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:142", - "comment": "greeter feature card description" - }, - { - "term": "Niri Integration", - "context": "Niri Integration", - "reference": "Modules/Settings/LauncherTab.qml:493", - "comment": "" - }, - { - "term": "Niri Layout Overrides", - "context": "Niri Layout Overrides", - "reference": "Modules/Settings/ThemeColorsTab.qml:1902", - "comment": "" - }, - { - "term": "Niri compositor actions (focus, move, etc.)", - "context": "Niri compositor actions (focus, move, etc.)", - "reference": "Widgets/KeybindItem.qml:855", - "comment": "" - }, - { - "term": "No", - "context": "No", - "reference": "Modules/Settings/PrinterTab.qml:1169, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1232, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1236, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1246, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1256, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1258", - "comment": "" - }, - { - "term": "No Active Players", - "context": "No Active Players", - "reference": "Modules/DankDash/MediaPlayerTab.qml:277", - "comment": "" - }, - { - "term": "No Anim", - "context": "No Anim", - "reference": "Modals/WindowRuleModal.qml:963, Modules/Settings/WindowRulesTab.qml:561", - "comment": "" - }, - { - "term": "No Background", - "context": "No Background", - "reference": "Modules/Settings/DankBarTab.qml:1297", - "comment": "" - }, - { - "term": "No Battery", - "context": "No Battery", - "reference": "Services/BatteryService.qml:155", - "comment": "battery status" - }, - { - "term": "No Bluetooth adapter found", - "context": "No Bluetooth adapter found", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:589", - "comment": "" - }, - { - "term": "No Blur", - "context": "No Blur", - "reference": "Modals/WindowRuleModal.qml:959, Modules/Settings/WindowRulesTab.qml:560", - "comment": "" - }, - { - "term": "No Border", - "context": "No Border", - "reference": "Modals/WindowRuleModal.qml:947, Modules/Settings/WindowRulesTab.qml:557", - "comment": "" - }, - { - "term": "No DMS shortcuts configured", - "context": "No DMS shortcuts configured", - "reference": "Modals/Greeter/GreeterCompletePage.qml:265", - "comment": "greeter no keybinds message" - }, - { - "term": "No Dim", - "context": "No Dim", - "reference": "Modals/WindowRuleModal.qml:955, Modules/Settings/WindowRulesTab.qml:559", - "comment": "" - }, - { - "term": "No Focus", - "context": "No Focus", - "reference": "Modals/WindowRuleModal.qml:943, Modules/Settings/WindowRulesTab.qml:556", - "comment": "" - }, - { - "term": "No GPU detected", - "context": "No GPU detected", - "reference": "Modules/Settings/WidgetsTabSection.qml:146", - "comment": "" - }, - { - "term": "No GPUs detected", - "context": "No GPUs detected", - "reference": "Modules/ProcessList/SystemView.qml:350", - "comment": "empty state in gpu list" - }, - { - "term": "No History", - "context": "No History", - "reference": "Modules/Settings/NotificationsTab.qml:135", - "comment": "notification rule action option" - }, - { - "term": "No Media", - "context": "No Media", - "reference": "Modules/DankDash/Overview/MediaOverviewCard.qml:56", - "comment": "" - }, - { - "term": "No Round", - "context": "No Round", - "reference": "Modules/Settings/WindowRulesTab.qml:562", - "comment": "" - }, - { - "term": "No Rounding", - "context": "No Rounding", - "reference": "Modals/WindowRuleModal.qml:967", - "comment": "" - }, - { - "term": "No Shadow", - "context": "No Shadow", - "reference": "Modals/WindowRuleModal.qml:951, Modules/Settings/WindowRulesTab.qml:558", - "comment": "" - }, - { - "term": "No VPN profiles", - "context": "No VPN profiles", - "reference": "Widgets/VpnDetailContent.qml:177, Modules/Settings/NetworkTab.qml:1671", - "comment": "" - }, - { - "term": "No Weather", - "context": "No Weather", - "reference": "Modules/DankDash/Overview/WeatherOverviewCard.qml:31", - "comment": "" - }, - { - "term": "No Weather Data", - "context": "No Weather Data", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:166", - "comment": "" - }, - { - "term": "No Weather Data Available", - "context": "No Weather Data Available", - "reference": "Modules/DankDash/WeatherTab.qml:135, Modules/Settings/TimeWeatherTab.qml:651", - "comment": "" - }, - { - "term": "No action", - "context": "No action", - "reference": "Widgets/KeybindItem.qml:372", - "comment": "" - }, - { - "term": "No active %1 sessions", - "context": "No active %1 sessions", - "reference": "Modals/MuxModal.qml:562", - "comment": "" - }, - { - "term": "No adapter", - "context": "No adapter", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:315", - "comment": "bluetooth status" - }, - { - "term": "No adapters", - "context": "No adapters", - "reference": "Modules/Settings/NetworkTab.qml:341, Modules/ControlCenter/Components/DragDropGrid.qml:353", - "comment": "bluetooth status" - }, - { - "term": "No app customizations.", - "context": "No app customizations.", - "reference": "Modules/Settings/LauncherTab.qml:1126", - "comment": "" - }, - { - "term": "No apps found", - "context": "No apps found", - "reference": "Modals/DankLauncherV2/ResultsList.qml:490", - "comment": "" - }, - { - "term": "No apps have been launched yet.", - "context": "No apps have been launched yet.", - "reference": "Modules/Settings/LauncherTab.qml:1296", - "comment": "" - }, - { - "term": "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.", - "context": "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.", - "reference": "Modules/Settings/NotificationsTab.qml:641", - "comment": "" - }, - { - "term": "No battery", - "context": "No battery", - "reference": "Modules/ControlCenter/Widgets/BatteryPill.qml:15", - "comment": "" - }, - { - "term": "No brightness devices available", - "context": "No brightness devices available", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:147", - "comment": "" - }, - { - "term": "No changes", - "context": "No changes", - "reference": "Widgets/KeybindItem.qml:1807", - "comment": "" - }, - { - "term": "No checks passed", - "context": "No checks passed", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:338", - "comment": "greeter doctor page empty state" - }, - { - "term": "No custom theme file", - "context": "No custom theme file", - "reference": "Modules/Settings/ThemeColorsTab.qml:574", - "comment": "no custom theme file status" - }, - { - "term": "No devices", - "context": "No devices", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:33, Modules/ControlCenter/Components/DragDropGrid.qml:368", - "comment": "Phone Connect no devices status | bluetooth status" - }, - { - "term": "No devices connected", - "context": "No devices connected", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:35", - "comment": "KDE Connect status" - }, - { - "term": "No devices found", - "context": "No devices found", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:124, dms-plugins/DankKDEConnect/components/EmptyState.qml:11, Modules/Settings/PrinterTab.qml:436", - "comment": "KDE Connect no devices message" - }, - { - "term": "No disk data", - "context": "No disk data", - "reference": "Modules/ControlCenter/Widgets/DiskUsagePill.qml:38", - "comment": "" - }, - { - "term": "No disk data available", - "context": "No disk data available", - "reference": "Modules/ControlCenter/Details/DiskUsageDetail.qml:65, Modules/ControlCenter/Widgets/DiskUsagePill.qml:48", - "comment": "" - }, - { - "term": "No drivers found", - "context": "No drivers found", - "reference": "Modules/Settings/PrinterTab.qml:704", - "comment": "" - }, - { - "term": "No errors", - "context": "No errors", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:332", - "comment": "greeter doctor page empty state" - }, - { - "term": "No features enabled", - "context": "No features enabled", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:84", - "comment": "" - }, - { - "term": "No files found", - "context": "No files found", - "reference": "Modals/DankLauncherV2/ResultsList.qml:483", - "comment": "" - }, - { - "term": "No fingerprint reader detected.", - "context": "No fingerprint reader detected.", - "reference": "Modules/Settings/GreeterTab.qml:45, Modules/Settings/LockScreenTab.qml:24", - "comment": "" - }, - { - "term": "No folders found", - "context": "No folders found", - "reference": "Modals/DankLauncherV2/ResultsList.qml:481", - "comment": "" - }, - { - "term": "No hidden apps.", - "context": "No hidden apps.", - "reference": "Modules/Settings/LauncherTab.qml:1016", - "comment": "" - }, - { - "term": "No info items", - "context": "No info items", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:336", - "comment": "greeter doctor page empty state" - }, - { - "term": "No information available", - "context": "No information available", - "reference": "Modals/NetworkWiredInfoModal.qml:105, Modals/NetworkInfoModal.qml:105", - "comment": "" - }, - { - "term": "No input device", - "context": "No input device", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:323", - "comment": "audio status" - }, - { - "term": "No input devices found", - "context": "No input devices found", - "reference": "Modules/Settings/AudioTab.qml:372", - "comment": "Audio settings empty state" - }, - { - "term": "No items added yet", - "context": "No items added yet", - "reference": "Modules/Plugins/ListSetting.qml:79, Modules/Plugins/ListSettingWithInput.qml:250", - "comment": "" - }, - { - "term": "No keybinds found", - "context": "No keybinds found", - "reference": "Modules/Settings/KeybindsTab.qml:590", - "comment": "" - }, - { - "term": "No launcher plugins installed.", - "context": "No launcher plugins installed.", - "reference": "Modules/Settings/LauncherTab.qml:855", - "comment": "" - }, - { - "term": "No match criteria", - "context": "No match criteria", - "reference": "Modules/Settings/WindowRulesTab.qml:513", - "comment": "" - }, - { - "term": "No matches", - "context": "No matches", - "reference": "Modals/Settings/SettingsSidebar.qml:809, Modules/Notepad/NotepadTextEditor.qml:391", - "comment": "" - }, - { - "term": "No matching processes", - "context": "No matching processes", - "reference": "Modules/ProcessList/ProcessesView.qml:361", - "comment": "empty state in process list" - }, - { - "term": "No monitors", - "context": "No monitors", - "reference": "Modules/Settings/WallpaperTab.qml:828, Modules/Settings/WallpaperTab.qml:859", - "comment": "no monitors available label" - }, - { - "term": "No mount points found", - "context": "No mount points found", - "reference": "Modules/ProcessList/DisksView.qml:335", - "comment": "empty state in disk mounts list" - }, - { - "term": "No output device", - "context": "No output device", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:321", - "comment": "audio status" - }, - { - "term": "No output devices found", - "context": "No output devices found", - "reference": "Modules/Settings/AudioTab.qml:228", - "comment": "Audio settings empty state" - }, - { - "term": "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.", - "context": "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.", - "reference": "Modules/SystemUpdatePopout.qml:144", - "comment": "" - }, - { - "term": "No plugin results", - "context": "No plugin results", - "reference": "Modals/DankLauncherV2/ResultsList.qml:488", - "comment": "" - }, - { - "term": "No plugins found", - "context": "No plugins found", - "reference": "Modules/Settings/PluginBrowser.qml:708", - "comment": "empty plugin list" - }, - { - "term": "No plugins found.", - "context": "No plugins found.", - "reference": "Modules/Settings/PluginsTab.qml:337", - "comment": "" - }, - { - "term": "No printer found", - "context": "No printer found", - "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:24, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:67", - "comment": "" - }, - { - "term": "No printers configured", - "context": "No printers configured", - "reference": "Modules/Settings/PrinterTab.qml:881", - "comment": "" - }, - { - "term": "No printers found", - "context": "No printers found", - "reference": "Modules/Settings/PrinterTab.qml:923", - "comment": "" - }, - { - "term": "No profiles", - "context": "No profiles", - "reference": "Modules/Settings/DisplayConfigTab.qml:182", - "comment": "" - }, - { - "term": "No recent clipboard entries found", - "context": "No recent clipboard entries found", - "reference": "Modals/Clipboard/ClipboardContent.qml:125", - "comment": "" - }, - { - "term": "No results found", - "context": "No results found", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:153, dms-plugins/DankGifSearch/DankGifSearch.qml:96, Modals/DankLauncherV2/ResultsList.qml:485, Modals/DankLauncherV2/ResultsList.qml:492", - "comment": "" - }, - { - "term": "No saved clipboard entries", - "context": "No saved clipboard entries", - "reference": "Modals/Clipboard/ClipboardContent.qml:184", - "comment": "" - }, - { - "term": "No sessions found", - "context": "No sessions found", - "reference": "Modals/MuxModal.qml:562", - "comment": "" - }, - { - "term": "No status output.", - "context": "No status output.", - "reference": "Modules/Settings/GreeterTab.qml:269", - "comment": "" - }, - { - "term": "No themes found", - "context": "No themes found", - "reference": "Modules/Settings/ThemeBrowser.qml:684", - "comment": "empty theme list" - }, - { - "term": "No themes installed. Browse themes to install from the registry.", - "context": "No themes installed. Browse themes to install from the registry.", - "reference": "Modules/Settings/ThemeColorsTab.qml:780", - "comment": "no registry themes installed hint" - }, - { - "term": "No trigger", - "context": "No trigger", - "reference": "Modals/DankLauncherV2/Controller.qml:1237, Modules/Settings/LauncherTab.qml:768", - "comment": "" - }, - { - "term": "No video found in folder", - "context": "No video found in folder", - "reference": "Modules/Lock/VideoScreensaver.qml:57", - "comment": "" - }, - { - "term": "No wallpaper selected", - "context": "No wallpaper selected", - "reference": "Modules/Settings/ThemeColorsTab.qml:471, Modules/Settings/WallpaperTab.qml:240", - "comment": "no wallpaper status" - }, - { - "term": "No wallpapers", - "context": "No wallpapers", - "reference": "Modules/DankDash/WallpaperTab.qml:545", - "comment": "" - }, - { - "term": "No wallpapers found\n\nClick the folder icon below to browse", - "context": "No wallpapers found\n\nClick the folder icon below to browse", - "reference": "Modules/DankDash/WallpaperTab.qml:499", - "comment": "" - }, - { - "term": "No warnings", - "context": "No warnings", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:334", - "comment": "greeter doctor page empty state" - }, - { - "term": "No widgets added. Click \"Add Widget\" to get started.", - "context": "No widgets added. Click \"Add Widget\" to get started.", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:603", - "comment": "" - }, - { - "term": "No widgets available", - "context": "No widgets available", - "reference": "Modules/Settings/DesktopWidgetBrowser.qml:459", - "comment": "" - }, - { - "term": "No widgets match your search", - "context": "No widgets match your search", - "reference": "Modules/Settings/DesktopWidgetBrowser.qml:459", - "comment": "" - }, - { - "term": "No window rules configured", - "context": "No window rules configured", - "reference": "Modules/Settings/WindowRulesTab.qml:429", - "comment": "" - }, - { - "term": "None", - "context": "None", - "reference": "Modals/WindowRuleModal.qml:740, Services/CupsService.qml:784, Modules/Settings/TypographyMotionTab.qml:212, Modules/Settings/TypographyMotionTab.qml:315, Modules/Settings/TypographyMotionTab.qml:399, Modules/Settings/WallpaperTab.qml:1161, Modules/Settings/DesktopWidgetInstanceCard.qml:258, Modules/Settings/DesktopWidgetInstanceCard.qml:274, Modules/Settings/DankBarTab.qml:729, Modules/Settings/DankBarTab.qml:729, Modules/Settings/DankBarTab.qml:766, Modules/Settings/NotificationsTab.qml:337, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:87, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:100, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:104", - "comment": "wallpaper transition option" - }, - { - "term": "Normal", - "context": "Normal", - "reference": "Modals/WindowRuleModal.qml:762, Modules/Settings/DisplayConfig/OutputCard.qml:257, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1793, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1809, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1814", - "comment": "" - }, - { - "term": "Normal Font", - "context": "Normal Font", - "reference": "Modules/Settings/TypographyMotionTab.qml:69", - "comment": "" - }, - { - "term": "Normal Priority", - "context": "Normal Priority", - "reference": "Modules/Settings/NotificationsTab.qml:150, Modules/Settings/NotificationsTab.qml:768, Modules/Settings/NotificationsTab.qml:883, Modules/Notifications/Center/NotificationSettings.qml:196, Modules/Notifications/Center/NotificationSettings.qml:398", - "comment": "notification rule urgency option" - }, - { - "term": "Not available", - "context": "Not available", - "reference": "Modules/ControlCenter/Widgets/BatteryPill.qml:22", - "comment": "" - }, - { - "term": "Not available — install fprintd and pam_fprintd, or configure greetd PAM.", - "context": "Not available — install fprintd and pam_fprintd, or configure greetd PAM.", - "reference": "Modules/Settings/GreeterTab.qml:47", - "comment": "" - }, - { - "term": "Not available — install fprintd and pam_fprintd.", - "context": "Not available — install fprintd and pam_fprintd.", - "reference": "Modules/Settings/LockScreenTab.qml:26", - "comment": "" - }, - { - "term": "Not available — install or configure pam_u2f, or configure greetd PAM.", - "context": "Not available — install or configure pam_u2f, or configure greetd PAM.", - "reference": "Modules/Settings/GreeterTab.qml:69", - "comment": "" - }, - { - "term": "Not available — install or configure pam_u2f.", - "context": "Not available — install or configure pam_u2f.", - "reference": "Modules/Settings/LockScreenTab.qml:41", - "comment": "" - }, - { - "term": "Not connected", - "context": "Not connected", - "reference": "Modules/Settings/NetworkTab.qml:826, Modules/ControlCenter/Components/DragDropGrid.qml:307", - "comment": "network status" - }, - { - "term": "Not detected", - "context": "Not detected", - "reference": "Modules/Settings/ThemeColorsTab.qml:118, Modules/Settings/ThemeColorsTab.qml:119", - "comment": "" - }, - { - "term": "Not paired", - "context": "Not paired", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:214, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:207", - "comment": "KDE Connect not paired status" - }, - { - "term": "Not set", - "context": "Not set", - "reference": "Modules/Settings/WallpaperTab.qml:567, Modules/Settings/WallpaperTab.qml:757", - "comment": "wallpaper not set label" - }, - { - "term": "Note: this only changes the percentage, it does not actually limit charging.", - "context": "Note: this only changes the percentage, it does not actually limit charging.", - "reference": "Modules/Settings/PowerSleepTab.qml:588", - "comment": "" - }, - { - "term": "Notepad", - "context": "Notepad", - "reference": "DMSShell.qml:826, Services/AppSearchService.qml:179, Modules/Settings/WidgetsTab.qml:232", - "comment": "Notepad" - }, - { - "term": "Notepad Font Settings", - "context": "Notepad Font Settings", - "reference": "Modules/Notepad/NotepadSettings.qml:113", - "comment": "" - }, - { - "term": "Notepad Slideout", - "context": "Notepad Slideout", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:61", - "comment": "" - }, - { - "term": "Nothing", - "context": "Nothing", - "reference": "Modules/Settings/MediaPlayerTab.qml:58", - "comment": "media scroll wheel option" - }, - { - "term": "Nothing to see here", - "context": "Nothing to see here", - "reference": "Modules/Notifications/Center/NotificationEmptyState.qml:27", - "comment": "" - }, - { - "term": "Notification Center", - "context": "Notification Center", - "reference": "Modules/Settings/WidgetsTab.qml:169", - "comment": "" - }, - { - "term": "Notification Display", - "context": "Notification Display", - "reference": "Modules/Settings/LockScreenTab.qml:146, Modules/Settings/NotificationsTab.qml:727", - "comment": "lock screen notification privacy setting" - }, - { - "term": "Notification Overlay", - "context": "Notification Overlay", - "reference": "Modules/Settings/NotificationsTab.qml:261, Modules/Notifications/Center/NotificationSettings.qml:257", - "comment": "" - }, - { - "term": "Notification Popups", - "context": "Notification Popups", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:37, Modules/Settings/NotificationsTab.qml:206", - "comment": "" - }, - { - "term": "Notification Rules", - "context": "Notification Rules", - "reference": "Modules/Settings/NotificationsTab.qml:403", - "comment": "" - }, - { - "term": "Notification Settings", - "context": "Notification Settings", - "reference": "Modules/Notifications/Center/NotificationSettings.qml:127", - "comment": "" - }, - { - "term": "Notification Timeouts", - "context": "Notification Timeouts", - "reference": "Modules/Settings/NotificationsTab.qml:743, Modules/Notifications/Center/NotificationSettings.qml:174", - "comment": "" - }, - { - "term": "Notification toast popups", - "context": "Notification toast popups", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:38", - "comment": "" - }, - { - "term": "Notifications", - "context": "Notifications", - "reference": "Modals/Greeter/GreeterCompletePage.qml:397, Modals/Settings/SettingsSidebar.qml:146, Modules/Notifications/Center/NotificationHeader.qml:49", - "comment": "greeter settings link" - }, - { - "term": "Numbers", - "context": "Numbers", - "reference": "Widgets/DankIconPicker.qml:23", - "comment": "" - }, - { - "term": "Numeric (D/M)", - "context": "Numeric (D/M)", - "reference": "Modules/Settings/GreeterTab.qml:414, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:154, Modules/Settings/TimeWeatherTab.qml:179, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:241, Modules/Settings/TimeWeatherTab.qml:266", - "comment": "date format option" - }, - { - "term": "Numeric (M/D)", - "context": "Numeric (M/D)", - "reference": "Modules/Settings/GreeterTab.qml:410, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:150, Modules/Settings/TimeWeatherTab.qml:178, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:237, Modules/Settings/TimeWeatherTab.qml:265", - "comment": "date format option" - }, - { - "term": "OK", - "context": "OK", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:281", - "comment": "greeter doctor page status card" - }, - { - "term": "OS Logo", - "context": "OS Logo", - "reference": "Modules/Settings/DockTab.qml:266, Modules/Settings/LauncherTab.qml:59", - "comment": "" - }, - { - "term": "OSD Position", - "context": "OSD Position", - "reference": "Modules/Settings/OSDTab.qml:30", - "comment": "" - }, - { - "term": "Occupied Color", - "context": "Occupied Color", - "reference": "Modules/Settings/WorkspacesTab.qml:234", - "comment": "" - }, - { - "term": "Off", - "context": "Off", - "reference": "Modules/ProcessList/SystemView.qml:274, Modules/Settings/DisplayConfig/OutputCard.qml:280, Modules/Settings/DisplayConfig/OutputCard.qml:289, Modules/Settings/DisplayConfig/OutputCard.qml:292, Modules/Settings/DisplayConfig/OutputCard.qml:303, Modules/Settings/DisplayConfig/OutputCard.qml:311, Modules/Settings/DisplayConfig/OutputCard.qml:315, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:89, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:97, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:104, Modules/ControlCenter/Components/DragDropGrid.qml:355", - "comment": "bluetooth status" - }, - { - "term": "Office", - "context": "Office", - "reference": "Services/AppSearchService.qml:649, Services/AppSearchService.qml:650, Services/AppSearchService.qml:651, Services/AppSearchService.qml:652", - "comment": "" - }, - { - "term": "Offline", - "context": "Offline", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:40, dms-plugins/DankKDEConnect/components/DeviceCard.qml:216, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:209", - "comment": "KDE Connect offline status | Phone Connect offline status" - }, - { - "term": "Offline Report", - "context": "Offline Report", - "reference": "Services/CupsService.qml:829", - "comment": "" - }, - { - "term": "Older", - "context": "Older", - "reference": "Modules/Notifications/Center/HistoryNotificationList.qml:117", - "comment": "notification history filter for content older than other filters" - }, - { - "term": "On", - "context": "On", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:280, Modules/Settings/DisplayConfig/OutputCard.qml:288, Modules/Settings/DisplayConfig/OutputCard.qml:303, Modules/Settings/DisplayConfig/OutputCard.qml:312", - "comment": "" - }, - { - "term": "On-Demand", - "context": "On-Demand", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:303, Modules/Settings/DisplayConfig/OutputCard.qml:307, Modules/Settings/DisplayConfig/OutputCard.qml:316", - "comment": "" - }, - { - "term": "On-Screen Displays", - "context": "On-Screen Displays", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:49", - "comment": "" - }, - { - "term": "On-screen Displays", - "context": "On-screen Displays", - "reference": "Modals/Settings/SettingsSidebar.qml:152, Modules/Settings/OSDTab.qml:25", - "comment": "" - }, - { - "term": "Only adjust gamma based on time or location rules.", - "context": "Only adjust gamma based on time or location rules.", - "reference": "Modules/Settings/GammaControlTab.qml:140", - "comment": "" - }, - { - "term": "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.", - "context": "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.", - "reference": "Modules/Settings/GreeterTab.qml:39", - "comment": "" - }, - { - "term": "Only show windows from the current monitor on each dock", - "context": "Only show windows from the current monitor on each dock", - "reference": "Modules/Settings/DockTab.qml:149", - "comment": "" - }, - { - "term": "Only visible if hibernate is supported by your system", - "context": "Only visible if hibernate is supported by your system", - "reference": "Modules/Settings/PowerSleepTab.qml:436", - "comment": "" - }, - { - "term": "Opacity", - "context": "Opacity", - "reference": "Modals/WindowRuleModal.qml:679, Modals/DankColorPickerModal.qml:521, Modules/Settings/DankBarTab.qml:1104, Modules/Settings/DankBarTab.qml:1429, Modules/Settings/DankBarTab.qml:1519, Modules/Settings/WindowRulesTab.qml:534", - "comment": "" - }, - { - "term": "Opaque", - "context": "Opaque", - "reference": "Modals/WindowRuleModal.qml:975, Modules/Settings/WindowRulesTab.qml:564", - "comment": "" - }, - { - "term": "Open", - "context": "Open", - "reference": "Modals/DankLauncherV2/Controller.qml:1106, Modals/DankLauncherV2/Controller.qml:1110, Modals/DankLauncherV2/Controller.qml:1114, Modules/Notepad/NotepadTextEditor.qml:790, Modules/Settings/NetworkTab.qml:1201, Modules/Settings/NetworkTab.qml:1448, Modules/ControlCenter/Details/NetworkDetail.qml:609, Modules/Notifications/Center/NotificationCard.qml:716, Modules/Notifications/Center/NotificationCard.qml:852", - "comment": "" - }, - { - "term": "Open App", - "context": "Open App", - "reference": "dms-plugins/DankKDEConnect/components/SmsDialog.qml:91", - "comment": "KDE Connect open SMS app button" - }, - { - "term": "Open KDE Connect on your phone", - "context": "Open KDE Connect on your phone", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:131", - "comment": "KDE Connect open app hint" - }, - { - "term": "Open Notepad File", - "context": "Open Notepad File", - "reference": "Modules/Notepad/Notepad.qml:343", - "comment": "" - }, - { - "term": "Open a new note", - "context": "Open a new note", - "reference": "Modules/DankBar/Widgets/NotepadButton.qml:347", - "comment": "" - }, - { - "term": "Open folder", - "context": "Open folder", - "reference": "Modals/DankLauncherV2/Controller.qml:1114", - "comment": "" - }, - { - "term": "Open in Browser", - "context": "Open in Browser", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:301, dms-plugins/DankGifSearch/DankGifSearch.qml:248", - "comment": "" - }, - { - "term": "Open in terminal", - "context": "Open in terminal", - "reference": "Modals/DankLauncherV2/Controller.qml:1114", - "comment": "" - }, - { - "term": "Open search bar to find text", - "context": "Open search bar to find text", - "reference": "Modules/Notepad/NotepadSettings.qml:192", - "comment": "" - }, - { - "term": "Open with...", - "context": "Open with...", - "reference": "DMSShell.qml:660, Modals/BrowserPickerModal.qml:11", - "comment": "" - }, - { - "term": "Opening SMS", - "context": "Opening SMS", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:344", - "comment": "KDE Connect SMS action" - }, - { - "term": "Opening SMS app", - "context": "Opening SMS app", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:136", - "comment": "Phone Connect SMS action" - }, - { - "term": "Opening file browser", - "context": "Opening file browser", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:146", - "comment": "Phone Connect browse action" - }, - { - "term": "Opening files", - "context": "Opening files", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:328", - "comment": "KDE Connect browse action" - }, - { - "term": "Opening terminal: ", - "context": "Opening terminal: ", - "reference": "Modules/Settings/GreeterTab.qml:156", - "comment": "" - }, - { - "term": "Optional description", - "context": "Optional description", - "reference": "Modules/Settings/PrinterTab.qml:806", - "comment": "" - }, - { - "term": "Optional location", - "context": "Optional location", - "reference": "Modules/Settings/PrinterTab.qml:785", - "comment": "" - }, - { - "term": "Options", - "context": "Options", - "reference": "Widgets/KeybindItem.qml:1222, Widgets/KeybindItem.qml:1711", - "comment": "" - }, - { - "term": "Organize widgets into collapsible groups", - "context": "Organize widgets into collapsible groups", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:123", - "comment": "" - }, - { - "term": "Original: %1", - "context": "Original: %1", - "reference": "Modules/Settings/AudioTab.qml:600, Modules/Settings/Widgets/DeviceAliasRow.qml:103", - "comment": "Shows the original device name before renaming" - }, - { - "term": "Other", - "context": "Other", - "reference": "Services/CupsService.qml:785", - "comment": "" - }, - { - "term": "Outline", - "context": "Outline", - "reference": "Modules/Settings/ThemeColorsTab.qml:1853, Modules/Settings/ThemeColorsTab.qml:1865, Modules/Settings/LauncherTab.qml:477", - "comment": "blur border color | outline color" - }, - { - "term": "Output", - "context": "Output", - "reference": "Modals/WindowRuleModal.qml:559, Modules/Settings/WindowRulesTab.qml:540", - "comment": "" - }, - { - "term": "Output Area Almost Full", - "context": "Output Area Almost Full", - "reference": "Services/CupsService.qml:809", - "comment": "" - }, - { - "term": "Output Area Full", - "context": "Output Area Full", - "reference": "Services/CupsService.qml:810", - "comment": "" - }, - { - "term": "Output Device", - "context": "Output Device", - "reference": "Modules/DankDash/MediaPlayerTab.qml:781", - "comment": "" - }, - { - "term": "Output Devices", - "context": "Output Devices", - "reference": "Modules/Settings/AudioTab.qml:128", - "comment": "Audio settings: speaker/headphone devices" - }, - { - "term": "Output Tray Missing", - "context": "Output Tray Missing", - "reference": "Services/CupsService.qml:808", - "comment": "" - }, - { - "term": "Outputs Include Missing", - "context": "Outputs Include Missing", - "reference": "Modules/Settings/DisplayConfig/IncludeWarningBox.qml:50", - "comment": "" - }, - { - "term": "Overcast", - "context": "Overcast", - "reference": "Services/WeatherService.qml:125", - "comment": "" - }, - { - "term": "Overflow", - "context": "Overflow", - "reference": "Modules/Settings/WidgetsTabSection.qml:2434", - "comment": "" - }, - { - "term": "Overridden by config", - "context": "Overridden by config", - "reference": "Widgets/KeybindItem.qml:414", - "comment": "" - }, - { - "term": "Override", - "context": "Override", - "reference": "Widgets/KeybindItem.qml:400", - "comment": "" - }, - { - "term": "Override Border Size", - "context": "Override Border Size", - "reference": "Modules/Settings/ThemeColorsTab.qml:1974, Modules/Settings/ThemeColorsTab.qml:2077, Modules/Settings/ThemeColorsTab.qml:2180", - "comment": "" - }, - { - "term": "Override Corner Radius", - "context": "Override Corner Radius", - "reference": "Modules/Settings/ThemeColorsTab.qml:1943, Modules/Settings/ThemeColorsTab.qml:2046, Modules/Settings/ThemeColorsTab.qml:2149", - "comment": "" - }, - { - "term": "Override Gaps", - "context": "Override Gaps", - "reference": "Modules/Settings/ThemeColorsTab.qml:1911, Modules/Settings/ThemeColorsTab.qml:2014, Modules/Settings/ThemeColorsTab.qml:2117", - "comment": "" - }, - { - "term": "Override global layout settings for this output", - "context": "Override global layout settings for this output", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:200", - "comment": "" - }, - { - "term": "Override terminal with a custom command or script", - "context": "Override terminal with a custom command or script", - "reference": "Modules/Settings/MuxTab.qml:57", - "comment": "" - }, - { - "term": "Override the global shadow with per-bar settings", - "context": "Override the global shadow with per-bar settings", - "reference": "Modules/Settings/DankBarTab.qml:1073", - "comment": "" - }, - { - "term": "Overrides", - "context": "Overrides", - "reference": "Modules/Settings/KeybindsTab.qml:76", - "comment": "" - }, - { - "term": "Overview", - "context": "Overview", - "reference": "Widgets/KeybindItem.qml:1101, Widgets/KeybindItem.qml:1104, Modules/DankDash/DankDashPopout.qml:271", - "comment": "" - }, - { - "term": "Overview of your network connections", - "context": "Overview of your network connections", - "reference": "Modules/Settings/NetworkTab.qml:148", - "comment": "" - }, - { - "term": "Overwrite", - "context": "Overwrite", - "reference": "Modals/FileBrowser/FileBrowserOverwriteDialog.qml:108", - "comment": "" - }, - { - "term": "PAM already provides fingerprint auth. Enable this to show it at login.", - "context": "PAM already provides fingerprint auth. Enable this to show it at login.", - "reference": "Modules/Settings/GreeterTab.qml:27", - "comment": "" - }, - { - "term": "PAM already provides security-key auth. Enable this to show it at login.", - "context": "PAM already provides security-key auth. Enable this to show it at login.", - "reference": "Modules/Settings/GreeterTab.qml:58", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but availability could not be confirmed.", - "context": "PAM provides fingerprint auth, but availability could not be confirmed.", - "reference": "Modules/Settings/GreeterTab.qml:33", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but no prints are enrolled yet.", - "context": "PAM provides fingerprint auth, but no prints are enrolled yet.", - "reference": "Modules/Settings/GreeterTab.qml:29", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but no reader was detected.", - "context": "PAM provides fingerprint auth, but no reader was detected.", - "reference": "Modules/Settings/GreeterTab.qml:31", - "comment": "" - }, - { - "term": "PIN", - "context": "PIN", - "reference": "Modals/WifiPasswordModal.qml:182", - "comment": "" - }, - { - "term": "Pad", - "context": "Pad", - "reference": "Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Pad Hours", - "context": "Pad Hours", - "reference": "Modules/Settings/TimeWeatherTab.qml:73", - "comment": "" - }, - { - "term": "Pad hours (02:00 vs 2:00)", - "context": "Pad hours (02:00 vs 2:00)", - "reference": "Modules/Settings/GreeterTab.qml:618", - "comment": "" - }, - { - "term": "Padding", - "context": "Padding", - "reference": "Modules/Settings/DockTab.qml:537, Modules/Settings/DankBarTab.qml:872", - "comment": "" - }, - { - "term": "Pair", - "context": "Pair", - "reference": "Modals/BluetoothPairingModal.qml:324, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:391, Modules/ControlCenter/Details/BluetoothDetail.qml:558", - "comment": "KDE Connect pair button" - }, - { - "term": "Pair Bluetooth Device", - "context": "Pair Bluetooth Device", - "reference": "Modals/BluetoothPairingModal.qml:121", - "comment": "" - }, - { - "term": "Paired", - "context": "Paired", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:299", - "comment": "" - }, - { - "term": "Pairing", - "context": "Pairing", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:212, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:205", - "comment": "KDE Connect pairing in progress status" - }, - { - "term": "Pairing failed", - "context": "Pairing failed", - "reference": "Modals/BluetoothPairingModal.qml:400, dms-plugins/DankKDEConnect/DankKDEConnect.qml:152, Modules/ControlCenter/Details/BluetoothDetail.qml:50", - "comment": "Phone Connect error" - }, - { - "term": "Pairing request from", - "context": "Pairing request from", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:71", - "comment": "Phone Connect pairing request notification" - }, - { - "term": "Pairing request sent", - "context": "Pairing request sent", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:155", - "comment": "Phone Connect pairing action" - }, - { - "term": "Pairing requested", - "context": "Pairing requested", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:210, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:203", - "comment": "KDE Connect pairing requested status" - }, - { - "term": "Pairing...", - "context": "Pairing...", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:530, Modules/ControlCenter/Details/BluetoothDetail.qml:555", - "comment": "" - }, - { - "term": "Partly Cloudy", - "context": "Partly Cloudy", - "reference": "Services/WeatherService.qml:124", - "comment": "" - }, - { - "term": "Passkey:", - "context": "Passkey:", - "reference": "Modals/BluetoothPairingModal.qml:235", - "comment": "" - }, - { - "term": "Password", - "context": "Password", - "reference": "Modals/WifiPasswordModal.qml:174, Modals/WifiPasswordModal.qml:184, Modals/WifiPasswordModal.qml:553", - "comment": "" - }, - { - "term": "Password...", - "context": "Password...", - "reference": "Modules/Greetd/GreeterContent.qml:1021", - "comment": "" - }, - { - "term": "Paste", - "context": "Paste", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:248, dms-plugins/DankGifSearch/DankGifSearch.qml:195", - "comment": "" - }, - { - "term": "Path to a video file or folder containing videos", - "context": "Path to a video file or folder containing videos", - "reference": "Modules/Settings/LockScreenTab.qml:301", - "comment": "" - }, - { - "term": "Pattern", - "context": "Pattern", - "reference": "Modules/Settings/RunningAppsTab.qml:87, Modules/Settings/NotificationsTab.qml:522, Modules/Settings/NotificationsTab.qml:531", - "comment": "" - }, - { - "term": "Pause", - "context": "Pause", - "reference": "Modules/Settings/PrinterTab.qml:1232, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:136", - "comment": "" - }, - { - "term": "Paused", - "context": "Paused", - "reference": "Services/CupsService.qml:814", - "comment": "" - }, - { - "term": "Pending", - "context": "Pending", - "reference": "Services/CupsService.qml:759", - "comment": "" - }, - { - "term": "Pending Charge", - "context": "Pending Charge", - "reference": "Services/BatteryService.qml:144", - "comment": "battery status" - }, - { - "term": "Pending Discharge", - "context": "Pending Discharge", - "reference": "Services/BatteryService.qml:146", - "comment": "battery status" - }, - { - "term": "Per-Mode Wallpapers", - "context": "Per-Mode Wallpapers", - "reference": "Modules/Settings/WallpaperTab.qml:370", - "comment": "" - }, - { - "term": "Per-Monitor Wallpapers", - "context": "Per-Monitor Wallpapers", - "reference": "Modules/Settings/WallpaperTab.qml:801", - "comment": "" - }, - { - "term": "Per-screen config", - "context": "Per-screen config", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:131", - "comment": "greeter feature card description" - }, - { - "term": "Percentage", - "context": "Percentage", - "reference": "Modules/Settings/WidgetsTabSection.qml:1098, Modules/Settings/WidgetsTab.qml:125", - "comment": "" - }, - { - "term": "Performance", - "context": "Performance", - "reference": "Modals/ProcessListModal.qml:311, Common/Theme.qml:1476", - "comment": "power profile option" - }, - { - "term": "Permission denied to set profile image.", - "context": "Permission denied to set profile image.", - "reference": "Services/PortalService.qml:150", - "comment": "" - }, - { - "term": "Personalization", - "context": "Personalization", - "reference": "Modals/Settings/SettingsSidebar.qml:71, Modals/Settings/SettingsSidebar.qml:581", - "comment": "" - }, - { - "term": "Phone Connect Not Available", - "context": "Phone Connect Not Available", - "reference": "dms-plugins/DankKDEConnect/components/UnavailableMessage.qml:30", - "comment": "Phone Connect unavailable error title" - }, - { - "term": "Phone Connect unavailable", - "context": "Phone Connect unavailable", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:97", - "comment": "Phone Connect service unavailable message" - }, - { - "term": "Phone number", - "context": "Phone number", - "reference": "dms-plugins/DankKDEConnect/components/SmsDialog.qml:67", - "comment": "KDE Connect SMS phone input placeholder" - }, - { - "term": "Pick a different random video each time from the same folder", - "context": "Pick a different random video each time from the same folder", - "reference": "Modules/Settings/LockScreenTab.qml:337", - "comment": "" - }, - { - "term": "Pictures", - "context": "Pictures", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:256", - "comment": "" - }, - { - "term": "Pin", - "context": "Pin", - "reference": "Modals/WindowRuleModal.qml:971, dms-plugins/DankLauncherKeys/DankLauncherKeys.qml:165, Modules/Settings/WindowRulesTab.qml:563, Modules/ControlCenter/Details/BluetoothDetail.qml:357, Modules/ControlCenter/Details/BrightnessDetail.qml:207, Modules/ControlCenter/Details/AudioInputDetail.qml:295, Modules/ControlCenter/Details/AudioOutputDetail.qml:304, Modules/ControlCenter/Details/NetworkDetail.qml:676", - "comment": "" - }, - { - "term": "Pin to Dock", - "context": "Pin to Dock", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:103, Modules/Dock/DockContextMenu.qml:418, Modules/DankBar/Widgets/AppsDockContextMenu.qml:341", - "comment": "" - }, - { - "term": "Ping", - "context": "Ping", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:124, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:281", - "comment": "KDE Connect ping tooltip" - }, - { - "term": "Ping sent", - "context": "Ping sent", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:286", - "comment": "KDE Connect ping action" - }, - { - "term": "Ping sent to", - "context": "Ping sent to", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:108", - "comment": "Phone Connect ping action" - }, - { - "term": "Pinned", - "context": "Pinned", - "reference": "Modals/DankLauncherV2/Controller.qml:146, Modules/ControlCenter/Details/BluetoothDetail.qml:357, Modules/ControlCenter/Details/BrightnessDetail.qml:207, Modules/ControlCenter/Details/AudioInputDetail.qml:295, Modules/ControlCenter/Details/AudioOutputDetail.qml:304, Modules/ControlCenter/Details/NetworkDetail.qml:676", - "comment": "" - }, - { - "term": "Pinned and running apps with drag-and-drop", - "context": "Pinned and running apps with drag-and-drop", - "reference": "Modules/Settings/WidgetsTab.qml:74", - "comment": "" - }, - { - "term": "Pixelate", - "context": "Pixelate", - "reference": "Modules/Settings/WallpaperTab.qml:1173", - "comment": "wallpaper transition option" - }, - { - "term": "Place plugin directories here. Each plugin should have a plugin.json manifest file.", - "context": "Place plugin directories here. Each plugin should have a plugin.json manifest file.", - "reference": "Modules/Settings/PluginsTab.qml:275", - "comment": "" - }, - { - "term": "Place plugins in %1", - "context": "Place plugins in %1", - "reference": "Modules/Settings/PluginsTab.qml:337", - "comment": "" - }, - { - "term": "Play a video when the screen locks.", - "context": "Play a video when the screen locks.", - "reference": "Modules/Settings/LockScreenTab.qml:283", - "comment": "" - }, - { - "term": "Play sound after logging in", - "context": "Play sound after logging in", - "reference": "Modules/Settings/SoundsTab.qml:99", - "comment": "" - }, - { - "term": "Play sound when new notification arrives", - "context": "Play sound when new notification arrives", - "reference": "Modules/Settings/SoundsTab.qml:109", - "comment": "" - }, - { - "term": "Play sound when power cable is connected", - "context": "Play sound when power cable is connected", - "reference": "Modules/Settings/SoundsTab.qml:130", - "comment": "" - }, - { - "term": "Play sound when volume is adjusted", - "context": "Play sound when volume is adjusted", - "reference": "Modules/Settings/SoundsTab.qml:119", - "comment": "" - }, - { - "term": "Play sounds for system events", - "context": "Play sounds for system events", - "reference": "Modules/Settings/SoundsTab.qml:37", - "comment": "" - }, - { - "term": "Playback", - "context": "Playback", - "reference": "Modules/ControlCenter/Details/AudioOutputDetail.qml:375", - "comment": "" - }, - { - "term": "Playback error: ", - "context": "Playback error: ", - "reference": "Modules/Lock/VideoScreensaver.qml:102", - "comment": "" - }, - { - "term": "Please wait...", - "context": "Please wait...", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:333", - "comment": "network status" - }, - { - "term": "Please write a name for your new %1 session", - "context": "Please write a name for your new %1 session", - "reference": "Modals/MuxModal.qml:113", - "comment": "" - }, - { - "term": "Plugged In", - "context": "Plugged In", - "reference": "Services/BatteryService.qml:159, Services/BatteryService.qml:165, Modules/Settings/SoundsTab.qml:129", - "comment": "battery status" - }, - { - "term": "Plugged in", - "context": "Plugged in", - "reference": "Modules/ControlCenter/Widgets/BatteryPill.qml:28", - "comment": "" - }, - { - "term": "Plugin", - "context": "Plugin", - "reference": "Modals/DankLauncherV2/ResultItem.qml:183, Modules/Settings/DesktopWidgetBrowser.qml:408, Modules/ControlCenter/Models/WidgetModel.qml:242", - "comment": "" - }, - { - "term": "Plugin Directory", - "context": "Plugin Directory", - "reference": "Modules/Settings/PluginsTab.qml:257", - "comment": "" - }, - { - "term": "Plugin Management", - "context": "Plugin Management", - "reference": "Modules/Settings/PluginsTab.qml:71", - "comment": "" - }, - { - "term": "Plugin Visibility", - "context": "Plugin Visibility", - "reference": "Modules/Settings/LauncherTab.qml:603", - "comment": "" - }, - { - "term": "Plugin is disabled - enable in Plugins settings to use", - "context": "Plugin is disabled - enable in Plugins settings to use", - "reference": "Modules/Settings/WidgetsTab.qml:269", - "comment": "" - }, - { - "term": "Plugins", - "context": "Plugins", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:122, Modals/Greeter/GreeterCompletePage.qml:476, Modals/DankLauncherV2/LauncherContent.qml:363, Modals/Settings/SettingsSidebar.qml:312, Modules/Settings/AboutTab.qml:290, Modules/Settings/AboutTab.qml:298", - "comment": "greeter feature card title | greeter plugins link" - }, - { - "term": "Pointer", - "context": "Pointer", - "reference": "Widgets/KeybindItem.qml:1340", - "comment": "" - }, - { - "term": "Popout Shadows", - "context": "Popout Shadows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1809", - "comment": "" - }, - { - "term": "Popouts", - "context": "Popouts", - "reference": "Modules/Settings/TypographyMotionTab.qml:300, Modules/Settings/TypographyMotionTab.qml:348", - "comment": "" - }, - { - "term": "Popouts and Modals follow global Animation Speed (disable to customize independently)", - "context": "Popouts and Modals follow global Animation Speed (disable to customize independently)", - "reference": "Modules/Settings/TypographyMotionTab.qml:285", - "comment": "" - }, - { - "term": "Popup Only", - "context": "Popup Only", - "reference": "Modules/Settings/NotificationsTab.qml:131", - "comment": "notification rule action option" - }, - { - "term": "Popup Position", - "context": "Popup Position", - "reference": "Modules/Settings/NotificationsTab.qml:212", - "comment": "" - }, - { - "term": "Popup Shadow", - "context": "Popup Shadow", - "reference": "Modules/Settings/NotificationsTab.qml:279", - "comment": "" - }, - { - "term": "Popup Transparency", - "context": "Popup Transparency", - "reference": "Modules/Settings/ThemeColorsTab.qml:1620", - "comment": "" - }, - { - "term": "Popup behavior, position", - "context": "Popup behavior, position", - "reference": "Modals/Greeter/GreeterCompletePage.qml:398", - "comment": "greeter notifications description" - }, - { - "term": "Port", - "context": "Port", - "reference": "Modules/Settings/PrinterTab.qml:525", - "comment": "Label for printer port number input field" - }, - { - "term": "Portal", - "context": "Portal", - "reference": "Modules/Settings/WallpaperTab.qml:1175", - "comment": "wallpaper transition option" - }, - { - "term": "Position", - "context": "Position", - "reference": "Modules/Settings/DockTab.qml:92, Modules/Settings/DankBarTab.qml:531, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1218", - "comment": "" - }, - { - "term": "Position, pinned apps", - "context": "Position, pinned apps", - "reference": "Modals/Greeter/GreeterCompletePage.qml:423", - "comment": "greeter dock description" - }, - { - "term": "Possible Override Conflicts", - "context": "Possible Override Conflicts", - "reference": "Modules/Settings/KeybindsTab.qml:330", - "comment": "" - }, - { - "term": "Power", - "context": "Power", - "reference": "Modules/Settings/WidgetsTab.qml:253, Modules/ControlCenter/Details/BatteryDetail.qml:72, Modules/DankBar/Popouts/BatteryPopout.qml:191", - "comment": "" - }, - { - "term": "Power & Security", - "context": "Power & Security", - "reference": "Modals/Settings/SettingsSidebar.qml:286, Modals/Settings/SettingsSidebar.qml:569", - "comment": "" - }, - { - "term": "Power & Sleep", - "context": "Power & Sleep", - "reference": "Modals/Settings/SettingsSidebar.qml:304", - "comment": "" - }, - { - "term": "Power Action Confirmation", - "context": "Power Action Confirmation", - "reference": "Modules/Settings/PowerSleepTab.qml:466", - "comment": "" - }, - { - "term": "Power Menu Customization", - "context": "Power Menu Customization", - "reference": "Modules/Settings/PowerSleepTab.qml:353", - "comment": "" - }, - { - "term": "Power Off", - "context": "Power Off", - "reference": "Modals/PowerMenuModal.qml:192, Modules/Lock/LockPowerMenu.qml:116, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Power Options", - "context": "Power Options", - "reference": "Modules/Lock/LockPowerMenu.qml:480", - "comment": "" - }, - { - "term": "Power Profile", - "context": "Power Profile", - "reference": "Modules/Settings/OSDTab.qml:149", - "comment": "" - }, - { - "term": "Power Profile Degradation", - "context": "Power Profile Degradation", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:248, Modules/DankBar/Popouts/BatteryPopout.qml:613", - "comment": "" - }, - { - "term": "Power Saver", - "context": "Power Saver", - "reference": "Common/Theme.qml:1472", - "comment": "power profile option" - }, - { - "term": "Power off monitors on lock", - "context": "Power off monitors on lock", - "reference": "Modules/Settings/LockScreenTab.qml:201", - "comment": "" - }, - { - "term": "Power profile management available", - "context": "Power profile management available", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:106, Modules/DankBar/Popouts/BatteryPopout.qml:176", - "comment": "" - }, - { - "term": "Power source", - "context": "Power source", - "reference": "Modules/Settings/PowerSleepTab.qml:42", - "comment": "" - }, - { - "term": "Pre-fill the last successful username on the greeter", - "context": "Pre-fill the last successful username on the greeter", - "reference": "Modules/Settings/GreeterTab.qml:744", - "comment": "" - }, - { - "term": "Pre-select the last used session on the greeter", - "context": "Pre-select the last used session on the greeter", - "reference": "Modules/Settings/GreeterTab.qml:735", - "comment": "" - }, - { - "term": "Precip", - "context": "Precip", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:441", - "comment": "" - }, - { - "term": "Precipitation", - "context": "Precipitation", - "reference": "Modules/DankDash/WeatherTab.qml:99", - "comment": "" - }, - { - "term": "Precipitation Chance", - "context": "Precipitation Chance", - "reference": "Modules/DankDash/WeatherForecastCard.qml:95", - "comment": "" - }, - { - "term": "Preference", - "context": "Preference", - "reference": "Modules/Settings/NetworkTab.qml:247, Modules/Settings/NetworkTab.qml:292", - "comment": "" - }, - { - "term": "Preset Widths (%)", - "context": "Preset Widths (%)", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:298", - "comment": "" - }, - { - "term": "Press 'n' or click 'New Session' to create one", - "context": "Press 'n' or click 'New Session' to create one", - "reference": "Modals/MuxModal.qml:569", - "comment": "" - }, - { - "term": "Press Enter and the audio system will restart to apply the change", - "context": "Press Enter and the audio system will restart to apply the change", - "reference": "Modules/Settings/AudioTab.qml:657", - "comment": "Audio device rename dialog hint" - }, - { - "term": "Press Enter to paste, Shift+Enter to copy", - "context": "Press Enter to paste, Shift+Enter to copy", - "reference": "Modules/Settings/ClipboardTab.qml:436", - "comment": "Clipboard behavior setting description" - }, - { - "term": "Press key...", - "context": "Press key...", - "reference": "Widgets/KeybindItem.qml:662", - "comment": "" - }, - { - "term": "Pressure", - "context": "Pressure", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:453, Modules/DankDash/WeatherTab.qml:94, Modules/DankDash/WeatherForecastCard.qml:90, Modules/Settings/TimeWeatherTab.qml:1034", - "comment": "" - }, - { - "term": "Prevent screen timeout", - "context": "Prevent screen timeout", - "reference": "Modules/Settings/WidgetsTab.qml:191, Modules/ControlCenter/Models/WidgetModel.qml:94", - "comment": "" - }, - { - "term": "Preview", - "context": "Preview", - "reference": "Modules/Notepad/NotepadTextEditor.qml:824", - "comment": "" - }, - { - "term": "Primary", - "context": "Primary", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:39, Modules/Settings/ThemeColorsTab.qml:1558, Modules/Settings/ThemeColorsTab.qml:1568, Modules/Settings/ThemeColorsTab.qml:1590, Modules/Settings/ThemeColorsTab.qml:1600, Modules/Settings/ThemeColorsTab.qml:1690, Modules/Settings/ThemeColorsTab.qml:1696, Modules/Settings/ThemeColorsTab.qml:1707, Modules/Settings/ThemeColorsTab.qml:1853, Modules/Settings/ThemeColorsTab.qml:1857, Modules/Settings/ThemeColorsTab.qml:1869, Modules/Settings/DockTab.qml:389, Modules/Settings/DockTab.qml:600, Modules/Settings/LauncherTab.qml:181, Modules/Settings/LauncherTab.qml:477, Modules/Settings/WorkspacesTab.qml:369, Modules/Settings/NetworkTab.qml:227, Modules/Settings/DankBarTab.qml:1211, Modules/Settings/Widgets/SettingsColorPicker.qml:42", - "comment": "blur border color | button color option | color option | primary color | shadow color option | tile color option" - }, - { - "term": "Primary Container", - "context": "Primary Container", - "reference": "Modules/Settings/ThemeColorsTab.qml:1558, Modules/Settings/ThemeColorsTab.qml:1562, Modules/Settings/ThemeColorsTab.qml:1572, Modules/Settings/ThemeColorsTab.qml:1590, Modules/Settings/ThemeColorsTab.qml:1594, Modules/Settings/ThemeColorsTab.qml:1604", - "comment": "button color option | tile color option" - }, - { - "term": "Print Server Management", - "context": "Print Server Management", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:198", - "comment": "" - }, - { - "term": "Print Server not available", - "context": "Print Server not available", - "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:22, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:67", - "comment": "" - }, - { - "term": "Printer", - "context": "Printer", - "reference": "Modules/Settings/WidgetsTabSection.qml:1294, Modules/Settings/WidgetsTabSection.qml:1448", - "comment": "" - }, - { - "term": "Printer Classes", - "context": "Printer Classes", - "reference": "Modules/Settings/PrinterTab.qml:1570", - "comment": "" - }, - { - "term": "Printer created successfully", - "context": "Printer created successfully", - "reference": "Services/CupsService.qml:522", - "comment": "" - }, - { - "term": "Printer deleted", - "context": "Printer deleted", - "reference": "Services/CupsService.qml:539", - "comment": "" - }, - { - "term": "Printer name (no spaces)", - "context": "Printer name (no spaces)", - "reference": "Modules/Settings/PrinterTab.qml:764", - "comment": "" - }, - { - "term": "Printer reachable", - "context": "Printer reachable", - "reference": "Modules/Settings/PrinterTab.qml:639", - "comment": "Status message when test connection to printer succeeds" - }, - { - "term": "Printers", - "context": "Printers", - "reference": "Modals/Settings/SettingsSidebar.qml:264, Modules/Settings/PrinterTab.qml:210, Modules/Settings/PrinterTab.qml:869, Modules/ControlCenter/Models/WidgetModel.qml:197, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:16", - "comment": "" - }, - { - "term": "Printers: ", - "context": "Printers: ", - "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:19", - "comment": "" - }, - { - "term": "Prioritize performance", - "context": "Prioritize performance", - "reference": "Common/Theme.qml:1489", - "comment": "power profile description" - }, - { - "term": "Priority", - "context": "Priority", - "reference": "Modules/Settings/NotificationsTab.qml:607", - "comment": "" - }, - { - "term": "Privacy Indicator", - "context": "Privacy Indicator", - "reference": "Modules/Settings/WidgetsTab.qml:155", - "comment": "" - }, - { - "term": "Privacy Mode", - "context": "Privacy Mode", - "reference": "Modules/Settings/NotificationsTab.qml:288, Modules/Notifications/Center/NotificationSettings.qml:308", - "comment": "" - }, - { - "term": "Private Key Password", - "context": "Private Key Password", - "reference": "Modals/WifiPasswordModal.qml:179", - "comment": "" - }, - { - "term": "Process Count", - "context": "Process Count", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:283", - "comment": "" - }, - { - "term": "Processes", - "context": "Processes", - "reference": "Modals/ProcessListModal.qml:307, Modules/ProcessList/ProcessListPopout.qml:140, Modules/ProcessList/SystemView.qml:88", - "comment": "" - }, - { - "term": "Processes:", - "context": "Processes:", - "reference": "Modals/ProcessListModal.qml:491", - "comment": "process count label in footer" - }, - { - "term": "Processing", - "context": "Processing", - "reference": "Services/CupsService.qml:763, Services/CupsService.qml:779", - "comment": "" - }, - { - "term": "Profile Image Error", - "context": "Profile Image Error", - "reference": "Services/PortalService.qml:157", - "comment": "" - }, - { - "term": "Profile activated: %1", - "context": "Profile activated: %1", - "reference": "Modules/Settings/DisplayConfigTab.qml:59", - "comment": "" - }, - { - "term": "Profile deleted", - "context": "Profile deleted", - "reference": "Modules/Settings/DisplayConfigTab.qml:67", - "comment": "" - }, - { - "term": "Profile error", - "context": "Profile error", - "reference": "Modules/Settings/DisplayConfigTab.qml:70", - "comment": "" - }, - { - "term": "Profile image is too large. Please use a smaller image.", - "context": "Profile image is too large. Please use a smaller image.", - "reference": "Services/PortalService.qml:148", - "comment": "" - }, - { - "term": "Profile name", - "context": "Profile name", - "reference": "Modules/Settings/DisplayConfigTab.qml:233", - "comment": "" - }, - { - "term": "Profile not found", - "context": "Profile not found", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:222, Modules/Settings/DisplayConfig/DisplayConfigState.qml:257", - "comment": "" - }, - { - "term": "Profile saved: %1", - "context": "Profile saved: %1", - "reference": "Modules/Settings/DisplayConfigTab.qml:63", - "comment": "" - }, - { - "term": "Protocol", - "context": "Protocol", - "reference": "Widgets/VpnProfileDelegate.qml:63, Modules/Settings/PrinterTab.qml:549, Modules/Settings/NetworkTab.qml:1925", - "comment": "Label for printer protocol selector, e.g. ipp, ipps, lpd, socket" - }, - { - "term": "QtMultimedia is not available", - "context": "QtMultimedia is not available", - "reference": "Modules/Lock/VideoScreensaver.qml:126", - "comment": "" - }, - { - "term": "QtMultimedia is not available - video screensaver requires qt multimedia services", - "context": "QtMultimedia is not available - video screensaver requires qt multimedia services", - "reference": "Modules/Settings/LockScreenTab.qml:272", - "comment": "" - }, - { - "term": "Quick Access", - "context": "Quick Access", - "reference": "Modals/FileBrowser/FileBrowserSidebar.qml:22", - "comment": "" - }, - { - "term": "Quick access to application launcher", - "context": "Quick access to application launcher", - "reference": "Modules/Settings/WidgetsTab.qml:46", - "comment": "" - }, - { - "term": "Quick access to color picker", - "context": "Quick access to color picker", - "reference": "Modules/Settings/WidgetsTab.qml:240", - "comment": "" - }, - { - "term": "Quick access to notepad", - "context": "Quick access to notepad", - "reference": "Modules/Settings/WidgetsTab.qml:233", - "comment": "" - }, - { - "term": "Quick note-taking slideout panel", - "context": "Quick note-taking slideout panel", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:62", - "comment": "" - }, - { - "term": "Quick system toggles", - "context": "Quick system toggles", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:150", - "comment": "greeter feature card description" - }, - { - "term": "RGB", - "context": "RGB", - "reference": "Modals/DankColorPickerModal.qml:627", - "comment": "" - }, - { - "term": "Radius", - "context": "Radius", - "reference": "Modules/Settings/WindowRulesTab.qml:548", - "comment": "" - }, - { - "term": "Rain", - "context": "Rain", - "reference": "Services/WeatherService.qml:134, Services/WeatherService.qml:143", - "comment": "" - }, - { - "term": "Rain Chance", - "context": "Rain Chance", - "reference": "Modules/Settings/TimeWeatherTab.qml:1084", - "comment": "" - }, - { - "term": "Rainbow", - "context": "Rainbow", - "reference": "Common/Theme.qml:499", - "comment": "matugen color scheme option" - }, - { - "term": "Random", - "context": "Random", - "reference": "Modules/Settings/WallpaperTab.qml:1159, Modules/Settings/WallpaperTab.qml:1182, Modules/Settings/WallpaperTab.qml:1185", - "comment": "wallpaper transition option" - }, - { - "term": "Rate", - "context": "Rate", - "reference": "Modules/Settings/NetworkTab.qml:1433", - "comment": "" - }, - { - "term": "Read:", - "context": "Read:", - "reference": "Modules/ProcessList/DisksView.qml:73", - "comment": "disk read label" - }, - { - "term": "Reason", - "context": "Reason", - "reference": "Services/CupsService.qml:355, Modules/Settings/PrinterTab.qml:1154", - "comment": "" - }, - { - "term": "Reboot", - "context": "Reboot", - "reference": "Modals/PowerMenuModal.qml:180, Modules/Lock/LockPowerMenu.qml:104, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Recent Colors", - "context": "Recent Colors", - "reference": "Modals/DankColorPickerModal.qml:468", - "comment": "" - }, - { - "term": "Recently Used Apps", - "context": "Recently Used Apps", - "reference": "Modules/Settings/LauncherTab.qml:1139", - "comment": "" - }, - { - "term": "Recommended available", - "context": "Recommended available", - "reference": "Modules/Settings/PrinterTab.qml:716", - "comment": "" - }, - { - "term": "Refresh", - "context": "Refresh", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:296, Modules/Settings/GreeterTab.qml:504, Modules/DankDash/Overview/WeatherOverviewCard.qml:38", - "comment": "Phone Connect refresh tooltip" - }, - { - "term": "Refresh Weather", - "context": "Refresh Weather", - "reference": "Modules/DankDash/WeatherTab.qml:164, Modules/DankDash/WeatherTab.qml:902", - "comment": "" - }, - { - "term": "Regex", - "context": "Regex", - "reference": "Modules/Settings/NotificationsTab.qml:112", - "comment": "notification rule match type option" - }, - { - "term": "Reject", - "context": "Reject", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:188, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:377", - "comment": "KDE Connect reject pairing button" - }, - { - "term": "Reject Jobs", - "context": "Reject Jobs", - "reference": "Modules/Settings/PrinterTab.qml:1306", - "comment": "" - }, - { - "term": "Release", - "context": "Release", - "reference": "Widgets/KeybindItem.qml:1623", - "comment": "" - }, - { - "term": "Reload Plugin", - "context": "Reload Plugin", - "reference": "Modules/Settings/PluginListItem.qml:301", - "comment": "" - }, - { - "term": "Remaining", - "context": "Remaining", - "reference": "Modules/Settings/WidgetsTabSection.qml:1108", - "comment": "" - }, - { - "term": "Remaining / Total", - "context": "Remaining / Total", - "reference": "Modules/Settings/WidgetsTabSection.qml:1113", - "comment": "" - }, - { - "term": "Remember Last Query", - "context": "Remember Last Query", - "reference": "Modules/Settings/LauncherTab.qml:882", - "comment": "" - }, - { - "term": "Remember last session", - "context": "Remember last session", - "reference": "Modules/Settings/GreeterTab.qml:734", - "comment": "" - }, - { - "term": "Remember last user", - "context": "Remember last user", - "reference": "Modules/Settings/GreeterTab.qml:743", - "comment": "" - }, - { - "term": "Remove", - "context": "Remove", - "reference": "Modules/Plugins/ListSetting.qml:114, Modules/Plugins/ListSettingWithInput.qml:230", - "comment": "" - }, - { - "term": "Remove Widget Padding", - "context": "Remove Widget Padding", - "reference": "Modules/Settings/DankBarTab.qml:1321", - "comment": "" - }, - { - "term": "Remove gaps and border when windows are maximized", - "context": "Remove gaps and border when windows are maximized", - "reference": "Modules/Settings/DankBarTab.qml:709", - "comment": "" - }, - { - "term": "Rename", - "context": "Rename", - "reference": "Modals/MuxModal.qml:597, Modals/WorkspaceRenameModal.qml:185", - "comment": "" - }, - { - "term": "Rename Session", - "context": "Rename Session", - "reference": "Modals/MuxModal.qml:89", - "comment": "" - }, - { - "term": "Rename Workspace", - "context": "Rename Workspace", - "reference": "Modals/WorkspaceRenameModal.qml:15", - "comment": "" - }, - { - "term": "Repeat", - "context": "Repeat", - "reference": "Widgets/KeybindItem.qml:1579, Widgets/KeybindItem.qml:1735", - "comment": "" - }, - { - "term": "Replacement", - "context": "Replacement", - "reference": "Modules/Settings/RunningAppsTab.qml:106", - "comment": "" - }, - { - "term": "Report", - "context": "Report", - "reference": "Services/CupsService.qml:836", - "comment": "" - }, - { - "term": "Request Pairing", - "context": "Request Pairing", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:199", - "comment": "KDE Connect request pairing button" - }, - { - "term": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", - "context": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", - "reference": "Modules/Settings/PowerSleepTab.qml:473", - "comment": "" - }, - { - "term": "Required plugin: ", - "context": "Required plugin: ", - "reference": "Modules/Settings/ThemeColorsTab.qml:2678", - "comment": "" - }, - { - "term": "Requires %1", - "context": "Requires %1", - "reference": "Modules/Settings/PluginBrowser.qml:632", - "comment": "version requirement" - }, - { - "term": "Requires 'dgop' tool", - "context": "Requires 'dgop' tool", - "reference": "Modules/Settings/WidgetsTab.qml:112, Modules/Settings/WidgetsTab.qml:120, Modules/Settings/WidgetsTab.qml:128, Modules/Settings/WidgetsTab.qml:136, Modules/Settings/WidgetsTab.qml:143, Modules/Settings/WidgetsTab.qml:221, Modules/ControlCenter/Models/WidgetModel.qml:174", - "comment": "" - }, - { - "term": "Requires DMS %1", - "context": "Requires DMS %1", - "reference": "Modules/Settings/PluginListItem.qml:133", - "comment": "" - }, - { - "term": "Requires DWL compositor", - "context": "Requires DWL compositor", - "reference": "Modules/Settings/WidgetsTab.qml:41", - "comment": "" - }, - { - "term": "Requires a newer version of Quickshell", - "context": "Requires a newer version of Quickshell", - "reference": "Modules/Settings/ThemeColorsTab.qml:1840", - "comment": "" - }, - { - "term": "Requires night mode support", - "context": "Requires night mode support", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:73", - "comment": "" - }, - { - "term": "Reset", - "context": "Reset", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:1009, Modules/Settings/WidgetsTab.qml:899, Modules/ControlCenter/Components/EditControls.qml:232", - "comment": "" - }, - { - "term": "Reset Position", - "context": "Reset Position", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:416, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:135, Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml:108", - "comment": "" - }, - { - "term": "Reset Size", - "context": "Reset Size", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:430, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:149, Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml:122", - "comment": "" - }, - { - "term": "Reset to default name", - "context": "Reset to default name", - "reference": "Modules/Settings/Widgets/DeviceAliasRow.qml:127", - "comment": "" - }, - { - "term": "Resize Widget", - "context": "Resize Widget", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:687", - "comment": "" - }, - { - "term": "Resolution & Refresh", - "context": "Resolution & Refresh", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:109", - "comment": "" - }, - { - "term": "Resolution, position, scale", - "context": "Resolution, position, scale", - "reference": "Modals/Greeter/GreeterCompletePage.qml:374", - "comment": "greeter displays description" - }, - { - "term": "Restart DMS", - "context": "Restart DMS", - "reference": "Modals/PowerMenuModal.qml:216, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Restart the DankMaterialShell", - "context": "Restart the DankMaterialShell", - "reference": "Modules/Settings/PowerSleepTab.qml:431", - "comment": "" - }, - { - "term": "Restarting audio system...", - "context": "Restarting audio system...", - "reference": "Modules/Settings/AudioTab.qml:503", - "comment": "Loading overlay while WirePlumber restarts" - }, - { - "term": "Restore Special Workspace Windows", - "context": "Restore Special Workspace Windows", - "reference": "Modules/Settings/DockTab.qml:166", - "comment": "" - }, - { - "term": "Resume", - "context": "Resume", - "reference": "Modules/Settings/PrinterTab.qml:1232, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:136", - "comment": "" - }, - { - "term": "Reverse Scrolling Direction", - "context": "Reverse Scrolling Direction", - "reference": "Modules/Settings/WorkspacesTab.qml:161", - "comment": "" - }, - { - "term": "Reverse workspace switch direction when scrolling over the bar", - "context": "Reverse workspace switch direction when scrolling over the bar", - "reference": "Modules/Settings/WorkspacesTab.qml:162", - "comment": "" - }, - { - "term": "Revert", - "context": "Revert", - "reference": "Modals/DisplayConfirmationModal.qml:139", - "comment": "" - }, - { - "term": "Right", - "context": "Right", - "reference": "Modules/Settings/DockTab.qml:102, Modules/Settings/DankBarTab.qml:290, Modules/Settings/DankBarTab.qml:542", - "comment": "" - }, - { - "term": "Right Center", - "context": "Right Center", - "reference": "Modules/Settings/OSDTab.qml:49, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:70", - "comment": "screen position option" - }, - { - "term": "Right Section", - "context": "Right Section", - "reference": "Modules/Settings/WidgetsTab.qml:1087", - "comment": "" - }, - { - "term": "Right Tiling", - "context": "Right Tiling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:51", - "comment": "" - }, - { - "term": "Right-click and drag anywhere on the widget", - "context": "Right-click and drag anywhere on the widget", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:654", - "comment": "" - }, - { - "term": "Right-click and drag the bottom-right corner", - "context": "Right-click and drag the bottom-right corner", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:696", - "comment": "" - }, - { - "term": "Right-click bar widget to cycle", - "context": "Right-click bar widget to cycle", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:292", - "comment": "" - }, - { - "term": "Ring", - "context": "Ring", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:115, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:267", - "comment": "KDE Connect ring tooltip" - }, - { - "term": "Ringing", - "context": "Ringing", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:99, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:272", - "comment": "KDE Connect ring action | Phone Connect ring action" - }, - { - "term": "Ripple Effects", - "context": "Ripple Effects", - "reference": "Modules/Settings/TypographyMotionTab.qml:468", - "comment": "" - }, - { - "term": "Root Filesystem", - "context": "Root Filesystem", - "reference": "Modules/ControlCenter/Details/DiskUsageDetail.qml:128", - "comment": "" - }, - { - "term": "Rounded corners for windows", - "context": "Rounded corners for windows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1960", - "comment": "" - }, - { - "term": "Rounded corners for windows (border_radius)", - "context": "Rounded corners for windows (border_radius)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2166", - "comment": "" - }, - { - "term": "Rounded corners for windows (decoration.rounding)", - "context": "Rounded corners for windows (decoration.rounding)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2063", - "comment": "" - }, - { - "term": "Rule", - "context": "Rule", - "reference": "Modals/WindowRuleModal.qml:254, Modules/Settings/NotificationsTab.qml:468", - "comment": "" - }, - { - "term": "Rule Name", - "context": "Rule Name", - "reference": "Modals/WindowRuleModal.qml:457", - "comment": "" - }, - { - "term": "Rules (%1)", - "context": "Rules (%1)", - "reference": "Modules/Settings/WindowRulesTab.qml:402", - "comment": "" - }, - { - "term": "Run Again", - "context": "Run Again", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:380", - "comment": "greeter doctor page button" - }, - { - "term": "Run DMS Templates", - "context": "Run DMS Templates", - "reference": "Modules/Settings/ThemeColorsTab.qml:2494", - "comment": "" - }, - { - "term": "Run User Templates", - "context": "Run User Templates", - "reference": "Modules/Settings/ThemeColorsTab.qml:2484", - "comment": "" - }, - { - "term": "Run a program (e.g., firefox, kitty)", - "context": "Run a program (e.g., firefox, kitty)", - "reference": "Widgets/KeybindItem.qml:856", - "comment": "" - }, - { - "term": "Run a shell command (e.g., notify-send)", - "context": "Run a shell command (e.g., notify-send)", - "reference": "Widgets/KeybindItem.qml:857", - "comment": "" - }, - { - "term": "Running Apps", - "context": "Running Apps", - "reference": "Modals/Settings/SettingsSidebar.qml:158, Modules/Settings/WidgetsTab.qml:66", - "comment": "" - }, - { - "term": "Running Apps Settings", - "context": "Running Apps Settings", - "reference": "Modules/Settings/WidgetsTabSection.qml:2176", - "comment": "" - }, - { - "term": "Running greeter sync…", - "context": "Running greeter sync…", - "reference": "Modules/Settings/GreeterTab.qml:332", - "comment": "" - }, - { - "term": "SDR Brightness", - "context": "SDR Brightness", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:246, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1252", - "comment": "" - }, - { - "term": "SDR Saturation", - "context": "SDR Saturation", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:279, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1254", - "comment": "" - }, - { - "term": "SMS", - "context": "SMS", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:161, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:338", - "comment": "KDE Connect SMS tooltip" - }, - { - "term": "Save", - "context": "Save", - "reference": "Modals/DankColorPickerModal.qml:757, Widgets/KeybindItem.qml:1365, Widgets/KeybindItem.qml:1830, Modals/DankLauncherV2/LauncherContent.qml:1057, Modals/FileBrowser/FileBrowserSaveRow.qml:55, Modules/Notepad/NotepadTextEditor.qml:774, Modules/Notepad/Notepad.qml:482, Modules/Settings/AudioTab.qml:693", - "comment": "" - }, - { - "term": "Save Notepad File", - "context": "Save Notepad File", - "reference": "Modules/Notepad/Notepad.qml:277", - "comment": "" - }, - { - "term": "Save QR Code", - "context": "Save QR Code", - "reference": "Modals/WifiQRCodeModal.qml:81", - "comment": "" - }, - { - "term": "Save and switch between display configurations", - "context": "Save and switch between display configurations", - "reference": "Modules/Settings/DisplayConfigTab.qml:133", - "comment": "" - }, - { - "term": "Save critical priority notifications to history", - "context": "Save critical priority notifications to history", - "reference": "Modules/Settings/NotificationsTab.qml:893", - "comment": "notification history setting" - }, - { - "term": "Save dismissed notifications to history", - "context": "Save dismissed notifications to history", - "reference": "Modules/Settings/NotificationsTab.qml:810", - "comment": "notification history toggle description" - }, - { - "term": "Save low priority notifications to history", - "context": "Save low priority notifications to history", - "reference": "Modules/Settings/NotificationsTab.qml:875", - "comment": "notification history setting" - }, - { - "term": "Save normal priority notifications to history", - "context": "Save normal priority notifications to history", - "reference": "Modules/Settings/NotificationsTab.qml:884", - "comment": "notification history setting" - }, - { - "term": "Save password", - "context": "Save password", - "reference": "Modals/WifiPasswordModal.qml:664", - "comment": "" - }, - { - "term": "Saved", - "context": "Saved", - "reference": "Modals/Clipboard/ClipboardHeader.qml:52, Modules/Notepad/NotepadTextEditor.qml:880, Modules/Settings/NetworkTab.qml:1214, Modules/ControlCenter/Details/NetworkDetail.qml:615", - "comment": "" - }, - { - "term": "Saved Configurations", - "context": "Saved Configurations", - "reference": "Modules/Settings/NetworkTab.qml:707", - "comment": "" - }, - { - "term": "Saved Note", - "context": "Saved Note", - "reference": "Modules/DankBar/Widgets/NotepadButton.qml:305", - "comment": "" - }, - { - "term": "Saved item deleted", - "context": "Saved item deleted", - "reference": "Services/ClipboardService.qml:177", - "comment": "" - }, - { - "term": "Saving...", - "context": "Saving...", - "reference": "Modals/WindowRuleModal.qml:1154", - "comment": "" - }, - { - "term": "Scale", - "context": "Scale", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:154, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1222", - "comment": "" - }, - { - "term": "Scale DankBar font sizes independently", - "context": "Scale DankBar font sizes independently", - "reference": "Modules/Settings/DankBarTab.qml:952", - "comment": "" - }, - { - "term": "Scale DankBar icon sizes independently", - "context": "Scale DankBar icon sizes independently", - "reference": "Modules/Settings/DankBarTab.qml:977", - "comment": "" - }, - { - "term": "Scale all font sizes throughout the shell", - "context": "Scale all font sizes throughout the shell", - "reference": "Modules/Settings/TypographyMotionTab.qml:184", - "comment": "" - }, - { - "term": "Scan", - "context": "Scan", - "reference": "Modules/Settings/PluginsTab.qml:218, Modules/ControlCenter/Details/BluetoothDetail.qml:134", - "comment": "" - }, - { - "term": "Scanning", - "context": "Scanning", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:134", - "comment": "" - }, - { - "term": "Scanning...", - "context": "Scanning...", - "reference": "Modules/Settings/PrinterTab.qml:439, Modules/Settings/NetworkTab.qml:1069", - "comment": "" - }, - { - "term": "Science", - "context": "Science", - "reference": "Services/AppSearchService.qml:653", - "comment": "" - }, - { - "term": "Score", - "context": "Score", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:698, Modals/DankLauncherV2/LauncherContent.qml:706, Modals/DankLauncherV2/LauncherContent.qml:709, Modals/DankLauncherV2/LauncherContent.qml:713", - "comment": "" - }, - { - "term": "Screen Sharing", - "context": "Screen Sharing", - "reference": "Modules/Settings/WidgetsTabSection.qml:1304, Modules/Settings/WidgetsTabSection.qml:1448", - "comment": "" - }, - { - "term": "Screen sharing", - "context": "Screen sharing", - "reference": "Modules/Settings/WidgetsTabSection.qml:1877", - "comment": "" - }, - { - "term": "Scroll", - "context": "Scroll", - "reference": "Modules/Settings/WindowRulesTab.qml:547", - "comment": "" - }, - { - "term": "Scroll Factor", - "context": "Scroll Factor", - "reference": "Modals/WindowRuleModal.qml:774", - "comment": "" - }, - { - "term": "Scroll GitHub", - "context": "Scroll GitHub", - "reference": "Modules/Settings/AboutTab.qml:75, Modules/Settings/AboutTab.qml:77", - "comment": "" - }, - { - "term": "Scroll Wheel", - "context": "Scroll Wheel", - "reference": "Modules/Settings/MediaPlayerTab.qml:60, Modules/Settings/DankBarTab.qml:719", - "comment": "" - }, - { - "term": "Scroll song title", - "context": "Scroll song title", - "reference": "Modules/Settings/MediaPlayerTab.qml:36", - "comment": "" - }, - { - "term": "Scroll title if it doesn't fit in widget", - "context": "Scroll title if it doesn't fit in widget", - "reference": "Modules/Settings/MediaPlayerTab.qml:37", - "comment": "" - }, - { - "term": "Scroll wheel behavior on media widget", - "context": "Scroll wheel behavior on media widget", - "reference": "Modules/Settings/MediaPlayerTab.qml:61", - "comment": "" - }, - { - "term": "Scrolling", - "context": "Scrolling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:52", - "comment": "" - }, - { - "term": "Search App Actions", - "context": "Search App Actions", - "reference": "Modules/Settings/LauncherTab.qml:873", - "comment": "" - }, - { - "term": "Search Options", - "context": "Search Options", - "reference": "Modules/Settings/LauncherTab.qml:867", - "comment": "" - }, - { - "term": "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.", - "context": "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:217", - "comment": "" - }, - { - "term": "Search for a location...", - "context": "Search for a location...", - "reference": "Widgets/DankLocationSearch.qml:20", - "comment": "" - }, - { - "term": "Search keybinds...", - "context": "Search keybinds...", - "reference": "Modules/Settings/KeybindsTab.qml:259", - "comment": "" - }, - { - "term": "Search keyboard shortcuts from your compositor and applications", - "context": "Search keyboard shortcuts from your compositor and applications", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:78", - "comment": "" - }, - { - "term": "Search plugins...", - "context": "Search plugins...", - "reference": "Modules/Settings/PluginBrowser.qml:345", - "comment": "plugin search placeholder" - }, - { - "term": "Search processes...", - "context": "Search processes...", - "reference": "Modals/ProcessListModal.qml:409", - "comment": "process search placeholder" - }, - { - "term": "Search sessions...", - "context": "Search sessions...", - "reference": "Modals/MuxModal.qml:339", - "comment": "" - }, - { - "term": "Search themes...", - "context": "Search themes...", - "reference": "Modules/Settings/ThemeBrowser.qml:314", - "comment": "theme search placeholder" - }, - { - "term": "Search widgets...", - "context": "Search widgets...", - "reference": "Modules/Settings/WidgetSelectionPopup.qml:271, Modules/Settings/DesktopWidgetBrowser.qml:287", - "comment": "" - }, - { - "term": "Search...", - "context": "Search...", - "reference": "Widgets/DankDropdown.qml:315, Modals/Settings/SettingsSidebar.qml:641, Modules/ProcessList/ProcessListPopout.qml:185", - "comment": "" - }, - { - "term": "Searching...", - "context": "Searching...", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:140, dms-plugins/DankGifSearch/DankGifSearch.qml:83", - "comment": "" - }, - { - "term": "Second Factor (AND)", - "context": "Second Factor (AND)", - "reference": "Modules/Settings/LockScreenTab.qml:253, Modules/Settings/LockScreenTab.qml:254, Modules/Settings/LockScreenTab.qml:256", - "comment": "U2F mode option: key required after password or fingerprint" - }, - { - "term": "Secondary", - "context": "Secondary", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:43, Modules/Settings/ThemeColorsTab.qml:1558, Modules/Settings/ThemeColorsTab.qml:1564, Modules/Settings/ThemeColorsTab.qml:1574, Modules/Settings/ThemeColorsTab.qml:1590, Modules/Settings/ThemeColorsTab.qml:1596, Modules/Settings/ThemeColorsTab.qml:1606, Modules/Settings/ThemeColorsTab.qml:1853, Modules/Settings/ThemeColorsTab.qml:1859, Modules/Settings/ThemeColorsTab.qml:1871, Modules/Settings/DockTab.qml:600, Modules/Settings/LauncherTab.qml:477, Modules/Settings/WorkspacesTab.qml:369, Modules/Settings/DankBarTab.qml:1211, Modules/Settings/Widgets/SettingsColorPicker.qml:47", - "comment": "blur border color | button color option | color option | secondary color | tile color option" - }, - { - "term": "Secured", - "context": "Secured", - "reference": "Modules/Settings/NetworkTab.qml:1201, Modules/ControlCenter/Details/NetworkDetail.qml:609", - "comment": "" - }, - { - "term": "Security", - "context": "Security", - "reference": "Modules/Settings/NetworkTab.qml:1447", - "comment": "" - }, - { - "term": "Security & privacy", - "context": "Security & privacy", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:159", - "comment": "greeter feature card description" - }, - { - "term": "Security key mode", - "context": "Security key mode", - "reference": "Modules/Settings/LockScreenTab.qml:250", - "comment": "lock screen U2F security key mode setting" - }, - { - "term": "Security-key availability could not be confirmed.", - "context": "Security-key availability could not be confirmed.", - "reference": "Modules/Settings/GreeterTab.qml:71, Modules/Settings/LockScreenTab.qml:43", - "comment": "" - }, - { - "term": "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", - "context": "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", - "reference": "Modules/Settings/GreeterTab.qml:67, Modules/Settings/LockScreenTab.qml:39", - "comment": "" - }, - { - "term": "Select", - "context": "Select", - "reference": "Modals/DankLauncherV2/Controller.qml:1380", - "comment": "" - }, - { - "term": "Select Application", - "context": "Select Application", - "reference": "Modals/AppPickerModal.qml:11", - "comment": "" - }, - { - "term": "Select Bar", - "context": "Select Bar", - "reference": "Modules/Settings/WidgetsTab.qml:814", - "comment": "" - }, - { - "term": "Select Custom Theme", - "context": "Select Custom Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:2985", - "comment": "custom theme file browser title" - }, - { - "term": "Select Dock Launcher Logo", - "context": "Select Dock Launcher Logo", - "reference": "Modules/Settings/DockTab.qml:13", - "comment": "" - }, - { - "term": "Select File to Send", - "context": "Select File to Send", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:101", - "comment": "KDE Connect file browser title" - }, - { - "term": "Select Launcher Logo", - "context": "Select Launcher Logo", - "reference": "Modules/Settings/LauncherTab.qml:13", - "comment": "" - }, - { - "term": "Select Profile Image", - "context": "Select Profile Image", - "reference": "Modals/Settings/SettingsModal.qml:127", - "comment": "profile image file browser title" - }, - { - "term": "Select Video or Folder", - "context": "Select Video or Folder", - "reference": "Modules/Settings/LockScreenTab.qml:59", - "comment": "" - }, - { - "term": "Select Wallpaper", - "context": "Select Wallpaper", - "reference": "Modals/Settings/SettingsModal.qml:151, Modules/Settings/WallpaperTab.qml:1313, Modules/Settings/WallpaperTab.qml:1335, Modules/Settings/WallpaperTab.qml:1355", - "comment": "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title" - }, - { - "term": "Select Wallpaper Directory", - "context": "Select Wallpaper Directory", - "reference": "Modules/DankDash/WallpaperTab.qml:320", - "comment": "wallpaper directory file browser title" - }, - { - "term": "Select a color from the palette or use custom sliders", - "context": "Select a color from the palette or use custom sliders", - "reference": "Modals/DankColorPickerModal.qml:223", - "comment": "" - }, - { - "term": "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.", - "context": "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.", - "reference": "Modules/Settings/DesktopWidgetBrowser.qml:265", - "comment": "" - }, - { - "term": "Select a widget to add. You can add multiple instances of the same widget if needed.", - "context": "Select a widget to add. You can add multiple instances of the same widget if needed.", - "reference": "Modules/Settings/WidgetSelectionPopup.qml:249", - "comment": "" - }, - { - "term": "Select a window...", - "context": "Select a window...", - "reference": "Modules/Settings/WindowRulesTab.qml:291", - "comment": "" - }, - { - "term": "Select an image file...", - "context": "Select an image file...", - "reference": "Modules/Settings/DockTab.qml:340, Modules/Settings/LauncherTab.qml:132", - "comment": "" - }, - { - "term": "Select at least one provider", - "context": "Select at least one provider", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:178", - "comment": "" - }, - { - "term": "Select device", - "context": "Select device", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:373, Modules/ControlCenter/Components/DragDropGrid.qml:384", - "comment": "audio status" - }, - { - "term": "Select device...", - "context": "Select device...", - "reference": "Modules/Settings/PrinterTab.qml:442", - "comment": "" - }, - { - "term": "Select driver...", - "context": "Select driver...", - "reference": "Modules/Settings/PrinterTab.qml:716", - "comment": "" - }, - { - "term": "Select font weight for UI text", - "context": "Select font weight for UI text", - "reference": "Modules/Settings/TypographyMotionTab.qml:115", - "comment": "" - }, - { - "term": "Select greeter background image", - "context": "Select greeter background image", - "reference": "Modules/Settings/GreeterTab.qml:90", - "comment": "" - }, - { - "term": "Select monitor to configure wallpaper", - "context": "Select monitor to configure wallpaper", - "reference": "Modules/Settings/WallpaperTab.qml:820", - "comment": "" - }, - { - "term": "Select monospace font for process list and technical displays", - "context": "Select monospace font for process list and technical displays", - "reference": "Modules/Settings/TypographyMotionTab.qml:89", - "comment": "" - }, - { - "term": "Select network", - "context": "Select network", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:347", - "comment": "network status" - }, - { - "term": "Select system sound theme", - "context": "Select system sound theme", - "reference": "Modules/Settings/SoundsTab.qml:72", - "comment": "" - }, - { - "term": "Select the font family for UI text", - "context": "Select the font family for UI text", - "reference": "Modules/Settings/TypographyMotionTab.qml:70", - "comment": "" - }, - { - "term": "Select the palette algorithm used for wallpaper-based colors", - "context": "Select the palette algorithm used for wallpaper-based colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:505", - "comment": "" - }, - { - "term": "Select which keybind providers to include", - "context": "Select which keybind providers to include", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:151", - "comment": "" - }, - { - "term": "Select which transitions to include in randomization", - "context": "Select which transitions to include in randomization", - "reference": "Modules/Settings/WallpaperTab.qml:1208", - "comment": "" - }, - { - "term": "Select...", - "context": "Select...", - "reference": "Widgets/KeybindItem.qml:951, Widgets/KeybindItem.qml:1165, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:95, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:97, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:114", - "comment": "" - }, - { - "term": "Selected image file not found.", - "context": "Selected image file not found.", - "reference": "Services/PortalService.qml:152", - "comment": "" - }, - { - "term": "Send", - "context": "Send", - "reference": "dms-plugins/DankKDEConnect/components/SmsDialog.qml:80", - "comment": "KDE Connect SMS send button" - }, - { - "term": "Send Clipboard", - "context": "Send Clipboard", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:133, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:295", - "comment": "KDE Connect clipboard tooltip" - }, - { - "term": "Send File", - "context": "Send File", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:91", - "comment": "KDE Connect send file button" - }, - { - "term": "Send SMS", - "context": "Send SMS", - "reference": "dms-plugins/DankKDEConnect/components/SmsDialog.qml:28", - "comment": "KDE Connect SMS dialog title" - }, - { - "term": "Sending", - "context": "Sending", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:365, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:424", - "comment": "Phone Connect file send" - }, - { - "term": "Separator", - "context": "Separator", - "reference": "Modules/Settings/WidgetsTab.qml:211", - "comment": "" - }, - { - "term": "Server", - "context": "Server", - "reference": "Widgets/VpnProfileDelegate.qml:39, Modules/Settings/NetworkTab.qml:1905", - "comment": "" - }, - { - "term": "Session Filter", - "context": "Session Filter", - "reference": "Modules/Settings/MuxTab.qml:87", - "comment": "" - }, - { - "term": "Set Custom Device Name", - "context": "Set Custom Device Name", - "reference": "Modules/Settings/AudioTab.qml:580", - "comment": "Audio device rename dialog title" - }, - { - "term": "Set custom name", - "context": "Set custom name", - "reference": "Modules/Settings/Widgets/DeviceAliasRow.qml:156", - "comment": "" - }, - { - "term": "Set custom names for your audio input devices", - "context": "Set custom names for your audio input devices", - "reference": "Modules/Settings/AudioTab.qml:329", - "comment": "Audio settings description" - }, - { - "term": "Set custom names for your audio output devices", - "context": "Set custom names for your audio output devices", - "reference": "Modules/Settings/AudioTab.qml:138", - "comment": "Audio settings description" - }, - { - "term": "Set different wallpapers for each connected monitor", - "context": "Set different wallpapers for each connected monitor", - "reference": "Modules/Settings/WallpaperTab.qml:802", - "comment": "" - }, - { - "term": "Set different wallpapers for light and dark mode", - "context": "Set different wallpapers for light and dark mode", - "reference": "Modules/Settings/WallpaperTab.qml:371", - "comment": "" - }, - { - "term": "Set key and action to save", - "context": "Set key and action to save", - "reference": "Widgets/KeybindItem.qml:1807", - "comment": "" - }, - { - "term": "Set notification rules", - "context": "Set notification rules", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:1088, Modules/Notifications/Center/NotificationCard.qml:990", - "comment": "" - }, - { - "term": "Settings", - "context": "Settings", - "reference": "Services/AppSearchService.qml:168, Services/AppSearchService.qml:212, Services/AppSearchService.qml:654, Services/PopoutService.qml:405, Services/PopoutService.qml:422, Modals/Settings/SettingsSidebar.qml:114, Modals/Settings/SettingsModal.qml:82, Modals/Settings/SettingsModal.qml:222, Modules/DankDash/DankDashPopout.qml:292", - "comment": "settings window title" - }, - { - "term": "Settings are read-only. Changes will not persist.", - "context": "Settings are read-only. Changes will not persist.", - "reference": "Modals/Settings/SettingsModal.qml:294", - "comment": "read-only settings warning for NixOS home-manager users" - }, - { - "term": "Setup", - "context": "Setup", - "reference": "Modules/Settings/ThemeColorsTab.qml:2317, Modules/Settings/WindowRulesTab.qml:367, Modules/Settings/KeybindsTab.qml:370, Modules/Settings/DisplayConfig/IncludeWarningBox.qml:83", - "comment": "" - }, - { - "term": "Shadow Color", - "context": "Shadow Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:139, Modules/Settings/ThemeColorsTab.qml:1688", - "comment": "" - }, - { - "term": "Shadow Intensity", - "context": "Shadow Intensity", - "reference": "Modules/Settings/ThemeColorsTab.qml:1658", - "comment": "" - }, - { - "term": "Shadow Opacity", - "context": "Shadow Opacity", - "reference": "Modules/Settings/ThemeColorsTab.qml:1673", - "comment": "" - }, - { - "term": "Shadow Override", - "context": "Shadow Override", - "reference": "Modules/Settings/DankBarTab.qml:1052", - "comment": "bar shadow settings card" - }, - { - "term": "Shadow elevation on bars and panels", - "context": "Shadow elevation on bars and panels", - "reference": "Modules/Settings/ThemeColorsTab.qml:1821", - "comment": "" - }, - { - "term": "Shadow elevation on modals and dialogs", - "context": "Shadow elevation on modals and dialogs", - "reference": "Modules/Settings/ThemeColorsTab.qml:1799", - "comment": "" - }, - { - "term": "Shadow elevation on popouts, OSDs, and dropdowns", - "context": "Shadow elevation on popouts, OSDs, and dropdowns", - "reference": "Modules/Settings/ThemeColorsTab.qml:1810", - "comment": "" - }, - { - "term": "Shadows", - "context": "Shadows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1648", - "comment": "" - }, - { - "term": "Share", - "context": "Share", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:34, dms-plugins/DankKDEConnect/components/DeviceCard.qml:142, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:309", - "comment": "KDE Connect share dialog title | KDE Connect share tooltip" - }, - { - "term": "Share Gamma Control Settings", - "context": "Share Gamma Control Settings", - "reference": "Modules/Settings/ThemeColorsTab.qml:1076", - "comment": "" - }, - { - "term": "Share Text", - "context": "Share Text", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:81", - "comment": "KDE Connect share button" - }, - { - "term": "Share URL", - "context": "Share URL", - "reference": "dms-plugins/DankKDEConnect/components/ShareDialog.qml:81", - "comment": "KDE Connect share URL button" - }, - { - "term": "Shared", - "context": "Shared", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:344, dms-plugins/DankKDEConnect/DankKDEConnect.qml:352, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:410", - "comment": "Phone Connect share success" - }, - { - "term": "Shell", - "context": "Shell", - "reference": "Widgets/KeybindItem.qml:1498", - "comment": "" - }, - { - "term": "Shift+Del: Clear All • Esc: Close", - "context": "Shift+Del: Clear All • Esc: Close", - "reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:12", - "comment": "" - }, - { - "term": "Shift+Enter to paste", - "context": "Shift+Enter to paste", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:176, dms-plugins/DankGifSearch/DankGifSearch.qml:119", - "comment": "" - }, - { - "term": "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close", - "context": "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close", - "reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:13", - "comment": "Keyboard hints when enter-to-paste is enabled" - }, - { - "term": "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close", - "context": "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close", - "reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:13", - "comment": "" - }, - { - "term": "Short", - "context": "Short", - "reference": "Modules/Settings/TypographyMotionTab.qml:212, Modules/Settings/TypographyMotionTab.qml:315, Modules/Settings/TypographyMotionTab.qml:399, Modules/Settings/NotificationsTab.qml:337", - "comment": "" - }, - { - "term": "Shortcut (%1)", - "context": "Shortcut (%1)", - "reference": "Modules/Settings/KeybindsTab.qml:550", - "comment": "" - }, - { - "term": "Shortcuts", - "context": "Shortcuts", - "reference": "Modules/Settings/KeybindsTab.qml:547", - "comment": "" - }, - { - "term": "Shortcuts (%1)", - "context": "Shortcuts (%1)", - "reference": "Modules/Settings/KeybindsTab.qml:551", - "comment": "" - }, - { - "term": "Show", - "context": "Show", - "reference": "Modules/Settings/DisplayConfigTab.qml:473", - "comment": "" - }, - { - "term": "Show 3rd Party", - "context": "Show 3rd Party", - "reference": "Modules/Settings/PluginBrowser.qml:273", - "comment": "" - }, - { - "term": "Show All Tags", - "context": "Show All Tags", - "reference": "Modules/Settings/WorkspacesTab.qml:181", - "comment": "" - }, - { - "term": "Show Badge", - "context": "Show Badge", - "reference": "Modules/Settings/WidgetsTabSection.qml:2580", - "comment": "" - }, - { - "term": "Show CPU", - "context": "Show CPU", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:177", - "comment": "" - }, - { - "term": "Show CPU Graph", - "context": "Show CPU Graph", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:185", - "comment": "" - }, - { - "term": "Show CPU Temp", - "context": "Show CPU Temp", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:194", - "comment": "" - }, - { - "term": "Show Date", - "context": "Show Date", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:90, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:33", - "comment": "" - }, - { - "term": "Show Disk", - "context": "Show Disk", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:252", - "comment": "" - }, - { - "term": "Show Dock", - "context": "Show Dock", - "reference": "Modules/Settings/DockTab.qml:42", - "comment": "" - }, - { - "term": "Show Feels Like Temperature", - "context": "Show Feels Like Temperature", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:84", - "comment": "" - }, - { - "term": "Show Footer", - "context": "Show Footer", - "reference": "Modules/Settings/LauncherTab.qml:413", - "comment": "launcher footer visibility" - }, - { - "term": "Show Forecast", - "context": "Show Forecast", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:120", - "comment": "" - }, - { - "term": "Show GPU Temperature", - "context": "Show GPU Temperature", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:262", - "comment": "" - }, - { - "term": "Show Header", - "context": "Show Header", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:29, Modules/Settings/Widgets/SystemMonitorVariantCard.qml:167", - "comment": "" - }, - { - "term": "Show Hibernate", - "context": "Show Hibernate", - "reference": "Modules/Settings/PowerSleepTab.qml:435", - "comment": "" - }, - { - "term": "Show Hour Numbers", - "context": "Show Hour Numbers", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:60", - "comment": "" - }, - { - "term": "Show Hourly Forecast", - "context": "Show Hourly Forecast", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:135", - "comment": "" - }, - { - "term": "Show Humidity", - "context": "Show Humidity", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:90", - "comment": "" - }, - { - "term": "Show Launcher Button", - "context": "Show Launcher Button", - "reference": "Modules/Settings/DockTab.qml:232", - "comment": "" - }, - { - "term": "Show Line Numbers", - "context": "Show Line Numbers", - "reference": "Modules/Notepad/NotepadSettings.qml:142", - "comment": "" - }, - { - "term": "Show Location", - "context": "Show Location", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:72", - "comment": "" - }, - { - "term": "Show Lock", - "context": "Show Lock", - "reference": "Modules/Settings/PowerSleepTab.qml:422", - "comment": "" - }, - { - "term": "Show Log Out", - "context": "Show Log Out", - "reference": "Modules/Settings/PowerSleepTab.qml:414", - "comment": "" - }, - { - "term": "Show Material Design ripple animations on interactive elements", - "context": "Show Material Design ripple animations on interactive elements", - "reference": "Modules/Settings/TypographyMotionTab.qml:477", - "comment": "" - }, - { - "term": "Show Media Player", - "context": "Show Media Player", - "reference": "Modules/Settings/LockScreenTab.qml:138", - "comment": "Enable media player controls on the lock screen window" - }, - { - "term": "Show Memory", - "context": "Show Memory", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:205", - "comment": "" - }, - { - "term": "Show Memory Graph", - "context": "Show Memory Graph", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:213", - "comment": "" - }, - { - "term": "Show Memory in GB", - "context": "Show Memory in GB", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:222", - "comment": "" - }, - { - "term": "Show Network", - "context": "Show Network", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:233", - "comment": "" - }, - { - "term": "Show Network Graph", - "context": "Show Network Graph", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:241", - "comment": "" - }, - { - "term": "Show Occupied Workspaces Only", - "context": "Show Occupied Workspaces Only", - "reference": "Modules/Settings/WorkspacesTab.qml:151", - "comment": "" - }, - { - "term": "Show Overflow Badge Count", - "context": "Show Overflow Badge Count", - "reference": "Modules/Settings/DockTab.qml:216", - "comment": "" - }, - { - "term": "Show Password Field", - "context": "Show Password Field", - "reference": "Modules/Settings/LockScreenTab.qml:129", - "comment": "Enable password field display on the lock screen window" - }, - { - "term": "Show Power Actions", - "context": "Show Power Actions", - "reference": "Modules/Settings/LockScreenTab.qml:89", - "comment": "Enable power action icon on the lock screen window" - }, - { - "term": "Show Power Off", - "context": "Show Power Off", - "reference": "Modules/Settings/PowerSleepTab.qml:418", - "comment": "" - }, - { - "term": "Show Precipitation Probability", - "context": "Show Precipitation Probability", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:108", - "comment": "" - }, - { - "term": "Show Pressure", - "context": "Show Pressure", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:102", - "comment": "" - }, - { - "term": "Show Profile Image", - "context": "Show Profile Image", - "reference": "Modules/Settings/LockScreenTab.qml:121", - "comment": "Enable profile image display on the lock screen window" - }, - { - "term": "Show Reboot", - "context": "Show Reboot", - "reference": "Modules/Settings/PowerSleepTab.qml:410", - "comment": "" - }, - { - "term": "Show Restart DMS", - "context": "Show Restart DMS", - "reference": "Modules/Settings/PowerSleepTab.qml:430", - "comment": "" - }, - { - "term": "Show Saved Items", - "context": "Show Saved Items", - "reference": "Modules/DankBar/Widgets/ClipboardButton.qml:294", - "comment": "" - }, - { - "term": "Show Seconds", - "context": "Show Seconds", - "reference": "Modules/Settings/TimeWeatherTab.qml:63, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:71, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:82, PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml:27", - "comment": "" - }, - { - "term": "Show Sunrise/Sunset", - "context": "Show Sunrise/Sunset", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:114", - "comment": "" - }, - { - "term": "Show Suspend", - "context": "Show Suspend", - "reference": "Modules/Settings/PowerSleepTab.qml:426", - "comment": "" - }, - { - "term": "Show Swap", - "context": "Show Swap", - "reference": "Modules/Settings/WidgetsTabSection.qml:878", - "comment": "" - }, - { - "term": "Show System Date", - "context": "Show System Date", - "reference": "Modules/Settings/LockScreenTab.qml:113", - "comment": "Enable system date display on the lock screen window" - }, - { - "term": "Show System Icons", - "context": "Show System Icons", - "reference": "Modules/Settings/LockScreenTab.qml:97", - "comment": "Enable system status icons on the lock screen window" - }, - { - "term": "Show System Time", - "context": "Show System Time", - "reference": "Modules/Settings/LockScreenTab.qml:105", - "comment": "Enable system time display on the lock screen window" - }, - { - "term": "Show Top Processes", - "context": "Show Top Processes", - "reference": "Modules/Settings/Widgets/SystemMonitorVariantCard.qml:332", - "comment": "" - }, - { - "term": "Show Weather Condition", - "context": "Show Weather Condition", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:78", - "comment": "" - }, - { - "term": "Show Week Number", - "context": "Show Week Number", - "reference": "Modules/Settings/TimeWeatherTab.qml:92", - "comment": "" - }, - { - "term": "Show Welcome", - "context": "Show Welcome", - "reference": "Modules/Settings/AboutTab.qml:806", - "comment": "" - }, - { - "term": "Show Wind Speed", - "context": "Show Wind Speed", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:96", - "comment": "" - }, - { - "term": "Show Workspace Apps", - "context": "Show Workspace Apps", - "reference": "Modules/Settings/WorkspacesTab.qml:59", - "comment": "" - }, - { - "term": "Show all 9 tags instead of only occupied tags (DWL only)", - "context": "Show all 9 tags instead of only occupied tags (DWL only)", - "reference": "Modules/Settings/WorkspacesTab.qml:182", - "comment": "" - }, - { - "term": "Show an outline ring around the focused workspace indicator", - "context": "Show an outline ring around the focused workspace indicator", - "reference": "Modules/Settings/WorkspacesTab.qml:355", - "comment": "" - }, - { - "term": "Show cava audio visualizer in media widget", - "context": "Show cava audio visualizer in media widget", - "reference": "Modules/Settings/MediaPlayerTab.qml:44", - "comment": "" - }, - { - "term": "Show darkened overlay behind modal dialogs", - "context": "Show darkened overlay behind modal dialogs", - "reference": "Modules/Settings/ThemeColorsTab.qml:2220", - "comment": "" - }, - { - "term": "Show device", - "context": "Show device", - "reference": "Modules/Settings/Widgets/DeviceAliasRow.qml:142", - "comment": "" - }, - { - "term": "Show dock when floating windows don't overlap its area", - "context": "Show dock when floating windows don't overlap its area", - "reference": "Modules/Settings/DockTab.qml:67", - "comment": "" - }, - { - "term": "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.", - "context": "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.", - "reference": "Modules/Settings/NotificationsTab.qml:280", - "comment": "" - }, - { - "term": "Show in GB", - "context": "Show in GB", - "reference": "Modules/Settings/WidgetsTabSection.qml:931", - "comment": "" - }, - { - "term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.", - "context": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.", - "reference": "Modules/Settings/LauncherTab.qml:509", - "comment": "" - }, - { - "term": "Show mode tabs and keyboard hints at the bottom.", - "context": "Show mode tabs and keyboard hints at the bottom.", - "reference": "Modules/Settings/LauncherTab.qml:414", - "comment": "launcher footer description" - }, - { - "term": "Show notification popups only on the currently focused monitor", - "context": "Show notification popups only on the currently focused monitor", - "reference": "Modules/Settings/NotificationsTab.qml:298", - "comment": "" - }, - { - "term": "Show notifications only on the currently focused monitor", - "context": "Show notifications only on the currently focused monitor", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:423", - "comment": "" - }, - { - "term": "Show on Last Display", - "context": "Show on Last Display", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:431, Modules/Settings/DankBarTab.qml:462", - "comment": "" - }, - { - "term": "Show on Overlay", - "context": "Show on Overlay", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:295", - "comment": "" - }, - { - "term": "Show on Overview", - "context": "Show on Overview", - "reference": "Modules/Settings/DockTab.qml:81, Modules/Settings/DesktopWidgetInstanceCard.qml:312, Modules/Settings/DankBarTab.qml:696", - "comment": "" - }, - { - "term": "Show on Overview Only", - "context": "Show on Overview Only", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:329", - "comment": "" - }, - { - "term": "Show on all connected displays", - "context": "Show on all connected displays", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:402", - "comment": "" - }, - { - "term": "Show on screens:", - "context": "Show on screens:", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:385", - "comment": "" - }, - { - "term": "Show on-screen display when brightness changes", - "context": "Show on-screen display when brightness changes", - "reference": "Modules/Settings/OSDTab.qml:118", - "comment": "" - }, - { - "term": "Show on-screen display when caps lock state changes", - "context": "Show on-screen display when caps lock state changes", - "reference": "Modules/Settings/OSDTab.qml:142", - "comment": "" - }, - { - "term": "Show on-screen display when cycling audio output devices", - "context": "Show on-screen display when cycling audio output devices", - "reference": "Modules/Settings/OSDTab.qml:158", - "comment": "" - }, - { - "term": "Show on-screen display when idle inhibitor state changes", - "context": "Show on-screen display when idle inhibitor state changes", - "reference": "Modules/Settings/OSDTab.qml:126", - "comment": "" - }, - { - "term": "Show on-screen display when media player status changes", - "context": "Show on-screen display when media player status changes", - "reference": "Modules/Settings/OSDTab.qml:110", - "comment": "" - }, - { - "term": "Show on-screen display when media player volume changes", - "context": "Show on-screen display when media player volume changes", - "reference": "Modules/Settings/OSDTab.qml:102", - "comment": "" - }, - { - "term": "Show on-screen display when microphone is muted/unmuted", - "context": "Show on-screen display when microphone is muted/unmuted", - "reference": "Modules/Settings/OSDTab.qml:134", - "comment": "" - }, - { - "term": "Show on-screen display when power profile changes", - "context": "Show on-screen display when power profile changes", - "reference": "Modules/Settings/OSDTab.qml:150", - "comment": "" - }, - { - "term": "Show on-screen display when volume changes", - "context": "Show on-screen display when volume changes", - "reference": "Modules/Settings/OSDTab.qml:94", - "comment": "" - }, - { - "term": "Show seconds", - "context": "Show seconds", - "reference": "Modules/Settings/GreeterTab.qml:610", - "comment": "" - }, - { - "term": "Show weather information in top bar and control center", - "context": "Show weather information in top bar and control center", - "reference": "Modules/Settings/TimeWeatherTab.qml:401", - "comment": "" - }, - { - "term": "Show week number in the calendar", - "context": "Show week number in the calendar", - "reference": "Modules/Settings/TimeWeatherTab.qml:93", - "comment": "" - }, - { - "term": "Show workspace index numbers in the top bar workspace switcher", - "context": "Show workspace index numbers in the top bar workspace switcher", - "reference": "Modules/Settings/WorkspacesTab.qml:33", - "comment": "" - }, - { - "term": "Show workspace name on horizontal bars, and first letter on vertical bars", - "context": "Show workspace name on horizontal bars, and first letter on vertical bars", - "reference": "Modules/Settings/WorkspacesTab.qml:42", - "comment": "" - }, - { - "term": "Show workspaces of the currently focused monitor", - "context": "Show workspaces of the currently focused monitor", - "reference": "Modules/Settings/WorkspacesTab.qml:142", - "comment": "" - }, - { - "term": "Shows all running applications with focus indication", - "context": "Shows all running applications with focus indication", - "reference": "Modules/Settings/WidgetsTab.qml:67", - "comment": "" - }, - { - "term": "Shows current workspace and allows switching", - "context": "Shows current workspace and allows switching", - "reference": "Modules/Settings/WidgetsTab.qml:53", - "comment": "" - }, - { - "term": "Shows when caps lock is active", - "context": "Shows when caps lock is active", - "reference": "Modules/Settings/WidgetsTab.qml:198", - "comment": "" - }, - { - "term": "Shows when microphone, camera, or screen sharing is active", - "context": "Shows when microphone, camera, or screen sharing is active", - "reference": "Modules/Settings/WidgetsTab.qml:156", - "comment": "" - }, - { - "term": "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size", - "context": "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size", - "reference": "Modules/Settings/MediaPlayerTab.qml:51", - "comment": "" - }, - { - "term": "Shutdown", - "context": "Shutdown", - "reference": "Services/CupsService.qml:815", - "comment": "" - }, - { - "term": "Signal", - "context": "Signal", - "reference": "Modules/Settings/NetworkTab.qml:1418", - "comment": "" - }, - { - "term": "Signal:", - "context": "Signal:", - "reference": "Modules/Settings/NetworkTab.qml:965", - "comment": "" - }, - { - "term": "Size", - "context": "Size", - "reference": "Modals/WindowRuleModal.qml:989, Modals/DankLauncherV2/LauncherContent.qml:704, Modals/DankLauncherV2/LauncherContent.qml:709, Modals/DankLauncherV2/LauncherContent.qml:716, Modules/Settings/LauncherTab.qml:369, Modules/Settings/DankBarTab.qml:851, Modules/Settings/WindowRulesTab.qml:565", - "comment": "launcher size option" - }, - { - "term": "Size Constraints", - "context": "Size Constraints", - "reference": "Modals/WindowRuleModal.qml:811", - "comment": "" - }, - { - "term": "Size Offset", - "context": "Size Offset", - "reference": "Modules/Settings/DockTab.qml:465, Modules/Settings/LauncherTab.qml:257", - "comment": "" - }, - { - "term": "Sizing", - "context": "Sizing", - "reference": "Modules/Settings/DockTab.qml:512", - "comment": "" - }, - { - "term": "Skip", - "context": "Skip", - "reference": "Modals/Greeter/GreeterModal.qml:277", - "comment": "greeter skip button" - }, - { - "term": "Skip confirmation", - "context": "Skip confirmation", - "reference": "Widgets/KeybindItem.qml:1389", - "comment": "" - }, - { - "term": "Skip setup", - "context": "Skip setup", - "reference": "Modals/Greeter/GreeterModal.qml:231", - "comment": "greeter skip button tooltip" - }, - { - "term": "Small", - "context": "Small", - "reference": "Modules/Settings/WidgetsTabSection.qml:2053", - "comment": "" - }, - { - "term": "Smartcard Authentication", - "context": "Smartcard Authentication", - "reference": "Modals/WifiPasswordModal.qml:332", - "comment": "" - }, - { - "term": "Smartcard PIN", - "context": "Smartcard PIN", - "reference": "Modals/WifiPasswordModal.qml:248", - "comment": "" - }, - { - "term": "Snap", - "context": "Snap", - "reference": "Modules/Settings/DisplayConfigTab.qml:389", - "comment": "" - }, - { - "term": "Snow", - "context": "Snow", - "reference": "Services/WeatherService.qml:139, Services/WeatherService.qml:141", - "comment": "" - }, - { - "term": "Some plugins require a newer version of DMS:", - "context": "Some plugins require a newer version of DMS:", - "reference": "Modules/Settings/PluginsTab.qml:177", - "comment": "" - }, - { - "term": "Sort Alphabetically", - "context": "Sort Alphabetically", - "reference": "Modules/Settings/LauncherTab.qml:339", - "comment": "" - }, - { - "term": "Sort By", - "context": "Sort By", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:323", - "comment": "" - }, - { - "term": "Sorting & Layout", - "context": "Sorting & Layout", - "reference": "Modules/Settings/LauncherTab.qml:333", - "comment": "" - }, - { - "term": "Sound Theme", - "context": "Sound Theme", - "reference": "Modules/Settings/SoundsTab.qml:71", - "comment": "" - }, - { - "term": "Sounds", - "context": "Sounds", - "reference": "Modals/Settings/SettingsSidebar.qml:100", - "comment": "" - }, - { - "term": "Space between windows", - "context": "Space between windows", - "reference": "Modules/Settings/ThemeColorsTab.qml:1929", - "comment": "" - }, - { - "term": "Space between windows (gappih/gappiv/gappoh/gappov)", - "context": "Space between windows (gappih/gappiv/gappoh/gappov)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2135", - "comment": "" - }, - { - "term": "Space between windows (gaps_in and gaps_out)", - "context": "Space between windows (gaps_in and gaps_out)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2032", - "comment": "" - }, - { - "term": "Spacer", - "context": "Spacer", - "reference": "Modules/Settings/WidgetsTab.qml:204", - "comment": "" - }, - { - "term": "Spacing", - "context": "Spacing", - "reference": "Modules/Settings/DockTab.qml:531, Modules/Settings/DankBarTab.qml:803", - "comment": "" - }, - { - "term": "Speaker settings", - "context": "Speaker settings", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:120", - "comment": "" - }, - { - "term": "Speed", - "context": "Speed", - "reference": "Modules/Settings/NetworkTab.qml:587", - "comment": "" - }, - { - "term": "Spool Area Full", - "context": "Spool Area Full", - "reference": "Services/CupsService.qml:823", - "comment": "" - }, - { - "term": "Square Corners", - "context": "Square Corners", - "reference": "Modules/Settings/DankBarTab.qml:1289", - "comment": "" - }, - { - "term": "Stacked", - "context": "Stacked", - "reference": "Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:29, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:35, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:45", - "comment": "" - }, - { - "term": "Standard", - "context": "Standard", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:19", - "comment": "" - }, - { - "term": "Start", - "context": "Start", - "reference": "Modules/Settings/ThemeColorsTab.qml:1162, Modules/Settings/GammaControlTab.qml:252", - "comment": "" - }, - { - "term": "Start KDE Connect or Valent", - "context": "Start KDE Connect or Valent", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:104", - "comment": "Phone Connect start daemon hint" - }, - { - "term": "Start KDE Connect or Valent to use this plugin", - "context": "Start KDE Connect or Valent to use this plugin", - "reference": "dms-plugins/DankKDEConnect/components/UnavailableMessage.qml:39", - "comment": "Phone Connect daemon hint" - }, - { - "term": "Start typing your notes here...", - "context": "Start typing your notes here...", - "reference": "Modules/Notepad/NotepadTextEditor.qml:634", - "comment": "" - }, - { - "term": "State", - "context": "State", - "reference": "Modules/Settings/PrinterTab.qml:1149, Modules/Settings/NetworkTab.qml:601", - "comment": "" - }, - { - "term": "Status", - "context": "Status", - "reference": "Widgets/DankIconPicker.qml:55, Modules/Settings/AboutTab.qml:698, Modules/Settings/PrinterTab.qml:186, Modules/Settings/NetworkTab.qml:182", - "comment": "" - }, - { - "term": "Stopped", - "context": "Stopped", - "reference": "Services/CupsService.qml:765, Services/CupsService.qml:780", - "comment": "" - }, - { - "term": "Stopped Partly", - "context": "Stopped Partly", - "reference": "Services/CupsService.qml:819", - "comment": "" - }, - { - "term": "Stopping", - "context": "Stopping", - "reference": "Services/CupsService.qml:818", - "comment": "" - }, - { - "term": "Stretch", - "context": "Stretch", - "reference": "Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Stripes", - "context": "Stripes", - "reference": "Modules/Settings/WallpaperTab.qml:1169", - "comment": "wallpaper transition option" - }, - { - "term": "Summary", - "context": "Summary", - "reference": "Modules/Settings/NotificationsTab.qml:93", - "comment": "notification rule match field option" - }, - { - "term": "Sunrise", - "context": "Sunrise", - "reference": "Services/WeatherService.qml:245, Modules/DankDash/WeatherTab.qml:104, Modules/Settings/GammaControlTab.qml:574", - "comment": "" - }, - { - "term": "Sunset", - "context": "Sunset", - "reference": "Services/WeatherService.qml:270, Modules/DankDash/WeatherTab.qml:109, Modules/Settings/GammaControlTab.qml:610", - "comment": "" - }, - { - "term": "Suppress notification popups while enabled", - "context": "Suppress notification popups while enabled", - "reference": "Modules/Settings/NotificationsTab.qml:393", - "comment": "" - }, - { - "term": "Surface", - "context": "Surface", - "reference": "Modules/Settings/DockTab.qml:389, Modules/Settings/DockTab.qml:600, Modules/Settings/LauncherTab.qml:181, Modules/Settings/WorkspacesTab.qml:369, Modules/Settings/DankBarTab.qml:1211", - "comment": "color option | shadow color option" - }, - { - "term": "Surface Variant", - "context": "Surface Variant", - "reference": "Modules/Settings/ThemeColorsTab.qml:1558, Modules/Settings/ThemeColorsTab.qml:1566, Modules/Settings/ThemeColorsTab.qml:1576, Modules/Settings/ThemeColorsTab.qml:1590, Modules/Settings/ThemeColorsTab.qml:1598, Modules/Settings/ThemeColorsTab.qml:1608, Modules/Settings/ThemeColorsTab.qml:1690, Modules/Settings/ThemeColorsTab.qml:1698, Modules/Settings/ThemeColorsTab.qml:1709", - "comment": "button color option | shadow color option | tile color option" - }, - { - "term": "Suspend", - "context": "Suspend", - "reference": "Modals/PowerMenuModal.qml:204, Modules/Lock/LockPowerMenu.qml:122, Modules/Settings/PowerSleepTab.qml:311, Modules/Settings/PowerSleepTab.qml:378", - "comment": "" - }, - { - "term": "Suspend behavior", - "context": "Suspend behavior", - "reference": "Modules/Settings/PowerSleepTab.qml:302", - "comment": "" - }, - { - "term": "Suspend system after", - "context": "Suspend system after", - "reference": "Modules/Settings/PowerSleepTab.qml:267", - "comment": "" - }, - { - "term": "Suspend then Hibernate", - "context": "Suspend then Hibernate", - "reference": "Modules/Settings/PowerSleepTab.qml:311", - "comment": "" - }, - { - "term": "Sway Website", - "context": "Sway Website", - "reference": "Modules/Settings/AboutTab.qml:73", - "comment": "" - }, - { - "term": "Switch User", - "context": "Switch User", - "reference": "Modules/Greetd/GreeterContent.qml:1206", - "comment": "" - }, - { - "term": "Switch to power profile", - "context": "Switch to power profile", - "reference": "Modules/Settings/PowerSleepTab.qml:159", - "comment": "" - }, - { - "term": "Sync", - "context": "Sync", - "reference": "Modules/Settings/GreeterTab.qml:512", - "comment": "" - }, - { - "term": "Sync Mode with Portal", - "context": "Sync Mode with Portal", - "reference": "Modules/Settings/ThemeColorsTab.qml:2237", - "comment": "" - }, - { - "term": "Sync Popouts & Modals", - "context": "Sync Popouts & Modals", - "reference": "Modules/Settings/TypographyMotionTab.qml:284", - "comment": "" - }, - { - "term": "Sync Position Across Screens", - "context": "Sync Position Across Screens", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:358", - "comment": "" - }, - { - "term": "Sync completed successfully.", - "context": "Sync completed successfully.", - "reference": "Modules/Settings/GreeterTab.qml:301", - "comment": "" - }, - { - "term": "Sync dark mode with settings portals for system-wide theme hints", - "context": "Sync dark mode with settings portals for system-wide theme hints", - "reference": "Modules/Settings/ThemeColorsTab.qml:2238", - "comment": "" - }, - { - "term": "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.", - "context": "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.", - "reference": "Modules/Settings/GreeterTab.qml:308", - "comment": "" - }, - { - "term": "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.", - "context": "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.", - "reference": "Modules/Settings/GreeterTab.qml:337", - "comment": "" - }, - { - "term": "System", - "context": "System", - "reference": "Modals/ProcessListModal.qml:319, Modals/ProcessListModal.qml:377, Services/AppSearchService.qml:655, Widgets/DankIconPicker.qml:43, Modals/Settings/SettingsSidebar.qml:239, Modules/ProcessList/ProcessListPopout.qml:155", - "comment": "" - }, - { - "term": "System App Theming", - "context": "System App Theming", - "reference": "Modules/Settings/ThemeColorsTab.qml:2883", - "comment": "" - }, - { - "term": "System Check", - "context": "System Check", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:157, Modals/Greeter/GreeterDoctorPage.qml:221, Modules/Settings/AboutTab.qml:814", - "comment": "greeter doctor page title" - }, - { - "term": "System Default", - "context": "System Default", - "reference": "Modules/Settings/GreeterTab.qml:394, Modules/Settings/TimeWeatherTab.qml:12, Modules/Settings/TimeWeatherTab.qml:131, Modules/Settings/TimeWeatherTab.qml:134, Modules/Settings/TimeWeatherTab.qml:174, Modules/Settings/TimeWeatherTab.qml:218, Modules/Settings/TimeWeatherTab.qml:221, Modules/Settings/TimeWeatherTab.qml:261, Modules/Settings/LocaleTab.qml:9", - "comment": "date format option" - }, - { - "term": "System Information", - "context": "System Information", - "reference": "Modules/ProcessList/SystemView.qml:45", - "comment": "system info header in system monitor" - }, - { - "term": "System Monitor", - "context": "System Monitor", - "reference": "Modals/ProcessListModal.qml:51, Modals/ProcessListModal.qml:85, Modals/ProcessListModal.qml:261, Services/AppSearchService.qml:190, Services/DesktopWidgetRegistry.qml:54", - "comment": "System monitor widget name | sysmon window title" - }, - { - "term": "System Monitor Unavailable", - "context": "System Monitor Unavailable", - "reference": "Modals/ProcessListModal.qml:214", - "comment": "" - }, - { - "term": "System Sounds", - "context": "System Sounds", - "reference": "Modules/Settings/SoundsTab.qml:27", - "comment": "" - }, - { - "term": "System Tray", - "context": "System Tray", - "reference": "Modules/Settings/WidgetsTab.qml:148", - "comment": "" - }, - { - "term": "System Update", - "context": "System Update", - "reference": "Modules/Settings/WidgetsTab.qml:246", - "comment": "" - }, - { - "term": "System Updater", - "context": "System Updater", - "reference": "Modals/Settings/SettingsSidebar.qml:165, Modules/Settings/SystemUpdaterTab.qml:25", - "comment": "" - }, - { - "term": "System Updates", - "context": "System Updates", - "reference": "Modules/SystemUpdatePopout.qml:53", - "comment": "" - }, - { - "term": "System notification area icons", - "context": "System notification area icons", - "reference": "Modules/Settings/WidgetsTab.qml:149", - "comment": "" - }, - { - "term": "System sounds are not available. Install %1 for sound support.", - "context": "System sounds are not available. Install %1 for sound support.", - "reference": "Modules/Settings/SoundsTab.qml:159", - "comment": "" - }, - { - "term": "System theme toggle", - "context": "System theme toggle", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:78", - "comment": "" - }, - { - "term": "System toast notifications", - "context": "System toast notifications", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:56", - "comment": "" - }, - { - "term": "System update custom command", - "context": "System update custom command", - "reference": "Modules/Settings/SystemUpdaterTab.qml:64", - "comment": "" - }, - { - "term": "Tab", - "context": "Tab", - "reference": "Widgets/KeybindItem.qml:1078", - "comment": "" - }, - { - "term": "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select", - "context": "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select", - "reference": "Modals/FileBrowser/KeyboardHints.qml:26", - "comment": "" - }, - { - "term": "Terminal", - "context": "Terminal", - "reference": "Modules/Settings/MuxTab.qml:49", - "comment": "" - }, - { - "term": "Terminal custom additional parameters", - "context": "Terminal custom additional parameters", - "reference": "Modules/Settings/SystemUpdaterTab.qml:108", - "comment": "" - }, - { - "term": "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.", - "context": "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.", - "reference": "Common/settings/Processes.qml:506", - "comment": "" - }, - { - "term": "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.", - "context": "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.", - "reference": "Modules/Settings/GreeterTab.qml:360", - "comment": "" - }, - { - "term": "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.", - "context": "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.", - "reference": "Common/settings/Processes.qml:502", - "comment": "" - }, - { - "term": "Terminal fallback opened. Complete sync there; it will close automatically when done.", - "context": "Terminal fallback opened. Complete sync there; it will close automatically when done.", - "reference": "Modules/Settings/GreeterTab.qml:356", - "comment": "" - }, - { - "term": "Terminal multiplexer backend to use", - "context": "Terminal multiplexer backend to use", - "reference": "Modules/Settings/MuxTab.qml:39", - "comment": "" - }, - { - "term": "Terminal opened. Complete authentication setup there; it will close automatically when done.", - "context": "Terminal opened. Complete authentication setup there; it will close automatically when done.", - "reference": "Common/settings/Processes.qml:502", - "comment": "" - }, - { - "term": "Terminal opened. Complete sync authentication there; it will close automatically when done.", - "context": "Terminal opened. Complete sync authentication there; it will close automatically when done.", - "reference": "Modules/Settings/GreeterTab.qml:356", - "comment": "" - }, - { - "term": "Terminals - Always use Dark Theme", - "context": "Terminals - Always use Dark Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:2247", - "comment": "" - }, - { - "term": "Test Connection", - "context": "Test Connection", - "reference": "Modules/Settings/PrinterTab.qml:580", - "comment": "Button to test connection to a printer by IP address" - }, - { - "term": "Test Page", - "context": "Test Page", - "reference": "Modules/Settings/PrinterTab.qml:1272", - "comment": "" - }, - { - "term": "Test page sent to printer", - "context": "Test page sent to printer", - "reference": "Services/CupsService.qml:642", - "comment": "" - }, - { - "term": "Testing...", - "context": "Testing...", - "reference": "Modules/Settings/PrinterTab.qml:580", - "comment": "Button state while testing printer connection" - }, - { - "term": "Text", - "context": "Text", - "reference": "Modals/Clipboard/ClipboardEntry.qml:120, Modules/Settings/LauncherTab.qml:477", - "comment": "text color" - }, - { - "term": "Text Color", - "context": "Text Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1690, Modules/Settings/ThemeColorsTab.qml:1694, Modules/Settings/ThemeColorsTab.qml:1714, Modules/Settings/ThemeColorsTab.qml:1853, Modules/Settings/ThemeColorsTab.qml:1861, Modules/Settings/ThemeColorsTab.qml:1873", - "comment": "blur border color | shadow color option" - }, - { - "term": "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.", - "context": "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.", - "reference": "Modals/ProcessListModal.qml:222", - "comment": "dgop unavailable error message" - }, - { - "term": "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.", - "context": "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.", - "reference": "Modules/Settings/PluginsTab.qml:124", - "comment": "" - }, - { - "term": "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).", - "context": "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).", - "reference": "Modules/Settings/ThemeColorsTab.qml:2872", - "comment": "" - }, - { - "term": "The custom command used when attaching to sessions (receives the session name as the first argument)", - "context": "The custom command used when attaching to sessions (receives the session name as the first argument)", - "reference": "Modules/Settings/MuxTab.qml:69", - "comment": "" - }, - { - "term": "The job queue of this printer is empty", - "context": "The job queue of this printer is empty", - "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:238", - "comment": "" - }, - { - "term": "Theme & Colors", - "context": "Theme & Colors", - "reference": "Modals/Greeter/GreeterCompletePage.qml:389, Modals/Settings/SettingsSidebar.qml:82", - "comment": "greeter settings link" - }, - { - "term": "Theme Color", - "context": "Theme Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:209", - "comment": "" - }, - { - "term": "Theme Registry", - "context": "Theme Registry", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:106", - "comment": "greeter feature card title" - }, - { - "term": "Themes", - "context": "Themes", - "reference": "Modals/Greeter/GreeterCompletePage.qml:484", - "comment": "greeter themes link" - }, - { - "term": "Thickness", - "context": "Thickness", - "reference": "Modules/Settings/LauncherTab.qml:445, Modules/Settings/WorkspacesTab.qml:403, Modules/Settings/DankBarTab.qml:1451, Modules/Settings/DankBarTab.qml:1541", - "comment": "border thickness" - }, - { - "term": "Third-Party Plugin Warning", - "context": "Third-Party Plugin Warning", - "reference": "Modules/Settings/PluginBrowser.qml:735, Modules/Settings/PluginBrowser.qml:769", - "comment": "" - }, - { - "term": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.", - "context": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.", - "reference": "Modules/Settings/PluginBrowser.qml:793", - "comment": "" - }, - { - "term": "This bind is overridden by config.kdl", - "context": "This bind is overridden by config.kdl", - "reference": "Widgets/KeybindItem.qml:501", - "comment": "" - }, - { - "term": "This may take a few seconds", - "context": "This may take a few seconds", - "reference": "Modules/Settings/AudioTab.qml:512", - "comment": "Loading overlay subtitle" - }, - { - "term": "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json", - "context": "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json", - "reference": "Modules/Plugins/PluginSettings.qml:205", - "comment": "" - }, - { - "term": "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.", - "context": "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.", - "reference": "Modules/Settings/WidgetsTab.qml:143", - "comment": "" - }, - { - "term": "This will delete all unpinned entries. %1 pinned entries will be kept.", - "context": "This will delete all unpinned entries. %1 pinned entries will be kept.", - "reference": "Modals/Clipboard/ClipboardContent.qml:37, Modules/DankBar/DankBarContent.qml:638", - "comment": "" - }, - { - "term": "This will permanently delete all clipboard history.", - "context": "This will permanently delete all clipboard history.", - "reference": "Modals/Clipboard/ClipboardContent.qml:37, Modules/DankBar/DankBarContent.qml:638", - "comment": "" - }, - { - "term": "This will permanently remove this saved clipboard item. This action cannot be undone.", - "context": "This will permanently remove this saved clipboard item. This action cannot be undone.", - "reference": "Services/ClipboardService.qml:167", - "comment": "" - }, - { - "term": "Thunderstorm", - "context": "Thunderstorm", - "reference": "Services/WeatherService.qml:147", - "comment": "" - }, - { - "term": "Thunderstorm with Hail", - "context": "Thunderstorm with Hail", - "reference": "Services/WeatherService.qml:148, Services/WeatherService.qml:149", - "comment": "" - }, - { - "term": "Tile", - "context": "Tile", - "reference": "Modals/WindowRuleModal.qml:939, Modules/Settings/WallpaperTab.qml:312, Modules/Settings/WindowRulesTab.qml:555", - "comment": "wallpaper fill mode" - }, - { - "term": "Tile H", - "context": "Tile H", - "reference": "Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Tile V", - "context": "Tile V", - "reference": "Modules/Settings/WallpaperTab.qml:312", - "comment": "wallpaper fill mode" - }, - { - "term": "Tiled", - "context": "Tiled", - "reference": "Modules/Settings/WindowRulesTab.qml:550", - "comment": "" - }, - { - "term": "Tiled State", - "context": "Tiled State", - "reference": "Modals/WindowRuleModal.qml:709", - "comment": "" - }, - { - "term": "Tiling", - "context": "Tiling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:53", - "comment": "" - }, - { - "term": "Time", - "context": "Time", - "reference": "Modules/Settings/ThemeColorsTab.qml:1094, Modules/Settings/GammaControlTab.qml:184, Modules/Settings/WallpaperTab.qml:960", - "comment": "theme auto mode tab | wallpaper cycling mode tab" - }, - { - "term": "Time & Date Locale", - "context": "Time & Date Locale", - "reference": "Modules/Settings/LocaleTab.qml:75", - "comment": "" - }, - { - "term": "Time & Weather", - "context": "Time & Weather", - "reference": "Modals/Settings/SettingsSidebar.qml:94", - "comment": "" - }, - { - "term": "Time Format", - "context": "Time Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:45", - "comment": "" - }, - { - "term": "Time format", - "context": "Time format", - "reference": "Modules/Settings/GreeterTab.qml:591", - "comment": "" - }, - { - "term": "Time remaining: %1", - "context": "Time remaining: %1", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:109, Modules/DankBar/Popouts/BatteryPopout.qml:179", - "comment": "" - }, - { - "term": "Time until full: %1", - "context": "Time until full: %1", - "reference": "Modules/ControlCenter/Details/BatteryDetail.qml:109, Modules/DankBar/Popouts/BatteryPopout.qml:179", - "comment": "" - }, - { - "term": "Timed Out", - "context": "Timed Out", - "reference": "Services/CupsService.qml:817", - "comment": "" - }, - { - "term": "Timeout for critical priority notifications", - "context": "Timeout for critical priority notifications", - "reference": "Modules/Settings/NotificationsTab.qml:786, Modules/Notifications/Center/NotificationSettings.qml:212", - "comment": "" - }, - { - "term": "Timeout for low priority notifications", - "context": "Timeout for low priority notifications", - "reference": "Modules/Settings/NotificationsTab.qml:752, Modules/Notifications/Center/NotificationSettings.qml:182", - "comment": "" - }, - { - "term": "Timeout for normal priority notifications", - "context": "Timeout for normal priority notifications", - "reference": "Modules/Settings/NotificationsTab.qml:769, Modules/Notifications/Center/NotificationSettings.qml:197", - "comment": "" - }, - { - "term": "Title", - "context": "Title", - "reference": "Widgets/KeybindItem.qml:1527", - "comment": "" - }, - { - "term": "Title regex (optional)", - "context": "Title regex (optional)", - "reference": "Modals/WindowRuleModal.qml:492", - "comment": "" - }, - { - "term": "To Full", - "context": "To Full", - "reference": "Modules/DankBar/Popouts/BatteryPopout.qml:520", - "comment": "" - }, - { - "term": "To update, run the following command:", - "context": "To update, run the following command:", - "reference": "Services/DMSService.qml:320", - "comment": "" - }, - { - "term": "To use this DMS bind, remove or change the keybind in your config.kdl", - "context": "To use this DMS bind, remove or change the keybind in your config.kdl", - "reference": "Widgets/KeybindItem.qml:519", - "comment": "" - }, - { - "term": "Toast Messages", - "context": "Toast Messages", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:55", - "comment": "" - }, - { - "term": "Today", - "context": "Today", - "reference": "Services/WeatherService.qml:441, Modules/Notifications/Center/HistoryNotificationList.qml:97", - "comment": "notification history filter" - }, - { - "term": "Toggle visibility of this bar configuration", - "context": "Toggle visibility of this bar configuration", - "reference": "Modules/Settings/DankBarTab.qml:415", - "comment": "" - }, - { - "term": "Toggling...", - "context": "Toggling...", - "reference": "Modules/Settings/NetworkTab.qml:821", - "comment": "" - }, - { - "term": "Tomorrow", - "context": "Tomorrow", - "reference": "Services/WeatherService.qml:443", - "comment": "" - }, - { - "term": "Tonal Spot", - "context": "Tonal Spot", - "reference": "Common/Theme.qml:467", - "comment": "matugen color scheme option" - }, - { - "term": "Toner Empty", - "context": "Toner Empty", - "reference": "Services/CupsService.qml:790", - "comment": "" - }, - { - "term": "Toner Low", - "context": "Toner Low", - "reference": "Services/CupsService.qml:789", - "comment": "" - }, - { - "term": "Too many attempts - locked out", - "context": "Too many attempts - locked out", - "reference": "Modules/Lock/LockScreenContent.qml:58", - "comment": "" - }, - { - "term": "Too many failed attempts - account may be locked", - "context": "Too many failed attempts - account may be locked", - "reference": "Modules/Greetd/GreeterContent.qml:235", - "comment": "" - }, - { - "term": "Tools", - "context": "Tools", - "reference": "Modules/Settings/AboutTab.qml:793", - "comment": "" - }, - { - "term": "Top", - "context": "Top", - "reference": "Modules/Settings/DockTab.qml:102, Modules/Settings/DankBarTab.qml:284, Modules/Settings/DankBarTab.qml:292, Modules/Settings/DankBarTab.qml:542, Modules/Settings/DankBarTab.qml:1153, Modules/Settings/DankBarTab.qml:1163", - "comment": "shadow direction option" - }, - { - "term": "Top (Default)", - "context": "Top (Default)", - "reference": "Modules/Settings/ThemeColorsTab.qml:1728, Modules/Settings/ThemeColorsTab.qml:1740", - "comment": "shadow direction option" - }, - { - "term": "Top Bar Format", - "context": "Top Bar Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:129", - "comment": "" - }, - { - "term": "Top Center", - "context": "Top Center", - "reference": "Modules/Settings/OSDTab.qml:39, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:60, Modules/Settings/NotificationsTab.qml:216, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:241", - "comment": "screen position option" - }, - { - "term": "Top Left", - "context": "Top Left", - "reference": "Modules/Settings/ThemeColorsTab.qml:1728, Modules/Settings/ThemeColorsTab.qml:1734, Modules/Settings/ThemeColorsTab.qml:1747, Modules/Settings/DankBarTab.qml:1153, Modules/Settings/DankBarTab.qml:1157, Modules/Settings/DankBarTab.qml:1167, Modules/Settings/OSDTab.qml:37, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:58, Modules/Settings/NotificationsTab.qml:223, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:238, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:144", - "comment": "screen position option | shadow direction option" - }, - { - "term": "Top Processes", - "context": "Top Processes", - "reference": "Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:256", - "comment": "" - }, - { - "term": "Top Right", - "context": "Top Right", - "reference": "Modules/Settings/ThemeColorsTab.qml:1728, Modules/Settings/ThemeColorsTab.qml:1736, Modules/Settings/ThemeColorsTab.qml:1749, Modules/Settings/DankBarTab.qml:1153, Modules/Settings/DankBarTab.qml:1159, Modules/Settings/DankBarTab.qml:1171, Modules/Settings/OSDTab.qml:35, Modules/Settings/OSDTab.qml:54, Modules/Settings/OSDTab.qml:56, Modules/Settings/NotificationsTab.qml:219, Modules/Settings/NotificationsTab.qml:229, Modules/Settings/NotificationsTab.qml:232, Modules/Settings/NotificationsTab.qml:235, Modules/Settings/DisplayConfig/NiriOutputSettings.qml:144", - "comment": "screen position option | shadow direction option" - }, - { - "term": "Top Section", - "context": "Top Section", - "reference": "Modules/Settings/WidgetsTab.qml:953", - "comment": "" - }, - { - "term": "Total", - "context": "Total", - "reference": "Modules/Settings/WidgetsTabSection.qml:1103", - "comment": "" - }, - { - "term": "Total Jobs", - "context": "Total Jobs", - "reference": "Modules/Settings/PrinterTab.qml:222", - "comment": "" - }, - { - "term": "Touch your security key...", - "context": "Touch your security key...", - "reference": "Modules/Lock/LockScreenContent.qml:52", - "comment": "" - }, - { - "term": "Transform", - "context": "Transform", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:240, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1224", - "comment": "" - }, - { - "term": "Transition Effect", - "context": "Transition Effect", - "reference": "Modules/Settings/WallpaperTab.qml:1153", - "comment": "" - }, - { - "term": "Transparency", - "context": "Transparency", - "reference": "Modules/Settings/DockTab.qml:567, Modules/Settings/DankBarTab.qml:1000, Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml:379, Modules/Settings/DesktopWidgetSettings/ClockSettings.qml:98, Modules/Settings/Widgets/SystemMonitorVariantCard.qml:351", - "comment": "" - }, - { - "term": "Trending GIFs", - "context": "Trending GIFs", - "reference": "dms-plugins/DankGifSearch/DankGifSearch.qml:85", - "comment": "" - }, - { - "term": "Trending Stickers", - "context": "Trending Stickers", - "reference": "dms-plugins/DankStickerSearch/DankStickerSearch.qml:142", - "comment": "" - }, - { - "term": "Trigger", - "context": "Trigger", - "reference": "Modules/Settings/LauncherTab.qml:582", - "comment": "" - }, - { - "term": "Trigger Prefix", - "context": "Trigger Prefix", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:123", - "comment": "" - }, - { - "term": "Trigger: %1", - "context": "Trigger: %1", - "reference": "Modals/DankLauncherV2/Controller.qml:1236, Modules/Settings/LauncherTab.qml:768", - "comment": "" - }, - { - "term": "Trust", - "context": "Trust", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:673", - "comment": "" - }, - { - "term": "Try a different search", - "context": "Try a different search", - "reference": "Modals/MuxModal.qml:569, dms-plugins/DankStickerSearch/DankStickerSearch.qml:155, dms-plugins/DankGifSearch/DankGifSearch.qml:98", - "comment": "" - }, - { - "term": "Turn off all displays immediately when the lock screen activates", - "context": "Turn off all displays immediately when the lock screen activates", - "reference": "Modules/Settings/LockScreenTab.qml:202", - "comment": "" - }, - { - "term": "Turn off monitors after", - "context": "Turn off monitors after", - "reference": "Modules/Settings/PowerSleepTab.qml:234", - "comment": "" - }, - { - "term": "Type", - "context": "Type", - "reference": "Widgets/KeybindItem.qml:834, Modules/Settings/RunningAppsTab.qml:154, Modules/Settings/NotificationsTab.qml:566", - "comment": "" - }, - { - "term": "Type at least 2 characters", - "context": "Type at least 2 characters", - "reference": "Modals/DankLauncherV2/ResultsList.qml:477", - "comment": "" - }, - { - "term": "Type this prefix to search keybinds", - "context": "Type this prefix to search keybinds", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:124", - "comment": "" - }, - { - "term": "Type to search files", - "context": "Type to search files", - "reference": "Modals/DankLauncherV2/ResultsList.qml:475", - "comment": "" - }, - { - "term": "Typography", - "context": "Typography", - "reference": "Modules/Settings/TypographyMotionTab.qml:61", - "comment": "" - }, - { - "term": "Typography & Motion", - "context": "Typography & Motion", - "reference": "Modals/Settings/SettingsSidebar.qml:88, Modals/Settings/SettingsSidebar.qml:557", - "comment": "" - }, - { - "term": "Unavailable", - "context": "Unavailable", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:31, Modules/Settings/PrinterTab.qml:202, Modules/Settings/NetworkTab.qml:452", - "comment": "Phone Connect unavailable status" - }, - { - "term": "Unfocused Color", - "context": "Unfocused Color", - "reference": "Modules/Settings/WorkspacesTab.qml:276", - "comment": "" - }, - { - "term": "Ungrouped", - "context": "Ungrouped", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:469", - "comment": "" - }, - { - "term": "Uninstall", - "context": "Uninstall", - "reference": "Modules/Settings/GreeterTab.qml:123, Modules/Settings/GreeterTab.qml:174, Modules/Settings/ThemeBrowser.qml:650", - "comment": "uninstall action button" - }, - { - "term": "Uninstall Greeter", - "context": "Uninstall Greeter", - "reference": "Modules/Settings/GreeterTab.qml:172", - "comment": "greeter action confirmation" - }, - { - "term": "Uninstall Plugin", - "context": "Uninstall Plugin", - "reference": "Modules/Settings/PluginListItem.qml:260", - "comment": "" - }, - { - "term": "Uninstall complete. Greeter has been removed.", - "context": "Uninstall complete. Greeter has been removed.", - "reference": "Modules/Settings/GreeterTab.qml:383", - "comment": "" - }, - { - "term": "Uninstall failed: %1", - "context": "Uninstall failed: %1", - "reference": "Modules/Settings/ThemeColorsTab.qml:766, Modules/Settings/ThemeBrowser.qml:97", - "comment": "uninstallation error" - }, - { - "term": "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.", - "context": "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.", - "reference": "Modules/Settings/GreeterTab.qml:173", - "comment": "" - }, - { - "term": "Uninstalled: %1", - "context": "Uninstalled: %1", - "reference": "Modules/Settings/ThemeColorsTab.qml:769, Modules/Settings/ThemeBrowser.qml:100", - "comment": "uninstallation success" - }, - { - "term": "Uninstalling: %1", - "context": "Uninstalling: %1", - "reference": "Modules/Settings/ThemeColorsTab.qml:763, Modules/Settings/ThemeBrowser.qml:94", - "comment": "uninstallation progress" - }, - { - "term": "Unknown", - "context": "Unknown", - "reference": "Common/Theme.qml:1478, Services/WeatherService.qml:151, Services/WeatherService.qml:605, Services/WeatherService.qml:606, Services/WeatherService.qml:765, Services/WeatherService.qml:766, Services/BatteryService.qml:148, dms-plugins/DankKDEConnect/components/DeviceCard.qml:208, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:201, Modules/Lock/LockScreenContent.qml:396, Modules/Lock/LockScreenContent.qml:516, Modules/Lock/LockScreenContent.qml:612, Modules/Settings/PluginBrowser.qml:539, Modules/Settings/PrinterTab.qml:1638, Modules/Settings/ThemeBrowser.qml:527, Modules/Settings/NetworkTab.qml:175, Modules/Settings/NetworkTab.qml:217, Modules/Settings/NetworkTab.qml:431, Modules/Settings/NetworkTab.qml:454, Modules/Settings/NetworkTab.qml:602, Modules/Settings/NetworkTab.qml:747, Modules/Settings/NetworkTab.qml:1172, Modules/Settings/NotificationsTab.qml:666, Modules/ControlCenter/Details/BatteryDetail.qml:185, Modules/ControlCenter/Components/HeaderPane.qml:63, Modules/ControlCenter/Components/DragDropGrid.qml:325, Modules/ControlCenter/Components/DragDropGrid.qml:626, Modules/DankDash/Overview/MediaOverviewCard.qml:91, Modules/DankBar/Popouts/BatteryPopout.qml:341", - "comment": "KDE Connect unknown device status | battery status | power profile option | unknown author | widget status" - }, - { - "term": "Unknown App", - "context": "Unknown App", - "reference": "Modules/Settings/LauncherTab.qml:1244", - "comment": "" - }, - { - "term": "Unknown Artist", - "context": "Unknown Artist", - "reference": "Modules/DankDash/MediaPlayerTab.qml:335, Modules/OSD/MediaPlaybackOSD.qml:268, Modules/DankDash/Overview/MediaOverviewCard.qml:102", - "comment": "" - }, - { - "term": "Unknown Config", - "context": "Unknown Config", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:306", - "comment": "" - }, - { - "term": "Unknown Device", - "context": "Unknown Device", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:227, Modules/ControlCenter/Details/BluetoothDetail.qml:488", - "comment": "" - }, - { - "term": "Unknown GPU", - "context": "Unknown GPU", - "reference": "Modules/ProcessList/SystemView.qml:202", - "comment": "fallback gpu name" - }, - { - "term": "Unknown Monitor", - "context": "Unknown Monitor", - "reference": "Modules/ControlCenter/Details/BrightnessDetail.qml:179", - "comment": "" - }, - { - "term": "Unknown Network", - "context": "Unknown Network", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:562", - "comment": "" - }, - { - "term": "Unknown Title", - "context": "Unknown Title", - "reference": "Modules/OSD/MediaPlaybackOSD.qml:257", - "comment": "" - }, - { - "term": "Unknown Track", - "context": "Unknown Track", - "reference": "Modules/DankDash/MediaPlayerTab.qml:323", - "comment": "" - }, - { - "term": "Unload on Close", - "context": "Unload on Close", - "reference": "Modules/Settings/LauncherTab.qml:423", - "comment": "" - }, - { - "term": "Unmute", - "context": "Unmute", - "reference": "Modules/Settings/NotificationsTab.qml:679", - "comment": "" - }, - { - "term": "Unmute popups for %1", - "context": "Unmute popups for %1", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:1114, Modules/Notifications/Center/NotificationCard.qml:1016", - "comment": "" - }, - { - "term": "Unnamed Rule", - "context": "Unnamed Rule", - "reference": "Modules/Settings/WindowRulesTab.qml:471", - "comment": "" - }, - { - "term": "Unpair", - "context": "Unpair", - "reference": "dms-plugins/DankKDEConnect/components/DeviceCard.qml:171, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:354", - "comment": "KDE Connect unpair tooltip" - }, - { - "term": "Unpair failed", - "context": "Unpair failed", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:176", - "comment": "Phone Connect error" - }, - { - "term": "Unpin", - "context": "Unpin", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeys.qml:165", - "comment": "" - }, - { - "term": "Unpin from Dock", - "context": "Unpin from Dock", - "reference": "Modals/DankLauncherV2/LauncherContextMenu.qml:103, Modules/Dock/DockContextMenu.qml:418, Modules/DankBar/Widgets/AppsDockContextMenu.qml:341", - "comment": "" - }, - { - "term": "Unsaved Changes", - "context": "Unsaved Changes", - "reference": "Modules/Notepad/Notepad.qml:406", - "comment": "" - }, - { - "term": "Unsaved changes", - "context": "Unsaved changes", - "reference": "Widgets/KeybindItem.qml:1807, Modules/Notepad/NotepadTextEditor.qml:877", - "comment": "" - }, - { - "term": "Unsaved note...", - "context": "Unsaved note...", - "reference": "Modules/Notepad/NotepadTextEditor.qml:875", - "comment": "" - }, - { - "term": "Untitled", - "context": "Untitled", - "reference": "Services/NotepadStorageService.qml:80, Services/NotepadStorageService.qml:180, Services/NotepadStorageService.qml:221", - "comment": "" - }, - { - "term": "Untrust", - "context": "Untrust", - "reference": "Modules/ControlCenter/Details/BluetoothDetail.qml:673", - "comment": "" - }, - { - "term": "Up to date", - "context": "Up to date", - "reference": "Modules/SystemUpdatePopout.qml:74", - "comment": "" - }, - { - "term": "Update", - "context": "Update", - "reference": "Modals/WindowRuleModal.qml:1154", - "comment": "" - }, - { - "term": "Update All", - "context": "Update All", - "reference": "Modules/SystemUpdatePopout.qml:262", - "comment": "" - }, - { - "term": "Update Plugin", - "context": "Update Plugin", - "reference": "Modules/Settings/PluginListItem.qml:217", - "comment": "" - }, - { - "term": "Uptime", - "context": "Uptime", - "reference": "Modules/ProcessList/SystemView.qml:80", - "comment": "" - }, - { - "term": "Uptime:", - "context": "Uptime:", - "reference": "Modals/ProcessListModal.qml:508", - "comment": "uptime label in footer" - }, - { - "term": "Urgent Color", - "context": "Urgent Color", - "reference": "Modules/Settings/WorkspacesTab.qml:313", - "comment": "" - }, - { - "term": "Usage Tips", - "context": "Usage Tips", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:208", - "comment": "" - }, - { - "term": "Use 24-hour time format instead of 12-hour AM/PM", - "context": "Use 24-hour time format instead of 12-hour AM/PM", - "reference": "Modules/Settings/TimeWeatherTab.qml:54", - "comment": "" - }, - { - "term": "Use Custom Command", - "context": "Use Custom Command", - "reference": "Modules/Settings/MuxTab.qml:56, Modules/Settings/SystemUpdaterTab.qml:38", - "comment": "" - }, - { - "term": "Use Grid Layout", - "context": "Use Grid Layout", - "reference": "Modules/Settings/PowerSleepTab.qml:367", - "comment": "" - }, - { - "term": "Use IP Location", - "context": "Use IP Location", - "reference": "Modules/Settings/ThemeColorsTab.qml:1252, Modules/Settings/GammaControlTab.qml:345", - "comment": "" - }, - { - "term": "Use Imperial Units", - "context": "Use Imperial Units", - "reference": "Modules/Settings/TimeWeatherTab.qml:422", - "comment": "" - }, - { - "term": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)", - "context": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)", - "reference": "Modules/Settings/TimeWeatherTab.qml:423", - "comment": "" - }, - { - "term": "Use Inline Expansion", - "context": "Use Inline Expansion", - "reference": "Modules/Settings/WidgetsTabSection.qml:1016", - "comment": "" - }, - { - "term": "Use Monospace Font", - "context": "Use Monospace Font", - "reference": "Modules/Notepad/NotepadSettings.qml:130", - "comment": "" - }, - { - "term": "Use System Theme", - "context": "Use System Theme", - "reference": "Modules/Settings/SoundsTab.qml:59", - "comment": "" - }, - { - "term": "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.", - "context": "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.", - "reference": "Modules/Settings/GreeterTab.qml:658", - "comment": "" - }, - { - "term": "Use a fixed shadow direction for this bar", - "context": "Use a fixed shadow direction for this bar", - "reference": "Modules/Settings/DankBarTab.qml:1151", - "comment": "" - }, - { - "term": "Use a security key for lock screen authentication.", - "context": "Use a security key for lock screen authentication.", - "reference": "Modules/Settings/LockScreenTab.qml:35", - "comment": "lock screen U2F security key setting" - }, - { - "term": "Use an external wallpaper manager like swww, hyprpaper, or swaybg.", - "context": "Use an external wallpaper manager like swww, hyprpaper, or swaybg.", - "reference": "Modules/Settings/WallpaperTab.qml:1251", - "comment": "wallpaper settings disable description" - }, - { - "term": "Use animated wave progress bars for media playback", - "context": "Use animated wave progress bars for media playback", - "reference": "Modules/Settings/MediaPlayerTab.qml:30", - "comment": "" - }, - { - "term": "Use custom border size", - "context": "Use custom border size", - "reference": "Modules/Settings/ThemeColorsTab.qml:2078, Modules/Settings/ThemeColorsTab.qml:2181", - "comment": "" - }, - { - "term": "Use custom border/focus-ring width", - "context": "Use custom border/focus-ring width", - "reference": "Modules/Settings/ThemeColorsTab.qml:1975", - "comment": "" - }, - { - "term": "Use custom command for update your system", - "context": "Use custom command for update your system", - "reference": "Modules/Settings/SystemUpdaterTab.qml:39", - "comment": "" - }, - { - "term": "Use custom gaps instead of bar spacing", - "context": "Use custom gaps instead of bar spacing", - "reference": "Modules/Settings/ThemeColorsTab.qml:1912, Modules/Settings/ThemeColorsTab.qml:2015, Modules/Settings/ThemeColorsTab.qml:2118", - "comment": "" - }, - { - "term": "Use custom window radius instead of theme radius", - "context": "Use custom window radius instead of theme radius", - "reference": "Modules/Settings/ThemeColorsTab.qml:1944, Modules/Settings/ThemeColorsTab.qml:2150", - "comment": "" - }, - { - "term": "Use custom window rounding instead of theme radius", - "context": "Use custom window rounding instead of theme radius", - "reference": "Modules/Settings/ThemeColorsTab.qml:2047", - "comment": "" - }, - { - "term": "Use desktop wallpaper", - "context": "Use desktop wallpaper", - "reference": "Modules/Settings/GreeterTab.qml:672", - "comment": "" - }, - { - "term": "Use fingerprint authentication for the lock screen.", - "context": "Use fingerprint authentication for the lock screen.", - "reference": "Modules/Settings/LockScreenTab.qml:18", - "comment": "" - }, - { - "term": "Use light theme instead of dark theme", - "context": "Use light theme instead of dark theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:1486", - "comment": "" - }, - { - "term": "Use meters per second instead of km/h for wind speed", - "context": "Use meters per second instead of km/h for wind speed", - "reference": "Modules/Settings/TimeWeatherTab.qml:441", - "comment": "" - }, - { - "term": "Use smaller notification cards", - "context": "Use smaller notification cards", - "reference": "Modules/Settings/NotificationsTab.qml:271", - "comment": "" - }, - { - "term": "Use sound theme from system settings", - "context": "Use sound theme from system settings", - "reference": "Modules/Settings/SoundsTab.qml:60", - "comment": "" - }, - { - "term": "Use the same position and size on all displays", - "context": "Use the same position and size on all displays", - "reference": "Modules/Settings/DesktopWidgetInstanceCard.qml:359", - "comment": "" - }, - { - "term": "Use trigger prefix to activate", - "context": "Use trigger prefix to activate", - "reference": "dms-plugins/DankLauncherKeys/DankLauncherKeysSettings.qml:107", - "comment": "" - }, - { - "term": "Used when accent color is set to Custom", - "context": "Used when accent color is set to Custom", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:57", - "comment": "" - }, - { - "term": "User", - "context": "User", - "reference": "Modals/ProcessListModal.qml:377, Modules/ProcessList/ProcessListPopout.qml:155, Modules/ControlCenter/Components/HeaderPane.qml:57", - "comment": "" - }, - { - "term": "Username", - "context": "Username", - "reference": "Modals/WifiPasswordModal.qml:172, Modals/WifiPasswordModal.qml:520, Widgets/VpnProfileDelegate.qml:45, Modules/Settings/NetworkTab.qml:1910", - "comment": "" - }, - { - "term": "Username...", - "context": "Username...", - "reference": "Modules/Greetd/GreeterContent.qml:1023", - "comment": "" - }, - { - "term": "Uses sunrise/sunset times based on your location.", - "context": "Uses sunrise/sunset times based on your location.", - "reference": "Modules/Settings/ThemeColorsTab.qml:1331", - "comment": "" - }, - { - "term": "Uses sunrise/sunset times to automatically adjust night mode based on your location.", - "context": "Uses sunrise/sunset times to automatically adjust night mode based on your location.", - "reference": "Modules/Settings/GammaControlTab.qml:423", - "comment": "" - }, - { - "term": "Using shared settings from Gamma Control", - "context": "Using shared settings from Gamma Control", - "reference": "Modules/Settings/ThemeColorsTab.qml:1343", - "comment": "" - }, - { - "term": "Utilities", - "context": "Utilities", - "reference": "Services/AppSearchService.qml:656, Services/AppSearchService.qml:657, Services/AppSearchService.qml:658, Services/AppSearchService.qml:659", - "comment": "" - }, - { - "term": "VPN", - "context": "VPN", - "reference": "Modules/Settings/WidgetsTabSection.qml:1219, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/WidgetsTab.qml:183, Modules/Settings/NetworkTab.qml:1544, Modules/ControlCenter/Models/WidgetModel.qml:187, Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:15", - "comment": "" - }, - { - "term": "VPN Connections", - "context": "VPN Connections", - "reference": "Modules/DankBar/Popouts/VpnPopout.qml:64", - "comment": "" - }, - { - "term": "VPN Password", - "context": "VPN Password", - "reference": "Modals/WifiPasswordModal.qml:250", - "comment": "" - }, - { - "term": "VPN configuration updated", - "context": "VPN configuration updated", - "reference": "Services/VPNService.qml:143", - "comment": "" - }, - { - "term": "VPN connections", - "context": "VPN connections", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:188", - "comment": "" - }, - { - "term": "VPN deleted", - "context": "VPN deleted", - "reference": "Services/VPNService.qml:160", - "comment": "" - }, - { - "term": "VPN imported: %1", - "context": "VPN imported: %1", - "reference": "Services/VPNService.qml:91", - "comment": "" - }, - { - "term": "VPN not available", - "context": "VPN not available", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:192", - "comment": "" - }, - { - "term": "VPN status and quick connect", - "context": "VPN status and quick connect", - "reference": "Modules/Settings/WidgetsTab.qml:184", - "comment": "" - }, - { - "term": "VRR", - "context": "VRR", - "reference": "Modules/Settings/WindowRulesTab.qml:544, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1226", - "comment": "" - }, - { - "term": "VRR Fullscreen Only", - "context": "VRR Fullscreen Only", - "reference": "Modules/Settings/DisplayConfig/DisplayConfigState.qml:1260", - "comment": "" - }, - { - "term": "VRR On-Demand", - "context": "VRR On-Demand", - "reference": "Modals/WindowRuleModal.qml:701, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1234", - "comment": "" - }, - { - "term": "Variable Refresh Rate", - "context": "Variable Refresh Rate", - "reference": "Modules/Settings/DisplayConfig/OutputCard.qml:265, Modules/Settings/DisplayConfig/OutputCard.qml:278, Modules/Settings/DisplayConfig/OutputCard.qml:301", - "comment": "" - }, - { - "term": "Verification", - "context": "Verification", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:70", - "comment": "Phone Connect pairing verification key label" - }, - { - "term": "Version", - "context": "Version", - "reference": "Modules/Settings/AboutTab.qml:648", - "comment": "" - }, - { - "term": "Vertical Deck", - "context": "Vertical Deck", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:55", - "comment": "" - }, - { - "term": "Vertical Grid", - "context": "Vertical Grid", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:54", - "comment": "" - }, - { - "term": "Vertical Scrolling", - "context": "Vertical Scrolling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:56", - "comment": "" - }, - { - "term": "Vertical Tiling", - "context": "Vertical Tiling", - "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:57", - "comment": "" - }, - { - "term": "Vibrant", - "context": "Vibrant", - "reference": "Common/Theme.qml:471", - "comment": "matugen color scheme option" - }, - { - "term": "Vibrant palette with playful saturation.", - "context": "Vibrant palette with playful saturation.", - "reference": "Common/Theme.qml:480", - "comment": "" - }, - { - "term": "Video Path", - "context": "Video Path", - "reference": "Modules/Settings/LockScreenTab.qml:295", - "comment": "" - }, - { - "term": "Video Screensaver", - "context": "Video Screensaver", - "reference": "Modules/Lock/VideoScreensaver.qml:57, Modules/Lock/VideoScreensaver.qml:102, Modules/Lock/VideoScreensaver.qml:126, Modules/Settings/LockScreenTab.qml:267", - "comment": "" - }, - { - "term": "Videos", - "context": "Videos", - "reference": "Modals/FileBrowser/FileBrowserContent.qml:266", - "comment": "" - }, - { - "term": "View Mode", - "context": "View Mode", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeatherSettings.qml:11", - "comment": "" - }, - { - "term": "Visibility", - "context": "Visibility", - "reference": "Modules/DankDash/WeatherForecastCard.qml:100, Modules/Settings/TimeWeatherTab.qml:1128, Modules/Settings/DankBarTab.qml:589", - "comment": "" - }, - { - "term": "Visual Effects", - "context": "Visual Effects", - "reference": "Modules/Settings/WidgetsTabSection.qml:2621", - "comment": "" - }, - { - "term": "Visual divider between widgets", - "context": "Visual divider between widgets", - "reference": "Modules/Settings/WidgetsTab.qml:212", - "comment": "" - }, - { - "term": "Visual effect used when wallpaper changes", - "context": "Visual effect used when wallpaper changes", - "reference": "Modules/Settings/WallpaperTab.qml:1154", - "comment": "" - }, - { - "term": "Volume", - "context": "Volume", - "reference": "Modules/Settings/WidgetsTabSection.qml:1244, Modules/Settings/WidgetsTabSection.qml:1448, Modules/Settings/OSDTab.qml:93", - "comment": "" - }, - { - "term": "Volume Changed", - "context": "Volume Changed", - "reference": "Modules/Settings/SoundsTab.qml:118", - "comment": "" - }, - { - "term": "Volume Slider", - "context": "Volume Slider", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:135", - "comment": "" - }, - { - "term": "Volume, brightness, and other system OSDs", - "context": "Volume, brightness, and other system OSDs", - "reference": "Modules/Settings/DisplayWidgetsTab.qml:50", - "comment": "" - }, - { - "term": "WPA/WPA2", - "context": "WPA/WPA2", - "reference": "Modules/Settings/NetworkTab.qml:1448", - "comment": "" - }, - { - "term": "Wallpaper", - "context": "Wallpaper", - "reference": "Widgets/KeybindItem.qml:1097, Widgets/KeybindItem.qml:1104, Widgets/KeybindItem.qml:1113, Modals/Greeter/GreeterCompletePage.qml:381, Modals/Settings/SettingsSidebar.qml:76, Modules/Settings/DisplayWidgetsTab.qml:43, Modules/Settings/WallpaperTab.qml:63", - "comment": "greeter settings link" - }, - { - "term": "Wallpaper Error", - "context": "Wallpaper Error", - "reference": "Modules/Settings/ThemeColorsTab.qml:466", - "comment": "wallpaper error status" - }, - { - "term": "Wallpaper Monitor", - "context": "Wallpaper Monitor", - "reference": "Modules/Settings/WallpaperTab.qml:819", - "comment": "" - }, - { - "term": "Wallpaper fill mode", - "context": "Wallpaper fill mode", - "reference": "Modules/Settings/GreeterTab.qml:692", - "comment": "" - }, - { - "term": "Wallpaper processing failed", - "context": "Wallpaper processing failed", - "reference": "Modules/Settings/ThemeColorsTab.qml:483", - "comment": "wallpaper processing error" - }, - { - "term": "Wallpaper processing failed - check wallpaper path", - "context": "Wallpaper processing failed - check wallpaper path", - "reference": "Modules/Settings/ThemeColorsTab.qml:310", - "comment": "wallpaper error" - }, - { - "term": "Wallpapers", - "context": "Wallpapers", - "reference": "Modules/DankDash/DankDashPopout.qml:279", - "comment": "" - }, - { - "term": "Warm color temperature to apply", - "context": "Warm color temperature to apply", - "reference": "Modules/Settings/GammaControlTab.qml:106", - "comment": "" - }, - { - "term": "Warning", - "context": "Warning", - "reference": "Services/CupsService.qml:835", - "comment": "" - }, - { - "term": "Warnings", - "context": "Warnings", - "reference": "Modals/Greeter/GreeterDoctorPage.qml:259", - "comment": "greeter doctor page status card" - }, - { - "term": "Wave Progress Bars", - "context": "Wave Progress Bars", - "reference": "Modules/Settings/MediaPlayerTab.qml:29", - "comment": "" - }, - { - "term": "Weather", - "context": "Weather", - "reference": "Widgets/KeybindItem.qml:1099, Widgets/KeybindItem.qml:1104, Widgets/KeybindItem.qml:1116, Modules/DankDash/DankDashPopout.qml:286, Modules/Settings/TimeWeatherTab.qml:392", - "comment": "" - }, - { - "term": "Weather Widget", - "context": "Weather Widget", - "reference": "Modules/Settings/WidgetsTab.qml:87", - "comment": "" - }, - { - "term": "Welcome", - "context": "Welcome", - "reference": "Modals/Greeter/GreeterModal.qml:89", - "comment": "greeter modal window title" - }, - { - "term": "Welcome to DankMaterialShell", - "context": "Welcome to DankMaterialShell", - "reference": "Modals/Greeter/GreeterWelcomePage.qml:47", - "comment": "greeter welcome page title" - }, - { - "term": "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window", - "context": "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window", - "reference": "Modules/Settings/DockTab.qml:167", - "comment": "" - }, - { - "term": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.", - "context": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.", - "reference": "Modules/Settings/LauncherTab.qml:340", - "comment": "" - }, - { - "term": "When locked", - "context": "When locked", - "reference": "Widgets/KeybindItem.qml:1754", - "comment": "" - }, - { - "term": "When updater widget is used, then hide it if no update found", - "context": "When updater widget is used, then hide it if no update found", - "reference": "Modules/Settings/SystemUpdaterTab.qml:30", - "comment": "" - }, - { - "term": "Wi-Fi Password", - "context": "Wi-Fi Password", - "reference": "Modals/WifiPasswordModal.qml:253", - "comment": "" - }, - { - "term": "Wi-Fi and Ethernet connection", - "context": "Wi-Fi and Ethernet connection", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:102", - "comment": "" - }, - { - "term": "Wi-Fi not available", - "context": "Wi-Fi not available", - "reference": "Modules/ControlCenter/Models/WidgetModel.qml:106", - "comment": "" - }, - { - "term": "WiFi", - "context": "WiFi", - "reference": "Modules/Settings/NetworkTab.qml:213, Modules/Settings/NetworkTab.qml:260, Modules/Settings/NetworkTab.qml:810, Modules/ControlCenter/Details/NetworkDetail.qml:136", - "comment": "" - }, - { - "term": "WiFi Device", - "context": "WiFi Device", - "reference": "Modules/Settings/NetworkTab.qml:868, Modules/Settings/NetworkTab.qml:900", - "comment": "" - }, - { - "term": "WiFi QR code for ", - "context": "WiFi QR code for ", - "reference": "Modals/WifiQRCodeModal.qml:125", - "comment": "" - }, - { - "term": "WiFi disabled", - "context": "WiFi disabled", - "reference": "Services/DMSNetworkService.qml:571", - "comment": "" - }, - { - "term": "WiFi enabled", - "context": "WiFi enabled", - "reference": "Services/DMSNetworkService.qml:571, Services/DMSNetworkService.qml:583", - "comment": "" - }, - { - "term": "WiFi is off", - "context": "WiFi is off", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:225", - "comment": "" - }, - { - "term": "WiFi off", - "context": "WiFi off", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:308", - "comment": "network status" - }, - { - "term": "Wide (BT2020)", - "context": "Wide (BT2020)", - "reference": "Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:145, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:149, Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml:160", - "comment": "" - }, - { - "term": "Widget Background Color", - "context": "Widget Background Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:1521", - "comment": "" - }, - { - "term": "Widget Management", - "context": "Widget Management", - "reference": "Modules/Settings/WidgetsTab.qml:866", - "comment": "" - }, - { - "term": "Widget Outline", - "context": "Widget Outline", - "reference": "Modules/Settings/DankBarTab.qml:1474", - "comment": "" - }, - { - "term": "Widget Style", - "context": "Widget Style", - "reference": "Modules/Settings/ThemeColorsTab.qml:1506", - "comment": "" - }, - { - "term": "Widget Styling", - "context": "Widget Styling", - "reference": "Modules/Settings/ThemeColorsTab.qml:1498", - "comment": "" - }, - { - "term": "Widget Transparency", - "context": "Widget Transparency", - "reference": "Modules/Settings/DankBarTab.qml:1028", - "comment": "" - }, - { - "term": "Widget added", - "context": "Widget added", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:44", - "comment": "" - }, - { - "term": "Widget removed", - "context": "Widget removed", - "reference": "Modules/Settings/DesktopWidgetsTab.qml:371, Modules/Settings/DesktopWidgetsTab.qml:544", - "comment": "" - }, - { - "term": "Widgets", - "context": "Widgets", - "reference": "Modals/Settings/SettingsSidebar.qml:120, Modals/Settings/SettingsSidebar.qml:224", - "comment": "settings_displays" - }, - { - "term": "Widgets, layout, style", - "context": "Widgets, layout, style", - "reference": "Modals/Greeter/GreeterCompletePage.qml:406", - "comment": "greeter dankbar description" - }, - { - "term": "Width", - "context": "Width", - "reference": "Modules/Settings/WindowRulesTab.qml:542", - "comment": "" - }, - { - "term": "Width of window border (borderpx)", - "context": "Width of window border (borderpx)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2197", - "comment": "" - }, - { - "term": "Width of window border (general.border_size)", - "context": "Width of window border (general.border_size)", - "reference": "Modules/Settings/ThemeColorsTab.qml:2094", - "comment": "" - }, - { - "term": "Width of window border and focus ring", - "context": "Width of window border and focus ring", - "reference": "Modules/Settings/ThemeColorsTab.qml:1991", - "comment": "" - }, - { - "term": "Wind", - "context": "Wind", - "reference": "dms-plugins/DankDesktopWeather/DankDesktopWeather.qml:425, Modules/DankDash/WeatherTab.qml:89, Modules/Settings/TimeWeatherTab.qml:977", - "comment": "" - }, - { - "term": "Wind Speed", - "context": "Wind Speed", - "reference": "Modules/DankDash/WeatherForecastCard.qml:85", - "comment": "" - }, - { - "term": "Wind Speed in m/s", - "context": "Wind Speed in m/s", - "reference": "Modules/Settings/TimeWeatherTab.qml:440", - "comment": "" - }, - { - "term": "Window Corner Radius", - "context": "Window Corner Radius", - "reference": "Modules/Settings/ThemeColorsTab.qml:1959, Modules/Settings/ThemeColorsTab.qml:2165", - "comment": "" - }, - { - "term": "Window Gaps", - "context": "Window Gaps", - "reference": "Modules/Settings/ThemeColorsTab.qml:1928, Modules/Settings/ThemeColorsTab.qml:2031, Modules/Settings/ThemeColorsTab.qml:2134", - "comment": "" - }, - { - "term": "Window Gaps (px)", - "context": "Window Gaps (px)", - "reference": "Modules/Settings/DisplayConfig/NiriOutputSettings.qml:217", - "comment": "" - }, - { - "term": "Window Height", - "context": "Window Height", - "reference": "Modals/WindowRuleModal.qml:646", - "comment": "" - }, - { - "term": "Window Opening", - "context": "Window Opening", - "reference": "Modals/WindowRuleModal.qml:518", - "comment": "" - }, - { - "term": "Window Rounding", - "context": "Window Rounding", - "reference": "Modules/Settings/ThemeColorsTab.qml:2062", - "comment": "" - }, - { - "term": "Window Rules", - "context": "Window Rules", - "reference": "Modals/Settings/SettingsSidebar.qml:277, Modules/Settings/WindowRulesTab.qml:247", - "comment": "" - }, - { - "term": "Window Rules Include Missing", - "context": "Window Rules Include Missing", - "reference": "Modules/Settings/WindowRulesTab.qml:345", - "comment": "" - }, - { - "term": "Window Rules Not Configured", - "context": "Window Rules Not Configured", - "reference": "Modules/Settings/WindowRulesTab.qml:345", - "comment": "" - }, - { - "term": "Wipe", - "context": "Wipe", - "reference": "Modules/Settings/WallpaperTab.qml:1165", - "comment": "wallpaper transition option" - }, - { - "term": "Workspace", - "context": "Workspace", - "reference": "Modals/WindowRuleModal.qml:586, Modals/WindowRuleModal.qml:1076, Widgets/DankIconPicker.qml:27, Modules/Settings/DankBarTab.qml:729, Modules/Settings/DankBarTab.qml:729, Modules/Settings/DankBarTab.qml:766, Modules/Settings/WindowRulesTab.qml:541, Modules/Settings/WindowRulesTab.qml:568", - "comment": "" - }, - { - "term": "Workspace Appearance", - "context": "Workspace Appearance", - "reference": "Modules/Settings/WorkspacesTab.qml:192", - "comment": "" - }, - { - "term": "Workspace Index Numbers", - "context": "Workspace Index Numbers", - "reference": "Modules/Settings/WorkspacesTab.qml:32", - "comment": "" - }, - { - "term": "Workspace Names", - "context": "Workspace Names", - "reference": "Modules/Settings/WorkspacesTab.qml:41", - "comment": "" - }, - { - "term": "Workspace Padding", - "context": "Workspace Padding", - "reference": "Modules/Settings/WorkspacesTab.qml:50", - "comment": "" - }, - { - "term": "Workspace Settings", - "context": "Workspace Settings", - "reference": "Modules/Settings/WorkspacesTab.qml:26", - "comment": "" - }, - { - "term": "Workspace Switcher", - "context": "Workspace Switcher", - "reference": "Modules/Settings/WidgetsTab.qml:52", - "comment": "" - }, - { - "term": "Workspace name", - "context": "Workspace name", - "reference": "Modals/WorkspaceRenameModal.qml:134", - "comment": "" - }, - { - "term": "Workspaces", - "context": "Workspaces", - "reference": "Modals/Settings/SettingsSidebar.qml:134", - "comment": "" - }, - { - "term": "Workspaces & Widgets", - "context": "Workspaces & Widgets", - "reference": "Modals/Settings/SettingsSidebar.qml:128, Modals/Settings/SettingsSidebar.qml:551", - "comment": "" - }, - { - "term": "Write:", - "context": "Write:", - "reference": "Modules/ProcessList/DisksView.qml:91", - "comment": "disk write label" - }, - { - "term": "X Axis", - "context": "X Axis", - "reference": "Modules/Settings/DankBarTab.qml:764", - "comment": "" - }, - { - "term": "Y Axis", - "context": "Y Axis", - "reference": "Modules/Settings/DankBarTab.qml:728", - "comment": "" - }, - { - "term": "Yes", - "context": "Yes", - "reference": "Modules/Settings/PrinterTab.qml:1169, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1232, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1236, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1246, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1256, Modules/Settings/DisplayConfig/DisplayConfigState.qml:1258", - "comment": "" - }, - { - "term": "Yesterday", - "context": "Yesterday", - "reference": "Modules/Notifications/Center/HistoryNotificationList.qml:102", - "comment": "notification history filter" - }, - { - "term": "You have unsaved changes. Save before closing this tab?", - "context": "You have unsaved changes. Save before closing this tab?", - "reference": "Modules/Notepad/Notepad.qml:413", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before continuing?", - "context": "You have unsaved changes. Save before continuing?", - "reference": "Modules/Notepad/Notepad.qml:413", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before creating a new file?", - "context": "You have unsaved changes. Save before creating a new file?", - "reference": "Modules/Notepad/Notepad.qml:413", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before opening a file?", - "context": "You have unsaved changes. Save before opening a file?", - "reference": "Modules/Notepad/Notepad.qml:413", - "comment": "" - }, - { - "term": "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", - "context": "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", - "reference": "Modules/Settings/ThemeColorsTab.qml:2464", - "comment": "qt theme env error body" - }, - { - "term": "You're All Set!", - "context": "You're All Set!", - "reference": "Modals/Greeter/GreeterCompletePage.qml:105", - "comment": "greeter completion page title" - }, - { - "term": "Your system is up to date!", - "context": "Your system is up to date!", - "reference": "Modules/SystemUpdatePopout.qml:150", - "comment": "" - }, - { - "term": "actions", - "context": "actions", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:432", - "comment": "" - }, - { - "term": "attached", - "context": "attached", - "reference": "Modals/MuxModal.qml:484", - "comment": "" - }, - { - "term": "brandon", - "context": "brandon", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:44", - "comment": "" - }, - { - "term": "by %1", - "context": "by %1", - "reference": "Modules/Settings/PluginBrowser.qml:539, Modules/Settings/ThemeBrowser.qml:527", - "comment": "author attribution" - }, - { - "term": "days", - "context": "days", - "reference": "Modules/Settings/NotificationsTab.qml:849, Modules/Settings/ClipboardTab.qml:179", - "comment": "" - }, - { - "term": "detached", - "context": "detached", - "reference": "Modals/MuxModal.qml:484", - "comment": "" - }, - { - "term": "device", - "context": "device", - "reference": "dms-plugins/DankKDEConnect/DankKDEConnect.qml:91, dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:272", - "comment": "Generic device name | Generic device name fallback" - }, - { - "term": "devices connected", - "context": "devices connected", - "reference": "dms-plugins/DankKDEConnect/components/KDEConnectDetailContent.qml:38", - "comment": "KDE Connect status multiple devices" - }, - { - "term": "dgop not available", - "context": "dgop not available", - "reference": "Modules/ControlCenter/Details/DiskUsageDetail.qml:65, Modules/ControlCenter/Widgets/DiskUsagePill.qml:45", - "comment": "" - }, - { - "term": "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.", - "context": "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.", - "reference": "Modules/Settings/AboutTab.qml:585", - "comment": "" - }, - { - "term": "dms/cursor config exists but is not included. Cursor settings won't apply.", - "context": "dms/cursor config exists but is not included. Cursor settings won't apply.", - "reference": "Modules/Settings/ThemeColorsTab.qml:2306", - "comment": "" - }, - { - "term": "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.", - "context": "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.", - "reference": "Modules/Settings/DisplayConfig/IncludeWarningBox.qml:65", - "comment": "" - }, - { - "term": "e.g., firefox, kitty --title foo", - "context": "e.g., firefox, kitty --title foo", - "reference": "Widgets/KeybindItem.qml:1477", - "comment": "" - }, - { - "term": "e.g., focus-workspace 3, resize-column -10", - "context": "e.g., focus-workspace 3, resize-column -10", - "reference": "Widgets/KeybindItem.qml:1414", - "comment": "" - }, - { - "term": "e.g., notify-send 'Hello' && sleep 1", - "context": "e.g., notify-send 'Hello' && sleep 1", - "reference": "Widgets/KeybindItem.qml:1509", - "comment": "" - }, - { - "term": "e.g., scratch, /^tmp_.*/, build", - "context": "e.g., scratch, /^tmp_.*/, build", - "reference": "Modules/Settings/MuxTab.qml:105", - "comment": "" - }, - { - "term": "events", - "context": "events", - "reference": "Modules/DankDash/Overview/CalendarOverviewCard.qml:178", - "comment": "" - }, - { - "term": "ext", - "context": "ext", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:726", - "comment": "" - }, - { - "term": "featured", - "context": "featured", - "reference": "Modules/Settings/PluginBrowser.qml:487, Modules/Settings/DesktopWidgetBrowser.qml:389", - "comment": "" - }, - { - "term": "leave empty for default", - "context": "leave empty for default", - "reference": "Widgets/KeybindItem.qml:1045", - "comment": "" - }, - { - "term": "loginctl not available - lock integration requires DMS socket connection", - "context": "loginctl not available - lock integration requires DMS socket connection", - "reference": "Modules/Settings/LockScreenTab.qml:166", - "comment": "" - }, - { - "term": "mangowc Discord Server", - "context": "mangowc Discord Server", - "reference": "Modules/Settings/AboutTab.qml:100", - "comment": "" - }, - { - "term": "mangowc GitHub", - "context": "mangowc GitHub", - "reference": "Modules/Settings/AboutTab.qml:79", - "comment": "" - }, - { - "term": "matugen not found - install matugen package for dynamic theming", - "context": "matugen not found - install matugen package for dynamic theming", - "reference": "Modules/Settings/ThemeColorsTab.qml:308", - "comment": "matugen error" - }, - { - "term": "minutes", - "context": "minutes", - "reference": "Modules/Settings/NotificationsTab.qml:171, Modules/Notifications/Center/NotificationSettings.qml:106", - "comment": "" - }, - { - "term": "ms", - "context": "ms", - "reference": "Widgets/KeybindItem.qml:1695", - "comment": "" - }, - { - "term": "nav", - "context": "nav", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:418", - "comment": "" - }, - { - "term": "niri GitHub", - "context": "niri GitHub", - "reference": "Modules/Settings/AboutTab.qml:82", - "comment": "" - }, - { - "term": "niri Matrix Chat", - "context": "niri Matrix Chat", - "reference": "Modules/Settings/AboutTab.qml:399", - "comment": "" - }, - { - "term": "niri shortcuts config", - "context": "niri shortcuts config", - "reference": "Modals/Greeter/GreeterCompletePage.qml:414", - "comment": "greeter keybinds niri description" - }, - { - "term": "niri/dms Discord", - "context": "niri/dms Discord", - "reference": "Modules/Settings/AboutTab.qml:86", - "comment": "" - }, - { - "term": "now", - "context": "now", - "reference": "Services/NotificationService.qml:268", - "comment": "" - }, - { - "term": "official", - "context": "official", - "reference": "Modules/Settings/PluginBrowser.qml:509, Modules/Settings/ThemeBrowser.qml:494", - "comment": "" - }, - { - "term": "on Hyprland", - "context": "on Hyprland", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:69", - "comment": "" - }, - { - "term": "on MangoWC", - "context": "on MangoWC", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:72", - "comment": "" - }, - { - "term": "on Miracle WM", - "context": "on Miracle WM", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:78", - "comment": "" - }, - { - "term": "on Niri", - "context": "on Niri", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:67", - "comment": "" - }, - { - "term": "on Scroll", - "context": "on Scroll", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:76", - "comment": "" - }, - { - "term": "on Sway", - "context": "on Sway", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:74", - "comment": "" - }, - { - "term": "open", - "context": "open", - "reference": "Modals/DankLauncherV2/LauncherContent.qml:425", - "comment": "" - }, - { - "term": "or run ", - "context": "or run ", - "reference": "Modules/Settings/GreeterTab.qml:765", - "comment": "" - }, - { - "term": "power-profiles-daemon not available", - "context": "power-profiles-daemon not available", - "reference": "Modules/DankBar/Popouts/BatteryPopout.qml:25", - "comment": "" - }, - { - "term": "procs", - "context": "procs", - "reference": "Modules/ProcessList/ProcessListPopout.qml:288", - "comment": "short for processes" - }, - { - "term": "r/niri Subreddit", - "context": "r/niri Subreddit", - "reference": "Modules/Settings/AboutTab.qml:105", - "comment": "" - }, - { - "term": "seconds", - "context": "seconds", - "reference": "Modules/Settings/NotificationsTab.qml:170, Modules/Notifications/Center/NotificationSettings.qml:104", - "comment": "" - }, - { - "term": "source", - "context": "source", - "reference": "Modules/Settings/PluginBrowser.qml:540", - "comment": "source code link" - }, - { - "term": "this app", - "context": "this app", - "reference": "Modules/Notifications/Popup/NotificationPopup.qml:1114, Modules/Notifications/Popup/NotificationPopup.qml:1114, Modules/Notifications/Center/NotificationCard.qml:1016, Modules/Notifications/Center/NotificationCard.qml:1016", - "comment": "" - }, - { - "term": "up", - "context": "up", - "reference": "Modules/DankDash/Overview/UserInfoCard.qml:102", - "comment": "" - }, - { - "term": "update dms for NM integration.", - "context": "update dms for NM integration.", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:223", - "comment": "" - }, - { - "term": "v%1 by %2", - "context": "v%1 by %2", - "reference": "Modules/Settings/PluginListItem.qml:169", - "comment": "" - }, - { - "term": "wtype not available - install wtype for paste support", - "context": "wtype not available - install wtype for paste support", - "reference": "Services/ClipboardService.qml:118", - "comment": "" - }, - { - "term": "• Install only from trusted sources", - "context": "• Install only from trusted sources", - "reference": "Modules/Settings/PluginBrowser.qml:816", - "comment": "" - }, - { - "term": "• M - Month (1-12)", - "context": "• M - Month (1-12)", - "reference": "Modules/Settings/TimeWeatherTab.qml:348", - "comment": "" - }, - { - "term": "• MM - Month (01-12)", - "context": "• MM - Month (01-12)", - "reference": "Modules/Settings/TimeWeatherTab.qml:359", - "comment": "" - }, - { - "term": "• MMM - Month (Jan)", - "context": "• MMM - Month (Jan)", - "reference": "Modules/Settings/TimeWeatherTab.qml:364", - "comment": "" - }, - { - "term": "• MMMM - Month (January)", - "context": "• MMMM - Month (January)", - "reference": "Modules/Settings/TimeWeatherTab.qml:369", - "comment": "" - }, - { - "term": "• Plugins may contain bugs or security issues", - "context": "• Plugins may contain bugs or security issues", - "reference": "Modules/Settings/PluginBrowser.qml:804", - "comment": "" - }, - { - "term": "• Review code before installation when possible", - "context": "• Review code before installation when possible", - "reference": "Modules/Settings/PluginBrowser.qml:810", - "comment": "" - }, - { - "term": "• d - Day (1-31)", - "context": "• d - Day (1-31)", - "reference": "Modules/Settings/TimeWeatherTab.qml:328", - "comment": "" - }, - { - "term": "• dd - Day (01-31)", - "context": "• dd - Day (01-31)", - "reference": "Modules/Settings/TimeWeatherTab.qml:333", - "comment": "" - }, - { - "term": "• ddd - Day name (Mon)", - "context": "• ddd - Day name (Mon)", - "reference": "Modules/Settings/TimeWeatherTab.qml:338", - "comment": "" - }, - { - "term": "• dddd - Day name (Monday)", - "context": "• dddd - Day name (Monday)", - "reference": "Modules/Settings/TimeWeatherTab.qml:343", - "comment": "" - }, - { - "term": "• yy - Year (24)", - "context": "• yy - Year (24)", - "reference": "Modules/Settings/TimeWeatherTab.qml:374", - "comment": "" - }, - { - "term": "• yyyy - Year (2024)", - "context": "• yyyy - Year (2024)", - "reference": "Modules/Settings/TimeWeatherTab.qml:379", - "comment": "" - }, - { - "term": "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text", - "context": "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text", - "reference": "Modules/Notifications/Center/NotificationKeyboardHints.qml:26", - "comment": "" - }, - { - "term": "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help", - "context": "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help", - "reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:31", - "comment": "" - }, - { - "term": "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", - "context": "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", - "reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:30", - "comment": "Keyboard hints when enter-to-paste is enabled" - } -] diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_settings_index.py b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_settings_index.py deleted file mode 100755 index 8a7b935..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_settings_index.py +++ /dev/null @@ -1,522 +0,0 @@ -#!/usr/bin/env python3 -import json -import re -from collections import Counter -from pathlib import Path - -ABBREVIATIONS = { - "on-screen displays": ["osd"], - "on-screen display": ["osd"], - "do not disturb": ["dnd"], - "keyboard shortcuts": ["keybinds", "hotkeys", "bindings", "keys"], - "notifications": ["notif", "notifs", "alerts"], - "notification": ["notif", "alert"], - "wallpaper": ["background", "bg", "image", "picture", "desktop"], - "transparency": ["opacity", "alpha", "translucent", "transparent"], - "visibility": ["visible", "hide", "show", "hidden", "autohide", "auto-hide"], - "temperature": ["temp", "celsius", "fahrenheit"], - "configuration": ["config", "configure", "setup"], - "applications": ["apps", "programs"], - "application": ["app", "program"], - "animation": ["motion", "transition", "animate", "animations"], - "typography": ["font", "fonts", "text", "typeface"], - "workspaces": ["workspace", "desktops", "virtual"], - "workspace": ["desktop", "virtual"], - "bluetooth": ["bt"], - "network": ["wifi", "wi-fi", "ethernet", "internet", "connection", "wireless"], - "display": ["monitor", "screen", "output"], - "displays": ["monitors", "screens", "outputs"], - "brightness": ["bright", "dim", "backlight"], - "volume": ["audio", "sound", "speaker", "loudness"], - "battery": ["power", "charge", "charging"], - "clock": ["time", "watch"], - "calendar": ["date", "day", "month", "year"], - "launcher": ["app drawer", "app menu", "start menu", "applications"], - "dock": ["taskbar", "panel"], - "bar": ["panel", "taskbar", "topbar", "statusbar"], - "theme": ["appearance", "look", "style", "colors", "colour"], - "color": ["colour", "hue", "tint"], - "colors": ["colours", "palette"], - "dark": ["night", "dark mode"], - "light": ["day", "light mode"], - "lock screen": ["lockscreen", "login", "security"], - "power": ["shutdown", "reboot", "restart", "suspend", "hibernate", "sleep"], - "idle": ["afk", "inactive", "timeout", "screensaver"], - "gamma": ["color temperature", "night light", "blue light", "redshift"], - "media player": ["mpris", "music", "audio", "playback"], - "clipboard": ["copy", "paste", "cliphist", "history"], - "updater": ["updates", "upgrade", "packages"], - "plugins": ["extensions", "addons", "widgets"], - "spacing": ["gap", "gaps", "margin", "margins", "padding"], - "corner": ["corners", "rounded", "radius", "round"], - "matugen": ["dynamic", "wallpaper colors", "material"], - "running apps": ["taskbar", "windows", "active", "open"], - "weather": ["forecast", "temperature", "climate"], - "sounds": ["audio", "effects", "sfx"], - "printers": ["print", "cups", "printing"], - "widgets": ["components", "modules"], -} - -CATEGORY_KEYWORDS = { - "Personalization": ["customize", "custom", "personal", "appearance"], - "Time & Weather": ["clock", "forecast", "date"], - "Keyboard Shortcuts": ["keys", "bindings", "hotkey"], - "Dank Bar": ["panel", "topbar", "statusbar"], - "Workspaces": ["virtual desktops", "spaces"], - "Dock": ["taskbar", "launcher bar"], - "Network": ["connectivity", "online"], - "System": ["os", "linux"], - "Launcher": ["start", "menu", "drawer"], - "Theme & Colors": ["appearance", "look", "style", "scheme"], - "Lock Screen": ["security", "login", "password"], - "Plugins": ["extend", "addon"], - "About": ["info", "version", "credits", "help"], - "Typography & Motion": ["fonts", "animation", "text"], - "Sounds": ["audio", "sfx", "effects"], - "Media Player": ["music", "spotify", "mpris"], - "Notifications": ["alerts", "messages", "toast"], - "On-screen Displays": ["osd", "indicator", "popup"], - "Running Apps": ["windows", "tasks", "active"], - "System Updater": ["packages", "upgrade"], - "Power & Sleep": ["shutdown", "suspend", "energy"], - "Displays": ["monitor", "screen", "resolution"], - "Desktop Widgets": ["conky", "desktop clock"], - "Audio": ["sound", "volume", "speaker", "microphone", "headphones", "pipewire"], - "Window Rules": [ - "window", - "rules", - "matching", - "floating", - "fullscreen", - "opacity", - ], - "Locale": ["locale", "language", "country"], -} - -TAB_INDEX_MAP = { - "WallpaperTab.qml": 0, - "TimeWeatherTab.qml": 1, - "KeybindsTab.qml": 2, - "DankBarTab.qml": 3, - "WorkspacesTab.qml": 4, - "DockTab.qml": 5, - "NetworkTab.qml": 7, - "PrinterTab.qml": 8, - "LauncherTab.qml": 9, - "ThemeColorsTab.qml": 10, - "LockScreenTab.qml": 11, - "PluginsTab.qml": 12, - "AboutTab.qml": 13, - "TypographyMotionTab.qml": 14, - "SoundsTab.qml": 15, - "MediaPlayerTab.qml": 16, - "NotificationsTab.qml": 17, - "OSDTab.qml": 18, - "RunningAppsTab.qml": 19, - "SystemUpdaterTab.qml": 20, - "PowerSleepTab.qml": 21, - "WidgetsTab.qml": 22, - "ClipboardTab.qml": 23, - "DisplayConfigTab.qml": 24, - "GammaControlTab.qml": 25, - "DisplayWidgetsTab.qml": 26, - "DesktopWidgetsTab.qml": 27, - "WindowRulesTab.qml": 28, - "AudioTab.qml": 29, - "LocaleTab.qml": 30, -} - -TAB_CATEGORY_MAP = { - 0: "Personalization", - 1: "Time & Weather", - 2: "Keyboard Shortcuts", - 3: "Dank Bar", - 4: "Workspaces", - 5: "Dock", - 7: "Network", - 8: "System", - 9: "Launcher", - 10: "Theme & Colors", - 11: "Lock Screen", - 12: "Plugins", - 13: "About", - 14: "Typography & Motion", - 15: "Sounds", - 16: "Media Player", - 17: "Notifications", - 18: "On-screen Displays", - 19: "Running Apps", - 20: "System Updater", - 21: "Power & Sleep", - 22: "Dank Bar", - 23: "System", - 24: "Displays", - 25: "Displays", - 26: "Displays", - 27: "Desktop Widgets", - 28: "Window Rules", - 29: "Audio", - 30: "Locale", -} - -SEARCHABLE_COMPONENTS = [ - "SettingsCard", - "SettingsToggleRow", - "SettingsSliderCard", - "SettingsDropdownRow", - "SettingsButtonGroupRow", - "SettingsSliderRow", - "SettingsToggleCard", -] - -STOPWORDS = { - "the", - "and", - "for", - "with", - "from", - "this", - "that", - "are", - "was", - "will", - "can", - "has", - "have", - "been", - "when", - "your", - "use", - "used", - "using", - "instead", - "like", - "such", - "also", - "only", - "which", - "each", - "other", - "some", - "into", - "than", - "then", - "them", - "these", - "those", -} - - -def enrich_keywords(label, description, category, existing_tags): - keywords = set(existing_tags) - - label_lower = label.lower() - label_words = re.split(r"[\s\-_&/]+", label_lower) - keywords.update(w for w in label_words if len(w) > 2) - - for term, aliases in ABBREVIATIONS.items(): - if term in label_lower: - keywords.update(aliases) - - if description: - desc_lower = description.lower() - desc_words = re.split(r"[\s\-_&/,.]+", desc_lower) - keywords.update(w for w in desc_words if len(w) > 3 and w.isalpha()) - for term, aliases in ABBREVIATIONS.items(): - if term in desc_lower: - keywords.update(aliases) - - if category in CATEGORY_KEYWORDS: - keywords.update(CATEGORY_KEYWORDS[category]) - - cat_lower = category.lower() - cat_words = re.split(r"[\s\-_&/]+", cat_lower) - keywords.update(w for w in cat_words if len(w) > 2) - - keywords = {k for k in keywords if k not in STOPWORDS and len(k) > 1} - return sorted(keywords) - - -def extract_i18n_string(value): - match = re.search(r'I18n\.tr\(["\']([^"\']+)["\']', value) - if match: - return match.group(1) - match = re.search(r'^["\']([^"\']+)["\']$', value.strip()) - if match: - return match.group(1) - return None - - -def extract_tags(value): - match = re.search(r"\[([^\]]+)\]", value) - if not match: - return [] - content = match.group(1) - tags = re.findall(r'["\']([^"\']+)["\']', content) - return tags - - -def parse_component_block(content, start_pos, component_name): - brace_count = 0 - started = False - block_start = start_pos - - for i in range(start_pos, len(content)): - if content[i] == "{": - if not started: - block_start = i - started = True - brace_count += 1 - elif content[i] == "}": - brace_count -= 1 - if started and brace_count == 0: - return content[block_start : i + 1] - return "" - - -def extract_property(block, prop_name): - pattern = rf"{prop_name}\s*:\s*([^\n]+)" - match = re.search(pattern, block) - if match: - return match.group(1).strip() - return None - - -def find_settings_components(content, filename): - results = [] - tab_index = TAB_INDEX_MAP.get(filename, -1) - - if tab_index == -1: - return results - - for component in SEARCHABLE_COMPONENTS: - pattern = rf"\b{component}\s*\{{" - for match in re.finditer(pattern, content): - block = parse_component_block(content, match.start(), component) - if not block: - continue - - setting_key = extract_property(block, "settingKey") - if setting_key: - setting_key = setting_key.strip("\"'") - - if not setting_key: - continue - - title_raw = extract_property(block, "title") - text_raw = extract_property(block, "text") - label = None - if title_raw: - label = extract_i18n_string(title_raw) - if not label and text_raw: - label = extract_i18n_string(text_raw) - - if not label: - continue - - icon_raw = extract_property(block, "iconName") - icon = None - if icon_raw: - icon = icon_raw.strip("\"'") - if icon.startswith("{") or "?" in icon: - icon = None - - tags_raw = extract_property(block, "tags") - tags = [] - if tags_raw: - tags = extract_tags(tags_raw) - - desc_raw = extract_property(block, "description") - description = None - if desc_raw: - description = extract_i18n_string(desc_raw) - - visible_raw = extract_property(block, "visible") - condition_key = None - if visible_raw: - if "CompositorService.isNiri" in visible_raw: - condition_key = "isNiri" - elif "CompositorService.isHyprland" in visible_raw: - condition_key = "isHyprland" - elif "KeybindsService.available" in visible_raw: - condition_key = "keybindsAvailable" - elif "AudioService.soundsAvailable" in visible_raw: - condition_key = "soundsAvailable" - elif "CupsService.cupsAvailable" in visible_raw: - condition_key = "cupsAvailable" - elif "NetworkService.usingLegacy" in visible_raw: - condition_key = "networkNotLegacy" - elif "DMSService.isConnected" in visible_raw: - condition_key = "dmsConnected" - elif "Theme.matugenAvailable" in visible_raw: - condition_key = "matugenAvailable" - elif "CompositorService.isDwl" in visible_raw: - condition_key = "isDwl" - - category = TAB_CATEGORY_MAP.get(tab_index, "Settings") - enriched_keywords = enrich_keywords(label, description, category, tags) - - entry = { - "section": setting_key, - "label": label, - "tabIndex": tab_index, - "category": category, - "keywords": enriched_keywords, - } - - if icon: - entry["icon"] = icon - if description: - entry["description"] = description - if condition_key: - entry["conditionKey"] = condition_key - - results.append(entry) - - return results - - -def parse_tabs_from_sidebar(sidebar_file): - with open(sidebar_file, "r", encoding="utf-8") as f: - content = f.read() - - pattern = r'"text"\s*:\s*I18n\.tr\("([^"]+)"(?:,\s*"[^"]+")?\).*?"icon"\s*:\s*"([^"]+)".*?"tabIndex"\s*:\s*(\d+)' - tabs = [] - - for match in re.finditer(pattern, content, re.DOTALL): - label, icon, tab_idx = match.group(1), match.group(2), int(match.group(3)) - - before_text = content[: match.start()] - parent_match = re.search( - r'"text"\s*:\s*I18n\.tr\("([^"]+)"\)[^{]*"children"[^[]*\[[^{]*$', - before_text, - ) - parent = parent_match.group(1) if parent_match else None - - cond = None - after_pos = match.end() - snippet = content[match.start() : min(after_pos + 200, len(content))] - for qml_cond, key in [ - ("shortcutsOnly", "keybindsAvailable"), - ("soundsOnly", "soundsAvailable"), - ("cupsOnly", "cupsAvailable"), - ("dmsOnly", "dmsConnected"), - ("hyprlandNiriOnly", "isHyprlandOrNiri"), - ("clipboardOnly", "dmsConnected"), - ("niriOnly", "isNiri"), - ]: - if f'"{qml_cond}": true' in snippet: - cond = key - break - - tabs.append( - { - "tabIndex": tab_idx, - "label": label, - "icon": icon, - "parent": parent, - "conditionKey": cond, - } - ) - - return tabs - - -def generate_tab_entries(sidebar_file): - tabs = parse_tabs_from_sidebar(sidebar_file) - - label_counts = Counter([t["label"] for t in tabs]) - - entries = [] - for tab in tabs: - label = ( - f"{tab['parent']}: {tab['label']}" - if label_counts[tab["label"]] > 1 and tab["parent"] - else tab["label"] - ) - category = TAB_CATEGORY_MAP.get(tab["tabIndex"], "Settings") - - keywords = enrich_keywords(tab["label"], None, category, []) - - if tab["parent"]: - parent_keywords = [ - w for w in re.split(r"[\s\-_&/]+", tab["parent"].lower()) if len(w) > 2 - ] - keywords = sorted( - set( - keywords - + parent_keywords - + [k for p in parent_keywords for k in ABBREVIATIONS.get(p, [])] - ) - ) - - entry = { - "section": f"_tab_{tab['tabIndex']}", - "label": label, - "tabIndex": tab["tabIndex"], - "category": category, - "keywords": keywords, - "icon": tab["icon"], - } - if tab["conditionKey"]: - entry["conditionKey"] = tab["conditionKey"] - entries.append(entry) - - return entries - - -def extract_settings_index(root_dir): - settings_dir = Path(root_dir) / "Modules" / "Settings" - all_entries = [] - seen_keys = set() - - for qml_file in settings_dir.glob("*.qml"): - if not qml_file.name.endswith("Tab.qml"): - continue - - with open(qml_file, "r", encoding="utf-8") as f: - content = f.read() - - entries = find_settings_components(content, qml_file.name) - for entry in entries: - key = entry["section"] - if key not in seen_keys: - seen_keys.add(key) - all_entries.append(entry) - - return all_entries - - -def main(): - script_dir = Path(__file__).parent - root_dir = script_dir.parent - sidebar_file = root_dir / "Modals" / "Settings" / "SettingsSidebar.qml" - - print("Extracting settings search index...") - settings_entries = extract_settings_index(root_dir) - tab_entries = generate_tab_entries(sidebar_file) - - all_entries = tab_entries + settings_entries - - all_entries.sort(key=lambda x: (x["tabIndex"], x["label"])) - - output_path = script_dir / "settings_search_index.json" - with open(output_path, "w", encoding="utf-8") as f: - json.dump(all_entries, f, indent=2, ensure_ascii=False) - - print(f"Found {len(settings_entries)} searchable settings") - print(f"Found {len(tab_entries)} tab entries") - print(f"Total: {len(all_entries)} entries") - print(f"Output: {output_path}") - - conditions = set() - for entry in all_entries: - if "conditionKey" in entry: - conditions.add(entry["conditionKey"]) - - if conditions: - print(f"Condition keys found: {', '.join(sorted(conditions))}") - - -if __name__ == "__main__": - main() diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_translations.py b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_translations.py deleted file mode 100755 index 5e78549..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/extract_translations.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -import ast -import re -import json -from pathlib import Path -from collections import defaultdict - - -def decode_string_literal(content, quote): - try: - return ast.literal_eval(f"{quote}{content}{quote}") - except (ValueError, SyntaxError): - return content - - -def spans_overlap(a, b): - return a[0] < b[1] and b[0] < a[1] - - -def extract_qstr_strings(root_dir): - translations = defaultdict(lambda: {'contexts': set(), 'occurrences': []}) - qstr_patterns = [ - (re.compile(r'qsTr\(\s*"((?:\\.|[^"\\])*)"\s*\)'), '"'), - (re.compile(r"qsTr\(\s*'((?:\\.|[^'\\])*)'\s*\)"), "'") - ] - i18n_context_patterns = [ - ( - re.compile(r'I18n\.tr\(\s*"((?:\\.|[^"\\])*)"\s*,\s*"((?:\\.|[^"\\])*)"\s*\)'), - '"' - ), - ( - re.compile(r"I18n\.tr\(\s*'((?:\\.|[^'\\])*)'\s*,\s*'((?:\\.|[^'\\])*)'\s*\)"), - "'" - ) - ] - i18n_simple_patterns = [ - (re.compile(r'I18n\.tr\(\s*"((?:\\.|[^"\\])*)"\s*\)'), '"'), - (re.compile(r"I18n\.tr\(\s*'((?:\\.|[^'\\])*)'\s*\)"), "'") - ] - - for qml_file in Path(root_dir).rglob('*.qml'): - relative_path = qml_file.relative_to(root_dir) - - with open(qml_file, 'r', encoding='utf-8') as f: - for line_num, line in enumerate(f, 1): - for pattern, quote in qstr_patterns: - for match in pattern.finditer(line): - term = decode_string_literal(match.group(1), quote) - translations[term]['occurrences'].append({ - 'file': str(relative_path), - 'line': line_num - }) - - context_spans = [] - for pattern, quote in i18n_context_patterns: - for match in pattern.finditer(line): - term = decode_string_literal(match.group(1), quote) - context = decode_string_literal(match.group(2), quote) - translations[term]['contexts'].add(context) - translations[term]['occurrences'].append({ - 'file': str(relative_path), - 'line': line_num - }) - context_spans.append(match.span()) - - for pattern, quote in i18n_simple_patterns: - for match in pattern.finditer(line): - if any(spans_overlap(match.span(), span) for span in context_spans): - continue - term = decode_string_literal(match.group(1), quote) - translations[term]['occurrences'].append({ - 'file': str(relative_path), - 'line': line_num - }) - - return translations - -def create_poeditor_json(translations): - poeditor_data = [] - - for term, data in sorted(translations.items()): - references = [] - - for occ in data['occurrences']: - ref = f"{occ['file']}:{occ['line']}" - references.append(ref) - - contexts = sorted(data['contexts']) if data['contexts'] else [] - comment = " | ".join(contexts) if contexts else "" - - entry = { - "term": term, - "context": term, - "reference": ", ".join(references), - "comment": comment - } - poeditor_data.append(entry) - - return poeditor_data - -def create_template_json(translations): - template_data = [] - - for term, data in sorted(translations.items()): - contexts = sorted(data['contexts']) if data['contexts'] else [] - context_str = " | ".join(contexts) if contexts else "" - - entry = { - "term": term, - "translation": "", - "context": context_str, - "reference": "", - "comment": "" - } - template_data.append(entry) - - return template_data - -def main(): - script_dir = Path(__file__).parent - root_dir = script_dir.parent - translations_dir = script_dir - - print("Extracting qsTr() strings from QML files...") - translations = extract_qstr_strings(root_dir) - - print(f"Found {len(translations)} unique strings") - - poeditor_data = create_poeditor_json(translations) - en_json_path = translations_dir / 'en.json' - with open(en_json_path, 'w', encoding='utf-8') as f: - json.dump(poeditor_data, f, indent=2, ensure_ascii=False) - print(f"Created source language file: {en_json_path}") - - template_data = create_template_json(translations) - template_json_path = translations_dir / 'template.json' - with open(template_json_path, 'w', encoding='utf-8') as f: - json.dump(template_data, f, indent=2, ensure_ascii=False) - print(f"Created template file: {template_json_path}") - - print("\nSummary:") - print(f" - Unique strings: {len(translations)}") - print(f" - Total occurrences: {sum(len(data['occurrences']) for data in translations.values())}") - print(f" - Strings with contexts: {sum(1 for data in translations.values() if data['contexts'])}") - print(f" - Source file: {en_json_path}") - print(f" - Template file: {template_json_path}") - -if __name__ == '__main__': - main() diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/de.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/de.json deleted file mode 100644 index e1d75f6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/de.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 Animationsgeschwindigkeit" - }, - "%1 Sessions": { - "%1 Sessions": "%1 Sitzungen" - }, - "%1 active session": { - "%1 active session": "%1 aktive Sitzung" - }, - "%1 active sessions": { - "%1 active sessions": "%1 aktive Sitzungen" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 Adapter, keiner verbunden" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 Adapter, keine verbunden" - }, - "%1 character": { - "%1 character": "%1 Zeichen" - }, - "%1 characters": { - "%1 characters": "%1 Zeichen" - }, - "%1 connected": { - "%1 connected": "%1 verbunden" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 benutzerdefinierte Animationsdauer" - }, - "%1 disconnected": { - "%1 disconnected": "%1 getrennt" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 getrennt (ausgeblendet)" - }, - "%1 display": { - "%1 display": "%1 Anzeige" - }, - "%1 displays": { - "%1 displays": "%1 Anzeigen" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 existiert, ist aber nicht in der Konfiguration enthalten. Benutzerdefinierte Tastenkombinationen funktionieren erst, wenn dies behoben ist." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 existiert, ist aber nicht enthalten. Fensterregeln werden nicht angewendet." - }, - "%1 filtered": { - "%1 filtered": "%1 gefiltert" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 ist jetzt in der Konfiguration enthalten" - }, - "%1 issue found": { - "%1 issue found": "%1 Problem gefunden" - }, - "%1 issues found": { - "%1 issues found": "%1 Probleme gefunden" - }, - "%1 notifications": { - "%1 notifications": "%1 Benachrichtigungen" - }, - "%1 update": { - "%1 update": "%1 Update" - }, - "%1 updates": { - "%1 updates": "%1 Updates" - }, - "%1 variants": { - "%1 variants": "%1 Varianten" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 Hintergrundbild • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 Hintergrundbilder • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 Widgets" - }, - "%1 window": { - "%1 window": "%1 Fenster" - }, - "%1 windows": { - "%1 windows": "%1 Fenster" - }, - "%1m ago": { - "%1m ago": "vor %1 Min." - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "'Alternative' ermöglicht das Entsperren nur mit dem Schlüssel. 'Zweiter Faktor' erfordert zuerst ein Passwort oder einen Fingerabdruck, dann den Schlüssel." - }, - "(Default)": { - "(Default)": "(Standard)" - }, - "(Unnamed)": { - "(Unnamed)": "(Unbenannt)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 weitere" - }, - "/path/to/videos": { - "/path/to/videos": "/pfad/zu/videos" - }, - "0 = square corners": { - "0 = square corners": "0 = keine Abrundung" - }, - "1 day": { - "1 day": "1 Tag" - }, - "1 device connected": { - "1 device connected": "1 Gerät verbunden" - }, - "1 event": { - "1 event": "1 Ereignis" - }, - "1 hour": { - "1 hour": "1 Stunde" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 Stunde 30 Minuten" - }, - "1 minute": { - "1 minute": "1 Minute" - }, - "1 notification": { - "1 notification": "1 Benachrichtigung" - }, - "1 second": { - "1 second": "1 Sekunde" - }, - "10 minutes": { - "10 minutes": "10 Minuten" - }, - "10 seconds": { - "10 seconds": "10 Sekunden" - }, - "10-bit Color": { - "10-bit Color": "10-bit Farbe" - }, - "12 hours": { - "12 hours": "12 Stunden" - }, - "14 days": { - "14 days": "14 Tage" - }, - "15 minutes": { - "15 minutes": "15 Minuten" - }, - "15 seconds": { - "15 seconds": "15 Sekunden" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 Stunden" - }, - "2 minutes": { - "2 minutes": "2 Minuten" - }, - "2 seconds": { - "2 seconds": "2 Sekunden" - }, - "20 minutes": { - "20 minutes": "20 Minuten" - }, - "20 seconds": { - "20 seconds": "20 Sekunden" - }, - "24-Hour Format": { - "24-Hour Format": "24-h Format" - }, - "24-hour clock": { - "24-hour clock": "24-Stunden-Format" - }, - "24-hour format": { - "24-hour format": "24-h Format" - }, - "25 seconds": { - "25 seconds": "25 Sekunden" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 Tage" - }, - "3 hours": { - "3 hours": "3 Stunden" - }, - "3 minutes": { - "3 minutes": "3 Minuten" - }, - "3 seconds": { - "3 seconds": "3 Sekunden" - }, - "30 days": { - "30 days": "30 Tage" - }, - "30 minutes": { - "30 minutes": "30 Minuten" - }, - "30 seconds": { - "30 seconds": "30 Sekunden" - }, - "35 seconds": { - "35 seconds": "35 Sekunden" - }, - "3rd party": { - "3rd party": "Drittanbieter" - }, - "4 hours": { - "4 hours": "4 Stunden" - }, - "4 seconds": { - "4 seconds": "4 Sekunden" - }, - "40 seconds": { - "40 seconds": "40 Sekunden" - }, - "45 seconds": { - "45 seconds": "45 Sekunden" - }, - "5 minutes": { - "5 minutes": "5 Minuten" - }, - "5 seconds": { - "5 seconds": "5 Sekunden" - }, - "50 seconds": { - "50 seconds": "50 Sekunden" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 Sekunden" - }, - "6 hours": { - "6 hours": "6 Stunden" - }, - "7 days": { - "7 days": "7 Tage" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 Stunden" - }, - "8 seconds": { - "8 seconds": "8 Sekunden" - }, - "90 days": { - "90 days": "90 Tage" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "MIT-Lizenz" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Eine Datei mit diesem Namen existiert bereits. Überschreiben?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Eine moderne Desktop-Shell für Wayland-Compositor" - }, - "AC Power": { - "AC Power": "Netzbetrieb" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Abgebrochen" - }, - "About": { - "About": "Über" - }, - "Accent Color": { - "Accent Color": "Akzentfarbe" - }, - "Accept": { - "Accept": "Akzeptieren" - }, - "Accept Jobs": { - "Accept Jobs": "Aufträge annehmen" - }, - "Accepting": { - "Accepting": "Nimmt an" - }, - "Access clipboard history": { - "Access clipboard history": "Zugriff auf Zwischenablage-Historie" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Zugriff auf Benachrichtigungen und Nicht Stören" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Zugriff auf Systemeinstellungen" - }, - "Action": { - "Action": "Aktion" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "Aktion fehlgeschlagen oder Terminal wurde geschlossen." - }, - "Actions": { - "Actions": "Aktionen" - }, - "Activate": { - "Activate": "Aktivieren" - }, - "Activate Greeter": { - "Activate Greeter": "Greeter aktivieren" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "DMS Greeter aktivieren? Ein Terminal für die Sudo-Authentifizierung wird geöffnet. Führen Sie nach der Aktivierung 'Sync' aus, um Ihre Einstellungen zu übernehmen." - }, - "Activation": { - "Activation": "Aktivierung" - }, - "Active": { - "Active": "Aktiv" - }, - "Active Color": { - "Active Color": "Aktive Farbe" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Aktiver Sperrbildschirm-Monitor" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Hintergrund und Symbolfarbe der aktiven Kachel" - }, - "Active: %1": { - "Active: %1": "Aktiv: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Aktiv: %1 +%2" - }, - "Active: None": { - "Active: None": "Aktiv: Keins" - }, - "Adapters": { - "Adapters": "Adapter" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Hinzufügen" - }, - "Add Bar": { - "Add Bar": "Leiste hinzufügen" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Desktop-Widget hinzufügen" - }, - "Add Printer": { - "Add Printer": "Drucker hinzufügen" - }, - "Add Title": { - "Add Title": "Titel hinzufügen" - }, - "Add Widget": { - "Add Widget": "Widget hinzufügen" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Widget zu %1 Sektion hinzufügen" - }, - "Add a border around the dock": { - "Add a border around the dock": "Einen Rahmen um das Dock hinzufügen" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Fügen Sie allen Anwendungsstarts ein benutzerdefiniertes Präfix hinzu. Dies kann für Dinge wie 'uwsm-app', 'systemd-run' oder andere Befehls-Wrapper verwendet werden." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Widgets hinzufügen und konfigurieren, die auf Ihrem Desktop erscheinen" - }, - "Add by Address": { - "Add by Address": "Über Adresse hinzufügen" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Anzahl der Spalten in der Rasteransicht anpassen." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Lautstärke pro Scroll-Schritt anpassen" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "Passt den Kontrast der generierten Farben an (-100 = Minimum, 0 = Standard, 100 = Maximum)" - }, - "Advanced": { - "Advanced": "Fortgeschritten" - }, - "Afternoon": { - "Afternoon": "Nachmittags" - }, - "All": { - "All": "Alle" - }, - "All Monitors": { - "All Monitors": "Alle Monitore" - }, - "All checks passed": { - "All checks passed": "Alle Überprüfungen bestanden" - }, - "All day": { - "All day": "Ganzer Tag" - }, - "All displays": { - "All displays": "Alle Bildschirme" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Klicks durch das Widget zulassen" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Zurück: Zurück • F1/I: Datei Info • F10: Hilfe • Esc: Schließen" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternative (ODER)" - }, - "Always Active": { - "Always Active": "Immer aktiv" - }, - "Always Show Percentage": { - "Always Show Percentage": "Prozentsatz immer anzeigen" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Das Dock immer ausblenden und einblenden, wenn man sich mit dem Mauszeiger in der Nähe des Dock-Bereichs befindet" - }, - "Always on icons": { - "Always on icons": "Immer Symbols anzeigen" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Zeige immer mindestens 3 Arbeitsbereiche, selbst wenn weniger vorhanden sind" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Das Dock immer anzeigen, wenn die Niri-Übersicht geöffnet ist" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Immer zeigen wenn nur ein Monitor verbunden" - }, - "Amount": { - "Amount": "Menge" - }, - "Analog": { - "Analog": "Analog" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analoge, digitale oder gestapelte Uhranzeige" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Konfiguration wird analysiert..." - }, - "Animation Duration": { - "Animation Duration": "Animationsdauer" - }, - "Animation Speed": { - "Animation Speed": "Animationsgeschwindigkeit" - }, - "Anonymous Identity": { - "Anonymous Identity": "Anonyme Identität" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Anonyme Identität (optional)" - }, - "App Customizations": { - "App Customizations": "App-Anpassungen" - }, - "App ID Substitutions": { - "App ID Substitutions": "App-ID-Ersetzungen" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "App-ID-Regex (z. B. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "App-Starter" - }, - "App Names": { - "App Names": "App-Namen" - }, - "App Theming": { - "App Theming": "App-Theming" - }, - "Appearance": { - "Appearance": "Erscheinungsbild" - }, - "Application Dock": { - "Application Dock": "Applikations Dock" - }, - "Applications": { - "Applications": "Anwendungen" - }, - "Apply Changes": { - "Apply Changes": "Änderungen anwenden" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "GTK Farben anwenden" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Qt Farben anwenden" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Warmes Farbschema für weniger Augenbelastung. Automatisierungseinstellungen unten zur Aktivierung." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "Authentifizierungsänderungen werden angewendet…" - }, - "Apps": { - "Apps": "Apps" - }, - "Apps Dock": { - "Apps Dock": "Apps-Dock" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Apps-Dock-Einstellungen" - }, - "Apps Icon": { - "Apps Icon": "Anwendungen Icon" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Apps sind nach Nutzungshäufigkeit sortiert, dann zuletzt genutzt, dann alphabetisch." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Apps mit benutzerdefiniertem Anzeigenamen, Symbol oder Startoptionen. Rechtsklicken Sie auf eine App und wählen Sie 'App bearbeiten', um sie anzupassen." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Apps mit stummgeschalteten Benachrichtigungs-Popups. Stummschaltung aufheben oder löschen zum Entfernen." - }, - "Architecture": { - "Architecture": "Architektur" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Sind Sie sicher, dass Sie die Sitzung \"%1\" beenden möchten?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Anzeigen anordnen und Auflösung, Bildwiederholfrequenz und VRR konfigurieren" - }, - "Attach": { - "Attach": "Verbinden" - }, - "Audio": { - "Audio": "Audio" - }, - "Audio Codec": { - "Audio Codec": "Audio Codec" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Auswahl Audio Codec" - }, - "Audio Devices": { - "Audio Devices": "Audiogeräte" - }, - "Audio Input": { - "Audio Input": "Audio Eingang" - }, - "Audio Output": { - "Audio Output": "Audio Ausgang" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Audio-Ausgabegeräte (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Audioausgangs-Umschalter" - }, - "Audio Visualizer": { - "Audio Visualizer": "Audio-Visualisierer" - }, - "Audio system restarted": { - "Audio system restarted": "Audiosystem neu gestartet" - }, - "Audio volume control": { - "Audio volume control": "Audiolautstärkeregelung" - }, - "Auth": { - "Auth": "Authentifizierung" - }, - "Auth Type": { - "Auth Type": "Authentifizierungs Typ" - }, - "Authenticate": { - "Authenticate": "Authentifizieren" - }, - "Authenticating...": { - "Authenticating...": "Authentifizierung..." - }, - "Authentication": { - "Authentication": "Authentifizierung" - }, - "Authentication Required": { - "Authentication Required": "Authentifzierung erforderlich" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "Authentifizierungsänderungen angewendet." - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "Authentifizierungsänderungen werden automatisch angewendet." - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "Authentifizierungsänderungen werden automatisch angewendet. Eine Anmeldung nur per Fingerabdruck entsperrt den Schlüsselbund möglicherweise nicht." - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "Authentifizierungsänderungen erfordern Sudo-Rechte. Ein Terminal wird geöffnet, damit Sie das Passwort oder Ihren Fingerabdruck verwenden können." - }, - "Authentication error - try again": { - "Authentication error - try again": "Authentifizierungsfehler - erneut versuchen" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Authentifizierung nicht erfolgreich, bitte nochmals probieren" - }, - "Authorize": { - "Authorize": "Autorisieren" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autorisiere Kopplung mit " - }, - "Authorize service for ": { - "Authorize service for ": "Autorisiere Dienst für " - }, - "Auto": { - "Auto": "Auto" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "Automatisch (Leisten-bewusst)" - }, - "Auto (Wide)": { - "Auto (Wide)": "Auto (Breit)" - }, - "Auto Location": { - "Auto Location": "Automatischer Standort" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Automatische Popup-Abstände" - }, - "Auto-Clear After": { - "Auto-Clear After": "Automatisch löschen nach" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Zeitüberschreitung für automatisches Ausblenden" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Niri Übersicht schliessen beim öffnen von Anwendungs." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Benachrichtigungen, die älter als diese Einstellung sind, automatisch löschen" - }, - "Auto-hide": { - "Auto-hide": "Automatisch ausblenden" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Dock automatisch ausblenden" - }, - "Auto-saving...": { - "Auto-saving...": "Auto-Speichern..." - }, - "Autoconnect": { - "Autoconnect": "automatisch verbinden" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Automatische Verbindung deaktiviert" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Automatische Verbindung aktiviert" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "Zuletzt gemerkte Suchanfrage beim Öffnen automatisch ausfüllen" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Automatischer Farbmodus" - }, - "Automatic Control": { - "Automatic Control": "Automatische Steuerung" - }, - "Automatic Cycling": { - "Automatic Cycling": "Automatischer Wechsel" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Wechselt automatisch durch die Hintergründe im selben Ordner" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Lösche Einträge automatisch die älter sind als" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Automatische Positionserkennung durch IP Adresse" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Bestimmt automatisch den Standort anhand deiner IP-Adresse" - }, - "Automatically lock after": { - "Automatically lock after": "Automatisch sperren nach" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Bildschirm beim Start von DMS automatisch sperren" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Bilschirmsperrung aktivieren wenn das System in den Ruhemodus wechselt" - }, - "Automation": { - "Automation": "Automatisierung" - }, - "Available": { - "Available": "Verfügbar" - }, - "Available Layouts": { - "Available Layouts": "Verfügbare Layouts" - }, - "Available Networks": { - "Available Networks": "Verfügbare Netzwerke" - }, - "Available Plugins": { - "Available Plugins": "Verfügbare Plugins" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Verfügbare Bildschirme (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Verfügbar in den Ansichtsmodi „Detailliert“ und „Vorhersage“" - }, - "Available.": { - "Available.": "Verfügbar." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Zurück" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "Hintergrund" - }, - "Background Blur": { - "Background Blur": "Hintergrundunschärfe" - }, - "Background Opacity": { - "Background Opacity": "Hintergrunddeckkraft" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "Hintergrund-Authentifizierungssynchronisierung fehlgeschlagen. Terminal-Modus wird versucht." - }, - "Background image": { - "Background image": "Hintergrundbild" - }, - "Backlight device": { - "Backlight device": "Hintergrundbeleuchtungsgerät" - }, - "Balance power and performance": { - "Balance power and performance": "Energie und Leistung ausgleichen" - }, - "Balanced": { - "Balanced": "Ausgeglichen" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Ausgewählte Farbpalette mit Akzenten (Standard)." - }, - "Bar Configurations": { - "Bar Configurations": "Leistenkonfiguration" - }, - "Bar Shadows": { - "Bar Shadows": "Leistenschatten" - }, - "Bar Transparency": { - "Bar Transparency": "Leistentransparenz" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Basisfarbe für Schatten (Deckkraft wird automatisch angewendet)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Basisdauer für Animationen (ziehen, um Benutzerdefiniert zu verwenden)" - }, - "Battery": { - "Battery": "Batterie" - }, - "Battery %1": { - "Battery %1": "Akku %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Ladebegrenzung des Akkus" - }, - "Battery and power management": { - "Battery and power management": "Batterie- und Energieverwaltung" - }, - "Battery level and power management": { - "Battery level and power management": "Batteriestand und Energiemanagement" - }, - "Behavior": { - "Behavior": "Verhalten" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Bildschirmsperrung durch dbus Signal von loginctl. Deaktiviere bei externer Bildschirmsperre" - }, - "Binds Include Missing": { - "Binds Include Missing": "Bindings-Include fehlt" - }, - "Binds include added": { - "Binds include added": "Bindings-Include hinzugefügt" - }, - "Bit Depth": { - "Bit Depth": "Bittiefe" - }, - "Block Out": { - "Block Out": "Blockieren" - }, - "Block Out From": { - "Block Out From": "Blockieren von" - }, - "Block notifications": { - "Block notifications": "Blocke Benachrichtigungen" - }, - "Blocked": { - "Blocked": "Geblockt" - }, - "Blue light filter": { - "Blue light filter": "Blaulichtfilter" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth Einstellungen" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth nicht verfügbar" - }, - "Blur Border Color": { - "Blur Border Color": "Rahmenfarbe der Unschärfe" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "Rahmendeckkraft der Unschärfe" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Hintergrundbild-Ebene weichzeichnen" - }, - "Blur on Overview": { - "Blur on Overview": "Unschärfe auf Übersicht" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "Den Hintergrund hinter Leisten, Pop-outs, Modalen und Benachrichtigungen weichzeichnen. Erfordert Compositor-Unterstützung und Konfiguration." - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Hintergrundbild weichzeichnen, wenn Niri-Übersicht geöffnet ist" - }, - "Body": { - "Body": "Textkörper" - }, - "Border": { - "Border": "Rahmen" - }, - "Border Color": { - "Border Color": "Rahmenfarbe" - }, - "Border Opacity": { - "Border Opacity": "Transparenz des Rahmens" - }, - "Border Size": { - "Border Size": "Rahmengröße" - }, - "Border Thickness": { - "Border Thickness": "Rahmenstärke" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "Rahmenfarbe um weichgezeichnete Oberflächen" - }, - "Border with BG": { - "Border with BG": "Rahmen mit Hintergrund" - }, - "Bottom": { - "Bottom": "Unten" - }, - "Bottom Center": { - "Bottom Center": "Unten zentriert" - }, - "Bottom Left": { - "Bottom Left": "Unten links" - }, - "Bottom Right": { - "Bottom Right": "Unten rechts" - }, - "Bottom Section": { - "Bottom Section": "Unterer Bereich" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Unteres Dock für angepinnte und laufende Anwendungen" - }, - "Brightness": { - "Brightness": "Helligkeit" - }, - "Brightness Slider": { - "Brightness Slider": "Helligkeitsregler" - }, - "Brightness Value": { - "Brightness Value": "Helligkeitswert" - }, - "Brightness control not available": { - "Brightness control not available": "Helligkeits Regelung nicht verfügbar" - }, - "Browse": { - "Browse": "Durchsuchen" - }, - "Browse Files": { - "Browse Files": "Dateien durchsuchen" - }, - "Browse Plugins": { - "Browse Plugins": "Plugins durchsuchen" - }, - "Browse Themes": { - "Browse Themes": "Themes durchsuchen" - }, - "Browse or search plugins": { - "Browse or search plugins": "Plugins durchsuchen oder suchen" - }, - "Button Color": { - "Button Color": "Schaltflächenfarbe" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU-Diagramm" - }, - "CPU Temperature": { - "CPU Temperature": "CPU Temperatur" - }, - "CPU Usage": { - "CPU Usage": "CPU-Auslastung" - }, - "CPU temperature display": { - "CPU temperature display": "Anzeige der CPU-Temperatur" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU-Auslastungsindikator" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU, Speicher, Netzwerk und Laufwerk Monitor" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS-Warnung: Unsicherer Filter" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS-Warnung: Fehlender Filter" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS Drucker-Server" - }, - "CUPS not available": { - "CUPS not available": "CUPS nicht verfügbar" - }, - "Camera": { - "Camera": "Kamera" - }, - "Cancel": { - "Cancel": "Abbrechen" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Alle Aufträge für \"%1\" abbrechen?" - }, - "Canceled": { - "Canceled": "Abgebrochen" - }, - "Cannot pair": { - "Cannot pair": "Kann nicht koppeln" - }, - "Capabilities": { - "Capabilities": "Fähigkeiten" - }, - "Capacity": { - "Capacity": "Kapazität" - }, - "Caps Lock": { - "Caps Lock": "Feststelltaste" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indikator für Feststelltaste" - }, - "Caps Lock is on": { - "Caps Lock is on": "Feststelltaste ist aktiviert" - }, - "Center Section": { - "Center Section": "Mittlerer Abschnitt" - }, - "Center Single Column": { - "Center Single Column": "Einzelne Spalte zentrieren" - }, - "Center Tiling": { - "Center Tiling": "Zentrierte Kachelung" - }, - "Certificate Password": { - "Certificate Password": "zertifiziertes Passwort" - }, - "Change Song": { - "Change Song": "Song wechseln" - }, - "Change Volume": { - "Change Volume": "Lautstärke ändern" - }, - "Change bar appearance": { - "Change bar appearance": "Ändere Leistenerscheinungsbild" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "Ändern Sie das Gebietsschema für die DMS-Benutzeroberfläche." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Ändern Sie das Gebietsschema für die Datums- und Zeitformatierung, unabhängig von der Sprache der Benutzeroberfläche." - }, - "Channel": { - "Channel": "Kanal" - }, - "Charging": { - "Charging": "Aufladen" - }, - "Check for system updates": { - "Check for system updates": "Auf Systemupdates prüfen" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "Synchronisierungsstatus bei Bedarf prüfen. Die Synchronisierung kopiert Ihr Design, Ihre Einstellungen und Ihre Hintergrundbildkonfiguration auf den Anmeldebildschirm. Authentifizierungsänderungen werden automatisch angewendet." - }, - "Checking for updates...": { - "Checking for updates...": "Suche nach Updates..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Prüfen, ob eine Sudo-Authentifizierung erforderlich ist…" - }, - "Checking...": { - "Checking...": "Prüfung..." - }, - "Checking…": { - "Checking…": "Prüfen…" - }, - "Choose Color": { - "Choose Color": "Farbe" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Dunkelmodus-Farbe wählen" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Logo-Farbe des Dock-Launchers wählen" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Launcher Logo auswählen" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Hellmodus-Farbe wählen" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Hintergrundbild-Farbe wählen" - }, - "Choose a color": { - "Choose a color": "eine Farbe" - }, - "Choose colors from palette": { - "Choose colors from palette": "Farbe von Palette" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Wählen Sie aus, wie das Wetter-Widget angezeigt werden soll" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Wählen Sie aus, wie diese Leiste die Schattenrichtung bestimmt" - }, - "Choose icon": { - "Choose icon": "Symbol auswählen" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Hintergrundfarbe für Widgets" - }, - "Choose the border accent color": { - "Choose the border accent color": "Rahmenakzentfarbe auswählen" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Wähle das Logo des Launcher Knopfs in der DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Wähle wo auf dem Bildschirm Benachrichtigungen erscheinen" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Wählen Sie, wo Bildschirmanzeigen auf dem Bildschirm erscheinen" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Wählen Sie aus, welche Anzeigen dieses Widget anzeigen" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Wählen Sie aus, welcher Monitor die Sperrbildschirm-Oberfläche anzeigt. Andere Monitore zeigen eine Volltonfarbe zum Schutz vor OLED-Einbrennen an." - }, - "Chroma Style": { - "Chroma Style": "Chroma-Stil" - }, - "Cipher": { - "Cipher": "Verschlüsselung" - }, - "Circle": { - "Circle": "Kreis" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Klassen-Regex (z. B. ^firefox$)" - }, - "Clear": { - "Clear": "Löschen" - }, - "Clear All": { - "Clear All": "Alles löschen" - }, - "Clear All Jobs": { - "Clear All Jobs": "Alle Druckaufträge entfernen" - }, - "Clear History?": { - "Clear History?": "Verlauf löschen?" - }, - "Clear Sky": { - "Clear Sky": "Klarer Himmel" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Gesamten Verlauf beim Serverstart löschen" - }, - "Clear at Startup": { - "Clear at Startup": "Beim Start löschen" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Klicken Sie auf 'Setup', um %1 zu erstellen und das Include zur Konfiguration hinzuzufügen." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Klicken Sie auf 'Setup', um %1 zu erstellen und das Include zu Ihrer Compositor-Konfiguration hinzuzufügen." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Klicken Sie auf 'Setup', um die Cursor-Konfiguration zu erstellen und das Include zu Ihrer Compositor-Konfiguration hinzuzufügen." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Klicken Sie auf 'Setup', um die Ausgabekonfiguration zu erstellen und 'include' zu Ihrer Compositor-Konfiguration hinzuzufügen." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Klicken Sie auf Importieren, um eine .ovpn oder .conf hinzuzufügen" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Klicken Sie auf Aktualisieren, um den Status zu prüfen." - }, - "Click Through": { - "Click Through": "Durchklicken" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Klicken Sie auf eine beliebige Verknüpfung zum Bearbeiten. Änderungen werden in %1 gespeichert" - }, - "Click to capture": { - "Click to capture": "Zum Erfassen klicken" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Klicken, um eine benutzerdefinierte Theme-JSON-Datei auszuwählen" - }, - "Clip": { - "Clip": "Zuschneiden" - }, - "Clip to Geometry": { - "Clip to Geometry": "Auf Geometrie zuschneiden" - }, - "Clipboard": { - "Clipboard": "Zwischenablage" - }, - "Clipboard History": { - "Clipboard History": "Historie Zwischenablage" - }, - "Clipboard Manager": { - "Clipboard Manager": "Zwischenablage Manager" - }, - "Clipboard sent": { - "Clipboard sent": "Zwischenablage gesendet" - }, - "Clipboard service not available": { - "Clipboard service not available": "Service für Zwischenablage nicht verfügbar" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Zwischenablage funktioniert, aber nichts auf Festplatte gespeichert" - }, - "Clock": { - "Clock": "Uhr" - }, - "Clock Style": { - "Clock Style": "Uhrenstil" - }, - "Close": { - "Close": "Schließen" - }, - "Close All Windows": { - "Close All Windows": "Alle Fenster schließen" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Übersicht bei start des Launchers schließen" - }, - "Close Window": { - "Close Window": "Fenster schließen" - }, - "Color": { - "Color": "Farbe" - }, - "Color Gamut": { - "Color Gamut": "Farbraum" - }, - "Color Management": { - "Color Management": "Farbmanagement" - }, - "Color Mode": { - "Color Mode": "Farbmodus" - }, - "Color Override": { - "Color Override": "Farbe überschreiben" - }, - "Color Picker": { - "Color Picker": "Farbwähler" - }, - "Color Temperature": { - "Color Temperature": "Farbtemperatur" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Farbe auf Monitoren ohne Sperrbildschirm" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Farbe für primäre Aktionsschaltflächen" - }, - "Color temperature for day time": { - "Color temperature for day time": "Farbtemperatur für Tageszeit" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Farbtemperatur für Nachtmodus" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Farbschema für Syntax-Hervorhebung." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Farbschema für Syntax-Hervorhebung. %1 Schemata verfügbar." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Farbschema aus der DMS-Registry" - }, - "Colorful": { - "Colorful": "Farbenfroh" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Bunte Mischung aus hellen, kontrastreichen Akzenten." - }, - "Colorize Active": { - "Colorize Active": "Aktive einfärben" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Farben vom Hintergrundbild" - }, - "Column": { - "Column": "Spalte" - }, - "Column Display": { - "Column Display": "Spaltenanzeige" - }, - "Column Width": { - "Column Width": "Spaltenbreite" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "Kommagetrennte Liste von Sitzungsnamen zum Ausblenden. In Schrägstriche für Regex einschließen (z. B. /^_.*/)." - }, - "Command": { - "Command": "Befehl" - }, - "Commands": { - "Commands": "Befehle" - }, - "Communication": { - "Communication": "Kommunikation" - }, - "Community themes": { - "Community themes": "Community-Themes" - }, - "Compact": { - "Compact": "Kompakt" - }, - "Compact Mode": { - "Compact Mode": "Kompaktmodus" - }, - "Completed": { - "Completed": "Abgeschlossen" - }, - "Compositor": { - "Compositor": "Compositor" - }, - "Compositor Settings": { - "Compositor Settings": "Compositor-Einstellungen" - }, - "Compositor not supported": { - "Compositor not supported": "Compositor wird nicht unterstützt" - }, - "Config Format": { - "Config Format": "Konfigurationsformat" - }, - "Config action: %1": { - "Config action: %1": "Konfigurationsaktion: %1" - }, - "Config validation failed": { - "Config validation failed": "Validierung der Konfiguration fehlgeschlagen" - }, - "Configuration": { - "Configuration": "Konfiguration" - }, - "Configuration activated": { - "Configuration activated": "Konfiguration wurde aktiviert" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Konfiguration wird beibehalten wenn der Monitor wieder angeschlossen wird" - }, - "Configure": { - "Configure": "Konfigurieren" - }, - "Configure Keybinds": { - "Configure Keybinds": "Tastenkombinationen konfigurieren" - }, - "Configure a new printer": { - "Configure a new printer": "Neuen Drucker einrichten" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Konfiguriere Icons für benannte Workspaces. Icons haben eine höhere Priorität als Nummern, wenn beide aktiviert sind." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Suchkriterien und Aktionen konfigurieren" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Konfigurieren, auf welchen Displays \"%1\" angezeigt wird" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Konfiguriere, welche Bildschirme Shell-Komponenten anzeigen" - }, - "Confirm": { - "Confirm": "Bestätigung" - }, - "Confirm Delete": { - "Confirm Delete": "Löschen bestätigen" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Bestätige neue Monitoreinstellung" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Bestätige Passkey für " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "In Konflikt mit: %1" - }, - "Connect": { - "Connect": "Verbinden" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Mit verborgenem Netzwerk verbinden" - }, - "Connect to VPN": { - "Connect to VPN": "Mit VPN verbinden" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "WLAN verbinden" - }, - "Connected": { - "Connected": "Verbunden" - }, - "Connected Device": { - "Connected Device": "Verbundenes Gerät" - }, - "Connected Displays": { - "Connected Displays": "Verbundene Bildschirme" - }, - "Connecting to Device": { - "Connecting to Device": "Verbinde Gerät" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Verbinden..." - }, - "Connection failed": { - "Connection failed": "Verbindung fehlgeschlagen" - }, - "Contains": { - "Contains": "Enthält" - }, - "Content": { - "Content": "Inhalt" - }, - "Content copied": { - "Content copied": "Inhalt kopiert" - }, - "Contrast": { - "Contrast": "Kontrast" - }, - "Control Center": { - "Control Center": "Kontrollzentrum" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Kachelfarbe des Kontrollzentrums" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Animationsdauer für Benachrichtigungs-Popups und Verlauf steuern" - }, - "Control currently playing media": { - "Control currently playing media": "Aktuelle Medienwiedergabe steuern" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Steuern Sie, welche Benachrichtigungsinformationen auf dem Sperrbildschirm angezeigt werden" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Steuern Sie, welche Plugins im Modus 'Alle' ohne Trigger-Präfix erscheinen. Zum Neuanordnen ziehen." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Arbeitsbereiche und Spalten durch Scrollen auf der Leiste steuern" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Steuert die Deckkraft aller Popouts, Modals und deren Inhaltsebenen" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "Steuert die Schattenwurfrichtung für Erhebungsebenen" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "Steuert den Basis-Unschärferadius und den Versatz von Schatten" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Steuert die Transparenz des Schattens" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Komfortoptionen für den Anmeldebildschirm. Synchronisieren zum Anwenden." - }, - "Cooldown": { - "Cooldown": "Abkühlzeit" - }, - "Copied GIF": { - "Copied GIF": "GIF kopiert" - }, - "Copied MP4": { - "Copied MP4": "MP4 kopiert" - }, - "Copied WebP": { - "Copied WebP": "WebP kopiert" - }, - "Copied to clipboard": { - "Copied to clipboard": "In Zwischenablage kopiert" - }, - "Copied!": { - "Copied!": "Kopiert!" - }, - "Copy": { - "Copy": "Kopieren" - }, - "Copy Content": { - "Copy Content": "Inhalt kopieren" - }, - "Copy Full Command": { - "Copy Full Command": "Vollständigen Befehl kopieren" - }, - "Copy HTML": { - "Copy HTML": "HTML kopieren" - }, - "Copy Name": { - "Copy Name": "Name kopieren" - }, - "Copy PID": { - "Copy PID": "PID kopieren" - }, - "Copy Text": { - "Copy Text": "Text kopieren" - }, - "Copy path": { - "Copy path": "Pfad kopieren" - }, - "Corner Radius": { - "Corner Radius": "Abrundungsradius" - }, - "Corner Radius Override": { - "Corner Radius Override": "Abrundung überschreiben" - }, - "Corners & Background": { - "Corners & Background": "Ecken & Hintergrund" - }, - "Count Only": { - "Count Only": "Nur Anzahl" - }, - "Cover Open": { - "Cover Open": "Abdeckung offen" - }, - "Create": { - "Create": "Erzeuge" - }, - "Create Dir": { - "Create Dir": "Ordner erstellen" - }, - "Create Printer": { - "Create Printer": "Drucker anlegen" - }, - "Create Window Rule": { - "Create Window Rule": "Erzeuge Fensterregel" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Neue %1-Sitzung erstellen (n)" - }, - "Create rule for:": { - "Create rule for:": "Erzeuge Regel für:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Regeln erstellen, um Benachrichtigungen stummzuschalten, zu ignorieren, im Verlauf auszublenden oder die Priorität zu überschreiben. Standardmäßig wird nur die Priorität überschrieben; Benachrichtigungen werden weiterhin normal angezeigt." - }, - "Creating...": { - "Creating...": "erzeugen..." - }, - "Critical Priority": { - "Critical Priority": "Kritische Priorität" - }, - "Current": { - "Current": "Aktuell" - }, - "Current Items": { - "Current Items": "Aktuelle Einträge" - }, - "Current Locale": { - "Current Locale": "Aktuelles Gebietsschema" - }, - "Current Monitor": { - "Current Monitor": "Aktueller Monitor" - }, - "Current Period": { - "Current Period": "Aktuelle Periode" - }, - "Current Status": { - "Current Status": "Aktueller Status" - }, - "Current Temp": { - "Current Temp": "Aktuelle Temperatur" - }, - "Current Theme: %1": { - "Current Theme: %1": "Aktuelles Theme: %1" - }, - "Current Weather": { - "Current Weather": "Aktuelles Wetter" - }, - "Current Workspace": { - "Current Workspace": "Aktuelle Arbeitsfläche" - }, - "Current time and date display": { - "Current time and date display": "Aktuelle Zeit / Datum Anzeige" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Aktuelle Wetter- und Temperaturbedingungen" - }, - "Current: %1": { - "Current: %1": "Aktuell: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Cursor-Konfiguration nicht konfiguriert" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Cursor-Include fehlt" - }, - "Cursor Size": { - "Cursor Size": "Cursor-Größe" - }, - "Cursor Theme": { - "Cursor Theme": "Cursor-Design" - }, - "Custom": { - "Custom": "Individuell" - }, - "Custom Color": { - "Custom Color": "Benutzerdefinierte Farbe" - }, - "Custom Duration": { - "Custom Duration": "Anpassung der Dauer" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Benutzerdefinierter Ruhezustandsbefehl" - }, - "Custom Location": { - "Custom Location": "Individueller Ort" - }, - "Custom Lock Command": { - "Custom Lock Command": "Anpassung des Sperr-Befehls" - }, - "Custom Logout Command": { - "Custom Logout Command": "Anpassung des Logout-Befehls" - }, - "Custom Name": { - "Custom Name": "Benutzerdefinierter Name" - }, - "Custom Power Actions": { - "Custom Power Actions": "Benutzerdefinierte Energieoptionen" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Anpassung des Ausschalt-Befehls" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Anpassung des Neustart-Befehls" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Benutzerdefinierte Schattenfarbe" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Benutzerdefinierte Schatten-Überschreibung" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Benutzerdefinierter Bereitschaftsbefehl" - }, - "Custom Transparency": { - "Custom Transparency": "Individuelle Transparenz" - }, - "Custom power profile": { - "Custom power profile": "Benutzerdefiniertes Energieprofil" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Benutzerdefiniertes Theme aus JSON-Datei geladen" - }, - "Custom...": { - "Custom...": "Benutzerdefiniert..." - }, - "Custom: ": { - "Custom: ": "Individuell: " - }, - "Customizable empty space": { - "Customizable empty space": "Spezifischer leerer Platz" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Wählbare Energieoptionen im Power Menü anpassen" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI-Monitor" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMO MODUS - Irgendwo klicken um abzubrechen" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS Plugin Manager nicht verfügbar" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS-Kurzbefehle" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "DMS-Greeter benötigt: greetd, dms-greeter. Fingerabdruck: fprintd, pam_fprintd. Sicherheitsschlüssel: pam_u2f. Fügen Sie Ihren Benutzer der Gruppe „greeter“ hinzu. Authentifizierungsänderungen werden automatisch angewendet und können ein Terminal öffnen, wenn eine Sudo-Authentifizierung erforderlich ist." - }, - "DMS out of date": { - "DMS out of date": "DMS ist veraltet" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS-Dienst ist nicht verbunden. Zwischenablage-Einstellungen sind nicht verfügbar." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS Shell Aktionen (Launcher, Zwischenablage, etc.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET nicht verfügbar" - }, - "DWL service not available": { - "DWL service not available": "DWL Service ist nicht verfügbar" - }, - "Daily": { - "Daily": "Täglich" - }, - "Daily at:": { - "Daily at:": "Täglich um:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell ist einsatzbereit" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell & System Icons (Neutstart erforderlich)" - }, - "Dark Mode": { - "Dark Mode": "Dunkler Modus" - }, - "Dark mode base": { - "Dark mode base": "Dunkelmodus Basis" - }, - "Dark mode harmony": { - "Dark mode harmony": "Dunkelmodus Harmonie" - }, - "Darken Modal Background": { - "Darken Modal Background": "Modalen Hintergrund abdunkeln" - }, - "Date Format": { - "Date Format": "Datumsformat" - }, - "Date format": { - "Date format": "Datumsformat" - }, - "Date format on greeter": { - "Date format on greeter": "Datumsformat im Greeter" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Morgendämmerung (Astronomische Dämmerung)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Morgendämmerung (Bürgerliche Dämmerung)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Morgendämmerung (Nautische Dämmerung)" - }, - "Day Date": { - "Day Date": "Tag Datum" - }, - "Day Month Date": { - "Day Month Date": "Tag Monat Datum" - }, - "Day Temperature": { - "Day Temperature": "Farbtemperatur am Tag" - }, - "Daytime": { - "Daytime": "Tageszeit" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "Standard" - }, - "Default (Black)": { - "Default (Black)": "Standard (Schwarz)" - }, - "Default Width (%)": { - "Default Width (%)": "Standardbreite (%)" - }, - "Default selected action": { - "Default selected action": "Vorausgewählte Energieoption" - }, - "Defaults": { - "Defaults": "Standards" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Regeln für das Fensterverhalten definieren. Speichert in %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Löschen • Shift+Del: Alles löschen • 1-9: Aktionen • F10: Hilfe • Esc: Schließen" - }, - "Delete": { - "Delete": "Löschen" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "\"%1\" löschen?" - }, - "Delete Class": { - "Delete Class": "Klasse löschen" - }, - "Delete Printer": { - "Delete Printer": "Drucker löschen" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Gespeichertes Element löschen?" - }, - "Delete VPN": { - "Delete VPN": "VPN löschen" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Klasse \"%1\" löschen?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Profil \"%1\" löschen?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Abhängigkeiten & Dokumentation" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Leitet Farben ab, die eng mit dem darunter liegenden Bild übereinstimmen." - }, - "Description": { - "Description": "Beschreibung" - }, - "Desktop": { - "Desktop": "Desktop" - }, - "Desktop Clock": { - "Desktop Clock": "Desktop Uhr" - }, - "Desktop Entry": { - "Desktop Entry": "Desktop-Eintrag" - }, - "Desktop Widget": { - "Desktop Widget": "Desktop Widget" - }, - "Desktop Widgets": { - "Desktop Widgets": "Desktop Widgets" - }, - "Desktop background images": { - "Desktop background images": "Desktop-Hintergrundbilder" - }, - "Detailed": { - "Detailed": "Detailliert" - }, - "Details for \"%1": { - "Details for \"%1\"": "Details für \"%1\"" - }, - "Development": { - "Development": "Entwicklung" - }, - "Device": { - "Device": "Gerät" - }, - "Device connections": { - "Device connections": "Geräteverbindungen" - }, - "Device names updated": { - "Device names updated": "Gerätenamen aktualisiert" - }, - "Device paired": { - "Device paired": "Gerät verbunden" - }, - "Device unpaired": { - "Device unpaired": "Gerät entkoppelt" - }, - "Digital": { - "Digital": "Digital" - }, - "Direction Source": { - "Direction Source": "Richtungsquelle" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Automatische Verbindung deaktivieren" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Integrierte Hintergrundbilder deaktivieren" - }, - "Disable History Persistence": { - "Disable History Persistence": "Verlaufsspeicherung deaktivieren" - }, - "Disable Output": { - "Disable Output": "Ausgabe deaktivieren" - }, - "Disabled": { - "Disabled": "Deaktiviert" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "deaktiviere WLAN..." - }, - "Disc": { - "Disc": "Scheibe" - }, - "Discard": { - "Discard": "Verwerfen" - }, - "Discharging": { - "Discharging": "Entlädt" - }, - "Disconnect": { - "Disconnect": "Trennen" - }, - "Disconnected": { - "Disconnected": "Getrennt" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "WLAN Verbindung unterbrochen" - }, - "Discover Devices": { - "Discover Devices": "Geräte suchen" - }, - "Disk": { - "Disk": "Festplatte" - }, - "Disk I/O": { - "Disk I/O": "Laufwerks-E/A" - }, - "Disk Usage": { - "Disk Usage": "Datenträgerauslastung" - }, - "Disk Usage Display": { - "Disk Usage Display": "Speicherplatzanzeige" - }, - "Disks": { - "Disks": "Laufwerke" - }, - "Dismiss": { - "Dismiss": "Ausblenden" - }, - "Display": { - "Display": "Anzeige" - }, - "Display Assignment": { - "Display Assignment": "Monitorzuweisung" - }, - "Display Control": { - "Display Control": "Anzeigesteuerung" - }, - "Display Name Format": { - "Display Name Format": "Anzeige-Namensformat" - }, - "Display Profiles": { - "Display Profiles": "Anzeigeprofile" - }, - "Display Settings": { - "Display Settings": "Monitoreinstellungen" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Ein Dock mit angehefteten und laufenden Anwendungen anzeigen" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Zeige alle Prioritäten über Fullscreen-Anwendungen" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "DWL-Layouts anzeigen und wechseln" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Anwendungssymbole in Arbeitsbereichs-Indikatoren anzeigen" - }, - "Display brightness control": { - "Display brightness control": "Zeige Helligkeitseinstellung" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Monitoreinstellung nicht verfügbar. WLR Ausgabe Protokoll wird nicht unterstützt." - }, - "Display currently focused application title": { - "Display currently focused application title": "Zeige aktuell fokussierten Anwendungstitel" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Stündliche Wettervorhersagen anzeigen" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Nur Arbeitsbereiche anzeigen, die Fenster enthalten" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Zeige Energieoptionen als Raster anstatt von einer Liste" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Sekunden in Uhr anzeigen" - }, - "Display the power system menu": { - "Display the power system menu": "System-Energiemenü anzeigen" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Lautstärke- und Helligkeitsprozente in OSD-Popups anzeigen" - }, - "Displays": { - "Displays": "Bildschirme" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Anzahl der Anzeigen, wenn Überlauf aktiv ist" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Zeigt aktives Tastaturlayout und erlaubt Umschaltung" - }, - "Distribution": { - "Distribution": "Distribution" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Vielfältige Palette, die das gesamte Spektrum abdeckt." - }, - "Do Not Disturb": { - "Do Not Disturb": "Nicht stören" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock & Launcher" - }, - "Dock Transparency": { - "Dock Transparency": "Dock Transparenz" - }, - "Dock Visibility": { - "Dock Visibility": "Dock-Sichtbarkeit" - }, - "Docs": { - "Docs": "Dokumentation" - }, - "Documents": { - "Documents": "Dokumente" - }, - "Domain (optional)": { - "Domain (optional)": "Domain (optional)" - }, - "Don't Change": { - "Don't Change": "Nicht ändern" - }, - "Don't Save": { - "Don't Save": "Nicht speichern" - }, - "Door Open": { - "Door Open": "Klappe offen" - }, - "Downloads": { - "Downloads": "Downloads" - }, - "Drag to Reorder": { - "Drag to Reorder": "Zum Neuanordnen ziehen" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Ziehen Sie Widgets, um sie innerhalb von Abschnitten neu anzuordnen. Verwenden Sie das Augensymbol, um Widgets auszublenden/anzuzeigen (behält den Abstand bei), oder X, um sie vollständig zu entfernen." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Arbeitsbereich-Indikatoren ziehen, um sie neu anzuordnen" - }, - "Driver": { - "Driver": "Treiber" - }, - "Drizzle": { - "Drizzle": "Nieselregen" - }, - "Duplicate": { - "Duplicate": "Duplizieren" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Hintergrundbild mit Unschärfe duplizieren" - }, - "Duration": { - "Duration": "Dauer" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Abenddämmerung (Astronomische Dämmerung)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Abenddämmerung (Bürgerliche Dämmerung)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Abenddämmerung (Nautische Dämmerung)" - }, - "Dynamic": { - "Dynamic": "Dynamisch" - }, - "Dynamic Properties": { - "Dynamic Properties": "Dynamische Eigenschaften" - }, - "Dynamic Theming": { - "Dynamic Theming": "Dynamisches Theming" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Dynamische Farben von Hintergrundbild" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Dynamische Farben, Voreinstellungen" - }, - "Edge Spacing": { - "Edge Spacing": "Randabstand" - }, - "Edit App": { - "Edit App": "App bearbeiten" - }, - "Edit Window Rule": { - "Edit Window Rule": "Bearbeite Fensterregel" - }, - "Education": { - "Education": "Bildung" - }, - "Empty": { - "Empty": "Leer" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "10-Bit-Farbtiefe für einen breiteren Farbraum und HDR-Unterstützung aktivieren" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Automatische Verbindung aktivieren" - }, - "Enable Bar": { - "Enable Bar": "Aktiviere Leiste" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "\"Bitte nicht stören\" aktivieren" - }, - "Enable History": { - "Enable History": "Verlauf aktivieren" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Übersichts-Overlay aktivieren" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Wellen-Effekte aktivieren" - }, - "Enable System Sounds": { - "Enable System Sounds": "Aktiviere Systemtöne" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Video-Bildschirmschoner aktivieren" - }, - "Enable Weather": { - "Enable Weather": "Wetter aktivieren" - }, - "Enable WiFi": { - "Enable WiFi": "WiFi aktivieren" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "Aktivieren Sie unten eine benutzerdefinierte Überschreibung, um Schattenintensität, Deckkraft und Farbe pro Leiste festzulegen." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Compositor-zielbaren Weichzeichner-Layer aktivieren (Namespace: dms:blurwallpaper). Erfordert manuelle Niri-Konfiguration." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Fingerabdruck bei Anmeldung aktivieren" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Aktiviere Fingerabdruck Authentifizierung" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "Fingerabdruck oder Sicherheitsschlüssel für DMS-Greeter aktivieren. Authentifizierungsänderungen werden automatisch angewendet." - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Loginctl‑Sperrintegration aktivieren" - }, - "Enable security key at login": { - "Enable security key at login": "Sicherheitsschlüssel bei Anmeldung aktivieren" - }, - "Enable security key authentication": { - "Enable security key authentication": "Authentifizierung per Sicherheitsschlüssel aktivieren" - }, - "Enabled": { - "Enabled": "Aktiviert" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Aktiviert, aber die Verfügbarkeit des Fingerabdrucks konnte nicht bestätigt werden." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Aktiviert, aber es wurde kein Fingerabdruckleser erkannt." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "Aktiviert, aber es sind noch keine Abdrücke registriert. Authentifizierungsänderungen werden automatisch angewendet, sobald Sie Fingerabdrücke registrieren." - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Aktiviert, aber es sind noch keine Abdrücke registriert. Fingerabdrücke registrieren und Sync ausführen." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "Aktiviert, aber es wurde noch kein registrierter Sicherheitsschlüssel gefunden. Authentifizierungsänderungen werden automatisch angewendet, sobald Ihr Schlüssel registriert oder Ihre U2F-Konfiguration aktualisiert wurde." - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "Aktiviert, aber es wurde noch kein registrierter Sicherheitsschlüssel gefunden. Einen Schlüssel registrieren und Sync ausführen." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Aktiviert, aber die Verfügbarkeit des Sicherheitsschlüssels konnte nicht bestätigt werden." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Aktiviert. PAM bietet bereits Fingerabdruck-Authentifizierung." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Aktiviert. PAM bietet bereits Sicherheitsschlüssel-Authentifizierung." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Aktiviert. PAM bietet Fingerabdruck-Authentifizierung, aber es sind noch keine Abdrücke registriert." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "aktiviere WLAN..." - }, - "End": { - "End": "Ende" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Vergrößern beim Drüberfahren" - }, - "Enlargement %": { - "Enlargement %": "Vergrößerung %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "6-stelligen Passkey eingeben" - }, - "Enter PIN": { - "Enter PIN": "PIN eingeben" - }, - "Enter PIN for ": { - "Enter PIN for ": "PIN eingeben für " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "URL oder Text zum Teilen eingeben" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Neuen Namen für Sitzung \"%1\" eingeben" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Geben Sie einen neuen Namen für diesen Arbeitsbereich ein" - }, - "Enter command or script path": { - "Enter command or script path": "Befehl oder Skriptpfad eingeben" - }, - "Enter credentials for ": { - "Enter credentials for ": "Passworteingabe für " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Individuelles Sperrbildschirm-Format (bspw. dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Individuelles oberes Leistenformat (bspw. ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Gerätenamen eingeben..." - }, - "Enter filename...": { - "Enter filename...": "Dateiname eingeben..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Startpräfix eingeben (z. B. 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Netzwerkname und Passwort eingeben" - }, - "Enter passkey for ": { - "Enter passkey for ": "Passkey eingeben für " - }, - "Enter password for ": { - "Enter password for ": "Passworteingabe für " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Geben Sie diesen Passkey ein auf " - }, - "Enter to Paste": { - "Enter to Paste": "Eingabetaste zum Einfügen" - }, - "Enterprise": { - "Enterprise": "Enterprise" - }, - "Entry pinned": { - "Entry pinned": "Eintrag angeheftet" - }, - "Entry unpinned": { - "Entry unpinned": "Eintrag losgeheftet" - }, - "Environment Variables": { - "Environment Variables": "Umgebungsvariablen" - }, - "Error": { - "Error": "Fehler" - }, - "Errors": { - "Errors": "Fehler" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Exakt" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Exklusives Zonenoffset" - }, - "Experimental Feature": { - "Experimental Feature": "Experimentelle Funktion" - }, - "Explore": { - "Explore": "Erkunden" - }, - "Exponential": { - "Exponential": "Exponentiell" - }, - "Expressive": { - "Expressive": "Expressiv" - }, - "Extend battery life": { - "Extend battery life": "Akkulaufzeit verlängern" - }, - "Extensible architecture": { - "Extensible architecture": "Erweiterbare Architektur" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Externe Hintergrundbild Verwaltung" - }, - "Extra Arguments": { - "Extra Arguments": "Zusätzliche Argumente" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Umschalten • F10: Hilfe" - }, - "Fade": { - "Fade": "Überblenden" - }, - "Fade to lock screen": { - "Fade to lock screen": "Zum Sperrbildschirm überblenden" - }, - "Fade to monitor off": { - "Fade to monitor off": "Ausblenden bis Monitor aus" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Kopplung konnte nicht akzeptiert werden" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Fehler beim aktivieren der Konfiguration" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Profil konnte nicht aktiviert werden - Datei nicht gefunden" - }, - "Failed to add binds include": { - "Failed to add binds include": "Hinzufügen des Bindings-Includes fehlgeschlagen" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Drucker konnte der Klasse nicht hinzugefügt werden" - }, - "Failed to browse device": { - "Failed to browse device": "Gerät konnte nicht durchsucht werden" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Fehler beim widerrufen der Druckaufträge" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Fehler beim widerrufen des ausgewählten Druckauftrages" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Fehler beim Suchen nach Updates:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Anheftungsbegrenzung konnte nicht überprüft werden" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "VPN-Verbindung fehlgeschlagen" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Verbindung zu %1 fehlgeschlagen" - }, - "Failed to copy entry": { - "Failed to copy entry": "Eintrag konnte nicht kopiert werden" - }, - "Failed to create printer": { - "Failed to create printer": "Fehler beim anlegen des Druckers" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Profilverzeichnis konnte nicht erstellt werden" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Fehler beim löschen des VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Klasse konnte nicht gelöscht werden" - }, - "Failed to delete printer": { - "Failed to delete printer": "Fehler beim löschen des Druckers" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Auftragsannahme konnte nicht deaktiviert werden" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Fehler beim deaktivieren des Nachtmodus" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "VPN-Trennung fehlgeschlagen" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Trennen der VPNs fehlgeschlagen" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Fehler beim unterbrechen der WLAN Verbindung" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Fehler beim aktivieren der IP Ortung" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Fehler beim aktivieren von WLAN" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Auftragsannahme konnte nicht aktiviert werden" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Nachtmodus konnte nicht aktiviert werden" - }, - "Failed to hold job": { - "Failed to hold job": "Auftrag konnte nicht angehalten werden" - }, - "Failed to import VPN": { - "Failed to import VPN": "Fehler beim importieren des VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "SMS-App konnte nicht gestartet werden" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Fehler beim laden der VPN-Konfiguration" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Zwischenablage-Konfiguration konnte nicht geladen werden." - }, - "Failed to move job": { - "Failed to move job": "Auftrag konnte nicht verschoben werden" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "plugin_settings.json konnte nicht geparst werden" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "session.json konnte nicht geparst werden" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "settings.json konnte nicht geparst werden" - }, - "Failed to pause printer": { - "Failed to pause printer": "Fehler beim Pausieren des Druckers" - }, - "Failed to pin entry": { - "Failed to pin entry": "Eintrag konnte nicht angeheftet werden" - }, - "Failed to print test page": { - "Failed to print test page": "Fehler beim Drucken der Testseite" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Kopplung konnte nicht abgelehnt werden" - }, - "Failed to remove device": { - "Failed to remove device": "Gerät entfernen fehlgeschlagen" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Tastenkürzel konnte nicht entfernt werden" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Drucker konnte nicht aus der Klasse entfernt werden" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Neustart des Audiosystems fehlgeschlagen" - }, - "Failed to restart job": { - "Failed to restart job": "Auftrag konnte nicht neu gestartet werden" - }, - "Failed to resume printer": { - "Failed to resume printer": "Fehler bei der Wiederaufnahme des Druckauftrages" - }, - "Failed to ring device": { - "Failed to ring device": "Gerät konnte nicht klingeln gelassen werden" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Fehler beim Ausführen von 'dms greeter status'. Stellen Sie sicher, dass DMS installiert ist und dms im PATH liegt." - }, - "Failed to save audio config": { - "Failed to save audio config": "Speichern der Audiokonfiguration fehlgeschlagen" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Zwischenablage-Einstellung konnte nicht gespeichert werden" - }, - "Failed to save keybind": { - "Failed to save keybind": "Tastenkürzel konnte nicht gespeichert werden" - }, - "Failed to save profile file": { - "Failed to save profile file": "Profildatei konnte nicht gespeichert werden" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Zwischenablage konnte nicht gesendet werden" - }, - "Failed to send file": { - "Failed to send file": "Datei senden fehlgeschlagen" - }, - "Failed to send ping": { - "Failed to send ping": "Ping konnte nicht gesendet werden" - }, - "Failed to set brightness": { - "Failed to set brightness": "Helligkeit konnte nicht eingestellt werden" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Standort für Nachtmodus konnte nicht eingestellt werden" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Zeitplan für Nachtmodus konnte nicht eingestellt werden" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Farbtemperatur für Nachtmodus konnte nicht eingestellt werden" - }, - "Failed to set power profile": { - "Failed to set power profile": "Energieprofil konnte nicht festgelegt werden" - }, - "Failed to set profile image": { - "Failed to set profile image": "Fehler beim setzen des Profilbildes" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Profilbild konnte nicht gesetzt werden: %1" - }, - "Failed to share": { - "Failed to share": "Teilen fehlgeschlagen" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Start der Verbindung zu %1 fehlgeschlagen" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Eintrag konnte nicht losgeheftet werden" - }, - "Failed to update VPN": { - "Failed to update VPN": "Fehler beim updaten des VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Aktualisierung der automatischen Verbindung fehlgeschlagen" - }, - "Failed to update description": { - "Failed to update description": "Beschreibung konnte nicht aktualisiert werden" - }, - "Failed to update location": { - "Failed to update location": "Standort konnte nicht aktualisiert werden" - }, - "Failed to update sharing": { - "Failed to update sharing": "Freigabe konnte nicht aktualisiert werden" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Temporäre Datei zur Validierung konnte nicht geschrieben werden" - }, - "Features": { - "Features": "Funktionen" - }, - "Feels": { - "Feels": "Gefühlt" - }, - "Feels Like": { - "Feels Like": "Gefühlte Temperatur" - }, - "Feels Like %1°": { - "Feels Like %1°": "Gefühlt %1°" - }, - "Fidelity": { - "Fidelity": "Originaltreue" - }, - "Field": { - "Field": "Feld" - }, - "File": { - "File": "Datei" - }, - "File Already Exists": { - "File Already Exists": "Datei existiert bereits" - }, - "File Information": { - "File Information": "Dateiinformation" - }, - "File received from": { - "File received from": "Datei empfangen von" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Dateisuche erfordert dsearch\nVon github.com/AvengeMedia/danksearch installieren" - }, - "Files": { - "Files": "Dateien" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Dateisystem-Nutzungsüberwachung" - }, - "Fill": { - "Fill": "Füllen" - }, - "Find in Text": { - "Find in Text": "In Text suchen" - }, - "Find in note...": { - "Find in note...": "In Notiz suchen..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "Verfügbarkeit des Fingerabdrucks konnte nicht bestätigt werden." - }, - "Fingerprint error": { - "Fingerprint error": "Fingerabdruckfehler" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "Fingerabdruckfehler: %1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "Fingerabdruck nicht erkannt (%1/%2). Bitte versuchen Sie es erneut oder verwenden Sie das Passwort." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Fingerabdruckleser erkannt, aber es sind noch keine Abdrücke registriert. Sie können dies jetzt aktivieren und später registrieren." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "Fingerabdruckleser erkannt, aber es sind noch keine Abdrücke registriert. Sie können dies jetzt aktivieren und später Sync ausführen." - }, - "Finish": { - "Finish": "Abschließen" - }, - "First Day of Week": { - "First Day of Week": "Erster Wochentag" - }, - "First Time Setup": { - "First Time Setup": "Ersteinrichtung" - }, - "Fit": { - "Fit": "Anpassen" - }, - "Fix Now": { - "Fix Now": "Jetzt beheben" - }, - "Fixing...": { - "Fixing...": "Behebe..." - }, - "Flags": { - "Flags": "Flags" - }, - "Flipped": { - "Flipped": "Gespiegelt" - }, - "Flipped 180°": { - "Flipped 180°": "Gespiegelt 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Gespiegelt 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Gespiegelt 90°" - }, - "Float": { - "Float": "Schwebend" - }, - "Focus": { - "Focus": "Fokus" - }, - "Focus at Startup": { - "Focus at Startup": "Fokus beim Start" - }, - "Focused Border": { - "Focused Border": "Fokussierter Rand" - }, - "Focused Color": { - "Focused Color": "Fokussierte Farbe" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Nur fokussierter Monitor" - }, - "Focused Window": { - "Focused Window": "Fokussiertes Fenster" - }, - "Focused monitor only": { - "Focused monitor only": "Nur fokussierter Monitor" - }, - "Fog": { - "Fog": "Nebel" - }, - "Folder": { - "Folder": "Ordner" - }, - "Folders": { - "Folders": "Ordner" - }, - "Follow DMS background color": { - "Follow DMS background color": "DMS-Hintergrundfarbe folgen" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Monitorfokus folgen" - }, - "Follow focus": { - "Follow focus": "Fokus folgen" - }, - "Font": { - "Font": "Schriftart" - }, - "Font Family": { - "Font Family": "Schriftart" - }, - "Font Scale": { - "Font Scale": "Schriftskalierung" - }, - "Font Size": { - "Font Size": "Schriftgrösse" - }, - "Font Weight": { - "Font Weight": "Schriftstärke" - }, - "Font used on the login screen": { - "Font used on the login screen": "Auf dem Anmeldebildschirm verwendete Schriftart" - }, - "Force HDR": { - "Force HDR": "HDR erzwingen" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Beenden erzwingen (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Breiten Farbraum erzwingen" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Terminalanwendungen zwingen immer dunkle Farbschemata zu verwenden" - }, - "Forecast": { - "Forecast": "Vorhersage" - }, - "Forecast Days": { - "Forecast Days": "Vorhersagetage" - }, - "Forecast Not Available": { - "Forecast Not Available": "Vorhersage nicht verfügbar" - }, - "Forever": { - "Forever": "Dauerhaft" - }, - "Forget": { - "Forget": "Vergessen" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "\"%1\" vergessen?" - }, - "Forget Device": { - "Forget Device": "Gerät vergessen" - }, - "Forget Network": { - "Forget Network": "Netzwerk vergessen" - }, - "Forgot network %1": { - "Forgot network %1": "Netzwerk %1 vergessen" - }, - "Format Legend": { - "Format Legend": "Legende formatieren" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "Ein Paket zum Aktualisieren gefunden:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "%1 Pakete zum Aktualisieren gefunden:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "VRAM/Speicher freigeben, wenn der Launcher geschlossen wird. Kann beim erneuten Öffnen zu einer leichten Verzögerung führen." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Gefrierender Nieselregen" - }, - "Frequency": { - "Frequency": "Frequenz" - }, - "Fruit Salad": { - "Fruit Salad": "Obstsalat" - }, - "Full Command:": { - "Full Command:": "Vollständiger Befehl:" - }, - "Full Content": { - "Full Content": "Vollständiger Inhalt" - }, - "Full Day & Month": { - "Full Day & Month": "Ganzer Tag & Monat" - }, - "Full with Year": { - "Full with Year": "Vollständig mit Jahr" - }, - "Fullscreen": { - "Fullscreen": "Vollbild" - }, - "Fullscreen Only": { - "Fullscreen Only": "Nur Vollbild" - }, - "Fully Charged": { - "Fully Charged": "Komplett geladen" - }, - "Fun": { - "Fun": "Spaß" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: Gitter • Z/X: Größe" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "GPU-Überwachung" - }, - "GPU Temperature": { - "GPU Temperature": "GPU Temperatur" - }, - "GPU temperature display": { - "GPU temperature display": "GPU-Temperaturanzeige" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDEs, mehr" - }, - "Games": { - "Games": "Spiele" - }, - "Gamma Control": { - "Gamma Control": "Gamma-Steuerung" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Gamma-Steuerung nicht verfügbar. Erfordert DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "Basis-GTK3/4- oder QT5/QT6-Konfigurationen (erfordert qt6ct-kde) erstellen, um DMS-Farben zu folgen. Nur einmal erforderlich.

        Es wird empfohlen, adw-gtk3 vor der Anwendung von GTK-Themes zu konfigurieren." - }, - "Generic": { - "Generic": "Generisch" - }, - "Get Started": { - "Get Started": "Erste Schritte" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Alle Animationsdauern global skalieren" - }, - "Golden Hour": { - "Golden Hour": "Goldene Stunde" - }, - "Good": { - "Good": "Gut" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Goth-Eckenradius" - }, - "Goth Corners": { - "Goth Corners": "Goth Ecken" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Den Bildschirm vor dem Sperren schrittweise ausblenden mit einer konfigurierbaren Schonfrist" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Bildschirm schrittweise ausblenden, bevor die Monitore mit einer konfigurierbaren Schonfrist ausgeschaltet werden" - }, - "Graph Time Range": { - "Graph Time Range": "Zeitbereich des Diagramms" - }, - "Graphics": { - "Graphics": "Grafik" - }, - "Greeter": { - "Greeter": "Greeter" - }, - "Greeter Appearance": { - "Greeter Appearance": "Greeter-Erscheinungsbild" - }, - "Greeter Behavior": { - "Greeter Behavior": "Greeter-Verhalten" - }, - "Greeter Status": { - "Greeter Status": "Greeter-Status" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Greeter aktiviert. greetd ist jetzt aktiviert." - }, - "Greeter font": { - "Greeter font": "Greeter-Schriftart" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Nur Greeter — betrifft nicht die Hauptuhr" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Nur Greeter — Format für das Datum auf dem Anmeldebildschirm" - }, - "Grid": { - "Grid": "Gitter" - }, - "Grid Columns": { - "Grid Columns": "Gitter-Spalten" - }, - "Grid: OFF": { - "Grid: OFF": "Gitter: AUS" - }, - "Grid: ON": { - "Grid: ON": "Gitter: AN" - }, - "Group": { - "Group": "Gruppe" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Arbeitsbereich-Apps gruppieren" - }, - "Group by App": { - "Group by App": "Nach Anwendung gruppieren" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Gruppiere mehrere Fenster derselben Anwendung zusammen mit Fensteranzahl-Anzeige" - }, - "Group removed": { - "Group removed": "Gruppe entfernt" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Wiederholte Anwendungssymbole in nicht fokussierten Arbeitsbereichen gruppieren" - }, - "Groups": { - "Groups": "Gruppen" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR Tone Mapping" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "Der HDR-Modus ist experimentell. Vergewissern Sie sich, dass Ihr Monitor HDR unterstützt, bevor Sie ihn aktivieren." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML in die Zwischenablage kopiert" - }, - "Health": { - "Health": "Gesundheit" - }, - "Heavy Rain": { - "Heavy Rain": "Starker Regen" - }, - "Heavy Snow": { - "Heavy Snow": "Starker Schneefall" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Starker Schneeschauer" - }, - "Height": { - "Height": "Höhe" - }, - "Held": { - "Held": "Angehalten" - }, - "Help": { - "Help": "Hilfe" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Ruhezustand" - }, - "Hidden": { - "Hidden": "Verborgen" - }, - "Hidden (%1)": { - "Hidden (%1)": "Ausgeblendet (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Versteckte Apps" - }, - "Hidden Network": { - "Hidden Network": "Verborgenes Netzwerk" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Versteckte Apps erscheinen nicht im Launcher. Rechtsklicken Sie auf eine App und wählen Sie 'App ausblenden', um sie zu verstecken." - }, - "Hide": { - "Hide": "Ausblenden" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Drittanbieter ausblenden" - }, - "Hide App": { - "Hide App": "App ausblenden" - }, - "Hide Delay": { - "Hide Delay": "Ausblendverzögerung" - }, - "Hide Indicators": { - "Hide Indicators": "Indikatoren ausblenden" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Updater-Widget ausblenden" - }, - "Hide When Typing": { - "Hide When Typing": "Beim Tippen ausblenden" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Ausblenden, wenn Fenster geöffnet sind" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Cursor nach Inaktivität ausblenden (0 = deaktiviert)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Cursor beim Drücken von Tasten ausblenden" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Cursor bei Touch-Eingabe ausblenden" - }, - "Hide device": { - "Hide device": "Gerät ausblenden" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Benachrichtigungsinhalt ausblenden, bis er erweitert wird" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Benachrichtigungsinhalt ausblenden, bis er erweitert wird; Popups werden standardmäßig minimiert angezeigt" - }, - "Hide on Touch": { - "Hide on Touch": "Bei Berührung ausblenden" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "High-Fidelity-Palette, die Quellfarbtöne bewahrt." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Aktive Workspace-App hervorheben" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "Die aktuell fokussierte App in den Workspace-Indikatoren hervorheben" - }, - "History": { - "History": "Verlauf" - }, - "History Retention": { - "History Retention": "Aufbewahrungsdauer des Verlaufs" - }, - "History Settings": { - "History Settings": "Verlaufseinstellungen" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Verlauf gelöscht. %1 angeheftete Einträge behalten." - }, - "Hold Duration": { - "Hold Duration": "Halte Dauer" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Halte länger zum bestätigen" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Halten um Energieoption zu bestätigen" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Gedrückt halten zum Bestätigen (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Halten zum bestätigen (%1s)" - }, - "Home": { - "Home": "Zuhause" - }, - "Host": { - "Host": "Host" - }, - "Hostname": { - "Hostname": "Hostname" - }, - "Hot Corners": { - "Hot Corners": "Aktive Ecken" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Hotkey-Overlay-Titel (optional)" - }, - "Hour": { - "Hour": "Stunde" - }, - "Hourly": { - "Hourly": "Stündlich" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Anzahl der stündlichen Vorhersagen" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Wie oft soll der Hintergrund gewechselt werden" - }, - "How the background image is scaled": { - "How the background image is scaled": "Wie das Hintergrundbild skaliert wird" - }, - "Humidity": { - "Humidity": "Feuchtigkeit" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Hyprland Discord-Server" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland-Layout-Überschreibungen" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland-Optionen" - }, - "Hyprland Website": { - "Hyprland Website": "Hyprland Webseite" - }, - "I Understand": { - "I Understand": "Ich verstehe" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP Adresse:" - }, - "IP address or hostname": { - "IP address or hostname": "IP-Adresse oder Hostname" - }, - "ISO Date": { - "ISO Date": "ISO-Datum" - }, - "Icon": { - "Icon": "Icon" - }, - "Icon Scale": { - "Icon Scale": "Icon-Skalierung" - }, - "Icon Size": { - "Icon Size": "Icon Größe" - }, - "Icon Size %": { - "Icon Size %": "Icon Größe %" - }, - "Icon Theme": { - "Icon Theme": "Icon Theme" - }, - "Idle": { - "Idle": "Leerlauf" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inaktivitätssperre" - }, - "Idle Settings": { - "Idle Settings": "Inaktivitätseinstellungen" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Idle-Überwachung nicht unterstützt - erfordert neuere Quickshell Version" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Wenn das Feld ausgeblendet ist, erscheint es, sobald eine Taste gedrückt wird." - }, - "Ignore Completely": { - "Ignore Completely": "Vollständig ignorieren" - }, - "Image": { - "Image": "Bild" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Bild in Zwischenablage kopiert" - }, - "Import": { - "Import": "Importieren" - }, - "Import VPN": { - "Import VPN": "VPN importieren" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Farbe für inaktive Monitore" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Einschließlich Übergänge" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Desktop-Aktionen (Verknüpfungen) in Suchergebnisse einbeziehen." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Inkompatible Plugins geladen" - }, - "Incorrect password": { - "Incorrect password": "Passwort nicht korrekt" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Falsches Passwort - Versuch %1 von %2 (Sperrung kann folgen)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Falsches Passwort - nächste Fehler können zur Kontosperrung führen" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "Falsches Passwort – bitte erneut versuchen" - }, - "Indicator Style": { - "Indicator Style": "Indikatorstil" - }, - "Individual Batteries": { - "Individual Batteries": "Einzelne Akkus" - }, - "Individual bar configuration": { - "Individual bar configuration": "Individuelle Leistenkonfiguration" - }, - "Info": { - "Info": "Info" - }, - "Inherit": { - "Inherit": "Vererben" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Global übernehmen (Standard)" - }, - "Inhibitable": { - "Inhibitable": "Unterdrückbar" - }, - "Input Devices": { - "Input Devices": "Eingabegeräte" - }, - "Input Volume Slider": { - "Input Volume Slider": "Eingangslautstärkeregler" - }, - "Insert your security key...": { - "Insert your security key...": "Setzen Sie Ihren Sicherheitsschlüssel ein..." - }, - "Install": { - "Install": "Installieren" - }, - "Install Greeter": { - "Install Greeter": "Greeter installieren" - }, - "Install Plugin": { - "Install Plugin": "Plugin installieren" - }, - "Install Theme": { - "Install Theme": "Theme installieren" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Farbschemata aus der DMS-Theme-Registry installieren" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Installation abgeschlossen. Greeter wurde installiert." - }, - "Install failed: %1": { - "Install failed: %1": "Installation fehlgeschlagen: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Installieren Sie das matugen-Paket für dynamisches Theming" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Plugin '%1' aus der DMS-Registry installieren?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Installiere Plugins aus der DMS Plugin-Registry" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "DMS Greeter installieren? Ein Terminal für die Sudo-Authentifizierung wird geöffnet." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Theme '%1' aus der DMS-Registry installieren?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Installation und PAM-Einrichtung: siehe die " - }, - "Installed": { - "Installed": "Installiert" - }, - "Installed: %1": { - "Installed: %1": "Installiert: %1" - }, - "Installing: %1": { - "Installing: %1": "Installiere: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Intelligentes automatisches Ausblenden" - }, - "Intensity": { - "Intensity": "Intensität" - }, - "Interface:": { - "Interface:": "Schnittstelle:" - }, - "Interlock Open": { - "Interlock Open": "Verriegelung offen" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervall" - }, - "Invalid configuration": { - "Invalid configuration": "Invalide Konfiguration" - }, - "Invert on mode change": { - "Invert on mode change": "Invertieren bei Moduswechsel" - }, - "Iris Bloom": { - "Iris Bloom": "Iris-Blüte" - }, - "Isolate Displays": { - "Isolate Displays": "Displays isolieren" - }, - "Jobs": { - "Jobs": "Druckaufträge" - }, - "Jobs: ": { - "Jobs: ": "Druckaufträge: " - }, - "Keep Awake": { - "Keep Awake": "Wach halten" - }, - "Keep Changes": { - "Keep Changes": "Änderungen beibehalten" - }, - "Keeping Awake": { - "Keeping Awake": "am wach halten" - }, - "Kernel": { - "Kernel": "Kernel" - }, - "Key": { - "Key": "Taste" - }, - "Keybind Sources": { - "Keybind Sources": "Tastenkombinationsquellen" - }, - "Keybinds": { - "Keybinds": "Tastenkombinationen" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Sucheinstellungen für Tastenkombinationen" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Tastenkombinationen werden neben regulären Suchergebnissen angezeigt" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Tastatur Layout Name" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Tastenkombinationen" - }, - "Keys": { - "Keys": "Tasten" - }, - "Kill": { - "Kill": "Beenden" - }, - "Kill Process": { - "Kill Process": "Prozess beenden" - }, - "Kill Session": { - "Kill Session": "Sitzung beenden" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED-Gerät" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC-Kanal" - }, - "LabWC Website": { - "LabWC Website": "LabWC Webseite" - }, - "Large": { - "Large": "Groß" - }, - "Largest": { - "Largest": "Größte" - }, - "Last hour": { - "Last hour": "Letzte Stunde" - }, - "Last launched %1": { - "Last launched %1": "Zuletzt geöffnet %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Zuletzt gestartet vor %1 Tag" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Zuletzt gestartet vor %1 Tagen" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Zuletzt gestartet vor %1 Stunde" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Zuletzt gestartet vor %1 Stunden" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Zuletzt gestartet vor %1 Minute" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Zuletzt vor %1 Minuten gestartet" - }, - "Last launched just now": { - "Last launched just now": "Gerade eben zuletzt geöffnet" - }, - "Latitude": { - "Latitude": "Latitude" - }, - "Launch": { - "Launch": "Start" - }, - "Launch Prefix": { - "Launch Prefix": "Start Prefix" - }, - "Launch on dGPU": { - "Launch on dGPU": "Starte auf dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "Standardmäßig mit dGPU starten" - }, - "Launcher": { - "Launcher": "Launcher" - }, - "Launcher Button": { - "Launcher Button": "Launcher-Schaltfläche" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Launcher Button Logo" - }, - "Layout": { - "Layout": "Layout" - }, - "Layout Overrides": { - "Layout Overrides": "Layout-Überschreibungen" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "Layout- und Modulpositionen auf dem Greeter werden von Ihrer Shell synchronisiert (z. B. Bar-Konfiguration). Führen Sie Sync zum Anwenden aus." - }, - "Left": { - "Left": "Links" - }, - "Left Center": { - "Left Center": "Links zentriert" - }, - "Left Section": { - "Left Section": "Linke Sektion" - }, - "Light Direction": { - "Light Direction": "Lichtrichtung" - }, - "Light Mode": { - "Light Mode": "Heller Modus" - }, - "Light Rain": { - "Light Rain": "Leichter Regen" - }, - "Light Snow": { - "Light Snow": "Leichter Schneefall" - }, - "Light Snow Showers": { - "Light Snow Showers": "Leichter Schneeschauer" - }, - "Light mode base": { - "Light mode base": "Hellmodus Basis" - }, - "Light mode harmony": { - "Light mode harmony": "Hellmodus Harmonie" - }, - "Line": { - "Line": "Linie" - }, - "Line: %1": { - "Line: %1": "Zeile: %1" - }, - "Linear": { - "Linear": "Linear" - }, - "Lines: %1": { - "Lines: %1": "Zeilen: %1" - }, - "List": { - "List": "Liste" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Lebendige Palette mit gesättigten Akzenten." - }, - "Load Average": { - "Load Average": "Durchschnittliche Last" - }, - "Loading codecs...": { - "Loading codecs...": "Codecs werden geladen..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Tastenkürzel werden geladen..." - }, - "Loading trending...": { - "Loading trending...": "Trends werden geladen..." - }, - "Loading...": { - "Loading...": "Laden..." - }, - "Local": { - "Local": "Lokal" - }, - "Locale": { - "Locale": "Sprachumgebung" - }, - "Locale Settings": { - "Locale Settings": "Sprachumgebung-Einstellungen" - }, - "Location": { - "Location": "Standort" - }, - "Location Search": { - "Location Search": "Standort-Suche" - }, - "Lock": { - "Lock": "Sperren" - }, - "Lock Screen": { - "Lock Screen": "Sperrbildschirm" - }, - "Lock Screen Display": { - "Lock Screen Display": "Sperrbildschirm-Anzeige" - }, - "Lock Screen Format": { - "Lock Screen Format": "Sperrbildschirm-Format" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Verhalten des Sperrbildschirms" - }, - "Lock Screen layout": { - "Lock Screen layout": "Sperrbildschirm Layout" - }, - "Lock at startup": { - "Lock at startup": "Beim Start sperren" - }, - "Lock before suspend": { - "Lock before suspend": "Sperren vor Standby" - }, - "Lock fade grace period": { - "Lock fade grace period": "Schonfrist für Sperrausblendung" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "Authentifizierungsänderungen für den Sperrbildschirm werden automatisch angewendet und können ein Terminal öffnen, wenn eine Sudo-Authentifizierung erforderlich ist." - }, - "Locked": { - "Locked": "Gesperrt" - }, - "Log Out": { - "Log Out": "Ausloggen" - }, - "Logging in...": { - "Logging in...": "Anmeldung..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Anmelde-Authentifizierung" - }, - "Long": { - "Long": "Lang" - }, - "Long Text": { - "Long Text": "Langer Text" - }, - "Long press": { - "Long press": "Langes Drücken" - }, - "Longitude": { - "Longitude": "Längengrad" - }, - "Low Priority": { - "Low Priority": "Niedrige Priorität" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Stellen Sie sicher, dass KDE Connect oder Valent auf Ihren anderen Geräten läuft" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Plugins zur Erweiterung der DMS-Funktionalität verwalten und konfigurieren" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Verwalten Sie bis zu 4 unabhängige Leistenkonfigurationen. Jede Leiste hat ihre eigene Position, Widgets, Styling und Display-Zuweisung." - }, - "Management": { - "Management": "Verwaltung" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC-Layout-Überschreibungen" - }, - "Manual": { - "Manual": "Manuell" - }, - "Manual Coordinates": { - "Manual Coordinates": "Manuelle Koordinaten" - }, - "Manual Direction": { - "Manual Direction": "Manuelle Richtung" - }, - "Manual Gap Size": { - "Manual Gap Size": "Manuelle Abstandsgröße" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Manuelles Anzeigen/Verstecken" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Fensterklassennamen Symbolnamen zuordnen für korrekte Symbolanzeige" - }, - "Margin": { - "Margin": "äußerer Abstand" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Marker-Vorrat leer" - }, - "Marker Supply Low": { - "Marker Supply Low": "Marker-Vorrat fast leer" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Marker-Abfallbehälter fast voll" - }, - "Marker Waste Full": { - "Marker Waste Full": "Marker-Abfallbehälter voll" - }, - "Match Criteria": { - "Match Criteria": "Übereinstimmungskriterien" - }, - "Matches profile: %1": { - "Matches profile: %1": "Entspricht Profil: %1" - }, - "Material Colors": { - "Material Colors": "Material Farben" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Von Material Design inspirierte Farbschemata" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Material-Farben generiert aus dem Hintergrundbild" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "Von Material Design inspirierte Schatten und Erhöhungen auf Modalen, Popouts und Dialogen" - }, - "Matugen Contrast": { - "Matugen Contrast": "Matugen-Kontrast" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen nicht gefunden" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen Palette" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen Ziel Monitor" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen Vorlagen" - }, - "Max Edges": { - "Max Edges": "Max. Kanten" - }, - "Max H": { - "Max H": "Max H" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Max. angeheftete Apps" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Max. angeheftete Apps (0 = unbegrenzt)" - }, - "Max Running Apps": { - "Max Running Apps": "Max. laufende Apps" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Max. laufende Apps (0 = unbegrenzt)" - }, - "Max Volume": { - "Max Volume": "Maximale Lautstärke" - }, - "Max W": { - "Max W": "Max. W" - }, - "Max apps to show": { - "Max apps to show": "Max. Anwendungs zum anzeigen" - }, - "Max to Edges": { - "Max to Edges": "Max. an Kanten" - }, - "Maximize": { - "Maximize": "Maximieren" - }, - "Maximize Detection": { - "Maximize Detection": "Maximierungserkennung" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Widget-Icons maximieren" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Widget-Text maximieren" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maximale Größe der Einträge" - }, - "Maximum History": { - "Maximum History": "Maximaler Verlauf" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Maximale Anzahl angehefteter Einträge" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "Maximale Anzahl an Fingerabdruckversuchen erreicht. Bitte verwenden Sie das Passwort." - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Maximale Anzahl der Einträge in der Zwischenablage" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Maximale Anzahl an Einträgen, die gespeichert werden können" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Maximale Anzahl der zu behaltenden Benachrichtigungen" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Maximale Anzahl angehefteter Einträge erreicht" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Maximale Größe eines Eintrages in der Zwischenablage" - }, - "Media": { - "Media": "Medien" - }, - "Media Controls": { - "Media Controls": "Mediensteuerung" - }, - "Media Empty": { - "Media Empty": "Medium leer" - }, - "Media Jam": { - "Media Jam": "Medienstau" - }, - "Media Low": { - "Media Low": "Medium fast leer" - }, - "Media Needed": { - "Media Needed": "Medium benötigt" - }, - "Media Playback": { - "Media Playback": "Medienwiedergabe" - }, - "Media Player": { - "Media Player": "Mediaplayer" - }, - "Media Player Settings": { - "Media Player Settings": "Einstellungen für Media Player " - }, - "Media Players": { - "Media Players": "Medienplayer" - }, - "Media Players (": { - "Media Players (": "Media Players (" - }, - "Media Volume": { - "Media Volume": "Medienlautstärke" - }, - "Medium": { - "Medium": "Mittel" - }, - "Memory": { - "Memory": "Speicher" - }, - "Memory Graph": { - "Memory Graph": "Speicher Graph" - }, - "Memory Usage": { - "Memory Usage": "Speichernutzung" - }, - "Memory usage indicator": { - "Memory usage indicator": "Speicherauslastungsanzeige" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Nachricht" - }, - "Message Content": { - "Message Content": "Nachrichteninhalt" - }, - "Microphone": { - "Microphone": "Mikrofon" - }, - "Microphone Mute": { - "Microphone Mute": "Mikrofon stummschalten" - }, - "Microphone Volume": { - "Microphone Volume": "Mikrofonlautstärke" - }, - "Microphone settings": { - "Microphone settings": "Mikrofoneinstellungen" - }, - "Microphone volume control": { - "Microphone volume control": "Mikrofonlautstärkeregelung" - }, - "Middle Section": { - "Middle Section": "Mittlere Sektion" - }, - "Min H": { - "Min H": "Min H" - }, - "Min W": { - "Min W": "Min W" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Minimale Palette mit einem Farbton." - }, - "Minute": { - "Minute": "Minute" - }, - "Mirror Display": { - "Mirror Display": "Display spiegeln" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Fehlende Umgebungsvariablen" - }, - "Modal Background": { - "Modal Background": "Modaler Hintergrund" - }, - "Modal Shadows": { - "Modal Shadows": "Modale Schatten" - }, - "Modals": { - "Modals": "Modale" - }, - "Mode": { - "Mode": "Modus" - }, - "Mode:": { - "Mode:": "Modus:" - }, - "Model": { - "Model": "Modell" - }, - "Modified": { - "Modified": "Geändert" - }, - "Modular widget bar": { - "Modular widget bar": "Modulare Widget-Leiste" - }, - "Monitor": { - "Monitor": "Bildschirm" - }, - "Monitor Configuration": { - "Monitor Configuration": "Monitor Konfiguration" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Schonfrist für Monitorausblendung" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Monitor mit Hintergrundbild für dynamische Farbton-Bestimmung" - }, - "Monochrome": { - "Monochrome": "Monochrom" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "Monospace Schriftart" - }, - "Month Date": { - "Month Date": "Monat Datum" - }, - "Morning": { - "Morning": "Morgen" - }, - "Mount Points": { - "Mount Points": "Einhängepunkte" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Erscheinungsbild des Mauszeigers" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Mauszeigergröße in Pixeln" - }, - "Move": { - "Move": "Verschieben" - }, - "Move Widget": { - "Move Widget": "Verschiebe Widget" - }, - "Moving to Paused": { - "Moving to Paused": "Wird angehalten" - }, - "Multi-Monitor": { - "Multi-Monitor": "Multi-Monitor" - }, - "Multiplexer": { - "Multiplexer": "Multiplexer" - }, - "Multiplexer Type": { - "Multiplexer Type": "Multiplexer-Typ" - }, - "Multiplexers": { - "Multiplexers": "Multiplexer" - }, - "Music": { - "Music": "Musik" - }, - "Mute Popups": { - "Mute Popups": "Popups stummschalten" - }, - "Mute popups for %1": { - "Mute popups for %1": "Popups für %1 stummschalten" - }, - "Muted": { - "Muted": "Stumm" - }, - "Muted Apps": { - "Muted Apps": "Stummgeschaltete Apps" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Gedämpfte Palette mit beruhigenden, dezenten Farben." - }, - "NM not supported": { - "NM not supported": "NM nicht unterstützt" - }, - "Name": { - "Name": "Name" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Benannte Arbeitsfächen-Symbole" - }, - "Navigate": { - "Navigate": "Navigieren" - }, - "Navigation": { - "Navigation": "Navigation" - }, - "Network": { - "Network": "Netzwerk" - }, - "Network Graph": { - "Network Graph": "Netzwerk Graph" - }, - "Network Info": { - "Network Info": "Netzwerk-Info" - }, - "Network Information": { - "Network Information": "Netzwerkinformationen" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Netzwerkname (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Netzwerk-Geschwindigkeitsmonitor" - }, - "Network Status": { - "Network Status": "Netzwerkstatus" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Anzeige Netzwerk-Download- und -Upload-Geschwindigkeit" - }, - "Neutral": { - "Neutral": "Neutral" - }, - "Never": { - "Never": "Niemals" - }, - "Never used": { - "Never used": "Nie verwendet" - }, - "New": { - "New": "Neu" - }, - "New Key": { - "New Key": "Neue Taste" - }, - "New Keybind": { - "New Keybind": "Neues Tastenkürzel" - }, - "New Notification": { - "New Notification": "Neue Benachrichtigung" - }, - "New Session": { - "New Session": "Neue Sitzung" - }, - "New Window Rule": { - "New Window Rule": "Neue Fensterregel" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Neuer Gruppenname..." - }, - "Next": { - "Next": "Weiter" - }, - "Next Transition": { - "Next Transition": "Nächster Übergang" - }, - "Night": { - "Night": "Nacht" - }, - "Night Mode": { - "Night Mode": "Nachtmodus" - }, - "Night Temperature": { - "Night Temperature": "Farbtemperatur in der Nacht" - }, - "Night mode & gamma": { - "Night mode & gamma": "Nachtmodus & Gamma" - }, - "Niri Integration": { - "Niri Integration": "Niri-Integration" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri-Layout-Überschreibungen" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri-Compositor-Aktionen (Fokus, Verschieben, etc.)" - }, - "No": { - "No": "Nein" - }, - "No Active Players": { - "No Active Players": "Kein aktiver Player." - }, - "No Anim": { - "No Anim": "Keine Anim." - }, - "No Background": { - "No Background": "Kein Hintergrund" - }, - "No Battery": { - "No Battery": "Kein Akku" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Kein Bluetooth-Adapter gefunden" - }, - "No Blur": { - "No Blur": "Kein Weichzeichnen" - }, - "No Border": { - "No Border": "Kein Rand" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Keine DMS-Tastenkombinationen konfiguriert" - }, - "No Dim": { - "No Dim": "Kein Abdunkeln" - }, - "No Focus": { - "No Focus": "Kein Fokus" - }, - "No GPU detected": { - "No GPU detected": "Keine GPU erkannt" - }, - "No GPUs detected": { - "No GPUs detected": "Keine GPUs erkannt" - }, - "No History": { - "No History": "Kein Verlauf" - }, - "No Media": { - "No Media": "Keine Medien" - }, - "No Round": { - "No Round": "Nicht abgerundet" - }, - "No Rounding": { - "No Rounding": "Keine Abrundung" - }, - "No Shadow": { - "No Shadow": "Kein Schatten" - }, - "No VPN profiles": { - "No VPN profiles": "Keine VPN-Profile" - }, - "No Weather": { - "No Weather": "Kein Wetter" - }, - "No Weather Data": { - "No Weather Data": "Keine Wetterdaten" - }, - "No Weather Data Available": { - "No Weather Data Available": "Keine Wetterdaten verfügbar" - }, - "No action": { - "No action": "Keine Aktion" - }, - "No active %1 sessions": { - "No active %1 sessions": "Keine aktiven %1-Sitzungen" - }, - "No adapter": { - "No adapter": "Kein Adapter" - }, - "No adapters": { - "No adapters": "Keine Adapter" - }, - "No app customizations.": { - "No app customizations.": "Keine App-Anpassungen." - }, - "No apps found": { - "No apps found": "Keine Anwendungs gefunden" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Es wurden noch keine Apps gestartet." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Keine Apps stummgeschaltet. Rechtsklicken Sie auf eine Benachrichtigung und wählen Sie „Popups stummschalten“, um hier eine hinzuzufügen." - }, - "No battery": { - "No battery": "Kein Akku" - }, - "No brightness devices available": { - "No brightness devices available": "Keine Helligkeitsgeräte verfügbar" - }, - "No changes": { - "No changes": "Keine Änderungen" - }, - "No checks passed": { - "No checks passed": "Keine Prüfungen bestanden" - }, - "No custom theme file": { - "No custom theme file": "Keine benutzerdefinierte Theme-Datei" - }, - "No devices": { - "No devices": "Keine Geräte" - }, - "No devices connected": { - "No devices connected": "Keine Geräte verbunden" - }, - "No devices found": { - "No devices found": "Kein Gerät gefunden" - }, - "No disk data": { - "No disk data": "Keine Festplattendaten" - }, - "No disk data available": { - "No disk data available": "Keine Festplattendaten verfügbar" - }, - "No drivers found": { - "No drivers found": "Keine Treiber gefunden" - }, - "No errors": { - "No errors": "Keine Fehler" - }, - "No features enabled": { - "No features enabled": "Keine Funktionen aktiviert" - }, - "No files found": { - "No files found": "Keine Dateien gefunden" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Kein Fingerabdruckleser erkannt." - }, - "No folders found": { - "No folders found": "Keine Ordner gefunden" - }, - "No hidden apps.": { - "No hidden apps.": "Keine versteckten Apps." - }, - "No info items": { - "No info items": "Keine Info-Elemente" - }, - "No information available": { - "No information available": "Keine Informationen verfügbar" - }, - "No input device": { - "No input device": "Keine Eingabegeräte" - }, - "No input devices found": { - "No input devices found": "Keine Eingabegeräte gefunden" - }, - "No items added yet": { - "No items added yet": "Noch keine Einträge hinzugefügt" - }, - "No keybinds found": { - "No keybinds found": "Keine Tastenkürzel gefunden" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Keine Launcher-Plugins installiert." - }, - "No match criteria": { - "No match criteria": "Keine Übereinstimmungskriterien" - }, - "No matches": { - "No matches": "Keine Übereinstimmungen" - }, - "No matching processes": { - "No matching processes": "Keine passenden Prozesse" - }, - "No monitors": { - "No monitors": "Keine Bildschirme" - }, - "No mount points found": { - "No mount points found": "Keine Einhängepunkte gefunden" - }, - "No output device": { - "No output device": "Keine Ausgabegeräte" - }, - "No output devices found": { - "No output devices found": "Keine Ausgabegeräte gefunden" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Kein Paketmanager gefunden. Bitte installieren Sie 'paru' oder 'yay' auf Arch-basierten Systemen, um nach Updates zu suchen." - }, - "No plugin results": { - "No plugin results": "Keine Plugin-Ergebnisse" - }, - "No plugins found": { - "No plugins found": "Keine Plugins gefunden" - }, - "No plugins found.": { - "No plugins found.": "Keine Plugins gefunden." - }, - "No printer found": { - "No printer found": "Kein Drucker gefunden" - }, - "No printers configured": { - "No printers configured": "Keine Drucker eingerichtet" - }, - "No printers found": { - "No printers found": "Keine Drucker gefunden" - }, - "No profiles": { - "No profiles": "Keine Profile" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Keine aktuellen Einträge in der Zwischenablage gefunden" - }, - "No results found": { - "No results found": "Keine Ergebnisse gefunden" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Keine gespeicherten Einträge in der Zwischenablage" - }, - "No sessions found": { - "No sessions found": "Keine Sitzungen gefunden" - }, - "No status output.": { - "No status output.": "Keine Statusausgabe." - }, - "No themes found": { - "No themes found": "Keine Themes gefunden" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Keine Themes installiert. Durchsuchen Sie die Registry, um Themes zu installieren." - }, - "No trigger": { - "No trigger": "Kein Trigger" - }, - "No video found in folder": { - "No video found in folder": "Kein Video im Ordner gefunden" - }, - "No wallpaper selected": { - "No wallpaper selected": "Kein Hintergrundbild gewählt" - }, - "No wallpapers": { - "No wallpapers": "Keine Hintergrundbilder" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Keine Hintergrundbilder gefunden\n\nKlicken Sie unten auf das Ordnersymbol, um zu suchen" - }, - "No warnings": { - "No warnings": "Keine Warnungen" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Keine Widgets hinzugefügt. Klicken Sie auf „Widget hinzufügen“, um zu beginnen." - }, - "No widgets available": { - "No widgets available": "Keine Widgets verfügbar" - }, - "No widgets match your search": { - "No widgets match your search": "Keine Widgets zur Suche gefunden" - }, - "No window rules configured": { - "No window rules configured": "Keine Fensterregeln eingerichtet" - }, - "None": { - "None": "Nichts" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Normale Schriftart" - }, - "Normal Priority": { - "Normal Priority": "Standard-Priorität" - }, - "Not available": { - "Not available": "Nicht verfügbar" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Nicht verfügbar — installiere fprintd und pam_fprintd oder konfiguriere greetd PAM." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Nicht verfügbar — installiere fprintd und pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "Nicht verfügbar — installiere oder konfiguriere pam_u2f oder konfiguriere greetd PAM." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Nicht verfügbar — installiere oder konfiguriere pam_u2f." - }, - "Not connected": { - "Not connected": "Nicht verbunden" - }, - "Not detected": { - "Not detected": "Nicht erkannt" - }, - "Not paired": { - "Not paired": "Nicht gekoppelt" - }, - "Not set": { - "Not set": "Nicht festgelegt" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Hinweis: Dies ändert nur den Prozentsatz, die Ladung wird nicht tatsächlich begrenzt." - }, - "Notepad": { - "Notepad": "Notizblock" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Notizblock Schriftart-Einstellungen" - }, - "Notepad Slideout": { - "Notepad Slideout": "Notizen Ausklappmenü" - }, - "Nothing": { - "Nothing": "Nichts" - }, - "Nothing to see here": { - "Nothing to see here": "Nichts zu sehen" - }, - "Notification Center": { - "Notification Center": "Benachrichtigungszentrum" - }, - "Notification Display": { - "Notification Display": "Benachrichtigungsanzeige" - }, - "Notification Overlay": { - "Notification Overlay": "Benachrichtigungs-Overlay" - }, - "Notification Popups": { - "Notification Popups": "Benachrichtigungs-Popups" - }, - "Notification Rules": { - "Notification Rules": "Benachrichtigungsregeln" - }, - "Notification Settings": { - "Notification Settings": "Benachrichtigungseinstellungen" - }, - "Notification Timeouts": { - "Notification Timeouts": "Benachrichtigungszeitüberschreitungen" - }, - "Notification toast popups": { - "Notification toast popups": "Benachrichtigungs‑Toast" - }, - "Notifications": { - "Notifications": "Benachrichtigungen" - }, - "Numbers": { - "Numbers": "Zahlen" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numerisch (T/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numerisch (M/T)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Betriebssystem-Logo" - }, - "OSD Position": { - "OSD Position": "OSD-Position" - }, - "Occupied Color": { - "Occupied Color": "Belegte Farbe" - }, - "Off": { - "Off": "Aus" - }, - "Office": { - "Office": "Büro" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Offline Report" - }, - "Older": { - "Older": "Älter" - }, - "On": { - "On": "Ein" - }, - "On-Demand": { - "On-Demand": "Auf Abruf" - }, - "On-Screen Displays": { - "On-Screen Displays": "Bildschirm‑anzeigen" - }, - "On-screen Displays": { - "On-screen Displays": "Bildschirmanzeigen (OSD)" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Nur die Gamma-Einstellung basierend auf Zeit- oder Ortsregeln anpassen." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "Betrifft nur von DMS verwaltetes PAM. Wenn greetd bereits pam_fprintd enthält, bleibt der Fingerabdruck aktiviert." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Nur Fenster des aktuellen Monitors in jedem Dock anzeigen" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Nur sichtbar, wenn Ruhezustand von Ihrem System unterstützt wird" - }, - "Opacity": { - "Opacity": "Deckkraft" - }, - "Opaque": { - "Opaque": "Deckend" - }, - "Open": { - "Open": "Öffnen" - }, - "Open App": { - "Open App": "App öffnen" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Öffnen Sie KDE Connect auf Ihrem Telefon" - }, - "Open Notepad File": { - "Open Notepad File": "Notizbuch-Datei öffnen" - }, - "Open a new note": { - "Open a new note": "Öffne eine neue Notiz" - }, - "Open folder": { - "Open folder": "Ordner öffnen" - }, - "Open in Browser": { - "Open in Browser": "Im Browser öffnen" - }, - "Open in terminal": { - "Open in terminal": "Terminal öffnen" - }, - "Open search bar to find text": { - "Open search bar to find text": "Suchleiste öffnen, um Text zu finden" - }, - "Open with...": { - "Open with...": "Öffnen mit…" - }, - "Opening SMS": { - "Opening SMS": "SMS wird geöffnet" - }, - "Opening SMS app": { - "Opening SMS app": "SMS-App wird geöffnet" - }, - "Opening file browser": { - "Opening file browser": "Dateibrowser wird geöffnet" - }, - "Opening files": { - "Opening files": "Dateien werden geöffnet" - }, - "Opening terminal: ": { - "Opening terminal: ": "Terminal wird geöffnet: " - }, - "Optional description": { - "Optional description": "Optionale Beschreibung" - }, - "Optional location": { - "Optional location": "Optionaler Standort" - }, - "Options": { - "Options": "Optionen" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Widgets in ausklappbaren Gruppen organisieren" - }, - "Original: %1": { - "Original: %1": "Original: %1" - }, - "Other": { - "Other": "Andere" - }, - "Outline": { - "Outline": "Umriss" - }, - "Output": { - "Output": "Ausgabe" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Ausgabebereich fast voll" - }, - "Output Area Full": { - "Output Area Full": "Ausgabebereich voll" - }, - "Output Device": { - "Output Device": "Ausgabegerät" - }, - "Output Devices": { - "Output Devices": "Ausgabegeräte" - }, - "Output Tray Missing": { - "Output Tray Missing": "Ausgabefach fehlt" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Ausgaben inklusive fehlender" - }, - "Overcast": { - "Overcast": "Bedeckt" - }, - "Overflow": { - "Overflow": "Überlauf" - }, - "Overridden by config": { - "Overridden by config": "Durch Konfiguration überschrieben" - }, - "Override": { - "Override": "Überschreiben" - }, - "Override Border Size": { - "Override Border Size": "Rahmengröße überschreiben" - }, - "Override Corner Radius": { - "Override Corner Radius": "Überschreibe Abrundungsradius" - }, - "Override Gaps": { - "Override Gaps": "Abstände überschreiben" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Überschreibe globale Layouteinstellungen für diesen Monitor" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Terminal mit einem benutzerdefinierten Befehl oder Skript überschreiben" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "Globalen Schatten durch Einstellungen pro Leiste überschreiben" - }, - "Overrides": { - "Overrides": "überschreibt" - }, - "Overview": { - "Overview": "Übersicht" - }, - "Overview of your network connections": { - "Overview of your network connections": "Übersicht Ihrer Netzwerkverbindungen" - }, - "Overwrite": { - "Overwrite": "Überschreiben" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM bietet bereits Fingerabdruck-Authentifizierung. Aktiviere dies, um sie beim Login anzuzeigen." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM bietet bereits Sicherheitsschlüssel-Authentifizierung. Aktiviere dies, um sie beim Login anzuzeigen." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM bietet Fingerabdruck-Authentifizierung, aber die Verfügbarkeit konnte nicht bestätigt werden." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM bietet Fingerabdruck-Authentifizierung, aber es wurden noch keine Abdrücke registriert." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM bietet Fingerabdruck-Authentifizierung, aber es wurde kein Lesegerät erkannt." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Auffüllen" - }, - "Pad Hours": { - "Pad Hours": "Stunden auffüllen" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "Stunden auffüllen (02:00 vs. 2:00)" - }, - "Padding": { - "Padding": "Innenabstand" - }, - "Pair": { - "Pair": "Koppeln" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Koppel Bluetooth Gerät" - }, - "Paired": { - "Paired": "Gekoppelt" - }, - "Pairing": { - "Pairing": "Kopplung" - }, - "Pairing failed": { - "Pairing failed": "Koppeln fehlgeschlagen" - }, - "Pairing request from": { - "Pairing request from": "Kopplungsanfrage von" - }, - "Pairing request sent": { - "Pairing request sent": "Kopplungsanfrage gesendet" - }, - "Pairing requested": { - "Pairing requested": "Kopplung angefordert" - }, - "Pairing...": { - "Pairing...": "Koppeln..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Teilweise bewölkt" - }, - "Passkey:": { - "Passkey:": "Passkey:" - }, - "Password": { - "Password": "Passwort" - }, - "Password...": { - "Password...": "Passwort..." - }, - "Paste": { - "Paste": "Einfügen" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Pfad zu einer Videodatei oder einem Ordner mit Videos" - }, - "Pattern": { - "Pattern": "Muster" - }, - "Pause": { - "Pause": "Pause" - }, - "Paused": { - "Paused": "Pausiert" - }, - "Pending": { - "Pending": "Unerledigt" - }, - "Pending Charge": { - "Pending Charge": "Ladung steht aus" - }, - "Pending Discharge": { - "Pending Discharge": "Entladung steht aus" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Pro-Modus Hintergründe" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Pro-Monitor Hintergründe" - }, - "Per-screen config": { - "Per-screen config": "Konfiguration pro Bildschirm" - }, - "Percentage": { - "Percentage": "Prozent" - }, - "Performance": { - "Performance": "Leistung" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Fehlende Berechtigung zum setzen eines Profilbildes." - }, - "Personalization": { - "Personalization": "Personalisierung" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Telefonverbindung nicht verfügbar" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Telefonverbindung nicht verfügbar" - }, - "Phone number": { - "Phone number": "Telefonnummer" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Jedes Mal ein anderes zufälliges Video aus demselben Ordner wählen" - }, - "Pictures": { - "Pictures": "Bilder" - }, - "Pin": { - "Pin": "Anheften" - }, - "Pin to Dock": { - "Pin to Dock": "An Dock anpinnen" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping senden" - }, - "Ping sent to": { - "Ping sent to": "Ping senden an" - }, - "Pinned": { - "Pinned": "Angeheftet" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Angeheftete und laufende Apps mit Drag-and-Drop" - }, - "Pixelate": { - "Pixelate": "Verpixeln" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Legen Sie hier die Plugin-Verzeichnisse ab. Jedes Plugin sollte eine Manifestdatei namens plugin.json enthalten." - }, - "Place plugins in %1": { - "Place plugins in %1": "Plugins in %1 platzieren" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Ein Video abspielen, wenn der Bildschirm gesperrt wird." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Tonausgabe bei neuer Benachrichtigung" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Tonausgabe wenn Stromkabel eingesteckt" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Tonausgabe bei ändern der Lautstärke" - }, - "Play sounds for system events": { - "Play sounds for system events": "Tonausgabe für System Ereignisse" - }, - "Playback": { - "Playback": "Wiedergabe" - }, - "Playback error: ": { - "Playback error: ": "Wiedergabefehler: " - }, - "Please wait...": { - "Please wait...": "Bitte warten..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Bitte gib einen Namen für deine neue %1-Sitzung ein" - }, - "Plugged In": { - "Plugged In": "Eingesteckt" - }, - "Plugged in": { - "Plugged in": "Eingesteckt" - }, - "Plugin": { - "Plugin": "Plugin" - }, - "Plugin Directory": { - "Plugin Directory": "Plugin Verzeichnis" - }, - "Plugin Management": { - "Plugin Management": "Plugin Management" - }, - "Plugin Visibility": { - "Plugin Visibility": "Plugin-Sichtbarkeit" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Plugin ist deaktiviert – in den Plugin-Einstellungen aktivieren, um es zu verwenden" - }, - "Plugins": { - "Plugins": "Plugins" - }, - "Pointer": { - "Pointer": "Zeiger" - }, - "Popout Shadows": { - "Popout Shadows": "Popout-Schatten" - }, - "Popouts": { - "Popouts": "Popouts" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Popouts und Modale folgen der globalen Animationsgeschwindigkeit (deaktivieren, um sie einzeln anzupassen)" - }, - "Popup Only": { - "Popup Only": "Nur Popup" - }, - "Popup Position": { - "Popup Position": "Popup Position" - }, - "Popup Shadow": { - "Popup Shadow": "Popup-Schatten" - }, - "Popup Transparency": { - "Popup Transparency": "Popup Transparenz" - }, - "Popup behavior, position": { - "Popup behavior, position": "Popup-Verhalten, Position" - }, - "Port": { - "Port": "Port" - }, - "Portal": { - "Portal": "Portal" - }, - "Position": { - "Position": "Position" - }, - "Position, pinned apps": { - "Position, pinned apps": "Position, angeheftete Apps" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Mögliche Überschreibungskonflikte" - }, - "Power": { - "Power": "Energie" - }, - "Power & Security": { - "Power & Security": "Energieoptionen & Sicherheit" - }, - "Power & Sleep": { - "Power & Sleep": "Energie & Schlafmodus" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Bestätigung von Energieoptionen" - }, - "Power Menu Customization": { - "Power Menu Customization": "Energieoptionen im Power Menü anpassen" - }, - "Power Off": { - "Power Off": "Ausschalten" - }, - "Power Options": { - "Power Options": "Energieoptionen" - }, - "Power Profile": { - "Power Profile": "Energieprofil" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Leistungsverschlechterung" - }, - "Power Saver": { - "Power Saver": "Energiesparmodus" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Monitore beim Sperren ausschalten" - }, - "Power profile management available": { - "Power profile management available": "Energieprofilverwaltung verfügbar" - }, - "Power source": { - "Power source": "Stromquelle" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Den letzten erfolgreichen Benutzernamen im Greeter vorausfüllen" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "Die zuletzt verwendete Sitzung im Greeter vorauswählen" - }, - "Precip": { - "Precip": "Niederschlag" - }, - "Precipitation": { - "Precipitation": "Niederschlag" - }, - "Precipitation Chance": { - "Precipitation Chance": "Niederschlagswahrscheinlichkeit" - }, - "Preference": { - "Preference": "Präferenz" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Voreingestellte Breiten (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Drücke 'n' oder klicke auf 'Neue Sitzung', um eine zu erstellen" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Drücken Sie die Eingabetaste, um das Audiosystem neu zu starten und die Änderungen zu übernehmen" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Eingabetaste zum Einfügen, Umschalt+Eingabe zum Kopieren" - }, - "Press key...": { - "Press key...": "Drücke Taste..." - }, - "Pressure": { - "Pressure": "Druck" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Bildschirm-Timeout verhindern" - }, - "Preview": { - "Preview": "Vorschau" - }, - "Primary": { - "Primary": "Primär" - }, - "Primary Container": { - "Primary Container": "Primärer Container" - }, - "Print Server Management": { - "Print Server Management": "Druckerserververwaltung" - }, - "Print Server not available": { - "Print Server not available": "Drucker-Server nicht erreichbar" - }, - "Printer": { - "Printer": "Drucker" - }, - "Printer Classes": { - "Printer Classes": "Druckerklassen" - }, - "Printer created successfully": { - "Printer created successfully": "Drucker erfolgreich angelegt" - }, - "Printer deleted": { - "Printer deleted": "Drucker gelöscht" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Druckername (ohne Leerzeichen)" - }, - "Printer reachable": { - "Printer reachable": "Drucker erreichbar" - }, - "Printers": { - "Printers": "Drucker" - }, - "Printers: ": { - "Printers: ": "Drucker: " - }, - "Prioritize performance": { - "Prioritize performance": "Leistung priorisieren" - }, - "Priority": { - "Priority": "Priorität" - }, - "Privacy Indicator": { - "Privacy Indicator": "Datenschutzindikator" - }, - "Privacy Mode": { - "Privacy Mode": "Privatmodus" - }, - "Private Key Password": { - "Private Key Password": "Passwort für privaten Schlüssel" - }, - "Process Count": { - "Process Count": "Prozessanzahl" - }, - "Processes": { - "Processes": "Prozesse" - }, - "Processes:": { - "Processes:": "Prozesse:" - }, - "Processing": { - "Processing": "Verarbeitung" - }, - "Profile Image Error": { - "Profile Image Error": "Profilbildfehler" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profil aktiviert: %1" - }, - "Profile deleted": { - "Profile deleted": "Profil gelöscht" - }, - "Profile error": { - "Profile error": "Profilfehler" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Profilbild ist zu groß. Bitte ein kleineres Bild verwenden." - }, - "Profile name": { - "Profile name": "Profilname" - }, - "Profile not found": { - "Profile not found": "Profil nicht gefunden" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profil gespeichert: %1" - }, - "Protocol": { - "Protocol": "Protokoll" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia ist nicht verfügbar" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia ist nicht verfügbar – Video-Bildschirmschoner erfordert Qt-Multimedia-Dienste" - }, - "Quick Access": { - "Quick Access": "Schnellzugriff" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Schnellzugriff auf Anwendung-Starter" - }, - "Quick access to color picker": { - "Quick access to color picker": "Schnellzugriff auf den Farbwähler" - }, - "Quick access to notepad": { - "Quick access to notepad": "Schnellzugriff auf Notizblock" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Schnell‑Notizen‑Ausklappmenü" - }, - "Quick system toggles": { - "Quick system toggles": "System-Schnellschalter" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Radius" - }, - "Rain": { - "Rain": "Regen" - }, - "Rain Chance": { - "Rain Chance": "Regenwahrscheinlichkeit" - }, - "Rainbow": { - "Rainbow": "Regenborgen" - }, - "Random": { - "Random": "Zufällig" - }, - "Rate": { - "Rate": "Übertragungsrate" - }, - "Read:": { - "Read:": "Lesen:" - }, - "Reason": { - "Reason": "Grund" - }, - "Reboot": { - "Reboot": "Neustart" - }, - "Recent Colors": { - "Recent Colors": "Aktuelle Farben" - }, - "Recently Used Apps": { - "Recently Used Apps": "Zuletzt verwendete Apps" - }, - "Recommended available": { - "Recommended available": "Empfohlen verfügbar" - }, - "Refresh": { - "Refresh": "Aktualisieren" - }, - "Refresh Weather": { - "Refresh Weather": "Wetter aktualisieren" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Ablehnen" - }, - "Reject Jobs": { - "Reject Jobs": "Druckaufträge abbrechen" - }, - "Release": { - "Release": "Loslassen" - }, - "Reload Plugin": { - "Reload Plugin": "Plugin neu laden" - }, - "Remaining": { - "Remaining": "Verbleibend" - }, - "Remaining / Total": { - "Remaining / Total": "Verbleibend / Gesamt" - }, - "Remember Last Query": { - "Remember Last Query": "Letzte Suchanfrage merken" - }, - "Remember last session": { - "Remember last session": "Letzte Sitzung merken" - }, - "Remember last user": { - "Remember last user": "Letzten Benutzer merken" - }, - "Remove": { - "Remove": "Entfernen" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Widget-Abstand entfernen" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Abstände und Rahmen entfernen, wenn Fenster maximiert sind" - }, - "Rename": { - "Rename": "Umbenennen" - }, - "Rename Session": { - "Rename Session": "Sitzung umbenennen" - }, - "Rename Workspace": { - "Rename Workspace": "Arbeitsfläche umbenennen" - }, - "Repeat": { - "Repeat": "Wiederholen" - }, - "Replacement": { - "Replacement": "Ersetzung" - }, - "Report": { - "Report": "Report" - }, - "Request Pairing": { - "Request Pairing": "Kopplung anfordern" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Erfordert halten der Taste zum Herunterfahren, Neustarten, Anhalten, Ruhezustand und Abmelden" - }, - "Required plugin: ": { - "Required plugin: ": "Erforderliches Plugin: " - }, - "Requires %1": { - "Requires %1": "Erfordert %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Erfordert 'dgop' Tool" - }, - "Requires DMS %1": { - "Requires DMS %1": "Erfordert DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Erfordert DWL-Compositor" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "Erfordert eine neuere Version von Quickshell" - }, - "Requires night mode support": { - "Requires night mode support": "Erfordert Nachtmodus-Unterstützung" - }, - "Reset": { - "Reset": "Zurücksetzen" - }, - "Reset Position": { - "Reset Position": "Position zurücksetzen" - }, - "Reset Size": { - "Reset Size": "Größe zurücksetzen" - }, - "Reset to default name": { - "Reset to default name": "Auf Standardnamen zurücksetzen" - }, - "Resize Widget": { - "Resize Widget": "Widget-Größe ändern" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Auflösung & Bildwiederholrate" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Auflösung, Position, Skalierung" - }, - "Restart DMS": { - "Restart DMS": "Neustart DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "DankMaterialShell neustarten" - }, - "Restarting audio system...": { - "Restarting audio system...": "Audiosystem wird neu gestartet..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "Fenster in speziellen Arbeitsbereichen wiederherstellen" - }, - "Resume": { - "Resume": "Fortsetzen" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Scrollrichtung umkehren" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Arbeitsbereich-Wechselrichtung beim Scrollen über die Leiste umkehren" - }, - "Revert": { - "Revert": "Rückgängig machen" - }, - "Right": { - "Right": "Rechts" - }, - "Right Center": { - "Right Center": "Rechts zentriert" - }, - "Right Section": { - "Right Section": "Rechte Sektion" - }, - "Right Tiling": { - "Right Tiling": "Kachelung rechts" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Rechtsklick und ziehen an einer beliebigen Stelle auf dem Widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Rechtsklick und ziehen der unteren rechten Ecke" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Rechtsklick auf das Leisten-Widget zum Durchwechseln" - }, - "Ring": { - "Ring": "Klingeln lassen" - }, - "Ringing": { - "Ringing": "Klingeln" - }, - "Ripple Effects": { - "Ripple Effects": "Wellen-Effekte" - }, - "Root Filesystem": { - "Root Filesystem": "Root-Dateisystem" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Abgerundete Ecken für Fenster" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Abgerundete Ecken für Fenster (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Abgerundete Ecken für Fenster (decoration.rounding)" - }, - "Rule": { - "Rule": "Regel" - }, - "Rule Name": { - "Rule Name": "Regelname" - }, - "Rules (%1)": { - "Rules (%1)": "Regeln (%1)" - }, - "Run Again": { - "Run Again": "Erneut ausführen" - }, - "Run DMS Templates": { - "Run DMS Templates": "DMS Vorlagen ausführen" - }, - "Run User Templates": { - "Run User Templates": "Benutzer-Vorlagen ausführen" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Starte Programm (z.B. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Starte Shell Kommando (z.B. notify-send)" - }, - "Running Apps": { - "Running Apps": "Laufende Apps" - }, - "Running Apps Settings": { - "Running Apps Settings": "Einstellungen für laufende Applikationen" - }, - "Running greeter sync…": { - "Running greeter sync…": "Greeter-Sync wird ausgeführt…" - }, - "SDR Brightness": { - "SDR Brightness": "SDR Helligkeit" - }, - "SDR Saturation": { - "SDR Saturation": "SDR Sättigung" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Speichern" - }, - "Save Notepad File": { - "Save Notepad File": "Speicher Notepad Datei" - }, - "Save QR Code": { - "Save QR Code": "QR Code speichern" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Anzeige-Konfigurationen speichern und zwischen ihnen wechseln" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Benachrichtigungen mit kritischer Priorität im Verlauf speichern" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Verworfene Benachrichtigungen im Verlauf speichern" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Benachrichtigungen mit niedriger Priorität im Verlauf speichern" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Benachrichtigungen mit normaler Priorität im Verlauf speichern" - }, - "Save password": { - "Save password": "Passwort speichern" - }, - "Saved": { - "Saved": "Gespeichert" - }, - "Saved Configurations": { - "Saved Configurations": "Konfigurationen gespeichert" - }, - "Saved Note": { - "Saved Note": "Gespeicherte Notiz" - }, - "Saved item deleted": { - "Saved item deleted": "Gespeichertes Element gelöscht" - }, - "Saving...": { - "Saving...": "Speichert..." - }, - "Scale": { - "Scale": "Skalierung" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Skaliere DankBar Schriftgröße seperat" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "DankBar-Icon-Größen unabhängig skalieren" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Alle Schriftgrößen in der Shell skalieren" - }, - "Scan": { - "Scan": "Scannen" - }, - "Scanning": { - "Scanning": "Scannen" - }, - "Scanning...": { - "Scanning...": "Scannen..." - }, - "Science": { - "Science": "Wissenschaft" - }, - "Score": { - "Score": "Score" - }, - "Screen Sharing": { - "Screen Sharing": "Bildschirmfreigabe" - }, - "Screen sharing": { - "Screen sharing": "Bildschirm teilen" - }, - "Scroll": { - "Scroll": "Scrollen" - }, - "Scroll Factor": { - "Scroll Factor": "Scroll-Faktor" - }, - "Scroll GitHub": { - "Scroll GitHub": "GitHub scrollen" - }, - "Scroll Wheel": { - "Scroll Wheel": "Mausrad" - }, - "Scroll song title": { - "Scroll song title": "scrolle Songtitel" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Titel scrollen, wenn er nicht in das Widget passt" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Mausrad-Verhalten auf dem Medien-Widget" - }, - "Scrolling": { - "Scrolling": "Scrollen" - }, - "Search App Actions": { - "Search App Actions": "App-Aktionen suchen" - }, - "Search Options": { - "Search Options": "Suchoptionen" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Suchen Sie nach Tastenkombination, Beschreibung oder Aktionsname.\n\nDie Standardaktion kopiert die Tastenkombination in die Zwischenablage.\nRechtsklick oder Rechts-Pfeil drücken, um häufig verwendete Tastenkombinationen anzuheften – diese erscheinen oben, wenn nicht gesucht wird." - }, - "Search for a location...": { - "Search for a location...": "Suche nach Ort..." - }, - "Search keybinds...": { - "Search keybinds...": "Suche Tastenbelegung..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Tastenkombinationen von Ihrem Compositor und Anwendungen suchen" - }, - "Search plugins...": { - "Search plugins...": "Suche Plugins..." - }, - "Search processes...": { - "Search processes...": "Prozesse suchen..." - }, - "Search sessions...": { - "Search sessions...": "Sitzungen suchen..." - }, - "Search themes...": { - "Search themes...": "Themes suchen..." - }, - "Search widgets...": { - "Search widgets...": "Suche Widgets..." - }, - "Search...": { - "Search...": "Suche..." - }, - "Searching...": { - "Searching...": "Suchen..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Zweiter Faktor (UND)" - }, - "Secondary": { - "Secondary": "Sekundär" - }, - "Secured": { - "Secured": "Gesichert" - }, - "Security": { - "Security": "Sicherheit" - }, - "Security & privacy": { - "Security & privacy": "Sicherheit & Privatsphäre" - }, - "Security key mode": { - "Security key mode": "Sicherheitsschlüssel-Modus" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "Sicherheitsschlüssel-Verfügbarkeit konnte nicht bestätigt werden." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Sicherheitsschlüssel-Unterstützung wurde erkannt, aber es wurde noch kein registrierter Schlüssel gefunden. Du kannst dies jetzt aktivieren und später einen registrieren." - }, - "Select": { - "Select": "Auswählen" - }, - "Select Application": { - "Select Application": "Wähle Applikation" - }, - "Select Bar": { - "Select Bar": "Leiste auswählen" - }, - "Select Custom Theme": { - "Select Custom Theme": "Benutzerdefiniertes Design auswählen" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Dock-Launcher-Logo auswählen" - }, - "Select File to Send": { - "Select File to Send": "Datei zum Senden auswählen" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Launcher Logo" - }, - "Select Profile Image": { - "Select Profile Image": "Profilbild auswählen" - }, - "Select Video or Folder": { - "Select Video or Folder": "Video oder Ordner auswählen" - }, - "Select Wallpaper": { - "Select Wallpaper": "Hintergrundbild" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Hintergrundbild-Verzeichnis auswählen" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "eine Farbe aus der Farbpalette oder nutze die Schieberegler" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Wählen Sie ein Widget aus, das Sie Ihrem Desktop hinzufügen möchten. Jedes Widget ist eine separate Instanz mit eigenen Einstellungen." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Widget zum hinzufügen. Widgets können mehrfach platziert werden, wenn nötig." - }, - "Select a window...": { - "Select a window...": "ein Fenster..." - }, - "Select an image file...": { - "Select an image file...": "eine Bilddatei..." - }, - "Select at least one provider": { - "Select at least one provider": "Wählen Sie mindestens einen Anbieter aus" - }, - "Select device": { - "Select device": "Gerät auswählen" - }, - "Select device...": { - "Select device...": "Drucker..." - }, - "Select driver...": { - "Select driver...": "Treiber..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Schriftstärke für UI" - }, - "Select greeter background image": { - "Select greeter background image": "Hintergrundbild für den Greeter auswählen" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "einen Monitor für das Hintergrundbild" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Monospace Schriftart für Prozessliste und technische Details" - }, - "Select network": { - "Select network": "Netzwerk auswählen" - }, - "Select system sound theme": { - "Select system sound theme": "Systemklangtöne" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Schriftfamilie für UI" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Algorithmus für Hintergrundbilder zur Bestimmung der Farben" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Wählen Sie aus, welche Tastenkombinationsanbieter einbezogen werden sollen" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Wählen Sie aus, welche Übergänge in die Zufallsauswahl aufgenommen werden sollen" - }, - "Select...": { - "Select...": "..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Ausgewähltes Bild konnte nicht gefunden werden." - }, - "Send": { - "Send": "Senden" - }, - "Send Clipboard": { - "Send Clipboard": "Zwischenablage senden" - }, - "Send File": { - "Send File": "Datei senden" - }, - "Send SMS": { - "Send SMS": "SMS senden" - }, - "Sending": { - "Sending": "Senden" - }, - "Separator": { - "Separator": "Trenner" - }, - "Server": { - "Server": "Server" - }, - "Session Filter": { - "Session Filter": "Sitzungsfilter" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Benutzerdefinierten Gerätenamen festlegen" - }, - "Set custom name": { - "Set custom name": "Benutzerdefinierten Namen festlegen" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Benutzerdefinierte Namen für Ihre Audioeingabegeräte festlegen" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Benutzerdefinierte Namen für Ihre Audioausgabegeräte festlegen" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Setze Hintergrundbilder für jeweiligen Monitor" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Setze Hintergrundbilder für helle und dunkle Darstellung" - }, - "Set key and action to save": { - "Set key and action to save": "Taste und Aktion zum Speichern festlegen" - }, - "Set notification rules": { - "Set notification rules": "Benachrichtigungsregeln festlegen" - }, - "Settings": { - "Settings": "Einstellungen" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Einstellungen sind schreibgeschützt. Änderungen werden nicht gespeichert." - }, - "Setup": { - "Setup": "Einrichtung" - }, - "Shadow Color": { - "Shadow Color": "Schattenfarbe" - }, - "Shadow Intensity": { - "Shadow Intensity": "Schattenintensität" - }, - "Shadow Opacity": { - "Shadow Opacity": "Schattendeckkraft" - }, - "Shadow Override": { - "Shadow Override": "Schattenüberschreibung" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Schatten-Erhöhung auf Leisten und Panels" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Schatten-Erhöhung auf Modalen und Dialogen" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "Schatten-Erhöhung auf Popouts, OSDs und Dropdowns" - }, - "Shadows": { - "Shadows": "Schatten" - }, - "Share": { - "Share": "Teilen" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Gamma-Control-Einstellungen teilen" - }, - "Share Text": { - "Share Text": "Text teilen" - }, - "Share URL": { - "Share URL": "URL teilen" - }, - "Shared": { - "Shared": "Geteilt" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Alle entfernen • Esc: Schließen" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Umschalt+Eingabe zum Einfügen" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Umschalt+Eingabe: Kopieren • Umschalt+Entf: Alles löschen • Esc: Schließen" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Einfügen • Shift+Entf: Alle entfernen • Esc: Schließen" - }, - "Short": { - "Short": "Kurz" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Tastenkürzel (%1)" - }, - "Shortcuts": { - "Shortcuts": "Tastenkürzel" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Tastenkombinationen (%1)" - }, - "Show": { - "Show": "Anzeigen" - }, - "Show 3rd Party": { - "Show 3rd Party": "Drittanbieter anzeigen" - }, - "Show All Tags": { - "Show All Tags": "Alle Tags anzeigen" - }, - "Show Badge": { - "Show Badge": "Badge anzeigen" - }, - "Show CPU": { - "Show CPU": "CPU anzeigen" - }, - "Show CPU Graph": { - "Show CPU Graph": "CPU-Diagramm anzeigen" - }, - "Show CPU Temp": { - "Show CPU Temp": "CPU-Temperatur anzeigen" - }, - "Show Date": { - "Show Date": "Zeige Datum" - }, - "Show Disk": { - "Show Disk": "Zeige Festaplatte" - }, - "Show Dock": { - "Show Dock": "Dock anzeigen" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Gefühlte Temperatur anzeigen" - }, - "Show Footer": { - "Show Footer": "Fußzeile anzeigen" - }, - "Show Forecast": { - "Show Forecast": "Vorhersage anzeigen" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Zeige GPU Temperatur" - }, - "Show Header": { - "Show Header": "Zeige Kopfzeile" - }, - "Show Hibernate": { - "Show Hibernate": "Ruhezustand anzeigen" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Zeige Stundenangabe" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Stündliche Vorhersage anzeigen" - }, - "Show Humidity": { - "Show Humidity": "Luftfeuchtigkeit anzeigen" - }, - "Show Launcher Button": { - "Show Launcher Button": "Launcher-Schaltfläche anzeigen" - }, - "Show Line Numbers": { - "Show Line Numbers": "Zeige Zeilennummern" - }, - "Show Location": { - "Show Location": "Standort anzeigen" - }, - "Show Lock": { - "Show Lock": "Sperren anzeigen" - }, - "Show Log Out": { - "Show Log Out": "Abmelden anzeigen" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Material Design Wellen-Animationen auf interaktiven Elementen anzeigen" - }, - "Show Media Player": { - "Show Media Player": "Zeige Media Player" - }, - "Show Memory": { - "Show Memory": "Zeige Speicher" - }, - "Show Memory Graph": { - "Show Memory Graph": "Zeige Speicher Graph" - }, - "Show Memory in GB": { - "Show Memory in GB": "Arbeitsspeicher in GB anzeigen" - }, - "Show Network": { - "Show Network": "Zeige Netzwerk" - }, - "Show Network Graph": { - "Show Network Graph": "Zeige Netzwerk Graph" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Zeige nur genutzte Arbeitsbereiche an" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Überlauf-Badge-Anzahl anzeigen" - }, - "Show Password Field": { - "Show Password Field": "Zeige Passwort Feld" - }, - "Show Power Actions": { - "Show Power Actions": "Zeige Energieoptionen" - }, - "Show Power Off": { - "Show Power Off": "Ausschalten anzeigen" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Niederschlagswahrscheinlichkeit anzeigen" - }, - "Show Pressure": { - "Show Pressure": "Luftdruck anzeigen" - }, - "Show Profile Image": { - "Show Profile Image": "Zeige Profilbild" - }, - "Show Reboot": { - "Show Reboot": "Neustart anzeigen" - }, - "Show Restart DMS": { - "Show Restart DMS": "DMS-Neustart anzeigen" - }, - "Show Saved Items": { - "Show Saved Items": "Gespeicherte Elemente anzeigen" - }, - "Show Seconds": { - "Show Seconds": "Zeige Sekunden" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Sonnenaufgang/-untergang anzeigen" - }, - "Show Suspend": { - "Show Suspend": "Zeige Ruhemodus" - }, - "Show Swap": { - "Show Swap": "Swap anzeigen" - }, - "Show System Date": { - "Show System Date": "Zeige Systemdatum" - }, - "Show System Icons": { - "Show System Icons": "Zeige Systemicons" - }, - "Show System Time": { - "Show System Time": "Zeige Systemzeit" - }, - "Show Top Processes": { - "Show Top Processes": "Zeige Top Prozesse" - }, - "Show Weather Condition": { - "Show Weather Condition": "Wetterlage anzeigen" - }, - "Show Week Number": { - "Show Week Number": "Wochennummer anzeigen" - }, - "Show Welcome": { - "Show Welcome": "Willkommensseite anzeigen" - }, - "Show Wind Speed": { - "Show Wind Speed": "Windgeschwindigkeit anzeigen" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Zeige Applikationen von Arbeitsbereich" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Alle 9 Tags anzeigen, statt nur die belegten (nur mit DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Einen Umrissring um die Anzeige des fokussierten Arbeitsbereichs anzeigen" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Cava-Audio-Visualisierer im Medien-Widget anzeigen" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Abgedunkeltes Overlay hinter modalen Dialogen anzeigen" - }, - "Show device": { - "Show device": "Gerät anzeigen" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Dock anzeigen, wenn schwebende Fenster seinen Bereich nicht überlappen" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "Schlagschatten auf Benachrichtigungs-Popups anzeigen. Erfordert die Aktivierung von M3 Elevation unter Theme & Farben." - }, - "Show in GB": { - "Show in GB": "In GB anzeigen" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Launcher-Overlay anzeigen, wenn in der Niri-Übersicht getippt wird. Deaktivieren, um einen anderen Launcher zu verwenden." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Modus-Tabs und Tastaturhinweise unten anzeigen." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "Benachrichtigungs-Popups nur auf dem aktuell fokussierten Monitor anzeigen" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "Benachrichtigungen nur auf dem aktuell fokussierten Monitor anzeigen" - }, - "Show on Last Display": { - "Show on Last Display": "Zeigen auf letzten Montior" - }, - "Show on Overlay": { - "Show on Overlay": "Im Overlay anzeigen" - }, - "Show on Overview": { - "Show on Overview": "Zeige auf Übersicht" - }, - "Show on Overview Only": { - "Show on Overview Only": "Nur in der Übersicht anzeigen" - }, - "Show on all connected displays": { - "Show on all connected displays": "Zeige alle verbundenen Monitore" - }, - "Show on screens:": { - "Show on screens:": "Auf Bildschirmen anzeigen:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Bildschirmanzeige bei Helligkeitsänderung anzeigen" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Bildschirmanzeige bei Statusänderung der Feststelltaste anzeigen" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "On-Screen-Display beim Durchwechseln von Audioausgabegeräten anzeigen" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Bildschirmanzeige bei Statusänderung des Leerlauf-Inhibitors anzeigen" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Bildschirmanzeige einblenden, wenn sich der Status des Mediaplayers ändert" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Bildschirmanzeige bei Lautstärkeänderung des Mediaplayers anzeigen" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Bildschirmanzeige beim Stummschalten/Aktivieren des Mikrofons anzeigen" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Bildschirmanzeige bei Änderung des Energieprofils anzeigen" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Bildschirmanzeige bei Lautstärkeänderung anzeigen" - }, - "Show seconds": { - "Show seconds": "Sekunden anzeigen" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Wetter Informationen in Top-Bar und in Einstellungen anzeigen" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Wochennummer im Kalender anzeigen" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Arbeitsbereich-Indexnummern im Wechsler der oberen Leiste anzeigen" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Arbeitsbereichsnamen auf horizontalen Leisten und den ersten Buchstaben auf vertikalen Leisten anzeigen" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Arbeitsbereiche des aktuell fokussierten Monitors anzeigen" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Zeigt alle laufenden Anwendungen mit Fokus-Anzeige" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Zeigt Arbeitsbereich und ermöglicht das Umschalten" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Zeige wenn Festelltaste aktiv" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Zeigt wenn Mikrofon, Kamera oder Bildschirmteilung aktiv ist" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Ausschalten" - }, - "Signal": { - "Signal": "Signal" - }, - "Signal:": { - "Signal:": "Signal:" - }, - "Size": { - "Size": "Größe" - }, - "Size Constraints": { - "Size Constraints": "Größenbeschränkungen" - }, - "Size Offset": { - "Size Offset": "Abstand" - }, - "Sizing": { - "Sizing": "Größenanpassung" - }, - "Skip": { - "Skip": "Überspringen" - }, - "Skip confirmation": { - "Skip confirmation": "Bestätigung überspringen" - }, - "Skip setup": { - "Skip setup": "Einrichtung überspringen" - }, - "Small": { - "Small": "Klein" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Smartcard-Authentifizierung" - }, - "Smartcard PIN": { - "Smartcard PIN": "Smartcard-PIN" - }, - "Snap": { - "Snap": "Einrasten" - }, - "Snow": { - "Snow": "Schnee" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Einige Plugins benötigen eine neuere DMS Version:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Alphabetisch sortieren" - }, - "Sort By": { - "Sort By": "Sortieren nach" - }, - "Sorting & Layout": { - "Sorting & Layout": "Sortierung & Layout" - }, - "Sound Theme": { - "Sound Theme": "Klangtöne" - }, - "Sounds": { - "Sounds": "Töne" - }, - "Space between windows": { - "Space between windows": "Abstand zwischen Fenster" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Abstand zwischen Fenstern (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Abstand zwischen Fenstern (gaps_in und gaps_out)" - }, - "Spacer": { - "Spacer": "Abstandshalter" - }, - "Spacing": { - "Spacing": "Zwischenraum" - }, - "Speaker settings": { - "Speaker settings": "Lautsprechereinstellungen" - }, - "Speed": { - "Speed": "Geschwindigkeit" - }, - "Spool Area Full": { - "Spool Area Full": "Spool-Bereich voll" - }, - "Square Corners": { - "Square Corners": "keine Abrundung" - }, - "Stacked": { - "Stacked": "Gestapelt" - }, - "Standard": { - "Standard": "Standard" - }, - "Start": { - "Start": "Start" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "KDE Connect oder Valent starten" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Starten Sie KDE Connect oder Valent, um dieses Plugin zu verwenden" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Schreibe deine Notiz hier..." - }, - "State": { - "State": "Zustand" - }, - "Status": { - "Status": "Status" - }, - "Stopped": { - "Stopped": "Gestoppt" - }, - "Stopped Partly": { - "Stopped Partly": "zum Teil gestoppt" - }, - "Stopping": { - "Stopping": "am Stoppen" - }, - "Stretch": { - "Stretch": "Strecken" - }, - "Stripes": { - "Stripes": "Streifen" - }, - "Summary": { - "Summary": "Zusammenfassung" - }, - "Sunrise": { - "Sunrise": "Sonnenaufgang" - }, - "Sunset": { - "Sunset": "Sonnenuntergang" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Unterdrückt Benachrichtigungen wenn aktiviert" - }, - "Surface": { - "Surface": "Oberfläche" - }, - "Surface Variant": { - "Surface Variant": "Oberflächenvariante" - }, - "Suspend": { - "Suspend": "Ruhemodus" - }, - "Suspend behavior": { - "Suspend behavior": "Ruhemodus Verhalten" - }, - "Suspend system after": { - "Suspend system after": "In Ruhemodus wechseln nach" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Ruhezustand nach Standby" - }, - "Sway Website": { - "Sway Website": "Sway-Website" - }, - "Switch User": { - "Switch User": "Benutzer wechseln" - }, - "Switch to power profile": { - "Switch to power profile": "Zu Energieprofil wechseln" - }, - "Sync": { - "Sync": "Sync" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Synchronisiere Modus mit Portal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Popouts & Modale synchronisieren" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Position über Bildschirme hinweg synchronisieren" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Sync erfolgreich abgeschlossen." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Dunkelmodus mit Einstellungsportalen für systemweite Theme-Hinweise synchronisieren" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "Sync im Hintergrundmodus fehlgeschlagen. Terminal-Modus wird versucht, damit Sie sich interaktiv authentifizieren können." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "Sync erfordert Sudo-Authentifizierung. Terminal wird geöffnet, damit Sie Passwort oder Fingerabdruck verwenden können." - }, - "System": { - "System": "System" - }, - "System App Theming": { - "System App Theming": "System App Darstellung" - }, - "System Check": { - "System Check": "Systemprüfung" - }, - "System Default": { - "System Default": "Systemstandard" - }, - "System Information": { - "System Information": "Systeminformationen" - }, - "System Monitor": { - "System Monitor": "Systemmonitor" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "System Monitor nicht verfügbar" - }, - "System Sounds": { - "System Sounds": "System Töne" - }, - "System Tray": { - "System Tray": "Taskleiste" - }, - "System Update": { - "System Update": "Systemupdate" - }, - "System Updater": { - "System Updater": "System-Updater" - }, - "System Updates": { - "System Updates": "Systemupdates" - }, - "System notification area icons": { - "System notification area icons": "Symbole im Benachrichtigungsbereich des Systems" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Systemklänge sind nicht verfügbar. Installieren Sie %1 für Sound-Unterstützung." - }, - "System theme toggle": { - "System theme toggle": "System-Design umschalten" - }, - "System toast notifications": { - "System toast notifications": "System-Toast-Benachrichtigungen" - }, - "System update custom command": { - "System update custom command": "Benutzerdefinierter Befehl für System-Update" - }, - "Tab": { - "Tab": "Tab" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Navigation • ←→↑↓: Grid Nav • Enter/Leertaste: Auswählen" - }, - "Terminal": { - "Terminal": "Terminal" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Zusätzliche benutzerdefinierte Terminal-Parameter" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "Terminal-Fallback fehlgeschlagen. Installieren Sie einen unterstützten Terminal-Emulator oder führen Sie „dms auth sync“ manuell aus." - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "Terminal-Fallback fehlgeschlagen. Installieren Sie einen der unterstützten Terminal-Emulatoren oder führen Sie 'dms greeter sync' manuell aus." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "Terminal-Fallback geöffnet. Schließen Sie dort die Authentifizierungseinrichtung ab; es wird nach Abschluss automatisch geschlossen." - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "Terminal-Fallback geöffnet. Schließen Sie den Sync dort ab; das Fenster wird nach Abschluss automatisch geschlossen." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "Zu verwendendes Terminal-Multiplexer-Backend" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "Terminal geöffnet. Schließen Sie dort die Authentifizierungseinrichtung ab; es wird nach Abschluss automatisch geschlossen." - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "Terminal geöffnet. Schließen Sie die Sync-Authentifizierung dort ab; das Fenster wird nach Abschluss automatisch geschlossen." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminals - Immer dunkles Farbschema wählen" - }, - "Test Connection": { - "Test Connection": "Verbindung testen" - }, - "Test Page": { - "Test Page": "Testseite" - }, - "Test page sent to printer": { - "Test page sent to printer": "Testseite wurde zum Drucker gesendet" - }, - "Testing...": { - "Testing...": "Testen..." - }, - "Text": { - "Text": "Text" - }, - "Text Color": { - "Text Color": "Textfarbe" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "Das Tool 'dgop' ist für die Systemüberwachung erforderlich.\nBitte installieren Sie dgop, um diese Funktion zu nutzen." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "Die Umgebungsvariable DMS_SOCKET ist nicht gesetzt oder der Socket ist nicht verfügbar. Die automatische Plugin-Verwaltung erfordert DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Die folgenden Einstellungen werden Ihre GTK- und Qt-Einstellungen ändern. Wenn Sie Ihre aktuellen Konfigurationen beibehalten möchten, sichern Sie diese bitte (qt5ct.conf|qt6ct.conf und ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "Der benutzerdefinierte Befehl beim Verbinden mit Sitzungen (erhält den Sitzungsnamen als erstes Argument)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "Warteschlange der Druckaufträge ist leer" - }, - "Theme & Colors": { - "Theme & Colors": "Theme & Farben" - }, - "Theme Color": { - "Theme Color": "Theme-Farbe" - }, - "Theme Registry": { - "Theme Registry": "Design-Registrierung" - }, - "Themes": { - "Themes": "Designs" - }, - "Thickness": { - "Thickness": "Stärke" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Drittanbieter-Plugin Warnung" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Plugins von Drittanbietern werden von der Community erstellt und nicht offiziell von DankMaterialShell unterstützt.\n\nDiese Plugins können Sicherheits- und Datenschutzrisiken bergen – Installation auf eigene Gefahr." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Diese Bindung wird durch config.kdl überschrieben" - }, - "This may take a few seconds": { - "This may take a few seconds": "Dies kann einige Sekunden dauern" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Dieses Plugin hat keine 'settings_write'-Berechtigung.\n\nFügen Sie \"permissions\": [\"settings_read\", \"settings_write\"] zur plugin.json hinzu" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Dieses Widget verhindert das Abschalten der GPU, was die Akkulaufzeit bei Laptops erheblich beeinträchtigen kann. Es wird nicht empfohlen, dies auf Laptops mit Hybrid-Grafik zu verwenden." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Dies löscht alle nicht angehefteten Einträge. %1 angeheftete Einträge werden beibehalten." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Das löscht den gesamten Verlauf der Zwischenablage dauerhaft." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Dies wird dieses gespeicherte Zwischenablage-Element dauerhaft entfernen. Diese Aktion kann nicht rückgängig gemacht werden." - }, - "Thunderstorm": { - "Thunderstorm": "Gewitter" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Gewitter mit Hagel" - }, - "Tile": { - "Tile": "Kachel" - }, - "Tile H": { - "Tile H": "Kachel H" - }, - "Tile V": { - "Tile V": "Kachel V" - }, - "Tiled": { - "Tiled": "Gekachelt" - }, - "Tiled State": { - "Tiled State": "Kachelzustand" - }, - "Tiling": { - "Tiling": "Kachelung" - }, - "Time": { - "Time": "Zeit" - }, - "Time & Date Locale": { - "Time & Date Locale": "Sprachumgebung für Zeit & Datum" - }, - "Time & Weather": { - "Time & Weather": "Zeit & Wetter" - }, - "Time Format": { - "Time Format": "Zeitformat" - }, - "Time format": { - "Time format": "Zeitformat" - }, - "Time remaining: %1": { - "Time remaining: %1": "Verbleibende Zeit: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Zeit bis voll: %1" - }, - "Timed Out": { - "Timed Out": "Zeit abgelaufen" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Zeitüberschreitung für Benachrichtigungen mit kritischer Priorität" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Zeitüberschreitung für Benachrichtigungen mit niedriger Priorität" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Zeitüberschreitung für Benachrichtigungen mit normaler Priorität" - }, - "Title": { - "Title": "Titel" - }, - "Title regex (optional)": { - "Title regex (optional)": "Titel-Regex (optional)" - }, - "To Full": { - "To Full": "Bis voll" - }, - "To update, run the following command:": { - "To update, run the following command:": "Zum Aktualisieren führen Sie folgenden Befehl aus:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Um diese DMS-Bindung zu verwenden, entfernen oder ändern Sie das Tastenkürzel in Ihrer config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Toast-Nachrichten" - }, - "Today": { - "Today": "Heute" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Sichtbarkeit dieser Leistenkonfiguration umschalten" - }, - "Toggling...": { - "Toggling...": "Umschalten..." - }, - "Tomorrow": { - "Tomorrow": "Morgen" - }, - "Tonal Spot": { - "Tonal Spot": "Tonaler Punkt" - }, - "Toner Empty": { - "Toner Empty": "Toner leer" - }, - "Toner Low": { - "Toner Low": "Toner fast leer" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "Zu viele Versuche – gesperrt" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "Zu viele fehlgeschlagene Versuche - Konto könnte gesperrt sein" - }, - "Tools": { - "Tools": "Werkzeuge" - }, - "Top": { - "Top": "Oben" - }, - "Top (Default)": { - "Top (Default)": "Oben (Standard)" - }, - "Top Bar Format": { - "Top Bar Format": "Format der oberen Leiste" - }, - "Top Center": { - "Top Center": "Oben zentriert" - }, - "Top Left": { - "Top Left": "Oben links" - }, - "Top Processes": { - "Top Processes": "Top Prozesse" - }, - "Top Right": { - "Top Right": "Oben rechts" - }, - "Top Section": { - "Top Section": "Oberste Sektion" - }, - "Total": { - "Total": "Gesamt" - }, - "Total Jobs": { - "Total Jobs": "Alle Druckaufträge" - }, - "Touch your security key...": { - "Touch your security key...": "Berühren Sie Ihren Sicherheitsschlüssel..." - }, - "Transform": { - "Transform": "Transformiere" - }, - "Transition Effect": { - "Transition Effect": "Übergangseffekt" - }, - "Transparency": { - "Transparency": "Transparenz" - }, - "Trending GIFs": { - "Trending GIFs": "Beliebte GIF's" - }, - "Trending Stickers": { - "Trending Stickers": "Beliebte Sticker" - }, - "Trigger": { - "Trigger": "Auslöser" - }, - "Trigger Prefix": { - "Trigger Prefix": "Auslöser-Präfix" - }, - "Trigger: %1": { - "Trigger: %1": "Trigger: %1" - }, - "Trust": { - "Trust": "Vertrauen" - }, - "Try a different search": { - "Try a different search": "Versuchen Sie eine andere Suche" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Alle Bildschirme sofort ausschalten, wenn der Sperrbildschirm aktiviert wird" - }, - "Turn off monitors after": { - "Turn off monitors after": "Schalte Monitore aus nach" - }, - "Type": { - "Type": "Typ" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Geben Sie mindestens 2 Zeichen ein" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Geben Sie dieses Präfix ein, um nach Tastenkombinationen zu suchen" - }, - "Type to search files": { - "Type to search files": "Tippen, um nach Dateien zu suchen" - }, - "Typography": { - "Typography": "Typografie" - }, - "Typography & Motion": { - "Typography & Motion": "Typografie & Bewegung" - }, - "Unavailable": { - "Unavailable": "nicht Verfügbar" - }, - "Unfocused Color": { - "Unfocused Color": "Nicht fokussierte Farbe" - }, - "Ungrouped": { - "Ungrouped": "Nicht gruppiert" - }, - "Uninstall": { - "Uninstall": "Deinstallieren" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Greeter deinstallieren" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Plugin deinstallieren" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Deinstallation abgeschlossen. Greeter wurde entfernt." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Deinstallation fehlgeschlagen: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "DMS-Greeter deinstallieren? Dies entfernt die Konfiguration und stellt Ihren vorherigen Display-Manager wieder her. Ein Terminal zur Sudo-Authentifizierung wird geöffnet." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Deinstalliert: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Deinstallieren: %1" - }, - "Unknown": { - "Unknown": "Unbekannt" - }, - "Unknown App": { - "Unknown App": "Unbekannte App" - }, - "Unknown Artist": { - "Unknown Artist": "Unbekannter Künstler" - }, - "Unknown Config": { - "Unknown Config": "Unbekannte Konfiguration" - }, - "Unknown Device": { - "Unknown Device": "Unbekanntes Gerät" - }, - "Unknown GPU": { - "Unknown GPU": "Unbekannte GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "Unbekannter Monitor" - }, - "Unknown Network": { - "Unknown Network": "Unbekanntes Netzwerk" - }, - "Unknown Title": { - "Unknown Title": "Unbekannter Titel" - }, - "Unknown Track": { - "Unknown Track": "Unbekannter Titel" - }, - "Unload on Close": { - "Unload on Close": "Beim Schließen entladen" - }, - "Unmute": { - "Unmute": "Stummschaltung aufheben" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Stummschaltung der Popups für %1 aufheben" - }, - "Unnamed Rule": { - "Unnamed Rule": "Unbenannte Regel" - }, - "Unpair": { - "Unpair": "Entkoppeln" - }, - "Unpair failed": { - "Unpair failed": "Entkoppeln fehlgeschlagen" - }, - "Unpin": { - "Unpin": "Anheften aufheben" - }, - "Unpin from Dock": { - "Unpin from Dock": "Vom Dock entfernen" - }, - "Unsaved Changes": { - "Unsaved Changes": "Ungespeicherte Änderungen" - }, - "Unsaved changes": { - "Unsaved changes": "Ungespeicherte Änderungen" - }, - "Unsaved note...": { - "Unsaved note...": "Ungespeicherte Notiz..." - }, - "Untitled": { - "Untitled": "ohne Titel" - }, - "Untrust": { - "Untrust": "Misstrauen" - }, - "Up to date": { - "Up to date": "Auf dem neuesten Stand" - }, - "Update": { - "Update": "Aktualisieren" - }, - "Update All": { - "Update All": "Alle updaten" - }, - "Update Plugin": { - "Update Plugin": "Plugin updaten" - }, - "Uptime": { - "Uptime": "Betriebszeit" - }, - "Uptime:": { - "Uptime:": "Betriebszeit:" - }, - "Urgent Color": { - "Urgent Color": "Dringende Farbe" - }, - "Usage Tips": { - "Usage Tips": "Tipps zur Verwendung" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "24‑Stunden‑Format statt 12‑Stunden‑AM/PM verwenden" - }, - "Use Custom Command": { - "Use Custom Command": "Benutzerdefinierten Befehl verwenden" - }, - "Use Grid Layout": { - "Use Grid Layout": "Nutze Raster Layout" - }, - "Use IP Location": { - "Use IP Location": "Positionserkennung durch IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Britische Maßeinheiten verwenden" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Britische Maßeinheiten verwenden (°F, mph, inHg) anstatt von metrischen Einheiten (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Monospace-Schriftart verwenden" - }, - "Use System Theme": { - "Use System Theme": "Nutze System Darstellung" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Ein benutzerdefiniertes Bild für den Anmeldebildschirm verwenden oder leer lassen, um das Desktop-Hintergrundbild zu verwenden." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Eine feste Schattenrichtung für diese Leiste verwenden" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Sicherheitsschlüssel für die Sperrbildschirm-Authentifizierung verwenden." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Nutze externe Hintergrundbild Verwaltung, z.B. swww, hyprpaper, or swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Animierte Wellen-Fortschrittsbalken für Medienwiedergabe verwenden" - }, - "Use custom border size": { - "Use custom border size": "Benutzerdefinierte Rahmengröße verwenden" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Benutzerdefinierte Rahmen-/Fokusringbreite verwenden" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Benutzerdefinierten Befehl zum Aktualisieren Ihres Systems verwenden" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Benutzerdefinierte Abstände anstelle von Leistenabständen verwenden" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Benutzerdefinierten Fensterradius anstelle des Theme-Radius verwenden" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Benutzerdefinierte Fensterabrundung statt Design-Radius verwenden" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Desktop-Hintergrundbild verwenden" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Fingerabdruck-Authentifizierung für den Sperrbildschirm verwenden." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Nutze helle Darstellung anstatt von dunkler" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Meter pro Sekunde anstelle von km/h für Windgeschwindigkeit verwenden" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Kleinere Benachrichtigungskarten verwenden" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Nutze Systemklang Thema von den System Einstellungen" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Dieselbe Position und Größe auf allen Displays verwenden" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Auslöser-Präfix zum Aktivieren verwenden" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Wird verwendet, wenn die Akzentfarbe auf Benutzerdefiniert eingestellt ist" - }, - "User": { - "User": "Benutzer" - }, - "Username": { - "Username": "Benutzername" - }, - "Username...": { - "Username...": "Benutzername..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Verwendet Sonnenaufgangs-/-untergangszeiten basierend auf Ihrem Standort." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Verwendet Sonnenaufgang/-untergang, um den Nachtmodus automatisch an Ihren Standort anzupassen." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Verwendet geteilte Einstellungen von Gamma Control" - }, - "Utilities": { - "Utilities": "Dienstprogramme" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN Verbindungen" - }, - "VPN Password": { - "VPN Password": "VPN Passwort" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN Konfiguration geupdated" - }, - "VPN connections": { - "VPN connections": "VPN-Verbindungen" - }, - "VPN deleted": { - "VPN deleted": "VPN gelöscht" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importiert: %1" - }, - "VPN not available": { - "VPN not available": "VPN nicht verfügbar" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN‑Status & Schnellverbindung" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "Nur VRR-Vollbild" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR bei Bedarf" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Variable Bildwiederholrate" - }, - "Verification": { - "Verification": "Verifizierung" - }, - "Version": { - "Version": "Version" - }, - "Vertical Deck": { - "Vertical Deck": "Vertikales Deck" - }, - "Vertical Grid": { - "Vertical Grid": "Vertikales Raster" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Vertikales Scrollen" - }, - "Vertical Tiling": { - "Vertical Tiling": "Vertikale Kachelung" - }, - "Vibrant": { - "Vibrant": "Lebhaft" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Lebendige Farbpaletete mit spielerischer Sättigung." - }, - "Video Path": { - "Video Path": "Videopfad" - }, - "Video Screensaver": { - "Video Screensaver": "Video-Bildschirmschoner" - }, - "Videos": { - "Videos": "Videos" - }, - "View Mode": { - "View Mode": "Ansichtsmodus" - }, - "Visibility": { - "Visibility": "Sichtbarkeit" - }, - "Visual Effects": { - "Visual Effects": "Visuelle Effekte" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Visueller Trenner zwischen Widgets" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Visueller Effekt beim wechseln des Hintergrundbildes" - }, - "Volume": { - "Volume": "Lautstärke" - }, - "Volume Changed": { - "Volume Changed": "Lautstärke geändert" - }, - "Volume Slider": { - "Volume Slider": "Lautstärkeregler" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Lautstärke, Helligkeit und andere System-OSDs" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Hintergrundbild" - }, - "Wallpaper Error": { - "Wallpaper Error": "Hintergrundbild-Fehler" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Hintergrundbild Monitor" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Hintergrund-Füllmodus" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Verarbeitung des Hintergrundbilds fehlgeschlagen" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Verarbeitung des Hintergrundbilds fehlgeschlagen - Pfad prüfen" - }, - "Wallpapers": { - "Wallpapers": "Hintergrundbilder" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Anzuwendende warme Farbtemperatur" - }, - "Warning": { - "Warning": "Warnung" - }, - "Warnings": { - "Warnings": "Warnungen" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Wellen-Fortschrittsbalken" - }, - "Weather": { - "Weather": "Wetter" - }, - "Weather Widget": { - "Weather Widget": "Wetter Widget" - }, - "Welcome": { - "Welcome": "Willkommen" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Willkommen bei DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "Beim Klicken auf ein Dock-Fenster in einem speziellen Hyprland-Arbeitsbereich diesen wiederherstellen, bevor das Fenster fokussiert wird" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Aktivieren für alphabetische Anwendung-Sortierung. Deaktivieren für Anwendung-Sortierung nach Nutzung." - }, - "When locked": { - "When locked": "Wenn gesperrt" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Wenn das Updater-Widget verwendet wird, blende es aus, wenn kein Update gefunden wurde" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi Passwort" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "WLAN und Ethernet Verbindung" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "WLAN nicht verfügbar" - }, - "WiFi": { - "WiFi": "Wi-Fi" - }, - "WiFi Device": { - "WiFi Device": "Wi-Fi Gerät" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Wi-Fi QR Code für " - }, - "WiFi disabled": { - "WiFi disabled": "WLAN ist deaktiviert" - }, - "WiFi enabled": { - "WiFi enabled": "WLAN aktiviert" - }, - "WiFi is off": { - "WiFi is off": "WLAN ist aus" - }, - "WiFi off": { - "WiFi off": "WLAN aus" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Breit (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Widget-Hintergrundfarbe" - }, - "Widget Management": { - "Widget Management": "Widget Verwaltung" - }, - "Widget Outline": { - "Widget Outline": "Widget-Umriss" - }, - "Widget Style": { - "Widget Style": "Widget-Stil" - }, - "Widget Styling": { - "Widget Styling": "Widgetstil" - }, - "Widget Transparency": { - "Widget Transparency": "Widget Transparenz" - }, - "Widget added": { - "Widget added": "Widget hinzugefügt" - }, - "Widget removed": { - "Widget removed": "Widget entfernt" - }, - "Widgets": { - "Widgets": "Widgets" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgets, Layout, Stil" - }, - "Width": { - "Width": "Breite" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Breite des Fensterrahmens (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Breite des Fensterrahmens (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Breite von Fensterrahmen und Fokusring" - }, - "Wind": { - "Wind": "Wind" - }, - "Wind Speed": { - "Wind Speed": "Windgeschwindigkeit" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Windgeschwindigkeit in m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Fensterabrundung" - }, - "Window Gaps": { - "Window Gaps": "Fensterabstände" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Fensterabstände (px)" - }, - "Window Height": { - "Window Height": "Fensterhöhe" - }, - "Window Opening": { - "Window Opening": "Fensteröffnung" - }, - "Window Rounding": { - "Window Rounding": "Fensterabrundung" - }, - "Window Rules": { - "Window Rules": "Fensterregeln" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Fensterregeln schließen fehlende ein" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Fensterregeln nicht konfiguriert" - }, - "Wipe": { - "Wipe": "Wischen" - }, - "Workspace": { - "Workspace": "Arbeitsbereich" - }, - "Workspace Appearance": { - "Workspace Appearance": "Arbeitsbereich-Erscheinungsbild" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Arbeitsbereich Nummerierung" - }, - "Workspace Names": { - "Workspace Names": "Arbeitsflächennamen" - }, - "Workspace Padding": { - "Workspace Padding": "Abstand des Arbeitsbereiches" - }, - "Workspace Settings": { - "Workspace Settings": "Einstellungen zum Arbeitsbereich" - }, - "Workspace Switcher": { - "Workspace Switcher": "Arbeitsbereich-Wechsler" - }, - "Workspace name": { - "Workspace name": "Arbeitsflächenname" - }, - "Workspaces": { - "Workspaces": "Arbeitsbereiche" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Arbeitsbereiche & Widgets" - }, - "Write:": { - "Write:": "Schreiben:" - }, - "X Axis": { - "X Axis": "X-Achse" - }, - "Y Axis": { - "Y Axis": "Y-Achse" - }, - "Yes": { - "Yes": "Ja" - }, - "Yesterday": { - "Yesterday": "Gestern" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Ungespeicherte Änderungen vorhanden. Speichern vor schliessen?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Ungespeicherte Änderungen vorhanden. Jetzt speichern?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Sie haben ungespeicherte Änderungen. Vor dem Erstellen einer neuen Datei speichern?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Sie haben ungespeicherte Änderungen. Vor dem Öffnen einer Datei speichern?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Sie müssen entweder:\nQT_QPA_PLATFORMTHEME=gtk3 ODER\nQT_QPA_PLATFORMTHEME=qt6ct\nals Umgebungsvariablen setzen und dann die Shell neu starten.\n\nqt6ct erfordert die Installation von qt6ct-kde." - }, - "You're All Set!": { - "You're All Set!": "Alles bereit!" - }, - "Your system is up to date!": { - "Your system is up to date!": "Dein System ist auf dem neuesten Stand!" - }, - "actions": { - "actions": "Aktionen" - }, - "attached": { - "attached": "verbunden" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "von %1" - }, - "days": { - "days": "Tage" - }, - "detached": { - "detached": "getrennt" - }, - "device": { - "device": "Gerät" - }, - "devices connected": { - "devices connected": "Geräte verbunden" - }, - "dgop not available": { - "dgop not available": "dgop nicht verfügbar" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "dms ist eine hochgradig anpassbare, moderne Desktop-Shell mit einem Material 3 inspirierten Design.

        Sie wurde mit Quickshell entwickelt, einem QT6-Framework zum Erstellen von Desktop-Shells, und Go, einer statisch typisierten, kompilierten Programmiersprache." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "dms/cursor-Konfiguration existiert, ist aber nicht eingebunden. Cursor-Einstellungen werden nicht angewendet." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "Die Konfiguration 'dms/outputs' existiert, ist aber nicht in Ihrer Compositor-Konfiguration enthalten. Anzeigeänderungen werden nicht dauerhaft gespeichert." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "z.B., firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "z.B., focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "e.g., notify-send 'Hallo' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "z. B. scratch, /^tmp_.*/, build" - }, - "events": { - "events": "Ereignisse" - }, - "ext": { - "ext": "ext" - }, - "featured": { - "featured": "Hervorgehoben" - }, - "leave empty for default": { - "leave empty for default": "leer lassen für Standardwert" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl nicht verfügbar – Sperrintegration erfordert DMS-Socket-Verbindung" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord-Server" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen nicht gefunden - installieren Sie das matugen-Paket für dynamisches Theming" - }, - "minutes": { - "minutes": "minuten" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "Nav" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix-Chat" - }, - "niri shortcuts config": { - "niri shortcuts config": "niri-Tastenkombinationskonfiguration" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "jetzt" - }, - "official": { - "official": "offiziell" - }, - "on Hyprland": { - "on Hyprland": "auf Hyprland" - }, - "on MangoWC": { - "on MangoWC": "auf MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "auf Miracle WM" - }, - "on Niri": { - "on Niri": "auf Niri" - }, - "on Scroll": { - "on Scroll": "auf Scroll" - }, - "on Sway": { - "on Sway": "auf Sway" - }, - "open": { - "open": "öffnen" - }, - "or run ": { - "or run ": "oder ausführen " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon nicht verfügbar" - }, - "procs": { - "procs": "Prozesse" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri Subreddit" - }, - "seconds": { - "seconds": "sekunden" - }, - "source": { - "source": "Quelle" - }, - "this app": { - "this app": "diese App" - }, - "up": { - "up": "hoch" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "dms für NM-Integration aktualisieren." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 von %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype ist nicht verfügbar - installiere wtype für Unterstützung zum Einfügen" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "Nur aus vertrauenswürdigen Quellen installieren" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "M - Monat (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "MM - Monat (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "MMM - Monat (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "MMMM - Monat (Januar)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "Plugins können Fehler oder Sicherheitsprobleme enthalten" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "Code vor der Installation prüfen, wenn möglich" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "d - Tag (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "dd - Tag (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "ddd - Tag (Mon)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "dddd - Tag (Montag)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "yy - Jahr (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "yyyy - Jahr (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Nav • Leertaste: Erweitern • Eingabe: Aktion/Erweitern • E: Text" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: Navigieren • Enter/Strg+C: Kopieren • Entf: Löschen • F10: Hilfe" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Navigieren • Eingabe: Einfügen • Entf: Löschen • F10: Hilfe" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/es.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/es.json deleted file mode 100644 index 7aa9371..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/es.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 caracteres" - }, - "%1 connected": { - "%1 connected": "%1 conectado" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "" - }, - "%1 disconnected": { - "%1 disconnected": "" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "" - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "%1 notificaciones" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 variantes" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 widgets" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "hace %1m" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "" - }, - "(Unnamed)": { - "(Unnamed)": "(Sin nombre)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 más" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "0 = esquinas cuadradas" - }, - "1 day": { - "1 day": "1 dia" - }, - "1 device connected": { - "1 device connected": "1 dispositivo conectado" - }, - "1 event": { - "1 event": "1 evento" - }, - "1 hour": { - "1 hour": "" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "" - }, - "1 minute": { - "1 minute": "1 minuto" - }, - "1 notification": { - "1 notification": "1 notificación" - }, - "1 second": { - "1 second": "1 segundo" - }, - "10 minutes": { - "10 minutes": "10 minutos" - }, - "10 seconds": { - "10 seconds": "10 segundos" - }, - "10-bit Color": { - "10-bit Color": "Color de 10 bits" - }, - "12 hours": { - "12 hours": "" - }, - "14 days": { - "14 days": "14 dias" - }, - "15 minutes": { - "15 minutes": "" - }, - "15 seconds": { - "15 seconds": "15 segundos" - }, - "180°": { - "180°": "180º" - }, - "2 hours": { - "2 hours": "" - }, - "2 minutes": { - "2 minutes": "2 minutos" - }, - "2 seconds": { - "2 seconds": "" - }, - "20 minutes": { - "20 minutes": "" - }, - "20 seconds": { - "20 seconds": "" - }, - "24-Hour Format": { - "24-Hour Format": "Formato de 24 horas" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "Formato de 24 horas" - }, - "25 seconds": { - "25 seconds": "" - }, - "250 ms": { - "250 ms": "" - }, - "270°": { - "270°": "270º" - }, - "3 days": { - "3 days": "3 dias" - }, - "3 hours": { - "3 hours": "" - }, - "3 minutes": { - "3 minutes": "" - }, - "3 seconds": { - "3 seconds": "3 segundos" - }, - "30 days": { - "30 days": "30 dias" - }, - "30 minutes": { - "30 minutes": "" - }, - "30 seconds": { - "30 seconds": "30 segundos" - }, - "35 seconds": { - "35 seconds": "" - }, - "3rd party": { - "3rd party": "De terceros" - }, - "4 hours": { - "4 hours": "" - }, - "4 seconds": { - "4 seconds": "" - }, - "40 seconds": { - "40 seconds": "" - }, - "45 seconds": { - "45 seconds": "" - }, - "5 minutes": { - "5 minutes": "5 minutos" - }, - "5 seconds": { - "5 seconds": "5 segundos" - }, - "50 seconds": { - "50 seconds": "" - }, - "500 ms": { - "500 ms": "" - }, - "55 seconds": { - "55 seconds": "" - }, - "6 hours": { - "6 hours": "" - }, - "7 days": { - "7 days": "7 días" - }, - "750 ms": { - "750 ms": "" - }, - "8 hours": { - "8 hours": "" - }, - "8 seconds": { - "8 seconds": "8 segundos" - }, - "90 days": { - "90 days": "90 días" - }, - "90°": { - "90°": "90º" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Un archivo con este nombre ya existe. ¿Quieres reemplazarlo?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Un shell de escritorio moderno para compositores Wayland" - }, - "AC Power": { - "AC Power": "" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Abortado" - }, - "About": { - "About": "Información" - }, - "Accent Color": { - "Accent Color": "Color de acento" - }, - "Accept": { - "Accept": "" - }, - "Accept Jobs": { - "Accept Jobs": "Aceptar trabajos" - }, - "Accepting": { - "Accepting": "Aceptando" - }, - "Access clipboard history": { - "Access clipboard history": "Acceso al historial del portapapeles" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Acceso a notificaciones y al modo no molestar" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Acceso a controles y ajustes del sistema" - }, - "Action": { - "Action": "Acción" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "Acciones" - }, - "Activate": { - "Activate": "Activar" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "" - }, - "Active": { - "Active": "Activo" - }, - "Active Color": { - "Active Color": "" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Monitor de pantalla de bloqueo activo" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "" - }, - "Active: %1": { - "Active: %1": "Activo: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Activo: %1 +%2" - }, - "Active: None": { - "Active: None": "Activo: Ninguno" - }, - "Adapters": { - "Adapters": "Adaptadores" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Añadir" - }, - "Add Bar": { - "Add Bar": "Añadir barra" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Añadir Widget de Escritorio" - }, - "Add Printer": { - "Add Printer": "Añadir impresora" - }, - "Add Title": { - "Add Title": "" - }, - "Add Widget": { - "Add Widget": "Añadir widget" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Agregar widget a la sección %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Añade un recuadro alrededor del dock" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Añadir un prefijo personalizado a todas las aplicaciones que se ejecutan. Esto puede ser usado para cosas como 'uwsm-app', 'systemd-run', o otro comando envoltorio." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Añade y configura los widgets que aparecen en tu escritorio" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Ajustar cuántas columnas se muestran en la cuadrícula." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Avanzado" - }, - "Afternoon": { - "Afternoon": "Tarde" - }, - "All": { - "All": "Todo" - }, - "All Monitors": { - "All Monitors": "Todos los monitores" - }, - "All checks passed": { - "All checks passed": "Todas las comprobaciones fueron exitosas" - }, - "All day": { - "All day": "Todo el día" - }, - "All displays": { - "All displays": "Todas las pantallas" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Atrás • F1/I: Información del archivo • F10: Ayuda • Esc: Cerrar+" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "Siempre activo" - }, - "Always Show Percentage": { - "Always Show Percentage": "Mostrar siempre el porcentaje" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "" - }, - "Always on icons": { - "Always on icons": "Iconos fijos" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Mostrar siempre al menos 3 espacios, aunque haya menos disponibles" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Mostrar siempre el muelle cuando la vista general de niri está abierta" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Siempre mostrar cuando solo hay una pantalla conectada" - }, - "Amount": { - "Amount": "Cantidad" - }, - "Analog": { - "Analog": "Analogico" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Reloj analógico, digital o apilado" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Analizando la configuración..." - }, - "Animation Duration": { - "Animation Duration": "" - }, - "Animation Speed": { - "Animation Speed": "Velocidad de animación" - }, - "Anonymous Identity": { - "Anonymous Identity": "Identidad anónima" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Identidad anónima (opcional)" - }, - "App Customizations": { - "App Customizations": "" - }, - "App ID Substitutions": { - "App ID Substitutions": "" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "" - }, - "App Launcher": { - "App Launcher": "Lanzador de aplicaciones" - }, - "App Names": { - "App Names": "Nombre de la aplicación" - }, - "App Theming": { - "App Theming": "" - }, - "Appearance": { - "Appearance": "Apariencia" - }, - "Application Dock": { - "Application Dock": "Dock de aplicaciones" - }, - "Applications": { - "Applications": "Aplicaciones" - }, - "Apply Changes": { - "Apply Changes": "Aplicar cambios" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Aplicar colores GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Aplicar colores Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Aplicar un tono cálido para disminuir la fatiga visual. Configure abajo la automatización para definir cuándo se activa." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "" - }, - "Apps Dock": { - "Apps Dock": "" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "" - }, - "Apps Icon": { - "Apps Icon": "Apps" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Las aplicaciones son ordenadas por frecuencia de uso, luego por último utilizado, y luego alfabéticamente." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "" - }, - "Architecture": { - "Architecture": "Arquitectura" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Organice las pantallas y configure la resolución, la frecuencia de actualización y el VRR." - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "Audio" - }, - "Audio Codec": { - "Audio Codec": "Códec de Audio" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Selección de Codec de Audio" - }, - "Audio Devices": { - "Audio Devices": "Dispositivos de audio" - }, - "Audio Input": { - "Audio Input": "Entrada de audio" - }, - "Audio Output": { - "Audio Output": "Salida de auido" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Salida de audio (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Interruptor de salida de audio" - }, - "Audio Visualizer": { - "Audio Visualizer": "Visualizador de audio" - }, - "Audio system restarted": { - "Audio system restarted": "" - }, - "Audio volume control": { - "Audio volume control": "Control del volumen de audio" - }, - "Auth": { - "Auth": "Autenticación" - }, - "Auth Type": { - "Auth Type": "Tipo de autenticación" - }, - "Authenticate": { - "Authenticate": "Autenticar" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "Autenticación" - }, - "Authentication Required": { - "Authentication Required": "Autenticación requerida" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Autenticación fallida, intente nuevamente" - }, - "Authorize": { - "Authorize": "Autorizar" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autorizar emparejamiento con " - }, - "Authorize service for ": { - "Authorize service for ": "Autorizar servicio para " - }, - "Auto": { - "Auto": "Auto" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Auto (Ancho)" - }, - "Auto Location": { - "Auto Location": "Localización automática" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Márgenes automáticos en pop‑ups" - }, - "Auto-Clear After": { - "Auto-Clear After": "Limpiar automáticamente despues" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Cierre automático de la vista general de Niri al iniciar aplicaciones." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Eliminar automáticamente las notificaciones más antiguas" - }, - "Auto-hide": { - "Auto-hide": "Ocultar automáticamente" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Ocultar dock Automáticamente" - }, - "Auto-saving...": { - "Auto-saving...": "Guardando automáticamente..." - }, - "Autoconnect": { - "Autoconnect": "Autoconectar" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Conexión automática desactivada" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Conexión automática activada" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "" - }, - "Automatic Control": { - "Automatic Control": "Control Automático" - }, - "Automatic Cycling": { - "Automatic Cycling": "Ciclo automático" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Rotar automáticamente entre los fondos de pantalla en la misma carpeta" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Eliminar automaticamente entradas más viejas que esta" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Detectar la localización automáticamente basándose en la dirección IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Determinar tu ubicación usando tu dirección IP" - }, - "Automatically lock after": { - "Automatically lock after": "Bloquear después de" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Bloquear pantalla cuando el sistema se vaya a suspender" - }, - "Automation": { - "Automation": "" - }, - "Available": { - "Available": "Disponible" - }, - "Available Layouts": { - "Available Layouts": "Diseños disponibles" - }, - "Available Networks": { - "Available Networks": "Redes disponibles" - }, - "Available Plugins": { - "Available Plugins": "Complementos disponibles" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Pantallas disponibles (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Disponible en modo detallado y pronóstico" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Atrás" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Opacidad del fondo de pantalla" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Imagen de fondo" - }, - "Backlight device": { - "Backlight device": "Dispositivo de brillo" - }, - "Balance power and performance": { - "Balance power and performance": "" - }, - "Balanced": { - "Balanced": "" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Colores armonizados con acentos definidos (base)." - }, - "Bar Configurations": { - "Bar Configurations": "Configuración de barras" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "Transparencia de barra" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "" - }, - "Battery": { - "Battery": "Batería" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Limite de carga de bateria" - }, - "Battery and power management": { - "Battery and power management": "Bateria y gestion de energia" - }, - "Battery level and power management": { - "Battery level and power management": "Nivel de batería y gestión de energía" - }, - "Behavior": { - "Behavior": "Comportamiento" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Conectar pantalla de bloqueo a las señales dbus de loginctl. Deshabilitar si se usa una pantalla de bloqueo externa" - }, - "Binds Include Missing": { - "Binds Include Missing": "Enlaces Incluir Falta" - }, - "Binds include added": { - "Binds include added": "Inclusión de atajos añadida" - }, - "Bit Depth": { - "Bit Depth": "Profundidad de bits" - }, - "Block Out": { - "Block Out": "" - }, - "Block Out From": { - "Block Out From": "" - }, - "Block notifications": { - "Block notifications": "Bloquear notificaciones" - }, - "Blocked": { - "Blocked": "Bloqueado" - }, - "Blue light filter": { - "Blue light filter": "Filtro de luz azul" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Ajustes Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth no disponible" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Desenfocar capa de papel tapiz" - }, - "Blur on Overview": { - "Blur on Overview": "Desenfocar en la vista general" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Aplicar desenfoque en la vista general de niri" - }, - "Body": { - "Body": "" - }, - "Border": { - "Border": "Borde" - }, - "Border Color": { - "Border Color": "Color de borde" - }, - "Border Opacity": { - "Border Opacity": "Opacidad del borde" - }, - "Border Size": { - "Border Size": "Grosor del borde" - }, - "Border Thickness": { - "Border Thickness": "Grosor del borde" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "" - }, - "Bottom": { - "Bottom": "Abajo" - }, - "Bottom Center": { - "Bottom Center": "" - }, - "Bottom Left": { - "Bottom Left": "Abajo a la izquierda" - }, - "Bottom Right": { - "Bottom Right": "Abajo a la derecha" - }, - "Bottom Section": { - "Bottom Section": "Sección inferior" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Dock inferior para aplicaciones fijadas y abiertas" - }, - "Brightness": { - "Brightness": "Brillo" - }, - "Brightness Slider": { - "Brightness Slider": "Deslizador de brillo" - }, - "Brightness Value": { - "Brightness Value": "Valor del brillo" - }, - "Brightness control not available": { - "Brightness control not available": "Control de brillo no disponible" - }, - "Browse": { - "Browse": "Explorar" - }, - "Browse Files": { - "Browse Files": "" - }, - "Browse Plugins": { - "Browse Plugins": "Explorar Complementos" - }, - "Browse Themes": { - "Browse Themes": "Busqueda de temas" - }, - "Browse or search plugins": { - "Browse or search plugins": "" - }, - "Button Color": { - "Button Color": "" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "Grafico de la CPU" - }, - "CPU Temperature": { - "CPU Temperature": "Temperatura de CPU" - }, - "CPU Usage": { - "CPU Usage": "Uso de CPU" - }, - "CPU temperature display": { - "CPU temperature display": "Mostrar temperatura de CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "Indicador de uso de la CPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Monitorización de CPU, memoria, red y disco" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "Alerta de filtro inseguro en CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "Alerta de filtro faltante en CUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "Servidor de impresión CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS no esta disponibl" - }, - "Camera": { - "Camera": "Cámara" - }, - "Cancel": { - "Cancel": "Cancelar" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "" - }, - "Canceled": { - "Canceled": "Cancelado" - }, - "Cannot pair": { - "Cannot pair": "No se puede emparejar" - }, - "Capabilities": { - "Capabilities": "Capacidades" - }, - "Capacity": { - "Capacity": "Capacidad" - }, - "Caps Lock": { - "Caps Lock": "Bloqueo de Mayus." - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indicador de Bloq Mayús" - }, - "Caps Lock is on": { - "Caps Lock is on": "" - }, - "Center Section": { - "Center Section": "Sección central" - }, - "Center Single Column": { - "Center Single Column": "Columna central única" - }, - "Center Tiling": { - "Center Tiling": "Mosaico centrado" - }, - "Certificate Password": { - "Certificate Password": "Certificar contraseña" - }, - "Change Song": { - "Change Song": "" - }, - "Change Volume": { - "Change Volume": "" - }, - "Change bar appearance": { - "Change bar appearance": "Cambiar apariencia de la barra" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "Canal" - }, - "Charging": { - "Charging": "Cargando" - }, - "Check for system updates": { - "Check for system updates": "Comprobar actualizaciones del sistema" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "Elegir color" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Elegir Color del Icono en el Lanzador" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "" - }, - "Choose a color": { - "Choose a color": "Escojer un color" - }, - "Choose colors from palette": { - "Choose colors from palette": "Escoje colores de la paleta" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Elige cómo se muestra el widget del tiempo" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "Elegir icono" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Elegir el color de fondo para los widgets" - }, - "Choose the border accent color": { - "Choose the border accent color": "Elegir el color de acento del borde" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Elegir logo del lanzador en la DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Elegir posición de las notificaciones" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Elije dónde aparecen los indicadores en pantalla" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Elija qué pantallas muestran este widget" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Escoger en cuál monitor se muestra la interfaz de la pantalla de bloqueo. Otros mostrarán un color sólido para proteger las pantallas OLED contra quemaduras." - }, - "Chroma Style": { - "Chroma Style": "" - }, - "Cipher": { - "Cipher": "Cifrado" - }, - "Circle": { - "Circle": "" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "" - }, - "Clear": { - "Clear": "Limpiar" - }, - "Clear All": { - "Clear All": "Limpiar Todo" - }, - "Clear All Jobs": { - "Clear All Jobs": "Borrar todos los trabajos" - }, - "Clear History?": { - "Clear History?": "Limpiar historia?" - }, - "Clear Sky": { - "Clear Sky": "" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Limpiar todo el historial cuando el servidor inicia" - }, - "Clear at Startup": { - "Clear at Startup": "Limpiar al inicio" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Haga clic en \"Configuración\" para crear la configuración de salida y añadirla a la configuración del compositor." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Clic en importar para añadir un archivo .ovpn o .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "" - }, - "Click to capture": { - "Click to capture": "Clic para capturar" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Haz clic para seleccionar un archivo JSON de tema personalizado" - }, - "Clip": { - "Clip": "" - }, - "Clip to Geometry": { - "Clip to Geometry": "" - }, - "Clipboard": { - "Clipboard": "Portapapeles" - }, - "Clipboard History": { - "Clipboard History": "Historial del portapapeles" - }, - "Clipboard Manager": { - "Clipboard Manager": "Gestor de portapapeles" - }, - "Clipboard sent": { - "Clipboard sent": "" - }, - "Clipboard service not available": { - "Clipboard service not available": "Servicio de portapapeles no disponible" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "El portapapeles funciona pero no se guarda nada en el disco" - }, - "Clock": { - "Clock": "Reloj" - }, - "Clock Style": { - "Clock Style": "Estilo del reloj" - }, - "Close": { - "Close": "Cerrar" - }, - "Close All Windows": { - "Close All Windows": "" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Cerrar vista general al iniciar" - }, - "Close Window": { - "Close Window": "" - }, - "Color": { - "Color": "Color" - }, - "Color Gamut": { - "Color Gamut": "Gama de colores" - }, - "Color Management": { - "Color Management": "Gestion de color" - }, - "Color Mode": { - "Color Mode": "Modo de color" - }, - "Color Override": { - "Color Override": "Sobrescribir color" - }, - "Color Picker": { - "Color Picker": "Selector de color" - }, - "Color Temperature": { - "Color Temperature": "Temperatura de color" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "El color es mostrado en los monitores sin la pantalla de bloqueo" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "" - }, - "Color temperature for day time": { - "Color temperature for day time": "Temperatura de color para el día" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Temperatura de color para el modo nocturno" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Tema de color del registro DMS" - }, - "Colorful": { - "Colorful": "" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Colores vivos con contrastes luminosos." - }, - "Colorize Active": { - "Colorize Active": "" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Colores del fondo de pantalla" - }, - "Column": { - "Column": "Columna" - }, - "Column Display": { - "Column Display": "" - }, - "Column Width": { - "Column Width": "" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Comando" - }, - "Commands": { - "Commands": "" - }, - "Communication": { - "Communication": "Comunicación" - }, - "Community themes": { - "Community themes": "Temas de la comunidad" - }, - "Compact": { - "Compact": "Compacto" - }, - "Compact Mode": { - "Compact Mode": "Modo compacto" - }, - "Completed": { - "Completed": "Completado" - }, - "Compositor": { - "Compositor": "Compositor" - }, - "Compositor Settings": { - "Compositor Settings": "Ajustes del compositor" - }, - "Compositor not supported": { - "Compositor not supported": "" - }, - "Config Format": { - "Config Format": "Formato de la configuracion" - }, - "Config action: %1": { - "Config action: %1": "Acción de configuración: %1" - }, - "Config validation failed": { - "Config validation failed": "Fallo en la validación de la configuracion" - }, - "Configuration": { - "Configuration": "Configuracion" - }, - "Configuration activated": { - "Configuration activated": "Configuración activada" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "La configuración se conservará cuando esta pantalla vuelva a conectarse" - }, - "Configure": { - "Configure": "Configurar" - }, - "Configure Keybinds": { - "Configure Keybinds": "Configurar atajos de teclado" - }, - "Configure a new printer": { - "Configure a new printer": "Configurar nueva impresora" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Configurar íconos para espacios de trabajo con nombre. Los íconos tienen prioridad sobre los números cuando ambos están activados." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Configurar qué pantallas muestran los componentes del sistema" - }, - "Confirm": { - "Confirm": "Confirmar" - }, - "Confirm Delete": { - "Confirm Delete": "Confirmar eliminacion" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Confirmar cambios de pantalla" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Confirmar clave de acceso para " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Conflictos con: %1" - }, - "Connect": { - "Connect": "Conectar" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Conectar a una red oculta" - }, - "Connect to VPN": { - "Connect to VPN": "Conectar a una VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Conectarse al Wi-Fi" - }, - "Connected": { - "Connected": "Conectado" - }, - "Connected Device": { - "Connected Device": "" - }, - "Connected Displays": { - "Connected Displays": "Pantallas conectadas" - }, - "Connecting to Device": { - "Connecting to Device": "Conectando al dispositivo" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Conectando..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "" - }, - "Content": { - "Content": "" - }, - "Content copied": { - "Content copied": "" - }, - "Contrast": { - "Contrast": "Contraste" - }, - "Control Center": { - "Control Center": "Centro de control" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "" - }, - "Control currently playing media": { - "Control currently playing media": "Controlar la reproducción en curso" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Controla cuánta información de las notificaciones se muestra en la pantalla de bloqueo" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Controle los espacios de trabajo y las columnas desplazándose por la barra" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Controla la opacidad de todas las ventanas emergentes, modales y sus capas de contenido." - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "Enfriamiento" - }, - "Copied GIF": { - "Copied GIF": "" - }, - "Copied MP4": { - "Copied MP4": "" - }, - "Copied WebP": { - "Copied WebP": "" - }, - "Copied to clipboard": { - "Copied to clipboard": "Copiado al portapapeles" - }, - "Copied!": { - "Copied!": "¡Copiado!" - }, - "Copy": { - "Copy": "" - }, - "Copy Content": { - "Copy Content": "" - }, - "Copy Full Command": { - "Copy Full Command": "" - }, - "Copy HTML": { - "Copy HTML": "Copiar HTML" - }, - "Copy Name": { - "Copy Name": "" - }, - "Copy PID": { - "Copy PID": "Copiar ID del Proceso" - }, - "Copy Text": { - "Copy Text": "Copiar texto" - }, - "Copy path": { - "Copy path": "Copiar ubicación" - }, - "Corner Radius": { - "Corner Radius": "Radio de la esquina" - }, - "Corner Radius Override": { - "Corner Radius Override": "Redondeo de esquinas personal" - }, - "Corners & Background": { - "Corners & Background": "Esquinas y Fondo" - }, - "Count Only": { - "Count Only": "Solo la cantidad" - }, - "Cover Open": { - "Cover Open": "Cubierta abierta" - }, - "Create": { - "Create": "" - }, - "Create Dir": { - "Create Dir": "Crear carpeta" - }, - "Create Printer": { - "Create Printer": "Crear impresora" - }, - "Create Window Rule": { - "Create Window Rule": "" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "" - }, - "Creating...": { - "Creating...": "Creando..." - }, - "Critical Priority": { - "Critical Priority": "Prioridad Crítica" - }, - "Current": { - "Current": "Actuales" - }, - "Current Items": { - "Current Items": "Elementos Actuales" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "" - }, - "Current Period": { - "Current Period": "Período actual" - }, - "Current Status": { - "Current Status": "Estado actual" - }, - "Current Temp": { - "Current Temp": "Temperatura actual" - }, - "Current Theme: %1": { - "Current Theme: %1": "Tema actual: %1" - }, - "Current Weather": { - "Current Weather": "Clima actual" - }, - "Current Workspace": { - "Current Workspace": "" - }, - "Current time and date display": { - "Current time and date display": "Mostrar hora y fecha actual" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Condiciones meteorológicas y temperatura actuales" - }, - "Current: %1": { - "Current: %1": "Actual: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "" - }, - "Cursor Size": { - "Cursor Size": "Tamaño del cursor" - }, - "Cursor Theme": { - "Cursor Theme": "Tema del cursor" - }, - "Custom": { - "Custom": "Personal" - }, - "Custom Color": { - "Custom Color": "Color personalizado" - }, - "Custom Duration": { - "Custom Duration": "Duracion personalizada" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Comando de hibernación personalizado" - }, - "Custom Location": { - "Custom Location": "Ubicación personalizada" - }, - "Custom Lock Command": { - "Custom Lock Command": "Comando de bloqueo personalizado" - }, - "Custom Logout Command": { - "Custom Logout Command": "Comando de cierre de sesion personalizado" - }, - "Custom Name": { - "Custom Name": "" - }, - "Custom Power Actions": { - "Custom Power Actions": "Acciones de energía personalizadas" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Comando de apagado personalizado" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Comando de reinicio personalizado" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Comando de suspension personalizado" - }, - "Custom Transparency": { - "Custom Transparency": "Transparencia personalizada" - }, - "Custom power profile": { - "Custom power profile": "" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Tema personalizado cargado desde archivo JSON" - }, - "Custom...": { - "Custom...": "Personalizado..." - }, - "Custom: ": { - "Custom: ": "Personalizado: " - }, - "Customizable empty space": { - "Customizable empty space": "Espacio vacío personalizable" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Personalizar qué acciones aparecen en el menú de energía" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "Monitor DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMOSTRACIÓN - Haz clic en cualquier lugar para salir" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Gestor de complementos DMS no disponible" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Atajos de DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS desactualizado" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Servicio de DMS no está conectado. Los ajustes del portapapeles no están disponibles." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Acciones de DMS Shell (lanzador, portapapeles, etc.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET no disponible" - }, - "DWL service not available": { - "DWL service not available": "Servicio DWL no disponible" - }, - "Daily": { - "Daily": "" - }, - "Daily at:": { - "Daily at:": "Todos los días a las:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell está listo para utilizarse" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "Dank Shell e Iconos del Sistema (requiere reinicio)" - }, - "Dark Mode": { - "Dark Mode": "Modo oscuro" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Fondo de modal oscuro" - }, - "Date Format": { - "Date Format": "Formato de fecha" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Amanecer (Crepúsculo astronómico)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Amanecer (Crepusculo Civil)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Amanecer (Crepúsculo náutico)" - }, - "Day Date": { - "Day Date": "" - }, - "Day Month Date": { - "Day Month Date": "" - }, - "Day Temperature": { - "Day Temperature": "Temperatura de día" - }, - "Daytime": { - "Daytime": "Durante el día" - }, - "Deck": { - "Deck": "Bandeja" - }, - "Default": { - "Default": "Base" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "Anchura por defecto (%)" - }, - "Default selected action": { - "Default selected action": "Acción predeterminada" - }, - "Defaults": { - "Defaults": "Base" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Borrar • Shift+Del: Borrar todo • 1-9: Acciones • F10: Ayuda • Esc: Cerrar" - }, - "Delete": { - "Delete": "Eliminar" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "" - }, - "Delete Class": { - "Delete Class": "Eliminar clase" - }, - "Delete Printer": { - "Delete Printer": "Eliminar impresora" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "" - }, - "Delete VPN": { - "Delete VPN": "Eliminar VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Colores que reflejan fielmente la imagen original." - }, - "Description": { - "Description": "Descripción" - }, - "Desktop": { - "Desktop": "" - }, - "Desktop Clock": { - "Desktop Clock": "Reloj del escritorio" - }, - "Desktop Entry": { - "Desktop Entry": "" - }, - "Desktop Widget": { - "Desktop Widget": "Widget de escritorio" - }, - "Desktop Widgets": { - "Desktop Widgets": "Widgets del Escritorio" - }, - "Desktop background images": { - "Desktop background images": "Imágenes de fondo de escritorio" - }, - "Detailed": { - "Detailed": "Detallado" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "Desarrollo" - }, - "Device": { - "Device": "Dispositivo" - }, - "Device connections": { - "Device connections": "Conexiones de dispositivos" - }, - "Device names updated": { - "Device names updated": "" - }, - "Device paired": { - "Device paired": "Dispositivo emparejado" - }, - "Device unpaired": { - "Device unpaired": "" - }, - "Digital": { - "Digital": "Digital" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Desactivar conexión automática" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Desactivar sitema de fondos de pantalla por defecto" - }, - "Disable History Persistence": { - "Disable History Persistence": "Deshabilitar persistencia del historial" - }, - "Disable Output": { - "Disable Output": "Desabilitar salida" - }, - "Disabled": { - "Disabled": "Desactivado" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Desabilitando WiFi..." - }, - "Disc": { - "Disc": "" - }, - "Discard": { - "Discard": "Descartar" - }, - "Discharging": { - "Discharging": "" - }, - "Disconnect": { - "Disconnect": "Desconectar" - }, - "Disconnected": { - "Disconnected": "Desconectado" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Wi‑Fi desconectado" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "Disco" - }, - "Disk I/O": { - "Disk I/O": "E/S de disco" - }, - "Disk Usage": { - "Disk Usage": "Uso de disco" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "Discos" - }, - "Dismiss": { - "Dismiss": "Descartar" - }, - "Display": { - "Display": "" - }, - "Display Assignment": { - "Display Assignment": "Pantalla asignada" - }, - "Display Control": { - "Display Control": "Control del monitor" - }, - "Display Name Format": { - "Display Name Format": "Formato de nombre" - }, - "Display Profiles": { - "Display Profiles": "" - }, - "Display Settings": { - "Display Settings": "Ajustes de monitor" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Mostrar un dock con aplicaciones ancladas y en ejecución" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Prioridades visibles sobre apps en pantalla completa" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Mostrar y cambiar diseños DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Mostrar iconos de aplicaciones en los espacios" - }, - "Display brightness control": { - "Display brightness control": "Control del brillo de la pantalla" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "La configuración de la pantalla no está disponible. No se admite el protocolo de gestión de salida WLR." - }, - "Display currently focused application title": { - "Display currently focused application title": "Mostrar título de la aplicación enfocada" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Mostrar pronósticos por hora" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Mostrar solo los espacios que contengan ventanas" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Mostrar acciones en una cuadrícula en vez de una lista" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Mostrar segundos en el reloj" - }, - "Display the power system menu": { - "Display the power system menu": "Mostrar el menu de apagado de sistema" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Mostrar valores de porcentaje de brillo y volumen en las ventanas emergentes del OSD" - }, - "Displays": { - "Displays": "Pantallas" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Muestra la distribución de teclado activa y permite cambiarla" - }, - "Distribution": { - "Distribution": "Distribución" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Paleta variada con toda la gama de colores." - }, - "Do Not Disturb": { - "Do Not Disturb": "No molestar" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock y Lanzador" - }, - "Dock Transparency": { - "Dock Transparency": "Transparencia del dock" - }, - "Dock Visibility": { - "Dock Visibility": "Visibilidad del dock" - }, - "Docs": { - "Docs": "Docs" - }, - "Documents": { - "Documents": "" - }, - "Domain (optional)": { - "Domain (optional)": "Dominio (opcional)" - }, - "Don't Change": { - "Don't Change": "No cambiar" - }, - "Don't Save": { - "Don't Save": "No guardar" - }, - "Door Open": { - "Door Open": "Puera abierta" - }, - "Downloads": { - "Downloads": "" - }, - "Drag to Reorder": { - "Drag to Reorder": "" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Arrastra los widgets para reordenarlos dentro de las secciones. Usa el icono de ojo para ocultar/mostrar widgets (mantiene el espacio), o la X para eliminarlos por completo." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "" - }, - "Driver": { - "Driver": "Controlador" - }, - "Drizzle": { - "Drizzle": "" - }, - "Duplicate": { - "Duplicate": "Duplicado" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Desenfocar fondo de pantalla" - }, - "Duration": { - "Duration": "" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Crepúsculo (crepúsculo astronómico)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Crepúsculo (Civil Twighlight)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Atardecer (Crepúsculo náutico)" - }, - "Dynamic": { - "Dynamic": "Dinamico" - }, - "Dynamic Properties": { - "Dynamic Properties": "" - }, - "Dynamic Theming": { - "Dynamic Theming": "Temas dinámicos" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Colores dinámicos desde el fondo de pantalla" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Colores y esquemas dinámicos" - }, - "Edge Spacing": { - "Edge Spacing": "Espacio entre bordes" - }, - "Edit App": { - "Edit App": "" - }, - "Edit Window Rule": { - "Edit Window Rule": "" - }, - "Education": { - "Education": "Educación" - }, - "Empty": { - "Empty": "Vacío" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Habilita la profundidad de color de 10 bits para ampliar la gama de colores y la compatibilidad con HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Activar conexión automática" - }, - "Enable Bar": { - "Enable Bar": "Habilitar barra" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Activar \"No Molestar\"" - }, - "Enable History": { - "Enable History": "Activar historial" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Activar el overlay en la vista general" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "" - }, - "Enable System Sounds": { - "Enable System Sounds": "Activar sonidos del sistema" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "Habilitar clima" - }, - "Enable WiFi": { - "Enable WiFi": "Habilitar WiFi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Activar capa de desenfoque dirigida por el compositor (namespace: dms:blurwallpaper). Requiere configuración manual de Niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Habilitar autenticación por huella digital" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Habilitar integración con loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "Habilitado" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Habilitando WiFi..." - }, - "End": { - "End": "Final" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "" - }, - "Enlargement %": { - "Enlargement %": "" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Ingresar clave de 6 dígitos" - }, - "Enter PIN": { - "Enter PIN": "Ingresar PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Ingresar PIN para " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "Ingresar credenciales para " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Ingresar formato personalizado para la pantalla de bloqueo (e.j., dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Ingresar formato personalizado para la barra superior (e.j., ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "" - }, - "Enter filename...": { - "Enter filename...": "Ingrese nombre de archivo..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Introduce prefijo de lanzamiento (e.j.,'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Ingrese el nombre y la contraseña de la red" - }, - "Enter passkey for ": { - "Enter passkey for ": "Ingresar clave para " - }, - "Enter password for ": { - "Enter password for ": "Ingresa la contraseña para " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Introduzca esta clave en " - }, - "Enter to Paste": { - "Enter to Paste": "" - }, - "Enterprise": { - "Enterprise": "Empresa" - }, - "Entry pinned": { - "Entry pinned": "" - }, - "Entry unpinned": { - "Entry unpinned": "" - }, - "Environment Variables": { - "Environment Variables": "" - }, - "Error": { - "Error": "Error" - }, - "Errors": { - "Errors": "Errores" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Zona exclusiva" - }, - "Experimental Feature": { - "Experimental Feature": "Funcion experimental" - }, - "Explore": { - "Explore": "Explorar" - }, - "Exponential": { - "Exponential": "Exponencial" - }, - "Expressive": { - "Expressive": "" - }, - "Extend battery life": { - "Extend battery life": "" - }, - "Extensible architecture": { - "Extensible architecture": "Arquitectura extensible" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Manejo externo del fondo de pantalla" - }, - "Extra Arguments": { - "Extra Arguments": "Argumentos extra" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Accionar • F10: Ayudar" - }, - "Fade": { - "Fade": "" - }, - "Fade to lock screen": { - "Fade to lock screen": "Bloquear con transición suave" - }, - "Fade to monitor off": { - "Fade to monitor off": "Fundido antes de apagar monitor" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Error al activar la configuración" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "" - }, - "Failed to add binds include": { - "Failed to add binds include": "Fallo al añadir la inclusion de binds" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Error al agregar la impresora a la clase" - }, - "Failed to browse device": { - "Failed to browse device": "" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Error al cancelar todos los trabajos" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Error al cancelar el trabajo seleccionado" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Hubo un error al conectar con la VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Fallo al conectar a %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Fallo al copiar la entrada" - }, - "Failed to create printer": { - "Failed to create printer": "Error al crear la impresora" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Error al eliminar VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Error al eliminar la clase" - }, - "Failed to delete printer": { - "Failed to delete printer": "Error al eliminar la impresora" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Error al desactivar la aceptación de trabajos" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Error al desactivar el modo nocturno" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Error al desconectar VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Error al desconectar los VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Error al desconectar Wi‑Fi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Fallo al habilitar la localizacion por IP" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Error al activar el WiFi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Error al habilitar la aceptación de trabajos" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Fallo al habilitar el modo nocturno" - }, - "Failed to hold job": { - "Failed to hold job": "Error al retener el trabajo" - }, - "Failed to import VPN": { - "Failed to import VPN": "Error al importar VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Error al cargar configuración VPN" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Fallo al cargar la configuración del portapapeles" - }, - "Failed to move job": { - "Failed to move job": "Error al mover el trabajo" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Fallo al parsear plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Fallo al parsear session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Fallo al parsear settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Error al pausar la impresora" - }, - "Failed to pin entry": { - "Failed to pin entry": "" - }, - "Failed to print test page": { - "Failed to print test page": "Error al imprimir la página de prueba" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "" - }, - "Failed to remove device": { - "Failed to remove device": "Error al eliminar dispositivo" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Fallo al eliminar atajo de tecla" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Error al quitar la impresora de la clase" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "" - }, - "Failed to restart job": { - "Failed to restart job": "Error al reiniciar el trabajo" - }, - "Failed to resume printer": { - "Failed to resume printer": "Error al reanudar la impresora" - }, - "Failed to ring device": { - "Failed to ring device": "" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Fallo al guardar ajuste del portapapeles" - }, - "Failed to save keybind": { - "Failed to save keybind": "No se ha podido guardar la combinación de teclas" - }, - "Failed to save profile file": { - "Failed to save profile file": "" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "" - }, - "Failed to send file": { - "Failed to send file": "" - }, - "Failed to send ping": { - "Failed to send ping": "" - }, - "Failed to set brightness": { - "Failed to set brightness": "Fallo al establecer el brillo" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Fallo al establecer la ubicación del modo nocturno" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Fallo al establecer el horario del modo nocturno" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "No se ha podido ajustar la temperatura del modo nocturno" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "Hubo un error al poner la imágen de perfil" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Error al establecer la imagen de perfil: %1" - }, - "Failed to share": { - "Failed to share": "" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Error al iniciar la conexión con %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "" - }, - "Failed to update VPN": { - "Failed to update VPN": "Error al actualizar VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Fallo al actualizar la conexión automática" - }, - "Failed to update description": { - "Failed to update description": "Error al actualizar la descripción" - }, - "Failed to update location": { - "Failed to update location": "Error al actualizar la ubicación" - }, - "Failed to update sharing": { - "Failed to update sharing": "Error al actualizar la compartición" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Fallo al escribir archivo temporal para la validacion" - }, - "Features": { - "Features": "Funciones" - }, - "Feels": { - "Feels": "Sensación" - }, - "Feels Like": { - "Feels Like": "Sensación térmica" - }, - "Feels Like %1°": { - "Feels Like %1°": "Sensación térmica %1°" - }, - "Fidelity": { - "Fidelity": "" - }, - "Field": { - "Field": "" - }, - "File": { - "File": "Archivo" - }, - "File Already Exists": { - "File Already Exists": "El archivo ya existe" - }, - "File Information": { - "File Information": "Información del archivo" - }, - "File received from": { - "File received from": "" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "" - }, - "Files": { - "Files": "Archivos" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Supervisión del uso del sistema de archivos" - }, - "Fill": { - "Fill": "" - }, - "Find in Text": { - "Find in Text": "Encontrar texto" - }, - "Find in note...": { - "Find in note...": "Encontrar en notas..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "Terminar" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "Configuración inicial" - }, - "Fit": { - "Fit": "" - }, - "Fix Now": { - "Fix Now": "Arreglar ahora" - }, - "Fixing...": { - "Fixing...": "Arreglando..." - }, - "Flags": { - "Flags": "" - }, - "Flipped": { - "Flipped": "Voltear" - }, - "Flipped 180°": { - "Flipped 180°": "Volteado 180" - }, - "Flipped 270°": { - "Flipped 270°": "Volteado 270" - }, - "Flipped 90°": { - "Flipped 90°": "Volteado 90" - }, - "Float": { - "Float": "" - }, - "Focus": { - "Focus": "" - }, - "Focus at Startup": { - "Focus at Startup": "Centrarse en el inicio" - }, - "Focused Border": { - "Focused Border": "" - }, - "Focused Color": { - "Focused Color": "" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "Ventana enfocada" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "" - }, - "Folder": { - "Folder": "" - }, - "Folders": { - "Folders": "" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "" - }, - "Follow focus": { - "Follow focus": "Seguir foco" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "Familia de tipografía" - }, - "Font Scale": { - "Font Scale": "Tamaño de la tipografía" - }, - "Font Size": { - "Font Size": "Tamaño de fuente" - }, - "Font Weight": { - "Font Weight": "Grosor de fuente" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "Forzar HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "" - }, - "Force Wide Color": { - "Force Wide Color": "Force Wide Color" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Forzar que las aplicaciones de terminal usen esquemas de colores oscuros" - }, - "Forecast": { - "Forecast": "Pronóstico" - }, - "Forecast Days": { - "Forecast Days": "" - }, - "Forecast Not Available": { - "Forecast Not Available": "No hay previsión del tiempo disponible" - }, - "Forever": { - "Forever": "Siempre" - }, - "Forget": { - "Forget": "Olvidar" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "" - }, - "Forget Device": { - "Forget Device": "Olvidar dispositivo" - }, - "Forget Network": { - "Forget Network": "Olvidar red" - }, - "Forgot network %1": { - "Forgot network %1": "Olvidaste la red %1" - }, - "Format Legend": { - "Format Legend": "Guía de formato" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "" - }, - "Frequency": { - "Frequency": "Frecuencia" - }, - "Fruit Salad": { - "Fruit Salad": "" - }, - "Full Command:": { - "Full Command:": "" - }, - "Full Content": { - "Full Content": "Contenido completo" - }, - "Full Day & Month": { - "Full Day & Month": "" - }, - "Full with Year": { - "Full with Year": "" - }, - "Fullscreen": { - "Fullscreen": "" - }, - "Fullscreen Only": { - "Fullscreen Only": "" - }, - "Fully Charged": { - "Fully Charged": "" - }, - "Fun": { - "Fun": "Diversión" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: cuadrícula - Z/X: tamaño" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "Monitorización de GPU" - }, - "GPU Temperature": { - "GPU Temperature": "Temperatura de GPU" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE y más" - }, - "Games": { - "Games": "Juegos" - }, - "Gamma Control": { - "Gamma Control": "Control de gamma" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Control de gamma no disponible. Requiere DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "" - }, - "Get Started": { - "Get Started": "Comenzar" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "" - }, - "Golden Hour": { - "Golden Hour": "Crepúsculo" - }, - "Good": { - "Good": "Bien" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Redondeo de esquinas góticas" - }, - "Goth Corners": { - "Goth Corners": "Esquinas góticas" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Desvanecer gradualmente la pantalla antes de bloquear, con una duración configurable" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "La pantalla se funde a negro antes de apagar el monitor, tras un intervalo configurable" - }, - "Graph Time Range": { - "Graph Time Range": "Gráfico Intervalo de tiempo" - }, - "Graphics": { - "Graphics": "Gráficos" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "Cuadricula" - }, - "Grid Columns": { - "Grid Columns": "Columnas de cuadrícula" - }, - "Grid: OFF": { - "Grid: OFF": "Cuadricula: OFF" - }, - "Grid: ON": { - "Grid: ON": "Cuadricula: ON" - }, - "Group": { - "Group": "" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Aplicaciones del espacio de trabajo en grupo" - }, - "Group by App": { - "Group by App": "Agrupar por aplicación" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Mostrar número de ventanas agrupadas en el icono de la aplicación" - }, - "Group removed": { - "Group removed": "" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Agrupar iconos de aplicaciones repetidos en espacios de trabajo desenfocados" - }, - "Groups": { - "Groups": "" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Mapeo de tonos HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "El modo HDR es experimental. Comprueba que tu monitor es compatible con HDR antes de activarlo." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML copiado al portapapeles" - }, - "Health": { - "Health": "Salud" - }, - "Heavy Rain": { - "Heavy Rain": "" - }, - "Heavy Snow": { - "Heavy Snow": "" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "" - }, - "Height": { - "Height": "" - }, - "Held": { - "Held": "Retenido" - }, - "Help": { - "Help": "Ayuda" - }, - "Hex": { - "Hex": "HEX" - }, - "Hibernate": { - "Hibernate": "Hibernar" - }, - "Hidden": { - "Hidden": "" - }, - "Hidden (%1)": { - "Hidden (%1)": "" - }, - "Hidden Apps": { - "Hidden Apps": "" - }, - "Hidden Network": { - "Hidden Network": "" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "" - }, - "Hide": { - "Hide": "" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "" - }, - "Hide App": { - "Hide App": "" - }, - "Hide Delay": { - "Hide Delay": "Ocultar Retardo" - }, - "Hide Indicators": { - "Hide Indicators": "" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Ocultar widget de actualizacion" - }, - "Hide When Typing": { - "Hide When Typing": "Ocultar cuando se tipea" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Ocultar opciones cuando hay ventanas abiertas" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Ocultar cursor cuando se presionan teclas" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "" - }, - "Hide device": { - "Hide device": "" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "" - }, - "Hide on Touch": { - "Hide on Touch": "" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Paleta fiel que conserva los tonos originales." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "Historial" - }, - "History Retention": { - "History Retention": "Preservación del historial" - }, - "History Settings": { - "History Settings": "Ajustes de historial" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "" - }, - "Hold Duration": { - "Hold Duration": "Duración de pulsación" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Mantenga pulsado para confirmar" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Mantener pulsado para confirmar" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Manten para confirmar (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Mantener pulsado para confirmar (%1s)" - }, - "Home": { - "Home": "" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "" - }, - "Hot Corners": { - "Hot Corners": "Esquinas calientes" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Título de la superposición de teclas de acceso rápido (opcional)" - }, - "Hour": { - "Hour": "Hora" - }, - "Hourly": { - "Hourly": "" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Con qué frecuencia cambiar el fondo de pantalla" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "Humedad" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Sobreescribir opciones de Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "Lo entiendo" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "Dirección IP:" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "" - }, - "Icon": { - "Icon": "Icono" - }, - "Icon Scale": { - "Icon Scale": "" - }, - "Icon Size": { - "Icon Size": "Tamaño de icono" - }, - "Icon Size %": { - "Icon Size %": "" - }, - "Icon Theme": { - "Icon Theme": "Tema de iconos" - }, - "Idle": { - "Idle": "Inactivo" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inhibir inactividad" - }, - "Idle Settings": { - "Idle Settings": "Ajustes de inactividad" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Monitoreo de inactividad no soportado - requiere versión reciente de Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Si el campo esta oculto, aparecera tan pronto como la tecla este presionada" - }, - "Ignore Completely": { - "Ignore Completely": "" - }, - "Image": { - "Image": "Imagen" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Imagen copiada al portapapeles" - }, - "Import": { - "Import": "Importar" - }, - "Import VPN": { - "Import VPN": "Importar VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Color del monitor inactivo" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Incluir transiciones" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Plugins incompatibles cargados" - }, - "Incorrect password": { - "Incorrect password": "Contraseña incorrecta" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Estilo del indicador" - }, - "Individual Batteries": { - "Individual Batteries": "Baterías individuales" - }, - "Individual bar configuration": { - "Individual bar configuration": "Configuración individual de la barra" - }, - "Info": { - "Info": "Información" - }, - "Inherit": { - "Inherit": "Heredar" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "" - }, - "Input Devices": { - "Input Devices": "Dispositivos de entrada" - }, - "Input Volume Slider": { - "Input Volume Slider": "Deslizador de volumen de entrada" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Instalar" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "Instalar complemento" - }, - "Install Theme": { - "Install Theme": "Instalar tema" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Instalar tema de colores desde el repositorio de temas de DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "Instalación fallida: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Instalar matugen para tematizacion dinamica" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "¿Instalar plugin '%1' desde el registro de DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Instalar complementos de los registros de complementos DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "¿Instalar el tema '%1' desde el registro DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "Instalado" - }, - "Installed: %1": { - "Installed: %1": "Instalado: %1" - }, - "Installing: %1": { - "Installing: %1": "Instalando: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "" - }, - "Intensity": { - "Intensity": "Intensidad" - }, - "Interface:": { - "Interface:": "Interfaz:" - }, - "Interlock Open": { - "Interlock Open": "Bloqueo abierto" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervalo" - }, - "Invalid configuration": { - "Invalid configuration": "Configuracion invalida" - }, - "Invert on mode change": { - "Invert on mode change": "Invertir al cambiar de modo" - }, - "Iris Bloom": { - "Iris Bloom": "" - }, - "Isolate Displays": { - "Isolate Displays": "Aislar pantallas" - }, - "Jobs": { - "Jobs": "Trabajos" - }, - "Jobs: ": { - "Jobs: ": "Trabajos:" - }, - "Keep Awake": { - "Keep Awake": "Mantener despierto" - }, - "Keep Changes": { - "Keep Changes": "Mantener cambios" - }, - "Keeping Awake": { - "Keeping Awake": "Mantener despierto" - }, - "Kernel": { - "Kernel": "" - }, - "Key": { - "Key": "Tecla" - }, - "Keybind Sources": { - "Keybind Sources": "" - }, - "Keybinds": { - "Keybinds": "Atajos de teclado" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Distribución de teclado" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Atajos de teclado" - }, - "Keys": { - "Keys": "Teclas" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "Matar el proceso" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "Dispositivo LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "" - }, - "Largest": { - "Largest": "" - }, - "Last hour": { - "Last hour": "Última hora" - }, - "Last launched %1": { - "Last launched %1": "Usado hace %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "Usado justo ahora" - }, - "Latitude": { - "Latitude": "Latitud" - }, - "Launch": { - "Launch": "Iniciar" - }, - "Launch Prefix": { - "Launch Prefix": "Prefijo de lanzamiento" - }, - "Launch on dGPU": { - "Launch on dGPU": "Iniciar con la tarjeta discreta" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Lanzador" - }, - "Launcher Button": { - "Launcher Button": "" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Icono del lanzador" - }, - "Layout": { - "Layout": "Diseño" - }, - "Layout Overrides": { - "Layout Overrides": "Anulaciones de diseño" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Izquierda" - }, - "Left Center": { - "Left Center": "" - }, - "Left Section": { - "Left Section": "Sección izquierda" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "Modo claro" - }, - "Light Rain": { - "Light Rain": "" - }, - "Light Snow": { - "Light Snow": "" - }, - "Light Snow Showers": { - "Light Snow Showers": "" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "Lineal" - }, - "Lines: %1": { - "Lines: %1": "Líneas: %1" - }, - "List": { - "List": "Lista" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Paleta vibrante con acentos saturados." - }, - "Load Average": { - "Load Average": "" - }, - "Loading codecs...": { - "Loading codecs...": "Cargando codecs..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Cargando los atajos..." - }, - "Loading trending...": { - "Loading trending...": "" - }, - "Loading...": { - "Loading...": "Cargando..." - }, - "Local": { - "Local": "Local" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "Ubicación" - }, - "Location Search": { - "Location Search": "Búsqueda de ubicación" - }, - "Lock": { - "Lock": "Bloquear" - }, - "Lock Screen": { - "Lock Screen": "Pantalla de bloqueo" - }, - "Lock Screen Display": { - "Lock Screen Display": "Visualización de la pantalla de bloqueo" - }, - "Lock Screen Format": { - "Lock Screen Format": "Formato en la pantalla de bloqueo" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Comportamiento de la pantalla de bloqueo" - }, - "Lock Screen layout": { - "Lock Screen layout": "Disposicion de la pantalla de bloqueo" - }, - "Lock at startup": { - "Lock at startup": "" - }, - "Lock before suspend": { - "Lock before suspend": "Bloquear pantalla antes de suspender" - }, - "Lock fade grace period": { - "Lock fade grace period": "Intervalo de fundido antes de bloquear la pantalla" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "" - }, - "Log Out": { - "Log Out": "Cerrar sesión" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "Largo" - }, - "Long Text": { - "Long Text": "Texto largo" - }, - "Long press": { - "Long press": "" - }, - "Longitude": { - "Longitude": "Longitud" - }, - "Low Priority": { - "Low Priority": "Prioridad baja" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Configurar complementos para extender la funcionalidad de DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Administra hasta 4 barras diferentes. Cada una tiene su posición, widgets, estilo y pantalla asignada." - }, - "Management": { - "Management": "Gestión" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "Sobreescribir opciones de MangoWC" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "Coordenadas manuales" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "Tamaño de separación manual" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Mostrar/Ocultar manualmente" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "" - }, - "Margin": { - "Margin": "Margen" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Suministro de tinta vacío" - }, - "Marker Supply Low": { - "Marker Supply Low": "Suministro de tinta bajo" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Depósito de residuos casi lleno" - }, - "Marker Waste Full": { - "Marker Waste Full": "Depósito de residuos lleno" - }, - "Match Criteria": { - "Match Criteria": "" - }, - "Matches profile: %1": { - "Matches profile: %1": "" - }, - "Material Colors": { - "Material Colors": "Colores Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Temas de color inspirados en Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Colores material generados desde el fondo de pantalla" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen perdido" - }, - "Matugen Palette": { - "Matugen Palette": "Paleta de Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Monitor objetivo de Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Plantillas de Matugen" - }, - "Max Edges": { - "Max Edges": "" - }, - "Max H": { - "Max H": "" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "" - }, - "Max Running Apps": { - "Max Running Apps": "" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "" - }, - "Max Volume": { - "Max Volume": "" - }, - "Max W": { - "Max W": "" - }, - "Max apps to show": { - "Max apps to show": "Máximo de aplicaciones a mostrar" - }, - "Max to Edges": { - "Max to Edges": "" - }, - "Maximize": { - "Maximize": "" - }, - "Maximize Detection": { - "Maximize Detection": "Maximizar la detección" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Tamaño máximo de entrada" - }, - "Maximum History": { - "Maximum History": "Historial máxima" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Número máximo de entradas del portapapeles a conservar" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Número máximo de notificaciones que se conservarán" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Tamaño máximo por entrada en el portapapeles" - }, - "Media": { - "Media": "Multimedia" - }, - "Media Controls": { - "Media Controls": "Controles multimedia" - }, - "Media Empty": { - "Media Empty": "Medio vacio" - }, - "Media Jam": { - "Media Jam": "Papel atascado" - }, - "Media Low": { - "Media Low": "Medio bajo" - }, - "Media Needed": { - "Media Needed": "Medio necesario" - }, - "Media Playback": { - "Media Playback": "" - }, - "Media Player": { - "Media Player": "Reproductor de multimedia" - }, - "Media Player Settings": { - "Media Player Settings": "Ajustes del reproductor" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "Reproductores (" - }, - "Media Volume": { - "Media Volume": "Volumen de multimedia" - }, - "Medium": { - "Medium": "Medio" - }, - "Memory": { - "Memory": "Memoria" - }, - "Memory Graph": { - "Memory Graph": "Grafico de memoria" - }, - "Memory Usage": { - "Memory Usage": "Uso de memoria" - }, - "Memory usage indicator": { - "Memory usage indicator": "Indicador del uso de memoria" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Mensaje" - }, - "Message Content": { - "Message Content": "" - }, - "Microphone": { - "Microphone": "Micrófono" - }, - "Microphone Mute": { - "Microphone Mute": "Silenciar micrófono" - }, - "Microphone Volume": { - "Microphone Volume": "Volumen del micrófono" - }, - "Microphone settings": { - "Microphone settings": "Ajustes de microfono" - }, - "Microphone volume control": { - "Microphone volume control": "Control de volumen del microfono" - }, - "Middle Section": { - "Middle Section": "Sección central" - }, - "Min H": { - "Min H": "" - }, - "Min W": { - "Min W": "" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Paleta simple con un único color base." - }, - "Minute": { - "Minute": "Minuto" - }, - "Mirror Display": { - "Mirror Display": "Pantalla de espejo" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "" - }, - "Modal Background": { - "Modal Background": "Fondo modal" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "" - }, - "Mode": { - "Mode": "Modo" - }, - "Mode:": { - "Mode:": "Modo:" - }, - "Model": { - "Model": "Modelo" - }, - "Modified": { - "Modified": "Modificado" - }, - "Modular widget bar": { - "Modular widget bar": "Barra de widgets modular" - }, - "Monitor": { - "Monitor": "" - }, - "Monitor Configuration": { - "Monitor Configuration": "Configuracion del monitor" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Intervalo de fundido antes de apagar el monitor" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Seleccionar monitor que define los colores dinámicos" - }, - "Monochrome": { - "Monochrome": "" - }, - "Monocle": { - "Monocle": "Monóculo" - }, - "Monospace Font": { - "Monospace Font": "Fuente monoespaciada" - }, - "Month Date": { - "Month Date": "" - }, - "Morning": { - "Morning": "Mañana" - }, - "Mount Points": { - "Mount Points": "Puntos de montaje" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Apariencia del cursor del ratón" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "" - }, - "Move": { - "Move": "" - }, - "Move Widget": { - "Move Widget": "Mover widget" - }, - "Moving to Paused": { - "Moving to Paused": "Pausando" - }, - "Multi-Monitor": { - "Multi-Monitor": "" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "" - }, - "Mute Popups": { - "Mute Popups": "" - }, - "Mute popups for %1": { - "Mute popups for %1": "" - }, - "Muted": { - "Muted": "" - }, - "Muted Apps": { - "Muted Apps": "" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Paleta con tonos suaves y relajantes." - }, - "NM not supported": { - "NM not supported": "No se soporta este NM" - }, - "Name": { - "Name": "Nombre" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Iconos de espacios de trabajo numerados" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "Navegación" - }, - "Network": { - "Network": "Red" - }, - "Network Graph": { - "Network Graph": "Gráfico de red" - }, - "Network Info": { - "Network Info": "Información de red" - }, - "Network Information": { - "Network Information": "Información de red" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Monitor de velocidad de red" - }, - "Network Status": { - "Network Status": "Estado de conexión" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Mostrar velocidad de descarga y subida de la red" - }, - "Neutral": { - "Neutral": "" - }, - "Never": { - "Never": "Nunca" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "Nuevo" - }, - "New Key": { - "New Key": "Nueva tecla" - }, - "New Keybind": { - "New Keybind": "Nuevo atajo" - }, - "New Notification": { - "New Notification": "Nueva notificación" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "" - }, - "Next": { - "Next": "Siguiente" - }, - "Next Transition": { - "Next Transition": "Siguiente transicion" - }, - "Night": { - "Night": "Noche" - }, - "Night Mode": { - "Night Mode": "Modo noche" - }, - "Night Temperature": { - "Night Temperature": "Temperatura nocturna" - }, - "Night mode & gamma": { - "Night mode & gamma": "" - }, - "Niri Integration": { - "Niri Integration": "Integración con Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Anulaciones de diseño Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Acciones del compositor Niri (enfocar,mover, etc.)" - }, - "No": { - "No": "No" - }, - "No Active Players": { - "No Active Players": "Sin reproductores activos" - }, - "No Anim": { - "No Anim": "" - }, - "No Background": { - "No Background": "Sin fondo" - }, - "No Battery": { - "No Battery": "" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "No se encontró un adaptador de Bluetooth" - }, - "No Blur": { - "No Blur": "" - }, - "No Border": { - "No Border": "" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "" - }, - "No Dim": { - "No Dim": "" - }, - "No Focus": { - "No Focus": "" - }, - "No GPU detected": { - "No GPU detected": "No se detecta GPU" - }, - "No GPUs detected": { - "No GPUs detected": "No se detectaron GPUs" - }, - "No History": { - "No History": "" - }, - "No Media": { - "No Media": "Sin medios" - }, - "No Round": { - "No Round": "" - }, - "No Rounding": { - "No Rounding": "" - }, - "No Shadow": { - "No Shadow": "" - }, - "No VPN profiles": { - "No VPN profiles": "Sin perfiles VPN" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "Sin datos climáticos" - }, - "No Weather Data Available": { - "No Weather Data Available": "No hay datos meteorológicos disponibles" - }, - "No action": { - "No action": "Sin accion" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "" - }, - "No adapters": { - "No adapters": "Sin adaptadores" - }, - "No app customizations.": { - "No app customizations.": "" - }, - "No apps found": { - "No apps found": "" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "" - }, - "No battery": { - "No battery": "Sin bateria" - }, - "No brightness devices available": { - "No brightness devices available": "No hay dispositivos de brillo disponibles" - }, - "No changes": { - "No changes": "Sin cambios" - }, - "No checks passed": { - "No checks passed": "" - }, - "No custom theme file": { - "No custom theme file": "Ningún archivo de tema personalizado" - }, - "No devices": { - "No devices": "" - }, - "No devices connected": { - "No devices connected": "No hay dispositivos conectados" - }, - "No devices found": { - "No devices found": "No se encontraron dispositivos" - }, - "No disk data": { - "No disk data": "No hay datos en el disco" - }, - "No disk data available": { - "No disk data available": "No hay datos de disco disponibles" - }, - "No drivers found": { - "No drivers found": "No se encontraron controladores" - }, - "No errors": { - "No errors": "Sin errores" - }, - "No features enabled": { - "No features enabled": "Ninguna función activada" - }, - "No files found": { - "No files found": "Archivos no encontrados" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "" - }, - "No hidden apps.": { - "No hidden apps.": "" - }, - "No info items": { - "No info items": "" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "" - }, - "No input devices found": { - "No input devices found": "" - }, - "No items added yet": { - "No items added yet": "No hay nada añadido todavía" - }, - "No keybinds found": { - "No keybinds found": "No se encontraron atajos" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "" - }, - "No match criteria": { - "No match criteria": "" - }, - "No matches": { - "No matches": "Sin coincidencias" - }, - "No matching processes": { - "No matching processes": "" - }, - "No monitors": { - "No monitors": "" - }, - "No mount points found": { - "No mount points found": "" - }, - "No output device": { - "No output device": "" - }, - "No output devices found": { - "No output devices found": "" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "" - }, - "No plugins found": { - "No plugins found": "No hay complementos encontrados" - }, - "No plugins found.": { - "No plugins found.": "No hay complementos encontrados." - }, - "No printer found": { - "No printer found": "Impresora no encontrada" - }, - "No printers configured": { - "No printers configured": "No hay impresoras configuradas" - }, - "No printers found": { - "No printers found": "No se encontraron impresoras" - }, - "No profiles": { - "No profiles": "" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "" - }, - "No results found": { - "No results found": "" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "No se han encontrado temas" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "No hay temas instalados. Busca temas para instalar en el repositorio/tienda de complementos." - }, - "No trigger": { - "No trigger": "" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "No hay papel pintado seleccionado" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "" - }, - "No warnings": { - "No warnings": "Sin alertas" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "" - }, - "No widgets available": { - "No widgets available": "No hay widgets disponibles" - }, - "No widgets match your search": { - "No widgets match your search": "Ningún widget encaja con tu búsqueda" - }, - "No window rules configured": { - "No window rules configured": "" - }, - "None": { - "None": "Ninguna" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Fuente normal" - }, - "Normal Priority": { - "Normal Priority": "Prioridad normal" - }, - "Not available": { - "Not available": "No disponible" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "No conectado" - }, - "Not detected": { - "Not detected": "No detectado" - }, - "Not paired": { - "Not paired": "" - }, - "Not set": { - "Not set": "" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Nota: esto sólo cambia el porcentaje, no limita realmente la carga." - }, - "Notepad": { - "Notepad": "Notas" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Ajustes del bloc de notas" - }, - "Notepad Slideout": { - "Notepad Slideout": "Bloc de notas" - }, - "Nothing": { - "Nothing": "" - }, - "Nothing to see here": { - "Nothing to see here": "Nada que ver aquí" - }, - "Notification Center": { - "Notification Center": "Centro de notificaciones" - }, - "Notification Display": { - "Notification Display": "" - }, - "Notification Overlay": { - "Notification Overlay": "Superposición de notificaciones" - }, - "Notification Popups": { - "Notification Popups": "Notificaciones emergentes" - }, - "Notification Rules": { - "Notification Rules": "" - }, - "Notification Settings": { - "Notification Settings": "Ajustes de notificaciones" - }, - "Notification Timeouts": { - "Notification Timeouts": "Duración de las notificaciones" - }, - "Notification toast popups": { - "Notification toast popups": "Notificaciones emergentes en pantalla" - }, - "Notifications": { - "Notifications": "Notificaciones" - }, - "Numbers": { - "Numbers": "Números" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "" - }, - "OK": { - "OK": "" - }, - "OS Logo": { - "OS Logo": "OS Logo" - }, - "OSD Position": { - "OSD Position": "Posición OSD" - }, - "Occupied Color": { - "Occupied Color": "" - }, - "Off": { - "Off": "Apagado" - }, - "Office": { - "Office": "Oficina" - }, - "Offline": { - "Offline": "" - }, - "Offline Report": { - "Offline Report": "Reporte sin conexión" - }, - "Older": { - "Older": "Más antiguas" - }, - "On": { - "On": "" - }, - "On-Demand": { - "On-Demand": "" - }, - "On-Screen Displays": { - "On-Screen Displays": "Indicadores en pantalla" - }, - "On-screen Displays": { - "On-screen Displays": "Indicadores en pantalla" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Ajustar gamma en función de la hora o ubicación." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Solo mostrar ventanas del monitor actual en cada dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Solo visible si la hibernación es soportada por tu sistema" - }, - "Opacity": { - "Opacity": "Opacidad" - }, - "Opaque": { - "Opaque": "" - }, - "Open": { - "Open": "Abrir" - }, - "Open App": { - "Open App": "" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "" - }, - "Open Notepad File": { - "Open Notepad File": "Abrir archivo de Notas" - }, - "Open a new note": { - "Open a new note": "" - }, - "Open folder": { - "Open folder": "" - }, - "Open in Browser": { - "Open in Browser": "" - }, - "Open in terminal": { - "Open in terminal": "" - }, - "Open search bar to find text": { - "Open search bar to find text": "Abrir barra de búsqueda para encontrar texto" - }, - "Open with...": { - "Open with...": "Abrir con..." - }, - "Opening SMS": { - "Opening SMS": "" - }, - "Opening SMS app": { - "Opening SMS app": "" - }, - "Opening file browser": { - "Opening file browser": "" - }, - "Opening files": { - "Opening files": "" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "Descripción opcional" - }, - "Optional location": { - "Optional location": "Ubicación opcional" - }, - "Options": { - "Options": "Opciones" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "" - }, - "Original: %1": { - "Original: %1": "" - }, - "Other": { - "Other": "Otro" - }, - "Outline": { - "Outline": "" - }, - "Output": { - "Output": "" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Área de salida casi llena" - }, - "Output Area Full": { - "Output Area Full": "Área de salida llena" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "" - }, - "Output Tray Missing": { - "Output Tray Missing": "Bandeja de salida no encontrada" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Los resultados incluyen" - }, - "Overcast": { - "Overcast": "" - }, - "Overflow": { - "Overflow": "" - }, - "Overridden by config": { - "Overridden by config": "Sobreescrito por la configuracion" - }, - "Override": { - "Override": "Sobrescribir" - }, - "Override Border Size": { - "Override Border Size": "" - }, - "Override Corner Radius": { - "Override Corner Radius": "Anular radio de esquina" - }, - "Override Gaps": { - "Override Gaps": "Anular lagunas" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Anular la configuración de diseño global para esta salida" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "Sobreescribe" - }, - "Overview": { - "Overview": "Resumen" - }, - "Overview of your network connections": { - "Overview of your network connections": "Vista general de conexiones de red" - }, - "Overwrite": { - "Overwrite": "Sobrescribir" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "" - }, - "Pad Hours": { - "Pad Hours": "" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Relleno" - }, - "Pair": { - "Pair": "Emparejar" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Emparejar dispositivo Bluetooth" - }, - "Paired": { - "Paired": "Vinculado" - }, - "Pairing": { - "Pairing": "" - }, - "Pairing failed": { - "Pairing failed": "Emparejamiento fallido" - }, - "Pairing request from": { - "Pairing request from": "" - }, - "Pairing request sent": { - "Pairing request sent": "" - }, - "Pairing requested": { - "Pairing requested": "" - }, - "Pairing...": { - "Pairing...": "Vinculando..." - }, - "Partly Cloudy": { - "Partly Cloudy": "" - }, - "Passkey:": { - "Passkey:": "Clave de acceso:" - }, - "Password": { - "Password": "Contraseña" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "" - }, - "Pause": { - "Pause": "Pausar" - }, - "Paused": { - "Paused": "Pausado" - }, - "Pending": { - "Pending": "Pendiente" - }, - "Pending Charge": { - "Pending Charge": "" - }, - "Pending Discharge": { - "Pending Discharge": "" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Fondos de pantalla según el modo" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Fondos de pantalla según el monitor" - }, - "Per-screen config": { - "Per-screen config": "" - }, - "Percentage": { - "Percentage": "Porcentaje" - }, - "Performance": { - "Performance": "" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Permiso denegado para poner la imagen de perfil." - }, - "Personalization": { - "Personalization": "Personalización" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "" - }, - "Phone number": { - "Phone number": "" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "" - }, - "Pin": { - "Pin": "Fijar" - }, - "Pin to Dock": { - "Pin to Dock": "Fijar al dock" - }, - "Ping": { - "Ping": "" - }, - "Ping sent": { - "Ping sent": "" - }, - "Ping sent to": { - "Ping sent to": "" - }, - "Pinned": { - "Pinned": "Fijado" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "" - }, - "Pixelate": { - "Pixelate": "" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Pon aquí el directorio de complementos. Cada complemento debe tener un archivo plugin.json adjunto." - }, - "Place plugins in %1": { - "Place plugins in %1": "Colocar plugins en %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Reproducir sonido al recibir una nueva notificación" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Reproducir sonido al conectar el cable de alimentación" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Reproducir sonido al ajustar el volumen" - }, - "Play sounds for system events": { - "Play sounds for system events": "Reproducir sonidos para eventos del sistema" - }, - "Playback": { - "Playback": "Reproducción" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "Enchufado" - }, - "Plugged in": { - "Plugged in": "Enchufado" - }, - "Plugin": { - "Plugin": "Complemento" - }, - "Plugin Directory": { - "Plugin Directory": "Directorio de complementos" - }, - "Plugin Management": { - "Plugin Management": "Gestión de complementos" - }, - "Plugin Visibility": { - "Plugin Visibility": "" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Complemento desactivado – actívalo en los ajustes de complementos" - }, - "Plugins": { - "Plugins": "Complementos" - }, - "Pointer": { - "Pointer": "Puntero" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "" - }, - "Popup Only": { - "Popup Only": "" - }, - "Popup Position": { - "Popup Position": "Posición" - }, - "Popup Shadow": { - "Popup Shadow": "" - }, - "Popup Transparency": { - "Popup Transparency": "Transparencia de popups" - }, - "Popup behavior, position": { - "Popup behavior, position": "Comportamiento y posición de las notificaciones emergentes" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "" - }, - "Position": { - "Position": "Posición" - }, - "Position, pinned apps": { - "Position, pinned apps": "Posición de las aplicaciones fijadas" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Posibles conflictos de sobrescritura" - }, - "Power": { - "Power": "Potencia" - }, - "Power & Security": { - "Power & Security": "Energía y seguridad" - }, - "Power & Sleep": { - "Power & Sleep": "Energia y Sueño" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Confirmación de acción" - }, - "Power Menu Customization": { - "Power Menu Customization": "Ajustes del menú de apagado" - }, - "Power Off": { - "Power Off": "Apagar" - }, - "Power Options": { - "Power Options": "Opciones de Energía" - }, - "Power Profile": { - "Power Profile": "Perfil de energia" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Perfil de Energía Degradada" - }, - "Power Saver": { - "Power Saver": "" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Apagar monitores al bloquearse" - }, - "Power profile management available": { - "Power profile management available": "Gestión del perfil de potencia disponible" - }, - "Power source": { - "Power source": "Fuente de energia" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "Precipitaciones" - }, - "Precipitation": { - "Precipitation": "" - }, - "Precipitation Chance": { - "Precipitation Chance": "Probabilidad de lluvia" - }, - "Preference": { - "Preference": "Preferencia" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Anchuras prefijadas (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "" - }, - "Press key...": { - "Press key...": "Presiona la tecla deseada..." - }, - "Pressure": { - "Pressure": "Presión" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Evitar que la pantalla se apague por inactividad" - }, - "Preview": { - "Preview": "" - }, - "Primary": { - "Primary": "Primario" - }, - "Primary Container": { - "Primary Container": "" - }, - "Print Server Management": { - "Print Server Management": "Gestión del servidor de impresión" - }, - "Print Server not available": { - "Print Server not available": "Servidor de impresión no disponible" - }, - "Printer": { - "Printer": "Impresora" - }, - "Printer Classes": { - "Printer Classes": "Clases de impresoras" - }, - "Printer created successfully": { - "Printer created successfully": "Impresora creada con éxito" - }, - "Printer deleted": { - "Printer deleted": "Impresora eliminada" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nombre de impresora (sin espacios)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "Impresoras" - }, - "Printers: ": { - "Printers: ": "Impresoras: " - }, - "Prioritize performance": { - "Prioritize performance": "" - }, - "Priority": { - "Priority": "" - }, - "Privacy Indicator": { - "Privacy Indicator": "Indicador de privacidad" - }, - "Privacy Mode": { - "Privacy Mode": "" - }, - "Private Key Password": { - "Private Key Password": "Clave de acceso privada" - }, - "Process Count": { - "Process Count": "Conteo de procesos" - }, - "Processes": { - "Processes": "Procesos" - }, - "Processes:": { - "Processes:": "Procesos:" - }, - "Processing": { - "Processing": "Procesando" - }, - "Profile Image Error": { - "Profile Image Error": "Error de imagen de perfil" - }, - "Profile activated: %1": { - "Profile activated: %1": "" - }, - "Profile deleted": { - "Profile deleted": "" - }, - "Profile error": { - "Profile error": "" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "La imagen de perfil es muy grande. Por favor usa una más pequeña." - }, - "Profile name": { - "Profile name": "" - }, - "Profile not found": { - "Profile not found": "" - }, - "Profile saved: %1": { - "Profile saved: %1": "" - }, - "Protocol": { - "Protocol": "Protocolo" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Acceso rápido al lanzador de aplicaciones" - }, - "Quick access to color picker": { - "Quick access to color picker": "Acceso rápido al selector de color" - }, - "Quick access to notepad": { - "Quick access to notepad": "Acceso rápido al bloc de notas" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Panel deslizante para apuntar notas rápidas" - }, - "Quick system toggles": { - "Quick system toggles": "Configuración rápida del sistema" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "" - }, - "Rain": { - "Rain": "" - }, - "Rain Chance": { - "Rain Chance": "Lluvia" - }, - "Rainbow": { - "Rainbow": "" - }, - "Random": { - "Random": "" - }, - "Rate": { - "Rate": "Tasa" - }, - "Read:": { - "Read:": "" - }, - "Reason": { - "Reason": "R" - }, - "Reboot": { - "Reboot": "Reiniciar" - }, - "Recent Colors": { - "Recent Colors": "Colores recientes" - }, - "Recently Used Apps": { - "Recently Used Apps": "Aplicaciones usadas recientemente" - }, - "Recommended available": { - "Recommended available": "Recomendación disponible" - }, - "Refresh": { - "Refresh": "Recargar" - }, - "Refresh Weather": { - "Refresh Weather": "Actualizar El Tiempo" - }, - "Regex": { - "Regex": "" - }, - "Reject": { - "Reject": "" - }, - "Reject Jobs": { - "Reject Jobs": "Rechazar trabajos" - }, - "Release": { - "Release": "" - }, - "Reload Plugin": { - "Reload Plugin": "Reiniciar complemento" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "Remover" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Eliminar espacios y bordes cuando las ventanas estan maximizadas" - }, - "Rename": { - "Rename": "" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "" - }, - "Repeat": { - "Repeat": "" - }, - "Replacement": { - "Replacement": "" - }, - "Report": { - "Report": "Reporte" - }, - "Request Pairing": { - "Request Pairing": "" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Requiere mantener pulsado el botón/tecla para confirmar apagar, reiniciar, suspender, hibernar y cerrar sesión" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Requiere la herramienta 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "DMS Requiere %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Requiere un compositor DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Requiere compatibilidad con el modo nocturno" - }, - "Reset": { - "Reset": "Reiniciar" - }, - "Reset Position": { - "Reset Position": "Reiniciar posicion" - }, - "Reset Size": { - "Reset Size": "Reiniciar tamaño" - }, - "Reset to default name": { - "Reset to default name": "" - }, - "Resize Widget": { - "Resize Widget": "Redimensionar Widget" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Resolución y refresco" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Resolución, posición, escala" - }, - "Restart DMS": { - "Restart DMS": "Reiniciar DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Reiniciar DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "" - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Continuar" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Invertir la dirección de desplazamiento" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Invertir la dirección del cambio de espacio de trabajo al desplazarse por la barra" - }, - "Revert": { - "Revert": "Revertir" - }, - "Right": { - "Right": "Derecha" - }, - "Right Center": { - "Right Center": "" - }, - "Right Section": { - "Right Section": "Sección derecha" - }, - "Right Tiling": { - "Right Tiling": "Mosaico derecho" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Haga clic con el botón derecho del ratón y arrástrelo a cualquier parte del widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Haz clic con el botón derecho y arrastra la esquina inferior derecha" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Clic derecho en la barra para cambiar" - }, - "Ring": { - "Ring": "" - }, - "Ringing": { - "Ringing": "" - }, - "Ripple Effects": { - "Ripple Effects": "" - }, - "Root Filesystem": { - "Root Filesystem": "Raíz del sistema de archivos" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Esquinas redondeadas para ventanas" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Esquinas de ventana redondeadas (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Esquinas de ventana redondeadas (decoration.rounding)" - }, - "Rule": { - "Rule": "" - }, - "Rule Name": { - "Rule Name": "" - }, - "Rules (%1)": { - "Rules (%1)": "" - }, - "Run Again": { - "Run Again": "Ejecutar de nuevo" - }, - "Run DMS Templates": { - "Run DMS Templates": "Ejecutar plantillas de DMS" - }, - "Run User Templates": { - "Run User Templates": "Ejecutar plantillas de usuario" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Ejecutar un programa (e.j, firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Ejecutar un comando de shell (e.j, notify-send)" - }, - "Running Apps": { - "Running Apps": "Aplicaciones activas" - }, - "Running Apps Settings": { - "Running Apps Settings": "Ajustes de aplicaciones activas" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "Brillo SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Saturación SDR" - }, - "SMS": { - "SMS": "" - }, - "Save": { - "Save": "Guardar" - }, - "Save Notepad File": { - "Save Notepad File": "Guardar archivo" - }, - "Save QR Code": { - "Save QR Code": "" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Guardar en el historial las notificaciones de prioridad crítica" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Guardar en el historial las notificaciones ignoradas" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Guardar en el historial las notificaciones de prioridad baja" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Guardar en el historial las notificaciones de prioridad normal" - }, - "Save password": { - "Save password": "Guardar contraseña" - }, - "Saved": { - "Saved": "Guardado" - }, - "Saved Configurations": { - "Saved Configurations": "Configuraciones guardadas" - }, - "Saved Note": { - "Saved Note": "" - }, - "Saved item deleted": { - "Saved item deleted": "" - }, - "Saving...": { - "Saving...": "" - }, - "Scale": { - "Scale": "Escala" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Escalar fuentes de la barra independientemente" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Escala todos los tamaños de fuente en todo el shell" - }, - "Scan": { - "Scan": "Escanear" - }, - "Scanning": { - "Scanning": "Escaneando" - }, - "Scanning...": { - "Scanning...": "Escaneando..." - }, - "Science": { - "Science": "Ciencia" - }, - "Score": { - "Score": "" - }, - "Screen Sharing": { - "Screen Sharing": "" - }, - "Screen sharing": { - "Screen sharing": "Compartir pantalla" - }, - "Scroll": { - "Scroll": "" - }, - "Scroll Factor": { - "Scroll Factor": "" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Rueda de desplazamiento" - }, - "Scroll song title": { - "Scroll song title": "Desplazamiento del título de la canción" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Desplazar el título si no cabe en el widget" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Comportamiento de la rueda de desplazamiento en el widget multimedia" - }, - "Scrolling": { - "Scrolling": "Desplazamiento" - }, - "Search App Actions": { - "Search App Actions": "" - }, - "Search Options": { - "Search Options": "" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "" - }, - "Search for a location...": { - "Search for a location...": "Buscar una ubicación..." - }, - "Search keybinds...": { - "Search keybinds...": "Buscar combinaciones de tecla" - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "" - }, - "Search plugins...": { - "Search plugins...": "Buscar complementos..." - }, - "Search processes...": { - "Search processes...": "" - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "Buscar temas..." - }, - "Search widgets...": { - "Search widgets...": "Buscar widgets..." - }, - "Search...": { - "Search...": "Buscar..." - }, - "Searching...": { - "Searching...": "Buscando..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "Secundario" - }, - "Secured": { - "Secured": "Seguro" - }, - "Security": { - "Security": "Seguridad" - }, - "Security & privacy": { - "Security & privacy": "Seguridad y privacidad" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "" - }, - "Select Application": { - "Select Application": "Seleccionar una aplicación" - }, - "Select Bar": { - "Select Bar": "Seleccionar barra" - }, - "Select Custom Theme": { - "Select Custom Theme": "Elegir tema personalizado" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "" - }, - "Select File to Send": { - "Select File to Send": "" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Seleccionar logo del lanzador" - }, - "Select Profile Image": { - "Select Profile Image": "Elegir foto de perfil" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "Seleccionar fondo de pantalla" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Elegir carpeta de fondos de pantalla" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Selecciona un color de la paleta o usa el deslizador" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Selecciona un widget para añadirlo a tu escritorio. Cada widget es una instancia independiente con su propia configuración." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Elija un widget para añadir. Puede añadir varias copias del mismo widget si es necesario." - }, - "Select a window...": { - "Select a window...": "" - }, - "Select an image file...": { - "Select an image file...": "Selecciona un archivo de imagen..." - }, - "Select at least one provider": { - "Select at least one provider": "Seleccione al menos un proveedor" - }, - "Select device": { - "Select device": "" - }, - "Select device...": { - "Select device...": "Elegir dispositivo..." - }, - "Select driver...": { - "Select driver...": "Elegir controlador..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Seleccionar el peso de la fuente para el texto de la interfaz de usuario" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Seleccionar monitor para configurar el fondo de pantalla" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Selecciona la fuente monoespaciada para la lista de procesos y la información técnica" - }, - "Select network": { - "Select network": "" - }, - "Select system sound theme": { - "Select system sound theme": "Seleccionar tema de sonidos del sistema" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Seleccione la familia de fuentes para el texto de la interfaz de usuario" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Selecciona el algoritmo de colores del fondo de pantalla" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Seleccionar transiciones para aplicar de forma aleatoria" - }, - "Select...": { - "Select...": "Seleccionar..." - }, - "Selected image file not found.": { - "Selected image file not found.": "La imagen seleccionada no se encuentra." - }, - "Send": { - "Send": "" - }, - "Send Clipboard": { - "Send Clipboard": "" - }, - "Send File": { - "Send File": "" - }, - "Send SMS": { - "Send SMS": "" - }, - "Sending": { - "Sending": "" - }, - "Separator": { - "Separator": "Separador" - }, - "Server": { - "Server": "Servidor" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "" - }, - "Set custom name": { - "Set custom name": "" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Configurar diferentes fondos de pantalla para cada monitor conectado" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Configurar diferentes fondos de pantalla para los modos claro y oscuro" - }, - "Set key and action to save": { - "Set key and action to save": "Establecer tecla y acción para guardar" - }, - "Set notification rules": { - "Set notification rules": "" - }, - "Settings": { - "Settings": "Ajustes" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Los ajustes son de solo lectura. Los cambios no persistirán." - }, - "Setup": { - "Setup": "Configurar" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "" - }, - "Share Text": { - "Share Text": "" - }, - "Share URL": { - "Share URL": "" - }, - "Shared": { - "Shared": "" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Borrar todo • Esc: Cerrar " - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Mayús+Intro: Pegar - Mayús+Supr: Borrar todo - Esc: Cerrar" - }, - "Short": { - "Short": "Corto" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "Atajos" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Atajos (%1)" - }, - "Show": { - "Show": "" - }, - "Show 3rd Party": { - "Show 3rd Party": "" - }, - "Show All Tags": { - "Show All Tags": "Mostrar todas las etiquetas" - }, - "Show Badge": { - "Show Badge": "" - }, - "Show CPU": { - "Show CPU": "Mostrar CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Mostrar grafico de CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Mostrar temperatura de CPU" - }, - "Show Date": { - "Show Date": "Mostrar fecha" - }, - "Show Disk": { - "Show Disk": "Mostrar disco" - }, - "Show Dock": { - "Show Dock": "Mostrar dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Mostrar sensación térmica" - }, - "Show Footer": { - "Show Footer": "" - }, - "Show Forecast": { - "Show Forecast": "Mostrar pronóstico" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Mostrar temperatura de la GPU" - }, - "Show Header": { - "Show Header": "Mostrar cabecera" - }, - "Show Hibernate": { - "Show Hibernate": "Mostrar Hibernar" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Mostrar números de horas" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Mostrar pronóstico por hora" - }, - "Show Humidity": { - "Show Humidity": "Mostrar humedad" - }, - "Show Launcher Button": { - "Show Launcher Button": "" - }, - "Show Line Numbers": { - "Show Line Numbers": "Mostrar números de líneas" - }, - "Show Location": { - "Show Location": "Mostrar ubicación" - }, - "Show Lock": { - "Show Lock": "Mostrar Bloquear" - }, - "Show Log Out": { - "Show Log Out": "Mostrar Cerrar sesión" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "" - }, - "Show Media Player": { - "Show Media Player": "" - }, - "Show Memory": { - "Show Memory": "Mostrar memoria" - }, - "Show Memory Graph": { - "Show Memory Graph": "Mostrar gráfico de memoria" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "Mostrar red" - }, - "Show Network Graph": { - "Show Network Graph": "Mostrar grafico de la red" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Mostrar solo espacios de trabajo ocupados" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "" - }, - "Show Password Field": { - "Show Password Field": "Mostrar campo de contraseña" - }, - "Show Power Actions": { - "Show Power Actions": "Mostrar acciones de energia" - }, - "Show Power Off": { - "Show Power Off": "Mostrar Apagar" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Mostrar probabilidad de precipitaciones" - }, - "Show Pressure": { - "Show Pressure": "Mostrar presión" - }, - "Show Profile Image": { - "Show Profile Image": "Mostrar imagen de perfil" - }, - "Show Reboot": { - "Show Reboot": "Mostrar Reiniciar" - }, - "Show Restart DMS": { - "Show Restart DMS": "Mostrar Reiniciar DMS" - }, - "Show Saved Items": { - "Show Saved Items": "" - }, - "Show Seconds": { - "Show Seconds": "Mostrar segundos" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Mostrar amanecer/anochecer" - }, - "Show Suspend": { - "Show Suspend": "Mostrar Suspender" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "Mostrar fecha del sistema" - }, - "Show System Icons": { - "Show System Icons": "Mostrar iconos del sistema" - }, - "Show System Time": { - "Show System Time": "Mostrar tiempo del sistema" - }, - "Show Top Processes": { - "Show Top Processes": "Mostrar procesos principales" - }, - "Show Weather Condition": { - "Show Weather Condition": "Mostrar estado del tiempo" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "Mostrar bienvenida" - }, - "Show Wind Speed": { - "Show Wind Speed": "Mostrar velocidad del viento" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Mostrar aplicaciones en el espacio de trabajo" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Mostrar las 9 etiquetas en lugar de solo las ocupadas (solo DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Mostrar visualizador de auido cava en el widget de multimedia" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Oscurecer el fondo al abrir un modal" - }, - "Show device": { - "Show device": "" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Mostrar la superposición del lanzador al escribir en la vista general de Niri. Desactivar para utilizar otro lanzador." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Mostrar en última pantalla" - }, - "Show on Overlay": { - "Show on Overlay": "Mostrar en superposición" - }, - "Show on Overview": { - "Show on Overview": "Mostrar en vista general" - }, - "Show on Overview Only": { - "Show on Overview Only": "" - }, - "Show on all connected displays": { - "Show on all connected displays": "Mostrar en todas las pantallas conectadas" - }, - "Show on screens:": { - "Show on screens:": "Mostrar en pantallas:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Mostrar en pantalla cuando el brillo cambia" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Mostrar en pantalla al activar o desactivar Bloq Mayús" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Mostrar en pantalla al ciclar los dispositivos de salida de audio" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Mostrar en pantalla cuando el estado del inhibidor cambia" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Mostrar en pantalla cuando el volumen multimedia cambia" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Mostrar en pantalla cuando el micrófono se silencia/reactiva" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Mostrar en pantalla cuando el perfil de energía cambia" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Mostrar en pantalla cuando el volumen cambia" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Mostrar clima en la barra superior y en el centro de control" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Indicar el orden de los espacios en la barra superior" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Mostrar el nombre del espacio de trabajo en las barras horizontales y la primera letra en las verticales" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Mostrar todas las ventanas abiertas destacando la enfocada" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Mostrar espacios de trabajo y permitir cambiar entre ellos" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Indica si las mayúsculas están activadas" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Muestra si micrófono, cámara o pantalla están en uso" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Apagar" - }, - "Signal": { - "Signal": "Señal" - }, - "Signal:": { - "Signal:": "Señal:" - }, - "Size": { - "Size": "Tamaño" - }, - "Size Constraints": { - "Size Constraints": "" - }, - "Size Offset": { - "Size Offset": "Tamaño relativo" - }, - "Sizing": { - "Sizing": "Redimensionamiento" - }, - "Skip": { - "Skip": "Pasar" - }, - "Skip confirmation": { - "Skip confirmation": "" - }, - "Skip setup": { - "Skip setup": "" - }, - "Small": { - "Small": "" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Autenticación con tarjeta inteligente" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN de la tarjeta inteligente" - }, - "Snap": { - "Snap": "" - }, - "Snow": { - "Snow": "" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Algunos plugins requieren una version más nueva de DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Ordenar alfabéticamente" - }, - "Sort By": { - "Sort By": "Ordenar por" - }, - "Sorting & Layout": { - "Sorting & Layout": "Clasificación y presentación" - }, - "Sound Theme": { - "Sound Theme": "Tema de sonidos" - }, - "Sounds": { - "Sounds": "Sonidos" - }, - "Space between windows": { - "Space between windows": "Espacio entre ventanas" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Espacio entre ventanas (hueco_in y hueco_ext)" - }, - "Spacer": { - "Spacer": "Espaciador" - }, - "Spacing": { - "Spacing": "Espacio" - }, - "Speaker settings": { - "Speaker settings": "Ajustes del altavoz" - }, - "Speed": { - "Speed": "Velocidad" - }, - "Spool Area Full": { - "Spool Area Full": "Cola de impresión llena" - }, - "Square Corners": { - "Square Corners": "Esquinas cuadradas" - }, - "Stacked": { - "Stacked": "Apilado" - }, - "Standard": { - "Standard": "" - }, - "Start": { - "Start": "Empezar" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Escribe tus notas aquí..." - }, - "State": { - "State": "Estado" - }, - "Status": { - "Status": "Estado" - }, - "Stopped": { - "Stopped": "Detenido" - }, - "Stopped Partly": { - "Stopped Partly": "Detenido parcialmente" - }, - "Stopping": { - "Stopping": "Deteniendo" - }, - "Stretch": { - "Stretch": "" - }, - "Stripes": { - "Stripes": "" - }, - "Summary": { - "Summary": "" - }, - "Sunrise": { - "Sunrise": "Amanecer" - }, - "Sunset": { - "Sunset": "Atardecer" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Suprimir las ventanas emergentes de notificación mientras están activadas" - }, - "Surface": { - "Surface": "Superficie" - }, - "Surface Variant": { - "Surface Variant": "" - }, - "Suspend": { - "Suspend": "Suspender" - }, - "Suspend behavior": { - "Suspend behavior": "Comportamiento de suspensión" - }, - "Suspend system after": { - "Suspend system after": "Suspender sistema después de" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "Cambiar usuario" - }, - "Switch to power profile": { - "Switch to power profile": "Cambiar perfil de energia" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Sincronizar modo con los portales" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Sincronizar el tema oscuro con las preferencias globales del sistema" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "Sistema" - }, - "System App Theming": { - "System App Theming": "Tematización de aplicaciones" - }, - "System Check": { - "System Check": "" - }, - "System Default": { - "System Default": "" - }, - "System Information": { - "System Information": "" - }, - "System Monitor": { - "System Monitor": "Monitor del sistema" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Monitor del sistema no disponible" - }, - "System Sounds": { - "System Sounds": "Sonidos del sistema" - }, - "System Tray": { - "System Tray": "Bandeja del sistema" - }, - "System Update": { - "System Update": "Actualización del sistema" - }, - "System Updater": { - "System Updater": "Actualizador del sistema" - }, - "System Updates": { - "System Updates": "Actualizaciones del sistema" - }, - "System notification area icons": { - "System notification area icons": "Iconos del área de notificaciones del sistema" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "" - }, - "System theme toggle": { - "System theme toggle": "Tema del sistema" - }, - "System toast notifications": { - "System toast notifications": "Notificaciones emergentes del sistema" - }, - "System update custom command": { - "System update custom command": "Comando al actualizar" - }, - "Tab": { - "Tab": "Pestaña" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Seleccionar" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Parametros adicionales" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Forzar modo oscuro en terminales" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "Página de prueba" - }, - "Test page sent to printer": { - "Test page sent to printer": "Página de prueba enviada a la impresora" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "Texto" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "La variable de entorno DMS_SOCKET no está configurada o el socket no está disponible. La gestión automática de complementos requiere DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Los siguientes ajustes modificarán tu configuración de GTK y Qt. Si deseas conservar tu configuración actual, haz una copia de seguridad de los archivos (qt5ct.conf | qt6ct.conf y ~/.config/gtk-3.0 | gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "La cola de impresión está vacía" - }, - "Theme & Colors": { - "Theme & Colors": "Tema y colores" - }, - "Theme Color": { - "Theme Color": "Color del tema" - }, - "Theme Registry": { - "Theme Registry": "" - }, - "Themes": { - "Themes": "Temas" - }, - "Thickness": { - "Thickness": "Espesor" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Aviso sobre complemento externo" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "La combinacion de teclas ha sido sobreescrita por config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Este widget evita que la GPU entre en estados de apagado y puede afectar significativamente la batería en portátiles. No se recomienda usarlo en portátiles con gráficos híbridos." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Esto eliminará permanentemente todo el historial del portapapeles." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "" - }, - "Thunderstorm": { - "Thunderstorm": "" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "" - }, - "Tile": { - "Tile": "" - }, - "Tile H": { - "Tile H": "" - }, - "Tile V": { - "Tile V": "" - }, - "Tiled": { - "Tiled": "" - }, - "Tiled State": { - "Tiled State": "" - }, - "Tiling": { - "Tiling": "Mosaico" - }, - "Time": { - "Time": "" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "Tiempo y clima" - }, - "Time Format": { - "Time Format": "Formato de tiempo" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "Tiempo restante: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Tiempo hasta lleno: %1" - }, - "Timed Out": { - "Timed Out": "Tiempo agotado" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Tiempo de espera para notificaciones de prioridad crítica" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Tiempo limite para las notificaciones de baja prioridad" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Tiempo de espera para notificaciones de prioridad normal" - }, - "Title": { - "Title": "Titulo" - }, - "Title regex (optional)": { - "Title regex (optional)": "" - }, - "To Full": { - "To Full": "Carga completa" - }, - "To update, run the following command:": { - "To update, run the following command:": "Para actualizar, ejecute el siguiente comando:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Para utilizar este bind DMS, elimine o cambie el keybind en su config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Mensajes emergentes" - }, - "Today": { - "Today": "Hoy" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Cambiar visibilidad de la barra" - }, - "Toggling...": { - "Toggling...": "Cambiando..." - }, - "Tomorrow": { - "Tomorrow": "Mañana" - }, - "Tonal Spot": { - "Tonal Spot": "" - }, - "Toner Empty": { - "Toner Empty": "Tóner vacío" - }, - "Toner Low": { - "Toner Low": "Tóner bajo" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "Herrramientas" - }, - "Top": { - "Top": "Arriba" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "Formato en la barra superior" - }, - "Top Center": { - "Top Center": "" - }, - "Top Left": { - "Top Left": "Arriba a la izquierda" - }, - "Top Processes": { - "Top Processes": "Procesos superiores" - }, - "Top Right": { - "Top Right": "Arriba a la derecha" - }, - "Top Section": { - "Top Section": "Sección superior" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "Trabajos totales" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Transformar" - }, - "Transition Effect": { - "Transition Effect": "Efecto de transición" - }, - "Transparency": { - "Transparency": "Transparencia" - }, - "Trending GIFs": { - "Trending GIFs": "" - }, - "Trending Stickers": { - "Trending Stickers": "" - }, - "Trigger": { - "Trigger": "" - }, - "Trigger Prefix": { - "Trigger Prefix": "" - }, - "Trigger: %1": { - "Trigger: %1": "" - }, - "Trust": { - "Trust": "" - }, - "Try a different search": { - "Try a different search": "" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "" - }, - "Turn off monitors after": { - "Turn off monitors after": "Apagar monitores después de" - }, - "Type": { - "Type": "Tipo" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "" - }, - "Type to search files": { - "Type to search files": "" - }, - "Typography": { - "Typography": "Tipografía" - }, - "Typography & Motion": { - "Typography & Motion": "Tipografia y movimiento" - }, - "Unavailable": { - "Unavailable": "No disponible" - }, - "Unfocused Color": { - "Unfocused Color": "" - }, - "Ungrouped": { - "Ungrouped": "" - }, - "Uninstall": { - "Uninstall": "Desinstalar" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Desinstalar complemento" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Desinstalacion fallida: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Desinstalado: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Desinstalando: %1" - }, - "Unknown": { - "Unknown": "Desconocido" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "" - }, - "Unknown Config": { - "Unknown Config": "Configuración desconocida" - }, - "Unknown Device": { - "Unknown Device": "Dispositivo desconocido" - }, - "Unknown GPU": { - "Unknown GPU": "GPU desconocida" - }, - "Unknown Monitor": { - "Unknown Monitor": "Monitor desconocido" - }, - "Unknown Network": { - "Unknown Network": "Red desconocida" - }, - "Unknown Title": { - "Unknown Title": "" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "" - }, - "Unmute": { - "Unmute": "" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "" - }, - "Unnamed Rule": { - "Unnamed Rule": "" - }, - "Unpair": { - "Unpair": "" - }, - "Unpair failed": { - "Unpair failed": "" - }, - "Unpin": { - "Unpin": "" - }, - "Unpin from Dock": { - "Unpin from Dock": "Desfijar del dock" - }, - "Unsaved Changes": { - "Unsaved Changes": "Cambios sin guardar" - }, - "Unsaved changes": { - "Unsaved changes": "Cambios sin guardar" - }, - "Unsaved note...": { - "Unsaved note...": "Nota sin guardar..." - }, - "Untitled": { - "Untitled": "Sin titulo" - }, - "Untrust": { - "Untrust": "" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "" - }, - "Update All": { - "Update All": "Actualizar todo" - }, - "Update Plugin": { - "Update Plugin": "Actualizar complemento" - }, - "Uptime": { - "Uptime": "" - }, - "Uptime:": { - "Uptime:": "" - }, - "Urgent Color": { - "Urgent Color": "Color para urgencia" - }, - "Usage Tips": { - "Usage Tips": "" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Usar formato de 24 horas en lugar de 12 horas AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Usar comando personalizado" - }, - "Use Grid Layout": { - "Use Grid Layout": "Usar diseño en cuadrícula" - }, - "Use IP Location": { - "Use IP Location": "Usar la localización de la IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Usar unidades imperiales" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Usar unidades imperiales (°F, mph, inHg) en lugar de métricas (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Usar fuente monoespaciada" - }, - "Use System Theme": { - "Use System Theme": "Usar tema del sistema" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Usar un gestor de fondos de pantalla externo como swww, hyprpaper, o swaybg" - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Utilizar barras de progreso con efecto de ola para la reproducción de medios" - }, - "Use custom border size": { - "Use custom border size": "Usar un tamaño de borde personalizado" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Utilizar un comando personalizado para actualizar el sistema" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Utilizar espacios personalizados en lugar de espaciado entre barras" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Usar radio de ventana personalizado en lugar del radio del tema" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Usar tema claro en lugar del tema oscuro" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Usar tema de sonidos del sistema" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "" - }, - "User": { - "User": "Usuario" - }, - "Username": { - "Username": "Nombre de usuario" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Usar las horas de amanecer/anochecer para ajustar automáticamente el modo noche basándose en tu localización." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "" - }, - "Utilities": { - "Utilities": "Utilidades" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "Conexiones VPN" - }, - "VPN Password": { - "VPN Password": "Contraseña VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "Configuración VPN actualizada" - }, - "VPN connections": { - "VPN connections": "Conexiones VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN eliminada" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importada: %1" - }, - "VPN not available": { - "VPN not available": "VPN no disponible" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "Estado de VPN y conexión rápida" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR a la carta" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Frecuencia de actualización variable" - }, - "Verification": { - "Verification": "" - }, - "Version": { - "Version": "Versión" - }, - "Vertical Deck": { - "Vertical Deck": "Bandeja vertical" - }, - "Vertical Grid": { - "Vertical Grid": "Cuadricula vertical" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Desplazamiento vertical" - }, - "Vertical Tiling": { - "Vertical Tiling": "Desplazamiento vertical" - }, - "Vibrant": { - "Vibrant": "" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Paleta vibrante y juguetona." - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "" - }, - "View Mode": { - "View Mode": "" - }, - "Visibility": { - "Visibility": "Visibilidad" - }, - "Visual Effects": { - "Visual Effects": "" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Divisor visual entre widgets" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Efecto visual usado al cambiar el fondo de pantalla" - }, - "Volume": { - "Volume": "Volumen" - }, - "Volume Changed": { - "Volume Changed": "Cambio de volumen" - }, - "Volume Slider": { - "Volume Slider": "Deslizador de volumen" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volumen, brillo y otros indicadores en pantalla" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Fondo de pantalla" - }, - "Wallpaper Error": { - "Wallpaper Error": "Error en el fondo de pantalla" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Monitor de fondo de pantalla" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Fallo en el procesamiento del fondo de pantalla" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Fallo en el procesamiento del fondo de pantalla - compruebe la ruta del fondo de pantalla" - }, - "Wallpapers": { - "Wallpapers": "Fondos de pantalla" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Temperatura de color cálida para aplicar" - }, - "Warning": { - "Warning": "Advertencia" - }, - "Warnings": { - "Warnings": "Alertas" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Barras de progreso en forma de onda" - }, - "Weather": { - "Weather": "Clima" - }, - "Weather Widget": { - "Weather Widget": "Clima" - }, - "Welcome": { - "Welcome": "Bienvenido" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Al activarse, las aplicaciones se ordenan alfabéticamente. Al desactivarse, se ordenan por frecuencia de uso." - }, - "When locked": { - "When locked": "" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Si se utiliza el widget actualizador, ocultarlo si no se encuentra ninguna actualización" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Contraseña Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Conexión Wi-Fi y Eternet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi no disponible" - }, - "WiFi": { - "WiFi": "Wi-Fi" - }, - "WiFi Device": { - "WiFi Device": "Dispositivo Wi-Fi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "" - }, - "WiFi disabled": { - "WiFi disabled": "Wi‑Fi desactivado" - }, - "WiFi enabled": { - "WiFi enabled": "Wi-Fi habilitado" - }, - "WiFi is off": { - "WiFi is off": "Wi‑Fi apagado" - }, - "WiFi off": { - "WiFi off": "" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Ancho (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Color de fondo del Widget" - }, - "Widget Management": { - "Widget Management": "Gestión de widgets" - }, - "Widget Outline": { - "Widget Outline": "Contorno en widgets" - }, - "Widget Style": { - "Widget Style": "Estilo de Widget" - }, - "Widget Styling": { - "Widget Styling": "Estilo de widgets" - }, - "Widget Transparency": { - "Widget Transparency": "Transparencia de widget" - }, - "Widget added": { - "Widget added": "Widget añadido" - }, - "Widget removed": { - "Widget removed": "Widget eliminado" - }, - "Widgets": { - "Widgets": "Widgets" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "" - }, - "Width": { - "Width": "" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "" - }, - "Wind": { - "Wind": "Viento" - }, - "Wind Speed": { - "Wind Speed": "Velocidad del viento" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "" - }, - "Window Corner Radius": { - "Window Corner Radius": "Radio de la esquina de la ventana" - }, - "Window Gaps": { - "Window Gaps": "Separacion de ventana" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Separacion de ventanas (px)" - }, - "Window Height": { - "Window Height": "" - }, - "Window Opening": { - "Window Opening": "" - }, - "Window Rounding": { - "Window Rounding": "" - }, - "Window Rules": { - "Window Rules": "" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "" - }, - "Wipe": { - "Wipe": "" - }, - "Workspace": { - "Workspace": "Espacio de trabajo" - }, - "Workspace Appearance": { - "Workspace Appearance": "" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Espacios de trabajo numerados" - }, - "Workspace Names": { - "Workspace Names": "Nombres de los espacios de trabajo" - }, - "Workspace Padding": { - "Workspace Padding": "Margen de los espacios de trabajo" - }, - "Workspace Settings": { - "Workspace Settings": "Ajustes de espacios de trabajo" - }, - "Workspace Switcher": { - "Workspace Switcher": "Espacios de trabajo" - }, - "Workspace name": { - "Workspace name": "" - }, - "Workspaces": { - "Workspaces": "Espacios de trabajo" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Espacios de trabajo y Widgets" - }, - "Write:": { - "Write:": "" - }, - "X Axis": { - "X Axis": "Eje X" - }, - "Y Axis": { - "Y Axis": "Eje Y" - }, - "Yes": { - "Yes": "Si" - }, - "Yesterday": { - "Yesterday": "Ayer" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Tienes cambios sin guardar. ¿Guardar antes de cerrar esta pestaña?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Tienes cambios sin guardar. ¿Guardar antes de continuar?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Tienes cambios sin guardar. ¿Guardar antes de crear un archivo nuevo?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Tienes cambios sin guardar. ¿Guardar antes de abrir otro archivo?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "" - }, - "You're All Set!": { - "You're All Set!": "" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "" - }, - "by %1": { - "by %1": "por %1" - }, - "days": { - "days": "dias" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "dispositivo" - }, - "devices connected": { - "devices connected": "dispositivos conectados" - }, - "dgop not available": { - "dgop not available": "dgop no disponible" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "La configuración dms/outputs existe pero no está incluida en la configuración del compositor. Los cambios de visualización no persistirán." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "e.j. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "por ejemplo, focus-workspace 3, redimensionar-columna -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "e.j., notify-send 'Hola' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "eventos" - }, - "ext": { - "ext": "" - }, - "featured": { - "featured": "" - }, - "leave empty for default": { - "leave empty for default": "deja vacio para valor por defecto" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl no disponible - integración requiere conexión al socket DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matguen no encontrado - instala el paquete matugen para la tematización dinámica" - }, - "minutes": { - "minutes": "minutos" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "ahora" - }, - "official": { - "official": "oficial" - }, - "on Hyprland": { - "on Hyprland": "" - }, - "on MangoWC": { - "on MangoWC": "" - }, - "on Miracle WM": { - "on Miracle WM": "" - }, - "on Niri": { - "on Niri": "" - }, - "on Scroll": { - "on Scroll": "" - }, - "on Sway": { - "on Sway": "" - }, - "open": { - "open": "" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "segundos" - }, - "source": { - "source": "fuente" - }, - "this app": { - "this app": "" - }, - "up": { - "up": "" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "Actualizar dms para integración con NM." - }, - "v%1 by %2": { - "v%1 by %2": "" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype no disponible - instala wtype para soporte de pegado" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Instalar solo desde fuentes confiables" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "M - Mes (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "MM - Mes (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "MMM - Mes (Ene)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "MMMM - Mes (Enero)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Los complementos pueden tener fallos o riesgos de seguridad" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Revisa el código antes de instalar cuando sea posible" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "d - Día (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "dd - Día (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "ddd - Nombre del día (Lun)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "dddd - Nombre del día (Lunes)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "yy - Año (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "yyyy - Año (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fa.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fa.json deleted file mode 100644 index 86c389e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fa.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "سرعت انیمیشن %1" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 حرف" - }, - "%1 connected": { - "%1 connected": "%1 متصل" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "مدت زمان سفارشی انیمیشن %1" - }, - "%1 disconnected": { - "%1 disconnected": "%1 غیرمتصل" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 غیرمتصل (پنهان)" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 وجود دارد اما در فایل پیکربندی شامل نشده است. نگاشت‌کلیدهای سفارشی تا زمانی که این مشکل برطرف نشده باشد کار نخواهند کرد." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 وجود دارد اما وارد نشده است. قواعد پنجره اعمال نخواهند شد." - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "اکنون %1 وارد پیکربندی شد" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "%1 اعلان" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 نوع" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 ابزارک" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "%1 دقیقه پیش" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "(پیش‌فرض)" - }, - "(Unnamed)": { - "(Unnamed)": "(بدون نام)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 بیشتر" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "۰ = گوشه‌های مربعی" - }, - "1 day": { - "1 day": "۱ روز" - }, - "1 device connected": { - "1 device connected": "1 دستگاه متصل" - }, - "1 event": { - "1 event": "۱ رویداد" - }, - "1 hour": { - "1 hour": "۱ ساعت" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "۱ ساعت و نیم" - }, - "1 minute": { - "1 minute": "۱ دقیقه" - }, - "1 notification": { - "1 notification": "1 اعلان" - }, - "1 second": { - "1 second": "۱ ثانیه" - }, - "10 minutes": { - "10 minutes": "۱۰ دقیقه" - }, - "10 seconds": { - "10 seconds": "۱۰ ثانیه" - }, - "10-bit Color": { - "10-bit Color": "رنگ ۱۰ بیتی" - }, - "12 hours": { - "12 hours": "۱۲ ساعت" - }, - "14 days": { - "14 days": "۱۴ روز" - }, - "15 minutes": { - "15 minutes": "۱۵ دقیقه" - }, - "15 seconds": { - "15 seconds": "۱۵ ثانیه" - }, - "180°": { - "180°": "۱۸۰°" - }, - "2 hours": { - "2 hours": "۲ ساعت" - }, - "2 minutes": { - "2 minutes": "۲ دقیقه" - }, - "2 seconds": { - "2 seconds": "۲ ثانیه" - }, - "20 minutes": { - "20 minutes": "۲۰ دقیقه" - }, - "20 seconds": { - "20 seconds": "۲۰ ثانیه" - }, - "24-Hour Format": { - "24-Hour Format": "قالب ۲۴ ساعته" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "قالب ۲۴ ساعته" - }, - "25 seconds": { - "25 seconds": "۲۵ ثانیه" - }, - "250 ms": { - "250 ms": "۲۵۰ ms" - }, - "270°": { - "270°": "۲۷۰°" - }, - "3 days": { - "3 days": "۳ روز" - }, - "3 hours": { - "3 hours": "۳ ساعت" - }, - "3 minutes": { - "3 minutes": "۳ دقیقه" - }, - "3 seconds": { - "3 seconds": "۳ ثانیه" - }, - "30 days": { - "30 days": "۳۰ روز" - }, - "30 minutes": { - "30 minutes": "۳۰ دقیقه" - }, - "30 seconds": { - "30 seconds": "۳۰ ثانیه" - }, - "35 seconds": { - "35 seconds": "۳۵ ثانیه" - }, - "3rd party": { - "3rd party": "شخص ثالث" - }, - "4 hours": { - "4 hours": "۴ ساعت" - }, - "4 seconds": { - "4 seconds": "۴ ثانیه" - }, - "40 seconds": { - "40 seconds": "۴۰ ثانیه" - }, - "45 seconds": { - "45 seconds": "۴۵ ثانیه" - }, - "5 minutes": { - "5 minutes": "‍۵ دقیقه" - }, - "5 seconds": { - "5 seconds": "۵ ثانیه" - }, - "50 seconds": { - "50 seconds": "۵۰ ثانیه" - }, - "500 ms": { - "500 ms": "۵۰۰ ms" - }, - "55 seconds": { - "55 seconds": "۵۵ ثانیه" - }, - "6 hours": { - "6 hours": "۶ ساعت" - }, - "7 days": { - "7 days": "۷ روز" - }, - "750 ms": { - "750 ms": "۷۵۰ ms" - }, - "8 hours": { - "8 hours": "۸ ساعت" - }, - "8 seconds": { - "8 seconds": "۸ ثانیه" - }, - "90 days": { - "90 days": "۹۰ روز" - }, - "90°": { - "90°": "۹۰°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "فایلی با این نام از قبل وجود دارد. آیا می‌خواهید آن را بازنویسی کنید؟" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "یک پوسته دسکتاپ مدرن برای کامپازیتورهای وِیلند" - }, - "AC Power": { - "AC Power": "برق AC" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "لغو شد" - }, - "About": { - "About": "درباره" - }, - "Accent Color": { - "Accent Color": "رنگ تأکیدی" - }, - "Accept": { - "Accept": "پذیرفتن" - }, - "Accept Jobs": { - "Accept Jobs": "پذیرش کار‌های چاپ" - }, - "Accepting": { - "Accepting": "پذیرش" - }, - "Access clipboard history": { - "Access clipboard history": "دسترسی به تاریخچه کلیپ‌بورد" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "دسترسی به اعلان‌ها و مزاحم نشوید" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "دسترسی به کنترل‌ها و تنظیمات سیستم" - }, - "Action": { - "Action": "اقدام" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "اقدام‌ها" - }, - "Activate": { - "Activate": "فعال‌سازی" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "فعال‌سازی" - }, - "Active": { - "Active": "فعال" - }, - "Active Color": { - "Active Color": "رنگ فعال" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "مانیتور فعال صفحه قفل" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "رنگ کاشی پس‌زمینه فعال و آیکون" - }, - "Active: %1": { - "Active: %1": "فعال: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "فعال: %1 + %2" - }, - "Active: None": { - "Active: None": "فعال: هیچکدام" - }, - "Adapters": { - "Adapters": "آداپتور‌ها" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "افزودن" - }, - "Add Bar": { - "Add Bar": "افزودن نوار" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "افزودن ابزارک دسکتاپ" - }, - "Add Printer": { - "Add Printer": "افزودن چاپگر" - }, - "Add Title": { - "Add Title": "افزودن عنوان" - }, - "Add Widget": { - "Add Widget": "افزودن ابزارک" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "افزودن ابزارک به بخش %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "افزودن یک حاشیه دور داک" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "یک پیشوند سفارشی به تمام برنامه‌های در حال اجرا اضافه کنید. این می‌تواند برای مواردی مانند «uwsm-app»، «systemd-run» یا سایر بسته‌بندی دستور‌ها استفاده شود." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "افزودن و پیکربندی ابزارک‌هایی که در دسکتاپ شما نمایان می‌شوند" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "تعداد ستون‌ها در حالت نمای جدولی را تنظیم کنید." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "تنظیم حجم صدا به‌ازای هر پله اسکرول" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "پیشرفته" - }, - "Afternoon": { - "Afternoon": "بعد از ظهر" - }, - "All": { - "All": "همه" - }, - "All Monitors": { - "All Monitors": "همه مانیتورها" - }, - "All checks passed": { - "All checks passed": "همه بررسی‌ها با موفقیت انجام شد" - }, - "All day": { - "All day": "کل روز" - }, - "All displays": { - "All displays": "همه نمایشگر‌ها" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "اجازه بده کلیک ها از ابزارک عبور کنند" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: بازگشت • F1/I: اطلاعات فایل • F10: راهنما • Esc: بستن" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "همیشه فعال" - }, - "Always Show Percentage": { - "Always Show Percentage": "همیشه درصد را نشان بده" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "همیشه داک را پنهان کن و هنگام نزدیک شدن اشاره‌گر موس به منطقه داک آن را نمایش بده" - }, - "Always on icons": { - "Always on icons": "آیکون‌ها همیشه فعال" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "همیشه حداقل ۳ محیط‌کار را نمایش بده، حتی اگر کمتر موجود بود" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "همیشه هنگامی که نمای کلی نیری باز است داک را نشان بده" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "همیشه وقتی فقط یک نمایشگر متصل وجود دارد، نشان بده" - }, - "Amount": { - "Amount": "مقدار" - }, - "Analog": { - "Analog": "آنالوگ" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "نمایش ساعت آنالوگ، دیجیتال یا انباشته" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "در حال تحلیل پیکربندی..." - }, - "Animation Duration": { - "Animation Duration": "مدت زمان انیمیشن" - }, - "Animation Speed": { - "Animation Speed": "سرعت انیمیشن" - }, - "Anonymous Identity": { - "Anonymous Identity": "هویت ناشناس" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "هویت ناشناس (اختیاری)" - }, - "App Customizations": { - "App Customizations": "سفارشی‌سازی برنامه" - }, - "App ID Substitutions": { - "App ID Substitutions": "جایگزینی شناسه برنامه‌ها" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "رجکس شناسه برنامه (مانند ^firefox$)" - }, - "App Launcher": { - "App Launcher": "لانچر برنامه" - }, - "App Names": { - "App Names": "نام برنامه‌ها" - }, - "App Theming": { - "App Theming": "تم برنامه" - }, - "Appearance": { - "Appearance": "نمای ظاهری" - }, - "Application Dock": { - "Application Dock": "داک برنامه" - }, - "Applications": { - "Applications": "برنامه‌ها" - }, - "Apply Changes": { - "Apply Changes": "اعمال تغییرات" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "اعمال رنگ‌های GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "اعمال رنگ‌های Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "برای کاهش خستگی چشم دمای رنگ گرم را اعمال کن. از تنظیمات خودکارسازی پایین برای زمان فعال شدن آن استفاده کنید." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "برنامه‌ها" - }, - "Apps Dock": { - "Apps Dock": "داک برنامه‌ها" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "تنظیمات داک برنامه‌ها" - }, - "Apps Icon": { - "Apps Icon": "آیکون برنامه‌ها" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "برنامه‌ها بر اساس دفعات استفاده، سپس آخرین استفاده و در نهایت بر اساس حروف الفبا مرتب شده‌اند." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "برنامه‌ها با نام نمایشی، آیکون و گزینه‌های اجرای سفارشی. روی یک برنامه راست‌کلیک کرده و «ویرایش برنامه» را برای سفارشی‌سازی انتخاب کنید." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "برنامه‌هایی که پاپ‌آپ اعلان آن‌ها بی‌صدا شده است. برای حذف، بی‌صدا را بردارید یا برنامه را حذف کنید." - }, - "Architecture": { - "Architecture": "معماری" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "چیدمان نمایشگرها و پیکربندی وضوح، نرخ تازه‌سازی و VRR" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "صدا" - }, - "Audio Codec": { - "Audio Codec": "کدک صوتی" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "انتخاب کدک صوتی" - }, - "Audio Devices": { - "Audio Devices": "دستگاه‌های صوتی" - }, - "Audio Input": { - "Audio Input": "ورودی صوتی" - }, - "Audio Output": { - "Audio Output": "خروجی صوتی" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "دستگاه‌های خروجی صوتی (" - }, - "Audio Output Switch": { - "Audio Output Switch": "تغییر خروجی صوتی" - }, - "Audio Visualizer": { - "Audio Visualizer": "مصورساز صوتی" - }, - "Audio system restarted": { - "Audio system restarted": "سیستم صوتی راه‌اندازی مجدد شد" - }, - "Audio volume control": { - "Audio volume control": "کنترل حجم صدا" - }, - "Auth": { - "Auth": "احراز هویت" - }, - "Auth Type": { - "Auth Type": "نوع احراز هویت" - }, - "Authenticate": { - "Authenticate": "احراز هویت" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "احراز هویت" - }, - "Authentication Required": { - "Authentication Required": "احراز هویت نیاز است" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "احراز هویت ناموفق بود، لطفا دوباره تلاش کنید" - }, - "Authorize": { - "Authorize": "اجازه دادن" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "اجازه جفت‌سازی با " - }, - "Authorize service for ": { - "Authorize service for ": "اجازه سرویس برای " - }, - "Auto": { - "Auto": "خودکار" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "خودکار (عریض)" - }, - "Auto Location": { - "Auto Location": "موقعیت مکانی خودکار" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "فاصله پاپ‌آپ خودکار" - }, - "Auto-Clear After": { - "Auto-Clear After": "پاک‌کردن خودکار پس از" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "وقفه پنهان خودکار" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "هنگام اجرای برنامه‌ها نمای کلی نیری را خودکار ببند." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "اعلان‌های قدیمی تر از این را خودکار حذف کن" - }, - "Auto-hide": { - "Auto-hide": "پنهان خودکار" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "پنهان خودکار داک" - }, - "Auto-saving...": { - "Auto-saving...": "درحال ذخیره خودکار..." - }, - "Autoconnect": { - "Autoconnect": "اتصال خودکار" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "اتصال خودکار غیرفعال" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "اتصال خودکار فعال" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "حالت رنگ خودکار" - }, - "Automatic Control": { - "Automatic Control": "کنترل خودکار" - }, - "Automatic Cycling": { - "Automatic Cycling": "تغییر خودکار" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "تصاویر پس‌زمینه را در همان پوشه به صورت خودکار تغییر بده" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "مدخل‌های قدیمی‌تر از این را به صورت خودکار پاک کن" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "تشخیص خودکار موقعیت مکانی بر اساس آدرس IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "تشخیص خودکار موقعیت مکانی بر اساس آدرس IP شما" - }, - "Automatically lock after": { - "Automatically lock after": "قفل خودکار پس از" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "به طور خودکار صفحه را هنگامی که DMS شروع می‌شود قفل کن" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "صفحه را هنگام آماده‌شدن سیستم برای تعلیق به صورت خودکار قفل کن" - }, - "Automation": { - "Automation": "خودکار‌سازی" - }, - "Available": { - "Available": "در دسترس" - }, - "Available Layouts": { - "Available Layouts": "چیدمان‌های موجود" - }, - "Available Networks": { - "Available Networks": "شبکه‌های در دسترس" - }, - "Available Plugins": { - "Available Plugins": "افزونه‌های در دسترس" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "نمایشگر‌های در دسترس (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "در حالت‌های نمایش با جزئیات و پیش‌بینی در دسترس است" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "بازگشت" - }, - "Backend": { - "Backend": "بک‌اند" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "شفافیت پس‌زمینه" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "تصویر پس‌زمینه" - }, - "Backlight device": { - "Backlight device": "دستگاه نور پس‌زمینه" - }, - "Balance power and performance": { - "Balance power and performance": "تعادل انرژی و کارایی" - }, - "Balanced": { - "Balanced": "متعادل" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "پالت رنگی متعادل با رنگ تأکیدی متمرکز (پیش‌فرض)." - }, - "Bar Configurations": { - "Bar Configurations": "پیکربندی نوار" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "شفافیت نوار" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "مدت زمان پایه برای انیمیشن‌ها (برای استفاده سفارشی بکشید)" - }, - "Battery": { - "Battery": "باتری" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "محدودیت شارژ باتری" - }, - "Battery and power management": { - "Battery and power management": "مدیریت باتری و پاور" - }, - "Battery level and power management": { - "Battery level and power management": "وضعیت باتری و مدیریت انرژی" - }, - "Behavior": { - "Behavior": "رفتار" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "صفحه قفل را از loginctl به سیگنال dbus متصل کن. در صورت استفاده از یک صفحه قفل خارجی غیر فعال کنید" - }, - "Binds Include Missing": { - "Binds Include Missing": "Include نگاشت‌ها یافت نشد" - }, - "Binds include added": { - "Binds include added": "Include نگاشت‌ها اضافه شد" - }, - "Bit Depth": { - "Bit Depth": "عمق بیت" - }, - "Block Out": { - "Block Out": "مسدود کردن خروج" - }, - "Block Out From": { - "Block Out From": "مسدود کردن خروج از" - }, - "Block notifications": { - "Block notifications": "مسدود‌کردن اعلان‌ها" - }, - "Blocked": { - "Blocked": "مسدود شده" - }, - "Blue light filter": { - "Blue light filter": "فیلتر نور آبی" - }, - "Bluetooth": { - "Bluetooth": "بلوتوث" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "تنظیمات بلوتوث" - }, - "Bluetooth not available": { - "Bluetooth not available": "بلوتوث در دسترس نیست" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "مات‌کردن لایه تصویر پس‌زمینه" - }, - "Blur on Overview": { - "Blur on Overview": "لایه مات در نمای کلی" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "هنگامی که نمای کلی niri باز است تصویر پس‌زمینه را مات کن" - }, - "Body": { - "Body": "بدنه" - }, - "Border": { - "Border": "حاشیه" - }, - "Border Color": { - "Border Color": "رنگ حاشیه" - }, - "Border Opacity": { - "Border Opacity": "شفافیت حاشیه" - }, - "Border Size": { - "Border Size": "اندازه حاشیه" - }, - "Border Thickness": { - "Border Thickness": "ضخامت حاشیه" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "حاشیه با پس‌زمینه" - }, - "Bottom": { - "Bottom": "پایین" - }, - "Bottom Center": { - "Bottom Center": "پایین وسط" - }, - "Bottom Left": { - "Bottom Left": "پایین چپ" - }, - "Bottom Right": { - "Bottom Right": "پایین راست" - }, - "Bottom Section": { - "Bottom Section": "بخش پایین" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "داک پایین برای برنامه‌های درحال اجرا یا سنجاق شده" - }, - "Brightness": { - "Brightness": "روشنایی" - }, - "Brightness Slider": { - "Brightness Slider": "اسلایدر روشنایی" - }, - "Brightness Value": { - "Brightness Value": "مقدار روشنایی" - }, - "Brightness control not available": { - "Brightness control not available": "کنترل روشنایی در دسترس نیست" - }, - "Browse": { - "Browse": "مرور" - }, - "Browse Files": { - "Browse Files": "مرور فایل‌ها" - }, - "Browse Plugins": { - "Browse Plugins": "مرور افزونه‌ها" - }, - "Browse Themes": { - "Browse Themes": "مرور تم‌ها" - }, - "Browse or search plugins": { - "Browse or search plugins": "مرور یا جستجوی افزونه‌ها" - }, - "Button Color": { - "Button Color": "رنگ دکمه‌" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "نمودار CPU" - }, - "CPU Temperature": { - "CPU Temperature": "دمای CPU" - }, - "CPU Usage": { - "CPU Usage": "میزان مصرف CPU" - }, - "CPU temperature display": { - "CPU temperature display": "نمایش دمای CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "نشانگر میزان مصرف CPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "نظارت بر CPU، حافظه، شبکه و دیسک" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "اخطار فیلتر ناایمن CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "اخطار نبود فیلتر CUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "سرور چاپ CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS در دسترس نیست" - }, - "Camera": { - "Camera": "دوربین" - }, - "Cancel": { - "Cancel": "لغو" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "تمام کار‌ها برای «%1» لغو شود؟" - }, - "Canceled": { - "Canceled": "لغو شد" - }, - "Cannot pair": { - "Cannot pair": "جفت‌سازی امکان‌پذیر نیست" - }, - "Capabilities": { - "Capabilities": "قابلیت‌ها" - }, - "Capacity": { - "Capacity": "ظرفیت" - }, - "Caps Lock": { - "Caps Lock": "قفل حروف بزرگ" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "نشانگر Caps Lock" - }, - "Caps Lock is on": { - "Caps Lock is on": "قفل حروف بزرگ روشن است" - }, - "Center Section": { - "Center Section": "بخش مرکزی" - }, - "Center Single Column": { - "Center Single Column": "تک ستون مرکزی" - }, - "Center Tiling": { - "Center Tiling": "تایلینگ مرکزی" - }, - "Certificate Password": { - "Certificate Password": "گذرواژه گواهی" - }, - "Change Song": { - "Change Song": "تغییر آهنگ" - }, - "Change Volume": { - "Change Volume": "تغییر حجم صدا" - }, - "Change bar appearance": { - "Change bar appearance": "نمای ظاهری نوار را تغییر بده" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "کانال" - }, - "Charging": { - "Charging": "درحال شارژ" - }, - "Check for system updates": { - "Check for system updates": "بررسی برای بروزرسانی‌های سیستم" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "انتخاب رنگ" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "انتخاب رنگ حالت تاریک" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "رنگ لوگوی لانجر دَنک را انتخاب کنید" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "انتخاب رنگ لوگوی لانچر" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "انتخاب رنگ حالت روشن" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "انتخاب رنگ تصویر پس‌زمینه" - }, - "Choose a color": { - "Choose a color": "یک رنگ انتخاب کنید" - }, - "Choose colors from palette": { - "Choose colors from palette": "انتخاب رنگ‌ها از پالت رنگی" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "انتخاب کنید که ابزارک آب و هوا چگونه نمایش داده شود" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "انتخاب آیکون" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "رنگ پس‌زمینه برای ابزارک‌ها انتخاب کنید" - }, - "Choose the border accent color": { - "Choose the border accent color": "انتخاب رنگ تأکیدی حاشیه" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "لوگوی نمایش‌داده شده بر دکمه‌ی لانچر در نوار دَنک را انتخاب کنید" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "انتخاب کنید پاپ‌آپ اعلان کجای صفحه ظاهر شود" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "انتخاب کنید که کدام نمایشگر‌های بر صفحه نمایان شوند" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "انتخاب کنید که کدام نمایشگر‌ها این ابزارک را نشان دهند" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "انتخاب کنید که کدام مانیتور رابط صفحه قفل را نشان دهد. مانیتورهای دیگر برای محافظت در برابر سوختگی OLED، رنگ ثابتی را نمایش می‌دهند." - }, - "Chroma Style": { - "Chroma Style": "استایل رنگی" - }, - "Cipher": { - "Cipher": "رمزگذار" - }, - "Circle": { - "Circle": "دایره" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "رجکس کلاس (مانند ^firefox$)" - }, - "Clear": { - "Clear": "پاک‌کردن" - }, - "Clear All": { - "Clear All": "پاک‌کردن همه" - }, - "Clear All Jobs": { - "Clear All Jobs": "پاک‌کردن همه کار‌های چاپ" - }, - "Clear History?": { - "Clear History?": "تاریخچه پاک شود؟" - }, - "Clear Sky": { - "Clear Sky": "آسمان پاک" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "هنگام راه‌اندازی سرور تمام تاریخچه را پاک کن" - }, - "Clear at Startup": { - "Clear at Startup": "پاک‌کردن در هنگام راه‌اندازی" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "برای ایجاد %1 و افزودن include به پیکربندی، روی «راه‌اندازی» کلیک کنید." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "برای ایجاد %1 و افزودن include به پیکربندی کامپازیتور خود، روی «راه‌اندازی» کلیک کنید." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "برای ایجاد پیکربندی اشاره‌گر موس و افزودن include به پیکربندی کامپازیتور خود، روی «راه‌اندازی» کلیک کنید." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "برای ایجاد پیکربندی خروجی‌ها و افزودن include به پیکربندی کامپازیتور خود، روی «راه‌اندازی» کلیک کنید." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "برای افزودن یک فایل .conf یا .ovpn روی وارد کردن کلیک کنید" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "رد شدن کلیک" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "برای ویرایش، روی هر میانبری کلیک کنید. تغییرات در %1 ذخیره می‌شوند" - }, - "Click to capture": { - "Click to capture": "برای ضبط کلیک کنید" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "برای انتخاب یک فایل JSON قالب سفارشی کلیک کنید" - }, - "Clip": { - "Clip": "برش" - }, - "Clip to Geometry": { - "Clip to Geometry": "برش براساس ابعاد" - }, - "Clipboard": { - "Clipboard": "کلیپ‌بورد" - }, - "Clipboard History": { - "Clipboard History": "تاریخچه کلیپ‌بورد" - }, - "Clipboard Manager": { - "Clipboard Manager": "مدیریت کلیپ‌بورد" - }, - "Clipboard sent": { - "Clipboard sent": "کلیپ‌بورد ارسال شد" - }, - "Clipboard service not available": { - "Clipboard service not available": "سرویس کلیپ‌بورد در دسترس نیست" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "کلیپ‌بورد کار می‌کند اما چیزی در دیسک ذخیره نمی‌شود" - }, - "Clock": { - "Clock": "ساعت" - }, - "Clock Style": { - "Clock Style": "استایل ساعت" - }, - "Close": { - "Close": "بستن" - }, - "Close All Windows": { - "Close All Windows": "بستن همه پنجره‌ها" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "بستن نمای کلی هنگام اجرا" - }, - "Close Window": { - "Close Window": "بستن پنجره" - }, - "Color": { - "Color": "رنگ" - }, - "Color Gamut": { - "Color Gamut": "طیف رنگ" - }, - "Color Management": { - "Color Management": "مدیریت رنگ" - }, - "Color Mode": { - "Color Mode": "حالت رنگ" - }, - "Color Override": { - "Color Override": "رنگ جایگزین" - }, - "Color Picker": { - "Color Picker": "انتخابگر رنگ" - }, - "Color Temperature": { - "Color Temperature": "دمای رنگ" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "رنگ نمایش داده شده در مانیتورهای بدون صفحه قفل" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "رنگ برای دکمه‌‌های عمل اصلی" - }, - "Color temperature for day time": { - "Color temperature for day time": "دمای رنگ برای زمان روز" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "دمای رنگ برای حالت شب" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "تم رنگی برای برجسته‌سازی کد." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "تم رنگی برای برجسته‌سازی کد. %1 تم دردسترس است." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "رنگ تم از مخزن DMS" - }, - "Colorful": { - "Colorful": "رنگارنگ" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "ترکیب رنگارنگ از رنگ‌های تأکیدی متضاد." - }, - "Colorize Active": { - "Colorize Active": "رنگ‌آمیزی حالت فعال" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "رنگ‌ها از تصویر پس‌زمینه" - }, - "Column": { - "Column": "ستون" - }, - "Column Display": { - "Column Display": "نمایشگر ستون" - }, - "Column Width": { - "Column Width": "طول ستون" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "دستور" - }, - "Commands": { - "Commands": "دستورات" - }, - "Communication": { - "Communication": "ارتباطات" - }, - "Community themes": { - "Community themes": "تم‌های کامیونیتی" - }, - "Compact": { - "Compact": "فشرده" - }, - "Compact Mode": { - "Compact Mode": "حالت فشرده" - }, - "Completed": { - "Completed": "کامل شده" - }, - "Compositor": { - "Compositor": "کامپازیتور" - }, - "Compositor Settings": { - "Compositor Settings": "تنظیمات کامپازیتور" - }, - "Compositor not supported": { - "Compositor not supported": "کامپازیتور پشتیبانی نمی‌شود" - }, - "Config Format": { - "Config Format": "تنظیم قالب" - }, - "Config action: %1": { - "Config action: %1": "اقدام پیکربندی: %1" - }, - "Config validation failed": { - "Config validation failed": "اعتبارسنجی پیکربندی ناموفق بود" - }, - "Configuration": { - "Configuration": "پیکربندی" - }, - "Configuration activated": { - "Configuration activated": "پیکربندی فعال شد" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "وقتی این نمایشگر دوباره وصل شود، پیکربندی حفظ خواهد شد" - }, - "Configure": { - "Configure": "پیکربندی" - }, - "Configure Keybinds": { - "Configure Keybinds": "پیکربندی نگاشت‌کلیدها" - }, - "Configure a new printer": { - "Configure a new printer": "پیکربندی یک چاپگر جدید" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "آیکون‌ها را برای محیط‌کارهای نام‌دار تنظیم کنید. آیکون‌ها بر شماره‌ها هنگامی که هر دو فعال باشند اولویت دارند." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "پیکربندی انطباق معیار و اقدامات" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "تنظیم کنید که کدام نمایشگر‌ها «%1» را نشان دهند" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "تنظیم کنید که کدام نمایشگر‌ها اجزای پوسته را نمایش دهند" - }, - "Confirm": { - "Confirm": "تأیید" - }, - "Confirm Delete": { - "Confirm Delete": "تأیید حذف" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "تأیید تغییرات نمایشگر" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "تأیید کلید عبور برای " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "تداخل با: %1" - }, - "Connect": { - "Connect": "اتصال" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "اتصال به شبکه پنهان" - }, - "Connect to VPN": { - "Connect to VPN": "اتصال به VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "اتصال به وای‌فای" - }, - "Connected": { - "Connected": "متصل" - }, - "Connected Device": { - "Connected Device": "دستگاه متصل" - }, - "Connected Displays": { - "Connected Displays": "نمایشگر‌های متصل" - }, - "Connecting to Device": { - "Connecting to Device": "درحال اتصال به دستگاه" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "درحال اتصال..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "شامل" - }, - "Content": { - "Content": "محتوا" - }, - "Content copied": { - "Content copied": "محتوا کپی شد" - }, - "Contrast": { - "Contrast": "کنتراست" - }, - "Control Center": { - "Control Center": "مرکز کنترل" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "رنگ کاشی مرکز کنترل" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "مدت زمان انیمیشن را برای پاپ‌آپ اعلان‌ها و تاریخچه مشخص کنید" - }, - "Control currently playing media": { - "Control currently playing media": "کنترل رسانه درحال پخش" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "مشخص کنید که کدام اطلاعات اعلان در صفحه قفل نمایش داده شود" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "مشخص کنید کدام افزونه‌ها در حالت «همه» بدون نیاز به پیشوند راه‌انداز نمایش داده شوند. برای تغییر ترتیب بکشید." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "کنترل محیط‎‌کارها و ستون‌ها با اسکرول روی نوار" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "میزان شفافیت همه پاپ‌آپ‌ها، مودال‌ها و لایه‌های محتوای آنها را کنترل می‌کند" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "زمان باقی مانده" - }, - "Copied GIF": { - "Copied GIF": "گیف کپی شد" - }, - "Copied MP4": { - "Copied MP4": "MP4 کپی شد" - }, - "Copied WebP": { - "Copied WebP": "WebP کپی شد" - }, - "Copied to clipboard": { - "Copied to clipboard": "در کلیپ‌بورد کپی شد" - }, - "Copied!": { - "Copied!": "کپی شد!" - }, - "Copy": { - "Copy": "کپی" - }, - "Copy Content": { - "Copy Content": "کپی محتوا" - }, - "Copy Full Command": { - "Copy Full Command": "کپی دستور کامل" - }, - "Copy HTML": { - "Copy HTML": "کپی HTML" - }, - "Copy Name": { - "Copy Name": "کپی نام" - }, - "Copy PID": { - "Copy PID": "کپی PID" - }, - "Copy Text": { - "Copy Text": "کپی متن" - }, - "Copy path": { - "Copy path": "کپی مسیر" - }, - "Corner Radius": { - "Corner Radius": "شعاع گوشه" - }, - "Corner Radius Override": { - "Corner Radius Override": "جایگزینی شعاع گوشه‌ها" - }, - "Corners & Background": { - "Corners & Background": "گوشه‌ها و پس‌زمینه" - }, - "Count Only": { - "Count Only": "فقط تعداد" - }, - "Cover Open": { - "Cover Open": "درپوش باز" - }, - "Create": { - "Create": "ایجاد" - }, - "Create Dir": { - "Create Dir": "ایجاد دایرکتوری" - }, - "Create Printer": { - "Create Printer": "ایجاد چاپگر" - }, - "Create Window Rule": { - "Create Window Rule": "ایجاد قاعده پنجره" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "ایجاد قاعده برای:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "برای بی‌صدا کردن، نادیده گرفتن، مخفی‌سازی از تاریخچه، یا تغییر اولویت اعلان‌ها قواعدی ایجاد کنید. در حالت پیش‌فرض، تنها اولویت تغییر می‌کند؛ اعلان‌ها همچنان به‌صورت عادی نمایش داده می‌شوند." - }, - "Creating...": { - "Creating...": "درحال ایجاد..." - }, - "Critical Priority": { - "Critical Priority": "اولویت حیاتی" - }, - "Current": { - "Current": "کنونی" - }, - "Current Items": { - "Current Items": "آیتم‌های کنونی" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "مانیتور کنونی" - }, - "Current Period": { - "Current Period": "بازه‌ی کنونی" - }, - "Current Status": { - "Current Status": "وضعیت کنونی" - }, - "Current Temp": { - "Current Temp": "دمای کنونی" - }, - "Current Theme: %1": { - "Current Theme: %1": "تم کنونی: %1" - }, - "Current Weather": { - "Current Weather": "آب و هوای کنونی" - }, - "Current Workspace": { - "Current Workspace": "محیط‌کار کنونی" - }, - "Current time and date display": { - "Current time and date display": "نمایش زمان و تاریخ کنونی" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "وضعیت آب و هوا و دمای کنونی" - }, - "Current: %1": { - "Current: %1": "کنونی: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "پیکربندی اشاره‌گر موس تنظیم نشده" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "دستور include اشاره‌گر موس یافت نشد" - }, - "Cursor Size": { - "Cursor Size": "اندازه اشاره‌گر موس" - }, - "Cursor Theme": { - "Cursor Theme": "تم اشاره‌گر موس" - }, - "Custom": { - "Custom": "سفارشی" - }, - "Custom Color": { - "Custom Color": "رنگ سفارشی" - }, - "Custom Duration": { - "Custom Duration": "مدت زمان سفارشی" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "دستور هایبرنیت سفارشی" - }, - "Custom Location": { - "Custom Location": "موقعیت مکانی سفارشی" - }, - "Custom Lock Command": { - "Custom Lock Command": "دستور قفل سفارشی" - }, - "Custom Logout Command": { - "Custom Logout Command": "دستور خروج سفارشی" - }, - "Custom Name": { - "Custom Name": "نام سفارشی" - }, - "Custom Power Actions": { - "Custom Power Actions": "اقدام‌های پاور سفارشی" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "دستور خاموش‌کردن سفارشی" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "دستور راه‌اندازی مجدد سفارشی" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "دستور تعلیق سفارشی" - }, - "Custom Transparency": { - "Custom Transparency": "شفافیت سفارشی" - }, - "Custom power profile": { - "Custom power profile": "پروفایل پاور سفارشی" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "تم سفارشی از فایل JSON بارگذاری شد" - }, - "Custom...": { - "Custom...": "سفارشی..." - }, - "Custom: ": { - "Custom: ": "سفارشی: " - }, - "Customizable empty space": { - "Customizable empty space": "فضای خالی قابل تنظیم" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "مشخص کن کدام گزینه‌ها در منوی پاور نمایش داده شوند" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "مانیتور DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "حالت آزمایشی - برای خروج بر هر‌جایی کلیک کنید" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "مدیریت افزونه DMS در دسترس نیست" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "میانبرهای DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS بروز نیست" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "سرویس DMS قطع می‌باشد. تنظیمات کلیپ‌بورد در دسترس نیست." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "اقدام‌های شِل DMS (لانچر، کلیپ‌بورد و غیره)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET در دسترس نیست" - }, - "DWL service not available": { - "DWL service not available": "سرویس DWL در دسترس نیست" - }, - "Daily": { - "Daily": "روزانه" - }, - "Daily at:": { - "Daily at:": "روزانه در:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "نوار دَنک" - }, - "DankBar": { - "DankBar": "نوار دَنک" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "دَنک متریال شل آماده استفاده می‌باشد" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "آیکون‌های DankShell و سیستم (نیازمند راه‌اندازی مجدد)" - }, - "Dark Mode": { - "Dark Mode": "حالت تاریک" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "تیره‌کردن پس‌زمینه مودال" - }, - "Date Format": { - "Date Format": "قالب تاریخ" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "سپیده دم (گرگ و میش نجومی)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "سپیده دم (گرگ و میش مدنی)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "سپیده دم (گرگ و میش دریایی)" - }, - "Day Date": { - "Day Date": "تاریخ روز" - }, - "Day Month Date": { - "Day Month Date": "تاریخ روز ماه" - }, - "Day Temperature": { - "Day Temperature": "دمای روز" - }, - "Daytime": { - "Daytime": "روز" - }, - "Deck": { - "Deck": "دک" - }, - "Default": { - "Default": "پیش‌فرض" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "طول پیش‌فرض (%)" - }, - "Default selected action": { - "Default selected action": "اقدام انتخابی پیش‌فرض" - }, - "Defaults": { - "Defaults": "پیش‌فرض‌ها" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "برای رفتار پنجره قواعد تعریف کنید. در %1 ذخیره می‌شود" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: پاک‌کردن • Shift+Del: پاک‌کردن همه • 1-9: اقدامات • F10: راهنما • Esc: بستن" - }, - "Delete": { - "Delete": "حذف" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "«%1» حذف شود؟" - }, - "Delete Class": { - "Delete Class": "حذف کلاس" - }, - "Delete Printer": { - "Delete Printer": "حذف چاپگر" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "مورد ذخیره‌شده حذف شود؟" - }, - "Delete VPN": { - "Delete VPN": "حذف VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "کلاس «%1» حذف شود؟" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "پروفایل «%1» حذف شود؟" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "رنگ‌هایی را استخراج می‌کند که با تصویر زیرین مطابقت نزدیکی دارند." - }, - "Description": { - "Description": "توضیحات" - }, - "Desktop": { - "Desktop": "دسکتاپ" - }, - "Desktop Clock": { - "Desktop Clock": "ساعت دسکتاپ" - }, - "Desktop Entry": { - "Desktop Entry": "مدخل دسکتاپ" - }, - "Desktop Widget": { - "Desktop Widget": "ابزارک دسکتاپ" - }, - "Desktop Widgets": { - "Desktop Widgets": "ابزارک‌های دسکتاپ" - }, - "Desktop background images": { - "Desktop background images": "تصاویر پس‌زمینه دسکتاپ" - }, - "Detailed": { - "Detailed": "با جزئیات" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "توسعه" - }, - "Device": { - "Device": "دستگاه" - }, - "Device connections": { - "Device connections": "اتصال‌های دستگاه" - }, - "Device names updated": { - "Device names updated": "نام دستگاه‌ها بروز شدند" - }, - "Device paired": { - "Device paired": "دستگاه جفت شد" - }, - "Device unpaired": { - "Device unpaired": "دستگاه جفت نشده" - }, - "Digital": { - "Digital": "دیجیتال" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "غیرفعال کردن اتصال خودکار" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "غیرفعال کردن تصاویر پس‌زمینه داخلی" - }, - "Disable History Persistence": { - "Disable History Persistence": "غیرفعال کردن ماندگاری تاریخچه" - }, - "Disable Output": { - "Disable Output": "غیرفعال‌کردن خروجی" - }, - "Disabled": { - "Disabled": "غیرفعال" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "غیرفعال‌سازی وای‌فای..." - }, - "Disc": { - "Disc": "دیسک" - }, - "Discard": { - "Discard": "نادیده‌گرفتن" - }, - "Discharging": { - "Discharging": "تخلیه شارژ" - }, - "Disconnect": { - "Disconnect": "قطع اتصال" - }, - "Disconnected": { - "Disconnected": "غیر متصل" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "اتصال از وای‌فای قطع شد" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "دیسک" - }, - "Disk I/O": { - "Disk I/O": "ورودی/خروجی دیسک" - }, - "Disk Usage": { - "Disk Usage": "میزان مصرف دیسک" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "دیسک‌ها" - }, - "Dismiss": { - "Dismiss": "رد کردن" - }, - "Display": { - "Display": "نمایشگر" - }, - "Display Assignment": { - "Display Assignment": "تنظیم نمایشگر" - }, - "Display Control": { - "Display Control": "کنترل نمایشگر" - }, - "Display Name Format": { - "Display Name Format": "قالب نمایش نام" - }, - "Display Profiles": { - "Display Profiles": "پروفایل‌های نمایشگر" - }, - "Display Settings": { - "Display Settings": "تنظیمات نمایشگر" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "یک داک با برنامه‌های سنجاق شده و درحال اجرا را نمایش بده" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "نمایش همه اولویت‌ها روی برنامه‌های تمام‌صفحه" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "نمایش و تغییر چیدمان‌های DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "آیکون برنامه‌ها را در نشانگر‌های محیط‌کار نمایش بده" - }, - "Display brightness control": { - "Display brightness control": "کنترل روشنایی نمایشگر" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "پیکربندی نمایشگر در دسترس نیست. پروتکل مدیریت خروجی WLR پشتیبانی نمی‌شود." - }, - "Display currently focused application title": { - "Display currently focused application title": "نمایش عنوان برنامه فوکوس شده کنونی" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "نمایش پیش‌بینی‌های ساعتی آب و هوا" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "فقط محیط‌کارهایی که شامل پنجره هستند را نمایش بده" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "اقدامات منوی پاور را در جدول به جای فهرست نمایش بده" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "نمایش ثانیه در ساعت" - }, - "Display the power system menu": { - "Display the power system menu": "نمایش منوی پاور سیستم" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "مقدار درصد حجم صدا و روشنایی صفحه را در پاپ‌آپ‌های OSD نمایش بده" - }, - "Displays": { - "Displays": "نمایشگر‌ها" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "تعداد را هنگام فعال بودن سرریز شدن نمایش می‌دهد" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "چیدمان صفحه‌کلید فعال را نمایش می‌دهد و امکان تغییر را فراهم می‌کند" - }, - "Distribution": { - "Distribution": "توزیع" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "پالت رنگی متنوع که طیف کاملی از رنگ‌ها را در بر می‌گیرد." - }, - "Do Not Disturb": { - "Do Not Disturb": "مزاحم نشوید" - }, - "Dock": { - "Dock": "داک" - }, - "Dock & Launcher": { - "Dock & Launcher": "داک و لانچر" - }, - "Dock Transparency": { - "Dock Transparency": "شفافیت داک" - }, - "Dock Visibility": { - "Dock Visibility": "وضعیت نمایش داک" - }, - "Docs": { - "Docs": "مستندات" - }, - "Documents": { - "Documents": "اسناد" - }, - "Domain (optional)": { - "Domain (optional)": "دامنه (اختیاری)" - }, - "Don't Change": { - "Don't Change": "تغییر نده" - }, - "Don't Save": { - "Don't Save": "ذخیره نکن" - }, - "Door Open": { - "Door Open": "درب باز" - }, - "Downloads": { - "Downloads": "بارگیری‌ها" - }, - "Drag to Reorder": { - "Drag to Reorder": "نگه‌داشتن برای بازآرایی" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "برای مرتب‌سازی مجدد ابزارک‌ها میان بخش‌ها، آنها را بکشید. از نماد چشم برای مخفی کردن/نمایش ویجت‌ها (حفظ فاصله) یا از X برای حذف کامل آنها استفاده کنید." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "نگه‌داشتن نشانگر محیط‌کارها برای بازآرایی آنها" - }, - "Driver": { - "Driver": "درایور" - }, - "Drizzle": { - "Drizzle": "باران‌ریزه" - }, - "Duplicate": { - "Duplicate": "تکثیر" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "تصویر پس‌زمینه تکراری با تاری" - }, - "Duration": { - "Duration": "مدت زمان" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "غروب (گرگ و میش نجومی)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "غروب (گرگ و میش مدنی)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "غروب (گرگ و میش دریایی)" - }, - "Dynamic": { - "Dynamic": "پویا" - }, - "Dynamic Properties": { - "Dynamic Properties": "ترجیهات پویا" - }, - "Dynamic Theming": { - "Dynamic Theming": "پوسته پویا" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "رنگ‌های پویا از تصویر پس‌زمینه" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "رنگ‌های پویا، پیش‌تنظیم‌ها" - }, - "Edge Spacing": { - "Edge Spacing": "فاصله لبه" - }, - "Edit App": { - "Edit App": "ویرایش برنامه" - }, - "Edit Window Rule": { - "Edit Window Rule": "ویرایش قاعده پنجره" - }, - "Education": { - "Education": "آموزش" - }, - "Empty": { - "Empty": "خالی" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "فعال‌کردن عمق رنگ ۱۰ بیت برای طیف رنگ عریض‌تر و پشتیبانی HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "فعال‌کردن اتصال خودکار" - }, - "Enable Bar": { - "Enable Bar": "فعال‌کردن نوار" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "فعال‌کردن مزاحم نشوید" - }, - "Enable History": { - "Enable History": "فعال‌کردن تاریخچه" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "فعال‌کردن overlay نمای کلی" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "فعال کردن افکت موجی" - }, - "Enable System Sounds": { - "Enable System Sounds": "فعال‌کردن صدای سیستم" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "فعال کردن آب و هوا" - }, - "Enable WiFi": { - "Enable WiFi": "فعال کردن وای‌فای" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "فعال‌سازی لایه مات قابل کنترل توسط کامپازیتور (namespace: dms:blurwallpaper). نیازمند پیکربندی دستی niri است." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "فعال‌کردن احراز هویت با اثرانگشت" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "فعال‌کردن یکپارچه‌سازی قفل loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "فعال" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "فعال‌سازی وای‌فای..." - }, - "End": { - "End": "پایان" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "بزرگنمایی با اشاره" - }, - "Enlargement %": { - "Enlargement %": "٪ بزرگنمایی" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "کلید عبور ۶ رقمی را وارد کنید" - }, - "Enter PIN": { - "Enter PIN": "PIN را وارد کنید" - }, - "Enter PIN for ": { - "Enter PIN for ": "ورود PIN برای " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "متن یا URL برای اشتراک‌گذاری وارد کنید" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "نام جدید برای این محیط‌کار وارد کنید" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "ورود اعتبارنامه‌ها برای " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "قالب سفارشی صفحه قفل را وارد کنید (مانند dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "قالب سفارشی نوار بالا را وارد کنید (مانند ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "نام دستگاه‌ را وارد کنید..." - }, - "Enter filename...": { - "Enter filename...": "نام فایل را وارد کنید..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "پیشوند اجرا را وارد کنید (مانند 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "نام شبکه و گذرواژه را وارد کنید" - }, - "Enter passkey for ": { - "Enter passkey for ": "ورود کلید عبور برای " - }, - "Enter password for ": { - "Enter password for ": "ورود گذرواژه برای " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "ورود این کلید عبور در " - }, - "Enter to Paste": { - "Enter to Paste": "Enter برای الصاق" - }, - "Enterprise": { - "Enterprise": "شرکت" - }, - "Entry pinned": { - "Entry pinned": "مدخل سنجاق شد" - }, - "Entry unpinned": { - "Entry unpinned": "سنجاق مدخل برداشته شد" - }, - "Environment Variables": { - "Environment Variables": "متغیر‌های محیطی" - }, - "Error": { - "Error": "خطا" - }, - "Errors": { - "Errors": "خطا‌ها" - }, - "Ethernet": { - "Ethernet": "اترنت" - }, - "Exact": { - "Exact": "دقیق" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "آفست ناحیه انحصاری" - }, - "Experimental Feature": { - "Experimental Feature": "قابلیت آزمایشی" - }, - "Explore": { - "Explore": "کاوش" - }, - "Exponential": { - "Exponential": "نمایی" - }, - "Expressive": { - "Expressive": "پررنگ" - }, - "Extend battery life": { - "Extend battery life": "افزایش عمر باتری" - }, - "Extensible architecture": { - "Extensible architecture": "معماری گسترش‌پذیر" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "مدیریت تصویر پس‌زمینه خارجی" - }, - "Extra Arguments": { - "Extra Arguments": "آرگومان‌های اضافی" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: تغییر حالت • F10: راهنما" - }, - "Fade": { - "Fade": "محو شدن" - }, - "Fade to lock screen": { - "Fade to lock screen": "محو شدن برای قفل صفحه" - }, - "Fade to monitor off": { - "Fade to monitor off": "محو شدن تا خاموشی نمایشگر" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "پذیرش جفت‌سازی ناموفق بود" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "فعال‌سازی پیکربندی ناموفق بود" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "فعال‌سازی پروفایل ناموفق بود - فایل یافت نشد" - }, - "Failed to add binds include": { - "Failed to add binds include": "افزودن include نگاشت‌ها ناموفق بود" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "افزودن چاپگر به کلاس ناموفق بود" - }, - "Failed to browse device": { - "Failed to browse device": "مرور دستگاه ناموفق بود" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "لغو همه کار‌های چاپ ناموفق بود" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "لغو کار چاپ انتخاب شده ناموفق بود" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "بررسی محدودیت سنجاق ناموفق بود" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "اتصال به VPN ناموفق بود" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "اتصال به %1 ناموفق بود" - }, - "Failed to copy entry": { - "Failed to copy entry": "کپی مدخل ناموفق بود" - }, - "Failed to create printer": { - "Failed to create printer": "ایجاد چاپگر ناموفق بود" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "ساخت دایرکتوری پروفایل‌ها ناموفق بود" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "حذف VPN ناموفق بود" - }, - "Failed to delete class": { - "Failed to delete class": "حذف کلاس ناموفق بود" - }, - "Failed to delete printer": { - "Failed to delete printer": "حذف چاپگر ناموفق بود" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "غیرفعال‌سازی پذیرش کارهای چاپ ناموفق بود" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "غیرفعال‌کردن حال شب ناموفق بود" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "قطع اتصال از VPN ناموفق بود" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "قطع اتصال از VPN‌ها ناموفق بود" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "قطع اتصال وای‌فای ناموفق بود" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "فعال‌کردن موقعیت مکانی IP ناموفق بود" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "فعال‌کردن وای‌فای ناموفق بود" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "فعال‌سازی پذیرش کارهای چاپ ناموفق بود" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "فعال‌کردن حالت شب ناموفق بود" - }, - "Failed to hold job": { - "Failed to hold job": "نگه‌داشتن کار چاپ ناموفق بود" - }, - "Failed to import VPN": { - "Failed to import VPN": "وارد کردن VPN ناموفق بود" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "اجرای برنامه SMS ناموفق بود" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "بارگذاری پیکربندی VPN ناموفق بود" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "بارگذاری پیکربندی کلیپ‌بورد ناموفق بود." - }, - "Failed to move job": { - "Failed to move job": "انتقال کار چاپ ناموفق بود" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "تجزیه فایل plugin_settings.json ناموفق بود" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "تجزیه فایل session.json ناموفق بود" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "تجزیه فایل settings.json ناموفق بود" - }, - "Failed to pause printer": { - "Failed to pause printer": "توقف چاپگر ناموفق بود" - }, - "Failed to pin entry": { - "Failed to pin entry": "سنجاق کردن مدخل ناموفق بود" - }, - "Failed to print test page": { - "Failed to print test page": "چاپ صفحه تست ناموفق بود" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "رد کردن اتصال ناموفق بود" - }, - "Failed to remove device": { - "Failed to remove device": "حذف دستگاه ناموفق بود" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "حذف نگاشت‌کلید ناموفق بود" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "حذف چاپگر از کلاس ناموفق بود" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "راه‌اندازی مجدد سیستم صوتی ناموفق بود" - }, - "Failed to restart job": { - "Failed to restart job": "شروع مجدد کار چاپ ناموفق بود" - }, - "Failed to resume printer": { - "Failed to resume printer": "ازسرگیری چاپگر ناموفق بود" - }, - "Failed to ring device": { - "Failed to ring device": "زنگ زدن دستگاه ناموفق بود" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "ذخیره پیکربندی صوتی ناموفق بود" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "ذخیره تنظیمات کلیپ‌بورد ناموفق بود" - }, - "Failed to save keybind": { - "Failed to save keybind": "ذخیره نگاشت‌کلید ناموفق بود" - }, - "Failed to save profile file": { - "Failed to save profile file": "ذخیره فایل پروفایل ناموفق بود" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "ارسال کلیپ‌بورد ناموفق بود" - }, - "Failed to send file": { - "Failed to send file": "ارسال فایل ناموفق بود" - }, - "Failed to send ping": { - "Failed to send ping": "ارسال پینگ ناموفق بود" - }, - "Failed to set brightness": { - "Failed to set brightness": "تنظیم روشنایی ناموفق بود" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "تنظیم مکان حالت شب ناموفق بود" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "تنظیم زمان‌بندی حالت شب ناموفق بود" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "تنظیم دمای حالت شب ناموفق بود" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "تنظیم تصویر نمایه ناموفق بود" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "تنظیم تصویر نمایه ناموفق بود: %1" - }, - "Failed to share": { - "Failed to share": "اشتراک‌گذاری ناموفق بود" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "شروع اتصال به %1 ناموفق بود" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "برداشتن سنجاق مدخل ناموفق بود" - }, - "Failed to update VPN": { - "Failed to update VPN": "بروزرسانی VPN ناموفق بود" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "بروزرسانی اتصال خودکار ناموفق بود" - }, - "Failed to update description": { - "Failed to update description": "بروزرسانی توضیحات ناموفق بود" - }, - "Failed to update location": { - "Failed to update location": "بروزرسانی مکان ناموفق بود" - }, - "Failed to update sharing": { - "Failed to update sharing": "بروزرسانی اشتراک‌گذاری ناموفق بود" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "نوشتن فایل موقت برای اعتبارسنجی ناموفق بود" - }, - "Features": { - "Features": "ویژگی‌ها" - }, - "Feels": { - "Feels": "دمای حسی" - }, - "Feels Like": { - "Feels Like": "دمای حسی" - }, - "Feels Like %1°": { - "Feels Like %1°": "دمای حسی %1°" - }, - "Fidelity": { - "Fidelity": "دقیق" - }, - "Field": { - "Field": "فیلد" - }, - "File": { - "File": "فایل" - }, - "File Already Exists": { - "File Already Exists": "فایل از قبل وجود دارد" - }, - "File Information": { - "File Information": "اطلاعات فایل" - }, - "File received from": { - "File received from": "فایل دریافت شده از" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "جستجوی فایل به dsearch نیاز دارد\nاز github.com/morelazers/dsearch نصب کنید" - }, - "Files": { - "Files": "فایل‌ها" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "نظارت بر استفاده از سیستم فایل" - }, - "Fill": { - "Fill": "پُر" - }, - "Find in Text": { - "Find in Text": "یافتن در متن" - }, - "Find in note...": { - "Find in note...": "یافتن در یادداشت..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "پایان" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "راه‌اندازی اولیه" - }, - "Fit": { - "Fit": "متناسب" - }, - "Fix Now": { - "Fix Now": "رفع فوری" - }, - "Fixing...": { - "Fixing...": "درحال رفع..." - }, - "Flags": { - "Flags": "فلگ‌ها" - }, - "Flipped": { - "Flipped": "وارونه" - }, - "Flipped 180°": { - "Flipped 180°": "وارونه ۱۸۰°" - }, - "Flipped 270°": { - "Flipped 270°": "وارونه ۲۷۰°" - }, - "Flipped 90°": { - "Flipped 90°": "وارونه ۹۰°" - }, - "Float": { - "Float": "شناور" - }, - "Focus": { - "Focus": "فوکوس" - }, - "Focus at Startup": { - "Focus at Startup": "فوکوس در هنگام راه‌اندازی" - }, - "Focused Border": { - "Focused Border": "حاشیه فوکوس" - }, - "Focused Color": { - "Focused Color": "رنگ فوکوس شده" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "پنجره فوکوس‌شده" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "مه" - }, - "Folder": { - "Folder": "پوشه" - }, - "Folders": { - "Folders": "پوشه‌ها" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "فوکوس مانیتور را دنبال کن" - }, - "Follow focus": { - "Follow focus": "پیروی از فوکوس" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "خانواده فونت" - }, - "Font Scale": { - "Font Scale": "بزرگنمایی فونت" - }, - "Font Size": { - "Font Size": "اندازه فونت" - }, - "Font Weight": { - "Font Weight": "وزن فونت" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "اجبار HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "بستن اجباری (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "اجبار رنگ عریض" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "برنامه‌های ترمینال به استفاده از طرح‌های رنگی تیره وادار کن" - }, - "Forecast": { - "Forecast": "پیش‌بینی" - }, - "Forecast Days": { - "Forecast Days": "پیش‌بینی روزها" - }, - "Forecast Not Available": { - "Forecast Not Available": "پیش‌بینی موجود نیست" - }, - "Forever": { - "Forever": "برای همیشه" - }, - "Forget": { - "Forget": "فراموش کردن" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "«%1» فراموش شود؟" - }, - "Forget Device": { - "Forget Device": "فراموش‌کردن دستگاه" - }, - "Forget Network": { - "Forget Network": "فراموش‌کردن شبکه" - }, - "Forgot network %1": { - "Forgot network %1": "فراموشی شبکه %1" - }, - "Format Legend": { - "Format Legend": "راهنمای قالب‌بندی" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "هنگامی که لانچر بسته شد VRAM/حافظه را آزاد کن. ممکن است باعث اندکی تأخیر هنگام باز کردن مجدد شود." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "باران‌ریزه یخ‌زن" - }, - "Frequency": { - "Frequency": "فرکانس" - }, - "Fruit Salad": { - "Fruit Salad": "رنگارنگ" - }, - "Full Command:": { - "Full Command:": "دستور کامل:" - }, - "Full Content": { - "Full Content": "محتوای کامل" - }, - "Full Day & Month": { - "Full Day & Month": "روز کامل و ماه" - }, - "Full with Year": { - "Full with Year": "کامل با سال" - }, - "Fullscreen": { - "Fullscreen": "تمام‌صفحه" - }, - "Fullscreen Only": { - "Fullscreen Only": "فقط تمام‌صفحه" - }, - "Fully Charged": { - "Fully Charged": "کاملا شارژ شده" - }, - "Fun": { - "Fun": "سرگرمی" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: جدول • Z/X: اندازه" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "نظارت بر GPU" - }, - "GPU Temperature": { - "GPU Temperature": "دمای GPU" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK، Qt، IDEها و بیشتر" - }, - "Games": { - "Games": "بازی‌ها" - }, - "Gamma Control": { - "Gamma Control": "کنترل گاما" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "کنترل گاما در دسترس نیست. نیاز به DMS API نسخه ۶ به بالا دارد." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "عمومی" - }, - "Get Started": { - "Get Started": "شروع کنید" - }, - "GitHub": { - "GitHub": "گیت‌هاب" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "مدت تمام انیمیشن‌ها را سراسری مقیاس کن" - }, - "Golden Hour": { - "Golden Hour": "ساعت طلایی" - }, - "Good": { - "Good": "خوب" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "شعاع گوشه‌های گوتیک" - }, - "Goth Corners": { - "Goth Corners": "گوشه‌های گوتیک" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "قبل از قفل شدن، صفحه را با یک دوره زمانی قابل تنظیم به تدریج محو کن" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "قبل از خاموش شدن مانیتور‌ها، صفحه را با یک دوره زمانی قابل تنظیم به تدریج محو کن" - }, - "Graph Time Range": { - "Graph Time Range": "بازه زمانی نمودار" - }, - "Graphics": { - "Graphics": "گرافیک" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "جدولی" - }, - "Grid Columns": { - "Grid Columns": "ستون‌های جدول" - }, - "Grid: OFF": { - "Grid: OFF": "جدول:‌ خاموش" - }, - "Grid: ON": { - "Grid: ON": "جدول:‌ روشن" - }, - "Group": { - "Group": "گروه" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "گروه‌بندی برنامه‌های محیط‌کار" - }, - "Group by App": { - "Group by App": "گروه‌بندی بر اساس برنامه" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "چندین پنجره از برنامه یکسان با نشانگر تعداد پنجره‌ها گروه‌بندی کن" - }, - "Group removed": { - "Group removed": "گروه حذف شد" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "برنامه‌های تکرار شده در محیط‌کارهای فوکوس نشده را گروه‌بندی کن" - }, - "Groups": { - "Groups": "گروه‌ها" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "نگاشت تُن HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "حالت HDR آزمایشی است. قبل از فعال کردن، مطمئن شوید که مانیتور شما از HDR پشتیبانی می‌کند." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "کد HTML در کلیپ‌بورد کپی شد" - }, - "Health": { - "Health": "سلامت" - }, - "Heavy Rain": { - "Heavy Rain": "باران سنگین" - }, - "Heavy Snow": { - "Heavy Snow": "برف سنگین" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "برف سنگین پراکنده" - }, - "Height": { - "Height": "ارتفاع" - }, - "Held": { - "Held": "نگه‌داشتن" - }, - "Help": { - "Help": "راهنما" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "هایبرنیت" - }, - "Hidden": { - "Hidden": "پنهان" - }, - "Hidden (%1)": { - "Hidden (%1)": "پنهان (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "برنامه‌های پنهان" - }, - "Hidden Network": { - "Hidden Network": "شبکه پنهان" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "برنامه‌های پنهان در لانچر ظاهر نمی‌شوند. روی یک برنامه راست‌کلیک کرده و «پنهان کردن برنامه» را برای پنهان کردن آن انتخاب کنید." - }, - "Hide": { - "Hide": "پنهان" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "پنهان کردن شخص ثالث" - }, - "Hide App": { - "Hide App": "پنهان کردن برنامه" - }, - "Hide Delay": { - "Hide Delay": "تأخیر پنهان‌شدن" - }, - "Hide Indicators": { - "Hide Indicators": "پنهان کردن نشانگر‌ها" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "پنهان‌کردن ابزارک بروزرسان" - }, - "Hide When Typing": { - "Hide When Typing": "هنگام تایپ پنهان کن" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "وقتی پنجره‌ها باز هستند پنهان کن" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "اشاره‌گر موس را بعد از عدم فعالیت پنهان کن (۰ = غیرفعال)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "اشاره‌گر موس را هنگام فشردن کلید‌های صفحه‌کلید پنهان کن" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "اشاره‌گر موس را هنگام استفاده از ورودی لمسی پنهان کن" - }, - "Hide device": { - "Hide device": "پنهان کردن دستگاه" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "پنهان کردن محتوای اعلان را تا هنگام گسترش" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "محتوای اعلان را تا هنگام گسترش پنهان کن؛ پاپ‌آپ‌ها به طور پیش‌فرض گسترش‌یافته نمایش داده می‌شوند" - }, - "Hide on Touch": { - "Hide on Touch": "هنگام لمس پنهان کن" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "پالت رنگی با دقت بالا که رنگ‌های اصلی را حفظ می‌کند." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "تاریخچه" - }, - "History Retention": { - "History Retention": "نگهداری تاریخچه" - }, - "History Settings": { - "History Settings": "تنظیمات تاریخچه" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "تاریخچه پاک شد. %1 مدخل سنجاق شده نگه داشته شد." - }, - "Hold Duration": { - "Hold Duration": "مدت زمان نگه‌داشتن" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "برای تأیید بیشتر نگه‌دارید" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "نگه‌داشتن برای تأیید اقدام پاور" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "برای تأیید نگه‌دارید (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "برای تأیید نگه‌دارید (%1s)" - }, - "Home": { - "Home": "خانه" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "نام هاست" - }, - "Hot Corners": { - "Hot Corners": "گوشه‌های فعال" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "عنوان کلید میانبر overlay (اختیاری)" - }, - "Hour": { - "Hour": "ساعت" - }, - "Hourly": { - "Hourly": "ساعتی" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "تعداد پیش‌بینی‌های ساعتی" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "چند وقت یکبار تصویر پس‌زمینه تغییر کند" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "رطوبت" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "جایگزینی‌های چیدمان هایپرلند" - }, - "Hyprland Options": { - "Hyprland Options": "گزینه‌های هایپرلند" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "متوجه شدم" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "آدرس IP:" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "تاریخ ISO" - }, - "Icon": { - "Icon": "آیکون" - }, - "Icon Scale": { - "Icon Scale": "بزرگنمایی آیکون" - }, - "Icon Size": { - "Icon Size": "اندازه آیکون" - }, - "Icon Size %": { - "Icon Size %": "٪ اندازه آیکون" - }, - "Icon Theme": { - "Icon Theme": "تم آیکون" - }, - "Idle": { - "Idle": "بیکار" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "مهارگر بیکاری" - }, - "Idle Settings": { - "Idle Settings": "تنظیمات بیکاری سیستم" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "نظارت بر بیکاری سیستم پشتیبانی نمی‌شود - به نسخه بروزتر Quickshell نیاز است" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "اگر فیلد پنهان باشد، به محض فشردن کلید پدیدار می‌شود." - }, - "Ignore Completely": { - "Ignore Completely": "کلاً نادیده بگیر" - }, - "Image": { - "Image": "تصویر" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "تصویر در کلیپ‌بورد کپی شد" - }, - "Import": { - "Import": "وارد کردن" - }, - "Import VPN": { - "Import VPN": "وارد کردن VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "رنگ مانیتور غیر‌فعال" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "اضافه‌کردن گذارها" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "اقدام‌های دسکتاپ (میانبر‌ها) را در نتایج جستجو وارد کن." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "افزونه‌های ناسازگار بارگذاری شده‌اند" - }, - "Incorrect password": { - "Incorrect password": "گذرواژه نادرست" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "استایل نشانگر" - }, - "Individual Batteries": { - "Individual Batteries": "باتری‌های جداگانه" - }, - "Individual bar configuration": { - "Individual bar configuration": "پیکربندی جداگانه نوار‌ها" - }, - "Info": { - "Info": "اطلاعات" - }, - "Inherit": { - "Inherit": "ارث‌بردن" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "قابل جلوگیری" - }, - "Input Devices": { - "Input Devices": "دستگاه‌های ورودی" - }, - "Input Volume Slider": { - "Input Volume Slider": "اسلایدر حجم صدای ورودی" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "نصب" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "نصب افزونه" - }, - "Install Theme": { - "Install Theme": "نصب تم" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "نصب تم رنگ‌ها از مخزن تم DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "نصب ناموفق بود:‌ %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "نصب بسته matugen برای تم پویا" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "آیا می‌خواهید افزونه '%1' را از مخزن DMS نصب کنید؟" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "نصب افزونه‌ها از مخزن افزونه DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "آیا می‌خواهید تم '%1' را از مخزن DMS نصب کنید؟" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "نصب شده" - }, - "Installed: %1": { - "Installed: %1": "نصب شده: %1" - }, - "Installing: %1": { - "Installing: %1": "درحال نصب: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "پنهان خودکار هوشمند" - }, - "Intensity": { - "Intensity": "شدت" - }, - "Interface:": { - "Interface:": "رابط:" - }, - "Interlock Open": { - "Interlock Open": "قفل داخلی باز" - }, - "Internet": { - "Internet": "اینترنت" - }, - "Interval": { - "Interval": "وقفه" - }, - "Invalid configuration": { - "Invalid configuration": "پیکربندی نامعتبر" - }, - "Invert on mode change": { - "Invert on mode change": "معکوس هنگام تغییر حالت" - }, - "Iris Bloom": { - "Iris Bloom": "باز کردن چشم" - }, - "Isolate Displays": { - "Isolate Displays": "ایزوله‌کردن نمایشگر‌ها" - }, - "Jobs": { - "Jobs": "کار‌های چاپ" - }, - "Jobs: ": { - "Jobs: ": "کار‌های چاپ: " - }, - "Keep Awake": { - "Keep Awake": "بیدار نگه‌ دار" - }, - "Keep Changes": { - "Keep Changes": "حفظ تغییرات" - }, - "Keeping Awake": { - "Keeping Awake": "بیدار نگه داشتن" - }, - "Kernel": { - "Kernel": "کرنل" - }, - "Key": { - "Key": "کلید" - }, - "Keybind Sources": { - "Keybind Sources": "منابع نگاشت‌کلیدها" - }, - "Keybinds": { - "Keybinds": "نگاشت‌کلیدها" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "تنظیمات نگاشت‌کلیدهای جستجو" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "نگاشت‌کلیدها همراه نتایج عادی جستجو نمایش داده می‌شوند" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "نام چیدمان صفحه‌کلید" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "میانبر‌های صفحه‌کلید" - }, - "Keys": { - "Keys": "کلیدها" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "بستن فرایند" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "دستگاه LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "بزرگ" - }, - "Largest": { - "Largest": "بزرگ‌ترین" - }, - "Last hour": { - "Last hour": "ساعت گذشته" - }, - "Last launched %1": { - "Last launched %1": "آخرین اجرا %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "آخرین اجرا به تازگی" - }, - "Latitude": { - "Latitude": "عرض جغرافیایی" - }, - "Launch": { - "Launch": "اجرا" - }, - "Launch Prefix": { - "Launch Prefix": "پیشوند اجرا" - }, - "Launch on dGPU": { - "Launch on dGPU": "اجرا با dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "لانچر" - }, - "Launcher Button": { - "Launcher Button": "دکمه لانچر" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "لوگوی دکمه لانچر" - }, - "Layout": { - "Layout": "چیدمان" - }, - "Layout Overrides": { - "Layout Overrides": "جایگزینی‌های چیدمان" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "چپ" - }, - "Left Center": { - "Left Center": "چپ وسط" - }, - "Left Section": { - "Left Section": "بخش چپ" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "حالت روشن" - }, - "Light Rain": { - "Light Rain": "باران سبک" - }, - "Light Snow": { - "Light Snow": "برف سبک" - }, - "Light Snow Showers": { - "Light Snow Showers": "برف پراکنده" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "خط" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "خطی" - }, - "Lines: %1": { - "Lines: %1": "خط: %1" - }, - "List": { - "List": "فهرست" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "پالت رنگی زنده با رنگ‌های تأکیدی اشباع شده." - }, - "Load Average": { - "Load Average": "متوسط بارگذاری" - }, - "Loading codecs...": { - "Loading codecs...": "بارگذاری کدک‌ها..." - }, - "Loading keybinds...": { - "Loading keybinds...": "بارگذاری نگاشت‌کلید..." - }, - "Loading trending...": { - "Loading trending...": "درحال بارگذاری پرطرفدار‌ها..." - }, - "Loading...": { - "Loading...": "درحال بارگذاری..." - }, - "Local": { - "Local": "محلی" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "مکان" - }, - "Location Search": { - "Location Search": "جستجوی موقعیت مکانی" - }, - "Lock": { - "Lock": "قفل" - }, - "Lock Screen": { - "Lock Screen": "صفحه قفل" - }, - "Lock Screen Display": { - "Lock Screen Display": "نمایشگر صفحه قفل" - }, - "Lock Screen Format": { - "Lock Screen Format": "قالب صفحه قفل" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "رفتار صفحه قفل" - }, - "Lock Screen layout": { - "Lock Screen layout": "چیدمان صفحه قفل" - }, - "Lock at startup": { - "Lock at startup": "قفل در هنگام راه‌اندازی" - }, - "Lock before suspend": { - "Lock before suspend": "قفل‌کردن قبل از تعلیق" - }, - "Lock fade grace period": { - "Lock fade grace period": "بازه زمانی محو شدن تدریجی قفل" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "قفل شده" - }, - "Log Out": { - "Log Out": "خروج" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "طولانی" - }, - "Long Text": { - "Long Text": "متن طولانی" - }, - "Long press": { - "Long press": "فشردن طولانی" - }, - "Longitude": { - "Longitude": "طول جغرافیایی" - }, - "Low Priority": { - "Low Priority": "اولویت پایین" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "از اجرای KDE Connect یا Valent در دستگاه‌های دیگر خود اطمینان حاصل کنید" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "مدیریت و پیکربندی افزونه‌ها برای گسترش کارایی DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "مدیریت حداکثر ۴ پیکربندی مستقل برای نوارها. هر نوار موقعیت، ابزارک‌ها، استایل و نحوه نمایش خاص خود را دارد." - }, - "Management": { - "Management": "مدیریت" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "جایگزینی‌های چیدمان MangoWC" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "مختصات دستی" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "اندازه فاصله دستی" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "نمایش/پنهان دستی" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "نام کلاس پنجره‌ها را برای نمایش مناسب آیکون به نام آیکون‌ها نگاشت کنید" - }, - "Margin": { - "Margin": "فاصله بیرونی" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "مخزن مارکر خالی است" - }, - "Marker Supply Low": { - "Marker Supply Low": "مخزن مارکر کم است" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "ضایعات مارکر تقریبا پر است" - }, - "Marker Waste Full": { - "Marker Waste Full": "ضایعات مارکر پر است" - }, - "Match Criteria": { - "Match Criteria": "انطباق معیار" - }, - "Matches profile: %1": { - "Matches profile: %1": "منطبق با پروفایل: %1" - }, - "Material Colors": { - "Material Colors": "رنگ‌های Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "رنگ‌های تم الهام گرفته شده از متریال دیزاین" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "رنگ‌های متریال گرفته شده از تصویر پس‌زمینه" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen یافت نشد" - }, - "Matugen Palette": { - "Matugen Palette": "پالت رنگی Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "مانیتور هدف Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "قالب‌های Matugen" - }, - "Max Edges": { - "Max Edges": "بیشینه لبه‌ها" - }, - "Max H": { - "Max H": "بیشینه H" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "بیشینه برنامه‌های سنجاق شده" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "بیشینه برنامه‌های سنجاق شده (۰ = نامحدود)" - }, - "Max Running Apps": { - "Max Running Apps": "بیشینه برنامه‌های درحال اجرا" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "بیشینه برنامه‌های درحال اجرا (۰ = نامحدود)" - }, - "Max Volume": { - "Max Volume": "حجم صدای بیشینه" - }, - "Max W": { - "Max W": "بیشینه W" - }, - "Max apps to show": { - "Max apps to show": "بیشینه برنامه‌ها برای نمایش" - }, - "Max to Edges": { - "Max to Edges": "بیشینه تا لبه‌ها" - }, - "Maximize": { - "Maximize": "بزرگ‌کردن پنجره" - }, - "Maximize Detection": { - "Maximize Detection": "تشخیص بزرگ‌شدن پنجره" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "بیشینه کردن آیکون‌های ابزارک" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "بیشینه کردن متن ابزارک" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "حداکثر اندازه مدخل" - }, - "Maximum History": { - "Maximum History": "حداکثر تاریخچه" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "بیشینه مدخل‌های سنجاق شده" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "بیشینه تعداد مدخل‌های کلیپ‌بورد برای نگه‌داری" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "بیشینه تعداد مدخل‌هایی که می‌توانند ذخیره شوند" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "بیشینه تعداد اعلان‌هایی که باید نگه داشته شوند" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "به بیشینه مدخل‌های سنجاق شده رسیدید" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "بیشینه اندازه برای هر مدخل کلیپ‌بورد" - }, - "Media": { - "Media": "رسانه" - }, - "Media Controls": { - "Media Controls": "کنترل‌های رسانه" - }, - "Media Empty": { - "Media Empty": "مدیا خالی است" - }, - "Media Jam": { - "Media Jam": "مدیا مسدود شده است" - }, - "Media Low": { - "Media Low": "مدیا کم است" - }, - "Media Needed": { - "Media Needed": "مدیا مورد نیاز است" - }, - "Media Playback": { - "Media Playback": "پخش رسانه" - }, - "Media Player": { - "Media Player": "پخش‌کننده رسانه" - }, - "Media Player Settings": { - "Media Player Settings": "تنظیمات پخش‌کننده رسانه" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "پخش‌کننده‌های رسانه (" - }, - "Media Volume": { - "Media Volume": "حجم صدای رسانه" - }, - "Medium": { - "Medium": "متوسط" - }, - "Memory": { - "Memory": "حافظه" - }, - "Memory Graph": { - "Memory Graph": "نمودار حافظه" - }, - "Memory Usage": { - "Memory Usage": "میزان مصرف حافظه" - }, - "Memory usage indicator": { - "Memory usage indicator": "نشانگر میزان مصرف حافظه" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "پیام" - }, - "Message Content": { - "Message Content": "محتوای پیام" - }, - "Microphone": { - "Microphone": "میکروفون" - }, - "Microphone Mute": { - "Microphone Mute": "میکروفون بی‌صدا" - }, - "Microphone Volume": { - "Microphone Volume": "حجم صدای میکروفون" - }, - "Microphone settings": { - "Microphone settings": "تنظیمات میکروفون" - }, - "Microphone volume control": { - "Microphone volume control": "کنترل حجم صدای میکروفون" - }, - "Middle Section": { - "Middle Section": "بخش میانی" - }, - "Min H": { - "Min H": "کمینه H" - }, - "Min W": { - "Min W": "کمینه W" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "پالت رنگی مینیمال ساخته‌شده حول یک رنگ." - }, - "Minute": { - "Minute": "دقیقه" - }, - "Mirror Display": { - "Mirror Display": "آینه‌کردن نمایشگر" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "متغیر‌های محیطی یافت نشد" - }, - "Modal Background": { - "Modal Background": "پس‌زمینه مودال" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "مودال‌ها" - }, - "Mode": { - "Mode": "حالت" - }, - "Mode:": { - "Mode:": "حالت:" - }, - "Model": { - "Model": "مدل" - }, - "Modified": { - "Modified": "اصلاح شده" - }, - "Modular widget bar": { - "Modular widget bar": "نوار ابزارک ماژولار" - }, - "Monitor": { - "Monitor": "مانیتور" - }, - "Monitor Configuration": { - "Monitor Configuration": "پیکربندی مانیتور" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "بازه زمانی محو شدن تدریجی مانیتور" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "مانیتوری که تصویر پس‌زمینه آن رنگ‌های تم پویا را تعیین می‌کند" - }, - "Monochrome": { - "Monochrome": "تک‌رنگ" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "فونت monospace" - }, - "Month Date": { - "Month Date": "تاریخ ماه" - }, - "Morning": { - "Morning": "صبح" - }, - "Mount Points": { - "Mount Points": "نقاط اتصال" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "نمای ظاهری اشاره‌گر موس" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "اندازه اشاره‌گر موس به پیکسل" - }, - "Move": { - "Move": "حرکت" - }, - "Move Widget": { - "Move Widget": "انتقال ابزارک" - }, - "Moving to Paused": { - "Moving to Paused": "انتقال به حالت متوقف شده" - }, - "Multi-Monitor": { - "Multi-Monitor": "چند مانیتوره" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "موسیقی" - }, - "Mute Popups": { - "Mute Popups": "پاپ‌آپ‌ها بی‌صدا شوند" - }, - "Mute popups for %1": { - "Mute popups for %1": "بی‌صدا کردن پاپ‌آپ‌ها را برای %1" - }, - "Muted": { - "Muted": "بی‌صدا" - }, - "Muted Apps": { - "Muted Apps": "برنامه‌های بی‌صدا" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "پالت رنگی ساکت با تن‌های ملایم و آرامش‌بخش." - }, - "NM not supported": { - "NM not supported": "NM پشتیبانی نمی‌شود" - }, - "Name": { - "Name": "نام" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "آیکون محیط‌کارهای نام‌دار" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "پیمایش" - }, - "Network": { - "Network": "شبکه" - }, - "Network Graph": { - "Network Graph": "نمودار شبکه" - }, - "Network Info": { - "Network Info": "اطلاعات شبکه" - }, - "Network Information": { - "Network Information": "اطلاعات شبکه" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "نام شبکه (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "نمایشگر سرعت شبکه" - }, - "Network Status": { - "Network Status": "وضعیت شبکه" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "نمایش سرعت بارگیری و بارگذاری شبکه" - }, - "Neutral": { - "Neutral": "خنثی" - }, - "Never": { - "Never": "هرگز" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "جدید" - }, - "New Key": { - "New Key": "کلید جدید" - }, - "New Keybind": { - "New Keybind": "نگاشت‌کلید جدید" - }, - "New Notification": { - "New Notification": "اعلان جدید" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "قاعده پنجره جدید" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "نام جدید گروه..." - }, - "Next": { - "Next": "بعدی" - }, - "Next Transition": { - "Next Transition": "گذار بعدی" - }, - "Night": { - "Night": "شب" - }, - "Night Mode": { - "Night Mode": "حالت شب" - }, - "Night Temperature": { - "Night Temperature": "دمای شب" - }, - "Night mode & gamma": { - "Night mode & gamma": "حالت شب و گاما" - }, - "Niri Integration": { - "Niri Integration": "همگام‌سازی نیری" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "جایگزینی‌های چیدمان‌ نیری" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "اقدام‌های کامپازیتور نیری (focus، move و غیره)" - }, - "No": { - "No": "خیر" - }, - "No Active Players": { - "No Active Players": "پخش‌کننده فعالی یافت نشد" - }, - "No Anim": { - "No Anim": "بدون انیمیشن" - }, - "No Background": { - "No Background": "بدون پس‌زمینه" - }, - "No Battery": { - "No Battery": "بدون باتری" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "آداپتور بلوتوثی یافت نشد" - }, - "No Blur": { - "No Blur": "بدون مات شدن" - }, - "No Border": { - "No Border": "بدون حاشیه" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "هیچ میانبری برای DMS پیکربندی نشده" - }, - "No Dim": { - "No Dim": "بدون تاریک‌شدن" - }, - "No Focus": { - "No Focus": "بدون فوکوس" - }, - "No GPU detected": { - "No GPU detected": "GPU شناسایی نشد" - }, - "No GPUs detected": { - "No GPUs detected": "هیچ GPUای شناسایی نشد" - }, - "No History": { - "No History": "بدون تاریخچه" - }, - "No Media": { - "No Media": "رسانه‌ای یافت نشد" - }, - "No Round": { - "No Round": "بدون گردی" - }, - "No Rounding": { - "No Rounding": "بدون گردی" - }, - "No Shadow": { - "No Shadow": "بدون سایه" - }, - "No VPN profiles": { - "No VPN profiles": "هیچ پروفایل VPNای یافت نشد" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "بدون داده آب و هوا" - }, - "No Weather Data Available": { - "No Weather Data Available": "داده آب و هوا در دسترس نیست" - }, - "No action": { - "No action": "بدون اقدام" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "بدون آداپتور" - }, - "No adapters": { - "No adapters": "آداپتوری یافت نشد" - }, - "No app customizations.": { - "No app customizations.": "هیچ سفارشی‌سازی برنامه‌ای موجود نیست." - }, - "No apps found": { - "No apps found": "هیچ برنامه‌ای یافت نشد" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "هیچ برنامه‌ای هنوز اجرا نشده است." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "هیچ برنامه‌ای بی‌صدا نشده است. برای افزودن یکی به اینجا روی اعلان راست‌کلیک کرده و «بی‌صدا کردن پاپ‌آپ‌ها» را انتخاب کنید." - }, - "No battery": { - "No battery": "بدون باتری" - }, - "No brightness devices available": { - "No brightness devices available": "هیچ دستگاه روشنایی موجود نیست" - }, - "No changes": { - "No changes": "بدون تغییرات" - }, - "No checks passed": { - "No checks passed": "هیچ‌یک از بررسی‌ها موفق نبود" - }, - "No custom theme file": { - "No custom theme file": "هیچ تم سفارشی یافت نشد" - }, - "No devices": { - "No devices": "بدون دستگاه" - }, - "No devices connected": { - "No devices connected": "بدون دستگاه متصل" - }, - "No devices found": { - "No devices found": "دستگاهی یافت نشد" - }, - "No disk data": { - "No disk data": "بدون داده دیسک" - }, - "No disk data available": { - "No disk data available": "داده دیسک در دسترس نیست" - }, - "No drivers found": { - "No drivers found": "درایوری یافت نشد" - }, - "No errors": { - "No errors": "بدون خطا" - }, - "No features enabled": { - "No features enabled": "هیچ قابلیتی فعال نشده" - }, - "No files found": { - "No files found": "هیچ فایلی یافت نشد" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "هیچ پوشه‌ای یافت نشد" - }, - "No hidden apps.": { - "No hidden apps.": "هیچ برنامه پنهانی موجود نیست." - }, - "No info items": { - "No info items": "مورد اطلاعاتی وجود ندارد" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "بدون دستگاه ورودی" - }, - "No input devices found": { - "No input devices found": "هیچ دستگاه ورودی‌ای یافت نشد" - }, - "No items added yet": { - "No items added yet": "هنوز آیتمی اضافه نشده" - }, - "No keybinds found": { - "No keybinds found": "هیچ نگاشت‌کلیدی یافت نشد" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "هیچ افزونه‌ لانچری نصب نشده است." - }, - "No match criteria": { - "No match criteria": "هیچ انطباق معیاری یافت نشد" - }, - "No matches": { - "No matches": "موردی پیدا نشد" - }, - "No matching processes": { - "No matching processes": "فرآیند موردنظر یافت نشد" - }, - "No monitors": { - "No monitors": "بدون مانیتور" - }, - "No mount points found": { - "No mount points found": "هیچ نقاط اتصالی یافت نشد" - }, - "No output device": { - "No output device": "بدون دستگاه خروجی" - }, - "No output devices found": { - "No output devices found": "هیچ دستگاه خروجی‌ای یافت نشد" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "بدون نتایج افزونه" - }, - "No plugins found": { - "No plugins found": "افزونه‌ای یافت نشد" - }, - "No plugins found.": { - "No plugins found.": "افزونه‌ای یافت نشد." - }, - "No printer found": { - "No printer found": "هیچ چاپگری یافت نشد" - }, - "No printers configured": { - "No printers configured": "هیچ چاپگری پیکربندی نشده است" - }, - "No printers found": { - "No printers found": "هیچ چاپگری یافت نشد" - }, - "No profiles": { - "No profiles": "هیچ پروفایلی یافت نشد" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "هیچ مدخل کلیپ‌بورد اخیری یافت نشد" - }, - "No results found": { - "No results found": "هیچ نتیجه‌ای یافت نشد" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "هیچ مدخل کلیپ‌بوردی ذخیره نشده است" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "هیچ تمی یافت نشد" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "هیچ تمی نصب نشده. تم‌ها را برای نصب از مخزن مرور کنید." - }, - "No trigger": { - "No trigger": "بدون راه‌انداز" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "تصویر پس‌زمینه‌ای انتخاب نشده" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "هیچ تصویر پس‌زمینه‌ای یافت نشد\n\nروی آیکون پوشه زیر برای مرور کلیک کنید" - }, - "No warnings": { - "No warnings": "بدون اخطار" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "هیچ ابزارکی افزوده نشده است. برای شروع روی «افزودن ابزارک» کلیک کنید." - }, - "No widgets available": { - "No widgets available": "هیچ ابزارکی موجود نیست" - }, - "No widgets match your search": { - "No widgets match your search": "هیچ ابزارکی با جستجوی شما مطابقت ندارد" - }, - "No window rules configured": { - "No window rules configured": "هیچ قاعده پنجره‌ای پیکربندی نشده" - }, - "None": { - "None": "هیچکدام" - }, - "Normal": { - "Normal": "عادی" - }, - "Normal Font": { - "Normal Font": "فونت معمولی" - }, - "Normal Priority": { - "Normal Priority": "اولویت عادی" - }, - "Not available": { - "Not available": "در دسترس نیست" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "متصل نیست" - }, - "Not detected": { - "Not detected": "تشخیص داده نشد" - }, - "Not paired": { - "Not paired": "جفت نشده" - }, - "Not set": { - "Not set": "تنظیم نشده" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "نکته: این فقط درصد را تغییر می‌دهد، به طور واقعی محدودیت روی شارژ کردن اعمال نمی‌کند." - }, - "Notepad": { - "Notepad": "دفترچه یادداشت" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "تنظیمات دفترچه یادداشت" - }, - "Notepad Slideout": { - "Notepad Slideout": "دفترچه یادداشت کشویی" - }, - "Nothing": { - "Nothing": "هیچ" - }, - "Nothing to see here": { - "Nothing to see here": "چیزی برای مشاهده نیست" - }, - "Notification Center": { - "Notification Center": "مرکز اعلانات" - }, - "Notification Display": { - "Notification Display": "نمایشگر اعلان" - }, - "Notification Overlay": { - "Notification Overlay": "نمایش اعلان‌ها بر لایه overlay" - }, - "Notification Popups": { - "Notification Popups": "پاپ‌آپ اعلان‌ها" - }, - "Notification Rules": { - "Notification Rules": "قواعد اعلان‌ها" - }, - "Notification Settings": { - "Notification Settings": "تنظیمات اعلان‌ها" - }, - "Notification Timeouts": { - "Notification Timeouts": "وقفه اعلان‌ها" - }, - "Notification toast popups": { - "Notification toast popups": "پاپ‌آپ‌های اعلان به صورت تُست" - }, - "Notifications": { - "Notifications": "اعلان‌ها" - }, - "Numbers": { - "Numbers": "شماره‌ها" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "عددی (ماه/روز)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "عددی (روز/ماه)" - }, - "OK": { - "OK": "خوب" - }, - "OS Logo": { - "OS Logo": "لوگوی OS" - }, - "OSD Position": { - "OSD Position": "مکان OSD" - }, - "Occupied Color": { - "Occupied Color": "رنگ اشغال شده" - }, - "Off": { - "Off": "خاموش" - }, - "Office": { - "Office": "اداری" - }, - "Offline": { - "Offline": "آفلاین" - }, - "Offline Report": { - "Offline Report": "گزارش آفلاین" - }, - "Older": { - "Older": "قدیمی‌تر" - }, - "On": { - "On": "روشن" - }, - "On-Demand": { - "On-Demand": "هنگام درخواست" - }, - "On-Screen Displays": { - "On-Screen Displays": "نمایشگر‌های بر صفحه" - }, - "On-screen Displays": { - "On-screen Displays": "نمایشگر‌های بر صفحه (OSD)" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "گاما را فقط بر اساس قواعد زمانی یا مکانی تنظیم کن." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "تنها پنجره‌ها در مانیتور کنونی را در هر داک نمایش بده" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "فقط در صورتی قابل مشاهده است که سیستم شما از هایبرنیت پشتیبانی کند" - }, - "Opacity": { - "Opacity": "شفافیت" - }, - "Opaque": { - "Opaque": "کدر" - }, - "Open": { - "Open": "باز‌ کردن" - }, - "Open App": { - "Open App": "باز کردن برنامه" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "برنامه KDE Connect را در گوشی خود باز کنید" - }, - "Open Notepad File": { - "Open Notepad File": "باز‌ کردن فایل دفترچه یادداشت" - }, - "Open a new note": { - "Open a new note": "باز کردن یادداشت جدید" - }, - "Open folder": { - "Open folder": "باز کردن پوشه" - }, - "Open in Browser": { - "Open in Browser": "باز کردن در مرورگر" - }, - "Open in terminal": { - "Open in terminal": "باز کردن در ترمینال" - }, - "Open search bar to find text": { - "Open search bar to find text": "باز‌ کردن نوار جستجو برای یافتن متن" - }, - "Open with...": { - "Open with...": "باز کردن با..." - }, - "Opening SMS": { - "Opening SMS": "باز کردن SMS" - }, - "Opening SMS app": { - "Opening SMS app": "باز کردن برنامه SMS" - }, - "Opening file browser": { - "Opening file browser": "باز کردن مرورگر فایل" - }, - "Opening files": { - "Opening files": "باز کردن فایل‌ها" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "توضیحات اختیاری" - }, - "Optional location": { - "Optional location": "مکان اختیاری" - }, - "Options": { - "Options": "گزینه‌ها" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "ابزارک‌ها را در گروه‌های تاشو سامان‌دهی کن" - }, - "Original: %1": { - "Original: %1": "اصل: %1" - }, - "Other": { - "Other": "دیگر" - }, - "Outline": { - "Outline": "خط بیرونی" - }, - "Output": { - "Output": "خروجی" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "محل خروج تقریبا پر است" - }, - "Output Area Full": { - "Output Area Full": "محل خروج پر است" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "دستگاه‌های خروجی" - }, - "Output Tray Missing": { - "Output Tray Missing": "سینی خروج موجود نیست" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Include خروجی‌ها یافت نشد" - }, - "Overcast": { - "Overcast": "کاملاْ ابری" - }, - "Overflow": { - "Overflow": "سرریزی" - }, - "Overridden by config": { - "Overridden by config": "جایگزین شده توسط پیکربندی" - }, - "Override": { - "Override": "جایگزین" - }, - "Override Border Size": { - "Override Border Size": "بازنویسی اندازه حاشیه" - }, - "Override Corner Radius": { - "Override Corner Radius": "جایگزینی شعاع گوشه‌ها" - }, - "Override Gaps": { - "Override Gaps": "جایگزینی فاصله‌ها" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "تنظیمات چیدمان عمومی را برای این خروجی جایگزین کن" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "جایگزینی‌ها" - }, - "Overview": { - "Overview": "نمای کلی" - }, - "Overview of your network connections": { - "Overview of your network connections": "نمای کلی از اتصالات شبکه شما" - }, - "Overwrite": { - "Overwrite": "بازنویسی" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "حاشیه‌دار" - }, - "Pad Hours": { - "Pad Hours": "حاشیه‌گذاری ساعات" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "فاصله درونی" - }, - "Pair": { - "Pair": "جفت‌سازی" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "جفت‌سازی دستگاه بلوتوثی" - }, - "Paired": { - "Paired": "جفت شده" - }, - "Pairing": { - "Pairing": "درحال جفت‌سازی" - }, - "Pairing failed": { - "Pairing failed": "جفت‌سازی ناموفق بود" - }, - "Pairing request from": { - "Pairing request from": "درخواست جفت‌سازی از" - }, - "Pairing request sent": { - "Pairing request sent": "درخواست جفت‌سازی فرستاده شد" - }, - "Pairing requested": { - "Pairing requested": "جفت‌سازی درخواست شد" - }, - "Pairing...": { - "Pairing...": "درحال جفت شدن..." - }, - "Partly Cloudy": { - "Partly Cloudy": "نیمه ابری" - }, - "Passkey:": { - "Passkey:": "کلید عبور:" - }, - "Password": { - "Password": "گذرواژه" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "الصاق" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "الگو" - }, - "Pause": { - "Pause": "توقف" - }, - "Paused": { - "Paused": "متوقف شده" - }, - "Pending": { - "Pending": "در حال بررسی" - }, - "Pending Charge": { - "Pending Charge": "در انتظار شارژ" - }, - "Pending Discharge": { - "Pending Discharge": "در انتظار تخلیه شارژ" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "تصاویر پس‌زمینه اختصاصی هر حالت" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "تصویر پس‌زمینه برای هر مانیتور" - }, - "Per-screen config": { - "Per-screen config": "پیکربندی به ازای هر صفحه" - }, - "Percentage": { - "Percentage": "درصد" - }, - "Performance": { - "Performance": "کارایی" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "اجازه تنظیم تصویر نمایه داده نشد." - }, - "Personalization": { - "Personalization": "شخصی‌سازی" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect دردسترس نیست" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "عدم دسترسی Phone Connect" - }, - "Phone number": { - "Phone number": "شماره تلفن" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "تصاویر" - }, - "Pin": { - "Pin": "سنجاق" - }, - "Pin to Dock": { - "Pin to Dock": "سنجاق به داک" - }, - "Ping": { - "Ping": "پینگ" - }, - "Ping sent": { - "Ping sent": "پینگ فرستاده شد" - }, - "Ping sent to": { - "Ping sent to": "پینگ فرستاده شد به" - }, - "Pinned": { - "Pinned": "سنجاق شده" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "برنامه‌های سنجاق شده و درحال اجرا به همراه کشیدن و رها کردن" - }, - "Pixelate": { - "Pixelate": "پیکسلی کردن" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "دایرکتوری افزونه‌ها را اینجا قرار دهید. هر افزونه باید فایل مشخصات plugins.json داشته باشد." - }, - "Place plugins in %1": { - "Place plugins in %1": "افزونه‌ها را در %1 قرار بده" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "وقتی اعلان جدید وارد شد صدا را پخش کن" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "وقتی کابل شارژر وصل شد صدا را پخش کن" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "وقتی حجم صدا تنظیم شد صدا را پخش کن" - }, - "Play sounds for system events": { - "Play sounds for system events": "برای رویداد‌های سیستمی صدا را پخش کن" - }, - "Playback": { - "Playback": "پخش" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "لطفا صبر کنید..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "اتصال به برق" - }, - "Plugged in": { - "Plugged in": "اتصال به برق" - }, - "Plugin": { - "Plugin": "افزونه" - }, - "Plugin Directory": { - "Plugin Directory": "دایرکتوری افزونه" - }, - "Plugin Management": { - "Plugin Management": "مدیریت افزونه" - }, - "Plugin Visibility": { - "Plugin Visibility": "نمایانی افزونه‌ها" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "افزونه غیرفعال است - برای استفاده آن را در تنظیمات افزونه‌ها فعال کنید" - }, - "Plugins": { - "Plugins": "افزونه‌ها" - }, - "Pointer": { - "Pointer": "اشاره‌گر" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "پاپ‌آپ‌ها" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "پاپ‌آپ‌ها و مودال‌ها از سرعت انیمیشن سراسری پیروی کنند (برای سفارشی‌سازی جداگانه غیرفعال کنید)" - }, - "Popup Only": { - "Popup Only": "فقط پاپ‌آپ" - }, - "Popup Position": { - "Popup Position": "مکان پاپ‌آپ" - }, - "Popup Shadow": { - "Popup Shadow": "سایه پاپ‌آپ" - }, - "Popup Transparency": { - "Popup Transparency": "شفافیت پاپ‌آپ" - }, - "Popup behavior, position": { - "Popup behavior, position": "رفتار پاپ‌آپ، مکان" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "پورتال" - }, - "Position": { - "Position": "مکان" - }, - "Position, pinned apps": { - "Position, pinned apps": "مکاان، برنامه‌های سنجاق شده" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "امکان تداخل جایگزین‌ها" - }, - "Power": { - "Power": "پاور" - }, - "Power & Security": { - "Power & Security": "پاور و امنیت" - }, - "Power & Sleep": { - "Power & Sleep": "پاور و خواب" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "تأیید اقدام پاور" - }, - "Power Menu Customization": { - "Power Menu Customization": "سفارشی‌سازی منوی پاور" - }, - "Power Off": { - "Power Off": "خاموش" - }, - "Power Options": { - "Power Options": "گزینه‌های پاور" - }, - "Power Profile": { - "Power Profile": "پروفایل پاور" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "تنزل‌دادن پروفایل پاور" - }, - "Power Saver": { - "Power Saver": "ذخیره انرژی" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "خاموش کردن مانیتورها هنگام قفل" - }, - "Power profile management available": { - "Power profile management available": "مدیریت پروفایل پاور در دسترس" - }, - "Power source": { - "Power source": "منبع پاور" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "بارش" - }, - "Precipitation": { - "Precipitation": "احتمال بارش" - }, - "Precipitation Chance": { - "Precipitation Chance": "احتمال بارش" - }, - "Preference": { - "Preference": "تنظیمات" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "عرض‌های از پیش تعیین شده (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "دکمه Enter را فشار دهید و سیستم صوتی برای اعمال تغییرات راه‌اندازی مجدد خواهد شد" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "برای الصاق Enter، برای کپی Shift+Enter را فشار دهید" - }, - "Press key...": { - "Press key...": "کلید را فشار دهید..." - }, - "Pressure": { - "Pressure": "فشار" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "وقفه جلوگیری از خاموش‌شدن صفحه" - }, - "Preview": { - "Preview": "پیش‌نمایش" - }, - "Primary": { - "Primary": "اصلی" - }, - "Primary Container": { - "Primary Container": "زمینه اصلی" - }, - "Print Server Management": { - "Print Server Management": "مدیریت سرور چاپ" - }, - "Print Server not available": { - "Print Server not available": "سرور چاپ در دسترس نیست" - }, - "Printer": { - "Printer": "چاپگر" - }, - "Printer Classes": { - "Printer Classes": "کلاس‌های چاپگر" - }, - "Printer created successfully": { - "Printer created successfully": "چاپگر با موفقیت ایجاد شد" - }, - "Printer deleted": { - "Printer deleted": "چاپگر حذف شد" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "نام چاپگر (بدون فاصله)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "چاپگر‌ها" - }, - "Printers: ": { - "Printers: ": "چاپگر‌ها: " - }, - "Prioritize performance": { - "Prioritize performance": "اولویت با کارایی" - }, - "Priority": { - "Priority": "اولویت" - }, - "Privacy Indicator": { - "Privacy Indicator": "نشانگر حریم خصوصی" - }, - "Privacy Mode": { - "Privacy Mode": "حالت حریم خصوصی" - }, - "Private Key Password": { - "Private Key Password": "کلید خصوصی گذرواژه" - }, - "Process Count": { - "Process Count": "تعداد فرایند‌ها" - }, - "Processes": { - "Processes": "فرایندها" - }, - "Processes:": { - "Processes:": "فرایندها:" - }, - "Processing": { - "Processing": "درحال پردازش" - }, - "Profile Image Error": { - "Profile Image Error": "خطای تصویر نمایه" - }, - "Profile activated: %1": { - "Profile activated: %1": "پروفایل فعال شد: %1" - }, - "Profile deleted": { - "Profile deleted": "پروفایل حذف شد" - }, - "Profile error": { - "Profile error": "خطای پروفایل" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "تصویر پروفایل بیش‌از حد بزرگ است. لطفا از تصویر کوچکتر استفاده کنید." - }, - "Profile name": { - "Profile name": "نام پروفایل" - }, - "Profile not found": { - "Profile not found": "پروفایل یافت نشد" - }, - "Profile saved: %1": { - "Profile saved: %1": "پروفایل ذخیره شد: %1" - }, - "Protocol": { - "Protocol": "پروتکل" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "دسترسی سریع" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "دسترسی سریع به لانچر برنامه" - }, - "Quick access to color picker": { - "Quick access to color picker": "دسترسی سریع به انتخابگر رنگ" - }, - "Quick access to notepad": { - "Quick access to notepad": "دسترسی سریع به دفترچه یادداشت" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "پنل کشویی یادداشت‌برداری سریع" - }, - "Quick system toggles": { - "Quick system toggles": "تنظیمات سریع" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "شعاع" - }, - "Rain": { - "Rain": "باران" - }, - "Rain Chance": { - "Rain Chance": "احتمال بارش" - }, - "Rainbow": { - "Rainbow": "رنگین‌کمان" - }, - "Random": { - "Random": "تصادفی" - }, - "Rate": { - "Rate": "نرخ انتقال" - }, - "Read:": { - "Read:": "خواندن:" - }, - "Reason": { - "Reason": "علت" - }, - "Reboot": { - "Reboot": "راه‌اندازی مجدد" - }, - "Recent Colors": { - "Recent Colors": "رنگ‌های اخیر" - }, - "Recently Used Apps": { - "Recently Used Apps": "برنامه‌های استفاده شده اخیر" - }, - "Recommended available": { - "Recommended available": "پیشنهادی موجود است" - }, - "Refresh": { - "Refresh": "تازه‌سازی" - }, - "Refresh Weather": { - "Refresh Weather": "تازه‌سازی آب و هوا" - }, - "Regex": { - "Regex": "رجکس" - }, - "Reject": { - "Reject": "رد کردن" - }, - "Reject Jobs": { - "Reject Jobs": "ردکردن کارهای چاپ" - }, - "Release": { - "Release": "رها کردن" - }, - "Reload Plugin": { - "Reload Plugin": "بارگذاری مجدد افزونه" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "حذف" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "حذف فاصله درونی ابزارک" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "حذف فاصله‌ها و حاشیه هنگام بزرگ‌کردن پنجره‌ها" - }, - "Rename": { - "Rename": "تغییر نام" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "تغییر نام محیط‌کار" - }, - "Repeat": { - "Repeat": "تکرار" - }, - "Replacement": { - "Replacement": "جایگزین" - }, - "Report": { - "Report": "گزارش" - }, - "Request Pairing": { - "Request Pairing": "درخواست جفت‌سازی" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "برای تأیید خاموش، راه‌اندازی مجدد، تعلیق، هایبرنیت و خروج، نگه داشتن دکمه/کلید را الزام کن" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "به %1 نیاز دارد" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "به ابزار 'dgop' نیاز دارد" - }, - "Requires DMS %1": { - "Requires DMS %1": "به DMS %1 نیاز دارد" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "به کامپازیتور DWL نیاز دارد" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "به پشتیبانی حالت شب نیاز دارد" - }, - "Reset": { - "Reset": "تنظیم مجدد" - }, - "Reset Position": { - "Reset Position": "تنظیم مجدد مکان" - }, - "Reset Size": { - "Reset Size": "تنظیم مجدد اندازه" - }, - "Reset to default name": { - "Reset to default name": "تنظیم مجدد به نام پیش‌فرض" - }, - "Resize Widget": { - "Resize Widget": "تغییر اندازه ابزارک" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "وضوح و تازه‌سازی" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "وضوح، مکان، بزرگنمایی" - }, - "Restart DMS": { - "Restart DMS": "راه‌اندازی مجدد DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "دَنک متریال شل را مجدد راه بینداز" - }, - "Restarting audio system...": { - "Restarting audio system...": "راه‌اندازی مجدد سیستم صوتی..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "ازسرگیری" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "جهت اسکرول معکوس" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "جهت تغییر محیط‌کار را هنگام اسکرول‌کردن روی نوار معکوس کن" - }, - "Revert": { - "Revert": "برگرداندن" - }, - "Right": { - "Right": "راست" - }, - "Right Center": { - "Right Center": "راست وسط" - }, - "Right Section": { - "Right Section": "بخش راست" - }, - "Right Tiling": { - "Right Tiling": "تایلینگ راست" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "راست‌کلیک کرده و بر هر جایی از ابزارک بکشید" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "راست‌کلیک کرده و گوشه پایین سمت راست را بکشید" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "برای تغییر چیدمان، روی ابزارک نوار راست‌کلیک کنید" - }, - "Ring": { - "Ring": "زنگ زدن" - }, - "Ringing": { - "Ringing": "درحال زنگ زدن" - }, - "Ripple Effects": { - "Ripple Effects": "افکت موجی" - }, - "Root Filesystem": { - "Root Filesystem": "سیستم‌فایل ریشه" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "گوشه‌های گرد برای پنجره‌ها" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "گوشه‌های گرد برای پنجره‌ها (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "گوشه‌های گرد برای پنجره‌ها (decoration.rounding)" - }, - "Rule": { - "Rule": "قاعده" - }, - "Rule Name": { - "Rule Name": "نام قاعده" - }, - "Rules (%1)": { - "Rules (%1)": "قواعد (%1)" - }, - "Run Again": { - "Run Again": "اجرای دوباره" - }, - "Run DMS Templates": { - "Run DMS Templates": "اجرای قالب‌های DMS" - }, - "Run User Templates": { - "Run User Templates": "اجرای قالب‌های کاربر" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "اجرای یک برنامه (مانند firefox، kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "اجرای یک دستور شِل (مانند notify-send)" - }, - "Running Apps": { - "Running Apps": "برنامه‌های درحال اجرا" - }, - "Running Apps Settings": { - "Running Apps Settings": "تنظیمات برنامه‌های درحال اجرا" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "روشنایی SDR" - }, - "SDR Saturation": { - "SDR Saturation": "اشباع رنگ SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "ذخیره" - }, - "Save Notepad File": { - "Save Notepad File": "ذخیره فایل دفترچه یادداشت" - }, - "Save QR Code": { - "Save QR Code": "ذخیره کد QR" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "ذخیره و جابه‌جایی بین پیکربندی‌های نمایشگر" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "اعلان‌ها با اولویت حیاتی را در تاریخچه ذخیره کن" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "اعلان‌های رد شده را در تاریخچه ذخیره کن" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "اعلان‌ها با اولویت پایین را در تاریخچه ذخیره کن" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "اعلان‌ها با اولویت عادی را در تاریخچه ذخیره کن" - }, - "Save password": { - "Save password": "ذخیره گذرواژه" - }, - "Saved": { - "Saved": "ذخیره شد" - }, - "Saved Configurations": { - "Saved Configurations": "پیکربندی‌های ذخیره شده" - }, - "Saved Note": { - "Saved Note": "یادداشت ذخیره شده" - }, - "Saved item deleted": { - "Saved item deleted": "مورد ذخیره شده حذف شد" - }, - "Saving...": { - "Saving...": "درحال ذخیره..." - }, - "Scale": { - "Scale": "بزرگنمایی" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "اندازه فونت نوار دَنک را به صورت مستقل مقیاس کن" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "اندازه آیکون‌های نوار دَنک را به صورت مستقل مقیاس کن" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "تمام اندازه‌های فونت در سراسر شِل مقیاس کن" - }, - "Scan": { - "Scan": "اسکن" - }, - "Scanning": { - "Scanning": "درحال اسکن" - }, - "Scanning...": { - "Scanning...": "درحال اسکن..." - }, - "Science": { - "Science": "علمی" - }, - "Score": { - "Score": "امتیاز" - }, - "Screen Sharing": { - "Screen Sharing": "اشتراک‌گذاری صفحه" - }, - "Screen sharing": { - "Screen sharing": "اشتراک‌گذاری صفحه" - }, - "Scroll": { - "Scroll": "اسکرول" - }, - "Scroll Factor": { - "Scroll Factor": "ضریب اسکرول" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "چرخ اسکرول" - }, - "Scroll song title": { - "Scroll song title": "حرکت عنوان آهنگ" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "اگر عنوان در ابزارک جا نشد آن را حرکت بده" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "رفتار چرخ اسکرول در ابزارک رسانه" - }, - "Scrolling": { - "Scrolling": "اسکرولینگ" - }, - "Search App Actions": { - "Search App Actions": "جستجوی اقدام برنامه‌ها" - }, - "Search Options": { - "Search Options": "گزینه‌های جستجو" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "با ترکیب کلید‌ها، توضیحات یا نام اقدام‌ جستجو کنید.\n\nاقدام پیش‌فرض نگاشت‌کلید را در کلیپ‌بورد کپی می‌کند.\nبرای سنجاق‌ کردن نگاشت‌کلید‌های پر استفاده راست‌کلیک کنید یا پیکان راست را فشار دهید - آن‌ها هنگام جستجو نکردن در بالای لیست ظاهر خواهند شد." - }, - "Search for a location...": { - "Search for a location...": "جستجو برای موقعیت مکانی..." - }, - "Search keybinds...": { - "Search keybinds...": "جستجو در نگاشت‌کلیدها..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "میانبر‌های صفحه‌کلید از کامپازیتور یا برنامه‌هایتان را جستجو کنید" - }, - "Search plugins...": { - "Search plugins...": "جستجوی افزونه‌ها..." - }, - "Search processes...": { - "Search processes...": "جستجوی فرایند‌ها..." - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "جستجوی تم‌ها..." - }, - "Search widgets...": { - "Search widgets...": "جستجوی ابزارک‌ها..." - }, - "Search...": { - "Search...": "جستجو..." - }, - "Searching...": { - "Searching...": "درحال جستجو..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "ثانویه" - }, - "Secured": { - "Secured": "ایمن" - }, - "Security": { - "Security": "امنیت" - }, - "Security & privacy": { - "Security & privacy": "امنیت و حریم خصوصی" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "انتخاب" - }, - "Select Application": { - "Select Application": "انتخاب برنامه" - }, - "Select Bar": { - "Select Bar": "انتخاب نوار" - }, - "Select Custom Theme": { - "Select Custom Theme": "انتخاب تم سفارشی" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "لوگوی لانچر داک را انتخاب کنید" - }, - "Select File to Send": { - "Select File to Send": "فایل برای ارسال انتخاب کنید" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "انتخاب لوگوی لانچر" - }, - "Select Profile Image": { - "Select Profile Image": "انتخاب تصویر نمایه" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "انتخاب تصویر پس‌زمینه" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "انتخاب دایرکتوری تصاویر پس‌زمینه" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "انتخاب رنگ از پالت رنگی یا اسلایدر‌های سفارشی" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "یک ابزارک برای افزودن به دسکتاپ خود انتخاب کنید. هر ابزارک یک نمونه جداگانه با تنظیمات خاص خود است." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "یک ابزارک برای افزودن انتخاب کنید. در صورت نیاز می‌توانید چندین نمونه از یک ابزارک را اضافه کنید." - }, - "Select a window...": { - "Select a window...": "یک پنجره انتخاب کنید..." - }, - "Select an image file...": { - "Select an image file...": "انتخاب فایل تصویر..." - }, - "Select at least one provider": { - "Select at least one provider": "حداقل یک ارائه‌دهنده انتخاب کنید" - }, - "Select device": { - "Select device": "انتخاب دستگاه" - }, - "Select device...": { - "Select device...": "انتخاب دستگاه..." - }, - "Select driver...": { - "Select driver...": "انتخاب درایور..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "وزن فونت برای متن UI انتخاب کنید" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "مانیتور را برای پیکربندی تصویر پس‌زمینه انتخاب کنید" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "فونت monospace را برای فهرست فرایند‌ها و نمایشگر‌های فنی انتخاب کنید" - }, - "Select network": { - "Select network": "انتخاب شبکه" - }, - "Select system sound theme": { - "Select system sound theme": "انتخاب تم صدای سیستم" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "خانواده فونت را برای متن UI انتخاب کنید" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "انتخاب الگوریتم پالت رنگی استفاده شده برای رنگ‌های بر اساس تصویر پس‌زمینه" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "انتخاب کنید که کدام ارائه دهنده نگاشت‌کلید‌ها include شود" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "انتخاب کنید کدام گذارها در تصادفی‌سازی باشند" - }, - "Select...": { - "Select...": "انتخاب..." - }, - "Selected image file not found.": { - "Selected image file not found.": "فایل تصویر انتخاب شده یافت نشد." - }, - "Send": { - "Send": "ارسال" - }, - "Send Clipboard": { - "Send Clipboard": "ارسال کلیپ‌بورد" - }, - "Send File": { - "Send File": "ارسال فایل" - }, - "Send SMS": { - "Send SMS": "ارسال SMS" - }, - "Sending": { - "Sending": "درحال ارسال" - }, - "Separator": { - "Separator": "جداکننده" - }, - "Server": { - "Server": "سرور" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "تنظیم نام سفارشی دستگاه" - }, - "Set custom name": { - "Set custom name": "تنظیم نام سفارشی" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "برای دستگاه‌های ورودی صوتی خود نام سفارشی تنظیم کنید" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "برای دستگاه‌های خروجی صوتی خود نام سفارشی تنظیم کنید" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "تصاویر پس‌زمینه مختلف برای هر مانیتور متصل تنظیم کن" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "تصاویر پس‌زمینه مختلف برای حالت روشن و تاریک تنظیم کن" - }, - "Set key and action to save": { - "Set key and action to save": "کلید و اقدام را برای ذخیره تنظیم کنید" - }, - "Set notification rules": { - "Set notification rules": "تنظیم قوانین اعلان‌ها" - }, - "Settings": { - "Settings": "تنظیمات" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "تنظیمات فقط قابل خواندن هستند. تغییرات حفظ نخواهند شد." - }, - "Setup": { - "Setup": "راه‌اندازی" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "اشتراک‌گذاری" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "اشتراک‌گذاری تنظیمات کنترل گاما" - }, - "Share Text": { - "Share Text": "اشتراک‌گذاری متن" - }, - "Share URL": { - "Share URL": "اشتراک‌گذاری URL" - }, - "Shared": { - "Shared": "به اشتراک گذاشته شد" - }, - "Shell": { - "Shell": "شِل" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: پاک‌کردن همه • Esc: بستن" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "برای الصاق Shift+Enter" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: کپی • Shift+Del: پاک‌کردن همه • Esc: بستن" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: الصاق • Shift+Del: پاک‌کردن همه • Esc: بستن" - }, - "Short": { - "Short": "کوتاه" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "میانبرها" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "میانبر‌ها (%1)" - }, - "Show": { - "Show": "نمایش" - }, - "Show 3rd Party": { - "Show 3rd Party": "نمایش شخص ثالث" - }, - "Show All Tags": { - "Show All Tags": "نمایش همه برچسب‌ها" - }, - "Show Badge": { - "Show Badge": "نمایش نشان" - }, - "Show CPU": { - "Show CPU": "نمایش CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "نمایش نمودار CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "نمایش دمای CPU" - }, - "Show Date": { - "Show Date": "نمایش تاریخ" - }, - "Show Disk": { - "Show Disk": "نمایش دیسک" - }, - "Show Dock": { - "Show Dock": "نمایش داک" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "نمایش دمای حسی" - }, - "Show Footer": { - "Show Footer": "نمایش پاورقی" - }, - "Show Forecast": { - "Show Forecast": "نمایش پیش‌بینی" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "نمایش دمای GPU" - }, - "Show Header": { - "Show Header": "نمایش سربرگ" - }, - "Show Hibernate": { - "Show Hibernate": "نمایش هایبرنیت" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "نمایش شماره‌های ساعت" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "نمایش پیش‌بینی‌های ساعتی" - }, - "Show Humidity": { - "Show Humidity": "نمایش رطوبت" - }, - "Show Launcher Button": { - "Show Launcher Button": "دکمه لانچر را نمایش بده" - }, - "Show Line Numbers": { - "Show Line Numbers": "نمایش شماره خطوط" - }, - "Show Location": { - "Show Location": "نمایش موقعیت مکانی" - }, - "Show Lock": { - "Show Lock": "نمایش قفل" - }, - "Show Log Out": { - "Show Log Out": "نمایش خروج" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "انیمیشن موجی متریال دیزاین روی عناصر تعاملی نمایش بده" - }, - "Show Media Player": { - "Show Media Player": "نمایش پخش‌کننده رسانه" - }, - "Show Memory": { - "Show Memory": "نمایش حافظه" - }, - "Show Memory Graph": { - "Show Memory Graph": "نمایش نمودار حافظه" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "نمایش شبکه" - }, - "Show Network Graph": { - "Show Network Graph": "نمایش نمودار شبکه" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "نمایش فقط محیط‌کار اشغال شده" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "نمایش نشان تعداد سرریز" - }, - "Show Password Field": { - "Show Password Field": "نمایش فیلد گذرواژه" - }, - "Show Power Actions": { - "Show Power Actions": "نمایش اقدام‌های پاور" - }, - "Show Power Off": { - "Show Power Off": "نمایش خاموش‌کردن" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "نمایش احتمال بارش" - }, - "Show Pressure": { - "Show Pressure": "نمایش فشار" - }, - "Show Profile Image": { - "Show Profile Image": "نمایش تصویر نمایه" - }, - "Show Reboot": { - "Show Reboot": "نمایش راه‌اندازی مجدد" - }, - "Show Restart DMS": { - "Show Restart DMS": "نمایش راه‌اندازی مجدد DMS" - }, - "Show Saved Items": { - "Show Saved Items": "نمایش موارد ذخیره شده" - }, - "Show Seconds": { - "Show Seconds": "نمایش ثانیه‌ها" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "نمایش طلوع/غروب" - }, - "Show Suspend": { - "Show Suspend": "نمایش تعلیق" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "نمایش تاریخ سیستم" - }, - "Show System Icons": { - "Show System Icons": "نمایش آیکون‌های سیستم" - }, - "Show System Time": { - "Show System Time": "نمایش زمان سیستم" - }, - "Show Top Processes": { - "Show Top Processes": "نمایش فرایند‌های مهم" - }, - "Show Weather Condition": { - "Show Weather Condition": "نمایش شرایط آب و هوا" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "نمایش خوش آمدید" - }, - "Show Wind Speed": { - "Show Wind Speed": "نمایش سرعت باد" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "نمایش برنامه‌های محیط‌کار" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "نمایش کل ۹ برچسب به جای فقط برچسب‌های اشغال شده (فقط DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "یک خط بیرونی دور نشانگر محیط‌کار فوکوس شده نشان بده" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "نمایش مصورساز صوتی cava در ابزارک رسانه" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "لایه overlay تیره پشت پنجره مودال نمایش بده" - }, - "Show device": { - "Show device": "نمایش دستگاه" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "داک را هنگامی که پنجره‌های شناور با محیط آن همپوشانی ندارند نمایش بده" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "لایه overlay لانچر را هنگام تایپ در نمای کلی نیری نمایش بده. برای استفاده از لانچر دیگری غیرفعال کنید." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "حالت تب‌ها و راهنمایی‌های صفحه‌کلید را در پایین نمایش بده." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "نمایش در آخرین نمایشگر" - }, - "Show on Overlay": { - "Show on Overlay": "نمایش بر لایه overlay" - }, - "Show on Overview": { - "Show on Overview": "نمایش روی نمای کلی" - }, - "Show on Overview Only": { - "Show on Overview Only": "فقط روی نمای کلی نمایش بده" - }, - "Show on all connected displays": { - "Show on all connected displays": "نمایش همه نمایشگر‌های متصل" - }, - "Show on screens:": { - "Show on screens:": "نمایش روی صفحات:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "نمایشگر بر صفحه را هنگام تغییر روشنایی نمایش بده" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "نمایشگر بر صفحه را هنگام تغییر وضعیت قفل حروف بزرگ نمایش بده" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "نمایشگر بر صفحه را هنگام تغییر دستگاه‌های خروجی صوتی نمایش بده" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "نمایشگر بر صفحه را هنگام تغیر وضعیت مهارگر بیکاری نمایش بده" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "نمایشگر بر صفحه را هنگامی که وضعیت پخش‌کننده رسانه تغییر می‌کند نمایش بده" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "نمایشگر بر صفحه را هنگام تغییر حجم صدای پخش‌کننده رسانه نمایش بده" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "نمایشگر بر صفحه را هنگام بی‌صدا/صدادار شدن میکروفون نمایش بده" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "نمایشگر بر صفحه را هنگام تغییر پروفایل پاور نمایش بده" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "نمایشگر بر صفحه را هنگام تغییر حجم صدا نمایش بده" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "اطلاعات آب و هوا را در نوار بالا و مرکز کنترل نمایش بده" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "شماره شاخص محیط‌‎کار را در تغییردهنده محیط‌کار نوار بالا نمایش بده" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "نام محیط‌کار را در نوارهای افقی و اولین حرف را در نوار‌های عمودی نمایش بده" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "محیط‌کارهای مانیتور فوکوس شده کنونی را نمایش بده" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "همه برنامه‌های درحال اجرا را با نشانگر متمرکز نمایش می‌دهد" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "محیط‌کار کنونی را نمایش می‌دهد و امکان تغییر را فراهم می‌کند" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "زمانی که caps lock فعال است نمایش داده می‌شود" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "هنگامی که میکروفون، دوربین یا اشتراک‌گذاری صفحه فعال باشد نشان داده می‌شود" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "خاموش‌کردن" - }, - "Signal": { - "Signal": "سیگنال" - }, - "Signal:": { - "Signal:": "سیگنال:" - }, - "Size": { - "Size": "اندازه" - }, - "Size Constraints": { - "Size Constraints": "محدودیت‌های اندازه" - }, - "Size Offset": { - "Size Offset": "آفست اندازه" - }, - "Sizing": { - "Sizing": "اندازه‌دهی" - }, - "Skip": { - "Skip": "رد کردن" - }, - "Skip confirmation": { - "Skip confirmation": "رد کردن تأیید" - }, - "Skip setup": { - "Skip setup": "رد کردن راه‌اندازی" - }, - "Small": { - "Small": "کوچک" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "احراز هویت با کارت هوشمند" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN کارت هوشمند" - }, - "Snap": { - "Snap": "چسباندن" - }, - "Snow": { - "Snow": "برف" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "برخی افزونه‌ها نیازمند نسخه جدیدتر DMS هستند:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "مرتب‌سازی بر اساس حروف الفبا" - }, - "Sort By": { - "Sort By": "مرتب‌سازی براساس" - }, - "Sorting & Layout": { - "Sorting & Layout": "مرتب‌سازی و چیدمان" - }, - "Sound Theme": { - "Sound Theme": "تم صدا" - }, - "Sounds": { - "Sounds": "صدا‌ها" - }, - "Space between windows": { - "Space between windows": "فاصله بین پنجره‌ها" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "فاصله بین پنجره‌ها (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "فاصله بین پنجره‌ها (gaps_in و gaps_out)" - }, - "Spacer": { - "Spacer": "فاصله دهنده" - }, - "Spacing": { - "Spacing": "فاصله گذاری" - }, - "Speaker settings": { - "Speaker settings": "تنظیمات بلندگو" - }, - "Speed": { - "Speed": "سرعت" - }, - "Spool Area Full": { - "Spool Area Full": "فضای صف چاپ پر است" - }, - "Square Corners": { - "Square Corners": "گوشه‌های مربعی" - }, - "Stacked": { - "Stacked": "انباشته" - }, - "Standard": { - "Standard": "استاندارد" - }, - "Start": { - "Start": "شروع" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "برنامه KDE Connect یا Valent را آغاز کنید" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "برنامه KDE Connect یا Valent را برای استفاده از این افزونه آغاز کنید" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "تایپ‌کردن یادداشت‌هایتان را اینجا شروع کنید..." - }, - "State": { - "State": "وضعیت" - }, - "Status": { - "Status": "وضعیت" - }, - "Stopped": { - "Stopped": "متوقف شد" - }, - "Stopped Partly": { - "Stopped Partly": "تا حدی متوقف شد" - }, - "Stopping": { - "Stopping": "درحال توقف" - }, - "Stretch": { - "Stretch": "کشیده" - }, - "Stripes": { - "Stripes": "راه راه" - }, - "Summary": { - "Summary": "خلاصه" - }, - "Sunrise": { - "Sunrise": "طلوع" - }, - "Sunset": { - "Sunset": "غروب" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "هنگام فعال‌ بودن پاپ‌آپ‌های اعلان را مسدود می‌کند" - }, - "Surface": { - "Surface": "زمینه" - }, - "Surface Variant": { - "Surface Variant": "سطح متغیر" - }, - "Suspend": { - "Suspend": "تعلیق" - }, - "Suspend behavior": { - "Suspend behavior": "رفتار تعلیق" - }, - "Suspend system after": { - "Suspend system after": "تعلیق پس از" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "تعلیق سپس هایبرنیت" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "تغییر کاربر" - }, - "Switch to power profile": { - "Switch to power profile": "تغییر به پروفایل پاور" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "همگام‌سازی حالت با پورتال" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "همگام‌سازی پاپ‌آپ‌ها و مودال‌ها" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "همگام‌سازی مکان در تمامی صفحات" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "همگام‌سازی حالت تاریک با پورتال سیستم برای هماهنگی تم در سطح سیستم" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "سیستم" - }, - "System App Theming": { - "System App Theming": "تم‌دادن برنامه‌ سیستمی" - }, - "System Check": { - "System Check": "بررسی سیستم" - }, - "System Default": { - "System Default": "پیش‌فرض سیستم" - }, - "System Information": { - "System Information": "اطلاعات سیستم" - }, - "System Monitor": { - "System Monitor": "ناظر سیستم" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "ناظر سیستم در دسترس نیست" - }, - "System Sounds": { - "System Sounds": "صدا‌های سیستمی" - }, - "System Tray": { - "System Tray": "سینی سیستم" - }, - "System Update": { - "System Update": "بروزرسانی سیستم" - }, - "System Updater": { - "System Updater": "بروزرسان سیستم" - }, - "System Updates": { - "System Updates": "بروزرسانی‌های سیستم" - }, - "System notification area icons": { - "System notification area icons": "آیکون های ناحیه اعلان‌های سیستم" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "صدا‌های سیستم دردسترس نیستند. %1 را برای پشتیبانی صوتی نصب کنید." - }, - "System theme toggle": { - "System theme toggle": "تغییر تم سیستم" - }, - "System toast notifications": { - "System toast notifications": "اعلان‌های سیستم به صورت تُست" - }, - "System update custom command": { - "System update custom command": "دستور سفارشی بروزرسانی سیستم" - }, - "Tab": { - "Tab": "تب" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: پیمایش • ←→↑↓: پیمایش جدولی • Enter/Space: انتخاب" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "پارامتر‌های اضافی سفارشی ترمینال" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "ترمینال‌ها - همیشه از تم تاریک استفاده کن" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "صفحه تست" - }, - "Test page sent to printer": { - "Test page sent to printer": "صفحه تست به چاپگر ارسال شد" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "متن" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "ابزار «dgop» برای نظارت سیستم نیاز است.\nلطفا برای استفاده از این قابلیت dgop را نصب کنید." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "متغیر محیطی DMS_SOCKET تنظیم نشده یا سوکت موجود نیست. مدیریت افزونه خودکار به DMS_SOCKET نیاز دارد." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "تنظیمات پایین، تنظیمات Qt و GTK شما را تغییر می‌دهند. اگر می‌خواهید تنظیمات کنونی خود را نگه دارید، لطفا از آنها نسخه پشتیبان تهیه کنید (qt5ctl.conf |qt6ctl.conf و ~/.config/gtk-3.0|gtk-4.0)" - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "صف کار چاپگر خالی است" - }, - "Theme & Colors": { - "Theme & Colors": "تم و رنگ‌ها" - }, - "Theme Color": { - "Theme Color": "رنگ تم" - }, - "Theme Registry": { - "Theme Registry": "مخزن تم‌ها" - }, - "Themes": { - "Themes": "تم‌ها" - }, - "Thickness": { - "Thickness": "ضخامت" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "اخطار افزونه شخص ثالث" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "افزونه‌های شخص‌ثالث توسط کامیونیتی ساخته شده‌اند و به‌طور رسمی توسط دَنک متریال شل پشتیبانی نمی‌شوند.\n\nاین افزونه‌ها ممکن است خطرات امنیتی و حریم خصوصی داشته باشند - با مسئولیت خودتان نصب کنید." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "این نگاشت توسط config.kdl بازنویسی شده" - }, - "This may take a few seconds": { - "This may take a few seconds": "این ممکن است چند ثانیه طول بکشد" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "این افزونه اجازه «settings_write» را ندارد.\n\nبه plugins.json خط \"permissions\": [\"settings_read\", \"settings_write\"] را اضافه کنید" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "این ابزارک از حالت‌های خاموش شدن GPU جلوگیری می‌کند، که ​​می‌تواند به طور قابل توجهی بر عمر باتری لپ‌تاپ‌ها تأثیر بگذارد. استفاده از این ابزارک در لپ‌تاپ‌هایی با گرافیک هیبریدی توصیه نمی‌شود." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "این همه مدخل‌های سنجاق نشده را پاک می‌کند. %1 مدخل سنجاق شده نگه داشته می‌شوند." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "این کار تمام تاریخچه کلیپ‌بورد را برای همیشه حذف می‌کند." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "این به طور دائمی این مورد کلیپ‌بورد را حذف خواهد کرد. این عمل برگشت‌ناپذیر است." - }, - "Thunderstorm": { - "Thunderstorm": "رعد و برق" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "رعد و برق با تگرگ" - }, - "Tile": { - "Tile": "کاشی‌وار" - }, - "Tile H": { - "Tile H": "کاشی‌وار افقی" - }, - "Tile V": { - "Tile V": "کاشی‌وار عمودی" - }, - "Tiled": { - "Tiled": "کاشی‌شده" - }, - "Tiled State": { - "Tiled State": "حالت کاشی‌شده" - }, - "Tiling": { - "Tiling": "تایلینگ" - }, - "Time": { - "Time": "زمان" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "زمان و آب و هوا" - }, - "Time Format": { - "Time Format": "قالب زمان" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "زمان باقی‌مانده: %1" - }, - "Time until full: %1": { - "Time until full: %1": "زمان تا پر شدن:‌ %1" - }, - "Timed Out": { - "Timed Out": "زمان تمام شد" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "وقفه اعلان‌ها با اولویت حیاتی" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "وقفه اعلان‌ها با اولویت پایین" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "وقفه اعلان‌ها با اولویت عادی" - }, - "Title": { - "Title": "عنوان" - }, - "Title regex (optional)": { - "Title regex (optional)": "رجکس عنوان (اختیاری)" - }, - "To Full": { - "To Full": "تا پر شدن" - }, - "To update, run the following command:": { - "To update, run the following command:": "برای بروزرسانی، دستور زیر را اجرا کن:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "برای استفاده از این نگاشت DMS، نگاشت‌کلید را در config.kdl خود حذف کنید یا تغییر دهید" - }, - "Toast Messages": { - "Toast Messages": "پیام‌های تًست" - }, - "Today": { - "Today": "امروز" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "پیکربندی تغییر نمایش این نوار" - }, - "Toggling...": { - "Toggling...": "در حال تغییر وضعیت..." - }, - "Tomorrow": { - "Tomorrow": "فردا" - }, - "Tonal Spot": { - "Tonal Spot": "تُن برجسته" - }, - "Toner Empty": { - "Toner Empty": "تونر خالی است" - }, - "Toner Low": { - "Toner Low": "تونر کم است" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "ابزارها" - }, - "Top": { - "Top": "بالا" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "قالب نوار بالا" - }, - "Top Center": { - "Top Center": "بالا وسط" - }, - "Top Left": { - "Top Left": "بالا چپ" - }, - "Top Processes": { - "Top Processes": "فرایند‌های مهم" - }, - "Top Right": { - "Top Right": "بالا راست" - }, - "Top Section": { - "Top Section": "بخش بالا" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "تمام کار‌های چاپ" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "تبدیل" - }, - "Transition Effect": { - "Transition Effect": "افکت گذار" - }, - "Transparency": { - "Transparency": "شفافیت" - }, - "Trending GIFs": { - "Trending GIFs": "گیف‌های پرطرفدار" - }, - "Trending Stickers": { - "Trending Stickers": "برچسب‌های پرطرفدار" - }, - "Trigger": { - "Trigger": "راه‌انداز" - }, - "Trigger Prefix": { - "Trigger Prefix": "پیشوند راه‌انداز" - }, - "Trigger: %1": { - "Trigger: %1": "راه‌انداز: %1" - }, - "Trust": { - "Trust": "اعتماد" - }, - "Try a different search": { - "Try a different search": "یک جستجوی دیگر را امتحان کنید" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "همه نمایشگر‌ها را هنگامی که صفحه قفل فعال می‌شود بلادرنگ خاموش کن" - }, - "Turn off monitors after": { - "Turn off monitors after": "خاموش‌کردن مانیتور پس از" - }, - "Type": { - "Type": "نوع" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "حداقل ۲ کاراکتر تایپ کنید" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "این پیشوند را برای جستجوی نگاشت‌کلیدها تایپ کنید" - }, - "Type to search files": { - "Type to search files": "برای جستجوی فایل‌ها تایپ کنید" - }, - "Typography": { - "Typography": "تایپوگرافی" - }, - "Typography & Motion": { - "Typography & Motion": "تایپوگرافی و حرکت" - }, - "Unavailable": { - "Unavailable": "ناموجود" - }, - "Unfocused Color": { - "Unfocused Color": "رنگ فوکوس نشده" - }, - "Ungrouped": { - "Ungrouped": "گروه‌بندی نشده" - }, - "Uninstall": { - "Uninstall": "حذف" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "حذف افزونه" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "حذف ناموفق بود: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "حذف شده: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "درحال حذف: %1" - }, - "Unknown": { - "Unknown": "ناشناخته" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "هنرمند ناشناس" - }, - "Unknown Config": { - "Unknown Config": "پیکربندی ناشناخته" - }, - "Unknown Device": { - "Unknown Device": "دستگاه ناشناخته" - }, - "Unknown GPU": { - "Unknown GPU": "کارت گرافیک ناشناخته" - }, - "Unknown Monitor": { - "Unknown Monitor": "مانیتور ناشناخته" - }, - "Unknown Network": { - "Unknown Network": "شبکه ناشناخته" - }, - "Unknown Title": { - "Unknown Title": "عنوان ناشناس" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "خالی‌کردن هنگام بستن" - }, - "Unmute": { - "Unmute": "صدادار کردن" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "صدادار کردن پاپ‌آپ‌ها را برای %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "قاعده بی‌نام" - }, - "Unpair": { - "Unpair": "لغو جفت‌سازی" - }, - "Unpair failed": { - "Unpair failed": "لغو جفت‌سازی ناموفق بود" - }, - "Unpin": { - "Unpin": "برداشتن سنجاق" - }, - "Unpin from Dock": { - "Unpin from Dock": "جداکردن از داک" - }, - "Unsaved Changes": { - "Unsaved Changes": "تغییرات ذخیره نشده" - }, - "Unsaved changes": { - "Unsaved changes": "تغییرات ذخیره نشده" - }, - "Unsaved note...": { - "Unsaved note...": "یادداشت ذخیره نشده..." - }, - "Untitled": { - "Untitled": "بدون عنوان" - }, - "Untrust": { - "Untrust": "لغو اعتماد" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "بروزرسانی" - }, - "Update All": { - "Update All": "بروزرسانی همه" - }, - "Update Plugin": { - "Update Plugin": "بروزرسانی افزونه" - }, - "Uptime": { - "Uptime": "زمان اجرا" - }, - "Uptime:": { - "Uptime:": "زمان اجرا:" - }, - "Urgent Color": { - "Urgent Color": "رنگ ضروری" - }, - "Usage Tips": { - "Usage Tips": "راهنمای استفاده" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "از قالب 24 ساعته به جای 12 ساعته ق.ظ/ب.ظ استفاده کن" - }, - "Use Custom Command": { - "Use Custom Command": "استفاده از دستور سفارشی" - }, - "Use Grid Layout": { - "Use Grid Layout": "استفاده از چیدمان جدولی" - }, - "Use IP Location": { - "Use IP Location": "استفاده از موقعیت مکانی IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "استفاده از واحد‌های بریتانیایی" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "استفاده از واحد‌های بریتانیایی (°F, mph, inHg) به جای واحد‌های متریک (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "استفاده از فونت monospace" - }, - "Use System Theme": { - "Use System Theme": "استفاده از تم سیستم" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "از مدیریت تصویر پس‌زمینه خارجی مانند swww، hyprpaper یا swaybg استفاده کن." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "استفاده از نوارهای پیشرفت موجی متحرک برای پخش رسانه" - }, - "Use custom border size": { - "Use custom border size": "از اندازه حاشیه سفارشی استفاده کن" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "از طول حاشیه/focus-ring سفارشی استفاده کن" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "استفاده از دستور سفارشی برای بروزرسانی سیستم شما" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "از فاصله سفارشی به جای فاصله نوار استفاده کن" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "استفاده از شعاع پنجره سفارشی به جای شعاع تم" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "استفاده از گردی پنجره سفارشی به جای شعاع تم" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "از تم روشن به جای تم تاریک استفاده کن" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "از متر بر ثانیه به جای km/h برای سرعت باد استفاده کن" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "از کارت‌های اعلان کوچکتر استفاده کن" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "استفاده از تم صدا در تنظیمات سیستم" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "از مکان و اندازه یکسان بین تمامی نمایشگرها استفاده کن" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "از پیشوند راه‌انداز برای فعال‌کردن استفاده کن" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "وقتی رنگ تأکیدی سفارشی تنظیم شده استفاده می‌شود" - }, - "User": { - "User": "کاربر" - }, - "Username": { - "Username": "نام کاربری" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "از زمان‌های طلوع/غروب بر اساس موقعیت مکانی شما استفاده می‌کند." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "از زمان طلوع/غروب خورشید برای تنظیم خودکار حالت شب بر اساس موقعیت مکانی شما استفاده می‌کند." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "با استفاده از تنظیمات مشترک کنترل گاما" - }, - "Utilities": { - "Utilities": "برنامه‌های کمکی" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "اتصال‌های VPN" - }, - "VPN Password": { - "VPN Password": "گذرواژه VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "گذرواژه VPN بروز شد" - }, - "VPN connections": { - "VPN connections": "اتصالات VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN حذف شد" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN وارد شد:‌ %1" - }, - "VPN not available": { - "VPN not available": "VPN موجود نیست" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "وضعیت VPN و اتصال سریع" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR فقط تمام‌صفحه" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR بر اساس تقاضا" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "نرخ تازه‌سازی متغیر (VRR)" - }, - "Verification": { - "Verification": "تأیید" - }, - "Version": { - "Version": "نسخه" - }, - "Vertical Deck": { - "Vertical Deck": "دک عمودی" - }, - "Vertical Grid": { - "Vertical Grid": "جدول عمودی" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "اسکرولینگ عمودی" - }, - "Vertical Tiling": { - "Vertical Tiling": "تایلینگ عمودی" - }, - "Vibrant": { - "Vibrant": "زنده" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "پالتر رنگی پر جنب و جوش با اشباع رنگی سرزنده." - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "ویدئوها" - }, - "View Mode": { - "View Mode": "حالت نمایش" - }, - "Visibility": { - "Visibility": "دید" - }, - "Visual Effects": { - "Visual Effects": "افکت‌های بصری" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "جداکننده بصری بین ابزارک‌ها" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "افکت بصری مورد استفاده هنگام تغییر تصویر زمینه" - }, - "Volume": { - "Volume": "حجم صدا" - }, - "Volume Changed": { - "Volume Changed": "تغییر حجم صدا" - }, - "Volume Slider": { - "Volume Slider": "اسلایدر حجم صدا" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "OSD‌های حجم صدا، روشنایی و سیستمی" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "تصویر پس‌زمینه" - }, - "Wallpaper Error": { - "Wallpaper Error": "خطای تصویر پس‌زمینه" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "مانیتور تصویر پس‌زمینه" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "پردازش تصویر پس‌زمینه ناموفق بود" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "پردازش تصویر پس‌زمینه ناموفق بود - مسیر تصویر پس‌زمینه را بررسی کنید" - }, - "Wallpapers": { - "Wallpapers": "تصاویر پس‌زمینه" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "دمای رنگ گرم برای اعمال" - }, - "Warning": { - "Warning": "اخطار" - }, - "Warnings": { - "Warnings": "اخطار‌ها" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "نوار‌های پیشرفت موجی" - }, - "Weather": { - "Weather": "آب و هوا" - }, - "Weather Widget": { - "Weather Widget": "ابزارک آب و هوا" - }, - "Welcome": { - "Welcome": "خوش آمدید" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "به دَنک متریال شل خوش آمدید" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "هنگام فعال بودن، برنامه‌ها بر اساس حروف الفبا مرتب می‌شوند. هنگام غیرفعال بودن، برنامه ها بر اساس دفعات استفاده مرتب می‌شوند." - }, - "When locked": { - "When locked": "هنگام قفل شدن" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "وقتی از ابزارک بروزرسان استفاده می‌شود، اگر بروزرسانی یافت نشد، آن را پنهان کن" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "گذرواژه وای‌فای" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "اتصالات Wi-Fi و اترنت" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi در دسترس نیست" - }, - "WiFi": { - "WiFi": "وای‌فای" - }, - "WiFi Device": { - "WiFi Device": "دستگاه وای‌فای" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "کد QR وای‌فای برای " - }, - "WiFi disabled": { - "WiFi disabled": "وای‌فای غیرفعال" - }, - "WiFi enabled": { - "WiFi enabled": "وای‌فای فعال" - }, - "WiFi is off": { - "WiFi is off": "وای‌فای خاموش است" - }, - "WiFi off": { - "WiFi off": "وای‌فای خاموش" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "عریض (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "رنگ پس‌زمینه ابزارک" - }, - "Widget Management": { - "Widget Management": "مدیریت ابزارک‌ها" - }, - "Widget Outline": { - "Widget Outline": "خط بیرونی ابزارک" - }, - "Widget Style": { - "Widget Style": "استایل ابزارک" - }, - "Widget Styling": { - "Widget Styling": "استایل‌‌دهی ابزارک‌" - }, - "Widget Transparency": { - "Widget Transparency": "شفافیت ابزارک" - }, - "Widget added": { - "Widget added": "ابزارک اضافه شد" - }, - "Widget removed": { - "Widget removed": "ابزارک حذف شد" - }, - "Widgets": { - "Widgets": "ابزارک‌ها" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "ابزارک‌ها، چیدمان، استایل" - }, - "Width": { - "Width": "طول" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "ضخامت حاشیه پنجره (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "ضخامت حاشیه پنجره (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "ضخامت حاشیه پنجره و حلقه فوکوس" - }, - "Wind": { - "Wind": "باد" - }, - "Wind Speed": { - "Wind Speed": "سرعت باد" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "سرعت باد به m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "شعاع گوشه پنجره‌ها" - }, - "Window Gaps": { - "Window Gaps": "فاصله پنجره‌ها" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "فاصله پنجره‌ها (px)" - }, - "Window Height": { - "Window Height": "ارتفاع پنجره" - }, - "Window Opening": { - "Window Opening": "باز کردن پنجره" - }, - "Window Rounding": { - "Window Rounding": "گردی پنجره" - }, - "Window Rules": { - "Window Rules": "قواعد پنجره‌ها" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "دستور Include برای قواعد پنجره‌ها یافت نشد" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "قواعد پنجره‌ها پیکربندی نشده‌اند" - }, - "Wipe": { - "Wipe": "پاک کردن" - }, - "Workspace": { - "Workspace": "محیط‌کار" - }, - "Workspace Appearance": { - "Workspace Appearance": "نمای ظاهری محیط‌کار" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "شماره شاخص محیط‌کارها" - }, - "Workspace Names": { - "Workspace Names": "نام محیط‌کارها" - }, - "Workspace Padding": { - "Workspace Padding": "فاصله درونی محیط‌کار" - }, - "Workspace Settings": { - "Workspace Settings": "تنظیمات محیط‌کار" - }, - "Workspace Switcher": { - "Workspace Switcher": "تغییردهنده محیط‌کار" - }, - "Workspace name": { - "Workspace name": "نام محیط‌کار" - }, - "Workspaces": { - "Workspaces": "محیط‌کارها" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "محیط‌کارها و ابزارک‌ها" - }, - "Write:": { - "Write:": "نوشتن:" - }, - "X Axis": { - "X Axis": "محور X" - }, - "Y Axis": { - "Y Axis": "محور Y" - }, - "Yes": { - "Yes": "بله" - }, - "Yesterday": { - "Yesterday": "دیروز" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "شما تغییرات ذخیره نشده‌ دارید. آیا پیش از بستن این برگه ذخیره شوند؟" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "شما تغییرات ذخیره نشده‌ دارید. پیش از ادامه ذخیره شوند؟" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "شما تغییرات ذخیره نشده‌ دارید. پیش از ایجاد فایل جدید، ذخیره شوند؟" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "شما تغییرات ذخیره نشده‌ دارید. پیش از باز کردن فایل، ذخیره شوند؟" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "لازم است یکی از مقادیر زیر را به عنوان متغیر محیطی تنظیم نمایید:\nQT_QPA_PLATFORMTHEME=gtk3 یا\nQT_QPA_PLATFORMTHEME=qt6ct\nو پس از آن، شل را مجدداً راه‌اندازی کنید.\n\nبسته qt6ct نیازمند نصب qt6ct-kde است." - }, - "You're All Set!": { - "You're All Set!": "همه چیز آماده است!" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "اقدام‌ها" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "براندون" - }, - "by %1": { - "by %1": "توسط %1" - }, - "days": { - "days": "روز" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "دستگاه" - }, - "devices connected": { - "devices connected": "دستگاه‌های متصل" - }, - "dgop not available": { - "dgop not available": "dgop در دسترس نیست" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "پیکربندی dms/cursor وجود دارد اما وارد نشده است. تنظیمات اشاره‌گر موس اعمال نخواهند شد." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "پیکربندی dms/outputs وجود دارد اما در پیکربندی کامپوزیتور شما گنجانده نشده است. تغییرات نمایشگر پایدار نخواهند بود." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "مانند firefox، kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "مانند focus-workspace 3، resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "مانند notify-send 'Hello' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "رویداد‌ها" - }, - "ext": { - "ext": "پسوند" - }, - "featured": { - "featured": "پیشنهادی" - }, - "leave empty for default": { - "leave empty for default": "برای پیش‌فرض خالی رها کنید" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl در دسترس نیست - یکپارچه‌سازی قفل به اتصال سوکت DMS نیاز دارد" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen یافت نشد - بسته matugen را برای تم پویا نصب کنید" - }, - "minutes": { - "minutes": "دقیقه" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "پیمایش" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "پیکربندی میانبرهای نیری" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "اکنون" - }, - "official": { - "official": "رسمی" - }, - "on Hyprland": { - "on Hyprland": "در Hyprland" - }, - "on MangoWC": { - "on MangoWC": "در MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "در Miracle WM" - }, - "on Niri": { - "on Niri": "در Niri" - }, - "on Scroll": { - "on Scroll": "در Scroll" - }, - "on Sway": { - "on Sway": "در Sway" - }, - "open": { - "open": "باز کردن" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "فرایند" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "ثانیه" - }, - "source": { - "source": "منبع" - }, - "this app": { - "this app": "این برنامه" - }, - "up": { - "up": "روشن" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "DMS را برای یکپارچه‌سازی NM بروز کنید." - }, - "v%1 by %2": { - "v%1 by %2": "نسخه %1 توسط %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype در دسترس نیست - wtype را برای پشتیبانی از الصاق نصب کنید" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "نصب فقط از منابع معتبر" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - ماه (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - ماه (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - ماه (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - ماه (January)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• افزونه ممکن است باگ یا مشکلات امنیتی داشته باشد" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• پیش از نصب در صورت امکان کد را بررسی کنید" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - روز (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - روز (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - نام روز (Mon)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - نام روز (Monday)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - سال (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - سال (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: پیمایش • Space: گسترش • Enter: اقدام/گسترش • E: متن" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: پیمایش • Enter: الصاق • Del: حذف • F10: راهنما" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fr.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fr.json deleted file mode 100644 index af781a7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/fr.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "Vitesse d'animation %1" - }, - "%1 Sessions": { - "%1 Sessions": "%1 sessions" - }, - "%1 active session": { - "%1 active session": "%1 session active" - }, - "%1 active sessions": { - "%1 active sessions": "%1 sessions actives" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 adaptateur, aucun connecté" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 adaptateurs, aucun connecté" - }, - "%1 character": { - "%1 character": "%1 caractère" - }, - "%1 characters": { - "%1 characters": "%1 caractères" - }, - "%1 connected": { - "%1 connected": "%1 connecté" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "Durée d'animation personnalisée %1" - }, - "%1 disconnected": { - "%1 disconnected": "%1 déconnecté" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 déconnecté (caché)" - }, - "%1 display": { - "%1 display": "%1 écran" - }, - "%1 displays": { - "%1 displays": "%1 écrans" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 existe mais n’est pas inclus dans la configuration. Les raccourcis personnalisés ne fonctionneront pas tant que ce problème n’est pas corrigé." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 existe mais n'est pas inclus. Les règles de fenêtres ne s'appliqueront pas." - }, - "%1 filtered": { - "%1 filtered": "%1 filtré" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 est maintenant inclus dans la configuration" - }, - "%1 issue found": { - "%1 issue found": "%1 problème trouvé" - }, - "%1 issues found": { - "%1 issues found": "%1 problèmes trouvés" - }, - "%1 notifications": { - "%1 notifications": "%1 notification(s)" - }, - "%1 update": { - "%1 update": "%1 mise à jour" - }, - "%1 updates": { - "%1 updates": "%1 mises à jour" - }, - "%1 variants": { - "%1 variants": "%1 variante(s)" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 fond d'écran • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 fonds d'écran • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 widgets" - }, - "%1 window": { - "%1 window": "%1 fenêtre" - }, - "%1 windows": { - "%1 windows": "%1 fenêtres" - }, - "%1m ago": { - "%1m ago": "il y a %1 min" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "'Alternatif' laisse la clé se déverrouiller d'elle-même. 'Deux facteurs' nécessite un mot de passe ou une empreinte d'abord, puis la clé." - }, - "(Default)": { - "(Default)": "(Par défaut)" - }, - "(Unnamed)": { - "(Unnamed)": "(Sans nom)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 supplémentaire(s)" - }, - "/path/to/videos": { - "/path/to/videos": "/chemin/vers/vidéos/" - }, - "0 = square corners": { - "0 = square corners": "0 = coins carrés" - }, - "1 day": { - "1 day": "1 jour" - }, - "1 device connected": { - "1 device connected": "1 appareil connecté" - }, - "1 event": { - "1 event": "1 événement" - }, - "1 hour": { - "1 hour": "1 heure" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 heure et 30 minutes" - }, - "1 minute": { - "1 minute": "1 minute" - }, - "1 notification": { - "1 notification": "1 notification" - }, - "1 second": { - "1 second": "1 seconde" - }, - "10 minutes": { - "10 minutes": "10 minutes" - }, - "10 seconds": { - "10 seconds": "10 secondes" - }, - "10-bit Color": { - "10-bit Color": "Couleur 10 bits" - }, - "12 hours": { - "12 hours": "12 heures" - }, - "14 days": { - "14 days": "14 jours" - }, - "15 minutes": { - "15 minutes": "15 minutes" - }, - "15 seconds": { - "15 seconds": "15 secondes" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 heures" - }, - "2 minutes": { - "2 minutes": "2 minutes" - }, - "2 seconds": { - "2 seconds": "2 secondes" - }, - "20 minutes": { - "20 minutes": "20 minutes" - }, - "20 seconds": { - "20 seconds": "20 secondes" - }, - "24-Hour Format": { - "24-Hour Format": "Format 24 Heures" - }, - "24-hour clock": { - "24-hour clock": "Horloge 24 heures" - }, - "24-hour format": { - "24-hour format": "Format 24 heures" - }, - "25 seconds": { - "25 seconds": "25 secondes" - }, - "250 ms": { - "250 ms": "250ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 jours" - }, - "3 hours": { - "3 hours": "3 heures" - }, - "3 minutes": { - "3 minutes": "3 minutes" - }, - "3 seconds": { - "3 seconds": "3 secondes" - }, - "30 days": { - "30 days": "30 jours" - }, - "30 minutes": { - "30 minutes": "30 minutes" - }, - "30 seconds": { - "30 seconds": "30 secondes" - }, - "35 seconds": { - "35 seconds": "35 secondes" - }, - "3rd party": { - "3rd party": "tiers" - }, - "4 hours": { - "4 hours": "4 heures" - }, - "4 seconds": { - "4 seconds": "4 secondes" - }, - "40 seconds": { - "40 seconds": "40 secondes" - }, - "45 seconds": { - "45 seconds": "45 secondes" - }, - "5 minutes": { - "5 minutes": "5 minutes" - }, - "5 seconds": { - "5 seconds": "5 secondes" - }, - "50 seconds": { - "50 seconds": "50 secondes" - }, - "500 ms": { - "500 ms": "500ms" - }, - "55 seconds": { - "55 seconds": "55 secondes" - }, - "6 hours": { - "6 hours": "6 heures" - }, - "7 days": { - "7 days": "7 jours" - }, - "750 ms": { - "750 ms": "750ms" - }, - "8 hours": { - "8 hours": "8 heures" - }, - "8 seconds": { - "8 seconds": "8 secondes" - }, - "90 days": { - "90 days": "90 jours" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Un fichier portant ce nom existe déjà. Voulez-vous le remplacer ?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Un environnement de bureau moderne pour les compositeurs Wayland" - }, - "AC Power": { - "AC Power": "Alimentation secteur" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Annulé" - }, - "About": { - "About": "À propos" - }, - "Accent Color": { - "Accent Color": "Couleur d’accentuation" - }, - "Accept": { - "Accept": "Accepter" - }, - "Accept Jobs": { - "Accept Jobs": "Accepter les tâches" - }, - "Accepting": { - "Accepting": "En cours d’acceptation" - }, - "Access clipboard history": { - "Access clipboard history": "Accéder à l’historique du presse-papiers" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Accès aux notifications et au mode ne pas déranger" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Accès aux contrôles et paramètres système" - }, - "Action": { - "Action": "Action" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "L'action a échoué ou le terminal a été fermé." - }, - "Actions": { - "Actions": "Actions" - }, - "Activate": { - "Activate": "Activer" - }, - "Activate Greeter": { - "Activate Greeter": "Activer le Greeter" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "Activer le greeter DMS ? Un terminal va s'ouvrir pour l'authentification sudo. Exécutez la Synchro après l'activation pour appliquer vos paramètres." - }, - "Activation": { - "Activation": "Activation" - }, - "Active": { - "Active": "Actif" - }, - "Active Color": { - "Active Color": "Couleur active" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Écran actif pour l’écran de verrouillage" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Activer l’arrière-plan de la tuile et la couleur de l’icône" - }, - "Active: %1": { - "Active: %1": "Actif : %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Actif : %1 +%2" - }, - "Active: None": { - "Active: None": "Actif : aucun" - }, - "Adapters": { - "Adapters": "Adaptateurs" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Ajouter" - }, - "Add Bar": { - "Add Bar": "Ajouter une barre" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Ajouter un widget de bureau" - }, - "Add Printer": { - "Add Printer": "Ajouter une imprimante" - }, - "Add Title": { - "Add Title": "Ajouter titre" - }, - "Add Widget": { - "Add Widget": "Ajouter un widget" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Ajouter un widget à la section %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Ajouter une bordure autour du dock" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Ajouter un préfixe personnalisé à tous les lancements d’applications (ex. uwsm-app, systemd-run ou autres wrappers de commandes)." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Ajouter et configurer les widgets affichés sur le bureau" - }, - "Add by Address": { - "Add by Address": "Ajouter par adresse" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Ajuster le nombre de colonnes en mode vue en grille." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Ajuster le volume à la molette" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "Ajuste le contraste des couleurs générées (-100 = minimum, 0 = standard, 100 = maximum)" - }, - "Advanced": { - "Advanced": "Avancé" - }, - "Afternoon": { - "Afternoon": "Après-midi" - }, - "All": { - "All": "Tous" - }, - "All Monitors": { - "All Monitors": "Tous les écrans" - }, - "All checks passed": { - "All checks passed": "Toutes les vérifications ont réussi" - }, - "All day": { - "All day": "Toute la journée" - }, - "All displays": { - "All displays": "Tous les écrans" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Autoriser les clics à travers le widget" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Retour arrière : Retour • F1/I : Infos fichier • F10 : Aide • Échap : Fermer" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternatif (OR)" - }, - "Always Active": { - "Always Active": "Toujours actif" - }, - "Always Show Percentage": { - "Always Show Percentage": "Toujours afficher le pourcentage" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Toujours cacher le dock et le révéler au survol proche de la zone du dock" - }, - "Always on icons": { - "Always on icons": "Icônes toujours visibles" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Toujours afficher au minimum 3 espaces de travail, même si moins sont disponibles" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Toujours afficher le dock lorsque la vue d’ensemble de Niri est ouverte" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Toujours afficher lorsqu’un seul écran est connecté" - }, - "Amount": { - "Amount": "Quantité" - }, - "Analog": { - "Analog": "Analogique" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Affichage de l’horloge analogique, numérique ou empilée" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Analyse de la configuration…" - }, - "Animation Duration": { - "Animation Duration": "Durée d'animation" - }, - "Animation Speed": { - "Animation Speed": "Vitesse d'animation" - }, - "Anonymous Identity": { - "Anonymous Identity": "Identité anonyme" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Identité anonyme (facultatif)" - }, - "App Customizations": { - "App Customizations": "Personnalisation d'appli" - }, - "App ID Substitutions": { - "App ID Substitutions": "Substitutions d’identifiant d’application" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "Regex de l'ID d'appli (e.g. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Lanceur d’applications" - }, - "App Names": { - "App Names": "Noms des applications" - }, - "App Theming": { - "App Theming": "Habillage des applis" - }, - "Appearance": { - "Appearance": "Apparence" - }, - "Application Dock": { - "Application Dock": "Dock d’applications" - }, - "Applications": { - "Applications": "Applications" - }, - "Apply Changes": { - "Apply Changes": "Appliquer les modifications" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Appliquer les couleurs GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Appliquer les couleurs Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Appliquer une température de couleur chaude pour réduire la fatigue visuelle. Utilisez les paramètres d’automatisation ci-dessous pour définir son activation." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "Applis" - }, - "Apps Dock": { - "Apps Dock": "Dock d'applis" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Paramètres des applis du Dock" - }, - "Apps Icon": { - "Apps Icon": "Icône des applis" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Les applications sont classées par fréquence d’utilisation, puis par dernière utilisation, puis par ordre alphabétique." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Les applis avec un nom, une icône ou des options de lancement personnalisées. Faites un clic droit sur une appli et sélectionnez 'Editer appli' pour customiser." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Applis dont les notifications popup sont en sourdine. Réactivez ou supprimez pour les rétablir. " - }, - "Architecture": { - "Architecture": "Architecture" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Êtes-vous sur de vouloir terminer la session \"%1\" ? " - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Organiser les écrans et configurer la résolution, la fréquence de rafraîchissement et le VRR." - }, - "Attach": { - "Attach": "Attacher" - }, - "Audio": { - "Audio": "Audio" - }, - "Audio Codec": { - "Audio Codec": "Codec audio" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Sélection du codec audio" - }, - "Audio Devices": { - "Audio Devices": "Appareils audio" - }, - "Audio Input": { - "Audio Input": "Entrée audio" - }, - "Audio Output": { - "Audio Output": "Sortie audio" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Périphériques de sortie audio (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Sélecteur de sortie audio" - }, - "Audio Visualizer": { - "Audio Visualizer": "Visualiseur audio" - }, - "Audio system restarted": { - "Audio system restarted": "Système audio redémarré" - }, - "Audio volume control": { - "Audio volume control": "Contrôle du volume audio" - }, - "Auth": { - "Auth": "Authentification" - }, - "Auth Type": { - "Auth Type": "Type d’authentification" - }, - "Authenticate": { - "Authenticate": "S’authentifier" - }, - "Authenticating...": { - "Authenticating...": "Authentification..." - }, - "Authentication": { - "Authentication": "Authentification" - }, - "Authentication Required": { - "Authentication Required": "Authentification requise" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "Erreur d'authentification - essayez à nouveau" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Échec de l’authentification, veuillez réessayer" - }, - "Authorize": { - "Authorize": "Autoriser" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autoriser l’appairage avec " - }, - "Authorize service for ": { - "Authorize service for ": "Autoriser le service pour " - }, - "Auto": { - "Auto": "Auto" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Auto (large)" - }, - "Auto Location": { - "Auto Location": "Localisation automatique" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Espacements automatiques des fenêtres contextuelles" - }, - "Auto-Clear After": { - "Auto-Clear After": "Nettoyage automatique après" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Délai de masquage automatique" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Fermer automatiquement la vue d’ensemble de Niri lors du lancement d’applications." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Supprimer automatiquement les notifications plus anciennes que ceci" - }, - "Auto-hide": { - "Auto-hide": "Cacher automatiquement" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Masquer automatiquement le dock" - }, - "Auto-saving...": { - "Auto-saving...": "Sauvegarde automatique..." - }, - "Autoconnect": { - "Autoconnect": "Connexion automatique" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Connexion automatique désactivée" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Connexion automatique activée" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Mode sombre automatique" - }, - "Automatic Control": { - "Automatic Control": "Passage automatique" - }, - "Automatic Cycling": { - "Automatic Cycling": "Défilement automatique" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Faire défiler automatiquement les fonds d’écran du même dossier" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Supprimer automatiquement les entrées plus anciennes que ce délai" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Détecter automatiquement la localisation à partir de l’adresse IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Détermine automatiquement votre emplacement à l'aide de votre adresse IP" - }, - "Automatically lock after": { - "Automatically lock after": "Verrouillage automatique après" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Verrouiller l'écran automatiquement lorsque DMS démarre" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Verrouiller automatiquement l’écran lorsque le système se prépare à se mettre en veille" - }, - "Automation": { - "Automation": "Automatisation" - }, - "Available": { - "Available": "Disponible" - }, - "Available Layouts": { - "Available Layouts": "Dispositions disponibles" - }, - "Available Networks": { - "Available Networks": "Réseaux disponibles" - }, - "Available Plugins": { - "Available Plugins": "Plugins disponibles" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Écrans disponibles (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Disponible dans les modes Vue détaillée et Prévisions" - }, - "Available.": { - "Available.": "Disponible." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Retour" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "Arrière-plan" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Opacité de l’arrière-plan" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Image d’arrière-plan" - }, - "Backlight device": { - "Backlight device": "Périphérique de rétroéclairage" - }, - "Balance power and performance": { - "Balance power and performance": "Équilibre entre consommation et performance" - }, - "Balanced": { - "Balanced": "Equilibré" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Palette équilibrée avec des accents ciblés (par défaut)." - }, - "Bar Configurations": { - "Bar Configurations": "Configurations de la barre" - }, - "Bar Shadows": { - "Bar Shadows": "Ombres de barre" - }, - "Bar Transparency": { - "Bar Transparency": "Transparence de la barre" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Couleur de base pour les ombres (l'opacité est appliquée automatiquement)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Durée de base des animations (faites glisser pour utiliser une valeur personnalisée)" - }, - "Battery": { - "Battery": "Batterie" - }, - "Battery %1": { - "Battery %1": "Batterie %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Limite de charge de la batterie" - }, - "Battery and power management": { - "Battery and power management": "Gestion de la batterie et de l’alimentation" - }, - "Battery level and power management": { - "Battery level and power management": "Niveau de batterie et gestion de l'alimentation" - }, - "Behavior": { - "Behavior": "Comportement" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Lier l’écran de verrouillage aux signaux D-Bus de loginctl. À désactiver si un écran de verrouillage externe est utilisé." - }, - "Binds Include Missing": { - "Binds Include Missing": "Inclusion des raccourcis manquante" - }, - "Binds include added": { - "Binds include added": "Inclusion des raccourcis ajoutée" - }, - "Bit Depth": { - "Bit Depth": "Profondeur de bits" - }, - "Block Out": { - "Block Out": "Bloquer" - }, - "Block Out From": { - "Block Out From": "Bloquer de" - }, - "Block notifications": { - "Block notifications": "Bloquer les notifications" - }, - "Blocked": { - "Blocked": "Bloqué" - }, - "Blue light filter": { - "Blue light filter": "Filtre de lumière bleue" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Paramètres Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth non disponible" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Flouter la couche du fond d’écran" - }, - "Blur on Overview": { - "Blur on Overview": "Flou dans la vue d’ensemble" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Flouter le fond d’écran lorsque la vue d’ensemble de Niri est ouverte" - }, - "Body": { - "Body": "Corps" - }, - "Border": { - "Border": "Bordure" - }, - "Border Color": { - "Border Color": "Couleur de la bordure" - }, - "Border Opacity": { - "Border Opacity": "Opacité de la bordure" - }, - "Border Size": { - "Border Size": "Taille de la bordure" - }, - "Border Thickness": { - "Border Thickness": "Épaisseur de la bordure" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "Bordures avec fond" - }, - "Bottom": { - "Bottom": "Bas" - }, - "Bottom Center": { - "Bottom Center": "Au centre en bas" - }, - "Bottom Left": { - "Bottom Left": "Bas gauche" - }, - "Bottom Right": { - "Bottom Right": "Bas droit" - }, - "Bottom Section": { - "Bottom Section": "Section inférieure" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Dock inférieur pour les applications épinglées et en cours d’exécution" - }, - "Brightness": { - "Brightness": "Luminosité" - }, - "Brightness Slider": { - "Brightness Slider": "Curseur de luminosité" - }, - "Brightness Value": { - "Brightness Value": "Valeur de luminosité" - }, - "Brightness control not available": { - "Brightness control not available": "Contrôle de la luminosité non disponible" - }, - "Browse": { - "Browse": "Parcourir" - }, - "Browse Files": { - "Browse Files": "Chercher des fichiers" - }, - "Browse Plugins": { - "Browse Plugins": "Parcourir les plugins" - }, - "Browse Themes": { - "Browse Themes": "Parcourir les thèmes" - }, - "Browse or search plugins": { - "Browse or search plugins": "Chercher des plugins" - }, - "Button Color": { - "Button Color": "Couleur du bouton" - }, - "CPU": { - "CPU": "Processeur" - }, - "CPU Graph": { - "CPU Graph": "Graphique du CPU" - }, - "CPU Temperature": { - "CPU Temperature": "Température CPU" - }, - "CPU Usage": { - "CPU Usage": "Utilisation CPU" - }, - "CPU temperature display": { - "CPU temperature display": "Affichage de la température du CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "Indicateur d’utilisation du CPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Surveillance du processeur, de la mémoire, du réseau et du disque" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "Avertissement de filtre non sécurisé CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "Avertissement de filtre manquant CUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "Serveur d’impression CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS non disponible" - }, - "Camera": { - "Camera": "Caméra" - }, - "Cancel": { - "Cancel": "Annuler" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Annuler tous les jobs pour \"%1\" ?" - }, - "Canceled": { - "Canceled": "Annulé" - }, - "Cannot pair": { - "Cannot pair": "Impossible d’appairer" - }, - "Capabilities": { - "Capabilities": "Capacités" - }, - "Capacity": { - "Capacity": "Capacité" - }, - "Caps Lock": { - "Caps Lock": "Verr. Maj." - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indicateur Verr. Maj." - }, - "Caps Lock is on": { - "Caps Lock is on": "Verr Maj est activé" - }, - "Center Section": { - "Center Section": "Partie centrale" - }, - "Center Single Column": { - "Center Single Column": "Colonne centrale unique" - }, - "Center Tiling": { - "Center Tiling": "Mosaïque centrée" - }, - "Certificate Password": { - "Certificate Password": "Mot de passe du certificat" - }, - "Change Song": { - "Change Song": "Changer de musique" - }, - "Change Volume": { - "Change Volume": "Changer le volume" - }, - "Change bar appearance": { - "Change bar appearance": "Modifier l’apparence de la barre" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Changer les paramètres régionaux utilisés pour le format de la date et de l'heure, indépendant de la langue de l'interface." - }, - "Channel": { - "Channel": "Canal" - }, - "Charging": { - "Charging": "En charge" - }, - "Check for system updates": { - "Check for system updates": "Rechercher des mises à jour système" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "Vérification des mises à jour..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Vérification de la nécessité de l'authentification sudo..." - }, - "Checking...": { - "Checking...": "Vérification..." - }, - "Checking…": { - "Checking…": "Vérification..." - }, - "Choose Color": { - "Choose Color": "Choisir une couleur" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Choisir la couleur du mode sombre" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Choisir la couleur du logo du Lanceur dans le Dock" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Choisir la couleur du logo du lanceur" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Choisir la couleur du mode clair" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Choisir la couleur du fond d'écran" - }, - "Choose a color": { - "Choose a color": "Choisir une couleur" - }, - "Choose colors from palette": { - "Choose colors from palette": "Choisir des couleurs depuis la palette" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Choisir le mode d’affichage du widget météo" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Choisissez comment cette barre gère la direction de l'ombre" - }, - "Choose icon": { - "Choose icon": "Choisir une icône" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Choisir la couleur de fond des widgets" - }, - "Choose the border accent color": { - "Choose the border accent color": "Choisir la couleur d’accentuation de la bordure" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Choisir le logo affiché sur le bouton du lanceur dans la DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Choisir l’emplacement d’affichage des notifications" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Choisir l’emplacement des affichages à l’écran" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Choisir les écrans sur lesquels afficher ce widget" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Choisir l’écran qui affiche l’interface de verrouillage. Les autres écrans afficheront une couleur unie pour éviter le marquage OLED." - }, - "Chroma Style": { - "Chroma Style": "Style chromatique" - }, - "Cipher": { - "Cipher": "Chiffrement" - }, - "Circle": { - "Circle": "Cercle" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Classe regex (e.g. firefox$)" - }, - "Clear": { - "Clear": "Effacer" - }, - "Clear All": { - "Clear All": "Tout effacer" - }, - "Clear All Jobs": { - "Clear All Jobs": "Supprimer toutes les tâches" - }, - "Clear History?": { - "Clear History?": "Effacer l'historique ?" - }, - "Clear Sky": { - "Clear Sky": "Ciel dégagé" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Effacer tout l’historique au démarrage du serveur" - }, - "Clear at Startup": { - "Clear at Startup": "Effacer au démarrage" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Cliquez sur « Configurer » pour créer %1 et l’ajouter à la configuration." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Cliquez sur “Configuration” pour créer %1 et l’ajouter aux inclusions de la configuration de votre compositeur." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Cliquez sur « Configurer » pour créer la configuration du curseur et l’ajouter à celle du compositeur." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Cliquez sur « Configurer » pour créer la configuration des sorties et l’inclure dans la configuration du compositeur." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Cliquez sur importer pour ajouter un fichier .ovpn ou .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Cliquez sur Actualiser pour vérifier l'état." - }, - "Click Through": { - "Click Through": "Cliquable à travers" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Cliquez sur un raccourci pour l’éditer. Les modifications sont enregistrées dans %1" - }, - "Click to capture": { - "Click to capture": "Cliquer pour capturer" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Cliquez pour sélectionner un fichier JSON de thème personnalisé" - }, - "Clip": { - "Clip": "Ancrer" - }, - "Clip to Geometry": { - "Clip to Geometry": "Ancrer à la géométrie" - }, - "Clipboard": { - "Clipboard": "Presse-papiers" - }, - "Clipboard History": { - "Clipboard History": "Historique du presse-papiers" - }, - "Clipboard Manager": { - "Clipboard Manager": "Gestionnaire de presse-papiers" - }, - "Clipboard sent": { - "Clipboard sent": "Presse-papier envoyé" - }, - "Clipboard service not available": { - "Clipboard service not available": "Service de presse-papiers non disponible" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Le presse-papiers fonctionne mais rien n’est enregistré sur le disque" - }, - "Clock": { - "Clock": "Horloge" - }, - "Clock Style": { - "Clock Style": "Style de l’horloge" - }, - "Close": { - "Close": "Fermer" - }, - "Close All Windows": { - "Close All Windows": "Fermer toutes les fenêtres" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Fermer la vue d’ensemble au lancement" - }, - "Close Window": { - "Close Window": "Fermer la fenêtre" - }, - "Color": { - "Color": "Couleur" - }, - "Color Gamut": { - "Color Gamut": "Gamme de couleurs" - }, - "Color Management": { - "Color Management": "Gestion des couleurs" - }, - "Color Mode": { - "Color Mode": "Mode actuel" - }, - "Color Override": { - "Color Override": "Forcer la couleur" - }, - "Color Picker": { - "Color Picker": "Sélecteur de couleur" - }, - "Color Temperature": { - "Color Temperature": "Température de couleur" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Couleur affichée sur les écrans sans interface de verrouillage" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Couleur primaire pour les boutons d'action" - }, - "Color temperature for day time": { - "Color temperature for day time": "Température de couleur pour la journée" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Température de couleur pour le mode nuit" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Thème de couleur pour le surlignage." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Thème de couleur pour le surlignage. %1 thèmes disponibles." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Thème de couleurs provenant du registre DMS" - }, - "Colorful": { - "Colorful": "Coloré" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Mélange coloré avec des accents lumineux et contrastés." - }, - "Colorize Active": { - "Colorize Active": "Coloriser actif" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Couleurs extraites du fond d’écran" - }, - "Column": { - "Column": "Colonne" - }, - "Column Display": { - "Column Display": "Affichage en colonnes" - }, - "Column Width": { - "Column Width": "Longueur de colonne" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Commande" - }, - "Commands": { - "Commands": "Commandes" - }, - "Communication": { - "Communication": "Communication" - }, - "Community themes": { - "Community themes": "Thèmes de la communauté" - }, - "Compact": { - "Compact": "Compact" - }, - "Compact Mode": { - "Compact Mode": "Mode compact" - }, - "Completed": { - "Completed": "Terminé" - }, - "Compositor": { - "Compositor": "Compositeur" - }, - "Compositor Settings": { - "Compositor Settings": "Paramètres du compositeur" - }, - "Compositor not supported": { - "Compositor not supported": "Compositeur non supporté" - }, - "Config Format": { - "Config Format": "Format de configuration" - }, - "Config action: %1": { - "Config action: %1": "Action de configuration : %1" - }, - "Config validation failed": { - "Config validation failed": "Échec de la validation de la configuration" - }, - "Configuration": { - "Configuration": "Configuration" - }, - "Configuration activated": { - "Configuration activated": "Configuration activée" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "La configuration sera conservée lorsque cet écran se reconnectera" - }, - "Configure": { - "Configure": "Configurer" - }, - "Configure Keybinds": { - "Configure Keybinds": "Configurer les raccourcis clavier" - }, - "Configure a new printer": { - "Configure a new printer": "Configurer une nouvelle imprimante" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Configurer les icônes pour les espaces de travail nommés. Les icônes ont priorité sur les numéros lorsqu’ils sont tous deux activés." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Configurer les critères de correspondance et les actions" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Configurer les écrans affichant \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Configurer les écrans affichant les composants du shell" - }, - "Confirm": { - "Confirm": "Confirmer" - }, - "Confirm Delete": { - "Confirm Delete": "Confirmer la suppression" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Confirmer les modifications d’affichage" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Confirmer la clé de sécurité pour " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Conflits avec : %1" - }, - "Connect": { - "Connect": "Connecter" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Se connecter à un réseau masqué" - }, - "Connect to VPN": { - "Connect to VPN": "Se connecter à un VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Se connecter au Wi-Fi" - }, - "Connected": { - "Connected": "Connecté" - }, - "Connected Device": { - "Connected Device": "Appareil connecté" - }, - "Connected Displays": { - "Connected Displays": "Écrans connectés" - }, - "Connecting to Device": { - "Connecting to Device": "Connexion au périphérique" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Connexion..." - }, - "Connection failed": { - "Connection failed": "Connexion échouée" - }, - "Contains": { - "Contains": "Contient" - }, - "Content": { - "Content": "Contenu" - }, - "Content copied": { - "Content copied": "Contenu copié" - }, - "Contrast": { - "Contrast": "Contraste" - }, - "Control Center": { - "Control Center": "Centre de contrôle" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Couleur de la tuile du centre de contrôle" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Contrôler la durée des animations des popups et de l’historique des notifications" - }, - "Control currently playing media": { - "Control currently playing media": "Contrôle le média en lecture" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Contrôlez les informations de notification affichées sur l’écran de verrouillage" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Contrôlez quels plugins apparaissent dans le mode 'Tous' sans nécessiter de préfixe de déclenchement. Faites glisser pour réorganiser." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Contrôler les espaces de travail et les colonnes via le défilement sur la barre" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Contrôle l’opacité de toutes les fenêtres contextuelles, modales et de leurs couches de contenu" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Contrôle la transparence des ombres" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "Délai" - }, - "Copied GIF": { - "Copied GIF": "GIF copié" - }, - "Copied MP4": { - "Copied MP4": "MP4 copié" - }, - "Copied WebP": { - "Copied WebP": "WebP copié" - }, - "Copied to clipboard": { - "Copied to clipboard": "Copié dans le presse-papiers" - }, - "Copied!": { - "Copied!": "Copié !" - }, - "Copy": { - "Copy": "Copier" - }, - "Copy Content": { - "Copy Content": "Copier contenu" - }, - "Copy Full Command": { - "Copy Full Command": "Copier commande complète" - }, - "Copy HTML": { - "Copy HTML": "Copier HTML" - }, - "Copy Name": { - "Copy Name": "Copier nom" - }, - "Copy PID": { - "Copy PID": "Copier le PID" - }, - "Copy Text": { - "Copy Text": "Copier texte" - }, - "Copy path": { - "Copy path": "Copier chemin" - }, - "Corner Radius": { - "Corner Radius": "Rayon des coins" - }, - "Corner Radius Override": { - "Corner Radius Override": "Forcer le rayon des coins" - }, - "Corners & Background": { - "Corners & Background": "Coins et arrière-plan" - }, - "Count Only": { - "Count Only": "Nombre uniquement" - }, - "Cover Open": { - "Cover Open": "Capot ouvert" - }, - "Create": { - "Create": "Créer" - }, - "Create Dir": { - "Create Dir": "Créer un dossier" - }, - "Create Printer": { - "Create Printer": "Créer une imprimante" - }, - "Create Window Rule": { - "Create Window Rule": "Créer règle de fenêtre" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Créer une nouvelle %1 session (n)" - }, - "Create rule for:": { - "Create rule for:": "Créer règle pour :" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Créez des règles pour mettre en sourdine, ignorer, masquer de l’historique ou modifier la priorité des notifications. Par défaut, seule la priorité est modifiée; les notifications s’affichent normalement. " - }, - "Creating...": { - "Creating...": "Création..." - }, - "Critical Priority": { - "Critical Priority": "Priorité critique" - }, - "Current": { - "Current": "Actuel" - }, - "Current Items": { - "Current Items": "Éléments actuels" - }, - "Current Locale": { - "Current Locale": "Paramètres régionaux actuels" - }, - "Current Monitor": { - "Current Monitor": "Ecran actuel" - }, - "Current Period": { - "Current Period": "Période actuelle" - }, - "Current Status": { - "Current Status": "État actuel" - }, - "Current Temp": { - "Current Temp": "Température actuelle" - }, - "Current Theme: %1": { - "Current Theme: %1": "Thème actuel : %1" - }, - "Current Weather": { - "Current Weather": "Météo actuelle" - }, - "Current Workspace": { - "Current Workspace": "Espace de travail actuel" - }, - "Current time and date display": { - "Current time and date display": "Affichage de l'heure et de la date actuelles" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Conditions météorologiques et température actuelles" - }, - "Current: %1": { - "Current: %1": "Actuel : %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Configuration du curseur non définie" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Inclusion du curseur manquante" - }, - "Cursor Size": { - "Cursor Size": "Taille du curseur" - }, - "Cursor Theme": { - "Cursor Theme": "Thème du curseur" - }, - "Custom": { - "Custom": "Personnalisé" - }, - "Custom Color": { - "Custom Color": "Couleur personnalisée" - }, - "Custom Duration": { - "Custom Duration": "Durée personnalisée" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Commande d’hibernation personnalisée" - }, - "Custom Location": { - "Custom Location": "Localisation personnalisée" - }, - "Custom Lock Command": { - "Custom Lock Command": "Commande de verrouillage personnalisée" - }, - "Custom Logout Command": { - "Custom Logout Command": "Commande de déconnexion personnalisée" - }, - "Custom Name": { - "Custom Name": "Nom personnalisé" - }, - "Custom Power Actions": { - "Custom Power Actions": "Actions d’alimentation personnalisées" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Commande d’extinction personnalisée" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Commande de redémarrage personnalisée" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Couleur d'ombre personnalisée" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Surcharge d'ombre personnalisée" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Commande de mise en veille personnalisée" - }, - "Custom Transparency": { - "Custom Transparency": "Transparence personnalisée" - }, - "Custom power profile": { - "Custom power profile": "Profil d’alimentation personnalisé" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Thème personnalisé chargé depuis un fichier JSON" - }, - "Custom...": { - "Custom...": "Personnalisé..." - }, - "Custom: ": { - "Custom: ": "Personnalisé : " - }, - "Customizable empty space": { - "Customizable empty space": "Espace vide personnalisable" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Personnaliser les actions affichées dans le menu d’alimentation" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "Moniteur DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "MODE DÉMO — Cliquez n’importe où pour quitter" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Gestionnaire de plugins DMS indisponible" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Raccourcis DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS obsolète" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Le service DMS n’est pas connecté. Les paramètres du presse-papiers sont indisponibles." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Actions du shell DMS (lanceur, presse-papiers, etc.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET indisponible" - }, - "DWL service not available": { - "DWL service not available": "Service DWL indisponible" - }, - "Daily": { - "Daily": "Par jour" - }, - "Daily at:": { - "Daily at:": "Chaque jour à :" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Barre Dank" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell est prêt à l’emploi" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "Icônes DankShell et système (redémarrage requis)" - }, - "Dark Mode": { - "Dark Mode": "Mode sombre" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Assombrir l’arrière-plan des fenêtres modales" - }, - "Date Format": { - "Date Format": "Format de date" - }, - "Date format": { - "Date format": "Format de date" - }, - "Date format on greeter": { - "Date format on greeter": "Format de date sur le greeter" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Aube (crépuscule astronomique)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Aube (crépuscule civil)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Aube (crépuscule nautique)" - }, - "Day Date": { - "Day Date": "Date jour" - }, - "Day Month Date": { - "Day Month Date": "Date jour mois" - }, - "Day Temperature": { - "Day Temperature": "Température en journée" - }, - "Daytime": { - "Daytime": "En journée" - }, - "Deck": { - "Deck": "Dock" - }, - "Default": { - "Default": "Par défaut" - }, - "Default (Black)": { - "Default (Black)": "Par défaut (Noir)" - }, - "Default Width (%)": { - "Default Width (%)": "Largeur par défaut (%)" - }, - "Default selected action": { - "Default selected action": "Action sélectionnée par défaut" - }, - "Defaults": { - "Defaults": "Valeurs par défaut" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Définir les règles pour le comportement des fenêtres. Enregistré dans %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Suppr : Effacer • Maj+Suppr : Tout effacer • 1-9 : Actions • F10 : Aide • Échap : Fermer" - }, - "Delete": { - "Delete": "Supprimer" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Supprimer \"%1\" ?" - }, - "Delete Class": { - "Delete Class": "Supprimer la classe" - }, - "Delete Printer": { - "Delete Printer": "Supprimer l’imprimante" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Supprimer l'élément sauvegardé ?" - }, - "Delete VPN": { - "Delete VPN": "Supprimer le VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Supprimer la classe \"%1\" ?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Supprimer le profil \"%1\" ?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Dépendances & documentation" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Génère des couleurs proches de l’image sous-jacente." - }, - "Description": { - "Description": "Description" - }, - "Desktop": { - "Desktop": "Bureau" - }, - "Desktop Clock": { - "Desktop Clock": "Horloge du bureau" - }, - "Desktop Entry": { - "Desktop Entry": "Entrée de bureau" - }, - "Desktop Widget": { - "Desktop Widget": "Widget de bureau" - }, - "Desktop Widgets": { - "Desktop Widgets": "Widgets de bureau" - }, - "Desktop background images": { - "Desktop background images": "Images d’arrière-plan du bureau" - }, - "Detailed": { - "Detailed": "Détaillé" - }, - "Details for \"%1": { - "Details for \"%1\"": "Détails pour \"%1\"" - }, - "Development": { - "Development": "Développement" - }, - "Device": { - "Device": "Appareil" - }, - "Device connections": { - "Device connections": "Connexions des périphériques" - }, - "Device names updated": { - "Device names updated": "Noms des appareils mis à jour" - }, - "Device paired": { - "Device paired": "Périphérique appairé" - }, - "Device unpaired": { - "Device unpaired": "Appareil déconnecté" - }, - "Digital": { - "Digital": "Numérique" - }, - "Direction Source": { - "Direction Source": "Direction de la source" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Désactiver la connexion automatique" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Désactiver les fonds d’écran intégrés" - }, - "Disable History Persistence": { - "Disable History Persistence": "Désactiver la persistance de l’historique" - }, - "Disable Output": { - "Disable Output": "Désactiver la sortie" - }, - "Disabled": { - "Disabled": "Désactivé" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Désactivation du Wi-Fi..." - }, - "Disc": { - "Disc": "Disc" - }, - "Discard": { - "Discard": "Ignorer" - }, - "Discharging": { - "Discharging": "Déchargement" - }, - "Disconnect": { - "Disconnect": "Déconnecter" - }, - "Disconnected": { - "Disconnected": "Déconnecté" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Wi-Fi déconnecté" - }, - "Discover Devices": { - "Discover Devices": "Découvrir les appareils" - }, - "Disk": { - "Disk": "Disque" - }, - "Disk I/O": { - "Disk I/O": "Disque I/O" - }, - "Disk Usage": { - "Disk Usage": "Utilisation du disque" - }, - "Disk Usage Display": { - "Disk Usage Display": "Affichage de l'utilisation du disque" - }, - "Disks": { - "Disks": "Disques" - }, - "Dismiss": { - "Dismiss": "Ignorer" - }, - "Display": { - "Display": "Écran" - }, - "Display Assignment": { - "Display Assignment": "Affectation de l’écran" - }, - "Display Control": { - "Display Control": "Contrôle de l’affichage" - }, - "Display Name Format": { - "Display Name Format": "Format du nom d’affichage" - }, - "Display Profiles": { - "Display Profiles": "Profils d'écran" - }, - "Display Settings": { - "Display Settings": "Paramètres d’affichage" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Afficher un dock avec les applications épinglées et en cours d’exécution" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Afficher toutes les priorités au-dessus des applications en plein écran" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Afficher et changer les dispositions DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Afficher les icônes des applications dans les indicateurs d’espaces de travail" - }, - "Display brightness control": { - "Display brightness control": "Contrôle de la luminosité de l’écran" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "La configuration d’affichage n’est pas disponible. Le protocole de gestion de sortie WLR n’est pas pris en charge." - }, - "Display currently focused application title": { - "Display currently focused application title": "Afficher le titre de l’application actuellement active" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Afficher les prévisions météo horaires" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Afficher uniquement les espaces de travail contenant des fenêtres" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Afficher les actions du menu d’alimentation sous forme de grille" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Afficher les secondes sur l’horloge" - }, - "Display the power system menu": { - "Display the power system menu": "Afficher le menu d’alimentation du système" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Afficher les pourcentages de volume et de luminosité dans les fenêtres OSD" - }, - "Displays": { - "Displays": "Affichages" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Affiche le compteur lorsque le débordement est actif" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Affiche la disposition de clavier active et permet de la changer" - }, - "Distribution": { - "Distribution": "Distribution" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Palette variée couvrant l’ensemble du spectre." - }, - "Do Not Disturb": { - "Do Not Disturb": "Ne pas déranger" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock et lanceur" - }, - "Dock Transparency": { - "Dock Transparency": "Transparence du dock" - }, - "Dock Visibility": { - "Dock Visibility": "Visibilité du dock" - }, - "Docs": { - "Docs": "Documentation" - }, - "Documents": { - "Documents": "Documents" - }, - "Domain (optional)": { - "Domain (optional)": "Domaine (optionnel)" - }, - "Don't Change": { - "Don't Change": "Ne pas modifier" - }, - "Don't Save": { - "Don't Save": "Ne pas enregistrer" - }, - "Door Open": { - "Door Open": "Porte ouverte" - }, - "Downloads": { - "Downloads": "Téléchargements" - }, - "Drag to Reorder": { - "Drag to Reorder": "Glisser pour réorganiser" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Faites glisser les widgets pour les réorganiser dans les sections. Utilisez l’icône en forme d’œil pour afficher ou masquer les widgets (en conservant l’espacement), ou le X pour les supprimer complètement." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Glisser les indicateurs d'espaces de travail pour les réorganiser" - }, - "Driver": { - "Driver": "Pilote" - }, - "Drizzle": { - "Drizzle": "Bruine" - }, - "Duplicate": { - "Duplicate": "Dupliquer" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Dupliquer le fond d’écran avec flou" - }, - "Duration": { - "Duration": "Durée" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Crépuscule (astronomique)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Crépuscule (civil)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Crépuscule (nautique)" - }, - "Dynamic": { - "Dynamic": "Dynamique" - }, - "Dynamic Properties": { - "Dynamic Properties": "Propriétés dynamiques" - }, - "Dynamic Theming": { - "Dynamic Theming": "Habillage dynamique" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Couleurs dynamiques à partir du fond d’écran" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Couleurs dynamiques, préréglages" - }, - "Edge Spacing": { - "Edge Spacing": "Espacement des bords" - }, - "Edit App": { - "Edit App": "Editer appli" - }, - "Edit Window Rule": { - "Edit Window Rule": "Editer règle de fenêtre" - }, - "Education": { - "Education": "Éducation" - }, - "Empty": { - "Empty": "Vide" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Activer la profondeur de couleur 10 bits pour une gamme de couleurs étendue et la prise en charge du HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Activer la connexion automatique" - }, - "Enable Bar": { - "Enable Bar": "Activer la barre" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Activer le mode ne pas déranger" - }, - "Enable History": { - "Enable History": "Activer l’historique" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Activer la superposition de la vue d’ensemble" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Activer l'effet d'ondulation" - }, - "Enable System Sounds": { - "Enable System Sounds": "Activer les sons système" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Activer l'économiseur d'écran vidéo" - }, - "Enable Weather": { - "Enable Weather": "Activer la météo" - }, - "Enable WiFi": { - "Enable WiFi": "Activer le Wi-Fi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Activer une couche de flou détectable par le compositeur (espace de noms : dms:blurwallpaper). Nécessite une configuration manuelle de Niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Activer l'empreinte à la connexion" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Activer l’authentification par empreinte digitale" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Activer l’intégration du verrouillage via loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "Activer la clé de sécurité à la connexion" - }, - "Enable security key authentication": { - "Enable security key authentication": "Activer l'authentification avec clé de sécurité" - }, - "Enabled": { - "Enabled": "Activé" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Activé, mais la disponibilité de l'empreinte n'a pas pu être confirmée." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Activé, mais aucun lecteur d'empreintes n'a été détecté." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Activé, mais aucune empreinte n'a encore été enregistrée. Enregistrez une empreinte et exécutez la Synchro." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Activé, mais la disponibilité de la clé de sécurité n'a pas pu être confirmée." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Activé. PAM fourni déjà une authentification par empreinte." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Activé. PAM fourni déjà une authentification par clé de sécurité." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Activé. PAM fourni l'authentification par empreinte, mais aucune empreinte n'a encore été enregistrée." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Activation du Wi-Fi..." - }, - "End": { - "End": "Fin" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Élargir lors du survol" - }, - "Enlargement %": { - "Enlargement %": "Élargissement %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Saisir la clé à 6 chiffres" - }, - "Enter PIN": { - "Enter PIN": "Entrer le code PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Saisir le code PIN pour " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Entrer l'URL ou le texte à partager" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Entrer un nouveau nom pour la session \"%1\"" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Entrer un nom pour cet espace de travail" - }, - "Enter command or script path": { - "Enter command or script path": "Entrer une commande ou un chemin de script" - }, - "Enter credentials for ": { - "Enter credentials for ": "Saisir les identifiants pour " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Saisir le format personnalisé de l’écran de verrouillage (ex. : dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Saisir le format personnalisé de la barre supérieure (ex. : ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Entrer le nom de l'appareil..." - }, - "Enter filename...": { - "Enter filename...": "Entrez le nom du fichier..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Saisir le préfixe de lancement (ex. : « uwsm-app »)" - }, - "Enter network name and password": { - "Enter network name and password": "Saisir le nom du réseau et le mot de passe" - }, - "Enter passkey for ": { - "Enter passkey for ": "Saisir la clé pour " - }, - "Enter password for ": { - "Enter password for ": "Saisir le mot de passe pour " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Saisir cette clé sur " - }, - "Enter to Paste": { - "Enter to Paste": "Entrée pour coller" - }, - "Enterprise": { - "Enterprise": "Entreprise" - }, - "Entry pinned": { - "Entry pinned": "Entrée épinglée" - }, - "Entry unpinned": { - "Entry unpinned": "Entrée désépinglée" - }, - "Environment Variables": { - "Environment Variables": "Variables d'environnement" - }, - "Error": { - "Error": "Erreur" - }, - "Errors": { - "Errors": "Erreurs" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Exact" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Décalage de zone exclusive" - }, - "Experimental Feature": { - "Experimental Feature": "Fonctionnalité expérimentale" - }, - "Explore": { - "Explore": "Explorer" - }, - "Exponential": { - "Exponential": "Exponentiel" - }, - "Expressive": { - "Expressive": "Expressif" - }, - "Extend battery life": { - "Extend battery life": "Étendre la durée de vide la batterie" - }, - "Extensible architecture": { - "Extensible architecture": "Architecture extensible" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Gestion externe des fonds d’écran" - }, - "Extra Arguments": { - "Extra Arguments": "Arguments supplémentaires" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I : Basculer • F10 : Aide" - }, - "Fade": { - "Fade": "Fondu" - }, - "Fade to lock screen": { - "Fade to lock screen": "Fondu vers l’écran de verrouillage" - }, - "Fade to monitor off": { - "Fade to monitor off": "Fondu avant extinction de l’écran" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Échec de l'appairage" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Échec de l’activation de la configuration" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Échec d'activation du profil - fichier non trouvé" - }, - "Failed to add binds include": { - "Failed to add binds include": "Échec de l’ajout de l’inclusion des raccourcis" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Échec de l’ajout de l’imprimante à la classe" - }, - "Failed to browse device": { - "Failed to browse device": "Échec de la recherche de l'appareil" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Échec de l’annulation de toutes les tâches" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Échec de l’annulation de la tâche sélectionnée" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Échec de la vérification des mises à jour : %1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Échec de la vérification de la limite d'épinglage" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Échec de la connexion au VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Échec de la connexion à %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Échec de la copie de l’entrée" - }, - "Failed to create printer": { - "Failed to create printer": "Échec de la création de l’imprimante" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Échec de la création des répertoires de profils" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Échec de la suppression du VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Échec de la suppression de la classe" - }, - "Failed to delete printer": { - "Failed to delete printer": "Échec de la suppression de l’imprimante" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Échec de la désactivation de l’acceptation des tâches" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Échec de la désactivation du mode nuit" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Échec de la déconnexion du VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Échec de la déconnexion des VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Échec de la déconnexion du Wi-Fi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Échec de l’activation de la localisation par IP" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Échec de l’activation du Wi-Fi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Échec de l’activation de l’acceptation des tâches" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Échec de l’activation du mode nuit" - }, - "Failed to hold job": { - "Failed to hold job": "Échec de la mise en attente de la tâche" - }, - "Failed to import VPN": { - "Failed to import VPN": "Échec de l’importation du VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Échec du lancement de l'appli SMS" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Échec du chargement de la configuration VPN" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Échec du chargement de la configuration du presse-papiers" - }, - "Failed to move job": { - "Failed to move job": "Échec du déplacement de la tâche" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Échec de l’analyse de plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Échec de l’analyse de session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Échec de l’analyse de settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Échec de la mise en pause de l’imprimante" - }, - "Failed to pin entry": { - "Failed to pin entry": "Échec de l'épinglage de l'entrée" - }, - "Failed to print test page": { - "Failed to print test page": "Échec de l’impression de la page de test" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Échec du rejet de l'appairage" - }, - "Failed to remove device": { - "Failed to remove device": "Échec de la suppression du périphérique" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Échec de la suppression du raccourci clavier" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Échec du retrait de l’imprimante de la classe" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Échec du redémarrage du système audio" - }, - "Failed to restart job": { - "Failed to restart job": "Échec du redémarrage de la tâche" - }, - "Failed to resume printer": { - "Failed to resume printer": "Échec de la reprise de l’imprimante" - }, - "Failed to ring device": { - "Failed to ring device": "Échec de la sonnerie sur l'appareil" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Échec de l'exécution de 'dms greeter status'. Vérifiez que DMS est installé et dans le PATH." - }, - "Failed to save audio config": { - "Failed to save audio config": "Échec de la sauvegarde de la config audio" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Échec de l’enregistrement du paramètre du presse-papiers" - }, - "Failed to save keybind": { - "Failed to save keybind": "Échec de l’enregistrement du raccourci clavier" - }, - "Failed to save profile file": { - "Failed to save profile file": "Échec de la sauvegarde du fichier de profil" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Échec de l'envoi du presse-papier" - }, - "Failed to send file": { - "Failed to send file": "Échec de l'envoi du fichier" - }, - "Failed to send ping": { - "Failed to send ping": "Échec de l'envoi du ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "Échec du réglage de la luminosité" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Échec du réglage de l’emplacement du mode nuit" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Échec du réglage de la planification du mode nuit" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Échec du réglage de la température du mode nuit" - }, - "Failed to set power profile": { - "Failed to set power profile": "Échec lors de l'édition du profil d'alimentation" - }, - "Failed to set profile image": { - "Failed to set profile image": "Échec de la définition de l’image de profil" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Échec de la définition de l’image de profil : %1" - }, - "Failed to share": { - "Failed to share": "Échec du partage" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Échec du démarrage de la connexion à %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Échec du désépinglage de l'entrée" - }, - "Failed to update VPN": { - "Failed to update VPN": "Échec de la mise à jour du VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Échec de la mise à jour de la connexion automatique" - }, - "Failed to update description": { - "Failed to update description": "Échec de la mise à jour de la description" - }, - "Failed to update location": { - "Failed to update location": "Échec de la mise à jour de l’emplacement" - }, - "Failed to update sharing": { - "Failed to update sharing": "Échec de la mise à jour du partage" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Échec de l’écriture du fichier temporaire pour la validation" - }, - "Features": { - "Features": "Fonctionnalités" - }, - "Feels": { - "Feels": "Ressenti" - }, - "Feels Like": { - "Feels Like": "Température ressentie" - }, - "Feels Like %1°": { - "Feels Like %1°": "Ressenti %1°C" - }, - "Fidelity": { - "Fidelity": "Fidelité" - }, - "Field": { - "Field": "Champ" - }, - "File": { - "File": "Fichier" - }, - "File Already Exists": { - "File Already Exists": "Fichier déjà existant" - }, - "File Information": { - "File Information": "Informations sur le fichier" - }, - "File received from": { - "File received from": "Fichier reçu de" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "La recherche de fichiers nécessite dsearch\nInstallez-le depuis github.com/morelazers/dsearch" - }, - "Files": { - "Files": "Fichiers" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Surveillance de l’utilisation du système de fichiers" - }, - "Fill": { - "Fill": "Remplir" - }, - "Find in Text": { - "Find in Text": "Rechercher dans le texte" - }, - "Find in note...": { - "Find in note...": "Rechercher dans la note..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "La disponibilité de l'empreinte n'a pas pu être confirmée." - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Lecteur d'empreintes détecté, mais aucune empreinte n'a encore été enregistrée. Vous pouvez l'activer maintenant et enregistrer une empreinte plus tard." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "Terminer" - }, - "First Day of Week": { - "First Day of Week": "Premier jour de la semaine" - }, - "First Time Setup": { - "First Time Setup": "Configuration initiale" - }, - "Fit": { - "Fit": "Ajuster" - }, - "Fix Now": { - "Fix Now": "Corriger maintenant" - }, - "Fixing...": { - "Fixing...": "Correction en cours..." - }, - "Flags": { - "Flags": "Indicateurs" - }, - "Flipped": { - "Flipped": "Inversé" - }, - "Flipped 180°": { - "Flipped 180°": "Inversé à 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Inversé à 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Inversé à 90°" - }, - "Float": { - "Float": "Flottant" - }, - "Focus": { - "Focus": "Focus" - }, - "Focus at Startup": { - "Focus at Startup": "Focus au démarrage" - }, - "Focused Border": { - "Focused Border": "Bordure active" - }, - "Focused Color": { - "Focused Color": "Couleur active" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Uniquement l'écran sélectionné" - }, - "Focused Window": { - "Focused Window": "Fenêtre active" - }, - "Focused monitor only": { - "Focused monitor only": "Uniquement l'écran sélectionné" - }, - "Fog": { - "Fog": "Brouillard" - }, - "Folder": { - "Folder": "Dossier" - }, - "Folders": { - "Folders": "Dossiers" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Suivre le focus de l’écran" - }, - "Follow focus": { - "Follow focus": "Suivre le focus" - }, - "Font": { - "Font": "Police" - }, - "Font Family": { - "Font Family": "Famille de Polices" - }, - "Font Scale": { - "Font Scale": "Échelle de la police" - }, - "Font Size": { - "Font Size": "Taille de la police" - }, - "Font Weight": { - "Font Weight": "Épaisseur de la police" - }, - "Font used on the login screen": { - "Font used on the login screen": "Police utilisée sur l'écran de verrouillage" - }, - "Force HDR": { - "Force HDR": "Forcer le HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Forcer l'arrêt (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Forcer les couleurs étendues" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Forcer les applications terminal à toujours utiliser des thèmes sombres" - }, - "Forecast": { - "Forecast": "Prévisions" - }, - "Forecast Days": { - "Forecast Days": "Nombre de jours de prévision" - }, - "Forecast Not Available": { - "Forecast Not Available": "Prévisions indisponibles" - }, - "Forever": { - "Forever": "Toujours" - }, - "Forget": { - "Forget": "Oublier" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Oublier \"%1\" ?" - }, - "Forget Device": { - "Forget Device": "Oublier le périphérique" - }, - "Forget Network": { - "Forget Network": "Oublier le réseau" - }, - "Forgot network %1": { - "Forgot network %1": "Réseau %1 oublié" - }, - "Format Legend": { - "Format Legend": "Légende du format" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "%1 paquet trouvé à mettre à jour :" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "%1 paquets trouvés à mettre à jour :" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "Libérer la VRAM/mémoire lorsque le lanceur est fermé. Cela peut provoquer un léger délai à la réouverture." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Bruine verglaçante" - }, - "Frequency": { - "Frequency": "Fréquence" - }, - "Fruit Salad": { - "Fruit Salad": "Salade de fruits" - }, - "Full Command:": { - "Full Command:": "Commande complète :" - }, - "Full Content": { - "Full Content": "Contenu complet" - }, - "Full Day & Month": { - "Full Day & Month": "Jour et mois complets" - }, - "Full with Year": { - "Full with Year": "Complet avec l'année" - }, - "Fullscreen": { - "Fullscreen": "Plein écran" - }, - "Fullscreen Only": { - "Fullscreen Only": "Plein écran seulement" - }, - "Fully Charged": { - "Fully Charged": "Complètement chargé" - }, - "Fun": { - "Fun": "Divertissement" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G : grille • Z/X : taille" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "Surveillance du GPU" - }, - "GPU Temperature": { - "GPU Temperature": "Température GPU" - }, - "GPU temperature display": { - "GPU temperature display": "Affichage de la température du GPU" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE, et plus encore" - }, - "Games": { - "Games": "Jeux" - }, - "Gamma Control": { - "Gamma Control": "Contrôle du gamma" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Le contrôle du gamma n’est pas disponible. Nécessite l’API DMS v6 ou supérieure." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "Générique" - }, - "Get Started": { - "Get Started": "Commencer" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Échelle globale des durées d’animation" - }, - "Golden Hour": { - "Golden Hour": "Heure dorée" - }, - "Good": { - "Good": "Bon" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Rayon des coins gothiques" - }, - "Goth Corners": { - "Goth Corners": "Coins gothiques" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Atténuer progressivement l'écran avant de verrouiller avec un délai configurable" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Atténuer progressivement l'écran avant d'éteindre les écrans avec un délai configurable" - }, - "Graph Time Range": { - "Graph Time Range": "Intervalle temporel du graphique" - }, - "Graphics": { - "Graphics": "Graphiques" - }, - "Greeter": { - "Greeter": "Greeter" - }, - "Greeter Appearance": { - "Greeter Appearance": "Apparence du Greeter" - }, - "Greeter Behavior": { - "Greeter Behavior": "Comportement du Greeter" - }, - "Greeter Status": { - "Greeter Status": "État du Greeter" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Greeter activé. greetd est désormais activé." - }, - "Greeter font": { - "Greeter font": "Police du Greeter" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Greeter seulement — n'affecte pas l'horloge principale" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Greeter seulement — format pour la date sur l'écran de verrouillage" - }, - "Grid": { - "Grid": "Grille" - }, - "Grid Columns": { - "Grid Columns": "Colonnes de la grille" - }, - "Grid: OFF": { - "Grid: OFF": "Grille : désactivée" - }, - "Grid: ON": { - "Grid: ON": "Grille : activée" - }, - "Group": { - "Group": "Groupe" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Regrouper les applications de l'espace de travail" - }, - "Group by App": { - "Group by App": "Regrouper par application" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Regrouper plusieurs fenêtres de la même application avec un indicateur du nombre de fenêtres" - }, - "Group removed": { - "Group removed": "Group supprimé" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Regrouper les icônes d'applications répétées dans les espaces de travail non focalisés" - }, - "Groups": { - "Groups": "Groupes" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Cartographie des tons HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "Le mode HDR est expérimental. Vérifiez que votre écran est compatible HDR avant de l'activer." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML copié dans le presse-papier" - }, - "Health": { - "Health": "Santé" - }, - "Heavy Rain": { - "Heavy Rain": "Forte pluie" - }, - "Heavy Snow": { - "Heavy Snow": "Forte neige" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Fortes averses de neige" - }, - "Height": { - "Height": "Hauteur" - }, - "Held": { - "Held": "Maintenu" - }, - "Help": { - "Help": "Aide" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Veille prolongée" - }, - "Hidden": { - "Hidden": "Masqué" - }, - "Hidden (%1)": { - "Hidden (%1)": "Masqué (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Applis masquées" - }, - "Hidden Network": { - "Hidden Network": "Réseau masqué" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Les applications masquées n’apparaîtront pas dans le lanceur. Faites un clic droit sur une appli et sélectionnez 'Masquer l’appli' pour la masquer." - }, - "Hide": { - "Hide": "Cacher" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Cacher les tiers" - }, - "Hide App": { - "Hide App": "Masquer l'appli" - }, - "Hide Delay": { - "Hide Delay": "Délai de masquage" - }, - "Hide Indicators": { - "Hide Indicators": "Cacher les indicateurs" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Masquer le widget de mise à jour" - }, - "Hide When Typing": { - "Hide When Typing": "Masquer lors de la saisie" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Masquer quand des fenêtres sont ouvertes" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Masquer le curseur après une période d’inactivité (0 = désactivé)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Masquer le curseur lors de l’utilisation du clavier" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Masquer le curseur lors de l’utilisation du tactile" - }, - "Hide device": { - "Hide device": "Masquer l'appareil" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Masquer le contenu des notifications tant qu'elles ne sont pas développées" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Masquer le contenu des notifications tant qu’elles ne sont pas développées; les popups s’affichent réduites par défaut" - }, - "Hide on Touch": { - "Hide on Touch": "Masquer au toucher" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Palette fidèle qui préserve les teintes d'origine." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Mettre en évidence l'appli de l'espace de travail actif" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "Mettre en évidence l'appli sélectionnée dans les indicateurs d'espace de travail" - }, - "History": { - "History": "Historique" - }, - "History Retention": { - "History Retention": "Conservation de l’historique" - }, - "History Settings": { - "History Settings": "Paramètres de l'historique" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Historique effacé. %1 entrées épinglées conservées." - }, - "Hold Duration": { - "Hold Duration": "Durée de maintien" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Maintenez plus longtemps pour confirmer" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Maintenir pour confirmer les actions d'alimentation" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Maintenir pour confirmer (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Maintenir pour confirmer (%1s)" - }, - "Home": { - "Home": "Accueil" - }, - "Host": { - "Host": "Hôte" - }, - "Hostname": { - "Hostname": "Nom d'hôte" - }, - "Hot Corners": { - "Hot Corners": "Coins actifs" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Titre de la superposition des raccourcis clavier (optionnel)" - }, - "Hour": { - "Hour": "Heure" - }, - "Hourly": { - "Hourly": "Par heure" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Nombre de prévisions horaires" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Fréquence de changement de fond d'écran" - }, - "How the background image is scaled": { - "How the background image is scaled": "Comment l'image d'arrière-plan est échelonnée" - }, - "Humidity": { - "Humidity": "Humidité" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Serveur Discord Hyprland" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Surcharges de disposition Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "Options Hyprland" - }, - "Hyprland Website": { - "Hyprland Website": "Site Hyprland" - }, - "I Understand": { - "I Understand": "Je comprends" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "Adresse IP :" - }, - "IP address or hostname": { - "IP address or hostname": "Adresse IP ou nom d'hôte" - }, - "ISO Date": { - "ISO Date": "Date ISO" - }, - "Icon": { - "Icon": "Icône" - }, - "Icon Scale": { - "Icon Scale": "Échelle des icônes" - }, - "Icon Size": { - "Icon Size": "Taille d'icônes" - }, - "Icon Size %": { - "Icon Size %": "Taille d'icône %" - }, - "Icon Theme": { - "Icon Theme": "Thème d'icônes" - }, - "Idle": { - "Idle": "Au repos" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inhibiteur d'inactivité" - }, - "Idle Settings": { - "Idle Settings": "Paramètres d'inactivité" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Surveillance de l'inactivité non prise en charge - nécessite une version plus récente de Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Si le champ est masqué, il apparaîtra dès qu'une touche est pressée." - }, - "Ignore Completely": { - "Ignore Completely": "Ignorer complètement" - }, - "Image": { - "Image": "Image" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Image copiée dans le presse-papier" - }, - "Import": { - "Import": "Importer" - }, - "Import VPN": { - "Import VPN": "Importer VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Couleur d'écran inactif" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Inclure les transitions" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Inclure les actions du bureau (raccourcis) dans les résultats de recherche." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Plugins incompatibles chargés" - }, - "Incorrect password": { - "Incorrect password": "Mot de passe incorrect" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Mot de passe incorrect - tentative %1 sur %2 (un verrouillage peut s'ensuivre)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Mot de passe incorrect - les prochains échecs pourraient activer le verrouillage du compte" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Style d'indicateur" - }, - "Individual Batteries": { - "Individual Batteries": "Batteries individuelles" - }, - "Individual bar configuration": { - "Individual bar configuration": "Configuration individuelle de la barre" - }, - "Info": { - "Info": "Informations" - }, - "Inherit": { - "Inherit": "Hériter" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Hérite des paramètres globaux (par défaut)" - }, - "Inhibitable": { - "Inhibitable": "Inhibable" - }, - "Input Devices": { - "Input Devices": "Périphériques d'entrée" - }, - "Input Volume Slider": { - "Input Volume Slider": "Curseur du volume d'entrée" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Installer" - }, - "Install Greeter": { - "Install Greeter": "Installer Greeter" - }, - "Install Plugin": { - "Install Plugin": "Installer le plugin" - }, - "Install Theme": { - "Install Theme": "Installer le thème" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Installer des thèmes de couleurs depuis le registre de thèmes DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Installation terminée. Greeter a été installé." - }, - "Install failed: %1": { - "Install failed: %1": "Échec de l’installation : %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Installez le paquet matugen pour le thème dynamique" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Installer le plugin « %1 » depuis le registre DMS ?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Installer les plugins depuis le dépôt de plugins DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "Installer le Greeter DMS ? Un terminal va s'ouvrir pour l'authentification sudo." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Installer le thème « %1 » depuis le registre DMS ?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Installation et mise en place de PAM : voir le " - }, - "Installed": { - "Installed": "Installé" - }, - "Installed: %1": { - "Installed: %1": "Installé : %1" - }, - "Installing: %1": { - "Installing: %1": "Installation : %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Masquage automatique" - }, - "Intensity": { - "Intensity": "Intensité" - }, - "Interface:": { - "Interface:": "Interface :" - }, - "Interlock Open": { - "Interlock Open": "Interverrouillage ouvert" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervalle" - }, - "Invalid configuration": { - "Invalid configuration": "Configuration invalide" - }, - "Invert on mode change": { - "Invert on mode change": "Inverser lors du changement de mode" - }, - "Iris Bloom": { - "Iris Bloom": "Floraison Iris" - }, - "Isolate Displays": { - "Isolate Displays": "Isoler les écrans" - }, - "Jobs": { - "Jobs": "Tâches" - }, - "Jobs: ": { - "Jobs: ": "Tâches : " - }, - "Keep Awake": { - "Keep Awake": "Maintenir éveillé" - }, - "Keep Changes": { - "Keep Changes": "Conserver les modifications" - }, - "Keeping Awake": { - "Keeping Awake": "Maintien éveillé" - }, - "Kernel": { - "Kernel": "Noyau" - }, - "Key": { - "Key": "Touche" - }, - "Keybind Sources": { - "Keybind Sources": "Sources des raccourcis clavier" - }, - "Keybinds": { - "Keybinds": "Raccourcis clavier" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Paramètres de recherche des raccourcis clavier" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Afficher les raccourcis clavier dans les résultats de recherche" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Nom de la disposition du clavier" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Raccourcis Clavier" - }, - "Keys": { - "Keys": "Touches" - }, - "Kill": { - "Kill": "Tuer" - }, - "Kill Process": { - "Kill Process": "Forcer l’arrêt du processus" - }, - "Kill Session": { - "Kill Session": "Tuer la session" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "Périphérique LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "Site LabWC" - }, - "Large": { - "Large": "Large" - }, - "Largest": { - "Largest": "Le plus large" - }, - "Last hour": { - "Last hour": "Dernière heure" - }, - "Last launched %1": { - "Last launched %1": "Dernier lancement %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Dernier lancement il y a %1 jour" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Dernier lancement il y a %1 jours" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Dernier lancement il y a %1 heure" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Dernier lancement il y a %1 heures" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Dernier lancement il y a %1 minute" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Dernier lancement il y a %1 minutes" - }, - "Last launched just now": { - "Last launched just now": "Dernier lancement à l’instant" - }, - "Latitude": { - "Latitude": "Latitude" - }, - "Launch": { - "Launch": "Lancer" - }, - "Launch Prefix": { - "Launch Prefix": "Préfixe de lancement" - }, - "Launch on dGPU": { - "Launch on dGPU": "Lancer sur le GPU intégrée" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "Lancer sur dGPU par défaut" - }, - "Launcher": { - "Launcher": "Lanceur" - }, - "Launcher Button": { - "Launcher Button": "Bouton du Lanceur" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Icône du bouton du lanceur" - }, - "Layout": { - "Layout": "Disposition" - }, - "Layout Overrides": { - "Layout Overrides": "Surcharges de disposition" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Gauche" - }, - "Left Center": { - "Left Center": "Au centre à gauche" - }, - "Left Section": { - "Left Section": "Partie gauche" - }, - "Light Direction": { - "Light Direction": "Direction de la lumière" - }, - "Light Mode": { - "Light Mode": "Mode Clair" - }, - "Light Rain": { - "Light Rain": "Pluie légère" - }, - "Light Snow": { - "Light Snow": "Neige légère" - }, - "Light Snow Showers": { - "Light Snow Showers": "Faibles averses de neige" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "Ligne" - }, - "Line: %1": { - "Line: %1": "Ligne : %1" - }, - "Linear": { - "Linear": "Linéaire" - }, - "Lines: %1": { - "Lines: %1": "Lignes : %1" - }, - "List": { - "List": "Liste" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Palette vive avec des accents saturés." - }, - "Load Average": { - "Load Average": "Charge moyenne" - }, - "Loading codecs...": { - "Loading codecs...": "Chargement des codecs..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Chargement des raccourcis clavier..." - }, - "Loading trending...": { - "Loading trending...": "Chargement des tendances..." - }, - "Loading...": { - "Loading...": "Chargement..." - }, - "Local": { - "Local": "Local" - }, - "Locale": { - "Locale": "Régional" - }, - "Locale Settings": { - "Locale Settings": "Paramètres régionaux" - }, - "Location": { - "Location": "Emplacement" - }, - "Location Search": { - "Location Search": "Recherche d’emplacement" - }, - "Lock": { - "Lock": "Verrouiller" - }, - "Lock Screen": { - "Lock Screen": "Écran de verrouillage" - }, - "Lock Screen Display": { - "Lock Screen Display": "Affichage de l’écran de verrouillage" - }, - "Lock Screen Format": { - "Lock Screen Format": "Format de l’écran de verrouillage" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Comportement de l’écran de verrouillage" - }, - "Lock Screen layout": { - "Lock Screen layout": "Disposition de l’écran de verrouillage" - }, - "Lock at startup": { - "Lock at startup": "Verrouillage au démarrage" - }, - "Lock before suspend": { - "Lock before suspend": "Verrouiller avant la mise en veille" - }, - "Lock fade grace period": { - "Lock fade grace period": "Délai de grâce avant le fondu du verrouillage" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "Verrouillé" - }, - "Log Out": { - "Log Out": "Déconnexion" - }, - "Logging in...": { - "Logging in...": "Connexion..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Authentification lors de la connexion" - }, - "Long": { - "Long": "Long" - }, - "Long Text": { - "Long Text": "Texte long" - }, - "Long press": { - "Long press": "Appui long" - }, - "Longitude": { - "Longitude": "Longitude" - }, - "Low Priority": { - "Low Priority": "Faible priorité" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Assurez-vous que KDE Connect ou Valent est lancé sur vos autres appareils" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Gérer et configurer les plugins pour étendre les fonctionnalités de DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Gérez jusqu’à 4 configurations de barres indépendantes. Chaque barre possède sa position, ses widgets, son style et son écran assigné." - }, - "Management": { - "Management": "Gestion" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "Surcharges de disposition MangoWC" - }, - "Manual": { - "Manual": "Manuel" - }, - "Manual Coordinates": { - "Manual Coordinates": "Coordonnées manuelles" - }, - "Manual Direction": { - "Manual Direction": "Direction manuelle" - }, - "Manual Gap Size": { - "Manual Gap Size": "Taille de l’espacement manuel" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Afficher / masquer manuellement" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Associer les classes de fenêtres aux icônes correspondantes" - }, - "Margin": { - "Margin": "Marge" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Cartouche vide" - }, - "Marker Supply Low": { - "Marker Supply Low": "Cartouche presque vide" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Bac de récupération presque plein" - }, - "Marker Waste Full": { - "Marker Waste Full": "Bac de récupération plein" - }, - "Match Criteria": { - "Match Criteria": "Critères de correspondance" - }, - "Matches profile: %1": { - "Matches profile: %1": "Correspond au profil : %1" - }, - "Material Colors": { - "Material Colors": "Couleurs Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Thèmes de couleurs inspirés de Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Couleurs Material générées à partir du fond d’écran" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "Contraste Matugen" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen manquant" - }, - "Matugen Palette": { - "Matugen Palette": "Palette Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Écran cible Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Modèles Matugen" - }, - "Max Edges": { - "Max Edges": "Bordures max" - }, - "Max H": { - "Max H": "H max" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Nombre maximum d'applis épinglées" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Nombre maximum d'applis épinglées (0 = illimité)" - }, - "Max Running Apps": { - "Max Running Apps": "Nombre maximum d'applis lancées" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Nombre maximum d'applis lancées (0 = illimité)" - }, - "Max Volume": { - "Max Volume": "Volume max" - }, - "Max W": { - "Max W": "L max" - }, - "Max apps to show": { - "Max apps to show": "Nombre max d'apps à afficher" - }, - "Max to Edges": { - "Max to Edges": "Maximum vers les bords" - }, - "Maximize": { - "Maximize": "Maximiser" - }, - "Maximize Detection": { - "Maximize Detection": "Détection de maximisation" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Maximiser les icônes des widgets" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Maximiser le texte des widgets" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Taille maximale d’entrée" - }, - "Maximum History": { - "Maximum History": "Historique maximal" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Maximum d'entrées épinglées" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Nombre maximal d’éléments conservés dans le presse-papiers" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Nombre maximum d'entrées qui peuvent être sauvegardées" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Nombre maximal de notifications à conserver" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Le maximum d'entrées épinglées a été atteint" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Taille maximale par élément du presse-papiers" - }, - "Media": { - "Media": "Média" - }, - "Media Controls": { - "Media Controls": "Contrôles multimédias" - }, - "Media Empty": { - "Media Empty": "Support vide" - }, - "Media Jam": { - "Media Jam": "Bourrage papier" - }, - "Media Low": { - "Media Low": "Support faible" - }, - "Media Needed": { - "Media Needed": "Support requis" - }, - "Media Playback": { - "Media Playback": "Lecture multimédia" - }, - "Media Player": { - "Media Player": "Lecteur multimédia" - }, - "Media Player Settings": { - "Media Player Settings": "Paramètres du lecteur multimédia" - }, - "Media Players": { - "Media Players": "Lecteurs multimédia" - }, - "Media Players (": { - "Media Players (": "Lecteurs multimédias (" - }, - "Media Volume": { - "Media Volume": "Volume multimédia" - }, - "Medium": { - "Medium": "Moyen" - }, - "Memory": { - "Memory": "Mémoire" - }, - "Memory Graph": { - "Memory Graph": "Graphique de la mémoire" - }, - "Memory Usage": { - "Memory Usage": "Utilisation mémoire" - }, - "Memory usage indicator": { - "Memory usage indicator": "Indicateur d’utilisation de la mémoire" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Message" - }, - "Message Content": { - "Message Content": "Contenu du message" - }, - "Microphone": { - "Microphone": "Microphone" - }, - "Microphone Mute": { - "Microphone Mute": "Couper le microphone" - }, - "Microphone Volume": { - "Microphone Volume": "Volume du microphone" - }, - "Microphone settings": { - "Microphone settings": "Paramètres du microphone" - }, - "Microphone volume control": { - "Microphone volume control": "Contrôle du volume du microphone" - }, - "Middle Section": { - "Middle Section": "Section centrale" - }, - "Min H": { - "Min H": "H min" - }, - "Min W": { - "Min W": "L min" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Palette minimaliste basée sur une seule teinte." - }, - "Minute": { - "Minute": "Minute" - }, - "Mirror Display": { - "Mirror Display": "Dupliquer l’écran" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Variables d'environnement manquantes" - }, - "Modal Background": { - "Modal Background": "Arrière-plan modal" - }, - "Modal Shadows": { - "Modal Shadows": "Ombres des modales" - }, - "Modals": { - "Modals": "Modales" - }, - "Mode": { - "Mode": "Mode" - }, - "Mode:": { - "Mode:": "Mode :" - }, - "Model": { - "Model": "Modèle" - }, - "Modified": { - "Modified": "Modifié" - }, - "Modular widget bar": { - "Modular widget bar": "Barre de widgets modulaire" - }, - "Monitor": { - "Monitor": "Moniteur" - }, - "Monitor Configuration": { - "Monitor Configuration": "Configuration de l’écran" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Délai de grâce avant le fondu de l’écran" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Écran dont le fond d’écran définit les couleurs dynamiques" - }, - "Monochrome": { - "Monochrome": "Monochrome" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "Police Monospace" - }, - "Month Date": { - "Month Date": "Date mois" - }, - "Morning": { - "Morning": "Matin" - }, - "Mount Points": { - "Mount Points": "Points de montage" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Apparence du pointeur de la souris" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Taille du pointeur de la souris en pixels" - }, - "Move": { - "Move": "Déplacer" - }, - "Move Widget": { - "Move Widget": "Déplacer le widget" - }, - "Moving to Paused": { - "Moving to Paused": "Mise en pause en cours" - }, - "Multi-Monitor": { - "Multi-Monitor": "Multi-écrans" - }, - "Multiplexer": { - "Multiplexer": "Multiplexeur" - }, - "Multiplexer Type": { - "Multiplexer Type": "Type de multiplexeur" - }, - "Multiplexers": { - "Multiplexers": "Multiplexeurs" - }, - "Music": { - "Music": "Musique" - }, - "Mute Popups": { - "Mute Popups": "Mettre les popups en sourdine" - }, - "Mute popups for %1": { - "Mute popups for %1": "Popup en sourdine pour %1" - }, - "Muted": { - "Muted": "Muet" - }, - "Muted Apps": { - "Muted Apps": "Applis en sourdine" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Palette atténuée aux tons doux et apaisants." - }, - "NM not supported": { - "NM not supported": "NM non pris en charge" - }, - "Name": { - "Name": "Nom" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Icônes d’espaces de travail nommés" - }, - "Navigate": { - "Navigate": "Naviguer" - }, - "Navigation": { - "Navigation": "Navigation" - }, - "Network": { - "Network": "Réseau" - }, - "Network Graph": { - "Network Graph": "Graphique réseau" - }, - "Network Info": { - "Network Info": "Info réseau" - }, - "Network Information": { - "Network Information": "Informations réseau" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Nom du réseau (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Moniteur de vitesse réseau" - }, - "Network Status": { - "Network Status": "État du réseau" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Affichage des vitesses de téléchargement et d’envoi du réseau" - }, - "Neutral": { - "Neutral": "Neutre" - }, - "Never": { - "Never": "Jamais" - }, - "Never used": { - "Never used": "Jamais utilisé" - }, - "New": { - "New": "Nouveau" - }, - "New Key": { - "New Key": "Nouvelle touche" - }, - "New Keybind": { - "New Keybind": "Nouveau raccourci clavier" - }, - "New Notification": { - "New Notification": "Nouvelle notification" - }, - "New Session": { - "New Session": "Nouvelle session" - }, - "New Window Rule": { - "New Window Rule": "Nouvelle règle de fenêtre" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Nom du nouveau groupe..." - }, - "Next": { - "Next": "Suivant" - }, - "Next Transition": { - "Next Transition": "Prochaine transition" - }, - "Night": { - "Night": "Nuit" - }, - "Night Mode": { - "Night Mode": "Mode nuit" - }, - "Night Temperature": { - "Night Temperature": "Température de nuit" - }, - "Night mode & gamma": { - "Night mode & gamma": "Mode nuit et gamma" - }, - "Niri Integration": { - "Niri Integration": "Intégration Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Surcharges de disposition Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Actions du compositeur Niri (focus, déplacement, etc.)" - }, - "No": { - "No": "Non" - }, - "No Active Players": { - "No Active Players": "Aucun lecteur actif" - }, - "No Anim": { - "No Anim": "Pas d'animation" - }, - "No Background": { - "No Background": "Aucun arrière-plan" - }, - "No Battery": { - "No Battery": "Aucune batterie" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Aucun adaptateur Bluetooth détecté" - }, - "No Blur": { - "No Blur": "Pas de flou" - }, - "No Border": { - "No Border": "Pas de bordure" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Aucun raccourci DMS configuré" - }, - "No Dim": { - "No Dim": "Ne pas assombrir" - }, - "No Focus": { - "No Focus": "Ne pas prendre le focus" - }, - "No GPU detected": { - "No GPU detected": "Aucun GPU détecté" - }, - "No GPUs detected": { - "No GPUs detected": "Aucun GPU détecté" - }, - "No History": { - "No History": "Pas d'historique" - }, - "No Media": { - "No Media": "Aucun média" - }, - "No Round": { - "No Round": "Pas d'arrondi" - }, - "No Rounding": { - "No Rounding": "Pas d'arrondi" - }, - "No Shadow": { - "No Shadow": "Pas d'ombre" - }, - "No VPN profiles": { - "No VPN profiles": "Aucun profil VPN" - }, - "No Weather": { - "No Weather": "Aucune météo" - }, - "No Weather Data": { - "No Weather Data": "Aucune donnée météo" - }, - "No Weather Data Available": { - "No Weather Data Available": "Aucune donnée météorologique disponible" - }, - "No action": { - "No action": "Aucune action" - }, - "No active %1 sessions": { - "No active %1 sessions": "Aucune session %1 active" - }, - "No adapter": { - "No adapter": "Aucun adaptateur" - }, - "No adapters": { - "No adapters": "Aucun adaptateur" - }, - "No app customizations.": { - "No app customizations.": "Aucune personnalisation des applis." - }, - "No apps found": { - "No apps found": "Aucune appli trouvée" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Aucune appli n'a été lancée pour le moment." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Aucune appli en sourdine. Faites un clic droit sur une notification et choisir \"Mettre en sourdine\" pour l'ajouter." - }, - "No battery": { - "No battery": "Aucune batterie" - }, - "No brightness devices available": { - "No brightness devices available": "Aucun périphérique de réglage de la luminosité disponible" - }, - "No changes": { - "No changes": "Aucune modification" - }, - "No checks passed": { - "No checks passed": "Aucune vérification réussie" - }, - "No custom theme file": { - "No custom theme file": "Aucun fichier de thème personnalisé" - }, - "No devices": { - "No devices": "Aucun appareil" - }, - "No devices connected": { - "No devices connected": "Aucun appareil connecté" - }, - "No devices found": { - "No devices found": "Aucun périphérique trouvé" - }, - "No disk data": { - "No disk data": "Aucune donnée de disque" - }, - "No disk data available": { - "No disk data available": "Aucune donnée de disque disponible" - }, - "No drivers found": { - "No drivers found": "Aucun pilote trouvé" - }, - "No errors": { - "No errors": "Aucune erreur" - }, - "No features enabled": { - "No features enabled": "Aucune fonctionnalité activée" - }, - "No files found": { - "No files found": "Aucun fichier trouvé" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Aucun lecteur d'empreintes détecté." - }, - "No folders found": { - "No folders found": "Aucun dossier trouvé" - }, - "No hidden apps.": { - "No hidden apps.": "Aucune appli masquée." - }, - "No info items": { - "No info items": "Aucune information" - }, - "No information available": { - "No information available": "Aucune information disponible" - }, - "No input device": { - "No input device": "Aucun appareil d'entrée" - }, - "No input devices found": { - "No input devices found": "Aucun périphérique d'entrée trouvé" - }, - "No items added yet": { - "No items added yet": "Aucun élément ajouté pour le moment" - }, - "No keybinds found": { - "No keybinds found": "Aucun raccourci clavier trouvé" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Aucun plugins de Lanceur installé." - }, - "No match criteria": { - "No match criteria": "Aucun critère correspondant" - }, - "No matches": { - "No matches": "Aucune correspondance" - }, - "No matching processes": { - "No matching processes": "Aucun processus correspondant" - }, - "No monitors": { - "No monitors": "Aucun moniteur" - }, - "No mount points found": { - "No mount points found": "Aucun point de montage trouvé" - }, - "No output device": { - "No output device": "Aucun appareil de sortie" - }, - "No output devices found": { - "No output devices found": "Aucun périphérique de sortie trouvé" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Aucun gestionnaire de paquets trouvé. Installer 'paru' ou 'yay' sur les systèmes basés sur Arch pour vérifier les mises à jour." - }, - "No plugin results": { - "No plugin results": "Aucun résultat pour les plugins" - }, - "No plugins found": { - "No plugins found": "Aucun plugin trouvé" - }, - "No plugins found.": { - "No plugins found.": "Aucun plugin trouvé." - }, - "No printer found": { - "No printer found": "Aucune imprimante trouvée" - }, - "No printers configured": { - "No printers configured": "Aucune imprimante configurée" - }, - "No printers found": { - "No printers found": "Aucune imprimante trouvée" - }, - "No profiles": { - "No profiles": "Aucun profil" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Aucune entrée récente trouvée dans le presse-papier" - }, - "No results found": { - "No results found": "Aucun résultat trouvé" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Aucune entrée du presse-papier sauvegardée" - }, - "No sessions found": { - "No sessions found": "Aucune session trouvée" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "Aucun thème trouvé" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Aucun thème installé. Parcourez les thèmes pour en installer depuis le registre." - }, - "No trigger": { - "No trigger": "Aucun déclencheur" - }, - "No video found in folder": { - "No video found in folder": "Aucune vidéo trouvée dans le dossier" - }, - "No wallpaper selected": { - "No wallpaper selected": "Aucun fond d’écran sélectionné" - }, - "No wallpapers": { - "No wallpapers": "Aucun fond d'écran" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Aucun fond d'écran trouvé\n\nCliquer l'icône du dossier en bas pour parcourir" - }, - "No warnings": { - "No warnings": "Aucun avertissement" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Aucun widget ajouté. Cliquer sur \"Ajouter widget\" pour commencer." - }, - "No widgets available": { - "No widgets available": "Aucun widget disponible" - }, - "No widgets match your search": { - "No widgets match your search": "Aucun widget ne correspond à votre recherche" - }, - "No window rules configured": { - "No window rules configured": "Aucune règle de fenêtre configurée" - }, - "None": { - "None": "Aucun" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Police normale" - }, - "Normal Priority": { - "Normal Priority": "Priorité normale" - }, - "Not available": { - "Not available": "Non disponible" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Non disponible — installez fprintd et pam_fprintd, ou configurez greetd PAM." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Non disponible — installez fprintd et pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Non disponible — installez ou configurez pam_u2f." - }, - "Not connected": { - "Not connected": "Non connecté" - }, - "Not detected": { - "Not detected": "Non détecté" - }, - "Not paired": { - "Not paired": "Non appairé" - }, - "Not set": { - "Not set": "Non défini" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Remarque : cela modifie uniquement le pourcentage et ne limite pas réellement la charge." - }, - "Notepad": { - "Notepad": "Bloc-notes" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Paramètres de police du bloc-notes" - }, - "Notepad Slideout": { - "Notepad Slideout": "Panneau du bloc-notes" - }, - "Nothing": { - "Nothing": "Rien" - }, - "Nothing to see here": { - "Nothing to see here": "Rien à voir ici." - }, - "Notification Center": { - "Notification Center": "Centre de Notifications" - }, - "Notification Display": { - "Notification Display": "Affichage des notifications" - }, - "Notification Overlay": { - "Notification Overlay": "Superposition de notifications" - }, - "Notification Popups": { - "Notification Popups": "Notifications contextuelles" - }, - "Notification Rules": { - "Notification Rules": "Règles de notification" - }, - "Notification Settings": { - "Notification Settings": "Paramètres de notifications" - }, - "Notification Timeouts": { - "Notification Timeouts": "Délais d’affichage des notifications" - }, - "Notification toast popups": { - "Notification toast popups": "Notifications éphémères à l’écran" - }, - "Notifications": { - "Notifications": "Notifications" - }, - "Numbers": { - "Numbers": "Nombres" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numérique (J/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numérique (M/J)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Logo de l'OS" - }, - "OSD Position": { - "OSD Position": "Position de l’OSD" - }, - "Occupied Color": { - "Occupied Color": "Couleur occupée" - }, - "Off": { - "Off": "Désactivé" - }, - "Office": { - "Office": "Bureau" - }, - "Offline": { - "Offline": "Hors ligne" - }, - "Offline Report": { - "Offline Report": "Rapport hors ligne" - }, - "Older": { - "Older": "Plus ancien" - }, - "On": { - "On": "Activé" - }, - "On-Demand": { - "On-Demand": "Sur demande" - }, - "On-Screen Displays": { - "On-Screen Displays": "Affichages à l’écran" - }, - "On-screen Displays": { - "On-screen Displays": "Affichages à l’écran" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Ajuster le gamma uniquement en fonction de l’heure ou de l’emplacement." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Afficher uniquement les fenêtres de l'écran actuel sur chaque dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Visible uniquement si l’hibernation est prise en charge par votre système" - }, - "Opacity": { - "Opacity": "Opacité" - }, - "Opaque": { - "Opaque": "Opaque" - }, - "Open": { - "Open": "Ouvrir" - }, - "Open App": { - "Open App": "Ouvrir appli" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Ouvrir KDE Connect sur votre téléphone" - }, - "Open Notepad File": { - "Open Notepad File": "Ouvrir un fichier du bloc-notes" - }, - "Open a new note": { - "Open a new note": "Ouvrir une nouvelle note" - }, - "Open folder": { - "Open folder": "Ouvrir dossier" - }, - "Open in Browser": { - "Open in Browser": "Ouvrir dans le navigateur" - }, - "Open in terminal": { - "Open in terminal": "Ouvrir dans le terminal" - }, - "Open search bar to find text": { - "Open search bar to find text": "Ouvrir la barre de recherche pour trouver du texte" - }, - "Open with...": { - "Open with...": "Ouvrir avec..." - }, - "Opening SMS": { - "Opening SMS": "Ouvrir les SMS" - }, - "Opening SMS app": { - "Opening SMS app": "Ouvrir l'appli SMS" - }, - "Opening file browser": { - "Opening file browser": "Ouvrir l'explorateur de fichiers" - }, - "Opening files": { - "Opening files": "Ouvrir les fichiers" - }, - "Opening terminal: ": { - "Opening terminal: ": "Ouverture du terminal : " - }, - "Optional description": { - "Optional description": "Description facultative" - }, - "Optional location": { - "Optional location": "Emplacement facultatif" - }, - "Options": { - "Options": "Options" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Organiser les widgets en groupes repliables" - }, - "Original: %1": { - "Original: %1": "Original : %1" - }, - "Other": { - "Other": "Autre" - }, - "Outline": { - "Outline": "Contour" - }, - "Output": { - "Output": "Sortie" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Zone de sortie presque pleine" - }, - "Output Area Full": { - "Output Area Full": "Zone de sortie pleine" - }, - "Output Device": { - "Output Device": "Appareil de sortie" - }, - "Output Devices": { - "Output Devices": "Périphériques de sortie" - }, - "Output Tray Missing": { - "Output Tray Missing": "Bac de sortie manquant" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Les sorties incluent des éléments manquants" - }, - "Overcast": { - "Overcast": "Couvert" - }, - "Overflow": { - "Overflow": "Débordement" - }, - "Overridden by config": { - "Overridden by config": "Surchargé par la configuration" - }, - "Override": { - "Override": "Modifier" - }, - "Override Border Size": { - "Override Border Size": "Forcer la taille de la bordure" - }, - "Override Corner Radius": { - "Override Corner Radius": "Forcer l'arrondi des coins" - }, - "Override Gaps": { - "Override Gaps": "Forcer les espacements" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Remplacer les paramètres de mise en page globale pour cette sortie" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Surcharger le terminal avec une commande personnalisée ou un script" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "Surcharger l'ombre globale avec des paramètres par barre" - }, - "Overrides": { - "Overrides": "Remplacements" - }, - "Overview": { - "Overview": "Aperçu" - }, - "Overview of your network connections": { - "Overview of your network connections": "Aperçu de vos connexions réseau" - }, - "Overwrite": { - "Overwrite": "Écraser" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM fourni déjà une authentification par empreinte. Activez ceci pour l'afficher lors de la connexion." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM fourni déjà une authentification par clé de sécurité. Activez ceci pour l'afficher lors de la connexion." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM fourni l'authentification par empreinte, mais aucune empreinte n'a été encore enregistrée." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM fourni l'authentification par empreinte, mais aucun lecteur n'a été détecté." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Remplissage" - }, - "Pad Hours": { - "Pad Hours": "Heures facturées" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Marge" - }, - "Pair": { - "Pair": "Appairer" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Appairer un périphérique Bluetooth" - }, - "Paired": { - "Paired": "Appairé" - }, - "Pairing": { - "Pairing": "Connexion" - }, - "Pairing failed": { - "Pairing failed": "Échec de l’appairage" - }, - "Pairing request from": { - "Pairing request from": "Demande d'appairage de" - }, - "Pairing request sent": { - "Pairing request sent": "Demande d'appairage envoyée" - }, - "Pairing requested": { - "Pairing requested": "Appairage demandé" - }, - "Pairing...": { - "Pairing...": "Appairage en cours..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Partiellement nuageux" - }, - "Passkey:": { - "Passkey:": "Code d’accès :" - }, - "Password": { - "Password": "Mot de passe" - }, - "Password...": { - "Password...": "Mot de passe..." - }, - "Paste": { - "Paste": "Coller" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Chemin vers un fichier vidéo ou dossier contenant des vidéos" - }, - "Pattern": { - "Pattern": "Motif" - }, - "Pause": { - "Pause": "Pause" - }, - "Paused": { - "Paused": "En pause" - }, - "Pending": { - "Pending": "En attente" - }, - "Pending Charge": { - "Pending Charge": "Charge en attente" - }, - "Pending Discharge": { - "Pending Discharge": "Décharge en attente" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Fonds d’écran par mode" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Fonds d’écran par écran" - }, - "Per-screen config": { - "Per-screen config": "Configuration par écran" - }, - "Percentage": { - "Percentage": "Pourcentage" - }, - "Performance": { - "Performance": "Performance" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Permission refusée pour définir l’image de profil." - }, - "Personalization": { - "Personalization": "Personnalisation" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Connexion au téléphone non disponible" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Connexion au téléphone indisponible" - }, - "Phone number": { - "Phone number": "Numéro de téléphone" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Choisir une vidéo différente aléatoirement du même dossier à chaque fois" - }, - "Pictures": { - "Pictures": "Photos" - }, - "Pin": { - "Pin": "Épingler" - }, - "Pin to Dock": { - "Pin to Dock": "Épingler au dock" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping envoyé" - }, - "Ping sent to": { - "Ping sent to": "Ping envoyé à" - }, - "Pinned": { - "Pinned": "Épinglé" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Applis épinglées et lancées avec glisser-déposer" - }, - "Pixelate": { - "Pixelate": "Pixelliser" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Placez ici les dossiers de plugins. Chaque plugin doit contenir un fichier manifeste plugin.json." - }, - "Place plugins in %1": { - "Place plugins in %1": "Placez les plugins dans %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Lancer une vidéo lorsque l'écran se verrouille." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Jouer un son à l’arrivée d’une nouvelle notification" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Jouer un son lors de la connexion du câble d’alimentation" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Jouer un son lors du réglage du volume" - }, - "Play sounds for system events": { - "Play sounds for system events": "Jouer les sons pour les événements système" - }, - "Playback": { - "Playback": "Lecture" - }, - "Playback error: ": { - "Playback error: ": "Erreur de lecture : " - }, - "Please wait...": { - "Please wait...": "Veuillez patienter..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Entrer un nom pour votre nouvelle session %1" - }, - "Plugged In": { - "Plugged In": "Branché" - }, - "Plugged in": { - "Plugged in": "Branché" - }, - "Plugin": { - "Plugin": "Plugin" - }, - "Plugin Directory": { - "Plugin Directory": "Répertoire des plugins" - }, - "Plugin Management": { - "Plugin Management": "Gestion des plugins" - }, - "Plugin Visibility": { - "Plugin Visibility": "Visibilité du plugin" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Plugin désactivé – activez-le dans les paramètres des plugins" - }, - "Plugins": { - "Plugins": "Plugins" - }, - "Pointer": { - "Pointer": "Curseur" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "Fenêtres détachables" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Les popouts et modales suivent la vitesse d’animation globale (désactivez pour les personnaliser indépendamment)" - }, - "Popup Only": { - "Popup Only": "Popup seulement" - }, - "Popup Position": { - "Popup Position": "Position du popup" - }, - "Popup Shadow": { - "Popup Shadow": "Ombre de la popup" - }, - "Popup Transparency": { - "Popup Transparency": "Transparence du popup" - }, - "Popup behavior, position": { - "Popup behavior, position": "Comportement et position des notifications" - }, - "Port": { - "Port": "Port" - }, - "Portal": { - "Portal": "Portail" - }, - "Position": { - "Position": "Position" - }, - "Position, pinned apps": { - "Position, pinned apps": "Position, applications épinglées" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Conflits possibles de surcharge" - }, - "Power": { - "Power": "Alimentation" - }, - "Power & Security": { - "Power & Security": "Alimentation et sécurité" - }, - "Power & Sleep": { - "Power & Sleep": "Alimentation et mise en veille" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Confirmation de l’action d’alimentation" - }, - "Power Menu Customization": { - "Power Menu Customization": "Personnalisation du menu d’alimentation" - }, - "Power Off": { - "Power Off": "Arrêter" - }, - "Power Options": { - "Power Options": "Options d’alimentation" - }, - "Power Profile": { - "Power Profile": "Profil d’alimentation" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Dégradation du profil d’alimentation" - }, - "Power Saver": { - "Power Saver": "Économie d'énergie" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Éteindre les écrans au verrouillage" - }, - "Power profile management available": { - "Power profile management available": "Gestion du profil d’alimentation disponible" - }, - "Power source": { - "Power source": "Source d’alimentation" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Pré-remplir le dernier nom d'utilisateur connecté avec succès sur le greeter" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "Précipitations" - }, - "Precipitation": { - "Precipitation": "Précipitations" - }, - "Precipitation Chance": { - "Precipitation Chance": "Probabilité de précipitations" - }, - "Preference": { - "Preference": "Préférence" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Largeurs prédéfinies (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Appuyez sur 'n' ou cliquez sur 'Nouvelle session' pour en créer une" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Appuyer sur Entrer et le système audio redémarrera pour appliquer les changements" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Appuyer sur Entrée pour coller, Shift+Entrée pour copier" - }, - "Press key...": { - "Press key...": "Appuyez sur la touche..." - }, - "Pressure": { - "Pressure": "Pression" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Empêcher la mise en veille de l’écran" - }, - "Preview": { - "Preview": "Aperçu" - }, - "Primary": { - "Primary": "Principal" - }, - "Primary Container": { - "Primary Container": "Conteneur primaire" - }, - "Print Server Management": { - "Print Server Management": "Gestion du serveur d’impression" - }, - "Print Server not available": { - "Print Server not available": "Serveur d’impression non disponible" - }, - "Printer": { - "Printer": "Imprimante" - }, - "Printer Classes": { - "Printer Classes": "Classes d’imprimantes" - }, - "Printer created successfully": { - "Printer created successfully": "Imprimante créée avec succès" - }, - "Printer deleted": { - "Printer deleted": "Imprimante supprimée" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nom de l’imprimante (sans espaces)" - }, - "Printer reachable": { - "Printer reachable": "Imprimante disponible" - }, - "Printers": { - "Printers": "Imprimantes" - }, - "Printers: ": { - "Printers: ": "Imprimantes : " - }, - "Prioritize performance": { - "Prioritize performance": "Prioriser les performances" - }, - "Priority": { - "Priority": "Priorité" - }, - "Privacy Indicator": { - "Privacy Indicator": "Indicateur de confidentialité" - }, - "Privacy Mode": { - "Privacy Mode": "Mode privé" - }, - "Private Key Password": { - "Private Key Password": "Mot de passe de clé privée" - }, - "Process Count": { - "Process Count": "Nombre de processus" - }, - "Processes": { - "Processes": "Processus" - }, - "Processes:": { - "Processes:": "Processus :" - }, - "Processing": { - "Processing": "Traitement en cours" - }, - "Profile Image Error": { - "Profile Image Error": "Erreur de l’image de profil" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profil activé : %1" - }, - "Profile deleted": { - "Profile deleted": "Profil supprimé" - }, - "Profile error": { - "Profile error": "Erreur du profil" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "L’image de profil est trop grande. Veuillez utiliser une image plus petite." - }, - "Profile name": { - "Profile name": "Nom du profil" - }, - "Profile not found": { - "Profile not found": "Profil introuvable" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profil sauvegardé : %1" - }, - "Protocol": { - "Protocol": "Protocole" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia n'est pas disponible" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia n'est pas disponible - l'économiseur d'écran vidéo requiert les services qt multimedia" - }, - "Quick Access": { - "Quick Access": "Accès rapide" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Accès rapide au lanceur d’applications" - }, - "Quick access to color picker": { - "Quick access to color picker": "Accès rapide au sélecteur de couleurs" - }, - "Quick access to notepad": { - "Quick access to notepad": "Accès rapide au bloc-notes" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Panneau coulissant pour notes rapides" - }, - "Quick system toggles": { - "Quick system toggles": "Raccourcis système rapides" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Rayon" - }, - "Rain": { - "Rain": "Pluie" - }, - "Rain Chance": { - "Rain Chance": "Risque de pluie" - }, - "Rainbow": { - "Rainbow": "Arc-en-ciel" - }, - "Random": { - "Random": "Aléatoire" - }, - "Rate": { - "Rate": "Taux" - }, - "Read:": { - "Read:": "Lire :" - }, - "Reason": { - "Reason": "Raison" - }, - "Reboot": { - "Reboot": "Redémarrer" - }, - "Recent Colors": { - "Recent Colors": "Couleurs récentes" - }, - "Recently Used Apps": { - "Recently Used Apps": "Applications récemment utilisées" - }, - "Recommended available": { - "Recommended available": "Recommandé disponible" - }, - "Refresh": { - "Refresh": "Actualiser" - }, - "Refresh Weather": { - "Refresh Weather": "Actualiser la météo" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Rejeter" - }, - "Reject Jobs": { - "Reject Jobs": "Refuser les tâches" - }, - "Release": { - "Release": "Version" - }, - "Reload Plugin": { - "Reload Plugin": "Recharger le module" - }, - "Remaining": { - "Remaining": "Restant" - }, - "Remaining / Total": { - "Remaining / Total": "Restant / Total" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "Se souvenir de la dernière session" - }, - "Remember last user": { - "Remember last user": "Se souvenir du dernier utilisateur" - }, - "Remove": { - "Remove": "Supprimer" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Supprimer la marge interne des widgets" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Supprimer les marges et bordures lorsque les fenêtres sont maximisées" - }, - "Rename": { - "Rename": "Renommer" - }, - "Rename Session": { - "Rename Session": "Renommer la session" - }, - "Rename Workspace": { - "Rename Workspace": "Renommer l'espace de travail" - }, - "Repeat": { - "Repeat": "Répéter" - }, - "Replacement": { - "Replacement": "Remplacement" - }, - "Report": { - "Report": "Rapport" - }, - "Request Pairing": { - "Request Pairing": "Demander l'appairage" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Nécessite de maintenir le bouton/la touche pour confirmer arrêt, redémarrage, suspension, hibernation et déconnexion" - }, - "Required plugin: ": { - "Required plugin: ": "Plugin requis : " - }, - "Requires %1": { - "Requires %1": "Nécessite %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Nécessite l’outil 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "Nécessite DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Nécessite un compositeur DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Nécessite le support du mode nuit" - }, - "Reset": { - "Reset": "Réinitialiser" - }, - "Reset Position": { - "Reset Position": "Réinitialiser la position" - }, - "Reset Size": { - "Reset Size": "Réinitialiser la taille" - }, - "Reset to default name": { - "Reset to default name": "Réinitialiser le nom par défaut" - }, - "Resize Widget": { - "Resize Widget": "Redimensionner le widget" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Résolution et rafraîchissement" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Résolution, position, mise à l’échelle" - }, - "Restart DMS": { - "Restart DMS": "Redémarrer DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Redémarrer DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Redémarrage du système audio..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Reprendre" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Inverser la direction du défilement" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Inverser la direction du changement d’espace lors du défilement sur la barre" - }, - "Revert": { - "Revert": "Annuler" - }, - "Right": { - "Right": "Droite" - }, - "Right Center": { - "Right Center": "Au centre à droite" - }, - "Right Section": { - "Right Section": "Partie droite" - }, - "Right Tiling": { - "Right Tiling": "Mosaïque droite" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Clic droit et glisser n’importe où sur le widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Clic droit et glisser la coin inférieur droit" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Clic droit sur le widget de la barre pour faire défiler" - }, - "Ring": { - "Ring": "Faire sonner" - }, - "Ringing": { - "Ringing": "En train de sonner" - }, - "Ripple Effects": { - "Ripple Effects": "Effets d'ondulation" - }, - "Root Filesystem": { - "Root Filesystem": "Système de fichiers racine" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Coins arrondis pour les fenêtres" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Coins arrondis pour les fenêtres (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Coins arrondis pour les fenêtres (decoration.rounding)" - }, - "Rule": { - "Rule": "Règle" - }, - "Rule Name": { - "Rule Name": "Nom de la règle" - }, - "Rules (%1)": { - "Rules (%1)": "Règles (%1)" - }, - "Run Again": { - "Run Again": "Relancer" - }, - "Run DMS Templates": { - "Run DMS Templates": "Exécuter les modèles DMS" - }, - "Run User Templates": { - "Run User Templates": "Exécuter les modèles utilisateur" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Exécuter un programme (ex. : firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Exécuter une commande shell (ex. : notify-send)" - }, - "Running Apps": { - "Running Apps": "Applications en cours" - }, - "Running Apps Settings": { - "Running Apps Settings": "Paramètres des applications en cours" - }, - "Running greeter sync…": { - "Running greeter sync…": "Synchro du greeter en cours…" - }, - "SDR Brightness": { - "SDR Brightness": "Luminosité SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Saturation SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Enregistrer" - }, - "Save Notepad File": { - "Save Notepad File": "Enregistrer le fichier" - }, - "Save QR Code": { - "Save QR Code": "Sauvegarder code QR" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Enregistrer et basculer entre les configurations d’affichage" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Enregistrer les notifications de priorité critique dans l’historique" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Enregistrer les notifications ignorées dans l’historique" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Enregistrer les notifications de faible priorité dans l’historique" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Enregistrer les notifications de priorité normale dans l’historique" - }, - "Save password": { - "Save password": "Enregistrer le mot de passe" - }, - "Saved": { - "Saved": "Enregistré" - }, - "Saved Configurations": { - "Saved Configurations": "Configurations enregistrées" - }, - "Saved Note": { - "Saved Note": "Note sauvegardée" - }, - "Saved item deleted": { - "Saved item deleted": "Élément sauvegardé supprimé" - }, - "Saving...": { - "Saving...": "Sauvegarde..." - }, - "Scale": { - "Scale": "Échelle" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Échelle des polices de la barre indépendamment" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "Mettre à l’échelle les icônes de la DankBar indépendamment" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Échelle de toutes les polices dans le shell" - }, - "Scan": { - "Scan": "Scanner" - }, - "Scanning": { - "Scanning": "Scan en cours" - }, - "Scanning...": { - "Scanning...": "Scan en cours..." - }, - "Science": { - "Science": "Science" - }, - "Score": { - "Score": "Score" - }, - "Screen Sharing": { - "Screen Sharing": "Partage d'écran" - }, - "Screen sharing": { - "Screen sharing": "Partage d’écran" - }, - "Scroll": { - "Scroll": "Défiler" - }, - "Scroll Factor": { - "Scroll Factor": "Sensibilité du défilement" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Molette" - }, - "Scroll song title": { - "Scroll song title": "Faire défiler le titre de la chanson" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Faire défiler le titre si il ne tient pas dans le widget" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Comportement de la molette sur le widget média" - }, - "Scrolling": { - "Scrolling": "Défilement" - }, - "Search App Actions": { - "Search App Actions": "Chercher des actions d'appli" - }, - "Search Options": { - "Search Options": "Chercher des options" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Recherchez par combinaison de touches, description ou nom de l’action.\n\nL’action par défaut copie le raccourci dans le presse-papiers.\nCliquez droit ou appuyez sur la flèche droite pour épingler les raccourcis fréquents – ils apparaîtront en haut lorsqu’aucune recherche n’est effectuée." - }, - "Search for a location...": { - "Search for a location...": "Rechercher un emplacement..." - }, - "Search keybinds...": { - "Search keybinds...": "Rechercher des raccourcis..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Rechercher les raccourcis clavier dans le compositeur et les applications" - }, - "Search plugins...": { - "Search plugins...": "Rechercher un plugin..." - }, - "Search processes...": { - "Search processes...": "Chercher des processus..." - }, - "Search sessions...": { - "Search sessions...": "Chercher les sessions..." - }, - "Search themes...": { - "Search themes...": "Rechercher des thèmes…" - }, - "Search widgets...": { - "Search widgets...": "Rechercher des widgets..." - }, - "Search...": { - "Search...": "Rechercher..." - }, - "Searching...": { - "Searching...": "Recherche en cours..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Deux facteurs (AND)" - }, - "Secondary": { - "Secondary": "Secondaire" - }, - "Secured": { - "Secured": "Sécurisé" - }, - "Security": { - "Security": "Sécurité" - }, - "Security & privacy": { - "Security & privacy": "Sécurité et confidentialité" - }, - "Security key mode": { - "Security key mode": "Mode clé de sécurité" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "La disponibilité de la clé de sécurité n'a pas pu être confirmée." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Le support pour la clé de sécurité a été détecté, mais aucune clé n'a été enregistrée pour le moment. Vous pouvez activer cette option maintenant et en enregistrer une plus tard." - }, - "Select": { - "Select": "Sélectionner" - }, - "Select Application": { - "Select Application": "Sélectionner une application" - }, - "Select Bar": { - "Select Bar": "Sélectionner une barre" - }, - "Select Custom Theme": { - "Select Custom Theme": "Choisir un thème personnalisé" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Sélectionner le logo du lanceur du dock" - }, - "Select File to Send": { - "Select File to Send": "Sélectionner un fichier à envoyer" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Sélectionner le logo du lanceur" - }, - "Select Profile Image": { - "Select Profile Image": "Sélectionner une image de profil" - }, - "Select Video or Folder": { - "Select Video or Folder": "Sélectionnez Vidéo ou Dossier" - }, - "Select Wallpaper": { - "Select Wallpaper": "Sélectionner un fond d’écran" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Sélectionner le dossier des fonds d’écran" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Sélectionner une couleur dans la palette ou utiliser les curseurs personnalisés" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Sélectionner un widget à ajouter au bureau. Chaque widget est une instance indépendante avec ses propres paramètres." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Sélectionner un widget à ajouter. Vous pouvez ajouter plusieurs instances du même widget si nécessaire." - }, - "Select a window...": { - "Select a window...": "Sélectionner une fenêtre..." - }, - "Select an image file...": { - "Select an image file...": "Sélectionner un fichier image..." - }, - "Select at least one provider": { - "Select at least one provider": "Sélectionner au moins un fournisseur" - }, - "Select device": { - "Select device": "Sélectionner appareil" - }, - "Select device...": { - "Select device...": "Sélectionner un périphérique..." - }, - "Select driver...": { - "Select driver...": "Sélectionner un pilote..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Sélectionner le poids de la police pour le texte de l’interface" - }, - "Select greeter background image": { - "Select greeter background image": "Sélectionnez l'image d'arrière-plan du greeter" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Sélectionner l'écran sur lequel configurer le fond d’écran" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Sélectionner la police monospace pour la liste des processus et les affichages techniques" - }, - "Select network": { - "Select network": "Sélectionner réseau" - }, - "Select system sound theme": { - "Select system sound theme": "Sélectionner le thème sonore du système" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Sélectionner la famille de polices pour le texte de l’interface" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Sélectionner la palette utilisée pour les couleurs basées sur le fond d’écran" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Sélectionner les fournisseurs de raccourcis à inclure" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Sélectionner les transitions à inclure pour l'effet aléatoire" - }, - "Select...": { - "Select...": "Sélectionner..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Fichier image sélectionné introuvable" - }, - "Send": { - "Send": "Envoyer" - }, - "Send Clipboard": { - "Send Clipboard": "Envoyer le presse-papier" - }, - "Send File": { - "Send File": "Envoyer un fichier" - }, - "Send SMS": { - "Send SMS": "Envoyer SMS" - }, - "Sending": { - "Sending": "Envoi" - }, - "Separator": { - "Separator": "Séparateur" - }, - "Server": { - "Server": "Serveur" - }, - "Session Filter": { - "Session Filter": "Filtre de session" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Définir un nom d'appareil personnalisé" - }, - "Set custom name": { - "Set custom name": "Définir un nom personnalisé" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Définir des noms personnalisés pour vos appareils audio d'entrée" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Définir des noms personnalisés pour vos appareils audio de sortie" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Définir des fonds d’écran différents pour chaque écran connecté" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Définir des fonds d’écran différents pour le mode clair et sombre" - }, - "Set key and action to save": { - "Set key and action to save": "Définir la touche et l’action à enregistrer" - }, - "Set notification rules": { - "Set notification rules": "Définir les règles de notification" - }, - "Settings": { - "Settings": "Paramètres" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Les paramètres sont en lecture seule. Les modifications ne seront pas conservées." - }, - "Setup": { - "Setup": "Configuration" - }, - "Shadow Color": { - "Shadow Color": "Couleur de l'ombre" - }, - "Shadow Intensity": { - "Shadow Intensity": "Intensité de l'ombre" - }, - "Shadow Opacity": { - "Shadow Opacity": "Opacité de l'ombre" - }, - "Shadow Override": { - "Shadow Override": "Surcharge de l'ombre" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Élévation de l'ombre sur les barres et les panneaux" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Élévation de l'ombre sur les modales et les dialogues" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "Ombres" - }, - "Share": { - "Share": "Partager" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Partager les réglages de contrôle Gamma" - }, - "Share Text": { - "Share Text": "Partager le texte" - }, - "Share URL": { - "Share URL": "Partager l'URL" - }, - "Shared": { - "Shared": "Partagé" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Maj+Suppr : Tout effacer • Échap : Fermer" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Entrer pour coller" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Entrée: Copier • Shift+Suppr: Tout effacer • Echap: Fermer" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Entrée : Coller • Shift+Suppr : Tout effacer • Échap : Fermer" - }, - "Short": { - "Short": "Court" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Raccourci (%1)" - }, - "Shortcuts": { - "Shortcuts": "Raccourcis" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Raccourcis (%1)" - }, - "Show": { - "Show": "Montrer" - }, - "Show 3rd Party": { - "Show 3rd Party": "Montrer les tiers" - }, - "Show All Tags": { - "Show All Tags": "Afficher toutes les étiquettes" - }, - "Show Badge": { - "Show Badge": "Montrer badge" - }, - "Show CPU": { - "Show CPU": "Afficher le CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Afficher le graphique CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Afficher la température du CPU" - }, - "Show Date": { - "Show Date": "Afficher la date" - }, - "Show Disk": { - "Show Disk": "Afficher le disque" - }, - "Show Dock": { - "Show Dock": "Afficher le dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Afficher la température ressentie" - }, - "Show Footer": { - "Show Footer": "Afficher le pied de page" - }, - "Show Forecast": { - "Show Forecast": "Afficher la prévision" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Afficher la température du GPU" - }, - "Show Header": { - "Show Header": "Afficher l’en-tête" - }, - "Show Hibernate": { - "Show Hibernate": "Afficher hiberner" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Afficher les heures" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Afficher les prévisions horaires" - }, - "Show Humidity": { - "Show Humidity": "Afficher l’humidité" - }, - "Show Launcher Button": { - "Show Launcher Button": "Montrer le bouton du Lanceur" - }, - "Show Line Numbers": { - "Show Line Numbers": "Afficher les numéros de ligne" - }, - "Show Location": { - "Show Location": "Afficher la localisation" - }, - "Show Lock": { - "Show Lock": "Afficher verrouiller" - }, - "Show Log Out": { - "Show Log Out": "Afficher déconnexion" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Afficher les animations d’ondulation Material Design sur les éléments interactifs" - }, - "Show Media Player": { - "Show Media Player": "Montrer lecteur multimédia" - }, - "Show Memory": { - "Show Memory": "Afficher la mémoire" - }, - "Show Memory Graph": { - "Show Memory Graph": "Afficher le graphique de la mémoire" - }, - "Show Memory in GB": { - "Show Memory in GB": "Afficher la mémoire en Go" - }, - "Show Network": { - "Show Network": "Afficher le réseau" - }, - "Show Network Graph": { - "Show Network Graph": "Afficher le graphique du réseau" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Afficher uniquement les espaces occupés" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Afficher le compteur du badge de débordement" - }, - "Show Password Field": { - "Show Password Field": "Afficher le champ de mot de passe" - }, - "Show Power Actions": { - "Show Power Actions": "Afficher les actions d’alimentation" - }, - "Show Power Off": { - "Show Power Off": "Afficher éteindre" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Afficher la probabilité de précipitation" - }, - "Show Pressure": { - "Show Pressure": "Afficher la pression" - }, - "Show Profile Image": { - "Show Profile Image": "Afficher l’image de profil" - }, - "Show Reboot": { - "Show Reboot": "Afficher redémarrer" - }, - "Show Restart DMS": { - "Show Restart DMS": "Afficher redémarrer DMS" - }, - "Show Saved Items": { - "Show Saved Items": "Montrer les éléments sauvegardés" - }, - "Show Seconds": { - "Show Seconds": "Afficher les secondes" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Afficher lever/coucher du soleil" - }, - "Show Suspend": { - "Show Suspend": "Afficher suspendre" - }, - "Show Swap": { - "Show Swap": "Afficher la Swap" - }, - "Show System Date": { - "Show System Date": "Afficher la date système" - }, - "Show System Icons": { - "Show System Icons": "Afficher les icônes système" - }, - "Show System Time": { - "Show System Time": "Afficher l’heure système" - }, - "Show Top Processes": { - "Show Top Processes": "Afficher les processus principaux" - }, - "Show Weather Condition": { - "Show Weather Condition": "Afficher l’état météo" - }, - "Show Week Number": { - "Show Week Number": "Afficher le numéro de la semaine" - }, - "Show Welcome": { - "Show Welcome": "Afficher accueil" - }, - "Show Wind Speed": { - "Show Wind Speed": "Afficher la vitesse du vent" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Afficher les applications de l’espace de travail" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Afficher les 9 étiquettes au lieu de seulement celles occupées (DWL uniquement)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Afficher un contour autour de l’indicateur de l’espace actif" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Afficher le visualiseur audio Cava dans le widget multimédia" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Afficher un arrière-plan sombre derrière les modaux" - }, - "Show device": { - "Show device": "Afficher l'appareil" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Montrer le dock lorsque les fenêtres flottantes ne passent pas devant" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "Afficher en Go" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Afficher la superposition du lanceur lors de la saisie dans l’aperçu Niri. Désactiver pour utiliser un autre lanceur." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Afficher les onglets de mode et les raccourcis clavier en bas." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Afficher sur le dernier écran" - }, - "Show on Overlay": { - "Show on Overlay": "Afficher sur superposition" - }, - "Show on Overview": { - "Show on Overview": "Afficher dans l’aperçu" - }, - "Show on Overview Only": { - "Show on Overview Only": "Afficher uniquement dans l’aperçu" - }, - "Show on all connected displays": { - "Show on all connected displays": "Afficher sur tous les écrans connectés" - }, - "Show on screens:": { - "Show on screens:": "Afficher sur les écrans :" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Afficher à l’écran lors du changement de luminosité" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Afficher à l’écran lors de l’activation/désactivation du verrouillage majuscules" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Afficher à l’écran lors du changement de périphériques audio" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Afficher à l’écran lors du changement de l’état du bloqueur d’inactivité" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Afficher l’OSD lors des changements d’état du lecteur multimédia" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Afficher à l’écran lors du changement de volume du lecteur multimédia" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Afficher à l’écran lorsque le microphone est coupé/rétabli" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Afficher à l’écran lors du changement du profil d’alimentation" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Afficher à l’écran lors du changement du volume" - }, - "Show seconds": { - "Show seconds": "Afficher les secondes" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Afficher les informations météo dans la barre supérieure et le centre de contrôle" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Afficher le numéro de semaine dans le calendrier" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Afficher les numéros des espaces de travail dans le sélecteur de la barre supérieure" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Afficher le nom de l’espace de travail sur les barres horizontales et la première lettre sur les barres verticales" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Afficher les espaces de travail de l'écran actuellement actif" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Afficher toutes les applications en cours avec indication de focus" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Afficher l’espace de travail actuel et permettre de changer" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Indique lorsque la touche majuscule est activée" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Indique lorsque le microphone, la caméra ou le partage d’écran est actif" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Arrêter" - }, - "Signal": { - "Signal": "Signal" - }, - "Signal:": { - "Signal:": "Signal :" - }, - "Size": { - "Size": "Taille" - }, - "Size Constraints": { - "Size Constraints": "Contraintes de taille" - }, - "Size Offset": { - "Size Offset": "Décalage de taille" - }, - "Sizing": { - "Sizing": "Redimensionnement" - }, - "Skip": { - "Skip": "Ignorer" - }, - "Skip confirmation": { - "Skip confirmation": "Passer la confirmation" - }, - "Skip setup": { - "Skip setup": "Ignorer la configuration" - }, - "Small": { - "Small": "Petit" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Authentification par carte à puce" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN de la carte à puce" - }, - "Snap": { - "Snap": "Épingler" - }, - "Snow": { - "Snow": "Neige" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Certains plugins nécessitent une version plus récente de DMS :" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Trier par ordre alphabétique" - }, - "Sort By": { - "Sort By": "Trier par" - }, - "Sorting & Layout": { - "Sorting & Layout": "Tri et disposition" - }, - "Sound Theme": { - "Sound Theme": "Thème sonore" - }, - "Sounds": { - "Sounds": "Sons" - }, - "Space between windows": { - "Space between windows": "Espacement entre fenêtres" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Espacement entre fenêtres (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Espacement entre fenêtres (gaps_in et gaps_out)" - }, - "Spacer": { - "Spacer": "Espacement" - }, - "Spacing": { - "Spacing": "Espacement" - }, - "Speaker settings": { - "Speaker settings": "Paramètres du haut-parleur" - }, - "Speed": { - "Speed": "Vitesse" - }, - "Spool Area Full": { - "Spool Area Full": "File d’impression pleine" - }, - "Square Corners": { - "Square Corners": "Coins carrés" - }, - "Stacked": { - "Stacked": "Empilé" - }, - "Standard": { - "Standard": "Standard" - }, - "Start": { - "Start": "Démarrer" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Démarrer KDE Connect ou Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Démarrer KDE Connect ou Valent pour utiliser ce plugin" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Commencez à taper vos notes ici..." - }, - "State": { - "State": "État" - }, - "Status": { - "Status": "Statut" - }, - "Stopped": { - "Stopped": "Arrêté" - }, - "Stopped Partly": { - "Stopped Partly": "Arrêt partiel" - }, - "Stopping": { - "Stopping": "Arrêt en cours" - }, - "Stretch": { - "Stretch": "Étendre" - }, - "Stripes": { - "Stripes": "Rayures" - }, - "Summary": { - "Summary": "Résumé" - }, - "Sunrise": { - "Sunrise": "Lever du soleil" - }, - "Sunset": { - "Sunset": "Coucher de soleil" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Supprimer les notifications pop-up lorsqu’activé" - }, - "Surface": { - "Surface": "Surface" - }, - "Surface Variant": { - "Surface Variant": "Variante de surface" - }, - "Suspend": { - "Suspend": "Mettre en veille" - }, - "Suspend behavior": { - "Suspend behavior": "Comportement de suspension" - }, - "Suspend system after": { - "Suspend system after": "Suspendre le système après" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Suspendre puis mettre en veille prolongée" - }, - "Sway Website": { - "Sway Website": "Site Sway" - }, - "Switch User": { - "Switch User": "Changer d'utilisateur" - }, - "Switch to power profile": { - "Switch to power profile": "Changer de profil d’énergie" - }, - "Sync": { - "Sync": "Synchro" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Synchroniser le mode avec les portails" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Synchroniser popouts et modales" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Synchroniser la position entre les écrans" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Synchro complétée avec succès." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Synchroniser le mode sombre avec les préférences système pour l’ensemble du thème" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "Synchro échouée en arrière-plan. Essayez avec le terminal pour vous authentifier de façon interactive." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "La Synchro nécessite une authentification sudo. Ouverture du terminal pour utiliser le mot de passe ou l'empreinte." - }, - "System": { - "System": "Système" - }, - "System App Theming": { - "System App Theming": "Habillage des applications système" - }, - "System Check": { - "System Check": "Vérification du système" - }, - "System Default": { - "System Default": "Paramètres par défaut" - }, - "System Information": { - "System Information": "Information système" - }, - "System Monitor": { - "System Monitor": "Moniteur système" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Moniteur système indisponible" - }, - "System Sounds": { - "System Sounds": "Sons système" - }, - "System Tray": { - "System Tray": "Zone de notification" - }, - "System Update": { - "System Update": "Mise à jour du système" - }, - "System Updater": { - "System Updater": "Outil de mise à jour" - }, - "System Updates": { - "System Updates": "Mises à jour système" - }, - "System notification area icons": { - "System notification area icons": "Icônes de la zone de notification système" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Les sons système ne sont pas disponibles. Installez %1 pour activer le support audio." - }, - "System theme toggle": { - "System theme toggle": "Thème système" - }, - "System toast notifications": { - "System toast notifications": "Notifications toast système" - }, - "System update custom command": { - "System update custom command": "Commande personnalisée de mise à jour" - }, - "Tab": { - "Tab": "Onglet" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab : Navigation • ←→↑↓ : Navigation grille • Enter/Espace : Sélectionner" - }, - "Terminal": { - "Terminal": "Terminal" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Paramètres supplémentaires pour le terminal" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Forcer le mode sombre dans les terminaux" - }, - "Test Connection": { - "Test Connection": "Tester la connexion" - }, - "Test Page": { - "Test Page": "Page de test" - }, - "Test page sent to printer": { - "Test page sent to printer": "Page de test envoyée à l’imprimante" - }, - "Testing...": { - "Testing...": "Test..." - }, - "Text": { - "Text": "Texte" - }, - "Text Color": { - "Text Color": "Couleur du texte" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "L'outil 'dgop' est requis pour la surveillance du système.\nVeuillez installer dgop pour utiliser cette fonctionnalité." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "La variable d’environnement DMS_SOCKET n’est pas définie ou le socket est indisponible. La gestion automatique des plugins nécessite DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Les réglages ci-dessous modifieront vos paramètres GTK et Qt. Pour conserver vos configurations actuelles, effectuez une sauvegarde (qt5ct.conf|qt6ct.conf et ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "La file d’attente d’impression est vide" - }, - "Theme & Colors": { - "Theme & Colors": "Thème et couleurs" - }, - "Theme Color": { - "Theme Color": "Couleur du thème" - }, - "Theme Registry": { - "Theme Registry": "Registre de thèmes" - }, - "Themes": { - "Themes": "Thèmes" - }, - "Thickness": { - "Thickness": "Épaisseur" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Avertissement sur plugin tiers" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Les plugins tiers sont créés par la communauté et ne sont pas officiellement pris en charge par DankMaterialShell.\n\nCes plugins peuvent présenter des risques pour la sécurité et la vie privée – installez-les à vos propres risques." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Ce raccourci est remplacé par config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Cela peut prendre quelques secondes" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Ce plugin n’a pas la permission 'settings_write'.\n\nAjoutez \"permissions\": [\"settings_read\", \"settings_write\"] dans le fichier plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Ce widget empêche la mise hors tension de la GPU, ce qui peut affecter considérablement l’autonomie des portables. Son utilisation n’est pas recommandée sur les portables à GPU hybride." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Cela supprimera toutes les entrées non épinglées. %1 entrées épinglées seront conservées." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Cela supprimera définitivement tout l’historique du presse-papiers." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Cela supprimera définitivement cet élément du presse-papier. Cela ne peut pas être annulé." - }, - "Thunderstorm": { - "Thunderstorm": "Orage" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Orage avec grêle" - }, - "Tile": { - "Tile": "Tuile" - }, - "Tile H": { - "Tile H": "Tuile H" - }, - "Tile V": { - "Tile V": "Tuile V" - }, - "Tiled": { - "Tiled": "Ajusté" - }, - "Tiled State": { - "Tiled State": "Etat ajusté" - }, - "Tiling": { - "Tiling": "Mosaïque" - }, - "Time": { - "Time": "Heure" - }, - "Time & Date Locale": { - "Time & Date Locale": "Format régional de la date et de l'heure" - }, - "Time & Weather": { - "Time & Weather": "Heure et météo" - }, - "Time Format": { - "Time Format": "Format de l’heure" - }, - "Time format": { - "Time format": "Format de l'heure" - }, - "Time remaining: %1": { - "Time remaining: %1": "Temps restant : %1" - }, - "Time until full: %1": { - "Time until full: %1": "Temps avant remplissage : %1" - }, - "Timed Out": { - "Timed Out": "Temps écoulé" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Durée d’affichage des notifications critiques" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Durée d’affichage des notifications basse priorité" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Durée d’affichage des notifications priorité normale" - }, - "Title": { - "Title": "Titre" - }, - "Title regex (optional)": { - "Title regex (optional)": "Regex du titre (optionnelle)" - }, - "To Full": { - "To Full": "Chargé" - }, - "To update, run the following command:": { - "To update, run the following command:": "Pour mettre à jour, exécutez la commande suivante :" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Pour utiliser ce raccourci DMS, supprimez ou modifiez le keybind dans votre config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Messages toast" - }, - "Today": { - "Today": "Aujourd'hui" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Basculer la visibilité de cette configuration de barre" - }, - "Toggling...": { - "Toggling...": "Basculage..." - }, - "Tomorrow": { - "Tomorrow": "Demain" - }, - "Tonal Spot": { - "Tonal Spot": "Point tonal" - }, - "Toner Empty": { - "Toner Empty": "Toner vide" - }, - "Toner Low": { - "Toner Low": "Toner faible" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "Trop de tentatives échouées - le compte peut être verrouillé" - }, - "Tools": { - "Tools": "Outils" - }, - "Top": { - "Top": "Haut" - }, - "Top (Default)": { - "Top (Default)": "Haut (par défaut)" - }, - "Top Bar Format": { - "Top Bar Format": "Format de la barre supérieure" - }, - "Top Center": { - "Top Center": "Au centre en haut" - }, - "Top Left": { - "Top Left": "Haut gauche" - }, - "Top Processes": { - "Top Processes": "Processus principaux" - }, - "Top Right": { - "Top Right": "Haut droite" - }, - "Top Section": { - "Top Section": "Section supérieure" - }, - "Total": { - "Total": "Total" - }, - "Total Jobs": { - "Total Jobs": "Total des tâches" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Transformer" - }, - "Transition Effect": { - "Transition Effect": "Effet de transition" - }, - "Transparency": { - "Transparency": "Transparence" - }, - "Trending GIFs": { - "Trending GIFs": "GIFs populaires" - }, - "Trending Stickers": { - "Trending Stickers": "Stickers populaires" - }, - "Trigger": { - "Trigger": "Déclencheur" - }, - "Trigger Prefix": { - "Trigger Prefix": "Préfixe du déclencheur" - }, - "Trigger: %1": { - "Trigger: %1": "Déclencheur : %1" - }, - "Trust": { - "Trust": "Approuver" - }, - "Try a different search": { - "Try a different search": "Essayez une recherche différente" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Éteindre les écrans immédiatement lorsque le verrouillage d'écran s'active" - }, - "Turn off monitors after": { - "Turn off monitors after": "Éteindre les écrans après" - }, - "Type": { - "Type": "Type" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Tapez au moins 2 caractères" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Tapez ce préfixe pour rechercher des raccourcis" - }, - "Type to search files": { - "Type to search files": "Taper pour chercher des fichiers" - }, - "Typography": { - "Typography": "Typographie" - }, - "Typography & Motion": { - "Typography & Motion": "Typographie et animation" - }, - "Unavailable": { - "Unavailable": "Indisponible" - }, - "Unfocused Color": { - "Unfocused Color": "Couleur non focalisée" - }, - "Ungrouped": { - "Ungrouped": "Non groupé" - }, - "Uninstall": { - "Uninstall": "Désinstaller" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Désinstaller le Greeter" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Désinstaller le plugin" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Désinstallation terminée. Le Greeter a été supprimé." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Échec de la désinstallation : %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "Désinstaller le greeter DMS ? Cela supprimera la configuration et restorera votre ancien gestionnaire d'affichage. Un terminal va s'ouvrir pour l'authentification sudo." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Désinstallé : %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Désinstallation : %1" - }, - "Unknown": { - "Unknown": "Inconnu" - }, - "Unknown App": { - "Unknown App": "Appli inconnue" - }, - "Unknown Artist": { - "Unknown Artist": "Artiste inconnu" - }, - "Unknown Config": { - "Unknown Config": "Configuration inconnue" - }, - "Unknown Device": { - "Unknown Device": "Périphérique inconnu" - }, - "Unknown GPU": { - "Unknown GPU": "GPU inconnu" - }, - "Unknown Monitor": { - "Unknown Monitor": "Moniteur inconnu" - }, - "Unknown Network": { - "Unknown Network": "Réseau inconnu" - }, - "Unknown Title": { - "Unknown Title": "Titre inconnu" - }, - "Unknown Track": { - "Unknown Track": "Piste inconnue" - }, - "Unload on Close": { - "Unload on Close": "Libérer à la fermeture" - }, - "Unmute": { - "Unmute": "Désactiver sourdine" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Désactiver sourdine pour %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Règle non nommée" - }, - "Unpair": { - "Unpair": "Déconnexion" - }, - "Unpair failed": { - "Unpair failed": "Échec de la déconnexion" - }, - "Unpin": { - "Unpin": "Détacher" - }, - "Unpin from Dock": { - "Unpin from Dock": "Détacher du dock" - }, - "Unsaved Changes": { - "Unsaved Changes": "Modifications non enregistrées" - }, - "Unsaved changes": { - "Unsaved changes": "Modifications non enregistrées" - }, - "Unsaved note...": { - "Unsaved note...": "Note non enregistrée..." - }, - "Untitled": { - "Untitled": "Sans titre" - }, - "Untrust": { - "Untrust": "Révoquer" - }, - "Up to date": { - "Up to date": "À jour" - }, - "Update": { - "Update": "Mettre à jour" - }, - "Update All": { - "Update All": "Tout mettre à jour" - }, - "Update Plugin": { - "Update Plugin": "Mettre à jour le plugin" - }, - "Uptime": { - "Uptime": "Durée d'activité" - }, - "Uptime:": { - "Uptime:": "Durée d'activité :" - }, - "Urgent Color": { - "Urgent Color": "Couleur urgente" - }, - "Usage Tips": { - "Usage Tips": "Conseils d’utilisation" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Utilisez le format horaire 24 heures au lieu du format 12 heures AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Utiliser une commande personnalisée" - }, - "Use Grid Layout": { - "Use Grid Layout": "Utiliser une disposition en grille" - }, - "Use IP Location": { - "Use IP Location": "Utiliser la localisation IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Utiliser les unités impériales" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Utilisez les unités impériales (°F, mph, inHg) au lieu des unités métriques (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Utiliser la police Monospace" - }, - "Use System Theme": { - "Use System Theme": "Utiliser le thème système" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Utilisez une image personnalisée pour l'écran de connexion, ou laissez vide pour utiliser pour fond d'écran de bureau." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Utiliser une direction d'ombre fixe pour cette barre" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Utilisez une clé de sécurité pour l'authentification de l'écran de verrouillage." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Utiliser un gestionnaire de fonds d’écran externe comme swww, hyprpaper ou swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Utiliser des barres de progression animées en forme de vague pour la lecture multimédia" - }, - "Use custom border size": { - "Use custom border size": "Utiliser une taille de bordure personnalisée" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Utiliser une largeur de bordure/anneau de focus personnalisée" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Utiliser une commande personnalisée pour mettre à jour le système" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Utiliser des espaces personnalisés au lieu de l’espacement de la barre" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Utiliser un rayon de fenêtre personnalisé au lieu du rayon du thème" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Utiliser un arrondi de fenêtre personnalisé au lieu du rayon du thème" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Utiliser le fond d'écran du bureau" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Utilisez l'authentification par empreinte pour l'écran de verrouillage." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Utiliser le thème clair au lieu du thème sombre" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Utiliser les m/s au lieu des km/h pour la vitesse du vent" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Utiliser des cartes de notification plus petites" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Utiliser le thème sonore des paramètres système" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Utiliser la même position et taille sur tous les écrans" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Utiliser le préfixe de déclenchement pour activer" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Utilisé lorsque la couleur d’accent est personnalisée" - }, - "User": { - "User": "Utilisateur" - }, - "Username": { - "Username": "Nom d’utilisateur" - }, - "Username...": { - "Username...": "Nom d'utilisateur..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Utiliser l'heure du lever/coucher du soleil basée sur votre localisation." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Utilise les heures de lever et coucher du soleil pour ajuster automatiquement le mode nuit selon votre localisation." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Utiliser les réglages partagés de contrôle Gamma" - }, - "Utilities": { - "Utilities": "Utilitaires" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "Connexions VPN" - }, - "VPN Password": { - "VPN Password": "Mot de passe VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "Configuration VPN mise à jour" - }, - "VPN connections": { - "VPN connections": "Connexions VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN supprimée" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importée : %1" - }, - "VPN not available": { - "VPN not available": "VPN non disponible" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "État VPN et connexion rapide" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR en plein écran seulement" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR à la demande" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Fréquence de rafraîchissement variable" - }, - "Verification": { - "Verification": "Vérification" - }, - "Version": { - "Version": "Version" - }, - "Vertical Deck": { - "Vertical Deck": "Pile verticale" - }, - "Vertical Grid": { - "Vertical Grid": "Grille verticale" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Défilement vertical" - }, - "Vertical Tiling": { - "Vertical Tiling": "Tuilage vertical" - }, - "Vibrant": { - "Vibrant": "Vif" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Palette vibrante avec saturation ludique." - }, - "Video Path": { - "Video Path": "Chemin Vidéo" - }, - "Video Screensaver": { - "Video Screensaver": "Économiseur d'écran vidéo" - }, - "Videos": { - "Videos": "Vidéos" - }, - "View Mode": { - "View Mode": "Mode d’affichage" - }, - "Visibility": { - "Visibility": "Visibilité" - }, - "Visual Effects": { - "Visual Effects": "Effets visuels" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Séparateur visuel entre widgets" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Effet visuel utilisé lors du changement de fond d’écran" - }, - "Volume": { - "Volume": "Volume" - }, - "Volume Changed": { - "Volume Changed": "Volume modifié" - }, - "Volume Slider": { - "Volume Slider": "Curseur de volume" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volume, luminosité et autres affichages système" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Fond d'écran" - }, - "Wallpaper Error": { - "Wallpaper Error": "Erreur de fond d’écran" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Moniteur de fond d’écran" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Mode de remplissage du fond d'écran" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Échec du traitement du fond d’écran" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Échec du traitement du fond d’écran – vérifiez le chemin du fichier" - }, - "Wallpapers": { - "Wallpapers": "Fonds d'écran" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Température de couleur chaude à appliquer" - }, - "Warning": { - "Warning": "Avertissement" - }, - "Warnings": { - "Warnings": "Avertissements" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Barres de progression en forme d’onde" - }, - "Weather": { - "Weather": "Météo" - }, - "Weather Widget": { - "Weather Widget": "Widget météo" - }, - "Welcome": { - "Welcome": "Bienvenue" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Bienvenue sur DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Si activé, les applications sont triées par ordre alphabétique. Sinon, elles sont triées selon la fréquence d’utilisation." - }, - "When locked": { - "When locked": "Une fois verrouillé" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Lorsque ce widget est utilisé, le masquer s'il n'y a aucune mise à jour" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Mot de passe Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Connexion Wi-Fi et Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi non disponible" - }, - "WiFi": { - "WiFi": "Wi-Fi" - }, - "WiFi Device": { - "WiFi Device": "Appareil Wi-Fi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Code QR Wi-Fi pour " - }, - "WiFi disabled": { - "WiFi disabled": "Wi-Fi désactivé" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi activé" - }, - "WiFi is off": { - "WiFi is off": "Wi-Fi éteint" - }, - "WiFi off": { - "WiFi off": "Wi-Fi off" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Large (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Couleur de fond du widget" - }, - "Widget Management": { - "Widget Management": "Gestion des widgets" - }, - "Widget Outline": { - "Widget Outline": "Contour du widget" - }, - "Widget Style": { - "Widget Style": "Style du widget" - }, - "Widget Styling": { - "Widget Styling": "Stylisation du widget" - }, - "Widget Transparency": { - "Widget Transparency": "Transparence du widget" - }, - "Widget added": { - "Widget added": "Widget ajouté" - }, - "Widget removed": { - "Widget removed": "Widget supprimé" - }, - "Widgets": { - "Widgets": "Widgets" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgets, disposition, style" - }, - "Width": { - "Width": "Longueur" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Largeur de la bordure de la fenêtre (px)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Largeur de la bordure de la fenêtre (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Largeur de la bordure et de l’anneau de focus" - }, - "Wind": { - "Wind": "Vent" - }, - "Wind Speed": { - "Wind Speed": "Vitesse du vent " - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Vitesse du vent en m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Rayon des coins de la fenêtre" - }, - "Window Gaps": { - "Window Gaps": "Espacement des fenêtres" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Espacement des fenêtres (px)" - }, - "Window Height": { - "Window Height": "Hauteur de fenêtre" - }, - "Window Opening": { - "Window Opening": "Ouverture de fenêtre" - }, - "Window Rounding": { - "Window Rounding": "Arrondi des fenêtres" - }, - "Window Rules": { - "Window Rules": "Règles de fenêtre" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Inclusion des règles de fenêtre manquante" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Règles de fenêtres non configurées" - }, - "Wipe": { - "Wipe": "Effacer" - }, - "Workspace": { - "Workspace": "Espace de travail" - }, - "Workspace Appearance": { - "Workspace Appearance": "Apparence de l’espace de travail" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Numéros des espaces de travail" - }, - "Workspace Names": { - "Workspace Names": "Noms des espaces de travail" - }, - "Workspace Padding": { - "Workspace Padding": "Marge des espaces de travail" - }, - "Workspace Settings": { - "Workspace Settings": "Paramètres des espaces de travail" - }, - "Workspace Switcher": { - "Workspace Switcher": "Sélecteur d’espaces de travail" - }, - "Workspace name": { - "Workspace name": "Nom de l'espace de travail" - }, - "Workspaces": { - "Workspaces": "Espaces de travail" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Espaces de travail et widgets" - }, - "Write:": { - "Write:": "Écrire :" - }, - "X Axis": { - "X Axis": "Axe X" - }, - "Y Axis": { - "Y Axis": "Axe Y" - }, - "Yes": { - "Yes": "Oui" - }, - "Yesterday": { - "Yesterday": "Hier" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Vous avez des modifications non enregistrées. Enregistrer avant de fermer cet onglet ?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Vous avez des modifications non enregistrées. Enregistrer avant de continuer ?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Vous avez des modifications non enregistrées. Enregistrer avant de créer un nouveau fichier ?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Vous avez des modifications non enregistrées. Enregistrer avant d’ouvrir un fichier ?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Vous devez définir soit :\nQT_QPA_PLATFORMTHEME=gtk3 OU\nQT_QPA_PLATFORMTHEME=qt6ct\ncomme variables d'environnement, puis redémarrer le shell.\n\nqt6ct nécessite que qt6ct-kde soit installé." - }, - "You're All Set!": { - "You're All Set!": "Tout est prêt !" - }, - "Your system is up to date!": { - "Your system is up to date!": "Votre système est à jour !" - }, - "actions": { - "actions": "actions" - }, - "attached": { - "attached": "attaché" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "par %1" - }, - "days": { - "days": "jours" - }, - "detached": { - "detached": "détaché" - }, - "device": { - "device": "appareil" - }, - "devices connected": { - "devices connected": "appareils connectés" - }, - "dgop not available": { - "dgop not available": "dgop non disponible" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "La configuration dms/cursor existe mais n’est pas incluse. Les paramètres du curseur ne seront pas appliqués." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "La configuration dms/outputs existe mais n’est pas incluse dans votre configuration du compositeur. Les changements d’affichage ne persisteront pas." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "i.e., firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "i.e., focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "ex. notify-send 'Bonjour' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "événements" - }, - "ext": { - "ext": "ext" - }, - "featured": { - "featured": "À la une" - }, - "leave empty for default": { - "leave empty for default": "laisser vide pour la valeur par défaut" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl non disponible - l'intégration de verrouillage nécessite une connexion au socket DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "Serveur Discord mangowc" - }, - "mangowc GitHub": { - "mangowc GitHub": "Github mangowc" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen introuvable – installez le paquet matugen pour le thème dynamique" - }, - "minutes": { - "minutes": "minutes" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "nav" - }, - "niri GitHub": { - "niri GitHub": "Github niri" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "Chat Matrix niri" - }, - "niri shortcuts config": { - "niri shortcuts config": "Configuration des raccourcis niri" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "maintenant" - }, - "official": { - "official": "officiel" - }, - "on Hyprland": { - "on Hyprland": "sur Hyprland" - }, - "on MangoWC": { - "on MangoWC": "sur MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "sur Miracle WM" - }, - "on Niri": { - "on Niri": "sur Niri" - }, - "on Scroll": { - "on Scroll": "sur Scroll" - }, - "on Sway": { - "on Sway": "sur Sway" - }, - "open": { - "open": "ouvrir" - }, - "or run ": { - "or run ": "ou lancer " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon non disponible" - }, - "procs": { - "procs": "procs" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri Subreddit" - }, - "seconds": { - "seconds": "secondes" - }, - "source": { - "source": "code source" - }, - "this app": { - "this app": "cette appli" - }, - "up": { - "up": "allumé" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "Mettre à jour DMS pour l'intégration NM." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 par %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype non disponible - installez wtype pour le support du collage" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Installez seulement à partir de source fiables" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Mois (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• M - Mois (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• M - Mois (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• M - Mois (Janvier)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Les plugins peuvent contenir des bugs ou avoir des problèmes de sécurité" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Vérifiez le code avant installation si possible" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Jour (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Jour (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Nom du jour (Mon)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Nom du jour (Monday)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Année (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Année (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Nav • Espace: Étendre • Entrée: Action/Étendre • E: Texte" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓ : Naviguer • Entrée/Ctrl+C : Copier • Suppr : Supprimer • F10 : Aide" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Naviguer • Entrée: Coller • Suppr: Supprimer • F10: Aide" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/he.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/he.json deleted file mode 100644 index 9b572db..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/he.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "מהירות האנימציה ב%1" - }, - "%1 Sessions": { - "%1 Sessions": "%1 הפעלות" - }, - "%1 active session": { - "%1 active session": "%1 הפעלה פעילה" - }, - "%1 active sessions": { - "%1 active sessions": "%1 הפעלות פעילות" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "מתאם %1, אין מתאמים מחוברים" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 מתאמים, אין מתאמים מחוברים" - }, - "%1 character": { - "%1 character": "%1 תו" - }, - "%1 characters": { - "%1 characters": "%1 תווים" - }, - "%1 connected": { - "%1 connected": "%1 מחובר/ים" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "משך אנימציה מותאם אישית %1" - }, - "%1 disconnected": { - "%1 disconnected": "%1 מנותק" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 מנותק (מוסתר)" - }, - "%1 display": { - "%1 display": "מסך %1" - }, - "%1 displays": { - "%1 displays": "%1 מסכים" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 קיים אך אינו כלול בconfig. קיצורי מקלדת מותאמים אישית לא יעבדו עד שהבעיה תתוקן." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 קיים אך אינו כלול. חוקי החלון לא יתקיימו." - }, - "%1 filtered": { - "%1 filtered": "%1 מסוננים" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 כעת כלול בconfig" - }, - "%1 issue found": { - "%1 issue found": "נמצאה בעיה %1" - }, - "%1 issues found": { - "%1 issues found": "נמצאו %1 בעיות" - }, - "%1 notifications": { - "%1 notifications": "%1 התראות" - }, - "%1 update": { - "%1 update": "%1 עדכון" - }, - "%1 updates": { - "%1 updates": "%1 עדכונים" - }, - "%1 variants": { - "%1 variants": "%1 גרסאות" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 תמונת רקע • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 תמונות רקע • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 ווידג׳טים" - }, - "%1 window": { - "%1 window": "%1 חלון" - }, - "%1 windows": { - "%1 windows": "%1 חלונות" - }, - "%1m ago": { - "%1m ago": "לפני %1 דקות" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "'חלופי' מאפשר למפתח לפתוח את הנעילה בעצמו. 'גורם שני' דורש קודם סיסמה או טביעת אצבע, ואז את המפתח." - }, - "(Default)": { - "(Default)": "(ברירת מחדל)" - }, - "(Unnamed)": { - "(Unnamed)": "(ללא שם)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 נוספים" - }, - "/path/to/videos": { - "/path/to/videos": "/path/to/videos" - }, - "0 = square corners": { - "0 = square corners": "0 = פינות מרובעות" - }, - "1 day": { - "1 day": "יום אחד" - }, - "1 device connected": { - "1 device connected": "התקן אחד מחובר" - }, - "1 event": { - "1 event": "אירוע אחד" - }, - "1 hour": { - "1 hour": "שעה אחת" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "שעה וחצי (ו30 דקות)" - }, - "1 minute": { - "1 minute": "דקה אחת" - }, - "1 notification": { - "1 notification": "התראה אחת" - }, - "1 second": { - "1 second": "שנייה אחת" - }, - "10 minutes": { - "10 minutes": "10 דקות" - }, - "10 seconds": { - "10 seconds": "10 שניות" - }, - "10-bit Color": { - "10-bit Color": "צבע 10 סיביות" - }, - "12 hours": { - "12 hours": "12 שעות" - }, - "14 days": { - "14 days": "14 ימים" - }, - "15 minutes": { - "15 minutes": "15 דקות" - }, - "15 seconds": { - "15 seconds": "15 שניות" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 שעות" - }, - "2 minutes": { - "2 minutes": "2 דקות" - }, - "2 seconds": { - "2 seconds": "2 שניות" - }, - "20 minutes": { - "20 minutes": "20 דקות" - }, - "20 seconds": { - "20 seconds": "20 שניות" - }, - "24-Hour Format": { - "24-Hour Format": "תבנית 24 שעות" - }, - "24-hour clock": { - "24-hour clock": "שעון 24 שעות" - }, - "24-hour format": { - "24-hour format": "תבנית 24 שעות" - }, - "25 seconds": { - "25 seconds": "25 שניות" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 ימים" - }, - "3 hours": { - "3 hours": "3 שעות" - }, - "3 minutes": { - "3 minutes": "3 דקות" - }, - "3 seconds": { - "3 seconds": "3 שניות" - }, - "30 days": { - "30 days": "30 ימים" - }, - "30 minutes": { - "30 minutes": "30 דקות" - }, - "30 seconds": { - "30 seconds": "30 שניות" - }, - "35 seconds": { - "35 seconds": "35 שניות" - }, - "3rd party": { - "3rd party": "צד שלישי" - }, - "4 hours": { - "4 hours": "4 שעות" - }, - "4 seconds": { - "4 seconds": "4 שניות" - }, - "40 seconds": { - "40 seconds": "40 שניות" - }, - "45 seconds": { - "45 seconds": "45 שניות" - }, - "5 minutes": { - "5 minutes": "5 דקות" - }, - "5 seconds": { - "5 seconds": "5 שניות" - }, - "50 seconds": { - "50 seconds": "50 שניות" - }, - "500 ms": { - "500 ms": "500 מילישניות" - }, - "55 seconds": { - "55 seconds": "55 שניות" - }, - "6 hours": { - "6 hours": "6 שעות" - }, - "7 days": { - "7 days": "7 ימים" - }, - "750 ms": { - "750 ms": "750 מילישניות" - }, - "8 hours": { - "8 hours": "8 שעות" - }, - "8 seconds": { - "8 seconds": "8 שניות" - }, - "90 days": { - "90 days": "90 ימים" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "רישיון MIT" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "קיים כבר קובץ עם השם זה. האם ברצונך לדרוס אותו?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "מעטפת שולחן עבודה מודרנית לקומפוזיטורים של Wayland" - }, - "AC Power": { - "AC Power": "חשמל AC" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "בוטל" - }, - "About": { - "About": "אודות" - }, - "Accent Color": { - "Accent Color": "צבע הדגשה" - }, - "Accept": { - "Accept": "אישור" - }, - "Accept Jobs": { - "Accept Jobs": "קבל/י עבודות" - }, - "Accepting": { - "Accepting": "מקבלת עבודות" - }, - "Access clipboard history": { - "Access clipboard history": "גישה להיסטוריית לוח ההעתקה" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "גישה להתראות ומצב ״נא לא להפריע״" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "גישה לבקרי המערכת והגדרות" - }, - "Action": { - "Action": "פעולה" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "הפעולה נכשלה או שהמסוף נסגר." - }, - "Actions": { - "Actions": "פעולות" - }, - "Activate": { - "Activate": "הפעל/י" - }, - "Activate Greeter": { - "Activate Greeter": "הפעל/י את מסך ההתחברות" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "האם להפעיל את מסך ההתחברות של DMS? מסוף ייפתח לאימות עם sudo. הרץ/י את הסנכרון לאחר ההפעלה כדי להחיל את ההגדרות שלך." - }, - "Activation": { - "Activation": "הפעלה" - }, - "Active": { - "Active": "פעיל" - }, - "Active Color": { - "Active Color": "צבע פעיל" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "המסך הפעיל שבו מוצג מסך הנעילה" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "צבע רקע וסמל של האריח הפעיל" - }, - "Active: %1": { - "Active: %1": "פעיל: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "פעיל: %1 +%2" - }, - "Active: None": { - "Active: None": "פעיל: אין" - }, - "Adapters": { - "Adapters": "מתאמים" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "הוספה" - }, - "Add Bar": { - "Add Bar": "הוסף/י סרגל" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "הוספת ווידג׳ט לשולחן העבודה" - }, - "Add Printer": { - "Add Printer": "הוספת מדפסת" - }, - "Add Title": { - "Add Title": "הוסף/י כותרת" - }, - "Add Widget": { - "Add Widget": "הוספת ווידג׳ט" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "הוספת ווידג׳ט למקטע %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "הוסף/י מסגרת מסביב לDock" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "הוסף/י קידומת מותאמת אישית לכל הפעלות האפליקציות. ניתן להשתמש בזה עבור דברים כמו 'uwsm-app', 'systemd-run', או עוטפי פקודות אחרים." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "הוסף/י והגדר/י ווידג׳טים שמופיעים על שולחן העבודה שלך" - }, - "Add by Address": { - "Add by Address": "הוספה לפי כתובת" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "התאם/י את מספר העמודות במצב תצוגת רשת." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "התאמת עוצמה לכל הזחת גלילה" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "כוונן/י את הניגודיות של הצבעים שנוצרו (100- = מינימום, 0 = סטנדרטי, 100 = מקסימום)" - }, - "Advanced": { - "Advanced": "מתקדם" - }, - "Afternoon": { - "Afternoon": "אחר הצהריים" - }, - "All": { - "All": "הכל" - }, - "All Monitors": { - "All Monitors": "כל המסכים" - }, - "All checks passed": { - "All checks passed": "כל הבדיקות עברו בהצלחה" - }, - "All day": { - "All day": "כל היום" - }, - "All displays": { - "All displays": "כל המסכים" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "אפשר/י ללחיצות לעבור מבעד לווידג׳ט" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: חזרה • F1/I: מידע על הקובץ • F10: עזרה • Esc: סגירה" - }, - "Alternative (OR)": { - "Alternative (OR)": "חלופי (OR)" - }, - "Always Active": { - "Always Active": "פעיל תמיד" - }, - "Always Show Percentage": { - "Always Show Percentage": "הצגה תמידית של אחוזים" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "הסתר/י תמיד את הDock והצג/י אותו בעת ריחוף ליד האזור שלו" - }, - "Always on icons": { - "Always on icons": "סמלים דולקים תמיד" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "הצג/י תמיד לפחות 3 סביבות עבודה, גם אם קיימות פחות סביבות פעילות" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "הצג/י תמיד את הDock כאשר הסקירה של Niri פתוחה" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "הצג/י תמיד כשיש רק מסך אחד מחובר" - }, - "Amount": { - "Amount": "כמות" - }, - "Analog": { - "Analog": "אנלוגי" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "שעון אנלוגי, דיגיטלי או בערימה" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "מנתח תצורה..." - }, - "Animation Duration": { - "Animation Duration": "משך זמן לאנימציה" - }, - "Animation Speed": { - "Animation Speed": "מהירות האנימציה" - }, - "Anonymous Identity": { - "Anonymous Identity": "זהות אנונימית" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "זהות אנונימית (אופציונלי)" - }, - "App Customizations": { - "App Customizations": "התאמות אישיות לאפליקציות" - }, - "App ID Substitutions": { - "App ID Substitutions": "החלפת ID לאפליקציות" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "App ID regex (לדוגמה ^firefox$)" - }, - "App Launcher": { - "App Launcher": "משגר אפליקציות" - }, - "App Names": { - "App Names": "שמות האפליקציות" - }, - "App Theming": { - "App Theming": "עיצוב לאפליקציות" - }, - "Appearance": { - "Appearance": "מראה" - }, - "Application Dock": { - "Application Dock": "Dock אפליקציות" - }, - "Applications": { - "Applications": "אפליקציות" - }, - "Apply Changes": { - "Apply Changes": "החל/י שינויים" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "החלת צבעים על GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "החלת צבעים על Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "הגדרת טמפרטורת צבע חמה כדי להפחית מאמץ בעיניים. השתמש/י בהגדרות האוטומציה למטה כדי לשלוט מתי ההגדרה מופעלת." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "מחיל שינויי אימות…" - }, - "Apps": { - "Apps": "אפליקציות" - }, - "Apps Dock": { - "Apps Dock": "אפליקציות Dock" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "הגדרות לאפליקציות Dock" - }, - "Apps Icon": { - "Apps Icon": "סמל האפליקציות" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "האפליקציות ממוינות לפי תדירות השימוש, אחר כך לפי שימוש אחרון ולבסוף לפי סדר אלפביתי." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "אפליקציות עם שם תצוגה, סמל או אפשרויות הפעלה מותאמות אישית. לחץ/י לחיצה ימנית על אפליקציה ובחר/י את 'עריכת אפליקציה' להתאמה אישית." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "אפליקציות עם חלונות קופצים של התראות מושתקות. בטל/י השתקה או מחק/י להסרה." - }, - "Architecture": { - "Architecture": "ארכיטקטורה" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "האם אתה/את בטוח/ה שברצונך לסיים את ההפעלה \"%1\"?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "סדר/י מסכים והגדר/י רזולוציה, קצב רענון וVRR" - }, - "Attach": { - "Attach": "חבר/י" - }, - "Audio": { - "Audio": "שמע" - }, - "Audio Codec": { - "Audio Codec": "קודק אודיו" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "בחירת קודק אודיו" - }, - "Audio Devices": { - "Audio Devices": "התקני שמע" - }, - "Audio Input": { - "Audio Input": "קלט לשמע" - }, - "Audio Output": { - "Audio Output": "פלט לשמע" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "התקני פלט לשמע (" - }, - "Audio Output Switch": { - "Audio Output Switch": "שינויים בפלט השמע" - }, - "Audio Visualizer": { - "Audio Visualizer": "מחולל חזותי לשמע" - }, - "Audio system restarted": { - "Audio system restarted": "מערכת השמע הופעלה מחדש" - }, - "Audio volume control": { - "Audio volume control": "בקרת עוצמת שמע" - }, - "Auth": { - "Auth": "אימות" - }, - "Auth Type": { - "Auth Type": "סוג אימות" - }, - "Authenticate": { - "Authenticate": "אימות" - }, - "Authenticating...": { - "Authenticating...": "מאמת..." - }, - "Authentication": { - "Authentication": "אימות" - }, - "Authentication Required": { - "Authentication Required": "נדרש אימות" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "שינויי האימות הוחלו." - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "שינויי אימות מוחלים באופן אוטומטי." - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "שינויי אימות מוחלים באופן אוטומטי. התחברות באמצעות טביעת אצבע בלבד עשויה שלא לפתוח את צרור המפתחות." - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "שינויי אימות דורשים להזדהות עם sudo. נפתח מסוף כדי שתוכל/י להשתמש בסיסמה או בטביעת אצבע." - }, - "Authentication error - try again": { - "Authentication error - try again": "שגיאת אימות - נסה/י שנית" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "האימות נכשל, נא לנסות שוב" - }, - "Authorize": { - "Authorize": "אשר/י" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "אשר/י צימוד עם " - }, - "Authorize service for ": { - "Authorize service for ": "אשר/י שירות עבור " - }, - "Auto": { - "Auto": "אוטומטי" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "אוטומטי (מודע לסרגל)" - }, - "Auto (Wide)": { - "Auto (Wide)": "אוטומטי (רחב)" - }, - "Auto Location": { - "Auto Location": "מיקום אוטומטי" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "מרווחי חלוניות קופצות אוטומטיים" - }, - "Auto-Clear After": { - "Auto-Clear After": "ניקוי אוטומטי אחרי" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "זמן קצוב להסתרה אוטומטית" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "סגור/י אוטומטית את הסקירה של Niri כשמופעלות אפליקציות." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "מחק/י אוטומטית התראות שהן ישנות יותר מהזמן המצוין" - }, - "Auto-hide": { - "Auto-hide": "הסתרה אוטומטית" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "הסתרה אוטומטית של הDock" - }, - "Auto-saving...": { - "Auto-saving...": "שומר אוטומטית..." - }, - "Autoconnect": { - "Autoconnect": "התחברות אוטומטית" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "התחברות אוטומטית מושבתת" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "התחברות אוטומטית מופעלת" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "מילוי אוטומטי של השאילתה האחרונה שנשמרה בעת הפתיחה" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "מצב צבע אוטומטי" - }, - "Automatic Control": { - "Automatic Control": "בקרה אוטומטית" - }, - "Automatic Cycling": { - "Automatic Cycling": "מעבר מחזורי אוטומטי" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "עבור/עברי באופן אוטומטי ומחזורי בין רקעים שנמצאים באותה תיקייה" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "מחק/י אוטומטית רשומות שהן ישנות יותר מהזמן המצוין" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "זיהוי מיקום אוטומטי לפי כתובת IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "קבע/י את מיקומך אוטומטית באמצעות כתובת הIP שלך" - }, - "Automatically lock after": { - "Automatically lock after": "נעילה אוטומטית לאחר" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "נעל/י אוטומטית את המסך כאשר DMS מופעל" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "נעילה אוטומטית של המסך כשהמערכת מתכוננת למצב השהיה" - }, - "Automation": { - "Automation": "אוטומציה" - }, - "Available": { - "Available": "זמין" - }, - "Available Layouts": { - "Available Layouts": "פריסות זמינות" - }, - "Available Networks": { - "Available Networks": "רשתות זמינות" - }, - "Available Plugins": { - "Available Plugins": "תוספים זמינים" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "מסכים זמינים (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "זמין כתצוגה מפורטת או תצוגה של התחזית" - }, - "Available.": { - "Available.": "זמין." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "חזרה" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "רקע" - }, - "Background Blur": { - "Background Blur": "טשטוש רקע" - }, - "Background Opacity": { - "Background Opacity": "שקיפות רקע" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "סנכרון האימות ברקע נכשל. מנסה במצב מסוף." - }, - "Background image": { - "Background image": "תמונת רקע" - }, - "Backlight device": { - "Backlight device": "התקן תאורה אחורית" - }, - "Balance power and performance": { - "Balance power and performance": "איזון חשמל וביצועים" - }, - "Balanced": { - "Balanced": "מאוזן" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "פלטה מאוזנת עם דגשים ממוקדים (ברירת מחדל)." - }, - "Bar Configurations": { - "Bar Configurations": "תצורות סרגלים" - }, - "Bar Shadows": { - "Bar Shadows": "הצללות סרגל" - }, - "Bar Transparency": { - "Bar Transparency": "שקיפות סרגל" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "צבע בסיס לצללים (שקיפות מוחלת אוטומטית)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "משך בסיסי לאנימציות (גרור/גררי כדי להשתמש בהגדרות מותאמות אישית)" - }, - "Battery": { - "Battery": "סוללה" - }, - "Battery %1": { - "Battery %1": "סוללה %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "מגבלה טעינה לסוללה" - }, - "Battery and power management": { - "Battery and power management": "ניהול סוללה וחשמל" - }, - "Battery level and power management": { - "Battery level and power management": "רמת סוללה וניהול חשמל" - }, - "Behavior": { - "Behavior": "התנהגות" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "מקשר את מסך הנעילה לאותות D-Bus מloginctl. יש להשבית אם משתמשים במסך נעילה חיצוני." - }, - "Binds Include Missing": { - "Binds Include Missing": "קובץ includes של קיצורי מקלדת חסר" - }, - "Binds include added": { - "Binds include added": "קובץ includes של קיצורי מקלדת נוסף" - }, - "Bit Depth": { - "Bit Depth": "עומק סיביות" - }, - "Block Out": { - "Block Out": "חסימה החוצה" - }, - "Block Out From": { - "Block Out From": "חסום/חסמי מתוך" - }, - "Block notifications": { - "Block notifications": "חסום/י התראות" - }, - "Blocked": { - "Blocked": "חסום" - }, - "Blue light filter": { - "Blue light filter": "מסנן אור כחול" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "הגדרות Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth אינו זמין" - }, - "Blur Border Color": { - "Blur Border Color": "צבע מסגרת הטשטוש" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "שקיפות מסגרת הטשטוש" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "שכבת טשטוש לתמונת הרקע" - }, - "Blur on Overview": { - "Blur on Overview": "טשטוש בסקירה" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "טשטש/י את הרקע מאחורי סרגלים, חלונות קופצים, מודלים והתראות. דורש תמיכה והגדרה של הקומפוזיטור." - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "טשטש/י את הרקע כאשר הסקירה של Niri פתוחה" - }, - "Body": { - "Body": "גוף" - }, - "Border": { - "Border": "מסגרת" - }, - "Border Color": { - "Border Color": "צבע מסגרת" - }, - "Border Opacity": { - "Border Opacity": "שקיפות המסגרת" - }, - "Border Size": { - "Border Size": "גודל מסגרת" - }, - "Border Thickness": { - "Border Thickness": "עובי המסגרת" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "צבע המסגרת סביב משטחים מטושטשים" - }, - "Border with BG": { - "Border with BG": "מסגרת עם רקע" - }, - "Bottom": { - "Bottom": "למטה" - }, - "Bottom Center": { - "Bottom Center": "במרכז למטה" - }, - "Bottom Left": { - "Bottom Left": "שמאל למטה" - }, - "Bottom Right": { - "Bottom Right": "ימין למטה" - }, - "Bottom Section": { - "Bottom Section": "קטע תחתון" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "הצגת Dock תחתון לאפליקציות נעוצות ופעילות" - }, - "Brightness": { - "Brightness": "בהירות" - }, - "Brightness Slider": { - "Brightness Slider": "מחוון בהירות" - }, - "Brightness Value": { - "Brightness Value": "ערך הבהירות" - }, - "Brightness control not available": { - "Brightness control not available": "בקרת בהירות לא זמינה" - }, - "Browse": { - "Browse": "עיון" - }, - "Browse Files": { - "Browse Files": "עיין/י בקבצים" - }, - "Browse Plugins": { - "Browse Plugins": "עיון בתוספים" - }, - "Browse Themes": { - "Browse Themes": "עיין/י בערכות נושא" - }, - "Browse or search plugins": { - "Browse or search plugins": "עיין/י או חפש/י תוספים" - }, - "Button Color": { - "Button Color": "צבע כפתור" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "גרף למעבד" - }, - "CPU Temperature": { - "CPU Temperature": "טמפרטורת CPU" - }, - "CPU Usage": { - "CPU Usage": "שימוש בCPU" - }, - "CPU temperature display": { - "CPU temperature display": "תצוגת טמפרטורת CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "מחוון שימוש בCPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "ניטור מעבד, זיכרון, רשת ודיסק" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "אזהרת מסנן לא מאובטח של CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "אזהרת מסנן חסר בCUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "שרת ההדפסה של CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS אינו זמין" - }, - "Camera": { - "Camera": "מצלמה" - }, - "Cancel": { - "Cancel": "ביטול" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "לבטל את כל העבודות עבור \"%1\"?" - }, - "Canceled": { - "Canceled": "בוטל" - }, - "Cannot pair": { - "Cannot pair": "לא ניתן לצמד" - }, - "Capabilities": { - "Capabilities": "יכולות" - }, - "Capacity": { - "Capacity": "קיבולת" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "מחוון Caps Lock" - }, - "Caps Lock is on": { - "Caps Lock is on": "Caps Lock פעיל" - }, - "Center Section": { - "Center Section": "קטע אמצעי" - }, - "Center Single Column": { - "Center Single Column": "מרכוז של עמודה בודדת" - }, - "Center Tiling": { - "Center Tiling": "ריצוף מרכזי" - }, - "Certificate Password": { - "Certificate Password": "סיסמת אישור" - }, - "Change Song": { - "Change Song": "החלפת שיר" - }, - "Change Volume": { - "Change Volume": "שינוי עוצמה" - }, - "Change bar appearance": { - "Change bar appearance": "שנה/י את מראה הסרגל" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "שנה/י את השפה שנעשה בה שימוש בממשק של DMS." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "שנה/י את הגדרות האזור שנעשה בהם שימוש כדי להציג תאריך ושעה, ללא תלות בשפת הממשק." - }, - "Channel": { - "Channel": "ערוץ" - }, - "Charging": { - "Charging": "בטעינה" - }, - "Check for system updates": { - "Check for system updates": "בדוק/בדקי עדכוני מערכת" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "בדוק/בדקי את מצב הסנכרון לפי דרישה. הסנכרון מעתיק את תצורת ערכת הנושא, ההגדרות ותמונת הרקע שלך למסך ההתחברות. שינויי אימות מוחלים באופן אוטומטי." - }, - "Checking for updates...": { - "Checking for updates...": "בודק עדכונים..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "בודק האם נדרש אימות sudo…" - }, - "Checking...": { - "Checking...": "בודק..." - }, - "Checking…": { - "Checking…": "בודק…" - }, - "Choose Color": { - "Choose Color": "בחר/י צבע" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "בחר/י צבע למצב כהה" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "בחר/י צבע לוגו למשגר Dock" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "בחר/י צבע לוגו למשגר" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "בחר/י צבע למצב בהיר" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "בחר/י צבע לרקע" - }, - "Choose a color": { - "Choose a color": "בחר/י צבע" - }, - "Choose colors from palette": { - "Choose colors from palette": "בחר/י צבעים מפלטה" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "בחר/י כיצד ווידג׳ט מזג האוויר מוצג" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "בחר/י לאיזה כיוון יופנה הצל על הסרגל הזה" - }, - "Choose icon": { - "Choose icon": "בחר/י סמל" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "בחר/י את צבע הרקע לווידג׳טים" - }, - "Choose the border accent color": { - "Choose the border accent color": "בחר/י את צבע ההדגשה של המסגרת" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "בחר/י את הלוגו המוצג על כפתור המשגר בDank Bar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "בחר/י היכן יופיעו התראות קופצות על המסך" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "בחר/י היכן יופיעו תצוגות הOSD על המסך" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "בחר/י באילו מסכים יוצג ווידג׳ט זה" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "בחר/י איזה מסך מציג את ממשק מסך הנעילה. מסכים אחרים יציגו צבע אחיד להגנה מפני צריבת OLED." - }, - "Chroma Style": { - "Chroma Style": "סגנון Chroma" - }, - "Cipher": { - "Cipher": "צופן" - }, - "Circle": { - "Circle": "עיגול" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Class regex (לדוגמה ^firefox$)" - }, - "Clear": { - "Clear": "ניקוי" - }, - "Clear All": { - "Clear All": "ניקוי הכל" - }, - "Clear All Jobs": { - "Clear All Jobs": "נקה/י את כל העבודות" - }, - "Clear History?": { - "Clear History?": "לנקות את ההיסטוריה?" - }, - "Clear Sky": { - "Clear Sky": "שמיים בהירים" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "נקה/י את כל ההיסטוריה כאשר השרת מופעל" - }, - "Clear at Startup": { - "Clear at Startup": "ניקוי בהפעלה" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "לחץ/י על 'התקנה' כדי ליצור %1 ולהוסיף אותו לקובץ הconfig שלך." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "לחץ/י על 'התקנה' כדי ליצור את %1 ולכלול אותו בהגדרות הקומפוזיטור שלך." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "לחץ/י על 'התקנה' כדי ליצור קובץ הגדרה לסמן העכבר ולכלול אותו בהגדרות הקומפוזיטור שלך." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "לחץ/י על 'התקנה' כדי ליצור קובץ הגדרה לפלט התצוגה ולכול אותו בהגדרות הקומפוזיטור שלך." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "לחץ/י על ייבוא כדי להוסיף קובץ ovpn. או conf." - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "לחץ/י על רענון כדי לבדוק את הסטטוס." - }, - "Click Through": { - "Click Through": "לחיצה מבעד לווידג׳ט" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "לחץ/י על כל קיצור דרך כדי לערוך. השינויים נשמרים ב-%1" - }, - "Click to capture": { - "Click to capture": "לחץ/י ללכידה" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "לחץ/י כדי לבחור קובץ JSON של ערכת נושא מותאמת אישית" - }, - "Clip": { - "Clip": "חיתוך" - }, - "Clip to Geometry": { - "Clip to Geometry": "הצמדה לגיאומטריה" - }, - "Clipboard": { - "Clipboard": "לוח ההעתקה" - }, - "Clipboard History": { - "Clipboard History": "היסטוריית לוח ההעתקה" - }, - "Clipboard Manager": { - "Clipboard Manager": "מנהל לוח ההעתקה" - }, - "Clipboard sent": { - "Clipboard sent": "לוח ההעתקה נשלח" - }, - "Clipboard service not available": { - "Clipboard service not available": "שירות לוח ההעתקה אינו זמין" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "לוח ההעתקה יעבוד אך שום דבר לא יישמר לדיסק" - }, - "Clock": { - "Clock": "שעון" - }, - "Clock Style": { - "Clock Style": "סגנון השעון" - }, - "Close": { - "Close": "סגירה" - }, - "Close All Windows": { - "Close All Windows": "סגור/י את כל החלונות" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "סגירת הסקירה בעת ההפעלה" - }, - "Close Window": { - "Close Window": "סגור/י חלון" - }, - "Color": { - "Color": "צבע" - }, - "Color Gamut": { - "Color Gamut": "סולם צבעים" - }, - "Color Management": { - "Color Management": "ניהול צבעים" - }, - "Color Mode": { - "Color Mode": "מצב צבע" - }, - "Color Override": { - "Color Override": "דריסת צבע" - }, - "Color Picker": { - "Color Picker": "בוחר הצבעים" - }, - "Color Temperature": { - "Color Temperature": "טמפרטורת צבע" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "הצבע שמוצג על מסכים שלא מציגים את מסך הנעילה" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "צבע לכפתורי פעולה ראשיים" - }, - "Color temperature for day time": { - "Color temperature for day time": "טמפרטורת צבע לשעות היום" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "טמפרטורת צבע למצב לילה" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "ערכת צבעים להדגשת תחביר." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "ערכת צבעים להדגשת תחביר. %1 ערכות נושא זמינות." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "ערכת צבעים מהמאגר של DMS" - }, - "Colorful": { - "Colorful": "צבעוני" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "שילוב צבעוני של דגשים מנוגדים ובהירים." - }, - "Colorize Active": { - "Colorize Active": "צבע למצב ״פעיל״" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "צבעים מתמונת רקע" - }, - "Column": { - "Column": "עמודה" - }, - "Column Display": { - "Column Display": "תצוגת עמודה" - }, - "Column Width": { - "Column Width": "רוחב עמודה" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "רשימה מופרדת בפסיקים של שמות הפעלות להסתרה. עטוף/עטפי בלוכסניות עבור regex (לדוגמה, /^_.*/)." - }, - "Command": { - "Command": "פקודה" - }, - "Commands": { - "Commands": "פקודות" - }, - "Communication": { - "Communication": "תקשורת" - }, - "Community themes": { - "Community themes": "ערכות נושא קהילתיות" - }, - "Compact": { - "Compact": "קומפקטי" - }, - "Compact Mode": { - "Compact Mode": "מצב קומפקטי" - }, - "Completed": { - "Completed": "הושלם" - }, - "Compositor": { - "Compositor": "קומפוזיטור" - }, - "Compositor Settings": { - "Compositor Settings": "הגדרות לקומפוזיטור" - }, - "Compositor not supported": { - "Compositor not supported": "קומפוזיטור לא נתמך" - }, - "Config Format": { - "Config Format": "פורמט ההגדרות" - }, - "Config action: %1": { - "Config action: %1": "פעולת config: %1" - }, - "Config validation failed": { - "Config validation failed": "אימות ההגדרות נכשל" - }, - "Configuration": { - "Configuration": "הגדרות" - }, - "Configuration activated": { - "Configuration activated": "התצורה הופעלה" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "ההגדרות יישמרו כאשר מסך זה יתחבר מחדש" - }, - "Configure": { - "Configure": "הגדר/י" - }, - "Configure Keybinds": { - "Configure Keybinds": "הגדר/י קיצורי מקלדת" - }, - "Configure a new printer": { - "Configure a new printer": "הגדר/י מדפסת חדשה" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "הגדר/י סמלים עבור סביבות עבודה בעלות שם. לסמלים תהיה עדיפות על פני מספרים כאשר שניהם מופעלים." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "הגדר/י קריטריוני התאמה ופעולות" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "הגדר/י אילו מסכים מציגים את \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "הגדר/י אילו מסכים יציגו רכיבי מעטפת" - }, - "Confirm": { - "Confirm": "אשר/י" - }, - "Confirm Delete": { - "Confirm Delete": "אשר/י מחיקה" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "אשר/י שינויי תצוגה" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "אשר/י מפתח גישה עבור " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "מתנגש עם: %1" - }, - "Connect": { - "Connect": "התחבר/י" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "התחבר/י לרשת מוסתרת" - }, - "Connect to VPN": { - "Connect to VPN": "התחבר/י לVPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "התחבר/י לWi-Fi" - }, - "Connected": { - "Connected": "מחובר" - }, - "Connected Device": { - "Connected Device": "התקן מחובר" - }, - "Connected Displays": { - "Connected Displays": "מסכים מחוברים" - }, - "Connecting to Device": { - "Connecting to Device": "מתחבר להתקן" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "מתחבר..." - }, - "Connection failed": { - "Connection failed": "החיבור נכשל" - }, - "Contains": { - "Contains": "כולל" - }, - "Content": { - "Content": "תוכן" - }, - "Content copied": { - "Content copied": "התוכן הועתק" - }, - "Contrast": { - "Contrast": "ניגודיות" - }, - "Control Center": { - "Control Center": "מרכז הבקרה" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "צבע אריח במרכז הבקרה" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "שלוט/שלטי במשך הזמן לאנימציה עבור חלונות קופצים של התראות והיסטוריה" - }, - "Control currently playing media": { - "Control currently playing media": "שלוט/שלטי במדיה שמתנגנת כעת" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "שלוט/י איזה מידע של ההתראות מוצג על מסך הנעילה" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "שלוט/י אילו תוספים מופיעים במצב 'הכל' ללא צורך בקידומת מפעיל. גרור/י כדי לסדר מחדש." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "שלוט/י בסביבות העבודה ועמודות באמצעות גלילה על הסרגל" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "שולט בשקיפות של כל החלונות הקופצים, המודלים ושכבות התוכן שלהם" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "שולט בכיוון הטלת הצל עבור שכבות הגבהה" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "שולט ברדיוס הטשטוש הבסיסי ובהיסט של הצללים" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "שולט בשקיפות הצל" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "אפשרויות נוחות למסך ההתחברות. הרץ/י סנכרון כדי להחיל." - }, - "Cooldown": { - "Cooldown": "זמן המתנה" - }, - "Copied GIF": { - "Copied GIF": "GIF הועתק" - }, - "Copied MP4": { - "Copied MP4": "MP4 הועתק" - }, - "Copied WebP": { - "Copied WebP": "WebP הועתק" - }, - "Copied to clipboard": { - "Copied to clipboard": "הועתק ללוח" - }, - "Copied!": { - "Copied!": "הועתק!" - }, - "Copy": { - "Copy": "העתק/י" - }, - "Copy Content": { - "Copy Content": "העתק/י תוכן" - }, - "Copy Full Command": { - "Copy Full Command": "העתק/י פקודה מלאה" - }, - "Copy HTML": { - "Copy HTML": "העתק/י HTML" - }, - "Copy Name": { - "Copy Name": "העתק/י שם" - }, - "Copy PID": { - "Copy PID": "העתק/י PID" - }, - "Copy Text": { - "Copy Text": "העתק/י טקסט" - }, - "Copy path": { - "Copy path": "העתק/י נתיב" - }, - "Corner Radius": { - "Corner Radius": "רדיוס פינות" - }, - "Corner Radius Override": { - "Corner Radius Override": "דריסת רדיוס הפינות" - }, - "Corners & Background": { - "Corners & Background": "פינות ורקע" - }, - "Count Only": { - "Count Only": "ספירה בלבד" - }, - "Cover Open": { - "Cover Open": "מכסה פתוח" - }, - "Create": { - "Create": "יצירה" - }, - "Create Dir": { - "Create Dir": "יצירת תיקייה" - }, - "Create Printer": { - "Create Printer": "צור/צרי מדפסת" - }, - "Create Window Rule": { - "Create Window Rule": "צור/צרי חוק לחלון" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "צור/צרי הפעלה חדשה של %1 (n)" - }, - "Create rule for:": { - "Create rule for:": "צור/צרי חוק עבור:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "צור/צרי חוקים להשתקה, התעלמות, הסתרה מההיסטוריה או דריסת עדיפויות להתראה. כברירת מחדל רק העדיפויות נדרסות; ההתראות עדיין מוצגות כרגיל." - }, - "Creating...": { - "Creating...": "יוצר..." - }, - "Critical Priority": { - "Critical Priority": "עדיפות קריטית" - }, - "Current": { - "Current": "עכשיו" - }, - "Current Items": { - "Current Items": "פריטים נוכחיים" - }, - "Current Locale": { - "Current Locale": "השפה והאזור הנוכחיים" - }, - "Current Monitor": { - "Current Monitor": "המסך הנוכחי" - }, - "Current Period": { - "Current Period": "הזמן הנוכחי" - }, - "Current Status": { - "Current Status": "המצב הנוכחי" - }, - "Current Temp": { - "Current Temp": "הטמפרטורה הנוכחית" - }, - "Current Theme: %1": { - "Current Theme: %1": "ערכת נושא נוכחית: %1" - }, - "Current Weather": { - "Current Weather": "מזג אוויר נוכחי" - }, - "Current Workspace": { - "Current Workspace": "סביבת העבודה הנוכחית" - }, - "Current time and date display": { - "Current time and date display": "הצגה של התאריך והשעה הנוכחיים" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "תנאי מזג אוויר וטמפרטורה נוכחיים" - }, - "Current: %1": { - "Current: %1": "נוכחי: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "סמן העכבר אינו מוגדר" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "קובץ includes של סמן העכבר חסר" - }, - "Cursor Size": { - "Cursor Size": "גודל סמן העכבר" - }, - "Cursor Theme": { - "Cursor Theme": "ערכת נושא לסמן העכבר" - }, - "Custom": { - "Custom": "מותאם אישית" - }, - "Custom Color": { - "Custom Color": "צבע מותאם אישית" - }, - "Custom Duration": { - "Custom Duration": "משך מותאם אישית" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "פקודת שינה עמוקה מותאמת אישית" - }, - "Custom Location": { - "Custom Location": "מיקום מותאם אישית" - }, - "Custom Lock Command": { - "Custom Lock Command": "פקודת נעילה מותאמת אישית" - }, - "Custom Logout Command": { - "Custom Logout Command": "פקודת התנתקות מותאמת אישית" - }, - "Custom Name": { - "Custom Name": "שם מותאם אישית" - }, - "Custom Power Actions": { - "Custom Power Actions": "פעולות חשמל מותאמות אישית" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "פקודת כיבוי מותאמת אישית" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "פקודת הפעלה מחדש מותאמת אישית" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "צבע צל מותאם אישית" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "דריסת צל מותאמת אישית" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "פקודת השהיה מותאמת אישית" - }, - "Custom Transparency": { - "Custom Transparency": "שקיפות מותאמת אישית" - }, - "Custom power profile": { - "Custom power profile": "פרופיל חשמל מותאם אישית" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "ערכת נושא מותאמת אישית נטענה מקובץ JSON" - }, - "Custom...": { - "Custom...": "מותאם אישית..." - }, - "Custom: ": { - "Custom: ": "מותאם אישית: " - }, - "Customizable empty space": { - "Customizable empty space": "רווח ריק הניתן להתאמה" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "התאם/י אישית אילו פעולות יופיעו בתפריט הכיבוי" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "מנטר DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "מצב הדגמה - לחץ/י בכל מקום כדי לצאת" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "מנהל התוספים של DMS אינו זמין" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "קיצורי DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "מסך ההתחברות של DMS דורש את החבילות הבאות: greetd ו-dms-greeter (חובה), fprintd ו-pam_fprintd (להזדהות עם טביעת אצבע) ו-pam_u2f (להזדהות עם מפתחות אבטחה). הוסף/הוסיפי את המשתמש שלך לקבוצת greeter. שינויי אימות מוחלים באופן אוטומטי ועשויים לפתוח מסוף כאשר נדרש אימות עם sudo." - }, - "DMS out of date": { - "DMS out of date": "הDMS לא מעודכן" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "השירות של DMS אינו מחובר. הגדרות לוח ההעתקה אינן זמינות." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "פעולות מעטפת של DMS (משגר, לוח העתקה וכו')" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET אינו זמין" - }, - "DWL service not available": { - "DWL service not available": "שירות DWL אינו זמין" - }, - "Daily": { - "Daily": "יומי" - }, - "Daily at:": { - "Daily at:": "יומי בשעה:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "Dank Bar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell מוכן לשימוש" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "סמלי DankShell ומערכת (דורש הפעלה מחדש)" - }, - "Dark Mode": { - "Dark Mode": "מצב כהה" - }, - "Dark mode base": { - "Dark mode base": "בסיס למצב כהה" - }, - "Dark mode harmony": { - "Dark mode harmony": "הרמוניה במצב כהה" - }, - "Darken Modal Background": { - "Darken Modal Background": "הכהיית הרקע של חלוניות" - }, - "Date Format": { - "Date Format": "תבנית תאריך" - }, - "Date format": { - "Date format": "תבנית תאריך" - }, - "Date format on greeter": { - "Date format on greeter": "תבנית תאריך בGreeter" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "שחר (דמדומים אסטרונומיים)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "שחר (דמדומים אזרחיים)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "שחר (דמדומים ימיים)" - }, - "Day Date": { - "Day Date": "יום תאריך" - }, - "Day Month Date": { - "Day Month Date": "יום חודש תאריך" - }, - "Day Temperature": { - "Day Temperature": "טמפרטורת יום" - }, - "Daytime": { - "Daytime": "יום" - }, - "Deck": { - "Deck": "חפיסה" - }, - "Default": { - "Default": "ברירת מחדל" - }, - "Default (Black)": { - "Default (Black)": "ברירת מחדל (שחור)" - }, - "Default Width (%)": { - "Default Width (%)": "רוחב ברירת מחדל (%)" - }, - "Default selected action": { - "Default selected action": "פעולת ברירת המחדל הרצויה" - }, - "Defaults": { - "Defaults": "ערכי ברירת מחדל" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "הגדר/י חוקים להתנהגות חלון. נשמר ב-%1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: ניקוי • Shift+Del: ניקוי הכל • 1-9: פעולות • F10: עזרה • Esc: סגירה" - }, - "Delete": { - "Delete": "מחק/י" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "למחוק את \"%1\"?" - }, - "Delete Class": { - "Delete Class": "מחק/י סוג" - }, - "Delete Printer": { - "Delete Printer": "מחק/י מדפסת" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "למחוק את הפריט השמור?" - }, - "Delete VPN": { - "Delete VPN": "מחק/י VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "למחוק את המחלקה \"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "למחוק את הפרופיל \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "חבילות נדרשות ודוקיומנטציה" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "גוזר צבעים התואמים באופן הדוק לתמונה שמתחת." - }, - "Description": { - "Description": "תיאור" - }, - "Desktop": { - "Desktop": "שולחן העבודה" - }, - "Desktop Clock": { - "Desktop Clock": "שעון לשולחן העבודה" - }, - "Desktop Entry": { - "Desktop Entry": "רשומה של שולחן העבודה" - }, - "Desktop Widget": { - "Desktop Widget": "ווידג׳ט לשולחן העבודה" - }, - "Desktop Widgets": { - "Desktop Widgets": "ווידג׳טים לשולחן העבודה" - }, - "Desktop background images": { - "Desktop background images": "תמונות רקע לשולחן העבודה" - }, - "Detailed": { - "Detailed": "תצוגה מפורטת" - }, - "Details for \"%1": { - "Details for \"%1\"": "פרטים עבור \"%1\"" - }, - "Development": { - "Development": "פיתוח" - }, - "Device": { - "Device": "התקן" - }, - "Device connections": { - "Device connections": "חיבורי התקנים" - }, - "Device names updated": { - "Device names updated": "שמות ההתקנים עודכנו" - }, - "Device paired": { - "Device paired": "ההתקן צומד" - }, - "Device unpaired": { - "Device unpaired": "הצמדת ההתקן בוטלה" - }, - "Digital": { - "Digital": "דיגיטלי" - }, - "Direction Source": { - "Direction Source": "מקור כיוון" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "השבת/י התחברות אוטומטית" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "השבתת רקעים מובנים" - }, - "Disable History Persistence": { - "Disable History Persistence": "השבתה של שמירת ההיסטוריה" - }, - "Disable Output": { - "Disable Output": "השבתת פלט תצוגה" - }, - "Disabled": { - "Disabled": "מושבת" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "משבית WiFi..." - }, - "Disc": { - "Disc": "דיסק" - }, - "Discard": { - "Discard": "השלך/י" - }, - "Discharging": { - "Discharging": "מתרוקן" - }, - "Disconnect": { - "Disconnect": "ניתוק" - }, - "Disconnected": { - "Disconnected": "מנותק" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "החיבור לWiFi התנתק" - }, - "Discover Devices": { - "Discover Devices": "גלה/י התקנים" - }, - "Disk": { - "Disk": "דיסק" - }, - "Disk I/O": { - "Disk I/O": "קלט/פלט של הדיסק" - }, - "Disk Usage": { - "Disk Usage": "שימוש בדיסק" - }, - "Disk Usage Display": { - "Disk Usage Display": "תצוגת שימוש בדיסק" - }, - "Disks": { - "Disks": "דיסקים" - }, - "Dismiss": { - "Dismiss": "סגירה" - }, - "Display": { - "Display": "תצוגה" - }, - "Display Assignment": { - "Display Assignment": "הקצאת תצוגה" - }, - "Display Control": { - "Display Control": "בקרת תצוגה" - }, - "Display Name Format": { - "Display Name Format": "תבנית שם התצוגה" - }, - "Display Profiles": { - "Display Profiles": "פרופילי תצוגה" - }, - "Display Settings": { - "Display Settings": "הגדרות תצוגה" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "הצג/י את הDock עם אפליקציות מוצמדות ופעילות" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "הצג/י את כל ההתראות מעל אפליקציות במסך מלא" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "הצג/י והחלף/י פריסות DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "הצג/י סמלי אפליקציות במצייני סביבת העבודה" - }, - "Display brightness control": { - "Display brightness control": "בקרת בהירות תצוגה" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "הגדרת התצוגה אינה זמינה. פרוטוקול ניהול פלט WLR אינו נתמך." - }, - "Display currently focused application title": { - "Display currently focused application title": "הצג/י את כותרת האפליקציה שנמצאת כרגע במוקד" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "הצג/י תחזיות מזג אוויר שעתיות" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "הצג/י רק סביבות עבודה שמכילות חלונות" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "הצג/י את פעולות תפריט הכיבוי ברשת במקום ברשימה" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "הצג/י שניות בשעון" - }, - "Display the power system menu": { - "Display the power system menu": "הצג/י את תפריט המערכת לניהול החשמל" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "הצג/י ערכי אחוזים של עוצמת קול ובהירות בחלונות OSD קופצים" - }, - "Displays": { - "Displays": "מסכים" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "מציג ספירה כאשר הגלישה פעילה" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "מציג את פריסת המקלדת הפעילה ומאפשר להחליף בין פריסות" - }, - "Distribution": { - "Distribution": "הפצה" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "פלטה מגוונת המקיפה את כל הספקטרום." - }, - "Do Not Disturb": { - "Do Not Disturb": "״נא לא להפריע״" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "משגר וDock" - }, - "Dock Transparency": { - "Dock Transparency": "שקיפות הDock" - }, - "Dock Visibility": { - "Dock Visibility": "נראות הDock" - }, - "Docs": { - "Docs": "דוקיומנטציה" - }, - "Documents": { - "Documents": "מסמכים" - }, - "Domain (optional)": { - "Domain (optional)": "דומיין (לא חובה)" - }, - "Don't Change": { - "Don't Change": "ללא שינוי" - }, - "Don't Save": { - "Don't Save": "אל תשמור/תשמרי" - }, - "Door Open": { - "Door Open": "דלת פתוחה" - }, - "Downloads": { - "Downloads": "הורדות" - }, - "Drag to Reorder": { - "Drag to Reorder": "גרירה בכדי לסדר מחדש" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "גרור/גררי ווידג׳טים כדי לשנות את סדרם בתוך מקטעים. השתמש/י בסמל העין כדי להסתיר/להציג ווידג׳טים (שומר על המרווח), או בX כדי להסיר אותם לחלוטין." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "גרור/גררי את מחווני סביבות העבודה כדי לסדר אותם מחדש" - }, - "Driver": { - "Driver": "מנהל התקן" - }, - "Drizzle": { - "Drizzle": "טפטוף" - }, - "Duplicate": { - "Duplicate": "שכפל/י" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "שכפול רקע עם טשטוש" - }, - "Duration": { - "Duration": "משך זמן" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "צאת הכוכבים (דמדומים אסטרונומיים)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "צאת הכוכבים (דמדומים אזרחיים)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "צאת הכוכבים (דמדומים ימיים)" - }, - "Dynamic": { - "Dynamic": "דינמי" - }, - "Dynamic Properties": { - "Dynamic Properties": "מאפיינים דינמיים" - }, - "Dynamic Theming": { - "Dynamic Theming": "עיצוב דינמי" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "צבעים דינמיים מתמונת הרקע" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "צבעים דינמיים, הגדרות מוכנות" - }, - "Edge Spacing": { - "Edge Spacing": "ריווח קצוות" - }, - "Edit App": { - "Edit App": "ערוך/ערכי אפליקציה" - }, - "Edit Window Rule": { - "Edit Window Rule": "ערוך/ערכי את חוק החלון" - }, - "Education": { - "Education": "חינוך" - }, - "Empty": { - "Empty": "ריק" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "הפעל/י עומק צבע של 10 סיביות לסולם צבעים רחב יותר עם תמיכה בHDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "הפעל/י התחברות אוטומטית" - }, - "Enable Bar": { - "Enable Bar": "הפעל/י סרגל" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "הפעלה של מצב ״נא לא להפריע״" - }, - "Enable History": { - "Enable History": "הפעלת ההיסטוריה" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "הפעלת שכבת כיסוי לסקירה" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "הפעלת אפקטי אדווה" - }, - "Enable System Sounds": { - "Enable System Sounds": "הפעלת צלילי מערכת" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "הפעלת שומר מסך עם וידאו" - }, - "Enable Weather": { - "Enable Weather": "הפעלת מזג אוויר" - }, - "Enable WiFi": { - "Enable WiFi": "הפעל/י Wi-Fi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "הפעל/י דריסה מותאמת אישית למטה כדי להגדיר עוצמת צל, שקיפות וצבע עבור כל סרגל בנפרד." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "הפעל/י שכבת טשטוש הניתנת לזיהוי על ידי הקומפוזיטור (namespace: dms:blurwallpaper). דורש הגדרה ידנית של Niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "הפעלת הזדהות עם טביעת אצבע" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "הפעלת אימות באמצעות טביעת אצבע" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "הפעל/י הזדהות באמצעות טביעת אצבע או מפתח אבטחה במסך ההתחברות של DMS. שינויי אימות מוחלים באופן אוטומטי." - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "הפעלת האינטגרציה עם loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "הפעלת הזדהות עם מפתח אבטחה" - }, - "Enable security key authentication": { - "Enable security key authentication": "הפעלת אימות באמצעות מפתח אבטחה" - }, - "Enabled": { - "Enabled": "מופעל" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "מופעל, אך לא ניתן היה לאשר את זמינות טביעת האצבע." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "מופעל, אך לא זוהה קורא טביעות אצבע." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "מופעל, אך אין טביעות אצבע רשומות עדיין. שינויי אימות מוחלים באופן אוטומטי לאחר רישום טביעות אצבע." - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "מופעל, אך אין טביעות אצבע רשומות עדיין. רשום/י טביעות אצבע והרץ/י את הסנכרון." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "מופעל, אך לא נמצא מפתח אבטחה רשום עדיין. שינויי אימות מוחלים באופן אוטומטי לאחר רישום המפתח שלך או עדכון תצורת ה-U2F שלך." - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "מופעל, אך לא נמצא מפתח אבטחה רשום עדיין. רשום/י מפתח והרץ/י את הסנכרון." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "מופעל, אך לא ניתן היה לאמת את זמינות מפתח האבטחה." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "מופעל. PAM כבר מספק אימות באמצעות טביעת אצבע." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "מופעל. PAM כבר מספק אימות באמצעות מפתח אבטחה." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "מופעל. PAM מספק אימות באמצעות טביעת אצבע, אך אין טביעות אצבע רשומות עדיין." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "מפעיל WiFi..." - }, - "End": { - "End": "סוף" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "הגדל/י בריחוף" - }, - "Enlargement %": { - "Enlargement %": "אחוז הגדלה" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "הזן/י מפתח גישה בן 6 ספרות" - }, - "Enter PIN": { - "Enter PIN": "הזן/י קוד PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "הזן/י קוד PIN עבור " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "הזן/י קישור (URL) או טקסט לשיתוף" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "הזן/י שם חדש להפעלה \"%1\"" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "הזן/י שם חדש לסביבת העבודה הזו" - }, - "Enter command or script path": { - "Enter command or script path": "הזן/י פקודה או נתיב לתסריט" - }, - "Enter credentials for ": { - "Enter credentials for ": "הזן/י אישורי גישה עבור " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "הזן/י תבנית מותאמת אישית למסך הנעילה (לדוגמא: dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "הזן/י תבנית מותאמת אישית לסרגל העליון (לדוגמא: ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "הזן/י שם להתקן..." - }, - "Enter filename...": { - "Enter filename...": "הזן/י שם קובץ..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "הזן/י קידומת הפעלה (לדוגמה: 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "הזן/י שם רשת וסיסמה" - }, - "Enter passkey for ": { - "Enter passkey for ": "הזן/י מפתח גישה עבור " - }, - "Enter password for ": { - "Enter password for ": "הזן/י סיסמה עבור " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "הזן/י מפתח גישה זה ב" - }, - "Enter to Paste": { - "Enter to Paste": "הדבקה עם Enter" - }, - "Enterprise": { - "Enterprise": "ארגוני" - }, - "Entry pinned": { - "Entry pinned": "הרשומה הוצמדה" - }, - "Entry unpinned": { - "Entry unpinned": "הצמדת הרשומה בוטלה" - }, - "Environment Variables": { - "Environment Variables": "משתני סביבה" - }, - "Error": { - "Error": "שגיאה" - }, - "Errors": { - "Errors": "שגיאות" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "מדויק" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "היסט האזור הבלעדי" - }, - "Experimental Feature": { - "Experimental Feature": "תכונה ניסיונית" - }, - "Explore": { - "Explore": "גלה/י" - }, - "Exponential": { - "Exponential": "אקספוננציאלי" - }, - "Expressive": { - "Expressive": "אקספרסיבי" - }, - "Extend battery life": { - "Extend battery life": "הארכת חיי סוללה" - }, - "Extensible architecture": { - "Extensible architecture": "ארכיטקטורה ניתנת להרחבה" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "ניהול רקעים חיצוני" - }, - "Extra Arguments": { - "Extra Arguments": "ארגומנטים נוספים" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: החלפה • F10: עזרה" - }, - "Fade": { - "Fade": "דהייה" - }, - "Fade to lock screen": { - "Fade to lock screen": "דהייה למסך הנעילה" - }, - "Fade to monitor off": { - "Fade to monitor off": "דהייה לכיבוי המסך" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "אישור הצימוד נכשל" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "הפעלת התצורה נכשלה" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "הפעלת הפרופיל נכשלה - הקובץ לא נמצא" - }, - "Failed to add binds include": { - "Failed to add binds include": "הוספת קובץ includes של קיצורי מקלדת נכשלה" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "הוספת המדפסת לסוג נכשלה" - }, - "Failed to browse device": { - "Failed to browse device": "הניסיון לעיין בהתקן נכשל" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "ביטול כל העבודות נכשל" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "ביטול העבודה שנבחרה נכשל" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "בדיקת העדכונים נכשלה:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "בדיקת מגבלת ההצמדה נכשלה" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "החיבור לVPN נכשל" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "ההתחברות ל-%1 נכשלה" - }, - "Failed to copy entry": { - "Failed to copy entry": "העתקת הרשומה נכשלה" - }, - "Failed to create printer": { - "Failed to create printer": "יצירת המדפסת נכשלה" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "יצירת תיקיית הפרופילים נכשלה" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "מחיקת הVPN נכשלה" - }, - "Failed to delete class": { - "Failed to delete class": "מחיקת הסוג נכשלה" - }, - "Failed to delete printer": { - "Failed to delete printer": "מחיקת המדפסת נכשלה" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "השבתת קבלת עבודות נכשלה" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "השבתת מצב לילה נכשלה" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "הניתוק מVPN נכשל" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "ניתוק הVPNs נכשל" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "ניתוק הWiFi נכשל" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "הפעלת מיקום לפי IP נכשלה" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "הפעלת הWiFi נכשלה" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "הפעלת קבלת עבודות נכשלה" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "הפעלת מצב לילה נכשלה" - }, - "Failed to hold job": { - "Failed to hold job": "השהיית העבודה נכשלה" - }, - "Failed to import VPN": { - "Failed to import VPN": "ייבוא הVPN נכשל" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "הפעלת אפליקציית הSMS נכשלה" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "טעינת תצורת הVPN נכשלה" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "טעינת הגדרות לוח ההעתקה נכשלה." - }, - "Failed to move job": { - "Failed to move job": "העברת העבודה נכשלה" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "הקריאה של הקובץ plugin_settings.json נכשלה" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "הקריאה של הקובץ session.json נכשלה" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "הקריאה של הקובץ settings.json נכשלה" - }, - "Failed to pause printer": { - "Failed to pause printer": "השהיית המדפסת נכשלה" - }, - "Failed to pin entry": { - "Failed to pin entry": "הצמדת הרשומה נכשלה" - }, - "Failed to print test page": { - "Failed to print test page": "הדפסת דף בדיקה נכשלה" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "דחיית ההצמדה נכשלה" - }, - "Failed to remove device": { - "Failed to remove device": "הסרת ההתקן נכשלה" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "הסרת קיצור המקלדת נכשלה" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "הסרת המדפסת מהסוג נכשלה" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "הפעלת מערכת השמע מחדש נכשלה" - }, - "Failed to restart job": { - "Failed to restart job": "הפעלת העבודה מחדש נכשלה" - }, - "Failed to resume printer": { - "Failed to resume printer": "המשך פעולת המדפסת נכשל" - }, - "Failed to ring device": { - "Failed to ring device": "שליחת הצלצול להתקן נכשלה" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "הרצת הפקודה 'dms greeter status' נכשלה. ודא/י שDMS מותקן ו-dms נמצא בPATH." - }, - "Failed to save audio config": { - "Failed to save audio config": "שמירת הגדרות שמע נכשלה" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "שמירת ההגדרה של לוח ההעתקה נכשלה" - }, - "Failed to save keybind": { - "Failed to save keybind": "שמירת קיצור המקלדת נכשלה" - }, - "Failed to save profile file": { - "Failed to save profile file": "שמירת קובץ פרופיל נכשלה" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "שליחת לוח ההעתקה נכשלה" - }, - "Failed to send file": { - "Failed to send file": "שליחת הקובץ נכשלה" - }, - "Failed to send ping": { - "Failed to send ping": "הניסיון לשלוח פינג נכשל" - }, - "Failed to set brightness": { - "Failed to set brightness": "הגדרת הבהירות נכשלה" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "הגדרת מיקום למצב לילה נכשלה" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "הגדרת לוח הזמנים של מצב לילה נכשלה" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "הגדרת טמפרטורת מצב לילה נכשלה" - }, - "Failed to set power profile": { - "Failed to set power profile": "הניסיון להגדיר פרופיל לצריכת החשמל נכשל" - }, - "Failed to set profile image": { - "Failed to set profile image": "הגדרת תמונת הפרופיל נכשלה" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "הגדרת תמונת פרופיל נכשלה: %1" - }, - "Failed to share": { - "Failed to share": "השיתוף נכשל" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "התחלת החיבור ל%1 נכשלה" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "ביטול הצמדת הרשומה נכשל" - }, - "Failed to update VPN": { - "Failed to update VPN": "עדכון הVPN נכשל" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "עדכון הגדרת התחברות אוטומטית נכשל" - }, - "Failed to update description": { - "Failed to update description": "עדכון התיאור נכשל" - }, - "Failed to update location": { - "Failed to update location": "עדכון המיקום נכשל" - }, - "Failed to update sharing": { - "Failed to update sharing": "עדכון השיתוף נכשל" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "כתיבת קובץ זמני לאימות נכשלה" - }, - "Features": { - "Features": "תכונות" - }, - "Feels": { - "Feels": "מרגיש כמו" - }, - "Feels Like": { - "Feels Like": "מרגיש כמו" - }, - "Feels Like %1°": { - "Feels Like %1°": "מרגיש כמו %1°" - }, - "Fidelity": { - "Fidelity": "נאמנות" - }, - "Field": { - "Field": "שדה" - }, - "File": { - "File": "קובץ" - }, - "File Already Exists": { - "File Already Exists": "הקובץ כבר קיים" - }, - "File Information": { - "File Information": "פרטי קובץ" - }, - "File received from": { - "File received from": "התקבל קובץ מ" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "חיפוש קבצים הכלי dsearch נדרש כדי לבצע חיפוש של קבצים.\nהתקן/י אותו מ: github.com/morelazers/dsearch" - }, - "Files": { - "Files": "קבצים" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "ניטור שימוש במערכת הקבצים" - }, - "Fill": { - "Fill": "מילוי" - }, - "Find in Text": { - "Find in Text": "חפש/י בטקסט" - }, - "Find in note...": { - "Find in note...": "חפש/י בפתק..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "לא ניתן היה לאשר את זמינות טביעת האצבע." - }, - "Fingerprint error": { - "Fingerprint error": "שגיאת טביעת אצבע" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "שגיאת טביעת אצבע: %1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "טביעת האצבע לא זוהתה (%1/%2). נא לנסות שוב או להשתמש בסיסמה." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "זוהה קורא טביעות אצבע, אך אין טביעות אצבע רשומות עדיין. ניתן להפעיל את ההזדהות כעת ולרשום את הטביעות מאוחר יותר." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "זוהה קורא טביעות אצבע, אך אין טביעות אצבע רשומות עדיין. ניתן להפעיל את ההזדהות כעת ולהריץ סנכרון מאוחר יותר." - }, - "Finish": { - "Finish": "סיום" - }, - "First Day of Week": { - "First Day of Week": "היום הראשון בשבוע" - }, - "First Time Setup": { - "First Time Setup": "התקנה ראשונית" - }, - "Fit": { - "Fit": "התאמה" - }, - "Fix Now": { - "Fix Now": "תקן/י עכשיו" - }, - "Fixing...": { - "Fixing...": "מתקן..." - }, - "Flags": { - "Flags": "דגלים" - }, - "Flipped": { - "Flipped": "הפוך" - }, - "Flipped 180°": { - "Flipped 180°": "היפוך של 180°" - }, - "Flipped 270°": { - "Flipped 270°": "היפוך של 270°" - }, - "Flipped 90°": { - "Flipped 90°": "היפוך של 90°" - }, - "Float": { - "Float": "צף" - }, - "Focus": { - "Focus": "מיקוד" - }, - "Focus at Startup": { - "Focus at Startup": "מיקוד בהפעלה" - }, - "Focused Border": { - "Focused Border": "מסגרת ממוקדת" - }, - "Focused Color": { - "Focused Color": "צבע ממוקד" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "מסך ממוקד בלבד" - }, - "Focused Window": { - "Focused Window": "חלון ממוקד" - }, - "Focused monitor only": { - "Focused monitor only": "מסך ממוקד בלבד" - }, - "Fog": { - "Fog": "ערפל" - }, - "Folder": { - "Folder": "תיקייה" - }, - "Folders": { - "Folders": "תיקיות" - }, - "Follow DMS background color": { - "Follow DMS background color": "עקוב/י אחרי צבע הרקע של DMS" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "מעקב אחרי המסך הממוקד" - }, - "Follow focus": { - "Follow focus": "עקוב/י אחר מיקוד" - }, - "Font": { - "Font": "גופן" - }, - "Font Family": { - "Font Family": "משפחת הגופן" - }, - "Font Scale": { - "Font Scale": "קנה מידה לגופן" - }, - "Font Size": { - "Font Size": "גודל הגופן" - }, - "Font Weight": { - "Font Weight": "משקל הגופן" - }, - "Font used on the login screen": { - "Font used on the login screen": "הגופן שנעשה בו שימוש במסך ההתחברות" - }, - "Force HDR": { - "Force HDR": "אלץ/י HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "כפה/י סגירה (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "אלץ/י צבע רחב" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "אלץ/י יישומי מסוף להשתמש תמיד בערכות צבעים כהות" - }, - "Forecast": { - "Forecast": "תחזית" - }, - "Forecast Days": { - "Forecast Days": "ימי תחזית" - }, - "Forecast Not Available": { - "Forecast Not Available": "תחזית לא זמינה" - }, - "Forever": { - "Forever": "לנצח" - }, - "Forget": { - "Forget": "שכח/י" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "לשכוח את הרשת \"%1\"?" - }, - "Forget Device": { - "Forget Device": "שכח/י התקן" - }, - "Forget Network": { - "Forget Network": "שכח/י רשת" - }, - "Forgot network %1": { - "Forgot network %1": "נשכחה הרשת %1" - }, - "Format Legend": { - "Format Legend": "מקרא תבניות" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "נמצאה %1 חבילה לעדכון:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "נמצאו %1 חבילות לעדכון:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "שחרר/י את הזיכרון (VRAM) כאשר המשגר נסגר. עלול לגרום לעיכוב קל בפתיחה מחדש." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "טפטוף קפוא" - }, - "Frequency": { - "Frequency": "תדירות" - }, - "Fruit Salad": { - "Fruit Salad": "סלט פירות" - }, - "Full Command:": { - "Full Command:": "פקודה מלאה:" - }, - "Full Content": { - "Full Content": "תוכן מלא" - }, - "Full Day & Month": { - "Full Day & Month": "יום וחודש מלאים" - }, - "Full with Year": { - "Full with Year": "מלא עם שנה" - }, - "Fullscreen": { - "Fullscreen": "מסך מלא" - }, - "Fullscreen Only": { - "Fullscreen Only": "מסך מלא בלבד" - }, - "Fully Charged": { - "Fully Charged": "טעונה במלואה" - }, - "Fun": { - "Fun": "כיף" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: רשת • Z/X: גודל" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "ניטור GPU" - }, - "GPU Temperature": { - "GPU Temperature": "טמפרטורת GPU" - }, - "GPU temperature display": { - "GPU temperature display": "הצגת טמפרטורת GPU" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "Qt, GTK, סביבות פיתוח, ועוד" - }, - "Games": { - "Games": "משחקים" - }, - "Gamma Control": { - "Gamma Control": "בקרת גאמה" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "בקרת גאמה אינה זמינה. נדרש API של DMS גרסה 6 ומעלה." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "צור/צרי תצורות בסיס עבור GTK3/4 או QT5/QT6 (החבילה qt6ct-kde נדרשת) כדי לעקוב אחר הצבעים של DMS. צריך ליצור את התבנית רק פעם אחת.

        מומלץ להגדיר את adw-gtk3 לפני החלת ערכות נושא על GTK." - }, - "Generic": { - "Generic": "כללי" - }, - "Get Started": { - "Get Started": "התחל/י" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "התאם/י גלובלית את כל משכי הזמן לאנימציה" - }, - "Golden Hour": { - "Golden Hour": "שעת הזהב" - }, - "Good": { - "Good": "טוב" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "רדיוס לפינה גות׳ית" - }, - "Goth Corners": { - "Goth Corners": "פינות גות׳יות" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "הפעל/י דהייה הדרגתית של המסך לפני הנעילה עם תקופת חסד הניתנת להגדרה" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "הפעל/י דהייה הדרגתית של התצוגה לפני כיבוי המסכים עם תקופת חסד הניתנת להגדרה" - }, - "Graph Time Range": { - "Graph Time Range": "טווח זמן לגרף" - }, - "Graphics": { - "Graphics": "גרפיקה" - }, - "Greeter": { - "Greeter": "מסך ההתחברות" - }, - "Greeter Appearance": { - "Greeter Appearance": "המראה של מסך ההתחברות" - }, - "Greeter Behavior": { - "Greeter Behavior": "התנהגות מסך ההתחברות" - }, - "Greeter Status": { - "Greeter Status": "מצב מסך ההתחברות" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "מסך ההתחברות הופעל. greetd פועל כעת כמנהל התצוגה." - }, - "Greeter font": { - "Greeter font": "גופן מסך ההתחברות" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "במסך ההתחברות בלבד - ללא השפעה על השעון הראשי" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "במסך ההתחברות בלבד - תבנית לתאריך שמופיע בכניסה" - }, - "Grid": { - "Grid": "רשת" - }, - "Grid Columns": { - "Grid Columns": "עמודות רשת" - }, - "Grid: OFF": { - "Grid: OFF": "תצוגת רשת: כבויה" - }, - "Grid: ON": { - "Grid: ON": "תצוגת רשת: מופעלת" - }, - "Group": { - "Group": "קבוצה" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "קיבוץ האפליקציות של סביבת העבודה" - }, - "Group by App": { - "Group by App": "קיבוץ לפי אפליקציה" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "קבץ/י מספר חלונות של אותה אפליקציה יחד עם מונה חלונות" - }, - "Group removed": { - "Group removed": "הקבוצה הוסרה" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "קבץ/י סמלי אפליקציות חוזרים בסביבות עבודה לא ממוקדות" - }, - "Groups": { - "Groups": "קבוצות" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "מיפוי גוונים HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "מצב HDR הוא ניסיוני. ודא/י שהצג שלך תומך בHDR לפני ההפעלה." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML הועתק ללוח ההעתקה" - }, - "Health": { - "Health": "בריאות" - }, - "Heavy Rain": { - "Heavy Rain": "גשם כבד" - }, - "Heavy Snow": { - "Heavy Snow": "שלג כבד" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "מקלחות שלג כבדות" - }, - "Height": { - "Height": "גובה" - }, - "Held": { - "Held": "מושהה" - }, - "Help": { - "Help": "עזרה" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "שינה עמוקה" - }, - "Hidden": { - "Hidden": "מוסתר" - }, - "Hidden (%1)": { - "Hidden (%1)": "מוסתר (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "אפליקציות מוסתרות" - }, - "Hidden Network": { - "Hidden Network": "רשת מוסתרת" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "אפליקציות מוסתרות לא יופיעו במשגר. לחץ/י לחיצה ימנית על האפליקציה ובחר/י 'הסתר/י אפליקציה' כדי להסתיר אותה." - }, - "Hide": { - "Hide": "הסתר/י" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "הסתר/י תוספים מצד שלישי" - }, - "Hide App": { - "Hide App": "הסתר/י אפליקציה" - }, - "Hide Delay": { - "Hide Delay": "עיכוב הסתרה" - }, - "Hide Indicators": { - "Hide Indicators": "הסתר/י מחוונים" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "הסתרת הווידג׳ט של מעדכן המערכת" - }, - "Hide When Typing": { - "Hide When Typing": "הסתרה בעת ההקלדה" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "הסתר/י כאשר חלונות נפתחים" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "הסתר/י את סמן העכבר אחרי חוסר פעילות (0 = מושבת)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "הסתר/י את סמן העכבר בעת לחיצה על מקשים במקלדת" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "הסתר/י את סמן העכבר בעת שימוש בקלט מגע" - }, - "Hide device": { - "Hide device": "הסתר/י התקן" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "הסתר/י את תוכן ההתראה עד להרחבה" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "הסתר/י את תוכן ההתראה עד להרחבה; חלונות קופצים מוצגים כמכווצים כברירת מחדל" - }, - "Hide on Touch": { - "Hide on Touch": "הסתר/י במגע" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "פלטת צבעים בנאמנות גבוהה המשמרת את גווני המקור." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "הדגש/י את האפליקציה הפעילה בסביבת העבודה" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "הדגש/י את האפליקציה הממוקדת כעת בתוך מחווני סביבת העבודה" - }, - "History": { - "History": "היסטוריה" - }, - "History Retention": { - "History Retention": "שמירת היסטוריה" - }, - "History Settings": { - "History Settings": "ההגדרות של היסטוריית ההתראות" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "ההיסטוריה נוקתה. %1 רשומות מוצמדות נשמרו." - }, - "Hold Duration": { - "Hold Duration": "משך הלחיצה" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "החזק/י לחוץ זמן רב יותר כדי לאשר" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "החזקה לאישור פעולות חשמל" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "החזק/י לחוץ לאישור (%1 מילישניות)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "החזק/י לחוץ כדי לאשר (%1 שניות)" - }, - "Home": { - "Home": "בית" - }, - "Host": { - "Host": "מארח" - }, - "Hostname": { - "Hostname": "שם מארח" - }, - "Hot Corners": { - "Hot Corners": "פינות חמות" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "כותרת קיצור דרך שתופיע בשכבה עליונה (אופציונלי)" - }, - "Hour": { - "Hour": "שעה" - }, - "Hourly": { - "Hourly": "שעתי" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "מספר תחזיות שעתיות" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "כל כמה זמן להחליף רקע" - }, - "How the background image is scaled": { - "How the background image is scaled": "כיצד תמונת הרקע מוצגת בקנה מידה" - }, - "Humidity": { - "Humidity": "לחות" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "שרת הDiscord של Hyprland" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "דריסות פריסה של Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "אפשרויות Hyprland" - }, - "Hyprland Website": { - "Hyprland Website": "האתר של Hyprland" - }, - "I Understand": { - "I Understand": "הבנתי" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "כתובת IP:" - }, - "IP address or hostname": { - "IP address or hostname": "כתובת IP או שם מארח" - }, - "ISO Date": { - "ISO Date": "תאריך ISO" - }, - "Icon": { - "Icon": "סמל" - }, - "Icon Scale": { - "Icon Scale": "קנה מידה לסמל" - }, - "Icon Size": { - "Icon Size": "גודל סמל" - }, - "Icon Size %": { - "Icon Size %": "גודל הסמל ב%" - }, - "Icon Theme": { - "Icon Theme": "ערכת נושא של סמלים" - }, - "Idle": { - "Idle": "בהמתנה" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "מונע ההמתנה" - }, - "Idle Settings": { - "Idle Settings": "הגדרות המתנה" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "ניטור המתנה אינו נתמך – נדרשת גרסת Quickshell חדשה יותר" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "אם השדה מוסתר, הוא יופיע ברגע שלוחצים על מקש." - }, - "Ignore Completely": { - "Ignore Completely": "התעלם/י לחלוטין" - }, - "Image": { - "Image": "תמונה" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "התמונה הועתקה ללוח ההעתקה" - }, - "Import": { - "Import": "ייבוא" - }, - "Import VPN": { - "Import VPN": "ייבוא VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "צבע למסך הלא פעיל" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "כלול/כללי מעברים" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "כלול/כללי פעולות לשולחן העבודה (קיצורי דרך) בתוצאות החיפוש." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "נטענו תוספים לא תואמים" - }, - "Incorrect password": { - "Incorrect password": "סיסמה שגויה" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "סיסמה שגויה - ניסיון %1 מתוך %2 (עלולה להתרחש נעילה)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "סיסמה שגויה - כשלונות נוספים עלולים לגרום לנעילת החשבון" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "סיסמה שגויה - נסה/י שנית" - }, - "Indicator Style": { - "Indicator Style": "סגנון מחוון" - }, - "Individual Batteries": { - "Individual Batteries": "סוללות נפרדות" - }, - "Individual bar configuration": { - "Individual bar configuration": "תצורת סרגל אישית" - }, - "Info": { - "Info": "מידע" - }, - "Inherit": { - "Inherit": "קבל/י בירושה" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "ירושה גלובלית (ברירת מחדל)" - }, - "Inhibitable": { - "Inhibitable": "ניתן לעיכוב" - }, - "Input Devices": { - "Input Devices": "התקני קלט" - }, - "Input Volume Slider": { - "Input Volume Slider": "מחוון עוצמת קלט" - }, - "Insert your security key...": { - "Insert your security key...": "הכנס/י את מפתח האבטחה שלך..." - }, - "Install": { - "Install": "התקן/י" - }, - "Install Greeter": { - "Install Greeter": "התקן/י את מסך ההתחברות" - }, - "Install Plugin": { - "Install Plugin": "התקן/י תוסף" - }, - "Install Theme": { - "Install Theme": "התקן/י ערכת נושא" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "התקן/י ערכות צבעים ממאגר ערכות הנושא של DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "ההתקנה הושלמה. מסך ההתחברות הותקן." - }, - "Install failed: %1": { - "Install failed: %1": "ההתקנה נכשלה: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "התקן/י את החבילה של matugen כדי לאפשר עיצוב דינמי" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "להתקין את התוסף '%1' מהמאגר של DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "התקן/י תוספים ממאגר התוספים של DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "להתקין את מסך ההתחברות של DMS? ייפתח מסוף לאימות עם sudo." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "להתקין את ערכת הנושא '%1' מהמאגר של DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "להתקנה והגדרה של PAM: ראה/י את " - }, - "Installed": { - "Installed": "מותקן" - }, - "Installed: %1": { - "Installed: %1": "הותקן: %1" - }, - "Installing: %1": { - "Installing: %1": "מתקין: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "הסתרה אוטומטית חכמה" - }, - "Intensity": { - "Intensity": "עוצמה" - }, - "Interface:": { - "Interface:": "ממשק:" - }, - "Interlock Open": { - "Interlock Open": "מנגנון נעילה פתוח" - }, - "Internet": { - "Internet": "אינטרנט" - }, - "Interval": { - "Interval": "מרווח זמן" - }, - "Invalid configuration": { - "Invalid configuration": "הגדרה לא חוקית" - }, - "Invert on mode change": { - "Invert on mode change": "היפוך בעת שינוי מצב" - }, - "Iris Bloom": { - "Iris Bloom": "פריחת האיריס" - }, - "Isolate Displays": { - "Isolate Displays": "בידוד מסכים" - }, - "Jobs": { - "Jobs": "עבודות" - }, - "Jobs: ": { - "Jobs: ": "עבודות: " - }, - "Keep Awake": { - "Keep Awake": "מניעת שינה" - }, - "Keep Changes": { - "Keep Changes": "שמור/י שינויים" - }, - "Keeping Awake": { - "Keeping Awake": "משאיר ער" - }, - "Kernel": { - "Kernel": "ליבה" - }, - "Key": { - "Key": "מקש" - }, - "Keybind Sources": { - "Keybind Sources": "מקורות של קיצורי מקלדת" - }, - "Keybinds": { - "Keybinds": "קיצורי מקלדת" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "הגדרות חיפוש של קיצורי מקלדת" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "קיצורי מקלדת מוצגים לצד תוצאות חיפוש רגילות" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "שם פריסת המקלדת" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "קיצורי מקלדת" - }, - "Keys": { - "Keys": "מקשים" - }, - "Kill": { - "Kill": "סיום" - }, - "Kill Process": { - "Kill Process": "סיים/י תהליך" - }, - "Kill Session": { - "Kill Session": "סיום הפעלה" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "התקן LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "ערוץ הIRC של LabWC" - }, - "LabWC Website": { - "LabWC Website": "האתר של LabWC" - }, - "Large": { - "Large": "גדול" - }, - "Largest": { - "Largest": "הכי גדול" - }, - "Last hour": { - "Last hour": "בשעה האחרונה" - }, - "Last launched %1": { - "Last launched %1": "ההפעלה האחרונה הייתה %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "ההפעלה האחרונה הייתה לפני יום %1" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "ההפעלה האחרונה הייתה לפני %1 ימים" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "ההפעלה האחרונה הייתה לפני שעה %1" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "ההפעלה האחרונה הייתה לפני %1 שעות" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "ההפעלה האחרונה הייתה לפני דקה %1" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "ההפעלה האחרונה הייתה לפני %1 דקות" - }, - "Last launched just now": { - "Last launched just now": "ההפעלה האחרונה הייתה ממש עכשיו" - }, - "Latitude": { - "Latitude": "קו רוחב" - }, - "Launch": { - "Launch": "הפעל/י" - }, - "Launch Prefix": { - "Launch Prefix": "קידומת הפעלה" - }, - "Launch on dGPU": { - "Launch on dGPU": "הפעל/י על dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "הפעל/י על הdGPU כברירת מחדל" - }, - "Launcher": { - "Launcher": "משגר" - }, - "Launcher Button": { - "Launcher Button": "כפתור המשגר" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "סמל כפתור המשגר" - }, - "Layout": { - "Layout": "פריסה" - }, - "Layout Overrides": { - "Layout Overrides": "דריסות פריסה" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "פריסה ומיקומי מודולים במסך ההתחברות מסונכרנים מהמעטפת שלך (לדוגמה, הגדרות הסרגל). הרץ/י סנכרון כדי להחיל." - }, - "Left": { - "Left": "שמאל" - }, - "Left Center": { - "Left Center": "צד שמאל במרכז" - }, - "Left Section": { - "Left Section": "קטע שמאלי" - }, - "Light Direction": { - "Light Direction": "כיוון האור" - }, - "Light Mode": { - "Light Mode": "מצב בהיר" - }, - "Light Rain": { - "Light Rain": "גשם קל" - }, - "Light Snow": { - "Light Snow": "שלג קל" - }, - "Light Snow Showers": { - "Light Snow Showers": "מקלחות שלג קלות" - }, - "Light mode base": { - "Light mode base": "בסיס למצב בהיר" - }, - "Light mode harmony": { - "Light mode harmony": "הרמוניה במצב בהיר" - }, - "Line": { - "Line": "קו" - }, - "Line: %1": { - "Line: %1": "שורה: %1" - }, - "Linear": { - "Linear": "ליניארי" - }, - "Lines: %1": { - "Lines: %1": "שורות: %1" - }, - "List": { - "List": "רשימה" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "פלטת צבעים תוססת עם דגשים רוויים." - }, - "Load Average": { - "Load Average": "עומס ממוצע" - }, - "Loading codecs...": { - "Loading codecs...": "טוען קודקים..." - }, - "Loading keybinds...": { - "Loading keybinds...": "טוען קיצורי מקלדת..." - }, - "Loading trending...": { - "Loading trending...": "טוען טרנדים..." - }, - "Loading...": { - "Loading...": "טוען..." - }, - "Local": { - "Local": "מקומי" - }, - "Locale": { - "Locale": "שפה ואזור" - }, - "Locale Settings": { - "Locale Settings": "הגדרות אזוריות" - }, - "Location": { - "Location": "מיקום" - }, - "Location Search": { - "Location Search": "חיפוש מיקום" - }, - "Lock": { - "Lock": "נעילה" - }, - "Lock Screen": { - "Lock Screen": "מסך הנעילה" - }, - "Lock Screen Display": { - "Lock Screen Display": "תצוגת מסך הנעילה" - }, - "Lock Screen Format": { - "Lock Screen Format": "תבנית מסך הנעילה" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "התנהגות מסך הנעילה" - }, - "Lock Screen layout": { - "Lock Screen layout": "פריסת מסך הנעילה" - }, - "Lock at startup": { - "Lock at startup": "נעילה בעת ההפעלה" - }, - "Lock before suspend": { - "Lock before suspend": "נעל/י לפני השהיה" - }, - "Lock fade grace period": { - "Lock fade grace period": "תקופת חסד לדהייה של מסך הנעילה" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "שינויי אימות למסך הנעילה מוחלים באופן אוטומטי ועשויים לפתוח מסוף כאשר נדרש אימות עם sudo." - }, - "Locked": { - "Locked": "נעול" - }, - "Log Out": { - "Log Out": "התנתקות" - }, - "Logging in...": { - "Logging in...": "מתחבר..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "הזדהות בכניסה" - }, - "Long": { - "Long": "ארוך" - }, - "Long Text": { - "Long Text": "טקסט ארוך" - }, - "Long press": { - "Long press": "לחיצה ארוכה" - }, - "Longitude": { - "Longitude": "קו אורך" - }, - "Low Priority": { - "Low Priority": "עדיפות נמוכה" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "ודא/י ש-KDE Connect או Valent פועל על ההתקנים האחרים שלך" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "נהל/י והגדר/י תוספים להרחבת היכולות של DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "נהל/י עד 4 תצורות סרגל עצמאיות. לכל סרגל יש מיקום, ווידג׳טים, סגנון והקצאת תצוגה משלו." - }, - "Management": { - "Management": "ניהול" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "דריסות פריסה של MangoWC" - }, - "Manual": { - "Manual": "ידני" - }, - "Manual Coordinates": { - "Manual Coordinates": "קואורדינטות ידניות" - }, - "Manual Direction": { - "Manual Direction": "כיוון ידני" - }, - "Manual Gap Size": { - "Manual Gap Size": "גודל מרווח ידני" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "הצגה/הסתרה ידנית" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "מפה/י שמות של סוגי חלונות לשמות של סמלים כדי לוודא שהסמלים מוצגים כראוי" - }, - "Margin": { - "Margin": "שוליים" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "אספקת צבע/טונר ריקה" - }, - "Marker Supply Low": { - "Marker Supply Low": "אספקת צבע/טונר נמוכה" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "מיכל העודפים כמעט מלא" - }, - "Marker Waste Full": { - "Marker Waste Full": "מיכל העודפים מלא" - }, - "Match Criteria": { - "Match Criteria": "קריטריוני התאמה" - }, - "Matches profile: %1": { - "Matches profile: %1": "תואם לפרופיל: %1" - }, - "Material Colors": { - "Material Colors": "צבעי Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "ערכות צבעים בהשראת Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "צבעי Material שנוצרו מהרקע" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "הצללות והגבהה בהשראת Material Design על חלוניות, חלונות קופצים ותיבות דו-שיח" - }, - "Matugen Contrast": { - "Matugen Contrast": "ניגודיות Matugen" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen חסר" - }, - "Matugen Palette": { - "Matugen Palette": "פלטת צבעים של Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "מסך יעד עבור Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "תבניות Matugen" - }, - "Max Edges": { - "Max Edges": "קצוות מקסימליים" - }, - "Max H": { - "Max H": "גובה מקסימלי" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "מקסימום אפליקציות מוצמדות" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "מקסימום אפליקציות מוצמדות (0 = ללא הגבלה)" - }, - "Max Running Apps": { - "Max Running Apps": "מקסימום אפליקציות פועלות" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "מקסימום אפליקציות פועלות (0 = ללא הגבלה)" - }, - "Max Volume": { - "Max Volume": "עוצמה מקסימלית" - }, - "Max W": { - "Max W": "רוחב מקסימלי" - }, - "Max apps to show": { - "Max apps to show": "מספר מקסימלי של אפליקציות להצגה" - }, - "Max to Edges": { - "Max to Edges": "מקסום לקצוות" - }, - "Maximize": { - "Maximize": "ממוקסם" - }, - "Maximize Detection": { - "Maximize Detection": "זיהוי הגדלה של החלון" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "הגדלת סמלי הווידג׳טים למקסימום" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "הגדלת טקסט הווידג׳טים למקסימום" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "גודל רשומה מקסימלי" - }, - "Maximum History": { - "Maximum History": "היסטוריה מקסימלית" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "מקסימום רשומות מוצמדות" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "הגעת למספר המרבי של ניסיונות לטביעת אצבע. נא להשתמש בסיסמה." - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "מספר מקסימלי של רשומות לוח ההעתקה לשמירה" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "מספר מקסימלי של רשומות שניתן לשמור" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "מספר מקסימלי של התראות לשמירה" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "הושג מקסימום רשומות מוצמדות" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "גודל מקסימלי לרשומת לוח ההעתקה" - }, - "Media": { - "Media": "מדיה" - }, - "Media Controls": { - "Media Controls": "פקדי מדיה" - }, - "Media Empty": { - "Media Empty": "אין נייר/מדיה" - }, - "Media Jam": { - "Media Jam": "תקיעת נייר/מדיה" - }, - "Media Low": { - "Media Low": "מפלס נייר/מדיה נמוך" - }, - "Media Needed": { - "Media Needed": "נדרש נייר/מדיה" - }, - "Media Playback": { - "Media Playback": "השמעת מדיה" - }, - "Media Player": { - "Media Player": "נגן מדיה" - }, - "Media Player Settings": { - "Media Player Settings": "הגדרות נגן המדיה" - }, - "Media Players": { - "Media Players": "נגני מדיה" - }, - "Media Players (": { - "Media Players (": "נגני מדיה (" - }, - "Media Volume": { - "Media Volume": "עוצמת מדיה" - }, - "Medium": { - "Medium": "בינוני" - }, - "Memory": { - "Memory": "זיכרון" - }, - "Memory Graph": { - "Memory Graph": "גרף לזיכרון" - }, - "Memory Usage": { - "Memory Usage": "שימוש בזיכרון" - }, - "Memory usage indicator": { - "Memory usage indicator": "מחוון שימוש בזיכרון" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "הודעה" - }, - "Message Content": { - "Message Content": "תוכן ההתראה" - }, - "Microphone": { - "Microphone": "מיקרופון" - }, - "Microphone Mute": { - "Microphone Mute": "השתקת מיקרופון" - }, - "Microphone Volume": { - "Microphone Volume": "עוצמת מיקרופון" - }, - "Microphone settings": { - "Microphone settings": "הגדרות מיקרופון" - }, - "Microphone volume control": { - "Microphone volume control": "בקרת עוצמת מיקרופון" - }, - "Middle Section": { - "Middle Section": "קטע אמצעי" - }, - "Min H": { - "Min H": "גובה מינימלי" - }, - "Min W": { - "Min W": "רוחב מינימלי" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "פלטת צבעים מינימלית הבנויה סביב גוון יחיד." - }, - "Minute": { - "Minute": "דקה" - }, - "Mirror Display": { - "Mirror Display": "שיקוף תצוגה" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "משתני סביבה חסרים" - }, - "Modal Background": { - "Modal Background": "רקע מודל" - }, - "Modal Shadows": { - "Modal Shadows": "הצללות של מודלים" - }, - "Modals": { - "Modals": "חלונות מודליים" - }, - "Mode": { - "Mode": "מצב" - }, - "Mode:": { - "Mode:": "מצב:" - }, - "Model": { - "Model": "דגם" - }, - "Modified": { - "Modified": "שונה" - }, - "Modular widget bar": { - "Modular widget bar": "פס ווידג׳טים מודולרי" - }, - "Monitor": { - "Monitor": "מסך" - }, - "Monitor Configuration": { - "Monitor Configuration": "הגדרת מסך" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "תקופת חסד לדהיית התצוגה" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "המסך שהרקע שלו קובע את צבעי ערכת הנושא הדינמית" - }, - "Monochrome": { - "Monochrome": "מונוכרומטי" - }, - "Monocle": { - "Monocle": "מונוקל (יחיד)" - }, - "Monospace Font": { - "Monospace Font": "גופן ברוחב קבוע" - }, - "Month Date": { - "Month Date": "חודש תאריך" - }, - "Morning": { - "Morning": "בוקר" - }, - "Mount Points": { - "Mount Points": "נקודות עגינה" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "מראה של סמן העכבר" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "גודל סמן העכבר בפיקסלים" - }, - "Move": { - "Move": "הזז/י" - }, - "Move Widget": { - "Move Widget": "הזזת הווידג׳ט" - }, - "Moving to Paused": { - "Moving to Paused": "עובר להשהיה" - }, - "Multi-Monitor": { - "Multi-Monitor": "ריבוי מסכים" - }, - "Multiplexer": { - "Multiplexer": "מרבב" - }, - "Multiplexer Type": { - "Multiplexer Type": "סוג המרבב" - }, - "Multiplexers": { - "Multiplexers": "מרבבי מסוף" - }, - "Music": { - "Music": "מוסיקה" - }, - "Mute Popups": { - "Mute Popups": "השתק/י חלונות קופצים" - }, - "Mute popups for %1": { - "Mute popups for %1": "השתק/י חלונות קופצים עבור %1" - }, - "Muted": { - "Muted": "מושתק" - }, - "Muted Apps": { - "Muted Apps": "אפליקציות מושתקות" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "פלטת צבעים מעודנת עם גוונים רגועים ושקטים." - }, - "NM not supported": { - "NM not supported": "NM אינו נתמך" - }, - "Name": { - "Name": "שם" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "סמלים לסביבות עבודה בעלות שם" - }, - "Navigate": { - "Navigate": "ניווט" - }, - "Navigation": { - "Navigation": "ניווט" - }, - "Network": { - "Network": "רשת" - }, - "Network Graph": { - "Network Graph": "גרף לרשת" - }, - "Network Info": { - "Network Info": "מידע רשת" - }, - "Network Information": { - "Network Information": "מידע רשת מפורט" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "שם הרשת (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "מנטר מהירות רשת" - }, - "Network Status": { - "Network Status": "מצב רשת" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "תצוגת מהירות הורדה והעלאה ברשת" - }, - "Neutral": { - "Neutral": "נייטרלי" - }, - "Never": { - "Never": "לעולם לא" - }, - "Never used": { - "Never used": "לא היה בשימוש מעולם" - }, - "New": { - "New": "חדש" - }, - "New Key": { - "New Key": "מקש חדש" - }, - "New Keybind": { - "New Keybind": "קיצור מקלדת חדש" - }, - "New Notification": { - "New Notification": "התראה חדשה" - }, - "New Session": { - "New Session": "הפעלה חדשה" - }, - "New Window Rule": { - "New Window Rule": "חוק חלון חדש" - }, - "New York, NY": { - "New York, NY": "ניו יורק, ניו יורק" - }, - "New group name...": { - "New group name...": "שם לקבוצה החדשה..." - }, - "Next": { - "Next": "הבא" - }, - "Next Transition": { - "Next Transition": "המעבר הבא" - }, - "Night": { - "Night": "לילה" - }, - "Night Mode": { - "Night Mode": "מצב לילה" - }, - "Night Temperature": { - "Night Temperature": "טמפרטורת לילה" - }, - "Night mode & gamma": { - "Night mode & gamma": "מצב לילה וגאמה" - }, - "Niri Integration": { - "Niri Integration": "אינטגרציה עם Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "דריסות פריסה של Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "פעולות קומפוזיטור של Niri (מיקוד, הזזה וכו')" - }, - "No": { - "No": "לא" - }, - "No Active Players": { - "No Active Players": "אין נגנים פעילים" - }, - "No Anim": { - "No Anim": "ללא אנימציה" - }, - "No Background": { - "No Background": "ללא רקע" - }, - "No Battery": { - "No Battery": "אין סוללה" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "לא נמצא מתאם Bluetooth" - }, - "No Blur": { - "No Blur": "ללא טשטוש" - }, - "No Border": { - "No Border": "ללא מסגרת" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "לא הוגדרו קיצורי DMS" - }, - "No Dim": { - "No Dim": "ללא עמעום" - }, - "No Focus": { - "No Focus": "ללא מיקוד" - }, - "No GPU detected": { - "No GPU detected": "לא זוהה GPU" - }, - "No GPUs detected": { - "No GPUs detected": "לא זוהו GPUs" - }, - "No History": { - "No History": "ללא היסטוריה" - }, - "No Media": { - "No Media": "אין מדיה" - }, - "No Round": { - "No Round": "ללא עיגול" - }, - "No Rounding": { - "No Rounding": "ללא עיגול" - }, - "No Shadow": { - "No Shadow": "ללא צל" - }, - "No VPN profiles": { - "No VPN profiles": "אין פרופילי VPN" - }, - "No Weather": { - "No Weather": "אין מזג אוויר" - }, - "No Weather Data": { - "No Weather Data": "אין נתוני מזג אוויר" - }, - "No Weather Data Available": { - "No Weather Data Available": "אין נתוני מזג אוויר זמינים" - }, - "No action": { - "No action": "אין פעולה" - }, - "No active %1 sessions": { - "No active %1 sessions": "אין הפעלות פעילות של %1" - }, - "No adapter": { - "No adapter": "אין מתאם" - }, - "No adapters": { - "No adapters": "אין מתאמים" - }, - "No app customizations.": { - "No app customizations.": "אין התאמות אישיות לאפליקציות." - }, - "No apps found": { - "No apps found": "לא נמצאו אפליקציות" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "עדיין לא הופעלו אפליקציות." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "אין אפליקציות מושתקות. לחץ/י לחיצה ימנית על התראה ובחר/י ב\"השתק/י חלונות קופצים\" להוספה לכאן." - }, - "No battery": { - "No battery": "אין סוללה" - }, - "No brightness devices available": { - "No brightness devices available": "אין התקני בהירות זמינים" - }, - "No changes": { - "No changes": "אין שינויים" - }, - "No checks passed": { - "No checks passed": "אף בדיקה לא עברה" - }, - "No custom theme file": { - "No custom theme file": "אין קובץ ערכת נושא מותאמת אישית" - }, - "No devices": { - "No devices": "אין התקנים" - }, - "No devices connected": { - "No devices connected": "אין התקנים מחוברים" - }, - "No devices found": { - "No devices found": "לא נמצאו התקנים" - }, - "No disk data": { - "No disk data": "אין נתוני דיסק" - }, - "No disk data available": { - "No disk data available": "אין נתוני דיסק זמינים" - }, - "No drivers found": { - "No drivers found": "לא נמצאו מנהלי התקן" - }, - "No errors": { - "No errors": "אין שגיאות" - }, - "No features enabled": { - "No features enabled": "אין תכונות מופעלות" - }, - "No files found": { - "No files found": "לא נמצאו קבצים" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "לא זוהה קורא טביעות אצבע." - }, - "No folders found": { - "No folders found": "לא נמצאו תיקיות" - }, - "No hidden apps.": { - "No hidden apps.": "אין אפליקציות מוסתרות." - }, - "No info items": { - "No info items": "אין פריטי מידע" - }, - "No information available": { - "No information available": "אין מידע זמין" - }, - "No input device": { - "No input device": "אין התקן קלט" - }, - "No input devices found": { - "No input devices found": "לא נמצאו התקני קלט" - }, - "No items added yet": { - "No items added yet": "לא נוספו פריטים עדיין" - }, - "No keybinds found": { - "No keybinds found": "לא נמצאו קיצורי מקלדת" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "אין תוספי משגר מותקנים." - }, - "No match criteria": { - "No match criteria": "אין קריטריוני התאמה" - }, - "No matches": { - "No matches": "אין התאמות" - }, - "No matching processes": { - "No matching processes": "אין תהליכים תואמים" - }, - "No monitors": { - "No monitors": "אין מסכים" - }, - "No mount points found": { - "No mount points found": "לא נמצאו נקודות עגינה" - }, - "No output device": { - "No output device": "אין התקן פלט" - }, - "No output devices found": { - "No output devices found": "לא נמצאו התקני פלט" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "לא נמצא מנהל חבילות. אנא התקן/י את 'paru' או 'yay' כדי לבדוק עדכונים במערכות מבוססות Arch." - }, - "No plugin results": { - "No plugin results": "לא נמצאו תוספים" - }, - "No plugins found": { - "No plugins found": "לא נמצאו תוספים" - }, - "No plugins found.": { - "No plugins found.": "לא נמצאו תוספים." - }, - "No printer found": { - "No printer found": "לא נמצאה מדפסת" - }, - "No printers configured": { - "No printers configured": "לא הוגדרו מדפסות" - }, - "No printers found": { - "No printers found": "לא נמצאו מדפסות" - }, - "No profiles": { - "No profiles": "אין פרופילים" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "לא נמצאו רשומות לוח ההעתקה אחרונות" - }, - "No results found": { - "No results found": "לא נמצאו תוצאות" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "אין רשומות לוח ההעתקה שמורות" - }, - "No sessions found": { - "No sessions found": "לא נמצאו הפעלות" - }, - "No status output.": { - "No status output.": "לא התקבל פלט לעדכון המצב." - }, - "No themes found": { - "No themes found": "לא נמצאו ערכות נושא" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "אין ערכות נושא מותקנות. עיין/י בערכות נושא להתקנה מהמאגר." - }, - "No trigger": { - "No trigger": "אין מפעיל" - }, - "No video found in folder": { - "No video found in folder": "לא נמצא וידאו בתיקייה" - }, - "No wallpaper selected": { - "No wallpaper selected": "לא נבחר רקע" - }, - "No wallpapers": { - "No wallpapers": "אין תמונות רקע" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "לא נמצאו רקעים\n\nלחץ/י על סמל התיקייה למטה כדי לעיין" - }, - "No warnings": { - "No warnings": "אין אזהרות" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "לא נוספו ווידג'טים. לחץ/י על \"הוסף ווידג'ט\" כדי להתחיל." - }, - "No widgets available": { - "No widgets available": "אין ווידג׳טים זמינים" - }, - "No widgets match your search": { - "No widgets match your search": "אין ווידג׳טים שתואמים לחיפוש שלך" - }, - "No window rules configured": { - "No window rules configured": "לא הוגדרו חוקי חלון" - }, - "None": { - "None": "ללא" - }, - "Normal": { - "Normal": "רגיל" - }, - "Normal Font": { - "Normal Font": "גופן רגיל" - }, - "Normal Priority": { - "Normal Priority": "עדיפות רגילה" - }, - "Not available": { - "Not available": "לא זמינה" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "לא זמין — התקן/י את החבילות fprintd ו pam_fprintd, או הגדר/י את greetd PAM." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "לא זמין — התקן/י את fprintd ו pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "לא זמין — התקן/י או הגדר/י את pam_u2f, או לחלופין הגדר/י את greetd PAM." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "לא זמין — התקן/י או הגדר/י את pam_u2f." - }, - "Not connected": { - "Not connected": "לא מחובר" - }, - "Not detected": { - "Not detected": "לא זוהה" - }, - "Not paired": { - "Not paired": "לא מוצמד" - }, - "Not set": { - "Not set": "לא מוגדר" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "הערה: זה רק משנה את האחוזים, זה לא באמת מגביל את הטעינה." - }, - "Notepad": { - "Notepad": "פנקס" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "הגדרות גופן של הפנקס" - }, - "Notepad Slideout": { - "Notepad Slideout": "החלקה של הפנקס" - }, - "Nothing": { - "Nothing": "כלום" - }, - "Nothing to see here": { - "Nothing to see here": "אין מה לראות כאן" - }, - "Notification Center": { - "Notification Center": "מרכז ההתראות" - }, - "Notification Display": { - "Notification Display": "תצוגת התראות" - }, - "Notification Overlay": { - "Notification Overlay": "שכבת התראות" - }, - "Notification Popups": { - "Notification Popups": "חלוניות התראה קופצות" - }, - "Notification Rules": { - "Notification Rules": "חוקי התראות" - }, - "Notification Settings": { - "Notification Settings": "הגדרות התראות" - }, - "Notification Timeouts": { - "Notification Timeouts": "הקצבת זמן להתראות" - }, - "Notification toast popups": { - "Notification toast popups": "התראות קופצות" - }, - "Notifications": { - "Notifications": "התראות" - }, - "Numbers": { - "Numbers": "מספרים" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "מספרי (D/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "מספרי (M/D)" - }, - "OK": { - "OK": "תקין" - }, - "OS Logo": { - "OS Logo": "לוגו מערכת ההפעלה" - }, - "OSD Position": { - "OSD Position": "מיקום OSD" - }, - "Occupied Color": { - "Occupied Color": "צבע למצב ״תפוס״" - }, - "Off": { - "Off": "כבוי" - }, - "Office": { - "Office": "משרד" - }, - "Offline": { - "Offline": "לא מקוון" - }, - "Offline Report": { - "Offline Report": "דו\"ח לא מקוון" - }, - "Older": { - "Older": "ישן יותר" - }, - "On": { - "On": "פועל" - }, - "On-Demand": { - "On-Demand": "לפי דרישה" - }, - "On-Screen Displays": { - "On-Screen Displays": "תצוגות על המסך" - }, - "On-screen Displays": { - "On-screen Displays": "תצוגות על המסך (OSD)" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "כוונן/י את הגאמה רק לפי כללי זמן או מיקום." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "משפיע רק על PAM המנוהל על ידי DMS. אם greetd כבר כולל את pam_fprintd, טביעת האצבע תישאר מופעלת." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "הצג/י רק חלונות מהמסך הנוכחי בכל Dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "גלוי רק אם מצב שינה עמוקה נתמך במערכת שלך" - }, - "Opacity": { - "Opacity": "שקיפות" - }, - "Opaque": { - "Opaque": "אטום" - }, - "Open": { - "Open": "פתח/י" - }, - "Open App": { - "Open App": "פתח/י אפליקציה" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "פתח/י את KDE Connect בטלפון שלך" - }, - "Open Notepad File": { - "Open Notepad File": "פתח/י קובץ בפנקס" - }, - "Open a new note": { - "Open a new note": "פתח/י פתק חדש" - }, - "Open folder": { - "Open folder": "פתח/י תיקייה" - }, - "Open in Browser": { - "Open in Browser": "פתח/י בדפדפן" - }, - "Open in terminal": { - "Open in terminal": "פתח/י במסוף" - }, - "Open search bar to find text": { - "Open search bar to find text": "פתח/י שורת חיפוש כדי למצוא טקסט" - }, - "Open with...": { - "Open with...": "פתח/י עם..." - }, - "Opening SMS": { - "Opening SMS": "פותח SMS" - }, - "Opening SMS app": { - "Opening SMS app": "פותח את אפליקציית הSMS" - }, - "Opening file browser": { - "Opening file browser": "פותח דפדפן קבצים" - }, - "Opening files": { - "Opening files": "פותח קבצים" - }, - "Opening terminal: ": { - "Opening terminal: ": "פותח מסוף: " - }, - "Optional description": { - "Optional description": "תיאור אופציונלי" - }, - "Optional location": { - "Optional location": "מיקום אופציונלי" - }, - "Options": { - "Options": "אפשרויות" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "ארגן/י ווידג׳טים בקבוצות שניתן לצמצם" - }, - "Original: %1": { - "Original: %1": "מקורי: %1" - }, - "Other": { - "Other": "אחר" - }, - "Outline": { - "Outline": "מתאר" - }, - "Output": { - "Output": "פלט" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "אזור הפלט כמעט מלא" - }, - "Output Area Full": { - "Output Area Full": "אזור הפלט מלא" - }, - "Output Device": { - "Output Device": "התקן פלט" - }, - "Output Devices": { - "Output Devices": "התקני פלט" - }, - "Output Tray Missing": { - "Output Tray Missing": "מגש הפלט חסר" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "קובץ includes של פלטי תצוגה חסר" - }, - "Overcast": { - "Overcast": "מעונן" - }, - "Overflow": { - "Overflow": "גלישה" - }, - "Overridden by config": { - "Overridden by config": "נדרס על ידי config" - }, - "Override": { - "Override": "דריסה" - }, - "Override Border Size": { - "Override Border Size": "דריסת גודל המסגרת" - }, - "Override Corner Radius": { - "Override Corner Radius": "דריסת רדיוס הפינות" - }, - "Override Gaps": { - "Override Gaps": "דריסת רווחים" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "דרוס/י הגדרות פריסה גלובליות לפלט זה" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "דרוס/דרסי את המסוף עם פקודה או תסריט מותאמים אישית" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "דרוס/י את הצל הגלובלי עם הגדרות לכל סרגל בנפרד" - }, - "Overrides": { - "Overrides": "דריסות" - }, - "Overview": { - "Overview": "סקירה כללית" - }, - "Overview of your network connections": { - "Overview of your network connections": "סקירה של חיבורי הרשת שלך" - }, - "Overwrite": { - "Overwrite": "דריסה" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM כבר מספק אימות באמצעות טביעת אצבע. הפעל/י את ההזדהות כדי להציג אותה בכניסה." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM כבר מספק אימות באמצעות מפתח אבטחה. הפעל/י את ההזדהות כדי להציג אותה בכניסה." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM מספק אימות באמצעות טביעת אצבע, אך לא ניתן היה לאמת את הזמינות." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM מספק אימות באמצעות טביעת אצבע, אך אין טביעות אצבע רשומות עדיין." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM מספק אימות באמצעות טביעת אצבע, אך לא זוהה קורא טביעות אצבע." - }, - "PIN": { - "PIN": "קוד PIN" - }, - "Pad": { - "Pad": "ריפוד" - }, - "Pad Hours": { - "Pad Hours": "ריפוד שעות" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "ריפוד שעות (02:00 לעומת 2:00)" - }, - "Padding": { - "Padding": "ריווח פנימי" - }, - "Pair": { - "Pair": "צימוד" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "צמד/י התקן Bluetooth" - }, - "Paired": { - "Paired": "מותאם" - }, - "Pairing": { - "Pairing": "צימוד בתהליך" - }, - "Pairing failed": { - "Pairing failed": "הצימוד נכשל" - }, - "Pairing request from": { - "Pairing request from": "בקשת צימוד מ" - }, - "Pairing request sent": { - "Pairing request sent": "בקשת צימוד נשלחה" - }, - "Pairing requested": { - "Pairing requested": "התבקש צימוד" - }, - "Pairing...": { - "Pairing...": "מתאים..." - }, - "Partly Cloudy": { - "Partly Cloudy": "מעונן חלקית" - }, - "Passkey:": { - "Passkey:": "מפתח גישה:" - }, - "Password": { - "Password": "סיסמה" - }, - "Password...": { - "Password...": "סיסמה..." - }, - "Paste": { - "Paste": "הדבק/י" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "נתיב לקובץ וידאו או תיקייה המכילה סרטוני וידאו" - }, - "Pattern": { - "Pattern": "תבנית" - }, - "Pause": { - "Pause": "השהיה" - }, - "Paused": { - "Paused": "מושהה" - }, - "Pending": { - "Pending": "ממתין" - }, - "Pending Charge": { - "Pending Charge": "טעינה ממתינה" - }, - "Pending Discharge": { - "Pending Discharge": "ריקון ממתין" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "רקעים לפי מצב" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "רקעים לפי מסך" - }, - "Per-screen config": { - "Per-screen config": "הגדרה לכל מסך" - }, - "Percentage": { - "Percentage": "אחוזים" - }, - "Performance": { - "Performance": "ביצועים" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "ההרשאה להגדרת תמונת הפרופיל נדחתה." - }, - "Personalization": { - "Personalization": "התאמה אישית" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect לא זמין" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Phone Connect לא זמין" - }, - "Phone number": { - "Phone number": "מספר טלפון" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "בחר/י סרטון וידאו אקראי שונה בכל פעם מאותה תיקייה" - }, - "Pictures": { - "Pictures": "תמונות" - }, - "Pin": { - "Pin": "הצמד/י" - }, - "Pin to Dock": { - "Pin to Dock": "נעץ/י בDock" - }, - "Ping": { - "Ping": "פינג" - }, - "Ping sent": { - "Ping sent": "פינג נשלח" - }, - "Ping sent to": { - "Ping sent to": "פינג נשלח ל" - }, - "Pinned": { - "Pinned": "מוצמד" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "אפליקציות מוצמדות ופועלים עם גרירה ושחרור" - }, - "Pixelate": { - "Pixelate": "פיקסול" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "מקם/י כאן את תיקיות התוספים. לכל תוסף צריך להיות קובץ מניפסט בשם plugin.json." - }, - "Place plugins in %1": { - "Place plugins in %1": "מקם/י תוספים ב-%1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "נגן/י וידאו כאשר המסך ננעל." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "ניגון צליל כשהתראה חדשה מגיעה" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "ניגון צליל בעת חיבור כבל החשמל" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "ניגון צליל בעת שינוי עוצמת השמע" - }, - "Play sounds for system events": { - "Play sounds for system events": "ניגון צלילים לאירועי מערכת" - }, - "Playback": { - "Playback": "השמעה" - }, - "Playback error: ": { - "Playback error: ": "שגיאת השמעה: " - }, - "Please wait...": { - "Please wait...": "אנא המתן/י..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "אנא כתוב/כתבי שם להפעלת %1 החדשה שלך" - }, - "Plugged In": { - "Plugged In": "מחובר לחשמל" - }, - "Plugged in": { - "Plugged in": "מחובר לחשמל" - }, - "Plugin": { - "Plugin": "תוסף" - }, - "Plugin Directory": { - "Plugin Directory": "תיקיית תוספים" - }, - "Plugin Management": { - "Plugin Management": "ניהול תוספים" - }, - "Plugin Visibility": { - "Plugin Visibility": "נראות תוסף" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "התוסף מושבת – הפעל/י אותו בהגדרות התוספים כדי להשתמש בו" - }, - "Plugins": { - "Plugins": "תוספים" - }, - "Pointer": { - "Pointer": "מצביע" - }, - "Popout Shadows": { - "Popout Shadows": "הצללות של חלונות קופצים" - }, - "Popouts": { - "Popouts": "חלונות קופצים" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "חלונות קופצים ומודליים עוקבים אחר מהירות האנימציה הגלובלית (השבת/י כדי להתאים אישית באופן עצמאי)" - }, - "Popup Only": { - "Popup Only": "חלון קופץ בלבד" - }, - "Popup Position": { - "Popup Position": "מיקום חלונית קופצת" - }, - "Popup Shadow": { - "Popup Shadow": "צל לחלון קופץ" - }, - "Popup Transparency": { - "Popup Transparency": "שקיפות חלונית קופצת" - }, - "Popup behavior, position": { - "Popup behavior, position": "התנהגות ומיקום חלונות קופצים" - }, - "Port": { - "Port": "פורט" - }, - "Portal": { - "Portal": "פורטל" - }, - "Position": { - "Position": "מיקום" - }, - "Position, pinned apps": { - "Position, pinned apps": "מיקום, אפליקציות מוצמדות" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "קונפליקטים אפשריים של דריסה" - }, - "Power": { - "Power": "חשמל" - }, - "Power & Security": { - "Power & Security": "חשמל ואבטחה" - }, - "Power & Sleep": { - "Power & Sleep": "חשמל ושינה" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "אישור פעולות חשמל" - }, - "Power Menu Customization": { - "Power Menu Customization": "התאמה אישית של תפריט הכיבוי" - }, - "Power Off": { - "Power Off": "כיבוי" - }, - "Power Options": { - "Power Options": "אפשרויות חשמל" - }, - "Power Profile": { - "Power Profile": "פרופיל חשמל" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "ירידת ביצועים בפרופיל צריכת החשמל" - }, - "Power Saver": { - "Power Saver": "חיסכון בחשמל" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "כיבוי מסכים בנעילה" - }, - "Power profile management available": { - "Power profile management available": "ניהול פרופיל חשמל זמין" - }, - "Power source": { - "Power source": "מקור חשמל" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "מלא/י מראש את שם המשתמש האחרון שהתחבר בהצלחה במסך ההתחברות" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "בחר/י מראש את ההפעלה האחרונה שהייתה בשימוש במסך ההתחברות" - }, - "Precip": { - "Precip": "משקעים" - }, - "Precipitation": { - "Precipitation": "משקעים" - }, - "Precipitation Chance": { - "Precipitation Chance": "סיכוי למשקעים" - }, - "Preference": { - "Preference": "העדפה" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "רוחבים מוגדרים מראש (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "לחץ/י על 'n' במקלדת או על הכפתור 'הפעלה חדשה' כדי ליצור אחת" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "לחץ/י Enter ומערכת השמע תופעל מחדש כדי להחיל את השינוי" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "לחץ/י על Enter להדבקה, Shift+Enter להעתקה" - }, - "Press key...": { - "Press key...": "לחץ/י על מקש..." - }, - "Pressure": { - "Pressure": "לחץ" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "מנע/י כיבוי מסך אוטומטי" - }, - "Preview": { - "Preview": "תצוגה מקדימה" - }, - "Primary": { - "Primary": "ראשי" - }, - "Primary Container": { - "Primary Container": "מיכל ראשי" - }, - "Print Server Management": { - "Print Server Management": "ניהול שרת הדפסה" - }, - "Print Server not available": { - "Print Server not available": "שרת ההדפסה אינו זמין" - }, - "Printer": { - "Printer": "מדפסת" - }, - "Printer Classes": { - "Printer Classes": "סוגי מדפסות" - }, - "Printer created successfully": { - "Printer created successfully": "המדפסת נוצרה בהצלחה" - }, - "Printer deleted": { - "Printer deleted": "המדפסת נמחקה" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "שם המדפסת (ללא רווחים)" - }, - "Printer reachable": { - "Printer reachable": "המדפסת זמינה" - }, - "Printers": { - "Printers": "מדפסות" - }, - "Printers: ": { - "Printers: ": "מדפסות: " - }, - "Prioritize performance": { - "Prioritize performance": "עדיפות לביצועים" - }, - "Priority": { - "Priority": "עדיפות" - }, - "Privacy Indicator": { - "Privacy Indicator": "מחוון פרטיות" - }, - "Privacy Mode": { - "Privacy Mode": "מצב פרטיות" - }, - "Private Key Password": { - "Private Key Password": "סיסמת מפתח פרטי" - }, - "Process Count": { - "Process Count": "מספר תהליכים" - }, - "Processes": { - "Processes": "תהליכים" - }, - "Processes:": { - "Processes:": "תהליכים:" - }, - "Processing": { - "Processing": "מעבד" - }, - "Profile Image Error": { - "Profile Image Error": "שגיאה בתמונת הפרופיל" - }, - "Profile activated: %1": { - "Profile activated: %1": "פרופיל הופעל: %1" - }, - "Profile deleted": { - "Profile deleted": "הפרופיל נמחק" - }, - "Profile error": { - "Profile error": "שגיאת פרופיל" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "תמונת הפרופיל גדולה מדי. נא להשתמש בתמונה קטנה יותר." - }, - "Profile name": { - "Profile name": "שם הפרופיל" - }, - "Profile not found": { - "Profile not found": "הפרופיל לא נמצא" - }, - "Profile saved: %1": { - "Profile saved: %1": "פרופיל נשמר: %1" - }, - "Protocol": { - "Protocol": "פרוטוקול" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia אינו זמין" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia אינו זמין - שומר מסך וידאו דורש שירותי מולטימדיה של Qt" - }, - "Quick Access": { - "Quick Access": "גישה מהירה" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "גישה מהירה למשגר האפליקציות" - }, - "Quick access to color picker": { - "Quick access to color picker": "גישה מהירה לבוחר הצבעים" - }, - "Quick access to notepad": { - "Quick access to notepad": "גישה מהירה לפנקס" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "לוח נשלף מהיר לרישום הערות" - }, - "Quick system toggles": { - "Quick system toggles": "מתגי מערכת מהירים" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "רדיוס" - }, - "Rain": { - "Rain": "גשם" - }, - "Rain Chance": { - "Rain Chance": "סיכוי לגשם" - }, - "Rainbow": { - "Rainbow": "קשת" - }, - "Random": { - "Random": "אקראי" - }, - "Rate": { - "Rate": "קצב" - }, - "Read:": { - "Read:": "קריאה:" - }, - "Reason": { - "Reason": "סיבה" - }, - "Reboot": { - "Reboot": "הפעלה מחדש" - }, - "Recent Colors": { - "Recent Colors": "צבעים אחרונים" - }, - "Recently Used Apps": { - "Recently Used Apps": "אפליקציות שהיו בשימוש לאחרונה" - }, - "Recommended available": { - "Recommended available": "מומלץ זמין" - }, - "Refresh": { - "Refresh": "רענון" - }, - "Refresh Weather": { - "Refresh Weather": "רענן/י מזג אוויר" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "דחה/י" - }, - "Reject Jobs": { - "Reject Jobs": "דחה/י עבודות" - }, - "Release": { - "Release": "שחרור" - }, - "Reload Plugin": { - "Reload Plugin": "טען/י תוסף מחדש" - }, - "Remaining": { - "Remaining": "נותר" - }, - "Remaining / Total": { - "Remaining / Total": "נותר / סה״כ" - }, - "Remember Last Query": { - "Remember Last Query": "זכירת הבקשה האחרונה" - }, - "Remember last session": { - "Remember last session": "זכירת ההפעלה האחרונה" - }, - "Remember last user": { - "Remember last user": "זכירת המשתמש האחרון" - }, - "Remove": { - "Remove": "הסרה" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "הסרת הריווח של הווידג׳טים" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "הסר/י רווחים ומסגרת כאשר חלונות ממוקסמים" - }, - "Rename": { - "Rename": "שנה/י שם" - }, - "Rename Session": { - "Rename Session": "שינוי שם להפעלה" - }, - "Rename Workspace": { - "Rename Workspace": "שנה/י את השם של סביבת העבודה" - }, - "Repeat": { - "Repeat": "חזרה" - }, - "Replacement": { - "Replacement": "החלפה" - }, - "Report": { - "Report": "דיווח" - }, - "Request Pairing": { - "Request Pairing": "בקש/י התאמה" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "דרוש/דרשי החזקה של הכפתור לאישור כיבוי, הפעלה מחדש, השהיה, שינה עמוקה והתנתקות" - }, - "Required plugin: ": { - "Required plugin: ": "תוסף נדרש: " - }, - "Requires %1": { - "Requires %1": "גרסה %1 נדרשת" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "הכלי 'dgop' נדרש" - }, - "Requires DMS %1": { - "Requires DMS %1": "DMS %1 נדרש" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "קומפוזיטור DWL נדרש" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "נדרשת גרסה חדשה יותר של Quickshell" - }, - "Requires night mode support": { - "Requires night mode support": "תמיכה במצב לילה נדרשת" - }, - "Reset": { - "Reset": "איפוס" - }, - "Reset Position": { - "Reset Position": "אפס/י מיקום" - }, - "Reset Size": { - "Reset Size": "אפס/י גודל" - }, - "Reset to default name": { - "Reset to default name": "אפס/י לשם ברירת מחדל" - }, - "Resize Widget": { - "Resize Widget": "שינוי גודל הווידג׳ט" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "רזולוציה ורענון" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "רזולוציה, מיקום, קנה מידה" - }, - "Restart DMS": { - "Restart DMS": "הפעלה מחדש של DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "הפעל/י מחדש את DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "מפעיל מערכת שמע מחדש..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "שחזר/י חלונות מסביבת עבודה מיוחדת" - }, - "Resume": { - "Resume": "המשך" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "היפוך של כיוון הגלילה" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "הפוך/י את כיוון החלפת סביבות העבודה בעת גלילה על הסרגל" - }, - "Revert": { - "Revert": "חזור/חזרי" - }, - "Right": { - "Right": "ימין" - }, - "Right Center": { - "Right Center": "צד ימין במרכז" - }, - "Right Section": { - "Right Section": "מקטע ימני" - }, - "Right Tiling": { - "Right Tiling": "ריצוף ימני" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "לחץ/י לחיצה ימנית וגרור/גררי בכל מקום על הווידג׳ט" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "לחץ/י לחיצה ימנית וגרור/גררי את הפינה הימנית התחתונה" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "לחץ/י קליק ימני על הווידג׳ט כדי לעבור במעגל" - }, - "Ring": { - "Ring": "צלצל/י" - }, - "Ringing": { - "Ringing": "מצלצל" - }, - "Ripple Effects": { - "Ripple Effects": "אפקטי אדווה" - }, - "Root Filesystem": { - "Root Filesystem": "מערכת הקבצים הראשית" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "פינות מעוגלות לחלונות" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "פינות מעוגלות לחלונות (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "פינות מעוגלות לחלונות (decoration.rounding)" - }, - "Rule": { - "Rule": "חוק" - }, - "Rule Name": { - "Rule Name": "שם חוק" - }, - "Rules (%1)": { - "Rules (%1)": "חוקים (%1)" - }, - "Run Again": { - "Run Again": "הרץ/י שוב" - }, - "Run DMS Templates": { - "Run DMS Templates": "הרץ/י תבניות DMS" - }, - "Run User Templates": { - "Run User Templates": "הרץ/י תבניות משתמש" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "הרץ/י תוכנית (לדוגמא firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "הרץ/י פקודת מעטפת (לדוגמא notify-send)" - }, - "Running Apps": { - "Running Apps": "אפליקציות פעילות" - }, - "Running Apps Settings": { - "Running Apps Settings": "הגדרות אפליקציות פעילות" - }, - "Running greeter sync…": { - "Running greeter sync…": "מריץ סנכרון במסך ההתחברות…" - }, - "SDR Brightness": { - "SDR Brightness": "בהירות של SDR" - }, - "SDR Saturation": { - "SDR Saturation": "רוויה של SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "שמירה" - }, - "Save Notepad File": { - "Save Notepad File": "שמור/י פתק כקובץ" - }, - "Save QR Code": { - "Save QR Code": "שמור/י קוד QR" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "שמור/שמרי והחלף/החליפי את הגדרות התצוגה" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "שמור/י התראות בעדיפות קריטית להיסטוריה" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "שמור/י התראות שנסגרו להיסטוריה" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "שמור/י התראות בעדיפות נמוכה להיסטוריה" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "שמור/י התראות בעדיפות רגילה להיסטוריה" - }, - "Save password": { - "Save password": "שמור/י סיסמה" - }, - "Saved": { - "Saved": "נשמר" - }, - "Saved Configurations": { - "Saved Configurations": "תצורות שמורות" - }, - "Saved Note": { - "Saved Note": "פתק נשמר" - }, - "Saved item deleted": { - "Saved item deleted": "פריט שמור נמחק" - }, - "Saving...": { - "Saving...": "שומר/ת..." - }, - "Scale": { - "Scale": "קנה מידה" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "שנה/י את גודל הגופנים של DankBar באופן עצמאי" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "התאם/י את גודל הסמלים בDankBar באופן עצמאי" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "שנה/י קנה מידה של כל גדלי הגופנים בכל המעטפת" - }, - "Scan": { - "Scan": "סריקה" - }, - "Scanning": { - "Scanning": "סורק" - }, - "Scanning...": { - "Scanning...": "סורק..." - }, - "Science": { - "Science": "מדע" - }, - "Score": { - "Score": "Score" - }, - "Screen Sharing": { - "Screen Sharing": "שיתוף מסך" - }, - "Screen sharing": { - "Screen sharing": "שיתוף מסך" - }, - "Scroll": { - "Scroll": "גלילה" - }, - "Scroll Factor": { - "Scroll Factor": "מקדם גלילה" - }, - "Scroll GitHub": { - "Scroll GitHub": "הGitHub של Scroll" - }, - "Scroll Wheel": { - "Scroll Wheel": "גלגל הגלילה" - }, - "Scroll song title": { - "Scroll song title": "גלילה של שם השיר" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "גלילה של הכותרת אם היא לא נכנסת במלואה בווידג׳ט" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "התנהגות גלגל הגלילה על ווידג׳ט המדיה" - }, - "Scrolling": { - "Scrolling": "גלילה" - }, - "Search App Actions": { - "Search App Actions": "חיפוש פעולות לאפליקציה" - }, - "Search Options": { - "Search Options": "אפשרויות חיפוש" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "חפש/י לפי צירוף מקשים, תיאור או שם פעולה.\n\nפעולת ברירת מחדל מעתיקה את קיצור המקלדת ללוח ההעתקה.\nלחץ/י לחיצה ימנית או לחץ/י על חץ ימינה כדי להצמיד קיצורי מקלדת בשימוש תכוף - הם יופיעו בראש כשלא מחפשים." - }, - "Search for a location...": { - "Search for a location...": "חפש/י מיקום..." - }, - "Search keybinds...": { - "Search keybinds...": "חפש/י קיצורי מקלדת..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "חפש/י קיצורי מקלדת מהקומפוזיטור והאפליקציות שלך" - }, - "Search plugins...": { - "Search plugins...": "חפש/י תוספים..." - }, - "Search processes...": { - "Search processes...": "חפש/י תהליכים..." - }, - "Search sessions...": { - "Search sessions...": "חפש/י הפעלות..." - }, - "Search themes...": { - "Search themes...": "חפש/י ערכות נושא..." - }, - "Search widgets...": { - "Search widgets...": "חפש/י ווידג׳טים..." - }, - "Search...": { - "Search...": "חיפוש..." - }, - "Searching...": { - "Searching...": "מחפש..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "גורם שני (AND)" - }, - "Secondary": { - "Secondary": "משני" - }, - "Secured": { - "Secured": "מאובטח" - }, - "Security": { - "Security": "אבטחה" - }, - "Security & privacy": { - "Security & privacy": "אבטחה ופרטיות" - }, - "Security key mode": { - "Security key mode": "מצב מפתח אבטחה" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "לא ניתן היה לאמת את הזמינות של מפתח האבטחה." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "זוהתה תמיכה במפתח אבטחה, אך לא נמצא מפתח רשום עדיין. ניתן להפעיל את ההזדהות כעת ולרשום מפתח מאוחר יותר." - }, - "Select": { - "Select": "בחר/י" - }, - "Select Application": { - "Select Application": "בחר/י אפליקציה" - }, - "Select Bar": { - "Select Bar": "בחר/י סרגל" - }, - "Select Custom Theme": { - "Select Custom Theme": "בחר/י ערכת נושא מותאמת אישית" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "בחר/י לוגו למשגר בDock" - }, - "Select File to Send": { - "Select File to Send": "בחר/י קובץ לשליחה" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "בחר/י לוגו למשגר" - }, - "Select Profile Image": { - "Select Profile Image": "בחר/י תמונת פרופיל" - }, - "Select Video or Folder": { - "Select Video or Folder": "בחר/י וידאו או תיקייה" - }, - "Select Wallpaper": { - "Select Wallpaper": "בחר/י רקע" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "בחר/י תיקיית רקעים" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "בחר/י צבע מהפלטה או השתמש/י במחוונים מותאמים אישית" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "בחר/י ווידג׳ט להוספה לשולחן העבודה שלך. כל ווידג׳ט הוא מופע נפרד עם הגדרות משלו." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "בחר/י ווידג׳ט להוספה. ניתן להוסיף מספר מופעים של אותו ווידג׳ט במידת הצורך." - }, - "Select a window...": { - "Select a window...": "בחר/י חלון..." - }, - "Select an image file...": { - "Select an image file...": "בחר/י קובץ תמונה..." - }, - "Select at least one provider": { - "Select at least one provider": "בחר/י לפחות ספק אחד" - }, - "Select device": { - "Select device": "בחר/י התקן" - }, - "Select device...": { - "Select device...": "בחר/י התקן..." - }, - "Select driver...": { - "Select driver...": "בחר/י מנהל התקן..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "בחר/י משקל לגופן שבחרת לטקסט ממשק המשתמש" - }, - "Select greeter background image": { - "Select greeter background image": "בחר/י תמונת רקע במסך ההתחברות" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "בחר/י מסך להגדרת הרקע" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "בחר/י גופן ברוחב קבוע לרשימת תהליכים ותצוגות טכניות" - }, - "Select network": { - "Select network": "בחר/י רשת" - }, - "Select system sound theme": { - "Select system sound theme": "בחר/י את ערכת הצלילים של המערכת" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "בחר/י גופן לטקסט ממשק המשתמש" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "בחר/י את האלגוריתם שייקבע את פלטת הצבעים עבור צבעים מבוססי תמונת רקע" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "בחר/י אילו ספקי קיצורי מקלדת לכלול" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "בחר/י אילו מעברים לכלול באקראיות" - }, - "Select...": { - "Select...": "בחר/י..." - }, - "Selected image file not found.": { - "Selected image file not found.": "קובץ התמונה שנבחר לא נמצא." - }, - "Send": { - "Send": "שלח/י" - }, - "Send Clipboard": { - "Send Clipboard": "שלח/י לוח ההעתקה" - }, - "Send File": { - "Send File": "שלח/י קובץ" - }, - "Send SMS": { - "Send SMS": "שלח/י SMS" - }, - "Sending": { - "Sending": "שולח" - }, - "Separator": { - "Separator": "מפריד" - }, - "Server": { - "Server": "שרת" - }, - "Session Filter": { - "Session Filter": "מסנן הפעלות" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "הגדר/י שם התקן מותאם אישית" - }, - "Set custom name": { - "Set custom name": "הגדר/י שם מותאם אישית" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "הגדר/י שמות מותאמים אישית להתקני קלט השמע שלך" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "הגדר/י שמות מותאמים אישית להתקני פלט השמע שלך" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "הגדר/י רקעים שונים לכל מסך מחובר" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "הגדר/י רקעים שונים למצב בהיר ולמצב כהה" - }, - "Set key and action to save": { - "Set key and action to save": "הגדר/י מקש ופעולה לשמירה" - }, - "Set notification rules": { - "Set notification rules": "הגדר/י חוקים להתראות" - }, - "Settings": { - "Settings": "הגדרות" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "ההגדרות הן לקריאה בלבד. שינויים לא יישמרו." - }, - "Setup": { - "Setup": "התקנה" - }, - "Shadow Color": { - "Shadow Color": "צבע צל" - }, - "Shadow Intensity": { - "Shadow Intensity": "עוצמת צל" - }, - "Shadow Opacity": { - "Shadow Opacity": "שקיפות צל" - }, - "Shadow Override": { - "Shadow Override": "דריסת צל" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "הגבהה של הצללה בסרגלים ופאנלים" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "הגבהה של הצללה במודלים ותיבות דו-שיח" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "הגבהה של הצללה בחלונות קופצים, תצוגות OSD ותפריטים נפתחים" - }, - "Shadows": { - "Shadows": "צללים" - }, - "Share": { - "Share": "שתף/י" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "שיתוף ההגדרות עם בקרת גאמה" - }, - "Share Text": { - "Share Text": "שתף/י טקסט" - }, - "Share URL": { - "Share URL": "שתף/י URL" - }, - "Shared": { - "Shared": "שותף" - }, - "Shell": { - "Shell": "מעטפת" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: ניקוי הכל • Esc: סגירה" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter להדבקה" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: העתקה • Shift+Del: ניקוי הכל • Esc: סגירה" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: הדבקה • Shift+Del: ניקוי הכל • Esc: סגירה" - }, - "Short": { - "Short": "קצר" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "קיצור (%1)" - }, - "Shortcuts": { - "Shortcuts": "קיצורי דרך" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "קיצורי דרך (%1)" - }, - "Show": { - "Show": "הצג/י" - }, - "Show 3rd Party": { - "Show 3rd Party": "הצג/י צד שלישי" - }, - "Show All Tags": { - "Show All Tags": "הצג/י את כל התגים" - }, - "Show Badge": { - "Show Badge": "הצג/י תג" - }, - "Show CPU": { - "Show CPU": "הצג/י מעבד" - }, - "Show CPU Graph": { - "Show CPU Graph": "הצג/י גרף מעבד" - }, - "Show CPU Temp": { - "Show CPU Temp": "הצגת טמפרטורת המעבד" - }, - "Show Date": { - "Show Date": "הצג/י תאריך" - }, - "Show Disk": { - "Show Disk": "הצג/י דיסק" - }, - "Show Dock": { - "Show Dock": "הצגה של הDock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "הצגת הטמפרטורה המורגשת (\"מרגיש כמו\")" - }, - "Show Footer": { - "Show Footer": "הצגת כותרת תחתונה" - }, - "Show Forecast": { - "Show Forecast": "הצג/י תחזית" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "הצגת טמפרטורת הGPU" - }, - "Show Header": { - "Show Header": "הצג/י כותרת" - }, - "Show Hibernate": { - "Show Hibernate": "הצגה של \"שינה עמוקה\"" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "הצג/י מספרי שעות" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "הצג/י תחזית שעתית" - }, - "Show Humidity": { - "Show Humidity": "הצג/י לחות" - }, - "Show Launcher Button": { - "Show Launcher Button": "הצג/י את כפתור המשגר" - }, - "Show Line Numbers": { - "Show Line Numbers": "הצג/י מספרי שורות" - }, - "Show Location": { - "Show Location": "הצגת מיקום" - }, - "Show Lock": { - "Show Lock": "הצגה של \"נעילה\"" - }, - "Show Log Out": { - "Show Log Out": "הצגה של \"התנתקות\"" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "הצג/י אנימציות של אדוות בעיצוב Material על גבי רכיבים אינטראקטיביים" - }, - "Show Media Player": { - "Show Media Player": "הצגת נגן מדיה" - }, - "Show Memory": { - "Show Memory": "הצג/י זיכרון" - }, - "Show Memory Graph": { - "Show Memory Graph": "הצג/י גרף זיכרון" - }, - "Show Memory in GB": { - "Show Memory in GB": "הצג/י זיכרון בGB" - }, - "Show Network": { - "Show Network": "הצג/י רשת" - }, - "Show Network Graph": { - "Show Network Graph": "הצג/י גרף רשת" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "הצגת סביבות עבודה שאינן ריקות בלבד" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "הצגת תג עם ספירה לגלישה" - }, - "Show Password Field": { - "Show Password Field": "הצגת שדה לסיסמה" - }, - "Show Power Actions": { - "Show Power Actions": "הצגת פעולות חשמל" - }, - "Show Power Off": { - "Show Power Off": "הצגה של \"כיבוי\"" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "הצג/י סיכוי למשקעים" - }, - "Show Pressure": { - "Show Pressure": "הצג/י לחץ" - }, - "Show Profile Image": { - "Show Profile Image": "הצגת תמונת הפרופיל" - }, - "Show Reboot": { - "Show Reboot": "הצגה של \"הפעלה מחדש\"" - }, - "Show Restart DMS": { - "Show Restart DMS": "הצגה של \"הפעלה מחדש של DMS\"" - }, - "Show Saved Items": { - "Show Saved Items": "הצג/י פריטים שמורים" - }, - "Show Seconds": { - "Show Seconds": "הצגת שניות" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "הצג/י זריחה/שקיעה" - }, - "Show Suspend": { - "Show Suspend": "הצגה של \"השהיה\"" - }, - "Show Swap": { - "Show Swap": "הצג/י Swap" - }, - "Show System Date": { - "Show System Date": "הצגת תאריך המערכת" - }, - "Show System Icons": { - "Show System Icons": "הצגת סמלי מערכת" - }, - "Show System Time": { - "Show System Time": "הצגת זמן המערכת" - }, - "Show Top Processes": { - "Show Top Processes": "הצג/י תהליכים עליונים" - }, - "Show Weather Condition": { - "Show Weather Condition": "הצגת תנאי מזג האוויר" - }, - "Show Week Number": { - "Show Week Number": "הצגת מספר שבוע" - }, - "Show Welcome": { - "Show Welcome": "הצגת המסך ״ברוכים הבאים״" - }, - "Show Wind Speed": { - "Show Wind Speed": "הצג/י מהירות רוח" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "הצגת אפליקציות בסביבת העבודה" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "הצג/י את כל 9 התגים במקום רק את התגים הפעילים (DWL בלבד)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "הצג/י טבעת מתאר סביב המחוון של סביבת העבודה הממוקדת" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "הצג/י את המחולל החזותי לשמע (cava) בווידג׳ט המדיה" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "הצג/י שכבה כהה מאחורי חלוניות שיח" - }, - "Show device": { - "Show device": "הצג/י התקן" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "הצג/י את הDock כאשר חלונות צפים לא חופפים את השטח שלו" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "הצג/י צל נופל על חלונות קופצים של התראות. דורש הפעלה של M3 Elevation (הגבהה) בערכת נושא וצבעים." - }, - "Show in GB": { - "Show in GB": "הצג/י בGB" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "הצג/י שכבת משגר בעת הקלדה בסקירה של Niri. השבת/י כדי להשתמש במשגר אחר." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "הצג/י לשוניות מצב ורמזי מקלדת בתחתית." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "הצג/י חלונות קופצים של התראות רק במסך הממוקד כעת" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "הצג/י התראות רק במסך הממוקד כעת" - }, - "Show on Last Display": { - "Show on Last Display": "הצג/י במסך האחרון" - }, - "Show on Overlay": { - "Show on Overlay": "הצגה על שכבת הכיסוי" - }, - "Show on Overview": { - "Show on Overview": "הצגה בתצוגת סקירה" - }, - "Show on Overview Only": { - "Show on Overview Only": "הצגה בסקירה בלבד" - }, - "Show on all connected displays": { - "Show on all connected displays": "הצג/י בכל המסכים המחוברים" - }, - "Show on screens:": { - "Show on screens:": "הצג/י במסכים:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "הצג/י תצוגה על המסך (OSD) כאשר הבהירות משתנה" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "הצג/י תצוגה על המסך (OSD) כאשר מצב Caps Lock משתנה" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "הצג/י תצוגה על המסך (OSD) בעת מעבר בין התקני פלט של שמע" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "הצג/י תצוגה על המסך (OSD) כאשר מצב מונע ההמתנה משתנה" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "הצג/י תצוגה על המסך (OSD) כאשר מצב נגן המדיה משתנה" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "הצג/י תצוגה על המסך (OSD) כאשר עוצמת השמע בנגן המדיה משתנה" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "הצג/י תצוגה על המסך (OSD) כאשר המיקרופון מושתק/מופעל" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "הצג/י תצוגה על המסך (OSD) כאשר פרופיל החשמל משתנה" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "הצג/י תצוגה על המסך (OSD) כאשר עוצמת השמע משתנה" - }, - "Show seconds": { - "Show seconds": "הצג/י שניות" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "הצג/י מידע על מזג האוויר בסרגל העליון ובמרכז הבקרה" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "הצג/י מספר שבוע בלוח השנה" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "הצג/י את מספרי האינדקס של סביבות העבודה במחליף סביבת העבודה שבסרגל העליון" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "הצג/י את השם של סביבת העבודה על סרגלים אופקיים, ואות ראשונה על סרגלים אנכיים" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "הצג/י סביבות עבודה שפעילות על המסך שכרגע ממוקד" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "מציג את כל האפליקציות הפעילות עם סימון למיקוד" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "מציג את סביבת העבודה הנוכחית ומאפשר להחליף סביבה" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "מוצג כאשר Caps Lock פעיל" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "מוצג כאשר המיקרופון, המצלמה או שיתוף המסך פעילים" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "כיבוי" - }, - "Signal": { - "Signal": "אות" - }, - "Signal:": { - "Signal:": "אות:" - }, - "Size": { - "Size": "גודל" - }, - "Size Constraints": { - "Size Constraints": "מגבלות גודל" - }, - "Size Offset": { - "Size Offset": "היסט לגודל" - }, - "Sizing": { - "Sizing": "גודל" - }, - "Skip": { - "Skip": "דילוג" - }, - "Skip confirmation": { - "Skip confirmation": "דלג/י על אישור" - }, - "Skip setup": { - "Skip setup": "דלג/י על ההתקנה" - }, - "Small": { - "Small": "קטן" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "אימות עם כרטיס חכם" - }, - "Smartcard PIN": { - "Smartcard PIN": "קוד PIN של הכרטיס החכם" - }, - "Snap": { - "Snap": "הצמד/י" - }, - "Snow": { - "Snow": "שלג" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "תוספים מסוימים דורשים גרסה חדשה יותר של DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "מיון לפי סדר אלפביתי" - }, - "Sort By": { - "Sort By": "מיין/י לפי" - }, - "Sorting & Layout": { - "Sorting & Layout": "מיון ופריסה" - }, - "Sound Theme": { - "Sound Theme": "ערכת נושא של צלילים" - }, - "Sounds": { - "Sounds": "צלילים" - }, - "Space between windows": { - "Space between windows": "רווח בין חלונות" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "רווח בין חלונות (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "רווח בין חלונות (gaps_in ו-gaps_out)" - }, - "Spacer": { - "Spacer": "מרווח" - }, - "Spacing": { - "Spacing": "ריווח" - }, - "Speaker settings": { - "Speaker settings": "הגדרות רמקול" - }, - "Speed": { - "Speed": "מהירות" - }, - "Spool Area Full": { - "Spool Area Full": "אזור התור (Spool) מלא" - }, - "Square Corners": { - "Square Corners": "פינות ישרות" - }, - "Stacked": { - "Stacked": "בערימה" - }, - "Standard": { - "Standard": "רגיל" - }, - "Start": { - "Start": "התחל/י" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "הפעל/י KDE Connect או Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "הפעל/י KDE Connect או Valent כדי להשתמש בתוסף זה" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "התחל/י להקליד את ההערות שלך כאן..." - }, - "State": { - "State": "מצב" - }, - "Status": { - "Status": "מצב" - }, - "Stopped": { - "Stopped": "נעצר" - }, - "Stopped Partly": { - "Stopped Partly": "נעצר חלקית" - }, - "Stopping": { - "Stopping": "עוצר" - }, - "Stretch": { - "Stretch": "מתיחה" - }, - "Stripes": { - "Stripes": "פסים" - }, - "Summary": { - "Summary": "סיכום" - }, - "Sunrise": { - "Sunrise": "זריחה" - }, - "Sunset": { - "Sunset": "שקיעה" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "דכא/י הצגה של התראות בחלונות קופצים בזמן שהמצב מופעל" - }, - "Surface": { - "Surface": "משטח" - }, - "Surface Variant": { - "Surface Variant": "גרסת משטח" - }, - "Suspend": { - "Suspend": "השהיה" - }, - "Suspend behavior": { - "Suspend behavior": "התנהגות ההשהיה" - }, - "Suspend system after": { - "Suspend system after": "העבר/י את המערכת למצב השהיה לאחר" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "השהיה ואחריה שינה עמוקה" - }, - "Sway Website": { - "Sway Website": "האתר של Sway" - }, - "Switch User": { - "Switch User": "החלף/י משתמש" - }, - "Switch to power profile": { - "Switch to power profile": "החלף/י לפרופיל חשמל" - }, - "Sync": { - "Sync": "סנכרון" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "סנכרון מצב עם הפורטל" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "סנכרון חלונות קופצים ומודליים" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "סנכרון המיקום בין מסכים" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "הסנכרון הושלם בהצלחה." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "סנכרון מצב כהה עם פורטלי ההגדרות לרמזי ערכת נושא ברמת המערכת" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "הסנכרון נכשל במצב רקע. מנסה במצב מסוף כדי שתוכל/י להזדהות באופן אינטראקטיבי." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "הסנכרון דורש אימות עם sudo. ייפתח מסוף כדי שתוכל/י להשתמש בסיסמה או בטביעת אצבע." - }, - "System": { - "System": "מערכת" - }, - "System App Theming": { - "System App Theming": "ערכת נושא לאפליקציות מערכת" - }, - "System Check": { - "System Check": "בדיקת מערכת" - }, - "System Default": { - "System Default": "ברירת מחדל של המערכת" - }, - "System Information": { - "System Information": "מידע מערכת" - }, - "System Monitor": { - "System Monitor": "מנטר המערכת" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "מנטר המערכת אינו זמין" - }, - "System Sounds": { - "System Sounds": "צלילי מערכת" - }, - "System Tray": { - "System Tray": "מגש המערכת" - }, - "System Update": { - "System Update": "עדכון מערכת" - }, - "System Updater": { - "System Updater": "מעדכן המערכת" - }, - "System Updates": { - "System Updates": "עדכוני מערכת" - }, - "System notification area icons": { - "System notification area icons": "סמלי אזור ההתראות של המערכת" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "צלילי מערכת אינם זמינים. התקן/י %1 לתמיכה בצלילים." - }, - "System theme toggle": { - "System theme toggle": "מתג ערכת נושא של המערכת" - }, - "System toast notifications": { - "System toast notifications": "התראות מערכת קופצות" - }, - "System update custom command": { - "System update custom command": "פקודה מותאמת אישית לעדכון המערכת" - }, - "Tab": { - "Tab": "טאב" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: ניווט • ←→↑↓: ניווט ברשת • Enter/Space: בחירה" - }, - "Terminal": { - "Terminal": "מסוף" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "פרמטרים נוספים מותאמים אישית למסוף" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "המעבר למסוף כגיבוי נכשל. התקן/י יישום מסוף נתמך או הרץ/י את הפקודה 'dms auth sync' באופן ידני." - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "המעבר למסוף כגיבוי נכשל. התקן/י את אחד מיישומי המסוף הנתמכים או הרץ/י את הפקודה 'dms greeter sync' באופן ידני." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "נפתח מסוף כגיבוי. השלם/השלימי את הגדרת האימות שם, הוא ייסגר אוטומטית בסיום." - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "נפתח מסוף כגיבוי. השלם/השלימי את הסנכרון שם. הוא ייסגר אוטומטית בסיום." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "הbackend של מרבב המסוף שברצונך להשתמש בו" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "המסוף נפתח. השלם/השלימי את הגדרת האימות שם, הוא ייסגר אוטומטית בסיום." - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "המסוף נפתח. השלם/השלימי את אימות הסנכרון שם. הוא ייסגר אוטומטית בסיום." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "השתמש/י תמיד בערכת נושא כהה במסופים" - }, - "Test Connection": { - "Test Connection": "בדיקת חיבור" - }, - "Test Page": { - "Test Page": "דף בדיקה" - }, - "Test page sent to printer": { - "Test page sent to printer": "דף בדיקה נשלח למדפסת" - }, - "Testing...": { - "Testing...": "בודק..." - }, - "Text": { - "Text": "טקסט" - }, - "Text Color": { - "Text Color": "צבע טקסט" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "כלי 'dgop' נדרש לניטור מערכת.\nאנא התקן/י dgop כדי להשתמש בתכונה זו." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "משתנה הסביבה DMS_SOCKET אינו מוגדר או שהsocket אינו זמין. ניהול תוספים אוטומטי דורש את DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "ההגדרות הבאות ישנו את הגדרות ה GTK וQt שלך. אם ברצונך לשמור על התצורות הנוכחיות, נא לגבות אותן (qt5ct.conf|qt6ct.conf וconfig/gtk-3.0|gtk-4.0./~)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "הפקודה המותאמת אישית שנמצאת בשימוש בעת חיבור להפעלות (מקבלת את שם ההפעלה כארגומנט הראשון)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "תור ההדפסה של מדפסת זו ריק" - }, - "Theme & Colors": { - "Theme & Colors": "ערכת נושא וצבעים" - }, - "Theme Color": { - "Theme Color": "צבע ערכת הנושא" - }, - "Theme Registry": { - "Theme Registry": "מאגר ערכות הנושא" - }, - "Themes": { - "Themes": "ערכות נושא" - }, - "Thickness": { - "Thickness": "עובי" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "אזהרת תוסף צד שלישי" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "תוספי צד שלישי נוצרו על ידי הקהילה ואינם נתמכים רשמית על ידי DankMaterialShell.\n\nתוספים אלה עלולים להוות סיכוני אבטחה ופרטיות - התקן/י על אחריותך בלבד." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "קיצור זה נדרס על ידי config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "זה עשוי לקחת מספר שניות" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "לתוסף זה אין הרשאת 'settings_write'.\n\nהוסף/י \"permissions\": [\"settings_read\", \"settings_write\"] ל-plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "ווידג׳ט זה מונע מהGPU לעבור למצב כבוי, דבר שעלול להשפיע משמעותית על חיי הסוללה במחשבים ניידים. לא מומלץ להשתמש בו במחשבים ניידים עם גרפיקה היברידית." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "זה ימחק את כל הרשומות שלא מוצמדות. %1 רשומות מוצמדות יישמרו." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "פעולה זו תמחק לצמיתות את כל היסטוריית לוח ההעתקה." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "זה יסיר לצמיתות את פריט לוח ההעתקה השמור הזה. לא ניתן לבטל פעולה זו." - }, - "Thunderstorm": { - "Thunderstorm": "סערת ברקים" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "סערת ברקים עם ברד" - }, - "Tile": { - "Tile": "ריצוף" - }, - "Tile H": { - "Tile H": "ריצוף אופקי" - }, - "Tile V": { - "Tile V": "ריצוף אנכי" - }, - "Tiled": { - "Tiled": "באריחים" - }, - "Tiled State": { - "Tiled State": "מצב אריחים" - }, - "Tiling": { - "Tiling": "ריצוף" - }, - "Time": { - "Time": "זמן" - }, - "Time & Date Locale": { - "Time & Date Locale": "אזור לתאריך ושעה" - }, - "Time & Weather": { - "Time & Weather": "שעה ומזג אוויר" - }, - "Time Format": { - "Time Format": "פורמט שעה" - }, - "Time format": { - "Time format": "תבנית זמן" - }, - "Time remaining: %1": { - "Time remaining: %1": "זמן שנותר: %1" - }, - "Time until full: %1": { - "Time until full: %1": "זמן עד טעינה מלאה: %1" - }, - "Timed Out": { - "Timed Out": "הזמן אזל" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "הזמן שמוקצב להתראות בעדיפות קריטית" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "הזמן שמוקצב להתראות בעדיפות נמוכה" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "הזמן שמוקצב להתראות בעדיפות רגילה" - }, - "Title": { - "Title": "כותרת" - }, - "Title regex (optional)": { - "Title regex (optional)": "Title regex (אופציונלי)" - }, - "To Full": { - "To Full": "לטעינה מלאה" - }, - "To update, run the following command:": { - "To update, run the following command:": "כדי לעדכן, הרץ/י את הפקודה הבאה:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "כדי להשתמש בקיצור המקלדת הזה ב DMS, הסר/י או שנה/י את קיצור המקלדת בקובץ הconfig.kdl שלך" - }, - "Toast Messages": { - "Toast Messages": "הודעות קופצות" - }, - "Today": { - "Today": "היום" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "שנה/י את ההצגה/הסתרה של תצורת סרגל זו" - }, - "Toggling...": { - "Toggling...": "משנה מצב..." - }, - "Tomorrow": { - "Tomorrow": "מחר" - }, - "Tonal Spot": { - "Tonal Spot": "נקודה טונלית" - }, - "Toner Empty": { - "Toner Empty": "הטונר התרוקן" - }, - "Toner Low": { - "Toner Low": "הטונר עומד להסתיים" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "יותר מדי ניסיונות - החשבון ננעל" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "יותר מדי ניסיונות כושלים - החשבון עלול להינעל" - }, - "Tools": { - "Tools": "כלים" - }, - "Top": { - "Top": "למעלה" - }, - "Top (Default)": { - "Top (Default)": "למעלה (ברירת מחדל)" - }, - "Top Bar Format": { - "Top Bar Format": "תבנית הסרגל העליון" - }, - "Top Center": { - "Top Center": "במרכז למעלה" - }, - "Top Left": { - "Top Left": "שמאל למעלה" - }, - "Top Processes": { - "Top Processes": "תהליכים מובילים" - }, - "Top Right": { - "Top Right": "ימין למעלה" - }, - "Top Section": { - "Top Section": "מקטע עליון" - }, - "Total": { - "Total": "סה״כ" - }, - "Total Jobs": { - "Total Jobs": "סה״כ עבודות" - }, - "Touch your security key...": { - "Touch your security key...": "גע/י במפתח האבטחה שלך..." - }, - "Transform": { - "Transform": "שינוי" - }, - "Transition Effect": { - "Transition Effect": "אפקט מעבר" - }, - "Transparency": { - "Transparency": "שקיפות" - }, - "Trending GIFs": { - "Trending GIFs": "GIFים טרנדיים" - }, - "Trending Stickers": { - "Trending Stickers": "מדבקות טרנדיות" - }, - "Trigger": { - "Trigger": "מפעיל" - }, - "Trigger Prefix": { - "Trigger Prefix": "קידומת מפעיל" - }, - "Trigger: %1": { - "Trigger: %1": "מפעיל: %1" - }, - "Trust": { - "Trust": "מתן אמון" - }, - "Try a different search": { - "Try a different search": "נסה/י חיפוש אחר" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "כבה/י את כל המסכים מיד כאשר מסך הנעילה מופעל" - }, - "Turn off monitors after": { - "Turn off monitors after": "כבה/י את כל המסכים לאחר" - }, - "Type": { - "Type": "סוג" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "הקלד/י לפחות 2 תווים" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "הקלד/י קידומת זו לחיפוש קיצורי מקלדת" - }, - "Type to search files": { - "Type to search files": "הקלד/י לחיפוש קבצים" - }, - "Typography": { - "Typography": "טיפוגרפיה" - }, - "Typography & Motion": { - "Typography & Motion": "טיפוגרפיה ותנועה" - }, - "Unavailable": { - "Unavailable": "לא זמין" - }, - "Unfocused Color": { - "Unfocused Color": "צבע לא ממוקד" - }, - "Ungrouped": { - "Ungrouped": "לא בקבוצה" - }, - "Uninstall": { - "Uninstall": "הסר/י התקנה" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "הסר/י את מסך ההתחברות" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "הסר/י תוסף" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "ההסרה הושלמה. מסך ההתחברות הוסר." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "הסרת ההתקנה נכשלה: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "להסיר את מסך ההתחברות של DMS? זה יסיר את ההגדרות וישחזר את מנהל התצוגה הקודם שלך. ייפתח חלון מסוף לאימות עם sudo." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "הוסר: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "מסיר: %1" - }, - "Unknown": { - "Unknown": "לא ידוע" - }, - "Unknown App": { - "Unknown App": "אפליקציה לא ידועה" - }, - "Unknown Artist": { - "Unknown Artist": "אמן לא ידוע" - }, - "Unknown Config": { - "Unknown Config": "הגדרה לא ידועה" - }, - "Unknown Device": { - "Unknown Device": "התקן לא ידוע" - }, - "Unknown GPU": { - "Unknown GPU": "GPU לא ידוע" - }, - "Unknown Monitor": { - "Unknown Monitor": "מסך לא ידוע" - }, - "Unknown Network": { - "Unknown Network": "רשת לא ידועה" - }, - "Unknown Title": { - "Unknown Title": "כותרת לא ידועה" - }, - "Unknown Track": { - "Unknown Track": "רצועה לא ידועה" - }, - "Unload on Close": { - "Unload on Close": "פריקה בעת הסגירה" - }, - "Unmute": { - "Unmute": "בטל/י השתקה" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "בטל/י השתקת חלונות קופצים עבור %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "חוק ללא שם" - }, - "Unpair": { - "Unpair": "בטל/י צימוד" - }, - "Unpair failed": { - "Unpair failed": "ביטול הצימוד נכשל" - }, - "Unpin": { - "Unpin": "בטל/י הצמדה" - }, - "Unpin from Dock": { - "Unpin from Dock": "בטל/י נעיצה על הDock" - }, - "Unsaved Changes": { - "Unsaved Changes": "שינויים שלא נשמרו" - }, - "Unsaved changes": { - "Unsaved changes": "שינויים שלא נשמרו" - }, - "Unsaved note...": { - "Unsaved note...": "פתק שלא נשמר..." - }, - "Untitled": { - "Untitled": "ללא כותרת" - }, - "Untrust": { - "Untrust": "הסרת האמון" - }, - "Up to date": { - "Up to date": "מעודכן" - }, - "Update": { - "Update": "עדכן/י" - }, - "Update All": { - "Update All": "עדכן/י הכל" - }, - "Update Plugin": { - "Update Plugin": "עדכן/י תוסף" - }, - "Uptime": { - "Uptime": "זמן פעילות" - }, - "Uptime:": { - "Uptime:": "זמן פעילות:" - }, - "Urgent Color": { - "Urgent Color": "צבע דחוף" - }, - "Usage Tips": { - "Usage Tips": "טיפים לשימוש" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "השתמש/י בתבנית 24 שעות במקום 12 שעות (AM/PM)" - }, - "Use Custom Command": { - "Use Custom Command": "שימוש בפקודה מותאמת אישית" - }, - "Use Grid Layout": { - "Use Grid Layout": "שימוש בפריסת רשת" - }, - "Use IP Location": { - "Use IP Location": "שימוש במיקום לפי כתובת IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "שימוש ביחידות אימפריאליות" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "השתמש/י ביחידות אימפריאליות (°F, mph, inHg) במקום מטריות (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "השתמש/י בגופן ברוחב קבוע" - }, - "Use System Theme": { - "Use System Theme": "שימוש בערכת הנושא של המערכת" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "השתמש/י בתמונה מותאמת אישית למסך ההתחברות, או השאר/י ריק כדי להשתמש בתמונת הרקע של שולחן העבודה שלך." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "השתמש/י בכיוון צל קבוע עבור סרגל זה" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "השתמש/י במפתח אבטחה לאימות מסך הנעילה." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "השתמש/י במנהל רקעים חיצוני כמו hyprpaper, awww או swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "השתמש/י בסרגלי התקדמות מונפשים בצורת גלים לניגון מדיה" - }, - "Use custom border size": { - "Use custom border size": "השתמש/י בגודל מסגרת מותאם אישית" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "השתמש/י ברוחב מסגרת/טבעת מיקוד מותאם אישית" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "השתמש/י בפקודה מותאמת אישית לעדכון המערכת" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "השתמש/י במרווחים מותאמים אישית במקום בריווח של הסרגל" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "השתמש/י ברדיוס חלון מותאם אישית במקום ברדיוס של ערכת הנושא" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "השתמש/י בעיגול חלון מותאם אישית במקום ברדיוס של ערכת הנושא" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "שימוש ברקע של שולחן העבודה" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "השתמש/י באימות טביעת אצבע עבור מסך הנעילה." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "השתמש/י בערכת נושא בהירה במקום כהה" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "השתמש/י במטרים לשנייה במקום קמ\"ש למהירות רוח" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "השתמש/י בכרטיסי התראות קטנים יותר" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "השתמש/י בערכת הצלילים מהגדרות המערכת" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "השתמש/י באותו מיקום וגודל בכל המסכים" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "השתמש/י בקידומת מפעיל להפעלה" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "צבע שיעשה בו שימוש כאשר צבע ההדגשה מוגדר למותאם אישית" - }, - "User": { - "User": "משתמש" - }, - "Username": { - "Username": "שם משתמש" - }, - "Username...": { - "Username...": "שם משתמש..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "משתמש/ת בזמני זריחה/שקיעה על פי המיקום שלך." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "משתמש בזמני זריחה/שקיעה כדי לכוונן אוטומטית את מצב הלילה (גאמה) לפי המיקום שלך." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "משתמש/ת בהגדרות משותפות מבקרת גאמה" - }, - "Utilities": { - "Utilities": "כלי עזר" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "חיבורי VPN" - }, - "VPN Password": { - "VPN Password": "סיסמת VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "תצורת הVPN עודכנה" - }, - "VPN connections": { - "VPN connections": "חיבורי VPN" - }, - "VPN deleted": { - "VPN deleted": "הVPN נמחק" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN יובא: %1" - }, - "VPN not available": { - "VPN not available": "VPN אינו זמין" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "מצב הVPN וחיבור מהיר" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR במסך מלא בלבד" - }, - "VRR On-Demand": { - "VRR On-Demand": "לפי דרישה VRR" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "קצב רענון משתנה" - }, - "Verification": { - "Verification": "אימות" - }, - "Version": { - "Version": "גרסה" - }, - "Vertical Deck": { - "Vertical Deck": "חפיסה אנכית" - }, - "Vertical Grid": { - "Vertical Grid": "רשת אנכית" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "גלילה אנכית" - }, - "Vertical Tiling": { - "Vertical Tiling": "ריצוף אנכי" - }, - "Vibrant": { - "Vibrant": "תוסס" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "פלטת צבעים עשירה עם רוויה משחקית." - }, - "Video Path": { - "Video Path": "נתיב לוידאו" - }, - "Video Screensaver": { - "Video Screensaver": "שומר מסך עם וידאו" - }, - "Videos": { - "Videos": "סרטונים" - }, - "View Mode": { - "View Mode": "מצב תצוגה" - }, - "Visibility": { - "Visibility": "נראות" - }, - "Visual Effects": { - "Visual Effects": "אפקטים ויזואליים" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "מפריד חזותי בין ווידג׳טים" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "אפקט חזותי שיעשה בו שימוש בעת שינוי הרקע" - }, - "Volume": { - "Volume": "עוצמת קול" - }, - "Volume Changed": { - "Volume Changed": "עוצמת השמע השתנתה" - }, - "Volume Slider": { - "Volume Slider": "מחוון עוצמה" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "עוצמת שמע, בהירות ותצוגות מערכת (OSD) אחרות על המסך" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "תמונת רקע" - }, - "Wallpaper Error": { - "Wallpaper Error": "שגיאת תמונת רקע" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "מסך הרקע" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "מצב מילוי של תמונת הרקע" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "עיבוד תמונת הרקע נכשל" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "עיבוד תמונת הרקע נכשל - בדוק/י את נתיב הקובץ של הרקע" - }, - "Wallpapers": { - "Wallpapers": "רקעים" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "טמפרטורת צבע חמה להחלה" - }, - "Warning": { - "Warning": "אזהרה" - }, - "Warnings": { - "Warnings": "אזהרות" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "סרגלי התקדמות בצורת גל" - }, - "Weather": { - "Weather": "מזג אוויר" - }, - "Weather Widget": { - "Weather Widget": "ווידג׳ט מזג האוויר" - }, - "Welcome": { - "Welcome": "ברוכים הבאים" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "ברוכים הבאים לDankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "בעת לחיצה על חלון Dock בסביבת עבודה מיוחדת של Hyprland, החזר/י את סביבת העבודה המיוחדת הזו לפני המיקוד של החלון" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "כאשר האפשרות פעילה, האפליקציות ממוינות לפי סדר אלפביתי. כאשר היא כבויה, האפליקציות ממוינות לפי תדירות השימוש." - }, - "When locked": { - "When locked": "כאשר נעול" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "כאשר הווידג׳ט ״מעדכן המערכת״ נמצא בשימוש, הסתר/י אותו אם לא נמצאו עדכונים" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "סיסמת Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "חיבור Wi-Fi ו-Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi אינו זמין" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "התקן WiFi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "קוד QR לרשת הWiFi " - }, - "WiFi disabled": { - "WiFi disabled": "WiFi מושבת" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi פעיל" - }, - "WiFi is off": { - "WiFi is off": "הWi-Fi כבוי" - }, - "WiFi off": { - "WiFi off": "WiFi כבוי" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "רחב (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "צבע רקע לווידג׳טים" - }, - "Widget Management": { - "Widget Management": "ניהול ווידג׳טים" - }, - "Widget Outline": { - "Widget Outline": "מתאר לווידג׳טים" - }, - "Widget Style": { - "Widget Style": "סגנון לווידג׳טים" - }, - "Widget Styling": { - "Widget Styling": "עיצוב לווידג׳טים" - }, - "Widget Transparency": { - "Widget Transparency": "שקיפות לווידג׳טים" - }, - "Widget added": { - "Widget added": "הווידג׳ט נוסף" - }, - "Widget removed": { - "Widget removed": "הווידג׳ט הוסר" - }, - "Widgets": { - "Widgets": "ווידג׳טים" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "ווידג׳טים, פריסה, סגנון" - }, - "Width": { - "Width": "רוחב" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "רוחב מסגרת חלון (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "רוחב מסגרת חלון (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "רוחב מסגרת חלון וטבעת מיקוד" - }, - "Wind": { - "Wind": "רוח" - }, - "Wind Speed": { - "Wind Speed": "מהירות הרוח" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "מהירות רוח במ'/שנייה" - }, - "Window Corner Radius": { - "Window Corner Radius": "רדיוס הפינות של החלון" - }, - "Window Gaps": { - "Window Gaps": "מרווחי החלון" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "מרווחי החלון (בפיקסלים)" - }, - "Window Height": { - "Window Height": "גובה חלון" - }, - "Window Opening": { - "Window Opening": "פתיחת חלון" - }, - "Window Rounding": { - "Window Rounding": "עיגול החלון" - }, - "Window Rules": { - "Window Rules": "חוקי חלון" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "קובץ includes של חוקי חלון חסר" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "חוקי חלון אינם מוגדרים" - }, - "Wipe": { - "Wipe": "ניגוב" - }, - "Workspace": { - "Workspace": "סביבת עבודה" - }, - "Workspace Appearance": { - "Workspace Appearance": "המראה של סביבות העבודה" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "מספרי אינדקס של סביבות העבודה" - }, - "Workspace Names": { - "Workspace Names": "שמות לסביבות העבודה" - }, - "Workspace Padding": { - "Workspace Padding": "ריווח סביבת העבודה" - }, - "Workspace Settings": { - "Workspace Settings": "הגדרות סביבות העבודה" - }, - "Workspace Switcher": { - "Workspace Switcher": "מחליף סביבות העבודה" - }, - "Workspace name": { - "Workspace name": "שם סביבת העבודה" - }, - "Workspaces": { - "Workspaces": "סביבות עבודה" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "סביבות עבודה וווידג׳טים" - }, - "Write:": { - "Write:": "כתיבה:" - }, - "X Axis": { - "X Axis": "ציר X" - }, - "Y Axis": { - "Y Axis": "ציר Y" - }, - "Yes": { - "Yes": "כן" - }, - "Yesterday": { - "Yesterday": "אתמול" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "יש לך שינויים שלא נשמרו. האם ברצונך לשמור אותם לפני סגירת הכרטיסייה הזו?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "יש לך שינויים שלא נשמרו. האם ברצונך לשמור אותם לפני שממשיכים?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "יש לך שינויים שלא נשמרו. האם ברצונך לשמור לפני יצירת קובץ חדש?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "יש לך שינויים שלא נשמרו. האם ברצונך לשמור לפני פתיחת קובץ?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "עליך להגדיר את אחד מהמשתנים הבאים:\nQT_QPA_PLATFORMTHEME=gtk3 או\nQT_QPA_PLATFORMTHEME=qt6ct\nכמשתני סביבה ולאחר מכן להפעיל מחדש את DMS.\n\n* qt6ct דורש התקנה של qt6ct-kde." - }, - "You're All Set!": { - "You're All Set!": "הכל מוכן!" - }, - "Your system is up to date!": { - "Your system is up to date!": "המערכת שלך מעודכנת!" - }, - "actions": { - "actions": "פעולות" - }, - "attached": { - "attached": "מחובר" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "מאת %1" - }, - "days": { - "days": "ימים" - }, - "detached": { - "detached": "מנותק" - }, - "device": { - "device": "התקן" - }, - "devices connected": { - "devices connected": "התקנים מחוברים" - }, - "dgop not available": { - "dgop not available": "dgop אינו זמין" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "הפרויקט DMS הוא מעטפת שולחן עבודה מודרנית וניתנת להתאמה אישית עם עיצוב בהשראת Material Design 3 של גוגל.

        היא נבנתה עם שפת התכנות Go וQuickshell, ספריית QT6 לבניית מעטפות לשולחן העבודה." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "קובץ ההגדרה dms/cursor קיים אך אינו כלול. הגדרות סמן העכבר לא יחולו." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "קובץ ההגדרה dms/outputs קיים אך אינו כלול בהגדרות הקומפוזיטור שלך. שינויי תצוגה לא יישמרו." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "לדוגמא: firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "לדוגמא: focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "לדוגמה: notify-send 'Hello' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "לדוגמה, scratch, /^tmp_.*/, build" - }, - "events": { - "events": "אירועים" - }, - "ext": { - "ext": "ext" - }, - "featured": { - "featured": "מומלץ" - }, - "leave empty for default": { - "leave empty for default": "השאר/י ריק לברירת מחדל" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl אינו זמין, אינטגרציה של הנעילה דורשת חיבור socket לDMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "שרת הDiscord של mangowc" - }, - "mangowc GitHub": { - "mangowc GitHub": "הGitHub של mangowc" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen לא נמצא - התקן/י את החבילה של matugen כדי לאפשר עיצוב דינמי" - }, - "minutes": { - "minutes": "דקות" - }, - "ms": { - "ms": "מילישניות" - }, - "nav": { - "nav": "ניווט" - }, - "niri GitHub": { - "niri GitHub": "הGitHub של niri" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "שרת הMatrix של niri" - }, - "niri shortcuts config": { - "niri shortcuts config": "הגדרת קיצורים של Niri" - }, - "niri/dms Discord": { - "niri/dms Discord": "שרת הDiscord של niri/dms" - }, - "now": { - "now": "עכשיו" - }, - "official": { - "official": "רשמי" - }, - "on Hyprland": { - "on Hyprland": "על Hyprland" - }, - "on MangoWC": { - "on MangoWC": "על MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "על Miracle WM" - }, - "on Niri": { - "on Niri": "על Niri" - }, - "on Scroll": { - "on Scroll": "על Scroll" - }, - "on Sway": { - "on Sway": "על Sway" - }, - "open": { - "open": "פתח/י" - }, - "or run ": { - "or run ": "או הרץ/י " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon אינו זמין" - }, - "procs": { - "procs": "תהליכים" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri בReddit" - }, - "seconds": { - "seconds": "שניות" - }, - "source": { - "source": "קוד מקור" - }, - "this app": { - "this app": "אפליקציה זו" - }, - "up": { - "up": "פועל" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "עדכן/י את DMS כדי לאפשר אינטגרציה עם NM." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 מאת %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype אינו זמין - התקן/י את wtype כדי לאפשר תמיכה בהדבקה" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• התקן/י רק ממקורות מהימנים" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - חודש (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - חודש (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - חודש (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - חודש (January)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• תוספים עלולים להכיל באגים או בעיות אבטחה" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• בדוק/י את הקוד לפני ההתקנה ככל שניתן" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - יום (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - יום (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - שם יום (Mon)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - שם יום (Monday)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - שנה (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - שנה (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: ניווט • Space: הרחב • Enter: פעולה/הרחבה • E: טקסט" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: ניווט • Enter/Ctrl+C: העתקה • Del: מחיקה • F10: עזרה" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: ניווט • Enter: הדבקה • Del: מחיקה • F10: עזרה" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/hu.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/hu.json deleted file mode 100644 index 14734cf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/hu.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 Animáció sebessége" - }, - "%1 Sessions": { - "%1 Sessions": "%1 munkamenet" - }, - "%1 active session": { - "%1 active session": "%1 aktív munkamenet" - }, - "%1 active sessions": { - "%1 active sessions": "%1 aktív munkamenet" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 adapter, nincs csatlakoztatva" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 adapter, nincs csatlakoztatva" - }, - "%1 character": { - "%1 character": "%1 karakter" - }, - "%1 characters": { - "%1 characters": "%1 karakter" - }, - "%1 connected": { - "%1 connected": "%1 csatlakoztatva" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 egyéni animáció időtartama" - }, - "%1 disconnected": { - "%1 disconnected": "%1 leválasztva" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 leválasztva (rejtett)" - }, - "%1 display": { - "%1 display": "%1 kijelző" - }, - "%1 displays": { - "%1 displays": "%1 kijelző" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "A(z) %1 létezik, de nincs befoglalva a konfigurációba. Az egyéni gyorsbillentyűk nem fognak működni, amíg ezt nem lesz javítva." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 létezik, de nincs befoglalva. Az ablakszabályok nem fognak érvényesülni." - }, - "%1 filtered": { - "%1 filtered": "%1 szűrve" - }, - "%1 is now included in config": { - "%1 is now included in config": "A(z) %1 mostantól szerepel a konfigurációban" - }, - "%1 issue found": { - "%1 issue found": "%1 hiba található" - }, - "%1 issues found": { - "%1 issues found": "%1 hiba található" - }, - "%1 notifications": { - "%1 notifications": "%1 értesítés" - }, - "%1 update": { - "%1 update": "%1 frissítés" - }, - "%1 updates": { - "%1 updates": "%1 frissítés" - }, - "%1 variants": { - "%1 variants": "%1 variáns" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 háttérkép • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 háttérkép • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 widget" - }, - "%1 window": { - "%1 window": "%1 ablak" - }, - "%1 windows": { - "%1 windows": "%1 ablak" - }, - "%1m ago": { - "%1m ago": "%1 perccel ezelőtt" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "Az 'Alternatív' lehetővé teszi a kulccsal történő önálló feloldást. A 'Második faktor' először jelszót vagy ujjlenyomatot igényel, majd a kulcsot." - }, - "(Default)": { - "(Default)": "(Alapértelmezett)" - }, - "(Unnamed)": { - "(Unnamed)": "(Névtelen)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 további" - }, - "/path/to/videos": { - "/path/to/videos": "/elérési/út/videókhoz" - }, - "0 = square corners": { - "0 = square corners": "0 = szögletes sarkok" - }, - "1 day": { - "1 day": "1 nap" - }, - "1 device connected": { - "1 device connected": "1 eszköz csatlakoztatva" - }, - "1 event": { - "1 event": "1 esemény" - }, - "1 hour": { - "1 hour": "1 óra" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 óra 30 perc" - }, - "1 minute": { - "1 minute": "1 perc" - }, - "1 notification": { - "1 notification": "1 értesítés" - }, - "1 second": { - "1 second": "1 másodperc" - }, - "10 minutes": { - "10 minutes": "10 perc" - }, - "10 seconds": { - "10 seconds": "10 másodperc" - }, - "10-bit Color": { - "10-bit Color": "10 bites színmélység" - }, - "12 hours": { - "12 hours": "12 óra" - }, - "14 days": { - "14 days": "14 nap" - }, - "15 minutes": { - "15 minutes": "15 perc" - }, - "15 seconds": { - "15 seconds": "15 másodperc" - }, - "180°": { - "180°": "180 fok" - }, - "2 hours": { - "2 hours": "2 óra" - }, - "2 minutes": { - "2 minutes": "2 perc" - }, - "2 seconds": { - "2 seconds": "2 másodperc" - }, - "20 minutes": { - "20 minutes": "20 perc" - }, - "20 seconds": { - "20 seconds": "20 másodperc" - }, - "24-Hour Format": { - "24-Hour Format": "24 órás formátum" - }, - "24-hour clock": { - "24-hour clock": "24 órás óra" - }, - "24-hour format": { - "24-hour format": "24 órás formátum" - }, - "25 seconds": { - "25 seconds": "25 másodperc" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270 fok" - }, - "3 days": { - "3 days": "3 nap" - }, - "3 hours": { - "3 hours": "3 óra" - }, - "3 minutes": { - "3 minutes": "3 perc" - }, - "3 seconds": { - "3 seconds": "3 másodperc" - }, - "30 days": { - "30 days": "30 nap" - }, - "30 minutes": { - "30 minutes": "30 perc" - }, - "30 seconds": { - "30 seconds": "30 másodperc" - }, - "35 seconds": { - "35 seconds": "35 másodperc" - }, - "3rd party": { - "3rd party": "Külső" - }, - "4 hours": { - "4 hours": "4 óra" - }, - "4 seconds": { - "4 seconds": "4 másodperc" - }, - "40 seconds": { - "40 seconds": "40 másodperc" - }, - "45 seconds": { - "45 seconds": "45 másodperc" - }, - "5 minutes": { - "5 minutes": "5 perc" - }, - "5 seconds": { - "5 seconds": "5 másodperc" - }, - "50 seconds": { - "50 seconds": "50 másodperc" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 másodperc" - }, - "6 hours": { - "6 hours": "6 óra" - }, - "7 days": { - "7 days": "7 nap" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 óra" - }, - "8 seconds": { - "8 seconds": "8 másodperc" - }, - "90 days": { - "90 days": "90 nap" - }, - "90°": { - "90°": "90 fok" - }, - "MIT License": { - "MIT License": "MIT licenc" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Már létezik ilyen nevű fájl. Felül szeretnéd írni?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Egy modern asztali héj Wayland kompozitorokhoz" - }, - "AC Power": { - "AC Power": "Hálózati tápellátás" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Megszakítva" - }, - "About": { - "About": "Névjegy" - }, - "Accent Color": { - "Accent Color": "Hangsúlyszín" - }, - "Accept": { - "Accept": "Elfogadás" - }, - "Accept Jobs": { - "Accept Jobs": "Feladatok elfogadása" - }, - "Accepting": { - "Accepting": "Elfogadva" - }, - "Access clipboard history": { - "Access clipboard history": "Hozzáférés a vágólap előzményeihez" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Hozzáférés az értesítésekhez és a Ne zavarjanak üzemmódhoz" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Hozzáférés a rendszervezérlőkhöz és beállításokhoz" - }, - "Action": { - "Action": "Művelet" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "A művelet sikertelen, vagy a terminál bezárult." - }, - "Actions": { - "Actions": "Műveletek" - }, - "Activate": { - "Activate": "Aktiválás" - }, - "Activate Greeter": { - "Activate Greeter": "Üdvözlőképernyő aktiválása" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "Aktiválod a DMS-üdvözlőképernyőt? (greeter) Egy terminál fog megnyílni a sudo hitelesítéshez. Az aktiválás után futtasd a szinkronizálást a beállítások alkalmazásához." - }, - "Activation": { - "Activation": "Aktiválás" - }, - "Active": { - "Active": "Aktív" - }, - "Active Color": { - "Active Color": "Aktív szín" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Aktív zárolási képernyő monitor" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Aktív csempe háttér- és ikonszíne" - }, - "Active: %1": { - "Active: %1": "Aktív: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Aktív: %1 +%2" - }, - "Active: None": { - "Active: None": "Aktív: Nincs" - }, - "Adapters": { - "Adapters": "Adapterek" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Hozzáadás" - }, - "Add Bar": { - "Add Bar": "Sáv hozzáadása" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Asztali widget hozzáadása" - }, - "Add Printer": { - "Add Printer": "Nyomtató hozzáadása" - }, - "Add Title": { - "Add Title": "Cím hozzáadása" - }, - "Add Widget": { - "Add Widget": "Widget hozzáadása" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Widget hozzáadása a(z) %1. szekcióhoz" - }, - "Add a border around the dock": { - "Add a border around the dock": "Szegély hozzáadása a dokk körül" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Adj meg egy egyéni előtagot minden alkalmazás indításához. Ez használható például „uwsm-app”, „systemd-run” vagy más parancscsomagolókhoz." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Asztali widgetek hozzáadása és konfigurálása" - }, - "Add by Address": { - "Add by Address": "Hozzáadás cím alapján" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Oszlopok számának beállítása rácsnézet módban." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Hangerőállítás görgetési lépésenként" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "Beállítja a generált színek kontrasztját (-100 = minimum, 0 = normál, 100 = maximum)" - }, - "Advanced": { - "Advanced": "Speciális" - }, - "Afternoon": { - "Afternoon": "Délután" - }, - "All": { - "All": "Összes" - }, - "All Monitors": { - "All Monitors": "Minden monitor" - }, - "All checks passed": { - "All checks passed": "Minden ellenőrzés sikeres" - }, - "All day": { - "All day": "Egész nap" - }, - "All displays": { - "All displays": "Összes kijelző" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Kattintások átengedése a widgeten" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Vissza • F1/I: Fájlinformáció • F10: Súgó • Esc: Bezárás" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternatív (VAGY)" - }, - "Always Active": { - "Always Active": "Mindig aktív" - }, - "Always Show Percentage": { - "Always Show Percentage": "Mindig mutassa a százalékot" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "A dokk mindig rejtett, és csak akkor jelenik meg, ha az egérrel a közelébe mutatsz" - }, - "Always on icons": { - "Always on icons": "Mindig látható ikonok" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Mindig mutasson legalább 3 munkaterületet, még ha nincs is annyi" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Dokk megjelenítése mindig, ha a niri-áttekintés nyitva van" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Megjelenítés mindig, amikor csak egy csatlakoztatott kijelző van" - }, - "Amount": { - "Amount": "Mennyiség" - }, - "Analog": { - "Analog": "Analóg" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analóg, digitális vagy halmozott órakijelző" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Konfiguráció elemzése…" - }, - "Animation Duration": { - "Animation Duration": "Animáció időtartama" - }, - "Animation Speed": { - "Animation Speed": "Animáció sebessége" - }, - "Anonymous Identity": { - "Anonymous Identity": "Névtelen azonosító" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Névtelen azonosító (opcionális)" - }, - "App Customizations": { - "App Customizations": "Alkalmazás-testreszabások" - }, - "App ID Substitutions": { - "App ID Substitutions": "Alkalmazásazonosító-helyettesítések" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "App ID regex (pl. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Alkalmazásindító" - }, - "App Names": { - "App Names": "Alkalmazásnevek" - }, - "App Theming": { - "App Theming": "Alkalmazás témázása" - }, - "Appearance": { - "Appearance": "Megjelenés" - }, - "Application Dock": { - "Application Dock": "Alkalmazásdokk" - }, - "Applications": { - "Applications": "Alkalmazások" - }, - "Apply Changes": { - "Apply Changes": "Változtatások alkalmazása" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "GTK-színek alkalmazása" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Qt-színek alkalmazása" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Meleg színhőmérséklet alkalmazása a szem megerőltetésének csökkentése érdekében. Az alábbi automatizálási beállítások segítségével szabályozhatod, hogy mikor aktiválódjon." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "A hitelesítési módosítások alkalmazása…" - }, - "Apps": { - "Apps": "Alkalmazások" - }, - "Apps Dock": { - "Apps Dock": "Alkalmazásdokk" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Alkalmazásdokk beállításai" - }, - "Apps Icon": { - "Apps Icon": "Alkalmazások ikon" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Az alkalmazások használati gyakoriság, majd az utolsó használat ideje, végül betűrend szerint vannak rendezve." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Egyedi megjelenített névvel, ikonnal vagy indítási beállításokkal rendelkező alkalmazások. Kattints jobb gombbal egy alkalmazásra, és válaszd az „Alkalmazás szerkesztése” lehetőséget a testreszabáshoz." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Alkalmazások elnémított értesítési felugrókkal. A visszakapcsoláshoz hangosíts vissza vagy töröld őket." - }, - "Architecture": { - "Architecture": "Architektúra" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Biztosan le meg akarod szakítani a(z) „%1\" munkamenetet?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Képernyő-elrendezés és a felbontás, frissítési frekvencia, valamint VRR beállítása" - }, - "Attach": { - "Attach": "Csatlakozás" - }, - "Audio": { - "Audio": "Hang" - }, - "Audio Codec": { - "Audio Codec": "Hangkodek" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Hangkodek kiválasztása" - }, - "Audio Devices": { - "Audio Devices": "Hangeszközök" - }, - "Audio Input": { - "Audio Input": "Hangbemenet" - }, - "Audio Output": { - "Audio Output": "Hangkimenet" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Hangkimeneti eszközök (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Hangkimenet váltása" - }, - "Audio Visualizer": { - "Audio Visualizer": "Hangvizualizáló" - }, - "Audio system restarted": { - "Audio system restarted": "Hangrendszer újraindítva" - }, - "Audio volume control": { - "Audio volume control": "Hangerőszabályozó" - }, - "Auth": { - "Auth": "Hitelesítés" - }, - "Auth Type": { - "Auth Type": "Hitelesítés típusa" - }, - "Authenticate": { - "Authenticate": "Hitelesítés" - }, - "Authenticating...": { - "Authenticating...": "Hitelesítés…" - }, - "Authentication": { - "Authentication": "Hitelesítés" - }, - "Authentication Required": { - "Authentication Required": "Hitelesítés szükséges" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "A hitelesítési módosítások alkalmazva." - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "A hitelesítési módosítások automatikusan alkalmazásra kerülnek." - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "A hitelesítési módosítások automatikusan alkalmazásra kerülnek. A kizárólag ujjlenyomatos bejelentkezés nem biztos, hogy feloldja a kulcstartót." - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "A hitelesítési módosításokhoz sudo jogosultság szükséges. Terminál megnyitása a jelszó vagy ujjlenyomat használatához." - }, - "Authentication error - try again": { - "Authentication error - try again": "Hitelesítési hiba – próbáld újra" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "A hitelesítés sikertelen, próbáld újra" - }, - "Authorize": { - "Authorize": "Hitelesítés" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Párosítás engedélyezése ezzel: " - }, - "Authorize service for ": { - "Authorize service for ": "Szolgáltatás engedélyezése ehhez: " - }, - "Auto": { - "Auto": "Automatikus" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "Automatikus (sávérzékeny)" - }, - "Auto (Wide)": { - "Auto (Wide)": "Automatikus (széles)" - }, - "Auto Location": { - "Auto Location": "Automatikus helymeghatározás" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Automatikus felugró ablak rések" - }, - "Auto-Clear After": { - "Auto-Clear After": "Automatikus törlés" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Automatikus elrejtés időtúllépése" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "A Niri-áttekintés automatikus bezárása alkalmazások indításakor." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Ennél régebbi értesítések automatikus törlése" - }, - "Auto-hide": { - "Auto-hide": "Automatikus elrejtés" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Dokk automatikus elrejtése" - }, - "Auto-saving...": { - "Auto-saving...": "Automatikus mentés…" - }, - "Autoconnect": { - "Autoconnect": "Automatikus csatlakozás" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Automatikus csatlakozás letiltva" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Automatikus csatlakozás engedélyezve" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "Megnyitáskor az utoljára megjegyzett lekérdezés automatikus kitöltése" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Automatikus színmód" - }, - "Automatic Control": { - "Automatic Control": "Automatikus vezérlés" - }, - "Automatic Cycling": { - "Automatic Cycling": "Automatikus váltás" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Automatikus váltás az ugyanabban a mappában lévő háttérképek között" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Az ennél régebbi bejegyzések automatikus törlése" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Hely automatikus észlelése IP-cím alapján" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Tartózkodási hely meghatározása IP-cím segítségével" - }, - "Automatically lock after": { - "Automatically lock after": "Automatikus zárolás" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Képernyő automatikus zárolása a DMS indulásakor" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "A képernyő automatikus zárolása, amikor a rendszer felfüggesztésre készül" - }, - "Automation": { - "Automation": "Automatizálás" - }, - "Available": { - "Available": "Elérhető" - }, - "Available Layouts": { - "Available Layouts": "Elérhető elrendezések" - }, - "Available Networks": { - "Available Networks": "Elérhető hálózatok" - }, - "Available Plugins": { - "Available Plugins": "Elérhető bővítmények" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Elérhető kijelzők (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Részletes és Előrejelzés nézetmódokban érhető el" - }, - "Available.": { - "Available.": "Elérhető." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Vissza" - }, - "Backend": { - "Backend": "Háttérrendszer" - }, - "Background": { - "Background": "Háttér" - }, - "Background Blur": { - "Background Blur": "Háttér elmosása" - }, - "Background Opacity": { - "Background Opacity": "Háttér átlátszósága" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "A háttérbeli hitelesítési szinkronizálás sikertelen. Próbálkozás terminál módban." - }, - "Background image": { - "Background image": "Háttérkép" - }, - "Backlight device": { - "Backlight device": "Háttérvilágítás eszköz" - }, - "Balance power and performance": { - "Balance power and performance": "Energiafogyasztás és teljesítmény egyensúlya" - }, - "Balanced": { - "Balanced": "Kiegyensúlyozott" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Kiegyensúlyozott paletta fókuszált kiemelésekkel (alapértelmezett)." - }, - "Bar Configurations": { - "Bar Configurations": "Sáv konfiguráció" - }, - "Bar Shadows": { - "Bar Shadows": "Sáv árnyékai" - }, - "Bar Transparency": { - "Bar Transparency": "Sáv átlátszósága" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Az árnyékok alapszíne (az áttetszőség automatikusan alkalmazva)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Animációk alapértelmezett időtartama (húzd az egyéni beállításhoz)" - }, - "Battery": { - "Battery": "Akkumulátor" - }, - "Battery %1": { - "Battery %1": "Akkumulátor: %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Akkumulátor töltési korlát" - }, - "Battery and power management": { - "Battery and power management": "Akkumulátor- és energiakezelés" - }, - "Battery level and power management": { - "Battery level and power management": "Akkumulátor töltöttségi szintje és energiagazdálkodás" - }, - "Behavior": { - "Behavior": "Viselkedés" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "A zárolási képernyő kötése a loginctl dbus jeleihez. Tiltsd le, ha külső zárolási képernyőt használsz" - }, - "Binds Include Missing": { - "Binds Include Missing": "A kötések include bejegyzés hiányzik" - }, - "Binds include added": { - "Binds include added": "A kötések include bejegyzés hozzáadva" - }, - "Bit Depth": { - "Bit Depth": "Színmélység" - }, - "Block Out": { - "Block Out": "Kizárás" - }, - "Block Out From": { - "Block Out From": "Kizárás innen" - }, - "Block notifications": { - "Block notifications": "Értesítések tiltása" - }, - "Blocked": { - "Blocked": "Tiltva" - }, - "Blue light filter": { - "Blue light filter": "Kék fény szűrő" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth-beállítások" - }, - "Bluetooth not available": { - "Bluetooth not available": "A Bluetooth nem elérhető" - }, - "Blur Border Color": { - "Blur Border Color": "Elmosás szegélyszíne" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "Elmosás szegélyének átlátszatlansága" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Háttérkép elmosási réteg" - }, - "Blur on Overview": { - "Blur on Overview": "Elmosás az áttekintésben" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "A sávok, felugró ablakok, modális ablakok és értesítések mögötti háttér elmosása. Kompozitor támogatást és beállítást igényel." - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Háttérkép elmosása, ha a niri-áttekintés nyitva van" - }, - "Body": { - "Body": "Szövegtörzs" - }, - "Border": { - "Border": "Szegély" - }, - "Border Color": { - "Border Color": "Szegély színe" - }, - "Border Opacity": { - "Border Opacity": "Szegély átlátszósága" - }, - "Border Size": { - "Border Size": "Keretméret" - }, - "Border Thickness": { - "Border Thickness": "Szegély vastagsága" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "Szegélyszín az elmosott felületek körül" - }, - "Border with BG": { - "Border with BG": "Szegély háttérrel" - }, - "Bottom": { - "Bottom": "Alul" - }, - "Bottom Center": { - "Bottom Center": "Alul középen" - }, - "Bottom Left": { - "Bottom Left": "Bal Lent" - }, - "Bottom Right": { - "Bottom Right": "Jobb Lent" - }, - "Bottom Section": { - "Bottom Section": "Alsó rész" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Alsó dokk a rögzített és a futó alkalmazásoknak" - }, - "Brightness": { - "Brightness": "Fényerő" - }, - "Brightness Slider": { - "Brightness Slider": "Fényerőszabályozó" - }, - "Brightness Value": { - "Brightness Value": "Fényerő értéke" - }, - "Brightness control not available": { - "Brightness control not available": "A fényerőszabályozás nem elérhető" - }, - "Browse": { - "Browse": "Böngészés" - }, - "Browse Files": { - "Browse Files": "Fájlok böngészése" - }, - "Browse Plugins": { - "Browse Plugins": "Bővítmények böngészése" - }, - "Browse Themes": { - "Browse Themes": "Témák böngészése" - }, - "Browse or search plugins": { - "Browse or search plugins": "Bővítmények tallózása vagy keresése" - }, - "Button Color": { - "Button Color": "Gomb színe" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU-grafikon" - }, - "CPU Temperature": { - "CPU Temperature": "CPU-hőmérséklet" - }, - "CPU Usage": { - "CPU Usage": "CPU-használat" - }, - "CPU temperature display": { - "CPU temperature display": "CPU-hőmérséklet kijelző" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU-kihasználtság jelző" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU, memória, hálózat és lemez figyelése" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS nem biztonságos szűrő figyelmeztetés" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS hiányzó szűrő figyelmeztetés" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS nyomtatókiszolgáló" - }, - "CUPS not available": { - "CUPS not available": "CUPS nem elérhető" - }, - "Camera": { - "Camera": "Kamera" - }, - "Cancel": { - "Cancel": "Mégse" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Összes feladat megszakítása ennél: „%1”?" - }, - "Canceled": { - "Canceled": "Törölve" - }, - "Cannot pair": { - "Cannot pair": "Nem lehet párosítani" - }, - "Capabilities": { - "Capabilities": "Képességek" - }, - "Capacity": { - "Capacity": "Kapacitás" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Caps Lock-jelző" - }, - "Caps Lock is on": { - "Caps Lock is on": "A Caps Lock be van kapcsolva" - }, - "Center Section": { - "Center Section": "Középső rész" - }, - "Center Single Column": { - "Center Single Column": "Középső egyoszlopos" - }, - "Center Tiling": { - "Center Tiling": "Központi csempézés" - }, - "Certificate Password": { - "Certificate Password": "Tanúsítvány jelszava" - }, - "Change Song": { - "Change Song": "Dalváltás" - }, - "Change Volume": { - "Change Volume": "Hangerő módosítása" - }, - "Change bar appearance": { - "Change bar appearance": "Sáv megjelenésének megváltoztatása" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "A DMS felület által használt területi beállítás módosítása." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "A dátum- és időformátumhoz használt területi beállítás módosítása, a felület nyelvétől függetlenül." - }, - "Channel": { - "Channel": "Csatorna" - }, - "Charging": { - "Charging": "Töltés" - }, - "Check for system updates": { - "Check for system updates": "Rendszerfrissítések keresése" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "Szinkronizálási állapot ellenőrzése igény szerint. A szinkronizálás átmásolja a témát, a beállításokat és a háttérkép konfigurációját a bejelentkezési képernyőre. A hitelesítési módosítások automatikusan alkalmazásra kerülnek." - }, - "Checking for updates...": { - "Checking for updates...": "Frissítések keresése…" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Sudo hitelesítés szükségességének ellenőrzése…" - }, - "Checking...": { - "Checking...": "Ellenőrzés…" - }, - "Checking…": { - "Checking…": "Ellenőrzés…" - }, - "Choose Color": { - "Choose Color": "Szín választása" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Sötét mód színének kiválasztása" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Dokkindító-logó színének kiválasztása" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Indítóikon színének kiválasztása" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Világos mód színének kiválasztása" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Háttérkép színének kiválasztása" - }, - "Choose a color": { - "Choose a color": "Válassz színt" - }, - "Choose colors from palette": { - "Choose colors from palette": "Színek választása a palettáról" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Válaszd ki az időjárás widget megjelenítési módját" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Válaszd ki, hogyan határozza meg ez a sáv az árnyék irányát" - }, - "Choose icon": { - "Choose icon": "Ikon kiválasztása" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Válaszd ki a widgetek háttérszínét" - }, - "Choose the border accent color": { - "Choose the border accent color": "Válaszd ki a szegély kiemelőszínét" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Válaszd ki a DankBar indítógombján megjelenő logót" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "A felugró értesítések megjelenési helye" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "A képernyőkijelzők megjelenítési helye" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Válaszd ki, mely kijelzők mutassák ezt a widgetet" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Válaszd ki, melyik monitor jelenítse meg a zárolási képernyő felületét. A többi monitor egy színt fog mutatni az OLED beégés elleni védelem miatt." - }, - "Chroma Style": { - "Chroma Style": "Chroma stílus" - }, - "Cipher": { - "Cipher": "Titkosítás" - }, - "Circle": { - "Circle": "Kör" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Osztály (Class) regex (pl. ^firefox$)" - }, - "Clear": { - "Clear": "Törlés" - }, - "Clear All": { - "Clear All": "Összes törlése" - }, - "Clear All Jobs": { - "Clear All Jobs": "Összes feladat törlése" - }, - "Clear History?": { - "Clear History?": "Törlöd az előzményeket?" - }, - "Clear Sky": { - "Clear Sky": "Tiszta égbolt" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Minden előzmény törlése a kiszolgáló indulásakor" - }, - "Clear at Startup": { - "Clear at Startup": "Törlés indításkor" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Kattints a „Beállítás” gombra a(z) %1 létrehozásához és a konfigurációhoz való hozzáadásához." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Kattints a „Beállítás” gombra a %1 létrehozásához és az include bejegyzés hozzáadásához a kompozitor konfigurációhoz." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Kattints a „Beállítás” gombra a kurzor konfiguráció létrehozásához és az include bejegyzés hozzáadásához a kompozitor beállításaihoz." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Kattints a „Beállítás” gombra a kimenetek konfiguráció létrehozásához és az include bejegyzés hozzáadásához a kompozitor konfigurációjához." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Kattints az importálás gombra .ovpn vagy .conf fájl hozzáadásához" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Kattints a Frissítés gombra az állapot ellenőrzéséhez." - }, - "Click Through": { - "Click Through": "Átkattintás" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Kattints bármelyik parancsikonra a szerkesztéshez. A módosítások a(z) %1 fájlba lesznek mentve." - }, - "Click to capture": { - "Click to capture": "Kattints a rögzítéshez" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Kattints egy egyéni téma JSON fájl kiválasztásához" - }, - "Clip": { - "Clip": "Vágás" - }, - "Clip to Geometry": { - "Clip to Geometry": "Vágás a geometriához" - }, - "Clipboard": { - "Clipboard": "Vágólap" - }, - "Clipboard History": { - "Clipboard History": "Vágólapelőzmények" - }, - "Clipboard Manager": { - "Clipboard Manager": "Vágólapkezelő" - }, - "Clipboard sent": { - "Clipboard sent": "Vágólap elküldve" - }, - "Clipboard service not available": { - "Clipboard service not available": "A vágólap szolgáltatások nem elérhetők" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "A vágólap működni fog, de nem lesz a lemezre mentve semmi" - }, - "Clock": { - "Clock": "Óra" - }, - "Clock Style": { - "Clock Style": "Órastílius" - }, - "Close": { - "Close": "Bezárás" - }, - "Close All Windows": { - "Close All Windows": "Összes ablak bezárása" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Áttekintés bezárása indításkor" - }, - "Close Window": { - "Close Window": "Ablak bezárása" - }, - "Color": { - "Color": "Szín" - }, - "Color Gamut": { - "Color Gamut": "Színtér" - }, - "Color Management": { - "Color Management": "Színkezelés" - }, - "Color Mode": { - "Color Mode": "Színmód" - }, - "Color Override": { - "Color Override": "Színfelülírás" - }, - "Color Picker": { - "Color Picker": "Színválasztó" - }, - "Color Temperature": { - "Color Temperature": "Színhőmérséklet" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Szín, amely a zárolási képernyő nélküli monitorokon jelenik meg" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Elsődleges akciógombok színe" - }, - "Color temperature for day time": { - "Color temperature for day time": "Színhőmérséklet a nappali módhoz" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Színhőmérséklet az éjszakai módhoz" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Színtéma a szintaxiskiemeléshez." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Színtéma a szintaxiskiemeléshez. %1 téma érhető el." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Színtéma a DMS-regiszterből" - }, - "Colorful": { - "Colorful": "Színes" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Színes keverék, fényes kontrasztos kiemelésekkel." - }, - "Colorize Active": { - "Colorize Active": "Aktív színezése" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Színek a háttérképből" - }, - "Column": { - "Column": "Oszlop" - }, - "Column Display": { - "Column Display": "Oszlopos megjelenítés" - }, - "Column Width": { - "Column Width": "Oszlopszélesség" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "Vesszővel elválasztott lista az elrejtendő munkamenet-nevekről. Reguláris kifejezésekhez (regex) tedd perjelek közé (pl. /^_.*/)." - }, - "Command": { - "Command": "Parancs" - }, - "Commands": { - "Commands": "Parancsok" - }, - "Communication": { - "Communication": "Kommunikáció" - }, - "Community themes": { - "Community themes": "Közösségi témák" - }, - "Compact": { - "Compact": "Kompakt" - }, - "Compact Mode": { - "Compact Mode": "Kompakt mód" - }, - "Completed": { - "Completed": "Befejezve" - }, - "Compositor": { - "Compositor": "Kompozitor" - }, - "Compositor Settings": { - "Compositor Settings": "Kompozitorbeállítások" - }, - "Compositor not supported": { - "Compositor not supported": "A kompozitor nem támogatott" - }, - "Config Format": { - "Config Format": "Konfigurációformátum" - }, - "Config action: %1": { - "Config action: %1": "Konfigurációs művelet: %1" - }, - "Config validation failed": { - "Config validation failed": "Nem sikerült ellenőrizni a konfigurációt" - }, - "Configuration": { - "Configuration": "Konfiguráció" - }, - "Configuration activated": { - "Configuration activated": "Konfiguráció aktiválva" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "A konfiguráció megmarad, amikor ez a kijelző újra csatlakozik" - }, - "Configure": { - "Configure": "Beállítás" - }, - "Configure Keybinds": { - "Configure Keybinds": "Billentyűkombinációk beállítása" - }, - "Configure a new printer": { - "Configure a new printer": "Új nyomtató konfigurálása" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Ikonok konfigurálása a megnevezett munkaterületekhez. Az ikonok előnyt élveznek a számokkal szemben, ha mindkettő engedélyezve van." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Illesztési feltételek és műveletek konfigurálása" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Mely kijelzők mutassák ezt: „%1”" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Mely kijelzőkön jelenjenek meg a héj összetevői" - }, - "Confirm": { - "Confirm": "Megerősítés" - }, - "Confirm Delete": { - "Confirm Delete": "Törlés megerősítése" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Kijelzőváltoztatások megerősítése" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Párosítási kód megerősítése ehhez: " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Ütközik ezzel: %1" - }, - "Connect": { - "Connect": "Csatlakozás" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Csatlakozás rejtett hálózathoz" - }, - "Connect to VPN": { - "Connect to VPN": "Csatlakozás VPN-hez" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Csatlakozás a Wi-Fi-hez" - }, - "Connected": { - "Connected": "Csatlakoztatva" - }, - "Connected Device": { - "Connected Device": "Csatlakoztatott eszköz" - }, - "Connected Displays": { - "Connected Displays": "Csatlakoztatott kijelzők" - }, - "Connecting to Device": { - "Connecting to Device": "Csatlakozás az eszközhöz" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Csatlakozás…" - }, - "Connection failed": { - "Connection failed": "Kapcsolódás sikertelen" - }, - "Contains": { - "Contains": "Tartalmazza" - }, - "Content": { - "Content": "Tartalom" - }, - "Content copied": { - "Content copied": "Tartalom másolva" - }, - "Contrast": { - "Contrast": "Kontraszt" - }, - "Control Center": { - "Control Center": "Vezérlőközpont" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Vezérlőközpont csempeszíne" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Az értesítési felugró ablakok és az előzmények animációs időtartama" - }, - "Control currently playing media": { - "Control currently playing media": "Jelenleg játszott média vezérlése" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Milyen értesítési információk jelenjenek meg a zárolási képernyőn" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Mely bővítmények jelenjenek meg „Összes” módban indító előtag nélkül. Húzd az átrendezéshez." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Munkaterületek és oszlopok vezérlése görgetéssel a sávon" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Az összes felugró ablak, kizárólagos párbeszédablak és tartalomréteg átlátszósága" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "Az árnyékvetés iránya a kiemelési rétegekhez" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "Az árnyékok alap elmosási sugara és eltolása" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Az árnyék átlátszósága" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Kényelmi beállítások a bejelentkezési képernyőhöz. Szinkronizálj az alkalmazáshoz." - }, - "Cooldown": { - "Cooldown": "Várakozási idő" - }, - "Copied GIF": { - "Copied GIF": "GIF másolva" - }, - "Copied MP4": { - "Copied MP4": "MP4 másolva" - }, - "Copied WebP": { - "Copied WebP": "WebP másolva" - }, - "Copied to clipboard": { - "Copied to clipboard": "Másolva a vágólapra" - }, - "Copied!": { - "Copied!": "Másolva!" - }, - "Copy": { - "Copy": "Másolás" - }, - "Copy Content": { - "Copy Content": "Tartalom másolása" - }, - "Copy Full Command": { - "Copy Full Command": "Teljes parancs másolása" - }, - "Copy HTML": { - "Copy HTML": "HTML másolása" - }, - "Copy Name": { - "Copy Name": "Név másolása" - }, - "Copy PID": { - "Copy PID": "PID másolása" - }, - "Copy Text": { - "Copy Text": "Szöveg másolása" - }, - "Copy path": { - "Copy path": "Útvonal másolása" - }, - "Corner Radius": { - "Corner Radius": "Sarokkerekítés" - }, - "Corner Radius Override": { - "Corner Radius Override": "Sarokkerekítés felülbírálása" - }, - "Corners & Background": { - "Corners & Background": "Sarkok és háttér" - }, - "Count Only": { - "Count Only": "Csak darabszám" - }, - "Cover Open": { - "Cover Open": "Fedél nyitva" - }, - "Create": { - "Create": "Létrehozás" - }, - "Create Dir": { - "Create Dir": "Mappa létrehozása" - }, - "Create Printer": { - "Create Printer": "Nyomtató létrehozása" - }, - "Create Window Rule": { - "Create Window Rule": "Ablakszabály létrehozása" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Új %1 munkamenet létrehozása (n)" - }, - "Create rule for:": { - "Create rule for:": "Szabály létrehozása ehhez:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Szabályokat hozhatsz létre a némításhoz, figyelmen kívül hagyáshoz, az előzményekből való elrejtéshez vagy az értesítések prioritásának felülbírálásához. Az alapértelmezett beállítás csak a prioritást bírálja felül; az értesítések továbbra is normálisan megjelennek." - }, - "Creating...": { - "Creating...": "Létrehozás…" - }, - "Critical Priority": { - "Critical Priority": "Kritikus prioritás" - }, - "Current": { - "Current": "Jelenlegi" - }, - "Current Items": { - "Current Items": "Jelenlegi elemek" - }, - "Current Locale": { - "Current Locale": "Jelenlegi területi beállítás" - }, - "Current Monitor": { - "Current Monitor": "Jelenlegi monitor" - }, - "Current Period": { - "Current Period": "Jelenlegi időszak" - }, - "Current Status": { - "Current Status": "Jelenlegi állapot" - }, - "Current Temp": { - "Current Temp": "Jelenlegi hőmérséklet" - }, - "Current Theme: %1": { - "Current Theme: %1": "Jelenlegi téma: %1" - }, - "Current Weather": { - "Current Weather": "Jelenlegi időjárás" - }, - "Current Workspace": { - "Current Workspace": "Jelenlegi munkaterület" - }, - "Current time and date display": { - "Current time and date display": "Jelenlegi idő- és dátumkijelzés" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Jelenlegi időjárási viszonyok és hőmérséklet" - }, - "Current: %1": { - "Current: %1": "Jelenleg: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Kurzor konfiguráció nincs beállítva" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "A mutató include bejegyzés hiányzik" - }, - "Cursor Size": { - "Cursor Size": "Kurzorméret" - }, - "Cursor Theme": { - "Cursor Theme": "Kurzortéma" - }, - "Custom": { - "Custom": "Egyéni" - }, - "Custom Color": { - "Custom Color": "Egyéni szín" - }, - "Custom Duration": { - "Custom Duration": "Egyéni időtartam" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Egyéni hibernálási parancs" - }, - "Custom Location": { - "Custom Location": "Egyéni tartózkodási hely" - }, - "Custom Lock Command": { - "Custom Lock Command": "Egyéni zárolási parancs" - }, - "Custom Logout Command": { - "Custom Logout Command": "Egyéni kijelentkezési parancs" - }, - "Custom Name": { - "Custom Name": "Egyéni név" - }, - "Custom Power Actions": { - "Custom Power Actions": "Egyéni főkapcsoló műveletek" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Egyéni kikapcsolási parancs" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Egyéni újraindítási parancs" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Egyéni árnyékszín" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Egyéni árnyék felülbírálása" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Egyéni felfüggesztési parancs" - }, - "Custom Transparency": { - "Custom Transparency": "Egyéni átlátszóság" - }, - "Custom power profile": { - "Custom power profile": "Egyéni energiaprofil" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "JSON fájlból betöltött egyéni téma" - }, - "Custom...": { - "Custom...": "Egyéni…" - }, - "Custom: ": { - "Custom: ": "Egyéni: " - }, - "Customizable empty space": { - "Customizable empty space": "Testre szabható üres hely" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "A főkapcsoló menüben megjelenő műveletek testreszabása" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI monitor" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMO MÓD - Kattints bárhova a kilépéshez" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "A DMS-bővítménykezelő nem elérhető" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS gyorsbillentyűk" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "A DMS-üdvözlőképernyőnek (greeter) szüksége van a következőkre: greetd, dms-greeter. Ujjlenyomat: fprintd, pam_fprintd. Biztonsági kulcsok: pam_u2f. Add hozzá a felhasználódat a greeter csoporthoz. A hitelesítési módosítások automatikusan alkalmazásra kerülnek, és terminált nyithatnak meg, ha sudo hitelesítés szükséges." - }, - "DMS out of date": { - "DMS out of date": "A DMS elavult" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "A DMS-szolgáltatás nincs csatlakoztatva. A vágólapbeállítások nem elérhetők." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS héj-műveletek (indító, vágólap, stb.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "A DMS_SOCKET nem elérhető" - }, - "DWL service not available": { - "DWL service not available": "A DWL szolgáltatás nem elérhető" - }, - "Daily": { - "Daily": "Napi" - }, - "Daily at:": { - "Daily at:": "Naponta ekkor:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "A DankMaterialShell használatra kész" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell és Rendszerikonok (újraindítást igényel)" - }, - "Dark Mode": { - "Dark Mode": "Sötét mód" - }, - "Dark mode base": { - "Dark mode base": "Sötét mód (alap)" - }, - "Dark mode harmony": { - "Dark mode harmony": "Sötét mód (harmónia)" - }, - "Darken Modal Background": { - "Darken Modal Background": "Kizárólagos ablak háttérének sötétítése" - }, - "Date Format": { - "Date Format": "Dátumformátum" - }, - "Date format": { - "Date format": "Dátumformátum" - }, - "Date format on greeter": { - "Date format on greeter": "Dátumformátum az üdvözlőképernyőn" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Csillagászati hajnal" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Polgári hajnal" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Navigációs hajnal" - }, - "Day Date": { - "Day Date": "Nap, dátum" - }, - "Day Month Date": { - "Day Month Date": "Nap, hónap, dátum" - }, - "Day Temperature": { - "Day Temperature": "Nappali hőmérséklet" - }, - "Daytime": { - "Daytime": "Nappal" - }, - "Deck": { - "Deck": "Köteg" - }, - "Default": { - "Default": "Alapértelmezett" - }, - "Default (Black)": { - "Default (Black)": "Alapértelmezett (Fekete)" - }, - "Default Width (%)": { - "Default Width (%)": "Alapértelmezett szélesség (%)" - }, - "Default selected action": { - "Default selected action": "Alapértelmezett kiválasztott művelet" - }, - "Defaults": { - "Defaults": "Alapértelmezés" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Ablakviselkedési szabályok meghatározása. Mentés ide: %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Törlés • Shift+Del: Összes törlése • 1-9: Műveletek • F10: Súgó • Esc: Bezárás" - }, - "Delete": { - "Delete": "Törlés" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Törlöd ezt: „%1”?" - }, - "Delete Class": { - "Delete Class": "Osztály törlése" - }, - "Delete Printer": { - "Delete Printer": "Nyomtató törlése" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Mentett elem törlése?" - }, - "Delete VPN": { - "Delete VPN": "VPN törlése" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Törlöd a(z) „%1” osztályt?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Törlöd a(z) „%1” profilt?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Függőségek és dokumentáció" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Az alapul szolgáló képhez szorosan illeszkedő színek levezetése." - }, - "Description": { - "Description": "Leírás" - }, - "Desktop": { - "Desktop": "Asztal" - }, - "Desktop Clock": { - "Desktop Clock": "Asztali óra" - }, - "Desktop Entry": { - "Desktop Entry": "Asztali bejegyzés" - }, - "Desktop Widget": { - "Desktop Widget": "Asztali widget" - }, - "Desktop Widgets": { - "Desktop Widgets": "Asztali widgetek" - }, - "Desktop background images": { - "Desktop background images": "Asztali háttérképek" - }, - "Detailed": { - "Detailed": "Részletes" - }, - "Details for \"%1": { - "Details for \"%1\"": "„%1\" részletei" - }, - "Development": { - "Development": "Fejlesztés" - }, - "Device": { - "Device": "Eszköz" - }, - "Device connections": { - "Device connections": "Eszköz csatlakozások" - }, - "Device names updated": { - "Device names updated": "Eszköznevek frissítve" - }, - "Device paired": { - "Device paired": "Eszköz párosítva" - }, - "Device unpaired": { - "Device unpaired": "Eszköz párosítása megszüntetve" - }, - "Digital": { - "Digital": "Digitális" - }, - "Direction Source": { - "Direction Source": "Irány forrása" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Automatikus csatlakozás letiltása" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Beépített háttérképek letiltása" - }, - "Disable History Persistence": { - "Disable History Persistence": "Előzménymentés letiltása" - }, - "Disable Output": { - "Disable Output": "Kimenet letiltása" - }, - "Disabled": { - "Disabled": "Letiltva" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Wi-Fi kikapcsolása…" - }, - "Disc": { - "Disc": "Lemez" - }, - "Discard": { - "Discard": "Elvetés" - }, - "Discharging": { - "Discharging": "Merülés" - }, - "Disconnect": { - "Disconnect": "Lecsatlakozás" - }, - "Disconnected": { - "Disconnected": "Leválasztva" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Lecsatlakozva a Wi-Fi-ről" - }, - "Discover Devices": { - "Discover Devices": "Eszközök felderítése" - }, - "Disk": { - "Disk": "Lemez" - }, - "Disk I/O": { - "Disk I/O": "Lemez I/O" - }, - "Disk Usage": { - "Disk Usage": "Lemezhasználat" - }, - "Disk Usage Display": { - "Disk Usage Display": "Lemezhasználat megjelenítése" - }, - "Disks": { - "Disks": "Lemezek" - }, - "Dismiss": { - "Dismiss": "Bezárás" - }, - "Display": { - "Display": "Kijelző" - }, - "Display Assignment": { - "Display Assignment": "Kijelző-hozzárendelés" - }, - "Display Control": { - "Display Control": "Kijelzővezérlés" - }, - "Display Name Format": { - "Display Name Format": "Kijelzőnév formátuma" - }, - "Display Profiles": { - "Display Profiles": "Kijelzőprofilok" - }, - "Display Settings": { - "Display Settings": "Kijelzőbeállítások" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Dokk megjelenítése rögzített és futó alkalmazásokkal" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Minden prioritás megjelenítése a teljes képernyős alkalmazások felett" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "DWL elrendezések megjelenítése és váltása" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Alkalmazás ikonok megjelenítése a munkaterület-jelzőkben" - }, - "Display brightness control": { - "Display brightness control": "A kijelző fényerejének szabályozásása" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Kijelző konfiguráció nem elérhető. A WLR kimenetkezelési protokoll nem támogatott." - }, - "Display currently focused application title": { - "Display currently focused application title": "Jelenleg fókuszban lévő alkalmazás címének megjelenítése" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Óránkénti időjárás-előrejelzés megjelenítése" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Csak azokat a munkaterületeket jelenítse meg, amelyek ablakokat tartalmaznak" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Főkapcsoló menü műveletek megjelenítése rácsban lista helyett" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Másodpercek megjelenítése az órán" - }, - "Display the power system menu": { - "Display the power system menu": "A főkapcsoló rendszermenüjének megjelenítése" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Hangerő és fényerő százalékos értékek megjelenítése a képernyőkijelző felugró ablakokban" - }, - "Displays": { - "Displays": "Kijelzők" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Kijelzők száma, ha a túlcsordulás aktív" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Megjeleníti az aktív billentyűzetkiosztást és lehetővé teszi a váltást" - }, - "Distribution": { - "Distribution": "Disztribúció" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Változatos paletta, amely a teljes spektrumot lefedi." - }, - "Do Not Disturb": { - "Do Not Disturb": "Ne zavarjanak" - }, - "Dock": { - "Dock": "Dokk" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dokk és indító" - }, - "Dock Transparency": { - "Dock Transparency": "Dokk átlátszóság" - }, - "Dock Visibility": { - "Dock Visibility": "Dokk láthatósága" - }, - "Docs": { - "Docs": "Dokumentumok" - }, - "Documents": { - "Documents": "Dokumentumok" - }, - "Domain (optional)": { - "Domain (optional)": "Tartomány (opcionális)" - }, - "Don't Change": { - "Don't Change": "Ne módosítsa" - }, - "Don't Save": { - "Don't Save": "Ne mentse" - }, - "Door Open": { - "Door Open": "Ajtó nyitva" - }, - "Downloads": { - "Downloads": "Letöltések" - }, - "Drag to Reorder": { - "Drag to Reorder": "Húzd az átrendezéshez" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Húzd át a widgeteket a szakaszokon belüli átrendezéshez. Használd a szem ikont a widgetek elrejtéséhez/megjelenítéséhez (megtartja a távolságot), vagy az X-et az eltávolításukhoz." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Húzd a munkaterület-jelzőket az átrendezéshez" - }, - "Driver": { - "Driver": "Illesztőprogram" - }, - "Drizzle": { - "Drizzle": "Szitálás" - }, - "Duplicate": { - "Duplicate": "Kettőzés" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Háttérkép megkettőzése elmosással" - }, - "Duration": { - "Duration": "Időtartam" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Csillagászati alkony" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Polgári alkony" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Tengeri alkony" - }, - "Dynamic": { - "Dynamic": "Dinamikus" - }, - "Dynamic Properties": { - "Dynamic Properties": "Dinamikus tulajdonságok" - }, - "Dynamic Theming": { - "Dynamic Theming": "Dinamikus témázás" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Dinamikus színek a háttérképből" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Dinamikus színek, előbeállítások" - }, - "Edge Spacing": { - "Edge Spacing": "Élek távolsága" - }, - "Edit App": { - "Edit App": "Alkalmazás szerkesztése" - }, - "Edit Window Rule": { - "Edit Window Rule": "Ablakszabály szerkesztése" - }, - "Education": { - "Education": "Oktatás" - }, - "Empty": { - "Empty": "Üres" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "10 bites színmélység engedélyezése a szélesebb színtartomány és a HDR támogatása érdekében" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Automatikus csatlakozás engedélyezése" - }, - "Enable Bar": { - "Enable Bar": "Sáv engedélyezése" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Ne zavarjanak engedélyezése" - }, - "Enable History": { - "Enable History": "Előzmények engedélyezése" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Áttekintő átfedés engedélyezése" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Hullám effektusok engedélyezése" - }, - "Enable System Sounds": { - "Enable System Sounds": "Rendszerhangok engedélyezése" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Videós képernyővédő engedélyezése" - }, - "Enable Weather": { - "Enable Weather": "Időjárás engedélyezése" - }, - "Enable WiFi": { - "Enable WiFi": "Wi-Fi engedélyezése" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "Engedélyezd az egyéni felülbírálást alább a sávonkénti árnyékintenzitás, áttetszőség és szín beállításához." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Kompozitor által célozható elmosás réteg engedélyezése (névtér: dms:blurwallpaper). Kézi niri konfigurációt igényel." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Ujjlenyomat engedélyezése bejelentkezéskor" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Ujjlenyomatos azonosítás engedélyezése" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "Ujjlenyomat vagy biztonsági kulcs engedélyezése a DMS-üdvözlőképernyőhöz (greeter). A hitelesítési módosítások automatikusan alkalmazásra kerülnek." - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "loginctl-alapú zárolás integráció engedélyezése" - }, - "Enable security key at login": { - "Enable security key at login": "Biztonsági kulcs engedélyezése bejelentkezéskor" - }, - "Enable security key authentication": { - "Enable security key authentication": "Biztonsági kulcsos hitelesítés engedélyezése" - }, - "Enabled": { - "Enabled": "Engedélyezve" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Engedélyezve, de az ujjlenyomat-olvasó elérhetősége nem erősíthető meg." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Engedélyezve, de nem található ujjlenyomat-olvasó." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "Engedélyezve, de még nincsenek regisztrált ujjlenyomatok. A hitelesítési módosítások automatikusan alkalmazásra kerülnek, amint ujjlenyomatokat regisztrálsz." - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Engedélyezve, de még nincs regisztrált ujjlenyomat. Regisztrálj ujjlenyomatokat, majd futtasd a szinkronizálást." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "Engedélyezve, de még nem található regisztrált biztonsági kulcs. A hitelesítési módosítások automatikusan alkalmazásra kerülnek, amint regisztrálod a kulcsodat vagy frissíted az U2F-konfigurációdat." - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "Engedélyezve, de nem található regisztrált biztonsági kulcs. Regisztrálj egy kulcsot, majd futtasd a szinkronizálást." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Engedélyezve, de a biztonsági kulcs elérhetősége nem erősíthető meg." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Engedélyezve. A PAM már biztosít ujjlenyomatos hitelesítést." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Engedélyezve. A PAM már biztosít biztonsági kulcsos hitelesítést." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Engedélyezve. A PAM biztosít ujjlenyomatos hitelesítést, de még nincs regisztrált ujjlenyomat." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Wi-Fi bekapcsolása…" - }, - "End": { - "End": "Vége" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Nagyítás rámutatáskor" - }, - "Enlargement %": { - "Enlargement %": "Nagyítás %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Add meg a 6 számjegyű párosítási kódot" - }, - "Enter PIN": { - "Enter PIN": "Írd be a PIN-kódot" - }, - "Enter PIN for ": { - "Enter PIN for ": "PIN-kód megadása ehhez: " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Adj meg egy URL-t vagy szöveget a megosztáshoz" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Add meg a(z) „%1\" munkamenet új nevét" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Add meg a munkaterület új nevét" - }, - "Enter command or script path": { - "Enter command or script path": "Add meg a parancsot vagy a szkript útvonalát" - }, - "Enter credentials for ": { - "Enter credentials for ": "Add meg a hitelesítő adatokat ehhez: " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Zárolási képernyő egyéni formátumának megadása (pl., dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Egyéni felső sáv formátum megadása (pl. ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Add meg az eszköz nevét…" - }, - "Enter filename...": { - "Enter filename...": "Adj meg egy fájlnevet…" - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Írd be az indítási előtagot (pl. „uwsm-app”)" - }, - "Enter network name and password": { - "Enter network name and password": "Add meg a hálózat nevét és jelszavát" - }, - "Enter passkey for ": { - "Enter passkey for ": "Párosítási kód megadása ehhez: " - }, - "Enter password for ": { - "Enter password for ": "Add meg a jelszót ehhez: " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Írd be ezt a párosítási kódot ehhez: " - }, - "Enter to Paste": { - "Enter to Paste": "Enter a beillesztéshez" - }, - "Enterprise": { - "Enterprise": "Vállalati" - }, - "Entry pinned": { - "Entry pinned": "Bejegyzés rögzítve" - }, - "Entry unpinned": { - "Entry unpinned": "Bejegyzés rögzítése feloldva" - }, - "Environment Variables": { - "Environment Variables": "Környezeti változók" - }, - "Error": { - "Error": "Hiba" - }, - "Errors": { - "Errors": "Hibák" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Pontos egyezés" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Exkluzív zóna eltolása" - }, - "Experimental Feature": { - "Experimental Feature": "Kísérleti funkció" - }, - "Explore": { - "Explore": "Felfedezés" - }, - "Exponential": { - "Exponential": "Exponenciális" - }, - "Expressive": { - "Expressive": "Expresszív" - }, - "Extend battery life": { - "Extend battery life": "Akkumulátor-üzemidő növelése" - }, - "Extensible architecture": { - "Extensible architecture": "Bővíthető architektúra" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Külső háttérképkezelés" - }, - "Extra Arguments": { - "Extra Arguments": "További argumentumok" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Váltás • F10: Súgó" - }, - "Fade": { - "Fade": "Elhalványítás" - }, - "Fade to lock screen": { - "Fade to lock screen": "Halványítás a zárolási képernyőre" - }, - "Fade to monitor off": { - "Fade to monitor off": "Elhalványítás a monitor kikapcsolásáig" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Nem sikerült a párosítás elfogadása" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Nem sikerült aktiválni a konfigurációt" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Nem sikerült a profil aktiválása - a fájl nem található" - }, - "Failed to add binds include": { - "Failed to add binds include": "Nem sikerült hozzáadni a kötések include bejegyzést" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Nem sikerült a nyomtatót osztályhoz adni" - }, - "Failed to browse device": { - "Failed to browse device": "Nem sikerült az eszköz tallózása" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Nem sikerült az összes feladatot törölni" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Nem sikerült a kiválasztott feladatot törölni" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Nem sikerült a frissítések keresése:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Nem sikerült a rögzítési korlát ellenőrzése" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Nem sikerült csatlakozni a VPN-hez" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Nem sikerült csatlakozni ehhez: %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Nem sikerült másolni a bejegyzést" - }, - "Failed to create printer": { - "Failed to create printer": "Nem sikerült létrehozni a nyomtatót" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Nem sikerült a profilkönyvtár létrehozása" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Nem sikerült törölni a VPN-kapcsolatot" - }, - "Failed to delete class": { - "Failed to delete class": "Nem sikerült törölni az osztályt" - }, - "Failed to delete printer": { - "Failed to delete printer": "Nem sikerült törölni a nyomtatót" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Nem sikerült a feladatok elfogadásának letiltása" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Nem sikerült letiltani az éjszakai módot" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Nem sikerült lecsatlakozni a VPN-ről" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Nem sikerült lecsatlakoztatni a VPN-eket" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Nem sikerült lecsatlakozni a Wi-Fi-ről" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Nem sikerült engedélyezni az IP-helymeghatározást" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Nem sikerült engedélyezni a Wi-Fi-t" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Nem sikerült a feladatok elfogadásának engedélyezése" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Nem sikerült engedélyezni az éjszakai módot" - }, - "Failed to hold job": { - "Failed to hold job": "Nem sikerült a feladat várakoztatása" - }, - "Failed to import VPN": { - "Failed to import VPN": "Nem sikerült importálni a VPN-konfigurációt" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Nem sikerült az SMS-alkalmazás indítása" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Nem sikerült betölteni a VPN-konfigurációt" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Nem sikerült betölteni a vágólap konfigurációt." - }, - "Failed to move job": { - "Failed to move job": "Nem sikerült a feladat áthelyezése" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Nem sikerült a plugin_settings.json feldolgozása" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Nem sikerült a session.json feldolgozása" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Nem sikerült a settings.json feldolgozása" - }, - "Failed to pause printer": { - "Failed to pause printer": "Nem sikerült a nyomtatót szüneteltetni" - }, - "Failed to pin entry": { - "Failed to pin entry": "Nem sikerült a bejegyzés rögzítése" - }, - "Failed to print test page": { - "Failed to print test page": "Nem sikerült kinyomtatni a tesztoldalt" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Nem sikerült a párosítás elutasítása" - }, - "Failed to remove device": { - "Failed to remove device": "Nem sikerült eltávolítani az eszközt" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Nem sikerült eltávolítani a gyorsbillentyűt" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Nem sikerült eltávolítani a nyomtatót az osztályból" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Nem sikerült újraindítani a hangrendszert" - }, - "Failed to restart job": { - "Failed to restart job": "Nem sikerült újraindítani a feladatot" - }, - "Failed to resume printer": { - "Failed to resume printer": "Nem sikerült folytatni a nyomtatót" - }, - "Failed to ring device": { - "Failed to ring device": "Nem sikerült az eszköz megcsöngetése" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Nem sikerült futtatni a 'dms greeter status' parancsot. Győződj meg róla, hogy a DMS telepítve van, és a dms benne van a PATH környezeti változóban." - }, - "Failed to save audio config": { - "Failed to save audio config": "Nem sikerült menteni a hangkonfigurációt" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Nem sikerült menteni a vágólap beállítást" - }, - "Failed to save keybind": { - "Failed to save keybind": "Nem sikerült menteni a gyorsbillentyűt" - }, - "Failed to save profile file": { - "Failed to save profile file": "Nem sikerült a profilfájl mentése" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Nem sikerült a vágólap elküldése" - }, - "Failed to send file": { - "Failed to send file": "Nem sikerült elküldeni a fájlt" - }, - "Failed to send ping": { - "Failed to send ping": "Nem sikerült a ping küldése" - }, - "Failed to set brightness": { - "Failed to set brightness": "Nem sikerült beállítani a fényerőt" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Nem sikerült beállítani az éjszakai mód helyét" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Nem sikerült beállítani az éjszakai mód ütemezését" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Nem sikerült beállítani az éjszakai mód hőmérsékletét" - }, - "Failed to set power profile": { - "Failed to set power profile": "Nem sikerült az energiagazdálkodási profil beállítása" - }, - "Failed to set profile image": { - "Failed to set profile image": "Nem sikerült beállítani a profilképet" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Nem sikerült beállítani a profilképet: %1" - }, - "Failed to share": { - "Failed to share": "Nem sikerült a megosztás" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Nem sikerült elindítani a csatlakozást ehhez: %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Nem sikerült a bejegyzés rögzítésének feloldása" - }, - "Failed to update VPN": { - "Failed to update VPN": "Nem sikerült frissíteni a VPN-t" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Nem sikerült frissíteni az automatikus csatlakozást" - }, - "Failed to update description": { - "Failed to update description": "Nem sikerült frissíteni a leírást" - }, - "Failed to update location": { - "Failed to update location": "Nem sikerült frissíteni a helyet" - }, - "Failed to update sharing": { - "Failed to update sharing": "Nem sikerült frissíteni a megosztás állapotát" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Nem sikerült írni az ideiglenes fájlt az ellenőrzéshez" - }, - "Features": { - "Features": "Funkciók" - }, - "Feels": { - "Feels": "Hőérzet" - }, - "Feels Like": { - "Feels Like": "Hőérzet" - }, - "Feels Like %1°": { - "Feels Like %1°": "Hőérzet: %1°" - }, - "Fidelity": { - "Fidelity": "Hűség" - }, - "Field": { - "Field": "Mező" - }, - "File": { - "File": "Fájl" - }, - "File Already Exists": { - "File Already Exists": "A fájl már létezik" - }, - "File Information": { - "File Information": "Fájlinformáció" - }, - "File received from": { - "File received from": "Fájl érkezett innen:" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "A fájlkereséshez dsearch szükséges\nTelepítsd innen: github.com/AvengeMedia/danksearch" - }, - "Files": { - "Files": "Fájlok" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Fájlrendszer-használat figyelése" - }, - "Fill": { - "Fill": "Kitöltés" - }, - "Find in Text": { - "Find in Text": "Keresés szövegben…" - }, - "Find in note...": { - "Find in note...": "Keresés jegyzetben…" - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "Az ujjlenyomat-olvasó elérhetősége nem erősíthető meg." - }, - "Fingerprint error": { - "Fingerprint error": "Ujjlenyomathiba" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "Ujjlenyomathiba: %1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "Az ujjlenyomat nem felismerhető (%1/%2). Próbáld újra, vagy használj jelszót." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Ujjlenyomat-olvasó észlelve, de még nincs regisztrált ujjlenyomat. Most engedélyezheted, és később regisztrálhatsz." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "Ujjlenyomat-olvasó észlelve, de még nincs regisztrált ujjlenyomat. Most engedélyezheted, és később futtathatod a szinkronizálást." - }, - "Finish": { - "Finish": "Befejezés" - }, - "First Day of Week": { - "First Day of Week": "A hét első napja" - }, - "First Time Setup": { - "First Time Setup": "Első indítási beállítás" - }, - "Fit": { - "Fit": "Illesztés" - }, - "Fix Now": { - "Fix Now": "Javítás most" - }, - "Fixing...": { - "Fixing...": "Javítás…" - }, - "Flags": { - "Flags": "Jelzők" - }, - "Flipped": { - "Flipped": "Tükrözött" - }, - "Flipped 180°": { - "Flipped 180°": "180 fokkal tükrözött" - }, - "Flipped 270°": { - "Flipped 270°": "270 fokkal tükrözött" - }, - "Flipped 90°": { - "Flipped 90°": "90 fokkal tükrözött" - }, - "Float": { - "Float": "Lebegő" - }, - "Focus": { - "Focus": "Fókusz" - }, - "Focus at Startup": { - "Focus at Startup": "Fókusz indításkor" - }, - "Focused Border": { - "Focused Border": "Fókuszált szegély" - }, - "Focused Color": { - "Focused Color": "Fókuszált szín" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Csak a fókuszált monitor" - }, - "Focused Window": { - "Focused Window": "Fókuszált ablak" - }, - "Focused monitor only": { - "Focused monitor only": "Csak a fókuszált monitor" - }, - "Fog": { - "Fog": "Köd" - }, - "Folder": { - "Folder": "Mappa" - }, - "Folders": { - "Folders": "Mappa" - }, - "Follow DMS background color": { - "Follow DMS background color": "A DMS háttérszínének követése" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Monitor fókuszának követése" - }, - "Follow focus": { - "Follow focus": "Fókusz követése" - }, - "Font": { - "Font": "Betűtípus" - }, - "Font Family": { - "Font Family": "Betűtípus-család" - }, - "Font Scale": { - "Font Scale": "Betűméret-skála" - }, - "Font Size": { - "Font Size": "Betűméret" - }, - "Font Weight": { - "Font Weight": "Betűvastagság" - }, - "Font used on the login screen": { - "Font used on the login screen": "A bejelentkezési képernyőn használt betűtípus" - }, - "Force HDR": { - "Force HDR": "HDR kényszerítése" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Kényszerített megszakítás (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Széles színskála kényszerítése" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Terminálalkalmazások kényszerítése sötét színsémák használatára" - }, - "Forecast": { - "Forecast": "Előrejelzés" - }, - "Forecast Days": { - "Forecast Days": "Előrejelzési napok" - }, - "Forecast Not Available": { - "Forecast Not Available": "Előrejelzés nem elérhető" - }, - "Forever": { - "Forever": "Örökké" - }, - "Forget": { - "Forget": "Elfelejtés" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Elfelejted ezt: „%1”?" - }, - "Forget Device": { - "Forget Device": "Eszköz elfelejtése" - }, - "Forget Network": { - "Forget Network": "Hálózat elfelejtése" - }, - "Forgot network %1": { - "Forgot network %1": "Elfelejtett hálózat: %1" - }, - "Format Legend": { - "Format Legend": "Formátum-magyarázat" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "%1 frissíthető csomag található:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "%1 frissíthető csomag található:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "VRAM/memória felszabadítása az indító bezárásakor. Újranyitáskor némi késést okozhat." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Ónos szitálás" - }, - "Frequency": { - "Frequency": "Frekvencia" - }, - "Fruit Salad": { - "Fruit Salad": "Gyümölcssaláta" - }, - "Full Command:": { - "Full Command:": "Teljes parancs:" - }, - "Full Content": { - "Full Content": "Teljes tartalom" - }, - "Full Day & Month": { - "Full Day & Month": "Teljes nap és hónap" - }, - "Full with Year": { - "Full with Year": "Teljes évvel" - }, - "Fullscreen": { - "Fullscreen": "Teljes képernyő" - }, - "Fullscreen Only": { - "Fullscreen Only": "Csak teljes képernyőn" - }, - "Fully Charged": { - "Fully Charged": "Teljesen feltöltve" - }, - "Fun": { - "Fun": "Szórakozás" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: rács • Z/X: méret" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "GPU figyelés" - }, - "GPU Temperature": { - "GPU Temperature": "GPU-hőmérséklet" - }, - "GPU temperature display": { - "GPU temperature display": "GPU hőmérséklet kijelzése" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE-k és egyebek" - }, - "Games": { - "Games": "Játékok" - }, - "Gamma Control": { - "Gamma Control": "Gammavezérlés" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "A gammavezérlés nem érhető el. DMS API v6+ szükséges." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "Alapszintű GTK3/4 vagy QT5/QT6 (qt6ct-kde szükséges) konfigurációk generálása a DMS színeinek követéséhez. Csak egyszer kell.

        Javasolt az adw-gtk3 konfigurálása a GTK témák alkalmazása előtt." - }, - "Generic": { - "Generic": "Általános" - }, - "Get Started": { - "Get Started": "Kezdés" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Az összes animáció időtartamának globális méretezése" - }, - "Golden Hour": { - "Golden Hour": "Aranyóra" - }, - "Good": { - "Good": "Jó" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Gótikus sarokkerekítés" - }, - "Goth Corners": { - "Goth Corners": "Gótikus sarkok" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Fokozatosan halványítsa el a képernyőt a zárolás előtt egy konfigurálható türelmi idővel" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "A képernyő fokozatos elhalványítása a monitorok kikapcsolása előtt egy beállítható türelmi idővel" - }, - "Graph Time Range": { - "Graph Time Range": "Grafikon időtartománya" - }, - "Graphics": { - "Graphics": "Grafika" - }, - "Greeter": { - "Greeter": "Üdvözlőképernyő" - }, - "Greeter Appearance": { - "Greeter Appearance": "Üdvözlőképernyő megjelenése" - }, - "Greeter Behavior": { - "Greeter Behavior": "Üdvözlőképernyő viselkedése" - }, - "Greeter Status": { - "Greeter Status": "Üdvözlőképernyő állapota" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Üdvözlőképernyő aktiválva. A greetd mostantól engedélyezve van." - }, - "Greeter font": { - "Greeter font": "Üdvözlőképernyő betűtípusa" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Csak az üdvözlőképernyőre – nincs hatással a fő órára" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Csak az üdvözlőképernyőre – a bejelentkezési képernyőn megjelenő dátum formátuma" - }, - "Grid": { - "Grid": "Rács" - }, - "Grid Columns": { - "Grid Columns": "Rácsos oszlopok" - }, - "Grid: OFF": { - "Grid: OFF": "Rács: KI" - }, - "Grid: ON": { - "Grid: ON": "Rács: BE" - }, - "Group": { - "Group": "Csoport" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Munkaterület-alkalmazások csoportosítása" - }, - "Group by App": { - "Group by App": "Csoportosítás alkalmazás szerint" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Ugyanazon alkalmazás több ablakának csoportosítása egy ablakszám-jelzővel" - }, - "Group removed": { - "Group removed": "Csoport eltávolítva" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Ismétlődő alkalmazásikonok csoportosítása a nem fókuszált munkaterületeken" - }, - "Groups": { - "Groups": "Csoportok" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR-tónusleképezés" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "A HDR mód kísérleti jellegű. Engedélyezés előtt ellenőrizd, hogy a monitor támogatja-e a HDR-t." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML a vágólapra másolva" - }, - "Health": { - "Health": "Állapot" - }, - "Heavy Rain": { - "Heavy Rain": "Heves esőzés" - }, - "Heavy Snow": { - "Heavy Snow": "Erős havazás" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Erős hózáporok" - }, - "Height": { - "Height": "Magasság" - }, - "Held": { - "Held": "Felfüggesztve" - }, - "Help": { - "Help": "Súgó" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Hibernálás" - }, - "Hidden": { - "Hidden": "Rejtett" - }, - "Hidden (%1)": { - "Hidden (%1)": "Rejtett (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Rejtett alkalmazások" - }, - "Hidden Network": { - "Hidden Network": "Rejtett hálózat" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "A rejtett alkalmazások nem jelennek meg az indítóban. Kattints jobb gombbal egy alkalmazásra, és válaszd az „Alkalmazás elrejtése” lehetőséget az elrejtéshez." - }, - "Hide": { - "Hide": "Elrejtés" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Külső bővítmények elrejtése" - }, - "Hide App": { - "Hide App": "Alkalmazás elrejtése" - }, - "Hide Delay": { - "Hide Delay": "Elrejtési késleltetés" - }, - "Hide Indicators": { - "Hide Indicators": "Jelzők elrejtése" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Frissítő widget elrejtése" - }, - "Hide When Typing": { - "Hide When Typing": "Elrejtés gépeléskor" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Elrejtés, amikor ablakok vannak megnyitva" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Kurzor elrejtése inaktivitás után (0 = letiltva)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Kurzor elrejtése billentyűleütéskor" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Kurzor elrejtése érintéses bevitel használatakor" - }, - "Hide device": { - "Hide device": "Eszköz elrejtése" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Értesítés tartalmának elrejtése a kibontásig" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Értesítés tartalmának elrejtése a kibontásig; a felugró ablakok alapértelmezés szerint összecsukva jelennek meg" - }, - "Hide on Touch": { - "Hide on Touch": "Elrejtés érintéskor" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Nagy hűségű paletta, amely megőrzi a forrás árnyalatait." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Aktív munkaterület-alkalmazás kiemelése" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "A fókuszált alkalmazás kiemelése a munkaterület-jelzőkben" - }, - "History": { - "History": "Előzmények" - }, - "History Retention": { - "History Retention": "Előzmények megőrzése" - }, - "History Settings": { - "History Settings": "Előzménybeállítások" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Előzmények törölve. %1 rögzített bejegyzés megtartva." - }, - "Hold Duration": { - "Hold Duration": "Nyomva tartás időtartama" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Tartsd lenyomva a megerősítéshez" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Lenyomva tartás a főkapcsoló műveletek megerősítéséhez" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Tartsd lenyomva a megerősítéshez (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Tartsd lenyomva a megerősítéshez (%1 mp)" - }, - "Home": { - "Home": "Saját mappa" - }, - "Host": { - "Host": "Gép" - }, - "Hostname": { - "Hostname": "Gépnév" - }, - "Hot Corners": { - "Hot Corners": "Aktív sarkok" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Gyorsbillentyű-átfedés címe (opcionális)" - }, - "Hour": { - "Hour": "Óra" - }, - "Hourly": { - "Hourly": "Óránkénti" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Óránkénti előrejelzések száma" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Milyen gyakran változzon a háttérkép" - }, - "How the background image is scaled": { - "How the background image is scaled": "A háttérkép méretezésének módja" - }, - "Humidity": { - "Humidity": "Páratartalom" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Hyprland Discord szervere" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland elrendezés felülbírálások" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland beállítások" - }, - "Hyprland Website": { - "Hyprland Website": "Hyprland weboldal" - }, - "I Understand": { - "I Understand": "Megértettem" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP-cím:" - }, - "IP address or hostname": { - "IP address or hostname": "IP-cím vagy gépnév" - }, - "ISO Date": { - "ISO Date": "ISO dátum" - }, - "Icon": { - "Icon": "Ikon" - }, - "Icon Scale": { - "Icon Scale": "Ikonméret" - }, - "Icon Size": { - "Icon Size": "Ikonméret" - }, - "Icon Size %": { - "Icon Size %": "Ikonméret %" - }, - "Icon Theme": { - "Icon Theme": "Ikontéma" - }, - "Idle": { - "Idle": "Tétlen" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inaktivitás megakadályozása" - }, - "Idle Settings": { - "Idle Settings": "Inaktivitási beállítások" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Az inaktivitás figyelése nem támogatott – újabb Quickshell verzió szükséges" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Ha a mező rejtett, megjelenik, amint lenyomsz egy billentyűt." - }, - "Ignore Completely": { - "Ignore Completely": "Teljes mellőzés" - }, - "Image": { - "Image": "Kép" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Kép másolva a vágólapra" - }, - "Import": { - "Import": "Importálás" - }, - "Import VPN": { - "Import VPN": "VPN-kapcsolat importálása" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Inaktív monitor színe" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Átmenetekkel együtt" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Asztali műveletek (parancsikonok) belefoglalása a keresési eredményekbe." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Inkompatibilis bővítmények betöltve" - }, - "Incorrect password": { - "Incorrect password": "Helytelen jelszó" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Helytelen jelszó – %1 / %2 próbálkozás (kizárás követheti)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Helytelen jelszó – a következő sikertelen próbálkozások a fiók zárolását vonhatják maguk után" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "Helytelen jelszó - próbáld újra" - }, - "Indicator Style": { - "Indicator Style": "Jelző stílusa" - }, - "Individual Batteries": { - "Individual Batteries": "Egyéni akkumulátorok" - }, - "Individual bar configuration": { - "Individual bar configuration": "Egyéni sáv konfiguráció" - }, - "Info": { - "Info": "Információ" - }, - "Inherit": { - "Inherit": "Öröklés" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Globális öröklése (Alapértelmezett)" - }, - "Inhibitable": { - "Inhibitable": "Gátolható" - }, - "Input Devices": { - "Input Devices": "Bemeneti eszközök" - }, - "Input Volume Slider": { - "Input Volume Slider": "Bemeneti hangerő csúszka" - }, - "Insert your security key...": { - "Insert your security key...": "Helyezd be a biztonsági kulcsodat..." - }, - "Install": { - "Install": "Telepítés" - }, - "Install Greeter": { - "Install Greeter": "Üdvözlőképernyő telepítése" - }, - "Install Plugin": { - "Install Plugin": "Bővítmény telepítése" - }, - "Install Theme": { - "Install Theme": "Téma telepítése" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Színtémák telepítése a DMS-témaregiszterből" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Telepítés befejezve. Az üdvözlőképernyő telepítve lett." - }, - "Install failed: %1": { - "Install failed: %1": "Telepítés sikertelen: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Telepítsd a matugen csomagot a dinamikus témázáshoz" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Telepíted a(z) „%1” bővítményt a DMS-regiszterből?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Bővítmények telepítése a DMS-bővítményregiszterből" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "Telepíted a DMS-üdvözlőképernyőt? (greeter) Egy terminál fog megnyílni a sudo hitelesítéshez." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Telepíted a(z) „%1” témát a DMS-regiszterből?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Telepítés és PAM beállítása: lásd a " - }, - "Installed": { - "Installed": "Telepítve" - }, - "Installed: %1": { - "Installed: %1": "Telepített: %1" - }, - "Installing: %1": { - "Installing: %1": "Telepítés: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Intelligens automatikus elrejtés" - }, - "Intensity": { - "Intensity": "Intenzitás" - }, - "Interface:": { - "Interface:": "Interfész:" - }, - "Interlock Open": { - "Interlock Open": "Retesz nyitva" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervallum" - }, - "Invalid configuration": { - "Invalid configuration": "Érvénytelen konfiguráció" - }, - "Invert on mode change": { - "Invert on mode change": "Invertálás módváltáskor" - }, - "Iris Bloom": { - "Iris Bloom": "Íriszvirágzás" - }, - "Isolate Displays": { - "Isolate Displays": "Kijelzők elszigetelése" - }, - "Jobs": { - "Jobs": "Munkák" - }, - "Jobs: ": { - "Jobs: ": "Munkák: " - }, - "Keep Awake": { - "Keep Awake": "Ébren tartás" - }, - "Keep Changes": { - "Keep Changes": "Változtatások megtartása" - }, - "Keeping Awake": { - "Keeping Awake": "Ébren tartva" - }, - "Kernel": { - "Kernel": "Rendszermag" - }, - "Key": { - "Key": "Billentyű" - }, - "Keybind Sources": { - "Keybind Sources": "Gyorsbillentyű-források" - }, - "Keybinds": { - "Keybinds": "Billentyűkombinációk" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Gyorsbillentyű-keresési beállítások" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Gyorsbillentyűk megjelenítése a normál keresési eredmények mellett" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Billentyűzetkiosztás neve" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Gyorsbillentyűk" - }, - "Keys": { - "Keys": "Billentyűk" - }, - "Kill": { - "Kill": "Megszakítás" - }, - "Kill Process": { - "Kill Process": "Folyamat megszakítása" - }, - "Kill Session": { - "Kill Session": "Munkamenet megszakítása" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED-eszköz" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC csatorna" - }, - "LabWC Website": { - "LabWC Website": "LabWC weboldala" - }, - "Large": { - "Large": "Nagy" - }, - "Largest": { - "Largest": "Legnagyobb" - }, - "Last hour": { - "Last hour": "Utolsó óra" - }, - "Last launched %1": { - "Last launched %1": "Utoljára elindítva: %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Utoljára %1 napja indítva" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Utoljára %1 napja indítva" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Utoljára %1 órája indítva" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Utoljára %1 órája indítva" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Utoljára %1 perce indítva" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Utoljára %1 perce indítva" - }, - "Last launched just now": { - "Last launched just now": "Épp most indítva" - }, - "Latitude": { - "Latitude": "Szélesség" - }, - "Launch": { - "Launch": "Indítás" - }, - "Launch Prefix": { - "Launch Prefix": "Indítási előtag" - }, - "Launch on dGPU": { - "Launch on dGPU": "Indítás dGPU-n" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "Indítás alapértelmezés szerint a dGPU-n" - }, - "Launcher": { - "Launcher": "Indító" - }, - "Launcher Button": { - "Launcher Button": "Indítógomb" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Indító gomb logója" - }, - "Layout": { - "Layout": "Elrendezés" - }, - "Layout Overrides": { - "Layout Overrides": "Elrendezés felülbírálása" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "Az üdvözlőképernyő elrendezése és a modulok pozíciói a héjból (pl. sávkonfiguráció) vannak szinkronizálva. Futtasd a szinkronizálást az alkalmazáshoz." - }, - "Left": { - "Left": "Bal" - }, - "Left Center": { - "Left Center": "Bal középen" - }, - "Left Section": { - "Left Section": "Bal oldali szakasz" - }, - "Light Direction": { - "Light Direction": "Fény iránya" - }, - "Light Mode": { - "Light Mode": "Világos mód" - }, - "Light Rain": { - "Light Rain": "Enyhe eső" - }, - "Light Snow": { - "Light Snow": "Enyhe havazás" - }, - "Light Snow Showers": { - "Light Snow Showers": "Enyhe hózáporok" - }, - "Light mode base": { - "Light mode base": "Világos mód (alap)" - }, - "Light mode harmony": { - "Light mode harmony": "Világos mód (harmónia)" - }, - "Line": { - "Line": "Vonal" - }, - "Line: %1": { - "Line: %1": "Sor: %1" - }, - "Linear": { - "Linear": "Lineáris" - }, - "Lines: %1": { - "Lines: %1": "%1 sor" - }, - "List": { - "List": "Lista" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Élénk paletta telített kiemelésekkel." - }, - "Load Average": { - "Load Average": "Átlagos terhelés" - }, - "Loading codecs...": { - "Loading codecs...": "Kodekek betöltése…" - }, - "Loading keybinds...": { - "Loading keybinds...": "Gyorsbillentyűk betöltése…" - }, - "Loading trending...": { - "Loading trending...": "Trendek betöltése…" - }, - "Loading...": { - "Loading...": "Betöltés…" - }, - "Local": { - "Local": "Helyi" - }, - "Locale": { - "Locale": "Területi beállítás" - }, - "Locale Settings": { - "Locale Settings": "Területi beállítások" - }, - "Location": { - "Location": "Hely" - }, - "Location Search": { - "Location Search": "Hely keresése" - }, - "Lock": { - "Lock": "Zárolás" - }, - "Lock Screen": { - "Lock Screen": "Zárolási képernyő" - }, - "Lock Screen Display": { - "Lock Screen Display": "Zárolási képernyő megjelenítése" - }, - "Lock Screen Format": { - "Lock Screen Format": "Zárolási képernyő formátuma" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Zárolási képernyő viselkedés" - }, - "Lock Screen layout": { - "Lock Screen layout": "Zárolási képernyő elrendezés" - }, - "Lock at startup": { - "Lock at startup": "Zárolás indításkor" - }, - "Lock before suspend": { - "Lock before suspend": "Zárolás felfüggesztés előtt" - }, - "Lock fade grace period": { - "Lock fade grace period": "Zárolási elhalványítás türelmi ideje" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "A képernyőzár hitelesítési módosításai automatikusan alkalmazásra kerülnek, és terminált nyithatnak meg, ha sudo hitelesítés szükséges." - }, - "Locked": { - "Locked": "Zárolva" - }, - "Log Out": { - "Log Out": "Kijelentkezés" - }, - "Logging in...": { - "Logging in...": "Bejelentkezés…" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Bejelentkezési hitelesítés" - }, - "Long": { - "Long": "Hosszú" - }, - "Long Text": { - "Long Text": "Hosszú szöveg" - }, - "Long press": { - "Long press": "Hosszú gombnyomás" - }, - "Longitude": { - "Longitude": "Hosszúság" - }, - "Low Priority": { - "Low Priority": "Alacsony prioritás" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Győződj meg róla, hogy a KDE Connect vagy a Valent fut a többi eszközön" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Bővítmények kezelése és konfigurálása a DMS funkcionalitásának kiterjesztésére" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Legfeljebb 4 független sávkonfiguráció kezelése. Minden sávnak megvan a saját pozíciója, widgetjei, stílusa és kijelző-hozzárendelése." - }, - "Management": { - "Management": "Kezelés" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC elrendezés felülbírálások" - }, - "Manual": { - "Manual": "Kézi" - }, - "Manual Coordinates": { - "Manual Coordinates": "Manuális koordináták" - }, - "Manual Direction": { - "Manual Direction": "Kézi irány" - }, - "Manual Gap Size": { - "Manual Gap Size": "Manuális rés mérete" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Manuális megjelenítés/elrejtés" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Rendelj hozzá ablakosztályneveket ikonnevekhez a megfelelő megjelenítés érdekében" - }, - "Margin": { - "Margin": "Margó" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "A festék kifogyott" - }, - "Marker Supply Low": { - "Marker Supply Low": "A festék szintje alacsony" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "A hulladéktartály majdnem tele" - }, - "Marker Waste Full": { - "Marker Waste Full": "A hulladéktartály megtelt" - }, - "Match Criteria": { - "Match Criteria": "Illesztési feltételek" - }, - "Matches profile: %1": { - "Matches profile: %1": "Illeszkedik a profilra: %1" - }, - "Material Colors": { - "Material Colors": "Material színek" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Material Design ihlette színtémák" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Háttérképből generált Material színek" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "Material stílusú árnyékok és emelések a modális ablakokon, felugrókon és párbeszédpaneleken" - }, - "Matugen Contrast": { - "Matugen Contrast": "Matugen kontraszt" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen hiányzik" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen paletta" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen célmonitor" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen-sablonok" - }, - "Max Edges": { - "Max Edges": "Maximális élek" - }, - "Max H": { - "Max H": "Max. mag." - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Max. rögzített alk." - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Max. rögzített alk. (0 = korlátlan)" - }, - "Max Running Apps": { - "Max Running Apps": "Max. futó alk." - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Max. futó alk. (0 = korlátlan)" - }, - "Max Volume": { - "Max Volume": "Maximális hangerő" - }, - "Max W": { - "Max W": "Max. szél." - }, - "Max apps to show": { - "Max apps to show": "Megjelenítendő alkalmazások maximális száma" - }, - "Max to Edges": { - "Max to Edges": "Maximalizálás az élekig" - }, - "Maximize": { - "Maximize": "Maximalizálás" - }, - "Maximize Detection": { - "Maximize Detection": "Maximalizálás érzékelése" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Widget ikonok maximalizálása" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Widget szöveg maximalizálása" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maximális bejegyzés méret" - }, - "Maximum History": { - "Maximum History": "Maximális előzmény" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Rögzített bejegyzések maximális száma" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "Elérted a maximális ujjlenyomat-kísérletet. Használj jelszót." - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Megtartandó vágólap-bejegyzések maximális száma" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "A menthető bejegyzések maximális száma" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Megőrizni kívánt értesítések maximális száma" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Elérted a rögzített bejegyzések maximális számát" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Maximális méret vágólap-bejegyzésenként" - }, - "Media": { - "Media": "Média" - }, - "Media Controls": { - "Media Controls": "Médiavezérlők" - }, - "Media Empty": { - "Media Empty": "Adathordozó üres" - }, - "Media Jam": { - "Media Jam": "Adathordozó elakadás" - }, - "Media Low": { - "Media Low": "Adathordozó alacsony" - }, - "Media Needed": { - "Media Needed": "Adathordozó szükséges" - }, - "Media Playback": { - "Media Playback": "Médialejátszás" - }, - "Media Player": { - "Media Player": "Médialejátszó" - }, - "Media Player Settings": { - "Media Player Settings": "Médialejátszó-beállítások" - }, - "Media Players": { - "Media Players": "Zenelejátszók" - }, - "Media Players (": { - "Media Players (": "Médialejátszók (" - }, - "Media Volume": { - "Media Volume": "Média hangereje" - }, - "Medium": { - "Medium": "Közepes" - }, - "Memory": { - "Memory": "Memória" - }, - "Memory Graph": { - "Memory Graph": "Memória grafikon" - }, - "Memory Usage": { - "Memory Usage": "Memóriahasználat" - }, - "Memory usage indicator": { - "Memory usage indicator": "Memóriahasználat-jelző" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Üzenet" - }, - "Message Content": { - "Message Content": "Üzenet tartalma" - }, - "Microphone": { - "Microphone": "Mikrofon" - }, - "Microphone Mute": { - "Microphone Mute": "Mikrofon némítás" - }, - "Microphone Volume": { - "Microphone Volume": "Mikrofon hangereje" - }, - "Microphone settings": { - "Microphone settings": "Mikrofonbeállítások" - }, - "Microphone volume control": { - "Microphone volume control": "Mikrofon hangerőszabályozó" - }, - "Middle Section": { - "Middle Section": "Középső szekció" - }, - "Min H": { - "Min H": "Min. mag." - }, - "Min W": { - "Min W": "Min. szél." - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Minimális paletta, amely egyetlen árnyalat köré épül." - }, - "Minute": { - "Minute": "Perc" - }, - "Mirror Display": { - "Mirror Display": "Kijelző tükrözése" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Hiányzó környezeti változók" - }, - "Modal Background": { - "Modal Background": "Kizárólagos párbeszédablakok háttere" - }, - "Modal Shadows": { - "Modal Shadows": "Modális ablak árnyékok" - }, - "Modals": { - "Modals": "Kizárólagos ablakok" - }, - "Mode": { - "Mode": "Mód" - }, - "Mode:": { - "Mode:": "Mód:" - }, - "Model": { - "Model": "Modell" - }, - "Modified": { - "Modified": "Módosítva" - }, - "Modular widget bar": { - "Modular widget bar": "Moduláris widget-sáv" - }, - "Monitor": { - "Monitor": "Monitor" - }, - "Monitor Configuration": { - "Monitor Configuration": "Monitorkonfiguráció" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Monitor elhalványítási türelmi ideje" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Az a monitor, amelynek háttérképe meghatározza a dinamikus témaszíneket" - }, - "Monochrome": { - "Monochrome": "Monokróm" - }, - "Monocle": { - "Monocle": "Egyablakos" - }, - "Monospace Font": { - "Monospace Font": "Rögzített szélességű betűtípus" - }, - "Month Date": { - "Month Date": "Hónap, dátum" - }, - "Morning": { - "Morning": "Reggel" - }, - "Mount Points": { - "Mount Points": "Csatolási pontok" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Egérmutató megjelenése" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Egérmutató mérete képpontban" - }, - "Move": { - "Move": "Mozgatás" - }, - "Move Widget": { - "Move Widget": "Widget mozgatása" - }, - "Moving to Paused": { - "Moving to Paused": "Szüneteltetésre váltás" - }, - "Multi-Monitor": { - "Multi-Monitor": "Több monitor" - }, - "Multiplexer": { - "Multiplexer": "Multiplexer" - }, - "Multiplexer Type": { - "Multiplexer Type": "Multiplexer típusa" - }, - "Multiplexers": { - "Multiplexers": "Multiplexerek" - }, - "Music": { - "Music": "Zene" - }, - "Mute Popups": { - "Mute Popups": "Felugrók némítása" - }, - "Mute popups for %1": { - "Mute popups for %1": "Felugró ablakok némítása ehhez: %1" - }, - "Muted": { - "Muted": "Némítva" - }, - "Muted Apps": { - "Muted Apps": "Némított alkalmazások" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Visszafogott paletta, tompa, nyugtató tónusokkal." - }, - "NM not supported": { - "NM not supported": "Az NM nem támogatott" - }, - "Name": { - "Name": "Név" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Nevesített munkaterület ikonok" - }, - "Navigate": { - "Navigate": "Navigáció" - }, - "Navigation": { - "Navigation": "Navigáció" - }, - "Network": { - "Network": "Hálózat" - }, - "Network Graph": { - "Network Graph": "Hálózati grafikon" - }, - "Network Info": { - "Network Info": "Hálózati információ" - }, - "Network Information": { - "Network Information": "Hálózati információ" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Hálózatnév (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Hálózati sebességfigyelő" - }, - "Network Status": { - "Network Status": "Hálózati állapot" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Hálózati le- és feltöltési sebesség kijelzése" - }, - "Neutral": { - "Neutral": "Semleges" - }, - "Never": { - "Never": "Soha" - }, - "Never used": { - "Never used": "Soha nem használt" - }, - "New": { - "New": "Új" - }, - "New Key": { - "New Key": "Új billentyű" - }, - "New Keybind": { - "New Keybind": "Új gyorsbillentyű" - }, - "New Notification": { - "New Notification": "Új értesítés" - }, - "New Session": { - "New Session": "Új munkamenet" - }, - "New Window Rule": { - "New Window Rule": "Új ablakszabály" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Új csoportnév…" - }, - "Next": { - "Next": "Következő" - }, - "Next Transition": { - "Next Transition": "Következő átmenet" - }, - "Night": { - "Night": "Éjszaka" - }, - "Night Mode": { - "Night Mode": "Éjszakai mód" - }, - "Night Temperature": { - "Night Temperature": "Éjszakai hőmérséklet" - }, - "Night mode & gamma": { - "Night mode & gamma": "Éjszakai mód és gamma" - }, - "Niri Integration": { - "Niri Integration": "Niri integráció" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri elrendezés felülbírálásai" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri-kompozitorműveletek (fókusz, mozgatás, stb.)" - }, - "No": { - "No": "Nem" - }, - "No Active Players": { - "No Active Players": "Nincsenek aktív lejátszók" - }, - "No Anim": { - "No Anim": "Nincs animáció" - }, - "No Background": { - "No Background": "Nincs háttérkép" - }, - "No Battery": { - "No Battery": "Nincs akkumulátor" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Nem található Bluetooth adapter" - }, - "No Blur": { - "No Blur": "Nincs elmosódás" - }, - "No Border": { - "No Border": "Nincs szegély" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Nincsenek DMS gyorsbillentyűk beállítva" - }, - "No Dim": { - "No Dim": "Nincs sötétítés" - }, - "No Focus": { - "No Focus": "Nincs fókusz" - }, - "No GPU detected": { - "No GPU detected": "Nem észlelhető GPU" - }, - "No GPUs detected": { - "No GPUs detected": "Nem található GPU" - }, - "No History": { - "No History": "Nincs előzmény" - }, - "No Media": { - "No Media": "Nincs média" - }, - "No Round": { - "No Round": "Nincs kerekítés" - }, - "No Rounding": { - "No Rounding": "Nincs kerekítés" - }, - "No Shadow": { - "No Shadow": "Nincs árnyék" - }, - "No VPN profiles": { - "No VPN profiles": "Nincs VPN-profil" - }, - "No Weather": { - "No Weather": "Nincs időjárás" - }, - "No Weather Data": { - "No Weather Data": "Nincsenek időjárási adatok" - }, - "No Weather Data Available": { - "No Weather Data Available": "Nincs elérhető időjárási adat" - }, - "No action": { - "No action": "Nincs művelet" - }, - "No active %1 sessions": { - "No active %1 sessions": "Nincs aktív %1 munkamenet" - }, - "No adapter": { - "No adapter": "Nincs adapter" - }, - "No adapters": { - "No adapters": "Nincs adapter" - }, - "No app customizations.": { - "No app customizations.": "Nincsenek alkalmazás testreszabások." - }, - "No apps found": { - "No apps found": "Nem találhatók alkalmazások" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Még nem indult el alkalmazás." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Nincsenek némított alkalmazások. Kattints jobb gombbal egy értesítésre, és válaszd a „Felugró ablakok némítása” lehetőséget a hozzáadáshoz." - }, - "No battery": { - "No battery": "Nincs akkumulátor" - }, - "No brightness devices available": { - "No brightness devices available": "Nincs elérhető fényerő eszköz" - }, - "No changes": { - "No changes": "Nincs változás" - }, - "No checks passed": { - "No checks passed": "Nincs sikeres ellenőrzés" - }, - "No custom theme file": { - "No custom theme file": "Nincs egyéni témafájl" - }, - "No devices": { - "No devices": "Nincsenek eszközök" - }, - "No devices connected": { - "No devices connected": "Nincsenek csatlakoztatott eszközök" - }, - "No devices found": { - "No devices found": "Nem található eszköz" - }, - "No disk data": { - "No disk data": "Nincs lemezadat" - }, - "No disk data available": { - "No disk data available": "Nincs lemezadat elérhető" - }, - "No drivers found": { - "No drivers found": "Nem található illesztőprogram" - }, - "No errors": { - "No errors": "Nincsenek hibák" - }, - "No features enabled": { - "No features enabled": "Nincs funkció engedélyezve" - }, - "No files found": { - "No files found": "Nem található fájl" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Nem található ujjlenyomat-olvasó." - }, - "No folders found": { - "No folders found": "Nem található mappa" - }, - "No hidden apps.": { - "No hidden apps.": "Nincsenek rejtett alkalmazások." - }, - "No info items": { - "No info items": "Nincsenek információs elemek" - }, - "No information available": { - "No information available": "Nincs elérhető információ" - }, - "No input device": { - "No input device": "Nincs bemeneti eszköz" - }, - "No input devices found": { - "No input devices found": "Nem található bemeneti eszköz" - }, - "No items added yet": { - "No items added yet": "Még nincsenek hozzáadott elemek" - }, - "No keybinds found": { - "No keybinds found": "Nem található billentyű" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Nincsenek indítóbővítmények telepítve." - }, - "No match criteria": { - "No match criteria": "Nincs egyezési feltétel" - }, - "No matches": { - "No matches": "Nincs találat" - }, - "No matching processes": { - "No matching processes": "Nincs találat a folyamatok között" - }, - "No monitors": { - "No monitors": "Nincsenek monitorok" - }, - "No mount points found": { - "No mount points found": "Nem találhatók csatolási pontok" - }, - "No output device": { - "No output device": "Nincs kimeneti eszköz" - }, - "No output devices found": { - "No output devices found": "Nem található kimeneti eszköz" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Nem található csomagkezelő. Arch-alapú rendszereken telepítsd a 'paru' vagy 'yay' csomagot a frissítések ellenőrzéséhez." - }, - "No plugin results": { - "No plugin results": "Nincsenek bővítménytalálatok" - }, - "No plugins found": { - "No plugins found": "Nem található bővítmény" - }, - "No plugins found.": { - "No plugins found.": "Nem található bővítmény." - }, - "No printer found": { - "No printer found": "Nem található nyomtató" - }, - "No printers configured": { - "No printers configured": "Nincs konfigurálva nyomtató" - }, - "No printers found": { - "No printers found": "Nem található nyomtató" - }, - "No profiles": { - "No profiles": "Nincsenek profilok" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Nem találhatók legutóbbi vágólapbejegyzések" - }, - "No results found": { - "No results found": "Nincsenek találatok" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Nincsenek mentett vágólapbejegyzések" - }, - "No sessions found": { - "No sessions found": "Nem található munkamenet" - }, - "No status output.": { - "No status output.": "Nincs állapotkimenet." - }, - "No themes found": { - "No themes found": "Nem található téma" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Nincsenek telepített témák. Böngéssz a regiszterben a telepíthető témákért." - }, - "No trigger": { - "No trigger": "Nincs indító" - }, - "No video found in folder": { - "No video found in folder": "Nem található videó a mappában" - }, - "No wallpaper selected": { - "No wallpaper selected": "Nincs háttérkép kiválasztva" - }, - "No wallpapers": { - "No wallpapers": "Nincsenek háttérképek" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Nem található háttérkép\n\nKattints a mappaikonra a tallózáshoz" - }, - "No warnings": { - "No warnings": "Nincsenek figyelmeztetések" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Nincsenek hozzáadva widgetek. Kattints a „Widget hozzáadása\" gombra a kezdéshez." - }, - "No widgets available": { - "No widgets available": "Nincsenek elérhető widgetek" - }, - "No widgets match your search": { - "No widgets match your search": "Nincs a keresésnek megfelelő widget" - }, - "No window rules configured": { - "No window rules configured": "Nincsenek ablakszabályok beállítva" - }, - "None": { - "None": "Nincs" - }, - "Normal": { - "Normal": "Normál" - }, - "Normal Font": { - "Normal Font": "Normál betűtípus" - }, - "Normal Priority": { - "Normal Priority": "Normál prioritás" - }, - "Not available": { - "Not available": "Nem elérhető" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Nem érhető el — telepítsd az fprintd és pam_fprintd csomagokat, vagy konfiguráld a greetd PAM-ot." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Nem érhető el — telepítsd az fprintd és pam_fprintd csomagokat." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "Nem érhető el — telepítsd vagy konfiguráld a pam_u2f-et, vagy konfiguráld a greetd PAM-ot." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Nem érhető el — telepítsd vagy konfiguráld a pam_u2f-et." - }, - "Not connected": { - "Not connected": "Nincs csatlakozva" - }, - "Not detected": { - "Not detected": "Nem észlelhető" - }, - "Not paired": { - "Not paired": "Nincs párosítva" - }, - "Not set": { - "Not set": "Nincs beállítva" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Megjegyzés: ez csak a százalékot módosítja, ténylegesen nem korlátozza a töltést." - }, - "Notepad": { - "Notepad": "Jegyzettömb" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Jegyzettömb-betűbeállítások" - }, - "Notepad Slideout": { - "Notepad Slideout": "Jegyzettömb oldalsáv" - }, - "Nothing": { - "Nothing": "Semmi" - }, - "Nothing to see here": { - "Nothing to see here": "Nincs itt semmi" - }, - "Notification Center": { - "Notification Center": "Értesítési központ" - }, - "Notification Display": { - "Notification Display": "Értesítések megjelenítése" - }, - "Notification Overlay": { - "Notification Overlay": "Értesítési átfedés" - }, - "Notification Popups": { - "Notification Popups": "Felugró értesítések" - }, - "Notification Rules": { - "Notification Rules": "Értesítési szabályok" - }, - "Notification Settings": { - "Notification Settings": "Értesítési beállítások" - }, - "Notification Timeouts": { - "Notification Timeouts": "Értesítési időkorlátok" - }, - "Notification toast popups": { - "Notification toast popups": "Értesítési felugró üzenetek" - }, - "Notifications": { - "Notifications": "Értesítések" - }, - "Numbers": { - "Numbers": "Számok" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numerikus (N/H)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numerikus (H/N)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Operációs rendszer logó" - }, - "OSD Position": { - "OSD Position": "Képernyőkijelző pozíciója" - }, - "Occupied Color": { - "Occupied Color": "Foglalt szín" - }, - "Off": { - "Off": "Kikapcsolva" - }, - "Office": { - "Office": "Iroda" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Offline jelentés" - }, - "Older": { - "Older": "Régebbi" - }, - "On": { - "On": "Be" - }, - "On-Demand": { - "On-Demand": "Igény szerint" - }, - "On-Screen Displays": { - "On-Screen Displays": "Képernyőkijelzők" - }, - "On-screen Displays": { - "On-screen Displays": "Képernyőkijelzők" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Csak az idő- vagy helyalapú szabályok szerint állítsa a gammát." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "Csak a DMS által kezelt PAM-ra van hatással. Ha a greetd már tartalmazza a pam_fprintd-t, az ujjlenyomat-olvasó engedélyezve marad." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Csak az aktuális monitor ablakainak megjelenítése minden dokkon" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Csak akkor látható, ha a hibernálás támogatott a rendszeren" - }, - "Opacity": { - "Opacity": "Átlátszóság" - }, - "Opaque": { - "Opaque": "Átlátszatlan" - }, - "Open": { - "Open": "Megnyitás" - }, - "Open App": { - "Open App": "Alkalmazás megnyitása" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Nyisd meg a KDE Connectet a telefonodon" - }, - "Open Notepad File": { - "Open Notepad File": "Jegyzettömb-fájl megnyitása" - }, - "Open a new note": { - "Open a new note": "Új jegyzet megnyitása" - }, - "Open folder": { - "Open folder": "Mappa megnyitása" - }, - "Open in Browser": { - "Open in Browser": "Megnyitás böngészőben" - }, - "Open in terminal": { - "Open in terminal": "Megnyitás terminálban" - }, - "Open search bar to find text": { - "Open search bar to find text": "Keresősáv megnyitása a szöveg kereséséhez" - }, - "Open with...": { - "Open with...": "Megnyitás ezzel…" - }, - "Opening SMS": { - "Opening SMS": "SMS megnyitása" - }, - "Opening SMS app": { - "Opening SMS app": "SMS-alkalmazás megnyitása" - }, - "Opening file browser": { - "Opening file browser": "Fájlkezelő megnyitása" - }, - "Opening files": { - "Opening files": "Fájlok megnyitása" - }, - "Opening terminal: ": { - "Opening terminal: ": "Terminál megnyitása: " - }, - "Optional description": { - "Optional description": "Opcionális leírás" - }, - "Optional location": { - "Optional location": "Opcionális hely" - }, - "Options": { - "Options": "Opciók" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Widgetek rendszerezése összecsukható csoportokba" - }, - "Original: %1": { - "Original: %1": "Eredeti: %1" - }, - "Other": { - "Other": "Egyéb" - }, - "Outline": { - "Outline": "Körvonal" - }, - "Output": { - "Output": "Kimenet" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Kimeneti terület majdnem tele" - }, - "Output Area Full": { - "Output Area Full": "Kimeneti terület tele" - }, - "Output Device": { - "Output Device": "Kimeneti eszköz" - }, - "Output Devices": { - "Output Devices": "Kimeneti eszközök" - }, - "Output Tray Missing": { - "Output Tray Missing": "Kimeneti tálca hiányzik" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "A kimenetek include bejegyzés hiányzik" - }, - "Overcast": { - "Overcast": "Borult" - }, - "Overflow": { - "Overflow": "Túlcsordulás" - }, - "Overridden by config": { - "Overridden by config": "Felülírta a konfiguráció" - }, - "Override": { - "Override": "Felülírás" - }, - "Override Border Size": { - "Override Border Size": "Szegélyméret felülbírálása" - }, - "Override Corner Radius": { - "Override Corner Radius": "Sarokkerekítés felülbírálása" - }, - "Override Gaps": { - "Override Gaps": "Térközök felülbírálása" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Globális elrendezési beállítások felülbírálása ehhez a kimenethez" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Terminál felülbírálása egyéni paranccsal vagy szkripttel" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "A globális árnyék felülbírálása sávonkénti beállításokkal" - }, - "Overrides": { - "Overrides": "Felülírások" - }, - "Overview": { - "Overview": "Áttekintés" - }, - "Overview of your network connections": { - "Overview of your network connections": "Hálózati kapcsolatok áttekintése" - }, - "Overwrite": { - "Overwrite": "Felülírás" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "A PAM már biztosítja az ujjlenyomatos hitelesítést. Engedélyezd ezt a bejelentkezéskori megjelenítéshez." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "A PAM már biztosítja a biztonsági kulcsos hitelesítést. Engedélyezd ezt a bejelentkezéskori megjelenítéshez." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "A PAM biztosítja az ujjlenyomatos hitelesítést, de az elérhetőséget nem sikerült megerősíteni." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "A PAM biztosítja az ujjlenyomatos hitelesítést, de még nincsenek ujjlenyomatok regisztrálva." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "A PAM biztosítja az ujjlenyomatos hitelesítést, de nem található olvasó." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Keretezés" - }, - "Pad Hours": { - "Pad Hours": "Kezdő nulla az órákhoz" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "Órák kiegészítése nullával (02:00 vs 2:00)" - }, - "Padding": { - "Padding": "Belső margó" - }, - "Pair": { - "Pair": "Párosítás" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Bluetooth-eszköz párosítása" - }, - "Paired": { - "Paired": "Párosítva" - }, - "Pairing": { - "Pairing": "Párosítás" - }, - "Pairing failed": { - "Pairing failed": "A párosítás sikertelen" - }, - "Pairing request from": { - "Pairing request from": "Párosítási kérelem érkezett innen:" - }, - "Pairing request sent": { - "Pairing request sent": "Párosítási kérelem elküldve" - }, - "Pairing requested": { - "Pairing requested": "Párosítás kérve" - }, - "Pairing...": { - "Pairing...": "Párosítás…" - }, - "Partly Cloudy": { - "Partly Cloudy": "Részben felhős" - }, - "Passkey:": { - "Passkey:": "Párosítási kód:" - }, - "Password": { - "Password": "Jelszó" - }, - "Password...": { - "Password...": "Jelszó…" - }, - "Paste": { - "Paste": "Beillesztés" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Egy videófájl vagy videókat tartalmazó mappa elérési útja" - }, - "Pattern": { - "Pattern": "Minta" - }, - "Pause": { - "Pause": "Szüneteltetés" - }, - "Paused": { - "Paused": "Szüneteltetve" - }, - "Pending": { - "Pending": "Függőben" - }, - "Pending Charge": { - "Pending Charge": "Függőben lévő töltés" - }, - "Pending Discharge": { - "Pending Discharge": "Függőben lévő merülés" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Módonkénti háttérképek" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Monitoronkénti háttérképek" - }, - "Per-screen config": { - "Per-screen config": "Képernyőnkénti konfiguráció" - }, - "Percentage": { - "Percentage": "Százalék" - }, - "Performance": { - "Performance": "Teljesítmény" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Engedély megtagadva a profilkép beállításához." - }, - "Personalization": { - "Personalization": "Személyre szabás" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "A telefonos kapcsolat nem érhető el" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "A telefonos kapcsolat nem érhető el" - }, - "Phone number": { - "Phone number": "Telefonszám" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Minden alkalommal válasszon más véletlenszerű videót ugyanabból a mappából" - }, - "Pictures": { - "Pictures": "Képek" - }, - "Pin": { - "Pin": "Rögzítés" - }, - "Pin to Dock": { - "Pin to Dock": "Rögzítés a dokkra" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping elküldve" - }, - "Ping sent to": { - "Ping sent to": "Ping elküldve ide:" - }, - "Pinned": { - "Pinned": "Rögzítve" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Kitűzött és futó alkalmazások átrendezése húzással" - }, - "Pixelate": { - "Pixelate": "Képpontosítás" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Helyezd ide a bővítménykönyvtárakat. Minden bővítménynek rendelkeznie kell egy plugin.json fájllal." - }, - "Place plugins in %1": { - "Place plugins in %1": "Bővítmények helye: %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Videó lejátszása a képernyő zárolásakor." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Hang lejátszása az értesítések érkezésekor" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Hang lejátszása a tápkábel csatlakoztatásakor" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Hang lejátszása a hangerő állításakor" - }, - "Play sounds for system events": { - "Play sounds for system events": "Hang lejátszása rendszereseményekkor" - }, - "Playback": { - "Playback": "Lejátszás" - }, - "Playback error: ": { - "Playback error: ": "Lejátszási hiba: " - }, - "Please wait...": { - "Please wait...": "Kis türelmet…" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Adj nevet az új %1 munkamenetnek" - }, - "Plugged In": { - "Plugged In": "Csatlakoztatva" - }, - "Plugged in": { - "Plugged in": "Csatlakoztatva" - }, - "Plugin": { - "Plugin": "Bővítmény" - }, - "Plugin Directory": { - "Plugin Directory": "Bővítménymappa" - }, - "Plugin Management": { - "Plugin Management": "Bővítménykezelés" - }, - "Plugin Visibility": { - "Plugin Visibility": "Bővítmény láthatósága" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "A bővítmény le van tiltva - engedélyezd a bővítménybeállításokban a használathoz" - }, - "Plugins": { - "Plugins": "Bővítmények" - }, - "Pointer": { - "Pointer": "Mutató" - }, - "Popout Shadows": { - "Popout Shadows": "Felugró ablak árnyékok" - }, - "Popouts": { - "Popouts": "Felugró ablakok" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "A felugró ablakok és kizárólagos párbeszédablakok a globális animációs sebességet követik (letiltás az egyéni testreszabáshoz)" - }, - "Popup Only": { - "Popup Only": "Csak felugró" - }, - "Popup Position": { - "Popup Position": "Felugró ablak pozíciója" - }, - "Popup Shadow": { - "Popup Shadow": "Felugró ablak árnyéka" - }, - "Popup Transparency": { - "Popup Transparency": "Felugró ablak átlátszósága" - }, - "Popup behavior, position": { - "Popup behavior, position": "Felugró ablak viselkedése, pozíciója" - }, - "Port": { - "Port": "Port" - }, - "Portal": { - "Portal": "Portál" - }, - "Position": { - "Position": "Pozíció" - }, - "Position, pinned apps": { - "Position, pinned apps": "Pozíció, rögzített alkalmazások" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Lehetséges felülírási konfliktusok" - }, - "Power": { - "Power": "Energia" - }, - "Power & Security": { - "Power & Security": "Energia és biztonság" - }, - "Power & Sleep": { - "Power & Sleep": "Energia és alvás" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Főkapcsoló művelet megerősítése" - }, - "Power Menu Customization": { - "Power Menu Customization": "Főkapcsoló menü testreszabása" - }, - "Power Off": { - "Power Off": "Leállítás" - }, - "Power Options": { - "Power Options": "Energiabeállítások" - }, - "Power Profile": { - "Power Profile": "Energiaprofil" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Energiaprofil romlása" - }, - "Power Saver": { - "Power Saver": "Energiatakarékos mód" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Monitorok kikapcsolása zároláskor" - }, - "Power profile management available": { - "Power profile management available": "Az energiaprofil-kezelés elérhető" - }, - "Power source": { - "Power source": "Áramforrás" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Az utolsó sikeres felhasználónév előre kitöltése az üdvözlőképernyőn" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "Az utolsó használt munkamenet előre kijelölése az üdvözlőképernyőn" - }, - "Precip": { - "Precip": "Csapadék" - }, - "Precipitation": { - "Precipitation": "Csapadék" - }, - "Precipitation Chance": { - "Precipitation Chance": "Csapadék esélye" - }, - "Preference": { - "Preference": "Beállítás" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Előre beállított szélességek (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Nyomd meg az 'n' billentyűt vagy kattints az 'Új munkamenet' gombra a létrehozáshoz" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Nyomd meg az Entert a hangrendszer újraindulásához és a módosítások alkalmazásához" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Enter a beillesztéshez, Shift+Enter a másoláshoz" - }, - "Press key...": { - "Press key...": "Nyomj meg egy billentyűt…" - }, - "Pressure": { - "Pressure": "Légnyomás" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Képernyő időtúllépésének megakadályozása" - }, - "Preview": { - "Preview": "Előnézet" - }, - "Primary": { - "Primary": "Elsődleges" - }, - "Primary Container": { - "Primary Container": "Elsődleges tároló" - }, - "Print Server Management": { - "Print Server Management": "Nyomtatókiszolgáló-kezelés" - }, - "Print Server not available": { - "Print Server not available": "A nyomtatókiszolgáló nem érhető el" - }, - "Printer": { - "Printer": "Nyomtató" - }, - "Printer Classes": { - "Printer Classes": "Nyomtatóosztályok" - }, - "Printer created successfully": { - "Printer created successfully": "Nyomtató sikeresen létrehozva" - }, - "Printer deleted": { - "Printer deleted": "Nyomtató törölve" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nyomtató neve (szóköz nélkül)" - }, - "Printer reachable": { - "Printer reachable": "Nyomtató elérhető" - }, - "Printers": { - "Printers": "Nyomtatók" - }, - "Printers: ": { - "Printers: ": "Nyomtatók: " - }, - "Prioritize performance": { - "Prioritize performance": "Teljesítmény előtérbe helyezése" - }, - "Priority": { - "Priority": "Prioritás" - }, - "Privacy Indicator": { - "Privacy Indicator": "Adatvédelmi jelző" - }, - "Privacy Mode": { - "Privacy Mode": "Adatvédelmi mód" - }, - "Private Key Password": { - "Private Key Password": "Titkos kulcs jelszava" - }, - "Process Count": { - "Process Count": "Folyamatszám" - }, - "Processes": { - "Processes": "Folyamatok" - }, - "Processes:": { - "Processes:": "Folyamatok:" - }, - "Processing": { - "Processing": "Feldolgozás" - }, - "Profile Image Error": { - "Profile Image Error": "Profilképhiba" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profil aktiválva: %1" - }, - "Profile deleted": { - "Profile deleted": "Profil törölve" - }, - "Profile error": { - "Profile error": "Profilhiba" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "A profilkép túl nagy, használj kisebb képet." - }, - "Profile name": { - "Profile name": "Profilnév" - }, - "Profile not found": { - "Profile not found": "Profil nem található" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profil mentve: %1" - }, - "Protocol": { - "Protocol": "Protokoll" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "A QtMultimedia nem érhető el" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "A QtMultimedia nem érhető el - a videó képernyővédőhöz qt multimedia szolgáltatások szükségesek" - }, - "Quick Access": { - "Quick Access": "Gyors elérés" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Gyors hozzáférés az alkalmazásindítóhoz" - }, - "Quick access to color picker": { - "Quick access to color picker": "Gyors hozzáférés a színválasztóhoz" - }, - "Quick access to notepad": { - "Quick access to notepad": "Gyors hozzáférés a jegyzettömbhöz" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Gyors jegyzetkészítő oldalpanel" - }, - "Quick system toggles": { - "Quick system toggles": "Gyors rendszerkapcsolók" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Sugár" - }, - "Rain": { - "Rain": "Eső" - }, - "Rain Chance": { - "Rain Chance": "Eső esélye" - }, - "Rainbow": { - "Rainbow": "Szivárvány" - }, - "Random": { - "Random": "Véletlenszerű" - }, - "Rate": { - "Rate": "Sebesség" - }, - "Read:": { - "Read:": "Olvasás:" - }, - "Reason": { - "Reason": "Ok" - }, - "Reboot": { - "Reboot": "Újraindítás" - }, - "Recent Colors": { - "Recent Colors": "Legutóbbi színek" - }, - "Recently Used Apps": { - "Recently Used Apps": "Legutóbb használt alkalmazások" - }, - "Recommended available": { - "Recommended available": "Ajánlott, elérhető" - }, - "Refresh": { - "Refresh": "Újratöltés" - }, - "Refresh Weather": { - "Refresh Weather": "Időjárás frissítése" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Elutasítás" - }, - "Reject Jobs": { - "Reject Jobs": "Feladatok elutasítása" - }, - "Release": { - "Release": "Felengedés" - }, - "Reload Plugin": { - "Reload Plugin": "Bővítmény újratöltése" - }, - "Remaining": { - "Remaining": "Hátralévő" - }, - "Remaining / Total": { - "Remaining / Total": "Hátralévő / Összesen" - }, - "Remember Last Query": { - "Remember Last Query": "Utolsó lekérdezés megjegyzése" - }, - "Remember last session": { - "Remember last session": "Utolsó munkamenet megjegyzése" - }, - "Remember last user": { - "Remember last user": "Utolsó felhasználó megjegyzése" - }, - "Remove": { - "Remove": "Eltávolítás" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Widget térköz eltávolítása" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Rések és szegély eltávolítása az ablakok maximalizálásakor" - }, - "Rename": { - "Rename": "Átnevezés" - }, - "Rename Session": { - "Rename Session": "Munkamenet átnevezése" - }, - "Rename Workspace": { - "Rename Workspace": "Munkaterület átnevezése" - }, - "Repeat": { - "Repeat": "Ismétlés" - }, - "Replacement": { - "Replacement": "Helyettesítés" - }, - "Report": { - "Report": "Jelentés" - }, - "Request Pairing": { - "Request Pairing": "Párosítás kérése" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Megköveteli a gomb/billentyű nyomva tartását a kikapcsolás, újraindítás, felfüggesztés, hibernálás és kijelentkezés megerősítéséhez" - }, - "Required plugin: ": { - "Required plugin: ": "Szükséges bővítmény: " - }, - "Requires %1": { - "Requires %1": "%1 szükséges" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Szükséges a „dgop” eszköz" - }, - "Requires DMS %1": { - "Requires DMS %1": "Szükséges DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Szükséges a DWL kompozitor" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "A Quickshell újabb verziója szükséges" - }, - "Requires night mode support": { - "Requires night mode support": "Éjszakai mód támogatás szükséges" - }, - "Reset": { - "Reset": "Visszaállítás" - }, - "Reset Position": { - "Reset Position": "Pozíció visszaállítása" - }, - "Reset Size": { - "Reset Size": "Méret visszaállítása" - }, - "Reset to default name": { - "Reset to default name": "Visszaállítás az alapértelmezett névre" - }, - "Resize Widget": { - "Resize Widget": "Widget méretezése" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Felbontás és frissítés" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Felbontás, pozíció, méretezés" - }, - "Restart DMS": { - "Restart DMS": "DMS újraindítása" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "A DankMaterialShell újraindítása" - }, - "Restarting audio system...": { - "Restarting audio system...": "Hangrendszer újraindítása…" - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "Speciális munkaterület ablakainak visszaállítása" - }, - "Resume": { - "Resume": "Folytatás" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Görgetési irány megfordítása" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Munkaterület-váltási irány megfordítása a sáv feletti görgetéskor" - }, - "Revert": { - "Revert": "Visszaállítás" - }, - "Right": { - "Right": "Jobb" - }, - "Right Center": { - "Right Center": "Jobb közép" - }, - "Right Section": { - "Right Section": "Jobb oldali szakasz" - }, - "Right Tiling": { - "Right Tiling": "Jobb oldali csempézés" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Kattints jobb gombbal és húzd bárhol a widgeten" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Kattints jobb gombbal és húzd a jobb alsó sarkot" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Kattints jobb gombbal a sáv widgetre a váltáshoz" - }, - "Ring": { - "Ring": "Megcsörgetés" - }, - "Ringing": { - "Ringing": "Csörgetés" - }, - "Ripple Effects": { - "Ripple Effects": "Hullám effektusok" - }, - "Root Filesystem": { - "Root Filesystem": "Gyökérkönyvtár fájlrendszer" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Lekerekített sarkok az ablakoknál" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Ablakok lekerekített sarkai (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Ablakok lekerekített sarkai (decoration.rounding)" - }, - "Rule": { - "Rule": "Szabály" - }, - "Rule Name": { - "Rule Name": "Szabály neve" - }, - "Rules (%1)": { - "Rules (%1)": "Szabályok (%1)" - }, - "Run Again": { - "Run Again": "Futtatás újra" - }, - "Run DMS Templates": { - "Run DMS Templates": "DMS-sablonok futtatása" - }, - "Run User Templates": { - "Run User Templates": "Felhasználói sablonok futtatása" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Program futtatása (pl. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Héjparancs futtatása (pl. notify-send)" - }, - "Running Apps": { - "Running Apps": "Futó alkalmazások" - }, - "Running Apps Settings": { - "Running Apps Settings": "Futó alkalmazások beállításai" - }, - "Running greeter sync…": { - "Running greeter sync…": "Üdvözlőképernyő szinkronizálása folyamatban…" - }, - "SDR Brightness": { - "SDR Brightness": "SDR-fényerő" - }, - "SDR Saturation": { - "SDR Saturation": "SDR-színtelítettség" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Mentés" - }, - "Save Notepad File": { - "Save Notepad File": "Jegyzettömb-fájl mentése" - }, - "Save QR Code": { - "Save QR Code": "QR-kód mentése" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Kijelző-konfigurációk mentése és váltása" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Kritikus prioritású értesítések mentése az előzményekbe" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Elutasított értesítések mentése az előzményekbe" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Alacsony prioritású értesítések mentése az előzményekbe" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Normál prioritású értesítések mentése az előzményekbe" - }, - "Save password": { - "Save password": "Jelszó mentése" - }, - "Saved": { - "Saved": "Mentve" - }, - "Saved Configurations": { - "Saved Configurations": "Mentett konfigurációk" - }, - "Saved Note": { - "Saved Note": "Mentett jegyzet" - }, - "Saved item deleted": { - "Saved item deleted": "Mentett elem törölve" - }, - "Saving...": { - "Saving...": "Mentés…" - }, - "Scale": { - "Scale": "Skála" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "A DankBar betűméretének független méretezése" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "DankBar ikonméretek független skálázása" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Betűméret skálázása a felületen" - }, - "Scan": { - "Scan": "Szkennelés" - }, - "Scanning": { - "Scanning": "Szkennelés" - }, - "Scanning...": { - "Scanning...": "Keresés…" - }, - "Science": { - "Science": "Tudomány" - }, - "Score": { - "Score": "Pontszám" - }, - "Screen Sharing": { - "Screen Sharing": "Képernyőmegosztás" - }, - "Screen sharing": { - "Screen sharing": "Képernyőmegosztás" - }, - "Scroll": { - "Scroll": "Görgetés" - }, - "Scroll Factor": { - "Scroll Factor": "Görgetési tényező" - }, - "Scroll GitHub": { - "Scroll GitHub": "Scroll GitHub" - }, - "Scroll Wheel": { - "Scroll Wheel": "Egérgörgő" - }, - "Scroll song title": { - "Scroll song title": "Zeneszám címének görgetése" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Cím görgetése, ha nem fér bele a widgetbe" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Egérgörgő viselkedése a média widgeten" - }, - "Scrolling": { - "Scrolling": "Görgetés" - }, - "Search App Actions": { - "Search App Actions": "Alkalmazásműveletek keresése" - }, - "Search Options": { - "Search Options": "Keresési beállítások" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Keresés billentyűkombináció, leírás vagy műveletnév alapján.\n\nAz alapértelmezett művelet a vágólapra másolja a gyorsbillentyűt.\nKattints jobb gombbal vagy nyomd meg a jobb nyilat a gyakran használt gyorsbillentyűk rögzítéséhez – ezek a keresésen kívül felül jelennek meg." - }, - "Search for a location...": { - "Search for a location...": "Keress rá egy helyre…" - }, - "Search keybinds...": { - "Search keybinds...": "Billentyűk keresése…" - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Gyorsbillentyűk keresése a kompozitortól és az alkalmazásoktól" - }, - "Search plugins...": { - "Search plugins...": "Bővítmények keresése…" - }, - "Search processes...": { - "Search processes...": "Folyamatok keresése…" - }, - "Search sessions...": { - "Search sessions...": "Munkamenetek keresése…" - }, - "Search themes...": { - "Search themes...": "Témák keresése…" - }, - "Search widgets...": { - "Search widgets...": "Widgetek keresése…" - }, - "Search...": { - "Search...": "Keresés…" - }, - "Searching...": { - "Searching...": "Keresés…" - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Második faktor (ÉS)" - }, - "Secondary": { - "Secondary": "Másodlagos" - }, - "Secured": { - "Secured": "Védett" - }, - "Security": { - "Security": "Biztonság" - }, - "Security & privacy": { - "Security & privacy": "Biztonság és adatvédelem" - }, - "Security key mode": { - "Security key mode": "Biztonsági kulcs mód" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "A biztonsági kulcs elérhetőségét nem sikerült megerősíteni." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Biztonsági kulcs támogatás észlelve, de nem található regisztrált kulcs. Most is engedélyezheted, és regisztrálhatsz egyet később." - }, - "Select": { - "Select": "Kiválasztás" - }, - "Select Application": { - "Select Application": "Alkalmazás kiválasztása" - }, - "Select Bar": { - "Select Bar": "Sáv kiválasztása" - }, - "Select Custom Theme": { - "Select Custom Theme": "Egyéni téma kiválasztása" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Dokkindító logó kiválasztása" - }, - "Select File to Send": { - "Select File to Send": "Küldendő fájl kiválasztása" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Indító logó kiválasztása" - }, - "Select Profile Image": { - "Select Profile Image": "Profilkép kiválasztása" - }, - "Select Video or Folder": { - "Select Video or Folder": "Videó vagy mappa kiválasztása" - }, - "Select Wallpaper": { - "Select Wallpaper": "Háttérkép kiválasztása" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Háttérkép könyvtár kiválasztása" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Válassz színt a palettáról, vagy használd az egyéni csúszkákat" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Válassz ki egy widgetet az asztalhoz való hozzáadáshoz. Minden widget egy külön példány, saját beállításokkal." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Válassz ki egy widgetet a hozzáadáshoz. Több példányt is hozzáadhatsz ugyanabból a widgetből, ha szükséges." - }, - "Select a window...": { - "Select a window...": "Válassz egy ablakot…" - }, - "Select an image file...": { - "Select an image file...": "Képfájl kiválasztása…" - }, - "Select at least one provider": { - "Select at least one provider": "Válassz ki legalább egy szolgáltatót" - }, - "Select device": { - "Select device": "Eszköz kiválasztása" - }, - "Select device...": { - "Select device...": "Eszköz kiválasztása…" - }, - "Select driver...": { - "Select driver...": "Illesztőprogram kiválasztása…" - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Betűvastagság a felületen lévő szövegekhez" - }, - "Select greeter background image": { - "Select greeter background image": "Üdvözlőképernyő háttérképének kiválasztása" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Válassz monitort a háttérkép konfigurálásához" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Rögzített szélességű betűtípus (folyamatlistához és technikai kijelzőkhöz)" - }, - "Select network": { - "Select network": "Hálózat kiválasztása" - }, - "Select system sound theme": { - "Select system sound theme": "Rendszerhang-téma kiválasztása" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Betűtípus-család a felületen lévő szövegekhez" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Válaszd ki a háttérkép alapú színekhez használt paletta algoritmust" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Válaszd ki a befoglalni kívánt gyorsbillentyű-szolgáltatókat" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Válaszd ki, mely átmenetek legyenek a véletlenszerűsítésben" - }, - "Select...": { - "Select...": "Kiválasztás…" - }, - "Selected image file not found.": { - "Selected image file not found.": "A kiválasztott képfájl nem található." - }, - "Send": { - "Send": "Küldés" - }, - "Send Clipboard": { - "Send Clipboard": "Vágólap küldése" - }, - "Send File": { - "Send File": "Fájl küldése" - }, - "Send SMS": { - "Send SMS": "SMS küldése" - }, - "Sending": { - "Sending": "Küldés" - }, - "Separator": { - "Separator": "Elválasztó" - }, - "Server": { - "Server": "Kiszolgáló" - }, - "Session Filter": { - "Session Filter": "Munkamenet szűrő" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Egyéni eszköznév beállítása" - }, - "Set custom name": { - "Set custom name": "Egyéni név beállítása" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Egyéni nevek beállítása a hangbemeneti eszközökhöz" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Egyéni nevek beállítása a hangkimeneti eszközökhöz" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Különböző háttérképek beállítása minden csatlakoztatott monitorhoz" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Különböző háttérképek beállítása világos és sötét módhoz" - }, - "Set key and action to save": { - "Set key and action to save": "Állítsd be a billentyűt és a műveletet a mentéshez" - }, - "Set notification rules": { - "Set notification rules": "Értesítési szabályok beállítása" - }, - "Settings": { - "Settings": "Beállítások" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "A beállítások csak olvashatók. A módosítások nem fognak megmaradni." - }, - "Setup": { - "Setup": "Beállítás" - }, - "Shadow Color": { - "Shadow Color": "Árnyék színe" - }, - "Shadow Intensity": { - "Shadow Intensity": "Árnyék intenzitása" - }, - "Shadow Opacity": { - "Shadow Opacity": "Árnyék átlátszatlansága" - }, - "Shadow Override": { - "Shadow Override": "Árnyék felülbírálása" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Árnyék emelése a sávokon és paneleken" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Árnyék emelése a modális ablakokon és párbeszédpaneleken" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "Árnyék emelése a felugrókon, OSD-ken és legördülő menükön" - }, - "Shadows": { - "Shadows": "Árnyékok" - }, - "Share": { - "Share": "Megosztás" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Gammavezérlési beállítások megosztása" - }, - "Share Text": { - "Share Text": "Szöveg megosztása" - }, - "Share URL": { - "Share URL": "URL megosztása" - }, - "Shared": { - "Shared": "Megosztva" - }, - "Shell": { - "Shell": "Héj" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Összes törlése • Esc: Bezárás" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter a beillesztéshez" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Másolás • Shift+Del: Összes törlése • Esc: Bezárás" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Beillesztés • Shift+Del: Összes törlése • Esc: Bezárás" - }, - "Short": { - "Short": "Rövid" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Gyorsbillentyű (%1)" - }, - "Shortcuts": { - "Shortcuts": "Gyorsbillentyűk" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Gyorsbillentyűk (%1)" - }, - "Show": { - "Show": "Megjelenítés" - }, - "Show 3rd Party": { - "Show 3rd Party": "Külső bővítmények megjelenítése" - }, - "Show All Tags": { - "Show All Tags": "Összes címke megjelenítése" - }, - "Show Badge": { - "Show Badge": "Jelvény megjelenítése" - }, - "Show CPU": { - "Show CPU": "CPU megjelenítése" - }, - "Show CPU Graph": { - "Show CPU Graph": "CPU-grafikon megjelenítése" - }, - "Show CPU Temp": { - "Show CPU Temp": "CPU-hőmérséklet megjelenítése" - }, - "Show Date": { - "Show Date": "Dátum megjelenítése" - }, - "Show Disk": { - "Show Disk": "Lemez megjelenítése" - }, - "Show Dock": { - "Show Dock": "Dokk megjelenítése" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Hőérzet megjelenítése" - }, - "Show Footer": { - "Show Footer": "Élőláb megjelenítése" - }, - "Show Forecast": { - "Show Forecast": "Előrejelzés megjelenítése" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "GPU-hőmérséklet megjelenítése" - }, - "Show Header": { - "Show Header": "Fejléc megjelenítése" - }, - "Show Hibernate": { - "Show Hibernate": "Hibernáció megjelenítése" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Óraszámok megjelenítése" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Óránkénti előrejelzés megjelenítése" - }, - "Show Humidity": { - "Show Humidity": "Páratartalom megjelenítése" - }, - "Show Launcher Button": { - "Show Launcher Button": "Indítógomb megjelenítése" - }, - "Show Line Numbers": { - "Show Line Numbers": "Sorok számának megjelenítése" - }, - "Show Location": { - "Show Location": "Hely megjelenítése" - }, - "Show Lock": { - "Show Lock": "Zárolás megjelenítése" - }, - "Show Log Out": { - "Show Log Out": "Kijelentkezés megjelenítése" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Material Design hullám animációk megjelenítése az interaktív elemeken" - }, - "Show Media Player": { - "Show Media Player": "Médialejátszó megjelenítése" - }, - "Show Memory": { - "Show Memory": "Memória megjelenítése" - }, - "Show Memory Graph": { - "Show Memory Graph": "Memória grafikon megjelenítése" - }, - "Show Memory in GB": { - "Show Memory in GB": "Memória megjelenítése GB-ban" - }, - "Show Network": { - "Show Network": "Hálózat megjelenítése" - }, - "Show Network Graph": { - "Show Network Graph": "Hálózati grafikon megjelenítése" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Csak az elfoglalt munkaterületek megjelenítése" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Túlcsordulási jelvényszámláló megjelenítése" - }, - "Show Password Field": { - "Show Password Field": "Jelszómező megjelenítése" - }, - "Show Power Actions": { - "Show Power Actions": "Főkapcsoló műveletek megjelenítése" - }, - "Show Power Off": { - "Show Power Off": "Leállítás megjelenítése" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Csapadékvalószínűség megjelenítése" - }, - "Show Pressure": { - "Show Pressure": "Légnyomás megjelenítése" - }, - "Show Profile Image": { - "Show Profile Image": "Profilkép megjelenítése" - }, - "Show Reboot": { - "Show Reboot": "Újraindítás megjelenítése" - }, - "Show Restart DMS": { - "Show Restart DMS": "„DMS újraindítása” megjelenítése" - }, - "Show Saved Items": { - "Show Saved Items": "Mentett elemek megjelenítése" - }, - "Show Seconds": { - "Show Seconds": "Másodpercek megjelenítése" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Napkelte/Napnyugta megjelenítése" - }, - "Show Suspend": { - "Show Suspend": "Felfüggesztés megjelenítése" - }, - "Show Swap": { - "Show Swap": "Cserehely megjelenítése" - }, - "Show System Date": { - "Show System Date": "Dátum megjelenítése" - }, - "Show System Icons": { - "Show System Icons": "Rendszerikonok megjelenítése" - }, - "Show System Time": { - "Show System Time": "Rendszeridő megjelenítése" - }, - "Show Top Processes": { - "Show Top Processes": "Top folyamatok megjelenítése" - }, - "Show Weather Condition": { - "Show Weather Condition": "Időjárási körülmények megjelenítése" - }, - "Show Week Number": { - "Show Week Number": "Hétszám megjelenítése" - }, - "Show Welcome": { - "Show Welcome": "Üdvözlőképernyő megjelenítése" - }, - "Show Wind Speed": { - "Show Wind Speed": "Szélsebesség megjelenítése" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Munkaterület alkalmazások megjelenítése" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Mind a 9 címke megjelenítése a csak foglalt címkék helyett (csak DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Körvonal megjelenítése a fókuszált munkaterület-jelző körül" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Cava hangvizualizáló megjelenítése a média widgeten" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Sötétített átfedés megjelenítése a kizárólagos párbeszédablakok mögött" - }, - "Show device": { - "Show device": "Eszköz megjelenítése" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Dokk megjelenítése, ha a lebegő ablakok nem takarják el a területét" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "Vetett árnyék megjelenítése az értesítési felugró ablakokon. Szükséges hozzá az M3 emelés engedélyezése a Téma és színek beállításnál." - }, - "Show in GB": { - "Show in GB": "Megjelenítés GB-ban" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Indító átfedés megjelenítése, amikor gépelsz a Niri-áttekintésben. Tiltsd le, ha másik indítót használsz." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Módlapok és billentyűzettippek megjelenítése alul." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "Értesítési felugró ablakok megjelenítése csak az éppen fókuszált monitoron" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "Értesítések megjelenítése csak az éppen fókuszált monitoron" - }, - "Show on Last Display": { - "Show on Last Display": "Megjelenítés az utolsó kijelzőn" - }, - "Show on Overlay": { - "Show on Overlay": "Megjelenítés az átfedésen" - }, - "Show on Overview": { - "Show on Overview": "Megjelenítés az áttekintésben" - }, - "Show on Overview Only": { - "Show on Overview Only": "Megjelenítés csak az áttekintésben" - }, - "Show on all connected displays": { - "Show on all connected displays": "Megjelenítés minden csatlakoztatott kijelzőn" - }, - "Show on screens:": { - "Show on screens:": "Megjelenítés képernyőkön:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Képernyőkijelző megjelenítése a fényerő változásakor" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Képernyőkijelző megjelenítése a Caps Lock állapotának változásakor" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Képernyőkijelző megjelenítése hangkimeneti eszközök váltásakor" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Képernyőkijelző megjelenítése az inaktivitás-megakadályozó állapotának változásakor" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Képernyőkijelző megjelenítése a médialejátszó állapotának változásakor" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Képernyőkijelző megjelenítése a médialejátszó hangerejének változásakor" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Képernyőkijelző megjelenítése a mikrofon némításakor/visszahangosításakor" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Képernyőkijelző megjelenítése az energiaprofil változásakor" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Képernyőkijelző megjelenítése a hangerő változásakor" - }, - "Show seconds": { - "Show seconds": "Másodpercek megjelenítése" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Időjárási információk megjelenítése a felső sávon és a vezérlőközponton" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Hétszám megjelenítése a naptárban" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Munkaterület indexszámok megjelenítése a felső sáv munkaterület-váltójában" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Munkaterület nevének megjelenítése a vízszintes sávokon, és az első betűjét a függőleges sávokon" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "A jelenleg fókuszált monitor munkaterületeinek megjelenítése" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Megjeleníti az összes futó alkalmazást fókuszjelzéssel" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Megjeleníti az aktuális munkaterületet és lehetővé teszi a váltást" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Megjelenik amikor a Caps Lock be van kapcsolva" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Megjelenik, ha a mikrofon, kamera vagy képernyőmegosztás aktív" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Leállítás" - }, - "Signal": { - "Signal": "Jel" - }, - "Signal:": { - "Signal:": "Jel:" - }, - "Size": { - "Size": "Méret" - }, - "Size Constraints": { - "Size Constraints": "Méretkorlátozások" - }, - "Size Offset": { - "Size Offset": "Méret eltolása" - }, - "Sizing": { - "Sizing": "Méretezés" - }, - "Skip": { - "Skip": "Kihagyás" - }, - "Skip confirmation": { - "Skip confirmation": "Megerősítés kihagyása" - }, - "Skip setup": { - "Skip setup": "Beállítás kihagyása" - }, - "Small": { - "Small": "Kicsi" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Intelligens kártyás hitelesítés" - }, - "Smartcard PIN": { - "Smartcard PIN": "Intelligens kártya PIN-kódja" - }, - "Snap": { - "Snap": "Illesztés" - }, - "Snow": { - "Snow": "Hó" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Néhány bővítmény a DMS újabb verzióját igényli:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Rendezés betűrend szerint" - }, - "Sort By": { - "Sort By": "Rendezés" - }, - "Sorting & Layout": { - "Sorting & Layout": "Rendezés és elrendezés" - }, - "Sound Theme": { - "Sound Theme": "Hangtéma" - }, - "Sounds": { - "Sounds": "Hangok" - }, - "Space between windows": { - "Space between windows": "Ablakok közötti hely" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Ablakok közötti távolság (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Ablakok közötti távolság (gaps_in és gaps_out)" - }, - "Spacer": { - "Spacer": "Térköz" - }, - "Spacing": { - "Spacing": "Távolság" - }, - "Speaker settings": { - "Speaker settings": "Hangszóró-beállítások" - }, - "Speed": { - "Speed": "Sebesség" - }, - "Spool Area Full": { - "Spool Area Full": "A nyomtatási sor megtelt" - }, - "Square Corners": { - "Square Corners": "Szögletes sarkok" - }, - "Stacked": { - "Stacked": "Halmozott" - }, - "Standard": { - "Standard": "Szabványos" - }, - "Start": { - "Start": "Indítás" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "A KDE Connect vagy a Valent indítása" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Indítsd el a KDE Connectet vagy a Valentet a bővítmény használatához" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Írd ide a jegyzeteidet…" - }, - "State": { - "State": "Állapot" - }, - "Status": { - "Status": "Állapot" - }, - "Stopped": { - "Stopped": "Megállítva" - }, - "Stopped Partly": { - "Stopped Partly": "Részlegesen megállítva" - }, - "Stopping": { - "Stopping": "Megállítás" - }, - "Stretch": { - "Stretch": "Nyújtás" - }, - "Stripes": { - "Stripes": "Csíkok" - }, - "Summary": { - "Summary": "Összegzés" - }, - "Sunrise": { - "Sunrise": "Napkelte" - }, - "Sunset": { - "Sunset": "Napnyugta" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Ha engedélyezve van, elnyomja az értesítési felugrókat" - }, - "Surface": { - "Surface": "Felület" - }, - "Surface Variant": { - "Surface Variant": "Felületváltozat" - }, - "Suspend": { - "Suspend": "Felfüggesztés" - }, - "Suspend behavior": { - "Suspend behavior": "Felfüggesztési viselkedés" - }, - "Suspend system after": { - "Suspend system after": "Felfüggesztés ennyi idő után" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Felfüggesztés, majd hibernálás" - }, - "Sway Website": { - "Sway Website": "Sway weboldal" - }, - "Switch User": { - "Switch User": "Felhasználóváltás" - }, - "Switch to power profile": { - "Switch to power profile": "Váltás energiaprofilra" - }, - "Sync": { - "Sync": "Szinkronizálás" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Mód szinkronizálása a portállal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Felugrók és kizárólagos párbeszédablakok szinkronizálása" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Pozíció szinkronizálása a képernyők között" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Szinkronizálás sikeresen befejeződött." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Sötét mód szinkronizálása a beállítási portálokkal a rendszer egészére vonatkozó témajavaslatokhoz" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "A szinkronizálás sikertelen lett háttér módban. Terminál mód megkísérlése az interaktív hitelesítéshez." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "A szinkronizáláshoz sudo hitelesítés szükséges. Terminál megnyitása a jelszó vagy ujjlenyomat használatához." - }, - "System": { - "System": "Rendszer" - }, - "System App Theming": { - "System App Theming": "Rendszeralkalmazás témázása" - }, - "System Check": { - "System Check": "Rendszerellenőrzés" - }, - "System Default": { - "System Default": "Rendszer alapértelmezett" - }, - "System Information": { - "System Information": "Rendszerinformáció" - }, - "System Monitor": { - "System Monitor": "Rendszerfigyelő" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Rendszerfigyelő nem elérhető" - }, - "System Sounds": { - "System Sounds": "Rendszerhangok" - }, - "System Tray": { - "System Tray": "Rendszertálca" - }, - "System Update": { - "System Update": "Rendszerfrissítés" - }, - "System Updater": { - "System Updater": "Rendszerfrissítő" - }, - "System Updates": { - "System Updates": "Rendszerfrissítések" - }, - "System notification area icons": { - "System notification area icons": "Rendszer értesítési terület ikonjai" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "A rendszerhangok nem elérhetők. Telepítsd a(z) %1 csomagot a hangtámogatáshoz." - }, - "System theme toggle": { - "System theme toggle": "Rendszertémaváltó" - }, - "System toast notifications": { - "System toast notifications": "Rendszer értesítési felugró üzenetek" - }, - "System update custom command": { - "System update custom command": "Rendszerfrissítési egyéni parancs" - }, - "Tab": { - "Tab": "Lap" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nav • ←→↑↓: Rács Nav • Enter/Szóköz: Kiválasztás" - }, - "Terminal": { - "Terminal": "Terminál" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Terminál egyéni további paraméterei" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "A terminál visszalépés sikertelen. Telepíts egy támogatott terminálemulátort, vagy futtasd a 'dms auth sync' parancsot." - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "A terminál tartalék megnyitása sikertelen. Telepíts egyet a támogatott terminálemulátorok közül, vagy futtasd a 'dms greeter sync' parancsot." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "Tartalék terminál megnyitva. Fejezd be ott a hitelesítési beállítást; a befejezés után automatikusan be fog záródni." - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "Terminál tartalék megnyitva, ott befejezheted a szinkronizálást; automatikusan be fog záródni, ha kész lesz." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "Használandó terminálmultiplexer-háttérprogram" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "Terminál megnyitva. Fejezd be ott a hitelesítési beállítást; a befejezés után automatikusan be fog záródni." - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "Terminál megnyitva, ott befejezheted a szinkronizálás hitelesítését; automatikusan be fog záródni, ha kész lesz." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminálok – Mindig sötét téma használata" - }, - "Test Connection": { - "Test Connection": "Kapcsolat tesztelése" - }, - "Test Page": { - "Test Page": "Tesztoldal" - }, - "Test page sent to printer": { - "Test page sent to printer": "Tesztoldal elküldve a nyomtatónak" - }, - "Testing...": { - "Testing...": "Tesztelés…" - }, - "Text": { - "Text": "Szöveg" - }, - "Text Color": { - "Text Color": "Szövegszín" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "A rendszerfigyeléshez a „dgop” eszköz szükséges.\nTelepítsd a dgop-ot a funkció használatához." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "A DMS_SOCKET környezeti változó nincs beállítva, vagy a socket nem elérhető. Az automatizált bővítménykezeléshez DMS_SOCKET szükséges." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Az alábbi beállítások módosítják a GTK és Qt beállításokat. Ha meg szeretnéd őrizni a jelenlegi konfigurációt, készíts róluk biztonsági másolatot (qt5ct.conf|qt6ct.conf és ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "A munkamenetekhez való csatlakozáskor használt egyéni parancs (első argumentumként a munkamenet nevét kapja)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "A nyomtató feladatlistája üres" - }, - "Theme & Colors": { - "Theme & Colors": "Téma és színek" - }, - "Theme Color": { - "Theme Color": "Témaszín" - }, - "Theme Registry": { - "Theme Registry": "Témanyilvántartás" - }, - "Themes": { - "Themes": "Témák" - }, - "Thickness": { - "Thickness": "Vastagság" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Külső bővítmény figyelmeztetés" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "A külső bővítményeket a közösség készíti, és a DankMaterialShell hivatalosan nem támogatja őket.\n\nEzek a bővítmények biztonsági és adatvédelmi kockázatokat jelenthetnek – telepítés csak saját felelősségre." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Ezt a billentyűt felülírja a config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Ez eltarthat néhány másodpercig" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Ez a bővítmény nem rendelkezik „settings_write” engedéllyel.\n\nAdd hozzá a \"permissions\": [\"settings_read\", \"settings_write\"] sort a plugin.json fájlhoz" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Ez a widget megakadályozza a GPU kikapcsolt állapotát, ami jelentősen befolyásolhatja a laptopok akkumulátor élettartamát. Nem ajánlott hibrid grafikus kártyával rendelkező laptopokon használni." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Ez törli az összes nem rögzített bejegyzést. %1 rögzített bejegyzés marad meg." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Ez véglegesen törölni fogja a vágólapelőzményeket." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Ez véglegesen eltávolítja ezt a mentett vágólapelemet. A művelet nem vonható vissza." - }, - "Thunderstorm": { - "Thunderstorm": "Zivatar" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Zivatar jégesővel" - }, - "Tile": { - "Tile": "Mozaik" - }, - "Tile H": { - "Tile H": "Vízszintes mozaik" - }, - "Tile V": { - "Tile V": "Függőleges mozaik" - }, - "Tiled": { - "Tiled": "Csempézett" - }, - "Tiled State": { - "Tiled State": "Csempézett állapot" - }, - "Tiling": { - "Tiling": "Csempézés" - }, - "Time": { - "Time": "Idő" - }, - "Time & Date Locale": { - "Time & Date Locale": "Idő és dátum területi beállítása" - }, - "Time & Weather": { - "Time & Weather": "Idő és időjárás" - }, - "Time Format": { - "Time Format": "Időformátum" - }, - "Time format": { - "Time format": "Időformátum" - }, - "Time remaining: %1": { - "Time remaining: %1": "Hátralévő idő: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Teljes töltésig hátralévő idő: %1" - }, - "Timed Out": { - "Timed Out": "Időtúllépés" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Időtúllépés a kritikus prioritású értesítésekhez" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Időtúllépés az alacsony prioritású értesítésekhez" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Időtúllépés a normál prioritású értesítésekhez" - }, - "Title": { - "Title": "Cím" - }, - "Title regex (optional)": { - "Title regex (optional)": "Cím reguláris kifejezése (opcionális)" - }, - "To Full": { - "To Full": "A teljes töltöttségig" - }, - "To update, run the following command:": { - "To update, run the following command:": "A frissítéshez futtasd a következő parancsot:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "A DMS-billentyű használatához távolítsd el vagy módosítsd a billentyűkombinációt a config.kdl fájlban" - }, - "Toast Messages": { - "Toast Messages": "Felugró üzenetek" - }, - "Today": { - "Today": "Ma" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "A sávkonfiguráció láthatóságának váltása" - }, - "Toggling...": { - "Toggling...": "Váltás…" - }, - "Tomorrow": { - "Tomorrow": "Holnap" - }, - "Tonal Spot": { - "Tonal Spot": "Tónusos pont" - }, - "Toner Empty": { - "Toner Empty": "Toner üres" - }, - "Toner Low": { - "Toner Low": "Toner alacsony" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "Túl sok kísérlet - kizárva" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "Túl sok sikertelen próbálkozás - a fiók zárolva lehet" - }, - "Tools": { - "Tools": "Eszközök" - }, - "Top": { - "Top": "Felső" - }, - "Top (Default)": { - "Top (Default)": "Fent (alapértelmezett)" - }, - "Top Bar Format": { - "Top Bar Format": "Felső sáv formátuma" - }, - "Top Center": { - "Top Center": "Fent középen" - }, - "Top Left": { - "Top Left": "Bal Felül" - }, - "Top Processes": { - "Top Processes": "Top folyamatok" - }, - "Top Right": { - "Top Right": "Jobb Felül" - }, - "Top Section": { - "Top Section": "Felső szakasz" - }, - "Total": { - "Total": "Összesen" - }, - "Total Jobs": { - "Total Jobs": "Összes feladat" - }, - "Touch your security key...": { - "Touch your security key...": "Érintsd meg a biztonsági kulcsodat..." - }, - "Transform": { - "Transform": "Átalakítás" - }, - "Transition Effect": { - "Transition Effect": "Átmeneti hatás" - }, - "Transparency": { - "Transparency": "Átlátszóság" - }, - "Trending GIFs": { - "Trending GIFs": "Népszerű GIF-ek" - }, - "Trending Stickers": { - "Trending Stickers": "Népszerű matricák" - }, - "Trigger": { - "Trigger": "Indító" - }, - "Trigger Prefix": { - "Trigger Prefix": "Indító előtag" - }, - "Trigger: %1": { - "Trigger: %1": "Indító: %1" - }, - "Trust": { - "Trust": "Megbízható" - }, - "Try a different search": { - "Try a different search": "Próbálkozz más kereséssel" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Az összes kijelző azonnali kikapcsolása a zárolás képernyő aktiválásakor" - }, - "Turn off monitors after": { - "Turn off monitors after": "Monitorok kikapcsolása ennyi idő után:" - }, - "Type": { - "Type": "Típus" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Írj be legalább 2 karaktert" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Írd be ezt az előtagot a gyorsbillentyűk kereséséhez" - }, - "Type to search files": { - "Type to search files": "Írj a fájlok kereséséhez" - }, - "Typography": { - "Typography": "Tipográfia" - }, - "Typography & Motion": { - "Typography & Motion": "Tipográfia és animáció" - }, - "Unavailable": { - "Unavailable": "Nem elérhető" - }, - "Unfocused Color": { - "Unfocused Color": "Nem fókuszált szín" - }, - "Ungrouped": { - "Ungrouped": "Csoportosítatlan" - }, - "Uninstall": { - "Uninstall": "Eltávolítás" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Üdvözlőképernyő eltávolítása" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Bővítmény eltávolítása" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Az eltávolítás befejeződött. Az üdvözlőképernyő el lett távolítva." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Eltávolítás sikertelen: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "Eltávolítod a DMS-üdvözlőképernyőt? (greeter) Ez törli a beállításokat és visszaállítja az előző megjelenítéskezelőt. Egy terminál fog megnyílni a sudo hitelesítéshez." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Eltávolítva: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Eltávolítás: %1" - }, - "Unknown": { - "Unknown": "Ismeretlen" - }, - "Unknown App": { - "Unknown App": "Ismeretlen alkalmazás" - }, - "Unknown Artist": { - "Unknown Artist": "Ismeretlen előadó" - }, - "Unknown Config": { - "Unknown Config": "Ismeretlen konfiguráció" - }, - "Unknown Device": { - "Unknown Device": "Ismeretlen eszköz" - }, - "Unknown GPU": { - "Unknown GPU": "Ismeretlen GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "Ismeretlen monitor" - }, - "Unknown Network": { - "Unknown Network": "Ismeretlen hálózat" - }, - "Unknown Title": { - "Unknown Title": "Ismeretlen cím" - }, - "Unknown Track": { - "Unknown Track": "Ismeretlen szám" - }, - "Unload on Close": { - "Unload on Close": "Kiürítés bezáráskor" - }, - "Unmute": { - "Unmute": "Visszahangosítás" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Felugró ablakok visszahangosítása ennyi időre: %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Névtelen szabály" - }, - "Unpair": { - "Unpair": "Párosítás megszüntetése" - }, - "Unpair failed": { - "Unpair failed": "A párosítás megszüntetése sikertelen" - }, - "Unpin": { - "Unpin": "Rögzítés feloldása" - }, - "Unpin from Dock": { - "Unpin from Dock": "Rögzítés feloldása a Dokkról" - }, - "Unsaved Changes": { - "Unsaved Changes": "Nem mentett változtatások" - }, - "Unsaved changes": { - "Unsaved changes": "Nem mentett változtatások" - }, - "Unsaved note...": { - "Unsaved note...": "Nem mentett jegyzet…" - }, - "Untitled": { - "Untitled": "Névtelen" - }, - "Untrust": { - "Untrust": "Nem megbízható" - }, - "Up to date": { - "Up to date": "Naprakész" - }, - "Update": { - "Update": "Frissítés" - }, - "Update All": { - "Update All": "Összes frissítése" - }, - "Update Plugin": { - "Update Plugin": "Bővítmény frissítése" - }, - "Uptime": { - "Uptime": "Működési idő" - }, - "Uptime:": { - "Uptime:": "Működési idő:" - }, - "Urgent Color": { - "Urgent Color": "Sürgős szín" - }, - "Usage Tips": { - "Usage Tips": "Használati tippek" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "24 órás időformátum használata a 12 órás AM/PM formátum helyett" - }, - "Use Custom Command": { - "Use Custom Command": "Egyéni parancs használata" - }, - "Use Grid Layout": { - "Use Grid Layout": "Rács elrendezés használata" - }, - "Use IP Location": { - "Use IP Location": "IP-cím használata" - }, - "Use Imperial Units": { - "Use Imperial Units": "Angolszász mértékegységek használata" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Angolszász mértékegységek (°F, mph, inHg) használata a metrikus (°C, km/h, hPa) helyett" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Rögzített szélességű betűtípus használata" - }, - "Use System Theme": { - "Use System Theme": "Rendszertéma használata" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Egyéni kép használata a bejelentkezési képernyőhöz, hagyd üresen az asztali háttérkép használatához." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Rögzített árnyékirány használata ehhez a sávhoz" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Biztonsági kulcs használata a képernyőzár hitelesítéséhez." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Külső háttérképkezelő használatához, mint például a swww, hyprpaper vagy a swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Animált, hullámzó folyamatjelzők használata a médialejátszáshoz" - }, - "Use custom border size": { - "Use custom border size": "Egyéni szegélyméret használata" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Egyéni szegély/fókuszgyűrű szélesség használata" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Egyéni parancs használata a rendszer frissítésére" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Egyéni térközök használata a sáv térközei helyett" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Egyéni ablaksugár használata a téma sugara helyett" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Egyéni ablaklekerekítés használata a téma sugara helyett" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Asztali háttérkép használata" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Ujjlenyomatos hitelesítés használata a képernyőzárhoz." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Világos téma használata a sötét helyett" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Méter per másodperc használata km/h helyett a szélsebességhez" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Kisebb értesítési kártyák használata" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Hangtéma használata a rendszerbeállításokból" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Azonos pozíció és méret használata minden kijelzőn" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Indító előtag használata az aktiváláshoz" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Akkor használatos, ha a kiemelőszín Egyéni-re van állítva" - }, - "User": { - "User": "Felhasználó" - }, - "Username": { - "Username": "Felhasználónév" - }, - "Username...": { - "Username...": "Felhasználónév…" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "A tartózkodási hely szerinti napkelte és napnyugta időpontokat használata." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Napkelte/napnyugta időpontok használata az éjszakai mód automatikus beállításához a tartózkodási helyed alapján." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "A Gammavezérlés megosztott beállításainak használata" - }, - "Utilities": { - "Utilities": "Segédprogramok" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN-kapcsolatok" - }, - "VPN Password": { - "VPN Password": "VPN jelszó" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN-konfiguráció frissítve" - }, - "VPN connections": { - "VPN connections": "VPN-kapcsolatok" - }, - "VPN deleted": { - "VPN deleted": "VPN-kapcsolat törölve" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN-profil importálva: %1" - }, - "VPN not available": { - "VPN not available": "A VPN nem elérhető" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN-állapot és gyors csatlakozás" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR csak teljes képernyőn" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR igény szerint" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Változó frissítési gyakoriság" - }, - "Verification": { - "Verification": "Ellenőrzés" - }, - "Version": { - "Version": "Verzió" - }, - "Vertical Deck": { - "Vertical Deck": "Függőleges köteg" - }, - "Vertical Grid": { - "Vertical Grid": "Függőleges rács" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Függőleges görgetés" - }, - "Vertical Tiling": { - "Vertical Tiling": "Függőleges csempézés" - }, - "Vibrant": { - "Vibrant": "Élénk" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Élénk paletta játékos telítettséggel." - }, - "Video Path": { - "Video Path": "Videó útvonala" - }, - "Video Screensaver": { - "Video Screensaver": "Videós képernyővédő" - }, - "Videos": { - "Videos": "Videók" - }, - "View Mode": { - "View Mode": "Nézetmód" - }, - "Visibility": { - "Visibility": "Láthatóság" - }, - "Visual Effects": { - "Visual Effects": "Vizuális effektusok" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Vizuális elválasztó a widgetek között" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Vizuális effektus a háttérkép változásakor" - }, - "Volume": { - "Volume": "Hangerő" - }, - "Volume Changed": { - "Volume Changed": "Hangerő megváltozott" - }, - "Volume Slider": { - "Volume Slider": "Hangerőszabályozó" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Hangerő, fényerő és egyéb rendszer képernyőkijelzők" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Háttérkép" - }, - "Wallpaper Error": { - "Wallpaper Error": "Háttérképhiba" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Háttérkép monitor" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Háttérkép kitöltési módja" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "A háttérkép feldolgozása sikertelen" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "A háttérkép feldolgozása sikertelen - ellenőrizd a háttérkép útvonalát" - }, - "Wallpapers": { - "Wallpapers": "Háttérképek" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Alkalmazandó meleg színhőmérséklet" - }, - "Warning": { - "Warning": "Figyelmeztetés" - }, - "Warnings": { - "Warnings": "Figyelmeztetések" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Hullámzó folyamatjelzők" - }, - "Weather": { - "Weather": "Időjárás" - }, - "Weather Widget": { - "Weather Widget": "Időjárás widget" - }, - "Welcome": { - "Welcome": "Üdvözlünk" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Üdvözlünk a DankMaterialShell-ben" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "Ha a Hyprland speciális munkaterületén lévő dokkolóablakra kattintasz, visszahozza azt a speciális munkaterületet, mielőtt az ablakra fókuszálna" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Ha engedélyezve van, az alkalmazások betűrendben vannak rendezve. Ha le van tiltva, az alkalmazások használati gyakoriság szerint vannak rendezve." - }, - "When locked": { - "When locked": "Zároláskor" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Ha a frissítő widget használatban van, akkor elrejtés (ha nem található frissítés)" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi jelszó" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi- és Ethernet-kapcsolatok" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi nem elérhető" - }, - "WiFi": { - "WiFi": "Wi-Fi" - }, - "WiFi Device": { - "WiFi Device": "Wi-Fi-eszköz" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Wi-Fi QR-kód ehhez: " - }, - "WiFi disabled": { - "WiFi disabled": "Wi-Fi letiltva" - }, - "WiFi enabled": { - "WiFi enabled": "Wi-Fi engedélyezve" - }, - "WiFi is off": { - "WiFi is off": "A Wi-Fi ki van kapcsolva" - }, - "WiFi off": { - "WiFi off": "Wi-Fi kikapcsolva" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Széles (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Widget háttérszíne" - }, - "Widget Management": { - "Widget Management": "Widgetkezelés" - }, - "Widget Outline": { - "Widget Outline": "Widget körvonal" - }, - "Widget Style": { - "Widget Style": "Widget stílus" - }, - "Widget Styling": { - "Widget Styling": "Widget stílus" - }, - "Widget Transparency": { - "Widget Transparency": "Widget átlátszósága" - }, - "Widget added": { - "Widget added": "Widget hozzáadva" - }, - "Widget removed": { - "Widget removed": "Widget eltávolítva" - }, - "Widgets": { - "Widgets": "Widgetek" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgetek, elrendezés, stílus" - }, - "Width": { - "Width": "Szélesség" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Ablakszegély szélessége (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Ablakszegély szélessége (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Ablakszegély és fókuszgyűrű szélessége" - }, - "Wind": { - "Wind": "Szél" - }, - "Wind Speed": { - "Wind Speed": "Szélsebesség" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Szélsebesség m/s-ban" - }, - "Window Corner Radius": { - "Window Corner Radius": "Ablaksarok sugara" - }, - "Window Gaps": { - "Window Gaps": "Ablakközök" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Ablakközök (px)" - }, - "Window Height": { - "Window Height": "Ablakmagasság" - }, - "Window Opening": { - "Window Opening": "Ablak megnyitása" - }, - "Window Rounding": { - "Window Rounding": "Ablaklekerekítés" - }, - "Window Rules": { - "Window Rules": "Ablakszabályok" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Az ablakszabályok include bejegyzés hiányzik" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Az ablakszabályok nincsenek beállítva" - }, - "Wipe": { - "Wipe": "Törlés" - }, - "Workspace": { - "Workspace": "Munkaterület" - }, - "Workspace Appearance": { - "Workspace Appearance": "Munkaterület megjelenése" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Munkaterület-indexszámok" - }, - "Workspace Names": { - "Workspace Names": "Munkaterület-nevek" - }, - "Workspace Padding": { - "Workspace Padding": "Munkaterület-margó" - }, - "Workspace Settings": { - "Workspace Settings": "Munkaterület-beállítások" - }, - "Workspace Switcher": { - "Workspace Switcher": "Munkaterület-váltó" - }, - "Workspace name": { - "Workspace name": "Munkaterület neve" - }, - "Workspaces": { - "Workspaces": "Munkaterületek" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Munkaterületek és widgetek" - }, - "Write:": { - "Write:": "Írás:" - }, - "X Axis": { - "X Axis": "X tengely" - }, - "Y Axis": { - "Y Axis": "Y tengely" - }, - "Yes": { - "Yes": "Igen" - }, - "Yesterday": { - "Yesterday": "Tegnap" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Nem mentett változtatásaid vannak. Szeretnél menteni a lap bezárása előtt?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Nem mentett változtatásaid vannak. Szeretnél menteni a folytatás előtt?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Nem mentett változtatásaid vannak. Szeretnél menteni az új fájl létrehozása előtt?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Nem mentett változtatásaid vannak. Szeretnél menteni a fájl megnyitása előtt?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Be kell állítanod a\nQT_QPA_PLATFORMTHEME=gtk3\nvagy a\nQT_QPA_PLATFORMTHEME=qt6ct\nkörnyezeti változót, majd indítsd újra a héjat.\n\nA qt6ct-hez telepíteni kell a qt6ct-kde csomagot." - }, - "You're All Set!": { - "You're All Set!": "Minden kész!" - }, - "Your system is up to date!": { - "Your system is up to date!": "A rendszer naprakész!" - }, - "actions": { - "actions": "műveletek" - }, - "attached": { - "attached": "csatolva" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "ettől: %1" - }, - "days": { - "days": "nap" - }, - "detached": { - "detached": "leválasztva" - }, - "device": { - "device": "eszköz" - }, - "devices connected": { - "devices connected": "csatlakoztatott eszköz" - }, - "dgop not available": { - "dgop not available": "A dgop nem elérhető" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "A dms egy nagymértékben testreszabható, modern asztali héj, material 3 ihlette dizájnnal.

        A Quickshell-lel, egy QT6 keretrendszerrel asztali héjak építéséhez, és a Go statikusan típusos, fordított programozási nyelvvel készült." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "A dms/cursor konfiguráció létezik, de nincs befoglalva. A kurzorbeállítások nem lesznek érvényesek." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "A dms/outputs konfiguráció létezik, de nincs benne a kompozitor konfigurációjában. A kijelző változások nem maradnak meg." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "pl.: firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "pl.: focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "pl. notify-send „Hello” && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "pl. scratch, /^tmp_.*/, build" - }, - "events": { - "events": "események" - }, - "ext": { - "ext": "kiterj." - }, - "featured": { - "featured": "kiemelt" - }, - "leave empty for default": { - "leave empty for default": "hagyd üresen az alapértelmezéshez" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl nem elérhető – a zárolás integrációhoz DMS socket kapcsolat szükséges" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord szerver" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen nem található - telepítsd a matugen csomagot a dinamikus témázásért" - }, - "minutes": { - "minutes": "perc" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "navigáció" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix csevegés" - }, - "niri shortcuts config": { - "niri shortcuts config": "niri gyorsbillentyűk beállítása" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "most" - }, - "official": { - "official": "hivatalos" - }, - "on Hyprland": { - "on Hyprland": "Hyprlanden" - }, - "on MangoWC": { - "on MangoWC": "MangoWC-n" - }, - "on Miracle WM": { - "on Miracle WM": "Miracle WM-en" - }, - "on Niri": { - "on Niri": "Nirin" - }, - "on Scroll": { - "on Scroll": "Scrollon" - }, - "on Sway": { - "on Sway": "Sway-en" - }, - "open": { - "open": "megnyitás" - }, - "or run ": { - "or run ": "vagy futtasd ezt: " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "A power-profiles-daemon nem érhető el" - }, - "procs": { - "procs": "folyamat" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri subreddit" - }, - "seconds": { - "seconds": "másodperc" - }, - "source": { - "source": "forrás" - }, - "this app": { - "this app": "ez az alkalmazás" - }, - "up": { - "up": "fel" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "frissítsd a dms-t az NM integrációhoz." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 ettől: %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "A wtype nem elérhető - telepítsd a wtype csomagot a beillesztés támogatásához" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Csak megbízható forrásokból telepíts" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Hónap (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Hónap (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Hónap (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Hónap (Január)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• A bővítmények hibákat vagy biztonsági problémákat tartalmazhatnak" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Lehetőség szerint ellenőrizd a kódot telepítés előtt" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Nap (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Nap (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Nap neve (H)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Nap neve (Hétfő)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Év (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Év (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Nav • Szóköz: Kibontás • Enter: Művelet/Kibontás • E: Szöveg" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: Navigáció • Enter/Ctrl+C: Másolás • Del: Törlés • F10: Súgó" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Navigálás • Enter: Beillesztés • Del: Törlés • F10: Súgó" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/it.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/it.json deleted file mode 100644 index 3f1b91f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/it.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "Velocità Animazione %1" - }, - "%1 Sessions": { - "%1 Sessions": "%1 Sessioni" - }, - "%1 active session": { - "%1 active session": "%1 sessione attiva" - }, - "%1 active sessions": { - "%1 active sessions": "%1 sessioni attive" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 adattatore, nessuno connesso" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 adattatori, nessuno connesso" - }, - "%1 character": { - "%1 character": "%1 carattere" - }, - "%1 characters": { - "%1 characters": "%1 caratteri" - }, - "%1 connected": { - "%1 connected": "%1 connesso" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 durata animazione personalizzata" - }, - "%1 disconnected": { - "%1 disconnected": "%1 disconnesso" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 disconnesso (nascosto)" - }, - "%1 display": { - "%1 display": "%1 schermo" - }, - "%1 displays": { - "%1 displays": "%1 schermi" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 esiste ma non è incluso nella configurazione. Le scorciatoie personalizzate non funzioneranno finché non sarà risolto." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 esiste ma non è incluso. Le regole della finestra non verranno applicate." - }, - "%1 filtered": { - "%1 filtered": "%1 filtrato(i)" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 è ora incluso nella configurazione" - }, - "%1 issue found": { - "%1 issue found": "%1 problema trovato" - }, - "%1 issues found": { - "%1 issues found": "%1 problemi trovati" - }, - "%1 notifications": { - "%1 notifications": "%1 notifiche" - }, - "%1 update": { - "%1 update": "%1 aggiornamento" - }, - "%1 updates": { - "%1 updates": "%1 aggiornamenti" - }, - "%1 variants": { - "%1 variants": "%1 varianti" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 sfondo • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 sfondi • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 widget" - }, - "%1 window": { - "%1 window": "%1 finestra" - }, - "%1 windows": { - "%1 windows": "%1 finestre" - }, - "%1m ago": { - "%1m ago": "%1 min fa" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "\"Alternativa\" permette alla chiave di sbloccare da sola. \"Secondo fattore\" richiede prima la password o l'impronta digitale, poi la chiave." - }, - "(Default)": { - "(Default)": "(Predefinito)" - }, - "(Unnamed)": { - "(Unnamed)": "(Senza nome)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 altre" - }, - "/path/to/videos": { - "/path/to/videos": "/percorso/dei/video" - }, - "0 = square corners": { - "0 = square corners": "0 = angoli squadrati" - }, - "1 day": { - "1 day": "1 giorno" - }, - "1 device connected": { - "1 device connected": "1 dispositivo connesso" - }, - "1 event": { - "1 event": "1 evento" - }, - "1 hour": { - "1 hour": "1 ora" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 ora 30 minuti" - }, - "1 minute": { - "1 minute": "1 minuto" - }, - "1 notification": { - "1 notification": "1 notifica" - }, - "1 second": { - "1 second": "1 secondo" - }, - "10 minutes": { - "10 minutes": "10 minuti" - }, - "10 seconds": { - "10 seconds": "10 secondi" - }, - "10-bit Color": { - "10-bit Color": "Colore a 10 bit" - }, - "12 hours": { - "12 hours": "12 ore" - }, - "14 days": { - "14 days": "14 giorni" - }, - "15 minutes": { - "15 minutes": "15 minuti" - }, - "15 seconds": { - "15 seconds": "15 secondi" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 ore" - }, - "2 minutes": { - "2 minutes": "2 minuti" - }, - "2 seconds": { - "2 seconds": "2 secondi" - }, - "20 minutes": { - "20 minutes": "20 minuti" - }, - "20 seconds": { - "20 seconds": "20 secondi" - }, - "24-Hour Format": { - "24-Hour Format": "Formato 24 Ore" - }, - "24-hour clock": { - "24-hour clock": "Orologio 24 ore" - }, - "24-hour format": { - "24-hour format": "formato 24 ore" - }, - "25 seconds": { - "25 seconds": "25 secondi" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 giorni" - }, - "3 hours": { - "3 hours": "3 ore" - }, - "3 minutes": { - "3 minutes": "3 minuti" - }, - "3 seconds": { - "3 seconds": "3 secondi" - }, - "30 days": { - "30 days": "30 giorni" - }, - "30 minutes": { - "30 minutes": "30 minuti" - }, - "30 seconds": { - "30 seconds": "30 secondi" - }, - "35 seconds": { - "35 seconds": "35 secondi" - }, - "3rd party": { - "3rd party": "terze parti" - }, - "4 hours": { - "4 hours": "4 ore" - }, - "4 seconds": { - "4 seconds": "4 secondi" - }, - "40 seconds": { - "40 seconds": "40 secondi" - }, - "45 seconds": { - "45 seconds": "45 secondi" - }, - "5 minutes": { - "5 minutes": "5 minuti" - }, - "5 seconds": { - "5 seconds": "5 secondi" - }, - "50 seconds": { - "50 seconds": "50 secondi" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 secondi" - }, - "6 hours": { - "6 hours": "6 ore" - }, - "7 days": { - "7 days": "7 giorni" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 ore" - }, - "8 seconds": { - "8 seconds": "8 secondi" - }, - "90 days": { - "90 days": "90 giorni" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "Licenza MIT" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Esiste già un file con questo nome. Vuoi sovrascriverlo?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Una moderna shell desktop per compositor Wayland" - }, - "AC Power": { - "AC Power": "Alimentazione CA" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Interrotto" - }, - "About": { - "About": "Informazioni" - }, - "Accent Color": { - "Accent Color": "Colore di Accento" - }, - "Accept": { - "Accept": "Accetta" - }, - "Accept Jobs": { - "Accept Jobs": "Accetta Stampe" - }, - "Accepting": { - "Accepting": "In Accettazione" - }, - "Access clipboard history": { - "Access clipboard history": "Accesso alla cronologia degli appunti" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Accesso a notifiche e non disturbare" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Accesso ai controlli e alle impostazioni del sistema" - }, - "Action": { - "Action": "Azione" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "Azione non riuscita o il terminale è stato chiuso." - }, - "Actions": { - "Actions": "Azioni" - }, - "Activate": { - "Activate": "Attiva" - }, - "Activate Greeter": { - "Activate Greeter": "Attiva Greeter" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "Attivare il greeter DMS? Si aprirà un terminale per l'autenticazione sudo. Esegui Sincronizza dopo l'attivazione per applicare le tue impostazioni." - }, - "Activation": { - "Activation": "Attivazione" - }, - "Active": { - "Active": "Attivo" - }, - "Active Color": { - "Active Color": "Colore Attivo" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Schermo Attivo per la Schermata di Blocco" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Colore sfondo e icona dei riquadri attivi" - }, - "Active: %1": { - "Active: %1": "Attivo: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Attivo: %1 +%2" - }, - "Active: None": { - "Active: None": "Attivo: Nessuno" - }, - "Adapters": { - "Adapters": "Adattatori" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Aggiungi" - }, - "Add Bar": { - "Add Bar": "Aggiungi Barra" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Aggiungi Widget Desktop" - }, - "Add Printer": { - "Add Printer": "Aggiungi Stampante" - }, - "Add Title": { - "Add Title": "Aggiungi Titolo" - }, - "Add Widget": { - "Add Widget": "Aggiungi Widget" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Aggiungi Widget alla Sezione %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Aggiungi un bordo alla dock" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Aggiungi un prefisso personalizzato all'avvio di tutte le applicazioni. Può essere utilizzato per strumenti come \"uwsm-app\", \"systemd-run\" o altri wrapper di comandi." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Aggiungi e configura widget che compaiono sul tuo desktop" - }, - "Add by Address": { - "Add by Address": "Aggiungi tramite Indirizzo" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Regola il numero di colonne nella modalità di visualizzazione a griglia." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Regola volume per scatto rotellina" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "Regola il contrasto dei colori generati (-100 = minimo, 0 = standard, 100 = massimo)" - }, - "Advanced": { - "Advanced": "Avanzate" - }, - "Afternoon": { - "Afternoon": "Pomeriggio" - }, - "All": { - "All": "Tutto" - }, - "All Monitors": { - "All Monitors": "Tutti gli Schermi" - }, - "All checks passed": { - "All checks passed": "Tutti i controlli superati" - }, - "All day": { - "All day": "Tutto il giorno" - }, - "All displays": { - "All displays": "Tutti gli schermi" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Consenti clic attraverso il widget" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Indietro • F1/I: Info File • F10: Aiuto • Esc: Chiudi" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternativa (O)" - }, - "Always Active": { - "Always Active": "Sempre Attivo" - }, - "Always Show Percentage": { - "Always Show Percentage": "Mostra Sempre Percentuale" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Nascondi sempre la dock e mostrala passando il cursore vicino all’area della dock" - }, - "Always on icons": { - "Always on icons": "Icone sempre attive" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Mostra sempre almeno 3 spazi di lavoro, anche se ne sono disponibili meno" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Mostra sempre la dock quando la vista panoramica di niri è aperta" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Mostra sempre quando è presente un solo schermo connesso" - }, - "Amount": { - "Amount": "Quantità" - }, - "Analog": { - "Analog": "Analogico" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Visualizzazione dell’orologio analogica, digitale o impilata" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Analisi configurazione in corso..." - }, - "Animation Duration": { - "Animation Duration": "Durata Animazione" - }, - "Animation Speed": { - "Animation Speed": "Velocità Animazione" - }, - "Anonymous Identity": { - "Anonymous Identity": "Identità Anonima" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Identità Anonima (facoltativa)" - }, - "App Customizations": { - "App Customizations": "Personalizzazioni App" - }, - "App ID Substitutions": { - "App ID Substitutions": "Sostituzioni App ID" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "Regex ID applicazione (es. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Launcher Applicazioni" - }, - "App Names": { - "App Names": "Nomi App" - }, - "App Theming": { - "App Theming": "Theming Applicazioni" - }, - "Appearance": { - "Appearance": "Aspetto" - }, - "Application Dock": { - "Application Dock": "Dock delle Applicazioni" - }, - "Applications": { - "Applications": "Applicazioni" - }, - "Apply Changes": { - "Apply Changes": "Applica Modifiche" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Applica Colori GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Applica Colori Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Applica una temperatura colore più calda per ridurre l'affaticamento visivo. Usa le impostazioni di automazione qui sotto per controllare quando attivarla." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "Applicazione delle modifiche di autenticazione in corso…" - }, - "Apps": { - "Apps": "App" - }, - "Apps Dock": { - "Apps Dock": "Dock delle App" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Impostazioni Dock App" - }, - "Apps Icon": { - "Apps Icon": "Icona App" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Le applicazioni sono ordinate per frequenza d'uso, poi per ultimo utilizzo, e infine in ordine alfabetico." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "App con nome visualizzato, icona o opzioni di avvio personalizzati. Fai clic con il tasto destro su un'app e seleziona \"Modifica App\" per personalizzare." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "App con popup di notifica silenziati. Riattiva o elimina per rimuovere." - }, - "Architecture": { - "Architecture": "Architettura" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Sei sicuro di voler terminare la sessione \"%1\"?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Disponi gli schermi e configura risoluzione, frequenza di aggiornamento e VRR" - }, - "Attach": { - "Attach": "Aggancia" - }, - "Audio": { - "Audio": "Audio" - }, - "Audio Codec": { - "Audio Codec": "Codec Audio" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Selezione Codec Audio" - }, - "Audio Devices": { - "Audio Devices": "Dispositivi Audio" - }, - "Audio Input": { - "Audio Input": "Input Audio" - }, - "Audio Output": { - "Audio Output": "Output Audio" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Dispositivi di Uscita Audio (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Cambio Uscita Audio" - }, - "Audio Visualizer": { - "Audio Visualizer": "Visualizzatore Audio" - }, - "Audio system restarted": { - "Audio system restarted": "Sistema audio riavviato" - }, - "Audio volume control": { - "Audio volume control": "Controllo volume audio" - }, - "Auth": { - "Auth": "Autenticazione" - }, - "Auth Type": { - "Auth Type": "Tipo di Autenticazione" - }, - "Authenticate": { - "Authenticate": "Autenticati" - }, - "Authenticating...": { - "Authenticating...": "Autenticazione in corso..." - }, - "Authentication": { - "Authentication": "Autenticazione" - }, - "Authentication Required": { - "Authentication Required": "Autenticazione Richiesta" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "Modifiche di autenticazione applicate." - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "Le modifiche di autenticazione vengono applicate automaticamente." - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "Le modifiche di autenticazione vengono applicate automaticamente. L'accesso solo con impronta digitale potrebbe non sbloccare il Portachiavi." - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "Le modifiche di autenticazione richiedono sudo. Apertura del terminale per consentirti l'uso della password o dell'impronta digitale." - }, - "Authentication error - try again": { - "Authentication error - try again": "Errore di autenticazione - riprova" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Impossibile autenticarsi, per favore riprova" - }, - "Authorize": { - "Authorize": "Autorizza" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autorizza associazione con " - }, - "Authorize service for ": { - "Authorize service for ": "Autorizza servizio per " - }, - "Auto": { - "Auto": "Automatico" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "Auto (In base alla barra)" - }, - "Auto (Wide)": { - "Auto (Wide)": "Automatico (Ampio)" - }, - "Auto Location": { - "Auto Location": "Posizione Automatica" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Spaziature Popup Automatiche" - }, - "Auto-Clear After": { - "Auto-Clear After": "Cancellazione Automatica Dopo" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Ritardo Auto-Nascondimento" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Chiudi automaticamente la panoramica di Niri all'avvio delle app." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Elimina automaticamente le notifiche più vecchie di questo periodo" - }, - "Auto-hide": { - "Auto-hide": "Nascondi Automaticamente" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Nascondi Automaticamente la Dock" - }, - "Auto-saving...": { - "Auto-saving...": "Salvataggio in corso..." - }, - "Autoconnect": { - "Autoconnect": "Connessione Automatica" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Connessione automatica disabilitata" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Connessione automatica abilitata" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "Compila automaticamente con l'ultima ricerca ricordata all'apertura" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Modalità Colore Automatica" - }, - "Automatic Control": { - "Automatic Control": "Controllo Automatico" - }, - "Automatic Cycling": { - "Automatic Cycling": "Rotazione Automatica" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Alterna automaticamente gli sfondi nella stessa cartella" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Elimina automaticamente le voci più vecchie di questo periodo" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Rileva automaticamente la posizione in base all'indirizzo IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Determina automaticamente la tua posizione usando l'indirizzo IP" - }, - "Automatically lock after": { - "Automatically lock after": "Blocca automaticamente dopo" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Blocca automaticamente lo schermo all'avvio della DMS" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Blocca automaticamente lo schermo quando il sistema si prepara alla sospensione" - }, - "Automation": { - "Automation": "Automazione" - }, - "Available": { - "Available": "Disponibile" - }, - "Available Layouts": { - "Available Layouts": "Layout Disponibili" - }, - "Available Networks": { - "Available Networks": "Reti Disponibili" - }, - "Available Plugins": { - "Available Plugins": "Plugin Disponibili" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Schermi Disponibili (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Disponibile nelle modalità Dettagliata e Previsioni" - }, - "Available.": { - "Available.": "Disponibile." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Indietro" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "Sfondo" - }, - "Background Blur": { - "Background Blur": "Sfocatura Sfondo" - }, - "Background Opacity": { - "Background Opacity": "Opacità dello Sfondo" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "Sincronizzazione dell'autenticazione in background non riuscita. Tentativo con la modalità terminale in corso" - }, - "Background image": { - "Background image": "Immagine di sfondo" - }, - "Backlight device": { - "Backlight device": "Dispositivo di retroilluminazione" - }, - "Balance power and performance": { - "Balance power and performance": "Bilancia risparmio energetico e prestazioni" - }, - "Balanced": { - "Balanced": "Bilanciato" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Tavolozza bilanciata con accenti focalizzati (predefinito)." - }, - "Bar Configurations": { - "Bar Configurations": "Configurazioni Barra" - }, - "Bar Shadows": { - "Bar Shadows": "Ombre della Barra" - }, - "Bar Transparency": { - "Bar Transparency": "Trasparenza Barra" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Colore base per le ombre (l'opacità è applicata automaticamente)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Durata base delle animazioni (trascina per usare Personalizzato)" - }, - "Battery": { - "Battery": "Batteria" - }, - "Battery %1": { - "Battery %1": "Batteria %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Limite Carica Batteria" - }, - "Battery and power management": { - "Battery and power management": "Gestione batteria e alimentazione" - }, - "Battery level and power management": { - "Battery level and power management": "Livello batteria e gestione energetica" - }, - "Behavior": { - "Behavior": "Comportamento" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Associa la schermata di blocco ai segnali dbus di loginctl. Disabilita se utilizzi una schermata di blocco esterna" - }, - "Binds Include Missing": { - "Binds Include Missing": "Inclusione Scorciatoie Mancante" - }, - "Binds include added": { - "Binds include added": "Inclusione scorciatoie aggiunta" - }, - "Bit Depth": { - "Bit Depth": "Profondità di Bit" - }, - "Block Out": { - "Block Out": "Escludi" - }, - "Block Out From": { - "Block Out From": "Escludi Da" - }, - "Block notifications": { - "Block notifications": "Blocca notifiche" - }, - "Blocked": { - "Blocked": "Bloccato" - }, - "Blue light filter": { - "Blue light filter": "Filtro luce blu" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Impostazioni Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth non disponibile" - }, - "Blur Border Color": { - "Blur Border Color": "Colore Bordo Sfocato" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "Opacità Bordo Sfocato" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Sfoca il Livello dello Sfondo" - }, - "Blur on Overview": { - "Blur on Overview": "Sfocatura su Panoramica" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "Sfoca lo sfondo dietro barre, popup, modali e notifiche. Richiede supporto e configurazione del compositore." - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Sfoca lo sfondo quando la panoramica di niri è aperta" - }, - "Body": { - "Body": "Corpo" - }, - "Border": { - "Border": "Bordo" - }, - "Border Color": { - "Border Color": "Colore Bordo" - }, - "Border Opacity": { - "Border Opacity": "Opacità Bordo" - }, - "Border Size": { - "Border Size": "Spessore Bordo" - }, - "Border Thickness": { - "Border Thickness": "Spessore Bordo" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "Colore del bordo attorno alle superfici sfocate" - }, - "Border with BG": { - "Border with BG": "Bordo con Sfondo" - }, - "Bottom": { - "Bottom": "In Basso" - }, - "Bottom Center": { - "Bottom Center": "In Basso al Centro" - }, - "Bottom Left": { - "Bottom Left": "In Basso a Sinistra" - }, - "Bottom Right": { - "Bottom Right": "In Basso a Destra" - }, - "Bottom Section": { - "Bottom Section": "Sezione Inferiore" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Dock inferiore per applicazioni fissate e in esecuzione" - }, - "Brightness": { - "Brightness": "Luminosità" - }, - "Brightness Slider": { - "Brightness Slider": "Slider Luminosità" - }, - "Brightness Value": { - "Brightness Value": "Valore di Luminosità" - }, - "Brightness control not available": { - "Brightness control not available": "Controllo luminosità non disponibile" - }, - "Browse": { - "Browse": "Sfoglia" - }, - "Browse Files": { - "Browse Files": "Sfoglia File" - }, - "Browse Plugins": { - "Browse Plugins": "Sfoglia Plugin" - }, - "Browse Themes": { - "Browse Themes": "Sfoglia Temi" - }, - "Browse or search plugins": { - "Browse or search plugins": "Sfoglia o cerca plugin" - }, - "Button Color": { - "Button Color": "Colore Pulsante" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "Grafico della CPU" - }, - "CPU Temperature": { - "CPU Temperature": "Temperatura CPU" - }, - "CPU Usage": { - "CPU Usage": "Utilizzo CPU" - }, - "CPU temperature display": { - "CPU temperature display": "Mostra temperatura CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "Indicatore utilizzo CPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Monitoraggio CPU, memoria, rete e disco" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "Avviso Filtro non Sicuro CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "Avviso Filtro Mancante CUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "Server di Stampa CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS non disponibile" - }, - "Camera": { - "Camera": "Fotocamera" - }, - "Cancel": { - "Cancel": "Annulla" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Annullare tutte le stampe per \"%1\"?" - }, - "Canceled": { - "Canceled": "Annullato" - }, - "Cannot pair": { - "Cannot pair": "Impossibile associare" - }, - "Capabilities": { - "Capabilities": "Capacità" - }, - "Capacity": { - "Capacity": "Capacità" - }, - "Caps Lock": { - "Caps Lock": "Blocco Maiuscole" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indicatore Blocco Maiuscole" - }, - "Caps Lock is on": { - "Caps Lock is on": "Blocco Maiuscole è attivo" - }, - "Center Section": { - "Center Section": "Sezione Centrale" - }, - "Center Single Column": { - "Center Single Column": "Colonna Singola Centrale" - }, - "Center Tiling": { - "Center Tiling": "Tiling Centrale" - }, - "Certificate Password": { - "Certificate Password": "Password del Certificato" - }, - "Change Song": { - "Change Song": "Cambia Brano" - }, - "Change Volume": { - "Change Volume": "Cambia Volume" - }, - "Change bar appearance": { - "Change bar appearance": "Cambia aspetto barra" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "Cambia la lingua utilizzata dall'interfaccia DMS." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Cambia la lingua per la formattazione di data e ora, indipendentemente dalla lingua dell'interfaccia." - }, - "Channel": { - "Channel": "Canale" - }, - "Charging": { - "Charging": "In Carica" - }, - "Check for system updates": { - "Check for system updates": "Controlla aggiornamenti di sistema" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "Controlla lo stato della sincronizzazione su richiesta. Sincronizza copia il tema, le impostazioni e la configurazione dello sfondo nella schermata di accesso. Le modifiche di autenticazione vengono applicate automaticamente." - }, - "Checking for updates...": { - "Checking for updates...": "Controllo aggiornamenti..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Verifica della necessità di autenticazione sudo…" - }, - "Checking...": { - "Checking...": "Verifica in corso..." - }, - "Checking…": { - "Checking…": "Controllo in corso…" - }, - "Choose Color": { - "Choose Color": "Scegli Colore" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Scegli Colore Modalità Scura" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Scegli il Colore del Logo del Dock Launcher" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Scegli il Colore del Logo del Launcher" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Scegli Colore Modalità Chiara" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Scegli Colore Sfondo" - }, - "Choose a color": { - "Choose a color": "Scegli un colore" - }, - "Choose colors from palette": { - "Choose colors from palette": "Scegli i colori dalla tavolozza" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Scegli come visualizzare il widget meteo" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Scegli come questa barra determina la direzione delle ombre" - }, - "Choose icon": { - "Choose icon": "Scegli icona" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Scegli il colore di sfondo per i widget" - }, - "Choose the border accent color": { - "Choose the border accent color": "Scegli il colore di accento del bordo" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Scegli il logo visualizzato sul pulsante del launcher nella DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Scegli dove i popup delle notifiche appaiono sullo schermo" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Scegli dove i messaggi appaiono sullo schermo" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Scegli su quali schermi mostrare questo widget" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Scegli quale schermo mostra l'interfaccia della schermata di blocco. Gli altri schermi visualizzeranno un colore solido per proteggere gli schermi OLED dal burn-in." - }, - "Chroma Style": { - "Chroma Style": "Stile Chroma" - }, - "Cipher": { - "Cipher": "Cifratura" - }, - "Circle": { - "Circle": "Cerchio" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Regex classe (es. ^firefox$)" - }, - "Clear": { - "Clear": "Cancella" - }, - "Clear All": { - "Clear All": "Cancella Tutto" - }, - "Clear All Jobs": { - "Clear All Jobs": "Elimina Tutte le Stampe" - }, - "Clear History?": { - "Clear History?": "Cancellare la Cronologia?" - }, - "Clear Sky": { - "Clear Sky": "Sereno" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Cancella tutta la cronologia all'avvio del server" - }, - "Clear at Startup": { - "Clear at Startup": "Cancella all'Avvio" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Fai clic su \"Configura\" per creare %1 e aggiungere l'inclusione alla configurazione." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Fai clic su \"Configura\" per creare %1 e aggiungere l'inclusione al file di configurazione del compositor." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Fai clic su \"Configura\" per creare la configurazione del cursore e aggiungere l'inclusione al tuo file di configurazione del compositor." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Fai clic su \"Configura\" per creare la configurazione degli output e aggiungere l'istruzione include alla configurazione del compositor." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Fai clic su Importa per aggiungere un file .ovpn o .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Fai clic su Aggiorna per controllare lo stato." - }, - "Click Through": { - "Click Through": "Ignora Clic Mouse" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Fai clic su qualsiasi scorciatoia per modificare. Le modifiche vengono salvate in %1" - }, - "Click to capture": { - "Click to capture": "Fai clic per acquisire" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Fai clic per selezionare un file tema JSON personalizzato" - }, - "Clip": { - "Clip": "Ritaglia" - }, - "Clip to Geometry": { - "Clip to Geometry": "Ritaglia alla Geometria" - }, - "Clipboard": { - "Clipboard": "Appunti" - }, - "Clipboard History": { - "Clipboard History": "Cronologia Appunti" - }, - "Clipboard Manager": { - "Clipboard Manager": "Gestore Appunti" - }, - "Clipboard sent": { - "Clipboard sent": "Appunti inviati" - }, - "Clipboard service not available": { - "Clipboard service not available": "Servizio degli appunti non disponibile" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Gli appunti funzionano ma nulla viene salvato su disco" - }, - "Clock": { - "Clock": "Orologio" - }, - "Clock Style": { - "Clock Style": "Stile dell'Orologio" - }, - "Close": { - "Close": "Chiudi" - }, - "Close All Windows": { - "Close All Windows": "Chiudi Tutte le Finestre" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Chiudi Panoramica all'Avvio" - }, - "Close Window": { - "Close Window": "Chiudi Finestra" - }, - "Color": { - "Color": "Colore" - }, - "Color Gamut": { - "Color Gamut": "Gamma Cromatica" - }, - "Color Management": { - "Color Management": "Gestione del Colore" - }, - "Color Mode": { - "Color Mode": "Modalità Colore" - }, - "Color Override": { - "Color Override": "Forzatura Colore" - }, - "Color Picker": { - "Color Picker": "Selettore Colore" - }, - "Color Temperature": { - "Color Temperature": "Temperatura Colore" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Colore visualizzato sui monitor senza la schermata di blocco" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Colore per i pulsanti di azione principali" - }, - "Color temperature for day time": { - "Color temperature for day time": "Temperatura colore per il giorno" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Temperatura colore per la modalità notturna" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Tema colori per l'evidenziazione della sintassi." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Tema colori per l'evidenziazione della sintassi. %1 temi disponibili." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Tema colore dal registro DMS" - }, - "Colorful": { - "Colorful": "Colorato" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Mix colorato di accenti contrastanti brillanti." - }, - "Colorize Active": { - "Colorize Active": "Colora Attivo" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Colori dallo sfondo" - }, - "Column": { - "Column": "Colonna" - }, - "Column Display": { - "Column Display": "Visualizzazione a Colonna" - }, - "Column Width": { - "Column Width": "Larghezza Colonna" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "Elenco separato da virgole dei nomi di sessione da nascondere. Racchiudi tra barre per usare regex (es. /^_.*/)." - }, - "Command": { - "Command": "Comando" - }, - "Commands": { - "Commands": "Comandi" - }, - "Communication": { - "Communication": "Comunicazione" - }, - "Community themes": { - "Community themes": "Temi della community" - }, - "Compact": { - "Compact": "Compatto" - }, - "Compact Mode": { - "Compact Mode": "Modalità Compatta" - }, - "Completed": { - "Completed": "Completato" - }, - "Compositor": { - "Compositor": "Compositor" - }, - "Compositor Settings": { - "Compositor Settings": "Impostazioni del Compositor" - }, - "Compositor not supported": { - "Compositor not supported": "Compositor non supportato" - }, - "Config Format": { - "Config Format": "Formato di Configurazione" - }, - "Config action: %1": { - "Config action: %1": "Azione di configurazione: %1" - }, - "Config validation failed": { - "Config validation failed": "Impossibile convalidare la configurazione" - }, - "Configuration": { - "Configuration": "Configurazione" - }, - "Configuration activated": { - "Configuration activated": "Configurazione attivata" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "La configurazione verrà preservata quando questo schermo si riconnette" - }, - "Configure": { - "Configure": "Configura" - }, - "Configure Keybinds": { - "Configure Keybinds": "Configura Scorciatoie" - }, - "Configure a new printer": { - "Configure a new printer": "Configura una nuova stampante" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Configura le icone per gli spazi di lavoro con nome. Le icone hanno la priorità sui numeri quando sono entrambi abilitati." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Configura criteri di corrispondenza e azioni" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Configura quali schermi mostrano \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Configura quali schermi mostrano i componenti della shell" - }, - "Confirm": { - "Confirm": "Conferma" - }, - "Confirm Delete": { - "Confirm Delete": "Conferma" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Conferma Modifiche Schermo" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Conferma passkey per " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "In conflitto con: %1" - }, - "Connect": { - "Connect": "Connetti" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Connetti a Rete Nascosta" - }, - "Connect to VPN": { - "Connect to VPN": "Connetti alla VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Connetti a Wi-Fi" - }, - "Connected": { - "Connected": "Connesso" - }, - "Connected Device": { - "Connected Device": "Dispositivo Connesso" - }, - "Connected Displays": { - "Connected Displays": "Schermi Connessi" - }, - "Connecting to Device": { - "Connecting to Device": "Connessione al Dispositivo" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Connessione in corso..." - }, - "Connection failed": { - "Connection failed": "Connessione non riuscita" - }, - "Contains": { - "Contains": "Contiene" - }, - "Content": { - "Content": "Contenuto" - }, - "Content copied": { - "Content copied": "Contenuto copiato" - }, - "Contrast": { - "Contrast": "Contrasto" - }, - "Control Center": { - "Control Center": "Centro di Controllo" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Colore Riquadri Centro di Controllo" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Controlla la durata dell'animazione per i popup di notifica e la cronologia" - }, - "Control currently playing media": { - "Control currently playing media": "Controlla media in riproduzione" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Scegli quali informazioni delle notifiche vengono mostrate sulla schermata di blocco" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Controlla quali plugin appaiono nella modalità \"Tutti\" senza richiedere un prefisso di attivazione. Trascina per riordinare." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Controlla spazi di lavoro e colonne scorrendo sulla barra" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Controlla l'opacità di tutti i popup, le finestre modali e i loro livelli di contenuto" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "Controlla la direzione della proiezione dell'ombra per i livelli in rilievo" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "Controlla il raggio di sfocatura base e l'offset delle ombre" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Controlla la trasparenza dell'ombra" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Opzioni di comodità per la schermata di accesso. Sincronizza per applicare." - }, - "Cooldown": { - "Cooldown": "Tempo di Attesa" - }, - "Copied GIF": { - "Copied GIF": "GIF Copiata" - }, - "Copied MP4": { - "Copied MP4": "MP4 Copiato" - }, - "Copied WebP": { - "Copied WebP": "WebP Copiato" - }, - "Copied to clipboard": { - "Copied to clipboard": "Copiato negli appunti" - }, - "Copied!": { - "Copied!": "Copiato!" - }, - "Copy": { - "Copy": "Copia" - }, - "Copy Content": { - "Copy Content": "Copia Contenuto" - }, - "Copy Full Command": { - "Copy Full Command": "Copia Comando Completo" - }, - "Copy HTML": { - "Copy HTML": "Copia HTML" - }, - "Copy Name": { - "Copy Name": "Copia Nome" - }, - "Copy PID": { - "Copy PID": "Copia PID" - }, - "Copy Text": { - "Copy Text": "Copia Testo" - }, - "Copy path": { - "Copy path": "Copia percorso" - }, - "Corner Radius": { - "Corner Radius": "Raggio degli Angoli" - }, - "Corner Radius Override": { - "Corner Radius Override": "Forzatura Raggio Angoli" - }, - "Corners & Background": { - "Corners & Background": "Angoli e Sfondo" - }, - "Count Only": { - "Count Only": "Solo Conteggio" - }, - "Cover Open": { - "Cover Open": "Coperchio Aperto" - }, - "Create": { - "Create": "Crea" - }, - "Create Dir": { - "Create Dir": "Crea Cartella" - }, - "Create Printer": { - "Create Printer": "Crea Stampante" - }, - "Create Window Rule": { - "Create Window Rule": "Crea Regola Finestra" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Crea una nuova sessione %1 (n)" - }, - "Create rule for:": { - "Create rule for:": "Crea regola per:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Crea regole per silenziare, ignorare, nascondere dalla cronologia o sovrascrivere la priorità delle notifiche. L'impostazione predefinita sovrascrive solo la priorità; le notifiche appaiono comunque normalmente." - }, - "Creating...": { - "Creating...": "Creazione in Corso..." - }, - "Critical Priority": { - "Critical Priority": "Priorità Critica" - }, - "Current": { - "Current": "Attuali" - }, - "Current Items": { - "Current Items": "Elementi Correnti" - }, - "Current Locale": { - "Current Locale": "Lingua Corrente" - }, - "Current Monitor": { - "Current Monitor": "Schermo Attuale" - }, - "Current Period": { - "Current Period": "Periodo Corrente" - }, - "Current Status": { - "Current Status": "Stato Attuale" - }, - "Current Temp": { - "Current Temp": "Temperatura Attuale" - }, - "Current Theme: %1": { - "Current Theme: %1": "Tema corrente: %1" - }, - "Current Weather": { - "Current Weather": "Meteo Attuale" - }, - "Current Workspace": { - "Current Workspace": "Spazio di Lavoro Attuale" - }, - "Current time and date display": { - "Current time and date display": "Visualizzazione data e ora correnti" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Temperatura e condizioni meteo attuali" - }, - "Current: %1": { - "Current: %1": "Attuale: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Configurazione Cursore Non Impostata" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Inclusione Cursore Mancante" - }, - "Cursor Size": { - "Cursor Size": "Dimensione Cursore" - }, - "Cursor Theme": { - "Cursor Theme": "Tema Cursore" - }, - "Custom": { - "Custom": "Personalizzata" - }, - "Custom Color": { - "Custom Color": "Colore Personalizzato" - }, - "Custom Duration": { - "Custom Duration": "Durata Personalizzata" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Comando Personalizzato per Ibernazione" - }, - "Custom Location": { - "Custom Location": "Posizione Personalizzata" - }, - "Custom Lock Command": { - "Custom Lock Command": "Comando Personalizzato per il Blocco" - }, - "Custom Logout Command": { - "Custom Logout Command": "Comando Personalizzato per il Termina Sessione" - }, - "Custom Name": { - "Custom Name": "Nome Personalizzato" - }, - "Custom Power Actions": { - "Custom Power Actions": "Azioni Alimentazione Personalizzate" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Comando Personalizzato per lo Spegnimento" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Comando Personalizzato per il Riavvio" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Colore Ombra Personalizzato" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Sovrascrittura Ombra Personalizzata" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Comando Personalizzato per la Sospensione" - }, - "Custom Transparency": { - "Custom Transparency": "Trasparenza Personalizzata" - }, - "Custom power profile": { - "Custom power profile": "Profilo energetico personalizzato" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Tema personalizzato caricato da file JSON" - }, - "Custom...": { - "Custom...": "Personalizzato..." - }, - "Custom: ": { - "Custom: ": "Personalizzato: " - }, - "Customizable empty space": { - "Customizable empty space": "Spazio vuoto personalizzabile" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Personalizza quali azioni visualizzare nel menu alimentazione" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "Monitor DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "MODALITÀ DEMO - Fai clic ovunque per uscire" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Gestore Plugin DMS non Disponibile" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Scorciatoie DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "Il greeter DMS richiede: greetd, dms-greeter. Impronte digitali: fprintd, pam_fprintd. Chiavi di sicurezza: pam_u2f. Aggiungi il tuo utente al gruppo greeter. Le modifiche di autenticazione vengono applicate automaticamente e potrebbero aprire un terminale quando è richiesta l'autenticazione sudo." - }, - "DMS out of date": { - "DMS out of date": "DMS obsoleta" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Il servizio DMS non è connesso. Le impostazioni degli appunti non sono disponibili." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Azioni della shell DMS (launcher, appunti, ecc.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET non disponibile" - }, - "DWL service not available": { - "DWL service not available": "Servizio DWL non disponibile" - }, - "Daily": { - "Daily": "Giornaliero" - }, - "Daily at:": { - "Daily at:": "Ogni giorno alle:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell è pronta per l'uso" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell e Icone di Sistema (richiede riavvio)" - }, - "Dark Mode": { - "Dark Mode": "Modalità Scura" - }, - "Dark mode base": { - "Dark mode base": "Base modalità scura" - }, - "Dark mode harmony": { - "Dark mode harmony": "Armonia modalità scura" - }, - "Darken Modal Background": { - "Darken Modal Background": "Scurisci Sfondo Modale" - }, - "Date Format": { - "Date Format": "Formato Data" - }, - "Date format": { - "Date format": "Formato data" - }, - "Date format on greeter": { - "Date format on greeter": "Formato data sul greeter" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Aurora (Crepuscolo Astronomico)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Aurora (Crepuscolo Civile)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Aurora (Crepuscolo Nautico)" - }, - "Day Date": { - "Day Date": "Giorno e Data" - }, - "Day Month Date": { - "Day Month Date": "Giorno, Mese e Data" - }, - "Day Temperature": { - "Day Temperature": "Temperatura Diurna" - }, - "Daytime": { - "Daytime": "Giorno" - }, - "Deck": { - "Deck": "Pila" - }, - "Default": { - "Default": "Predefinito" - }, - "Default (Black)": { - "Default (Black)": "Predefinito (Nero)" - }, - "Default Width (%)": { - "Default Width (%)": "Larghezza Predefinita (%)" - }, - "Default selected action": { - "Default selected action": "Azione selezionata predefinita" - }, - "Defaults": { - "Defaults": "Predefiniti" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Definisci regole per il comportamento delle finestre. Salva in %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Canc: Cancella • Shift+Canc: Cancella Tutto • 1-9: Azioni • F10: Aiuto • Esc: Chiudi" - }, - "Delete": { - "Delete": "Elimina" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Eliminare \"%1\"?" - }, - "Delete Class": { - "Delete Class": "Elimina Classe" - }, - "Delete Printer": { - "Delete Printer": "Elimina Stampante" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Eliminare l'Elemento Salvato?" - }, - "Delete VPN": { - "Delete VPN": "Elimina VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Eliminare la classe \"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Eliminare il profilo \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Dipendenze e documentazione" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Deriva colori che si avvicinano all'immagine sottostante." - }, - "Description": { - "Description": "Descrizione" - }, - "Desktop": { - "Desktop": "Scrivania" - }, - "Desktop Clock": { - "Desktop Clock": "Orologio Desktop" - }, - "Desktop Entry": { - "Desktop Entry": "Voce Desktop" - }, - "Desktop Widget": { - "Desktop Widget": "Widget Desktop" - }, - "Desktop Widgets": { - "Desktop Widgets": "Widget su Desktop" - }, - "Desktop background images": { - "Desktop background images": "Immagini sfondo desktop" - }, - "Detailed": { - "Detailed": "Dettagliata" - }, - "Details for \"%1": { - "Details for \"%1\"": "Dettagli per \"%1\"" - }, - "Development": { - "Development": "Sviluppo" - }, - "Device": { - "Device": "Dispositivo" - }, - "Device connections": { - "Device connections": "Connessioni del dispositivo" - }, - "Device names updated": { - "Device names updated": "Nomi dei dispositivi aggiornati" - }, - "Device paired": { - "Device paired": "Dispositivo associato" - }, - "Device unpaired": { - "Device unpaired": "Dispositivo dissociato" - }, - "Digital": { - "Digital": "Digitale" - }, - "Direction Source": { - "Direction Source": "Origine della Direzione" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Disattiva Autoconn." - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Disabilita Sfondi Incorporati" - }, - "Disable History Persistence": { - "Disable History Persistence": "Disabilita Persistenza Cronologia" - }, - "Disable Output": { - "Disable Output": "Disabilita Output" - }, - "Disabled": { - "Disabled": "Disattivato" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Disattivazione Wi-Fi..." - }, - "Disc": { - "Disc": "Disco" - }, - "Discard": { - "Discard": "Scarta" - }, - "Discharging": { - "Discharging": "In Scarica" - }, - "Disconnect": { - "Disconnect": "Disconnetti" - }, - "Disconnected": { - "Disconnected": "Disconnesso" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Disconnesso dal Wi-Fi" - }, - "Discover Devices": { - "Discover Devices": "Scopri Dispositivi" - }, - "Disk": { - "Disk": "Disco" - }, - "Disk I/O": { - "Disk I/O": "I/O del Disco" - }, - "Disk Usage": { - "Disk Usage": "Utilizzo Disco" - }, - "Disk Usage Display": { - "Disk Usage Display": "Visualizzazione Utilizzo Disco" - }, - "Disks": { - "Disks": "Dischi" - }, - "Dismiss": { - "Dismiss": "Ignora" - }, - "Display": { - "Display": "Schermo" - }, - "Display Assignment": { - "Display Assignment": "Assegnazione Schermo" - }, - "Display Control": { - "Display Control": "Controllo Schermo" - }, - "Display Name Format": { - "Display Name Format": "Formato del Nome Visualizzato" - }, - "Display Profiles": { - "Display Profiles": "Profili Schermo" - }, - "Display Settings": { - "Display Settings": "Impostazioni Schermo" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Mostra una dock con applicazioni fissate e in esecuzione" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Mostra priorità sopra app a schermo intero" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Visualizza e cambia i layout DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Mostra icone applicazioni negli indicatori degli spazi di lavoro" - }, - "Display brightness control": { - "Display brightness control": "Controllo luminosità dello schermo" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "La configurazione dello schermo non è disponibile. Il protocollo WLR Output Management non è supportato." - }, - "Display currently focused application title": { - "Display currently focused application title": "Mostra il titolo dell'applicazione attualmente attiva" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Mostra previsioni meteo orarie" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Mostra solo gli spazi di lavoro con finestre" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Visualizza le azioni di alimentazione in una griglia invece che in una lista" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Mostra i secondi nell'orologio" - }, - "Display the power system menu": { - "Display the power system menu": "Mostra il menu di alimentazione del sistema" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Mostra le percentuali di volume e luminosità nei popup a schermo" - }, - "Displays": { - "Displays": "Schermi" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Conteggio schermi quando l'overflow è attivo" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Mostra il layout tastiera attivo e ne permette il cambio" - }, - "Distribution": { - "Distribution": "Distribuzione" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Tavolozza diversificata che copre l'intero spettro." - }, - "Do Not Disturb": { - "Do Not Disturb": "Non Disturbare" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock e Launcher" - }, - "Dock Transparency": { - "Dock Transparency": "Trasparenza Dock" - }, - "Dock Visibility": { - "Dock Visibility": "Visibilità Dock" - }, - "Docs": { - "Docs": "Documentazione" - }, - "Documents": { - "Documents": "Documenti" - }, - "Domain (optional)": { - "Domain (optional)": "Dominio (opzionale)" - }, - "Don't Change": { - "Don't Change": "Non Modificare" - }, - "Don't Save": { - "Don't Save": "Non Salvare" - }, - "Door Open": { - "Door Open": "Sportello Aperto" - }, - "Downloads": { - "Downloads": "Scaricati" - }, - "Drag to Reorder": { - "Drag to Reorder": "Trascina per Riordinare" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Trascina i widget per riordinarli nelle sezioni. Usa l'icona dell'occhio per nascondere/mostrare i widget (mantenendo la spaziatura), o X per rimuoverli completamente." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Trascina gli indicatori degli spazi di lavoro per riordinarli" - }, - "Driver": { - "Driver": "Driver" - }, - "Drizzle": { - "Drizzle": "Pioviggine" - }, - "Duplicate": { - "Duplicate": "Duplica" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Duplica Sfondo con Sfocatura" - }, - "Duration": { - "Duration": "Durata" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Crepuscolo (Crepuscolo Astronomico)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Crepuscolo (Crepuscolo Civile)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Crepuscolo (Crepuscolo Nautico)" - }, - "Dynamic": { - "Dynamic": "Dinamico" - }, - "Dynamic Properties": { - "Dynamic Properties": "Proprietà Dinamiche" - }, - "Dynamic Theming": { - "Dynamic Theming": "Theming Dinamico" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Colori dinamici dallo sfondo" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Colori dinamici, preimpostazioni" - }, - "Edge Spacing": { - "Edge Spacing": "Spaziatura del Bordo" - }, - "Edit App": { - "Edit App": "Modifica App" - }, - "Edit Window Rule": { - "Edit Window Rule": "Modifica Regola Finestra" - }, - "Education": { - "Education": "Istruzione" - }, - "Empty": { - "Empty": "Vuoto" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Abilita profondità colore a 10 bit per una gamma cromatica più ampia e supporto HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Attiva Autoconn." - }, - "Enable Bar": { - "Enable Bar": "Abilita Barra" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Abilita Non Disturbare" - }, - "Enable History": { - "Enable History": "Abilita Cronologia" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Abilita Sovrapposizione Panoramica" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Abilita Effetti Onda" - }, - "Enable System Sounds": { - "Enable System Sounds": "Abilita Suoni di Sistema" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Abilita Salvaschermo Video" - }, - "Enable Weather": { - "Enable Weather": "Abilita Meteo" - }, - "Enable WiFi": { - "Enable WiFi": "Abilita WiFi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "Abilita una sovrascrittura personalizzata qui sotto per impostare intensità, opacità e colore dell'ombra per ogni barra." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Abilita il livello di sfocatura gestibile dal compositor (namespace: dms:blurwallpaper). Richiede la configurazione manuale di niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Abilita impronta digitale all'accesso" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Abilita autenticazione tramite impronta digitale" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "Abilita impronta digitale o chiave di sicurezza per il Greeter DMS. Le modifiche di autenticazione vengono applicate automaticamente." - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Abilita l'integrazione di blocco loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "Abilita chiave di sicurezza all'accesso" - }, - "Enable security key authentication": { - "Enable security key authentication": "Abilita l'autenticazione con chiave di sicurezza" - }, - "Enabled": { - "Enabled": "Attivato" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Attivato, ma impossibile confermare la disponibilità dell'impronta digitale." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Attivato, ma non è stato rilevato nessun lettore di impronte digitali." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "Attivato, ma nessuna impronta è ancora registrata. Le modifiche di autenticazione verranno applicate automaticamente una volta registrate le impronte digitali." - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Attivato, ma nessuna impronta è ancora registrata. Registra le impronte ed esegui Sincronizza." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "Attivato, ma nessuna chiave di sicurezza registrata trovata finora. Le modifiche di autenticazione verranno applicate automaticamente una volta registrata la chiave o aggiornata la configurazione U2F." - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "Attivato, ma nessuna chiave di sicurezza registrata trovata. Registra una chiave ed esegui Sincronizza." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Attivato, ma la disponibilità della chiave di sicurezza non ha potuto essere confermata." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Attivato. PAM fornisce già l'autenticazione tramite impronta digitale." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Attivato. PAM fornisce già l'autenticazione tramite chiave di sicurezza." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Attivato. PAM fornisce l'autenticazione tramite impronta digitale, ma nessuna impronta è ancora registrata." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Attivazione Wi-Fi..." - }, - "End": { - "End": "Fine" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Ingrandisci al passaggio del mouse" - }, - "Enlargement %": { - "Enlargement %": "% Ingrandimento" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Inserisci passkey di 6 cifre" - }, - "Enter PIN": { - "Enter PIN": "Inserisci PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Inserisci PIN per " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Inserisci un URL o un testo da condividere" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Inserisci un nuovo nome per la sessione \"%1\"" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Inserisci un nuovo nome per questo spazio di lavoro" - }, - "Enter command or script path": { - "Enter command or script path": "Inserisci un comando o il percorso di uno script" - }, - "Enter credentials for ": { - "Enter credentials for ": "Inserisci credenziali per " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Inserisci il formato schermata di blocco personalizzato (es. dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Inserisci formato personalizzato barra superiore (es. ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Inserisci nome dispositivo..." - }, - "Enter filename...": { - "Enter filename...": "Inserisci nome file..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Inserisci il prefisso di avvio (es. \"uwsm-app\")" - }, - "Enter network name and password": { - "Enter network name and password": "Inserisci nome rete e password" - }, - "Enter passkey for ": { - "Enter passkey for ": "Inserisci passkey per " - }, - "Enter password for ": { - "Enter password for ": "Inserisci password per " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Inserisci questa passkey su " - }, - "Enter to Paste": { - "Enter to Paste": "Invio per Incollare" - }, - "Enterprise": { - "Enterprise": "Enterprise" - }, - "Entry pinned": { - "Entry pinned": "Voce fissata" - }, - "Entry unpinned": { - "Entry unpinned": "Voce rimossa" - }, - "Environment Variables": { - "Environment Variables": "Variabili d'Ambiente" - }, - "Error": { - "Error": "Errore" - }, - "Errors": { - "Errors": "Errori" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Esatto" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Offset Zona Esclusiva" - }, - "Experimental Feature": { - "Experimental Feature": "Funzionalità Sperimentale" - }, - "Explore": { - "Explore": "Esplora" - }, - "Exponential": { - "Exponential": "Esponenziale" - }, - "Expressive": { - "Expressive": "Espressivo" - }, - "Extend battery life": { - "Extend battery life": "Prolunga la durata della batteria" - }, - "Extensible architecture": { - "Extensible architecture": "Architettura estensibile" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Gestore Sfondi Esterno" - }, - "Extra Arguments": { - "Extra Arguments": "Argomenti Aggiuntivi" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Alterna • F10: Aiuto" - }, - "Fade": { - "Fade": "Dissolvenza" - }, - "Fade to lock screen": { - "Fade to lock screen": "Dissolvenza verso la schermata di blocco" - }, - "Fade to monitor off": { - "Fade to monitor off": "Dissolvenza fino allo spegnimento dello schermo" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Impossibile accettare l'associazione" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Impossibile attivare la configurazione" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Impossibile attivare il profilo - file non trovato" - }, - "Failed to add binds include": { - "Failed to add binds include": "Impossibile aggiungere l'inclusione delle scorciatoie" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Impossibile aggiungere la stampante alla classe" - }, - "Failed to browse device": { - "Failed to browse device": "Impossibile esplorare il dispositivo" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Impossibile annullare tutte le stampe" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Impossibile annullare la stampa selezionata" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Impossibile verificare gli aggiornamenti:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Impossibile verificare il limite delle voci fissate" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Impossibile connettersi alla VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Impossibile connettersi a %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Impossibile copiare la voce" - }, - "Failed to create printer": { - "Failed to create printer": "Impossibile creare la stampante" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Impossibile creare la directory dei profili" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Impossibile eliminare la VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Impossibile eliminare la classe" - }, - "Failed to delete printer": { - "Failed to delete printer": "Impossibile eliminare la stampante" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Impossibile disabilitare l'accettazione delle stampe" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Impossibile disattivare la modalità notturna" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Impossibile disconnettersi dalla VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Impossibile disconnettersi dalle VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Impossibile disconnettersi dal Wi-Fi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Impossibile attivare la posizione tramite IP" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Impossibile abilitare WiFi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Impossibile abilitare l'accettazione delle stampe" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Impossibile attivare la modalità notturna" - }, - "Failed to hold job": { - "Failed to hold job": "Impossibile sospendere la stampa" - }, - "Failed to import VPN": { - "Failed to import VPN": "Impossibile importare la VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Impossibile avviare l'app SMS" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Impossibile caricare la configurazione VPN" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Impossibile caricare la configurazione degli appunti." - }, - "Failed to move job": { - "Failed to move job": "Impossibile spostare la stampa" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Impossibile analizzare plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Impossibile analizzare session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Impossibile analizzare settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Impossibile mettere in pausa la stampante" - }, - "Failed to pin entry": { - "Failed to pin entry": "Impossibile fissare la voce" - }, - "Failed to print test page": { - "Failed to print test page": "Impossibile stampare la pagina di prova" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Impossibile rifiutare l'associazione" - }, - "Failed to remove device": { - "Failed to remove device": "Impossibile rimuovere dispositivo" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Impossibile rimuovere la scorciatoia" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Impossibile rimuovere la stampante dalla classe" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Impossibile riavviare il sistema audio" - }, - "Failed to restart job": { - "Failed to restart job": "Impossibile riavviare la stampa" - }, - "Failed to resume printer": { - "Failed to resume printer": "Impossibile riavviare la stampante" - }, - "Failed to ring device": { - "Failed to ring device": "Impossibile far squillare il dispositivo" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Impossibile eseguire \"dms greeter status\". Assicurati che DMS sia installato e dms sia nel PATH." - }, - "Failed to save audio config": { - "Failed to save audio config": "Impossibile salvare la configurazione audio" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Impossibile salvare l'impostazione degli appunti" - }, - "Failed to save keybind": { - "Failed to save keybind": "Impossibile salvare la scorciatoia" - }, - "Failed to save profile file": { - "Failed to save profile file": "Impossibile salvare il file del profilo" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Impossibile inviare gli appunti" - }, - "Failed to send file": { - "Failed to send file": "Impossibile inviare il file" - }, - "Failed to send ping": { - "Failed to send ping": "Impossibile inviare il ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "Impossibile impostare la luminosità" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Impossibile impostare la posizione per la modalità notturna" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Impossibile impostare la programmazione della modalità notturna" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Impossibile impostare la temperatura della modalità notturna" - }, - "Failed to set power profile": { - "Failed to set power profile": "Impossibile impostare il profilo energetico" - }, - "Failed to set profile image": { - "Failed to set profile image": "Impossibile impostare immagine profilo" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Impossibile impostare l'immagine del profilo: %1" - }, - "Failed to share": { - "Failed to share": "Impossibile condividere" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Impossibile avviare la connessione a %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Impossibile rimuovere la voce" - }, - "Failed to update VPN": { - "Failed to update VPN": "Impossibile aggiornare la VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Impossibile aggiornare connessione automatica" - }, - "Failed to update description": { - "Failed to update description": "Impossibile aggiornare la descrizione" - }, - "Failed to update location": { - "Failed to update location": "Impossibile aggiornare la posizione" - }, - "Failed to update sharing": { - "Failed to update sharing": "Impossibile aggiornare la condivisione" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Impossibile scrivere il file temporaneo per la validazione" - }, - "Features": { - "Features": "Funzionalità" - }, - "Feels": { - "Feels": "Temp. percepita" - }, - "Feels Like": { - "Feels Like": "Temp. percepita" - }, - "Feels Like %1°": { - "Feels Like %1°": "Percepiti %1°" - }, - "Fidelity": { - "Fidelity": "Fedeltà" - }, - "Field": { - "Field": "Campo" - }, - "File": { - "File": "File" - }, - "File Already Exists": { - "File Already Exists": "File già esistente" - }, - "File Information": { - "File Information": "Informazioni File" - }, - "File received from": { - "File received from": "File ricevuto da" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "La ricerca file richiede dsearch\\nInstalla da github.com/AvengeMedia/danksearch" - }, - "Files": { - "Files": "File" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Monitoraggio utilizzo del filesystem" - }, - "Fill": { - "Fill": "Riempi" - }, - "Find in Text": { - "Find in Text": "Trova nel Testo" - }, - "Find in note...": { - "Find in note...": "Trova in note..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "Impossibile confermare la disponibilità dell'impronta digitale." - }, - "Fingerprint error": { - "Fingerprint error": "Errore impronta digitale" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "Errore impronta digitale: %1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "Impronta digitale non riconosciuta (%1/%2). Riprova o usa la password." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Lettore di impronte rilevato, ma nessuna impronta è ancora registrata. Puoi abilitarlo ora e registrare le impronte in seguito." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "Lettore di impronte rilevato, ma nessuna impronta è ancora registrata. Puoi abilitarlo ora ed eseguire Sincronizza in seguito." - }, - "Finish": { - "Finish": "Fine" - }, - "First Day of Week": { - "First Day of Week": "Primo Giorno della Settimana" - }, - "First Time Setup": { - "First Time Setup": "Configurazione Iniziale" - }, - "Fit": { - "Fit": "Adatta" - }, - "Fix Now": { - "Fix Now": "Correggi Ora" - }, - "Fixing...": { - "Fixing...": "Correzione in corso..." - }, - "Flags": { - "Flags": "Flag" - }, - "Flipped": { - "Flipped": "Specchiato" - }, - "Flipped 180°": { - "Flipped 180°": "Specchiato di 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Specchiato di 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Specchiato di 90°" - }, - "Float": { - "Float": "Fluttuante" - }, - "Focus": { - "Focus": "Focus" - }, - "Focus at Startup": { - "Focus at Startup": "Attiva all'Avvio" - }, - "Focused Border": { - "Focused Border": "Bordo Attivo" - }, - "Focused Color": { - "Focused Color": "Colore Attivo" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Solo Schermo Attivo" - }, - "Focused Window": { - "Focused Window": "Finestra Attiva" - }, - "Focused monitor only": { - "Focused monitor only": "Solo schermo attivo" - }, - "Fog": { - "Fog": "Nebbia" - }, - "Folder": { - "Folder": "Cartella" - }, - "Folders": { - "Folders": "Cartelle" - }, - "Follow DMS background color": { - "Follow DMS background color": "Segui il colore di sfondo della DMS" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Segui lo Schermo Attivo" - }, - "Follow focus": { - "Follow focus": "Segui il focus" - }, - "Font": { - "Font": "Carattere" - }, - "Font Family": { - "Font Family": "Famiglia Font" - }, - "Font Scale": { - "Font Scale": "Scala Font" - }, - "Font Size": { - "Font Size": "Dimensione Font" - }, - "Font Weight": { - "Font Weight": "Spessore Font" - }, - "Font used on the login screen": { - "Font used on the login screen": "Carattere utilizzato nella schermata di accesso" - }, - "Force HDR": { - "Force HDR": "Forza HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Terminazione Forzata (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Forza Colore Esteso" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Forza applicazioni da terminale ad usare schemi di colori scuri" - }, - "Forecast": { - "Forecast": "Previsioni" - }, - "Forecast Days": { - "Forecast Days": "Giorni di Previsione" - }, - "Forecast Not Available": { - "Forecast Not Available": "Previsioni Non Disponibili" - }, - "Forever": { - "Forever": "Per Sempre" - }, - "Forget": { - "Forget": "Dimentica" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Dimenticare \"%1\"?" - }, - "Forget Device": { - "Forget Device": "Dimentica Disp." - }, - "Forget Network": { - "Forget Network": "Dimentica Rete" - }, - "Forgot network %1": { - "Forgot network %1": "Rete %1 dimenticata" - }, - "Format Legend": { - "Format Legend": "Legenda Formato" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "Trovato %1 pacchetto da aggiornare:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "Trovati %1 pacchetti da aggiornare:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "Libera VRAM/memoria alla chiusura del launcher. Potrebbe causare un leggero ritardo alla riapertura." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Pioviggine Gelante" - }, - "Frequency": { - "Frequency": "Frequenza" - }, - "Fruit Salad": { - "Fruit Salad": "Macedonia" - }, - "Full Command:": { - "Full Command:": "Comando completo:" - }, - "Full Content": { - "Full Content": "Contenuto Completo" - }, - "Full Day & Month": { - "Full Day & Month": "Data e Mese Est." - }, - "Full with Year": { - "Full with Year": "Completo con Anno" - }, - "Fullscreen": { - "Fullscreen": "Schermo intero" - }, - "Fullscreen Only": { - "Fullscreen Only": "Solo Schermo Intero" - }, - "Fully Charged": { - "Fully Charged": "Carica Completa" - }, - "Fun": { - "Fun": "Svago" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: griglia • Z/X: dimensione" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "Monitoraggio GPU" - }, - "GPU Temperature": { - "GPU Temperature": "Temperatura GPU" - }, - "GPU temperature display": { - "GPU temperature display": "Mostra Temperatura GPU" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE, altro" - }, - "Games": { - "Games": "Giochi" - }, - "Gamma Control": { - "Gamma Control": "Controllo Gamma" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Controllo gamma non disponibile. Richiede API DMS v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "Genera configurazioni di base GTK3/4 o QT5/QT6 (richiede qt6ct-kde) per seguire i colori DMS. Necessario solo una volta.

        Si consiglia di configurare adw-gtk3 prima di applicare i temi GTK." - }, - "Generic": { - "Generic": "Generico" - }, - "Get Started": { - "Get Started": "Inizia" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Scala globalmente tutte le durate delle animazioni" - }, - "Golden Hour": { - "Golden Hour": "Ora d'Oro" - }, - "Good": { - "Good": "Buona" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Raggio Angoli Gotici" - }, - "Goth Corners": { - "Goth Corners": "Angoli Acuti" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Dissolvi gradualmente lo schermo prima del blocco, con un periodo di tolleranza configurabile" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Dissolvi gradualmente lo schermo prima di spegnere gli schermi, con un periodo di tolleranza configurabile" - }, - "Graph Time Range": { - "Graph Time Range": "Intervallo Temporale del Grafico" - }, - "Graphics": { - "Graphics": "Grafica" - }, - "Greeter": { - "Greeter": "Greeter" - }, - "Greeter Appearance": { - "Greeter Appearance": "Aspetto del Greeter" - }, - "Greeter Behavior": { - "Greeter Behavior": "Comportamento del Greeter" - }, - "Greeter Status": { - "Greeter Status": "Stato del Greeter" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Greeter attivato. greetd è ora attivato." - }, - "Greeter font": { - "Greeter font": "Carattere del Greeter" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Solo per il greeter - non influenza l'orologio principale" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Solo per il greeter - formato della data sulla schermata di accesso" - }, - "Grid": { - "Grid": "Griglia" - }, - "Grid Columns": { - "Grid Columns": "Colonne Griglia" - }, - "Grid: OFF": { - "Grid: OFF": "Griglia: disattivata" - }, - "Grid: ON": { - "Grid: ON": "Griglia: attivata" - }, - "Group": { - "Group": "Gruppo" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Raggruppa App per Spazio di Lavoro" - }, - "Group by App": { - "Group by App": "Raggruppa per App" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Raggruppa molteplici finestre della stessa app con un indicatore del numero di finestre" - }, - "Group removed": { - "Group removed": "Gruppo rimosso" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Raggruppa le icone delle applicazioni duplicate negli spazi di lavoro non attivi" - }, - "Groups": { - "Groups": "Gruppi" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Mappatura dei Toni HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "La modalità HDR è sperimentale. Verifica che lo schermo supporti l’HDR prima di abilitarla." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML copiato negli appunti" - }, - "Health": { - "Health": "Salute" - }, - "Heavy Rain": { - "Heavy Rain": "Pioggia Forte" - }, - "Heavy Snow": { - "Heavy Snow": "Neve Abbondante" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Forti Rovesci di Neve" - }, - "Height": { - "Height": "Altezza" - }, - "Held": { - "Held": "In Sospeso" - }, - "Help": { - "Help": "Guida" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Ibernazione" - }, - "Hidden": { - "Hidden": "Nascosto" - }, - "Hidden (%1)": { - "Hidden (%1)": "Nascosti (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "App Nascoste" - }, - "Hidden Network": { - "Hidden Network": "Rete Nascosta" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Le app nascoste non appariranno nel launcher. Fai clic col tasto destro su un'app e seleziona \"Nascondi App\" per nasconderla." - }, - "Hide": { - "Hide": "Nascondi" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Nascondi Terze Parti" - }, - "Hide App": { - "Hide App": "Nascondi App" - }, - "Hide Delay": { - "Hide Delay": "Ritardo Scomparsa" - }, - "Hide Indicators": { - "Hide Indicators": "Nascondi Indicatori" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Nascondi Widget di Aggiornamento" - }, - "Hide When Typing": { - "Hide When Typing": "Nascondi Durante la Digitazione" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Nascondi Quando le Finestre Sono Aperte" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Nascondi il cursore dopo inattività (0 = disattivato)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Nascondi il cursore quando si premono i tasti della tastiera" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Nascondi il cursore quando si usa l'input touch" - }, - "Hide device": { - "Hide device": "Nascondi dispositivo" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Nascondi il contenuto della notifica finché non viene espansa" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Nascondi il contenuto della notifica finché non viene espansa; i popup appaiono ridotti per impostazione predefinita" - }, - "Hide on Touch": { - "Hide on Touch": "Nascondi al Tocco" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Tavolozza ad alta fedeltà che preserva le tonalità della sorgente." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Evidenzia App Spazio di Lavoro Attivo" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "Evidenzia l'app attualmente in focus negli indicatori degli spazi di lavoro" - }, - "History": { - "History": "Cronologia" - }, - "History Retention": { - "History Retention": "Conservazione della Cronologia" - }, - "History Settings": { - "History Settings": "Impostazioni Cronologia" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Cronologia cancellata. %1 voci fissate mantenute." - }, - "Hold Duration": { - "Hold Duration": "Durata della Pressione" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Tieni premuto più a lungo per confermare" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Tieni Premuto per Confermare le Azioni di Alimentazione" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Tieni premuto per confermare (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Tieni premuto per confermare (%1s)" - }, - "Home": { - "Home": "Home" - }, - "Host": { - "Host": "Host" - }, - "Hostname": { - "Hostname": "Nome host" - }, - "Hot Corners": { - "Hot Corners": "Angoli Attivi" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Titolo della sovrapposizione per scorciatoie (opzionale)" - }, - "Hour": { - "Hour": "Ora" - }, - "Hourly": { - "Hourly": "Orario" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Numero di Previsioni Orarie" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Quanto spesso cambiare lo sfondo" - }, - "How the background image is scaled": { - "How the background image is scaled": "Come viene ridimensionata l'immagine di sfondo" - }, - "Humidity": { - "Humidity": "Umidità" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Server Discord di Hyprland" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Sovrascritture Layout Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "Opzioni Hyprland" - }, - "Hyprland Website": { - "Hyprland Website": "Sito Web di Hyprland" - }, - "I Understand": { - "I Understand": "Ho capito" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "Indirizzo IP:" - }, - "IP address or hostname": { - "IP address or hostname": "Indirizzo IP o nome host" - }, - "ISO Date": { - "ISO Date": "Data ISO" - }, - "Icon": { - "Icon": "Icona" - }, - "Icon Scale": { - "Icon Scale": "Scala Icone" - }, - "Icon Size": { - "Icon Size": "Dimensione Icona" - }, - "Icon Size %": { - "Icon Size %": "% Dimensione Icona" - }, - "Icon Theme": { - "Icon Theme": "Tema Icone" - }, - "Idle": { - "Idle": "Inattivo" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Blocco Sospensione" - }, - "Idle Settings": { - "Idle Settings": "Impostazioni Riposo" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Monitoraggio riposo non supportato - richiede una versione più recente di Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Se il campo è nascosto, apparirà non appena viene premuto un tasto." - }, - "Ignore Completely": { - "Ignore Completely": "Ignora Completamente" - }, - "Image": { - "Image": "Immagine" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Immagine copiata negli appunti" - }, - "Import": { - "Import": "Importa" - }, - "Import VPN": { - "Import VPN": "Importa una VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Colore dello Schermo Inattivo" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Includi Transizioni" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Includi azioni desktop (scorciatoie) nei risultati di ricerca." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Plugin Incompatibili Caricati" - }, - "Incorrect password": { - "Incorrect password": "Password errata" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Password errata - tentativo %1 di %2 (il blocco potrebbe avvenire)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Password errata - ulteriori errori potrebbero bloccare l'account" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "Password errata - riprova" - }, - "Indicator Style": { - "Indicator Style": "Stile Indicatore" - }, - "Individual Batteries": { - "Individual Batteries": "Batterie Individuali" - }, - "Individual bar configuration": { - "Individual bar configuration": "Configurazione barra individuale" - }, - "Info": { - "Info": "Informazioni" - }, - "Inherit": { - "Inherit": "Eredita" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Eredita Globale (Predefinito)" - }, - "Inhibitable": { - "Inhibitable": "Inibibile" - }, - "Input Devices": { - "Input Devices": "Dispositivi di Input" - }, - "Input Volume Slider": { - "Input Volume Slider": "Slider Volume di Input" - }, - "Insert your security key...": { - "Insert your security key...": "Inserisci la tua chiave di sicurezza..." - }, - "Install": { - "Install": "Installa" - }, - "Install Greeter": { - "Install Greeter": "Installa Greeter" - }, - "Install Plugin": { - "Install Plugin": "Installa Plugin" - }, - "Install Theme": { - "Install Theme": "Installa Tema" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Installa temi colore dal registro temi DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Installazione completata. Il Greeter è stato installato." - }, - "Install failed: %1": { - "Install failed: %1": "Installazione fallita: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Installa il pacchetto matugen per il theming dinamico" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Installa il plugin \"%1\" dal registro DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Installa plugin dal registro dei plugin DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "Installare il greeter DMS? Si aprirà un terminale per l'autenticazione sudo." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Installa il tema \"%1\" dal registro DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Installazione e configurazione di PAM: vedi la " - }, - "Installed": { - "Installed": "Installato" - }, - "Installed: %1": { - "Installed: %1": "Installato: %1" - }, - "Installing: %1": { - "Installing: %1": "Installando: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Nascondimento automatico intelligente" - }, - "Intensity": { - "Intensity": "Intensità" - }, - "Interface:": { - "Interface:": "Interfaccia:" - }, - "Interlock Open": { - "Interlock Open": "Interblocco Aperto" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervallo" - }, - "Invalid configuration": { - "Invalid configuration": "Configurazione non valida" - }, - "Invert on mode change": { - "Invert on mode change": "Inverti al cambio di modalità" - }, - "Iris Bloom": { - "Iris Bloom": "Effetto Iride" - }, - "Isolate Displays": { - "Isolate Displays": "Isola Schermi" - }, - "Jobs": { - "Jobs": "Stampe" - }, - "Jobs: ": { - "Jobs: ": "Stampe: " - }, - "Keep Awake": { - "Keep Awake": "Mantieni Attivo" - }, - "Keep Changes": { - "Keep Changes": "Conserva Modifiche" - }, - "Keeping Awake": { - "Keeping Awake": "Mantieni Attivo" - }, - "Kernel": { - "Kernel": "Kernel" - }, - "Key": { - "Key": "Tasto" - }, - "Keybind Sources": { - "Keybind Sources": "Sorgenti Scorciatoie" - }, - "Keybinds": { - "Keybinds": "Scorciatoie" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Impostazioni Ricerca Scorciatoie" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Scorciatoie mostrate insieme ai normali risultati di ricerca" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Nome Layout Tastiera" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Scorciatoie da Tastiera" - }, - "Keys": { - "Keys": "Tasti" - }, - "Kill": { - "Kill": "Termina" - }, - "Kill Process": { - "Kill Process": "Termina Processo" - }, - "Kill Session": { - "Kill Session": "Termina Sessione" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "Dispositivo LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "Canale IRC di LabWC" - }, - "LabWC Website": { - "LabWC Website": "Sito Web di LabWC" - }, - "Large": { - "Large": "Grande" - }, - "Largest": { - "Largest": "Molto Grande" - }, - "Last hour": { - "Last hour": "Ultima ora" - }, - "Last launched %1": { - "Last launched %1": "Ultimo avvio %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Ultimo avvio %1 giorno fa" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Ultimo avvio %1 giorni fa" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Ultimo avvio %1 ora fa" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Ultimo avvio %1 ore fa" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Ultimo avvio %1 minuto fa" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Ultimo avvio %1 minuti fa" - }, - "Last launched just now": { - "Last launched just now": "Appena avviato" - }, - "Latitude": { - "Latitude": "Latitudine" - }, - "Launch": { - "Launch": "Avvia" - }, - "Launch Prefix": { - "Launch Prefix": "Prefisso Avvio" - }, - "Launch on dGPU": { - "Launch on dGPU": "Avvia su dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "Avvia sulla GPU dedicata per impostazione predefinita" - }, - "Launcher": { - "Launcher": "Launcher" - }, - "Launcher Button": { - "Launcher Button": "Pulsante del Launcher" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Logo Pulsante Launcher" - }, - "Layout": { - "Layout": "Layout" - }, - "Layout Overrides": { - "Layout Overrides": "Sovrascritture del Layout" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "Il layout e le posizioni dei moduli sul greeter sono sincronizzati dalla tua shell (es. configurazione della barra). Esegui Sincronizza per applicare." - }, - "Left": { - "Left": "Sinistra" - }, - "Left Center": { - "Left Center": "Al Centro a Sinistra" - }, - "Left Section": { - "Left Section": "Sezione Sinistra" - }, - "Light Direction": { - "Light Direction": "Direzione della Luce" - }, - "Light Mode": { - "Light Mode": "Modalità Chiara" - }, - "Light Rain": { - "Light Rain": "Pioggia Leggera" - }, - "Light Snow": { - "Light Snow": "Neve Leggera" - }, - "Light Snow Showers": { - "Light Snow Showers": "Deboli Rovesci di Neve" - }, - "Light mode base": { - "Light mode base": "Base modalità chiara" - }, - "Light mode harmony": { - "Light mode harmony": "Armonia modalità chiara" - }, - "Line": { - "Line": "Linea" - }, - "Line: %1": { - "Line: %1": "Riga: %1" - }, - "Linear": { - "Linear": "Lineare" - }, - "Lines: %1": { - "Lines: %1": "Righe: %1" - }, - "List": { - "List": "Elenco" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Tavolozza vivace con accenti saturi." - }, - "Load Average": { - "Load Average": "Carico Medio" - }, - "Loading codecs...": { - "Loading codecs...": "Caricamento codec in corso..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Caricamento scorciatoie..." - }, - "Loading trending...": { - "Loading trending...": "Caricamento tendenze..." - }, - "Loading...": { - "Loading...": "Caricamento..." - }, - "Local": { - "Local": "Locale" - }, - "Locale": { - "Locale": "Lingua" - }, - "Locale Settings": { - "Locale Settings": "Impostazioni della Lingua" - }, - "Location": { - "Location": "Posizione" - }, - "Location Search": { - "Location Search": "Ricerca Posizione" - }, - "Lock": { - "Lock": "Blocca" - }, - "Lock Screen": { - "Lock Screen": "Schermata di Blocco" - }, - "Lock Screen Display": { - "Lock Screen Display": "Schermo della Schermata di Blocco" - }, - "Lock Screen Format": { - "Lock Screen Format": "Formato Schermata di Blocco" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Comportamento Schermata di Blocco" - }, - "Lock Screen layout": { - "Lock Screen layout": "Layout Schermata di Blocco" - }, - "Lock at startup": { - "Lock at startup": "Blocca all'avvio" - }, - "Lock before suspend": { - "Lock before suspend": "Blocca prima di sospendere" - }, - "Lock fade grace period": { - "Lock fade grace period": "Periodo di attesa per la dissolvenza al blocco" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "Le modifiche all'autenticazione della schermata di blocco vengono applicate automaticamente e potrebbero aprire un terminale quando è richiesta l'autenticazione sudo." - }, - "Locked": { - "Locked": "Bloccato" - }, - "Log Out": { - "Log Out": "Termina Sessione" - }, - "Logging in...": { - "Logging in...": "Accesso in corso..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Autenticazione di Accesso" - }, - "Long": { - "Long": "Lunga" - }, - "Long Text": { - "Long Text": "Testo Lungo" - }, - "Long press": { - "Long press": "Pressione prolungata" - }, - "Longitude": { - "Longitude": "Longitudine" - }, - "Low Priority": { - "Low Priority": "Bassa Priorità" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Assicurati che KDE Connect o Valent siano in esecuzione sui tuoi altri dispositivi" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Gestione e configurazione dei plugin per estendere le funzionalità della DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Gestisci fino a 4 configurazioni di barre indipendenti. Ogni barra ha la propria posizione, widget, stile e assegnazione schermo." - }, - "Management": { - "Management": "Gestione" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "Sovrascritture Layout MangoWC" - }, - "Manual": { - "Manual": "Manuale" - }, - "Manual Coordinates": { - "Manual Coordinates": "Coordinate Manuali" - }, - "Manual Direction": { - "Manual Direction": "Direzione Manuale" - }, - "Manual Gap Size": { - "Manual Gap Size": "Dimensione Manuale Spaziatura" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Mostra/Nascondi Manuale" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Associa i nomi delle classi delle finestre ai nomi delle icone per una corretta visualizzazione" - }, - "Margin": { - "Margin": "Margini" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Toner Esaurito" - }, - "Marker Supply Low": { - "Marker Supply Low": "Toner in Esaurimento" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Vaschetta Recupero Toner Quasi Piena" - }, - "Marker Waste Full": { - "Marker Waste Full": "Vaschetta Recupero Toner Piena" - }, - "Match Criteria": { - "Match Criteria": "Criteri di Corrispondenza" - }, - "Matches profile: %1": { - "Matches profile: %1": "Corrisponde al profilo: %1" - }, - "Material Colors": { - "Material Colors": "Colori Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Temi colore ispirati al Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Colori material generati dallo sfondo" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "Ombre e rilievi ispirati al Material Design su modali, popup e finestre di dialogo" - }, - "Matugen Contrast": { - "Matugen Contrast": "Contrasto Matugen" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen Mancante" - }, - "Matugen Palette": { - "Matugen Palette": "Tavolozza Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Schermo di Destinazione Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Template Matugen" - }, - "Max Edges": { - "Max Edges": "Bordi Massimi" - }, - "Max H": { - "Max H": "Altezza Max." - }, - "Max Pinned Apps": { - "Max Pinned Apps": "App Fissate Massime" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "App Fissate Massime (0 = Illimitate)" - }, - "Max Running Apps": { - "Max Running Apps": "App in Esecuzione Massime" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "App in Esecuzione Massime (0 = Illimitate)" - }, - "Max Volume": { - "Max Volume": "Volume Massimo" - }, - "Max W": { - "Max W": "Larghezza Max." - }, - "Max apps to show": { - "Max apps to show": "Numero massimo di app da visualizzare" - }, - "Max to Edges": { - "Max to Edges": "Espandi ai Bordi" - }, - "Maximize": { - "Maximize": "Massimizza" - }, - "Maximize Detection": { - "Maximize Detection": "Rilevamento Finestra Massimizzata" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Massimizza Icone Widget" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Massimizza Testo Widget" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Dimensione Massima della Voce" - }, - "Maximum History": { - "Maximum History": "Cronologia Massima" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Numero Massimo di Voci Fissate" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "Raggiunto il numero massimo di tentativi per l'impronta digitale. Per favore usa la password." - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Numero massimo di voci degli appunti da conservare" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Numero massimo di voci che possono essere salvate" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Numero massimo di notifiche da conservare" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Raggiunto il numero massimo di voci fissate" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Dimensione massima per ogni voce degli appunti" - }, - "Media": { - "Media": "Media" - }, - "Media Controls": { - "Media Controls": "Controlli Media" - }, - "Media Empty": { - "Media Empty": "Carta Esaurita" - }, - "Media Jam": { - "Media Jam": "Inceppamento Carta" - }, - "Media Low": { - "Media Low": "Carta in Esaurimento" - }, - "Media Needed": { - "Media Needed": "Carta Richiesta" - }, - "Media Playback": { - "Media Playback": "Riproduzione Multimediale" - }, - "Media Player": { - "Media Player": "Lettore Multimediale" - }, - "Media Player Settings": { - "Media Player Settings": "Impostazioni Lettore Multimediale" - }, - "Media Players": { - "Media Players": "Lettori Multimediali" - }, - "Media Players (": { - "Media Players (": "Lettori Multimediali (" - }, - "Media Volume": { - "Media Volume": "Volume Media" - }, - "Medium": { - "Medium": "Media" - }, - "Memory": { - "Memory": "Memoria" - }, - "Memory Graph": { - "Memory Graph": "Grafico della Memoria" - }, - "Memory Usage": { - "Memory Usage": "Utilizzo Memoria" - }, - "Memory usage indicator": { - "Memory usage indicator": "Indicatore utilizzo memoria" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Messaggio" - }, - "Message Content": { - "Message Content": "Contenuto Messaggio" - }, - "Microphone": { - "Microphone": "Microfono" - }, - "Microphone Mute": { - "Microphone Mute": "Silenzia Microfono" - }, - "Microphone Volume": { - "Microphone Volume": "Volume Microfono" - }, - "Microphone settings": { - "Microphone settings": "Impostazioni Microfono" - }, - "Microphone volume control": { - "Microphone volume control": "Controllo volume microfono" - }, - "Middle Section": { - "Middle Section": "Sezione Centrale" - }, - "Min H": { - "Min H": "Altezza Min." - }, - "Min W": { - "Min W": "Larghezza Min." - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Tavolozza minima costruita attorno a una singola tonalità." - }, - "Minute": { - "Minute": "Minuto" - }, - "Mirror Display": { - "Mirror Display": "Duplica Schermo" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Variabili di Ambiente Mancanti" - }, - "Modal Background": { - "Modal Background": "Sfondo Modale" - }, - "Modal Shadows": { - "Modal Shadows": "Ombre Modali" - }, - "Modals": { - "Modals": "Finestre Modali" - }, - "Mode": { - "Mode": "Modalità" - }, - "Mode:": { - "Mode:": "Modalità:" - }, - "Model": { - "Model": "Modello" - }, - "Modified": { - "Modified": "Modificato" - }, - "Modular widget bar": { - "Modular widget bar": "Barra widget modulare" - }, - "Monitor": { - "Monitor": "Schermo" - }, - "Monitor Configuration": { - "Monitor Configuration": "Configurazione Schermo" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Periodo di attesa per la dissolvenza dello schermo" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Monitor il cui sfondo determina i colori del tema dinamico" - }, - "Monochrome": { - "Monochrome": "Monocromatico" - }, - "Monocle": { - "Monocle": "Vista Singola" - }, - "Monospace Font": { - "Monospace Font": "Font a Larghezza Fissa" - }, - "Month Date": { - "Month Date": "Mese e Data" - }, - "Morning": { - "Morning": "Mattina" - }, - "Mount Points": { - "Mount Points": "Punti di Montaggio" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Aspetto puntatore del mouse" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Dimensione puntatore del mouse in pixel" - }, - "Move": { - "Move": "Sposta" - }, - "Move Widget": { - "Move Widget": "Sposta Widget" - }, - "Moving to Paused": { - "Moving to Paused": "Messa in Pausa" - }, - "Multi-Monitor": { - "Multi-Monitor": "Multi-Schermo" - }, - "Multiplexer": { - "Multiplexer": "Multiplexer" - }, - "Multiplexer Type": { - "Multiplexer Type": "Tipo di Multiplexer" - }, - "Multiplexers": { - "Multiplexers": "Multiplexer" - }, - "Music": { - "Music": "Musica" - }, - "Mute Popups": { - "Mute Popups": "Silenzia Popup" - }, - "Mute popups for %1": { - "Mute popups for %1": "Silenzia popup per %1" - }, - "Muted": { - "Muted": "Silenziato" - }, - "Muted Apps": { - "Muted Apps": "App Silenziate" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Tavolozza sobria con toni sommessi e calmanti." - }, - "NM not supported": { - "NM not supported": "NM non supportato" - }, - "Name": { - "Name": "Nome" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Icone Spazi di Lavoro con Nome" - }, - "Navigate": { - "Navigate": "Naviga" - }, - "Navigation": { - "Navigation": "Navigazione" - }, - "Network": { - "Network": "Rete" - }, - "Network Graph": { - "Network Graph": "Grafico della Rete" - }, - "Network Info": { - "Network Info": "Info Rete" - }, - "Network Information": { - "Network Information": "Informazioni Rete" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Nome della Rete (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Monitor Velocità Rete" - }, - "Network Status": { - "Network Status": "Stato Rete" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Mostra velocità di download e upload della rete" - }, - "Neutral": { - "Neutral": "Neutro" - }, - "Never": { - "Never": "Mai" - }, - "Never used": { - "Never used": "Mai usato" - }, - "New": { - "New": "Nuovo" - }, - "New Key": { - "New Key": "Nuovo Tasto" - }, - "New Keybind": { - "New Keybind": "Nuova Scorciatoia" - }, - "New Notification": { - "New Notification": "Nuova Notifica" - }, - "New Session": { - "New Session": "Nuova Sessione" - }, - "New Window Rule": { - "New Window Rule": "Nuova Regola Finestra" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Nome del nuovo gruppo..." - }, - "Next": { - "Next": "Avanti" - }, - "Next Transition": { - "Next Transition": "Prossima Transizione" - }, - "Night": { - "Night": "Notte" - }, - "Night Mode": { - "Night Mode": "Modalità Notte" - }, - "Night Temperature": { - "Night Temperature": "Temperatura Notturna" - }, - "Night mode & gamma": { - "Night mode & gamma": "Modalità notte e gamma" - }, - "Niri Integration": { - "Niri Integration": "Integrazione Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Sovrascritture Layout Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Azioni del compositor Niri (focus, sposta, etc.)" - }, - "No": { - "No": "No" - }, - "No Active Players": { - "No Active Players": "Nessun Riproduttore Attivo" - }, - "No Anim": { - "No Anim": "Nessuna Anim." - }, - "No Background": { - "No Background": "Nessuno Sfondo" - }, - "No Battery": { - "No Battery": "Nessuna Batteria" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Nessun adattatore Bluetooth trovato" - }, - "No Blur": { - "No Blur": "Nessuna Sfocatura" - }, - "No Border": { - "No Border": "Nessun Bordo" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Nessuna scorciatoia DMS configurata" - }, - "No Dim": { - "No Dim": "Nessun Oscuramento" - }, - "No Focus": { - "No Focus": "Nessun Focus" - }, - "No GPU detected": { - "No GPU detected": "Nessuna GPU rilevata" - }, - "No GPUs detected": { - "No GPUs detected": "Nessuna GPU rilevata" - }, - "No History": { - "No History": "Nessuna Cronologia" - }, - "No Media": { - "No Media": "Nessun Media" - }, - "No Round": { - "No Round": "Niente Arr." - }, - "No Rounding": { - "No Rounding": "Nessun Arr." - }, - "No Shadow": { - "No Shadow": "Nessuna Ombra" - }, - "No VPN profiles": { - "No VPN profiles": "Nessun profilo VPN" - }, - "No Weather": { - "No Weather": "Nessun Meteo" - }, - "No Weather Data": { - "No Weather Data": "Nessun Dato Meteo" - }, - "No Weather Data Available": { - "No Weather Data Available": "Nessun Dato Meteo Disponibile" - }, - "No action": { - "No action": "Nessuna azione" - }, - "No active %1 sessions": { - "No active %1 sessions": "Nessuna sessione %1 attiva" - }, - "No adapter": { - "No adapter": "Nessun adattatore" - }, - "No adapters": { - "No adapters": "Nessun adattatore" - }, - "No app customizations.": { - "No app customizations.": "Nessuna personalizzazione app." - }, - "No apps found": { - "No apps found": "Nessuna app trovata" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Nessuna app è stata ancora avviata." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Nessuna app silenziata. Fai clic destro su una notifica e scegli \"Silenzia popup\" per aggiungerne una qui." - }, - "No battery": { - "No battery": "Nessuna batteria" - }, - "No brightness devices available": { - "No brightness devices available": "Nessun dispositivo di luminosità disponibile" - }, - "No changes": { - "No changes": "Nessun cambiamento" - }, - "No checks passed": { - "No checks passed": "Nessun controllo superato" - }, - "No custom theme file": { - "No custom theme file": "Nessun file tema personalizzato" - }, - "No devices": { - "No devices": "Nessun dispositivo" - }, - "No devices connected": { - "No devices connected": "Nessun dispositivo connesso" - }, - "No devices found": { - "No devices found": "Nessun dispositivo trovato" - }, - "No disk data": { - "No disk data": "Nessun dato sul disco" - }, - "No disk data available": { - "No disk data available": "Nessun dato sul disco disponibile" - }, - "No drivers found": { - "No drivers found": "Nessun driver trovato" - }, - "No errors": { - "No errors": "Nessun errore" - }, - "No features enabled": { - "No features enabled": "Nessuna funzionalità abilitata" - }, - "No files found": { - "No files found": "Nessun file trovato" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Nessun lettore di impronte digitali rilevato." - }, - "No folders found": { - "No folders found": "Nessuna cartella trovata" - }, - "No hidden apps.": { - "No hidden apps.": "Nessuna app nascosta." - }, - "No info items": { - "No info items": "Nessun elemento informativo" - }, - "No information available": { - "No information available": "Nessuna informazione disponibile" - }, - "No input device": { - "No input device": "Nessun dispositivo di input" - }, - "No input devices found": { - "No input devices found": "Nessun dispositivo di input trovato" - }, - "No items added yet": { - "No items added yet": "Nessun elemento aggiunto ancora" - }, - "No keybinds found": { - "No keybinds found": "Nessuna scorciatoia trovata" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Nessun plugin del launcher installato." - }, - "No match criteria": { - "No match criteria": "Nessun criterio di corrispondenza" - }, - "No matches": { - "No matches": "Nessun risultato" - }, - "No matching processes": { - "No matching processes": "Nessun processo corrispondente" - }, - "No monitors": { - "No monitors": "Nessun monitor" - }, - "No mount points found": { - "No mount points found": "Nessun punto di montaggio trovato" - }, - "No output device": { - "No output device": "Nessun dispositivo di output" - }, - "No output devices found": { - "No output devices found": "Nessun dispositivo di output trovato" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Nessun gestore pacchetti trovato. Installa \"paru\" o \"yay\" su sistemi basati su Arch per verificare gli aggiornamenti." - }, - "No plugin results": { - "No plugin results": "Nessun risultato plugin" - }, - "No plugins found": { - "No plugins found": "Nessun plugin trovato" - }, - "No plugins found.": { - "No plugins found.": "Nessun plugin trovato." - }, - "No printer found": { - "No printer found": "Nessuna stampante trovata" - }, - "No printers configured": { - "No printers configured": "Nessuna stampante configurata" - }, - "No printers found": { - "No printers found": "Nessuna stampante trovata" - }, - "No profiles": { - "No profiles": "Nessun profilo" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Nessuna voce recente negli appunti" - }, - "No results found": { - "No results found": "Nessun risultato trovato" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Nessuna voce degli appunti salvata" - }, - "No sessions found": { - "No sessions found": "Nessuna sessione trovata" - }, - "No status output.": { - "No status output.": "Nessun output di stato." - }, - "No themes found": { - "No themes found": "Nessun tema trovato" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Nessun tema installato. Sfoglia i temi dal registro per installarli." - }, - "No trigger": { - "No trigger": "Nessun attivatore" - }, - "No video found in folder": { - "No video found in folder": "Nessun video trovato nella cartella" - }, - "No wallpaper selected": { - "No wallpaper selected": "Nessuno sfondo selezionato" - }, - "No wallpapers": { - "No wallpapers": "Nessuno sfondo" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Nessuno sfondo trovato\n\nFai clic sull'icona della cartella qui sotto per sfogliare" - }, - "No warnings": { - "No warnings": "Nessun avviso" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Nessun widget aggiunto. Fai clic su \"Aggiungi Widget\" per iniziare." - }, - "No widgets available": { - "No widgets available": "Nessun widget disponibile" - }, - "No widgets match your search": { - "No widgets match your search": "Nessun widget corrisponde alla tua ricerca" - }, - "No window rules configured": { - "No window rules configured": "Nessuna regola finestra configurata" - }, - "None": { - "None": "Nessuna" - }, - "Normal": { - "Normal": "Normale" - }, - "Normal Font": { - "Normal Font": "Font Normale" - }, - "Normal Priority": { - "Normal Priority": "Priorità Normale" - }, - "Not available": { - "Not available": "Non disponibile" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Non disponibile — installa fprintd e pam_fprintd, o configura il PAM di greetd." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Non disponibile — installa fprintd e pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "Non disponibile — installa o configura pam_u2f, o configura il PAM di greetd." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Non disponibile — installa o configura pam_u2f." - }, - "Not connected": { - "Not connected": "Non connesso" - }, - "Not detected": { - "Not detected": "Non rilevato" - }, - "Not paired": { - "Not paired": "Non associato" - }, - "Not set": { - "Not set": "Non impostato" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Nota: questa opzione modifica solo la percentuale, non limita effettivamente la carica." - }, - "Notepad": { - "Notepad": "Blocco Note" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Impostazioni Font Blocco Note" - }, - "Notepad Slideout": { - "Notepad Slideout": "Blocco Note a Comparsa" - }, - "Nothing": { - "Nothing": "Niente" - }, - "Nothing to see here": { - "Nothing to see here": "Nulla da vedere qui" - }, - "Notification Center": { - "Notification Center": "Centro Notifiche" - }, - "Notification Display": { - "Notification Display": "Visualizzazione Notifiche" - }, - "Notification Overlay": { - "Notification Overlay": "Sovrapposizione Notifiche" - }, - "Notification Popups": { - "Notification Popups": "Popup Notifiche" - }, - "Notification Rules": { - "Notification Rules": "Regole Notifica" - }, - "Notification Settings": { - "Notification Settings": "Impostazioni Notifiche" - }, - "Notification Timeouts": { - "Notification Timeouts": "Timeout Notifiche" - }, - "Notification toast popups": { - "Notification toast popups": "Popup notifiche a comparsa" - }, - "Notifications": { - "Notifications": "Notifiche" - }, - "Numbers": { - "Numbers": "Numeri" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numerico (G/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numerico (M/G)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Logo OS" - }, - "OSD Position": { - "OSD Position": "Posizione Indicatori a Schermo" - }, - "Occupied Color": { - "Occupied Color": "Colore Occupato" - }, - "Off": { - "Off": "Disattivato" - }, - "Office": { - "Office": "Ufficio" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Riepilogo Offline" - }, - "Older": { - "Older": "Più Vecchie" - }, - "On": { - "On": "Attivo" - }, - "On-Demand": { - "On-Demand": "Su Richiesta" - }, - "On-Screen Displays": { - "On-Screen Displays": "Indicatori a Schermo" - }, - "On-screen Displays": { - "On-screen Displays": "Indicatori a Schermo" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Regola la gamma solo in base alle regole di tempo o di posizione." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "Influisce solo sul PAM gestito da DMS. Se greetd include già pam_fprintd, l'impronta digitale rimane abilitata." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Mostra solo le finestre dello schermo corrente su ogni dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Visibile solo se l'ibernazione è supportata dal tuo sistema" - }, - "Opacity": { - "Opacity": "Opacità" - }, - "Opaque": { - "Opaque": "Opaco" - }, - "Open": { - "Open": "Apri" - }, - "Open App": { - "Open App": "Apri l'App" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Apri KDE Connect sul tuo telefono" - }, - "Open Notepad File": { - "Open Notepad File": "Apri File Blocco Note" - }, - "Open a new note": { - "Open a new note": "Apri una nuova nota" - }, - "Open folder": { - "Open folder": "Apri cartella" - }, - "Open in Browser": { - "Open in Browser": "Apri nel Browser" - }, - "Open in terminal": { - "Open in terminal": "Apri nel Terminale" - }, - "Open search bar to find text": { - "Open search bar to find text": "Apri barra di ricerca per cercare testo" - }, - "Open with...": { - "Open with...": "Apri con..." - }, - "Opening SMS": { - "Opening SMS": "Apertura SMS" - }, - "Opening SMS app": { - "Opening SMS app": "Apertura dell'app SMS" - }, - "Opening file browser": { - "Opening file browser": "Apertura del gestore file" - }, - "Opening files": { - "Opening files": "Apertura dei file" - }, - "Opening terminal: ": { - "Opening terminal: ": "Apertura del terminale: " - }, - "Optional description": { - "Optional description": "Descrizione facoltativa" - }, - "Optional location": { - "Optional location": "Posizione facoltativa" - }, - "Options": { - "Options": "Opzioni" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Organizza i widget in gruppi comprimibili" - }, - "Original: %1": { - "Original: %1": "Originale: %1" - }, - "Other": { - "Other": "Altro" - }, - "Outline": { - "Outline": "Bordo" - }, - "Output": { - "Output": "Output" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Vassoio di Uscita Quasi Pieno" - }, - "Output Area Full": { - "Output Area Full": "Vassoio di Uscita Pieno" - }, - "Output Device": { - "Output Device": "Dispositivo di Uscita" - }, - "Output Devices": { - "Output Devices": "Dispositivi di Uscita" - }, - "Output Tray Missing": { - "Output Tray Missing": "Vassoio Uscita Mancante" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Inclusione Output Mancanti" - }, - "Overcast": { - "Overcast": "Coperto" - }, - "Overflow": { - "Overflow": "Overflow" - }, - "Overridden by config": { - "Overridden by config": "Sovrascritto dalla configurazione" - }, - "Override": { - "Override": "Sovrascrivi" - }, - "Override Border Size": { - "Override Border Size": "Sovrascrivi Spessore Bordo" - }, - "Override Corner Radius": { - "Override Corner Radius": "Sovrascrivi Raggio Angoli" - }, - "Override Gaps": { - "Override Gaps": "Sovrascrivi Spaziature" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Sovrascrivi le impostazioni di layout globali per questa uscita" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Sostituisci il terminale con un comando o script personalizzato" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "Sovrascrivi l'ombra globale con le impostazioni per ogni singola barra" - }, - "Overrides": { - "Overrides": "Sovrascritture" - }, - "Overview": { - "Overview": "Panoramica" - }, - "Overview of your network connections": { - "Overview of your network connections": "Panoramica delle tue connessioni di rete" - }, - "Overwrite": { - "Overwrite": "Sovrascrivi" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM fornisce già l'autenticazione tramite impronta digitale. Abilita questa opzione per mostrarla al login." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM fornisce già l'autenticazione tramite chiave di sicurezza. Abilita questa opzione per mostrarla al login." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM fornisce l'autenticazione tramite impronta digitale, ma la disponibilità non ha potuto essere confermata." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM fornisce l'autenticazione tramite impronta digitale, ma nessuna impronta è ancora registrata." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM fornisce l'autenticazione tramite impronta digitale, ma non è stato rilevato nessun lettore." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Centra" - }, - "Pad Hours": { - "Pad Hours": "Ore a Due Cifre" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "Ore a due cifre (02:00 vs 2:00)" - }, - "Padding": { - "Padding": "Spaziatura Interna" - }, - "Pair": { - "Pair": "Associa" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Associa Dispositivo Bluetooth" - }, - "Paired": { - "Paired": "Associato" - }, - "Pairing": { - "Pairing": "Associazione in corso" - }, - "Pairing failed": { - "Pairing failed": "Impossibile associare" - }, - "Pairing request from": { - "Pairing request from": "Richiesta di associazione da" - }, - "Pairing request sent": { - "Pairing request sent": "Richiesta di associazione inviata" - }, - "Pairing requested": { - "Pairing requested": "Associazione richiesta" - }, - "Pairing...": { - "Pairing...": "Associazione in corso..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Parzialmente Nuvoloso" - }, - "Passkey:": { - "Passkey:": "Passkey:" - }, - "Password": { - "Password": "Password" - }, - "Password...": { - "Password...": "Password..." - }, - "Paste": { - "Paste": "Incolla" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Percorso di un file video o di una cartella contenente video" - }, - "Pattern": { - "Pattern": "Pattern" - }, - "Pause": { - "Pause": "Pausa" - }, - "Paused": { - "Paused": "In Pausa" - }, - "Pending": { - "Pending": "In Attesa" - }, - "Pending Charge": { - "Pending Charge": "In Attesa di Carica" - }, - "Pending Discharge": { - "Pending Discharge": "In Attesa di Scarica" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Sfondi per Modalità" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Sfondi per Schermi" - }, - "Per-screen config": { - "Per-screen config": "Configurazione per schermo" - }, - "Percentage": { - "Percentage": "Percentuale" - }, - "Performance": { - "Performance": "Prestazioni" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Permesso negato per impostare l'immagine del profilo." - }, - "Personalization": { - "Personalization": "Personalizzazione" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect Non Disponibile" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Phone Connect non disponibile" - }, - "Phone number": { - "Phone number": "Numero di telefono" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Scegli un video casuale diverso ogni volta dalla stessa cartella" - }, - "Pictures": { - "Pictures": "Immagini" - }, - "Pin": { - "Pin": "Fissa" - }, - "Pin to Dock": { - "Pin to Dock": "Fissa sulla Dock" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping inviato" - }, - "Ping sent to": { - "Ping sent to": "Ping inviato a" - }, - "Pinned": { - "Pinned": "Fissato" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "App fissate e in esecuzione con trascinamento" - }, - "Pixelate": { - "Pixelate": "Mosaico" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Posiziona la cartella dei plugin qui. Ogni plugin dovrebbe avere un file manifesto plugin.json." - }, - "Place plugins in %1": { - "Place plugins in %1": "Inserisci i plugin in %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Riproduci un video quando lo schermo si blocca." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Riproduci suono quando arriva una nuova notifica" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Riproduci un suono al collegamento del cavo di alimentazione" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Riproduci suono quando il volume viene regolato" - }, - "Play sounds for system events": { - "Play sounds for system events": "Riproduci suoni per eventi di sistema" - }, - "Playback": { - "Playback": "Riproduzione" - }, - "Playback error: ": { - "Playback error: ": "Errore di riproduzione: " - }, - "Please wait...": { - "Please wait...": "Attendi..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Scrivi un nome per la nuova sessione %1" - }, - "Plugged In": { - "Plugged In": "Collegato" - }, - "Plugged in": { - "Plugged in": "Collegato all'alimentazione" - }, - "Plugin": { - "Plugin": "Plugin" - }, - "Plugin Directory": { - "Plugin Directory": "Cartella Plugin" - }, - "Plugin Management": { - "Plugin Management": "Gestione Plugin" - }, - "Plugin Visibility": { - "Plugin Visibility": "Visibilità Plugin" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Plugin disattivato - per usarlo, attivalo nelle impostazioni Plugin" - }, - "Plugins": { - "Plugins": "Plugin" - }, - "Pointer": { - "Pointer": "Puntatore" - }, - "Popout Shadows": { - "Popout Shadows": "Ombre dei Popup" - }, - "Popouts": { - "Popouts": "Pannelli a Comparsa" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Pannelli a comparsa e finestre modali seguono la Velocità Animazione globale (disabilita per personalizzare indipendentemente)" - }, - "Popup Only": { - "Popup Only": "Solo Popup" - }, - "Popup Position": { - "Popup Position": "Posizione Popup" - }, - "Popup Shadow": { - "Popup Shadow": "Ombra Popup" - }, - "Popup Transparency": { - "Popup Transparency": "Trasparenza Popup" - }, - "Popup behavior, position": { - "Popup behavior, position": "Comportamento e posizione dei popup" - }, - "Port": { - "Port": "Porta" - }, - "Portal": { - "Portal": "Vortice" - }, - "Position": { - "Position": "Posizione" - }, - "Position, pinned apps": { - "Position, pinned apps": "Posizione, app fissate" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Possibili Conflitti di Sovrascrittura" - }, - "Power": { - "Power": "Alimentazione" - }, - "Power & Security": { - "Power & Security": "Alimentazione e Sicurezza" - }, - "Power & Sleep": { - "Power & Sleep": "Alimentazione e Sospensione" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Conferma Azioni Alimentazione" - }, - "Power Menu Customization": { - "Power Menu Customization": "Personalizzazione Menu Alimentazione" - }, - "Power Off": { - "Power Off": "Spegni" - }, - "Power Options": { - "Power Options": "Opzioni Alimentazione" - }, - "Power Profile": { - "Power Profile": "Profilo Energetico" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Degrado Profilo Energetico" - }, - "Power Saver": { - "Power Saver": "Risparmio Energetico" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Spegni gli schermi al blocco" - }, - "Power profile management available": { - "Power profile management available": "Gestione dei profili energetici disponibile" - }, - "Power source": { - "Power source": "Sorgente di alimentazione" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Precompila l'ultimo nome utente corretto sul greeter" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "Preseleziona l'ultima sessione utilizzata sul greeter" - }, - "Precip": { - "Precip": "Precipitazioni" - }, - "Precipitation": { - "Precipitation": "Precipitazioni" - }, - "Precipitation Chance": { - "Precipitation Chance": "Probabilità di Precipitazioni" - }, - "Preference": { - "Preference": "Preferenza" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Larghezze Predefinite (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Premi \"n\" o fai clic su \"Nuova Sessione\" per crearne una" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Premi Invio e il sistema audio si riavvierà per applicare la modifica" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Premi Invio per incollare, Shift+Invio per copiare" - }, - "Press key...": { - "Press key...": "Premi un tasto..." - }, - "Pressure": { - "Pressure": "Pressione" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Disattiva sospensione schermo" - }, - "Preview": { - "Preview": "Anteprima" - }, - "Primary": { - "Primary": "Primario" - }, - "Primary Container": { - "Primary Container": "Contenitore Primario" - }, - "Print Server Management": { - "Print Server Management": "Gestione Server di Stampa" - }, - "Print Server not available": { - "Print Server not available": "Server di Stampa non disponibile" - }, - "Printer": { - "Printer": "Stampante" - }, - "Printer Classes": { - "Printer Classes": "Classi di Stampanti" - }, - "Printer created successfully": { - "Printer created successfully": "Stampante creata con successo" - }, - "Printer deleted": { - "Printer deleted": "Stampante eliminata" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nome stampante (senza spazi)" - }, - "Printer reachable": { - "Printer reachable": "Stampante raggiungibile" - }, - "Printers": { - "Printers": "Stampanti" - }, - "Printers: ": { - "Printers: ": "Stampanti: " - }, - "Prioritize performance": { - "Prioritize performance": "Dai priorità alle prestazioni" - }, - "Priority": { - "Priority": "Priorità" - }, - "Privacy Indicator": { - "Privacy Indicator": "Indicatore Privacy" - }, - "Privacy Mode": { - "Privacy Mode": "Modalità Privacy" - }, - "Private Key Password": { - "Private Key Password": "Password della Chiave Privata" - }, - "Process Count": { - "Process Count": "Numero di Processi" - }, - "Processes": { - "Processes": "Processi" - }, - "Processes:": { - "Processes:": "Processi:" - }, - "Processing": { - "Processing": "In Elaborazione" - }, - "Profile Image Error": { - "Profile Image Error": "Errore Immagine Profilo" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profilo attivato: %1" - }, - "Profile deleted": { - "Profile deleted": "Profilo eliminato" - }, - "Profile error": { - "Profile error": "Errore profilo" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Immagine profilo troppo grande. Per favore usa un'immagine più piccola." - }, - "Profile name": { - "Profile name": "Nome profilo" - }, - "Profile not found": { - "Profile not found": "Profilo non trovato" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profilo salvato: %1" - }, - "Protocol": { - "Protocol": "Protocollo" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia non è disponibile" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia non è disponibile - il salvaschermo video richiede i servizi multimediali qt" - }, - "Quick Access": { - "Quick Access": "Accesso Rapido" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Accesso veloce al launcher applicazioni" - }, - "Quick access to color picker": { - "Quick access to color picker": "Accesso veloce al selettore colore" - }, - "Quick access to notepad": { - "Quick access to notepad": "Accesso veloce al blocco note" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Pannello scorrevole per la presa veloce di appunti" - }, - "Quick system toggles": { - "Quick system toggles": "Comandi rapidi di sistema" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Raggio" - }, - "Rain": { - "Rain": "Pioggia" - }, - "Rain Chance": { - "Rain Chance": "Prob. Pioggia" - }, - "Rainbow": { - "Rainbow": "Arcobaleno" - }, - "Random": { - "Random": "Casuale" - }, - "Rate": { - "Rate": "Velocità" - }, - "Read:": { - "Read:": "Lettura:" - }, - "Reason": { - "Reason": "Motivo" - }, - "Reboot": { - "Reboot": "Riavvia" - }, - "Recent Colors": { - "Recent Colors": "Colori Recenti" - }, - "Recently Used Apps": { - "Recently Used Apps": "App Usate Recentemente" - }, - "Recommended available": { - "Recommended available": "Opzione consigliata disponibile" - }, - "Refresh": { - "Refresh": "Aggiorna" - }, - "Refresh Weather": { - "Refresh Weather": "Aggiorna Meteo" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Rifiuta" - }, - "Reject Jobs": { - "Reject Jobs": "Rifiuta Stampe" - }, - "Release": { - "Release": "Rilascio" - }, - "Reload Plugin": { - "Reload Plugin": "Ricarica Plugin" - }, - "Remaining": { - "Remaining": "Rimanente" - }, - "Remaining / Total": { - "Remaining / Total": "Rimanente/Totale" - }, - "Remember Last Query": { - "Remember Last Query": "Ricorda l'Ultima Ricerca" - }, - "Remember last session": { - "Remember last session": "Ricorda l'ultima sessione" - }, - "Remember last user": { - "Remember last user": "Ricorda l'ultimo utente" - }, - "Remove": { - "Remove": "Rimuovi" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Rimuovi Spaziatura Widget" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Rimuovi spazi e bordo quando le finestre sono massimizzate" - }, - "Rename": { - "Rename": "Rinomina" - }, - "Rename Session": { - "Rename Session": "Rinomina Sessione" - }, - "Rename Workspace": { - "Rename Workspace": "Rinomina Spazio di Lavoro" - }, - "Repeat": { - "Repeat": "Ripeti" - }, - "Replacement": { - "Replacement": "Sostituzione" - }, - "Report": { - "Report": "Riepilogo" - }, - "Request Pairing": { - "Request Pairing": "Richiedi Associazione" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Richiede di tenere premuto il pulsante/tasto per confermare lo spegnimento, il riavvio, la sospensione, l'ibernazione e il termina sessione" - }, - "Required plugin: ": { - "Required plugin: ": "Plugin richiesto: " - }, - "Requires %1": { - "Requires %1": "Richiede %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Richiede lo strumento \"dgop\"" - }, - "Requires DMS %1": { - "Requires DMS %1": "Richiede DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Richiede compositor DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "Richiede una versione più recente di Quickshell" - }, - "Requires night mode support": { - "Requires night mode support": "Richiede il supporto alla modalità notturna" - }, - "Reset": { - "Reset": "Reimposta" - }, - "Reset Position": { - "Reset Position": "Reimposta Posizione" - }, - "Reset Size": { - "Reset Size": "Reimposta Dimensioni" - }, - "Reset to default name": { - "Reset to default name": "Ripristina nome predefinito" - }, - "Resize Widget": { - "Resize Widget": "Ridimensiona Widget" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Risoluzione e Frequenza di Aggiornamento" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Risoluzione, posizione, ridimensionamento" - }, - "Restart DMS": { - "Restart DMS": "Riavvia DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Riavvia la DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Riavvio del sistema audio in corso..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "Ripristina Finestre dello Spazio di Lavoro Speciale" - }, - "Resume": { - "Resume": "Riprendi" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Inverti Direzione Scorrimento" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Inverti direzione cambio spazio di lavoro quando si scorre sulla barra" - }, - "Revert": { - "Revert": "Ripristina" - }, - "Right": { - "Right": "Destra" - }, - "Right Center": { - "Right Center": "Al Centro a Destra" - }, - "Right Section": { - "Right Section": "Sezione Destra" - }, - "Right Tiling": { - "Right Tiling": "Tiling Destro" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Fai clic con il tasto destro e trascina in qualsiasi punto del widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Fai clic con il tasto destro e trascina l’angolo in basso a destra" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Fai clic destro sulla barra per alternare" - }, - "Ring": { - "Ring": "Fai squillare" - }, - "Ringing": { - "Ringing": "Squillo in corso" - }, - "Ripple Effects": { - "Ripple Effects": "Effetti Onda" - }, - "Root Filesystem": { - "Root Filesystem": "Filesystem Root" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Angoli arrotondati per le finestre" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Angoli arrotondati per le finestre (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Angoli arrotondati per le finestre (decoration.rounding)" - }, - "Rule": { - "Rule": "Regola" - }, - "Rule Name": { - "Rule Name": "Nome Regola" - }, - "Rules (%1)": { - "Rules (%1)": "Regole (%1)" - }, - "Run Again": { - "Run Again": "Esegui di Nuovo" - }, - "Run DMS Templates": { - "Run DMS Templates": "Esegui Template DMS" - }, - "Run User Templates": { - "Run User Templates": "Esegui Template Utente" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Esegui un programma (es. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Esegui un comando shell (es. notify-send)" - }, - "Running Apps": { - "Running Apps": "App in Esecuzione" - }, - "Running Apps Settings": { - "Running Apps Settings": "Impostazioni App in Esecuzione" - }, - "Running greeter sync…": { - "Running greeter sync…": "Sincronizzazione del greeter in corso…" - }, - "SDR Brightness": { - "SDR Brightness": "Luminosità SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Saturazione SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Salva" - }, - "Save Notepad File": { - "Save Notepad File": "Salva File Blocco Note" - }, - "Save QR Code": { - "Save QR Code": "Salva Codice QR" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Salva e passa tra le configurazioni dello schermo" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Salva nella cronologia le notifiche a priorità critica" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Salva nella cronologia le notifiche ignorate" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Salva nella cronologia le notifiche a bassa priorità" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Salva nella cronologia le notifiche a priorità normale" - }, - "Save password": { - "Save password": "Salva password" - }, - "Saved": { - "Saved": "Salvato" - }, - "Saved Configurations": { - "Saved Configurations": "Configurazioni Salvate" - }, - "Saved Note": { - "Saved Note": "Nota Salvata" - }, - "Saved item deleted": { - "Saved item deleted": "Elemento salvato eliminato" - }, - "Saving...": { - "Saving...": "Salvataggio..." - }, - "Scale": { - "Scale": "Scala" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Scala le dimensioni dei font della DankBar in modo indipendente" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "Scala dimensioni icone DankBar indipendentemente" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Ridimensiona tutte le dimensioni dei caratteri nell'intera shell" - }, - "Scan": { - "Scan": "Scansiona" - }, - "Scanning": { - "Scanning": "Scansione" - }, - "Scanning...": { - "Scanning...": "Scansione..." - }, - "Science": { - "Science": "Scienza" - }, - "Score": { - "Score": "Punteggio" - }, - "Screen Sharing": { - "Screen Sharing": "Condivisione Schermo" - }, - "Screen sharing": { - "Screen sharing": "Condivisione schermo" - }, - "Scroll": { - "Scroll": "Scorrimento" - }, - "Scroll Factor": { - "Scroll Factor": "Fattore di Scorrimento" - }, - "Scroll GitHub": { - "Scroll GitHub": "GitHub di Scroll" - }, - "Scroll Wheel": { - "Scroll Wheel": "Rotella di Scorrimento" - }, - "Scroll song title": { - "Scroll song title": "Scorri titolo del brano" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Scorri il titolo se non entra nel widget" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Comportamento della rotellina del mouse nel widget multimediale" - }, - "Scrolling": { - "Scrolling": "Scorrimento" - }, - "Search App Actions": { - "Search App Actions": "Cerca Azioni App" - }, - "Search Options": { - "Search Options": "Opzioni di Ricerca" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Cerca per combinazione di tasti, descrizione o nome azione.\n\nL'azione predefinita copia la scorciatoia negli appunti.\nFai clic destro o Freccia Destra per fissare le scorciatoie frequenti - appariranno in cima quando non si cerca." - }, - "Search for a location...": { - "Search for a location...": "Cerca una posizione..." - }, - "Search keybinds...": { - "Search keybinds...": "Cerca scorciatoie..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Cerca scorciatoie da tastiera dal tuo compositor e applicazioni" - }, - "Search plugins...": { - "Search plugins...": "Cerca plugin..." - }, - "Search processes...": { - "Search processes...": "Cerca processi..." - }, - "Search sessions...": { - "Search sessions...": "Cerca sessioni..." - }, - "Search themes...": { - "Search themes...": "Cerca temi..." - }, - "Search widgets...": { - "Search widgets...": "Cerca widget..." - }, - "Search...": { - "Search...": "Cerca..." - }, - "Searching...": { - "Searching...": "Ricerca in corso..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Secondo Fattore (AND)" - }, - "Secondary": { - "Secondary": "Secondario" - }, - "Secured": { - "Secured": "Protetto" - }, - "Security": { - "Security": "Sicurezza" - }, - "Security & privacy": { - "Security & privacy": "Sicurezza e privacy" - }, - "Security key mode": { - "Security key mode": "Modalità chiave di sicurezza" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "La disponibilità della chiave di sicurezza non ha potuto essere confermata." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Il supporto per chiavi di sicurezza è stato rilevato, ma nessuna chiave registrata è ancora stata trovata. Puoi abilitarlo ora e registrarne una in seguito." - }, - "Select": { - "Select": "Seleziona" - }, - "Select Application": { - "Select Application": "Seleziona Applicazione" - }, - "Select Bar": { - "Select Bar": "Seleziona Barra" - }, - "Select Custom Theme": { - "Select Custom Theme": "Seleziona Tema Personalizzato" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Seleziona Logo Launcher della Dock" - }, - "Select File to Send": { - "Select File to Send": "Seleziona File da Inviare" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Seleziona Logo Launcher" - }, - "Select Profile Image": { - "Select Profile Image": "Seleziona Immagine Profilo" - }, - "Select Video or Folder": { - "Select Video or Folder": "Seleziona Video o Cartella" - }, - "Select Wallpaper": { - "Select Wallpaper": "Seleziona Sfondo" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Seleziona Cartella Sfondo" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Seleziona un colore dalla tavolozza o usa lo slider di personalizzazione" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Seleziona un widget da aggiungere al tuo desktop. Ogni widget è un'istanza separata con le proprie impostazioni." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Seleziona un widget da aggiungere. Se necessario, puoi aggiungere più istanze dello stesso widget." - }, - "Select a window...": { - "Select a window...": "Seleziona una finestra..." - }, - "Select an image file...": { - "Select an image file...": "Seleziona un'immagine..." - }, - "Select at least one provider": { - "Select at least one provider": "Seleziona almeno un fornitore" - }, - "Select device": { - "Select device": "Seleziona dispositivo" - }, - "Select device...": { - "Select device...": "Seleziona un dispositivo..." - }, - "Select driver...": { - "Select driver...": "Seleziona un driver..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Seleziona lo spessore del font per il testo dell'interfaccia utente" - }, - "Select greeter background image": { - "Select greeter background image": "Seleziona l'immagine di sfondo del greeter" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Seleziona lo schermo per configurare lo sfondo" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Seleziona font a larghezza fissa per lista processi e visualizzazioni tecniche" - }, - "Select network": { - "Select network": "Seleziona rete" - }, - "Select system sound theme": { - "Select system sound theme": "Seleziona tema suoni di sistema" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Seleziona la famiglia di font per il testo dell'interfaccia utente" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Seleziona l'algoritmo della tavolozza usato per i colori basati sullo sfondo" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Seleziona quali fornitori di scorciatoie includere" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Seleziona quali transizioni includere nella randomizzazione" - }, - "Select...": { - "Select...": "Seleziona..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Immagine selezionata non trovata." - }, - "Send": { - "Send": "Invia" - }, - "Send Clipboard": { - "Send Clipboard": "Invia Appunti" - }, - "Send File": { - "Send File": "Invia File" - }, - "Send SMS": { - "Send SMS": "Invia SMS" - }, - "Sending": { - "Sending": "Invio in Corso" - }, - "Separator": { - "Separator": "Separatore" - }, - "Server": { - "Server": "Server" - }, - "Session Filter": { - "Session Filter": "Filtro Sessioni" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Imposta Nome Dispositivo Personalizzato" - }, - "Set custom name": { - "Set custom name": "Imposta nome personalizzato" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Imposta nomi personalizzati per i tuoi dispositivi di input" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Imposta nomi personalizzati per i tuoi dispositivi di output" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Imposta sfondi differenti per ogni schermo connesso" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Imposta sfondi differenti per modalità chiara e scura" - }, - "Set key and action to save": { - "Set key and action to save": "Imposta tasto e azione per salvare" - }, - "Set notification rules": { - "Set notification rules": "Imposta regole di notifica" - }, - "Settings": { - "Settings": "Impostazioni" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Le impostazioni sono in sola lettura. Le modifiche non verranno salvate." - }, - "Setup": { - "Setup": "Configurazione" - }, - "Shadow Color": { - "Shadow Color": "Colore Ombra" - }, - "Shadow Intensity": { - "Shadow Intensity": "Intensità dell'Ombra" - }, - "Shadow Opacity": { - "Shadow Opacity": "Opacità dell'Ombra" - }, - "Shadow Override": { - "Shadow Override": "Sovrascrittura Ombra" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Ombra in rilievo su barre e pannelli" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Ombra in rilievo su modali e finestre di dialogo" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "Ombra in rilievo su popup, OSD e menu a discesa" - }, - "Shadows": { - "Shadows": "Ombre" - }, - "Share": { - "Share": "Condividi" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Condividi Impostazioni Controllo Gamma" - }, - "Share Text": { - "Share Text": "Condividi Testo" - }, - "Share URL": { - "Share URL": "Condividi URL" - }, - "Shared": { - "Shared": "Condiviso" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Canc: Cancella Tutto • Esc: Chiudi" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Invio per incollare" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Invio: Copia • Shift+Canc: Cancella Tutto • Esc: Chiudi" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Invio: Incolla • Shift+Canc: Cancella Tutto • Esc: Chiudi" - }, - "Short": { - "Short": "Breve" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Scorciatoia (%1)" - }, - "Shortcuts": { - "Shortcuts": "Scorciatoie" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Scorciatoie (%1)" - }, - "Show": { - "Show": "Mostra" - }, - "Show 3rd Party": { - "Show 3rd Party": "Mostra Terze Parti" - }, - "Show All Tags": { - "Show All Tags": "Mostra Tutti i Tag" - }, - "Show Badge": { - "Show Badge": "Mostra Badge" - }, - "Show CPU": { - "Show CPU": "Mostra CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Mostra Grafico CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Mostra Temperatura CPU" - }, - "Show Date": { - "Show Date": "Mostra Data" - }, - "Show Disk": { - "Show Disk": "Mostra Disco" - }, - "Show Dock": { - "Show Dock": "Mostra la Dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Mostra Temperatura Percepita" - }, - "Show Footer": { - "Show Footer": "Mostra Piè di Pagina" - }, - "Show Forecast": { - "Show Forecast": "Mostra Previsioni" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Mostra Temperatura GPU" - }, - "Show Header": { - "Show Header": "Mostra Intestazione" - }, - "Show Hibernate": { - "Show Hibernate": "Mostra Ibernazione" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Mostra Numeri Ore" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Mostra Previsioni Orarie" - }, - "Show Humidity": { - "Show Humidity": "Mostra Umidità" - }, - "Show Launcher Button": { - "Show Launcher Button": "Mostra Pulsante Launcher" - }, - "Show Line Numbers": { - "Show Line Numbers": "Mostra Numero Righe" - }, - "Show Location": { - "Show Location": "Mostra Posizione" - }, - "Show Lock": { - "Show Lock": "Mostra Blocco" - }, - "Show Log Out": { - "Show Log Out": "Mostra Termina Sessione" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Mostra animazioni onda Material Design sugli elementi interattivi" - }, - "Show Media Player": { - "Show Media Player": "Mostra Lettore Multimediale" - }, - "Show Memory": { - "Show Memory": "Mostra Memoria" - }, - "Show Memory Graph": { - "Show Memory Graph": "Mostra Grafico Memoria" - }, - "Show Memory in GB": { - "Show Memory in GB": "Mostra la Memoria in GB" - }, - "Show Network": { - "Show Network": "Mostra Rete" - }, - "Show Network Graph": { - "Show Network Graph": "Mostra Grafico Rete" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Mostra Solo Spazi di Lavoro Occupati" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Mostra Conteggio Badge Overflow" - }, - "Show Password Field": { - "Show Password Field": "Mostra Campo Password" - }, - "Show Power Actions": { - "Show Power Actions": "Mostra Azioni Alimentazione" - }, - "Show Power Off": { - "Show Power Off": "Mostra Spegni" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Mostra Probabilità di Precipitazioni" - }, - "Show Pressure": { - "Show Pressure": "Mostra Pressione" - }, - "Show Profile Image": { - "Show Profile Image": "Mostra Immagine Profilo" - }, - "Show Reboot": { - "Show Reboot": "Mostra Riavvio" - }, - "Show Restart DMS": { - "Show Restart DMS": "Mostra Riavvia DMS" - }, - "Show Saved Items": { - "Show Saved Items": "Mostra Elementi Salvati" - }, - "Show Seconds": { - "Show Seconds": "Mostra Secondi" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Mostra Alba/Tramonto" - }, - "Show Suspend": { - "Show Suspend": "Mostra Sospensione" - }, - "Show Swap": { - "Show Swap": "Mostra Swap" - }, - "Show System Date": { - "Show System Date": "Mostra Data di Sistema" - }, - "Show System Icons": { - "Show System Icons": "Mostra Icone di Sistema" - }, - "Show System Time": { - "Show System Time": "Mostra Ora di Sistema" - }, - "Show Top Processes": { - "Show Top Processes": "Mostra Processi Principali" - }, - "Show Weather Condition": { - "Show Weather Condition": "Mostra Condizioni Meteo" - }, - "Show Week Number": { - "Show Week Number": "Mostra Numero della Settimana" - }, - "Show Welcome": { - "Show Welcome": "Mostra Benvenuto" - }, - "Show Wind Speed": { - "Show Wind Speed": "Mostra Velocità del Vento" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Mostra App negli Spazi di Lavoro" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Mostra tutti i 9 tag invece di quelli occupati (solo DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Mostra un bordo attorno all’indicatore dello spazio di lavoro attivo" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Mostra il visualizzatore audio cava nel widget multimediale" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Mostra la sovrapposizione oscurata dietro le finestre di dialogo modali" - }, - "Show device": { - "Show device": "Mostra dispositivo" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Mostra la dock quando le finestre fluttuanti non ne sovrappongono l’area" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "Mostra ombra esterna sui popup di notifica. Richiede che M3 Elevation sia attivato in Tema e Colori." - }, - "Show in GB": { - "Show in GB": "Mostra in GB" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Mostra la sovrapposizione del launcher durante la digitazione nella panoramica di Niri. Disabilita per usare un altro launcher." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Mostra schede modalità e suggerimenti tastiera in basso." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "Mostra i popup delle notifiche solo sullo schermo attualmente attivo" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "Mostra le notifiche solo sullo schermo attualmente attivo" - }, - "Show on Last Display": { - "Show on Last Display": "Mostra sull'Ultimo Schermo" - }, - "Show on Overlay": { - "Show on Overlay": "Mostra in Sovraimpressione" - }, - "Show on Overview": { - "Show on Overview": "Mostra in Panoramica" - }, - "Show on Overview Only": { - "Show on Overview Only": "Mostra Solo nella Panoramica" - }, - "Show on all connected displays": { - "Show on all connected displays": "Mostra su tutti gli schermi connessi" - }, - "Show on screens:": { - "Show on screens:": "Mostra sugli schermi:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Mostra indicatore a schermo quando la luminosità cambia" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Mostra indicatore a schermo quando lo stato del blocco maiuscole cambia" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Mostra indicatore a schermo quando si scorre tra i dispositivi di uscita audio" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Mostra indicatore a schermo quando cambia lo stato del blocco sospensione" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Mostra indicatore a schermo quando cambia lo stato del lettore multimediale" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Mostra indicatore a schermo quando cambia il volume del lettore multimediale" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Mostra indicatore a schermo quando il microfono è attivato/disattivato" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Mostra indicatore a schermo quando il profilo di alimentazione cambia" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Mostra indicatore a schermo quando il volume cambia" - }, - "Show seconds": { - "Show seconds": "Mostra secondi" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Mostra informazioni meteo nella barra superiore e nel centro di controllo" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Mostra il numero della settimana nel calendario" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Mostra i numeri d'indice degli spazi di lavoro nello switcher degli spazi di lavoro nella barra superiore" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Mostra il nome dello spazio di lavoro nelle barre orizzontali e la prima lettera in quelle verticali" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Mostra gli spazi di lavoro dello schermo attualmente attivo" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Mostra tutte le applicazioni in esecuzione con indicazione focus" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Visualizza lo spazio di lavoro attuale e consente di passare ad un altro" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Mostra quando il blocco maiuscole è attivo" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Mostra quando microfono, videocamera, o condivisione schermo sono attivi" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Spegni" - }, - "Signal": { - "Signal": "Segnale" - }, - "Signal:": { - "Signal:": "Segnale:" - }, - "Size": { - "Size": "Dimensione" - }, - "Size Constraints": { - "Size Constraints": "Vincoli Dimensione" - }, - "Size Offset": { - "Size Offset": "Offset Dimensione" - }, - "Sizing": { - "Sizing": "Dimensionamento" - }, - "Skip": { - "Skip": "Salta" - }, - "Skip confirmation": { - "Skip confirmation": "Salta Conferma" - }, - "Skip setup": { - "Skip setup": "Salta configurazione" - }, - "Small": { - "Small": "Piccolo" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Autenticazione Tramite Smart Card" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN della Smart Card" - }, - "Snap": { - "Snap": "Aggancia" - }, - "Snow": { - "Snow": "Neve" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Alcuni plugin richiedono una versione più recente di DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Ordina Alfabeticamente" - }, - "Sort By": { - "Sort By": "Ordina Per" - }, - "Sorting & Layout": { - "Sorting & Layout": "Ordinamento e Layout" - }, - "Sound Theme": { - "Sound Theme": "Tema Suoni" - }, - "Sounds": { - "Sounds": "Suoni" - }, - "Space between windows": { - "Space between windows": "Spazio tra le finestre" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Spazio tra le finestre (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Spazio tra le finestre (gaps_in e gaps_out)" - }, - "Spacer": { - "Spacer": "Distanziatore" - }, - "Spacing": { - "Spacing": "Spaziatura" - }, - "Speaker settings": { - "Speaker settings": "Impostazioni altoparlanti" - }, - "Speed": { - "Speed": "Velocità" - }, - "Spool Area Full": { - "Spool Area Full": "Area Spool Piena" - }, - "Square Corners": { - "Square Corners": "Angoli Squadrati" - }, - "Stacked": { - "Stacked": "Impilato" - }, - "Standard": { - "Standard": "Standard" - }, - "Start": { - "Start": "Avvia" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Avvia KDE Connect o Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Avvia KDE Connect o Valent per usare questo plugin" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Inizia a scrivere i tuoi appunti qui..." - }, - "State": { - "State": "Stato" - }, - "Status": { - "Status": "Stato" - }, - "Stopped": { - "Stopped": "Arrestato" - }, - "Stopped Partly": { - "Stopped Partly": "Parzialmente Arrestato" - }, - "Stopping": { - "Stopping": "In Arresto" - }, - "Stretch": { - "Stretch": "Estendi" - }, - "Stripes": { - "Stripes": "Strisce" - }, - "Summary": { - "Summary": "Riassunto" - }, - "Sunrise": { - "Sunrise": "Alba" - }, - "Sunset": { - "Sunset": "Tramonto" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Sopprimi i popup di notifica quando attivato" - }, - "Surface": { - "Surface": "Superficie" - }, - "Surface Variant": { - "Surface Variant": "Variante Superficie" - }, - "Suspend": { - "Suspend": "Sospendi" - }, - "Suspend behavior": { - "Suspend behavior": "Comportamento Sospensione" - }, - "Suspend system after": { - "Suspend system after": "Sospendi sistema dopo" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Sospendi e poi Iberna" - }, - "Sway Website": { - "Sway Website": "Sito Web di Sway" - }, - "Switch User": { - "Switch User": "Cambia Utente" - }, - "Switch to power profile": { - "Switch to power profile": "Passa al profilo energetico" - }, - "Sync": { - "Sync": "Sincronizza" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Modalità Sincronizzazione con il Portale" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Sincronizza Pannelli a Comparsa e Modali" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Sincronizza la Posizione tra gli Schermi" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Sincronizzazione completata con successo." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Sincronizza la modalità scura con i portali di sistema per i suggerimenti sul tema globale" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "Sincronizzazione fallita in modalità background. Avvio la modalità terminale per consentirti l'autenticazione interattiva." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "La sincronizzazione richiede l'autenticazione sudo. Apertura del terminale per poter usare password o impronta digitale." - }, - "System": { - "System": "Sistema" - }, - "System App Theming": { - "System App Theming": "Theming App Sistema" - }, - "System Check": { - "System Check": "Controllo di Sistema" - }, - "System Default": { - "System Default": "Predefinito di Sistema" - }, - "System Information": { - "System Information": "Informazioni di Sistema" - }, - "System Monitor": { - "System Monitor": "Monitor di Sistema" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Monitor di Sistema non Disponibile" - }, - "System Sounds": { - "System Sounds": "Suoni di Sistema" - }, - "System Tray": { - "System Tray": "Area di Notifica" - }, - "System Update": { - "System Update": "Aggiornamento di Sistema" - }, - "System Updater": { - "System Updater": "Gestore Aggiornamenti di Sistema" - }, - "System Updates": { - "System Updates": "Aggiornamenti di Sistema" - }, - "System notification area icons": { - "System notification area icons": "Icone area notifiche di sistema" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "I suoni di sistema non sono disponibili. Installa %1 per il supporto audio." - }, - "System theme toggle": { - "System theme toggle": "Interruttore tema di sistema" - }, - "System toast notifications": { - "System toast notifications": "Notifiche a comparsa di sistema" - }, - "System update custom command": { - "System update custom command": "Comando personalizzato aggiornamento sistema" - }, - "Tab": { - "Tab": "Scheda" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nav • ←→↑↓: Nav Griglia • Invio/Spazio: Seleziona" - }, - "Terminal": { - "Terminal": "Terminale" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Parametri aggiuntivi personalizzati terminale" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "Terminale di ripiego non riuscito. Installa un emulatore di terminale supportato o esegui 'dms auth sync' manualmente." - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "Terminale di ripiego fallito. Installa uno degli emulatori di terminale supportati o esegui \"dms greeter sync\" manualmente." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "Terminale di ripiego aperto. Completa la configurazione dell'autenticazione lì; si chiuderà automaticamente al termine." - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "Terminale di ripiego aperto. Completa la sincronizzazione lì; si chiuderà automaticamente al termine." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "Backend multiplexer del terminale da usare" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "Terminale aperto. Completa la configurazione dell'autenticazione lì; si chiuderà automaticamente al termine." - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "Terminale aperto. Completa l'autenticazione per la sincronizzazione lì; si chiuderà automaticamente al termine." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminali - Usa Sempre Tema Scuro" - }, - "Test Connection": { - "Test Connection": "Testa Connessione" - }, - "Test Page": { - "Test Page": "Pagina di Prova" - }, - "Test page sent to printer": { - "Test page sent to printer": "Pagina di prova inviata alla stampante" - }, - "Testing...": { - "Testing...": "Test in corso..." - }, - "Text": { - "Text": "Testo" - }, - "Text Color": { - "Text Color": "Colore Testo" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "Lo strumento \"dgop\" è necessario per il monitoraggio del sistema.\nInstalla dgop per utilizzare questa funzionalità." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "La variabile d'ambiente DMS_SOCKET non è impostata o il socket non è disponibile. La gestione automatica dei plugin richiede il DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Le seguenti impostazioni modificheranno le tue impostazioni GTK e Qt. Se vuoi preservare la tua configurazione attuale, per favore fai il backup (qt5ct.conf|qt6ct.conf e ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "Il comando personalizzato usato per agganciarsi alle sessioni (riceve il nome della sessione come primo argomento)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "La coda delle stampe della stampante è vuota" - }, - "Theme & Colors": { - "Theme & Colors": "Tema e Colori" - }, - "Theme Color": { - "Theme Color": "Colore Tema" - }, - "Theme Registry": { - "Theme Registry": "Registro dei Temi" - }, - "Themes": { - "Themes": "Temi" - }, - "Thickness": { - "Thickness": "Spessore" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Avviso Plugin di Terze Parti" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "I plugin di terze parti sono creati dalla community e non sono ufficialmente supportati da DankMaterialShell.\n\nQuesti plugin possono comportare rischi per la sicurezza e la privacy - l'installazione è a proprio rischio." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Questa scorciatoia è stata sovrascritta da config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "L'operazione potrebbe richiedere alcuni secondi" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Questo plugin non ha il permesso \"settings_write\".\n\nAggiungi \"permissions\": [\"settings_read\", \"settings_write\"] al plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Questo widget impedisce gli stati di spegnimento della GPU, che possono influire in modo significativo sulla durata della batteria sui laptop. Non è consigliabile utilizzarlo su laptop con grafica ibrida." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Questo eliminerà tutte le voci non fissate. %1 voci fissate verranno mantenute." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "La cronologia degli appunti verrà cancellata definitivamente." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Questo rimuoverà definitivamente questo elemento degli appunti salvato. Questa azione non può essere annullata." - }, - "Thunderstorm": { - "Thunderstorm": "Temporale" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Temporale con Grandine" - }, - "Tile": { - "Tile": "Affianca" - }, - "Tile H": { - "Tile H": "Affianca Orizz." - }, - "Tile V": { - "Tile V": "Affianca Vert." - }, - "Tiled": { - "Tiled": "Affiancato" - }, - "Tiled State": { - "Tiled State": "Stato Affiancato" - }, - "Tiling": { - "Tiling": "Tiling" - }, - "Time": { - "Time": "Tempo" - }, - "Time & Date Locale": { - "Time & Date Locale": "Lingua di Data e Ora" - }, - "Time & Weather": { - "Time & Weather": "Orario e Meteo" - }, - "Time Format": { - "Time Format": "Formato Ora" - }, - "Time format": { - "Time format": "Formato ora" - }, - "Time remaining: %1": { - "Time remaining: %1": "Tempo rimanente: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Tempo alla carica completa: %1" - }, - "Timed Out": { - "Timed Out": "Scaduto" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Timeout per le notifiche di priorità critica" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Timeout per le notifiche di bassa priorità" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Timeout per le notifiche di priorità normale" - }, - "Title": { - "Title": "Titolo" - }, - "Title regex (optional)": { - "Title regex (optional)": "Regex titolo (opzionale)" - }, - "To Full": { - "To Full": "Alla Carica Completa" - }, - "To update, run the following command:": { - "To update, run the following command:": "Per aggiornare, esegui il seguente comando:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Per utilizzare questa scorciatoia DMS, rimuovi o modifica la scorciatoia nel tuo config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Messaggi a Comparsa" - }, - "Today": { - "Today": "Oggi" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Attiva/Disattiva questa configurazione della barra" - }, - "Toggling...": { - "Toggling...": "Attivazione/Disattivazione in corso..." - }, - "Tomorrow": { - "Tomorrow": "Domani" - }, - "Tonal Spot": { - "Tonal Spot": "Punto Tonale" - }, - "Toner Empty": { - "Toner Empty": "Toner Vuoto" - }, - "Toner Low": { - "Toner Low": "Toner in Esaurimento" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "Troppi tentativi - accesso bloccato" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "Troppi tentativi falliti - l'account potrebbe essere bloccato" - }, - "Tools": { - "Tools": "Strumenti" - }, - "Top": { - "Top": "In Alto" - }, - "Top (Default)": { - "Top (Default)": "In Alto (Predefinito)" - }, - "Top Bar Format": { - "Top Bar Format": "Formato Barra Superiore" - }, - "Top Center": { - "Top Center": "In Alto al Centro" - }, - "Top Left": { - "Top Left": "In Alto a Sinistra" - }, - "Top Processes": { - "Top Processes": "Processi Principali" - }, - "Top Right": { - "Top Right": "In Alto a Destra" - }, - "Top Section": { - "Top Section": "Sezione Superiore" - }, - "Total": { - "Total": "Totale" - }, - "Total Jobs": { - "Total Jobs": "Stampe Totali" - }, - "Touch your security key...": { - "Touch your security key...": "Tocca la tua chiave di sicurezza..." - }, - "Transform": { - "Transform": "Trasforma" - }, - "Transition Effect": { - "Transition Effect": "Effetto Transizione" - }, - "Transparency": { - "Transparency": "Trasparenza" - }, - "Trending GIFs": { - "Trending GIFs": "GIF di Tendenza" - }, - "Trending Stickers": { - "Trending Stickers": "Sticker di Tendenza" - }, - "Trigger": { - "Trigger": "Attivatore" - }, - "Trigger Prefix": { - "Trigger Prefix": "Prefisso Attivatore" - }, - "Trigger: %1": { - "Trigger: %1": "Attivatore: %1" - }, - "Trust": { - "Trust": "Fidati" - }, - "Try a different search": { - "Try a different search": "Prova una ricerca diversa" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Spegni immediatamente tutti gli schermi quando si attiva la schermata di blocco" - }, - "Turn off monitors after": { - "Turn off monitors after": "Spegni schermi dopo" - }, - "Type": { - "Type": "Tipo" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Digita almeno 2 caratteri" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Digita questo prefisso per cercare scorciatoie" - }, - "Type to search files": { - "Type to search files": "Scrivi per cercare file" - }, - "Typography": { - "Typography": "Tipografia" - }, - "Typography & Motion": { - "Typography & Motion": "Tipografia e Animazioni" - }, - "Unavailable": { - "Unavailable": "Non disponibile" - }, - "Unfocused Color": { - "Unfocused Color": "Colore Inattivo" - }, - "Ungrouped": { - "Ungrouped": "Non Raggruppato" - }, - "Uninstall": { - "Uninstall": "Disinstalla" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Disinstalla Greeter" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Disinstalla Plugin" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Disinstallazione completata. Il Greeter è stato rimosso." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Disinstallazione fallita: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "Disinstallare il greeter DMS? Questo rimuoverà la configurazione e ripristinerà il tuo display manager precedente. Si aprirà un terminale per l'autenticazione sudo." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Disinstallato: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Disinstallando: %1" - }, - "Unknown": { - "Unknown": "Sconosciuto" - }, - "Unknown App": { - "Unknown App": "App Sconosciuta" - }, - "Unknown Artist": { - "Unknown Artist": "Artista Sconosciuto" - }, - "Unknown Config": { - "Unknown Config": "Configurazione Sconosciuta" - }, - "Unknown Device": { - "Unknown Device": "Dispositivo Sconosciuto" - }, - "Unknown GPU": { - "Unknown GPU": "GPU Sconosciuta" - }, - "Unknown Monitor": { - "Unknown Monitor": "Schermo Sconosciuto" - }, - "Unknown Network": { - "Unknown Network": "Rete Sconosciuta" - }, - "Unknown Title": { - "Unknown Title": "Titolo Sconosciuto" - }, - "Unknown Track": { - "Unknown Track": "Traccia Sconosciuta" - }, - "Unload on Close": { - "Unload on Close": "Scarica alla Chiusura" - }, - "Unmute": { - "Unmute": "Riattiva" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Riattiva popup per %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Regola Senza Nome" - }, - "Unpair": { - "Unpair": "Dissocia" - }, - "Unpair failed": { - "Unpair failed": "Impossibile dissociare" - }, - "Unpin": { - "Unpin": "Rimuovi" - }, - "Unpin from Dock": { - "Unpin from Dock": "Rimuovi dalla Dock" - }, - "Unsaved Changes": { - "Unsaved Changes": "Modifiche Non Salvate" - }, - "Unsaved changes": { - "Unsaved changes": "Modifiche non salvate" - }, - "Unsaved note...": { - "Unsaved note...": "Nota non salvata..." - }, - "Untitled": { - "Untitled": "Senza Titolo" - }, - "Untrust": { - "Untrust": "Non Fidarti" - }, - "Up to date": { - "Up to date": "Aggiornato" - }, - "Update": { - "Update": "Aggiorna" - }, - "Update All": { - "Update All": "Aggiorna Tutto" - }, - "Update Plugin": { - "Update Plugin": "Aggiorna Plugin" - }, - "Uptime": { - "Uptime": "Tempo di Attività" - }, - "Uptime:": { - "Uptime:": "Tempo di Attività:" - }, - "Urgent Color": { - "Urgent Color": "Colore Urgente" - }, - "Usage Tips": { - "Usage Tips": "Suggerimenti d'Uso" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Usa formato 24 ore invece del formato 12 ore AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Usa Comando Personalizzato" - }, - "Use Grid Layout": { - "Use Grid Layout": "Usa Layout a Griglia" - }, - "Use IP Location": { - "Use IP Location": "Usa Posizione IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Usa Unità Imperiali" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Usa unità Imperiali (°F, mph, inHg) invece di quelle Metriche (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Usa Font a Larghezza Fissa" - }, - "Use System Theme": { - "Use System Theme": "Usa Tema di Sistema" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Usa un'immagine personalizzata per la schermata di blocco, o lascia vuoto per utilizzare lo sfondo del tuo desktop." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Usa una direzione dell'ombra fissa per questa barra" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Usa una chiave di sicurezza per l'autenticazione della schermata di blocco." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Usa un gestore di sfondi esterno come swww, hyprpaper o swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Usa barre ad onde animate per la riproduzione media" - }, - "Use custom border size": { - "Use custom border size": "Usa uno spessore bordo personalizzato" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Usa larghezza bordo/cornice di focus personalizzata" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Usa comando personalizzato per aggiornare il sistema" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Usa spaziature personalizzate invece di quelle della barra" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Usa raggio personalizzato per le finestre invece di quello del tema" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Usa un arrotondamento finestre personalizzato invece del raggio del tema" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Usa lo sfondo del desktop" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Usa l'autenticazione tramite impronta digitale per la schermata di blocco." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Usa tema chiaro invece del tema scuro" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Usa metri al secondo invece di km/h per la velocità del vento" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Usa schede di notifica più piccole" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Usa tema di suoni dalle impostazioni di sistema" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Usa la stessa posizione e dimensione su tutti gli schermi" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Usa il prefisso attivatore per attivare" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Utilizzato quando il colore di accento è impostato su Personalizzato" - }, - "User": { - "User": "Utente" - }, - "Username": { - "Username": "Nome Utente" - }, - "Username...": { - "Username...": "Nome utente..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Utilizza gli orari di alba/tramonto in base alla tua posizione." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Usa gli orari di alba e tramonto per regolare automaticamente la modalità notte in base alla tua posizione." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Utilizzo delle impostazioni condivise di Gamma Control" - }, - "Utilities": { - "Utilities": "Utilità" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "Connessioni VPN" - }, - "VPN Password": { - "VPN Password": "Password VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "Configurazione VPN aggiornata" - }, - "VPN connections": { - "VPN connections": "Connessioni VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN eliminata" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importata: %1" - }, - "VPN not available": { - "VPN not available": "VPN non disponibile" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "Stato VPN e connessione veloce" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR Solo Schermo Intero" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR On-Demand" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Frequenza di Aggiornamento Variabile" - }, - "Verification": { - "Verification": "Verifica" - }, - "Version": { - "Version": "Versione" - }, - "Vertical Deck": { - "Vertical Deck": "Pila Verticale" - }, - "Vertical Grid": { - "Vertical Grid": "Griglia Verticale" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Scorrimento Verticale" - }, - "Vertical Tiling": { - "Vertical Tiling": "Tiling Verticale" - }, - "Vibrant": { - "Vibrant": "Vivace" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Tavolozza vibrante con saturazione giocosa." - }, - "Video Path": { - "Video Path": "Percorso Video" - }, - "Video Screensaver": { - "Video Screensaver": "Salvaschermo Video" - }, - "Videos": { - "Videos": "Video" - }, - "View Mode": { - "View Mode": "Modalità Visualizzazione" - }, - "Visibility": { - "Visibility": "Visibilità" - }, - "Visual Effects": { - "Visual Effects": "Effetti Visivi" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Separatore visivo tra i widget" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Effetto visivo usato quando cambia lo sfondo" - }, - "Volume": { - "Volume": "Volume" - }, - "Volume Changed": { - "Volume Changed": "Volume Modificato" - }, - "Volume Slider": { - "Volume Slider": "Slider Volume" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volume, luminosità e altri indicatori a schermo di sistema" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Sfondo" - }, - "Wallpaper Error": { - "Wallpaper Error": "Errore Sfondo" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Schermo per lo Sfondo" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Modalità di riempimento sfondo" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Elaborazione dello sfondo fallita" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Elaborazione sfondo fallita - verifica il percorso dello sfondo" - }, - "Wallpapers": { - "Wallpapers": "Sfondi" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Temperatura colore calda da applicare" - }, - "Warning": { - "Warning": "Attenzione" - }, - "Warnings": { - "Warnings": "Avvisi" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Barre di Avanzamento a Onda" - }, - "Weather": { - "Weather": "Meteo" - }, - "Weather Widget": { - "Weather Widget": "Widget Meteo" - }, - "Welcome": { - "Welcome": "Benvenuto" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Benvenuto in DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "Facendo clic su una finestra nella dock in uno spazio di lavoro speciale di Hyprland, ripristina lo spazio di lavoro speciale prima di portare in primo piano la finestra" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Quando attivato, le applicazioni sono ordinate alfabeticamente. Quando disattivato, le applicazioni sono ordinate per frequenza d'uso." - }, - "When locked": { - "When locked": "Quando bloccato" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Se si usa il widget di aggiornamento, nascondilo se non ne viene trovato nessuno" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Password Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Connessione Wi-Fi ed Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi non disponibile" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "Dispositivo WiFi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Codice QR WiFi per " - }, - "WiFi disabled": { - "WiFi disabled": "WiFi disattivato" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi attivato" - }, - "WiFi is off": { - "WiFi is off": "WiFi spento" - }, - "WiFi off": { - "WiFi off": "Wi-Fi spento" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Ampio (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Colore Sfondo Widget" - }, - "Widget Management": { - "Widget Management": "Gestione Widget" - }, - "Widget Outline": { - "Widget Outline": "Contorno Widget" - }, - "Widget Style": { - "Widget Style": "Stile Widget" - }, - "Widget Styling": { - "Widget Styling": "Aspetto Widget" - }, - "Widget Transparency": { - "Widget Transparency": "Trasparenza Widget" - }, - "Widget added": { - "Widget added": "Widget aggiunto" - }, - "Widget removed": { - "Widget removed": "Widget rimosso" - }, - "Widgets": { - "Widgets": "Widget" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widget, layout, stile" - }, - "Width": { - "Width": "Larghezza" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Larghezza bordo finestra (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Larghezza bordo finestra (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Larghezza del bordo e dell'anello di focus" - }, - "Wind": { - "Wind": "Vento" - }, - "Wind Speed": { - "Wind Speed": "Velocità Vento" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Velocità del Vento in m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Raggio Angoli Finestra" - }, - "Window Gaps": { - "Window Gaps": "Distanza tra Finestre" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Spaziatura tra Finestre (px)" - }, - "Window Height": { - "Window Height": "Altezza Finestra" - }, - "Window Opening": { - "Window Opening": "Apertura Finestra" - }, - "Window Rounding": { - "Window Rounding": "Arrotondamento Finestre" - }, - "Window Rules": { - "Window Rules": "Regole Finestra" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Inclusione Regole Finestra Mancanti" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Regole Finestra Non Configurate" - }, - "Wipe": { - "Wipe": "Tendina" - }, - "Workspace": { - "Workspace": "Spazio di Lavoro" - }, - "Workspace Appearance": { - "Workspace Appearance": "Aspetto Spazi di Lavoro" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Numeri Indice Spazi di Lavoro" - }, - "Workspace Names": { - "Workspace Names": "Nomi degli Spazi di Lavoro" - }, - "Workspace Padding": { - "Workspace Padding": "Spaziatura Interna degli Spazi di Lavoro" - }, - "Workspace Settings": { - "Workspace Settings": "Impostazioni Spazi di Lavoro" - }, - "Workspace Switcher": { - "Workspace Switcher": "Switcher Spazi di Lavoro" - }, - "Workspace name": { - "Workspace name": "Nome dello Spazio di Lavoro" - }, - "Workspaces": { - "Workspaces": "Spazi di Lavoro" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Spazi di Lavoro e Widget" - }, - "Write:": { - "Write:": "Scrittura:" - }, - "X Axis": { - "X Axis": "Asse X" - }, - "Y Axis": { - "Y Axis": "Asse Y" - }, - "Yes": { - "Yes": "Sì" - }, - "Yesterday": { - "Yesterday": "Ieri" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Ci sono modifiche non salvate. Salvare prima di chiudere questa scheda?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Ci sono modifiche non salvate. Salvare prima di continuare?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Ci sono modifiche non salvate. Salvare prima di creare un nuovo file?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Ci sono modifiche non salvate. Salvare prima di aprire un file?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Devi impostare una delle seguenti come variabili d'ambiente:\nQT_QPA_PLATFORMTHEME=gtk3 OPPURE\nQT_QPA_PLATFORMTHEME=qt6ct,\ne poi riavviare la shell.\n\nqt6ct richiede che qt6ct-kde sia installato." - }, - "You're All Set!": { - "You're All Set!": "Tutto Pronto!" - }, - "Your system is up to date!": { - "Your system is up to date!": "Il tuo sistema è aggiornato!" - }, - "actions": { - "actions": "azioni" - }, - "attached": { - "attached": "agganciato" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "di %1" - }, - "days": { - "days": "giorni" - }, - "detached": { - "detached": "disconnessa" - }, - "device": { - "device": "dispositivo" - }, - "devices connected": { - "devices connected": "dispositivi connessi" - }, - "dgop not available": { - "dgop not available": "dgop non disponibile" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "dms è una shell desktop moderna e altamente personalizzabile con un design ispirato a Material 3.

        È costruita con Quickshell, un framework QT6 per la creazione di shell desktop, e Go, un linguaggio di programmazione compilato e staticamente tipizzato." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "Il file di configurazione dms/cursor esiste ma non è incluso. Le impostazioni del cursore non verranno applicate." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "La configurazione dms/outputs esiste ma non è inclusa nella configurazione del compositor. Le modifiche allo schermo non saranno persistenti." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "es. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "es. focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "es. notify-send \"Ciao\" && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "es. scratch, /^tmp_.*/, build" - }, - "events": { - "events": "eventi" - }, - "ext": { - "ext": "est" - }, - "featured": { - "featured": "in primo piano" - }, - "leave empty for default": { - "leave empty for default": "lascia vuoto per il valore predefinito" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl non disponibile - integrazione blocco richiede connessione socket DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "Server Discord di MangoWC" - }, - "mangowc GitHub": { - "mangowc GitHub": "GitHub di MangoWC" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen non trovato - installa il pacchetto matugen per il theming dinamico" - }, - "minutes": { - "minutes": "minuti" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "nav" - }, - "niri GitHub": { - "niri GitHub": "GitHub di niri" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "Chat Matrix di niri" - }, - "niri shortcuts config": { - "niri shortcuts config": "configurazione scorciatoie niri" - }, - "niri/dms Discord": { - "niri/dms Discord": "Server Discord niri/dms" - }, - "now": { - "now": "ora" - }, - "official": { - "official": "ufficiale" - }, - "on Hyprland": { - "on Hyprland": "su Hyprland" - }, - "on MangoWC": { - "on MangoWC": "su MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "su Miracle WM" - }, - "on Niri": { - "on Niri": "su Niri" - }, - "on Scroll": { - "on Scroll": "su Scroll" - }, - "on Sway": { - "on Sway": "su Sway" - }, - "open": { - "open": "apri" - }, - "or run ": { - "or run ": "o esegui " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon non disponibile" - }, - "procs": { - "procs": "proc" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "Subreddit r/niri" - }, - "seconds": { - "seconds": "secondi" - }, - "source": { - "source": "sorgente" - }, - "this app": { - "this app": "questa app" - }, - "up": { - "up": "attivo da" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "aggiorna dms per l'integrazione NM." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 di %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype non disponibile – installa wtype per il supporto alla funzione incolla" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Installa solo da sorgenti fidate" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Mese (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Mese (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Mese (Gen)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Mese (Gennaio)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• I Plugin possono contenere errori o problemi di sicurezza" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Controlla il codice prima dell'installazione quando possibile" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Giorno (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Giorno (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Nome giorno (Lun)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Nome giorno (Lunedì)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Anno (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Anno (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Nav • Spazio: Espandi • Invio: Azione/Espandi • E: Testo" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: Naviga • Invio/Ctrl+C: Copia • Canc: Elimina • F10: Aiuto" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Naviga • Invio: Incolla • Canc: Elimina • F10: Aiuto" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ja.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ja.json deleted file mode 100644 index 84e306e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ja.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 文字" - }, - "%1 connected": { - "%1 connected": "" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "" - }, - "%1 disconnected": { - "%1 disconnected": "" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "" - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 ウィジェット" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "" - }, - "(Unnamed)": { - "(Unnamed)": "(名前なし)" - }, - "+ %1 more": { - "+ %1 more": "" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "" - }, - "1 day": { - "1 day": "" - }, - "1 device connected": { - "1 device connected": "" - }, - "1 event": { - "1 event": "1件のイベント" - }, - "1 hour": { - "1 hour": "" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "" - }, - "1 minute": { - "1 minute": "" - }, - "1 notification": { - "1 notification": "" - }, - "1 second": { - "1 second": "" - }, - "10 minutes": { - "10 minutes": "" - }, - "10 seconds": { - "10 seconds": "" - }, - "10-bit Color": { - "10-bit Color": "" - }, - "12 hours": { - "12 hours": "" - }, - "14 days": { - "14 days": "" - }, - "15 minutes": { - "15 minutes": "" - }, - "15 seconds": { - "15 seconds": "" - }, - "180°": { - "180°": "" - }, - "2 hours": { - "2 hours": "" - }, - "2 minutes": { - "2 minutes": "" - }, - "2 seconds": { - "2 seconds": "" - }, - "20 minutes": { - "20 minutes": "" - }, - "20 seconds": { - "20 seconds": "" - }, - "24-Hour Format": { - "24-Hour Format": "24時間形式" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "24時間形式" - }, - "25 seconds": { - "25 seconds": "" - }, - "250 ms": { - "250 ms": "" - }, - "270°": { - "270°": "" - }, - "3 days": { - "3 days": "" - }, - "3 hours": { - "3 hours": "" - }, - "3 minutes": { - "3 minutes": "" - }, - "3 seconds": { - "3 seconds": "" - }, - "30 days": { - "30 days": "" - }, - "30 minutes": { - "30 minutes": "" - }, - "30 seconds": { - "30 seconds": "" - }, - "35 seconds": { - "35 seconds": "" - }, - "3rd party": { - "3rd party": "サードパーティ" - }, - "4 hours": { - "4 hours": "" - }, - "4 seconds": { - "4 seconds": "" - }, - "40 seconds": { - "40 seconds": "" - }, - "45 seconds": { - "45 seconds": "" - }, - "5 minutes": { - "5 minutes": "" - }, - "5 seconds": { - "5 seconds": "" - }, - "50 seconds": { - "50 seconds": "" - }, - "500 ms": { - "500 ms": "" - }, - "55 seconds": { - "55 seconds": "" - }, - "6 hours": { - "6 hours": "" - }, - "7 days": { - "7 days": "" - }, - "750 ms": { - "750 ms": "" - }, - "8 hours": { - "8 hours": "" - }, - "8 seconds": { - "8 seconds": "" - }, - "90 days": { - "90 days": "" - }, - "90°": { - "90°": "" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "この名前のファイルは既に存在します。上書きしてもよろしいですか?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "" - }, - "AC Power": { - "AC Power": "" - }, - "API": { - "API": "" - }, - "Aborted": { - "Aborted": "" - }, - "About": { - "About": "詳細" - }, - "Accent Color": { - "Accent Color": "" - }, - "Accept": { - "Accept": "" - }, - "Accept Jobs": { - "Accept Jobs": "" - }, - "Accepting": { - "Accepting": "" - }, - "Access clipboard history": { - "Access clipboard history": "クリップボードの履歴へのアクセス" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "通知へのアクセスおよびサイレントモード" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "システム制御へのアクセスおよび設定" - }, - "Action": { - "Action": "" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "アクション" - }, - "Activate": { - "Activate": "" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "" - }, - "Active": { - "Active": "" - }, - "Active Color": { - "Active Color": "" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "" - }, - "Active: %1": { - "Active: %1": "" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "" - }, - "Active: None": { - "Active: None": "" - }, - "Adapters": { - "Adapters": "" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "追加" - }, - "Add Bar": { - "Add Bar": "バーを作る" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "" - }, - "Add Printer": { - "Add Printer": "" - }, - "Add Title": { - "Add Title": "" - }, - "Add Widget": { - "Add Widget": "ウィジェットを追加" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "" - }, - "Add a border around the dock": { - "Add a border around the dock": "" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "" - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "グリッド表示モードでの列数を調整します。" - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "" - }, - "Afternoon": { - "Afternoon": "" - }, - "All": { - "All": "全て" - }, - "All Monitors": { - "All Monitors": "" - }, - "All checks passed": { - "All checks passed": "" - }, - "All day": { - "All day": "毎日" - }, - "All displays": { - "All displays": "すべてのディスプレイ" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: 戻る • F1/I: ファイル情報 • F10: ヘルプ • Esc: 閉じる" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "" - }, - "Always Show Percentage": { - "Always Show Percentage": "" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "" - }, - "Always on icons": { - "Always on icons": "常時表示アイコン" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "使用可能なワークスペースが少ない場合でも、常に最低 3 つを表示" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "" - }, - "Amount": { - "Amount": "" - }, - "Analog": { - "Analog": "" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "" - }, - "Animation Duration": { - "Animation Duration": "" - }, - "Animation Speed": { - "Animation Speed": "アニメーション速度" - }, - "Anonymous Identity": { - "Anonymous Identity": "" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "匿名 ID (オプション)" - }, - "App Customizations": { - "App Customizations": "" - }, - "App ID Substitutions": { - "App ID Substitutions": "" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "" - }, - "App Launcher": { - "App Launcher": "アプリランチャー" - }, - "App Names": { - "App Names": "" - }, - "App Theming": { - "App Theming": "" - }, - "Appearance": { - "Appearance": "" - }, - "Application Dock": { - "Application Dock": "アプリドック" - }, - "Applications": { - "Applications": "アプリ" - }, - "Apply Changes": { - "Apply Changes": "" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "GTKカラーを適用" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Qtカラーを適用" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "目の疲れを軽減するために、暖色系の色温度を適用します。以下の自動化設定で、いつアクティブにするか制御できます。" - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "" - }, - "Apps Dock": { - "Apps Dock": "" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "" - }, - "Apps Icon": { - "Apps Icon": "アプリアイコン" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "アプリは使用頻度、最終使用日、アルファベット順の優先順位で並べられています。" - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "" - }, - "Architecture": { - "Architecture": "" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "" - }, - "Audio Codec": { - "Audio Codec": "オーディオコーデック" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "オーディオコーデックの選択" - }, - "Audio Devices": { - "Audio Devices": "オーディオデバイス" - }, - "Audio Input": { - "Audio Input": "" - }, - "Audio Output": { - "Audio Output": "" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "オーディオ出力デバイス(" - }, - "Audio Output Switch": { - "Audio Output Switch": "" - }, - "Audio Visualizer": { - "Audio Visualizer": "" - }, - "Audio system restarted": { - "Audio system restarted": "" - }, - "Audio volume control": { - "Audio volume control": "" - }, - "Auth": { - "Auth": "" - }, - "Auth Type": { - "Auth Type": "" - }, - "Authenticate": { - "Authenticate": "認証" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "" - }, - "Authentication Required": { - "Authentication Required": "認証が必要です" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "認証が失敗しました、もう一度試してください" - }, - "Authorize": { - "Authorize": "許可" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "ペアリングを許可 " - }, - "Authorize service for ": { - "Authorize service for ": "サービスを許可 " - }, - "Auto": { - "Auto": "" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "" - }, - "Auto Location": { - "Auto Location": "自動位置検出" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "自動ポップアップギャップ" - }, - "Auto-Clear After": { - "Auto-Clear After": "" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "" - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "" - }, - "Auto-hide": { - "Auto-hide": "自動的に非表示" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "ドックを自動的に隠す" - }, - "Auto-saving...": { - "Auto-saving...": "自動保存中..." - }, - "Autoconnect": { - "Autoconnect": "" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "自動接続が無効" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "自動接続が有効" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "" - }, - "Automatic Control": { - "Automatic Control": "自動制御" - }, - "Automatic Cycling": { - "Automatic Cycling": "自動サイクリング" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "同じフォルダ内の壁紙を自動的に切り替える" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "IPアドレスに基づいて位置を自動的に検出" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "IPアドレスを使用して現在地を自動的に特定します" - }, - "Automatically lock after": { - "Automatically lock after": "自動的にロック" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "システムが一時停止の準備中に自動的に画面をロック" - }, - "Automation": { - "Automation": "" - }, - "Available": { - "Available": "利用可能" - }, - "Available Layouts": { - "Available Layouts": "利用可能なレイアウト" - }, - "Available Networks": { - "Available Networks": "" - }, - "Available Plugins": { - "Available Plugins": "利用可能なプラグイン" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "" - }, - "Back": { - "Back": "戻る" - }, - "Backend": { - "Backend": "" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "" - }, - "Backlight device": { - "Backlight device": "" - }, - "Balance power and performance": { - "Balance power and performance": "" - }, - "Balanced": { - "Balanced": "" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "アクセントに焦点を絞ったバランスの取れたパレット(デフォルト)。" - }, - "Bar Configurations": { - "Bar Configurations": "バーの設定" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "バーの透明度" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "" - }, - "Battery": { - "Battery": "バッテリー" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "" - }, - "Battery and power management": { - "Battery and power management": "" - }, - "Battery level and power management": { - "Battery level and power management": "バッテリーレベルおよび電源管理" - }, - "Behavior": { - "Behavior": "" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "ロック画面をloginctlからのdbus信号にバインド。外部ロック画面を使用している場合は無効に" - }, - "Binds Include Missing": { - "Binds Include Missing": "" - }, - "Binds include added": { - "Binds include added": "" - }, - "Bit Depth": { - "Bit Depth": "" - }, - "Block Out": { - "Block Out": "" - }, - "Block Out From": { - "Block Out From": "" - }, - "Block notifications": { - "Block notifications": "" - }, - "Blocked": { - "Blocked": "" - }, - "Blue light filter": { - "Blue light filter": "" - }, - "Bluetooth": { - "Bluetooth": "" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth設定" - }, - "Bluetooth not available": { - "Bluetooth not available": "" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "" - }, - "Blur on Overview": { - "Blur on Overview": "概要でぼかす" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Niri概要が開いているときに壁紙をぼかす" - }, - "Body": { - "Body": "" - }, - "Border": { - "Border": "ボーダー" - }, - "Border Color": { - "Border Color": "ボーダーの色" - }, - "Border Opacity": { - "Border Opacity": "ボーダーの透明度" - }, - "Border Size": { - "Border Size": "" - }, - "Border Thickness": { - "Border Thickness": "ボーダーの太さ" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "" - }, - "Bottom": { - "Bottom": "ボトム" - }, - "Bottom Center": { - "Bottom Center": "" - }, - "Bottom Left": { - "Bottom Left": "" - }, - "Bottom Right": { - "Bottom Right": "" - }, - "Bottom Section": { - "Bottom Section": "ボトムセクション" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "固定および実行中のアプリケーション用のボトムドック" - }, - "Brightness": { - "Brightness": "明るさ" - }, - "Brightness Slider": { - "Brightness Slider": "" - }, - "Brightness Value": { - "Brightness Value": "" - }, - "Brightness control not available": { - "Brightness control not available": "" - }, - "Browse": { - "Browse": "ブラウズ" - }, - "Browse Files": { - "Browse Files": "" - }, - "Browse Plugins": { - "Browse Plugins": "ブラウズプラグイン" - }, - "Browse Themes": { - "Browse Themes": "" - }, - "Browse or search plugins": { - "Browse or search plugins": "" - }, - "Button Color": { - "Button Color": "" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "" - }, - "CPU Temperature": { - "CPU Temperature": "CPU温度" - }, - "CPU Usage": { - "CPU Usage": "CPU使用率" - }, - "CPU temperature display": { - "CPU temperature display": "CPU温度表示" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU使用率インジケーター" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS の安全でないフィルターの警告" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS の欠落フィルターの警告" - }, - "CUPS Print Server": { - "CUPS Print Server": "" - }, - "CUPS not available": { - "CUPS not available": "" - }, - "Camera": { - "Camera": "カメラ" - }, - "Cancel": { - "Cancel": "キャンセル" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "" - }, - "Canceled": { - "Canceled": "" - }, - "Cannot pair": { - "Cannot pair": "" - }, - "Capabilities": { - "Capabilities": "" - }, - "Capacity": { - "Capacity": "容量" - }, - "Caps Lock": { - "Caps Lock": "" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Caps Lock インジケーター" - }, - "Caps Lock is on": { - "Caps Lock is on": "" - }, - "Center Section": { - "Center Section": "センターセクション" - }, - "Center Single Column": { - "Center Single Column": "" - }, - "Center Tiling": { - "Center Tiling": "中央タイルリング" - }, - "Certificate Password": { - "Certificate Password": "" - }, - "Change Song": { - "Change Song": "" - }, - "Change Volume": { - "Change Volume": "" - }, - "Change bar appearance": { - "Change bar appearance": "バーの見た目を変更" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "" - }, - "Charging": { - "Charging": "" - }, - "Check for system updates": { - "Check for system updates": "システムアップデートを検査" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "色を選んでください" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "ランチャーロゴの色を選ぶ" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "" - }, - "Choose a color": { - "Choose a color": "" - }, - "Choose colors from palette": { - "Choose colors from palette": "" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "アイコンを選ぶ" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "ウィジェットの背景色を選んでください" - }, - "Choose the border accent color": { - "Choose the border accent color": "ボーダーの強調色を選ぶ" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Dank Barのランチャーボタンに表示されるロゴを選ぶ" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "通知ポップアップが画面に表示される場所を選ぶ" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "OSDの表示する場所を選んでください" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "" - }, - "Chroma Style": { - "Chroma Style": "" - }, - "Cipher": { - "Cipher": "" - }, - "Circle": { - "Circle": "" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "" - }, - "Clear": { - "Clear": "クリア" - }, - "Clear All": { - "Clear All": "すべてクリア" - }, - "Clear All Jobs": { - "Clear All Jobs": "" - }, - "Clear History?": { - "Clear History?": "" - }, - "Clear Sky": { - "Clear Sky": "" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "" - }, - "Clear at Startup": { - "Clear at Startup": "" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "" - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "" - }, - "Click to capture": { - "Click to capture": "" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "" - }, - "Clip": { - "Clip": "" - }, - "Clip to Geometry": { - "Clip to Geometry": "" - }, - "Clipboard": { - "Clipboard": "" - }, - "Clipboard History": { - "Clipboard History": "クリップボード履歴" - }, - "Clipboard Manager": { - "Clipboard Manager": "クリップボード管理" - }, - "Clipboard sent": { - "Clipboard sent": "" - }, - "Clipboard service not available": { - "Clipboard service not available": "" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "" - }, - "Clock": { - "Clock": "時計" - }, - "Clock Style": { - "Clock Style": "" - }, - "Close": { - "Close": "閉じる" - }, - "Close All Windows": { - "Close All Windows": "" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "起動中のときに概要を閉じる" - }, - "Close Window": { - "Close Window": "" - }, - "Color": { - "Color": "" - }, - "Color Gamut": { - "Color Gamut": "" - }, - "Color Management": { - "Color Management": "" - }, - "Color Mode": { - "Color Mode": "" - }, - "Color Override": { - "Color Override": "色のオーバーライド" - }, - "Color Picker": { - "Color Picker": "カラーピッカー" - }, - "Color Temperature": { - "Color Temperature": "" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "" - }, - "Color temperature for day time": { - "Color temperature for day time": "昼間の色温度" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "ナイトモードの色温度" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "" - }, - "Colorful": { - "Colorful": "" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "明るいコントラストのアクセントのカラフルなミックス。" - }, - "Colorize Active": { - "Colorize Active": "" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "" - }, - "Column": { - "Column": "" - }, - "Column Display": { - "Column Display": "" - }, - "Column Width": { - "Column Width": "" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "" - }, - "Commands": { - "Commands": "" - }, - "Communication": { - "Communication": "コミュニケーション" - }, - "Community themes": { - "Community themes": "" - }, - "Compact": { - "Compact": "" - }, - "Compact Mode": { - "Compact Mode": "コンパクトモード" - }, - "Completed": { - "Completed": "" - }, - "Compositor": { - "Compositor": "コンポジター" - }, - "Compositor Settings": { - "Compositor Settings": "" - }, - "Compositor not supported": { - "Compositor not supported": "" - }, - "Config Format": { - "Config Format": "" - }, - "Config action: %1": { - "Config action: %1": "" - }, - "Config validation failed": { - "Config validation failed": "" - }, - "Configuration": { - "Configuration": "" - }, - "Configuration activated": { - "Configuration activated": "設定が適用されました" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "" - }, - "Configure": { - "Configure": "" - }, - "Configure Keybinds": { - "Configure Keybinds": "" - }, - "Configure a new printer": { - "Configure a new printer": "" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "名前付きワークスペースのアイコンを設定します。両方が有効になっている場合、アイコンが数字よりも優先されます。" - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "シェルコンポーネントを表示するディスプレイを配置" - }, - "Confirm": { - "Confirm": "確認" - }, - "Confirm Delete": { - "Confirm Delete": "" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "表示変更を確認" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "パスキーを確認 " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "" - }, - "Connect": { - "Connect": "接続" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "" - }, - "Connect to VPN": { - "Connect to VPN": "VPNに接続" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Wi-Fiに接続" - }, - "Connected": { - "Connected": "" - }, - "Connected Device": { - "Connected Device": "" - }, - "Connected Displays": { - "Connected Displays": "接続されたディスプレイ" - }, - "Connecting to Device": { - "Connecting to Device": "デバイスに接続中" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "" - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "" - }, - "Content": { - "Content": "" - }, - "Content copied": { - "Content copied": "" - }, - "Contrast": { - "Contrast": "コントラスト" - }, - "Control Center": { - "Control Center": "コントロールセンター" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "" - }, - "Control currently playing media": { - "Control currently playing media": "現在再生中のメディアを制御" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "" - }, - "Copied GIF": { - "Copied GIF": "" - }, - "Copied MP4": { - "Copied MP4": "" - }, - "Copied WebP": { - "Copied WebP": "" - }, - "Copied to clipboard": { - "Copied to clipboard": "クリップボードにコピーしました" - }, - "Copied!": { - "Copied!": "コピーしました!" - }, - "Copy": { - "Copy": "" - }, - "Copy Content": { - "Copy Content": "" - }, - "Copy Full Command": { - "Copy Full Command": "" - }, - "Copy HTML": { - "Copy HTML": "" - }, - "Copy Name": { - "Copy Name": "" - }, - "Copy PID": { - "Copy PID": "PIDをコピー" - }, - "Copy Text": { - "Copy Text": "" - }, - "Copy path": { - "Copy path": "" - }, - "Corner Radius": { - "Corner Radius": "" - }, - "Corner Radius Override": { - "Corner Radius Override": "コーナー半径オーバーライド" - }, - "Corners & Background": { - "Corners & Background": "" - }, - "Count Only": { - "Count Only": "" - }, - "Cover Open": { - "Cover Open": "カバーオープン" - }, - "Create": { - "Create": "" - }, - "Create Dir": { - "Create Dir": "ディレクトリを作成" - }, - "Create Printer": { - "Create Printer": "" - }, - "Create Window Rule": { - "Create Window Rule": "" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "" - }, - "Creating...": { - "Creating...": "" - }, - "Critical Priority": { - "Critical Priority": "最優先事項" - }, - "Current": { - "Current": "" - }, - "Current Items": { - "Current Items": "現在のアイテム" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "" - }, - "Current Period": { - "Current Period": "" - }, - "Current Status": { - "Current Status": "" - }, - "Current Temp": { - "Current Temp": "" - }, - "Current Theme: %1": { - "Current Theme: %1": "" - }, - "Current Weather": { - "Current Weather": "現在の天気" - }, - "Current Workspace": { - "Current Workspace": "" - }, - "Current time and date display": { - "Current time and date display": "現在の日時を表示" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "現在の天気状況と気温" - }, - "Current: %1": { - "Current: %1": "" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "" - }, - "Cursor Size": { - "Cursor Size": "" - }, - "Cursor Theme": { - "Cursor Theme": "" - }, - "Custom": { - "Custom": "カスタム" - }, - "Custom Color": { - "Custom Color": "" - }, - "Custom Duration": { - "Custom Duration": "" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "" - }, - "Custom Location": { - "Custom Location": "カスタムロケーション" - }, - "Custom Lock Command": { - "Custom Lock Command": "" - }, - "Custom Logout Command": { - "Custom Logout Command": "" - }, - "Custom Name": { - "Custom Name": "" - }, - "Custom Power Actions": { - "Custom Power Actions": "カスタム電源アクション" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "" - }, - "Custom Transparency": { - "Custom Transparency": "カスタム透明度" - }, - "Custom power profile": { - "Custom power profile": "" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "" - }, - "Custom...": { - "Custom...": "" - }, - "Custom: ": { - "Custom: ": "カスタム: " - }, - "Customizable empty space": { - "Customizable empty space": "カスタマイズ可能な空きスペース" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "電源メニューに表示されるアクションをカスタマイズ" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "デモモード -任意の場所をクリックして 終了" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS プラグイン マネージャーが利用できません" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMSに更新があります" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "" - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKETが利用できません" - }, - "DWL service not available": { - "DWL service not available": "DWLサービスが利用できません" - }, - "Daily": { - "Daily": "" - }, - "Daily at:": { - "Daily at:": "毎日:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "" - }, - "Dark Mode": { - "Dark Mode": "ダークモード" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "モーダル背景を暗くする" - }, - "Date Format": { - "Date Format": "日付形式" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "" - }, - "Day Date": { - "Day Date": "" - }, - "Day Month Date": { - "Day Month Date": "" - }, - "Day Temperature": { - "Day Temperature": "昼間の温度" - }, - "Daytime": { - "Daytime": "" - }, - "Deck": { - "Deck": "デッキ" - }, - "Default": { - "Default": "デフォルト" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "" - }, - "Default selected action": { - "Default selected action": "デフォルトで選択されるアクション" - }, - "Defaults": { - "Defaults": "デフォルト" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: クリア • Shift+Del: すべてクリア • 1-9: アクション • F10: ヘルプ • Esc: 閉じる" - }, - "Delete": { - "Delete": "" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "" - }, - "Delete Class": { - "Delete Class": "" - }, - "Delete Printer": { - "Delete Printer": "" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "" - }, - "Delete VPN": { - "Delete VPN": "" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "下にある画像に密接に一致する色を導き出します。" - }, - "Description": { - "Description": "" - }, - "Desktop": { - "Desktop": "" - }, - "Desktop Clock": { - "Desktop Clock": "" - }, - "Desktop Entry": { - "Desktop Entry": "" - }, - "Desktop Widget": { - "Desktop Widget": "" - }, - "Desktop Widgets": { - "Desktop Widgets": "" - }, - "Desktop background images": { - "Desktop background images": "デスクトップの背景画像" - }, - "Detailed": { - "Detailed": "" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "開発" - }, - "Device": { - "Device": "デバイス" - }, - "Device connections": { - "Device connections": "" - }, - "Device names updated": { - "Device names updated": "" - }, - "Device paired": { - "Device paired": "デバイスがペアリングされました" - }, - "Device unpaired": { - "Device unpaired": "" - }, - "Digital": { - "Digital": "" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "自動接続を無効" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "" - }, - "Disable History Persistence": { - "Disable History Persistence": "" - }, - "Disable Output": { - "Disable Output": "" - }, - "Disabled": { - "Disabled": "無効化されました" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "" - }, - "Disc": { - "Disc": "" - }, - "Discard": { - "Discard": "" - }, - "Discharging": { - "Discharging": "" - }, - "Disconnect": { - "Disconnect": "切断" - }, - "Disconnected": { - "Disconnected": "" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "WiFiから切断されました" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "ディスク" - }, - "Disk I/O": { - "Disk I/O": "" - }, - "Disk Usage": { - "Disk Usage": "ディスク使用率" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "" - }, - "Dismiss": { - "Dismiss": "解除" - }, - "Display": { - "Display": "" - }, - "Display Assignment": { - "Display Assignment": "表示割り当て" - }, - "Display Control": { - "Display Control": "" - }, - "Display Name Format": { - "Display Name Format": "名称形式を表示" - }, - "Display Profiles": { - "Display Profiles": "" - }, - "Display Settings": { - "Display Settings": "" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "フルスクリーンアプリよりもすべての優先度を表示する" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "DWL レイアウトの表示と切り替え" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "ワークスペース インジケーターにアプリのアイコンを表示" - }, - "Display brightness control": { - "Display brightness control": "" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "" - }, - "Display currently focused application title": { - "Display currently focused application title": "現在フォーカスされているアプリケーションのタイトルを表示" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "電源メニューのアクションをリストではなくグリッドに表示" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "" - }, - "Display the power system menu": { - "Display the power system menu": "" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "" - }, - "Displays": { - "Displays": "表示" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "アクティブなキーボードレイアウトを表示、切り替えを可能に" - }, - "Distribution": { - "Distribution": "" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "全スペクトルにまたがる多様なパレット。" - }, - "Do Not Disturb": { - "Do Not Disturb": "サイレントモード" - }, - "Dock": { - "Dock": "ドック" - }, - "Dock & Launcher": { - "Dock & Launcher": "" - }, - "Dock Transparency": { - "Dock Transparency": "ドックの透明度" - }, - "Dock Visibility": { - "Dock Visibility": "" - }, - "Docs": { - "Docs": "" - }, - "Documents": { - "Documents": "" - }, - "Domain (optional)": { - "Domain (optional)": "ドメイン (オプション)" - }, - "Don't Change": { - "Don't Change": "" - }, - "Don't Save": { - "Don't Save": "" - }, - "Door Open": { - "Door Open": "ドアオープン" - }, - "Downloads": { - "Downloads": "" - }, - "Drag to Reorder": { - "Drag to Reorder": "" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "ウィジェットをドラッグしてセクション内で順序を変更できます。目のアイコンでウィジェットを表示/非表示に(スペースは維持)、Xで完全に削除できます。" - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "" - }, - "Driver": { - "Driver": "" - }, - "Drizzle": { - "Drizzle": "" - }, - "Duplicate": { - "Duplicate": "" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "ぼかしで壁紙を複製" - }, - "Duration": { - "Duration": "" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "" - }, - "Dynamic": { - "Dynamic": "" - }, - "Dynamic Properties": { - "Dynamic Properties": "" - }, - "Dynamic Theming": { - "Dynamic Theming": "" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "" - }, - "Edge Spacing": { - "Edge Spacing": "" - }, - "Edit App": { - "Edit App": "" - }, - "Edit Window Rule": { - "Edit Window Rule": "" - }, - "Education": { - "Education": "教育" - }, - "Empty": { - "Empty": "空白" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "自動接続を有効" - }, - "Enable Bar": { - "Enable Bar": "バーを起用" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "" - }, - "Enable History": { - "Enable History": "" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "" - }, - "Enable System Sounds": { - "Enable System Sounds": "システムサウンドを有効に" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "天気を有効にする" - }, - "Enable WiFi": { - "Enable WiFi": "WiFiを有効にする" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "コンポジターをターゲットに設定できるぼかしレイヤー(名前空間:dms:blurwallpaper)を有効にします。Niri を手動で設定する必要があります。" - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "指紋認証を有効に" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "ログインロックの統合を有効に" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "有効化されました" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "" - }, - "End": { - "End": "終わり" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "" - }, - "Enlargement %": { - "Enlargement %": "" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "6桁のパスキーを入力してください" - }, - "Enter PIN": { - "Enter PIN": "PINを入力してください" - }, - "Enter PIN for ": { - "Enter PIN for ": "PINを入力してください " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "資格情報を入力" - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "カスタムロック画面の形式を入力してください(e.g., dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "カスタムトップバー形式を入力してください (e.g., ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "" - }, - "Enter filename...": { - "Enter filename...": "ファイル名を入力してください..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "" - }, - "Enter network name and password": { - "Enter network name and password": "" - }, - "Enter passkey for ": { - "Enter passkey for ": "パスキーを入力してください " - }, - "Enter password for ": { - "Enter password for ": "パスワードを入力" - }, - "Enter this passkey on ": { - "Enter this passkey on ": "ここでパスキーを入力してください " - }, - "Enter to Paste": { - "Enter to Paste": "" - }, - "Enterprise": { - "Enterprise": "" - }, - "Entry pinned": { - "Entry pinned": "" - }, - "Entry unpinned": { - "Entry unpinned": "" - }, - "Environment Variables": { - "Environment Variables": "" - }, - "Error": { - "Error": "エラー" - }, - "Errors": { - "Errors": "" - }, - "Ethernet": { - "Ethernet": "" - }, - "Exact": { - "Exact": "" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "排他ゾーンオフセット" - }, - "Experimental Feature": { - "Experimental Feature": "" - }, - "Explore": { - "Explore": "" - }, - "Exponential": { - "Exponential": "" - }, - "Expressive": { - "Expressive": "" - }, - "Extend battery life": { - "Extend battery life": "" - }, - "Extensible architecture": { - "Extensible architecture": "" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "" - }, - "Extra Arguments": { - "Extra Arguments": "" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: 切り替え • F10: ヘルプ" - }, - "Fade": { - "Fade": "" - }, - "Fade to lock screen": { - "Fade to lock screen": "" - }, - "Fade to monitor off": { - "Fade to monitor off": "" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "設定が適用できませんでした" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "" - }, - "Failed to add binds include": { - "Failed to add binds include": "" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "" - }, - "Failed to browse device": { - "Failed to browse device": "" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "すべてのジョブの取り消しに失敗しました" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "選ばれたジョブの取り消しに失敗しました" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "VPNへの接続が失敗しました" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "" - }, - "Failed to copy entry": { - "Failed to copy entry": "" - }, - "Failed to create printer": { - "Failed to create printer": "" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "" - }, - "Failed to delete class": { - "Failed to delete class": "" - }, - "Failed to delete printer": { - "Failed to delete printer": "" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "VPNへの切断が失敗しました" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "VPNへの切断が失敗しました" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "WiFiの切断ができませんでした" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "WiFiを有効化にできませんでした" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "" - }, - "Failed to hold job": { - "Failed to hold job": "" - }, - "Failed to import VPN": { - "Failed to import VPN": "" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "" - }, - "Failed to move job": { - "Failed to move job": "" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "" - }, - "Failed to pause printer": { - "Failed to pause printer": "プリンターの一時中断に失敗しました" - }, - "Failed to pin entry": { - "Failed to pin entry": "" - }, - "Failed to print test page": { - "Failed to print test page": "" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "" - }, - "Failed to remove device": { - "Failed to remove device": "デバイスの削除に失敗しました" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "" - }, - "Failed to restart job": { - "Failed to restart job": "" - }, - "Failed to resume printer": { - "Failed to resume printer": "プリンタの再開に失敗しました" - }, - "Failed to ring device": { - "Failed to ring device": "" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "" - }, - "Failed to save keybind": { - "Failed to save keybind": "" - }, - "Failed to save profile file": { - "Failed to save profile file": "" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "" - }, - "Failed to send file": { - "Failed to send file": "" - }, - "Failed to send ping": { - "Failed to send ping": "" - }, - "Failed to set brightness": { - "Failed to set brightness": "" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "プロフィール画像の設定に失敗しました" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "" - }, - "Failed to share": { - "Failed to share": "" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "" - }, - "Failed to update VPN": { - "Failed to update VPN": "" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "自動接続の更新が失敗しました" - }, - "Failed to update description": { - "Failed to update description": "" - }, - "Failed to update location": { - "Failed to update location": "" - }, - "Failed to update sharing": { - "Failed to update sharing": "" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "" - }, - "Features": { - "Features": "" - }, - "Feels": { - "Feels": "" - }, - "Feels Like": { - "Feels Like": "どうやら" - }, - "Feels Like %1°": { - "Feels Like %1°": "" - }, - "Fidelity": { - "Fidelity": "" - }, - "Field": { - "Field": "" - }, - "File": { - "File": "" - }, - "File Already Exists": { - "File Already Exists": "ファイルが既に存在します" - }, - "File Information": { - "File Information": "ファイル情報" - }, - "File received from": { - "File received from": "" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "" - }, - "Files": { - "Files": "" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "" - }, - "Fill": { - "Fill": "" - }, - "Find in Text": { - "Find in Text": "テキスト内検索" - }, - "Find in note...": { - "Find in note...": "メモで検索..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "" - }, - "Fit": { - "Fit": "" - }, - "Fix Now": { - "Fix Now": "" - }, - "Fixing...": { - "Fixing...": "" - }, - "Flags": { - "Flags": "" - }, - "Flipped": { - "Flipped": "" - }, - "Flipped 180°": { - "Flipped 180°": "" - }, - "Flipped 270°": { - "Flipped 270°": "" - }, - "Flipped 90°": { - "Flipped 90°": "" - }, - "Float": { - "Float": "" - }, - "Focus": { - "Focus": "" - }, - "Focus at Startup": { - "Focus at Startup": "" - }, - "Focused Border": { - "Focused Border": "" - }, - "Focused Color": { - "Focused Color": "" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "フォーカスされたウィンドウ" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "" - }, - "Folder": { - "Folder": "" - }, - "Folders": { - "Folders": "" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "" - }, - "Follow focus": { - "Follow focus": "" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "フォントファミリー" - }, - "Font Scale": { - "Font Scale": "フォントスケール" - }, - "Font Size": { - "Font Size": "フォントサイズ" - }, - "Font Weight": { - "Font Weight": "フォントの太さ" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "" - }, - "Force Wide Color": { - "Force Wide Color": "" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "端末アプリで常に暗い配色を強制使用" - }, - "Forecast": { - "Forecast": "" - }, - "Forecast Days": { - "Forecast Days": "" - }, - "Forecast Not Available": { - "Forecast Not Available": "" - }, - "Forever": { - "Forever": "" - }, - "Forget": { - "Forget": "" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "" - }, - "Forget Device": { - "Forget Device": "デバイスを忘れる" - }, - "Forget Network": { - "Forget Network": "ネットワークを忘れる" - }, - "Forgot network %1": { - "Forgot network %1": "" - }, - "Format Legend": { - "Format Legend": "フォーマット凡例" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "" - }, - "Frequency": { - "Frequency": "" - }, - "Fruit Salad": { - "Fruit Salad": "" - }, - "Full Command:": { - "Full Command:": "" - }, - "Full Content": { - "Full Content": "" - }, - "Full Day & Month": { - "Full Day & Month": "" - }, - "Full with Year": { - "Full with Year": "" - }, - "Fullscreen": { - "Fullscreen": "" - }, - "Fullscreen Only": { - "Fullscreen Only": "" - }, - "Fully Charged": { - "Fully Charged": "" - }, - "Fun": { - "Fun": "娯楽" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "" - }, - "GPU Temperature": { - "GPU Temperature": "GPU温度" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "" - }, - "Games": { - "Games": "ゲーム" - }, - "Gamma Control": { - "Gamma Control": "ガンマ設定" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "ガンマ制御は使用できません。DMS API v6+ が必要です。" - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "" - }, - "Get Started": { - "Get Started": "" - }, - "GitHub": { - "GitHub": "" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "" - }, - "Golden Hour": { - "Golden Hour": "" - }, - "Good": { - "Good": "良い" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "ゴスコーナー半径" - }, - "Goth Corners": { - "Goth Corners": "ゴスコーナーズ" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "" - }, - "Graph Time Range": { - "Graph Time Range": "" - }, - "Graphics": { - "Graphics": "グラフィック" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "グリッド" - }, - "Grid Columns": { - "Grid Columns": "グリッド列" - }, - "Grid: OFF": { - "Grid: OFF": "" - }, - "Grid: ON": { - "Grid: ON": "" - }, - "Group": { - "Group": "" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "" - }, - "Group by App": { - "Group by App": "アプリ別にグループ化" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "同じアプリの複数のウィンドウをウィンドウ数インジケーターでグループ化します" - }, - "Group removed": { - "Group removed": "" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "" - }, - "Groups": { - "Groups": "" - }, - "HDR (EDID)": { - "HDR (EDID)": "" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "" - }, - "HSV": { - "HSV": "色相/彩度/輝度" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "" - }, - "Health": { - "Health": "健康" - }, - "Heavy Rain": { - "Heavy Rain": "" - }, - "Heavy Snow": { - "Heavy Snow": "" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "" - }, - "Height": { - "Height": "" - }, - "Held": { - "Held": "" - }, - "Help": { - "Help": "" - }, - "Hex": { - "Hex": "16進数" - }, - "Hibernate": { - "Hibernate": "休止状態" - }, - "Hidden": { - "Hidden": "" - }, - "Hidden (%1)": { - "Hidden (%1)": "" - }, - "Hidden Apps": { - "Hidden Apps": "" - }, - "Hidden Network": { - "Hidden Network": "" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "" - }, - "Hide": { - "Hide": "" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "" - }, - "Hide App": { - "Hide App": "" - }, - "Hide Delay": { - "Hide Delay": "" - }, - "Hide Indicators": { - "Hide Indicators": "" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "" - }, - "Hide When Typing": { - "Hide When Typing": "" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "" - }, - "Hide device": { - "Hide device": "" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "" - }, - "Hide on Touch": { - "Hide on Touch": "" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "ソースの色相を保持する忠実度の高いパレット。" - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "" - }, - "History Retention": { - "History Retention": "" - }, - "History Settings": { - "History Settings": "" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "" - }, - "Hold Duration": { - "Hold Duration": "" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "" - }, - "Home": { - "Home": "" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "" - }, - "Hot Corners": { - "Hot Corners": "" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "" - }, - "Hour": { - "Hour": "時間" - }, - "Hourly": { - "Hourly": "" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "壁紙を切り替える間隔" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "湿度" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "" - }, - "Hyprland Options": { - "Hyprland Options": "" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "わかりました" - }, - "IP": { - "IP": "" - }, - "IP Address:": { - "IP Address:": "" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "" - }, - "Icon": { - "Icon": "" - }, - "Icon Scale": { - "Icon Scale": "" - }, - "Icon Size": { - "Icon Size": "アイコンサイズ" - }, - "Icon Size %": { - "Icon Size %": "" - }, - "Icon Theme": { - "Icon Theme": "アイコンテーマ" - }, - "Idle": { - "Idle": "アイドル" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "アイドルインヒビター" - }, - "Idle Settings": { - "Idle Settings": "アイドル設定" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "アイドル監視はサポートされていません - 新しい Quickshell バージョンが必要です" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "" - }, - "Ignore Completely": { - "Ignore Completely": "" - }, - "Image": { - "Image": "画像" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "" - }, - "Import": { - "Import": "" - }, - "Import VPN": { - "Import VPN": "" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "トランジションを含める" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "" - }, - "Incorrect password": { - "Incorrect password": "パスワードが間違っています" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "インジケータースタイル" - }, - "Individual Batteries": { - "Individual Batteries": "バッテリーごと" - }, - "Individual bar configuration": { - "Individual bar configuration": "バーの個別設定" - }, - "Info": { - "Info": "" - }, - "Inherit": { - "Inherit": "" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "" - }, - "Input Devices": { - "Input Devices": "入力デバイス" - }, - "Input Volume Slider": { - "Input Volume Slider": "" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "" - }, - "Install Theme": { - "Install Theme": "" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "DMSプラグインレジストリからプラグインをインストールする" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "" - }, - "Installed: %1": { - "Installed: %1": "" - }, - "Installing: %1": { - "Installing: %1": "" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "" - }, - "Intensity": { - "Intensity": "" - }, - "Interface:": { - "Interface:": "" - }, - "Interlock Open": { - "Interlock Open": "インターロックオープン" - }, - "Internet": { - "Internet": "インターネット" - }, - "Interval": { - "Interval": "間隔" - }, - "Invalid configuration": { - "Invalid configuration": "" - }, - "Invert on mode change": { - "Invert on mode change": "モード変更時に反転" - }, - "Iris Bloom": { - "Iris Bloom": "" - }, - "Isolate Displays": { - "Isolate Displays": "" - }, - "Jobs": { - "Jobs": "ジョブ" - }, - "Jobs: ": { - "Jobs: ": "ジョブ: " - }, - "Keep Awake": { - "Keep Awake": "活動状態を維持" - }, - "Keep Changes": { - "Keep Changes": "変更を保持" - }, - "Keeping Awake": { - "Keeping Awake": "活動状態を維持" - }, - "Kernel": { - "Kernel": "" - }, - "Key": { - "Key": "" - }, - "Keybind Sources": { - "Keybind Sources": "" - }, - "Keybinds": { - "Keybinds": "" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "キーボードレイアウト名" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "" - }, - "Keys": { - "Keys": "" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "プロセスを強制終了" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "" - }, - "LED device": { - "LED device": "" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "" - }, - "Largest": { - "Largest": "" - }, - "Last hour": { - "Last hour": "" - }, - "Last launched %1": { - "Last launched %1": "最終起動日 %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "ただいま起動しました" - }, - "Latitude": { - "Latitude": "緯度" - }, - "Launch": { - "Launch": "起動" - }, - "Launch Prefix": { - "Launch Prefix": "起動プリフィックス" - }, - "Launch on dGPU": { - "Launch on dGPU": "dGPUで起動" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "ランチャー" - }, - "Launcher Button": { - "Launcher Button": "" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "ランチャーのボタンロゴ" - }, - "Layout": { - "Layout": "レイアウト" - }, - "Layout Overrides": { - "Layout Overrides": "" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "左" - }, - "Left Center": { - "Left Center": "" - }, - "Left Section": { - "Left Section": "左セクション" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "ライトモード" - }, - "Light Rain": { - "Light Rain": "" - }, - "Light Snow": { - "Light Snow": "" - }, - "Light Snow Showers": { - "Light Snow Showers": "" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "" - }, - "Lines: %1": { - "Lines: %1": "行数: %1" - }, - "List": { - "List": "" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "彩度の高いアクセントを備えた生き生きとしたパレット。" - }, - "Load Average": { - "Load Average": "" - }, - "Loading codecs...": { - "Loading codecs...": "" - }, - "Loading keybinds...": { - "Loading keybinds...": "" - }, - "Loading trending...": { - "Loading trending...": "" - }, - "Loading...": { - "Loading...": "" - }, - "Local": { - "Local": "" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "" - }, - "Location Search": { - "Location Search": "ロケーション検索" - }, - "Lock": { - "Lock": "ロック" - }, - "Lock Screen": { - "Lock Screen": "ロック画面" - }, - "Lock Screen Display": { - "Lock Screen Display": "" - }, - "Lock Screen Format": { - "Lock Screen Format": "ロック画面のフォーマット" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "" - }, - "Lock Screen layout": { - "Lock Screen layout": "" - }, - "Lock at startup": { - "Lock at startup": "" - }, - "Lock before suspend": { - "Lock before suspend": "一時停止前にロック" - }, - "Lock fade grace period": { - "Lock fade grace period": "" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "" - }, - "Log Out": { - "Log Out": "ログアウト" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "" - }, - "Long Text": { - "Long Text": "長文" - }, - "Long press": { - "Long press": "" - }, - "Longitude": { - "Longitude": "経度" - }, - "Low Priority": { - "Low Priority": "低優先度" - }, - "MAC": { - "MAC": "" - }, - "MTU": { - "MTU": "" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "DMS 機能を拡張するためのプラグインを管理および構成" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "最大4つの独立したバー構成を管理できます。各バーには独自の位置、ウィジェット、スタイリング、表示割り当てがあります。" - }, - "Management": { - "Management": "" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "手動座標" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "手動ギャップサイズ" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "手動で表示/非表示" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "" - }, - "Margin": { - "Margin": "マージン" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "マーカー供給量がない" - }, - "Marker Supply Low": { - "Marker Supply Low": "マーカー供給量が少ない" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "マーカー廃棄物がほぼ満杯" - }, - "Marker Waste Full": { - "Marker Waste Full": "マーカー廃棄物がいっぱい" - }, - "Match Criteria": { - "Match Criteria": "" - }, - "Matches profile: %1": { - "Matches profile: %1": "" - }, - "Material Colors": { - "Material Colors": "Material Colors" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen Palette" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugenターゲットモニター" - }, - "Matugen Templates": { - "Matugen Templates": "" - }, - "Max Edges": { - "Max Edges": "" - }, - "Max H": { - "Max H": "" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "" - }, - "Max Running Apps": { - "Max Running Apps": "" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "" - }, - "Max Volume": { - "Max Volume": "" - }, - "Max W": { - "Max W": "" - }, - "Max apps to show": { - "Max apps to show": "表示するアプリの最大数" - }, - "Max to Edges": { - "Max to Edges": "" - }, - "Maximize": { - "Maximize": "" - }, - "Maximize Detection": { - "Maximize Detection": "" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "" - }, - "Maximum History": { - "Maximum History": "" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "" - }, - "Media": { - "Media": "メディア" - }, - "Media Controls": { - "Media Controls": "メディアコントロール" - }, - "Media Empty": { - "Media Empty": "メディアがない" - }, - "Media Jam": { - "Media Jam": "メディアジャム" - }, - "Media Low": { - "Media Low": "メディアロー" - }, - "Media Needed": { - "Media Needed": "メディアが必要" - }, - "Media Playback": { - "Media Playback": "" - }, - "Media Player": { - "Media Player": "" - }, - "Media Player Settings": { - "Media Player Settings": "メディアプレーヤーの設定" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "メディアプレーヤー(" - }, - "Media Volume": { - "Media Volume": "" - }, - "Medium": { - "Medium": "" - }, - "Memory": { - "Memory": "メモリ" - }, - "Memory Graph": { - "Memory Graph": "" - }, - "Memory Usage": { - "Memory Usage": "メモリ使用率" - }, - "Memory usage indicator": { - "Memory usage indicator": "メモリ使用率インジケーター" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "" - }, - "Message Content": { - "Message Content": "" - }, - "Microphone": { - "Microphone": "マイク" - }, - "Microphone Mute": { - "Microphone Mute": "" - }, - "Microphone Volume": { - "Microphone Volume": "" - }, - "Microphone settings": { - "Microphone settings": "" - }, - "Microphone volume control": { - "Microphone volume control": "" - }, - "Middle Section": { - "Middle Section": "中間区間" - }, - "Min H": { - "Min H": "" - }, - "Min W": { - "Min W": "" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "単一の色相を中心に構築された最小限のパレット。" - }, - "Minute": { - "Minute": "分" - }, - "Mirror Display": { - "Mirror Display": "" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "" - }, - "Modal Background": { - "Modal Background": "" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "" - }, - "Mode": { - "Mode": "" - }, - "Mode:": { - "Mode:": "モード:" - }, - "Model": { - "Model": "モデル" - }, - "Modified": { - "Modified": "" - }, - "Modular widget bar": { - "Modular widget bar": "" - }, - "Monitor": { - "Monitor": "" - }, - "Monitor Configuration": { - "Monitor Configuration": "" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "ダイナミックテーマの色を駆動する壁紙をモニター" - }, - "Monochrome": { - "Monochrome": "" - }, - "Monocle": { - "Monocle": "モノクル" - }, - "Monospace Font": { - "Monospace Font": "等幅フォント" - }, - "Month Date": { - "Month Date": "" - }, - "Morning": { - "Morning": "" - }, - "Mount Points": { - "Mount Points": "" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "" - }, - "Move": { - "Move": "" - }, - "Move Widget": { - "Move Widget": "" - }, - "Moving to Paused": { - "Moving to Paused": "一時停止への移行" - }, - "Multi-Monitor": { - "Multi-Monitor": "" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "" - }, - "Mute Popups": { - "Mute Popups": "" - }, - "Mute popups for %1": { - "Mute popups for %1": "" - }, - "Muted": { - "Muted": "" - }, - "Muted Apps": { - "Muted Apps": "" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "落ち着いた色調のパレット。" - }, - "NM not supported": { - "NM not supported": "NMが利用できません" - }, - "Name": { - "Name": "名称" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "名前付きワークスペースアイコン" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "ナビゲーション" - }, - "Network": { - "Network": "ネットワーク" - }, - "Network Graph": { - "Network Graph": "" - }, - "Network Info": { - "Network Info": "ネットワーク情報" - }, - "Network Information": { - "Network Information": "ネットワーク情報" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "ネットワーク速度モニター" - }, - "Network Status": { - "Network Status": "" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "ネットワークのダウンロードおよびアップロード速度を表示" - }, - "Neutral": { - "Neutral": "" - }, - "Never": { - "Never": "" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "新しい" - }, - "New Key": { - "New Key": "" - }, - "New Keybind": { - "New Keybind": "" - }, - "New Notification": { - "New Notification": "新しい通知" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "" - }, - "Next": { - "Next": "" - }, - "Next Transition": { - "Next Transition": "" - }, - "Night": { - "Night": "" - }, - "Night Mode": { - "Night Mode": "ナイトモード" - }, - "Night Temperature": { - "Night Temperature": "夜間の温度" - }, - "Night mode & gamma": { - "Night mode & gamma": "" - }, - "Niri Integration": { - "Niri Integration": "" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "" - }, - "No": { - "No": "" - }, - "No Active Players": { - "No Active Players": "アクティブプレイヤーなし" - }, - "No Anim": { - "No Anim": "" - }, - "No Background": { - "No Background": "背景なし" - }, - "No Battery": { - "No Battery": "" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Bluetoothアダプタが見つかりませんでした" - }, - "No Blur": { - "No Blur": "" - }, - "No Border": { - "No Border": "" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "" - }, - "No Dim": { - "No Dim": "" - }, - "No Focus": { - "No Focus": "" - }, - "No GPU detected": { - "No GPU detected": "" - }, - "No GPUs detected": { - "No GPUs detected": "" - }, - "No History": { - "No History": "" - }, - "No Media": { - "No Media": "メディアなし" - }, - "No Round": { - "No Round": "" - }, - "No Rounding": { - "No Rounding": "" - }, - "No Shadow": { - "No Shadow": "" - }, - "No VPN profiles": { - "No VPN profiles": "" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "" - }, - "No Weather Data Available": { - "No Weather Data Available": "気象データはありません" - }, - "No action": { - "No action": "" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "" - }, - "No adapters": { - "No adapters": "" - }, - "No app customizations.": { - "No app customizations.": "" - }, - "No apps found": { - "No apps found": "" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "" - }, - "No battery": { - "No battery": "" - }, - "No brightness devices available": { - "No brightness devices available": "" - }, - "No changes": { - "No changes": "" - }, - "No checks passed": { - "No checks passed": "" - }, - "No custom theme file": { - "No custom theme file": "" - }, - "No devices": { - "No devices": "" - }, - "No devices connected": { - "No devices connected": "" - }, - "No devices found": { - "No devices found": "" - }, - "No disk data": { - "No disk data": "" - }, - "No disk data available": { - "No disk data available": "" - }, - "No drivers found": { - "No drivers found": "" - }, - "No errors": { - "No errors": "" - }, - "No features enabled": { - "No features enabled": "" - }, - "No files found": { - "No files found": "ファイルが見つかりませんでした" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "" - }, - "No hidden apps.": { - "No hidden apps.": "" - }, - "No info items": { - "No info items": "" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "" - }, - "No input devices found": { - "No input devices found": "" - }, - "No items added yet": { - "No items added yet": "まだアイテムが追加されていません" - }, - "No keybinds found": { - "No keybinds found": "" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "" - }, - "No match criteria": { - "No match criteria": "" - }, - "No matches": { - "No matches": "一致するものはありません" - }, - "No matching processes": { - "No matching processes": "" - }, - "No monitors": { - "No monitors": "" - }, - "No mount points found": { - "No mount points found": "" - }, - "No output device": { - "No output device": "" - }, - "No output devices found": { - "No output devices found": "" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "" - }, - "No plugins found": { - "No plugins found": "プラグインが見つかりませんでした" - }, - "No plugins found.": { - "No plugins found.": "プラグインが見つかりませんでした。" - }, - "No printer found": { - "No printer found": "プリンターが見つかりませんでした" - }, - "No printers configured": { - "No printers configured": "" - }, - "No printers found": { - "No printers found": "" - }, - "No profiles": { - "No profiles": "" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "" - }, - "No results found": { - "No results found": "" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "" - }, - "No trigger": { - "No trigger": "" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "" - }, - "No warnings": { - "No warnings": "" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "" - }, - "No widgets available": { - "No widgets available": "" - }, - "No widgets match your search": { - "No widgets match your search": "" - }, - "No window rules configured": { - "No window rules configured": "" - }, - "None": { - "None": "ない" - }, - "Normal": { - "Normal": "" - }, - "Normal Font": { - "Normal Font": "" - }, - "Normal Priority": { - "Normal Priority": "通常の優先度" - }, - "Not available": { - "Not available": "" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "" - }, - "Not detected": { - "Not detected": "" - }, - "Not paired": { - "Not paired": "" - }, - "Not set": { - "Not set": "" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "" - }, - "Notepad": { - "Notepad": "メモ帳" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "メモ帳のフォント設定" - }, - "Notepad Slideout": { - "Notepad Slideout": "メモ帳スライドアウト" - }, - "Nothing": { - "Nothing": "" - }, - "Nothing to see here": { - "Nothing to see here": "ここには何もありません" - }, - "Notification Center": { - "Notification Center": "通知センター" - }, - "Notification Display": { - "Notification Display": "" - }, - "Notification Overlay": { - "Notification Overlay": "通知オーバーレイ" - }, - "Notification Popups": { - "Notification Popups": "通知ポップアップ" - }, - "Notification Rules": { - "Notification Rules": "" - }, - "Notification Settings": { - "Notification Settings": "通知設定" - }, - "Notification Timeouts": { - "Notification Timeouts": "通知タイムアウト" - }, - "Notification toast popups": { - "Notification toast popups": "通知トーストポップアップ" - }, - "Notifications": { - "Notifications": "通知" - }, - "Numbers": { - "Numbers": "数字" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "" - }, - "OK": { - "OK": "" - }, - "OS Logo": { - "OS Logo": "OSロゴ" - }, - "OSD Position": { - "OSD Position": "OSD位置" - }, - "Occupied Color": { - "Occupied Color": "" - }, - "Off": { - "Off": "" - }, - "Office": { - "Office": "オフィス" - }, - "Offline": { - "Offline": "" - }, - "Offline Report": { - "Offline Report": "オフライン報告" - }, - "Older": { - "Older": "" - }, - "On": { - "On": "" - }, - "On-Demand": { - "On-Demand": "" - }, - "On-Screen Displays": { - "On-Screen Displays": "オンスクリーンディスプレイ" - }, - "On-screen Displays": { - "On-screen Displays": "オンスクリーンディスプレイ" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "ガンマは、時間または場所のルールに基づいてのみ調整します。" - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "システムでサポートされている場合にのみ、休止状態が表示されます" - }, - "Opacity": { - "Opacity": "不透明度" - }, - "Opaque": { - "Opaque": "" - }, - "Open": { - "Open": "開ける" - }, - "Open App": { - "Open App": "" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "" - }, - "Open Notepad File": { - "Open Notepad File": "メモ帳ファイルを開く" - }, - "Open a new note": { - "Open a new note": "" - }, - "Open folder": { - "Open folder": "" - }, - "Open in Browser": { - "Open in Browser": "" - }, - "Open in terminal": { - "Open in terminal": "" - }, - "Open search bar to find text": { - "Open search bar to find text": "検索バーを開いてテキストを検索" - }, - "Open with...": { - "Open with...": "" - }, - "Opening SMS": { - "Opening SMS": "" - }, - "Opening SMS app": { - "Opening SMS app": "" - }, - "Opening file browser": { - "Opening file browser": "" - }, - "Opening files": { - "Opening files": "" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "" - }, - "Optional location": { - "Optional location": "" - }, - "Options": { - "Options": "" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "" - }, - "Original: %1": { - "Original: %1": "" - }, - "Other": { - "Other": "他" - }, - "Outline": { - "Outline": "" - }, - "Output": { - "Output": "" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "アウトプットエリアがほぼ満杯" - }, - "Output Area Full": { - "Output Area Full": "アウトプットエリアがいっぱい" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "" - }, - "Output Tray Missing": { - "Output Tray Missing": "アウトプットトレイが見つかりませんでした" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "" - }, - "Overcast": { - "Overcast": "" - }, - "Overflow": { - "Overflow": "" - }, - "Overridden by config": { - "Overridden by config": "" - }, - "Override": { - "Override": "" - }, - "Override Border Size": { - "Override Border Size": "" - }, - "Override Corner Radius": { - "Override Corner Radius": "" - }, - "Override Gaps": { - "Override Gaps": "" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "" - }, - "Overview": { - "Overview": "概要" - }, - "Overview of your network connections": { - "Overview of your network connections": "" - }, - "Overwrite": { - "Overwrite": "上書き" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "" - }, - "Pad": { - "Pad": "" - }, - "Pad Hours": { - "Pad Hours": "" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "パディング" - }, - "Pair": { - "Pair": "ペアリング" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Bluetoothデバイスのペアリング" - }, - "Paired": { - "Paired": "" - }, - "Pairing": { - "Pairing": "" - }, - "Pairing failed": { - "Pairing failed": "ペアリングが失敗しました" - }, - "Pairing request from": { - "Pairing request from": "" - }, - "Pairing request sent": { - "Pairing request sent": "" - }, - "Pairing requested": { - "Pairing requested": "" - }, - "Pairing...": { - "Pairing...": "" - }, - "Partly Cloudy": { - "Partly Cloudy": "" - }, - "Passkey:": { - "Passkey:": "パスキー:" - }, - "Password": { - "Password": "パスワード" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "" - }, - "Pause": { - "Pause": "一時停止" - }, - "Paused": { - "Paused": "一時停止" - }, - "Pending": { - "Pending": "" - }, - "Pending Charge": { - "Pending Charge": "" - }, - "Pending Discharge": { - "Pending Discharge": "" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "モードごとの壁紙" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "モニターごとの壁紙" - }, - "Per-screen config": { - "Per-screen config": "" - }, - "Percentage": { - "Percentage": "百分率" - }, - "Performance": { - "Performance": "" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "プロフィール画像の設定権限が拒否されました。" - }, - "Personalization": { - "Personalization": "パーソナライゼーション" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "" - }, - "Phone number": { - "Phone number": "" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "" - }, - "Pin": { - "Pin": "" - }, - "Pin to Dock": { - "Pin to Dock": "ドックにピン留め" - }, - "Ping": { - "Ping": "" - }, - "Ping sent": { - "Ping sent": "" - }, - "Ping sent to": { - "Ping sent to": "" - }, - "Pinned": { - "Pinned": "" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "" - }, - "Pixelate": { - "Pixelate": "" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "プラグインディレクトリをここに配置します。各プラグインには plugin.json マニフェストファイルが必要です。" - }, - "Place plugins in %1": { - "Place plugins in %1": "" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "新しい通知が届いたときにサウンドを再生" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "電源ケーブルを接続したときにサウンドを再生" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "音量を調整したときにサウンドを再生" - }, - "Play sounds for system events": { - "Play sounds for system events": "システムイベントが発生したときにサウンドを再生" - }, - "Playback": { - "Playback": "" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "接続" - }, - "Plugged in": { - "Plugged in": "" - }, - "Plugin": { - "Plugin": "" - }, - "Plugin Directory": { - "Plugin Directory": "プラグインディレクトリ" - }, - "Plugin Management": { - "Plugin Management": "プラグイン管理" - }, - "Plugin Visibility": { - "Plugin Visibility": "" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "プラグインは無効です - 使用するにはプラグイン設定で有効にしてください" - }, - "Plugins": { - "Plugins": "プラグイン" - }, - "Pointer": { - "Pointer": "" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "" - }, - "Popup Only": { - "Popup Only": "" - }, - "Popup Position": { - "Popup Position": "ポップアップの位置" - }, - "Popup Shadow": { - "Popup Shadow": "" - }, - "Popup Transparency": { - "Popup Transparency": "ポップアップの透明度" - }, - "Popup behavior, position": { - "Popup behavior, position": "" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "" - }, - "Position": { - "Position": "位置" - }, - "Position, pinned apps": { - "Position, pinned apps": "" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "" - }, - "Power": { - "Power": "" - }, - "Power & Security": { - "Power & Security": "電源とセキュリティ" - }, - "Power & Sleep": { - "Power & Sleep": "" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "電源アクションの確認" - }, - "Power Menu Customization": { - "Power Menu Customization": "電源メニューのカスタマイズ" - }, - "Power Off": { - "Power Off": "電源オフ" - }, - "Power Options": { - "Power Options": "電源オプション" - }, - "Power Profile": { - "Power Profile": "" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "電源プロファイルの劣化" - }, - "Power Saver": { - "Power Saver": "" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "" - }, - "Power profile management available": { - "Power profile management available": "" - }, - "Power source": { - "Power source": "" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "" - }, - "Precipitation": { - "Precipitation": "" - }, - "Precipitation Chance": { - "Precipitation Chance": "" - }, - "Preference": { - "Preference": "" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "" - }, - "Press key...": { - "Press key...": "" - }, - "Pressure": { - "Pressure": "プレッシャー" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "画面のタイムアウトを防止" - }, - "Preview": { - "Preview": "" - }, - "Primary": { - "Primary": "プライマリー" - }, - "Primary Container": { - "Primary Container": "" - }, - "Print Server Management": { - "Print Server Management": "" - }, - "Print Server not available": { - "Print Server not available": "プリントサーバーが利用できません" - }, - "Printer": { - "Printer": "" - }, - "Printer Classes": { - "Printer Classes": "" - }, - "Printer created successfully": { - "Printer created successfully": "" - }, - "Printer deleted": { - "Printer deleted": "" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "プリンター" - }, - "Printers: ": { - "Printers: ": "プリンター: " - }, - "Prioritize performance": { - "Prioritize performance": "" - }, - "Priority": { - "Priority": "" - }, - "Privacy Indicator": { - "Privacy Indicator": "プライバシーインジケーター" - }, - "Privacy Mode": { - "Privacy Mode": "" - }, - "Private Key Password": { - "Private Key Password": "" - }, - "Process Count": { - "Process Count": "" - }, - "Processes": { - "Processes": "" - }, - "Processes:": { - "Processes:": "" - }, - "Processing": { - "Processing": "進行中" - }, - "Profile Image Error": { - "Profile Image Error": "プロフィール画像エラー" - }, - "Profile activated: %1": { - "Profile activated: %1": "" - }, - "Profile deleted": { - "Profile deleted": "" - }, - "Profile error": { - "Profile error": "" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "プロフィール画像が大きすぎます。より小さい画像を使用してください。" - }, - "Profile name": { - "Profile name": "" - }, - "Profile not found": { - "Profile not found": "" - }, - "Profile saved: %1": { - "Profile saved: %1": "" - }, - "Protocol": { - "Protocol": "" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "アプリケーションランチャーへのクイックアクセス" - }, - "Quick access to color picker": { - "Quick access to color picker": "カラーピッカーへのクイックアクセス" - }, - "Quick access to notepad": { - "Quick access to notepad": "メモ帳へのクイックアクセス" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "クイックノート作成スライドアウトパネル" - }, - "Quick system toggles": { - "Quick system toggles": "" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "" - }, - "Rain": { - "Rain": "" - }, - "Rain Chance": { - "Rain Chance": "降水確率" - }, - "Rainbow": { - "Rainbow": "" - }, - "Random": { - "Random": "" - }, - "Rate": { - "Rate": "" - }, - "Read:": { - "Read:": "" - }, - "Reason": { - "Reason": "原因" - }, - "Reboot": { - "Reboot": "再起動" - }, - "Recent Colors": { - "Recent Colors": "最近の色" - }, - "Recently Used Apps": { - "Recently Used Apps": "最近使用したアプリ" - }, - "Recommended available": { - "Recommended available": "" - }, - "Refresh": { - "Refresh": "リフレッシュ" - }, - "Refresh Weather": { - "Refresh Weather": "" - }, - "Regex": { - "Regex": "" - }, - "Reject": { - "Reject": "" - }, - "Reject Jobs": { - "Reject Jobs": "" - }, - "Release": { - "Release": "" - }, - "Reload Plugin": { - "Reload Plugin": "プラグインをリロード" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "削除" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "" - }, - "Rename": { - "Rename": "" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "" - }, - "Repeat": { - "Repeat": "" - }, - "Replacement": { - "Replacement": "" - }, - "Report": { - "Report": "報告" - }, - "Request Pairing": { - "Request Pairing": "" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "" - }, - "Requires DMS %1": { - "Requires DMS %1": "" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "DWLコンポジターが必要" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "" - }, - "Reset": { - "Reset": "リセット" - }, - "Reset Position": { - "Reset Position": "" - }, - "Reset Size": { - "Reset Size": "" - }, - "Reset to default name": { - "Reset to default name": "" - }, - "Resize Widget": { - "Resize Widget": "" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "" - }, - "Restart DMS": { - "Restart DMS": "DMSを再起動" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "DankMaterialShellを再起動" - }, - "Restarting audio system...": { - "Restarting audio system...": "" - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "レジュメ" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "" - }, - "Revert": { - "Revert": "戻す" - }, - "Right": { - "Right": "右" - }, - "Right Center": { - "Right Center": "" - }, - "Right Section": { - "Right Section": "右セクション" - }, - "Right Tiling": { - "Right Tiling": "右タイリング" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "バーウィジェットを右クリックして循環" - }, - "Ring": { - "Ring": "" - }, - "Ringing": { - "Ringing": "" - }, - "Ripple Effects": { - "Ripple Effects": "" - }, - "Root Filesystem": { - "Root Filesystem": "" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "" - }, - "Rule": { - "Rule": "" - }, - "Rule Name": { - "Rule Name": "" - }, - "Rules (%1)": { - "Rules (%1)": "" - }, - "Run Again": { - "Run Again": "" - }, - "Run DMS Templates": { - "Run DMS Templates": "" - }, - "Run User Templates": { - "Run User Templates": "ユーザーのテンプレを実行" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "" - }, - "Running Apps": { - "Running Apps": "実行中のアプリ" - }, - "Running Apps Settings": { - "Running Apps Settings": "実行中のアプリの設定" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "" - }, - "SDR Saturation": { - "SDR Saturation": "" - }, - "SMS": { - "SMS": "" - }, - "Save": { - "Save": "保存" - }, - "Save Notepad File": { - "Save Notepad File": "メモ帳ファイルを保存" - }, - "Save QR Code": { - "Save QR Code": "" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "" - }, - "Save password": { - "Save password": "パスワードを保存" - }, - "Saved": { - "Saved": "保存されました" - }, - "Saved Configurations": { - "Saved Configurations": "" - }, - "Saved Note": { - "Saved Note": "" - }, - "Saved item deleted": { - "Saved item deleted": "" - }, - "Saving...": { - "Saving...": "" - }, - "Scale": { - "Scale": "" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Dank Barのフォントサイズを個別に調整" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "" - }, - "Scan": { - "Scan": "スキャン" - }, - "Scanning": { - "Scanning": "" - }, - "Scanning...": { - "Scanning...": "" - }, - "Science": { - "Science": "科学" - }, - "Score": { - "Score": "" - }, - "Screen Sharing": { - "Screen Sharing": "" - }, - "Screen sharing": { - "Screen sharing": "画面共有" - }, - "Scroll": { - "Scroll": "" - }, - "Scroll Factor": { - "Scroll Factor": "" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "" - }, - "Scroll song title": { - "Scroll song title": "" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "" - }, - "Scrolling": { - "Scrolling": "スクロール" - }, - "Search App Actions": { - "Search App Actions": "" - }, - "Search Options": { - "Search Options": "" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "" - }, - "Search for a location...": { - "Search for a location...": "ロケーションを検索..." - }, - "Search keybinds...": { - "Search keybinds...": "" - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "" - }, - "Search plugins...": { - "Search plugins...": "プラグインを検索..." - }, - "Search processes...": { - "Search processes...": "" - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "" - }, - "Search widgets...": { - "Search widgets...": "" - }, - "Search...": { - "Search...": "検索..." - }, - "Searching...": { - "Searching...": "検索中..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "" - }, - "Secured": { - "Secured": "" - }, - "Security": { - "Security": "" - }, - "Security & privacy": { - "Security & privacy": "" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "" - }, - "Select Application": { - "Select Application": "" - }, - "Select Bar": { - "Select Bar": "" - }, - "Select Custom Theme": { - "Select Custom Theme": "カスタムテーマを選んでください" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "" - }, - "Select File to Send": { - "Select File to Send": "" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "ランチャーロゴを選ぶ" - }, - "Select Profile Image": { - "Select Profile Image": "プロファイル画像を選んでください" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "壁紙を選んでください" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "壁紙のディレクトリを選んでください" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "パレットから色を選ぶか、カスタムスライダーを使用します" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "" - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "" - }, - "Select a window...": { - "Select a window...": "" - }, - "Select an image file...": { - "Select an image file...": "画像ファイルを選ぶ..." - }, - "Select at least one provider": { - "Select at least one provider": "" - }, - "Select device": { - "Select device": "" - }, - "Select device...": { - "Select device...": "" - }, - "Select driver...": { - "Select driver...": "" - }, - "Select font weight for UI text": { - "Select font weight for UI text": "" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "壁紙を設定するモニターを選ぶ" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "プロセスリストと技術表示用の等幅フォントを選ぶ" - }, - "Select network": { - "Select network": "" - }, - "Select system sound theme": { - "Select system sound theme": "システムサウンドテーマを選ぶ" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "壁紙ベースの色で、使用するパレットアルゴリズムを選ぶ" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "含めたいトランジションをランダム化に選択" - }, - "Select...": { - "Select...": "" - }, - "Selected image file not found.": { - "Selected image file not found.": "選択した画像ファイルが見つかりませんでした。" - }, - "Send": { - "Send": "" - }, - "Send Clipboard": { - "Send Clipboard": "" - }, - "Send File": { - "Send File": "" - }, - "Send SMS": { - "Send SMS": "" - }, - "Sending": { - "Sending": "" - }, - "Separator": { - "Separator": "区切り" - }, - "Server": { - "Server": "" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "" - }, - "Set custom name": { - "Set custom name": "" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "接続されているモニターごとに異なる壁紙を設定する" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "ライトモードとダークモードで異なる壁紙を設定する" - }, - "Set key and action to save": { - "Set key and action to save": "" - }, - "Set notification rules": { - "Set notification rules": "" - }, - "Settings": { - "Settings": "設定" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "" - }, - "Setup": { - "Setup": "" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "" - }, - "Share Text": { - "Share Text": "" - }, - "Share URL": { - "Share URL": "" - }, - "Shared": { - "Shared": "" - }, - "Shell": { - "Shell": "" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: すべてクリア • Esc: 閉じる" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "" - }, - "Short": { - "Short": "" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "" - }, - "Show": { - "Show": "" - }, - "Show 3rd Party": { - "Show 3rd Party": "" - }, - "Show All Tags": { - "Show All Tags": "すべてのタグを表示" - }, - "Show Badge": { - "Show Badge": "" - }, - "Show CPU": { - "Show CPU": "" - }, - "Show CPU Graph": { - "Show CPU Graph": "" - }, - "Show CPU Temp": { - "Show CPU Temp": "" - }, - "Show Date": { - "Show Date": "" - }, - "Show Disk": { - "Show Disk": "" - }, - "Show Dock": { - "Show Dock": "ドックを表示" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "" - }, - "Show Footer": { - "Show Footer": "" - }, - "Show Forecast": { - "Show Forecast": "" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "" - }, - "Show Header": { - "Show Header": "" - }, - "Show Hibernate": { - "Show Hibernate": "休止状態を表示" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "" - }, - "Show Humidity": { - "Show Humidity": "" - }, - "Show Launcher Button": { - "Show Launcher Button": "" - }, - "Show Line Numbers": { - "Show Line Numbers": "行番号を表示" - }, - "Show Location": { - "Show Location": "" - }, - "Show Lock": { - "Show Lock": "ロックを表示" - }, - "Show Log Out": { - "Show Log Out": "ログアウトを表示" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "" - }, - "Show Media Player": { - "Show Media Player": "" - }, - "Show Memory": { - "Show Memory": "" - }, - "Show Memory Graph": { - "Show Memory Graph": "" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "" - }, - "Show Network Graph": { - "Show Network Graph": "" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "" - }, - "Show Password Field": { - "Show Password Field": "" - }, - "Show Power Actions": { - "Show Power Actions": "" - }, - "Show Power Off": { - "Show Power Off": "パワーオフを表示" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "" - }, - "Show Pressure": { - "Show Pressure": "" - }, - "Show Profile Image": { - "Show Profile Image": "" - }, - "Show Reboot": { - "Show Reboot": "再起動を表示" - }, - "Show Restart DMS": { - "Show Restart DMS": "DMS再起動を表示" - }, - "Show Saved Items": { - "Show Saved Items": "" - }, - "Show Seconds": { - "Show Seconds": "" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "" - }, - "Show Suspend": { - "Show Suspend": "一時停止を表示" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "" - }, - "Show System Icons": { - "Show System Icons": "" - }, - "Show System Time": { - "Show System Time": "" - }, - "Show Top Processes": { - "Show Top Processes": "" - }, - "Show Weather Condition": { - "Show Weather Condition": "" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "" - }, - "Show Wind Speed": { - "Show Wind Speed": "" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "ワークスペースアプリを表示" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "占有タグのみではなく、9 つのタグをすべて表示 (DWL のみ)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "モーダルダイアログの背後に暗いオーバーレイを表示" - }, - "Show device": { - "Show device": "" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "" - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "最後のディスプレイに表示" - }, - "Show on Overlay": { - "Show on Overlay": "" - }, - "Show on Overview": { - "Show on Overview": "概要に表示" - }, - "Show on Overview Only": { - "Show on Overview Only": "" - }, - "Show on all connected displays": { - "Show on all connected displays": "すべての接続されたディスプレイに表示" - }, - "Show on screens:": { - "Show on screens:": "画面に表示:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "明るさが変化した時にOSDを表示" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Caps Lock の状態が変化した時にOSDを表示" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "アイドルインヒビターの状態が変化した時にOSDを表示" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "メディアプレーヤーの音量が変化したときにOSDを表示" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "マイクがミュート/ミュート解除された時にOSDを表示" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "電源プロファイルが変化した時にOSDを表示" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "音量が変化したときにOSDを表示" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "トップバーとコントロールセンターに天気情報を表示" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "上部バーのワークスペーススイッチャーにワークスペースインデックス番号を表示" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "実行中のすべてのアプリケーションをフォーカス状態で表示" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "現在のワークスペースを表示、切り替えを可能に" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Caps Lock がアクティブなときに表示" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "マイク、カメラ、または画面共有がアクティブなときに表示" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "シャットダウン" - }, - "Signal": { - "Signal": "" - }, - "Signal:": { - "Signal:": "" - }, - "Size": { - "Size": "サイズ" - }, - "Size Constraints": { - "Size Constraints": "" - }, - "Size Offset": { - "Size Offset": "サイズオフセット" - }, - "Sizing": { - "Sizing": "" - }, - "Skip": { - "Skip": "" - }, - "Skip confirmation": { - "Skip confirmation": "" - }, - "Skip setup": { - "Skip setup": "" - }, - "Small": { - "Small": "" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "" - }, - "Smartcard PIN": { - "Smartcard PIN": "" - }, - "Snap": { - "Snap": "" - }, - "Snow": { - "Snow": "" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "アルファベット順に並べ替える" - }, - "Sort By": { - "Sort By": "" - }, - "Sorting & Layout": { - "Sorting & Layout": "" - }, - "Sound Theme": { - "Sound Theme": "サウンドテーマ" - }, - "Sounds": { - "Sounds": "" - }, - "Space between windows": { - "Space between windows": "" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "" - }, - "Spacer": { - "Spacer": "間隔" - }, - "Spacing": { - "Spacing": "間隔" - }, - "Speaker settings": { - "Speaker settings": "" - }, - "Speed": { - "Speed": "" - }, - "Spool Area Full": { - "Spool Area Full": "スプールエリアがいっぱい" - }, - "Square Corners": { - "Square Corners": "四角コーナー" - }, - "Stacked": { - "Stacked": "" - }, - "Standard": { - "Standard": "" - }, - "Start": { - "Start": "始める" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "ここでメモを入力しましょう..." - }, - "State": { - "State": "" - }, - "Status": { - "Status": "状態" - }, - "Stopped": { - "Stopped": "停止" - }, - "Stopped Partly": { - "Stopped Partly": "一部停止" - }, - "Stopping": { - "Stopping": "停止中" - }, - "Stretch": { - "Stretch": "" - }, - "Stripes": { - "Stripes": "" - }, - "Summary": { - "Summary": "" - }, - "Sunrise": { - "Sunrise": "" - }, - "Sunset": { - "Sunset": "" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "" - }, - "Surface": { - "Surface": "表面" - }, - "Surface Variant": { - "Surface Variant": "" - }, - "Suspend": { - "Suspend": "一時停止" - }, - "Suspend behavior": { - "Suspend behavior": "一時停止の行為" - }, - "Suspend system after": { - "Suspend system after": "後にシステムを一時停止" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "ユーザーを切り替える" - }, - "Switch to power profile": { - "Switch to power profile": "" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "ポータルとの同期モード" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "ダークモードをシステム全体のテーマヒントの設定ポータルと同期" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "システム" - }, - "System App Theming": { - "System App Theming": "システムアプリのテーマ設定" - }, - "System Check": { - "System Check": "" - }, - "System Default": { - "System Default": "" - }, - "System Information": { - "System Information": "" - }, - "System Monitor": { - "System Monitor": "システムモニタ" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "システムモニターが利用できません" - }, - "System Sounds": { - "System Sounds": "" - }, - "System Tray": { - "System Tray": "システムトレイ" - }, - "System Update": { - "System Update": "システムアップデート" - }, - "System Updater": { - "System Updater": "システムアップデーター" - }, - "System Updates": { - "System Updates": "システムアップデート" - }, - "System notification area icons": { - "System notification area icons": "システム通知エリアアイコン" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "" - }, - "System theme toggle": { - "System theme toggle": "" - }, - "System toast notifications": { - "System toast notifications": "システムトースト通知" - }, - "System update custom command": { - "System update custom command": "システム更新カスタムコマンド" - }, - "Tab": { - "Tab": "" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: ナビゲーション • ←→↑↓: グリッドナビゲーション • Enter/Space: 選択" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "端末のカスタム追加パラメーター" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "端末 - 常にダークテーマを使用" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "" - }, - "Test page sent to printer": { - "Test page sent to printer": "" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "テキスト" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "DMS_SOCKET環境変数が設定されていないか、ソケットが利用できません。自動プラグイン管理にはDMS_SOCKETが必要です。" - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "以下の設定は、GTKとQtの設定を変更します。現在の設定を維持したい場合は、バックアップを作成してください(qt5ct.conf|qt6ct.conf および ~/.config/gtk-3.0|gtk-4.0)。" - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "このプリンタのジョブ待ち行列は空です" - }, - "Theme & Colors": { - "Theme & Colors": "テーマおよびカラー" - }, - "Theme Color": { - "Theme Color": "テーマカラー" - }, - "Theme Registry": { - "Theme Registry": "" - }, - "Themes": { - "Themes": "" - }, - "Thickness": { - "Thickness": "" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "サードパーティ製プラグインの警告" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "" - }, - "This may take a few seconds": { - "This may take a few seconds": "" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "このウィジェットはGPUの省電力状態を防ぎ、ノートパソコンのバッテリー寿命に大きな影響を与える可能性があります。ハイブリッドグラフィックス搭載のノートパソコンでの使用は推奨されません。" - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "これはすべてのクリップボード履歴を完全に削除します。" - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "" - }, - "Thunderstorm": { - "Thunderstorm": "" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "" - }, - "Tile": { - "Tile": "" - }, - "Tile H": { - "Tile H": "" - }, - "Tile V": { - "Tile V": "" - }, - "Tiled": { - "Tiled": "" - }, - "Tiled State": { - "Tiled State": "" - }, - "Tiling": { - "Tiling": "タイリング" - }, - "Time": { - "Time": "" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "時間および天気" - }, - "Time Format": { - "Time Format": "" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "" - }, - "Time until full: %1": { - "Time until full: %1": "" - }, - "Timed Out": { - "Timed Out": "タイムアウト" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "" - }, - "Title": { - "Title": "" - }, - "Title regex (optional)": { - "Title regex (optional)": "" - }, - "To Full": { - "To Full": "フルへ" - }, - "To update, run the following command:": { - "To update, run the following command:": "更新するには以下のコマンドを実行してください:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "" - }, - "Toast Messages": { - "Toast Messages": "トーストメッセージ" - }, - "Today": { - "Today": "今日" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "このバー構成の可視性を切り替える" - }, - "Toggling...": { - "Toggling...": "" - }, - "Tomorrow": { - "Tomorrow": "明日" - }, - "Tonal Spot": { - "Tonal Spot": "" - }, - "Toner Empty": { - "Toner Empty": "トナーが空です" - }, - "Toner Low": { - "Toner Low": "トナーが低い" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "" - }, - "Top": { - "Top": "トップ" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "トップバー形式" - }, - "Top Center": { - "Top Center": "" - }, - "Top Left": { - "Top Left": "" - }, - "Top Processes": { - "Top Processes": "" - }, - "Top Right": { - "Top Right": "" - }, - "Top Section": { - "Top Section": "トップセクション" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "" - }, - "Transition Effect": { - "Transition Effect": "トランジション効果" - }, - "Transparency": { - "Transparency": "" - }, - "Trending GIFs": { - "Trending GIFs": "" - }, - "Trending Stickers": { - "Trending Stickers": "" - }, - "Trigger": { - "Trigger": "" - }, - "Trigger Prefix": { - "Trigger Prefix": "" - }, - "Trigger: %1": { - "Trigger: %1": "" - }, - "Trust": { - "Trust": "" - }, - "Try a different search": { - "Try a different search": "" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "" - }, - "Turn off monitors after": { - "Turn off monitors after": "後にモニターの電源を切る" - }, - "Type": { - "Type": "" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "" - }, - "Type to search files": { - "Type to search files": "" - }, - "Typography": { - "Typography": "" - }, - "Typography & Motion": { - "Typography & Motion": "" - }, - "Unavailable": { - "Unavailable": "" - }, - "Unfocused Color": { - "Unfocused Color": "" - }, - "Ungrouped": { - "Ungrouped": "" - }, - "Uninstall": { - "Uninstall": "" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "プラグインをアンインストール" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "" - }, - "Unknown": { - "Unknown": "" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "" - }, - "Unknown Config": { - "Unknown Config": "" - }, - "Unknown Device": { - "Unknown Device": "" - }, - "Unknown GPU": { - "Unknown GPU": "" - }, - "Unknown Monitor": { - "Unknown Monitor": "" - }, - "Unknown Network": { - "Unknown Network": "" - }, - "Unknown Title": { - "Unknown Title": "" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "" - }, - "Unmute": { - "Unmute": "" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "" - }, - "Unnamed Rule": { - "Unnamed Rule": "" - }, - "Unpair": { - "Unpair": "" - }, - "Unpair failed": { - "Unpair failed": "" - }, - "Unpin": { - "Unpin": "" - }, - "Unpin from Dock": { - "Unpin from Dock": "ドックから固定を解除" - }, - "Unsaved Changes": { - "Unsaved Changes": "保存されていない変更" - }, - "Unsaved changes": { - "Unsaved changes": "保存されていない変更" - }, - "Unsaved note...": { - "Unsaved note...": "保存されていないメモ..." - }, - "Untitled": { - "Untitled": "無題" - }, - "Untrust": { - "Untrust": "" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "" - }, - "Update All": { - "Update All": "すべて更新" - }, - "Update Plugin": { - "Update Plugin": "プラグインを更新" - }, - "Uptime": { - "Uptime": "" - }, - "Uptime:": { - "Uptime:": "" - }, - "Urgent Color": { - "Urgent Color": "" - }, - "Usage Tips": { - "Usage Tips": "" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "12時間制のAM/PMではなく、24時間表記を使用" - }, - "Use Custom Command": { - "Use Custom Command": "カスタムコマンドを使用" - }, - "Use Grid Layout": { - "Use Grid Layout": "グリッドレイアウトを使用" - }, - "Use IP Location": { - "Use IP Location": "IP ロケーションの使用" - }, - "Use Imperial Units": { - "Use Imperial Units": "インペリアル単位を使用" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "メートル法(°C、km / h、hPa)の代わりにインペリアル単位(°F、mph、inHg)を使用" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "等幅フォントを使用" - }, - "Use System Theme": { - "Use System Theme": "システムテーマを使用" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "" - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "アニメーション化されたウェーブの進行状況バーをメディア再生に使用" - }, - "Use custom border size": { - "Use custom border size": "" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "カスタムコマンドを使用してシステムを更新" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "ダークテーマではなく、ライトテーマを使用" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "システム設定からサウンドテーマを使用" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "" - }, - "User": { - "User": "" - }, - "Username": { - "Username": "ユーザー名" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "あなたの位置情報に基づいて、日の出と日の入りの時間を使ってナイトモードを自動調整します。" - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "" - }, - "Utilities": { - "Utilities": "ユーティリティ" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN接続" - }, - "VPN Password": { - "VPN Password": "" - }, - "VPN configuration updated": { - "VPN configuration updated": "" - }, - "VPN connections": { - "VPN connections": "" - }, - "VPN deleted": { - "VPN deleted": "" - }, - "VPN imported: %1": { - "VPN imported: %1": "" - }, - "VPN not available": { - "VPN not available": "" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPNステータスとクイック接続" - }, - "VRR": { - "VRR": "" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "" - }, - "VRR On-Demand": { - "VRR On-Demand": "" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "" - }, - "Verification": { - "Verification": "" - }, - "Version": { - "Version": "" - }, - "Vertical Deck": { - "Vertical Deck": "垂直デッキ" - }, - "Vertical Grid": { - "Vertical Grid": "垂直グリッド" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "垂直スクロール" - }, - "Vertical Tiling": { - "Vertical Tiling": "垂直タイリング" - }, - "Vibrant": { - "Vibrant": "" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "遊び心のある彩度の鮮やかなパレット。" - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "" - }, - "View Mode": { - "View Mode": "" - }, - "Visibility": { - "Visibility": "可視性" - }, - "Visual Effects": { - "Visual Effects": "" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "ウィジェット間の視覚的分離" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "壁紙が変更される時に使用されるビジュアルエフェクト" - }, - "Volume": { - "Volume": "" - }, - "Volume Changed": { - "Volume Changed": "音量変更" - }, - "Volume Slider": { - "Volume Slider": "" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "音量、明るさ、その他のシステム OSD" - }, - "WPA/WPA2": { - "WPA/WPA2": "" - }, - "Wallpaper": { - "Wallpaper": "壁紙" - }, - "Wallpaper Error": { - "Wallpaper Error": "" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "壁紙モニター" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "" - }, - "Wallpapers": { - "Wallpapers": "壁紙" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "" - }, - "Warning": { - "Warning": "警告" - }, - "Warnings": { - "Warnings": "" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "ウェーブプログレスバー" - }, - "Weather": { - "Weather": "天気" - }, - "Weather Widget": { - "Weather Widget": "天気ウィジェット" - }, - "Welcome": { - "Welcome": "" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "有効にすると、アプリはアルファベット順に並べ替えられます。無効にすると、アプリは使用頻度で並べ替えられます。" - }, - "When locked": { - "When locked": "" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "" - }, - "WiFi": { - "WiFi": "" - }, - "WiFi Device": { - "WiFi Device": "" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "" - }, - "WiFi disabled": { - "WiFi disabled": "WiFiを無効化にしました" - }, - "WiFi enabled": { - "WiFi enabled": "WiFiを有効化にしました" - }, - "WiFi is off": { - "WiFi is off": "Wi-Fiはオフ中" - }, - "WiFi off": { - "WiFi off": "" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "" - }, - "Widget Background Color": { - "Widget Background Color": "ウィジェットの背景色" - }, - "Widget Management": { - "Widget Management": "ウィジェット管理" - }, - "Widget Outline": { - "Widget Outline": "" - }, - "Widget Style": { - "Widget Style": "ウィジェットのスタイル" - }, - "Widget Styling": { - "Widget Styling": "ウィジェットのスタイル" - }, - "Widget Transparency": { - "Widget Transparency": "ウィジェットの透明度" - }, - "Widget added": { - "Widget added": "" - }, - "Widget removed": { - "Widget removed": "" - }, - "Widgets": { - "Widgets": "" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "" - }, - "Width": { - "Width": "" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "" - }, - "Wind": { - "Wind": "風" - }, - "Wind Speed": { - "Wind Speed": "" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "" - }, - "Window Corner Radius": { - "Window Corner Radius": "" - }, - "Window Gaps": { - "Window Gaps": "" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "" - }, - "Window Height": { - "Window Height": "" - }, - "Window Opening": { - "Window Opening": "" - }, - "Window Rounding": { - "Window Rounding": "" - }, - "Window Rules": { - "Window Rules": "" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "" - }, - "Wipe": { - "Wipe": "" - }, - "Workspace": { - "Workspace": "ワークスペース" - }, - "Workspace Appearance": { - "Workspace Appearance": "" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "ワークスペースのインデックス番号" - }, - "Workspace Names": { - "Workspace Names": "" - }, - "Workspace Padding": { - "Workspace Padding": "ワークスペースのパディング" - }, - "Workspace Settings": { - "Workspace Settings": "ワークスペース設定" - }, - "Workspace Switcher": { - "Workspace Switcher": "ワークスペーススイッチャー" - }, - "Workspace name": { - "Workspace name": "" - }, - "Workspaces": { - "Workspaces": "" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "" - }, - "Write:": { - "Write:": "" - }, - "X Axis": { - "X Axis": "" - }, - "Y Axis": { - "Y Axis": "" - }, - "Yes": { - "Yes": "" - }, - "Yesterday": { - "Yesterday": "" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "保存されていない変更があります。このタブを閉じる前に保存しますか?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "保存されていない変更があります。続行する前に保存しますか?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "保存されていない変更があります。新しいファイルを作成する前に保存しますか?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "保存されていない変更があります。ファイルを開く前に保存しますか?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "" - }, - "You're All Set!": { - "You're All Set!": "" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "" - }, - "by %1": { - "by %1": "" - }, - "days": { - "days": "" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "" - }, - "devices connected": { - "devices connected": "" - }, - "dgop not available": { - "dgop not available": "" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "" - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "イベント" - }, - "ext": { - "ext": "" - }, - "featured": { - "featured": "" - }, - "leave empty for default": { - "leave empty for default": "" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctlが利用できません- ロック統合のためにDMS socketの接続が必要です。" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "" - }, - "minutes": { - "minutes": "" - }, - "ms": { - "ms": "" - }, - "nav": { - "nav": "" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "" - }, - "official": { - "official": "公式" - }, - "on Hyprland": { - "on Hyprland": "" - }, - "on MangoWC": { - "on MangoWC": "" - }, - "on Miracle WM": { - "on Miracle WM": "" - }, - "on Niri": { - "on Niri": "" - }, - "on Scroll": { - "on Scroll": "" - }, - "on Sway": { - "on Sway": "" - }, - "open": { - "open": "" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "" - }, - "source": { - "source": "" - }, - "this app": { - "this app": "" - }, - "up": { - "up": "" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "NM統合のためにDMSを更新します。" - }, - "v%1 by %2": { - "v%1 by %2": "" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• 信頼できるソースからのみインストールする" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - 月 (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - 月 (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - 月(1月)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - 月(1月)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• プラグインにはバグやセキュリティ上の問題が含まれている可能性があります" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• 可能であればインストール前にコードを確認してください" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - 日(1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - 日 (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - 曜日名(月)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - 曜日名(月曜日)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - 年 (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - 年(2024年)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/nl.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/nl.json deleted file mode 100644 index 5dcc166..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/nl.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 animatiesnelheid" - }, - "%1 Sessions": { - "%1 Sessions": "%1 sessies" - }, - "%1 active session": { - "%1 active session": "%1 actieve sessie" - }, - "%1 active sessions": { - "%1 active sessions": "%1 actieve sessies" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 adapter, geen verbonden" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 adapters, geen verbonden" - }, - "%1 character": { - "%1 character": "%1 teken" - }, - "%1 characters": { - "%1 characters": "%1 tekens" - }, - "%1 connected": { - "%1 connected": "%1 verbonden" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 aangepaste animatieduur" - }, - "%1 disconnected": { - "%1 disconnected": "%1 verbroken" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 verbroken (verborgen)" - }, - "%1 display": { - "%1 display": "%1 scherm" - }, - "%1 displays": { - "%1 displays": "%1 schermen" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 bestaat maar is niet opgenomen in config. Aangepaste sneltoetsen werken pas als dit is opgelost." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 bestaat maar is niet opgenomen. Vensterregels zijn niet van toepassing." - }, - "%1 filtered": { - "%1 filtered": "%1 gefilterd" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 is nu opgenomen in config" - }, - "%1 issue found": { - "%1 issue found": "%1 probleem gevonden" - }, - "%1 issues found": { - "%1 issues found": "%1 problemen gevonden" - }, - "%1 notifications": { - "%1 notifications": "%1 meldingen" - }, - "%1 update": { - "%1 update": "%1 update" - }, - "%1 updates": { - "%1 updates": "%1 updates" - }, - "%1 variants": { - "%1 variants": "%1 varianten" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 achtergrond • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 achtergronden • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 widgets" - }, - "%1 window": { - "%1 window": "%1 venster" - }, - "%1 windows": { - "%1 windows": "%1 vensters" - }, - "%1m ago": { - "%1m ago": "%1m geleden" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "'Alternatief' laat de sleutel zelfstandig ontgrendelen. 'Tweede factor' vereist eerst een wachtwoord of vingerafdruk en daarna pas de sleutel." - }, - "(Default)": { - "(Default)": "(Standaard)" - }, - "(Unnamed)": { - "(Unnamed)": "(Naamloos)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 meer" - }, - "/path/to/videos": { - "/path/to/videos": "/pad/naar/video's" - }, - "0 = square corners": { - "0 = square corners": "0 = vierkante hoeken" - }, - "1 day": { - "1 day": "1 dag" - }, - "1 device connected": { - "1 device connected": "1 apparaat verbonden" - }, - "1 event": { - "1 event": "1 afspraak" - }, - "1 hour": { - "1 hour": "1 uur" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 uur 30 minuten" - }, - "1 minute": { - "1 minute": "1 minuut" - }, - "1 notification": { - "1 notification": "1 melding" - }, - "1 second": { - "1 second": "1 seconde" - }, - "10 minutes": { - "10 minutes": "10 minuten" - }, - "10 seconds": { - "10 seconds": "10 seconden" - }, - "10-bit Color": { - "10-bit Color": "10-bits kleur" - }, - "12 hours": { - "12 hours": "12 uur" - }, - "14 days": { - "14 days": "14 dagen" - }, - "15 minutes": { - "15 minutes": "15 minuten" - }, - "15 seconds": { - "15 seconds": "15 seconden" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 uur" - }, - "2 minutes": { - "2 minutes": "2 minuten" - }, - "2 seconds": { - "2 seconds": "2 seconden" - }, - "20 minutes": { - "20 minutes": "20 minuten" - }, - "20 seconds": { - "20 seconds": "20 seconden" - }, - "24-Hour Format": { - "24-Hour Format": "24-uursnotatie" - }, - "24-hour clock": { - "24-hour clock": "24-uursklok" - }, - "24-hour format": { - "24-hour format": "24-uursnotatie" - }, - "25 seconds": { - "25 seconds": "25 seconden" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 dagen" - }, - "3 hours": { - "3 hours": "3 uur" - }, - "3 minutes": { - "3 minutes": "3 minuten" - }, - "3 seconds": { - "3 seconds": "3 seconden" - }, - "30 days": { - "30 days": "30 dagen" - }, - "30 minutes": { - "30 minutes": "30 minuten" - }, - "30 seconds": { - "30 seconds": "30 seconden" - }, - "35 seconds": { - "35 seconds": "35 seconden" - }, - "3rd party": { - "3rd party": "Derden" - }, - "4 hours": { - "4 hours": "4 uur" - }, - "4 seconds": { - "4 seconds": "4 seconden" - }, - "40 seconds": { - "40 seconds": "40 seconden" - }, - "45 seconds": { - "45 seconds": "45 seconden" - }, - "5 minutes": { - "5 minutes": "5 minuten" - }, - "5 seconds": { - "5 seconds": "5 seconden" - }, - "50 seconds": { - "50 seconds": "50 seconden" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 seconden" - }, - "6 hours": { - "6 hours": "6 uur" - }, - "7 days": { - "7 days": "7 dagen" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 uur" - }, - "8 seconds": { - "8 seconds": "8 seconden" - }, - "90 days": { - "90 days": "90 dagen" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "MIT-licentie" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Er bestaat al een bestand met deze naam. Wilt u het overschrijven?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Een moderne desktop-shell voor Wayland-compositors" - }, - "AC Power": { - "AC Power": "Netstroom" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Afgebroken" - }, - "About": { - "About": "Over" - }, - "Accent Color": { - "Accent Color": "Accentkleur" - }, - "Accept": { - "Accept": "Accepteren" - }, - "Accept Jobs": { - "Accept Jobs": "Taken accepteren" - }, - "Accepting": { - "Accepting": "Accepteert" - }, - "Access clipboard history": { - "Access clipboard history": "Toegang tot klembordgeschiedenis" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Toegang tot meldingen en niet storen" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Toegang tot systeembediening en instellingen" - }, - "Action": { - "Action": "Actie" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "Actie mislukt of terminal is gesloten." - }, - "Actions": { - "Actions": "Acties" - }, - "Activate": { - "Activate": "Activeren" - }, - "Activate Greeter": { - "Activate Greeter": "Greeter activeren" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "De DMS Greeter activeren? Er wordt een terminal geopend voor sudo-authenticatie. Voer Sync uit na activering om instellingen toe te passen." - }, - "Activation": { - "Activation": "Activering" - }, - "Active": { - "Active": "Actief" - }, - "Active Color": { - "Active Color": "Actieve kleur" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Actief vergrendelscherm-beeldscherm" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Achtergrond- en pictogramkleur van actieve tegel" - }, - "Active: %1": { - "Active: %1": "Actief: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Actief: %1 +%2" - }, - "Active: None": { - "Active: None": "Actief: Geen" - }, - "Adapters": { - "Adapters": "Adapters" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Toevoegen" - }, - "Add Bar": { - "Add Bar": "Balk toevoegen" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Bureaubladwidget toevoegen" - }, - "Add Printer": { - "Add Printer": "Printer toevoegen" - }, - "Add Title": { - "Add Title": "Titel toevoegen" - }, - "Add Widget": { - "Add Widget": "Widget toevoegen" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Widget toevoegen aan sectie %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Een rand om het dock toevoegen" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Voeg een aangepast voorvoegsel toe aan alle applicatiestarts. Dit kan worden gebruikt voor zaken als 'uwsm-app', 'systemd-run' of andere opdrachtwrappers." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Widgets toevoegen en configureren die op uw bureaublad verschijnen" - }, - "Add by Address": { - "Add by Address": "Toevoegen op adres" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Pas het aantal kolommen in rasterweergave aan." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Volume per scrollstap aanpassen" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "Past het contrast van gegenereerde kleuren aan (-100 = minimum, 0 = standaard, 100 = maximum)" - }, - "Advanced": { - "Advanced": "Geavanceerd" - }, - "Afternoon": { - "Afternoon": "Middag" - }, - "All": { - "All": "Alles" - }, - "All Monitors": { - "All Monitors": "Alle beeldschermen" - }, - "All checks passed": { - "All checks passed": "Alle controles geslaagd" - }, - "All day": { - "All day": "Hele dag" - }, - "All displays": { - "All displays": "Alle beeldschermen" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Klikken door de widget heen laten gaan" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Terug • F1/I: Bestandsinfo • F10: Hulp • Esc: Sluiten" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternatief (OF)" - }, - "Always Active": { - "Always Active": "Altijd actief" - }, - "Always Show Percentage": { - "Always Show Percentage": "Altijd percentage tonen" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Verberg het dock altijd en toon het bij zweven in het dockgebied" - }, - "Always on icons": { - "Always on icons": "Altijd-aan pictogrammen" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Altijd minimaal 3 werkbladen tonen, zelfs als er minder beschikbaar zijn" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Toon het dock altijd wanneer niri's overzicht open is" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Altijd tonen wanneer er slechts één beeldscherm is aangesloten" - }, - "Amount": { - "Amount": "Hoeveelheid" - }, - "Analog": { - "Analog": "Analoog" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analoge, digitale of gestapelde klokweergave" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Configuratie analyseren..." - }, - "Animation Duration": { - "Animation Duration": "Animatieduur" - }, - "Animation Speed": { - "Animation Speed": "Animatiesnelheid" - }, - "Anonymous Identity": { - "Anonymous Identity": "Anonieme identiteit" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Anonieme identiteit (optioneel)" - }, - "App Customizations": { - "App Customizations": "App-aanpassingen" - }, - "App ID Substitutions": { - "App ID Substitutions": "App ID-vervangingen" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "App-ID regex (bijv. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "App-starter" - }, - "App Names": { - "App Names": "App-namen" - }, - "App Theming": { - "App Theming": "App-thema's" - }, - "Appearance": { - "Appearance": "Uiterlijk" - }, - "Application Dock": { - "Application Dock": "Applicatiedock" - }, - "Applications": { - "Applications": "Applicaties" - }, - "Apply Changes": { - "Apply Changes": "Wijzigingen toepassen" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "GTK-kleuren toepassen" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Qt-kleuren toepassen" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Warme kleurtemperatuur toepassen om oogvermoeidheid te verminderen. Gebruik de automatiseringsinstellingen hieronder om te bepalen wanneer dit activeert." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "Verificatiewijzigingen toepassen…" - }, - "Apps": { - "Apps": "Apps" - }, - "Apps Dock": { - "Apps Dock": "Apps-dock" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "App-dockinstellingen" - }, - "Apps Icon": { - "Apps Icon": "Apps-pictogram" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Apps worden geordend op gebruiksfrequentie, dan laatst gebruikt, dan alfabetisch." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Apps met aangepaste weergavenaam, pictogram of startopties. Klik rechts op een app en selecteer 'App bewerken' om aan te passen." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Apps met gedempte meldingspop-ups. Dempen opheffen of verwijderen om te wissen." - }, - "Architecture": { - "Architecture": "Architectuur" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Weet u zeker dat u sessie \"%1\" wilt beëindigen?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Beeldschermen rangschikken en resolutie, verversingssnelheid en VRR configureren" - }, - "Attach": { - "Attach": "Koppelen" - }, - "Audio": { - "Audio": "Audio" - }, - "Audio Codec": { - "Audio Codec": "Audio-codec" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Audio-codec selectie" - }, - "Audio Devices": { - "Audio Devices": "Audioapparaten" - }, - "Audio Input": { - "Audio Input": "Audio-invoer" - }, - "Audio Output": { - "Audio Output": "Audio-uitvoer" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Audio-uitvoerapparaten (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Wisselen audio-uitvoer" - }, - "Audio Visualizer": { - "Audio Visualizer": "Audiovisualisatie" - }, - "Audio system restarted": { - "Audio system restarted": "Audiosysteem herstart" - }, - "Audio volume control": { - "Audio volume control": "Audio-volumeregeling" - }, - "Auth": { - "Auth": "Auth" - }, - "Auth Type": { - "Auth Type": "Authtype" - }, - "Authenticate": { - "Authenticate": "Authenticeren" - }, - "Authenticating...": { - "Authenticating...": "Controleren..." - }, - "Authentication": { - "Authentication": "Authenticatie" - }, - "Authentication Required": { - "Authentication Required": "Authenticatie vereist" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "Verificatiewijzigingen toegepast." - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "Verificatiewijzigingen worden automatisch toegepast." - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "Verificatiewijzigingen worden automatisch toegepast. Inloggen met alleen een vingerafdruk ontgrendelt de sleutelbos mogelijk niet." - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "Verificatiewijzigingen vereisen sudo. Terminal wordt geopend zodat u een wachtwoord of vingerafdruk kunt gebruiken." - }, - "Authentication error - try again": { - "Authentication error - try again": "Authenticatiefout - probeer het opnieuw" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Authenticatie mislukt, probeer het opnieuw" - }, - "Authorize": { - "Authorize": "Autoriseren" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Koppeling autoriseren met " - }, - "Authorize service for ": { - "Authorize service for ": "Service autoriseren voor " - }, - "Auto": { - "Auto": "Auto" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "Auto (Balk-bewust)" - }, - "Auto (Wide)": { - "Auto (Wide)": "Auto (Breed)" - }, - "Auto Location": { - "Auto Location": "Automatische locatie" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Automatische tussenruimte popups" - }, - "Auto-Clear After": { - "Auto-Clear After": "Automatisch wissen na" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Time-out automatisch verbergen" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Niri-overzicht automatisch sluiten bij starten van apps." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Automatisch verwijderen van meldingen ouder dan dit" - }, - "Auto-hide": { - "Auto-hide": "Automatisch verbergen" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Dock automatisch verbergen" - }, - "Auto-saving...": { - "Auto-saving...": "Automatisch opslaan..." - }, - "Autoconnect": { - "Autoconnect": "Automatisch verbinden" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Automatisch verbinden uitgeschakeld" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Automatisch verbinden ingeschakeld" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "Laatst onthouden zoekopdracht automatisch invullen bij openen" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Automatische kleurmodus" - }, - "Automatic Control": { - "Automatic Control": "Automatische regeling" - }, - "Automatic Cycling": { - "Automatic Cycling": "Automatisch wisselen" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Automatisch wisselen tussen achtergronden in dezelfde map" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Items die ouder zijn dan dit automatisch verwijderen" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Locatie automatisch detecteren op basis van IP-adres" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Uw locatie automatisch bepalen aan de hand van uw IP-adres" - }, - "Automatically lock after": { - "Automatically lock after": "Automatisch vergrendelen na" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Scherm automatisch vergrendelen wanneer DMS start" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Het scherm automatisch vergrendelen wanneer het systeem in slaapstand gaat" - }, - "Automation": { - "Automation": "Automatisering" - }, - "Available": { - "Available": "Beschikbaar" - }, - "Available Layouts": { - "Available Layouts": "Beschikbare indelingen" - }, - "Available Networks": { - "Available Networks": "Beschikbare netwerken" - }, - "Available Plugins": { - "Available Plugins": "Beschikbare plug-ins" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Beschikbare schermen (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Beschikbaar in weergavemodi Gedetailleerd en Voorspelling" - }, - "Available.": { - "Available.": "Beschikbaar." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Terug" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "Achtergrond" - }, - "Background Blur": { - "Background Blur": "Achtergrondvervaging" - }, - "Background Opacity": { - "Background Opacity": "Achtergronddekking" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "Synchronisatie van verificatie op de achtergrond mislukt. Terminalmodus wordt geprobeerd." - }, - "Background image": { - "Background image": "Achtergrondafbeelding" - }, - "Backlight device": { - "Backlight device": "Achtergrondverlichtingsapparaat" - }, - "Balance power and performance": { - "Balance power and performance": "Balans tussen energie en prestaties" - }, - "Balanced": { - "Balanced": "Gebalanceerd" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Gebalanceerd palet met gerichte accenten (standaard)." - }, - "Bar Configurations": { - "Bar Configurations": "Balkconfiguraties" - }, - "Bar Shadows": { - "Bar Shadows": "Balkschaduwen" - }, - "Bar Transparency": { - "Bar Transparency": "Balktransparantie" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Basiskleur voor schaduwen (dekking wordt automatisch toegepast)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Basisduur voor animaties (sleep om Aangepast te gebruiken)" - }, - "Battery": { - "Battery": "Batterij" - }, - "Battery %1": { - "Battery %1": "Accu %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Batterijlaadlimiet" - }, - "Battery and power management": { - "Battery and power management": "Batterij- en energiebeheer" - }, - "Battery level and power management": { - "Battery level and power management": "Batterijniveau en energiebeheer" - }, - "Behavior": { - "Behavior": "Gedrag" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Vergrendelscherm koppelen aan dbus-signalen van loginctl. Uitschakelen indien een extern vergrendelscherm wordt gebruikt" - }, - "Binds Include Missing": { - "Binds Include Missing": "Binds-include ontbreekt" - }, - "Binds include added": { - "Binds include added": "Binds-include toegevoegd" - }, - "Bit Depth": { - "Bit Depth": "Kleurdiepte" - }, - "Block Out": { - "Block Out": "Uitsluiten" - }, - "Block Out From": { - "Block Out From": "Uitsluiten van" - }, - "Block notifications": { - "Block notifications": "Meldingen blokkeren" - }, - "Blocked": { - "Blocked": "Geblokkeerd" - }, - "Blue light filter": { - "Blue light filter": "Blauwlichtfilter" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth-instellingen" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth niet beschikbaar" - }, - "Blur Border Color": { - "Blur Border Color": "Kleur van vervagingsrand" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "Dekking van vervagingsrand" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Achtergrondlaag vervagen" - }, - "Blur on Overview": { - "Blur on Overview": "Vervagen bij overzicht" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "Vervaag de achtergrond achter balken, pop-ups, modale vensters en meldingen. Vereist ondersteuning van de compositor en configuratie." - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Achtergrond vervagen wanneer niri-overzicht open is" - }, - "Body": { - "Body": "Inhoud" - }, - "Border": { - "Border": "Rand" - }, - "Border Color": { - "Border Color": "Randkleur" - }, - "Border Opacity": { - "Border Opacity": "Randdekking" - }, - "Border Size": { - "Border Size": "Randgrootte" - }, - "Border Thickness": { - "Border Thickness": "Randdikte" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "Randkleur rondom vervaagde oppervlakken" - }, - "Border with BG": { - "Border with BG": "Rand met achtergrond" - }, - "Bottom": { - "Bottom": "Onder" - }, - "Bottom Center": { - "Bottom Center": "Middenonder" - }, - "Bottom Left": { - "Bottom Left": "Linksonder" - }, - "Bottom Right": { - "Bottom Right": "Rechtsonder" - }, - "Bottom Section": { - "Bottom Section": "Onderste sectie" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Onderste dock voor vastgemaakte en actieve applicaties" - }, - "Brightness": { - "Brightness": "Helderheid" - }, - "Brightness Slider": { - "Brightness Slider": "Helderheidsschuif" - }, - "Brightness Value": { - "Brightness Value": "Helderheidswaarde" - }, - "Brightness control not available": { - "Brightness control not available": "Helderheidsregeling niet beschikbaar" - }, - "Browse": { - "Browse": "Bladeren" - }, - "Browse Files": { - "Browse Files": "Bestanden doorbladeren" - }, - "Browse Plugins": { - "Browse Plugins": "Plug-ins doorbladeren" - }, - "Browse Themes": { - "Browse Themes": "Thema's doorbladeren" - }, - "Browse or search plugins": { - "Browse or search plugins": "Plug-ins bladeren of zoeken" - }, - "Button Color": { - "Button Color": "Knopkleur" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU-grafiek" - }, - "CPU Temperature": { - "CPU Temperature": "CPU-temperatuur" - }, - "CPU Usage": { - "CPU Usage": "CPU-gebruik" - }, - "CPU temperature display": { - "CPU temperature display": "Weergave CPU-temperatuur" - }, - "CPU usage indicator": { - "CPU usage indicator": "Indicator CPU-gebruik" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU-, geheugen-, netwerk- en schijfbewaking" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS onveilige filterwaarschuwing" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS ontbrekende filterwaarschuwing" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS-printserver" - }, - "CUPS not available": { - "CUPS not available": "CUPS niet beschikbaar" - }, - "Camera": { - "Camera": "Camera" - }, - "Cancel": { - "Cancel": "Annuleren" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Alle taken voor \"%1\" annuleren?" - }, - "Canceled": { - "Canceled": "Geannuleerd" - }, - "Cannot pair": { - "Cannot pair": "Kan niet koppelen" - }, - "Capabilities": { - "Capabilities": "Mogelijkheden" - }, - "Capacity": { - "Capacity": "Capaciteit" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Caps Lock-indicator" - }, - "Caps Lock is on": { - "Caps Lock is on": "Caps Lock staat aan" - }, - "Center Section": { - "Center Section": "Middensectie" - }, - "Center Single Column": { - "Center Single Column": "Enkele kolom centreren" - }, - "Center Tiling": { - "Center Tiling": "Centreren" - }, - "Certificate Password": { - "Certificate Password": "Certificaatwachtwoord" - }, - "Change Song": { - "Change Song": "Nummer wijzigen" - }, - "Change Volume": { - "Change Volume": "Volume wijzigen" - }, - "Change bar appearance": { - "Change bar appearance": "Balkuiterlijk wijzigen" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "Wijzig de locale (taal en regio) die wordt gebruikt door de DMS-interface." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Wijzig de locale voor datum- en tijdnotatie, onafhankelijk van de interfacetaal." - }, - "Channel": { - "Channel": "Kanaal" - }, - "Charging": { - "Charging": "Opladen" - }, - "Check for system updates": { - "Check for system updates": "Controleren op systeemupdates" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "Synchronisatiestatus op aanvraag controleren. Synchronisatie kopieert uw thema, instellingen en achtergrondconfiguratie naar het aanmeldscherm. Verificatiewijzigingen worden automatisch toegepast." - }, - "Checking for updates...": { - "Checking for updates...": "Zoeken naar updates..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Controleren of sudo-authenticatie vereist is…" - }, - "Checking...": { - "Checking...": "Controleren..." - }, - "Checking…": { - "Checking…": "Controleren…" - }, - "Choose Color": { - "Choose Color": "Kleur kiezen" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Kleur donkere modus kiezen" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Kies kleur dockstartlogo" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Kleur startpictogram kiezen" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Kleur lichte modus kiezen" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Achtergrondkleur kiezen" - }, - "Choose a color": { - "Choose a color": "Kies een kleur" - }, - "Choose colors from palette": { - "Choose colors from palette": "Kies kleuren uit palet" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Kies hoe de weer-widget wordt weergegeven" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Kies hoe deze balk de schaduwrichting bepaalt" - }, - "Choose icon": { - "Choose icon": "Kies pictogram" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Kies de achtergrondkleur voor widgets" - }, - "Choose the border accent color": { - "Choose the border accent color": "Kies de accentkleur voor de rand" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Kies het logo voor de startknop in DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Kies waar meldingen op het scherm verschijnen" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Kies waar on-screen displays op het scherm verschijnen" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Kies welke beeldschermen deze widget tonen" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Kies welk beeldscherm de vergrendelscherm-interface toont. Andere beeldschermen tonen een effen kleur voor bescherming tegen inbranden van OLED." - }, - "Chroma Style": { - "Chroma Style": "Chroma-stijl" - }, - "Cipher": { - "Cipher": "Cijfer" - }, - "Circle": { - "Circle": "Cirkel" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Klasse-regex (bijv. ^firefox$)" - }, - "Clear": { - "Clear": "Wissen" - }, - "Clear All": { - "Clear All": "Alles wissen" - }, - "Clear All Jobs": { - "Clear All Jobs": "Alle taken wissen" - }, - "Clear History?": { - "Clear History?": "Geschiedenis wissen?" - }, - "Clear Sky": { - "Clear Sky": "Heldere hemel" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Alle geschiedenis wissen wanneer server start" - }, - "Clear at Startup": { - "Clear at Startup": "Wissen bij opstarten" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Klik op 'Instellen' om %1 te maken en include toe te voegen aan config." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Klik op 'Instellen' om %1 aan te maken en de include toe te voegen aan je compositor-configuratie." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Klik op 'Instellen' om cursorconfiguratie te maken en include toe te voegen aan uw compositor-configuratie." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Klik op 'Instellen' om de outputs-configuratie te maken en include toe te voegen aan uw compositor-configuratie." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Klik op Importeren om een .ovpn of .conf toe te voegen" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Klik op Vernieuwen om de status te controleren." - }, - "Click Through": { - "Click Through": "Doorklikken" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Klik op een sneltoets om te bewerken. Wijzigingen worden opgeslagen in %1" - }, - "Click to capture": { - "Click to capture": "Klik om vast te leggen" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Klik om een aangepast thema-JSON-bestand te selecteren" - }, - "Clip": { - "Clip": "Bijsnijden" - }, - "Clip to Geometry": { - "Clip to Geometry": "Bijsnijden naar afmetingen" - }, - "Clipboard": { - "Clipboard": "Klembord" - }, - "Clipboard History": { - "Clipboard History": "Klembordgeschiedenis" - }, - "Clipboard Manager": { - "Clipboard Manager": "Klembordbeheer" - }, - "Clipboard sent": { - "Clipboard sent": "Klembord verzonden" - }, - "Clipboard service not available": { - "Clipboard service not available": "Klembord-service niet beschikbaar" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Klembord werkt maar niets opgeslagen op schijf" - }, - "Clock": { - "Clock": "Klok" - }, - "Clock Style": { - "Clock Style": "Klokstijl" - }, - "Close": { - "Close": "Sluiten" - }, - "Close All Windows": { - "Close All Windows": "Alle vensters sluiten" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Overzicht sluiten bij starten" - }, - "Close Window": { - "Close Window": "Venster sluiten" - }, - "Color": { - "Color": "Kleur" - }, - "Color Gamut": { - "Color Gamut": "Kleurengamma" - }, - "Color Management": { - "Color Management": "Kleurbeheer" - }, - "Color Mode": { - "Color Mode": "Kleurmodus" - }, - "Color Override": { - "Color Override": "Kleur overschrijven" - }, - "Color Picker": { - "Color Picker": "Kleurkiezer" - }, - "Color Temperature": { - "Color Temperature": "Kleurtemperatuur" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Kleur weergegeven op beeldschermen zonder vergrendelscherm" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Kleur voor primaire actieknoppen" - }, - "Color temperature for day time": { - "Color temperature for day time": "Kleurtemperatuur voor overdag" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Kleurtemperatuur voor nachtmodus" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Kleurthema voor syntaxismarkering." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Kleurthema voor syntaxismarkering. %1 thema's beschikbaar." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Kleurthema uit DMS-register" - }, - "Colorful": { - "Colorful": "Kleurrijk" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Kleurrijke mix van heldere contrasterende accenten." - }, - "Colorize Active": { - "Colorize Active": "Actieve items kleuren" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Kleuren van achtergrond" - }, - "Column": { - "Column": "Kolom" - }, - "Column Display": { - "Column Display": "Kolomweergave" - }, - "Column Width": { - "Column Width": "Kolombreedte" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "Komma-gescheiden lijst van te verbergen sessienamen. Gebruik slashes voor regex (bijv. /^_.*/)." - }, - "Command": { - "Command": "Opdracht" - }, - "Commands": { - "Commands": "Opdrachten" - }, - "Communication": { - "Communication": "Communicatie" - }, - "Community themes": { - "Community themes": "Community-thema's" - }, - "Compact": { - "Compact": "Compact" - }, - "Compact Mode": { - "Compact Mode": "Compacte modus" - }, - "Completed": { - "Completed": "Voltooid" - }, - "Compositor": { - "Compositor": "Compositor" - }, - "Compositor Settings": { - "Compositor Settings": "Compositor-instellingen" - }, - "Compositor not supported": { - "Compositor not supported": "Compositor niet ondersteund" - }, - "Config Format": { - "Config Format": "Config-formaat" - }, - "Config action: %1": { - "Config action: %1": "Config-actie: %1" - }, - "Config validation failed": { - "Config validation failed": "Configuratievalidatie mislukt" - }, - "Configuration": { - "Configuration": "Configuratie" - }, - "Configuration activated": { - "Configuration activated": "Configuratie geactiveerd" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Configuratie wordt bewaard wanneer dit beeldscherm opnieuw verbindt" - }, - "Configure": { - "Configure": "Configureren" - }, - "Configure Keybinds": { - "Configure Keybinds": "Sneltoetsen configureren" - }, - "Configure a new printer": { - "Configure a new printer": "Een nieuwe printer configureren" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Configureer pictogrammen voor benoemde werkbladen. Pictogrammen hebben voorrang op nummers als beide zijn ingeschakeld." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Criteria en acties configureren" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Configureren op welke schermen \"%1\" wordt getoond" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Configureer welke beeldschermen shell-onderdelen tonen" - }, - "Confirm": { - "Confirm": "Bevestigen" - }, - "Confirm Delete": { - "Confirm Delete": "Verwijderen bevestigen" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Beeldschermwijzigingen bevestigen" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Bevestig toegangscode voor " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Conflicteert met: %1" - }, - "Connect": { - "Connect": "Verbinden" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Verbinden met verborgen netwerk" - }, - "Connect to VPN": { - "Connect to VPN": "Verbinden met VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Verbinden met wifi" - }, - "Connected": { - "Connected": "Verbonden" - }, - "Connected Device": { - "Connected Device": "Verbonden apparaat" - }, - "Connected Displays": { - "Connected Displays": "Aangesloten beeldschermen" - }, - "Connecting to Device": { - "Connecting to Device": "Verbinden met apparaat" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Verbinden..." - }, - "Connection failed": { - "Connection failed": "Verbinding mislukt" - }, - "Contains": { - "Contains": "Bevat" - }, - "Content": { - "Content": "Inhoud" - }, - "Content copied": { - "Content copied": "Inhoud gekopieerd" - }, - "Contrast": { - "Contrast": "Contrast" - }, - "Control Center": { - "Control Center": "Bedieningspaneel" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Tegelkleur bedieningspaneel" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Animatieduur voor meldingspop-ups en geschiedenis beheren" - }, - "Control currently playing media": { - "Control currently playing media": "Huidige media bedienen" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Bepaal welke meldinginformatie op het vergrendelscherm wordt getoond" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Bepaal welke plug-ins verschijnen in 'Alles'-modus zonder trigger-voorvoegsel. Sleep om te herschikken." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Werkbladen en kolommen bedienen door te scrollen op de balk" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Regelt dekking van alle pop-outs, modale vensters en hun inhoudslagen" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "Bepaalt de richting van de schaduw voor hoogtelagen" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "Bepaalt de basisvervagingsstraal en verschuiving van schaduwen" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Bepaalt de transparantie van de schaduw" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Gemaksopties voor het aanmeldscherm. Voer Sync uit om toe te passen." - }, - "Cooldown": { - "Cooldown": "Afkoeltijd" - }, - "Copied GIF": { - "Copied GIF": "GIF gekopieerd" - }, - "Copied MP4": { - "Copied MP4": "MP4 gekopieerd" - }, - "Copied WebP": { - "Copied WebP": "WebP gekopieerd" - }, - "Copied to clipboard": { - "Copied to clipboard": "Gekopieerd naar klembord" - }, - "Copied!": { - "Copied!": "Gekopieerd!" - }, - "Copy": { - "Copy": "Kopiëren" - }, - "Copy Content": { - "Copy Content": "Inhoud kopiëren" - }, - "Copy Full Command": { - "Copy Full Command": "Volledige opdracht kopiëren" - }, - "Copy HTML": { - "Copy HTML": "HTML kopiëren" - }, - "Copy Name": { - "Copy Name": "Naam kopiëren" - }, - "Copy PID": { - "Copy PID": "PID kopiëren" - }, - "Copy Text": { - "Copy Text": "Tekst kopiëren" - }, - "Copy path": { - "Copy path": "Pad kopiëren" - }, - "Corner Radius": { - "Corner Radius": "Hoekradius" - }, - "Corner Radius Override": { - "Corner Radius Override": "Overschrijven hoekradius" - }, - "Corners & Background": { - "Corners & Background": "Hoeken & Achtergrond" - }, - "Count Only": { - "Count Only": "Alleen aantal" - }, - "Cover Open": { - "Cover Open": "Klep open" - }, - "Create": { - "Create": "Aanmaken" - }, - "Create Dir": { - "Create Dir": "Map maken" - }, - "Create Printer": { - "Create Printer": "Printer aanmaken" - }, - "Create Window Rule": { - "Create Window Rule": "Vensterregel aanmaken" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Maak een nieuwe %1-sessie aan (n)" - }, - "Create rule for:": { - "Create rule for:": "Regel aanmaken voor:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Regels maken om meldingen te dempen, negeren, verbergen in geschiedenis of prioriteit te overschrijven. Standaard wordt alleen de prioriteit overschreven; meldingen worden nog steeds normaal weergegeven." - }, - "Creating...": { - "Creating...": "Aanmaken..." - }, - "Critical Priority": { - "Critical Priority": "Kritieke prioriteit" - }, - "Current": { - "Current": "Huidig" - }, - "Current Items": { - "Current Items": "Huidige items" - }, - "Current Locale": { - "Current Locale": "Huidige locale" - }, - "Current Monitor": { - "Current Monitor": "Huidige monitor" - }, - "Current Period": { - "Current Period": "Huidige periode" - }, - "Current Status": { - "Current Status": "Huidige status" - }, - "Current Temp": { - "Current Temp": "Huidige temp" - }, - "Current Theme: %1": { - "Current Theme: %1": "Huidig thema: %1" - }, - "Current Weather": { - "Current Weather": "Huidig weer" - }, - "Current Workspace": { - "Current Workspace": "Huidig werkblad" - }, - "Current time and date display": { - "Current time and date display": "Weergave huidige tijd en datum" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Huidige weersomstandigheden en temperatuur" - }, - "Current: %1": { - "Current: %1": "Huidige: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Cursorconfiguratie niet geconfigureerd" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Cursor-include ontbreekt" - }, - "Cursor Size": { - "Cursor Size": "Cursorgrootte" - }, - "Cursor Theme": { - "Cursor Theme": "Cursorthema" - }, - "Custom": { - "Custom": "Aangepast" - }, - "Custom Color": { - "Custom Color": "Aangepaste kleur" - }, - "Custom Duration": { - "Custom Duration": "Aangepaste duur" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Aangepaste sluimeropdracht" - }, - "Custom Location": { - "Custom Location": "Aangepaste locatie" - }, - "Custom Lock Command": { - "Custom Lock Command": "Aangepaste vergrendelopdracht" - }, - "Custom Logout Command": { - "Custom Logout Command": "Aangepaste afmeldopdracht" - }, - "Custom Name": { - "Custom Name": "Aangepaste naam" - }, - "Custom Power Actions": { - "Custom Power Actions": "Aangepaste energieacties" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Aangepaste uitschakelopdracht" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Aangepaste herstartopdracht" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Aangepaste schaduwkleur" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Aangepaste schaduwoverschrijving" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Aangepaste slaapstandopdracht" - }, - "Custom Transparency": { - "Custom Transparency": "Aangepaste transparantie" - }, - "Custom power profile": { - "Custom power profile": "Aangepast energieprofiel" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Aangepast thema geladen uit JSON-bestand" - }, - "Custom...": { - "Custom...": "Aangepast..." - }, - "Custom: ": { - "Custom: ": "Aangepast: " - }, - "Customizable empty space": { - "Customizable empty space": "Aanpasbare lege ruimte" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Pas aan welke acties in het energiemenu verschijnen" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI-monitor" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMOMODUS - Klik ergens om te sluiten" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS Plug-inbeheer niet beschikbaar" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS-sneltoetsen" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "DMS-aanmeldscherm heeft nodig: greetd, dms-greeter. Vingerafdruk: fprintd, pam_fprintd. Beveiligingssleutels: pam_u2f. Voeg uw gebruiker toe aan de greeter-groep. Verificatiewijzigingen worden automatisch toegepast en kunnen een terminal openen wanneer sudo-verificatie vereist is." - }, - "DMS out of date": { - "DMS out of date": "DMS verouderd" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS-service is niet verbonden. Klembordinstellingen zijn niet beschikbaar." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS-shellacties (starter, klembord, enz.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET niet beschikbaar" - }, - "DWL service not available": { - "DWL service not available": "DWL-service niet beschikbaar" - }, - "Daily": { - "Daily": "Dagelijks" - }, - "Daily at:": { - "Daily at:": "Dagelijks om:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell is klaar voor gebruik" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell- & systeempictogrammen (vereist herstart)" - }, - "Dark Mode": { - "Dark Mode": "Donkere modus" - }, - "Dark mode base": { - "Dark mode base": "Donkere modus basis" - }, - "Dark mode harmony": { - "Dark mode harmony": "Donkere modus harmonie" - }, - "Darken Modal Background": { - "Darken Modal Background": "Modale achtergrond verduisteren" - }, - "Date Format": { - "Date Format": "Datumnotatie" - }, - "Date format": { - "Date format": "Datumnotatie" - }, - "Date format on greeter": { - "Date format on greeter": "Datumnotatie op Greeter" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Dageraad (Astronomische schemering)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Dageraad (Civiele schemering)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Dageraad (Nautische schemering)" - }, - "Day Date": { - "Day Date": "Dag Datum" - }, - "Day Month Date": { - "Day Month Date": "Dag Maand Datum" - }, - "Day Temperature": { - "Day Temperature": "Dagtemperatuur" - }, - "Daytime": { - "Daytime": "Overdag" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "Standaard" - }, - "Default (Black)": { - "Default (Black)": "Standaard (Zwart)" - }, - "Default Width (%)": { - "Default Width (%)": "Standaardbreedte (%)" - }, - "Default selected action": { - "Default selected action": "Standaard geselecteerde actie" - }, - "Defaults": { - "Defaults": "Standaardwaarden" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Definieer regels voor venstergedrag. Wordt opgeslagen in %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Wissen • Shift+Del: Alles wissen • 1-9: Acties • F10: Hulp • Esc: Sluiten" - }, - "Delete": { - "Delete": "Verwijderen" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "\"%1\" verwijderen?" - }, - "Delete Class": { - "Delete Class": "Klasse verwijderen" - }, - "Delete Printer": { - "Delete Printer": "Printer verwijderen" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Opgeslagen item verwijderen?" - }, - "Delete VPN": { - "Delete VPN": "VPN verwijderen" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Klasse \"%1\" verwijderen?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Profiel \"%1\" verwijderen?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Afhankelijkheden & documentatie" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Leidt kleuren af die nauw aansluiten bij de onderliggende afbeelding." - }, - "Description": { - "Description": "Beschrijving" - }, - "Desktop": { - "Desktop": "Bureaublad" - }, - "Desktop Clock": { - "Desktop Clock": "Bureaubladklok" - }, - "Desktop Entry": { - "Desktop Entry": "Desktop-item" - }, - "Desktop Widget": { - "Desktop Widget": "Bureaubladwidget" - }, - "Desktop Widgets": { - "Desktop Widgets": "Bureaubladwidgets" - }, - "Desktop background images": { - "Desktop background images": "Bureaubladachtergronden" - }, - "Detailed": { - "Detailed": "Gedetailleerd" - }, - "Details for \"%1": { - "Details for \"%1\"": "Details voor \"%1\"" - }, - "Development": { - "Development": "Ontwikkeling" - }, - "Device": { - "Device": "Apparaat" - }, - "Device connections": { - "Device connections": "Apparaatverbindingen" - }, - "Device names updated": { - "Device names updated": "Apparaatnamen bijgewerkt" - }, - "Device paired": { - "Device paired": "Apparaat gekoppeld" - }, - "Device unpaired": { - "Device unpaired": "Apparaat ontkoppeld" - }, - "Digital": { - "Digital": "Digitaal" - }, - "Direction Source": { - "Direction Source": "Richtingsbron" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Automatisch verbinden uitschakelen" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Ingebouwde achtergronden uitschakelen" - }, - "Disable History Persistence": { - "Disable History Persistence": "Geschiedenisopslag uitschakelen" - }, - "Disable Output": { - "Disable Output": "Uitvoer uitschakelen" - }, - "Disabled": { - "Disabled": "Uitgeschakeld" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Wifi uitschakelen..." - }, - "Disc": { - "Disc": "Schijf" - }, - "Discard": { - "Discard": "Verwerpen" - }, - "Discharging": { - "Discharging": "Ontladen" - }, - "Disconnect": { - "Disconnect": "Verbinding verbreken" - }, - "Disconnected": { - "Disconnected": "Niet verbonden" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Verbinding met wifi verbroken" - }, - "Discover Devices": { - "Discover Devices": "Apparaten ontdekken" - }, - "Disk": { - "Disk": "Schijf" - }, - "Disk I/O": { - "Disk I/O": "Schijf I/O" - }, - "Disk Usage": { - "Disk Usage": "Schijfgebruik" - }, - "Disk Usage Display": { - "Disk Usage Display": "Weergave schijfgebruik" - }, - "Disks": { - "Disks": "Schijven" - }, - "Dismiss": { - "Dismiss": "Sluiten" - }, - "Display": { - "Display": "Beeldscherm" - }, - "Display Assignment": { - "Display Assignment": "Beeldschermtoewijzing" - }, - "Display Control": { - "Display Control": "Beeldschermbeheer" - }, - "Display Name Format": { - "Display Name Format": "Indeling schermnaam" - }, - "Display Profiles": { - "Display Profiles": "Beeldschermprofielen" - }, - "Display Settings": { - "Display Settings": "Beeldscherminstellingen" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Een dock tonen met vastgemaakte en actieve applicaties" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Alle prioriteiten over applicaties op volledig scherm tonen" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "DWL-indelingen tonen en wisselen" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Applicatiepictogrammen tonen in werkbladindicatoren" - }, - "Display brightness control": { - "Display brightness control": "Helderheidsregeling beeldscherm" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Beeldschermconfiguratie is niet beschikbaar. WLR-uitvoerbeheerprotocol wordt niet ondersteund." - }, - "Display currently focused application title": { - "Display currently focused application title": "Titel van huidige actieve applicatie tonen" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Toon weersvoorspellingen per uur" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Toon alleen werkbladen die vensters bevatten" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Energiemenu-acties weergeven in een raster in plaats van een lijst" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Seconden tonen in de klok" - }, - "Display the power system menu": { - "Display the power system menu": "Het systeem-energiemenu weergeven" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Volume- en helderheidspercentages tonen in OSD-pop-ups" - }, - "Displays": { - "Displays": "Beeldschermen" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Toont aantal wanneer overloop actief is" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Toont de actieve toetsenbordindeling en maakt wisselen mogelijk" - }, - "Distribution": { - "Distribution": "Distributie" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Divers palet dat het volledige spectrum beslaat." - }, - "Do Not Disturb": { - "Do Not Disturb": "Niet storen" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock & Starter" - }, - "Dock Transparency": { - "Dock Transparency": "Dock-transparantie" - }, - "Dock Visibility": { - "Dock Visibility": "Zichtbaarheid dock" - }, - "Docs": { - "Docs": "Documentatie" - }, - "Documents": { - "Documents": "Documenten" - }, - "Domain (optional)": { - "Domain (optional)": "Domein (optioneel)" - }, - "Don't Change": { - "Don't Change": "Niet wijzigen" - }, - "Don't Save": { - "Don't Save": "Niet opslaan" - }, - "Door Open": { - "Door Open": "Deur open" - }, - "Downloads": { - "Downloads": "Downloads" - }, - "Drag to Reorder": { - "Drag to Reorder": "Sleep om te rangschikken" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Sleep widgets om ze te herschikken binnen secties. Gebruik het oog-pictogram om widgets te verbergen/tonen (behoudt tussenruimte), of X om ze volledig te verwijderen." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Sleep werkbladindicatoren om ze te rangschikken" - }, - "Driver": { - "Driver": "Stuurprogramma" - }, - "Drizzle": { - "Drizzle": "Motregen" - }, - "Duplicate": { - "Duplicate": "Dupliceren" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Achtergrond dupliceren met vervaging" - }, - "Duration": { - "Duration": "Duur" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Avondschemering (Astronomische schemering)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Avondschemering (Civiele schemering)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Avondschemering (Nautische schemering)" - }, - "Dynamic": { - "Dynamic": "Dynamisch" - }, - "Dynamic Properties": { - "Dynamic Properties": "Dynamische eigenschappen" - }, - "Dynamic Theming": { - "Dynamic Theming": "Dynamische thema's" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Dynamische kleuren van achtergrond" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Dynamische kleuren, voorinstellingen" - }, - "Edge Spacing": { - "Edge Spacing": "Randafstand" - }, - "Edit App": { - "Edit App": "App bewerken" - }, - "Edit Window Rule": { - "Edit Window Rule": "Vensterregel bewerken" - }, - "Education": { - "Education": "Onderwijs" - }, - "Empty": { - "Empty": "Leeg" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Schakel 10-bits kleurdiepte in voor een breder kleurengamma en HDR-ondersteuning" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Automatisch verbinden inschakelen" - }, - "Enable Bar": { - "Enable Bar": "Balk inschakelen" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Niet storen inschakelen" - }, - "Enable History": { - "Enable History": "Geschiedenis inschakelen" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Overzicht-overlay inschakelen" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Rimpel-effecten inschakelen" - }, - "Enable System Sounds": { - "Enable System Sounds": "Systeemgeluiden inschakelen" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Video-screensaver inschakelen" - }, - "Enable Weather": { - "Enable Weather": "Weer inschakelen" - }, - "Enable WiFi": { - "Enable WiFi": "Wifi inschakelen" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "Schakel hieronder een aangepaste overschrijving in om de schaduwintensiteit, dekking en kleur per balk in te stellen." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Schakel compositor-targetable vervagingslaag in (namespace: dms:blurwallpaper). Vereist handmatige niri-configuratie." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Vingerafdruk inschakelen bij aanmelden" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Vingerafdrukverificatie inschakelen" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "Schakel vingerafdruk of beveiligingssleutel in voor DMS-aanmeldscherm. Verificatiewijzigingen worden automatisch toegepast." - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Loginctl-vergrendelintegratie inschakelen" - }, - "Enable security key at login": { - "Enable security key at login": "Beveiligingssleutel inschakelen bij aanmelden" - }, - "Enable security key authentication": { - "Enable security key authentication": "Beveiligingssleutel-authenticatie inschakelen" - }, - "Enabled": { - "Enabled": "Ingeschakeld" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Ingeschakeld, maar de beschikbaarheid van de vingerafdrukscanner kon niet worden bevestigd." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Ingeschakeld, maar er is geen vingerafdrukscanner gedetecteerd." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "Ingeschakeld, maar er zijn nog geen afdrukken geregistreerd. Verificatiewijzigingen worden automatisch toegepast zodra u vingerafdrukken registreert." - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Ingeschakeld, maar er zijn nog geen afdrukken geregistreerd. Registreer vingerafdrukken en voer Sync uit." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "Ingeschakeld, maar er is nog geen geregistreerde beveiligingssleutel gevonden. Verificatiewijzigingen worden automatisch toegepast zodra uw sleutel is geregistreerd of uw U2F-configuratie is bijgewerkt." - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "Ingeschakeld, maar er is nog geen geregistreerde beveiligingssleutel gevonden. Registreer een sleutel en voer Sync uit." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Ingeschakeld, maar de beschikbaarheid van de beveiligingssleutel kon niet worden bevestigd." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Ingeschakeld. PAM biedt al vingerafdrukauthenticatie." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Ingeschakeld. PAM biedt al authenticatie via beveiligingssleutel." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Ingeschakeld. PAM biedt vingerafdrukauthenticatie, maar er zijn nog geen afdrukken geregistreerd." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Wifi inschakelen..." - }, - "End": { - "End": "Einde" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Vergroten bij aanwijzen" - }, - "Enlargement %": { - "Enlargement %": "Vergroting %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Voer 6-cijferige toegangscode in" - }, - "Enter PIN": { - "Enter PIN": "Voer pincode in" - }, - "Enter PIN for ": { - "Enter PIN for ": "Voer pincode in voor " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Voer URL of tekst in om te delen" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Voer een nieuwe naam in voor sessie \"%1\"" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Voer een nieuwe naam in voor dit werkblad" - }, - "Enter command or script path": { - "Enter command or script path": "Voer opdracht of scriptpad in" - }, - "Enter credentials for ": { - "Enter credentials for ": "Voer inloggegevens in voor " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Voer aangepaste notatie voor vergrendelscherm in (bijv. dddd, d MMMM)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Voer aangepaste notatie voor bovenbalk in (bijv. ddd d MMM)" - }, - "Enter device name...": { - "Enter device name...": "Voer apparaatnaam in..." - }, - "Enter filename...": { - "Enter filename...": "Voer bestandsnaam in..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Voer startvoorvoegsel in (bijv. 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Voer netwerknaam en wachtwoord in" - }, - "Enter passkey for ": { - "Enter passkey for ": "Voer toegangscode in voor " - }, - "Enter password for ": { - "Enter password for ": "Voer wachtwoord in voor " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Voer deze toegangscode in op " - }, - "Enter to Paste": { - "Enter to Paste": "Enter om te plakken" - }, - "Enterprise": { - "Enterprise": "Enterprise" - }, - "Entry pinned": { - "Entry pinned": "Item vastgemaakt" - }, - "Entry unpinned": { - "Entry unpinned": "Item losgemaakt" - }, - "Environment Variables": { - "Environment Variables": "Omgevingsvariabelen" - }, - "Error": { - "Error": "Fout" - }, - "Errors": { - "Errors": "Fouten" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Exact" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Verschuiving exclusieve zone" - }, - "Experimental Feature": { - "Experimental Feature": "Experimentele functie" - }, - "Explore": { - "Explore": "Verkennen" - }, - "Exponential": { - "Exponential": "Exponentieel" - }, - "Expressive": { - "Expressive": "Expressief" - }, - "Extend battery life": { - "Extend battery life": "Batterijduur verlengen" - }, - "Extensible architecture": { - "Extensible architecture": "Uitbreidbare architectuur" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Extern achtergrondbeheer" - }, - "Extra Arguments": { - "Extra Arguments": "Extra argumenten" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Schakelen • F10: Hulp" - }, - "Fade": { - "Fade": "Vervagen" - }, - "Fade to lock screen": { - "Fade to lock screen": "Vervagen naar vergrendelscherm" - }, - "Fade to monitor off": { - "Fade to monitor off": "Vervagen naar scherm uit" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Accepteren van koppeling mislukt" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Activeren van configuratie mislukt" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Kon profiel niet activeren - bestand niet gevonden" - }, - "Failed to add binds include": { - "Failed to add binds include": "Toevoegen van binds-include mislukt" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Toevoegen van printer aan klasse mislukt" - }, - "Failed to browse device": { - "Failed to browse device": "Bladeren op apparaat mislukt" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Annuleren van alle taken mislukt" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Annuleren van geselecteerde taak mislukt" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Controleren op updates mislukt:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Controleren van vastmaaklimiet mislukt" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Verbinden met VPN mislukt" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Verbinding maken met %1 mislukt" - }, - "Failed to copy entry": { - "Failed to copy entry": "Kopiëren van item mislukt" - }, - "Failed to create printer": { - "Failed to create printer": "Aanmaken van printer mislukt" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Kon profielenmap niet aanmaken" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Verwijderen van VPN mislukt" - }, - "Failed to delete class": { - "Failed to delete class": "Verwijderen van klasse mislukt" - }, - "Failed to delete printer": { - "Failed to delete printer": "Verwijderen van printer mislukt" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Uitschakelen van taakacceptatie mislukt" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Uitschakelen van nachtmodus mislukt" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Verbreken van VPN-verbinding mislukt" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Verbreken van VPN-verbindingen mislukt" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Verbreken van wifi-verbinding mislukt" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Inschakelen van IP-locatie mislukt" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Inschakelen van wifi mislukt" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Inschakelen van taakacceptatie mislukt" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Inschakelen van nachtmodus mislukt" - }, - "Failed to hold job": { - "Failed to hold job": "Vasthouden van taak mislukt" - }, - "Failed to import VPN": { - "Failed to import VPN": "Importeren van VPN mislukt" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Starten van sms-app mislukt" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Laden van VPN-configuratie mislukt" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Laden van klembordconfiguratie mislukt." - }, - "Failed to move job": { - "Failed to move job": "Verplaatsen van taak mislukt" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Ontleden van plugin_settings.json mislukt" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Ontleden van session.json mislukt" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Ontleden van settings.json mislukt" - }, - "Failed to pause printer": { - "Failed to pause printer": "Pauzeren van printer mislukt" - }, - "Failed to pin entry": { - "Failed to pin entry": "Vastmaken van item mislukt" - }, - "Failed to print test page": { - "Failed to print test page": "Afdrukken van testpagina mislukt" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Weigeren van koppeling mislukt" - }, - "Failed to remove device": { - "Failed to remove device": "Verwijderen van apparaat mislukt" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Verwijderen van sneltoets mislukt" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Verwijderen van printer uit klasse mislukt" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Audiosysteem herstarten mislukt" - }, - "Failed to restart job": { - "Failed to restart job": "Herstarten van taak mislukt" - }, - "Failed to resume printer": { - "Failed to resume printer": "Hervatten van printer mislukt" - }, - "Failed to ring device": { - "Failed to ring device": "Klingelen van apparaat mislukt" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Uitvoeren van 'dms greeter status' mislukt. Zorg ervoor dat DMS is geïnstalleerd en dms in het PATH staat." - }, - "Failed to save audio config": { - "Failed to save audio config": "Audio-configuratie opslaan mislukt" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Opslaan van klembordinstelling mislukt" - }, - "Failed to save keybind": { - "Failed to save keybind": "Opslaan van sneltoets mislukt" - }, - "Failed to save profile file": { - "Failed to save profile file": "Kon profielbestand niet opslaan" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Verzenden van klembord mislukt" - }, - "Failed to send file": { - "Failed to send file": "Verzenden van bestand mislukt" - }, - "Failed to send ping": { - "Failed to send ping": "Verzenden van ping mislukt" - }, - "Failed to set brightness": { - "Failed to set brightness": "Instellen van helderheid mislukt" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Instellen van nachtmodus-locatie mislukt" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Instellen van nachtmodus-schema mislukt" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Instellen van nachtmodus-temperatuur mislukt" - }, - "Failed to set power profile": { - "Failed to set power profile": "Instellen van energieprofiel mislukt" - }, - "Failed to set profile image": { - "Failed to set profile image": "Instellen van profielafbeelding mislukt" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Instellen van profielafbeelding mislukt: %1" - }, - "Failed to share": { - "Failed to share": "Delen mislukt" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Starten van verbinding met %1 mislukt" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Losmaken van item mislukt" - }, - "Failed to update VPN": { - "Failed to update VPN": "Bijwerken van VPN mislukt" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Bijwerken van automatisch verbinden mislukt" - }, - "Failed to update description": { - "Failed to update description": "Bijwerken van beschrijving mislukt" - }, - "Failed to update location": { - "Failed to update location": "Bijwerken van locatie mislukt" - }, - "Failed to update sharing": { - "Failed to update sharing": "Bijwerken van delen mislukt" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Schrijven van tijdelijk bestand voor validatie mislukt" - }, - "Features": { - "Features": "Functies" - }, - "Feels": { - "Feels": "Voelt als" - }, - "Feels Like": { - "Feels Like": "Gevoelstemperatuur" - }, - "Feels Like %1°": { - "Feels Like %1°": "Voelt als %1°" - }, - "Fidelity": { - "Fidelity": "Getrouwheid" - }, - "Field": { - "Field": "Veld" - }, - "File": { - "File": "Bestand" - }, - "File Already Exists": { - "File Already Exists": "Bestand bestaat al" - }, - "File Information": { - "File Information": "Bestandsinformatie" - }, - "File received from": { - "File received from": "Bestand ontvangen van" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Bestandszoeken vereist dsearch\nInstalleer via github.com/morelazers/dsearch" - }, - "Files": { - "Files": "Bestanden" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Bestandssysteemgebruik monitoren" - }, - "Fill": { - "Fill": "Vullen" - }, - "Find in Text": { - "Find in Text": "Zoeken in tekst" - }, - "Find in note...": { - "Find in note...": "Zoeken in notitie..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "Beschikbaarheid van vingerafdrukscanner kon niet worden bevestigd." - }, - "Fingerprint error": { - "Fingerprint error": "Vingerafdrukfout" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "Vingerafdrukfout: %1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "Vingerafdruk niet herkend (%1/%2). Probeer het opnieuw of gebruik een wachtwoord." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Vingerafdrukscanner gedetecteerd, maar er zijn nog geen afdrukken geregistreerd. U kunt dit nu inschakelen en later registreren." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "Vingerafdrukscanner gedetecteerd, maar er zijn nog geen afdrukken geregistreerd. U kunt dit nu inschakelen en later Sync uitvoeren." - }, - "Finish": { - "Finish": "Voltooien" - }, - "First Day of Week": { - "First Day of Week": "Eerste dag van de week" - }, - "First Time Setup": { - "First Time Setup": "Eerste installatie" - }, - "Fit": { - "Fit": "Passend" - }, - "Fix Now": { - "Fix Now": "Nu repareren" - }, - "Fixing...": { - "Fixing...": "Repareren..." - }, - "Flags": { - "Flags": "Vlaggen" - }, - "Flipped": { - "Flipped": "Gespiegeld" - }, - "Flipped 180°": { - "Flipped 180°": "Gespiegeld 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Gespiegeld 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Gespiegeld 90°" - }, - "Float": { - "Float": "Zweven" - }, - "Focus": { - "Focus": "Focus" - }, - "Focus at Startup": { - "Focus at Startup": "Focus bij opstarten" - }, - "Focused Border": { - "Focused Border": "Gefocuste rand" - }, - "Focused Color": { - "Focused Color": "Gefocuste kleur" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Alleen op actieve monitor" - }, - "Focused Window": { - "Focused Window": "Actieve venster" - }, - "Focused monitor only": { - "Focused monitor only": "Alleen op actieve monitor" - }, - "Fog": { - "Fog": "Mist" - }, - "Folder": { - "Folder": "Map" - }, - "Folders": { - "Folders": "Mappen" - }, - "Follow DMS background color": { - "Follow DMS background color": "DMS-achtergrondkleur volgen" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Monitorfocus volgen" - }, - "Follow focus": { - "Follow focus": "Focus volgen" - }, - "Font": { - "Font": "Lettertype" - }, - "Font Family": { - "Font Family": "Lettertypefamilie" - }, - "Font Scale": { - "Font Scale": "Schaal lettertype" - }, - "Font Size": { - "Font Size": "Lettergrootte" - }, - "Font Weight": { - "Font Weight": "Letterdikte" - }, - "Font used on the login screen": { - "Font used on the login screen": "Lettertype dat op het aanmeldscherm wordt gebruikt" - }, - "Force HDR": { - "Force HDR": "HDR forceren" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Geforceerd beëindigen (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Breed kleurengamma forceren" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Dwing terminalapplicaties altijd donkere kleurenschema's te gebruiken" - }, - "Forecast": { - "Forecast": "Voorspelling" - }, - "Forecast Days": { - "Forecast Days": "Dagen voorspelling" - }, - "Forecast Not Available": { - "Forecast Not Available": "Voorspelling niet beschikbaar" - }, - "Forever": { - "Forever": "Voor altijd" - }, - "Forget": { - "Forget": "Vergeten" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "\"%1\" vergeten?" - }, - "Forget Device": { - "Forget Device": "Apparaat vergeten" - }, - "Forget Network": { - "Forget Network": "Netwerk vergeten" - }, - "Forgot network %1": { - "Forgot network %1": "Netwerk %1 vergeten" - }, - "Format Legend": { - "Format Legend": "Legenda voor notatie" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "%1 pakket gevonden om bij te werken:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "%1 pakketten gevonden om bij te werken:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "VRAM/geheugen vrijmaken wanneer het startmenu gesloten is. Dit kan een lichte vertraging veroorzaken bij het heropenen." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "IJzel" - }, - "Frequency": { - "Frequency": "Frequentie" - }, - "Fruit Salad": { - "Fruit Salad": "Fruitsalade" - }, - "Full Command:": { - "Full Command:": "Volledige opdracht:" - }, - "Full Content": { - "Full Content": "Volledige inhoud" - }, - "Full Day & Month": { - "Full Day & Month": "Volledige dag & maand" - }, - "Full with Year": { - "Full with Year": "Volledig met jaar" - }, - "Fullscreen": { - "Fullscreen": "Volledig scherm" - }, - "Fullscreen Only": { - "Fullscreen Only": "Alleen volledig scherm" - }, - "Fully Charged": { - "Fully Charged": "Volledig opgeladen" - }, - "Fun": { - "Fun": "Plezier" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: raster • Z/X: grootte" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "GPU-bewaking" - }, - "GPU Temperature": { - "GPU Temperature": "GPU-temperatuur" - }, - "GPU temperature display": { - "GPU temperature display": "GPU-temperatuurweergave" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE's, meer" - }, - "Games": { - "Games": "Spellen" - }, - "Gamma Control": { - "Gamma Control": "Gammaregeling" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Gammaregeling niet beschikbaar. Vereist DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "Genereer basisconfiguraties voor GTK3/4 of QT5/QT6 (vereist qt6ct-kde) om de DMS-kleuren te volgen. Slechts eenmalig nodig.

        Het wordt aanbevolen om adw-gtk3 te configureren voordat u GTK-thema's toepast." - }, - "Generic": { - "Generic": "Generiek" - }, - "Get Started": { - "Get Started": "Aan de slag" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Alle animatieduren globaal schalen" - }, - "Golden Hour": { - "Golden Hour": "Gouden uur" - }, - "Good": { - "Good": "Goed" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Goth-hoekradius" - }, - "Goth Corners": { - "Goth Corners": "Goth-hoeken" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Het scherm geleidelijk vervagen voor vergrendeling met een instelbare vervalperiode" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Het scherm geleidelijk vervagen voor het uitschakelen van beeldschermen met een instelbare vervalperiode" - }, - "Graph Time Range": { - "Graph Time Range": "Tijdsbereik grafiek" - }, - "Graphics": { - "Graphics": "Grafisch" - }, - "Greeter": { - "Greeter": "Greeter" - }, - "Greeter Appearance": { - "Greeter Appearance": "Uiterlijk Greeter" - }, - "Greeter Behavior": { - "Greeter Behavior": "Gedrag Greeter" - }, - "Greeter Status": { - "Greeter Status": "Status Greeter" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Greeter geactiveerd. greetd is nu ingeschakeld." - }, - "Greeter font": { - "Greeter font": "Lettertype Greeter" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Alleen Greeter — heeft geen invloed op de hoofdklok" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Alleen Greeter — indeling voor de datum op het aanmeldscherm" - }, - "Grid": { - "Grid": "Raster" - }, - "Grid Columns": { - "Grid Columns": "Rasterkolommen" - }, - "Grid: OFF": { - "Grid: OFF": "Raster: UIT" - }, - "Grid: ON": { - "Grid: ON": "Raster: AAN" - }, - "Group": { - "Group": "Groep" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Werkblad-apps groeperen" - }, - "Group by App": { - "Group by App": "Groeperen op app" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Meerdere vensters van dezelfde app groeperen met een indicator voor het aantal" - }, - "Group removed": { - "Group removed": "Groep verwijderd" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Herhaalde applicatiepictogrammen in niet-gefocusseerde werkbladen groeperen" - }, - "Groups": { - "Groups": "Groepen" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR Tone Mapping" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "HDR-modus is experimenteel. Controleer of uw monitor HDR ondersteunt voordat u dit inschakelt." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML gekopieerd naar klembord" - }, - "Health": { - "Health": "Gezondheid" - }, - "Heavy Rain": { - "Heavy Rain": "Zware regen" - }, - "Heavy Snow": { - "Heavy Snow": "Zware sneeuwval" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Zware sneeuwbuien" - }, - "Height": { - "Height": "Hoogte" - }, - "Held": { - "Held": "Vastgehouden" - }, - "Help": { - "Help": "Hulp" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Sluimerstand" - }, - "Hidden": { - "Hidden": "Verborgen" - }, - "Hidden (%1)": { - "Hidden (%1)": "Verborgen (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Verborgen apps" - }, - "Hidden Network": { - "Hidden Network": "Verborgen netwerk" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Verborgen apps verschijnen niet in de starter. Klik rechts op een app en selecteer 'App verbergen' om deze te verbergen." - }, - "Hide": { - "Hide": "Verbergen" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Derde partijen verbergen" - }, - "Hide App": { - "Hide App": "App verbergen" - }, - "Hide Delay": { - "Hide Delay": "Verbergvertraging" - }, - "Hide Indicators": { - "Hide Indicators": "Indicatoren verbergen" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Updater-widget verbergen" - }, - "Hide When Typing": { - "Hide When Typing": "Verbergen tijdens typen" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Verbergen wanneer vensters open zijn" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Cursor verbergen na inactiviteit (0 = uitgeschakeld)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Cursor verbergen bij indrukken van toetsen" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Cursor verbergen bij gebruik van aanraakinvoer" - }, - "Hide device": { - "Hide device": "Apparaat verbergen" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Meldingsinhoud verbergen tot uitgevouwen" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Meldingsinhoud verbergen tot uitgevouwen; pop-ups worden standaard ingeklapt weergegeven" - }, - "Hide on Touch": { - "Hide on Touch": "Verbergen bij aanraking" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Natuurgetrouw palet dat de oorspronkelijke tinten behoudt." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Actieve app in werkruimte markeren" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "Markeer de momenteel actieve app in de werkruimte-indicatoren" - }, - "History": { - "History": "Geschiedenis" - }, - "History Retention": { - "History Retention": "Geschiedenisbehoud" - }, - "History Settings": { - "History Settings": "Geschiedenisinstellingen" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Geschiedenis gewist. %1 vastgemaakte items behouden." - }, - "Hold Duration": { - "Hold Duration": "Houdduur" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Langer ingedrukt houden om te bevestigen" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Ingedrukt houden om energieacties te bevestigen" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Ingedrukt houden om te bevestigen (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Ingedrukt houden om te bevestigen (%1s)" - }, - "Home": { - "Home": "Persoonlijke map" - }, - "Host": { - "Host": "Host" - }, - "Hostname": { - "Hostname": "Hostnaam" - }, - "Hot Corners": { - "Hot Corners": "Hot Corners" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Titel sneltoetsoverlay (optioneel)" - }, - "Hour": { - "Hour": "Uur" - }, - "Hourly": { - "Hourly": "Per uur" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Aantal uren voorspelling" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Hoe vaak de achtergrond moet wisselen" - }, - "How the background image is scaled": { - "How the background image is scaled": "Hoe de achtergrondafbeelding wordt geschaald" - }, - "Humidity": { - "Humidity": "Luchtvochtigheid" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Hyprland Discord-server" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland-indelingsoverschrijvingen" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland-opties" - }, - "Hyprland Website": { - "Hyprland Website": "Hyprland-website" - }, - "I Understand": { - "I Understand": "Ik begrijp het" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP-adres:" - }, - "IP address or hostname": { - "IP address or hostname": "IP-adres of hostnaam" - }, - "ISO Date": { - "ISO Date": "ISO-datum" - }, - "Icon": { - "Icon": "Pictogram" - }, - "Icon Scale": { - "Icon Scale": "Pictogramschaal" - }, - "Icon Size": { - "Icon Size": "Pictogramgrootte" - }, - "Icon Size %": { - "Icon Size %": "Pictogramgrootte %" - }, - "Icon Theme": { - "Icon Theme": "Pictogramthema" - }, - "Idle": { - "Idle": "Inactief" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inactiviteitspreventie" - }, - "Idle Settings": { - "Idle Settings": "Instellingen voor inactiviteit" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Monitoring van inactiviteit niet ondersteund - vereist nieuwere Quickshell-versie" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Als het veld verborgen is, verschijnt het zodra een toets wordt ingedrukt." - }, - "Ignore Completely": { - "Ignore Completely": "Volledig negeren" - }, - "Image": { - "Image": "Afbeelding" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Afbeelding gekopieerd naar klembord" - }, - "Import": { - "Import": "Importeren" - }, - "Import VPN": { - "Import VPN": "VPN importeren" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Kleur inactief beeldscherm" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Overgangen opnemen" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Neem bureaubladacties (snelkoppelingen) op in zoekresultaten." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Incompatibele plug-ins geladen" - }, - "Incorrect password": { - "Incorrect password": "Onjuist wachtwoord" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Onjuist wachtwoord - poging %1 van %2 (blokkering kan volgen)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Onjuist wachtwoord - volgende fouten kunnen leiden tot blokkering van account" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "Onjuist wachtwoord - probeer het opnieuw" - }, - "Indicator Style": { - "Indicator Style": "Indicatorstijl" - }, - "Individual Batteries": { - "Individual Batteries": "Individuele batterijen" - }, - "Individual bar configuration": { - "Individual bar configuration": "Individuele balkconfiguratie" - }, - "Info": { - "Info": "Info" - }, - "Inherit": { - "Inherit": "Overnemen" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Globaal overnemen (Standaard)" - }, - "Inhibitable": { - "Inhibitable": "Onderdrukbaar" - }, - "Input Devices": { - "Input Devices": "Invoerapparaten" - }, - "Input Volume Slider": { - "Input Volume Slider": "Invoervolumeschuif" - }, - "Insert your security key...": { - "Insert your security key...": "Plaats uw beveiligingssleutel..." - }, - "Install": { - "Install": "Installeren" - }, - "Install Greeter": { - "Install Greeter": "Greeter installeren" - }, - "Install Plugin": { - "Install Plugin": "Plug-in installeren" - }, - "Install Theme": { - "Install Theme": "Thema installeren" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Installeer kleurthema's uit het DMS-themaregister" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Installatie voltooid. Greeter is geïnstalleerd." - }, - "Install failed: %1": { - "Install failed: %1": "Installatie mislukt: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Installeer matugen-pakket voor dynamische thema's" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Plug-in '%1' installeren uit het DMS-register?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Plug-ins installeren uit het DMS-plug-inregister" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "De DMS Greeter installeren? Er wordt een terminal geopend voor sudo-authenticatie." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Thema '%1' installeren uit het DMS-register?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Installatie en PAM-configuratie: zie de " - }, - "Installed": { - "Installed": "Geïnstalleerd" - }, - "Installed: %1": { - "Installed: %1": "Geïnstalleerd: %1" - }, - "Installing: %1": { - "Installing: %1": "Installeren: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Intelligent automatisch verbergen" - }, - "Intensity": { - "Intensity": "Intensiteit" - }, - "Interface:": { - "Interface:": "Interface:" - }, - "Interlock Open": { - "Interlock Open": "Vergrendeling open" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Interval" - }, - "Invalid configuration": { - "Invalid configuration": "Ongeldige configuratie" - }, - "Invert on mode change": { - "Invert on mode change": "Omkeren bij moduswisseling" - }, - "Iris Bloom": { - "Iris Bloom": "Irisbloei" - }, - "Isolate Displays": { - "Isolate Displays": "Beeldschermen isoleren" - }, - "Jobs": { - "Jobs": "Taken" - }, - "Jobs: ": { - "Jobs: ": "Taken: " - }, - "Keep Awake": { - "Keep Awake": "Wakker houden" - }, - "Keep Changes": { - "Keep Changes": "Wijzigingen behouden" - }, - "Keeping Awake": { - "Keeping Awake": "Wakker houdend" - }, - "Kernel": { - "Kernel": "Kernel" - }, - "Key": { - "Key": "Toets" - }, - "Keybind Sources": { - "Keybind Sources": "Sneltoetsbronnen" - }, - "Keybinds": { - "Keybinds": "Sneltoetsen" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Zoekinstellingen sneltoetsen" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Sneltoetsen getoond naast gewone zoekresultaten" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Naam toetsenbordindeling" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Sneltoetsen" - }, - "Keys": { - "Keys": "Toetsen" - }, - "Kill": { - "Kill": "Beëindigen" - }, - "Kill Process": { - "Kill Process": "Proces beëindigen" - }, - "Kill Session": { - "Kill Session": "Sessie beëindigen" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED-apparaat" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC-kanaal" - }, - "LabWC Website": { - "LabWC Website": "LabWC-website" - }, - "Large": { - "Large": "Groot" - }, - "Largest": { - "Largest": "Grootst" - }, - "Last hour": { - "Last hour": "Afgelopen uur" - }, - "Last launched %1": { - "Last launched %1": "Laatst gestart %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Laatst gestart: %1 dag geleden" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Laatst gestart: %1 dagen geleden" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Laatst gestart: %1 uur geleden" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Laatst gestart: %1 uur geleden" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Laatst gestart: %1 minuut geleden" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Laatst gestart: %1 minuten geleden" - }, - "Last launched just now": { - "Last launched just now": "Zojuist gestart" - }, - "Latitude": { - "Latitude": "Breedtegraad" - }, - "Launch": { - "Launch": "Starten" - }, - "Launch Prefix": { - "Launch Prefix": "Startvoorvoegsel" - }, - "Launch on dGPU": { - "Launch on dGPU": "Starten op dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "Start standaard op dGPU" - }, - "Launcher": { - "Launcher": "Starter" - }, - "Launcher Button": { - "Launcher Button": "Startknop" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Logo startknop" - }, - "Layout": { - "Layout": "Indeling" - }, - "Layout Overrides": { - "Layout Overrides": "Indeling overschrijven" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "Lay-out en moduleposities op de Greeter worden gesynchroniseerd met je shell (bijv. balkconfiguratie). Voer Sync uit om toe te passen." - }, - "Left": { - "Left": "Links" - }, - "Left Center": { - "Left Center": "Middenlinks" - }, - "Left Section": { - "Left Section": "Linkersectie" - }, - "Light Direction": { - "Light Direction": "Lichtrichting" - }, - "Light Mode": { - "Light Mode": "Lichte modus" - }, - "Light Rain": { - "Light Rain": "Lichte regen" - }, - "Light Snow": { - "Light Snow": "Lichte sneeuwval" - }, - "Light Snow Showers": { - "Light Snow Showers": "Lichte sneeuwbuien" - }, - "Light mode base": { - "Light mode base": "Lichte modus basis" - }, - "Light mode harmony": { - "Light mode harmony": "Lichte modus harmonie" - }, - "Line": { - "Line": "Lijn" - }, - "Line: %1": { - "Line: %1": "Regel: %1" - }, - "Linear": { - "Linear": "Lineair" - }, - "Lines: %1": { - "Lines: %1": "Regels: %1" - }, - "List": { - "List": "Lijst" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Levendig palet met verzadigde accenten." - }, - "Load Average": { - "Load Average": "Gemiddelde belasting" - }, - "Loading codecs...": { - "Loading codecs...": "Codecs laden..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Sneltoetsen laden..." - }, - "Loading trending...": { - "Loading trending...": "Trending laden..." - }, - "Loading...": { - "Loading...": "Laden..." - }, - "Local": { - "Local": "Lokaal" - }, - "Locale": { - "Locale": "Locale" - }, - "Locale Settings": { - "Locale Settings": "Locale-instellingen" - }, - "Location": { - "Location": "Locatie" - }, - "Location Search": { - "Location Search": "Locatie zoeken" - }, - "Lock": { - "Lock": "Vergrendelen" - }, - "Lock Screen": { - "Lock Screen": "Vergrendelscherm" - }, - "Lock Screen Display": { - "Lock Screen Display": "Weergave vergrendelscherm" - }, - "Lock Screen Format": { - "Lock Screen Format": "Notatie vergrendelscherm" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Gedrag vergrendelscherm" - }, - "Lock Screen layout": { - "Lock Screen layout": "Indeling vergrendelscherm" - }, - "Lock at startup": { - "Lock at startup": "Vergrendelen bij opstarten" - }, - "Lock before suspend": { - "Lock before suspend": "Vergrendelen voor opschorten" - }, - "Lock fade grace period": { - "Lock fade grace period": "Vervalperiode vergrendelvervaging" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "Verificatiewijzigingen voor het vergrendelscherm worden automatisch toegepast en kunnen een terminal openen wanneer sudo-verificatie vereist is." - }, - "Locked": { - "Locked": "Vergrendeld" - }, - "Log Out": { - "Log Out": "Afmelden" - }, - "Logging in...": { - "Logging in...": "Inloggen..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Aanmeld-authenticatie" - }, - "Long": { - "Long": "Lang" - }, - "Long Text": { - "Long Text": "Lange tekst" - }, - "Long press": { - "Long press": "Lang indrukken" - }, - "Longitude": { - "Longitude": "Lengtegraad" - }, - "Low Priority": { - "Low Priority": "Lage prioriteit" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Zorg ervoor dat KDE Connect of Valent actief is op je andere apparaten" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Plug-ins beheren en configureren voor uitbreiding van DMS-functionaliteit" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Beheer tot 4 onafhankelijke balkconfiguraties. Elke balk heeft zijn eigen positie, widgets, stijl en beeldschermtoewijzing." - }, - "Management": { - "Management": "Beheer" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC-indelingsoverschrijvingen" - }, - "Manual": { - "Manual": "Handmatig" - }, - "Manual Coordinates": { - "Manual Coordinates": "Handmatige coördinaten" - }, - "Manual Direction": { - "Manual Direction": "Handmatige richting" - }, - "Manual Gap Size": { - "Manual Gap Size": "Handmatige grootte tussenruimte" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Handmatig tonen/verbergen" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Koppel vensterklassennamen aan pictogramnamen voor correcte weergave" - }, - "Margin": { - "Margin": "Marge" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Markeervoorraad leeg" - }, - "Marker Supply Low": { - "Marker Supply Low": "Markeervoorraad laag" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Afvaltank bijna vol" - }, - "Marker Waste Full": { - "Marker Waste Full": "Afvaltank vol" - }, - "Match Criteria": { - "Match Criteria": "Overeenkomstcriteria" - }, - "Matches profile: %1": { - "Matches profile: %1": "Komt overeen met profiel: %1" - }, - "Material Colors": { - "Material Colors": "Material-kleuren" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Op Material Design geïnspireerde kleurthema's" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Material-kleuren gegenereerd van achtergrond" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "Op Material Design geïnspireerde schaduwen en diepte (elevation) op modale vensters, pop-outs en dialoogvensters" - }, - "Matugen Contrast": { - "Matugen Contrast": "Matugen Contrast" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen ontbreekt" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen-palet" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Doelbeeldscherm Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen-sjablonen" - }, - "Max Edges": { - "Max Edges": "Max. randen" - }, - "Max H": { - "Max H": "Max. H" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Max. vastgezette apps" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Max. vastgezette apps (0 = onbeperkt)" - }, - "Max Running Apps": { - "Max Running Apps": "Max. actieve apps" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Max. actieve apps (0 = onbeperkt)" - }, - "Max Volume": { - "Max Volume": "Max. volume" - }, - "Max W": { - "Max W": "Max. B" - }, - "Max apps to show": { - "Max apps to show": "Maximaal aantal te tonen apps" - }, - "Max to Edges": { - "Max to Edges": "Maximaliseren naar randen" - }, - "Maximize": { - "Maximize": "Maximaliseren" - }, - "Maximize Detection": { - "Maximize Detection": "Maximalisatiedetectie" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Widgetpictogrammen maximaliseren" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Widgettekst maximaliseren" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maximale grootte item" - }, - "Maximum History": { - "Maximum History": "Maximale geschiedenis" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Maximaal aantal vastgemaakte items" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "Maximaal aantal vingerafdrukpogingen bereikt. Gebruik uw wachtwoord." - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Maximaal aantal te bewaren klemborditems" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Maximaal aantal items dat kan worden opgeslagen" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Maximaal aantal te bewaren meldingen" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Maximaal aantal vastgemaakte items bereikt" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Maximale grootte per klemborditem" - }, - "Media": { - "Media": "Media" - }, - "Media Controls": { - "Media Controls": "Mediabediening" - }, - "Media Empty": { - "Media Empty": "Media leeg" - }, - "Media Jam": { - "Media Jam": "Media vastgelopen" - }, - "Media Low": { - "Media Low": "Media laag" - }, - "Media Needed": { - "Media Needed": "Media nodig" - }, - "Media Playback": { - "Media Playback": "Media-weergave" - }, - "Media Player": { - "Media Player": "Mediaspeler" - }, - "Media Player Settings": { - "Media Player Settings": "Instellingen mediaspeler" - }, - "Media Players": { - "Media Players": "Mediaspelers" - }, - "Media Players (": { - "Media Players (": "Mediaspelers (" - }, - "Media Volume": { - "Media Volume": "Mediavolume" - }, - "Medium": { - "Medium": "Middel" - }, - "Memory": { - "Memory": "Geheugen" - }, - "Memory Graph": { - "Memory Graph": "Geheugengrafiek" - }, - "Memory Usage": { - "Memory Usage": "Geheugengebruik" - }, - "Memory usage indicator": { - "Memory usage indicator": "Indicator geheugengebruik" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Bericht" - }, - "Message Content": { - "Message Content": "Berichtinhoud" - }, - "Microphone": { - "Microphone": "Microfoon" - }, - "Microphone Mute": { - "Microphone Mute": "Microfoon dempen" - }, - "Microphone Volume": { - "Microphone Volume": "Microfoonvolume" - }, - "Microphone settings": { - "Microphone settings": "Microfooninstellingen" - }, - "Microphone volume control": { - "Microphone volume control": "Microfoonvolumeregeling" - }, - "Middle Section": { - "Middle Section": "Middensectie" - }, - "Min H": { - "Min H": "Min. H" - }, - "Min W": { - "Min W": "Min. B" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Minimalistisch palet gebaseerd op één enkele tint." - }, - "Minute": { - "Minute": "Minuut" - }, - "Mirror Display": { - "Mirror Display": "Beeldscherm spiegelen" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Ontbrekende omgevingsvariabelen" - }, - "Modal Background": { - "Modal Background": "Modale achtergrond" - }, - "Modal Shadows": { - "Modal Shadows": "Schaduwen modale vensters" - }, - "Modals": { - "Modals": "Modale vensters" - }, - "Mode": { - "Mode": "Modus" - }, - "Mode:": { - "Mode:": "Modus:" - }, - "Model": { - "Model": "Model" - }, - "Modified": { - "Modified": "Gewijzigd" - }, - "Modular widget bar": { - "Modular widget bar": "Modulaire widgetbalk" - }, - "Monitor": { - "Monitor": "Monitor" - }, - "Monitor Configuration": { - "Monitor Configuration": "Beeldschermconfiguratie" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Vervalperiode schermvervaging" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Beeldscherm waarvan de achtergrond de dynamische themakleuren bepaalt" - }, - "Monochrome": { - "Monochrome": "Monochroom" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "Monospace-lettertype" - }, - "Month Date": { - "Month Date": "Maand Datum" - }, - "Morning": { - "Morning": "Ochtend" - }, - "Mount Points": { - "Mount Points": "Aankoppelpunten" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Uiterlijk muisaanwijzer" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Grootte muisaanwijzer in pixels" - }, - "Move": { - "Move": "Verplaatsen" - }, - "Move Widget": { - "Move Widget": "Widget verplaatsen" - }, - "Moving to Paused": { - "Moving to Paused": "Overschakelen naar gepauzeerd" - }, - "Multi-Monitor": { - "Multi-Monitor": "Multi-monitor" - }, - "Multiplexer": { - "Multiplexer": "Multiplexer" - }, - "Multiplexer Type": { - "Multiplexer Type": "Multiplexer-type" - }, - "Multiplexers": { - "Multiplexers": "Multiplexers" - }, - "Music": { - "Music": "Muziek" - }, - "Mute Popups": { - "Mute Popups": "Pop-ups dempen" - }, - "Mute popups for %1": { - "Mute popups for %1": "Pop-ups dempen voor %1" - }, - "Muted": { - "Muted": "Gedempt" - }, - "Muted Apps": { - "Muted Apps": "Gedempte apps" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Gedempt palet met ingetogen, rustgevende tinten." - }, - "NM not supported": { - "NM not supported": "NM niet ondersteund" - }, - "Name": { - "Name": "Naam" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Pictogrammen voor benoemde werkbladen" - }, - "Navigate": { - "Navigate": "Navigeren" - }, - "Navigation": { - "Navigation": "Navigatie" - }, - "Network": { - "Network": "Netwerk" - }, - "Network Graph": { - "Network Graph": "Netwerkgrafiek" - }, - "Network Info": { - "Network Info": "Netwerkinfo" - }, - "Network Information": { - "Network Information": "Netwerkinformatie" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Netwerknaam (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Netwerksnelheidsmeter" - }, - "Network Status": { - "Network Status": "Netwerkstatus" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Weergave van download- en uploadsnelheid" - }, - "Neutral": { - "Neutral": "Neutraal" - }, - "Never": { - "Never": "Nooit" - }, - "Never used": { - "Never used": "Nooit gebruikt" - }, - "New": { - "New": "Nieuw" - }, - "New Key": { - "New Key": "Nieuwe toets" - }, - "New Keybind": { - "New Keybind": "Nieuwe sneltoets" - }, - "New Notification": { - "New Notification": "Nieuwe melding" - }, - "New Session": { - "New Session": "Nieuwe sessie" - }, - "New Window Rule": { - "New Window Rule": "Nieuwe vensterregel" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Nieuwe groepsnaam..." - }, - "Next": { - "Next": "Volgende" - }, - "Next Transition": { - "Next Transition": "Volgende overgang" - }, - "Night": { - "Night": "Nacht" - }, - "Night Mode": { - "Night Mode": "Nachtmodus" - }, - "Night Temperature": { - "Night Temperature": "Nachttemperatuur" - }, - "Night mode & gamma": { - "Night mode & gamma": "Nachtmodus & gamma" - }, - "Niri Integration": { - "Niri Integration": "Niri-integratie" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri-indelingsoverschrijvingen" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri-compositoracties (focus, verplaatsen, enz.)" - }, - "No": { - "No": "Nee" - }, - "No Active Players": { - "No Active Players": "Geen actieve spelers" - }, - "No Anim": { - "No Anim": "Geen animatie" - }, - "No Background": { - "No Background": "Geen achtergrond" - }, - "No Battery": { - "No Battery": "Geen batterij" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Geen Bluetooth-adapter gevonden" - }, - "No Blur": { - "No Blur": "Geen vervaging" - }, - "No Border": { - "No Border": "Geen rand" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Geen DMS-sneltoetsen geconfigureerd" - }, - "No Dim": { - "No Dim": "Niet dimmen" - }, - "No Focus": { - "No Focus": "Geen focus" - }, - "No GPU detected": { - "No GPU detected": "Geen GPU gedetecteerd" - }, - "No GPUs detected": { - "No GPUs detected": "Geen GPU's gedetecteerd" - }, - "No History": { - "No History": "Geen geschiedenis" - }, - "No Media": { - "No Media": "Geen media" - }, - "No Round": { - "No Round": "Niet afronden" - }, - "No Rounding": { - "No Rounding": "Geen afronding" - }, - "No Shadow": { - "No Shadow": "Geen schaduw" - }, - "No VPN profiles": { - "No VPN profiles": "Geen VPN-profielen" - }, - "No Weather": { - "No Weather": "Geen weergegevens" - }, - "No Weather Data": { - "No Weather Data": "Geen weergegevens" - }, - "No Weather Data Available": { - "No Weather Data Available": "Geen weergegevens beschikbaar" - }, - "No action": { - "No action": "Geen actie" - }, - "No active %1 sessions": { - "No active %1 sessions": "Geen actieve %1-sessies" - }, - "No adapter": { - "No adapter": "Geen adapter" - }, - "No adapters": { - "No adapters": "Geen adapters" - }, - "No app customizations.": { - "No app customizations.": "Geen app-aanpassingen." - }, - "No apps found": { - "No apps found": "Geen apps gevonden" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Er zijn nog geen apps gestart." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Geen apps gedempt. Klik met de rechtermuisknop op een melding en kies \"Pop-ups dempen\" om er hier een toe te voegen." - }, - "No battery": { - "No battery": "Geen batterij" - }, - "No brightness devices available": { - "No brightness devices available": "Geen helderheidsapparaten beschikbaar" - }, - "No changes": { - "No changes": "Geen wijzigingen" - }, - "No checks passed": { - "No checks passed": "Geen controles geslaagd" - }, - "No custom theme file": { - "No custom theme file": "Geen aangepast themabestand" - }, - "No devices": { - "No devices": "Geen apparaten" - }, - "No devices connected": { - "No devices connected": "Geen apparaten verbonden" - }, - "No devices found": { - "No devices found": "Geen apparaten gevonden" - }, - "No disk data": { - "No disk data": "Geen schijfgegevens" - }, - "No disk data available": { - "No disk data available": "Geen schijfgegevens beschikbaar" - }, - "No drivers found": { - "No drivers found": "Geen stuurprogramma's gevonden" - }, - "No errors": { - "No errors": "Geen fouten" - }, - "No features enabled": { - "No features enabled": "Geen functies ingeschakeld" - }, - "No files found": { - "No files found": "Geen bestanden gevonden" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Geen vingerafdrukscanner gedetecteerd." - }, - "No folders found": { - "No folders found": "Geen mappen gevonden" - }, - "No hidden apps.": { - "No hidden apps.": "Geen verborgen apps." - }, - "No info items": { - "No info items": "Geen info-items" - }, - "No information available": { - "No information available": "Geen informatie beschikbaar" - }, - "No input device": { - "No input device": "Geen invoerapparaat" - }, - "No input devices found": { - "No input devices found": "Geen invoerapparaten gevonden" - }, - "No items added yet": { - "No items added yet": "Nog geen items toegevoegd" - }, - "No keybinds found": { - "No keybinds found": "Geen sneltoetsen gevonden" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Geen starter-plug-ins geïnstalleerd." - }, - "No match criteria": { - "No match criteria": "Geen overeenkomstcriteria" - }, - "No matches": { - "No matches": "Geen overeenkomsten" - }, - "No matching processes": { - "No matching processes": "Geen overeenkomende processen" - }, - "No monitors": { - "No monitors": "Geen beeldschermen" - }, - "No mount points found": { - "No mount points found": "Geen aankoppelpunten gevonden" - }, - "No output device": { - "No output device": "Geen uitvoerapparaat" - }, - "No output devices found": { - "No output devices found": "Geen uitvoerapparaten gevonden" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Geen pakketbeheerder gevonden. Installeer 'paru' of 'yay' op Arch-gebaseerde systemen om op updates te controleren." - }, - "No plugin results": { - "No plugin results": "Geen plug-in resultaten" - }, - "No plugins found": { - "No plugins found": "Geen plug-ins gevonden" - }, - "No plugins found.": { - "No plugins found.": "Geen plug-ins gevonden." - }, - "No printer found": { - "No printer found": "Geen printer gevonden" - }, - "No printers configured": { - "No printers configured": "Geen printers geconfigureerd" - }, - "No printers found": { - "No printers found": "Geen printers gevonden" - }, - "No profiles": { - "No profiles": "Geen profielen" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Geen recente klemborditems gevonden" - }, - "No results found": { - "No results found": "Geen resultaten gevonden" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Geen opgeslagen klemborditems" - }, - "No sessions found": { - "No sessions found": "Geen sessies gevonden" - }, - "No status output.": { - "No status output.": "Geen statusuitvoer." - }, - "No themes found": { - "No themes found": "Geen thema's gevonden" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Geen thema's geïnstalleerd. Blader door thema's om te installeren uit het register." - }, - "No trigger": { - "No trigger": "Geen trigger" - }, - "No video found in folder": { - "No video found in folder": "Geen video gevonden in map" - }, - "No wallpaper selected": { - "No wallpaper selected": "Geen achtergrond geselecteerd" - }, - "No wallpapers": { - "No wallpapers": "Geen achtergronden" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Geen achtergronden gevonden\n\nKlik op het map-pictogram hieronder om te bladeren" - }, - "No warnings": { - "No warnings": "Geen waarschuwingen" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Geen widgets toegevoegd. Klik op \"Widget toevoegen\" om te beginnen." - }, - "No widgets available": { - "No widgets available": "Geen widgets beschikbaar" - }, - "No widgets match your search": { - "No widgets match your search": "Geen widgets voldoen aan uw zoekopdracht" - }, - "No window rules configured": { - "No window rules configured": "Geen vensterregels geconfigureerd" - }, - "None": { - "None": "Geen" - }, - "Normal": { - "Normal": "Normaal" - }, - "Normal Font": { - "Normal Font": "Normaal lettertype" - }, - "Normal Priority": { - "Normal Priority": "Normale prioriteit" - }, - "Not available": { - "Not available": "Niet beschikbaar" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Niet beschikbaar — installeer fprintd en pam_fprintd, of configureer greetd PAM." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Niet beschikbaar — installeer fprintd en pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "Niet beschikbaar — installeer of configureer pam_u2f, of configureer greetd PAM." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Niet beschikbaar — installeer of configureer pam_u2f." - }, - "Not connected": { - "Not connected": "Niet verbonden" - }, - "Not detected": { - "Not detected": "Niet gedetecteerd" - }, - "Not paired": { - "Not paired": "Niet gekoppeld" - }, - "Not set": { - "Not set": "Niet ingesteld" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Opmerking: dit verandert alleen het percentage, het beperkt het opladen niet daadwerkelijk." - }, - "Notepad": { - "Notepad": "Kladblok" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Lettertype-instellingen Kladblok" - }, - "Notepad Slideout": { - "Notepad Slideout": "Kladblok-uittrekpaneel" - }, - "Nothing": { - "Nothing": "Niets" - }, - "Nothing to see here": { - "Nothing to see here": "Hier is niets te zien" - }, - "Notification Center": { - "Notification Center": "Meldingencentrum" - }, - "Notification Display": { - "Notification Display": "Meldingweergave" - }, - "Notification Overlay": { - "Notification Overlay": "Meldingen-overlay" - }, - "Notification Popups": { - "Notification Popups": "Meldingen-popups" - }, - "Notification Rules": { - "Notification Rules": "Meldingsregels" - }, - "Notification Settings": { - "Notification Settings": "Meldinginstellingen" - }, - "Notification Timeouts": { - "Notification Timeouts": "Time-outs voor meldingen" - }, - "Notification toast popups": { - "Notification toast popups": "Meldingen-popups" - }, - "Notifications": { - "Notifications": "Meldingen" - }, - "Numbers": { - "Numbers": "Nummers" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numeriek (D/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numeriek (M/D)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "OS-logo" - }, - "OSD Position": { - "OSD Position": "OSD-positie" - }, - "Occupied Color": { - "Occupied Color": "Bezette kleur" - }, - "Off": { - "Off": "Uit" - }, - "Office": { - "Office": "Kantoor" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Offline-rapport" - }, - "Older": { - "Older": "Ouder" - }, - "On": { - "On": "Aan" - }, - "On-Demand": { - "On-Demand": "Op aanvraag" - }, - "On-Screen Displays": { - "On-Screen Displays": "On-screen displays" - }, - "On-screen Displays": { - "On-screen Displays": "On-screen displays" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Gamma alleen aanpassen op basis van tijd- of locatieregels." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "Heeft alleen invloed op door DMS beheerde PAM. Als greetd al pam_fprintd bevat, blijft de vingerafdruk ingeschakeld." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Toon op elk dock alleen vensters van het huidige beeldscherm" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Alleen zichtbaar als sluimerstand wordt ondersteund door uw systeem" - }, - "Opacity": { - "Opacity": "Dekking" - }, - "Opaque": { - "Opaque": "Ondoorzichtig" - }, - "Open": { - "Open": "Openen" - }, - "Open App": { - "Open App": "App openen" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Open KDE Connect op uw telefoon" - }, - "Open Notepad File": { - "Open Notepad File": "Kladblok-bestand openen" - }, - "Open a new note": { - "Open a new note": "Een nieuwe notitie openen" - }, - "Open folder": { - "Open folder": "Map openen" - }, - "Open in Browser": { - "Open in Browser": "Openen in browser" - }, - "Open in terminal": { - "Open in terminal": "Openen in terminal" - }, - "Open search bar to find text": { - "Open search bar to find text": "Zoekbalk openen om tekst te vinden" - }, - "Open with...": { - "Open with...": "Openen met..." - }, - "Opening SMS": { - "Opening SMS": "Sms openen" - }, - "Opening SMS app": { - "Opening SMS app": "Sms-app openen" - }, - "Opening file browser": { - "Opening file browser": "Bestandsbeheer openen" - }, - "Opening files": { - "Opening files": "Bestanden openen" - }, - "Opening terminal: ": { - "Opening terminal: ": "Terminal openen: " - }, - "Optional description": { - "Optional description": "Optionele beschrijving" - }, - "Optional location": { - "Optional location": "Optionele locatie" - }, - "Options": { - "Options": "Opties" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Organiseer widgets in inklapbare groepen" - }, - "Original: %1": { - "Original: %1": "Origineel: %1" - }, - "Other": { - "Other": "Overige" - }, - "Outline": { - "Outline": "Omtrek" - }, - "Output": { - "Output": "Uitvoer" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Uitvoergebied bijna vol" - }, - "Output Area Full": { - "Output Area Full": "Uitvoergebied vol" - }, - "Output Device": { - "Output Device": "Uitvoerapparaat" - }, - "Output Devices": { - "Output Devices": "Uitvoerapparaten" - }, - "Output Tray Missing": { - "Output Tray Missing": "Uitvoerlade ontbreekt" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Outputs-include ontbreekt" - }, - "Overcast": { - "Overcast": "Bewolkt" - }, - "Overflow": { - "Overflow": "Overloop" - }, - "Overridden by config": { - "Overridden by config": "Overschreven door config" - }, - "Override": { - "Override": "Overschrijven" - }, - "Override Border Size": { - "Override Border Size": "Randgrootte overschrijven" - }, - "Override Corner Radius": { - "Override Corner Radius": "Hoekradius overschrijven" - }, - "Override Gaps": { - "Override Gaps": "Tussenruimtes overschrijven" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Globale indelingsinstellingen overschrijven voor deze uitvoer" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Terminal overschrijven met een aangepaste opdracht of script" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "Overschrijf de globale schaduw met instellingen per balk" - }, - "Overrides": { - "Overrides": "Overschrijvingen" - }, - "Overview": { - "Overview": "Overzicht" - }, - "Overview of your network connections": { - "Overview of your network connections": "Overzicht van uw netwerkverbindingen" - }, - "Overwrite": { - "Overwrite": "Overschrijven" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM biedt al vingerafdrukauthenticatie. Schakel dit in om het te tonen bij het inloggen." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM biedt al authenticatie via beveiligingssleutel. Schakel dit in om het te tonen bij het inloggen." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM biedt vingerafdrukauthenticatie, maar de beschikbaarheid kon niet worden bevestigd." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM biedt vingerafdrukauthenticatie, maar er zijn nog geen afdrukken geregistreerd." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM biedt vingerafdrukauthenticatie, maar er is geen scanner gedetecteerd." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Opvullen" - }, - "Pad Hours": { - "Pad Hours": "Uren opvullen" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "Uren opvullen (02:00 in plaats van 2:00)" - }, - "Padding": { - "Padding": "Opvulling" - }, - "Pair": { - "Pair": "Koppelen" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Bluetooth-apparaat koppelen" - }, - "Paired": { - "Paired": "Gekoppeld" - }, - "Pairing": { - "Pairing": "Koppelen" - }, - "Pairing failed": { - "Pairing failed": "Koppelen mislukt" - }, - "Pairing request from": { - "Pairing request from": "Koppelingsverzoek van" - }, - "Pairing request sent": { - "Pairing request sent": "Koppelingsverzoek verzonden" - }, - "Pairing requested": { - "Pairing requested": "Koppeling aangevraagd" - }, - "Pairing...": { - "Pairing...": "Koppelen..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Half bewolkt" - }, - "Passkey:": { - "Passkey:": "Toegangscode:" - }, - "Password": { - "Password": "Wachtwoord" - }, - "Password...": { - "Password...": "Wachtwoord..." - }, - "Paste": { - "Paste": "Plakken" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Pad naar een videobestand of map met video's" - }, - "Pattern": { - "Pattern": "Patroon" - }, - "Pause": { - "Pause": "Pauzeren" - }, - "Paused": { - "Paused": "Gepauzeerd" - }, - "Pending": { - "Pending": "In wachtrij" - }, - "Pending Charge": { - "Pending Charge": "Wachten op opladen" - }, - "Pending Discharge": { - "Pending Discharge": "Wachten op ontladen" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Achtergronden per modus" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Achtergronden per beeldscherm" - }, - "Per-screen config": { - "Per-screen config": "Configuratie per scherm" - }, - "Percentage": { - "Percentage": "Percentage" - }, - "Performance": { - "Performance": "Prestaties" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Toegang geweigerd om profielafbeelding in te stellen." - }, - "Personalization": { - "Personalization": "Persoonlijke instellingen" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect niet beschikbaar" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Phone Connect niet beschikbaar" - }, - "Phone number": { - "Phone number": "Telefoonnummer" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Kies telkens een willekeurige andere video uit dezelfde map" - }, - "Pictures": { - "Pictures": "Afbeeldingen" - }, - "Pin": { - "Pin": "Vastmaken" - }, - "Pin to Dock": { - "Pin to Dock": "Aan dock vastmaken" - }, - "Ping": { - "Ping": "Pingen" - }, - "Ping sent": { - "Ping sent": "Ping verzonden" - }, - "Ping sent to": { - "Ping sent to": "Ping verzonden naar" - }, - "Pinned": { - "Pinned": "Vastgemaakt" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Vastgemaakte en actieve apps met slepen-en-neerzetten" - }, - "Pixelate": { - "Pixelate": "Pixelvorming" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Plaats plug-inmappen hier. Elke plug-in moet een plugin.json manifestbestand hebben." - }, - "Place plugins in %1": { - "Place plugins in %1": "Plaats plug-ins in %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Speel een video af wanneer het scherm vergrendelt." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Geluid afspelen bij nieuwe melding" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Geluid afspelen wanneer stroomkabel wordt aangesloten" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Geluid afspelen wanneer volume wordt aangepast" - }, - "Play sounds for system events": { - "Play sounds for system events": "Geluiden afspelen voor systeemgebeurtenissen" - }, - "Playback": { - "Playback": "Afspelen" - }, - "Playback error: ": { - "Playback error: ": "Afspeelfout: " - }, - "Please wait...": { - "Please wait...": "Even geduld..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Voer een naam in voor uw nieuwe %1-sessie" - }, - "Plugged In": { - "Plugged In": "Aangesloten" - }, - "Plugged in": { - "Plugged in": "Aangesloten" - }, - "Plugin": { - "Plugin": "Plug-in" - }, - "Plugin Directory": { - "Plugin Directory": "Plug-inmap" - }, - "Plugin Management": { - "Plugin Management": "Plug-inbeheer" - }, - "Plugin Visibility": { - "Plugin Visibility": "Zichtbaarheid plug-in" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Plug-in is uitgeschakeld - schakel in via Plug-ininstellingen om te gebruiken" - }, - "Plugins": { - "Plugins": "Plug-ins" - }, - "Pointer": { - "Pointer": "Aanwijzer" - }, - "Popout Shadows": { - "Popout Shadows": "Schaduwen pop-outs" - }, - "Popouts": { - "Popouts": "Pop-outs" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Pop-outs en modalen volgen de globale animatiesnelheid (uitschakelen om onafhankelijk aan te passen)" - }, - "Popup Only": { - "Popup Only": "Alleen pop-up" - }, - "Popup Position": { - "Popup Position": "Popup-positie" - }, - "Popup Shadow": { - "Popup Shadow": "Pop-upschaduw" - }, - "Popup Transparency": { - "Popup Transparency": "Popup-transparantie" - }, - "Popup behavior, position": { - "Popup behavior, position": "Gedrag en positie pop-ups" - }, - "Port": { - "Port": "Poort" - }, - "Portal": { - "Portal": "Portaal" - }, - "Position": { - "Position": "Positie" - }, - "Position, pinned apps": { - "Position, pinned apps": "Positie, vastgemaakte apps" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Mogelijke overschrijfconflicten" - }, - "Power": { - "Power": "Energie" - }, - "Power & Security": { - "Power & Security": "Energie & Beveiliging" - }, - "Power & Sleep": { - "Power & Sleep": "Energie & Slaapstand" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Bevestiging energieactie" - }, - "Power Menu Customization": { - "Power Menu Customization": "Aanpassing energiemenu" - }, - "Power Off": { - "Power Off": "Uitschakelen" - }, - "Power Options": { - "Power Options": "Energieopties" - }, - "Power Profile": { - "Power Profile": "Energieprofiel" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Degradatie energieprofiel" - }, - "Power Saver": { - "Power Saver": "Energiebesparing" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Beeldschermen uitschakelen bij vergrendeling" - }, - "Power profile management available": { - "Power profile management available": "Energieprofielbeheer beschikbaar" - }, - "Power source": { - "Power source": "Voedingsbron" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Vul de laatst succesvolle gebruikersnaam vooraf in op de Greeter" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "Selecteer de laatst gebruikte sessie vooraf op de Greeter" - }, - "Precip": { - "Precip": "Neerslag" - }, - "Precipitation": { - "Precipitation": "Neerslag" - }, - "Precipitation Chance": { - "Precipitation Chance": "Neerslagkans" - }, - "Preference": { - "Preference": "Voorkeur" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Voor ingestelde breedtes (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Druk op 'n' of klik op 'Nieuwe sessie' om er een aan te maken" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Druk op Enter om het audiosysteem te herstarten en de wijziging toe te passen" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Druk Enter om te plakken, Shift+Enter om te kopiëren" - }, - "Press key...": { - "Press key...": "Druk op toets..." - }, - "Pressure": { - "Pressure": "Luchtdruk" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Scherm-time-out voorkomen" - }, - "Preview": { - "Preview": "Voorbeeld" - }, - "Primary": { - "Primary": "Primair" - }, - "Primary Container": { - "Primary Container": "Primaire container" - }, - "Print Server Management": { - "Print Server Management": "Printserverbeheer" - }, - "Print Server not available": { - "Print Server not available": "Printserver niet beschikbaar" - }, - "Printer": { - "Printer": "Printer" - }, - "Printer Classes": { - "Printer Classes": "Printerklassen" - }, - "Printer created successfully": { - "Printer created successfully": "Printer succesvol aangemaakt" - }, - "Printer deleted": { - "Printer deleted": "Printer verwijderd" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Printernaam (geen spaties)" - }, - "Printer reachable": { - "Printer reachable": "Printer bereikbaar" - }, - "Printers": { - "Printers": "Printers" - }, - "Printers: ": { - "Printers: ": "Printers: " - }, - "Prioritize performance": { - "Prioritize performance": "Prestaties prioriteren" - }, - "Priority": { - "Priority": "Prioriteit" - }, - "Privacy Indicator": { - "Privacy Indicator": "Privacy-indicator" - }, - "Privacy Mode": { - "Privacy Mode": "Privacy-modus" - }, - "Private Key Password": { - "Private Key Password": "Wachtwoord privésleutel" - }, - "Process Count": { - "Process Count": "Aantal processen" - }, - "Processes": { - "Processes": "Processen" - }, - "Processes:": { - "Processes:": "Processen:" - }, - "Processing": { - "Processing": "Verwerken" - }, - "Profile Image Error": { - "Profile Image Error": "Fout profielafbeelding" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profiel geactiveerd: %1" - }, - "Profile deleted": { - "Profile deleted": "Profiel verwijderd" - }, - "Profile error": { - "Profile error": "Profiel-fout" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Profielafbeelding is te groot. Gebruik een kleinere afbeelding." - }, - "Profile name": { - "Profile name": "Profielnaam" - }, - "Profile not found": { - "Profile not found": "Profiel niet gevonden" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profiel opgeslagen: %1" - }, - "Protocol": { - "Protocol": "Protocol" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia is niet beschikbaar" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia is niet beschikbaar - video-screensaver vereist Qt multimedia-services" - }, - "Quick Access": { - "Quick Access": "Snelle toegang" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Snelle toegang tot app-starter" - }, - "Quick access to color picker": { - "Quick access to color picker": "Snelle toegang tot kleurkiezer" - }, - "Quick access to notepad": { - "Quick access to notepad": "Snelle toegang tot kladblok" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Uittrekpaneel voor snelle notities" - }, - "Quick system toggles": { - "Quick system toggles": "Snelle systeemschakelaars" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Straal" - }, - "Rain": { - "Rain": "Regen" - }, - "Rain Chance": { - "Rain Chance": "Neerslagkans" - }, - "Rainbow": { - "Rainbow": "Regenboog" - }, - "Random": { - "Random": "Willekeurig" - }, - "Rate": { - "Rate": "Snelheid" - }, - "Read:": { - "Read:": "Lezen:" - }, - "Reason": { - "Reason": "Reden" - }, - "Reboot": { - "Reboot": "Opnieuw opstarten" - }, - "Recent Colors": { - "Recent Colors": "Recente kleuren" - }, - "Recently Used Apps": { - "Recently Used Apps": "Recent gebruikte apps" - }, - "Recommended available": { - "Recommended available": "Aanbevolen beschikbaar" - }, - "Refresh": { - "Refresh": "Verversen" - }, - "Refresh Weather": { - "Refresh Weather": "Weer verversen" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Weigeren" - }, - "Reject Jobs": { - "Reject Jobs": "Taken weigeren" - }, - "Release": { - "Release": "Loslaten" - }, - "Reload Plugin": { - "Reload Plugin": "Plug-in herladen" - }, - "Remaining": { - "Remaining": "Resterend" - }, - "Remaining / Total": { - "Remaining / Total": "Resterend / Totaal" - }, - "Remember Last Query": { - "Remember Last Query": "Laatste zoekopdracht onthouden" - }, - "Remember last session": { - "Remember last session": "Onthoud laatste sessie" - }, - "Remember last user": { - "Remember last user": "Onthoud laatste gebruiker" - }, - "Remove": { - "Remove": "Verwijderen" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Widgetopvulling verwijderen" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Tussenruimte en rand verwijderen wanneer vensters gemaximaliseerd zijn" - }, - "Rename": { - "Rename": "Hernoemen" - }, - "Rename Session": { - "Rename Session": "Sessie hernoemen" - }, - "Rename Workspace": { - "Rename Workspace": "Werkblad hernoemen" - }, - "Repeat": { - "Repeat": "Herhalen" - }, - "Replacement": { - "Replacement": "Vervanging" - }, - "Report": { - "Report": "Rapport" - }, - "Request Pairing": { - "Request Pairing": "Koppeling aanvragen" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Vereis het ingedrukt houden van knop/toets om uitschakelen, opnieuw opstarten, slaapstand, sluimerstand en afmelden te bevestigen" - }, - "Required plugin: ": { - "Required plugin: ": "Vereiste plug-in: " - }, - "Requires %1": { - "Requires %1": "Vereist %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Vereist 'dgop'-tool" - }, - "Requires DMS %1": { - "Requires DMS %1": "Vereist DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Vereist DWL-compositor" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "Vereist een nieuwere versie van Quickshell" - }, - "Requires night mode support": { - "Requires night mode support": "Vereist ondersteuning voor nachtmodus" - }, - "Reset": { - "Reset": "Herstellen" - }, - "Reset Position": { - "Reset Position": "Positie herstellen" - }, - "Reset Size": { - "Reset Size": "Grootte herstellen" - }, - "Reset to default name": { - "Reset to default name": "Terugzetten naar standaardnaam" - }, - "Resize Widget": { - "Resize Widget": "Widgetgrootte wijzigen" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Resolutie & Verversing" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Resolutie, positie, schaal" - }, - "Restart DMS": { - "Restart DMS": "DMS herstarten" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Herstart de DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Audiosysteem herstarten..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "Speciale werkruimtevensters herstellen" - }, - "Resume": { - "Resume": "Hervatten" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Scrollrichting omkeren" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Werkbladwisselrichting omkeren bij scrollen over de balk" - }, - "Revert": { - "Revert": "Terugdraaien" - }, - "Right": { - "Right": "Rechts" - }, - "Right Center": { - "Right Center": "Middenrechts" - }, - "Right Section": { - "Right Section": "Rechtersectie" - }, - "Right Tiling": { - "Right Tiling": "Rechts tegelen" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Rechtsklikken en slepen ergens op de widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Rechtsklikken en slepen aan de rechteronderhoek" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Klik rechts op de widget in de balk om te wisselen" - }, - "Ring": { - "Ring": "Klingelen" - }, - "Ringing": { - "Ringing": "Klingelen" - }, - "Ripple Effects": { - "Ripple Effects": "Rimpel-effecten" - }, - "Root Filesystem": { - "Root Filesystem": "Root-bestandssysteem" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Afgeronde hoeken voor vensters" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Afgeronde hoeken voor vensters (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Afgeronde hoeken voor vensters (decoration.rounding)" - }, - "Rule": { - "Rule": "Regel" - }, - "Rule Name": { - "Rule Name": "Regelnaam" - }, - "Rules (%1)": { - "Rules (%1)": "Regels (%1)" - }, - "Run Again": { - "Run Again": "Opnieuw uitvoeren" - }, - "Run DMS Templates": { - "Run DMS Templates": "DMS-sjablonen uitvoeren" - }, - "Run User Templates": { - "Run User Templates": "Gebruikerssjablonen uitvoeren" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Een programma uitvoeren (bijv. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Een shell-opdracht uitvoeren (bijv. notify-send)" - }, - "Running Apps": { - "Running Apps": "Actieve apps" - }, - "Running Apps Settings": { - "Running Apps Settings": "Instellingen actieve apps" - }, - "Running greeter sync…": { - "Running greeter sync…": "Greeter-synchronisatie uitvoeren…" - }, - "SDR Brightness": { - "SDR Brightness": "SDR-helderheid" - }, - "SDR Saturation": { - "SDR Saturation": "SDR-verzadiging" - }, - "SMS": { - "SMS": "Sms" - }, - "Save": { - "Save": "Opslaan" - }, - "Save Notepad File": { - "Save Notepad File": "Kladblok-bestand opslaan" - }, - "Save QR Code": { - "Save QR Code": "QR-code opslaan" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Opslaan en schakelen tussen beeldschermconfiguraties" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Meldingen met kritieke prioriteit opslaan in geschiedenis" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Gesloten meldingen opslaan in geschiedenis" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Meldingen met lage prioriteit opslaan in geschiedenis" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Meldingen met normale prioriteit opslaan in geschiedenis" - }, - "Save password": { - "Save password": "Wachtwoord opslaan" - }, - "Saved": { - "Saved": "Opgeslagen" - }, - "Saved Configurations": { - "Saved Configurations": "Opgeslagen configuraties" - }, - "Saved Note": { - "Saved Note": "Opgeslagen notitie" - }, - "Saved item deleted": { - "Saved item deleted": "Opgeslagen item verwijderd" - }, - "Saving...": { - "Saving...": "Opslaan..." - }, - "Scale": { - "Scale": "Schaal" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "DankBar-lettergroottes onafhankelijk schalen" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "DankBar-pictogramgroottes onafhankelijk schalen" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Alle lettergroottes in de shell schalen" - }, - "Scan": { - "Scan": "Scannen" - }, - "Scanning": { - "Scanning": "Scannen" - }, - "Scanning...": { - "Scanning...": "Scannen..." - }, - "Science": { - "Science": "Wetenschap" - }, - "Score": { - "Score": "Score" - }, - "Screen Sharing": { - "Screen Sharing": "Schermdelen" - }, - "Screen sharing": { - "Screen sharing": "Schermdelen" - }, - "Scroll": { - "Scroll": "Scrollen" - }, - "Scroll Factor": { - "Scroll Factor": "Scrollfactor" - }, - "Scroll GitHub": { - "Scroll GitHub": "Scroll GitHub" - }, - "Scroll Wheel": { - "Scroll Wheel": "Scrollwiel" - }, - "Scroll song title": { - "Scroll song title": "Liedtitel scrollen" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Titel scrollen als deze niet in widget past" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Gedrag scrollwiel op mediawidget" - }, - "Scrolling": { - "Scrolling": "Scrollen" - }, - "Search App Actions": { - "Search App Actions": "App-acties zoeken" - }, - "Search Options": { - "Search Options": "Zoekopties" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Zoek op toetsencombinatie, beschrijving of actienaam.\n\nDe standaardactie kopieert de sneltoets naar het klembord.\nKlik met rechts of druk op Pijl-rechts om veelgebruikte sneltoetsen vast te pinnen - ze verschijnen bovenaan als u niet zoekt." - }, - "Search for a location...": { - "Search for a location...": "Zoeken naar een locatie..." - }, - "Search keybinds...": { - "Search keybinds...": "Sneltoetsen zoeken..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Zoek sneltoetsen van uw compositor en applicaties" - }, - "Search plugins...": { - "Search plugins...": "Plug-ins zoeken..." - }, - "Search processes...": { - "Search processes...": "Processen zoeken..." - }, - "Search sessions...": { - "Search sessions...": "Sessies zoeken..." - }, - "Search themes...": { - "Search themes...": "Thema's zoeken..." - }, - "Search widgets...": { - "Search widgets...": "Widgets zoeken..." - }, - "Search...": { - "Search...": "Zoeken..." - }, - "Searching...": { - "Searching...": "Zoeken..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Tweede factor (EN)" - }, - "Secondary": { - "Secondary": "Secundair" - }, - "Secured": { - "Secured": "Beveiligd" - }, - "Security": { - "Security": "Beveiliging" - }, - "Security & privacy": { - "Security & privacy": "Beveiliging & privacy" - }, - "Security key mode": { - "Security key mode": "Beveiligingssleutel-modus" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "Beschikbaarheid van beveiligingssleutel kon niet worden bevestigd." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Ondersteuning voor beveiligingssleutels gedetecteerd, maar er is nog geen geregistreerde sleutel gevonden. U kunt dit nu inschakelen en later een sleutel registreren." - }, - "Select": { - "Select": "Selecteren" - }, - "Select Application": { - "Select Application": "Selecteer applicatie" - }, - "Select Bar": { - "Select Bar": "Balk selecteren" - }, - "Select Custom Theme": { - "Select Custom Theme": "Selecteer aangepast thema" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Kies Dock launcher Logo" - }, - "Select File to Send": { - "Select File to Send": "Selecteer bestand om te verzenden" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Startlogo selecteren" - }, - "Select Profile Image": { - "Select Profile Image": "Selecteer profielafbeelding" - }, - "Select Video or Folder": { - "Select Video or Folder": "Selecteer video of map" - }, - "Select Wallpaper": { - "Select Wallpaper": "Selecteer achtergrond" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Selecteer achtergrondmap" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Selecteer een kleur uit het palet of gebruik aangepaste schuifregelaars" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Selecteer een widget om toe te voegen aan uw bureaublad. Elke widget is een apart exemplaar met eigen instellingen." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Selecteer een widget om toe te voegen. U kunt indien nodig meerdere exemplaren van dezelfde widget toevoegen." - }, - "Select a window...": { - "Select a window...": "Selecteer een venster..." - }, - "Select an image file...": { - "Select an image file...": "Selecteer een afbeeldingsbestand..." - }, - "Select at least one provider": { - "Select at least one provider": "Selecteer ten minste één provider" - }, - "Select device": { - "Select device": "Selecteer apparaat" - }, - "Select device...": { - "Select device...": "Selecteer apparaat..." - }, - "Select driver...": { - "Select driver...": "Selecteer stuurprogramma..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Selecteer letterdikte voor UI-tekst" - }, - "Select greeter background image": { - "Select greeter background image": "Selecteer achtergrondafbeelding Greeter" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Selecteer beeldscherm om achtergrond te configureren" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Selecteer monospace-lettertype voor proceslijst en technische weergaven" - }, - "Select network": { - "Select network": "Selecteer netwerk" - }, - "Select system sound theme": { - "Select system sound theme": "Selecteer systeemgeluidsthema" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Selecteer de lettertypefamilie voor UI-tekst" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Selecteer het paletalgoritme voor op achtergrond gebaseerde kleuren" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Selecteer welke sneltoetsproviders moeten worden opgenomen" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Selecteer welke overgangen worden opgenomen in de willekeurige selectie" - }, - "Select...": { - "Select...": "Selecteren..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Geselecteerd afbeeldingsbestand niet gevonden." - }, - "Send": { - "Send": "Verzenden" - }, - "Send Clipboard": { - "Send Clipboard": "Klembord verzenden" - }, - "Send File": { - "Send File": "Bestand verzenden" - }, - "Send SMS": { - "Send SMS": "Sms verzenden" - }, - "Sending": { - "Sending": "Verzenden" - }, - "Separator": { - "Separator": "Scheidingsteken" - }, - "Server": { - "Server": "Server" - }, - "Session Filter": { - "Session Filter": "Sessiefilter" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Aangepaste apparaatnaam instellen" - }, - "Set custom name": { - "Set custom name": "Aangepaste naam instellen" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Stel aangepaste namen in voor uw audio-invoerapparaten" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Stel aangepaste namen in voor uw audio-uitvoerapparaten" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Stel verschillende achtergronden in voor elk aangesloten beeldscherm" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Stel verschillende achtergronden in voor lichte en donkere modus" - }, - "Set key and action to save": { - "Set key and action to save": "Stel toets en actie in om op te slaan" - }, - "Set notification rules": { - "Set notification rules": "Meldingsregels instellen" - }, - "Settings": { - "Settings": "Instellingen" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Instellingen zijn alleen-lezen. Wijzigingen worden niet opgeslagen." - }, - "Setup": { - "Setup": "Instellen" - }, - "Shadow Color": { - "Shadow Color": "Schaduwkleur" - }, - "Shadow Intensity": { - "Shadow Intensity": "Schaduwintensiteit" - }, - "Shadow Opacity": { - "Shadow Opacity": "Schaduwdekking" - }, - "Shadow Override": { - "Shadow Override": "Schaduwoverschrijving" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Schaduwhoogte op balken en panelen" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Schaduwhoogte op modale en dialoogvensters" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "Schaduwhoogte op pop-outs, OSD's en vervolgkeuzemenu's" - }, - "Shadows": { - "Shadows": "Schaduwen" - }, - "Share": { - "Share": "Delen" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Gammaregeling-instellingen delen" - }, - "Share Text": { - "Share Text": "Tekst delen" - }, - "Share URL": { - "Share URL": "URL delen" - }, - "Shared": { - "Shared": "Gedeeld" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Alles wissen • Esc: Sluiten" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter om te plakken" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Kopiëren • Shift+Del: Alles leegmaken • Esc: Sluiten" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Plakken • Shift+Del: Alles wissen • Esc: Sluiten" - }, - "Short": { - "Short": "Kort" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Sneltoets (%1)" - }, - "Shortcuts": { - "Shortcuts": "Sneltoetsen" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Sneltoetsen (%1)" - }, - "Show": { - "Show": "Tonen" - }, - "Show 3rd Party": { - "Show 3rd Party": "Derde partijen tonen" - }, - "Show All Tags": { - "Show All Tags": "Alle tags tonen" - }, - "Show Badge": { - "Show Badge": "Badge tonen" - }, - "Show CPU": { - "Show CPU": "CPU tonen" - }, - "Show CPU Graph": { - "Show CPU Graph": "CPU-grafiek tonen" - }, - "Show CPU Temp": { - "Show CPU Temp": "CPU-temp tonen" - }, - "Show Date": { - "Show Date": "Datum tonen" - }, - "Show Disk": { - "Show Disk": "Schijf tonen" - }, - "Show Dock": { - "Show Dock": "Dock tonen" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Toon gevoelstemperatuur" - }, - "Show Footer": { - "Show Footer": "Voettekst tonen" - }, - "Show Forecast": { - "Show Forecast": "Toon voorspelling" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "GPU-temperatuur tonen" - }, - "Show Header": { - "Show Header": "Koptekst tonen" - }, - "Show Hibernate": { - "Show Hibernate": "Sluimerstand tonen" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Uurnummers tonen" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Toon voorspelling per uur" - }, - "Show Humidity": { - "Show Humidity": "Toon luchtvochtigheid" - }, - "Show Launcher Button": { - "Show Launcher Button": "Startknop tonen" - }, - "Show Line Numbers": { - "Show Line Numbers": "Regelnummers tonen" - }, - "Show Location": { - "Show Location": "Toon locatie" - }, - "Show Lock": { - "Show Lock": "Vergrendelen tonen" - }, - "Show Log Out": { - "Show Log Out": "Afmelden tonen" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Material Design rimpel-animaties tonen op interactieve elementen" - }, - "Show Media Player": { - "Show Media Player": "Mediaspeler tonen" - }, - "Show Memory": { - "Show Memory": "Geheugen tonen" - }, - "Show Memory Graph": { - "Show Memory Graph": "Geheugengrafiek tonen" - }, - "Show Memory in GB": { - "Show Memory in GB": "Toon geheugen in GB" - }, - "Show Network": { - "Show Network": "Netwerk tonen" - }, - "Show Network Graph": { - "Show Network Graph": "Netwerkgrafiek tonen" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Alleen bezette werkbladen tonen" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Aantal in overloop-badge tonen" - }, - "Show Password Field": { - "Show Password Field": "Wachtwoordveld tonen" - }, - "Show Power Actions": { - "Show Power Actions": "Energieacties tonen" - }, - "Show Power Off": { - "Show Power Off": "Uitschakelen tonen" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Toon neerslagkans" - }, - "Show Pressure": { - "Show Pressure": "Toon luchtdruk" - }, - "Show Profile Image": { - "Show Profile Image": "Profielafbeelding tonen" - }, - "Show Reboot": { - "Show Reboot": "Opnieuw opstarten tonen" - }, - "Show Restart DMS": { - "Show Restart DMS": "DMS herstarten tonen" - }, - "Show Saved Items": { - "Show Saved Items": "Toon opgeslagen items" - }, - "Show Seconds": { - "Show Seconds": "Seconden tonen" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Toon zonsopgang/zonsondergang" - }, - "Show Suspend": { - "Show Suspend": "Slaapstand tonen" - }, - "Show Swap": { - "Show Swap": "Toon swap" - }, - "Show System Date": { - "Show System Date": "Systeemdatum tonen" - }, - "Show System Icons": { - "Show System Icons": "Systeempictogrammen tonen" - }, - "Show System Time": { - "Show System Time": "Systeemtijd tonen" - }, - "Show Top Processes": { - "Show Top Processes": "Topprocessen tonen" - }, - "Show Weather Condition": { - "Show Weather Condition": "Toon weersomstandigheid" - }, - "Show Week Number": { - "Show Week Number": "Weeknummer tonen" - }, - "Show Welcome": { - "Show Welcome": "Toon welkom" - }, - "Show Wind Speed": { - "Show Wind Speed": "Toon windsnelheid" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Werkblad-apps tonen" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Alle 9 tags tonen in plaats van alleen bezette tags (alleen DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Toon een omlijningsring rond de indicator van het gefocuste werkblad" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Cava-audiovisualisatie tonen in mediawidget" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Verduisterde overlay tonen achter modale vensters" - }, - "Show device": { - "Show device": "Apparaat tonen" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Dock tonen wanneer zwevende vensters het gebied niet overlappen" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "Toon slagschaduw op meldingspop-ups. Vereist dat M3 Elevation is ingeschakeld in Thema & kleuren." - }, - "Show in GB": { - "Show in GB": "Toon in GB" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Starter-overlay tonen bij typen in Niri-overzicht. Schakel uit om een andere starter te gebruiken." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Toon modustabbladen en toetsenbordhints onderaan." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "Meldingspop-ups alleen op de momenteel actieve monitor tonen" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "Meldingen alleen op de momenteel actieve monitor tonen" - }, - "Show on Last Display": { - "Show on Last Display": "Tonen op laatste beeldscherm" - }, - "Show on Overlay": { - "Show on Overlay": "Tonen op overlay" - }, - "Show on Overview": { - "Show on Overview": "Tonen in overzicht" - }, - "Show on Overview Only": { - "Show on Overview Only": "Alleen tonen op overzicht" - }, - "Show on all connected displays": { - "Show on all connected displays": "Tonen op alle aangesloten beeldschermen" - }, - "Show on screens:": { - "Show on screens:": "Tonen op schermen:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "On-screen display tonen wanneer helderheid wijzigt" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "On-screen display tonen wanneer Caps Lock-status wijzigt" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "On-screen display tonen bij wisselen van audio-uitvoerapparaten" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "On-screen display tonen wanneer status inactiviteitspreventie wijzigt" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "On-screen display (OSD) tonen wanneer de status van de mediaspeler wijzigt" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "On-screen display tonen wanneer volume mediaspeler wijzigt" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "On-screen display tonen wanneer microfoon wordt gedempt/ingeschakeld" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "On-screen display tonen wanneer energieprofiel wijzigt" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "On-screen display tonen wanneer volume wijzigt" - }, - "Show seconds": { - "Show seconds": "Toon seconden" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Weerinformatie tonen in bovenbalk en bedieningspaneel" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Toon weeknummer in de kalender" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Werkbladindexnummers tonen in de werkbladwisselaar in de bovenbalk" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Toon werkbladnaam op horizontale balken, en eerste letter op verticale balken" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Toon werkbladen van het momenteel gefocuste beeldscherm" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Toont alle actieve applicaties met focusindicatie" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Toont huidig werkblad en maakt wisselen mogelijk" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Toont wanneer Caps Lock actief is" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Toont wanneer microfoon, camera of schermdelen actief is" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Afsluiten" - }, - "Signal": { - "Signal": "Signaal" - }, - "Signal:": { - "Signal:": "Signaal:" - }, - "Size": { - "Size": "Grootte" - }, - "Size Constraints": { - "Size Constraints": "Groottebeperkingen" - }, - "Size Offset": { - "Size Offset": "Grootteverschuiving" - }, - "Sizing": { - "Sizing": "Formaat" - }, - "Skip": { - "Skip": "Overslaan" - }, - "Skip confirmation": { - "Skip confirmation": "Bevestiging overslaan" - }, - "Skip setup": { - "Skip setup": "Installatie overslaan" - }, - "Small": { - "Small": "Klein" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Smartcard-authenticatie" - }, - "Smartcard PIN": { - "Smartcard PIN": "Smartcard-pincode" - }, - "Snap": { - "Snap": "Vastklikken" - }, - "Snow": { - "Snow": "Sneeuw" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Sommige plug-ins vereisen een nieuwere versie van DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Alfabetisch sorteren" - }, - "Sort By": { - "Sort By": "Sorteren op" - }, - "Sorting & Layout": { - "Sorting & Layout": "Sortering & Indeling" - }, - "Sound Theme": { - "Sound Theme": "Geluidsthema" - }, - "Sounds": { - "Sounds": "Geluiden" - }, - "Space between windows": { - "Space between windows": "Ruimte tussen vensters" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Ruimte tussen vensters (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Ruimte tussen vensters (gaps_in en gaps_out)" - }, - "Spacer": { - "Spacer": "Afstandhouder" - }, - "Spacing": { - "Spacing": "Tussenruimte" - }, - "Speaker settings": { - "Speaker settings": "Luidsprekerinstellingen" - }, - "Speed": { - "Speed": "Snelheid" - }, - "Spool Area Full": { - "Spool Area Full": "Spool-gebied vol" - }, - "Square Corners": { - "Square Corners": "Vierkante hoeken" - }, - "Stacked": { - "Stacked": "Gestapeld" - }, - "Standard": { - "Standard": "Standaard" - }, - "Start": { - "Start": "Start" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Start KDE Connect of Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Start KDE Connect of Valent om deze plug-in te gebruiken" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Begin hier met het typen van uw notities..." - }, - "State": { - "State": "Status" - }, - "Status": { - "Status": "Status" - }, - "Stopped": { - "Stopped": "Gestopt" - }, - "Stopped Partly": { - "Stopped Partly": "Gedeeltelijk gestopt" - }, - "Stopping": { - "Stopping": "Stoppen" - }, - "Stretch": { - "Stretch": "Uitrekken" - }, - "Stripes": { - "Stripes": "Strepen" - }, - "Summary": { - "Summary": "Samenvatting" - }, - "Sunrise": { - "Sunrise": "Zonsopgang" - }, - "Sunset": { - "Sunset": "Zonsondergang" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Meldingen onderdrukken indien ingeschakeld" - }, - "Surface": { - "Surface": "Oppervlak" - }, - "Surface Variant": { - "Surface Variant": "Oppervlakvariant" - }, - "Suspend": { - "Suspend": "Slaapstand" - }, - "Suspend behavior": { - "Suspend behavior": "Gedrag slaapstand" - }, - "Suspend system after": { - "Suspend system after": "Systeem in slaapstand zetten na" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Onderbreken dan Sluimerstand" - }, - "Sway Website": { - "Sway Website": "Sway-website" - }, - "Switch User": { - "Switch User": "Ander account" - }, - "Switch to power profile": { - "Switch to power profile": "Wisselen naar energieprofiel" - }, - "Sync": { - "Sync": "Sync" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Modus synchroniseren met portaal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Pop-outs & modalen synchroniseren" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Positie synchroniseren over schermen" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Sync is succesvol voltooid." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Donkere modus synchroniseren met instellingsportalen voor systeembrede themahints" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "Sync mislukt in achtergrondmodus. Terminalmodus wordt geprobeerd zodat je interactief kunt authenticeren." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "Sync vereist sudo-authenticatie. Terminal wordt geopend zodat je een wachtwoord of vingerafdruk kunt gebruiken." - }, - "System": { - "System": "Systeem" - }, - "System App Theming": { - "System App Theming": "Thema's systeemapps" - }, - "System Check": { - "System Check": "Systeemcontrole" - }, - "System Default": { - "System Default": "Systeemstandaard" - }, - "System Information": { - "System Information": "Systeeminformatie" - }, - "System Monitor": { - "System Monitor": "Systeemmonitor" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Systeemmonitor niet beschikbaar" - }, - "System Sounds": { - "System Sounds": "Systeemgeluiden" - }, - "System Tray": { - "System Tray": "Systeemvak" - }, - "System Update": { - "System Update": "Systeemupdate" - }, - "System Updater": { - "System Updater": "Systeemupdater" - }, - "System Updates": { - "System Updates": "Systeemupdates" - }, - "System notification area icons": { - "System notification area icons": "Pictogrammen systeemmeldingengebied" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Systeemgeluiden zijn niet beschikbaar. Installeer %1 voor geluidsondersteuning." - }, - "System theme toggle": { - "System theme toggle": "Systeemthema schakelen" - }, - "System toast notifications": { - "System toast notifications": "Systeemmeldingen" - }, - "System update custom command": { - "System update custom command": "Aangepaste opdracht systeemupdate" - }, - "Tab": { - "Tab": "Tab" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nav • ←→↑↓: Raster Nav • Enter/Spatie: Selecteren" - }, - "Terminal": { - "Terminal": "Terminal" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Aangepaste extra parameters terminal" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "Terminal-terugval mislukt. Installeer een ondersteunde terminalemulator of voer handmatig 'dms auth sync' uit." - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "Terminal fallback mislukt. Installeer een van de ondersteunde terminal-emulators of voer handmatig 'dms greeter sync' uit." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "Terminal-terugval geopend. Voltooi de verificatie-instellingen daar; deze zal automatisch sluiten wanneer voltooid." - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "Terminal fallback geopend. Voltooi de synchronisatie daar; de terminal sluit automatisch wanneer dit is voltooid." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "Te gebruiken terminal-multiplexer-backend" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "Terminal geopend. Voltooi de verificatie-instellingen daar; deze zal automatisch sluiten wanneer voltooid." - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "Terminal geopend. Voltooi de sync-authenticatie daar; de terminal sluit automatisch wanneer dit is voltooid." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminals - Altijd donker thema gebruiken" - }, - "Test Connection": { - "Test Connection": "Verbinding testen" - }, - "Test Page": { - "Test Page": "Testpagina" - }, - "Test page sent to printer": { - "Test page sent to printer": "Testpagina verzonden naar printer" - }, - "Testing...": { - "Testing...": "Testen..." - }, - "Text": { - "Text": "Tekst" - }, - "Text Color": { - "Text Color": "Tekstkleur" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "De tool 'dgop' is vereist voor systeembewaking.\nInstalleer dgop om deze functie te gebruiken." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "De DMS_SOCKET omgevingsvariabele is niet ingesteld of de socket is niet beschikbaar. Geautomatiseerd plug-inbeheer vereist de DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "De onderstaande instellingen wijzigen uw GTK- en Qt-instellingen. Als u uw huidige configuraties wilt behouden, maak er dan een back-up van (qt5ct.conf|qt6ct.conf en ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "De aangepaste opdracht die wordt gebruikt bij het koppelen aan sessies (ontvangt de sessienaam als eerste argument)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "De wachtrij van deze printer is leeg" - }, - "Theme & Colors": { - "Theme & Colors": "Thema & Kleuren" - }, - "Theme Color": { - "Theme Color": "Themakleur" - }, - "Theme Registry": { - "Theme Registry": "Themaregister" - }, - "Themes": { - "Themes": "Thema's" - }, - "Thickness": { - "Thickness": "Dikte" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Waarschuwing plug-ins van derden" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Plugins van derden zijn gemaakt door de gemeenschap en worden niet officieel ondersteund door DankMaterialShell.\n\nDeze plugins kunnen veiligheids- en privacyrisico's met zich meebrengen - installatie is op eigen risico." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Deze bind wordt overschreven door config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Dit kan enkele seconden duren" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Deze plugin heeft geen 'settings_write' rechten.\n\nVoeg \"permissions\": [\"settings_read\", \"settings_write\"] toe aan plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Deze widget voorkomt dat de GPU wordt uitgeschakeld, wat de batterijduur op laptops aanzienlijk kan beïnvloeden. Het wordt niet aanbevolen dit te gebruiken op laptops met hybride graphics." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Dit verwijdert alle niet-vastgemaakte items. %1 vastgemaakte items blijven bewaard." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Dit zal de volledige klembordgeschiedenis permanent verwijderen." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Dit verwijdert dit opgeslagen klemborditem permanent. Deze actie kan niet ongedaan worden gemaakt." - }, - "Thunderstorm": { - "Thunderstorm": "Onweer" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Onweer met hagel" - }, - "Tile": { - "Tile": "Tegelen" - }, - "Tile H": { - "Tile H": "Tegelen H" - }, - "Tile V": { - "Tile V": "Tegelen V" - }, - "Tiled": { - "Tiled": "Getegeld" - }, - "Tiled State": { - "Tiled State": "Tegelstatus" - }, - "Tiling": { - "Tiling": "Tegelen" - }, - "Time": { - "Time": "Tijd" - }, - "Time & Date Locale": { - "Time & Date Locale": "Locale voor tijd & datum" - }, - "Time & Weather": { - "Time & Weather": "Tijd & Weer" - }, - "Time Format": { - "Time Format": "Tijdnotatie" - }, - "Time format": { - "Time format": "Tijdnotatie" - }, - "Time remaining: %1": { - "Time remaining: %1": "Resterende tijd: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Tijd tot vol: %1" - }, - "Timed Out": { - "Timed Out": "Time-out" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Time-out voor meldingen met kritieke prioriteit" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Time-out voor meldingen met lage prioriteit" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Time-out voor meldingen met normale prioriteit" - }, - "Title": { - "Title": "Titel" - }, - "Title regex (optional)": { - "Title regex (optional)": "Titel-regex (optioneel)" - }, - "To Full": { - "To Full": "Tot vol" - }, - "To update, run the following command:": { - "To update, run the following command:": "Voer de volgende opdracht uit om bij te werken:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Om deze DMS-bind te gebruiken, verwijder of wijzig de keybind in uw config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Pop-upberichten" - }, - "Today": { - "Today": "Vandaag" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Zichtbaarheid van deze balkconfiguratie in-/uitschakelen" - }, - "Toggling...": { - "Toggling...": "Schakelen..." - }, - "Tomorrow": { - "Tomorrow": "Morgen" - }, - "Tonal Spot": { - "Tonal Spot": "Tonaal punt" - }, - "Toner Empty": { - "Toner Empty": "Toner leeg" - }, - "Toner Low": { - "Toner Low": "Toner laag" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "Te veel pogingen - toegang geblokkeerd" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "Te veel mislukte pogingen - account is mogelijk geblokkeerd" - }, - "Tools": { - "Tools": "Hulpmiddelen" - }, - "Top": { - "Top": "Boven" - }, - "Top (Default)": { - "Top (Default)": "Boven (Standaard)" - }, - "Top Bar Format": { - "Top Bar Format": "Notatie bovenbalk" - }, - "Top Center": { - "Top Center": "Middenboven" - }, - "Top Left": { - "Top Left": "Linksboven" - }, - "Top Processes": { - "Top Processes": "Topprocessen" - }, - "Top Right": { - "Top Right": "Rechtsboven" - }, - "Top Section": { - "Top Section": "Bovenste sectie" - }, - "Total": { - "Total": "Totaal" - }, - "Total Jobs": { - "Total Jobs": "Totaal aantal taken" - }, - "Touch your security key...": { - "Touch your security key...": "Raak uw beveiligingssleutel aan..." - }, - "Transform": { - "Transform": "Transformatie" - }, - "Transition Effect": { - "Transition Effect": "Overgangseffect" - }, - "Transparency": { - "Transparency": "Transparantie" - }, - "Trending GIFs": { - "Trending GIFs": "Populaire GIF's" - }, - "Trending Stickers": { - "Trending Stickers": "Populaire stickers" - }, - "Trigger": { - "Trigger": "Trigger" - }, - "Trigger Prefix": { - "Trigger Prefix": "Trigger-voorvoegsel" - }, - "Trigger: %1": { - "Trigger: %1": "Trigger: %1" - }, - "Trust": { - "Trust": "Vertrouwen" - }, - "Try a different search": { - "Try a different search": "Probeer een andere zoekopdracht" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Schakel alle beeldschermen onmiddellijk uit wanneer het vergrendelscherm activeert" - }, - "Turn off monitors after": { - "Turn off monitors after": "Beeldschermen uitschakelen na" - }, - "Type": { - "Type": "Type" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Typ minstens 2 tekens" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Typ dit voorvoegsel om sneltoetsen te zoeken" - }, - "Type to search files": { - "Type to search files": "Typ om bestanden te zoeken" - }, - "Typography": { - "Typography": "Typografie" - }, - "Typography & Motion": { - "Typography & Motion": "Typografie & Beweging" - }, - "Unavailable": { - "Unavailable": "Niet beschikbaar" - }, - "Unfocused Color": { - "Unfocused Color": "Ongefocusseerde kleur" - }, - "Ungrouped": { - "Ungrouped": "Niet gegroepeerd" - }, - "Uninstall": { - "Uninstall": "Verwijderen" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Greeter verwijderen" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Plug-in verwijderen" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Verwijderen voltooid. Greeter is verwijderd." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Verwijderen mislukt: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "De DMS Greeter verwijderen? Dit verwijdert de configuratie en herstelt je vorige display manager. Er wordt een terminal geopend voor sudo-authenticatie." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Verwijderd: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Verwijderen: %1" - }, - "Unknown": { - "Unknown": "Onbekend" - }, - "Unknown App": { - "Unknown App": "Onbekende app" - }, - "Unknown Artist": { - "Unknown Artist": "Onbekende artiest" - }, - "Unknown Config": { - "Unknown Config": "Onbekende configuratie" - }, - "Unknown Device": { - "Unknown Device": "Onbekend apparaat" - }, - "Unknown GPU": { - "Unknown GPU": "Onbekende GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "Onbekende monitor" - }, - "Unknown Network": { - "Unknown Network": "Onbekend netwerk" - }, - "Unknown Title": { - "Unknown Title": "Onbekende titel" - }, - "Unknown Track": { - "Unknown Track": "Onbekend nummer" - }, - "Unload on Close": { - "Unload on Close": "Ontladen bij sluiten" - }, - "Unmute": { - "Unmute": "Dempen opheffen" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Dempen van pop-ups opheffen voor %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Naamloze regel" - }, - "Unpair": { - "Unpair": "Ontkoppelen" - }, - "Unpair failed": { - "Unpair failed": "Ontkoppelen mislukt" - }, - "Unpin": { - "Unpin": "Losmaken" - }, - "Unpin from Dock": { - "Unpin from Dock": "Van dock losmaken" - }, - "Unsaved Changes": { - "Unsaved Changes": "Niet-opgeslagen wijzigingen" - }, - "Unsaved changes": { - "Unsaved changes": "Niet-opgeslagen wijzigingen" - }, - "Unsaved note...": { - "Unsaved note...": "Niet-opgeslagen notitie..." - }, - "Untitled": { - "Untitled": "Naamloos" - }, - "Untrust": { - "Untrust": "Niet vertrouwen" - }, - "Up to date": { - "Up to date": "Bijgewerkt" - }, - "Update": { - "Update": "Bijwerken" - }, - "Update All": { - "Update All": "Alles bijwerken" - }, - "Update Plugin": { - "Update Plugin": "Plug-in bijwerken" - }, - "Uptime": { - "Uptime": "Uptime" - }, - "Uptime:": { - "Uptime:": "Uptime:" - }, - "Urgent Color": { - "Urgent Color": "Urgente kleur" - }, - "Usage Tips": { - "Usage Tips": "Gebruikstips" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Gebruik 24-uursnotatie in plaats van 12-uurs AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Aangepaste opdracht gebruiken" - }, - "Use Grid Layout": { - "Use Grid Layout": "Rasterindeling gebruiken" - }, - "Use IP Location": { - "Use IP Location": "IP-locatie gebruiken" - }, - "Use Imperial Units": { - "Use Imperial Units": "Imperiale eenheden gebruiken" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Imperiale eenheden (°F, mph, inHg) gebruiken in plaats van Metrisch (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Monospace-lettertype gebruiken" - }, - "Use System Theme": { - "Use System Theme": "Systeemthema gebruiken" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Gebruik een aangepaste afbeelding voor het aanmeldscherm, of laat leeg om je bureaubladachtergrond te gebruiken." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Gebruik een vaste schaduwrichting voor deze balk" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Gebruik een beveiligingssleutel voor vergrendelscherm-authenticatie." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Gebruik een externe achtergrondbeheerder zoals swww, hyprpaper of swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Geanimeerde golf-voortgangsbalken gebruiken voor mediaweergave" - }, - "Use custom border size": { - "Use custom border size": "Aangepaste randgrootte gebruiken" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Aangepaste rand-/focusringbreedte gebruiken" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Gebruik aangepaste opdracht om uw systeem bij te werken" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Gebruik aangepaste tussenruimtes in plaats van balkafstand" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Gebruik aangepaste vensterradius in plaats van themaradius" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Aangepaste vensterronding gebruiken in plaats van themaradius" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Bureaubladachtergrond gebruiken" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Gebruik vingerafdrukauthenticatie voor het vergrendelscherm." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Licht thema gebruiken in plaats van donker thema" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Gebruik meters per seconde in plaats van km/u voor windsnelheid" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Kleinere meldingkaarten gebruiken" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Geluidsthema van systeeminstellingen gebruiken" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Dezelfde positie en grootte gebruiken op alle beeldschermen" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Gebruik trigger-voorvoegsel om te activeren" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Gebruikt wanneer accentkleur is ingesteld op Aangepast" - }, - "User": { - "User": "Gebruiker" - }, - "Username": { - "Username": "Gebruikersnaam" - }, - "Username...": { - "Username...": "Gebruikersnaam..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Gebruikt tijden voor zonsopgang/zonsondergang op basis van uw locatie." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Gebruikt tijden voor zonsopgang/zonsondergang om de nachtmodus automatisch aan te passen op basis van uw locatie." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Gebruikt gedeelde instellingen van Gammaregeling" - }, - "Utilities": { - "Utilities": "Hulpprogramma's" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN-verbindingen" - }, - "VPN Password": { - "VPN Password": "VPN-wachtwoord" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN-configuratie bijgewerkt" - }, - "VPN connections": { - "VPN connections": "VPN-verbindingen" - }, - "VPN deleted": { - "VPN deleted": "VPN verwijderd" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN geïmporteerd: %1" - }, - "VPN not available": { - "VPN not available": "VPN niet beschikbaar" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN-status en snel verbinden" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR alleen volledig scherm" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR op aanvraag" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Variabele verversingssnelheid" - }, - "Verification": { - "Verification": "Verificatie" - }, - "Version": { - "Version": "Versie" - }, - "Vertical Deck": { - "Vertical Deck": "Verticaal Deck" - }, - "Vertical Grid": { - "Vertical Grid": "Verticaal raster" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Verticaal scrollen" - }, - "Vertical Tiling": { - "Vertical Tiling": "Verticaal tegelen" - }, - "Vibrant": { - "Vibrant": "Levendig" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Levendig palet met speelse verzadiging." - }, - "Video Path": { - "Video Path": "Videopad" - }, - "Video Screensaver": { - "Video Screensaver": "Video-screensaver" - }, - "Videos": { - "Videos": "Video's" - }, - "View Mode": { - "View Mode": "Weergavemodus" - }, - "Visibility": { - "Visibility": "Zichtbaarheid" - }, - "Visual Effects": { - "Visual Effects": "Visuele effecten" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Visuele scheiding tussen widgets" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Visueel effect bij wisselen van achtergrond" - }, - "Volume": { - "Volume": "Volume" - }, - "Volume Changed": { - "Volume Changed": "Volume gewijzigd" - }, - "Volume Slider": { - "Volume Slider": "Volumeschuif" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volume, helderheid en andere systeem-OSD's" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Achtergrond" - }, - "Wallpaper Error": { - "Wallpaper Error": "Achtergrondfout" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Achtergrondbeeldscherm" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Vulmodus achtergrond" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Verwerken achtergrond mislukt" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Verwerken achtergrond mislukt - controleer achtergrondpad" - }, - "Wallpapers": { - "Wallpapers": "Achtergronden" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Toe te passen warme kleurtemperatuur" - }, - "Warning": { - "Warning": "Waarschuwing" - }, - "Warnings": { - "Warnings": "Waarschuwingen" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Golf-voortgangsbalken" - }, - "Weather": { - "Weather": "Weer" - }, - "Weather Widget": { - "Weather Widget": "Weer-widget" - }, - "Welcome": { - "Welcome": "Welkom" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Welkom bij DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "Breng bij het klikken op een dock-venster in een Hyprland-speciale-werkruimte die werkruimte terug voordat het venster wordt gefocust" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Indien ingeschakeld, worden apps alfabetisch gesorteerd. Indien uitgeschakeld, worden apps gesorteerd op gebruiksfrequentie." - }, - "When locked": { - "When locked": "Indien vergrendeld" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Wanneer de updater-widget wordt gebruikt, verberg deze dan als er geen updates zijn gevonden" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi-wachtwoord" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wifi- en Ethernet-verbinding" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wifi niet beschikbaar" - }, - "WiFi": { - "WiFi": "Wifi" - }, - "WiFi Device": { - "WiFi Device": "Wifi-apparaat" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Wifi-QR-code voor " - }, - "WiFi disabled": { - "WiFi disabled": "Wifi uitgeschakeld" - }, - "WiFi enabled": { - "WiFi enabled": "Wifi ingeschakeld" - }, - "WiFi is off": { - "WiFi is off": "Wifi is uit" - }, - "WiFi off": { - "WiFi off": "Wifi uit" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Breed (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Achtergrondkleur widget" - }, - "Widget Management": { - "Widget Management": "Widgetbeheer" - }, - "Widget Outline": { - "Widget Outline": "Widget-omtrek" - }, - "Widget Style": { - "Widget Style": "Widget-stijl" - }, - "Widget Styling": { - "Widget Styling": "Widget-stijl" - }, - "Widget Transparency": { - "Widget Transparency": "Widget-transparantie" - }, - "Widget added": { - "Widget added": "Widget toegevoegd" - }, - "Widget removed": { - "Widget removed": "Widget verwijderd" - }, - "Widgets": { - "Widgets": "Widgets" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgets, indeling, stijl" - }, - "Width": { - "Width": "Breedte" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Breedte van vensterrand (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Breedte van vensterrand (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Breedte van vensterrand en focusring" - }, - "Wind": { - "Wind": "Wind" - }, - "Wind Speed": { - "Wind Speed": "Windsnelheid" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Windsnelheid in m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Vensterhoekradius" - }, - "Window Gaps": { - "Window Gaps": "Venstertussenruimtes" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Venstertussenruimte (px)" - }, - "Window Height": { - "Window Height": "Vensterhoogte" - }, - "Window Opening": { - "Window Opening": "Venster openen" - }, - "Window Rounding": { - "Window Rounding": "Vensterronding" - }, - "Window Rules": { - "Window Rules": "Vensterregels" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Vensterregels-include ontbreekt" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Vensterregels niet geconfigureerd" - }, - "Wipe": { - "Wipe": "Vegen" - }, - "Workspace": { - "Workspace": "Werkblad" - }, - "Workspace Appearance": { - "Workspace Appearance": "Uiterlijk werkblad" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Indexnummers werkblad" - }, - "Workspace Names": { - "Workspace Names": "Werkbladnamen" - }, - "Workspace Padding": { - "Workspace Padding": "Werkblad-opvulling" - }, - "Workspace Settings": { - "Workspace Settings": "Werkbladinstellingen" - }, - "Workspace Switcher": { - "Workspace Switcher": "Werkbladwisselaar" - }, - "Workspace name": { - "Workspace name": "Werkbladnaam" - }, - "Workspaces": { - "Workspaces": "Werkbladen" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Werkbladen & Widgets" - }, - "Write:": { - "Write:": "Schrijven:" - }, - "X Axis": { - "X Axis": "X-as" - }, - "Y Axis": { - "Y Axis": "Y-as" - }, - "Yes": { - "Yes": "Ja" - }, - "Yesterday": { - "Yesterday": "Gisteren" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "U hebt niet-opgeslagen wijzigingen. Opslaan voordat u dit tabblad sluit?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "U hebt niet-opgeslagen wijzigingen. Opslaan voordat u doorgaat?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "U hebt niet-opgeslagen wijzigingen. Opslaan voordat u een nieuw bestand maakt?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "U hebt niet-opgeslagen wijzigingen. Opslaan voordat u een bestand opent?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "U moet het volgende instellen:\nQT_QPA_PLATFORMTHEME=gtk3 OF\nQT_QPA_PLATFORMTHEME=qt6ct\nals omgevingsvariabelen, en daarna de shell herstarten.\n\nqt6ct vereist dat qt6ct-kde is geïnstalleerd." - }, - "You're All Set!": { - "You're All Set!": "U bent helemaal klaar!" - }, - "Your system is up to date!": { - "Your system is up to date!": "Uw systeem is bijgewerkt!" - }, - "actions": { - "actions": "acties" - }, - "attached": { - "attached": "gekoppeld" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "door %1" - }, - "days": { - "days": "dagen" - }, - "detached": { - "detached": "ontkoppeld" - }, - "device": { - "device": "apparaat" - }, - "devices connected": { - "devices connected": "apparaten verbonden" - }, - "dgop not available": { - "dgop not available": "dgop niet beschikbaar" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "dms is een zeer aanpasbare, moderne desktop-shell met een op Material 3 geïnspireerd ontwerp.

        Het is gebouwd met Quickshell, een QT6-framework voor het bouwen van desktop-shells, en Go, een statisch getypeerde, gecompileerde programmeertaal." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "dms/cursor-configuratie bestaat maar is niet ingesloten. Cursorinstellingen worden niet toegepast." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/outputs-configuratie bestaat maar is niet opgenomen in uw compositor-configuratie. Beeldschermwijzigingen blijven niet behouden." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "bijv. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "bijv. focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "bijv. notify-send 'Hallo' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "bijv. scratch, /^tmp_.*/, build" - }, - "events": { - "events": "afspraken" - }, - "ext": { - "ext": "ext" - }, - "featured": { - "featured": "uitgelicht" - }, - "leave empty for default": { - "leave empty for default": "laat leeg voor standaard" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl niet beschikbaar - vergrendelintegratie vereist DMS-socketverbinding" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord-server" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen niet gevonden - installeer matugen-pakket voor dynamische thema's" - }, - "minutes": { - "minutes": "minuten" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "navigatie" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix-chat" - }, - "niri shortcuts config": { - "niri shortcuts config": "niri-sneltoetsenconfiguratie" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "nu" - }, - "official": { - "official": "officieel" - }, - "on Hyprland": { - "on Hyprland": "op Hyprland" - }, - "on MangoWC": { - "on MangoWC": "op MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "op Miracle WM" - }, - "on Niri": { - "on Niri": "op Niri" - }, - "on Scroll": { - "on Scroll": "op Scroll" - }, - "on Sway": { - "on Sway": "op Sway" - }, - "open": { - "open": "openen" - }, - "or run ": { - "or run ": "of voer uit: " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon niet beschikbaar" - }, - "procs": { - "procs": "procs" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri Subreddit" - }, - "seconds": { - "seconds": "seconden" - }, - "source": { - "source": "broncode" - }, - "this app": { - "this app": "deze app" - }, - "up": { - "up": "actief" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "update dms voor NM-integratie." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 door %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype niet beschikbaar - installeer wtype voor plakondersteuning" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Installeer alleen vanuit vertrouwde bronnen" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Maand (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Maand (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Maand (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Maand (Januari)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Plug-ins kunnen bugs of beveiligingsproblemen bevatten" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Controleer code voor installatie indien mogelijk" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Dag (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Dag (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Dagnaam (Ma)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Dagnaam (Maandag)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Jaar (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Jaar (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Nav • Spatie: Uitvouwen • Enter: Actie/Uitvouwen • E: Tekst" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: Navigeer • Enter/Ctrl+C: Kopieer • Del: Verwijder • F10: Help" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Navigeren • Enter: Plakken • Del: Verwijderen • F10: Help" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pl.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pl.json deleted file mode 100644 index dbb7375..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pl.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 znaków" - }, - "%1 connected": { - "%1 connected": "%1 połączono" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "" - }, - "%1 disconnected": { - "%1 disconnected": "" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "" - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "%1 powiadomień" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 wariantów" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 widżetów" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "%1m temu" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "" - }, - "(Unnamed)": { - "(Unnamed)": "(Bez nazwy)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 więcej" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "0 = kwadratowe rogi" - }, - "1 day": { - "1 day": "1 dzień" - }, - "1 device connected": { - "1 device connected": "1 połączone urządzenie" - }, - "1 event": { - "1 event": "1 wydarzenie" - }, - "1 hour": { - "1 hour": "" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "" - }, - "1 minute": { - "1 minute": "1 minuta" - }, - "1 notification": { - "1 notification": "1 powiadomienie" - }, - "1 second": { - "1 second": "1 sekunda" - }, - "10 minutes": { - "10 minutes": "10 minut" - }, - "10 seconds": { - "10 seconds": "10 sekund" - }, - "10-bit Color": { - "10-bit Color": "Kolor 10 bitowy" - }, - "12 hours": { - "12 hours": "" - }, - "14 days": { - "14 days": "14 dni" - }, - "15 minutes": { - "15 minutes": "" - }, - "15 seconds": { - "15 seconds": "15 sekund" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "" - }, - "2 minutes": { - "2 minutes": "2 minuty" - }, - "2 seconds": { - "2 seconds": "" - }, - "20 minutes": { - "20 minutes": "" - }, - "20 seconds": { - "20 seconds": "" - }, - "24-Hour Format": { - "24-Hour Format": "Format 24-godzinny" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "format 24-godzinny" - }, - "25 seconds": { - "25 seconds": "" - }, - "250 ms": { - "250 ms": "" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 dni" - }, - "3 hours": { - "3 hours": "" - }, - "3 minutes": { - "3 minutes": "" - }, - "3 seconds": { - "3 seconds": "3 sekundy" - }, - "30 days": { - "30 days": "30 dni" - }, - "30 minutes": { - "30 minutes": "" - }, - "30 seconds": { - "30 seconds": "30 sekund" - }, - "35 seconds": { - "35 seconds": "" - }, - "3rd party": { - "3rd party": "strona trzecia" - }, - "4 hours": { - "4 hours": "" - }, - "4 seconds": { - "4 seconds": "" - }, - "40 seconds": { - "40 seconds": "" - }, - "45 seconds": { - "45 seconds": "" - }, - "5 minutes": { - "5 minutes": "5 minut" - }, - "5 seconds": { - "5 seconds": "5 sekund" - }, - "50 seconds": { - "50 seconds": "" - }, - "500 ms": { - "500 ms": "" - }, - "55 seconds": { - "55 seconds": "" - }, - "6 hours": { - "6 hours": "" - }, - "7 days": { - "7 days": "7 dni" - }, - "750 ms": { - "750 ms": "" - }, - "8 hours": { - "8 hours": "" - }, - "8 seconds": { - "8 seconds": "8 sekund" - }, - "90 days": { - "90 days": "90 dni" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Plik o takiej nazwie już istnieje. Czy chcesz go nadpisać?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "" - }, - "AC Power": { - "AC Power": "" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Przerwane" - }, - "About": { - "About": "O programie" - }, - "Accent Color": { - "Accent Color": "Kolor akcentu" - }, - "Accept": { - "Accept": "Akceptuj" - }, - "Accept Jobs": { - "Accept Jobs": "Akceptuj zadania" - }, - "Accepting": { - "Accepting": "Akceptowanie" - }, - "Access clipboard history": { - "Access clipboard history": "Dostęp do historii schowka" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Dostęp do powiadomień i trybu „Nie przeszkadzać”" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Dostęp do elementów sterujących i ustawień systemu" - }, - "Action": { - "Action": "Działanie" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "Akcje" - }, - "Activate": { - "Activate": "Aktywuj" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "" - }, - "Active": { - "Active": "Aktywny" - }, - "Active Color": { - "Active Color": "" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Aktywny monitor blokady ekranu" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "" - }, - "Active: %1": { - "Active: %1": "Aktywne: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Aktywne: %1 + %2" - }, - "Active: None": { - "Active: None": "Aktywny: Brak" - }, - "Adapters": { - "Adapters": "Adaptery" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Dodaj" - }, - "Add Bar": { - "Add Bar": "Dodaj pasek" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Dodaj Widżet Pulpitu" - }, - "Add Printer": { - "Add Printer": "Dodaj drukarkę" - }, - "Add Title": { - "Add Title": "" - }, - "Add Widget": { - "Add Widget": "Dodaj widżet" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Dodaj widżet do sekcji %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Dodaj obramowanie wokół doku" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Dodaj niestandardowy prefiks do wszystkich poleceń aplikacji. Można tego użyć do poleceń takich jak 'uwsm-app', 'systemd-run' lub innych wrapperów." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Dodaj i skonfiguruj widżety pulpitu" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Dostosuj liczbę kolumn w widoku siatki." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Zaawansowane" - }, - "Afternoon": { - "Afternoon": "Popołudnie" - }, - "All": { - "All": "Wszystkie" - }, - "All Monitors": { - "All Monitors": "Wszystkie monitory" - }, - "All checks passed": { - "All checks passed": "" - }, - "All day": { - "All day": "Cały dzień" - }, - "All displays": { - "All displays": "Wszystkie ekrany" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Wstecz • F1/I: Informacje o pliku • F10: Pomoc • Esc: Zamknij" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "" - }, - "Always Show Percentage": { - "Always Show Percentage": "Zawsze pokazuj procenty" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Zawsze ukrywaj dok i pokaż, gdy kursor jest nakierowany wokół przestrzeni doku" - }, - "Always on icons": { - "Always on icons": "Ikony zawsze włączone" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Zawsze pokazuj co najmniej 3 obszary robocze, nawet jeśli jest ich mniej." - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Zawsze pokazuj dock kiedy pogląd niri jest otwarty" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Zawsze pokazuj gdy podłączony jest tylko jeden wyświetlacz" - }, - "Amount": { - "Amount": "Ilość" - }, - "Analog": { - "Analog": "Analogowy" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analogowy, cyfrowy lub piętrowy zegar" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "" - }, - "Animation Duration": { - "Animation Duration": "" - }, - "Animation Speed": { - "Animation Speed": "Szybkość animacji" - }, - "Anonymous Identity": { - "Anonymous Identity": "Tożsamość anonimowa" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Tożsamość anonimowa (opcjonalnie)" - }, - "App Customizations": { - "App Customizations": "" - }, - "App ID Substitutions": { - "App ID Substitutions": "" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "" - }, - "App Launcher": { - "App Launcher": "Program Uruchamiający" - }, - "App Names": { - "App Names": "Nazwy aplikacji" - }, - "App Theming": { - "App Theming": "Motywy aplikacji" - }, - "Appearance": { - "Appearance": "" - }, - "Application Dock": { - "Application Dock": "Dok Aplikacji" - }, - "Applications": { - "Applications": "Aplikacje" - }, - "Apply Changes": { - "Apply Changes": "Zastosuj zmiany" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Zastosuj kolory GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Zastosuj kolory Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Zastosuj ciepłą temperaturę barwową, aby zmniejszyć zmęczenie oczu. Użyj poniższych ustawień automatyzacji, aby kontrolować, kiedy się aktywuje." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "" - }, - "Apps Dock": { - "Apps Dock": "" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "" - }, - "Apps Icon": { - "Apps Icon": "Ikona aplikacji" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Aplikacje są uporządkowane według częstotliwości użytkowania, następnie według daty ostatniego użycia, a następnie alfabetycznie." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "" - }, - "Architecture": { - "Architecture": "Architektura" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Zarządzaj wyświetlaczami, konfiguruj rozdzielczość, częstotliwość odświeżania i VRR" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "Dźwięk" - }, - "Audio Codec": { - "Audio Codec": "Kodek audio" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Wybór kodeka audio" - }, - "Audio Devices": { - "Audio Devices": "Urządzenia audio" - }, - "Audio Input": { - "Audio Input": "Wejście Audio" - }, - "Audio Output": { - "Audio Output": "Wyjście Audio" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Urządzenia wyjściowe audio (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Przełącznik Wyjścia Audio" - }, - "Audio Visualizer": { - "Audio Visualizer": "Wizualizator Audio" - }, - "Audio system restarted": { - "Audio system restarted": "" - }, - "Audio volume control": { - "Audio volume control": "Kontrola głośności dźwięku" - }, - "Auth": { - "Auth": "Uwierzytelnianie" - }, - "Auth Type": { - "Auth Type": "Typ uwierzytelniania" - }, - "Authenticate": { - "Authenticate": "Uwierzytelnij" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "Uwierzytelnianie" - }, - "Authentication Required": { - "Authentication Required": "Wymagane uwierzytelnienie" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Uwierzytelnianie nie powiodło się, spróbuj ponownie" - }, - "Authorize": { - "Authorize": "Autoryzuj" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autoryzuj parowanie z " - }, - "Authorize service for ": { - "Authorize service for ": "Autoryzuj usługę dla " - }, - "Auto": { - "Auto": "Automatycznie" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Auto (Szeroki)" - }, - "Auto Location": { - "Auto Location": "Automatyczna lokalizacja" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Automatyczne odstępy wyskakujących okienek" - }, - "Auto-Clear After": { - "Auto-Clear After": "Automatycznie czyść po" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Automatycznie zamknij podgląd Niri otwierając aplikacje." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Automatyczne usuwanie powiadomień starszych niż" - }, - "Auto-hide": { - "Auto-hide": "Automatyczne ukrywanie" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Automatyczne ukrywanie doku" - }, - "Auto-saving...": { - "Auto-saving...": "Automatyczny zapis..." - }, - "Autoconnect": { - "Autoconnect": "Połącz automatycznie" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Automatyczne łączenie wyłączone" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Automatyczne łączenie włączone" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "" - }, - "Automatic Control": { - "Automatic Control": "Automatyczna kontrola" - }, - "Automatic Cycling": { - "Automatic Cycling": "Automatyczne cykl" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Automatycznie zmieniaj tapety z tego samego katalogu" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Automatycznie usuń wpisy starsze niż" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Automatycznie wykrywaj lokalizację na podstawie adresu IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Automatycznie określ swoją lokalizację na podstawie adresu IP" - }, - "Automatically lock after": { - "Automatically lock after": "Automatycznie zablokuj po" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Automatycznie blokuj ekran, gdy system przygotowuje się do wstrzymania" - }, - "Automation": { - "Automation": "" - }, - "Available": { - "Available": "Dostępny" - }, - "Available Layouts": { - "Available Layouts": "Dostępne układy" - }, - "Available Networks": { - "Available Networks": "Dostępne sieci" - }, - "Available Plugins": { - "Available Plugins": "Dostępne Wtyczki" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Dostępne Ekrany (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Wstecz" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Przeźroczystość tła" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Obraz tła" - }, - "Backlight device": { - "Backlight device": "Urządzenie podświetlenia" - }, - "Balance power and performance": { - "Balance power and performance": "" - }, - "Balanced": { - "Balanced": "" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Zrównoważona paleta ze skupionymi akcentami (domyślnie)." - }, - "Bar Configurations": { - "Bar Configurations": "Konfiguracje pasków" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "Przezroczystość paska" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "" - }, - "Battery": { - "Battery": "Bateria" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Limit Ładowania Baterii" - }, - "Battery and power management": { - "Battery and power management": "Bateria i zarządzanie zasilaniem" - }, - "Battery level and power management": { - "Battery level and power management": "Poziom baterii i zarządzanie zasilaniem" - }, - "Behavior": { - "Behavior": "Zachowanie" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Powiąż ekran blokady z sygnałami dbus z loginctl. Wyłącz, jeśli używasz zewnętrznego ekranu blokady" - }, - "Binds Include Missing": { - "Binds Include Missing": "Powiązania obejmują brakujące" - }, - "Binds include added": { - "Binds include added": "Dodano powiązania" - }, - "Bit Depth": { - "Bit Depth": "Głębokość Bitowa" - }, - "Block Out": { - "Block Out": "" - }, - "Block Out From": { - "Block Out From": "" - }, - "Block notifications": { - "Block notifications": "Blokuj powiadomienia" - }, - "Blocked": { - "Blocked": "Zablokowane" - }, - "Blue light filter": { - "Blue light filter": "Filtr światła niebieskiego" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Ustawienia Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth niedostępne" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Rozmyj Warstwę Tapety" - }, - "Blur on Overview": { - "Blur on Overview": "Rozmycie w podglądzie" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Rozmyj tapetę, gdy podgląd niri jest otwarty" - }, - "Body": { - "Body": "" - }, - "Border": { - "Border": "Ramka" - }, - "Border Color": { - "Border Color": "Kolor obramowania" - }, - "Border Opacity": { - "Border Opacity": "Przezroczystość obramowania" - }, - "Border Size": { - "Border Size": "Rozmiar obramowania" - }, - "Border Thickness": { - "Border Thickness": "Grubość obramowania" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "" - }, - "Bottom": { - "Bottom": "Dół" - }, - "Bottom Center": { - "Bottom Center": "" - }, - "Bottom Left": { - "Bottom Left": "Dolny Lewy" - }, - "Bottom Right": { - "Bottom Right": "Dolny Prawy" - }, - "Bottom Section": { - "Bottom Section": "Sekcja dolna" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Dolna stacja dokująca dla przypiętych i działających aplikacji" - }, - "Brightness": { - "Brightness": "Jasność" - }, - "Brightness Slider": { - "Brightness Slider": "Suwak Jasności" - }, - "Brightness Value": { - "Brightness Value": "Wartość Jasności" - }, - "Brightness control not available": { - "Brightness control not available": "Kontrola jasności niedostępna" - }, - "Browse": { - "Browse": "Przeglądaj" - }, - "Browse Files": { - "Browse Files": "Przeglądaj pliki" - }, - "Browse Plugins": { - "Browse Plugins": "Przeglądaj Wtyczki" - }, - "Browse Themes": { - "Browse Themes": "Przeglądaj Motywy" - }, - "Browse or search plugins": { - "Browse or search plugins": "" - }, - "Button Color": { - "Button Color": "" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "Wykres CPU" - }, - "CPU Temperature": { - "CPU Temperature": "Temperatura CPU" - }, - "CPU Usage": { - "CPU Usage": "Użycie CPU" - }, - "CPU temperature display": { - "CPU temperature display": "Wskaźnik temperatury procesora" - }, - "CPU usage indicator": { - "CPU usage indicator": "Wskaźnik użycia procesora" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Monitorowanie CPU, pamięci, sieci i dysku" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS: Ostrzeżenie o niezabezpieczonym filtrze" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS: Ostrzeżenie o brakującym filtrze" - }, - "CUPS Print Server": { - "CUPS Print Server": "Serwer wydruku CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS niedostępne" - }, - "Camera": { - "Camera": "Kamera" - }, - "Cancel": { - "Cancel": "Anuluj" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "" - }, - "Canceled": { - "Canceled": "Anulowane" - }, - "Cannot pair": { - "Cannot pair": "Parowanie nie powiodło się" - }, - "Capabilities": { - "Capabilities": "Możliwości" - }, - "Capacity": { - "Capacity": "Pojemność" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Wskaźnik caps locka" - }, - "Caps Lock is on": { - "Caps Lock is on": "" - }, - "Center Section": { - "Center Section": "Sekcja środkowa" - }, - "Center Single Column": { - "Center Single Column": "Pojedyncza kolumna na środku" - }, - "Center Tiling": { - "Center Tiling": "Płytki środkowe" - }, - "Certificate Password": { - "Certificate Password": "Hasło certyfikatu" - }, - "Change Song": { - "Change Song": "" - }, - "Change Volume": { - "Change Volume": "" - }, - "Change bar appearance": { - "Change bar appearance": "Zmień wygląd paska" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "Kanał" - }, - "Charging": { - "Charging": "Ładowanie" - }, - "Check for system updates": { - "Check for system updates": "Sprawdź aktualizacje systemu" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "Wybierz kolor" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Wybierz kolor logo launchera" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "" - }, - "Choose a color": { - "Choose a color": "Wybierz kolor" - }, - "Choose colors from palette": { - "Choose colors from palette": "Wybierz kolory z palety" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Wybierz, jak wyświetlane jest rozszerzenie pogody" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "Wybierz ikonę" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Wybierz kolor tła dla widżetów" - }, - "Choose the border accent color": { - "Choose the border accent color": "Wybierz kolor akcentu obramowania" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Wybierz logo wyświetlane na przycisku launchera w DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Wybierz, gdzie na ekranie mają pojawiać się powiadomienia" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Wybierz miejsce wyświetlania informacji na ekranie" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Wybierz wyświetlacze na których pokaże się ten widżet" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Wybierz monitor, na którym będzie wyświetlany interfejs ekranu blokady. Inne monitory będą wyświetlać jednolity kolor, aby chronić ekran OLED przed wypaleniem." - }, - "Chroma Style": { - "Chroma Style": "" - }, - "Cipher": { - "Cipher": "Szyfr" - }, - "Circle": { - "Circle": "" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "" - }, - "Clear": { - "Clear": "Wyczyść" - }, - "Clear All": { - "Clear All": "Wyczyść wszystkie" - }, - "Clear All Jobs": { - "Clear All Jobs": "Wyczyść wszystkie zadania" - }, - "Clear History?": { - "Clear History?": "Czy wyczyścić historię?" - }, - "Clear Sky": { - "Clear Sky": "" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Wyczyść historię gdy serwer startuje" - }, - "Clear at Startup": { - "Clear at Startup": "Wyczyść przy starcie" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Kliknij 'Konfiguruj' by stworzyć konfigurację wyjść i dodać konfiguracji kompozytora." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Kliknij Importuj, aby dodać plik .ovpn lub .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "" - }, - "Click to capture": { - "Click to capture": "Kliknij, aby uchwycić" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Kliknij by wybrać plik JSON niestandardowego motywu" - }, - "Clip": { - "Clip": "" - }, - "Clip to Geometry": { - "Clip to Geometry": "" - }, - "Clipboard": { - "Clipboard": "Schowek" - }, - "Clipboard History": { - "Clipboard History": "Historia schowka" - }, - "Clipboard Manager": { - "Clipboard Manager": "Menedżer schowka" - }, - "Clipboard sent": { - "Clipboard sent": "Wysłano zawartość schowka" - }, - "Clipboard service not available": { - "Clipboard service not available": "Usługa schowka nie jest dostępna" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Schowek działa, ale nic nie zostało zapisane na dysku" - }, - "Clock": { - "Clock": "Zegar" - }, - "Clock Style": { - "Clock Style": "Styl Zegara" - }, - "Close": { - "Close": "Zamknij" - }, - "Close All Windows": { - "Close All Windows": "" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Zamknij podgląd przy uruchomieniu" - }, - "Close Window": { - "Close Window": "" - }, - "Color": { - "Color": "Kolor" - }, - "Color Gamut": { - "Color Gamut": "Gameta kolorów" - }, - "Color Management": { - "Color Management": "Zarządzanie kolorami" - }, - "Color Mode": { - "Color Mode": "Tryb kolorów" - }, - "Color Override": { - "Color Override": "Nadpisanie koloru" - }, - "Color Picker": { - "Color Picker": "Próbnik kolorów" - }, - "Color Temperature": { - "Color Temperature": "Temperatura Barw" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Kolor wyświetlany na monitorach bez ekranu blokady" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "" - }, - "Color temperature for day time": { - "Color temperature for day time": "Temperatura barwowa w ciągu dnia" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Temperatura barwowa dla trybu nocnego" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Motyw z rejestru DMS" - }, - "Colorful": { - "Colorful": "" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Kolorowa mieszanka jasnych kontrastujących akcentów." - }, - "Colorize Active": { - "Colorize Active": "" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Kolory z tapety" - }, - "Column": { - "Column": "Kolumna" - }, - "Column Display": { - "Column Display": "" - }, - "Column Width": { - "Column Width": "" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Rozkaz" - }, - "Commands": { - "Commands": "" - }, - "Communication": { - "Communication": "Komunikacja" - }, - "Community themes": { - "Community themes": "Motywy społeczności" - }, - "Compact": { - "Compact": "Kompaktowe powiadomienia" - }, - "Compact Mode": { - "Compact Mode": "Tryb kompaktowy" - }, - "Completed": { - "Completed": "Ukończone" - }, - "Compositor": { - "Compositor": "Kompozytor" - }, - "Compositor Settings": { - "Compositor Settings": "Ustawienia Kompozytora" - }, - "Compositor not supported": { - "Compositor not supported": "" - }, - "Config Format": { - "Config Format": "Format konfiguracji" - }, - "Config action: %1": { - "Config action: %1": "Akcja konfiguracji: %1" - }, - "Config validation failed": { - "Config validation failed": "Walidacja konfiguracji nie powiodła się" - }, - "Configuration": { - "Configuration": "Konfiguracja" - }, - "Configuration activated": { - "Configuration activated": "Konfiguracja aktywowana" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Konfiguracja zostanie zachowana gdy wyświetlacz połączy się ponownie" - }, - "Configure": { - "Configure": "" - }, - "Configure Keybinds": { - "Configure Keybinds": "Konfiguruj przypisania klawiszy" - }, - "Configure a new printer": { - "Configure a new printer": "Skonfiguruj nową drukarkę" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Skonfiguruj ikony dla nazwanych obszarów roboczych. Ikony mają pierwszeństwo przed numerami, gdy obie opcje są włączone." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Skonfiguruj, które wyświetlacze pokazują komponenty powłoki" - }, - "Confirm": { - "Confirm": "Potwierdź" - }, - "Confirm Delete": { - "Confirm Delete": "Potwierdź Usunięcie" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Potwierdź zmiany wyświetlania" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Potwierdź klucz dostępu dla " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Konflikty z: %1" - }, - "Connect": { - "Connect": "Połącz" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Połącz z ukrytą siecią" - }, - "Connect to VPN": { - "Connect to VPN": "Połącz z VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Połącz z siecią Wi-Fi" - }, - "Connected": { - "Connected": "Połączono" - }, - "Connected Device": { - "Connected Device": "" - }, - "Connected Displays": { - "Connected Displays": "Podłączone ekrany" - }, - "Connecting to Device": { - "Connecting to Device": "Łączenie z urządzeniem" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Łączenie..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "" - }, - "Content": { - "Content": "" - }, - "Content copied": { - "Content copied": "Zawartość została skopiowana" - }, - "Contrast": { - "Contrast": "Kontrast" - }, - "Control Center": { - "Control Center": "Centrum sterowania" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "" - }, - "Control currently playing media": { - "Control currently playing media": "Steruj aktualnie odtwarzanymi multimediami" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Kontroluj, jakie informacje z powiadomienia są pokazywane na ekranie blokady" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Steruj obszarami roboczymi i kolumnami poprzez przewijanie na pasku" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Steruje kryciem wszystkich okien pop-up, modów i ich warstw zawartości" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "Czas Odnowienia" - }, - "Copied GIF": { - "Copied GIF": "Skopiowano GIF" - }, - "Copied MP4": { - "Copied MP4": "Skopiowano MP4" - }, - "Copied WebP": { - "Copied WebP": "Skopiowano WebP" - }, - "Copied to clipboard": { - "Copied to clipboard": "Skopiowano do schowka" - }, - "Copied!": { - "Copied!": "Skopiowane!" - }, - "Copy": { - "Copy": "Kopiuj" - }, - "Copy Content": { - "Copy Content": "" - }, - "Copy Full Command": { - "Copy Full Command": "Skopiuj pełną komendę" - }, - "Copy HTML": { - "Copy HTML": "" - }, - "Copy Name": { - "Copy Name": "Skopiuj nazwę" - }, - "Copy PID": { - "Copy PID": "Kopiuj PID" - }, - "Copy Text": { - "Copy Text": "" - }, - "Copy path": { - "Copy path": "Skopiuj ścieżkę" - }, - "Corner Radius": { - "Corner Radius": "Promień narożnika" - }, - "Corner Radius Override": { - "Corner Radius Override": "Zastąpienie promienia narożnika" - }, - "Corners & Background": { - "Corners & Background": "Rogi i tło" - }, - "Count Only": { - "Count Only": "Tylko liczba" - }, - "Cover Open": { - "Cover Open": "Pokrywa otwarta" - }, - "Create": { - "Create": "" - }, - "Create Dir": { - "Create Dir": "Utwórz katalog" - }, - "Create Printer": { - "Create Printer": "Utwórz drukarkę" - }, - "Create Window Rule": { - "Create Window Rule": "" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "" - }, - "Creating...": { - "Creating...": "Tworzenie..." - }, - "Critical Priority": { - "Critical Priority": "Priorytet krytyczny" - }, - "Current": { - "Current": "" - }, - "Current Items": { - "Current Items": "Bieżące elementy" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "" - }, - "Current Period": { - "Current Period": "Aktualny Okres" - }, - "Current Status": { - "Current Status": "Aktualny Status" - }, - "Current Temp": { - "Current Temp": "Aktualna Temperatura" - }, - "Current Theme: %1": { - "Current Theme: %1": "Aktualny Motyw: %1" - }, - "Current Weather": { - "Current Weather": "Bieżąca pogoda" - }, - "Current Workspace": { - "Current Workspace": "" - }, - "Current time and date display": { - "Current time and date display": "Wyświetlanie aktualnej godziny i daty" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Aktualne warunki pogodowe i temperatura" - }, - "Current: %1": { - "Current: %1": "Aktualnie: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "" - }, - "Cursor Size": { - "Cursor Size": "Rozmiar kursora" - }, - "Cursor Theme": { - "Cursor Theme": "Motyw kursora" - }, - "Custom": { - "Custom": "Niestandardowy" - }, - "Custom Color": { - "Custom Color": "" - }, - "Custom Duration": { - "Custom Duration": "Czas trwania niestandardowy" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Niestandardowe polecenie hibernacji" - }, - "Custom Location": { - "Custom Location": "Niestandardowa lokalizacja" - }, - "Custom Lock Command": { - "Custom Lock Command": "Niestandardowe polecenie blokady" - }, - "Custom Logout Command": { - "Custom Logout Command": "Niestandardowe polecenie wylogowania" - }, - "Custom Name": { - "Custom Name": "" - }, - "Custom Power Actions": { - "Custom Power Actions": "Niestandardowe akcje zasilania" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Niestandardowe polecenie wyłączenia zasilania" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Niestandardowe polecenie ponownego uruchomienia" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Niestandardowe polecenie wstrzymania" - }, - "Custom Transparency": { - "Custom Transparency": "Niestandardowa przezroczystość" - }, - "Custom power profile": { - "Custom power profile": "" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Niestandardowy motyw załadowany z pliku JSON" - }, - "Custom...": { - "Custom...": "Niestandardowy..." - }, - "Custom: ": { - "Custom: ": "Niestandardowy: " - }, - "Customizable empty space": { - "Customizable empty space": "Dostosowywalna pusta przestrzeń" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Dostosuj, które akcje będą wyświetlane w menu zasilania" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "Monitor DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "TRYB DEMO - Kliknij gdziekolwiek aby wyjść" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Menedżer wtyczek DMS niedostępny" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Skróty DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS nieaktualny" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Usługa DMS nie jest połączona. Ustawienia schowka nie są dostępne." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Akcje powłoki DMS (program uruchamiający, schowek itp.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET niedostępny" - }, - "DWL service not available": { - "DWL service not available": "Usługa DWL niedostępna" - }, - "Daily": { - "Daily": "" - }, - "Daily at:": { - "Daily at:": "Codziennie o:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell jest gotowy do użycia" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell i ikony systemowe (wymaga ponownego uruchomienia)" - }, - "Dark Mode": { - "Dark Mode": "Ciemny Motyw" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Przyciemnij tło trybu" - }, - "Date Format": { - "Date Format": "Format daty" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Świt (Zmierzch astronomiczny)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Świt (Zmierzch Cywilny)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Świt (Żeglarski zmierzch)" - }, - "Day Date": { - "Day Date": "" - }, - "Day Month Date": { - "Day Month Date": "" - }, - "Day Temperature": { - "Day Temperature": "Temperatura w dzień" - }, - "Daytime": { - "Daytime": "Dzień" - }, - "Deck": { - "Deck": "Pokład" - }, - "Default": { - "Default": "Domyślne" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "Domyślna Szerokość (%)" - }, - "Default selected action": { - "Default selected action": "Domyślnie wybrana akcja" - }, - "Defaults": { - "Defaults": "Domyślne" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Wyczyść • Shift+Del: Wyczyść wszystko • 1-9: Akcje • F10: Pomoc • Esc: Zamknij" - }, - "Delete": { - "Delete": "Usuń" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "" - }, - "Delete Class": { - "Delete Class": "Usuń klasę" - }, - "Delete Printer": { - "Delete Printer": "Usuń drukarkę" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Usunąć zapisany element?" - }, - "Delete VPN": { - "Delete VPN": "Usuń VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Uzyskuje kolory, które ściśle pasują do obrazu bazowego." - }, - "Description": { - "Description": "Opis" - }, - "Desktop": { - "Desktop": "" - }, - "Desktop Clock": { - "Desktop Clock": "Zegar na pulpicie" - }, - "Desktop Entry": { - "Desktop Entry": "" - }, - "Desktop Widget": { - "Desktop Widget": "Widżet na Pulpicie" - }, - "Desktop Widgets": { - "Desktop Widgets": "Widżety Pultitu" - }, - "Desktop background images": { - "Desktop background images": "Obrazy tła pulpitu" - }, - "Detailed": { - "Detailed": "" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "Programowanie" - }, - "Device": { - "Device": "Urządzenie" - }, - "Device connections": { - "Device connections": "Połączone urządzenia" - }, - "Device names updated": { - "Device names updated": "" - }, - "Device paired": { - "Device paired": "Urządzenie sparowane" - }, - "Device unpaired": { - "Device unpaired": "Urządzenie niesparowane" - }, - "Digital": { - "Digital": "Cyfrowy" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Wyłącz automatyczne łączenie" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Wyłącz wbudowane tapety" - }, - "Disable History Persistence": { - "Disable History Persistence": "Wyłącz zapisywanie historii" - }, - "Disable Output": { - "Disable Output": "Wyłącz wyjście" - }, - "Disabled": { - "Disabled": "Wyłączony" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Wyłączanie WiFi..." - }, - "Disc": { - "Disc": "" - }, - "Discard": { - "Discard": "Odrzuć" - }, - "Discharging": { - "Discharging": "" - }, - "Disconnect": { - "Disconnect": "Rozłącz" - }, - "Disconnected": { - "Disconnected": "Rozłączono" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Rozłączono z Wi-Fi" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "Dysk" - }, - "Disk I/O": { - "Disk I/O": "Dysk I/O" - }, - "Disk Usage": { - "Disk Usage": "Użycie dysku" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "Dyski" - }, - "Dismiss": { - "Dismiss": "Odrzuć" - }, - "Display": { - "Display": "" - }, - "Display Assignment": { - "Display Assignment": "Przypisanie wyświetlacza" - }, - "Display Control": { - "Display Control": "" - }, - "Display Name Format": { - "Display Name Format": "Format nazwy wyświetlanej" - }, - "Display Profiles": { - "Display Profiles": "" - }, - "Display Settings": { - "Display Settings": "Ustawienia Wyświetlacza" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Wyświetl dok z przypiętymi i uruchomionymi aplikacjami" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Wyświetlaj wszystkie priorytety nad aplikacjami pełnoekranowymi" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Wyświetlanie i przełączanie układów DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Wyświetlaj ikony aplikacji we wskaźnikach obszaru roboczego" - }, - "Display brightness control": { - "Display brightness control": "Kontrola jasności monitora" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Konfiguracja wyświetlacza nie jest dostępna. Protokół WLR nie jest wspierany." - }, - "Display currently focused application title": { - "Display currently focused application title": "Wyświetlaj tytuł aktywnej aplikacji" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Wyświetl godzinną prognozę pogody" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Wyświetlaj tylko obszary robocze zawierające okna" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Wyświetl elementy menu zasilania w siatce zamiast listy" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Wyświetlanie sekund na zegarze" - }, - "Display the power system menu": { - "Display the power system menu": "Wyświetl menu zasilania" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Wyświetlaj wartości procentowe głośności i jasności w wyskakujących okienkach OSD" - }, - "Displays": { - "Displays": "Ekrany" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Wyświetla aktywny układ klawiatury i umożliwia przełączanie" - }, - "Distribution": { - "Distribution": "Dystrybucja" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Zróżnicowana paleta obejmująca pełne spektrum." - }, - "Do Not Disturb": { - "Do Not Disturb": "Nie przeszkadać" - }, - "Dock": { - "Dock": "Dok" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dok i launcher" - }, - "Dock Transparency": { - "Dock Transparency": "Przezroczystość Doka" - }, - "Dock Visibility": { - "Dock Visibility": "Widoczność doku" - }, - "Docs": { - "Docs": "Dokumenty" - }, - "Documents": { - "Documents": "" - }, - "Domain (optional)": { - "Domain (optional)": "Domena (opcjonalnie)" - }, - "Don't Change": { - "Don't Change": "Nie zmieniaj" - }, - "Don't Save": { - "Don't Save": "Nie zapisuj" - }, - "Door Open": { - "Door Open": "Drzwi otwarte" - }, - "Downloads": { - "Downloads": "" - }, - "Drag to Reorder": { - "Drag to Reorder": "" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Przeciągnij widżety, aby zmienić kolejność w sekcjach. Użyj ikony oka, aby ukryć/pokazać widżety (zachowując odstępy), lub X, aby je całkowicie usunąć." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "" - }, - "Driver": { - "Driver": "Sterownik" - }, - "Drizzle": { - "Drizzle": "" - }, - "Duplicate": { - "Duplicate": "Duplikuj" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Powiel tapetę z rozmyciem" - }, - "Duration": { - "Duration": "" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Zmierzch (Zmierzch astronomiczny)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Zmierzch (Cywilny Zmierzch)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Zmierzch (Żeglarski zmierzch)" - }, - "Dynamic": { - "Dynamic": "Dynamiczny" - }, - "Dynamic Properties": { - "Dynamic Properties": "" - }, - "Dynamic Theming": { - "Dynamic Theming": "Dynamiczny motyw" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Dynamiczne kolory z tapety" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Dynamiczne kolory, presety" - }, - "Edge Spacing": { - "Edge Spacing": "Odstępy między krawędziami" - }, - "Edit App": { - "Edit App": "Edytuj aplikację" - }, - "Edit Window Rule": { - "Edit Window Rule": "" - }, - "Education": { - "Education": "Edukacja" - }, - "Empty": { - "Empty": "Pusty" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Włącz 10 bitową głębię kolorów dla szerszej gamety kolorów i wsparcia HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Włącz automatyczne łączenie" - }, - "Enable Bar": { - "Enable Bar": "Włącz pasek" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Włącz opcję Nie przeszkadzać" - }, - "Enable History": { - "Enable History": "Włącz historię" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Włącz nakładkę przeglądu" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "" - }, - "Enable System Sounds": { - "Enable System Sounds": "Włącz dźwięki systemowe" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "Pokaż pogodę" - }, - "Enable WiFi": { - "Enable WiFi": "Włącz Wi-Fi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Włącz warstwę rozmycia dla kompozytora (przestrzeń nazw: dms:blurwallpaper). Wymaga ręcznej konfiguracji niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Włącz uwierzytelnianie odciskiem palca" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Włącz integrację blokady loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "Włączony" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Włączanie WiFi..." - }, - "End": { - "End": "Koniec" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "" - }, - "Enlargement %": { - "Enlargement %": "" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Wprowadź 6-cyfrowy klucz dostępu" - }, - "Enter PIN": { - "Enter PIN": "Wprowadź PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Wprowadź PIN dla " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Wprowadź URL lub tekst, aby go udostępnić" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Wprowadź nową nazwę dla tej przestrzeni roboczej" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "Wprowadź poświadczenia dla " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Wprowadź niestandardowy format ekranu blokady (np. dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Wprowadź niestandardowy format górnego paska (np. ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "" - }, - "Enter filename...": { - "Enter filename...": "Podaj nazwę pliku..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Dodaj prefiks uruchamiania (np. 'uwsp-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Wpisz nazwę sieci i hasło" - }, - "Enter passkey for ": { - "Enter passkey for ": "Wprowadź klucz dostępu dla " - }, - "Enter password for ": { - "Enter password for ": "Wprowadź hasło dla " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Wprowadź ten klucz dostępu " - }, - "Enter to Paste": { - "Enter to Paste": "" - }, - "Enterprise": { - "Enterprise": "Korporacyjny" - }, - "Entry pinned": { - "Entry pinned": "Przypięto wpis" - }, - "Entry unpinned": { - "Entry unpinned": "Odpięto wpis" - }, - "Environment Variables": { - "Environment Variables": "Zmienne środowiskowe" - }, - "Error": { - "Error": "Błąd" - }, - "Errors": { - "Errors": "Błędy" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Przesunięcie strefy wyłączności" - }, - "Experimental Feature": { - "Experimental Feature": "Eksperymentalna Funkcja" - }, - "Explore": { - "Explore": "Eksploruj" - }, - "Exponential": { - "Exponential": "Wykładniczy" - }, - "Expressive": { - "Expressive": "" - }, - "Extend battery life": { - "Extend battery life": "" - }, - "Extensible architecture": { - "Extensible architecture": "" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Zarządzanie tapetami zewnętrznymi" - }, - "Extra Arguments": { - "Extra Arguments": "Dodatkowe argumenty" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Przełącz • F10: Pomoc" - }, - "Fade": { - "Fade": "" - }, - "Fade to lock screen": { - "Fade to lock screen": "Wygaszanie do ekranu blokady" - }, - "Fade to monitor off": { - "Fade to monitor off": "" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Nie udało się zaakceptować parowania" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Nie udało się aktywować konfiguracji" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "" - }, - "Failed to add binds include": { - "Failed to add binds include": "Nie udało się dodać powiązań" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Nie udało się dodać drukarki do klasy" - }, - "Failed to browse device": { - "Failed to browse device": "Nie udało się przeglądać plików urządzenia" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Anulowanie wszystkich zadań nie powiodło się" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Anulowanie wybranego zadania nie powiodło się" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Nie udało się sprawdzić limitu pinu" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Nie udało się połączyć z VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Połączenie do %1 nie powiodło się" - }, - "Failed to copy entry": { - "Failed to copy entry": "Nie udało się skopiować wpisu" - }, - "Failed to create printer": { - "Failed to create printer": "Nie udało się utworzyć drukarki" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Nie udało się usunąć VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Nie udało się usunąć klasy" - }, - "Failed to delete printer": { - "Failed to delete printer": "Nie udało się usunąć drukarki" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Nie udało się wyłączyć akceptowania zadań" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Wyłączenie trybu nocnego nie powiodło się" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Nie udało się rozłączyć z VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Nie udało się rozłączyć z sieciami VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Nie udało się rozłączyć z Wi-Fi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Włączenie lokalizacji IP nie powiodło się" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Nie udało się włączyć Wi-Fi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Nie udało się włączyć akceptowania zadań" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Włączenie trybu nocnego nie powiodło się" - }, - "Failed to hold job": { - "Failed to hold job": "Nie udało się wstrzymać zadania" - }, - "Failed to import VPN": { - "Failed to import VPN": "Nie udało się zaimportować VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Nie udało się uruchomić aplikacji do SMS-ów" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Nie udało się wczytać konfiguracji VPN" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Załadowanie konfiguracji schowka nie powiodło się." - }, - "Failed to move job": { - "Failed to move job": "Nie udało się przenieść zadania" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Nie udało się przeczytać plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Nie udało się przeczytać session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Nie udało się przeczytać settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Wstrzymanie drukarki nie powiodło się" - }, - "Failed to pin entry": { - "Failed to pin entry": "Nie udało się wprowadzić pinu" - }, - "Failed to print test page": { - "Failed to print test page": "Nie udało się wydrukować strony testowej" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Nie udało się sparować" - }, - "Failed to remove device": { - "Failed to remove device": "Nie udało się usunąć urządzenia" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Nie udało się usunąć skrótu klawiszowego" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Nie udało się usunąć drukarki z klasy" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "" - }, - "Failed to restart job": { - "Failed to restart job": "Nie udało się uruchomić ponownie zadania" - }, - "Failed to resume printer": { - "Failed to resume printer": "Wznowienie drukarki nie powiodło się" - }, - "Failed to ring device": { - "Failed to ring device": "Nie udało się " - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Zapisanie konfiguracji schowka nie powiodło się" - }, - "Failed to save keybind": { - "Failed to save keybind": "Nie udało się zapisać skrótu klawiszowego" - }, - "Failed to save profile file": { - "Failed to save profile file": "" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Nie udało się wysłać zawartości schowka" - }, - "Failed to send file": { - "Failed to send file": "Nie udało się wysłać pliku" - }, - "Failed to send ping": { - "Failed to send ping": "Nie udało się spingować" - }, - "Failed to set brightness": { - "Failed to set brightness": "Ustawienie jasności nie powiodło się" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Ustawienie lokalizacji trybu nocnego nie powiodło się" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Ustawienie harmonogramu trybu nocnego nie powiodło się" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Ustawienie temperatury trybu nocnego nie powiodło się" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "Nie udało się ustawić zdjęcia profilowego" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Ustawienie obrazu prof. nie powiodło się: %1" - }, - "Failed to share": { - "Failed to share": "Nie udało się udostępnić" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Rozpoczęcie połączenia do %1 nie powiodło się" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Nie udało się odpiąć wpisu" - }, - "Failed to update VPN": { - "Failed to update VPN": "Nie udało się zaktualizować VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Nie udało się zaktualizować automatycznego łączenia" - }, - "Failed to update description": { - "Failed to update description": "Nie udało się zaktualizować opisu" - }, - "Failed to update location": { - "Failed to update location": "Nie udało się zaktualizować lokalizacji" - }, - "Failed to update sharing": { - "Failed to update sharing": "Nie udało się zaktualizować udostępniania" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Zapisanie pliku tymczasowego do walidacji nie powiodło się" - }, - "Features": { - "Features": "Możliwości" - }, - "Feels": { - "Feels": "" - }, - "Feels Like": { - "Feels Like": "Odczuwalna" - }, - "Feels Like %1°": { - "Feels Like %1°": "" - }, - "Fidelity": { - "Fidelity": "" - }, - "Field": { - "Field": "" - }, - "File": { - "File": "Plik" - }, - "File Already Exists": { - "File Already Exists": "Plik już istnieje" - }, - "File Information": { - "File Information": "Informacje" - }, - "File received from": { - "File received from": "Otrzymano plik z" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "" - }, - "Files": { - "Files": "Akta" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Monitorowanie użycia systemu plików" - }, - "Fill": { - "Fill": "" - }, - "Find in Text": { - "Find in Text": "Znajdź w tekście" - }, - "Find in note...": { - "Find in note...": "Znajdź w notatce..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "Pierwsza konfiguracja" - }, - "Fit": { - "Fit": "" - }, - "Fix Now": { - "Fix Now": "Napraw teraz" - }, - "Fixing...": { - "Fixing...": "Ustalenie..." - }, - "Flags": { - "Flags": "Flagi" - }, - "Flipped": { - "Flipped": "Odwrócony" - }, - "Flipped 180°": { - "Flipped 180°": "Odwrócony o 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Odwrócony o 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Odwrócony o 90°" - }, - "Float": { - "Float": "" - }, - "Focus": { - "Focus": "" - }, - "Focus at Startup": { - "Focus at Startup": "Aktywuj przy starcie" - }, - "Focused Border": { - "Focused Border": "" - }, - "Focused Color": { - "Focused Color": "" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "Aktywne okno" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "" - }, - "Folder": { - "Folder": "" - }, - "Folders": { - "Folders": "" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "" - }, - "Follow focus": { - "Follow focus": "Podążaj za kursorem" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "Rodzina czcionki" - }, - "Font Scale": { - "Font Scale": "Skala czcionki" - }, - "Font Size": { - "Font Size": "Rozmiar czcionki" - }, - "Font Weight": { - "Font Weight": "Grubość czcionki" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "Wymuś HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "" - }, - "Force Wide Color": { - "Force Wide Color": "Wymuś Szerokie Kolory" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Wymuś ciemny motyw na aplikacjach terminala" - }, - "Forecast": { - "Forecast": "Prognoza" - }, - "Forecast Days": { - "Forecast Days": "Dni prognozyz" - }, - "Forecast Not Available": { - "Forecast Not Available": "Prognoza niedostępna" - }, - "Forever": { - "Forever": "Zawsze" - }, - "Forget": { - "Forget": "Zapomnij" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "" - }, - "Forget Device": { - "Forget Device": "Zapomnij urządzenie" - }, - "Forget Network": { - "Forget Network": "Zapomnij sieć" - }, - "Forgot network %1": { - "Forgot network %1": "Zapomniano sieć %1" - }, - "Format Legend": { - "Format Legend": "Legenda formatowania" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "" - }, - "Frequency": { - "Frequency": "Częstotliwość" - }, - "Fruit Salad": { - "Fruit Salad": "" - }, - "Full Command:": { - "Full Command:": "Pełna komenda:" - }, - "Full Content": { - "Full Content": "" - }, - "Full Day & Month": { - "Full Day & Month": "" - }, - "Full with Year": { - "Full with Year": "" - }, - "Fullscreen": { - "Fullscreen": "" - }, - "Fullscreen Only": { - "Fullscreen Only": "" - }, - "Fully Charged": { - "Fully Charged": "" - }, - "Fun": { - "Fun": "Zabawa" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: siatka • Z/X: rozmiar" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "Monitorowanie GPU" - }, - "GPU Temperature": { - "GPU Temperature": "Temperatura GPU" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE i więcej" - }, - "Games": { - "Games": "Gry" - }, - "Gamma Control": { - "Gamma Control": "Kontrola gammy" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Kontrola gamma niedostępna. Wymaga DMS API w wersji 6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "" - }, - "Get Started": { - "Get Started": "Rozpocznij" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "" - }, - "Golden Hour": { - "Golden Hour": "Złota godzina" - }, - "Good": { - "Good": "Dobry" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Gotycki promień narożnika" - }, - "Goth Corners": { - "Goth Corners": "Gotyckie narożniki" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Stopniowe wygaszanie ekranu przed zablokowaniem z konfigurowalnym czasem opóźnienia" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "" - }, - "Graph Time Range": { - "Graph Time Range": "Zakres czasowy wykresu" - }, - "Graphics": { - "Graphics": "Grafika" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "Siatka" - }, - "Grid Columns": { - "Grid Columns": "Kolumny siatki" - }, - "Grid: OFF": { - "Grid: OFF": "Siatka: Wyłączona" - }, - "Grid: ON": { - "Grid: ON": "Siatka: Włączona" - }, - "Group": { - "Group": "Grupy" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Aplikacje obszaru roboczego grupy" - }, - "Group by App": { - "Group by App": "Grupuj według aplikacji" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Grupuj wiele okien tej samej aplikacji ze wskaźnikiem liczby okien" - }, - "Group removed": { - "Group removed": "Grupa usunięta" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Grupuj powtarzające się ikony aplikacji w nieaktywnych obszarach roboczych" - }, - "Groups": { - "Groups": "Grupy" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Mapowanie Tonów HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "Tryb HDR jest eksperymentalny. Upewnij się że twój monitor wspiera HDR przed włączeniem." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML skopiowany do schowka" - }, - "Health": { - "Health": "Stan" - }, - "Heavy Rain": { - "Heavy Rain": "" - }, - "Heavy Snow": { - "Heavy Snow": "" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "" - }, - "Height": { - "Height": "" - }, - "Held": { - "Held": "Wstrzymane" - }, - "Help": { - "Help": "Pomoc" - }, - "Hex": { - "Hex": "Klątwa" - }, - "Hibernate": { - "Hibernate": "Hibernacja" - }, - "Hidden": { - "Hidden": "Ukryte" - }, - "Hidden (%1)": { - "Hidden (%1)": "" - }, - "Hidden Apps": { - "Hidden Apps": "" - }, - "Hidden Network": { - "Hidden Network": "Ukryta sieć" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "" - }, - "Hide": { - "Hide": "" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "" - }, - "Hide App": { - "Hide App": "" - }, - "Hide Delay": { - "Hide Delay": "Ukryj opóźnienie" - }, - "Hide Indicators": { - "Hide Indicators": "" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Ukryj Widżet Aktualizatora" - }, - "Hide When Typing": { - "Hide When Typing": "Ukryj podczas pisania" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Ukryj Gdy Otwarte Są Okna" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Ukryj kursor po czasie nieaktywności (0 = wyłączone)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Ukryj kursor podczas wciskania klawiszy klawiatury" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Ukryj kursor podczas używania dotyku" - }, - "Hide device": { - "Hide device": "" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "" - }, - "Hide on Touch": { - "Hide on Touch": "Ukryj przy dotknięciu" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Wysokiej jakości paleta, która zachowuje źródłowe odcienie." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "Historia" - }, - "History Retention": { - "History Retention": "Okres przechowywania" - }, - "History Settings": { - "History Settings": "Ustawienia Historii" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Historia została wyczyszczona. Zachowano %1 przypiętych pozycji." - }, - "Hold Duration": { - "Hold Duration": "Czas przytrzymania" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Przytrzymaj dłużej, aby potwierdzić" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Przytrzymaj, aby potwierdzić akcje zasilania" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Przytrzymaj by potwierdzić (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Przytrzymaj, aby potwierdzić (%1s)" - }, - "Home": { - "Home": "" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "Nazwa hosta" - }, - "Hot Corners": { - "Hot Corners": "Gorące Narożniki" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Tytuł nakładki skrótu klawiszowego (opcjonalnie)" - }, - "Hour": { - "Hour": "Godzina" - }, - "Hourly": { - "Hourly": "" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Jak często zmieniać tapetę" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "Wilgotność" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "" - }, - "Hyprland Options": { - "Hyprland Options": "" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "Rozumiem" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "Adres IP:" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "" - }, - "Icon": { - "Icon": "" - }, - "Icon Scale": { - "Icon Scale": "" - }, - "Icon Size": { - "Icon Size": "Rozmiar ikony" - }, - "Icon Size %": { - "Icon Size %": "" - }, - "Icon Theme": { - "Icon Theme": "Motyw ikon" - }, - "Idle": { - "Idle": "Bezczynna" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inhibitor bezczynności" - }, - "Idle Settings": { - "Idle Settings": "Ustawienia bezczynności" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Monitorowanie bezczynności nie jest obsługiwane - wymaga nowszej wersji Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Jeśli pole jest ukryte pokaże się gdy klawisz zostanie wciśnięty." - }, - "Ignore Completely": { - "Ignore Completely": "" - }, - "Image": { - "Image": "Zdjęcie" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Obraz skopiowany do schowka" - }, - "Import": { - "Import": "Importuj" - }, - "Import VPN": { - "Import VPN": "Importuj VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Nieaktywny kolor monitora" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Uwzględnij przejścia" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Załadowano niekompatybilne pluginy" - }, - "Incorrect password": { - "Incorrect password": "Niepoprawne hasło" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Styl wskaźnika" - }, - "Individual Batteries": { - "Individual Batteries": "Pojedyncze akumulatory" - }, - "Individual bar configuration": { - "Individual bar configuration": "Indywidualna konfiguracja paska" - }, - "Info": { - "Info": "Informacje" - }, - "Inherit": { - "Inherit": "Dziedzicz" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "" - }, - "Input Devices": { - "Input Devices": "Urządzenia wejściowe" - }, - "Input Volume Slider": { - "Input Volume Slider": "Suwak Głośności Wejściowej" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Instaluj" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "Instalowanie Wtyczki" - }, - "Install Theme": { - "Install Theme": "Instalowanie Motywu" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Zainstaluj motywy z rejestru DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "Instalacja nie powiodła się: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Zainstaluj matugen dla dynamiczych motywów" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Zainstalować wtyczkę '%1' z rejestru DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Instaluj wtyczki z rejestru wtyczek DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Zainstalować motyw '%1' z rejestru DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "Zainstalowano" - }, - "Installed: %1": { - "Installed: %1": "Zainstalowano: %1" - }, - "Installing: %1": { - "Installing: %1": "Instalowanie: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Inteligentne autoukrywanie" - }, - "Intensity": { - "Intensity": "Intensywność" - }, - "Interface:": { - "Interface:": "Interfejs:" - }, - "Interlock Open": { - "Interlock Open": "Blokada otwarta" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Interwał" - }, - "Invalid configuration": { - "Invalid configuration": "Nieprawidłowa konfiguracja" - }, - "Invert on mode change": { - "Invert on mode change": "Odwróć przy zmianie trybu" - }, - "Iris Bloom": { - "Iris Bloom": "" - }, - "Isolate Displays": { - "Isolate Displays": "Izoluj Wyświetlacze" - }, - "Jobs": { - "Jobs": "Zadania" - }, - "Jobs: ": { - "Jobs: ": "Zadania: " - }, - "Keep Awake": { - "Keep Awake": "Utrzymuj aktywność" - }, - "Keep Changes": { - "Keep Changes": "Zachowaj zmiany" - }, - "Keeping Awake": { - "Keeping Awake": "Utrzymywanie aktywności" - }, - "Kernel": { - "Kernel": "Jądro" - }, - "Key": { - "Key": "Klawisz" - }, - "Keybind Sources": { - "Keybind Sources": "Źródła " - }, - "Keybinds": { - "Keybinds": "Skróty klawiszowe" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Ustawienia wyszukiwania skrótów klawiszowych" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Nazwa układu klawiatury" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Skróty klawiaturowe" - }, - "Keys": { - "Keys": "Klawiatura" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "Zabij proces" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "Urządzenie LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "" - }, - "Largest": { - "Largest": "" - }, - "Last hour": { - "Last hour": "Ostatnia godzina" - }, - "Last launched %1": { - "Last launched %1": "Ostatnio uruchomiony %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "Ostatni uruchomiony właśnie teraz" - }, - "Latitude": { - "Latitude": "Szerokość geograficzna" - }, - "Launch": { - "Launch": "Uruchom" - }, - "Launch Prefix": { - "Launch Prefix": "Prefiks uruchomienia" - }, - "Launch on dGPU": { - "Launch on dGPU": "Uruchom na dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Program uruchamiający" - }, - "Launcher Button": { - "Launcher Button": "" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Logo przycisku programu uruchamiającego" - }, - "Layout": { - "Layout": "Układ" - }, - "Layout Overrides": { - "Layout Overrides": "Nadpisywanie Układu" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Lewa" - }, - "Left Center": { - "Left Center": "" - }, - "Left Section": { - "Left Section": "Sekcja lewa" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "Jasny Motyw" - }, - "Light Rain": { - "Light Rain": "" - }, - "Light Snow": { - "Light Snow": "" - }, - "Light Snow Showers": { - "Light Snow Showers": "" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "Liniowy" - }, - "Lines: %1": { - "Lines: %1": "Linie: %1" - }, - "List": { - "List": "Lista" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Żywa paleta z nasyconymi akcentami." - }, - "Load Average": { - "Load Average": "Średnie obciążenie" - }, - "Loading codecs...": { - "Loading codecs...": "Ładowanie kodeków..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Ładowanie skrótów klawiszowych..." - }, - "Loading trending...": { - "Loading trending...": "" - }, - "Loading...": { - "Loading...": "Wczytywanie..." - }, - "Local": { - "Local": "Lokalna" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "Lokalizacja" - }, - "Location Search": { - "Location Search": "Wyszukiwanie lokalizacji" - }, - "Lock": { - "Lock": "Zablokuj" - }, - "Lock Screen": { - "Lock Screen": "Ekran blokady" - }, - "Lock Screen Display": { - "Lock Screen Display": "Wyświetlanie ekranu blokady" - }, - "Lock Screen Format": { - "Lock Screen Format": "Format ekranu blokady" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Zachowanie ekranu blokady" - }, - "Lock Screen layout": { - "Lock Screen layout": "Układ ekranu blokady" - }, - "Lock at startup": { - "Lock at startup": "" - }, - "Lock before suspend": { - "Lock before suspend": "Zablokuj przed wstrzymaniem" - }, - "Lock fade grace period": { - "Lock fade grace period": "" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "Zablokowane" - }, - "Log Out": { - "Log Out": "Wyloguj" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "Długi" - }, - "Long Text": { - "Long Text": "Długi tekst" - }, - "Long press": { - "Long press": "Długie naciśnięcie" - }, - "Longitude": { - "Longitude": "Długość geograficzna" - }, - "Low Priority": { - "Low Priority": "Niski priorytet" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Zarządzaj i konfiguruj wtyczki rozszerzające funkcjonalność DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Zarządzaj maksymalnie 4 niezależnymi konfiguracjami pasków. Każdy pasek ma własną pozycję, widżety, styl i przypisanie do wyświetlacza." - }, - "Management": { - "Management": "Zarządzanie" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "Ręczne współrzędne" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "Ręczny rozmiar odstępu" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Ręczne pokazywanie/ukrywanie" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "" - }, - "Margin": { - "Margin": "Margines" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Brak materiału eksploatacyjnego" - }, - "Marker Supply Low": { - "Marker Supply Low": "Niski poziom materiału eksploatacyjnego" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Pojemnik na zużyty materiał prawie pełny" - }, - "Marker Waste Full": { - "Marker Waste Full": "Pojemnik na zużyty materiał pełny" - }, - "Match Criteria": { - "Match Criteria": "" - }, - "Matches profile: %1": { - "Matches profile: %1": "" - }, - "Material Colors": { - "Material Colors": "Kolory Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Motywy inspirowane Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Kolory Material wygenerowane z tapety" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Brak Matugen" - }, - "Matugen Palette": { - "Matugen Palette": "Paleta Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Monitor docelowy Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Szablony Matugen" - }, - "Max Edges": { - "Max Edges": "" - }, - "Max H": { - "Max H": "" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "" - }, - "Max Running Apps": { - "Max Running Apps": "" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "" - }, - "Max Volume": { - "Max Volume": "" - }, - "Max W": { - "Max W": "" - }, - "Max apps to show": { - "Max apps to show": "Maksymalna liczba aplikacji do pokazania" - }, - "Max to Edges": { - "Max to Edges": "" - }, - "Maximize": { - "Maximize": "" - }, - "Maximize Detection": { - "Maximize Detection": "Wykrywanie maksymalizacji" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maksymalny rozmiar wpisu" - }, - "Maximum History": { - "Maximum History": "Maksymalna historia" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Maksymalna ilość przypiętych pozycji" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Maksymalna liczba wpisów schowka" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Maksymalna liczba wpisów, które mogą być zachowane" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Osiągnięto maksymalną liczbę wpisów" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Maksymalny rozmiar per wpis schowka" - }, - "Media": { - "Media": "Media" - }, - "Media Controls": { - "Media Controls": "Sterowanie mediami" - }, - "Media Empty": { - "Media Empty": "Brak nośnika" - }, - "Media Jam": { - "Media Jam": "Zacięcie nośnika" - }, - "Media Low": { - "Media Low": "Niski poziom nośnika" - }, - "Media Needed": { - "Media Needed": "Wymagany nośnik" - }, - "Media Playback": { - "Media Playback": "" - }, - "Media Player": { - "Media Player": "Odtwarzacz multimedialny" - }, - "Media Player Settings": { - "Media Player Settings": "Ustawienia odtwarzacza multimediów" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "Odtwarzacze multimediów (" - }, - "Media Volume": { - "Media Volume": "Głośność Multimediów" - }, - "Medium": { - "Medium": "Średni" - }, - "Memory": { - "Memory": "Pamięć" - }, - "Memory Graph": { - "Memory Graph": "Wykres pamięci" - }, - "Memory Usage": { - "Memory Usage": "Użycie pamięci" - }, - "Memory usage indicator": { - "Memory usage indicator": "Wskaźnik zużycia pamięci" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Wiadomość" - }, - "Message Content": { - "Message Content": "" - }, - "Microphone": { - "Microphone": "Mikrofon" - }, - "Microphone Mute": { - "Microphone Mute": "Wyciszenie mikrofonu" - }, - "Microphone Volume": { - "Microphone Volume": "Głośność Mikrofonu" - }, - "Microphone settings": { - "Microphone settings": "Ustawienia mikrofonu" - }, - "Microphone volume control": { - "Microphone volume control": "Kontrola głośności mikrofonu" - }, - "Middle Section": { - "Middle Section": "Sekcja środkowa" - }, - "Min H": { - "Min H": "" - }, - "Min W": { - "Min W": "" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Minimalna paleta zbudowana wokół jednego odcienia." - }, - "Minute": { - "Minute": "Minuta" - }, - "Mirror Display": { - "Mirror Display": "Wyświetlacz Lustrzany" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "" - }, - "Modal Background": { - "Modal Background": "Tło Okna Dialogowego" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "" - }, - "Mode": { - "Mode": "Tryb" - }, - "Mode:": { - "Mode:": "Tryb:" - }, - "Model": { - "Model": "Model" - }, - "Modified": { - "Modified": "Zmodyfikowane" - }, - "Modular widget bar": { - "Modular widget bar": "" - }, - "Monitor": { - "Monitor": "" - }, - "Monitor Configuration": { - "Monitor Configuration": "Konfiguracja monitora" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Monitor, którego tapeta steruje dynamicznymi kolorami motywu" - }, - "Monochrome": { - "Monochrome": "" - }, - "Monocle": { - "Monocle": "Monokl" - }, - "Monospace Font": { - "Monospace Font": "Czcionka o stałej szerokości" - }, - "Month Date": { - "Month Date": "" - }, - "Morning": { - "Morning": "Poranek" - }, - "Mount Points": { - "Mount Points": "Punkty montowania" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "" - }, - "Move": { - "Move": "" - }, - "Move Widget": { - "Move Widget": "Przesuń Widżet" - }, - "Moving to Paused": { - "Moving to Paused": "Przechodzenie w stan wstrzymania" - }, - "Multi-Monitor": { - "Multi-Monitor": "" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "" - }, - "Mute Popups": { - "Mute Popups": "" - }, - "Mute popups for %1": { - "Mute popups for %1": "" - }, - "Muted": { - "Muted": "" - }, - "Muted Apps": { - "Muted Apps": "" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Wyciszona paleta ze stonowanymi, uspokajającymi tonami." - }, - "NM not supported": { - "NM not supported": "NM nie jest obsługiwany" - }, - "Name": { - "Name": "Nazwa" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Ikony nazwanych obszarów roboczych" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "Nawigacja" - }, - "Network": { - "Network": "Sieć" - }, - "Network Graph": { - "Network Graph": "Wykres Sieci" - }, - "Network Info": { - "Network Info": "Informacje o sieci" - }, - "Network Information": { - "Network Information": "Informacje sieciowe" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Nazwa sieci (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Monitor prędkości sieci" - }, - "Network Status": { - "Network Status": "Stan sieci" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Wyświetlanie prędkości pobierania i wysyłania sieci" - }, - "Neutral": { - "Neutral": "" - }, - "Never": { - "Never": "Nigdy" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "Nowy" - }, - "New Key": { - "New Key": "Nowy klucz" - }, - "New Keybind": { - "New Keybind": "Nowy skrót klawiszowy" - }, - "New Notification": { - "New Notification": "Nowe powiadomienie" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "" - }, - "New York, NY": { - "New York, NY": "Nowy Jork, NY" - }, - "New group name...": { - "New group name...": "Nowa nazwa grupy..." - }, - "Next": { - "Next": "" - }, - "Next Transition": { - "Next Transition": "Następne Przejście" - }, - "Night": { - "Night": "Noc" - }, - "Night Mode": { - "Night Mode": "Tryb nocny" - }, - "Night Temperature": { - "Night Temperature": "Temperatura w nocy" - }, - "Night mode & gamma": { - "Night mode & gamma": "Tryb nocny i gamma" - }, - "Niri Integration": { - "Niri Integration": "Integracja Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Nadpisywanie Układów Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Akcje kompozytora Niri (skupienie, ruch itp.)" - }, - "No": { - "No": "Nie" - }, - "No Active Players": { - "No Active Players": "Brak aktywnych odtwarzaczy" - }, - "No Anim": { - "No Anim": "" - }, - "No Background": { - "No Background": "Brak tła" - }, - "No Battery": { - "No Battery": "" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Nie znaleziono adaptera Bluetooth" - }, - "No Blur": { - "No Blur": "" - }, - "No Border": { - "No Border": "" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Nie skonfigurowano żadnych skrótów DMS" - }, - "No Dim": { - "No Dim": "" - }, - "No Focus": { - "No Focus": "" - }, - "No GPU detected": { - "No GPU detected": "Nie wykryto GPU" - }, - "No GPUs detected": { - "No GPUs detected": "" - }, - "No History": { - "No History": "" - }, - "No Media": { - "No Media": "Brak mediów" - }, - "No Round": { - "No Round": "" - }, - "No Rounding": { - "No Rounding": "" - }, - "No Shadow": { - "No Shadow": "" - }, - "No VPN profiles": { - "No VPN profiles": "Brak profili VPN" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "Brak danych pogodowych" - }, - "No Weather Data Available": { - "No Weather Data Available": "Brak danych pogodowych" - }, - "No action": { - "No action": "Brak działania" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "" - }, - "No adapters": { - "No adapters": "Brak adapterów" - }, - "No app customizations.": { - "No app customizations.": "" - }, - "No apps found": { - "No apps found": "" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "" - }, - "No battery": { - "No battery": "Brak baterii" - }, - "No brightness devices available": { - "No brightness devices available": "Brak dostępnych urządzeń jasności" - }, - "No changes": { - "No changes": "Bez zmian" - }, - "No checks passed": { - "No checks passed": "" - }, - "No custom theme file": { - "No custom theme file": "Brak niestandardowego pliku motywu" - }, - "No devices": { - "No devices": "" - }, - "No devices connected": { - "No devices connected": "" - }, - "No devices found": { - "No devices found": "Nie znaleziono urządzeń" - }, - "No disk data": { - "No disk data": "Brak danych o dysku" - }, - "No disk data available": { - "No disk data available": "Brak danych o dysku" - }, - "No drivers found": { - "No drivers found": "Nie znaleziono sterowników" - }, - "No errors": { - "No errors": "Brak błędów" - }, - "No features enabled": { - "No features enabled": "Brak włączonych funkcji" - }, - "No files found": { - "No files found": "Nie znaleziono plików" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "" - }, - "No hidden apps.": { - "No hidden apps.": "" - }, - "No info items": { - "No info items": "" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "" - }, - "No input devices found": { - "No input devices found": "" - }, - "No items added yet": { - "No items added yet": "Nie dodano jeszcze żadnych elementów" - }, - "No keybinds found": { - "No keybinds found": "Nie znaleziono skrótów klawiszowych" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "" - }, - "No match criteria": { - "No match criteria": "" - }, - "No matches": { - "No matches": "Brak wyników" - }, - "No matching processes": { - "No matching processes": "" - }, - "No monitors": { - "No monitors": "" - }, - "No mount points found": { - "No mount points found": "" - }, - "No output device": { - "No output device": "" - }, - "No output devices found": { - "No output devices found": "" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "" - }, - "No plugins found": { - "No plugins found": "Nie znaleziono wtyczek" - }, - "No plugins found.": { - "No plugins found.": "Nie znaleziono wtyczek." - }, - "No printer found": { - "No printer found": "Nie znaleziono drukarki" - }, - "No printers configured": { - "No printers configured": "Brak skonfigurowanych drukarek" - }, - "No printers found": { - "No printers found": "Nie znaleziono drukarek" - }, - "No profiles": { - "No profiles": "" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "" - }, - "No results found": { - "No results found": "" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "Nie znaleziono motywów" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Motywy nie są zainstalowane. Przeglądaj by zainstalować motywy z rejestru." - }, - "No trigger": { - "No trigger": "" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "Nie wybrano tapety" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "" - }, - "No warnings": { - "No warnings": "Brak ostrzeżeń" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "" - }, - "No widgets available": { - "No widgets available": "Brak dostępnych widżetów" - }, - "No widgets match your search": { - "No widgets match your search": "Żaden widżet nie pasuje do wyszukiwania" - }, - "No window rules configured": { - "No window rules configured": "" - }, - "None": { - "None": "Brak" - }, - "Normal": { - "Normal": "Normalny" - }, - "Normal Font": { - "Normal Font": "Czcionka normalna" - }, - "Normal Priority": { - "Normal Priority": "Normalny priorytet" - }, - "Not available": { - "Not available": "Niedostępne" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "Nie połączono" - }, - "Not detected": { - "Not detected": "Nie wykryto" - }, - "Not paired": { - "Not paired": "" - }, - "Not set": { - "Not set": "" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Notatka: ta opcja zmienia tylko procent, nie ogranicza ładowania." - }, - "Notepad": { - "Notepad": "Notatnik" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Ustawienia czcionki notatnika" - }, - "Notepad Slideout": { - "Notepad Slideout": "Wysuwany notatnik" - }, - "Nothing": { - "Nothing": "" - }, - "Nothing to see here": { - "Nothing to see here": "Nic tu nie ma" - }, - "Notification Center": { - "Notification Center": "Centrum powiadomień" - }, - "Notification Display": { - "Notification Display": "Wyświetlanie powiadomień" - }, - "Notification Overlay": { - "Notification Overlay": "Nakładka powiadomień" - }, - "Notification Popups": { - "Notification Popups": "Wyskakujące powiadomienia" - }, - "Notification Rules": { - "Notification Rules": "" - }, - "Notification Settings": { - "Notification Settings": "Ustawienia powiadomień" - }, - "Notification Timeouts": { - "Notification Timeouts": "Limity czasu powiadomień" - }, - "Notification toast popups": { - "Notification toast popups": "Wyskakujące okienka powiadomień" - }, - "Notifications": { - "Notifications": "Powiadomienia" - }, - "Numbers": { - "Numbers": "Liczby" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Logo OS" - }, - "OSD Position": { - "OSD Position": "Pozycja OSD" - }, - "Occupied Color": { - "Occupied Color": "" - }, - "Off": { - "Off": "Wyłączony" - }, - "Office": { - "Office": "Biuro" - }, - "Offline": { - "Offline": "" - }, - "Offline Report": { - "Offline Report": "Raport offline" - }, - "Older": { - "Older": "Starsze" - }, - "On": { - "On": "" - }, - "On-Demand": { - "On-Demand": "" - }, - "On-Screen Displays": { - "On-Screen Displays": "Wyświetlacze ekranowe" - }, - "On-screen Displays": { - "On-screen Displays": "Powiadomienia ekranowe" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Dostosuj gamma tylko na podstawie reguł czasu lub lokalizacji." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Pokaż tylko okna z aktualnego monitora na każdym doku" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Widoczne tylko wtedy, gdy system obsługuje hibernację" - }, - "Opacity": { - "Opacity": "Przezroczystość" - }, - "Opaque": { - "Opaque": "" - }, - "Open": { - "Open": "Otwórz" - }, - "Open App": { - "Open App": "" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "" - }, - "Open Notepad File": { - "Open Notepad File": "Otwórz plik" - }, - "Open a new note": { - "Open a new note": "" - }, - "Open folder": { - "Open folder": "" - }, - "Open in Browser": { - "Open in Browser": "" - }, - "Open in terminal": { - "Open in terminal": "" - }, - "Open search bar to find text": { - "Open search bar to find text": "Otwórz pasek wyszukiwania, aby znaleźć tekst" - }, - "Open with...": { - "Open with...": "Otwórz za pomocą..." - }, - "Opening SMS": { - "Opening SMS": "Otwieranie SMS" - }, - "Opening SMS app": { - "Opening SMS app": "Otwieranie aplikacji do SMS-ów" - }, - "Opening file browser": { - "Opening file browser": "Otwieranie przeglądarki plików" - }, - "Opening files": { - "Opening files": "" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "Opcjonalny opis" - }, - "Optional location": { - "Optional location": "Opcjonalna lokalizacja" - }, - "Options": { - "Options": "Opcje" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "" - }, - "Original: %1": { - "Original: %1": "" - }, - "Other": { - "Other": "Inne" - }, - "Outline": { - "Outline": "" - }, - "Output": { - "Output": "" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Obszar wyjściowy prawie pełny" - }, - "Output Area Full": { - "Output Area Full": "Obszar wyjściowy pełny" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "" - }, - "Output Tray Missing": { - "Output Tray Missing": "Brak tacy wyjściowej" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Wyjścia zawierają brakujące" - }, - "Overcast": { - "Overcast": "" - }, - "Overflow": { - "Overflow": "" - }, - "Overridden by config": { - "Overridden by config": "Nadpisane przez konfigurację" - }, - "Override": { - "Override": "Prześcigać" - }, - "Override Border Size": { - "Override Border Size": "Nadpisz szerokość obramowania" - }, - "Override Corner Radius": { - "Override Corner Radius": "Nadpisz Promień Narożnika" - }, - "Override Gaps": { - "Override Gaps": "Nadpisz Odstępy" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Nadpisz globalne ustawienia układu dla tego wyjścia" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "Nadpisuje" - }, - "Overview": { - "Overview": "Podgląd" - }, - "Overview of your network connections": { - "Overview of your network connections": "Przegląd połączeń sieciowych" - }, - "Overwrite": { - "Overwrite": "Nadpisz" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "" - }, - "Pad Hours": { - "Pad Hours": "" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Dopełnienie" - }, - "Pair": { - "Pair": "Paruj" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Paruj urządzenie Bluetooth" - }, - "Paired": { - "Paired": "Sparowane" - }, - "Pairing": { - "Pairing": "" - }, - "Pairing failed": { - "Pairing failed": "Parowanie nieudane" - }, - "Pairing request from": { - "Pairing request from": "" - }, - "Pairing request sent": { - "Pairing request sent": "" - }, - "Pairing requested": { - "Pairing requested": "" - }, - "Pairing...": { - "Pairing...": "Parowanie..." - }, - "Partly Cloudy": { - "Partly Cloudy": "" - }, - "Passkey:": { - "Passkey:": "Klucz dostępu:" - }, - "Password": { - "Password": "Hasło" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "" - }, - "Pause": { - "Pause": "Wstrzymaj" - }, - "Paused": { - "Paused": "Wstrzymano" - }, - "Pending": { - "Pending": "Oczekujące" - }, - "Pending Charge": { - "Pending Charge": "" - }, - "Pending Discharge": { - "Pending Discharge": "" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Tapety dla każdego trybu" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Tapety dla każdego monitora" - }, - "Per-screen config": { - "Per-screen config": "" - }, - "Percentage": { - "Percentage": "Procent" - }, - "Performance": { - "Performance": "" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Odmowa uprawnień do ustawienia zdjęcia profilowego." - }, - "Personalization": { - "Personalization": "Personalizacja" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "" - }, - "Phone number": { - "Phone number": "Numer telefonu" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "" - }, - "Pin": { - "Pin": "Przypnij" - }, - "Pin to Dock": { - "Pin to Dock": "Przypnij do doku" - }, - "Ping": { - "Ping": "" - }, - "Ping sent": { - "Ping sent": "Wysłano ping" - }, - "Ping sent to": { - "Ping sent to": "Ping został wysłany na" - }, - "Pinned": { - "Pinned": "Przypięte" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "" - }, - "Pixelate": { - "Pixelate": "" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Umieść tutaj katalogi wtyczek. Każda wtyczka powinna zawierać plik manifestu plugin.json." - }, - "Place plugins in %1": { - "Place plugins in %1": "Umieść wtyczki w %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Odtwórz dźwięk, gdy nadejdzie nowe powiadomienie" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Odtwórz dźwięk po podłączeniu zasilania" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Odtwarzaj dźwięk przy zmianie głośności" - }, - "Play sounds for system events": { - "Play sounds for system events": "Odtwarzaj dźwięki zdarzeń systemowych" - }, - "Playback": { - "Playback": "Odtwarzanie" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "Wpięty do zasilania" - }, - "Plugged in": { - "Plugged in": "Wpięto" - }, - "Plugin": { - "Plugin": "Wtyczka" - }, - "Plugin Directory": { - "Plugin Directory": "Katalog Wtyczek" - }, - "Plugin Management": { - "Plugin Management": "Zarządzenie Wtyczkami" - }, - "Plugin Visibility": { - "Plugin Visibility": "" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Wtyczka jest wyłączona – włącz ją w ustawieniach Wtyczek, aby jej używać" - }, - "Plugins": { - "Plugins": "Wtyczki" - }, - "Pointer": { - "Pointer": "Wskaźnik" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "" - }, - "Popup Only": { - "Popup Only": "" - }, - "Popup Position": { - "Popup Position": "Pozycja wyskakującego okienka" - }, - "Popup Shadow": { - "Popup Shadow": "" - }, - "Popup Transparency": { - "Popup Transparency": "Przezroczystość wyskakującego okienka" - }, - "Popup behavior, position": { - "Popup behavior, position": "" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "" - }, - "Position": { - "Position": "Pozycja" - }, - "Position, pinned apps": { - "Position, pinned apps": "Pozycja, przypięte aplikacje" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Możliwe konflikty nadpisywania" - }, - "Power": { - "Power": "Zasilanie" - }, - "Power & Security": { - "Power & Security": "Zasilanie i bezpieczeństwo" - }, - "Power & Sleep": { - "Power & Sleep": "Zasilanie i Usypianie" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Potwierdzenie działania zasilania" - }, - "Power Menu Customization": { - "Power Menu Customization": "Dostosowywanie menu zasilania" - }, - "Power Off": { - "Power Off": "Wyłącz komputer" - }, - "Power Options": { - "Power Options": "Opcje zasilania" - }, - "Power Profile": { - "Power Profile": "Profil mocy" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Pogorszenie profilu zasilania" - }, - "Power Saver": { - "Power Saver": "" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Wyłącz monitory przy zablokowanym ekranie" - }, - "Power profile management available": { - "Power profile management available": "Zarządzanie profilami zasilania dostępne" - }, - "Power source": { - "Power source": "Źródło zasilania" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "" - }, - "Precipitation": { - "Precipitation": "" - }, - "Precipitation Chance": { - "Precipitation Chance": "Prawdopodobieństwo opadów" - }, - "Preference": { - "Preference": "Ustawienie" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Predefiniowane szerokości (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "" - }, - "Press key...": { - "Press key...": "Naciśnij klawisz..." - }, - "Pressure": { - "Pressure": "Ciśnienie" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Zapobiegaj wygaszaniu ekranu" - }, - "Preview": { - "Preview": "" - }, - "Primary": { - "Primary": "Główny" - }, - "Primary Container": { - "Primary Container": "" - }, - "Print Server Management": { - "Print Server Management": "Zarządzanie Serwerem Drukowania" - }, - "Print Server not available": { - "Print Server not available": "Serwer wydruku niedostępny" - }, - "Printer": { - "Printer": "Drukarka" - }, - "Printer Classes": { - "Printer Classes": "Klasy drukarek" - }, - "Printer created successfully": { - "Printer created successfully": "Drukarka utworzona pomyślnie" - }, - "Printer deleted": { - "Printer deleted": "Drukarka usunięta" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nazwa drukarki (bez spacji)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "Drukarki" - }, - "Printers: ": { - "Printers: ": "Drukarki: " - }, - "Prioritize performance": { - "Prioritize performance": "" - }, - "Priority": { - "Priority": "" - }, - "Privacy Indicator": { - "Privacy Indicator": "Wskaźnik prywatności" - }, - "Privacy Mode": { - "Privacy Mode": "" - }, - "Private Key Password": { - "Private Key Password": "Hasło klucza prywatnego" - }, - "Process Count": { - "Process Count": "Liczba procesów" - }, - "Processes": { - "Processes": "Procesy" - }, - "Processes:": { - "Processes:": "Procesy:" - }, - "Processing": { - "Processing": "Przetwarzanie" - }, - "Profile Image Error": { - "Profile Image Error": "Błąd zdjęcia profilowego" - }, - "Profile activated: %1": { - "Profile activated: %1": "" - }, - "Profile deleted": { - "Profile deleted": "" - }, - "Profile error": { - "Profile error": "" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Zdjęcie profilowe jest za duże. Użyj mniejszego zdjęcia." - }, - "Profile name": { - "Profile name": "" - }, - "Profile not found": { - "Profile not found": "" - }, - "Profile saved: %1": { - "Profile saved: %1": "" - }, - "Protocol": { - "Protocol": "Protokół" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Szybki dostęp do uruchamiania aplikacji" - }, - "Quick access to color picker": { - "Quick access to color picker": "Szybki dostęp do próbnika kolorów" - }, - "Quick access to notepad": { - "Quick access to notepad": "Szybki dostęp do notatnika" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Wysuwany panel szybkiego sporządzania notatek" - }, - "Quick system toggles": { - "Quick system toggles": "" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "" - }, - "Rain": { - "Rain": "" - }, - "Rain Chance": { - "Rain Chance": "Szansa na deszcz" - }, - "Rainbow": { - "Rainbow": "" - }, - "Random": { - "Random": "" - }, - "Rate": { - "Rate": "Prędkość" - }, - "Read:": { - "Read:": "Odczyt:" - }, - "Reason": { - "Reason": "Powód" - }, - "Reboot": { - "Reboot": "Uruchom ponownie" - }, - "Recent Colors": { - "Recent Colors": "Ostatnie kolory" - }, - "Recently Used Apps": { - "Recently Used Apps": "Ostatnio używane aplikacje" - }, - "Recommended available": { - "Recommended available": "Zalecane dostępne" - }, - "Refresh": { - "Refresh": "Odśwież" - }, - "Refresh Weather": { - "Refresh Weather": "Odśwież pogodę" - }, - "Regex": { - "Regex": "" - }, - "Reject": { - "Reject": "Odrzuć" - }, - "Reject Jobs": { - "Reject Jobs": "Odrzucaj zadania" - }, - "Release": { - "Release": "" - }, - "Reload Plugin": { - "Reload Plugin": "Wczytaj ponownie wtyczkę" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "Usuń" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Usuń odstępy i ramkę gdy okna są zmaksymalizowane" - }, - "Rename": { - "Rename": "" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "" - }, - "Repeat": { - "Repeat": "Powtórz" - }, - "Replacement": { - "Replacement": "" - }, - "Report": { - "Report": "Raport" - }, - "Request Pairing": { - "Request Pairing": "Sparuj" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Wymagaj przytrzymania przycisku/klawisza, aby potwierdzić wyłączenie, ponowne uruchomienie, wstrzymanie, hibernację i wylogowanie" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "Wymaga %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Wymaga narzędzia 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "Wymaga DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Wymaga kompozytora DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Wymaga wsparcia dla trybu nocnego" - }, - "Reset": { - "Reset": "Resetuj" - }, - "Reset Position": { - "Reset Position": "Resetuj pozycję" - }, - "Reset Size": { - "Reset Size": "Resetuj rozmiar" - }, - "Reset to default name": { - "Reset to default name": "" - }, - "Resize Widget": { - "Resize Widget": "Zmień rozmiar widżetu" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Rozdzielczość i odświeżanie" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Rozdzielczość, pozycja, skalowanie" - }, - "Restart DMS": { - "Restart DMS": "Uruchom ponownie DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Uruchom ponownie DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "" - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Wznów" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Odwróć Kierunek Przewijania" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Odwróc kierunek przełączania obszarów roboczych podczas przewijania nad paskiem" - }, - "Revert": { - "Revert": "Odwracać" - }, - "Right": { - "Right": "Prawo" - }, - "Right Center": { - "Right Center": "" - }, - "Right Section": { - "Right Section": "Sekcja prawa" - }, - "Right Tiling": { - "Right Tiling": "Prawe kafelkowanie" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Kliknij prawym i przeciągnij na widżecie" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Kliknij prawy i przeciągnij dolny prawy róg" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Kliknij prawym przyciskiem myszy pasek widżetu, aby przejść do następnego" - }, - "Ring": { - "Ring": "Zadzwoń" - }, - "Ringing": { - "Ringing": "Dzwonienie" - }, - "Ripple Effects": { - "Ripple Effects": "" - }, - "Root Filesystem": { - "Root Filesystem": "Główny System Plików" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Zaokrąglone narożniki okien" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "" - }, - "Rule": { - "Rule": "" - }, - "Rule Name": { - "Rule Name": "" - }, - "Rules (%1)": { - "Rules (%1)": "" - }, - "Run Again": { - "Run Again": "Uruchom ponownie" - }, - "Run DMS Templates": { - "Run DMS Templates": "Wykonaj szablony DMS" - }, - "Run User Templates": { - "Run User Templates": "Uruchom szablony użytkownika" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Uruchom program (np. Firefox, Kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Uruchom polecenie powłoki (np. notification-send)" - }, - "Running Apps": { - "Running Apps": "Uruchomione aplikacje" - }, - "Running Apps Settings": { - "Running Apps Settings": "Ustawienia uruchomionych aplikacji" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "Jasność SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Saturacja SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Zapisz" - }, - "Save Notepad File": { - "Save Notepad File": "Zapisz plik notatnika" - }, - "Save QR Code": { - "Save QR Code": "" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Zapisuj w historii odrzucone powiadomienia" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Zapisuj w historii powiadomienia o niskim priorytecie" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Zapisuj w historii powiadomienia o normalnym priorytecie" - }, - "Save password": { - "Save password": "Zapisz hasło" - }, - "Saved": { - "Saved": "Zapisano" - }, - "Saved Configurations": { - "Saved Configurations": "Zapisane konfiguracje" - }, - "Saved Note": { - "Saved Note": "" - }, - "Saved item deleted": { - "Saved item deleted": "Usunięto zapisany element" - }, - "Saving...": { - "Saving...": "" - }, - "Scale": { - "Scale": "Skala" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Skaluj rozmiary czcionek DankBar niezależnie" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Skaluj wszystkie rozmiary czcionek w całej powłoce" - }, - "Scan": { - "Scan": "Skanuj" - }, - "Scanning": { - "Scanning": "Skanowanie" - }, - "Scanning...": { - "Scanning...": "Skanowanie..." - }, - "Science": { - "Science": "Nauka" - }, - "Score": { - "Score": "" - }, - "Screen Sharing": { - "Screen Sharing": "Udostępnianie ekranu" - }, - "Screen sharing": { - "Screen sharing": "Udostępnianie ekranu" - }, - "Scroll": { - "Scroll": "" - }, - "Scroll Factor": { - "Scroll Factor": "" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Kółko przewijania" - }, - "Scroll song title": { - "Scroll song title": "Przewiń tytuł piosenki" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Przewijaj tytuł jeśli nie mieści się w widżecie" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Zachowanie kółka przewijania w widżecie multimediów" - }, - "Scrolling": { - "Scrolling": "Przewijanie" - }, - "Search App Actions": { - "Search App Actions": "" - }, - "Search Options": { - "Search Options": "" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "" - }, - "Search for a location...": { - "Search for a location...": "Szukaj lokalizacji..." - }, - "Search keybinds...": { - "Search keybinds...": "Wyszukaj skróty klawiszowe..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "" - }, - "Search plugins...": { - "Search plugins...": "Szukaj wtyczek..." - }, - "Search processes...": { - "Search processes...": "Szukanie procesów..." - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "Szukaj motywów..." - }, - "Search widgets...": { - "Search widgets...": "Szukaj widżetów..." - }, - "Search...": { - "Search...": "Szukaj..." - }, - "Searching...": { - "Searching...": "Wyszukiwanie..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "Drugorzędny" - }, - "Secured": { - "Secured": "Zabezpieczona" - }, - "Security": { - "Security": "Bezpieczeństwo" - }, - "Security & privacy": { - "Security & privacy": "Bezpieczeństwo i prywatność" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "" - }, - "Select Application": { - "Select Application": "Wybierz aplikację" - }, - "Select Bar": { - "Select Bar": "Wybierz pasek" - }, - "Select Custom Theme": { - "Select Custom Theme": "Wybierz niestandardowy motyw" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "" - }, - "Select File to Send": { - "Select File to Send": "" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Wybierz logo launchera" - }, - "Select Profile Image": { - "Select Profile Image": "Wybierz obraz profilowy" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "Wybierz tapetę" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Wybierz katalog z tapetami" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Wybierz kolor z palety lub użyj niestandardowych suwaków" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Wybierz widżet do dodania na pulpit. Każdy widżet jest osobną instancją z własnymi ustawieniami." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Wybierz widżet do dodania. W razie potrzeby można dodać wiele instancji tego samego widżetu." - }, - "Select a window...": { - "Select a window...": "" - }, - "Select an image file...": { - "Select an image file...": "Wybierz plik obrazu..." - }, - "Select at least one provider": { - "Select at least one provider": "" - }, - "Select device": { - "Select device": "" - }, - "Select device...": { - "Select device...": "Wybierz urządzenie..." - }, - "Select driver...": { - "Select driver...": "Wybierz sterownik..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Wybierz grubość czcionki dla tekstu interfejsu użytkownika" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Wybierz monitor, aby skonfigurować tapetę" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Wybierz czcionkę o stałej szerokości dla listy procesów i wyświetlaczy technicznych" - }, - "Select network": { - "Select network": "" - }, - "Select system sound theme": { - "Select system sound theme": "Wybierz motyw dźwiękowy systemu" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Wybierz rodzinę czcionek dla tekstu interfejsu użytkownika" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Wybierz algorytm palety używany dla kolorów tapet." - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Wybierz, które przejścia uwzględnić w losowaniu" - }, - "Select...": { - "Select...": "Wybierać..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Nie znaleziono wybranego pliku obrazu." - }, - "Send": { - "Send": "Wyślij" - }, - "Send Clipboard": { - "Send Clipboard": "Wyślij schowek" - }, - "Send File": { - "Send File": "" - }, - "Send SMS": { - "Send SMS": "Wyślij SMS" - }, - "Sending": { - "Sending": "" - }, - "Separator": { - "Separator": "Separator" - }, - "Server": { - "Server": "Serwer" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "" - }, - "Set custom name": { - "Set custom name": "" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Ustaw różne tapety dla każdego podłączonego monitora" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Ustaw różne tapety dla trybu jasnego i ciemnego" - }, - "Set key and action to save": { - "Set key and action to save": "Ustaw klucz i akcję, aby zapisać" - }, - "Set notification rules": { - "Set notification rules": "" - }, - "Settings": { - "Settings": "Ustawienia" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Ustawienia są tylko do odczytu. Zmiany nie zostaną zapisane." - }, - "Setup": { - "Setup": "Konfiguruj" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "Udostępnij" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "" - }, - "Share Text": { - "Share Text": "" - }, - "Share URL": { - "Share URL": "Udostępnij URL" - }, - "Shared": { - "Shared": "Udostępniono" - }, - "Shell": { - "Shell": "Powłoka" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Wyczyść wszystko • Esc: Zamknij" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Wklej • Shift+Del: Wyczyść wszystko • Esc: Zamknij" - }, - "Short": { - "Short": "Krótki" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "Skróty" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Skróty (%1)" - }, - "Show": { - "Show": "" - }, - "Show 3rd Party": { - "Show 3rd Party": "" - }, - "Show All Tags": { - "Show All Tags": "Pokaż wszystkie tagi" - }, - "Show Badge": { - "Show Badge": "" - }, - "Show CPU": { - "Show CPU": "Pokaż CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Pokaż wykres CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Pokaż temp. CPU" - }, - "Show Date": { - "Show Date": "Pokaż datę" - }, - "Show Disk": { - "Show Disk": "Pokaż dysk" - }, - "Show Dock": { - "Show Dock": "Pokaż dok" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "" - }, - "Show Footer": { - "Show Footer": "" - }, - "Show Forecast": { - "Show Forecast": "" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Pokaż temperaturę GPU" - }, - "Show Header": { - "Show Header": "Pokaż nagłówek" - }, - "Show Hibernate": { - "Show Hibernate": "Pokaż hibernację" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Pokaż Liczbę Godzin" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "" - }, - "Show Humidity": { - "Show Humidity": "" - }, - "Show Launcher Button": { - "Show Launcher Button": "" - }, - "Show Line Numbers": { - "Show Line Numbers": "Pokaż numery wierszy" - }, - "Show Location": { - "Show Location": "Pokaż lokację" - }, - "Show Lock": { - "Show Lock": "Pokaż blokadę" - }, - "Show Log Out": { - "Show Log Out": "Pokaż wylogowanie" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "" - }, - "Show Media Player": { - "Show Media Player": "" - }, - "Show Memory": { - "Show Memory": "Pokaż pamięć" - }, - "Show Memory Graph": { - "Show Memory Graph": "Pokaż wykres pamięci" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "Pokaż sieć" - }, - "Show Network Graph": { - "Show Network Graph": "Pokaż wykres sieci" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Pokaż tylko zajęte obszary robocze" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "" - }, - "Show Password Field": { - "Show Password Field": "Pokaż pole hasła" - }, - "Show Power Actions": { - "Show Power Actions": "Pokaż akcje zasilania" - }, - "Show Power Off": { - "Show Power Off": "Pokaż wyłączone zasilanie" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Pokaż prawdopodobieństwo przewidywania" - }, - "Show Pressure": { - "Show Pressure": "Pokaż ciśnienie atmosferyczne" - }, - "Show Profile Image": { - "Show Profile Image": "Pokaż obraz profilowy" - }, - "Show Reboot": { - "Show Reboot": "Pokaż ponowne uruchomienie" - }, - "Show Restart DMS": { - "Show Restart DMS": "Pokaż ponowne uruchomienie DMS" - }, - "Show Saved Items": { - "Show Saved Items": "" - }, - "Show Seconds": { - "Show Seconds": "Pokaż sekundy" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Pokaż wschód/zachód" - }, - "Show Suspend": { - "Show Suspend": "Pokaż wstrzymanie" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "Pokaż datę" - }, - "Show System Icons": { - "Show System Icons": "Pokaż ikony systemowe" - }, - "Show System Time": { - "Show System Time": "Pokaż czas" - }, - "Show Top Processes": { - "Show Top Processes": "Pokaż procesy" - }, - "Show Weather Condition": { - "Show Weather Condition": "Pokaż warunki pogodowe" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "" - }, - "Show Wind Speed": { - "Show Wind Speed": "Pokaż prędkość wiatru" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Pokaż aplikacje z obszaru roboczego" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Pokaż wszystkie 9 tagów zamiast tylko zajętych (tylko DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Pokaż wizualizację audio cava w widżecie multimediów" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Pokaż przyciemnioną nakładkę za oknami modalnymi" - }, - "Show device": { - "Show device": "" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Pokaż nakładkę launchera podczas pisania w przeglądzie Niri. Wyłączy by użyć innego launchera." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Pokaż na ostatnim wyświetlaczu" - }, - "Show on Overlay": { - "Show on Overlay": "Pokaż na Nakładce" - }, - "Show on Overview": { - "Show on Overview": "Pokaż w podglądzie" - }, - "Show on Overview Only": { - "Show on Overview Only": "" - }, - "Show on all connected displays": { - "Show on all connected displays": "Pokaż na wszystkich podłączonych wyświetlaczach" - }, - "Show on screens:": { - "Show on screens:": "Pokaż na ekranach:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Wyświetlaj powiadomienie ekranowe przy zmianie jasności" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Wyświetlaj powiadomienie ekranowe przy zmianie stanu Caps Lock" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Pokaż powiadomienie podczas zmiany wyjścia audio" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Wyświetlaj powiadomienie ekranowe przy zmianie stanu inhibitora bezczynności" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Pokaż OSD przy zmianie głośności multimediów" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Wyświetlaj powiadomienie ekranowe przy wyciszaniu/włączaniu mikrofonu" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Wyświetlaj powiadomienie ekranowe przy zmianie profilu zasilania" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Wyświetlaj powiadomienie ekranowe przy zmianie głośności" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Wyświetl informacje o pogodzie na górnym pasku i w centrum sterowania" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Pokaż numery indeksów obszarów roboczych na górnym pasku przełącznika obszarów roboczych" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Pokaż nazwę obszaru roboczego na paskach poziomych i pierwszą literę na paskach pionowych" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Pokazuje wszystkie uruchomione aplikacje ze wskaźnikiem fokusu" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Pokazuje bieżący obszar roboczy i pozwala na przełączanie" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Pojawia się gdy 'Caps Lock' jest aktywny" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Pokazuje, gdy mikrofon, kamera lub udostępnianie ekranu są aktywne" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Wyłączenie" - }, - "Signal": { - "Signal": "Sygnał" - }, - "Signal:": { - "Signal:": "Sygnał:" - }, - "Size": { - "Size": "Rozmiar" - }, - "Size Constraints": { - "Size Constraints": "" - }, - "Size Offset": { - "Size Offset": "Przesunięcie rozmiaru" - }, - "Sizing": { - "Sizing": "Rozmiarowanie" - }, - "Skip": { - "Skip": "Pomiń" - }, - "Skip confirmation": { - "Skip confirmation": "" - }, - "Skip setup": { - "Skip setup": "Pomiń ustawianie" - }, - "Small": { - "Small": "" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Uwierzytelnianie za pomocą karty inteligentnej" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN karty inteligentnej" - }, - "Snap": { - "Snap": "" - }, - "Snow": { - "Snow": "" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Niektóre pluginy wymagają nowszej wersji DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Sortuj alfabetycznie" - }, - "Sort By": { - "Sort By": "Sortuj po" - }, - "Sorting & Layout": { - "Sorting & Layout": "Sortowanie i układ" - }, - "Sound Theme": { - "Sound Theme": "Motyw dźwiękowy" - }, - "Sounds": { - "Sounds": "Dźwięki" - }, - "Space between windows": { - "Space between windows": "Przerwa między oknami" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Odległość pomiędzy oknami (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Odległość pomiędzy oknami (gaps_in and gaps_out)" - }, - "Spacer": { - "Spacer": "Odstęp" - }, - "Spacing": { - "Spacing": "Odstępy" - }, - "Speaker settings": { - "Speaker settings": "Ustawenia głośników" - }, - "Speed": { - "Speed": "Prędkość" - }, - "Spool Area Full": { - "Spool Area Full": "Obszar buforowania pełny" - }, - "Square Corners": { - "Square Corners": "Kwadratowe rogi" - }, - "Stacked": { - "Stacked": "W stosie" - }, - "Standard": { - "Standard": "" - }, - "Start": { - "Start": "Start" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Zacznij pisać swoje notatki tutaj..." - }, - "State": { - "State": "Stan" - }, - "Status": { - "Status": "Status" - }, - "Stopped": { - "Stopped": "Zatrzymano" - }, - "Stopped Partly": { - "Stopped Partly": "Częściowo zatrzymano" - }, - "Stopping": { - "Stopping": "Zatrzymywanie" - }, - "Stretch": { - "Stretch": "" - }, - "Stripes": { - "Stripes": "" - }, - "Summary": { - "Summary": "" - }, - "Sunrise": { - "Sunrise": "Wschód słońca" - }, - "Sunset": { - "Sunset": "Zachód słońca" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Wyłącz wyskakujące okienka powiadomień, gdy opcja jest włączona" - }, - "Surface": { - "Surface": "Powierzchnia" - }, - "Surface Variant": { - "Surface Variant": "" - }, - "Suspend": { - "Suspend": "Wstrzymaj" - }, - "Suspend behavior": { - "Suspend behavior": "Zachowanie wstrzymania" - }, - "Suspend system after": { - "Suspend system after": "Wstrzymaj system po" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "Przełącz użytkownika" - }, - "Switch to power profile": { - "Switch to power profile": "Przełącz profil zasilania" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Tryb synchronizacji z portalem" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Synchronizuj ciemny motyw z systemem" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "System" - }, - "System App Theming": { - "System App Theming": "Motywy aplikacji systemowych" - }, - "System Check": { - "System Check": "Sprawdzanie systemu" - }, - "System Default": { - "System Default": "" - }, - "System Information": { - "System Information": "Informacje o systemie" - }, - "System Monitor": { - "System Monitor": "Monitor systemu" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Monitor systemu niedostępny" - }, - "System Sounds": { - "System Sounds": "Dźwięki systemowe" - }, - "System Tray": { - "System Tray": "Zasobnik systemowy" - }, - "System Update": { - "System Update": "Aktualizacja systemu" - }, - "System Updater": { - "System Updater": "Aktualizator Systemu" - }, - "System Updates": { - "System Updates": "Aktualizacje systemu" - }, - "System notification area icons": { - "System notification area icons": "Ikony obszaru powiadomień systemowych" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "" - }, - "System theme toggle": { - "System theme toggle": "Przełącz motyw systemowy" - }, - "System toast notifications": { - "System toast notifications": "Powiadomienia o toastach systemowych" - }, - "System update custom command": { - "System update custom command": "Niestandardowe polecenie aktualizacji systemu" - }, - "Tab": { - "Tab": "Karta" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nawigacja • ←→↑↓: Nawigacja po siatce • Enter/Spacja: Wybierz" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Niestandardowe dodatkowe parametry terminala" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminal - Zawsze używaj ciemnego motywu" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "Strona testowa" - }, - "Test page sent to printer": { - "Test page sent to printer": "Strona testowa wysłana do drukarki" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "Tekst" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "Zmienna środowiskowa DMS_SOCKET nie jest ustawiona lub gniazdo jest niedostępne. Automatyczne zarządzanie wtyczkami wymaga zmiennej DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Poniższe ustawienia zmodyfikują ustawienia GTK i Qt. Jeśli chcesz zachować obecne konfiguracje, wykonaj ich kopię zapasową (qt5ct.conf|qt6ct.conf i ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "Kolejka zadań tej drukarki jest pusta" - }, - "Theme & Colors": { - "Theme & Colors": "Motyw i kolory" - }, - "Theme Color": { - "Theme Color": "Kolor motywu" - }, - "Theme Registry": { - "Theme Registry": "Rejestr motywów" - }, - "Themes": { - "Themes": "Motywy" - }, - "Thickness": { - "Thickness": "Grubość" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Ostrzeżenie dotyczące wtyczek stron trzecich" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "To powiązanie jest nadpisywane przez config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Ten widżet zapobiega wyłączaniu zasilania GPU, co może znacznie wpłynąć na żywotność baterii w laptopach. Nie zaleca się używania go na laptopach z hybrydową grafiką." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "To trwale usunie całą historię schowka." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "" - }, - "Thunderstorm": { - "Thunderstorm": "" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "" - }, - "Tile": { - "Tile": "" - }, - "Tile H": { - "Tile H": "" - }, - "Tile V": { - "Tile V": "" - }, - "Tiled": { - "Tiled": "" - }, - "Tiled State": { - "Tiled State": "" - }, - "Tiling": { - "Tiling": "Dekarstwo" - }, - "Time": { - "Time": "" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "Czas i pogoda" - }, - "Time Format": { - "Time Format": "Format czasu" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "Czas pozostały: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Czas do pełnego naładowania: %1" - }, - "Timed Out": { - "Timed Out": "Przekroczono limit czasu" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Przekroczenie limitu czasu powiadomień o krytycznym priorytecie" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Przekroczenie limitu czasu dla powiadomień o niskim priorytecie" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Przekroczenie limitu czasu dla powiadomień o normalnym priorytecie" - }, - "Title": { - "Title": "Tytuł" - }, - "Title regex (optional)": { - "Title regex (optional)": "" - }, - "To Full": { - "To Full": "Do pełna" - }, - "To update, run the following command:": { - "To update, run the following command:": "Aby dokonać aktualizacji, uruchom następujące polecenie:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Aby użyć tego powiązania DMS, usuń lub zmień powiązanie klawiszy w pliku config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Wiadomości toastowe" - }, - "Today": { - "Today": "Dzisiaj" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Przełącz widoczność tej konfiguracji paska" - }, - "Toggling...": { - "Toggling...": "Przełączanie..." - }, - "Tomorrow": { - "Tomorrow": "Jutro" - }, - "Tonal Spot": { - "Tonal Spot": "" - }, - "Toner Empty": { - "Toner Empty": "Brak tonera" - }, - "Toner Low": { - "Toner Low": "Niski poziom tonera" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "Narzędzia" - }, - "Top": { - "Top": "Góra" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "Format górnego paska" - }, - "Top Center": { - "Top Center": "" - }, - "Top Left": { - "Top Left": "Górny Lewy" - }, - "Top Processes": { - "Top Processes": "Procesy" - }, - "Top Right": { - "Top Right": "Górny Prawy" - }, - "Top Section": { - "Top Section": "Górna sekcja" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "Suma zadań" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Przekształć" - }, - "Transition Effect": { - "Transition Effect": "Efekt przejścia" - }, - "Transparency": { - "Transparency": "Przezroczystość" - }, - "Trending GIFs": { - "Trending GIFs": "" - }, - "Trending Stickers": { - "Trending Stickers": "" - }, - "Trigger": { - "Trigger": "" - }, - "Trigger Prefix": { - "Trigger Prefix": "" - }, - "Trigger: %1": { - "Trigger: %1": "" - }, - "Trust": { - "Trust": "" - }, - "Try a different search": { - "Try a different search": "" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "" - }, - "Turn off monitors after": { - "Turn off monitors after": "Wyłącz monitory po" - }, - "Type": { - "Type": "Typ" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "" - }, - "Type to search files": { - "Type to search files": "" - }, - "Typography": { - "Typography": "Typografia" - }, - "Typography & Motion": { - "Typography & Motion": "Czcionki i Animacje" - }, - "Unavailable": { - "Unavailable": "Niedostępny" - }, - "Unfocused Color": { - "Unfocused Color": "" - }, - "Ungrouped": { - "Ungrouped": "" - }, - "Uninstall": { - "Uninstall": "Odinstaluj" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Odinstaluj wtyczkę" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Nie udało się odinstalować: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Odinstalowano: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Odinstalowywanie: %1" - }, - "Unknown": { - "Unknown": "Nieznany" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "" - }, - "Unknown Config": { - "Unknown Config": "Nieznana Konfiguracja" - }, - "Unknown Device": { - "Unknown Device": "Nieznane Urządzenie" - }, - "Unknown GPU": { - "Unknown GPU": "" - }, - "Unknown Monitor": { - "Unknown Monitor": "Nieznany Monitor" - }, - "Unknown Network": { - "Unknown Network": "Nieznana Sieć" - }, - "Unknown Title": { - "Unknown Title": "" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "" - }, - "Unmute": { - "Unmute": "" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "" - }, - "Unnamed Rule": { - "Unnamed Rule": "" - }, - "Unpair": { - "Unpair": "" - }, - "Unpair failed": { - "Unpair failed": "" - }, - "Unpin": { - "Unpin": "" - }, - "Unpin from Dock": { - "Unpin from Dock": "Odepnij z doku" - }, - "Unsaved Changes": { - "Unsaved Changes": "Niezapisane zmiany" - }, - "Unsaved changes": { - "Unsaved changes": "Niezapisane zmiany" - }, - "Unsaved note...": { - "Unsaved note...": "Niezapisana notatka..." - }, - "Untitled": { - "Untitled": "Bez tytułu" - }, - "Untrust": { - "Untrust": "" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "" - }, - "Update All": { - "Update All": "Aktualizuj wszystko" - }, - "Update Plugin": { - "Update Plugin": "Zaktualizuj wtyczkę" - }, - "Uptime": { - "Uptime": "" - }, - "Uptime:": { - "Uptime:": "" - }, - "Urgent Color": { - "Urgent Color": "" - }, - "Usage Tips": { - "Usage Tips": "" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Użyj 24-godzinnego formatu czasu zamiast 12-godzinnego AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Użyj niestandardowego polecenia" - }, - "Use Grid Layout": { - "Use Grid Layout": "Użyj układu siatki" - }, - "Use IP Location": { - "Use IP Location": "Użyj lokalizacji IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Użyj imperialnych jednostek" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Użyj imperialnych jednostek (°F, mph, inHg) zamiast metrycznych (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Użyj czcionki o stałej szerokości" - }, - "Use System Theme": { - "Use System Theme": "Użyj motywu systemowego" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Użyj zewnętrznego menedżera tapet, takiego jak swww, hyprpaper lub swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Używaj animowanych pasków postępu fali do odtwarzania multimediów" - }, - "Use custom border size": { - "Use custom border size": "Użyj niestandardowej szerokości obramowania" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Użyj niestandardowej szerokości obramowania/focus-ring" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Użyj niestandardowego polecenia do aktualizacji systemu" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Użyj własnych odstępów w miejsce odstępów paska" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Używaj własnego promienia okna w zamiast ustawień motywu" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Użyj niestandardowego zaokrąglenia okien zamiast motywowego" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Użyj jasnego motywu zamiast ciemnego" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Użyj motywu dźwiękowego z ustawień systemowych" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Używany, gdy kolor akcentu jest ustawiony na niestandardowy" - }, - "User": { - "User": "Użytkownik" - }, - "Username": { - "Username": "Nazwa użytkownika" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Używa czasów wschodu/zachodu słońca do automatycznego dostosowywania trybu nocnego na podstawie Twojej lokalizacji." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "" - }, - "Utilities": { - "Utilities": "Narzędzia" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "Połączenia VPN" - }, - "VPN Password": { - "VPN Password": "Hasło VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "Konfiguracja VPN zaktualizowana" - }, - "VPN connections": { - "VPN connections": "Połączenia VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN usunięty" - }, - "VPN imported: %1": { - "VPN imported: %1": "Zaimportowano VPN: %1" - }, - "VPN not available": { - "VPN not available": "VPN niedostępny" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "Status VPN i szybkie połączenie" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR na żądanie" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Zmienna Częstotliwość Odświeżania" - }, - "Verification": { - "Verification": "" - }, - "Version": { - "Version": "Wersja" - }, - "Vertical Deck": { - "Vertical Deck": "Pionowy pokład" - }, - "Vertical Grid": { - "Vertical Grid": "Siatka pionowa" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Przewijanie pionowe" - }, - "Vertical Tiling": { - "Vertical Tiling": "Płytki pionowe" - }, - "Vibrant": { - "Vibrant": "" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Wibrująca paleta z zabawnym nasyceniem." - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "" - }, - "View Mode": { - "View Mode": "" - }, - "Visibility": { - "Visibility": "Widoczność" - }, - "Visual Effects": { - "Visual Effects": "" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Wizualny separator między widżetami" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Efekt wizualny używany przy zmianie tapety" - }, - "Volume": { - "Volume": "Głośność" - }, - "Volume Changed": { - "Volume Changed": "Zmiana Głośności" - }, - "Volume Slider": { - "Volume Slider": "Suwak Głośności" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Głośność, jasność i inne systemowe menu ekranowe" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Tapeta" - }, - "Wallpaper Error": { - "Wallpaper Error": "Błąd Tapety" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Monitor tapety" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Przetwarzanie tapety nie powiodło się" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Przetwarzanie tapety nie powiodło się - sprawdź ścieżkę" - }, - "Wallpapers": { - "Wallpapers": "Tapety" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Ciepła temperatura kolorów" - }, - "Warning": { - "Warning": "Ostrzeżenie" - }, - "Warnings": { - "Warnings": "Ostrzeżenia" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Faliste paski postępu" - }, - "Weather": { - "Weather": "Pogoda" - }, - "Weather Widget": { - "Weather Widget": "Widżet pogody" - }, - "Welcome": { - "Welcome": "Witaj" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Witaj w DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Po włączeniu aplikacje są sortowane alfabetycznie. Po wyłączeniu aplikacje są sortowane według częstotliwości użytkowania." - }, - "When locked": { - "When locked": "" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Kiedy widżet aktualizatora jest użyty, ukryj go gdy nie ma aktualizacji" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Hasło Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi i połączenie Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi niedostępne" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "Urządzenie WiFi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "" - }, - "WiFi disabled": { - "WiFi disabled": "WiFi wyłączone" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi włączone" - }, - "WiFi is off": { - "WiFi is off": "WiFi jest wyłączone" - }, - "WiFi off": { - "WiFi off": "" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Szeroki (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Kolor tła widżetu" - }, - "Widget Management": { - "Widget Management": "Zarządzanie widżetami" - }, - "Widget Outline": { - "Widget Outline": "Zarys widżetu" - }, - "Widget Style": { - "Widget Style": "Styl widżetu" - }, - "Widget Styling": { - "Widget Styling": "Stylizacja widżetów" - }, - "Widget Transparency": { - "Widget Transparency": "Przezroczystość widżetu" - }, - "Widget added": { - "Widget added": "Dodano widżet" - }, - "Widget removed": { - "Widget removed": "Usunięto widżet" - }, - "Widgets": { - "Widgets": "Widżety" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Wtyczki, układ, styl" - }, - "Width": { - "Width": "" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Szerokość obramowania okna (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Szerokość obramowania okna (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "" - }, - "Wind": { - "Wind": "Wiatr" - }, - "Wind Speed": { - "Wind Speed": "Prędkość wiatru" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "" - }, - "Window Corner Radius": { - "Window Corner Radius": "Promień Narożnika Okna" - }, - "Window Gaps": { - "Window Gaps": "Odstęp Między Oknami" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Odstępy Okien (px)" - }, - "Window Height": { - "Window Height": "" - }, - "Window Opening": { - "Window Opening": "" - }, - "Window Rounding": { - "Window Rounding": "" - }, - "Window Rules": { - "Window Rules": "" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "" - }, - "Wipe": { - "Wipe": "" - }, - "Workspace": { - "Workspace": "Obszar roboczy" - }, - "Workspace Appearance": { - "Workspace Appearance": "" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Numery indeksów obszarów roboczych" - }, - "Workspace Names": { - "Workspace Names": "Nazwy obszarów roboczych" - }, - "Workspace Padding": { - "Workspace Padding": "Dopełnienie Obszarów Roboczych" - }, - "Workspace Settings": { - "Workspace Settings": "Ustawienia obszaru roboczego" - }, - "Workspace Switcher": { - "Workspace Switcher": "Przełącznik obszarów roboczych" - }, - "Workspace name": { - "Workspace name": "" - }, - "Workspaces": { - "Workspaces": "Przestrzenie robocze" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Obszary robocze i widżety" - }, - "Write:": { - "Write:": "" - }, - "X Axis": { - "X Axis": "Oś X" - }, - "Y Axis": { - "Y Axis": "Oś Y" - }, - "Yes": { - "Yes": "Tak" - }, - "Yesterday": { - "Yesterday": "Wczoraj" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Masz niezapisane zmiany. Zapisać przed zamknięciem tej karty?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Masz niezapisane zmiany. Zapisać przed kontynuowaniem?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Masz niezapisane zmiany. Zapisać przed utworzeniem nowego pliku?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Masz niezapisane zmiany. Zapisać przed otwarciem pliku?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "" - }, - "You're All Set!": { - "You're All Set!": "" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "" - }, - "by %1": { - "by %1": "od %1" - }, - "days": { - "days": "dni" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "" - }, - "devices connected": { - "devices connected": "" - }, - "dgop not available": { - "dgop not available": "dgop niedostępne" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "Konfiguracja dms/outputs istnieje, ale nie jest dodana do konfiguracji twojego kompozytora. Zmiany nie będą miały efektu." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "np. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "np. fokus-obszar roboczy 3, zmiana rozmiaru kolumny -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "np. notify-send 'Cześć' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "wydarzenia" - }, - "ext": { - "ext": "" - }, - "featured": { - "featured": "" - }, - "leave empty for default": { - "leave empty for default": "pozostaw puste dla domyślnej wartości" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl niedostępny - integracja blokady wymaga połączenia z gniazdem DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen nie znaleziony - zainstaluj matugen dla dynamicznych motywów" - }, - "minutes": { - "minutes": "protokół" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "teraz" - }, - "official": { - "official": "oficjalny" - }, - "on Hyprland": { - "on Hyprland": "" - }, - "on MangoWC": { - "on MangoWC": "" - }, - "on Miracle WM": { - "on Miracle WM": "" - }, - "on Niri": { - "on Niri": "" - }, - "on Scroll": { - "on Scroll": "" - }, - "on Sway": { - "on Sway": "" - }, - "open": { - "open": "" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "towary drugiej jakości" - }, - "source": { - "source": "źródło" - }, - "this app": { - "this app": "" - }, - "up": { - "up": "" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "zaktualizuj dms dla integracji z NM." - }, - "v%1 by %2": { - "v%1 by %2": "" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype niedostępny - zainstaluj wtype dla wsparcia wklejania" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Instaluj tylko z zaufanych źródeł" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Miesiąc (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Miesiąc (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Miesiąc (Sty)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Miesiąc (Styczeń)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Wtyczki mogą zawierać błędy lub problemy z bezpieczeństwem" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• W miarę możliwości przejrzyj kod przed instalacją" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Dzień (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Dzień (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Nazwa dnia (Pon)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Nazwa dnia (Poniedziałek)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Rok (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Rok (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pt.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pt.json deleted file mode 100644 index c85f06c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/pt.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 Velocidade de Animação" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 caracteres" - }, - "%1 connected": { - "%1 connected": "%1 conectado(s)" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 duração de animação personalizada" - }, - "%1 disconnected": { - "%1 disconnected": "%1 desconectado" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 desconectado (oculto)" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 existe, mas não está incluído na configuração. Os atalhos personalizados não funcionarão até que isso seja corrigido." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 existe mas não está incluído. Regras de janela não serão aplicadas." - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 agora está incluído na configuração" - }, - "%1 issue found": { - "%1 issue found": "%1 problema encontrado" - }, - "%1 issues found": { - "%1 issues found": "%1 problemas encontrados" - }, - "%1 notifications": { - "%1 notifications": "%1 notificações" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 variantes" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 widgets" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "%1m atrás" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "(Padrão)" - }, - "(Unnamed)": { - "(Unnamed)": "(Sem nome)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 mais" - }, - "/path/to/videos": { - "/path/to/videos": "/caminho/dos/videos" - }, - "0 = square corners": { - "0 = square corners": "0 = cantos quadrados" - }, - "1 day": { - "1 day": "1 dia" - }, - "1 device connected": { - "1 device connected": "1 dispositivo conectado" - }, - "1 event": { - "1 event": "1 evento" - }, - "1 hour": { - "1 hour": "1 hora" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 hora e 30 minutos" - }, - "1 minute": { - "1 minute": "1 minuto" - }, - "1 notification": { - "1 notification": "1 notificação" - }, - "1 second": { - "1 second": "1 segundo" - }, - "10 minutes": { - "10 minutes": "10 minutos" - }, - "10 seconds": { - "10 seconds": "10 segundos" - }, - "10-bit Color": { - "10-bit Color": "Cor de 10-bit" - }, - "12 hours": { - "12 hours": "12 horas" - }, - "14 days": { - "14 days": "14 dias" - }, - "15 minutes": { - "15 minutes": "15 minutos" - }, - "15 seconds": { - "15 seconds": "15 segundos" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 horas" - }, - "2 minutes": { - "2 minutes": "2 minutos" - }, - "2 seconds": { - "2 seconds": "2 segundos" - }, - "20 minutes": { - "20 minutes": "20 minutos" - }, - "20 seconds": { - "20 seconds": "20 segundos" - }, - "24-Hour Format": { - "24-Hour Format": "Formato de 24 Horas" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "formato de 24 horas" - }, - "25 seconds": { - "25 seconds": "25 segundos" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 dias" - }, - "3 hours": { - "3 hours": "3 horas" - }, - "3 minutes": { - "3 minutes": "3 minutos" - }, - "3 seconds": { - "3 seconds": "3 segundos" - }, - "30 days": { - "30 days": "30 dias" - }, - "30 minutes": { - "30 minutes": "30 minutos" - }, - "30 seconds": { - "30 seconds": "30 segundos" - }, - "35 seconds": { - "35 seconds": "35 segundos" - }, - "3rd party": { - "3rd party": "Terceiros" - }, - "4 hours": { - "4 hours": "4 horas" - }, - "4 seconds": { - "4 seconds": "4 segundos" - }, - "40 seconds": { - "40 seconds": "40 segundos" - }, - "45 seconds": { - "45 seconds": "45 segundos" - }, - "5 minutes": { - "5 minutes": "5 minutos" - }, - "5 seconds": { - "5 seconds": "5 segundos" - }, - "50 seconds": { - "50 seconds": "50 segundos" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 segundos" - }, - "6 hours": { - "6 hours": "6 horas" - }, - "7 days": { - "7 days": "7 dias" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 horas" - }, - "8 seconds": { - "8 seconds": "8 segundos" - }, - "90 days": { - "90 days": "90 dias" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Um arquivo com esse nome já existe. Você quer sobrescrevê-lo?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Um shell de desktop moderno para compositores Wayland" - }, - "AC Power": { - "AC Power": "Energia AC" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Abortado" - }, - "About": { - "About": "Sobre" - }, - "Accent Color": { - "Accent Color": "Cor de Destaque" - }, - "Accept": { - "Accept": "Aceitar" - }, - "Accept Jobs": { - "Accept Jobs": "Aceitar Trabalhos" - }, - "Accepting": { - "Accepting": "Aceitando" - }, - "Access clipboard history": { - "Access clipboard history": "Acesso ao histórico área de transferência" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Acesso as notificações e ao não pertube" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Acesso aos controles de sistema e configurações" - }, - "Action": { - "Action": "Ação" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "A ação falhou ou o termianl foi fechado." - }, - "Actions": { - "Actions": "Ações" - }, - "Activate": { - "Activate": "Ativar" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "Ativação" - }, - "Active": { - "Active": "Ativa" - }, - "Active Color": { - "Active Color": "Cor Ativa" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Monitor de Tela de Bloqueio Atual" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Cor de fundo e ícone do bloco ativo" - }, - "Active: %1": { - "Active: %1": "Ativo: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Ativo: %1 +%2" - }, - "Active: None": { - "Active: None": "Ativa: Nenhuma" - }, - "Adapters": { - "Adapters": "Adaptadores" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Adicionar" - }, - "Add Bar": { - "Add Bar": "Adicionar Barra" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Adicionar Widget de Área de Trabalho" - }, - "Add Printer": { - "Add Printer": "Adicionar Impressora" - }, - "Add Title": { - "Add Title": "Adicionar Título" - }, - "Add Widget": { - "Add Widget": "Adicionar Widget" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Adicionar Widget para a Seção %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Adicionar uma borda ao redor da dock" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Adicionar um prefixo personalizado para todos os inicializações de aplicativos. Isso pode ser usado para coisas como 'uwsm-app', 'systemd-run' ou outros invólucros de comandos." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Adicionar e configurar widgets que aparecem na sua área de trabalho" - }, - "Add by Address": { - "Add by Address": "Adicionar por Endereço" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Ajusta o número de colunas no modo de visualização em grade" - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Ajustar volume por rolagem" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Avançado" - }, - "Afternoon": { - "Afternoon": "Tarde" - }, - "All": { - "All": "Todos" - }, - "All Monitors": { - "All Monitors": "Todos os Monitores" - }, - "All checks passed": { - "All checks passed": "Todas as verificações passaram" - }, - "All day": { - "All day": "O dia todo" - }, - "All displays": { - "All displays": "Todos as Telas" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Permitir cliques passarem pelo widget" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Voltar • F1/I: Informações de Arquivo • F10: Ajuda • Esc: Fechar" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "Sempre Ativo" - }, - "Always Show Percentage": { - "Always Show Percentage": "Sempre Mostrar Porcentagem" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Sempre ocultar o dock e revelá-lo ao passar próximo à área do dock" - }, - "Always on icons": { - "Always on icons": "Ícones sempre ligados" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Sempre mostrar o mínimo de 3 áreas de trabalho, mesmo se menos estiverem disponíveis" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Sempre mostrar o dock quando a visão geral do niri estiver aberta" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Sempre mostrar quando houver apenas um monitor conectado" - }, - "Amount": { - "Amount": "Quantidade" - }, - "Analog": { - "Analog": "Analógico" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Exibição de relógio analógico, digital ou empilhado" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Analisando configuração..." - }, - "Animation Duration": { - "Animation Duration": "Duração da Animação" - }, - "Animation Speed": { - "Animation Speed": "Velocidade de Animação" - }, - "Anonymous Identity": { - "Anonymous Identity": "Identidade Anônima" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Identidade Anônima (opcional)" - }, - "App Customizations": { - "App Customizations": "Personalizações do Aplicativo" - }, - "App ID Substitutions": { - "App ID Substitutions": "Substituições de ID de Aplicativo" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "Regex de ID de Aplicativo (ex: ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Lançador de Apps" - }, - "App Names": { - "App Names": "Nomes de Aplicativos" - }, - "App Theming": { - "App Theming": "Tema de Aplicativos" - }, - "Appearance": { - "Appearance": "Aparência" - }, - "Application Dock": { - "Application Dock": "Dock de Aplicativos" - }, - "Applications": { - "Applications": "Aplicativos" - }, - "Apply Changes": { - "Apply Changes": "Aplicar Alterações" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Aplicar cores no GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Aplicar cores no QT" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Aplicar temperatura de cor quente para reduzir a fadiga ocular. Use as configurações de automação abaixo para controlar quando ela será ativada." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "Aplicativos" - }, - "Apps Dock": { - "Apps Dock": "Dock de Aplicativos" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Configurações do Dock de Aplicativos" - }, - "Apps Icon": { - "Apps Icon": "Ícones de Apps" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Os aplicativos são ordenados por frequência de uso, mais recentes, e por último, alfabéticamente." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Aplicativos com nome de exibição personalizado, ícone ou opções de inicialização. Clique com o botão direito em um aplicativo e selecione 'Editar Aplicativo' para personalizar." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Aplicativos com popups de notificação silenciados. Dessilenciar ou excluir para remover." - }, - "Architecture": { - "Architecture": "Arquitetura" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Organizar monitores e configurar resolução, taxa de atualização e VRR" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "Áudio" - }, - "Audio Codec": { - "Audio Codec": "Codec de Áudio" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Seleção dos Codec's de Áudio" - }, - "Audio Devices": { - "Audio Devices": "Dispositivos de Áudio" - }, - "Audio Input": { - "Audio Input": "Entrada de Áudio" - }, - "Audio Output": { - "Audio Output": "Saída de Áudio" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Dispositivos de Saída de Áudio (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Seletor de Saída de Áudio" - }, - "Audio Visualizer": { - "Audio Visualizer": "Visualizador de Áudio" - }, - "Audio system restarted": { - "Audio system restarted": "Sistema de áudio reiniciado" - }, - "Audio volume control": { - "Audio volume control": "Controle de volume de áudio" - }, - "Auth": { - "Auth": "Autenticação" - }, - "Auth Type": { - "Auth Type": "Tipo de Autenticação" - }, - "Authenticate": { - "Authenticate": "Autenticar" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "Autenticação" - }, - "Authentication Required": { - "Authentication Required": "Autenticação Necessária" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Erro ao autenticar, por favor tente novamente" - }, - "Authorize": { - "Authorize": "Autorizar" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Autorizar emparelhamento com " - }, - "Authorize service for ": { - "Authorize service for ": "Autorizar serviço para " - }, - "Auto": { - "Auto": "Automático" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Automático (Largo)" - }, - "Auto Location": { - "Auto Location": "Localização Automática" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Espaçamento Automático de Popup" - }, - "Auto-Clear After": { - "Auto-Clear After": "Auto-Limpeza Depois" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Tempo Limite de Ocultação Automática" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Fechar automaticamente overview do niri ao lançar aplicativos." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Auto-excluir notificações mais antigas que este período" - }, - "Auto-hide": { - "Auto-hide": "Esconder Automaticamente" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Esconder Automaticamente o Dock" - }, - "Auto-saving...": { - "Auto-saving...": "Salvando automáticamente..." - }, - "Autoconnect": { - "Autoconnect": "Conectar automáticamente" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Conexão automática desativada" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Conexão automática ativada" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Modo de Cor Automático" - }, - "Automatic Control": { - "Automatic Control": "Controle Automático" - }, - "Automatic Cycling": { - "Automatic Cycling": "Rotação Automática" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Circular automaticamente dentre os papéis de parede na mesma pasta" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Deleta automaticamente entradas mais antigas que essa" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Detectar localização automáticamente baseado no endereço IP" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Detectar automaticamente a sua localização usando o seu endereço de IP" - }, - "Automatically lock after": { - "Automatically lock after": "Bloquear automaticamente após" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Bloquear tela automaticamente quando o DMS iniciar" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Bloquear tela automaticamente quando o sistema é preparado para suspensão" - }, - "Automation": { - "Automation": "Automação" - }, - "Available": { - "Available": "Disponível" - }, - "Available Layouts": { - "Available Layouts": "Layouts Disponíveis" - }, - "Available Networks": { - "Available Networks": "Redes Disponíveis" - }, - "Available Plugins": { - "Available Plugins": "Plugins disponíveis" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Telas Disponíveis (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Disponível em modos de visualização Detalhada e Previsão" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Voltar" - }, - "Backend": { - "Backend": "Backend" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Opacidade do Fundo" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Imagem de fundo" - }, - "Backlight device": { - "Backlight device": "Dispositivo de iluminação de fundo" - }, - "Balance power and performance": { - "Balance power and performance": "Equilibrar energia e desempenho" - }, - "Balanced": { - "Balanced": "Balanceado" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Paleta equilibrada com destaques de cor focados (padrão)." - }, - "Bar Configurations": { - "Bar Configurations": "Configurações da Barra" - }, - "Bar Shadows": { - "Bar Shadows": "Sombras da Barra" - }, - "Bar Transparency": { - "Bar Transparency": "Trasparência da Barra" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Cor base para sombras (a opacidade é aplicada automaticamente)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Duração base para animações (arraste para usar Personalizado)" - }, - "Battery": { - "Battery": "Bateria" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Limite de Carga da Bateria" - }, - "Battery and power management": { - "Battery and power management": "Gerenciamento de bateria e energia" - }, - "Battery level and power management": { - "Battery level and power management": "Nível de bateria e manejamento de energia" - }, - "Behavior": { - "Behavior": "Comportamento" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Vincular o bloqueio de tela aos sinais do DBus do loginctl. Desative se estiver usando um bloqueio de tela externo" - }, - "Binds Include Missing": { - "Binds Include Missing": "Atalhos Incluem Definições Ausentes" - }, - "Binds include added": { - "Binds include added": "Atalhos incluem adicionados" - }, - "Bit Depth": { - "Bit Depth": "Profundidade de Bits" - }, - "Block Out": { - "Block Out": "Bloquear" - }, - "Block Out From": { - "Block Out From": "Bloquear De" - }, - "Block notifications": { - "Block notifications": "Bloquear notificações" - }, - "Blocked": { - "Blocked": "Bloqueado" - }, - "Blue light filter": { - "Blue light filter": "Filtro de luz azul" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Configurações do Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth indisponível" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Camada de Papel de Parede com Desfoque" - }, - "Blur on Overview": { - "Blur on Overview": "Desfoque na Visão Geral" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Desfoque de papel de parede quando a visão geral do niri estiver aberta" - }, - "Body": { - "Body": "Corpo" - }, - "Border": { - "Border": "Borda" - }, - "Border Color": { - "Border Color": "Cor da Borda" - }, - "Border Opacity": { - "Border Opacity": "Opacidade da Borda" - }, - "Border Size": { - "Border Size": "Tamanho da Borda" - }, - "Border Thickness": { - "Border Thickness": "Espessura da Borda" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "Borda com Fundo" - }, - "Bottom": { - "Bottom": "Inferior" - }, - "Bottom Center": { - "Bottom Center": "Centro Inferior" - }, - "Bottom Left": { - "Bottom Left": "Inferior Esquerdo" - }, - "Bottom Right": { - "Bottom Right": "Inferior Direito" - }, - "Bottom Section": { - "Bottom Section": "Seção Inferior" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Dock inferior para aplicativos fixados e rodando" - }, - "Brightness": { - "Brightness": "Brilho" - }, - "Brightness Slider": { - "Brightness Slider": "Controle deslizante de brilho" - }, - "Brightness Value": { - "Brightness Value": "Valor de Brilho" - }, - "Brightness control not available": { - "Brightness control not available": "Controle de brilho indisponível" - }, - "Browse": { - "Browse": "Navegar" - }, - "Browse Files": { - "Browse Files": "Navegar Arquivos" - }, - "Browse Plugins": { - "Browse Plugins": "Navegar por Plugins" - }, - "Browse Themes": { - "Browse Themes": "Navegar Temas" - }, - "Browse or search plugins": { - "Browse or search plugins": "Procurar ou pesquisar plugins" - }, - "Button Color": { - "Button Color": "Cor do Botão" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "Gráfico de CPU" - }, - "CPU Temperature": { - "CPU Temperature": "Temperatura da CPU" - }, - "CPU Usage": { - "CPU Usage": "Uso da CPU" - }, - "CPU temperature display": { - "CPU temperature display": "Mostrar temperatura da CPU" - }, - "CPU usage indicator": { - "CPU usage indicator": "Indicador de uso da CPU" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Monitoramento de CPU, memória, rede e disco" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "Aviso de Filtro Inseguro do CUPS" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "Aviso de Filtro Inseguro do CUPS" - }, - "CUPS Print Server": { - "CUPS Print Server": "Servidor de Impressão CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS indisponível" - }, - "Camera": { - "Camera": "Câmera" - }, - "Cancel": { - "Cancel": "Cancelar" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Cancelar todos os trabalhos para \"%1\"?" - }, - "Canceled": { - "Canceled": "Cancelado" - }, - "Cannot pair": { - "Cannot pair": "Não foi possível parear" - }, - "Capabilities": { - "Capabilities": "Capacidades" - }, - "Capacity": { - "Capacity": "Capacidade" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indicador de Caps Lock" - }, - "Caps Lock is on": { - "Caps Lock is on": "Caps Lock está ligado" - }, - "Center Section": { - "Center Section": "Seção Central" - }, - "Center Single Column": { - "Center Single Column": "Centralizar Coluna Única" - }, - "Center Tiling": { - "Center Tiling": "Centralizar Tiling" - }, - "Certificate Password": { - "Certificate Password": "Senha do Certificado" - }, - "Change Song": { - "Change Song": "Mudar Música" - }, - "Change Volume": { - "Change Volume": "Alterar Volume" - }, - "Change bar appearance": { - "Change bar appearance": "Alterar aparência da barra" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "Mudar a localidade usada pela interface do DMS." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Mudar a localidade usada para formatação de data e hora, independente da língua da interface." - }, - "Channel": { - "Channel": "Canal" - }, - "Charging": { - "Charging": "Carregando" - }, - "Check for system updates": { - "Check for system updates": "Verificar por atualizações de sistema" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "Escolha a Cor" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Escolher Cor do Modo Escuro" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Escolher Cor do Logotipo do Launcher do Dock" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Escolher a cor para a logo do Lançador" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Escolher Cor do Modo Claro" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Escolher Cor do Papel de Parede" - }, - "Choose a color": { - "Choose a color": "Escolha uma cor" - }, - "Choose colors from palette": { - "Choose colors from palette": "Escolha cores da paleta" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Escolha como o widget de clima é exibido" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "Escolher Ícone" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Escolha a cor de fundo para os widgets" - }, - "Choose the border accent color": { - "Choose the border accent color": "Escolha a cor de realce da borda" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Escolher a logo que será exibida no botão do Lançador no DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Escolher onde as notificações irão aparecer na tela" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Escolher onde OSDs aparecerão na tela" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Escolha quais monitores mostrarão este widget" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Escolha qual monitor mostra a interface de tela de bloqueio. Outros monitores vão mostrar uma cor sólida evitar burn-in no OLED." - }, - "Chroma Style": { - "Chroma Style": "Estilo Chroma" - }, - "Cipher": { - "Cipher": "Cifra" - }, - "Circle": { - "Circle": "Círculo" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Regex de Classe (ex: ^firefox$)" - }, - "Clear": { - "Clear": "Limpar" - }, - "Clear All": { - "Clear All": "Limpar Tudo" - }, - "Clear All Jobs": { - "Clear All Jobs": "Limpar Todos os Trabalhos" - }, - "Clear History?": { - "Clear History?": "Limpar Histórico?" - }, - "Clear Sky": { - "Clear Sky": "Céu Claro" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Limpar todo o histórico quando o servidor iniciar" - }, - "Clear at Startup": { - "Clear at Startup": "Limpar ao Iniciar" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Clique em 'Configurar' para criar %1 e adicionar à configuração" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Clique em 'Configurar' para criar %1 e adicionar inclusão na configuração do seu compositor" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Clique em 'Configurar' para criar configuração de cursor e adicionar inclusão à configuração do compositor." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Clique em 'Configurar' para criar a configuração de saídas e adicionar inclusão no seu configurador de compositor" - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Clique em Importar para adicionar um arquivo .ovpn ou .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "Atravessar Clique" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Clique em qualquer atalho para editar. Alterações salvas em %1" - }, - "Click to capture": { - "Click to capture": "Clique para capturar" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Clique para selecionar um arquivo JSON de tema personalizado" - }, - "Clip": { - "Clip": "Recortar" - }, - "Clip to Geometry": { - "Clip to Geometry": "Recortar para Geometria" - }, - "Clipboard": { - "Clipboard": "Área de transferência" - }, - "Clipboard History": { - "Clipboard History": "Histórico da Área de Transferência" - }, - "Clipboard Manager": { - "Clipboard Manager": "Gerenciador da Área de Transferência" - }, - "Clipboard sent": { - "Clipboard sent": "Área de transferência enviada" - }, - "Clipboard service not available": { - "Clipboard service not available": "Serviço de área de transferência não disponível" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "A área de transferência funciona mas nada é salvo no disco" - }, - "Clock": { - "Clock": "Relógio" - }, - "Clock Style": { - "Clock Style": "Estilo de Relógio" - }, - "Close": { - "Close": "Fechar" - }, - "Close All Windows": { - "Close All Windows": "Fechar Todas as Janelas" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Fechar Overview ao Lançar Aplicativos" - }, - "Close Window": { - "Close Window": "Fechar Janela" - }, - "Color": { - "Color": "Cor" - }, - "Color Gamut": { - "Color Gamut": "Gamut de Cor" - }, - "Color Management": { - "Color Management": "Gerenciamento de Cor" - }, - "Color Mode": { - "Color Mode": "Modo de Cor" - }, - "Color Override": { - "Color Override": "Sobrescrever Cor" - }, - "Color Picker": { - "Color Picker": "Seletor de Cores" - }, - "Color Temperature": { - "Color Temperature": "Temperatura da Cor" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Cor aparente nos monitores sem tela de bloqueio" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Cor para botões de ação primária" - }, - "Color temperature for day time": { - "Color temperature for day time": "Temperatura de cor durante o dia" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Temperatura da cor para o modo noturno" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Tema de cor para destaque de sintaxe." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Tema de cor para destaque de sintaxe. %1 temas disponíveis." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Tema de cor do registro DMS" - }, - "Colorful": { - "Colorful": "Colorido" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Mistura colorida de destaques de cor brilhantes e contrastantes." - }, - "Colorize Active": { - "Colorize Active": "Colorir Ativo" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Cores do papel de parede" - }, - "Column": { - "Column": "Coluna" - }, - "Column Display": { - "Column Display": "Exibição em Coluna" - }, - "Column Width": { - "Column Width": "Largura da Coluna" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Comando" - }, - "Commands": { - "Commands": "Comandos" - }, - "Communication": { - "Communication": "Comunicação" - }, - "Community themes": { - "Community themes": "Temas da comunidade" - }, - "Compact": { - "Compact": "Compacto" - }, - "Compact Mode": { - "Compact Mode": "Modo Compacto" - }, - "Completed": { - "Completed": "Completado" - }, - "Compositor": { - "Compositor": "Compositor" - }, - "Compositor Settings": { - "Compositor Settings": "Configurações do Compositor" - }, - "Compositor not supported": { - "Compositor not supported": "Compositor não suportado" - }, - "Config Format": { - "Config Format": "Formato de Configuração" - }, - "Config action: %1": { - "Config action: %1": "Configurar ação: %1" - }, - "Config validation failed": { - "Config validation failed": "Falha na configuração de validação" - }, - "Configuration": { - "Configuration": "Configuração" - }, - "Configuration activated": { - "Configuration activated": "Configuração ativada" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "A configuração será mantida quando esse monitor reconectar" - }, - "Configure": { - "Configure": "Configurar" - }, - "Configure Keybinds": { - "Configure Keybinds": "Configurar Atalhos de Teclado" - }, - "Configure a new printer": { - "Configure a new printer": "Configure uma nova impressora" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Configurações de ícones para área de trabalho nomeadas. Ícones têm prioridade sobre números quando ambos estão habilitados." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Configurar critérios de correspondência e ações" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Configurar quais telas mostram \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Configurar em quais telas serão mostrados os componentes do shell" - }, - "Confirm": { - "Confirm": "Confirmar" - }, - "Confirm Delete": { - "Confirm Delete": "Confirmar Exclusão" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Confirmar Alterações de Tela" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Confirmar chave de acesso para " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Conflita com: %1" - }, - "Connect": { - "Connect": "Conectar" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Conectar a Rede Oculta" - }, - "Connect to VPN": { - "Connect to VPN": "Conectar à VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Conectar ao Wi-Fi" - }, - "Connected": { - "Connected": "Conectado" - }, - "Connected Device": { - "Connected Device": "Dispositivo Conectado" - }, - "Connected Displays": { - "Connected Displays": "Telas Conectadas" - }, - "Connecting to Device": { - "Connecting to Device": "Conectando ao Dispositivo" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Conectando..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "Contém" - }, - "Content": { - "Content": "Conteúdo" - }, - "Content copied": { - "Content copied": "Conteúdo copiado" - }, - "Contrast": { - "Contrast": "Contraste" - }, - "Control Center": { - "Control Center": "Painel de Controle" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Cor do Bloco do Centro de Controle" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Controlar duração da animação para popups de notificação e histórico" - }, - "Control currently playing media": { - "Control currently playing media": "Controlar mídia que está sendo reproduzida" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Controle quais informações de notificação são mostradas na tela de bloqueio" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Controle quais plugins aparecem no modo 'Todos' sem exigir um prefixo de gatilho. Arraste para reordenar." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Controle espaços de trabalho e colunas rolando na barra" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Controla a opacidade de todos os popouts, modais e suas camadas de conteúdo" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Controla a transparência da sombra" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Opções de conveniência para a tela de login. Sincronize para aplicar." - }, - "Cooldown": { - "Cooldown": "Tempo de espera" - }, - "Copied GIF": { - "Copied GIF": "GIF Copiado" - }, - "Copied MP4": { - "Copied MP4": "MP4 Copiado" - }, - "Copied WebP": { - "Copied WebP": "WebP Copiado" - }, - "Copied to clipboard": { - "Copied to clipboard": "Copiado para a área de transferência" - }, - "Copied!": { - "Copied!": "Copiado!" - }, - "Copy": { - "Copy": "Copiar" - }, - "Copy Content": { - "Copy Content": "Copiar Conteúdo" - }, - "Copy Full Command": { - "Copy Full Command": "Copiar Comando Completo" - }, - "Copy HTML": { - "Copy HTML": "Copiar HTML" - }, - "Copy Name": { - "Copy Name": "Copiar Nome" - }, - "Copy PID": { - "Copy PID": "Copiar PID" - }, - "Copy Text": { - "Copy Text": "Copiar Texto" - }, - "Copy path": { - "Copy path": "Copiar caminho" - }, - "Corner Radius": { - "Corner Radius": "Arredondamento" - }, - "Corner Radius Override": { - "Corner Radius Override": "Sobrescrever Arredondamento" - }, - "Corners & Background": { - "Corners & Background": "Cantos e Fundo" - }, - "Count Only": { - "Count Only": "Apenas Contagem" - }, - "Cover Open": { - "Cover Open": "Tampa Aberta" - }, - "Create": { - "Create": "Criar" - }, - "Create Dir": { - "Create Dir": "Criar pasta" - }, - "Create Printer": { - "Create Printer": "Criar Impressora" - }, - "Create Window Rule": { - "Create Window Rule": "Criar Regra de Janela" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "Criar regra para:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Criar regras para silenciar, ignorar, ocultar do histórico ou substituir a prioridade de notificação. O padrão apenas substitui a prioridade; as notificações ainda aparecem normalmente." - }, - "Creating...": { - "Creating...": "Criando..." - }, - "Critical Priority": { - "Critical Priority": "Prioridade Crítica" - }, - "Current": { - "Current": "Atual" - }, - "Current Items": { - "Current Items": "Itens Atuais" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "Monitor Atual" - }, - "Current Period": { - "Current Period": "Período Atual" - }, - "Current Status": { - "Current Status": "Status Atual" - }, - "Current Temp": { - "Current Temp": "Temperatura Atual" - }, - "Current Theme: %1": { - "Current Theme: %1": "Tema Atual: %1" - }, - "Current Weather": { - "Current Weather": "Clima Atual" - }, - "Current Workspace": { - "Current Workspace": "Área de Trabalho Atual" - }, - "Current time and date display": { - "Current time and date display": "Mostrar hora e data atuais" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Condições de clima atuais e temperatura" - }, - "Current: %1": { - "Current: %1": "Atual: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Configuração de Cursor Não Configurada" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Inclusão de Cursor Ausente" - }, - "Cursor Size": { - "Cursor Size": "Tamanho do Cursor" - }, - "Cursor Theme": { - "Cursor Theme": "Tema do Cursor" - }, - "Custom": { - "Custom": "Customizado" - }, - "Custom Color": { - "Custom Color": "Cor Personalizada" - }, - "Custom Duration": { - "Custom Duration": "Duração Personalizada" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Comando Personalizado Para Hibernar" - }, - "Custom Location": { - "Custom Location": "Customizar Localização" - }, - "Custom Lock Command": { - "Custom Lock Command": "Comando de Bloqueio Personalizado" - }, - "Custom Logout Command": { - "Custom Logout Command": "Comando Personalizado Para Sair" - }, - "Custom Name": { - "Custom Name": "Nome Personalizado" - }, - "Custom Power Actions": { - "Custom Power Actions": "Ações de Energia Customizadas" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Comando Personalizado Para Desligar" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Comando Personalizado Para Reiniciar" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Comando Personalizado Para Suspender" - }, - "Custom Transparency": { - "Custom Transparency": "Transparência Customizada" - }, - "Custom power profile": { - "Custom power profile": "Perfil de energia personalizado" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Tema personalizado carregado do arquivo JSON" - }, - "Custom...": { - "Custom...": "Customizado..." - }, - "Custom: ": { - "Custom: ": "Customizar: " - }, - "Customizable empty space": { - "Customizable empty space": "Espaço vazio customizável" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Customize quais ações aparecerão no menu de energia" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "Monitor DDC/CI" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "MODO DEMONSTRAÇÃO - Clique em qualquer lugar para sair" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Gerenciador de Plugins DMS indispónivel" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Atalhos DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS desatualizado" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Serviço do DMS não está conectado. Configurações de área de transferência não estão disponíveis." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Ações do shell do DMS (lançador, área de transferência, etc.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET não está disponível" - }, - "DWL service not available": { - "DWL service not available": "Serviço do DWL não disponível" - }, - "Daily": { - "Daily": "Diário" - }, - "Daily at:": { - "Daily at:": "Diária:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell está pronto para uso" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell e Ícones do Sistema (Reinicialização necessária)" - }, - "Dark Mode": { - "Dark Mode": "Modo Escuro" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Escurecer Fundo de Modais" - }, - "Date Format": { - "Date Format": "Formatação de Data" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Amanhecer (Crepúsculo Astronômico)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Amanhecer (Crepúsculo Cívil)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Amanhecer (Crepúsculo Náutico)" - }, - "Day Date": { - "Day Date": "Dia Data" - }, - "Day Month Date": { - "Day Month Date": "Dia Mês Data" - }, - "Day Temperature": { - "Day Temperature": "Temperatura Diurna" - }, - "Daytime": { - "Daytime": "Hora do dia" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "Padrão" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "Largura Padrão (%)" - }, - "Default selected action": { - "Default selected action": "Ação selecionada por padrão" - }, - "Defaults": { - "Defaults": "Padrões" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Definir regras para comportamento de janela. Salva em %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Limpar • Shift+Del: Limpar Tudo • 1-9: Ações • F10: Ajuda • Esc: Fechar" - }, - "Delete": { - "Delete": "Excluir" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Excluir \"%1\"?" - }, - "Delete Class": { - "Delete Class": "Excluir Classe" - }, - "Delete Printer": { - "Delete Printer": "Excluir Impressora" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Excluir Item Salvo?" - }, - "Delete VPN": { - "Delete VPN": "Excluir VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Excluir classe \"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Excluir perfil \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Deriva cores que combinam de perto com a imagem de fundo." - }, - "Description": { - "Description": "Descrição" - }, - "Desktop": { - "Desktop": "Área de Trabalho" - }, - "Desktop Clock": { - "Desktop Clock": "Relógio da Área de Trabalho" - }, - "Desktop Entry": { - "Desktop Entry": "Entrada de Desktop" - }, - "Desktop Widget": { - "Desktop Widget": "Widget de Área de Trabalho" - }, - "Desktop Widgets": { - "Desktop Widgets": "Widgets da Área de Trabalho" - }, - "Desktop background images": { - "Desktop background images": "Imagens de fundo da área de trabalho" - }, - "Detailed": { - "Detailed": "Detalhado" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "Desenvolvimento" - }, - "Device": { - "Device": "Dispositivo" - }, - "Device connections": { - "Device connections": "Conexões de dispositivo" - }, - "Device names updated": { - "Device names updated": "Nomes de dispositivos atualizados" - }, - "Device paired": { - "Device paired": "Dispositivo pareado" - }, - "Device unpaired": { - "Device unpaired": "Dispositivo desemparelhado" - }, - "Digital": { - "Digital": "Digital" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Desativar conexão automática" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Desabilitar Papéis de Parede Embutidos" - }, - "Disable History Persistence": { - "Disable History Persistence": "Desativar Persistência de Histórico" - }, - "Disable Output": { - "Disable Output": "Desabilitar Saída" - }, - "Disabled": { - "Disabled": "Desativado" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Desativando WiFi..." - }, - "Disc": { - "Disc": "Disco" - }, - "Discard": { - "Discard": "Descartar" - }, - "Discharging": { - "Discharging": "Descarregando" - }, - "Disconnect": { - "Disconnect": "Desconectar" - }, - "Disconnected": { - "Disconnected": "Desconectado" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Disconectado do WiFi" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "Disco" - }, - "Disk I/O": { - "Disk I/O": "E/S de Disco" - }, - "Disk Usage": { - "Disk Usage": "Uso de Disco" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "Discos" - }, - "Dismiss": { - "Dismiss": "Descartar" - }, - "Display": { - "Display": "Exibição" - }, - "Display Assignment": { - "Display Assignment": "Atribuição de Monitores" - }, - "Display Control": { - "Display Control": "Controle de Exibição" - }, - "Display Name Format": { - "Display Name Format": "Formato do Nome do Monitor" - }, - "Display Profiles": { - "Display Profiles": "Perfis de Exibição" - }, - "Display Settings": { - "Display Settings": "Configurações de Exibição" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Exibir um dock com aplicativos fixados e abertos" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Exibir todas as prioridades em aplicativos de tela cheia" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Mostra e altera layouts do DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Mostrar ícones de aplicativos em indicadores de espaço de trabalho" - }, - "Display brightness control": { - "Display brightness control": "Controle de brilho da tela" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "A configuração de exibição não está disponível. Protocolo de gerenciamento de saída WLR não suportado." - }, - "Display currently focused application title": { - "Display currently focused application title": "Mostrar título do app em foco" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Exibir previsões meteorológicas por hora" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Mostrar apenas áreas de trabalho que possuem janelas" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Mostra as ações do menu de energia em uma grade ao invés de uma lista" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Exibir segundos no relógio" - }, - "Display the power system menu": { - "Display the power system menu": "Mostra o menu de energia do sistema" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Exibir porcentagem de volume e brilho nos pop-ups OSD" - }, - "Displays": { - "Displays": "Telas" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Contagem de Exibições quando o estouro está ativo" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Exibir Layout ativo do teclado, e permitir alterações" - }, - "Distribution": { - "Distribution": "Distribuição" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Paleta diversa que abrange todo o espectro." - }, - "Do Not Disturb": { - "Do Not Disturb": "Não Perturbe" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock & Lançador" - }, - "Dock Transparency": { - "Dock Transparency": "Transparência da Dock" - }, - "Dock Visibility": { - "Dock Visibility": "Visibilidade do Dock" - }, - "Docs": { - "Docs": "Documentos" - }, - "Documents": { - "Documents": "Documentos" - }, - "Domain (optional)": { - "Domain (optional)": "Domínio (opcional)" - }, - "Don't Change": { - "Don't Change": "Não Alterar" - }, - "Don't Save": { - "Don't Save": "Não Salvar" - }, - "Door Open": { - "Door Open": "Porta Aberta" - }, - "Downloads": { - "Downloads": "Downloads" - }, - "Drag to Reorder": { - "Drag to Reorder": "Arraste para Reordenar" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Arraste Widgets para reordená-los nas seções. Use o ícone de olho para esconder ou mostrá-los (manter o espaçamento), ou clique no X para removê-los por completo." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Arraste os indicadores de área de trabalho para reordená-los" - }, - "Driver": { - "Driver": "Driver" - }, - "Drizzle": { - "Drizzle": "Garoa" - }, - "Duplicate": { - "Duplicate": "Duplicar" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Duplicar Papel de Parede com Blur" - }, - "Duration": { - "Duration": "Duração" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Escurecer (Crepúsculo Astronômico)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Escurecer (Crepúsculo Cívil)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Escurecer (Crepúsculo Náutico)" - }, - "Dynamic": { - "Dynamic": "Dinâmico" - }, - "Dynamic Properties": { - "Dynamic Properties": "Propriedades Dinâmicas" - }, - "Dynamic Theming": { - "Dynamic Theming": "Tema Dinâmico" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Cores dinâmicas do papel de parede" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Cores dinâmicas, predefinições" - }, - "Edge Spacing": { - "Edge Spacing": "Espaçamento de Bordas" - }, - "Edit App": { - "Edit App": "Editar Aplicativo" - }, - "Edit Window Rule": { - "Edit Window Rule": "Editar Regra de Janela" - }, - "Education": { - "Education": "Educação" - }, - "Empty": { - "Empty": "Vázio" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Ativar a profundidade de cores de 10 bits para uma gama de cores mais ampla e suporte HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Ativar conexão automática" - }, - "Enable Bar": { - "Enable Bar": "Habilitar Barra" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Habilitar Não Perturbe" - }, - "Enable History": { - "Enable History": "Ativar Histórico" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Habilitar Sobreposição do Overview" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Ativar Efeitos de Ondulação" - }, - "Enable System Sounds": { - "Enable System Sounds": "Ativar Sons do Sistema" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "Habilitar Clima" - }, - "Enable WiFi": { - "Enable WiFi": "Ativar WiFi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Habilitar camada de desfoque direcionável ao compositor (namespace: dms:blurwallpaper). Requer configuração manual do niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Habilitar impressão digital no login" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Habilitar autenticação por impressão digital" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Ativar integração de bloqueio do loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "Ativado" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Ativando WiFi..." - }, - "End": { - "End": "Fim" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Aumentar ao Passar o Mouse" - }, - "Enlargement %": { - "Enlargement %": "Ampliação %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Entre a chave de acesso de 6 dígitos" - }, - "Enter PIN": { - "Enter PIN": "Entre código PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Entre código PIN para " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Digite URL ou texto para compartilhar" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Insira um novo nome para este espaço de trabalho" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "Insira as credenciais para " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Insira um formato customizado para a tela de bloqueio (exemplo: dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Insira um formato customizado para a barra superior (exemplo: ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Digite o nome do dispositivo..." - }, - "Enter filename...": { - "Enter filename...": "Insira nome do arquivo..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Insira o prefixo de inicialização (por exemplo, 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Digite o nome da rede e a senha" - }, - "Enter passkey for ": { - "Enter passkey for ": "Entre chave de acesso para " - }, - "Enter password for ": { - "Enter password for ": "Insira senha para " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Entre esse código em " - }, - "Enter to Paste": { - "Enter to Paste": "Enter para Colar" - }, - "Enterprise": { - "Enterprise": "Enterprise" - }, - "Entry pinned": { - "Entry pinned": "Entrada fixada" - }, - "Entry unpinned": { - "Entry unpinned": "Entrada removida" - }, - "Environment Variables": { - "Environment Variables": "Variáveis de Ambiente" - }, - "Error": { - "Error": "Erro" - }, - "Errors": { - "Errors": "Erros" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Exato" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Ajuste da Zona Exclusiva" - }, - "Experimental Feature": { - "Experimental Feature": "Recurso Experimental" - }, - "Explore": { - "Explore": "Explorar" - }, - "Exponential": { - "Exponential": "Exponencial" - }, - "Expressive": { - "Expressive": "Expressivo" - }, - "Extend battery life": { - "Extend battery life": "Estender duração da bateria" - }, - "Extensible architecture": { - "Extensible architecture": "Arquitetura extensível" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Gerenciamento Externo de Papéis de Parede" - }, - "Extra Arguments": { - "Extra Arguments": "Argumentos Extras" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Ativar • F10: Ajuda" - }, - "Fade": { - "Fade": "Esmaecimento" - }, - "Fade to lock screen": { - "Fade to lock screen": "Esmaecer para a tela de bloqueio" - }, - "Fade to monitor off": { - "Fade to monitor off": "Desaparecer para monitor desligado" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Falha ao aceitar pareamento" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Erro ao ativar configuração" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Falha ao ativar perfil - arquivo não encontrado" - }, - "Failed to add binds include": { - "Failed to add binds include": "Falha ao adicionar \"include\" dos atalhos" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Falha ao adicionar impressora para a classe" - }, - "Failed to browse device": { - "Failed to browse device": "Falha ao navegar no dispositivo" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Falha ao cancelar todos os trabalhos" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Falha ao cancelar o trabalho selecionado" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Falha ao verificar limite de pin" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Erro ao conectar à VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Falha ao conectar a %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Falha ao copiar entrada" - }, - "Failed to create printer": { - "Failed to create printer": "Falha ao criar impressora" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Falha ao criar diretório de perfis" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Falha ao excluir VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Falha ao excluir classe" - }, - "Failed to delete printer": { - "Failed to delete printer": "Falha ao excluir impressora" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Falha ao desativar aceitação de trabalhos" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Falha ao desativar o modo noturno" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Erro ao desconectar VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Erro ao desconectar VPNs" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Erro ao disconectar WiFi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Falha ao ativar a localização IP" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Erro ao habilitar WiFi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Falha ao habilitar aceitação de trabalhos" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Falha ao ativar o modo noturno" - }, - "Failed to hold job": { - "Failed to hold job": "Falha ao segurar trabalho" - }, - "Failed to import VPN": { - "Failed to import VPN": "Falha ao importar VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Falha ao iniciar aplicativo de SMS" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Falha ao carregar configuração da VPN" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Falha ao carregar configuração de área de transferência." - }, - "Failed to move job": { - "Failed to move job": "Falha ao mover trabalho" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Falha ao analisar plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Falha ao analisar session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Falha ao analisar settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Falha ao pausar impressora" - }, - "Failed to pin entry": { - "Failed to pin entry": "Falha ao fixar entrada" - }, - "Failed to print test page": { - "Failed to print test page": "Falha ao imprimir página de testes" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Falha ao rejeitar pareamento" - }, - "Failed to remove device": { - "Failed to remove device": "Erro ao remover dispositivo" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Falha ao remover atalho" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Falha ao remover impressora da classe" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Falha ao reiniciar o sistema de áudio" - }, - "Failed to restart job": { - "Failed to restart job": "Falha ao reiniciar trabalho" - }, - "Failed to resume printer": { - "Failed to resume printer": "Falha ao resumir impressora" - }, - "Failed to ring device": { - "Failed to ring device": "Falha ao tocar dispositivo" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "Falha ao salvar a configuração de áudio" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Falha ao salvar configuração de área de transferência" - }, - "Failed to save keybind": { - "Failed to save keybind": "Falha ao salvar atalho" - }, - "Failed to save profile file": { - "Failed to save profile file": "Falha ao salvar arquivo de perfil" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Falha ao enviar área de transferência" - }, - "Failed to send file": { - "Failed to send file": "Falha ao enviar arquivo" - }, - "Failed to send ping": { - "Failed to send ping": "Falha ao enviar ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "Falha ao definir o brilho" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Falha ao definir a localização do modo noturno" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Falha ao definir o agendamento do modo noturno" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Falha ao definir a temperatura do modo noturno" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "Erro ao definir imagem de perfil" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Falha ao definir imagem de perfil: %1" - }, - "Failed to share": { - "Failed to share": "Falha ao compartilhar" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Falha ao iniciar conexão com %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Falha ao remover entrada" - }, - "Failed to update VPN": { - "Failed to update VPN": "Falha ao atualizar VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Erro ao atualizar conexão automática" - }, - "Failed to update description": { - "Failed to update description": "Falha ao atualizar descrição" - }, - "Failed to update location": { - "Failed to update location": "Falha ao atualizar localização" - }, - "Failed to update sharing": { - "Failed to update sharing": "Falha ao atualizar compartilhamento" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Falha ao salvar arquivo temporário para validação" - }, - "Features": { - "Features": "Recursos" - }, - "Feels": { - "Feels": "Sensações" - }, - "Feels Like": { - "Feels Like": "Sensação Térmica" - }, - "Feels Like %1°": { - "Feels Like %1°": "Sensação Térmica %1°" - }, - "Fidelity": { - "Fidelity": "Fidelidade" - }, - "Field": { - "Field": "Campo" - }, - "File": { - "File": "Arquivo" - }, - "File Already Exists": { - "File Already Exists": "Arquivo já existe" - }, - "File Information": { - "File Information": "Informação do Arquivo" - }, - "File received from": { - "File received from": "Arquivo recebido de" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Pesquisa de arquivo requer dsearch\nInstalar de github.com/morelazers/dsearch" - }, - "Files": { - "Files": "Arquivos" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Monitoramento de uso do sistema de arquivos" - }, - "Fill": { - "Fill": "Preenchimento" - }, - "Find in Text": { - "Find in Text": "Procurar no Texto" - }, - "Find in note...": { - "Find in note...": "Procurar na nota..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "Concluir" - }, - "First Day of Week": { - "First Day of Week": "Primeiro Dia da Semana" - }, - "First Time Setup": { - "First Time Setup": "Configuração Inicial" - }, - "Fit": { - "Fit": "Ajustar" - }, - "Fix Now": { - "Fix Now": "Consertar Agora" - }, - "Fixing...": { - "Fixing...": "Consertando..." - }, - "Flags": { - "Flags": "Bandeiras" - }, - "Flipped": { - "Flipped": "Invertido" - }, - "Flipped 180°": { - "Flipped 180°": "Invertido 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Girado 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Girado 90°" - }, - "Float": { - "Float": "Flutuante" - }, - "Focus": { - "Focus": "Foco" - }, - "Focus at Startup": { - "Focus at Startup": "Foco no Iniciar" - }, - "Focused Border": { - "Focused Border": "Borda em Foco" - }, - "Focused Color": { - "Focused Color": "Cor em Foco" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "Janela Focada" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "Neblina" - }, - "Folder": { - "Folder": "Pasta" - }, - "Folders": { - "Folders": "Pastas" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Seguir Foco do Monitor" - }, - "Follow focus": { - "Follow focus": "Seguir foco" - }, - "Font": { - "Font": "Fonte" - }, - "Font Family": { - "Font Family": "Família da Fonte" - }, - "Font Scale": { - "Font Scale": "Escala da Fonte" - }, - "Font Size": { - "Font Size": "Tamanho da Fonte" - }, - "Font Weight": { - "Font Weight": "Peso da Fonte" - }, - "Font used on the login screen": { - "Font used on the login screen": "Fonte usada na tela de login" - }, - "Force HDR": { - "Force HDR": "Forçar HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Forçar Encerramento (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Forçar Cor Ampla" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Forçar aplicativos de terminal a usar sempre temas escuros" - }, - "Forecast": { - "Forecast": "Previsão" - }, - "Forecast Days": { - "Forecast Days": "Dias de Previsão" - }, - "Forecast Not Available": { - "Forecast Not Available": "Previsão do Tempo não Disponível" - }, - "Forever": { - "Forever": "Para sempre" - }, - "Forget": { - "Forget": "Esquecer" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Esquecer \"%1\"?" - }, - "Forget Device": { - "Forget Device": "Esquecer Dispositivo" - }, - "Forget Network": { - "Forget Network": "Esquecer Internet" - }, - "Forgot network %1": { - "Forgot network %1": "Rede esquecida %1" - }, - "Format Legend": { - "Format Legend": "Formatar Legenda" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "Liberar VRAM/memória quando o lançador estiver fechado. Pode causar um pequeno atraso ao reabrir." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Garoa Congelante" - }, - "Frequency": { - "Frequency": "Frequência" - }, - "Fruit Salad": { - "Fruit Salad": "Salada de Frutas" - }, - "Full Command:": { - "Full Command:": "Comando Completo:" - }, - "Full Content": { - "Full Content": "Conteúdo Completo" - }, - "Full Day & Month": { - "Full Day & Month": "Dia e Mês Completo" - }, - "Full with Year": { - "Full with Year": "Completo com Ano" - }, - "Fullscreen": { - "Fullscreen": "Tela Cheia" - }, - "Fullscreen Only": { - "Fullscreen Only": "Apenas Tela Cheia" - }, - "Fully Charged": { - "Fully Charged": "Totalmente Carregado" - }, - "Fun": { - "Fun": "Diversão" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: grade • Z/X: tamanho" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "Monitoramento de GPU" - }, - "GPU Temperature": { - "GPU Temperature": "Temperatura da GPU" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDEs, mais" - }, - "Games": { - "Games": "Jogos" - }, - "Gamma Control": { - "Gamma Control": "Controle de Gama" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Controle de gama não disponível. Necessário DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "Genérico" - }, - "Get Started": { - "Get Started": "Começar" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Dimensionar globalmente todas as durações de animação" - }, - "Golden Hour": { - "Golden Hour": "Hora Dourada" - }, - "Good": { - "Good": "Bom" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Arredondamento do Canto Gótico" - }, - "Goth Corners": { - "Goth Corners": "Cantos Gotícos" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Gradualmente esmaecer a tela antes de bloquear com um período de tolerância configurável" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Desaparecer gradualmente a tela antes de desligar monitores com um período de carência configurável" - }, - "Graph Time Range": { - "Graph Time Range": "Intervalo de Tempo do Gráfico" - }, - "Graphics": { - "Graphics": "Gráficos" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "Grade" - }, - "Grid Columns": { - "Grid Columns": "Colunas da Grade" - }, - "Grid: OFF": { - "Grid: OFF": "Grade: DESLIGADA" - }, - "Grid: ON": { - "Grid: ON": "Grade: LIGADA" - }, - "Group": { - "Group": "Grupo" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Agrupar Aplicativos da Área de Trabalho" - }, - "Group by App": { - "Group by App": "Agrupar por App" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Agrupar múltiplas janelas do mesmo app com um indicador de número de janelas" - }, - "Group removed": { - "Group removed": "Grupo removido" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Agrupar ícones de aplicativos repetidos em áreas de trabalho não focadas" - }, - "Groups": { - "Groups": "Grupos" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Mapeamento de Tom HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "O modo HDR é experimental. Verifique se seu monitor suporta HDR antes de ativar." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML copiado para a área de transferência" - }, - "Health": { - "Health": "Saúde" - }, - "Heavy Rain": { - "Heavy Rain": "Chuva Forte" - }, - "Heavy Snow": { - "Heavy Snow": "Neve Forte" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Nevascas Intensas" - }, - "Height": { - "Height": "Altura" - }, - "Held": { - "Held": "Mantido" - }, - "Help": { - "Help": "Ajuda" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Hibernar" - }, - "Hidden": { - "Hidden": "Oculto" - }, - "Hidden (%1)": { - "Hidden (%1)": "Oculto (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Aplicativos Ocultos" - }, - "Hidden Network": { - "Hidden Network": "Rede Oculta" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Aplicativos ocultos não aparecerão no launcher. Clique com o botão direito em um aplicativo e selecione 'Ocultar Aplicativo' para ocultá-lo." - }, - "Hide": { - "Hide": "Ocultar" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Ocultar Terceiros" - }, - "Hide App": { - "Hide App": "Ocultar Aplicativo" - }, - "Hide Delay": { - "Hide Delay": "Ocultar atraso" - }, - "Hide Indicators": { - "Hide Indicators": "Ocultar Indicadores" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Ocultar Widget de Atualização" - }, - "Hide When Typing": { - "Hide When Typing": "Ocultar ao Digitar" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Ocultar Quando Janelas Abertas" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Ocultar cursor após inatividade (0 = desativado)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Ocultar cursor ao pressionar teclas do teclado" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Ocultar cursor ao usar entrada por toque" - }, - "Hide device": { - "Hide device": "Ocultar dispositivo" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Ocultar conteúdo da notificação até expandir" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Ocultar conteúdo da notificação até expandir; popups mostram recolhidos por padrão" - }, - "Hide on Touch": { - "Hide on Touch": "Ocultar no Toque" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Paleta de alta fidelidade que preserva tons da fonte." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "Histórico" - }, - "History Retention": { - "History Retention": "Retenção de Histórico" - }, - "History Settings": { - "History Settings": "Configurações do Histórico" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Histórico limpo. %1 entradas fixadas mantidas." - }, - "Hold Duration": { - "Hold Duration": "Duração do Pressionamento" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Mantenha pressionado por mais tempo para confirmar" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Manter Pressionado para Confirmar Ações de Energia" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Segure para confirmar (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Manter pressionado para confirmar (%1s)" - }, - "Home": { - "Home": "Casa" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "Nome do host" - }, - "Hot Corners": { - "Hot Corners": "Cantos Quentes" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Título da sobreposição de atalhos" - }, - "Hour": { - "Hour": "Hora" - }, - "Hourly": { - "Hourly": "Por Hora" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Contagem de Previsão por Hora" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Tempo entre papéis de parede" - }, - "How the background image is scaled": { - "How the background image is scaled": "Como a imagem de fundo é dimensionada" - }, - "Humidity": { - "Humidity": "Umidade" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Substituições de Layout Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "Opções do Hyprland" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "Entendi" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "Endereço IP:" - }, - "IP address or hostname": { - "IP address or hostname": "Endereço de IP ou nome do host" - }, - "ISO Date": { - "ISO Date": "Data ISO" - }, - "Icon": { - "Icon": "Ícone" - }, - "Icon Scale": { - "Icon Scale": "Escala de Ícone" - }, - "Icon Size": { - "Icon Size": "Tamanho do Ícone" - }, - "Icon Size %": { - "Icon Size %": "Tamanho do Ícone %" - }, - "Icon Theme": { - "Icon Theme": "Tema de Ícones" - }, - "Idle": { - "Idle": "Em espera" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Inibitor de inatividade" - }, - "Idle Settings": { - "Idle Settings": "Configurações de inatividade" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Monitoramento de inatividade não disponível – requer versão mais recente do Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Se o campo está escondido, ele aparecerá no momento que uma tecla e pressionada." - }, - "Ignore Completely": { - "Ignore Completely": "Ignorar Completamente" - }, - "Image": { - "Image": "Imagem" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Imagem copiada para a área de trabalho" - }, - "Import": { - "Import": "Importar" - }, - "Import VPN": { - "Import VPN": "Importar VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Cor do Monitor Inativo" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Incluir Transições" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Incluir ações de desktop (atalhos) nos resultados da pesquisa." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Plugins Incompatíveis Carregados" - }, - "Incorrect password": { - "Incorrect password": "Senha incorreta" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Estilo de Indicador" - }, - "Individual Batteries": { - "Individual Batteries": "Baterias Individuais" - }, - "Individual bar configuration": { - "Individual bar configuration": "Configuração individual da barra" - }, - "Info": { - "Info": "Informações" - }, - "Inherit": { - "Inherit": "Herdar" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "Inibível" - }, - "Input Devices": { - "Input Devices": "Dispositivos de Entrada" - }, - "Input Volume Slider": { - "Input Volume Slider": "Controle deslizante de volume de entrada" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Instalar" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "Instalar Plugin" - }, - "Install Theme": { - "Install Theme": "Instalar Tema" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Instalar temas de cor do registro de temas DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "Instalação falhou: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Instalar pacote matugen para tema dinâmico" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Instalar plugin '%1' do registro DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Instale plugins a partir do registro de plugins do DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Instalar tema '%1' do registro DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "Instalado" - }, - "Installed: %1": { - "Installed: %1": "Instalado: %1" - }, - "Installing: %1": { - "Installing: %1": "Instalando: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Ocultação Automática Inteligente" - }, - "Intensity": { - "Intensity": "Intensidade" - }, - "Interface:": { - "Interface:": "Interface:" - }, - "Interlock Open": { - "Interlock Open": "Trava de Segurança Aberta" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervalo" - }, - "Invalid configuration": { - "Invalid configuration": "Configuração inválida" - }, - "Invert on mode change": { - "Invert on mode change": "Inverter na mudança de modo" - }, - "Iris Bloom": { - "Iris Bloom": "Íris em Flor" - }, - "Isolate Displays": { - "Isolate Displays": "Isolar Monitores" - }, - "Jobs": { - "Jobs": "Trabalhos" - }, - "Jobs: ": { - "Jobs: ": "Trabalhos:" - }, - "Keep Awake": { - "Keep Awake": "Manter Ligado" - }, - "Keep Changes": { - "Keep Changes": "Manter Alterações" - }, - "Keeping Awake": { - "Keeping Awake": "Mantendo Ligado" - }, - "Kernel": { - "Kernel": "Kernel" - }, - "Key": { - "Key": "Tecla" - }, - "Keybind Sources": { - "Keybind Sources": "Fontes de Combinações de Teclas" - }, - "Keybinds": { - "Keybinds": "Atalhos de Teclado" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Configurações de Pesquisa de Combinações de Teclas" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Combinações de teclas mostradas junto com resultados de pesquisa regulares" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Nome de Layout do Teclado" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Atalhos do Teclado" - }, - "Keys": { - "Keys": "Teclas" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "Matar Processo" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "Dispositivo LED" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "Grande" - }, - "Largest": { - "Largest": "Maior" - }, - "Last hour": { - "Last hour": "Última hora" - }, - "Last launched %1": { - "Last launched %1": "Lançado pela última vez em %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Lançado pela última vez %1 dia atrás" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "Lançado pela última vez agora" - }, - "Latitude": { - "Latitude": "Latitude" - }, - "Launch": { - "Launch": "Inicializar" - }, - "Launch Prefix": { - "Launch Prefix": "Prefixo de Inicialização" - }, - "Launch on dGPU": { - "Launch on dGPU": "Inicializar na dGPU" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Lançador" - }, - "Launcher Button": { - "Launcher Button": "Botão do Launcher" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Logo do botão do Lançador" - }, - "Layout": { - "Layout": "Layout" - }, - "Layout Overrides": { - "Layout Overrides": "Substituições de Layout" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Esquerda" - }, - "Left Center": { - "Left Center": "Centro Esquerdo" - }, - "Left Section": { - "Left Section": "Seção da Esquerda" - }, - "Light Direction": { - "Light Direction": "Direção da Luz" - }, - "Light Mode": { - "Light Mode": "Modo Claro" - }, - "Light Rain": { - "Light Rain": "Chuva Leve" - }, - "Light Snow": { - "Light Snow": "Neve Leve" - }, - "Light Snow Showers": { - "Light Snow Showers": "Nevascas Leves" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "Linha" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "Linear" - }, - "Lines: %1": { - "Lines: %1": "Linhas: %1" - }, - "List": { - "List": "Lista" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Paleta vívida com destaques de cor saturados." - }, - "Load Average": { - "Load Average": "Carga Média" - }, - "Loading codecs...": { - "Loading codecs...": "Carregando codecs..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Carregando atalhos..." - }, - "Loading trending...": { - "Loading trending...": "Carregando trending..." - }, - "Loading...": { - "Loading...": "Carregando..." - }, - "Local": { - "Local": "Local" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "Localização" - }, - "Location Search": { - "Location Search": "Procurar Localização" - }, - "Lock": { - "Lock": "Bloquear" - }, - "Lock Screen": { - "Lock Screen": "Tela de Bloqueio" - }, - "Lock Screen Display": { - "Lock Screen Display": "Exibição da Tela de Boqueio" - }, - "Lock Screen Format": { - "Lock Screen Format": "Formato da Tela de Bloqueio" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Comportamento da Tela de Bloqueio" - }, - "Lock Screen layout": { - "Lock Screen layout": "Layout da Tela de Bloqueio" - }, - "Lock at startup": { - "Lock at startup": "Bloquear na inicialização" - }, - "Lock before suspend": { - "Lock before suspend": "Bloquear antes de suspender" - }, - "Lock fade grace period": { - "Lock fade grace period": "Período de carência de fade de bloqueio" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "Bloqueado" - }, - "Log Out": { - "Log Out": "Sair" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "Longo" - }, - "Long Text": { - "Long Text": "Longo Texto" - }, - "Long press": { - "Long press": "Pressionar e segurar" - }, - "Longitude": { - "Longitude": "Longitude" - }, - "Low Priority": { - "Low Priority": "Baixa Prioridade" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Certifique-se de que o KDE Connect ou Valent esteja em execução em seus outros dispositivos" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Gerencia e configure plugins para extender funcionalidades do DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Gerencie até 4 configurações de barras independentes. Cada barra possui sua própria posição, widgets, estilo e atribuição de telas." - }, - "Management": { - "Management": "Gerenciamento" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "Substituições de Layout MangoWC" - }, - "Manual": { - "Manual": "Manual" - }, - "Manual Coordinates": { - "Manual Coordinates": "Coordenadas Manuais" - }, - "Manual Direction": { - "Manual Direction": "Direção Manual" - }, - "Manual Gap Size": { - "Manual Gap Size": "Espaçamento Manual" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Mostrar/Esconder Manualmente" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Mapear nomes de classe de janela para nomes de ícones para exibição adequada do ícone" - }, - "Margin": { - "Margin": "Margem" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Suprimento Vazio" - }, - "Marker Supply Low": { - "Marker Supply Low": "Suprimento Baixo" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Coletor de Resíduos Quase Cheio" - }, - "Marker Waste Full": { - "Marker Waste Full": "Coletor de Resíduos Cheio" - }, - "Match Criteria": { - "Match Criteria": "Critérios de Correspondência" - }, - "Matches profile: %1": { - "Matches profile: %1": "Perfil correspondente: %1" - }, - "Material Colors": { - "Material Colors": "Cores Material" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Temas de cor inspirados no Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Cores materiais geradas a partir do papel de parede" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen Ausente" - }, - "Matugen Palette": { - "Matugen Palette": "Paleta Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Monitor-alvo do Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Templates do Matugen" - }, - "Max Edges": { - "Max Edges": "Bordas Máximas" - }, - "Max H": { - "Max H": "Altura Máx" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Máximo de Aplicativos Fixados" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Máximo de Aplicativos Fixados (0 = Ilimitado)" - }, - "Max Running Apps": { - "Max Running Apps": "Máximo de Aplicativos em Execução" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Máximo de Aplicativos em Execução (0 = Ilimitado)" - }, - "Max Volume": { - "Max Volume": "Volume Máximo" - }, - "Max W": { - "Max W": "Largura Máx" - }, - "Max apps to show": { - "Max apps to show": "Máximo de apps para mostrar" - }, - "Max to Edges": { - "Max to Edges": "Máximo nas Bordas" - }, - "Maximize": { - "Maximize": "Maximizar" - }, - "Maximize Detection": { - "Maximize Detection": "Detecção de Maximizado" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Maximizar Ícones de Widgets" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Maximizar Texto de Widgets" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Tamanho Máximo de Entrada" - }, - "Maximum History": { - "Maximum History": "Histórico Máximo" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Máximo de Entradas Fixadas" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Número máximo de entradas da área de transferência para guardar" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Número máximo de entradas que podem ser salvas" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Número máximo de notificações para manter" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Máximo de entradas fixadas alcançado" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Tamanho máximo por entrada da área de transferência" - }, - "Media": { - "Media": "Mídia" - }, - "Media Controls": { - "Media Controls": "Controles de Mídia" - }, - "Media Empty": { - "Media Empty": "Sem Papel" - }, - "Media Jam": { - "Media Jam": "Papel Atolado" - }, - "Media Low": { - "Media Low": "Papel Baixo" - }, - "Media Needed": { - "Media Needed": "Papel Necessário" - }, - "Media Playback": { - "Media Playback": "Reprodução de Mídia" - }, - "Media Player": { - "Media Player": "Reprodutor de Mídia" - }, - "Media Player Settings": { - "Media Player Settings": "Configurações do Reprodutor de Mídia" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "Reprodutores de Mídia(" - }, - "Media Volume": { - "Media Volume": "Volume de Mídia" - }, - "Medium": { - "Medium": "Médio" - }, - "Memory": { - "Memory": "Memória" - }, - "Memory Graph": { - "Memory Graph": "Gráfico de Memória" - }, - "Memory Usage": { - "Memory Usage": "Uso de Memória" - }, - "Memory usage indicator": { - "Memory usage indicator": "Indicador de uso de memória" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Mensagem" - }, - "Message Content": { - "Message Content": "Conteúdo da Mensagem" - }, - "Microphone": { - "Microphone": "Microfone" - }, - "Microphone Mute": { - "Microphone Mute": "Mutar Microfone" - }, - "Microphone Volume": { - "Microphone Volume": "Volume do Microfone" - }, - "Microphone settings": { - "Microphone settings": "Configurações de microfone" - }, - "Microphone volume control": { - "Microphone volume control": "Controle de volume de microfone" - }, - "Middle Section": { - "Middle Section": "Seção do Meio" - }, - "Min H": { - "Min H": "Altura Mín" - }, - "Min W": { - "Min W": "Largura Mín" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Paleta mínima construída ao redor de um único tom." - }, - "Minute": { - "Minute": "Minuto" - }, - "Mirror Display": { - "Mirror Display": "Espelhar Exibição" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Variáveis de Ambiente Ausentes" - }, - "Modal Background": { - "Modal Background": "Fundo Modal" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "Modais" - }, - "Mode": { - "Mode": "Modo" - }, - "Mode:": { - "Mode:": "Modo:" - }, - "Model": { - "Model": "Modelo" - }, - "Modified": { - "Modified": "Modificado" - }, - "Modular widget bar": { - "Modular widget bar": "Barra de widgets modular" - }, - "Monitor": { - "Monitor": "Monitor" - }, - "Monitor Configuration": { - "Monitor Configuration": "Configuração de Monitor" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Período de carência de fade do monitor" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Monitor o qual papel de parede controla cores de tema dinâmicas" - }, - "Monochrome": { - "Monochrome": "Monocromático" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "Fonte Mono espaço" - }, - "Month Date": { - "Month Date": "Mês Data" - }, - "Morning": { - "Morning": "Manhã" - }, - "Mount Points": { - "Mount Points": "Pontos de Montagem" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Aparência do ponteiro do mouse" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Tamanho do ponteiro do mouse em pixels" - }, - "Move": { - "Move": "Mover" - }, - "Move Widget": { - "Move Widget": "Mover Widget" - }, - "Moving to Paused": { - "Moving to Paused": "Movendo para Pausado" - }, - "Multi-Monitor": { - "Multi-Monitor": "Multi-Monitor" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "Música" - }, - "Mute Popups": { - "Mute Popups": "Silenciar Popups" - }, - "Mute popups for %1": { - "Mute popups for %1": "Silenciar popups para %1" - }, - "Muted": { - "Muted": "Silenciado" - }, - "Muted Apps": { - "Muted Apps": "Aplicativos Silenciados" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Paleta suave com tons sutis e calmantes." - }, - "NM not supported": { - "NM not supported": "NM não suportado" - }, - "Name": { - "Name": "Nome" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Ícones de Áreas de Trabalho Nomeadas" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "Navegação" - }, - "Network": { - "Network": "Rede" - }, - "Network Graph": { - "Network Graph": "Gráfico de Rede" - }, - "Network Info": { - "Network Info": "Informação de Rede" - }, - "Network Information": { - "Network Information": "Informações de Rede" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Nome da Rede (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Monitor de Velocidade da Rede" - }, - "Network Status": { - "Network Status": "Status da Rede" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Monitor de velocidades de download e upload da rede" - }, - "Neutral": { - "Neutral": "Neutro" - }, - "Never": { - "Never": "Nunca" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "Novo" - }, - "New Key": { - "New Key": "Nova Tecla" - }, - "New Keybind": { - "New Keybind": "Novo Atalho" - }, - "New Notification": { - "New Notification": "Nova Notificação" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "Nova Regra de Janela" - }, - "New York, NY": { - "New York, NY": "Nova York, NY" - }, - "New group name...": { - "New group name...": "Novo nome de grupo..." - }, - "Next": { - "Next": "Próximo" - }, - "Next Transition": { - "Next Transition": "Próxima Transição" - }, - "Night": { - "Night": "Noite" - }, - "Night Mode": { - "Night Mode": "Modo Noturno" - }, - "Night Temperature": { - "Night Temperature": "Temperatura Noturna" - }, - "Night mode & gamma": { - "Night mode & gamma": "Modo noturno e gama" - }, - "Niri Integration": { - "Niri Integration": "Integração com niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Substituições de Layout do Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Ações do compositor Niri (focar, mover, etc.)" - }, - "No": { - "No": "Não" - }, - "No Active Players": { - "No Active Players": "Sem Tocadores Ativos" - }, - "No Anim": { - "No Anim": "Sem Animação" - }, - "No Background": { - "No Background": "Sem fundo" - }, - "No Battery": { - "No Battery": "Sem Bateria" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Adaptador Bluetooth não encontrado" - }, - "No Blur": { - "No Blur": "Sem Desfoque" - }, - "No Border": { - "No Border": "Sem Borda" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Nenhum atalho DMS configurado" - }, - "No Dim": { - "No Dim": "Sem Escurecimento" - }, - "No Focus": { - "No Focus": "Sem Foco" - }, - "No GPU detected": { - "No GPU detected": "Nenhuma GPU detectada" - }, - "No GPUs detected": { - "No GPUs detected": "Nenhuma GPU detectada" - }, - "No History": { - "No History": "Sem Histórico" - }, - "No Media": { - "No Media": "Sem Mídia" - }, - "No Round": { - "No Round": "Sem Arredondamento" - }, - "No Rounding": { - "No Rounding": "Sem Arredondamento" - }, - "No Shadow": { - "No Shadow": "Sem Sombra" - }, - "No VPN profiles": { - "No VPN profiles": "Sem perfis de VPN" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "Sem Dados Meteorológicos" - }, - "No Weather Data Available": { - "No Weather Data Available": "Informações de Clima não dispóniveis" - }, - "No action": { - "No action": "Nenhuma ação" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "Sem adaptador" - }, - "No adapters": { - "No adapters": "Sem adaptadores" - }, - "No app customizations.": { - "No app customizations.": "Sem personalizações de aplicativo." - }, - "No apps found": { - "No apps found": "Nenhum aplicativo encontrado" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Nenhum aplicativo foi iniciado ainda." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Nenhum aplicativo silenciado. Clique com o botão direito em uma notificação e escolha \"Silenciar popups\" para adicionar um aqui." - }, - "No battery": { - "No battery": "Sem bateria" - }, - "No brightness devices available": { - "No brightness devices available": "Nenhum dispositivo de brilho disponível" - }, - "No changes": { - "No changes": "Nenhuma alteração" - }, - "No checks passed": { - "No checks passed": "Nenhuma verificação passou" - }, - "No custom theme file": { - "No custom theme file": "Nenhum arquivo de tema personalizado" - }, - "No devices": { - "No devices": "Sem dispositivos" - }, - "No devices connected": { - "No devices connected": "Nenhum dispositivo conectado" - }, - "No devices found": { - "No devices found": "Nenhum dispositivo encontrado" - }, - "No disk data": { - "No disk data": "Sem dados de disco" - }, - "No disk data available": { - "No disk data available": "Nenhum dado de disco disponível" - }, - "No drivers found": { - "No drivers found": "Nenhum driver encontrado" - }, - "No errors": { - "No errors": "Sem erros" - }, - "No features enabled": { - "No features enabled": "Nenhum recurso ativado" - }, - "No files found": { - "No files found": "Nenhum arquivo encontrado" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "Nenhuma pasta encontrada" - }, - "No hidden apps.": { - "No hidden apps.": "Sem aplicativos ocultos." - }, - "No info items": { - "No info items": "Nenhum item de informação" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "Sem dispositivo de entrada" - }, - "No input devices found": { - "No input devices found": "Nenhum dispositivo de entrada encontrado" - }, - "No items added yet": { - "No items added yet": "Nenhum item adicionado" - }, - "No keybinds found": { - "No keybinds found": "Nenhum atalho encontrado" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Nenhum plugin de launcher instalado." - }, - "No match criteria": { - "No match criteria": "Sem critérios de correspondência" - }, - "No matches": { - "No matches": "Nenhuma correspondência" - }, - "No matching processes": { - "No matching processes": "Nenhum processo correspondente" - }, - "No monitors": { - "No monitors": "Sem monitores" - }, - "No mount points found": { - "No mount points found": "Nenhum ponto de montagem encontrado" - }, - "No output device": { - "No output device": "Sem dispositivo de saída" - }, - "No output devices found": { - "No output devices found": "Nenhum dispositivo de saída encontrado" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "Sem resultados de plugin" - }, - "No plugins found": { - "No plugins found": "Nenhum plugin encontrado" - }, - "No plugins found.": { - "No plugins found.": "Nenhum plugin encontrado." - }, - "No printer found": { - "No printer found": "Nenhuma impressora encontrada" - }, - "No printers configured": { - "No printers configured": "Nenhuma impressora configurada" - }, - "No printers found": { - "No printers found": "Nenhuma impressora encontrada" - }, - "No profiles": { - "No profiles": "Sem perfis" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Nenhuma entrada recente de área de transferência encontrada" - }, - "No results found": { - "No results found": "Nenhum resultado encontrado" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Nenhuma entrada de área de transferência salva" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "Nenhum tema encontrado" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Nenhum tema instalado. Navegue por temas para instalar do registro." - }, - "No trigger": { - "No trigger": "Sem gatilho" - }, - "No video found in folder": { - "No video found in folder": "Nenhum vídeo encontrado na pasta" - }, - "No wallpaper selected": { - "No wallpaper selected": "Nenhum papel de parede selecionado" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Nenhum papel de parede encontrado\n\nClique no ícone de pasta abaixo para navegar" - }, - "No warnings": { - "No warnings": "Sem avisos" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Nenhum widget adicionado. Clique em \"Adicionar Widget\" para começar." - }, - "No widgets available": { - "No widgets available": "Nenhum widget disponível" - }, - "No widgets match your search": { - "No widgets match your search": "Nenhum widget corresponde à sua pesquisa" - }, - "No window rules configured": { - "No window rules configured": "Nenhuma regra de janela configurada" - }, - "None": { - "None": "Nenhum" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Fonte Normal" - }, - "Normal Priority": { - "Normal Priority": "Prioridade Normal" - }, - "Not available": { - "Not available": "Indisponível" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "Não conectado" - }, - "Not detected": { - "Not detected": "Não detectado" - }, - "Not paired": { - "Not paired": "Não pareado" - }, - "Not set": { - "Not set": "Não definido" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Nota: isso apenas altera a porcentagem, não limita realmente a carga." - }, - "Notepad": { - "Notepad": "Bloco de Nota" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Configurações da Fonte do Bloco de Notas" - }, - "Notepad Slideout": { - "Notepad Slideout": "Blocos de Notas Deslizante" - }, - "Nothing": { - "Nothing": "Nada" - }, - "Nothing to see here": { - "Nothing to see here": "Nada para ver aqui" - }, - "Notification Center": { - "Notification Center": "Centro de Notificações" - }, - "Notification Display": { - "Notification Display": "Exibição de Notificação" - }, - "Notification Overlay": { - "Notification Overlay": "Sobreposição de Notificação" - }, - "Notification Popups": { - "Notification Popups": "Popups de Notificação" - }, - "Notification Rules": { - "Notification Rules": "Regras de Notificação" - }, - "Notification Settings": { - "Notification Settings": "Configurações de Notificação" - }, - "Notification Timeouts": { - "Notification Timeouts": "Tempo Máximo de Notificação" - }, - "Notification toast popups": { - "Notification toast popups": "Pop-ups de notificações toast" - }, - "Notifications": { - "Notifications": "Notificações" - }, - "Numbers": { - "Numbers": "Números" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numérico (D/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numérico (M/D)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "Logo do SO" - }, - "OSD Position": { - "OSD Position": "Posição do OSD" - }, - "Occupied Color": { - "Occupied Color": "Cor Ocupada" - }, - "Off": { - "Off": "Desligado" - }, - "Office": { - "Office": "Escritório" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Relatório Offline" - }, - "Older": { - "Older": "Mais antigas" - }, - "On": { - "On": "Ligado" - }, - "On-Demand": { - "On-Demand": "Por Demanda" - }, - "On-Screen Displays": { - "On-Screen Displays": "Displays na Tela (OSDs)" - }, - "On-screen Displays": { - "On-screen Displays": "Exibições OSD" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Apenas ajustar gama baseada em regras de tempo ou localização." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Mostrar apenas janelas do monitor atual em cada dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Apenas visível se suportado por seu sistema" - }, - "Opacity": { - "Opacity": "Opacidade" - }, - "Opaque": { - "Opaque": "Opaco" - }, - "Open": { - "Open": "Aberto" - }, - "Open App": { - "Open App": "Abrir Aplicativo" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Abra o KDE Connect em seu telefone" - }, - "Open Notepad File": { - "Open Notepad File": "Abrir Arquivo do Bloco de Notas" - }, - "Open a new note": { - "Open a new note": "Abrir uma nova nota" - }, - "Open folder": { - "Open folder": "Abrir pasta" - }, - "Open in Browser": { - "Open in Browser": "Abrir no Navegador" - }, - "Open in terminal": { - "Open in terminal": "Abrir no terminal" - }, - "Open search bar to find text": { - "Open search bar to find text": "Abrir barra de pesquisa e encontrar texto" - }, - "Open with...": { - "Open with...": "Abrir com..." - }, - "Opening SMS": { - "Opening SMS": "Abrindo SMS" - }, - "Opening SMS app": { - "Opening SMS app": "Abrindo aplicativo de SMS" - }, - "Opening file browser": { - "Opening file browser": "Abrindo navegador de arquivos" - }, - "Opening files": { - "Opening files": "Abrindo arquivos" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "Descrição opcional" - }, - "Optional location": { - "Optional location": "Localização opcional" - }, - "Options": { - "Options": "Opções" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Organizar widgets em grupos recolhíveis" - }, - "Original: %1": { - "Original: %1": "Original: %1" - }, - "Other": { - "Other": "Outro" - }, - "Outline": { - "Outline": "Contorno" - }, - "Output": { - "Output": "Saída" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Área de Saída Quase Cheia" - }, - "Output Area Full": { - "Output Area Full": "Área de Saída Cheia" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "Dispositivos de Saída" - }, - "Output Tray Missing": { - "Output Tray Missing": "Bandeja de Saída Ausente" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Incluir Saídas Ausentes" - }, - "Overcast": { - "Overcast": "Nublado" - }, - "Overflow": { - "Overflow": "Estouro" - }, - "Overridden by config": { - "Overridden by config": "Substituído pela config" - }, - "Override": { - "Override": "Sobrescrever" - }, - "Override Border Size": { - "Override Border Size": "Substituir Tamanho da Borda" - }, - "Override Corner Radius": { - "Override Corner Radius": "Sobrescrever Arredondamento" - }, - "Override Gaps": { - "Override Gaps": "Substituir Espaçamentos" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Substituir configurações de layout global para esta saída" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "Sobrescritas" - }, - "Overview": { - "Overview": "Visão Geral" - }, - "Overview of your network connections": { - "Overview of your network connections": "Visão geral das suas conexões de rede" - }, - "Overwrite": { - "Overwrite": "Sobrescrever" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Pad" - }, - "Pad Hours": { - "Pad Hours": "Adicionar Horas" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Preenchimento" - }, - "Pair": { - "Pair": "Parear" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Emparelhar Dispositivo Bluetooth" - }, - "Paired": { - "Paired": "Pareado" - }, - "Pairing": { - "Pairing": "Pareando" - }, - "Pairing failed": { - "Pairing failed": "Erro ao emparelhar" - }, - "Pairing request from": { - "Pairing request from": "Solicitação de pareamento de" - }, - "Pairing request sent": { - "Pairing request sent": "Solicitação de pareamento enviada" - }, - "Pairing requested": { - "Pairing requested": "Pareamento solicitado" - }, - "Pairing...": { - "Pairing...": "Pareando..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Parcialmente Nublado" - }, - "Passkey:": { - "Passkey:": "Chave de acesso:" - }, - "Password": { - "Password": "Senha" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "Colar" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Caminho para um arquivo de vídeo ou pasta de vídeos" - }, - "Pattern": { - "Pattern": "Padrão" - }, - "Pause": { - "Pause": "Pausar" - }, - "Paused": { - "Paused": "Pausado" - }, - "Pending": { - "Pending": "Pendente" - }, - "Pending Charge": { - "Pending Charge": "Carga Pendente" - }, - "Pending Discharge": { - "Pending Discharge": "Descarga Pendente" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Papéis de Parede por Modo" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Papéis de Parede por Monitor" - }, - "Per-screen config": { - "Per-screen config": "Configuração por tela" - }, - "Percentage": { - "Percentage": "Porcetagem" - }, - "Performance": { - "Performance": "Desempenho" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Permissão negada ao definir imagem de perfil." - }, - "Personalization": { - "Personalization": "Personalização" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Conexão de Telefone Não Disponível" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Conexão de Telefone indisponível" - }, - "Phone number": { - "Phone number": "Número de telefone" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "Imagens" - }, - "Pin": { - "Pin": "Fixar" - }, - "Pin to Dock": { - "Pin to Dock": "Fixar ao Dock" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping enviado" - }, - "Ping sent to": { - "Ping sent to": "Ping enviado para" - }, - "Pinned": { - "Pinned": "Fixado" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Aplicativos fixados e em execução com arrastar e soltar" - }, - "Pixelate": { - "Pixelate": "Pixelizar" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Use este local para os diretórios de plugin. Cada plugin deve ter um arquivo de manifesto plugin.json." - }, - "Place plugins in %1": { - "Place plugins in %1": "Coloque plugins em %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Reproduzir som ao conectar o cabo de energia" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Reproduzir som ao conectar o cabo de energia" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Reproduzir som quando o volume é ajustado" - }, - "Play sounds for system events": { - "Play sounds for system events": "Reproduzir sons para eventos do sistema" - }, - "Playback": { - "Playback": "Reprodução" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "Aguarde..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "Conectado" - }, - "Plugged in": { - "Plugged in": "Conectado" - }, - "Plugin": { - "Plugin": "Plugin" - }, - "Plugin Directory": { - "Plugin Directory": "Diretório de Plugins" - }, - "Plugin Management": { - "Plugin Management": "Gerenciamento de Plugins" - }, - "Plugin Visibility": { - "Plugin Visibility": "Visibilidade do Plugin" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Plugin está desativado - ative em configurações de Plugins para usar" - }, - "Plugins": { - "Plugins": "Plugins" - }, - "Pointer": { - "Pointer": "Ponteiro" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "Popouts" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Popouts e Modais seguem Velocidade Global de Animação (desative para personalizar independentemente)" - }, - "Popup Only": { - "Popup Only": "Apenas Popup" - }, - "Popup Position": { - "Popup Position": "Posição do Popup" - }, - "Popup Shadow": { - "Popup Shadow": "Sombra do Popup" - }, - "Popup Transparency": { - "Popup Transparency": "Transparência do Popup" - }, - "Popup behavior, position": { - "Popup behavior, position": "Comportamento de pop-up, posição" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "Portal" - }, - "Position": { - "Position": "Posição" - }, - "Position, pinned apps": { - "Position, pinned apps": "Posição, aplicativos fixados" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Possíveis Conflitos de Sobrescrita" - }, - "Power": { - "Power": "Energia" - }, - "Power & Security": { - "Power & Security": "Energia & Segurança" - }, - "Power & Sleep": { - "Power & Sleep": "Energia & Suspensão" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Confirmação de Ação de Energia" - }, - "Power Menu Customization": { - "Power Menu Customization": "Customização do Menu de Energia" - }, - "Power Off": { - "Power Off": "Desligar" - }, - "Power Options": { - "Power Options": "Opções de Energia" - }, - "Power Profile": { - "Power Profile": "Perfil de Energia" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Degradação do Perfil de Energia" - }, - "Power Saver": { - "Power Saver": "Economia de Energia" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Desligar monitores no bloqueio" - }, - "Power profile management available": { - "Power profile management available": "Gerenciamento de perfil de energia disponível" - }, - "Power source": { - "Power source": "Fonte de energia" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "Precipitação" - }, - "Precipitation": { - "Precipitation": "Precipitação" - }, - "Precipitation Chance": { - "Precipitation Chance": "Chance de Precipitação" - }, - "Preference": { - "Preference": "Preferência" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Larguras Predefinidas (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Pressione Enter e o sistema de áudio reiniciará para aplicar a mudança" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Pressione Enter para colar, Shift+Enter para copiar" - }, - "Press key...": { - "Press key...": "Pressione a tecla..." - }, - "Pressure": { - "Pressure": "Pressão" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Impedir suspensão da tela" - }, - "Preview": { - "Preview": "Pré-visualização" - }, - "Primary": { - "Primary": "Primário" - }, - "Primary Container": { - "Primary Container": "Contêiner Primário" - }, - "Print Server Management": { - "Print Server Management": "Gerenciamento do Servidor de Impressão" - }, - "Print Server not available": { - "Print Server not available": "Servidor de Impressão indisponível" - }, - "Printer": { - "Printer": "Impressora" - }, - "Printer Classes": { - "Printer Classes": "Classes de Impressoras" - }, - "Printer created successfully": { - "Printer created successfully": "Impressora criada com sucesso" - }, - "Printer deleted": { - "Printer deleted": "Impressora excluída" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Nome da impressora (sem espaços)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "Impressoras" - }, - "Printers: ": { - "Printers: ": "Impressoras: " - }, - "Prioritize performance": { - "Prioritize performance": "Priorizar desempenho" - }, - "Priority": { - "Priority": "Prioridade" - }, - "Privacy Indicator": { - "Privacy Indicator": "Indicador de Privacidade" - }, - "Privacy Mode": { - "Privacy Mode": "Modo de Privacidade" - }, - "Private Key Password": { - "Private Key Password": "Senha da Chave Privada" - }, - "Process Count": { - "Process Count": "Contador de Processos" - }, - "Processes": { - "Processes": "Processos" - }, - "Processes:": { - "Processes:": "Processos:" - }, - "Processing": { - "Processing": "Processando" - }, - "Profile Image Error": { - "Profile Image Error": "Erro da Imagem de Perfil" - }, - "Profile activated: %1": { - "Profile activated: %1": "Perfil ativado: %1" - }, - "Profile deleted": { - "Profile deleted": "Perfil excluído" - }, - "Profile error": { - "Profile error": "Erro de perfil" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "A imagem de perfil é muito grande. Por favor use uma imagem menor." - }, - "Profile name": { - "Profile name": "Nome do Perfil" - }, - "Profile not found": { - "Profile not found": "Perfil não encontrado" - }, - "Profile saved: %1": { - "Profile saved: %1": "Perfil salvo: %1" - }, - "Protocol": { - "Protocol": "Protocolo" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia não está disponível" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "Acesso Rápido" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Acesso rápido ao lançador de aplicativos" - }, - "Quick access to color picker": { - "Quick access to color picker": "Acesso rápido ao seletor de cores" - }, - "Quick access to notepad": { - "Quick access to notepad": "Acesso rápido ao bloco de notas" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Painel deslizante para anotações rápidas" - }, - "Quick system toggles": { - "Quick system toggles": "Alternadores rápidos do sistema" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Raio" - }, - "Rain": { - "Rain": "Chuva" - }, - "Rain Chance": { - "Rain Chance": "Chance de Chuva" - }, - "Rainbow": { - "Rainbow": "Arco-íris" - }, - "Random": { - "Random": "Aleatório" - }, - "Rate": { - "Rate": "Taxa" - }, - "Read:": { - "Read:": "Leitura:" - }, - "Reason": { - "Reason": "Razão" - }, - "Reboot": { - "Reboot": "Reiniciar" - }, - "Recent Colors": { - "Recent Colors": "Cores Recentes" - }, - "Recently Used Apps": { - "Recently Used Apps": "Apps Usados Recentemente" - }, - "Recommended available": { - "Recommended available": "Recomendado disponível" - }, - "Refresh": { - "Refresh": "Recarregar" - }, - "Refresh Weather": { - "Refresh Weather": "Atualizar Clima" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Rejeitar" - }, - "Reject Jobs": { - "Reject Jobs": "Rejeitar Trabalhos" - }, - "Release": { - "Release": "Soltar" - }, - "Reload Plugin": { - "Reload Plugin": "Reiniciar Plugin" - }, - "Remaining": { - "Remaining": "Restante" - }, - "Remaining / Total": { - "Remaining / Total": "Restante / Total" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "Lembrar última sessão" - }, - "Remember last user": { - "Remember last user": "Lembrar último usuário" - }, - "Remove": { - "Remove": "Remover" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Remover Preenchimento de Widgets" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Remover espaçámentos e borda quando janelas estão maximizadas" - }, - "Rename": { - "Rename": "Renomear" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "Renomear Espaço de Trabalho" - }, - "Repeat": { - "Repeat": "Repetir" - }, - "Replacement": { - "Replacement": "Substituição" - }, - "Report": { - "Report": "Relatório" - }, - "Request Pairing": { - "Request Pairing": "Solicitar Pareamento" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Exigir manter o botão/tecla pressionado para confirmar desligamento, reinicialização, suspensão, hibernação e encerramento de sessão" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "Requer %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Requer ferramenta 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "Requer DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Requer o compositor DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Requer suporte a modo noturno" - }, - "Reset": { - "Reset": "Resetar" - }, - "Reset Position": { - "Reset Position": "Restaurar Posição" - }, - "Reset Size": { - "Reset Size": "Restaurar Tamanho" - }, - "Reset to default name": { - "Reset to default name": "Redefinir para o nome padrão" - }, - "Resize Widget": { - "Resize Widget": "Redimensionar Widget" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Resolução & Taxa de Atualização" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Resolução, posição, escala" - }, - "Restart DMS": { - "Restart DMS": "Reiniciar DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Reinicie o DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Reiniciando sistema de áudio..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Resumir" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Inverter Direção do Scroll" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Inverter direção de troca de área de trabalho ao rolar sobre a barra" - }, - "Revert": { - "Revert": "Reverter" - }, - "Right": { - "Right": "Direita" - }, - "Right Center": { - "Right Center": "Centro Direito" - }, - "Right Section": { - "Right Section": "Seção da Direita" - }, - "Right Tiling": { - "Right Tiling": "Tiling na Direita" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Clique-Direto e arrastar em qualquer lugar do widget" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Clique-Direito e arrastar no canto inferior direito" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Clique no widget com o botão direito para alternar" - }, - "Ring": { - "Ring": "Tocar" - }, - "Ringing": { - "Ringing": "Tocando" - }, - "Ripple Effects": { - "Ripple Effects": "Efeitos de Ondulação" - }, - "Root Filesystem": { - "Root Filesystem": "Sistema de Arquivos Raiz" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Cantos arredondados para janelas" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Cantos arredondados para janelas (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Cantos arredondados para janelas (decoration.rounding)" - }, - "Rule": { - "Rule": "Regra" - }, - "Rule Name": { - "Rule Name": "Nome da Regra" - }, - "Rules (%1)": { - "Rules (%1)": "Regras (%1)" - }, - "Run Again": { - "Run Again": "Executar Novamente" - }, - "Run DMS Templates": { - "Run DMS Templates": "Rodar templates do DMS" - }, - "Run User Templates": { - "Run User Templates": "Executar Templates do Usuário" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Rodar um programa (ex. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Rodar um comando do shell (ex. notify-send)" - }, - "Running Apps": { - "Running Apps": "Apps Em Execução" - }, - "Running Apps Settings": { - "Running Apps Settings": "Configurações de Apps em Execução" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "Brilho SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Saturação SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Salvar" - }, - "Save Notepad File": { - "Save Notepad File": "Salvar Arquivo do Bloco de Notas" - }, - "Save QR Code": { - "Save QR Code": "Salvar Código QR" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Salvar e alternar entre configurações de exibição" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Salvar notificações de prioridade crítica no histórico" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Salvar notificações descartadas no histórico" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Salvar notificações de baixa prioridade no histórico" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Salvar notificações de prioridade normal no histórico" - }, - "Save password": { - "Save password": "Salvar senha" - }, - "Saved": { - "Saved": "Salvo" - }, - "Saved Configurations": { - "Saved Configurations": "Configurações Salvas" - }, - "Saved Note": { - "Saved Note": "Nota Salva" - }, - "Saved item deleted": { - "Saved item deleted": "Item salvo excluído" - }, - "Saving...": { - "Saving...": "Salvando..." - }, - "Scale": { - "Scale": "Escala" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Ajustar tamanho da fonte da DankBar de forma independente" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "Escalar tamanhos de ícones da DankBar independentemente" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Ajuste todos os tamanhos de fonte em todo o shell" - }, - "Scan": { - "Scan": "Escanear" - }, - "Scanning": { - "Scanning": "Scanning" - }, - "Scanning...": { - "Scanning...": "Escaneando..." - }, - "Science": { - "Science": "Ciência" - }, - "Score": { - "Score": "Pontuação" - }, - "Screen Sharing": { - "Screen Sharing": "Compartilhamento de Tela" - }, - "Screen sharing": { - "Screen sharing": "Compartilhamento de tela" - }, - "Scroll": { - "Scroll": "Rolagem" - }, - "Scroll Factor": { - "Scroll Factor": "Fator de Rolagem" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Roda de Rolagem" - }, - "Scroll song title": { - "Scroll song title": "Scrollar título da música" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Rolar título se não couber no widget" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Comportamento da roda de rolagem no widget de mídia" - }, - "Scrolling": { - "Scrolling": "Scrolling" - }, - "Search App Actions": { - "Search App Actions": "Pesquisar Ações do Aplicativo" - }, - "Search Options": { - "Search Options": "Opções de Pesquisa" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Buscar por combinação de teclas, descrição ou nome de ação.\n\nA ação padrão copia o atalho para a área de transferência.\nClique com o botão direito ou pressione Seta para a Direita para fixar atalhos usados com frequência - eles aparecerão no topo quando não estiver pesquisando." - }, - "Search for a location...": { - "Search for a location...": "Procurar um local..." - }, - "Search keybinds...": { - "Search keybinds...": "Pesquisar atalhos..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Pesquisar atalhos de teclado do seu compositor e aplicativos" - }, - "Search plugins...": { - "Search plugins...": "Buscar plugins..." - }, - "Search processes...": { - "Search processes...": "Buscar processos..." - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "Pesquisar temas..." - }, - "Search widgets...": { - "Search widgets...": "Procurar widgets..." - }, - "Search...": { - "Search...": "Buscar..." - }, - "Searching...": { - "Searching...": "Pesquisando..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "Secundário" - }, - "Secured": { - "Secured": "Seguro" - }, - "Security": { - "Security": "Segurança" - }, - "Security & privacy": { - "Security & privacy": "Segurança e privacidade" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "Selecionar" - }, - "Select Application": { - "Select Application": "Selecionar Aplicação" - }, - "Select Bar": { - "Select Bar": "Selecionar Barra" - }, - "Select Custom Theme": { - "Select Custom Theme": "Selecionar Tema Customizado" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Selecionar Logo do Lançador de Dock" - }, - "Select File to Send": { - "Select File to Send": "Selecionar Arquivo para Enviar" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Selecionar Logo do Lançador" - }, - "Select Profile Image": { - "Select Profile Image": "Selecionar Imagem de Perfil" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "Selecionar Papel de Parede" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Selecionar Diretório de Papéis de Parede" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Escolha uma cor na paleta ou use controles deslizantes" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Selecione um widget para adicionar à sua área de trabalho. Cada widget é uma instância separada com suas próprias configurações." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Selecione um widget para adicionar. Você pode adicionar múltiplas instâncias do mesmo wiget caso necessário." - }, - "Select a window...": { - "Select a window...": "Selecionar uma janela..." - }, - "Select an image file...": { - "Select an image file...": "Selecione um arquivo de imagem..." - }, - "Select at least one provider": { - "Select at least one provider": "Selecione pelo menos um provedor" - }, - "Select device": { - "Select device": "Selecionar dispositivo" - }, - "Select device...": { - "Select device...": "Selecionar dispositivo..." - }, - "Select driver...": { - "Select driver...": "Selecionar driver..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Selecione a espessura da fonte para o texto da UI" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Selecionar monitor para configurar papel de parede" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Selecionar fonte monoespaçada para a lista de processos e telas técnicas" - }, - "Select network": { - "Select network": "Selecionar rede" - }, - "Select system sound theme": { - "Select system sound theme": "Selecionar tema do som do sistema" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Selecione a família de fontes para o texto da UI" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Selecione o algoritmo usado para cores baseadas no papel de parede" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Selecionar quais provedores de combinações de teclas incluir" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Selecionar quais transições incluir na randomização" - }, - "Select...": { - "Select...": "Selecionar..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Imagem selecionada não encontrada." - }, - "Send": { - "Send": "Enviar" - }, - "Send Clipboard": { - "Send Clipboard": "Enviar Área de Transferência" - }, - "Send File": { - "Send File": "Enviar Arquivo" - }, - "Send SMS": { - "Send SMS": "Enviar SMS" - }, - "Sending": { - "Sending": "Enviando" - }, - "Separator": { - "Separator": "Separador" - }, - "Server": { - "Server": "Servidor" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Definir Nome de Dispositivo Personalizado" - }, - "Set custom name": { - "Set custom name": "Definir nome personalizado" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Definir nomes personalizados para seus dispositivos de entrada de áudio" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Definir nomes personalizados para seus dispositivos de saída de áudio" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Use papéis de paredes diferentes para cada monitor conectado" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Use papéis de parede diferentes para modos claro e escuro" - }, - "Set key and action to save": { - "Set key and action to save": "Definir chave e ação para salvar" - }, - "Set notification rules": { - "Set notification rules": "Definir regras de notificação" - }, - "Settings": { - "Settings": "Configurações" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Configurações são somente leitura. Mudanças não serão mantidas." - }, - "Setup": { - "Setup": "Configurar" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "Compartilhar" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Compartilhar Configurações de Controle Gamma" - }, - "Share Text": { - "Share Text": "Compartilhar Texto" - }, - "Share URL": { - "Share URL": "Compartilhar URL" - }, - "Shared": { - "Shared": "Compartilhado" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Apagar tudo • Esc: Fechar" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter para colar" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Copiar • Shift+Del: Limpar Tudo • Esc: Fechar" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Colar • Shift+Del: Limpar Tudo • Esc: Fechar" - }, - "Short": { - "Short": "Curto" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "Atalhos" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Atalhos (%1)" - }, - "Show": { - "Show": "Mostrar" - }, - "Show 3rd Party": { - "Show 3rd Party": "Mostrar Terceiros" - }, - "Show All Tags": { - "Show All Tags": "Mostrar Todas as Tags" - }, - "Show Badge": { - "Show Badge": "Mostrar Distintivo" - }, - "Show CPU": { - "Show CPU": "Mostrar CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Mostrar Gráfico de CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Mostrar Temperatura da CPU" - }, - "Show Date": { - "Show Date": "Mostrar Data" - }, - "Show Disk": { - "Show Disk": "Mostrar Disco" - }, - "Show Dock": { - "Show Dock": "Mostrar Dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Mostrar Temperatura Aparente" - }, - "Show Footer": { - "Show Footer": "Mostrar Rodapé" - }, - "Show Forecast": { - "Show Forecast": "Mostrar Previsão" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Mostrar Temperatura da GPU" - }, - "Show Header": { - "Show Header": "Mostrar Cabeçalho" - }, - "Show Hibernate": { - "Show Hibernate": "Mostrar Hibernar" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Mostrar Números das Horas" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Mostrar Previsão Horária" - }, - "Show Humidity": { - "Show Humidity": "Mostrar Umidade" - }, - "Show Launcher Button": { - "Show Launcher Button": "Mostrar Botão do Launcher" - }, - "Show Line Numbers": { - "Show Line Numbers": "Mostrar Numeração de Linha" - }, - "Show Location": { - "Show Location": "Mostrar Localização" - }, - "Show Lock": { - "Show Lock": "Mostrar Bloquear" - }, - "Show Log Out": { - "Show Log Out": "Mostrar Sair" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Mostrar animações de ondulação Material Design em elementos interativos" - }, - "Show Media Player": { - "Show Media Player": "Mostrar Reprodutor de Mídia" - }, - "Show Memory": { - "Show Memory": "Mostrar Memória" - }, - "Show Memory Graph": { - "Show Memory Graph": "Mostrar Gráfico de Memória" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "Mostrar Rede" - }, - "Show Network Graph": { - "Show Network Graph": "Mostrar Gráfico de Rede" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Mostrar Apenas Workspaces Ocupadas" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Mostrar Contagem de Distintivo de Estouro" - }, - "Show Password Field": { - "Show Password Field": "Mostrar Campo de Senha" - }, - "Show Power Actions": { - "Show Power Actions": "Mostrar Ações de Energia" - }, - "Show Power Off": { - "Show Power Off": "Mostra Desligar" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Mostrar Probabilidade de Precipitação" - }, - "Show Pressure": { - "Show Pressure": "Mostrar Pressão" - }, - "Show Profile Image": { - "Show Profile Image": "Mostrar Imagem de Perfil" - }, - "Show Reboot": { - "Show Reboot": "Mostrar Reiniciar" - }, - "Show Restart DMS": { - "Show Restart DMS": "Mostrar Reiniciar DMS" - }, - "Show Saved Items": { - "Show Saved Items": "Mostrar Itens Salvos" - }, - "Show Seconds": { - "Show Seconds": "Mostrar Segundos" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Mostrar Nascer/Pôr do Sol" - }, - "Show Suspend": { - "Show Suspend": "Mostrar Suspender" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "Mostrar Data do Sistema" - }, - "Show System Icons": { - "Show System Icons": "Exibir Ícones do Sistema" - }, - "Show System Time": { - "Show System Time": "Exibir Hora do Sistema" - }, - "Show Top Processes": { - "Show Top Processes": "Mostrar Processos Principais" - }, - "Show Weather Condition": { - "Show Weather Condition": "Mostrar Condição do Tempo" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "Mostrar Boas-vindas" - }, - "Show Wind Speed": { - "Show Wind Speed": "Mostrar Velocidade do Vento" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Mostrar Aplicativos da Área de Trabalho Virtual" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Mostrar todas as 9 tags ao invés de apenas tags ocupadas (apenas DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Mostrar um anel de contorno ao redor do indicador de espaço de trabalho em foco" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Exibir a visualização cava no widget de mídia" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Exibir sobreposição escurecida atrás de diálogos modais" - }, - "Show device": { - "Show device": "Mostrar dispositivo" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Mostrar dock quando janelas flutuantes não se sobrepõem à sua área" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Mostrar sobreposição do iniciador ao digitar na visão geral do Niri. Desative para usar outro iniciador." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Mostrar guias de modo e dicas de teclado na parte inferior." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Mostrar na Última Tela" - }, - "Show on Overlay": { - "Show on Overlay": "Mostrar na Sobreposição" - }, - "Show on Overview": { - "Show on Overview": "Mostrar na Visão Geral" - }, - "Show on Overview Only": { - "Show on Overview Only": "Mostrar Apenas na Visão Geral" - }, - "Show on all connected displays": { - "Show on all connected displays": "Mostrar em todas as telas conectadas" - }, - "Show on screens:": { - "Show on screens:": "Mostrar nas telas:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Mostrar aviso na tela quando o brilho muda" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Mostrar aviso na tela quando o estado do caps lock muda" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Mostrar aviso na tela ao alternar dispositivos de saída de áudio" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Mostrar aviso na tela quando o estado do inibidor de ociosidade mudar" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Mostrar exibição na tela quando o status do reprodutor de mídia mudar" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Mostrar aviso na tela quando o volume do reprodutor de mídia mudar" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Mostrar aviso na tela quando o microfone for mutado/desmutado" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Mostrar aviso na tela quando o perfil de energia mudar" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Mostrar aviso na tela quando o volume mudar" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Mostrar informação de clima na barra superior e na central de controle" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Mostrar números de índice das áreas de trabalho no seletor de áreas de trabalho" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Mostrar nome da área de trabalho em barras horizontais, e primeira letra em barras verticais" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Mostrar espaços de trabalho do monitor atualmente em foco" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Mostra todos os aplicativos em execução, destacando o que está em foco" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Mostra a área de trabalho atual e permite alternar entre elas" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Mostra quando caps lock está ativo" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Mostra quando microfone, câmera, ou compartilhamento de tela está ativado" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Desligar" - }, - "Signal": { - "Signal": "Sinal" - }, - "Signal:": { - "Signal:": "Sinal:" - }, - "Size": { - "Size": "Tamanho" - }, - "Size Constraints": { - "Size Constraints": "Restrições de Tamanho" - }, - "Size Offset": { - "Size Offset": "Ajuste de Tamanho" - }, - "Sizing": { - "Sizing": "Tamanhos" - }, - "Skip": { - "Skip": "Pular" - }, - "Skip confirmation": { - "Skip confirmation": "Pular confirmação" - }, - "Skip setup": { - "Skip setup": "Pular configuração" - }, - "Small": { - "Small": "Pequeno" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Autenticação de Cartão Inteligente" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN do Cartão Inteligente" - }, - "Snap": { - "Snap": "Encaixar" - }, - "Snow": { - "Snow": "Neve" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Alguns plugins requerem uma versão mais recente do DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Ordenar Alfabeticamente" - }, - "Sort By": { - "Sort By": "Ordenar Por" - }, - "Sorting & Layout": { - "Sorting & Layout": "Classificação e Layout" - }, - "Sound Theme": { - "Sound Theme": "Tema do Som" - }, - "Sounds": { - "Sounds": "Sons" - }, - "Space between windows": { - "Space between windows": "Espaço entre janelas" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Espaço entre janelas (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Espaço entre janelas (gaps_in e gaps_out)" - }, - "Spacer": { - "Spacer": "Espaçador" - }, - "Spacing": { - "Spacing": "Espaçamento" - }, - "Speaker settings": { - "Speaker settings": "Configurações de alto-falante" - }, - "Speed": { - "Speed": "Velocidade" - }, - "Spool Area Full": { - "Spool Area Full": "Área de Spool Cheia" - }, - "Square Corners": { - "Square Corners": "Cantos Retos" - }, - "Stacked": { - "Stacked": "Empilhado" - }, - "Standard": { - "Standard": "Padrão" - }, - "Start": { - "Start": "Iniciar" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Iniciar KDE Connect ou Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Inicie o KDE Connect ou Valent para usar este plugin" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Comece a digitar suas anotações aqui..." - }, - "State": { - "State": "Estado" - }, - "Status": { - "Status": "Status" - }, - "Stopped": { - "Stopped": "Parado" - }, - "Stopped Partly": { - "Stopped Partly": "Parado Parcialmente" - }, - "Stopping": { - "Stopping": "Parando" - }, - "Stretch": { - "Stretch": "Esticar" - }, - "Stripes": { - "Stripes": "Listras" - }, - "Summary": { - "Summary": "Resumo" - }, - "Sunrise": { - "Sunrise": "Nascer do Sol" - }, - "Sunset": { - "Sunset": "Pôr do Sol" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Suprimir pop-ups de notificação enquanto ativado" - }, - "Surface": { - "Surface": "Superfície" - }, - "Surface Variant": { - "Surface Variant": "Variante de Superfície" - }, - "Suspend": { - "Suspend": "Suspender" - }, - "Suspend behavior": { - "Suspend behavior": "Comportamento de suspensão" - }, - "Suspend system after": { - "Suspend system after": "Suspender sitema após" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Suspender e Hibernar" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "Trocar Usuário" - }, - "Switch to power profile": { - "Switch to power profile": "Trocar para perfil de energia" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Sincronizar Modo Com Portal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Sincronizar Popouts & Modais" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Sincronizar Posição entre Telas" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Sincronize o modo escuro com os portais de configurações para ter indicações de temas em todo o sistema" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "Sistema" - }, - "System App Theming": { - "System App Theming": "Tema de Apps do Sistema" - }, - "System Check": { - "System Check": "Verificação do Sistema" - }, - "System Default": { - "System Default": "Padrão do Sistema" - }, - "System Information": { - "System Information": "Informações do Sistema" - }, - "System Monitor": { - "System Monitor": "Monitor do Sistema" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Monitor do Sistema Indisponível" - }, - "System Sounds": { - "System Sounds": "Sons do Sistema" - }, - "System Tray": { - "System Tray": "Bandeja do Sistema" - }, - "System Update": { - "System Update": "Atualização do Sistema" - }, - "System Updater": { - "System Updater": "Atualizador do Sistema" - }, - "System Updates": { - "System Updates": "Atualizações do Sistema" - }, - "System notification area icons": { - "System notification area icons": "Área de ícones de notificações do sistema" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Os sons do sistema não estão disponíveis. Instale %1 para suporte de som." - }, - "System theme toggle": { - "System theme toggle": "Alternar tema do sistema" - }, - "System toast notifications": { - "System toast notifications": "Notificações toast do sistema" - }, - "System update custom command": { - "System update custom command": "Comando personalizado para atualização do sistema" - }, - "Tab": { - "Tab": "Aba" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Navegação • ←→↑↓: Navegação em Grade • Enter/Espaço: Selecionar" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Parâmetros adicionais para o terminal" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminais - Sempre usar Tema Escuro" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "Página de Testes" - }, - "Test page sent to printer": { - "Test page sent to printer": "Página de testes enviada para a impressora" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "Texto" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "A ferramenta 'dgop' é necessária para monitoramento do sistema.\nPor favor, instale o dgop para usar este recurso." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "A variável de ambiente DMS_SOCKET não está definida ou o socket está indisponível. O gerenciamento automático de plugins requer a DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "As configurações abaixo vão modificar suas configurações GTK e Qt. Se você deseja preservá-las, por favor faça um back up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "A fila de trabalhos dessa impressora está vazia" - }, - "Theme & Colors": { - "Theme & Colors": "Tema & Cores" - }, - "Theme Color": { - "Theme Color": "Cor do Tema" - }, - "Theme Registry": { - "Theme Registry": "Registro de Tema" - }, - "Themes": { - "Themes": "Temas" - }, - "Thickness": { - "Thickness": "Espessura" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Aviso Sobre Plugins de Terceiros" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Plugins de terceiros são criados pela comunidade e não são oficialmente suportados pelo DankMaterialShell.\n\nEstes plugins podem representar riscos de segurança e privacidade - instale por sua conta e risco." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Esta vinculação é substituída pela configuração do config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Isso pode levar alguns segundos" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Este plugin não possui permissão de 'settings_write'.\n\nAdicione \"permissions\": [\"settings_read\", \"settings_write\"] ao plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Este widget mantém a GPU ativa, podendo reduzir a duração da bateria. Não recomendado em laptops com gráficos híbridos." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Isso excluirá todas as entradas não fixadas. %1 entradas fixadas serão mantidas." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Isso vai apagar permanentemetne todo o histórico da área de transferência." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Isso removerá permanentemente este item salvo da área de transferência. Esta ação não pode ser desfeita." - }, - "Thunderstorm": { - "Thunderstorm": "Tempestade" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Tempestade com Granizo" - }, - "Tile": { - "Tile": "Azulejo" - }, - "Tile H": { - "Tile H": "Azulejo H" - }, - "Tile V": { - "Tile V": "Azulejo V" - }, - "Tiled": { - "Tiled": "Em Mosaico" - }, - "Tiled State": { - "Tiled State": "Estado em Mosaico" - }, - "Tiling": { - "Tiling": "Tiling" - }, - "Time": { - "Time": "Tempo" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "Hora & Clima" - }, - "Time Format": { - "Time Format": "Formato de Tempo" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "Tempo restante: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Tempo até o carregamento completo: %1" - }, - "Timed Out": { - "Timed Out": "Tempo Limite Esgotado" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Tempo limite para notificações de prioridade crítica" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Tempo limite para notificações de baixa prioridade" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Tempo limite para notificações de prioridade normal" - }, - "Title": { - "Title": "Título" - }, - "Title regex (optional)": { - "Title regex (optional)": "Regex de Título (opcional)" - }, - "To Full": { - "To Full": "Para completar" - }, - "To update, run the following command:": { - "To update, run the following command:": "Para atualizar, execute o seguinte comando:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Para usar este vinculo de DMS, remova ou altere o keybind no seu config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Mensagens Toast" - }, - "Today": { - "Today": "Hoje" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Alternar visibilidade dessa configuração de barra" - }, - "Toggling...": { - "Toggling...": "Alternando..." - }, - "Tomorrow": { - "Tomorrow": "Amanhã" - }, - "Tonal Spot": { - "Tonal Spot": "Ponto Tonal" - }, - "Toner Empty": { - "Toner Empty": "Toner Vazio" - }, - "Toner Low": { - "Toner Low": "Toner Baixo" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "Ferramentas" - }, - "Top": { - "Top": "Topo" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "Formato da Barra Superior" - }, - "Top Center": { - "Top Center": "Centro Superior" - }, - "Top Left": { - "Top Left": "Superior Esquerdo" - }, - "Top Processes": { - "Top Processes": "Processos Principais" - }, - "Top Right": { - "Top Right": "Superior Direito" - }, - "Top Section": { - "Top Section": "Seção do topo" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "Total de Trabalhos" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Transformar" - }, - "Transition Effect": { - "Transition Effect": "Efeito de Transição" - }, - "Transparency": { - "Transparency": "Transparência" - }, - "Trending GIFs": { - "Trending GIFs": "GIFs em alta" - }, - "Trending Stickers": { - "Trending Stickers": "Figurinhas em alta" - }, - "Trigger": { - "Trigger": "Gatilho" - }, - "Trigger Prefix": { - "Trigger Prefix": "Prefixo de Gatilho" - }, - "Trigger: %1": { - "Trigger: %1": "Gatilho: %1" - }, - "Trust": { - "Trust": "Confiar" - }, - "Try a different search": { - "Try a different search": "Tente uma pesquisa diferente" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Desligar todos os monitores imediatamente quando a tela de bloqueio for ativada" - }, - "Turn off monitors after": { - "Turn off monitors after": "Desligar monitores depois de" - }, - "Type": { - "Type": "Tipo" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Digite pelo menos 2 caracteres" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Digite este prefixo para pesquisar combinações de teclas" - }, - "Type to search files": { - "Type to search files": "Digite para pesquisar arquivos" - }, - "Typography": { - "Typography": "Tipografia" - }, - "Typography & Motion": { - "Typography & Motion": "Tipografia & Movimento" - }, - "Unavailable": { - "Unavailable": "Indisponível" - }, - "Unfocused Color": { - "Unfocused Color": "Cor sem Foco" - }, - "Ungrouped": { - "Ungrouped": "Sem Grupo" - }, - "Uninstall": { - "Uninstall": "Desinstalar" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Desinstalar Plugin" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Desinstalação falhou: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Desinstalado: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Desinstalando: %1" - }, - "Unknown": { - "Unknown": "Desconhecido" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "Artista Desconhecido" - }, - "Unknown Config": { - "Unknown Config": "Configuração Desconhecida" - }, - "Unknown Device": { - "Unknown Device": "Dispositivo Desconhecido" - }, - "Unknown GPU": { - "Unknown GPU": "GPU Desconhecida" - }, - "Unknown Monitor": { - "Unknown Monitor": "Monitor Desconhecido" - }, - "Unknown Network": { - "Unknown Network": "Rede Desconhecida" - }, - "Unknown Title": { - "Unknown Title": "Título Desconhecido" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "Descarregar ao Fechar" - }, - "Unmute": { - "Unmute": "Dessilenciar" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Dessilenciar popups para %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Regra Sem Nome" - }, - "Unpair": { - "Unpair": "Despareado" - }, - "Unpair failed": { - "Unpair failed": "Despareamento falhou" - }, - "Unpin": { - "Unpin": "Desafixar" - }, - "Unpin from Dock": { - "Unpin from Dock": "Desafixar do Dock" - }, - "Unsaved Changes": { - "Unsaved Changes": "Mudanças não salvas" - }, - "Unsaved changes": { - "Unsaved changes": "Mudanças não salvas" - }, - "Unsaved note...": { - "Unsaved note...": "Nota não salva..." - }, - "Untitled": { - "Untitled": "Sem título" - }, - "Untrust": { - "Untrust": "Deixar de confiar" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "Atualizar" - }, - "Update All": { - "Update All": "Atualizar Tudo" - }, - "Update Plugin": { - "Update Plugin": "Atualizar Plugin" - }, - "Uptime": { - "Uptime": "Tempo de Atividade" - }, - "Uptime:": { - "Uptime:": "Tempo de Atividade:" - }, - "Urgent Color": { - "Urgent Color": "Cor Urgente" - }, - "Usage Tips": { - "Usage Tips": "Dicas de Uso" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Usar relógio de 24 horas em vez de 12 horas com AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Usar Comando Personalizado" - }, - "Use Grid Layout": { - "Use Grid Layout": "Usar Layout em Grade" - }, - "Use IP Location": { - "Use IP Location": "Usar Localização do Endereço IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Usar Medidas Imperiais" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Usar unidades Imperiais (°F, mph, inHg) ao invés de Métricas (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Usar Fonte Monoespaçada" - }, - "Use System Theme": { - "Use System Theme": "Usar Tema do Sistema" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Use um gerenciador de papel de parede externo como swww, hyprpaper ou swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Usar barras de progresso de ondas animadas para reprodução de mídia" - }, - "Use custom border size": { - "Use custom border size": "Usar tamanho de borda personalizado" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Usar largura de borda/anel de foco personalizada" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Usar comando personalizado para atualizar seu sistema" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Usar espaçamentos personalizados em vez de espaçamento da barra" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Usar raio de janela personalizado em vez do raio do tema" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Usar arredondamento de janela personalizado em vez do raio do tema" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Usar tema claro em vez de escuro" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Usar metros por segundo em vez de km/h para velocidade do vento" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Usar cartões de notificação menores" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Usar tema de som das configurações do sistema" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Usar a mesma posição e tamanho em todos os monitores" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Usar prefixo de gatilho para ativar" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Usado quando a cor de destaque é definida como Personalizada" - }, - "User": { - "User": "Usuário" - }, - "Username": { - "Username": "Nome de usuário" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Usa horários de nascer/pôr do sol com base na sua localização." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Usa o tempo de nascer e pôr do sol para ajustar automaticamente o modo noturno baseado na sua localização." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Usando configurações compartilhadas do Gamma Control" - }, - "Utilities": { - "Utilities": "Utilitários" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "Conexões de VPN" - }, - "VPN Password": { - "VPN Password": "Senha da VPN" - }, - "VPN configuration updated": { - "VPN configuration updated": "Configuração da VPN atualizada" - }, - "VPN connections": { - "VPN connections": "Conexões VPN" - }, - "VPN deleted": { - "VPN deleted": "VPN excluída" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importada: %1" - }, - "VPN not available": { - "VPN not available": "VPN não disponível" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "Status de VPN e conexão rápida" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR Apenas Tela Cheia" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR sob Demanda" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Taxa de Atualização Variável" - }, - "Verification": { - "Verification": "Verificação" - }, - "Version": { - "Version": "Versão" - }, - "Vertical Deck": { - "Vertical Deck": "Deck Vertical" - }, - "Vertical Grid": { - "Vertical Grid": "Grade Vertical" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Scrolling Vertical" - }, - "Vertical Tiling": { - "Vertical Tiling": "Tiling Vertical" - }, - "Vibrant": { - "Vibrant": "Vibrante" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Paleta vibrante com saturação divertida." - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "Vídeos" - }, - "View Mode": { - "View Mode": "Modo de Visualização" - }, - "Visibility": { - "Visibility": "Visibilidade" - }, - "Visual Effects": { - "Visual Effects": "Efeitos Visuais" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Divisória visual entre os widgets" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Efeito visual usado na mudança do papel de parede" - }, - "Volume": { - "Volume": "Volume" - }, - "Volume Changed": { - "Volume Changed": "Volume Alterado" - }, - "Volume Slider": { - "Volume Slider": "Controle de Volume" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volume, brilho, e outros OSDs do sistema" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Papel de parede" - }, - "Wallpaper Error": { - "Wallpaper Error": "Erro de Papel de Parede" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Monitor do Papel de Parede" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Processamento de papel de parede falhou" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Processamento de papel de parede falhou - verifique o caminho do papel de parede" - }, - "Wallpapers": { - "Wallpapers": "Papéis de parede" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Temperatura de cor quente para aplicar" - }, - "Warning": { - "Warning": "Aviso" - }, - "Warnings": { - "Warnings": "Avisos" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Barra de Progresso de Ondas" - }, - "Weather": { - "Weather": "Clima" - }, - "Weather Widget": { - "Weather Widget": "Widget de Clima" - }, - "Welcome": { - "Welcome": "Boas-vindas" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Bem-vindo ao DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Quando ativado, apps são ordenados alfabeticamente. Quando desativado, apps são ordenados por frequência de uso." - }, - "When locked": { - "When locked": "Quando bloqueado" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Quando o widget de atualização for usado, ocultá-lo se nenhuma atualização for encontrada" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Senha do Wi-Fi" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Conexão Wi-Fi e Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi não disponível" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "Dispositivo WiFi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Código QR do WiFi para " - }, - "WiFi disabled": { - "WiFi disabled": "WiFi desativado" - }, - "WiFi enabled": { - "WiFi enabled": "Wifi ativado" - }, - "WiFi is off": { - "WiFi is off": "WiFi desligado" - }, - "WiFi off": { - "WiFi off": "WiFi desligado" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Amplo (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Cor de Fundo dos Widgets" - }, - "Widget Management": { - "Widget Management": "Gerenciamento de Widgets" - }, - "Widget Outline": { - "Widget Outline": "Borda de Widgets" - }, - "Widget Style": { - "Widget Style": "Estilo dos Widgets" - }, - "Widget Styling": { - "Widget Styling": "Estilo dos Widgets" - }, - "Widget Transparency": { - "Widget Transparency": "Transparência dos Widgets" - }, - "Widget added": { - "Widget added": "Widget adicionado" - }, - "Widget removed": { - "Widget removed": "Widget removido" - }, - "Widgets": { - "Widgets": "Widgets" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgets, layout, estilo" - }, - "Width": { - "Width": "Largura" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Largura da borda da janela (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Largura da borda da janela (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Largura da borda da janela e anel de foco" - }, - "Wind": { - "Wind": "Vento" - }, - "Wind Speed": { - "Wind Speed": "Velocidade do Vento" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Velocidade do Vento em m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Arredondamento de Janelas" - }, - "Window Gaps": { - "Window Gaps": "Espaçamentos de Janela" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Espaçamento de Janelas (px)" - }, - "Window Height": { - "Window Height": "Altura da Janela" - }, - "Window Opening": { - "Window Opening": "Abertura de Janela" - }, - "Window Rounding": { - "Window Rounding": "Arredondamento da Janela" - }, - "Window Rules": { - "Window Rules": "Regras de Janela" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Regras de Janela Incluem Ausentes" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Regras de Janela Não Configuradas" - }, - "Wipe": { - "Wipe": "Limpar" - }, - "Workspace": { - "Workspace": "Área de Trabalho" - }, - "Workspace Appearance": { - "Workspace Appearance": "Aparência do Espaço de Trabalho" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Índices das Áreas de Trabalho" - }, - "Workspace Names": { - "Workspace Names": "Nomes das Áreas de Trabalho" - }, - "Workspace Padding": { - "Workspace Padding": "Mínimo de 3 Áreas de Trabalho" - }, - "Workspace Settings": { - "Workspace Settings": "Configurações da Área de Trabalho" - }, - "Workspace Switcher": { - "Workspace Switcher": "Seletor de Áreas de Trabalho" - }, - "Workspace name": { - "Workspace name": "Nome do espaço de trabalho" - }, - "Workspaces": { - "Workspaces": "Áreas de Trabalho" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Áreas de Trabalho e Widgets" - }, - "Write:": { - "Write:": "Escrita:" - }, - "X Axis": { - "X Axis": "Eixo X" - }, - "Y Axis": { - "Y Axis": "Eixo Y" - }, - "Yes": { - "Yes": "Sim" - }, - "Yesterday": { - "Yesterday": "Ontem" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Você tem mudanças não salvas. Salvar antes de fechar esta guia?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Você tem mudanças não salvas. Deseja salvar antes de continuar?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Você tem mudanças não salvas. Deseja salvar antes de criar um novo arquivo?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Você tem mudanças não salvas. Deseja salvar antes de abrir um arquivo?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Você precisa definir um dos seguintes:\nQT_QPA_PLATFORMTHEME=gtk3 OU\nQT_QPA_PLATFORMTHEME=qt6ct\ncomo variáveis de ambiente, e então reiniciar o shell.\n\nqt6ct requer qt6ct-kde para ser instalado." - }, - "You're All Set!": { - "You're All Set!": "Tudo Pronto!" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "ações" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "por %1" - }, - "days": { - "days": "dias" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "dispositivo" - }, - "devices connected": { - "devices connected": "dispositivos conectados" - }, - "dgop not available": { - "dgop not available": "dgop não disponível" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "arquivo de configuração dms/cursor existe, mas não está incluído. As configurações de cursor não serão aplicadas." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "A configuração dms/outputs existe, mas não está incluída no seu configurador de compositor. As alterações de exibição não serão persistentes." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "ex. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "ex. focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "por exemplo, notify-send 'Olá' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "eventos" - }, - "ext": { - "ext": "ext" - }, - "featured": { - "featured": "em destaque" - }, - "leave empty for default": { - "leave empty for default": "deixe vazio por padrão" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl não disponível - integração com bloqueio requer conexão de socket DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen não encontrado - instale o pacote matugen para tematização dinâmica" - }, - "minutes": { - "minutes": "minutos" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "nav" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "configuração de atalhos do niri" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "agora" - }, - "official": { - "official": "oficial" - }, - "on Hyprland": { - "on Hyprland": "no Hyprland" - }, - "on MangoWC": { - "on MangoWC": "no MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "no Miracle WM" - }, - "on Niri": { - "on Niri": "no Niri" - }, - "on Scroll": { - "on Scroll": "no Scroll" - }, - "on Sway": { - "on Sway": "no Sway" - }, - "open": { - "open": "abrir" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "processos" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "segundos" - }, - "source": { - "source": "fonte" - }, - "this app": { - "this app": "este aplicativo" - }, - "up": { - "up": "cima" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "atualize dms para integração com o NM." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 por %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype não disponível - installe wtype para suporte de colagem" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "Instale apenas de fontes confiáveis" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Mês (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Mês (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Mês (Jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMM - Mês (Janeiro)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "Plugins podem ter bugs ou problemas de segurança" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "Se possível, revise o código antes de instalar" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "d - Dia (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "dd - Dia (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "ddd - Nome do dia (seg)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "dddd - Nome do dia (segunda-feira)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "yy - Ano (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "yyyy - Ano (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Navegar • Espaço: Expandir • Enter: Ação/Expandir • E: Texto" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Navegar • Enter: Colar • Del: Excluir • F10: Ajuda" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ru.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ru.json deleted file mode 100644 index d46ceac..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/ru.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "Скорость анимации %1" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 символов" - }, - "%1 connected": { - "%1 connected": "%1 подключен(о)" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "Пользовательская длительность анимации %1" - }, - "%1 disconnected": { - "%1 disconnected": "%1 отключен(о)" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 отключен(о) (скрыто)" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 существует, но не включён в конфигурацию. Пользовательские комбинации клавиш не будут работать, пока это не будет исправлено." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 существует, но не включен. Правила окон не будут применены." - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 теперь включен в конфигурацию" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "%1 уведомлений" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 вариант(ов)" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 виджет(ов)" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "%1 мин. назад" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "(По умолчанию)" - }, - "(Unnamed)": { - "(Unnamed)": "(Без названия)" - }, - "+ %1 more": { - "+ %1 more": "+ ещё %1" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "0 = прямые углы" - }, - "1 day": { - "1 day": "1 день" - }, - "1 device connected": { - "1 device connected": "1 устройство подключено" - }, - "1 event": { - "1 event": "1 событие" - }, - "1 hour": { - "1 hour": "1 час" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 час 30 минут" - }, - "1 minute": { - "1 minute": "1 минута" - }, - "1 notification": { - "1 notification": "1 уведомлений" - }, - "1 second": { - "1 second": "1 секунда" - }, - "10 minutes": { - "10 minutes": "10 минут" - }, - "10 seconds": { - "10 seconds": "10 секунд" - }, - "10-bit Color": { - "10-bit Color": "10-битный цвет" - }, - "12 hours": { - "12 hours": "12 часов" - }, - "14 days": { - "14 days": "14 дней" - }, - "15 minutes": { - "15 minutes": "15 минут" - }, - "15 seconds": { - "15 seconds": "15 секунд" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 часа" - }, - "2 minutes": { - "2 minutes": "2 минуты" - }, - "2 seconds": { - "2 seconds": "2 секунды" - }, - "20 minutes": { - "20 minutes": "20 минут" - }, - "20 seconds": { - "20 seconds": "20 секунд" - }, - "24-Hour Format": { - "24-Hour Format": "24-Часовой формат" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "24-часовой формат" - }, - "25 seconds": { - "25 seconds": "25 секунд" - }, - "250 ms": { - "250 ms": "250 мс" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 дня" - }, - "3 hours": { - "3 hours": "3 часа" - }, - "3 minutes": { - "3 minutes": "3 минуты" - }, - "3 seconds": { - "3 seconds": "3 секунды" - }, - "30 days": { - "30 days": "30 дней" - }, - "30 minutes": { - "30 minutes": "30 минут" - }, - "30 seconds": { - "30 seconds": "30 секунд" - }, - "35 seconds": { - "35 seconds": "35 секунд" - }, - "3rd party": { - "3rd party": "Сторонние" - }, - "4 hours": { - "4 hours": "4 часа" - }, - "4 seconds": { - "4 seconds": "4 секунды" - }, - "40 seconds": { - "40 seconds": "40 секунд" - }, - "45 seconds": { - "45 seconds": "45 секунд" - }, - "5 minutes": { - "5 minutes": "5 минут" - }, - "5 seconds": { - "5 seconds": "5 секунд" - }, - "50 seconds": { - "50 seconds": "50 секунд" - }, - "500 ms": { - "500 ms": "500 мс" - }, - "55 seconds": { - "55 seconds": "55 секунд" - }, - "6 hours": { - "6 hours": "6 часов" - }, - "7 days": { - "7 days": "7 дней" - }, - "750 ms": { - "750 ms": "750 мс" - }, - "8 hours": { - "8 hours": "8 часов" - }, - "8 seconds": { - "8 seconds": "8 секунд" - }, - "90 days": { - "90 days": "90 дней" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Файл с таким именем уже существует. Хотите его перезаписать?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Современная оболочка рабочего стола для композиторов Wayland" - }, - "AC Power": { - "AC Power": "Сеть" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Прервано" - }, - "About": { - "About": "О нас" - }, - "Accent Color": { - "Accent Color": "Акцентный цвет" - }, - "Accept": { - "Accept": "Принять" - }, - "Accept Jobs": { - "Accept Jobs": "Принять задания" - }, - "Accepting": { - "Accepting": "Принятие" - }, - "Access clipboard history": { - "Access clipboard history": "Доступ к буферу обмена" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Доступ к уведомлениям и 'не беспокоить'" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Доступ к панели управления и настройкам" - }, - "Action": { - "Action": "Действие" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "Действия" - }, - "Activate": { - "Activate": "Активировать" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "Активация" - }, - "Active": { - "Active": "Активен" - }, - "Active Color": { - "Active Color": "Активный цвет" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Монитор экрана блокировки" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Фон активной плитки и цвет значка" - }, - "Active: %1": { - "Active: %1": "Активно: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Активно: %1 +%2" - }, - "Active: None": { - "Active: None": "Активен: Нет" - }, - "Adapters": { - "Adapters": "Адаптеры" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Добавить" - }, - "Add Bar": { - "Add Bar": "Добавить бар" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Добавить виджет рабочего стола" - }, - "Add Printer": { - "Add Printer": "Добавить принтер" - }, - "Add Title": { - "Add Title": "Добавить заголовок" - }, - "Add Widget": { - "Add Widget": "Добавить виджет" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Добавить виджет в секцию %1" - }, - "Add a border around the dock": { - "Add a border around the dock": "Добавить рамку вокруг дока" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Добавить пользовательский префикс ко всем запускам приложений. Можно использовать для 'uwsm-app', 'systemd-run' или других командных обёрток." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Добавить и настроить виджеты, отображаемые на рабочем столе" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Настроить количество столбцов в режиме сетки." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Регулировка громкости на шаг прокрутки" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Дополнительно" - }, - "Afternoon": { - "Afternoon": "День" - }, - "All": { - "All": "Все" - }, - "All Monitors": { - "All Monitors": "Все мониторы" - }, - "All checks passed": { - "All checks passed": "Все проверки пройдены" - }, - "All day": { - "All day": "Весь день" - }, - "All displays": { - "All displays": "Все мониторы" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Разрешить клики проходить сквозь виджет" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Назад • F1/I: Информация о Файле • F10: Справка • Esc: Закрыть" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "Всегда активно" - }, - "Always Show Percentage": { - "Always Show Percentage": "Всегда показывать процент" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Всегда скрывать док и показывать при наведении на область дока" - }, - "Always on icons": { - "Always on icons": "Всегда на значках" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Всегда показывать минимум 3 рабочих пространства, даже если доступно меньше" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Всегда показывать док, когда открыт Niri Overview" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Всегда показывать, если подключен только один дисплей" - }, - "Amount": { - "Amount": "Количество" - }, - "Analog": { - "Analog": "Аналоговый" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Аналоговые, цифровые или многоярусные часы" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Анализ конфигурации..." - }, - "Animation Duration": { - "Animation Duration": "Длительность анимации" - }, - "Animation Speed": { - "Animation Speed": "Скорость анимации" - }, - "Anonymous Identity": { - "Anonymous Identity": "Анонимный идентификатор" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Анонимный идентификатор (необязательно)" - }, - "App Customizations": { - "App Customizations": "Приложение Настройки" - }, - "App ID Substitutions": { - "App ID Substitutions": "Подстановки ID приложения" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "Regex ID приложения (например, ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Программа Запуска Приложений" - }, - "App Names": { - "App Names": "Имена приложений" - }, - "App Theming": { - "App Theming": "Реестр тем" - }, - "Appearance": { - "Appearance": "Внешний вид" - }, - "Application Dock": { - "Application Dock": "Приложение Док" - }, - "Applications": { - "Applications": "Приложения" - }, - "Apply Changes": { - "Apply Changes": "Применить изменения" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Применить цвета GTK" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Применить цвета Qt" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Применить тёплую цветовую температуру для снижения нагрузки на глаза. Используйте настройки автоматизации ниже для управления активацией." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "Приложения" - }, - "Apps Dock": { - "Apps Dock": "Приложения Док" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Приложения Док Настройки" - }, - "Apps Icon": { - "Apps Icon": "Иконки приложений" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Приложения упорядочены по частоте использования, затем по последнему использованию, затем по алфавиту." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Приложения с пользовательским именем, значком или параметрами запуска. Щёлкните ПКМ и выберите «Изменить приложение» для настройки." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Приложения с отключёнными всплывающими уведомлениями. Включите звук или удалите для удаления." - }, - "Architecture": { - "Architecture": "Архитектура" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Расположить дисплеи и настроить разрешение, частоту обновления и VRR" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "Аудио" - }, - "Audio Codec": { - "Audio Codec": "Аудио кодек" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Выбор аудио кодека" - }, - "Audio Devices": { - "Audio Devices": "Аудио устройства" - }, - "Audio Input": { - "Audio Input": "Аудио Вход" - }, - "Audio Output": { - "Audio Output": "Аудио Выход" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Устройства вывода аудио (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Аудио Выход Переключатель" - }, - "Audio Visualizer": { - "Audio Visualizer": "Аудио Визуализатор" - }, - "Audio system restarted": { - "Audio system restarted": "Аудио система перезапущена" - }, - "Audio volume control": { - "Audio volume control": "Аудио громкость управление" - }, - "Auth": { - "Auth": "Аутентификация" - }, - "Auth Type": { - "Auth Type": "Аутентификация Тип" - }, - "Authenticate": { - "Authenticate": "Аутентифицировать" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "Аутентификация" - }, - "Authentication Required": { - "Authentication Required": "Требуется авторизация" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Аутентификация не удалась, попробуйте снова" - }, - "Authorize": { - "Authorize": "Авторизовать" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Авторизовать сопряжение с " - }, - "Authorize service for ": { - "Authorize service for ": "Авторизовать службу для " - }, - "Auto": { - "Auto": "Авто" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Авто (широкий)" - }, - "Auto Location": { - "Auto Location": "Автоматическое Определение Местоположения" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Авто Всплывающее Отступы" - }, - "Auto-Clear After": { - "Auto-Clear After": "Автоочистка через" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Тайм-аут автоскрытия" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Автозакрытие обзора Niri при запуске приложений." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Сохранять уведомления обычного приоритета в историю" - }, - "Auto-hide": { - "Auto-hide": "Автоскрытие" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Автоскрытие Дока" - }, - "Auto-saving...": { - "Auto-saving...": "Автосохранение..." - }, - "Autoconnect": { - "Autoconnect": "Автоподключение" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Автоподключение отключено" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Автоподключение включено" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Автоматический Цвет Режим" - }, - "Automatic Control": { - "Automatic Control": "Автоматическое Управление" - }, - "Automatic Cycling": { - "Automatic Cycling": "Автоматическое Переключение" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Автоматическое переключение между обоями в одной папке" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Автоматически удалять записи старше этого срока" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Автоматически определять местоположение по IP-адресу" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Автоматическое определение вашего местоположения с помощью вашего IP-адреса" - }, - "Automatically lock after": { - "Automatically lock after": "Автоматическая блокировка после" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Автоматически блокировать экран при запуске DMS" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Автоматически блокировать экран при подготовке системы к приостановке" - }, - "Automation": { - "Automation": "Автоматизация" - }, - "Available": { - "Available": "Доступный" - }, - "Available Layouts": { - "Available Layouts": "Доступные Макеты" - }, - "Available Networks": { - "Available Networks": "Доступные Сети" - }, - "Available Plugins": { - "Available Plugins": "Доступные Дополнения" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Доступные Экраны (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Доступно в режимах просмотра 'Подробно' и 'Прогноз'" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Назад" - }, - "Backend": { - "Backend": "Бэкенд" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Непрозрачность фона" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Фоновое изображение" - }, - "Backlight device": { - "Backlight device": "Подсветки устройство" - }, - "Balance power and performance": { - "Balance power and performance": "Приоритет производительности" - }, - "Balanced": { - "Balanced": "Экономия энергии" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Сбалансированная палитра с фокусными акцентами (по умолчанию)." - }, - "Bar Configurations": { - "Bar Configurations": "Конфигурации бара" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "Прозрачность бара" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Базовая длительность анимаций (перетащите для использования пользовательской)" - }, - "Battery": { - "Battery": "Батарея" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Батарея Заряда Ограничение" - }, - "Battery and power management": { - "Battery and power management": "Батарея и управление питанием" - }, - "Battery level and power management": { - "Battery level and power management": "Уровень заряда батареи и управление питанием" - }, - "Behavior": { - "Behavior": "Поведение" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Привязать экран блокировки к DBus-сигналам от loginctl. Отключите при использовании внешнего экрана блокировки" - }, - "Binds Include Missing": { - "Binds Include Missing": "Binds Include отсутствует" - }, - "Binds include added": { - "Binds include added": "Binds include добавлен" - }, - "Bit Depth": { - "Bit Depth": "Глубина цвета" - }, - "Block Out": { - "Block Out": "Блокировать с" - }, - "Block Out From": { - "Block Out From": "Блокировать с" - }, - "Block notifications": { - "Block notifications": "Блокировать уведомления" - }, - "Blocked": { - "Blocked": "Заблокировано" - }, - "Blue light filter": { - "Blue light filter": "Фильтр синего света" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Настройки Bluetooth" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth недоступен" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Размытие Обоев слоя" - }, - "Blur on Overview": { - "Blur on Overview": "Размытие в режиме обзора" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Размытие обоев при открытом обзоре Niri" - }, - "Body": { - "Body": "Заголовок" - }, - "Border": { - "Border": "Рамка" - }, - "Border Color": { - "Border Color": "Цвет рамки" - }, - "Border Opacity": { - "Border Opacity": "Границы Непрозрачность" - }, - "Border Size": { - "Border Size": "Размер границы" - }, - "Border Thickness": { - "Border Thickness": "Толщина рамки" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "Граница с фоном" - }, - "Bottom": { - "Bottom": "Снизу" - }, - "Bottom Center": { - "Bottom Center": "Вверху справа" - }, - "Bottom Left": { - "Bottom Left": "Внизу слева" - }, - "Bottom Right": { - "Bottom Right": "Внизу справа" - }, - "Bottom Section": { - "Bottom Section": "Нижняя секция" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Нижний док для закреплённых и запущенных приложений" - }, - "Brightness": { - "Brightness": "Яркость" - }, - "Brightness Slider": { - "Brightness Slider": "Яркости Ползунок" - }, - "Brightness Value": { - "Brightness Value": "Яркости Значение" - }, - "Brightness control not available": { - "Brightness control not available": "Управление яркостью недоступно" - }, - "Browse": { - "Browse": "Просмотр" - }, - "Browse Files": { - "Browse Files": "Обзор файлов" - }, - "Browse Plugins": { - "Browse Plugins": "Просмотр Дополнений" - }, - "Browse Themes": { - "Browse Themes": "Просмотр тем" - }, - "Browse or search plugins": { - "Browse or search plugins": "Обзор или поиск Плагины" - }, - "Button Color": { - "Button Color": "Цвет кнопки" - }, - "CPU": { - "CPU": "ЦП" - }, - "CPU Graph": { - "CPU Graph": "CPU График" - }, - "CPU Temperature": { - "CPU Temperature": "Температура ЦП" - }, - "CPU Usage": { - "CPU Usage": "Использование ЦП" - }, - "CPU temperature display": { - "CPU temperature display": "Отображение температуры ЦП" - }, - "CPU usage indicator": { - "CPU usage indicator": "Индикатор загрузки ЦП" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "Мониторинг ЦП, памяти, сети и диска" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS: предупреждение о небезопасном фильтре" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS: предупреждение об отсутствующем фильтре" - }, - "CUPS Print Server": { - "CUPS Print Server": "Сервер печати CUPS" - }, - "CUPS not available": { - "CUPS not available": "CUPS недоступен" - }, - "Camera": { - "Camera": "Камера" - }, - "Cancel": { - "Cancel": "Отмена" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "%1 задани(й/я)" - }, - "Canceled": { - "Canceled": "Отменено" - }, - "Cannot pair": { - "Cannot pair": "Невозможно сопрячь" - }, - "Capabilities": { - "Capabilities": "Возможности" - }, - "Capacity": { - "Capacity": "Ёмкость" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Индикатор Caps Lock" - }, - "Caps Lock is on": { - "Caps Lock is on": "Caps Lock включён" - }, - "Center Section": { - "Center Section": "Центральная Секция" - }, - "Center Single Column": { - "Center Single Column": "Центральная одиночная колонна" - }, - "Center Tiling": { - "Center Tiling": "Центрированный тайлинг" - }, - "Certificate Password": { - "Certificate Password": "Сертификата Пароль" - }, - "Change Song": { - "Change Song": "Ничего" - }, - "Change Volume": { - "Change Volume": "Ничего" - }, - "Change bar appearance": { - "Change bar appearance": "Изменить панели внешний вид" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "Канал" - }, - "Charging": { - "Charging": "Заряжается" - }, - "Check for system updates": { - "Check for system updates": "Проверить наличие обновлений системы" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "Выбрать Цвет" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Выбрать цвет тёмного режима" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Выбрать Док Лаунчер Логотипа Цвет" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Выбрать Цвет Логотипа Лаунчера" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Выбрать цвет светлого режима" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Выбрать цвет обоев" - }, - "Choose a color": { - "Choose a color": "Выбрать a цвет" - }, - "Choose colors from palette": { - "Choose colors from palette": "Выбрать цвета из палитры" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Выбрать способ отображения виджета погоды" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "Выбрать Значок" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Выбрать цвет фона для виджетов" - }, - "Choose the border accent color": { - "Choose the border accent color": "Выбрать акцентный цвет рамки" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Выбрать логотип, отображаемый на кнопке запуска приложений в DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Выбрать, где на экране будут отображаться всплывающие уведомления" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Выбрать, где на экране появляются наэкранные дисплеи" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Выбрать, на каких дисплеях показывать этот виджет" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Выбрать монитор для отображения экрана блокировки. Другие мониторы будут отображать сплошной цвет для защиты OLED от выгорания." - }, - "Chroma Style": { - "Chroma Style": "Стиль Chroma" - }, - "Cipher": { - "Cipher": "Шифр" - }, - "Circle": { - "Circle": "Линия" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Regex класса (например, ^firefox$)" - }, - "Clear": { - "Clear": "Очистить" - }, - "Clear All": { - "Clear All": "Очистить Всё" - }, - "Clear All Jobs": { - "Clear All Jobs": "Очистить все задания" - }, - "Clear History?": { - "Clear History?": "Отчистить историю?" - }, - "Clear Sky": { - "Clear Sky": "Ясно" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Очистить всю историю при запуске сервера" - }, - "Clear at Startup": { - "Clear at Startup": "Очистить при запуске" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Нажмите «Setup» для создания %1 и добавления include в конфиг." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Нажмите «Setup» для создания %1 и добавления include в конфиг композитора." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Нажмите «Setup» для создания конфига курсора и добавления include в конфиг композитора." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Нажмите «Setup» для создания конфига outputs и добавления include в конфиг композитора." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Нажмите Import для добавления .ovpn или .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "Нажмите насквозь" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Нажмите любую горячую клавишу для редактирования. Изменения сохраняются в %1" - }, - "Click to capture": { - "Click to capture": "Нажмите для захвата" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Нажмите для выбора пользовательского JSON-файла темы" - }, - "Clip": { - "Clip": "Обрезать" - }, - "Clip to Geometry": { - "Clip to Geometry": "Обрезать по геометрии" - }, - "Clipboard": { - "Clipboard": "Буфер обмена" - }, - "Clipboard History": { - "Clipboard History": "История Буфера Обмена" - }, - "Clipboard Manager": { - "Clipboard Manager": "Менеджер Буфера Обмена" - }, - "Clipboard sent": { - "Clipboard sent": "Буфер обмена отправлен" - }, - "Clipboard service not available": { - "Clipboard service not available": "Служба буфера обмена недоступна" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Буфер обмена работает, но ничего не сохраняется на диск" - }, - "Clock": { - "Clock": "Часы" - }, - "Clock Style": { - "Clock Style": "Стиль часов" - }, - "Close": { - "Close": "Закрыть" - }, - "Close All Windows": { - "Close All Windows": "Закрыть все окна" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Закрыть обзор при запуске" - }, - "Close Window": { - "Close Window": "Закрыть окно" - }, - "Color": { - "Color": "Цвет" - }, - "Color Gamut": { - "Color Gamut": "Цветовой охват" - }, - "Color Management": { - "Color Management": "Управление цветом" - }, - "Color Mode": { - "Color Mode": "Цвет Режим" - }, - "Color Override": { - "Color Override": "Изменение Цвета" - }, - "Color Picker": { - "Color Picker": "Выбор Цвета" - }, - "Color Temperature": { - "Color Temperature": "Цветовая температура" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Цвет, отображаемый на мониторах без экрана блокировки" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Цвет для кнопок основных действий" - }, - "Color temperature for day time": { - "Color temperature for day time": "Цветовая температура для дневного времени" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Цветовая температура для ночного режима" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Цветовая тема для подсветки синтаксиса." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Цветовая тема для подсветки синтаксиса. Доступно тем: %1." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Цветовая тема из реестра DMS" - }, - "Colorful": { - "Colorful": "По умолчанию" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Красочная смесь ярких контрастных акцентов." - }, - "Colorize Active": { - "Colorize Active": "Colorize активен" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Безопасность и конфиденциальность" - }, - "Column": { - "Column": "Колонка" - }, - "Column Display": { - "Column Display": "Отображение столбца" - }, - "Column Width": { - "Column Width": "Ширина столбца" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Команда" - }, - "Commands": { - "Commands": "Команды" - }, - "Communication": { - "Communication": "Взаимодействие" - }, - "Community themes": { - "Community themes": "Безопасность и конфиденциальность" - }, - "Compact": { - "Compact": "Компактно" - }, - "Compact Mode": { - "Compact Mode": "Компактный Режим" - }, - "Completed": { - "Completed": "Завершено" - }, - "Compositor": { - "Compositor": "Композитор" - }, - "Compositor Settings": { - "Compositor Settings": "Настройки композитора" - }, - "Compositor not supported": { - "Compositor not supported": "Композитор не поддерживается" - }, - "Config Format": { - "Config Format": "Формат конфига" - }, - "Config action: %1": { - "Config action: %1": "Действие конфига: %1" - }, - "Config validation failed": { - "Config validation failed": "Проверка конфига не удалась" - }, - "Configuration": { - "Configuration": "Конфигурация" - }, - "Configuration activated": { - "Configuration activated": "Конфигурация активирована" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Конфигурация будет сохранена при переподключении этого дисплея" - }, - "Configure": { - "Configure": "Настроить" - }, - "Configure Keybinds": { - "Configure Keybinds": "Настроить комбинации клавиш" - }, - "Configure a new printer": { - "Configure a new printer": "Настроить новый принтер" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Настроить значки для именованных рабочих областей. Значки имеют приоритет перед номерами, если включены оба параметра." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Настроить критерии соответствия и действия" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "%1 дисплей(ев)" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Настроить мониторы для отображения компонентов оболочки" - }, - "Confirm": { - "Confirm": "Подтвердить" - }, - "Confirm Delete": { - "Confirm Delete": "Подтвердить удаление" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Подтвердить изменения дисплеев" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Подтвердить ключ доступа для " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Конфликтует с: %1" - }, - "Connect": { - "Connect": "Подключиться" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Подключиться к скрытой сети" - }, - "Connect to VPN": { - "Connect to VPN": "Подключиться к VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Подключение к Wi-Fi" - }, - "Connected": { - "Connected": "Подключено" - }, - "Connected Device": { - "Connected Device": "Выкл" - }, - "Connected Displays": { - "Connected Displays": "Подключённые Мониторы" - }, - "Connecting to Device": { - "Connecting to Device": "Подключение к устройству" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Подключение..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "Регулярное выражение" - }, - "Content": { - "Content": "Яркий" - }, - "Content copied": { - "Content copied": "Содержимое скопировано" - }, - "Contrast": { - "Contrast": "Контраст" - }, - "Control Center": { - "Control Center": "Центр Управления" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Цвет плиток центра управления" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Контроль длительности анимации для всплывающих уведомлений и истории" - }, - "Control currently playing media": { - "Control currently playing media": "Управление воспроизводимым медиа" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Отображение уведомлений" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Контроль того, какие плагины появляются в режиме «All» без требования префикса триггера. Перетащите для изменения порядка." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Управление рабочими пространствами и столбцами прокруткой на панели" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Контролирует непрозрачность всех всплывающих окон, модальных окон и их слоев контента" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "Перезарядка" - }, - "Copied GIF": { - "Copied GIF": "GIF скопирован" - }, - "Copied MP4": { - "Copied MP4": "MP4 скопирован" - }, - "Copied WebP": { - "Copied WebP": "WebP скопирован" - }, - "Copied to clipboard": { - "Copied to clipboard": "Скопировано в буфер обмена" - }, - "Copied!": { - "Copied!": "Скопировано!" - }, - "Copy": { - "Copy": "Копировать" - }, - "Copy Content": { - "Copy Content": "Копировать содержимое" - }, - "Copy Full Command": { - "Copy Full Command": "Скопировать полную команду" - }, - "Copy HTML": { - "Copy HTML": "Копировать HTML" - }, - "Copy Name": { - "Copy Name": "Копировать имя" - }, - "Copy PID": { - "Copy PID": "Скопировать PID" - }, - "Copy Text": { - "Copy Text": "Копировать текст" - }, - "Copy path": { - "Copy path": "Копировать путь" - }, - "Corner Radius": { - "Corner Radius": "Радиус скругления углов" - }, - "Corner Radius Override": { - "Corner Radius Override": "Переопределение радиуса скругления" - }, - "Corners & Background": { - "Corners & Background": "Углы и фон" - }, - "Count Only": { - "Count Only": "Полное содержимое" - }, - "Cover Open": { - "Cover Open": "Крышка открыта" - }, - "Create": { - "Create": "Создать" - }, - "Create Dir": { - "Create Dir": "Создать Каталог" - }, - "Create Printer": { - "Create Printer": "Создать принтер" - }, - "Create Window Rule": { - "Create Window Rule": "Создать правило окна" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "Создать правило для:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Создать правила для отключения звука, игнорирования, скрытия из истории или переопределения приоритета уведомлений. По умолчанию переопределяется только приоритет; уведомления всё равно показываются нормально." - }, - "Creating...": { - "Creating...": "Создание..." - }, - "Critical Priority": { - "Critical Priority": "Критический Приоритет" - }, - "Current": { - "Current": "История" - }, - "Current Items": { - "Current Items": "Текущие Элементы" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "Текущий монитор" - }, - "Current Period": { - "Current Period": "Текущий период" - }, - "Current Status": { - "Current Status": "Текущий статус" - }, - "Current Temp": { - "Current Temp": "Текущая температура" - }, - "Current Theme: %1": { - "Current Theme: %1": "Текущая тема: %1" - }, - "Current Weather": { - "Current Weather": "Погода сейчас" - }, - "Current Workspace": { - "Current Workspace": "Текущее рабочее пространство" - }, - "Current time and date display": { - "Current time and date display": "Отображение текущих даты и времени" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Текущие погодные условия и температура" - }, - "Current: %1": { - "Current: %1": "Текущее: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Конфигурация курсора не настроена" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Cursor Include отсутствует" - }, - "Cursor Size": { - "Cursor Size": "Размер курсора" - }, - "Cursor Theme": { - "Cursor Theme": "Тема курсора" - }, - "Custom": { - "Custom": "Свой" - }, - "Custom Color": { - "Custom Color": "Пользовательский цвет" - }, - "Custom Duration": { - "Custom Duration": "Пользовательская длительность" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Пользовательская команда гибернации" - }, - "Custom Location": { - "Custom Location": "Своя Локация" - }, - "Custom Lock Command": { - "Custom Lock Command": "Пользовательская команда блокировки" - }, - "Custom Logout Command": { - "Custom Logout Command": "Пользовательская команда выхода" - }, - "Custom Name": { - "Custom Name": "Пользовательское имя" - }, - "Custom Power Actions": { - "Custom Power Actions": "Пользовательские действия питания" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Пользовательская команда выключения" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Пользовательская команда перезагрузки" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Пользовательская команда приостановки" - }, - "Custom Transparency": { - "Custom Transparency": "Своя Прозрачность" - }, - "Custom power profile": { - "Custom power profile": "Приоритет производительности" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Пользовательская тема загружена из JSON-файла" - }, - "Custom...": { - "Custom...": "Пользовательский..." - }, - "Custom: ": { - "Custom: ": "Свой: " - }, - "Customizable empty space": { - "Customizable empty space": "Настраиваемое пустое пространство" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Настроить, какие действия появляются в меню питания" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI монитор" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "ДЕМОНСТРАЦИОННЫЙ РЕЖИМ - Нажмите в любом месте, чтобы выйти" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "Менеджер Дополнений DMS Недоступен" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "Комбинации клавиш DMS" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS устарел" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "Служба DMS не подключена. Настройки буфера обмена недоступны." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "Действия оболочки DMS (лаунчер, буфер обмена и т.д.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET не доступен" - }, - "DWL service not available": { - "DWL service not available": "Служба DWL недоступна" - }, - "Daily": { - "Daily": "Ежедневно" - }, - "Daily at:": { - "Daily at:": "Ежедневно в:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Панель Dank" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell готов к использованию" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell и системные значки (требуется перезапуск)" - }, - "Dark Mode": { - "Dark Mode": "Тёмный режим" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Затемнение фона модальных окон" - }, - "Date Format": { - "Date Format": "Формат Даты" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Рассвет (астрономические сумерки)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Рассвет (гражданские сумерки)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Рассвет (навигационные сумерки)" - }, - "Day Date": { - "Day Date": "Системный по умолчанию" - }, - "Day Month Date": { - "Day Month Date": "Системный по умолчанию" - }, - "Day Temperature": { - "Day Temperature": "Дневная температура" - }, - "Daytime": { - "Daytime": "Дневное время" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "По умолчанию" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "Ширина по умолчанию (%)" - }, - "Default selected action": { - "Default selected action": "Действие по умолчанию" - }, - "Defaults": { - "Defaults": "Значения по умолчанию" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Определить правила поведения окон. Сохраняется в %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Очистить • Shift+Del: Очистить Всё • 1-9: Действия • F10: Справка • Esc: Закрыть" - }, - "Delete": { - "Delete": "Удалить" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Удалить \"%1\"?" - }, - "Delete Class": { - "Delete Class": "Delete Класса" - }, - "Delete Printer": { - "Delete Printer": "Удалить принтер" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Удалить сохранённый элемент?" - }, - "Delete VPN": { - "Delete VPN": "Удалить VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "%1 класс(ов)" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Удалить профиль \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Извлекает цвета, которые точно соответствуют исходному изображению." - }, - "Description": { - "Description": "Описание" - }, - "Desktop": { - "Desktop": "Рабочий стол" - }, - "Desktop Clock": { - "Desktop Clock": "Настольные часы" - }, - "Desktop Entry": { - "Desktop Entry": "Заголовок" - }, - "Desktop Widget": { - "Desktop Widget": "Виджет рабочего стола" - }, - "Desktop Widgets": { - "Desktop Widgets": "Виджеты рабочего стола" - }, - "Desktop background images": { - "Desktop background images": "Фоновые изображения рабочего стола" - }, - "Detailed": { - "Detailed": "Подробно" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "Разработка" - }, - "Device": { - "Device": "Устройство" - }, - "Device connections": { - "Device connections": "Подключения устройств" - }, - "Device names updated": { - "Device names updated": "Имена устройств обновлены" - }, - "Device paired": { - "Device paired": "Устройство сопряжено" - }, - "Device unpaired": { - "Device unpaired": "Сопряжение устройства отменено" - }, - "Digital": { - "Digital": "Цифровой" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Отключите Автоподключение" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Отключить встроенные обои" - }, - "Disable History Persistence": { - "Disable History Persistence": "Отключить сохранение истории" - }, - "Disable Output": { - "Disable Output": "Отключите Выход" - }, - "Disabled": { - "Disabled": "Отключено" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Отключение Wi-Fi…" - }, - "Disc": { - "Disc": "Стирание" - }, - "Discard": { - "Discard": "Отменить" - }, - "Discharging": { - "Discharging": "Подключено" - }, - "Disconnect": { - "Disconnect": "Отключить" - }, - "Disconnected": { - "Disconnected": "Отключено" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Отключен от WiFi" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "Диск" - }, - "Disk I/O": { - "Disk I/O": "Дисковый ввод/вывод" - }, - "Disk Usage": { - "Disk Usage": "Использование Диска" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "Диски" - }, - "Dismiss": { - "Dismiss": "Отклонить" - }, - "Display": { - "Display": "Дисплей" - }, - "Display Assignment": { - "Display Assignment": "Назначение дисплеев" - }, - "Display Control": { - "Display Control": "Реестр тем" - }, - "Display Name Format": { - "Display Name Format": "Формат имени дисплея" - }, - "Display Profiles": { - "Display Profiles": "Профили дисплеев" - }, - "Display Settings": { - "Display Settings": "Настройки дисплея" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Отображать док с закреплёнными и запущенными приложениями" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Отображает все приоритеты в полноэкранных приложениях" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Отображать и переключать layout DWL" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Отображать значки приложений в индикаторах рабочих пространств" - }, - "Display brightness control": { - "Display brightness control": "Управление яркостью дисплея" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Конфигурация дисплея недоступна. Протокол управления выводом WLR не поддерживается." - }, - "Display currently focused application title": { - "Display currently focused application title": "Отображает заголовок используемого приложения" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Отображать почасовые прогнозы погоды" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Отображать только рабочие пространства, содержащие окна" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Отображать действия меню питания в виде сетки вместо списка" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Отображать секунды в часах" - }, - "Display the power system menu": { - "Display the power system menu": "Отображать меню системы питания" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Отображать значения громкости и яркости в процентах во всплывающих окнах OSD" - }, - "Displays": { - "Displays": "Мониторы" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Количество дисплеев при активном переполнении" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Отображает активную раскладку клавиатуры и позволяет переключаться" - }, - "Distribution": { - "Distribution": "Имя хоста" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Разнообразная палитра, охватывающая весь спектр." - }, - "Do Not Disturb": { - "Do Not Disturb": "Не Беспокоить" - }, - "Dock": { - "Dock": "Док" - }, - "Dock & Launcher": { - "Dock & Launcher": "Док & Лаунчер" - }, - "Dock Transparency": { - "Dock Transparency": "Прозрачность Дока" - }, - "Dock Visibility": { - "Dock Visibility": "Видимость дока" - }, - "Docs": { - "Docs": "Документация" - }, - "Documents": { - "Documents": "Документы" - }, - "Domain (optional)": { - "Domain (optional)": "Домен (необязательно)" - }, - "Don't Change": { - "Don't Change": "Не изменять" - }, - "Don't Save": { - "Don't Save": "Не сохранять" - }, - "Door Open": { - "Door Open": "Дверь открыта" - }, - "Downloads": { - "Downloads": "Загрузки" - }, - "Drag to Reorder": { - "Drag to Reorder": "Перетащите для изменения порядка" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Перетаскивайте виджеты, чтобы изменить их порядок. Используйте значок глаза, чтобы скрыть/отобразить виджеты (с сохранением интервалов), или крестик, чтобы полностью удалить их." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Перетащите индикаторы рабочих пространств для изменения порядка" - }, - "Driver": { - "Driver": "Драйвер" - }, - "Drizzle": { - "Drizzle": "Морось" - }, - "Duplicate": { - "Duplicate": "Дублировать" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Дублировать обои с размытием" - }, - "Duration": { - "Duration": "Длительность" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Сумерки (астрономические сумерки)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Сумерки (гражданские сумерки)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Сумерки (навигационные сумерки)" - }, - "Dynamic": { - "Dynamic": "Динамическая" - }, - "Dynamic Properties": { - "Dynamic Properties": "Динамические свойства" - }, - "Dynamic Theming": { - "Dynamic Theming": "Динамичные темы" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Динамические цвета из обоев" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Динамические цвета, предустановки" - }, - "Edge Spacing": { - "Edge Spacing": "Отступ краёв" - }, - "Edit App": { - "Edit App": "Изменить приложение" - }, - "Edit Window Rule": { - "Edit Window Rule": "Изменить правило окна" - }, - "Education": { - "Education": "Обучение" - }, - "Empty": { - "Empty": "Пусто" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Включить 10-битную глубину цвета для более широкой цветовой гаммы и поддержки HDR" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Включить автоподключение" - }, - "Enable Bar": { - "Enable Bar": "Включить бар" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Включить режим 'Не беспокоить'" - }, - "Enable History": { - "Enable History": "Включить историю" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Включить наложение обзора" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Включить эффекты ряби" - }, - "Enable System Sounds": { - "Enable System Sounds": "Включить системные звуки" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "Включить Погоду" - }, - "Enable WiFi": { - "Enable WiFi": "Включить WiFi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Включить слой размытия, доступный для композитора (пространство имён: dms:blurwallpaper). Требуется ручная настройка niri." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Включить аутентификацию по отпечатку пальца" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Включить интеграцию блокировки loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "Включено" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Включение Wi-Fi…" - }, - "End": { - "End": "Конец" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Увеличивать при наведении" - }, - "Enlargement %": { - "Enlargement %": "Увеличение %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Введите 6-значный ключ доступа" - }, - "Enter PIN": { - "Enter PIN": "Введите пин-код" - }, - "Enter PIN for ": { - "Enter PIN for ": "Введите PIN для " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Введите URL или текст для отправки" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Введите новое имя для этого рабочего пространства" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "Введите учётные данные для " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Введите пользовательский формат экрана блокировки (например, dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Введите пользовательский формат верхней панели (например, ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Введите имя устройства..." - }, - "Enter filename...": { - "Enter filename...": "Введите имя файла..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Введите префикс запуска (например, 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Введите имя сети и пароль" - }, - "Enter passkey for ": { - "Enter passkey for ": "Введите ключ доступа для " - }, - "Enter password for ": { - "Enter password for ": "Введите пароль для " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Введите этот ключ доступа на " - }, - "Enter to Paste": { - "Enter to Paste": "Enter для вставки" - }, - "Enterprise": { - "Enterprise": "Корпоративный" - }, - "Entry pinned": { - "Entry pinned": "Запись закреплена" - }, - "Entry unpinned": { - "Entry unpinned": "Запись откреплена" - }, - "Environment Variables": { - "Environment Variables": "Переменные окружения" - }, - "Error": { - "Error": "Ошибка" - }, - "Errors": { - "Errors": "Ошибки" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Регулярное выражение" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Смещение Исключительной Зоны" - }, - "Experimental Feature": { - "Experimental Feature": "Экспериментальная функция" - }, - "Explore": { - "Explore": "Обзор" - }, - "Exponential": { - "Exponential": "Экспоненциальный" - }, - "Expressive": { - "Expressive": "Яркий" - }, - "Extend battery life": { - "Extend battery life": "Приоритет производительности" - }, - "Extensible architecture": { - "Extensible architecture": "Безопасность и конфиденциальность" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Внешнее управление обоями" - }, - "Extra Arguments": { - "Extra Arguments": "Дополнительные аргументы" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Переключить • F10: Справка" - }, - "Fade": { - "Fade": "Стирание" - }, - "Fade to lock screen": { - "Fade to lock screen": "Плавный переход к экрану блокировки" - }, - "Fade to monitor off": { - "Fade to monitor off": "Плавное выключение монитора" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Не удалось принять сопряжение" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Не удалось активировать конфигурацию" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Не удалось активировать профиль — файл не найден" - }, - "Failed to add binds include": { - "Failed to add binds include": "Не удалось добавить binds include" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Не удалось добавить принтер в класс" - }, - "Failed to browse device": { - "Failed to browse device": "Не удалось просмотреть устройство" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Не удалось отменить все задания" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Не удалось отменить выбранное задание" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Не удалось проверить лимит закрепления" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Не удалось подключиться к VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Не удалось подключиться к %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Не удалось скопировать запись" - }, - "Failed to create printer": { - "Failed to create printer": "Не удалось создать принтер" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Не удалось создать директорию Profiles" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Не удалось удалить VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Не удалось удалить Class" - }, - "Failed to delete printer": { - "Failed to delete printer": "Не удалось удалить принтер" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Не удалось отключить принятие заданий" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Не удалось отключить ночной режим" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Не удалось отключить VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Не удалось отключить VPNs" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Не удалось отключить WiFi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Не удалось включить определение местоположения по IP" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Не удалось включить WiFi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Не удалось включить принятие заданий" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Не удалось включить ночной режим" - }, - "Failed to hold job": { - "Failed to hold job": "Не удалось удержать задание" - }, - "Failed to import VPN": { - "Failed to import VPN": "Не удалось импортировать VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Не удалось запустить SMS-приложение" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Не удалось загрузить VPN config" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Не удалось загрузить конфигурацию буфера обмена." - }, - "Failed to move job": { - "Failed to move job": "Не удалось переместить задание" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Не удалось разобрать plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Не удалось разобрать session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Не удалось разобрать settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Не удалось приостановить принтер" - }, - "Failed to pin entry": { - "Failed to pin entry": "Не удалось закрепить запись" - }, - "Failed to print test page": { - "Failed to print test page": "Не удалось напечатать тестовую страницу" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Не удалось отклонить сопряжение" - }, - "Failed to remove device": { - "Failed to remove device": "Не удалось удалить устройство" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Не удалось удалить комбинацию клавиш" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Не удалось удалить принтер из класса" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Не удалось перезапустить аудиосистему" - }, - "Failed to restart job": { - "Failed to restart job": "Не удалось перезапустить задание" - }, - "Failed to resume printer": { - "Failed to resume printer": "Не удалось возобновить принтер" - }, - "Failed to ring device": { - "Failed to ring device": "Не удалось вызвать устройство" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "Не удалось сохранить аудиоконфиг" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Не удалось сохранить настройку буфера обмена" - }, - "Failed to save keybind": { - "Failed to save keybind": "Не удалось сохранить комбинацию клавиш" - }, - "Failed to save profile file": { - "Failed to save profile file": "Не удалось сохранить файл профиля" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Не удалось отправить буфер обмена" - }, - "Failed to send file": { - "Failed to send file": "Не удалось отправить файл" - }, - "Failed to send ping": { - "Failed to send ping": "Не удалось отправить ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "Не удалось установить яркость" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Не удалось установить местоположение ночного режима" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Не удалось установить расписание ночного режима" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Не удалось установить температуру ночного режима" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "Не удалось установить изображение профиля" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Не удалось установить изображение профиля: %1" - }, - "Failed to share": { - "Failed to share": "Не удалось поделиться" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Не удалось начать подключение к %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Не удалось открепить запись" - }, - "Failed to update VPN": { - "Failed to update VPN": "Не удалось обновить VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Не удалось обновить автоподключение" - }, - "Failed to update description": { - "Failed to update description": "Не удалось обновить описание" - }, - "Failed to update location": { - "Failed to update location": "Не удалось обновить местоположение" - }, - "Failed to update sharing": { - "Failed to update sharing": "Не удалось обновить общий доступ" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Не удалось записать временный файл для проверки" - }, - "Features": { - "Features": "Возможности" - }, - "Feels": { - "Feels": "Ощущается" - }, - "Feels Like": { - "Feels Like": "Ощущается как" - }, - "Feels Like %1°": { - "Feels Like %1°": "Ощущается как %1°" - }, - "Fidelity": { - "Fidelity": "Яркий" - }, - "Field": { - "Field": "Поле" - }, - "File": { - "File": "Файл" - }, - "File Already Exists": { - "File Already Exists": "Файл Уже Существует" - }, - "File Information": { - "File Information": "Информация о Файле" - }, - "File received from": { - "File received from": "Файл получен от" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Поиск файлов требует dsearch. Установите с github.com/morelazers/dsearch" - }, - "Files": { - "Files": "Файлы" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Мониторинг использования файловой системы" - }, - "Fill": { - "Fill": "Плитка вертикально" - }, - "Find in Text": { - "Find in Text": "Найти в Тексте" - }, - "Find in note...": { - "Find in note...": "Поиск по заметке..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "Завершить" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "Первоначальная настройка" - }, - "Fit": { - "Fit": "Плитка вертикально" - }, - "Fix Now": { - "Fix Now": "Исправить сейчас" - }, - "Fixing...": { - "Fixing...": "Исправление..." - }, - "Flags": { - "Flags": "Флаги" - }, - "Flipped": { - "Flipped": "Отражённый" - }, - "Flipped 180°": { - "Flipped 180°": "Перевёрнуто на 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Перевёрнуто на 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Перевёрнуто на 90°" - }, - "Float": { - "Float": "Плавающий" - }, - "Focus": { - "Focus": "Фокус" - }, - "Focus at Startup": { - "Focus at Startup": "Фокус при запуске" - }, - "Focused Border": { - "Focused Border": "Граница активного" - }, - "Focused Color": { - "Focused Color": "Цвет активного" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "Используемое Окно" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "Туман" - }, - "Folder": { - "Folder": "Папка" - }, - "Folders": { - "Folders": "Папки" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Следовать за фокусом монитора" - }, - "Follow focus": { - "Follow focus": "Следовать за фокусом" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "Семейство Шрифта" - }, - "Font Scale": { - "Font Scale": "Масштаб Шрифта" - }, - "Font Size": { - "Font Size": "Размер Шрифта" - }, - "Font Weight": { - "Font Weight": "Вес Шрифта" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "Принудительный HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Принудительно остановить (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Force Wide цвет" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Принудительно использовать тёмные цветовые схемы в терминальных приложениях" - }, - "Forecast": { - "Forecast": "Прогноз" - }, - "Forecast Days": { - "Forecast Days": "Дней прогноза" - }, - "Forecast Not Available": { - "Forecast Not Available": "Прогноз недоступен" - }, - "Forever": { - "Forever": "Навсегда" - }, - "Forget": { - "Forget": "Забыть" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Забыть \"%1\"?" - }, - "Forget Device": { - "Forget Device": "Забыть Устройство" - }, - "Forget Network": { - "Forget Network": "Забыть Сеть" - }, - "Forgot network %1": { - "Forgot network %1": "Забыть сеть %1" - }, - "Format Legend": { - "Format Legend": "Условные Обозначения" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "Освободить VRAM/память при закрытии лаунчера. Может вызвать небольшую задержку при повторном открытии." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Ледяная морось" - }, - "Frequency": { - "Frequency": "Частота" - }, - "Fruit Salad": { - "Fruit Salad": "Яркий" - }, - "Full Command:": { - "Full Command:": "Полная комманда:" - }, - "Full Content": { - "Full Content": "Полное содержимое" - }, - "Full Day & Month": { - "Full Day & Month": "Системный по умолчанию" - }, - "Full with Year": { - "Full with Year": "Системный по умолчанию" - }, - "Fullscreen": { - "Fullscreen": "Полноэкранный" - }, - "Fullscreen Only": { - "Fullscreen Only": "Только полноэкранный" - }, - "Fully Charged": { - "Fully Charged": "Подключено" - }, - "Fun": { - "Fun": "Развлечение" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: сетка • Z/X: размер" - }, - "GPU": { - "GPU": "ГП" - }, - "GPU Monitoring": { - "GPU Monitoring": "Мониторинг ГП" - }, - "GPU Temperature": { - "GPU Temperature": "Температура ГП" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDEs, и далее" - }, - "Games": { - "Games": "Игры" - }, - "Gamma Control": { - "Gamma Control": "Настройка гаммы" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Управление Gamma недоступно. Требуется DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "Общий" - }, - "Get Started": { - "Get Started": "Начать" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Глобально масштабировать все длительности анимаций" - }, - "Golden Hour": { - "Golden Hour": "Золотой час" - }, - "Good": { - "Good": "Хорошо" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Goth радиус скругления" - }, - "Goth Corners": { - "Goth Corners": "Готические Углы" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Постепенно затемнять экран перед блокировкой с настраиваемым льготным периодом" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Постепенно затемнять экран перед выключением мониторов с настраиваемым льготным периодом" - }, - "Graph Time Range": { - "Graph Time Range": "Временной диапазон графика" - }, - "Graphics": { - "Graphics": "Графика" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "Сетка" - }, - "Grid Columns": { - "Grid Columns": "Столбцы сетки" - }, - "Grid: OFF": { - "Grid: OFF": "Сетка: ВКЛ" - }, - "Grid: ON": { - "Grid: ON": "Сетка: ВКЛ" - }, - "Group": { - "Group": "Группа" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Группировать приложения рабочего пространства" - }, - "Group by App": { - "Group by App": "Группировать по Приложениям" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Группировать несколько окон одного приложения с помощью индикатора количества окон" - }, - "Group removed": { - "Group removed": "Группа удалена" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Группировать повторяющиеся значки приложений в неактивных рабочих пространствах" - }, - "Groups": { - "Groups": "Группы" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "Тонирование HDR" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "Режим HDR экспериментальный. Убедитесь, что ваш монитор поддерживает HDR, перед включением." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML скопирован в буфера обмена" - }, - "Health": { - "Health": "Здоровье" - }, - "Heavy Rain": { - "Heavy Rain": "Сильный дождь" - }, - "Heavy Snow": { - "Heavy Snow": "Сильный снег" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Сильный снегопад" - }, - "Height": { - "Height": "Высота" - }, - "Held": { - "Held": "Удерживается" - }, - "Help": { - "Help": "Помощь" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Гибернация" - }, - "Hidden": { - "Hidden": "Скрытый" - }, - "Hidden (%1)": { - "Hidden (%1)": "Скрыто (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Скрытые приложения" - }, - "Hidden Network": { - "Hidden Network": "Скрытая сеть" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Скрытые приложения не будут отображаться в лаунчере. Щёлкните ПКМ по приложению и выберите «Скрыть приложение» для скрытия." - }, - "Hide": { - "Hide": "Скрыть" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Скрыть сторонние" - }, - "Hide App": { - "Hide App": "Скрыть приложение" - }, - "Hide Delay": { - "Hide Delay": "Задержка скрытия" - }, - "Hide Indicators": { - "Hide Indicators": "Скрыть индикаторы" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Скрыть виджет обновления" - }, - "Hide When Typing": { - "Hide When Typing": "Скрывать когда печатаешь" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Скрывать при открытых окнах" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Скрывать курсор после бездействия (0 = отключено)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Скрывать курсор при нажатии клавиш клавиатуры" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Скрывать курсор при использовании сенсорного ввода" - }, - "Hide device": { - "Hide device": "Скрыть устройство" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Скрывать содержимое уведомления до развёртывания" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Скрывать содержимое уведомления до развёртывания; всплывающие окна показываются свёрнутыми по умолчанию" - }, - "Hide on Touch": { - "Hide on Touch": "Скрывать при касании" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Высокоточная палитра, сохраняющая исходные оттенки." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "История" - }, - "History Retention": { - "History Retention": "Хранение истории" - }, - "History Settings": { - "History Settings": "Историю Настройки" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "История очищена. %1 закреплённых записей сохранено." - }, - "Hold Duration": { - "Hold Duration": "Длительность удержания" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Удерживайте дольше для подтверждения" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Удерживать для подтверждения действий питания" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Удерживать для подтверждения (%1 мс)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Удерживать для подтверждения (%1 с)" - }, - "Home": { - "Home": "Домой" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "Имя хоста" - }, - "Hot Corners": { - "Hot Corners": "Горячие углы" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Заголовок наложения горячей клавиши (необязательно)" - }, - "Hour": { - "Hour": "Час" - }, - "Hourly": { - "Hourly": "Почасовой" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Количество почасовых прогнозов" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Как часто изменять обои" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "Влажность" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Переопределения макета Hyprland" - }, - "Hyprland Options": { - "Hyprland Options": "Опции Hyprland" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "Я Понимаю" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP-адрес:" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "Системный по умолчанию" - }, - "Icon": { - "Icon": "Значок" - }, - "Icon Scale": { - "Icon Scale": "Масштаб значка" - }, - "Icon Size": { - "Icon Size": "Размер иконок" - }, - "Icon Size %": { - "Icon Size %": "Размер значка %" - }, - "Icon Theme": { - "Icon Theme": "Тема Значков" - }, - "Idle": { - "Idle": "Бездействие" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Ингибитор бездействия" - }, - "Idle Settings": { - "Idle Settings": "Настройки бездействия" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Мониторинг бездействия не поддерживается — требуется более новая версия Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Если поле скрыто, оно появится сразу после нажатия клавиши." - }, - "Ignore Completely": { - "Ignore Completely": "Только всплывающее" - }, - "Image": { - "Image": "Изображение" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Изображение скопировано в буфера обмена" - }, - "Import": { - "Import": "Импорт" - }, - "Import VPN": { - "Import VPN": "Импортировать VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Цвет неактивного монитора" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Включить переходы" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Включить действия рабочего стола (ярлыки) в результаты поиска." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Загружены несовместимые плагины" - }, - "Incorrect password": { - "Incorrect password": "Неправильный пароль" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Индикатор Стиль" - }, - "Individual Batteries": { - "Individual Batteries": "Отдельные батареи" - }, - "Individual bar configuration": { - "Individual bar configuration": "Индивидуальная конфигурация бара" - }, - "Info": { - "Info": "Информация" - }, - "Inherit": { - "Inherit": "Наследовать" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "Блокируемый" - }, - "Input Devices": { - "Input Devices": "Устройства Ввода" - }, - "Input Volume Slider": { - "Input Volume Slider": "Вход Громкость Ползунок" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Установить" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "Установить дополнение" - }, - "Install Theme": { - "Install Theme": "Установить тему" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Установить цветовые темы из реестра тем DMS" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "Ошибка установки: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Установите пакет matugen для динамического оформления" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Установить дополнение '%1' из реестра DMS?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Установить дополнения из репозитория DMS" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Установить тему '%1' из реестра DMS?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "Установлено" - }, - "Installed: %1": { - "Installed: %1": "Установлено: %1" - }, - "Installing: %1": { - "Installing: %1": "Установка: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Умное автоскрытие" - }, - "Intensity": { - "Intensity": "Интенсивность" - }, - "Interface:": { - "Interface:": "Интерфейс:" - }, - "Interlock Open": { - "Interlock Open": "Interlock открыт" - }, - "Internet": { - "Internet": "Интернет" - }, - "Interval": { - "Interval": "Интервал" - }, - "Invalid configuration": { - "Invalid configuration": "Недействительная конфигурация" - }, - "Invert on mode change": { - "Invert on mode change": "Инвертировать при смене режима" - }, - "Iris Bloom": { - "Iris Bloom": "Стирание" - }, - "Isolate Displays": { - "Isolate Displays": "Изолировать дисплеи" - }, - "Jobs": { - "Jobs": "Задания" - }, - "Jobs: ": { - "Jobs: ": "Задания: " - }, - "Keep Awake": { - "Keep Awake": "Не спать" - }, - "Keep Changes": { - "Keep Changes": "Сохранить изменения" - }, - "Keeping Awake": { - "Keeping Awake": "Не спит" - }, - "Kernel": { - "Kernel": "Ядро" - }, - "Key": { - "Key": "Ключ" - }, - "Keybind Sources": { - "Keybind Sources": "Источники комбинаций клавиш" - }, - "Keybinds": { - "Keybinds": "Темы и цвета" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Настройки поиска комбинаций клавиш" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Комбинации клавиш показываются вместе с обычными результатами поиска" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Наименование Раскладки Клавиатуры" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Горячие клавиши" - }, - "Keys": { - "Keys": "Ключи" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "Завершить Процесс" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED устройство" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "Большой" - }, - "Largest": { - "Largest": "Крупнейший" - }, - "Last hour": { - "Last hour": "Вчера" - }, - "Last launched %1": { - "Last launched %1": "Последние запущененные %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "Последний запуск только что" - }, - "Latitude": { - "Latitude": "Широта" - }, - "Launch": { - "Launch": "Запустить" - }, - "Launch Prefix": { - "Launch Prefix": "Префикс Запуска" - }, - "Launch on dGPU": { - "Launch on dGPU": "Запустить на дискретной видеокарте" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Лаунчер" - }, - "Launcher Button": { - "Launcher Button": "Кнопка лаунчера" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Логотип кнопки лаунчера" - }, - "Layout": { - "Layout": "Макет" - }, - "Layout Overrides": { - "Layout Overrides": "Переопределения макета" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Слева" - }, - "Left Center": { - "Left Center": "Вверху справа" - }, - "Left Section": { - "Left Section": "Левая секция" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "Светлый Режим" - }, - "Light Rain": { - "Light Rain": "Легкий дождь" - }, - "Light Snow": { - "Light Snow": "Легкий снег" - }, - "Light Snow Showers": { - "Light Snow Showers": "Лёгкий снегопад" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "Линия" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "Линейный" - }, - "Lines: %1": { - "Lines: %1": "Строки: %1" - }, - "List": { - "List": "Список" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Живая палитра с насыщенными акцентами." - }, - "Load Average": { - "Load Average": "Средняя загрузка" - }, - "Loading codecs...": { - "Loading codecs...": "Загрузка кодеков..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Загрузка комбинаций клавиш..." - }, - "Loading trending...": { - "Loading trending...": "Загрузка трендов..." - }, - "Loading...": { - "Loading...": "Загрузка..." - }, - "Local": { - "Local": "Локальный" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "Местоположение" - }, - "Location Search": { - "Location Search": "Поиск Местоположения" - }, - "Lock": { - "Lock": "Блокировка" - }, - "Lock Screen": { - "Lock Screen": "Экран Блокировки" - }, - "Lock Screen Display": { - "Lock Screen Display": "Дисплей экрана блокировки" - }, - "Lock Screen Format": { - "Lock Screen Format": "Формат Экрана Блокировки" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Поведение экрана блокировки" - }, - "Lock Screen layout": { - "Lock Screen layout": "Макет экрана блокировки" - }, - "Lock at startup": { - "Lock at startup": "Блокировка при запуске" - }, - "Lock before suspend": { - "Lock before suspend": "Блокировка перед приостановкой" - }, - "Lock fade grace period": { - "Lock fade grace period": "Льготный период затухания блокировки" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "Заблокировано" - }, - "Log Out": { - "Log Out": "Выйти" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "Длинный" - }, - "Long Text": { - "Long Text": "Длинный Текст" - }, - "Long press": { - "Long press": "Долгое нажатие" - }, - "Longitude": { - "Longitude": "Долгота" - }, - "Low Priority": { - "Low Priority": "Низкий Приоритет" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Убедитесь, что KDE Connect или Valent запущены на других устройствах" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Управление и настройка дополнений для расширения функционала DMS" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Управление до 4 независимыми конфигурациями панели. Каждая панель имеет собственную позицию, виджетов, стиль и назначение Display." - }, - "Management": { - "Management": "Управление" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "Переопределения макета MangoWC" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "Свои Координаты" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "Ручной размер отступа" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Ручное Отображение/Скрытие" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Сопоставить имена классов окон с именами значков для правильного отображения значков" - }, - "Margin": { - "Margin": "Поле" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Marker Supply пусто" - }, - "Marker Supply Low": { - "Marker Supply Low": "Marker Supply низко" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Marker Waste почти полно" - }, - "Marker Waste Full": { - "Marker Waste Full": "Marker Waste полно" - }, - "Match Criteria": { - "Match Criteria": "Критерии соответствия" - }, - "Matches profile: %1": { - "Matches profile: %1": "Соответствует профилю: %1" - }, - "Material Colors": { - "Material Colors": "Акцентные Цвета" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Цветовые темы в стиле Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Цветовая палитра Material, созданная из обоев" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen отсутствует" - }, - "Matugen Palette": { - "Matugen Palette": "Палитра Matugen" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Целевой монитор Matugen" - }, - "Matugen Templates": { - "Matugen Templates": "Шаблоны Matugen" - }, - "Max Edges": { - "Max Edges": "Макс краёв" - }, - "Max H": { - "Max H": "Макс В" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Макс закреплённых приложений" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Макс закреплённых приложений (0 = безлимитно)" - }, - "Max Running Apps": { - "Max Running Apps": "Макс запущенных приложений" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Макс запущенных приложений (0 = безлимитно)" - }, - "Max Volume": { - "Max Volume": "Максимальная громкость" - }, - "Max W": { - "Max W": "Макс Ш" - }, - "Max apps to show": { - "Max apps to show": "Максимальное количество приложений для отображения" - }, - "Max to Edges": { - "Max to Edges": "Макс до краёв" - }, - "Maximize": { - "Maximize": "Развернуть" - }, - "Maximize Detection": { - "Maximize Detection": "Максимизировать обнаружение" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Максимизировать значки виджетов" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Максимизировать текст виджетов" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Максимальный размер записи" - }, - "Maximum History": { - "Maximum History": "Максимум истории" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Максимум закреплённых записей" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Максимальное количество записей буфера обмена для хранения" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Максимальное количество записей, которые можно сохранить" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Максимальное количество уведомлений для хранения" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Достигнуто максимальное количество закреплённых записей" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Максимальный размер одной записи буфера обмена" - }, - "Media": { - "Media": "Медиа" - }, - "Media Controls": { - "Media Controls": "Управление Медиа" - }, - "Media Empty": { - "Media Empty": "Медиа пусто" - }, - "Media Jam": { - "Media Jam": "Media Jam" - }, - "Media Low": { - "Media Low": "Медиа низко" - }, - "Media Needed": { - "Media Needed": "Медиа требуется" - }, - "Media Playback": { - "Media Playback": "Воспроизведение медиа" - }, - "Media Player": { - "Media Player": "Медиаплеер" - }, - "Media Player Settings": { - "Media Player Settings": "Настройки Медиаплеера" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "Медиаплееры (" - }, - "Media Volume": { - "Media Volume": "Громкость медиа" - }, - "Medium": { - "Medium": "Средний" - }, - "Memory": { - "Memory": "Память" - }, - "Memory Graph": { - "Memory Graph": "График памяти" - }, - "Memory Usage": { - "Memory Usage": "Использование Памяти" - }, - "Memory usage indicator": { - "Memory usage indicator": "Индикатор Использования Памяти" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Сообщение" - }, - "Message Content": { - "Message Content": "Содержимое сообщения" - }, - "Microphone": { - "Microphone": "Микрофон" - }, - "Microphone Mute": { - "Microphone Mute": "Микрофон отключён" - }, - "Microphone Volume": { - "Microphone Volume": "Громкость микрофона" - }, - "Microphone settings": { - "Microphone settings": "Настройки микрофона" - }, - "Microphone volume control": { - "Microphone volume control": "Управление громкостью микрофона" - }, - "Middle Section": { - "Middle Section": "Средняя секция" - }, - "Min H": { - "Min H": "Мин В" - }, - "Min W": { - "Min W": "Мин Ш" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Минимальная палитра, встроенная вокруг одного оттенка." - }, - "Minute": { - "Minute": "Минута" - }, - "Mirror Display": { - "Mirror Display": "Зеркальный дисплей" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Отсутствующие переменные окружения" - }, - "Modal Background": { - "Modal Background": "Фон модального окна" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "Модальные окна" - }, - "Mode": { - "Mode": "Режим" - }, - "Mode:": { - "Mode:": "Режим:" - }, - "Model": { - "Model": "Модель" - }, - "Modified": { - "Modified": "Изменено" - }, - "Modular widget bar": { - "Modular widget bar": "Безопасность и конфиденциальность" - }, - "Monitor": { - "Monitor": "Монитор" - }, - "Monitor Configuration": { - "Monitor Configuration": "Конфигурация монитора" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Льготный период затухания монитора" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Монитор, чьи обои определяют цвета динамической темы" - }, - "Monochrome": { - "Monochrome": "Яркий" - }, - "Monocle": { - "Monocle": "Монокль" - }, - "Monospace Font": { - "Monospace Font": "Моноширинный Шрифт" - }, - "Month Date": { - "Month Date": "Системный по умолчанию" - }, - "Morning": { - "Morning": "Утро" - }, - "Mount Points": { - "Mount Points": "Точки монтирования" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Внешний вид указателя мыши" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Размер указателя мыши в пикселях" - }, - "Move": { - "Move": "Переместить" - }, - "Move Widget": { - "Move Widget": "Переместить виджет" - }, - "Moving to Paused": { - "Moving to Paused": "Перемещение в Paused" - }, - "Multi-Monitor": { - "Multi-Monitor": "Мульти-мониторы" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "Музыка" - }, - "Mute Popups": { - "Mute Popups": "Только всплывающее" - }, - "Mute popups for %1": { - "Mute popups for %1": "Отключить всплывающие окна для %1" - }, - "Muted": { - "Muted": "Выбрать устройство" - }, - "Muted Apps": { - "Muted Apps": "Отключённые приложения" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Приглушённая палитра со спокойными тонами." - }, - "NM not supported": { - "NM not supported": "NM не поддерживается" - }, - "Name": { - "Name": "Имя" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Значки Именованных Рабочих Пространств" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "Навигация" - }, - "Network": { - "Network": "Сеть" - }, - "Network Graph": { - "Network Graph": "График сети" - }, - "Network Info": { - "Network Info": "Информация о Сети" - }, - "Network Information": { - "Network Information": "Информация о Сети" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Имя сети (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Отслеживание Скорости Сети" - }, - "Network Status": { - "Network Status": "Статус сети" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Отображение скорости скачивания и загрузки данных по сети" - }, - "Neutral": { - "Neutral": "Яркий" - }, - "Never": { - "Never": "Никогда" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "Новый" - }, - "New Key": { - "New Key": "Новый ключ" - }, - "New Keybind": { - "New Keybind": "Новая комбинация клавиш" - }, - "New Notification": { - "New Notification": "Новое уведомление" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "Новое правило окна" - }, - "New York, NY": { - "New York, NY": "Нью-Йорк, NY" - }, - "New group name...": { - "New group name...": "Новое название группы..." - }, - "Next": { - "Next": "Далее" - }, - "Next Transition": { - "Next Transition": "Следующий переход" - }, - "Night": { - "Night": "Ночь" - }, - "Night Mode": { - "Night Mode": "Ночной Режим" - }, - "Night Temperature": { - "Night Temperature": "Ночная температура" - }, - "Night mode & gamma": { - "Night mode & gamma": "Безопасность и конфиденциальность" - }, - "Niri Integration": { - "Niri Integration": "Интеграция Niri" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Переопределения макета Niri" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Действия композитора Niri (фокус, перемещение и т.д.)" - }, - "No": { - "No": "Нет" - }, - "No Active Players": { - "No Active Players": "Нет Активных Проигрывателей" - }, - "No Anim": { - "No Anim": "Без анимации" - }, - "No Background": { - "No Background": "Без Заднего Фона" - }, - "No Battery": { - "No Battery": "Подключено" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Адаптер Bluetooth не найден" - }, - "No Blur": { - "No Blur": "Без размытия" - }, - "No Border": { - "No Border": "Без границы" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Комбинации клавиш DMS не настроены" - }, - "No Dim": { - "No Dim": "Без затемнения" - }, - "No Focus": { - "No Focus": "Нет фокуса" - }, - "No GPU detected": { - "No GPU detected": "GPU не обнаружен" - }, - "No GPUs detected": { - "No GPUs detected": "ГП не обнаружены" - }, - "No History": { - "No History": "Только всплывающее" - }, - "No Media": { - "No Media": "Нет Медиа" - }, - "No Round": { - "No Round": "Без скругления" - }, - "No Rounding": { - "No Rounding": "Без скругления" - }, - "No Shadow": { - "No Shadow": "Без тени" - }, - "No VPN profiles": { - "No VPN profiles": "Нет профилей VPN" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "Нету данных о погоде" - }, - "No Weather Data Available": { - "No Weather Data Available": "Нет Данных о Погоде" - }, - "No action": { - "No action": "Нет действия" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "Выкл" - }, - "No adapters": { - "No adapters": "Нет адаптеров" - }, - "No app customizations.": { - "No app customizations.": "Настроек приложений нет." - }, - "No apps found": { - "No apps found": "Приложения не найдены" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Приложения ещё не запускались." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Приложения не отключены. Щёлкните ПКМ по уведомлению и выберите «Отключить всплывающие» для добавления сюда." - }, - "No battery": { - "No battery": "Нет батареи" - }, - "No brightness devices available": { - "No brightness devices available": "Устройства яркости недоступны" - }, - "No changes": { - "No changes": "Нет изменений" - }, - "No checks passed": { - "No checks passed": "Нет предупреждений" - }, - "No custom theme file": { - "No custom theme file": "Нет пользовательского файла темы" - }, - "No devices": { - "No devices": "Нет устройств" - }, - "No devices connected": { - "No devices connected": "Нет подключённых устройств" - }, - "No devices found": { - "No devices found": "Устройства не найдены" - }, - "No disk data": { - "No disk data": "Нет данных о диске" - }, - "No disk data available": { - "No disk data available": "Данные о диске недоступны" - }, - "No drivers found": { - "No drivers found": "Драйверы не найдены" - }, - "No errors": { - "No errors": "Нет ошибок" - }, - "No features enabled": { - "No features enabled": "Функции не включены" - }, - "No files found": { - "No files found": "Файлы не найдены" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "Папки не найдены" - }, - "No hidden apps.": { - "No hidden apps.": "Нет скрытых приложений." - }, - "No info items": { - "No info items": "Нет предупреждений" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "Выбрать устройство" - }, - "No input devices found": { - "No input devices found": "Устройства вывода не найдены" - }, - "No items added yet": { - "No items added yet": "Ни один элемент ещё не добавлен" - }, - "No keybinds found": { - "No keybinds found": "Комбинации клавиш не найдены" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Плагины лаунчера не установлены." - }, - "No match criteria": { - "No match criteria": "Нет критериев совпадения" - }, - "No matches": { - "No matches": "Нет совпадений" - }, - "No matching processes": { - "No matching processes": "Нет соответствующих процессов" - }, - "No monitors": { - "No monitors": "Нет мониторов" - }, - "No mount points found": { - "No mount points found": "Точки монтирования не найдены" - }, - "No output device": { - "No output device": "Выбрать устройство" - }, - "No output devices found": { - "No output devices found": "Устройства вывода не найдены" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "Нет результатов плагинов" - }, - "No plugins found": { - "No plugins found": "Дополнения не найдены" - }, - "No plugins found.": { - "No plugins found.": "Дополнения не найдены." - }, - "No printer found": { - "No printer found": "Принтер не найден" - }, - "No printers configured": { - "No printers configured": "Принтеры не настроены" - }, - "No printers found": { - "No printers found": "Принтеры не найдены" - }, - "No profiles": { - "No profiles": "Нет профилей" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Недавние записи буфера обмена не найдены" - }, - "No results found": { - "No results found": "Ничего не найдено" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Сохранённые записи буфера обмена отсутствуют" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "Темы не найдены" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Темы не установлены. Просмотрите темы для установки из реестра." - }, - "No trigger": { - "No trigger": "Нет триггера" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "Обои не выбраны" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Обои не найдены\n\nНажмите на значок папки ниже для просмотра" - }, - "No warnings": { - "No warnings": "Нет предупреждений" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Виджеты не добавлены. Нажмите «Добавить виджет» для начала." - }, - "No widgets available": { - "No widgets available": "Нет доступных виджетов" - }, - "No widgets match your search": { - "No widgets match your search": "Ни один виджет не соответствует вашему поиску" - }, - "No window rules configured": { - "No window rules configured": "Правила окон не настроены" - }, - "None": { - "None": "Нет" - }, - "Normal": { - "Normal": "Нормальный" - }, - "Normal Font": { - "Normal Font": "Обычный шрифт" - }, - "Normal Priority": { - "Normal Priority": "Обычный Приоритет" - }, - "Not available": { - "Not available": "Недоступно" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "Не подключено" - }, - "Not detected": { - "Not detected": "Не обнаружено" - }, - "Not paired": { - "Not paired": "Не сопряжено" - }, - "Not set": { - "Not set": "Не установлено" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Примечание: это изменяет только процент, это фактически не ограничивает зарядку." - }, - "Notepad": { - "Notepad": "Блокнот" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Настройки Шрифта Блокнота" - }, - "Notepad Slideout": { - "Notepad Slideout": "Выезжающий блокнот" - }, - "Nothing": { - "Nothing": "Ничего" - }, - "Nothing to see here": { - "Nothing to see here": "Здесь не на что смотреть" - }, - "Notification Center": { - "Notification Center": "Центр Уведомлений" - }, - "Notification Display": { - "Notification Display": "Отображение уведомлений" - }, - "Notification Overlay": { - "Notification Overlay": "Наложение уведомлений" - }, - "Notification Popups": { - "Notification Popups": "Всплывающие уведомление" - }, - "Notification Rules": { - "Notification Rules": "Правила уведомлений" - }, - "Notification Settings": { - "Notification Settings": "Настройки Уведомлений" - }, - "Notification Timeouts": { - "Notification Timeouts": "Задержка Уведомлений" - }, - "Notification toast popups": { - "Notification toast popups": "Всплывающие уведомления-тосты" - }, - "Notifications": { - "Notifications": "Уведомления" - }, - "Numbers": { - "Numbers": "Числа" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Системный по умолчанию" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Системный по умолчанию" - }, - "OK": { - "OK": "ОК" - }, - "OS Logo": { - "OS Logo": "Логотип ОС" - }, - "OSD Position": { - "OSD Position": "Позиция OSD" - }, - "Occupied Color": { - "Occupied Color": "Цвет занятого" - }, - "Off": { - "Off": "Выкл" - }, - "Office": { - "Office": "Офис" - }, - "Offline": { - "Offline": "Оффлайн" - }, - "Offline Report": { - "Offline Report": "Офлайн отчёт" - }, - "Older": { - "Older": "Старее" - }, - "On": { - "On": "Вкл" - }, - "On-Demand": { - "On-Demand": "По требованию" - }, - "On-Screen Displays": { - "On-Screen Displays": "Наэкранные отображения" - }, - "On-screen Displays": { - "On-screen Displays": "Наэкранные отображения" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Регулировать цветовую температуру только на основе правил времени или местоположения." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Показывать только окна с текущего монитора на каждом доке" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Видно только если ваша система поддерживает гибернацию" - }, - "Opacity": { - "Opacity": "Непрозрачность" - }, - "Opaque": { - "Opaque": "Непрозрачный" - }, - "Open": { - "Open": "Открыть" - }, - "Open App": { - "Open App": "Открыть приложение" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Откройте KDE Connect на телефоне" - }, - "Open Notepad File": { - "Open Notepad File": "Открыть Файл Блокнота" - }, - "Open a new note": { - "Open a new note": "Открыть новую заметку" - }, - "Open folder": { - "Open folder": "Открыть папку" - }, - "Open in Browser": { - "Open in Browser": "Открыть в браузере" - }, - "Open in terminal": { - "Open in terminal": "Открыть в терминале" - }, - "Open search bar to find text": { - "Open search bar to find text": "Открыть строку для поиска текста" - }, - "Open with...": { - "Open with...": "Открыть с помощью..." - }, - "Opening SMS": { - "Opening SMS": "Открытие SMS-приложения" - }, - "Opening SMS app": { - "Opening SMS app": "Открытие SMS-приложения" - }, - "Opening file browser": { - "Opening file browser": "Открытие файлового менеджера" - }, - "Opening files": { - "Opening files": "Открытие файлов" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "Необязательное описание" - }, - "Optional location": { - "Optional location": "Необязательное местоположение" - }, - "Options": { - "Options": "Опции" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Организовать виджеты в сворачиваемые группы" - }, - "Original: %1": { - "Original: %1": "Оригинал: %1" - }, - "Other": { - "Other": "Другое" - }, - "Outline": { - "Outline": "Контур" - }, - "Output": { - "Output": "Вывод" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Область вывода почти заполнена" - }, - "Output Area Full": { - "Output Area Full": "Область вывода заполнена" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "Устройства вывода" - }, - "Output Tray Missing": { - "Output Tray Missing": "Выходной лоток отсутствует" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Outputs Include отсутствует" - }, - "Overcast": { - "Overcast": "Пасмурно" - }, - "Overflow": { - "Overflow": "Переполнение" - }, - "Overridden by config": { - "Overridden by config": "Переопределено конфигурацией" - }, - "Override": { - "Override": "Переопределить" - }, - "Override Border Size": { - "Override Border Size": "Переопределение размера границы" - }, - "Override Corner Radius": { - "Override Corner Radius": "Переопределить радиус углов" - }, - "Override Gaps": { - "Override Gaps": "Переопределение отступов" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Переопределить глобальные настройки макета для этого выхода" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "Переопределения" - }, - "Overview": { - "Overview": "Обзор" - }, - "Overview of your network connections": { - "Overview of your network connections": "Обзор ваших сетевых подключений" - }, - "Overwrite": { - "Overwrite": "Перезаписать" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Плитка вертикально" - }, - "Pad Hours": { - "Pad Hours": "Пад часы" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Отступ" - }, - "Pair": { - "Pair": "Сопряжение" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Сопрячь устройство Bluetooth" - }, - "Paired": { - "Paired": "Сопряжено" - }, - "Pairing": { - "Pairing": "Сопряжение" - }, - "Pairing failed": { - "Pairing failed": "Сопряжение не удалось" - }, - "Pairing request from": { - "Pairing request from": "Запрос сопряжения от" - }, - "Pairing request sent": { - "Pairing request sent": "Запрос сопряжения отправлен" - }, - "Pairing requested": { - "Pairing requested": "Запрос сопряжения отправлен" - }, - "Pairing...": { - "Pairing...": "Сопряжение..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Переменная облачность" - }, - "Passkey:": { - "Passkey:": "Ключ доступа:" - }, - "Password": { - "Password": "Пароль" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "Вставить" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "Шаблон" - }, - "Pause": { - "Pause": "Пауза" - }, - "Paused": { - "Paused": "На паузе" - }, - "Pending": { - "Pending": "Ожидание" - }, - "Pending Charge": { - "Pending Charge": "Подключено" - }, - "Pending Discharge": { - "Pending Discharge": "Подключено" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Обои для режима" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Обои для монитора" - }, - "Per-screen config": { - "Per-screen config": "Безопасность и конфиденциальность" - }, - "Percentage": { - "Percentage": "Процент" - }, - "Performance": { - "Performance": "Производительность" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Отказано в доступе при установки изображения профиля." - }, - "Personalization": { - "Personalization": "Персонализация" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect недоступен" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Phone Connect недоступен" - }, - "Phone number": { - "Phone number": "Номер телефона" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "Картинки" - }, - "Pin": { - "Pin": "Закрепить" - }, - "Pin to Dock": { - "Pin to Dock": "Закрепить в Доке" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping отправлен на" - }, - "Ping sent to": { - "Ping sent to": "Ping отправлен на" - }, - "Pinned": { - "Pinned": "Закреплено" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Закреплённые и запущенные приложения с перетаскиванием" - }, - "Pixelate": { - "Pixelate": "Стирание" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Поместите каталоги дополнений здесь. Каждое дополнение должно иметь файл plugin.json в качестве манифеста." - }, - "Place plugins in %1": { - "Place plugins in %1": "Поместите плагины в %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Проигрывать звук при новом уведомление" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Проигрывать звук при подключение кабеля питания" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Воспроизводить звук при регулировке громкости" - }, - "Play sounds for system events": { - "Play sounds for system events": "Проигрывать звук при событиях системы" - }, - "Playback": { - "Playback": "Воспроизведение" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "Пожалуйста, подождите…" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "Подключено" - }, - "Plugged in": { - "Plugged in": "Подключено" - }, - "Plugin": { - "Plugin": "Плагин" - }, - "Plugin Directory": { - "Plugin Directory": "Каталог Дополнений" - }, - "Plugin Management": { - "Plugin Management": "Управление Дополнениями" - }, - "Plugin Visibility": { - "Plugin Visibility": "Видимость плагинов" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Дополнение отключено - для использования включите в настройках дополнений" - }, - "Plugins": { - "Plugins": "Дополнения" - }, - "Pointer": { - "Pointer": "Указатель" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "Всплывающие окна" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Всплывающие окна и модальные следуют глобальной скорости анимации (отключите для независимой настройки)" - }, - "Popup Only": { - "Popup Only": "Только всплывающее" - }, - "Popup Position": { - "Popup Position": "Позиция Всплывающего Окна" - }, - "Popup Shadow": { - "Popup Shadow": "Тень всплывающего" - }, - "Popup Transparency": { - "Popup Transparency": "Прозрачность Всплывающего Окна" - }, - "Popup behavior, position": { - "Popup behavior, position": "Поведение всплывающих окон, позиция" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "Стирание" - }, - "Position": { - "Position": "Позиция" - }, - "Position, pinned apps": { - "Position, pinned apps": "Позиция, закреплённые приложения" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Возможные конфликты переопределения" - }, - "Power": { - "Power": "Питание" - }, - "Power & Security": { - "Power & Security": "Питание & Безопасность" - }, - "Power & Sleep": { - "Power & Sleep": "Питание и сон" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Подтверждение действия питания" - }, - "Power Menu Customization": { - "Power Menu Customization": "Настройка меню питания" - }, - "Power Off": { - "Power Off": "Завершить Работу" - }, - "Power Options": { - "Power Options": "Параметры Питания" - }, - "Power Profile": { - "Power Profile": "Профиль питания" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Ухудшение Профиля Питания" - }, - "Power Saver": { - "Power Saver": "Экономия энергии" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Выключить мониторы при блокировке" - }, - "Power profile management available": { - "Power profile management available": "Управление профилями питания доступно" - }, - "Power source": { - "Power source": "Источник питания" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "Осадки" - }, - "Precipitation": { - "Precipitation": "Осадки" - }, - "Precipitation Chance": { - "Precipitation Chance": "Вероятность осадков" - }, - "Preference": { - "Preference": "Предпочтение" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Предустановленные ширины (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Нажмите Enter, и аудиосистема перезапустится для применения изменений" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Нажмите Enter для вставки, Shift+Enter для копирования" - }, - "Press key...": { - "Press key...": "Нажмите клавишу..." - }, - "Pressure": { - "Pressure": "Давление" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Предотвращение тайм-аута экрана" - }, - "Preview": { - "Preview": "Предпросмотр" - }, - "Primary": { - "Primary": "Основной" - }, - "Primary Container": { - "Primary Container": "Вариант поверхности" - }, - "Print Server Management": { - "Print Server Management": "Управление Print Server" - }, - "Print Server not available": { - "Print Server not available": "Print Server недоступен" - }, - "Printer": { - "Printer": "Принтер" - }, - "Printer Classes": { - "Printer Classes": "Классы принтеров" - }, - "Printer created successfully": { - "Printer created successfully": "Принтер успешно создан" - }, - "Printer deleted": { - "Printer deleted": "Принтер удалён" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Имя принтера (без пробелов)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "Принтеры" - }, - "Printers: ": { - "Printers: ": "Принтеры: " - }, - "Prioritize performance": { - "Prioritize performance": "Приоритет производительности" - }, - "Priority": { - "Priority": "Приоритет" - }, - "Privacy Indicator": { - "Privacy Indicator": "Индикатор Конфиденциальности" - }, - "Privacy Mode": { - "Privacy Mode": "Режим конфиденциальности" - }, - "Private Key Password": { - "Private Key Password": "Пароль приватного ключа" - }, - "Process Count": { - "Process Count": "Количество процессов" - }, - "Processes": { - "Processes": "Процессы" - }, - "Processes:": { - "Processes:": "Процессы:" - }, - "Processing": { - "Processing": "Обработка" - }, - "Profile Image Error": { - "Profile Image Error": "Ошибка изображения профиля" - }, - "Profile activated: %1": { - "Profile activated: %1": "Профиль активирован: %1" - }, - "Profile deleted": { - "Profile deleted": "Профиль удалён" - }, - "Profile error": { - "Profile error": "Ошибка профиля" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Изображение профиля слишком велико. Используйте изображение меньшего размера." - }, - "Profile name": { - "Profile name": "Имя профиля" - }, - "Profile not found": { - "Profile not found": "Профиль не найден" - }, - "Profile saved: %1": { - "Profile saved: %1": "Профиль сохранён: %1" - }, - "Protocol": { - "Protocol": "Протокол" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "Быстрый доступ" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Быстрый доступ к меню запуска приложений" - }, - "Quick access to color picker": { - "Quick access to color picker": "Быстрый доступ к выбору цвета" - }, - "Quick access to notepad": { - "Quick access to notepad": "Быстрый доступ к блокноту" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Выезжающая панель для быстрых заметок" - }, - "Quick system toggles": { - "Quick system toggles": "Безопасность и конфиденциальность" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Радиус" - }, - "Rain": { - "Rain": "Дождь" - }, - "Rain Chance": { - "Rain Chance": "Вероятность Осадков" - }, - "Rainbow": { - "Rainbow": "Яркий" - }, - "Random": { - "Random": "Стирание" - }, - "Rate": { - "Rate": "Частота" - }, - "Read:": { - "Read:": "Прочитано:" - }, - "Reason": { - "Reason": "Причина" - }, - "Reboot": { - "Reboot": "Перезагрузка" - }, - "Recent Colors": { - "Recent Colors": "Недавние Цвета" - }, - "Recently Used Apps": { - "Recently Used Apps": "Недавно Использованные Приложения" - }, - "Recommended available": { - "Recommended available": "Рекомендуемое доступно" - }, - "Refresh": { - "Refresh": "Обновить" - }, - "Refresh Weather": { - "Refresh Weather": "Обновить погоду" - }, - "Regex": { - "Regex": "Регулярное выражение" - }, - "Reject": { - "Reject": "Отклонить" - }, - "Reject Jobs": { - "Reject Jobs": "Отклонить задания" - }, - "Release": { - "Release": "Релиз" - }, - "Reload Plugin": { - "Reload Plugin": "Перезагрузить плагин" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "Удалить" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Убрать отступ виджета" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Убрать отступы и границу когда окна развёрнуты" - }, - "Rename": { - "Rename": "Переименовать" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "Переименовать рабочую область" - }, - "Repeat": { - "Repeat": "Повторить" - }, - "Replacement": { - "Replacement": "Замена" - }, - "Report": { - "Report": "Отчёт" - }, - "Request Pairing": { - "Request Pairing": "Запрос сопряжения" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Требовать удержания кнопки/клавиши для подтверждения выключения, перезапуска, приостановки, гибернации и выхода" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "Требуется %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Требуется инструмент 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "Требуется DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Требуется композитор DWL" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Требуется поддержка ночного режима" - }, - "Reset": { - "Reset": "Сбросить" - }, - "Reset Position": { - "Reset Position": "Сбросить позицию" - }, - "Reset Size": { - "Reset Size": "Сбросить размер" - }, - "Reset to default name": { - "Reset to default name": "Сбросить к имени по умолчанию" - }, - "Resize Widget": { - "Resize Widget": "Изменить размер виджета" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Разрешение и обновление" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Разрешение, позиция, масштаб" - }, - "Restart DMS": { - "Restart DMS": "Перезагрузить DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Перезагрузить DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Перезапуск аудиосистемы..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Продолжить" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Обратить направление прокрутки" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Обратить направление переключения рабочих пространств при прокрутке на панели" - }, - "Revert": { - "Revert": "Инвертировать" - }, - "Right": { - "Right": "Справа" - }, - "Right Center": { - "Right Center": "Вверху справа" - }, - "Right Section": { - "Right Section": "Правая секция" - }, - "Right Tiling": { - "Right Tiling": "Правый тайлинг" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Щёлкните ПКМ и перетащите в любом месте виджета" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Щёлкните ПКМ и перетащите за нижний правый угол" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Щёлкните ПКМ по виджету панели для переключения" - }, - "Ring": { - "Ring": "Вызов" - }, - "Ringing": { - "Ringing": "Вызов" - }, - "Ripple Effects": { - "Ripple Effects": "Эффекты ряби" - }, - "Root Filesystem": { - "Root Filesystem": "Корневая файловая система" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Скруглённые углы для окон" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Скруглённые углы для окон (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Скруглённые углы для окон (decoration.rounding)" - }, - "Rule": { - "Rule": "Правило" - }, - "Rule Name": { - "Rule Name": "Имя правила" - }, - "Rules (%1)": { - "Rules (%1)": "Правила (%1)" - }, - "Run Again": { - "Run Again": "Запустить ещё раз" - }, - "Run DMS Templates": { - "Run DMS Templates": "Запустить шаблоны DMS" - }, - "Run User Templates": { - "Run User Templates": "Запустить пользовательский пример" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Запустить программу (например, firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Запустить команду оболочки (например, notify-send)" - }, - "Running Apps": { - "Running Apps": "Запущенные Приложения" - }, - "Running Apps Settings": { - "Running Apps Settings": "Настройка Запущенных Приложений" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "Яркость SDR" - }, - "SDR Saturation": { - "SDR Saturation": "Насыщенность SDR" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Сохранить" - }, - "Save Notepad File": { - "Save Notepad File": "Сохранить Файл Блокнота" - }, - "Save QR Code": { - "Save QR Code": "Сохранить QR-код" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Сохранить и переключаться между конфигурациями дисплеев" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Сохранять уведомления обычного приоритета в историю" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Сохранять отклонённые уведомления в историю" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Сохранять уведомления обычного приоритета в историю" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Сохранять уведомления обычного приоритета в историю" - }, - "Save password": { - "Save password": "Сохранить пароль" - }, - "Saved": { - "Saved": "Сохранено" - }, - "Saved Configurations": { - "Saved Configurations": "Saved Конфигурации" - }, - "Saved Note": { - "Saved Note": "Сохранённая заметка" - }, - "Saved item deleted": { - "Saved item deleted": "Сохранённый элемент удалён" - }, - "Saving...": { - "Saving...": "Сохранение..." - }, - "Scale": { - "Scale": "Масштаб" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Изменять размер шрифта DankBar независимо" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "Масштабировать размеры значков DankBar независимо" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Масштабировать все размеры шрифтов во всей оболочке" - }, - "Scan": { - "Scan": "Сканировать" - }, - "Scanning": { - "Scanning": "Сканирование" - }, - "Scanning...": { - "Scanning...": "Сканирование..." - }, - "Science": { - "Science": "Наука" - }, - "Score": { - "Score": "Счёт" - }, - "Screen Sharing": { - "Screen Sharing": "Демонстрация экрана" - }, - "Screen sharing": { - "Screen sharing": "Демонстрация экрана" - }, - "Scroll": { - "Scroll": "Прокрутка" - }, - "Scroll Factor": { - "Scroll Factor": "Фактор прокрутки" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Колесо прокрутки" - }, - "Scroll song title": { - "Scroll song title": "Прокручивать название песни" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Прокручивать заголовок если он не помещается в виджете" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Поведение колеса прокрутки на медиа виджете" - }, - "Scrolling": { - "Scrolling": "Прокрутка" - }, - "Search App Actions": { - "Search App Actions": "Поиск действий приложений" - }, - "Search Options": { - "Search Options": "Опции поиска" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Поиск по комбинации клавиш, описанию или имени действия.\n\nДействие по умолчанию копирует комбинацию клавиш в буфер обмена.\nЩёлкните ПКМ или нажмите стрелку вправо для закрепления часто используемых комбинаций клавиш — они будут отображаться вверху при отсутствии поиска." - }, - "Search for a location...": { - "Search for a location...": "Поиск местоположения..." - }, - "Search keybinds...": { - "Search keybinds...": "Поиск комбинаций клавиш..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Поиск горячих клавиш из вашего композитора и приложений" - }, - "Search plugins...": { - "Search plugins...": "Поиск дополнений..." - }, - "Search processes...": { - "Search processes...": "Поиск процессов..." - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "Поиск тем..." - }, - "Search widgets...": { - "Search widgets...": "Поиск виджетов..." - }, - "Search...": { - "Search...": "Поиск..." - }, - "Searching...": { - "Searching...": "Поиск..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "Вторичный" - }, - "Secured": { - "Secured": "Защищено" - }, - "Security": { - "Security": "Безопасность" - }, - "Security & privacy": { - "Security & privacy": "Безопасность и конфиденциальность" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "Выбрать" - }, - "Select Application": { - "Select Application": "Select Приложение" - }, - "Select Bar": { - "Select Bar": "Select Панели" - }, - "Select Custom Theme": { - "Select Custom Theme": "Выберите пользовательскую тему" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Выбрать логотип лаунчера дока" - }, - "Select File to Send": { - "Select File to Send": "Выбрать файл для отправки" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Выбрать лого лаунчера" - }, - "Select Profile Image": { - "Select Profile Image": "Выберите изображение профиля" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "Выберите обои для рабочего стола" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Выберите каталог обоев" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Выбрать цвет из палитры или использовать пользовательские ползунки" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Выбрать виджет для добавления на рабочий стол. Каждый виджет это отдельный экземпляр со своими настройками." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Выбрать виджет для добавления. Вы можете добавить несколько экземпляров одного виджета если нужно." - }, - "Select a window...": { - "Select a window...": "Выбрать окно..." - }, - "Select an image file...": { - "Select an image file...": "Выбрать изображение..." - }, - "Select at least one provider": { - "Select at least one provider": "Выбрать хотя бы одного провайдера" - }, - "Select device": { - "Select device": "Выбрать устройство" - }, - "Select device...": { - "Select device...": "Выбрать устройство..." - }, - "Select driver...": { - "Select driver...": "Выбрать драйвер..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Выбрать насыщенность шрифта для текста UI" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Выберите монитор для настройки обоев" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Выбрать моноширинный шрифт для списка процессов и технических дисплеев" - }, - "Select network": { - "Select network": "Подключено" - }, - "Select system sound theme": { - "Select system sound theme": "Выбрать системную тему звуков" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Выбрать семейство шрифтов для текста UI" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Выбрать алгоритм палитры, используемый для цветов на основе обоев" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Выбрать, какие источники комбинаций клавиш включать" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Выбрать какие переходы включать в рандомизацию" - }, - "Select...": { - "Select...": "Выбрать..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Выбранный файл изображения не найден." - }, - "Send": { - "Send": "Отправить" - }, - "Send Clipboard": { - "Send Clipboard": "Отправить буфер обмена" - }, - "Send File": { - "Send File": "Отправить файл" - }, - "Send SMS": { - "Send SMS": "Отправить SMS" - }, - "Sending": { - "Sending": "Отправка" - }, - "Separator": { - "Separator": "Разделитель" - }, - "Server": { - "Server": "Сервер" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Установить пользовательское имя устройства" - }, - "Set custom name": { - "Set custom name": "Установить пользовательское имя" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Установить пользовательские имена для устройств вывода аудио" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Установить пользовательские имена для устройств вывода аудио" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Установить разные обои для каждого подключённого монитора" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Установить разные обои для светлого и тёмного режима" - }, - "Set key and action to save": { - "Set key and action to save": "Установить клавишу и действие для сохранения" - }, - "Set notification rules": { - "Set notification rules": "Установить правила уведомлений" - }, - "Settings": { - "Settings": "Настройки" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Настройки доступны только для чтения. Изменения не будут сохранены." - }, - "Setup": { - "Setup": "Настройка" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "Поделиться" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Поделиться настройками управления Gamma" - }, - "Share Text": { - "Share Text": "Поделиться текстом" - }, - "Share URL": { - "Share URL": "Поделиться URL" - }, - "Shared": { - "Shared": "Отправлено" - }, - "Shell": { - "Shell": "Оболочка" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Очистить All • Esc: Закрыть" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter для вставки" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "↑/↓: Навигация • Enter: Вставить • Del: Удалить • F10: Справка" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Вставить • Shift+Del: Очистить всё • Esc: Закрыть" - }, - "Short": { - "Short": "Короткий" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "Ярлыки" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Ярлыки (%1)" - }, - "Show": { - "Show": "Показать" - }, - "Show 3rd Party": { - "Show 3rd Party": "Показать сторонние" - }, - "Show All Tags": { - "Show All Tags": "Показать все тэги" - }, - "Show Badge": { - "Show Badge": "Показать значок" - }, - "Show CPU": { - "Show CPU": "Показать CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Показать график CPU" - }, - "Show CPU Temp": { - "Show CPU Temp": "Показать температуру CPU" - }, - "Show Date": { - "Show Date": "Показать дату" - }, - "Show Disk": { - "Show Disk": "Показать диск" - }, - "Show Dock": { - "Show Dock": "Показывать Док" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Показать ощущаемую температуру" - }, - "Show Footer": { - "Show Footer": "Показать нижний колонтитул" - }, - "Show Forecast": { - "Show Forecast": "Показать прогноз" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Показать температуру GPU" - }, - "Show Header": { - "Show Header": "Показать заголовок" - }, - "Show Hibernate": { - "Show Hibernate": "Показать гибернацию" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Показать номера часов" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Показать почасовой прогноз" - }, - "Show Humidity": { - "Show Humidity": "Показать влажность" - }, - "Show Launcher Button": { - "Show Launcher Button": "Показать кнопку лаунчера" - }, - "Show Line Numbers": { - "Show Line Numbers": "Показать номера строк" - }, - "Show Location": { - "Show Location": "Показать локацию" - }, - "Show Lock": { - "Show Lock": "Show Блокировка" - }, - "Show Log Out": { - "Show Log Out": "Показать выход" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Показать анимацию ряби Material Design на интерактивных элементах" - }, - "Show Media Player": { - "Show Media Player": "Показать медиаплеер" - }, - "Show Memory": { - "Show Memory": "Показать память" - }, - "Show Memory Graph": { - "Show Memory Graph": "Показать график памяти" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "Показать сеть" - }, - "Show Network Graph": { - "Show Network Graph": "Показать сетевой график" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Показать только занятые рабочие области" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Показать счётчик переполнения" - }, - "Show Password Field": { - "Show Password Field": "Показать поле для ввода пароля" - }, - "Show Power Actions": { - "Show Power Actions": "Показать действия питания" - }, - "Show Power Off": { - "Show Power Off": "Показать выключение" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Показать вероятность осадков" - }, - "Show Pressure": { - "Show Pressure": "Показывать нажатия" - }, - "Show Profile Image": { - "Show Profile Image": "Показать изображение профиля" - }, - "Show Reboot": { - "Show Reboot": "Показать перезагрузку" - }, - "Show Restart DMS": { - "Show Restart DMS": "Показать перезапуск DMS" - }, - "Show Saved Items": { - "Show Saved Items": "Показать сохранённые элементы" - }, - "Show Seconds": { - "Show Seconds": "Показать секунды" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Показать рассвет/закат" - }, - "Show Suspend": { - "Show Suspend": "Показать приостановку" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "Показать системную дату" - }, - "Show System Icons": { - "Show System Icons": "Показать системные иконки" - }, - "Show System Time": { - "Show System Time": "Показать системное время" - }, - "Show Top Processes": { - "Show Top Processes": "Показать топ процессов" - }, - "Show Weather Condition": { - "Show Weather Condition": "Показать условие погоды" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "Показать приветствие" - }, - "Show Wind Speed": { - "Show Wind Speed": "Показать скорость ветра" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Показать приложения рабочего пространства" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Показать все 9 тегов вместо только занятых (только DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Показать контурное кольцо вокруг индикатора сфокусированного рабочего пространства" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Показать аудиовизуализатор cava в медиа виджете" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Показать затемнённое наложение за модальными диалогами" - }, - "Show device": { - "Show device": "Show устройство" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Показывать док, когда плавающие окна не перекрывают его область" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Показывать наложение лаунчера при вводе в обзоре Niri. Отключите для использования другого лаунчера." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Показывать вкладки режимов и подсказки клавиатуры внизу." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Показать на последнем дисплее" - }, - "Show on Overlay": { - "Show on Overlay": "Показать на наложении" - }, - "Show on Overview": { - "Show on Overview": "Показать на обзоре" - }, - "Show on Overview Only": { - "Show on Overview Only": "Показать только на обзоре" - }, - "Show on all connected displays": { - "Show on all connected displays": "Показать все подключенные дисплеи" - }, - "Show on screens:": { - "Show on screens:": "Показать на экранах:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Показывать OSD при изменении яркости" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Показывать on-screen отображение при изменении состояния Caps Lock" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Показывать on-screen отображение при переключении устройств аудиовыхода" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Показывать on-screen отображение при изменении состояния ингибитора бездействия" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Показывать on-screen отображение при изменении статуса медиаплеера" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Показывать on-screen отображение при изменении громкости медиаплеера" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Показывать on-screen отображение при отключении/включении микрофона" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Показывать on-screen отображение при изменении профиля питания" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Показывать on-screen отображение при изменении громкости" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Показывать информацию о погоде в верхней панели и центре управления" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Показывать номера индексов рабочих пространств в переключателе рабочих пространств верхней панели" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Показать имя рабочей области на горизонтальных панелях и первую букву на вертикальных панелях" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Показать рабочие области текущего сфокусированного монитора" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Показывает все запущенные приложения с индикацией фокуса" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Показывает текущую рабочую область и позволяет переключаться" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Показывает, когда Caps Lock активен" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Показывает, когда микрофон, камера или демонстрация экрана активны" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Выключение" - }, - "Signal": { - "Signal": "Сигнал" - }, - "Signal:": { - "Signal:": "Сигнал:" - }, - "Size": { - "Size": "Размер" - }, - "Size Constraints": { - "Size Constraints": "Ограничения размера" - }, - "Size Offset": { - "Size Offset": "Смещение размера" - }, - "Sizing": { - "Sizing": "Размер" - }, - "Skip": { - "Skip": "Пропустить" - }, - "Skip confirmation": { - "Skip confirmation": "Пропустить подтверждение" - }, - "Skip setup": { - "Skip setup": "Пропустить настройку" - }, - "Small": { - "Small": "Маленький" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Аутентификация Smartcard" - }, - "Smartcard PIN": { - "Smartcard PIN": "PIN смарт-карты" - }, - "Snap": { - "Snap": "Прилипание" - }, - "Snow": { - "Snow": "Снег" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Некоторые плагины требуют более новую версию DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Сортировать по алфавиту" - }, - "Sort By": { - "Sort By": "Сортировать по" - }, - "Sorting & Layout": { - "Sorting & Layout": "Сортировка и макет" - }, - "Sound Theme": { - "Sound Theme": "Звуковая тема" - }, - "Sounds": { - "Sounds": "Звуки" - }, - "Space between windows": { - "Space between windows": "Расстояние между окнами" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Расстояние между окнами (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Расстояние между окнами (gaps_in и gaps_out)" - }, - "Spacer": { - "Spacer": "Разделитель" - }, - "Spacing": { - "Spacing": "Отступ" - }, - "Speaker settings": { - "Speaker settings": "Настройки динамиков" - }, - "Speed": { - "Speed": "Скорость" - }, - "Spool Area Full": { - "Spool Area Full": "Область очереди заполнена" - }, - "Square Corners": { - "Square Corners": "Прямые углы" - }, - "Stacked": { - "Stacked": "Стопкой" - }, - "Standard": { - "Standard": "Стандарт" - }, - "Start": { - "Start": "Старт" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Запустите KDE Connect или Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Запустите KDE Connect или Valent для использования этого плагина" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Начните вводить заметки здесь..." - }, - "State": { - "State": "Штат/Область" - }, - "Status": { - "Status": "Статус" - }, - "Stopped": { - "Stopped": "Остановить" - }, - "Stopped Partly": { - "Stopped Partly": "Остановлено частично" - }, - "Stopping": { - "Stopping": "Останавливается" - }, - "Stretch": { - "Stretch": "Плитка вертикально" - }, - "Stripes": { - "Stripes": "Стирание" - }, - "Summary": { - "Summary": "Заголовок" - }, - "Sunrise": { - "Sunrise": "Восход" - }, - "Sunset": { - "Sunset": "Закат" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Подавить всплывающие уведомления, пока включено" - }, - "Surface": { - "Surface": "Поверхность" - }, - "Surface Variant": { - "Surface Variant": "Вариант поверхности" - }, - "Suspend": { - "Suspend": "Приостановить" - }, - "Suspend behavior": { - "Suspend behavior": "Поведение приостановки" - }, - "Suspend system after": { - "Suspend system after": "Приостановить систему через" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Приостановить затем гибернация" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "Переключить пользователя" - }, - "Switch to power profile": { - "Switch to power profile": "Переключиться на профиль питания" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Синхронизировать режим с Portal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Синхронизировать всплывающие и модальные" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Синхронизировать позицию на всех экранах" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Синхронизировать тёмный режим с порталами настроек для общесистемных подсказок темы" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "Система" - }, - "System App Theming": { - "System App Theming": "Темы системных приложений" - }, - "System Check": { - "System Check": "Проверка системы" - }, - "System Default": { - "System Default": "Системный по умолчанию" - }, - "System Information": { - "System Information": "Системная информация" - }, - "System Monitor": { - "System Monitor": "Системный монитор" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Системный монитор недоступен" - }, - "System Sounds": { - "System Sounds": "Системные звуки" - }, - "System Tray": { - "System Tray": "Системный трей" - }, - "System Update": { - "System Update": "Обновление системы" - }, - "System Updater": { - "System Updater": "Системное обновление" - }, - "System Updates": { - "System Updates": "Обновления системы" - }, - "System notification area icons": { - "System notification area icons": "Значки области системных уведомлений" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Системные звуки недоступны. Установите %1 для поддержки звуков." - }, - "System theme toggle": { - "System theme toggle": "Переключатель системной темы" - }, - "System toast notifications": { - "System toast notifications": "Системные всплывающие уведомления" - }, - "System update custom command": { - "System update custom command": "Пользовательская команда обновления системы" - }, - "Tab": { - "Tab": "Вкладка" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Навигация • ←→↑↓: Навигация сетки • Enter/Space: Выбрать" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Пользовательские дополнительные параметры терминала" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Терминалы — всегда использовать тёмную тему" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "Тестовая страница" - }, - "Test page sent to printer": { - "Test page sent to printer": "Тестовая страница отправлена на принтер" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "Текст" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "Инструмент 'dgop' требуется для системного мониторинга.\nУстановите dgop для использования этой функции." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "Переменная окружения DMS_SOCKET не установлена или сокет недоступен. Автоматизированное управление плагинами требует DMS_SOCKET." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Приведённые ниже настройки изменят ваши настройки GTK и Qt. Если вы хотите сохранить текущие конфигурации, сделайте их резервную копию (qt5ct.conf|qt6ct.conf и ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "Очередь заданий этого принтера пуста" - }, - "Theme & Colors": { - "Theme & Colors": "Темы и цвета" - }, - "Theme Color": { - "Theme Color": "Theme Цвет" - }, - "Theme Registry": { - "Theme Registry": "Реестр тем" - }, - "Themes": { - "Themes": "Темы" - }, - "Thickness": { - "Thickness": "Толщина" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Предупреждение о стороннем плагине" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Сторонние плагины созданы сообществом и официально не поддерживаются DankMaterialShell.\n\nЭти плагины могут представлять риски для безопасности и конфиденциальности — устанавливайте на свой страх и риск." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Эта комбинация клавиш переопределена в config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Это может занять несколько секунд" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Этот плагин не имеет разрешения 'settings_write'.\n\nДобавьте \"permissions\": [\"settings_read\", \"settings_write\"] в plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Этот виджет предотвращает состояния отключения питания GPU, что может значительно повлиять на время работы батареи на ноутбуках. Не рекомендуется использовать это на ноутбуках с гибридной графикой." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Это удалит все незакреплённые записи. %1 закреплённых записей будут сохранены." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Это навсегда удалит всю историю буфера обмена." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Это навсегда удалит этот сохранённый элемент буфера обмена. Это действие нельзя отменить." - }, - "Thunderstorm": { - "Thunderstorm": "Гроза" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Гроза с градом" - }, - "Tile": { - "Tile": "Плитка вертикально" - }, - "Tile H": { - "Tile H": "Плитка вертикально" - }, - "Tile V": { - "Tile V": "Плитка вертикально" - }, - "Tiled": { - "Tiled": "Плиточный" - }, - "Tiled State": { - "Tiled State": "Плиточное состояние" - }, - "Tiling": { - "Tiling": "Тайлинг" - }, - "Time": { - "Time": "Время" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "Время & Погода" - }, - "Time Format": { - "Time Format": "Формат времени" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "Осталось времени: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Времени до полной зарядки: %1" - }, - "Timed Out": { - "Timed Out": "Тайм-аут" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Тайм-аут для уведомлений критического приоритета" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Тайм-аут для уведомлений низкого приоритета" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Тайм-аут для уведомлений нормального приоритета" - }, - "Title": { - "Title": "Заголовок" - }, - "Title regex (optional)": { - "Title regex (optional)": "Regex заголовка (необязательно)" - }, - "To Full": { - "To Full": "До полной" - }, - "To update, run the following command:": { - "To update, run the following command:": "Для обновления, запустите следующую команду:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Для использования этой комбинации клавиш DMS, удалите или измените комбинацию в config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Всплывающие сообщения" - }, - "Today": { - "Today": "Сегодня" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Переключить видимость этой конфигурации панели" - }, - "Toggling...": { - "Toggling...": "Переключение..." - }, - "Tomorrow": { - "Tomorrow": "Завтра" - }, - "Tonal Spot": { - "Tonal Spot": "Яркий" - }, - "Toner Empty": { - "Toner Empty": "Тонер пуст" - }, - "Toner Low": { - "Toner Low": "Тонер заканчивается" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "Инструменты" - }, - "Top": { - "Top": "Сверху" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "Формат верхней панели" - }, - "Top Center": { - "Top Center": "Вверху справа" - }, - "Top Left": { - "Top Left": "Вверху слева" - }, - "Top Processes": { - "Top Processes": "Топ процессов" - }, - "Top Right": { - "Top Right": "Вверху справа" - }, - "Top Section": { - "Top Section": "Верхняя секция" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "Всего заданий" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Преобразовать" - }, - "Transition Effect": { - "Transition Effect": "Эффект перехода" - }, - "Transparency": { - "Transparency": "Прозрачность" - }, - "Trending GIFs": { - "Trending GIFs": "Трендовые GIF" - }, - "Trending Stickers": { - "Trending Stickers": "Трендовые стикеры" - }, - "Trigger": { - "Trigger": "Триггер" - }, - "Trigger Prefix": { - "Trigger Prefix": "Префикс триггера" - }, - "Trigger: %1": { - "Trigger: %1": "Триггер: %1" - }, - "Trust": { - "Trust": "Доверять" - }, - "Try a different search": { - "Try a different search": "Попробуйте другой поиск" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Выключить все дисплеи немедленно при активации Lock Screen" - }, - "Turn off monitors after": { - "Turn off monitors after": "Отключить мониторы после" - }, - "Type": { - "Type": "Тип" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Введите не менее 2 символов" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Введите этот префикс для поиска комбинацию клавишs" - }, - "Type to search files": { - "Type to search files": "Введите для поиска файлов" - }, - "Typography": { - "Typography": "Типография" - }, - "Typography & Motion": { - "Typography & Motion": "Типография и движение" - }, - "Unavailable": { - "Unavailable": "Недоступно" - }, - "Unfocused Color": { - "Unfocused Color": "Цвет неактивного" - }, - "Ungrouped": { - "Ungrouped": "Негруппированный" - }, - "Uninstall": { - "Uninstall": "Удалить" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Удалить плагин" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Ошибка удаления: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Удалено: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Удаление: %1" - }, - "Unknown": { - "Unknown": "Неизвестный" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "Неизвестный исполнитель" - }, - "Unknown Config": { - "Unknown Config": "Неизвестная конфигурация" - }, - "Unknown Device": { - "Unknown Device": "Неизвестное устройство" - }, - "Unknown GPU": { - "Unknown GPU": "Неизвестный GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "Неизвестный монитор" - }, - "Unknown Network": { - "Unknown Network": "Неизвестная сеть" - }, - "Unknown Title": { - "Unknown Title": "Неизвестный заголовок" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "Выгрузить при закрытии" - }, - "Unmute": { - "Unmute": "Включить звук" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Включить всплывающие окна для %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Правило без имени" - }, - "Unpair": { - "Unpair": "Отменить сопряжение" - }, - "Unpair failed": { - "Unpair failed": "Отмена сопряжения не удалась" - }, - "Unpin": { - "Unpin": "Открепить" - }, - "Unpin from Dock": { - "Unpin from Dock": "Открепить от дока" - }, - "Unsaved Changes": { - "Unsaved Changes": "Несохранённые изменения" - }, - "Unsaved changes": { - "Unsaved changes": "Несохранённые изменения" - }, - "Unsaved note...": { - "Unsaved note...": "Несохранённая заметка..." - }, - "Untitled": { - "Untitled": "Без названия" - }, - "Untrust": { - "Untrust": "Не доверять" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "Обновление" - }, - "Update All": { - "Update All": "Обновить всё" - }, - "Update Plugin": { - "Update Plugin": "Обновить плагин" - }, - "Uptime": { - "Uptime": "Время работы" - }, - "Uptime:": { - "Uptime:": "Время работы:" - }, - "Urgent Color": { - "Urgent Color": "Цвет срочного" - }, - "Usage Tips": { - "Usage Tips": "Советы по использованию" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Использовать 24-часовой формат времени вместо 12-часового AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "Использовать пользовательскую команду" - }, - "Use Grid Layout": { - "Use Grid Layout": "Использовать макет сетки" - }, - "Use IP Location": { - "Use IP Location": "Используемый IP" - }, - "Use Imperial Units": { - "Use Imperial Units": "Использовать имперские единицы" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Использовать имперские единицы (°F, mph, inHg) вместо метрических (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Использовать моноширинный шрифт" - }, - "Use System Theme": { - "Use System Theme": "Использовать системную тему" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Используйте внешний менеджер обоев, такой как swww, hyprpaper или swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Использовать анимированные волновые прогресс-бары для воспроизведения медиа" - }, - "Use custom border size": { - "Use custom border size": "Использовать пользовательский размер границы" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Использовать пользовательскую ширину границы/кольца фокуса" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Использовать пользовательскую команду для обновления вашей системы" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Использовать пользовательские отступы вместо отступов панели" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Использовать пользовательский радиус окон вместо радиуса темы" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Использовать пользовательское скругление окон вместо радиуса темы" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Использовать светлую тему вместо тёмной" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Использовать метры в секунду вместо км/ч для скорости ветра" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Использовать меньшие карточки уведомлений" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Использовать звуковую тему из системных настроек" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Использовать одинаковую позицию и размер на всех дисплеях" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Использовать префикс триггера для активации" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Используется, когда акцентный цвет установлен в Custom" - }, - "User": { - "User": "Пользователь" - }, - "Username": { - "Username": "Имя пользователя" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Использует время восхода/заката солнца на основе вашего местоположения." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Использует время восхода/заката солнца для автоматической настройки ночного режима на основе вашего местоположения." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Использование общих настроек из Gamma Control" - }, - "Utilities": { - "Utilities": "Утилиты" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN соединение" - }, - "VPN Password": { - "VPN Password": "VPN Пароль" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN конфигурации updated" - }, - "VPN connections": { - "VPN connections": "VPN подключения" - }, - "VPN deleted": { - "VPN deleted": "VPN удалён" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN импортирован: %1" - }, - "VPN not available": { - "VPN not available": "VPN недоступен" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN статус и быстрое подключение" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR только полноэкранный" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR по требованию" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Переменная частота обновления" - }, - "Verification": { - "Verification": "Проверка" - }, - "Version": { - "Version": "Версия" - }, - "Vertical Deck": { - "Vertical Deck": "Вертикальная дека" - }, - "Vertical Grid": { - "Vertical Grid": "Вертикальная сетка" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Вертикальная прокрутка" - }, - "Vertical Tiling": { - "Vertical Tiling": "Вертикальный тайлинг" - }, - "Vibrant": { - "Vibrant": "Яркий" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Яркая палитра с игривой насыщенностью." - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "Видео" - }, - "View Mode": { - "View Mode": "Режим просмотра" - }, - "Visibility": { - "Visibility": "Видимость" - }, - "Visual Effects": { - "Visual Effects": "Визуальные эффекты" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Визуальный разделитель между виджетами" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Визуальные эффекты используеться при смене обоев" - }, - "Volume": { - "Volume": "Громкость" - }, - "Volume Changed": { - "Volume Changed": "Громкость изменена" - }, - "Volume Slider": { - "Volume Slider": "Громкость Ползунок" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Громкость, яркость и другие системные OSD" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Обои" - }, - "Wallpaper Error": { - "Wallpaper Error": "Ошибка в выборе обоев" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Монитор обоев" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Не удалось обработать обои" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Ошибка обработки обоев - проверьте путь к обоям" - }, - "Wallpapers": { - "Wallpapers": "Обои" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Тёплая цветовая температура для применения" - }, - "Warning": { - "Warning": "Предупреждение" - }, - "Warnings": { - "Warnings": "Предупреждения" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Волновые прогресс-бары" - }, - "Weather": { - "Weather": "Погода" - }, - "Weather Widget": { - "Weather Widget": "Виджет погоды" - }, - "Welcome": { - "Welcome": "Добро пожаловать" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Добро пожаловать в DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Когда включено, приложения сортируются по алфавиту. Когда отключено, приложения сортируются по частоте использования." - }, - "When locked": { - "When locked": "Когда заблокировано" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Когда виджет обновления используется, скрывать его если обновление не найдено" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi Пароль" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Подключение Wi-Fi и Ethernet" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi недоступен" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "Устройство WiFi" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "WiFi QR-код для " - }, - "WiFi disabled": { - "WiFi disabled": "WiFi отключен" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi включен" - }, - "WiFi is off": { - "WiFi is off": "WiFi отключен" - }, - "WiFi off": { - "WiFi off": "Подключено" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Широкий (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Виджет Фоновое Цвет" - }, - "Widget Management": { - "Widget Management": "Управление виджетами" - }, - "Widget Outline": { - "Widget Outline": "Контур виджета" - }, - "Widget Style": { - "Widget Style": "Стиль виджета" - }, - "Widget Styling": { - "Widget Styling": "Стилизация виджета" - }, - "Widget Transparency": { - "Widget Transparency": "Виджет Прозрачность" - }, - "Widget added": { - "Widget added": "Виджет добавленные" - }, - "Widget removed": { - "Widget removed": "Виджет удалён" - }, - "Widgets": { - "Widgets": "Виджеты" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Виджеты, макет, стиль" - }, - "Width": { - "Width": "Ширина" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Ширина границы окна (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Ширина границы окна (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Ширина границы окна и кольца фокуса" - }, - "Wind": { - "Wind": "Ветер" - }, - "Wind Speed": { - "Wind Speed": "Скорость ветра" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Скорость ветра в м/с" - }, - "Window Corner Radius": { - "Window Corner Radius": "Радиус углов окна" - }, - "Window Gaps": { - "Window Gaps": "Отступы окон" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Отступы окон (px)" - }, - "Window Height": { - "Window Height": "Высота окна" - }, - "Window Opening": { - "Window Opening": "Открытие окна" - }, - "Window Rounding": { - "Window Rounding": "Скругление окон" - }, - "Window Rules": { - "Window Rules": "Правила окон" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Window Rules включают отсутствующие" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Правила окон не настроены" - }, - "Wipe": { - "Wipe": "Стирание" - }, - "Workspace": { - "Workspace": "Рабочее пространство" - }, - "Workspace Appearance": { - "Workspace Appearance": "Внешний вид рабочей области" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Номера индексов рабочих областей" - }, - "Workspace Names": { - "Workspace Names": "Workspace Названия" - }, - "Workspace Padding": { - "Workspace Padding": "Отступ рабочей области" - }, - "Workspace Settings": { - "Workspace Settings": "Настройки рабочего пространства" - }, - "Workspace Switcher": { - "Workspace Switcher": "Переключатель рабочих областей" - }, - "Workspace name": { - "Workspace name": "Имя рабочей области" - }, - "Workspaces": { - "Workspaces": "Рабочие пространства" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Рабочие области и виджеты" - }, - "Write:": { - "Write:": "Запись:" - }, - "X Axis": { - "X Axis": "Ось X" - }, - "Y Axis": { - "Y Axis": "Ось Y" - }, - "Yes": { - "Yes": "Да" - }, - "Yesterday": { - "Yesterday": "Вчера" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "У вас есть несохранённые изменения. Сохранить перед закрытием этой вкладки?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "У вас есть несохранённые изменения. Сохранить перед продолжением?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "У вас есть несохранённые изменения. Сохранить перед созданием нового файла?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "У вас есть несохранённые изменения. Сохранить изменения перед открытием файла?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Необходимо установить одну из переменных окружения:\nQT_QPA_PLATFORMTHEME=gtk3 ИЛИ\nQT_QPA_PLATFORMTHEME=qt6ct\nа затем перезапустить оболочку.\n\nДля qt6ct требуется qt6ct-kde." - }, - "You're All Set!": { - "You're All Set!": "Всё готово!" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "действия" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "на %1" - }, - "days": { - "days": "дней" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "устройство" - }, - "devices connected": { - "devices connected": "устройств подключено" - }, - "dgop not available": { - "dgop not available": "dgop недоступен" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "конфигурация dms/cursor существует но не включена. Настройки курсора не будут применены." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/outputs config существует, но не включён в ваш конфиг композитора. Изменения дисплеев не сохранятся." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "например, firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "например, focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "например, notify-send 'Hello' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "события" - }, - "ext": { - "ext": "расш" - }, - "featured": { - "featured": "избранное" - }, - "leave empty for default": { - "leave empty for default": "оставьте пустым для значения по умолчанию" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl недоступен — интеграция блокировки требует подключения к сокету DMS" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen не найден - установите пакет matugen для динамической тематизации" - }, - "minutes": { - "minutes": "минут" - }, - "ms": { - "ms": "мс" - }, - "nav": { - "nav": "навигация" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "конфигурация комбинаций клавиш niri" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "сейчас" - }, - "official": { - "official": "оффициально" - }, - "on Hyprland": { - "on Hyprland": "на Hyprland" - }, - "on MangoWC": { - "on MangoWC": "на MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "на Miracle WM" - }, - "on Niri": { - "on Niri": "на Niri" - }, - "on Scroll": { - "on Scroll": "при прокрутке" - }, - "on Sway": { - "on Sway": "на Sway" - }, - "open": { - "open": "открыть" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "проц." - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "секунд" - }, - "source": { - "source": "исходный" - }, - "this app": { - "this app": "это приложение" - }, - "up": { - "up": "вверх" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "обновите dms для NM интеграции." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 от %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype недоступен - установите wtype для поддержки вставки" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Устанавливайте только из доверенных источников" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "М - Месяц (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Месяц (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM — месяц (Янв)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM — месяц (Январь)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Плагины могут содержать ошибки или проблемы с безопасностью" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Проверяйте код перед установкой когда возможно" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - День (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd — день (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd — название дня (Пн)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd — название дня (Понедельник)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy — год (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy — год (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Навигация • Пробел: Развернуть • Enter: Действие/Развернуть • E: Текст" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Навигация • Enter: Вставить • Del: Удалить • F10: Справка" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/sv.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/sv.json deleted file mode 100644 index 5b9f9be..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/sv.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 animeringshastighet" - }, - "%1 Sessions": { - "%1 Sessions": "%1 sessioner" - }, - "%1 active session": { - "%1 active session": "%1 aktiv session" - }, - "%1 active sessions": { - "%1 active sessions": "%1 aktiva sessioner" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 adapter, ingen ansluten" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 adaptrar, ingen ansluten" - }, - "%1 character": { - "%1 character": "%1 tecken" - }, - "%1 characters": { - "%1 characters": "%1 tecken" - }, - "%1 connected": { - "%1 connected": "%1 ansluten" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 anpassad animeringstid" - }, - "%1 disconnected": { - "%1 disconnected": "%1 frånkopplad" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 frånkopplad (dold)" - }, - "%1 display": { - "%1 display": "%1 bildskärm" - }, - "%1 displays": { - "%1 displays": "%1 bildskärmar" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 finns men ingår inte i konfigurationen. Anpassade kortkommandon fungerar inte förrän detta är åtgärdat." - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 finns men ingår inte. Fönsterregler tillämpas inte." - }, - "%1 filtered": { - "%1 filtered": "%1 filtrerade" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 ingår nu i konfigurationen" - }, - "%1 issue found": { - "%1 issue found": "%1 problem hittades" - }, - "%1 issues found": { - "%1 issues found": "%1 problem hittades" - }, - "%1 notifications": { - "%1 notifications": "%1 notiser" - }, - "%1 update": { - "%1 update": "%1 uppdatering" - }, - "%1 updates": { - "%1 updates": "%1 uppdateringar" - }, - "%1 variants": { - "%1 variants": "%1 varianter" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 bakgrundsbild • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 bakgrundsbilder • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 widgetar" - }, - "%1 window": { - "%1 window": "%1 fönster" - }, - "%1 windows": { - "%1 windows": "%1 fönster" - }, - "%1m ago": { - "%1m ago": "för %1 min sedan" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "'Alternativ' låter nyckeln låsa upp på egen hand. 'Andra faktor' kräver lösenord eller fingeravtryck först, sedan nyckeln." - }, - "(Default)": { - "(Default)": "(Standard)" - }, - "(Unnamed)": { - "(Unnamed)": "(Inget namn)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 till" - }, - "/path/to/videos": { - "/path/to/videos": "/sökväg/till/videor" - }, - "0 = square corners": { - "0 = square corners": "0 = fyrkantiga hörn" - }, - "1 day": { - "1 day": "1 dag" - }, - "1 device connected": { - "1 device connected": "1 enhet ansluten" - }, - "1 event": { - "1 event": "1 händelse" - }, - "1 hour": { - "1 hour": "1 timme" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 timme 30 minuter" - }, - "1 minute": { - "1 minute": "1 minut" - }, - "1 notification": { - "1 notification": "1 notis" - }, - "1 second": { - "1 second": "1 sekund" - }, - "10 minutes": { - "10 minutes": "10 minuter" - }, - "10 seconds": { - "10 seconds": "10 sekunder" - }, - "10-bit Color": { - "10-bit Color": "10-bitars färg" - }, - "12 hours": { - "12 hours": "12 timmar" - }, - "14 days": { - "14 days": "14 dagar" - }, - "15 minutes": { - "15 minutes": "15 minuter" - }, - "15 seconds": { - "15 seconds": "15 sekunder" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 timmar" - }, - "2 minutes": { - "2 minutes": "2 minuter" - }, - "2 seconds": { - "2 seconds": "2 sekunder" - }, - "20 minutes": { - "20 minutes": "20 minuter" - }, - "20 seconds": { - "20 seconds": "20 sekunder" - }, - "24-Hour Format": { - "24-Hour Format": "24-timmarsklocka" - }, - "24-hour clock": { - "24-hour clock": "24-timmarsklocka" - }, - "24-hour format": { - "24-hour format": "24-timmarsklocka" - }, - "25 seconds": { - "25 seconds": "25 sekunder" - }, - "250 ms": { - "250 ms": "250 ms" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 dagar" - }, - "3 hours": { - "3 hours": "3 timmar" - }, - "3 minutes": { - "3 minutes": "3 minuter" - }, - "3 seconds": { - "3 seconds": "3 sekunder" - }, - "30 days": { - "30 days": "30 dagar" - }, - "30 minutes": { - "30 minutes": "30 minuter" - }, - "30 seconds": { - "30 seconds": "30 sekunder" - }, - "35 seconds": { - "35 seconds": "35 sekunder" - }, - "3rd party": { - "3rd party": "tredje part" - }, - "4 hours": { - "4 hours": "4 timmar" - }, - "4 seconds": { - "4 seconds": "4 sekunder" - }, - "40 seconds": { - "40 seconds": "40 sekunder" - }, - "45 seconds": { - "45 seconds": "45 sekunder" - }, - "5 minutes": { - "5 minutes": "5 minuter" - }, - "5 seconds": { - "5 seconds": "5 sekunder" - }, - "50 seconds": { - "50 seconds": "50 sekunder" - }, - "500 ms": { - "500 ms": "500 ms" - }, - "55 seconds": { - "55 seconds": "55 sekunder" - }, - "6 hours": { - "6 hours": "6 timmar" - }, - "7 days": { - "7 days": "7 dagar" - }, - "750 ms": { - "750 ms": "750 ms" - }, - "8 hours": { - "8 hours": "8 timmar" - }, - "8 seconds": { - "8 seconds": "8 sekunder" - }, - "90 days": { - "90 days": "90 dagar" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "MIT-licens" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "En fil med det här namnet finns redan. Vill du ersätta den?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "Ett modernt skrivbordsskal för Wayland-kompositorer" - }, - "AC Power": { - "AC Power": "Nätström" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Avbruten" - }, - "About": { - "About": "Om" - }, - "Accent Color": { - "Accent Color": "Accentfärg" - }, - "Accept": { - "Accept": "Acceptera" - }, - "Accept Jobs": { - "Accept Jobs": "Ta emot jobb" - }, - "Accepting": { - "Accepting": "Tar emot" - }, - "Access clipboard history": { - "Access clipboard history": "Åtkomst till urklippshistorik" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Åtkomst till notiser och stör ej" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Åtkomst till systeminställningar" - }, - "Action": { - "Action": "Åtgärd" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "Åtgärden misslyckades eller terminalen stängdes." - }, - "Actions": { - "Actions": "Åtgärder" - }, - "Activate": { - "Activate": "Aktivera" - }, - "Activate Greeter": { - "Activate Greeter": "Aktivera välkomstskärm" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "Aktivera DMS-välkomstskärmen? En terminal öppnas för sudo-autentisering. Kör Synka efter aktivering för att tillämpa dina inställningar." - }, - "Activation": { - "Activation": "Aktivering" - }, - "Active": { - "Active": "Aktiv" - }, - "Active Color": { - "Active Color": "Aktiv färg" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Aktiv låsskärmsbildskärm" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "Bakgrund och iconfärg för aktiv platta" - }, - "Active: %1": { - "Active: %1": "Aktiv: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Aktiv: %1 +%2" - }, - "Active: None": { - "Active: None": "Aktiv: Ingen" - }, - "Adapters": { - "Adapters": "Adaptrar" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Lägg till" - }, - "Add Bar": { - "Add Bar": "Lägg till menyrad" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Lägg till skrivbordswidget" - }, - "Add Printer": { - "Add Printer": "Lägg till skrivare" - }, - "Add Title": { - "Add Title": "Lägg till titel" - }, - "Add Widget": { - "Add Widget": "Lägg till widget" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "Lägg till widget i %1-avdelningen" - }, - "Add a border around the dock": { - "Add a border around the dock": "Lägg till en ram runt docken" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Lägg till ett anpassat prefix på alla programstarter. Detta kan användas för t.ex. 'uwsm-app', 'systemd-run' eller andra kommandoomslag." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Lägg till och konfigurera widgetar som visas på skrivbordet" - }, - "Add by Address": { - "Add by Address": "Lägg till med adress" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Justera antalet kolumner i rutnätsvy." - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "Justera volym per rullningsindrag" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Avancerat" - }, - "Afternoon": { - "Afternoon": "Eftermiddag" - }, - "All": { - "All": "Alla" - }, - "All Monitors": { - "All Monitors": "Alla bildskärmar" - }, - "All checks passed": { - "All checks passed": "Alla kontroller godkända" - }, - "All day": { - "All day": "Hela dagen" - }, - "All displays": { - "All displays": "Alla bildskärmar" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "Tillåt klick att passera genom widgeten" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backsteg: Gå tillbaka • F1/I: Filinformation • F10: Hjälp • Esc: Stäng" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternativ (ELLER)" - }, - "Always Active": { - "Always Active": "Alltid aktiv" - }, - "Always Show Percentage": { - "Always Show Percentage": "Visa alltid procent" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "Dölj alltid docken och visa den när pekaren är nära dockområdet" - }, - "Always on icons": { - "Always on icons": "Ikoner alltid synliga" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Visa alltid minst 3 arbetsytor, även om färre är tillgängliga" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Visa alltid docken när niri-översikten är öppen" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Visa alltid när bara en bildskärm är ansluten" - }, - "Amount": { - "Amount": "Antal" - }, - "Analog": { - "Analog": "Analog" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analog, digital eller staplade klockvisning" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "Analyserar konfiguration..." - }, - "Animation Duration": { - "Animation Duration": "Animeringstid" - }, - "Animation Speed": { - "Animation Speed": "Animeringshastighet" - }, - "Anonymous Identity": { - "Anonymous Identity": "Anonym identitet" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Anonym identitet (valfritt)" - }, - "App Customizations": { - "App Customizations": "Appanpassningar" - }, - "App ID Substitutions": { - "App ID Substitutions": "App-ID-substitutioner" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "App-ID-regex (t.ex. ^firefox$)" - }, - "App Launcher": { - "App Launcher": "Appstartare" - }, - "App Names": { - "App Names": "Appnamn" - }, - "App Theming": { - "App Theming": "Apptematisering" - }, - "Appearance": { - "Appearance": "Utseende" - }, - "Application Dock": { - "Application Dock": "Programdock" - }, - "Applications": { - "Applications": "Appar" - }, - "Apply Changes": { - "Apply Changes": "Tillämpa ändringar" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "Tillämpa GTK-färger" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "Tillämpa Qt-färger" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Applicera varm färgtemperatur för att minska ögontrötthet. Använd automatiseringsinställningarna nedan för att styra när det aktiveras." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "Appar" - }, - "Apps Dock": { - "Apps Dock": "Appdock" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "Appdockinställningar" - }, - "Apps Icon": { - "Apps Icon": "Appar-ikon" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Appar ordnas först efter användningsfrekvens, sedan senast användning, sist alfabetiskt." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "Appar med anpassat visningsnamn, ikon eller startalternativ. Högerklicka på en app och välj 'Redigera app' för att anpassa." - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "Appar med tystade notisbanderoller. Ta bort tystning eller radera för att ta bort." - }, - "Architecture": { - "Architecture": "Arkitektur" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "Är du säker på att du vill avsluta sessionen \"%1\"?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Arrangera bildskärmar och konfigurera upplösning, uppdateringsfrekvens och VRR" - }, - "Attach": { - "Attach": "Anslut" - }, - "Audio": { - "Audio": "Ljud" - }, - "Audio Codec": { - "Audio Codec": "Ljudkodek" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Val av ljudkodek" - }, - "Audio Devices": { - "Audio Devices": "Ljudenheter" - }, - "Audio Input": { - "Audio Input": "Ljudingång" - }, - "Audio Output": { - "Audio Output": "Ljudutgång" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Utgångsenheter för ljud (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Byt ljudutgång" - }, - "Audio Visualizer": { - "Audio Visualizer": "Ljudvisualiserare" - }, - "Audio system restarted": { - "Audio system restarted": "Ljudsystem omstartat" - }, - "Audio volume control": { - "Audio volume control": "Volymkontroll" - }, - "Auth": { - "Auth": "Autent." - }, - "Auth Type": { - "Auth Type": "Autentiseringstyp" - }, - "Authenticate": { - "Authenticate": "Autentisera" - }, - "Authenticating...": { - "Authenticating...": "Autentiserar..." - }, - "Authentication": { - "Authentication": "Autentisering" - }, - "Authentication Required": { - "Authentication Required": "Autentisering krävs" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "Autentiseringsfel – försök igen" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Autentisering misslyckades, försök igen" - }, - "Authorize": { - "Authorize": "Auktorisera" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Auktorisera parkoppling med " - }, - "Authorize service for ": { - "Authorize service for ": "Auktorisera tjänst för " - }, - "Auto": { - "Auto": "Automatisk" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "Automatisk (menyradsmedveten)" - }, - "Auto (Wide)": { - "Auto (Wide)": "Automatisk (bred)" - }, - "Auto Location": { - "Auto Location": "Automatisk plats" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Automatiska mellanrum för popupfönster" - }, - "Auto-Clear After": { - "Auto-Clear After": "Rensa automatiskt efter" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "Tidsgräns för auto-döljande" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Stäng niri-översikten automatiskt när appar startas." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Radera automatiskt notiser äldre än detta" - }, - "Auto-hide": { - "Auto-hide": "Göm automatiskt" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Göm Dock automatiskt" - }, - "Auto-saving...": { - "Auto-saving...": "Sparar automatiskt..." - }, - "Autoconnect": { - "Autoconnect": "Automatisk anslutning" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Automatisk anslutning avaktiverad" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Automatisk anslutning aktiverad" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "Automatiskt färgläge" - }, - "Automatic Control": { - "Automatic Control": "Automatisk justering" - }, - "Automatic Cycling": { - "Automatic Cycling": "Automatiskt bildspel" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Växla bakgrundsbilder i samma mapp automatiskt" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Radera automatiskt poster äldre än detta" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "Identifiera plats automatiskt baserat på IP-adress" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "Fastställ din plats automatiskt utifrån din IP-adress" - }, - "Automatically lock after": { - "Automatically lock after": "Lås automatiskt efter" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "Lås skärmen automatiskt när DMS startar" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Lås skärmen automatiskt när systemet förbereder sig för strömsparläge" - }, - "Automation": { - "Automation": "Automatisering" - }, - "Available": { - "Available": "Tillgängligt" - }, - "Available Layouts": { - "Available Layouts": "Tillgängliga layouter" - }, - "Available Networks": { - "Available Networks": "Tillgängliga nätverk" - }, - "Available Plugins": { - "Available Plugins": "Tillgängliga tillägg" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Tillgängliga skärmar (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "Tillgänglig i detaljerade och prognosvyer" - }, - "Available.": { - "Available.": "Tillgängligt." - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Tillbaka" - }, - "Backend": { - "Backend": "Bakgrundstjänst" - }, - "Background": { - "Background": "Bakgrund" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Bakgrundsopacitet" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "Bakgrundsbild" - }, - "Backlight device": { - "Backlight device": "Bakgrundsbelysningsenhet" - }, - "Balance power and performance": { - "Balance power and performance": "Balansera ström och prestanda" - }, - "Balanced": { - "Balanced": "Balanserad" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Balanserad palett med fokuserade accenter (standard)." - }, - "Bar Configurations": { - "Bar Configurations": "Menyradskonfigurationer" - }, - "Bar Shadows": { - "Bar Shadows": "Menyradsskuggor" - }, - "Bar Transparency": { - "Bar Transparency": "Genomskinlighet på menyraden" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "Basfärg för skuggor (opacitet tillämpas automatiskt)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "Bastid för animeringar (dra för att använda Anpassad)" - }, - "Battery": { - "Battery": "Batteri" - }, - "Battery %1": { - "Battery %1": "Batteri %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Laddningsgräns" - }, - "Battery and power management": { - "Battery and power management": "Batteri och energihantering" - }, - "Battery level and power management": { - "Battery level and power management": "Energi och batteri" - }, - "Behavior": { - "Behavior": "Beteende" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Koppla låsskärmen till dbus-signaler från loginctl. Avaktivera om du använder en extern låsskärm" - }, - "Binds Include Missing": { - "Binds Include Missing": "Inkludering av kortkommandon saknas" - }, - "Binds include added": { - "Binds include added": "Inkludering av kortkommandon tillagd" - }, - "Bit Depth": { - "Bit Depth": "Bitdjup" - }, - "Block Out": { - "Block Out": "Blockera" - }, - "Block Out From": { - "Block Out From": "Blockera från" - }, - "Block notifications": { - "Block notifications": "Blockera notiser" - }, - "Blocked": { - "Blocked": "Blockerad" - }, - "Blue light filter": { - "Blue light filter": "Blåljusfilter" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth-inställningar" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth är inte tillgängligt" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Oskärpa bakgrundsbildslager" - }, - "Blur on Overview": { - "Blur on Overview": "Oskärpa i översikt" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Oskärpa bakgrundsbild när niri-översikten är öppen" - }, - "Body": { - "Body": "Brödtext" - }, - "Border": { - "Border": "Ram" - }, - "Border Color": { - "Border Color": "Färg på kantlinje" - }, - "Border Opacity": { - "Border Opacity": "Opacitet på kantlinje" - }, - "Border Size": { - "Border Size": "Ramstorlek" - }, - "Border Thickness": { - "Border Thickness": "Tjocklek på kantlinje" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "Ram med bakgrund" - }, - "Bottom": { - "Bottom": "Nederkant" - }, - "Bottom Center": { - "Bottom Center": "Nedre mitten" - }, - "Bottom Left": { - "Bottom Left": "Nedre vänster" - }, - "Bottom Right": { - "Bottom Right": "Nedre höger" - }, - "Bottom Section": { - "Bottom Section": "Nedre avdelning" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Nedre dock för fästa och aktiva appar" - }, - "Brightness": { - "Brightness": "Ljusstyrka" - }, - "Brightness Slider": { - "Brightness Slider": "Ljusstyrkereglage" - }, - "Brightness Value": { - "Brightness Value": "Ljusstyrkevärde" - }, - "Brightness control not available": { - "Brightness control not available": "Ljusstyrkekontrollen är inte tillgänglig" - }, - "Browse": { - "Browse": "Bläddra" - }, - "Browse Files": { - "Browse Files": "Bläddra bland filer" - }, - "Browse Plugins": { - "Browse Plugins": "Bläddra bland tillägg" - }, - "Browse Themes": { - "Browse Themes": "Bläddra bland teman" - }, - "Browse or search plugins": { - "Browse or search plugins": "Bläddra bland eller sök tillägg" - }, - "Button Color": { - "Button Color": "Knappfärg" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU-graf" - }, - "CPU Temperature": { - "CPU Temperature": "CPU-temperatur" - }, - "CPU Usage": { - "CPU Usage": "CPU-användning" - }, - "CPU temperature display": { - "CPU temperature display": "Visa CPU-temperaturen" - }, - "CPU usage indicator": { - "CPU usage indicator": "Visa CPU-användningen" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU-, minnes-, nätverks- och diskövervakning" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS-varning om osäkert filter" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS-varning om saknat filter" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS-skrivarserver" - }, - "CUPS not available": { - "CUPS not available": "CUPS är inte tillgängligt" - }, - "Camera": { - "Camera": "Kamera" - }, - "Cancel": { - "Cancel": "Avbryt" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "Avbryt alla jobb för \"%1\"?" - }, - "Canceled": { - "Canceled": "Avbruten" - }, - "Cannot pair": { - "Cannot pair": "Kan inte parkoppla" - }, - "Capabilities": { - "Capabilities": "Funktioner" - }, - "Capacity": { - "Capacity": "Kapacitet" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Indikator för Caps Lock" - }, - "Caps Lock is on": { - "Caps Lock is on": "Caps Lock är på" - }, - "Center Section": { - "Center Section": "Mittavdelning" - }, - "Center Single Column": { - "Center Single Column": "Centrera enstaka kolumn" - }, - "Center Tiling": { - "Center Tiling": "Kakla i center" - }, - "Certificate Password": { - "Certificate Password": "Certifikats-lösenord" - }, - "Change Song": { - "Change Song": "Byt låt" - }, - "Change Volume": { - "Change Volume": "Ändra volym" - }, - "Change bar appearance": { - "Change bar appearance": "Ändra utseende på menyraden" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "Ändra det språk som används av DMS-gränssnittet." - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "Ändra det språk som används för datum- och tidsformatering, oberoende av gränssnittsspråket." - }, - "Channel": { - "Channel": "Kanal" - }, - "Charging": { - "Charging": "Laddar" - }, - "Check for system updates": { - "Check for system updates": "Sök efter systemuppdateringar" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "Söker efter uppdateringar..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "Kontrollerar om sudo-autentisering behövs…" - }, - "Checking...": { - "Checking...": "Kontrollerar..." - }, - "Checking…": { - "Checking…": "Kontrollerar…" - }, - "Choose Color": { - "Choose Color": "Välj färg" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "Välj mörkt läge-färg" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "Välj färg på dockens startarikon" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Välj färgen på appstartarens ikon" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "Välj ljust läge-färg" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "Välj bakgrundsbildsfärg" - }, - "Choose a color": { - "Choose a color": "Välj en färg" - }, - "Choose colors from palette": { - "Choose colors from palette": "Välj färger från paletten" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "Välj hur väderwidgeten visas" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "Välj hur denna menyrad hanterar skuggriktning" - }, - "Choose icon": { - "Choose icon": "Välj ikon" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Välj bakgrundsfärg för widgetar" - }, - "Choose the border accent color": { - "Choose the border accent color": "Välj accentfärg på kantlinjen" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "Välj ikonen som visas på appstartarknappen i DankBar" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Välj var notisbanderoller visas på skärmen" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Välj var skärmvisningar visas på skärmen" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Välj vilka bildskärmar som visar denna widget" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Välj vilken bildskärm som visar låsskärmsgränssnittet. Övriga bildskärmar visar en enfärgad bild för OLED-inbränningsskydd." - }, - "Chroma Style": { - "Chroma Style": "Chroma-stil" - }, - "Cipher": { - "Cipher": "Chiffer" - }, - "Circle": { - "Circle": "Cirkel" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "Klassregex (t.ex. ^firefox$)" - }, - "Clear": { - "Clear": "Rensa" - }, - "Clear All": { - "Clear All": "Rensa allt" - }, - "Clear All Jobs": { - "Clear All Jobs": "Rensa alla jobb" - }, - "Clear History?": { - "Clear History?": "Rensa historik?" - }, - "Clear Sky": { - "Clear Sky": "Klar himmel" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Rensa all historik när servern startar" - }, - "Clear at Startup": { - "Clear at Startup": "Rensa vid start" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "Klicka på 'Konfiguration' för att skapa %1 och lägga till inkludering i konfigurationen." - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "Klicka på 'Konfiguration' för att skapa %1 och lägga till inkludering i din kompositorkonfiguration." - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "Klicka på 'Konfiguration' för att skapa markörskonfigurationen och lägga till inkludering i din kompositorkonfiguration." - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Klicka på 'Konfiguration' för att skapa utgångskonfigurationen och lägga till inkludering i din kompositorkonfiguration." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "Klicka på Importera för att lägga till en .ovpn- eller .conf-fil" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "Klicka på Uppdatera för att kontrollera status." - }, - "Click Through": { - "Click Through": "Klick igenom" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "Klicka på ett kortkommando för att redigera. Ändringar sparas i %1" - }, - "Click to capture": { - "Click to capture": "Klicka för att fånga" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Klicka för att välja en anpassad JSON-temafil" - }, - "Clip": { - "Clip": "Klipp" - }, - "Clip to Geometry": { - "Clip to Geometry": "Klipp till geometri" - }, - "Clipboard": { - "Clipboard": "Urklipp" - }, - "Clipboard History": { - "Clipboard History": "Urklippshistorik" - }, - "Clipboard Manager": { - "Clipboard Manager": "Urklippshanterare" - }, - "Clipboard sent": { - "Clipboard sent": "Urklipp skickat" - }, - "Clipboard service not available": { - "Clipboard service not available": "Urklippstjänsten är inte tillgänglig" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Urklipp fungerar men inget sparas till disk" - }, - "Clock": { - "Clock": "Klocka" - }, - "Clock Style": { - "Clock Style": "Klockstil" - }, - "Close": { - "Close": "Stäng" - }, - "Close All Windows": { - "Close All Windows": "Stäng alla fönster" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Stäng översikt vid start" - }, - "Close Window": { - "Close Window": "Stäng fönster" - }, - "Color": { - "Color": "Färg" - }, - "Color Gamut": { - "Color Gamut": "Färgomfång" - }, - "Color Management": { - "Color Management": "Färghantering" - }, - "Color Mode": { - "Color Mode": "Färgläge" - }, - "Color Override": { - "Color Override": "Anpassad färg" - }, - "Color Picker": { - "Color Picker": "Färgverktyg" - }, - "Color Temperature": { - "Color Temperature": "Färgtemperatur" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Färg som visas på bildskärmar utan låsskärm" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "Färg på primära åtgärdsknappar" - }, - "Color temperature for day time": { - "Color temperature for day time": "Färgtemperatur för dagtid" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Färgtemperatur för nattläge" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "Färgtema för syntaxmarkering." - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "Färgtema för syntaxmarkering. %1 teman tillgängliga." - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "Färgtema från DMS-registret" - }, - "Colorful": { - "Colorful": "Färgglad" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Färgrik blandning av ljusa kontrastfärger." - }, - "Colorize Active": { - "Colorize Active": "Färglägg aktiv" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "Färger från bakgrundsbild" - }, - "Column": { - "Column": "Kolumn" - }, - "Column Display": { - "Column Display": "Kolumnvisning" - }, - "Column Width": { - "Column Width": "Kolumnbredd" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "Kommaseparerad lista med sessionsnamn att dölja. Omslut med snedstreck för regex (t.ex. /^_.*/)." - }, - "Command": { - "Command": "Kommando" - }, - "Commands": { - "Commands": "Kommandon" - }, - "Communication": { - "Communication": "Samtal" - }, - "Community themes": { - "Community themes": "Gemenskapsteman" - }, - "Compact": { - "Compact": "Kompakt" - }, - "Compact Mode": { - "Compact Mode": "Kompakt läge" - }, - "Completed": { - "Completed": "Klar" - }, - "Compositor": { - "Compositor": "Kompositor" - }, - "Compositor Settings": { - "Compositor Settings": "Kompositoriminställningar" - }, - "Compositor not supported": { - "Compositor not supported": "Kompositor stöds inte" - }, - "Config Format": { - "Config Format": "Konfigurationsformat" - }, - "Config action: %1": { - "Config action: %1": "Konfigurationsåtgärd: %1" - }, - "Config validation failed": { - "Config validation failed": "Konfigurationsvalidering misslyckades" - }, - "Configuration": { - "Configuration": "Konfiguration" - }, - "Configuration activated": { - "Configuration activated": "Konfiguration aktiverad" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Konfigurationen bevaras när denna bildskärm återansluts" - }, - "Configure": { - "Configure": "Konfigurera" - }, - "Configure Keybinds": { - "Configure Keybinds": "Konfigurera kortkommandon" - }, - "Configure a new printer": { - "Configure a new printer": "Konfigurera en ny skrivare" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Anpassa ikoner till arbetsytor med namn. Ikoner prioriteras före arbetsytans nummer när båda aktiveras." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "Konfigurera matchkriterier och åtgärder" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "Konfigurera vilka bildskärmar som visar \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Konfigurera vilka bildskärmar visar shellkomponenter" - }, - "Confirm": { - "Confirm": "Bekräfta" - }, - "Confirm Delete": { - "Confirm Delete": "Bekräfta radering" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Bekräfta skärmändringar" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Bekräfta lösenkod för " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Konflikt med: %1" - }, - "Connect": { - "Connect": "Anslut" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "Anslut till dolt nätverk" - }, - "Connect to VPN": { - "Connect to VPN": "Anslut till VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Anslut till Wi-Fi" - }, - "Connected": { - "Connected": "Ansluten" - }, - "Connected Device": { - "Connected Device": "Ansluten enhet" - }, - "Connected Displays": { - "Connected Displays": "Anslutna bildskärmar" - }, - "Connecting to Device": { - "Connecting to Device": "Ansluter till enhet" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Ansluter..." - }, - "Connection failed": { - "Connection failed": "Anslutning misslyckades" - }, - "Contains": { - "Contains": "Innehåller" - }, - "Content": { - "Content": "Innehåll" - }, - "Content copied": { - "Content copied": "Innehåll kopierat" - }, - "Contrast": { - "Contrast": "Kontrast" - }, - "Control Center": { - "Control Center": "Kontrollcenter" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "Färg på kontrollcentrets platta" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "Styr animeringstid för notisbanderoller och historik" - }, - "Control currently playing media": { - "Control currently playing media": "Styr medier som spelas nu" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "Styr vilken notissinformation som visas på låsskärmen" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "Styr vilka tillägg som visas i 'Alla'-läget utan att kräva ett utlösarprefix. Dra för att ordna om." - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Styr arbetsytor och kolumner genom att rulla på menyraden" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Styr opaciteten för alla popupfönster, dialogrutor och deras innehållslager" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "Styr skuggkastningsriktning för upphöjningslager" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "Styr grundoskärperadien och förskjutningen av skuggor" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "Styr skuggans genomskinlighet" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "Bekvämlighetsalternativ för inloggningsskärmen. Synka för att tillämpa." - }, - "Cooldown": { - "Cooldown": "Nedkylningstid" - }, - "Copied GIF": { - "Copied GIF": "GIF kopierat" - }, - "Copied MP4": { - "Copied MP4": "MP4 kopierat" - }, - "Copied WebP": { - "Copied WebP": "WebP kopierat" - }, - "Copied to clipboard": { - "Copied to clipboard": "Kopierat till urklipp" - }, - "Copied!": { - "Copied!": "Kopierat!" - }, - "Copy": { - "Copy": "Kopiera" - }, - "Copy Content": { - "Copy Content": "Kopiera innehåll" - }, - "Copy Full Command": { - "Copy Full Command": "Kopiera fullständigt kommando" - }, - "Copy HTML": { - "Copy HTML": "Kopiera HTML" - }, - "Copy Name": { - "Copy Name": "Kopiera namn" - }, - "Copy PID": { - "Copy PID": "Kopiera PID" - }, - "Copy Text": { - "Copy Text": "Kopiera text" - }, - "Copy path": { - "Copy path": "Kopiera sökväg" - }, - "Corner Radius": { - "Corner Radius": "Hörnradie" - }, - "Corner Radius Override": { - "Corner Radius Override": "Anpassad hörnradie" - }, - "Corners & Background": { - "Corners & Background": "Hörn & bakgrund" - }, - "Count Only": { - "Count Only": "Bara antal" - }, - "Cover Open": { - "Cover Open": "Övre lock öppet" - }, - "Create": { - "Create": "Skapa" - }, - "Create Dir": { - "Create Dir": "Skapa mapp" - }, - "Create Printer": { - "Create Printer": "Skapa skrivare" - }, - "Create Window Rule": { - "Create Window Rule": "Skapa fönsterregel" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "Skapa en ny %1-session (n)" - }, - "Create rule for:": { - "Create rule for:": "Skapa regel för:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "Skapa regler för att tysta, ignorera, dölja från historiken eller åsidosätta notisprioriteten. Standard åsidosätter bara prioriteten; notiser visas fortfarande normalt." - }, - "Creating...": { - "Creating...": "Skapar..." - }, - "Critical Priority": { - "Critical Priority": "Kritisk prioritet" - }, - "Current": { - "Current": "Aktuell" - }, - "Current Items": { - "Current Items": "Aktuella objekt" - }, - "Current Locale": { - "Current Locale": "Aktuellt språk" - }, - "Current Monitor": { - "Current Monitor": "Aktuell bildskärm" - }, - "Current Period": { - "Current Period": "Aktuell period" - }, - "Current Status": { - "Current Status": "Aktuell status" - }, - "Current Temp": { - "Current Temp": "Aktuell temperatur" - }, - "Current Theme: %1": { - "Current Theme: %1": "Aktuellt tema: %1" - }, - "Current Weather": { - "Current Weather": "Vädret just nu" - }, - "Current Workspace": { - "Current Workspace": "Aktuell arbetsyta" - }, - "Current time and date display": { - "Current time and date display": "Visa aktuell tid och datum" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Visa aktuella väderförhållanden och temperatur" - }, - "Current: %1": { - "Current: %1": "Aktuell: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "Markörskonfiguration ej konfigurerad" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "Markörinkludering saknas" - }, - "Cursor Size": { - "Cursor Size": "Markörstorlek" - }, - "Cursor Theme": { - "Cursor Theme": "Markörtemat" - }, - "Custom": { - "Custom": "Anpassad" - }, - "Custom Color": { - "Custom Color": "Anpassad färg" - }, - "Custom Duration": { - "Custom Duration": "Anpassad tidslängd" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Anpassat vilolägeskommando" - }, - "Custom Location": { - "Custom Location": "Anpassad plats" - }, - "Custom Lock Command": { - "Custom Lock Command": "Anpassat låskommando" - }, - "Custom Logout Command": { - "Custom Logout Command": "Anpassat utloggningskommando" - }, - "Custom Name": { - "Custom Name": "Anpassat namn" - }, - "Custom Power Actions": { - "Custom Power Actions": "Anpassade strömåtgärder" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Anpassat stäng av-kommando" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Anpassat omstartskommando" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "Anpassad skuggfärg" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "Anpassad skuggöverstyrning" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Anpassat strömsparlägeskommando" - }, - "Custom Transparency": { - "Custom Transparency": "Anpassad genomskinlighet" - }, - "Custom power profile": { - "Custom power profile": "Anpassad energiprofil" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Anpassat tema inläst från JSON-fil" - }, - "Custom...": { - "Custom...": "Anpassad..." - }, - "Custom: ": { - "Custom: ": "Anpassat: " - }, - "Customizable empty space": { - "Customizable empty space": "Anpassningsbart mellanrum" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Anpassa vilka åtgärder som visas i strömmenyn" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI-bildskärm" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMO-LÄGE - Klicka var som helst för att avbryta" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS-tilläggshanterare otillgänglig" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS-kortkommandon" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS är utdaterat" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS-tjänsten är inte ansluten. Urklippsinställningar är inte tillgängliga." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS shellåtgärder (startare, urklipp, o.s.v.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET otillgänglig" - }, - "DWL service not available": { - "DWL service not available": "DWL-tjänsten är inte tillgänglig" - }, - "Daily": { - "Daily": "Dagligen" - }, - "Daily at:": { - "Daily at:": "Dagligen vid:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell är redo att användas" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell & systemikoner (kräver omstart)" - }, - "Dark Mode": { - "Dark Mode": "Mörkt läge" - }, - "Dark mode base": { - "Dark mode base": "Mörkt läge-bas" - }, - "Dark mode harmony": { - "Dark mode harmony": "Mörkt läge-harmoni" - }, - "Darken Modal Background": { - "Darken Modal Background": "Mörklägg bakgrund bakom dialogrutor" - }, - "Date Format": { - "Date Format": "Datumformat" - }, - "Date format": { - "Date format": "Datumformat" - }, - "Date format on greeter": { - "Date format on greeter": "Datumformat på välkomstskärmen" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Gryning (astronomisk skymning)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Gryning (civil skymning)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Gryning (nautisk skymning)" - }, - "Day Date": { - "Day Date": "Dag Datum" - }, - "Day Month Date": { - "Day Month Date": "Dag Månad Datum" - }, - "Day Temperature": { - "Day Temperature": "Dagstemperatur" - }, - "Daytime": { - "Daytime": "Dagtid" - }, - "Deck": { - "Deck": "Kortlek" - }, - "Default": { - "Default": "Standard" - }, - "Default (Black)": { - "Default (Black)": "Standard (svart)" - }, - "Default Width (%)": { - "Default Width (%)": "Standardbredd (%)" - }, - "Default selected action": { - "Default selected action": "Förvald åtgärd" - }, - "Defaults": { - "Defaults": "Standardinställningar" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "Definiera regler för fönsterbeteende. Sparas i %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Rensa • Skift+Del: Rensa allt • 1-9: Åtgärder • F10: Hjälp • Esc: Stäng" - }, - "Delete": { - "Delete": "Radera" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "Radera \"%1\"?" - }, - "Delete Class": { - "Delete Class": "Radera klass" - }, - "Delete Printer": { - "Delete Printer": "Radera skrivare" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "Radera sparat objekt?" - }, - "Delete VPN": { - "Delete VPN": "Radera VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "Radera klassen \"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "Radera profilen \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "Beroenden och dokumentation" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Hämtar färger som nära matchar den underliggande bilden." - }, - "Description": { - "Description": "Beskrivning" - }, - "Desktop": { - "Desktop": "Skrivbord" - }, - "Desktop Clock": { - "Desktop Clock": "Skrivbordsklocka" - }, - "Desktop Entry": { - "Desktop Entry": "Skrivbordspost" - }, - "Desktop Widget": { - "Desktop Widget": "Skrivbordswidget" - }, - "Desktop Widgets": { - "Desktop Widgets": "Skrivbordswidgetar" - }, - "Desktop background images": { - "Desktop background images": "Skrivbordsbakgrund" - }, - "Detailed": { - "Detailed": "Detaljerad" - }, - "Details for \"%1": { - "Details for \"%1\"": "Detaljer för \"%1\"" - }, - "Development": { - "Development": "Utveckling" - }, - "Device": { - "Device": "Enhet" - }, - "Device connections": { - "Device connections": "Enhetsanslutningar" - }, - "Device names updated": { - "Device names updated": "Enhetsnamn uppdaterade" - }, - "Device paired": { - "Device paired": "Enheten parkopplad" - }, - "Device unpaired": { - "Device unpaired": "Enhet bortkopplad" - }, - "Digital": { - "Digital": "Digital" - }, - "Direction Source": { - "Direction Source": "Riktningskälla" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Avaktivera automatisk anslutning" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Inaktivera inbyggda bakgrundsbilder" - }, - "Disable History Persistence": { - "Disable History Persistence": "Avaktivera historiklagring" - }, - "Disable Output": { - "Disable Output": "Avaktivera utgång" - }, - "Disabled": { - "Disabled": "Avaktiverat" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "Avaktiverar Wi-Fi..." - }, - "Disc": { - "Disc": "Skiva" - }, - "Discard": { - "Discard": "Ignorera" - }, - "Discharging": { - "Discharging": "Laddar ur" - }, - "Disconnect": { - "Disconnect": "Koppla från" - }, - "Disconnected": { - "Disconnected": "Frånkopplad" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Frånkopplad från Wi-Fi" - }, - "Discover Devices": { - "Discover Devices": "Upptäck enheter" - }, - "Disk": { - "Disk": "Disk" - }, - "Disk I/O": { - "Disk I/O": "Disk-I/O" - }, - "Disk Usage": { - "Disk Usage": "Diskanvändning" - }, - "Disk Usage Display": { - "Disk Usage Display": "Diskanvändningsvisning" - }, - "Disks": { - "Disks": "Diskar" - }, - "Dismiss": { - "Dismiss": "Stäng" - }, - "Display": { - "Display": "Bildskärm" - }, - "Display Assignment": { - "Display Assignment": "Bildskärmstilldelning" - }, - "Display Control": { - "Display Control": "Bildskärmskontroll" - }, - "Display Name Format": { - "Display Name Format": "Format för bildskärmsnamn" - }, - "Display Profiles": { - "Display Profiles": "Bildskärmsprofiler" - }, - "Display Settings": { - "Display Settings": "Bildskärmsinställningar" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Visa en dock med fästa och aktiva appar" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Visa alla prioritetsnotiser ovanpå appar i helskärmsläge" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "Visa och växla DWL-layouter" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Visa appikoner i arbetsytans indikatorer" - }, - "Display brightness control": { - "Display brightness control": "Kontroll för bildskärmsljusstyrka" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Bildskärmskonfiguration är inte tillgänglig. WLR-utgångshanteringsprotokollet stöds inte." - }, - "Display currently focused application title": { - "Display currently focused application title": "Visa rubrik på appen i fokus" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "Visa timvisa väderprognoser" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Visa bara arbetsytor som innehåller fönster" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Visa strömmenyn i rutnätsform istället för lista" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Visa sekunder i klockan" - }, - "Display the power system menu": { - "Display the power system menu": "Visa strömmenyn" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "Visa volym- och ljusstyrkaprocent i skärmvisningspopupfönster" - }, - "Displays": { - "Displays": "Bildskärmar" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "Antal bildskärmar när overflow är aktivt" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Visa aktiv tangentbordslayout och växla tangentbordslayouter" - }, - "Distribution": { - "Distribution": "Distribution" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Varierad palett som spänner hela färgspektrumet." - }, - "Do Not Disturb": { - "Do Not Disturb": "Stör ej" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock & Appstartare" - }, - "Dock Transparency": { - "Dock Transparency": "Genomskinlighet på Dock" - }, - "Dock Visibility": { - "Dock Visibility": "Docksynlighet" - }, - "Docs": { - "Docs": "Dokumentation" - }, - "Documents": { - "Documents": "Dokument" - }, - "Domain (optional)": { - "Domain (optional)": "Domän (valfritt)" - }, - "Don't Change": { - "Don't Change": "Ändra inte" - }, - "Don't Save": { - "Don't Save": "Spara inte" - }, - "Door Open": { - "Door Open": "Dörr öppen" - }, - "Downloads": { - "Downloads": "Hämtningar" - }, - "Drag to Reorder": { - "Drag to Reorder": "Dra för att ordna om" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Håll och dra för att ordna widgetar inom en avdelning. Klicka på ögat för att gömma eller visa widgetar (mellanrum bevaras), eller X för att ta bort dem." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "Dra arbetsytans indikatorer för att ordna om dem" - }, - "Driver": { - "Driver": "Drivrutin" - }, - "Drizzle": { - "Drizzle": "Duggregn" - }, - "Duplicate": { - "Duplicate": "Duplicera" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Duplicera bakgrundsbild med oskärpa" - }, - "Duration": { - "Duration": "Tid" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Skymning (astronomisk skymning)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Skymning (civil skymning)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Skymning (nautisk skymning)" - }, - "Dynamic": { - "Dynamic": "Dynamisk" - }, - "Dynamic Properties": { - "Dynamic Properties": "Dynamiska egenskaper" - }, - "Dynamic Theming": { - "Dynamic Theming": "Dynamisk tematisering" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Dynamiska färger från bakgrundsbild" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "Dynamiska färger, förinställningar" - }, - "Edge Spacing": { - "Edge Spacing": "Avstånd från skärmkanter" - }, - "Edit App": { - "Edit App": "Redigera app" - }, - "Edit Window Rule": { - "Edit Window Rule": "Redigera fönsterregel" - }, - "Education": { - "Education": "Utbildning" - }, - "Empty": { - "Empty": "Tom" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Aktivera 10-bitars färgdjup för bredare färgomfång och HDR-stöd" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Aktivera automatisk anslutning" - }, - "Enable Bar": { - "Enable Bar": "Aktivera menyrad" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Aktivera Stör ej" - }, - "Enable History": { - "Enable History": "Aktivera historik" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Aktivera översiktsöverlägg" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "Aktivera rippeleffekter" - }, - "Enable System Sounds": { - "Enable System Sounds": "Aktivera systemljud" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "Aktivera videoskärmsläckare" - }, - "Enable Weather": { - "Enable Weather": "Aktivera Väder" - }, - "Enable WiFi": { - "Enable WiFi": "Aktivera Wi-Fi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "Aktivera en anpassad överstyrning nedan för att ange skuggintensitet, opacitet och färg per menyrad." - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Aktivera kompositor-riktbart oskärpelager (namnrymd: dms:blurwallpaper). Kräver manuell niri-konfiguration." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "Aktivera fingeravtryck vid inloggning" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Aktivera fingeravtrycksautentisering" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "Aktivera låsintegration med loginctl" - }, - "Enable security key at login": { - "Enable security key at login": "Aktivera säkerhetsnyckel vid inloggning" - }, - "Enable security key authentication": { - "Enable security key authentication": "Aktivera säkerhetsnyckelautentisering" - }, - "Enabled": { - "Enabled": "Aktiverat" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "Aktiverat, men fingeravtryckstillgänglighet kunde inte bekräftas." - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "Aktiverat, men ingen fingeravtrycksläsare hittades." - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "Aktiverat, men inga fingeravtryck har registrerats ännu. Registrera fingeravtryck och kör Synka." - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "Aktiverat, men ingen registrerad säkerhetsnyckel hittades ännu. Registrera en nyckel och kör Synka." - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "Aktiverat, men säkerhetsnyckelns tillgänglighet kunde inte bekräftas." - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "Aktiverat. PAM tillhandahåller redan fingeravtrycksautentisering." - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "Aktiverat. PAM tillhandahåller redan säkerhetsnyckelautentisering." - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "Aktiverat. PAM tillhandahåller fingeravtrycksautentisering, men inga fingeravtryck har registrerats ännu." - }, - "Enabling WiFi...": { - "Enabling WiFi...": "Aktiverar Wi-Fi..." - }, - "End": { - "End": "Slut" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "Förstora vid hovring" - }, - "Enlargement %": { - "Enlargement %": "Förstoring %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "Ange 6-siffrig lösenkod" - }, - "Enter PIN": { - "Enter PIN": "Ange PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "Ange PIN för " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "Ange URL eller text att dela" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "Ange ett nytt namn för sessionen \"%1\"" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "Ange ett nytt namn för denna arbetsyta" - }, - "Enter command or script path": { - "Enter command or script path": "Ange kommando eller skriptsökväg" - }, - "Enter credentials for ": { - "Enter credentials for ": "Ange inloggningsuppgifter för " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Lägg till anpassat datumformat på låsskärmen (t.ex., dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Lägg till anpassat datumformat i menyraden (t.ex., ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "Ange enhetsnamn..." - }, - "Enter filename...": { - "Enter filename...": "Lägg till filnamn..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Ange startprefix (t.ex. 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "Ange nätverksnamn och lösenord" - }, - "Enter passkey for ": { - "Enter passkey for ": "Ange lösenkod för " - }, - "Enter password for ": { - "Enter password for ": "Ange lösenord för " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Ange denna lösenkod på " - }, - "Enter to Paste": { - "Enter to Paste": "Retur för att klistra in" - }, - "Enterprise": { - "Enterprise": "Enterprise" - }, - "Entry pinned": { - "Entry pinned": "Post fäst" - }, - "Entry unpinned": { - "Entry unpinned": "Post borttagen från fästning" - }, - "Environment Variables": { - "Environment Variables": "Miljövariabler" - }, - "Error": { - "Error": "Fel" - }, - "Errors": { - "Errors": "Fel" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "Exakt" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Avstånd från fönster" - }, - "Experimental Feature": { - "Experimental Feature": "Experimentell funktion" - }, - "Explore": { - "Explore": "Utforska" - }, - "Exponential": { - "Exponential": "Exponentiell" - }, - "Expressive": { - "Expressive": "Uttrycksfull" - }, - "Extend battery life": { - "Extend battery life": "Förläng batteritiden" - }, - "Extensible architecture": { - "Extensible architecture": "Utbyggbar arkitektur" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Extern bakgrundsbildshantering" - }, - "Extra Arguments": { - "Extra Arguments": "Extra argument" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Växla • F10: Hjälp" - }, - "Fade": { - "Fade": "Tona" - }, - "Fade to lock screen": { - "Fade to lock screen": "Tona till låsskärm" - }, - "Fade to monitor off": { - "Fade to monitor off": "Tona till bildskärm av" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "Misslyckades med att acceptera parkoppling" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Misslyckades med att aktivera konfiguration" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "Misslyckades med att aktivera profil – filen hittades inte" - }, - "Failed to add binds include": { - "Failed to add binds include": "Misslyckades med att lägga till inkludering av kortkommandon" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Misslyckades med att lägga till skrivare i klass" - }, - "Failed to browse device": { - "Failed to browse device": "Misslyckades med att bläddra på enhet" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Misslyckades med att avbryta alla jobb" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Misslyckades med att avbryta valt jobb" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "Misslyckades med att söka efter uppdateringar:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "Misslyckades med att kontrollera fästningsgräns" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "Misslyckades med att ansluta till VPN" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "Misslyckades med att ansluta till %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "Misslyckades med att kopiera post" - }, - "Failed to create printer": { - "Failed to create printer": "Misslyckades med att skapa skrivare" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "Misslyckades med att skapa profilmapp" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "Misslyckades med att radera VPN" - }, - "Failed to delete class": { - "Failed to delete class": "Misslyckades med att radera klass" - }, - "Failed to delete printer": { - "Failed to delete printer": "Misslyckades med att radera skrivare" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "Misslyckades med att inaktivera jobbmottagning" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Misslyckades med att avaktivera nattläge" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "Misslyckades med att koppla från VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "Misslyckades med att koppla från VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "Misslyckades med att koppla från Wi-Fi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "Misslyckades med att aktivera IP-plats" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "Misslyckades med att aktivera Wi-Fi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "Misslyckades med att aktivera jobbmottagning" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Misslyckades med att aktivera nattläge" - }, - "Failed to hold job": { - "Failed to hold job": "Misslyckades med att pausa jobb" - }, - "Failed to import VPN": { - "Failed to import VPN": "Misslyckades med att importera VPN" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "Misslyckades med att starta SMS-app" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "Misslyckades med att läsa in VPN-konfiguration" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Misslyckades med att läsa in urklippskonfiguration." - }, - "Failed to move job": { - "Failed to move job": "Misslyckades med att flytta jobb" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "Misslyckades med att tolka plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "Misslyckades med att tolka session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "Misslyckades med att tolka settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "Misslyckades med att pausa skrivaren" - }, - "Failed to pin entry": { - "Failed to pin entry": "Misslyckades med att fästa post" - }, - "Failed to print test page": { - "Failed to print test page": "Misslyckades med att skriva ut testsida" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "Misslyckades med att avvisa parkoppling" - }, - "Failed to remove device": { - "Failed to remove device": "Misslyckades med att ta bort enhet" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Misslyckades med att ta bort kortkommando" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Misslyckades med att ta bort skrivare från klass" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "Misslyckades med att starta om ljudsystemet" - }, - "Failed to restart job": { - "Failed to restart job": "Misslyckades med att starta om jobb" - }, - "Failed to resume printer": { - "Failed to resume printer": "Misslyckades med att återuppta skrivaren" - }, - "Failed to ring device": { - "Failed to ring device": "Misslyckades med att ringa enheten" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "Misslyckades med att köra 'dms greeter status'. Se till att DMS är installerat och att dms finns i PATH." - }, - "Failed to save audio config": { - "Failed to save audio config": "Misslyckades med att spara ljudkonfiguration" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Misslyckades med att spara urklippsinställning" - }, - "Failed to save keybind": { - "Failed to save keybind": "Misslyckades med att spara kortkommando" - }, - "Failed to save profile file": { - "Failed to save profile file": "Misslyckades med att spara profilfil" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "Misslyckades med att skicka urklipp" - }, - "Failed to send file": { - "Failed to send file": "Misslyckades med att skicka fil" - }, - "Failed to send ping": { - "Failed to send ping": "Misslyckades med att skicka ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "Misslyckades med att ange ljusstyrka" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Misslyckades med att ange nattlägesplats" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Misslyckades med att ange nattlägesschema" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Misslyckades med att ange nattlägestemperatur" - }, - "Failed to set power profile": { - "Failed to set power profile": "Misslyckades med att ange energiprofil" - }, - "Failed to set profile image": { - "Failed to set profile image": "Misslyckades med att ändra profilbild" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Misslyckades med att ange profilbild: %1" - }, - "Failed to share": { - "Failed to share": "Misslyckades med att dela" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "Misslyckades med att starta anslutning till %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "Misslyckades med att ta bort fästning av post" - }, - "Failed to update VPN": { - "Failed to update VPN": "Misslyckades med att uppdatera VPN" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Misslyckades med att uppdatera automatisk anslutning" - }, - "Failed to update description": { - "Failed to update description": "Misslyckades med att uppdatera beskrivning" - }, - "Failed to update location": { - "Failed to update location": "Misslyckades med att uppdatera plats" - }, - "Failed to update sharing": { - "Failed to update sharing": "Misslyckades med att uppdatera delning" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Misslyckades med att skriva temporär fil för validering" - }, - "Features": { - "Features": "Funktioner" - }, - "Feels": { - "Feels": "Känns som" - }, - "Feels Like": { - "Feels Like": "Känns som" - }, - "Feels Like %1°": { - "Feels Like %1°": "Känns som %1°" - }, - "Fidelity": { - "Fidelity": "Trohet" - }, - "Field": { - "Field": "Fält" - }, - "File": { - "File": "Fil" - }, - "File Already Exists": { - "File Already Exists": "Filen finns redan" - }, - "File Information": { - "File Information": "Filinformation" - }, - "File received from": { - "File received from": "Fil mottagen från" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Filsökning kräver dsearch\nInstallera från github.com/AvengeMedia/danksearch" - }, - "Files": { - "Files": "Filer" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Övervakning av filsystemsanvändning" - }, - "Fill": { - "Fill": "Fyll" - }, - "Find in Text": { - "Find in Text": "Sök i text" - }, - "Find in note...": { - "Find in note...": "Sök i anteckning..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "Fingeravtryckstillgänglighet kunde inte bekräftas." - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "Fingeravtrycksläsare hittades, men inga fingeravtryck har registrerats ännu. Du kan aktivera detta nu och registrera senare." - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "Fingeravtrycksläsare hittades, men inga fingeravtryck har registrerats ännu. Du kan aktivera detta nu och köra Synka senare." - }, - "Finish": { - "Finish": "Klar" - }, - "First Day of Week": { - "First Day of Week": "Veckans första dag" - }, - "First Time Setup": { - "First Time Setup": "Förstagångsinställning" - }, - "Fit": { - "Fit": "Anpassa" - }, - "Fix Now": { - "Fix Now": "Åtgärda nu" - }, - "Fixing...": { - "Fixing...": "Åtgärdar..." - }, - "Flags": { - "Flags": "Flaggor" - }, - "Flipped": { - "Flipped": "Speglad" - }, - "Flipped 180°": { - "Flipped 180°": "Speglad 180°" - }, - "Flipped 270°": { - "Flipped 270°": "Speglad 270°" - }, - "Flipped 90°": { - "Flipped 90°": "Speglad 90°" - }, - "Float": { - "Float": "Flytande" - }, - "Focus": { - "Focus": "Fokus" - }, - "Focus at Startup": { - "Focus at Startup": "Fokusera vid start" - }, - "Focused Border": { - "Focused Border": "Fokusrad ram" - }, - "Focused Color": { - "Focused Color": "Fokusradfärg" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "Bara fokuserad bildskärm" - }, - "Focused Window": { - "Focused Window": "Fönster i fokus" - }, - "Focused monitor only": { - "Focused monitor only": "Bara fokuserad bildskärm" - }, - "Fog": { - "Fog": "Dimma" - }, - "Folder": { - "Folder": "Mapp" - }, - "Folders": { - "Folders": "Mappar" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "Följ bildskärmsfokus" - }, - "Follow focus": { - "Follow focus": "Följ fokus" - }, - "Font": { - "Font": "Teckensnitt" - }, - "Font Family": { - "Font Family": "Teckensnittsfamilj" - }, - "Font Scale": { - "Font Scale": "Teckenskala" - }, - "Font Size": { - "Font Size": "Teckenstorlek" - }, - "Font Weight": { - "Font Weight": "Teckensnittsvikt" - }, - "Font used on the login screen": { - "Font used on the login screen": "Teckensnitt som används på inloggningsskärmen" - }, - "Force HDR": { - "Force HDR": "Tvinga HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "Tvångsavsluta (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "Tvinga bred färg" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Tvinga terminalprogram att alltid använda mörkt tema" - }, - "Forecast": { - "Forecast": "Prognos" - }, - "Forecast Days": { - "Forecast Days": "Prognos­dagar" - }, - "Forecast Not Available": { - "Forecast Not Available": "Prognos otillgänglig" - }, - "Forever": { - "Forever": "Obegränsat" - }, - "Forget": { - "Forget": "Glöm" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "Glöm \"%1\"?" - }, - "Forget Device": { - "Forget Device": "Glöm enhet" - }, - "Forget Network": { - "Forget Network": "Glöm nätverk" - }, - "Forgot network %1": { - "Forgot network %1": "Glömde nätverket %1" - }, - "Format Legend": { - "Format Legend": "Formateringsguide" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "Hittade %1 paket att uppdatera:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "Hittade %1 paket att uppdatera:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "Frigör VRAM/minne när startaren stängs. Kan orsaka en liten fördröjning vid återöppning." - }, - "Freezing Drizzle": { - "Freezing Drizzle": "Isande duggregn" - }, - "Frequency": { - "Frequency": "Frekvens" - }, - "Fruit Salad": { - "Fruit Salad": "Fruktblandning" - }, - "Full Command:": { - "Full Command:": "Fullständigt kommando:" - }, - "Full Content": { - "Full Content": "Fullständigt innehåll" - }, - "Full Day & Month": { - "Full Day & Month": "Fullständig dag och månad" - }, - "Full with Year": { - "Full with Year": "Fullständigt med år" - }, - "Fullscreen": { - "Fullscreen": "Helskärm" - }, - "Fullscreen Only": { - "Fullscreen Only": "Endast helskärm" - }, - "Fully Charged": { - "Fully Charged": "Fulladdat" - }, - "Fun": { - "Fun": "Nöje" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: rutnät • Z/X: storlek" - }, - "GPU": { - "GPU": "Grafikkort" - }, - "GPU Monitoring": { - "GPU Monitoring": "Grafikkorts­övervakning" - }, - "GPU Temperature": { - "GPU Temperature": "Grafikkortstemperatur" - }, - "GPU temperature display": { - "GPU temperature display": "Grafikkortstemperaturvisning" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK, Qt, IDE:er och mer" - }, - "Games": { - "Games": "Spel" - }, - "Gamma Control": { - "Gamma Control": "Gamma-kontroll" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Gammakontroll är inte tillgänglig. Kräver DMS API v6+." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "Generera grundläggande GTK3/4- eller QT5/QT6-konfigurationer (kräver qt6ct-kde) för att följa DMS-färger. Behövs bara en gång.

        Det rekommenderas att konfigurera adw-gtk3 innan GTK-teman tillämpas." - }, - "Generic": { - "Generic": "Generisk" - }, - "Get Started": { - "Get Started": "Kom igång" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "Skala alla animeringstider globalt" - }, - "Golden Hour": { - "Golden Hour": "Gyllene timmen" - }, - "Good": { - "Good": "Bra" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Goth-hörnradie" - }, - "Goth Corners": { - "Goth Corners": "Goth-kanter" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Tona ner skärmen gradvis före låsning med en konfigurerbar fördröjning" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "Tona ner skärmen gradvis innan bildskärmarna stängs av med en konfigurerbar fördröjning" - }, - "Graph Time Range": { - "Graph Time Range": "Grafens tidsintervall" - }, - "Graphics": { - "Graphics": "Grafik" - }, - "Greeter": { - "Greeter": "Välkomstskärm" - }, - "Greeter Appearance": { - "Greeter Appearance": "Välkomstskärmens utseende" - }, - "Greeter Behavior": { - "Greeter Behavior": "Välkomstskärmens beteende" - }, - "Greeter Status": { - "Greeter Status": "Välkomstskärmens status" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "Välkomstskärmen aktiverad. greetd är nu aktiverat." - }, - "Greeter font": { - "Greeter font": "Välkomstskärmens teckensnitt" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "Gäller bara välkomstskärmen – påverkar inte huvudklockan" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "Gäller bara välkomstskärmen – format för datumet på inloggningsskärmen" - }, - "Grid": { - "Grid": "Rutnät" - }, - "Grid Columns": { - "Grid Columns": "Rutnätskolumner" - }, - "Grid: OFF": { - "Grid: OFF": "Rutnät: AV" - }, - "Grid: ON": { - "Grid: ON": "Rutnät: PÅ" - }, - "Group": { - "Group": "Grupp" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "Gruppera appar i arbetsytor" - }, - "Group by App": { - "Group by App": "Gruppera per app" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Gruppera flera fönster från samma app tillsammans och visa fönsterantal" - }, - "Group removed": { - "Group removed": "Grupp borttagen" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "Gruppera upprepade appikoner i ofokuserade arbetsytor" - }, - "Groups": { - "Groups": "Grupper" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR-tonmappning" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "HDR-läge är experimentellt. Kontrollera att din bildskärm stöder HDR innan du aktiverar." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML kopierat till urklipp" - }, - "Health": { - "Health": "Hälsa" - }, - "Heavy Rain": { - "Heavy Rain": "Kraftigt regn" - }, - "Heavy Snow": { - "Heavy Snow": "Kraftigt snöfall" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "Kraftiga snöbyar" - }, - "Height": { - "Height": "Höjd" - }, - "Held": { - "Held": "Pausat" - }, - "Help": { - "Help": "Hjälp" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Viloläge" - }, - "Hidden": { - "Hidden": "Dolt" - }, - "Hidden (%1)": { - "Hidden (%1)": "Dold (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "Dolda appar" - }, - "Hidden Network": { - "Hidden Network": "Dolt nätverk" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "Dolda appar visas inte i startaren. Högerklicka på en app och välj 'Dölj app' för att dölja den." - }, - "Hide": { - "Hide": "Dölj" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "Dölj tredjepartsappar" - }, - "Hide App": { - "Hide App": "Dölj app" - }, - "Hide Delay": { - "Hide Delay": "Fördröjning vid döljande" - }, - "Hide Indicators": { - "Hide Indicators": "Dölj indikatorer" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Dölj uppdateringswidget" - }, - "Hide When Typing": { - "Hide When Typing": "Dölj vid skrivning" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Dölj när fönster öppnas" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "Dölj markören efter inaktivitet (0 = avaktiverat)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "Dölj markören vid tangenttryckning" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "Dölj markören vid pekskärmsinmatning" - }, - "Hide device": { - "Hide device": "Dölj enhet" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "Dölj notisinnehåll tills det expanderas" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "Dölj notisinnehåll tills det expanderas; banderoller visas hopfällda som standard" - }, - "Hide on Touch": { - "Hide on Touch": "Dölj vid beröring" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Högtrogen palett som bevarar källfärgerna." - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "Markera aktiv app i arbetsytan" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "Markera den aktuellt fokuserade appen inuti arbetsytans indikator" - }, - "History": { - "History": "Historik" - }, - "History Retention": { - "History Retention": "Historikbehållning" - }, - "History Settings": { - "History Settings": "Historiksinställningar" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "Historiken rensad. %1 fästa poster behållna." - }, - "Hold Duration": { - "Hold Duration": "Hålltid" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Håll längre för att bekräfta" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Håll för att bekräfta strömåtgärder" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Håll för att bekräfta (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Håll för att bekräfta (%1 s)" - }, - "Home": { - "Home": "Hem" - }, - "Host": { - "Host": "Värd" - }, - "Hostname": { - "Hostname": "Värdnamn" - }, - "Hot Corners": { - "Hot Corners": "Aktiva hörn" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Titel på genkvägöverlägg (valfritt)" - }, - "Hour": { - "Hour": "Timme" - }, - "Hourly": { - "Hourly": "Timvis" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "Antal timvisa prognoser" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Byt bakgrundsbild efter" - }, - "How the background image is scaled": { - "How the background image is scaled": "Hur bakgrundsbilden skalas" - }, - "Humidity": { - "Humidity": "Luftfuktighet" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Hyprland Discord-server" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland-layoutöverstyrningar" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland-alternativ" - }, - "Hyprland Website": { - "Hyprland Website": "Hyprlands webbplats" - }, - "I Understand": { - "I Understand": "Jag förstår" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP-adress:" - }, - "IP address or hostname": { - "IP address or hostname": "IP-adress eller värdnamn" - }, - "ISO Date": { - "ISO Date": "ISO-datum" - }, - "Icon": { - "Icon": "Ikon" - }, - "Icon Scale": { - "Icon Scale": "Ikonskala" - }, - "Icon Size": { - "Icon Size": "Ikonstorlek" - }, - "Icon Size %": { - "Icon Size %": "Ikonstorlek %" - }, - "Icon Theme": { - "Icon Theme": "Ikontema" - }, - "Idle": { - "Idle": "Inaktiv" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Förhindra strömsparläge" - }, - "Idle Settings": { - "Idle Settings": "Inställningar för strömsparläge" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Stöd för aktivitetsövervakning saknas - kräver nyare Quickshell-version" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Om fältet är dolt visas det så snart en tangent trycks ned." - }, - "Ignore Completely": { - "Ignore Completely": "Ignorera helt" - }, - "Image": { - "Image": "Bild" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Bild kopierad till urklipp" - }, - "Import": { - "Import": "Importera" - }, - "Import VPN": { - "Import VPN": "Importera VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "Inaktiv bildskärmsfärg" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Inkludera övergångar" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "Inkludera skrivbordsåtgärder (genvägar) i sökresultaten." - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Inkompatibla tillägg inlästa" - }, - "Incorrect password": { - "Incorrect password": "Felaktigt lösenord" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "Felaktigt lösenord – försök %1 av %2 (utelåsning kan följa)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "Felaktigt lösenord – nästa misslyckanden kan utlösa kontoutelåsning" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Indikatorstil" - }, - "Individual Batteries": { - "Individual Batteries": "Enskilda batterier" - }, - "Individual bar configuration": { - "Individual bar configuration": "Individuell menyradskonfiguration" - }, - "Info": { - "Info": "Info" - }, - "Inherit": { - "Inherit": "Ärv" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "Ärv global (standard)" - }, - "Inhibitable": { - "Inhibitable": "Kan inhiberas" - }, - "Input Devices": { - "Input Devices": "Ingångsenheter" - }, - "Input Volume Slider": { - "Input Volume Slider": "Inmatningsvolymreglage" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Installera" - }, - "Install Greeter": { - "Install Greeter": "Installera välkomstskärm" - }, - "Install Plugin": { - "Install Plugin": "Installera tillägg" - }, - "Install Theme": { - "Install Theme": "Installera tema" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "Installera färgteman från DMS-temaregistret" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "Installation klar. Välkomstskärmen har installerats." - }, - "Install failed: %1": { - "Install failed: %1": "Installation misslyckades: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Installera matugen-paketet för dynamisk tematisering" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "Installera tillägget '%1' från DMS-registret?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "Installera tillägg från DMS tilläggsregister" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "Installera DMS-välkomstskärmen? En terminal öppnas för sudo-autentisering." - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "Installera temat '%1' från DMS-registret?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "Installation och PAM-inställning: se " - }, - "Installed": { - "Installed": "Installerat" - }, - "Installed: %1": { - "Installed: %1": "Installerat: %1" - }, - "Installing: %1": { - "Installing: %1": "Installerar: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "Intelligent auto-döljande" - }, - "Intensity": { - "Intensity": "Intensitet" - }, - "Interface:": { - "Interface:": "Gränssnitt:" - }, - "Interlock Open": { - "Interlock Open": "Interlock öppet" - }, - "Internet": { - "Internet": "Internet" - }, - "Interval": { - "Interval": "Intervall" - }, - "Invalid configuration": { - "Invalid configuration": "Ogiltig konfiguration" - }, - "Invert on mode change": { - "Invert on mode change": "Invertera vid växling av ljust och mörkt läge" - }, - "Iris Bloom": { - "Iris Bloom": "Iris Bloom" - }, - "Isolate Displays": { - "Isolate Displays": "Isolera bildskärmar" - }, - "Jobs": { - "Jobs": "Jobb" - }, - "Jobs: ": { - "Jobs: ": "Jobb: " - }, - "Keep Awake": { - "Keep Awake": "Håll vaken" - }, - "Keep Changes": { - "Keep Changes": "Behåll ändringar" - }, - "Keeping Awake": { - "Keeping Awake": "Håller vaken" - }, - "Kernel": { - "Kernel": "Kärna" - }, - "Key": { - "Key": "Tangent" - }, - "Keybind Sources": { - "Keybind Sources": "Kortkommandokällor" - }, - "Keybinds": { - "Keybinds": "Kortkommandon" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "Sökinställningar för kortkommandon" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "Kortkommandon visas bredvid vanliga sökresultat" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Namn på tangentbordslayout" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Kortkommandon" - }, - "Keys": { - "Keys": "Tangenter" - }, - "Kill": { - "Kill": "Avsluta" - }, - "Kill Process": { - "Kill Process": "Avsluta process" - }, - "Kill Session": { - "Kill Session": "Avsluta session" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED-enhet" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC-kanal" - }, - "LabWC Website": { - "LabWC Website": "LabWCs webbplats" - }, - "Large": { - "Large": "Stor" - }, - "Largest": { - "Largest": "Störst" - }, - "Last hour": { - "Last hour": "Senaste timmen" - }, - "Last launched %1": { - "Last launched %1": "Startades %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "Startades för %1 dag sedan" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "Startades för %1 dagar sedan" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "Startades för %1 timme sedan" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "Startades för %1 timmar sedan" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "Startades för %1 minut sedan" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "Startades för %1 minuter sedan" - }, - "Last launched just now": { - "Last launched just now": "Startades nyss" - }, - "Latitude": { - "Latitude": "Latitud" - }, - "Launch": { - "Launch": "Kör" - }, - "Launch Prefix": { - "Launch Prefix": "Körprefix" - }, - "Launch on dGPU": { - "Launch on dGPU": "Kör med diskret grafikkort" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Appstartare" - }, - "Launcher Button": { - "Launcher Button": "Startarknapp" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Appstartarknappens ikon" - }, - "Layout": { - "Layout": "Layout" - }, - "Layout Overrides": { - "Layout Overrides": "Layoutöverstyrningar" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "Layout och modulpositioner på välkomstskärmen synkroniseras från ditt skal (t.ex. menyradskonfiguration). Kör Synka för att tillämpa." - }, - "Left": { - "Left": "Vänster" - }, - "Left Center": { - "Left Center": "Vänster mitten" - }, - "Left Section": { - "Left Section": "Vänster avdelning" - }, - "Light Direction": { - "Light Direction": "Ljusriktning" - }, - "Light Mode": { - "Light Mode": "Ljust läge" - }, - "Light Rain": { - "Light Rain": "Lätt regn" - }, - "Light Snow": { - "Light Snow": "Lätt snöfall" - }, - "Light Snow Showers": { - "Light Snow Showers": "Lätta snöbyar" - }, - "Light mode base": { - "Light mode base": "Ljust läge-bas" - }, - "Light mode harmony": { - "Light mode harmony": "Ljust läge-harmoni" - }, - "Line": { - "Line": "Linje" - }, - "Line: %1": { - "Line: %1": "Rad: %1" - }, - "Linear": { - "Linear": "Linjär" - }, - "Lines: %1": { - "Lines: %1": "Rader: %1" - }, - "List": { - "List": "Lista" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Livfull palett med mättade accenter." - }, - "Load Average": { - "Load Average": "Genomsnittlig belastning" - }, - "Loading codecs...": { - "Loading codecs...": "Läser in kodeker..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Läser in kortkommandon..." - }, - "Loading trending...": { - "Loading trending...": "Läser in trendande..." - }, - "Loading...": { - "Loading...": "Läser in..." - }, - "Local": { - "Local": "Lokal" - }, - "Locale": { - "Locale": "Språk" - }, - "Locale Settings": { - "Locale Settings": "Språkinställningar" - }, - "Location": { - "Location": "Plats" - }, - "Location Search": { - "Location Search": "Sök efter plats" - }, - "Lock": { - "Lock": "Lås" - }, - "Lock Screen": { - "Lock Screen": "Låsskärm" - }, - "Lock Screen Display": { - "Lock Screen Display": "Låsskärmsvisning" - }, - "Lock Screen Format": { - "Lock Screen Format": "Datumformat på låsskärm" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Låsskärmsbeteende" - }, - "Lock Screen layout": { - "Lock Screen layout": "Låsskärmslayout" - }, - "Lock at startup": { - "Lock at startup": "Lås vid start" - }, - "Lock before suspend": { - "Lock before suspend": "Lås innan datorn går i strömsparläge" - }, - "Lock fade grace period": { - "Lock fade grace period": "Fördröjning för låstonande" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "Låst" - }, - "Log Out": { - "Log Out": "Logga ut" - }, - "Logging in...": { - "Logging in...": "Loggar in..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "Inloggningsautentisering" - }, - "Long": { - "Long": "Lång" - }, - "Long Text": { - "Long Text": "Lång text" - }, - "Long press": { - "Long press": "Lång tryckning" - }, - "Longitude": { - "Longitude": "Longitud" - }, - "Low Priority": { - "Low Priority": "Låg prioritet" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "Se till att KDE Connect eller Valent körs på dina andra enheter" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "Hantera och konfigurera tillägg för att utöka DMS funktioner" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Hantera upp till 4 oberoende menyradskonfigurationer. Varje menyrad har sin egen position, widgetar, stil och bildskärmstilldelning." - }, - "Management": { - "Management": "Hantering" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC-layoutöverstyrningar" - }, - "Manual": { - "Manual": "Manuell" - }, - "Manual Coordinates": { - "Manual Coordinates": "Manuellt valda koordinater" - }, - "Manual Direction": { - "Manual Direction": "Manuell riktning" - }, - "Manual Gap Size": { - "Manual Gap Size": "Manuell storlek på mellanrum" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Göm och visa manuellt" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "Mappa fönsterklassnamn till ikonnamn för korrekt ikonvisning" - }, - "Margin": { - "Margin": "Marginal" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Bläckförrådet tomt" - }, - "Marker Supply Low": { - "Marker Supply Low": "Bläcknivån låg" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Bläckavfall nästan fullt" - }, - "Marker Waste Full": { - "Marker Waste Full": "Bläckavfall fullt" - }, - "Match Criteria": { - "Match Criteria": "Matchkriterier" - }, - "Matches profile: %1": { - "Matches profile: %1": "Matchar profil: %1" - }, - "Material Colors": { - "Material Colors": "Material-färger" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Färgteman inspirerade av Material Design" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Materialfärger genererade från bakgrundsbild" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "Materialinspirerade skuggor och upphöjning på dialogrutor, popupfönster och dialoger" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen saknas" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen-färgpalett" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen-målbilskärm" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen-mallar" - }, - "Max Edges": { - "Max Edges": "Max kanter" - }, - "Max H": { - "Max H": "Max H" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "Max fästa appar" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "Max fästa appar (0 = obegränsat)" - }, - "Max Running Apps": { - "Max Running Apps": "Max aktiva appar" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "Max aktiva appar (0 = obegränsat)" - }, - "Max Volume": { - "Max Volume": "Maxvolym" - }, - "Max W": { - "Max W": "Max B" - }, - "Max apps to show": { - "Max apps to show": "Högst antal appar att visa" - }, - "Max to Edges": { - "Max to Edges": "Max till kanter" - }, - "Maximize": { - "Maximize": "Maximera" - }, - "Maximize Detection": { - "Maximize Detection": "Detektering av maximering" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "Maximera widgetikoner" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "Maximera widgettext" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maximal poststorlek" - }, - "Maximum History": { - "Maximum History": "Maximal historik" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "Maximalt antal fästa poster" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Maximalt antal urklippsposter att behålla" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "Maximalt antal poster som kan sparas" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "Maximalt antal notiser att behålla" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "Maximalt antal fästa poster uppnått" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Maximal storlek per urklippspost" - }, - "Media": { - "Media": "Medier" - }, - "Media Controls": { - "Media Controls": "Mediereglage" - }, - "Media Empty": { - "Media Empty": "Inget media" - }, - "Media Jam": { - "Media Jam": "Pappersstopp" - }, - "Media Low": { - "Media Low": "Lite media kvar" - }, - "Media Needed": { - "Media Needed": "Media behövs" - }, - "Media Playback": { - "Media Playback": "Mediauppspelning" - }, - "Media Player": { - "Media Player": "Mediespelare" - }, - "Media Player Settings": { - "Media Player Settings": "Inställningar för mediespelaren" - }, - "Media Players": { - "Media Players": "Mediespelare" - }, - "Media Players (": { - "Media Players (": "Mediespelare (" - }, - "Media Volume": { - "Media Volume": "Medievolym" - }, - "Medium": { - "Medium": "Medel" - }, - "Memory": { - "Memory": "Minne" - }, - "Memory Graph": { - "Memory Graph": "Minnesgraf" - }, - "Memory Usage": { - "Memory Usage": "Minnesanvändning" - }, - "Memory usage indicator": { - "Memory usage indicator": "Visa minnesanvändning" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "Meddelande" - }, - "Message Content": { - "Message Content": "Meddelandeinnehåll" - }, - "Microphone": { - "Microphone": "Mikrofon" - }, - "Microphone Mute": { - "Microphone Mute": "Tysta mikrofon" - }, - "Microphone Volume": { - "Microphone Volume": "Mikrofonvolym" - }, - "Microphone settings": { - "Microphone settings": "Mikrofoninställningar" - }, - "Microphone volume control": { - "Microphone volume control": "Mikrofonvolymkontroll" - }, - "Middle Section": { - "Middle Section": "Mittenavdelning" - }, - "Min H": { - "Min H": "Min H" - }, - "Min W": { - "Min W": "Min B" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Minimal palett byggd kring en enda färg." - }, - "Minute": { - "Minute": "Minut" - }, - "Mirror Display": { - "Mirror Display": "Spegla bildskärm" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "Miljövariabler saknas" - }, - "Modal Background": { - "Modal Background": "Dialogrutebakgrund" - }, - "Modal Shadows": { - "Modal Shadows": "Dialogruteskuggor" - }, - "Modals": { - "Modals": "Dialogrutor" - }, - "Mode": { - "Mode": "Läge" - }, - "Mode:": { - "Mode:": "Läge:" - }, - "Model": { - "Model": "Modell" - }, - "Modified": { - "Modified": "Ändrad" - }, - "Modular widget bar": { - "Modular widget bar": "Modulär widgetbar" - }, - "Monitor": { - "Monitor": "Bildskärm" - }, - "Monitor Configuration": { - "Monitor Configuration": "Bildskärmskonfiguration" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "Fördröjning för bildskärmstonande" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Bildskärm vars bakgrundsbild styr dynamiska temafärger" - }, - "Monochrome": { - "Monochrome": "Monokrom" - }, - "Monocle": { - "Monocle": "Helskärm" - }, - "Monospace Font": { - "Monospace Font": "Monospaceteckensnitt" - }, - "Month Date": { - "Month Date": "Månad Datum" - }, - "Morning": { - "Morning": "Förmiddag" - }, - "Mount Points": { - "Mount Points": "Monteringspunkter" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "Muspekarens utseende" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "Muspekarens storlek i pixlar" - }, - "Move": { - "Move": "Flytta" - }, - "Move Widget": { - "Move Widget": "Flytta widget" - }, - "Moving to Paused": { - "Moving to Paused": "Pausar" - }, - "Multi-Monitor": { - "Multi-Monitor": "Flera bildskärmar" - }, - "Multiplexer": { - "Multiplexer": "Multiplexer" - }, - "Multiplexer Type": { - "Multiplexer Type": "Multiplexertyp" - }, - "Multiplexers": { - "Multiplexers": "Multiplexers" - }, - "Music": { - "Music": "Musik" - }, - "Mute Popups": { - "Mute Popups": "Tysta banderoller" - }, - "Mute popups for %1": { - "Mute popups for %1": "Tysta banderoller för %1" - }, - "Muted": { - "Muted": "Dämpad" - }, - "Muted Apps": { - "Muted Apps": "Tystade appar" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Dämpad palett med lugnande toner." - }, - "NM not supported": { - "NM not supported": "NM stöds inte" - }, - "Name": { - "Name": "Namn" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Ikoner för arbetsytor med namn" - }, - "Navigate": { - "Navigate": "Navigera" - }, - "Navigation": { - "Navigation": "Navigering" - }, - "Network": { - "Network": "Nätverk" - }, - "Network Graph": { - "Network Graph": "Nätverksgraf" - }, - "Network Info": { - "Network Info": "Nätverksinformation" - }, - "Network Information": { - "Network Information": "Nätverksinformation" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "Nätverksnamn (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Övervakning för nätverkshastighet" - }, - "Network Status": { - "Network Status": "Nätverksstatus" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Visa upp- och nedladdningshastighet" - }, - "Neutral": { - "Neutral": "Neutral" - }, - "Never": { - "Never": "Aldrig" - }, - "Never used": { - "Never used": "Aldrig använt" - }, - "New": { - "New": "Ny" - }, - "New Key": { - "New Key": "Ny tangent" - }, - "New Keybind": { - "New Keybind": "Nytt kortkommando" - }, - "New Notification": { - "New Notification": "Ny notis" - }, - "New Session": { - "New Session": "Ny session" - }, - "New Window Rule": { - "New Window Rule": "Ny fönsterregel" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "Nytt gruppnamn..." - }, - "Next": { - "Next": "Nästa" - }, - "Next Transition": { - "Next Transition": "Nästa övergång" - }, - "Night": { - "Night": "Natt" - }, - "Night Mode": { - "Night Mode": "Nattläge" - }, - "Night Temperature": { - "Night Temperature": "Natttemperatur" - }, - "Night mode & gamma": { - "Night mode & gamma": "Nattläge och gamma" - }, - "Niri Integration": { - "Niri Integration": "Niri-integration" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri-layoutöverstyrningar" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri-kompositorsåtgärder (fokus, flytta, o.s.v.)" - }, - "No": { - "No": "Nej" - }, - "No Active Players": { - "No Active Players": "Ingen aktiv mediespelare" - }, - "No Anim": { - "No Anim": "Ingen animering" - }, - "No Background": { - "No Background": "Ingen bakgrund" - }, - "No Battery": { - "No Battery": "Inget batteri" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Ingen Bluetooth-adapter hittades" - }, - "No Blur": { - "No Blur": "Ingen oskärpa" - }, - "No Border": { - "No Border": "Ingen ram" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "Inga DMS-kortkommandon konfigurerade" - }, - "No Dim": { - "No Dim": "Ingen dämpad" - }, - "No Focus": { - "No Focus": "Inget fokus" - }, - "No GPU detected": { - "No GPU detected": "Inget grafikkort hittades" - }, - "No GPUs detected": { - "No GPUs detected": "Inga grafikkort hittades" - }, - "No History": { - "No History": "Ingen historik" - }, - "No Media": { - "No Media": "Inga medier" - }, - "No Round": { - "No Round": "Ingen avrundning" - }, - "No Rounding": { - "No Rounding": "Ingen avrundning" - }, - "No Shadow": { - "No Shadow": "Ingen skugga" - }, - "No VPN profiles": { - "No VPN profiles": "Inga VPN-profiler" - }, - "No Weather": { - "No Weather": "Inget väder" - }, - "No Weather Data": { - "No Weather Data": "Ingen väderdata" - }, - "No Weather Data Available": { - "No Weather Data Available": "Väderinformation otillgänglig" - }, - "No action": { - "No action": "Ingen åtgärd" - }, - "No active %1 sessions": { - "No active %1 sessions": "Inga aktiva %1-sessioner" - }, - "No adapter": { - "No adapter": "Ingen adapter" - }, - "No adapters": { - "No adapters": "Inga adaptrar" - }, - "No app customizations.": { - "No app customizations.": "Inga appanpassningar." - }, - "No apps found": { - "No apps found": "Inga appar hittades" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "Inga appar har startats ännu." - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "Inga appar tystade. Högerklicka på en notis och välj \"Tysta banderoller\" för att lägga till en här." - }, - "No battery": { - "No battery": "Inget batteri" - }, - "No brightness devices available": { - "No brightness devices available": "Inga ljusstyrkeenheter tillgängliga" - }, - "No changes": { - "No changes": "Inga ändringar" - }, - "No checks passed": { - "No checks passed": "Inga kontroller godkända" - }, - "No custom theme file": { - "No custom theme file": "Ingen anpassad temafil" - }, - "No devices": { - "No devices": "Inga enheter" - }, - "No devices connected": { - "No devices connected": "Inga enheter anslutna" - }, - "No devices found": { - "No devices found": "Inga enheter hittades" - }, - "No disk data": { - "No disk data": "Ingen diskdata" - }, - "No disk data available": { - "No disk data available": "Ingen diskdata tillgänglig" - }, - "No drivers found": { - "No drivers found": "Inga drivrutiner hittades" - }, - "No errors": { - "No errors": "Inga fel" - }, - "No features enabled": { - "No features enabled": "Inga funktioner aktiverade" - }, - "No files found": { - "No files found": "Inga filer hittades" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "Ingen fingeravtrycksläsare hittades." - }, - "No folders found": { - "No folders found": "Inga mappar hittades" - }, - "No hidden apps.": { - "No hidden apps.": "Inga dolda appar." - }, - "No info items": { - "No info items": "Inga informationsobjekt" - }, - "No information available": { - "No information available": "Ingen information tillgänglig" - }, - "No input device": { - "No input device": "Ingen inmatningsenhet" - }, - "No input devices found": { - "No input devices found": "Inga inmatningsenheter hittades" - }, - "No items added yet": { - "No items added yet": "Inga objekt har lagts till än" - }, - "No keybinds found": { - "No keybinds found": "Inga kortkommandon hittades" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "Inga startartillägg installerade." - }, - "No match criteria": { - "No match criteria": "Inga matchkriterier" - }, - "No matches": { - "No matches": "Inga träffar" - }, - "No matching processes": { - "No matching processes": "Inga matchande processer" - }, - "No monitors": { - "No monitors": "Inga bildskärmar" - }, - "No mount points found": { - "No mount points found": "Inga monteringspunkter hittades" - }, - "No output device": { - "No output device": "Ingen utgångsenhet" - }, - "No output devices found": { - "No output devices found": "Inga utgångsenheter hittades" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "Ingen pakethanterare hittades. Installera 'paru' eller 'yay' på Arch-baserade system för att söka efter uppdateringar." - }, - "No plugin results": { - "No plugin results": "Inga tilläggsresultat" - }, - "No plugins found": { - "No plugins found": "Inga tillägg hittades" - }, - "No plugins found.": { - "No plugins found.": "Inga tillägg hittades." - }, - "No printer found": { - "No printer found": "Ingen skrivare hittades" - }, - "No printers configured": { - "No printers configured": "Inga skrivare konfigurerade" - }, - "No printers found": { - "No printers found": "Inga skrivare hittades" - }, - "No profiles": { - "No profiles": "Inga profiler" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "Inga nyliga urklippsposter hittades" - }, - "No results found": { - "No results found": "Inga resultat hittades" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "Inga sparade urklippsposter" - }, - "No sessions found": { - "No sessions found": "Inga sessioner hittades" - }, - "No status output.": { - "No status output.": "Ingen statusutdata." - }, - "No themes found": { - "No themes found": "Inga teman hittades" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Inga teman installerade. Bläddra bland teman för att installera från registret." - }, - "No trigger": { - "No trigger": "Ingen utlösare" - }, - "No video found in folder": { - "No video found in folder": "Ingen video hittades i mappen" - }, - "No wallpaper selected": { - "No wallpaper selected": "Ingen bakgrundsbild vald" - }, - "No wallpapers": { - "No wallpapers": "Inga bakgrundsbilder" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "Inga bakgrundsbilder hittades\n\nKlicka på mappikonen nedan för att bläddra" - }, - "No warnings": { - "No warnings": "Inga varningar" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "Inga widgetar tillagda. Klicka på \"Lägg till widget\" för att komma igång." - }, - "No widgets available": { - "No widgets available": "Inga widgetar tillgängliga" - }, - "No widgets match your search": { - "No widgets match your search": "Inga widgetar matchar din sökning" - }, - "No window rules configured": { - "No window rules configured": "Inga fönsterregler konfigurerade" - }, - "None": { - "None": "Ingen" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Normalt teckensnitt" - }, - "Normal Priority": { - "Normal Priority": "Normal prioritet" - }, - "Not available": { - "Not available": "Inte tillgängligt" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "Inte tillgängligt – installera fprintd och pam_fprintd, eller konfigurera greetd PAM." - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "Inte tillgängligt – installera fprintd och pam_fprintd." - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "Inte tillgängligt – installera eller konfigurera pam_u2f, eller konfigurera greetd PAM." - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "Inte tillgängligt – installera eller konfigurera pam_u2f." - }, - "Not connected": { - "Not connected": "Inte ansluten" - }, - "Not detected": { - "Not detected": "Inte detekterat" - }, - "Not paired": { - "Not paired": "Inte parkopplad" - }, - "Not set": { - "Not set": "Inte inställt" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Obs: detta ändrar bara procenttalet, det begränsar inte faktisk laddning." - }, - "Notepad": { - "Notepad": "Anteckningar" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Teckensnittsinställningar för Anteckningar" - }, - "Notepad Slideout": { - "Notepad Slideout": "Anteckningspanel" - }, - "Nothing": { - "Nothing": "Inget" - }, - "Nothing to see here": { - "Nothing to see here": "Inga äldre notiser" - }, - "Notification Center": { - "Notification Center": "Notiscenter" - }, - "Notification Display": { - "Notification Display": "Notisvisning" - }, - "Notification Overlay": { - "Notification Overlay": "Notisöverlägg" - }, - "Notification Popups": { - "Notification Popups": "Banderoller" - }, - "Notification Rules": { - "Notification Rules": "Notisregler" - }, - "Notification Settings": { - "Notification Settings": "Notisinställningar" - }, - "Notification Timeouts": { - "Notification Timeouts": "Tidsgräns för notiser" - }, - "Notification toast popups": { - "Notification toast popups": "Notisbanderoller" - }, - "Notifications": { - "Notifications": "Notiser" - }, - "Numbers": { - "Numbers": "Tal" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "Numeriskt (D/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "Numeriskt (M/D)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "OS-logo" - }, - "OSD Position": { - "OSD Position": "Position för skärmvisning" - }, - "Occupied Color": { - "Occupied Color": "Färg för aktiv arbetsyta" - }, - "Off": { - "Off": "Av" - }, - "Office": { - "Office": "Kontor" - }, - "Offline": { - "Offline": "Offline" - }, - "Offline Report": { - "Offline Report": "Offlinerapport" - }, - "Older": { - "Older": "Äldre" - }, - "On": { - "On": "På" - }, - "On-Demand": { - "On-Demand": "Vid behov" - }, - "On-Screen Displays": { - "On-Screen Displays": "Skärmvisningar" - }, - "On-screen Displays": { - "On-screen Displays": "Skärmvisningar" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Justera bara gamma baserat på tids- eller platsregler." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "Påverkar bara DMS-hanterad PAM. Om greetd redan inkluderar pam_fprintd förblir fingeravtrycksläsaren aktiverad." - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Visa bara fönster från den aktuella bildskärmen i varje dock" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Visas bara om viloläge stöds av ditt system" - }, - "Opacity": { - "Opacity": "Opacitet" - }, - "Opaque": { - "Opaque": "Ogenomskinlig" - }, - "Open": { - "Open": "Öppna" - }, - "Open App": { - "Open App": "Öppna app" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "Öppna KDE Connect på din telefon" - }, - "Open Notepad File": { - "Open Notepad File": "Öppna anteckning" - }, - "Open a new note": { - "Open a new note": "Öppna en ny anteckning" - }, - "Open folder": { - "Open folder": "Öppna mapp" - }, - "Open in Browser": { - "Open in Browser": "Öppna i webbläsare" - }, - "Open in terminal": { - "Open in terminal": "Öppna i terminal" - }, - "Open search bar to find text": { - "Open search bar to find text": "Öppna sökfältet för att hitta text" - }, - "Open with...": { - "Open with...": "Öppna med..." - }, - "Opening SMS": { - "Opening SMS": "Öppnar SMS" - }, - "Opening SMS app": { - "Opening SMS app": "Öppnar SMS-app" - }, - "Opening file browser": { - "Opening file browser": "Öppnar filbläddraren" - }, - "Opening files": { - "Opening files": "Öppnar filer" - }, - "Opening terminal: ": { - "Opening terminal: ": "Öppnar terminal: " - }, - "Optional description": { - "Optional description": "Valfri beskrivning" - }, - "Optional location": { - "Optional location": "Valfri plats" - }, - "Options": { - "Options": "Alternativ" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "Organisera widgetar i hopfällbara grupper" - }, - "Original: %1": { - "Original: %1": "Original: %1" - }, - "Other": { - "Other": "Övrigt" - }, - "Outline": { - "Outline": "Kontur" - }, - "Output": { - "Output": "Utgång" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Utmatningsfäcket nästan fullt" - }, - "Output Area Full": { - "Output Area Full": "Utmatningsfäcket fullt" - }, - "Output Device": { - "Output Device": "Utgångsenhet" - }, - "Output Devices": { - "Output Devices": "Utgångsenheter" - }, - "Output Tray Missing": { - "Output Tray Missing": "Utmatningsfäcket saknas" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Utgångsinkludering saknas" - }, - "Overcast": { - "Overcast": "Mulet" - }, - "Overflow": { - "Overflow": "Overflow" - }, - "Overridden by config": { - "Overridden by config": "Åsidosatt av konfiguration" - }, - "Override": { - "Override": "Åsidosätt" - }, - "Override Border Size": { - "Override Border Size": "Åsidosätt ramstorlek" - }, - "Override Corner Radius": { - "Override Corner Radius": "Åsidosätt hörnradie" - }, - "Override Gaps": { - "Override Gaps": "Åsidosätt mellanrum" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Åsidosätt globala layoutinställningar för denna utgång" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "Åsidosätt terminal med ett anpassat kommando eller skript" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "Åsidosätt den globala skuggan med menyradsspecifika inställningar" - }, - "Overrides": { - "Overrides": "Åsidosättningar" - }, - "Overview": { - "Overview": "Översikt" - }, - "Overview of your network connections": { - "Overview of your network connections": "Översikt över dina nätverksanslutningar" - }, - "Overwrite": { - "Overwrite": "Ersätt" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM tillhandahåller redan fingeravtrycksautentisering. Aktivera detta för att visa det vid inloggning." - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM tillhandahåller redan säkerhetsnyckelautentisering. Aktivera detta för att visa det vid inloggning." - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM tillhandahåller fingeravtrycksautentisering, men tillgängligheten kunde inte bekräftas." - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM tillhandahåller fingeravtrycksautentisering, men inga fingeravtryck har registrerats ännu." - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM tillhandahåller fingeravtrycksautentisering, men ingen läsare hittades." - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "Fyll ut" - }, - "Pad Hours": { - "Pad Hours": "Fyll ut timmar" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "Fyll ut timmar (02:00 vs 2:00)" - }, - "Padding": { - "Padding": "Utfyllnad" - }, - "Pair": { - "Pair": "Parkoppla" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Parkoppla Bluetooth-enhet" - }, - "Paired": { - "Paired": "Parkopplad" - }, - "Pairing": { - "Pairing": "Parkopplar" - }, - "Pairing failed": { - "Pairing failed": "Parkoppling misslyckades" - }, - "Pairing request from": { - "Pairing request from": "Parkopplingsförfrågan från" - }, - "Pairing request sent": { - "Pairing request sent": "Parkopplingsförfrågan skickad" - }, - "Pairing requested": { - "Pairing requested": "Parkoppling begärd" - }, - "Pairing...": { - "Pairing...": "Parkopplar..." - }, - "Partly Cloudy": { - "Partly Cloudy": "Delvis molnigt" - }, - "Passkey:": { - "Passkey:": "Lösenkod:" - }, - "Password": { - "Password": "Lösenord" - }, - "Password...": { - "Password...": "Lösenord..." - }, - "Paste": { - "Paste": "Klistra in" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "Sökväg till en videofil eller mapp med videor" - }, - "Pattern": { - "Pattern": "Mönster" - }, - "Pause": { - "Pause": "Pausa" - }, - "Paused": { - "Paused": "Pausad" - }, - "Pending": { - "Pending": "Väntande" - }, - "Pending Charge": { - "Pending Charge": "Laddning väntar" - }, - "Pending Discharge": { - "Pending Discharge": "Urladdning väntar" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Bakgrundsbild i ljust och mörkt läge" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Bakgrundsbild på flera bildskärmar" - }, - "Per-screen config": { - "Per-screen config": "Konfiguration per skärm" - }, - "Percentage": { - "Percentage": "Procent" - }, - "Performance": { - "Performance": "Prestanda" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Behörighet saknas för att ändra profilbild." - }, - "Personalization": { - "Personalization": "Anpassning" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "Phone Connect är inte tillgängligt" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "Phone Connect är inte tillgängligt" - }, - "Phone number": { - "Phone number": "Telefonnummer" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "Välj en annan slumpmässig video varje gång från samma mapp" - }, - "Pictures": { - "Pictures": "Bilder" - }, - "Pin": { - "Pin": "Nål" - }, - "Pin to Dock": { - "Pin to Dock": "Fäst på Dock" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping skickat" - }, - "Ping sent to": { - "Ping sent to": "Ping skickat till" - }, - "Pinned": { - "Pinned": "Fäst" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "Fästa och aktiva appar med dra-och-släpp" - }, - "Pixelate": { - "Pixelate": "Pixelera" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Lägg till tilläggsmappar här. Varje tillägg ska ha en plugin.json manifestfil." - }, - "Place plugins in %1": { - "Place plugins in %1": "Placera tillägg i %1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "Spela upp en video när skärmen låses." - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Spela upp ljud när en ny notis anländer" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Spela upp ljud när strömkabeln ansluts" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Spela upp ljud när volymen justeras" - }, - "Play sounds for system events": { - "Play sounds for system events": "Spela upp ljud för systemhändelser" - }, - "Playback": { - "Playback": "Uppspelning" - }, - "Playback error: ": { - "Playback error: ": "Uppspelningsfel: " - }, - "Please wait...": { - "Please wait...": "Vänta..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "Ange ett namn för din nya %1-session" - }, - "Plugged In": { - "Plugged In": "Inkopplad" - }, - "Plugged in": { - "Plugged in": "Inkopplad" - }, - "Plugin": { - "Plugin": "Tillägg" - }, - "Plugin Directory": { - "Plugin Directory": "Tilläggsmapp" - }, - "Plugin Management": { - "Plugin Management": "Tilläggshantering" - }, - "Plugin Visibility": { - "Plugin Visibility": "Tilläggssynlighet" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Det här tillägget är avaktiverat - aktivera det i Tilläggsinställningar för att använda" - }, - "Plugins": { - "Plugins": "Tillägg" - }, - "Pointer": { - "Pointer": "Pekare" - }, - "Popout Shadows": { - "Popout Shadows": "Popupfönsterskuggor" - }, - "Popouts": { - "Popouts": "Popupfönster" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "Popupfönster och dialogrutor följer global animeringshastighet (avaktivera för att anpassa individuellt)" - }, - "Popup Only": { - "Popup Only": "Bara banderoll" - }, - "Popup Position": { - "Popup Position": "Position på notisbanderoller" - }, - "Popup Shadow": { - "Popup Shadow": "Banderollskugga" - }, - "Popup Transparency": { - "Popup Transparency": "Genomskinlighet på notisbanderoller" - }, - "Popup behavior, position": { - "Popup behavior, position": "Popupbeteende, position" - }, - "Port": { - "Port": "Port" - }, - "Portal": { - "Portal": "Portal" - }, - "Position": { - "Position": "Position" - }, - "Position, pinned apps": { - "Position, pinned apps": "Position, fästa appar" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Möjliga åsidosättningskonflikter" - }, - "Power": { - "Power": "Ström" - }, - "Power & Security": { - "Power & Security": "Ström och säkerhet" - }, - "Power & Sleep": { - "Power & Sleep": "Ström och Vila" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Bekräftelse av strömåtgärd" - }, - "Power Menu Customization": { - "Power Menu Customization": "Anpassning av strömmenyn" - }, - "Power Off": { - "Power Off": "Stäng av" - }, - "Power Options": { - "Power Options": "Inställningar för ström" - }, - "Power Profile": { - "Power Profile": "Energiprofil" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Nedgradering av energiläge" - }, - "Power Saver": { - "Power Saver": "Energisparläge" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "Stäng av bildskärmar vid låsning" - }, - "Power profile management available": { - "Power profile management available": "Energiprofilhantering tillgänglig" - }, - "Power source": { - "Power source": "Strömkälla" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "Förifyll det senast lyckade användarnamnet på välkomstskärmen" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "Förmarkera den senast använda sessionen på välkomstskärmen" - }, - "Precip": { - "Precip": "Nbd." - }, - "Precipitation": { - "Precipitation": "Nederbörd" - }, - "Precipitation Chance": { - "Precipitation Chance": "Nederbördssannolikhet" - }, - "Preference": { - "Preference": "Preferens" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Förinställda bredder (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "Tryck på 'n' eller klicka på 'Ny session' för att skapa en" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "Tryck på Retur så startar ljudsystemet om för att tillämpa ändringen" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "Tryck Retur för att klistra in, Skift+Retur för att kopiera" - }, - "Press key...": { - "Press key...": "Tryck på tangent..." - }, - "Pressure": { - "Pressure": "Lufttryck" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Förhindra att skärmen stängs av" - }, - "Preview": { - "Preview": "Förhandsgranskning" - }, - "Primary": { - "Primary": "Primär" - }, - "Primary Container": { - "Primary Container": "Primär behållare" - }, - "Print Server Management": { - "Print Server Management": "Skrivarserverhantering" - }, - "Print Server not available": { - "Print Server not available": "Skrivarservern är inte tillgänglig" - }, - "Printer": { - "Printer": "Skrivare" - }, - "Printer Classes": { - "Printer Classes": "Skrivarklasser" - }, - "Printer created successfully": { - "Printer created successfully": "Skrivaren skapades" - }, - "Printer deleted": { - "Printer deleted": "Skrivaren raderades" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Skrivarnamn (inga blanksteg)" - }, - "Printer reachable": { - "Printer reachable": "Skrivare nåbar" - }, - "Printers": { - "Printers": "Skrivare" - }, - "Printers: ": { - "Printers: ": "Skrivare: " - }, - "Prioritize performance": { - "Prioritize performance": "Prioritera prestanda" - }, - "Priority": { - "Priority": "Prioritet" - }, - "Privacy Indicator": { - "Privacy Indicator": "Integritetsavisering" - }, - "Privacy Mode": { - "Privacy Mode": "Integritetsläge" - }, - "Private Key Password": { - "Private Key Password": "Lösenord för privat nyckel" - }, - "Process Count": { - "Process Count": "Antal processer" - }, - "Processes": { - "Processes": "Processer" - }, - "Processes:": { - "Processes:": "Processer:" - }, - "Processing": { - "Processing": "Bearbetar" - }, - "Profile Image Error": { - "Profile Image Error": "Fel på profilbild" - }, - "Profile activated: %1": { - "Profile activated: %1": "Profil aktiverad: %1" - }, - "Profile deleted": { - "Profile deleted": "Profil raderad" - }, - "Profile error": { - "Profile error": "Profilfel" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Profilbilden är för stor. Använd en mindre bild." - }, - "Profile name": { - "Profile name": "Profilnamn" - }, - "Profile not found": { - "Profile not found": "Profil hittades inte" - }, - "Profile saved: %1": { - "Profile saved: %1": "Profil sparad: %1" - }, - "Protocol": { - "Protocol": "Protokoll" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia är inte tillgängligt" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia är inte tillgängligt – videoskärmsläckaren kräver qt multimediatjänster" - }, - "Quick Access": { - "Quick Access": "Snabbåtkomst" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Snabb åtkomst till appstartare" - }, - "Quick access to color picker": { - "Quick access to color picker": "Snabb åtkomst till färgverktyg" - }, - "Quick access to notepad": { - "Quick access to notepad": "Snabb åtkomst till Anteckningar" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Snabb anteckningspanel som glider ut" - }, - "Quick system toggles": { - "Quick system toggles": "Snabba systemväxlar" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "Radie" - }, - "Rain": { - "Rain": "Regn" - }, - "Rain Chance": { - "Rain Chance": "Sannolikhet för nederbörd" - }, - "Rainbow": { - "Rainbow": "Regnbåge" - }, - "Random": { - "Random": "Slumpmässig" - }, - "Rate": { - "Rate": "Hastighet" - }, - "Read:": { - "Read:": "Läst:" - }, - "Reason": { - "Reason": "Orsak" - }, - "Reboot": { - "Reboot": "Starta om" - }, - "Recent Colors": { - "Recent Colors": "Nyligen använda färger" - }, - "Recently Used Apps": { - "Recently Used Apps": "Nyligen använda appar" - }, - "Recommended available": { - "Recommended available": "Rekommenderad tillgänglig" - }, - "Refresh": { - "Refresh": "Uppdatera" - }, - "Refresh Weather": { - "Refresh Weather": "Uppdatera väder" - }, - "Regex": { - "Regex": "Regex" - }, - "Reject": { - "Reject": "Avvisa" - }, - "Reject Jobs": { - "Reject Jobs": "Avvisa jobb" - }, - "Release": { - "Release": "Släpp" - }, - "Reload Plugin": { - "Reload Plugin": "Ladda om tillägg" - }, - "Remaining": { - "Remaining": "Återstående" - }, - "Remaining / Total": { - "Remaining / Total": "Återstående / Totalt" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "Kom ihåg senaste session" - }, - "Remember last user": { - "Remember last user": "Kom ihåg senaste användare" - }, - "Remove": { - "Remove": "Ta bort" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "Ta bort widgetutfyllnad" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Ta bort mellanrum och ram när fönster är maximerade" - }, - "Rename": { - "Rename": "Byt namn" - }, - "Rename Session": { - "Rename Session": "Byt namn på session" - }, - "Rename Workspace": { - "Rename Workspace": "Byt namn på arbetsyta" - }, - "Repeat": { - "Repeat": "Upprepa" - }, - "Replacement": { - "Replacement": "Ersättning" - }, - "Report": { - "Report": "Rapport" - }, - "Request Pairing": { - "Request Pairing": "Begär parkoppling" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Kräv att knapp/tangent hålls inne för att bekräfta stäng av, starta om, strömsparläge, viloläge och utloggning" - }, - "Required plugin: ": { - "Required plugin: ": "Obligatoriskt tillägg: " - }, - "Requires %1": { - "Requires %1": "Kräver %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "Kräver verktyget 'dgop'" - }, - "Requires DMS %1": { - "Requires DMS %1": "Kräver DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "Kräver DWL-kompositor" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Kräver stöd för nattläge" - }, - "Reset": { - "Reset": "Återställ" - }, - "Reset Position": { - "Reset Position": "Återställ position" - }, - "Reset Size": { - "Reset Size": "Återställ storlek" - }, - "Reset to default name": { - "Reset to default name": "Återställ till standardnamn" - }, - "Resize Widget": { - "Resize Widget": "Ändra storlek på widget" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Upplösning och uppdateringsfrekvens" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "Upplösning, position, skala" - }, - "Restart DMS": { - "Restart DMS": "Starta om DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "Starta om DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "Startar om ljudsystemet..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "Återställ fönster från specialarbetsyta" - }, - "Resume": { - "Resume": "Återuppta" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Omvänd rullningsriktning" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Omvänd växlingsriktning på arbetsytor vid rullning över menyraden" - }, - "Revert": { - "Revert": "Återställ" - }, - "Right": { - "Right": "Höger" - }, - "Right Center": { - "Right Center": "Höger mitten" - }, - "Right Section": { - "Right Section": "Höger avdelning" - }, - "Right Tiling": { - "Right Tiling": "Kakla till höger" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Högerklicka och dra var som helst på widgeten" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Högerklicka och dra i det nedre högra hörnet" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Högerklicka på menyradswidget för att växla" - }, - "Ring": { - "Ring": "Ring" - }, - "Ringing": { - "Ringing": "Ringer" - }, - "Ripple Effects": { - "Ripple Effects": "Rippeleffekter" - }, - "Root Filesystem": { - "Root Filesystem": "Rotfilsystem" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Rundade hörn för fönster" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "Rundade hörn för fönster (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "Rundade hörn för fönster (decoration.rounding)" - }, - "Rule": { - "Rule": "Regel" - }, - "Rule Name": { - "Rule Name": "Regelnamn" - }, - "Rules (%1)": { - "Rules (%1)": "Regler (%1)" - }, - "Run Again": { - "Run Again": "Kör igen" - }, - "Run DMS Templates": { - "Run DMS Templates": "Kör DMS-mallar" - }, - "Run User Templates": { - "Run User Templates": "Kör användarmallar" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Kör ett program (t.ex. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Kör ett shellkommando (t.ex. notify-send)" - }, - "Running Apps": { - "Running Apps": "Aktiva appar" - }, - "Running Apps Settings": { - "Running Apps Settings": "Inställningar för aktiva appar" - }, - "Running greeter sync…": { - "Running greeter sync…": "Kör välkomstskärmssynkronisering…" - }, - "SDR Brightness": { - "SDR Brightness": "SDR-ljusstyrka" - }, - "SDR Saturation": { - "SDR Saturation": "SDR-mättnad" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "Spara" - }, - "Save Notepad File": { - "Save Notepad File": "Spara anteckning" - }, - "Save QR Code": { - "Save QR Code": "Spara QR-kod" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "Spara och växla mellan bildskärmskonfigurationer" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "Spara notiser med kritisk prioritet i historiken" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "Spara avvisade notiser i historiken" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "Spara notiser med låg prioritet i historiken" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "Spara notiser med normal prioritet i historiken" - }, - "Save password": { - "Save password": "Spara lösenord" - }, - "Saved": { - "Saved": "Sparat" - }, - "Saved Configurations": { - "Saved Configurations": "Sparade konfigurationer" - }, - "Saved Note": { - "Saved Note": "Sparad anteckning" - }, - "Saved item deleted": { - "Saved item deleted": "Sparat objekt raderat" - }, - "Saving...": { - "Saving...": "Sparar..." - }, - "Scale": { - "Scale": "Skala" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "Skala teckensnitt på DankBar oberoende av systeminställningarna" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "Skala DankBars ikonstorlekar oberoende av systeminställningarna" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Skala alla teckenstorlekar i shell" - }, - "Scan": { - "Scan": "Skanna" - }, - "Scanning": { - "Scanning": "Söker" - }, - "Scanning...": { - "Scanning...": "Söker..." - }, - "Science": { - "Science": "Vetenskap" - }, - "Score": { - "Score": "Poäng" - }, - "Screen Sharing": { - "Screen Sharing": "Skärmdelning" - }, - "Screen sharing": { - "Screen sharing": "Skärmdelning" - }, - "Scroll": { - "Scroll": "Rulla" - }, - "Scroll Factor": { - "Scroll Factor": "Rullningsfaktor" - }, - "Scroll GitHub": { - "Scroll GitHub": "Scroll GitHub" - }, - "Scroll Wheel": { - "Scroll Wheel": "Scrollhjul" - }, - "Scroll song title": { - "Scroll song title": "Rulla låttitel" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Rulla titeln om den inte ryms i widgeten" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "Scrollhjulsbeteende på mediawidget" - }, - "Scrolling": { - "Scrolling": "Rullning" - }, - "Search App Actions": { - "Search App Actions": "Sök appåtgärder" - }, - "Search Options": { - "Search Options": "Sökalternativ" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "Sök efter tangentkombination, beskrivning eller åtgärdsnamn.\n\nStandardåtgärden kopierar kortkommandot till urklipp.\nHögerklicka eller tryck på högerpil för att fästa kortkommandon – de visas överst när du inte söker." - }, - "Search for a location...": { - "Search for a location...": "Sök efter en plats..." - }, - "Search keybinds...": { - "Search keybinds...": "Sök kortkommandon..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "Sök kortkommandon från din kompositor och dina program" - }, - "Search plugins...": { - "Search plugins...": "Sök tillägg..." - }, - "Search processes...": { - "Search processes...": "Sök processer..." - }, - "Search sessions...": { - "Search sessions...": "Sök sessioner..." - }, - "Search themes...": { - "Search themes...": "Sök teman..." - }, - "Search widgets...": { - "Search widgets...": "Sök widgetar..." - }, - "Search...": { - "Search...": "Sök..." - }, - "Searching...": { - "Searching...": "Söker..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "Andra faktor (OCH)" - }, - "Secondary": { - "Secondary": "Sekundär" - }, - "Secured": { - "Secured": "Lösenordsskyddad" - }, - "Security": { - "Security": "Säkerhet" - }, - "Security & privacy": { - "Security & privacy": "Säkerhet och integritet" - }, - "Security key mode": { - "Security key mode": "Säkerhetsnyckelläge" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "Säkerhetsnyckelns tillgänglighet kunde inte bekräftas." - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "Stöd för säkerhetsnyckel hittades, men ingen registrerad nyckel hittades ännu. Du kan aktivera detta nu och registrera en senare." - }, - "Select": { - "Select": "Välj" - }, - "Select Application": { - "Select Application": "Välj program" - }, - "Select Bar": { - "Select Bar": "Välj menyrad" - }, - "Select Custom Theme": { - "Select Custom Theme": "Välj anpassat tema" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "Välj dockens startarikon" - }, - "Select File to Send": { - "Select File to Send": "Välj fil att skicka" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Välj appstartarens ikon" - }, - "Select Profile Image": { - "Select Profile Image": "Välj profilbild" - }, - "Select Video or Folder": { - "Select Video or Folder": "Välj video eller mapp" - }, - "Select Wallpaper": { - "Select Wallpaper": "Välj bakgrundsbild" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Välj bakgrundsbildsmapp" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Välj en standardfärg från färgpaletten eller välj din egen" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Välj en widget att lägga till på skrivbordet. Varje widget är en separat instans med egna inställningar." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Välj en widget att lägga till. Du kan lägga till flera instanser av samma widget om det behövs." - }, - "Select a window...": { - "Select a window...": "Välj ett fönster..." - }, - "Select an image file...": { - "Select an image file...": "Välj en bild..." - }, - "Select at least one provider": { - "Select at least one provider": "Välj minst en leverantör" - }, - "Select device": { - "Select device": "Välj enhet" - }, - "Select device...": { - "Select device...": "Välj enhet..." - }, - "Select driver...": { - "Select driver...": "Välj drivrutin..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Välj teckenstorlek för gränssnittstext" - }, - "Select greeter background image": { - "Select greeter background image": "Välj bakgrundsbild för välkomstskärmen" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Ställ in bakgrundsbild på den här bildskärmen" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Välj monospaceteckensnitt för processlistan och övriga tekniska funktioner" - }, - "Select network": { - "Select network": "Välj nätverk" - }, - "Select system sound theme": { - "Select system sound theme": "Välj systemljudtema" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Välj teckensnitts­familj för gränssnittstext" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Välj palettalgoritm för färger baserade på bakgrundsbilden" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "Välj vilka kortkommandoleverantörer som ska inkluderas" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Välj övergångar som visas slumpmässigt" - }, - "Select...": { - "Select...": "Välj..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Den valda bildfilen hittades inte." - }, - "Send": { - "Send": "Skicka" - }, - "Send Clipboard": { - "Send Clipboard": "Skicka urklipp" - }, - "Send File": { - "Send File": "Skicka fil" - }, - "Send SMS": { - "Send SMS": "Skicka SMS" - }, - "Sending": { - "Sending": "Skickar" - }, - "Separator": { - "Separator": "Avskiljare" - }, - "Server": { - "Server": "Server" - }, - "Session Filter": { - "Session Filter": "Sessionsfilter" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "Ange anpassat enhetsnamn" - }, - "Set custom name": { - "Set custom name": "Ange anpassat namn" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "Ange anpassade namn för dina ljudingångsenheter" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "Ange anpassade namn för dina ljudutgångsenheter" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Ställ in olika bakgrundsbilder på varje ansluten bildskärm" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Ställ in olika bakgrundsbilder i ljust och mörkt läge" - }, - "Set key and action to save": { - "Set key and action to save": "Ange tangent och åtgärd för att spara" - }, - "Set notification rules": { - "Set notification rules": "Ange notisregler" - }, - "Settings": { - "Settings": "Inställningar" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "Inställningarna är skrivskyddade. Ändringar sparas inte." - }, - "Setup": { - "Setup": "Konfiguration" - }, - "Shadow Color": { - "Shadow Color": "Skuggfärg" - }, - "Shadow Intensity": { - "Shadow Intensity": "Skuggintensitet" - }, - "Shadow Opacity": { - "Shadow Opacity": "Skuggopacitet" - }, - "Shadow Override": { - "Shadow Override": "Skuggöverstyrning" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "Skuggupphöjning på barer och paneler" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "Skuggupphöjning på dialogrutor och dialoger" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "Skuggupphöjning på popupfönster, skärmvisningar och rullgardinsmenyer" - }, - "Shadows": { - "Shadows": "Skuggor" - }, - "Share": { - "Share": "Dela" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "Dela gammakontrollinställningar" - }, - "Share Text": { - "Share Text": "Dela text" - }, - "Share URL": { - "Share URL": "Dela URL" - }, - "Shared": { - "Shared": "Delat" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Skift+Del: Rensa allt • Esc: Stäng" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Skift+Retur för att klistra in" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Skift+Retur: Kopiera • Skift+Del: Rensa allt • Esc: Stäng" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Skift+Retur: Klistra in • Skift+Del: Rensa allt • Esc: Stäng" - }, - "Short": { - "Short": "Kort" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "Kortkommando (%1)" - }, - "Shortcuts": { - "Shortcuts": "Genvägar" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Kortkommandon (%1)" - }, - "Show": { - "Show": "Visa" - }, - "Show 3rd Party": { - "Show 3rd Party": "Visa tredjepartsappar" - }, - "Show All Tags": { - "Show All Tags": "Visa alla taggar" - }, - "Show Badge": { - "Show Badge": "Visa märke" - }, - "Show CPU": { - "Show CPU": "Visa CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "Visa CPU-graf" - }, - "Show CPU Temp": { - "Show CPU Temp": "Visa CPU-temperatur" - }, - "Show Date": { - "Show Date": "Visa datum" - }, - "Show Disk": { - "Show Disk": "Visa disk" - }, - "Show Dock": { - "Show Dock": "Visa Dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "Visa känns som-temperatur" - }, - "Show Footer": { - "Show Footer": "Visa sidfot" - }, - "Show Forecast": { - "Show Forecast": "Visa prognos" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "Visa grafikkortstemperatur" - }, - "Show Header": { - "Show Header": "Visa rubrik" - }, - "Show Hibernate": { - "Show Hibernate": "Visa viloläge" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Visa timvisare" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "Visa timvis prognos" - }, - "Show Humidity": { - "Show Humidity": "Visa luftfuktighet" - }, - "Show Launcher Button": { - "Show Launcher Button": "Visa startarknapp" - }, - "Show Line Numbers": { - "Show Line Numbers": "Visa radnummer" - }, - "Show Location": { - "Show Location": "Visa plats" - }, - "Show Lock": { - "Show Lock": "Visa lås" - }, - "Show Log Out": { - "Show Log Out": "Visa utloggning" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "Visa Material Design-rippelanimationer på interaktiva element" - }, - "Show Media Player": { - "Show Media Player": "Visa mediespelaren" - }, - "Show Memory": { - "Show Memory": "Visa minne" - }, - "Show Memory Graph": { - "Show Memory Graph": "Visa minnesgraf" - }, - "Show Memory in GB": { - "Show Memory in GB": "Visa minne i GB" - }, - "Show Network": { - "Show Network": "Visa nätverk" - }, - "Show Network Graph": { - "Show Network Graph": "Visa nätverksgraf" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Visa bara aktiva arbetsytor" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "Visa overflow-märkesantal" - }, - "Show Password Field": { - "Show Password Field": "Visa lösenordsfält" - }, - "Show Power Actions": { - "Show Power Actions": "Visa strömåtgärder" - }, - "Show Power Off": { - "Show Power Off": "Visa stäng av" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "Visa nederbördssannolikhet" - }, - "Show Pressure": { - "Show Pressure": "Visa lufttryck" - }, - "Show Profile Image": { - "Show Profile Image": "Visa profilbild" - }, - "Show Reboot": { - "Show Reboot": "Visa omstart" - }, - "Show Restart DMS": { - "Show Restart DMS": "Visa DMS-omstart" - }, - "Show Saved Items": { - "Show Saved Items": "Visa sparade objekt" - }, - "Show Seconds": { - "Show Seconds": "Visa sekunder" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "Visa soluppgång/solnedgång" - }, - "Show Suspend": { - "Show Suspend": "Visa strömsparläge" - }, - "Show Swap": { - "Show Swap": "Visa växlingsutrymme" - }, - "Show System Date": { - "Show System Date": "Visa systemdatum" - }, - "Show System Icons": { - "Show System Icons": "Visa systemikoner" - }, - "Show System Time": { - "Show System Time": "Visa systemtid" - }, - "Show Top Processes": { - "Show Top Processes": "Visa toppprocesser" - }, - "Show Weather Condition": { - "Show Weather Condition": "Visa väderförhållanden" - }, - "Show Week Number": { - "Show Week Number": "Visa veckonummer" - }, - "Show Welcome": { - "Show Welcome": "Visa välkomstskärm" - }, - "Show Wind Speed": { - "Show Wind Speed": "Visa vindhastighet" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Visa appar i en arbetsyta" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Visa alla 9 taggar istället för bara aktiva taggar (endast DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "Visa en konturring runt den fokuserade arbetsytans indikator" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Visa cava-ljudvisualiserare i mediawidget" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Visa mörklagt överlägg bakom modala dialogrutor" - }, - "Show device": { - "Show device": "Visa enhet" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "Visa docken när flytande fönster inte överlappar dess område" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "Visa droppskugga på notisbanderoller. Kräver att M3-upphöjning är aktiverat i Teman och färger." - }, - "Show in GB": { - "Show in GB": "Visa i GB" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Visa startarens överlägg när du skriver i Niri-översikten. Avaktivera för att använda en annan startare." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "Visa lägesflikar och tangentbordstips längst ned." - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "Visa notisbanderoller bara på den aktuellt fokuserade bildskärmen" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "Visa notiser bara på den aktuellt fokuserade bildskärmen" - }, - "Show on Last Display": { - "Show on Last Display": "Visa på sista bildskärm" - }, - "Show on Overlay": { - "Show on Overlay": "Visa på överlägg" - }, - "Show on Overview": { - "Show on Overview": "Visa på Översikt" - }, - "Show on Overview Only": { - "Show on Overview Only": "Visa bara i översikt" - }, - "Show on all connected displays": { - "Show on all connected displays": "Visa på alla anslutna bildskärmar" - }, - "Show on screens:": { - "Show on screens:": "Visa på bildskärm:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Visa skärmvisning när ljusstyrkan ändras" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Visa skärmvisning när Caps Lock-status ändras" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Visa skärmvisning när ljudutgångsenheter växlas" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Visa skärmvisning när inaktivitetsstatus ändras" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "Visa skärmvisning när mediaspecelarens status ändras" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Visa skärmvisning när mediaspelaren ändrar volym" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Visa skärmvisning när mikrofonen tystas/aktiveras" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Visa skärmvisning när energiprofilen ändras" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Visa skärmvisning när volymen ändras" - }, - "Show seconds": { - "Show seconds": "Visa sekunder" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Visa väderinformation i menyraden och kontrollcentret" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "Visa veckonummer i kalendern" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Visa indexnummer på arbetsytan på växlaren i menyraden" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "Visa arbetsytans namn på horisontella barer, och första bokstaven på vertikala barer" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "Visa arbetsytor på den aktuellt fokuserade bildskärmen" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Visa aktiva appar och indikera appen i fokus" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Visa aktiv arbetsyta och växla arbetsytor" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Visar när Caps Lock är aktiverat" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Visa när mikrofon, kamera, eller skärmdelning är aktiv" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Stäng av" - }, - "Signal": { - "Signal": "Signal" - }, - "Signal:": { - "Signal:": "Signal:" - }, - "Size": { - "Size": "Storlek" - }, - "Size Constraints": { - "Size Constraints": "Storleksbegränsningar" - }, - "Size Offset": { - "Size Offset": "Storleksförskjutning" - }, - "Sizing": { - "Sizing": "Storlek" - }, - "Skip": { - "Skip": "Hoppa över" - }, - "Skip confirmation": { - "Skip confirmation": "Hoppa över bekräftelse" - }, - "Skip setup": { - "Skip setup": "Hoppa över konfiguration" - }, - "Small": { - "Small": "Liten" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "Smartkortsautentisering" - }, - "Smartcard PIN": { - "Smartcard PIN": "Smartkorts-PIN" - }, - "Snap": { - "Snap": "Knäppa" - }, - "Snow": { - "Snow": "Snö" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Några tillägg kräver en nyare version av DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Sortera alfabetiskt" - }, - "Sort By": { - "Sort By": "Sortera efter" - }, - "Sorting & Layout": { - "Sorting & Layout": "Sortering & layout" - }, - "Sound Theme": { - "Sound Theme": "Ljudtema" - }, - "Sounds": { - "Sounds": "Ljud" - }, - "Space between windows": { - "Space between windows": "Mellanrum mellan fönster" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "Mellanrum mellan fönster (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "Mellanrum mellan fönster (gaps_in och gaps_out)" - }, - "Spacer": { - "Spacer": "Mellanrum" - }, - "Spacing": { - "Spacing": "Mellanrum" - }, - "Speaker settings": { - "Speaker settings": "Högtalarinställningar" - }, - "Speed": { - "Speed": "Hastighet" - }, - "Spool Area Full": { - "Spool Area Full": "Utskriftskön full" - }, - "Square Corners": { - "Square Corners": "Fyrkantiga kanter" - }, - "Stacked": { - "Stacked": "Staplade" - }, - "Standard": { - "Standard": "Standard" - }, - "Start": { - "Start": "Start" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "Starta KDE Connect eller Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "Starta KDE Connect eller Valent för att använda detta tillägg" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Skriv dina anteckningar här..." - }, - "State": { - "State": "Tillstånd" - }, - "Status": { - "Status": "Status" - }, - "Stopped": { - "Stopped": "Stoppad" - }, - "Stopped Partly": { - "Stopped Partly": "Delvis stoppad" - }, - "Stopping": { - "Stopping": "Stoppar" - }, - "Stretch": { - "Stretch": "Sträck ut" - }, - "Stripes": { - "Stripes": "Ränder" - }, - "Summary": { - "Summary": "Sammanfattning" - }, - "Sunrise": { - "Sunrise": "Soluppgång" - }, - "Sunset": { - "Sunset": "Solnedgång" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Undertryck notisbanderoller när aktiverat" - }, - "Surface": { - "Surface": "Yta" - }, - "Surface Variant": { - "Surface Variant": "Ytvariant" - }, - "Suspend": { - "Suspend": "Strömsparläge" - }, - "Suspend behavior": { - "Suspend behavior": "Strömsparlägestägning" - }, - "Suspend system after": { - "Suspend system after": "Ställ systemet i strömsparläge efter" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "Sätt i strömsparläge och sedan viloläge" - }, - "Sway Website": { - "Sway Website": "Sways webbplats" - }, - "Switch User": { - "Switch User": "Byt användare" - }, - "Switch to power profile": { - "Switch to power profile": "Byt till energiprofil" - }, - "Sync": { - "Sync": "Synka" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Synkronisera läge med portal" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "Synkronisera popupfönster och dialogrutor" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "Synkronisera position mellan skärmar" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "Synkronisering klar." - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Synkronisera mörkt läge med inställningsportalar för systemomfattande tematips" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "Synkronisering misslyckades i bakgrundsläge. Försöker med terminalläge för interaktiv autentisering." - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "Synkronisering kräver sudo-autentisering. Öppnar terminal för lösenord eller fingeravtryck." - }, - "System": { - "System": "System" - }, - "System App Theming": { - "System App Theming": "Systemapptema" - }, - "System Check": { - "System Check": "Systemkontroll" - }, - "System Default": { - "System Default": "Systemstandard" - }, - "System Information": { - "System Information": "Systeminformation" - }, - "System Monitor": { - "System Monitor": "Systemövervakning" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Systemövervakning otillgänglig" - }, - "System Sounds": { - "System Sounds": "Systemljud" - }, - "System Tray": { - "System Tray": "Statusmeny" - }, - "System Update": { - "System Update": "Systemuppdatering" - }, - "System Updater": { - "System Updater": "Systemuppdaterare" - }, - "System Updates": { - "System Updates": "Systemuppdateringar" - }, - "System notification area icons": { - "System notification area icons": "Visa ikon för systemnotiser" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "Systemljud är inte tillgängliga. Installera %1 för ljudstöd." - }, - "System theme toggle": { - "System theme toggle": "Växla systemtema" - }, - "System toast notifications": { - "System toast notifications": "Systemnotiser" - }, - "System update custom command": { - "System update custom command": "Anpassat kommando för systemuppdatering" - }, - "Tab": { - "Tab": "Flik" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Skift+Tab: Navigering • ←→↑↓: Rutnätsnavigering • Retur/Blanksteg: Välj" - }, - "Terminal": { - "Terminal": "Terminal" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Ytterligare parametrar för terminalen" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "Terminalåterfall misslyckades. Installera en av de stödda terminalemulatorerna eller kör 'dms greeter sync' manuellt." - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "Terminalåterfall öppnat. Slutför synkroniseringen där; det stängs automatiskt när det är klart." - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "Terminalmultiplexerbakgrundstjänst att använda" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "Terminal öppnad. Slutför synkroniseringsautentiseringen där; det stängs automatiskt när det är klart." - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminaler – Använd alltid mörkt tema" - }, - "Test Connection": { - "Test Connection": "Testa anslutning" - }, - "Test Page": { - "Test Page": "Testsida" - }, - "Test page sent to printer": { - "Test page sent to printer": "Testsida skickad till skrivaren" - }, - "Testing...": { - "Testing...": "Testar..." - }, - "Text": { - "Text": "Text" - }, - "Text Color": { - "Text Color": "Textfärg" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "Verktyget 'dgop' krävs för systemövervakning.\nInstallera dgop för att använda den här funktionen." - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "Miljövariabeln DMS_SOCKET har antingen inte ställts in eller socketen är otillgänglig. DMS_SOCKET krävs för att hantera tillägg automatiskt." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Inställningarna nedan kommer att modifiera dina GTK- och Qt-inställningar. Om du vill behålla dina konfigurationer, vänligen säkerhetskopiera (qt5ct.conf|qt6ct.conf och ~/.config/gtk-3.0|gtk-4.0)" - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "Det anpassade kommandot som används vid anslutning till sessioner (tar emot sessionsnamnet som första argument)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "Skrivarens jobbkö är tom" - }, - "Theme & Colors": { - "Theme & Colors": "Teman och färger" - }, - "Theme Color": { - "Theme Color": "Temafärg" - }, - "Theme Registry": { - "Theme Registry": "Temaregister" - }, - "Themes": { - "Themes": "Teman" - }, - "Thickness": { - "Thickness": "Tjocklek" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Varning för tredjepartstillägg" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "Tredjepartstillägg skapas av gemenskapen och har inte officiellt stöd av DankMaterialShell.\n\nDe här tilläggen kan utgöra en risk för din säkerhet och integritet – installera på egen risk." - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Denna bindning åsidosätts av config.kdl" - }, - "This may take a few seconds": { - "This may take a few seconds": "Detta kan ta några sekunder" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "Detta tillägg saknar behörigheten 'settings_write'.\n\nLägg till \"permissions\": [\"settings_read\", \"settings_write\"] i plugin.json" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Den här widgeten förhindrar att grafikkortet stängs av, vilket kan kraftigt minska batteritiden på bärbara datorer. Vi rekommenderar att inte använda den på bärbara datorer med både inbyggd och diskret grafik." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "Detta raderar alla ofästa poster. %1 fästa poster behålls." - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Urklippshistorik kommer att raderas permanent." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "Detta tar permanent bort det sparade urklippsobjektet. Åtgärden kan inte ångras." - }, - "Thunderstorm": { - "Thunderstorm": "Åskväder" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "Åskväder med hagel" - }, - "Tile": { - "Tile": "Kakla" - }, - "Tile H": { - "Tile H": "Kakla H" - }, - "Tile V": { - "Tile V": "Kakla V" - }, - "Tiled": { - "Tiled": "Kaklat" - }, - "Tiled State": { - "Tiled State": "Kaklat tillstånd" - }, - "Tiling": { - "Tiling": "Kakelläge" - }, - "Time": { - "Time": "Tid" - }, - "Time & Date Locale": { - "Time & Date Locale": "Språk för tid och datum" - }, - "Time & Weather": { - "Time & Weather": "Tid och väder" - }, - "Time Format": { - "Time Format": "Tidsformat" - }, - "Time format": { - "Time format": "Tidsformat" - }, - "Time remaining: %1": { - "Time remaining: %1": "Återstående tid: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Tid till fullt: %1" - }, - "Timed Out": { - "Timed Out": "Tidsgräns överskriden" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Tidsgräns för aviseringar med kritisk prioritet" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Tidsgräns för aviseringar med låg prioritet" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Tidsgräns för aviseringar med normal prioritet" - }, - "Title": { - "Title": "Titel" - }, - "Title regex (optional)": { - "Title regex (optional)": "Titelregex (valfritt)" - }, - "To Full": { - "To Full": "Till full" - }, - "To update, run the following command:": { - "To update, run the following command:": "Kör följande kommando för att uppdatera:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "För att använda denna DMS-kommando, ta bort eller ändra kortkommandot i din config.kdl" - }, - "Toast Messages": { - "Toast Messages": "Notisbanderoller" - }, - "Today": { - "Today": "Idag" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Växla synlighet för denna menyradskonfiguration" - }, - "Toggling...": { - "Toggling...": "Växlar..." - }, - "Tomorrow": { - "Tomorrow": "Imorgon" - }, - "Tonal Spot": { - "Tonal Spot": "Tonalpunkt" - }, - "Toner Empty": { - "Toner Empty": "Tonern är slut" - }, - "Toner Low": { - "Toner Low": "Låg tonernivå" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "För många misslyckade försök – kontot kan vara låst" - }, - "Tools": { - "Tools": "Verktyg" - }, - "Top": { - "Top": "Topp" - }, - "Top (Default)": { - "Top (Default)": "Topp (standard)" - }, - "Top Bar Format": { - "Top Bar Format": "Datumformat i menyrad" - }, - "Top Center": { - "Top Center": "Övre mitten" - }, - "Top Left": { - "Top Left": "Övre vänster" - }, - "Top Processes": { - "Top Processes": "Toppprocesser" - }, - "Top Right": { - "Top Right": "Övre höger" - }, - "Top Section": { - "Top Section": "Topp-avdelning" - }, - "Total": { - "Total": "Totalt" - }, - "Total Jobs": { - "Total Jobs": "Totalt antal jobb" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Transformera" - }, - "Transition Effect": { - "Transition Effect": "Övergångseffekt" - }, - "Transparency": { - "Transparency": "Genomskinlighet" - }, - "Trending GIFs": { - "Trending GIFs": "Trendande GIF:er" - }, - "Trending Stickers": { - "Trending Stickers": "Trendande klistermärken" - }, - "Trigger": { - "Trigger": "Utlösare" - }, - "Trigger Prefix": { - "Trigger Prefix": "Utlösarprefix" - }, - "Trigger: %1": { - "Trigger: %1": "Utlösare: %1" - }, - "Trust": { - "Trust": "Lita på" - }, - "Try a different search": { - "Try a different search": "Prova en annan sökning" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "Stäng av alla bildskärmar direkt när låsskärmen aktiveras" - }, - "Turn off monitors after": { - "Turn off monitors after": "Stäng av bildskärmar efter" - }, - "Type": { - "Type": "Typ" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "Skriv minst 2 tecken" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "Skriv detta prefix för att söka kortkommandon" - }, - "Type to search files": { - "Type to search files": "Skriv för att söka filer" - }, - "Typography": { - "Typography": "Typografi" - }, - "Typography & Motion": { - "Typography & Motion": "Typografi & rörelse" - }, - "Unavailable": { - "Unavailable": "Otillgänglig" - }, - "Unfocused Color": { - "Unfocused Color": "Ofokuserad färg" - }, - "Ungrouped": { - "Ungrouped": "Inte grupperad" - }, - "Uninstall": { - "Uninstall": "Avinstallera" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "Avinstallera välkomstskärm" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Avinstallera tillägg" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "Avinstallation klar. Välkomstskärmen har tagits bort." - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Avinstallation misslyckades: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "Avinstallera DMS-välkomstskärmen? Detta tar bort konfigurationen och återställer din tidigare displayhanterare. En terminal öppnas för sudo-autentisering." - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Avinstallerat: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Avinstallerar: %1" - }, - "Unknown": { - "Unknown": "Okänd" - }, - "Unknown App": { - "Unknown App": "Okänd app" - }, - "Unknown Artist": { - "Unknown Artist": "Okänd artist" - }, - "Unknown Config": { - "Unknown Config": "Okänd konfiguration" - }, - "Unknown Device": { - "Unknown Device": "Okänd enhet" - }, - "Unknown GPU": { - "Unknown GPU": "Okänt grafikkort" - }, - "Unknown Monitor": { - "Unknown Monitor": "Okänd bildskärm" - }, - "Unknown Network": { - "Unknown Network": "Okänt nätverk" - }, - "Unknown Title": { - "Unknown Title": "Okänd titel" - }, - "Unknown Track": { - "Unknown Track": "Okänt spår" - }, - "Unload on Close": { - "Unload on Close": "Avlasta vid stängning" - }, - "Unmute": { - "Unmute": "Slå på ljud" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "Slå på banderoller för %1" - }, - "Unnamed Rule": { - "Unnamed Rule": "Namnlös regel" - }, - "Unpair": { - "Unpair": "Ta bort parkoppling" - }, - "Unpair failed": { - "Unpair failed": "Bortkoppling misslyckades" - }, - "Unpin": { - "Unpin": "Ta bort fästning" - }, - "Unpin from Dock": { - "Unpin from Dock": "Ta bort från Dock" - }, - "Unsaved Changes": { - "Unsaved Changes": "Osparade ändringar" - }, - "Unsaved changes": { - "Unsaved changes": "Osparade ändringar" - }, - "Unsaved note...": { - "Unsaved note...": "Osparad anteckning..." - }, - "Untitled": { - "Untitled": "Inget namn" - }, - "Untrust": { - "Untrust": "Lita inte på" - }, - "Up to date": { - "Up to date": "Uppdaterat" - }, - "Update": { - "Update": "Uppdatera" - }, - "Update All": { - "Update All": "Uppdatera alla" - }, - "Update Plugin": { - "Update Plugin": "Uppdatera tillägg" - }, - "Uptime": { - "Uptime": "Drifttid" - }, - "Uptime:": { - "Uptime:": "Drifttid:" - }, - "Urgent Color": { - "Urgent Color": "Brådskande färg" - }, - "Usage Tips": { - "Usage Tips": "Användartips" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "Använd 24-timmarsklocka istället för 12-timmarsklocka" - }, - "Use Custom Command": { - "Use Custom Command": "Använd anpassat kommando" - }, - "Use Grid Layout": { - "Use Grid Layout": "Använd rutnätslayout" - }, - "Use IP Location": { - "Use IP Location": "Använd IP-plats" - }, - "Use Imperial Units": { - "Use Imperial Units": "Använd imperiska enheter" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Använd imperiska enheter (°F, mph, inHg) istället för metriska (°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Använd monospaceteckensnitt" - }, - "Use System Theme": { - "Use System Theme": "Använd systemtema" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "Använd en anpassad bild för inloggningsskärmen, eller lämna tomt för att använda skrivbordets bakgrundsbild." - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "Använd en fast skuggriktning för denna menyrad" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "Använd en säkerhetsnyckel för låsskärmsautentisering." - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Använd en extern bakgrundsbildshanterare som swww, hyprpaper eller swaybg." - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Använd animerade vågiga förloppsrader för mediauppspelning" - }, - "Use custom border size": { - "Use custom border size": "Använd anpassad ramstorlek" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "Använd anpassad ram/fokusring-bredd" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Använd ett anpassat kommando för att uppdatera systemet" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Använd anpassade mellanrum istället för menyradsavstånd" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Använd anpassad fönsterradie istället för temaradie" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "Använd anpassad fönsteravrundning istället för temaradie" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "Använd skrivbordets bakgrundsbild" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "Använd fingeravtrycksautentisering för låsskärmen." - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Använd ljust läge istället för mörkt läge" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "Använd meter per sekund istället för km/h för vindhastighet" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "Använd mindre notiskort" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Använd ljudtemat från systeminställningarna" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "Använd samma position och storlek på alla bildskärmar" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "Använd utlösarprefix för att aktivera" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "Används när accentfärgen är inställd på Anpassad" - }, - "User": { - "User": "Användare" - }, - "Username": { - "Username": "Användarnamn" - }, - "Username...": { - "Username...": "Användarnamn..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "Använder soluppgång/solnedgångstider baserat på din plats." - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Använder soluppgång och solnedgång till att automatiskt schemalägga nattläge utifrån din plats." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "Använder delade inställningar från Gammakontroll" - }, - "Utilities": { - "Utilities": "Verktyg" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN-anslutningar" - }, - "VPN Password": { - "VPN Password": "VPN-lösenord" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN-konfiguration uppdaterad" - }, - "VPN connections": { - "VPN connections": "VPN-anslutningar" - }, - "VPN deleted": { - "VPN deleted": "VPN raderat" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN importerat: %1" - }, - "VPN not available": { - "VPN not available": "VPN är inte tillgängligt" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "Visa VPN-status och snabbanslutning" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "VRR endast helskärm" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR vid behov" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Variabel uppdateringsfrekvens" - }, - "Verification": { - "Verification": "Verifiering" - }, - "Version": { - "Version": "Version" - }, - "Vertical Deck": { - "Vertical Deck": "Vertikal kortlek" - }, - "Vertical Grid": { - "Vertical Grid": "Vertikalt rutnät" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Vertikal rullning" - }, - "Vertical Tiling": { - "Vertical Tiling": "Kakla vertikalt" - }, - "Vibrant": { - "Vibrant": "Livlig" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Livlig palett med lekfull mättnad." - }, - "Video Path": { - "Video Path": "Videosökväg" - }, - "Video Screensaver": { - "Video Screensaver": "Videoskärmsläckare" - }, - "Videos": { - "Videos": "Videor" - }, - "View Mode": { - "View Mode": "Visningsläge" - }, - "Visibility": { - "Visibility": "Synlighet" - }, - "Visual Effects": { - "Visual Effects": "Visuella effekter" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Avskiljare mellan widgetar" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Animerad övergång som spelas vid byte av bakgrundsbild" - }, - "Volume": { - "Volume": "Volym" - }, - "Volume Changed": { - "Volume Changed": "Volymen ändrades" - }, - "Volume Slider": { - "Volume Slider": "Volymreglage" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Volym, ljusstyrka och andra systemskärmvisningar" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Bakgrundsbild" - }, - "Wallpaper Error": { - "Wallpaper Error": "Bakgrundsbildsfel" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Bakgrundsbildskärm" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "Bakgrundsbildsfyllningsläge" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Bakgrundsbildsbearbetning misslyckades" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Bakgrundsbildsbearbetning misslyckades – kontrollera sökvägen" - }, - "Wallpapers": { - "Wallpapers": "Bakgrundsbilder" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Varm färgtemperatur att applicera" - }, - "Warning": { - "Warning": "Varning" - }, - "Warnings": { - "Warnings": "Varningar" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Vågig förloppsrad" - }, - "Weather": { - "Weather": "Väder" - }, - "Weather Widget": { - "Weather Widget": "Väderwidget" - }, - "Welcome": { - "Welcome": "Välkommen" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "Välkommen till DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "När du klickar på ett dockfönster i en Hyprland-specialarbetsyta, ta tillbaka den specialarbetsytan innan fönstret fokuseras" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "När aktiverat sorteras appar alfabetiskt. När avaktiverat sorteras appar efter användningsfrekvens." - }, - "When locked": { - "When locked": "När låst" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "När uppdateringswidgeten används, dölj den om ingen uppdatering hittas" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi-lösenord" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi och Ethernet-anslutning" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi är inte tillgängligt" - }, - "WiFi": { - "WiFi": "Wi-Fi" - }, - "WiFi Device": { - "WiFi Device": "Wi-Fi-enhet" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "Wi-Fi QR-kod för " - }, - "WiFi disabled": { - "WiFi disabled": "Wi-Fi är avaktiverat" - }, - "WiFi enabled": { - "WiFi enabled": "Wi-Fi är aktiverat" - }, - "WiFi is off": { - "WiFi is off": "Wi-Fi är av" - }, - "WiFi off": { - "WiFi off": "Wi-Fi av" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Bred (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Bakgrundsfärg för widget" - }, - "Widget Management": { - "Widget Management": "Widgethantering" - }, - "Widget Outline": { - "Widget Outline": "Widgetkantlinje" - }, - "Widget Style": { - "Widget Style": "Widgetstil" - }, - "Widget Styling": { - "Widget Styling": "Widgetstil" - }, - "Widget Transparency": { - "Widget Transparency": "Genomskinlighet på widget" - }, - "Widget added": { - "Widget added": "Widget tillagd" - }, - "Widget removed": { - "Widget removed": "Widget borttagen" - }, - "Widgets": { - "Widgets": "Widgetar" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "Widgetar, layout, stil" - }, - "Width": { - "Width": "Bredd" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "Bredd på fönsterram (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "Bredd på fönsterram (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "Bredd på fönsterram och fokusring" - }, - "Wind": { - "Wind": "Vind" - }, - "Wind Speed": { - "Wind Speed": "Vindhastighet" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "Vindhastighet i m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "Fönsterhörnradie" - }, - "Window Gaps": { - "Window Gaps": "Fönstermellanrum" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Fönstermellanrum (px)" - }, - "Window Height": { - "Window Height": "Fönsterhöjd" - }, - "Window Opening": { - "Window Opening": "Fönsteröppning" - }, - "Window Rounding": { - "Window Rounding": "Fönsteravrundning" - }, - "Window Rules": { - "Window Rules": "Fönsterregler" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "Inkludering av fönsterregler saknas" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "Fönsterregler inte konfigurerade" - }, - "Wipe": { - "Wipe": "Sudda" - }, - "Workspace": { - "Workspace": "Arbetsyta" - }, - "Workspace Appearance": { - "Workspace Appearance": "Utseende på arbetsyta" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Indexnummer på arbetsyta" - }, - "Workspace Names": { - "Workspace Names": "Namn på arbetsytor" - }, - "Workspace Padding": { - "Workspace Padding": "Minst antal alltid synliga arbetsytor" - }, - "Workspace Settings": { - "Workspace Settings": "Inställningar för arbetsytor" - }, - "Workspace Switcher": { - "Workspace Switcher": "Växla arbetsytor" - }, - "Workspace name": { - "Workspace name": "Arbetsytans namn" - }, - "Workspaces": { - "Workspaces": "Arbetsytor" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Arbetsytor & widgetar" - }, - "Write:": { - "Write:": "Skrivit:" - }, - "X Axis": { - "X Axis": "X-axel" - }, - "Y Axis": { - "Y Axis": "Y-axel" - }, - "Yes": { - "Yes": "Ja" - }, - "Yesterday": { - "Yesterday": "Igår" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Du har osparade ändringar. Vill du spara dem innan du stänger fliken?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Du har osparade ändringar. Vill du spara dem innan du fortsätter?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Du har osparade ändringar. Vill du spara dem innan du skapar en ny fil?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Du har osparade ändringar. Vill du spara dem innan du öppnar en fil?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "Du måste ange antingen:\nQT_QPA_PLATFORMTHEME=gtk3 ELLER\nQT_QPA_PLATFORMTHEME=qt6ct\nsom miljövariabler och sedan starta om skalet.\n\nqt6ct kräver att qt6ct-kde är installerat." - }, - "You're All Set!": { - "You're All Set!": "Allt är klart!" - }, - "Your system is up to date!": { - "Your system is up to date!": "Ditt system är uppdaterat!" - }, - "actions": { - "actions": "åtgärder" - }, - "attached": { - "attached": "ansluten" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "av %1" - }, - "days": { - "days": "dagar" - }, - "detached": { - "detached": "frånkopplad" - }, - "device": { - "device": "enhet" - }, - "devices connected": { - "devices connected": "enheter anslutna" - }, - "dgop not available": { - "dgop not available": "dgop är inte tillgängligt" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "dms är ett mycket anpassningsbart, modernt skrivbordsskal med en Material 3-inspirerad design.

        Det är byggt med Quickshell, ett QT6-ramverk för att bygga skrivbordsskal, och Go, ett statiskt typat kompilerat programmeringsspråk." - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "dms/cursor-konfigurationen finns men ingår inte. Markörsinställningar tillämpas inte." - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/outputs-konfigurationen finns men ingår inte i din kompositorkonfiguration. Bildskärmsändringar sparas inte." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "t.ex. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "t.ex. focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "t.ex. notify-send 'Hej' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "t.ex. scratch, /^tmp_.*/, build" - }, - "events": { - "events": "händelser" - }, - "ext": { - "ext": "tillägg" - }, - "featured": { - "featured": "utvald" - }, - "leave empty for default": { - "leave empty for default": "lämna tomt för standard" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl inte tillgänglig – låsintegration kräver DMS-socketanslutning" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord-server" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "Matugen hittades inte – installera matugen-paketet för dynamisk tematisering" - }, - "minutes": { - "minutes": "minuter" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "nav" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix-chatt" - }, - "niri shortcuts config": { - "niri shortcuts config": "niri-kortkommandokonfiguration" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "nu" - }, - "official": { - "official": "officiell" - }, - "on Hyprland": { - "on Hyprland": "på Hyprland" - }, - "on MangoWC": { - "on MangoWC": "på MangoWC" - }, - "on Miracle WM": { - "on Miracle WM": "på Miracle WM" - }, - "on Niri": { - "on Niri": "på Niri" - }, - "on Scroll": { - "on Scroll": "på Scroll" - }, - "on Sway": { - "on Sway": "på Sway" - }, - "open": { - "open": "öppna" - }, - "or run ": { - "or run ": "eller kör " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon är inte tillgänglig" - }, - "procs": { - "procs": "proc." - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri Subreddit" - }, - "seconds": { - "seconds": "sekunder" - }, - "source": { - "source": "källa" - }, - "this app": { - "this app": "den här appen" - }, - "up": { - "up": "upp" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "Uppdatera DMS för NM-intergration." - }, - "v%1 by %2": { - "v%1 by %2": "v%1 av %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype är inte tillgängligt – installera wtype för inklistrningsstöd" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Installera endast från trovärdiga källor." - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Månad (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - Månad (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Månad (jan)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Månad (januari)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Tillägg kan innehålla buggar och säkerhetsrisker" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Granska källkoden innan du installerar om möjligheten finns" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Dag (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Dag (1-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Dagens namn (mån)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Dagens namn (måndag)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - År (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - År (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: Navigera • Blanksteg: Expandera • Retur: Åtgärd/Expandera • E: Text" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: Navigera • Retur/Ctrl+C: Kopiera • Del: Radera • F10: Hjälp" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: Navigera • Retur: Klistra in • Del: Radera • F10: Hjälp" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/tr.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/tr.json deleted file mode 100644 index a2ebd69..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/tr.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "" - }, - "%1 Sessions": { - "%1 Sessions": "" - }, - "%1 active session": { - "%1 active session": "" - }, - "%1 active sessions": { - "%1 active sessions": "" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "" - }, - "%1 character": { - "%1 character": "" - }, - "%1 characters": { - "%1 characters": "%1 karakter" - }, - "%1 connected": { - "%1 connected": "%1 bağlı" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "" - }, - "%1 disconnected": { - "%1 disconnected": "" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "" - }, - "%1 display": { - "%1 display": "" - }, - "%1 displays": { - "%1 displays": "" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "" - }, - "%1 filtered": { - "%1 filtered": "" - }, - "%1 is now included in config": { - "%1 is now included in config": "" - }, - "%1 issue found": { - "%1 issue found": "" - }, - "%1 issues found": { - "%1 issues found": "" - }, - "%1 notifications": { - "%1 notifications": "" - }, - "%1 update": { - "%1 update": "" - }, - "%1 updates": { - "%1 updates": "" - }, - "%1 variants": { - "%1 variants": "%1 varyant" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "" - }, - "%1 widgets": { - "%1 widgets": "%1 widget" - }, - "%1 window": { - "%1 window": "" - }, - "%1 windows": { - "%1 windows": "" - }, - "%1m ago": { - "%1m ago": "%1dk önce" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "" - }, - "(Default)": { - "(Default)": "" - }, - "(Unnamed)": { - "(Unnamed)": "(İsimsiz)" - }, - "+ %1 more": { - "+ %1 more": "" - }, - "/path/to/videos": { - "/path/to/videos": "" - }, - "0 = square corners": { - "0 = square corners": "0 = kare köşeler" - }, - "1 day": { - "1 day": "1 gün" - }, - "1 device connected": { - "1 device connected": "" - }, - "1 event": { - "1 event": "1 etkinlik" - }, - "1 hour": { - "1 hour": "" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "" - }, - "1 minute": { - "1 minute": "1 dakika" - }, - "1 notification": { - "1 notification": "" - }, - "1 second": { - "1 second": "1 saniye" - }, - "10 minutes": { - "10 minutes": "10 dakika" - }, - "10 seconds": { - "10 seconds": "10 saniye" - }, - "10-bit Color": { - "10-bit Color": "10-bit Renk" - }, - "12 hours": { - "12 hours": "" - }, - "14 days": { - "14 days": "14 gün" - }, - "15 minutes": { - "15 minutes": "" - }, - "15 seconds": { - "15 seconds": "15 saniye" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "" - }, - "2 minutes": { - "2 minutes": "2 dakika" - }, - "2 seconds": { - "2 seconds": "" - }, - "20 minutes": { - "20 minutes": "" - }, - "20 seconds": { - "20 seconds": "" - }, - "24-Hour Format": { - "24-Hour Format": "24-Saat Biçimi" - }, - "24-hour clock": { - "24-hour clock": "" - }, - "24-hour format": { - "24-hour format": "24-saat biçimi" - }, - "25 seconds": { - "25 seconds": "" - }, - "250 ms": { - "250 ms": "" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 gün" - }, - "3 hours": { - "3 hours": "" - }, - "3 minutes": { - "3 minutes": "" - }, - "3 seconds": { - "3 seconds": "3 saniye" - }, - "30 days": { - "30 days": "30 gün" - }, - "30 minutes": { - "30 minutes": "" - }, - "30 seconds": { - "30 seconds": "30 saniye" - }, - "35 seconds": { - "35 seconds": "" - }, - "3rd party": { - "3rd party": "Üçüncü taraf" - }, - "4 hours": { - "4 hours": "" - }, - "4 seconds": { - "4 seconds": "" - }, - "40 seconds": { - "40 seconds": "" - }, - "45 seconds": { - "45 seconds": "" - }, - "5 minutes": { - "5 minutes": "5 dakika" - }, - "5 seconds": { - "5 seconds": "5 saniye" - }, - "50 seconds": { - "50 seconds": "" - }, - "500 ms": { - "500 ms": "" - }, - "55 seconds": { - "55 seconds": "" - }, - "6 hours": { - "6 hours": "" - }, - "7 days": { - "7 days": "7 gün" - }, - "750 ms": { - "750 ms": "" - }, - "8 hours": { - "8 hours": "" - }, - "8 seconds": { - "8 seconds": "8 saniye" - }, - "90 days": { - "90 days": "90 gün" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "Bu isimde bir dosya zaten var. Üzerine yazmak istiyor musunuz?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "" - }, - "AC Power": { - "AC Power": "" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "Durduruldu" - }, - "About": { - "About": "Hakkında" - }, - "Accent Color": { - "Accent Color": "" - }, - "Accept": { - "Accept": "" - }, - "Accept Jobs": { - "Accept Jobs": "İşleri Kabul Et" - }, - "Accepting": { - "Accepting": "Kabul ediliyor" - }, - "Access clipboard history": { - "Access clipboard history": "Pano geçmişine eriş" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "Bildirimlere ve rahatsız etmeye eriş" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "Sistem kontrolleri ve ayarlara eriş" - }, - "Action": { - "Action": "Eylem" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "" - }, - "Actions": { - "Actions": "Eylemler" - }, - "Activate": { - "Activate": "Etkinleştir" - }, - "Activate Greeter": { - "Activate Greeter": "" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "" - }, - "Activation": { - "Activation": "" - }, - "Active": { - "Active": "Etkin" - }, - "Active Color": { - "Active Color": "" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "Aktif Kilit Ekranı Monitörü" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "" - }, - "Active: %1": { - "Active: %1": "Aktif: %1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "Aktif: %1 +%2" - }, - "Active: None": { - "Active: None": "Etkin: Hiçbiri" - }, - "Adapters": { - "Adapters": "Bağdaştırıcılar" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "Ekle" - }, - "Add Bar": { - "Add Bar": "Bar Ekle" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "Masaüstü Widget'ı Ekle" - }, - "Add Printer": { - "Add Printer": "Yazıcı Ekle" - }, - "Add Title": { - "Add Title": "" - }, - "Add Widget": { - "Add Widget": "Widget Ekle" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "%1 Bölümüne Widget Ekle" - }, - "Add a border around the dock": { - "Add a border around the dock": "Dock etrafına kenarlık ekle" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "Tüm uygulama başlatmalarına özel bir önek ekleyin. Bu, 'uwsm-app', 'systemd-run' veya diğer komut sarmalayıcıları gibi şeyler için kullanılabilir." - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "Masaüstünüzde görünen widget'ları ekle ve yapılandır" - }, - "Add by Address": { - "Add by Address": "" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "Izgara görünümü modunda sütun sayısını ayarla" - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "Gelişmiş" - }, - "Afternoon": { - "Afternoon": "Öğleden Sonra" - }, - "All": { - "All": "Tümü" - }, - "All Monitors": { - "All Monitors": "Tüm Monitörler" - }, - "All checks passed": { - "All checks passed": "" - }, - "All day": { - "All day": "Tüm gün" - }, - "All displays": { - "All displays": "Tüm ekranlar" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Geri • F1/I: Dosya bilgisi • F10: Yardım • Esc: Kapat" - }, - "Alternative (OR)": { - "Alternative (OR)": "" - }, - "Always Active": { - "Always Active": "" - }, - "Always Show Percentage": { - "Always Show Percentage": "Yüzdeyi Her Zaman Göster" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "" - }, - "Always on icons": { - "Always on icons": "Her zaman açık simgeler" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "Her zaman en az 3 çalışma alanı göster, daha azı kullanılabilir olsa da" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "Niri'nin genel görünümü açıkken her zaman dock'u göster" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "Yalnızca bir ekran bağlı olduğunda her zaman göster" - }, - "Amount": { - "Amount": "Miktar" - }, - "Analog": { - "Analog": "Analog" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "Analog, dijital veya yığılmış saat ekranı" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "" - }, - "Animation Duration": { - "Animation Duration": "" - }, - "Animation Speed": { - "Animation Speed": "Animasyon Hızı" - }, - "Anonymous Identity": { - "Anonymous Identity": "Anonim Kimlik" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "Anonim Kimlik (isteğe bağlı)" - }, - "App Customizations": { - "App Customizations": "" - }, - "App ID Substitutions": { - "App ID Substitutions": "" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "" - }, - "App Launcher": { - "App Launcher": "Uygulama Başlatıcı" - }, - "App Names": { - "App Names": "" - }, - "App Theming": { - "App Theming": "" - }, - "Appearance": { - "Appearance": "" - }, - "Application Dock": { - "Application Dock": "Uygulama Dock'u" - }, - "Applications": { - "Applications": "Uygulamalar" - }, - "Apply Changes": { - "Apply Changes": "Değişiklikleri Uygula" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "GTK Renklerini Uygula" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "QT Renklerini Uygula" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "Göz yorgunluğunu azaltmak için sıcak renk sıcaklığı uygulayın. Etkinleştirme zamanını kontrol etmek için aşağıdaki otomasyon ayarlarını kullanın." - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "" - }, - "Apps Dock": { - "Apps Dock": "" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "" - }, - "Apps Icon": { - "Apps Icon": "Uygulamalar" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "Uygulamalar önce kullanım sıklığına göre, daha sonra son kullanılana göre ve en son alfabetik olarak sıralanır." - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "" - }, - "Architecture": { - "Architecture": "" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "Ekranları düzenleyin ve çözünürlüğü, yenileme hızını ve VRR'yi yapılandırın" - }, - "Attach": { - "Attach": "" - }, - "Audio": { - "Audio": "Ses" - }, - "Audio Codec": { - "Audio Codec": "Ses Codec'i" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "Ses Codec Seçimi" - }, - "Audio Devices": { - "Audio Devices": "Ses Aygıtları" - }, - "Audio Input": { - "Audio Input": "Ses Girişi" - }, - "Audio Output": { - "Audio Output": "Ses Çıkışı" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "Ses Çıkış Aygıtları (" - }, - "Audio Output Switch": { - "Audio Output Switch": "Ses Çıkışı Değişimi" - }, - "Audio Visualizer": { - "Audio Visualizer": "Ses Görselleştirici" - }, - "Audio system restarted": { - "Audio system restarted": "" - }, - "Audio volume control": { - "Audio volume control": "Ses seviyesi kontrolü" - }, - "Auth": { - "Auth": "Kimlik" - }, - "Auth Type": { - "Auth Type": "Kimlik Türü" - }, - "Authenticate": { - "Authenticate": "Kimlik Doğrula" - }, - "Authenticating...": { - "Authenticating...": "" - }, - "Authentication": { - "Authentication": "Kimlik Doğrulama" - }, - "Authentication Required": { - "Authentication Required": "Kimlik Doğrulama Gerekli" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "Kimlik doğrulama başarısız, lütfen tekrar deneyin" - }, - "Authorize": { - "Authorize": "Yetkilendir" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "Şununla eşleşmeyi yetkilendir: " - }, - "Authorize service for ": { - "Authorize service for ": "Şunun için servisi yetkilendir: " - }, - "Auto": { - "Auto": "Oto" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "" - }, - "Auto (Wide)": { - "Auto (Wide)": "Oto (Geniş)" - }, - "Auto Location": { - "Auto Location": "Otomatik Konum" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "Otomatik Açılır Pencere Boşlukları" - }, - "Auto-Clear After": { - "Auto-Clear After": "Sonra Otomatik Sil" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "Uygulamaları başlatınca Niri genel görünümünü otomatik kapat." - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "Bildirimler şundan eskiyse otomatik sil" - }, - "Auto-hide": { - "Auto-hide": "Otomatik Gizleme" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "Dock'u Otomatik Gizle" - }, - "Auto-saving...": { - "Auto-saving...": "Otomatik kaydetme..." - }, - "Autoconnect": { - "Autoconnect": "Otomatik Bağlan" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "Otomatik bağlanma devre dışı" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "Otomatik bağlanma etkin" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "" - }, - "Automatic Control": { - "Automatic Control": "Otomatik Kontrol" - }, - "Automatic Cycling": { - "Automatic Cycling": "Otomatik Döngü" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "Aynı klasördeki duvar kağıtlarını otomatik olarak değiştir" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "Bundan daha eski girişleri otomatik olarak sil" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "IP adresine göre konumu otomatik olarak algıla" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "IP adresinizi kullanarak konumunuzu otomatik olarak belirleyin" - }, - "Automatically lock after": { - "Automatically lock after": "Şu zaman sonra otomatik olarak kilitle" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "Sistem askıya alınmaya hazırlanırken ekranı otomatik olarak kilitle" - }, - "Automation": { - "Automation": "" - }, - "Available": { - "Available": "Kullanılabilir" - }, - "Available Layouts": { - "Available Layouts": "Mevcut Düzenler" - }, - "Available Networks": { - "Available Networks": "Kullanılabilir Ağlar" - }, - "Available Plugins": { - "Available Plugins": "Kullanılabilir Eklentiler" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "Kullanılabilir Ekranlar (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "" - }, - "Available.": { - "Available.": "" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "Geri" - }, - "Backend": { - "Backend": "Arka Uç" - }, - "Background": { - "Background": "" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "Arkaplan Opaklığı" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "" - }, - "Backlight device": { - "Backlight device": "Arka aydınlatma cihazı" - }, - "Balance power and performance": { - "Balance power and performance": "" - }, - "Balanced": { - "Balanced": "" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "Odaklanmış vurgularla dengeli palet (varsayılan)." - }, - "Bar Configurations": { - "Bar Configurations": "Bar Ayarları" - }, - "Bar Shadows": { - "Bar Shadows": "" - }, - "Bar Transparency": { - "Bar Transparency": "Bar Opaklığı" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "" - }, - "Battery": { - "Battery": "Batarya" - }, - "Battery %1": { - "Battery %1": "" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "Batarya Şarj Sınırı" - }, - "Battery and power management": { - "Battery and power management": "Batarya ve güç yönetimi" - }, - "Battery level and power management": { - "Battery level and power management": "Batarya seviyesi ve güç yönetimi" - }, - "Behavior": { - "Behavior": "Davranış" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Kilit ekranını loginctl'den gelen dbus sinyallerine bağlayın. Harici bir kilit ekranı kullanıyorsanız devre dışı bırakın" - }, - "Binds Include Missing": { - "Binds Include Missing": "Bağlantı dahili yok" - }, - "Binds include added": { - "Binds include added": "Bağlantı dahili eklendi" - }, - "Bit Depth": { - "Bit Depth": "Bit Derinliği" - }, - "Block Out": { - "Block Out": "" - }, - "Block Out From": { - "Block Out From": "" - }, - "Block notifications": { - "Block notifications": "Bildirimleri engelle" - }, - "Blocked": { - "Blocked": "Engellendi" - }, - "Blue light filter": { - "Blue light filter": "Mavi ışık filtresi" - }, - "Bluetooth": { - "Bluetooth": "Bluetooth" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "Bluetooth Ayarları" - }, - "Bluetooth not available": { - "Bluetooth not available": "Bluetooth kullanılamıyor" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "Bulanık Duvar Kağıdı Katmanı" - }, - "Blur on Overview": { - "Blur on Overview": "Genel Görünümde Bulanıklık" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "Niri genel görünümü açıkken duvar kağıdını bulanıklaştır" - }, - "Body": { - "Body": "" - }, - "Border": { - "Border": "Kenarlık" - }, - "Border Color": { - "Border Color": "Kenarlık Rengi" - }, - "Border Opacity": { - "Border Opacity": "Kenarlık Opaklığı" - }, - "Border Size": { - "Border Size": "" - }, - "Border Thickness": { - "Border Thickness": "Kenarlık Kalınlığı" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "" - }, - "Bottom": { - "Bottom": "Alt" - }, - "Bottom Center": { - "Bottom Center": "" - }, - "Bottom Left": { - "Bottom Left": "Alt Sol" - }, - "Bottom Right": { - "Bottom Right": "Alt Sağ" - }, - "Bottom Section": { - "Bottom Section": "Alt Bölüm" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "Sabitlenmiş ve çalışan uygulamalar için alt dock" - }, - "Brightness": { - "Brightness": "Parlaklık" - }, - "Brightness Slider": { - "Brightness Slider": "Parlaklık Kaydırıcı" - }, - "Brightness Value": { - "Brightness Value": "Parlaklık Değeri" - }, - "Brightness control not available": { - "Brightness control not available": "Parlaklık kontrolü kullanılamıyor" - }, - "Browse": { - "Browse": "Göz at" - }, - "Browse Files": { - "Browse Files": "" - }, - "Browse Plugins": { - "Browse Plugins": "Eklentilere Göz At" - }, - "Browse Themes": { - "Browse Themes": "Temalara Göz At" - }, - "Browse or search plugins": { - "Browse or search plugins": "" - }, - "Button Color": { - "Button Color": "" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU Grafiği" - }, - "CPU Temperature": { - "CPU Temperature": "CPU Sıcaklığı" - }, - "CPU Usage": { - "CPU Usage": "CPU Kullanımı" - }, - "CPU temperature display": { - "CPU temperature display": "CPU sıcaklık göstergesi" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU kullanım göstergesi" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU, bellek, ağ ve disk izleme" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS Güvenli Olmayan Filtre Uyarısı" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS Eksik Filtre Uyarısı" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS Yazıcı Sunucusu" - }, - "CUPS not available": { - "CUPS not available": "CUPS kullanılamıyor" - }, - "Camera": { - "Camera": "Kamera" - }, - "Cancel": { - "Cancel": "İptal" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "" - }, - "Canceled": { - "Canceled": "İptal Edildi" - }, - "Cannot pair": { - "Cannot pair": "Eşleştirilemedi" - }, - "Capabilities": { - "Capabilities": "Yetenekler" - }, - "Capacity": { - "Capacity": "Kapasite" - }, - "Caps Lock": { - "Caps Lock": "Caps Lock" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "Caps Lock Göstergesi" - }, - "Caps Lock is on": { - "Caps Lock is on": "" - }, - "Center Section": { - "Center Section": "Orta Bölüm" - }, - "Center Single Column": { - "Center Single Column": "Tek Sütunu Ortala" - }, - "Center Tiling": { - "Center Tiling": "Merkez Döşeme" - }, - "Certificate Password": { - "Certificate Password": "Sertifika Parolası" - }, - "Change Song": { - "Change Song": "" - }, - "Change Volume": { - "Change Volume": "" - }, - "Change bar appearance": { - "Change bar appearance": "Bar görünümünü değiştir" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "" - }, - "Channel": { - "Channel": "Kanal" - }, - "Charging": { - "Charging": "Şarj ediliyor" - }, - "Check for system updates": { - "Check for system updates": "Sistem güncellemelerini kontrol et" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "" - }, - "Checking...": { - "Checking...": "" - }, - "Checking…": { - "Checking…": "" - }, - "Choose Color": { - "Choose Color": "Renk Seç" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "Başlatıcı Logo Rengini Seçin" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "" - }, - "Choose a color": { - "Choose a color": "Renk seç" - }, - "Choose colors from palette": { - "Choose colors from palette": "Paletten renkler seç" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "" - }, - "Choose icon": { - "Choose icon": "Simge seçin" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "Widgetlar için arkaplan rengini seç" - }, - "Choose the border accent color": { - "Choose the border accent color": "Kenarlık vurgu rengini seç" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "DankBar'daki başlatıcı düğmesinde görüntülenen logoyu seçin" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "Bildirim açılır pencerelerinin ekranda nerede görüneceğini seçin" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "Ekran gösterimlerinin ekranda nerede gösterileceğini seç" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "Bu widget'ı hangi ekranlarda göstereceğinizi seçin" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "Hangi monitörün kilit ekranı arayüzünü göstereceğini seçin. Diğer monitörler, OLED yanma koruması için düz bir renk gösterecektir." - }, - "Chroma Style": { - "Chroma Style": "" - }, - "Cipher": { - "Cipher": "Şifre" - }, - "Circle": { - "Circle": "" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "" - }, - "Clear": { - "Clear": "Temizle" - }, - "Clear All": { - "Clear All": "Tümünü Temizle" - }, - "Clear All Jobs": { - "Clear All Jobs": "Tüm İşleri Temizle" - }, - "Clear History?": { - "Clear History?": "" - }, - "Clear Sky": { - "Clear Sky": "" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "Sunucu başladığında tüm geçmişi temizle" - }, - "Clear at Startup": { - "Clear at Startup": "Başlangıçta Temizle" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "Çıktı yapılandırmasını oluşturmak ve kompozitör yapılandırmanıza dahil etmek için 'Kur'a tıklayın." - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": ".ovpn veya .conf dosyası eklemek için İçe Aktar'ı tıklayın." - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "" - }, - "Click Through": { - "Click Through": "" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "" - }, - "Click to capture": { - "Click to capture": "Yakalamak için tıkla" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "Özel tema JSON dosyasını seçmek için tıklayın" - }, - "Clip": { - "Clip": "" - }, - "Clip to Geometry": { - "Clip to Geometry": "" - }, - "Clipboard": { - "Clipboard": "Pano" - }, - "Clipboard History": { - "Clipboard History": "Pano Geçmişi" - }, - "Clipboard Manager": { - "Clipboard Manager": "Pano Yöneticisi" - }, - "Clipboard sent": { - "Clipboard sent": "" - }, - "Clipboard service not available": { - "Clipboard service not available": "Pano hizmeti kullanılamıyor" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "Pano çalışır fakat hiçbir şey diske kaydedilmez" - }, - "Clock": { - "Clock": "Saat" - }, - "Clock Style": { - "Clock Style": "Saat Stili" - }, - "Close": { - "Close": "Kapat" - }, - "Close All Windows": { - "Close All Windows": "" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "Başlatmada Genel Görünümü Kapat" - }, - "Close Window": { - "Close Window": "" - }, - "Color": { - "Color": "Renk" - }, - "Color Gamut": { - "Color Gamut": "Renk Gamı" - }, - "Color Management": { - "Color Management": "Renk Yönetimi" - }, - "Color Mode": { - "Color Mode": "Renk Modu" - }, - "Color Override": { - "Color Override": "Renk Değiştirme" - }, - "Color Picker": { - "Color Picker": "Renk Seçici" - }, - "Color Temperature": { - "Color Temperature": "Renk Sıcaklığı" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "Kilit ekranı olmayan monitörlerde görüntülenen renk" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "" - }, - "Color temperature for day time": { - "Color temperature for day time": "Gündüz için renk sıcaklığı" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "Gece modu için renk sıcaklığı" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "DMS kayıt defterinden renk teması" - }, - "Colorful": { - "Colorful": "" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "Parlak kontrastlı vurguların renkli karışımı." - }, - "Colorize Active": { - "Colorize Active": "" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "" - }, - "Column": { - "Column": "Kolon" - }, - "Column Display": { - "Column Display": "" - }, - "Column Width": { - "Column Width": "" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "" - }, - "Command": { - "Command": "Komut" - }, - "Commands": { - "Commands": "" - }, - "Communication": { - "Communication": "İletişim" - }, - "Community themes": { - "Community themes": "" - }, - "Compact": { - "Compact": "" - }, - "Compact Mode": { - "Compact Mode": "Kompakt Mod" - }, - "Completed": { - "Completed": "Tamamlandı" - }, - "Compositor": { - "Compositor": "Kompozitör" - }, - "Compositor Settings": { - "Compositor Settings": "Kompozitör Ayarları" - }, - "Compositor not supported": { - "Compositor not supported": "" - }, - "Config Format": { - "Config Format": "Yapılandırma Biçimi" - }, - "Config action: %1": { - "Config action: %1": "Yapılandırma eylemi: %1" - }, - "Config validation failed": { - "Config validation failed": "Yapılandırma doğrulaması başarısız oldu" - }, - "Configuration": { - "Configuration": "Yapılandırma" - }, - "Configuration activated": { - "Configuration activated": "Yapılandırma aktifleştirildi" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "Bu ekran yeniden bağlandığında yapılandırma korunacaktır" - }, - "Configure": { - "Configure": "" - }, - "Configure Keybinds": { - "Configure Keybinds": "" - }, - "Configure a new printer": { - "Configure a new printer": "Yeni bir yazıcı yapılandır" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "Adlandırılmış çalışma alanları için simgeleri yapılandırın. Her ikisi de etkinleştirildiğinde simgeler sayılara göre önceliklidir." - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "Hangi ekranların kabuk bileşenlerini göstereceğini yapılandırın" - }, - "Confirm": { - "Confirm": "Onayla" - }, - "Confirm Delete": { - "Confirm Delete": "Silmeyi Onayla" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "Ekran Değişikliklerini Onaylayın" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "Şunun için şifreyi onayla: " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "Şununla çakışıyor: %1" - }, - "Connect": { - "Connect": "Bağlan" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "" - }, - "Connect to VPN": { - "Connect to VPN": "VPN'e Bağlan" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "Wi-Fi'ye Bağlan" - }, - "Connected": { - "Connected": "Bağlı" - }, - "Connected Device": { - "Connected Device": "" - }, - "Connected Displays": { - "Connected Displays": "Bağlı Ekranlar" - }, - "Connecting to Device": { - "Connecting to Device": "Cihaza Bağlanma" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "Bağlanıyor..." - }, - "Connection failed": { - "Connection failed": "" - }, - "Contains": { - "Contains": "" - }, - "Content": { - "Content": "" - }, - "Content copied": { - "Content copied": "" - }, - "Contrast": { - "Contrast": "Kontrast" - }, - "Control Center": { - "Control Center": "Kontrol Merkezi" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "" - }, - "Control currently playing media": { - "Control currently playing media": "Şu anda oynatılan medyayı kontrol et" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "Çubuk üzerinde kaydırarak çalışma alanlarını ve sütunları kontrol edin" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "Tüm açılır pencerelerin, modal pencerelerin ve bunların içerik katmanlarının opaklığını kontrol eder." - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "" - }, - "Cooldown": { - "Cooldown": "Bekleme" - }, - "Copied GIF": { - "Copied GIF": "" - }, - "Copied MP4": { - "Copied MP4": "" - }, - "Copied WebP": { - "Copied WebP": "" - }, - "Copied to clipboard": { - "Copied to clipboard": "Panoya kopyalandı" - }, - "Copied!": { - "Copied!": "Kopyalandı!" - }, - "Copy": { - "Copy": "" - }, - "Copy Content": { - "Copy Content": "" - }, - "Copy Full Command": { - "Copy Full Command": "" - }, - "Copy HTML": { - "Copy HTML": "" - }, - "Copy Name": { - "Copy Name": "" - }, - "Copy PID": { - "Copy PID": "PID'i Kopyala" - }, - "Copy Text": { - "Copy Text": "" - }, - "Copy path": { - "Copy path": "" - }, - "Corner Radius": { - "Corner Radius": "Köşe Yarıçapı" - }, - "Corner Radius Override": { - "Corner Radius Override": "Köşe Yarıçapını Değiştir" - }, - "Corners & Background": { - "Corners & Background": "Köşeler & Arkaplan" - }, - "Count Only": { - "Count Only": "" - }, - "Cover Open": { - "Cover Open": "Kapak Açık" - }, - "Create": { - "Create": "" - }, - "Create Dir": { - "Create Dir": "Dizin Oluştur" - }, - "Create Printer": { - "Create Printer": "Yazıcı Oluştur" - }, - "Create Window Rule": { - "Create Window Rule": "" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "" - }, - "Create rule for:": { - "Create rule for:": "" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "" - }, - "Creating...": { - "Creating...": "Oluşturuluyor..." - }, - "Critical Priority": { - "Critical Priority": "Kritik Öncelik" - }, - "Current": { - "Current": "Şu an" - }, - "Current Items": { - "Current Items": "Mevcut Öğeler" - }, - "Current Locale": { - "Current Locale": "" - }, - "Current Monitor": { - "Current Monitor": "" - }, - "Current Period": { - "Current Period": "Mevcut Periyot" - }, - "Current Status": { - "Current Status": "Mevcut Durum" - }, - "Current Temp": { - "Current Temp": "Mevcut Sıcaklık" - }, - "Current Theme: %1": { - "Current Theme: %1": "Mevcut Tema: %1" - }, - "Current Weather": { - "Current Weather": "Güncel Hava Durumu" - }, - "Current Workspace": { - "Current Workspace": "" - }, - "Current time and date display": { - "Current time and date display": "Güncel saat ve tarih göstergesi" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "Mevcut hava koşulları ve sıcaklık" - }, - "Current: %1": { - "Current: %1": "Mevcut: %1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "" - }, - "Cursor Size": { - "Cursor Size": "" - }, - "Cursor Theme": { - "Cursor Theme": "" - }, - "Custom": { - "Custom": "Özel" - }, - "Custom Color": { - "Custom Color": "" - }, - "Custom Duration": { - "Custom Duration": "Özel Süre" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "Özel Hazırda Beklet Komutu" - }, - "Custom Location": { - "Custom Location": "Özel Konum" - }, - "Custom Lock Command": { - "Custom Lock Command": "Özel Kilitle Komutu" - }, - "Custom Logout Command": { - "Custom Logout Command": "Özel Çıkış Komutu" - }, - "Custom Name": { - "Custom Name": "" - }, - "Custom Power Actions": { - "Custom Power Actions": "Özel Güç Eylemleri" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "Özel Kapat Komutu" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "Özel Yeniden Başlat Komutu" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "Özel Askıya Al Komutu" - }, - "Custom Transparency": { - "Custom Transparency": "Özel Şeffaflık" - }, - "Custom power profile": { - "Custom power profile": "" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "Özel tema JSON dosyasından yüklendi" - }, - "Custom...": { - "Custom...": "Özel..." - }, - "Custom: ": { - "Custom: ": "Özel: " - }, - "Customizable empty space": { - "Customizable empty space": "Özelleştirilebilir boş alan" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "Güç menüsünde hangi eylemlerin görüneceğini özelleştirin" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI monitörü" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "DEMO MODU - Çıkmak için herhangi bir yere tıklayın" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS Eklenti Yöneticisi Kullanılamıyor" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS güncel değil" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS hizmeti bağlı değil. Pano ayarları kullanılamıyor." - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS kabuk eylemleri (başlatıcı, pano, vb.)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET kullanılamıyor" - }, - "DWL service not available": { - "DWL service not available": "DWL hizmeti kullanılamıyor" - }, - "Daily": { - "Daily": "" - }, - "Daily at:": { - "Daily at:": "Her gün saat:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell & Sistem İkonları (yeniden başlatma gerekir)" - }, - "Dark Mode": { - "Dark Mode": "Karanlık Mod" - }, - "Dark mode base": { - "Dark mode base": "" - }, - "Dark mode harmony": { - "Dark mode harmony": "" - }, - "Darken Modal Background": { - "Darken Modal Background": "Koyu Modal Arkaplanı" - }, - "Date Format": { - "Date Format": "Tarih Biçimi" - }, - "Date format": { - "Date format": "" - }, - "Date format on greeter": { - "Date format on greeter": "" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "Şafak (Astronomik Alacakaranlık)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "Şafak (Sivil Alacakaranlık)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "Şafak (Denizci Şafağı)" - }, - "Day Date": { - "Day Date": "" - }, - "Day Month Date": { - "Day Month Date": "" - }, - "Day Temperature": { - "Day Temperature": "Gündüz Sıcaklığı" - }, - "Daytime": { - "Daytime": "Gündüz" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "Varsayılan" - }, - "Default (Black)": { - "Default (Black)": "" - }, - "Default Width (%)": { - "Default Width (%)": "Varsayılan Genişlik (%)" - }, - "Default selected action": { - "Default selected action": "Ön tanımlı seçili eylem" - }, - "Defaults": { - "Defaults": "Varsayılanlar" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Temizle • Shift+Del: Tümünü Temizle • 1-9: Eylemler • F10: Yardım • Esc: Kapat" - }, - "Delete": { - "Delete": "Sil" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "" - }, - "Delete Class": { - "Delete Class": "Sınıf Sil" - }, - "Delete Printer": { - "Delete Printer": "Yazıcı Sil" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "" - }, - "Delete VPN": { - "Delete VPN": "VPN'i Sil" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "Altta yatan görüntüye çok yakın renkler türetir" - }, - "Description": { - "Description": "Tanım" - }, - "Desktop": { - "Desktop": "" - }, - "Desktop Clock": { - "Desktop Clock": "Masaüstü Saati" - }, - "Desktop Entry": { - "Desktop Entry": "" - }, - "Desktop Widget": { - "Desktop Widget": "Masaüstü Widget'ı" - }, - "Desktop Widgets": { - "Desktop Widgets": "Masaüstü Widgetları" - }, - "Desktop background images": { - "Desktop background images": "Masaüstü arkaplan resimleri" - }, - "Detailed": { - "Detailed": "" - }, - "Details for \"%1": { - "Details for \"%1\"": "" - }, - "Development": { - "Development": "Geliştirme" - }, - "Device": { - "Device": "Aygıt" - }, - "Device connections": { - "Device connections": "Cihaz bağlantıları" - }, - "Device names updated": { - "Device names updated": "" - }, - "Device paired": { - "Device paired": "Cihaz eşleştirildi" - }, - "Device unpaired": { - "Device unpaired": "" - }, - "Digital": { - "Digital": "Dijital" - }, - "Direction Source": { - "Direction Source": "" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "Otomatik Bağlanmayı Devre Dışı Bırak" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "Dahili Duvar Kağıtlarını Devre Dışı Bırak" - }, - "Disable History Persistence": { - "Disable History Persistence": "Geçmiş Kalıcılığını Devre Dışı Bırak" - }, - "Disable Output": { - "Disable Output": "Çıkışı Devre Dışı Bırak" - }, - "Disabled": { - "Disabled": "Devre Dışı" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "WiFi kapatılıyor..." - }, - "Disc": { - "Disc": "" - }, - "Discard": { - "Discard": "Yok Say" - }, - "Discharging": { - "Discharging": "" - }, - "Disconnect": { - "Disconnect": "Bağlantıyı Kes" - }, - "Disconnected": { - "Disconnected": "Bağlantı Kesildi" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "WiFi bağlantısı kesildi" - }, - "Discover Devices": { - "Discover Devices": "" - }, - "Disk": { - "Disk": "Disk" - }, - "Disk I/O": { - "Disk I/O": "" - }, - "Disk Usage": { - "Disk Usage": "Disk Kullanımı" - }, - "Disk Usage Display": { - "Disk Usage Display": "" - }, - "Disks": { - "Disks": "" - }, - "Dismiss": { - "Dismiss": "Reddet" - }, - "Display": { - "Display": "" - }, - "Display Assignment": { - "Display Assignment": "Ekran Ataması" - }, - "Display Control": { - "Display Control": "" - }, - "Display Name Format": { - "Display Name Format": "Ekran İsim Formatı" - }, - "Display Profiles": { - "Display Profiles": "" - }, - "Display Settings": { - "Display Settings": "Ekran Ayarları" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "Sabitlenmiş ve çalışan uygulamaları içeren bir dock göster" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "Tam ekran uygulamaların üzerinde tüm öncelikleri göster" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "DWL düzenlerini görüntüle ve değiştir" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "Çalışma alanı göstergesinde uygulama simgelerini göster" - }, - "Display brightness control": { - "Display brightness control": "Ekran parlaklık kontrolü" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "Ekran yapılandırması kullanılamıyor. WLR çıktı yönetimi protokolü desteklenmiyor." - }, - "Display currently focused application title": { - "Display currently focused application title": "Şu anda odaklanmış uygulamanın başlığını göster" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "Yalnızca pencere içeren çalışma alanlarını göster" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "Güç menüsü eylemlerini liste yerine ızgara şeklinde göster" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "Saatte saniyeleri göster" - }, - "Display the power system menu": { - "Display the power system menu": "Güç sistem menüsünü göster" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "OSD açılır pencerelerinde ses seviyesi ve parlaklık yüzdelerini göster" - }, - "Displays": { - "Displays": "Ekranlar" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "Etkin klavye düzenini gösterir ve değiştirmeye izin verir" - }, - "Distribution": { - "Distribution": "" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "Tüm spektrumu kapsayan çeşitli renk paleti" - }, - "Do Not Disturb": { - "Do Not Disturb": "Rahatsız Etme" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock & Başlatıcı" - }, - "Dock Transparency": { - "Dock Transparency": "Dock Şeffaflığı" - }, - "Dock Visibility": { - "Dock Visibility": "Dock Görünürlüğü" - }, - "Docs": { - "Docs": "Belgeler" - }, - "Documents": { - "Documents": "" - }, - "Domain (optional)": { - "Domain (optional)": "Etki alanı (isteğe bağlı)" - }, - "Don't Change": { - "Don't Change": "Değiştirme" - }, - "Don't Save": { - "Don't Save": "Kaydetme" - }, - "Door Open": { - "Door Open": "Kapı Açık" - }, - "Downloads": { - "Downloads": "" - }, - "Drag to Reorder": { - "Drag to Reorder": "" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Widget'ları sürükleyerek bölümler içinde yeniden sıralayın. Göz simgesini kullanarak widget'ları gizleyin/gösterin (aralıkları korur) veya X simgesini kullanarak tamamen kaldırın." - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "" - }, - "Driver": { - "Driver": "Sürücü" - }, - "Drizzle": { - "Drizzle": "" - }, - "Duplicate": { - "Duplicate": "Çoğalt" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "Duvar kağıdını bulanıklık ile çoğalt" - }, - "Duration": { - "Duration": "" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "Alacakaranlık (Astronomik Alacakaranlık)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "Alacakaranlık (Sivil Alacakaranlık)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "Alacakaranlık (Denizci Alacakaranlığı)" - }, - "Dynamic": { - "Dynamic": "Dinamik" - }, - "Dynamic Properties": { - "Dynamic Properties": "" - }, - "Dynamic Theming": { - "Dynamic Theming": "" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "Duvar kağıdından dinamik renkler" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "" - }, - "Edge Spacing": { - "Edge Spacing": "Kenar Aralığı" - }, - "Edit App": { - "Edit App": "" - }, - "Edit Window Rule": { - "Edit Window Rule": "" - }, - "Education": { - "Education": "Eğitim" - }, - "Empty": { - "Empty": "Boş" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "Daha geniş renk gamı ve HDR desteği için 10 bit renk derinliğini etkinleştirin" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "Otomatik Bağlanmayı Etkinleştir" - }, - "Enable Bar": { - "Enable Bar": "Barı Etkinleştir" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "Rahatsız Etmeyi Etkinleştir" - }, - "Enable History": { - "Enable History": "Geçmişi Aç" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "Genel Görünüm Katmanını Etkinleştir" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "" - }, - "Enable System Sounds": { - "Enable System Sounds": "Sistem Seslerini Etkinleştir" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "" - }, - "Enable Weather": { - "Enable Weather": "Hava Durumunu Etkinleştir" - }, - "Enable WiFi": { - "Enable WiFi": "WiFi Etkinleştir" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Kompozitör tarafından hedeflenebilir bulanıklık katmanını etkinleştir (isim alanı: dms:blurwallpaper). Manuel Niri yapılandırması gerektirir." - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "Parmak izi kimlik doğrulamasını etkinleştir" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "loginctl kilit entegrasyonunu etkinleştir" - }, - "Enable security key at login": { - "Enable security key at login": "" - }, - "Enable security key authentication": { - "Enable security key authentication": "" - }, - "Enabled": { - "Enabled": "Etkin" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "WiFi açılıyor..." - }, - "End": { - "End": "Son" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "" - }, - "Enlargement %": { - "Enlargement %": "" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "6 haneli şifreyi gir" - }, - "Enter PIN": { - "Enter PIN": "PIN gir" - }, - "Enter PIN for ": { - "Enter PIN for ": "Şunun için PIN gir: " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "" - }, - "Enter command or script path": { - "Enter command or script path": "" - }, - "Enter credentials for ": { - "Enter credentials for ": "Kimlik bilgilerini girin " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "Özel kilit ekranı biçimini girin (örneğin, dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "Özel üst çubuk biçimini girin (örneğin, ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "" - }, - "Enter filename...": { - "Enter filename...": "Dosya adı girin..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "Başlatma önekini girin (örneğin, 'uwsm-app')" - }, - "Enter network name and password": { - "Enter network name and password": "" - }, - "Enter passkey for ": { - "Enter passkey for ": "Şunun için şifre gir: " - }, - "Enter password for ": { - "Enter password for ": "Parolayı girin " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "Bu şifreyi şuraya gir: " - }, - "Enter to Paste": { - "Enter to Paste": "" - }, - "Enterprise": { - "Enterprise": "Kurumsal" - }, - "Entry pinned": { - "Entry pinned": "" - }, - "Entry unpinned": { - "Entry unpinned": "" - }, - "Environment Variables": { - "Environment Variables": "" - }, - "Error": { - "Error": "Hata" - }, - "Errors": { - "Errors": "Hatalar" - }, - "Ethernet": { - "Ethernet": "Ethernet" - }, - "Exact": { - "Exact": "" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "Özel Bölge Ofseti" - }, - "Experimental Feature": { - "Experimental Feature": "Deneysel Özellik" - }, - "Explore": { - "Explore": "" - }, - "Exponential": { - "Exponential": "Üstel" - }, - "Expressive": { - "Expressive": "" - }, - "Extend battery life": { - "Extend battery life": "" - }, - "Extensible architecture": { - "Extensible architecture": "" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "Harici Duvar Kağıdı Yönetimi" - }, - "Extra Arguments": { - "Extra Arguments": "" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: Değiştir • F10: Yardım" - }, - "Fade": { - "Fade": "" - }, - "Fade to lock screen": { - "Fade to lock screen": "Kilit Ekranı Solması" - }, - "Fade to monitor off": { - "Fade to monitor off": "" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "Yapılandırma etkinleştirilemedi" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "" - }, - "Failed to add binds include": { - "Failed to add binds include": "Bağlantı dahili eklenemedi" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "Yazıcı sınıfa eklenemedi" - }, - "Failed to browse device": { - "Failed to browse device": "" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "Tüm işler iptal edemedi" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "Seçilen işler iptal edemedi" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "VPN bağlantısı kurulamadı" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "%1 bağlanılamadı" - }, - "Failed to copy entry": { - "Failed to copy entry": "Kayıt kopyalanamadı" - }, - "Failed to create printer": { - "Failed to create printer": "Yazıcı oluşturulamadı" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "VPN silinemedi" - }, - "Failed to delete class": { - "Failed to delete class": "Sınıf silinemedi" - }, - "Failed to delete printer": { - "Failed to delete printer": "Yazıcı silinemedi" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "İş kabulü devre dışı bırakılamadı" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "Gece modu devre dışı bırakılamadı" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "VPN bağlantısı kesilemedi" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "VPN'lerin bağlantısı kesilemedi" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "WiFi bağlantısı kesilemedi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "IP konumunu etkinleştiremedi" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "WiFi etkinleştirilemedi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "İş kabulü etkinleştirilemedi" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "Gece modu etkinleştiremedi" - }, - "Failed to hold job": { - "Failed to hold job": "İş bekletilemedi" - }, - "Failed to import VPN": { - "Failed to import VPN": "VPN içe aktarılamadı" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "VPN ayarı yüklenemedi" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "Pano yapılandırması yüklenemedi." - }, - "Failed to move job": { - "Failed to move job": "İş taşınamadı" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "plugin_settings.json ayrıştırılamadı" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "session.json ayrıştırılamadı" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "settings.json ayrıştırılamadı" - }, - "Failed to pause printer": { - "Failed to pause printer": "Yazıcıyı duraklatma başarısız" - }, - "Failed to pin entry": { - "Failed to pin entry": "" - }, - "Failed to print test page": { - "Failed to print test page": "Test sayfası yazdırılamadı" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "" - }, - "Failed to remove device": { - "Failed to remove device": "Cihaz kaldırılamadı" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "Tuş kombinasyonu kaldırılamadı" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "Yazıcı sınıftan kaldırılamadı" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "" - }, - "Failed to restart job": { - "Failed to restart job": "İş yeniden başlatılamadı" - }, - "Failed to resume printer": { - "Failed to resume printer": "Yazıcıyı devam ettirme başarısız" - }, - "Failed to ring device": { - "Failed to ring device": "" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "" - }, - "Failed to save audio config": { - "Failed to save audio config": "" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "Pano ayarı kaydedilemedi" - }, - "Failed to save keybind": { - "Failed to save keybind": "Tuş kombinasyonu kaydedilemedi" - }, - "Failed to save profile file": { - "Failed to save profile file": "" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "" - }, - "Failed to send file": { - "Failed to send file": "" - }, - "Failed to send ping": { - "Failed to send ping": "" - }, - "Failed to set brightness": { - "Failed to set brightness": "Parlaklık ayarlanamadı" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "Gece modu konumu ayarlanamadı" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "Gece modu zamanlaması ayarlanamadı" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "Gece modu sıcaklığı ayarlanamadı" - }, - "Failed to set power profile": { - "Failed to set power profile": "" - }, - "Failed to set profile image": { - "Failed to set profile image": "Profil resmi ayarlanamadı" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "Profil resmi ayarlanamadı: %1" - }, - "Failed to share": { - "Failed to share": "" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "%1 bağlantı başlatılamadı" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "" - }, - "Failed to update VPN": { - "Failed to update VPN": "VPN güncellenemedi" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "Otomatik bağlanma güncellenemedi" - }, - "Failed to update description": { - "Failed to update description": "Tanım güncellenemedi" - }, - "Failed to update location": { - "Failed to update location": "Konum güncellenemedi" - }, - "Failed to update sharing": { - "Failed to update sharing": "Paylaşım güncellenemedi" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "Doğrulama için geçici dosya yazılmadı" - }, - "Features": { - "Features": "" - }, - "Feels": { - "Feels": "" - }, - "Feels Like": { - "Feels Like": "Hissedilen" - }, - "Feels Like %1°": { - "Feels Like %1°": "" - }, - "Fidelity": { - "Fidelity": "" - }, - "Field": { - "Field": "" - }, - "File": { - "File": "Dosya" - }, - "File Already Exists": { - "File Already Exists": "Dosya Zaten Mevcut" - }, - "File Information": { - "File Information": "Dosya Bilgisi" - }, - "File received from": { - "File received from": "" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "" - }, - "Files": { - "Files": "Dosyalar" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "Dosya sistemi kullanım izlemesi" - }, - "Fill": { - "Fill": "" - }, - "Find in Text": { - "Find in Text": "Metinde Bul" - }, - "Find in note...": { - "Find in note...": "Notta bul..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "" - }, - "Finish": { - "Finish": "" - }, - "First Day of Week": { - "First Day of Week": "" - }, - "First Time Setup": { - "First Time Setup": "İlk Kurulum" - }, - "Fit": { - "Fit": "" - }, - "Fix Now": { - "Fix Now": "Şimdi Düzelt" - }, - "Fixing...": { - "Fixing...": "Düzeltiliyor..." - }, - "Flags": { - "Flags": "" - }, - "Flipped": { - "Flipped": "Döndürülmüş" - }, - "Flipped 180°": { - "Flipped 180°": "180° döndürüldü" - }, - "Flipped 270°": { - "Flipped 270°": "270° döndürülmüş" - }, - "Flipped 90°": { - "Flipped 90°": "90° döndürülmüş" - }, - "Float": { - "Float": "" - }, - "Focus": { - "Focus": "" - }, - "Focus at Startup": { - "Focus at Startup": "Başlangıçta Odakla" - }, - "Focused Border": { - "Focused Border": "" - }, - "Focused Color": { - "Focused Color": "" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "" - }, - "Focused Window": { - "Focused Window": "Odaklanılmış Pencere" - }, - "Focused monitor only": { - "Focused monitor only": "" - }, - "Fog": { - "Fog": "" - }, - "Folder": { - "Folder": "" - }, - "Folders": { - "Folders": "" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "" - }, - "Follow focus": { - "Follow focus": "Odağı takip et" - }, - "Font": { - "Font": "" - }, - "Font Family": { - "Font Family": "Yazı Tipi Ailesi" - }, - "Font Scale": { - "Font Scale": "Yazı Tipi Ölçeği" - }, - "Font Size": { - "Font Size": "Yazı Tipi Boyutu" - }, - "Font Weight": { - "Font Weight": "Yazı Tipi Ağırlığı" - }, - "Font used on the login screen": { - "Font used on the login screen": "" - }, - "Force HDR": { - "Force HDR": "Zorla HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "" - }, - "Force Wide Color": { - "Force Wide Color": "Geniş Rengi Zorla" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "Terminal uygulamalarının her zaman koyu renk şemalarını kullanmasını zorla" - }, - "Forecast": { - "Forecast": "" - }, - "Forecast Days": { - "Forecast Days": "" - }, - "Forecast Not Available": { - "Forecast Not Available": "Hava Tahmini Mevcut Değil" - }, - "Forever": { - "Forever": "" - }, - "Forget": { - "Forget": "Unut" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "" - }, - "Forget Device": { - "Forget Device": "Aygıtı Unut" - }, - "Forget Network": { - "Forget Network": "Ağı Unut" - }, - "Forgot network %1": { - "Forgot network %1": "%1 ağını unut" - }, - "Format Legend": { - "Format Legend": "Biçim Açıklaması" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "" - }, - "Frequency": { - "Frequency": "Frekans" - }, - "Fruit Salad": { - "Fruit Salad": "" - }, - "Full Command:": { - "Full Command:": "" - }, - "Full Content": { - "Full Content": "" - }, - "Full Day & Month": { - "Full Day & Month": "" - }, - "Full with Year": { - "Full with Year": "" - }, - "Fullscreen": { - "Fullscreen": "" - }, - "Fullscreen Only": { - "Fullscreen Only": "" - }, - "Fully Charged": { - "Fully Charged": "" - }, - "Fun": { - "Fun": "Eğlence" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G: ızgara • Z/X: boyut" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "" - }, - "GPU Temperature": { - "GPU Temperature": "GPU Sıcaklığı" - }, - "GPU temperature display": { - "GPU temperature display": "" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "" - }, - "Games": { - "Games": "Oyunlar" - }, - "Gamma Control": { - "Gamma Control": "Gama Kontrolü" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Gama kontrolü mevcut değil. DMS API V6+ gerekir." - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "" - }, - "Generic": { - "Generic": "" - }, - "Get Started": { - "Get Started": "Başlarken" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "" - }, - "Golden Hour": { - "Golden Hour": "Altın Saat" - }, - "Good": { - "Good": "İyi" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "Gotik Köşe Yarıçapı" - }, - "Goth Corners": { - "Goth Corners": "Gotik Köşeler" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "Yapılandırılabilir bir bekleme süresi ile kilitlemeden önce ekranı kademeli olarak karartın" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "" - }, - "Graph Time Range": { - "Graph Time Range": "Grafik Zaman Aralığı" - }, - "Graphics": { - "Graphics": "Grafik" - }, - "Greeter": { - "Greeter": "" - }, - "Greeter Appearance": { - "Greeter Appearance": "" - }, - "Greeter Behavior": { - "Greeter Behavior": "" - }, - "Greeter Status": { - "Greeter Status": "" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "" - }, - "Greeter font": { - "Greeter font": "" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "" - }, - "Grid": { - "Grid": "Izgara" - }, - "Grid Columns": { - "Grid Columns": "Izgara Sütunları" - }, - "Grid: OFF": { - "Grid: OFF": "Izgara: KAPALI" - }, - "Grid: ON": { - "Grid: ON": "Izgara: AÇIK" - }, - "Group": { - "Group": "" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "" - }, - "Group by App": { - "Group by App": "Uygulamaya Göre Gruplandır" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "Aynı uygulamanın birden fazla penceresini pencere sayısı göstergesi ile gruplayın" - }, - "Group removed": { - "Group removed": "" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "" - }, - "Groups": { - "Groups": "" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR Ton Eşleme" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "HDR modu deneysel bir özelliktir. Etkinleştirmeden önce monitörünüzün HDR'yi desteklediğini doğrulayın." - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "" - }, - "Health": { - "Health": "Sağlık" - }, - "Heavy Rain": { - "Heavy Rain": "" - }, - "Heavy Snow": { - "Heavy Snow": "" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "" - }, - "Height": { - "Height": "" - }, - "Held": { - "Held": "Bekletildi" - }, - "Help": { - "Help": "Yardım" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "Hazırda Beklet" - }, - "Hidden": { - "Hidden": "" - }, - "Hidden (%1)": { - "Hidden (%1)": "" - }, - "Hidden Apps": { - "Hidden Apps": "" - }, - "Hidden Network": { - "Hidden Network": "" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "" - }, - "Hide": { - "Hide": "" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "" - }, - "Hide App": { - "Hide App": "" - }, - "Hide Delay": { - "Hide Delay": "Gizleme Gecikmesi" - }, - "Hide Indicators": { - "Hide Indicators": "" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "Güncelleyici Widgetını Gizle" - }, - "Hide When Typing": { - "Hide When Typing": "" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "Pencere Açıkken Gizle" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "" - }, - "Hide device": { - "Hide device": "" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "" - }, - "Hide on Touch": { - "Hide on Touch": "" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "Kaynak tonları koruyan yüksek sadakatli palet" - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "" - }, - "History": { - "History": "" - }, - "History Retention": { - "History Retention": "" - }, - "History Settings": { - "History Settings": "Geçmiş Ayarları" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "" - }, - "Hold Duration": { - "Hold Duration": "Tutma Süresi" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "Onaylamak için daha uzun süre basılı tutun" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "Güç Eylemlerini Onaylamak İçin Basılı Tutun" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "Onaylamak için basılı tutun (%1ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "Onaylamak için basılı tutun (%1s)" - }, - "Home": { - "Home": "" - }, - "Host": { - "Host": "" - }, - "Hostname": { - "Hostname": "" - }, - "Hot Corners": { - "Hot Corners": "Sıcak Köşeler" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "Kısayol katmanı başlığı (opsiyonel)" - }, - "Hour": { - "Hour": "Saat" - }, - "Hourly": { - "Hourly": "" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "Duvar kağıdı değiştirme sıklığı" - }, - "How the background image is scaled": { - "How the background image is scaled": "" - }, - "Humidity": { - "Humidity": "Nem" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "" - }, - "Hyprland Options": { - "Hyprland Options": "" - }, - "Hyprland Website": { - "Hyprland Website": "" - }, - "I Understand": { - "I Understand": "Anladım" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP Adresi:" - }, - "IP address or hostname": { - "IP address or hostname": "" - }, - "ISO Date": { - "ISO Date": "" - }, - "Icon": { - "Icon": "" - }, - "Icon Scale": { - "Icon Scale": "" - }, - "Icon Size": { - "Icon Size": "Simge Boyutu" - }, - "Icon Size %": { - "Icon Size %": "" - }, - "Icon Theme": { - "Icon Theme": "Simge Teması" - }, - "Idle": { - "Idle": "Boşta" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "Boşta Kalma Engelleyici" - }, - "Idle Settings": { - "Idle Settings": "Boşta Kalma Ayarları" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "Boşta kalma takibi desteklenmiyor - daha yeni Quickshell sürümü gerekli" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "Alan gizliyse, bir tuşa basıldığında görünür." - }, - "Ignore Completely": { - "Ignore Completely": "" - }, - "Image": { - "Image": "Resim" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "Görüntü panoya kopyalandı" - }, - "Import": { - "Import": "İçe Aktar" - }, - "Import VPN": { - "Import VPN": "VPN'i İçe Aktar" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "İnaktif Monitör Rengi" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "Geçişleri Dahil Et" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "Uyumsuz Eklentiler Yüklendi" - }, - "Incorrect password": { - "Incorrect password": "Hatalı parola" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "Gösterge Stili" - }, - "Individual Batteries": { - "Individual Batteries": "Tekil Piller" - }, - "Individual bar configuration": { - "Individual bar configuration": "Bireysel bar yapılandırması" - }, - "Info": { - "Info": "Bilgi" - }, - "Inherit": { - "Inherit": "Devral" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "" - }, - "Inhibitable": { - "Inhibitable": "" - }, - "Input Devices": { - "Input Devices": "Giriş Aygıtları" - }, - "Input Volume Slider": { - "Input Volume Slider": "Giriş Ses Seviyesi Kaydırıcı" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "Yükle" - }, - "Install Greeter": { - "Install Greeter": "" - }, - "Install Plugin": { - "Install Plugin": "Eklenti Yükle" - }, - "Install Theme": { - "Install Theme": "Tema Yükle" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "DMS tema kayıt defterinden renk temaları yükle" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "" - }, - "Install failed: %1": { - "Install failed: %1": "Yüklenemedi: %1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "Dinamik tema için matugen paketini yükleyin" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "DMS kayıt defterinden '%1' eklentisi yüklensin mi?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "DMS eklenti defterinden eklentiler yükle" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "DMS kayıt defterinden '%1' teması yüklensin mi?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "" - }, - "Installed": { - "Installed": "Yüklendi" - }, - "Installed: %1": { - "Installed: %1": "Yüklendi: %1" - }, - "Installing: %1": { - "Installing: %1": "Yükleniyor: %1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "" - }, - "Intensity": { - "Intensity": "" - }, - "Interface:": { - "Interface:": "Arayüz:" - }, - "Interlock Open": { - "Interlock Open": "Kilit Açık" - }, - "Internet": { - "Internet": "İnternet" - }, - "Interval": { - "Interval": "Aralık" - }, - "Invalid configuration": { - "Invalid configuration": "Geçersiz yapılandırma" - }, - "Invert on mode change": { - "Invert on mode change": "Mod değişikliğinde ters çevir" - }, - "Iris Bloom": { - "Iris Bloom": "" - }, - "Isolate Displays": { - "Isolate Displays": "İzole Ekranlar" - }, - "Jobs": { - "Jobs": "İşler" - }, - "Jobs: ": { - "Jobs: ": "İşler:" - }, - "Keep Awake": { - "Keep Awake": "Uyanık Tut" - }, - "Keep Changes": { - "Keep Changes": "Değişiklikleri Tut" - }, - "Keeping Awake": { - "Keeping Awake": "Uyanık Tutuluyor" - }, - "Kernel": { - "Kernel": "" - }, - "Key": { - "Key": "Tuş" - }, - "Keybind Sources": { - "Keybind Sources": "" - }, - "Keybinds": { - "Keybinds": "Kısayollar" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "Klavye Düzeni Adı" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "Klavye Kısayolları" - }, - "Keys": { - "Keys": "Tuşlar" - }, - "Kill": { - "Kill": "" - }, - "Kill Process": { - "Kill Process": "Süreci Öldür" - }, - "Kill Session": { - "Kill Session": "" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED cihazı" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "" - }, - "LabWC Website": { - "LabWC Website": "" - }, - "Large": { - "Large": "" - }, - "Largest": { - "Largest": "" - }, - "Last hour": { - "Last hour": "" - }, - "Last launched %1": { - "Last launched %1": "Son başlatma %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "" - }, - "Last launched just now": { - "Last launched just now": "Son başlatma şimdi" - }, - "Latitude": { - "Latitude": "Enlem" - }, - "Launch": { - "Launch": "Başlat" - }, - "Launch Prefix": { - "Launch Prefix": "Başlatma Ön Eki" - }, - "Launch on dGPU": { - "Launch on dGPU": "dGPU'da Başlat" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "Başlatıcı" - }, - "Launcher Button": { - "Launcher Button": "" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "Başlatıcı Buton Logosu" - }, - "Layout": { - "Layout": "Düzen" - }, - "Layout Overrides": { - "Layout Overrides": "Düzen geçersiz kılmaları" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "" - }, - "Left": { - "Left": "Sol" - }, - "Left Center": { - "Left Center": "" - }, - "Left Section": { - "Left Section": "Sol Bölüm" - }, - "Light Direction": { - "Light Direction": "" - }, - "Light Mode": { - "Light Mode": "Aydınlık Modu" - }, - "Light Rain": { - "Light Rain": "" - }, - "Light Snow": { - "Light Snow": "" - }, - "Light Snow Showers": { - "Light Snow Showers": "" - }, - "Light mode base": { - "Light mode base": "" - }, - "Light mode harmony": { - "Light mode harmony": "" - }, - "Line": { - "Line": "" - }, - "Line: %1": { - "Line: %1": "" - }, - "Linear": { - "Linear": "Doğrusal" - }, - "Lines: %1": { - "Lines: %1": "Satırlar: %1" - }, - "List": { - "List": "Liste" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "Doygun vurgularla canlı renk paleti." - }, - "Load Average": { - "Load Average": "" - }, - "Loading codecs...": { - "Loading codecs...": "Kodekler yükleniyor..." - }, - "Loading keybinds...": { - "Loading keybinds...": "Tuş kombinasyonları yükleniyor..." - }, - "Loading trending...": { - "Loading trending...": "" - }, - "Loading...": { - "Loading...": "Yükleniyor..." - }, - "Local": { - "Local": "Yerel" - }, - "Locale": { - "Locale": "" - }, - "Locale Settings": { - "Locale Settings": "" - }, - "Location": { - "Location": "Konum" - }, - "Location Search": { - "Location Search": "Konum Arama" - }, - "Lock": { - "Lock": "Kilitle" - }, - "Lock Screen": { - "Lock Screen": "Kilit Ekranı" - }, - "Lock Screen Display": { - "Lock Screen Display": "Kilit Ekranı Görüntüsü" - }, - "Lock Screen Format": { - "Lock Screen Format": "Kilit Ekranı Biçimi" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "Kilit Ekranı davranışı" - }, - "Lock Screen layout": { - "Lock Screen layout": "Kilit Ekranı düzeni" - }, - "Lock at startup": { - "Lock at startup": "" - }, - "Lock before suspend": { - "Lock before suspend": "Askıya almadan önce kilitle" - }, - "Lock fade grace period": { - "Lock fade grace period": "" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "" - }, - "Log Out": { - "Log Out": "Çıkış" - }, - "Logging in...": { - "Logging in...": "" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "" - }, - "Long": { - "Long": "Uzun" - }, - "Long Text": { - "Long Text": "Uzun Metin" - }, - "Long press": { - "Long press": "" - }, - "Longitude": { - "Longitude": "Boylam" - }, - "Low Priority": { - "Low Priority": "Düşük Öncelik" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "DMS işlevselliğini genişletmek için eklentileri yönetin ve yapılandırın" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "4 adede kadar bağımsız bar yapılandırmasını yönetin. Her barın kendi konumu, widget'ları, stili ve ekran ataması vardır." - }, - "Management": { - "Management": "Yönetim" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "" - }, - "Manual": { - "Manual": "" - }, - "Manual Coordinates": { - "Manual Coordinates": "Manuel Koordinatlar" - }, - "Manual Direction": { - "Manual Direction": "" - }, - "Manual Gap Size": { - "Manual Gap Size": "Manuel Boşluk Boyutu" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "Manuel Göster/Gizle" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "" - }, - "Margin": { - "Margin": "Kenar Boşluğu" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "Sarf Malzemesi Boş" - }, - "Marker Supply Low": { - "Marker Supply Low": "Sarf Malzemesi Az" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "Atık Haznesi Neredeyse Dolu" - }, - "Marker Waste Full": { - "Marker Waste Full": "Atık Haznesi Dolu" - }, - "Match Criteria": { - "Match Criteria": "" - }, - "Matches profile: %1": { - "Matches profile: %1": "" - }, - "Material Colors": { - "Material Colors": "Materyal Renkleri" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "Malzeme Tasarımı'ndan ilham alan renk temaları" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "Duvar kağıdından oluşturulan malzeme renkleri" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen Bulunamadı" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen Paleti" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen Hedef Monitör" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen Şablonları" - }, - "Max Edges": { - "Max Edges": "" - }, - "Max H": { - "Max H": "" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "" - }, - "Max Running Apps": { - "Max Running Apps": "" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "" - }, - "Max Volume": { - "Max Volume": "" - }, - "Max W": { - "Max W": "" - }, - "Max apps to show": { - "Max apps to show": "Gösterilecek maks uygulama" - }, - "Max to Edges": { - "Max to Edges": "" - }, - "Maximize": { - "Maximize": "" - }, - "Maximize Detection": { - "Maximize Detection": "Algılamayı En Üst Düzeye Çıkar" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "Maksimum Kayıt Boyutu" - }, - "Maximum History": { - "Maximum History": "Maksimum Geçmiş" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "Saklanacak maksimum pano kaydı sayısı" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "Pano kaydı başına maksimum boyut" - }, - "Media": { - "Media": "Medya" - }, - "Media Controls": { - "Media Controls": "Medya Kontrolleri" - }, - "Media Empty": { - "Media Empty": "Kağıt Bitti" - }, - "Media Jam": { - "Media Jam": "Kağıt Sıkışması" - }, - "Media Low": { - "Media Low": "Kağıt Az" - }, - "Media Needed": { - "Media Needed": "Kağıt Gerekli" - }, - "Media Playback": { - "Media Playback": "" - }, - "Media Player": { - "Media Player": "Medya Oynatıcı" - }, - "Media Player Settings": { - "Media Player Settings": "Medya Oynatıcı Ayarları" - }, - "Media Players": { - "Media Players": "" - }, - "Media Players (": { - "Media Players (": "Medya Oynatıcıları (" - }, - "Media Volume": { - "Media Volume": "Medya Ses Seviyesi" - }, - "Medium": { - "Medium": "Orta" - }, - "Memory": { - "Memory": "Bellek" - }, - "Memory Graph": { - "Memory Graph": "Bellek Grafiği" - }, - "Memory Usage": { - "Memory Usage": "Bellek Kullanımı" - }, - "Memory usage indicator": { - "Memory usage indicator": "Bellek kullanım göstergesi" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "" - }, - "Message Content": { - "Message Content": "" - }, - "Microphone": { - "Microphone": "Mikrofon" - }, - "Microphone Mute": { - "Microphone Mute": "Microfon Sessiz" - }, - "Microphone Volume": { - "Microphone Volume": "Mikrofon Ses Seviyesi" - }, - "Microphone settings": { - "Microphone settings": "Mikrofon ayarları" - }, - "Microphone volume control": { - "Microphone volume control": "Mikrofon ses seviyesi kontrolü" - }, - "Middle Section": { - "Middle Section": "Orta Bölüm" - }, - "Min H": { - "Min H": "" - }, - "Min W": { - "Min W": "" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "Tek bir renk tonu etrafında oluşturulmuş minimal palet." - }, - "Minute": { - "Minute": "Dakika" - }, - "Mirror Display": { - "Mirror Display": "Ekran Yansıt" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "" - }, - "Modal Background": { - "Modal Background": "Modal Arkaplanı" - }, - "Modal Shadows": { - "Modal Shadows": "" - }, - "Modals": { - "Modals": "" - }, - "Mode": { - "Mode": "Mod" - }, - "Mode:": { - "Mode:": "Mod:" - }, - "Model": { - "Model": "Model" - }, - "Modified": { - "Modified": "Değiştirilmiş" - }, - "Modular widget bar": { - "Modular widget bar": "" - }, - "Monitor": { - "Monitor": "" - }, - "Monitor Configuration": { - "Monitor Configuration": "Monitör Yapılandırması" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "Duvar kağıdı dinamik tema renklerini yönlendiren monitör" - }, - "Monochrome": { - "Monochrome": "" - }, - "Monocle": { - "Monocle": "Monocle" - }, - "Monospace Font": { - "Monospace Font": "Sabit Aralıklı Yazı Tipi" - }, - "Month Date": { - "Month Date": "" - }, - "Morning": { - "Morning": "Sabah" - }, - "Mount Points": { - "Mount Points": "" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "" - }, - "Move": { - "Move": "" - }, - "Move Widget": { - "Move Widget": "Widget Taşı" - }, - "Moving to Paused": { - "Moving to Paused": "Duraklatılıyor" - }, - "Multi-Monitor": { - "Multi-Monitor": "" - }, - "Multiplexer": { - "Multiplexer": "" - }, - "Multiplexer Type": { - "Multiplexer Type": "" - }, - "Multiplexers": { - "Multiplexers": "" - }, - "Music": { - "Music": "" - }, - "Mute Popups": { - "Mute Popups": "" - }, - "Mute popups for %1": { - "Mute popups for %1": "" - }, - "Muted": { - "Muted": "" - }, - "Muted Apps": { - "Muted Apps": "" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "Sakin ve yatıştırıcı tonlara sahip, yumuşak renk paleti." - }, - "NM not supported": { - "NM not supported": "NM desteklenmiyor" - }, - "Name": { - "Name": "İsim" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "Adlandırılmış Çalışma Alanı Simgeleri" - }, - "Navigate": { - "Navigate": "" - }, - "Navigation": { - "Navigation": "Navigasyon" - }, - "Network": { - "Network": "Ağ" - }, - "Network Graph": { - "Network Graph": "Ağ Grafiği" - }, - "Network Info": { - "Network Info": "Ağ Bilgisi" - }, - "Network Information": { - "Network Information": "Ağ Bilgisi" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "Ağ Hız Monitörü" - }, - "Network Status": { - "Network Status": "Ağ Durumu" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "Ağ indirme ve yükleme hız gösterimi" - }, - "Neutral": { - "Neutral": "" - }, - "Never": { - "Never": "Hiçbir Zaman" - }, - "Never used": { - "Never used": "" - }, - "New": { - "New": "Yeni" - }, - "New Key": { - "New Key": "Yeni Tuş" - }, - "New Keybind": { - "New Keybind": "Yeni Tuş Kombinasyonu" - }, - "New Notification": { - "New Notification": "Yeni Bildirim" - }, - "New Session": { - "New Session": "" - }, - "New Window Rule": { - "New Window Rule": "" - }, - "New York, NY": { - "New York, NY": "New York, NY" - }, - "New group name...": { - "New group name...": "" - }, - "Next": { - "Next": "Devam et" - }, - "Next Transition": { - "Next Transition": "Sonraki Geçiş" - }, - "Night": { - "Night": "Gece" - }, - "Night Mode": { - "Night Mode": "Gece Modu" - }, - "Night Temperature": { - "Night Temperature": "Gece Sıcaklığı" - }, - "Night mode & gamma": { - "Night mode & gamma": "Gece modu & gamma" - }, - "Niri Integration": { - "Niri Integration": "Niri Entegrasyonu" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri Düzeni Geçersiz Kılmaları" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri kompozitör (focus, move, vb.)" - }, - "No": { - "No": "Hayır" - }, - "No Active Players": { - "No Active Players": "Aktif Oynatıcı Yok" - }, - "No Anim": { - "No Anim": "" - }, - "No Background": { - "No Background": "Arkaplan Yok" - }, - "No Battery": { - "No Battery": "" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "Bluetooth adaptörü bulunamadı" - }, - "No Blur": { - "No Blur": "" - }, - "No Border": { - "No Border": "" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "" - }, - "No Dim": { - "No Dim": "" - }, - "No Focus": { - "No Focus": "" - }, - "No GPU detected": { - "No GPU detected": "GPU tespit edilmedi" - }, - "No GPUs detected": { - "No GPUs detected": "" - }, - "No History": { - "No History": "" - }, - "No Media": { - "No Media": "Medya Yok" - }, - "No Round": { - "No Round": "" - }, - "No Rounding": { - "No Rounding": "" - }, - "No Shadow": { - "No Shadow": "" - }, - "No VPN profiles": { - "No VPN profiles": "VPN profili yok" - }, - "No Weather": { - "No Weather": "" - }, - "No Weather Data": { - "No Weather Data": "" - }, - "No Weather Data Available": { - "No Weather Data Available": "Hava Durumu Verileri Mevcut Değil" - }, - "No action": { - "No action": "Eylem yok" - }, - "No active %1 sessions": { - "No active %1 sessions": "" - }, - "No adapter": { - "No adapter": "" - }, - "No adapters": { - "No adapters": "Bağdaştırıcı yok" - }, - "No app customizations.": { - "No app customizations.": "" - }, - "No apps found": { - "No apps found": "" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "" - }, - "No battery": { - "No battery": "Batarya yok" - }, - "No brightness devices available": { - "No brightness devices available": "Parlaklık cihazı yok" - }, - "No changes": { - "No changes": "Değişiklik yok" - }, - "No checks passed": { - "No checks passed": "" - }, - "No custom theme file": { - "No custom theme file": "Özel tema dosyası yok" - }, - "No devices": { - "No devices": "" - }, - "No devices connected": { - "No devices connected": "" - }, - "No devices found": { - "No devices found": "Aygıt bulunamadı" - }, - "No disk data": { - "No disk data": "Disk verisi yok" - }, - "No disk data available": { - "No disk data available": "Disk verisi mevcut değil" - }, - "No drivers found": { - "No drivers found": "Sürücü bulunamadı" - }, - "No errors": { - "No errors": "Sorun yok" - }, - "No features enabled": { - "No features enabled": "Etkinleştirilmiş özellik yok" - }, - "No files found": { - "No files found": "Dosya bulunamadı" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "" - }, - "No folders found": { - "No folders found": "" - }, - "No hidden apps.": { - "No hidden apps.": "" - }, - "No info items": { - "No info items": "" - }, - "No information available": { - "No information available": "" - }, - "No input device": { - "No input device": "" - }, - "No input devices found": { - "No input devices found": "" - }, - "No items added yet": { - "No items added yet": "Henüz eklenen öğe yok" - }, - "No keybinds found": { - "No keybinds found": "Tuş kombinasyonu bulunamadı" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "" - }, - "No match criteria": { - "No match criteria": "" - }, - "No matches": { - "No matches": "Eşleşme yok" - }, - "No matching processes": { - "No matching processes": "" - }, - "No monitors": { - "No monitors": "" - }, - "No mount points found": { - "No mount points found": "" - }, - "No output device": { - "No output device": "" - }, - "No output devices found": { - "No output devices found": "" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "" - }, - "No plugin results": { - "No plugin results": "" - }, - "No plugins found": { - "No plugins found": "Eklenti bulunamadı" - }, - "No plugins found.": { - "No plugins found.": "Eklenti bulunamadı." - }, - "No printer found": { - "No printer found": "Yazıcı Bulunamadı" - }, - "No printers configured": { - "No printers configured": "Hiçbir yazıcı ayarlanmadı" - }, - "No printers found": { - "No printers found": "Hiçbir yazıcı bulunmadı" - }, - "No profiles": { - "No profiles": "" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "" - }, - "No results found": { - "No results found": "" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "" - }, - "No sessions found": { - "No sessions found": "" - }, - "No status output.": { - "No status output.": "" - }, - "No themes found": { - "No themes found": "Tema bulunmadı" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "Yüklü tema yok. Kayıt defterinden yüklemek için temaları göz atın." - }, - "No trigger": { - "No trigger": "" - }, - "No video found in folder": { - "No video found in folder": "" - }, - "No wallpaper selected": { - "No wallpaper selected": "Duvar kağıdı seçilmedi" - }, - "No wallpapers": { - "No wallpapers": "" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "" - }, - "No warnings": { - "No warnings": "Uyarı yok" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "" - }, - "No widgets available": { - "No widgets available": "Kullanılabilir widget yok" - }, - "No widgets match your search": { - "No widgets match your search": "Aramanla eşleşen bir widget yok" - }, - "No window rules configured": { - "No window rules configured": "" - }, - "None": { - "None": "Hiçbiri" - }, - "Normal": { - "Normal": "Normal" - }, - "Normal Font": { - "Normal Font": "Normal Yazı Tipi" - }, - "Normal Priority": { - "Normal Priority": "Normal Öncelik" - }, - "Not available": { - "Not available": "Mevcut değil" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "" - }, - "Not connected": { - "Not connected": "Bağlı değil" - }, - "Not detected": { - "Not detected": "Algılanmadı" - }, - "Not paired": { - "Not paired": "" - }, - "Not set": { - "Not set": "" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "Not: Bu sadece yüzdeyi değiştirir, şarjı sınırlamaz." - }, - "Notepad": { - "Notepad": "Not Defteri" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "Not Defteri Yazı Tipi Ayarları" - }, - "Notepad Slideout": { - "Notepad Slideout": "Not Defteri Kaydırma" - }, - "Nothing": { - "Nothing": "" - }, - "Nothing to see here": { - "Nothing to see here": "Burada görülecek bir şey yok" - }, - "Notification Center": { - "Notification Center": "Bildirim Merkezi" - }, - "Notification Display": { - "Notification Display": "" - }, - "Notification Overlay": { - "Notification Overlay": "Bildirim Katmanı" - }, - "Notification Popups": { - "Notification Popups": "Bildirim Balonları" - }, - "Notification Rules": { - "Notification Rules": "" - }, - "Notification Settings": { - "Notification Settings": "Bildirim Ayarları" - }, - "Notification Timeouts": { - "Notification Timeouts": "Bildirim Zaman Aşımları" - }, - "Notification toast popups": { - "Notification toast popups": "Bildirim açılır pencereleri" - }, - "Notifications": { - "Notifications": "Bildirimler" - }, - "Numbers": { - "Numbers": "Numaralar" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "" - }, - "OK": { - "OK": "Tamam" - }, - "OS Logo": { - "OS Logo": "OS Logo" - }, - "OSD Position": { - "OSD Position": "OSD Pozisyonu" - }, - "Occupied Color": { - "Occupied Color": "" - }, - "Off": { - "Off": "Kapalı" - }, - "Office": { - "Office": "Ofis" - }, - "Offline": { - "Offline": "" - }, - "Offline Report": { - "Offline Report": "Çevrimdışı Rapor" - }, - "Older": { - "Older": "" - }, - "On": { - "On": "" - }, - "On-Demand": { - "On-Demand": "" - }, - "On-Screen Displays": { - "On-Screen Displays": "Ekran Üstü Gösterimler" - }, - "On-screen Displays": { - "On-screen Displays": "Ekran Gösterimleri" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "Gamayı yalnızca zaman veya konum kurallarına göre ayarlayın." - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "Her bir dock'ta yalnızca mevcut monitördeki pencereleri göster" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "Sisteminizde hazırda bekletme özelliği destekleniyorsa görünür" - }, - "Opacity": { - "Opacity": "Opaklık" - }, - "Opaque": { - "Opaque": "" - }, - "Open": { - "Open": "Aç" - }, - "Open App": { - "Open App": "" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "" - }, - "Open Notepad File": { - "Open Notepad File": "Not Defteri Dosyası Aç" - }, - "Open a new note": { - "Open a new note": "" - }, - "Open folder": { - "Open folder": "" - }, - "Open in Browser": { - "Open in Browser": "" - }, - "Open in terminal": { - "Open in terminal": "" - }, - "Open search bar to find text": { - "Open search bar to find text": "Metin bulmak için arama çubuğunu aç" - }, - "Open with...": { - "Open with...": "... ile aç" - }, - "Opening SMS": { - "Opening SMS": "" - }, - "Opening SMS app": { - "Opening SMS app": "" - }, - "Opening file browser": { - "Opening file browser": "" - }, - "Opening files": { - "Opening files": "" - }, - "Opening terminal: ": { - "Opening terminal: ": "" - }, - "Optional description": { - "Optional description": "Opsiyonel tanım" - }, - "Optional location": { - "Optional location": "Opsiyonel konum" - }, - "Options": { - "Options": "Seçenekler" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "" - }, - "Original: %1": { - "Original: %1": "" - }, - "Other": { - "Other": "Diğer" - }, - "Outline": { - "Outline": "" - }, - "Output": { - "Output": "" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "Çıkış Alanı Neredeyse Dolu" - }, - "Output Area Full": { - "Output Area Full": "Çıkış Alanı Dolu" - }, - "Output Device": { - "Output Device": "" - }, - "Output Devices": { - "Output Devices": "" - }, - "Output Tray Missing": { - "Output Tray Missing": "Çıktı Tepsisi Yok" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "Çıkış İçe Aktarımı Eksik" - }, - "Overcast": { - "Overcast": "" - }, - "Overflow": { - "Overflow": "" - }, - "Overridden by config": { - "Overridden by config": "Yapılandırma tarafından geçersiz kılınmıştır" - }, - "Override": { - "Override": "Geçersiz Kıl" - }, - "Override Border Size": { - "Override Border Size": "Kenar boyutunu geçersiz kıl" - }, - "Override Corner Radius": { - "Override Corner Radius": "Köşe Yarıçapını Değiştir" - }, - "Override Gaps": { - "Override Gaps": "Boşlukları Değiştir" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "Bu çıkış için genel düzen ayarlarını geçersiz kıl" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "" - }, - "Overrides": { - "Overrides": "Geçersiz Kılınanlar" - }, - "Overview": { - "Overview": "Genel Görünüm" - }, - "Overview of your network connections": { - "Overview of your network connections": "Ağ bağlantılarınızın genel görünümü" - }, - "Overwrite": { - "Overwrite": "Üstüne Yaz" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "" - }, - "PIN": { - "PIN": "PİN" - }, - "Pad": { - "Pad": "" - }, - "Pad Hours": { - "Pad Hours": "" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "" - }, - "Padding": { - "Padding": "Dolgu" - }, - "Pair": { - "Pair": "Eşle" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "Bluetooth Cihazı Eşleştir" - }, - "Paired": { - "Paired": "Eşleşti" - }, - "Pairing": { - "Pairing": "" - }, - "Pairing failed": { - "Pairing failed": "Eşleşme başarısız" - }, - "Pairing request from": { - "Pairing request from": "" - }, - "Pairing request sent": { - "Pairing request sent": "" - }, - "Pairing requested": { - "Pairing requested": "" - }, - "Pairing...": { - "Pairing...": "Eşleşiyor..." - }, - "Partly Cloudy": { - "Partly Cloudy": "" - }, - "Passkey:": { - "Passkey:": "Şifre:" - }, - "Password": { - "Password": "Parola" - }, - "Password...": { - "Password...": "" - }, - "Paste": { - "Paste": "" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "" - }, - "Pattern": { - "Pattern": "" - }, - "Pause": { - "Pause": "Duraklat" - }, - "Paused": { - "Paused": "Duraklatıldı" - }, - "Pending": { - "Pending": "Beklemede" - }, - "Pending Charge": { - "Pending Charge": "" - }, - "Pending Discharge": { - "Pending Discharge": "" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "Moda Özel Duvar Kağıtları" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "Monitöre Özel Duvar Kağıtları" - }, - "Per-screen config": { - "Per-screen config": "" - }, - "Percentage": { - "Percentage": "Yüzde" - }, - "Performance": { - "Performance": "" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "Profil resmi ayarlama izni reddedildi." - }, - "Personalization": { - "Personalization": "Kişiselleştirme" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "" - }, - "Phone number": { - "Phone number": "" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "" - }, - "Pictures": { - "Pictures": "" - }, - "Pin": { - "Pin": "Sabitle" - }, - "Pin to Dock": { - "Pin to Dock": "Dock'a Sabitle" - }, - "Ping": { - "Ping": "" - }, - "Ping sent": { - "Ping sent": "" - }, - "Ping sent to": { - "Ping sent to": "" - }, - "Pinned": { - "Pinned": "Sabitlendi" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "" - }, - "Pixelate": { - "Pixelate": "" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "Eklenti klasörlerini buraya yerleştirin. Her eklenti plugin.json manifest dosyasına sahip olmalı." - }, - "Place plugins in %1": { - "Place plugins in %1": "Eklentileri %1 konumuna yerleştirin" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "Yeni bildirim geldiğinde ses çal" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "Güç kablosu bağlandığında ses çal" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "Ses seviyesi ayarlandığında ses çal" - }, - "Play sounds for system events": { - "Play sounds for system events": "Sistem etkinlikleri için ses çal" - }, - "Playback": { - "Playback": "Oynatma" - }, - "Playback error: ": { - "Playback error: ": "" - }, - "Please wait...": { - "Please wait...": "" - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "" - }, - "Plugged In": { - "Plugged In": "Bağlandı" - }, - "Plugged in": { - "Plugged in": "Takılı" - }, - "Plugin": { - "Plugin": "Eklenti" - }, - "Plugin Directory": { - "Plugin Directory": "Eklenti Dizini" - }, - "Plugin Management": { - "Plugin Management": "Eklenti Yönetimi" - }, - "Plugin Visibility": { - "Plugin Visibility": "" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "Eklenti devre dışı - kullanmak için Eklenti ayarlarından etkinleştirin" - }, - "Plugins": { - "Plugins": "Eklentiler" - }, - "Pointer": { - "Pointer": "İşaretçi" - }, - "Popout Shadows": { - "Popout Shadows": "" - }, - "Popouts": { - "Popouts": "" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "" - }, - "Popup Only": { - "Popup Only": "" - }, - "Popup Position": { - "Popup Position": "Bildirim Pozisyonu" - }, - "Popup Shadow": { - "Popup Shadow": "" - }, - "Popup Transparency": { - "Popup Transparency": "Açılır Pencere Opaklığı" - }, - "Popup behavior, position": { - "Popup behavior, position": "" - }, - "Port": { - "Port": "" - }, - "Portal": { - "Portal": "" - }, - "Position": { - "Position": "Pozisyon" - }, - "Position, pinned apps": { - "Position, pinned apps": "" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "Olası Geçersiz Kılma Çakışmaları" - }, - "Power": { - "Power": "Güç" - }, - "Power & Security": { - "Power & Security": "Güç & Güvenlik" - }, - "Power & Sleep": { - "Power & Sleep": "Güç & Uyku" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "Güç Eylemi Onayı" - }, - "Power Menu Customization": { - "Power Menu Customization": "Güç Menüsü Özelleştirme" - }, - "Power Off": { - "Power Off": "Kapat" - }, - "Power Options": { - "Power Options": "Güç Ayarları" - }, - "Power Profile": { - "Power Profile": "Güç Profili" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "Güç Profili Dejenerasyonu" - }, - "Power Saver": { - "Power Saver": "" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "" - }, - "Power profile management available": { - "Power profile management available": "Güç profili yönetimi mevcut" - }, - "Power source": { - "Power source": "Güç kaynağı" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "" - }, - "Precip": { - "Precip": "" - }, - "Precipitation": { - "Precipitation": "" - }, - "Precipitation Chance": { - "Precipitation Chance": "Yağış Olasılığı" - }, - "Preference": { - "Preference": "Tercih" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "Ön Ayarlı Genişlik (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "" - }, - "Press key...": { - "Press key...": "Tuşa bas..." - }, - "Pressure": { - "Pressure": "Basınç" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "Ekran zaman aşımını önle" - }, - "Preview": { - "Preview": "" - }, - "Primary": { - "Primary": "Birincil" - }, - "Primary Container": { - "Primary Container": "" - }, - "Print Server Management": { - "Print Server Management": "Yazdırma Sunucusu Yönetimi" - }, - "Print Server not available": { - "Print Server not available": "Yazıcı Sunucusu Kullanılamıyor" - }, - "Printer": { - "Printer": "Yazıcı" - }, - "Printer Classes": { - "Printer Classes": "Yazıcı Sınıfları" - }, - "Printer created successfully": { - "Printer created successfully": "Yazıcı başarıyla oluşturuldu" - }, - "Printer deleted": { - "Printer deleted": "Yazıcı silindi" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "Yazıcı adı (boşluksuz)" - }, - "Printer reachable": { - "Printer reachable": "" - }, - "Printers": { - "Printers": "Yazıcılar" - }, - "Printers: ": { - "Printers: ": "Yazıcılar:" - }, - "Prioritize performance": { - "Prioritize performance": "" - }, - "Priority": { - "Priority": "" - }, - "Privacy Indicator": { - "Privacy Indicator": "Gizlilik Göstergesi" - }, - "Privacy Mode": { - "Privacy Mode": "" - }, - "Private Key Password": { - "Private Key Password": "Özel Anahtar Parolası" - }, - "Process Count": { - "Process Count": "Süreç Sayısı" - }, - "Processes": { - "Processes": "" - }, - "Processes:": { - "Processes:": "" - }, - "Processing": { - "Processing": "İşleniyor" - }, - "Profile Image Error": { - "Profile Image Error": "Profil Resmi Hatası" - }, - "Profile activated: %1": { - "Profile activated: %1": "" - }, - "Profile deleted": { - "Profile deleted": "" - }, - "Profile error": { - "Profile error": "" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "Profil resmi çok büyük. Lütfen daha küçük bir resim kullanın." - }, - "Profile name": { - "Profile name": "" - }, - "Profile not found": { - "Profile not found": "" - }, - "Profile saved: %1": { - "Profile saved: %1": "" - }, - "Protocol": { - "Protocol": "Protokol" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "" - }, - "Quick Access": { - "Quick Access": "" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "Uygulama başlatıcısına hızlı erişim" - }, - "Quick access to color picker": { - "Quick access to color picker": "Renk seçiciye hızlı erişim" - }, - "Quick access to notepad": { - "Quick access to notepad": "Not defterine hızlı erişim" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "Hızlı not alma sürgü paneli" - }, - "Quick system toggles": { - "Quick system toggles": "" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "" - }, - "Rain": { - "Rain": "" - }, - "Rain Chance": { - "Rain Chance": "Yağış İhtimali" - }, - "Rainbow": { - "Rainbow": "" - }, - "Random": { - "Random": "" - }, - "Rate": { - "Rate": "Oran" - }, - "Read:": { - "Read:": "" - }, - "Reason": { - "Reason": "Sebep" - }, - "Reboot": { - "Reboot": "Yeniden Başlat" - }, - "Recent Colors": { - "Recent Colors": "Son Renkler" - }, - "Recently Used Apps": { - "Recently Used Apps": "Son Kullanılan Uygulamalar" - }, - "Recommended available": { - "Recommended available": "Önerilen mevcut" - }, - "Refresh": { - "Refresh": "Yenile" - }, - "Refresh Weather": { - "Refresh Weather": "Hava Durumunu Yenile" - }, - "Regex": { - "Regex": "" - }, - "Reject": { - "Reject": "" - }, - "Reject Jobs": { - "Reject Jobs": "İşleri Reddet" - }, - "Release": { - "Release": "" - }, - "Reload Plugin": { - "Reload Plugin": "Eklentiyi Yeniden Yükle" - }, - "Remaining": { - "Remaining": "" - }, - "Remaining / Total": { - "Remaining / Total": "" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "" - }, - "Remember last user": { - "Remember last user": "" - }, - "Remove": { - "Remove": "Kaldır" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "Pencereler ekranı kapladığında boşlukları ve kenarlıkları kaldır" - }, - "Rename": { - "Rename": "" - }, - "Rename Session": { - "Rename Session": "" - }, - "Rename Workspace": { - "Rename Workspace": "" - }, - "Repeat": { - "Repeat": "" - }, - "Replacement": { - "Replacement": "" - }, - "Report": { - "Report": "Rapor" - }, - "Request Pairing": { - "Request Pairing": "" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "Güç kapatma, yeniden başlatma, askıya alma, hazırda bekletme ve oturumu kapatma işlemlerini onaylamak için düğmeyi/tuşu basılı tutmak gerekir" - }, - "Required plugin: ": { - "Required plugin: ": "" - }, - "Requires %1": { - "Requires %1": "" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "'dgop' aracını gerektirir" - }, - "Requires DMS %1": { - "Requires DMS %1": "DMS %1 gerektirir" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "DWL kompozitör gerektirir" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "Gece modu desteği gerektirir" - }, - "Reset": { - "Reset": "Sıfırla" - }, - "Reset Position": { - "Reset Position": "Pozisyonu Sıfırla" - }, - "Reset Size": { - "Reset Size": "Boyutu Sıfırla" - }, - "Reset to default name": { - "Reset to default name": "" - }, - "Resize Widget": { - "Resize Widget": "Widgetı Yeniden Boyutlandır" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "Çözünürlük ve Yenileme" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "" - }, - "Restart DMS": { - "Restart DMS": "DMS'yi Yeniden Başlat" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "DankMaterialShell'i yeniden başlatın" - }, - "Restarting audio system...": { - "Restarting audio system...": "" - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "" - }, - "Resume": { - "Resume": "Sürdür" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "Ters Kaydırma Yönü" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "Bar üzerinde kaydırırken çalışma alanı geçiş yönünü tersine çevir" - }, - "Revert": { - "Revert": "Geri Al" - }, - "Right": { - "Right": "Sağ" - }, - "Right Center": { - "Right Center": "" - }, - "Right Section": { - "Right Section": "Sağ Bölüm" - }, - "Right Tiling": { - "Right Tiling": "Sağ Döşeme" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "Widget'ın herhangi bir yerine sağ tıklayın ve sürükleyin." - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "Sağ tıklayın ve sağ alt köşeyi sürükleyin" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "Çubuk widget'ını sağ tıklayarak döngüye değiştir" - }, - "Ring": { - "Ring": "" - }, - "Ringing": { - "Ringing": "" - }, - "Ripple Effects": { - "Ripple Effects": "" - }, - "Root Filesystem": { - "Root Filesystem": "Kök Dosya Sistemi" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "Pencereler için yuvarlatılmış köşeler" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "" - }, - "Rule": { - "Rule": "" - }, - "Rule Name": { - "Rule Name": "" - }, - "Rules (%1)": { - "Rules (%1)": "" - }, - "Run Again": { - "Run Again": "" - }, - "Run DMS Templates": { - "Run DMS Templates": "DMS Şablonlarını Çalıştır" - }, - "Run User Templates": { - "Run User Templates": "Kullanıcı Şablonlarını Çalıştır" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "Program çalıştır (örn. firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "Shell komutu çalıştır (örn. notify-send)" - }, - "Running Apps": { - "Running Apps": "Çalışan Uygulamalar" - }, - "Running Apps Settings": { - "Running Apps Settings": "Çalışan Uygulamalar Ayarları" - }, - "Running greeter sync…": { - "Running greeter sync…": "" - }, - "SDR Brightness": { - "SDR Brightness": "SDR Parlaklık" - }, - "SDR Saturation": { - "SDR Saturation": "SDR Doygunluğu" - }, - "SMS": { - "SMS": "" - }, - "Save": { - "Save": "Kaydet" - }, - "Save Notepad File": { - "Save Notepad File": "Not Defteri Dosyasını Kaydet" - }, - "Save QR Code": { - "Save QR Code": "" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "" - }, - "Save password": { - "Save password": "Parolayı kaydet" - }, - "Saved": { - "Saved": "Kaydedildi" - }, - "Saved Configurations": { - "Saved Configurations": "Kaydedilen Yapılandırmalar" - }, - "Saved Note": { - "Saved Note": "" - }, - "Saved item deleted": { - "Saved item deleted": "" - }, - "Saving...": { - "Saving...": "" - }, - "Scale": { - "Scale": "Ölçek" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "DankBar yazı tipi boyutlarını bağımsız olarak ölçeklendir" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "Kabuk genelinde tüm yazı tipi boyutlarını ölçeklendir" - }, - "Scan": { - "Scan": "Tara" - }, - "Scanning": { - "Scanning": "Taranıyor" - }, - "Scanning...": { - "Scanning...": "Taranıyor..." - }, - "Science": { - "Science": "Bilim" - }, - "Score": { - "Score": "" - }, - "Screen Sharing": { - "Screen Sharing": "" - }, - "Screen sharing": { - "Screen sharing": "Ekran paylaşımı" - }, - "Scroll": { - "Scroll": "" - }, - "Scroll Factor": { - "Scroll Factor": "" - }, - "Scroll GitHub": { - "Scroll GitHub": "" - }, - "Scroll Wheel": { - "Scroll Wheel": "Kaydırma Tekerleği" - }, - "Scroll song title": { - "Scroll song title": "Şarkı başlığını kaydır" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "Widget'a sığmazsa başlığı kaydırın" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "" - }, - "Scrolling": { - "Scrolling": "Kaydırma" - }, - "Search App Actions": { - "Search App Actions": "" - }, - "Search Options": { - "Search Options": "" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "" - }, - "Search for a location...": { - "Search for a location...": "Bir konum ara..." - }, - "Search keybinds...": { - "Search keybinds...": "Tuş kombinasyonları ara..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "" - }, - "Search plugins...": { - "Search plugins...": "Eklentileri ara..." - }, - "Search processes...": { - "Search processes...": "" - }, - "Search sessions...": { - "Search sessions...": "" - }, - "Search themes...": { - "Search themes...": "Tema ara..." - }, - "Search widgets...": { - "Search widgets...": "Widget ara..." - }, - "Search...": { - "Search...": "Ara..." - }, - "Searching...": { - "Searching...": "Arıyor..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "" - }, - "Secondary": { - "Secondary": "İkincil" - }, - "Secured": { - "Secured": "Güvenli" - }, - "Security": { - "Security": "Güvenlik" - }, - "Security & privacy": { - "Security & privacy": "" - }, - "Security key mode": { - "Security key mode": "" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "" - }, - "Select": { - "Select": "" - }, - "Select Application": { - "Select Application": "Uygulama Seç" - }, - "Select Bar": { - "Select Bar": "Bar Seç" - }, - "Select Custom Theme": { - "Select Custom Theme": "Özel Tema Seç" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "" - }, - "Select File to Send": { - "Select File to Send": "" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "Başlatıcı Logosu Seç" - }, - "Select Profile Image": { - "Select Profile Image": "Profil Resmi Seç" - }, - "Select Video or Folder": { - "Select Video or Folder": "" - }, - "Select Wallpaper": { - "Select Wallpaper": "Duvar Kağıdı Seç" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "Duvar Kağıdı Dizinini Seç" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "Paletten bir renk seç veya özel kaydırıcıları kullan" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "Masaüstünüze eklemek için bir widget seçin. Her widget, kendi ayarları olan ayrı bir örnektir." - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "Eklemek için bir widget seçin. Gerekirse aynı widget'ın birden fazla örneğini ekleyebilirsiniz." - }, - "Select a window...": { - "Select a window...": "" - }, - "Select an image file...": { - "Select an image file...": "Bir resim dosyası seçin..." - }, - "Select at least one provider": { - "Select at least one provider": "" - }, - "Select device": { - "Select device": "" - }, - "Select device...": { - "Select device...": "Aygıt seç..." - }, - "Select driver...": { - "Select driver...": "Sürücü seç..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "Arayüz metni için yazı tipi kalınlığını seç" - }, - "Select greeter background image": { - "Select greeter background image": "" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "Duvar kağıdını ayarlamak için monitör seçin" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "Süreç listesi ve teknik göstergeler için sabit aralıklı yazı tipi seçin" - }, - "Select network": { - "Select network": "" - }, - "Select system sound theme": { - "Select system sound theme": "Sistem ses temasını seç" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "Arayüz metni için yazı tipi ailesini seç" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "Duvar kağıdı tabanlı renkler için kullanılan palet algoritmasını seçin" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "Rastgele seçime dahil edilecek geçişleri seçin" - }, - "Select...": { - "Select...": "Seç..." - }, - "Selected image file not found.": { - "Selected image file not found.": "Seçilen resim dosyası bulunamadı." - }, - "Send": { - "Send": "" - }, - "Send Clipboard": { - "Send Clipboard": "" - }, - "Send File": { - "Send File": "" - }, - "Send SMS": { - "Send SMS": "" - }, - "Sending": { - "Sending": "" - }, - "Separator": { - "Separator": "Ayraç" - }, - "Server": { - "Server": "Sunucu" - }, - "Session Filter": { - "Session Filter": "" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "" - }, - "Set custom name": { - "Set custom name": "" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "Bağlı her monitör için farklı duvar kağıtları ayarlayın" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "Karanlık ve aydınlık mod için farklı duvar kağıtları ayarlayın" - }, - "Set key and action to save": { - "Set key and action to save": "Kaydetmek için tuş ve eylem ayarlayın" - }, - "Set notification rules": { - "Set notification rules": "" - }, - "Settings": { - "Settings": "Ayarlar" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "" - }, - "Setup": { - "Setup": "Kurulum" - }, - "Shadow Color": { - "Shadow Color": "" - }, - "Shadow Intensity": { - "Shadow Intensity": "" - }, - "Shadow Opacity": { - "Shadow Opacity": "" - }, - "Shadow Override": { - "Shadow Override": "" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "" - }, - "Shadows": { - "Shadows": "" - }, - "Share": { - "Share": "" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "" - }, - "Share Text": { - "Share Text": "" - }, - "Share URL": { - "Share URL": "" - }, - "Shared": { - "Shared": "" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: Tümünü Temizle • Esc: Kapat" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter: Yapıştır • Shift+Del: Tümünü Temizle • Esc: Kapat" - }, - "Short": { - "Short": "Kısa" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "" - }, - "Shortcuts": { - "Shortcuts": "Kısayollar" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "Kısayollar (%1)" - }, - "Show": { - "Show": "" - }, - "Show 3rd Party": { - "Show 3rd Party": "" - }, - "Show All Tags": { - "Show All Tags": "Tüm Etiketleri Göster" - }, - "Show Badge": { - "Show Badge": "" - }, - "Show CPU": { - "Show CPU": "CPU'yu Göster" - }, - "Show CPU Graph": { - "Show CPU Graph": "CPU Grafiğini Göster" - }, - "Show CPU Temp": { - "Show CPU Temp": "CPU Sıcaklığını Göster" - }, - "Show Date": { - "Show Date": "Tarihi Göster" - }, - "Show Disk": { - "Show Disk": "Diski Göster" - }, - "Show Dock": { - "Show Dock": "Dock'u Göster" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "" - }, - "Show Footer": { - "Show Footer": "" - }, - "Show Forecast": { - "Show Forecast": "" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "GPU Sıcaklığını Göster" - }, - "Show Header": { - "Show Header": "Başlığı Göster" - }, - "Show Hibernate": { - "Show Hibernate": "Hazırda Bekleti Göster" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "Saat Numaralarını Göster" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "" - }, - "Show Humidity": { - "Show Humidity": "" - }, - "Show Launcher Button": { - "Show Launcher Button": "" - }, - "Show Line Numbers": { - "Show Line Numbers": "Satır Numaralarını Göster" - }, - "Show Location": { - "Show Location": "" - }, - "Show Lock": { - "Show Lock": "Kilitleyi Göster" - }, - "Show Log Out": { - "Show Log Out": "Çıkışı Göster" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "" - }, - "Show Media Player": { - "Show Media Player": "" - }, - "Show Memory": { - "Show Memory": "Belleği Göster" - }, - "Show Memory Graph": { - "Show Memory Graph": "Bellek Grafiğini Göster" - }, - "Show Memory in GB": { - "Show Memory in GB": "" - }, - "Show Network": { - "Show Network": "Ağı Göster" - }, - "Show Network Graph": { - "Show Network Graph": "Ağ Grafiğini Göster" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "Sadece Dolu Çalışma Alanlarını Göster" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "" - }, - "Show Password Field": { - "Show Password Field": "Parola Alanını Göster" - }, - "Show Power Actions": { - "Show Power Actions": "Güç Eylemlerini Göster" - }, - "Show Power Off": { - "Show Power Off": "Kapatı Göster" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "" - }, - "Show Pressure": { - "Show Pressure": "" - }, - "Show Profile Image": { - "Show Profile Image": "Profil Fotoğrafını Göster" - }, - "Show Reboot": { - "Show Reboot": "Yeniden Başlatı Göster" - }, - "Show Restart DMS": { - "Show Restart DMS": "DMS'yi Yeniden Başlatı Göster" - }, - "Show Saved Items": { - "Show Saved Items": "" - }, - "Show Seconds": { - "Show Seconds": "Saniyeleri Göster" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "" - }, - "Show Suspend": { - "Show Suspend": "Askıya Alı Göster" - }, - "Show Swap": { - "Show Swap": "" - }, - "Show System Date": { - "Show System Date": "Sistem Tarihini Göster" - }, - "Show System Icons": { - "Show System Icons": "Sistem Simgelerini Göster" - }, - "Show System Time": { - "Show System Time": "Sistem Zamanını Göster" - }, - "Show Top Processes": { - "Show Top Processes": "En Üst İşlemleri Göster" - }, - "Show Weather Condition": { - "Show Weather Condition": "" - }, - "Show Week Number": { - "Show Week Number": "" - }, - "Show Welcome": { - "Show Welcome": "" - }, - "Show Wind Speed": { - "Show Wind Speed": "" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "Çalışma Alanı Uygulamalarını Göster" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "Sadece dolu etiketleri değil, tüm 9 etiketi göster (sadece DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "Medya widget'ında cava ses görselleştiricisini göster" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "Modal diyalogların arkasında karartılmış kaplama göster" - }, - "Show device": { - "Show device": "" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "" - }, - "Show in GB": { - "Show in GB": "" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "Niri genel görünümde yazarken başlatıcı katmanını göster. Başka bir başlatıcı kullanmak için devre dışı bırakın." - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "" - }, - "Show on Last Display": { - "Show on Last Display": "Son Ekranda Göster" - }, - "Show on Overlay": { - "Show on Overlay": "Katmanda Göster" - }, - "Show on Overview": { - "Show on Overview": "Genel Görünümde Göster" - }, - "Show on Overview Only": { - "Show on Overview Only": "" - }, - "Show on all connected displays": { - "Show on all connected displays": "Tüm bağlı ekranlarda göster" - }, - "Show on screens:": { - "Show on screens:": "Şu ekranda göster:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "Parlaklık değiştiğinde ekran gösterimi göster" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "Caps lock durumu değiştiğinde ekran gösterimi göster" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "Ses çıkış cihazları arasında geçiş yaparken ekran gösterimi göster" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "Boşta kalma engelleyici durumu değiştiğinde ekran gösterimi göster" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "Medya oynatıcının ses seviyesi değiştiğinde ekran üstü görüntü göster" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "Mikrofon sessize alındığında/sessizden çıkarıldığında ekran gösterimi göster" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "Güç profili değiştiğinde ekran gösterimi göster" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "Ses değiştiğinde ekran gösterimi göster" - }, - "Show seconds": { - "Show seconds": "" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "Üst çubuk ve kontrol merkezinde hava durumu bilgisini göster" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "Üst çubuktaki çalışma alanı değiştiricide çalışma alanı dizin numaralarını göster" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "Odak göstergesiyle çalışan tüm uygulamaları gösterir" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "Mevcut çalışma alanı gösterir ve değiştirmeye izin verir" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "Caps Lock tuşunun etkin olduğunu gösterir" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "Mikrofon, kamera veya ekran paylaşımı aktif olduğunda gösterir" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "Kapat" - }, - "Signal": { - "Signal": "Sinyal" - }, - "Signal:": { - "Signal:": "Sinyal:" - }, - "Size": { - "Size": "Boyut" - }, - "Size Constraints": { - "Size Constraints": "" - }, - "Size Offset": { - "Size Offset": "Boyut Ofseti" - }, - "Sizing": { - "Sizing": "Boyutlandırma" - }, - "Skip": { - "Skip": "" - }, - "Skip confirmation": { - "Skip confirmation": "" - }, - "Skip setup": { - "Skip setup": "" - }, - "Small": { - "Small": "" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "" - }, - "Smartcard PIN": { - "Smartcard PIN": "" - }, - "Snap": { - "Snap": "" - }, - "Snow": { - "Snow": "" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "Bazı eklentiler daha yeni bir DMS sürümü gerektirir:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "Alfabetik Olarak Sırala" - }, - "Sort By": { - "Sort By": "Şuna Göre Sırala" - }, - "Sorting & Layout": { - "Sorting & Layout": "Sıralama & Düzen" - }, - "Sound Theme": { - "Sound Theme": "Ses Teması" - }, - "Sounds": { - "Sounds": "Sesler" - }, - "Space between windows": { - "Space between windows": "Pencereler arası boşluk" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "" - }, - "Spacer": { - "Spacer": "Boşluklandırıcı" - }, - "Spacing": { - "Spacing": "Boşluk" - }, - "Speaker settings": { - "Speaker settings": "Hoparlör ayarları" - }, - "Speed": { - "Speed": "Hız" - }, - "Spool Area Full": { - "Spool Area Full": "Aktarım Alanı Dolu" - }, - "Square Corners": { - "Square Corners": "Kare Köşeler" - }, - "Stacked": { - "Stacked": "Yığılmış" - }, - "Standard": { - "Standard": "" - }, - "Start": { - "Start": "Başlat" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "Notunuzu buraya yazmaya başlayın..." - }, - "State": { - "State": "Durum" - }, - "Status": { - "Status": "Durum" - }, - "Stopped": { - "Stopped": "Durduruldu" - }, - "Stopped Partly": { - "Stopped Partly": "Kısmen Durduruldu" - }, - "Stopping": { - "Stopping": "Durduruluyor" - }, - "Stretch": { - "Stretch": "" - }, - "Stripes": { - "Stripes": "" - }, - "Summary": { - "Summary": "" - }, - "Sunrise": { - "Sunrise": "Gündoğumu" - }, - "Sunset": { - "Sunset": "Günbatımı" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "Ekinken bildirim açılır pencerelerini bastır" - }, - "Surface": { - "Surface": "Yüzey" - }, - "Surface Variant": { - "Surface Variant": "" - }, - "Suspend": { - "Suspend": "Askıya Al" - }, - "Suspend behavior": { - "Suspend behavior": "Askıya alma davranışı" - }, - "Suspend system after": { - "Suspend system after": "Şu zaman sonra askıya al" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "" - }, - "Sway Website": { - "Sway Website": "" - }, - "Switch User": { - "Switch User": "Kullanıcı Değiştir" - }, - "Switch to power profile": { - "Switch to power profile": "Güç profiline geç" - }, - "Sync": { - "Sync": "" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "Modu Portal ile Eşitle" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "Sistem genelindeki tema ipuçları için karanlık modu ayar portalları ile senkronize et" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "" - }, - "System": { - "System": "Sistem" - }, - "System App Theming": { - "System App Theming": "Sistem Uygulama Teması" - }, - "System Check": { - "System Check": "" - }, - "System Default": { - "System Default": "" - }, - "System Information": { - "System Information": "" - }, - "System Monitor": { - "System Monitor": "Sistem Monitörü" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "Sistem Monitörü Kullanılamıyor" - }, - "System Sounds": { - "System Sounds": "Sistem Sesleri" - }, - "System Tray": { - "System Tray": "Sistem Tepsisi" - }, - "System Update": { - "System Update": "Sistem Güncelleme" - }, - "System Updater": { - "System Updater": "Sistem Güncelleyici" - }, - "System Updates": { - "System Updates": "Sistem Güncellemeleri" - }, - "System notification area icons": { - "System notification area icons": "Sistem bildirim alanı simgeleri" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "" - }, - "System theme toggle": { - "System theme toggle": "Sistem teması geçişi" - }, - "System toast notifications": { - "System toast notifications": "Sistem anlık bildirimleri" - }, - "System update custom command": { - "System update custom command": "Sistem güncelleme özel komutu" - }, - "Tab": { - "Tab": "Sekme" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Yön • ←→↑↓: Izgara Yönü • Enter/Space: Seç" - }, - "Terminal": { - "Terminal": "" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "Terminal özel ek parametreleri" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "Terminaller - Her zaman Karanlı Tema kullan" - }, - "Test Connection": { - "Test Connection": "" - }, - "Test Page": { - "Test Page": "Test Sayfası" - }, - "Test page sent to printer": { - "Test page sent to printer": "Test Sayfası yazıcıya gönderildi" - }, - "Testing...": { - "Testing...": "" - }, - "Text": { - "Text": "Metin" - }, - "Text Color": { - "Text Color": "" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "DMS_SOCKET ortam değişkeni ayarlanmamış veya soket kullanılamıyor. Otomatik eklenti yönetimi için DMS_SOCKET gereklidir." - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "Aşağıdaki ayarlar GTK ve Qt ayarlarınızı değiştirecektir. Mevcut yapılandırmalarınızı korumak istiyorsanız, lütfen yedekleyin (qt5ct.conf|qt6ct.conf ve ~/.config/gtk-3.0|gtk-4.0)." - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "Bu yazıcının iş kuyruğu boş" - }, - "Theme & Colors": { - "Theme & Colors": "Tema & Renkler" - }, - "Theme Color": { - "Theme Color": "Tema Rengi" - }, - "Theme Registry": { - "Theme Registry": "" - }, - "Themes": { - "Themes": "" - }, - "Thickness": { - "Thickness": "Kalınlık" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "Üçüncü Taraf Eklenti Uyarısı" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "Bu bağ, config.kdl tarafından geçersiz kılındı." - }, - "This may take a few seconds": { - "This may take a few seconds": "" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "Bu widget, dizüstü bilgisayarlarda pil ömrünü önemli ölçüde etkileyebilen GPU güç kapatma durumlarını önler. Hibrit grafik kartına sahip dizüstü bilgisayarlarda kullanılması önerilmez." - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "Bu, tüm pano geçmişini kalıcı olarak siler." - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "" - }, - "Thunderstorm": { - "Thunderstorm": "" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "" - }, - "Tile": { - "Tile": "" - }, - "Tile H": { - "Tile H": "" - }, - "Tile V": { - "Tile V": "" - }, - "Tiled": { - "Tiled": "" - }, - "Tiled State": { - "Tiled State": "" - }, - "Tiling": { - "Tiling": "Döşeme" - }, - "Time": { - "Time": "" - }, - "Time & Date Locale": { - "Time & Date Locale": "" - }, - "Time & Weather": { - "Time & Weather": "Zaman & Hava Durumu" - }, - "Time Format": { - "Time Format": "Zaman Biçimi" - }, - "Time format": { - "Time format": "" - }, - "Time remaining: %1": { - "Time remaining: %1": "Kalan zaman: %1" - }, - "Time until full: %1": { - "Time until full: %1": "Dolmasına kalan: %1" - }, - "Timed Out": { - "Timed Out": "Zaman Aşımı" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "Kritik öncelikli bildirimler için zaman aşımı" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "Düşük öncelikli bildirimler için zaman aşımı" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "Normal öncelikli bildirimler için zaman aşımı" - }, - "Title": { - "Title": "Başlık" - }, - "Title regex (optional)": { - "Title regex (optional)": "" - }, - "To Full": { - "To Full": "Dolmasına" - }, - "To update, run the following command:": { - "To update, run the following command:": "Güncellemek için aşağıdaki komutu çalıştırın:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "Bu DMS bağlamasını kullanmak için, config.kdl dosyanızdaki tuş bağlamasını kaldırın veya değiştirin." - }, - "Toast Messages": { - "Toast Messages": "Anlık Bildirimler" - }, - "Today": { - "Today": "Bugün" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "Bu bar yapılandırmasının görünürlüğünü değiştir" - }, - "Toggling...": { - "Toggling...": "Geçiş yapılıyor..." - }, - "Tomorrow": { - "Tomorrow": "Yarın" - }, - "Tonal Spot": { - "Tonal Spot": "" - }, - "Toner Empty": { - "Toner Empty": "Toner Boş" - }, - "Toner Low": { - "Toner Low": "Toner Az" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "" - }, - "Tools": { - "Tools": "" - }, - "Top": { - "Top": "Üst" - }, - "Top (Default)": { - "Top (Default)": "" - }, - "Top Bar Format": { - "Top Bar Format": "Üst Çubuk Biçimi" - }, - "Top Center": { - "Top Center": "" - }, - "Top Left": { - "Top Left": "Üst Sol" - }, - "Top Processes": { - "Top Processes": "En Üst İşlemler" - }, - "Top Right": { - "Top Right": "Üst Sağ" - }, - "Top Section": { - "Top Section": "Üst Bölüm" - }, - "Total": { - "Total": "" - }, - "Total Jobs": { - "Total Jobs": "Toplam İşler" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "Dönüştür" - }, - "Transition Effect": { - "Transition Effect": "Geçiş Efekti" - }, - "Transparency": { - "Transparency": "Transparanlık" - }, - "Trending GIFs": { - "Trending GIFs": "" - }, - "Trending Stickers": { - "Trending Stickers": "" - }, - "Trigger": { - "Trigger": "" - }, - "Trigger Prefix": { - "Trigger Prefix": "" - }, - "Trigger: %1": { - "Trigger: %1": "" - }, - "Trust": { - "Trust": "" - }, - "Try a different search": { - "Try a different search": "" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "" - }, - "Turn off monitors after": { - "Turn off monitors after": "Şu zaman sonra monitörleri kapat" - }, - "Type": { - "Type": "Tip" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "" - }, - "Type to search files": { - "Type to search files": "" - }, - "Typography": { - "Typography": "Tipografi" - }, - "Typography & Motion": { - "Typography & Motion": "Tipografi & Hareket" - }, - "Unavailable": { - "Unavailable": "Mevcut Değil" - }, - "Unfocused Color": { - "Unfocused Color": "" - }, - "Ungrouped": { - "Ungrouped": "" - }, - "Uninstall": { - "Uninstall": "Kaldır" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "Eklentiyi Kaldır" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "Kaldırma başarısız: %1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "Kaldırıldı: %1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "Kaldırılıyor: %1" - }, - "Unknown": { - "Unknown": "Bilinmeyen" - }, - "Unknown App": { - "Unknown App": "" - }, - "Unknown Artist": { - "Unknown Artist": "" - }, - "Unknown Config": { - "Unknown Config": "Bilinmeyen Yapılandırma" - }, - "Unknown Device": { - "Unknown Device": "Bilinmeyen Cihaz" - }, - "Unknown GPU": { - "Unknown GPU": "" - }, - "Unknown Monitor": { - "Unknown Monitor": "Bilinmeyen Monitör" - }, - "Unknown Network": { - "Unknown Network": "Bilinmeyen Ağ" - }, - "Unknown Title": { - "Unknown Title": "" - }, - "Unknown Track": { - "Unknown Track": "" - }, - "Unload on Close": { - "Unload on Close": "" - }, - "Unmute": { - "Unmute": "" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "" - }, - "Unnamed Rule": { - "Unnamed Rule": "" - }, - "Unpair": { - "Unpair": "" - }, - "Unpair failed": { - "Unpair failed": "" - }, - "Unpin": { - "Unpin": "" - }, - "Unpin from Dock": { - "Unpin from Dock": "Dock'tan Sabitlemeyi Kaldır" - }, - "Unsaved Changes": { - "Unsaved Changes": "Kaydedilmemiş Değişiklikler" - }, - "Unsaved changes": { - "Unsaved changes": "Kaydedilmemiş değişiklikler" - }, - "Unsaved note...": { - "Unsaved note...": "Kaydedilmemiş not..." - }, - "Untitled": { - "Untitled": "Başlıksız" - }, - "Untrust": { - "Untrust": "" - }, - "Up to date": { - "Up to date": "" - }, - "Update": { - "Update": "" - }, - "Update All": { - "Update All": "Tümünü Güncelle" - }, - "Update Plugin": { - "Update Plugin": "Eklentiyi Güncelle" - }, - "Uptime": { - "Uptime": "" - }, - "Uptime:": { - "Uptime:": "" - }, - "Urgent Color": { - "Urgent Color": "" - }, - "Usage Tips": { - "Usage Tips": "" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "12 saatlik ÖÖ/ÖS yerine 24 saatlik zaman formatını kullanın." - }, - "Use Custom Command": { - "Use Custom Command": "Özel Komut Kullan" - }, - "Use Grid Layout": { - "Use Grid Layout": "Izgara Düzeni Kullan" - }, - "Use IP Location": { - "Use IP Location": "IP Konumunu Kullan" - }, - "Use Imperial Units": { - "Use Imperial Units": "İngiliz Ölçü Birimini Kullan" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Metrik birimler (°C, km/h, hPa) yerine İngiliz birimleri (°F, mph, inHg) kullan" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "Sabit Aralıklı Yazı Tipi Kullan" - }, - "Use System Theme": { - "Use System Theme": "Sistem Temasını Kullan" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "Swww, hyprpaper veya swaybg gibi harici bir duvar kağıdı yöneticisi kullan" - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "Medya oynatımı için animasyonlu dalga ilerleme çubukları kullanın" - }, - "Use custom border size": { - "Use custom border size": "" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "Sistemi güncellemek için özel komut kullan" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "Bar aralığı yerine özel boşluklar kullanın" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "Tema yarıçapı yerine özel pencere yarıçapı kullanın" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "Karanlık tema yerine aydınlık tema kullan" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "Sistem ayarlarındaki ses temasını kullan" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "" - }, - "User": { - "User": "Kullanıcı" - }, - "Username": { - "Username": "Kullanıcı Adı" - }, - "Username...": { - "Username...": "" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "Gün doğumu/batımı saatlerini kullanarak konumunuza göre gece modunu otomatik olarak ayarlar." - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "" - }, - "Utilities": { - "Utilities": "Araçlar" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN Bağlantıları" - }, - "VPN Password": { - "VPN Password": "VPN Parolası" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN ayarı güncellendi" - }, - "VPN connections": { - "VPN connections": "VPN bağlantıları" - }, - "VPN deleted": { - "VPN deleted": "VPN silindi" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN içe aktarıldı: %1" - }, - "VPN not available": { - "VPN not available": "VPN mevcut değil" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN durumu ve hızlı bağlanma" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "" - }, - "VRR On-Demand": { - "VRR On-Demand": "Talep üzerine VRR" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "Değişken Yenileme Hızı" - }, - "Verification": { - "Verification": "" - }, - "Version": { - "Version": "Sürüm" - }, - "Vertical Deck": { - "Vertical Deck": "Dikey Deck" - }, - "Vertical Grid": { - "Vertical Grid": "Dikey Izgara" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "Dikey Kaydırma" - }, - "Vertical Tiling": { - "Vertical Tiling": "Dikey Döşeme" - }, - "Vibrant": { - "Vibrant": "" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "Oynak doygunluğa sahip canlı palet" - }, - "Video Path": { - "Video Path": "" - }, - "Video Screensaver": { - "Video Screensaver": "" - }, - "Videos": { - "Videos": "" - }, - "View Mode": { - "View Mode": "" - }, - "Visibility": { - "Visibility": "Görüş" - }, - "Visual Effects": { - "Visual Effects": "" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "Widget'lar arası görsel ayırıcı" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "Duvar kağıdı değiştiğinde kullanılan görsel efekt" - }, - "Volume": { - "Volume": "Ses" - }, - "Volume Changed": { - "Volume Changed": "Ses Seviyesi Değişti" - }, - "Volume Slider": { - "Volume Slider": "Ses Seviyesi Kaydırıcı" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "Ses, parlaklık ve diğer sistem ekran üstü gösterimleri" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "Duvar Kağıdı" - }, - "Wallpaper Error": { - "Wallpaper Error": "Duvar Kağıdı Hatası" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "Duvar Kağıdı Monitörü" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "Duvar kağıdı işleme başarısız oldu" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "Duvar kağıdı işleme başarısız - duvar kağıdı yolunu kontrol edin" - }, - "Wallpapers": { - "Wallpapers": "Duvar Kağıtları" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "Uygulanacak sıcak renk sıcaklığı" - }, - "Warning": { - "Warning": "Uyarı" - }, - "Warnings": { - "Warnings": "" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "Dalga İlerleme Çubukları" - }, - "Weather": { - "Weather": "Hava Durumu" - }, - "Weather Widget": { - "Weather Widget": "Hava Durumu Widget'ı" - }, - "Welcome": { - "Welcome": "" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Etkinleştirildiğinde, uygulamalar alfabetik olarak sıralanır. Devre dışı bırakıldığında, uygulamalar kullanım sıklığına göre sıralanır." - }, - "When locked": { - "When locked": "" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "Güncelleyici widgetı kullanıldığında, güncelleme bulunmazsa gizle" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi Parolası" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi ve Ethernet bağlantısı" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi mevcut değil" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "WiFi Aygıtı" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "" - }, - "WiFi disabled": { - "WiFi disabled": "WiFi devre dışı" - }, - "WiFi enabled": { - "WiFi enabled": "WiFi etkin" - }, - "WiFi is off": { - "WiFi is off": "WiFi kapalı" - }, - "WiFi off": { - "WiFi off": "" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "Geniş (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "Widget Arkaplan Rengi" - }, - "Widget Management": { - "Widget Management": "Widget Yönetimi" - }, - "Widget Outline": { - "Widget Outline": "Widget Çerçevesi" - }, - "Widget Style": { - "Widget Style": "Widget Stili" - }, - "Widget Styling": { - "Widget Styling": "Widget Stili" - }, - "Widget Transparency": { - "Widget Transparency": "Widget Opaklığı" - }, - "Widget added": { - "Widget added": "Widget eklendi" - }, - "Widget removed": { - "Widget removed": "Widget kaldırıldı" - }, - "Widgets": { - "Widgets": "Widgetlar" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "" - }, - "Width": { - "Width": "" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "" - }, - "Wind": { - "Wind": "Rüzgar" - }, - "Wind Speed": { - "Wind Speed": "Rüzgar hızı" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "" - }, - "Window Corner Radius": { - "Window Corner Radius": "Pencere Köşe Yarıçapı" - }, - "Window Gaps": { - "Window Gaps": "Pencere Boşlukları" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "Pencere Boşlukları (px)" - }, - "Window Height": { - "Window Height": "" - }, - "Window Opening": { - "Window Opening": "" - }, - "Window Rounding": { - "Window Rounding": "" - }, - "Window Rules": { - "Window Rules": "" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "" - }, - "Wipe": { - "Wipe": "" - }, - "Workspace": { - "Workspace": "Çalışma Alanı" - }, - "Workspace Appearance": { - "Workspace Appearance": "" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "Çalışma Alanı Sıra Numarası" - }, - "Workspace Names": { - "Workspace Names": "" - }, - "Workspace Padding": { - "Workspace Padding": "Çalışma Alanı Dolgusu" - }, - "Workspace Settings": { - "Workspace Settings": "Çalışma Alanı Ayarları" - }, - "Workspace Switcher": { - "Workspace Switcher": "Çalışma Alanı Değiştirici" - }, - "Workspace name": { - "Workspace name": "" - }, - "Workspaces": { - "Workspaces": "Çalışma Alanları" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "Çalışma Alanları & Widgetlar" - }, - "Write:": { - "Write:": "" - }, - "X Axis": { - "X Axis": "X Ekseni" - }, - "Y Axis": { - "Y Axis": "Y Ekseni" - }, - "Yes": { - "Yes": "Evet" - }, - "Yesterday": { - "Yesterday": "" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "Kaydedilmemiş değişiklikleriniz var. Sekmeyi kapatmadan önce kaydedelim mi?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "Kaydedilmemiş değişiklikleriniz var. Devam etmeden önce kaydedelim mi?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "Kaydedilmemiş değişiklikleriniz var. Yeni dosya oluşturmadan önce kaydedelim mi?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "Kaydedilmemiş değişiklikleriniz var. Yeni dosya açmadan önce kaydedelim mi?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "" - }, - "You're All Set!": { - "You're All Set!": "" - }, - "Your system is up to date!": { - "Your system is up to date!": "" - }, - "actions": { - "actions": "" - }, - "attached": { - "attached": "" - }, - "brandon": { - "brandon": "" - }, - "by %1": { - "by %1": "%1 tarafından" - }, - "days": { - "days": "gün" - }, - "detached": { - "detached": "" - }, - "device": { - "device": "" - }, - "devices connected": { - "devices connected": "" - }, - "dgop not available": { - "dgop not available": "dgop mevcut değil" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/outputs yapılandırması mevcut ancak kompozitör yapılandırmanıza dahil edilmemiş. Ekran değişiklikleri kalıcı olmayacaktır." - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "örn. firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "örn. focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "Örneğin, notify-send 'Merhaba' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "" - }, - "events": { - "events": "etkinlikler" - }, - "ext": { - "ext": "" - }, - "featured": { - "featured": "" - }, - "leave empty for default": { - "leave empty for default": "Varsayılanlar için boş bırakın" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl kullanılabilir değil - kilit entegrasyonu DMS soket bağlantısı gerektirir" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "" - }, - "mangowc GitHub": { - "mangowc GitHub": "" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "matugen bulunamadı - dinamik tema için matugen paketini yükleyin" - }, - "minutes": { - "minutes": "dakika" - }, - "ms": { - "ms": "ms" - }, - "nav": { - "nav": "" - }, - "niri GitHub": { - "niri GitHub": "" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "" - }, - "niri shortcuts config": { - "niri shortcuts config": "" - }, - "niri/dms Discord": { - "niri/dms Discord": "" - }, - "now": { - "now": "" - }, - "official": { - "official": "resmi" - }, - "on Hyprland": { - "on Hyprland": "" - }, - "on MangoWC": { - "on MangoWC": "" - }, - "on Miracle WM": { - "on Miracle WM": "" - }, - "on Niri": { - "on Niri": "" - }, - "on Scroll": { - "on Scroll": "" - }, - "on Sway": { - "on Sway": "" - }, - "open": { - "open": "" - }, - "or run ": { - "or run ": "" - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "" - }, - "procs": { - "procs": "" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "" - }, - "seconds": { - "seconds": "saniye" - }, - "source": { - "source": "kaynak" - }, - "this app": { - "this app": "" - }, - "up": { - "up": "" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "NM entegrasyonu için dms'yi güncelle" - }, - "v%1 by %2": { - "v%1 by %2": "" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype mevcut değil - yapıştırma desteği için wtype'ı yükleyin" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• Yalnızca güvenilir kaynaklardan yükle" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - Ay (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• M - Ay (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - Ay (Oca)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - Ay (Ocak)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• Eklentiler hata veya güvenlik sorunları içerebilir" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• Mümkünse kurulumdan önce kodu inceleyin" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - Gün (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - Gün (1-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - Gün adı (Pzt)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - Gün adı (Pazartesi)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - Yıl (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - Yıl (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_CN.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_CN.json deleted file mode 100644 index f6d79a4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_CN.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1动画速度" - }, - "%1 Sessions": { - "%1 Sessions": "%1个会话" - }, - "%1 active session": { - "%1 active session": "%1个激活会话" - }, - "%1 active sessions": { - "%1 active sessions": "%1个激活会话" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "1%个适配器,未连接任何适配器" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "1%个适配器,未连接任何适配器" - }, - "%1 character": { - "%1 character": "%1个字母" - }, - "%1 characters": { - "%1 characters": "%1个字符" - }, - "%1 connected": { - "%1 connected": "已连接 %1" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1自定义动画持续时间" - }, - "%1 disconnected": { - "%1 disconnected": "%1已断开连接" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1已断开连接(隐藏)" - }, - "%1 display": { - "%1 display": "%1个显示器" - }, - "%1 displays": { - "%1 displays": "%1个显示器" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1存在但并未被包含至配置文件。在此问题修复前,自定义快捷键绑定将不会生效。" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1已存在但未被包含。窗口规则将不会生效。" - }, - "%1 filtered": { - "%1 filtered": "%1个已筛选" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1现在已被包含至配置文件" - }, - "%1 issue found": { - "%1 issue found": "发现%1个问题" - }, - "%1 issues found": { - "%1 issues found": "发现%1个问题" - }, - "%1 notifications": { - "%1 notifications": "%1条通知" - }, - "%1 update": { - "%1 update": "%1个更新" - }, - "%1 updates": { - "%1 updates": "%1个更新" - }, - "%1 variants": { - "%1 variants": "%1变体" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1张壁纸 • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1张壁纸 • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 部件" - }, - "%1 window": { - "%1 window": "%1个窗口" - }, - "%1 windows": { - "%1 windows": "%1个窗口" - }, - "%1m ago": { - "%1m ago": "%1分之前" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "“Alternative”(替代)模式允许密钥自行解锁。“Second factor”(双重验证)模式则需要先输入密码或指纹,然后再使用密钥。" - }, - "(Default)": { - "(Default)": "(默认)" - }, - "(Unnamed)": { - "(Unnamed)": "(未命名)" - }, - "+ %1 more": { - "+ %1 more": "+%1更多" - }, - "/path/to/videos": { - "/path/to/videos": "/path/to/videos" - }, - "0 = square corners": { - "0 = square corners": "0 = 直角" - }, - "1 day": { - "1 day": "1天" - }, - "1 device connected": { - "1 device connected": "已连接1个设备" - }, - "1 event": { - "1 event": "1个事件" - }, - "1 hour": { - "1 hour": "1小时" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1小时30分钟" - }, - "1 minute": { - "1 minute": "1 分钟" - }, - "1 notification": { - "1 notification": "1条通知" - }, - "1 second": { - "1 second": "1 秒" - }, - "10 minutes": { - "10 minutes": "10 分钟" - }, - "10 seconds": { - "10 seconds": "10 秒" - }, - "10-bit Color": { - "10-bit Color": "10位色彩" - }, - "12 hours": { - "12 hours": "12小时" - }, - "14 days": { - "14 days": "14天" - }, - "15 minutes": { - "15 minutes": "15分钟" - }, - "15 seconds": { - "15 seconds": "15 秒" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2小时" - }, - "2 minutes": { - "2 minutes": "2 分钟" - }, - "2 seconds": { - "2 seconds": "2秒" - }, - "20 minutes": { - "20 minutes": "20分钟" - }, - "20 seconds": { - "20 seconds": "20秒" - }, - "24-Hour Format": { - "24-Hour Format": "24小时制" - }, - "24-hour clock": { - "24-hour clock": "24小时制时钟" - }, - "24-hour format": { - "24-hour format": "24小时制" - }, - "25 seconds": { - "25 seconds": "25秒" - }, - "250 ms": { - "250 ms": "250毫秒" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3天" - }, - "3 hours": { - "3 hours": "3小时" - }, - "3 minutes": { - "3 minutes": "3分钟" - }, - "3 seconds": { - "3 seconds": "3 秒" - }, - "30 days": { - "30 days": "30天" - }, - "30 minutes": { - "30 minutes": "30分钟" - }, - "30 seconds": { - "30 seconds": "30 秒" - }, - "35 seconds": { - "35 seconds": "35秒" - }, - "3rd party": { - "3rd party": "第三方" - }, - "4 hours": { - "4 hours": "4小时" - }, - "4 seconds": { - "4 seconds": "4秒" - }, - "40 seconds": { - "40 seconds": "40秒" - }, - "45 seconds": { - "45 seconds": "45秒" - }, - "5 minutes": { - "5 minutes": "5 分钟" - }, - "5 seconds": { - "5 seconds": "5 秒" - }, - "50 seconds": { - "50 seconds": "50秒" - }, - "500 ms": { - "500 ms": "500毫秒" - }, - "55 seconds": { - "55 seconds": "55秒" - }, - "6 hours": { - "6 hours": "6小时" - }, - "7 days": { - "7 days": "7天" - }, - "750 ms": { - "750 ms": "750毫秒" - }, - "8 hours": { - "8 hours": "8小时" - }, - "8 seconds": { - "8 seconds": "8 秒" - }, - "90 days": { - "90 days": "90天" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "MIT License" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "已存在同名文件,是否覆盖?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "为wayland合成器设计的一款现代桌面shell" - }, - "AC Power": { - "AC Power": "交流电" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "已中止" - }, - "About": { - "About": "关于" - }, - "Accent Color": { - "Accent Color": "重点色" - }, - "Accept": { - "Accept": "接受" - }, - "Accept Jobs": { - "Accept Jobs": "接受任务" - }, - "Accepting": { - "Accepting": "正在接受" - }, - "Access clipboard history": { - "Access clipboard history": "访问剪切板记录" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "访问通知与请勿打扰" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "访问系统控制和设置" - }, - "Action": { - "Action": "操作" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "操作失败或终端已关闭。" - }, - "Actions": { - "Actions": "操作" - }, - "Activate": { - "Activate": "激活" - }, - "Activate Greeter": { - "Activate Greeter": "激活 Greeter" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "激活 DMS Greeter?将打开一个终端进行 sudo 身份验证。激活后运行“同步”以应用您的设置。" - }, - "Activation": { - "Activation": "激活" - }, - "Active": { - "Active": "活动" - }, - "Active Color": { - "Active Color": "激活颜色" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "活动锁屏显示器" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "激活平铺背景与图标颜色" - }, - "Active: %1": { - "Active: %1": "激活:%1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "激活:%1 +%2" - }, - "Active: None": { - "Active: None": "活动: 无" - }, - "Adapters": { - "Adapters": "适配器" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "添加" - }, - "Add Bar": { - "Add Bar": "添加状态栏" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "添加桌面部件" - }, - "Add Printer": { - "Add Printer": "添加打印机" - }, - "Add Title": { - "Add Title": "添加标题" - }, - "Add Widget": { - "Add Widget": "添加部件" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "将部件添加到 %1 部分" - }, - "Add a border around the dock": { - "Add a border around the dock": "在程序坞周围添加边框" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "在所有应用启动后添加自定义前缀。这可以用来处理诸如uwsm-app、systemd-run或其他命令封装器。" - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "添加与配置出现在你桌面的部件" - }, - "Add by Address": { - "Add by Address": "通过地址添加" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "在网格模式中按需调整列的数量。" - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "每滚动一格调节音量" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "调整生成颜色的对比度(-100 = 最小,0 = 标准,100 = 最大)" - }, - "Advanced": { - "Advanced": "高级" - }, - "Afternoon": { - "Afternoon": "下午" - }, - "All": { - "All": "全部" - }, - "All Monitors": { - "All Monitors": "所有显示器" - }, - "All checks passed": { - "All checks passed": "所有检查均已通过" - }, - "All day": { - "All day": "每天" - }, - "All displays": { - "All displays": "所有显示器" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "允许鼠标穿透部件" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/退格: 返回 • F1/I: 文件信息 • F10: 帮助 • Esc: 关闭" - }, - "Alternative (OR)": { - "Alternative (OR)": "Alternative (OR)" - }, - "Always Active": { - "Always Active": "总是激活" - }, - "Always Show Percentage": { - "Always Show Percentage": "始终显示百分比" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "总是隐藏程序坞,并在靠近它时显露" - }, - "Always on icons": { - "Always on icons": "总显示的图标" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "即使不足也总是显示至少三个工作区" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "当Niri的概览打开时,也总是显示程序坞" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "当仅连接一个显示器时,总是显示" - }, - "Amount": { - "Amount": "数量" - }, - "Analog": { - "Analog": "模拟" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "模拟、数字以及堆叠时钟显示" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "配置分析中..." - }, - "Animation Duration": { - "Animation Duration": "动画时长" - }, - "Animation Speed": { - "Animation Speed": "动画速度" - }, - "Anonymous Identity": { - "Anonymous Identity": "匿名身份" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "匿名身份(可选)" - }, - "App Customizations": { - "App Customizations": "应用自定义" - }, - "App ID Substitutions": { - "App ID Substitutions": "应用ID替换" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "应用ID正则(比如^firefox$)" - }, - "App Launcher": { - "App Launcher": "启动器" - }, - "App Names": { - "App Names": "仅应用名" - }, - "App Theming": { - "App Theming": "应用主题" - }, - "Appearance": { - "Appearance": "外观" - }, - "Application Dock": { - "Application Dock": "程序坞" - }, - "Applications": { - "Applications": "应用程序" - }, - "Apply Changes": { - "Apply Changes": "应用更改" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "应用 GTK 配色" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "应用 Qt 配色" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "应用暖色温以减轻眼睛疲劳,可通过下方设置配置按时间自动启用。" - }, - "Applying authentication changes…": { - "Applying authentication changes…": "正在应用认证变更……" - }, - "Apps": { - "Apps": "应用" - }, - "Apps Dock": { - "Apps Dock": "程序坞" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "程序坞设定" - }, - "Apps Icon": { - "Apps Icon": "应用图标" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "应用按使用频率、最近使用时间和字母顺序排序。" - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "程序会带有自定义名称、图标与启动选项。右键应用并选择“编辑应用”进行自定义。" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "已静音通知弹窗的应用。请取消静音或删除以移除。" - }, - "Architecture": { - "Architecture": "架构" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "确认要结束会话\"%1\"吗?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "排列显示器、配置分辨率、刷新率和VRR" - }, - "Attach": { - "Attach": "标记" - }, - "Audio": { - "Audio": "音频" - }, - "Audio Codec": { - "Audio Codec": "音频编解码器" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "选择音频编解码器" - }, - "Audio Devices": { - "Audio Devices": "音频设备" - }, - "Audio Input": { - "Audio Input": "音频输入" - }, - "Audio Output": { - "Audio Output": "音频输出" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "音频输出设备 (" - }, - "Audio Output Switch": { - "Audio Output Switch": "声音输出切换" - }, - "Audio Visualizer": { - "Audio Visualizer": "音频可视化" - }, - "Audio system restarted": { - "Audio system restarted": "音频系统已重启" - }, - "Audio volume control": { - "Audio volume control": "音量控制" - }, - "Auth": { - "Auth": "认证" - }, - "Auth Type": { - "Auth Type": "认证方式" - }, - "Authenticate": { - "Authenticate": "认证" - }, - "Authenticating...": { - "Authenticating...": "认证中……" - }, - "Authentication": { - "Authentication": "认证" - }, - "Authentication Required": { - "Authentication Required": "需要认证" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "认证变更已应用。" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "认证变更自动应用。" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "认证变更自动应用。仅指纹登录可能无法解锁密钥环。" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "认证变更需要sudo权限。正在打开终端,你可以使用密码或指纹通过验证。" - }, - "Authentication error - try again": { - "Authentication error - try again": "认证错误——请重试" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "认证失败,请重试" - }, - "Authorize": { - "Authorize": "授权" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "授权配对 " - }, - "Authorize service for ": { - "Authorize service for ": "授权服务 " - }, - "Auto": { - "Auto": "自动" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "自动(基于Bar)" - }, - "Auto (Wide)": { - "Auto (Wide)": "自动(宽角)" - }, - "Auto Location": { - "Auto Location": "自动定位" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "自动弹窗间距" - }, - "Auto-Clear After": { - "Auto-Clear After": "在此之后自动清除" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "自动隐藏超时" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "当启动程序时自动关闭Niri概览。" - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "自动删除在此之前的通知" - }, - "Auto-hide": { - "Auto-hide": "自动隐藏" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "自动隐藏程序坞" - }, - "Auto-saving...": { - "Auto-saving...": "自动保存中..." - }, - "Autoconnect": { - "Autoconnect": "自动连接" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "已禁用自动连接" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "已启用自动连接" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "打开时自动填充上次记忆的查询" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "自动颜色模式" - }, - "Automatic Control": { - "Automatic Control": "自动切换" - }, - "Automatic Cycling": { - "Automatic Cycling": "自动轮换" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "自动轮换文件夹中的壁纸" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "自动删除比这更旧的项目" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "根据 IP 地址自动检测位置" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "通过 IP 地址自动检测您的位置" - }, - "Automatically lock after": { - "Automatically lock after": "在此时间后自动锁定" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "DMS 启动时自动锁定屏幕" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "当系统准备挂起时自动锁定屏幕" - }, - "Automation": { - "Automation": "自动" - }, - "Available": { - "Available": "可用" - }, - "Available Layouts": { - "Available Layouts": "可用布局" - }, - "Available Networks": { - "Available Networks": "可用网络" - }, - "Available Plugins": { - "Available Plugins": "可用插件" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "可用屏幕(%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "提供详细视图和预测视图两种模式" - }, - "Available.": { - "Available.": "可用。" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "返回" - }, - "Backend": { - "Backend": "后端" - }, - "Background": { - "Background": "背景" - }, - "Background Blur": { - "Background Blur": "背景模糊" - }, - "Background Opacity": { - "Background Opacity": "背景透明度" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "后台认证同步失败。请尝试终端模式。" - }, - "Background image": { - "Background image": "背景图片" - }, - "Backlight device": { - "Backlight device": "背光设备" - }, - "Balance power and performance": { - "Balance power and performance": "平衡与性能电源模式" - }, - "Balanced": { - "Balanced": "平衡" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "均衡配色,强调重点(默认)" - }, - "Bar Configurations": { - "Bar Configurations": "状态栏设置" - }, - "Bar Shadows": { - "Bar Shadows": "状态栏阴影" - }, - "Bar Transparency": { - "Bar Transparency": "状态栏透明度" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "阴影基础颜色(不透明度会自动应用)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "动画的基础持续时间(拖动以自定义)" - }, - "Battery": { - "Battery": "电池" - }, - "Battery %1": { - "Battery %1": "电池余量%1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "电池充电限制" - }, - "Battery and power management": { - "Battery and power management": "电池与电源管理" - }, - "Battery level and power management": { - "Battery level and power management": "电池电量与电源管理" - }, - "Behavior": { - "Behavior": "行为" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "将锁屏绑定到来自 loginctl 的 dbus 信号。如使用外部锁屏程序,请禁用此项" - }, - "Binds Include Missing": { - "Binds Include Missing": "缺失的绑定包含" - }, - "Binds include added": { - "Binds include added": "已添加绑定包含" - }, - "Bit Depth": { - "Bit Depth": "位深" - }, - "Block Out": { - "Block Out": "封锁" - }, - "Block Out From": { - "Block Out From": "从此处封锁" - }, - "Block notifications": { - "Block notifications": "屏蔽通知" - }, - "Blocked": { - "Blocked": "已屏蔽" - }, - "Blue light filter": { - "Blue light filter": "蓝光过滤器" - }, - "Bluetooth": { - "Bluetooth": "蓝牙" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "蓝牙设置" - }, - "Bluetooth not available": { - "Bluetooth not available": "蓝牙不可用" - }, - "Blur Border Color": { - "Blur Border Color": "模糊边框颜色" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "模糊边框透明度" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "模糊壁纸层" - }, - "Blur on Overview": { - "Blur on Overview": "在概览中模糊" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "模糊状态栏、弹窗、模态以及通知的背景。需要合成器支持与配置。" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "当打开概览时模糊壁纸" - }, - "Body": { - "Body": "主体" - }, - "Border": { - "Border": "边框" - }, - "Border Color": { - "Border Color": "边框颜色" - }, - "Border Opacity": { - "Border Opacity": "边框透明度" - }, - "Border Size": { - "Border Size": "边框宽度" - }, - "Border Thickness": { - "Border Thickness": "边框厚度" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "模糊表面周围的边框颜色" - }, - "Border with BG": { - "Border with BG": "带BG的边框" - }, - "Bottom": { - "Bottom": "底部" - }, - "Bottom Center": { - "Bottom Center": "底部中间" - }, - "Bottom Left": { - "Bottom Left": "左下角" - }, - "Bottom Right": { - "Bottom Right": "右下角" - }, - "Bottom Section": { - "Bottom Section": "底部区域" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "底部程序坞:显示已固定和活动应用" - }, - "Brightness": { - "Brightness": "亮度" - }, - "Brightness Slider": { - "Brightness Slider": "亮度滑块" - }, - "Brightness Value": { - "Brightness Value": "亮度值" - }, - "Brightness control not available": { - "Brightness control not available": "亮度控制不可用" - }, - "Browse": { - "Browse": "浏览" - }, - "Browse Files": { - "Browse Files": "浏览文件" - }, - "Browse Plugins": { - "Browse Plugins": "浏览插件" - }, - "Browse Themes": { - "Browse Themes": "浏览主题" - }, - "Browse or search plugins": { - "Browse or search plugins": "浏览或搜索插件" - }, - "Button Color": { - "Button Color": "按钮颜色" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU图表" - }, - "CPU Temperature": { - "CPU Temperature": "CPU 温度" - }, - "CPU Usage": { - "CPU Usage": "CPU 占用" - }, - "CPU temperature display": { - "CPU temperature display": "显示 CPU 温度" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU 占用情况" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU、内存、网络与磁盘监控" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS 警告:不安全的打印过滤器" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS 警告:缺少打印过滤器" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS 打印服务器" - }, - "CUPS not available": { - "CUPS not available": "CUPS不可用" - }, - "Camera": { - "Camera": "摄像头" - }, - "Cancel": { - "Cancel": "取消" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "取消“%1”的所有作业吗?" - }, - "Canceled": { - "Canceled": "已取消" - }, - "Cannot pair": { - "Cannot pair": "无法配对" - }, - "Capabilities": { - "Capabilities": "功能" - }, - "Capacity": { - "Capacity": "电池容量" - }, - "Caps Lock": { - "Caps Lock": "大写锁定" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "大小写指示灯" - }, - "Caps Lock is on": { - "Caps Lock is on": "大小写已锁定" - }, - "Center Section": { - "Center Section": "中间区域" - }, - "Center Single Column": { - "Center Single Column": "居中单列" - }, - "Center Tiling": { - "Center Tiling": "中心平铺" - }, - "Certificate Password": { - "Certificate Password": "证书密码" - }, - "Change Song": { - "Change Song": "切换歌曲" - }, - "Change Volume": { - "Change Volume": "切换音量" - }, - "Change bar appearance": { - "Change bar appearance": "更改状态栏外观" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "更改 DMS 界面使用的区域设置。" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "更改用于日期和时间格式化的区域设置,与界面语言无关。" - }, - "Channel": { - "Channel": "频道" - }, - "Charging": { - "Charging": "充电" - }, - "Check for system updates": { - "Check for system updates": "检查系统更新" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "按需检查同步状态。同步会将你的主题、设置和壁纸配置复制到登录界面。认证变更会自动生效。" - }, - "Checking for updates...": { - "Checking for updates...": "正检测更新……" - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "正在检查是否需要 sudo 认证..." - }, - "Checking...": { - "Checking...": "检测中……" - }, - "Checking…": { - "Checking…": "检查中……" - }, - "Choose Color": { - "Choose Color": "选择颜色" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "选择黑暗模式颜色" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "选择程序坞启动器图标颜色" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "设置启动器 Logo 颜色" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "选择明亮模式颜色" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "选择壁纸颜色" - }, - "Choose a color": { - "Choose a color": "选择颜色" - }, - "Choose colors from palette": { - "Choose colors from palette": "从调色板中选择颜色" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "选择天气部件的显示方式" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "选择此状态栏解析阴影方向的方式" - }, - "Choose icon": { - "Choose icon": "选择图标" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "选择部件背景色" - }, - "Choose the border accent color": { - "Choose the border accent color": "选择边框强调色" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "选择在 DankBar 启动器按钮上显示的 Logo" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "设置通知弹窗的出现位置" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "选择 OSD 在屏幕上出现的位置" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "选择要在哪个显示器显示该小部件" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "选择哪个显示器显示锁屏界面。其他显示器将显示纯色以保护 OLED 屏幕防烧伤。" - }, - "Chroma Style": { - "Chroma Style": "浓度风格" - }, - "Cipher": { - "Cipher": "密码" - }, - "Circle": { - "Circle": "圆形" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "窗口类型正则(比如^firefox$)" - }, - "Clear": { - "Clear": "清除" - }, - "Clear All": { - "Clear All": "清空" - }, - "Clear All Jobs": { - "Clear All Jobs": "清除所有任务" - }, - "Clear History?": { - "Clear History?": "是否清除历史?" - }, - "Clear Sky": { - "Clear Sky": "晴空" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "当服务器启动时清除所有纪录" - }, - "Clear at Startup": { - "Clear at Startup": "启动时清除" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "点击设置以创建%1并将其包含至配置文件。" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "点击设置以创建%1并添加包含文件至合成器配置文件。" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "点击设置以创建光标配置,并导入至合成器配置文件。" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "点击设置以创建输出配置,并添加至合成器配置。" - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "点击导入添加 .ovpn 或 .conf 文件" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "点击刷新以查看状态。" - }, - "Click Through": { - "Click Through": "鼠标穿透" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "点击任意快捷方式以编辑。更改将保存至%1。" - }, - "Click to capture": { - "Click to capture": "点击以捕获" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "点击以选择自定义主题的JSON文件" - }, - "Clip": { - "Clip": "裁剪" - }, - "Clip to Geometry": { - "Clip to Geometry": "裁剪至几何形" - }, - "Clipboard": { - "Clipboard": "剪切板" - }, - "Clipboard History": { - "Clipboard History": "剪切板历史记录" - }, - "Clipboard Manager": { - "Clipboard Manager": "剪切板管理器" - }, - "Clipboard sent": { - "Clipboard sent": "已发送剪切板" - }, - "Clipboard service not available": { - "Clipboard service not available": "剪切板服务不可用" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "剪切板正常工作但无存入磁盘内容" - }, - "Clock": { - "Clock": "时钟" - }, - "Clock Style": { - "Clock Style": "表盘样式" - }, - "Close": { - "Close": "关闭" - }, - "Close All Windows": { - "Close All Windows": "关闭所有窗口" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "在启动时关闭概览" - }, - "Close Window": { - "Close Window": "关闭窗口" - }, - "Color": { - "Color": "颜色" - }, - "Color Gamut": { - "Color Gamut": "色域" - }, - "Color Management": { - "Color Management": "色彩管理" - }, - "Color Mode": { - "Color Mode": "颜色模式" - }, - "Color Override": { - "Color Override": "覆盖颜色" - }, - "Color Picker": { - "Color Picker": "取色器" - }, - "Color Temperature": { - "Color Temperature": "色温" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "未显示锁屏的显示器上显示的颜色" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "主要操作按钮颜色" - }, - "Color temperature for day time": { - "Color temperature for day time": "白天模式色温" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "夜间模式色温" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "语法高亮的颜色主题。" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "语法高亮的颜色主题。有%1的主题可供使用。" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "DMS注册表的颜色主题" - }, - "Colorful": { - "Colorful": "彩色" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "色彩鲜明、对比强烈的配色。" - }, - "Colorize Active": { - "Colorize Active": "激活上色" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "从壁纸选取颜色" - }, - "Column": { - "Column": "列" - }, - "Column Display": { - "Column Display": "列式显示" - }, - "Column Width": { - "Column Width": "列宽" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "要隐藏的会话名称的逗号分隔列表。使用正则表达式时用斜杠包裹(例如 /^_.*/)。" - }, - "Command": { - "Command": "命令" - }, - "Commands": { - "Commands": "命令" - }, - "Communication": { - "Communication": "通讯" - }, - "Community themes": { - "Community themes": "社区主题" - }, - "Compact": { - "Compact": "紧凑" - }, - "Compact Mode": { - "Compact Mode": "紧凑模式" - }, - "Completed": { - "Completed": "已完成" - }, - "Compositor": { - "Compositor": "合成器" - }, - "Compositor Settings": { - "Compositor Settings": "合成器设置" - }, - "Compositor not supported": { - "Compositor not supported": "合成器不支持" - }, - "Config Format": { - "Config Format": "配置格式" - }, - "Config action: %1": { - "Config action: %1": "配置操作:%1" - }, - "Config validation failed": { - "Config validation failed": "配置验证失败" - }, - "Configuration": { - "Configuration": "配置" - }, - "Configuration activated": { - "Configuration activated": "已应用配置" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "当该显示器重新连接时,配置将被保留" - }, - "Configure": { - "Configure": "配置" - }, - "Configure Keybinds": { - "Configure Keybinds": "配置快捷键绑定" - }, - "Configure a new printer": { - "Configure a new printer": "配置新打印机" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "为已命名工作区配置图标。当数字和图标同时启用时,图标优先生效。" - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "配置文件匹配条件与动作" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "配置要显示的显示器\"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "配置哪些显示器显示各类部件" - }, - "Confirm": { - "Confirm": "确认" - }, - "Confirm Delete": { - "Confirm Delete": "确认删除" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "确认显示更改" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "确认密钥 " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "冲突:%1" - }, - "Connect": { - "Connect": "连接" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "连接到隐藏的网络" - }, - "Connect to VPN": { - "Connect to VPN": "连接到 VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "连接到 Wi-Fi" - }, - "Connected": { - "Connected": "已连接" - }, - "Connected Device": { - "Connected Device": "已连接的设备" - }, - "Connected Displays": { - "Connected Displays": "已连接显示器" - }, - "Connecting to Device": { - "Connecting to Device": "连接设备中" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "连接中..." - }, - "Connection failed": { - "Connection failed": "连接失败" - }, - "Contains": { - "Contains": "包含" - }, - "Content": { - "Content": "内容" - }, - "Content copied": { - "Content copied": "内容已复制" - }, - "Contrast": { - "Contrast": "对比度" - }, - "Control Center": { - "Control Center": "控制中心" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "控制中心平铺颜色" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "控制通知弹窗和历史记录的动画持续时间" - }, - "Control currently playing media": { - "Control currently playing media": "控制当前播放的媒体" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "控制在锁屏上显示的通知内容" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "控制哪些插件会出现在“所有”模式中,而无需触发器prefix。可通过拖拽调整顺序。" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "在状态栏上滚动时也会控制工作区和列" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "控制所有弹出窗口、模态框及其内容层的透明度" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "控制提升图层的阴影投射方向" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "控制阴影的基础模糊半径和偏移量" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "控制阴影的透明度" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "登录界面的便捷选项。同步以应用。" - }, - "Cooldown": { - "Cooldown": "冷却" - }, - "Copied GIF": { - "Copied GIF": "已复制的动图" - }, - "Copied MP4": { - "Copied MP4": "已复制的MP4" - }, - "Copied WebP": { - "Copied WebP": "已复制的WebP" - }, - "Copied to clipboard": { - "Copied to clipboard": "复制到剪切板" - }, - "Copied!": { - "Copied!": "复制成功!" - }, - "Copy": { - "Copy": "复制" - }, - "Copy Content": { - "Copy Content": "复制内容" - }, - "Copy Full Command": { - "Copy Full Command": "复制完整命令" - }, - "Copy HTML": { - "Copy HTML": "复制 HTML" - }, - "Copy Name": { - "Copy Name": "复制名称" - }, - "Copy PID": { - "Copy PID": "复制进程ID" - }, - "Copy Text": { - "Copy Text": "复制文本" - }, - "Copy path": { - "Copy path": "复制路径" - }, - "Corner Radius": { - "Corner Radius": "圆角半径" - }, - "Corner Radius Override": { - "Corner Radius Override": "圆角半径覆盖" - }, - "Corners & Background": { - "Corners & Background": "角落与背景" - }, - "Count Only": { - "Count Only": "仅数量" - }, - "Cover Open": { - "Cover Open": "打印机盖已打开" - }, - "Create": { - "Create": "创建" - }, - "Create Dir": { - "Create Dir": "创建目录" - }, - "Create Printer": { - "Create Printer": "创建打印机" - }, - "Create Window Rule": { - "Create Window Rule": "创建窗口规则" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "创建一个%1会话(n)" - }, - "Create rule for:": { - "Create rule for:": "为此创建规则:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "创建规则以静音、忽略、从历史记录中隐藏或覆盖通知优先级。默认设置仅覆盖优先级;通知仍会正常显示。" - }, - "Creating...": { - "Creating...": "正在创建..." - }, - "Critical Priority": { - "Critical Priority": "紧急通知" - }, - "Current": { - "Current": "当前" - }, - "Current Items": { - "Current Items": "当前项目" - }, - "Current Locale": { - "Current Locale": "当前区域设置" - }, - "Current Monitor": { - "Current Monitor": "当前显示器" - }, - "Current Period": { - "Current Period": "当前时间" - }, - "Current Status": { - "Current Status": "当前状态" - }, - "Current Temp": { - "Current Temp": "当前温度" - }, - "Current Theme: %1": { - "Current Theme: %1": "当前主题:%1" - }, - "Current Weather": { - "Current Weather": "当前天气" - }, - "Current Workspace": { - "Current Workspace": "当前工作区" - }, - "Current time and date display": { - "Current time and date display": "显示当前时间与日期" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "当前天气及气温" - }, - "Current: %1": { - "Current: %1": "当前:%1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "光标未配置" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "未找到光标导入配置" - }, - "Cursor Size": { - "Cursor Size": "光标尺寸" - }, - "Cursor Theme": { - "Cursor Theme": "光标主题" - }, - "Custom": { - "Custom": "自定义" - }, - "Custom Color": { - "Custom Color": "自定义颜色" - }, - "Custom Duration": { - "Custom Duration": "自定义持续时间" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "自定义休眠命令" - }, - "Custom Location": { - "Custom Location": "自定义位置" - }, - "Custom Lock Command": { - "Custom Lock Command": "自定义锁定命令" - }, - "Custom Logout Command": { - "Custom Logout Command": "自定义注销命令" - }, - "Custom Name": { - "Custom Name": "自定义名称" - }, - "Custom Power Actions": { - "Custom Power Actions": "自定义电源操作" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "自定义关机命令" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "自定义重启命令" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "自定义阴影颜色" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "自定义阴影覆盖" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "自定义挂起命令" - }, - "Custom Transparency": { - "Custom Transparency": "自定义透明度" - }, - "Custom power profile": { - "Custom power profile": "自定义电源配置" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "从JSON文件加载的自定义主题" - }, - "Custom...": { - "Custom...": "自定义..." - }, - "Custom: ": { - "Custom: ": "自定义: " - }, - "Customizable empty space": { - "Customizable empty space": "可调节留白" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "自定义电源菜单选项" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI监视器" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "演示模式 - 点击任意位置退出" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS 插件管理器不可用" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS快捷键" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "DMS欢迎界面需要:greetd、dms-greeter。指纹:fprintd、pam_fprintd。安全钥匙:pam_u2f。把你的用户添加到greeter组。认证变更会自动应用,当需要sudo认证时,可能会打开终端。" - }, - "DMS out of date": { - "DMS out of date": "DMS 不是最新版本" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS服务未连接。剪切板设置不可用。" - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS shell 操作(启动器、剪贴板等)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET 不可用" - }, - "DWL service not available": { - "DWL service not available": "DWL 服务不可用" - }, - "Daily": { - "Daily": "每日" - }, - "Daily at:": { - "Daily at:": "在每日:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell现已可用" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell 和系统图标 (需要重启)" - }, - "Dark Mode": { - "Dark Mode": "暗色模式" - }, - "Dark mode base": { - "Dark mode base": "基于黑暗模式" - }, - "Dark mode harmony": { - "Dark mode harmony": "黑暗模式和谐" - }, - "Darken Modal Background": { - "Darken Modal Background": "暗化背景" - }, - "Date Format": { - "Date Format": "日期格式" - }, - "Date format": { - "Date format": "日期格式" - }, - "Date format on greeter": { - "Date format on greeter": "Greeter 界面日期格式" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "黎明(天文晨光)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "黎明(民用晨光)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "黎明(航海晨光)" - }, - "Day Date": { - "Day Date": "日 日期" - }, - "Day Month Date": { - "Day Month Date": "日 月份 日期" - }, - "Day Temperature": { - "Day Temperature": "日间色温" - }, - "Daytime": { - "Daytime": "日期" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "默认" - }, - "Default (Black)": { - "Default (Black)": "默认(黑色)" - }, - "Default Width (%)": { - "Default Width (%)": "默认宽度(%)" - }, - "Default selected action": { - "Default selected action": "默认选项" - }, - "Defaults": { - "Defaults": "复位" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "定义窗口行为规则。保存至%1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: 清除 • Shift+Del: 清空 • 1-9: 操作 • F10: 帮助 • Esc: 关闭" - }, - "Delete": { - "Delete": "删除" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "删除\"%1\"?" - }, - "Delete Class": { - "Delete Class": "删除类别" - }, - "Delete Printer": { - "Delete Printer": "删除打印机" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "是否删除已保存项目?" - }, - "Delete VPN": { - "Delete VPN": "删除 VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "删除类别\"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "删除档案\"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "依赖与文档" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "提取与壁纸高度匹配的颜色。" - }, - "Description": { - "Description": "描述" - }, - "Desktop": { - "Desktop": "桌面" - }, - "Desktop Clock": { - "Desktop Clock": "桌面时钟" - }, - "Desktop Entry": { - "Desktop Entry": "桌面项目" - }, - "Desktop Widget": { - "Desktop Widget": "桌面部件" - }, - "Desktop Widgets": { - "Desktop Widgets": "桌面部件" - }, - "Desktop background images": { - "Desktop background images": "桌面壁纸" - }, - "Detailed": { - "Detailed": "详细" - }, - "Details for \"%1": { - "Details for \"%1\"": "\"%1\"的详细信息" - }, - "Development": { - "Development": "开发" - }, - "Device": { - "Device": "设备" - }, - "Device connections": { - "Device connections": "设备连接" - }, - "Device names updated": { - "Device names updated": "设备名已更新" - }, - "Device paired": { - "Device paired": "设备已配对" - }, - "Device unpaired": { - "Device unpaired": "设备已取消配对" - }, - "Digital": { - "Digital": "电子" - }, - "Direction Source": { - "Direction Source": "方向源" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "禁用自动连接" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "禁用内置壁纸" - }, - "Disable History Persistence": { - "Disable History Persistence": "禁用历史持久化" - }, - "Disable Output": { - "Disable Output": "禁止输出" - }, - "Disabled": { - "Disabled": "已关闭" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "正在禁用WiFi..." - }, - "Disc": { - "Disc": "涟漪" - }, - "Discard": { - "Discard": "放弃" - }, - "Discharging": { - "Discharging": "放电" - }, - "Disconnect": { - "Disconnect": "断开连接" - }, - "Disconnected": { - "Disconnected": "已断开连接" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "Wi-Fi 已断开" - }, - "Discover Devices": { - "Discover Devices": "发现设备" - }, - "Disk": { - "Disk": "磁盘" - }, - "Disk I/O": { - "Disk I/O": "磁盘I/O" - }, - "Disk Usage": { - "Disk Usage": "磁盘占用" - }, - "Disk Usage Display": { - "Disk Usage Display": "显示磁盘使用量" - }, - "Disks": { - "Disks": "磁盘" - }, - "Dismiss": { - "Dismiss": "忽略" - }, - "Display": { - "Display": "显示" - }, - "Display Assignment": { - "Display Assignment": "显示布局" - }, - "Display Control": { - "Display Control": "显示控制" - }, - "Display Name Format": { - "Display Name Format": "显示名称格式" - }, - "Display Profiles": { - "Display Profiles": "显示档案" - }, - "Display Settings": { - "Display Settings": "显示设置" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "显示带有固定和运行中应用程序的程序坞" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "应用全屏时仍显示所有优先级的通知" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "显示与切换 DWL 布局" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "在工作区指示器中显示应用程序图标" - }, - "Display brightness control": { - "Display brightness control": "显示亮度控制" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "显示配置不可用。WLR输出管理协议不受支持。" - }, - "Display currently focused application title": { - "Display currently focused application title": "显示当前聚焦应用的标题" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "显示每小时天气预报" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "只显示包含窗口的工作区" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "通过网格而非列表显示电源菜单" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "在时钟中显示秒数" - }, - "Display the power system menu": { - "Display the power system menu": "显示电源菜单" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "在 OSD 弹出窗口中显示音量和亮度百分比值" - }, - "Displays": { - "Displays": "显示" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "当溢出激活时显示计数" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "显示当前键盘布局并支持切换" - }, - "Distribution": { - "Distribution": "发行" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "绚丽多彩,覆盖全色系的配色。" - }, - "Do Not Disturb": { - "Do Not Disturb": "勿扰模式" - }, - "Dock": { - "Dock": "程序坞" - }, - "Dock & Launcher": { - "Dock & Launcher": "程序坞和启动器" - }, - "Dock Transparency": { - "Dock Transparency": "程序坞透明度" - }, - "Dock Visibility": { - "Dock Visibility": "程序坞可见性" - }, - "Docs": { - "Docs": "文档" - }, - "Documents": { - "Documents": "文档" - }, - "Domain (optional)": { - "Domain (optional)": "域(可选)" - }, - "Don't Change": { - "Don't Change": "不要更改" - }, - "Don't Save": { - "Don't Save": "不要保存" - }, - "Door Open": { - "Door Open": "打印机维护口已打开" - }, - "Downloads": { - "Downloads": "下载" - }, - "Drag to Reorder": { - "Drag to Reorder": "拖动以重新排序" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖动部件以在各区块内重新排序。点击眼睛图标可隐藏/显示部件(保留间距),点击 X 可彻底移除。" - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "拖动工作区指示器以重新排序" - }, - "Driver": { - "Driver": "驱动程序" - }, - "Drizzle": { - "Drizzle": "细雨" - }, - "Duplicate": { - "Duplicate": "复制" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "带模糊效果的壁纸复本" - }, - "Duration": { - "Duration": "持续时间" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "黄昏(天文暮光)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "黄昏(民用暮光)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "黄昏(航海暮光)" - }, - "Dynamic": { - "Dynamic": "动态" - }, - "Dynamic Properties": { - "Dynamic Properties": "动态属性" - }, - "Dynamic Theming": { - "Dynamic Theming": "动态主题" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "自壁纸选取动态色" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "动态颜色与预设" - }, - "Edge Spacing": { - "Edge Spacing": "边缘间距" - }, - "Edit App": { - "Edit App": "编辑应用" - }, - "Edit Window Rule": { - "Edit Window Rule": "编辑窗口规则" - }, - "Education": { - "Education": "教育" - }, - "Empty": { - "Empty": "空" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "为广色域与HDR支持启用10位色深" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "启用自动连接" - }, - "Enable Bar": { - "Enable Bar": "启用状态栏" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "启用请勿打扰" - }, - "Enable History": { - "Enable History": "启用历史记录" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "启用概览叠加层" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "启用波纹效果" - }, - "Enable System Sounds": { - "Enable System Sounds": "启用系统声音" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "启用视频屏保" - }, - "Enable Weather": { - "Enable Weather": "显示天气" - }, - "Enable WiFi": { - "Enable WiFi": "启用 Wi-Fi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "在下方启用自定义覆盖,以设置每条状态栏的阴影强度、透明度和颜色。" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "启用合成器可定位的模糊层(命名空间:dms:blurwallpaper),需要手动配置 niri。" - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "登录时启用指纹识别" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "启用指纹认证" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "启用DMS欢迎界面的指纹或安全密钥。认证变更会自动生效。" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "启用 loginctl 锁定集成" - }, - "Enable security key at login": { - "Enable security key at login": "登录时启用安全密钥" - }, - "Enable security key authentication": { - "Enable security key authentication": "启用安全密钥认证" - }, - "Enabled": { - "Enabled": "已开启" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "已启用,但无法确认指纹识别的可用性。" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "已启用,但无法检测到指纹识别的读取器。" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "已启用,但还没有指纹记录。一旦你注册指纹,认证变更会自动生效。" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "已启用,但尚无指印注册。请注册指纹后执行同步。" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "已启用,但尚未找到注册的安全密钥。一旦你的密钥注册或U2F配置更新,认证变更会自动生效。" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "已启用,但未找到任何已注册安全密钥。请注册后执行同步。" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "已启用,但无法确认安全密钥的可用性。" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "已启用。PAM已提供指纹认证。" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "已启用。PAM已提供安全密钥认证。" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "已启用。PAM将提供指纹认证,但尚未注册指纹。" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "正在启用WiFi..." - }, - "End": { - "End": "结束" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "悬停放大" - }, - "Enlargement %": { - "Enlargement %": "放大%1" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "输入六位数密钥" - }, - "Enter PIN": { - "Enter PIN": "输入PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "输入PIN " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "请输入想要共享的网址或文本" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "为会话\"%1\"输入新名称" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "为此工作区键入新名称" - }, - "Enter command or script path": { - "Enter command or script path": "输入命令或脚本路径" - }, - "Enter credentials for ": { - "Enter credentials for ": "输入凭据 " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "输入自定义锁屏格式(例如:dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "输入自定义顶栏格式(例如:ddd MMM d)" - }, - "Enter device name...": { - "Enter device name...": "输入设备名称..." - }, - "Enter filename...": { - "Enter filename...": "输入文件名..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "输入启动前缀(例如 uwsm-app)" - }, - "Enter network name and password": { - "Enter network name and password": "输入网络名称与密码" - }, - "Enter passkey for ": { - "Enter passkey for ": "输入密钥 " - }, - "Enter password for ": { - "Enter password for ": "输入密码" - }, - "Enter this passkey on ": { - "Enter this passkey on ": "在该处输入此通行密钥 " - }, - "Enter to Paste": { - "Enter to Paste": "按回车以粘贴" - }, - "Enterprise": { - "Enterprise": "企业" - }, - "Entry pinned": { - "Entry pinned": "项目已固定" - }, - "Entry unpinned": { - "Entry unpinned": "项目已取消固定" - }, - "Environment Variables": { - "Environment Variables": "环境变量" - }, - "Error": { - "Error": "错误" - }, - "Errors": { - "Errors": "错误" - }, - "Ethernet": { - "Ethernet": "以太网" - }, - "Exact": { - "Exact": "精确" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "独占区域偏移量" - }, - "Experimental Feature": { - "Experimental Feature": "实验性质功能" - }, - "Explore": { - "Explore": "浏览" - }, - "Exponential": { - "Exponential": "指数" - }, - "Expressive": { - "Expressive": "具有表现力的" - }, - "Extend battery life": { - "Extend battery life": "延长电池寿命" - }, - "Extensible architecture": { - "Extensible architecture": "可扩展架构" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "外部壁纸管理" - }, - "Extra Arguments": { - "Extra Arguments": "额外参数" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: 切换 • F10: 帮助" - }, - "Fade": { - "Fade": "淡入淡出" - }, - "Fade to lock screen": { - "Fade to lock screen": "淡出至锁定屏幕" - }, - "Fade to monitor off": { - "Fade to monitor off": "淡出至显示器关闭" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "接受配对失败" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "无法应用配置" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "无法激活配置 - 未找到文件" - }, - "Failed to add binds include": { - "Failed to add binds include": "添加绑定包含失败" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "将打印机添加到类别失败" - }, - "Failed to browse device": { - "Failed to browse device": "浏览设备失败" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "无法取消所有任务" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "无法取消所选的任务" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "检测更新失败:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "检查固定限制失败" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "连接 VPN 失败" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "连接至%1失败" - }, - "Failed to copy entry": { - "Failed to copy entry": "无法复制项目" - }, - "Failed to create printer": { - "Failed to create printer": "创建打印机失败" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "无法创建配置目录" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "删除 VPN 失败" - }, - "Failed to delete class": { - "Failed to delete class": "删除类别失败" - }, - "Failed to delete printer": { - "Failed to delete printer": "删除打印机失败" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "禁用任务接受失败" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "禁用夜间模式失败" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "断开 VPN 失败" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "断开 VPNs 失败" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "无法断开 Wi-Fi 连接" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "启用IP位置失败" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "无法启用 Wi-Fi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "启用任务接受失败" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "启用夜间模式失败" - }, - "Failed to hold job": { - "Failed to hold job": "暂停任务失败" - }, - "Failed to import VPN": { - "Failed to import VPN": "导入 VPN 失败" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "启动SMS应用失败" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "加载 VPN 配置失败" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "无法读取剪切板配置。" - }, - "Failed to move job": { - "Failed to move job": "移动任务失败" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "无法解析plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "无法解析session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "无法解析settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "无法暂停打印机" - }, - "Failed to pin entry": { - "Failed to pin entry": "固定项目失败" - }, - "Failed to print test page": { - "Failed to print test page": "打印测试页失败" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "拒绝配对失败" - }, - "Failed to remove device": { - "Failed to remove device": "删除设备失败" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "移除按键绑定失败" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "从类别中移除打印机失败" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "无法重启音频系统" - }, - "Failed to restart job": { - "Failed to restart job": "重新启动任务失败" - }, - "Failed to resume printer": { - "Failed to resume printer": "无法恢复打印机" - }, - "Failed to ring device": { - "Failed to ring device": "响铃设备失败" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "未能运行 'dms greeter status'。确保 DMS 已安装,且 dms 已在 PATH 中。" - }, - "Failed to save audio config": { - "Failed to save audio config": "音频配置保存失败" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "无法保存剪切板设置" - }, - "Failed to save keybind": { - "Failed to save keybind": "保存按键绑定失败" - }, - "Failed to save profile file": { - "Failed to save profile file": "保存配置文件失败" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "发送剪切板失败" - }, - "Failed to send file": { - "Failed to send file": "发送文件失败" - }, - "Failed to send ping": { - "Failed to send ping": "发送 Ping 失败" - }, - "Failed to set brightness": { - "Failed to set brightness": "设置亮度失败" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "设置夜间模式位置失败" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "设置夜间模式计划失败" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "设置夜间模式温度失败" - }, - "Failed to set power profile": { - "Failed to set power profile": "设置电源档案失败" - }, - "Failed to set profile image": { - "Failed to set profile image": "无法设置个人资料图片" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "设置用户头像:%1失败" - }, - "Failed to share": { - "Failed to share": "共享失败" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "连接至%1失败" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "取消固定项目失败" - }, - "Failed to update VPN": { - "Failed to update VPN": "更新 VPN 失败" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "无法更新自动连接" - }, - "Failed to update description": { - "Failed to update description": "更新描述失败" - }, - "Failed to update location": { - "Failed to update location": "更新位置失败" - }, - "Failed to update sharing": { - "Failed to update sharing": "更新共享失败" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "未能写入临时文件进行验证" - }, - "Features": { - "Features": "功能" - }, - "Feels": { - "Feels": "感官" - }, - "Feels Like": { - "Feels Like": "体感温度" - }, - "Feels Like %1°": { - "Feels Like %1°": "体感 %1°" - }, - "Fidelity": { - "Fidelity": "保真" - }, - "Field": { - "Field": "场地" - }, - "File": { - "File": "文件" - }, - "File Already Exists": { - "File Already Exists": "文件已存在" - }, - "File Information": { - "File Information": "文件信息" - }, - "File received from": { - "File received from": "已从此处接收文件" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "文件搜索需要dsearch\n请从此处安装:github.com/AvengeMedia/danksearch" - }, - "Files": { - "Files": "文件" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "监视文件系统使用率" - }, - "Fill": { - "Fill": "填充" - }, - "Find in Text": { - "Find in Text": "查找文本" - }, - "Find in note...": { - "Find in note...": "在便签中查找..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "无法确认指纹可用性。" - }, - "Fingerprint error": { - "Fingerprint error": "指纹错误" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "指纹错误:%1" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "指纹未识别(%1/%2)。请重试或使用密码。" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "已检测到指纹读取器,但尚未注册指纹。您可以现在就启用,并稍后注册。" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "已检测到指纹读取器,但尚未注册指纹。您可以现在就启用,并稍后执行同步。" - }, - "Finish": { - "Finish": "完成" - }, - "First Day of Week": { - "First Day of Week": "每周的第一天" - }, - "First Time Setup": { - "First Time Setup": "首次设置" - }, - "Fit": { - "Fit": "适合" - }, - "Fix Now": { - "Fix Now": "立即修复" - }, - "Fixing...": { - "Fixing...": "正在修复..." - }, - "Flags": { - "Flags": "标签" - }, - "Flipped": { - "Flipped": "翻转" - }, - "Flipped 180°": { - "Flipped 180°": "翻转180°" - }, - "Flipped 270°": { - "Flipped 270°": "翻转270°" - }, - "Flipped 90°": { - "Flipped 90°": "翻转90°" - }, - "Float": { - "Float": "浮动" - }, - "Focus": { - "Focus": "聚焦" - }, - "Focus at Startup": { - "Focus at Startup": "启动时聚焦" - }, - "Focused Border": { - "Focused Border": "聚焦边框" - }, - "Focused Color": { - "Focused Color": "聚焦颜色" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "仅聚焦的显示器" - }, - "Focused Window": { - "Focused Window": "当前窗口" - }, - "Focused monitor only": { - "Focused monitor only": "仅聚焦的显示器" - }, - "Fog": { - "Fog": "雾天" - }, - "Folder": { - "Folder": "文件夹" - }, - "Folders": { - "Folders": "文件夹" - }, - "Follow DMS background color": { - "Follow DMS background color": "遵循DMS背景颜色" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "遵守显示器聚焦" - }, - "Follow focus": { - "Follow focus": "跟随焦点" - }, - "Font": { - "Font": "字体" - }, - "Font Family": { - "Font Family": "字体" - }, - "Font Scale": { - "Font Scale": "字体缩放" - }, - "Font Size": { - "Font Size": "字体大小" - }, - "Font Weight": { - "Font Weight": "字体粗细" - }, - "Font used on the login screen": { - "Font used on the login screen": "登录界面使用的字体" - }, - "Force HDR": { - "Force HDR": "强制HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "强制结束(SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "强制广色域" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "强制终端应用使用暗色" - }, - "Forecast": { - "Forecast": "预测" - }, - "Forecast Days": { - "Forecast Days": "天气预测" - }, - "Forecast Not Available": { - "Forecast Not Available": "暂无预报" - }, - "Forever": { - "Forever": "永远" - }, - "Forget": { - "Forget": "忽略" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "忘记\"%1\"?" - }, - "Forget Device": { - "Forget Device": "取消配对" - }, - "Forget Network": { - "Forget Network": "取消保存" - }, - "Forgot network %1": { - "Forgot network %1": "忘记网络%1" - }, - "Format Legend": { - "Format Legend": "参考格式" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "找到了%1个可更新的包:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "找到了%1个可更新的包:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "关闭启动器时释放显存/内存。重新打开时可能会有轻微延迟。" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "冰冷细雨" - }, - "Frequency": { - "Frequency": "频率" - }, - "Fruit Salad": { - "Fruit Salad": "水果沙拉" - }, - "Full Command:": { - "Full Command:": "完整命令:" - }, - "Full Content": { - "Full Content": "完整内容" - }, - "Full Day & Month": { - "Full Day & Month": "日期与月份全写" - }, - "Full with Year": { - "Full with Year": "年份全写" - }, - "Fullscreen": { - "Fullscreen": "全屏" - }, - "Fullscreen Only": { - "Fullscreen Only": "仅全屏" - }, - "Fully Charged": { - "Fully Charged": "已充满" - }, - "Fun": { - "Fun": "娱乐" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G:网格 • Z/X:尺寸" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "GPU监视" - }, - "GPU Temperature": { - "GPU Temperature": "GPU 温度" - }, - "GPU temperature display": { - "GPU temperature display": "显示显卡温度" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK、Qt、IDEs等" - }, - "Games": { - "Games": "游戏" - }, - "Gamma Control": { - "Gamma Control": "伽马控制" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "伽玛控制不可用,需要 DMS API v6+。" - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "创建 GTK3/4 或 QT5/QT6 (需要 qt6ct-kde)的基线配置以遵守DMS颜色。仅需一次。

        建议在应用adw-gtk3GTK主题之前进行配置。" - }, - "Generic": { - "Generic": "通用" - }, - "Get Started": { - "Get Started": "已开始" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "全局缩放所有动画持续时间" - }, - "Golden Hour": { - "Golden Hour": "黄金时段" - }, - "Good": { - "Good": "良好" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "哥特圆角半径" - }, - "Goth Corners": { - "Goth Corners": "哥特风格圆角" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "在锁定前通过可配置的宽限期逐渐淡出屏幕" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "在关闭显示器前逐渐淡出屏幕,淡出时间可配置" - }, - "Graph Time Range": { - "Graph Time Range": "图表时间范围" - }, - "Graphics": { - "Graphics": "图形" - }, - "Greeter": { - "Greeter": "欢迎界面" - }, - "Greeter Appearance": { - "Greeter Appearance": "欢迎界面外观" - }, - "Greeter Behavior": { - "Greeter Behavior": "欢迎界面行为" - }, - "Greeter Status": { - "Greeter Status": "欢迎界面状态" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "欢迎界面处于激活状态。greetd已启用。" - }, - "Greeter font": { - "Greeter font": "欢迎界面字体" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "仅欢迎界面——不影响主时钟" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "仅欢迎界面——登录界面上的日期格式" - }, - "Grid": { - "Grid": "网格" - }, - "Grid Columns": { - "Grid Columns": "网格列" - }, - "Grid: OFF": { - "Grid: OFF": "网格:关闭" - }, - "Grid: ON": { - "Grid: ON": "网格:开启" - }, - "Group": { - "Group": "分组" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "分组工作区应用" - }, - "Group by App": { - "Group by App": "按应用分组" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "将同一应用的多个窗口合并显示,并标注窗口数量" - }, - "Group removed": { - "Group removed": "分组已移除" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "在不聚焦的工作区中将重复应用图标分组" - }, - "Groups": { - "Groups": "分组" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR(EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR 色调映射" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "HDR模式仍处实验性质。请先确认你的显示器支持HDR再启用。" - }, - "HSV": { - "HSV": "色相、饱和度、明度" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML 已复制到剪切板" - }, - "Health": { - "Health": "电池健康" - }, - "Heavy Rain": { - "Heavy Rain": "大雨" - }, - "Heavy Snow": { - "Heavy Snow": "大雪" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "大雪阵" - }, - "Height": { - "Height": "高度" - }, - "Held": { - "Held": "已暂停" - }, - "Help": { - "Help": "帮助" - }, - "Hex": { - "Hex": "十六进制" - }, - "Hibernate": { - "Hibernate": "休眠" - }, - "Hidden": { - "Hidden": "已隐藏" - }, - "Hidden (%1)": { - "Hidden (%1)": "已隐藏(%1)" - }, - "Hidden Apps": { - "Hidden Apps": "已隐藏应用" - }, - "Hidden Network": { - "Hidden Network": "隐藏的网络" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "已隐藏应用不会出现在启动器中。右键应用选择“隐藏应用”以隐藏。" - }, - "Hide": { - "Hide": "隐藏" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "隐藏第三方" - }, - "Hide App": { - "Hide App": "隐藏应用" - }, - "Hide Delay": { - "Hide Delay": "隐藏延迟" - }, - "Hide Indicators": { - "Hide Indicators": "隐藏指示器" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "隐藏更新器部件" - }, - "Hide When Typing": { - "Hide When Typing": "打字时隐藏" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "当窗口打开时隐藏" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "在未激活超过此时间后隐藏光标(0为禁用)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "当按下键盘时隐藏光标" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "当使用触摸板输入时隐藏光标" - }, - "Hide device": { - "Hide device": "隐藏设备" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "隐藏通知内容,直到展开" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "隐藏通知内容,直到展开;弹窗默认显示为折叠" - }, - "Hide on Touch": { - "Hide on Touch": "当使用触摸板时隐藏光标" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "高保真配色,保留原始色调。" - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "高亮活动工作区应用" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "在工作区指示器中高亮当前聚焦的应用" - }, - "History": { - "History": "历史记录" - }, - "History Retention": { - "History Retention": "历史保留" - }, - "History Settings": { - "History Settings": "历史设置" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "历史记录已清除。仍保留%1条已固定项目。" - }, - "Hold Duration": { - "Hold Duration": "按住持续时间" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "按住更长时间以确认" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "按住以确认电源操作" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "按住以确认 (%1 ms)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "按住以确认 (%1s)" - }, - "Home": { - "Home": "家" - }, - "Host": { - "Host": "主机" - }, - "Hostname": { - "Hostname": "Hostname" - }, - "Hot Corners": { - "Hot Corners": "热区" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "热键叠加层标题(可选)" - }, - "Hour": { - "Hour": "小时" - }, - "Hourly": { - "Hourly": "每小时" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "每小时预测计数" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "壁纸轮换频率" - }, - "How the background image is scaled": { - "How the background image is scaled": "背景图片如何缩放" - }, - "Humidity": { - "Humidity": "湿度" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": " Hyprland Discord 服务器" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland布局覆盖" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland 选项" - }, - "Hyprland Website": { - "Hyprland Website": " Hyprland 网站" - }, - "I Understand": { - "I Understand": "我明白以上内容" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP 地址:" - }, - "IP address or hostname": { - "IP address or hostname": "IP地址或主机名称" - }, - "ISO Date": { - "ISO Date": "ISO日期" - }, - "Icon": { - "Icon": "图标" - }, - "Icon Scale": { - "Icon Scale": "图标缩放" - }, - "Icon Size": { - "Icon Size": "图标大小" - }, - "Icon Size %": { - "Icon Size %": "图标大小%1" - }, - "Icon Theme": { - "Icon Theme": "图标主题" - }, - "Idle": { - "Idle": "待机" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "待机抑制器" - }, - "Idle Settings": { - "Idle Settings": "待机设置" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "不支持待机监控 - 请使用新版 Quickshell" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "如果区域是隐藏的,那么当按下按键后它会尽可能早地出现。" - }, - "Ignore Completely": { - "Ignore Completely": "完全忽略" - }, - "Image": { - "Image": "图像" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "已复制图像至剪切板" - }, - "Import": { - "Import": "导入" - }, - "Import VPN": { - "Import VPN": "导入 VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "非活动显示器颜色" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "包含过渡效果" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "在搜索结果中包含桌面动作(快捷方式)" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "加载了不兼容的插件" - }, - "Incorrect password": { - "Incorrect password": "密码错误" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "密码错误——尝试 %1 / 2(随后将锁定)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "密码错误——下一次失败将触发账号锁定" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "密码错误——请重试" - }, - "Indicator Style": { - "Indicator Style": "指示样式" - }, - "Individual Batteries": { - "Individual Batteries": "分别显示电池" - }, - "Individual bar configuration": { - "Individual bar configuration": "单栏配置" - }, - "Info": { - "Info": "信息" - }, - "Inherit": { - "Inherit": "继承" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "继承全局(默认)" - }, - "Inhibitable": { - "Inhibitable": "可拒绝" - }, - "Input Devices": { - "Input Devices": "输入设备" - }, - "Input Volume Slider": { - "Input Volume Slider": "输入音量滑块" - }, - "Insert your security key...": { - "Insert your security key...": "请输入安全密钥……" - }, - "Install": { - "Install": "安装" - }, - "Install Greeter": { - "Install Greeter": "安装欢迎界面" - }, - "Install Plugin": { - "Install Plugin": "安装插件" - }, - "Install Theme": { - "Install Theme": "安装主题" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "从DMS主题注册表安装色彩主题" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "安装完成。欢迎界面已安装。" - }, - "Install failed: %1": { - "Install failed: %1": "安装失败:%1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "为动态主题安装matugen包" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "要从DMS注册表安装插件%1吗?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "从 DMS 插件库安装插件" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "要安装DMS欢迎界面吗?降打开终端以进行sudo认证。" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "要从DMS注册表安装主题%1吗?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "安装与PAM设置:请参考 " - }, - "Installed": { - "Installed": "已安装" - }, - "Installed: %1": { - "Installed: %1": "已安装:%1" - }, - "Installing: %1": { - "Installing: %1": "安装中:%1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "智能自动隐藏" - }, - "Intensity": { - "Intensity": "强度" - }, - "Interface:": { - "Interface:": "接口:" - }, - "Interlock Open": { - "Interlock Open": "安全联锁已打开" - }, - "Internet": { - "Internet": "互联网" - }, - "Interval": { - "Interval": "轮换间隔" - }, - "Invalid configuration": { - "Invalid configuration": "无效配置" - }, - "Invert on mode change": { - "Invert on mode change": "切换模式时反色" - }, - "Iris Bloom": { - "Iris Bloom": "径向绽放" - }, - "Isolate Displays": { - "Isolate Displays": "隔离显示" - }, - "Jobs": { - "Jobs": "任务" - }, - "Jobs: ": { - "Jobs: ": "任务: " - }, - "Keep Awake": { - "Keep Awake": "保持活动" - }, - "Keep Changes": { - "Keep Changes": "保持更改" - }, - "Keeping Awake": { - "Keeping Awake": "保持活动" - }, - "Kernel": { - "Kernel": "内核" - }, - "Key": { - "Key": "键" - }, - "Keybind Sources": { - "Keybind Sources": "快捷键绑定源" - }, - "Keybinds": { - "Keybinds": "快捷键绑定" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "快捷键绑定搜索设置" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "快捷键绑定与常规搜索结果并列显示" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "键盘布局名称" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "键盘快捷键" - }, - "Keys": { - "Keys": "键" - }, - "Kill": { - "Kill": "结束" - }, - "Kill Process": { - "Kill Process": "结束进程" - }, - "Kill Session": { - "Kill Session": "结束会话" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED设备" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC 频道" - }, - "LabWC Website": { - "LabWC Website": "LabWC 网站" - }, - "Large": { - "Large": "大" - }, - "Largest": { - "Largest": "更大" - }, - "Last hour": { - "Last hour": "上个小时" - }, - "Last launched %1": { - "Last launched %1": "上次启动于 %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "最后启动于%1天前" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "最后启动于%1天前" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "最后启动于%1小时前" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "最后启动于%1小时前" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "最后启动于%1分前" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "最后启动于%1分前" - }, - "Last launched just now": { - "Last launched just now": "刚刚启动" - }, - "Latitude": { - "Latitude": "纬度" - }, - "Launch": { - "Launch": "启动" - }, - "Launch Prefix": { - "Launch Prefix": "启动前缀" - }, - "Launch on dGPU": { - "Launch on dGPU": "使用独立显卡运行" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "默认在独显上启动" - }, - "Launcher": { - "Launcher": "启动器" - }, - "Launcher Button": { - "Launcher Button": "启动器按钮" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "启动器按钮 Logo" - }, - "Layout": { - "Layout": "布局" - }, - "Layout Overrides": { - "Layout Overrides": "布局覆盖" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "欢迎界面上的布局和模块位置已从你的壳同步(例如状态栏配置)。运行同步以应用。" - }, - "Left": { - "Left": "左" - }, - "Left Center": { - "Left Center": "左侧中部" - }, - "Left Section": { - "Left Section": "左侧区域" - }, - "Light Direction": { - "Light Direction": "光线方向" - }, - "Light Mode": { - "Light Mode": "浅色模式" - }, - "Light Rain": { - "Light Rain": "小雨" - }, - "Light Snow": { - "Light Snow": "小雪" - }, - "Light Snow Showers": { - "Light Snow Showers": "小雨阵" - }, - "Light mode base": { - "Light mode base": "基于明亮模式" - }, - "Light mode harmony": { - "Light mode harmony": "明亮模式和谐" - }, - "Line": { - "Line": "线条" - }, - "Line: %1": { - "Line: %1": "行:%1" - }, - "Linear": { - "Linear": "线性" - }, - "Lines: %1": { - "Lines: %1": "行数: %1" - }, - "List": { - "List": "列表" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "活力十足的配色,带有高饱和点缀色。" - }, - "Load Average": { - "Load Average": "平均负载" - }, - "Loading codecs...": { - "Loading codecs...": "加载编解码器..." - }, - "Loading keybinds...": { - "Loading keybinds...": "正在加载按键绑定..." - }, - "Loading trending...": { - "Loading trending...": "加载热搜..." - }, - "Loading...": { - "Loading...": "正在加载..." - }, - "Local": { - "Local": "本地" - }, - "Locale": { - "Locale": "区域" - }, - "Locale Settings": { - "Locale Settings": "区域设置" - }, - "Location": { - "Location": "位置" - }, - "Location Search": { - "Location Search": "位置搜索" - }, - "Lock": { - "Lock": "锁定" - }, - "Lock Screen": { - "Lock Screen": "锁屏" - }, - "Lock Screen Display": { - "Lock Screen Display": "锁屏显示" - }, - "Lock Screen Format": { - "Lock Screen Format": "锁屏格式" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "锁屏行为" - }, - "Lock Screen layout": { - "Lock Screen layout": "锁屏布局" - }, - "Lock at startup": { - "Lock at startup": "启动时锁定" - }, - "Lock before suspend": { - "Lock before suspend": "挂起前锁屏" - }, - "Lock fade grace period": { - "Lock fade grace period": "锁定淡出时间" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "锁屏认证变更会自动生效,当需要sudo认证时可能会打开终端。" - }, - "Locked": { - "Locked": "已锁定" - }, - "Log Out": { - "Log Out": "注销" - }, - "Logging in...": { - "Logging in...": "正在登录......" - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "登录认证" - }, - "Long": { - "Long": "长" - }, - "Long Text": { - "Long Text": "长文本" - }, - "Long press": { - "Long press": "长按" - }, - "Longitude": { - "Longitude": "经度" - }, - "Low Priority": { - "Low Priority": "次要通知" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "确保 KDE Connect 或 Valent 正在您的其他设备上运行" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "管理和配置插件以扩展 DMS 功能" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "至多可管理4个独立的状态栏配置。每个状态栏都有自己的位置、控件、样式和显示布局。" - }, - "Management": { - "Management": "管理" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC布局覆盖" - }, - "Manual": { - "Manual": "手动" - }, - "Manual Coordinates": { - "Manual Coordinates": "手动设置坐标" - }, - "Manual Direction": { - "Manual Direction": "手动方向" - }, - "Manual Gap Size": { - "Manual Gap Size": "手动设置间距大小" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "手动显示/隐藏" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "将窗口类名称映射到图标名称以实现正确的图标显示" - }, - "Margin": { - "Margin": "边距" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "打印耗材已用尽" - }, - "Marker Supply Low": { - "Marker Supply Low": "打印耗材不足" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "废墨仓即将饱和" - }, - "Marker Waste Full": { - "Marker Waste Full": "废墨仓已饱和" - }, - "Match Criteria": { - "Match Criteria": "匹配条件" - }, - "Matches profile: %1": { - "Matches profile: %1": "匹配配置文件:%1" - }, - "Material Colors": { - "Material Colors": "Material 配色" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "受Material设计启发的色彩主题" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "从壁纸生成的Material色彩" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "模态、弹窗与对话框上出现的阴影(受Material启发的)与提升" - }, - "Matugen Contrast": { - "Matugen Contrast": "Matugen对比度" - }, - "Matugen Missing": { - "Matugen Missing": "未找到matugen" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen 配色方案" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen 目标显示器" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen模板" - }, - "Max Edges": { - "Max Edges": "最大边缘" - }, - "Max H": { - "Max H": "最大高度" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "最大固定应用数" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "最大固定应用数 (0 = 无限制)" - }, - "Max Running Apps": { - "Max Running Apps": "最大运行应用数" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "最大运行应用数 (0 = 无限制)" - }, - "Max Volume": { - "Max Volume": "最大音量" - }, - "Max W": { - "Max W": "最大宽度" - }, - "Max apps to show": { - "Max apps to show": "应用显示上限" - }, - "Max to Edges": { - "Max to Edges": "最大至边缘" - }, - "Maximize": { - "Maximize": "最小化" - }, - "Maximize Detection": { - "Maximize Detection": "最大化检测" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "最大化部件图标" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "最大化部件文本" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "最大尺寸" - }, - "Maximum History": { - "Maximum History": "最多历史数" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "固定项目最多数量" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "指纹尝试已达最大次数。请使用密码。" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "剪切板项目记住的最大数量" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "可被保存的项目最多数量" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "保留通知的最大数量" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "已达固定项目最多数量" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "每个剪切板项目的最大尺寸" - }, - "Media": { - "Media": "媒体" - }, - "Media Controls": { - "Media Controls": "媒体控制" - }, - "Media Empty": { - "Media Empty": "缺纸" - }, - "Media Jam": { - "Media Jam": "卡纸" - }, - "Media Low": { - "Media Low": "纸张不足" - }, - "Media Needed": { - "Media Needed": "需要纸张" - }, - "Media Playback": { - "Media Playback": "媒体回放" - }, - "Media Player": { - "Media Player": "媒体播放器" - }, - "Media Player Settings": { - "Media Player Settings": "媒体播放器设置" - }, - "Media Players": { - "Media Players": "媒体播放器" - }, - "Media Players (": { - "Media Players (": "媒体播放器 (" - }, - "Media Volume": { - "Media Volume": "媒体音量" - }, - "Medium": { - "Medium": "中" - }, - "Memory": { - "Memory": "内存" - }, - "Memory Graph": { - "Memory Graph": "内存图表" - }, - "Memory Usage": { - "Memory Usage": "内存占用" - }, - "Memory usage indicator": { - "Memory usage indicator": "内存占用情况" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "消息" - }, - "Message Content": { - "Message Content": "消息内容" - }, - "Microphone": { - "Microphone": "麦克风" - }, - "Microphone Mute": { - "Microphone Mute": "麦克风静音" - }, - "Microphone Volume": { - "Microphone Volume": "麦克风音量" - }, - "Microphone settings": { - "Microphone settings": "麦克风设置" - }, - "Microphone volume control": { - "Microphone volume control": "麦克风音量控制" - }, - "Middle Section": { - "Middle Section": "中间区域" - }, - "Min H": { - "Min H": "最小高度" - }, - "Min W": { - "Min W": "最小宽度" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "围绕单一色调构建的简约配色。" - }, - "Minute": { - "Minute": "分钟" - }, - "Mirror Display": { - "Mirror Display": "镜像显示" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "缺失环境变量" - }, - "Modal Background": { - "Modal Background": "模态背景" - }, - "Modal Shadows": { - "Modal Shadows": "模态阴影" - }, - "Modals": { - "Modals": "模态" - }, - "Mode": { - "Mode": "模式" - }, - "Mode:": { - "Mode:": "模式:" - }, - "Model": { - "Model": "型号" - }, - "Modified": { - "Modified": "改装" - }, - "Modular widget bar": { - "Modular widget bar": "模块化部件状态栏" - }, - "Monitor": { - "Monitor": "监视器" - }, - "Monitor Configuration": { - "Monitor Configuration": "监视器配置" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "显示器淡出时间" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "监视使用动态主题色的壁纸" - }, - "Monochrome": { - "Monochrome": "单色" - }, - "Monocle": { - "Monocle": "单页" - }, - "Monospace Font": { - "Monospace Font": "等宽字体" - }, - "Month Date": { - "Month Date": "月份日期" - }, - "Morning": { - "Morning": "上午" - }, - "Mount Points": { - "Mount Points": "挂载点" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "鼠标指针外观" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "鼠标指针的像素尺寸" - }, - "Move": { - "Move": "移动" - }, - "Move Widget": { - "Move Widget": "移动部件" - }, - "Moving to Paused": { - "Moving to Paused": "正在暂停打印机" - }, - "Multi-Monitor": { - "Multi-Monitor": "多显示器" - }, - "Multiplexer": { - "Multiplexer": "多路器" - }, - "Multiplexer Type": { - "Multiplexer Type": "多路器类型" - }, - "Multiplexers": { - "Multiplexers": "多路器" - }, - "Music": { - "Music": "音乐" - }, - "Mute Popups": { - "Mute Popups": "禁用弹窗" - }, - "Mute popups for %1": { - "Mute popups for %1": "禁用弹窗%1" - }, - "Muted": { - "Muted": "已静音" - }, - "Muted Apps": { - "Muted Apps": "已静音应用" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "柔和配色,带来舒缓的视觉感受。" - }, - "NM not supported": { - "NM not supported": "不支持 NM" - }, - "Name": { - "Name": "名称" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "已命名工作区图标" - }, - "Navigate": { - "Navigate": "导航" - }, - "Navigation": { - "Navigation": "导航栏" - }, - "Network": { - "Network": "网络" - }, - "Network Graph": { - "Network Graph": "网络图表" - }, - "Network Info": { - "Network Info": "网络信息" - }, - "Network Information": { - "Network Information": "网络信息" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "网络名称 (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "实时网速显示" - }, - "Network Status": { - "Network Status": "网络状态" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "显示网络下载与上传速度" - }, - "Neutral": { - "Neutral": "中性" - }, - "Never": { - "Never": "从不" - }, - "Never used": { - "Never used": "从未使用" - }, - "New": { - "New": "新建" - }, - "New Key": { - "New Key": "新键" - }, - "New Keybind": { - "New Keybind": "新按键绑定" - }, - "New Notification": { - "New Notification": "新通知" - }, - "New Session": { - "New Session": "新会话" - }, - "New Window Rule": { - "New Window Rule": "新窗口规则" - }, - "New York, NY": { - "New York, NY": "纽约,美国纽约州" - }, - "New group name...": { - "New group name...": "新分组名..." - }, - "Next": { - "Next": "下一个" - }, - "Next Transition": { - "Next Transition": "下一过渡" - }, - "Night": { - "Night": "夜晚" - }, - "Night Mode": { - "Night Mode": "夜间模式" - }, - "Night Temperature": { - "Night Temperature": "夜间色温" - }, - "Night mode & gamma": { - "Night mode & gamma": "夜间模式与伽玛" - }, - "Niri Integration": { - "Niri Integration": "Niri 集成" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri布局覆盖" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri 合成器操作(聚焦、移动等)" - }, - "No": { - "No": "否" - }, - "No Active Players": { - "No Active Players": "没有正在播放的音频" - }, - "No Anim": { - "No Anim": "无动画" - }, - "No Background": { - "No Background": "无背景底色" - }, - "No Battery": { - "No Battery": "无电池" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "未找到蓝牙适配器" - }, - "No Blur": { - "No Blur": "无模糊" - }, - "No Border": { - "No Border": "无边框" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "未配置DMS快捷键" - }, - "No Dim": { - "No Dim": "无蒙眬效果" - }, - "No Focus": { - "No Focus": "无聚焦" - }, - "No GPU detected": { - "No GPU detected": "未检测到显卡" - }, - "No GPUs detected": { - "No GPUs detected": "未检测到GPU" - }, - "No History": { - "No History": "无历史记录" - }, - "No Media": { - "No Media": "当前无播放内容" - }, - "No Round": { - "No Round": "无圆角" - }, - "No Rounding": { - "No Rounding": "无圆角" - }, - "No Shadow": { - "No Shadow": "无阴影" - }, - "No VPN profiles": { - "No VPN profiles": "无 VPN 配置" - }, - "No Weather": { - "No Weather": "无天气信息" - }, - "No Weather Data": { - "No Weather Data": "无天气数据" - }, - "No Weather Data Available": { - "No Weather Data Available": "暂无天气数据" - }, - "No action": { - "No action": "无操作" - }, - "No active %1 sessions": { - "No active %1 sessions": "无活动的%1个会话" - }, - "No adapter": { - "No adapter": "无适配器" - }, - "No adapters": { - "No adapters": "无适配器" - }, - "No app customizations.": { - "No app customizations.": "无应用自定义。" - }, - "No apps found": { - "No apps found": "未找到应用" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "尚未启动任何应用。" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "无静音应用。右键点击通知并选择“禁用弹窗”以添加。" - }, - "No battery": { - "No battery": "无电池" - }, - "No brightness devices available": { - "No brightness devices available": "无可用亮度设备" - }, - "No changes": { - "No changes": "无更改" - }, - "No checks passed": { - "No checks passed": "检查未通过" - }, - "No custom theme file": { - "No custom theme file": "缺失自定义主题文件" - }, - "No devices": { - "No devices": "无设备" - }, - "No devices connected": { - "No devices connected": "未连接设备" - }, - "No devices found": { - "No devices found": "未找到设备" - }, - "No disk data": { - "No disk data": "无磁盘数据" - }, - "No disk data available": { - "No disk data available": "无可用磁盘数据" - }, - "No drivers found": { - "No drivers found": "未找到驱动程序" - }, - "No errors": { - "No errors": "无报错" - }, - "No features enabled": { - "No features enabled": "未启用功能" - }, - "No files found": { - "No files found": "未找到文件" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "未检测到指纹读取器。" - }, - "No folders found": { - "No folders found": "未找到文件夹" - }, - "No hidden apps.": { - "No hidden apps.": "无已隐藏应用。" - }, - "No info items": { - "No info items": "无信息项目" - }, - "No information available": { - "No information available": "无可用信息。" - }, - "No input device": { - "No input device": "无输入设备" - }, - "No input devices found": { - "No input devices found": "未找到输入设备" - }, - "No items added yet": { - "No items added yet": "暂未添加任何项目" - }, - "No keybinds found": { - "No keybinds found": "未找到按键绑定" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "未安装启动器插件。" - }, - "No match criteria": { - "No match criteria": "无匹配标准" - }, - "No matches": { - "No matches": "未找到匹配项" - }, - "No matching processes": { - "No matching processes": "无匹配进程" - }, - "No monitors": { - "No monitors": "无监视器" - }, - "No mount points found": { - "No mount points found": "未找到挂载点" - }, - "No output device": { - "No output device": "无输出设备" - }, - "No output devices found": { - "No output devices found": "未找到输出设备" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "未找到包管理器。请在基于Arch的系统上安装paru或yay以检测更新。" - }, - "No plugin results": { - "No plugin results": "无插件结果" - }, - "No plugins found": { - "No plugins found": "未找到插件" - }, - "No plugins found.": { - "No plugins found.": "未找到插件" - }, - "No printer found": { - "No printer found": "未找到打印机" - }, - "No printers configured": { - "No printers configured": "未配置打印机" - }, - "No printers found": { - "No printers found": "未找到打印机" - }, - "No profiles": { - "No profiles": "无配置" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "未找到近期剪切板项目" - }, - "No results found": { - "No results found": "未找到结果" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "无已保存剪切板项目" - }, - "No sessions found": { - "No sessions found": "未找到会话" - }, - "No status output.": { - "No status output.": "无状态输出。" - }, - "No themes found": { - "No themes found": "未找到主题" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "未安装主题。从注册表浏览并安装。" - }, - "No trigger": { - "No trigger": "无触发器" - }, - "No video found in folder": { - "No video found in folder": "文件夹中未找到视频" - }, - "No wallpaper selected": { - "No wallpaper selected": "未选择壁纸" - }, - "No wallpapers": { - "No wallpapers": "无壁纸" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "未找到壁纸\n\n点击下方文件夹图标以浏览" - }, - "No warnings": { - "No warnings": "无警告" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "未添加部件。点击“添加部件”以继续。" - }, - "No widgets available": { - "No widgets available": "无可用部件" - }, - "No widgets match your search": { - "No widgets match your search": "未找到匹配的部件" - }, - "No window rules configured": { - "No window rules configured": "未配置窗口规则" - }, - "None": { - "None": "无" - }, - "Normal": { - "Normal": "正常" - }, - "Normal Font": { - "Normal Font": "普通字体" - }, - "Normal Priority": { - "Normal Priority": "标准通知" - }, - "Not available": { - "Not available": "不可用" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "不可用——请安装fprintd与pam_fprintd,或者配置greetd PAM。" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "不可用——请安装fprintd与pam_fprintd。" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "不可用——请安装或配置pam_u2f,或者配置greetd PAM。" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "不可用——请安装或配置pam_u2f。" - }, - "Not connected": { - "Not connected": "未连接" - }, - "Not detected": { - "Not detected": "未检测到" - }, - "Not paired": { - "Not paired": "未配对" - }, - "Not set": { - "Not set": "未设置" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "注意:这只会改变百分比,而不会实际限制充电。" - }, - "Notepad": { - "Notepad": "便签" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "便签字体设置" - }, - "Notepad Slideout": { - "Notepad Slideout": "便签侧边栏" - }, - "Nothing": { - "Nothing": "无" - }, - "Nothing to see here": { - "Nothing to see here": "空空如也" - }, - "Notification Center": { - "Notification Center": "通知中心" - }, - "Notification Display": { - "Notification Display": "通知显示" - }, - "Notification Overlay": { - "Notification Overlay": "全屏时显示通知" - }, - "Notification Popups": { - "Notification Popups": "通知弹窗" - }, - "Notification Rules": { - "Notification Rules": "通知规则" - }, - "Notification Settings": { - "Notification Settings": "通知设置" - }, - "Notification Timeouts": { - "Notification Timeouts": "显示时长" - }, - "Notification toast popups": { - "Notification toast popups": "通知弹窗" - }, - "Notifications": { - "Notifications": "通知" - }, - "Numbers": { - "Numbers": "数字" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "数字(D/M)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "数字(M/D)" - }, - "OK": { - "OK": "OK" - }, - "OS Logo": { - "OS Logo": "系统 Logo" - }, - "OSD Position": { - "OSD Position": "OSD位置" - }, - "Occupied Color": { - "Occupied Color": "占位色" - }, - "Off": { - "Off": "关闭" - }, - "Office": { - "Office": "办公" - }, - "Offline": { - "Offline": "离线" - }, - "Offline Report": { - "Offline Report": "官方报告" - }, - "Older": { - "Older": "更早" - }, - "On": { - "On": "开启" - }, - "On-Demand": { - "On-Demand": "按需随机" - }, - "On-Screen Displays": { - "On-Screen Displays": "屏幕显示" - }, - "On-screen Displays": { - "On-screen Displays": "屏上显示" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "根据时间或位置调节伽马值。" - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "仅影响受DMS管理的PAM。如果greetd已经包含了pam_fprintd,则指纹认证将依旧保持启用。" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "在每个程序坞上仅显示当前显示器上的窗口" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "仅在休眠受系统支持时可见" - }, - "Opacity": { - "Opacity": "不透明度" - }, - "Opaque": { - "Opaque": "不透明" - }, - "Open": { - "Open": "打开" - }, - "Open App": { - "Open App": "打开应用" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "在你的手机上打开KDE Connect" - }, - "Open Notepad File": { - "Open Notepad File": "打开便签" - }, - "Open a new note": { - "Open a new note": "打开新笔记" - }, - "Open folder": { - "Open folder": "打开文件夹" - }, - "Open in Browser": { - "Open in Browser": "在浏览器中打开" - }, - "Open in terminal": { - "Open in terminal": "在终端打开" - }, - "Open search bar to find text": { - "Open search bar to find text": "打开搜索栏以查找文本" - }, - "Open with...": { - "Open with...": "打开方式..." - }, - "Opening SMS": { - "Opening SMS": "正在打开SMS" - }, - "Opening SMS app": { - "Opening SMS app": "正在打开SMS应用" - }, - "Opening file browser": { - "Opening file browser": "正在打开文件浏览器" - }, - "Opening files": { - "Opening files": "正在打开文件" - }, - "Opening terminal: ": { - "Opening terminal: ": "正在打开终端: " - }, - "Optional description": { - "Optional description": "可选描述" - }, - "Optional location": { - "Optional location": "可选位置" - }, - "Options": { - "Options": "选项" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "将部件组织成可折叠分组" - }, - "Original: %1": { - "Original: %1": "原件:%1" - }, - "Other": { - "Other": "其他" - }, - "Outline": { - "Outline": "轮廓" - }, - "Output": { - "Output": "输出" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "出纸盒即将饱和" - }, - "Output Area Full": { - "Output Area Full": "出纸盒已满" - }, - "Output Device": { - "Output Device": "输出设备" - }, - "Output Devices": { - "Output Devices": "输出设备" - }, - "Output Tray Missing": { - "Output Tray Missing": "未检测到出纸盒" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "输出包括缺失" - }, - "Overcast": { - "Overcast": "阴天" - }, - "Overflow": { - "Overflow": "溢出" - }, - "Overridden by config": { - "Overridden by config": "被配置覆盖" - }, - "Override": { - "Override": "覆盖" - }, - "Override Border Size": { - "Override Border Size": "覆盖边框尺寸" - }, - "Override Corner Radius": { - "Override Corner Radius": "覆盖角半径" - }, - "Override Gaps": { - "Override Gaps": "覆盖间隙" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "为此输出覆盖全局布局设置" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "以自定义命令或脚本覆盖终端" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "以每条状态栏的单独设置覆盖全局阴影" - }, - "Overrides": { - "Overrides": "覆盖" - }, - "Overview": { - "Overview": "概览" - }, - "Overview of your network connections": { - "Overview of your network connections": "您的网络连接概览" - }, - "Overwrite": { - "Overwrite": "覆盖" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM已提供指纹认证。启用以在登录时显示。" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM已提供安全密钥认证。启用以在登录时显示。" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM提供了指纹认证,但无法确认其可用性。" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM提供了指纹认证,但尚无注册指纹。" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM提供了指纹认证,但无法检测到读取器。" - }, - "PIN": { - "PIN": "PIN 码" - }, - "Pad": { - "Pad": "覆盖" - }, - "Pad Hours": { - "Pad Hours": "摸鱼时间" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "休息时间(02:00 vs 2:00)" - }, - "Padding": { - "Padding": "内边距" - }, - "Pair": { - "Pair": "配对" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "配对蓝牙设备" - }, - "Paired": { - "Paired": "已配对" - }, - "Pairing": { - "Pairing": "正在配对" - }, - "Pairing failed": { - "Pairing failed": "配对失败" - }, - "Pairing request from": { - "Pairing request from": "正从此处接收配对请求" - }, - "Pairing request sent": { - "Pairing request sent": "配对请求已发送" - }, - "Pairing requested": { - "Pairing requested": "配对已请求" - }, - "Pairing...": { - "Pairing...": "配对中..." - }, - "Partly Cloudy": { - "Partly Cloudy": "部分多云" - }, - "Passkey:": { - "Passkey:": "密钥:" - }, - "Password": { - "Password": "密码" - }, - "Password...": { - "Password...": "密码……" - }, - "Paste": { - "Paste": "粘贴" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "视频文件路径或包含视频的文件夹" - }, - "Pattern": { - "Pattern": "模式" - }, - "Pause": { - "Pause": "暂停" - }, - "Paused": { - "Paused": "暂停" - }, - "Pending": { - "Pending": "待定" - }, - "Pending Charge": { - "Pending Charge": "待充电" - }, - "Pending Discharge": { - "Pending Discharge": "待放电" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "按模式设置壁纸" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "按显示器设置壁纸" - }, - "Per-screen config": { - "Per-screen config": "按屏幕区分设置" - }, - "Percentage": { - "Percentage": "占用率" - }, - "Performance": { - "Performance": "性能" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "因权限问题,无法设置个人资料图片。" - }, - "Personalization": { - "Personalization": "个性化" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "手机连接不可用" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "手机连接不可用" - }, - "Phone number": { - "Phone number": "电话号码" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "每次都从同一文件夹下选择随机的视频" - }, - "Pictures": { - "Pictures": "图片" - }, - "Pin": { - "Pin": "固定" - }, - "Pin to Dock": { - "Pin to Dock": "固定到程序坞" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping 已发送" - }, - "Ping sent to": { - "Ping sent to": "Ping 已发送至" - }, - "Pinned": { - "Pinned": "已固定" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "拖拽松开已固定和运行中应用" - }, - "Pixelate": { - "Pixelate": "像素化" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "此处为插件目录,每个插件应带有一个 plugin.json 描述文件。" - }, - "Place plugins in %1": { - "Place plugins in %1": "将插件放在%1" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "锁屏是播放视频。" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "有新通知时播放声音" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "连接电源线时播放声音" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "当音量调整时播放声音" - }, - "Play sounds for system events": { - "Play sounds for system events": "为系统事件播放声音" - }, - "Playback": { - "Playback": "播放" - }, - "Playback error: ": { - "Playback error: ": "播放错误: " - }, - "Please wait...": { - "Please wait...": "请稍候..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "请问您的新会话%1起名" - }, - "Plugged In": { - "Plugged In": "连接电源" - }, - "Plugged in": { - "Plugged in": "插件已置入" - }, - "Plugin": { - "Plugin": "插件" - }, - "Plugin Directory": { - "Plugin Directory": "插件目录" - }, - "Plugin Management": { - "Plugin Management": "插件管理" - }, - "Plugin Visibility": { - "Plugin Visibility": "插件可视化" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "插件已禁用 - 请在插件设置中启用以继续" - }, - "Plugins": { - "Plugins": "插件" - }, - "Pointer": { - "Pointer": "指示器" - }, - "Popout Shadows": { - "Popout Shadows": "弹窗阴影" - }, - "Popouts": { - "Popouts": "弹窗" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "弹窗与模态遵守全局动画速度(禁用以创建自定义独立规则)" - }, - "Popup Only": { - "Popup Only": "仅弹窗" - }, - "Popup Position": { - "Popup Position": "弹出位置" - }, - "Popup Shadow": { - "Popup Shadow": "弹窗阴影" - }, - "Popup Transparency": { - "Popup Transparency": "弹窗透明度" - }, - "Popup behavior, position": { - "Popup behavior, position": "弹窗行为与位置" - }, - "Port": { - "Port": "端口" - }, - "Portal": { - "Portal": "传送门" - }, - "Position": { - "Position": "位置" - }, - "Position, pinned apps": { - "Position, pinned apps": "位置与已固定应用" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "可能的覆盖冲突" - }, - "Power": { - "Power": "电源" - }, - "Power & Security": { - "Power & Security": "电源与安全" - }, - "Power & Sleep": { - "Power & Sleep": "电源与睡眠" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "电源操作确认" - }, - "Power Menu Customization": { - "Power Menu Customization": "自定义电源菜单" - }, - "Power Off": { - "Power Off": "关机" - }, - "Power Options": { - "Power Options": "电源菜单" - }, - "Power Profile": { - "Power Profile": "电源配置文件" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "电源配置性能下降" - }, - "Power Saver": { - "Power Saver": "省电" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "锁定时关闭显示器" - }, - "Power profile management available": { - "Power profile management available": "电源配置文件管理可用" - }, - "Power source": { - "Power source": "电源" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "在欢迎界面上预先填写上次成功登录的用户名" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "在欢迎界面预先选择上次使用的会话" - }, - "Precip": { - "Precip": "降水" - }, - "Precipitation": { - "Precipitation": "降水量" - }, - "Precipitation Chance": { - "Precipitation Chance": "降水概率" - }, - "Preference": { - "Preference": "偏好设置" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "预设宽度(%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "按下n或点击“新会话”以创建" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "按回车键,音频系统会重启以应用更改" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "按回车以粘贴,按Shift+回车以复制" - }, - "Press key...": { - "Press key...": "按键..." - }, - "Pressure": { - "Pressure": "气压" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "防止屏幕超时" - }, - "Preview": { - "Preview": "预览" - }, - "Primary": { - "Primary": "主题色" - }, - "Primary Container": { - "Primary Container": "首选容器" - }, - "Print Server Management": { - "Print Server Management": "打印服务器管理" - }, - "Print Server not available": { - "Print Server not available": "打印服务不可用" - }, - "Printer": { - "Printer": "打印机" - }, - "Printer Classes": { - "Printer Classes": "打印机类别" - }, - "Printer created successfully": { - "Printer created successfully": "打印机创建成功" - }, - "Printer deleted": { - "Printer deleted": "打印机已删除" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "打印机名称(无空格)" - }, - "Printer reachable": { - "Printer reachable": "打印机可达" - }, - "Printers": { - "Printers": "打印机" - }, - "Printers: ": { - "Printers: ": "打印机: " - }, - "Prioritize performance": { - "Prioritize performance": "优先考虑性能" - }, - "Priority": { - "Priority": "优先级" - }, - "Privacy Indicator": { - "Privacy Indicator": "隐私指示器" - }, - "Privacy Mode": { - "Privacy Mode": "隐私模式" - }, - "Private Key Password": { - "Private Key Password": "私钥密码" - }, - "Process Count": { - "Process Count": "进程计数" - }, - "Processes": { - "Processes": "进程" - }, - "Processes:": { - "Processes:": "进程:" - }, - "Processing": { - "Processing": "处理中" - }, - "Profile Image Error": { - "Profile Image Error": "个人资料图片错误" - }, - "Profile activated: %1": { - "Profile activated: %1": "已激活档案:%1" - }, - "Profile deleted": { - "Profile deleted": "配置已删除" - }, - "Profile error": { - "Profile error": "档案错误" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "个人资料图片过大,请选择更小的图片。" - }, - "Profile name": { - "Profile name": "档案名称" - }, - "Profile not found": { - "Profile not found": "未找到配置" - }, - "Profile saved: %1": { - "Profile saved: %1": "已保存档案:%1" - }, - "Protocol": { - "Protocol": "协议" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia不可用" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia不可用——视频屏保需要qt multimedia服务" - }, - "Quick Access": { - "Quick Access": "快速访问" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "快捷访问应用启动器" - }, - "Quick access to color picker": { - "Quick access to color picker": "快捷访问取色器" - }, - "Quick access to notepad": { - "Quick access to notepad": "快捷访问剪切板" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "便于快速记便签的侧边栏面板" - }, - "Quick system toggles": { - "Quick system toggles": "快速系统切换" - }, - "RGB": { - "RGB": "红绿蓝" - }, - "Radius": { - "Radius": "半径" - }, - "Rain": { - "Rain": "下雨" - }, - "Rain Chance": { - "Rain Chance": "降雨概率" - }, - "Rainbow": { - "Rainbow": "彩虹" - }, - "Random": { - "Random": "随机" - }, - "Rate": { - "Rate": "速率" - }, - "Read:": { - "Read:": "读取:" - }, - "Reason": { - "Reason": "原因" - }, - "Reboot": { - "Reboot": "重启" - }, - "Recent Colors": { - "Recent Colors": "最近拾取的颜色" - }, - "Recently Used Apps": { - "Recently Used Apps": "最近使用的应用" - }, - "Recommended available": { - "Recommended available": "推荐可用" - }, - "Refresh": { - "Refresh": "刷新" - }, - "Refresh Weather": { - "Refresh Weather": "刷新天气" - }, - "Regex": { - "Regex": "正则" - }, - "Reject": { - "Reject": "拒绝" - }, - "Reject Jobs": { - "Reject Jobs": "拒绝任务" - }, - "Release": { - "Release": "松开" - }, - "Reload Plugin": { - "Reload Plugin": "重载插件" - }, - "Remaining": { - "Remaining": "剩余" - }, - "Remaining / Total": { - "Remaining / Total": "剩余/总计" - }, - "Remember Last Query": { - "Remember Last Query": "记忆上次查询" - }, - "Remember last session": { - "Remember last session": "记住上次的会话" - }, - "Remember last user": { - "Remember last user": "记住上次的用户" - }, - "Remove": { - "Remove": "移除" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "移除部件填充" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "当窗口最大化时移除间距和边框" - }, - "Rename": { - "Rename": "重命名" - }, - "Rename Session": { - "Rename Session": "重命名会话" - }, - "Rename Workspace": { - "Rename Workspace": "重命名工作区" - }, - "Repeat": { - "Repeat": "重复" - }, - "Replacement": { - "Replacement": "替换" - }, - "Report": { - "Report": "报告" - }, - "Request Pairing": { - "Request Pairing": "请求配对" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "要求按住按钮/键以确认关机、重启、休眠、挂起和注销" - }, - "Required plugin: ": { - "Required plugin: ": "需要插件: " - }, - "Requires %1": { - "Requires %1": "需要%1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "需要dgop工具" - }, - "Requires DMS %1": { - "Requires DMS %1": "需要DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "需要 DWL 合成器" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "需要更新版本的Quickshell" - }, - "Requires night mode support": { - "Requires night mode support": "需要夜间模式支持" - }, - "Reset": { - "Reset": "重置" - }, - "Reset Position": { - "Reset Position": "重置位置" - }, - "Reset Size": { - "Reset Size": "重置尺寸" - }, - "Reset to default name": { - "Reset to default name": "重置为默认名称" - }, - "Resize Widget": { - "Resize Widget": "调整部件大小" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "分辨率与刷新率" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "分辨率、位置与缩放" - }, - "Restart DMS": { - "Restart DMS": "重启 DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "重启 DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "正在重启音频系统..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "恢复特殊工作区窗口" - }, - "Resume": { - "Resume": "恢复" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "反转滚动方向" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "当在状态栏上滚动时,反转工作区切换方向" - }, - "Revert": { - "Revert": "恢复: " - }, - "Right": { - "Right": "右侧" - }, - "Right Center": { - "Right Center": "右侧中部" - }, - "Right Section": { - "Right Section": "右侧区域" - }, - "Right Tiling": { - "Right Tiling": "右侧平铺" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "在部件上右键点击并拖拽任意位置" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "右键点击并拖拽右下角" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "点击状态栏上小部件以轮换" - }, - "Ring": { - "Ring": "响铃" - }, - "Ringing": { - "Ringing": "响铃" - }, - "Ripple Effects": { - "Ripple Effects": "波纹效果" - }, - "Root Filesystem": { - "Root Filesystem": "根文件系统" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "窗口圆角" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "窗口圆角(border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "窗口圆角(decoration.rounding)" - }, - "Rule": { - "Rule": "规则" - }, - "Rule Name": { - "Rule Name": "规则名称" - }, - "Rules (%1)": { - "Rules (%1)": "规则(%1)" - }, - "Run Again": { - "Run Again": "启动应用" - }, - "Run DMS Templates": { - "Run DMS Templates": "运行DMS模板" - }, - "Run User Templates": { - "Run User Templates": "运行用户模板" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "运行程序(例如:firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "运行 shell 命令(例如:notify-send)" - }, - "Running Apps": { - "Running Apps": "活动应用程序" - }, - "Running Apps Settings": { - "Running Apps Settings": "活动应用设置" - }, - "Running greeter sync…": { - "Running greeter sync…": "执行欢迎界面同步……" - }, - "SDR Brightness": { - "SDR Brightness": "SDR亮度" - }, - "SDR Saturation": { - "SDR Saturation": "SDR饱和度" - }, - "SMS": { - "SMS": "SMS" - }, - "Save": { - "Save": "保存" - }, - "Save Notepad File": { - "Save Notepad File": "保存便签" - }, - "Save QR Code": { - "Save QR Code": "保存二维码" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "保存并切换显示配置" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "将关键优先级通知保存至历史" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "将已关闭通知保存至历史" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "将低优先级通知保存至历史" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "将一般优先级通知保存至历史" - }, - "Save password": { - "Save password": "保存密码" - }, - "Saved": { - "Saved": "已保存" - }, - "Saved Configurations": { - "Saved Configurations": "已保存的配置" - }, - "Saved Note": { - "Saved Note": "已保存笔记" - }, - "Saved item deleted": { - "Saved item deleted": "保存项目已删除" - }, - "Saving...": { - "Saving...": "保存中..." - }, - "Scale": { - "Scale": "缩放" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "独立调整 DankBar 字体缩放" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "独立缩放DankBar图标大小" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "缩放整个 shell 中的所有字体大小" - }, - "Scan": { - "Scan": "扫描" - }, - "Scanning": { - "Scanning": "扫描中" - }, - "Scanning...": { - "Scanning...": "正在扫描..." - }, - "Science": { - "Science": "科学" - }, - "Score": { - "Score": "分数" - }, - "Screen Sharing": { - "Screen Sharing": "屏幕共享" - }, - "Screen sharing": { - "Screen sharing": "屏幕分享" - }, - "Scroll": { - "Scroll": "滚动" - }, - "Scroll Factor": { - "Scroll Factor": "滚动系数" - }, - "Scroll GitHub": { - "Scroll GitHub": "滚动GitHub" - }, - "Scroll Wheel": { - "Scroll Wheel": "滚动滚轮" - }, - "Scroll song title": { - "Scroll song title": "滚动歌曲标题" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "如果在部件中标题不适配,则可以滚动标题" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "媒体部件上的滚轮行为" - }, - "Scrolling": { - "Scrolling": "滚动" - }, - "Search App Actions": { - "Search App Actions": "搜索应用动作" - }, - "Search Options": { - "Search Options": "搜索选项" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "通过按键组合、描述或动作名称进行搜索。\n\n默认操作是将按键绑定复制到剪贴板。\n右键或右箭头可以固定常用的快捷键——不搜索时它们会出现在顶部。" - }, - "Search for a location...": { - "Search for a location...": "搜索位置..." - }, - "Search keybinds...": { - "Search keybinds...": "搜索按键绑定..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "从合成器与应用中搜索键盘快捷键" - }, - "Search plugins...": { - "Search plugins...": "搜索插件中..." - }, - "Search processes...": { - "Search processes...": "正在搜索进程..." - }, - "Search sessions...": { - "Search sessions...": "搜索会话……" - }, - "Search themes...": { - "Search themes...": "主题搜索中..." - }, - "Search widgets...": { - "Search widgets...": "搜索部件..." - }, - "Search...": { - "Search...": "搜索中..." - }, - "Searching...": { - "Searching...": "检索中..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "次选因素(AND)" - }, - "Secondary": { - "Secondary": "次要" - }, - "Secured": { - "Secured": "安全" - }, - "Security": { - "Security": "安全性" - }, - "Security & privacy": { - "Security & privacy": "安全与隐私" - }, - "Security key mode": { - "Security key mode": "安全密钥模式" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "无法确认安全密钥的可用性。" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "已检测到安全密钥支持,但尚无注册的密钥。您可以启用,并在稍后进行注册。" - }, - "Select": { - "Select": "选择" - }, - "Select Application": { - "Select Application": "选择应用程序" - }, - "Select Bar": { - "Select Bar": "选择状态栏" - }, - "Select Custom Theme": { - "Select Custom Theme": "选择自定义主题" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "选择程序坞启动器logo" - }, - "Select File to Send": { - "Select File to Send": "选择要发送的文件" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "选择启动器Logo" - }, - "Select Profile Image": { - "Select Profile Image": "选择个人信息图像" - }, - "Select Video or Folder": { - "Select Video or Folder": "请选择视频或文件夹" - }, - "Select Wallpaper": { - "Select Wallpaper": "选择壁纸" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "选择壁纸位置" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "从调色板中选择颜色,或使用自定义滑块" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "选择要添加至桌面的部件。每个部件均为独立实例,拥有自己的设置。" - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "选择要添加的部件。如果需要,您可以添加同一部件的多个实例。" - }, - "Select a window...": { - "Select a window...": "选择窗口..." - }, - "Select an image file...": { - "Select an image file...": "选择一张图片..." - }, - "Select at least one provider": { - "Select at least one provider": "至少选择一个提供源" - }, - "Select device": { - "Select device": "选择设备" - }, - "Select device...": { - "Select device...": "选择设备..." - }, - "Select driver...": { - "Select driver...": "选择驱动程序..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "选择 UI 文本的字体粗细" - }, - "Select greeter background image": { - "Select greeter background image": "请选择欢迎界面背景图片" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "选择要设置壁纸的屏幕" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "使用等宽字体显示进程和技术内容" - }, - "Select network": { - "Select network": "选择网络" - }, - "Select system sound theme": { - "Select system sound theme": "选择系统声音主题" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "选择 UI 文本的字体族" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "选择从壁纸取色的配色方案" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "选择快捷键绑定提供源以导入" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "选择在随机轮换中使用的过渡效果" - }, - "Select...": { - "Select...": "选择..." - }, - "Selected image file not found.": { - "Selected image file not found.": "未找到所选图像文件。" - }, - "Send": { - "Send": "发送" - }, - "Send Clipboard": { - "Send Clipboard": "发送剪切板" - }, - "Send File": { - "Send File": "发送文件" - }, - "Send SMS": { - "Send SMS": "发送SMS" - }, - "Sending": { - "Sending": "发送中" - }, - "Separator": { - "Separator": "分隔符" - }, - "Server": { - "Server": "服务器" - }, - "Session Filter": { - "Session Filter": "会话筛选器" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "设置自定义设备名称" - }, - "Set custom name": { - "Set custom name": "设置自定义名称" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "为您的音频输入设备设置自定义名称" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "为您的音频输出设备设置自定义名称" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "分别为各个显示器设置壁纸" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "分别设置浅色/深色模式下的壁纸" - }, - "Set key and action to save": { - "Set key and action to save": "设置要保存的键和操作" - }, - "Set notification rules": { - "Set notification rules": "设置通知规则" - }, - "Settings": { - "Settings": "设置" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "设置处于只读状态。更改将不会保存。" - }, - "Setup": { - "Setup": "设置" - }, - "Shadow Color": { - "Shadow Color": "阴影颜色" - }, - "Shadow Intensity": { - "Shadow Intensity": "阴影强度" - }, - "Shadow Opacity": { - "Shadow Opacity": "阴影不透明度" - }, - "Shadow Override": { - "Shadow Override": "阴影覆盖" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "在状态栏与面板上的阴影提升" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "在模态与对话框上的阴影提升" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "在弹窗、OSD与下拉框上的阴影提升" - }, - "Shadows": { - "Shadows": "阴影" - }, - "Share": { - "Share": "共享" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "共享伽马控制设置" - }, - "Share Text": { - "Share Text": "共享文本" - }, - "Share URL": { - "Share URL": "共享网址" - }, - "Shared": { - "Shared": "已共享" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: 清空 • Esc: 关闭" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "按Shift+Enter以粘贴" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+回车:复制 • Shift+Del:全部清除 • Esc:关闭" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter:粘贴 • Shift+Del:清除所有 • Esc:关闭" - }, - "Short": { - "Short": "短" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "快捷方式(%1)" - }, - "Shortcuts": { - "Shortcuts": "快捷键" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "快捷键(%1)" - }, - "Show": { - "Show": "显示" - }, - "Show 3rd Party": { - "Show 3rd Party": "显示第三方" - }, - "Show All Tags": { - "Show All Tags": "显示所有标签" - }, - "Show Badge": { - "Show Badge": "显示标记" - }, - "Show CPU": { - "Show CPU": "显示CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "显示CPU图表" - }, - "Show CPU Temp": { - "Show CPU Temp": "显示CPU温度" - }, - "Show Date": { - "Show Date": "显示日期" - }, - "Show Disk": { - "Show Disk": "显示磁盘" - }, - "Show Dock": { - "Show Dock": "显示程序坞" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "显示感官温度" - }, - "Show Footer": { - "Show Footer": "显示页脚" - }, - "Show Forecast": { - "Show Forecast": "显示天气预测" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "显示GPU温度" - }, - "Show Header": { - "Show Header": "显示表头" - }, - "Show Hibernate": { - "Show Hibernate": "显示休眠" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "显示小时数" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "显示每小时天气预测" - }, - "Show Humidity": { - "Show Humidity": "显示湿度" - }, - "Show Launcher Button": { - "Show Launcher Button": "显示启动器按钮" - }, - "Show Line Numbers": { - "Show Line Numbers": "显示行号" - }, - "Show Location": { - "Show Location": "显示位置" - }, - "Show Lock": { - "Show Lock": "显示锁定" - }, - "Show Log Out": { - "Show Log Out": "显示注销" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "在交互元素上显示Material设计的波纹动画" - }, - "Show Media Player": { - "Show Media Player": "显示媒体播放器" - }, - "Show Memory": { - "Show Memory": "显示内存" - }, - "Show Memory Graph": { - "Show Memory Graph": "显示内存图表" - }, - "Show Memory in GB": { - "Show Memory in GB": "以GB为单位显示内存" - }, - "Show Network": { - "Show Network": "显示网络" - }, - "Show Network Graph": { - "Show Network Graph": "显示网络图表" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "仅显示占用工作区" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "显示溢出徽标计数" - }, - "Show Password Field": { - "Show Password Field": "显示密码区域" - }, - "Show Power Actions": { - "Show Power Actions": "显示电源操作" - }, - "Show Power Off": { - "Show Power Off": "显示关机" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "显示降水概率" - }, - "Show Pressure": { - "Show Pressure": "显示气压" - }, - "Show Profile Image": { - "Show Profile Image": "显示用户头像" - }, - "Show Reboot": { - "Show Reboot": "显示重启" - }, - "Show Restart DMS": { - "Show Restart DMS": "显示重启 DMS" - }, - "Show Saved Items": { - "Show Saved Items": "显示已保存的项目" - }, - "Show Seconds": { - "Show Seconds": "显示秒数" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "显示日出/日落" - }, - "Show Suspend": { - "Show Suspend": "显示挂起" - }, - "Show Swap": { - "Show Swap": "显示Swap" - }, - "Show System Date": { - "Show System Date": "显示系统日期" - }, - "Show System Icons": { - "Show System Icons": "显示系统图标" - }, - "Show System Time": { - "Show System Time": "显示系统时间" - }, - "Show Top Processes": { - "Show Top Processes": "显示占用多的进程" - }, - "Show Weather Condition": { - "Show Weather Condition": "显示天气状况" - }, - "Show Week Number": { - "Show Week Number": "显示周数" - }, - "Show Welcome": { - "Show Welcome": "显示欢迎信息" - }, - "Show Wind Speed": { - "Show Wind Speed": "显示风速" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "显示工作区内应用" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "显示所有 9 个标签,而非仅占用的标签(仅限 DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "在聚焦工作区指示器周围显示一个轮廓环" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "在多媒体部件中显示cava音频可视化" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "在对话框后显示暗色遮罩" - }, - "Show device": { - "Show device": "显示设备" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "当浮动窗口不覆盖其区域时显示程序坞" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "在通知弹窗上显示下拉阴影。需要在主题与颜色中启用M3提升。" - }, - "Show in GB": { - "Show in GB": "以GB为单位" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "在 Niri 概览中打字时显示启动器叠加层。禁用该项以使用其他启动器。" - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "在底部显示模式切换与键盘提示。" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "仅在当前聚焦的显示器上显示通知弹窗" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "仅在当前聚焦的显示器上显示通知" - }, - "Show on Last Display": { - "Show on Last Display": "上一个显示器" - }, - "Show on Overlay": { - "Show on Overlay": "保持前台显示" - }, - "Show on Overview": { - "Show on Overview": "概览中显示" - }, - "Show on Overview Only": { - "Show on Overview Only": "仅在概览中显示" - }, - "Show on all connected displays": { - "Show on all connected displays": "在所有已连接的显示器上显示" - }, - "Show on screens:": { - "Show on screens:": "选择显示的屏幕:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "当亮度改变时显示 OSD" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "当大小写状态变化时显示 OSD" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "当循环切换音频输出设备时显示 OSD" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "当空闲抑制状态改变时显示 OSD" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "当媒体播放器状态改变时显示OSD" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "当媒体音量改变时显示OSD" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "当麦克风静音状态切换时显示 OSD" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "当电源配置改变时显示 OSD" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "当音量变化时显示 OSD" - }, - "Show seconds": { - "Show seconds": "显示秒" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "在顶栏和控制中心显示天气信息" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "在日历中显示周数" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "在顶栏工作区切换器中显示工作区索引号" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "在水平状态栏上显示工作区名称,而在垂直状态栏上显示首字母。" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "显示当前聚焦显示器的工作区" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "显示所有正在运行应用程序,并标记焦点所在" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "显示当前工作区并支持快速切换" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "大写锁定时显示" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "显示麦克风、摄像头或屏幕共享的使用状态" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "关机" - }, - "Signal": { - "Signal": "信号" - }, - "Signal:": { - "Signal:": "信号:" - }, - "Size": { - "Size": "尺寸" - }, - "Size Constraints": { - "Size Constraints": "大小限制" - }, - "Size Offset": { - "Size Offset": "尺寸偏移" - }, - "Sizing": { - "Sizing": "大小调整" - }, - "Skip": { - "Skip": "跳过" - }, - "Skip confirmation": { - "Skip confirmation": "跳过确认" - }, - "Skip setup": { - "Skip setup": "跳过设置" - }, - "Small": { - "Small": "小" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "智能卡认证" - }, - "Smartcard PIN": { - "Smartcard PIN": "智能卡PIN" - }, - "Snap": { - "Snap": "快照" - }, - "Snow": { - "Snow": "下雪" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "有些插件需要更新版的 DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "按字母顺序排序" - }, - "Sort By": { - "Sort By": "按顺序排列" - }, - "Sorting & Layout": { - "Sorting & Layout": "排序与布局" - }, - "Sound Theme": { - "Sound Theme": "声音主题" - }, - "Sounds": { - "Sounds": "声音" - }, - "Space between windows": { - "Space between windows": "窗口间空隙" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "窗口间隙(gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "窗口间隙(gaps_in与gaps_out)" - }, - "Spacer": { - "Spacer": "空白占位" - }, - "Spacing": { - "Spacing": "间距" - }, - "Speaker settings": { - "Speaker settings": "扬声器设置" - }, - "Speed": { - "Speed": "速度" - }, - "Spool Area Full": { - "Spool Area Full": "打印缓冲区已满" - }, - "Square Corners": { - "Square Corners": "直角边框" - }, - "Stacked": { - "Stacked": "堆叠" - }, - "Standard": { - "Standard": "基础设置" - }, - "Start": { - "Start": "开始" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "启动KDE Connect 或 Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "启动 KDE Connect 或 Valent 以使用此插件" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "请在这里记录你的笔记..." - }, - "State": { - "State": "状态" - }, - "Status": { - "Status": "状态" - }, - "Stopped": { - "Stopped": "已停止" - }, - "Stopped Partly": { - "Stopped Partly": "部分停止" - }, - "Stopping": { - "Stopping": "正在停止" - }, - "Stretch": { - "Stretch": "拉伸" - }, - "Stripes": { - "Stripes": "条纹" - }, - "Summary": { - "Summary": "概要" - }, - "Sunrise": { - "Sunrise": "日出" - }, - "Sunset": { - "Sunset": "日落" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "启用时抑制通知弹出窗口" - }, - "Surface": { - "Surface": "表面色" - }, - "Surface Variant": { - "Surface Variant": "表面变体" - }, - "Suspend": { - "Suspend": "挂起" - }, - "Suspend behavior": { - "Suspend behavior": "挂起行为" - }, - "Suspend system after": { - "Suspend system after": "在此时间后挂起系统" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "挂起后休眠" - }, - "Sway Website": { - "Sway Website": "Sway 网站" - }, - "Switch User": { - "Switch User": "切换用户" - }, - "Switch to power profile": { - "Switch to power profile": "切换至电源配置" - }, - "Sync": { - "Sync": "同步" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "同步系统深色模式" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "同步弹窗与模态" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "在显示器间同步位置" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "同步已完成。" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "随系统设置开启深色模式,以适配全局主题" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "后台模式同步失败。正尝试终端模式以进行交互式认证。" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "同步需要 sudo 身份验证。正在打开终端,以便您可以使用密码或指纹。" - }, - "System": { - "System": "系统工具" - }, - "System App Theming": { - "System App Theming": "系统应用主题设置" - }, - "System Check": { - "System Check": "系统检查" - }, - "System Default": { - "System Default": "系统默认" - }, - "System Information": { - "System Information": "系统信息" - }, - "System Monitor": { - "System Monitor": "系统监视器" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "系统监测不可用" - }, - "System Sounds": { - "System Sounds": "系统声音" - }, - "System Tray": { - "System Tray": "系统托盘" - }, - "System Update": { - "System Update": "系统更新" - }, - "System Updater": { - "System Updater": "系统更新" - }, - "System Updates": { - "System Updates": "系统更新" - }, - "System notification area icons": { - "System notification area icons": "系统通知区域图标" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "系统声音不可用。请安装 %1 以获得声音支持。" - }, - "System theme toggle": { - "System theme toggle": "切换系统主题" - }, - "System toast notifications": { - "System toast notifications": "系统弹出式通知" - }, - "System update custom command": { - "System update custom command": "自定义系统更新命令" - }, - "Tab": { - "Tab": "标签" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: 导航 • ←→↑↓: 网格导航 • 回车/空格: 选中" - }, - "Terminal": { - "Terminal": "终端" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "终端自定义附加参数" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "终端回滚失败。请安装支持的终端模拟器,或者手动运行dms auth sync。" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "终端回退失败。请安装受支持的终端模拟器之一,或手动运行“dms greeter sync”。" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "终端回滚已打开。请在那里完成认证配置,结束时会自动关闭。" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "终端回退已打开。同步将在该处完成;完成后将自动关闭。" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "要使用的终端多路器后端" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "终端已打开。请在那里完成认证配置,结束时会自动关闭。" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "终端已打开。请在终端完成同步身份验证;完成后将自动关闭。" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "终端总使用暗色主题" - }, - "Test Connection": { - "Test Connection": "测试连接" - }, - "Test Page": { - "Test Page": "测试页" - }, - "Test page sent to printer": { - "Test page sent to printer": "测试页已发送到打印机" - }, - "Testing...": { - "Testing...": "测试中……" - }, - "Text": { - "Text": "文本" - }, - "Text Color": { - "Text Color": "文本颜色" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "系统监视器功能需要dgop。\n请安装dgop以使用此功能。" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "未设置 DMS_SOCKET 环境变量或套接字不可用,无法使用自动插件管理。" - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "以下设置将修改您的 GTK 和 Qt 配置。如需保留当前配置,请先备份 (qt5ct.conf|qt6ct.conf 和 ~/.config/gtk-3.0|gtk-4.0)。" - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "连接会话时使用的自定义命令(将接收会话名称作为首个参数)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "打印任务队列为空" - }, - "Theme & Colors": { - "Theme & Colors": "主题与配色" - }, - "Theme Color": { - "Theme Color": "主题色" - }, - "Theme Registry": { - "Theme Registry": "主题注册表" - }, - "Themes": { - "Themes": "主题" - }, - "Thickness": { - "Thickness": "厚度" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "外部插件警示" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "第三方插件由社区创建,且不被 DankMaterialShell 官方支持。\n\n这些插件可能存在安全和隐私风险——安装时请自行承担风险。" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "此绑定已被 config.kdl 覆盖" - }, - "This may take a few seconds": { - "This may take a few seconds": "此操作可能会花费一些时间" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "该插件没有“settings_write”权限。\n\n请在plugin.json中添加 \"permissions\": [\"settings_read\", \"settings_write\"]" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "此部件会阻止 GPU 进入省电状态,可能会显著影响笔记本的电池续航。不建议在配备混合显卡的笔记本上使用。" - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "此操作将删除所有已取消固定的项目。%1个已固定项目将被保留。" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "此操作会清空剪贴板历史,且无法恢复。" - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "此操作会永久移除已保存的剪贴板项目。此操作将无法撤销。" - }, - "Thunderstorm": { - "Thunderstorm": "雷暴" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "雷暴伴冰雹" - }, - "Tile": { - "Tile": "平铺" - }, - "Tile H": { - "Tile H": "水平平铺" - }, - "Tile V": { - "Tile V": "垂直平铺" - }, - "Tiled": { - "Tiled": "已平铺" - }, - "Tiled State": { - "Tiled State": "已平铺状态" - }, - "Tiling": { - "Tiling": "平铺" - }, - "Time": { - "Time": "时间" - }, - "Time & Date Locale": { - "Time & Date Locale": "时间与日期区域" - }, - "Time & Weather": { - "Time & Weather": "时间与天气" - }, - "Time Format": { - "Time Format": "时间格式" - }, - "Time format": { - "Time format": "时间格式" - }, - "Time remaining: %1": { - "Time remaining: %1": "剩余时间:%1" - }, - "Time until full: %1": { - "Time until full: %1": "充满时间:%1" - }, - "Timed Out": { - "Timed Out": "超时" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "关键优先级通知的超时时间" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "低优先级通知的超时时间" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "普通优先级通知的超时时间" - }, - "Title": { - "Title": "标题" - }, - "Title regex (optional)": { - "Title regex (optional)": "标题正则(可选)" - }, - "To Full": { - "To Full": "充至满电" - }, - "To update, run the following command:": { - "To update, run the following command:": "请运行以下命令以更新:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "要使用此 DMS 绑定,请删除或更改 config.kdl 中的按键绑定" - }, - "Toast Messages": { - "Toast Messages": "弹出式信息" - }, - "Today": { - "Today": "今日" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "显示/隐藏当前状态栏配置" - }, - "Toggling...": { - "Toggling...": "正在切换..." - }, - "Tomorrow": { - "Tomorrow": "明日" - }, - "Tonal Spot": { - "Tonal Spot": "音色斑点" - }, - "Toner Empty": { - "Toner Empty": "碳粉已用尽" - }, - "Toner Low": { - "Toner Low": "碳粉不足" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "过多尝试次数——已锁定" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "失败次数太多——账号将会被锁定" - }, - "Tools": { - "Tools": "工具" - }, - "Top": { - "Top": "顶部" - }, - "Top (Default)": { - "Top (Default)": "顶部(默认)" - }, - "Top Bar Format": { - "Top Bar Format": "顶栏格式" - }, - "Top Center": { - "Top Center": "顶部中间" - }, - "Top Left": { - "Top Left": "左上" - }, - "Top Processes": { - "Top Processes": "占用多的进程" - }, - "Top Right": { - "Top Right": "右上" - }, - "Top Section": { - "Top Section": "顶部区域" - }, - "Total": { - "Total": "总计" - }, - "Total Jobs": { - "Total Jobs": "总任务数" - }, - "Touch your security key...": { - "Touch your security key...": "请触摸你的安全密钥……" - }, - "Transform": { - "Transform": "变换" - }, - "Transition Effect": { - "Transition Effect": "过渡效果" - }, - "Transparency": { - "Transparency": "透明度" - }, - "Trending GIFs": { - "Trending GIFs": "热门动图" - }, - "Trending Stickers": { - "Trending Stickers": "热门贴纸" - }, - "Trigger": { - "Trigger": "触发" - }, - "Trigger Prefix": { - "Trigger Prefix": "触发前缀" - }, - "Trigger: %1": { - "Trigger: %1": "触发器:%1" - }, - "Trust": { - "Trust": "信任" - }, - "Try a different search": { - "Try a different search": "尝试不同的搜索" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "当激活锁屏时将立即关闭所有显示器" - }, - "Turn off monitors after": { - "Turn off monitors after": "在此时间后关闭显示器" - }, - "Type": { - "Type": "类型" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "至少键入两个字符" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "键入此前缀以搜索快捷键绑定" - }, - "Type to search files": { - "Type to search files": "键入以搜索文件" - }, - "Typography": { - "Typography": "排版" - }, - "Typography & Motion": { - "Typography & Motion": "排版与动画" - }, - "Unavailable": { - "Unavailable": "不可用" - }, - "Unfocused Color": { - "Unfocused Color": "未聚焦颜色" - }, - "Ungrouped": { - "Ungrouped": "已解除分组" - }, - "Uninstall": { - "Uninstall": "卸载" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "卸载 Greeter" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "卸载插件" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "卸载完成。Greeter 已被移除。" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "卸载失败:%1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "卸载 DMS Greeter?这将删除配置并恢复您之前的显示管理器。系统将打开一个终端以进行 sudo 身份验证。" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "已卸载:%1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "卸载中:%1" - }, - "Unknown": { - "Unknown": "未知" - }, - "Unknown App": { - "Unknown App": "未知应用" - }, - "Unknown Artist": { - "Unknown Artist": "未知艺术家" - }, - "Unknown Config": { - "Unknown Config": "未知设置" - }, - "Unknown Device": { - "Unknown Device": "未知设备" - }, - "Unknown GPU": { - "Unknown GPU": "未知的GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "未知监视器" - }, - "Unknown Network": { - "Unknown Network": "未知网络" - }, - "Unknown Title": { - "Unknown Title": "未知标题" - }, - "Unknown Track": { - "Unknown Track": "未知乐曲" - }, - "Unload on Close": { - "Unload on Close": "关闭时上传" - }, - "Unmute": { - "Unmute": "启用" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "启用弹窗%1" - }, - "Unnamed Rule": { - "Unnamed Rule": "未命名规则" - }, - "Unpair": { - "Unpair": "取消配对" - }, - "Unpair failed": { - "Unpair failed": "取消配对失败" - }, - "Unpin": { - "Unpin": "解除固定" - }, - "Unpin from Dock": { - "Unpin from Dock": "从程序坞取消固定" - }, - "Unsaved Changes": { - "Unsaved Changes": "未保存更改" - }, - "Unsaved changes": { - "Unsaved changes": "未保存更改" - }, - "Unsaved note...": { - "Unsaved note...": "未保存的便签..." - }, - "Untitled": { - "Untitled": "无标题" - }, - "Untrust": { - "Untrust": "不信任" - }, - "Up to date": { - "Up to date": "已是最新" - }, - "Update": { - "Update": "更新" - }, - "Update All": { - "Update All": "更新所有" - }, - "Update Plugin": { - "Update Plugin": "更新插件" - }, - "Uptime": { - "Uptime": "运行时间" - }, - "Uptime:": { - "Uptime:": "运行时间:" - }, - "Urgent Color": { - "Urgent Color": "高亮颜色" - }, - "Usage Tips": { - "Usage Tips": "使用提示" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "改用24小时制显示时间" - }, - "Use Custom Command": { - "Use Custom Command": "使用自定义命令" - }, - "Use Grid Layout": { - "Use Grid Layout": "使用网格布局" - }, - "Use IP Location": { - "Use IP Location": "使用 IP 定位" - }, - "Use Imperial Units": { - "Use Imperial Units": "使用英制单位" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "使用英制单位(°F、mph、inHg)而非公制(°C、km/h、hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "使用等宽字体" - }, - "Use System Theme": { - "Use System Theme": "使用系统主题" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "使用自定义图像作为登录屏幕,或留空以使用您的桌面壁纸。" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "为此栏使用固定的阴影方向" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "使用安全密钥进行锁屏认证。" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "使用外部壁纸管理器,例如 swww、hyprpaper 或 swaybg。" - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "进行媒体播放时显示动画波形进度条" - }, - "Use custom border size": { - "Use custom border size": "使用自定义边框尺寸" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "使用自定义边框/焦点环宽度" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "使用自定义命令来更新系统" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "使用自定义间隔替代状态栏空隙" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "使用自定义窗口半径替代主题半径" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "使用自定义窗口圆角代替主题半径" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "使用桌面壁纸" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "为锁屏使用指纹认证。" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "使用浅色主题替代深色主题" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "使用m/s代替km/h来显示风速" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "使用更小的通知卡" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "使用系统设置中的声音主题" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "在所有显示器上使用同样的位置与大小" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "使用触发前缀以激活" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "当强调色为自定义时使用" - }, - "User": { - "User": "用户" - }, - "Username": { - "Username": "用户名" - }, - "Username...": { - "Username...": "用户名……" - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "使用基于位置信息的日出/日落时间。" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "使用所在位置的日出/日落时间,自动调节夜间模式。" - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "使用伽马控制的已共享设置" - }, - "Utilities": { - "Utilities": "实用工具" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN 连接" - }, - "VPN Password": { - "VPN Password": "VPN 密码" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN 配置已更新" - }, - "VPN connections": { - "VPN connections": "VPN连接" - }, - "VPN deleted": { - "VPN deleted": "VPN 已删除" - }, - "VPN imported: %1": { - "VPN imported: %1": "已导入VPN:%1" - }, - "VPN not available": { - "VPN not available": "VPN不可用" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN 状态与快速连接" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "仅VRR全屏" - }, - "VRR On-Demand": { - "VRR On-Demand": "按需VRR" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "可变刷新率" - }, - "Verification": { - "Verification": "验证" - }, - "Version": { - "Version": "版本" - }, - "Vertical Deck": { - "Vertical Deck": "垂直 Deck" - }, - "Vertical Grid": { - "Vertical Grid": "垂直网格" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "垂直滚动" - }, - "Vertical Tiling": { - "Vertical Tiling": "垂直平铺" - }, - "Vibrant": { - "Vibrant": "鲜艳" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "充满活力的调色板,有着俏皮的饱和度。" - }, - "Video Path": { - "Video Path": "视频路径" - }, - "Video Screensaver": { - "Video Screensaver": "动态屏保" - }, - "Videos": { - "Videos": "视频" - }, - "View Mode": { - "View Mode": "查看模式" - }, - "Visibility": { - "Visibility": "能见度" - }, - "Visual Effects": { - "Visual Effects": "视觉效果" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "部件分隔线" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "壁纸切换时的动画效果" - }, - "Volume": { - "Volume": "音量" - }, - "Volume Changed": { - "Volume Changed": "音量变化" - }, - "Volume Slider": { - "Volume Slider": "音量滑块" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "音量、亮度和其他系统屏幕显示" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "壁纸" - }, - "Wallpaper Error": { - "Wallpaper Error": "壁纸错误" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "壁纸监视器" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "壁纸填充模式" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "壁纸处理失败" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "壁纸处理失败 - 请检查壁纸路径" - }, - "Wallpapers": { - "Wallpapers": "壁纸" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "温暖色温以应用" - }, - "Warning": { - "Warning": "警告" - }, - "Warnings": { - "Warnings": "警告" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "波形进度条" - }, - "Weather": { - "Weather": "天气" - }, - "Weather Widget": { - "Weather Widget": "天气部件" - }, - "Welcome": { - "Welcome": "欢迎" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "欢迎来到DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "在 Hyprland 特殊工作区点击程序坞窗口时,会拉回该特殊工作区,再聚焦窗口" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "启用后,应用按字母顺序排序;禁用则按使用频率排序" - }, - "When locked": { - "When locked": "何时锁定" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "当使用更新器部件时,如果找不到更新就隐藏它" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi 密码" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi与以太网连接" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi不可用" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "WiFi 设备" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "WiFi二维码 " - }, - "WiFi disabled": { - "WiFi disabled": "Wi-Fi 已停用" - }, - "WiFi enabled": { - "WiFi enabled": "Wi-Fi 已启用" - }, - "WiFi is off": { - "WiFi is off": "Wi-Fi 已关闭" - }, - "WiFi off": { - "WiFi off": "WiFi关闭" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "广色域(BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "部件背景色" - }, - "Widget Management": { - "Widget Management": "部件管理" - }, - "Widget Outline": { - "Widget Outline": "部件轮廓" - }, - "Widget Style": { - "Widget Style": "部件风格" - }, - "Widget Styling": { - "Widget Styling": "部件样式" - }, - "Widget Transparency": { - "Widget Transparency": "部件透明度" - }, - "Widget added": { - "Widget added": "部件已添加" - }, - "Widget removed": { - "Widget removed": "部件已移除" - }, - "Widgets": { - "Widgets": "部件" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "部件、布局与风格" - }, - "Width": { - "Width": "宽度" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "窗口边框宽度(borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "窗口边框宽度(general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "窗口边框宽度与聚焦环" - }, - "Wind": { - "Wind": "风速" - }, - "Wind Speed": { - "Wind Speed": "风速" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "风速m/s" - }, - "Window Corner Radius": { - "Window Corner Radius": "窗口角半径" - }, - "Window Gaps": { - "Window Gaps": "窗口间隙" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "窗口间隙(像素)" - }, - "Window Height": { - "Window Height": "窗口高度" - }, - "Window Opening": { - "Window Opening": "正打开窗口" - }, - "Window Rounding": { - "Window Rounding": "窗口圆角" - }, - "Window Rules": { - "Window Rules": "窗口规则" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "未找到窗口规则包含文件" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "未配置窗口规则" - }, - "Wipe": { - "Wipe": "擦除" - }, - "Workspace": { - "Workspace": "工作区" - }, - "Workspace Appearance": { - "Workspace Appearance": "工作区外观" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "工作区序号" - }, - "Workspace Names": { - "Workspace Names": "工作区名称" - }, - "Workspace Padding": { - "Workspace Padding": "工作区内边距" - }, - "Workspace Settings": { - "Workspace Settings": "工作区设置" - }, - "Workspace Switcher": { - "Workspace Switcher": "工作区切换器" - }, - "Workspace name": { - "Workspace name": "工作区名称" - }, - "Workspaces": { - "Workspaces": "工作区" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "工作区与部件" - }, - "Write:": { - "Write:": "写入:" - }, - "X Axis": { - "X Axis": "X轴" - }, - "Y Axis": { - "Y Axis": "Y轴" - }, - "Yes": { - "Yes": "是" - }, - "Yesterday": { - "Yesterday": "昨天" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "检测到未保存的更改,是否在关闭此标签页前保存?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "检测到未保存的更改,是否在继续前保存?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "检测到未保存的更改,是否在创建新文件前保存?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "检测到未保存的更改,是否在打开文件前保存?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "你需要设置:\nQT_QPA_PLATFORMTHEME=gtk3 或\nQT_QPA_PLATFORMTHEME=qt6ct\n作为环境变量,然后重启shell。\n\nqt6ct需要安装qt6ct-kde。" - }, - "You're All Set!": { - "You're All Set!": "已全部设置!" - }, - "Your system is up to date!": { - "Your system is up to date!": "您的系统已是最新!" - }, - "actions": { - "actions": "动作" - }, - "attached": { - "attached": "已连接" - }, - "brandon": { - "brandon": "brandon" - }, - "by %1": { - "by %1": "%1" - }, - "days": { - "days": "天" - }, - "detached": { - "detached": "已分离" - }, - "device": { - "device": "设备" - }, - "devices connected": { - "devices connected": "设备已连接" - }, - "dgop not available": { - "dgop not available": "dgop不可用" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "DMS是一款高度可自定义的现代桌面shell,深受material 3的启发而设计。

        DMS基于Quickshell——一个专为创建桌面shell的QT6框架,并通过Go语言——一种静态类型化、编译的编程语言开发。" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "已找到dms/cursor的配置文件,但并未导入。光标设置将不会生效。" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/输出配置存在,但不包含在你的合成器配置里。显示更改不会保留。" - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "例如:firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "例如:focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "例如:通知发送 'Hello' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "例如,scratch, /^tmp_.*/, build" - }, - "events": { - "events": "事件" - }, - "ext": { - "ext": "外部" - }, - "featured": { - "featured": "已生效" - }, - "leave empty for default": { - "leave empty for default": "留空使用默认" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl 不可用 - 启用锁定集成需连接 DMS socket" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord 服务器" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "未找到matugen - 请为动态主题安装matugen包" - }, - "minutes": { - "minutes": "分钟" - }, - "ms": { - "ms": "毫秒" - }, - "nav": { - "nav": "向导" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix 聊天室" - }, - "niri shortcuts config": { - "niri shortcuts config": "Niri快捷键设置" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "现在" - }, - "official": { - "official": "官方" - }, - "on Hyprland": { - "on Hyprland": "在Hyprland上" - }, - "on MangoWC": { - "on MangoWC": "在MangoWC上" - }, - "on Miracle WM": { - "on Miracle WM": "在Miracle WM上" - }, - "on Niri": { - "on Niri": "在Niri上" - }, - "on Scroll": { - "on Scroll": "在滚动上" - }, - "on Sway": { - "on Sway": "在Sway上" - }, - "open": { - "open": "打开" - }, - "or run ": { - "or run ": "或运行 " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon不可用" - }, - "procs": { - "procs": "进程" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri 红迪子版块" - }, - "seconds": { - "seconds": "秒" - }, - "source": { - "source": "源" - }, - "this app": { - "this app": "此应用" - }, - "up": { - "up": "上" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "更新 DMS 以集成 NM" - }, - "v%1 by %2": { - "v%1 by %2": "v%1 by %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype不可用,为支持粘贴,请安装wtype" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• 仅从可信来源安装" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - 月(1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• M - 月(01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - 月份 (1月)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - 月份 (一月)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "插件可能包含漏洞或安全隐患" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• 请尽可能在安装前审查代码" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - 日(1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - 日(01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - 星期缩写(周一)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - 星期全称(星期一)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - 年(24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yy - 年(2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: 导航 • 空格:展开 • 回车:动作/展开 • E:文本" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: 导航 • 回车/Ctrl+C: 复制 • Del: 删除 • F10: 帮助" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: 导航 • 回车:粘贴 • Del:删除 • F10:帮助" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_TW.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_TW.json deleted file mode 100644 index de0ed01..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/poexports/zh_TW.json +++ /dev/null @@ -1,7175 +0,0 @@ -{ - "%1 Animation Speed": { - "%1 Animation Speed": "%1 動畫速度" - }, - "%1 Sessions": { - "%1 Sessions": "%1 個會話" - }, - "%1 active session": { - "%1 active session": "%1 個活躍會話" - }, - "%1 active sessions": { - "%1 active sessions": "%1 個活躍會話" - }, - "%1 adapter, none connected": { - "%1 adapter, none connected": "%1 個轉接器,未連接" - }, - "%1 adapters, none connected": { - "%1 adapters, none connected": "%1 個轉接器,未連接" - }, - "%1 character": { - "%1 character": "%1 個字元" - }, - "%1 characters": { - "%1 characters": "%1 個字元" - }, - "%1 connected": { - "%1 connected": "%1 已連接" - }, - "%1 custom animation duration": { - "%1 custom animation duration": "%1 自訂動畫持續時間" - }, - "%1 disconnected": { - "%1 disconnected": "%1 已中斷連線" - }, - "%1 disconnected (hidden)": { - "%1 disconnected (hidden)": "%1 已中斷連線 (隱藏)" - }, - "%1 display": { - "%1 display": "%1 個顯示器" - }, - "%1 displays": { - "%1 displays": "%1 個顯示器" - }, - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": { - "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.": "%1 存在但未包含在設定中。自訂快捷鍵在修正此問題前將無法運作。" - }, - "%1 exists but is not included. Window rules won't apply.": { - "%1 exists but is not included. Window rules won't apply.": "%1 存在但未納入。視窗規則將不適用。" - }, - "%1 filtered": { - "%1 filtered": "%1 個已篩選" - }, - "%1 is now included in config": { - "%1 is now included in config": "%1 現已包含在設定中" - }, - "%1 issue found": { - "%1 issue found": "發現 %1 個問題" - }, - "%1 issues found": { - "%1 issues found": "發現 %1 個問題" - }, - "%1 notifications": { - "%1 notifications": "%1 則通知" - }, - "%1 update": { - "%1 update": "%1 個更新" - }, - "%1 updates": { - "%1 updates": "%1 個更新" - }, - "%1 variants": { - "%1 variants": "%1 種變體" - }, - "%1 wallpaper • %2 / %3": { - "%1 wallpaper • %2 / %3": "%1 張桌布 • %2 / %3" - }, - "%1 wallpapers • %2 / %3": { - "%1 wallpapers • %2 / %3": "%1 張桌布 • %2 / %3" - }, - "%1 widgets": { - "%1 widgets": "%1 個部件" - }, - "%1 window": { - "%1 window": "%1 個視窗" - }, - "%1 windows": { - "%1 windows": "%1 個視窗" - }, - "%1m ago": { - "%1m ago": "%1 分鐘前" - }, - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": { - "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.": "「替代」讓密鑰自行解鎖。「第二因素」需要先輸入密碼或指紋,然後再輸入密鑰。" - }, - "(Default)": { - "(Default)": "(預設)" - }, - "(Unnamed)": { - "(Unnamed)": "(未命名)" - }, - "+ %1 more": { - "+ %1 more": "+ %1 個" - }, - "/path/to/videos": { - "/path/to/videos": "/影片/路徑" - }, - "0 = square corners": { - "0 = square corners": "0 = 直角" - }, - "1 day": { - "1 day": "1 天" - }, - "1 device connected": { - "1 device connected": "已連接 1 個裝置" - }, - "1 event": { - "1 event": "1 個活動" - }, - "1 hour": { - "1 hour": "1 小時" - }, - "1 hour 30 minutes": { - "1 hour 30 minutes": "1 小時 30 分鐘" - }, - "1 minute": { - "1 minute": "1 分鐘" - }, - "1 notification": { - "1 notification": "1 則通知" - }, - "1 second": { - "1 second": "1 秒" - }, - "10 minutes": { - "10 minutes": "10 分鐘" - }, - "10 seconds": { - "10 seconds": "10 秒" - }, - "10-bit Color": { - "10-bit Color": "10 位元色彩" - }, - "12 hours": { - "12 hours": "12 小時" - }, - "14 days": { - "14 days": "14 天" - }, - "15 minutes": { - "15 minutes": "15 分鐘" - }, - "15 seconds": { - "15 seconds": "15 秒" - }, - "180°": { - "180°": "180°" - }, - "2 hours": { - "2 hours": "2 小時" - }, - "2 minutes": { - "2 minutes": "2 分鐘" - }, - "2 seconds": { - "2 seconds": "2 秒" - }, - "20 minutes": { - "20 minutes": "20 分鐘" - }, - "20 seconds": { - "20 seconds": "20 秒" - }, - "24-Hour Format": { - "24-Hour Format": "24 小時制" - }, - "24-hour clock": { - "24-hour clock": "24 小時制" - }, - "24-hour format": { - "24-hour format": "24 小時制" - }, - "25 seconds": { - "25 seconds": "25 秒" - }, - "250 ms": { - "250 ms": "250 毫秒" - }, - "270°": { - "270°": "270°" - }, - "3 days": { - "3 days": "3 天" - }, - "3 hours": { - "3 hours": "3 小時" - }, - "3 minutes": { - "3 minutes": "3 分鐘" - }, - "3 seconds": { - "3 seconds": "3 秒" - }, - "30 days": { - "30 days": "30 天" - }, - "30 minutes": { - "30 minutes": "30 分鐘" - }, - "30 seconds": { - "30 seconds": "30 秒" - }, - "35 seconds": { - "35 seconds": "35 秒" - }, - "3rd party": { - "3rd party": "第三方" - }, - "4 hours": { - "4 hours": "4 小時" - }, - "4 seconds": { - "4 seconds": "4 秒" - }, - "40 seconds": { - "40 seconds": "40 秒" - }, - "45 seconds": { - "45 seconds": "45 秒" - }, - "5 minutes": { - "5 minutes": "5 分鐘" - }, - "5 seconds": { - "5 seconds": "5 秒" - }, - "50 seconds": { - "50 seconds": "50 秒" - }, - "500 ms": { - "500 ms": "500 毫秒" - }, - "55 seconds": { - "55 seconds": "55 秒" - }, - "6 hours": { - "6 hours": "6 小時" - }, - "7 days": { - "7 days": "7 天" - }, - "750 ms": { - "750 ms": "750 毫秒" - }, - "8 hours": { - "8 hours": "8 小時" - }, - "8 seconds": { - "8 seconds": "8 秒" - }, - "90 days": { - "90 days": "90 天" - }, - "90°": { - "90°": "90°" - }, - "MIT License": { - "MIT License": "MIT 授權" - }, - "A file with this name already exists. Do you want to overwrite it?": { - "A file with this name already exists. Do you want to overwrite it?": "檔案名稱已存在。是否要覆蓋它?" - }, - "A modern desktop shell for Wayland compositors": { - "A modern desktop shell for Wayland compositors": "適用於 Wayland 顯示合成器的現代桌面殼層" - }, - "AC Power": { - "AC Power": "交流電源" - }, - "API": { - "API": "API" - }, - "Aborted": { - "Aborted": "已中止" - }, - "About": { - "About": "關於" - }, - "Accent Color": { - "Accent Color": "強調色" - }, - "Accept": { - "Accept": "接受" - }, - "Accept Jobs": { - "Accept Jobs": "接受工作" - }, - "Accepting": { - "Accepting": "接受中" - }, - "Access clipboard history": { - "Access clipboard history": "剪貼簿歷史記錄" - }, - "Access to notifications and do not disturb": { - "Access to notifications and do not disturb": "通知和請勿打擾" - }, - "Access to system controls and settings": { - "Access to system controls and settings": "系統控制和設定" - }, - "Action": { - "Action": "動作" - }, - "Action failed or terminal was closed.": { - "Action failed or terminal was closed.": "操作失敗或終端機已關閉。" - }, - "Actions": { - "Actions": "選項" - }, - "Activate": { - "Activate": "啟用" - }, - "Activate Greeter": { - "Activate Greeter": "啟用歡迎畫面" - }, - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": { - "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.": "啟用 DMS 歡迎畫面?將開啟終端機以進行 sudo 驗證。啟用後執行「同步」以套用您的設定。" - }, - "Activation": { - "Activation": "啟用" - }, - "Active": { - "Active": "啟用" - }, - "Active Color": { - "Active Color": "活動顏色" - }, - "Active Lock Screen Monitor": { - "Active Lock Screen Monitor": "活動鎖定畫面監視器" - }, - "Active tile background and icon color": { - "Active tile background and icon color": "啟用磚背景與圖示顏色" - }, - "Active: %1": { - "Active: %1": "作用中:%1" - }, - "Active: %1 +%2": { - "Active: %1 +%2": "作用中:%1 +%2" - }, - "Active: None": { - "Active: None": "啟用:無" - }, - "Adapters": { - "Adapters": "轉接器" - }, - "Adaptive Media Width": { - "Adaptive Media Width": "" - }, - "Add": { - "Add": "新增" - }, - "Add Bar": { - "Add Bar": "新增欄" - }, - "Add Desktop Widget": { - "Add Desktop Widget": "新增桌面小工具" - }, - "Add Printer": { - "Add Printer": "新增印表機" - }, - "Add Title": { - "Add Title": "新增標題" - }, - "Add Widget": { - "Add Widget": "新增部件" - }, - "Add Widget to %1 Section": { - "Add Widget to %1 Section": "將部件新增至 %1 部分" - }, - "Add a border around the dock": { - "Add a border around the dock": "在 Dock 周圍新增邊框" - }, - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": { - "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.": "為所有應用程式啟動新增自訂前綴。這可用於「uwsm-app」、「systemd-run」或其他指令包裝器等。" - }, - "Add and configure widgets that appear on your desktop": { - "Add and configure widgets that appear on your desktop": "新增及設定顯示在桌面上的小工具" - }, - "Add by Address": { - "Add by Address": "按位址新增" - }, - "Adjust the number of columns in grid view mode.": { - "Adjust the number of columns in grid view mode.": "調整網格檢視模式中的欄數。" - }, - "Adjust volume per scroll indent": { - "Adjust volume per scroll indent": "調整每滾動縮排的音量" - }, - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": { - "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)": "" - }, - "Advanced": { - "Advanced": "進階" - }, - "Afternoon": { - "Afternoon": "下午" - }, - "All": { - "All": "所有" - }, - "All Monitors": { - "All Monitors": "所有監視器" - }, - "All checks passed": { - "All checks passed": "所有檢查皆通過" - }, - "All day": { - "All day": "全天" - }, - "All displays": { - "All displays": "所有螢幕" - }, - "Allow clicks to pass through the widget": { - "Allow clicks to pass through the widget": "允許點擊穿透小工具" - }, - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": { - "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: 返回 • F1/I: 檔案資訊 • F10: 幫助 • Esc: 關閉" - }, - "Alternative (OR)": { - "Alternative (OR)": "替代 (OR)" - }, - "Always Active": { - "Always Active": "總是啟用" - }, - "Always Show Percentage": { - "Always Show Percentage": "始終顯示百分比" - }, - "Always hide the dock and reveal it when hovering near the dock area": { - "Always hide the dock and reveal it when hovering near the dock area": "總是隱藏工作列,並在滑鼠移近工作列區域時顯示" - }, - "Always on icons": { - "Always on icons": "始終顯示圖示" - }, - "Always show a minimum of 3 workspaces, even if fewer are available": { - "Always show a minimum of 3 workspaces, even if fewer are available": "始終顯示至少 3 個工作區,即使可用的工作區較少" - }, - "Always show the dock when niri's overview is open": { - "Always show the dock when niri's overview is open": "當 Niri 總覽開啟時一律顯示 Dock" - }, - "Always show when there's only one connected display": { - "Always show when there's only one connected display": "僅連接一個顯示器時一律顯示" - }, - "Amount": { - "Amount": "數量" - }, - "Analog": { - "Analog": "類比" - }, - "Analog, digital, or stacked clock display": { - "Analog, digital, or stacked clock display": "類比、數位或堆疊時鐘顯示" - }, - "Analyzing configuration...": { - "Analyzing configuration...": "正在分析設定..." - }, - "Animation Duration": { - "Animation Duration": "動畫持續時間" - }, - "Animation Speed": { - "Animation Speed": "動畫速度" - }, - "Anonymous Identity": { - "Anonymous Identity": "匿名身份" - }, - "Anonymous Identity (optional)": { - "Anonymous Identity (optional)": "匿名身分 (可選)" - }, - "App Customizations": { - "App Customizations": "應用程式自訂" - }, - "App ID Substitutions": { - "App ID Substitutions": "應用程式ID替換" - }, - "App ID regex (e.g. ^firefox$)": { - "App ID regex (e.g. ^firefox$)": "應用程式 ID 正規表示式 (例如:^firefox$)" - }, - "App Launcher": { - "App Launcher": "應用程式啟動器" - }, - "App Names": { - "App Names": "應用程式名稱" - }, - "App Theming": { - "App Theming": "應用程式主題" - }, - "Appearance": { - "Appearance": "外觀" - }, - "Application Dock": { - "Application Dock": "應用程式 Dock" - }, - "Applications": { - "Applications": "應用程式" - }, - "Apply Changes": { - "Apply Changes": "套用變更" - }, - "Apply GTK Colors": { - "Apply GTK Colors": "套用 GTK 顏色" - }, - "Apply Qt Colors": { - "Apply Qt Colors": "套用 Qt 顏色" - }, - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": { - "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "應用暖色溫以減輕眼睛疲勞。使用下方的自動化設定來控制其啟動時間。" - }, - "Applying authentication changes…": { - "Applying authentication changes…": "" - }, - "Apps": { - "Apps": "應用程式" - }, - "Apps Dock": { - "Apps Dock": "應用程式工作列" - }, - "Apps Dock Settings": { - "Apps Dock Settings": "應用程式工具列設定" - }, - "Apps Icon": { - "Apps Icon": "啟動器圖示" - }, - "Apps are ordered by usage frequency, then last used, then alphabetically.": { - "Apps are ordered by usage frequency, then last used, then alphabetically.": "應用程式按使用頻率、最後使用時間、字母順序排列。" - }, - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": { - "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.": "具備自訂顯示名稱、圖示或啟動選項的應用程式。右鍵點擊應用程式並選擇「編輯應用程式」來自訂。" - }, - "Apps with notification popups muted. Unmute or delete to remove.": { - "Apps with notification popups muted. Unmute or delete to remove.": "已靜音通知彈出視窗的應用程式。解除靜音或刪除以移除。" - }, - "Architecture": { - "Architecture": "架構" - }, - "Are you sure you want to kill session \"%1\"?": { - "Are you sure you want to kill session \"%1\"?": "您確定要終止會話「%1」嗎?" - }, - "Arrange displays and configure resolution, refresh rate, and VRR": { - "Arrange displays and configure resolution, refresh rate, and VRR": "排列顯示器並設定解析度、重新整理頻率和 VRR" - }, - "Attach": { - "Attach": "附加" - }, - "Audio": { - "Audio": "音訊" - }, - "Audio Codec": { - "Audio Codec": "音訊編解碼器" - }, - "Audio Codec Selection": { - "Audio Codec Selection": "音訊編解碼器選擇" - }, - "Audio Devices": { - "Audio Devices": "音訊設備" - }, - "Audio Input": { - "Audio Input": "音訊輸入" - }, - "Audio Output": { - "Audio Output": "音訊輸出" - }, - "Audio Output Devices (": { - "Audio Output Devices (": "音訊輸出設備 (" - }, - "Audio Output Switch": { - "Audio Output Switch": "音訊輸出切換" - }, - "Audio Visualizer": { - "Audio Visualizer": "音訊視覺化工具" - }, - "Audio system restarted": { - "Audio system restarted": "音訊系統已重新啟動" - }, - "Audio volume control": { - "Audio volume control": "音量控制" - }, - "Auth": { - "Auth": "認證" - }, - "Auth Type": { - "Auth Type": "認證類型" - }, - "Authenticate": { - "Authenticate": "驗證" - }, - "Authenticating...": { - "Authenticating...": "正在驗證..." - }, - "Authentication": { - "Authentication": "驗證" - }, - "Authentication Required": { - "Authentication Required": "需要驗證" - }, - "Authentication changes applied.": { - "Authentication changes applied.": "" - }, - "Authentication changes apply automatically.": { - "Authentication changes apply automatically.": "" - }, - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": { - "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.": "" - }, - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": { - "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.": "" - }, - "Authentication error - try again": { - "Authentication error - try again": "驗證錯誤 - 請再試一次" - }, - "Authentication failed, please try again": { - "Authentication failed, please try again": "驗證失敗,請重試" - }, - "Authorize": { - "Authorize": "授權" - }, - "Authorize pairing with ": { - "Authorize pairing with ": "授權配對 " - }, - "Authorize service for ": { - "Authorize service for ": "授權服務 " - }, - "Auto": { - "Auto": "自動" - }, - "Auto (Bar-aware)": { - "Auto (Bar-aware)": "自動 (感知列)" - }, - "Auto (Wide)": { - "Auto (Wide)": "自動 (寬)" - }, - "Auto Location": { - "Auto Location": "自動定位" - }, - "Auto Popup Gaps": { - "Auto Popup Gaps": "自動調整彈出間隔" - }, - "Auto-Clear After": { - "Auto-Clear After": "自動清除於" - }, - "Auto-Hide Timeout": { - "Auto-Hide Timeout": "自動隱藏延遲" - }, - "Auto-close Niri overview when launching apps.": { - "Auto-close Niri overview when launching apps.": "啟動應用程式時自動關閉 Niri 總覽。" - }, - "Auto-delete notifications older than this": { - "Auto-delete notifications older than this": "自動刪除早於此時的通知" - }, - "Auto-hide": { - "Auto-hide": "自動隱藏" - }, - "Auto-hide Dock": { - "Auto-hide Dock": "自動隱藏 Dock" - }, - "Auto-saving...": { - "Auto-saving...": "自動保存..." - }, - "Autoconnect": { - "Autoconnect": "自動連接" - }, - "Autoconnect disabled": { - "Autoconnect disabled": "自動連線關閉" - }, - "Autoconnect enabled": { - "Autoconnect enabled": "自動連線啟用" - }, - "Autofill last remembered query when opened": { - "Autofill last remembered query when opened": "" - }, - "Automatic Color Mode": { - "Automatic Color Mode": "自動顏色模式" - }, - "Automatic Control": { - "Automatic Control": "自動控制" - }, - "Automatic Cycling": { - "Automatic Cycling": "桌布自動輪替" - }, - "Automatically cycle through wallpapers in the same folder": { - "Automatically cycle through wallpapers in the same folder": "自動輪替更換同一資料夾中的桌布" - }, - "Automatically delete entries older than this": { - "Automatically delete entries older than this": "自動刪除早於此時間的項目" - }, - "Automatically detect location based on IP address": { - "Automatically detect location based on IP address": "根據IP位址自動偵測位置" - }, - "Automatically determine your location using your IP address": { - "Automatically determine your location using your IP address": "使用您的 IP 位址自動確定您的位置" - }, - "Automatically lock after": { - "Automatically lock after": "指定時間後自動鎖定" - }, - "Automatically lock the screen when DMS starts": { - "Automatically lock the screen when DMS starts": "DMS 啟動時自動鎖定螢幕" - }, - "Automatically lock the screen when the system prepares to suspend": { - "Automatically lock the screen when the system prepares to suspend": "睡眠時自動鎖定螢幕" - }, - "Automation": { - "Automation": "自動化" - }, - "Available": { - "Available": "可用" - }, - "Available Layouts": { - "Available Layouts": "可用佈局" - }, - "Available Networks": { - "Available Networks": "可用網路" - }, - "Available Plugins": { - "Available Plugins": "可用的插件" - }, - "Available Screens (%1)": { - "Available Screens (%1)": "可用螢幕 (%1)" - }, - "Available in Detailed and Forecast view modes": { - "Available in Detailed and Forecast view modes": "可於詳細和預報檢視模式中顯示" - }, - "Available.": { - "Available.": "可用。" - }, - "BSSID": { - "BSSID": "BSSID" - }, - "Back": { - "Back": "返回" - }, - "Backend": { - "Backend": "後端" - }, - "Background": { - "Background": "背景" - }, - "Background Blur": { - "Background Blur": "" - }, - "Background Opacity": { - "Background Opacity": "背景不透明度" - }, - "Background authentication sync failed. Trying terminal mode.": { - "Background authentication sync failed. Trying terminal mode.": "" - }, - "Background image": { - "Background image": "背景圖片" - }, - "Backlight device": { - "Backlight device": "背光裝置" - }, - "Balance power and performance": { - "Balance power and performance": "平衡電源與效能" - }, - "Balanced": { - "Balanced": "平衡" - }, - "Balanced palette with focused accents (default).": { - "Balanced palette with focused accents (default).": "顏色平衡且帶有重點點綴的調色板 (預設)。" - }, - "Bar Configurations": { - "Bar Configurations": "欄設定" - }, - "Bar Shadows": { - "Bar Shadows": "列陰影" - }, - "Bar Transparency": { - "Bar Transparency": "欄透明度" - }, - "Base color for shadows (opacity is applied automatically)": { - "Base color for shadows (opacity is applied automatically)": "陰影的基礎顏色 (不透明度會自動套用)" - }, - "Base duration for animations (drag to use Custom)": { - "Base duration for animations (drag to use Custom)": "動畫基本持續時間(拖曳以使用自訂)" - }, - "Battery": { - "Battery": "電池" - }, - "Battery %1": { - "Battery %1": "電量 %1" - }, - "Battery Charge Limit": { - "Battery Charge Limit": "電池充電上限" - }, - "Battery and power management": { - "Battery and power management": "電池與電源管理" - }, - "Battery level and power management": { - "Battery level and power management": "電量與電源管理" - }, - "Behavior": { - "Behavior": "行為" - }, - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { - "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "將鎖定畫面綁定到 loginctl 的 dbus 訊號。如果使用外部鎖屏,請停用" - }, - "Binds Include Missing": { - "Binds Include Missing": "綁定包含遺失" - }, - "Binds include added": { - "Binds include added": "綁定包含已新增" - }, - "Bit Depth": { - "Bit Depth": "位元深度" - }, - "Block Out": { - "Block Out": "遮蔽" - }, - "Block Out From": { - "Block Out From": "從...遮蔽" - }, - "Block notifications": { - "Block notifications": "封鎖通知" - }, - "Blocked": { - "Blocked": "已封鎖" - }, - "Blue light filter": { - "Blue light filter": "藍光濾波器" - }, - "Bluetooth": { - "Bluetooth": "藍牙" - }, - "Bluetooth Settings": { - "Bluetooth Settings": "藍芽設定" - }, - "Bluetooth not available": { - "Bluetooth not available": "藍牙不可用" - }, - "Blur Border Color": { - "Blur Border Color": "" - }, - "Blur Border Opacity": { - "Blur Border Opacity": "" - }, - "Blur Wallpaper Layer": { - "Blur Wallpaper Layer": "模糊桌布圖層" - }, - "Blur on Overview": { - "Blur on Overview": "模糊概覽" - }, - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": { - "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.": "" - }, - "Blur wallpaper when niri overview is open": { - "Blur wallpaper when niri overview is open": "當 niri 概覽打開時模糊桌布" - }, - "Body": { - "Body": "主體" - }, - "Border": { - "Border": "邊框" - }, - "Border Color": { - "Border Color": "邊框顏色" - }, - "Border Opacity": { - "Border Opacity": "邊框不透明度" - }, - "Border Size": { - "Border Size": "邊框大小" - }, - "Border Thickness": { - "Border Thickness": "邊框厚度" - }, - "Border color around blurred surfaces": { - "Border color around blurred surfaces": "" - }, - "Border with BG": { - "Border with BG": "含背景邊界" - }, - "Bottom": { - "Bottom": "下方" - }, - "Bottom Center": { - "Bottom Center": "底部中央" - }, - "Bottom Left": { - "Bottom Left": "左下" - }, - "Bottom Right": { - "Bottom Right": "右下" - }, - "Bottom Section": { - "Bottom Section": "下方區塊" - }, - "Bottom dock for pinned and running applications": { - "Bottom dock for pinned and running applications": "底部 Dock 用於固定和正在運行的應用程式" - }, - "Brightness": { - "Brightness": "亮度" - }, - "Brightness Slider": { - "Brightness Slider": "亮度滑桿" - }, - "Brightness Value": { - "Brightness Value": "亮度值" - }, - "Brightness control not available": { - "Brightness control not available": "亮度控制不可用" - }, - "Browse": { - "Browse": "瀏覽" - }, - "Browse Files": { - "Browse Files": "瀏覽檔案" - }, - "Browse Plugins": { - "Browse Plugins": "瀏覽插件" - }, - "Browse Themes": { - "Browse Themes": "瀏覽佈景主題" - }, - "Browse or search plugins": { - "Browse or search plugins": "瀏覽或搜尋外掛程式" - }, - "Button Color": { - "Button Color": "按鈕顏色" - }, - "CPU": { - "CPU": "CPU" - }, - "CPU Graph": { - "CPU Graph": "CPU 圖表" - }, - "CPU Temperature": { - "CPU Temperature": "CPU 溫度" - }, - "CPU Usage": { - "CPU Usage": "CPU 使用率" - }, - "CPU temperature display": { - "CPU temperature display": "CPU 溫度顯示" - }, - "CPU usage indicator": { - "CPU usage indicator": "CPU 使用率指示器" - }, - "CPU, memory, network, and disk monitoring": { - "CPU, memory, network, and disk monitoring": "CPU、記憶體、網路與硬碟監控" - }, - "CUPS Insecure Filter Warning": { - "CUPS Insecure Filter Warning": "CUPS 不安全過濾器警告" - }, - "CUPS Missing Filter Warning": { - "CUPS Missing Filter Warning": "CUPS 缺少過濾器警告" - }, - "CUPS Print Server": { - "CUPS Print Server": "CUPS 列印伺服器" - }, - "CUPS not available": { - "CUPS not available": "CUPS 不可用" - }, - "Camera": { - "Camera": "相機" - }, - "Cancel": { - "Cancel": "取消" - }, - "Cancel all jobs for \"%1\"?": { - "Cancel all jobs for \"%1\"?": "取消 \"%1\" 的所有工作嗎?" - }, - "Canceled": { - "Canceled": "已取消" - }, - "Cannot pair": { - "Cannot pair": "無法配對" - }, - "Capabilities": { - "Capabilities": "功能" - }, - "Capacity": { - "Capacity": "容量" - }, - "Caps Lock": { - "Caps Lock": "大寫鎖定" - }, - "Caps Lock Indicator": { - "Caps Lock Indicator": "大小寫鎖定指示器" - }, - "Caps Lock is on": { - "Caps Lock is on": "大寫鎖定已開啟" - }, - "Center Section": { - "Center Section": "中間區塊" - }, - "Center Single Column": { - "Center Single Column": "中央單欄" - }, - "Center Tiling": { - "Center Tiling": "居中平鋪" - }, - "Certificate Password": { - "Certificate Password": "憑證密碼" - }, - "Change Song": { - "Change Song": "變更歌曲" - }, - "Change Volume": { - "Change Volume": "調整音量" - }, - "Change bar appearance": { - "Change bar appearance": "變更欄外觀" - }, - "Change the locale used by the DMS interface.": { - "Change the locale used by the DMS interface.": "變更 DMS 介面使用的語系。" - }, - "Change the locale used for date and time formatting, independent of the interface language.": { - "Change the locale used for date and time formatting, independent of the interface language.": "變更用於日期和時間格式的語系,與介面語言無關。" - }, - "Channel": { - "Channel": "頻道" - }, - "Charging": { - "Charging": "充電中" - }, - "Check for system updates": { - "Check for system updates": "檢查系統更新" - }, - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": { - "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.": "" - }, - "Checking for updates...": { - "Checking for updates...": "正在檢查更新..." - }, - "Checking whether sudo authentication is needed…": { - "Checking whether sudo authentication is needed…": "正在檢查是否需要 sudo 驗證…" - }, - "Checking...": { - "Checking...": "正在檢查..." - }, - "Checking…": { - "Checking…": "正在檢查…" - }, - "Choose Color": { - "Choose Color": "選擇顏色" - }, - "Choose Dark Mode Color": { - "Choose Dark Mode Color": "選擇深色模式顏色" - }, - "Choose Dock Launcher Logo Color": { - "Choose Dock Launcher Logo Color": "選擇工作列啟動器標誌顏色" - }, - "Choose Launcher Logo Color": { - "Choose Launcher Logo Color": "選擇啟動器 Logo 顏色" - }, - "Choose Light Mode Color": { - "Choose Light Mode Color": "選擇淺色模式顏色" - }, - "Choose Wallpaper Color": { - "Choose Wallpaper Color": "選擇壁紙顏色" - }, - "Choose a color": { - "Choose a color": "選擇顏色" - }, - "Choose colors from palette": { - "Choose colors from palette": "從調色盤選擇顏色" - }, - "Choose how the weather widget is displayed": { - "Choose how the weather widget is displayed": "選擇天氣小工具的顯示方式" - }, - "Choose how this bar resolves shadow direction": { - "Choose how this bar resolves shadow direction": "選擇此列如何解析陰影方向" - }, - "Choose icon": { - "Choose icon": "選擇圖示" - }, - "Choose the background color for widgets": { - "Choose the background color for widgets": "選擇部件的背景顏色" - }, - "Choose the border accent color": { - "Choose the border accent color": "選擇邊框強調色" - }, - "Choose the logo displayed on the launcher button in DankBar": { - "Choose the logo displayed on the launcher button in DankBar": "選擇 DankBar 啟動器按鈕上顯示的 logo" - }, - "Choose where notification popups appear on screen": { - "Choose where notification popups appear on screen": "選擇通知彈出視窗在螢幕上出現的位置" - }, - "Choose where on-screen displays appear on screen": { - "Choose where on-screen displays appear on screen": "選擇螢幕顯示出現在螢幕上的位置" - }, - "Choose which displays show this widget": { - "Choose which displays show this widget": "選擇哪些顯示器顯示此小工具" - }, - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": { - "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.": "選擇哪個監視器顯示鎖定畫面介面。其他監視器將顯示純色以保護 OLED 燒屏。" - }, - "Chroma Style": { - "Chroma Style": "色度樣式" - }, - "Cipher": { - "Cipher": "密碼" - }, - "Circle": { - "Circle": "圓形" - }, - "Class regex (e.g. ^firefox$)": { - "Class regex (e.g. ^firefox$)": "類別正規表示式 (例如:^firefox$)" - }, - "Clear": { - "Clear": "清除" - }, - "Clear All": { - "Clear All": "清除所有" - }, - "Clear All Jobs": { - "Clear All Jobs": "清除所有工作" - }, - "Clear History?": { - "Clear History?": "清除歷史記錄?" - }, - "Clear Sky": { - "Clear Sky": "晴空" - }, - "Clear all history when server starts": { - "Clear all history when server starts": "伺服器啟動時清除所有歷史紀錄" - }, - "Clear at Startup": { - "Clear at Startup": "啟動時清除" - }, - "Click 'Setup' to create %1 and add include to config.": { - "Click 'Setup' to create %1 and add include to config.": "點擊「設定」以建立 %1 並新增到設定中。" - }, - "Click 'Setup' to create %1 and add include to your compositor config.": { - "Click 'Setup' to create %1 and add include to your compositor config.": "點擊「設定」以建立 %1 並將其納入您的合成器設定中。" - }, - "Click 'Setup' to create cursor config and add include to your compositor config.": { - "Click 'Setup' to create cursor config and add include to your compositor config.": "點擊「設定」以建立游標設定檔,並將其包含至您的合成器設定中。" - }, - "Click 'Setup' to create the outputs config and add include to your compositor config.": { - "Click 'Setup' to create the outputs config and add include to your compositor config.": "按一下「設定」以建立輸出組態並將其包含至合成器組態中。" - }, - "Click Import to add a .ovpn or .conf": { - "Click Import to add a .ovpn or .conf": "點擊匯入以新增 .ovpn 或 .conf" - }, - "Click Refresh to check status.": { - "Click Refresh to check status.": "點擊「重新整理」以檢查狀態。" - }, - "Click Through": { - "Click Through": "穿透點擊" - }, - "Click any shortcut to edit. Changes save to %1": { - "Click any shortcut to edit. Changes save to %1": "點擊任一快捷鍵進行編輯。變更會儲存到 %1" - }, - "Click to capture": { - "Click to capture": "點擊擷取" - }, - "Click to select a custom theme JSON file": { - "Click to select a custom theme JSON file": "按一下以選取自訂佈景主題 JSON 檔案" - }, - "Clip": { - "Clip": "裁剪" - }, - "Clip to Geometry": { - "Clip to Geometry": "依幾何形狀裁剪" - }, - "Clipboard": { - "Clipboard": "剪貼簿" - }, - "Clipboard History": { - "Clipboard History": "剪貼簿歷史" - }, - "Clipboard Manager": { - "Clipboard Manager": "剪貼簿管理" - }, - "Clipboard sent": { - "Clipboard sent": "剪貼簿已傳送" - }, - "Clipboard service not available": { - "Clipboard service not available": "剪貼簿服務無法使用" - }, - "Clipboard works but nothing saved to disk": { - "Clipboard works but nothing saved to disk": "剪貼簿運作正常但未儲存任何內容至磁碟" - }, - "Clock": { - "Clock": "時鐘" - }, - "Clock Style": { - "Clock Style": "時鐘樣式" - }, - "Close": { - "Close": "關閉" - }, - "Close All Windows": { - "Close All Windows": "關閉所有視窗" - }, - "Close Overview on Launch": { - "Close Overview on Launch": "啟動時關閉概覽" - }, - "Close Window": { - "Close Window": "關閉視窗" - }, - "Color": { - "Color": "顏色" - }, - "Color Gamut": { - "Color Gamut": "色域" - }, - "Color Management": { - "Color Management": "色彩管理" - }, - "Color Mode": { - "Color Mode": "顏色模式" - }, - "Color Override": { - "Color Override": "顏色覆蓋" - }, - "Color Picker": { - "Color Picker": "顏色選擇器" - }, - "Color Temperature": { - "Color Temperature": "色溫" - }, - "Color displayed on monitors without the lock screen": { - "Color displayed on monitors without the lock screen": "未顯示鎖定畫面的監視器上顯示的顏色" - }, - "Color for primary action buttons": { - "Color for primary action buttons": "主要動作按鈕顏色" - }, - "Color temperature for day time": { - "Color temperature for day time": "白天螢幕的顏色溫度" - }, - "Color temperature for night mode": { - "Color temperature for night mode": "夜晚螢幕的顏色溫度" - }, - "Color theme for syntax highlighting.": { - "Color theme for syntax highlighting.": "語法標示的顏色佈景主題。" - }, - "Color theme for syntax highlighting. %1 themes available.": { - "Color theme for syntax highlighting. %1 themes available.": "語法標示的顏色佈景主題。有 %1 個佈景主題可用。" - }, - "Color theme from DMS registry": { - "Color theme from DMS registry": "來自 DMS 登錄檔的色彩主題" - }, - "Colorful": { - "Colorful": "彩色" - }, - "Colorful mix of bright contrasting accents.": { - "Colorful mix of bright contrasting accents.": "明亮對比點綴的繽紛組合。" - }, - "Colorize Active": { - "Colorize Active": "彩色活動" - }, - "Colors from wallpaper": { - "Colors from wallpaper": "從桌布取色" - }, - "Column": { - "Column": "欄" - }, - "Column Display": { - "Column Display": "欄顯示" - }, - "Column Width": { - "Column Width": "欄寬" - }, - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": { - "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).": "以逗號分隔要隱藏的會話名稱列表。用斜線括起來表示正規表達式(例如,/^_.*/)。" - }, - "Command": { - "Command": "指令" - }, - "Commands": { - "Commands": "指令" - }, - "Communication": { - "Communication": "通訊" - }, - "Community themes": { - "Community themes": "社群主題" - }, - "Compact": { - "Compact": "精簡" - }, - "Compact Mode": { - "Compact Mode": "緊湊模式" - }, - "Completed": { - "Completed": "已完成" - }, - "Compositor": { - "Compositor": "合成器" - }, - "Compositor Settings": { - "Compositor Settings": "合成器設定" - }, - "Compositor not supported": { - "Compositor not supported": "不支援合成器" - }, - "Config Format": { - "Config Format": "配置格式" - }, - "Config action: %1": { - "Config action: %1": "組態動作:%1" - }, - "Config validation failed": { - "Config validation failed": "配置驗證失敗" - }, - "Configuration": { - "Configuration": "配置" - }, - "Configuration activated": { - "Configuration activated": "配置已啟動" - }, - "Configuration will be preserved when this display reconnects": { - "Configuration will be preserved when this display reconnects": "此顯示器重新連線時將保留配置" - }, - "Configure": { - "Configure": "設定" - }, - "Configure Keybinds": { - "Configure Keybinds": "設定按鍵綁定" - }, - "Configure a new printer": { - "Configure a new printer": "設定新印表機" - }, - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": { - "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.": "為命名工作區配置圖示。當同時啟用圖示和數字時,圖示優先於數字。" - }, - "Configure match criteria and actions": { - "Configure match criteria and actions": "設定符合條件與動作" - }, - "Configure which displays show \"%1": { - "Configure which displays show \"%1\"": "設定哪些顯示器顯示 \"%1\"" - }, - "Configure which displays show shell components": { - "Configure which displays show shell components": "配置哪些顯示器顯示 shell 元件" - }, - "Confirm": { - "Confirm": "確認" - }, - "Confirm Delete": { - "Confirm Delete": "確認刪除" - }, - "Confirm Display Changes": { - "Confirm Display Changes": "確認顯示變更" - }, - "Confirm passkey for ": { - "Confirm passkey for ": "確認密碼 " - }, - "Conflicts with: %1": { - "Conflicts with: %1": "與 %1 衝突" - }, - "Connect": { - "Connect": "連線" - }, - "Connect to Hidden Network": { - "Connect to Hidden Network": "連線到隱藏網路" - }, - "Connect to VPN": { - "Connect to VPN": "連線到 VPN" - }, - "Connect to Wi-Fi": { - "Connect to Wi-Fi": "連線到 Wi-Fi" - }, - "Connected": { - "Connected": "已連接" - }, - "Connected Device": { - "Connected Device": "已連線裝置" - }, - "Connected Displays": { - "Connected Displays": "已連接的螢幕" - }, - "Connecting to Device": { - "Connecting to Device": "正在連接裝置" - }, - "Connecting to clipboard service…": { - "Connecting to clipboard service…": "" - }, - "Connecting...": { - "Connecting...": "連線中..." - }, - "Connection failed": { - "Connection failed": "連線失敗" - }, - "Contains": { - "Contains": "包含" - }, - "Content": { - "Content": "內容" - }, - "Content copied": { - "Content copied": "內容已複製" - }, - "Contrast": { - "Contrast": "對比" - }, - "Control Center": { - "Control Center": "控制台" - }, - "Control Center Tile Color": { - "Control Center Tile Color": "控制中心磚顏色" - }, - "Control animation duration for notification popups and history": { - "Control animation duration for notification popups and history": "控制通知彈出視窗和歷史記錄的動畫持續時間" - }, - "Control currently playing media": { - "Control currently playing media": "控制目前播放器" - }, - "Control what notification information is shown on the lock screen": { - "Control what notification information is shown on the lock screen": "控制鎖定畫面上顯示的通知資訊" - }, - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": { - "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.": "控制哪些外掛程式在「所有」模式中出現,無需觸發前綴。拖曳以重新排序。" - }, - "Control workspaces and columns by scrolling on the bar": { - "Control workspaces and columns by scrolling on the bar": "透過在列上捲動來控制工作區和欄位" - }, - "Controls opacity of all popouts, modals, and their content layers": { - "Controls opacity of all popouts, modals, and their content layers": "控制所有彈出視窗、互動視窗及其內容層的透明度" - }, - "Controls shadow cast direction for elevation layers": { - "Controls shadow cast direction for elevation layers": "控制高程層的陰影投射方向" - }, - "Controls the base blur radius and offset of shadows": { - "Controls the base blur radius and offset of shadows": "控制陰影的基本模糊半徑和偏移" - }, - "Controls the transparency of the shadow": { - "Controls the transparency of the shadow": "控制陰影的透明度" - }, - "Convenience options for the login screen. Sync to apply.": { - "Convenience options for the login screen. Sync to apply.": "登入畫面的便捷選項。同步以套用。" - }, - "Cooldown": { - "Cooldown": "冷卻時間" - }, - "Copied GIF": { - "Copied GIF": "已複製 GIF" - }, - "Copied MP4": { - "Copied MP4": "已複製 MP4" - }, - "Copied WebP": { - "Copied WebP": "已複製 WebP" - }, - "Copied to clipboard": { - "Copied to clipboard": "複製到剪貼簿" - }, - "Copied!": { - "Copied!": "已複製!" - }, - "Copy": { - "Copy": "複製" - }, - "Copy Content": { - "Copy Content": "複製內容" - }, - "Copy Full Command": { - "Copy Full Command": "複製完整指令" - }, - "Copy HTML": { - "Copy HTML": "複製 HTML" - }, - "Copy Name": { - "Copy Name": "複製名稱" - }, - "Copy PID": { - "Copy PID": "複製 PID" - }, - "Copy Text": { - "Copy Text": "複製文字" - }, - "Copy path": { - "Copy path": "複製路徑" - }, - "Corner Radius": { - "Corner Radius": "圓角半徑" - }, - "Corner Radius Override": { - "Corner Radius Override": "圓角半徑覆寫" - }, - "Corners & Background": { - "Corners & Background": "邊角與背景" - }, - "Count Only": { - "Count Only": "僅計數" - }, - "Cover Open": { - "Cover Open": "上蓋開啟" - }, - "Create": { - "Create": "建立" - }, - "Create Dir": { - "Create Dir": "新建資料夾" - }, - "Create Printer": { - "Create Printer": "建立印表機" - }, - "Create Window Rule": { - "Create Window Rule": "建立視窗規則" - }, - "Create a new %1 session (n)": { - "Create a new %1 session (n)": "建立一個新的 %1 會話 (n)" - }, - "Create rule for:": { - "Create rule for:": "建立規則:" - }, - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": { - "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.": "建立規則以靜音、忽略、從歷史記錄中隱藏或覆蓋通知優先級。預設只會覆蓋優先級;通知仍會正常顯示。" - }, - "Creating...": { - "Creating...": "建立中..." - }, - "Critical Priority": { - "Critical Priority": "關鍵優先級" - }, - "Current": { - "Current": "目前" - }, - "Current Items": { - "Current Items": "目前項目" - }, - "Current Locale": { - "Current Locale": "目前語系" - }, - "Current Monitor": { - "Current Monitor": "目前顯示器" - }, - "Current Period": { - "Current Period": "目前週期" - }, - "Current Status": { - "Current Status": "目前狀態" - }, - "Current Temp": { - "Current Temp": "目前溫度" - }, - "Current Theme: %1": { - "Current Theme: %1": "目前主題:%1" - }, - "Current Weather": { - "Current Weather": "目前天氣" - }, - "Current Workspace": { - "Current Workspace": "目前工作區" - }, - "Current time and date display": { - "Current time and date display": "目前日期時間顯示" - }, - "Current weather conditions and temperature": { - "Current weather conditions and temperature": "目前天氣狀況和溫度" - }, - "Current: %1": { - "Current: %1": "目前:%1" - }, - "Cursor Config Not Configured": { - "Cursor Config Not Configured": "游標設定檔未設定" - }, - "Cursor Include Missing": { - "Cursor Include Missing": "游標包含檔遺失" - }, - "Cursor Size": { - "Cursor Size": "游標大小" - }, - "Cursor Theme": { - "Cursor Theme": "游標主題" - }, - "Custom": { - "Custom": "自訂" - }, - "Custom Color": { - "Custom Color": "自訂顏色" - }, - "Custom Duration": { - "Custom Duration": "自訂持續時間" - }, - "Custom Hibernate Command": { - "Custom Hibernate Command": "自訂休眠指令" - }, - "Custom Location": { - "Custom Location": "自訂位置" - }, - "Custom Lock Command": { - "Custom Lock Command": "自訂鎖定指令" - }, - "Custom Logout Command": { - "Custom Logout Command": "自訂登出指令" - }, - "Custom Name": { - "Custom Name": "自訂名稱" - }, - "Custom Power Actions": { - "Custom Power Actions": "自訂電源選項" - }, - "Custom Power Off Command": { - "Custom Power Off Command": "自訂關機指令" - }, - "Custom Reboot Command": { - "Custom Reboot Command": "自訂重新啟動指令" - }, - "Custom Shadow Color": { - "Custom Shadow Color": "自訂陰影顏色" - }, - "Custom Shadow Override": { - "Custom Shadow Override": "自訂陰影覆寫" - }, - "Custom Suspend Command": { - "Custom Suspend Command": "自訂睡眠指令" - }, - "Custom Transparency": { - "Custom Transparency": "自訂透明度" - }, - "Custom power profile": { - "Custom power profile": "自訂電源設定檔" - }, - "Custom theme loaded from JSON file": { - "Custom theme loaded from JSON file": "從 JSON 檔案載入自訂主題" - }, - "Custom...": { - "Custom...": "自訂..." - }, - "Custom: ": { - "Custom: ": "自訂: " - }, - "Customizable empty space": { - "Customizable empty space": "可自訂空白空間" - }, - "Customize which actions appear in the power menu": { - "Customize which actions appear in the power menu": "自訂電源選單中顯示的動作" - }, - "DDC/CI monitor": { - "DDC/CI monitor": "DDC/CI 顯示器" - }, - "DEMO MODE - Click anywhere to exit": { - "DEMO MODE - Click anywhere to exit": "演示模式 - 點擊任意處關閉" - }, - "DMS Plugin Manager Unavailable": { - "DMS Plugin Manager Unavailable": "DMS 插件管理器不可用" - }, - "DMS Shortcuts": { - "DMS Shortcuts": "DMS 捷徑" - }, - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "DMS out of date": { - "DMS out of date": "DMS 已過期" - }, - "DMS service is not connected. Clipboard settings are unavailable.": { - "DMS service is not connected. Clipboard settings are unavailable.": "DMS 服務未連線。剪貼簿設定無法使用。" - }, - "DMS shell actions (launcher, clipboard, etc.)": { - "DMS shell actions (launcher, clipboard, etc.)": "DMS shell 動作 (啟動器、剪貼簿等)" - }, - "DMS_SOCKET not available": { - "DMS_SOCKET not available": "DMS_SOCKET 不可用" - }, - "DWL service not available": { - "DWL service not available": "DWL 服務不可用" - }, - "Daily": { - "Daily": "每日" - }, - "Daily at:": { - "Daily at:": "每日:" - }, - "Dank": { - "Dank": "Dank" - }, - "Dank Bar": { - "Dank Bar": "Dank Bar" - }, - "DankBar": { - "DankBar": "DankBar" - }, - "DankMaterialShell is ready to use": { - "DankMaterialShell is ready to use": "DankMaterialShell 已可使用" - }, - "DankShell & System Icons (requires restart)": { - "DankShell & System Icons (requires restart)": "DankShell 和系統圖示(需要重新啟動)" - }, - "Dark Mode": { - "Dark Mode": "深色主題" - }, - "Dark mode base": { - "Dark mode base": "深色模式基準" - }, - "Dark mode harmony": { - "Dark mode harmony": "深色模式協調" - }, - "Darken Modal Background": { - "Darken Modal Background": "暗化模態背景" - }, - "Date Format": { - "Date Format": "日期格式" - }, - "Date format": { - "Date format": "日期格式" - }, - "Date format on greeter": { - "Date format on greeter": "歡迎畫面上的日期格式" - }, - "Dawn (Astronomical Twilight)": { - "Dawn (Astronomical Twilight)": "黎明 (天文曙光)" - }, - "Dawn (Civil Twilight)": { - "Dawn (Civil Twilight)": "黎明 (民用曙光)" - }, - "Dawn (Nautical Twilight)": { - "Dawn (Nautical Twilight)": "黎明 (航海曙光)" - }, - "Day Date": { - "Day Date": "日期" - }, - "Day Month Date": { - "Day Month Date": "月日 (星期幾)" - }, - "Day Temperature": { - "Day Temperature": "日間色溫" - }, - "Daytime": { - "Daytime": "白天" - }, - "Deck": { - "Deck": "Deck" - }, - "Default": { - "Default": "預設" - }, - "Default (Black)": { - "Default (Black)": "預設 (黑色)" - }, - "Default Width (%)": { - "Default Width (%)": "預設寬度 (%)" - }, - "Default selected action": { - "Default selected action": "預設選定的動作" - }, - "Defaults": { - "Defaults": "預設" - }, - "Define rules for window behavior. Saves to %1": { - "Define rules for window behavior. Saves to %1": "定義視窗行為規則。儲存至 %1" - }, - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { - "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: 清除 • Shift+Del: 清除所有 • 1-9: 動作 • F10: 幫助 • Esc: 關閉" - }, - "Delete": { - "Delete": "刪除" - }, - "Delete \"%1\"?": { - "Delete \"%1\"?": "刪除 \"%1\"?" - }, - "Delete Class": { - "Delete Class": "刪除類別" - }, - "Delete Printer": { - "Delete Printer": "刪除印表機" - }, - "Delete Saved Item?": { - "Delete Saved Item?": "刪除已儲存項目?" - }, - "Delete VPN": { - "Delete VPN": "刪除 VPN" - }, - "Delete class \"%1\"?": { - "Delete class \"%1\"?": "刪除類別 \"%1\"?" - }, - "Delete profile \"%1\"?": { - "Delete profile \"%1\"?": "刪除設定檔 \"%1\"?" - }, - "Dependencies & documentation": { - "Dependencies & documentation": "依賴項與文件" - }, - "Derives colors that closely match the underlying image.": { - "Derives colors that closely match the underlying image.": "提取與底層圖像高度匹配的顏色。" - }, - "Description": { - "Description": "描述" - }, - "Desktop": { - "Desktop": "桌面" - }, - "Desktop Clock": { - "Desktop Clock": "桌面時鐘" - }, - "Desktop Entry": { - "Desktop Entry": "桌面項目" - }, - "Desktop Widget": { - "Desktop Widget": "桌面小工具" - }, - "Desktop Widgets": { - "Desktop Widgets": "桌面小工具" - }, - "Desktop background images": { - "Desktop background images": "桌面背景圖片" - }, - "Detailed": { - "Detailed": "詳細" - }, - "Details for \"%1": { - "Details for \"%1\"": "「%1」的詳細資訊" - }, - "Development": { - "Development": "開發" - }, - "Device": { - "Device": "設備" - }, - "Device connections": { - "Device connections": "裝置連線" - }, - "Device names updated": { - "Device names updated": "裝置名稱已更新" - }, - "Device paired": { - "Device paired": "裝置已配對" - }, - "Device unpaired": { - "Device unpaired": "裝置已解除配對" - }, - "Digital": { - "Digital": "數位" - }, - "Direction Source": { - "Direction Source": "方向來源" - }, - "Disable Autoconnect": { - "Disable Autoconnect": "關閉自動連線" - }, - "Disable Built-in Wallpapers": { - "Disable Built-in Wallpapers": "停用內建桌布" - }, - "Disable History Persistence": { - "Disable History Persistence": "停用歷史紀錄持久性" - }, - "Disable Output": { - "Disable Output": "停用輸出" - }, - "Disabled": { - "Disabled": "已停用" - }, - "Disabling WiFi...": { - "Disabling WiFi...": "正在停用 Wi-Fi..." - }, - "Disc": { - "Disc": "光碟" - }, - "Discard": { - "Discard": "捨棄" - }, - "Discharging": { - "Discharging": "放電中" - }, - "Disconnect": { - "Disconnect": "斷開連線" - }, - "Disconnected": { - "Disconnected": "已斷開連接" - }, - "Disconnected from WiFi": { - "Disconnected from WiFi": "已中斷 WiFi 連線" - }, - "Discover Devices": { - "Discover Devices": "探索裝置" - }, - "Disk": { - "Disk": "硬碟" - }, - "Disk I/O": { - "Disk I/O": "磁碟I/O" - }, - "Disk Usage": { - "Disk Usage": "硬碟使用率" - }, - "Disk Usage Display": { - "Disk Usage Display": "磁碟使用量顯示" - }, - "Disks": { - "Disks": "磁碟" - }, - "Dismiss": { - "Dismiss": "忽略" - }, - "Display": { - "Display": "顯示" - }, - "Display Assignment": { - "Display Assignment": "顯示分配" - }, - "Display Control": { - "Display Control": "顯示控制" - }, - "Display Name Format": { - "Display Name Format": "顯示名稱格式" - }, - "Display Profiles": { - "Display Profiles": "顯示設定檔" - }, - "Display Settings": { - "Display Settings": "顯示器設定" - }, - "Display a dock with pinned and running applications": { - "Display a dock with pinned and running applications": "顯示一個包含釘選和正在執行的應用程式的 Dock" - }, - "Display all priorities over fullscreen apps": { - "Display all priorities over fullscreen apps": "顯示全螢幕應用程式上的所有優先級" - }, - "Display and switch DWL layouts": { - "Display and switch DWL layouts": "顯示並切換 DWL 佈局" - }, - "Display application icons in workspace indicators": { - "Display application icons in workspace indicators": "在工作區標籤中顯示應用程式圖標" - }, - "Display brightness control": { - "Display brightness control": "顯示器亮度控制" - }, - "Display configuration is not available. WLR output management protocol not supported.": { - "Display configuration is not available. WLR output management protocol not supported.": "顯示器配置不可用。不支援 WLR 輸出管理通訊協定。" - }, - "Display currently focused application title": { - "Display currently focused application title": "顯示目前焦點應用程式的標題" - }, - "Display hourly weather predictions": { - "Display hourly weather predictions": "顯示每小時天氣預報" - }, - "Display only workspaces that contain windows": { - "Display only workspaces that contain windows": "只顯示包含視窗的工作區" - }, - "Display power menu actions in a grid instead of a list": { - "Display power menu actions in a grid instead of a list": "以網格而非列表顯示電源選單操作" - }, - "Display seconds in the clock": { - "Display seconds in the clock": "在時鐘中顯示秒數" - }, - "Display the power system menu": { - "Display the power system menu": "顯示電源系統選單" - }, - "Display volume and brightness percentage values in OSD popups": { - "Display volume and brightness percentage values in OSD popups": "在 OSD 彈出視窗中顯示音量和亮度百分比值" - }, - "Displays": { - "Displays": "螢幕" - }, - "Displays count when overflow is active": { - "Displays count when overflow is active": "當溢出啟用時的顯示計數" - }, - "Displays the active keyboard layout and allows switching": { - "Displays the active keyboard layout and allows switching": "顯示目前鍵盤布局且允許切換" - }, - "Distribution": { - "Distribution": "發行版" - }, - "Diverse palette spanning the full spectrum.": { - "Diverse palette spanning the full spectrum.": "涵蓋整個光譜的多元調色板。" - }, - "Do Not Disturb": { - "Do Not Disturb": "請勿打擾" - }, - "Dock": { - "Dock": "Dock" - }, - "Dock & Launcher": { - "Dock & Launcher": "Dock 和啟動器" - }, - "Dock Transparency": { - "Dock Transparency": "Dock 透明度" - }, - "Dock Visibility": { - "Dock Visibility": "Dock 可見性" - }, - "Docs": { - "Docs": "文件" - }, - "Documents": { - "Documents": "文件" - }, - "Domain (optional)": { - "Domain (optional)": "網域 (可選)" - }, - "Don't Change": { - "Don't Change": "不要變更" - }, - "Don't Save": { - "Don't Save": "不要儲存" - }, - "Door Open": { - "Door Open": "門開啟" - }, - "Downloads": { - "Downloads": "下載" - }, - "Drag to Reorder": { - "Drag to Reorder": "拖曳以重新排序" - }, - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { - "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖曳部件即可在版塊內重新排序。使用眼睛圖示隱藏/顯示部件 (會保持間距),或使用 X 將其完全移除。" - }, - "Drag workspace indicators to reorder them": { - "Drag workspace indicators to reorder them": "拖曳工作區指示器以重新排序" - }, - "Driver": { - "Driver": "驅動程式" - }, - "Drizzle": { - "Drizzle": "毛毛雨" - }, - "Duplicate": { - "Duplicate": "複製" - }, - "Duplicate Wallpaper with Blur": { - "Duplicate Wallpaper with Blur": "模糊化重複桌布" - }, - "Duration": { - "Duration": "持續時間" - }, - "Dusk (Astronomical Twilight)": { - "Dusk (Astronomical Twilight)": "黃昏 (天文暮光)" - }, - "Dusk (Civil Twighlight)": { - "Dusk (Civil Twighlight)": "黃昏 (民用暮光)" - }, - "Dusk (Nautical Twilight)": { - "Dusk (Nautical Twilight)": "黃昏 (航海暮光)" - }, - "Dynamic": { - "Dynamic": "動態" - }, - "Dynamic Properties": { - "Dynamic Properties": "動態屬性" - }, - "Dynamic Theming": { - "Dynamic Theming": "動態主題" - }, - "Dynamic colors from wallpaper": { - "Dynamic colors from wallpaper": "從桌布產生動態色彩" - }, - "Dynamic colors, presets": { - "Dynamic colors, presets": "動態顏色、預設集" - }, - "Edge Spacing": { - "Edge Spacing": "邊緣間距" - }, - "Edit App": { - "Edit App": "編輯應用程式" - }, - "Edit Window Rule": { - "Edit Window Rule": "編輯視窗規則" - }, - "Education": { - "Education": "教育" - }, - "Empty": { - "Empty": "空白" - }, - "Enable 10-bit color depth for wider color gamut and HDR support": { - "Enable 10-bit color depth for wider color gamut and HDR support": "啟用 10 位元色彩深度以獲得更寬廣的色域和 HDR 支援" - }, - "Enable Autoconnect": { - "Enable Autoconnect": "啟用自動連線" - }, - "Enable Bar": { - "Enable Bar": "啟用欄" - }, - "Enable Do Not Disturb": { - "Enable Do Not Disturb": "啟用勿擾模式" - }, - "Enable History": { - "Enable History": "啟用歷史記錄" - }, - "Enable Overview Overlay": { - "Enable Overview Overlay": "啟用概覽疊加層" - }, - "Enable Ripple Effects": { - "Enable Ripple Effects": "啟用漣漪效果" - }, - "Enable System Sounds": { - "Enable System Sounds": "啟用系統音效" - }, - "Enable Video Screensaver": { - "Enable Video Screensaver": "啟用影片螢幕保護程式" - }, - "Enable Weather": { - "Enable Weather": "啟用天氣預報" - }, - "Enable WiFi": { - "Enable WiFi": "啟用 WiFi" - }, - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": { - "Enable a custom override below to set per-bar shadow intensity, opacity, and color.": "啟用下面的自訂覆寫以設定每個列的陰影強度、不透明度和顏色。" - }, - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": { - "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "啟用合成器可定位的模糊圖層(命名空間:dms:blurwallpaper)。需要手動配置 niri。" - }, - "Enable fingerprint at login": { - "Enable fingerprint at login": "在登入時啟用指紋" - }, - "Enable fingerprint authentication": { - "Enable fingerprint authentication": "啟用指紋驗證" - }, - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": { - "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.": "" - }, - "Enable loginctl lock integration": { - "Enable loginctl lock integration": "啟用 loginctl 鎖定整合" - }, - "Enable security key at login": { - "Enable security key at login": "在登入時啟用安全密鑰" - }, - "Enable security key authentication": { - "Enable security key authentication": "啟用安全密鑰驗證" - }, - "Enabled": { - "Enabled": "已啟用" - }, - "Enabled, but fingerprint availability could not be confirmed.": { - "Enabled, but fingerprint availability could not be confirmed.": "已啟用,但無法確認指紋可用性。" - }, - "Enabled, but no fingerprint reader was detected.": { - "Enabled, but no fingerprint reader was detected.": "已啟用,但未偵測到指紋讀取器。" - }, - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": { - "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.": "" - }, - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": { - "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.": "已啟用,但尚未註冊指紋。請註冊指紋並執行同步。" - }, - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": { - "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.": "" - }, - "Enabled, but no registered security key was found yet. Register a key and run Sync.": { - "Enabled, but no registered security key was found yet. Register a key and run Sync.": "已啟用,但尚未找到已註冊的安全金鑰。請註冊金鑰並執行同步。" - }, - "Enabled, but security-key availability could not be confirmed.": { - "Enabled, but security-key availability could not be confirmed.": "已啟用,但無法確認安全金鑰可用性。" - }, - "Enabled. PAM already provides fingerprint auth.": { - "Enabled. PAM already provides fingerprint auth.": "已啟用。PAM 已提供指紋驗證。" - }, - "Enabled. PAM already provides security-key auth.": { - "Enabled. PAM already provides security-key auth.": "已啟用。PAM 已提供安全金鑰驗證。" - }, - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": { - "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.": "已啟用。PAM 提供指紋驗證,但尚未註冊指紋。" - }, - "Enabling WiFi...": { - "Enabling WiFi...": "正在啟用 Wi-Fi..." - }, - "End": { - "End": "結束" - }, - "Enlarge on Hover": { - "Enlarge on Hover": "懸停時放大" - }, - "Enlargement %": { - "Enlargement %": "放大 %" - }, - "Enter 6-digit passkey": { - "Enter 6-digit passkey": "輸入 6 位密碼" - }, - "Enter PIN": { - "Enter PIN": "請輸入 PIN" - }, - "Enter PIN for ": { - "Enter PIN for ": "請輸入 PIN 給 " - }, - "Enter URL or text to share": { - "Enter URL or text to share": "輸入網址或文字以分享" - }, - "Enter a new name for session \"%1": { - "Enter a new name for session \"%1\"": "為會話「%1」輸入新名稱" - }, - "Enter a new name for this workspace": { - "Enter a new name for this workspace": "為此工作區輸入新名稱" - }, - "Enter command or script path": { - "Enter command or script path": "輸入命令或腳本路徑" - }, - "Enter credentials for ": { - "Enter credentials for ": "輸入憑證 " - }, - "Enter custom lock screen format (e.g., dddd, MMMM d)": { - "Enter custom lock screen format (e.g., dddd, MMMM d)": "自訂鎖定畫面的日期格式 (例: dddd, MMMM d)" - }, - "Enter custom top bar format (e.g., ddd MMM d)": { - "Enter custom top bar format (e.g., ddd MMM d)": "自訂頂部欄的日期格式 (例: ddd, MMM d)" - }, - "Enter device name...": { - "Enter device name...": "輸入裝置名稱..." - }, - "Enter filename...": { - "Enter filename...": "請輸檔案名稱..." - }, - "Enter launch prefix (e.g., 'uwsm-app')": { - "Enter launch prefix (e.g., 'uwsm-app')": "輸入啟動前綴(例如:「uwsm-app」)" - }, - "Enter network name and password": { - "Enter network name and password": "輸入網路名稱和密碼" - }, - "Enter passkey for ": { - "Enter passkey for ": "請輸入密碼給 " - }, - "Enter password for ": { - "Enter password for ": "輸入密碼 " - }, - "Enter this passkey on ": { - "Enter this passkey on ": "輸入此密碼 " - }, - "Enter to Paste": { - "Enter to Paste": "按 Enter 貼上" - }, - "Enterprise": { - "Enterprise": "企業" - }, - "Entry pinned": { - "Entry pinned": "項目已釘選" - }, - "Entry unpinned": { - "Entry unpinned": "項目已解除釘選" - }, - "Environment Variables": { - "Environment Variables": "環境變數" - }, - "Error": { - "Error": "錯誤" - }, - "Errors": { - "Errors": "錯誤" - }, - "Ethernet": { - "Ethernet": "乙太網路" - }, - "Exact": { - "Exact": "精確" - }, - "Exclusive Zone Offset": { - "Exclusive Zone Offset": "獨佔區域偏移" - }, - "Experimental Feature": { - "Experimental Feature": "實驗性功能" - }, - "Explore": { - "Explore": "探索" - }, - "Exponential": { - "Exponential": "指數" - }, - "Expressive": { - "Expressive": "生動" - }, - "Extend battery life": { - "Extend battery life": "延長電池續航力" - }, - "Extensible architecture": { - "Extensible architecture": "可擴充架構" - }, - "External Wallpaper Management": { - "External Wallpaper Management": "外部桌布管理" - }, - "Extra Arguments": { - "Extra Arguments": "額外參數" - }, - "F1/I: Toggle • F10: Help": { - "F1/I: Toggle • F10: Help": "F1/I: 切換 • F10: 幫助" - }, - "Fade": { - "Fade": "淡化" - }, - "Fade to lock screen": { - "Fade to lock screen": "淡出至鎖定螢幕" - }, - "Fade to monitor off": { - "Fade to monitor off": "螢幕淡出關閉" - }, - "Failed to accept pairing": { - "Failed to accept pairing": "無法接受配對" - }, - "Failed to activate configuration": { - "Failed to activate configuration": "無法啟動配置" - }, - "Failed to activate profile - file not found": { - "Failed to activate profile - file not found": "無法啟用設定檔 - 找不到檔案" - }, - "Failed to add binds include": { - "Failed to add binds include": "新增綁定包含失敗" - }, - "Failed to add printer to class": { - "Failed to add printer to class": "無法將印表機新增至類別" - }, - "Failed to browse device": { - "Failed to browse device": "無法瀏覽裝置" - }, - "Failed to cancel all jobs": { - "Failed to cancel all jobs": "無法取消所有工作" - }, - "Failed to cancel selected job": { - "Failed to cancel selected job": "取消選定工作失敗" - }, - "Failed to check for updates:\n%1": { - "Failed to check for updates:\n%1": "檢查更新失敗:\n%1" - }, - "Failed to check pin limit": { - "Failed to check pin limit": "無法檢查釘選限制" - }, - "Failed to connect VPN": { - "Failed to connect VPN": "VPN 連線失敗" - }, - "Failed to connect to %1": { - "Failed to connect to %1": "無法連線至 %1" - }, - "Failed to copy entry": { - "Failed to copy entry": "複製項目失敗" - }, - "Failed to create printer": { - "Failed to create printer": "無法建立印表機" - }, - "Failed to create profiles directory": { - "Failed to create profiles directory": "無法建立設定檔目錄" - }, - "Failed to delete VPN": { - "Failed to delete VPN": "刪除 VPN 失敗" - }, - "Failed to delete class": { - "Failed to delete class": "無法刪除類別" - }, - "Failed to delete printer": { - "Failed to delete printer": "無法刪除印表機" - }, - "Failed to disable job acceptance": { - "Failed to disable job acceptance": "無法停用工作接受" - }, - "Failed to disable night mode": { - "Failed to disable night mode": "無法停用夜間模式" - }, - "Failed to disconnect VPN": { - "Failed to disconnect VPN": "無法斷開 VPN" - }, - "Failed to disconnect VPNs": { - "Failed to disconnect VPNs": "無法斷開 VPN" - }, - "Failed to disconnect WiFi": { - "Failed to disconnect WiFi": "無法斷開 WiFi" - }, - "Failed to enable IP location": { - "Failed to enable IP location": "無法啟用 IP 位置" - }, - "Failed to enable WiFi": { - "Failed to enable WiFi": "無法啟用 WiFi" - }, - "Failed to enable job acceptance": { - "Failed to enable job acceptance": "無法啟用工作接受" - }, - "Failed to enable night mode": { - "Failed to enable night mode": "無法啟用夜間模式" - }, - "Failed to hold job": { - "Failed to hold job": "無法保留工作" - }, - "Failed to import VPN": { - "Failed to import VPN": "匯入 VPN 失敗" - }, - "Failed to launch SMS app": { - "Failed to launch SMS app": "無法啟動簡訊應用程式" - }, - "Failed to load VPN config": { - "Failed to load VPN config": "載入 VPN 設定失敗" - }, - "Failed to load clipboard configuration.": { - "Failed to load clipboard configuration.": "載入剪貼簿組態失敗。" - }, - "Failed to move job": { - "Failed to move job": "無法移動工作" - }, - "Failed to parse plugin_settings.json": { - "Failed to parse plugin_settings.json": "無法解析 plugin_settings.json" - }, - "Failed to parse session.json": { - "Failed to parse session.json": "無法解析 session.json" - }, - "Failed to parse settings.json": { - "Failed to parse settings.json": "無法解析 settings.json" - }, - "Failed to pause printer": { - "Failed to pause printer": "無法暫停印表機" - }, - "Failed to pin entry": { - "Failed to pin entry": "無法釘選項目" - }, - "Failed to print test page": { - "Failed to print test page": "無法列印測試頁" - }, - "Failed to reject pairing": { - "Failed to reject pairing": "無法拒絕配對" - }, - "Failed to remove device": { - "Failed to remove device": "無法移除裝置" - }, - "Failed to remove keybind": { - "Failed to remove keybind": "移除按鍵綁定失敗" - }, - "Failed to remove printer from class": { - "Failed to remove printer from class": "無法從類別中移除印表機" - }, - "Failed to restart audio system": { - "Failed to restart audio system": "無法重新啟動音訊系統" - }, - "Failed to restart job": { - "Failed to restart job": "無法重新啟動工作" - }, - "Failed to resume printer": { - "Failed to resume printer": "印表機恢復失敗" - }, - "Failed to ring device": { - "Failed to ring device": "無法讓裝置響鈴" - }, - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": { - "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.": "執行 'dms greeter status' 失敗。請確保 DMS 已安裝且 dms 位於 PATH 中。" - }, - "Failed to save audio config": { - "Failed to save audio config": "無法儲存音訊設定" - }, - "Failed to save clipboard setting": { - "Failed to save clipboard setting": "儲存剪貼簿設定失敗" - }, - "Failed to save keybind": { - "Failed to save keybind": "保存按鍵綁定失敗" - }, - "Failed to save profile file": { - "Failed to save profile file": "無法儲存設定檔" - }, - "Failed to send clipboard": { - "Failed to send clipboard": "無法傳送剪貼簿" - }, - "Failed to send file": { - "Failed to send file": "傳送檔案失敗" - }, - "Failed to send ping": { - "Failed to send ping": "無法傳送 Ping" - }, - "Failed to set brightness": { - "Failed to set brightness": "無法設定亮度" - }, - "Failed to set night mode location": { - "Failed to set night mode location": "無法設定夜間模式位置" - }, - "Failed to set night mode schedule": { - "Failed to set night mode schedule": "無法設定夜間模式排程" - }, - "Failed to set night mode temperature": { - "Failed to set night mode temperature": "無法設定夜間模式色溫" - }, - "Failed to set power profile": { - "Failed to set power profile": "設定電源設定檔失敗" - }, - "Failed to set profile image": { - "Failed to set profile image": "無法設定個人資料圖片" - }, - "Failed to set profile image: %1": { - "Failed to set profile image: %1": "無法設定個人檔案圖片:%1" - }, - "Failed to share": { - "Failed to share": "無法分享" - }, - "Failed to start connection to %1": { - "Failed to start connection to %1": "無法啟動連線至 %1" - }, - "Failed to unpin entry": { - "Failed to unpin entry": "無法解除釘選項目" - }, - "Failed to update VPN": { - "Failed to update VPN": "更新 VPN 失敗" - }, - "Failed to update autoconnect": { - "Failed to update autoconnect": "自動連線更新失敗" - }, - "Failed to update description": { - "Failed to update description": "無法更新描述" - }, - "Failed to update location": { - "Failed to update location": "無法更新位置" - }, - "Failed to update sharing": { - "Failed to update sharing": "無法更新分享設定" - }, - "Failed to write temp file for validation": { - "Failed to write temp file for validation": "寫入驗證的暫存檔案失敗" - }, - "Features": { - "Features": "功能" - }, - "Feels": { - "Feels": "體感" - }, - "Feels Like": { - "Feels Like": "體感溫度" - }, - "Feels Like %1°": { - "Feels Like %1°": "體感溫度 %1°" - }, - "Fidelity": { - "Fidelity": "傳真度" - }, - "Field": { - "Field": "欄位" - }, - "File": { - "File": "檔案" - }, - "File Already Exists": { - "File Already Exists": "檔案已經存在" - }, - "File Information": { - "File Information": "檔案資訊" - }, - "File received from": { - "File received from": "檔案接收自" - }, - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": { - "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "檔案搜尋需要 dsearch\n從 github.com/morelazers/dsearch 安裝" - }, - "Files": { - "Files": "檔案" - }, - "Filesystem usage monitoring": { - "Filesystem usage monitoring": "檔案系統使用量監控" - }, - "Fill": { - "Fill": "填滿" - }, - "Find in Text": { - "Find in Text": "尋找文字" - }, - "Find in note...": { - "Find in note...": "尋找筆記..." - }, - "Fingerprint availability could not be confirmed.": { - "Fingerprint availability could not be confirmed.": "無法確認指紋可用性。" - }, - "Fingerprint error": { - "Fingerprint error": "" - }, - "Fingerprint error: %1": { - "Fingerprint error: %1": "" - }, - "Fingerprint not recognized (%1/%2). Please try again or use password.": { - "Fingerprint not recognized (%1/%2). Please try again or use password.": "" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.": "已偵測到指紋讀取器,但尚未註冊指紋。您可以現在啟用並稍後註冊。" - }, - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": { - "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.": "已偵測到指紋讀取器,但尚未註冊指紋。您可以現在啟用並稍後執行同步。" - }, - "Finish": { - "Finish": "完成" - }, - "First Day of Week": { - "First Day of Week": "一週的第一天" - }, - "First Time Setup": { - "First Time Setup": "首次設定" - }, - "Fit": { - "Fit": "符合" - }, - "Fix Now": { - "Fix Now": "立即修復" - }, - "Fixing...": { - "Fixing...": "正在修復..." - }, - "Flags": { - "Flags": "標幟" - }, - "Flipped": { - "Flipped": "翻轉" - }, - "Flipped 180°": { - "Flipped 180°": "翻轉 180°" - }, - "Flipped 270°": { - "Flipped 270°": "翻轉 270°" - }, - "Flipped 90°": { - "Flipped 90°": "翻轉 90°" - }, - "Float": { - "Float": "浮動" - }, - "Focus": { - "Focus": "聚焦" - }, - "Focus at Startup": { - "Focus at Startup": "啟動時聚焦" - }, - "Focused Border": { - "Focused Border": "聚焦邊框" - }, - "Focused Color": { - "Focused Color": "聚焦顏色" - }, - "Focused Monitor Only": { - "Focused Monitor Only": "僅限專注螢幕" - }, - "Focused Window": { - "Focused Window": "視窗對焦" - }, - "Focused monitor only": { - "Focused monitor only": "僅限專注螢幕" - }, - "Fog": { - "Fog": "霧" - }, - "Folder": { - "Folder": "資料夾" - }, - "Folders": { - "Folders": "資料夾" - }, - "Follow DMS background color": { - "Follow DMS background color": "" - }, - "Follow Monitor Focus": { - "Follow Monitor Focus": "跟隨螢幕焦點" - }, - "Follow focus": { - "Follow focus": "跟隨焦點" - }, - "Font": { - "Font": "字體" - }, - "Font Family": { - "Font Family": "字體" - }, - "Font Scale": { - "Font Scale": "字體比例" - }, - "Font Size": { - "Font Size": "字體大小" - }, - "Font Weight": { - "Font Weight": "字體粗細" - }, - "Font used on the login screen": { - "Font used on the login screen": "登入畫面使用的字體" - }, - "Force HDR": { - "Force HDR": "強制 HDR" - }, - "Force Kill (SIGKILL)": { - "Force Kill (SIGKILL)": "強制終止 (SIGKILL)" - }, - "Force Wide Color": { - "Force Wide Color": "強制廣色域" - }, - "Force terminal applications to always use dark color schemes": { - "Force terminal applications to always use dark color schemes": "強制終端應用程式始終使用深色配色方案" - }, - "Forecast": { - "Forecast": "預報" - }, - "Forecast Days": { - "Forecast Days": "預報天數" - }, - "Forecast Not Available": { - "Forecast Not Available": "預報不可用" - }, - "Forever": { - "Forever": "永遠" - }, - "Forget": { - "Forget": "忘記" - }, - "Forget \"%1\"?": { - "Forget \"%1\"?": "忘記 \"%1\"?" - }, - "Forget Device": { - "Forget Device": "忘記設備" - }, - "Forget Network": { - "Forget Network": "忘記網路" - }, - "Forgot network %1": { - "Forgot network %1": "忘記網路 %1" - }, - "Format Legend": { - "Format Legend": "格式說明" - }, - "Found %1 package to update:": { - "Found %1 package to update:": "找到 %1 個待更新套件:" - }, - "Found %1 packages to update:": { - "Found %1 packages to update:": "找到 %1 個待更新套件:" - }, - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": { - "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.": "啟動器關閉時釋放 VRAM/記憶體。重新打開時可能會造成輕微延遲。" - }, - "Freezing Drizzle": { - "Freezing Drizzle": "凍雨" - }, - "Frequency": { - "Frequency": "頻率" - }, - "Fruit Salad": { - "Fruit Salad": "水果沙拉" - }, - "Full Command:": { - "Full Command:": "完整指令:" - }, - "Full Content": { - "Full Content": "完整內容" - }, - "Full Day & Month": { - "Full Day & Month": "完整月日" - }, - "Full with Year": { - "Full with Year": "完整含年份" - }, - "Fullscreen": { - "Fullscreen": "全螢幕" - }, - "Fullscreen Only": { - "Fullscreen Only": "僅全螢幕" - }, - "Fully Charged": { - "Fully Charged": "已充飽電" - }, - "Fun": { - "Fun": "有趣的" - }, - "G: grid • Z/X: size": { - "G: grid • Z/X: size": "G:網格 • Z/X:大小" - }, - "GPU": { - "GPU": "GPU" - }, - "GPU Monitoring": { - "GPU Monitoring": "GPU 監控" - }, - "GPU Temperature": { - "GPU Temperature": "GPU 溫度" - }, - "GPU temperature display": { - "GPU temperature display": "GPU 溫度顯示" - }, - "GTK, Qt, IDEs, more": { - "GTK, Qt, IDEs, more": "GTK、Qt、IDE 等" - }, - "Games": { - "Games": "遊戲" - }, - "Gamma Control": { - "Gamma Control": "Gamma 控制" - }, - "Gamma control not available. Requires DMS API v6+.": { - "Gamma control not available. Requires DMS API v6+.": "Gamma 控制不可用。需要 DMS API v6+。" - }, - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": { - "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.": "產生基準 GTK3/4 或 QT5/QT6(需要 qt6ct-kde)配置以遵循 DMS 顏色。僅需執行一次。

        建議在應用 GTK 主題之前配置adw-gtk3。" - }, - "Generic": { - "Generic": "一般" - }, - "Get Started": { - "Get Started": "開始使用" - }, - "GitHub": { - "GitHub": "GitHub" - }, - "Globally scale all animation durations": { - "Globally scale all animation durations": "全域縮放所有動畫持續時間" - }, - "Golden Hour": { - "Golden Hour": "黃金時段" - }, - "Good": { - "Good": "好" - }, - "Goth Corner Radius": { - "Goth Corner Radius": "圓角半徑" - }, - "Goth Corners": { - "Goth Corners": "圓角介面融合" - }, - "Gradually fade the screen before locking with a configurable grace period": { - "Gradually fade the screen before locking with a configurable grace period": "在鎖定前逐漸淡出螢幕,並帶有可設定的緩衝期" - }, - "Gradually fade the screen before turning off monitors with a configurable grace period": { - "Gradually fade the screen before turning off monitors with a configurable grace period": "關閉顯示器前逐漸淡化螢幕,可設定緩衝期" - }, - "Graph Time Range": { - "Graph Time Range": "圖表時間範圍" - }, - "Graphics": { - "Graphics": "圖形" - }, - "Greeter": { - "Greeter": "歡迎畫面" - }, - "Greeter Appearance": { - "Greeter Appearance": "歡迎畫面外觀" - }, - "Greeter Behavior": { - "Greeter Behavior": "歡迎畫面行為" - }, - "Greeter Status": { - "Greeter Status": "歡迎畫面狀態" - }, - "Greeter activated. greetd is now enabled.": { - "Greeter activated. greetd is now enabled.": "歡迎畫面已啟用。greetd 現已啟用。" - }, - "Greeter font": { - "Greeter font": "歡迎畫面字體" - }, - "Greeter only — does not affect main clock": { - "Greeter only — does not affect main clock": "僅限歡迎畫面 — 不影響主時鐘" - }, - "Greeter only — format for the date on the login screen": { - "Greeter only — format for the date on the login screen": "僅限歡迎畫面 — 登入畫面上日期的格式" - }, - "Grid": { - "Grid": "網格" - }, - "Grid Columns": { - "Grid Columns": "網格欄數" - }, - "Grid: OFF": { - "Grid: OFF": "網格:關閉" - }, - "Grid: ON": { - "Grid: ON": "網格:開啟" - }, - "Group": { - "Group": "群組" - }, - "Group Workspace Apps": { - "Group Workspace Apps": "群組工作區應用程式" - }, - "Group by App": { - "Group by App": "App 分組" - }, - "Group multiple windows of the same app together with a window count indicator": { - "Group multiple windows of the same app together with a window count indicator": "將同一應用程式的多個視窗匯集在一起,並附帶視窗數量指示器" - }, - "Group removed": { - "Group removed": "群組已移除" - }, - "Group repeated application icons in unfocused workspaces": { - "Group repeated application icons in unfocused workspaces": "群組非作用中工作區的重複應用程式圖示" - }, - "Groups": { - "Groups": "群組" - }, - "HDR (EDID)": { - "HDR (EDID)": "HDR (EDID)" - }, - "HDR Tone Mapping": { - "HDR Tone Mapping": "HDR 色調映射" - }, - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": { - "HDR mode is experimental. Verify your monitor supports HDR before enabling.": "HDR 模式為實驗性質。啟用前請確認您的顯示器支援 HDR。" - }, - "HSV": { - "HSV": "HSV" - }, - "HTML copied to clipboard": { - "HTML copied to clipboard": "HTML 已複製到剪貼簿" - }, - "Health": { - "Health": "健康狀態" - }, - "Heavy Rain": { - "Heavy Rain": "大雨" - }, - "Heavy Snow": { - "Heavy Snow": "大雪" - }, - "Heavy Snow Showers": { - "Heavy Snow Showers": "大陣雪" - }, - "Height": { - "Height": "高度" - }, - "Held": { - "Held": "保留" - }, - "Help": { - "Help": "說明" - }, - "Hex": { - "Hex": "Hex" - }, - "Hibernate": { - "Hibernate": "休眠" - }, - "Hidden": { - "Hidden": "隱藏的" - }, - "Hidden (%1)": { - "Hidden (%1)": "隱藏 (%1)" - }, - "Hidden Apps": { - "Hidden Apps": "隱藏的應用程式" - }, - "Hidden Network": { - "Hidden Network": "隱藏網路" - }, - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": { - "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.": "隱藏的應用程式不會出現在啟動器中。右鍵點擊應用程式並選擇「隱藏應用程式」即可隱藏。" - }, - "Hide": { - "Hide": "隱藏" - }, - "Hide 3rd Party": { - "Hide 3rd Party": "隱藏第三方" - }, - "Hide App": { - "Hide App": "隱藏應用程式" - }, - "Hide Delay": { - "Hide Delay": "隱藏延遲" - }, - "Hide Indicators": { - "Hide Indicators": "隱藏指示器" - }, - "Hide Updater Widget": { - "Hide Updater Widget": "隱藏更新器小工具" - }, - "Hide When Typing": { - "Hide When Typing": "打字時隱藏" - }, - "Hide When Windows Open": { - "Hide When Windows Open": "視窗開啟時隱藏" - }, - "Hide cursor after inactivity (0 = disabled)": { - "Hide cursor after inactivity (0 = disabled)": "閒置後隱藏游標 (0 = 停用)" - }, - "Hide cursor when pressing keyboard keys": { - "Hide cursor when pressing keyboard keys": "按下鍵盤按鍵時隱藏游標" - }, - "Hide cursor when using touch input": { - "Hide cursor when using touch input": "使用觸控輸入時隱藏游標" - }, - "Hide device": { - "Hide device": "隱藏裝置" - }, - "Hide notification content until expanded": { - "Hide notification content until expanded": "展開前隱藏通知內容" - }, - "Hide notification content until expanded; popups show collapsed by default": { - "Hide notification content until expanded; popups show collapsed by default": "展開前隱藏通知內容;彈出視窗預設顯示為摺疊狀態" - }, - "Hide on Touch": { - "Hide on Touch": "觸控時隱藏" - }, - "High-fidelity palette that preserves source hues.": { - "High-fidelity palette that preserves source hues.": "保留來源色調的高保真調色板。" - }, - "Highlight Active Workspace App": { - "Highlight Active Workspace App": "突顯活躍工作區應用程式" - }, - "Highlight the currently focused app inside workspace indicators": { - "Highlight the currently focused app inside workspace indicators": "突顯工作區指示器中目前專注的應用程式" - }, - "History": { - "History": "歷史記錄" - }, - "History Retention": { - "History Retention": "歷史記錄保留期限" - }, - "History Settings": { - "History Settings": "歷史紀錄設定" - }, - "History cleared. %1 pinned entries kept.": { - "History cleared. %1 pinned entries kept.": "歷史記錄已清除。保留 %1 個釘選項目。" - }, - "Hold Duration": { - "Hold Duration": "按住持續時間" - }, - "Hold longer to confirm": { - "Hold longer to confirm": "按住更長時間以確認" - }, - "Hold to Confirm Power Actions": { - "Hold to Confirm Power Actions": "按住以確認電源操作" - }, - "Hold to confirm (%1 ms)": { - "Hold to confirm (%1 ms)": "按住以確認 (%1 毫秒)" - }, - "Hold to confirm (%1s)": { - "Hold to confirm (%1s)": "按住以確認 (%1s)" - }, - "Home": { - "Home": "家" - }, - "Host": { - "Host": "主機" - }, - "Hostname": { - "Hostname": "主機名稱" - }, - "Hot Corners": { - "Hot Corners": "熱區角落" - }, - "Hotkey overlay title (optional)": { - "Hotkey overlay title (optional)": "快捷鍵疊加層標題 (可選)" - }, - "Hour": { - "Hour": "小時" - }, - "Hourly": { - "Hourly": "每小時" - }, - "Hourly Forecast Count": { - "Hourly Forecast Count": "每小時預報數量" - }, - "How often to change wallpaper": { - "How often to change wallpaper": "多久更換一次桌布" - }, - "How the background image is scaled": { - "How the background image is scaled": "背景圖片的縮放方式" - }, - "Humidity": { - "Humidity": "濕度" - }, - "Hyprland Discord Server": { - "Hyprland Discord Server": "Hyprland Discord 伺服器" - }, - "Hyprland Layout Overrides": { - "Hyprland Layout Overrides": "Hyprland 版面配置覆寫" - }, - "Hyprland Options": { - "Hyprland Options": "Hyprland 選項" - }, - "Hyprland Website": { - "Hyprland Website": "Hyprland 網站" - }, - "I Understand": { - "I Understand": "我了解" - }, - "IP": { - "IP": "IP" - }, - "IP Address:": { - "IP Address:": "IP 位址:" - }, - "IP address or hostname": { - "IP address or hostname": "IP 位址或主機名稱" - }, - "ISO Date": { - "ISO Date": "ISO 日期" - }, - "Icon": { - "Icon": "圖示" - }, - "Icon Scale": { - "Icon Scale": "圖標縮放" - }, - "Icon Size": { - "Icon Size": "圖示大小" - }, - "Icon Size %": { - "Icon Size %": "圖示大小 %" - }, - "Icon Theme": { - "Icon Theme": "圖示主題" - }, - "Idle": { - "Idle": "閒置" - }, - "Idle Inhibitor": { - "Idle Inhibitor": "空閒抑制器" - }, - "Idle Settings": { - "Idle Settings": "閒置設定" - }, - "Idle monitoring not supported - requires newer Quickshell version": { - "Idle monitoring not supported - requires newer Quickshell version": "不支援閒置監控 - 需要最新的 Quickshell 版本" - }, - "If the field is hidden, it will appear as soon as a key is pressed.": { - "If the field is hidden, it will appear as soon as a key is pressed.": "如果此欄位已隱藏,只要按下按鍵便會顯示。" - }, - "Ignore Completely": { - "Ignore Completely": "完全忽略" - }, - "Image": { - "Image": "圖片" - }, - "Image copied to clipboard": { - "Image copied to clipboard": "影像已複製到剪貼簿" - }, - "Import": { - "Import": "匯入" - }, - "Import VPN": { - "Import VPN": "匯入 VPN" - }, - "Inactive Monitor Color": { - "Inactive Monitor Color": "非活動監視器顏色" - }, - "Include Files in All Tab": { - "Include Files in All Tab": "" - }, - "Include Folders in All Tab": { - "Include Folders in All Tab": "" - }, - "Include Transitions": { - "Include Transitions": "包括過渡" - }, - "Include desktop actions (shortcuts) in search results.": { - "Include desktop actions (shortcuts) in search results.": "在搜尋結果中包含桌面動作(捷徑)。" - }, - "Incompatible Plugins Loaded": { - "Incompatible Plugins Loaded": "載入了不相容的外掛程式" - }, - "Incorrect password": { - "Incorrect password": "密碼錯誤" - }, - "Incorrect password - attempt %1 of %2 (lockout may follow)": { - "Incorrect password - attempt %1 of %2 (lockout may follow)": "密碼不正確 - 第 %1 次嘗試(共 %2 次,之後可能會鎖定帳戶)" - }, - "Incorrect password - next failures may trigger account lockout": { - "Incorrect password - next failures may trigger account lockout": "密碼不正確 - 接下來的失敗可能會觸發帳戶鎖定" - }, - "Incorrect password - try again": { - "Incorrect password - try again": "" - }, - "Indicator Style": { - "Indicator Style": "指示樣式" - }, - "Individual Batteries": { - "Individual Batteries": "獨立電池" - }, - "Individual bar configuration": { - "Individual bar configuration": "個別欄設定" - }, - "Info": { - "Info": "資訊" - }, - "Inherit": { - "Inherit": "繼承" - }, - "Inherit Global (Default)": { - "Inherit Global (Default)": "繼承全域 (預設)" - }, - "Inhibitable": { - "Inhibitable": "可抑制" - }, - "Input Devices": { - "Input Devices": "輸入設備" - }, - "Input Volume Slider": { - "Input Volume Slider": "輸入音量滑桿" - }, - "Insert your security key...": { - "Insert your security key...": "" - }, - "Install": { - "Install": "安裝" - }, - "Install Greeter": { - "Install Greeter": "安裝歡迎畫面" - }, - "Install Plugin": { - "Install Plugin": "安裝外掛" - }, - "Install Theme": { - "Install Theme": "安裝主題" - }, - "Install color themes from the DMS theme registry": { - "Install color themes from the DMS theme registry": "從 DMS 主題登錄檔安裝色彩主題" - }, - "Install complete. Greeter has been installed.": { - "Install complete. Greeter has been installed.": "安裝完成。歡迎畫面已安裝。" - }, - "Install failed: %1": { - "Install failed: %1": "安裝失敗:%1" - }, - "Install matugen package for dynamic theming": { - "Install matugen package for dynamic theming": "安裝 matugen 套件以實現動態主題" - }, - "Install plugin '%1' from the DMS registry?": { - "Install plugin '%1' from the DMS registry?": "要從 DMS 登錄檔安裝外掛「%1」嗎?" - }, - "Install plugins from the DMS plugin registry": { - "Install plugins from the DMS plugin registry": "從 DMS 插件註冊表安裝插件" - }, - "Install the DMS greeter? A terminal will open for sudo authentication.": { - "Install the DMS greeter? A terminal will open for sudo authentication.": "安裝 DMS 歡迎畫面?將開啟終端機以進行 sudo 驗證。" - }, - "Install theme '%1' from the DMS registry?": { - "Install theme '%1' from the DMS registry?": "要從 DMS 登錄檔安裝主題「%1」嗎?" - }, - "Installation and PAM setup: see the ": { - "Installation and PAM setup: see the ": "安裝和 PAM 設定:請參閱" - }, - "Installed": { - "Installed": "已安裝" - }, - "Installed: %1": { - "Installed: %1": "已安裝:%1" - }, - "Installing: %1": { - "Installing: %1": "正在安裝:%1" - }, - "Intelligent Auto-hide": { - "Intelligent Auto-hide": "智慧型自動隱藏" - }, - "Intensity": { - "Intensity": "強度" - }, - "Interface:": { - "Interface:": "介面:" - }, - "Interlock Open": { - "Interlock Open": "聯鎖開啟" - }, - "Internet": { - "Internet": "網際網路" - }, - "Interval": { - "Interval": "間隔" - }, - "Invalid configuration": { - "Invalid configuration": "無效配置" - }, - "Invert on mode change": { - "Invert on mode change": "模式改變時反轉" - }, - "Iris Bloom": { - "Iris Bloom": "鳶尾花開" - }, - "Isolate Displays": { - "Isolate Displays": "隔離顯示器" - }, - "Jobs": { - "Jobs": "工作" - }, - "Jobs: ": { - "Jobs: ": "工作: " - }, - "Keep Awake": { - "Keep Awake": "保持喚醒" - }, - "Keep Changes": { - "Keep Changes": "保留變更" - }, - "Keeping Awake": { - "Keeping Awake": "保持喚醒" - }, - "Kernel": { - "Kernel": "核心" - }, - "Key": { - "Key": "按鍵" - }, - "Keybind Sources": { - "Keybind Sources": "快捷鍵來源" - }, - "Keybinds": { - "Keybinds": "按鍵綁定" - }, - "Keybinds Search Settings": { - "Keybinds Search Settings": "快捷鍵搜尋設定" - }, - "Keybinds shown alongside regular search results": { - "Keybinds shown alongside regular search results": "快捷鍵與一般搜尋結果一同顯示" - }, - "Keyboard Layout Name": { - "Keyboard Layout Name": "鍵盤布局名稱" - }, - "Keyboard Shortcuts": { - "Keyboard Shortcuts": "鍵盤快捷鍵" - }, - "Keys": { - "Keys": "按鍵" - }, - "Kill": { - "Kill": "終止" - }, - "Kill Process": { - "Kill Process": "結束程序" - }, - "Kill Session": { - "Kill Session": "終止會話" - }, - "Ko-fi": { - "Ko-fi": "Ko-fi" - }, - "LED device": { - "LED device": "LED 裝置" - }, - "LabWC IRC Channel": { - "LabWC IRC Channel": "LabWC IRC 頻道" - }, - "LabWC Website": { - "LabWC Website": "LabWC 網站" - }, - "Large": { - "Large": "大" - }, - "Largest": { - "Largest": "最大" - }, - "Last hour": { - "Last hour": "最近一小時" - }, - "Last launched %1": { - "Last launched %1": "上次啟動於 %1" - }, - "Last launched %1 day ago": { - "Last launched %1 day ago": "上次啟動於 %1 天前" - }, - "Last launched %1 days ago": { - "Last launched %1 days ago": "上次啟動於 %1 天前" - }, - "Last launched %1 hour ago": { - "Last launched %1 hour ago": "上次啟動於 %1 小時前" - }, - "Last launched %1 hours ago": { - "Last launched %1 hours ago": "上次啟動於 %1 小時前" - }, - "Last launched %1 minute ago": { - "Last launched %1 minute ago": "上次啟動於 %1 分鐘前" - }, - "Last launched %1 minutes ago": { - "Last launched %1 minutes ago": "上次啟動於 %1 分鐘前" - }, - "Last launched just now": { - "Last launched just now": "剛剛啟動" - }, - "Latitude": { - "Latitude": "緯度" - }, - "Launch": { - "Launch": "啟動" - }, - "Launch Prefix": { - "Launch Prefix": "啟動開頭" - }, - "Launch on dGPU": { - "Launch on dGPU": "在 dGPU 上啟動" - }, - "Launch on dGPU by default": { - "Launch on dGPU by default": "" - }, - "Launcher": { - "Launcher": "啟動器" - }, - "Launcher Button": { - "Launcher Button": "啟動器按鈕" - }, - "Launcher Button Logo": { - "Launcher Button Logo": "啟動器按鈕 Logo" - }, - "Layout": { - "Layout": "佈局" - }, - "Layout Overrides": { - "Layout Overrides": "版面配置覆寫" - }, - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": { - "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.": "歡迎畫面的佈局和模組位置與您的 Shell(例如 bar 配置)同步。執行同步以應用。" - }, - "Left": { - "Left": "左" - }, - "Left Center": { - "Left Center": "左中央" - }, - "Left Section": { - "Left Section": "左方區塊" - }, - "Light Direction": { - "Light Direction": "光線方向" - }, - "Light Mode": { - "Light Mode": "淺色主題" - }, - "Light Rain": { - "Light Rain": "小雨" - }, - "Light Snow": { - "Light Snow": "小雪" - }, - "Light Snow Showers": { - "Light Snow Showers": "小陣雪" - }, - "Light mode base": { - "Light mode base": "淺色模式基準" - }, - "Light mode harmony": { - "Light mode harmony": "淺色模式協調" - }, - "Line": { - "Line": "線" - }, - "Line: %1": { - "Line: %1": "行:%1" - }, - "Linear": { - "Linear": "線性" - }, - "Lines: %1": { - "Lines: %1": "行數:" - }, - "List": { - "List": "清單" - }, - "Lively palette with saturated accents.": { - "Lively palette with saturated accents.": "活潑的色調,帶有飽和的色調。" - }, - "Load Average": { - "Load Average": "平均負載" - }, - "Loading codecs...": { - "Loading codecs...": "正在載入編解碼器..." - }, - "Loading keybinds...": { - "Loading keybinds...": "正在載入按鍵綁定..." - }, - "Loading trending...": { - "Loading trending...": "載入熱門項目中..." - }, - "Loading...": { - "Loading...": "載入中..." - }, - "Local": { - "Local": "本機" - }, - "Locale": { - "Locale": "地區設定" - }, - "Locale Settings": { - "Locale Settings": "地區設定" - }, - "Location": { - "Location": "位置" - }, - "Location Search": { - "Location Search": "位置搜尋" - }, - "Lock": { - "Lock": "鎖定" - }, - "Lock Screen": { - "Lock Screen": "鎖定螢幕" - }, - "Lock Screen Display": { - "Lock Screen Display": "鎖定畫面顯示" - }, - "Lock Screen Format": { - "Lock Screen Format": "鎖定螢幕格式" - }, - "Lock Screen behaviour": { - "Lock Screen behaviour": "鎖定螢幕行為" - }, - "Lock Screen layout": { - "Lock Screen layout": "鎖定螢幕版面配置" - }, - "Lock at startup": { - "Lock at startup": "開機時鎖定" - }, - "Lock before suspend": { - "Lock before suspend": "鎖定後睡眠" - }, - "Lock fade grace period": { - "Lock fade grace period": "鎖定淡出緩衝期" - }, - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": { - "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.": "" - }, - "Locked": { - "Locked": "已鎖定" - }, - "Log Out": { - "Log Out": "登出" - }, - "Logging in...": { - "Logging in...": "正在登入..." - }, - "Login": { - "Login": "" - }, - "Login Authentication": { - "Login Authentication": "登入驗證" - }, - "Long": { - "Long": "長" - }, - "Long Text": { - "Long Text": "長文字" - }, - "Long press": { - "Long press": "長按" - }, - "Longitude": { - "Longitude": "經度" - }, - "Low Priority": { - "Low Priority": "低優先級" - }, - "MAC": { - "MAC": "MAC" - }, - "MTU": { - "MTU": "MTU" - }, - "Make sure KDE Connect or Valent is running on your other devices": { - "Make sure KDE Connect or Valent is running on your other devices": "請確認您的其他裝置上已執行 KDE Connect 或 Valent" - }, - "Manage and configure plugins for extending DMS functionality": { - "Manage and configure plugins for extending DMS functionality": "管理和配置用於擴展 DMS 功能的插件" - }, - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "管理最多 4 個獨立的欄設定。每個欄都有自己的位置、小工具、樣式和顯示分配。" - }, - "Management": { - "Management": "管理" - }, - "MangoWC Layout Overrides": { - "MangoWC Layout Overrides": "MangoWC 版面配置覆寫" - }, - "Manual": { - "Manual": "手動" - }, - "Manual Coordinates": { - "Manual Coordinates": "手動設定座標" - }, - "Manual Direction": { - "Manual Direction": "手動方向" - }, - "Manual Gap Size": { - "Manual Gap Size": "手動調整間隔" - }, - "Manual Show/Hide": { - "Manual Show/Hide": "手動顯示/隱藏" - }, - "Map window class names to icon names for proper icon display": { - "Map window class names to icon names for proper icon display": "為正確顯示圖示,將視窗類別名稱對應至圖示名稱" - }, - "Margin": { - "Margin": "邊距" - }, - "Marker Supply Empty": { - "Marker Supply Empty": "標記耗材用盡" - }, - "Marker Supply Low": { - "Marker Supply Low": "麥克筆存量低" - }, - "Marker Waste Almost Full": { - "Marker Waste Almost Full": "標記廢料即將滿載" - }, - "Marker Waste Full": { - "Marker Waste Full": "標記廢料已滿" - }, - "Match Criteria": { - "Match Criteria": "符合條件" - }, - "Matches profile: %1": { - "Matches profile: %1": "符合設定檔:%1" - }, - "Material Colors": { - "Material Colors": "手動調整顏色" - }, - "Material Design inspired color themes": { - "Material Design inspired color themes": "受 Material Design 啟發的色彩主題" - }, - "Material colors generated from wallpaper": { - "Material colors generated from wallpaper": "從桌布產生 Material 色彩" - }, - "Material inspired shadows and elevation on modals, popouts, and dialogs": { - "Material inspired shadows and elevation on modals, popouts, and dialogs": "受 Material Design 啟發的陰影和抬升效果,應用於模態框、彈出視窗和對話框" - }, - "Matugen Contrast": { - "Matugen Contrast": "" - }, - "Matugen Missing": { - "Matugen Missing": "Matugen 遺失" - }, - "Matugen Palette": { - "Matugen Palette": "Matugen 調色板" - }, - "Matugen Target Monitor": { - "Matugen Target Monitor": "Matugen 目標監視器" - }, - "Matugen Templates": { - "Matugen Templates": "Matugen 範本" - }, - "Max Edges": { - "Max Edges": "最大邊界" - }, - "Max H": { - "Max H": "最大高度" - }, - "Max Pinned Apps": { - "Max Pinned Apps": "最多釘選應用程式" - }, - "Max Pinned Apps (0 = Unlimited)": { - "Max Pinned Apps (0 = Unlimited)": "最多釘選應用程式 (0 = 無限制)" - }, - "Max Running Apps": { - "Max Running Apps": "最多執行中應用程式" - }, - "Max Running Apps (0 = Unlimited)": { - "Max Running Apps (0 = Unlimited)": "最多執行中應用程式 (0 = 無限制)" - }, - "Max Volume": { - "Max Volume": "最大音量" - }, - "Max W": { - "Max W": "最大寬度" - }, - "Max apps to show": { - "Max apps to show": "最多顯示App" - }, - "Max to Edges": { - "Max to Edges": "最大化至邊緣" - }, - "Maximize": { - "Maximize": "最大化" - }, - "Maximize Detection": { - "Maximize Detection": "最大化偵測" - }, - "Maximize Widget Icons": { - "Maximize Widget Icons": "最大化小部件圖標" - }, - "Maximize Widget Text": { - "Maximize Widget Text": "最大化小部件文字" - }, - "Maximum Entry Size": { - "Maximum Entry Size": "單一項目最大大小" - }, - "Maximum History": { - "Maximum History": "歷史紀錄上限" - }, - "Maximum Pinned Entries": { - "Maximum Pinned Entries": "最大釘選項目數量" - }, - "Maximum fingerprint attempts reached. Please use password.": { - "Maximum fingerprint attempts reached. Please use password.": "" - }, - "Maximum number of clipboard entries to keep": { - "Maximum number of clipboard entries to keep": "剪貼簿項目保留數量上限" - }, - "Maximum number of entries that can be saved": { - "Maximum number of entries that can be saved": "可儲存的最大項目數量" - }, - "Maximum number of notifications to keep": { - "Maximum number of notifications to keep": "通知保留上限" - }, - "Maximum pinned entries reached": { - "Maximum pinned entries reached": "已達最大釘選項目數量" - }, - "Maximum size per clipboard entry": { - "Maximum size per clipboard entry": "每個剪貼簿項目的最大大小" - }, - "Media": { - "Media": "媒體播放器" - }, - "Media Controls": { - "Media Controls": "媒體控制台" - }, - "Media Empty": { - "Media Empty": "媒體空白" - }, - "Media Jam": { - "Media Jam": "卡紙" - }, - "Media Low": { - "Media Low": "媒體不足" - }, - "Media Needed": { - "Media Needed": "需要媒體" - }, - "Media Playback": { - "Media Playback": "媒體播放" - }, - "Media Player": { - "Media Player": "媒體播放器" - }, - "Media Player Settings": { - "Media Player Settings": "媒體播放設定" - }, - "Media Players": { - "Media Players": "媒體播放器" - }, - "Media Players (": { - "Media Players (": "媒體播放 (" - }, - "Media Volume": { - "Media Volume": "媒體音量" - }, - "Medium": { - "Medium": "中" - }, - "Memory": { - "Memory": "記憶體" - }, - "Memory Graph": { - "Memory Graph": "記憶體圖表" - }, - "Memory Usage": { - "Memory Usage": "記憶體使用率" - }, - "Memory usage indicator": { - "Memory usage indicator": "記憶體使用率指示器" - }, - "Merge indexed file results into the All tab (requires dsearch).": { - "Merge indexed file results into the All tab (requires dsearch).": "" - }, - "Merge indexed folder results into the All tab (requires dsearch).": { - "Merge indexed folder results into the All tab (requires dsearch).": "" - }, - "Message": { - "Message": "訊息" - }, - "Message Content": { - "Message Content": "訊息內容" - }, - "Microphone": { - "Microphone": "麥克風" - }, - "Microphone Mute": { - "Microphone Mute": "麥克風靜音" - }, - "Microphone Volume": { - "Microphone Volume": "麥克風音量" - }, - "Microphone settings": { - "Microphone settings": "麥克風設定" - }, - "Microphone volume control": { - "Microphone volume control": "麥克風音量控制" - }, - "Middle Section": { - "Middle Section": "中間部分" - }, - "Min H": { - "Min H": "最小高度" - }, - "Min W": { - "Min W": "最小寬度" - }, - "Minimal palette built around a single hue.": { - "Minimal palette built around a single hue.": "圍繞單一色調構建的最小調色板。" - }, - "Minute": { - "Minute": "分鐘" - }, - "Mirror Display": { - "Mirror Display": "鏡像顯示" - }, - "Missing Environment Variables": { - "Missing Environment Variables": "缺少環境變數" - }, - "Modal Background": { - "Modal Background": "互動視窗背景" - }, - "Modal Shadows": { - "Modal Shadows": "模態陰影" - }, - "Modals": { - "Modals": "模態視窗" - }, - "Mode": { - "Mode": "模式" - }, - "Mode:": { - "Mode:": "模式:" - }, - "Model": { - "Model": "型號" - }, - "Modified": { - "Modified": "已修改" - }, - "Modular widget bar": { - "Modular widget bar": "模組化小工具列" - }, - "Monitor": { - "Monitor": "顯示器" - }, - "Monitor Configuration": { - "Monitor Configuration": "顯示器配置" - }, - "Monitor fade grace period": { - "Monitor fade grace period": "顯示器淡出緩衝期" - }, - "Monitor whose wallpaper drives dynamic theming colors": { - "Monitor whose wallpaper drives dynamic theming colors": "系統介面顏色依據哪一個螢幕上的桌布來決定" - }, - "Monochrome": { - "Monochrome": "單色" - }, - "Monocle": { - "Monocle": "單片" - }, - "Monospace Font": { - "Monospace Font": "等寬字體" - }, - "Month Date": { - "Month Date": "月日" - }, - "Morning": { - "Morning": "早上" - }, - "Mount Points": { - "Mount Points": "掛載點" - }, - "Mouse pointer appearance": { - "Mouse pointer appearance": "滑鼠指標外觀" - }, - "Mouse pointer size in pixels": { - "Mouse pointer size in pixels": "滑鼠指標像素大小" - }, - "Move": { - "Move": "移動" - }, - "Move Widget": { - "Move Widget": "移動小工具" - }, - "Moving to Paused": { - "Moving to Paused": "正在移至暫停" - }, - "Multi-Monitor": { - "Multi-Monitor": "多顯示器" - }, - "Multiplexer": { - "Multiplexer": "多工器" - }, - "Multiplexer Type": { - "Multiplexer Type": "多工器類型" - }, - "Multiplexers": { - "Multiplexers": "多工器" - }, - "Music": { - "Music": "音樂" - }, - "Mute Popups": { - "Mute Popups": "靜音彈出視窗" - }, - "Mute popups for %1": { - "Mute popups for %1": "靜音 %1 的彈出視窗" - }, - "Muted": { - "Muted": "靜音" - }, - "Muted Apps": { - "Muted Apps": "已靜音的應用程式" - }, - "Muted palette with subdued, calming tones.": { - "Muted palette with subdued, calming tones.": "柔和的調色板,柔和、平靜的色調。" - }, - "NM not supported": { - "NM not supported": "NM 不支援" - }, - "Name": { - "Name": "名稱" - }, - "Named Workspace Icons": { - "Named Workspace Icons": "命名工作區圖示" - }, - "Navigate": { - "Navigate": "導覽" - }, - "Navigation": { - "Navigation": "導航" - }, - "Network": { - "Network": "網路" - }, - "Network Graph": { - "Network Graph": "網路圖表" - }, - "Network Info": { - "Network Info": "網路資訊" - }, - "Network Information": { - "Network Information": "網路資訊" - }, - "Network Name (SSID)": { - "Network Name (SSID)": "網路名稱 (SSID)" - }, - "Network Speed Monitor": { - "Network Speed Monitor": "網速監視" - }, - "Network Status": { - "Network Status": "網路狀態" - }, - "Network download and upload speed display": { - "Network download and upload speed display": "顯示網路下載跟上傳速度" - }, - "Neutral": { - "Neutral": "中性" - }, - "Never": { - "Never": "從不" - }, - "Never used": { - "Never used": "從未使用" - }, - "New": { - "New": "新" - }, - "New Key": { - "New Key": "新按鍵" - }, - "New Keybind": { - "New Keybind": "新按鍵綁定" - }, - "New Notification": { - "New Notification": "新通知" - }, - "New Session": { - "New Session": "新會話" - }, - "New Window Rule": { - "New Window Rule": "新視窗規則" - }, - "New York, NY": { - "New York, NY": "紐約" - }, - "New group name...": { - "New group name...": "新群組名稱..." - }, - "Next": { - "Next": "下一步" - }, - "Next Transition": { - "Next Transition": "下一個轉場" - }, - "Night": { - "Night": "夜晚" - }, - "Night Mode": { - "Night Mode": "夜晚模式" - }, - "Night Temperature": { - "Night Temperature": "夜間色溫" - }, - "Night mode & gamma": { - "Night mode & gamma": "夜間模式與伽瑪" - }, - "Niri Integration": { - "Niri Integration": "Niri 整合" - }, - "Niri Layout Overrides": { - "Niri Layout Overrides": "Niri 版面配置覆寫" - }, - "Niri compositor actions (focus, move, etc.)": { - "Niri compositor actions (focus, move, etc.)": "Niri 合成器動作 (焦點、移動等)" - }, - "No": { - "No": "否" - }, - "No Active Players": { - "No Active Players": "無播放器" - }, - "No Anim": { - "No Anim": "無動畫" - }, - "No Background": { - "No Background": "部件無背景" - }, - "No Battery": { - "No Battery": "無電池" - }, - "No Bluetooth adapter found": { - "No Bluetooth adapter found": "未找到藍芽適配器" - }, - "No Blur": { - "No Blur": "無模糊" - }, - "No Border": { - "No Border": "無邊框" - }, - "No DMS shortcuts configured": { - "No DMS shortcuts configured": "未設定 DMS 捷徑" - }, - "No Dim": { - "No Dim": "不變暗" - }, - "No Focus": { - "No Focus": "無聚焦" - }, - "No GPU detected": { - "No GPU detected": "未偵測到 GPU" - }, - "No GPUs detected": { - "No GPUs detected": "未偵測到 GPU" - }, - "No History": { - "No History": "無歷史記錄" - }, - "No Media": { - "No Media": "無媒體" - }, - "No Round": { - "No Round": "無圓角" - }, - "No Rounding": { - "No Rounding": "無圓角" - }, - "No Shadow": { - "No Shadow": "無陰影" - }, - "No VPN profiles": { - "No VPN profiles": "沒有 VPN 設定檔" - }, - "No Weather": { - "No Weather": "無天氣" - }, - "No Weather Data": { - "No Weather Data": "無天氣資料" - }, - "No Weather Data Available": { - "No Weather Data Available": "沒有氣象數據" - }, - "No action": { - "No action": "無動作" - }, - "No active %1 sessions": { - "No active %1 sessions": "無活躍的 %1 會話" - }, - "No adapter": { - "No adapter": "無轉接器" - }, - "No adapters": { - "No adapters": "沒有介面卡" - }, - "No app customizations.": { - "No app customizations.": "沒有應用程式自訂設定。" - }, - "No apps found": { - "No apps found": "未找到應用程式" - }, - "No apps have been launched yet.": { - "No apps have been launched yet.": "尚未啟動任何應用程式。" - }, - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": { - "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.": "未靜音任何應用程式。右鍵點擊通知並選擇「靜音彈出視窗」以在此處添加一個。" - }, - "No battery": { - "No battery": "無電池" - }, - "No brightness devices available": { - "No brightness devices available": "沒有可用的亮度裝置" - }, - "No changes": { - "No changes": "無更改" - }, - "No checks passed": { - "No checks passed": "無檢查通過" - }, - "No custom theme file": { - "No custom theme file": "無自訂主題檔案" - }, - "No devices": { - "No devices": "無裝置" - }, - "No devices connected": { - "No devices connected": "無裝置已連接" - }, - "No devices found": { - "No devices found": "找不到裝置" - }, - "No disk data": { - "No disk data": "無硬碟資料" - }, - "No disk data available": { - "No disk data available": "無可用硬碟資料" - }, - "No drivers found": { - "No drivers found": "找不到驅動程式" - }, - "No errors": { - "No errors": "無錯誤" - }, - "No features enabled": { - "No features enabled": "未啟用任何功能" - }, - "No files found": { - "No files found": "沒有找到" - }, - "No fingerprint reader detected.": { - "No fingerprint reader detected.": "未偵測到指紋讀取器。" - }, - "No folders found": { - "No folders found": "未找到資料夾" - }, - "No hidden apps.": { - "No hidden apps.": "沒有隱藏的應用程式。" - }, - "No info items": { - "No info items": "無資訊項目" - }, - "No information available": { - "No information available": "無可用資訊" - }, - "No input device": { - "No input device": "無輸入裝置" - }, - "No input devices found": { - "No input devices found": "找不到輸入裝置" - }, - "No items added yet": { - "No items added yet": "未新增任何項目" - }, - "No keybinds found": { - "No keybinds found": "未找到按鍵綁定" - }, - "No launcher plugins installed.": { - "No launcher plugins installed.": "未安裝啟動器外掛程式。" - }, - "No match criteria": { - "No match criteria": "未設定符合條件" - }, - "No matches": { - "No matches": "不匹配" - }, - "No matching processes": { - "No matching processes": "無符合的處理程序" - }, - "No monitors": { - "No monitors": "無監視器" - }, - "No mount points found": { - "No mount points found": "找不到掛載點" - }, - "No output device": { - "No output device": "無輸出裝置" - }, - "No output devices found": { - "No output devices found": "找不到輸出裝置" - }, - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": { - "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.": "未找到套件管理器。請在基於 Arch 的系統上安裝 'paru' 或 'yay' 來檢查更新。" - }, - "No plugin results": { - "No plugin results": "沒有外掛程式結果" - }, - "No plugins found": { - "No plugins found": "找不到插件" - }, - "No plugins found.": { - "No plugins found.": "找不到插件。" - }, - "No printer found": { - "No printer found": "未找到印表機" - }, - "No printers configured": { - "No printers configured": "未設定印表機" - }, - "No printers found": { - "No printers found": "找不到印表機" - }, - "No profiles": { - "No profiles": "無任何設定檔" - }, - "No recent clipboard entries found": { - "No recent clipboard entries found": "找不到近期剪貼簿項目" - }, - "No results found": { - "No results found": "未找到結果" - }, - "No saved clipboard entries": { - "No saved clipboard entries": "沒有儲存的剪貼簿項目" - }, - "No sessions found": { - "No sessions found": "未找到會話" - }, - "No status output.": { - "No status output.": "無狀態輸出。" - }, - "No themes found": { - "No themes found": "找不到任何主題" - }, - "No themes installed. Browse themes to install from the registry.": { - "No themes installed. Browse themes to install from the registry.": "未安裝任何主題。請瀏覽登錄檔以安裝主題。" - }, - "No trigger": { - "No trigger": "無觸發條件" - }, - "No video found in folder": { - "No video found in folder": "資料夾中沒有找到影片" - }, - "No wallpaper selected": { - "No wallpaper selected": "未選擇任何桌布" - }, - "No wallpapers": { - "No wallpapers": "無桌布" - }, - "No wallpapers found\n\nClick the folder icon below to browse": { - "No wallpapers found\n\nClick the folder icon below to browse": "未找到桌布\n\n點擊下方的資料夾圖示瀏覽" - }, - "No warnings": { - "No warnings": "無警告" - }, - "No widgets added. Click \"Add Widget\" to get started.": { - "No widgets added. Click \"Add Widget\" to get started.": "未添加小工具。點擊「添加小工具」以開始。" - }, - "No widgets available": { - "No widgets available": "沒有可用的小工具" - }, - "No widgets match your search": { - "No widgets match your search": "沒有符合您搜尋條件的小工具" - }, - "No window rules configured": { - "No window rules configured": "未設定任何視窗規則" - }, - "None": { - "None": "無" - }, - "Normal": { - "Normal": "一般" - }, - "Normal Font": { - "Normal Font": "一般字體" - }, - "Normal Priority": { - "Normal Priority": "普通優先級" - }, - "Not available": { - "Not available": "無法使用" - }, - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": { - "Not available — install fprintd and pam_fprintd, or configure greetd PAM.": "無法使用 — 請安裝 fprintd 和 pam_fprintd,或設定 greetd PAM。" - }, - "Not available — install fprintd and pam_fprintd.": { - "Not available — install fprintd and pam_fprintd.": "無法使用 — 請安裝 fprintd 和 pam_fprintd。" - }, - "Not available — install or configure pam_u2f, or configure greetd PAM.": { - "Not available — install or configure pam_u2f, or configure greetd PAM.": "無法使用 — 請安裝或設定 pam_u2f,或設定 greetd PAM。" - }, - "Not available — install or configure pam_u2f.": { - "Not available — install or configure pam_u2f.": "無法使用 — 請安裝或設定 pam_u2f。" - }, - "Not connected": { - "Not connected": "未連接" - }, - "Not detected": { - "Not detected": "未偵測到" - }, - "Not paired": { - "Not paired": "未配對" - }, - "Not set": { - "Not set": "未設定" - }, - "Note: this only changes the percentage, it does not actually limit charging.": { - "Note: this only changes the percentage, it does not actually limit charging.": "注意:這只會變更百分比顯示,並不會實際限制充電。" - }, - "Notepad": { - "Notepad": "筆記本" - }, - "Notepad Font Settings": { - "Notepad Font Settings": "筆記本字體設定" - }, - "Notepad Slideout": { - "Notepad Slideout": "記事本滑出" - }, - "Nothing": { - "Nothing": "無內容" - }, - "Nothing to see here": { - "Nothing to see here": "這裡啥都沒有" - }, - "Notification Center": { - "Notification Center": "通知中心" - }, - "Notification Display": { - "Notification Display": "通知顯示" - }, - "Notification Overlay": { - "Notification Overlay": "通知外觀" - }, - "Notification Popups": { - "Notification Popups": "通知彈窗" - }, - "Notification Rules": { - "Notification Rules": "通知規則" - }, - "Notification Settings": { - "Notification Settings": "通知設定" - }, - "Notification Timeouts": { - "Notification Timeouts": "通知持續時間" - }, - "Notification toast popups": { - "Notification toast popups": "通知彈出窗口" - }, - "Notifications": { - "Notifications": "通知" - }, - "Numbers": { - "Numbers": "數字" - }, - "Numeric (D/M)": { - "Numeric (D/M)": "數字 (日/月)" - }, - "Numeric (M/D)": { - "Numeric (M/D)": "數字 (月/日)" - }, - "OK": { - "OK": "確定" - }, - "OS Logo": { - "OS Logo": "發行版 Logo" - }, - "OSD Position": { - "OSD Position": "OSD 位置" - }, - "Occupied Color": { - "Occupied Color": "佔用顏色" - }, - "Off": { - "Off": "關閉" - }, - "Office": { - "Office": "辦公" - }, - "Offline": { - "Offline": "離線" - }, - "Offline Report": { - "Offline Report": "離線報告" - }, - "Older": { - "Older": "舊有" - }, - "On": { - "On": "開啟" - }, - "On-Demand": { - "On-Demand": "按需" - }, - "On-Screen Displays": { - "On-Screen Displays": "螢幕顯示" - }, - "On-screen Displays": { - "On-screen Displays": "螢幕顯示" - }, - "Only adjust gamma based on time or location rules.": { - "Only adjust gamma based on time or location rules.": "僅根據時間或位置規則調整 gamma。" - }, - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": { - "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.": "僅影響 DMS 管理的 PAM。如果 greetd 已包含 pam_fprintd,指紋驗證會保持啟用。" - }, - "Only show windows from the current monitor on each dock": { - "Only show windows from the current monitor on each dock": "在每個 Dock 上僅顯示目前顯示器上的視窗" - }, - "Only visible if hibernate is supported by your system": { - "Only visible if hibernate is supported by your system": "僅當您的系統支援休眠時可見" - }, - "Opacity": { - "Opacity": "不透明度" - }, - "Opaque": { - "Opaque": "不透明" - }, - "Open": { - "Open": "打開" - }, - "Open App": { - "Open App": "開啟應用程式" - }, - "Open KDE Connect on your phone": { - "Open KDE Connect on your phone": "在您的手機上開啟 KDE Connect" - }, - "Open Notepad File": { - "Open Notepad File": "打開筆記文件" - }, - "Open a new note": { - "Open a new note": "開啟新筆記" - }, - "Open folder": { - "Open folder": "開啟資料夾" - }, - "Open in Browser": { - "Open in Browser": "在瀏覽器中開啟" - }, - "Open in terminal": { - "Open in terminal": "在終端中打開" - }, - "Open search bar to find text": { - "Open search bar to find text": "打開搜尋欄尋找文本" - }, - "Open with...": { - "Open with...": "開啟方式..." - }, - "Opening SMS": { - "Opening SMS": "正在開啟簡訊" - }, - "Opening SMS app": { - "Opening SMS app": "正在開啟簡訊應用程式" - }, - "Opening file browser": { - "Opening file browser": "正在開啟檔案瀏覽器" - }, - "Opening files": { - "Opening files": "正在開啟檔案" - }, - "Opening terminal: ": { - "Opening terminal: ": "正在開啟終端機:" - }, - "Optional description": { - "Optional description": "選填描述" - }, - "Optional location": { - "Optional location": "選填位置" - }, - "Options": { - "Options": "選項" - }, - "Organize widgets into collapsible groups": { - "Organize widgets into collapsible groups": "將小工具整理成可摺疊群組" - }, - "Original: %1": { - "Original: %1": "原始:%1" - }, - "Other": { - "Other": "其他" - }, - "Outline": { - "Outline": "外框" - }, - "Output": { - "Output": "輸出" - }, - "Output Area Almost Full": { - "Output Area Almost Full": "輸出區域即將滿載" - }, - "Output Area Full": { - "Output Area Full": "輸出區域已滿" - }, - "Output Device": { - "Output Device": "輸出裝置" - }, - "Output Devices": { - "Output Devices": "輸出裝置" - }, - "Output Tray Missing": { - "Output Tray Missing": "輸出托盤遺失" - }, - "Outputs Include Missing": { - "Outputs Include Missing": "輸出包含遺失的項目" - }, - "Overcast": { - "Overcast": "陰" - }, - "Overflow": { - "Overflow": "溢出" - }, - "Overridden by config": { - "Overridden by config": "被組態覆蓋" - }, - "Override": { - "Override": "覆蓋" - }, - "Override Border Size": { - "Override Border Size": "覆寫邊框大小" - }, - "Override Corner Radius": { - "Override Corner Radius": "覆寫圓角半徑" - }, - "Override Gaps": { - "Override Gaps": "覆寫間距" - }, - "Override global layout settings for this output": { - "Override global layout settings for this output": "覆寫此輸出的全域版面配置設定" - }, - "Override terminal with a custom command or script": { - "Override terminal with a custom command or script": "使用自訂指令或腳本覆蓋終端機" - }, - "Override the global shadow with per-bar settings": { - "Override the global shadow with per-bar settings": "使用每個 bar 的設定覆蓋全域陰影" - }, - "Overrides": { - "Overrides": "覆蓋" - }, - "Overview": { - "Overview": "概覽" - }, - "Overview of your network connections": { - "Overview of your network connections": "網路連線概覽" - }, - "Overwrite": { - "Overwrite": "覆寫" - }, - "PAM already provides fingerprint auth. Enable this to show it at login.": { - "PAM already provides fingerprint auth. Enable this to show it at login.": "PAM 已提供指紋驗證。啟用此選項以在登入時顯示。" - }, - "PAM already provides security-key auth. Enable this to show it at login.": { - "PAM already provides security-key auth. Enable this to show it at login.": "PAM 已提供安全金鑰驗證。啟用此選項以在登入時顯示。" - }, - "PAM provides fingerprint auth, but availability could not be confirmed.": { - "PAM provides fingerprint auth, but availability could not be confirmed.": "PAM 提供指紋驗證,但無法確認可用性。" - }, - "PAM provides fingerprint auth, but no prints are enrolled yet.": { - "PAM provides fingerprint auth, but no prints are enrolled yet.": "PAM 提供指紋驗證,但尚未註冊任何指紋。" - }, - "PAM provides fingerprint auth, but no reader was detected.": { - "PAM provides fingerprint auth, but no reader was detected.": "PAM 提供指紋驗證,但未檢測到讀取器。" - }, - "PIN": { - "PIN": "PIN" - }, - "Pad": { - "Pad": "填補" - }, - "Pad Hours": { - "Pad Hours": "填充小時" - }, - "Pad hours (02:00 vs 2:00)": { - "Pad hours (02:00 vs 2:00)": "小時補零 (02:00 vs 2:00)" - }, - "Padding": { - "Padding": "內距" - }, - "Pair": { - "Pair": "配對" - }, - "Pair Bluetooth Device": { - "Pair Bluetooth Device": "配對藍牙設備" - }, - "Paired": { - "Paired": "已配對" - }, - "Pairing": { - "Pairing": "正在配對" - }, - "Pairing failed": { - "Pairing failed": "配對失敗" - }, - "Pairing request from": { - "Pairing request from": "來自 的配對要求" - }, - "Pairing request sent": { - "Pairing request sent": "已送出配對要求" - }, - "Pairing requested": { - "Pairing requested": "已要求配對" - }, - "Pairing...": { - "Pairing...": "正在配對..." - }, - "Partly Cloudy": { - "Partly Cloudy": "多雲" - }, - "Passkey:": { - "Passkey:": "密碼:" - }, - "Password": { - "Password": "密碼" - }, - "Password...": { - "Password...": "密碼..." - }, - "Paste": { - "Paste": "貼上" - }, - "Path to a video file or folder containing videos": { - "Path to a video file or folder containing videos": "影片檔案或包含影片的資料夾路徑" - }, - "Pattern": { - "Pattern": "樣式" - }, - "Pause": { - "Pause": "暫停" - }, - "Paused": { - "Paused": "暫停" - }, - "Pending": { - "Pending": "待處理" - }, - "Pending Charge": { - "Pending Charge": "等待充電" - }, - "Pending Discharge": { - "Pending Discharge": "待解除" - }, - "Per-Mode Wallpapers": { - "Per-Mode Wallpapers": "以主題區分桌布" - }, - "Per-Monitor Wallpapers": { - "Per-Monitor Wallpapers": "以螢幕區分桌布" - }, - "Per-screen config": { - "Per-screen config": "依螢幕設定" - }, - "Percentage": { - "Percentage": "百分比" - }, - "Performance": { - "Performance": "效能" - }, - "Permission denied to set profile image.": { - "Permission denied to set profile image.": "權限不足,無法設定個人資料圖片。" - }, - "Personalization": { - "Personalization": "個人化" - }, - "Phone Connect Not Available": { - "Phone Connect Not Available": "手機連線無法使用" - }, - "Phone Connect unavailable": { - "Phone Connect unavailable": "手機連線無法使用" - }, - "Phone number": { - "Phone number": "電話號碼" - }, - "Pick a different random video each time from the same folder": { - "Pick a different random video each time from the same folder": "每次從同一個資料夾中選擇一個不同的隨機影片" - }, - "Pictures": { - "Pictures": "圖片" - }, - "Pin": { - "Pin": "釘選" - }, - "Pin to Dock": { - "Pin to Dock": "釘選到 Dock" - }, - "Ping": { - "Ping": "Ping" - }, - "Ping sent": { - "Ping sent": "Ping 已送出" - }, - "Ping sent to": { - "Ping sent to": "Ping 已送至" - }, - "Pinned": { - "Pinned": "已釘選" - }, - "Pinned and running apps with drag-and-drop": { - "Pinned and running apps with drag-and-drop": "已釘選及執行中的應用程式,可拖曳。" - }, - "Pixelate": { - "Pixelate": "馬賽克" - }, - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": { - "Place plugin directories here. Each plugin should have a plugin.json manifest file.": "將插件資料夾放在這裡。每個插件都應該有一個 plugin.json 清單檔案。" - }, - "Place plugins in %1": { - "Place plugins in %1": "將外掛程式置於 %1 中" - }, - "Play a video when the screen locks.": { - "Play a video when the screen locks.": "螢幕鎖定時播放影片。" - }, - "Play sound after logging in": { - "Play sound after logging in": "" - }, - "Play sound when new notification arrives": { - "Play sound when new notification arrives": "收到新通知時播放音效" - }, - "Play sound when power cable is connected": { - "Play sound when power cable is connected": "連接電源線時播放音效" - }, - "Play sound when volume is adjusted": { - "Play sound when volume is adjusted": "調整音量時播放音效" - }, - "Play sounds for system events": { - "Play sounds for system events": "播放系統事件的音效" - }, - "Playback": { - "Playback": "播放" - }, - "Playback error: ": { - "Playback error: ": "播放錯誤:" - }, - "Please wait...": { - "Please wait...": "請稍候..." - }, - "Please write a name for your new %1 session": { - "Please write a name for your new %1 session": "請為您的新 %1 會話取一個名稱" - }, - "Plugged In": { - "Plugged In": "已插入" - }, - "Plugged in": { - "Plugged in": "已插入" - }, - "Plugin": { - "Plugin": "外掛程式" - }, - "Plugin Directory": { - "Plugin Directory": "插件資料夾" - }, - "Plugin Management": { - "Plugin Management": "插件管理" - }, - "Plugin Visibility": { - "Plugin Visibility": "外掛程式可見度" - }, - "Plugin is disabled - enable in Plugins settings to use": { - "Plugin is disabled - enable in Plugins settings to use": "插件已停用 - 在插件設定中啟用即可使用" - }, - "Plugins": { - "Plugins": "插件" - }, - "Pointer": { - "Pointer": "指標" - }, - "Popout Shadows": { - "Popout Shadows": "彈出陰影" - }, - "Popouts": { - "Popouts": "彈出視窗" - }, - "Popouts and Modals follow global Animation Speed (disable to customize independently)": { - "Popouts and Modals follow global Animation Speed (disable to customize independently)": "彈出視窗和模態視窗遵循全局動畫速度(禁用可獨立自訂)" - }, - "Popup Only": { - "Popup Only": "僅彈出視窗" - }, - "Popup Position": { - "Popup Position": "彈窗位置" - }, - "Popup Shadow": { - "Popup Shadow": "彈出視窗陰影" - }, - "Popup Transparency": { - "Popup Transparency": "彈窗透明度" - }, - "Popup behavior, position": { - "Popup behavior, position": "彈出視窗行為與位置" - }, - "Port": { - "Port": "連接埠" - }, - "Portal": { - "Portal": "入口" - }, - "Position": { - "Position": "位置" - }, - "Position, pinned apps": { - "Position, pinned apps": "位置、釘選的應用程式" - }, - "Possible Override Conflicts": { - "Possible Override Conflicts": "可能存在的覆蓋衝突" - }, - "Power": { - "Power": "電源" - }, - "Power & Security": { - "Power & Security": "電源與安全" - }, - "Power & Sleep": { - "Power & Sleep": "電源和睡眠" - }, - "Power Action Confirmation": { - "Power Action Confirmation": "電源操作確認" - }, - "Power Menu Customization": { - "Power Menu Customization": "電源選單自訂" - }, - "Power Off": { - "Power Off": "關機" - }, - "Power Options": { - "Power Options": "電源選項" - }, - "Power Profile": { - "Power Profile": "電源設定檔" - }, - "Power Profile Degradation": { - "Power Profile Degradation": "電源配置降級" - }, - "Power Saver": { - "Power Saver": "省電模式" - }, - "Power off monitors on lock": { - "Power off monitors on lock": "鎖定時關閉螢幕" - }, - "Power profile management available": { - "Power profile management available": "電源設定檔管理功能可用" - }, - "Power source": { - "Power source": "電源" - }, - "Pre-fill the last successful username on the greeter": { - "Pre-fill the last successful username on the greeter": "在迎賓器上預填上次成功的用戶名" - }, - "Pre-select the last used session on the greeter": { - "Pre-select the last used session on the greeter": "在歡迎畫面上預選上次使用的會話" - }, - "Precip": { - "Precip": "降水" - }, - "Precipitation": { - "Precipitation": "降水" - }, - "Precipitation Chance": { - "Precipitation Chance": "降水機率" - }, - "Preference": { - "Preference": "偏好設定" - }, - "Preset Widths (%)": { - "Preset Widths (%)": "預設寬度 (%)" - }, - "Press 'n' or click 'New Session' to create one": { - "Press 'n' or click 'New Session' to create one": "按下 'n' 或點擊 '新會話' 即可創建一個" - }, - "Press Enter and the audio system will restart to apply the change": { - "Press Enter and the audio system will restart to apply the change": "按下 Enter 鍵,音訊系統將重新啟動以應用變更" - }, - "Press Enter to paste, Shift+Enter to copy": { - "Press Enter to paste, Shift+Enter to copy": "按 Enter 貼上,按 Shift+Enter 複製" - }, - "Press key...": { - "Press key...": "按下按鍵..." - }, - "Pressure": { - "Pressure": "氣壓" - }, - "Prevent screen timeout": { - "Prevent screen timeout": "防止螢幕超時" - }, - "Preview": { - "Preview": "預覽" - }, - "Primary": { - "Primary": "主要" - }, - "Primary Container": { - "Primary Container": "主要容器" - }, - "Print Server Management": { - "Print Server Management": "列印伺服器管理" - }, - "Print Server not available": { - "Print Server not available": "列印伺服器無法使用" - }, - "Printer": { - "Printer": "印表機" - }, - "Printer Classes": { - "Printer Classes": "印表機類別" - }, - "Printer created successfully": { - "Printer created successfully": "印表機建立成功" - }, - "Printer deleted": { - "Printer deleted": "印表機已刪除" - }, - "Printer name (no spaces)": { - "Printer name (no spaces)": "印表機名稱 (無空格)" - }, - "Printer reachable": { - "Printer reachable": "印表機可達" - }, - "Printers": { - "Printers": "印表機" - }, - "Printers: ": { - "Printers: ": "印表機:" - }, - "Prioritize performance": { - "Prioritize performance": "優先效能" - }, - "Priority": { - "Priority": "優先級" - }, - "Privacy Indicator": { - "Privacy Indicator": "隱私指示器" - }, - "Privacy Mode": { - "Privacy Mode": "隱私模式" - }, - "Private Key Password": { - "Private Key Password": "私鑰密碼" - }, - "Process Count": { - "Process Count": "程序數量" - }, - "Processes": { - "Processes": "處理程序" - }, - "Processes:": { - "Processes:": "處理程序:" - }, - "Processing": { - "Processing": "正在處理" - }, - "Profile Image Error": { - "Profile Image Error": "個人圖片錯誤" - }, - "Profile activated: %1": { - "Profile activated: %1": "設定檔已啟用:%1" - }, - "Profile deleted": { - "Profile deleted": "設定檔已刪除" - }, - "Profile error": { - "Profile error": "設定檔錯誤" - }, - "Profile image is too large. Please use a smaller image.": { - "Profile image is too large. Please use a smaller image.": "個人資料圖片太大。請使用較小的圖片。" - }, - "Profile name": { - "Profile name": "設定檔名稱" - }, - "Profile not found": { - "Profile not found": "找不到設定檔" - }, - "Profile saved: %1": { - "Profile saved: %1": "設定檔已儲存:%1" - }, - "Protocol": { - "Protocol": "協定" - }, - "QtMultimedia is not available": { - "QtMultimedia is not available": "QtMultimedia 不可用" - }, - "QtMultimedia is not available - video screensaver requires qt multimedia services": { - "QtMultimedia is not available - video screensaver requires qt multimedia services": "QtMultimedia 不可用 - 影片螢幕保護程式需要 Qt 多媒體服務" - }, - "Quick Access": { - "Quick Access": "快速存取" - }, - "Quick access to application launcher": { - "Quick access to application launcher": "快速存取應用程式啟動器" - }, - "Quick access to color picker": { - "Quick access to color picker": "快速存取顏色選擇器" - }, - "Quick access to notepad": { - "Quick access to notepad": "快速存取記事本" - }, - "Quick note-taking slideout panel": { - "Quick note-taking slideout panel": "快速筆記滑出面板" - }, - "Quick system toggles": { - "Quick system toggles": "快速系統切換" - }, - "RGB": { - "RGB": "RGB" - }, - "Radius": { - "Radius": "半徑" - }, - "Rain": { - "Rain": "雨" - }, - "Rain Chance": { - "Rain Chance": "降雨機率" - }, - "Rainbow": { - "Rainbow": "彩虹" - }, - "Random": { - "Random": "隨機" - }, - "Rate": { - "Rate": "速率" - }, - "Read:": { - "Read:": "讀取:" - }, - "Reason": { - "Reason": "原因" - }, - "Reboot": { - "Reboot": "重新啟動" - }, - "Recent Colors": { - "Recent Colors": "最近的顏色" - }, - "Recently Used Apps": { - "Recently Used Apps": "最近使用的應用程式" - }, - "Recommended available": { - "Recommended available": "建議可用" - }, - "Refresh": { - "Refresh": "重新整理" - }, - "Refresh Weather": { - "Refresh Weather": "刷新天氣" - }, - "Regex": { - "Regex": "正規表達式" - }, - "Reject": { - "Reject": "拒絕" - }, - "Reject Jobs": { - "Reject Jobs": "拒絕工作" - }, - "Release": { - "Release": "放開" - }, - "Reload Plugin": { - "Reload Plugin": "重新載入插件" - }, - "Remaining": { - "Remaining": "剩餘" - }, - "Remaining / Total": { - "Remaining / Total": "剩餘 / 總計" - }, - "Remember Last Query": { - "Remember Last Query": "" - }, - "Remember last session": { - "Remember last session": "記住上次會話" - }, - "Remember last user": { - "Remember last user": "記住上次用戶" - }, - "Remove": { - "Remove": "刪除" - }, - "Remove Widget Padding": { - "Remove Widget Padding": "移除小部件內邊距" - }, - "Remove gaps and border when windows are maximized": { - "Remove gaps and border when windows are maximized": "視窗最大化時移除間距與邊框" - }, - "Rename": { - "Rename": "重新命名" - }, - "Rename Session": { - "Rename Session": "重新命名會話" - }, - "Rename Workspace": { - "Rename Workspace": "重新命名工作區" - }, - "Repeat": { - "Repeat": "重複" - }, - "Replacement": { - "Replacement": "替換" - }, - "Report": { - "Report": "報告" - }, - "Request Pairing": { - "Request Pairing": "要求配對" - }, - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { - "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "需要按住按鈕/鍵以確認關機、重新啟動、睡眠、休眠和登出" - }, - "Required plugin: ": { - "Required plugin: ": "所需插件:" - }, - "Requires %1": { - "Requires %1": "需要 %1" - }, - "Requires 'dgop' tool": { - "Requires 'dgop' tool": "需要「dgop」工具" - }, - "Requires DMS %1": { - "Requires DMS %1": "需要 DMS %1" - }, - "Requires DWL compositor": { - "Requires DWL compositor": "需要 DWL 混成器" - }, - "Requires a newer version of Quickshell": { - "Requires a newer version of Quickshell": "" - }, - "Requires night mode support": { - "Requires night mode support": "需要夜間模式支援" - }, - "Reset": { - "Reset": "重設" - }, - "Reset Position": { - "Reset Position": "重設位置" - }, - "Reset Size": { - "Reset Size": "重設大小" - }, - "Reset to default name": { - "Reset to default name": "重設為預設名稱" - }, - "Resize Widget": { - "Resize Widget": "調整小工具大小" - }, - "Resolution & Refresh": { - "Resolution & Refresh": "解析度與更新率" - }, - "Resolution, position, scale": { - "Resolution, position, scale": "解析度、位置、比例" - }, - "Restart DMS": { - "Restart DMS": "重新啟動 DMS" - }, - "Restart the DankMaterialShell": { - "Restart the DankMaterialShell": "重新啟動 DankMaterialShell" - }, - "Restarting audio system...": { - "Restarting audio system...": "正在重新啟動音訊系統..." - }, - "Restore Special Workspace Windows": { - "Restore Special Workspace Windows": "恢復特殊工作區視窗" - }, - "Resume": { - "Resume": "恢復" - }, - "Reverse Scrolling Direction": { - "Reverse Scrolling Direction": "反轉捲動方向" - }, - "Reverse workspace switch direction when scrolling over the bar": { - "Reverse workspace switch direction when scrolling over the bar": "在工具列上捲動時反轉工作區切換方向" - }, - "Revert": { - "Revert": "還原" - }, - "Right": { - "Right": "右方" - }, - "Right Center": { - "Right Center": "右中" - }, - "Right Section": { - "Right Section": "右方區塊" - }, - "Right Tiling": { - "Right Tiling": "右側平鋪" - }, - "Right-click and drag anywhere on the widget": { - "Right-click and drag anywhere on the widget": "在小工具上任一處按右鍵並拖曳" - }, - "Right-click and drag the bottom-right corner": { - "Right-click and drag the bottom-right corner": "按右鍵並拖曳右下角" - }, - "Right-click bar widget to cycle": { - "Right-click bar widget to cycle": "右鍵點擊長條小工具以循環" - }, - "Ring": { - "Ring": "響鈴" - }, - "Ringing": { - "Ringing": "正在響鈴" - }, - "Ripple Effects": { - "Ripple Effects": "漣漪效果" - }, - "Root Filesystem": { - "Root Filesystem": "根檔案系統" - }, - "Rounded corners for windows": { - "Rounded corners for windows": "視窗圓角" - }, - "Rounded corners for windows (border_radius)": { - "Rounded corners for windows (border_radius)": "視窗圓角 (border_radius)" - }, - "Rounded corners for windows (decoration.rounding)": { - "Rounded corners for windows (decoration.rounding)": "視窗圓角 (decoration.rounding)" - }, - "Rule": { - "Rule": "規則" - }, - "Rule Name": { - "Rule Name": "規則名稱" - }, - "Rules (%1)": { - "Rules (%1)": "規則 (%1)" - }, - "Run Again": { - "Run Again": "重新執行" - }, - "Run DMS Templates": { - "Run DMS Templates": "執行 DMS 範本" - }, - "Run User Templates": { - "Run User Templates": "執行使用者模板" - }, - "Run a program (e.g., firefox, kitty)": { - "Run a program (e.g., firefox, kitty)": "執行程式 (例如,firefox, kitty)" - }, - "Run a shell command (e.g., notify-send)": { - "Run a shell command (e.g., notify-send)": "執行 shell 指令 (例如,notify-send)" - }, - "Running Apps": { - "Running Apps": "正在運行的應用程式" - }, - "Running Apps Settings": { - "Running Apps Settings": "正在運行的應用程式設定" - }, - "Running greeter sync…": { - "Running greeter sync…": "正在同步歡迎畫面…" - }, - "SDR Brightness": { - "SDR Brightness": "SDR 亮度" - }, - "SDR Saturation": { - "SDR Saturation": "SDR 飽和度" - }, - "SMS": { - "SMS": "簡訊" - }, - "Save": { - "Save": "儲存" - }, - "Save Notepad File": { - "Save Notepad File": "儲存記事本" - }, - "Save QR Code": { - "Save QR Code": "保存 QR 碼" - }, - "Save and switch between display configurations": { - "Save and switch between display configurations": "儲存並切換顯示設定" - }, - "Save critical priority notifications to history": { - "Save critical priority notifications to history": "將高優先順序通知儲存至歷史記錄" - }, - "Save dismissed notifications to history": { - "Save dismissed notifications to history": "將已忽略通知儲存至歷史記錄" - }, - "Save low priority notifications to history": { - "Save low priority notifications to history": "將低優先順序通知儲存至歷史記錄" - }, - "Save normal priority notifications to history": { - "Save normal priority notifications to history": "將一般優先順序通知儲存至歷史記錄" - }, - "Save password": { - "Save password": "儲存密碼" - }, - "Saved": { - "Saved": "已儲存" - }, - "Saved Configurations": { - "Saved Configurations": "已儲存的設定" - }, - "Saved Note": { - "Saved Note": "已儲存的筆記" - }, - "Saved item deleted": { - "Saved item deleted": "已刪除儲存項目" - }, - "Saving...": { - "Saving...": "儲存中..." - }, - "Scale": { - "Scale": "縮放" - }, - "Scale DankBar font sizes independently": { - "Scale DankBar font sizes independently": "獨立縮放 DankBar 字體大小" - }, - "Scale DankBar icon sizes independently": { - "Scale DankBar icon sizes independently": "獨立縮放 DankBar 圖標大小" - }, - "Scale all font sizes throughout the shell": { - "Scale all font sizes throughout the shell": "縮放整個 Shell 中的所有字體大小" - }, - "Scan": { - "Scan": "掃描" - }, - "Scanning": { - "Scanning": "正在掃描" - }, - "Scanning...": { - "Scanning...": "掃描中..." - }, - "Science": { - "Science": "科學" - }, - "Score": { - "Score": "分數" - }, - "Screen Sharing": { - "Screen Sharing": "螢幕分享" - }, - "Screen sharing": { - "Screen sharing": "螢幕分享" - }, - "Scroll": { - "Scroll": "捲動" - }, - "Scroll Factor": { - "Scroll Factor": "捲動係數" - }, - "Scroll GitHub": { - "Scroll GitHub": "捲動 GitHub" - }, - "Scroll Wheel": { - "Scroll Wheel": "滾輪" - }, - "Scroll song title": { - "Scroll song title": "滾動歌曲標題" - }, - "Scroll title if it doesn't fit in widget": { - "Scroll title if it doesn't fit in widget": "若標題不符合小工具空間,請捲動" - }, - "Scroll wheel behavior on media widget": { - "Scroll wheel behavior on media widget": "媒體小工具滾輪行為" - }, - "Scrolling": { - "Scrolling": "滾動" - }, - "Search App Actions": { - "Search App Actions": "搜尋應用程式動作" - }, - "Search Options": { - "Search Options": "搜尋選項" - }, - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": { - "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.": "按組合鍵、描述或動作名稱搜尋。\n\n預設動作將綁定鍵複製到剪貼簿。\n右鍵點擊或按右箭頭以釘選常用綁定鍵 — 搜尋時它們將出現在頂部。" - }, - "Search for a location...": { - "Search for a location...": "搜尋位置..." - }, - "Search keybinds...": { - "Search keybinds...": "搜尋按鍵綁定..." - }, - "Search keyboard shortcuts from your compositor and applications": { - "Search keyboard shortcuts from your compositor and applications": "搜尋合成器與應用程式的鍵盤快捷鍵" - }, - "Search plugins...": { - "Search plugins...": "搜尋插件..." - }, - "Search processes...": { - "Search processes...": "搜尋處理程序..." - }, - "Search sessions...": { - "Search sessions...": "搜尋會話..." - }, - "Search themes...": { - "Search themes...": "搜尋主題..." - }, - "Search widgets...": { - "Search widgets...": "搜尋部件..." - }, - "Search...": { - "Search...": "搜尋..." - }, - "Searching...": { - "Searching...": "搜尋中..." - }, - "Second Factor (AND)": { - "Second Factor (AND)": "第二因子 (AND)" - }, - "Secondary": { - "Secondary": "次要" - }, - "Secured": { - "Secured": "已保護" - }, - "Security": { - "Security": "安全性" - }, - "Security & privacy": { - "Security & privacy": "安全與隱私" - }, - "Security key mode": { - "Security key mode": "安全金鑰模式" - }, - "Security-key availability could not be confirmed.": { - "Security-key availability could not be confirmed.": "無法確認安全金鑰的可用性。" - }, - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": { - "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.": "已檢測到安全金鑰支援,但尚未找到已註冊的金鑰。您現在可以啟用此功能,稍後再註冊一個。" - }, - "Select": { - "Select": "選取" - }, - "Select Application": { - "Select Application": "選擇應用程式" - }, - "Select Bar": { - "Select Bar": "選取列" - }, - "Select Custom Theme": { - "Select Custom Theme": "選擇自訂主題" - }, - "Select Dock Launcher Logo": { - "Select Dock Launcher Logo": "選擇 Dock 啟動器標誌" - }, - "Select File to Send": { - "Select File to Send": "選取要傳送的檔案" - }, - "Select Launcher Logo": { - "Select Launcher Logo": "選擇啟動器 Logo" - }, - "Select Profile Image": { - "Select Profile Image": "選擇個人資料圖片" - }, - "Select Video or Folder": { - "Select Video or Folder": "選擇影片或資料夾" - }, - "Select Wallpaper": { - "Select Wallpaper": "選擇桌布" - }, - "Select Wallpaper Directory": { - "Select Wallpaper Directory": "選擇桌布目錄" - }, - "Select a color from the palette or use custom sliders": { - "Select a color from the palette or use custom sliders": "從調色板中選取一個顏色,或使用滑條調整" - }, - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": { - "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.": "選取一個小工具以新增至您的桌面。每個小工具都是獨立的實例,擁有自己的設定。" - }, - "Select a widget to add. You can add multiple instances of the same widget if needed.": { - "Select a widget to add. You can add multiple instances of the same widget if needed.": "選擇要新增的部件。如果需要,可以新增相同部件部件的多個實例。" - }, - "Select a window...": { - "Select a window...": "選擇一個視窗..." - }, - "Select an image file...": { - "Select an image file...": "選擇一張圖片..." - }, - "Select at least one provider": { - "Select at least one provider": "請至少選擇一個提供者" - }, - "Select device": { - "Select device": "選取裝置" - }, - "Select device...": { - "Select device...": "選擇裝置..." - }, - "Select driver...": { - "Select driver...": "選擇驅動程式..." - }, - "Select font weight for UI text": { - "Select font weight for UI text": "為使用者介面文字選擇字體粗細" - }, - "Select greeter background image": { - "Select greeter background image": "選擇歡迎畫面背景圖片" - }, - "Select monitor to configure wallpaper": { - "Select monitor to configure wallpaper": "選擇指定螢幕桌布" - }, - "Select monospace font for process list and technical displays": { - "Select monospace font for process list and technical displays": "寬字體用於處理程序列表和技術顯示" - }, - "Select network": { - "Select network": "選取網路" - }, - "Select system sound theme": { - "Select system sound theme": "選擇系統音效主題" - }, - "Select the font family for UI text": { - "Select the font family for UI text": "為使用者介面文字選擇字體家族" - }, - "Select the palette algorithm used for wallpaper-based colors": { - "Select the palette algorithm used for wallpaper-based colors": "請選擇調色板演算法,以桌布的顏色為基底。" - }, - "Select which keybind providers to include": { - "Select which keybind providers to include": "選擇要包含哪些快捷鍵提供者" - }, - "Select which transitions to include in randomization": { - "Select which transitions to include in randomization": "選擇要包含在隨機中的轉換效果" - }, - "Select...": { - "Select...": "選擇..." - }, - "Selected image file not found.": { - "Selected image file not found.": "未找到選定的圖片。" - }, - "Send": { - "Send": "傳送" - }, - "Send Clipboard": { - "Send Clipboard": "傳送剪貼簿" - }, - "Send File": { - "Send File": "傳送檔案" - }, - "Send SMS": { - "Send SMS": "傳送簡訊" - }, - "Sending": { - "Sending": "傳送中" - }, - "Separator": { - "Separator": "分隔符" - }, - "Server": { - "Server": "伺服器" - }, - "Session Filter": { - "Session Filter": "會話篩選器" - }, - "Set Custom Device Name": { - "Set Custom Device Name": "設定自訂裝置名稱" - }, - "Set custom name": { - "Set custom name": "設定自訂名稱" - }, - "Set custom names for your audio input devices": { - "Set custom names for your audio input devices": "為您的音訊輸入裝置設定自訂名稱" - }, - "Set custom names for your audio output devices": { - "Set custom names for your audio output devices": "為您的音訊輸出裝置設定自訂名稱" - }, - "Set different wallpapers for each connected monitor": { - "Set different wallpapers for each connected monitor": "為每個連接的螢幕設定不同的桌布" - }, - "Set different wallpapers for light and dark mode": { - "Set different wallpapers for light and dark mode": "為淺色/深色主題設定不同的桌布" - }, - "Set key and action to save": { - "Set key and action to save": "設定按鍵和動作以保存" - }, - "Set notification rules": { - "Set notification rules": "設定通知規則" - }, - "Settings": { - "Settings": "設定" - }, - "Settings are read-only. Changes will not persist.": { - "Settings are read-only. Changes will not persist.": "設定為唯讀。變更將不會保留。" - }, - "Setup": { - "Setup": "設定" - }, - "Shadow Color": { - "Shadow Color": "陰影顏色" - }, - "Shadow Intensity": { - "Shadow Intensity": "陰影強度" - }, - "Shadow Opacity": { - "Shadow Opacity": "陰影不透明度" - }, - "Shadow Override": { - "Shadow Override": "陰影覆蓋" - }, - "Shadow elevation on bars and panels": { - "Shadow elevation on bars and panels": "bar 和面板上的陰影抬升" - }, - "Shadow elevation on modals and dialogs": { - "Shadow elevation on modals and dialogs": "模態框和對話框上的陰影抬升" - }, - "Shadow elevation on popouts, OSDs, and dropdowns": { - "Shadow elevation on popouts, OSDs, and dropdowns": "彈出視窗、OSD 和下拉選單上的陰影抬升" - }, - "Shadows": { - "Shadows": "陰影" - }, - "Share": { - "Share": "分享" - }, - "Share Gamma Control Settings": { - "Share Gamma Control Settings": "分享 Gamma 控制設定" - }, - "Share Text": { - "Share Text": "分享文字" - }, - "Share URL": { - "Share URL": "分享網址" - }, - "Shared": { - "Shared": "已分享" - }, - "Shell": { - "Shell": "Shell" - }, - "Shift+Del: Clear All • Esc: Close": { - "Shift+Del: Clear All • Esc: Close": "Shift+Del: 清除所有 • Esc: 關閉" - }, - "Shift+Enter to paste": { - "Shift+Enter to paste": "Shift+Enter 貼上" - }, - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close": "Shift+Enter: 複製 • Shift+Del: 清除全部 • Esc: 關閉" - }, - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": { - "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close": "Shift+Enter:貼上 • Shift+Del:全部清除 • Esc:關閉" - }, - "Short": { - "Short": "短" - }, - "Shortcut (%1)": { - "Shortcut (%1)": "快捷鍵 (%1)" - }, - "Shortcuts": { - "Shortcuts": "快捷方式" - }, - "Shortcuts (%1)": { - "Shortcuts (%1)": "快速鍵 (%1)" - }, - "Show": { - "Show": "顯示" - }, - "Show 3rd Party": { - "Show 3rd Party": "顯示第三方" - }, - "Show All Tags": { - "Show All Tags": "顯示所有標籤" - }, - "Show Badge": { - "Show Badge": "顯示徽章" - }, - "Show CPU": { - "Show CPU": "顯示 CPU" - }, - "Show CPU Graph": { - "Show CPU Graph": "顯示 CPU 圖表" - }, - "Show CPU Temp": { - "Show CPU Temp": "顯示 CPU 溫度" - }, - "Show Date": { - "Show Date": "顯示日期" - }, - "Show Disk": { - "Show Disk": "顯示磁碟" - }, - "Show Dock": { - "Show Dock": "顯示 Dock" - }, - "Show Feels Like Temperature": { - "Show Feels Like Temperature": "顯示體感溫度" - }, - "Show Footer": { - "Show Footer": "顯示頁尾" - }, - "Show Forecast": { - "Show Forecast": "顯示預報" - }, - "Show GPU Temperature": { - "Show GPU Temperature": "顯示 GPU 溫度" - }, - "Show Header": { - "Show Header": "顯示標頭" - }, - "Show Hibernate": { - "Show Hibernate": "顯示休眠" - }, - "Show Hour Numbers": { - "Show Hour Numbers": "顯示小時數字" - }, - "Show Hourly Forecast": { - "Show Hourly Forecast": "顯示每小時預報" - }, - "Show Humidity": { - "Show Humidity": "顯示濕度" - }, - "Show Launcher Button": { - "Show Launcher Button": "顯示啟動器按鈕" - }, - "Show Line Numbers": { - "Show Line Numbers": "顯示行數" - }, - "Show Location": { - "Show Location": "顯示位置" - }, - "Show Lock": { - "Show Lock": "顯示鎖定" - }, - "Show Log Out": { - "Show Log Out": "顯示登出" - }, - "Show Material Design ripple animations on interactive elements": { - "Show Material Design ripple animations on interactive elements": "在互動元素上顯示 Material Design 漣漪動畫" - }, - "Show Media Player": { - "Show Media Player": "顯示媒體播放器" - }, - "Show Memory": { - "Show Memory": "顯示記憶體" - }, - "Show Memory Graph": { - "Show Memory Graph": "顯示記憶體圖表" - }, - "Show Memory in GB": { - "Show Memory in GB": "以 GB 顯示記憶體" - }, - "Show Network": { - "Show Network": "顯示網路" - }, - "Show Network Graph": { - "Show Network Graph": "顯示網路圖表" - }, - "Show Occupied Workspaces Only": { - "Show Occupied Workspaces Only": "只顯示已佔用的工作區" - }, - "Show Overflow Badge Count": { - "Show Overflow Badge Count": "顯示溢出徽章計數" - }, - "Show Password Field": { - "Show Password Field": "顯示密碼欄位" - }, - "Show Power Actions": { - "Show Power Actions": "顯示電源動作" - }, - "Show Power Off": { - "Show Power Off": "顯示關機" - }, - "Show Precipitation Probability": { - "Show Precipitation Probability": "顯示降雨機率" - }, - "Show Pressure": { - "Show Pressure": "顯示氣壓" - }, - "Show Profile Image": { - "Show Profile Image": "顯示個人資料圖片" - }, - "Show Reboot": { - "Show Reboot": "顯示重新啟動" - }, - "Show Restart DMS": { - "Show Restart DMS": "顯示重新啟動 DMS" - }, - "Show Saved Items": { - "Show Saved Items": "顯示已儲存的項目" - }, - "Show Seconds": { - "Show Seconds": "顯示秒數" - }, - "Show Sunrise/Sunset": { - "Show Sunrise/Sunset": "顯示日出/日落" - }, - "Show Suspend": { - "Show Suspend": "顯示睡眠" - }, - "Show Swap": { - "Show Swap": "顯示交換空間" - }, - "Show System Date": { - "Show System Date": "顯示系統日期" - }, - "Show System Icons": { - "Show System Icons": "顯示系統圖示" - }, - "Show System Time": { - "Show System Time": "顯示系統時間" - }, - "Show Top Processes": { - "Show Top Processes": "顯示最佔用程序" - }, - "Show Weather Condition": { - "Show Weather Condition": "顯示天氣狀況" - }, - "Show Week Number": { - "Show Week Number": "顯示週數" - }, - "Show Welcome": { - "Show Welcome": "顯示歡迎畫面" - }, - "Show Wind Speed": { - "Show Wind Speed": "顯示風速" - }, - "Show Workspace Apps": { - "Show Workspace Apps": "顯示工作區應用程式" - }, - "Show all 9 tags instead of only occupied tags (DWL only)": { - "Show all 9 tags instead of only occupied tags (DWL only)": "顯示所有 9 個標籤,而非僅顯示已佔用的標籤 (僅限 DWL)" - }, - "Show an outline ring around the focused workspace indicator": { - "Show an outline ring around the focused workspace indicator": "顯示聚焦工作區指示器外框" - }, - "Show cava audio visualizer in media widget": { - "Show cava audio visualizer in media widget": "在媒體小工具中顯示 cava 音訊視覺化工具" - }, - "Show darkened overlay behind modal dialogs": { - "Show darkened overlay behind modal dialogs": "在模態對話框後顯示暗化覆蓋層" - }, - "Show device": { - "Show device": "顯示裝置" - }, - "Show dock when floating windows don't overlap its area": { - "Show dock when floating windows don't overlap its area": "當浮動視窗未覆蓋其區域時顯示工作列" - }, - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": { - "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.": "在通知彈出視窗上顯示陰影。需要在主題和顏色中啟用 M3 抬升。" - }, - "Show in GB": { - "Show in GB": "以 GB 顯示" - }, - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": { - "Show launcher overlay when typing in Niri overview. Disable to use another launcher.": "在 Niri 總覽中輸入時顯示啟動器疊加。停用以使用其他啟動器。" - }, - "Show mode tabs and keyboard hints at the bottom.": { - "Show mode tabs and keyboard hints at the bottom.": "在底部顯示模式分頁與鍵盤提示。" - }, - "Show notification popups only on the currently focused monitor": { - "Show notification popups only on the currently focused monitor": "僅在當前焦點顯示器上顯示通知彈出視窗" - }, - "Show notifications only on the currently focused monitor": { - "Show notifications only on the currently focused monitor": "僅在當前焦點顯示器上顯示通知" - }, - "Show on Last Display": { - "Show on Last Display": "在最後顯示幕上顯示" - }, - "Show on Overlay": { - "Show on Overlay": "在覆疊層上顯示" - }, - "Show on Overview": { - "Show on Overview": "顯示在概覽畫面" - }, - "Show on Overview Only": { - "Show on Overview Only": "僅在總覽中顯示" - }, - "Show on all connected displays": { - "Show on all connected displays": "在所有連接的螢幕上顯示" - }, - "Show on screens:": { - "Show on screens:": "在螢幕上顯示:" - }, - "Show on-screen display when brightness changes": { - "Show on-screen display when brightness changes": "亮度改變時顯示螢幕顯示" - }, - "Show on-screen display when caps lock state changes": { - "Show on-screen display when caps lock state changes": "大小寫鎖定狀態改變時顯示螢幕顯示" - }, - "Show on-screen display when cycling audio output devices": { - "Show on-screen display when cycling audio output devices": "切換音訊輸出裝置時顯示螢幕顯示器" - }, - "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "閒置抑制器狀態改變時顯示螢幕顯示" - }, - "Show on-screen display when media player status changes": { - "Show on-screen display when media player status changes": "媒體播放器狀態變更時顯示螢幕顯示" - }, - "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "媒體播放器音量變化時顯示螢幕疊加" - }, - "Show on-screen display when microphone is muted/unmuted": { - "Show on-screen display when microphone is muted/unmuted": "麥克風靜音/取消靜音時顯示螢幕顯示" - }, - "Show on-screen display when power profile changes": { - "Show on-screen display when power profile changes": "電源設定檔改變時顯示螢幕顯示" - }, - "Show on-screen display when volume changes": { - "Show on-screen display when volume changes": "音量改變時顯示螢幕顯示" - }, - "Show seconds": { - "Show seconds": "顯示秒" - }, - "Show weather information in top bar and control center": { - "Show weather information in top bar and control center": "在頂部欄和控制中心顯示天氣資訊" - }, - "Show week number in the calendar": { - "Show week number in the calendar": "在日曆中顯示週數" - }, - "Show workspace index numbers in the top bar workspace switcher": { - "Show workspace index numbers in the top bar workspace switcher": "在頂部欄工作區切換器中顯示工作區編號" - }, - "Show workspace name on horizontal bars, and first letter on vertical bars": { - "Show workspace name on horizontal bars, and first letter on vertical bars": "在水平列顯示工作區名稱,垂直列顯示首字母" - }, - "Show workspaces of the currently focused monitor": { - "Show workspaces of the currently focused monitor": "顯示目前聚焦螢幕的工作區" - }, - "Shows all running applications with focus indication": { - "Shows all running applications with focus indication": "顯示所有正在運行的應用程式並帶有焦點指示" - }, - "Shows current workspace and allows switching": { - "Shows current workspace and allows switching": "顯示目前工作區並允許切換" - }, - "Shows when caps lock is active": { - "Shows when caps lock is active": "顯示大小寫鎖定啟用時" - }, - "Shows when microphone, camera, or screen sharing is active": { - "Shows when microphone, camera, or screen sharing is active": "顯示麥克風、攝影機或螢幕共用處於活動狀態" - }, - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": { - "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size": "" - }, - "Shutdown": { - "Shutdown": "關機" - }, - "Signal": { - "Signal": "訊號" - }, - "Signal:": { - "Signal:": "訊號:" - }, - "Size": { - "Size": "大小" - }, - "Size Constraints": { - "Size Constraints": "大小限制" - }, - "Size Offset": { - "Size Offset": "大小偏移" - }, - "Sizing": { - "Sizing": "尺寸" - }, - "Skip": { - "Skip": "跳過" - }, - "Skip confirmation": { - "Skip confirmation": "跳過確認" - }, - "Skip setup": { - "Skip setup": "跳過設定" - }, - "Small": { - "Small": "小" - }, - "Smartcard Authentication": { - "Smartcard Authentication": "智慧卡驗證" - }, - "Smartcard PIN": { - "Smartcard PIN": "智慧卡 PIN 碼" - }, - "Snap": { - "Snap": "貼齊" - }, - "Snow": { - "Snow": "雪" - }, - "Some plugins require a newer version of DMS:": { - "Some plugins require a newer version of DMS:": "部分外掛程式需要較新版 DMS:" - }, - "Sort Alphabetically": { - "Sort Alphabetically": "按字母順序排序" - }, - "Sort By": { - "Sort By": "排序方式" - }, - "Sorting & Layout": { - "Sorting & Layout": "排序和佈局" - }, - "Sound Theme": { - "Sound Theme": "音效主題" - }, - "Sounds": { - "Sounds": "聲音" - }, - "Space between windows": { - "Space between windows": "視窗間距" - }, - "Space between windows (gappih/gappiv/gappoh/gappov)": { - "Space between windows (gappih/gappiv/gappoh/gappov)": "視窗間距 (gappih/gappiv/gappoh/gappov)" - }, - "Space between windows (gaps_in and gaps_out)": { - "Space between windows (gaps_in and gaps_out)": "視窗間距 (gaps_in 和 gaps_out)" - }, - "Spacer": { - "Spacer": "空白間隔" - }, - "Spacing": { - "Spacing": "間距" - }, - "Speaker settings": { - "Speaker settings": "喇叭設定" - }, - "Speed": { - "Speed": "速度" - }, - "Spool Area Full": { - "Spool Area Full": "緩衝區已滿" - }, - "Square Corners": { - "Square Corners": "方角" - }, - "Stacked": { - "Stacked": "堆疊" - }, - "Standard": { - "Standard": "標準" - }, - "Start": { - "Start": "開始" - }, - "Start KDE Connect or Valent": { - "Start KDE Connect or Valent": "啟動 KDE Connect 或 Valent" - }, - "Start KDE Connect or Valent to use this plugin": { - "Start KDE Connect or Valent to use this plugin": "啟動 KDE Connect 或 Valent 以使用此外掛" - }, - "Start typing your notes here...": { - "Start typing your notes here...": "從這裡開始輸入您的筆記..." - }, - "State": { - "State": "狀態" - }, - "Status": { - "Status": "狀態" - }, - "Stopped": { - "Stopped": "已停止" - }, - "Stopped Partly": { - "Stopped Partly": "部分停止" - }, - "Stopping": { - "Stopping": "正在停止" - }, - "Stretch": { - "Stretch": "延展" - }, - "Stripes": { - "Stripes": "條紋" - }, - "Summary": { - "Summary": "摘要" - }, - "Sunrise": { - "Sunrise": "日出" - }, - "Sunset": { - "Sunset": "日落" - }, - "Suppress notification popups while enabled": { - "Suppress notification popups while enabled": "啟用時抑制通知彈出視窗" - }, - "Surface": { - "Surface": "表面" - }, - "Surface Variant": { - "Surface Variant": "表面變化" - }, - "Suspend": { - "Suspend": "睡眠" - }, - "Suspend behavior": { - "Suspend behavior": "睡眠行為" - }, - "Suspend system after": { - "Suspend system after": "指定時間後系統睡眠" - }, - "Suspend then Hibernate": { - "Suspend then Hibernate": "掛起後休眠" - }, - "Sway Website": { - "Sway Website": "Sway 網站" - }, - "Switch User": { - "Switch User": "切換使用者" - }, - "Switch to power profile": { - "Switch to power profile": "切換至電源設定檔" - }, - "Sync": { - "Sync": "同步" - }, - "Sync Mode with Portal": { - "Sync Mode with Portal": "透過 Portal 同步主題模式" - }, - "Sync Popouts & Modals": { - "Sync Popouts & Modals": "同步彈出視窗和模態視窗" - }, - "Sync Position Across Screens": { - "Sync Position Across Screens": "跨螢幕同步位置" - }, - "Sync completed successfully.": { - "Sync completed successfully.": "同步成功完成。" - }, - "Sync dark mode with settings portals for system-wide theme hints": { - "Sync dark mode with settings portals for system-wide theme hints": "將暗模式與設定入口網站同步以取得系統範圍的主題提示" - }, - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": { - "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.": "後台模式同步失敗。正在嘗試終端模式,以便您可以互動式驗證。" - }, - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": { - "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.": "同步需要 sudo 驗證。正在開啟終端機,以便您可以使用密碼或指紋。" - }, - "System": { - "System": "系統" - }, - "System App Theming": { - "System App Theming": "系統應用程式主題" - }, - "System Check": { - "System Check": "系統檢查" - }, - "System Default": { - "System Default": "系統預設" - }, - "System Information": { - "System Information": "系統資訊" - }, - "System Monitor": { - "System Monitor": "系統監視器" - }, - "System Monitor Unavailable": { - "System Monitor Unavailable": "系統監視器不可用" - }, - "System Sounds": { - "System Sounds": "系統聲音" - }, - "System Tray": { - "System Tray": "系統匣" - }, - "System Update": { - "System Update": "系統更新" - }, - "System Updater": { - "System Updater": "系統更新程式" - }, - "System Updates": { - "System Updates": "系統更新" - }, - "System notification area icons": { - "System notification area icons": "顯示常駐程式狀態圖示和系統通知" - }, - "System sounds are not available. Install %1 for sound support.": { - "System sounds are not available. Install %1 for sound support.": "系統音效無法使用。請安裝 %1 以取得音效支援。" - }, - "System theme toggle": { - "System theme toggle": "系統佈景主題切換" - }, - "System toast notifications": { - "System toast notifications": "系統快顯通知" - }, - "System update custom command": { - "System update custom command": "自訂系統更新指令" - }, - "Tab": { - "Tab": "分頁" - }, - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": { - "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: 切換焦點 • ←→↑↓: 切換焦點 • Enter/Space: 選擇" - }, - "Terminal": { - "Terminal": "終端機" - }, - "Terminal custom additional parameters": { - "Terminal custom additional parameters": "自訂終端附加參數" - }, - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": { - "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.": "" - }, - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": { - "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.": "終端機回退失敗。請安裝受支援的終端模擬器之一,或手動執行 'dms greeter sync'。" - }, - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal fallback opened. Complete sync there; it will close automatically when done.": { - "Terminal fallback opened. Complete sync there; it will close automatically when done.": "終端機回退已開啟。請在那裡完成同步;完成後它將自動關閉。" - }, - "Terminal multiplexer backend to use": { - "Terminal multiplexer backend to use": "要使用的終端多工器後端" - }, - "Terminal opened. Complete authentication setup there; it will close automatically when done.": { - "Terminal opened. Complete authentication setup there; it will close automatically when done.": "" - }, - "Terminal opened. Complete sync authentication there; it will close automatically when done.": { - "Terminal opened. Complete sync authentication there; it will close automatically when done.": "終端機已開啟。請在那裡完成同步驗證;完成後它將自動關閉。" - }, - "Terminals - Always use Dark Theme": { - "Terminals - Always use Dark Theme": "終端 - 始終使用深色主題" - }, - "Test Connection": { - "Test Connection": "測試連線" - }, - "Test Page": { - "Test Page": "測試頁" - }, - "Test page sent to printer": { - "Test page sent to printer": "測試頁已傳送至印表機" - }, - "Testing...": { - "Testing...": "正在測試..." - }, - "Text": { - "Text": "文字" - }, - "Text Color": { - "Text Color": "文字顏色" - }, - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": { - "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.": "系統監控需要 'dgop' 工具。\n請安裝 dgop 以使用此功能。" - }, - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": { - "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "DMS_SOCKET 環境變數未設定或套接字不可用。自動插件管理需要 DMS_SOCKET。" - }, - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": { - "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "以下設定將修改您的 GTK 和 Qt 設定。如果您希望保留目前配置,請備份 (qt5ct.conf|qt6ct.conf 和 ~/.config/gtk-3.0|gtk-4.0)。" - }, - "The custom command used when attaching to sessions (receives the session name as the first argument)": { - "The custom command used when attaching to sessions (receives the session name as the first argument)": "附加到會話時使用的自訂命令(將會話名稱作為第一個參數接收)" - }, - "The job queue of this printer is empty": { - "The job queue of this printer is empty": "此印表機的工作佇列為空" - }, - "Theme & Colors": { - "Theme & Colors": "主題和顏色" - }, - "Theme Color": { - "Theme Color": "主題顏色" - }, - "Theme Registry": { - "Theme Registry": "主題註冊" - }, - "Themes": { - "Themes": "主題" - }, - "Thickness": { - "Thickness": "粗細" - }, - "Third-Party Plugin Warning": { - "Third-Party Plugin Warning": "第三方插件警告" - }, - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": { - "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.": "第三方外掛程式由社群建立,非 DankMaterialShell 官方支援。\n\n這些外掛程式可能存在安全和隱私風險 — 請自行承擔風險安裝。" - }, - "This bind is overridden by config.kdl": { - "This bind is overridden by config.kdl": "此綁定已被 config.kdl 覆蓋" - }, - "This may take a few seconds": { - "This may take a few seconds": "這可能需要幾秒鐘" - }, - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": { - "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json": "意外掛程式沒有 'settings_write' 權限。\n\n請在 plugin.json 中添加 \"permissions\": [\"settings_read\", \"settings_write\"]" - }, - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": { - "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.": "此部件可防止 GPU 電源關閉,這會嚴重影響筆記型電腦的電池續航時間。不建議在配備混合顯示卡的筆記型電腦上使用此功能。" - }, - "This will delete all unpinned entries. %1 pinned entries will be kept.": { - "This will delete all unpinned entries. %1 pinned entries will be kept.": "這將刪除所有未釘選的項目。將保留 %1 個已釘選項目。" - }, - "This will permanently delete all clipboard history.": { - "This will permanently delete all clipboard history.": "這將永久刪除所有剪貼簿歷史記錄。" - }, - "This will permanently remove this saved clipboard item. This action cannot be undone.": { - "This will permanently remove this saved clipboard item. This action cannot be undone.": "這將永久移除此儲存的剪貼簿項目。此動作無法復原。" - }, - "Thunderstorm": { - "Thunderstorm": "雷暴" - }, - "Thunderstorm with Hail": { - "Thunderstorm with Hail": "帶冰雹的雷暴" - }, - "Tile": { - "Tile": "拼貼" - }, - "Tile H": { - "Tile H": "水平拼貼" - }, - "Tile V": { - "Tile V": "垂直拼貼" - }, - "Tiled": { - "Tiled": "並排" - }, - "Tiled State": { - "Tiled State": "並排狀態" - }, - "Tiling": { - "Tiling": "平鋪" - }, - "Time": { - "Time": "時間" - }, - "Time & Date Locale": { - "Time & Date Locale": "時間與日期地區設定" - }, - "Time & Weather": { - "Time & Weather": "時間與天氣" - }, - "Time Format": { - "Time Format": "時間格式" - }, - "Time format": { - "Time format": "時間格式" - }, - "Time remaining: %1": { - "Time remaining: %1": "剩餘時間:%1" - }, - "Time until full: %1": { - "Time until full: %1": "充滿電剩餘時間:%1" - }, - "Timed Out": { - "Timed Out": "逾時" - }, - "Timeout for critical priority notifications": { - "Timeout for critical priority notifications": "緊急優先級通知的超時" - }, - "Timeout for low priority notifications": { - "Timeout for low priority notifications": "低優先級通知的超時" - }, - "Timeout for normal priority notifications": { - "Timeout for normal priority notifications": "正常優先級通知的超時" - }, - "Title": { - "Title": "標題" - }, - "Title regex (optional)": { - "Title regex (optional)": "標題正規表達式 (選用)" - }, - "To Full": { - "To Full": "全部" - }, - "To update, run the following command:": { - "To update, run the following command:": "若要更新,請執行以下命令:" - }, - "To use this DMS bind, remove or change the keybind in your config.kdl": { - "To use this DMS bind, remove or change the keybind in your config.kdl": "若要使用此 DMS 綁定,請在 config.kdl 中移除或更改按鍵綁定" - }, - "Toast Messages": { - "Toast Messages": "快顯通知" - }, - "Today": { - "Today": "今天" - }, - "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "切換此欄配置的可見性" - }, - "Toggling...": { - "Toggling...": "切換中..." - }, - "Tomorrow": { - "Tomorrow": "明天" - }, - "Tonal Spot": { - "Tonal Spot": "色調斑點" - }, - "Toner Empty": { - "Toner Empty": "碳粉空" - }, - "Toner Low": { - "Toner Low": "碳粉不足" - }, - "Too many attempts - locked out": { - "Too many attempts - locked out": "" - }, - "Too many failed attempts - account may be locked": { - "Too many failed attempts - account may be locked": "嘗試失敗次數過多 - 帳戶可能已鎖定" - }, - "Tools": { - "Tools": "工具" - }, - "Top": { - "Top": "上方" - }, - "Top (Default)": { - "Top (Default)": "頂部 (預設)" - }, - "Top Bar Format": { - "Top Bar Format": "頂部欄格式" - }, - "Top Center": { - "Top Center": "頂端置中" - }, - "Top Left": { - "Top Left": "左上角" - }, - "Top Processes": { - "Top Processes": "最佔用程序" - }, - "Top Right": { - "Top Right": "右上角" - }, - "Top Section": { - "Top Section": "上方區塊" - }, - "Total": { - "Total": "總計" - }, - "Total Jobs": { - "Total Jobs": "總工作數" - }, - "Touch your security key...": { - "Touch your security key...": "" - }, - "Transform": { - "Transform": "變形" - }, - "Transition Effect": { - "Transition Effect": "切換動畫效果" - }, - "Transparency": { - "Transparency": "透明度" - }, - "Trending GIFs": { - "Trending GIFs": "熱門 GIF" - }, - "Trending Stickers": { - "Trending Stickers": "熱門貼圖" - }, - "Trigger": { - "Trigger": "觸發" - }, - "Trigger Prefix": { - "Trigger Prefix": "觸發前綴" - }, - "Trigger: %1": { - "Trigger: %1": "觸發條件:%1" - }, - "Trust": { - "Trust": "信任" - }, - "Try a different search": { - "Try a different search": "嘗試不同的搜尋" - }, - "Turn off all displays immediately when the lock screen activates": { - "Turn off all displays immediately when the lock screen activates": "鎖定螢幕啟用時立即關閉所有顯示器" - }, - "Turn off monitors after": { - "Turn off monitors after": "指定時間後關閉螢幕" - }, - "Type": { - "Type": "類型" - }, - "Type at least 2 characters": { - "Type at least 2 characters": "請輸入至少 2 個字元" - }, - "Type this prefix to search keybinds": { - "Type this prefix to search keybinds": "輸入此前綴以搜尋快捷鍵" - }, - "Type to search files": { - "Type to search files": "輸入以搜尋檔案" - }, - "Typography": { - "Typography": "字體排版" - }, - "Typography & Motion": { - "Typography & Motion": "字體排版和動態" - }, - "Unavailable": { - "Unavailable": "不可用" - }, - "Unfocused Color": { - "Unfocused Color": "未聚焦顏色" - }, - "Ungrouped": { - "Ungrouped": "未分組" - }, - "Uninstall": { - "Uninstall": "解除安裝" - }, - "Uninstall Greeter": { - "Uninstall Greeter": "解除安裝歡迎畫面" - }, - "Uninstall Plugin": { - "Uninstall Plugin": "解除安裝插件" - }, - "Uninstall complete. Greeter has been removed.": { - "Uninstall complete. Greeter has been removed.": "解除安裝完成。歡迎畫面已移除。" - }, - "Uninstall failed: %1": { - "Uninstall failed: %1": "解除安裝失敗:%1" - }, - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": { - "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.": "解除安裝 DMS 歡迎畫面?這將移除設定並還原您之前的顯示管理器。將會開啟一個終端機以進行 sudo 驗證。" - }, - "Uninstalled: %1": { - "Uninstalled: %1": "已解除安裝:%1" - }, - "Uninstalling: %1": { - "Uninstalling: %1": "正在解除安裝:%1" - }, - "Unknown": { - "Unknown": "未知" - }, - "Unknown App": { - "Unknown App": "未知應用程式" - }, - "Unknown Artist": { - "Unknown Artist": "未知藝人" - }, - "Unknown Config": { - "Unknown Config": "未知組態" - }, - "Unknown Device": { - "Unknown Device": "未知裝置" - }, - "Unknown GPU": { - "Unknown GPU": "未知 GPU" - }, - "Unknown Monitor": { - "Unknown Monitor": "未知監視器" - }, - "Unknown Network": { - "Unknown Network": "未知網路" - }, - "Unknown Title": { - "Unknown Title": "未知標題" - }, - "Unknown Track": { - "Unknown Track": "未知曲目" - }, - "Unload on Close": { - "Unload on Close": "關閉時卸載" - }, - "Unmute": { - "Unmute": "解除靜音" - }, - "Unmute popups for %1": { - "Unmute popups for %1": "解除靜音 %1 的彈出視窗" - }, - "Unnamed Rule": { - "Unnamed Rule": "未命名規則" - }, - "Unpair": { - "Unpair": "取消配對" - }, - "Unpair failed": { - "Unpair failed": "取消配對失敗" - }, - "Unpin": { - "Unpin": "取消釘選" - }, - "Unpin from Dock": { - "Unpin from Dock": "取消 Dock 釘選" - }, - "Unsaved Changes": { - "Unsaved Changes": "未儲存變更" - }, - "Unsaved changes": { - "Unsaved changes": "未儲存變更" - }, - "Unsaved note...": { - "Unsaved note...": "未儲存筆記..." - }, - "Untitled": { - "Untitled": "無標題" - }, - "Untrust": { - "Untrust": "不信任" - }, - "Up to date": { - "Up to date": "最新" - }, - "Update": { - "Update": "更新" - }, - "Update All": { - "Update All": "更新全部" - }, - "Update Plugin": { - "Update Plugin": "更新插件" - }, - "Uptime": { - "Uptime": "開機時間" - }, - "Uptime:": { - "Uptime:": "開機時間:" - }, - "Urgent Color": { - "Urgent Color": "緊急顏色" - }, - "Usage Tips": { - "Usage Tips": "使用提示" - }, - "Use 24-hour time format instead of 12-hour AM/PM": { - "Use 24-hour time format instead of 12-hour AM/PM": "使用 24 小時時間格式,而不是 12 小時 AM/PM" - }, - "Use Custom Command": { - "Use Custom Command": "使用自訂指令" - }, - "Use Grid Layout": { - "Use Grid Layout": "使用網格佈局" - }, - "Use IP Location": { - "Use IP Location": "使用 IP 位置" - }, - "Use Imperial Units": { - "Use Imperial Units": "使用英制單位" - }, - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": { - "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "使用英制單位(°F, mph, inHg)而非公制單位(°C, km/h, hPa)" - }, - "Use Inline Expansion": { - "Use Inline Expansion": "" - }, - "Use Monospace Font": { - "Use Monospace Font": "使用等寬字體" - }, - "Use System Theme": { - "Use System Theme": "使用系統主題" - }, - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": { - "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.": "為登入畫面使用自訂圖片,或留空以使用您的桌面背景。" - }, - "Use a fixed shadow direction for this bar": { - "Use a fixed shadow direction for this bar": "為此列使用固定陰影方向" - }, - "Use a security key for lock screen authentication.": { - "Use a security key for lock screen authentication.": "使用安全金鑰進行鎖定螢幕驗證。" - }, - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": { - "Use an external wallpaper manager like swww, hyprpaper, or swaybg.": "使用外部桌布管理器,如 swww、hyprpaper 或 swaybg。" - }, - "Use animated wave progress bars for media playback": { - "Use animated wave progress bars for media playback": "在媒體播放使用動畫波浪進度條" - }, - "Use custom border size": { - "Use custom border size": "使用自訂邊框大小" - }, - "Use custom border/focus-ring width": { - "Use custom border/focus-ring width": "使用自訂邊框/焦點環寬度" - }, - "Use custom command for update your system": { - "Use custom command for update your system": "使用自訂指令更新您的系統" - }, - "Use custom gaps instead of bar spacing": { - "Use custom gaps instead of bar spacing": "使用自訂間距而非預設間距" - }, - "Use custom window radius instead of theme radius": { - "Use custom window radius instead of theme radius": "使用自訂視窗圓角而非主題圓角" - }, - "Use custom window rounding instead of theme radius": { - "Use custom window rounding instead of theme radius": "使用自訂視窗圓角而非主題半徑" - }, - "Use desktop wallpaper": { - "Use desktop wallpaper": "使用桌面背景" - }, - "Use fingerprint authentication for the lock screen.": { - "Use fingerprint authentication for the lock screen.": "使用指紋驗證鎖定螢幕。" - }, - "Use light theme instead of dark theme": { - "Use light theme instead of dark theme": "使用淺色主題而不是深色主題" - }, - "Use meters per second instead of km/h for wind speed": { - "Use meters per second instead of km/h for wind speed": "風速使用公尺/秒而非公里/小時" - }, - "Use smaller notification cards": { - "Use smaller notification cards": "使用較小的通知卡" - }, - "Use sound theme from system settings": { - "Use sound theme from system settings": "使用系統設定中的音效主題" - }, - "Use the same position and size on all displays": { - "Use the same position and size on all displays": "在所有螢幕上使用相同的位置與大小" - }, - "Use trigger prefix to activate": { - "Use trigger prefix to activate": "使用觸發前綴啟用" - }, - "Used when accent color is set to Custom": { - "Used when accent color is set to Custom": "當強調色設為自訂時使用" - }, - "User": { - "User": "使用者" - }, - "Username": { - "Username": "使用者名稱" - }, - "Username...": { - "Username...": "使用者名稱..." - }, - "Uses sunrise/sunset times based on your location.": { - "Uses sunrise/sunset times based on your location.": "依據您的位置使用日出/日落時間。" - }, - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": { - "Uses sunrise/sunset times to automatically adjust night mode based on your location.": "使用根據您的位置日出/日落時間自動調整夜間模式。" - }, - "Using shared settings from Gamma Control": { - "Using shared settings from Gamma Control": "使用 Gamma Control 的共享設定" - }, - "Utilities": { - "Utilities": "實用項目" - }, - "VPN": { - "VPN": "VPN" - }, - "VPN Connections": { - "VPN Connections": "VPN 連線" - }, - "VPN Password": { - "VPN Password": "VPN 密碼" - }, - "VPN configuration updated": { - "VPN configuration updated": "VPN 設定已更新" - }, - "VPN connections": { - "VPN connections": "VPN 連線" - }, - "VPN deleted": { - "VPN deleted": "VPN 已刪除" - }, - "VPN imported: %1": { - "VPN imported: %1": "VPN 已匯入:%1" - }, - "VPN not available": { - "VPN not available": "VPN 無法使用" - }, - "VPN status and quick connect": { - "VPN status and quick connect": "VPN 狀態和快速連線" - }, - "VRR": { - "VRR": "VRR" - }, - "VRR Fullscreen Only": { - "VRR Fullscreen Only": "僅 VRR 全螢幕" - }, - "VRR On-Demand": { - "VRR On-Demand": "VRR 隨選啟用" - }, - "Variable Refresh Rate": { - "Variable Refresh Rate": "可變更新率" - }, - "Verification": { - "Verification": "驗證" - }, - "Version": { - "Version": "版本" - }, - "Vertical Deck": { - "Vertical Deck": "垂直 Deck" - }, - "Vertical Grid": { - "Vertical Grid": "垂直網格" - }, - "Vertical Scrolling": { - "Vertical Scrolling": "垂直滾動" - }, - "Vertical Tiling": { - "Vertical Tiling": "垂直平鋪" - }, - "Vibrant": { - "Vibrant": "鮮豔" - }, - "Vibrant palette with playful saturation.": { - "Vibrant palette with playful saturation.": "色彩鮮明且飽和度活潑的調色板。" - }, - "Video Path": { - "Video Path": "影片路徑" - }, - "Video Screensaver": { - "Video Screensaver": "影片螢幕保護程式" - }, - "Videos": { - "Videos": "影片" - }, - "View Mode": { - "View Mode": "檢視模式" - }, - "Visibility": { - "Visibility": "能見度" - }, - "Visual Effects": { - "Visual Effects": "視覺效果" - }, - "Visual divider between widgets": { - "Visual divider between widgets": "部件之間的視覺分隔符" - }, - "Visual effect used when wallpaper changes": { - "Visual effect used when wallpaper changes": "桌布變更時所使用的視覺效果" - }, - "Volume": { - "Volume": "音量" - }, - "Volume Changed": { - "Volume Changed": "音量改變" - }, - "Volume Slider": { - "Volume Slider": "音量滑桿" - }, - "Volume, brightness, and other system OSDs": { - "Volume, brightness, and other system OSDs": "音量、亮度及其他系統OSD" - }, - "WPA/WPA2": { - "WPA/WPA2": "WPA/WPA2" - }, - "Wallpaper": { - "Wallpaper": "桌布" - }, - "Wallpaper Error": { - "Wallpaper Error": "桌布錯誤" - }, - "Wallpaper Monitor": { - "Wallpaper Monitor": "桌布監視器" - }, - "Wallpaper fill mode": { - "Wallpaper fill mode": "背景圖片填充模式" - }, - "Wallpaper processing failed": { - "Wallpaper processing failed": "桌布處理失敗" - }, - "Wallpaper processing failed - check wallpaper path": { - "Wallpaper processing failed - check wallpaper path": "桌布處理失敗 - 請檢查桌布路徑" - }, - "Wallpapers": { - "Wallpapers": "桌布" - }, - "Warm color temperature to apply": { - "Warm color temperature to apply": "套用暖色溫" - }, - "Warning": { - "Warning": "警告" - }, - "Warnings": { - "Warnings": "警告" - }, - "Wave Progress Bars": { - "Wave Progress Bars": "波浪進度條" - }, - "Weather": { - "Weather": "天氣" - }, - "Weather Widget": { - "Weather Widget": "天氣部件" - }, - "Welcome": { - "Welcome": "歡迎" - }, - "Welcome to DankMaterialShell": { - "Welcome to DankMaterialShell": "歡迎使用 DankMaterialShell" - }, - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": { - "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window": "在 Hyprland 特殊工作區中點擊停靠視窗時,在聚焦視窗之前將該特殊工作區帶回" - }, - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { - "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "啟用後,應用程式將按字母順序排序。禁用後,應用程式將按使用頻率排序。" - }, - "When locked": { - "When locked": "鎖定時" - }, - "When updater widget is used, then hide it if no update found": { - "When updater widget is used, then hide it if no update found": "使用更新小工具時,若無更新則隱藏" - }, - "Wi-Fi Password": { - "Wi-Fi Password": "Wi-Fi 密碼" - }, - "Wi-Fi and Ethernet connection": { - "Wi-Fi and Ethernet connection": "Wi-Fi 與乙太網路連線" - }, - "Wi-Fi not available": { - "Wi-Fi not available": "Wi-Fi 無法使用" - }, - "WiFi": { - "WiFi": "WiFi" - }, - "WiFi Device": { - "WiFi Device": "WiFi 裝置" - }, - "WiFi QR code for ": { - "WiFi QR code for ": "WiFi 二維碼適用於 " - }, - "WiFi disabled": { - "WiFi disabled": "關閉 WiFi" - }, - "WiFi enabled": { - "WiFi enabled": "開啟 WiFi" - }, - "WiFi is off": { - "WiFi is off": "WiFi 關閉" - }, - "WiFi off": { - "WiFi off": "Wi-Fi 已關閉" - }, - "Wide (BT2020)": { - "Wide (BT2020)": "寬廣 (BT2020)" - }, - "Widget Background Color": { - "Widget Background Color": "部件背景顏色" - }, - "Widget Management": { - "Widget Management": "部件管理" - }, - "Widget Outline": { - "Widget Outline": "部件外框" - }, - "Widget Style": { - "Widget Style": "部件樣式" - }, - "Widget Styling": { - "Widget Styling": "部件樣式" - }, - "Widget Transparency": { - "Widget Transparency": "部件透明度" - }, - "Widget added": { - "Widget added": "小工具已新增" - }, - "Widget removed": { - "Widget removed": "小工具已移除" - }, - "Widgets": { - "Widgets": "小工具" - }, - "Widgets, layout, style": { - "Widgets, layout, style": "小工具、版面配置、樣式" - }, - "Width": { - "Width": "寬度" - }, - "Width of window border (borderpx)": { - "Width of window border (borderpx)": "視窗邊框寬度 (borderpx)" - }, - "Width of window border (general.border_size)": { - "Width of window border (general.border_size)": "視窗邊框寬度 (general.border_size)" - }, - "Width of window border and focus ring": { - "Width of window border and focus ring": "視窗邊框與焦點環寬度" - }, - "Wind": { - "Wind": "風速" - }, - "Wind Speed": { - "Wind Speed": "風速" - }, - "Wind Speed in m/s": { - "Wind Speed in m/s": "風速 (m/s)" - }, - "Window Corner Radius": { - "Window Corner Radius": "視窗圓角半徑" - }, - "Window Gaps": { - "Window Gaps": "視窗間距" - }, - "Window Gaps (px)": { - "Window Gaps (px)": "視窗間距 (像素)" - }, - "Window Height": { - "Window Height": "視窗高度" - }, - "Window Opening": { - "Window Opening": "視窗開啟" - }, - "Window Rounding": { - "Window Rounding": "視窗圓角" - }, - "Window Rules": { - "Window Rules": "視窗規則" - }, - "Window Rules Include Missing": { - "Window Rules Include Missing": "視窗規則包含遺失項目" - }, - "Window Rules Not Configured": { - "Window Rules Not Configured": "視窗規則未設定" - }, - "Wipe": { - "Wipe": "清除" - }, - "Workspace": { - "Workspace": "工作區" - }, - "Workspace Appearance": { - "Workspace Appearance": "工作區外觀" - }, - "Workspace Index Numbers": { - "Workspace Index Numbers": "工作區編號" - }, - "Workspace Names": { - "Workspace Names": "工作區名稱" - }, - "Workspace Padding": { - "Workspace Padding": "工作區內距" - }, - "Workspace Settings": { - "Workspace Settings": "工作區設定" - }, - "Workspace Switcher": { - "Workspace Switcher": "工作區切換器" - }, - "Workspace name": { - "Workspace name": "工作區名稱" - }, - "Workspaces": { - "Workspaces": "工作區" - }, - "Workspaces & Widgets": { - "Workspaces & Widgets": "工作區與小工具" - }, - "Write:": { - "Write:": "寫入:" - }, - "X Axis": { - "X Axis": "X 軸" - }, - "Y Axis": { - "Y Axis": "Y 軸" - }, - "Yes": { - "Yes": "是" - }, - "Yesterday": { - "Yesterday": "昨天" - }, - "You have unsaved changes. Save before closing this tab?": { - "You have unsaved changes. Save before closing this tab?": "您有未儲存的變更。是否要儲存?" - }, - "You have unsaved changes. Save before continuing?": { - "You have unsaved changes. Save before continuing?": "您有未儲存的變更。是否先保存再繼續?" - }, - "You have unsaved changes. Save before creating a new file?": { - "You have unsaved changes. Save before creating a new file?": "您有未儲存的變更。是否先保存再創新檔案?" - }, - "You have unsaved changes. Save before opening a file?": { - "You have unsaved changes. Save before opening a file?": "您有未儲存的變更。是否先保存再開檔案?" - }, - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": { - "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.": "您需要設定以下其中一個環境變數並重新啟動 shell:\nQT_QPA_PLATFORMTHEME=gtk3 或\nQT_QPA_PLATFORMTHEME=qt6ct\n\nqt6ct 需要安裝 qt6ct-kde。" - }, - "You're All Set!": { - "You're All Set!": "一切就緒!" - }, - "Your system is up to date!": { - "Your system is up to date!": "您的系統是最新版本!" - }, - "actions": { - "actions": "動作" - }, - "attached": { - "attached": "已附加" - }, - "brandon": { - "brandon": "布蘭登" - }, - "by %1": { - "by %1": "作者:%1" - }, - "days": { - "days": "天" - }, - "detached": { - "detached": "已分離" - }, - "device": { - "device": "裝置" - }, - "devices connected": { - "devices connected": "已連接裝置" - }, - "dgop not available": { - "dgop not available": "dgop 無法使用" - }, - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": { - "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.": "dms 是一個高度可自訂的現代桌面外殼,其設計靈感來自 material 3

        它使用 Quickshell(一個用於構建桌面外殼的 QT6 框架)和 Go(一種靜態類型、編譯式程式語言)構建。" - }, - "dms/cursor config exists but is not included. Cursor settings won't apply.": { - "dms/cursor config exists but is not included. Cursor settings won't apply.": "dms/cursor 設定存在但未被包含。游標設定將不會套用。" - }, - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": { - "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.": "dms/outputs 組態存在,但未包含在您的合成器組態中。顯示變更將不會保留。" - }, - "e.g., firefox, kitty --title foo": { - "e.g., firefox, kitty --title foo": "例如,firefox, kitty --title foo" - }, - "e.g., focus-workspace 3, resize-column -10": { - "e.g., focus-workspace 3, resize-column -10": "例如,focus-workspace 3, resize-column -10" - }, - "e.g., notify-send 'Hello' && sleep 1": { - "e.g., notify-send 'Hello' && sleep 1": "例如:notify-send 'Hello' && sleep 1" - }, - "e.g., scratch, /^tmp_.*/, build": { - "e.g., scratch, /^tmp_.*/, build": "例如:scratch, /^tmp_.*/, build" - }, - "events": { - "events": "活動" - }, - "ext": { - "ext": "外部" - }, - "featured": { - "featured": "精選" - }, - "leave empty for default": { - "leave empty for default": "留空以使用預設值" - }, - "loginctl not available - lock integration requires DMS socket connection": { - "loginctl not available - lock integration requires DMS socket connection": "loginctl 不可用 - 鎖定整合需要 DMS 套接字連接" - }, - "mangowc Discord Server": { - "mangowc Discord Server": "mangowc Discord 伺服器" - }, - "mangowc GitHub": { - "mangowc GitHub": "mangowc GitHub" - }, - "matugen not found - install matugen package for dynamic theming": { - "matugen not found - install matugen package for dynamic theming": "找不到 matugen - 請安裝 matugen 套件以實現動態主題" - }, - "minutes": { - "minutes": "分鐘" - }, - "ms": { - "ms": "毫秒" - }, - "nav": { - "nav": "導覽" - }, - "niri GitHub": { - "niri GitHub": "niri GitHub" - }, - "niri Matrix Chat": { - "niri Matrix Chat": "niri Matrix 聊天室" - }, - "niri shortcuts config": { - "niri shortcuts config": "niri 捷徑設定" - }, - "niri/dms Discord": { - "niri/dms Discord": "niri/dms Discord" - }, - "now": { - "now": "現在" - }, - "official": { - "official": "官方" - }, - "on Hyprland": { - "on Hyprland": "在 Hyprland 上" - }, - "on MangoWC": { - "on MangoWC": "在 MangoWC 上" - }, - "on Miracle WM": { - "on Miracle WM": "在 Miracle WM 上" - }, - "on Niri": { - "on Niri": "在 Niri 上" - }, - "on Scroll": { - "on Scroll": "在 Scroll 上" - }, - "on Sway": { - "on Sway": "在 Sway 上" - }, - "open": { - "open": "開啟" - }, - "or run ": { - "or run ": "或執行 " - }, - "power-profiles-daemon not available": { - "power-profiles-daemon not available": "power-profiles-daemon 不可用" - }, - "procs": { - "procs": "處理程序" - }, - "r/niri Subreddit": { - "r/niri Subreddit": "r/niri Subreddit" - }, - "seconds": { - "seconds": "秒" - }, - "source": { - "source": "來源" - }, - "this app": { - "this app": "此應用程式" - }, - "up": { - "up": "向上" - }, - "update dms for NM integration.": { - "update dms for NM integration.": "更新 dms 以進行 NM 整合。" - }, - "v%1 by %2": { - "v%1 by %2": "v%1 由 %2" - }, - "wtype not available - install wtype for paste support": { - "wtype not available - install wtype for paste support": "wtype 未可用 - 請安裝 wtype 以支援貼上功能" - }, - "• Install only from trusted sources": { - "• Install only from trusted sources": "• 僅從受信任的來源安裝" - }, - "• M - Month (1-12)": { - "• M - Month (1-12)": "• M - 月 (1-12)" - }, - "• MM - Month (01-12)": { - "• MM - Month (01-12)": "• MM - 月 (01-12)" - }, - "• MMM - Month (Jan)": { - "• MMM - Month (Jan)": "• MMM - 月 (一)" - }, - "• MMMM - Month (January)": { - "• MMMM - Month (January)": "• MMMM - 月 (一月)" - }, - "• Plugins may contain bugs or security issues": { - "• Plugins may contain bugs or security issues": "• 插件可能有錯誤或安全性問題" - }, - "• Review code before installation when possible": { - "• Review code before installation when possible": "• 盡可能在安裝前檢查程式碼" - }, - "• d - Day (1-31)": { - "• d - Day (1-31)": "• d - 日 (1-31)" - }, - "• dd - Day (01-31)": { - "• dd - Day (01-31)": "• dd - 日 (01-31)" - }, - "• ddd - Day name (Mon)": { - "• ddd - Day name (Mon)": "• ddd - 星期 (一)" - }, - "• dddd - Day name (Monday)": { - "• dddd - Day name (Monday)": "• dddd - 星期 (周一)" - }, - "• yy - Year (24)": { - "• yy - Year (24)": "• yy - 年 (24)" - }, - "• yyyy - Year (2024)": { - "• yyyy - Year (2024)": "• yyyy - 年 (2024)" - }, - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": { - "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text": "↑/↓: 導航 • 空格鍵: 展開 • Enter: 動作/展開 • E: 文字" - }, - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help": "↑/↓: 導航 • Enter/Ctrl+C: 複製 • Del: 刪除 • F10: 幫助" - }, - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": { - "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help": "↑/↓: 導航 • Enter: 貼上 • Del: 刪除 • F10: 幫助" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/replace_qstr.py b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/replace_qstr.py deleted file mode 100755 index b1ae17e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/replace_qstr.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -import os -import re -from pathlib import Path - -def replace_qstr_in_file(file_path, root_dir): - with open(file_path, 'r', encoding='utf-8') as f: - content = f.read() - - original_content = content - relative_path = file_path.relative_to(root_dir) - - qstr_pattern = re.compile(r'qsTr\("([^"]+)"\)') - - def replacement(match): - term = match.group(1) - context = term - return f'I18n.tr("{term}", "{context}")' - - content = qstr_pattern.sub(replacement, content) - - if content != original_content: - with open(file_path, 'w', encoding='utf-8') as f: - f.write(content) - return True - return False - -def main(): - script_dir = Path(__file__).parent - root_dir = script_dir.parent - - modified_count = 0 - - for qml_file in root_dir.rglob('*.qml'): - if 'translations' in str(qml_file): - continue - - try: - if replace_qstr_in_file(qml_file, root_dir): - modified_count += 1 - print(f"Modified: {qml_file.relative_to(root_dir)}") - except Exception as e: - print(f"Error processing {qml_file}: {e}") - - print(f"\nTotal files modified: {modified_count}") - -if __name__ == '__main__': - main() diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/settings_search_index.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/settings_search_index.json deleted file mode 100644 index a23662b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/settings_search_index.json +++ /dev/null @@ -1,7217 +0,0 @@ -[ - { - "section": "wallpaperCyclingEnabled", - "label": "Automatic Cycling", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "automatic", - "automatically", - "background", - "bg", - "custom", - "customize", - "cycle", - "cycling", - "desktop", - "folder", - "image", - "personal", - "personalization", - "picture", - "rotate", - "same", - "slideshow", - "through", - "wallpapers" - ], - "description": "Automatically cycle through wallpapers in the same folder" - }, - { - "section": "blurWallpaper", - "label": "Blur Wallpaper Layer", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "blur", - "compositor", - "config", - "configuration", - "configure", - "custom", - "customize", - "desktop", - "enable", - "image", - "layer", - "manual", - "niri", - "personal", - "personalization", - "picture", - "requires", - "setup", - "targetable", - "wallpaper" - ], - "description": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", - "conditionKey": "isNiri" - }, - { - "section": "blurWallpaperOnOverview", - "label": "Blur on Overview", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "blur", - "custom", - "customize", - "desktop", - "image", - "niri", - "open", - "overview", - "personal", - "personalization", - "picture", - "wallpaper" - ], - "description": "Blur wallpaper when niri overview is open", - "conditionKey": "isNiri" - }, - { - "section": "disableWallpapers", - "label": "Disable Built-in Wallpapers", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "built", - "custom", - "customize", - "desktop", - "disable", - "external", - "hyprpaper", - "image", - "management", - "manager", - "personal", - "personalization", - "picture", - "swaybg", - "swww", - "wallpaper", - "wallpapers" - ], - "description": "Use an external wallpaper manager like swww, hyprpaper, or swaybg." - }, - { - "section": "blurredWallpaperLayer", - "label": "Duplicate Wallpaper with Blur", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "blur", - "compositor", - "config", - "configuration", - "configure", - "custom", - "customize", - "desktop", - "duplicate", - "enable", - "image", - "layer", - "manual", - "niri", - "personal", - "personalization", - "picture", - "requires", - "setup", - "targetable", - "wallpaper" - ], - "description": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration." - }, - { - "section": "disableWallpaper", - "label": "External Wallpaper Management", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "custom", - "customize", - "desktop", - "disable", - "external", - "hyprpaper", - "image", - "management", - "manager", - "personal", - "personalization", - "picture", - "swaybg", - "swww", - "wallpaper" - ], - "icon": "wallpaper", - "description": "Use an external wallpaper manager like swww, hyprpaper, or swaybg." - }, - { - "section": "wallpaperCyclingInterval", - "label": "Interval", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "change", - "custom", - "customize", - "cycling", - "desktop", - "frequency", - "image", - "interval", - "often", - "personal", - "personalization", - "picture", - "time", - "wallpaper" - ], - "description": "How often to change wallpaper" - }, - { - "section": "matugenTargetMonitor", - "label": "Matugen Target Monitor", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "colors", - "colour", - "colours", - "custom", - "customize", - "desktop", - "drives", - "dynamic", - "hue", - "image", - "material", - "matugen", - "monitor", - "palette", - "personal", - "personalization", - "picture", - "target", - "theming", - "tint", - "wallpaper", - "wallpaper colors", - "whose" - ], - "description": "Monitor whose wallpaper drives dynamic theming colors" - }, - { - "section": "perModeWallpaper", - "label": "Per-Mode Wallpapers", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "custom", - "customize", - "dark", - "dark mode", - "day", - "desktop", - "different", - "image", - "light", - "light mode", - "mode", - "night", - "per", - "per-mode", - "personal", - "personalization", - "picture", - "theme", - "wallpapers" - ], - "description": "Set different wallpapers for light and dark mode" - }, - { - "section": "perMonitorWallpaper", - "label": "Per-Monitor Wallpapers", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "connected", - "custom", - "customize", - "desktop", - "different", - "display", - "image", - "monitor", - "multi-monitor", - "per", - "per-monitor", - "personal", - "personalization", - "picture", - "wallpapers" - ], - "description": "Set different wallpapers for each connected monitor" - }, - { - "section": "_tab_0", - "label": "Personalization", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "custom", - "customize", - "personal", - "personalization" - ], - "icon": "palette" - }, - { - "section": "wallpaperTransition", - "label": "Transition Effect", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "animation", - "appearance", - "background", - "bg", - "change", - "changes", - "custom", - "customize", - "desktop", - "effect", - "image", - "personal", - "personalization", - "picture", - "transition", - "visual", - "wallpaper" - ], - "description": "Visual effect used when wallpaper changes" - }, - { - "section": "wallpaper", - "label": "Wallpaper", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "custom", - "customize", - "dark", - "dark mode", - "day", - "desktop", - "different", - "image", - "light", - "light mode", - "mode", - "night", - "personal", - "personalization", - "picture", - "wallpaper", - "wallpapers" - ], - "icon": "wallpaper", - "description": "Set different wallpapers for light and dark mode" - }, - { - "section": "selectedMonitor", - "label": "Wallpaper Monitor", - "tabIndex": 0, - "category": "Personalization", - "keywords": [ - "appearance", - "background", - "bg", - "configure", - "custom", - "customize", - "desktop", - "display", - "image", - "monitor", - "personal", - "personalization", - "picture", - "screen", - "select", - "wallpaper" - ], - "description": "Select monitor to configure wallpaper" - }, - { - "section": "use24HourClock", - "label": "24-Hour Format", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "24hour", - "clock", - "date", - "forecast", - "format", - "hour", - "time", - "weather" - ], - "description": "Use 24-hour time format instead of 12-hour AM/PM" - }, - { - "section": "useAutoLocation", - "label": "Auto Location", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "address", - "auto", - "automatically", - "clock", - "date", - "determine", - "forecast", - "gps", - "location", - "time", - "weather" - ], - "description": "Automatically determine your location using your IP address" - }, - { - "section": "dateFormat", - "label": "Date Format", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "calendar", - "clock", - "date", - "day", - "forecast", - "format", - "month", - "number", - "show", - "time", - "weather", - "week", - "year" - ], - "icon": "calendar_today", - "description": "Show week number in the calendar" - }, - { - "section": "weatherEnabled", - "label": "Enable Weather", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "center", - "climate", - "clock", - "control", - "date", - "enable", - "forecast", - "information", - "panel", - "show", - "statusbar", - "taskbar", - "temperature", - "time", - "topbar", - "weather" - ], - "description": "Show weather information in top bar and control center" - }, - { - "section": "firstDayOfWeek", - "label": "First Day of Week", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "clock", - "date", - "day", - "first", - "forecast", - "time", - "weather", - "week" - ] - }, - { - "section": "lockDateFormat", - "label": "Lock Screen Format", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "clock", - "date", - "forecast", - "format", - "lock", - "lockscreen", - "login", - "screen", - "security", - "time", - "weather" - ] - }, - { - "section": "padHours12Hour", - "label": "Pad Hours", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "12hour", - "clock", - "date", - "forecast", - "format", - "hours", - "leading", - "pad", - "padding", - "time", - "weather", - "zero" - ], - "description": "02:31 PM vs 2:31 PM" - }, - { - "section": "showSeconds", - "label": "Show Seconds", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "clock", - "date", - "display", - "forecast", - "monitor", - "output", - "screen", - "seconds", - "show", - "time", - "watch", - "weather" - ], - "description": "Display seconds in the clock" - }, - { - "section": "showWeekNumber", - "label": "Show Week Number", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "calendar", - "clock", - "date", - "day", - "forecast", - "month", - "number", - "show", - "time", - "weather", - "week", - "year" - ], - "description": "Show week number in the calendar" - }, - { - "section": "_tab_1", - "label": "Time & Weather", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "climate", - "clock", - "date", - "forecast", - "temperature", - "time", - "weather" - ], - "icon": "schedule" - }, - { - "section": "timeFormat", - "label": "Time Format", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "24hour", - "clock", - "date", - "forecast", - "format", - "hour", - "time", - "weather" - ], - "icon": "schedule", - "description": "Use 24-hour time format instead of 12-hour AM/PM" - }, - { - "section": "clockDateFormat", - "label": "Top Bar Format", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "bar", - "clock", - "date", - "forecast", - "format", - "panel", - "statusbar", - "taskbar", - "time", - "top", - "topbar", - "weather" - ] - }, - { - "section": "useFahrenheit", - "label": "Use Imperial Units", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "clock", - "date", - "fahrenheit", - "forecast", - "imperial", - "metric", - "time", - "units", - "weather" - ], - "description": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)" - }, - { - "section": "weather", - "label": "Weather", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "center", - "climate", - "clock", - "control", - "date", - "enable", - "forecast", - "information", - "panel", - "show", - "statusbar", - "taskbar", - "temperature", - "time", - "topbar", - "weather" - ], - "icon": "cloud", - "description": "Show weather information in top bar and control center" - }, - { - "section": "windSpeedUnit", - "label": "Wind Speed in m/s", - "tabIndex": 1, - "category": "Time & Weather", - "keywords": [ - "clock", - "date", - "forecast", - "meters", - "metric", - "second", - "speed", - "time", - "units", - "weather", - "wind" - ], - "description": "Use meters per second instead of km/h for wind speed" - }, - { - "section": "_tab_2", - "label": "Keyboard Shortcuts", - "tabIndex": 2, - "category": "Keyboard Shortcuts", - "keywords": [ - "bindings", - "hotkey", - "hotkeys", - "keybinds", - "keyboard", - "keys", - "shortcuts" - ], - "icon": "keyboard", - "conditionKey": "keybindsAvailable" - }, - { - "section": "barConfigurations", - "label": "Bar Configurations", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "config", - "configurations", - "configure", - "dank", - "panel", - "setup", - "statusbar", - "taskbar", - "topbar" - ], - "icon": "dashboard" - }, - { - "section": "barCorners", - "label": "Corners & Background", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "background", - "bar", - "corners", - "dank", - "panel", - "radius", - "round", - "rounded", - "statusbar", - "topbar" - ], - "icon": "rounded_corner" - }, - { - "section": "_tab_3", - "label": "Dank Bar", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "panel", - "statusbar", - "taskbar", - "topbar" - ], - "icon": "toolbar" - }, - { - "section": "barShadowDirectionSource", - "label": "Direction Source", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "choose", - "dank", - "direction", - "panel", - "resolves", - "shadow", - "source", - "statusbar", - "taskbar", - "topbar" - ], - "description": "Choose how this bar resolves shadow direction" - }, - { - "section": "barDisplay", - "label": "Display Assignment", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "assignment", - "bar", - "dank", - "display", - "monitor", - "output", - "panel", - "screen", - "statusbar", - "topbar" - ], - "icon": "display_settings" - }, - { - "section": "barShadowDirectionManual", - "label": "Manual Direction", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "direction", - "fixed", - "manual", - "panel", - "shadow", - "statusbar", - "taskbar", - "topbar" - ], - "description": "Use a fixed shadow direction for this bar" - }, - { - "section": "barPosition", - "label": "Position", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "panel", - "position", - "statusbar", - "topbar" - ], - "icon": "vertical_align_center" - }, - { - "section": "barShadow", - "label": "Shadow Override", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "global", - "override", - "panel", - "settings", - "shadow", - "statusbar", - "taskbar", - "topbar" - ], - "icon": "layers", - "description": "Override the global shadow with per-bar settings" - }, - { - "section": "barSpacing", - "label": "Spacing", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "gap", - "gaps", - "margin", - "margins", - "padding", - "panel", - "spacing", - "statusbar", - "topbar" - ], - "icon": "space_bar" - }, - { - "section": "barTransparency", - "label": "Transparency", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "alpha", - "bar", - "dank", - "opacity", - "panel", - "statusbar", - "topbar", - "translucent", - "transparency", - "transparent" - ], - "icon": "opacity" - }, - { - "section": "barVisibility", - "label": "Visibility", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "auto-hide", - "autohide", - "bar", - "dank", - "hidden", - "hide", - "panel", - "show", - "statusbar", - "topbar", - "visibility", - "visible" - ], - "icon": "visibility_off" - }, - { - "section": "workspaceDragReorder", - "label": "Drag to Reorder", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "desktop", - "drag", - "indicators", - "move", - "reorder", - "sort", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Drag workspace indicators to reorder them", - "conditionKey": "isNiri" - }, - { - "section": "workspaceFocusedBorderEnabled", - "label": "Focused Border", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "around", - "border", - "desktop", - "focused", - "indicator", - "outline", - "ring", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show an outline ring around the focused workspace indicator" - }, - { - "section": "workspaceFollowFocus", - "label": "Follow Monitor Focus", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "currently", - "desktop", - "desktops", - "focus", - "focused", - "follow", - "monitor", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show workspaces of the currently focused monitor", - "conditionKey": "isNiri" - }, - { - "section": "groupWorkspaceApps", - "label": "Group Workspace Apps", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "app", - "application", - "apps", - "collapse", - "desktop", - "desktops", - "group", - "grouped", - "icons", - "program", - "repeated", - "spaces", - "unfocused", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Group repeated application icons in unfocused workspaces" - }, - { - "section": "workspaceActiveAppHighlightEnabled", - "label": "Highlight Active Workspace App", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "active", - "app", - "apps", - "currently", - "day", - "desktop", - "focused", - "highlight", - "icons", - "indicators", - "inside", - "light mode", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Highlight the currently focused app inside workspace indicators" - }, - { - "section": "workspaceIcons", - "label": "Named Workspace Icons", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "desktop", - "icons", - "named", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "icon": "label" - }, - { - "section": "reverseScrolling", - "label": "Reverse Scrolling Direction", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "desktop", - "direction", - "over", - "panel", - "reverse", - "scroll", - "scrolling", - "spaces", - "statusbar", - "switch", - "taskbar", - "topbar", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Reverse workspace switch direction when scrolling over the bar", - "conditionKey": "isNiri" - }, - { - "section": "dwlShowAllTags", - "label": "Show All Tags", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "all", - "dwl", - "occupied", - "show", - "spaces", - "tags", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show all 9 tags instead of only occupied tags (DWL only)", - "conditionKey": "isDwl" - }, - { - "section": "showOccupiedWorkspacesOnly", - "label": "Show Occupied Workspaces Only", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "active", - "contain", - "desktop", - "desktops", - "display", - "monitor", - "occupied", - "output", - "screen", - "show", - "spaces", - "virtual", - "virtual desktops", - "windows", - "workspace", - "workspaces" - ], - "description": "Display only workspaces that contain windows", - "conditionKey": "isNiri" - }, - { - "section": "showWorkspaceApps", - "label": "Show Workspace Apps", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "app", - "application", - "applications", - "apps", - "desktop", - "display", - "icons", - "indicators", - "monitor", - "output", - "program", - "screen", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Display application icons in workspace indicators", - "conditionKey": "isNiri" - }, - { - "section": "workspaceAppearance", - "label": "Workspace Appearance", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "appearance", - "around", - "border", - "desktop", - "focused", - "indicator", - "outline", - "ring", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "icon": "palette", - "description": "Show an outline ring around the focused workspace indicator", - "conditionKey": "isNiri" - }, - { - "section": "showWorkspaceIndex", - "label": "Workspace Index Numbers", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "desktop", - "index", - "labels", - "numbers", - "panel", - "show", - "spaces", - "statusbar", - "switcher", - "taskbar", - "topbar", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show workspace index numbers in the top bar workspace switcher" - }, - { - "section": "showWorkspaceName", - "label": "Workspace Names", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "bars", - "desktop", - "first", - "horizontal", - "labels", - "letter", - "name", - "names", - "panel", - "show", - "spaces", - "statusbar", - "taskbar", - "topbar", - "vertical", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show workspace name on horizontal bars, and first letter on vertical bars" - }, - { - "section": "showWorkspacePadding", - "label": "Workspace Padding", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "always", - "available", - "desktop", - "desktops", - "even", - "fewer", - "minimum", - "padding", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Always show a minimum of 3 workspaces, even if fewer are available" - }, - { - "section": "workspaceSettings", - "label": "Workspace Settings", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "desktop", - "index", - "labels", - "numbers", - "panel", - "settings", - "show", - "spaces", - "statusbar", - "switcher", - "taskbar", - "topbar", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "icon": "view_module", - "description": "Show workspace index numbers in the top bar workspace switcher", - "conditionKey": "isNiri" - }, - { - "section": "_tab_4", - "label": "Workspaces & Widgets", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "components", - "desktop", - "desktops", - "modules", - "spaces", - "virtual", - "virtual desktops", - "widgets", - "workspace", - "workspaces" - ], - "icon": "dashboard" - }, - { - "section": "dockAutoHide", - "label": "Auto-hide Dock", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "always", - "area", - "auto", - "autohide", - "dock", - "hide", - "hover", - "hovering", - "launcher bar", - "near", - "panel", - "reveal", - "taskbar" - ], - "description": "Always hide the dock and reveal it when hovering near the dock area" - }, - { - "section": "dockBehavior", - "label": "Behavior", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "behavior", - "current", - "dock", - "isolate", - "launcher bar", - "monitor", - "multi-monitor", - "panel", - "show", - "taskbar", - "windows" - ], - "icon": "apps", - "description": "Only show windows from the current monitor on each dock", - "conditionKey": "isHyprland" - }, - { - "section": "dockBorder", - "label": "Border", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "around", - "border", - "dock", - "launcher bar", - "panel", - "taskbar" - ], - "icon": "border_style", - "description": "Add a border around the dock" - }, - { - "section": "dockLauncherLogoBrightness", - "label": "Brightness", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "backlight", - "bright", - "brightness", - "color", - "dim", - "dock", - "launcher", - "launcher bar", - "logo", - "taskbar" - ] - }, - { - "section": "dockLauncherLogoContrast", - "label": "Contrast", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "color", - "contrast", - "dock", - "launcher", - "launcher bar", - "logo", - "taskbar" - ] - }, - { - "section": "_tab_5", - "label": "Dock & Launcher", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app drawer", - "app menu", - "applications", - "dock", - "launcher", - "launcher bar", - "panel", - "start menu", - "taskbar" - ], - "icon": "apps" - }, - { - "section": "dockVisibility", - "label": "Dock Visibility", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app", - "applications", - "apps", - "auto-hide", - "autohide", - "display", - "dock", - "enable", - "hidden", - "hide", - "launcher bar", - "monitor", - "output", - "panel", - "pinned", - "program", - "programs", - "running", - "screen", - "show", - "taskbar", - "visibility", - "visible" - ], - "icon": "dock_to_bottom", - "description": "Display a dock with pinned and running applications" - }, - { - "section": "dockGroupByApp", - "label": "Group by App", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app", - "count", - "dock", - "group", - "indicator", - "launcher bar", - "multiple", - "same", - "taskbar", - "together", - "window", - "windows" - ], - "description": "Group multiple windows of the same app together with a window count indicator" - }, - { - "section": "dockIconSize", - "label": "Icon Size", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "dock", - "icon", - "launcher bar", - "scale", - "size", - "taskbar" - ] - }, - { - "section": "dockIndicatorStyle", - "label": "Indicator Style", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "circle", - "dock", - "indicator", - "launcher bar", - "line", - "style", - "taskbar" - ] - }, - { - "section": "dockSmartAutoHide", - "label": "Intelligent Auto-hide", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "auto", - "autohide", - "dock", - "floating", - "hide", - "intelligent", - "launcher bar", - "overlap", - "panel", - "show", - "smart", - "taskbar", - "windows" - ], - "description": "Show dock when floating windows don", - "conditionKey": "isNiri" - }, - { - "section": "dockIsolateDisplays", - "label": "Isolate Displays", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "current", - "displays", - "dock", - "isolate", - "launcher bar", - "monitor", - "monitors", - "multi-monitor", - "output", - "outputs", - "panel", - "screen", - "screens", - "show", - "taskbar", - "windows" - ], - "description": "Only show windows from the current monitor on each dock" - }, - { - "section": "dockLauncher", - "label": "Launcher Button", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app drawer", - "app menu", - "applications", - "apps", - "button", - "dock", - "launcher", - "launcher bar", - "start menu", - "taskbar" - ], - "icon": "apps" - }, - { - "section": "dockMaxVisibleApps", - "label": "Max Pinned Apps (0 = Unlimited)", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "apps", - "dock", - "launcher bar", - "limit", - "max", - "overflow", - "pinned", - "taskbar", - "unlimited)" - ] - }, - { - "section": "dockMaxVisibleRunningApps", - "label": "Max Running Apps (0 = Unlimited)", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "active", - "apps", - "dock", - "launcher bar", - "limit", - "max", - "open", - "overflow", - "running", - "taskbar", - "unlimited)", - "windows" - ] - }, - { - "section": "dockPosition", - "label": "Position", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "dock", - "launcher bar", - "position", - "taskbar" - ], - "icon": "swap_vert" - }, - { - "section": "dockRestoreSpecialWorkspaceOnClick", - "label": "Restore Special Workspace Windows", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "back", - "before", - "bring", - "clicking", - "desktop", - "dock", - "focusing", - "hyprland", - "launcher bar", - "panel", - "restore", - "special", - "taskbar", - "virtual", - "window", - "windows", - "workspace" - ], - "description": "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window", - "conditionKey": "isHyprland" - }, - { - "section": "showDock", - "label": "Show Dock", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app", - "applications", - "apps", - "display", - "dock", - "enable", - "launcher bar", - "monitor", - "output", - "panel", - "pinned", - "program", - "programs", - "running", - "screen", - "show", - "taskbar" - ], - "description": "Display a dock with pinned and running applications" - }, - { - "section": "dockLauncherEnabled", - "label": "Show Launcher Button", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "app drawer", - "app menu", - "applications", - "apps", - "button", - "dock", - "launcher", - "launcher bar", - "show", - "start menu", - "taskbar" - ] - }, - { - "section": "dockShowOverflowBadge", - "label": "Show Overflow Badge Count", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "active", - "badge", - "count", - "displays", - "dock", - "indicator", - "launcher bar", - "monitor", - "monitors", - "output", - "outputs", - "overflow", - "screen", - "screens", - "show", - "taskbar" - ], - "description": "Displays count when overflow is active" - }, - { - "section": "dockOpenOnOverview", - "label": "Show on Overview", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "always", - "dock", - "launcher bar", - "niri", - "overview", - "panel", - "show", - "taskbar" - ], - "description": "Always show the dock when niri", - "conditionKey": "isNiri" - }, - { - "section": "dockLauncherLogoSizeOffset", - "label": "Size Offset", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "dock", - "launcher", - "launcher bar", - "logo", - "offset", - "scale", - "size", - "taskbar" - ] - }, - { - "section": "dockSizing", - "label": "Sizing", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "dock", - "icon", - "launcher bar", - "scale", - "size", - "sizing", - "taskbar" - ], - "icon": "photo_size_select_large" - }, - { - "section": "dockSpacing", - "label": "Spacing", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "dock", - "gap", - "gaps", - "launcher bar", - "margin", - "margins", - "padding", - "spacing", - "taskbar" - ], - "icon": "space_bar" - }, - { - "section": "dockTransparency", - "label": "Transparency", - "tabIndex": 5, - "category": "Dock", - "keywords": [ - "alpha", - "dock", - "launcher bar", - "opacity", - "taskbar", - "translucent", - "transparency", - "transparent" - ], - "icon": "opacity" - }, - { - "section": "_tab_7", - "label": "Network", - "tabIndex": 7, - "category": "Network", - "keywords": [ - "connection", - "connectivity", - "ethernet", - "internet", - "network", - "online", - "wi-fi", - "wifi", - "wireless" - ], - "icon": "wifi", - "conditionKey": "dmsConnected" - }, - { - "section": "_tab_8", - "label": "Printers", - "tabIndex": 8, - "category": "System", - "keywords": [ - "cups", - "linux", - "os", - "print", - "printers", - "printing", - "system" - ], - "icon": "print", - "conditionKey": "cupsAvailable" - }, - { - "section": "appOverrides", - "label": "App Customizations", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "app", - "customizations", - "drawer", - "launcher", - "menu", - "start" - ], - "icon": "edit" - }, - { - "section": "dankLauncherV2Appearance", - "label": "Appearance", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "appearance", - "bottom", - "drawer", - "footer", - "hints", - "keyboard", - "launcher", - "menu", - "mode", - "shortcuts", - "show", - "start", - "tabs" - ], - "icon": "tune", - "description": "Show mode tabs and keyboard hints at the bottom." - }, - { - "section": "dankLauncherV2BorderEnabled", - "label": "Border", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "border", - "drawer", - "launcher", - "menu", - "outline", - "start" - ] - }, - { - "section": "launcherLogoBrightness", - "label": "Brightness", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "backlight", - "bright", - "brightness", - "color", - "dim", - "drawer", - "launcher", - "logo", - "menu", - "start" - ] - }, - { - "section": "launcherLogoContrast", - "label": "Contrast", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "color", - "contrast", - "drawer", - "launcher", - "logo", - "menu", - "start" - ] - }, - { - "section": "builtInPlugins", - "label": "DMS", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "dms", - "drawer", - "launcher", - "menu", - "start" - ], - "icon": "extension" - }, - { - "section": "niriOverviewOverlayEnabled", - "label": "Enable Overview Overlay", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "another", - "app drawer", - "app menu", - "applications", - "disable", - "drawer", - "enable", - "launcher", - "menu", - "niri", - "overlay", - "overview", - "show", - "start", - "start menu", - "typing" - ], - "description": "Show launcher overlay when typing in Niri overview. Disable to use another launcher." - }, - { - "section": "appLauncherGridColumns", - "label": "Grid Columns", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "adjust", - "columns", - "drawer", - "grid", - "launcher", - "layout", - "menu", - "mode", - "number", - "start", - "view" - ], - "description": "Adjust the number of columns in grid view mode." - }, - { - "section": "hiddenApps", - "label": "Hidden Apps", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "apps", - "drawer", - "hidden", - "launcher", - "menu", - "start" - ], - "icon": "visibility_off" - }, - { - "section": "dankLauncherV2IncludeFilesInAll", - "label": "Include Files in All Tab", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "all", - "drawer", - "dsearch", - "file", - "files", - "include", - "indexed", - "launcher", - "menu", - "merge", - "results", - "start", - "tab" - ], - "description": "Merge indexed file results into the All tab (requires dsearch)." - }, - { - "section": "dankLauncherV2IncludeFoldersInAll", - "label": "Include Folders in All Tab", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "all", - "dirs", - "drawer", - "dsearch", - "folder", - "folders", - "include", - "indexed", - "launcher", - "menu", - "merge", - "results", - "start", - "tab" - ], - "description": "Merge indexed folder results into the All tab (requires dsearch)." - }, - { - "section": "launcherLogoColorInvertOnMode", - "label": "Invert on mode change", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "change", - "color", - "drawer", - "invert", - "launcher", - "logo", - "menu", - "mode", - "start" - ] - }, - { - "section": "launchPrefix", - "label": "Launch Prefix", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "drawer", - "launch", - "launcher", - "menu", - "prefix", - "start" - ], - "icon": "terminal" - }, - { - "section": "_tab_9", - "label": "Launcher", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "app drawer", - "app menu", - "applications", - "drawer", - "launcher", - "menu", - "start", - "start menu" - ], - "icon": "grid_view" - }, - { - "section": "launcherLogo", - "label": "Launcher Button Logo", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "app drawer", - "app menu", - "applications", - "button", - "drawer", - "launcher", - "logo", - "menu", - "offset", - "scale", - "size", - "start", - "start menu" - ], - "icon": "apps" - }, - { - "section": "spotlightCloseNiriOverview", - "label": "Niri Integration", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "apps", - "auto", - "close", - "drawer", - "integration", - "launch", - "launcher", - "launching", - "menu", - "niri", - "overview", - "start" - ], - "icon": "open_in_new", - "description": "Auto-close Niri overview when launching apps.", - "conditionKey": "isNiri" - }, - { - "section": "pluginVisibility", - "label": "Plugin Visibility", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "auto-hide", - "autohide", - "drawer", - "hidden", - "hide", - "launcher", - "menu", - "plugin", - "show", - "start", - "visibility", - "visible" - ], - "icon": "filter_list" - }, - { - "section": "recentApps", - "label": "Recently Used Apps", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "apps", - "drawer", - "launcher", - "menu", - "recently", - "start" - ], - "icon": "history" - }, - { - "section": "rememberLastQuery", - "label": "Remember Last Query", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "autofill", - "drawer", - "last", - "launcher", - "menu", - "opened", - "query", - "remember", - "remembered", - "search", - "start" - ], - "description": "Autofill last remembered query when opened" - }, - { - "section": "searchAppActions", - "label": "Search App Actions", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "actions", - "app", - "desktop", - "drawer", - "include", - "launcher", - "menu", - "results", - "search", - "shortcuts", - "start" - ], - "description": "Include desktop actions (shortcuts) in search results." - }, - { - "section": "searchOptions", - "label": "Search Options", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "actions", - "desktop", - "drawer", - "include", - "launcher", - "menu", - "options", - "results", - "search", - "shortcuts", - "start" - ], - "icon": "search", - "description": "Include desktop actions (shortcuts) in search results." - }, - { - "section": "dankLauncherV2ShowFooter", - "label": "Show Footer", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "bottom", - "drawer", - "footer", - "hints", - "keyboard", - "launcher", - "menu", - "mode", - "shortcuts", - "show", - "start", - "tabs" - ], - "description": "Show mode tabs and keyboard hints at the bottom." - }, - { - "section": "launcherLogoSizeOffset", - "label": "Size Offset", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "drawer", - "launcher", - "logo", - "menu", - "offset", - "scale", - "size", - "start" - ] - }, - { - "section": "sortAppsAlphabetically", - "label": "Sort Alphabetically", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "alphabetically", - "apps", - "disabled", - "drawer", - "enabled", - "frequency", - "launcher", - "menu", - "order", - "sort", - "sorted", - "start", - "usage" - ], - "description": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency." - }, - { - "section": "launcherSorting", - "label": "Sorting & Layout", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "alphabetically", - "apps", - "disabled", - "drawer", - "enabled", - "frequency", - "launcher", - "layout", - "menu", - "order", - "sort", - "sorted", - "sorting", - "start", - "usage" - ], - "icon": "sort_by_alpha", - "description": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency." - }, - { - "section": "dankLauncherV2BorderThickness", - "label": "Thickness", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "border", - "drawer", - "launcher", - "menu", - "start", - "thickness" - ] - }, - { - "section": "dankLauncherV2UnloadOnClose", - "label": "Unload on Close", - "tabIndex": 9, - "category": "Launcher", - "keywords": [ - "app drawer", - "app menu", - "applications", - "cause", - "close", - "closed", - "day", - "delay", - "drawer", - "free", - "launcher", - "light mode", - "memory", - "menu", - "reopening", - "slight", - "start", - "start menu", - "unload", - "vram" - ], - "description": "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening." - }, - { - "section": "matugenTemplateAlacritty", - "label": "Alacritty", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "alacritty", - "appearance", - "colors", - "look", - "matugen", - "scheme", - "style", - "template", - "terminal", - "theme" - ] - }, - { - "section": "applications", - "label": "Applications", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "app", - "appearance", - "applications", - "apps", - "colors", - "colour", - "dark", - "dark mode", - "hints", - "look", - "mode", - "night", - "portal", - "portals", - "program", - "programs", - "scheme", - "settings", - "style", - "sync", - "system", - "terminal", - "theme", - "wide" - ], - "icon": "apps", - "description": "Sync dark mode with settings portals for system-wide theme hints" - }, - { - "section": "cursorHideAfterInactive", - "label": "Auto-Hide Timeout", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "after", - "appearance", - "auto", - "colors", - "cursor", - "hide", - "inactive", - "inactivity", - "look", - "scheme", - "style", - "theme", - "timeout" - ], - "description": "Hide cursor after inactivity (0 = disabled)" - }, - { - "section": "automaticColorMode", - "label": "Automatic Color Mode", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "automatic", - "color", - "colors", - "colour", - "hue", - "look", - "mode", - "schedule", - "scheme", - "style", - "sunrise", - "sunset", - "theme", - "tint" - ], - "icon": "schedule" - }, - { - "section": "blurEnabled", - "label": "Background Blur", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "alert", - "alerts", - "appearance", - "background", - "bars", - "behind", - "blur", - "colors", - "compositor", - "config", - "configuration", - "configure", - "frosted", - "glass", - "look", - "modals", - "notif", - "notifications", - "notifs", - "panel", - "popouts", - "requires", - "scheme", - "setup", - "statusbar", - "style", - "support", - "taskbar", - "theme", - "topbar", - "transparency" - ], - "icon": "blur_on", - "description": "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration." - }, - { - "section": "barElevationEnabled", - "label": "Bar Shadows", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "bar", - "bars", - "colors", - "elevation", - "look", - "m3", - "navigation", - "panel", - "panels", - "scheme", - "shadow", - "shadows", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Shadow elevation on bars and panels" - }, - { - "section": "blurBorderColor", - "label": "Blur Border Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "around", - "blur", - "blurred", - "border", - "color", - "colors", - "colour", - "edge", - "hue", - "look", - "outline", - "scheme", - "style", - "surfaces", - "theme", - "tint" - ], - "description": "Border color around blurred surfaces" - }, - { - "section": "blurBorderOpacity", - "label": "Blur Border Opacity", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "blur", - "border", - "colors", - "look", - "opacity", - "scheme", - "style", - "theme" - ] - }, - { - "section": "niriLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "focus", - "look", - "niri", - "override", - "ring", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border and focus ring" - }, - { - "section": "hyprlandLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "hyprland", - "look", - "override", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border (general.border_size)" - }, - { - "section": "mangoLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "look", - "mango", - "mangowc", - "override", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border (borderpx)" - }, - { - "section": "buttonColorMode", - "label": "Button Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "accent", - "action", - "appearance", - "button", - "buttons", - "color", - "colors", - "colour", - "hue", - "look", - "primary", - "scheme", - "style", - "theme", - "tint" - ], - "description": "Color for primary action buttons" - }, - { - "section": "colorMode", - "label": "Color Mode", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "color", - "colors", - "colour", - "dark", - "dark mode", - "day", - "hue", - "light", - "light mode", - "look", - "mode", - "night", - "scheme", - "style", - "theme", - "tint" - ], - "icon": "contrast", - "description": "Use light theme instead of dark theme" - }, - { - "section": "controlCenterTileColorMode", - "label": "Control Center Tile Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "active", - "appearance", - "background", - "button", - "center", - "color", - "colors", - "colour", - "control", - "hue", - "icon", - "look", - "scheme", - "style", - "theme", - "tile", - "tint" - ], - "description": "Active tile background and icon color" - }, - { - "section": "cornerRadius", - "label": "Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corner", - "corners", - "look", - "radius", - "round", - "rounded", - "scheme", - "square", - "style", - "theme" - ], - "description": "0 = square corners" - }, - { - "section": "cursorSize", - "label": "Cursor Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "cursor", - "look", - "mouse", - "pixels", - "pointer", - "scheme", - "size", - "style", - "theme" - ], - "description": "Mouse pointer size in pixels" - }, - { - "section": "cursorTheme", - "label": "Cursor Theme", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "cursor", - "look", - "mouse", - "pointer", - "scheme", - "size", - "style", - "theme" - ], - "icon": "mouse", - "description": "Mouse pointer appearance", - "conditionKey": "isNiri" - }, - { - "section": "matugenTemplateNeovimSettings", - "label": "Dark mode base", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "base", - "colors", - "colour", - "dark", - "dark mode", - "derive", - "look", - "matugen", - "mode", - "neovim", - "night", - "scheme", - "style", - "template", - "terminal", - "theme" - ], - "description": "Base to derive dark theme from" - }, - { - "section": "modalDarkenBackground", - "label": "Darken Modal Background", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "background", - "behind", - "colors", - "dark mode", - "darken", - "darkened", - "dialogs", - "look", - "modal", - "night", - "overlay", - "scheme", - "show", - "style", - "theme" - ], - "description": "Show darkened overlay behind modal dialogs" - }, - { - "section": "matugenTemplateEmacs", - "label": "Emacs", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "emacs", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateFirefox", - "label": "Firefox", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "firefox", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateNeovimSetBackground", - "label": "Follow DMS background color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "background", - "color", - "colors", - "colour", - "dms", - "follow", - "hue", - "look", - "matugen", - "neovim", - "scheme", - "style", - "template", - "terminal", - "theme", - "tint" - ] - }, - { - "section": "matugenTemplateGtk", - "label": "GTK", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "gtk", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateGhostty", - "label": "Ghostty", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "ghostty", - "look", - "matugen", - "scheme", - "style", - "template", - "terminal", - "theme" - ] - }, - { - "section": "cursorHideWhenTyping", - "label": "Hide When Typing", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "cursor", - "hide", - "keyboard", - "keys", - "look", - "pressing", - "scheme", - "style", - "theme", - "typing" - ], - "description": "Hide cursor when pressing keyboard keys", - "conditionKey": "isNiri" - }, - { - "section": "cursorHideOnTouch", - "label": "Hide on Touch", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "cursor", - "hide", - "input", - "look", - "scheme", - "style", - "theme", - "touch" - ], - "description": "Hide cursor when using touch input", - "conditionKey": "isHyprland" - }, - { - "section": "matugenTemplateHyprland", - "label": "Hyprland", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "hyprland", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "hyprlandLayout", - "label": "Hyprland Layout Overrides", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "gap", - "gaps", - "hyprland", - "layout", - "look", - "margin", - "margins", - "overrides", - "padding", - "panel", - "radius", - "rounding", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isHyprland" - }, - { - "section": "iconTheme", - "label": "Icon Theme", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "dankshell", - "icon", - "icons", - "look", - "scheme", - "style", - "system", - "theme" - ], - "icon": "interests", - "description": "DankShell & System Icons (requires restart)" - }, - { - "section": "matugenTemplateKcolorscheme", - "label": "KColorScheme", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "colours", - "hue", - "kcolorscheme", - "kde", - "look", - "matugen", - "palette", - "scheme", - "style", - "template", - "theme", - "tint" - ] - }, - { - "section": "m3ElevationLightDirection", - "label": "Light Direction", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "advanced", - "appearance", - "cast", - "colors", - "controls", - "day", - "direction", - "elevation", - "layers", - "light", - "light mode", - "look", - "m3", - "scheme", - "shadow", - "style", - "theme" - ], - "description": "Controls shadow cast direction for elevation layers" - }, - { - "section": "isLightMode", - "label": "Light Mode", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "dark", - "dark mode", - "day", - "light", - "light mode", - "look", - "mode", - "night", - "scheme", - "style", - "theme" - ], - "description": "Use light theme instead of dark theme" - }, - { - "section": "mangoLayout", - "label": "MangoWC Layout Overrides", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "dwl", - "gap", - "gaps", - "layout", - "look", - "mango", - "mangowc", - "margin", - "margins", - "overrides", - "padding", - "panel", - "radius", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isDwl" - }, - { - "section": "matugenContrast", - "label": "Matugen Contrast", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "adjusts", - "appearance", - "colors", - "colour", - "colours", - "contrast", - "dynamic", - "generated", - "hue", - "look", - "material", - "matugen", - "minimum", - "palette", - "scheme", - "standard", - "style", - "theme", - "tint", - "wallpaper colors" - ], - "description": "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)" - }, - { - "section": "matugenScheme", - "label": "Matugen Palette", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "algorithm", - "appearance", - "background", - "based", - "bg", - "colors", - "colour", - "colours", - "desktop", - "dynamic", - "hue", - "image", - "look", - "material", - "matugen", - "palette", - "picture", - "scheme", - "select", - "style", - "theme", - "tint", - "wallpaper", - "wallpaper colors" - ], - "description": "Select the palette algorithm used for wallpaper-based colors" - }, - { - "section": "matugenTemplates", - "label": "Matugen Templates", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dynamic", - "look", - "material", - "matugen", - "scheme", - "style", - "templates", - "theme", - "theming", - "wallpaper colors" - ], - "icon": "auto_awesome", - "conditionKey": "matugenAvailable" - }, - { - "section": "modalBackground", - "label": "Modal Background", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "background", - "behind", - "colors", - "dark mode", - "darken", - "darkened", - "dialogs", - "look", - "modal", - "night", - "overlay", - "scheme", - "show", - "style", - "theme" - ], - "icon": "layers", - "description": "Show darkened overlay behind modal dialogs" - }, - { - "section": "modalElevationEnabled", - "label": "Modal Shadows", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dialog", - "dialogs", - "elevation", - "look", - "m3", - "modal", - "modals", - "scheme", - "shadow", - "shadows", - "style", - "theme" - ], - "description": "Shadow elevation on modals and dialogs" - }, - { - "section": "niriLayout", - "label": "Niri Layout Overrides", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "gap", - "gaps", - "layout", - "look", - "margin", - "margins", - "niri", - "overrides", - "padding", - "panel", - "radius", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isNiri" - }, - { - "section": "niriLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "focus", - "look", - "niri", - "override", - "ring", - "scheme", - "size", - "style", - "theme", - "width" - ], - "description": "Use custom border/focus-ring width" - }, - { - "section": "hyprlandLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "hyprland", - "look", - "override", - "scheme", - "size", - "style", - "theme" - ], - "description": "Use custom border size" - }, - { - "section": "mangoLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "look", - "mango", - "mangowc", - "override", - "scheme", - "size", - "style", - "theme" - ], - "description": "Use custom border size" - }, - { - "section": "niriLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "look", - "niri", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window" - ], - "description": "Use custom window radius instead of theme radius" - }, - { - "section": "hyprlandLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "hyprland", - "look", - "override", - "radius", - "round", - "rounded", - "rounding", - "scheme", - "style", - "theme", - "window" - ], - "description": "Use custom window rounding instead of theme radius" - }, - { - "section": "mangoLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "look", - "mango", - "mangowc", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window" - ], - "description": "Use custom window radius instead of theme radius" - }, - { - "section": "niriLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "look", - "margin", - "margins", - "niri", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" - }, - { - "section": "hyprlandLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "hyprland", - "look", - "margin", - "margins", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" - }, - { - "section": "mangoLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "look", - "mango", - "mangowc", - "margin", - "margins", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" - }, - { - "section": "popoutElevationEnabled", - "label": "Popout Shadows", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dropdown", - "dropdowns", - "elevation", - "look", - "m3", - "osd", - "osds", - "popout", - "popouts", - "popup", - "scheme", - "shadow", - "shadows", - "style", - "theme" - ], - "description": "Shadow elevation on popouts, OSDs, and dropdowns" - }, - { - "section": "popupTransparency", - "label": "Popup Transparency", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "alpha", - "appearance", - "colors", - "content", - "controls", - "layers", - "look", - "modal", - "modals", - "opacity", - "popouts", - "popup", - "scheme", - "style", - "their", - "theme", - "translucent", - "transparency", - "transparent" - ], - "description": "Controls opacity of all popouts, modals, and their content layers" - }, - { - "section": "runDmsMatugenTemplates", - "label": "Run DMS Templates", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dms", - "look", - "matugen", - "run", - "scheme", - "style", - "templates", - "theme" - ] - }, - { - "section": "runUserMatugenTemplates", - "label": "Run User Templates", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "run", - "scheme", - "style", - "templates", - "theme", - "user" - ] - }, - { - "section": "m3ElevationColorMode", - "label": "Shadow Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "applied", - "base", - "color", - "colors", - "colour", - "elevation", - "hue", - "look", - "m3", - "scheme", - "shadow", - "shadows", - "style", - "theme", - "tint" - ], - "description": "Base color for shadows (opacity is applied automatically)" - }, - { - "section": "m3ElevationIntensity", - "label": "Shadow Intensity", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "base", - "blur", - "colors", - "controls", - "elevation", - "intensity", - "look", - "m3", - "offset", - "radius", - "scheme", - "shadow", - "shadows", - "style", - "theme" - ], - "description": "Controls the base blur radius and offset of shadows" - }, - { - "section": "m3ElevationOpacity", - "label": "Shadow Opacity", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "alpha", - "appearance", - "colors", - "controls", - "elevation", - "look", - "m3", - "opacity", - "scheme", - "shadow", - "style", - "theme", - "translucent", - "transparency", - "transparent" - ], - "description": "Controls the transparency of the shadow" - }, - { - "section": "m3ElevationEnabled", - "label": "Shadows", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dialogs", - "elevation", - "inspired", - "lift", - "look", - "m3", - "material", - "modals", - "popouts", - "scheme", - "shadow", - "shadows", - "style", - "theme" - ], - "description": "Material inspired shadows and elevation on modals, popouts, and dialogs" - }, - { - "section": "syncModeWithPortal", - "label": "Sync Mode with Portal", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "dark", - "dark mode", - "hints", - "look", - "mode", - "night", - "portal", - "portals", - "scheme", - "settings", - "style", - "sync", - "system", - "theme", - "wide" - ], - "description": "Sync dark mode with settings portals for system-wide theme hints" - }, - { - "section": "systemAppTheming", - "label": "System App Theming", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "app", - "appearance", - "colors", - "gtk", - "look", - "qt", - "scheme", - "style", - "system", - "theme", - "theming" - ], - "icon": "brush", - "conditionKey": "matugenAvailable" - }, - { - "section": "terminalsAlwaysDark", - "label": "Terminals - Always use Dark Theme", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "always", - "app", - "appearance", - "applications", - "apps", - "color", - "colors", - "colour", - "dark", - "dark mode", - "force", - "hue", - "look", - "night", - "program", - "programs", - "scheme", - "schemes", - "style", - "terminal", - "terminals", - "theme", - "tint" - ], - "description": "Force terminal applications to always use dark color schemes" - }, - { - "section": "_tab_10", - "label": "Theme & Colors", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "colours", - "hue", - "look", - "palette", - "scheme", - "style", - "theme", - "tint" - ], - "icon": "format_paint" - }, - { - "section": "themeColor", - "label": "Theme Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "algorithm", - "appearance", - "background", - "based", - "bg", - "color", - "colors", - "colour", - "colours", - "desktop", - "hue", - "image", - "look", - "palette", - "picture", - "scheme", - "select", - "style", - "theme", - "tint", - "wallpaper" - ], - "icon": "palette", - "description": "Select the palette algorithm used for wallpaper-based colors" - }, - { - "section": "matugenTemplateVscode", - "label": "VS Code", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "code", - "colors", - "look", - "matugen", - "scheme", - "style", - "template", - "theme", - "vscode" - ] - }, - { - "section": "matugenTemplateWezterm", - "label": "WezTerm", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "scheme", - "style", - "template", - "terminal", - "theme", - "wezterm" - ] - }, - { - "section": "widgetBackgroundColor", - "label": "Widget Background Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "background", - "choose", - "color", - "colors", - "colour", - "components", - "hue", - "look", - "modules", - "scheme", - "style", - "theme", - "tint", - "widget", - "widgets" - ], - "description": "Choose the background color for widgets" - }, - { - "section": "widgetColorMode", - "label": "Widget Style", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "change", - "colorful", - "colors", - "default", - "look", - "panel", - "scheme", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "widget" - ], - "description": "Change bar appearance" - }, - { - "section": "widgetStyling", - "label": "Widget Styling", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "change", - "colors", - "look", - "opacity", - "panel", - "scheme", - "statusbar", - "style", - "styling", - "taskbar", - "theme", - "topbar", - "transparency", - "widget" - ], - "icon": "opacity", - "description": "Change bar appearance" - }, - { - "section": "niriLayoutRadiusOverride", - "label": "Window Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corner", - "corners", - "look", - "niri", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows" - }, - { - "section": "mangoLayoutRadiusOverride", - "label": "Window Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corner", - "corners", - "look", - "mango", - "mangowc", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows (border_radius)" - }, - { - "section": "niriLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gaps", - "look", - "niri", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows" - }, - { - "section": "hyprlandLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gaps", - "hyprland", - "look", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows (gaps_in and gaps_out)" - }, - { - "section": "mangoLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gappiv", - "gappoh", - "gaps", - "look", - "mango", - "mangowc", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows (gappih/gappiv/gappoh/gappov)" - }, - { - "section": "hyprlandLayoutRadiusOverride", - "label": "Window Rounding", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corners", - "hyprland", - "look", - "override", - "radius", - "round", - "rounded", - "rounding", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows (decoration.rounding)" - }, - { - "section": "matugenTemplateZed", - "label": "Zed", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "scheme", - "style", - "template", - "theme", - "zed" - ] - }, - { - "section": "matugenTemplateDgop", - "label": "dgop", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "dgop", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateEquibop", - "label": "equibop", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "discord", - "equibop", - "look", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateFoot", - "label": "foot", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "foot", - "look", - "matugen", - "scheme", - "style", - "template", - "terminal", - "theme" - ] - }, - { - "section": "matugenTemplateKitty", - "label": "kitty", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "kitty", - "look", - "matugen", - "scheme", - "style", - "template", - "terminal", - "theme" - ] - }, - { - "section": "matugenTemplateMangowc", - "label": "mangowc", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "mangowc", - "matugen", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateNeovim", - "label": "neovim", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "neovim", - "required", - "scheme", - "style", - "template", - "terminal", - "theme" - ], - "description": "Required plugin: " - }, - { - "section": "matugenTemplateNiri", - "label": "niri", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "niri", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplatePywalfox", - "label": "pywalfox", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "pywalfox", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateQt5ct", - "label": "qt5ct", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "qt5ct", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateQt6ct", - "label": "qt6ct", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "qt6ct", - "scheme", - "style", - "template", - "theme" - ] - }, - { - "section": "matugenTemplateVesktop", - "label": "vesktop", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "discord", - "look", - "matugen", - "scheme", - "style", - "template", - "theme", - "vesktop" - ] - }, - { - "section": "matugenTemplateZenBrowser", - "label": "zenbrowser", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "look", - "matugen", - "scheme", - "style", - "template", - "theme", - "zenbrowser" - ] - }, - { - "section": "lockScreenActiveMonitor", - "label": "Active Lock Screen Monitor", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "active", - "display", - "lock", - "lockscreen", - "login", - "monitor", - "password", - "screen", - "security" - ] - }, - { - "section": "lockScreenVideoCycling", - "label": "Automatic Cycling", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "automatic", - "cycling", - "different", - "folder", - "lock", - "login", - "password", - "pick", - "random", - "same", - "screen", - "screensaver", - "security", - "shuffle", - "time", - "video" - ], - "description": "Pick a different random video each time from the same folder" - }, - { - "section": "lockScreenVideoEnabled", - "label": "Enable Video Screensaver", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "animation", - "enable", - "lock", - "locks", - "login", - "movie", - "password", - "play", - "screen", - "screensaver", - "security", - "video" - ], - "description": "Play a video when the screen locks." - }, - { - "section": "enableFprint", - "label": "Enable fingerprint authentication", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "authentication", - "biometric", - "enable", - "fingerprint", - "fprint", - "lock", - "login", - "password", - "screen", - "security" - ] - }, - { - "section": "loginctlLockIntegration", - "label": "Enable loginctl lock integration", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "bind", - "dbus", - "disable", - "enable", - "external", - "integration", - "lock", - "lockscreen", - "login", - "loginctl", - "password", - "screen", - "security", - "signals" - ], - "description": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen" - }, - { - "section": "enableU2f", - "label": "Enable security key authentication", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "authentication", - "enable", - "fido", - "hardware", - "key", - "lock", - "login", - "password", - "screen", - "security", - "u2f", - "yubikey" - ] - }, - { - "section": "lockDisplay", - "label": "Lock Screen Display", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "active", - "display", - "lock", - "lockscreen", - "login", - "monitor", - "output", - "password", - "screen", - "security" - ], - "icon": "monitor" - }, - { - "section": "lockBehavior", - "label": "Lock Screen behaviour", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "behaviour", - "bind", - "dbus", - "disable", - "external", - "integration", - "lock", - "lockscreen", - "login", - "loginctl", - "password", - "screen", - "security", - "signals" - ], - "icon": "lock", - "description": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen" - }, - { - "section": "lockLayout", - "label": "Lock Screen layout", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "actions", - "appear", - "field", - "hidden", - "layout", - "lock", - "lockscreen", - "login", - "password", - "power", - "pressed", - "reboot", - "screen", - "security", - "shutdown", - "soon" - ], - "icon": "lock", - "description": "If the field is hidden, it will appear as soon as a key is pressed." - }, - { - "section": "lockAtStartup", - "label": "Lock at startup", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "automatic", - "automatically", - "boot", - "lock", - "login", - "password", - "screen", - "security", - "start", - "starts", - "startup" - ], - "description": "Automatically lock the screen when DMS starts" - }, - { - "section": "lockScreenNotificationMode", - "label": "Notification Display", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "alert", - "control", - "display", - "information", - "lock", - "lockscreen", - "login", - "monitor", - "notif", - "notification", - "notifications", - "output", - "password", - "privacy", - "screen", - "security", - "shown", - "what" - ], - "description": "Control what notification information is shown on the lock screen" - }, - { - "section": "_tab_11", - "label": "Power & Security", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "hibernate", - "lock", - "login", - "password", - "power", - "reboot", - "restart", - "screen", - "security", - "shutdown", - "sleep", - "suspend" - ], - "icon": "security" - }, - { - "section": "lockScreenPowerOffMonitorsOnLock", - "label": "Power off monitors on lock", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "activates", - "display", - "displays", - "dpms", - "hibernate", - "immediately", - "lock", - "lockscreen", - "login", - "monitor", - "monitors", - "off", - "output", - "outputs", - "password", - "power", - "reboot", - "restart", - "screen", - "screens", - "security", - "shutdown", - "sleep", - "suspend", - "turn" - ], - "description": "Turn off all displays immediately when the lock screen activates" - }, - { - "section": "u2fMode", - "label": "Security key mode", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "factor", - "key", - "lock", - "login", - "mode", - "password", - "screen", - "second", - "security", - "u2f", - "yubikey" - ] - }, - { - "section": "lockScreenShowMediaPlayer", - "label": "Show Media Player", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "audio", - "lock", - "login", - "media", - "mpris", - "music", - "password", - "playback", - "player", - "screen", - "security", - "show" - ] - }, - { - "section": "lockScreenShowPasswordField", - "label": "Show Password Field", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "appear", - "field", - "hidden", - "input", - "lock", - "login", - "password", - "pressed", - "screen", - "security", - "show", - "soon", - "visible" - ], - "description": "If the field is hidden, it will appear as soon as a key is pressed." - }, - { - "section": "lockScreenShowPowerActions", - "label": "Show Power Actions", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "actions", - "hibernate", - "lock", - "login", - "password", - "power", - "reboot", - "restart", - "screen", - "security", - "show", - "shutdown", - "sleep", - "suspend" - ] - }, - { - "section": "lockScreenShowProfileImage", - "label": "Show Profile Image", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "avatar", - "image", - "lock", - "login", - "password", - "picture", - "profile", - "screen", - "security", - "show" - ] - }, - { - "section": "lockScreenShowDate", - "label": "Show System Date", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "calendar", - "date", - "display", - "lock", - "login", - "password", - "screen", - "security", - "show", - "system" - ] - }, - { - "section": "lockScreenShowSystemIcons", - "label": "Show System Icons", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "icons", - "lock", - "login", - "password", - "screen", - "security", - "show", - "status", - "system" - ] - }, - { - "section": "lockScreenShowTime", - "label": "Show System Time", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "clock", - "display", - "lock", - "login", - "password", - "screen", - "security", - "show", - "system", - "time" - ] - }, - { - "section": "videoScreensaver", - "label": "Video Screensaver", - "tabIndex": 11, - "category": "Lock Screen", - "keywords": [ - "animation", - "lock", - "locks", - "login", - "movie", - "password", - "play", - "screen", - "screensaver", - "security", - "video" - ], - "icon": "movie", - "description": "Play a video when the screen locks." - }, - { - "section": "_tab_12", - "label": "Plugins", - "tabIndex": 12, - "category": "Plugins", - "keywords": [ - "addon", - "addons", - "extend", - "extensions", - "plugins", - "widgets" - ], - "icon": "extension" - }, - { - "section": "_tab_13", - "label": "About", - "tabIndex": 13, - "category": "About", - "keywords": [ - "about", - "credits", - "help", - "info", - "version" - ], - "icon": "info" - }, - { - "section": "popoutAnimationSpeed", - "label": "%1 Animation Speed", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "custom", - "duration", - "fonts", - "motion", - "popout", - "speed", - "sync", - "text", - "transition", - "typography" - ], - "icon": "open_in_new", - "description": "%1 custom animation duration" - }, - { - "section": "modalAnimationSpeed", - "label": "%1 Animation Speed", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "custom", - "duration", - "fonts", - "modal", - "motion", - "speed", - "sync", - "text", - "transition", - "typography" - ], - "icon": "web_asset", - "description": "%1 custom animation duration" - }, - { - "section": "customAnimationDuration", - "label": "Animation Duration", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "custom", - "duration", - "durations", - "fonts", - "globally", - "motion", - "scale", - "speed", - "text", - "transition", - "typography" - ], - "description": "Globally scale all animation durations" - }, - { - "section": "animationSpeed", - "label": "Animation Speed", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "duration", - "durations", - "fonts", - "globally", - "motion", - "scale", - "speed", - "text", - "transition", - "typography" - ], - "icon": "animation", - "description": "Globally scale all animation durations" - }, - { - "section": "popoutCustomAnimationDuration", - "label": "Custom Duration", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "custom", - "duration", - "fonts", - "motion", - "popout", - "speed", - "text", - "transition", - "typography" - ], - "description": "%1 custom animation duration" - }, - { - "section": "modalCustomAnimationDuration", - "label": "Custom Duration", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "custom", - "duration", - "fonts", - "modal", - "motion", - "speed", - "text", - "transition", - "typography" - ], - "description": "%1 custom animation duration" - }, - { - "section": "fontScale", - "label": "Font Scale", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "font", - "fonts", - "motion", - "scale", - "shell", - "size", - "sizes", - "text", - "throughout", - "typography", - "zoom" - ], - "description": "Scale all font sizes throughout the shell" - }, - { - "section": "fontWeight", - "label": "Font Weight", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "bold", - "font", - "fonts", - "light", - "motion", - "select", - "text", - "typography", - "weight" - ], - "description": "Select font weight for UI text" - }, - { - "section": "monoFontFamily", - "label": "Monospace Font", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "code", - "displays", - "font", - "fonts", - "list", - "monitor", - "monitors", - "monospace", - "motion", - "output", - "outputs", - "process", - "screen", - "screens", - "select", - "technical", - "terminal", - "text", - "typography" - ], - "description": "Select monospace font for process list and technical displays" - }, - { - "section": "fontFamily", - "label": "Normal Font", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "family", - "font", - "fonts", - "motion", - "normal", - "select", - "text", - "typography" - ], - "description": "Select the font family for UI text" - }, - { - "section": "enableRippleEffects", - "label": "Ripple Effects", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "design", - "effect", - "effects", - "elements", - "feedback", - "fonts", - "interactive", - "material", - "motion", - "ripple", - "show", - "text", - "transition", - "typography" - ], - "icon": "radio_button_unchecked", - "description": "Show Material Design ripple animations on interactive elements" - }, - { - "section": "syncComponentAnimationSpeeds", - "label": "Sync Popouts & Modals", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animate", - "animation", - "animations", - "customize", - "follow", - "fonts", - "global", - "modal", - "modals", - "motion", - "popout", - "popouts", - "speed", - "sync", - "text", - "transition", - "typography" - ], - "description": "Popouts and Modals follow global Animation Speed (disable to customize independently)" - }, - { - "section": "typography", - "label": "Typography", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "family", - "font", - "fonts", - "motion", - "select", - "text", - "typeface", - "typography" - ], - "icon": "text_fields", - "description": "Select the font family for UI text" - }, - { - "section": "_tab_14", - "label": "Typography & Motion", - "tabIndex": 14, - "category": "Typography & Motion", - "keywords": [ - "animation", - "font", - "fonts", - "motion", - "text", - "typeface", - "typography" - ], - "icon": "text_fields" - }, - { - "section": "soundsEnabled", - "label": "Enable System Sounds", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "audio", - "effects", - "enable", - "events", - "play", - "sfx", - "sound", - "sounds", - "system" - ], - "description": "Play sounds for system events" - }, - { - "section": "soundLogin", - "label": "Login", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "after", - "audio", - "boot", - "effects", - "logging", - "login", - "play", - "sfx", - "sound", - "sounds", - "startup" - ], - "description": "Play sound after logging in" - }, - { - "section": "soundNewNotification", - "label": "New Notification", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "alert", - "arrives", - "audio", - "effects", - "new", - "notif", - "notification", - "play", - "sfx", - "sound", - "sounds" - ], - "description": "Play sound when new notification arrives" - }, - { - "section": "soundPluggedIn", - "label": "Plugged In", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "audio", - "cable", - "connected", - "effects", - "hibernate", - "play", - "plugged", - "power", - "reboot", - "restart", - "sfx", - "shutdown", - "sleep", - "sound", - "sounds", - "suspend" - ], - "description": "Play sound when power cable is connected" - }, - { - "section": "soundTheme", - "label": "Sound Theme", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "appearance", - "audio", - "colors", - "colour", - "effects", - "look", - "select", - "sfx", - "sound", - "sounds", - "style", - "system", - "theme" - ], - "description": "Select system sound theme" - }, - { - "section": "_tab_15", - "label": "Sounds", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "audio", - "effects", - "sfx", - "sounds" - ], - "icon": "volume_up", - "conditionKey": "soundsAvailable" - }, - { - "section": "systemSounds", - "label": "System Sounds", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "audio", - "effects", - "events", - "notification", - "play", - "sfx", - "sound", - "sounds", - "system", - "volume" - ], - "description": "Play sounds for system events", - "conditionKey": "soundsAvailable" - }, - { - "section": "useSystemSoundTheme", - "label": "Use System Theme", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "appearance", - "audio", - "colors", - "colour", - "effects", - "look", - "settings", - "sfx", - "sound", - "sounds", - "style", - "system", - "theme" - ], - "description": "Use sound theme from system settings" - }, - { - "section": "soundVolumeChanged", - "label": "Volume Changed", - "tabIndex": 15, - "category": "Sounds", - "keywords": [ - "adjusted", - "audio", - "changed", - "effects", - "loudness", - "play", - "sfx", - "sound", - "sounds", - "speaker", - "volume" - ], - "description": "Play sound when volume is adjusted" - }, - { - "section": "_tab_16", - "label": "Media Player", - "tabIndex": 16, - "category": "Media Player", - "keywords": [ - "audio", - "media", - "mpris", - "music", - "playback", - "player", - "spotify" - ], - "icon": "music_note" - }, - { - "section": "mediaPlayer", - "label": "Media Player Settings", - "tabIndex": 16, - "category": "Media Player", - "keywords": [ - "animated", - "audio", - "bars", - "media", - "mpris", - "music", - "panel", - "playback", - "player", - "progress", - "scroll", - "settings", - "spotify", - "statusbar", - "taskbar", - "topbar", - "wave" - ], - "icon": "music_note", - "description": "Use animated wave progress bars for media playback" - }, - { - "section": "audioScrollMode", - "label": "Scroll Wheel", - "tabIndex": 16, - "category": "Media Player", - "keywords": [ - "behavior", - "media", - "mpris", - "music", - "player", - "scroll", - "spotify", - "wheel", - "widget" - ], - "description": "Scroll wheel behavior on media widget" - }, - { - "section": "notificationCompactMode", - "label": "Compact", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "cards", - "compact", - "display", - "messages", - "mode", - "notif", - "notification", - "notifications", - "size", - "smaller", - "toast" - ], - "description": "Use smaller notification cards" - }, - { - "section": "notificationHistorySaveCritical", - "label": "Critical Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "critical", - "history", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "save", - "toast" - ], - "description": "Save critical priority notifications to history" - }, - { - "section": "notificationTimeoutCritical", - "label": "Critical Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "critical", - "duration", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "timeout", - "toast" - ], - "description": "Timeout for critical priority notifications" - }, - { - "section": "doNotDisturb", - "label": "Do Not Disturb", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "disturb", - "dnd", - "enabled", - "messages", - "mute", - "not", - "notif", - "notification", - "notifications", - "popups", - "silent", - "suppress", - "toast", - "while" - ], - "icon": "notifications_off", - "description": "Suppress notification popups while enabled" - }, - { - "section": "notificationCustomAnimationDuration", - "label": "Duration", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alerts", - "animate", - "animation", - "animations", - "base", - "custom", - "duration", - "messages", - "motion", - "notification", - "notifications", - "speed", - "toast", - "transition" - ], - "description": "Base duration for animations (drag to use Custom)" - }, - { - "section": "notificationHistoryEnabled", - "label": "Enable History", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "disable", - "dismissed", - "enable", - "history", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "save", - "toast" - ], - "description": "Save dismissed notifications to history" - }, - { - "section": "notificationFocusedMonitor", - "label": "Focused Monitor Only", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "active", - "alert", - "alerts", - "currently", - "display", - "focused", - "messages", - "monitor", - "notif", - "notification", - "notifications", - "popup", - "popups", - "screen", - "show", - "toast" - ], - "description": "Show notification popups only on the currently focused monitor" - }, - { - "section": "notificationHistoryMaxAgeDays", - "label": "History Retention", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "age", - "alert", - "alerts", - "auto", - "days", - "delete", - "history", - "max", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "older", - "retention", - "toast" - ], - "description": "Auto-delete notifications older than this" - }, - { - "section": "notificationHistory", - "label": "History Settings", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "disable", - "dismissed", - "enable", - "history", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "save", - "settings", - "toast" - ], - "icon": "history", - "description": "Save dismissed notifications to history" - }, - { - "section": "lockScreenNotifications", - "label": "Lock Screen", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "control", - "information", - "lock", - "lockscreen", - "login", - "messages", - "notif", - "notification", - "notifications", - "privacy", - "screen", - "security", - "shown", - "toast", - "what" - ], - "icon": "lock", - "description": "Control what notification information is shown on the lock screen" - }, - { - "section": "notificationHistorySaveLow", - "label": "Low Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "history", - "low", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "save", - "toast" - ], - "description": "Save low priority notifications to history" - }, - { - "section": "notificationTimeoutLow", - "label": "Low Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "duration", - "low", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "timeout", - "toast" - ], - "description": "Timeout for low priority notifications" - }, - { - "section": "notificationHistoryMaxCount", - "label": "Maximum History", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "count", - "history", - "keep", - "limit", - "max", - "maximum", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "number", - "toast" - ], - "description": "Maximum number of notifications to keep" - }, - { - "section": "mutedApps", - "label": "Muted Apps", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alerts", - "apps", - "messages", - "mute", - "muted", - "notification", - "notifications", - "popup", - "toast", - "unmute" - ], - "icon": "volume_off" - }, - { - "section": "notificationHistorySaveNormal", - "label": "Normal Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "history", - "messages", - "normal", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "save", - "toast" - ], - "description": "Save normal priority notifications to history" - }, - { - "section": "notificationTimeoutNormal", - "label": "Normal Priority", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "duration", - "messages", - "normal", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "timeout", - "toast" - ], - "description": "Timeout for normal priority notifications" - }, - { - "section": "notificationOverlayEnabled", - "label": "Notification Overlay", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "apps", - "display", - "fullscreen", - "messages", - "monitor", - "notif", - "notification", - "notifications", - "output", - "over", - "overlay", - "priorities", - "priority", - "screen", - "toast" - ], - "description": "Display all priorities over fullscreen apps" - }, - { - "section": "notificationPopups", - "label": "Notification Popups", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "appear", - "choose", - "location", - "messages", - "notif", - "notification", - "notifications", - "popup", - "popups", - "position", - "screen", - "toast", - "where" - ], - "icon": "notifications", - "description": "Choose where notification popups appear on screen" - }, - { - "section": "notificationRules", - "label": "Notification Rules", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "history", - "ignore", - "messages", - "mute", - "notif", - "notification", - "notifications", - "priority", - "regex", - "rules", - "toast" - ], - "icon": "rule_settings" - }, - { - "section": "notificationTimeouts", - "label": "Notification Timeouts", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "duration", - "low", - "messages", - "notif", - "notification", - "notifications", - "notifs", - "priority", - "timeout", - "timeouts", - "toast" - ], - "icon": "timer", - "description": "Timeout for low priority notifications" - }, - { - "section": "_tab_17", - "label": "Notifications", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "messages", - "notif", - "notifications", - "notifs", - "toast" - ], - "icon": "notifications" - }, - { - "section": "notificationPopupPosition", - "label": "Popup Position", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "appear", - "choose", - "location", - "messages", - "notif", - "notification", - "notifications", - "popup", - "popups", - "position", - "screen", - "toast", - "where" - ], - "description": "Choose where notification popups appear on screen" - }, - { - "section": "notificationPopupShadowEnabled", - "label": "Popup Shadow", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "appearance", - "colors", - "colour", - "colours", - "drop", - "elevation", - "enabled", - "hue", - "look", - "messages", - "notif", - "notification", - "notifications", - "palette", - "popup", - "popups", - "radius", - "requires", - "rounded", - "shadow", - "show", - "style", - "theme", - "tint", - "toast" - ], - "description": "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors." - }, - { - "section": "notificationPopupPrivacyMode", - "label": "Privacy Mode", - "tabIndex": 17, - "category": "Notifications", - "keywords": [ - "alert", - "alerts", - "body", - "collapsed", - "content", - "default", - "hide", - "messages", - "mode", - "notif", - "notification", - "notifications", - "popup", - "popups", - "privacy", - "show", - "toast", - "until" - ], - "description": "Hide notification content until expanded; popups show collapsed by default" - }, - { - "section": "osdAlwaysShowValue", - "label": "Always Show Percentage", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "always", - "audio", - "backlight", - "bright", - "brightness", - "dim", - "display", - "displays", - "indicator", - "loudness", - "monitor", - "osd", - "output", - "percentage", - "popup", - "popups", - "screen", - "show", - "sound", - "speaker", - "values", - "volume" - ], - "description": "Display volume and brightness percentage values in OSD popups" - }, - { - "section": "osdAudioOutputEnabled", - "label": "Audio Output Switch", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "audio", - "cycling", - "devices", - "display", - "displays", - "indicator", - "monitor", - "osd", - "output", - "popup", - "screen", - "show", - "switch" - ], - "description": "Show on-screen display when cycling audio output devices" - }, - { - "section": "osdBrightnessEnabled", - "label": "Brightness", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "backlight", - "bright", - "brightness", - "changes", - "dim", - "display", - "displays", - "indicator", - "monitor", - "osd", - "output", - "popup", - "screen", - "show" - ], - "description": "Show on-screen display when brightness changes" - }, - { - "section": "osdCapsLockEnabled", - "label": "Caps Lock", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "caps", - "changes", - "display", - "displays", - "indicator", - "lock", - "monitor", - "osd", - "output", - "popup", - "screen", - "show", - "state" - ], - "description": "Show on-screen display when caps lock state changes" - }, - { - "section": "osdIdleInhibitorEnabled", - "label": "Idle Inhibitor", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "afk", - "changes", - "display", - "displays", - "idle", - "inactive", - "indicator", - "inhibitor", - "monitor", - "osd", - "output", - "popup", - "screen", - "screensaver", - "show", - "state", - "timeout" - ], - "description": "Show on-screen display when idle inhibitor state changes" - }, - { - "section": "osdMediaPlaybackEnabled", - "label": "Media Playback", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "audio", - "changes", - "display", - "displays", - "indicator", - "media", - "monitor", - "mpris", - "music", - "osd", - "output", - "playback", - "player", - "popup", - "screen", - "show", - "status" - ], - "description": "Show on-screen display when media player status changes" - }, - { - "section": "osdMediaVolumeEnabled", - "label": "Media Volume", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "audio", - "changes", - "display", - "displays", - "indicator", - "loudness", - "media", - "monitor", - "mpris", - "music", - "osd", - "output", - "playback", - "player", - "popup", - "screen", - "show", - "sound", - "speaker", - "volume" - ], - "description": "Show on-screen display when media player volume changes" - }, - { - "section": "osdMicMuteEnabled", - "label": "Microphone Mute", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "display", - "displays", - "indicator", - "microphone", - "monitor", - "mute", - "muted", - "osd", - "output", - "popup", - "screen", - "show", - "unmuted" - ], - "description": "Show on-screen display when microphone is muted/unmuted" - }, - { - "section": "osdPosition", - "label": "OSD Position", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "appear", - "choose", - "displays", - "indicator", - "monitor", - "monitors", - "osd", - "output", - "outputs", - "popup", - "position", - "screen", - "screens", - "where" - ], - "description": "Choose where on-screen displays appear on screen" - }, - { - "section": "_tab_18", - "label": "On-screen Displays", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "displays", - "indicator", - "monitor", - "monitors", - "osd", - "output", - "outputs", - "popup", - "screen", - "screens" - ], - "icon": "tune" - }, - { - "section": "osd", - "label": "On-screen Displays", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "appear", - "choose", - "displays", - "indicator", - "monitor", - "monitors", - "osd", - "output", - "outputs", - "popup", - "screen", - "screens", - "where" - ], - "icon": "tune", - "description": "Choose where on-screen displays appear on screen" - }, - { - "section": "osdPowerProfileEnabled", - "label": "Power Profile", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "changes", - "display", - "displays", - "hibernate", - "indicator", - "monitor", - "osd", - "output", - "popup", - "power", - "profile", - "reboot", - "restart", - "screen", - "show", - "shutdown", - "sleep", - "suspend" - ], - "description": "Show on-screen display when power profile changes" - }, - { - "section": "osdVolumeEnabled", - "label": "Volume", - "tabIndex": 18, - "category": "On-screen Displays", - "keywords": [ - "audio", - "changes", - "display", - "displays", - "indicator", - "loudness", - "monitor", - "osd", - "output", - "popup", - "screen", - "show", - "sound", - "speaker", - "volume" - ], - "description": "Show on-screen display when volume changes" - }, - { - "section": "appIdSubstitutions", - "label": "App ID Substitutions", - "tabIndex": 19, - "category": "Running Apps", - "keywords": [ - "active", - "app", - "apps", - "class", - "icon", - "pattern", - "regex", - "replacement", - "running", - "substitution", - "substitutions", - "tasks", - "window", - "windows" - ], - "icon": "find_replace" - }, - { - "section": "_tab_19", - "label": "Running Apps", - "tabIndex": 19, - "category": "Running Apps", - "keywords": [ - "active", - "apps", - "open", - "running", - "taskbar", - "tasks", - "windows" - ], - "icon": "app_registration", - "conditionKey": "isHyprlandOrNiri" - }, - { - "section": "_tab_20", - "label": "System Updater", - "tabIndex": 20, - "category": "System Updater", - "keywords": [ - "packages", - "system", - "updater", - "updates", - "upgrade" - ], - "icon": "refresh" - }, - { - "section": "systemUpdater", - "label": "System Updater", - "tabIndex": 20, - "category": "System Updater", - "keywords": [ - "found", - "hide", - "packages", - "system", - "update", - "updater", - "updates", - "upgrade", - "widget" - ], - "icon": "refresh", - "description": "When updater widget is used, then hide it if no update found" - }, - { - "section": "powerAdvanced", - "label": "Advanced", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actually", - "advanced", - "battery", - "changes", - "charge", - "charging", - "does", - "energy", - "limit", - "percentage", - "power", - "shutdown", - "sleep", - "suspend" - ], - "icon": "tune", - "description": "Note: this only changes the percentage, it does not actually limit charging." - }, - { - "section": "lockTimeout", - "label": "Automatically lock after", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "after", - "automatic", - "automatically", - "energy", - "idle", - "lock", - "power", - "security", - "shutdown", - "sleep", - "suspend", - "timeout" - ] - }, - { - "section": "batteryChargeLimit", - "label": "Battery Charge Limit", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actually", - "battery", - "changes", - "charge", - "charging", - "does", - "energy", - "limit", - "percentage", - "power", - "shutdown", - "sleep", - "suspend" - ], - "description": "Note: this only changes the percentage, it does not actually limit charging." - }, - { - "section": "customPowerActions", - "label": "Custom Power Actions", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actions", - "custom", - "energy", - "hibernate", - "power", - "reboot", - "restart", - "shutdown", - "sleep", - "suspend" - ], - "icon": "developer_mode" - }, - { - "section": "powerMenuDefaultAction", - "label": "Default selected action", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "action", - "default", - "energy", - "logout", - "menu", - "power", - "reboot", - "selected", - "shutdown", - "sleep", - "suspend" - ] - }, - { - "section": "fadeToLockEnabled", - "label": "Fade to lock screen", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "before", - "configurable", - "energy", - "fade", - "grace", - "grace period", - "gradually", - "idle", - "lock", - "locking", - "lockscreen", - "login", - "period", - "power", - "screen", - "security", - "shutdown", - "sleep", - "suspend" - ], - "description": "Gradually fade the screen before locking with a configurable grace period" - }, - { - "section": "fadeToDpmsEnabled", - "label": "Fade to monitor off", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "before", - "configurable", - "dpms", - "energy", - "fade", - "grace", - "grace period", - "gradually", - "idle", - "monitor", - "monitors", - "off", - "period", - "power", - "screen", - "shutdown", - "sleep", - "suspend", - "turning" - ], - "description": "Gradually fade the screen before turning off monitors with a configurable grace period" - }, - { - "section": "powerActionHoldDuration", - "label": "Hold Duration", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "confirm", - "duration", - "energy", - "hold", - "power", - "shutdown", - "sleep", - "suspend", - "time" - ] - }, - { - "section": "powerActionConfirm", - "label": "Hold to Confirm Power Actions", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actions", - "button", - "confirm", - "energy", - "hibernate", - "hold", - "holding", - "logout", - "power", - "reboot", - "require", - "restart", - "safety", - "shutdown", - "sleep", - "suspend" - ], - "description": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout" - }, - { - "section": "idleSettings", - "label": "Idle Settings", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "afk", - "before", - "configurable", - "energy", - "fade", - "grace", - "grace period", - "gradually", - "idle", - "inactive", - "lock", - "locking", - "period", - "power", - "screen", - "screensaver", - "settings", - "shutdown", - "sleep", - "suspend", - "timeout" - ], - "icon": "schedule", - "description": "Gradually fade the screen before locking with a configurable grace period" - }, - { - "section": "lockBeforeSuspend", - "label": "Lock before suspend", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "automatically", - "before", - "energy", - "lock", - "power", - "prepares", - "screen", - "security", - "shutdown", - "sleep", - "suspend", - "system" - ], - "description": "Automatically lock the screen when the system prepares to suspend" - }, - { - "section": "fadeToLockGracePeriod", - "label": "Lock fade grace period", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "energy", - "fade", - "grace", - "lock", - "period", - "power", - "shutdown", - "sleep", - "suspend", - "timeout" - ] - }, - { - "section": "fadeToDpmsGracePeriod", - "label": "Monitor fade grace period", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "dpms", - "energy", - "fade", - "grace", - "monitor", - "period", - "power", - "shutdown", - "sleep", - "suspend", - "timeout" - ] - }, - { - "section": "_tab_21", - "label": "Power & Sleep", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "energy", - "hibernate", - "power", - "reboot", - "restart", - "shutdown", - "sleep", - "suspend" - ], - "icon": "power_settings_new" - }, - { - "section": "powerConfirmation", - "label": "Power Action Confirmation", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "action", - "button", - "confirm", - "confirmation", - "energy", - "hibernate", - "hold", - "holding", - "logout", - "power", - "reboot", - "require", - "restart", - "safety", - "shutdown", - "sleep", - "suspend" - ], - "icon": "check_circle", - "description": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout" - }, - { - "section": "powerMenu", - "label": "Power Menu Customization", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actions", - "customization", - "display", - "energy", - "grid", - "hibernate", - "layout", - "list", - "menu", - "monitor", - "output", - "power", - "reboot", - "restart", - "screen", - "shutdown", - "sleep", - "suspend" - ], - "icon": "tune", - "description": "Display power menu actions in a grid instead of a list" - }, - { - "section": "suspendTimeout", - "label": "Suspend system after", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "after", - "energy", - "idle", - "power", - "shutdown", - "sleep", - "suspend", - "system", - "timeout" - ] - }, - { - "section": "powerProfile", - "label": "Switch to power profile", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "balanced", - "battery", - "energy", - "hibernate", - "performance", - "power", - "profile", - "reboot", - "restart", - "saver", - "shutdown", - "sleep", - "suspend", - "switch" - ] - }, - { - "section": "monitorTimeout", - "label": "Turn off monitors after", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "after", - "display", - "energy", - "idle", - "monitor", - "monitors", - "off", - "power", - "screen", - "shutdown", - "sleep", - "suspend", - "timeout", - "turn" - ] - }, - { - "section": "powerMenuGridLayout", - "label": "Use Grid Layout", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "actions", - "display", - "energy", - "grid", - "hibernate", - "layout", - "list", - "menu", - "monitor", - "output", - "power", - "reboot", - "restart", - "screen", - "shutdown", - "sleep", - "suspend" - ], - "description": "Display power menu actions in a grid instead of a list" - }, - { - "section": "_tab_22", - "label": "Widgets", - "tabIndex": 22, - "category": "Dank Bar", - "keywords": [ - "bar", - "components", - "dank", - "modules", - "panel", - "statusbar", - "topbar", - "widgets" - ], - "icon": "widgets" - }, - { - "section": "disabled", - "label": "Advanced", - "tabIndex": 23, - "category": "System", - "keywords": [ - "advanced", - "clipboard", - "cliphist", - "copy", - "disable", - "disk", - "history", - "linux", - "nothing", - "os", - "paste", - "saved", - "system", - "works" - ], - "icon": "tune", - "description": "Clipboard works but nothing saved to disk" - }, - { - "section": "autoClearDays", - "label": "Auto-Clear After", - "tabIndex": 23, - "category": "System", - "keywords": [ - "after", - "auto", - "automatically", - "clear", - "clipboard", - "days", - "delete", - "entries", - "linux", - "older", - "os", - "system" - ], - "description": "Automatically delete entries older than this" - }, - { - "section": "clearAtStartup", - "label": "Behavior", - "tabIndex": 23, - "category": "System", - "keywords": [ - "behavior", - "clear", - "clipboard", - "history", - "linux", - "os", - "server", - "starts", - "system" - ], - "icon": "settings", - "description": "Clear all history when server starts" - }, - { - "section": "_tab_23", - "label": "Clipboard", - "tabIndex": 23, - "category": "System", - "keywords": [ - "clipboard", - "cliphist", - "copy", - "history", - "linux", - "os", - "paste", - "system" - ], - "icon": "content_paste", - "conditionKey": "dmsConnected" - }, - { - "section": "clipboardEnterToPaste", - "label": "Enter to Paste", - "tabIndex": 23, - "category": "System", - "keywords": [ - "behavior", - "clipboard", - "copy", - "enter", - "linux", - "os", - "paste", - "press", - "system" - ], - "description": "Press Enter to paste, Shift+Enter to copy" - }, - { - "section": "maxHistory", - "label": "History Settings", - "tabIndex": 23, - "category": "System", - "keywords": [ - "clipboard", - "cliphist", - "copy", - "entries", - "history", - "keep", - "limit", - "linux", - "maximum", - "number", - "os", - "paste", - "settings", - "system" - ], - "icon": "history", - "description": "Maximum number of clipboard entries to keep" - }, - { - "section": "maxEntrySize", - "label": "Maximum Entry Size", - "tabIndex": 23, - "category": "System", - "keywords": [ - "clipboard", - "cliphist", - "copy", - "entry", - "history", - "limit", - "linux", - "maximum", - "os", - "paste", - "size", - "system" - ], - "description": "Maximum size per clipboard entry" - }, - { - "section": "maxPinned", - "label": "Maximum Pinned Entries", - "tabIndex": 23, - "category": "System", - "keywords": [ - "clipboard", - "entries", - "limit", - "linux", - "max", - "maximum", - "number", - "os", - "pinned", - "saved", - "system" - ], - "description": "Maximum number of entries that can be saved" - }, - { - "section": "_tab_24", - "label": "Displays", - "tabIndex": 24, - "category": "Displays", - "keywords": [ - "displays", - "monitor", - "monitors", - "output", - "outputs", - "resolution", - "screen", - "screens" - ], - "icon": "monitor" - }, - { - "section": "nightModeHighTemperature", - "label": "Day Temperature", - "tabIndex": 25, - "category": "Displays", - "keywords": [ - "celsius", - "color", - "colour", - "day", - "displays", - "fahrenheit", - "gamma", - "hue", - "kelvin", - "monitor", - "resolution", - "screen", - "temp", - "temperature", - "time", - "tint" - ], - "description": "Color temperature for day time" - }, - { - "section": "_tab_25", - "label": "Gamma Control", - "tabIndex": 25, - "category": "Displays", - "keywords": [ - "blue light", - "color temperature", - "control", - "displays", - "gamma", - "monitor", - "night light", - "redshift", - "resolution", - "screen" - ], - "icon": "brightness_6" - }, - { - "section": "nightModeTemperature", - "label": "Night Temperature", - "tabIndex": 25, - "category": "Displays", - "keywords": [ - "blue light", - "celsius", - "color", - "colour", - "displays", - "fahrenheit", - "gamma", - "hue", - "kelvin", - "mode", - "monitor", - "night", - "resolution", - "screen", - "temp", - "temperature", - "tint", - "warm" - ], - "description": "Color temperature for night mode" - }, - { - "section": "_tab_26", - "label": "Widgets", - "tabIndex": 26, - "category": "Displays", - "keywords": [ - "components", - "displays", - "modules", - "monitor", - "resolution", - "screen", - "widgets" - ], - "icon": "widgets" - }, - { - "section": "_tab_27", - "label": "Desktop Widgets", - "tabIndex": 27, - "category": "Desktop Widgets", - "keywords": [ - "components", - "conky", - "desktop", - "desktop clock", - "modules", - "widgets" - ], - "icon": "widgets" - }, - { - "section": "_tab_28", - "label": "Window Rules", - "tabIndex": 28, - "category": "Window Rules", - "keywords": [ - "floating", - "fullscreen", - "matching", - "opacity", - "rules", - "window" - ], - "icon": "select_window", - "conditionKey": "isNiri" - }, - { - "section": "audioInputDevices", - "label": "Input Devices", - "tabIndex": 29, - "category": "Audio", - "keywords": [ - "audio", - "device", - "devices", - "headphones", - "input", - "microphone", - "pipewire", - "sound", - "speaker", - "volume" - ], - "icon": "mic" - }, - { - "section": "audioOutputDevices", - "label": "Output Devices", - "tabIndex": 29, - "category": "Audio", - "keywords": [ - "audio", - "device", - "devices", - "headphones", - "microphone", - "output", - "pipewire", - "sound", - "speaker", - "volume" - ], - "icon": "volume_up" - }, - { - "section": "_tab_29", - "label": "System", - "tabIndex": 29, - "category": "Audio", - "keywords": [ - "audio", - "headphones", - "microphone", - "pipewire", - "sound", - "speaker", - "system", - "volume" - ], - "icon": "memory" - }, - { - "section": "_tab_30", - "label": "Locale", - "tabIndex": 30, - "category": "Locale", - "keywords": [ - "country", - "language", - "locale" - ], - "icon": "language" - }, - { - "section": "locale", - "label": "Locale Settings", - "tabIndex": 30, - "category": "Locale", - "keywords": [ - "change", - "country", - "interface", - "language", - "locale", - "settings" - ], - "icon": "language", - "description": "Change the locale used by the DMS interface." - }, - { - "section": "timeLocale", - "label": "Time & Date Locale", - "tabIndex": 30, - "category": "Locale", - "keywords": [ - "change", - "country", - "date", - "format", - "formatting", - "independent", - "interface", - "language", - "locale", - "region", - "time" - ], - "description": "Change the locale used for date and time formatting, independent of the interface language." - }, - { - "section": "_tab_31", - "label": "Greeter", - "tabIndex": 31, - "category": "Settings", - "keywords": [ - "greeter", - "settings" - ], - "icon": "login" - }, - { - "section": "_tab_32", - "label": "Multiplexers", - "tabIndex": 32, - "category": "Settings", - "keywords": [ - "multiplexers", - "settings" - ], - "icon": "terminal" - } -] diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/template.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/template.json deleted file mode 100644 index 41154dc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/translations/template.json +++ /dev/null @@ -1,16732 +0,0 @@ -[ - { - "term": "%1 Animation Speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 Sessions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 active session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 active sessions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 adapter, none connected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 adapters, none connected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 character", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 characters", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 connected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 custom animation duration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 disconnected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 disconnected (hidden)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 exists but is not included in config. Custom keybinds will not work until this is fixed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 exists but is not included. Window rules won't apply.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 filtered", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 is now included in config", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 issue found", - "translation": "", - "context": "greeter doctor page error count", - "reference": "", - "comment": "" - }, - { - "term": "%1 issues found", - "translation": "", - "context": "greeter doctor page error count", - "reference": "", - "comment": "" - }, - { - "term": "%1 notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 update", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 updates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 variants", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 wallpaper • %2 / %3", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 wallpapers • %2 / %3", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 widgets", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 window", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1 windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "%1m ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.", - "translation": "", - "context": "lock screen U2F security key mode setting", - "reference": "", - "comment": "" - }, - { - "term": "(Default)", - "translation": "", - "context": "default monitor label suffix", - "reference": "", - "comment": "" - }, - { - "term": "(Unnamed)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "+ %1 more", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "/path/to/videos", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "0 = square corners", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "1 day", - "translation": "", - "context": "notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "1 device connected", - "translation": "", - "context": "KDE Connect status single device", - "reference": "", - "comment": "" - }, - { - "term": "1 event", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "1 hour", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "1 hour 30 minutes", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "1 minute", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "1 notification", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "1 second", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "10 minutes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "10 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "10-bit Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "12 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "14 days", - "translation": "", - "context": "notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "15 minutes", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "15 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "180°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "2 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "2 minutes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "2 seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "20 minutes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "20 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "24-Hour Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "24-hour clock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "24-hour format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "25 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "250 ms", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "270°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "3 days", - "translation": "", - "context": "notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "3 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "3 minutes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "3 seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "30 days", - "translation": "", - "context": "notification history filter | notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "30 minutes", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "30 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "35 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "3rd party", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "4 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "4 seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "40 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "45 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "5 minutes", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "5 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "50 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "500 ms", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "55 seconds", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "6 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "7 days", - "translation": "", - "context": "notification history filter | notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "750 ms", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "8 hours", - "translation": "", - "context": "wallpaper interval", - "reference": "", - "comment": "" - }, - { - "term": "8 seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "90 days", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "90°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "MIT License", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "A file with this name already exists. Do you want to overwrite it?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "A modern desktop shell for Wayland compositors", - "translation": "", - "context": "greeter welcome page tagline", - "reference": "", - "comment": "" - }, - { - "term": "AC Power", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "API", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Aborted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "About", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Accent Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Accept", - "translation": "", - "context": "KDE Connect accept pairing button", - "reference": "", - "comment": "" - }, - { - "term": "Accept Jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Accepting", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Access clipboard history", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Access to notifications and do not disturb", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Access to system controls and settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Action", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Action failed or terminal was closed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Activate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Activate Greeter", - "translation": "", - "context": "greeter action confirmation", - "reference": "", - "comment": "" - }, - { - "term": "Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Activation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active Lock Screen Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active tile background and icon color", - "translation": "", - "context": "control center tile color setting description", - "reference": "", - "comment": "" - }, - { - "term": "Active: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active: %1 +%2", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Active: None", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Adapters", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Adaptive Media Width", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Desktop Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Title", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add Widget to %1 Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add a border around the dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add and configure widgets that appear on your desktop", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add by Address", - "translation": "", - "context": "Toggle button to manually add a printer by IP or hostname", - "reference": "", - "comment": "" - }, - { - "term": "Adjust the number of columns in grid view mode.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Adjust volume per scroll indent", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Advanced", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Afternoon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "All", - "translation": "", - "context": "notification history filter", - "reference": "", - "comment": "" - }, - { - "term": "All Monitors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "All checks passed", - "translation": "", - "context": "greeter doctor page success", - "reference": "", - "comment": "" - }, - { - "term": "All day", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "All displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Allow clicks to pass through the widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Alternative (OR)", - "translation": "", - "context": "U2F mode option: key works as standalone unlock method", - "reference": "", - "comment": "" - }, - { - "term": "Always Active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always Show Percentage", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always hide the dock and reveal it when hovering near the dock area", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always on icons", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always show a minimum of 3 workspaces, even if fewer are available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always show the dock when niri's overview is open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Always show when there's only one connected display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Amount", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Analog", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Analog, digital, or stacked clock display", - "translation": "", - "context": "Desktop clock widget description", - "reference": "", - "comment": "" - }, - { - "term": "Analyzing configuration...", - "translation": "", - "context": "greeter doctor page loading text", - "reference": "", - "comment": "" - }, - { - "term": "Animation Duration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Animation Speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Anonymous Identity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Anonymous Identity (optional)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "App Customizations", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "App ID Substitutions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "App ID regex (e.g. ^firefox$)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "App Launcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "App Names", - "translation": "", - "context": "lock screen notification mode option | notification rule match field option", - "reference": "", - "comment": "" - }, - { - "term": "App Theming", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Appearance", - "translation": "", - "context": "launcher appearance settings", - "reference": "", - "comment": "" - }, - { - "term": "Application Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Applications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apply Changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apply GTK Colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apply Qt Colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Applying authentication changes…", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps Dock Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps Icon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps are ordered by usage frequency, then last used, then alphabetically.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Apps with notification popups muted. Unmute or delete to remove.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Architecture", - "translation": "", - "context": "system info label", - "reference": "", - "comment": "" - }, - { - "term": "Are you sure you want to kill session \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Arrange displays and configure resolution, refresh rate, and VRR", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Attach", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Codec", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Codec Selection", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Devices", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Input", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Output", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Output Devices (", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Output Switch", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio Visualizer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio system restarted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Audio volume control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auth", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auth Type", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authenticate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authenticating...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication Required", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication changes applied.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication changes apply automatically.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication changes need sudo. Opening terminal so you can use password or fingerprint.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication error - try again", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authentication failed, please try again", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authorize", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authorize pairing with ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Authorize service for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto", - "translation": "", - "context": "theme category option", - "reference": "", - "comment": "" - }, - { - "term": "Auto (Bar-aware)", - "translation": "", - "context": "bar shadow direction source option | shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Auto (Wide)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto Location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto Popup Gaps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-Clear After", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-Hide Timeout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-close Niri overview when launching apps.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-delete notifications older than this", - "translation": "", - "context": "notification history setting", - "reference": "", - "comment": "" - }, - { - "term": "Auto-hide", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-hide Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Auto-saving...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Autoconnect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Autoconnect disabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Autoconnect enabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Autofill last remembered query when opened", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatic Color Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatic Control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatic Cycling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically cycle through wallpapers in the same folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically delete entries older than this", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically detect location based on IP address", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically determine your location using your IP address", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically lock after", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically lock the screen when DMS starts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automatically lock the screen when the system prepares to suspend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Automation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available Layouts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available Networks", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available Plugins", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available Screens (%1)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available in Detailed and Forecast view modes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Available.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "BSSID", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Back", - "translation": "", - "context": "greeter back button", - "reference": "", - "comment": "" - }, - { - "term": "Backend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Background", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Background Blur", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Background Opacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Background authentication sync failed. Trying terminal mode.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Background image", - "translation": "", - "context": "greeter wallpaper description", - "reference": "", - "comment": "" - }, - { - "term": "Backlight device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Balance power and performance", - "translation": "", - "context": "power profile description", - "reference": "", - "comment": "" - }, - { - "term": "Balanced", - "translation": "", - "context": "power profile option", - "reference": "", - "comment": "" - }, - { - "term": "Balanced palette with focused accents (default).", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bar Configurations", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bar Shadows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bar Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Base color for shadows (opacity is applied automatically)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Base duration for animations (drag to use Custom)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Battery", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Battery %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Battery Charge Limit", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Battery and power management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Battery level and power management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Behavior", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Binds Include Missing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Binds include added", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bit Depth", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Block Out", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Block Out From", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Block notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blocked", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blue light filter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bluetooth", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "Bluetooth Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bluetooth not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur Border Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur Border Opacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur Wallpaper Layer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur on Overview", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Blur wallpaper when niri overview is open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Body", - "translation": "", - "context": "notification rule match field option", - "reference": "", - "comment": "" - }, - { - "term": "Border", - "translation": "", - "context": "launcher border option", - "reference": "", - "comment": "" - }, - { - "term": "Border Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Border Opacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Border Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Border Thickness", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Border color around blurred surfaces", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Border with BG", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bottom", - "translation": "", - "context": "shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Bottom Center", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Bottom Left", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Bottom Right", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Bottom Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Bottom dock for pinned and running applications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Brightness", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Brightness Slider", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Brightness Value", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Brightness control not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Browse", - "translation": "", - "context": "theme category option", - "reference": "", - "comment": "" - }, - { - "term": "Browse Files", - "translation": "", - "context": "KDE Connect browse tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Browse Plugins", - "translation": "", - "context": "plugin browser header | plugin browser window title", - "reference": "", - "comment": "" - }, - { - "term": "Browse Themes", - "translation": "", - "context": "browse themes button | theme browser header | theme browser window title", - "reference": "", - "comment": "" - }, - { - "term": "Browse or search plugins", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Button Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU Usage", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU temperature display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU usage indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CPU, memory, network, and disk monitoring", - "translation": "", - "context": "System monitor widget description", - "reference": "", - "comment": "" - }, - { - "term": "CUPS Insecure Filter Warning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CUPS Missing Filter Warning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CUPS Print Server", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "CUPS not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Camera", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cancel", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cancel all jobs for \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Canceled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cannot pair", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Capabilities", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Capacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Caps Lock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Caps Lock Indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Caps Lock is on", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Center Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Center Single Column", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Center Tiling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Certificate Password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Change Song", - "translation": "", - "context": "media scroll wheel option", - "reference": "", - "comment": "" - }, - { - "term": "Change Volume", - "translation": "", - "context": "media scroll wheel option", - "reference": "", - "comment": "" - }, - { - "term": "Change bar appearance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Change the locale used by the DMS interface.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Change the locale used for date and time formatting, independent of the interface language.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Channel", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Charging", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Check for system updates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Checking for updates...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Checking whether sudo authentication is needed…", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Checking...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Checking…", - "translation": "", - "context": "greeter status loading", - "reference": "", - "comment": "" - }, - { - "term": "Choose Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose Dark Mode Color", - "translation": "", - "context": "dark mode wallpaper color picker title", - "reference": "", - "comment": "" - }, - { - "term": "Choose Dock Launcher Logo Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose Launcher Logo Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose Light Mode Color", - "translation": "", - "context": "light mode wallpaper color picker title", - "reference": "", - "comment": "" - }, - { - "term": "Choose Wallpaper Color", - "translation": "", - "context": "wallpaper color picker title", - "reference": "", - "comment": "" - }, - { - "term": "Choose a color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose colors from palette", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose how the weather widget is displayed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose how this bar resolves shadow direction", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose icon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose the background color for widgets", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose the border accent color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose the logo displayed on the launcher button in DankBar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose where notification popups appear on screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose where on-screen displays appear on screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose which displays show this widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Chroma Style", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cipher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Circle", - "translation": "", - "context": "dock indicator style option", - "reference": "", - "comment": "" - }, - { - "term": "Class regex (e.g. ^firefox$)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear All", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear All Jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear History?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear Sky", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear all history when server starts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clear at Startup", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click 'Setup' to create %1 and add include to config.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click 'Setup' to create %1 and add include to your compositor config.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click 'Setup' to create cursor config and add include to your compositor config.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click 'Setup' to create the outputs config and add include to your compositor config.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click Import to add a .ovpn or .conf", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click Refresh to check status.", - "translation": "", - "context": "greeter status placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Click Through", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click any shortcut to edit. Changes save to %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click to capture", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Click to select a custom theme JSON file", - "translation": "", - "context": "custom theme file hint", - "reference": "", - "comment": "" - }, - { - "term": "Clip", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clip to Geometry", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clipboard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clipboard History", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clipboard Manager", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clipboard sent", - "translation": "", - "context": "KDE Connect clipboard action | Phone Connect clipboard action", - "reference": "", - "comment": "" - }, - { - "term": "Clipboard works but nothing saved to disk", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Clock Style", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Close All Windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Close Overview on Launch", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Close Window", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color", - "translation": "", - "context": "border color", - "reference": "", - "comment": "" - }, - { - "term": "Color Gamut", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color Management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color Override", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color Picker", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color displayed on monitors without the lock screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color for primary action buttons", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color temperature for day time", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color temperature for night mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color theme for syntax highlighting.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color theme for syntax highlighting. %1 themes available.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Color theme from DMS registry", - "translation": "", - "context": "registry theme description", - "reference": "", - "comment": "" - }, - { - "term": "Colorful", - "translation": "", - "context": "widget style option", - "reference": "", - "comment": "" - }, - { - "term": "Colorful mix of bright contrasting accents.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Colorize Active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Colors from wallpaper", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Column", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Column Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Column Width", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Commands", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Communication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Community themes", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Compact", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Compact Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Completed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Compositor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Compositor Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Compositor not supported", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Config Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Config action: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Config validation failed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configuration activated", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configuration will be preserved when this display reconnects", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configure", - "translation": "", - "context": "greeter settings section header", - "reference": "", - "comment": "" - }, - { - "term": "Configure Keybinds", - "translation": "", - "context": "greeter configure keybinds link", - "reference": "", - "comment": "" - }, - { - "term": "Configure a new printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configure match criteria and actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configure which displays show \"%1\"", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Configure which displays show shell components", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Confirm", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Confirm Delete", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Confirm Display Changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Confirm passkey for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Conflicts with: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connect to Hidden Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connect to VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connect to Wi-Fi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connected", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Connected Device", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "Connected Displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connecting to Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connecting to clipboard service…", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connecting...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Connection failed", - "translation": "", - "context": "Status message when test connection to printer fails", - "reference": "", - "comment": "" - }, - { - "term": "Contains", - "translation": "", - "context": "notification rule match type option", - "reference": "", - "comment": "" - }, - { - "term": "Content", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Content copied", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Contrast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Control Center", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Control Center Tile Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Control animation duration for notification popups and history", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Control currently playing media", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Control what notification information is shown on the lock screen", - "translation": "", - "context": "lock screen notification privacy setting", - "reference": "", - "comment": "" - }, - { - "term": "Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Control workspaces and columns by scrolling on the bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Controls opacity of all popouts, modals, and their content layers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Controls shadow cast direction for elevation layers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Controls the base blur radius and offset of shadows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Controls the transparency of the shadow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Convenience options for the login screen. Sync to apply.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cooldown", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copied GIF", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copied MP4", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copied WebP", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copied to clipboard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copied!", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy Content", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy Full Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy HTML", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy Name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy PID", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy Text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Copy path", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Corner Radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Corner Radius Override", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Corners & Background", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Count Only", - "translation": "", - "context": "lock screen notification mode option", - "reference": "", - "comment": "" - }, - { - "term": "Cover Open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create Dir", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create Printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create Window Rule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create a new %1 session (n)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create rule for:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Creating...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Critical Priority", - "translation": "", - "context": "notification rule urgency option", - "reference": "", - "comment": "" - }, - { - "term": "Current", - "translation": "", - "context": "notification center tab", - "reference": "", - "comment": "" - }, - { - "term": "Current Items", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Locale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Monitor", - "translation": "", - "context": "Running apps filter: only show apps from the same monitor", - "reference": "", - "comment": "" - }, - { - "term": "Current Period", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Status", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Temp", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Theme: %1", - "translation": "", - "context": "current theme label", - "reference": "", - "comment": "" - }, - { - "term": "Current Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current Workspace", - "translation": "", - "context": "Running apps filter: only show apps from the active workspace", - "reference": "", - "comment": "" - }, - { - "term": "Current time and date display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current weather conditions and temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Current: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cursor Config Not Configured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cursor Include Missing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cursor Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Cursor Theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom", - "translation": "", - "context": "blur border color | shadow color option | theme category option", - "reference": "", - "comment": "" - }, - { - "term": "Custom Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Duration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Hibernate Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Lock Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Logout Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Name", - "translation": "", - "context": "Audio device rename dialog field label", - "reference": "", - "comment": "" - }, - { - "term": "Custom Power Actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Power Off Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Reboot Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Shadow Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Shadow Override", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Suspend Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Custom power profile", - "translation": "", - "context": "power profile description", - "reference": "", - "comment": "" - }, - { - "term": "Custom theme loaded from JSON file", - "translation": "", - "context": "custom theme description", - "reference": "", - "comment": "" - }, - { - "term": "Custom...", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Custom: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Customizable empty space", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Customize which actions appear in the power menu", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DDC/CI monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DEMO MODE - Click anywhere to exit", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS Plugin Manager Unavailable", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS Shortcuts", - "translation": "", - "context": "greeter keybinds section header", - "reference": "", - "comment": "" - }, - { - "term": "DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS out of date", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS service is not connected. Clipboard settings are unavailable.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS shell actions (launcher, clipboard, etc.)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DMS_SOCKET not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DWL service not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Daily", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Daily at:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dank", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dank Bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "DankBar", - "translation": "", - "context": "greeter feature card title | greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "DankMaterialShell is ready to use", - "translation": "", - "context": "greeter completion page subtitle", - "reference": "", - "comment": "" - }, - { - "term": "DankShell & System Icons (requires restart)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dark Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dark mode base", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dark mode harmony", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Darken Modal Background", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Date Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Date format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Date format on greeter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dawn (Astronomical Twilight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dawn (Civil Twilight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dawn (Nautical Twilight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Day Date", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Day Month Date", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Day Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Daytime", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Deck", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Default", - "translation": "", - "context": "notification rule action option | notification rule urgency option | widget style option", - "reference": "", - "comment": "" - }, - { - "term": "Default (Black)", - "translation": "", - "context": "shadow color option", - "reference": "", - "comment": "" - }, - { - "term": "Default Width (%)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Default selected action", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Defaults", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Define rules for window behavior. Saves to %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete Class", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete Printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete Saved Item?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete class \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Delete profile \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dependencies & documentation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Derives colors that closely match the underlying image.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Description", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Desktop", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Desktop Clock", - "translation": "", - "context": "Desktop clock widget name", - "reference": "", - "comment": "" - }, - { - "term": "Desktop Entry", - "translation": "", - "context": "notification rule match field option", - "reference": "", - "comment": "" - }, - { - "term": "Desktop Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Desktop Widgets", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Desktop background images", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Detailed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Details for \"%1\"", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Development", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Device connections", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Device names updated", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Device paired", - "translation": "", - "context": "Phone Connect pairing action", - "reference": "", - "comment": "" - }, - { - "term": "Device unpaired", - "translation": "", - "context": "KDE Connect unpair action | Phone Connect unpair action", - "reference": "", - "comment": "" - }, - { - "term": "Digital", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Direction Source", - "translation": "", - "context": "bar shadow direction source", - "reference": "", - "comment": "" - }, - { - "term": "Disable Autoconnect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disable Built-in Wallpapers", - "translation": "", - "context": "wallpaper settings disable toggle", - "reference": "", - "comment": "" - }, - { - "term": "Disable History Persistence", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disable Output", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disabled", - "translation": "", - "context": "bluetooth status | lock screen notification mode option", - "reference": "", - "comment": "" - }, - { - "term": "Disabling WiFi...", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Disc", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Discard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Discharging", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Disconnect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disconnected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disconnected from WiFi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Discover Devices", - "translation": "", - "context": "Toggle button to scan for printers via mDNS/Avahi", - "reference": "", - "comment": "" - }, - { - "term": "Disk", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disk I/O", - "translation": "", - "context": "disk io header in system monitor", - "reference": "", - "comment": "" - }, - { - "term": "Disk Usage", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disk Usage Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Disks", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dismiss", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display Assignment", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display Control", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Display Name Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display Profiles", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display a dock with pinned and running applications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display all priorities over fullscreen apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display and switch DWL layouts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display application icons in workspace indicators", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display brightness control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display configuration is not available. WLR output management protocol not supported.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display currently focused application title", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display hourly weather predictions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display only workspaces that contain windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display power menu actions in a grid instead of a list", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display seconds in the clock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display the power system menu", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Display volume and brightness percentage values in OSD popups", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Displays", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Displays count when overflow is active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Displays the active keyboard layout and allows switching", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Distribution", - "translation": "", - "context": "system info label", - "reference": "", - "comment": "" - }, - { - "term": "Diverse palette spanning the full spectrum.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Do Not Disturb", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dock", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Dock & Launcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dock Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dock Visibility", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Docs", - "translation": "", - "context": "greeter documentation link", - "reference": "", - "comment": "" - }, - { - "term": "Documents", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Domain (optional)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Don't Change", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Don't Save", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Door Open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Downloads", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Drag to Reorder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Drag workspace indicators to reorder them", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Driver", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Drizzle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Duplicate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Duplicate Wallpaper with Blur", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Duration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dusk (Astronomical Twilight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dusk (Civil Twighlight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dusk (Nautical Twilight)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dynamic", - "translation": "", - "context": "dynamic theme name", - "reference": "", - "comment": "" - }, - { - "term": "Dynamic Properties", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Dynamic Theming", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Dynamic colors from wallpaper", - "translation": "", - "context": "dynamic colors description", - "reference": "", - "comment": "" - }, - { - "term": "Dynamic colors, presets", - "translation": "", - "context": "greeter theme description", - "reference": "", - "comment": "" - }, - { - "term": "Edge Spacing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Edit App", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Edit Window Rule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Education", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Empty", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Enable 10-bit color depth for wider color gamut and HDR support", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Autoconnect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Do Not Disturb", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable History", - "translation": "", - "context": "notification history toggle label", - "reference": "", - "comment": "" - }, - { - "term": "Enable Overview Overlay", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Ripple Effects", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable System Sounds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Video Screensaver", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable WiFi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable a custom override below to set per-bar shadow intensity, opacity, and color.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable fingerprint at login", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable fingerprint authentication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable loginctl lock integration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable security key at login", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enable security key authentication", - "translation": "", - "context": "Enable FIDO2/U2F hardware security key for lock screen", - "reference": "", - "comment": "" - }, - { - "term": "Enabled", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but fingerprint availability could not be confirmed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but no fingerprint reader was detected.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but no registered security key was found yet. Register a key and run Sync.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled, but security-key availability could not be confirmed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled. PAM already provides fingerprint auth.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled. PAM already provides security-key auth.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enabling WiFi...", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "End", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enlarge on Hover", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enlargement %", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter 6-digit passkey", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter PIN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter PIN for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter URL or text to share", - "translation": "", - "context": "KDE Connect share input placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Enter a new name for session \"%1\"", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter a new name for this workspace", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter command or script path", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter credentials for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter custom lock screen format (e.g., dddd, MMMM d)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter custom top bar format (e.g., ddd MMM d)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter device name...", - "translation": "", - "context": "Audio device rename dialog placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Enter filename...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter launch prefix (e.g., 'uwsm-app')", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter network name and password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter passkey for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter password for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter this passkey on ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enter to Paste", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Enterprise", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Entry pinned", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Entry unpinned", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Environment Variables", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Error", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Errors", - "translation": "", - "context": "greeter doctor page status card", - "reference": "", - "comment": "" - }, - { - "term": "Ethernet", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Exact", - "translation": "", - "context": "notification rule match type option", - "reference": "", - "comment": "" - }, - { - "term": "Exclusive Zone Offset", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Experimental Feature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Explore", - "translation": "", - "context": "greeter explore section header", - "reference": "", - "comment": "" - }, - { - "term": "Exponential", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Expressive", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Extend battery life", - "translation": "", - "context": "power profile description", - "reference": "", - "comment": "" - }, - { - "term": "Extensible architecture", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "External Wallpaper Management", - "translation": "", - "context": "wallpaper settings external management", - "reference": "", - "comment": "" - }, - { - "term": "Extra Arguments", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "F1/I: Toggle • F10: Help", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fade", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Fade to lock screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fade to monitor off", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to accept pairing", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to activate configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to activate profile - file not found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to add binds include", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to add printer to class", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to browse device", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to cancel all jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to cancel selected job", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to check for updates:\n%1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to check pin limit", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to connect VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to connect to %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to copy entry", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to create printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to create profiles directory", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to delete VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to delete class", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to delete printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to disable job acceptance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to disable night mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to disconnect VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to disconnect VPNs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to disconnect WiFi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to enable IP location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to enable WiFi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to enable job acceptance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to enable night mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to hold job", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to import VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to launch SMS app", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to load VPN config", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to load clipboard configuration.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to move job", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to parse plugin_settings.json", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to parse session.json", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to parse settings.json", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to pause printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to pin entry", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to print test page", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to reject pairing", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to remove device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to remove keybind", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to remove printer from class", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to restart audio system", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to restart job", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to resume printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to ring device", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.", - "translation": "", - "context": "greeter status error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to save audio config", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to save clipboard setting", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to save keybind", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to save profile file", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to send clipboard", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to send file", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to send ping", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set brightness", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set night mode location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set night mode schedule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set night mode temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set power profile", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set profile image", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to set profile image: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to share", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Failed to start connection to %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to unpin entry", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to update VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to update autoconnect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to update description", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to update location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to update sharing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Failed to write temp file for validation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Features", - "translation": "", - "context": "greeter welcome page section header", - "reference": "", - "comment": "" - }, - { - "term": "Feels", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Feels Like", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Feels Like %1°", - "translation": "", - "context": "weather feels like temperature", - "reference": "", - "comment": "" - }, - { - "term": "Fidelity", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Field", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "File", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "File Already Exists", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "File Information", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "File received from", - "translation": "", - "context": "Phone Connect file share notification", - "reference": "", - "comment": "" - }, - { - "term": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Files", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Filesystem usage monitoring", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fill", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Find in Text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Find in note...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint availability could not be confirmed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint error", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint error: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint not recognized (%1/%2). Please try again or use password.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Finish", - "translation": "", - "context": "greeter finish button", - "reference": "", - "comment": "" - }, - { - "term": "First Day of Week", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "First Time Setup", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fit", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Fix Now", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fixing...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Flags", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Flipped", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Flipped 180°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Flipped 270°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Flipped 90°", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Float", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focus", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focus at Startup", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focused Border", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focused Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focused Monitor Only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focused Window", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Focused monitor only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fog", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Folders", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Follow DMS background color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Follow Monitor Focus", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Follow focus", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font Family", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font Scale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font Weight", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Font used on the login screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Force HDR", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Force Kill (SIGKILL)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Force Wide Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Force terminal applications to always use dark color schemes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forecast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forecast Days", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forecast Not Available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forever", - "translation": "", - "context": "notification history retention option", - "reference": "", - "comment": "" - }, - { - "term": "Forget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forget \"%1\"?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forget Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forget Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Forgot network %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Format Legend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Found %1 package to update:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Found %1 packages to update:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Freezing Drizzle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Frequency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fruit Salad", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Full Command:", - "translation": "", - "context": "process detail label", - "reference": "", - "comment": "" - }, - { - "term": "Full Content", - "translation": "", - "context": "lock screen notification mode option", - "reference": "", - "comment": "" - }, - { - "term": "Full Day & Month", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Full with Year", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Fullscreen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fullscreen Only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Fully Charged", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Fun", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "G: grid • Z/X: size", - "translation": "", - "context": "Widget grid keyboard hints", - "reference": "", - "comment": "" - }, - { - "term": "GPU", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "GPU Monitoring", - "translation": "", - "context": "gpu section header in system monitor", - "reference": "", - "comment": "" - }, - { - "term": "GPU Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "GPU temperature display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "GTK, Qt, IDEs, more", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Games", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Gamma Control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Gamma control not available. Requires DMS API v6+.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

        It is recommended to configure adw-gtk3 prior to applying GTK themes.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Generic", - "translation": "", - "context": "theme category option", - "reference": "", - "comment": "" - }, - { - "term": "Get Started", - "translation": "", - "context": "greeter first page button", - "reference": "", - "comment": "" - }, - { - "term": "GitHub", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Globally scale all animation durations", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Golden Hour", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Good", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Goth Corner Radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Goth Corners", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Gradually fade the screen before locking with a configurable grace period", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Gradually fade the screen before turning off monitors with a configurable grace period", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Graph Time Range", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Graphics", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter Appearance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter Behavior", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter Status", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter activated. greetd is now enabled.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter font", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter only — does not affect main clock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Greeter only — format for the date on the login screen", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Grid", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Grid Columns", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Grid: OFF", - "translation": "", - "context": "Widget grid snap status", - "reference": "", - "comment": "" - }, - { - "term": "Grid: ON", - "translation": "", - "context": "Widget grid snap status", - "reference": "", - "comment": "" - }, - { - "term": "Group", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Group Workspace Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Group by App", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Group multiple windows of the same app together with a window count indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Group removed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Group repeated application icons in unfocused workspaces", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Groups", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "HDR (EDID)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "HDR Tone Mapping", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "HDR mode is experimental. Verify your monitor supports HDR before enabling.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "HSV", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "HTML copied to clipboard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Health", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Heavy Rain", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Heavy Snow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Heavy Snow Showers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Height", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Held", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Help", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hex", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hibernate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hidden", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hidden (%1)", - "translation": "", - "context": "count of hidden audio devices", - "reference": "", - "comment": "" - }, - { - "term": "Hidden Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hidden Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide 3rd Party", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide App", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide Delay", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide Indicators", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide Updater Widget", - "translation": "", - "context": "When updater widget is used, then hide it if no update found", - "reference": "", - "comment": "" - }, - { - "term": "Hide When Typing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide When Windows Open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide cursor after inactivity (0 = disabled)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide cursor when pressing keyboard keys", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide cursor when using touch input", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide notification content until expanded", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide notification content until expanded; popups show collapsed by default", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hide on Touch", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "High-fidelity palette that preserves source hues.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Highlight Active Workspace App", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Highlight the currently focused app inside workspace indicators", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "History", - "translation": "", - "context": "notification center tab", - "reference": "", - "comment": "" - }, - { - "term": "History Retention", - "translation": "", - "context": "notification history retention settings label", - "reference": "", - "comment": "" - }, - { - "term": "History Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "History cleared. %1 pinned entries kept.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hold Duration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hold longer to confirm", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hold to Confirm Power Actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hold to confirm (%1 ms)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hold to confirm (%1s)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Home", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Host", - "translation": "", - "context": "Label for printer IP address or hostname input field", - "reference": "", - "comment": "" - }, - { - "term": "Hostname", - "translation": "", - "context": "system info label", - "reference": "", - "comment": "" - }, - { - "term": "Hot Corners", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hotkey overlay title (optional)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hour", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hourly", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hourly Forecast Count", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "How often to change wallpaper", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "How the background image is scaled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Humidity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hyprland Discord Server", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hyprland Layout Overrides", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hyprland Options", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Hyprland Website", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "I Understand", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "IP", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "IP Address:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "IP address or hostname", - "translation": "", - "context": "Placeholder text for manual printer address input", - "reference": "", - "comment": "" - }, - { - "term": "ISO Date", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Icon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Icon Scale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Icon Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Icon Size %", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Icon Theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Idle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Idle Inhibitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Idle Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Idle monitoring not supported - requires newer Quickshell version", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "If the field is hidden, it will appear as soon as a key is pressed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Ignore Completely", - "translation": "", - "context": "notification rule action option", - "reference": "", - "comment": "" - }, - { - "term": "Image", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Image copied to clipboard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Import", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Import VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Inactive Monitor Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Include Files in All Tab", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Include Folders in All Tab", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Include Transitions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Include desktop actions (shortcuts) in search results.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Incompatible Plugins Loaded", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Incorrect password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Incorrect password - attempt %1 of %2 (lockout may follow)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Incorrect password - next failures may trigger account lockout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Incorrect password - try again", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Indicator Style", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Individual Batteries", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Individual bar configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Info", - "translation": "", - "context": "greeter doctor page status card", - "reference": "", - "comment": "" - }, - { - "term": "Inherit", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Inherit Global (Default)", - "translation": "", - "context": "bar shadow direction source option", - "reference": "", - "comment": "" - }, - { - "term": "Inhibitable", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Input Devices", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Input Volume Slider", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Insert your security key...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Install", - "translation": "", - "context": "install action button", - "reference": "", - "comment": "" - }, - { - "term": "Install Greeter", - "translation": "", - "context": "greeter action confirmation", - "reference": "", - "comment": "" - }, - { - "term": "Install Plugin", - "translation": "", - "context": "plugin installation dialog title", - "reference": "", - "comment": "" - }, - { - "term": "Install Theme", - "translation": "", - "context": "theme installation dialog title", - "reference": "", - "comment": "" - }, - { - "term": "Install color themes from the DMS theme registry", - "translation": "", - "context": "theme browser description", - "reference": "", - "comment": "" - }, - { - "term": "Install complete. Greeter has been installed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Install failed: %1", - "translation": "", - "context": "installation error", - "reference": "", - "comment": "" - }, - { - "term": "Install matugen package for dynamic theming", - "translation": "", - "context": "matugen installation hint", - "reference": "", - "comment": "" - }, - { - "term": "Install plugin '%1' from the DMS registry?", - "translation": "", - "context": "plugin installation confirmation", - "reference": "", - "comment": "" - }, - { - "term": "Install plugins from the DMS plugin registry", - "translation": "", - "context": "plugin browser description", - "reference": "", - "comment": "" - }, - { - "term": "Install the DMS greeter? A terminal will open for sudo authentication.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Install theme '%1' from the DMS registry?", - "translation": "", - "context": "theme installation confirmation", - "reference": "", - "comment": "" - }, - { - "term": "Installation and PAM setup: see the ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Installed", - "translation": "", - "context": "installed status", - "reference": "", - "comment": "" - }, - { - "term": "Installed: %1", - "translation": "", - "context": "installation success", - "reference": "", - "comment": "" - }, - { - "term": "Installing: %1", - "translation": "", - "context": "installation progress", - "reference": "", - "comment": "" - }, - { - "term": "Intelligent Auto-hide", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Intensity", - "translation": "", - "context": "shadow intensity slider", - "reference": "", - "comment": "" - }, - { - "term": "Interface:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Interlock Open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Internet", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Interval", - "translation": "", - "context": "wallpaper cycling mode tab", - "reference": "", - "comment": "" - }, - { - "term": "Invalid configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Invert on mode change", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Iris Bloom", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Isolate Displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Jobs: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keep Awake", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keep Changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keeping Awake", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Kernel", - "translation": "", - "context": "system info label", - "reference": "", - "comment": "" - }, - { - "term": "Key", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keybind Sources", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keybinds", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Keybinds Search Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keybinds shown alongside regular search results", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keyboard Layout Name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keyboard Shortcuts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Keys", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Kill", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Kill Process", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Kill Session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Ko-fi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "LED device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "LabWC IRC Channel", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "LabWC Website", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Large", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Largest", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last hour", - "translation": "", - "context": "notification history filter", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 day ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 days ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 hour ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 hours ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 minute ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched %1 minutes ago", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Last launched just now", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Latitude", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launch", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launch Prefix", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launch on dGPU", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launch on dGPU by default", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launcher Button", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Launcher Button Logo", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Layout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Layout Overrides", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Left", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Left Center", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Left Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light Direction", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light Rain", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light Snow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light Snow Showers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light mode base", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Light mode harmony", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Line", - "translation": "", - "context": "dock indicator style option", - "reference": "", - "comment": "" - }, - { - "term": "Line: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Linear", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lines: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "List", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lively palette with saturated accents.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Load Average", - "translation": "", - "context": "system info label", - "reference": "", - "comment": "" - }, - { - "term": "Loading codecs...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Loading keybinds...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Loading trending...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Loading...", - "translation": "", - "context": "loading indicator", - "reference": "", - "comment": "" - }, - { - "term": "Local", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Locale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Locale Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Location", - "translation": "", - "context": "theme auto mode tab", - "reference": "", - "comment": "" - }, - { - "term": "Location Search", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock Screen", - "translation": "", - "context": "greeter feature card title | lock screen notifications settings card", - "reference": "", - "comment": "" - }, - { - "term": "Lock Screen Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock Screen Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock Screen behaviour", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock Screen layout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock at startup", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock before suspend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock fade grace period", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Locked", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Log Out", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Logging in...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Login", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Login Authentication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Long", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Long Text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Long press", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Longitude", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Low Priority", - "translation": "", - "context": "notification rule urgency option", - "reference": "", - "comment": "" - }, - { - "term": "MAC", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "MTU", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Make sure KDE Connect or Valent is running on your other devices", - "translation": "", - "context": "Phone Connect hint message", - "reference": "", - "comment": "" - }, - { - "term": "Manage and configure plugins for extending DMS functionality", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "MangoWC Layout Overrides", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Manual", - "translation": "", - "context": "bar shadow direction source option", - "reference": "", - "comment": "" - }, - { - "term": "Manual Coordinates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Manual Direction", - "translation": "", - "context": "bar manual shadow direction", - "reference": "", - "comment": "" - }, - { - "term": "Manual Gap Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Manual Show/Hide", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Map window class names to icon names for proper icon display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Margin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Marker Supply Empty", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Marker Supply Low", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Marker Waste Almost Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Marker Waste Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Match Criteria", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Matches profile: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Material Colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Material Design inspired color themes", - "translation": "", - "context": "generic theme description", - "reference": "", - "comment": "" - }, - { - "term": "Material colors generated from wallpaper", - "translation": "", - "context": "dynamic theme description", - "reference": "", - "comment": "" - }, - { - "term": "Material inspired shadows and elevation on modals, popouts, and dialogs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Matugen Contrast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Matugen Missing", - "translation": "", - "context": "matugen not found status", - "reference": "", - "comment": "" - }, - { - "term": "Matugen Palette", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Matugen Target Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Matugen Templates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Edges", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max H", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Pinned Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Pinned Apps (0 = Unlimited)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Running Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Running Apps (0 = Unlimited)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max Volume", - "translation": "", - "context": "Audio settings: maximum volume limit per device", - "reference": "", - "comment": "" - }, - { - "term": "Max W", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max apps to show", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Max to Edges", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximize", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximize Detection", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximize Widget Icons", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximize Widget Text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum Entry Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum History", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum Pinned Entries", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum fingerprint attempts reached. Please use password.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum number of clipboard entries to keep", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum number of entries that can be saved", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum number of notifications to keep", - "translation": "", - "context": "notification history limit", - "reference": "", - "comment": "" - }, - { - "term": "Maximum pinned entries reached", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Maximum size per clipboard entry", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Controls", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Empty", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Jam", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Low", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Needed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Playback", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Player", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Player Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Players", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Players (", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Media Volume", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Medium", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Memory", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Memory Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Memory Usage", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Memory usage indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Merge indexed file results into the All tab (requires dsearch).", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Merge indexed folder results into the All tab (requires dsearch).", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Message", - "translation": "", - "context": "KDE Connect SMS message input placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Message Content", - "translation": "", - "context": "notification privacy mode placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Microphone", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Microphone Mute", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Microphone Volume", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Microphone settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Microphone volume control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Middle Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Min H", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Min W", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Minimal palette built around a single hue.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Minute", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mirror Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Missing Environment Variables", - "translation": "", - "context": "qt theme env error title", - "reference": "", - "comment": "" - }, - { - "term": "Modal Background", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Modal Shadows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Modals", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mode:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Model", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Modified", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Modular widget bar", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Monitor Configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Monitor fade grace period", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Monitor whose wallpaper drives dynamic theming colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Monochrome", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Monocle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Monospace Font", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Month Date", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Morning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mount Points", - "translation": "", - "context": "mount points header in system monitor", - "reference": "", - "comment": "" - }, - { - "term": "Mouse pointer appearance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mouse pointer size in pixels", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Move", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Move Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Moving to Paused", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Multi-Monitor", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Multiplexer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Multiplexer Type", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Multiplexers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Music", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Mute Popups", - "translation": "", - "context": "notification rule action option", - "reference": "", - "comment": "" - }, - { - "term": "Mute popups for %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Muted", - "translation": "", - "context": "audio status", - "reference": "", - "comment": "" - }, - { - "term": "Muted Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Muted palette with subdued, calming tones.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "NM not supported", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Named Workspace Icons", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Navigate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Navigation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Info", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Information", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Name (SSID)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Speed Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network Status", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Network download and upload speed display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Neutral", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Never", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Never used", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New Key", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New Keybind", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New Notification", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New Session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New Window Rule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New York, NY", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "New group name...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Next", - "translation": "", - "context": "greeter next button", - "reference": "", - "comment": "" - }, - { - "term": "Next Transition", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Night", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Night Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Night Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Night mode & gamma", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Niri Integration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Niri Layout Overrides", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Niri compositor actions (focus, move, etc.)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Active Players", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Anim", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Background", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Battery", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "No Bluetooth adapter found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Blur", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Border", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No DMS shortcuts configured", - "translation": "", - "context": "greeter no keybinds message", - "reference": "", - "comment": "" - }, - { - "term": "No Dim", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Focus", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No GPU detected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No GPUs detected", - "translation": "", - "context": "empty state in gpu list", - "reference": "", - "comment": "" - }, - { - "term": "No History", - "translation": "", - "context": "notification rule action option", - "reference": "", - "comment": "" - }, - { - "term": "No Media", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Round", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Rounding", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Shadow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No VPN profiles", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Weather Data", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No Weather Data Available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No action", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No active %1 sessions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No adapter", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "No adapters", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "No app customizations.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No apps found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No apps have been launched yet.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No battery", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No brightness devices available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No checks passed", - "translation": "", - "context": "greeter doctor page empty state", - "reference": "", - "comment": "" - }, - { - "term": "No custom theme file", - "translation": "", - "context": "no custom theme file status", - "reference": "", - "comment": "" - }, - { - "term": "No devices", - "translation": "", - "context": "Phone Connect no devices status | bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "No devices connected", - "translation": "", - "context": "KDE Connect status", - "reference": "", - "comment": "" - }, - { - "term": "No devices found", - "translation": "", - "context": "KDE Connect no devices message", - "reference": "", - "comment": "" - }, - { - "term": "No disk data", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No disk data available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No drivers found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No errors", - "translation": "", - "context": "greeter doctor page empty state", - "reference": "", - "comment": "" - }, - { - "term": "No features enabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No files found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No fingerprint reader detected.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No folders found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No hidden apps.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No info items", - "translation": "", - "context": "greeter doctor page empty state", - "reference": "", - "comment": "" - }, - { - "term": "No information available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No input device", - "translation": "", - "context": "audio status", - "reference": "", - "comment": "" - }, - { - "term": "No input devices found", - "translation": "", - "context": "Audio settings empty state", - "reference": "", - "comment": "" - }, - { - "term": "No items added yet", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No keybinds found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No launcher plugins installed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No match criteria", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No matches", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No matching processes", - "translation": "", - "context": "empty state in process list", - "reference": "", - "comment": "" - }, - { - "term": "No monitors", - "translation": "", - "context": "no monitors available label", - "reference": "", - "comment": "" - }, - { - "term": "No mount points found", - "translation": "", - "context": "empty state in disk mounts list", - "reference": "", - "comment": "" - }, - { - "term": "No output device", - "translation": "", - "context": "audio status", - "reference": "", - "comment": "" - }, - { - "term": "No output devices found", - "translation": "", - "context": "Audio settings empty state", - "reference": "", - "comment": "" - }, - { - "term": "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No plugin results", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No plugins found", - "translation": "", - "context": "empty plugin list", - "reference": "", - "comment": "" - }, - { - "term": "No plugins found.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No printer found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No printers configured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No printers found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No profiles", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No recent clipboard entries found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No results found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No saved clipboard entries", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No sessions found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No status output.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No themes found", - "translation": "", - "context": "empty theme list", - "reference": "", - "comment": "" - }, - { - "term": "No themes installed. Browse themes to install from the registry.", - "translation": "", - "context": "no registry themes installed hint", - "reference": "", - "comment": "" - }, - { - "term": "No trigger", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No video found in folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No wallpaper selected", - "translation": "", - "context": "no wallpaper status", - "reference": "", - "comment": "" - }, - { - "term": "No wallpapers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No wallpapers found\n\nClick the folder icon below to browse", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No warnings", - "translation": "", - "context": "greeter doctor page empty state", - "reference": "", - "comment": "" - }, - { - "term": "No widgets added. Click \"Add Widget\" to get started.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No widgets available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No widgets match your search", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "No window rules configured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "None", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Normal", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Normal Font", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Normal Priority", - "translation": "", - "context": "notification rule urgency option", - "reference": "", - "comment": "" - }, - { - "term": "Not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not available — install fprintd and pam_fprintd, or configure greetd PAM.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not available — install fprintd and pam_fprintd.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not available — install or configure pam_u2f, or configure greetd PAM.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not available — install or configure pam_u2f.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not connected", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Not detected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Not paired", - "translation": "", - "context": "KDE Connect not paired status", - "reference": "", - "comment": "" - }, - { - "term": "Not set", - "translation": "", - "context": "wallpaper not set label", - "reference": "", - "comment": "" - }, - { - "term": "Note: this only changes the percentage, it does not actually limit charging.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notepad", - "translation": "", - "context": "Notepad", - "reference": "", - "comment": "" - }, - { - "term": "Notepad Font Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notepad Slideout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Nothing", - "translation": "", - "context": "media scroll wheel option", - "reference": "", - "comment": "" - }, - { - "term": "Nothing to see here", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Center", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Display", - "translation": "", - "context": "lock screen notification privacy setting", - "reference": "", - "comment": "" - }, - { - "term": "Notification Overlay", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Popups", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Rules", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification Timeouts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notification toast popups", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Notifications", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Numbers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Numeric (D/M)", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "Numeric (M/D)", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "OK", - "translation": "", - "context": "greeter doctor page status card", - "reference": "", - "comment": "" - }, - { - "term": "OS Logo", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "OSD Position", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Occupied Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Off", - "translation": "", - "context": "bluetooth status", - "reference": "", - "comment": "" - }, - { - "term": "Office", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Offline", - "translation": "", - "context": "KDE Connect offline status | Phone Connect offline status", - "reference": "", - "comment": "" - }, - { - "term": "Offline Report", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Older", - "translation": "", - "context": "notification history filter for content older than other filters", - "reference": "", - "comment": "" - }, - { - "term": "On", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "On-Demand", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "On-Screen Displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "On-screen Displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Only adjust gamma based on time or location rules.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Only show windows from the current monitor on each dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Only visible if hibernate is supported by your system", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Opacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Opaque", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open App", - "translation": "", - "context": "KDE Connect open SMS app button", - "reference": "", - "comment": "" - }, - { - "term": "Open KDE Connect on your phone", - "translation": "", - "context": "KDE Connect open app hint", - "reference": "", - "comment": "" - }, - { - "term": "Open Notepad File", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open a new note", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open in Browser", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open in terminal", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open search bar to find text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Open with...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Opening SMS", - "translation": "", - "context": "KDE Connect SMS action", - "reference": "", - "comment": "" - }, - { - "term": "Opening SMS app", - "translation": "", - "context": "Phone Connect SMS action", - "reference": "", - "comment": "" - }, - { - "term": "Opening file browser", - "translation": "", - "context": "Phone Connect browse action", - "reference": "", - "comment": "" - }, - { - "term": "Opening files", - "translation": "", - "context": "KDE Connect browse action", - "reference": "", - "comment": "" - }, - { - "term": "Opening terminal: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Optional description", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Optional location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Options", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Organize widgets into collapsible groups", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Original: %1", - "translation": "", - "context": "Shows the original device name before renaming", - "reference": "", - "comment": "" - }, - { - "term": "Other", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Outline", - "translation": "", - "context": "blur border color | outline color", - "reference": "", - "comment": "" - }, - { - "term": "Output", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Output Area Almost Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Output Area Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Output Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Output Devices", - "translation": "", - "context": "Audio settings: speaker/headphone devices", - "reference": "", - "comment": "" - }, - { - "term": "Output Tray Missing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Outputs Include Missing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overcast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overflow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overridden by config", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override Border Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override Corner Radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override Gaps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override global layout settings for this output", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override terminal with a custom command or script", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Override the global shadow with per-bar settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overrides", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overview", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overview of your network connections", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Overwrite", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PAM already provides fingerprint auth. Enable this to show it at login.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PAM already provides security-key auth. Enable this to show it at login.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but availability could not be confirmed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but no prints are enrolled yet.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PAM provides fingerprint auth, but no reader was detected.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "PIN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pad", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Pad Hours", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pad hours (02:00 vs 2:00)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Padding", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pair", - "translation": "", - "context": "KDE Connect pair button", - "reference": "", - "comment": "" - }, - { - "term": "Pair Bluetooth Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Paired", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pairing", - "translation": "", - "context": "KDE Connect pairing in progress status", - "reference": "", - "comment": "" - }, - { - "term": "Pairing failed", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Pairing request from", - "translation": "", - "context": "Phone Connect pairing request notification", - "reference": "", - "comment": "" - }, - { - "term": "Pairing request sent", - "translation": "", - "context": "Phone Connect pairing action", - "reference": "", - "comment": "" - }, - { - "term": "Pairing requested", - "translation": "", - "context": "KDE Connect pairing requested status", - "reference": "", - "comment": "" - }, - { - "term": "Pairing...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Partly Cloudy", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Passkey:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Password...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Paste", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Path to a video file or folder containing videos", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pattern", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pause", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Paused", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pending", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pending Charge", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Pending Discharge", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Per-Mode Wallpapers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Per-Monitor Wallpapers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Per-screen config", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Percentage", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Performance", - "translation": "", - "context": "power profile option", - "reference": "", - "comment": "" - }, - { - "term": "Permission denied to set profile image.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Personalization", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Phone Connect Not Available", - "translation": "", - "context": "Phone Connect unavailable error title", - "reference": "", - "comment": "" - }, - { - "term": "Phone Connect unavailable", - "translation": "", - "context": "Phone Connect service unavailable message", - "reference": "", - "comment": "" - }, - { - "term": "Phone number", - "translation": "", - "context": "KDE Connect SMS phone input placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Pick a different random video each time from the same folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pictures", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pin to Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Ping", - "translation": "", - "context": "KDE Connect ping tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Ping sent", - "translation": "", - "context": "KDE Connect ping action", - "reference": "", - "comment": "" - }, - { - "term": "Ping sent to", - "translation": "", - "context": "Phone Connect ping action", - "reference": "", - "comment": "" - }, - { - "term": "Pinned", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pinned and running apps with drag-and-drop", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pixelate", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Place plugin directories here. Each plugin should have a plugin.json manifest file.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Place plugins in %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play a video when the screen locks.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play sound after logging in", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play sound when new notification arrives", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play sound when power cable is connected", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play sound when volume is adjusted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Play sounds for system events", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Playback", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Playback error: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Please wait...", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Please write a name for your new %1 session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugged In", - "translation": "", - "context": "battery status", - "reference": "", - "comment": "" - }, - { - "term": "Plugged in", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugin Directory", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugin Management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugin Visibility", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugin is disabled - enable in Plugins settings to use", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Plugins", - "translation": "", - "context": "greeter feature card title | greeter plugins link", - "reference": "", - "comment": "" - }, - { - "term": "Pointer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popout Shadows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popouts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popouts and Modals follow global Animation Speed (disable to customize independently)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popup Only", - "translation": "", - "context": "notification rule action option", - "reference": "", - "comment": "" - }, - { - "term": "Popup Position", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popup Shadow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popup Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Popup behavior, position", - "translation": "", - "context": "greeter notifications description", - "reference": "", - "comment": "" - }, - { - "term": "Port", - "translation": "", - "context": "Label for printer port number input field", - "reference": "", - "comment": "" - }, - { - "term": "Portal", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Position", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Position, pinned apps", - "translation": "", - "context": "greeter dock description", - "reference": "", - "comment": "" - }, - { - "term": "Possible Override Conflicts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power & Security", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power & Sleep", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Action Confirmation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Menu Customization", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Off", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Options", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Profile", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Profile Degradation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power Saver", - "translation": "", - "context": "power profile option", - "reference": "", - "comment": "" - }, - { - "term": "Power off monitors on lock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power profile management available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Power source", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pre-fill the last successful username on the greeter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pre-select the last used session on the greeter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Precip", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Precipitation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Precipitation Chance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Preference", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Preset Widths (%)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Press 'n' or click 'New Session' to create one", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Press Enter and the audio system will restart to apply the change", - "translation": "", - "context": "Audio device rename dialog hint", - "reference": "", - "comment": "" - }, - { - "term": "Press Enter to paste, Shift+Enter to copy", - "translation": "", - "context": "Clipboard behavior setting description", - "reference": "", - "comment": "" - }, - { - "term": "Press key...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Pressure", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Prevent screen timeout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Preview", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Primary", - "translation": "", - "context": "blur border color | button color option | color option | primary color | shadow color option | tile color option", - "reference": "", - "comment": "" - }, - { - "term": "Primary Container", - "translation": "", - "context": "button color option | tile color option", - "reference": "", - "comment": "" - }, - { - "term": "Print Server Management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Print Server not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer Classes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer created successfully", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer deleted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer name (no spaces)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printer reachable", - "translation": "", - "context": "Status message when test connection to printer succeeds", - "reference": "", - "comment": "" - }, - { - "term": "Printers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Printers: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Prioritize performance", - "translation": "", - "context": "power profile description", - "reference": "", - "comment": "" - }, - { - "term": "Priority", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Privacy Indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Privacy Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Private Key Password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Process Count", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Processes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Processes:", - "translation": "", - "context": "process count label in footer", - "reference": "", - "comment": "" - }, - { - "term": "Processing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile Image Error", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile activated: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile deleted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile error", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile image is too large. Please use a smaller image.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile not found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Profile saved: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Protocol", - "translation": "", - "context": "Label for printer protocol selector, e.g. ipp, ipps, lpd, socket", - "reference": "", - "comment": "" - }, - { - "term": "QtMultimedia is not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "QtMultimedia is not available - video screensaver requires qt multimedia services", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick Access", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick access to application launcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick access to color picker", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick access to notepad", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick note-taking slideout panel", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Quick system toggles", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "RGB", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rain", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rain Chance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rainbow", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Random", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Rate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Read:", - "translation": "", - "context": "disk read label", - "reference": "", - "comment": "" - }, - { - "term": "Reason", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reboot", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Recent Colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Recently Used Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Recommended available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Refresh", - "translation": "", - "context": "Phone Connect refresh tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Refresh Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Regex", - "translation": "", - "context": "notification rule match type option", - "reference": "", - "comment": "" - }, - { - "term": "Reject", - "translation": "", - "context": "KDE Connect reject pairing button", - "reference": "", - "comment": "" - }, - { - "term": "Reject Jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Release", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reload Plugin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remaining", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remaining / Total", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remember Last Query", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remember last session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remember last user", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remove", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remove Widget Padding", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Remove gaps and border when windows are maximized", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rename", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rename Session", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rename Workspace", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Repeat", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Replacement", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Report", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Request Pairing", - "translation": "", - "context": "KDE Connect request pairing button", - "reference": "", - "comment": "" - }, - { - "term": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Required plugin: ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Requires %1", - "translation": "", - "context": "version requirement", - "reference": "", - "comment": "" - }, - { - "term": "Requires 'dgop' tool", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Requires DMS %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Requires DWL compositor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Requires a newer version of Quickshell", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Requires night mode support", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reset", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reset Position", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reset Size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reset to default name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Resize Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Resolution & Refresh", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Resolution, position, scale", - "translation": "", - "context": "greeter displays description", - "reference": "", - "comment": "" - }, - { - "term": "Restart DMS", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Restart the DankMaterialShell", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Restarting audio system...", - "translation": "", - "context": "Loading overlay while WirePlumber restarts", - "reference": "", - "comment": "" - }, - { - "term": "Restore Special Workspace Windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Resume", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reverse Scrolling Direction", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Reverse workspace switch direction when scrolling over the bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Revert", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right Center", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Right Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right Tiling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right-click and drag anywhere on the widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right-click and drag the bottom-right corner", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Right-click bar widget to cycle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Ring", - "translation": "", - "context": "KDE Connect ring tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Ringing", - "translation": "", - "context": "KDE Connect ring action | Phone Connect ring action", - "reference": "", - "comment": "" - }, - { - "term": "Ripple Effects", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Root Filesystem", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rounded corners for windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rounded corners for windows (border_radius)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rounded corners for windows (decoration.rounding)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rule Name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Rules (%1)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Run Again", - "translation": "", - "context": "greeter doctor page button", - "reference": "", - "comment": "" - }, - { - "term": "Run DMS Templates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Run User Templates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Run a program (e.g., firefox, kitty)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Run a shell command (e.g., notify-send)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Running Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Running Apps Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Running greeter sync…", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "SDR Brightness", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "SDR Saturation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "SMS", - "translation": "", - "context": "KDE Connect SMS tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Save", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Save Notepad File", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Save QR Code", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Save and switch between display configurations", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Save critical priority notifications to history", - "translation": "", - "context": "notification history setting", - "reference": "", - "comment": "" - }, - { - "term": "Save dismissed notifications to history", - "translation": "", - "context": "notification history toggle description", - "reference": "", - "comment": "" - }, - { - "term": "Save low priority notifications to history", - "translation": "", - "context": "notification history setting", - "reference": "", - "comment": "" - }, - { - "term": "Save normal priority notifications to history", - "translation": "", - "context": "notification history setting", - "reference": "", - "comment": "" - }, - { - "term": "Save password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Saved", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Saved Configurations", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Saved Note", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Saved item deleted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Saving...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scale DankBar font sizes independently", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scale DankBar icon sizes independently", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scale all font sizes throughout the shell", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scan", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scanning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scanning...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Science", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Score", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Screen Sharing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Screen sharing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll Factor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll GitHub", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll Wheel", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll song title", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll title if it doesn't fit in widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scroll wheel behavior on media widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Scrolling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search App Actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search Options", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search by key combo, description, or action name.\n\nDefault action copies the keybind to clipboard.\nRight-click or press Right Arrow to pin frequently used keybinds - they'll appear at the top when not searching.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search for a location...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search keybinds...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search keyboard shortcuts from your compositor and applications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search plugins...", - "translation": "", - "context": "plugin search placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Search processes...", - "translation": "", - "context": "process search placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Search sessions...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search themes...", - "translation": "", - "context": "theme search placeholder", - "reference": "", - "comment": "" - }, - { - "term": "Search widgets...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Search...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Searching...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Second Factor (AND)", - "translation": "", - "context": "U2F mode option: key required after password or fingerprint", - "reference": "", - "comment": "" - }, - { - "term": "Secondary", - "translation": "", - "context": "blur border color | button color option | color option | secondary color | tile color option", - "reference": "", - "comment": "" - }, - { - "term": "Secured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Security", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Security & privacy", - "translation": "", - "context": "greeter feature card description", - "reference": "", - "comment": "" - }, - { - "term": "Security key mode", - "translation": "", - "context": "lock screen U2F security key mode setting", - "reference": "", - "comment": "" - }, - { - "term": "Security-key availability could not be confirmed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select Application", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select Bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select Custom Theme", - "translation": "", - "context": "custom theme file browser title", - "reference": "", - "comment": "" - }, - { - "term": "Select Dock Launcher Logo", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select File to Send", - "translation": "", - "context": "KDE Connect file browser title", - "reference": "", - "comment": "" - }, - { - "term": "Select Launcher Logo", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select Profile Image", - "translation": "", - "context": "profile image file browser title", - "reference": "", - "comment": "" - }, - { - "term": "Select Video or Folder", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select Wallpaper", - "translation": "", - "context": "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title", - "reference": "", - "comment": "" - }, - { - "term": "Select Wallpaper Directory", - "translation": "", - "context": "wallpaper directory file browser title", - "reference": "", - "comment": "" - }, - { - "term": "Select a color from the palette or use custom sliders", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select a widget to add to your desktop. Each widget is a separate instance with its own settings.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select a widget to add. You can add multiple instances of the same widget if needed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select a window...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select an image file...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select at least one provider", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select device", - "translation": "", - "context": "audio status", - "reference": "", - "comment": "" - }, - { - "term": "Select device...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select driver...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select font weight for UI text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select greeter background image", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select monitor to configure wallpaper", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select monospace font for process list and technical displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select network", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Select system sound theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select the font family for UI text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select the palette algorithm used for wallpaper-based colors", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select which keybind providers to include", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select which transitions to include in randomization", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Select...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Selected image file not found.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Send", - "translation": "", - "context": "KDE Connect SMS send button", - "reference": "", - "comment": "" - }, - { - "term": "Send Clipboard", - "translation": "", - "context": "KDE Connect clipboard tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Send File", - "translation": "", - "context": "KDE Connect send file button", - "reference": "", - "comment": "" - }, - { - "term": "Send SMS", - "translation": "", - "context": "KDE Connect SMS dialog title", - "reference": "", - "comment": "" - }, - { - "term": "Sending", - "translation": "", - "context": "Phone Connect file send", - "reference": "", - "comment": "" - }, - { - "term": "Separator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Server", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Session Filter", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Set Custom Device Name", - "translation": "", - "context": "Audio device rename dialog title", - "reference": "", - "comment": "" - }, - { - "term": "Set custom name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Set custom names for your audio input devices", - "translation": "", - "context": "Audio settings description", - "reference": "", - "comment": "" - }, - { - "term": "Set custom names for your audio output devices", - "translation": "", - "context": "Audio settings description", - "reference": "", - "comment": "" - }, - { - "term": "Set different wallpapers for each connected monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Set different wallpapers for light and dark mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Set key and action to save", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Set notification rules", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Settings", - "translation": "", - "context": "settings window title", - "reference": "", - "comment": "" - }, - { - "term": "Settings are read-only. Changes will not persist.", - "translation": "", - "context": "read-only settings warning for NixOS home-manager users", - "reference": "", - "comment": "" - }, - { - "term": "Setup", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow Intensity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow Opacity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow Override", - "translation": "", - "context": "bar shadow settings card", - "reference": "", - "comment": "" - }, - { - "term": "Shadow elevation on bars and panels", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow elevation on modals and dialogs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadow elevation on popouts, OSDs, and dropdowns", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shadows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Share", - "translation": "", - "context": "KDE Connect share dialog title | KDE Connect share tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Share Gamma Control Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Share Text", - "translation": "", - "context": "KDE Connect share button", - "reference": "", - "comment": "" - }, - { - "term": "Share URL", - "translation": "", - "context": "KDE Connect share URL button", - "reference": "", - "comment": "" - }, - { - "term": "Shared", - "translation": "", - "context": "Phone Connect share success", - "reference": "", - "comment": "" - }, - { - "term": "Shell", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shift+Del: Clear All • Esc: Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shift+Enter to paste", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close", - "translation": "", - "context": "Keyboard hints when enter-to-paste is enabled", - "reference": "", - "comment": "" - }, - { - "term": "Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Short", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shortcut (%1)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shortcuts", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shortcuts (%1)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show 3rd Party", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show All Tags", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Badge", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show CPU", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show CPU Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show CPU Temp", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Date", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Disk", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Feels Like Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Footer", - "translation": "", - "context": "launcher footer visibility", - "reference": "", - "comment": "" - }, - { - "term": "Show Forecast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show GPU Temperature", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Header", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Hibernate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Hour Numbers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Hourly Forecast", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Humidity", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Launcher Button", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Line Numbers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Lock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Log Out", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Material Design ripple animations on interactive elements", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Media Player", - "translation": "", - "context": "Enable media player controls on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show Memory", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Memory Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Memory in GB", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Network Graph", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Occupied Workspaces Only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Overflow Badge Count", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Password Field", - "translation": "", - "context": "Enable password field display on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show Power Actions", - "translation": "", - "context": "Enable power action icon on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show Power Off", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Precipitation Probability", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Pressure", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Profile Image", - "translation": "", - "context": "Enable profile image display on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show Reboot", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Restart DMS", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Saved Items", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Sunrise/Sunset", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Suspend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Swap", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show System Date", - "translation": "", - "context": "Enable system date display on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show System Icons", - "translation": "", - "context": "Enable system status icons on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show System Time", - "translation": "", - "context": "Enable system time display on the lock screen window", - "reference": "", - "comment": "" - }, - { - "term": "Show Top Processes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Weather Condition", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Week Number", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Welcome", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Wind Speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show Workspace Apps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show all 9 tags instead of only occupied tags (DWL only)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show an outline ring around the focused workspace indicator", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show cava audio visualizer in media widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show darkened overlay behind modal dialogs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show dock when floating windows don't overlap its area", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show in GB", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show mode tabs and keyboard hints at the bottom.", - "translation": "", - "context": "launcher footer description", - "reference": "", - "comment": "" - }, - { - "term": "Show notification popups only on the currently focused monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show notifications only on the currently focused monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on Last Display", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on Overlay", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on Overview", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on Overview Only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on all connected displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on screens:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when brightness changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when caps lock state changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when cycling audio output devices", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when idle inhibitor state changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when media player status changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when media player volume changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when microphone is muted/unmuted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when power profile changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show on-screen display when volume changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show weather information in top bar and control center", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show week number in the calendar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show workspace index numbers in the top bar workspace switcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show workspace name on horizontal bars, and first letter on vertical bars", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Show workspaces of the currently focused monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shows all running applications with focus indication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shows current workspace and allows switching", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shows when caps lock is active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shows when microphone, camera, or screen sharing is active", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shrink the media widget to fit shorter song titles while still respecting the configured maximum size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Shutdown", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Signal", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Signal:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Size", - "translation": "", - "context": "launcher size option", - "reference": "", - "comment": "" - }, - { - "term": "Size Constraints", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Size Offset", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sizing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Skip", - "translation": "", - "context": "greeter skip button", - "reference": "", - "comment": "" - }, - { - "term": "Skip confirmation", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Skip setup", - "translation": "", - "context": "greeter skip button tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Small", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Smartcard Authentication", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Smartcard PIN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Snap", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Snow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Some plugins require a newer version of DMS:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sort Alphabetically", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sort By", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sorting & Layout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sound Theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sounds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Space between windows", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Space between windows (gappih/gappiv/gappoh/gappov)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Space between windows (gaps_in and gaps_out)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Spacer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Spacing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Speaker settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Spool Area Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Square Corners", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Stacked", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Standard", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Start", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Start KDE Connect or Valent", - "translation": "", - "context": "Phone Connect start daemon hint", - "reference": "", - "comment": "" - }, - { - "term": "Start KDE Connect or Valent to use this plugin", - "translation": "", - "context": "Phone Connect daemon hint", - "reference": "", - "comment": "" - }, - { - "term": "Start typing your notes here...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "State", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Status", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Stopped", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Stopped Partly", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Stopping", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Stretch", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Stripes", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Summary", - "translation": "", - "context": "notification rule match field option", - "reference": "", - "comment": "" - }, - { - "term": "Sunrise", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sunset", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Suppress notification popups while enabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Surface", - "translation": "", - "context": "color option | shadow color option", - "reference": "", - "comment": "" - }, - { - "term": "Surface Variant", - "translation": "", - "context": "button color option | shadow color option | tile color option", - "reference": "", - "comment": "" - }, - { - "term": "Suspend", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Suspend behavior", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Suspend system after", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Suspend then Hibernate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sway Website", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Switch User", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Switch to power profile", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync Mode with Portal", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync Popouts & Modals", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync Position Across Screens", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync completed successfully.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync dark mode with settings portals for system-wide theme hints", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync failed in background mode. Trying terminal mode so you can authenticate interactively.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Sync needs sudo authentication. Opening terminal so you can use password or fingerprint.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System App Theming", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Check", - "translation": "", - "context": "greeter doctor page title", - "reference": "", - "comment": "" - }, - { - "term": "System Default", - "translation": "", - "context": "date format option", - "reference": "", - "comment": "" - }, - { - "term": "System Information", - "translation": "", - "context": "system info header in system monitor", - "reference": "", - "comment": "" - }, - { - "term": "System Monitor", - "translation": "", - "context": "System monitor widget name | sysmon window title", - "reference": "", - "comment": "" - }, - { - "term": "System Monitor Unavailable", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Sounds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Tray", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Update", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Updater", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System Updates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System notification area icons", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System sounds are not available. Install %1 for sound support.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System theme toggle", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System toast notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "System update custom command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tab", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal custom additional parameters", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal fallback opened. Complete authentication setup there; it will close automatically when done.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal fallback opened. Complete sync there; it will close automatically when done.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal multiplexer backend to use", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal opened. Complete authentication setup there; it will close automatically when done.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminal opened. Complete sync authentication there; it will close automatically when done.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Terminals - Always use Dark Theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Test Connection", - "translation": "", - "context": "Button to test connection to a printer by IP address", - "reference": "", - "comment": "" - }, - { - "term": "Test Page", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Test page sent to printer", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Testing...", - "translation": "", - "context": "Button state while testing printer connection", - "reference": "", - "comment": "" - }, - { - "term": "Text", - "translation": "", - "context": "text color", - "reference": "", - "comment": "" - }, - { - "term": "Text Color", - "translation": "", - "context": "blur border color | shadow color option", - "reference": "", - "comment": "" - }, - { - "term": "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.", - "translation": "", - "context": "dgop unavailable error message", - "reference": "", - "comment": "" - }, - { - "term": "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "The custom command used when attaching to sessions (receives the session name as the first argument)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "The job queue of this printer is empty", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Theme & Colors", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Theme Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Theme Registry", - "translation": "", - "context": "greeter feature card title", - "reference": "", - "comment": "" - }, - { - "term": "Themes", - "translation": "", - "context": "greeter themes link", - "reference": "", - "comment": "" - }, - { - "term": "Thickness", - "translation": "", - "context": "border thickness", - "reference": "", - "comment": "" - }, - { - "term": "Third-Party Plugin Warning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This bind is overridden by config.kdl", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This may take a few seconds", - "translation": "", - "context": "Loading overlay subtitle", - "reference": "", - "comment": "" - }, - { - "term": "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This will delete all unpinned entries. %1 pinned entries will be kept.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This will permanently delete all clipboard history.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "This will permanently remove this saved clipboard item. This action cannot be undone.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Thunderstorm", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Thunderstorm with Hail", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tile", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Tile H", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Tile V", - "translation": "", - "context": "wallpaper fill mode", - "reference": "", - "comment": "" - }, - { - "term": "Tiled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tiled State", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tiling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time", - "translation": "", - "context": "theme auto mode tab | wallpaper cycling mode tab", - "reference": "", - "comment": "" - }, - { - "term": "Time & Date Locale", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time & Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time remaining: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Time until full: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Timed Out", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Timeout for critical priority notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Timeout for low priority notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Timeout for normal priority notifications", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Title", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Title regex (optional)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "To Full", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "To update, run the following command:", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "To use this DMS bind, remove or change the keybind in your config.kdl", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Toast Messages", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Today", - "translation": "", - "context": "notification history filter", - "reference": "", - "comment": "" - }, - { - "term": "Toggle visibility of this bar configuration", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Toggling...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tomorrow", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tonal Spot", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Toner Empty", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Toner Low", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Too many attempts - locked out", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Too many failed attempts - account may be locked", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Tools", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Top", - "translation": "", - "context": "shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Top (Default)", - "translation": "", - "context": "shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Top Bar Format", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Top Center", - "translation": "", - "context": "screen position option", - "reference": "", - "comment": "" - }, - { - "term": "Top Left", - "translation": "", - "context": "screen position option | shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Top Processes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Top Right", - "translation": "", - "context": "screen position option | shadow direction option", - "reference": "", - "comment": "" - }, - { - "term": "Top Section", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Total", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Total Jobs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Touch your security key...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Transform", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Transition Effect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trending GIFs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trending Stickers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trigger", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trigger Prefix", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trigger: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Trust", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Try a different search", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Turn off all displays immediately when the lock screen activates", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Turn off monitors after", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Type", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Type at least 2 characters", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Type this prefix to search keybinds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Type to search files", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Typography", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Typography & Motion", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unavailable", - "translation": "", - "context": "Phone Connect unavailable status", - "reference": "", - "comment": "" - }, - { - "term": "Unfocused Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Ungrouped", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall", - "translation": "", - "context": "uninstall action button", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall Greeter", - "translation": "", - "context": "greeter action confirmation", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall Plugin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall complete. Greeter has been removed.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall failed: %1", - "translation": "", - "context": "uninstallation error", - "reference": "", - "comment": "" - }, - { - "term": "Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uninstalled: %1", - "translation": "", - "context": "uninstallation success", - "reference": "", - "comment": "" - }, - { - "term": "Uninstalling: %1", - "translation": "", - "context": "uninstallation progress", - "reference": "", - "comment": "" - }, - { - "term": "Unknown", - "translation": "", - "context": "KDE Connect unknown device status | battery status | power profile option | unknown author | widget status", - "reference": "", - "comment": "" - }, - { - "term": "Unknown App", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Artist", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Config", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown GPU", - "translation": "", - "context": "fallback gpu name", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Network", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Title", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unknown Track", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unload on Close", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unmute", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unmute popups for %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unnamed Rule", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unpair", - "translation": "", - "context": "KDE Connect unpair tooltip", - "reference": "", - "comment": "" - }, - { - "term": "Unpair failed", - "translation": "", - "context": "Phone Connect error", - "reference": "", - "comment": "" - }, - { - "term": "Unpin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unpin from Dock", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unsaved Changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unsaved changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Unsaved note...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Untitled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Untrust", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Up to date", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Update", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Update All", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Update Plugin", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uptime", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uptime:", - "translation": "", - "context": "uptime label in footer", - "reference": "", - "comment": "" - }, - { - "term": "Urgent Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Usage Tips", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use 24-hour time format instead of 12-hour AM/PM", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Custom Command", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Grid Layout", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use IP Location", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Imperial Units", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Inline Expansion", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use Monospace Font", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use System Theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use a fixed shadow direction for this bar", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use a security key for lock screen authentication.", - "translation": "", - "context": "lock screen U2F security key setting", - "reference": "", - "comment": "" - }, - { - "term": "Use an external wallpaper manager like swww, hyprpaper, or swaybg.", - "translation": "", - "context": "wallpaper settings disable description", - "reference": "", - "comment": "" - }, - { - "term": "Use animated wave progress bars for media playback", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom border size", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom border/focus-ring width", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom command for update your system", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom gaps instead of bar spacing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom window radius instead of theme radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use custom window rounding instead of theme radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use desktop wallpaper", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use fingerprint authentication for the lock screen.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use light theme instead of dark theme", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use meters per second instead of km/h for wind speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use smaller notification cards", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use sound theme from system settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use the same position and size on all displays", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Use trigger prefix to activate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Used when accent color is set to Custom", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "User", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Username", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Username...", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uses sunrise/sunset times based on your location.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Uses sunrise/sunset times to automatically adjust night mode based on your location.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Using shared settings from Gamma Control", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Utilities", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN Connections", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN Password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN configuration updated", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN connections", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN deleted", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN imported: %1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VPN status and quick connect", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VRR", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VRR Fullscreen Only", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "VRR On-Demand", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Variable Refresh Rate", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Verification", - "translation": "", - "context": "Phone Connect pairing verification key label", - "reference": "", - "comment": "" - }, - { - "term": "Version", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Vertical Deck", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Vertical Grid", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Vertical Scrolling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Vertical Tiling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Vibrant", - "translation": "", - "context": "matugen color scheme option", - "reference": "", - "comment": "" - }, - { - "term": "Vibrant palette with playful saturation.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Video Path", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Video Screensaver", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Videos", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "View Mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Visibility", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Visual Effects", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Visual divider between widgets", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Visual effect used when wallpaper changes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Volume", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Volume Changed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Volume Slider", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Volume, brightness, and other system OSDs", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WPA/WPA2", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper", - "translation": "", - "context": "greeter settings link", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper Error", - "translation": "", - "context": "wallpaper error status", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper Monitor", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper fill mode", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper processing failed", - "translation": "", - "context": "wallpaper processing error", - "reference": "", - "comment": "" - }, - { - "term": "Wallpaper processing failed - check wallpaper path", - "translation": "", - "context": "wallpaper error", - "reference": "", - "comment": "" - }, - { - "term": "Wallpapers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Warm color temperature to apply", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Warning", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Warnings", - "translation": "", - "context": "greeter doctor page status card", - "reference": "", - "comment": "" - }, - { - "term": "Wave Progress Bars", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Weather", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Weather Widget", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Welcome", - "translation": "", - "context": "greeter modal window title", - "reference": "", - "comment": "" - }, - { - "term": "Welcome to DankMaterialShell", - "translation": "", - "context": "greeter welcome page title", - "reference": "", - "comment": "" - }, - { - "term": "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "When locked", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "When updater widget is used, then hide it if no update found", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wi-Fi Password", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wi-Fi and Ethernet connection", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wi-Fi not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi Device", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi QR code for ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi disabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi enabled", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi is off", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "WiFi off", - "translation": "", - "context": "network status", - "reference": "", - "comment": "" - }, - { - "term": "Wide (BT2020)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Background Color", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Management", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Outline", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Style", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Styling", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget Transparency", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget added", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widget removed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Widgets", - "translation": "", - "context": "settings_displays", - "reference": "", - "comment": "" - }, - { - "term": "Widgets, layout, style", - "translation": "", - "context": "greeter dankbar description", - "reference": "", - "comment": "" - }, - { - "term": "Width", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Width of window border (borderpx)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Width of window border (general.border_size)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Width of window border and focus ring", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wind", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wind Speed", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wind Speed in m/s", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Corner Radius", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Gaps", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Gaps (px)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Height", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Opening", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Rounding", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Rules", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Rules Include Missing", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Window Rules Not Configured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Wipe", - "translation": "", - "context": "wallpaper transition option", - "reference": "", - "comment": "" - }, - { - "term": "Workspace", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Appearance", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Index Numbers", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Names", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Padding", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Settings", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace Switcher", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspace name", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspaces", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Workspaces & Widgets", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Write:", - "translation": "", - "context": "disk write label", - "reference": "", - "comment": "" - }, - { - "term": "X Axis", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Y Axis", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Yes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Yesterday", - "translation": "", - "context": "notification history filter", - "reference": "", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before closing this tab?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before continuing?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before creating a new file?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "You have unsaved changes. Save before opening a file?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", - "translation": "", - "context": "qt theme env error body", - "reference": "", - "comment": "" - }, - { - "term": "You're All Set!", - "translation": "", - "context": "greeter completion page title", - "reference": "", - "comment": "" - }, - { - "term": "Your system is up to date!", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "attached", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "brandon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "by %1", - "translation": "", - "context": "author attribution", - "reference": "", - "comment": "" - }, - { - "term": "days", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "detached", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "device", - "translation": "", - "context": "Generic device name | Generic device name fallback", - "reference": "", - "comment": "" - }, - { - "term": "devices connected", - "translation": "", - "context": "KDE Connect status multiple devices", - "reference": "", - "comment": "" - }, - { - "term": "dgop not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "dms is a highly customizable, modern desktop shell with a material 3 inspired design.

        It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "dms/cursor config exists but is not included. Cursor settings won't apply.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "dms/outputs config exists but is not included in your compositor config. Display changes won't persist.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "e.g., firefox, kitty --title foo", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "e.g., focus-workspace 3, resize-column -10", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "e.g., notify-send 'Hello' && sleep 1", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "e.g., scratch, /^tmp_.*/, build", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "events", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "ext", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "featured", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "leave empty for default", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "loginctl not available - lock integration requires DMS socket connection", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "mangowc Discord Server", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "mangowc GitHub", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "matugen not found - install matugen package for dynamic theming", - "translation": "", - "context": "matugen error", - "reference": "", - "comment": "" - }, - { - "term": "minutes", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "ms", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "nav", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "niri GitHub", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "niri Matrix Chat", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "niri shortcuts config", - "translation": "", - "context": "greeter keybinds niri description", - "reference": "", - "comment": "" - }, - { - "term": "niri/dms Discord", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "now", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "official", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on Hyprland", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on MangoWC", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on Miracle WM", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on Niri", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on Scroll", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "on Sway", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "open", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "or run ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "power-profiles-daemon not available", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "procs", - "translation": "", - "context": "short for processes", - "reference": "", - "comment": "" - }, - { - "term": "r/niri Subreddit", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "seconds", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "source", - "translation": "", - "context": "source code link", - "reference": "", - "comment": "" - }, - { - "term": "this app", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "up", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "update dms for NM integration.", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "v%1 by %2", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "wtype not available - install wtype for paste support", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• Install only from trusted sources", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• M - Month (1-12)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• MM - Month (01-12)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• MMM - Month (Jan)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• MMMM - Month (January)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• Plugins may contain bugs or security issues", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• Review code before installation when possible", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• d - Day (1-31)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• dd - Day (01-31)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• ddd - Day name (Mon)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• dddd - Day name (Monday)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• yy - Year (24)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "• yyyy - Year (2024)", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", - "translation": "", - "context": "Keyboard hints when enter-to-paste is enabled", - "reference": "", - "comment": "" - } -] diff --git a/raveos-theme/hyprland/theme-data/background b/raveos-theme/hyprland/theme-data/background deleted file mode 100644 index 5945d58..0000000 Binary files a/raveos-theme/hyprland/theme-data/background and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/fastfetch/config-kitty.jsonc b/raveos-theme/hyprland/theme-data/fastfetch/config-kitty.jsonc deleted file mode 100644 index 1737df8..0000000 --- a/raveos-theme/hyprland/theme-data/fastfetch/config-kitty.jsonc +++ /dev/null @@ -1,47 +0,0 @@ -{ - "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "source": "~/.config/fastfetch/raveos-logo.txt", - "type": "file", - "color": { - "1": "green", - "2": "36", - "3": "white" - }, - "padding": { - "top": 1, - "left": 2, - "right": 3 - } - }, - "display": { - "separator": " → ", - "color": { - "keys": "green", - "title": "cyan" - } - }, - "modules": [ - { "type": "custom", "format": "\u001b[1;32mRaveOS" }, - "separator", - { "type": "os", "key": "OS" }, - { "type": "kernel", "key": "Kernel" }, - { "type": "uptime", "key": "Uptime" }, - { "type": "packages", "key": "Packages" }, - { "type": "shell", "key": "Shell" }, - { "type": "de", "key": "DE" }, - { "type": "wm", "key": "WM" }, - { "type": "terminal", "key": "Terminal" }, - "separator", - { "type": "cpu", "key": "CPU" }, - { "type": "gpu", "key": "GPU" }, - { "type": "memory", "key": "RAM" }, - { "type": "disk", "key": "Disk", "folders": "/" }, - "separator", - { "type": "display", "key": "Display" }, - { "type": "theme", "key": "Theme" }, - { "type": "icons", "key": "Icons" }, - "break", - "colors" - ] -} diff --git a/raveos-theme/hyprland/theme-data/fastfetch/config.jsonc b/raveos-theme/hyprland/theme-data/fastfetch/config.jsonc deleted file mode 100644 index f5f842d..0000000 --- a/raveos-theme/hyprland/theme-data/fastfetch/config.jsonc +++ /dev/null @@ -1,93 +0,0 @@ -{ - "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "source": "~/.config/fastfetch/raveos-logo.txt", - "type": "file", - "color": { - "1": "green", - "2": "36", - "3": "white" - }, - "padding": { - "top": 1, - "left": 2, - "right": 3 - } - }, - "display": { - "separator": " → ", - "color": { - "keys": "green", - "title": "cyan" - } - }, - "modules": [ - "title", - "separator", - { - "type": "os", - "key": "OS" - }, - { - "type": "kernel", - "key": "Kernel" - }, - { - "type": "uptime", - "key": "Uptime" - }, - { - "type": "packages", - "key": "Packages" - }, - { - "type": "shell", - "key": "Shell" - }, - { - "type": "de", - "key": "DE" - }, - { - "type": "wm", - "key": "WM" - }, - { - "type": "terminal", - "key": "Terminal" - }, - "separator", - { - "type": "cpu", - "key": "CPU" - }, - { - "type": "gpu", - "key": "GPU" - }, - { - "type": "memory", - "key": "RAM" - }, - { - "type": "disk", - "key": "Disk", - "folders": "/" - }, - "separator", - { - "type": "display", - "key": "Display" - }, - { - "type": "theme", - "key": "Theme" - }, - { - "type": "icons", - "key": "Icons" - }, - "break", - "colors" - ] -} diff --git a/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.png b/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.png deleted file mode 100644 index 93ebb33..0000000 Binary files a/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.png and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.txt b/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.txt deleted file mode 100644 index 41f87e2..0000000 --- a/raveos-theme/hyprland/theme-data/fastfetch/raveos-logo.txt +++ /dev/null @@ -1,19 +0,0 @@ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⢠⡀⠀⠀⠀⠀⠀⠀⡀⠀⣰⣾⣿⣿⣷⣄⠀⣠⠀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠙⣦⣄⡀⠠⡀⠀⣿⡆⠙⣿⣿⣿⡿⠃⢰⣧⠀⣀⠄⢀⣤⡴⠋⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⣀⠀⠑⢮⣙⠛⠂⠙⠀⡅⣹⣄⢸⣿⣿⡇⣠⡏⠁⠈⠉⠐⠟⣉⡵⠊⠀⣠⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠄⢈⣃⡀⠐⠿⣷⣦⣀⢰⣼⣈⣿⣾⣿⣿⣿⣿⢁⣥⡆⣠⣴⣾⠿⠂⢀⣀⠁⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠠⠤⠬⠿⠿⠷⠌⠻⢿⢷⡝⢿⣿⡌⣿⡿⢱⣿⡿⢫⡾⠿⠟⠡⠾⠿⠯⠥⠤⠄⠀⠀⠀⠀ -⠀⠀⠀⠙⠂⠈⠀⠀⠄⠀⠉⠀⠐⠶⢷⣦⣬⡁⠏⠷⢈⣥⣴⠿⠶⠂⠀⠉⠁⠀⠀⠀⠁⠘⠊⠂⠀⠀ -⠀⠀⠀⠀⢀⠄⢠⣴⣶⠀⠀⠀⢀⡀⠀⠉⠙⠃⣠⡄⠘⠉⠁⠀⢀⡀⠀⠀⢠⣶⣦⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⣠⠤⠌⠁⣩⣿⣇⡀⠢⣜⣛⠛⠀⠀⡴⢫⡝⣄⠀⠀⠛⢛⡡⠔⢀⣼⣯⣅⠈⠁⠤⡄⠀⠀⠀ -⠀⠀⠀⢀⡠⢴⠾⠉⢉⣿⣿⣷⣶⣭⣶⣾⡟⣱⣿⣿⡜⢻⣶⣦⣥⣶⣾⣿⣯⡉⠉⠷⡤⢄⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⢀⡴⠂⢚⠟⢉⣾⠿⠛⢙⠉⣠⠈⢹⠇⠁⣄⢈⠋⠛⠿⣷⡉⠿⡓⡐⢦⡀⠀⠁⠀⠀⠀ -⠀⠀⠀⠀⠀⠒⢉⣵⣿⣷⣧⠆⢂⠶⢿⡽⠛⠰⣦⣴⠀⠛⣯⠿⡢⡐⠲⣽⣼⣿⣮⡙⠓⠀⠀⠄⠀⠀ -⠀⠀⢀⣴⠷⠂⣾⣿⠿⠛⣡⣾⡤⠀⠘⠁⢰⣴⣿⣿⣤⠀⠈⠃⠀⢤⣶⣌⠻⢿⣿⣧⠐⠾⣦⡀⠀⠀ -⠀⠀⠀⠀⠀⠘⠉⠀⢠⣼⠏⠋⣠⢠⡄⢀⠻⠉⣿⡿⠈⠟⡄⢰⡀⡀⠻⠹⣦⡀⠀⠉⠃⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠂⠀⠁⠀⡄⡿⠀⢣⠀⠀⠐⡌⢡⠀⠈⢀⡌⠈⢧⠂⠀⠈⠀⠑⠀⠀⠀⠀⠀⠀⠀ -⢠⣤⣤⣤⣤⣄⣰⢠⣤⣴⣦⠟⣥⣦⣀⢳⣦⡆⣴⣦⣶⣴⣾⣄⠀⢈⣷⣶⣶⣦⣄⣄⣠⣴⣶⣦⣤⠀ -⢸⣿⣧⣤⣽⡿⢁⣿⣟⣹⣿⡄⠘⣿⣿⣾⡿⠀⣿⣿⣶⣶⣾⠋⠀⢾⣿⡍⠁⢹⣿⡎⠿⠷⠶⣶⣭⡀ -⠸⣿⠇⠙⢿⡦⢼⡿⠛⠛⢿⣷⠀⠹⣿⡿⠁⠀⢿⣿⣶⣶⣶⠆⠀⠘⠿⢷⣶⠿⠟⠀⠿⢿⣶⡾⠿⠃ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ diff --git a/raveos-theme/hyprland/theme-data/hypr/dms/colors.conf b/raveos-theme/hyprland/theme-data/hypr/dms/colors.conf deleted file mode 100644 index 16adcd2..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/dms/colors.conf +++ /dev/null @@ -1,22 +0,0 @@ -$primary = rgb(3d7839) -$outline = rgb(8a9386) -$error = rgb(f44336) - -general { - col.active_border = $primary - col.inactive_border = $outline -} - -group { - col.border_active = $primary - col.border_inactive = $outline - col.border_locked_active = $error - col.border_locked_inactive = $outline - - groupbar { - col.active = $primary - col.inactive = $outline - col.locked_active = $error - col.locked_inactive = $outline - } -} diff --git a/raveos-theme/hyprland/theme-data/hypr/dms/cursor.conf b/raveos-theme/hyprland/theme-data/hypr/dms/cursor.conf deleted file mode 100644 index 1054579..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/dms/cursor.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Auto-generated by DMS - do not edit manually - -env = HYPRCURSOR_THEME,default -env = XCURSOR_THEME,default -env = HYPRCURSOR_SIZE,24 -env = XCURSOR_SIZE,24 diff --git a/raveos-theme/hyprland/theme-data/hypr/dms/layout.conf b/raveos-theme/hyprland/theme-data/hypr/dms/layout.conf deleted file mode 100644 index b9a8ad9..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/dms/layout.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Auto-generated by DMS - do not edit manually - -general { - gaps_in = 4 - gaps_out = 4 - border_size = 2 -} - -decoration { - rounding = 12 -} diff --git a/raveos-theme/hyprland/theme-data/hypr/dms/windowrules.conf b/raveos-theme/hyprland/theme-data/hypr/dms/windowrules.conf deleted file mode 100644 index e69de29..0000000 diff --git a/raveos-theme/hyprland/theme-data/hypr/hyprland.conf b/raveos-theme/hyprland/theme-data/hypr/hyprland.conf deleted file mode 100644 index efdfc7d..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/hyprland.conf +++ /dev/null @@ -1,154 +0,0 @@ -source = ./dms/colors.conf - -# -# ALT TAB# -# -bind = SUPER, TAB, exec, hyprswitch gui --mod-key super_l --key tab --close mod-key-release --sort-recent --filter-current-monitor - -# -# MONITORS# -# -source = ./monitors.conf -source = ./workspaces.conf - -# -# MY PROGRAMS# -# -$terminal = kitty -$fileManager = Thunar - -# -# AUTOSTART & ENVIRONMENT# -# -exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -exec-once = dbus-update-activation-environment --systemd --all -exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -exec-once = gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' -exec-once = bash -c "wl-paste --watch cliphist store &" -exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 -exec-once = sleep 1 && dms run --config ~/.config/dms/ -exec-once = sleep 3 && dms ipc call wallpaper set "/usr/share/backgrounds/raveos/raveos-main-bg.jpeg" -exec-once = sleep 1 && /usr/lib/pam_kwallet_init -exec-once = /usr/lib/mate-polkit/polkit-mate-authentication-agent-1 - -# Theme & VM Fixes -env = XCURSOR_SIZE,24 -env = HYPRCURSOR_SIZE,24 -env = WLR_NO_HARDWARE_CURSORS,1 -env = WLR_RENDERER_ALLOW_SOFTWARE,1 -env = XDG_CURRENT_DESKTOP,Hyprland -env = XDG_SESSION_TYPE,wayland -env = XDG_SESSION_DESKTOP,Hyprland -env = GDK_BACKEND,wayland -env = QT_QPA_PLATFORM,wayland -env = QT_QPA_PLATFORMTHEME,qt6ct -env = QT_AUTO_SCREEN_SCALE_FACTOR,1 -env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 -env = QT_STYLE_OVERRIDE,kvantum - -# -# LOOK AND FEEL# -# -general { - gaps_in = 5 - gaps_out = 2 - border_size = 2 - col.active_border = $primary - col.inactive_border = $outline - resize_on_border = true - layout = dwindle -} - -decoration { - rounding = 11 - active_opacity = 1.0 - inactive_opacity = 1.0 - shadow { - enabled = false - } - blur { - enabled = true - size = 3 - passes = 1 - vibrancy = 0.1696 - } -} - -animations { - enabled = yes - bezier = easeOutQuint,0.23,1,0.32,1 - animation = global, 1, 10, default - animation = windows, 1, 4.79, easeOutQuint - animation = layers, 1, 3.81, easeOutQuint - animation = workspaces, 1, 1.94, almostLinear, fade -} - -dwindle { - pseudotile = true - preserve_split = true -} - -master { - new_status = master -} - -misc { - force_default_wallpaper = 0 - disable_hyprland_logo = true -} - -input { - kb_layout = gb - follow_mouse = 1 - numlock_by_default = true -} - -cursor { - no_warps = true -} - -# -# KEYBINDINGS# -# -$mainMod = SUPER -bind = $mainMod, Q, killactive, -bind = $mainMod, M, exit, -bind = $mainMod, E, exec, nautilus -bind = $mainMod, V, togglefloating, -bind = $mainMod, P, pseudo, -bind = $mainMod, J, togglesplit, -bind = $mainMod, Return, exec, $terminal - -# Move focus with mainMod + arrow keys -bind = $mainMod, left, movefocus, l -bind = $mainMod, right, movefocus, r -bind = $mainMod, up, movefocus, u -bind = $mainMod, down, movefocus, d - -# Switch workspaces with mainMod + [1-9] -bind = $mainMod, 1, workspace, 1 -bind = $mainMod, 2, workspace, 2 -bind = $mainMod, 3, workspace, 3 -bind = $mainMod, 4, workspace, 4 -bind = $mainMod, 5, workspace, 5 - -# Move active window to a workspace with mainMod + SHIFT + [0-9] -bind = $mainMod SHIFT, 1, movetoworkspace, 1 -bind = $mainMod SHIFT, 2, movetoworkspace, 2 - -# Shell Binds -bind = SUPER, SUPER_L, exec, dms ipc call spotlight toggle -bind = $mainMod, V, exec, dms ipc call clipboard toggle -bind = $mainMod, comma, exec, dms ipc call settings toggle -bind = $mainMod, N, exec, dms ipc call notifications toggle -bind = $mainMod SHIFT, N, exec, dms ipc call notepad toggle -bind = $mainMod, Y, exec, dms ipc call wallpaper next - -# Move/resize windows with mainMod + LMB/RMB and dragging -bindm = $mainMod, mouse:272, movewindow -bindm = $mainMod, mouse:273, resizewindow - -# Source remaining DMS configs -source = ./dms/cursor.conf -source = ./dms/layout.conf -source = ./dms/windowrules.conf diff --git a/raveos-theme/hyprland/theme-data/hypr/monitors.conf b/raveos-theme/hyprland/theme-data/hypr/monitors.conf deleted file mode 100644 index 12d095a..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/monitors.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Auto-generated by raveos-monitor-setup -# Run raveos-monitor-setup to reconfigure monitors -# Format: monitor=NAME, RESxRES@HZ, POSxPOS, SCALE - -monitor=,preferred,auto,1 diff --git a/raveos-theme/hyprland/theme-data/hypr/scripts/alt-tab.sh b/raveos-theme/hyprland/theme-data/hypr/scripts/alt-tab.sh deleted file mode 100755 index 0a40f9d..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/scripts/alt-tab.sh +++ /dev/null @@ -1,273 +0,0 @@ -#!/bin/bash - -STATE_DIR="/tmp/hypr-alt-tab" -STATE_FILE="$STATE_DIR/state" -TIME_FILE="$STATE_DIR/last_press" -CURRENT_INDEX_FILE="$STATE_DIR/current_index" -WINDOW_LIST_FILE="$STATE_DIR/window_list" - -# Cooldown in seconds (time within which presses count as "continuous") -COOLDOWN=0.8 - -# Create state directory if it doesn't exist -mkdir -p "$STATE_DIR" - -# Parse arguments -same_type=false -reverse=false -visible_only=false - -for arg in "$@"; do - case $arg in - --same) same_type=true ;; - --reverse) reverse=true ;; - --visible) visible_only=true ;; - esac -done - -# Function to get window class -get_window_class() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .class' -} - -# Function to get window title -get_window_title() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .title' -} - -# Function to get window workspace ID -get_window_workspace() { - local window="$1" - hyprctl clients -j | jq -r --arg addr "$window" '.[] | select(.address == $addr) | .workspace.id' -} - -# Function to get active workspaces (visible on monitors) -get_active_workspaces() { - hyprctl monitors -j | jq -r '.[].activeWorkspace.id' -} - -# Function to get all windows sorted by focus history (most recent first) -get_windows_by_focus() { - hyprctl clients -j | jq -r 'sort_by(-.focusHistoryID) | .[].address' -} - -# Function to get visible windows (on active workspaces) -get_visible_windows() { - # Get all active workspace IDs - mapfile -t active_workspaces < <(get_active_workspaces) - - if [[ ${#active_workspaces[@]} -eq 0 ]]; then - return - fi - - # Convert active workspaces to JSON array for jq query - local workspaces_json="[" - for ws in "${active_workspaces[@]}"; do - workspaces_json+="$ws," - done - workspaces_json="${workspaces_json%,}]" - - # Get windows in active workspaces, sorted by focus history - hyprctl clients -j | jq -r --argjson workspaces "$workspaces_json" ' - [.[] | select(.workspace.id as $ws | $workspaces | index($ws))] - | sort_by(-.focusHistoryID) - | .[].address - ' -} - -# Function to get windows filtered by type (same class or title pattern) -get_same_type_windows() { - local current_window="$1" - local current_class=$(get_window_class "$current_window") - local current_title=$(get_window_title "$current_window") - - # Get all windows with same class - hyprctl clients -j | jq -r --arg class "$current_class" \ - '.[] | select(.class == $class) | .address' -} - -# Function to get currently focused window -get_focused_window() { - hyprctl activewindow -j | jq -r '.address' -} - -# Function to check if window exists -window_exists() { - local window="$1" - [[ -n "$window" ]] && hyprctl clients -j | jq -r '.[].address' | grep -q "^${window}$" -} - -# Function to validate and refresh window list -validate_window_list() { - local windows=("$@") - local valid_windows=() - - for window in "${windows[@]}"; do - if window_exists "$window"; then - valid_windows+=("$window") - fi - done - - printf '%s\n' "${valid_windows[@]}" -} - -# Get currently focused window -current_focused=$(get_focused_window) - -# Get appropriate window list based on mode -if [[ "$visible_only" == "true" ]]; then - # Get only windows in active workspaces (visible on monitors) - echo "Switching between visible windows only" >&2 - mapfile -t windows < <(get_visible_windows) - - # If no visible windows, fall back to all windows - if [[ ${#windows[@]} -eq 0 ]]; then - echo "No visible windows found, falling back to all windows" >&2 - mapfile -t windows < <(get_windows_by_focus) - fi - - # Apply same-type filter if requested - if [[ "$same_type" == "true" ]] && [[ -n "$current_focused" ]]; then - # Get windows of the same type as current (from visible windows) - mapfile -t same_type_windows < <(get_same_type_windows "$current_focused") - - # Filter visible windows to only include same-type windows - local filtered_windows=() - for visible_window in "${windows[@]}"; do - for same_window in "${same_type_windows[@]}"; do - if [[ "$visible_window" == "$same_window" ]]; then - filtered_windows+=("$visible_window") - break - fi - done - done - - # If filtered list has windows, use it - if [[ ${#filtered_windows[@]} -gt 0 ]]; then - windows=("${filtered_windows[@]}") - else - echo "No visible windows of same type, using all visible windows" >&2 - fi - fi -elif [[ "$same_type" == "true" ]] && [[ -n "$current_focused" ]]; then - # Get windows of the same type as current (from all windows) - mapfile -t windows < <(get_same_type_windows "$current_focused") - - # If no same-type windows or only current window, fall back to all windows - if [[ ${#windows[@]} -le 1 ]]; then - echo "No other windows of same type found, switching to all windows" >&2 - mapfile -t windows < <(get_windows_by_focus) - fi -else - # Get all windows - mapfile -t windows < <(get_windows_by_focus) -fi - -# Validate windows still exist -mapfile -t windows < <(validate_window_list "${windows[@]}") - -# Exit if no windows or only one window -if [[ ${#windows[@]} -le 1 ]]; then - echo "Not enough windows to switch" >&2 - exit 0 -fi - -# Get current time -current_time=$(date +%s.%N) - -# Read last press time -last_press=0 -[[ -f "$TIME_FILE" ]] && last_press=$(<"$TIME_FILE") - -# Calculate time difference -time_diff=$(echo "$current_time - $last_press" | bc -l 2>/dev/null || echo "1") - -# Check if we're continuing the Alt+Tab session -continuing_session=false -if (( $(echo "$time_diff <= $COOLDOWN" | bc -l 2>/dev/null || echo "0") )); then - continuing_session=true -fi - -# Find current window index in the list -current_index=-1 -for i in "${!windows[@]}"; do - if [[ "${windows[$i]}" == "$current_focused" ]]; then - current_index=$i - break - fi -done - -# If current window not in filtered list, start from beginning -if [[ $current_index -eq -1 ]]; then - current_index=0 -fi - -# Calculate target index -if [[ "$continuing_session" == "true" ]] && [[ -f "$CURRENT_INDEX_FILE" ]] && [[ -f "$WINDOW_LIST_FILE" ]]; then - # Read saved state - saved_index=$(<"$CURRENT_INDEX_FILE") - mapfile -t saved_windows < "$WINDOW_LIST_FILE" - - # Check if saved windows match current windows - same_list=true - if [[ ${#windows[@]} -ne ${#saved_windows[@]} ]]; then - same_list=false - else - for i in "${!windows[@]}"; do - if [[ "${windows[$i]}" != "${saved_windows[$i]}" ]]; then - same_list=false - break - fi - done - fi - - if [[ "$same_list" == "true" ]]; then - if [[ "$reverse" == "true" ]]; then - target_index=$(( (saved_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (saved_index + 1) % ${#windows[@]} )) - fi - else - # List changed, recalculate from current - if [[ "$reverse" == "true" ]]; then - target_index=$(( (current_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (current_index + 1) % ${#windows[@]} )) - fi - fi -else - # Start new session - move from current window - if [[ "$reverse" == "true" ]]; then - target_index=$(( (current_index - 1 + ${#windows[@]}) % ${#windows[@]} )) - else - target_index=$(( (current_index + 1) % ${#windows[@]} )) - fi -fi - -# Save state -echo "$current_time" > "$TIME_FILE" -echo "$target_index" > "$CURRENT_INDEX_FILE" -printf '%s\n' "${windows[@]}" > "$WINDOW_LIST_FILE" - -# Focus the target window -target_window="${windows[$target_index]}" -if window_exists "$target_window"; then - echo "Switching to window: $target_window (Class: $(get_window_class "$target_window"), Workspace: $(get_window_workspace "$target_window"))" >&2 - hyprctl dispatch focuswindow "address:$target_window" - hyprctl dispatch bringactivetotop -fi - -# Visual feedback: dim inactive windows temporarily -hyprctl keyword decoration:dim_inactive true 2>/dev/null - -# Clear any existing reset timer -[[ -f "$STATE_DIR/dim_timer" ]] && kill "$(<"$STATE_DIR/dim_timer")" 2>/dev/null || true - -# Start timer to reset dimming -( - sleep 1.2 - hyprctl keyword decoration:dim_inactive false 2>/dev/null -) & -echo $! > "$STATE_DIR/dim_timer" diff --git a/raveos-theme/hyprland/theme-data/hypr/scripts/raveos-monitor-setup.sh b/raveos-theme/hyprland/theme-data/hypr/scripts/raveos-monitor-setup.sh deleted file mode 100755 index 2790ee4..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/scripts/raveos-monitor-setup.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash -# raveos-monitor-setup - Auto-detect monitors and generate Hyprland config -# Sets each monitor to max resolution at 60Hz -# -# Usage: raveos-monitor-setup.sh [--hypr-dir PATH] -# Default hypr dir: ~/.config/hypr - -HYPR_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/hypr" - -# Parse arguments -while [[ $# -gt 0 ]]; do - case "$1" in - --hypr-dir) HYPR_DIR="$2"; shift 2 ;; - *) shift ;; - esac -done - -MONITORS_CONF="$HYPR_DIR/monitors.conf" -WORKSPACES_CONF="$HYPR_DIR/workspaces.conf" - -# Find connected monitors via DRM sysfs -declare -a MON_NAMES -declare -a MON_RESOLUTIONS -declare -a MON_WIDTHS - -for card_output in /sys/class/drm/card*-*; do - [[ ! -d "$card_output" ]] && continue - - status=$(cat "$card_output/status" 2>/dev/null) - [[ "$status" != "connected" ]] && continue - - # Get output name: card0-DP-1 → DP-1, card1-HDMI-A-1 → HDMI-A-1 - raw_name=$(basename "$card_output") - name="${raw_name#card*-}" - - # Get available modes (first line = highest resolution) - modes_file="$card_output/modes" - if [[ -f "$modes_file" ]]; then - max_mode=$(head -1 "$modes_file") - if [[ -n "$max_mode" ]]; then - # Extract width from resolution (e.g., 2560x1440 → 2560) - width="${max_mode%%x*}" - MON_NAMES+=("$name") - MON_RESOLUTIONS+=("$max_mode") - MON_WIDTHS+=("$width") - fi - fi -done - -# If no monitors found, use fallback -if [[ ${#MON_NAMES[@]} -eq 0 ]]; then - cat > "$MONITORS_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# No monitors detected - using fallback -monitor=,preferred,auto,1 -EOF - cat > "$WORKSPACES_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# No monitors detected -EOF - echo "No monitors detected, using fallback config" - exit 0 -fi - -# Generate monitors.conf -cat > "$MONITORS_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -# Run raveos-monitor-setup.sh to reconfigure monitors -EOF - -pos_x=0 -for ((i=0; i<${#MON_NAMES[@]}; i++)); do - echo "monitor=${MON_NAMES[$i]}, ${MON_RESOLUTIONS[$i]}@60, ${pos_x}x0, 1" >> "$MONITORS_CONF" - pos_x=$((pos_x + MON_WIDTHS[i])) -done - -# Generate workspaces.conf - distribute 10 workspaces across monitors -cat > "$WORKSPACES_CONF" << 'EOF' -# Auto-generated by raveos-monitor-setup -EOF - -num_monitors=${#MON_NAMES[@]} -ws_per_mon=$((10 / num_monitors)) -remaining=$((10 % num_monitors)) - -ws=1 -for ((i=0; i> "$WORKSPACES_CONF" - ((ws++)) - done -done - -echo "Monitor setup complete: ${#MON_NAMES[@]} monitor(s) configured" -for ((i=0; i<${#MON_NAMES[@]}; i++)); do - echo " ${MON_NAMES[$i]}: ${MON_RESOLUTIONS[$i]}@60" -done diff --git a/raveos-theme/hyprland/theme-data/hypr/workspaces.conf b/raveos-theme/hyprland/theme-data/hypr/workspaces.conf deleted file mode 100644 index 328ed03..0000000 --- a/raveos-theme/hyprland/theme-data/hypr/workspaces.conf +++ /dev/null @@ -1,2 +0,0 @@ -# Auto-generated by raveos-monitor-setup -# Workspace assignments are configured automatically based on connected monitors diff --git a/raveos-theme/hyprland/theme-data/kitty/kitty.conf b/raveos-theme/hyprland/theme-data/kitty/kitty.conf deleted file mode 100644 index 5ad7fee..0000000 --- a/raveos-theme/hyprland/theme-data/kitty/kitty.conf +++ /dev/null @@ -1,38 +0,0 @@ -# RaveOS Kitty Terminal Config (Nord) -font_family JetBrains Mono -font_size 11.0 - -foreground #D8DEE9 -background #2E3440 -selection_foreground #2E3440 -selection_background #88C0D0 - -color0 #3B4252 -color1 #BF616A -color2 #A3BE8C -color3 #EBCB8B -color4 #81A1C1 -color5 #B48EAD -color6 #88C0D0 -color7 #E5E9F0 -color8 #4C566A -color9 #BF616A -color10 #A3BE8C -color11 #EBCB8B -color12 #81A1C1 -color13 #B48EAD -color14 #8FBCBB -color15 #ECEFF4 - -cursor #D8DEE9 -cursor_shape beam - -background_opacity 0.92 -window_padding_width 8 -confirm_os_window_close 0 - -tab_bar_style slant -active_tab_foreground #2E3440 -active_tab_background #A3BE8C -inactive_tab_foreground #D8DEE9 -inactive_tab_background #3B4252 diff --git a/raveos-theme/hyprland/theme-data/profile.d/raveos-fastfetch.sh b/raveos-theme/hyprland/theme-data/profile.d/raveos-fastfetch.sh deleted file mode 100644 index b3fe8ce..0000000 --- a/raveos-theme/hyprland/theme-data/profile.d/raveos-fastfetch.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -if [[ -z "${RAVEOS_GREETED:-}" && -z "${VSCODE_PID:-}" && "${TERM}" != "dumb" ]]; then - export RAVEOS_GREETED=1 - - if command -v fastfetch >/dev/null 2>&1; then - if [[ "${TERM}" == "xterm-kitty" ]]; then - fastfetch --config "${HOME}/.config/fastfetch/config-kitty.jsonc" - else - fastfetch --config "${HOME}/.config/fastfetch/config.jsonc" - fi - fi -fi diff --git a/raveos-theme/hyprland/theme-data/sddm/astronaut.conf b/raveos-theme/hyprland/theme-data/sddm/astronaut.conf deleted file mode 100644 index 7fa907e..0000000 --- a/raveos-theme/hyprland/theme-data/sddm/astronaut.conf +++ /dev/null @@ -1,162 +0,0 @@ -[General] -#################### General #################### - -ScreenWidth="1920" -ScreenHeight="1080" -ScreenPadding="" -# Default 0, Options: from 0 to min(screen width/2,screen height/2). - -Font="Open Sans" -FontSize="13" -# Default is screen height divided by 80 (1080/80=13.5), Options: 0-inf. - -KeyboardSize="0.4" -# Default 0.4, Options 0.1-1.0 - -RoundCorners="20" - -Locale="" -# Locale for data and time format. I suggest leaving it blank. -HourFormat="HH:mm" -# Default Locale.ShortFormat. -DateFormat="dddd d MMMM" -# Default Locale.LongFormat. - -HeaderText="" -# You can put somehting fun. - -#################### Background #################### - -BackgroundPlaceholder="" -# Must be a relative path. -# Background displayed before the actual background is loaded. -# Use only if the background is a video, otherwise leave blank. -# Connected with: Background. -Background="Backgrounds/new-raveos-main-bg.jpeg" -# Must be a relative path. -# Supports: png, jpg, jpeg, webp, gif, avi, mp4, mov, mkv, m4v, webm. -BackgroundSpeed="" -# Default 1.0. Options: 0.0-10.0 (can go higher). -# Speed of animated wallpaper. -# Connected with: Background. -PauseBackground="" -# Default false. -# If set to true, stops playback of gifs. Works only with gifs. -# Connected with: Background. -DimBackground="0.0" -# Options: 0.0-1.0. -# Connected with: DimBackgroundColor -CropBackground="true" -# Default false. -# Crop or fit background. -# Connected with: BackgroundHorizontalAlignment and BackgroundVerticalAlignment dosn't work when set to true. -BackgroundHorizontalAlignment="center" -# Default: center, Options: left, center, right. -# Horizontal position of the background picture. -# Connected with: CropBackground must be set to false. -BackgroundVerticalAlignment="center" -# Horizontal position of the background picture. -# Default: center, Options: bottom, center, top. -# Connected with: CropBackground must be set to false. - -#################### Colors #################### - -HeaderTextColor="#ffffff" -DateTextColor="#ffffff" -TimeTextColor="#ffffff" - -FormBackgroundColor="#21222C" -BackgroundColor="#21222C" -DimBackgroundColor="#21222C" - -LoginFieldBackgroundColor="#222222" -PasswordFieldBackgroundColor="#222222" -LoginFieldTextColor="#ffffff" -PasswordFieldTextColor="#ffffff" -UserIconColor="#ffffff" -PasswordIconColor="#ffffff" - -PlaceholderTextColor="#bbbbbb" -WarningColor="#343746" - -LoginButtonTextColor="#ffffff" -LoginButtonBackgroundColor="#343746" -SystemButtonsIconsColor="#F8F8F2" -SessionButtonTextColor="#F8F8F2" -VirtualKeyboardButtonTextColor="#F8F8F2" - -DropdownTextColor="#ffffff" -DropdownSelectedBackgroundColor="#343746" -DropdownBackgroundColor="#21222C" - -HighlightTextColor="#bbbbbb" -HighlightBackgroundColor="#343746" -HighlightBorderColor="#343746" - -HoverUserIconColor="#b7cef1" -HoverPasswordIconColor="#b7cef1" -HoverSystemButtonsIconsColor="#b7cef1" -HoverSessionButtonTextColor="#b7cef1" -HoverVirtualKeyboardButtonTextColor="#b7cef1" - -#################### Form #################### - -PartialBlur="true" -# Default false. -FullBlur="" -# Default false. -# If you use FullBlur I recommend setting BlurMax to 64 and Blur to 1.0. -BlurMax="" -# Default 48, Options: 2-64 (can go higher because depends on Blur). -# Connected with: Blur. -Blur="" -# Default 2.0, Options: 0.0-3.0 (without 3.0). -# Connected with: BlurMax. - -HaveFormBackground="false" -# Form background is transparent if set to false. -# Connected with: PartialBlur and BackgroundColor. -FormPosition="center" -# Default: left, Options: left, center, right. - -#################### Virtual Keyboard #################### - -VirtualKeyboardPosition="center" -# Default: left, Options: left, center, right. - -#################### Interface Behavior #################### - -HideVirtualKeyboard="false" -HideSystemButtons="false" -HideLoginButton="false" - -ForceLastUser="true" -# If set to true last successfully logged in user appeares automatically in the username field. -PasswordFocus="true" -# Automaticaly focuses password field. -HideCompletePassword="true" -# Hides the password while typing. -AllowEmptyPassword="false" -# Enable login for users without a password. -AllowUppercaseLettersInUsernames="false" -# Do not change this! Uppercase letters are generally not allowed in usernames. This option is only for systems that differ from this standard! -BypassSystemButtonsChecks="false" -# Skips checking if sddm can perform shutdown, restart, suspend or hibernate, always displays all system buttons. -RightToLeftLayout="false" -# Revert the layout either because you would like the login to be on the right hand side or SDDM won't respect your language locale for some reason. This will reverse the current position of FormPosition if it is either left or right and in addition position some smaller elements on the right hand side of the form itself (also when FormPosition is set to center). - -#################### Translation #################### - -# These don't necessarily need to translate anything. You can enter whatever you want here. -TranslatePlaceholderUsername="" -TranslatePlaceholderPassword="" -TranslateLogin="" -TranslateLoginFailedWarning="" -TranslateCapslockWarning="" -TranslateSuspend="" -TranslateHibernate="" -TranslateReboot="" -TranslateShutdown="" -TranslateSessionSelection="" -TranslateVirtualKeyboardButtonOn="" -TranslateVirtualKeyboardButtonOff="" diff --git a/raveos-theme/hyprland/theme-data/sddm/new-raveos-main-bg.jpeg b/raveos-theme/hyprland/theme-data/sddm/new-raveos-main-bg.jpeg deleted file mode 100644 index 5945d58..0000000 Binary files a/raveos-theme/hyprland/theme-data/sddm/new-raveos-main-bg.jpeg and /dev/null differ diff --git a/raveos-theme/hyprland/theme-data/sddm/sddm.conf b/raveos-theme/hyprland/theme-data/sddm/sddm.conf deleted file mode 100644 index 29b5b95..0000000 --- a/raveos-theme/hyprland/theme-data/sddm/sddm.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Theme] -Current = sddm-astronaut-theme -- cgit v1.3